Merge tag 'backlight-for-linus-3.17' of git://git.kernel.org/pub/scm/linux/kernel...
[cascardo/linux.git] / drivers / regulator / act8865-regulator.c
index b92d7dd..afd06f9 100644 (file)
@@ -1,6 +1,7 @@
 /*
- * act8865-regulator.c - Voltage regulation for the active-semi ACT8865
- * http://www.active-semi.com/sheets/ACT8865_Datasheet.pdf
+ * act8865-regulator.c - Voltage regulation for active-semi ACT88xx PMUs
+ *
+ * http://www.active-semi.com/products/power-management-units/act88xx/
  *
  * Copyright (C) 2013 Atmel Corporation
  *
 #include <linux/regulator/of_regulator.h>
 #include <linux/regmap.h>
 
+/*
+ * ACT8846 Global Register Map.
+ */
+#define        ACT8846_SYS0            0x00
+#define        ACT8846_SYS1            0x01
+#define        ACT8846_REG1_VSET       0x10
+#define        ACT8846_REG1_CTRL       0x12
+#define        ACT8846_REG2_VSET0      0x20
+#define        ACT8846_REG2_VSET1      0x21
+#define        ACT8846_REG2_CTRL       0x22
+#define        ACT8846_REG3_VSET0      0x30
+#define        ACT8846_REG3_VSET1      0x31
+#define        ACT8846_REG3_CTRL       0x32
+#define        ACT8846_REG4_VSET0      0x40
+#define        ACT8846_REG4_VSET1      0x41
+#define        ACT8846_REG4_CTRL       0x42
+#define        ACT8846_REG5_VSET       0x50
+#define        ACT8846_REG5_CTRL       0x51
+#define        ACT8846_REG6_VSET       0x58
+#define        ACT8846_REG6_CTRL       0x59
+#define        ACT8846_REG7_VSET       0x60
+#define        ACT8846_REG7_CTRL       0x61
+#define        ACT8846_REG8_VSET       0x68
+#define        ACT8846_REG8_CTRL       0x69
+#define        ACT8846_REG9_VSET       0x70
+#define        ACT8846_REG9_CTRL       0x71
+#define        ACT8846_REG10_VSET      0x80
+#define        ACT8846_REG10_CTRL      0x81
+#define        ACT8846_REG11_VSET      0x90
+#define        ACT8846_REG11_CTRL      0x91
+#define        ACT8846_REG12_VSET      0xa0
+#define        ACT8846_REG12_CTRL      0xa1
+#define        ACT8846_REG13_CTRL      0xb1
+
 /*
  * ACT8865 Global Register Map.
  */
@@ -70,7 +105,7 @@ static const struct regmap_config act8865_regmap_config = {
        .val_bits = 8,
 };
 
