]> Pileus Git - ~andy/linux/commitdiff
Merge remote-tracking branch 'regulator/topic/palmas' into v3.9-rc8
authorMark Brown <broonie@sirena.org.uk>
Sun, 28 Apr 2013 01:13:45 +0000 (02:13 +0100)
committerMark Brown <broonie@sirena.org.uk>
Sun, 28 Apr 2013 01:13:45 +0000 (02:13 +0100)
1  2 
drivers/regulator/palmas-regulator.c
include/linux/mfd/palmas.h

index 39cf14606784bd3571c6aab2d361807d0bdf7c99,1be9c3216974fed7683531337311f79a3fd7fdaa..92ceed0fc65e780216861143c8ccc25f9c16fa53
@@@ -1,10 -1,9 +1,10 @@@
  /*
   * Driver for Regulator part of Palmas PMIC Chips
   *
-  * Copyright 2011-2012 Texas Instruments Inc.
+  * Copyright 2011-2013 Texas Instruments Inc.
   *
   * Author: Graeme Gregory <gg@slimlogic.co.uk>
 + * Author: Ian Lartey <ian@slimlogic.co.uk>
   *
   *  This program is free software; you can redistribute it and/or modify it
   *  under  the terms of the GNU General  Public License as published by the
@@@ -29,6 -28,7 +29,7 @@@
  
  struct regs_info {
        char    *name;
+       char    *sname;
        u8      vsel_addr;
        u8      ctrl_addr;
        u8      tstep_addr;
  static const struct regs_info palmas_regs_info[] = {
        {
                .name           = "SMPS12",
+               .sname          = "smps1-in",
                .vsel_addr      = PALMAS_SMPS12_VOLTAGE,
                .ctrl_addr      = PALMAS_SMPS12_CTRL,
                .tstep_addr     = PALMAS_SMPS12_TSTEP,
        },
        {
                .name           = "SMPS123",
+               .sname          = "smps1-in",
                .vsel_addr      = PALMAS_SMPS12_VOLTAGE,
                .ctrl_addr      = PALMAS_SMPS12_CTRL,
                .tstep_addr     = PALMAS_SMPS12_TSTEP,
        },
        {
                .name           = "SMPS3",
+               .sname          = "smps3-in",
                .vsel_addr      = PALMAS_SMPS3_VOLTAGE,
                .ctrl_addr      = PALMAS_SMPS3_CTRL,
        },
        {
                .name           = "SMPS45",
+               .sname          = "smps4-in",
                .vsel_addr      = PALMAS_SMPS45_VOLTAGE,
                .ctrl_addr      = PALMAS_SMPS45_CTRL,
                .tstep_addr     = PALMAS_SMPS45_TSTEP,
        },
        {
                .name           = "SMPS457",
+               .sname          = "smps4-in",
                .vsel_addr      = PALMAS_SMPS45_VOLTAGE,
                .ctrl_addr      = PALMAS_SMPS45_CTRL,
                .tstep_addr     = PALMAS_SMPS45_TSTEP,
        },
        {
                .name           = "SMPS6",
+               .sname          = "smps6-in",
                .vsel_addr      = PALMAS_SMPS6_VOLTAGE,
                .ctrl_addr      = PALMAS_SMPS6_CTRL,
                .tstep_addr     = PALMAS_SMPS6_TSTEP,
        },
        {
                .name           = "SMPS7",
+               .sname          = "smps7-in",
                .vsel_addr      = PALMAS_SMPS7_VOLTAGE,
                .ctrl_addr      = PALMAS_SMPS7_CTRL,
        },
        {
                .name           = "SMPS8",
+               .sname          = "smps8-in",
                .vsel_addr      = PALMAS_SMPS8_VOLTAGE,
                .ctrl_addr      = PALMAS_SMPS8_CTRL,
                .tstep_addr     = PALMAS_SMPS8_TSTEP,
        },
        {
                .name           = "SMPS9",
+               .sname          = "smps9-in",
                .vsel_addr      = PALMAS_SMPS9_VOLTAGE,
                .ctrl_addr      = PALMAS_SMPS9_CTRL,
        },
        {
                .name           = "SMPS10",
+               .sname          = "smps10-in",
+               .ctrl_addr      = PALMAS_SMPS10_CTRL,
        },
        {
                .name           = "LDO1",
+               .sname          = "ldo1-in",
                .vsel_addr      = PALMAS_LDO1_VOLTAGE,
                .ctrl_addr      = PALMAS_LDO1_CTRL,
        },
        {
                .name           = "LDO2",
+               .sname          = "ldo2-in",
                .vsel_addr      = PALMAS_LDO2_VOLTAGE,
                .ctrl_addr      = PALMAS_LDO2_CTRL,
        },
        {
                .name           = "LDO3",
+               .sname          = "ldo3-in",
                .vsel_addr      = PALMAS_LDO3_VOLTAGE,
                .ctrl_addr      = PALMAS_LDO3_CTRL,
        },
        {
                .name           = "LDO4",
+               .sname          = "ldo4-in",
                .vsel_addr      = PALMAS_LDO4_VOLTAGE,
                .ctrl_addr      = PALMAS_LDO4_CTRL,
        },
        {
                .name           = "LDO5",
+               .sname          = "ldo5-in",
                .vsel_addr      = PALMAS_LDO5_VOLTAGE,
                .ctrl_addr      = PALMAS_LDO5_CTRL,
        },
        {
                .name           = "LDO6",
+               .sname          = "ldo6-in",
                .vsel_addr      = PALMAS_LDO6_VOLTAGE,
                .ctrl_addr      = PALMAS_LDO6_CTRL,
        },
        {
                .name           = "LDO7",
+               .sname          = "ldo7-in",
                .vsel_addr      = PALMAS_LDO7_VOLTAGE,
                .ctrl_addr      = PALMAS_LDO7_CTRL,
        },
        {
                .name           = "LDO8",
+               .sname          = "ldo8-in",
                .vsel_addr      = PALMAS_LDO8_VOLTAGE,
                .ctrl_addr      = PALMAS_LDO8_CTRL,
        },
        {
                .name           = "LDO9",
+               .sname          = "ldo9-in",
                .vsel_addr      = PALMAS_LDO9_VOLTAGE,
                .ctrl_addr      = PALMAS_LDO9_CTRL,
        },
        {
                .name           = "LDOLN",
+               .sname          = "ldoln-in",
                .vsel_addr      = PALMAS_LDOLN_VOLTAGE,
                .ctrl_addr      = PALMAS_LDOLN_CTRL,
        },
        {
                .name           = "LDOUSB",
+               .sname          = "ldousb-in",
                .vsel_addr      = PALMAS_LDOUSB_VOLTAGE,
                .ctrl_addr      = PALMAS_LDOUSB_CTRL,
        },
+       {
+               .name           = "REGEN1",
+               .ctrl_addr      = PALMAS_REGEN1_CTRL,
+       },
+       {
+               .name           = "REGEN2",
+               .ctrl_addr      = PALMAS_REGEN2_CTRL,
+       },
+       {
+               .name           = "REGEN3",
+               .ctrl_addr      = PALMAS_REGEN3_CTRL,
+       },
+       {
+               .name           = "SYSEN1",
+               .ctrl_addr      = PALMAS_SYSEN1_CTRL,
+       },
+       {
+               .name           = "SYSEN2",
+               .ctrl_addr      = PALMAS_SYSEN2_CTRL,
+       },
  };
  
+ static unsigned int palmas_smps_ramp_delay[4] = {0, 10000, 5000, 2500};
  #define SMPS_CTRL_MODE_OFF            0x00
  #define SMPS_CTRL_MODE_ON             0x01
  #define SMPS_CTRL_MODE_ECO            0x02
   *
   * So they are basically (maxV-minV)/stepV
   */
 -#define PALMAS_SMPS_NUM_VOLTAGES      116
 +#define PALMAS_SMPS_NUM_VOLTAGES      117
  #define PALMAS_SMPS10_NUM_VOLTAGES    2
  #define PALMAS_LDO_NUM_VOLTAGES               50
  
