aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeilBrown <neil@brown.name>2015-07-29 20:11:24 -0400
committerSebastian Reichel <sre@kernel.org>2015-08-04 23:15:25 -0400
commit1098cb58aed8eb4e06302d947a38bbfb69c8b4ba (patch)
tree608d82f41ee74396b9689c665b195974e03ad262
parent3b542f089dcbdcf1c21a01927fbc6d5116af01f6 (diff)
twl4030_charger: allow fine control of charger current.
The twl4030 allows control of the incoming current. Part of this control is a 'CGAIN' setting which doubles the range for half the precision. This control affects several different current setting, so all need to be updated at once when CGAIN is changed. With this patch, all of these current setting are managed by the driver, but most are left at their default settings. The current drawn is set to 500mA if the allow_usb module parameter is set, and to 100mA otherwise. More fine control will appear in later patches. Acked-by: Pavel Machek <pavel@ucw.cz> Signed-off-by: NeilBrown <neil@brown.name> Signed-off-by: Sebastian Reichel <sre@kernel.org>
-rw-r--r--drivers/power/twl4030_charger.c168
1 files changed, 160 insertions, 8 deletions
diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index 29984b263a35..3b7cc631bb8a 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -31,6 +31,11 @@
31#define TWL4030_BCIMFSTS4 0x10 31#define TWL4030_BCIMFSTS4 0x10
32#define TWL4030_BCICTL1 0x23 32#define TWL4030_BCICTL1 0x23
33#define TWL4030_BB_CFG 0x12 33#define TWL4030_BB_CFG 0x12
34#define TWL4030_BCIIREF1 0x27
35#define TWL4030_BCIIREF2 0x28
36#define TWL4030_BCIMFKEY 0x11
37#define TWL4030_BCIMFTH8 0x1d
38#define TWL4030_BCIMFTH9 0x1e
34 39
35#define TWL4030_BCIMFSTS1 0x01 40#define TWL4030_BCIMFSTS1 0x01
36 41
@@ -95,6 +100,12 @@ struct twl4030_bci {
95 int irq_bci; 100 int irq_bci;
96 int usb_enabled; 101 int usb_enabled;
97 102
103 /*
104 * ichg values in uA. If any are 'large', we set CGAIN to
105 * '1' which doubles the range for half the precision.
106 */
107 unsigned int ichg_eoc, ichg_lo, ichg_hi, cur;
108
98 unsigned long event; 109 unsigned long event;
99}; 110};
100 111
@@ -211,6 +222,146 @@ static int ua2regval(int ua, bool cgain)
211 return ret; 222 return ret;
212} 223}
213 224
225static int twl4030_charger_update_current(struct twl4030_bci *bci)
226{
227 int status;
228 unsigned reg, cur_reg;
229 u8 bcictl1, oldreg, fullreg;
230 bool cgain = false;
231 u8 boot_bci;
232
233 /* First, check thresholds and see if cgain is needed */
234 if (bci->ichg_eoc >= 200000)
235 cgain = true;
236 if (bci->ichg_lo >= 400000)
237 cgain = true;
238 if (bci->ichg_hi >= 820000)
239 cgain = true;
240 if (bci->cur > 852000)
241 cgain = true;
242
243 status = twl4030_bci_read(TWL4030_BCICTL1, &bcictl1);
244 if (status < 0)
245 return status;
246 if (twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &boot_bci,
247 TWL4030_PM_MASTER_BOOT_BCI) < 0)
248 boot_bci = 0;
249 boot_bci &= 7;
250
251 if ((!!cgain) != !!(bcictl1 & TWL4030_CGAIN))
252 /* Need to turn for charging while we change the
253 * CGAIN bit. Leave it off while everything is
254 * updated.
255 */
256 twl4030_clear_set_boot_bci(boot_bci, 0);
257
258 /*
259 * For ichg_eoc, the hardware only supports reg values matching
260 * 100XXXX000, and requires the XXXX be stored in the high nibble
261 * of TWL4030_BCIMFTH8.
262 */
263 reg = ua2regval(bci->ichg_eoc, cgain);
264 if (reg > 0x278)
265 reg = 0x278;
266 if (reg < 0x200)
267 reg = 0x200;
268 reg = (reg >> 3) & 0xf;
269 fullreg = reg << 4;
270
271 /*
272 * For ichg_lo, reg value must match 10XXXX0000.
273 * XXXX is stored in low nibble of TWL4030_BCIMFTH8.
274 */
275 reg = ua2regval(bci->ichg_lo, cgain);
276 if (reg > 0x2F0)
277 reg = 0x2F0;
278 if (reg < 0x200)
279 reg = 0x200;
280 reg = (reg >> 4) & 0xf;
281 fullreg |= reg;
282
283 /* ichg_eoc and ichg_lo live in same register */
284 status = twl4030_bci_read(TWL4030_BCIMFTH8, &oldreg);
285 if (status < 0)
286 return status;
287 if (oldreg != fullreg) {
288 status = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0xF4,
289 TWL4030_BCIMFKEY);
290 if (status < 0)
291 return status;
292 twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE,
293 fullreg, TWL4030_BCIMFTH8);
294 }
295
296 /* ichg_hi threshold must be 1XXXX01100 (I think) */
297 reg = ua2regval(bci->ichg_hi, cgain);
298 if (reg > 0x3E0)
299 reg = 0x3E0;
300 if (reg < 0x200)
301 reg = 0x200;
302 fullreg = (reg >> 5) & 0xF;
303 fullreg <<= 4;
304 status = twl4030_bci_read(TWL4030_BCIMFTH9, &oldreg);
305 if (status < 0)
306 return status;
307 if ((oldreg & 0xF0) != fullreg) {
308 fullreg |= (oldreg & 0x0F);
309 status = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0xE7,
310 TWL4030_BCIMFKEY);
311 if (status < 0)
312 return status;
313 twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE,
314 fullreg, TWL4030_BCIMFTH9);
315 }
316
317 /*
318 * And finally, set the current. This is stored in
319 * two registers.
320 */
321 reg = ua2regval(bci->cur, cgain);
322 /* we have only 10 bits */
323 if (reg > 0x3ff)
324 reg = 0x3ff;
325 status = twl4030_bci_read(TWL4030_BCIIREF1, &oldreg);
326 if (status < 0)
327 return status;
328 cur_reg = oldreg;
329 status = twl4030_bci_read(TWL4030_BCIIREF2, &oldreg);
330 if (status < 0)
331 return status;
332 cur_reg |= oldreg << 8;
333 if (reg != oldreg) {
334 /* disable write protection for one write access for
335 * BCIIREF */
336 status = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0xE7,
337 TWL4030_BCIMFKEY);
338 if (status < 0)
339 return status;
340 status = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE,
341 (reg & 0x100) ? 3 : 2,
342 TWL4030_BCIIREF2);
343 if (status < 0)
344 return status;
345 /* disable write protection for one write access for
346 * BCIIREF */
347 status = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0xE7,
348 TWL4030_BCIMFKEY);
349 if (status < 0)
350 return status;
351 status = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE,
352 reg & 0xff,
353 TWL4030_BCIIREF1);
354 }
355 if ((!!cgain) != !!(bcictl1 & TWL4030_CGAIN)) {
356 /* Flip CGAIN and re-enable charging */
357 bcictl1 ^= TWL4030_CGAIN;
358 twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE,
359 bcictl1, TWL4030_BCICTL1);
360 twl4030_clear_set_boot_bci(0, boot_bci);
361 }
362 return 0;
363}
364
214/* 365/*
215 * Enable/Disable USB Charge functionality. 366 * Enable/Disable USB Charge functionality.
216 */ 367 */
@@ -219,14 +370,6 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable)
219 int ret; 370 int ret;
220 371
221 if (enable && !IS_ERR_OR_NULL(bci->transceiver)) { 372 if (enable && !IS_ERR_OR_NULL(bci->transceiver)) {
222 /*
223 * Until we can find out what current the device can provide,
224 * require a module param to enable USB charging.
225 */
226 if (!allow_usb) {
227 dev_warn(bci->dev, "USB charging is disabled.\n");
228 return -EACCES;
229 }
230 373
231 /* Need to keep phy powered */ 374 /* Need to keep phy powered */
232 if (!bci->usb_enabled) { 375 if (!bci->usb_enabled) {
@@ -578,6 +721,14 @@ static int twl4030_bci_probe(struct platform_device *pdev)
578 if (!pdata) 721 if (!pdata)
579 pdata = twl4030_bci_parse_dt(&pdev->dev); 722 pdata = twl4030_bci_parse_dt(&pdev->dev);
580 723
724 bci->ichg_eoc = 80100; /* Stop charging when current drops to here */
725 bci->ichg_lo = 241000; /* Low threshold */
726 bci->ichg_hi = 500000; /* High threshold */
727 if (allow_usb)
728 bci->cur = 500000; /* 500mA */
729 else
730 bci->cur = 100000; /* 100mA */
731
581 bci->dev = &pdev->dev; 732 bci->dev = &pdev->dev;
582 bci->irq_chg = platform_get_irq(pdev, 0); 733 bci->irq_chg = platform_get_irq(pdev, 0);
583 bci->irq_bci = platform_get_irq(pdev, 1); 734 bci->irq_bci = platform_get_irq(pdev, 1);
@@ -657,6 +808,7 @@ static int twl4030_bci_probe(struct platform_device *pdev)
657 if (ret < 0) 808 if (ret < 0)
658 dev_warn(&pdev->dev, "failed to unmask interrupts: %d\n", ret); 809 dev_warn(&pdev->dev, "failed to unmask interrupts: %d\n", ret);
659 810
811 twl4030_charger_update_current(bci);
660 twl4030_charger_enable_ac(true); 812 twl4030_charger_enable_ac(true);
661 if (!IS_ERR_OR_NULL(bci->transceiver)) 813 if (!IS_ERR_OR_NULL(bci->transceiver))
662 twl4030_bci_usb_ncb(&bci->usb_nb, 814 twl4030_bci_usb_ncb(&bci->usb_nb,