2022-07-06 10:56:35

by Aidan MacDonald

[permalink] [raw]
Subject: [PATCH v5 00/13] Add support for AXP192 PMIC

This series adds support for the AXP192 PMIC to the AXP20x MFD driver
framework, including support for regulators, ADCs, and AC/USB/battery
power supplies.

This depends on the "regmap-irq cleanups and refactoring" series[1]
for the ->get_irq_reg() operation, needed by the AXP192's IRQ chip.

Changes in v5:

* Drop everything related to GPIO / pin control. It seems that driver
is going to require further discussion while the rest of the series
probably won't need much at this point, and I'd rather not hold the
whole series up over one driver.

Older changelogs can be found in v4[2].

[1]: https://lore.kernel.org/lkml/[email protected]/
[2]: https://lore.kernel.org/lkml/[email protected]/

Aidan MacDonald (13):
dt-bindings: mfd: add bindings for AXP192 MFD device
dt-bindings: iio: adc: axp209: Add AXP192 compatible
dt-bindings: power: supply: axp20x: Add AXP192 compatible
dt-bindings: power: axp20x-battery: Add AXP192 compatible
mfd: axp20x: Add support for AXP192
regulator: axp20x: Add support for AXP192
iio: adc: axp20x_adc: Minor code cleanups
iio: adc: axp20x_adc: Replace adc_en2 flag with adc_en2_mask field
iio: adc: axp20x_adc: Add support for AXP192
power: supply: axp20x_usb_power: Add support for AXP192
power: axp20x_battery: Add constant charge current table
power: axp20x_battery: Support battery status without fuel gauge
power: axp20x_battery: Add support for AXP192

.../bindings/iio/adc/x-powers,axp209-adc.yaml | 18 +
.../bindings/mfd/x-powers,axp152.yaml | 1 +
.../x-powers,axp20x-battery-power-supply.yaml | 1 +
.../x-powers,axp20x-usb-power-supply.yaml | 1 +
drivers/iio/adc/axp20x_adc.c | 356 ++++++++++++++++--
drivers/mfd/axp20x-i2c.c | 2 +
drivers/mfd/axp20x.c | 141 +++++++
drivers/power/supply/axp20x_battery.c | 142 ++++++-
drivers/power/supply/axp20x_usb_power.c | 84 ++++-
drivers/regulator/axp20x-regulator.c | 100 ++++-
include/linux/mfd/axp20x.h | 84 +++++
11 files changed, 856 insertions(+), 74 deletions(-)


base-commit: e35e5b6f695d241ffb1d223207da58a1fbcdff4b
prerequisite-patch-id: a45db1cac7537769dc10087fc61f977dc150744c
prerequisite-patch-id: cb8aa009c7bb7a6575eb05e3af65342dc8d0efa3
prerequisite-patch-id: 8d32557e53b894d1fb17250d2d0eb3673f068d37
prerequisite-patch-id: 5b293867ef81e3697892ac51b941bb53680a70dc
prerequisite-patch-id: 8138d39a4817e804141bfe8c2ad37d9c55456a40
prerequisite-patch-id: b01216129e887519d441cf556bbc75c397871773
prerequisite-patch-id: b5dcf0c0609113c2d81bc557c1fc95ef23f40811
prerequisite-patch-id: 622ca1c10e851b1889aaa567c1d2a0adf43cca44
prerequisite-patch-id: d28c5187f9bf0e43f27b2f4aa8dcf7fd91842a03
prerequisite-patch-id: d29d54b756be73304f844abeeaf9b46a5c0119d5
prerequisite-patch-id: 5d405790ae89c0831b46a359f86e94bac5a67470
prerequisite-patch-id: c90120e79acbb52ffa148bfedee1df9d35b5eced
--
2.35.1


2022-07-06 10:57:49

by Aidan MacDonald

[permalink] [raw]
Subject: [PATCH v5 09/13] iio: adc: axp20x_adc: Add support for AXP192

The AXP192 is identical to the AXP20x, except for the addition of
two more GPIO ADC channels.

Reviewed-by: Jonathan Cameron <[email protected]>
Reviewed-by: Andy Shevchenko <[email protected]>
Signed-off-by: Aidan MacDonald <[email protected]>
---
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, &regval);
+ 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

2022-07-06 11:00:29

by Aidan MacDonald

[permalink] [raw]
Subject: [PATCH v5 04/13] dt-bindings: power: axp20x-battery: Add AXP192 compatible

The AXP192's battery charger is similar to the others supported by
the axp20x_battery driver.

Acked-by: Rob Herring <[email protected]>
Signed-off-by: Aidan MacDonald <[email protected]>
---
.../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

2022-07-06 11:05:18

by Aidan MacDonald

[permalink] [raw]
Subject: [PATCH v5 05/13] mfd: axp20x: Add support for AXP192

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 <[email protected]>
Reviewed-by: Andy Shevchenko <[email protected]>
Signed-off-by: Aidan MacDonald <[email protected]>
---
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

2022-07-06 11:07:48

by Aidan MacDonald

[permalink] [raw]
Subject: [PATCH v5 01/13] dt-bindings: mfd: add bindings for AXP192 MFD device

The AXP192 is another X-Powers PMIC similar to the existing ones.

Acked-by: Rob Herring <[email protected]>
Acked-by: Chen-Yu Tsai <[email protected]>
Signed-off-by: Aidan MacDonald <[email protected]>
---
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