Commit 8bc8fc08 authored by Sebastian Reichel's avatar Sebastian Reichel
Browse files

Merge tag 'psy-cpcap-charge-volt-limit-signed' into psy-next



Immutable branch between arm and power-supply for cpcap-charger

This immutable branch contains CPCAP charger changes, which
touch ARM and power-supply subsystem.

Signed-off-by: default avatarSebastian Reichel <sre@kernel.org>
parents b10e9700 d4ee021c
Loading
Loading
Loading
Loading
+6 −3
Original line number Diff line number Diff line
@@ -5,7 +5,8 @@ Required properties:
- interrupts: Interrupt specifier for each name in interrupt-names
- interrupt-names: Should contain the following entries:
		   "chrg_det", "rvrs_chrg", "chrg_se1b", "se0conn",
		   "rvrs_mode", "chrgcurr1", "vbusvld", "battdetb"
		   "rvrs_mode", "chrgcurr2", "chrgcurr1", "vbusvld",
		   "battdetb"
- io-channels: IIO ADC channel specifier for each name in io-channel-names
- io-channel-names: Should contain the following entries:
		    "battdetb", "battp", "vbus", "chg_isense", "batti"
@@ -21,11 +22,13 @@ cpcap_charger: charger {
	compatible = "motorola,mapphone-cpcap-charger";
	interrupts-extended = <
		&cpcap 13 0 &cpcap 12 0 &cpcap 29 0 &cpcap 28 0
		&cpcap 22 0 &cpcap 20 0 &cpcap 19 0 &cpcap 54 0
		&cpcap 22 0 &cpcap 21 0 &cpcap 20 0 &cpcap 19 0
		&cpcap 54 0
	>;
	interrupt-names =
		"chrg_det", "rvrs_chrg", "chrg_se1b", "se0conn",
		"rvrs_mode", "chrgcurr1", "vbusvld", "battdetb";
		"rvrs_mode", "chrgcurr2", "chrgcurr1", "vbusvld",
		"battdetb";
	mode-gpios = <&gpio3 29 GPIO_ACTIVE_LOW
		      &gpio3 23 GPIO_ACTIVE_LOW>;
	io-channels = <&cpcap_adc 0 &cpcap_adc 1
+4 −2
Original line number Diff line number Diff line
@@ -43,11 +43,13 @@
			compatible = "motorola,mapphone-cpcap-charger";
			interrupts-extended = <
				&cpcap 13 0 &cpcap 12 0 &cpcap 29 0 &cpcap 28 0
				&cpcap 22 0 &cpcap 20 0 &cpcap 19 0 &cpcap 54 0
				&cpcap 22 0 &cpcap 21 0 &cpcap 20 0 &cpcap 19 0
				&cpcap 54 0
			>;
			interrupt-names =
				"chrg_det", "rvrs_chrg", "chrg_se1b", "se0conn",
				"rvrs_mode", "chrgcurr1", "vbusvld", "battdetb";
				"rvrs_mode", "chrgcurr2", "chrgcurr1", "vbusvld",
				"battdetb";
			mode-gpios = <&gpio3 29 GPIO_ACTIVE_LOW
				      &gpio3 23 GPIO_ACTIVE_LOW>;
			io-channels = <&cpcap_adc 0 &cpcap_adc 1
+130 −2
Original line number Diff line number Diff line
@@ -120,6 +120,13 @@ enum {
	CPCAP_CHARGER_IIO_NR,
};

enum {
	CPCAP_CHARGER_DISCONNECTED,
	CPCAP_CHARGER_DETECTING,
	CPCAP_CHARGER_CHARGING,
	CPCAP_CHARGER_DONE,
};

struct cpcap_charger_ddata {
	struct device *dev;
	struct regmap *reg;
@@ -138,6 +145,8 @@ struct cpcap_charger_ddata {
	atomic_t active;

	int status;
	int state;
	int voltage;
};

struct cpcap_interrupt_desc {
@@ -153,6 +162,7 @@ struct cpcap_charger_ints_state {

	bool chrg_se1b;
	bool rvrs_mode;
	bool chrgcurr2;
	bool chrgcurr1;
	bool vbusvld;

@@ -422,6 +432,7 @@ static int cpcap_charger_get_ints_state(struct cpcap_charger_ddata *ddata,

	s->chrg_se1b = val & BIT(13);
	s->rvrs_mode = val & BIT(6);
	s->chrgcurr2 = val & BIT(5);
	s->chrgcurr1 = val & BIT(4);
	s->vbusvld = val & BIT(3);

@@ -434,6 +445,79 @@ static int cpcap_charger_get_ints_state(struct cpcap_charger_ddata *ddata,
	return 0;
}

static void cpcap_charger_update_state(struct cpcap_charger_ddata *ddata,
				       int state)
{
	const char *status;

	if (state > CPCAP_CHARGER_DONE) {
		dev_warn(ddata->dev, "unknown state: %i\n", state);

		return;
	}

	ddata->state = state;

	switch (state) {
	case CPCAP_CHARGER_DISCONNECTED:
		status = "DISCONNECTED";
		break;
	case CPCAP_CHARGER_DETECTING:
		status = "DETECTING";
		break;
	case CPCAP_CHARGER_CHARGING:
		status = "CHARGING";
		break;
	case CPCAP_CHARGER_DONE:
		status = "DONE";
		break;
	default:
		return;
	}

	dev_dbg(ddata->dev, "state: %s\n", status);
}

int cpcap_charger_voltage_to_regval(int voltage)
{
	int offset;

	switch (voltage) {
	case 0 ... 4100000 - 1:
		return 0;
	case 4100000 ... 4200000 - 1:
		offset = 1;
		break;
	case 4200000 ... 4300000 - 1:
		offset = 0;
		break;
	case 4300000 ... 4380000 - 1:
		offset = -1;
		break;
	case 4380000 ... 4440000:
		offset = -2;
		break;
	default:
		return 0;
	}

	return ((voltage - 4100000) / 20000) + offset;
}

static void cpcap_charger_disconnect(struct cpcap_charger_ddata *ddata,
				     int state, unsigned long delay)
{
	int error;

	error = cpcap_charger_set_state(ddata, 0, 0, 0);
	if (error)
		return;

	cpcap_charger_update_state(ddata, state);
	power_supply_changed(ddata->usb);
	schedule_delayed_work(&ddata->detect_work, delay);
}

static void cpcap_usb_detect(struct work_struct *work)
{
	struct cpcap_charger_ddata *ddata;
@@ -447,24 +531,67 @@ 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 (!s.chrg_det && s.chrgcurr1 && s.vbusvld) {
		cpcap_charger_update_state(ddata, CPCAP_CHARGER_DETECTING);

		return;
	}

	/*
	 * If battery voltage is higher than charge voltage, it may have been
	 * charged to 4.35V by Android. Try again in 10 minutes.
	 */
	if (cpcap_charger_get_charge_voltage(ddata) > ddata->voltage) {
		cpcap_charger_disconnect(ddata, CPCAP_CHARGER_DETECTING,
					 HZ * 60 * 10);

		return;
	}

	/* Throttle chrgcurr2 interrupt for charger done and retry */
	switch (ddata->state) {
	case CPCAP_CHARGER_CHARGING:
		if (s.chrgcurr2)
			break;
		if (s.chrgcurr1 && s.vbusvld) {
			cpcap_charger_disconnect(ddata, CPCAP_CHARGER_DONE,
						 HZ * 5);
			return;
		}
		break;
	case CPCAP_CHARGER_DONE:
		if (!s.chrgcurr2)
			break;
		cpcap_charger_disconnect(ddata, CPCAP_CHARGER_DETECTING,
					 HZ * 5);
		return;
	default:
		break;
	}

	if (!ddata->feeding_vbus && cpcap_charger_vbus_valid(ddata) &&
	    s.chrgcurr1) {
		int max_current;
		int vchrg;

		if (cpcap_charger_battery_found(ddata))
			max_current = CPCAP_REG_CRM_ICHRG_1A596;
		else
			max_current = CPCAP_REG_CRM_ICHRG_0A532;

		vchrg = cpcap_charger_voltage_to_regval(ddata->voltage);
		error = cpcap_charger_set_state(ddata,
						CPCAP_REG_CRM_VCHRG_4V35,
						CPCAP_REG_CRM_VCHRG(vchrg),
						max_current, 0);
		if (error)
			goto out_err;
		cpcap_charger_update_state(ddata, CPCAP_CHARGER_CHARGING);
	} else {
		error = cpcap_charger_set_state(ddata, 0, 0, 0);
		if (error)
			goto out_err;
		cpcap_charger_update_state(ddata, CPCAP_CHARGER_DISCONNECTED);
	}

	power_supply_changed(ddata->usb);
@@ -524,7 +651,7 @@ static const char * const cpcap_charger_irqs[] = {
	"chrg_det", "rvrs_chrg",

	/* REG_INT1 */
	"chrg_se1b", "se0conn", "rvrs_mode", "chrgcurr1", "vbusvld",
	"chrg_se1b", "se0conn", "rvrs_mode", "chrgcurr2", "chrgcurr1", "vbusvld",

	/* REG_INT_3 */
	"battdetb",
@@ -625,6 +752,7 @@ static int cpcap_charger_probe(struct platform_device *pdev)
		return -ENOMEM;

	ddata->dev = &pdev->dev;
	ddata->voltage = 4200000;

	ddata->reg = dev_get_regmap(ddata->dev->parent, NULL);
	if (!ddata->reg)