@@@ -231,7 -275,10 +276,10 @@@ static int palmas_enable_smps(struct re
        palmas_smps_read(pmic->palmas, palmas_regs_info[id].ctrl_addr, &reg);
  
        reg &= ~PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK;
-       reg |= SMPS_CTRL_MODE_ON;
+       if (pmic->current_reg_mode[id])
+               reg |= pmic->current_reg_mode[id];
+       else
+               reg |= SMPS_CTRL_MODE_ON;
  
        palmas_smps_write(pmic->palmas, palmas_regs_info[id].ctrl_addr, reg);
  
@@@ -253,16 -300,19 +301,19 @@@ static int palmas_disable_smps(struct r
        return 0;
  }
  
  static int palmas_set_mode_smps(struct regulator_dev *dev, unsigned int mode)
  {
        struct palmas_pmic *pmic = rdev_get_drvdata(dev);
        int id = rdev_get_id(dev);
        unsigned int reg;
+       bool rail_enable = true;
  
        palmas_smps_read(pmic->palmas, palmas_regs_info[id].ctrl_addr, &reg);
        reg &= ~PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK;
  
+       if (reg == SMPS_CTRL_MODE_OFF)
+               rail_enable = false;
        switch (mode) {
        case REGULATOR_MODE_NORMAL:
                reg |= SMPS_CTRL_MODE_ON;
        default:
                return -EINVAL;
        }
-       palmas_smps_write(pmic->palmas, palmas_regs_info[id].ctrl_addr, reg);
  
+       pmic->current_reg_mode[id] = reg & PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK;
+       if (rail_enable)
+               palmas_smps_write(pmic->palmas,
+                       palmas_regs_info[id].ctrl_addr, reg);
        return 0;
  }
  
@@@ -287,9 -340,7 +341,7 @@@ static unsigned int palmas_get_mode_smp
        int id = rdev_get_id(dev);
        unsigned int reg;
  
-       palmas_smps_read(pmic->palmas, palmas_regs_info[id].ctrl_addr, &reg);
-       reg &= PALMAS_SMPS12_CTRL_STATUS_MASK;
-       reg >>= PALMAS_SMPS12_CTRL_STATUS_SHIFT;
+       reg = pmic->current_reg_mode[id] & PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK;
  
        switch (reg) {
        case SMPS_CTRL_MODE_ON:
@@@ -356,6 -407,63 +408,63 @@@ static int palmas_map_voltage_smps(stru
        return ret;
  }
  
+ static int palma_smps_set_voltage_smps_time_sel(struct regulator_dev *rdev,
+       unsigned int old_selector, unsigned int new_selector)
+ {
+       struct palmas_pmic *pmic = rdev_get_drvdata(rdev);
+       int id = rdev_get_id(rdev);
+       int old_uv, new_uv;
+       unsigned int ramp_delay = pmic->ramp_delay[id];
+       if (!ramp_delay)
+               return 0;
+       old_uv = palmas_list_voltage_smps(rdev, old_selector);
+       if (old_uv < 0)
+               return old_uv;
+       new_uv = palmas_list_voltage_smps(rdev, new_selector);
+       if (new_uv < 0)
+               return new_uv;
+       return DIV_ROUND_UP(abs(old_uv - new_uv), ramp_delay);
+ }
+ static int palmas_smps_set_ramp_delay(struct regulator_dev *rdev,
+                int ramp_delay)
+ {
+       struct palmas_pmic *pmic = rdev_get_drvdata(rdev);
+       int id = rdev_get_id(rdev);
+       unsigned int reg = 0;
+       unsigned int addr = palmas_regs_info[id].tstep_addr;
+       int ret;
+       /* SMPS3 and SMPS7 do not have tstep_addr setting */
+       switch (id) {
+       case PALMAS_REG_SMPS3:
+       case PALMAS_REG_SMPS7:
+               return 0;
+       }
+       if (ramp_delay <= 0)
+               reg = 0;
+       else if (ramp_delay <= 2500)
+               reg = 3;
+       else if (ramp_delay <= 5000)
+               reg = 2;
+       else
+               reg = 1;
+       ret = palmas_smps_write(pmic->palmas, addr, reg);
+       if (ret < 0) {
+               dev_err(pmic->palmas->dev, "TSTEP write failed: %d\n", ret);
+               return ret;
+       }
+       pmic->ramp_delay[id] = palmas_smps_ramp_delay[reg];
+       return ret;
+ }
  static struct regulator_ops palmas_ops_smps = {
        .is_enabled             = palmas_is_enabled_smps,
        .enable                 = palmas_enable_smps,
        .set_voltage_sel        = regulator_set_voltage_sel_regmap,
        .list_voltage           = palmas_list_voltage_smps,
        .map_voltage            = palmas_map_voltage_smps,
+       .set_voltage_time_sel   = palma_smps_set_voltage_smps_time_sel,
+       .set_ramp_delay         = palmas_smps_set_ramp_delay,
  };
  
  static struct regulator_ops palmas_ops_smps10 = {
@@@ -401,6 -511,12 +512,12 @@@ static struct regulator_ops palmas_ops_
        .map_voltage            = regulator_map_voltage_linear,
  };
  
+ static struct regulator_ops palmas_ops_extreg = {
+       .is_enabled             = regulator_is_enabled_regmap,
+       .enable                 = regulator_enable_regmap,
+       .disable                = regulator_disable_regmap,
+ };
  /*
   * setup the hardware based sleep configuration of the SMPS/LDO regulators
   * from the platform data. This is different to the software based control
@@@ -422,40 -538,32 +539,32 @@@ static int palmas_smps_init(struct palm
  
        switch (id) {
        case PALMAS_REG_SMPS10:
-               if (reg_init->mode_sleep) {
-                       reg &= ~PALMAS_SMPS10_CTRL_MODE_SLEEP_MASK;
+               reg &= ~PALMAS_SMPS10_CTRL_MODE_SLEEP_MASK;
+               if (reg_init->mode_sleep)
                        reg |= reg_init->mode_sleep <<
                                        PALMAS_SMPS10_CTRL_MODE_SLEEP_SHIFT;
-               }
                break;
        default:
                if (reg_init->warm_reset)
                        reg |= PALMAS_SMPS12_CTRL_WR_S;
+               else
+                       reg &= ~PALMAS_SMPS12_CTRL_WR_S;
  
                if (reg_init->roof_floor)
                        reg |= PALMAS_SMPS12_CTRL_ROOF_FLOOR_EN;
+               else
+                       reg &= ~PALMAS_SMPS12_CTRL_ROOF_FLOOR_EN;
  
-               if (reg_init->mode_sleep) {
-                       reg &= ~PALMAS_SMPS12_CTRL_MODE_SLEEP_MASK;
+               reg &= ~PALMAS_SMPS12_CTRL_MODE_SLEEP_MASK;
+               if (reg_init->mode_sleep)
                        reg |= reg_init->mode_sleep <<
                                        PALMAS_SMPS12_CTRL_MODE_SLEEP_SHIFT;
-               }
        }
  
        ret = palmas_smps_write(palmas, addr, reg);
        if (ret)
                return ret;
  
-       if (palmas_regs_info[id].tstep_addr && reg_init->tstep) {
-               addr = palmas_regs_info[id].tstep_addr;
-               reg = reg_init->tstep & PALMAS_SMPS12_TSTEP_TSTEP_MASK;
-               ret = palmas_smps_write(palmas, addr, reg);
-               if (ret)
-                       return ret;
-       }
        if (palmas_regs_info[id].vsel_addr && reg_init->vsel) {
                addr = palmas_regs_info[id].vsel_addr;
  
@@@ -485,9 -593,13 +594,13 @@@ static int palmas_ldo_init(struct palma
  
        if (reg_init->warm_reset)
                reg |= PALMAS_LDO1_CTRL_WR_S;
+       else
+               reg &= ~PALMAS_LDO1_CTRL_WR_S;
  
        if (reg_init->mode_sleep)
                reg |= PALMAS_LDO1_CTRL_MODE_SLEEP;
+       else
+               reg &= ~PALMAS_LDO1_CTRL_MODE_SLEEP;
  
        ret = palmas_ldo_write(palmas, addr, reg);
        if (ret)
        return 0;
  }
  
+ static int palmas_extreg_init(struct palmas *palmas, int id,
+               struct palmas_reg_init *reg_init)
+ {
+       unsigned int addr;
+       int ret;
+       unsigned int val = 0;
+       addr = palmas_regs_info[id].ctrl_addr;
+       if (reg_init->mode_sleep)
+               val = PALMAS_REGEN1_CTRL_MODE_SLEEP;
+       ret = palmas_update_bits(palmas, PALMAS_RESOURCE_BASE,
+                       addr, PALMAS_REGEN1_CTRL_MODE_SLEEP, val);
+       if (ret < 0) {
+               dev_err(palmas->dev, "Resource reg 0x%02x update failed %d\n",
+                       addr, ret);
+               return ret;
+       }
+       return 0;
+ }
+ static void palmas_enable_ldo8_track(struct palmas *palmas)
+ {
+       unsigned int reg;
+       unsigned int addr;
+       int ret;
+       addr = palmas_regs_info[PALMAS_REG_LDO8].ctrl_addr;
+       ret = palmas_ldo_read(palmas, addr, &reg);
+       if (ret) {
+               dev_err(palmas->dev, "Error in reading ldo8 control reg\n");
+               return;
+       }
+       reg |= PALMAS_LDO8_CTRL_LDO_TRACKING_EN;
+       ret = palmas_ldo_write(palmas, addr, reg);
+       if (ret < 0) {
+               dev_err(palmas->dev, "Error in enabling tracking mode\n");
+               return;
+       }
+       /*
+        * When SMPS45 is set to off and LDO8 tracking is enabled, the LDO8
+        * output is defined by the LDO8_VOLTAGE.VSEL register divided by two,
+        * and can be set from 0.45 to 1.65 V.
+        */
+       addr = palmas_regs_info[PALMAS_REG_LDO8].vsel_addr;
+       ret = palmas_ldo_read(palmas, addr, &reg);
+       if (ret) {
+               dev_err(palmas->dev, "Error in reading ldo8 voltage reg\n");
+               return;
+       }
+       reg = (reg << 1) & PALMAS_LDO8_VOLTAGE_VSEL_MASK;
+       ret = palmas_ldo_write(palmas, addr, reg);
+       if (ret < 0)
+               dev_err(palmas->dev, "Error in setting ldo8 voltage reg\n");
+       return;
+ }
  static struct of_regulator_match palmas_matches[] = {
        { .name = "smps12", },
        { .name = "smps123", },
        { .name = "ldo9", },
        { .name = "ldoln", },
        { .name = "ldousb", },
+       { .name = "regen1", },
+       { .name = "regen2", },
+       { .name = "regen3", },
+       { .name = "sysen1", },
+       { .name = "sysen2", },
  };
  
  static void palmas_dt_to_pdata(struct device *dev,
                pdata->reg_init[idx] = devm_kzalloc(dev,
                                sizeof(struct palmas_reg_init), GFP_KERNEL);
  
-               ret = of_property_read_u32(palmas_matches[idx].of_node,
-                               "ti,warm_reset", &prop);
-               if (!ret)
-                       pdata->reg_init[idx]->warm_reset = prop;
+               pdata->reg_init[idx]->warm_reset =
+                       of_property_read_bool(palmas_matches[idx].of_node,
+                                            "ti,warm-reset");
  
-               ret = of_property_read_u32(palmas_matches[idx].of_node,
-                               "ti,roof_floor", &prop);
-               if (!ret)
-                       pdata->reg_init[idx]->roof_floor = prop;
+               pdata->reg_init[idx]->roof_floor =
+                       of_property_read_bool(palmas_matches[idx].of_node,
+                                             "ti,roof-floor");
  
                ret = of_property_read_u32(palmas_matches[idx].of_node,
-                               "ti,mode_sleep", &prop);
+                               "ti,mode-sleep", &prop);
                if (!ret)
                        pdata->reg_init[idx]->mode_sleep = prop;
  
-               ret = of_property_read_u32(palmas_matches[idx].of_node,
-                               "ti,tstep", &prop);
-               if (!ret)
-                       pdata->reg_init[idx]->tstep = prop;
+               ret = of_property_read_bool(palmas_matches[idx].of_node,
+                                           "ti,smps-range");
+               if (ret)
+                       pdata->reg_init[idx]->vsel =
+                               PALMAS_SMPS12_VOLTAGE_RANGE;
  
-               ret = of_property_read_u32(palmas_matches[idx].of_node,
-                               "ti,vsel", &prop);
-               if (!ret)
-                       pdata->reg_init[idx]->vsel = prop;
+               if (idx == PALMAS_REG_LDO8)
+                       pdata->enable_ldo8_tracking = of_property_read_bool(
+                                               palmas_matches[idx].of_node,
+                                               "ti,enable-ldo8-tracking");
        }
  