-static const struct regulator_linear_range act8865_volatge_ranges[] = {
+static const struct regulator_linear_range act8865_voltage_ranges[] = {
        REGULATOR_LINEAR_RANGE(600000, 0, 23, 25000),
        REGULATOR_LINEAR_RANGE(1200000, 24, 47, 50000),
        REGULATOR_LINEAR_RANGE(2400000, 48, 63, 100000),
@@ -86,114 +121,70 @@ static struct regulator_ops act8865_ops = {
        .is_enabled             = regulator_is_enabled_regmap,
 };
 
-static const struct regulator_desc act8865_reg[] = {
-       {
-               .name = "DCDC_REG1",
-               .id = ACT8865_ID_DCDC1,
-               .ops = &act8865_ops,
-               .type = REGULATOR_VOLTAGE,
-               .n_voltages = ACT8865_VOLTAGE_NUM,
-               .linear_ranges = act8865_volatge_ranges,
-               .n_linear_ranges = ARRAY_SIZE(act8865_volatge_ranges),
-               .vsel_reg = ACT8865_DCDC1_VSET1,
-               .vsel_mask = ACT8865_VSEL_MASK,
-               .enable_reg = ACT8865_DCDC1_CTRL,
-               .enable_mask = ACT8865_ENA,
-               .owner = THIS_MODULE,
-       },
-       {
-               .name = "DCDC_REG2",
-               .id = ACT8865_ID_DCDC2,
-               .ops = &act8865_ops,
-               .type = REGULATOR_VOLTAGE,
-               .n_voltages = ACT8865_VOLTAGE_NUM,
-               .linear_ranges = act8865_volatge_ranges,
-               .n_linear_ranges = ARRAY_SIZE(act8865_volatge_ranges),
-               .vsel_reg = ACT8865_DCDC2_VSET1,
-               .vsel_mask = ACT8865_VSEL_MASK,
-               .enable_reg = ACT8865_DCDC2_CTRL,
-               .enable_mask = ACT8865_ENA,
-               .owner = THIS_MODULE,
-       },
-       {
-               .name = "DCDC_REG3",
-               .id = ACT8865_ID_DCDC3,
-               .ops = &act8865_ops,
-               .type = REGULATOR_VOLTAGE,
-               .n_voltages = ACT8865_VOLTAGE_NUM,
-               .linear_ranges = act8865_volatge_ranges,
-               .n_linear_ranges = ARRAY_SIZE(act8865_volatge_ranges),
-               .vsel_reg = ACT8865_DCDC3_VSET1,
-               .vsel_mask = ACT8865_VSEL_MASK,
-               .enable_reg = ACT8865_DCDC3_CTRL,
-               .enable_mask = ACT8865_ENA,
-               .owner = THIS_MODULE,
-       },
-       {
-               .name = "LDO_REG1",
-               .id = ACT8865_ID_LDO1,
-               .ops = &act8865_ops,
-               .type = REGULATOR_VOLTAGE,
-               .n_voltages = ACT8865_VOLTAGE_NUM,
-               .linear_ranges = act8865_volatge_ranges,
-               .n_linear_ranges = ARRAY_SIZE(act8865_volatge_ranges),
-               .vsel_reg = ACT8865_LDO1_VSET,
-               .vsel_mask = ACT8865_VSEL_MASK,
-               .enable_reg = ACT8865_LDO1_CTRL,
-               .enable_mask = ACT8865_ENA,
-               .owner = THIS_MODULE,
-       },
-       {
-               .name = "LDO_REG2",
-               .id = ACT8865_ID_LDO2,
-               .ops = &act8865_ops,
-               .type = REGULATOR_VOLTAGE,
-               .n_voltages = ACT8865_VOLTAGE_NUM,
-               .linear_ranges = act8865_volatge_ranges,
-               .n_linear_ranges = ARRAY_SIZE(act8865_volatge_ranges),
-               .vsel_reg = ACT8865_LDO2_VSET,
-               .vsel_mask = ACT8865_VSEL_MASK,
-               .enable_reg = ACT8865_LDO2_CTRL,
-               .enable_mask = ACT8865_ENA,
-               .owner = THIS_MODULE,
-       },
-       {
-               .name = "LDO_REG3",
-               .id = ACT8865_ID_LDO3,
-               .ops = &act8865_ops,
-               .type = REGULATOR_VOLTAGE,
-               .n_voltages = ACT8865_VOLTAGE_NUM,
-               .linear_ranges = act8865_volatge_ranges,
-               .n_linear_ranges = ARRAY_SIZE(act8865_volatge_ranges),
-               .vsel_reg = ACT8865_LDO3_VSET,
-               .vsel_mask = ACT8865_VSEL_MASK,
-               .enable_reg = ACT8865_LDO3_CTRL,
-               .enable_mask = ACT8865_ENA,
-               .owner = THIS_MODULE,
-       },
-       {
-               .name = "LDO_REG4",
-               .id = ACT8865_ID_LDO4,
-               .ops = &act8865_ops,
-               .type = REGULATOR_VOLTAGE,
-               .n_voltages = ACT8865_VOLTAGE_NUM,
-               .linear_ranges = act8865_volatge_ranges,
-               .n_linear_ranges = ARRAY_SIZE(act8865_volatge_ranges),
-               .vsel_reg = ACT8865_LDO4_VSET,
-               .vsel_mask = ACT8865_VSEL_MASK,
-               .enable_reg = ACT8865_LDO4_CTRL,
-               .enable_mask = ACT8865_ENA,
-               .owner = THIS_MODULE,
-       },
+#define ACT88xx_REG(_name, _family, _id, _vsel_reg)                    \
+       [_family##_ID_##_id] = {                                        \
+               .name                   = _name,                        \
+               .id                     = _family##_ID_##_id,           \
+               .type                   = REGULATOR_VOLTAGE,            \
+               .ops                    = &act8865_ops,                 \
+               .n_voltages             = ACT8865_VOLTAGE_NUM,          \
+               .linear_ranges          = act8865_voltage_ranges,       \
+               .n_linear_ranges        = ARRAY_SIZE(act8865_voltage_ranges), \
+               .vsel_reg               = _family##_##_id##_##_vsel_reg, \
+               .vsel_mask              = ACT8865_VSEL_MASK,            \
+               .enable_reg             = _family##_##_id##_CTRL,       \
+               .enable_mask            = ACT8865_ENA,                  \
+               .owner                  = THIS_MODULE,                  \
+       }
+
+static const struct regulator_desc act8846_regulators[] = {
+       ACT88xx_REG("REG1", ACT8846, REG1, VSET),
+       ACT88xx_REG("REG2", ACT8846, REG2, VSET0),
+       ACT88xx_REG("REG3", ACT8846, REG3, VSET0),
+       ACT88xx_REG("REG4", ACT8846, REG4, VSET0),
+       ACT88xx_REG("REG5", ACT8846, REG5, VSET),
+       ACT88xx_REG("REG6", ACT8846, REG6, VSET),
+       ACT88xx_REG("REG7", ACT8846, REG7, VSET),
+       ACT88xx_REG("REG8", ACT8846, REG8, VSET),
+       ACT88xx_REG("REG9", ACT8846, REG9, VSET),
+       ACT88xx_REG("REG10", ACT8846, REG10, VSET),
+       ACT88xx_REG("REG11", ACT8846, REG11, VSET),
+       ACT88xx_REG("REG12", ACT8846, REG12, VSET),
+};
+
+static const struct regulator_desc act8865_regulators[] = {
+       ACT88xx_REG("DCDC_REG1", ACT8865, DCDC1, VSET1),
+       ACT88xx_REG("DCDC_REG2", ACT8865, DCDC2, VSET1),
+       ACT88xx_REG("DCDC_REG3", ACT8865, DCDC3, VSET1),
+       ACT88xx_REG("LDO_REG1", ACT8865, LDO1, VSET),
+       ACT88xx_REG("LDO_REG2", ACT8865, LDO2, VSET),
+       ACT88xx_REG("LDO_REG3", ACT8865, LDO3, VSET),
+       ACT88xx_REG("LDO_REG4", ACT8865, LDO4, VSET),
 };
 
 #ifdef CONFIG_OF
 static const struct of_device_id act8865_dt_ids[] = {
-       { .compatible = "active-semi,act8865" },
+       { .compatible = "active-semi,act8846", .data = (void *)ACT8846 },
+       { .compatible = "active-semi,act8865", .data = (void *)ACT8865 },
        { }
 };
 MODULE_DEVICE_TABLE(of, act8865_dt_ids);
 
+static struct of_regulator_match act8846_matches[] = {
+       [ACT8846_ID_REG1]       = { .name = "REG1" },
+       [ACT8846_ID_REG2]       = { .name = "REG2" },
+       [ACT8846_ID_REG3]       = { .name = "REG3" },
+       [ACT8846_ID_REG4]       = { .name = "REG4" },
+       [ACT8846_ID_REG5]       = { .name = "REG5" },
+       [ACT8846_ID_REG6]       = { .name = "REG6" },
+       [ACT8846_ID_REG7]       = { .name = "REG7" },
+       [ACT8846_ID_REG8]       = { .name = "REG8" },
+       [ACT8846_ID_REG9]       = { .name = "REG9" },
+       [ACT8846_ID_REG10]      = { .name = "REG10" },
+       [ACT8846_ID_REG11]      = { .name = "REG11" },
+       [ACT8846_ID_REG12]      = { .name = "REG12" },
+};
+
 static struct of_regulator_match act8865_matches[] = {
        [ACT8865_ID_DCDC1]      = { .name = "DCDC_REG1"},
        [ACT8865_ID_DCDC2]      = { .name = "DCDC_REG2"},
@@ -206,11 +197,13 @@ static struct of_regulator_match act8865_matches[] = {
 
 static int act8865_pdata_from_dt(struct device *dev,
                                 struct device_node **of_node,
-                                struct act8865_platform_data *pdata)
+                                struct act8865_platform_data *pdata,
+                                unsigned long type)
 {
-       int matched, i;
+       int matched, i, num_matches;
        struct device_node *np;
        struct act8865_regulator_data *regulator;
+       struct of_regulator_match *matches;
 
        np = of_get_child_by_name(dev->of_node, "regulators");
        if (!np) {
@@ -218,26 +211,39 @@ static int act8865_pdata_from_dt(struct device *dev,
                return -EINVAL;
        }
 
-       matched = of_regulator_match(dev, np,
-                               act8865_matches, ARRAY_SIZE(act8865_matches));
+       switch (type) {
+       case ACT8846:
+               matches = act8846_matches;
+               num_matches = ARRAY_SIZE(act8846_matches);
+               break;
+       case ACT8865:
+               matches = act8865_matches;
+               num_matches = ARRAY_SIZE(act8865_matches);
+               break;
+       default:
+               dev_err(dev, "invalid device id %lu\n", type);
+               return -EINVAL;
+       }
+
+       matched = of_regulator_match(dev, np, matches, num_matches);
        of_node_put(np);
        if (matched <= 0)
                return matched;
 
        pdata->regulators = devm_kzalloc(dev,
-                               sizeof(struct act8865_regulator_data) *
-                               ARRAY_SIZE(act8865_matches), GFP_KERNEL);
+                                        sizeof(struct act8865_regulator_data) *
+                                        num_matches, GFP_KERNEL);
        if (!pdata->regulators)
                return -ENOMEM;
 
-       pdata->num_regulators = matched;
+       pdata->num_regulators = num_matches;
        regulator = pdata->regulators;
 
-       for (i = 0; i < ARRAY_SIZE(act8865_matches); i++) {
+       for (i = 0; i < num_matches; i++) {
                regulator->id = i;
-               regulator->name = act8865_matches[i].name;
-               regulator->platform_data = act8865_matches[i].init_data;
-               of_node[i] = act8865_matches[i].of_node;
+               regulator->name = matches[i].name;
+               regulator->platform_data = matches[i].init_data;
+               of_node[i] = matches[i].of_node;
                regulator++;
        }
 
@@ -246,42 +252,84 @@ static int act8865_pdata_from_dt(struct device *dev,
 #else
 static inline int act8865_pdata_from_dt(struct device *dev,
                                        struct device_node **of_node,
-                                       struct act8865_platform_data *pdata)
+                                       struct act8865_platform_data *pdata,
+                                       unsigned long type)
 {
        return 0;
 }
 #endif
 
+static struct regulator_init_data
+*act8865_get_init_data(int id, struct act8865_platform_data *pdata)
+{
+       int i;
+
+       if (!pdata)
+               return NULL;
+
+       for (i = 0; i < pdata->num_regulators; i++) {
+               if (pdata->regulators[i].id == id)
+                       return pdata->regulators[i].platform_data;
+       }
+
+       return NULL;
+}
+
 static int act8865_pmic_probe(struct i2c_client *client,
-                          const struct i2c_device_id *i2c_id)
+                             const struct i2c_device_id *i2c_id)
 {
-       struct regulator_dev *rdev;
+       static const struct regulator_desc *regulators;
+       struct act8865_platform_data pdata_of, *pdata;
        struct device *dev = &client->dev;
-       struct act8865_platform_data *pdata = dev_get_platdata(dev);
-       struct regulator_config config = { };
+       struct device_node **of_node;
+       int i, ret, num_regulators;
        struct act8865 *act8865;
-       struct device_node *of_node[ACT8865_REG_NUM];
-       int i, id;
-       int ret = -EINVAL;
-       int error;
+       unsigned long type;
+
+       pdata = dev_get_platdata(dev);
 
        if (dev->of_node && !pdata) {
                const struct of_device_id *id;
-               struct act8865_platform_data pdata_of;
 
                id = of_match_device(of_match_ptr(act8865_dt_ids), dev);
                if (!id)
                        return -ENODEV;
 
-               ret = act8865_pdata_from_dt(dev, of_node, &pdata_of);
+               type = (unsigned long) id->data;
+       } else {
+               type = i2c_id->driver_data;
+       }
+
+       switch (type) {
+       case ACT8846:
+               regulators = act8846_regulators;
+               num_regulators = ARRAY_SIZE(act8846_regulators);
+               break;
+       case ACT8865:
+               regulators = act8865_regulators;
+               num_regulators = ARRAY_SIZE(act8865_regulators);
+               break;
+       default:
+               dev_err(dev, "invalid device id %lu\n", type);
+               return -EINVAL;
+       }
+
+       of_node = devm_kzalloc(dev, sizeof(struct device_node *) *
+                              num_regulators, GFP_KERNEL);
+       if (!of_node)
+               return -ENOMEM;
+
+       if (dev->of_node && !pdata) {
+               ret = act8865_pdata_from_dt(dev, of_node, &pdata_of, type);
                if (ret < 0)
                        return ret;
 
                pdata = &pdata_of;
        }
 
-       if (pdata->num_regulators > ACT8865_REG_NUM) {
-               dev_err(dev, "Too many regulators found!\n");
+       if (pdata->num_regulators > num_regulators) {
+               dev_err(dev, "too many regulators: %d\n",
+                       pdata->num_regulators);
                return -EINVAL;
        }
 
@@ -291,39 +339,40 @@ static int act8865_pmic_probe(struct i2c_client *client,
 
        act8865->regmap = devm_regmap_init_i2c(client, &act8865_regmap_config);
        if (IS_ERR(act8865->regmap)) {
-               error = PTR_ERR(act8865->regmap);
+               ret = PTR_ERR(act8865->regmap);
                dev_err(&client->dev, "Failed to allocate register map: %d\n",
-                       error);
-               return error;
+                       ret);
+               return ret;
        }
 
        /* Finally register devices */
-       for (i = 0; i < ACT8865_REG_NUM; i++) {
-
-               id = pdata->regulators[i].id;
+       for (i = 0; i < num_regulators; i++) {
+               const struct regulator_desc *desc = &regulators[i];
+               struct regulator_config config = { };
+               struct regulator_dev *rdev;
 
                config.dev = dev;
-               config.init_data = pdata->regulators[i].platform_data;
+               config.init_data = act8865_get_init_data(desc->id, pdata);
                config.of_node = of_node[i];
                config.driver_data = act8865;
                config.regmap = act8865->regmap;
 
-               rdev = devm_regulator_register(&client->dev, &act8865_reg[i],
-                                              &config);
+               rdev = devm_regulator_register(&client->dev, desc, &config);
                if (IS_ERR(rdev)) {
-                       dev_err(dev, "failed to register %s\n",
-                               act8865_reg[id].name);
+                       dev_err(dev, "failed to register %s\n", desc->name);
                        return PTR_ERR(rdev);
                }
        }
 
        i2c_set_clientdata(client, act8865);
+       devm_kfree(dev, of_node);
 
        return 0;
 }
 
 static const struct i2c_device_id act8865_ids[] = {
-       { "act8865", 0 },
+       { .name = "act8846", .driver_data = ACT8846 },
+       { .name = "act8865", .driver_data = ACT8865 },
        { },
 };
 MODULE_DEVICE_TABLE(i2c, act8865_ids);
@@ -339,6 +388,6 @@ static struct i2c_driver act8865_pmic_driver = {
 
 module_i2c_driver(act8865_pmic_driver);
 
-MODULE_DESCRIPTION("active-semi act8865 voltage regulator driver");
+MODULE_DESCRIPTION("active-semi act88xx voltage regulator driver");
 MODULE_AUTHOR("Wenyou Yang <wenyou.yang@atmel.com>");
 MODULE_LICENSE("GPL v2");