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:
- 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
......
......@@ -43,11 +43,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
......
......@@ -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)
......
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