-       ret = of_property_read_u32(node, "ti,ldo6_vibrator", &prop);
-       if (!ret)
-               pdata->ldo6_vibrator = prop;
+       pdata->ldo6_vibrator = of_property_read_bool(node, "ti,ldo6-vibrator");
  }
  
  
- static int palmas_probe(struct platform_device *pdev)
+ static int palmas_regulators_probe(struct platform_device *pdev)
  {
        struct palmas *palmas = dev_get_drvdata(pdev->dev.parent);
        struct palmas_pmic_platform_data *pdata = pdev->dev.platform_data;
        config.driver_data = pmic;
  
        for (id = 0; id < PALMAS_REG_LDO1; id++) {
+               bool ramp_delay_support = false;
  
                /*
                 * Miss out regulators which are not available due
                case PALMAS_REG_SMPS3:
                        if (pmic->smps123)
                                continue;
+                       if (id == PALMAS_REG_SMPS12)
+                               ramp_delay_support = true;
                        break;
                case PALMAS_REG_SMPS123:
                        if (!pmic->smps123)
                                continue;
+                       ramp_delay_support = true;
                        break;
                case PALMAS_REG_SMPS45:
                case PALMAS_REG_SMPS7:
                        if (pmic->smps457)
                                continue;
+                       if (id == PALMAS_REG_SMPS45)
+                               ramp_delay_support = true;
                        break;
                case PALMAS_REG_SMPS457:
                        if (!pmic->smps457)
                                continue;
+                       ramp_delay_support = true;
+                       break;
+               }
+               if ((id == PALMAS_REG_SMPS6) && (id == PALMAS_REG_SMPS8))
+                       ramp_delay_support = true;
+               if (ramp_delay_support) {
+                       addr = palmas_regs_info[id].tstep_addr;
+                       ret = palmas_smps_read(pmic->palmas, addr, &reg);
+                       if (ret < 0) {
+                               dev_err(&pdev->dev,
+                                       "reading TSTEP reg failed: %d\n", ret);
+                               goto err_unregister_regulator;
+                       }
+                       pmic->desc[id].ramp_delay =
+                                       palmas_smps_ramp_delay[reg & 0x3];
+                       pmic->ramp_delay[id] = pmic->desc[id].ramp_delay;
                }
  
                /* Initialise sleep/init values from platform data */
                        /*
                         * Read and store the RANGE bit for later use
                         * This must be done before regulator is probed,
-                        * otherwise we error in probe with unsupportable ranges.
+                        * otherwise we error in probe with unsupportable
+                        * ranges. Read the current smps mode for later use.
                         */
                        addr = palmas_regs_info[id].vsel_addr;
  
                                                palmas_regs_info[id].vsel_addr);
                        pmic->desc[id].vsel_mask =
                                        PALMAS_SMPS12_VOLTAGE_VSEL_MASK;
+                       /* Read the smps mode for later use. */
+                       addr = palmas_regs_info[id].ctrl_addr;
+                       ret = palmas_smps_read(pmic->palmas, addr, &reg);
+                       if (ret)
+                               goto err_unregister_regulator;
+                       pmic->current_reg_mode[id] = reg &
+                                       PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK;
                }
  
                pmic->desc[id].type = REGULATOR_VOLTAGE;
                else
                        config.init_data = NULL;
  
