/* * Enable/disable hardware battery presence event notifications. */ static int twl4030battery_hw_presence_en(int enable) { int ret; if (enable) { /* unmask BATSTS interrupt for INT1 */ ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, BATSTS_IMR1, 0, REG_BCIIMR1A); if (ret) return ret; /* configuring interrupt edge for BATSTS */ ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, 0, BATSTS_EDRRISIN | BATSTS_EDRFALLING, REG_BCIEDR2); if (ret) return ret; } else { /* mask BATSTS interrupt for INT1 */ ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, 0, BATSTS_IMR1, REG_BCIIMR1A); if (ret) return ret; } return 0; }
/* * Enable/Disable AC Charge funtionality. */ static int twl4030charger_ac_en(int enable) { int ret; if (enable) { /* Set the charging current for AC */ ret = twl4030charger_cur_setup(AC_CURRENT, bci_charging_current); if (ret) return ret; /* forcing the field BCIAUTOAC (BOOT_BCI[0) to 1 */ ret = clear_n_set(TWL4030_MODULE_PM_MASTER, 0, (CONFIG_DONE | BCIAUTOWEN | BCIAUTOAC), REG_BOOT_BCI); if (ret) return ret; } else { /* forcing the field BCIAUTOAC (BOOT_BCI[0) to 0*/ ret = clear_n_set(TWL4030_MODULE_PM_MASTER, BCIAUTOAC, (CONFIG_DONE | BCIAUTOWEN), REG_BOOT_BCI); if (ret) return ret; } return 0; }
/* * Enable/Disable hardware battery level event notifications. */ static int twl4030battery_hw_level_en(int enable) { int ret; if (enable) { /* unmask VBATOV interrupt for INT1 */ ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, VBATLVL_IMR1, 0, REG_BCIIMR2A); if (ret) return ret; /* configuring interrupt edge detection for VBATOv */ ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, 0, VBATLVL_EDRRISIN, REG_BCIEDR3); if (ret) return ret; } else { /* mask VBATOV interrupt for INT1 */ ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, 0, VBATLVL_IMR1, REG_BCIIMR2A); if (ret) return ret; } return 0; }
static int read_bci_val(u8 reg) { int ret, temp; u8 val = 0; // 20100816 [email protected] Set TWL4030 register for MADC voltage check [START_LGE] ret = clear_n_set(TWL4030_MODULE_MAIN_CHARGE, 0, USBFASTMCHG, REG_BCIMFSTS4); // 20100816 [email protected] Set TWL4030 register for MADC voltage check [END_LGE] /* reading MSB */ ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val, reg + 1); if (ret) return ret; temp = ((int)(val & 0x03)) << 8; /* reading LSB */ ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val, reg); if (ret) return ret; return temp | val; }
/* * Report and clear the charger presence event. */ static inline int twl4030charger_presence_evt(void) { int ret = 0; u8 chg_sts = 0, set = 0, clear = 0; /* read charger power supply status */ ret = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &chg_sts, REG_STS_HW_CONDITIONS); if (ret) return IRQ_NONE; if (chg_sts & STS_CHG) { /* If the AC charger have been connected */ /* configuring falling edge detection for CHG_PRES */ set = CHG_PRES_FALLING; clear = CHG_PRES_RISING; } else { /* If the AC charger have been disconnected */ /* configuring rising edge detection for CHG_PRES */ set = CHG_PRES_RISING; clear = CHG_PRES_FALLING; } /* Update the interrupt edge detection register */ clear_n_set(TWL4030_MODULE_INT, clear, set, REG_PWR_EDR1); return 0; }
static int twl4030battery_presence_evt(void) { int ret; u8 batstsmchg, batstspchg; /* In case of invalid service event function abandon */ if (twl4030battery_event.battery_presence == NULL) return -ENXIO; /* checking for battery presence in main charge*/ if ((ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &batstsmchg, REG_BCIMFSTS3))) return ret; /* checking for battery presence in precharge*/ if ((ret = twl4030_i2c_read_u8(TWL4030_MODULE_PRECHARGE, &batstspchg, REG_BCIMFSTS1))) return ret; /* In case of the battery insertion event */ if ((batstspchg & BATSTSPCHG) || (batstsmchg & BATSTSMCHG)) { /* calling the battery presence event service function */ twl4030battery_event.battery_presence(EVT_BATTSTS_CONN); ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, BATSTS_EDRRISIN, BATSTS_EDRFALLING, REG_BCIEDR2); if (ret) return ret; } /* In case of the battery removal event */ else { /* calling the battery presence event service function */ twl4030battery_event.battery_presence(EVT_BATTSTS_DISC); ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, BATSTS_EDRFALLING, BATSTS_EDRRISIN, REG_BCIEDR2); if (ret) return ret; } return 0; }
/* * Settup the twl4030 BCI module to enable backup * battery charging. */ static int twl4030backupbatt_voltage_setup(void) { int ret; /* Starting backup batery charge */ ret = clear_n_set(TWL4030_MODULE_PM_RECEIVER, 0, BBCHEN, REG_BB_CFG); if (ret) return ret; return 0; }
/* * Settup the twl4030 BCI module to measure battery * temperature */ static int twl4030battery_temp_setup(void) { int ret; /* Enabling thermistor current */ ret = clear_n_set(TWL4030_MODULE_MAIN_CHARGE, 0, ITHEN, REG_BCICTL1); if (ret) return ret; return 0; }
/* * Enable/Disable AC Charge funtionality. */ static int twl4030charger_ac_en(int enable) { int ret; if (enable) { /* forcing the field BCIAUTOAC (BOOT_BCI[0) to 1 */ ret = clear_n_set(TWL4030_MODULE_PM_MASTER, 0, (CONFIG_DONE | BCIAUTOWEN | BCIAUTOAC), REG_BOOT_BCI); if (ret) return ret; } else { /* forcing the field BCIAUTOAC (BOOT_BCI[0) to 0*/ ret = clear_n_set(TWL4030_MODULE_PM_MASTER, BCIAUTOAC, (CONFIG_DONE | BCIAUTOWEN), REG_BOOT_BCI); if (ret) return ret; } return 0; }
/* * This function handles the twl4030 battery presence interrupt */ static int twl4030battery_presence_evt(void) { int ret; u8 batstsmchg = 0, batstspchg = 0; /* check for the battery presence in main charge*/ ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &batstsmchg, REG_BCIMFSTS3); if (ret) return ret; /* check for the battery presence in precharge */ ret = twl_i2c_read_u8(TWL4030_MODULE_PRECHARGE, &batstspchg, REG_BCIMFSTS1); if (ret) return ret; /* * REVISIT: Physically inserting/removing the batt * does not seem to generate an int on 3430ES2 SDP. */ if ((batstspchg & BATSTSPCHG) || (batstsmchg & BATSTSMCHG)) { /* In case of the battery insertion event */ ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, BATSTS_EDRRISIN, BATSTS_EDRFALLING, REG_BCIEDR2); if (ret) return ret; } else { /* In case of the battery removal event */ ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, BATSTS_EDRFALLING, BATSTS_EDRRISIN, REG_BCIEDR2); if (ret) return ret; } return 0; }
/* * Enable/Disable USB Charge funtionality. */ int twl4030charger_usb_en(int enable) { u8 value; int ret; unsigned long timeout; if (enable) { /* Check for USB charger conneted */ ret = twl4030charger_presence(); if (ret < 0) return ret; if (!(ret & USB_PW_CONN)) return -ENXIO; /* Set the charging current for USB */ ret = twl4030charger_cur_setup(USB_CURRENT, bci_charging_current); if (ret) return ret; /* forcing the field BCIAUTOUSB (BOOT_BCI[1]) to 1 */ ret = clear_n_set(TWL4030_MODULE_PM_MASTER, 0, (CONFIG_DONE | BCIAUTOWEN | BCIAUTOUSB), REG_BOOT_BCI); if (ret) return ret; ret = clear_n_set(TWL4030_MODULE_USB, 0, PHY_DPLL_CLK, REG_PHY_CLK_CTRL); if (ret) return ret; value = 0; timeout = jiffies + msecs_to_jiffies(50); while ((!(value & PHY_DPLL_CLK)) && time_before(jiffies, timeout)) { udelay(10); ret = twl4030_i2c_read_u8(TWL4030_MODULE_USB, &value, REG_PHY_CLK_CTRL_STS); if (ret) return ret; } /* OTG_EN (POWER_CTRL[5]) to 1 */ ret = clear_n_set(TWL4030_MODULE_USB, 0, OTG_EN, REG_POWER_CTRL); if (ret) return ret; mdelay(50); /* forcing USBFASTMCHG(BCIMFSTS4[2]) to 1 */ ret = clear_n_set(TWL4030_MODULE_MAIN_CHARGE, 0, USBFASTMCHG, REG_BCIMFSTS4); if (ret) return ret; } else { twl4030charger_presence(); ret = clear_n_set(TWL4030_MODULE_PM_MASTER, BCIAUTOUSB, (CONFIG_DONE | BCIAUTOWEN), REG_BOOT_BCI); if (ret) return ret; } return 0; }
static int twl4030charger_cur_setup(int charging_source, int bci_charging_current) { int ret; u8 cgain = 0, bciref1 = 0, bciref2 = 0, value = 0; if (charging_source == AC_CURRENT) { /* Disable AutoAC till the CGAIN is setup */ ret = clear_n_set(TWL4030_MODULE_PM_MASTER, BCIAUTOAC, (CONFIG_DONE | BCIAUTOWEN), REG_BOOT_BCI); if (ret) return ret; } else { /* Disable AutoUSB till CGAIN is setup */ ret = clear_n_set(TWL4030_MODULE_PM_MASTER, BCIAUTOUSB, (CONFIG_DONE | BCIAUTOWEN), REG_BOOT_BCI); if (ret) return ret; } switch (bci_charging_current) { case 1100: /* 1100 mA */ bciref1 = 0x58; bciref2 = 0x03; cgain = 1; break; case 852: /* 852 mA */ bciref1 = 0xFF; bciref2 = 0x03; cgain = 0; break; case 100: /* 100 mA */ bciref1 = 0x3C; bciref2 = 0x02; cgain = 0; break; default: /* Charging current as per reset values i,e 600mA */ printk(KERN_INFO "Unsupported charging current\n"); } /* enable access to BCIIREF1 */ ret = twl4030_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE, 0xE7, REG_BCIMFKEY); if (ret) return ret; ret = twl4030_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE, bciref1, REG_BCIIREF1); if (ret) return ret; /* enable access to BCIIREF2 */ ret = twl4030_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE, 0xE7, REG_BCIMFKEY); if (ret) return ret; ret = twl4030_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE, bciref2, REG_BCIIREF2); if (ret) return ret; ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &value, REG_BCICTL1); if (ret) return ret; if (cgain == 0) value = value & ~(CGAIN); else value = value | CGAIN; ret = twl4030_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE, value, REG_BCICTL1); if (ret) return ret; return 0; }
/* * Helper function * * This fucntion drives charger power supply events */ static int twl4030charger_presence_evt (void) { int ret, event = 0; u8 chg_sts, set = 0, clear = 0; /* * if there is no event sevice routine there is no need to do * anything. */ if (twl4030battery_event.charger_presence == NULL) return -ENXIO; /* checking charger power supply status */ ret = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER,&chg_sts, REG_STS_HW_CONDITIONS); if (ret) return IRQ_NONE; /* If the AC charger have been connected*/ if (chg_sts & STS_CHG) { /* configuring falling edge detection for CHG_PRES */ set = CHG_PRES_FALLING; clear = CHG_PRES_RISING; event = EVT_PWSPLY_AC_CONN; } /* If the AC charger have been disconnected*/ else { /* configuring rising edge detection for CHG_PRES */ set = CHG_PRES_RISING; clear = CHG_PRES_FALLING; event = EVT_PWSPLY_AC_DISC; } /* If the USB charger have been connected*/ if (chg_sts & STS_VBUS) { /* configuring falling edge detection for USB_PRES */ set |= USB_PRES_FALLING; clear |= USB_PRES_RISING; event |= EVT_PWSPLY_USB_CONN; } /* If the USB charger have been disconnected*/ else { /* * configuring interrupt edge detection * for USB_PRES and CHG_PRES. */ set |= USB_PRES_RISING; clear |= USB_PRES_FALLING; event |= EVT_PWSPLY_USB_DISC; } /* Update the interrupt edge detection register */ ret = clear_n_set(TWL4030_MODULE_INT, clear, set, REG_PWR_EDR1); if (ret) return 0; /* Calling to the charger presence event service routine */ twl4030battery_event.charger_presence(event); return 0; }