Message ID | 20220629143046.213584-12-aidanmacdonald.0x0@gmail.com |
---|---|
State | New |
Headers | show |
Series | Add support for AXP192 PMIC | expand |
On Wed, Jun 29, 2022 at 4:30 PM Aidan MacDonald <aidanmacdonald.0x0@gmail.com> wrote: > > The AXP192's USB power supply is similar to the AXP202 but it has > different USB current limits and a different offset for the VBUS > status register. Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com> > Acked-by: Sebastian Reichel <sebastian.reichel@collabora.com> > Reviewed-by: Chen-Yu Tsai <wens@csie.org> > Signed-off-by: Aidan MacDonald <aidanmacdonald.0x0@gmail.com> > --- > drivers/power/supply/axp20x_usb_power.c | 84 +++++++++++++++++++++---- > 1 file changed, 73 insertions(+), 11 deletions(-) > > diff --git a/drivers/power/supply/axp20x_usb_power.c b/drivers/power/supply/axp20x_usb_power.c > index a1e6d1d44808..f83e2ed6d507 100644 > --- a/drivers/power/supply/axp20x_usb_power.c > +++ b/drivers/power/supply/axp20x_usb_power.c > @@ -48,6 +48,9 @@ > #define AXP813_VBUS_CLIMIT_2000mA 2 > #define AXP813_VBUS_CLIMIT_2500mA 3 > > +#define AXP192_VBUS_CLIMIT_EN BIT(1) > +#define AXP192_VBUS_CLIMIT_100mA BIT(0) > + > #define AXP20X_ADC_EN1_VBUS_CURR BIT(2) > #define AXP20X_ADC_EN1_VBUS_VOLT BIT(3) > > @@ -121,6 +124,25 @@ static void axp20x_usb_power_poll_vbus(struct work_struct *work) > mod_delayed_work(system_power_efficient_wq, &power->vbus_detect, DEBOUNCE_TIME); > } > > +static int axp192_get_current_max(struct axp20x_usb_power *power, int *val) > +{ > + unsigned int v; > + int ret; > + > + ret = regmap_read(power->regmap, AXP20X_VBUS_IPSOUT_MGMT, &v); > + if (ret) > + return ret; > + > + if (!(v & AXP192_VBUS_CLIMIT_EN)) > + *val = -1; > + else if (v & AXP192_VBUS_CLIMIT_100mA) > + *val = 100000; > + else > + *val = 500000; > + > + return 0; > +} > + > static int axp20x_get_current_max(struct axp20x_usb_power *power, int *val) > { > unsigned int v; > @@ -179,7 +201,7 @@ static int axp20x_usb_power_get_property(struct power_supply *psy, > enum power_supply_property psp, union power_supply_propval *val) > { > struct axp20x_usb_power *power = power_supply_get_drvdata(psy); > - unsigned int input, v; > + unsigned int input, v, reg; > int ret; > > switch (psp) { > @@ -215,6 +237,8 @@ static int axp20x_usb_power_get_property(struct power_supply *psy, > case POWER_SUPPLY_PROP_CURRENT_MAX: > if (power->axp20x_id == AXP813_ID) > return axp813_get_current_max(power, &val->intval); > + else if (power->axp20x_id == AXP192_ID) > + return axp192_get_current_max(power, &val->intval); > return axp20x_get_current_max(power, &val->intval); > case POWER_SUPPLY_PROP_CURRENT_NOW: > if (IS_ENABLED(CONFIG_AXP20X_ADC)) { > @@ -256,16 +280,19 @@ static int axp20x_usb_power_get_property(struct power_supply *psy, > > val->intval = POWER_SUPPLY_HEALTH_GOOD; > > - if (power->axp20x_id == AXP202_ID) { > - ret = regmap_read(power->regmap, > - AXP20X_USB_OTG_STATUS, &v); > - if (ret) > - return ret; > + if (power->axp20x_id == AXP192_ID) > + reg = AXP192_USB_OTG_STATUS; > + else if (power->axp20x_id == AXP202_ID) > + reg = AXP20X_USB_OTG_STATUS; > + else > + break; /* Other chips lack the OTG status register */ > > - if (!(v & AXP20X_USB_STATUS_VBUS_VALID)) > - val->intval = > - POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; > - } > + ret = regmap_read(power->regmap, reg, &v); > + if (ret) > + return ret; > + > + if (!(v & AXP20X_USB_STATUS_VBUS_VALID)) > + val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; > break; > case POWER_SUPPLY_PROP_PRESENT: > val->intval = !!(input & AXP20X_PWR_STATUS_VBUS_PRESENT); > @@ -316,6 +343,28 @@ static int axp20x_usb_power_set_voltage_min(struct axp20x_usb_power *power, > return -EINVAL; > } > > +static int axp192_usb_power_set_current_max(struct axp20x_usb_power *power, > + int intval) > +{ > + const unsigned int mask = AXP192_VBUS_CLIMIT_EN | > + AXP192_VBUS_CLIMIT_100mA; > + unsigned int val; > + > + switch (intval) { > + case 100000: > + val = AXP192_VBUS_CLIMIT_EN | AXP192_VBUS_CLIMIT_100mA; > + break; > + case 500000: > + val = AXP192_VBUS_CLIMIT_EN; > + break; > + default: > + return -EINVAL; > + } > + > + return regmap_update_bits(power->regmap, > + AXP20X_VBUS_IPSOUT_MGMT, mask, val); > +} > + > static int axp813_usb_power_set_current_max(struct axp20x_usb_power *power, > int intval) > { > @@ -383,6 +432,9 @@ static int axp20x_usb_power_set_property(struct power_supply *psy, > if (power->axp20x_id == AXP813_ID) > return axp813_usb_power_set_current_max(power, > val->intval); > + else if (power->axp20x_id == AXP192_ID) > + return axp192_usb_power_set_current_max(power, > + val->intval); > return axp20x_usb_power_set_current_max(power, val->intval); > > default: > @@ -468,6 +520,13 @@ struct axp_data { > enum axp20x_variants axp20x_id; > }; > > +static const struct axp_data axp192_data = { > + .power_desc = &axp20x_usb_power_desc, > + .irq_names = axp20x_irq_names, > + .num_irq_names = ARRAY_SIZE(axp20x_irq_names), > + .axp20x_id = AXP192_ID, > +}; > + > static const struct axp_data axp202_data = { > .power_desc = &axp20x_usb_power_desc, > .irq_names = axp20x_irq_names, > @@ -600,7 +659,7 @@ static int axp20x_usb_power_probe(struct platform_device *pdev) > if (ret) > return ret; > > - if (power->axp20x_id == AXP202_ID) { > + if (power->axp20x_id == AXP192_ID || power->axp20x_id == AXP202_ID) { > /* Enable vbus valid checking */ > ret = regmap_update_bits(power->regmap, AXP20X_VBUS_MON, > AXP20X_VBUS_MON_VBUS_VALID, > @@ -659,6 +718,9 @@ static int axp20x_usb_power_probe(struct platform_device *pdev) > > static const struct of_device_id axp20x_usb_power_match[] = { > { > + .compatible = "x-powers,axp192-usb-power-supply", > + .data = &axp192_data, > + }, { > .compatible = "x-powers,axp202-usb-power-supply", > .data = &axp202_data, > }, { > -- > 2.35.1 >
diff --git a/drivers/power/supply/axp20x_usb_power.c b/drivers/power/supply/axp20x_usb_power.c index a1e6d1d44808..f83e2ed6d507 100644 --- a/drivers/power/supply/axp20x_usb_power.c +++ b/drivers/power/supply/axp20x_usb_power.c @@ -48,6 +48,9 @@ #define AXP813_VBUS_CLIMIT_2000mA 2 #define AXP813_VBUS_CLIMIT_2500mA 3 +#define AXP192_VBUS_CLIMIT_EN BIT(1) +#define AXP192_VBUS_CLIMIT_100mA BIT(0) + #define AXP20X_ADC_EN1_VBUS_CURR BIT(2) #define AXP20X_ADC_EN1_VBUS_VOLT BIT(3) @@ -121,6 +124,25 @@ static void axp20x_usb_power_poll_vbus(struct work_struct *work) mod_delayed_work(system_power_efficient_wq, &power->vbus_detect, DEBOUNCE_TIME); } +static int axp192_get_current_max(struct axp20x_usb_power *power, int *val) +{ + unsigned int v; + int ret; + + ret = regmap_read(power->regmap, AXP20X_VBUS_IPSOUT_MGMT, &v); + if (ret) + return ret; + + if (!(v & AXP192_VBUS_CLIMIT_EN)) + *val = -1; + else if (v & AXP192_VBUS_CLIMIT_100mA) + *val = 100000; + else + *val = 500000; + + return 0; +} + static int axp20x_get_current_max(struct axp20x_usb_power *power, int *val) { unsigned int v; @@ -179,7 +201,7 @@ static int axp20x_usb_power_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) { struct axp20x_usb_power *power = power_supply_get_drvdata(psy); - unsigned int input, v; + unsigned int input, v, reg; int ret; switch (psp) { @@ -215,6 +237,8 @@ static int axp20x_usb_power_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_CURRENT_MAX: if (power->axp20x_id == AXP813_ID) return axp813_get_current_max(power, &val->intval); + else if (power->axp20x_id == AXP192_ID) + return axp192_get_current_max(power, &val->intval); return axp20x_get_current_max(power, &val->intval); case POWER_SUPPLY_PROP_CURRENT_NOW: if (IS_ENABLED(CONFIG_AXP20X_ADC)) { @@ -256,16 +280,19 @@ static int axp20x_usb_power_get_property(struct power_supply *psy, val->intval = POWER_SUPPLY_HEALTH_GOOD; - if (power->axp20x_id == AXP202_ID) { - ret = regmap_read(power->regmap, - AXP20X_USB_OTG_STATUS, &v); - if (ret) - return ret; + if (power->axp20x_id == AXP192_ID) + reg = AXP192_USB_OTG_STATUS; + else if (power->axp20x_id == AXP202_ID) + reg = AXP20X_USB_OTG_STATUS; + else + break; /* Other chips lack the OTG status register */ - if (!(v & AXP20X_USB_STATUS_VBUS_VALID)) - val->intval = - POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; - } + ret = regmap_read(power->regmap, reg, &v); + if (ret) + return ret; + + if (!(v & AXP20X_USB_STATUS_VBUS_VALID)) + val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; break; case POWER_SUPPLY_PROP_PRESENT: val->intval = !!(input & AXP20X_PWR_STATUS_VBUS_PRESENT); @@ -316,6 +343,28 @@ static int axp20x_usb_power_set_voltage_min(struct axp20x_usb_power *power, return -EINVAL; } +static int axp192_usb_power_set_current_max(struct axp20x_usb_power *power, + int intval) +{ + const unsigned int mask = AXP192_VBUS_CLIMIT_EN | + AXP192_VBUS_CLIMIT_100mA; + unsigned int val; + + switch (intval) { + case 100000: + val = AXP192_VBUS_CLIMIT_EN | AXP192_VBUS_CLIMIT_100mA; + break; + case 500000: + val = AXP192_VBUS_CLIMIT_EN; + break; + default: + return -EINVAL; + } + + return regmap_update_bits(power->regmap, + AXP20X_VBUS_IPSOUT_MGMT, mask, val); +} + static int axp813_usb_power_set_current_max(struct axp20x_usb_power *power, int intval) { @@ -383,6 +432,9 @@ static int axp20x_usb_power_set_property(struct power_supply *psy, if (power->axp20x_id == AXP813_ID) return axp813_usb_power_set_current_max(power, val->intval); + else if (power->axp20x_id == AXP192_ID) + return axp192_usb_power_set_current_max(power, + val->intval); return axp20x_usb_power_set_current_max(power, val->intval); default: @@ -468,6 +520,13 @@ struct axp_data { enum axp20x_variants axp20x_id; }; +static const struct axp_data axp192_data = { + .power_desc = &axp20x_usb_power_desc, + .irq_names = axp20x_irq_names, + .num_irq_names = ARRAY_SIZE(axp20x_irq_names), + .axp20x_id = AXP192_ID, +}; + static const struct axp_data axp202_data = { .power_desc = &axp20x_usb_power_desc, .irq_names = axp20x_irq_names, @@ -600,7 +659,7 @@ static int axp20x_usb_power_probe(struct platform_device *pdev) if (ret) return ret; - if (power->axp20x_id == AXP202_ID) { + if (power->axp20x_id == AXP192_ID || power->axp20x_id == AXP202_ID) { /* Enable vbus valid checking */ ret = regmap_update_bits(power->regmap, AXP20X_VBUS_MON, AXP20X_VBUS_MON_VBUS_VALID, @@ -659,6 +718,9 @@ static int axp20x_usb_power_probe(struct platform_device *pdev) static const struct of_device_id axp20x_usb_power_match[] = { { + .compatible = "x-powers,axp192-usb-power-supply", + .data = &axp192_data, + }, { .compatible = "x-powers,axp202-usb-power-supply", .data = &axp202_data, }, {