On Tue, 2020-12-08 at 17:04 +0900, Yoshihiro Shimoda wrote: > From: Khiem Nguyen <khiem.nguyen.xt@xxxxxxxxxxx> > > The new PMIC BD9574MWF inherits features from BD9571MWV. > Add the support of new PMIC to existing bd9571mwv driver. > > Signed-off-by: Khiem Nguyen <khiem.nguyen.xt@xxxxxxxxxxx> > [shimoda: rebase and refactor] > Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@xxxxxxxxxxx> > --- > drivers/mfd/bd9571mwv.c | 92 > +++++++++++++++++++++++++++++++++++++++++++ > include/linux/mfd/bd9571mwv.h | 80 > +++++++++++++++++++++++++++++++++++++ > 2 files changed, 172 insertions(+) > > diff --git a/drivers/mfd/bd9571mwv.c b/drivers/mfd/bd9571mwv.c > index 57bdb6a..f8f0a87 100644 > --- a/drivers/mfd/bd9571mwv.c > +++ b/drivers/mfd/bd9571mwv.c > @@ -20,6 +20,7 @@ static const struct mfd_cell bd9571mwv_cells[] = { > { .name = "bd9571mwv-gpio", }, > }; > > +/* Regmap for BD9571MWV */ > static const struct regmap_range bd9571mwv_readable_yes_ranges[] = { > regmap_reg_range(BD9571MWV_VENDOR_CODE, > BD9571MWV_PRODUCT_REVISION), > regmap_reg_range(BD9571MWV_BKUP_MODE_CNT, > BD9571MWV_BKUP_MODE_CNT), > @@ -112,6 +113,95 @@ static const struct bd957x_data bd9571mwv_data = > { > .num_cells = ARRAY_SIZE(bd9571mwv_cells), > }; > > +static const struct mfd_cell bd9574mwf_cells[] = { > + { .name = "bd9571mwv-gpio", }, Another 'nit' suggestion which you can ignore if it does not make sense :) Are the GPIO blocks 100% identical? If not, then I would suggest changing this to: { .name = "bd9574mwf-gpio", }, and populating the platform_driver id_table for sub driver(s) using something like: static const struct platform_device_id bd957x_gpio_id[] = { { "bd9571mwv-gpio", ROHM_CHIP_TYPE_BD9571 }, { "bd9574mwf-gpio", ROHM_CHIP_TYPE_BD9574 }, { }, }; Then you can get the IC type using platform_get_device_id(pdev)->driver_data. Next, I think the parent data from MFD is only used to get the regmap and dev in sub-devices, right? Maybe you could simplify this and get rid of the whole MFD parent data structure? I think you can use pdev->dev.parent to get the parent device and dev_get_regmap(pdev->dev.parent, NULL); to get the regmap? (After this I wonder if you need the struct bd9571mwv at all?) > +}; > + > +/* Regmap for BD9574MWF */ > +static const struct regmap_range bd9574mwf_readable_yes_ranges[] = { > + regmap_reg_range(BD9574MWF_VENDOR_CODE, > BD9574MWF_PRODUCT_REVISION), > + regmap_reg_range(BD9574MWF_GPIO_IN, BD9574MWF_GPIO_IN), > + regmap_reg_range(BD9574MWF_GPIO_INT, BD9574MWF_GPIO_INTMASK), > + regmap_reg_range(BD9574MWF_GPIO_MUX, BD9574MWF_GPIO_MUX), > + regmap_reg_range(BD9574MWF_INT_INTREQ, BD9574MWF_INT_INTMASK), > +}; > + > +static const struct regmap_access_table bd9574mwf_readable_table = { > + .yes_ranges = bd9574mwf_readable_yes_ranges, > + .n_yes_ranges = ARRAY_SIZE(bd9574mwf_readable_yes_ranges), > +}; > + > +static const struct regmap_range bd9574mwf_writable_yes_ranges[] = { > + regmap_reg_range(BD9574MWF_GPIO_DIR, BD9574MWF_GPIO_OUT), > + regmap_reg_range(BD9574MWF_GPIO_INT_SET, > BD9574MWF_GPIO_INTMASK), > + regmap_reg_range(BD9574MWF_INT_INTREQ, BD9574MWF_INT_INTMASK), > +}; > + > +static const struct regmap_access_table bd9574mwf_writable_table = { > + .yes_ranges = bd9574mwf_writable_yes_ranges, > + .n_yes_ranges = ARRAY_SIZE(bd9574mwf_writable_yes_ranges), > +}; > + > +static const struct regmap_range bd9574mwf_volatile_yes_ranges[] = { > + regmap_reg_range(BD9574MWF_GPIO_IN, BD9574MWF_GPIO_IN), > + regmap_reg_range(BD9574MWF_GPIO_INT, BD9574MWF_GPIO_INT), > + regmap_reg_range(BD9574MWF_INT_INTREQ, BD9574MWF_INT_INTREQ), > +}; Are you using the other interrupts/statuses or VDCORE MoniVDAC? Should they be volatile too? > + > +static const struct regmap_access_table bd9574mwf_volatile_table = { > + .yes_ranges = bd9574mwf_volatile_yes_ranges, > + .n_yes_ranges = ARRAY_SIZE(bd9574mwf_volatile_yes_ranges), > +}; > + > +static const struct regmap_config bd9574mwf_regmap_config = { > + .reg_bits = 8, > + .val_bits = 8, > + .cache_type = REGCACHE_RBTREE, > + .rd_table = &bd9574mwf_readable_table, > + .wr_table = &bd9574mwf_writable_table, > + .volatile_table = &bd9574mwf_volatile_table, > + .max_register = 0xff, > +}; > + > +static const struct regmap_irq bd9574mwf_irqs[] = { > + REGMAP_IRQ_REG(BD9574MWF_IRQ_MD1, 0, > + BD9574MWF_INT_INTREQ_MD1_INT), > + REGMAP_IRQ_REG(BD9574MWF_IRQ_MD2_E1, 0, > + BD9574MWF_INT_INTREQ_MD2_E1_INT), > + REGMAP_IRQ_REG(BD9574MWF_IRQ_MD2_E2, 0, > + BD9574MWF_INT_INTREQ_MD2_E2_INT), > + REGMAP_IRQ_REG(BD9574MWF_IRQ_PROT_ERR, 0, > + BD9574MWF_INT_INTREQ_PROT_ERR_INT), > + REGMAP_IRQ_REG(BD9574MWF_IRQ_GP, 0, > + BD9574MWF_INT_INTREQ_GP_INT), > + REGMAP_IRQ_REG(BD9574MWF_IRQ_BKUP_HOLD_OF, 0, > + BD9574MWF_INT_INTREQ_BKUP_HOLD_OF_INT), > + REGMAP_IRQ_REG(BD9574MWF_IRQ_WDT_OF, 0, > + BD9574MWF_INT_INTREQ_WDT_OF_INT), > + REGMAP_IRQ_REG(BD9574MWF_IRQ_BKUP_TRG, 0, > + BD9574MWF_INT_INTREQ_BKUP_TRG_INT), > +}; > + > +static struct regmap_irq_chip bd9574mwf_irq_chip = { > + .name = "bd9574mwf", > + .status_base = BD9574MWF_INT_INTREQ, > + .mask_base = BD9574MWF_INT_INTMASK, > + .ack_base = BD9574MWF_INT_INTREQ, > + .init_ack_masked = true, > + .num_regs = 1, > + .irqs = bd9574mwf_irqs, > + .num_irqs = ARRAY_SIZE(bd9574mwf_irqs), > +}; > + > +static const struct bd957x_data bd9574mwf_data = { > + .product_code_val = BD9574MWF_PRODUCT_CODE_VAL, > + .part_number = BD9574MWF_PART_NUMBER, > + .regmap_config = &bd9574mwf_regmap_config, > + .irq_chip = &bd9574mwf_irq_chip, > + .cells = bd9574mwf_cells, > + .num_cells = ARRAY_SIZE(bd9574mwf_cells), > +}; > + > static int bd9571mwv_identify(struct bd9571mwv *bd) > { > struct device *dev = bd->dev; > @@ -182,6 +272,8 @@ static int bd9571mwv_probe(struct i2c_client > *client, > product_code = (unsigned int)ret; > if (product_code == BD9571MWV_PRODUCT_CODE_VAL) > bd->data = &bd9571mwv_data; > + else if (product_code == BD9574MWF_PRODUCT_CODE_VAL) > + bd->data = &bd9574mwf_data; > > if (!bd->data) { > dev_err(bd->dev, "No found supported device %d\n", > diff --git a/include/linux/mfd/bd9571mwv.h > b/include/linux/mfd/bd9571mwv.h > index 0126b52..e9e219b 100644 > --- a/include/linux/mfd/bd9571mwv.h > +++ b/include/linux/mfd/bd9571mwv.h > @@ -99,6 +99,86 @@ enum bd9571mwv_irqs { > BD9571MWV_IRQ_BKUP_TRG, > }; > > +/* List of registers for BD9574MWF */ > +#define BD9574MWF_VENDOR_CODE 0x00 > +#define BD9574MWF_VENDOR_CODE_VAL 0xdb > +#define BD9574MWF_PRODUCT_CODE 0x01 > +#define BD9574MWF_PRODUCT_CODE_VAL 0x74 > +#define BD9574MWF_PRODUCT_REVISION 0x02 > + > +#define BD9574MWF_I2C_FUSA_MODE 0x10 > +#define BD9574MWF_I2C_MD2_E1_BIT_1 0x11 > +#define BD9574MWF_I2C_MD2_E1_BIT_2 0x12 > + > +#define BD9574MWF_BKUP_MODE_CNT 0x20 > +#define BD9574MWF_BKUP_MODE_STATUS 0x21 > +#define BD9574MWF_BKUP_RECOVERY_CNT 0x22 > +#define BD9574MWF_BKUP_CTRL_TIM_CNT 0x23 > +#define BD9574MWF_WAITBKUP_WDT_CNT 0x24 > +#define BD9574MWF_BKUP_HOLD_TIM_CNT1 0x26 > +#define BD9574MWF_QLLM_CNT 0x27 > +#define BD9574MWF_BKUP_HOLD_TIM_CNT2 0x28 > + > +#define BD9574MWF_DCDC_FREQ 0x48 > + > +#define BD9574MWF_VDCORE_VINIT 0x50 > +#define BD9574MWF_VD09_VINIT 0x51 > +#define BD9574MWF_VDCORE_SETVMAX 0x52 > +#define BD9574MWF_VDCORE_SETVID 0x54 > +#define BD9574MWF_VDCORE_MONIVDAC 0x55 > +#define BD9574MWF_VDCORE_PGD_CNT 0x56 > + > +#define BD9574MWF_GPIO_DIR 0x60 > +#define BD9574MWF_GPIO_OUT 0x61 > +#define BD9574MWF_GPIO_IN 0x62 > +#define BD9574MWF_GPIO_DEB 0x63 > +#define BD9574MWF_GPIO_INT_SET 0x64 > +#define BD9574MWF_GPIO_INT 0x65 > +#define BD9574MWF_GPIO_INTMASK 0x66 > +#define BD9574MWF_GPIO_MUX 0x67 > + > +#define BD9574MWF_REG_KEEP(n) (0x70 + (n)) > + > +#define BD9574MWF_PMIC_INTERNAL_STATUS 0x80 > +#define BD9574MWF_PROT_ERROR_STATUS0 0x81 > +#define BD9574MWF_PROT_ERROR_STATUS1 0x82 > +#define BD9574MWF_PROT_ERROR_STATUS2 0x83 > +#define BD9574MWF_PROT_ERROR_STATUS3 0x84 > +#define BD9574MWF_PROT_ERROR_STATUS4 0x85 > +#define BD9574MWF_PROT_ERROR_STATUS5 0x86 > +#define BD9574MWF_SYS_ERROR_STATUS 0x87 > + > +#define BD9574MWF_INT_INTREQ 0x90 > +#define BD9574MWF_INT_INTREQ_MD1_INT BIT(0) > +#define BD9574MWF_INT_INTREQ_MD2_E1_INT BIT(1) > +#define BD9574MWF_INT_INTREQ_MD2_E2_INT BIT(2) > +#define BD9574MWF_INT_INTREQ_PROT_ERR_INT BIT(3) > +#define BD9574MWF_INT_INTREQ_GP_INT BIT(4) > +#define BD9574MWF_INT_INTREQ_BKUP_HOLD_OF_INT BIT(5) > +#define BD9574MWF_INT_INTREQ_WDT_OF_INT BIT(6) > +#define BD9574MWF_INT_INTREQ_BKUP_TRG_INT BIT(7) > +#define BD9574MWF_INT_INTMASK 0x91 > + > +#define BD9574MWF_SSCG_CNT 0xA0 > +#define BD9574MWF_POFFB_MRB 0xA1 > +#define BD9574MWF_SMRB_WR_PROT 0xA2 > +#define BD9574MWF_SMRB_ASSERT 0xA3 > +#define BD9574MWF_SMRB_STATUS 0xA4 > + > +#define BD9574MWF_PART_NUMBER "BD9574MWF" > + > +/* Define the BD9574MWF IRQ numbers */ > +enum bd9574mwf_irqs { > + BD9574MWF_IRQ_MD1, > + BD9574MWF_IRQ_MD2_E1, > + BD9574MWF_IRQ_MD2_E2, > + BD9574MWF_IRQ_PROT_ERR, > + BD9574MWF_IRQ_GP, > + BD9574MWF_IRQ_BKUP_HOLD_OF, > + BD9574MWF_IRQ_WDT_OF, > + BD9574MWF_IRQ_BKUP_TRG, > +}; > + > /** > * struct bd957x_data - internal data for the bd957x driver > * Overall a good looking driver! Thanks a lot! Best Regards Matti -- Matti Vaittinen, Linux device drivers ROHM Semiconductors, Finland SWDC Kiviharjunlenkki 1E 90220 OULU FINLAND ~~~ "I don't think so," said Rene Descartes. Just then he vanished ~~~ Simon says - in Latin please. "non cogito me" dixit Rene Descarte, deinde evanescavit (Thanks for the translation Simon)