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

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
...@@ -5,7 +5,8 @@ Required properties: ...@@ -5,7 +5,8 @@ Required properties:
- interrupts: Interrupt specifier for each name in interrupt-names - interrupts: Interrupt specifier for each name in interrupt-names
- interrupt-names: Should contain the following entries: - interrupt-names: Should contain the following entries:
"chrg_det", "rvrs_chrg", "chrg_se1b", "se0conn", "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-channels: IIO ADC channel specifier for each name in io-channel-names
- io-channel-names: Should contain the following entries: - io-channel-names: Should contain the following entries:
"battdetb", "battp", "vbus", "chg_isense", "batti" "battdetb", "battp", "vbus", "chg_isense", "batti"
...@@ -21,11 +22,13 @@ cpcap_charger: charger { ...@@ -21,11 +22,13 @@ cpcap_charger: charger {
compatible = "motorola,mapphone-cpcap-charger"; compatible = "motorola,mapphone-cpcap-charger";
interrupts-extended = < interrupts-extended = <
&cpcap 13 0 &cpcap 12 0 &cpcap 29 0 &cpcap 28 0 &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 = interrupt-names =
"chrg_det", "rvrs_chrg", "chrg_se1b", "se0conn", "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 mode-gpios = <&gpio3 29 GPIO_ACTIVE_LOW
&gpio3 23 GPIO_ACTIVE_LOW>; &gpio3 23 GPIO_ACTIVE_LOW>;
io-channels = <&cpcap_adc 0 &cpcap_adc 1 io-channels = <&cpcap_adc 0 &cpcap_adc 1
......
...@@ -43,11 +43,13 @@ cpcap_charger: charger { ...@@ -43,11 +43,13 @@ cpcap_charger: charger {
compatible = "motorola,mapphone-cpcap-charger"; compatible = "motorola,mapphone-cpcap-charger";
interrupts-extended = < interrupts-extended = <
&cpcap 13 0 &cpcap 12 0 &cpcap 29 0 &cpcap 28 0 &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 = interrupt-names =
"chrg_det", "rvrs_chrg", "chrg_se1b", "se0conn", "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 mode-gpios = <&gpio3 29 GPIO_ACTIVE_LOW
&gpio3 23 GPIO_ACTIVE_LOW>; &gpio3 23 GPIO_ACTIVE_LOW>;
io-channels = <&cpcap_adc 0 &cpcap_adc 1 io-channels = <&cpcap_adc 0 &cpcap_adc 1
......
...@@ -120,6 +120,13 @@ enum { ...@@ -120,6 +120,13 @@ enum {
CPCAP_CHARGER_IIO_NR, CPCAP_CHARGER_IIO_NR,
}; };
enum {
CPCAP_CHARGER_DISCONNECTED,
CPCAP_CHARGER_DETECTING,
CPCAP_CHARGER_CHARGING,
CPCAP_CHARGER_DONE,
};
struct cpcap_charger_ddata { struct cpcap_charger_ddata {
struct device *dev; struct device *dev;
struct regmap *reg; struct regmap *reg;
...@@ -138,6 +145,8 @@ struct cpcap_charger_ddata { ...@@ -138,6 +145,8 @@ struct cpcap_charger_ddata {
atomic_t active; atomic_t active;
int status; int status;
int state;
int voltage;
}; };
struct cpcap_interrupt_desc { struct cpcap_interrupt_desc {
...@@ -153,6 +162,7 @@ struct cpcap_charger_ints_state { ...@@ -153,6 +162,7 @@ struct cpcap_charger_ints_state {
bool chrg_se1b; bool chrg_se1b;
bool rvrs_mode; bool rvrs_mode;
bool chrgcurr2;
bool chrgcurr1; bool chrgcurr1;
bool vbusvld; bool vbusvld;
...@@ -422,6 +432,7 @@ static int cpcap_charger_get_ints_state(struct cpcap_charger_ddata *ddata, ...@@ -422,6 +432,7 @@ static int cpcap_charger_get_ints_state(struct cpcap_charger_ddata *ddata,
s->chrg_se1b = val & BIT(13); s->chrg_se1b = val & BIT(13);
s->rvrs_mode = val & BIT(6); s->rvrs_mode = val & BIT(6);
s->chrgcurr2 = val & BIT(5);
s->chrgcurr1 = val & BIT(4); s->chrgcurr1 = val & BIT(4);
s->vbusvld = val & BIT(3); s->vbusvld = val & BIT(3);
...@@ -434,6 +445,79 @@ static int cpcap_charger_get_ints_state(struct cpcap_charger_ddata *ddata, ...@@ -434,6 +445,79 @@ static int cpcap_charger_get_ints_state(struct cpcap_charger_ddata *ddata,
return 0; 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) static void cpcap_usb_detect(struct work_struct *work)
{ {
struct cpcap_charger_ddata *ddata; struct cpcap_charger_ddata *ddata;
...@@ -447,24 +531,67 @@ static void cpcap_usb_detect(struct work_struct *work) ...@@ -447,24 +531,67 @@ static void cpcap_usb_detect(struct work_struct *work)
if (error) if (error)
return; 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) && if (!ddata->feeding_vbus && cpcap_charger_vbus_valid(ddata) &&
s.chrgcurr1) { s.chrgcurr1) {
int max_current; int max_current;
int vchrg;
if (cpcap_charger_battery_found(ddata)) if (cpcap_charger_battery_found(ddata))
max_current = CPCAP_REG_CRM_ICHRG_1A596; max_current = CPCAP_REG_CRM_ICHRG_1A596;
else else
max_current = CPCAP_REG_CRM_ICHRG_0A532; max_current = CPCAP_REG_CRM_ICHRG_0A532;
vchrg = cpcap_charger_voltage_to_regval(ddata->voltage);
error = cpcap_charger_set_state(ddata, error = cpcap_charger_set_state(ddata,
CPCAP_REG_CRM_VCHRG_4V35, CPCAP_REG_CRM_VCHRG(vchrg),
max_current, 0); max_current, 0);
if (error) if (error)
goto out_err; goto out_err;
cpcap_charger_update_state(ddata, CPCAP_CHARGER_CHARGING);
} else { } else {
error = cpcap_charger_set_state(ddata, 0, 0, 0); error = cpcap_charger_set_state(ddata, 0, 0, 0);
if (error) if (error)
goto out_err; goto out_err;
cpcap_charger_update_state(ddata, CPCAP_CHARGER_DISCONNECTED);
} }
power_supply_changed(ddata->usb); power_supply_changed(ddata->usb);
...@@ -524,7 +651,7 @@ static const char * const cpcap_charger_irqs[] = { ...@@ -524,7 +651,7 @@ static const char * const cpcap_charger_irqs[] = {
"chrg_det", "rvrs_chrg", "chrg_det", "rvrs_chrg",
/* REG_INT1 */ /* REG_INT1 */
"chrg_se1b", "se0conn", "rvrs_mode", "chrgcurr1", "vbusvld", "chrg_se1b", "se0conn", "rvrs_mode", "chrgcurr2", "chrgcurr1", "vbusvld",
/* REG_INT_3 */ /* REG_INT_3 */
"battdetb", "battdetb",
...@@ -625,6 +752,7 @@ static int cpcap_charger_probe(struct platform_device *pdev) ...@@ -625,6 +752,7 @@ static int cpcap_charger_probe(struct platform_device *pdev)
return -ENOMEM; return -ENOMEM;
ddata->dev = &pdev->dev; ddata->dev = &pdev->dev;
ddata->voltage = 4200000;
ddata->reg = dev_get_regmap(ddata->dev->parent, NULL); ddata->reg = dev_get_regmap(ddata->dev->parent, NULL);
if (!ddata->reg) if (!ddata->reg)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment