[3/3] power: supply: cpcap-charger: Adjust current based on charger interrupts
diff mbox series

Message ID 20190917215253.17880-4-tony@atomide.com
State New
Headers show
Series
  • cpcap charger and battery changes to deal with dropped voltage
Related show

Commit Message

Tony Lindgren Sept. 17, 2019, 9:52 p.m. UTC
When debugging why higher than 500 mA charge current does not work, I
noticed that we start getting lots of chrgcurr1 interrupts if we attempt
to charge at rates higher than the charger can provide.

We can take advantage of the chrgcurr1 interrupts for charger detection,
and retry charging at a lower rate if charging fails. When an acceptable
charge rate is found, the chrgcurr1 interrupts stop.

Cc: Merlijn Wajer <merlijn@wizzup.org>
Cc: Pavel Machek <pavel@ucw.cz>
Signed-off-by: Tony Lindgren <tony@atomide.com>
---
 drivers/power/supply/cpcap-charger.c | 45 ++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)

Comments

Pavel Machek Sept. 19, 2019, 9:34 a.m. UTC | #1
On Tue 2019-09-17 14:52:53, Tony Lindgren wrote:
> When debugging why higher than 500 mA charge current does not work, I
> noticed that we start getting lots of chrgcurr1 interrupts if we attempt
> to charge at rates higher than the charger can provide.
> 
> We can take advantage of the chrgcurr1 interrupts for charger detection,
> and retry charging at a lower rate if charging fails. When an acceptable
> charge rate is found, the chrgcurr1 interrupts stop.

Do you still see these problems with "good" charger? (Wall one,
capable of providing 2A)?

Note that 1A charging will decrease battery lifetime, and that phone
definitely should not be charging with more than 500mA when charging
from computer. I actually prefer the way it charges slowly in mainline...

We'll eventually need a library or something; we don't want every
driver to reinvent charging code..

Best regards,

									Pavel
Tony Lindgren Sept. 20, 2019, 2:15 p.m. UTC | #2
* Pavel Machek <pavel@ucw.cz> [190919 09:35]:
> On Tue 2019-09-17 14:52:53, Tony Lindgren wrote:
> > When debugging why higher than 500 mA charge current does not work, I
> > noticed that we start getting lots of chrgcurr1 interrupts if we attempt
> > to charge at rates higher than the charger can provide.
> > 
> > We can take advantage of the chrgcurr1 interrupts for charger detection,
> > and retry charging at a lower rate if charging fails. When an acceptable
> > charge rate is found, the chrgcurr1 interrupts stop.
> 
> Do you still see these problems with "good" charger? (Wall one,
> capable of providing 2A)?

Yes, need to recheck again with the updated fix I posted.

> Note that 1A charging will decrease battery lifetime, and that phone
> definitely should not be charging with more than 500mA when charging
> from computer. I actually prefer the way it charges slowly in mainline...

It should still charge at 500mA when connected to a computer
because of different charger detection bits. Needs to be checked
again .though

> We'll eventually need a library or something; we don't want every
> driver to reinvent charging code..

Yeah currently implementing a charger takes weeks of work :)

Regards,

Tony

Patch
diff mbox series

diff --git a/drivers/power/supply/cpcap-charger.c b/drivers/power/supply/cpcap-charger.c
--- a/drivers/power/supply/cpcap-charger.c
+++ b/drivers/power/supply/cpcap-charger.c
@@ -145,6 +145,12 @@  enum {
 	CPCAP_CHARGER_IIO_NR,
 };
 
+enum {
+	CPCAP_CHARGER_DISCONNECTED,
+	CPCAP_CHARGER_DETECTING,
+	CPCAP_CHARGER_CONNECTED,
+};
+
 struct cpcap_charger_ddata {
 	struct device *dev;
 	struct regmap *reg;
@@ -161,6 +167,9 @@  struct cpcap_charger_ddata {
 	unsigned int vbus_enabled:1;
 	unsigned int feeding_vbus:1;
 	int const_charge_voltage;
+	int state;
+	int last_current;
+	int last_current_retries;
 	atomic_t active;
 
 	int status;
@@ -551,6 +560,15 @@  static void cpcap_usb_detect(struct work_struct *work)
 	if (error)
 		return;
 
+	/* Just init the state if a charger is connected with no chrg_det set */
+	if (!ddata->feeding_vbus && !s.chrg_det && s.chrgcurr1 && s.vbusvld) {
+		ddata->state = CPCAP_CHARGER_DETECTING;
+		ddata->last_current = 0;
+
+		return;
+	}
+
+	/* Start charger on chrgcurr1, stop chrger otherwise */
 	if (!ddata->feeding_vbus && cpcap_charger_vbus_valid(ddata) &&
 	    s.chrgcurr1) {
 		int max_current;
@@ -561,6 +579,32 @@  static void cpcap_usb_detect(struct work_struct *work)
 		else
 			max_current = CPCAP_REG_CRM_ICHRG_0A532;
 
+		switch (ddata->state) {
+		case CPCAP_CHARGER_DETECTING:
+			ddata->state = CPCAP_CHARGER_CONNECTED;
+			ddata->last_current_retries = 0;
+			break;
+		case CPCAP_CHARGER_DISCONNECTED:
+			if (ddata->last_current > CPCAP_REG_CRM_ICHRG_0A532) {
+				/* Attempt current 3 times before lowering */
+				if (ddata->last_current_retries++ >= 3) {
+					ddata->last_current--;
+					ddata->last_current_retries = 0;
+					/* Wait a bit for voltage to ramp up */
+					usleep_range(40000, 50000);
+				}
+				max_current = ddata->last_current;
+			}
+			ddata->state = CPCAP_CHARGER_CONNECTED;
+			dev_info(ddata->dev, "enabling charger with current %i\n",
+				 max_current);
+			break;
+		default:
+			ddata->last_current_retries = 0;
+			break;
+		}
+
+		ddata->last_current = max_current;
 		cpcap_charger_match_voltage(ddata, ddata->const_charge_voltage,
 					    &vchrg);
 		error = cpcap_charger_set_state(ddata,
@@ -569,6 +613,7 @@  static void cpcap_usb_detect(struct work_struct *work)
 		if (error)
 			goto out_err;
 	} else {
+		ddata->state = CPCAP_CHARGER_DISCONNECTED;
 		error = cpcap_charger_set_state(ddata, 0, 0, 0);
 		if (error)
 			goto out_err;