diff mbox series

[v4,11/15] power: supply: axp20x_usb_power: Add support for AXP192

Message ID 20220629143046.213584-12-aidanmacdonald.0x0@gmail.com (mailing list archive)
State Handled Elsewhere
Headers show
Series Add support for AXP192 PMIC | expand

Commit Message

Aidan MacDonald June 29, 2022, 2:30 p.m. UTC
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.

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(-)

Comments

Andy Shevchenko June 30, 2022, 7:59 a.m. UTC | #1
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 mbox series

Patch

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,
 	}, {