@@ -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,
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@gmail.com> --- Changes in v3: - Added this commit --- drivers/regulator/bcm590xx-regulator.c | 472 ++++++++++++++++++++++----------- 1 file changed, 316 insertions(+), 156 deletions(-)