[Gta04-owner] [PATCH] twl4030_charger: add software controlled linear charging mode.

benjamin deering ben_deering at swissmail.org
Thu Sep 26 03:21:57 CEST 2013


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);
+       } 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



More information about the Gta04-owner mailing list