[PATCH 3/3] power: supply: cpcap-charger: Adjust current based on charger interrupts

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxx>
Cc: Pavel Machek <pavel@xxxxxx>
Signed-off-by: Tony Lindgren <tony@xxxxxxxxxxx>
---
 drivers/power/supply/cpcap-charger.c | 45 ++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)

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;
-- 
2.23.0



[Index of Archives]     [Linux Arm (vger)]     [ARM Kernel]     [ARM MSM]     [Linux Tegra]     [Linux WPAN Networking]     [Linux Wireless Networking]     [Maemo Users]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux