mfd: tps80031: Move external pwr req to core driver
Laxman Dewangan [Tue, 8 Nov 2011 06:06:02 +0000 (11:06 +0530)]
Moving the configuration function for configuring the
rail control through the PREQ line to core from regulator
driver.

Fixing the correct voltage configuration for the LDO2 based
on TRACK mode.

Reviewed-on: http://git-master/r/63503
(cherry picked from commit 9190130f6cf1ba0bae3231321841ebe4ad94a54e)

Change-Id: I7dd511da7f809a44b1e66706054c0a4c57c36323
Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Reviewed-on: http://git-master/r/64055

Rebase-Id: R433728b4c83ccaf6f3ae2734412a90d9c89b6a2c

drivers/mfd/tps80031.c
drivers/regulator/tps80031-regulator.c
include/linux/mfd/tps80031.h
include/linux/regulator/tps80031-regulator.h

index 3630f7b..094adaa 100644 (file)
 #define STATE_ON       0x01
 #define STATE_MASK     0x03
 
+#define TRANS_SLEEP_OFF                0x00
+#define TRANS_SLEEP_ON         0x04
+#define TRANS_SLEEP_MASK       0x0C
+
 #define TPS_NUM_SLAVES 4
+#define EXT_PWR_REQ (PWR_REQ_INPUT_PREQ1 | PWR_REQ_INPUT_PREQ2 | \
+               PWR_REQ_INPUT_PREQ3)
+#define TPS80031_PREQ1_RES_ASS_A       0xD7
+#define TPS80031_PREQ2_RES_ASS_A       0xDA
+#define TPS80031_PREQ3_RES_ASS_A       0xDD
+#define TPS80031_PHOENIX_MSK_TRANSITION 0x20
+
 
 static u8 pmc_ext_control_base[] = {
        REGEN1_BASE_ADD,
@@ -403,6 +414,69 @@ out:
 }
 EXPORT_SYMBOL_GPL(tps80031_force_update);
 
+int tps80031_ext_power_req_config(struct device *dev,
+               enum tps80031_ext_control ext_pwr_ctrl, int preq_bit,
+               int state_reg_add, int trans_reg_add)
+{
+       u8 res_ass_reg = 0;
+       int preq_mask_bit = 0;
+       int ret;
+
+       if (!(ext_pwr_ctrl & EXT_PWR_REQ))
+               return 0;
+
+       if (ext_pwr_ctrl & PWR_REQ_INPUT_PREQ1) {
+               res_ass_reg = TPS80031_PREQ1_RES_ASS_A + (preq_bit >> 3);
+               preq_mask_bit = 5;
+       } else if (ext_pwr_ctrl & PWR_REQ_INPUT_PREQ2) {
+               res_ass_reg = TPS80031_PREQ2_RES_ASS_A + (preq_bit >> 3);
+               preq_mask_bit = 6;
+       } else if (ext_pwr_ctrl & PWR_REQ_INPUT_PREQ3) {
+               res_ass_reg = TPS80031_PREQ3_RES_ASS_A + (preq_bit >> 3);
+               preq_mask_bit = 7;
+       }
+
+       /* Configure REQ_ASS registers */
+       ret = tps80031_set_bits(dev, SLAVE_ID1, res_ass_reg,
+                                       BIT(preq_bit & 0x7));
+       if (ret < 0) {
+               dev_err(dev, "%s() Not able to set bit %d of "
+                       "reg %d error %d\n",
+                       __func__, preq_bit, res_ass_reg, ret);
+               return ret;
+       }
+
+       /* Unmask the PREQ */
+       ret = tps80031_clr_bits(dev, SLAVE_ID1,
+                       TPS80031_PHOENIX_MSK_TRANSITION, BIT(preq_mask_bit));
+       if (ret < 0) {
+               dev_err(dev, "%s() Not able to clear bit %d of "
+                       "reg %d error %d\n",
+                        __func__, preq_mask_bit,
+                       TPS80031_PHOENIX_MSK_TRANSITION, ret);
+               return ret;
+       }
+
+       /* Switch regulator control to resource now */
+       if (ext_pwr_ctrl &  (PWR_REQ_INPUT_PREQ2 | PWR_REQ_INPUT_PREQ3)) {
+               ret = tps80031_update(dev, SLAVE_ID1, state_reg_add, 0x0,
+                                               STATE_MASK);
+               if (ret < 0)
+                       dev_err(dev, "%s() Error in writing the STATE "
+                               "register %d error %d\n", __func__,
+                               state_reg_add, ret);
+       } else {
+               ret = tps80031_update(dev, SLAVE_ID1, trans_reg_add,
+                               TRANS_SLEEP_OFF, TRANS_SLEEP_MASK);
+               if (ret < 0)
+                       dev_err(dev, "%s() Error in writing the TRANS "
+                               "register %d error %d\n", __func__,
+                               trans_reg_add, ret);
+       }
+       return ret;
+}
+EXPORT_SYMBOL_GPL(tps80031_ext_power_req_config);
+
 unsigned long tps80031_get_chip_info(struct device *dev)
 {
        struct tps80031 *tps80031 = dev_get_drvdata(dev);
@@ -421,6 +495,29 @@ int tps80031_power_off(void)
        return __tps80031_write(tps->client, TPS80031_PHOENIX_DEV_ON, DEVOFF);
 }
 
+static void tps80031_init_ext_control(struct tps80031 *tps80031,
+                       struct tps80031_platform_data *pdata) {
+       int ret;
+       int i;
+
+       /* Clear all external control for this rail */
+       for (i = 0; i < 9; ++i) {
+               tps80031_write(tps80031->dev, SLAVE_ID1,
+                               TPS80031_PREQ1_RES_ASS_A + i, 0);
+               if (ret < 0)
+                       dev_err(tps80031->dev, "%s() Error in clearing "
+                               "register %02x\n", __func__,
+                               TPS80031_PREQ1_RES_ASS_A + i);
+       }
+
+       /* Mask the PREQ */
+       ret = tps80031_set_bits(tps80031->dev, SLAVE_ID1,
+                       TPS80031_PHOENIX_MSK_TRANSITION, 0x7 << 5);
+       if (ret < 0)
+               dev_err(tps80031->dev, "%s() Not able to mask register "
+                       "0x%02x\n", __func__, TPS80031_PHOENIX_MSK_TRANSITION);
+}
+
 static int tps80031_gpio_get(struct gpio_chip *gc, unsigned offset)
 {
        struct tps80031 *tps80031 = container_of(gc, struct tps80031, gpio);
@@ -491,16 +588,36 @@ static void tps80031_gpio_disable(struct gpio_chip *gc, unsigned offset)
                                                STATE_OFF, STATE_MASK);
 }
 
+
 static void tps80031_gpio_init(struct tps80031 *tps80031,
                        struct tps80031_platform_data *pdata)
 {
        int ret;
        int gpio_base = pdata->gpio_base;
        struct tps80031_client *tps = &tps80031->tps_clients[SLAVE_ID1];
+       struct tps80031_gpio_init_data *gpio_init_data = pdata->gpio_init_data;
+       int data_size = pdata->gpio_init_data_size;
+       static int preq_bit_pos[TPS80031_GPIO_NR] = {16, 17, 18};
+       int base_add;
+       int i;
 
        if (gpio_base <= 0)
                return;
 
+       /* Configure the external request mode */
+       for (i = 0; i < data_size; ++i) {
+               if (!(gpio_init_data[i].ext_control & EXT_PWR_REQ))
+                       continue;
+               base_add = pmc_ext_control_base[gpio_init_data[i].gpio_nr];
+               ret = tps80031_ext_power_req_config(tps80031->dev,
+                       gpio_init_data[i].ext_control,
+                       preq_bit_pos[gpio_init_data[i].gpio_nr],
+                       base_add + EXT_CONTROL_CFG_STATE,
+                       base_add + EXT_CONTROL_CFG_TRANS);
+               if (!ret)
+                       dev_warn(tps80031->dev, "GPIO sleep control fails\n");
+       }
+
        tps80031->gpio.owner            = THIS_MODULE;
        tps80031->gpio.label            = tps->client->name;
        tps80031->gpio.dev              = tps80031->dev;
@@ -890,6 +1007,7 @@ static int dbg_tps_show(struct seq_file *s, void *unused)
        print_regs("INT Regs",       s, SLAVE_ID2, 0xD0, 0xD8);
        print_regs("PREQ Regs",      s, SLAVE_ID1, 0xD7, 0xDF);
        print_regs("MASK_PH Regs",   s, SLAVE_ID1, 0x20, 0x21);
+       print_regs("PMC MISC Regs",  s, SLAVE_ID1, 0xE0, 0xEF);
        print_regs("CONT_STATE",     s, SLAVE_ID2, 0xE0, 0xE4);
        print_regs("VERNUM Regs",    s, SLAVE_ID1, 0x87, 0x87);
        print_regs("CHARGE Regs",    s, SLAVE_ID2, 0xDA, 0xF5);
@@ -1014,6 +1132,7 @@ static int __devinit tps80031_i2c_probe(struct i2c_client *client,
                        goto fail;
                }
        }
+       tps80031_init_ext_control(tps80031, pdata);
 
        ret = tps80031_add_subdevs(tps80031, pdata);
        if (ret) {
index 704de70..5cd164a 100644 (file)
@@ -35,6 +35,7 @@
 /* Flags for DCDC Voltage reading */
 #define DCDC_OFFSET_EN         BIT(0)
 #define DCDC_EXTENDED_EN       BIT(1)
+#define TRACK_MODE_ENABLE      BIT(2)
 
 #define SMPS_MULTOFFSET_VIO    BIT(1)
 #define SMPS_MULTOFFSET_SMPS1  BIT(3)
 
 #define EXT_PWR_REQ (PWR_REQ_INPUT_PREQ1 | PWR_REQ_INPUT_PREQ2 | \
                        PWR_REQ_INPUT_PREQ3)
-#define TPS80031_PREQ1_RES_ASS_A       0xD7
-#define TPS80031_PREQ2_RES_ASS_A       0xDA
-#define TPS80031_PREQ3_RES_ASS_A       0xDD
-#define TPS80031_PHOENIX_MSK_TRANSITION        0x20
 
 struct tps80031_regulator {
 
@@ -109,6 +106,7 @@ struct tps80031_regulator {
 
        u8                      flags;
        unsigned int            platform_flags;
+       enum tps80031_ext_control ext_pwr_ctrl;
 
        /* used by regulator core */
        struct regulator_desc   desc;
@@ -162,7 +160,7 @@ static int tps80031_reg_is_enabled(struct regulator_dev *rdev)
 {
        struct tps80031_regulator *ri = rdev_get_drvdata(rdev);
 
-       if (ri->platform_flags & EXT_PWR_REQ)
+       if (ri->ext_pwr_ctrl & EXT_PWR_REQ)
                return true;
        return ((ri->state_reg_cache & STATE_MASK) == STATE_ON);
 }
@@ -174,7 +172,7 @@ static int tps80031_reg_enable(struct regulator_dev *rdev)
        int ret;
        uint8_t reg_val;
 
-       if (ri->platform_flags & EXT_PWR_REQ)
+       if (ri->ext_pwr_ctrl & EXT_PWR_REQ)
                return 0;
 
        reg_val = (ri->state_reg_cache & ~STATE_MASK) |
@@ -196,7 +194,7 @@ static int tps80031_reg_disable(struct regulator_dev *rdev)
        int ret;
        uint8_t reg_val;
 
-       if (ri->platform_flags & EXT_PWR_REQ)
+       if (ri->ext_pwr_ctrl & EXT_PWR_REQ)
                return 0;
 
        reg_val = (ri->state_reg_cache & ~STATE_MASK) |
@@ -499,9 +497,40 @@ static int tps80031ldo_list_voltage(struct regulator_dev *rdev, unsigned index)
        if (index == 0)
                return 0;
 
+       if ((ri->desc.id == TPS80031_ID_LDO2) &&
+                       (ri->flags &  TRACK_MODE_ENABLE))
+               return (ri->min_mV + (((index - 1) * 125))/10) * 1000;
+
        return (ri->min_mV + ((index - 1) * 100)) * 1000;
 }
 
+static int __tps80031_ldo2_set_voltage(struct device *parent,
+               struct tps80031_regulator *ri, int min_uV, int max_uV)
+{
+       int vsel = 0;
+       int ret;
+
+       if (min_uV < 600000) {
+               vsel = 0;
+       } else if ((min_uV >= 600000) && (max_uV <= 1300000)) {
+               vsel = (min_uV - 600000) / 125;
+               if (vsel % 100)
+                       vsel += 100;
+               vsel /= 100;
+               vsel++;
+       } else {
+               return -EINVAL;
+       }
+
+       ret = tps80031_write(parent, ri->volt_id, ri->volt_reg, vsel);
+       if (ret < 0)
+               dev_err(ri->dev, "Error in writing the Voltage register\n");
+       else
+               ri->volt_reg_cache = vsel;
+       return ret;
+}
+
+
 static int __tps80031_ldo_set_voltage(struct device *parent,
                                      struct tps80031_regulator *ri,
                                      int min_uV, int max_uV,
@@ -513,6 +542,10 @@ static int __tps80031_ldo_set_voltage(struct device *parent,
        if ((min_uV/1000 < ri->min_mV) || (max_uV/1000 > ri->max_mV))
                return -EDOM;
 
+       if ((ri->desc.id == TPS80031_ID_LDO2) &&
+                       (ri->flags &  TRACK_MODE_ENABLE))
+               return __tps80031_ldo2_set_voltage(parent, ri, min_uV, max_uV);
+
        /*
         * Use the below formula to calculate vsel
         * mV = 1000mv + 100mv * (vsel - 1)
@@ -541,8 +574,14 @@ static int tps80031ldo_get_voltage(struct regulator_dev *rdev)
        struct tps80031_regulator *ri = rdev_get_drvdata(rdev);
        uint8_t vsel;
 
-       vsel = ri->volt_reg_cache & LDO_VSEL_MASK;
 
+       if ((ri->desc.id == TPS80031_ID_LDO2) &&
+                       (ri->flags &  TRACK_MODE_ENABLE)) {
+               vsel = ri->volt_reg_cache & 0x3F;
+               return (ri->min_mV + (((vsel - 1) * 125))/10) * 1000;
+       }
+
+       vsel = ri->volt_reg_cache & LDO_VSEL_MASK;
        /*
         * Use the below formula to calculate vsel
         * mV = 1000mv + 100mv * (vsel - 1)
@@ -739,85 +778,19 @@ static int tps80031_power_req_config(struct device *parent,
                struct tps80031_regulator *ri,
                struct tps80031_regulator_platform_data *tps80031_pdata)
 {
-       u8 res_ass_reg;
-       int preq_bit;
-       int preq_mask_bit;
        int ret;
-       uint8_t reg_val;
-
-       /* Clear all external control for this rail */
-       ret = tps80031_clr_bits(parent, SLAVE_ID1,
-                       TPS80031_PREQ1_RES_ASS_A + (ri->preq_bit >> 3),
-                       BIT(ri->preq_bit & 0x7));
-       if (!ret)
-               ret = tps80031_clr_bits(parent, SLAVE_ID1,
-                               TPS80031_PREQ2_RES_ASS_A + (ri->preq_bit >> 3),
-                               BIT(ri->preq_bit & 0x7));
-       if (!ret)
-               ret = tps80031_clr_bits(parent, SLAVE_ID1,
-                               TPS80031_PREQ3_RES_ASS_A + (ri->preq_bit >> 3),
-                               BIT(ri->preq_bit & 0x7));
-       if (ret < 0) {
-               dev_err(ri->dev, "%s() Not able to clr bit %d of "
-                       "TPS80031_PREQ_RES_ASS error %d\n",
-                       __func__, preq_bit, ret);
-               return ret;
-       }
-
-       if (!(ri->platform_flags & EXT_PWR_REQ))
+       if (ri->preq_bit < 0)
                return 0;
 
-       preq_bit = ri->preq_bit & 0x7;
-       if (ri->platform_flags & PWR_REQ_INPUT_PREQ1) {
-               res_ass_reg = TPS80031_PREQ1_RES_ASS_A + (ri->preq_bit >> 3);
-               preq_mask_bit = 5;
-       } else if (ri->platform_flags & PWR_REQ_INPUT_PREQ2) {
-               res_ass_reg = TPS80031_PREQ2_RES_ASS_A + (ri->preq_bit >> 3);
-               preq_mask_bit = 6;
-       } else if (ri->platform_flags & PWR_REQ_INPUT_PREQ3) {
-               res_ass_reg = TPS80031_PREQ3_RES_ASS_A + (ri->preq_bit >> 3);
-               preq_mask_bit = 7;
-       }
-
-       /* Configure REQ_ASS registers */
-       ret = tps80031_set_bits(parent, SLAVE_ID1, res_ass_reg, BIT(preq_bit));
-       if (ret < 0) {
-               dev_err(ri->dev, "%s() Not able to set bit %d of "
-                       "reg %d error %d\n",
-                       __func__, preq_bit, res_ass_reg, ret);
-               return ret;
-       }
-
-       /* Unmask the PREQ */
-       ret = tps80031_clr_bits(parent, SLAVE_ID1,
-                       TPS80031_PHOENIX_MSK_TRANSITION, BIT(preq_mask_bit));
-       if (ret < 0) {
-               dev_err(ri->dev, "%s() Not able to clear bit %d of "
-                       "reg %d error %d\n",
-                        __func__, preq_mask_bit,
-                       TPS80031_PHOENIX_MSK_TRANSITION, ret);
-               return ret;
-       }
+       ret = tps80031_ext_power_req_config(parent, ri->ext_pwr_ctrl,
+                       ri->preq_bit, ri->state_reg, ri->trans_reg);
+       if (!ret)
+               ret = tps80031_read(parent, SLAVE_ID1, ri->trans_reg,
+                       &ri->trans_reg_cache);
 
-       /* Switch regulator control to resource now */
-       if (ri->platform_flags &  (PWR_REQ_INPUT_PREQ2 | PWR_REQ_INPUT_PREQ3)) {
-               reg_val = (ri->state_reg_cache & ~STATE_MASK);
-               ret = tps80031_write(parent, SLAVE_ID1, ri->state_reg, reg_val);
-               if (ret < 0)
-                       dev_err(ri->dev, "%s() Error in writing the STATE "
-                               "register error %d\n", __func__, ret);
-               else
-                       ri->state_reg_cache = reg_val;
-       } else {
-               reg_val = (ri->trans_reg_cache & ~TRANS_SLEEP_MASK) |
-                                       TRANS_SLEEP_OFF;
-               ret = tps80031_write(parent, SLAVE_ID1, ri->trans_reg, reg_val);
-               if (ret < 0)
-                       dev_err(ri->dev, "%s() Error in writing the TRANS "
-                               "register error %d\n", __func__, ret);
-               else
-                       ri->trans_reg_cache = reg_val;
-       }
+       if (!ret && ri->state_reg)
+               ret = tps80031_read(parent, SLAVE_ID1, ri->state_reg,
+                       &ri->state_reg_cache);
        return ret;
 }
 
@@ -948,6 +921,16 @@ static void check_smps_mode_mult(struct device *parent,
        case TPS80031_ID_SMPS4:
                mult_offset = SMPS_MULTOFFSET_SMPS4;
                break;
+       case TPS80031_ID_LDO2:
+               ri->flags = (tps80031_get_smps_mult(parent) & (1 << 5)) ?
+                                               TRACK_MODE_ENABLE : 0;
+               /* TRACK mode the ldo2 varies from 600mV to 1300mV */
+               if (ri->flags & TRACK_MODE_ENABLE) {
+                       ri->min_mV = 600;
+                       ri->max_mV = 1300;
+                       ri->desc.n_voltages = 57;
+               }
+               return;
        default:
                return;
        }
@@ -1000,6 +983,7 @@ static int __devinit tps80031_regulator_probe(struct platform_device *pdev)
 
        check_smps_mode_mult(pdev->dev.parent, ri);
        ri->platform_flags = tps_pdata->flags;
+       ri->ext_pwr_ctrl = tps_pdata->ext_pwr_ctrl;
 
        err = tps80031_cache_regulator_register(pdev->dev.parent, ri);
        if (err) {
index 9f9af00..731dd07 100644 (file)
@@ -113,6 +113,14 @@ enum {
        I2C_ID3_ADDR = 0x4A,
 };
 
+/* External power requests */
+enum tps80031_ext_control {
+       PWR_REQ_INPUT_NONE      = 0x00000000,
+       PWR_REQ_INPUT_PREQ1     = 0x00000001,
+       PWR_REQ_INPUT_PREQ2     = 0x00000002,
+       PWR_REQ_INPUT_PREQ3     = 0x00000004,
+};
+
 struct tps80031_subdev_info {
        int             id;
        const char      *name;
@@ -130,12 +138,19 @@ struct tps80031_32kclock_plat_data {
        unsigned en_clk32kaudio:1;
 };
 
+struct tps80031_gpio_init_data {
+       int gpio_nr;
+       enum tps80031_ext_control ext_control;
+};
+
 struct tps80031_platform_data {
        int num_subdevs;
        struct tps80031_subdev_info *subdevs;
        int gpio_base;
        int irq_base;
        struct tps80031_32kclock_plat_data *clk32k_pdata;
+       struct tps80031_gpio_init_data *gpio_init_data;
+       int gpio_init_data_size;
 };
 
 struct tps80031_bg_platform_data {
@@ -160,6 +175,10 @@ extern int tps80031_update(struct device *dev, int sid, int reg, uint8_t val,
                           uint8_t mask);
 extern int tps80031_force_update(struct device *dev, int sid, int reg,
                                 uint8_t val, uint8_t mask);
+extern int tps80031_ext_power_req_config(struct device *dev,
+               enum tps80031_ext_control ext_pwr_ctrl, int preq_bit,
+               int state_reg_add, int trans_reg_add);
+
 extern int tps80031_power_off(void);
 
 extern unsigned long tps80031_get_chip_info(struct device *dev);
index e76c4b8..d84a8c4 100644 (file)
@@ -61,11 +61,6 @@ enum {
        VBUS_DISCHRG_EN_PDN     = 0x00000004,
        VBUS_SW_ONLY            = 0x00000008,
        VBUS_SW_N_ID            = 0x00000010,
-
-       /* Power requests */
-       PWR_REQ_INPUT_PREQ1     = 0x00000020,
-       PWR_REQ_INPUT_PREQ2     = 0x00000040,
-       PWR_REQ_INPUT_PREQ3     = 0x00000080,
 };
 
 /*
@@ -75,6 +70,7 @@ enum {
  * @init_uV: initial micro volts which need to be set.
  * @init_enable: Enable or do not enable the rails during initialization.
  * @init_apply: Init parameter applied or not.
+ * @ext_pwr_ctrl: External power request control.
  * @flags: Configuration flag to configure the rails. It should be ORed of
  *      above enums.
  * @delay_us: Delay in microsecond after setting the desired voltage.
@@ -85,6 +81,7 @@ struct tps80031_regulator_platform_data {
        int init_uV;
        unsigned init_enable:1;
        unsigned init_apply:1;
+       unsigned int ext_pwr_ctrl;
        unsigned int flags;
        int delay_us;
 };