[10/13] twl4030_charger: add software controlled linear charging mode.
diff mbox

Message ID 20150730001124.4012.27784.stgit@noble
State New
Headers show

Commit Message

NeilBrown July 30, 2015, 12:11 a.m. UTC
Add a 'continuous' option for usb charging which enables
the "linear" charging mode of the twl4030.

Linear charging does a good job with not-so-reliable power sources.
Auto mode does not work well as it switches off when voltage drops
momentarily.  Care must be taken not to over-charge.

It was used with a bike hub dynamo since a year or so. In that case
there are automatically charging stops when the cyclist needs a break.

Original-by: Andreas Kemnade <andreas@kemnade.info>
Signed-off-by: NeilBrown <neil@brown.name>
---
 .../ABI/testing/sysfs-class-power-twl4030          |    9 +++
 drivers/power/twl4030_charger.c                    |   55 ++++++++++++++++++--
 2 files changed, 59 insertions(+), 5 deletions(-)



--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Pavel Machek Sept. 15, 2015, 11:28 a.m. UTC | #1
On Thu 2015-07-30 10:11:24, NeilBrown wrote:
> 
> Add a 'continuous' option for usb charging which enables
> the "linear" charging mode of the twl4030.
> 
> Linear charging does a good job with not-so-reliable power sources.
> Auto mode does not work well as it switches off when voltage drops
> momentarily.  Care must be taken not to over-charge.

Can you explain how the user can "care not to over-charge"?

