Instead of filling in the regulator description programatically, store the data in a struct. This will make it a bit nicer to introduce support for other BCM590xx chips besides the BCM59056. To do this, add a new struct type, bcm590xx_reg_info, to store all of the necessary information. Drop the old IS_LDO, IS_GPLDO... macros in favor of the "type" field in this struct. Adapt the old bcm590xx_reg struct to the new types. Signed-off-by: Artur Weber <aweber.kernel@xxxxxxxxx> --- Changes in v3: - Added this commit --- drivers/regulator/bcm590xx-regulator.c | 472 ++++++++++++++++++++++----------- 1 file changed, 316 insertions(+), 156 deletions(-) diff --git a/drivers/regulator/bcm590xx-regulator.c b/drivers/regulator/bcm590xx-regulator.c index 9f0cda46b01506080ae5fa709104a8df4d174a8d..6548653a6fb7207a5aa8e006a005553bfb7b1d69 100644 --- a/drivers/regulator/bcm590xx-regulator.c +++ b/drivers/regulator/bcm590xx-regulator.c @@ -20,6 +20,18 @@ /* I2C slave 0 registers */ #define BCM590XX_RFLDOPMCTRL1 0x60 +#define BCM590XX_CAMLDO1PMCTRL1 0x62 +#define BCM590XX_CAMLDO2PMCTRL1 0x64 +#define BCM590XX_SIMLDO1PMCTRL1 0x66 +#define BCM590XX_SIMLDO2PMCTRL1 0x68 +#define BCM590XX_SDLDOPMCTRL1 0x6a +#define BCM590XX_SDXLDOPMCTRL1 0x6c +#define BCM590XX_MMCLDO1PMCTRL1 0x6e +#define BCM590XX_MMCLDO2PMCTRL1 0x70 +#define BCM590XX_AUDLDOPMCTRL1 0x72 +#define BCM590XX_MICLDOPMCTRL1 0x74 +#define BCM590XX_USBLDOPMCTRL1 0x76 +#define BCM590XX_VIBLDOPMCTRL1 0x78 #define BCM590XX_IOSR1PMCTRL1 0x7a #define BCM590XX_IOSR2PMCTRL1 0x7c #define BCM590XX_CSRPMCTRL1 0x7e @@ -28,7 +40,25 @@ #define BCM590XX_MSRPMCTRL1 0x8a #define BCM590XX_VSRPMCTRL1 0x8e #define BCM590XX_RFLDOCTRL 0x96 +#define BCM590XX_CAMLDO1CTRL 0x97 +#define BCM590XX_CAMLDO2CTRL 0x98 +#define BCM590XX_SIMLDO1CTRL 0x99 +#define BCM590XX_SIMLDO2CTRL 0x9a +#define BCM590XX_SDLDOCTRL 0x9b +#define BCM590XX_SDXLDOCTRL 0x9c +#define BCM590XX_MMCLDO1CTRL 0x9d +#define BCM590XX_MMCLDO2CTRL 0x9e +#define BCM590XX_AUDLDOCTRL 0x9f +#define BCM590XX_MICLDOCTRL 0xa0 +#define BCM590XX_USBLDOCTRL 0xa1 +#define BCM590XX_VIBLDOCTRL 0xa2 #define BCM590XX_CSRVOUT1 0xc0 +#define BCM590XX_IOSR1VOUT1 0xc3 +#define BCM590XX_IOSR2VOUT1 0xc6 +#define BCM590XX_MSRVOUT1 0xc9 +#define BCM590XX_SDSR1VOUT1 0xcc +#define BCM590XX_SDSR2VOUT1 0xcf +#define BCM590XX_VSRVOUT1 0xd2 /* I2C slave 1 registers */ #define BCM590XX_GPLDO5PMCTRL1 0x16 @@ -94,11 +124,6 @@ #define BCM590XX_NUM_REGS 27 -#define BCM590XX_REG_IS_LDO(n) (n < BCM590XX_REG_CSR) -#define BCM590XX_REG_IS_GPLDO(n) \ - ((n > BCM590XX_REG_VSR) && (n < BCM590XX_REG_VBUS)) -#define BCM590XX_REG_IS_VBUS(n) (n == BCM590XX_REG_VBUS) - /* LDO group A: supported voltages in microvolts */ static const unsigned int ldo_a_table[] = { 1200000, 1800000, 2500000, 2700000, 2800000, @@ -111,10 +136,6 @@ static const unsigned int ldo_c_table[] = { 2900000, 3000000, 3300000, }; -static const unsigned int ldo_vbus[] = { - 5000000, -}; - /* DCDC group CSR: supported voltages in microvolts */ static const struct linear_range dcdc_csr_ranges[] = { REGULATOR_LINEAR_RANGE(860000, 2, 50, 10000), @@ -137,115 +158,30 @@ static const struct linear_range dcdc_sdsr1_ranges[] = { REGULATOR_LINEAR_RANGE(900000, 52, 63, 0), }; -struct bcm590xx_info { - const char *name; - const char *vin_name; - u8 n_voltages; - const unsigned int *volt_table; - u8 n_linear_ranges; - const struct linear_range *linear_ranges; +enum bcm590xx_reg_type { + BCM590XX_REG_TYPE_LDO, + BCM590XX_REG_TYPE_GPLDO, + BCM590XX_REG_TYPE_SR, + BCM590XX_REG_TYPE_VBUS }; -#define BCM590XX_REG_TABLE(_name, _table) \ - { \ - .name = #_name, \ - .n_voltages = ARRAY_SIZE(_table), \ - .volt_table = _table, \ - } - -#define BCM590XX_REG_RANGES(_name, _ranges) \ - { \ - .name = #_name, \ - .n_voltages = 64, \ - .n_linear_ranges = ARRAY_SIZE(_ranges), \ - .linear_ranges = _ranges, \ - } +enum bcm590xx_reg_regmap { + BCM590XX_REG_REGMAP_PRI, + BCM590XX_REG_REGMAP_SEC, +}; -static struct bcm590xx_info bcm590xx_regs[] = { - BCM590XX_REG_TABLE(rfldo, ldo_a_table), - BCM590XX_REG_TABLE(camldo1, ldo_c_table), - BCM590XX_REG_TABLE(camldo2, ldo_c_table), - BCM590XX_REG_TABLE(simldo1, ldo_a_table), - BCM590XX_REG_TABLE(simldo2, ldo_a_table), - BCM590XX_REG_TABLE(sdldo, ldo_c_table), - BCM590XX_REG_TABLE(sdxldo, ldo_a_table), - BCM590XX_REG_TABLE(mmcldo1, ldo_a_table), - BCM590XX_REG_TABLE(mmcldo2, ldo_a_table), - BCM590XX_REG_TABLE(audldo, ldo_a_table), - BCM590XX_REG_TABLE(micldo, ldo_a_table), - BCM590XX_REG_TABLE(usbldo, ldo_a_table), - BCM590XX_REG_TABLE(vibldo, ldo_c_table), - BCM590XX_REG_RANGES(csr, dcdc_csr_ranges), - BCM590XX_REG_RANGES(iosr1, dcdc_iosr1_ranges), - BCM590XX_REG_RANGES(iosr2, dcdc_iosr1_ranges), - BCM590XX_REG_RANGES(msr, dcdc_iosr1_ranges), - BCM590XX_REG_RANGES(sdsr1, dcdc_sdsr1_ranges), - BCM590XX_REG_RANGES(sdsr2, dcdc_iosr1_ranges), - BCM590XX_REG_RANGES(vsr, dcdc_iosr1_ranges), - BCM590XX_REG_TABLE(gpldo1, ldo_a_table), - BCM590XX_REG_TABLE(gpldo2, ldo_a_table), - BCM590XX_REG_TABLE(gpldo3, ldo_a_table), - BCM590XX_REG_TABLE(gpldo4, ldo_a_table), - BCM590XX_REG_TABLE(gpldo5, ldo_a_table), - BCM590XX_REG_TABLE(gpldo6, ldo_a_table), - BCM590XX_REG_TABLE(vbus, ldo_vbus), +struct bcm590xx_reg_info { + enum bcm590xx_reg_type type; + enum bcm590xx_reg_regmap regmap; + const struct regulator_desc desc; }; struct bcm590xx_reg { - struct regulator_desc *desc; struct bcm590xx *mfd; + unsigned int n_regulators; + const struct bcm590xx_reg_info *regs; }; -static int bcm590xx_get_vsel_register(int id) -{ - if (BCM590XX_REG_IS_LDO(id)) - return BCM590XX_RFLDOCTRL + id; - else if (BCM590XX_REG_IS_GPLDO(id)) - return BCM590XX_GPLDO1CTRL + id; - else - return BCM590XX_CSRVOUT1 + (id - BCM590XX_REG_CSR) * 3; -} - -static int bcm590xx_get_enable_register(int id) -{ - int reg = 0; - - if (BCM590XX_REG_IS_LDO(id)) - reg = BCM590XX_RFLDOPMCTRL1 + id * 2; - else if (BCM590XX_REG_IS_GPLDO(id)) - reg = BCM590XX_GPLDO1PMCTRL1 + id * 2; - else - switch (id) { - case BCM590XX_REG_CSR: - reg = BCM590XX_CSRPMCTRL1; - break; - case BCM590XX_REG_IOSR1: - reg = BCM590XX_IOSR1PMCTRL1; - break; - case BCM590XX_REG_IOSR2: - reg = BCM590XX_IOSR2PMCTRL1; - break; - case BCM590XX_REG_MSR: - reg = BCM590XX_MSRPMCTRL1; - break; - case BCM590XX_REG_SDSR1: - reg = BCM590XX_SDSR1PMCTRL1; - break; - case BCM590XX_REG_SDSR2: - reg = BCM590XX_SDSR2PMCTRL1; - break; - case BCM590XX_REG_VSR: - reg = BCM590XX_VSRPMCTRL1; - break; - case BCM590XX_REG_VBUS: - reg = BCM590XX_OTG_CTRL; - break; - } - - - return reg; -} - static const struct regulator_ops bcm590xx_ops_ldo = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, @@ -272,73 +208,297 @@ static const struct regulator_ops bcm590xx_ops_vbus = { .disable = regulator_disable_regmap, }; +#define BCM590XX_REG_DESC(_name, _name_lower) \ + .id = BCM590XX_REG_##_name, \ + .name = #_name_lower, \ + .of_match = of_match_ptr(#_name_lower), \ + .regulators_node = of_match_ptr("regulators"), \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE \ + +#define BCM590XX_LDO_DESC(_name, _name_lower, _table) \ + BCM590XX_REG_DESC(_name, _name_lower), \ + .ops = &bcm590xx_ops_ldo, \ + .n_voltages = ARRAY_SIZE(_table), \ + .volt_table = _table, \ + .vsel_reg = BCM590XX_##_name##CTRL, \ + .vsel_mask = BCM590XX_LDO_VSEL_MASK, \ + .enable_reg = BCM590XX_##_name##PMCTRL1, \ + .enable_mask = BCM590XX_REG_ENABLE, \ + .enable_is_inverted = true + +#define BCM590XX_SR_DESC(_name, _name_lower, _ranges) \ + BCM590XX_REG_DESC(_name, _name_lower), \ + .ops = &bcm590xx_ops_dcdc, \ + .n_voltages = 64, \ + .linear_ranges = _ranges, \ + .n_linear_ranges = ARRAY_SIZE(_ranges), \ + .vsel_reg = BCM590XX_##_name##VOUT1, \ + .vsel_mask = BCM590XX_SR_VSEL_MASK, \ + .enable_reg = BCM590XX_##_name##PMCTRL1, \ + .enable_mask = BCM590XX_REG_ENABLE, \ + .enable_is_inverted = true + +static const struct bcm590xx_reg_info bcm590xx_regs[BCM590XX_NUM_REGS] = { + { + .type = BCM590XX_REG_TYPE_LDO, + .regmap = BCM590XX_REG_REGMAP_PRI, + .desc = { + BCM590XX_LDO_DESC(RFLDO, rfldo, ldo_a_table), + }, + }, + + { + .type = BCM590XX_REG_TYPE_LDO, + .regmap = BCM590XX_REG_REGMAP_PRI, + .desc = { + BCM590XX_LDO_DESC(CAMLDO1, camldo1, ldo_c_table), + }, + }, + + { + .type = BCM590XX_REG_TYPE_LDO, + .regmap = BCM590XX_REG_REGMAP_PRI, + .desc = { + BCM590XX_LDO_DESC(CAMLDO2, camldo2, ldo_c_table), + }, + }, + + { + .type = BCM590XX_REG_TYPE_LDO, + .regmap = BCM590XX_REG_REGMAP_PRI, + .desc = { + BCM590XX_LDO_DESC(SIMLDO1, simldo1, ldo_a_table), + }, + }, + + { + .type = BCM590XX_REG_TYPE_LDO, + .regmap = BCM590XX_REG_REGMAP_PRI, + .desc = { + BCM590XX_LDO_DESC(SIMLDO2, simldo2, ldo_a_table), + }, + }, + + { + .type = BCM590XX_REG_TYPE_LDO, + .regmap = BCM590XX_REG_REGMAP_PRI, + .desc = { + BCM590XX_LDO_DESC(SDLDO, sdldo, ldo_c_table), + }, + }, + + { + .type = BCM590XX_REG_TYPE_LDO, + .regmap = BCM590XX_REG_REGMAP_PRI, + .desc = { + BCM590XX_LDO_DESC(SDXLDO, sdxldo, ldo_a_table), + }, + }, + + { + .type = BCM590XX_REG_TYPE_LDO, + .regmap = BCM590XX_REG_REGMAP_PRI, + .desc = { + BCM590XX_LDO_DESC(MMCLDO1, mmcldo1, ldo_a_table), + }, + }, + + { + .type = BCM590XX_REG_TYPE_LDO, + .regmap = BCM590XX_REG_REGMAP_PRI, + .desc = { + BCM590XX_LDO_DESC(MMCLDO2, mmcldo2, ldo_a_table), + }, + }, + + { + .type = BCM590XX_REG_TYPE_LDO, + .regmap = BCM590XX_REG_REGMAP_PRI, + .desc = { + BCM590XX_LDO_DESC(AUDLDO, audldo, ldo_a_table), + }, + }, + + { + .type = BCM590XX_REG_TYPE_LDO, + .regmap = BCM590XX_REG_REGMAP_PRI, + .desc = { + BCM590XX_LDO_DESC(MICLDO, micldo, ldo_a_table), + }, + }, + + { + .type = BCM590XX_REG_TYPE_LDO, + .regmap = BCM590XX_REG_REGMAP_PRI, + .desc = { + BCM590XX_LDO_DESC(USBLDO, usbldo, ldo_a_table), + }, + }, + + { + .type = BCM590XX_REG_TYPE_LDO, + .regmap = BCM590XX_REG_REGMAP_PRI, + .desc = { + BCM590XX_LDO_DESC(VIBLDO, vibldo, ldo_c_table), + }, + }, + + { + .type = BCM590XX_REG_TYPE_SR, + .regmap = BCM590XX_REG_REGMAP_PRI, + .desc = { + BCM590XX_SR_DESC(CSR, csr, dcdc_csr_ranges), + }, + }, + + { + .type = BCM590XX_REG_TYPE_SR, + .regmap = BCM590XX_REG_REGMAP_PRI, + .desc = { + BCM590XX_SR_DESC(IOSR1, iosr1, dcdc_iosr1_ranges), + }, + }, + + { + .type = BCM590XX_REG_TYPE_SR, + .regmap = BCM590XX_REG_REGMAP_PRI, + .desc = { + BCM590XX_SR_DESC(IOSR2, iosr2, dcdc_iosr1_ranges), + }, + }, + + { + .type = BCM590XX_REG_TYPE_SR, + .regmap = BCM590XX_REG_REGMAP_PRI, + .desc = { + BCM590XX_SR_DESC(MSR, msr, dcdc_iosr1_ranges), + }, + }, + + { + .type = BCM590XX_REG_TYPE_SR, + .regmap = BCM590XX_REG_REGMAP_PRI, + .desc = { + BCM590XX_SR_DESC(SDSR1, sdsr1, dcdc_sdsr1_ranges), + }, + }, + + { + .type = BCM590XX_REG_TYPE_SR, + .regmap = BCM590XX_REG_REGMAP_PRI, + .desc = { + BCM590XX_SR_DESC(SDSR2, sdsr2, dcdc_iosr1_ranges), + }, + }, + + { + .type = BCM590XX_REG_TYPE_SR, + .regmap = BCM590XX_REG_REGMAP_PRI, + .desc = { + BCM590XX_SR_DESC(VSR, vsr, dcdc_iosr1_ranges), + }, + }, + + { + .type = BCM590XX_REG_TYPE_GPLDO, + .regmap = BCM590XX_REG_REGMAP_SEC, + .desc = { + BCM590XX_LDO_DESC(GPLDO1, gpldo1, ldo_a_table), + }, + }, + + { + .type = BCM590XX_REG_TYPE_GPLDO, + .regmap = BCM590XX_REG_REGMAP_SEC, + .desc = { + BCM590XX_LDO_DESC(GPLDO2, gpldo2, ldo_a_table), + }, + }, + + { + .type = BCM590XX_REG_TYPE_GPLDO, + .regmap = BCM590XX_REG_REGMAP_SEC, + .desc = { + BCM590XX_LDO_DESC(GPLDO3, gpldo3, ldo_a_table), + }, + }, + + { + .type = BCM590XX_REG_TYPE_GPLDO, + .regmap = BCM590XX_REG_REGMAP_SEC, + .desc = { + BCM590XX_LDO_DESC(GPLDO4, gpldo4, ldo_a_table), + }, + }, + + { + .type = BCM590XX_REG_TYPE_GPLDO, + .regmap = BCM590XX_REG_REGMAP_SEC, + .desc = { + BCM590XX_LDO_DESC(GPLDO5, gpldo5, ldo_a_table), + }, + }, + + { + .type = BCM590XX_REG_TYPE_GPLDO, + .regmap = BCM590XX_REG_REGMAP_SEC, + .desc = { + BCM590XX_LDO_DESC(GPLDO6, gpldo6, ldo_a_table), + }, + }, + + { + .type = BCM590XX_REG_TYPE_VBUS, + .regmap = BCM590XX_REG_REGMAP_SEC, + .desc = { + BCM590XX_REG_DESC(VBUS, vbus), + .ops = &bcm590xx_ops_vbus, + .n_voltages = 1, + .fixed_uV = 5000000, + .enable_reg = BCM590XX_OTG_CTRL, + .enable_mask = BCM590XX_VBUS_ENABLE, + }, + }, +}; + static int bcm590xx_probe(struct platform_device *pdev) { struct bcm590xx *bcm590xx = dev_get_drvdata(pdev->dev.parent); struct bcm590xx_reg *pmu; + const struct bcm590xx_reg_info *info; struct regulator_config config = { }; - struct bcm590xx_info *info; struct regulator_dev *rdev; - int i; + unsigned int i; pmu = devm_kzalloc(&pdev->dev, sizeof(*pmu), GFP_KERNEL); if (!pmu) return -ENOMEM; pmu->mfd = bcm590xx; + pmu->n_regulators = BCM590XX_NUM_REGS; + pmu->regs = bcm590xx_regs; platform_set_drvdata(pdev, pmu); - pmu->desc = devm_kcalloc(&pdev->dev, - BCM590XX_NUM_REGS, - sizeof(struct regulator_desc), - GFP_KERNEL); - if (!pmu->desc) - return -ENOMEM; - - info = bcm590xx_regs; - - for (i = 0; i < BCM590XX_NUM_REGS; i++, info++) { - /* Register the regulators */ - pmu->desc[i].name = info->name; - pmu->desc[i].of_match = of_match_ptr(info->name); - pmu->desc[i].regulators_node = of_match_ptr("regulators"); - pmu->desc[i].supply_name = info->vin_name; - pmu->desc[i].id = i; - pmu->desc[i].volt_table = info->volt_table; - pmu->desc[i].n_voltages = info->n_voltages; - pmu->desc[i].linear_ranges = info->linear_ranges; - pmu->desc[i].n_linear_ranges = info->n_linear_ranges; - - if ((BCM590XX_REG_IS_LDO(i)) || (BCM590XX_REG_IS_GPLDO(i))) { - pmu->desc[i].ops = &bcm590xx_ops_ldo; - pmu->desc[i].vsel_mask = BCM590XX_LDO_VSEL_MASK; - } else if (BCM590XX_REG_IS_VBUS(i)) - pmu->desc[i].ops = &bcm590xx_ops_vbus; - else { - pmu->desc[i].ops = &bcm590xx_ops_dcdc; - pmu->desc[i].vsel_mask = BCM590XX_SR_VSEL_MASK; - } - - if (BCM590XX_REG_IS_VBUS(i)) - pmu->desc[i].enable_mask = BCM590XX_VBUS_ENABLE; - else { - pmu->desc[i].vsel_reg = bcm590xx_get_vsel_register(i); - pmu->desc[i].enable_is_inverted = true; - pmu->desc[i].enable_mask = BCM590XX_REG_ENABLE; - } - pmu->desc[i].enable_reg = bcm590xx_get_enable_register(i); - pmu->desc[i].type = REGULATOR_VOLTAGE; - pmu->desc[i].owner = THIS_MODULE; + /* Register the regulators */ + for (i = 0; i < pmu->n_regulators; i++) { + info = &pmu->regs[i]; config.dev = bcm590xx->dev; config.driver_data = pmu; - if (BCM590XX_REG_IS_GPLDO(i) || BCM590XX_REG_IS_VBUS(i)) - config.regmap = bcm590xx->regmap_sec; - else + if (info->regmap == BCM590XX_REG_REGMAP_PRI) { config.regmap = bcm590xx->regmap_pri; + } else if (info->regmap == BCM590XX_REG_REGMAP_SEC) { + config.regmap = bcm590xx->regmap_sec; + } else { + dev_err(bcm590xx->dev, + "invalid regmap for %s regulator\n", + pdev->name); + return PTR_ERR(rdev); + } - rdev = devm_regulator_register(&pdev->dev, &pmu->desc[i], + rdev = devm_regulator_register(&pdev->dev, &info->desc, &config); if (IS_ERR(rdev)) { dev_err(bcm590xx->dev, -- 2.48.1