regulator: Convert anatop to use a struct to pass in regulator runtime configuration
[firefly-linux-kernel-4.4.55.git] / drivers / regulator / s5m8767.c
index 58447db15de14c15ebc30cd24c62c1ad42a11e4f..cb53187a60d3f89b4e1a5a4cb6480f86bd0d9b06 100644 (file)
@@ -28,6 +28,7 @@ struct s5m8767_info {
        struct s5m87xx_dev *iodev;
        int num_regulators;
        struct regulator_dev **rdev;
+       struct s5m_opmode_data *opmode;
 
        int ramp_delay;
        bool buck2_ramp;
@@ -141,9 +142,56 @@ static int s5m8767_list_voltage(struct regulator_dev *rdev,
        return val;
 }
 
-static int s5m8767_get_register(struct regulator_dev *rdev, int *reg)
+unsigned int s5m8767_opmode_reg[][4] = {
+       /* {OFF, ON, LOWPOWER, SUSPEND} */
+       /* LDO1 ... LDO28 */
+       {0x0, 0x3, 0x2, 0x1}, /* LDO1 */
+       {0x0, 0x3, 0x2, 0x1},
+       {0x0, 0x3, 0x2, 0x1},
+       {0x0, 0x0, 0x0, 0x0},
+       {0x0, 0x3, 0x2, 0x1}, /* LDO5 */
+       {0x0, 0x3, 0x2, 0x1},
+       {0x0, 0x3, 0x2, 0x1},
+       {0x0, 0x3, 0x2, 0x1},
+       {0x0, 0x3, 0x2, 0x1},
+       {0x0, 0x3, 0x2, 0x1}, /* LDO10 */
+       {0x0, 0x3, 0x2, 0x1},
+       {0x0, 0x3, 0x2, 0x1},
+       {0x0, 0x3, 0x2, 0x1},
+       {0x0, 0x3, 0x2, 0x1},
+       {0x0, 0x3, 0x2, 0x1}, /* LDO15 */
+       {0x0, 0x3, 0x2, 0x1},
+       {0x0, 0x3, 0x2, 0x1},
+       {0x0, 0x0, 0x0, 0x0},
+       {0x0, 0x3, 0x2, 0x1},
+       {0x0, 0x3, 0x2, 0x1}, /* LDO20 */
+       {0x0, 0x3, 0x2, 0x1},
+       {0x0, 0x3, 0x2, 0x1},
+       {0x0, 0x0, 0x0, 0x0},
+       {0x0, 0x3, 0x2, 0x1},
+       {0x0, 0x3, 0x2, 0x1}, /* LDO25 */
+       {0x0, 0x3, 0x2, 0x1},
+       {0x0, 0x3, 0x2, 0x1},
+       {0x0, 0x3, 0x2, 0x1}, /* LDO28 */
+
+       /* BUCK1 ... BUCK9 */
+       {0x0, 0x3, 0x1, 0x1}, /* BUCK1 */
+       {0x0, 0x3, 0x1, 0x1},
+       {0x0, 0x3, 0x1, 0x1},
+       {0x0, 0x3, 0x1, 0x1},
+       {0x0, 0x3, 0x2, 0x1}, /* BUCK5 */
+       {0x0, 0x3, 0x1, 0x1},
+       {0x0, 0x3, 0x1, 0x1},
+       {0x0, 0x3, 0x1, 0x1},
+       {0x0, 0x3, 0x1, 0x1}, /* BUCK9 */
+};
+
+static int s5m8767_get_register(struct regulator_dev *rdev, int *reg,
+                               int *enable_ctrl)
 {
        int reg_id = rdev_get_id(rdev);
+       unsigned int mode;
+       struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
 
        switch (reg_id) {
        case S5M8767_LDO1 ... S5M8767_LDO2:
@@ -168,6 +216,8 @@ static int s5m8767_get_register(struct regulator_dev *rdev, int *reg)
                return -EINVAL;
        }
 
+       mode = s5m8767->opmode[reg_id].mode;
+       *enable_ctrl = s5m8767_opmode_reg[reg_id][mode] << S5M8767_ENCTRL_SHIFT;
        return 0;
 }
 
@@ -175,10 +225,10 @@ static int s5m8767_reg_is_enabled(struct regulator_dev *rdev)
 {
        struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
        int ret, reg;
-       int mask = 0xc0, pattern = 0xc0;
+       int mask = 0xc0, enable_ctrl;
        u8 val;
 
-       ret = s5m8767_get_register(rdev, &reg);
+       ret = s5m8767_get_register(rdev, &reg, &enable_ctrl);
        if (ret == -EINVAL)
                return 1;
        else if (ret)
@@ -188,33 +238,33 @@ static int s5m8767_reg_is_enabled(struct regulator_dev *rdev)
        if (ret)
                return ret;
 
-       return (val & mask) == pattern;
+       return (val & mask) == enable_ctrl;
 }
 
 static int s5m8767_reg_enable(struct regulator_dev *rdev)
 {
        struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
        int ret, reg;
-       int mask = 0xc0, pattern = 0xc0;
+       int mask = 0xc0, enable_ctrl;
 
-       ret = s5m8767_get_register(rdev, &reg);
+       ret = s5m8767_get_register(rdev, &reg, &enable_ctrl);
        if (ret)
                return ret;
 
-       return s5m_reg_update(s5m8767->iodev, reg, pattern, mask);
+       return s5m_reg_update(s5m8767->iodev, reg, enable_ctrl, mask);
 }
 
 static int s5m8767_reg_disable(struct regulator_dev *rdev)
 {
        struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
        int ret, reg;
-       int  mask = 0xc0, pattern = 0xc0;
+       int  mask = 0xc0, enable_ctrl;
 
-       ret = s5m8767_get_register(rdev, &reg);
+       ret = s5m8767_get_register(rdev, &reg, &enable_ctrl);
        if (ret)
                return ret;
 
-       return s5m_reg_update(s5m8767->iodev, reg, ~pattern, mask);
+       return s5m_reg_update(s5m8767->iodev, reg, ~mask, mask);
 }
 
 static int s5m8767_get_voltage_register(struct regulator_dev *rdev, int *_reg)
@@ -305,51 +355,6 @@ static int s5m8767_convert_voltage_to_sel(
        return selector;
 }
 
-static int s5m8767_set_voltage(struct regulator_dev *rdev,
-                               int min_uV, int max_uV, unsigned *selector)
-{
-       struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
-       const struct s5m_voltage_desc *desc;
-       int reg_id = rdev_get_id(rdev);
-       int reg, mask, ret;
-       int i;
-       u8 val;
-
-       switch (reg_id) {
-       case S5M8767_LDO1 ... S5M8767_LDO28:
-               mask = 0x3f;
-               break;
-       case S5M8767_BUCK1 ... S5M8767_BUCK6:
-               mask = 0xff;
-               break;
-       case S5M8767_BUCK7 ... S5M8767_BUCK8:
-               return -EINVAL;
-       case S5M8767_BUCK9:
-               mask = 0xff;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       desc = reg_voltage_map[reg_id];
-
-       i = s5m8767_convert_voltage_to_sel(desc, min_uV, max_uV);
-       if (i < 0)
-               return i;
-
-       ret = s5m8767_get_voltage_register(rdev, &reg);
-       if (ret)
-               return ret;
-
-       s5m_reg_read(s5m8767->iodev, reg, &val);
-       val = val & mask;
-
-       ret = s5m_reg_write(s5m8767->iodev, reg, val);
-       *selector = i;
-
-       return ret;
-}
-
 static inline void s5m8767_set_high(struct s5m8767_info *s5m8767)
 {
        int temp_index = s5m8767->buck_gpioindex;
@@ -368,70 +373,70 @@ static inline void s5m8767_set_low(struct s5m8767_info *s5m8767)
        gpio_set_value(s5m8767->buck_gpios[0], (temp_index >> 2) & 0x1);
 }
 
-static int s5m8767_set_voltage_buck(struct regulator_dev *rdev,
-                                   int min_uV, int max_uV, unsigned *selector)
+static int s5m8767_set_voltage(struct regulator_dev *rdev,
+                               int min_uV, int max_uV, unsigned *selector)
 {
        struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
-       int reg_id = rdev_get_id(rdev);
        const struct s5m_voltage_desc *desc;
-       int new_val, old_val, i = 0;
-
-       if (reg_id < S5M8767_BUCK1 || reg_id > S5M8767_BUCK6)
-               return -EINVAL;
+       int reg_id = rdev_get_id(rdev);
+       int sel, reg, mask, ret = 0, old_index, index = 0;
+       u8 val;
+       u8 *buck234_vol = NULL;
 
        switch (reg_id) {
-       case S5M8767_BUCK1:
-               return s5m8767_set_voltage(rdev, min_uV, max_uV, selector);
-       case S5M8767_BUCK2 ... S5M8767_BUCK4:
+       case S5M8767_LDO1 ... S5M8767_LDO28:
+               mask = 0x3f;
+               break;
+       case S5M8767_BUCK1 ... S5M8767_BUCK6:
+               mask = 0xff;
+               if (reg_id == S5M8767_BUCK2 && s5m8767->buck2_gpiodvs)
+                       buck234_vol = &s5m8767->buck2_vol[0];
+               else if (reg_id == S5M8767_BUCK3 && s5m8767->buck3_gpiodvs)
+                       buck234_vol = &s5m8767->buck3_vol[0];
+               else if (reg_id == S5M8767_BUCK4 && s5m8767->buck4_gpiodvs)
+                       buck234_vol = &s5m8767->buck4_vol[0];
                break;
-       case S5M8767_BUCK5 ... S5M8767_BUCK6:
-               return s5m8767_set_voltage(rdev, min_uV, max_uV, selector);
+       case S5M8767_BUCK7 ... S5M8767_BUCK8:
+               return -EINVAL;
        case S5M8767_BUCK9:
-               return s5m8767_set_voltage(rdev, min_uV, max_uV, selector);
+               mask = 0xff;
+               break;
+       default:
+               return -EINVAL;
        }
 
        desc = reg_voltage_map[reg_id];
-       new_val = s5m8767_convert_voltage_to_sel(desc, min_uV, max_uV);
-       if (new_val < 0)
-               return new_val;
 
-       switch (reg_id) {
-       case S5M8767_BUCK2:
-               if (s5m8767->buck2_gpiodvs) {
-                       while (s5m8767->buck2_vol[i] != new_val)
-                               i++;
-               } else
-                       return s5m8767_set_voltage(rdev, min_uV,
-                                                  max_uV, selector);
-               break;
-       case S5M8767_BUCK3:
-               if (s5m8767->buck3_gpiodvs) {
-                       while (s5m8767->buck3_vol[i] != new_val)
-                               i++;
-               } else
-                       return s5m8767_set_voltage(rdev, min_uV,
-                                                  max_uV, selector);
-               break;
-       case S5M8767_BUCK4:
-               if (s5m8767->buck3_gpiodvs) {
-                       while (s5m8767->buck4_vol[i] != new_val)
-                               i++;
-               } else
-                       return s5m8767_set_voltage(rdev, min_uV,
-                                                  max_uV, selector);
-               break;
-       }
+       sel = s5m8767_convert_voltage_to_sel(desc, min_uV, max_uV);
+       if (sel < 0)
+               return sel;
 
-       old_val = s5m8767->buck_gpioindex;
-       s5m8767->buck_gpioindex = i;
+       /* buck234_vol != NULL means to control buck234 voltage via DVS GPIO */
+       if (buck234_vol) {
+               while (*buck234_vol != sel) {
+                       buck234_vol++;
+                       index++;
+               }
+               old_index = s5m8767->buck_gpioindex;
+               s5m8767->buck_gpioindex = index;
+
+               if (index > old_index)
+                       s5m8767_set_high(s5m8767);
+               else
+                       s5m8767_set_low(s5m8767);
+       } else {
+               ret = s5m8767_get_voltage_register(rdev, &reg);
+               if (ret)
+                       return ret;
 
-       if (i > old_val)
-               s5m8767_set_high(s5m8767);
-       else
-               s5m8767_set_low(s5m8767);
+               s5m_reg_read(s5m8767->iodev, reg, &val);
+               val = (val & ~mask) | sel;
 
-       *selector = new_val;
-       return 0;
+               ret = s5m_reg_write(s5m8767->iodev, reg, val);
+       }
+
+       *selector = sel;
+       return ret;
 }
 
 static int s5m8767_set_voltage_time_sel(struct regulator_dev *rdev,
@@ -450,7 +455,7 @@ static int s5m8767_set_voltage_time_sel(struct regulator_dev *rdev,
        return 0;
 }
 
-static struct regulator_ops s5m8767_ldo_ops = {
+static struct regulator_ops s5m8767_ops = {
        .list_voltage           = s5m8767_list_voltage,
        .is_enabled             = s5m8767_reg_is_enabled,
        .enable                 = s5m8767_reg_enable,
@@ -460,75 +465,59 @@ static struct regulator_ops s5m8767_ldo_ops = {
        .set_voltage_time_sel   = s5m8767_set_voltage_time_sel,
 };
 
-static struct regulator_ops s5m8767_buck_ops = {
-       .list_voltage           = s5m8767_list_voltage,
-       .is_enabled             = s5m8767_reg_is_enabled,
-       .enable                 = s5m8767_reg_enable,
-       .disable                = s5m8767_reg_disable,
-       .get_voltage_sel        = s5m8767_get_voltage_sel,
-       .set_voltage            = s5m8767_set_voltage_buck,
-       .set_voltage_time_sel   = s5m8767_set_voltage_time_sel,
-};
-
-#define regulator_desc_ldo(num)                {       \
-       .name           = "LDO"#num,            \
-       .id             = S5M8767_LDO##num,     \
-       .ops            = &s5m8767_ldo_ops,     \
-       .type           = REGULATOR_VOLTAGE,    \
-       .owner          = THIS_MODULE,          \
-}
-#define regulator_desc_buck(num)       {       \
-       .name           = "BUCK"#num,           \
-       .id             = S5M8767_BUCK##num,    \
-       .ops            = &s5m8767_buck_ops,    \
+#define s5m8767_regulator_desc(_name) {                \
+       .name           = #_name,               \
+       .id             = S5M8767_##_name,      \
+       .ops            = &s5m8767_ops,         \
        .type           = REGULATOR_VOLTAGE,    \
        .owner          = THIS_MODULE,          \
 }
 
 static struct regulator_desc regulators[] = {
-       regulator_desc_ldo(1),
-       regulator_desc_ldo(2),
-       regulator_desc_ldo(3),
-       regulator_desc_ldo(4),
-       regulator_desc_ldo(5),
-       regulator_desc_ldo(6),
-       regulator_desc_ldo(7),
-       regulator_desc_ldo(8),
-       regulator_desc_ldo(9),
-       regulator_desc_ldo(10),
-       regulator_desc_ldo(11),
-       regulator_desc_ldo(12),
-       regulator_desc_ldo(13),
-       regulator_desc_ldo(14),
-       regulator_desc_ldo(15),
-       regulator_desc_ldo(16),
-       regulator_desc_ldo(17),
-       regulator_desc_ldo(18),
-       regulator_desc_ldo(19),
-       regulator_desc_ldo(20),
-       regulator_desc_ldo(21),
-       regulator_desc_ldo(22),
-       regulator_desc_ldo(23),
-       regulator_desc_ldo(24),
-       regulator_desc_ldo(25),
-       regulator_desc_ldo(26),
-       regulator_desc_ldo(27),
-       regulator_desc_ldo(28),
-       regulator_desc_buck(1),
-       regulator_desc_buck(2),
-       regulator_desc_buck(3),
-       regulator_desc_buck(4),
-       regulator_desc_buck(5),
-       regulator_desc_buck(6),
-       regulator_desc_buck(7),
-       regulator_desc_buck(8),
-       regulator_desc_buck(9),
+       s5m8767_regulator_desc(LDO1),
+       s5m8767_regulator_desc(LDO2),
+       s5m8767_regulator_desc(LDO3),
+       s5m8767_regulator_desc(LDO4),
+       s5m8767_regulator_desc(LDO5),
+       s5m8767_regulator_desc(LDO6),
+       s5m8767_regulator_desc(LDO7),
+       s5m8767_regulator_desc(LDO8),
+       s5m8767_regulator_desc(LDO9),
+       s5m8767_regulator_desc(LDO10),
+       s5m8767_regulator_desc(LDO11),
+       s5m8767_regulator_desc(LDO12),
+       s5m8767_regulator_desc(LDO13),
+       s5m8767_regulator_desc(LDO14),
+       s5m8767_regulator_desc(LDO15),
+       s5m8767_regulator_desc(LDO16),
+       s5m8767_regulator_desc(LDO17),
+       s5m8767_regulator_desc(LDO18),
+       s5m8767_regulator_desc(LDO19),
+       s5m8767_regulator_desc(LDO20),
+       s5m8767_regulator_desc(LDO21),
+       s5m8767_regulator_desc(LDO22),
+       s5m8767_regulator_desc(LDO23),
+       s5m8767_regulator_desc(LDO24),
+       s5m8767_regulator_desc(LDO25),
+       s5m8767_regulator_desc(LDO26),
+       s5m8767_regulator_desc(LDO27),
+       s5m8767_regulator_desc(LDO28),
+       s5m8767_regulator_desc(BUCK1),
+       s5m8767_regulator_desc(BUCK2),
+       s5m8767_regulator_desc(BUCK3),
+       s5m8767_regulator_desc(BUCK4),
+       s5m8767_regulator_desc(BUCK5),
+       s5m8767_regulator_desc(BUCK6),
+       s5m8767_regulator_desc(BUCK7),
+       s5m8767_regulator_desc(BUCK8),
+       s5m8767_regulator_desc(BUCK9),
 };
 
 static __devinit int s5m8767_pmic_probe(struct platform_device *pdev)
 {
        struct s5m87xx_dev *iodev = dev_get_drvdata(pdev->dev.parent);
        struct s5m_platform_data *pdata = dev_get_platdata(iodev->dev);
+       struct regulator_config config = { };
        struct regulator_dev **rdev;
        struct s5m8767_info *s5m8767;
        int i, ret, size;
@@ -586,6 +575,7 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev)
        s5m8767->buck2_ramp = pdata->buck2_ramp_enable;
        s5m8767->buck3_ramp = pdata->buck3_ramp_enable;
        s5m8767->buck4_ramp = pdata->buck4_ramp_enable;
+       s5m8767->opmode = pdata->opmode;
 
        for (i = 0; i < 8; i++) {
                if (s5m8767->buck2_gpiodvs) {
@@ -723,8 +713,11 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev)
                        regulators[id].n_voltages =
                                (desc->max - desc->min) / desc->step + 1;
 
-               rdev[i] = regulator_register(&regulators[id], s5m8767->dev,
-                               pdata->regulators[i].initdata, s5m8767, NULL);
+               config.dev = s5m8767->dev;
+               config.init_data = pdata->regulators[i].initdata;
+               config.driver_data = s5m8767;
+
+               rdev[i] = regulator_register(&regulators[id], &config);
                if (IS_ERR(rdev[i])) {
                        ret = PTR_ERR(rdev[i]);
                        dev_err(s5m8767->dev, "regulator init failed for %d\n",