[Gta04-owner] [PATCH] twl4030_charger: add software controlled linear charging mode.
Dr. H. Nikolaus Schaller
hns at goldelico.com
Thu Sep 26 15:19:40 CEST 2013
Hi Ben,
thanks for the patch. I have applied it and now the /sys/.../lin file is back again.
One question (maybe to Andreas): "on" sets the variable do_lin=1 and "auto" resets it if it was on. But "off" does not set it to 0. Is this intended behaviour?
BR,
Nikolaus
Am 26.09.2013 um 03:21 schrieb benjamin deering:
> From: Ben Deering <ben_deering at swissmail.org>
>
> Make the needed changes to Andreas Kemnade's software controlled linear
> charging patch so it will work with the 3.12 kernel
>
> Signed-off-by: Ben Deering <ben_deering at swissmail.org>
> ---
> drivers/power/twl4030_charger.c | 100 ++++++++++++++++++++++++++++++++++++----
> 1 file changed, 92 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
> index e9de746..33be55d 100644
> --- a/drivers/power/twl4030_charger.c
> +++ b/drivers/power/twl4030_charger.c
> @@ -24,6 +24,8 @@
> #include <linux/usb/otg.h>
> #include <linux/regulator/machine.h>
>
> +#define TWL4030_BCIMDEN 0x00
> +#define TWL4030_BCIMDKEY 0x01
> #define TWL4030_BCIMSTATEC 0x02
> #define TWL4030_BCIICHG 0x08
> #define TWL4030_BCIVAC 0x0a
> @@ -34,6 +36,8 @@
> #define TWL4030_BCIIREF1 0x27
> #define TWL4030_BCIIREF2 0x28
> #define TWL4030_BCIMFKEY 0x11
> +#define TWL4030_BCIMFEN3 0x14
> +#define TWL4030_BCIWDKEY 0x21
>
>
>
> @@ -43,6 +47,7 @@
> #define TWL4030_BCIAUTOAC BIT(0)
> #define TWL4030_CGAIN BIT(5)
> #define TWL4030_USBFASTMCHG BIT(2)
> +#define TWL4030_USBSLOWMCHG BIT(1)
> #define TWL4030_STS_VBUS BIT(7)
> #define TWL4030_STS_USB_ID BIT(2)
> #define TWL4030_BBCHEN BIT(4)
> @@ -84,6 +89,7 @@ static bool allow_usb;
> module_param(allow_usb, bool, 0644);
> MODULE_PARM_DESC(allow_usb, "Allow USB charge drawing default current");
>
> +static int do_lin;
> static int default_usb_current = 100000;
> module_param(default_usb_current, int, 0644);
> MODULE_PARM_DESC(default_usb_current, "Default usb current for newly connected devices in uA");
> @@ -262,16 +268,37 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable)
> twl4030_charger_set_max_current(600000);
> else
> twl4030_charger_set_max_current(default_usb_current);
> - /* forcing the field BCIAUTOUSB (BOOT_BCI[1]) to 1 */
> - ret = twl4030_clear_set_boot_bci(0, TWL4030_BCIAUTOUSB);
> - if (ret < 0)
> - return ret;
> -
> + if (!do_lin) {
> + /* forcing the field BCIAUTOUSB (BOOT_BCI[1]) to 1 */
> + ret = twl4030_clear_set_boot_bci(0, TWL4030_BCIAUTOUSB);
> + if (ret < 0)
> + return ret;
> + }
> /* forcing USBFASTMCHG(BCIMFSTS4[2]) to 1 */
> - ret = twl4030_clear_set(TWL_MODULE_MAIN_CHARGE, 0,
> + ret = twl4030_clear_set(TWL_MODULE_MAIN_CHARGE,
> + TWL4030_USBSLOWMCHG,
> TWL4030_USBFASTMCHG, TWL4030_BCIMFSTS4);
> + if (do_lin) {
> + ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x33,
> + TWL4030_BCIWDKEY);
> + ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x2a,
> + TWL4030_BCIMDKEY);
> + ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x26,
> + TWL4030_BCIMDKEY);
> + ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0xf3,
> + TWL4030_BCIWDKEY);
> + ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x9c,
> + TWL4030_BCIMFKEY);
> + ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0xf0,
> + TWL4030_BCIMFEN3);
> + }
> } else {
> - ret = twl4030_clear_set_boot_bci(TWL4030_BCIAUTOUSB, 0);
> + if (!do_lin) {
> + ret = twl4030_clear_set_boot_bci(TWL4030_BCIAUTOUSB, 0);
> + } else {
> + ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x2a,
> + TWL4030_BCIMDKEY);
> + }
> if (bci->usb_enabled) {
> regulator_disable(bci->usb_reg);
> bci->usb_enabled = 0;
> @@ -427,6 +454,58 @@ static int twl4030_bci_usb_ncb(struct notifier_block *nb, unsigned long val,
> return NOTIFY_OK;
> }
>
> +static ssize_t
> +twl4030_bci_lin_show(struct device *dev, struct device_attribute *attr,
> + char *buf)
> +{
> + int ret = -EINVAL;
> + u8 val;
> + twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE, &val, TWL4030_BCIMDEN);
> + ret = sprintf(buf, "%d\n", (int)val);
> + return ret;
> +}
> +
> +static ssize_t
> +twl4030_bci_lin_store(struct device *dev, struct device_attribute *attr,
> + const char *buf, size_t n)
> +{
> + unsigned long flags;
> + int status = 0;
> + if (sysfs_streq(buf, "on")) {
> + status = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, 0x30,
> + TWL4030_PM_MASTER_BOOT_BCI);
> +
> + status = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x33,
> + TWL4030_BCIWDKEY);
> + status = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x2a,
> + TWL4030_BCIMDKEY);
> + status = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x26,
> + TWL4030_BCIMDKEY);
> + status = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0xf3,
> + TWL4030_BCIWDKEY);
> + do_lin = 1;
> +
> + } else if (sysfs_streq(buf, "off")) {
> + status = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x2a,
> + TWL4030_BCIMDKEY);
do_lin = 0; ????
> + } else if (sysfs_streq(buf, "auto")) {
> + if (do_lin) {
> + struct twl4030_bci *bci = dev_get_drvdata(dev);
> + status = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE,
> + 0x2a, TWL4030_BCIMDKEY);
> + do_lin = 0;
> + twl4030_charger_enable_usb(bci, true);
> + }
> + } else {
> + return -EINVAL;
> + }
> +
> +
> + return (status == 0) ? n : status;
> +}
> +
> +static DEVICE_ATTR(lin, 0644, twl4030_bci_lin_show, twl4030_bci_lin_store);
> +
>
> /*
> * sysfs max_current store
> @@ -524,6 +603,7 @@ static int twl4030_bci_get_property(struct power_supply *psy,
> int is_charging;
> int state;
> int ret;
> + u8 i2cval;
>
> state = twl4030bci_state(bci);
> if (state < 0)
> @@ -560,7 +640,8 @@ static int twl4030_bci_get_property(struct power_supply *psy,
> }
> break;
> case POWER_SUPPLY_PROP_CURRENT_NOW:
> - if (!is_charging)
> + twl4030_bci_read(TWL4030_BCIMFEN3, &i2cval);
> + if ((!is_charging) && (i2cval == 0))
> return -ENODATA;
> /* current measurement is shared between AC and USB */
> ret = twl4030_charger_get_current();
> @@ -673,6 +754,8 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
>
> if (device_create_file(&pdev->dev, &dev_attr_max_current))
> dev_warn(&pdev->dev, "could not create sysfs file\n");
> + if (device_create_file(&pdev->dev, &dev_attr_lin))
> + dev_warn(&pdev->dev, "could not create sysfs file\n");
>
>
> twl4030_charger_enable_ac(true);
> @@ -704,6 +787,7 @@ static int __exit twl4030_bci_remove(struct platform_device *pdev)
> {
> struct twl4030_bci *bci = platform_get_drvdata(pdev);
> device_remove_file(&pdev->dev, &dev_attr_max_current);
> + device_remove_file(&pdev->dev, &dev_attr_lin);
> twl4030_charger_enable_ac(false);
> twl4030_charger_enable_usb(bci, false);
> twl4030_charger_enable_backup(0, 0);
> --
> 1.7.12
>
> _______________________________________________
> Gta04-owner mailing list
> Gta04-owner at goldelico.com
> http://lists.goldelico.com/mailman/listinfo/gta04-owner
More information about the Gta04-owner
mailing list