* [PATCH v5 01/13] dt-bindings: mfd: add bindings for AXP192 MFD device
2022-07-06 10:18 [PATCH v5 00/13] Add support for AXP192 PMIC Aidan MacDonald
@ 2022-07-06 10:18 ` Aidan MacDonald
2022-07-06 10:18 ` [PATCH v5 02/13] dt-bindings: iio: adc: axp209: Add AXP192 compatible Aidan MacDonald
` (11 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Aidan MacDonald @ 2022-07-06 10:18 UTC (permalink / raw)
To: jic23, robh+dt, krzysztof.kozlowski+dt, wens, lee.jones, sre,
lgirdwood, broonie
Cc: lars, andy.shevchenko, linus.walleij, brgl, michael, samuel,
linux-iio, linux-kernel, devicetree, linux-pm, Rob Herring
The AXP192 is another X-Powers PMIC similar to the existing ones.
Acked-by: Rob Herring <robh@kernel.org>
Acked-by: Chen-Yu Tsai <wens@csie.org>
Signed-off-by: Aidan MacDonald <aidanmacdonald.0x0@gmail.com>
---
Documentation/devicetree/bindings/mfd/x-powers,axp152.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/mfd/x-powers,axp152.yaml b/Documentation/devicetree/bindings/mfd/x-powers,axp152.yaml
index 3a53bae611bc..33c9b1b3cc04 100644
--- a/Documentation/devicetree/bindings/mfd/x-powers,axp152.yaml
+++ b/Documentation/devicetree/bindings/mfd/x-powers,axp152.yaml
@@ -84,6 +84,7 @@ properties:
oneOf:
- enum:
- x-powers,axp152
+ - x-powers,axp192
- x-powers,axp202
- x-powers,axp209
- x-powers,axp221
--
2.35.1
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH v5 02/13] dt-bindings: iio: adc: axp209: Add AXP192 compatible
2022-07-06 10:18 [PATCH v5 00/13] Add support for AXP192 PMIC Aidan MacDonald
2022-07-06 10:18 ` [PATCH v5 01/13] dt-bindings: mfd: add bindings for AXP192 MFD device Aidan MacDonald
@ 2022-07-06 10:18 ` Aidan MacDonald
2022-07-06 10:18 ` [PATCH v5 03/13] dt-bindings: power: supply: axp20x: " Aidan MacDonald
` (10 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Aidan MacDonald @ 2022-07-06 10:18 UTC (permalink / raw)
To: jic23, robh+dt, krzysztof.kozlowski+dt, wens, lee.jones, sre,
lgirdwood, broonie
Cc: lars, andy.shevchenko, linus.walleij, brgl, michael, samuel,
linux-iio, linux-kernel, devicetree, linux-pm, Rob Herring
The AXP192 is identical to the AXP20x, except for two additional
GPIO ADC channels.
Acked-by: Rob Herring <robh@kernel.org>
Reviewed-by: Chen-Yu Tsai <wens@csie.org>
Signed-off-by: Aidan MacDonald <aidanmacdonald.0x0@gmail.com>
---
.../bindings/iio/adc/x-powers,axp209-adc.yaml | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/Documentation/devicetree/bindings/iio/adc/x-powers,axp209-adc.yaml b/Documentation/devicetree/bindings/iio/adc/x-powers,axp209-adc.yaml
index d6d3d8590171..1a68e650ac7d 100644
--- a/Documentation/devicetree/bindings/iio/adc/x-powers,axp209-adc.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/x-powers,axp209-adc.yaml
@@ -14,6 +14,23 @@ description: |
Device is a child of an axp209 multifunction device
ADC channels and their indexes per variant:
+ AXP192
+ ------
+ 0 | acin_v
+ 1 | acin_i
+ 2 | vbus_v
+ 3 | vbus_i
+ 4 | pmic_temp
+ 5 | gpio0_v
+ 6 | gpio1_v
+ 7 | gpio2_v
+ 8 | gpio3_v
+ 9 | ipsout_v
+ 10 | batt_v
+ 11 | batt_chrg_i
+ 12 | batt_dischrg_i
+ 13 | ts_v
+
AXP209
------
0 | acin_v
@@ -50,6 +67,7 @@ description: |
properties:
compatible:
oneOf:
+ - const: x-powers,axp192-adc
- const: x-powers,axp209-adc
- const: x-powers,axp221-adc
- const: x-powers,axp813-adc
--
2.35.1
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH v5 03/13] dt-bindings: power: supply: axp20x: Add AXP192 compatible
2022-07-06 10:18 [PATCH v5 00/13] Add support for AXP192 PMIC Aidan MacDonald
2022-07-06 10:18 ` [PATCH v5 01/13] dt-bindings: mfd: add bindings for AXP192 MFD device Aidan MacDonald
2022-07-06 10:18 ` [PATCH v5 02/13] dt-bindings: iio: adc: axp209: Add AXP192 compatible Aidan MacDonald
@ 2022-07-06 10:18 ` Aidan MacDonald
2022-07-06 10:18 ` [PATCH v5 04/13] dt-bindings: power: axp20x-battery: " Aidan MacDonald
` (9 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Aidan MacDonald @ 2022-07-06 10:18 UTC (permalink / raw)
To: jic23, robh+dt, krzysztof.kozlowski+dt, wens, lee.jones, sre,
lgirdwood, broonie
Cc: lars, andy.shevchenko, linus.walleij, brgl, michael, samuel,
linux-iio, linux-kernel, devicetree, linux-pm, Rob Herring
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: Rob Herring <robh@kernel.org>
Signed-off-by: Aidan MacDonald <aidanmacdonald.0x0@gmail.com>
---
.../bindings/power/supply/x-powers,axp20x-usb-power-supply.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/power/supply/x-powers,axp20x-usb-power-supply.yaml b/Documentation/devicetree/bindings/power/supply/x-powers,axp20x-usb-power-supply.yaml
index 0c371b55c9e1..e800b3b97f0d 100644
--- a/Documentation/devicetree/bindings/power/supply/x-powers,axp20x-usb-power-supply.yaml
+++ b/Documentation/devicetree/bindings/power/supply/x-powers,axp20x-usb-power-supply.yaml
@@ -22,6 +22,7 @@ properties:
compatible:
oneOf:
- enum:
+ - x-powers,axp192-usb-power-supply
- x-powers,axp202-usb-power-supply
- x-powers,axp221-usb-power-supply
- x-powers,axp223-usb-power-supply
--
2.35.1
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH v5 04/13] dt-bindings: power: axp20x-battery: Add AXP192 compatible
2022-07-06 10:18 [PATCH v5 00/13] Add support for AXP192 PMIC Aidan MacDonald
` (2 preceding siblings ...)
2022-07-06 10:18 ` [PATCH v5 03/13] dt-bindings: power: supply: axp20x: " Aidan MacDonald
@ 2022-07-06 10:18 ` Aidan MacDonald
2022-07-06 10:18 ` [PATCH v5 05/13] mfd: axp20x: Add support for AXP192 Aidan MacDonald
` (8 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Aidan MacDonald @ 2022-07-06 10:18 UTC (permalink / raw)
To: jic23, robh+dt, krzysztof.kozlowski+dt, wens, lee.jones, sre,
lgirdwood, broonie
Cc: lars, andy.shevchenko, linus.walleij, brgl, michael, samuel,
linux-iio, linux-kernel, devicetree, linux-pm, Rob Herring
The AXP192's battery charger is similar to the others supported by
the axp20x_battery driver.
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Aidan MacDonald <aidanmacdonald.0x0@gmail.com>
---
.../power/supply/x-powers,axp20x-battery-power-supply.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/power/supply/x-powers,axp20x-battery-power-supply.yaml b/Documentation/devicetree/bindings/power/supply/x-powers,axp20x-battery-power-supply.yaml
index d055428ae39f..b7347683a07e 100644
--- a/Documentation/devicetree/bindings/power/supply/x-powers,axp20x-battery-power-supply.yaml
+++ b/Documentation/devicetree/bindings/power/supply/x-powers,axp20x-battery-power-supply.yaml
@@ -20,6 +20,7 @@ allOf:
properties:
compatible:
oneOf:
+ - const: x-powers,axp192-battery-power-supply
- const: x-powers,axp202-battery-power-supply
- const: x-powers,axp209-battery-power-supply
- const: x-powers,axp221-battery-power-supply
--
2.35.1
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH v5 05/13] mfd: axp20x: Add support for AXP192
2022-07-06 10:18 [PATCH v5 00/13] Add support for AXP192 PMIC Aidan MacDonald
` (3 preceding siblings ...)
2022-07-06 10:18 ` [PATCH v5 04/13] dt-bindings: power: axp20x-battery: " Aidan MacDonald
@ 2022-07-06 10:18 ` Aidan MacDonald
2022-07-06 10:18 ` [PATCH v5 06/13] regulator: " Aidan MacDonald
` (7 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Aidan MacDonald @ 2022-07-06 10:18 UTC (permalink / raw)
To: jic23, robh+dt, krzysztof.kozlowski+dt, wens, lee.jones, sre,
lgirdwood, broonie
Cc: lars, andy.shevchenko, linus.walleij, brgl, michael, samuel,
linux-iio, linux-kernel, devicetree, linux-pm
The AXP192 PMIC is similar to the AXP202/AXP209, but with different
regulators, additional GPIOs, and a different IRQ register layout.
Acked-for-MFD-by: Lee Jones <lee.jones@linaro.org>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Signed-off-by: Aidan MacDonald <aidanmacdonald.0x0@gmail.com>
---
drivers/mfd/axp20x-i2c.c | 2 +
drivers/mfd/axp20x.c | 141 +++++++++++++++++++++++++++++++++++++
include/linux/mfd/axp20x.h | 84 ++++++++++++++++++++++
3 files changed, 227 insertions(+)
diff --git a/drivers/mfd/axp20x-i2c.c b/drivers/mfd/axp20x-i2c.c
index 00ab48018d8d..9ada58fad77f 100644
--- a/drivers/mfd/axp20x-i2c.c
+++ b/drivers/mfd/axp20x-i2c.c
@@ -62,6 +62,7 @@ static int axp20x_i2c_remove(struct i2c_client *i2c)
#ifdef CONFIG_OF
static const struct of_device_id axp20x_i2c_of_match[] = {
{ .compatible = "x-powers,axp152", .data = (void *)AXP152_ID },
+ { .compatible = "x-powers,axp192", .data = (void *)AXP192_ID },
{ .compatible = "x-powers,axp202", .data = (void *)AXP202_ID },
{ .compatible = "x-powers,axp209", .data = (void *)AXP209_ID },
{ .compatible = "x-powers,axp221", .data = (void *)AXP221_ID },
@@ -75,6 +76,7 @@ MODULE_DEVICE_TABLE(of, axp20x_i2c_of_match);
static const struct i2c_device_id axp20x_i2c_id[] = {
{ "axp152", 0 },
+ { "axp192", 0 },
{ "axp202", 0 },
{ "axp209", 0 },
{ "axp221", 0 },
diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c
index 8161a5dc68e8..3586bb13d7fc 100644
--- a/drivers/mfd/axp20x.c
+++ b/drivers/mfd/axp20x.c
@@ -34,6 +34,7 @@
static const char * const axp20x_model_names[] = {
"AXP152",
+ "AXP192",
"AXP202",
"AXP209",
"AXP221",
@@ -92,6 +93,35 @@ static const struct regmap_access_table axp20x_volatile_table = {
.n_yes_ranges = ARRAY_SIZE(axp20x_volatile_ranges),
};
+static const struct regmap_range axp192_writeable_ranges[] = {
+ regmap_reg_range(AXP192_DATACACHE(0), AXP192_DATACACHE(5)),
+ regmap_reg_range(AXP192_PWR_OUT_CTRL, AXP192_IRQ5_STATE),
+ regmap_reg_range(AXP20X_DCDC_MODE, AXP192_N_RSTO_CTRL),
+ regmap_reg_range(AXP20X_CC_CTRL, AXP20X_CC_CTRL),
+};
+
+static const struct regmap_range axp192_volatile_ranges[] = {
+ regmap_reg_range(AXP20X_PWR_INPUT_STATUS, AXP192_USB_OTG_STATUS),
+ regmap_reg_range(AXP192_IRQ1_STATE, AXP192_IRQ4_STATE),
+ regmap_reg_range(AXP192_IRQ5_STATE, AXP192_IRQ5_STATE),
+ regmap_reg_range(AXP20X_ACIN_V_ADC_H, AXP20X_IPSOUT_V_HIGH_L),
+ regmap_reg_range(AXP20X_TIMER_CTRL, AXP20X_TIMER_CTRL),
+ regmap_reg_range(AXP192_GPIO2_0_STATE, AXP192_GPIO2_0_STATE),
+ regmap_reg_range(AXP192_GPIO4_3_STATE, AXP192_GPIO4_3_STATE),
+ regmap_reg_range(AXP192_N_RSTO_CTRL, AXP192_N_RSTO_CTRL),
+ regmap_reg_range(AXP20X_CHRG_CC_31_24, AXP20X_CC_CTRL),
+};
+
+static const struct regmap_access_table axp192_writeable_table = {
+ .yes_ranges = axp192_writeable_ranges,
+ .n_yes_ranges = ARRAY_SIZE(axp192_writeable_ranges),
+};
+
+static const struct regmap_access_table axp192_volatile_table = {
+ .yes_ranges = axp192_volatile_ranges,
+ .n_yes_ranges = ARRAY_SIZE(axp192_volatile_ranges),
+};
+
/* AXP22x ranges are shared with the AXP809, as they cover the same range */
static const struct regmap_range axp22x_writeable_ranges[] = {
regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ5_STATE),
@@ -173,6 +203,19 @@ static const struct resource axp152_pek_resources[] = {
DEFINE_RES_IRQ_NAMED(AXP152_IRQ_PEK_FAL_EDGE, "PEK_DBF"),
};
+static const struct resource axp192_ac_power_supply_resources[] = {
+ DEFINE_RES_IRQ_NAMED(AXP192_IRQ_ACIN_PLUGIN, "ACIN_PLUGIN"),
+ DEFINE_RES_IRQ_NAMED(AXP192_IRQ_ACIN_REMOVAL, "ACIN_REMOVAL"),
+ DEFINE_RES_IRQ_NAMED(AXP192_IRQ_ACIN_OVER_V, "ACIN_OVER_V"),
+};
+
+static const struct resource axp192_usb_power_supply_resources[] = {
+ DEFINE_RES_IRQ_NAMED(AXP192_IRQ_VBUS_PLUGIN, "VBUS_PLUGIN"),
+ DEFINE_RES_IRQ_NAMED(AXP192_IRQ_VBUS_REMOVAL, "VBUS_REMOVAL"),
+ DEFINE_RES_IRQ_NAMED(AXP192_IRQ_VBUS_VALID, "VBUS_VALID"),
+ DEFINE_RES_IRQ_NAMED(AXP192_IRQ_VBUS_NOT_VALID, "VBUS_NOT_VALID"),
+};
+
static const struct resource axp20x_ac_power_supply_resources[] = {
DEFINE_RES_IRQ_NAMED(AXP20X_IRQ_ACIN_PLUGIN, "ACIN_PLUGIN"),
DEFINE_RES_IRQ_NAMED(AXP20X_IRQ_ACIN_REMOVAL, "ACIN_REMOVAL"),
@@ -245,6 +288,15 @@ static const struct regmap_config axp152_regmap_config = {
.cache_type = REGCACHE_RBTREE,
};
+static const struct regmap_config axp192_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .wr_table = &axp192_writeable_table,
+ .volatile_table = &axp192_volatile_table,
+ .max_register = AXP20X_CC_CTRL,
+ .cache_type = REGCACHE_RBTREE,
+};
+
static const struct regmap_config axp20x_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
@@ -304,6 +356,42 @@ static const struct regmap_irq axp152_regmap_irqs[] = {
INIT_REGMAP_IRQ(AXP152, GPIO0_INPUT, 2, 0),
};
+static const struct regmap_irq axp192_regmap_irqs[] = {
+ INIT_REGMAP_IRQ(AXP192, ACIN_OVER_V, 0, 7),
+ INIT_REGMAP_IRQ(AXP192, ACIN_PLUGIN, 0, 6),
+ INIT_REGMAP_IRQ(AXP192, ACIN_REMOVAL, 0, 5),
+ INIT_REGMAP_IRQ(AXP192, VBUS_OVER_V, 0, 4),
+ INIT_REGMAP_IRQ(AXP192, VBUS_PLUGIN, 0, 3),
+ INIT_REGMAP_IRQ(AXP192, VBUS_REMOVAL, 0, 2),
+ INIT_REGMAP_IRQ(AXP192, VBUS_V_LOW, 0, 1),
+ INIT_REGMAP_IRQ(AXP192, BATT_PLUGIN, 1, 7),
+ INIT_REGMAP_IRQ(AXP192, BATT_REMOVAL, 1, 6),
+ INIT_REGMAP_IRQ(AXP192, BATT_ENT_ACT_MODE, 1, 5),
+ INIT_REGMAP_IRQ(AXP192, BATT_EXIT_ACT_MODE, 1, 4),
+ INIT_REGMAP_IRQ(AXP192, CHARG, 1, 3),
+ INIT_REGMAP_IRQ(AXP192, CHARG_DONE, 1, 2),
+ INIT_REGMAP_IRQ(AXP192, BATT_TEMP_HIGH, 1, 1),
+ INIT_REGMAP_IRQ(AXP192, BATT_TEMP_LOW, 1, 0),
+ INIT_REGMAP_IRQ(AXP192, DIE_TEMP_HIGH, 2, 7),
+ INIT_REGMAP_IRQ(AXP192, CHARG_I_LOW, 2, 6),
+ INIT_REGMAP_IRQ(AXP192, DCDC1_V_LONG, 2, 5),
+ INIT_REGMAP_IRQ(AXP192, DCDC2_V_LONG, 2, 4),
+ INIT_REGMAP_IRQ(AXP192, DCDC3_V_LONG, 2, 3),
+ INIT_REGMAP_IRQ(AXP192, PEK_SHORT, 2, 1),
+ INIT_REGMAP_IRQ(AXP192, PEK_LONG, 2, 0),
+ INIT_REGMAP_IRQ(AXP192, N_OE_PWR_ON, 3, 7),
+ INIT_REGMAP_IRQ(AXP192, N_OE_PWR_OFF, 3, 6),
+ INIT_REGMAP_IRQ(AXP192, VBUS_VALID, 3, 5),
+ INIT_REGMAP_IRQ(AXP192, VBUS_NOT_VALID, 3, 4),
+ INIT_REGMAP_IRQ(AXP192, VBUS_SESS_VALID, 3, 3),
+ INIT_REGMAP_IRQ(AXP192, VBUS_SESS_END, 3, 2),
+ INIT_REGMAP_IRQ(AXP192, LOW_PWR_LVL, 3, 0),
+ INIT_REGMAP_IRQ(AXP192, TIMER, 4, 7),
+ INIT_REGMAP_IRQ(AXP192, GPIO2_INPUT, 4, 2),
+ INIT_REGMAP_IRQ(AXP192, GPIO1_INPUT, 4, 1),
+ INIT_REGMAP_IRQ(AXP192, GPIO0_INPUT, 4, 0),
+};
+
static const struct regmap_irq axp20x_regmap_irqs[] = {
INIT_REGMAP_IRQ(AXP20X, ACIN_OVER_V, 0, 7),
INIT_REGMAP_IRQ(AXP20X, ACIN_PLUGIN, 0, 6),
@@ -514,6 +602,32 @@ static const struct regmap_irq_chip axp152_regmap_irq_chip = {
.num_regs = 3,
};
+static unsigned int axp192_get_irq_reg(struct regmap_irq_chip_data *data,
+ unsigned int base, int index)
+{
+ /* linear mapping for IRQ1 to IRQ4 */
+ if (index < 4)
+ return base + index;
+
+ /* handle IRQ5 separately */
+ if (base == AXP192_IRQ1_EN)
+ return AXP192_IRQ5_EN;
+
+ return AXP192_IRQ5_STATE;
+}
+
+static const struct regmap_irq_chip axp192_regmap_irq_chip = {
+ .name = "axp192_irq_chip",
+ .status_base = AXP192_IRQ1_STATE,
+ .ack_base = AXP192_IRQ1_STATE,
+ .unmask_base = AXP192_IRQ1_EN,
+ .init_ack_masked = true,
+ .irqs = axp192_regmap_irqs,
+ .num_irqs = ARRAY_SIZE(axp192_regmap_irqs),
+ .num_regs = 5,
+ .get_irq_reg = axp192_get_irq_reg,
+};
+
static const struct regmap_irq_chip axp20x_regmap_irq_chip = {
.name = "axp20x_irq_chip",
.status_base = AXP20X_IRQ1_STATE,
@@ -588,6 +702,27 @@ static const struct regmap_irq_chip axp809_regmap_irq_chip = {
.num_regs = 5,
};
+static const struct mfd_cell axp192_cells[] = {
+ {
+ .name = "axp192-adc",
+ .of_compatible = "x-powers,axp192-adc",
+ }, {
+ .name = "axp20x-battery-power-supply",
+ .of_compatible = "x-powers,axp192-battery-power-supply",
+ }, {
+ .name = "axp20x-ac-power-supply",
+ .of_compatible = "x-powers,axp202-ac-power-supply",
+ .num_resources = ARRAY_SIZE(axp192_ac_power_supply_resources),
+ .resources = axp192_ac_power_supply_resources,
+ }, {
+ .name = "axp20x-usb-power-supply",
+ .of_compatible = "x-powers,axp192-usb-power-supply",
+ .num_resources = ARRAY_SIZE(axp192_usb_power_supply_resources),
+ .resources = axp192_usb_power_supply_resources,
+ },
+ { .name = "axp20x-regulator" },
+};
+
static const struct mfd_cell axp20x_cells[] = {
{
.name = "axp20x-gpio",
@@ -865,6 +1000,12 @@ int axp20x_match_device(struct axp20x_dev *axp20x)
axp20x->regmap_cfg = &axp152_regmap_config;
axp20x->regmap_irq_chip = &axp152_regmap_irq_chip;
break;
+ case AXP192_ID:
+ axp20x->nr_cells = ARRAY_SIZE(axp192_cells);
+ axp20x->cells = axp192_cells;
+ axp20x->regmap_cfg = &axp192_regmap_config;
+ axp20x->regmap_irq_chip = &axp192_regmap_irq_chip;
+ break;
case AXP202_ID:
case AXP209_ID:
axp20x->nr_cells = ARRAY_SIZE(axp20x_cells);
diff --git a/include/linux/mfd/axp20x.h b/include/linux/mfd/axp20x.h
index 9ab0e2fca7ea..c9a9ee8ec246 100644
--- a/include/linux/mfd/axp20x.h
+++ b/include/linux/mfd/axp20x.h
@@ -12,6 +12,7 @@
enum axp20x_variants {
AXP152_ID = 0,
+ AXP192_ID,
AXP202_ID,
AXP209_ID,
AXP221_ID,
@@ -24,6 +25,7 @@ enum axp20x_variants {
NR_AXP20X_VARIANTS,
};
+#define AXP192_DATACACHE(m) (0x06 + (m))
#define AXP20X_DATACACHE(m) (0x04 + (m))
/* Power supply */
@@ -45,6 +47,13 @@ enum axp20x_variants {
#define AXP152_DCDC_FREQ 0x37
#define AXP152_DCDC_MODE 0x80
+#define AXP192_USB_OTG_STATUS 0x04
+#define AXP192_PWR_OUT_CTRL 0x12
+#define AXP192_DCDC2_V_OUT 0x23
+#define AXP192_DCDC1_V_OUT 0x26
+#define AXP192_DCDC3_V_OUT 0x27
+#define AXP192_LDO2_3_V_OUT 0x28
+
#define AXP20X_PWR_INPUT_STATUS 0x00
#define AXP20X_PWR_OP_MODE 0x01
#define AXP20X_USB_OTG_STATUS 0x02
@@ -139,6 +148,17 @@ enum axp20x_variants {
#define AXP152_IRQ2_STATE 0x49
#define AXP152_IRQ3_STATE 0x4a
+#define AXP192_IRQ1_EN 0x40
+#define AXP192_IRQ2_EN 0x41
+#define AXP192_IRQ3_EN 0x42
+#define AXP192_IRQ4_EN 0x43
+#define AXP192_IRQ1_STATE 0x44
+#define AXP192_IRQ2_STATE 0x45
+#define AXP192_IRQ3_STATE 0x46
+#define AXP192_IRQ4_STATE 0x47
+#define AXP192_IRQ5_EN 0x4a
+#define AXP192_IRQ5_STATE 0x4d
+
#define AXP20X_IRQ1_EN 0x40
#define AXP20X_IRQ2_EN 0x41
#define AXP20X_IRQ3_EN 0x42
@@ -153,6 +173,11 @@ enum axp20x_variants {
#define AXP20X_IRQ6_STATE 0x4d
/* ADC */
+#define AXP192_GPIO2_V_ADC_H 0x68
+#define AXP192_GPIO2_V_ADC_L 0x69
+#define AXP192_GPIO3_V_ADC_H 0x6a
+#define AXP192_GPIO3_V_ADC_L 0x6b
+
#define AXP20X_ACIN_V_ADC_H 0x56
#define AXP20X_ACIN_V_ADC_L 0x57
#define AXP20X_ACIN_I_ADC_H 0x58
@@ -182,6 +207,8 @@ enum axp20x_variants {
#define AXP20X_IPSOUT_V_HIGH_L 0x7f
/* Power supply */
+#define AXP192_GPIO30_IN_RANGE 0x85
+
#define AXP20X_DCDC_MODE 0x80
#define AXP20X_ADC_EN1 0x82
#define AXP20X_ADC_EN2 0x83
@@ -210,6 +237,16 @@ enum axp20x_variants {
#define AXP152_PWM1_FREQ_Y 0x9c
#define AXP152_PWM1_DUTY_CYCLE 0x9d
+#define AXP192_GPIO0_CTRL 0x90
+#define AXP192_LDO_IO0_V_OUT 0x91
+#define AXP192_GPIO1_CTRL 0x92
+#define AXP192_GPIO2_CTRL 0x93
+#define AXP192_GPIO2_0_STATE 0x94
+#define AXP192_GPIO4_3_CTRL 0x95
+#define AXP192_GPIO4_3_STATE 0x96
+#define AXP192_GPIO2_0_PULL 0x97
+#define AXP192_N_RSTO_CTRL 0x9e
+
#define AXP20X_GPIO0_CTRL 0x90
#define AXP20X_LDO5_V_OUT 0x91
#define AXP20X_GPIO1_CTRL 0x92
@@ -287,6 +324,17 @@ enum axp20x_variants {
#define AXP288_FG_TUNE5 0xed
/* Regulators IDs */
+enum {
+ AXP192_DCDC1 = 0,
+ AXP192_DCDC2,
+ AXP192_DCDC3,
+ AXP192_LDO1,
+ AXP192_LDO2,
+ AXP192_LDO3,
+ AXP192_LDO_IO0,
+ AXP192_REG_ID_MAX
+};
+
enum {
AXP20X_LDO1 = 0,
AXP20X_LDO2,
@@ -440,6 +488,42 @@ enum {
AXP152_IRQ_GPIO0_INPUT,
};
+enum axp192_irqs {
+ AXP192_IRQ_ACIN_OVER_V = 1,
+ AXP192_IRQ_ACIN_PLUGIN,
+ AXP192_IRQ_ACIN_REMOVAL,
+ AXP192_IRQ_VBUS_OVER_V,
+ AXP192_IRQ_VBUS_PLUGIN,
+ AXP192_IRQ_VBUS_REMOVAL,
+ AXP192_IRQ_VBUS_V_LOW,
+ AXP192_IRQ_BATT_PLUGIN,
+ AXP192_IRQ_BATT_REMOVAL,
+ AXP192_IRQ_BATT_ENT_ACT_MODE,
+ AXP192_IRQ_BATT_EXIT_ACT_MODE,
+ AXP192_IRQ_CHARG,
+ AXP192_IRQ_CHARG_DONE,
+ AXP192_IRQ_BATT_TEMP_HIGH,
+ AXP192_IRQ_BATT_TEMP_LOW,
+ AXP192_IRQ_DIE_TEMP_HIGH,
+ AXP192_IRQ_CHARG_I_LOW,
+ AXP192_IRQ_DCDC1_V_LONG,
+ AXP192_IRQ_DCDC2_V_LONG,
+ AXP192_IRQ_DCDC3_V_LONG,
+ AXP192_IRQ_PEK_SHORT = 22,
+ AXP192_IRQ_PEK_LONG,
+ AXP192_IRQ_N_OE_PWR_ON,
+ AXP192_IRQ_N_OE_PWR_OFF,
+ AXP192_IRQ_VBUS_VALID,
+ AXP192_IRQ_VBUS_NOT_VALID,
+ AXP192_IRQ_VBUS_SESS_VALID,
+ AXP192_IRQ_VBUS_SESS_END,
+ AXP192_IRQ_LOW_PWR_LVL = 31,
+ AXP192_IRQ_TIMER,
+ AXP192_IRQ_GPIO2_INPUT = 37,
+ AXP192_IRQ_GPIO1_INPUT,
+ AXP192_IRQ_GPIO0_INPUT,
+};
+
enum {
AXP20X_IRQ_ACIN_OVER_V = 1,
AXP20X_IRQ_ACIN_PLUGIN,
--
2.35.1
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH v5 06/13] regulator: axp20x: Add support for AXP192
2022-07-06 10:18 [PATCH v5 00/13] Add support for AXP192 PMIC Aidan MacDonald
` (4 preceding siblings ...)
2022-07-06 10:18 ` [PATCH v5 05/13] mfd: axp20x: Add support for AXP192 Aidan MacDonald
@ 2022-07-06 10:18 ` Aidan MacDonald
2022-07-06 10:18 ` [PATCH v5 07/13] iio: adc: axp20x_adc: Minor code cleanups Aidan MacDonald
` (6 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Aidan MacDonald @ 2022-07-06 10:18 UTC (permalink / raw)
To: jic23, robh+dt, krzysztof.kozlowski+dt, wens, lee.jones, sre,
lgirdwood, broonie
Cc: lars, andy.shevchenko, linus.walleij, brgl, michael, samuel,
linux-iio, linux-kernel, devicetree, linux-pm
Add support for the AXP192 PMIC.
Acked-by: Mark Brown <broonie@kernel.org>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Signed-off-by: Aidan MacDonald <aidanmacdonald.0x0@gmail.com>
---
drivers/regulator/axp20x-regulator.c | 100 ++++++++++++++++++++++++---
1 file changed, 91 insertions(+), 9 deletions(-)
diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c
index d260c442b788..ee79a9ed0249 100644
--- a/drivers/regulator/axp20x-regulator.c
+++ b/drivers/regulator/axp20x-regulator.c
@@ -27,6 +27,29 @@
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
+#define AXP192_GPIO0_FUNC_MASK GENMASK(2, 0)
+
+#define AXP192_IO_ENABLED 0x02
+#define AXP192_IO_DISABLED 0x06
+
+#define AXP192_WORKMODE_DCDC1_MASK BIT_MASK(3)
+#define AXP192_WORKMODE_DCDC2_MASK BIT_MASK(2)
+#define AXP192_WORKMODE_DCDC3_MASK BIT_MASK(1)
+
+#define AXP192_DCDC1_V_OUT_MASK GENMASK(6, 0)
+#define AXP192_DCDC2_V_OUT_MASK GENMASK(5, 0)
+#define AXP192_DCDC3_V_OUT_MASK GENMASK(6, 0)
+#define AXP192_LDO2_V_OUT_MASK GENMASK(7, 4)
+#define AXP192_LDO3_V_OUT_MASK GENMASK(3, 0)
+#define AXP192_LDO_IO0_V_OUT_MASK GENMASK(7, 4)
+
+#define AXP192_PWR_OUT_EXTEN_MASK BIT_MASK(6)
+#define AXP192_PWR_OUT_DCDC2_MASK BIT_MASK(4)
+#define AXP192_PWR_OUT_LDO3_MASK BIT_MASK(3)
+#define AXP192_PWR_OUT_LDO2_MASK BIT_MASK(2)
+#define AXP192_PWR_OUT_DCDC3_MASK BIT_MASK(1)
+#define AXP192_PWR_OUT_DCDC1_MASK BIT_MASK(0)
+
#define AXP20X_GPIO0_FUNC_MASK GENMASK(3, 0)
#define AXP20X_GPIO1_FUNC_MASK GENMASK(3, 0)
@@ -375,25 +398,32 @@ static int axp20x_set_ramp_delay(struct regulator_dev *rdev, int ramp)
switch (axp20x->variant) {
case AXP209_ID:
- if (id == AXP20X_DCDC2) {
+ if (id == AXP20X_LDO3) {
slew_rates = axp209_dcdc2_ldo3_slew_rates;
rate_count = ARRAY_SIZE(axp209_dcdc2_ldo3_slew_rates);
reg = AXP20X_DCDC2_LDO3_V_RAMP;
- mask = AXP20X_DCDC2_LDO3_V_RAMP_DCDC2_RATE_MASK |
- AXP20X_DCDC2_LDO3_V_RAMP_DCDC2_EN_MASK;
+ mask = AXP20X_DCDC2_LDO3_V_RAMP_LDO3_RATE_MASK |
+ AXP20X_DCDC2_LDO3_V_RAMP_LDO3_EN_MASK;
enable = (ramp > 0) ?
- AXP20X_DCDC2_LDO3_V_RAMP_DCDC2_EN : 0;
+ AXP20X_DCDC2_LDO3_V_RAMP_LDO3_EN : 0;
break;
}
- if (id == AXP20X_LDO3) {
+ fallthrough;
+
+ case AXP192_ID:
+ /*
+ * AXP192 and AXP209 share the same DCDC2 ramp configuration
+ */
+ if ((axp20x->variant == AXP209_ID && id == AXP20X_DCDC2) ||
+ (axp20x->variant == AXP192_ID && id == AXP192_DCDC2)) {
slew_rates = axp209_dcdc2_ldo3_slew_rates;
rate_count = ARRAY_SIZE(axp209_dcdc2_ldo3_slew_rates);
reg = AXP20X_DCDC2_LDO3_V_RAMP;
- mask = AXP20X_DCDC2_LDO3_V_RAMP_LDO3_RATE_MASK |
- AXP20X_DCDC2_LDO3_V_RAMP_LDO3_EN_MASK;
+ mask = AXP20X_DCDC2_LDO3_V_RAMP_DCDC2_RATE_MASK |
+ AXP20X_DCDC2_LDO3_V_RAMP_DCDC2_EN_MASK;
enable = (ramp > 0) ?
- AXP20X_DCDC2_LDO3_V_RAMP_LDO3_EN : 0;
+ AXP20X_DCDC2_LDO3_V_RAMP_DCDC2_EN : 0;
break;
}
@@ -415,7 +445,8 @@ static int axp20x_set_ramp_delay(struct regulator_dev *rdev, int ramp)
if (ramp > slew_rates[i])
break;
- if (id == AXP20X_DCDC2)
+ if ((axp20x->variant == AXP209_ID && id == AXP20X_DCDC2) ||
+ (axp20x->variant == AXP192_ID && id == AXP192_DCDC2))
cfg = AXP20X_DCDC2_LDO3_V_RAMP_DCDC2_RATE(i);
else
cfg = AXP20X_DCDC2_LDO3_V_RAMP_LDO3_RATE(i);
@@ -511,6 +542,29 @@ static const struct regulator_ops axp20x_ops_sw = {
.is_enabled = regulator_is_enabled_regmap,
};
+static const struct regulator_desc axp192_regulators[] = {
+ AXP_DESC(AXP192, DCDC1, "dcdc1", "vin1", 700, 3500, 25,
+ AXP192_DCDC1_V_OUT, AXP192_DCDC1_V_OUT_MASK,
+ AXP192_PWR_OUT_CTRL, AXP192_PWR_OUT_DCDC1_MASK),
+ AXP_DESC(AXP192, DCDC2, "dcdc2", "vin2", 700, 2275, 25,
+ AXP192_DCDC2_V_OUT, AXP192_DCDC2_V_OUT_MASK,
+ AXP192_PWR_OUT_CTRL, AXP192_PWR_OUT_DCDC2_MASK),
+ AXP_DESC(AXP192, DCDC3, "dcdc3", "vin3", 700, 3500, 25,
+ AXP192_DCDC3_V_OUT, AXP192_DCDC3_V_OUT_MASK,
+ AXP192_PWR_OUT_CTRL, AXP192_PWR_OUT_DCDC3_MASK),
+ AXP_DESC_FIXED(AXP192, LDO1, "ldo1", "acin", 1250),
+ AXP_DESC(AXP192, LDO2, "ldo2", "ldoin", 1800, 3300, 100,
+ AXP192_LDO2_3_V_OUT, AXP192_LDO2_V_OUT_MASK,
+ AXP192_PWR_OUT_CTRL, AXP192_PWR_OUT_LDO2_MASK),
+ AXP_DESC(AXP192, LDO3, "ldo3", "ldoin", 1800, 3300, 100,
+ AXP192_LDO2_3_V_OUT, AXP192_LDO3_V_OUT_MASK,
+ AXP192_PWR_OUT_CTRL, AXP192_PWR_OUT_LDO3_MASK),
+ AXP_DESC_IO(AXP192, LDO_IO0, "ldo_io0", "ips", 700, 3300, 100,
+ AXP192_LDO_IO0_V_OUT, AXP192_LDO_IO0_V_OUT_MASK,
+ AXP192_GPIO0_CTRL, AXP192_GPIO0_FUNC_MASK,
+ AXP192_IO_ENABLED, AXP192_IO_DISABLED),
+};
+
static const struct linear_range axp20x_ldo4_ranges[] = {
REGULATOR_LINEAR_RANGE(1250000,
AXP20X_LDO4_V_OUT_1250mV_START,
@@ -1008,6 +1062,12 @@ static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq)
u32 min, max, def, step;
switch (axp20x->variant) {
+ case AXP192_ID:
+ min = 900;
+ max = 2025;
+ def = 1500;
+ step = 75;
+ break;
case AXP202_ID:
case AXP209_ID:
min = 750;
@@ -1100,6 +1160,24 @@ static int axp20x_set_dcdc_workmode(struct regulator_dev *rdev, int id, u32 work
unsigned int mask;
switch (axp20x->variant) {
+ case AXP192_ID:
+ switch (id) {
+ case AXP192_DCDC1:
+ mask = AXP192_WORKMODE_DCDC1_MASK;
+ break;
+ case AXP192_DCDC2:
+ mask = AXP192_WORKMODE_DCDC2_MASK;
+ break;
+ case AXP192_DCDC3:
+ mask = AXP192_WORKMODE_DCDC3_MASK;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ workmode <<= ffs(mask) - 1;
+ break;
+
case AXP202_ID:
case AXP209_ID:
if ((id != AXP20X_DCDC2) && (id != AXP20X_DCDC3))
@@ -1220,6 +1298,10 @@ static int axp20x_regulator_probe(struct platform_device *pdev)
bool drivevbus = false;
switch (axp20x->variant) {
+ case AXP192_ID:
+ regulators = axp192_regulators;
+ nregulators = AXP192_REG_ID_MAX;
+ break;
case AXP202_ID:
case AXP209_ID:
regulators = axp20x_regulators;
--
2.35.1
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH v5 07/13] iio: adc: axp20x_adc: Minor code cleanups
2022-07-06 10:18 [PATCH v5 00/13] Add support for AXP192 PMIC Aidan MacDonald
` (5 preceding siblings ...)
2022-07-06 10:18 ` [PATCH v5 06/13] regulator: " Aidan MacDonald
@ 2022-07-06 10:18 ` Aidan MacDonald
2022-07-06 10:18 ` [PATCH v5 08/13] iio: adc: axp20x_adc: Replace adc_en2 flag with adc_en2_mask field Aidan MacDonald
` (5 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Aidan MacDonald @ 2022-07-06 10:18 UTC (permalink / raw)
To: jic23, robh+dt, krzysztof.kozlowski+dt, wens, lee.jones, sre,
lgirdwood, broonie
Cc: lars, andy.shevchenko, linus.walleij, brgl, michael, samuel,
linux-iio, linux-kernel, devicetree, linux-pm, Jonathan Cameron
The code may be clearer if parameters are not re-purposed to hold
temporary results like register values, so introduce local variables
as necessary to avoid that. Regroup macros based on chip type, and
use the FIELD_PREP() macro instead of a hand-rolled version.
Suggested-by: Jonathan Cameron <jic23@kernel.org>
Reviewed-by: Chen-Yu Tsai <wens@csie.org>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Signed-off-by: Aidan MacDonald <aidanmacdonald.0x0@gmail.com>
---
drivers/iio/adc/axp20x_adc.c | 61 +++++++++++++++++++-----------------
1 file changed, 32 insertions(+), 29 deletions(-)
diff --git a/drivers/iio/adc/axp20x_adc.c b/drivers/iio/adc/axp20x_adc.c
index 53bf7d4899d2..ab25e6e1ff65 100644
--- a/drivers/iio/adc/axp20x_adc.c
+++ b/drivers/iio/adc/axp20x_adc.c
@@ -5,6 +5,7 @@
* Quentin Schulz <quentin.schulz@free-electrons.com>
*/
+#include <linux/bitfield.h>
#include <linux/completion.h>
#include <linux/interrupt.h>
#include <linux/io.h>
@@ -22,20 +23,20 @@
#include <linux/mfd/axp20x.h>
#define AXP20X_ADC_EN1_MASK GENMASK(7, 0)
-
#define AXP20X_ADC_EN2_MASK (GENMASK(3, 2) | BIT(7))
+
#define AXP22X_ADC_EN1_MASK (GENMASK(7, 5) | BIT(0))
#define AXP20X_GPIO10_IN_RANGE_GPIO0 BIT(0)
#define AXP20X_GPIO10_IN_RANGE_GPIO1 BIT(1)
-#define AXP20X_GPIO10_IN_RANGE_GPIO0_VAL(x) ((x) & BIT(0))
-#define AXP20X_GPIO10_IN_RANGE_GPIO1_VAL(x) (((x) & BIT(0)) << 1)
#define AXP20X_ADC_RATE_MASK GENMASK(7, 6)
-#define AXP813_V_I_ADC_RATE_MASK GENMASK(5, 4)
-#define AXP813_ADC_RATE_MASK (AXP20X_ADC_RATE_MASK | AXP813_V_I_ADC_RATE_MASK)
#define AXP20X_ADC_RATE_HZ(x) ((ilog2((x) / 25) << 6) & AXP20X_ADC_RATE_MASK)
+
#define AXP22X_ADC_RATE_HZ(x) ((ilog2((x) / 100) << 6) & AXP20X_ADC_RATE_MASK)
+
+#define AXP813_V_I_ADC_RATE_MASK GENMASK(5, 4)
+#define AXP813_ADC_RATE_MASK (AXP20X_ADC_RATE_MASK | AXP813_V_I_ADC_RATE_MASK)
#define AXP813_TS_GPIO0_ADC_RATE_HZ(x) AXP20X_ADC_RATE_HZ(x)
#define AXP813_V_I_ADC_RATE_HZ(x) ((ilog2((x) / 100) << 4) & AXP813_V_I_ADC_RATE_MASK)
#define AXP813_ADC_RATE_HZ(x) (AXP20X_ADC_RATE_HZ(x) | AXP813_V_I_ADC_RATE_HZ(x))
@@ -234,7 +235,7 @@ static int axp20x_adc_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val)
{
struct axp20x_adc_iio *info = iio_priv(indio_dev);
- int size = 12;
+ int ret, size;
/*
* N.B.: Unlike the Chinese datasheets tell, the charging current is
@@ -246,10 +247,11 @@ static int axp20x_adc_raw(struct iio_dev *indio_dev,
else
size = 12;
- *val = axp20x_read_variable_width(info->regmap, chan->address, size);
- if (*val < 0)
- return *val;
+ ret = axp20x_read_variable_width(info->regmap, chan->address, size);
+ if (ret < 0)
+ return ret;
+ *val = ret;
return IIO_VAL_INT;
}
@@ -257,11 +259,13 @@ static int axp22x_adc_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val)
{
struct axp20x_adc_iio *info = iio_priv(indio_dev);
+ int ret;
- *val = axp20x_read_variable_width(info->regmap, chan->address, 12);
- if (*val < 0)
- return *val;
+ ret = axp20x_read_variable_width(info->regmap, chan->address, 12);
+ if (ret < 0)
+ return ret;
+ *val = ret;
return IIO_VAL_INT;
}
@@ -269,11 +273,13 @@ static int axp813_adc_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val)
{
struct axp20x_adc_iio *info = iio_priv(indio_dev);
+ int ret;
- *val = axp20x_read_variable_width(info->regmap, chan->address, 12);
- if (*val < 0)
- return *val;
+ ret = axp20x_read_variable_width(info->regmap, chan->address, 12);
+ if (ret < 0)
+ return ret;
+ *val = ret;
return IIO_VAL_INT;
}
@@ -443,27 +449,27 @@ static int axp20x_adc_offset_voltage(struct iio_dev *indio_dev, int channel,
int *val)
{
struct axp20x_adc_iio *info = iio_priv(indio_dev);
+ unsigned int regval;
int ret;
- ret = regmap_read(info->regmap, AXP20X_GPIO10_IN_RANGE, val);
+ ret = regmap_read(info->regmap, AXP20X_GPIO10_IN_RANGE, ®val);
if (ret < 0)
return ret;
switch (channel) {
case AXP20X_GPIO0_V:
- *val &= AXP20X_GPIO10_IN_RANGE_GPIO0;
+ regval = FIELD_GET(AXP20X_GPIO10_IN_RANGE_GPIO0, regval);
break;
case AXP20X_GPIO1_V:
- *val &= AXP20X_GPIO10_IN_RANGE_GPIO1;
+ regval = FIELD_GET(AXP20X_GPIO10_IN_RANGE_GPIO1, regval);
break;
default:
return -EINVAL;
}
- *val = *val ? 700000 : 0;
-
+ *val = regval ? 700000 : 0;
return IIO_VAL_INT;
}
@@ -548,7 +554,7 @@ static int axp20x_write_raw(struct iio_dev *indio_dev,
long mask)
{
struct axp20x_adc_iio *info = iio_priv(indio_dev);
- unsigned int reg, regval;
+ unsigned int regmask, regval;
/*
* The AXP20X PMIC allows the user to choose between 0V and 0.7V offsets
@@ -560,25 +566,22 @@ static int axp20x_write_raw(struct iio_dev *indio_dev,
if (val != 0 && val != 700000)
return -EINVAL;
- val = val ? 1 : 0;
-
switch (chan->channel) {
case AXP20X_GPIO0_V:
- reg = AXP20X_GPIO10_IN_RANGE_GPIO0;
- regval = AXP20X_GPIO10_IN_RANGE_GPIO0_VAL(val);
+ regmask = AXP20X_GPIO10_IN_RANGE_GPIO0;
+ regval = FIELD_PREP(AXP20X_GPIO10_IN_RANGE_GPIO0, !!val);
break;
case AXP20X_GPIO1_V:
- reg = AXP20X_GPIO10_IN_RANGE_GPIO1;
- regval = AXP20X_GPIO10_IN_RANGE_GPIO1_VAL(val);
+ regmask = AXP20X_GPIO10_IN_RANGE_GPIO1;
+ regval = FIELD_PREP(AXP20X_GPIO10_IN_RANGE_GPIO1, !!val);
break;
default:
return -EINVAL;
}
- return regmap_update_bits(info->regmap, AXP20X_GPIO10_IN_RANGE, reg,
- regval);
+ return regmap_update_bits(info->regmap, AXP20X_GPIO10_IN_RANGE, regmask, regval);
}
static const struct iio_info axp20x_adc_iio_info = {
--
2.35.1
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH v5 08/13] iio: adc: axp20x_adc: Replace adc_en2 flag with adc_en2_mask field
2022-07-06 10:18 [PATCH v5 00/13] Add support for AXP192 PMIC Aidan MacDonald
` (6 preceding siblings ...)
2022-07-06 10:18 ` [PATCH v5 07/13] iio: adc: axp20x_adc: Minor code cleanups Aidan MacDonald
@ 2022-07-06 10:18 ` Aidan MacDonald
2022-07-06 10:18 ` [PATCH v5 09/13] iio: adc: axp20x_adc: Add support for AXP192 Aidan MacDonald
` (4 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Aidan MacDonald @ 2022-07-06 10:18 UTC (permalink / raw)
To: jic23, robh+dt, krzysztof.kozlowski+dt, wens, lee.jones, sre,
lgirdwood, broonie
Cc: lars, andy.shevchenko, linus.walleij, brgl, michael, samuel,
linux-iio, linux-kernel, devicetree, linux-pm, Jonathan Cameron
The adc_en2 flag is essentially specific to axp20x-compatible devices
because it hardcodes register values. Replace it with a mask field
so the register value can be specified in device match data.
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Signed-off-by: Aidan MacDonald <aidanmacdonald.0x0@gmail.com>
---
drivers/iio/adc/axp20x_adc.c | 16 +++++++---------
1 file changed, 7 insertions(+), 9 deletions(-)
diff --git a/drivers/iio/adc/axp20x_adc.c b/drivers/iio/adc/axp20x_adc.c
index ab25e6e1ff65..75bda94dbce1 100644
--- a/drivers/iio/adc/axp20x_adc.c
+++ b/drivers/iio/adc/axp20x_adc.c
@@ -623,9 +623,9 @@ struct axp_data {
int num_channels;
struct iio_chan_spec const *channels;
unsigned long adc_en1_mask;
+ unsigned long adc_en2_mask;
int (*adc_rate)(struct axp20x_adc_iio *info,
int rate);
- bool adc_en2;
struct iio_map *maps;
};
@@ -634,8 +634,8 @@ static const struct axp_data axp20x_data = {
.num_channels = ARRAY_SIZE(axp20x_adc_channels),
.channels = axp20x_adc_channels,
.adc_en1_mask = AXP20X_ADC_EN1_MASK,
+ .adc_en2_mask = AXP20X_ADC_EN2_MASK,
.adc_rate = axp20x_adc_rate,
- .adc_en2 = true,
.maps = axp20x_maps,
};
@@ -645,7 +645,6 @@ static const struct axp_data axp22x_data = {
.channels = axp22x_adc_channels,
.adc_en1_mask = AXP22X_ADC_EN1_MASK,
.adc_rate = axp22x_adc_rate,
- .adc_en2 = false,
.maps = axp22x_maps,
};
@@ -655,7 +654,6 @@ static const struct axp_data axp813_data = {
.channels = axp813_adc_channels,
.adc_en1_mask = AXP22X_ADC_EN1_MASK,
.adc_rate = axp813_adc_rate,
- .adc_en2 = false,
.maps = axp22x_maps,
};
@@ -713,10 +711,10 @@ static int axp20x_probe(struct platform_device *pdev)
/* Enable the ADCs on IP */
regmap_write(info->regmap, AXP20X_ADC_EN1, info->data->adc_en1_mask);
- if (info->data->adc_en2)
- /* Enable GPIO0/1 and internal temperature ADCs */
+ if (info->data->adc_en2_mask)
regmap_update_bits(info->regmap, AXP20X_ADC_EN2,
- AXP20X_ADC_EN2_MASK, AXP20X_ADC_EN2_MASK);
+ info->data->adc_en2_mask,
+ info->data->adc_en2_mask);
/* Configure ADCs rate */
info->data->adc_rate(info, 100);
@@ -741,7 +739,7 @@ static int axp20x_probe(struct platform_device *pdev)
fail_map:
regmap_write(info->regmap, AXP20X_ADC_EN1, 0);
- if (info->data->adc_en2)
+ if (info->data->adc_en2_mask)
regmap_write(info->regmap, AXP20X_ADC_EN2, 0);
return ret;
@@ -757,7 +755,7 @@ static int axp20x_remove(struct platform_device *pdev)
regmap_write(info->regmap, AXP20X_ADC_EN1, 0);
- if (info->data->adc_en2)
+ if (info->data->adc_en2_mask)
regmap_write(info->regmap, AXP20X_ADC_EN2, 0);
return 0;
--
2.35.1
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH v5 09/13] iio: adc: axp20x_adc: Add support for AXP192
2022-07-06 10:18 [PATCH v5 00/13] Add support for AXP192 PMIC Aidan MacDonald
` (7 preceding siblings ...)
2022-07-06 10:18 ` [PATCH v5 08/13] iio: adc: axp20x_adc: Replace adc_en2 flag with adc_en2_mask field Aidan MacDonald
@ 2022-07-06 10:18 ` Aidan MacDonald
2022-07-06 10:18 ` [PATCH v5 10/13] power: supply: axp20x_usb_power: " Aidan MacDonald
` (3 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Aidan MacDonald @ 2022-07-06 10:18 UTC (permalink / raw)
To: jic23, robh+dt, krzysztof.kozlowski+dt, wens, lee.jones, sre,
lgirdwood, broonie
Cc: lars, andy.shevchenko, linus.walleij, brgl, michael, samuel,
linux-iio, linux-kernel, devicetree, linux-pm, Jonathan Cameron
The AXP192 is identical to the AXP20x, except for the addition of
two more GPIO ADC channels.
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Signed-off-by: Aidan MacDonald <aidanmacdonald.0x0@gmail.com>
---
drivers/iio/adc/axp20x_adc.c | 279 +++++++++++++++++++++++++++++++++++
1 file changed, 279 insertions(+)
diff --git a/drivers/iio/adc/axp20x_adc.c b/drivers/iio/adc/axp20x_adc.c
index 75bda94dbce1..8d748b814f20 100644
--- a/drivers/iio/adc/axp20x_adc.c
+++ b/drivers/iio/adc/axp20x_adc.c
@@ -22,11 +22,19 @@
#include <linux/iio/machine.h>
#include <linux/mfd/axp20x.h>
+#define AXP192_ADC_EN1_MASK GENMASK(7, 0)
+#define AXP192_ADC_EN2_MASK (GENMASK(3, 0) | BIT(7))
+
#define AXP20X_ADC_EN1_MASK GENMASK(7, 0)
#define AXP20X_ADC_EN2_MASK (GENMASK(3, 2) | BIT(7))
#define AXP22X_ADC_EN1_MASK (GENMASK(7, 5) | BIT(0))
+#define AXP192_GPIO30_IN_RANGE_GPIO0 BIT(0)
+#define AXP192_GPIO30_IN_RANGE_GPIO1 BIT(1)
+#define AXP192_GPIO30_IN_RANGE_GPIO2 BIT(2)
+#define AXP192_GPIO30_IN_RANGE_GPIO3 BIT(3)
+
#define AXP20X_GPIO10_IN_RANGE_GPIO0 BIT(0)
#define AXP20X_GPIO10_IN_RANGE_GPIO1 BIT(1)
@@ -71,6 +79,25 @@ struct axp20x_adc_iio {
const struct axp_data *data;
};
+enum axp192_adc_channel_v {
+ AXP192_ACIN_V = 0,
+ AXP192_VBUS_V,
+ AXP192_TS_IN,
+ AXP192_GPIO0_V,
+ AXP192_GPIO1_V,
+ AXP192_GPIO2_V,
+ AXP192_GPIO3_V,
+ AXP192_IPSOUT_V,
+ AXP192_BATT_V,
+};
+
+enum axp192_adc_channel_i {
+ AXP192_ACIN_I = 0,
+ AXP192_VBUS_I,
+ AXP192_BATT_CHRG_I,
+ AXP192_BATT_DISCHRG_I,
+};
+
enum axp20x_adc_channel_v {
AXP20X_ACIN_V = 0,
AXP20X_VBUS_V,
@@ -158,6 +185,43 @@ static struct iio_map axp22x_maps[] = {
* The only exception is for the battery. batt_v will be in_voltage6_raw and
* charge current in_current6_raw and discharge current will be in_current7_raw.
*/
+static const struct iio_chan_spec axp192_adc_channels[] = {
+ AXP20X_ADC_CHANNEL(AXP192_ACIN_V, "acin_v", IIO_VOLTAGE,
+ AXP20X_ACIN_V_ADC_H),
+ AXP20X_ADC_CHANNEL(AXP192_ACIN_I, "acin_i", IIO_CURRENT,
+ AXP20X_ACIN_I_ADC_H),
+ AXP20X_ADC_CHANNEL(AXP192_VBUS_V, "vbus_v", IIO_VOLTAGE,
+ AXP20X_VBUS_V_ADC_H),
+ AXP20X_ADC_CHANNEL(AXP192_VBUS_I, "vbus_i", IIO_CURRENT,
+ AXP20X_VBUS_I_ADC_H),
+ {
+ .type = IIO_TEMP,
+ .address = AXP20X_TEMP_ADC_H,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_OFFSET),
+ .datasheet_name = "pmic_temp",
+ },
+ AXP20X_ADC_CHANNEL_OFFSET(AXP192_GPIO0_V, "gpio0_v", IIO_VOLTAGE,
+ AXP20X_GPIO0_V_ADC_H),
+ AXP20X_ADC_CHANNEL_OFFSET(AXP192_GPIO1_V, "gpio1_v", IIO_VOLTAGE,
+ AXP20X_GPIO1_V_ADC_H),
+ AXP20X_ADC_CHANNEL_OFFSET(AXP192_GPIO2_V, "gpio2_v", IIO_VOLTAGE,
+ AXP192_GPIO2_V_ADC_H),
+ AXP20X_ADC_CHANNEL_OFFSET(AXP192_GPIO3_V, "gpio3_v", IIO_VOLTAGE,
+ AXP192_GPIO3_V_ADC_H),
+ AXP20X_ADC_CHANNEL(AXP192_IPSOUT_V, "ipsout_v", IIO_VOLTAGE,
+ AXP20X_IPSOUT_V_HIGH_H),
+ AXP20X_ADC_CHANNEL(AXP192_BATT_V, "batt_v", IIO_VOLTAGE,
+ AXP20X_BATT_V_H),
+ AXP20X_ADC_CHANNEL(AXP192_BATT_CHRG_I, "batt_chrg_i", IIO_CURRENT,
+ AXP20X_BATT_CHRG_I_H),
+ AXP20X_ADC_CHANNEL(AXP192_BATT_DISCHRG_I, "batt_dischrg_i", IIO_CURRENT,
+ AXP20X_BATT_DISCHRG_I_H),
+ AXP20X_ADC_CHANNEL(AXP192_TS_IN, "ts_v", IIO_VOLTAGE,
+ AXP20X_TS_IN_H),
+};
+
static const struct iio_chan_spec axp20x_adc_channels[] = {
AXP20X_ADC_CHANNEL(AXP20X_ACIN_V, "acin_v", IIO_VOLTAGE,
AXP20X_ACIN_V_ADC_H),
@@ -231,6 +295,27 @@ static const struct iio_chan_spec axp813_adc_channels[] = {
AXP288_TS_ADC_H),
};
+static int axp192_adc_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val)
+{
+ struct axp20x_adc_iio *info = iio_priv(indio_dev);
+ int ret, size;
+
+ if (chan->type == IIO_CURRENT &&
+ (chan->channel == AXP192_BATT_CHRG_I ||
+ chan->channel == AXP192_BATT_DISCHRG_I))
+ size = 13;
+ else
+ size = 12;
+
+ ret = axp20x_read_variable_width(info->regmap, chan->address, size);
+ if (ret < 0)
+ return ret;
+
+ *val = ret;
+ return IIO_VAL_INT;
+}
+
static int axp20x_adc_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val)
{
@@ -283,6 +368,44 @@ static int axp813_adc_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT;
}
+static int axp192_adc_scale_voltage(int channel, int *val, int *val2)
+{
+ switch (channel) {
+ case AXP192_ACIN_V:
+ case AXP192_VBUS_V:
+ *val = 1;
+ *val2 = 700000;
+ return IIO_VAL_INT_PLUS_MICRO;
+
+ case AXP192_GPIO0_V:
+ case AXP192_GPIO1_V:
+ case AXP192_GPIO2_V:
+ case AXP192_GPIO3_V:
+ *val = 0;
+ *val2 = 500000;
+ return IIO_VAL_INT_PLUS_MICRO;
+
+ case AXP192_BATT_V:
+ *val = 1;
+ *val2 = 100000;
+ return IIO_VAL_INT_PLUS_MICRO;
+
+ case AXP192_IPSOUT_V:
+ *val = 1;
+ *val2 = 400000;
+ return IIO_VAL_INT_PLUS_MICRO;
+
+ case AXP192_TS_IN:
+ /* 0.8 mV per LSB */
+ *val = 0;
+ *val2 = 800000;
+ return IIO_VAL_INT_PLUS_MICRO;
+
+ default:
+ return -EINVAL;
+ }
+}
+
static int axp20x_adc_scale_voltage(int channel, int *val, int *val2)
{
switch (channel) {
@@ -386,6 +509,29 @@ static int axp20x_adc_scale_current(int channel, int *val, int *val2)
}
}
+static int axp192_adc_scale(struct iio_chan_spec const *chan, int *val,
+ int *val2)
+{
+ switch (chan->type) {
+ case IIO_VOLTAGE:
+ return axp192_adc_scale_voltage(chan->channel, val, val2);
+
+ case IIO_CURRENT:
+ /*
+ * AXP192 current channels are identical to the AXP20x,
+ * therefore we can re-use the scaling function.
+ */
+ return axp20x_adc_scale_current(chan->channel, val, val2);
+
+ case IIO_TEMP:
+ *val = 100;
+ return IIO_VAL_INT;
+
+ default:
+ return -EINVAL;
+ }
+}
+
static int axp20x_adc_scale(struct iio_chan_spec const *chan, int *val,
int *val2)
{
@@ -445,6 +591,42 @@ static int axp813_adc_scale(struct iio_chan_spec const *chan, int *val,
}
}
+static int axp192_adc_offset_voltage(struct iio_dev *indio_dev, int channel,
+ int *val)
+{
+ struct axp20x_adc_iio *info = iio_priv(indio_dev);
+ unsigned int regval;
+ int ret;
+
+ ret = regmap_read(info->regmap, AXP192_GPIO30_IN_RANGE, ®val);
+ if (ret < 0)
+ return ret;
+
+ switch (channel) {
+ case AXP192_GPIO0_V:
+ regval = FIELD_GET(AXP192_GPIO30_IN_RANGE_GPIO0, regval);
+ break;
+
+ case AXP192_GPIO1_V:
+ regval = FIELD_GET(AXP192_GPIO30_IN_RANGE_GPIO1, regval);
+ break;
+
+ case AXP192_GPIO2_V:
+ regval = FIELD_GET(AXP192_GPIO30_IN_RANGE_GPIO2, regval);
+ break;
+
+ case AXP192_GPIO3_V:
+ regval = FIELD_GET(AXP192_GPIO30_IN_RANGE_GPIO3, regval);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ *val = regval ? 700000 : 0;
+ return IIO_VAL_INT;
+}
+
static int axp20x_adc_offset_voltage(struct iio_dev *indio_dev, int channel,
int *val)
{
@@ -473,6 +655,22 @@ static int axp20x_adc_offset_voltage(struct iio_dev *indio_dev, int channel,
return IIO_VAL_INT;
}
+static int axp192_adc_offset(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val)
+{
+ switch (chan->type) {
+ case IIO_VOLTAGE:
+ return axp192_adc_offset_voltage(indio_dev, chan->channel, val);
+
+ case IIO_TEMP:
+ *val = -1447;
+ return IIO_VAL_INT;
+
+ default:
+ return -EINVAL;
+ }
+}
+
static int axp20x_adc_offset(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val)
{
@@ -489,6 +687,25 @@ static int axp20x_adc_offset(struct iio_dev *indio_dev,
}
}
+static int axp192_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ switch (mask) {
+ case IIO_CHAN_INFO_OFFSET:
+ return axp192_adc_offset(indio_dev, chan, val);
+
+ case IIO_CHAN_INFO_SCALE:
+ return axp192_adc_scale(chan, val, val2);
+
+ case IIO_CHAN_INFO_RAW:
+ return axp192_adc_raw(indio_dev, chan, val);
+
+ default:
+ return -EINVAL;
+ }
+}
+
static int axp20x_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val,
int *val2, long mask)
@@ -549,6 +766,51 @@ static int axp813_read_raw(struct iio_dev *indio_dev,
}
}
+static int axp192_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val, int val2,
+ long mask)
+{
+ struct axp20x_adc_iio *info = iio_priv(indio_dev);
+ unsigned int regmask, regval;
+
+ /*
+ * The AXP192 PMIC allows the user to choose between 0V and 0.7V offsets
+ * for (independently) GPIO0-3 when in ADC mode.
+ */
+ if (mask != IIO_CHAN_INFO_OFFSET)
+ return -EINVAL;
+
+ if (val != 0 && val != 700000)
+ return -EINVAL;
+
+ switch (chan->channel) {
+ case AXP192_GPIO0_V:
+ regmask = AXP192_GPIO30_IN_RANGE_GPIO0;
+ regval = FIELD_PREP(AXP192_GPIO30_IN_RANGE_GPIO0, !!val);
+ break;
+
+ case AXP192_GPIO1_V:
+ regmask = AXP192_GPIO30_IN_RANGE_GPIO1;
+ regval = FIELD_PREP(AXP192_GPIO30_IN_RANGE_GPIO1, !!val);
+ break;
+
+ case AXP192_GPIO2_V:
+ regmask = AXP192_GPIO30_IN_RANGE_GPIO2;
+ regval = FIELD_PREP(AXP192_GPIO30_IN_RANGE_GPIO2, !!val);
+ break;
+
+ case AXP192_GPIO3_V:
+ regmask = AXP192_GPIO30_IN_RANGE_GPIO3;
+ regval = FIELD_PREP(AXP192_GPIO30_IN_RANGE_GPIO3, !!val);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return regmap_update_bits(info->regmap, AXP192_GPIO30_IN_RANGE, regmask, regval);
+}
+
static int axp20x_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val, int val2,
long mask)
@@ -584,6 +846,11 @@ static int axp20x_write_raw(struct iio_dev *indio_dev,
return regmap_update_bits(info->regmap, AXP20X_GPIO10_IN_RANGE, regmask, regval);
}
+static const struct iio_info axp192_adc_iio_info = {
+ .read_raw = axp192_read_raw,
+ .write_raw = axp192_write_raw,
+};
+
static const struct iio_info axp20x_adc_iio_info = {
.read_raw = axp20x_read_raw,
.write_raw = axp20x_write_raw,
@@ -629,6 +896,16 @@ struct axp_data {
struct iio_map *maps;
};
+static const struct axp_data axp192_data = {
+ .iio_info = &axp192_adc_iio_info,
+ .num_channels = ARRAY_SIZE(axp192_adc_channels),
+ .channels = axp192_adc_channels,
+ .adc_en1_mask = AXP192_ADC_EN1_MASK,
+ .adc_en2_mask = AXP192_ADC_EN2_MASK,
+ .adc_rate = axp20x_adc_rate,
+ .maps = axp20x_maps,
+};
+
static const struct axp_data axp20x_data = {
.iio_info = &axp20x_adc_iio_info,
.num_channels = ARRAY_SIZE(axp20x_adc_channels),
@@ -658,6 +935,7 @@ static const struct axp_data axp813_data = {
};
static const struct of_device_id axp20x_adc_of_match[] = {
+ { .compatible = "x-powers,axp192-adc", .data = (void *)&axp192_data, },
{ .compatible = "x-powers,axp209-adc", .data = (void *)&axp20x_data, },
{ .compatible = "x-powers,axp221-adc", .data = (void *)&axp22x_data, },
{ .compatible = "x-powers,axp813-adc", .data = (void *)&axp813_data, },
@@ -666,6 +944,7 @@ static const struct of_device_id axp20x_adc_of_match[] = {
MODULE_DEVICE_TABLE(of, axp20x_adc_of_match);
static const struct platform_device_id axp20x_adc_id_match[] = {
+ { .name = "axp192-adc", .driver_data = (kernel_ulong_t)&axp192_data, },
{ .name = "axp20x-adc", .driver_data = (kernel_ulong_t)&axp20x_data, },
{ .name = "axp22x-adc", .driver_data = (kernel_ulong_t)&axp22x_data, },
{ .name = "axp813-adc", .driver_data = (kernel_ulong_t)&axp813_data, },
--
2.35.1
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH v5 10/13] power: supply: axp20x_usb_power: Add support for AXP192
2022-07-06 10:18 [PATCH v5 00/13] Add support for AXP192 PMIC Aidan MacDonald
` (8 preceding siblings ...)
2022-07-06 10:18 ` [PATCH v5 09/13] iio: adc: axp20x_adc: Add support for AXP192 Aidan MacDonald
@ 2022-07-06 10:18 ` Aidan MacDonald
2022-07-06 10:19 ` [PATCH v5 11/13] power: axp20x_battery: Add constant charge current table Aidan MacDonald
` (2 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Aidan MacDonald @ 2022-07-06 10:18 UTC (permalink / raw)
To: jic23, robh+dt, krzysztof.kozlowski+dt, wens, lee.jones, sre,
lgirdwood, broonie
Cc: lars, andy.shevchenko, linus.walleij, brgl, michael, samuel,
linux-iio, linux-kernel, devicetree, linux-pm, Sebastian Reichel
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>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
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
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH v5 11/13] power: axp20x_battery: Add constant charge current table
2022-07-06 10:18 [PATCH v5 00/13] Add support for AXP192 PMIC Aidan MacDonald
` (9 preceding siblings ...)
2022-07-06 10:18 ` [PATCH v5 10/13] power: supply: axp20x_usb_power: " Aidan MacDonald
@ 2022-07-06 10:19 ` Aidan MacDonald
2022-07-16 22:39 ` Sebastian Reichel
2022-07-06 10:19 ` [PATCH v5 12/13] power: axp20x_battery: Support battery status without fuel gauge Aidan MacDonald
2022-07-06 10:19 ` [PATCH v5 13/13] power: axp20x_battery: Add support for AXP192 Aidan MacDonald
12 siblings, 1 reply; 15+ messages in thread
From: Aidan MacDonald @ 2022-07-06 10:19 UTC (permalink / raw)
To: jic23, robh+dt, krzysztof.kozlowski+dt, wens, lee.jones, sre,
lgirdwood, broonie
Cc: lars, andy.shevchenko, linus.walleij, brgl, michael, samuel,
linux-iio, linux-kernel, devicetree, linux-pm
Add a table-based lookup method for constant charge current,
which is necessary when the setting cannot be represented as
a linear range.
This also replaces the hard-coded 300 mA default ccc setting
if the DT-specified value is unsupported; the minimum value
for the device is now set exactly instead of relying on the
value being rounded down to a supported value.
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Signed-off-by: Aidan MacDonald <aidanmacdonald.0x0@gmail.com>
---
drivers/power/supply/axp20x_battery.c | 59 +++++++++++++++++++++------
1 file changed, 47 insertions(+), 12 deletions(-)
diff --git a/drivers/power/supply/axp20x_battery.c b/drivers/power/supply/axp20x_battery.c
index 9106077c0dbb..401779d84d2b 100644
--- a/drivers/power/supply/axp20x_battery.c
+++ b/drivers/power/supply/axp20x_battery.c
@@ -61,6 +61,14 @@ struct axp20x_batt_ps;
struct axp_data {
int ccc_scale;
int ccc_offset;
+ /*
+ * Lookup table for constant charge current, if provided this is used
+ * instead of ccc_scale/ccc_offset.
+ *
+ * The table is indexed by the field AXP20X_CHRG_CTRL1_TGT_CURR so it
+ * must have AXP20X_CHRG_CTRL1_TGT_CURR+1 elements.
+ */
+ const int *ccc_table;
bool has_fg_valid;
int (*get_max_voltage)(struct axp20x_batt_ps *batt, int *val);
int (*set_max_voltage)(struct axp20x_batt_ps *batt, int val);
@@ -176,7 +184,10 @@ static int axp20x_get_constant_charge_current(struct axp20x_batt_ps *axp,
*val &= AXP20X_CHRG_CTRL1_TGT_CURR;
- *val = *val * axp->data->ccc_scale + axp->data->ccc_offset;
+ if (axp->data->ccc_table)
+ *val = axp->data->ccc_table[*val];
+ else
+ *val = *val * axp->data->ccc_scale + axp->data->ccc_offset;
return 0;
}
@@ -389,16 +400,35 @@ static int axp20x_battery_set_max_voltage(struct axp20x_batt_ps *axp20x_batt,
AXP20X_CHRG_CTRL1_TGT_VOLT, val);
}
+static int axp20x_get_constant_charge_current_sel(struct axp20x_batt_ps *axp_batt,
+ int charge_current)
+{
+ int i;
+
+ if (axp_batt->data->ccc_table) {
+ for (i = AXP20X_CHRG_CTRL1_TGT_CURR; i >= 0; i--) {
+ if (axp_batt->data->ccc_table[i] <= charge_current)
+ return i;
+ }
+
+ return -EINVAL;
+ }
+
+ i = (charge_current - axp_batt->data->ccc_offset) / axp_batt->data->ccc_scale;
+ if (i > AXP20X_CHRG_CTRL1_TGT_CURR || i < 0)
+ return -EINVAL;
+
+ return i;
+}
+
static int axp20x_set_constant_charge_current(struct axp20x_batt_ps *axp_batt,
int charge_current)
{
if (charge_current > axp_batt->max_ccc)
return -EINVAL;
- charge_current = (charge_current - axp_batt->data->ccc_offset) /
- axp_batt->data->ccc_scale;
-
- if (charge_current > AXP20X_CHRG_CTRL1_TGT_CURR || charge_current < 0)
+ charge_current = axp20x_get_constant_charge_current_sel(axp_batt, charge_current);
+ if (charge_current < 0)
return -EINVAL;
return regmap_update_bits(axp_batt->regmap, AXP20X_CHRG_CTRL1,
@@ -410,14 +440,14 @@ static int axp20x_set_max_constant_charge_current(struct axp20x_batt_ps *axp,
{
bool lower_max = false;
- charge_current = (charge_current - axp->data->ccc_offset) /
- axp->data->ccc_scale;
-
- if (charge_current > AXP20X_CHRG_CTRL1_TGT_CURR || charge_current < 0)
+ charge_current = axp20x_get_constant_charge_current_sel(axp, charge_current);
+ if (charge_current < 0)
return -EINVAL;
- charge_current = charge_current * axp->data->ccc_scale +
- axp->data->ccc_offset;
+ if (axp->data->ccc_table)
+ charge_current = axp->data->ccc_table[charge_current];
+ else
+ charge_current = charge_current * axp->data->ccc_scale + axp->data->ccc_offset;
if (charge_current > axp->max_ccc)
dev_warn(axp->dev,
@@ -629,7 +659,12 @@ static int axp20x_power_probe(struct platform_device *pdev)
ccc)) {
dev_err(&pdev->dev,
"couldn't set constant charge current from DT: fallback to minimum value\n");
- ccc = 300000;
+
+ if (axp20x_batt->data->ccc_table)
+ ccc = axp20x_batt->data->ccc_table[0];
+ else
+ ccc = axp20x_batt->data->ccc_offset;
+
axp20x_batt->max_ccc = ccc;
axp20x_set_constant_charge_current(axp20x_batt, ccc);
}
--
2.35.1
^ permalink raw reply related [flat|nested] 15+ messages in thread* Re: [PATCH v5 11/13] power: axp20x_battery: Add constant charge current table
2022-07-06 10:19 ` [PATCH v5 11/13] power: axp20x_battery: Add constant charge current table Aidan MacDonald
@ 2022-07-16 22:39 ` Sebastian Reichel
0 siblings, 0 replies; 15+ messages in thread
From: Sebastian Reichel @ 2022-07-16 22:39 UTC (permalink / raw)
To: Aidan MacDonald
Cc: jic23, robh+dt, krzysztof.kozlowski+dt, wens, lee.jones,
lgirdwood, broonie, lars, andy.shevchenko, linus.walleij, brgl,
michael, samuel, linux-iio, linux-kernel, devicetree, linux-pm
[-- Attachment #1: Type: text/plain, Size: 4627 bytes --]
Hi,
On Wed, Jul 06, 2022 at 11:19:00AM +0100, Aidan MacDonald wrote:
> Add a table-based lookup method for constant charge current,
> which is necessary when the setting cannot be represented as
> a linear range.
>
> This also replaces the hard-coded 300 mA default ccc setting
> if the DT-specified value is unsupported; the minimum value
> for the device is now set exactly instead of relying on the
> value being rounded down to a supported value.
>
> Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
> Signed-off-by: Aidan MacDonald <aidanmacdonald.0x0@gmail.com>
> ---
Acked-by: Sebastian Reichel <sebastian.reichel@collabora.com>
-- Sebastian
> drivers/power/supply/axp20x_battery.c | 59 +++++++++++++++++++++------
> 1 file changed, 47 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/power/supply/axp20x_battery.c b/drivers/power/supply/axp20x_battery.c
> index 9106077c0dbb..401779d84d2b 100644
> --- a/drivers/power/supply/axp20x_battery.c
> +++ b/drivers/power/supply/axp20x_battery.c
> @@ -61,6 +61,14 @@ struct axp20x_batt_ps;
> struct axp_data {
> int ccc_scale;
> int ccc_offset;
> + /*
> + * Lookup table for constant charge current, if provided this is used
> + * instead of ccc_scale/ccc_offset.
> + *
> + * The table is indexed by the field AXP20X_CHRG_CTRL1_TGT_CURR so it
> + * must have AXP20X_CHRG_CTRL1_TGT_CURR+1 elements.
> + */
> + const int *ccc_table;
> bool has_fg_valid;
> int (*get_max_voltage)(struct axp20x_batt_ps *batt, int *val);
> int (*set_max_voltage)(struct axp20x_batt_ps *batt, int val);
> @@ -176,7 +184,10 @@ static int axp20x_get_constant_charge_current(struct axp20x_batt_ps *axp,
>
> *val &= AXP20X_CHRG_CTRL1_TGT_CURR;
>
> - *val = *val * axp->data->ccc_scale + axp->data->ccc_offset;
> + if (axp->data->ccc_table)
> + *val = axp->data->ccc_table[*val];
> + else
> + *val = *val * axp->data->ccc_scale + axp->data->ccc_offset;
>
> return 0;
> }
> @@ -389,16 +400,35 @@ static int axp20x_battery_set_max_voltage(struct axp20x_batt_ps *axp20x_batt,
> AXP20X_CHRG_CTRL1_TGT_VOLT, val);
> }
>
> +static int axp20x_get_constant_charge_current_sel(struct axp20x_batt_ps *axp_batt,
> + int charge_current)
> +{
> + int i;
> +
> + if (axp_batt->data->ccc_table) {
> + for (i = AXP20X_CHRG_CTRL1_TGT_CURR; i >= 0; i--) {
> + if (axp_batt->data->ccc_table[i] <= charge_current)
> + return i;
> + }
> +
> + return -EINVAL;
> + }
> +
> + i = (charge_current - axp_batt->data->ccc_offset) / axp_batt->data->ccc_scale;
> + if (i > AXP20X_CHRG_CTRL1_TGT_CURR || i < 0)
> + return -EINVAL;
> +
> + return i;
> +}
> +
> static int axp20x_set_constant_charge_current(struct axp20x_batt_ps *axp_batt,
> int charge_current)
> {
> if (charge_current > axp_batt->max_ccc)
> return -EINVAL;
>
> - charge_current = (charge_current - axp_batt->data->ccc_offset) /
> - axp_batt->data->ccc_scale;
> -
> - if (charge_current > AXP20X_CHRG_CTRL1_TGT_CURR || charge_current < 0)
> + charge_current = axp20x_get_constant_charge_current_sel(axp_batt, charge_current);
> + if (charge_current < 0)
> return -EINVAL;
>
> return regmap_update_bits(axp_batt->regmap, AXP20X_CHRG_CTRL1,
> @@ -410,14 +440,14 @@ static int axp20x_set_max_constant_charge_current(struct axp20x_batt_ps *axp,
> {
> bool lower_max = false;
>
> - charge_current = (charge_current - axp->data->ccc_offset) /
> - axp->data->ccc_scale;
> -
> - if (charge_current > AXP20X_CHRG_CTRL1_TGT_CURR || charge_current < 0)
> + charge_current = axp20x_get_constant_charge_current_sel(axp, charge_current);
> + if (charge_current < 0)
> return -EINVAL;
>
> - charge_current = charge_current * axp->data->ccc_scale +
> - axp->data->ccc_offset;
> + if (axp->data->ccc_table)
> + charge_current = axp->data->ccc_table[charge_current];
> + else
> + charge_current = charge_current * axp->data->ccc_scale + axp->data->ccc_offset;
>
> if (charge_current > axp->max_ccc)
> dev_warn(axp->dev,
> @@ -629,7 +659,12 @@ static int axp20x_power_probe(struct platform_device *pdev)
> ccc)) {
> dev_err(&pdev->dev,
> "couldn't set constant charge current from DT: fallback to minimum value\n");
> - ccc = 300000;
> +
> + if (axp20x_batt->data->ccc_table)
> + ccc = axp20x_batt->data->ccc_table[0];
> + else
> + ccc = axp20x_batt->data->ccc_offset;
> +
> axp20x_batt->max_ccc = ccc;
> axp20x_set_constant_charge_current(axp20x_batt, ccc);
> }
> --
> 2.35.1
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v5 12/13] power: axp20x_battery: Support battery status without fuel gauge
2022-07-06 10:18 [PATCH v5 00/13] Add support for AXP192 PMIC Aidan MacDonald
` (10 preceding siblings ...)
2022-07-06 10:19 ` [PATCH v5 11/13] power: axp20x_battery: Add constant charge current table Aidan MacDonald
@ 2022-07-06 10:19 ` Aidan MacDonald
2022-07-06 10:19 ` [PATCH v5 13/13] power: axp20x_battery: Add support for AXP192 Aidan MacDonald
12 siblings, 0 replies; 15+ messages in thread
From: Aidan MacDonald @ 2022-07-06 10:19 UTC (permalink / raw)
To: jic23, robh+dt, krzysztof.kozlowski+dt, wens, lee.jones, sre,
lgirdwood, broonie
Cc: lars, andy.shevchenko, linus.walleij, brgl, michael, samuel,
linux-iio, linux-kernel, devicetree, linux-pm, Sebastian Reichel
Add a "has_fg" flag to indicate that the chip has a fuel gauge.
Report battery full status on chips with no fuel gauge using the
battery voltage.
Acked-by: Sebastian Reichel <sebastian.reichel@collabora.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Signed-off-by: Aidan MacDonald <aidanmacdonald.0x0@gmail.com>
---
drivers/power/supply/axp20x_battery.c | 34 ++++++++++++++++++++++++++-
1 file changed, 33 insertions(+), 1 deletion(-)
diff --git a/drivers/power/supply/axp20x_battery.c b/drivers/power/supply/axp20x_battery.c
index 401779d84d2b..574c1d001556 100644
--- a/drivers/power/supply/axp20x_battery.c
+++ b/drivers/power/supply/axp20x_battery.c
@@ -69,6 +69,7 @@ struct axp_data {
* must have AXP20X_CHRG_CTRL1_TGT_CURR+1 elements.
*/
const int *ccc_table;
+ bool has_fg;
bool has_fg_valid;
int (*get_max_voltage)(struct axp20x_batt_ps *batt, int *val);
int (*set_max_voltage)(struct axp20x_batt_ps *batt, int val);
@@ -197,7 +198,7 @@ static int axp20x_battery_get_prop(struct power_supply *psy,
union power_supply_propval *val)
{
struct axp20x_batt_ps *axp20x_batt = power_supply_get_drvdata(psy);
- int ret = 0, reg, val1;
+ int ret = 0, reg, val1, val2;
switch (psp) {
case POWER_SUPPLY_PROP_PRESENT:
@@ -231,6 +232,34 @@ static int axp20x_battery_get_prop(struct power_supply *psy,
return 0;
}
+ /*
+ * If the chip does not have a fuel gauge, we check battery full status
+ * using voltage instead.
+ */
+ if (!axp20x_batt->data->has_fg) {
+ ret = axp20x_batt->data->get_max_voltage(axp20x_batt, &val1);
+ if (ret)
+ return ret;
+
+ ret = iio_read_channel_processed(axp20x_batt->batt_v, &val2);
+ if (ret)
+ return ret;
+
+ /* IIO subsystem reports voltage in mV but we need uV */
+ val2 *= 1000;
+
+ /*
+ * According to the AXP192 datasheet, charging will restart if
+ * the battery voltage drops below V_rch = V_tgt - 0.1 V, so we
+ * report the battery is full if its voltage is at least V_rch.
+ */
+ if (val2 >= val1 - 100000)
+ val->intval = POWER_SUPPLY_STATUS_FULL;
+ else
+ val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ break;
+ }
+
ret = regmap_read(axp20x_batt->regmap, AXP20X_FG_RES, &val1);
if (ret)
return ret;
@@ -552,6 +581,7 @@ static const struct power_supply_desc axp20x_batt_ps_desc = {
static const struct axp_data axp209_data = {
.ccc_scale = 100000,
.ccc_offset = 300000,
+ .has_fg = true,
.get_max_voltage = axp20x_battery_get_max_voltage,
.set_max_voltage = axp20x_battery_set_max_voltage,
};
@@ -559,6 +589,7 @@ static const struct axp_data axp209_data = {
static const struct axp_data axp221_data = {
.ccc_scale = 150000,
.ccc_offset = 300000,
+ .has_fg = true,
.has_fg_valid = true,
.get_max_voltage = axp22x_battery_get_max_voltage,
.set_max_voltage = axp22x_battery_set_max_voltage,
@@ -567,6 +598,7 @@ static const struct axp_data axp221_data = {
static const struct axp_data axp813_data = {
.ccc_scale = 200000,
.ccc_offset = 200000,
+ .has_fg = true,
.has_fg_valid = true,
.get_max_voltage = axp813_battery_get_max_voltage,
.set_max_voltage = axp20x_battery_set_max_voltage,
--
2.35.1
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH v5 13/13] power: axp20x_battery: Add support for AXP192
2022-07-06 10:18 [PATCH v5 00/13] Add support for AXP192 PMIC Aidan MacDonald
` (11 preceding siblings ...)
2022-07-06 10:19 ` [PATCH v5 12/13] power: axp20x_battery: Support battery status without fuel gauge Aidan MacDonald
@ 2022-07-06 10:19 ` Aidan MacDonald
12 siblings, 0 replies; 15+ messages in thread
From: Aidan MacDonald @ 2022-07-06 10:19 UTC (permalink / raw)
To: jic23, robh+dt, krzysztof.kozlowski+dt, wens, lee.jones, sre,
lgirdwood, broonie
Cc: lars, andy.shevchenko, linus.walleij, brgl, michael, samuel,
linux-iio, linux-kernel, devicetree, linux-pm, Sebastian Reichel
The AXP192 has a battery charger similar to other X-Powers PMICs,
but unlike the other supported devices, it does not have a fuel
gauge and can't report battery capacity directly.
Acked-by: Sebastian Reichel <sebastian.reichel@collabora.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Signed-off-by: Aidan MacDonald <aidanmacdonald.0x0@gmail.com>
---
drivers/power/supply/axp20x_battery.c | 49 +++++++++++++++++++++++++--
1 file changed, 46 insertions(+), 3 deletions(-)
diff --git a/drivers/power/supply/axp20x_battery.c b/drivers/power/supply/axp20x_battery.c
index 574c1d001556..1e84d26ce8e3 100644
--- a/drivers/power/supply/axp20x_battery.c
+++ b/drivers/power/supply/axp20x_battery.c
@@ -544,6 +544,19 @@ static int axp20x_battery_set_prop(struct power_supply *psy,
}
}
+static enum power_supply_property axp192_battery_props[] = {
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
+ POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+};
+
static enum power_supply_property axp20x_battery_props[] = {
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_ONLINE,
@@ -568,6 +581,16 @@ static int axp20x_battery_prop_writeable(struct power_supply *psy,
psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX;
}
+static const struct power_supply_desc axp192_batt_ps_desc = {
+ .name = "axp192-battery",
+ .type = POWER_SUPPLY_TYPE_BATTERY,
+ .properties = axp192_battery_props,
+ .num_properties = ARRAY_SIZE(axp192_battery_props),
+ .property_is_writeable = axp20x_battery_prop_writeable,
+ .get_property = axp20x_battery_get_prop,
+ .set_property = axp20x_battery_set_prop,
+};
+
static const struct power_supply_desc axp20x_batt_ps_desc = {
.name = "axp20x-battery",
.type = POWER_SUPPLY_TYPE_BATTERY,
@@ -578,6 +601,19 @@ static const struct power_supply_desc axp20x_batt_ps_desc = {
.set_property = axp20x_battery_set_prop,
};
+static const int axp192_ccc_table[AXP20X_CHRG_CTRL1_TGT_CURR+1] = {
+ 100000, 190000, 280000, 360000,
+ 450000, 550000, 630000, 700000,
+ 780000, 880000, 960000, 1000000,
+ 1080000, 1160000, 1240000, 1320000,
+};
+
+static const struct axp_data axp192_data = {
+ .ccc_table = axp192_ccc_table,
+ .get_max_voltage = axp20x_battery_get_max_voltage,
+ .set_max_voltage = axp20x_battery_set_max_voltage,
+};
+
static const struct axp_data axp209_data = {
.ccc_scale = 100000,
.ccc_offset = 300000,
@@ -606,6 +642,9 @@ static const struct axp_data axp813_data = {
static const struct of_device_id axp20x_battery_ps_id[] = {
{
+ .compatible = "x-powers,axp192-battery-power-supply",
+ .data = (void *)&axp192_data,
+ }, {
.compatible = "x-powers,axp209-battery-power-supply",
.data = (void *)&axp209_data,
}, {
@@ -623,6 +662,7 @@ static int axp20x_power_probe(struct platform_device *pdev)
struct axp20x_batt_ps *axp20x_batt;
struct power_supply_config psy_cfg = {};
struct power_supply_battery_info *info;
+ const struct power_supply_desc *ps_desc;
struct device *dev = &pdev->dev;
if (!of_device_is_available(pdev->dev.of_node))
@@ -666,9 +706,12 @@ static int axp20x_power_probe(struct platform_device *pdev)
axp20x_batt->data = (struct axp_data *)of_device_get_match_data(dev);
- axp20x_batt->batt = devm_power_supply_register(&pdev->dev,
- &axp20x_batt_ps_desc,
- &psy_cfg);
+ if (!axp20x_batt->data->has_fg)
+ ps_desc = &axp192_batt_ps_desc;
+ else
+ ps_desc = &axp20x_batt_ps_desc;
+
+ axp20x_batt->batt = devm_power_supply_register(&pdev->dev, ps_desc, &psy_cfg);
if (IS_ERR(axp20x_batt->batt)) {
dev_err(&pdev->dev, "failed to register power supply: %ld\n",
PTR_ERR(axp20x_batt->batt));
--
2.35.1
^ permalink raw reply related [flat|nested] 15+ messages in thread