hi gregoire, i did not mention about charge current. the sysfs entry charge_current always returns 360. -- Best Regards Pramod On Fri, Sep 11, 2009 at 7:21 PM, pramod gurav <pramodforum@xxxxxxxxx> wrote: > Hello gregoire, > > Really sorry I could not reply to your mail as I was busy with some other work. > I applied your above patch tested. The sysfs entries return correct > values for status, charger device(online), voltage_now. But the > current across the battery is reported wrong. I compared the values > returned by current_now sysfs entry with multimeter values across the > battery. The values were varying whenever I remove AC and plug it > back. But what I could see was the current_now value was approximately > double the actual current across the battery. > Without your patch the twl4030_bci gives wrong values for current_now, > voltage_now, capacity etc. > But your patch fixes this issue. > > But the USB charging did not work. Is USB charging functional with > TWL4030 on any of the OMAP boards? > > > Don't mind for the late reply. Thanks for your help. > > -- > Thanks and Best Regards > Pramod > > On Wed, Aug 5, 2009 at 9:48 PM, Gregoire Gentil <gregoire@xxxxxxxxxx> wrote: >> Hello, >> >> Any feed-back on the patch I sent? Have you tried it? Have you fixed >> your problem? >> >> Grégoire >> >> >> On Fri, 2009-07-31 at 23:41 -0700, Gregoire Gentil wrote: >>> On Fri, 2009-07-31 at 19:19 +0530, pramod gurav wrote: >>> > Hi All, >>> > I was trying to get the USB battery charging working over TPS65950 BCI >>> > on the OMAP3430 custom board. I am working with linux-omap-2.6 >>> > v2.6.28-omap1 tag. I enabled the TWL4030 MADC and TWL4030 BCI drivers. >>> > I passed interrupt details to these drivers from platform_device >>> > structure from my board file. I could get the AC charging working. The >>> > AC and USB detection worked. However the USB charging is not >>> > happening. >>> > I read through the TPS TRM and took the dumps of the registers from >>> > BCI and some from TWL USB module and BOOT_BCI whenever I plug in the >>> > USB charger between host and the board. The register settings seem to >>> > be fine. But the battery is not charging. I am using BQ27000 chip for >>> > battery monitoring and I can see the battery voltage is decreasing. >>> > >>> > Following are the register dumps of TWL with and without USB plugged in: >>> > >>> > These are the register contents when USB charger is plugged in: >>> > BCIMDEN = 0x11 >>> > REG_BOOT_BCI = 0x37 >>> > REG_POWER_CTRL = 0x20 >>> > REG_BCIMFSTS4 = 0xf4 >>> > REG_BCIMFSTS1 = 0x13 >>> > REG_BCIIREF1 = 0x68 >>> > REG_BCIIREF2 = 0x3 >>> > REG_BCIMFEN4 = 0x6f >>> > REG_BCIMFSTS2 = 0x0 >>> > REG_BCIMSTATEC = 0x12 >>> > REG_STS_HW_CONDITIONS= 0x90 >>> > >>> > >>> > These are the register contents when USB charger is plugged out: >>> > BCIMDEN = 0x0 >>> > REG_BOOT_BCI = 0x35 >>> > REG_POWER_CTRL = 0x20 >>> > REG_BCIMFSTS4 = 0xf0 >>> > REG_BCIMFSTS1 = 0xaa >>> > REG_BCIIREF1 = 0x68 >>> > REG_BCIIREF2 = 0x3 >>> > REG_BCIMFEN4 = 0x68 >>> > REG_BCIMFSTS2 = 0x0 >>> > REG_BCIMSTATEC =0x0 >>> > REG_STS_HW_CONDITIONS= 0x10 >>> > >>> > Is there anything more I need to support to get BCI USB charging >>> > working? Need I follow any USB Communication protocol between Host and >>> > the board. >>> > I have pasted the kernel boot logs for reference at the end. >>> > Can any one please guide me to some pointers? >>> > >>> > -- >>> > Best Regards >>> > Pramod >>> I'm experiencing some problems with TWL4030 DC charging and I'm >>> interested by this kind of problem. Basically, the values reported by >>> our patch is different from the current going to the battery. We wrote >>> the attached enhanced patch so as to edit at run-time the charging mode >>> and various values including charge_current. It's against 2.6.29 but I >>> think that it should work again 2.6.28. Unfortunately, starting 2.6.30, >>> Tony has removed all the BCI battery code and has asked for updated code >>> against mainline but I've not seen anything so far. >>> >>> Pramod, can you try the attached patch (perhaps, it will help you) and >>> can you tell if you see the exact current going to the battery reported >>> by the driver? >>> >>> Grégoire >>> >>> >>> >>> >>> >>> --- a/drivers/power/twl4030_bci_battery.c 2009-07-22 18:27:16.000000000 >>> -0700 >>> +++ b/drivers/power/twl4030_bci_battery.c 2009-07-22 18:30:22.000000000 >>> -0700 >>> @@ -15,6 +15,9 @@ >>> * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. >>> */ >>> >>> +/* Boot with automatic charge */ >>> +#define CHARGE_MODE 1 >>> + >>> #include <linux/init.h> >>> #include <linux/module.h> >>> #include <linux/device.h> >>> @@ -50,6 +53,7 @@ >>> /* Boot BCI flag bits */ >>> #define BCIAUTOWEN 0x020 >>> #define CONFIG_DONE 0x010 >>> +#define CVENAC 0x004 >>> #define BCIAUTOUSB 0x002 >>> #define BCIAUTOAC 0x001 >>> #define BCIMSTAT_MASK 0x03F >>> @@ -81,6 +85,11 @@ >>> #define REG_BB_CFG 0x012 >>> #define BBCHEN 0x010 >>> >>> +/* GPBR */ >>> +#define REG_GPBR1 0x0c >>> +#define MADC_HFCLK_EN 0x80 >>> +#define DEFAULT_MADC_CLK_EN 0x10 >>> + >>> /* Power supply charge interrupt */ >>> #define REG_PWR_ISR1 0x00 >>> #define REG_PWR_IMR1 0x01 >>> @@ -125,6 +134,18 @@ >>> /* BCIEDR3 */ >>> #define VBATLVL_EDRRISIN 0x02 >>> >>> +/* BCIIREF1 */ >>> +#define REG_BCIIREF1 0x027 >>> +#define REG_BCIIREF2 0x028 >>> + >>> +/* BCIMFTH1 */ >>> +#define REG_BCIMFTH1 0x016 >>> + >>> +/* Key */ >>> +#define KEY_IIREF 0xE7 >>> +#define KEY_FTH1 0xD2 >>> +#define REG_BCIMFKEY 0x011 >>> + >>> /* Step size and prescaler ratio */ >>> #define TEMP_STEP_SIZE 147 >>> #define TEMP_PSR_R 100 >>> @@ -142,9 +163,6 @@ >>> #define ENABLE 1 >>> #define DISABLE 1 >>> >>> -/* Ptr to thermistor table */ >>> -int *therm_tbl; >>> - >>> struct twl4030_bci_device_info { >>> struct device *dev; >>> >>> @@ -160,6 +178,8 @@ >>> struct power_supply bk_bat; >>> struct delayed_work twl4030_bci_monitor_work; >>> struct delayed_work twl4030_bk_bci_monitor_work; >>> + >>> + struct twl4030_bci_platform_data *pdata; >>> }; >>> >>> static int usb_charger_flag; >>> @@ -425,15 +445,21 @@ >>> /* >>> * Enable/Disable AC Charge funtionality. >>> */ >>> -static int twl4030charger_ac_en(int enable) >>> +static int twl4030charger_ac_en(int enable, int automatic) >>> { >>> 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(!automatic) { >>> + ret = clear_n_set(TWL4030_MODULE_PM_MASTER, BCIAUTOAC | CVENAC, >>> + (CONFIG_DONE | BCIAUTOWEN), >>> + REG_BOOT_BCI); >>> + } else { >>> + ret = clear_n_set(TWL4030_MODULE_PM_MASTER, 0, >>> + (CONFIG_DONE | BCIAUTOWEN | BCIAUTOAC | CVENAC), >>> + REG_BOOT_BCI); >>> + } >>> if (ret) >>> return ret; >>> } else { >>> @@ -518,11 +544,15 @@ >>> * Return battery temperature >>> * Or < 0 on failure. >>> */ >>> -static int twl4030battery_temperature(void) >>> +static int twl4030battery_temperature(struct twl4030_bci_device_info >>> *di) >>> { >>> u8 val; >>> int temp, curr, volt, res, ret; >>> >>> + /* Is a temperature table specified? */ >>> + if (!di->pdata->tblsize) >>> + return 0; >>> + >>> /* Getting and calculating the thermistor voltage */ >>> ret = read_bci_val(T2_BATTERY_TEMP); >>> if (ret < 0) >>> @@ -543,7 +573,7 @@ >>> >>> /*calculating temperature*/ >>> for (temp = 58; temp >= 0; temp--) { >>> - int actual = therm_tbl[temp]; >>> + int actual = di->pdata->battery_tmp_tbl[temp]; >>> if ((actual - res) >= 0) >>> break; >>> } >>> @@ -661,6 +691,9 @@ >>> return ret; >>> } >>> >>> +#ifdef DEBUG >>> + printk("BCI DEBUG: BCIMSTATEC Charge state is 0x%x\n", status); >>> +#endif >>> return (int) (status & BCIMSTAT_MASK); >>> } >>> >>> @@ -709,14 +742,43 @@ >>> */ >>> static int twl4030battery_temp_setup(void) >>> { >>> - int ret; >>> +#ifdef DEBUG >>> + u8 i; >>> +#endif >>> + u8 ret; >>> >>> /* Enabling thermistor current */ >>> - ret = clear_n_set(TWL4030_MODULE_MAIN_CHARGE, 0, ITHEN, >>> + ret = clear_n_set(TWL4030_MODULE_MAIN_CHARGE, 0, 0x1B, >>> REG_BCICTL1); >>> if (ret) >>> return ret; >>> >>> +#ifdef DEBUG >>> + twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &ret, REG_BOOT_BCI); >>> + printk("BCI DEBUG: BOOT_BCI Value is 0x%x\n", ret); >>> + >>> + twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &ret, >>> REG_STS_HW_CONDITIONS); >>> + printk("BCI DEBUG: STS_HW_CONDITIONS Value is 0x%x\n", ret); >>> + >>> + twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &ret, REG_BCICTL1); >>> + printk("BCI DEBUG: BCICTL1 Value is 0x%x\n", ret); >>> + >>> + twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &ret, REG_BCICTL2); >>> + printk("BCI DEBUG: BCICTL2 Value is 0x%x\n", ret); >>> + >>> + twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &ret, 0x0); >>> + printk("BCI DEBUG: BCIMDEN Value is 0x%x\n", ret); >>> + >>> + twl4030_i2c_read_u8(TWL4030_MODULE_INTBR, &ret, REG_GPBR1); >>> + printk("BCI DEBUG: GPBR1 Value is 0x%x\n", ret); >>> + >>> + for(i = 0x0; i <= 0x32; i++) >>> + { >>> + twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &ret, i); >>> + printk("BCI DEBUG: BCI 0x%x Value is 0x%x\n", i, ret); >>> + } >>> +#endif >>> + >>> return 0; >>> } >>> >>> @@ -732,7 +794,6 @@ >>> ret = twl4030_i2c_read_u8(mod_no, &val, reg); >>> if (ret) >>> return ret; >>> - >>> /* Clearing all those bits to clear */ >>> val &= ~(clear); >>> >>> @@ -772,13 +833,14 @@ >>> struct twl4030_bci_device_info, >>> twl4030_bk_bci_monitor_work.work); >>> >>> - twl4030_bk_bci_battery_read_status(di); >>> + if(!di->pdata->no_backup_battery) >>> + twl4030_bk_bci_battery_read_status(di); >>> schedule_delayed_work(&di->twl4030_bk_bci_monitor_work, 500); >>> } >>> >>> static void twl4030_bci_battery_read_status(struct >>> twl4030_bci_device_info *di) >>> { >>> - di->temp_C = twl4030battery_temperature(); >>> + di->temp_C = twl4030battery_temperature(di); >>> di->voltage_uV = twl4030battery_voltage(); >>> di->current_uA = twl4030battery_current(); >>> } >>> @@ -819,6 +881,87 @@ >>> #define to_twl4030_bk_bci_device_info(x) container_of((x), \ >>> struct twl4030_bci_device_info, bk_bat); >>> >>> +static ssize_t >>> +show_charge_current(struct device *dev, struct device_attribute *attr, >>> char *buf) >>> +{ >>> + u8 ctl; >>> + int ret = read_bci_val(REG_BCIIREF1) & 0x1FF; >>> + twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &ctl, REG_BCICTL1); >>> + >>> + if (ctl & CGAIN) >>> + ret |= 0x200; >>> + >>> +#ifdef DEBUG >>> + /* Dump debug */ >>> + twl4030battery_temp_setup(); >>> +#endif >>> + >>> + return sprintf(buf, "%d\n", ret); >>> +} >>> + >>> +static ssize_t >>> +set_charge_current(struct device *dev, struct device_attribute *attr, >>> const char *buf, size_t count) >>> +{ >>> + unsigned long newCurrent; >>> + int ret; >>> + >>> + ret = strict_strtoul(buf, 10, &newCurrent); >>> + if (ret) >>> + return -EINVAL; >>> + >>> + ret = twl4030_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE, KEY_IIREF, >>> REG_BCIMFKEY); >>> + if (ret) >>> + return ret; >>> + >>> + ret = twl4030_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE, newCurrent & >>> 0xff, REG_BCIIREF1); >>> + if (ret) >>> + return ret; >>> + >>> + ret = twl4030_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE, KEY_IIREF, >>> REG_BCIMFKEY); >>> + if (ret) >>> + return ret; >>> + >>> + ret = twl4030_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE, (newCurrent >> >>> 8) & 0x1, REG_BCIIREF2); >>> + if (ret) >>> + return ret; >>> + >>> + /* Set software-controlled charge */ >>> + twl4030charger_ac_en(ENABLE, 0); >>> + >>> + /* Set CGAIN = 0 or 1 */ >>> + if(newCurrent > 511) { >>> + u8 tmp; >>> + >>> + /* Set CGAIN = 1 -- need to wait until automatic charge turns off */ >>> + while(!ret) { >>> + clear_n_set(TWL4030_MODULE_MAIN_CHARGE, 0, CGAIN | 0x1B, >>> REG_BCICTL1); >>> + twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &tmp, REG_BCICTL1); >>> + >>> + ret = tmp & CGAIN; >>> + if(!ret) >>> + mdelay(50); >>> + } >>> + } else { >>> + u8 tmp; >>> + >>> + /* Set CGAIN = 0 -- need to wait until automatic charge turns off */ >>> + while(!ret) { >>> + clear_n_set(TWL4030_MODULE_MAIN_CHARGE, CGAIN, 0x1B, REG_BCICTL1); >>> + twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &tmp, REG_BCICTL1); >>> + >>> + ret = !(tmp & CGAIN); >>> + if(!ret) >>> + mdelay(50); >>> + } >>> + } >>> + >>> + /* Set automatic charge (CGAIN = 0/1 persists) */ >>> + twl4030charger_ac_en(ENABLE, 1); >>> + >>> + return count; >>> +} >>> +static DEVICE_ATTR(charge_current, S_IRUGO | S_IWUSR, >>> show_charge_current, set_charge_current); >>> + >>> static int twl4030_bk_bci_battery_get_property(struct power_supply >>> *psy, >>> enum power_supply_property psp, >>> union power_supply_propval *val) >>> @@ -912,8 +1055,6 @@ >>> int irq; >>> int ret; >>> >>> - therm_tbl = pdata->battery_tmp_tbl; >>> - >>> di = kzalloc(sizeof(*di), GFP_KERNEL); >>> if (!di) >>> return -ENOMEM; >>> @@ -937,8 +1078,12 @@ >>> di->bk_bat.num_properties = ARRAY_SIZE(twl4030_bk_bci_battery_props); >>> di->bk_bat.get_property = twl4030_bk_bci_battery_get_property; >>> di->bk_bat.external_power_changed = NULL; >>> + di->pdata = pdata; >>> >>> - twl4030charger_ac_en(ENABLE); >>> + /* Set up clocks */ >>> + twl4030_i2c_write_u8(TWL4030_MODULE_INTBR, MADC_HFCLK_EN | >>> DEFAULT_MADC_CLK_EN, REG_GPBR1); >>> + >>> + twl4030charger_ac_en(ENABLE, CHARGE_MODE); >>> twl4030charger_usb_en(ENABLE); >>> twl4030battery_hw_level_en(ENABLE); >>> twl4030battery_hw_presence_en(ENABLE); >>> @@ -951,9 +1096,12 @@ >>> goto temp_setup_fail; >>> >>> /* enabling GPCH09 for read back battery voltage */ >>> - ret = twl4030backupbatt_voltage_setup(); >>> - if (ret) >>> - goto voltage_setup_fail; >>> + if(!di->pdata->no_backup_battery) >>> + { >>> + ret = twl4030backupbatt_voltage_setup(); >>> + if (ret) >>> + goto voltage_setup_fail; >>> + } >>> >>> /* REVISIT do we need to request both IRQs ?? */ >>> >>> @@ -988,9 +1136,18 @@ >>> twl4030_bci_battery_work); >>> schedule_delayed_work(&di->twl4030_bci_monitor_work, 0); >>> >>> - ret = power_supply_register(&pdev->dev, &di->bk_bat); >>> + if(!pdata->no_backup_battery) >>> + { >>> + ret = power_supply_register(&pdev->dev, &di->bk_bat); >>> + if (ret) { >>> + dev_dbg(&pdev->dev, "failed to register backup battery\n"); >>> + goto bk_batt_failed; >>> + } >>> + } >>> + >>> + ret = device_create_file(di->bat.dev, &dev_attr_charge_current); >>> if (ret) { >>> - dev_dbg(&pdev->dev, "failed to register backup battery\n"); >>> + dev_err(&pdev->dev, "failed to create sysfs entries\n"); >>> goto bk_batt_failed; >>> } >>> >>> @@ -1001,7 +1158,8 @@ >>> return 0; >>> >>> bk_batt_failed: >>> - power_supply_unregister(&di->bat); >>> + if(!pdata->no_backup_battery) >>> + power_supply_unregister(&di->bat); >>> batt_failed: >>> free_irq(irq, di); >>> chg_irq_fail: >>> @@ -1010,7 +1168,7 @@ >>> batt_irq_fail: >>> voltage_setup_fail: >>> temp_setup_fail: >>> - twl4030charger_ac_en(DISABLE); >>> + twl4030charger_ac_en(DISABLE, CHARGE_MODE); >>> twl4030charger_usb_en(DISABLE); >>> twl4030battery_hw_level_en(DISABLE); >>> twl4030battery_hw_presence_en(DISABLE); >>> @@ -1024,7 +1182,7 @@ >>> struct twl4030_bci_device_info *di = platform_get_drvdata(pdev); >>> int irq; >>> >>> - twl4030charger_ac_en(DISABLE); >>> + twl4030charger_ac_en(DISABLE, CHARGE_MODE); >>> twl4030charger_usb_en(DISABLE); >>> twl4030battery_hw_level_en(DISABLE); >>> twl4030battery_hw_presence_en(DISABLE); >>> --- a/include/linux/i2c/twl4030.h >>> +++ b/include/linux/i2c/twl4030.h >>> @@ -299,6 +299,8 @@ int twl4030_i2c_read(u8 mod_no, u8 *value, u8 reg, >>> unsigned num_bytes); >>> struct twl4030_bci_platform_data { >>> int *battery_tmp_tbl; >>> unsigned int tblsize; >>> + >>> + bool no_backup_battery; >>> }; >>> >>> /* TWL4030_GPIO_MAX (18) GPIOs, with interrupts */ >>> >> >> > -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html