> @@ -750,6 +784,17 @@ static int twl4030_bci_get_property(struct power_supply *psy,
>  		is_charging = state & TWL4030_MSTATEC_USB;
>  	else
>  		is_charging = state & TWL4030_MSTATEC_AC;
> +	if (!is_charging) {
> +		u8 s;
> +		twl4030_bci_read(TWL4030_BCIMDEN, &s);
> +		if (psy->desc->type == POWER_SUPPLY_TYPE_USB)
> +			is_charging = s & 1;
> +		else
> +			is_charging = s & 2;
> +		if (is_charging)
> +			/* A little white lie */
> +			state = TWL4030_MSTATEC_QUICK1;

I'm not sure... can't this white lie turn into black smoke?

Like.. normally, when battery is below something (like 3.5V) it must
not be quick-charged (because something is very wrong with it). Are
you just forcing the quick charge here?

									Pavel
Christ van Willegen Sept. 15, 2015, 12:08 p.m. UTC | #2
Hi all,

On Tue, Sep 15, 2015 at 1:28 PM, Pavel Machek <pavel@ucw.cz> wrote:
> On Thu 2015-07-30 10:11:24, NeilBrown wrote:
>>
>> Add a 'continuous' option for usb charging which enables
>> the "linear" charging mode of the twl4030.
>>
>> Linear charging does a good job with not-so-reliable power sources.
>> Auto mode does not work well as it switches off when voltage drops
>> momentarily.  Care must be taken not to over-charge.
>
> Can you explain how the user can "care not to over-charge"?

Just my $0.02, I assumed (whoops!) that Neil mean that the _code_
should take care not to over-charge... but not sure how he intended to
to that.

Anyway, that was my interpretation of the (indeed, it could be
explained in different ways...) comment.

Christ van Willegen
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
NeilBrown Oct. 1, 2015, 6:14 a.m. UTC | #3
Pavel Machek <pavel@ucw.cz> writes:

> On Thu 2015-07-30 10:11:24, NeilBrown wrote:
>> 
>> Add a 'continuous' option for usb charging which enables
>> the "linear" charging mode of the twl4030.
>> 
>> Linear charging does a good job with not-so-reliable power sources.
>> Auto mode does not work well as it switches off when voltage drops
>> momentarily.  Care must be taken not to over-charge.
>
> Can you explain how the user can "care not to over-charge"?

The following text reads:

    It was used with a bike hub dynamo since a year or so. In that case
    there are automatically charging stops when the cyclist needs a break.

so: take a break from cycling occasionally.

>
>> @@ -750,6 +784,17 @@ static int twl4030_bci_get_property(struct power_supply *psy,
>>  		is_charging = state & TWL4030_MSTATEC_USB;
>>  	else
>>  		is_charging = state & TWL4030_MSTATEC_AC;
>> +	if (!is_charging) {
>> +		u8 s;
>> +		twl4030_bci_read(TWL4030_BCIMDEN, &s);
>> +		if (psy->desc->type == POWER_SUPPLY_TYPE_USB)
>> +			is_charging = s & 1;
>> +		else
>> +			is_charging = s & 2;
>> +		if (is_charging)
>> +			/* A little white lie */
>> +			state = TWL4030_MSTATEC_QUICK1;
>
> I'm not sure... can't this white lie turn into black smoke?
>
> Like.. normally, when battery is below something (like 3.5V) it must
> not be quick-charged (because something is very wrong with it). Are
> you just forcing the quick charge here?

No.  That value is only used for reporting a status via sysfs.
That 'lie' gets translated to "POWER_SUPPLY_STATUS_CHARGING" which is
not a lie.

Thanks,
NeilBrown


>
> 									Pavel
> -- 
> (english) http://www.livejournal.com/~pavelmachek
> (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Pavel Machek Oct. 6, 2015, 2:34 p.m. UTC | #4
Hi!

> Pavel Machek <pavel@ucw.cz> writes:
> > On Thu 2015-07-30 10:11:24, NeilBrown wrote:
> >> 
> >> Add a 'continuous' option for usb charging which enables
> >> the "linear" charging mode of the twl4030.
> >> 
> >> Linear charging does a good job with not-so-reliable power sources.
> >> Auto mode does not work well as it switches off when voltage drops
> >> momentarily.  Care must be taken not to over-charge.
> >
> > Can you explain how the user can "care not to over-charge"?
> 
> The following text reads:
> 
>     It was used with a bike hub dynamo since a year or so. In that case
>     there are automatically charging stops when the cyclist needs a break.
> 
> so: take a break from cycling occasionally.

If the charger does not exceed 4.2V, I'd not call it overcharge. (Yes, some clever
chargers actually let the battery drop below 4.2V when charge is done, but...)

If the charger _does_ exceed 4.2V, then the battery will explode. Don't do that. Don't
offer that to the user.

On a related note... I've just killed USB charger by overloading it. They are not protected.

I believe your automatically-pull-max-power really should stick to the well-known charging
currents (.5A, 1A, 1.7A), at the very minimum.
Andreas Kemnade Oct. 29, 2015, 4:20 p.m. UTC | #5
On Tue, 6 Oct 2015 16:34:07 +0200
Pavel Machek <pavel@ucw.cz> wrote:

> Hi!
> 
> > Pavel Machek <pavel@ucw.cz> writes:
> > > On Thu 2015-07-30 10:11:24, NeilBrown wrote:
> > >> 
> > >> Add a 'continuous' option for usb charging which enables
> > >> the "linear" charging mode of the twl4030.
> > >> 
> > >> Linear charging does a good job with not-so-reliable power sources.
> > >> Auto mode does not work well as it switches off when voltage drops
> > >> momentarily.  Care must be taken not to over-charge.
> > >
> > > Can you explain how the user can "care not to over-charge"?
> > 
> > The following text reads:
> > 
> >     It was used with a bike hub dynamo since a year or so. In that case
> >     there are automatically charging stops when the cyclist needs a break.
> > 
> > so: take a break from cycling occasionally.
> 
> If the charger does not exceed 4.2V, I'd not call it overcharge. (Yes, some clever
> chargers actually let the battery drop below 4.2V when charge is done, but...)
> 
Yes, that is the case. Perhaps it is not to be called overcharge but
it is said that lithium battery charging has to stop if in CV mode the
current drops too low.  In automatic mode the charger does exactly
that.
I would not let a battery for days at 4.2V CV.mode although a lot
of cheap chargers 

> If the charger _does_ exceed 4.2V, then the battery will explode. Don't do that. Don't
> offer that to the user.
> 
> On a related note... I've just killed USB charger by overloading it. They are not protected.
> 
> I believe your automatically-pull-max-power really should stick to the well-known charging
> currents (.5A, 1A, 1.7A), at the very minimum.
> 
The main reason for the patch was to prevent switching off charging
when Vbus drops low. The reason was not to get out extremely much
current out of the charger.
The electrical characteristics of a  bicycle as a power source are.
- the amount of current available changes
   - 500mA at around 17km/h
- you cannot destroy it by electrically overloading

If the current is set to e.g. 500mA and that linear charging mode is
enabled, the battery gets the maximum current available (upto
500mA) regardless of the speed which is often changing.

Regards,
Andreas Kemnade
Pavel Machek Nov. 14, 2015, 6:12 p.m. UTC | #6
Hi!

> > > Pavel Machek <pavel@ucw.cz> writes:
> > > > On Thu 2015-07-30 10:11:24, NeilBrown wrote:
> > > >> 
> > > >> Add a 'continuous' option for usb charging which enables
> > > >> the "linear" charging mode of the twl4030.
> > > >> 
> > > >> Linear charging does a good job with not-so-reliable power sources.
> > > >> Auto mode does not work well as it switches off when voltage drops
> > > >> momentarily.  Care must be taken not to over-charge.
> > > >
> > > > Can you explain how the user can "care not to over-charge"?
> > > 
> > > The following text reads:
> > > 
> > >     It was used with a bike hub dynamo since a year or so. In that case
> > >     there are automatically charging stops when the cyclist needs a break.
> > > 
> > > so: take a break from cycling occasionally.
> > 
> > If the charger does not exceed 4.2V, I'd not call it overcharge. (Yes, some clever
> > chargers actually let the battery drop below 4.2V when charge is done, but...)
> > 
> Yes, that is the case. Perhaps it is not to be called overcharge but
> it is said that lithium battery charging has to stop if in CV mode the
> current drops too low.  In automatic mode the charger does exactly
> that.
> I would not let a battery for days at 4.2V CV.mode although a lot
> of cheap chargers

Well, I agree that keeping battery at 4.2V constant voltage mode is
bad, but I'd not call it overcharge. If someone can fix the comment,
that would be nice.

> > If the charger _does_ exceed 4.2V, then the battery will explode. Don't do that. Don't
> > offer that to the user.
> > 
> > On a related note... I've just killed USB charger by overloading it. They are not protected.
> > 
> > I believe your automatically-pull-max-power really should stick to the well-known charging
> > currents (.5A, 1A, 1.7A), at the very minimum.
> > 
> The main reason for the patch was to prevent switching off charging
> when Vbus drops low. The reason was not to get out extremely much
> current out of the charger.
> The electrical characteristics of a  bicycle as a power source are.
> - the amount of current available changes
>    - 500mA at around 17km/h
> - you cannot destroy it by electrically overloading
> 
> If the current is set to e.g. 500mA and that linear charging mode is
> enabled, the battery gets the maximum current available (upto
> 500mA) regardless of the speed which is often changing.

Yes... I guess that makes sense for you, but I wonder if we should be
doing this by default. It seems a lot of cheap chargers can be easily
destroyed if you overload them.

									Pavel
Andreas Kemnade Nov. 24, 2015, 10:31 p.m. UTC | #7
On Sat, 14 Nov 2015 19:12:16 +0100
Pavel Machek <pavel@ucw.cz> wrote:

> Hi!
> 
> > > > Pavel Machek <pavel@ucw.cz> writes:
> > > > > On Thu 2015-07-30 10:11:24, NeilBrown wrote:
> > > > >> 
> > > > >> Add a 'continuous' option for usb charging which enables
> > > > >> the "linear" charging mode of the twl4030.
> > > > >> 
> > > > >> Linear charging does a good job with not-so-reliable power sources.
> > > > >> Auto mode does not work well as it switches off when voltage drops
> > > > >> momentarily.  Care must be taken not to over-charge.
> > > > >
> > > > > Can you explain how the user can "care not to over-charge"?
> > > > 
> > > > The following text reads:
> > > > 
> > > >     It was used with a bike hub dynamo since a year or so. In that case
> > > >     there are automatically charging stops when the cyclist needs a break.
> > > > 
> > > > so: take a break from cycling occasionally.
> > > 
> > > If the charger does not exceed 4.2V, I'd not call it overcharge. (Yes, some clever
> > > chargers actually let the battery drop below 4.2V when charge is done, but...)
> > > 
> > Yes, that is the case. Perhaps it is not to be called overcharge but
> > it is said that lithium battery charging has to stop if in CV mode the
> > current drops too low.  In automatic mode the charger does exactly
> > that.
> > I would not let a battery for days at 4.2V CV.mode although a lot
> > of cheap chargers
> 
> Well, I agree that keeping battery at 4.2V constant voltage mode is
> bad, but I'd not call it overcharge. If someone can fix the comment,
> that would be nice.
>
here is my original comment ("on" was replaced by continuous "now"):

    twl4030_charger: add software controlled linear charging mode.
    
       adds a sysfs control node to achieve that.
       It can be set to
       auto: normal automatic charging is enabled (default)
       off: charging is off
       on: charing is on (software controlled)
           CC/CV mode is still automatically done,
           but end of charge due to low current not.
    
    Note: If linear charging mode is used there should be some method of
    stopping charging automatically. It is not a so time-critical, but
    it is the wrong setting for leaving a charger connected for several
days since Lithium batteries should not be kept at 100% for longer
periods. Linear charging does a good job with not so reliable power
sources, since several voltage controlling is then often too
intelligent. It was used with a bike hub dynamo since a year or so. In
that case there are automatically charging stops when the cyclist needs
a break. Signed-off-by: Andreas Kemnade <andreas@kemnade.info>


> > > If the charger _does_ exceed 4.2V, then the battery will explode. Don't do that. Don't
> > > offer that to the user.
> > > 
> > > On a related note... I've just killed USB charger by overloading it. They are not protected.
> > > 
> > > I believe your automatically-pull-max-power really should stick to the well-known charging
> > > currents (.5A, 1A, 1.7A), at the very minimum.
> > > 
> > The main reason for the patch was to prevent switching off charging
> > when Vbus drops low. The reason was not to get out extremely much
> > current out of the charger.
> > The electrical characteristics of a  bicycle as a power source are.
> > - the amount of current available changes
> >    - 500mA at around 17km/h
> > - you cannot destroy it by electrically overloading
> > 
> > If the current is set to e.g. 500mA and that linear charging mode is
> > enabled, the battery gets the maximum current available (upto
> > 500mA) regardless of the speed which is often changing.
> 
> Yes... I guess that makes sense for you, but I wonder if we should be
> doing this by default. It seems a lot of cheap chargers can be easily
> destroyed if you overload them.
> 
Hmm, I guess the twl4030_charger would not be the only one destroying
such chargers. I have seen such hub dynamo-friendly behaviour on every
device I had connected to it before (an ipaq h2200, openmoko gta02).
I have checked all usb wall plug chargers I have seen and I found none
which has a lower current then 500mA. Only one has 500mA. The rest has
1A or even 2A.

But I think the non-ending cv stuff is a reason enough so that it is not
the default charge method. I use it only at bootup when battery is low
to have some time to fix charging issues manually and when cycling.
Cycling is detected by acceleration values and I get some feedback if
that charge mode is enabled or disabled.

Regards.
Andreas Kemnade

Patch
diff mbox

diff --git a/Documentation/ABI/testing/sysfs-class-power-twl4030 b/Documentation/ABI/testing/sysfs-class-power-twl4030
index 40e0f919cbde..e8baa36aaa2b 100644
--- a/Documentation/ABI/testing/sysfs-class-power-twl4030
+++ b/Documentation/ABI/testing/sysfs-class-power-twl4030
@@ -24,3 +24,12 @@  Description:
 		"auto" - draw power as appropriate for detected
 			 power source and battery status.
 		"off"  - do not draw any power.
+		"continuous"
+		       - activate mode described as "linear" in
+		         TWL data sheets.  This uses whatever
+			 current is available and doesn't switch off
+			 when voltage drops.
+
+			 This is useful for unstable power sources
+			 such as bicycle dynamo, but care should
+			 be taken that battery is not over-charged.
diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index 6fa928ed3128..de5430deaf23 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -24,6 +24,8 @@ 
 #include <linux/usb/otg.h>
 #include <linux/i2c/twl4030-madc.h>
 
+#define TWL4030_BCIMDEN		0x00
+#define TWL4030_BCIMDKEY	0x01
 #define TWL4030_BCIMSTATEC	0x02
 #define TWL4030_BCIICHG		0x08
 #define TWL4030_BCIVAC		0x0a
@@ -35,13 +37,16 @@ 
 #define TWL4030_BCIIREF1	0x27
 #define TWL4030_BCIIREF2	0x28
 #define TWL4030_BCIMFKEY	0x11
+#define TWL4030_BCIMFEN3	0x14
 #define TWL4030_BCIMFTH8	0x1d
 #define TWL4030_BCIMFTH9	0x1e
+#define TWL4030_BCIWDKEY	0x21
 
 #define TWL4030_BCIMFSTS1	0x01
 
 #define TWL4030_BCIAUTOWEN	BIT(5)
 #define TWL4030_CONFIG_DONE	BIT(4)
+#define TWL4030_CVENAC		BIT(2)
 #define TWL4030_BCIAUTOUSB	BIT(1)
 #define TWL4030_BCIAUTOAC	BIT(0)
 #define TWL4030_CGAIN		BIT(5)
@@ -112,12 +117,13 @@  struct twl4030_bci {
 	int			usb_mode; /* charging mode requested */
 #define	CHARGE_OFF	0
 #define	CHARGE_AUTO	1
+#define	CHARGE_LINEAR	2
 
 	unsigned long		event;
 };
 
 /* strings for 'usb_mode' values */
-static char *modes[] = { "off", "auto" };
+static char *modes[] = { "off", "auto", "continuous" };
 
 /*
  * clear and set bits on an given register on a given module
@@ -404,16 +410,42 @@  static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable)
 			bci->usb_enabled = 1;
 		}
 
-		/* forcing the field BCIAUTOUSB (BOOT_BCI[1]) to 1 */
-		ret = twl4030_clear_set_boot_bci(0, TWL4030_BCIAUTOUSB);
-		if (ret < 0)
-			return ret;
+		if (bci->usb_mode == CHARGE_AUTO)
+			/* forcing the field BCIAUTOUSB (BOOT_BCI[1]) to 1 */
+			ret = twl4030_clear_set_boot_bci(0, TWL4030_BCIAUTOUSB);
 
 		/* forcing USBFASTMCHG(BCIMFSTS4[2]) to 1 */
 		ret = twl4030_clear_set(TWL_MODULE_MAIN_CHARGE, 0,
 			TWL4030_USBFASTMCHG, TWL4030_BCIMFSTS4);
+		if (bci->usb_mode == CHARGE_LINEAR) {
+			twl4030_clear_set_boot_bci(TWL4030_BCIAUTOAC|TWL4030_CVENAC, 0);
+			/* Watch dog key: WOVF acknowledge */
+			ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x33,
+					       TWL4030_BCIWDKEY);
+			/* 0x24 + EKEY6: off mode */
+			ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x2a,
+					       TWL4030_BCIMDKEY);
+			/* EKEY2: Linear charge: USB path */
+			ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x26,
+					       TWL4030_BCIMDKEY);
+			/* WDKEY5: stop watchdog count */
+			ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0xf3,
+					       TWL4030_BCIWDKEY);
+			/* enable MFEN3 access */
+			ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x9c,
+					       TWL4030_BCIMFKEY);
+			 /* ICHGEOCEN - end-of-charge monitor (current < 80mA)
+			  *                      (charging continues)
+			  * ICHGLOWEN - current level monitor (charge continues)
+			  * don't monitor over-current or heat save
+			  */
+			ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0xf0,
+					       TWL4030_BCIMFEN3);
+		}
 	} else {
 		ret = twl4030_clear_set_boot_bci(TWL4030_BCIAUTOUSB, 0);
+		ret |= twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x2a,
+					TWL4030_BCIMDKEY);
 		if (bci->usb_enabled) {
 			pm_runtime_mark_last_busy(bci->transceiver->dev);
 			pm_runtime_put_autosuspend(bci->transceiver->dev);
@@ -652,6 +684,8 @@  twl4030_bci_mode_store(struct device *dev, struct device_attribute *attr,
 		mode = 0;
 	else if (sysfs_streq(buf, modes[1]))
 		mode = 1;
+	else if (sysfs_streq(buf, modes[2]))
+		mode = 2;
 	else
 		return -EINVAL;
 	twl4030_charger_enable_usb(bci, false);
@@ -750,6 +784,17 @@  static int twl4030_bci_get_property(struct power_supply *psy,
 		is_charging = state & TWL4030_MSTATEC_USB;
 	else
 		is_charging = state & TWL4030_MSTATEC_AC;
+	if (!is_charging) {
+		u8 s;
+		twl4030_bci_read(TWL4030_BCIMDEN, &s);
+		if (psy->desc->type == POWER_SUPPLY_TYPE_USB)
+			is_charging = s & 1;
+		else
+			is_charging = s & 2;
+		if (is_charging)
+			/* A little white lie */
+			state = TWL4030_MSTATEC_QUICK1;
+	}
 
 	switch (psp) {
 	case POWER_SUPPLY_PROP_STATUS: