Re: [PATCH RESEND v6 4/5] mfd: axp20x: Add support for AXP318W PMIC
Chen-Yu Tsai <[email protected]>
| Newsgroups | gmane.linux.drivers.devicetree,gmane.linux.kernel |
|---|---|
| Message-ID | <CAGb2v66Uz6hCQaf5Nk5Eup8wQ+Xo9tuAqm0+ZH9J5CbT0zyAPg@mail.gmail.com> |
On Thu, Aug 13, 2026 at 5:31 AM Jerome Brunet <jbrunet-rdvid1DuHRBWk0Htik3J/[email protected]> wrote: > > From: Andre Przywara <[email protected]> > > The AXP318W is a PMIC chip produced by X-Powers, it can be connected to > an I2C bus. > > It has a large number of regulators: 9(!) DCDC buck converters, and 28 > LDOs, also some ADCs, interrupts, and a power key. > > Describe the regmap and the MFD bits, along with the registers exposed > via I2C only. This covers the regulators and interrupts for now. > Advertise the device using the new compatible string. > > We use just "318" for the internal identifiers, for easier typing and > less churn, but use "318W" for anything externally visible. If something > else other than the "AXP318W" shows up, that's an easy change then. > > Signed-off-by: Andre Przywara <[email protected]> > Signed-off-by: Jerome Brunet <jbrunet-rdvid1DuHRBWk0Htik3J/[email protected]> > --- > drivers/mfd/axp20x-i2c.c | 2 ++ > drivers/mfd/axp20x.c | 81 ++++++++++++++++++++++++++++++++++++++++++ > include/linux/mfd/axp20x.h | 88 ++++++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 171 insertions(+) [...] > diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c > index 84839d4aa1ca..ea00c0cdce58 100644 > --- a/drivers/mfd/axp20x.c > +++ b/drivers/mfd/axp20x.c > @@ -218,6 +219,31 @@ static const struct regmap_access_table axp313a_volatile_table = { > .n_yes_ranges = ARRAY_SIZE(axp313a_volatile_ranges), > }; > > +static const struct regmap_range axp318_writeable_ranges[] = { + regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_DATACACHE(3)), > + regmap_reg_range(AXP318_DCDC_OUTPUT_CONTROL1, AXP318_IRQ_STATE4), Probably want to skip the holes between: - AXP318_DCDC9_CONTROL and AXP318_DCDC_MODE_CTRL1 - AXP318_DCDC_MODE_CTRL1 and AXP318_DCDC_MODE_CTRL3 - AXP318_DCDC_MODE_CTRL3 and AXP318_LDO_OUTPUT_CONTROL1 - AXP318_IRQ_EN4 and AXP318_IRQ_STATE1 > + regmap_reg_range(AXP318_SHUTDOWN_SRC_CTRL1, AXP318_TEMP_ADC_H_EN), Holes between - AXP318_POK_CTRL and AXP318_TEMP_ADC_H_EN - AXP318_WAKEUP_PWROK_PIN_CFG and AXP318_TS_PIN_CFG - AXP318_TS_PIN_CFG and AXP318_TEMP_ADC_H_EN > + regmap_reg_range(AXP318_DIE_TEMP_ADC_H_EN, AXP318_DIE_TEMP_ADC_H_EN), > + regmap_reg_range(AXP318_GPADC_H_EN, AXP318_GPADC_H_EN), > + regmap_reg_range(AXP318_GPIO_CTRL, AXP318_WDOG_CTRL), > +}; > + > +static const struct regmap_range axp318_volatile_ranges[] = { > + regmap_reg_range(AXP318_IRQ_EN1, AXP318_IRQ_STATE4), The EN bits aren't volatile; only the status bits are. > + regmap_reg_range(AXP318_POWER_REASON, AXP318_SHUTDOWN_SOURCE), > + regmap_reg_range(AXP318_TEMP_ADC_H_EN, AXP318_GPADC_L), > + regmap_reg_range(AXP318_GPIO_INPUT, AXP318_GPIO_INPUT), > +}; > + > +static const struct regmap_access_table axp318_writeable_table = { > + .yes_ranges = axp318_writeable_ranges, > + .n_yes_ranges = ARRAY_SIZE(axp318_writeable_ranges), > +}; > + > +static const struct regmap_access_table axp318_volatile_table = { > + .yes_ranges = axp318_volatile_ranges, > + .n_yes_ranges = ARRAY_SIZE(axp318_volatile_ranges), > +}; > + > static const struct regmap_range axp717_writeable_ranges[] = { > regmap_reg_range(AXP717_PMU_FAULT, AXP717_MODULE_EN_CONTROL_1), > regmap_reg_range(AXP717_MIN_SYS_V_CONTROL, AXP717_BOOST_CONTROL), > @@ -447,6 +473,15 @@ static const struct regmap_config axp313a_regmap_config = { > .cache_type = REGCACHE_MAPLE, > }; > > +static const struct regmap_config axp318_regmap_config = { > + .reg_bits = 8, > + .val_bits = 8, > + .wr_table = &axp318_writeable_table, > + .volatile_table = &axp318_volatile_table, > + .max_register = AXP318_WDOG_CTRL, > + .cache_type = REGCACHE_MAPLE, > +}; > + > static const struct regmap_config axp323_regmap_config = { > .reg_bits = 8, > .val_bits = 8, > @@ -663,6 +698,28 @@ static const struct regmap_irq axp313a_regmap_irqs[] = { > INIT_REGMAP_IRQ(AXP313A, DIE_TEMP_HIGH, 0, 0), > }; > > +static const struct regmap_irq axp318_regmap_irqs[] = { > + INIT_REGMAP_IRQ(AXP318, DCDC8_V_LOW, 0, 7), > + INIT_REGMAP_IRQ(AXP318, DCDC7_V_LOW, 0, 6), > + INIT_REGMAP_IRQ(AXP318, DCDC6_V_LOW, 0, 5), > + INIT_REGMAP_IRQ(AXP318, DCDC5_V_LOW, 0, 4), > + INIT_REGMAP_IRQ(AXP318, DCDC4_V_LOW, 0, 3), > + INIT_REGMAP_IRQ(AXP318, DCDC3_V_LOW, 0, 2), > + INIT_REGMAP_IRQ(AXP318, DCDC2_V_LOW, 0, 1), > + INIT_REGMAP_IRQ(AXP318, DCDC1_V_LOW, 0, 0), > + INIT_REGMAP_IRQ(AXP318, PEK_RIS_EDGE, 1, 6), > + INIT_REGMAP_IRQ(AXP318, PEK_FAL_EDGE, 1, 5), > + INIT_REGMAP_IRQ(AXP318, PEK_LONG, 1, 4), > + INIT_REGMAP_IRQ(AXP318, PEK_SHORT, 1, 3), These two seem to be reversed. > + INIT_REGMAP_IRQ(AXP318, DIE_TEMP_HIGH_LV2, 1, 2), > + INIT_REGMAP_IRQ(AXP318, DIE_TEMP_HIGH_LV1, 1, 1), > + INIT_REGMAP_IRQ(AXP318, DCDC9_V_LOW, 1, 0), > + INIT_REGMAP_IRQ(AXP318, GPIO3_INPUT, 2, 6), > + INIT_REGMAP_IRQ(AXP318, GPIO2_INPUT, 2, 5), > + INIT_REGMAP_IRQ(AXP318, GPIO1_INPUT, 2, 4), > + INIT_REGMAP_IRQ(AXP318, WDOG_EXPIRE, 3, 0), > +}; > + > static const struct regmap_irq axp717_regmap_irqs[] = { > INIT_REGMAP_IRQ(AXP717, SOC_DROP_LVL2, 0, 7), > INIT_REGMAP_IRQ(AXP717, SOC_DROP_LVL1, 0, 6), > @@ -884,6 +941,17 @@ static const struct regmap_irq_chip axp313a_regmap_irq_chip = { > .num_regs = 1, > }; > > +static const struct regmap_irq_chip axp318_regmap_irq_chip = { > + .name = "axp318w_irq_chip", > + .status_base = AXP318_IRQ_STATE1, > + .ack_base = AXP318_IRQ_STATE1, > + .unmask_base = AXP318_IRQ_EN1, > + .init_ack_masked = true, > + .irqs = axp318_regmap_irqs, > + .num_irqs = ARRAY_SIZE(axp318_regmap_irqs), > + .num_regs = 4, > +}; > + > static const struct regmap_irq_chip axp717_regmap_irq_chip = { > .name = "axp717_irq_chip", > .status_base = AXP717_IRQ0_STATE, > @@ -1061,6 +1129,10 @@ static const struct mfd_cell axp313a_cells[] = { > MFD_CELL_RES("axp313a-pek", axp313a_pek_resources), > }; > > +static const struct mfd_cell axp318_cells[] = { > + MFD_CELL_BASIC("axp20x-regulator", NULL, NULL, 0, 1), Unless this PMIC is used as a sub-PMIC in other designs, we don't need an ID. Allwinner designs "mostly" only have one PMIC. We add IDs only when needed, as seen on the AXP313a and AXP806 + AXP809. > +}; > + > static const struct mfd_cell axp717_cells[] = { > MFD_CELL_NAME("axp20x-regulator"), > MFD_CELL_RES("axp20x-pek", axp717_pek_resources), > @@ -1248,6 +1320,9 @@ static int axp20x_power_off(struct sys_off_data *data) > case AXP313A_ID: > shutdown_reg = AXP313A_SHUTDOWN_CTRL; > break; > + case AXP318_ID: > + shutdown_reg = AXP318_SHUTDOWN_CTRL; > + break; > default: > shutdown_reg = AXP20X_OFF_CTRL; > break; > @@ -1312,6 +1387,12 @@ int axp20x_match_device(struct axp20x_dev *axp20x) > axp20x->regmap_cfg = &axp313a_regmap_config; > axp20x->regmap_irq_chip = &axp313a_regmap_irq_chip; > break; > + case AXP318_ID: > + axp20x->nr_cells = ARRAY_SIZE(axp318_cells); > + axp20x->cells = axp318_cells; > + axp20x->regmap_cfg = &axp318_regmap_config; > + axp20x->regmap_irq_chip = &axp318_regmap_irq_chip; > + break; > case AXP323_ID: > axp20x->nr_cells = ARRAY_SIZE(axp313a_cells); > axp20x->cells = axp313a_cells; > diff --git a/include/linux/mfd/axp20x.h b/include/linux/mfd/axp20x.h > index 1badb4868d17..0191467de4ec 100644 > --- a/include/linux/mfd/axp20x.h > +++ b/include/linux/mfd/axp20x.h > @@ -19,6 +19,7 @@ enum axp20x_variants { > AXP223_ID, > AXP288_ID, > AXP313A_ID, > + AXP318_ID, > AXP323_ID, > AXP717_ID, > AXP803_ID, > @@ -116,6 +117,71 @@ enum axp20x_variants { > #define AXP313A_IRQ_STATE 0x21 > #define AXP323_DCDC_MODE_CTRL2 0x22 > > +#define AXP318_DCDC_OUTPUT_CONTROL1 0x10 > +#define AXP318_DCDC_OUTPUT_CONTROL2 0x11 > +#define AXP318_DCDC1_CONTROL 0x12 > +#define AXP318_DCDC2_CONTROL 0x13 > +#define AXP318_DCDC3_CONTROL 0x14 > +#define AXP318_DCDC4_CONTROL 0x15 > +#define AXP318_DCDC5_CONTROL 0x16 > +#define AXP318_DCDC6_CONTROL 0x17 > +#define AXP318_DCDC7_CONTROL 0x18 > +#define AXP318_DCDC8_CONTROL 0x19 > +#define AXP318_DCDC9_CONTROL 0x1a +#define AXP318_DCDC_MODE_CTRL1 0x1b +#define AXP318_DCDC_MODE_CTRL3 0x1d > +#define AXP318_LDO_OUTPUT_CONTROL1 0x20 > +#define AXP318_LDO_OUTPUT_CONTROL2 0x21 > +#define AXP318_LDO_OUTPUT_CONTROL3 0x22 > +#define AXP318_LDO_OUTPUT_CONTROL4 0x23 > +#define AXP318_ALDO1_CONTROL 0x24 > +#define AXP318_ALDO2_CONTROL 0x25 > +#define AXP318_ALDO3_CONTROL 0x26 > +#define AXP318_ALDO4_CONTROL 0x27 > +#define AXP318_ALDO5_CONTROL 0x28 > +#define AXP318_ALDO6_CONTROL 0x29 > +#define AXP318_BLDO1_CONTROL 0x2a > +#define AXP318_BLDO2_CONTROL 0x2b > +#define AXP318_BLDO3_CONTROL 0x2c > +#define AXP318_BLDO4_CONTROL 0x2d > +#define AXP318_BLDO5_CONTROL 0x2e > +#define AXP318_CLDO1_CONTROL 0x2f > +#define AXP318_CLDO2_CONTROL 0x30 > +#define AXP318_CLDO3_CONTROL 0x31 > +#define AXP318_CLDO4_CONTROL 0x32 > +#define AXP318_CLDO5_CONTROL 0x33 > +#define AXP318_DLDO1_CONTROL 0x34 > +#define AXP318_DLDO2_CONTROL 0x35 > +#define AXP318_DLDO3_CONTROL 0x36 > +#define AXP318_DLDO4_CONTROL 0x37 > +#define AXP318_DLDO5_CONTROL 0x38 > +#define AXP318_DLDO6_CONTROL 0x39 > +#define AXP318_ELDO1_CONTROL 0x3a > +#define AXP318_ELDO2_CONTROL 0x3b > +#define AXP318_ELDO3_CONTROL 0x3c > +#define AXP318_ELDO4_CONTROL 0x3d > +#define AXP318_ELDO5_CONTROL 0x3e > +#define AXP318_ELDO6_CONTROL 0x3f > +#define AXP318_IRQ_EN1 0x40 > +#define AXP318_IRQ_EN2 0x41 > +#define AXP318_IRQ_EN3 0x42 > +#define AXP318_IRQ_EN4 0x43 > +#define AXP318_IRQ_STATE1 0x48 > +#define AXP318_IRQ_STATE2 0x49 > +#define AXP318_IRQ_STATE3 0x4a > +#define AXP318_IRQ_STATE4 0x4b > +#define AXP318_POWER_REASON 0x50 > +#define AXP318_SHUTDOWN_SOURCE 0x51 > +#define AXP318_SHUTDOWN_SRC_CTRL1 0x52 > +#define AXP318_SHUTDOWN_SRC_CTRL2 0x53 +#define AXP318_DISCHARGE_OVERTEMP_CTRL 0x54 > +#define AXP318_SHUTDOWN_CTRL 0x55 +#define AXP318_WAKEUP_VOFF_CTRL 0x56 +#define AXP318_POK_CTRL 0x57 +#define AXP318_WAKEUP_PWROK_PIN_CFG 0x5d +#define AXP318_TS_PIN_CFG 0x60 > +#define AXP318_TEMP_ADC_H_EN 0x65 > +#define AXP318_TEMP_ADC_L 0x66 > +#define AXP318_DIE_TEMP_ADC_H_EN 0x67 +#define AXP318_DIE_TEMP_ADC_L 0x68 > +#define AXP318_GPADC_H_EN 0x69 > +#define AXP318_GPADC_L 0x6a > +#define AXP318_GPIO_CTRL 0x70 > +#define AXP318_GPIO_INPUT 0x71 +#define AXP318_GPIO_OUTPUT 0x72 +#define AXP318_PWM_CTRL1 0x73 +#define AXP318_PWM_CTRL2 0x74 +#define AXP318_PWM_CTRL3 0x75 +#define AXP318_BACKUP_BATTERY_CTRL 0x76 > +#define AXP318_WDOG_CTRL 0x77 > + > #define AXP717_ON_INDICATE 0x00 > #define AXP717_PMU_STATUS_2 0x01 > #define AXP717_BC_DETECT 0x05 > @@ -819,6 +885,28 @@ enum axp313a_irqs { > AXP313A_IRQ_PEK_RIS_EDGE, > }; > > +enum axp318_irqs { > + AXP318_IRQ_DCDC1_V_LOW, > + AXP318_IRQ_DCDC2_V_LOW, > + AXP318_IRQ_DCDC3_V_LOW, > + AXP318_IRQ_DCDC4_V_LOW, > + AXP318_IRQ_DCDC5_V_LOW, > + AXP318_IRQ_DCDC6_V_LOW, > + AXP318_IRQ_DCDC7_V_LOW, > + AXP318_IRQ_DCDC8_V_LOW, > + AXP318_IRQ_DCDC9_V_LOW, > + AXP318_IRQ_DIE_TEMP_HIGH_LV1, > + AXP318_IRQ_DIE_TEMP_HIGH_LV2, > + AXP318_IRQ_PEK_SHORT, > + AXP318_IRQ_PEK_LONG, The order of these two are reversed. > + AXP318_IRQ_PEK_FAL_EDGE, > + AXP318_IRQ_PEK_RIS_EDGE, And these two as well. Once all these are fixed, Reviewed-by: Chen-Yu Tsai <[email protected]> ChenYu > + AXP318_IRQ_GPIO1_INPUT = 20, > + AXP318_IRQ_GPIO2_INPUT, > + AXP318_IRQ_GPIO3_INPUT, > + AXP318_IRQ_WDOG_EXPIRE = 24, > +}; > + > enum axp717_irqs { > AXP717_IRQ_VBUS_FAULT, > AXP717_IRQ_VBUS_OVER_V, > > -- > 2.47.3 >