-/* $Id$ */\r
-/*\r
- * Copyright (c) 2005 Arched Rock Corporation \r
- * All rights reserved. \r
- * Redistribution and use in source and binary forms, with or without\r
- * modification, are permitted provided that the following conditions are\r
- * met:\r
- * Redistributions of source code must retain the above copyright\r
- * notice, this list of conditions and the following disclaimer.\r
- * Redistributions in binary form must reproduce the above copyright\r
- * notice, this list of conditions and the following disclaimer in the\r
- * documentation and/or other materials provided with the distribution.\r
- * \r
- * Neither the name of the Arched Rock Corporation nor the names of its\r
- * contributors may be used to endorse or promote products derived from\r
- * this software without specific prior written permission.\r
- *\r
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\r
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ARCHED\r
- * ROCK OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\r
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS\r
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR\r
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE\r
- * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH\r
- * DAMAGE.\r
- */\r
-/* tab:4\r
- * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By\r
- * downloading, copying, installing or using the software you agree to\r
- * this license. If you do not agree to this license, do not download,\r
- * install, copy or use the software.\r
- *\r
- * Intel Open Source License \r
- *\r
- * Copyright (c) 2002 Intel Corporation \r
- * All rights reserved. \r
- * Redistribution and use in source and binary forms, with or without\r
- * modification, are permitted provided that the following conditions are\r
- * met:\r
- * \r
- * Redistributions of source code must retain the above copyright\r
- * notice, this list of conditions and the following disclaimer.\r
- * Redistributions in binary form must reproduce the above copyright\r
- * notice, this list of conditions and the following disclaimer in the\r
- * documentation and/or other materials provided with the distribution.\r
- * Neither the name of the Intel Corporation nor the names of its\r
- * contributors may be used to endorse or promote products derived from\r
- * this software without specific prior written permission.\r
- * \r
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A\r
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR ITS\r
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\r
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\r
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
- * \r
- * \r
- */\r
-\r
-/*\r
- *\r
- * Authors: Lama Nachman, Robert Adler\r
- */\r
-\r
-#define START_RADIO_LDO 1\r
-#define START_SENSOR_BOARD_LDO 1\r
-/*\r
- * VCC_MEM is connected to BUCK2 by default, make sure you have a board\r
- * that has the right resistor settings before disabling BUCK2\r
- */\r
-#define DISABLE_BUCK2 0 \r
-\r
-//#include "trace.h"\r
-#include "Timer.h"\r
-#include "pmic.h"\r
-\r
-module PMICM {\r
- provides{\r
- interface Init;\r
- interface PMIC;\r
- }\r
-\r
- uses interface Timer<TMilli> as chargeMonitorTimer;\r
- uses interface HplPXA27xGPIOPin as PMICGPIO;\r
- uses interface HplPXA27xI2C as PI2C;\r
- uses interface PlatformReset;\r
-}\r
-\r
-implementation {\r
-#include "pmic.h"\r
- \r
- bool gotReset;\r
- \r
- \r
- error_t readPMIC(uint8_t address, uint8_t *value, uint8_t numBytes){\r
- //send the PMIC the address that we want to read\r
- if(numBytes > 0){\r
- call PI2C.setIDBR(PMIC_SLAVE_ADDR<<1); \r
- call PI2C.setICR(call PI2C.getICR() | ICR_START);\r
- call PI2C.setICR(call PI2C.getICR() | ICR_TB); \r
- while(call PI2C.getICR() & ICR_TB);\r
- \r
- //actually send the address terminated with a STOP\r
- call PI2C.setIDBR(address);\r
- call PI2C.setICR(call PI2C.getICR() & ~ICR_START);\r
- call PI2C.setICR(call PI2C.getICR() | ICR_STOP);\r
- call PI2C.setICR(call PI2C.getICR() | ICR_TB); \r
- while(call PI2C.getICR() & ICR_TB);\r
- call PI2C.setICR(call PI2C.getICR() & ~ICR_STOP);\r
- \r
- //actually request the read of the data\r
- call PI2C.setIDBR(PMIC_SLAVE_ADDR<<1 | 1);\r
- call PI2C.setICR(call PI2C.getICR() | ICR_START); \r
- call PI2C.setICR(call PI2C.getICR() | ICR_TB);\r
- while(call PI2C.getICR() & ICR_TB);\r
- call PI2C.setICR(call PI2C.getICR() & ~ICR_START);\r
- \r
- //using Page Read Mode\r
- while (numBytes > 1){\r
- call PI2C.setICR(call PI2C.getICR() | ICR_TB); \r
- while(call PI2C.getICR() & ICR_TB);\r
- *value = call PI2C.getIDBR(); \r
- value++;\r
- numBytes--;\r
- }\r
- \r
- call PI2C.setICR(call PI2C.getICR() | ICR_STOP);\r
- call PI2C.setICR(call PI2C.getICR() | ICR_ACKNAK);\r
- call PI2C.setICR(call PI2C.getICR() | ICR_TB); \r
- while(call PI2C.getICR() & ICR_TB);\r
- *value = call PI2C.getIDBR(); \r
- call PI2C.setICR(call PI2C.getICR() & ~ICR_STOP); \r
- call PI2C.setICR(call PI2C.getICR() & ~ICR_ACKNAK);\r
- \r
- return SUCCESS;\r
- }\r
- else{\r
- return FAIL;\r
- }\r
- }\r
-\r
- error_t writePMIC(uint8_t address, uint8_t value){\r
- call PI2C.setIDBR(PMIC_SLAVE_ADDR<<1); \r
- call PI2C.setICR(call PI2C.getICR() | ICR_START); \r
- call PI2C.setICR(call PI2C.getICR() | ICR_TB); \r
- while(call PI2C.getICR() & ICR_TB);\r
- \r
- PIDBR = address;\r
- call PI2C.setICR(call PI2C.getICR() & ~ICR_START); \r
- call PI2C.setICR(call PI2C.getICR() | ICR_TB); \r
- while(call PI2C.getICR() & ICR_TB);\r
-\r
- PIDBR = value;\r
- call PI2C.setICR(call PI2C.getICR() | ICR_STOP); \r
- call PI2C.setICR(call PI2C.getICR() | ICR_TB); \r
- while(call PI2C.getICR() & ICR_TB);\r
- call PI2C.setICR(call PI2C.getICR() & ~ICR_STOP); PICR &= ~ICR_STOP;\r
-\r
- return SUCCESS;\r
- }\r
- \r
- void startLDOs() {\r
- //uint8_t temp;\r
- uint8_t oldVal, newVal;\r
-\r
-#if START_SENSOR_BOARD_LDO \r
- // TODO : Need to move out of here to sensor board functions\r
- readPMIC(PMIC_A_REG_CONTROL_1, &oldVal, 1);\r
- newVal = oldVal | ARC1_LDO10_EN | ARC1_LDO11_EN; // sensor board\r
- writePMIC(PMIC_A_REG_CONTROL_1, newVal);\r
-\r
- readPMIC(PMIC_B_REG_CONTROL_2, &oldVal, 1);\r
- newVal = oldVal | BRC2_LDO10_EN | BRC2_LDO11_EN;\r
- writePMIC(PMIC_B_REG_CONTROL_2, newVal);\r
-#endif\r
-\r
-#if START_RADIO_LDO\r
- // TODO : Move to radio start\r
- readPMIC(PMIC_B_REG_CONTROL_1, &oldVal, 1);\r
- newVal = oldVal | BRC1_LDO5_EN; \r
- writePMIC(PMIC_B_REG_CONTROL_1, newVal);\r
-#endif\r
-\r
-#if DISABLE_BUCK2 // Disable BUCK2 if VCC_MEM is not configured to use BUCK2\r
- readPMIC(PMIC_B_REG_CONTROL_1, &oldVal, 1);\r
- newVal = oldVal & ~BRC1_BUCK_EN;\r
- writePMIC(PMIC_B_REG_CONTROL_1, newVal);\r
-#endif\r
-\r
-#if 0\r
- // Configure above LDOs, Radio and sensor board LDOs to turn off in sleep\r
- // TODO : Sleep setting doesn't work\r
- temp = BSC1_LDO1(1) | BSC1_LDO2(1) | BSC1_LDO3(1) | BSC1_LDO4(1);\r
- writePMIC(PMIC_B_SLEEP_CONTROL_1, temp);\r
- temp = BSC2_LDO5(1) | BSC2_LDO7(1) | BSC2_LDO8(1) | BSC2_LDO9(1);\r
- writePMIC(PMIC_B_SLEEP_CONTROL_2, temp);\r
- temp = BSC3_LDO12(1); \r
- writePMIC(PMIC_B_SLEEP_CONTROL_3, temp);\r
-#endif\r
- }\r
-\r
- error_t startPMICstuff() {\r
- //command result_t StdControl.start(){ XXX-pb\r
- //init unit\r
- uint8_t val[3];\r
- //call PI2CInterrupt.enable(); XXX-pb\r
-\r
- }\r
-\r
- command error_t Init.init(){\r
- uint8_t val[3];\r
- PCFR |= PCFR_PI2C_EN; // Overrides GPIO settings on pins\r
- call PI2C.setICR(call PI2C.getICR() | (ICR_IUE | ICR_SCLE));\r
- atomic{\r
- gotReset=FALSE;\r
- } \r
-\r
- call PMICGPIO.setGAFRpin(0);\r
- call PMICGPIO.setGPDRbit(FALSE);\r
- call PMICGPIO.setGFERbit(TRUE);\r
- /*\r
- * Reset the watchdog, switch it to an interrupt, so we can disable it\r
- * Ignore SLEEP_N pin, enable H/W reset via button \r
- */\r
- writePMIC(PMIC_SYS_CONTROL_A, \r
- SCA_RESET_WDOG | SCA_WDOG_ACTION | SCA_HWRES_EN);\r
-\r
- // Disable all interrupts from PMIC except for ONKEY button\r
- writePMIC(PMIC_IRQ_MASK_A, ~IMA_ONKEY_N);\r
- writePMIC(PMIC_IRQ_MASK_B, 0xFF);\r
- writePMIC(PMIC_IRQ_MASK_C, 0xFF);\r
- \r
- //read out the EVENT registers so that we can receive interrupts\r
- readPMIC(PMIC_EVENTS, val, 3);\r
-\r
- // Set default core voltage to 0.85 V\r
-#ifdef PXA27X_13M\r
- //P85 is not reliable, using P95\r
- call PMIC.setCoreVoltage(B2R1_TRIM_P95_V);\r
-#else\r
- call PMIC.setCoreVoltage(B2R1_TRIM_1_25_V);\r
-#endif\r
- startLDOs();\r
- return SUCCESS;\r
- }\r
-\r
- async event void PI2C.interruptI2C() { //PI2CInterrupt.fired(){\r
- uint32_t status, update=0;\r
- status = call PI2C.getISR(); //PISR;\r
- if(status & ISR_ITE){\r
- update |= ISR_ITE;\r
- //trace(DBG_USR1,"sent data");\r
- }\r
-\r
- if(status & ISR_BED){\r
- update |= ISR_BED;\r
- //trace(DBG_USR1,"bus error");\r
- }\r
- call PI2C.setISAR(update); //PISR = update;\r
- }\r
- \r
- async event void PMICGPIO.interruptGPIOPin(){\r
- uint8_t events[3];\r
- bool localGotReset;\r
- \r
- //call PMICGPIO.call PMICInterrupt.clear(); XXX autocleard by GPIO module\r
- \r
- readPMIC(PMIC_EVENTS, events, 3);\r
- \r
- if(events[EVENTS_A_OFFSET] & EA_ONKEY_N){\r
- atomic{\r
- localGotReset = gotReset;\r
- }\r
- if(localGotReset==TRUE){\r
- call PlatformReset.reset();\r
- }\r
- else{\r
- atomic{\r
- gotReset=TRUE;\r
- }\r
- }\r
- }\r
- else{\r
- //trace(DBG_USR1,"PMIC EVENTs =%#x %#x %#x\r\n",events[0], events[1], events[2]);\r
- }\r
- }\r
-\r
- /*\r
- * The Buck2 controls the core voltage, set to appropriate trim value\r
- */\r
- command error_t PMIC.setCoreVoltage(uint8_t trimValue) {\r
- writePMIC(PMIC_BUCK2_REG1, (trimValue & B2R1_TRIM_MASK) | B2R1_GO);\r
- return SUCCESS;\r
- }\r
- \r
- command error_t PMIC.shutDownLDOs() {\r
- uint8_t temp;\r
- uint8_t oldVal, newVal;\r
- /* \r
- * Shut down all LDOs that are not controlled by the sleep mode\r
- * Note, we assume here the LDO10 & LDO11 (sensor board) will be off\r
- * Should be moved to sensor board control\r
- */\r
-\r
- // LDO1, LDO4, LDO6, LDO7, LDO8, LDO9, LDO10, LDO 11, LDO13, LDO14\r
-\r
- readPMIC(PMIC_A_REG_CONTROL_1, &oldVal, 1);\r
- newVal = oldVal & ~ARC1_LDO13_EN & ~ARC1_LDO14_EN;\r
- newVal = newVal & ~ARC1_LDO10_EN & ~ARC1_LDO11_EN; // sensor board\r
- writePMIC(PMIC_A_REG_CONTROL_1, newVal);\r
-\r
- readPMIC(PMIC_B_REG_CONTROL_1, &oldVal, 1);\r
- newVal = oldVal & ~BRC1_LDO1_EN & ~BRC1_LDO4_EN & ~BRC1_LDO5_EN &\r
- ~BRC1_LDO6_EN & ~BRC1_LDO7_EN;\r
- writePMIC(PMIC_B_REG_CONTROL_1, newVal);\r
-\r
- readPMIC(PMIC_B_REG_CONTROL_2, &oldVal, 1);\r
- newVal = oldVal & ~BRC2_LDO8_EN & ~BRC2_LDO9_EN & ~BRC2_LDO10_EN &\r
- ~BRC2_LDO11_EN & ~BRC2_LDO14_EN & ~BRC2_SIMCP_EN;\r
- writePMIC(PMIC_B_REG_CONTROL_2, newVal);\r
- \r
- return SUCCESS;\r
- }\r
-\r
- error_t getPMICADCVal(uint8_t channel, uint8_t *val){\r
- uint8_t oldval;\r
- error_t rval;\r
- \r
- //read out the old value so that we can reset at the end\r
- rval = readPMIC(PMIC_ADC_MAN_CONTROL, &oldval,1);\r
- if (rval == SUCCESS) {\r
- rval = writePMIC(PMIC_ADC_MAN_CONTROL, PMIC_AMC_ADCMUX(channel) | \r
- PMIC_AMC_MAN_CONV | PMIC_AMC_LDO_INT_Enable);\r
- }\r
- if (rval == SUCCESS) {\r
- rval = readPMIC(PMIC_MAN_RES,val,1);\r
- }\r
- if (rval == SUCCESS) {\r
- //reset to old state\r
- rval = writePMIC(PMIC_ADC_MAN_CONTROL, oldval);\r
- }\r
-\r
- return rval;\r
- }\r
-\r
- command error_t PMIC.getBatteryVoltage(uint8_t *val){\r
- //for now, let's use the manual conversion mode\r
- return getPMICADCVal(0, val);\r
- }\r
- \r
- command error_t PMIC.chargingStatus(uint8_t *vBat, uint8_t *vChg, \r
- uint8_t *iChg){\r
- getPMICADCVal(0, vBat);\r
- getPMICADCVal(2, vChg);\r
- getPMICADCVal(1, iChg);\r
- return SUCCESS;\r
- } \r
- \r
- command error_t PMIC.enableAutoCharging(bool enable){\r
- return SUCCESS;\r
- }\r
- \r
- command error_t PMIC.enableManualCharging(bool enable){\r
- //just turn on or off the LED for now!!\r
- uint8_t val;\r
- \r
- if(enable){\r
- //want to turn on the charger\r
- getPMICADCVal(2, &val);\r
- //if charger is present due some stuff...75 should be 4.65V or so \r
- if(val > 75 ) {\r
- //trace(DBG_USR1,"Charger Voltage is %.3fV...enabling charger...\r\n", ((val*6) * .01035));\r
- //write the total timeout to be 8 hours\r
- writePMIC(PMIC_TCTR_CONTROL,8);\r
- //enable the charger at 100mA and 4.35V\r
- writePMIC(PMIC_CHARGE_CONTROL,PMIC_CC_CHARGE_ENABLE | PMIC_CC_ISET(1) | PMIC_CC_VSET(7));\r
- //turn on the LED\r
- writePMIC(PMIC_LED1_CONTROL,0x80);\r
- //start a timer to monitor our progress every 5 minutes!\r
- call chargeMonitorTimer.startPeriodic(300000);\r
- }\r
- else{\r
- //trace(DBG_USR1,"Charger Voltage is %.3fV...charger not enabled\r\n", ((val*6) * .01035));\r
- }\r
- }\r
- else{\r
- //turn off the charger and the LED\r
- call PMIC.getBatteryVoltage(&val);\r
- //trace(DBG_USR1,"Disabling Charger...Battery Voltage is %.3fV\r\n", (val * .01035) + 2.65);\r
- //disable everything that we enabled\r
- writePMIC(PMIC_TCTR_CONTROL,0);\r
- writePMIC(PMIC_CHARGE_CONTROL,0);\r
- writePMIC(PMIC_LED1_CONTROL,0x00);\r
- }\r
- return SUCCESS; \r
- } \r
- \r
- event void chargeMonitorTimer.fired(){\r
- uint8_t val;\r
- call PMIC.getBatteryVoltage(&val);\r
- //stop when vBat>4V\r
- if(val>130){\r
- call PMIC.enableManualCharging(FALSE);\r
- call chargeMonitorTimer.stop();\r
- }\r
- return;\r
- }\r
-\r
-\r
-}\r
+/* $Id$ */
+/*
+ * Copyright (c) 2005 Arched Rock Corporation
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of the Arched Rock Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ARCHED
+ * ROCK OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+/* tab:4
+ * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By
+ * downloading, copying, installing or using the software you agree to
+ * this license. If you do not agree to this license, do not download,
+ * install, copy or use the software.
+ *
+ * Intel Open Source License
+ *
+ * Copyright (c) 2002 Intel Corporation
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR ITS
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ */
+
+/*
+ *
+ * Authors: Lama Nachman, Robert Adler
+ */
+
+#define START_RADIO_LDO 1
+#define START_SENSOR_BOARD_LDO 1
+/*
+ * VCC_MEM is connected to BUCK2 by default, make sure you have a board
+ * that has the right resistor settings before disabling BUCK2
+ */
+#define DISABLE_BUCK2 0
+
+//#include "trace.h"
+#include "Timer.h"
+#include "pmic.h"
+
+module PMICM {
+ provides{
+ interface Init;
+ interface PMIC;
+ }
+
+ uses interface Timer<TMilli> as chargeMonitorTimer;
+ uses interface HplPXA27xGPIOPin as PMICGPIO;
+ uses interface HplPXA27xI2C as PI2C;
+ uses interface PlatformReset;
+}
+
+implementation {
+#include "pmic.h"
+
+ bool gotReset;
+
+
+ error_t readPMIC(uint8_t address, uint8_t *value, uint8_t numBytes){
+ //send the PMIC the address that we want to read
+ if(numBytes > 0){
+ call PI2C.setIDBR(PMIC_SLAVE_ADDR<<1);
+ call PI2C.setICR(call PI2C.getICR() | ICR_START);
+ call PI2C.setICR(call PI2C.getICR() | ICR_TB);
+ while(call PI2C.getICR() & ICR_TB);
+
+ //actually send the address terminated with a STOP
+ call PI2C.setIDBR(address);
+ call PI2C.setICR(call PI2C.getICR() & ~ICR_START);
+ call PI2C.setICR(call PI2C.getICR() | ICR_STOP);
+ call PI2C.setICR(call PI2C.getICR() | ICR_TB);
+ while(call PI2C.getICR() & ICR_TB);
+ call PI2C.setICR(call PI2C.getICR() & ~ICR_STOP);
+
+ //actually request the read of the data
+ call PI2C.setIDBR(PMIC_SLAVE_ADDR<<1 | 1);
+ call PI2C.setICR(call PI2C.getICR() | ICR_START);
+ call PI2C.setICR(call PI2C.getICR() | ICR_TB);
+ while(call PI2C.getICR() & ICR_TB);
+ call PI2C.setICR(call PI2C.getICR() & ~ICR_START);
+
+ //using Page Read Mode
+ while (numBytes > 1){
+ call PI2C.setICR(call PI2C.getICR() | ICR_TB);
+ while(call PI2C.getICR() & ICR_TB);
+ *value = call PI2C.getIDBR();
+ value++;
+ numBytes--;
+ }
+
+ call PI2C.setICR(call PI2C.getICR() | ICR_STOP);
+ call PI2C.setICR(call PI2C.getICR() | ICR_ACKNAK);
+ call PI2C.setICR(call PI2C.getICR() | ICR_TB);
+ while(call PI2C.getICR() & ICR_TB);
+ *value = call PI2C.getIDBR();
+ call PI2C.setICR(call PI2C.getICR() & ~ICR_STOP);
+ call PI2C.setICR(call PI2C.getICR() & ~ICR_ACKNAK);
+
+ return SUCCESS;
+ }
+ else{
+ return FAIL;
+ }
+ }
+
+ error_t writePMIC(uint8_t address, uint8_t value){
+ call PI2C.setIDBR(PMIC_SLAVE_ADDR<<1);
+ call PI2C.setICR(call PI2C.getICR() | ICR_START);
+ call PI2C.setICR(call PI2C.getICR() | ICR_TB);
+ while(call PI2C.getICR() & ICR_TB);
+
+ PIDBR = address;
+ call PI2C.setICR(call PI2C.getICR() & ~ICR_START);
+ call PI2C.setICR(call PI2C.getICR() | ICR_TB);
+ while(call PI2C.getICR() & ICR_TB);
+
+ PIDBR = value;
+ call PI2C.setICR(call PI2C.getICR() | ICR_STOP);
+ call PI2C.setICR(call PI2C.getICR() | ICR_TB);
+ while(call PI2C.getICR() & ICR_TB);
+ call PI2C.setICR(call PI2C.getICR() & ~ICR_STOP); PICR &= ~ICR_STOP;
+
+ return SUCCESS;
+ }
+
+ void startLDOs() {
+ //uint8_t temp;
+ uint8_t oldVal, newVal;
+
+#if START_SENSOR_BOARD_LDO
+ // TODO : Need to move out of here to sensor board functions
+ readPMIC(PMIC_A_REG_CONTROL_1, &oldVal, 1);
+ newVal = oldVal | ARC1_LDO10_EN | ARC1_LDO11_EN; // sensor board
+ writePMIC(PMIC_A_REG_CONTROL_1, newVal);
+
+ readPMIC(PMIC_B_REG_CONTROL_2, &oldVal, 1);
+ newVal = oldVal | BRC2_LDO10_EN | BRC2_LDO11_EN;
+ writePMIC(PMIC_B_REG_CONTROL_2, newVal);
+#endif
+
+#if START_RADIO_LDO
+ // TODO : Move to radio start
+ readPMIC(PMIC_B_REG_CONTROL_1, &oldVal, 1);
+ newVal = oldVal | BRC1_LDO5_EN;
+ writePMIC(PMIC_B_REG_CONTROL_1, newVal);
+#endif
+
+#if DISABLE_BUCK2 // Disable BUCK2 if VCC_MEM is not configured to use BUCK2
+ readPMIC(PMIC_B_REG_CONTROL_1, &oldVal, 1);
+ newVal = oldVal & ~BRC1_BUCK_EN;
+ writePMIC(PMIC_B_REG_CONTROL_1, newVal);
+#endif
+
+#if 0
+ // Configure above LDOs, Radio and sensor board LDOs to turn off in sleep
+ // TODO : Sleep setting doesn't work
+ temp = BSC1_LDO1(1) | BSC1_LDO2(1) | BSC1_LDO3(1) | BSC1_LDO4(1);
+ writePMIC(PMIC_B_SLEEP_CONTROL_1, temp);
+ temp = BSC2_LDO5(1) | BSC2_LDO7(1) | BSC2_LDO8(1) | BSC2_LDO9(1);
+ writePMIC(PMIC_B_SLEEP_CONTROL_2, temp);
+ temp = BSC3_LDO12(1);
+ writePMIC(PMIC_B_SLEEP_CONTROL_3, temp);
+#endif
+ }
+
+ error_t startPMICstuff() {
+ //command result_t StdControl.start(){ XXX-pb
+ //init unit
+ uint8_t val[3];
+ //call PI2CInterrupt.enable(); XXX-pb
+
+ }
+
+ command error_t Init.init(){
+ uint8_t val[3];
+ PCFR |= PCFR_PI2C_EN; // Overrides GPIO settings on pins
+ call PI2C.setICR(call PI2C.getICR() | (ICR_IUE | ICR_SCLE));
+ atomic{
+ gotReset=FALSE;
+ }
+
+ call PMICGPIO.setGAFRpin(0);
+ call PMICGPIO.setGPDRbit(FALSE);
+ call PMICGPIO.setGFERbit(TRUE);
+ /*
+ * Reset the watchdog, switch it to an interrupt, so we can disable it
+ * Ignore SLEEP_N pin, enable H/W reset via button
+ */
+ writePMIC(PMIC_SYS_CONTROL_A,
+ SCA_RESET_WDOG | SCA_WDOG_ACTION | SCA_HWRES_EN);
+
+ // Disable all interrupts from PMIC except for ONKEY button
+ writePMIC(PMIC_IRQ_MASK_A, ~IMA_ONKEY_N);
+ writePMIC(PMIC_IRQ_MASK_B, 0xFF);
+ writePMIC(PMIC_IRQ_MASK_C, 0xFF);
+
+ //read out the EVENT registers so that we can receive interrupts
+ readPMIC(PMIC_EVENTS, val, 3);
+
+ // Set default core voltage to 0.85 V
+#ifdef PXA27X_13M
+ //P85 is not reliable, using P95
+ call PMIC.setCoreVoltage(B2R1_TRIM_P95_V);
+#else
+ call PMIC.setCoreVoltage(B2R1_TRIM_1_25_V);
+#endif
+ startLDOs();
+ return SUCCESS;
+ }
+
+ async event void PI2C.interruptI2C() { //PI2CInterrupt.fired(){
+ uint32_t status, update=0;
+ status = call PI2C.getISR(); //PISR;
+ if(status & ISR_ITE){
+ update |= ISR_ITE;
+ //trace(DBG_USR1,"sent data");
+ }
+
+ if(status & ISR_BED){
+ update |= ISR_BED;
+ //trace(DBG_USR1,"bus error");
+ }
+ call PI2C.setISAR(update); //PISR = update;
+ }
+
+ async event void PMICGPIO.interruptGPIOPin(){
+ uint8_t events[3];
+ bool localGotReset;
+
+ //call PMICGPIO.call PMICInterrupt.clear(); XXX autocleard by GPIO module
+
+ readPMIC(PMIC_EVENTS, events, 3);
+
+ if(events[EVENTS_A_OFFSET] & EA_ONKEY_N){
+ atomic{
+ localGotReset = gotReset;
+ }
+ if(localGotReset==TRUE){
+ call PlatformReset.reset();
+ }
+ else{
+ atomic{
+ gotReset=TRUE;
+ }
+ }
+ }
+ else{
+ //trace(DBG_USR1,"PMIC EVENTs =%#x %#x %#x\r\n",events[0], events[1], events[2]);
+ }
+ }
+
+ /*
+ * The Buck2 controls the core voltage, set to appropriate trim value
+ */
+ command error_t PMIC.setCoreVoltage(uint8_t trimValue) {
+ writePMIC(PMIC_BUCK2_REG1, (trimValue & B2R1_TRIM_MASK) | B2R1_GO);
+ return SUCCESS;
+ }
+
+ command error_t PMIC.shutDownLDOs() {
+ uint8_t temp;
+ uint8_t oldVal, newVal;
+ /*
+ * Shut down all LDOs that are not controlled by the sleep mode
+ * Note, we assume here the LDO10 & LDO11 (sensor board) will be off
+ * Should be moved to sensor board control
+ */
+
+ // LDO1, LDO4, LDO6, LDO7, LDO8, LDO9, LDO10, LDO 11, LDO13, LDO14
+
+ readPMIC(PMIC_A_REG_CONTROL_1, &oldVal, 1);
+ newVal = oldVal & ~ARC1_LDO13_EN & ~ARC1_LDO14_EN;
+ newVal = newVal & ~ARC1_LDO10_EN & ~ARC1_LDO11_EN; // sensor board
+ writePMIC(PMIC_A_REG_CONTROL_1, newVal);
+
+ readPMIC(PMIC_B_REG_CONTROL_1, &oldVal, 1);
+ newVal = oldVal & ~BRC1_LDO1_EN & ~BRC1_LDO4_EN & ~BRC1_LDO5_EN &
+ ~BRC1_LDO6_EN & ~BRC1_LDO7_EN;
+ writePMIC(PMIC_B_REG_CONTROL_1, newVal);
+
+ readPMIC(PMIC_B_REG_CONTROL_2, &oldVal, 1);
+ newVal = oldVal & ~BRC2_LDO8_EN & ~BRC2_LDO9_EN & ~BRC2_LDO10_EN &
+ ~BRC2_LDO11_EN & ~BRC2_LDO14_EN & ~BRC2_SIMCP_EN;
+ writePMIC(PMIC_B_REG_CONTROL_2, newVal);
+
+ return SUCCESS;
+ }
+
+ error_t getPMICADCVal(uint8_t channel, uint8_t *val){
+ uint8_t oldval;
+ error_t rval;
+
+ //read out the old value so that we can reset at the end
+ rval = readPMIC(PMIC_ADC_MAN_CONTROL, &oldval,1);
+ if (rval == SUCCESS) {
+ rval = writePMIC(PMIC_ADC_MAN_CONTROL, PMIC_AMC_ADCMUX(channel) |
+ PMIC_AMC_MAN_CONV | PMIC_AMC_LDO_INT_Enable);
+ }
+ if (rval == SUCCESS) {
+ rval = readPMIC(PMIC_MAN_RES,val,1);
+ }
+ if (rval == SUCCESS) {
+ //reset to old state
+ rval = writePMIC(PMIC_ADC_MAN_CONTROL, oldval);
+ }
+
+ return rval;
+ }
+
+ command error_t PMIC.getBatteryVoltage(uint8_t *val){
+ //for now, let's use the manual conversion mode
+ return getPMICADCVal(0, val);
+ }
+
+ command error_t PMIC.chargingStatus(uint8_t *vBat, uint8_t *vChg,
+ uint8_t *iChg){
+ getPMICADCVal(0, vBat);
+ getPMICADCVal(2, vChg);
+ getPMICADCVal(1, iChg);
+ return SUCCESS;
+ }
+
+ command error_t PMIC.enableAutoCharging(bool enable){
+ return SUCCESS;
+ }
+
+ command error_t PMIC.enableManualCharging(bool enable){
+ //just turn on or off the LED for now!!
+ uint8_t val;
+
+ if(enable){
+ //want to turn on the charger
+ getPMICADCVal(2, &val);
+ //if charger is present due some stuff...75 should be 4.65V or so
+ if(val > 75 ) {
+ //trace(DBG_USR1,"Charger Voltage is %.3fV...enabling charger...\r\n", ((val*6) * .01035));
+ //write the total timeout to be 8 hours
+ writePMIC(PMIC_TCTR_CONTROL,8);
+ //enable the charger at 100mA and 4.35V
+ writePMIC(PMIC_CHARGE_CONTROL,PMIC_CC_CHARGE_ENABLE | PMIC_CC_ISET(1) | PMIC_CC_VSET(7));
+ //turn on the LED
+ writePMIC(PMIC_LED1_CONTROL,0x80);
+ //start a timer to monitor our progress every 5 minutes!
+ call chargeMonitorTimer.startPeriodic(300000);
+ }
+ else{
+ //trace(DBG_USR1,"Charger Voltage is %.3fV...charger not enabled\r\n", ((val*6) * .01035));
+ }
+ }
+ else{
+ //turn off the charger and the LED
+ call PMIC.getBatteryVoltage(&val);
+ //trace(DBG_USR1,"Disabling Charger...Battery Voltage is %.3fV\r\n", (val * .01035) + 2.65);
+ //disable everything that we enabled
+ writePMIC(PMIC_TCTR_CONTROL,0);
+ writePMIC(PMIC_CHARGE_CONTROL,0);
+ writePMIC(PMIC_LED1_CONTROL,0x00);
+ }
+ return SUCCESS;
+ }
+
+ event void chargeMonitorTimer.fired(){
+ uint8_t val;
+ call PMIC.getBatteryVoltage(&val);
+ //stop when vBat>4V
+ if(val>130){
+ call PMIC.enableManualCharging(FALSE);
+ call chargeMonitorTimer.stop();
+ }
+ return;
+ }
+
+
+}