+               pmic->desc[id].supply_name = palmas_regs_info[id].sname;
                config.of_node = palmas_matches[id].of_node;
  
                rdev = regulator_register(&pmic->desc[id], &config);
                /* Register the regulators */
                pmic->desc[id].name = palmas_regs_info[id].name;
                pmic->desc[id].id = id;
-               pmic->desc[id].n_voltages = PALMAS_LDO_NUM_VOLTAGES;
-               pmic->desc[id].ops = &palmas_ops_ldo;
                pmic->desc[id].type = REGULATOR_VOLTAGE;
                pmic->desc[id].owner = THIS_MODULE;
-               pmic->desc[id].min_uV = 900000;
-               pmic->desc[id].uV_step = 50000;
-               pmic->desc[id].linear_min_sel = 1;
-               pmic->desc[id].vsel_reg = PALMAS_BASE_TO_REG(PALMAS_LDO_BASE,
+               if (id < PALMAS_REG_REGEN1) {
+                       pmic->desc[id].n_voltages = PALMAS_LDO_NUM_VOLTAGES;
+                       pmic->desc[id].ops = &palmas_ops_ldo;
+                       pmic->desc[id].min_uV = 900000;
+                       pmic->desc[id].uV_step = 50000;
+                       pmic->desc[id].linear_min_sel = 1;
+                       pmic->desc[id].vsel_reg =
+                                       PALMAS_BASE_TO_REG(PALMAS_LDO_BASE,
                                                palmas_regs_info[id].vsel_addr);
-               pmic->desc[id].vsel_mask = PALMAS_LDO1_VOLTAGE_VSEL_MASK;
-               pmic->desc[id].enable_reg = PALMAS_BASE_TO_REG(PALMAS_LDO_BASE,
+                       pmic->desc[id].vsel_mask =
+                                       PALMAS_LDO1_VOLTAGE_VSEL_MASK;
+                       pmic->desc[id].enable_reg =
+                                       PALMAS_BASE_TO_REG(PALMAS_LDO_BASE,
+                                               palmas_regs_info[id].ctrl_addr);
+                       pmic->desc[id].enable_mask =
+                                       PALMAS_LDO1_CTRL_MODE_ACTIVE;
+                       /* Check if LDO8 is in tracking mode or not */
+                       if (pdata && (id == PALMAS_REG_LDO8) &&
+                                       pdata->enable_ldo8_tracking) {
+                               palmas_enable_ldo8_track(palmas);
+                               pmic->desc[id].min_uV = 450000;
+                               pmic->desc[id].uV_step = 25000;
+                       }
+               } else {
+                       pmic->desc[id].n_voltages = 1;
+                       pmic->desc[id].ops = &palmas_ops_extreg;
+                       pmic->desc[id].enable_reg =
+                                       PALMAS_BASE_TO_REG(PALMAS_RESOURCE_BASE,
                                                palmas_regs_info[id].ctrl_addr);
-               pmic->desc[id].enable_mask = PALMAS_LDO1_CTRL_MODE_ACTIVE;
+                       pmic->desc[id].enable_mask =
+                                       PALMAS_REGEN1_CTRL_MODE_ACTIVE;
+               }
  
                if (pdata)
                        config.init_data = pdata->reg_data[id];
                else
                        config.init_data = NULL;
  
+               pmic->desc[id].supply_name = palmas_regs_info[id].sname;
                config.of_node = palmas_matches[id].of_node;
  
                rdev = regulator_register(&pmic->desc[id], &config);
                if (pdata) {
                        reg_init = pdata->reg_init[id];
                        if (reg_init) {
-                               ret = palmas_ldo_init(palmas, id, reg_init);
+                               if (id < PALMAS_REG_REGEN1)
+                                       ret = palmas_ldo_init(palmas,
+                                                       id, reg_init);
+                               else
+                                       ret = palmas_extreg_init(palmas,
+                                                       id, reg_init);
                                if (ret) {
                                        regulator_unregister(pmic->rdev[id]);
                                        goto err_unregister_regulator;
                }
        }
  
        return 0;
  
  err_unregister_regulator:
        return ret;
  }
  
- static int palmas_remove(struct platform_device *pdev)
+ static int palmas_regulators_remove(struct platform_device *pdev)
  {
        struct palmas_pmic *pmic = platform_get_drvdata(pdev);
        int id;
  
  static struct of_device_id of_palmas_match_tbl[] = {
        { .compatible = "ti,palmas-pmic", },
+       { .compatible = "ti,twl6035-pmic", },
+       { .compatible = "ti,twl6036-pmic", },
+       { .compatible = "ti,twl6037-pmic", },
+       { .compatible = "ti,tps65913-pmic", },
+       { .compatible = "ti,tps65914-pmic", },
+       { .compatible = "ti,tps80036-pmic", },
        { /* end */ }
  };
  
@@@ -815,8 -1059,8 +1060,8 @@@ static struct platform_driver palmas_dr
                .of_match_table = of_palmas_match_tbl,
                .owner = THIS_MODULE,
        },
-       .probe = palmas_probe,
-       .remove = palmas_remove,
+       .probe = palmas_regulators_probe,
+       .remove = palmas_regulators_remove,
  };
  
  static int __init palmas_init(void)
index 3bbda22721ea083cc35251e399a37742b72c8bae,e971a7c81b792a2b9b5568d9088adfce3bea1a7f..ecddc5173c7ca964f326bbd948337dc4c57a4583
@@@ -109,19 -109,6 +109,6 @@@ struct palmas_reg_init 
         */
        int mode_sleep;
  
-       /* tstep is the timestep loaded to the TSTEP register
-        *
-        * For SMPS
-        *
-        * 0: Jump (no slope control)
-        * 1: 10mV/us
-        * 2: 5mV/us
-        * 3: 2.5mV/us
-        *
-        * For LDO unused
-        */
-       int tstep;
        /* voltage_sel is the bitfield loaded onto the SMPSX_VOLTAGE
         * register. Set this is the default voltage set in OTP needs
         * to be overridden.
@@@ -154,6 -141,12 +141,12 @@@ enum palmas_regulators 
        PALMAS_REG_LDO9,
        PALMAS_REG_LDOLN,
        PALMAS_REG_LDOUSB,
+       /* External regulators */
+       PALMAS_REG_REGEN1,
+       PALMAS_REG_REGEN2,
+       PALMAS_REG_REGEN3,
+       PALMAS_REG_SYSEN1,
+       PALMAS_REG_SYSEN2,
        /* Total number of regulators */
        PALMAS_NUM_REGS,
  };
@@@ -171,6 -164,9 +164,9 @@@ struct palmas_pmic_platform_data 
  
        /* use LDO6 for vibrator control */
        int ldo6_vibrator;
+       /* Enable tracking mode of LDO8 */
+       bool enable_ldo8_tracking;
  };
  
  struct palmas_usb_platform_data {
@@@ -221,7 -217,6 +217,7 @@@ struct palmas_clk_platform_data 
  };
  
  struct palmas_platform_data {
 +      int irq_flags;
        int gpio_base;
  
        /* bit value to be loaded to the POWER_CTRL register */
@@@ -331,6 -326,8 +327,8 @@@ struct palmas_pmic 
        int smps457;
  
        int range[PALMAS_REG_SMPS10];
+       unsigned int ramp_delay[PALMAS_REG_SMPS10];
+       unsigned int current_reg_mode[PALMAS_REG_SMPS10];
  };
  
  struct palmas_resource {