mfd: tps80031: Support sleep configuration through platform data
Laxman Dewangan [Thu, 24 Nov 2011 13:53:46 +0000 (18:53 +0530)]
Supporting the sleep configuration through platform data.
Rearranging clock initialization to take external power control.

Reviewed-on: http://git-master/r/67076
(cherry picked from commit 9da9d369bdbe988b98eec9b63085dfdb26de8237)

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

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

index 1cffa45..6fe80dc 100644 (file)
@@ -106,6 +106,11 @@ static u8 pmc_ext_control_base[] = {
        SYSEN_BASE_ADD,
 };
 
+static u8 pmc_clk32k_control_base[] = {
+       CLK32KAO_BASE_ADD,
+       CLK32KG_BASE_ADD,
+       CLK32KAUDIO_BASE_ADD,
+};
 struct tps80031_irq_data {
        u8      mask_reg;
        u8      mask_mask;
@@ -416,23 +421,23 @@ 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,
+               unsigned long ext_ctrl_flag, 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))
+       if (!(ext_ctrl_flag & EXT_PWR_REQ))
                return 0;
 
-       if (ext_pwr_ctrl & PWR_REQ_INPUT_PREQ1) {
+       if (ext_ctrl_flag & 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) {
+       } else if (ext_ctrl_flag & 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) {
+       } else if (ext_ctrl_flag & PWR_REQ_INPUT_PREQ3) {
                res_ass_reg = TPS80031_PREQ3_RES_ASS_A + (preq_bit >> 3);
                preq_mask_bit = 7;
        }
@@ -459,7 +464,7 @@ int tps80031_ext_power_req_config(struct device *dev,
        }
 
        /* Switch regulator control to resource now */
-       if (ext_pwr_ctrl &  (PWR_REQ_INPUT_PREQ2 | PWR_REQ_INPUT_PREQ3)) {
+       if (ext_ctrl_flag & (PWR_REQ_INPUT_PREQ2 | PWR_REQ_INPUT_PREQ3)) {
                ret = tps80031_update(dev, SLAVE_ID1, state_reg_add, 0x0,
                                                STATE_MASK);
                if (ret < 0)
@@ -596,7 +601,6 @@ 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)
 {
@@ -614,16 +618,35 @@ static void tps80031_gpio_init(struct tps80031 *tps80031,
 
        /* 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");
+               struct tps80031_gpio_init_data *gpio_pd = &gpio_init_data[i];
+               base_add = pmc_ext_control_base[gpio_pd->gpio_nr];
+
+               if (gpio_pd->ext_ctrl_flag & EXT_PWR_REQ) {
+                       ret = tps80031_ext_power_req_config(tps80031->dev,
+                               gpio_pd->ext_ctrl_flag,
+                               preq_bit_pos[gpio_pd->gpio_nr],
+                               base_add + EXT_CONTROL_CFG_STATE,
+                               base_add + EXT_CONTROL_CFG_TRANS);
+                       if (ret < 0)
+                               dev_warn(tps80031->dev, "Ext pwrreq GPIO "
+                                       "sleep control fails\n");
+               }
+
+               if (gpio_pd->ext_ctrl_flag & PWR_OFF_ON_SLEEP) {
+                       ret = tps80031_update(tps80031->dev, SLAVE_ID1,
+                               base_add + EXT_CONTROL_CFG_TRANS, 0x0, 0xC);
+                       if (ret < 0)
+                               dev_warn(tps80031->dev, "GPIO OFF on sleep "
+                                       "control fails\n");
+               }
+
+               if (gpio_pd->ext_ctrl_flag & PWR_ON_ON_SLEEP) {
+                       ret = tps80031_update(tps80031->dev, SLAVE_ID1,
+                               base_add + EXT_CONTROL_CFG_TRANS, 0x4, 0xC);
+                       if (ret < 0)
+                               dev_warn(tps80031->dev, "GPIO ON on sleep "
+                                       "control fails\n");
+               }
        }
 
        tps80031->gpio.owner            = THIS_MODULE;
@@ -917,20 +940,51 @@ static void tps80031_clk32k_enable(struct tps80031 *tps80031, int base_add)
 static void tps80031_clk32k_init(struct tps80031 *tps80031,
                        struct tps80031_platform_data *pdata)
 {
-       struct tps80031_32kclock_plat_data *clk32k_pdata;
+       int ret;
+       struct tps80031_clk32k_init_data *clk32_idata = pdata->clk32k_init_data;
+       int data_size = pdata->clk32k_init_data_size;
+       static int clk32k_preq_bit_pos[TPS80031_CLOCK32K_NR] = {-1, 20, 19};
+       int base_add;
+       int i;
 
-       if (!(pdata && pdata->clk32k_pdata))
+       if (!clk32_idata || !data_size)
                return;
 
-       clk32k_pdata = pdata->clk32k_pdata;
-       if (clk32k_pdata->en_clk32kao)
-               tps80031_clk32k_enable(tps80031, CLK32KAO_BASE_ADD);
+       /* Configure the external request mode */
+       for (i = 0; i < data_size; ++i) {
+               struct tps80031_clk32k_init_data *clk32_pd =  &clk32_idata[i];
+               base_add = pmc_clk32k_control_base[clk32_pd->clk32k_nr];
+               if (clk32_pd->enable)
+                       tps80031_clk32k_enable(tps80031, base_add);
+
+               if ((clk32_pd->ext_ctrl_flag & EXT_PWR_REQ) &&
+                        (clk32k_preq_bit_pos[clk32_pd->clk32k_nr] != -1)) {
+                       ret = tps80031_ext_power_req_config(tps80031->dev,
+                               clk32_pd->ext_ctrl_flag,
+                               clk32k_preq_bit_pos[clk32_pd->clk32k_nr],
+                               base_add + EXT_CONTROL_CFG_STATE,
+                               base_add + EXT_CONTROL_CFG_TRANS);
+                       if (ret < 0)
+                               dev_warn(tps80031->dev, "Clk32 ext control "
+                                       "fails\n");
+               }
 
-       if (clk32k_pdata->en_clk32kg)
-               tps80031_clk32k_enable(tps80031, CLK32KG_BASE_ADD);
+               if (clk32_pd->ext_ctrl_flag & PWR_OFF_ON_SLEEP) {
+                       ret = tps80031_update(tps80031->dev, SLAVE_ID1,
+                               base_add + EXT_CONTROL_CFG_TRANS, 0x0, 0xC);
+                       if (ret < 0)
+                               dev_warn(tps80031->dev, "clk OFF on sleep "
+                                       "control fails\n");
+               }
 
-       if (clk32k_pdata->en_clk32kaudio)
-               tps80031_clk32k_enable(tps80031, CLK32KAUDIO_BASE_ADD);
+               if (clk32_pd->ext_ctrl_flag & PWR_ON_ON_SLEEP) {
+                       ret = tps80031_update(tps80031->dev, SLAVE_ID1,
+                               base_add + EXT_CONTROL_CFG_TRANS, 0x4, 0xC);
+                       if (ret < 0)
+                               dev_warn(tps80031->dev, "clk ON sleep "
+                                       "control fails\n");
+               }
+       }
 }
 
 static int __devinit tps80031_add_subdevs(struct tps80031 *tps80031,
index 9ea5cb9..deca7ad 100644 (file)
@@ -106,7 +106,7 @@ struct tps80031_regulator {
 
        u8                      flags;
        unsigned int            platform_flags;
-       enum tps80031_ext_control ext_pwr_ctrl;
+       unsigned int            ext_ctrl_flag;
 
        /* used by regulator core */
        struct regulator_desc   desc;
@@ -160,7 +160,7 @@ static int tps80031_reg_is_enabled(struct regulator_dev *rdev)
 {
        struct tps80031_regulator *ri = rdev_get_drvdata(rdev);
 
-       if (ri->ext_pwr_ctrl & EXT_PWR_REQ)
+       if (ri->ext_ctrl_flag & EXT_PWR_REQ)
                return true;
        return ((ri->state_reg_cache & STATE_MASK) == STATE_ON);
 }
@@ -172,7 +172,7 @@ static int tps80031_reg_enable(struct regulator_dev *rdev)
        int ret;
        uint8_t reg_val;
 
-       if (ri->ext_pwr_ctrl & EXT_PWR_REQ)
+       if (ri->ext_ctrl_flag & EXT_PWR_REQ)
                return 0;
 
        reg_val = (ri->state_reg_cache & ~STATE_MASK) |
@@ -194,7 +194,7 @@ static int tps80031_reg_disable(struct regulator_dev *rdev)
        int ret;
        uint8_t reg_val;
 
-       if (ri->ext_pwr_ctrl & EXT_PWR_REQ)
+       if (ri->ext_ctrl_flag & EXT_PWR_REQ)
                return 0;
 
        reg_val = (ri->state_reg_cache & ~STATE_MASK) |
@@ -793,10 +793,12 @@ static int tps80031_power_req_config(struct device *parent,
                struct tps80031_regulator_platform_data *tps80031_pdata)
 {
        int ret;
+       uint8_t reg_val;
+
        if (ri->preq_bit < 0)
                return 0;
 
-       ret = tps80031_ext_power_req_config(parent, ri->ext_pwr_ctrl,
+       ret = tps80031_ext_power_req_config(parent, ri->ext_ctrl_flag,
                        ri->preq_bit, ri->state_reg, ri->trans_reg);
        if (!ret)
                ret = tps80031_read(parent, SLAVE_ID1, ri->trans_reg,
@@ -805,6 +807,25 @@ static int tps80031_power_req_config(struct device *parent,
        if (!ret && ri->state_reg)
                ret = tps80031_read(parent, SLAVE_ID1, ri->state_reg,
                        &ri->state_reg_cache);
+       if (ret < 0) {
+               dev_err(ri->dev, "%s() fails\n", __func__);
+               return ret;
+       }
+
+       if (tps80031_pdata->ext_ctrl_flag &
+                       (PWR_OFF_ON_SLEEP | PWR_ON_ON_SLEEP)) {
+               reg_val = (ri->trans_reg_cache & ~0xC);
+               if (tps80031_pdata->ext_ctrl_flag & PWR_ON_ON_SLEEP)
+                       reg_val |= 0x4;
+
+               ret = tps80031_write(parent, SLAVE_ID1, ri->trans_reg,
+                       reg_val);
+               if (ret < 0)
+                       dev_err(ri->dev, "Not able to write reg 0x%02x\n",
+                               ri->trans_reg);
+               else
+                       ri->trans_reg_cache = reg_val;
+       }
        return ret;
 }
 
@@ -997,7 +1018,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;
+       ri->ext_ctrl_flag = tps_pdata->ext_ctrl_flag;
 
        err = tps80031_cache_regulator_register(pdev->dev.parent, ri);
        if (err) {
index ef5502c..c6aa7ea 100644 (file)
@@ -99,6 +99,15 @@ enum TPS80031_GPIO {
        TPS80031_GPIO_NR,
 };
 
+enum TPS80031_CLOCK32K {
+       TPS80031_CLOCK32K_AO,
+       TPS80031_CLOCK32K_G,
+       TPS80031_CLOCK32K_AUDIO,
+
+       /* Last entry */
+       TPS80031_CLOCK32K_NR,
+};
+
 enum {
        SLAVE_ID0 = 0,
        SLAVE_ID1 = 1,
@@ -113,12 +122,14 @@ enum {
        I2C_ID3_ADDR = 0x4A,
 };
 
-/* External power requests */
+/* External controls 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,
+       PWR_OFF_ON_SLEEP        = 0x00000008,
+       PWR_ON_ON_SLEEP         = 0x00000010,
 };
 
 struct tps80031_subdev_info {
@@ -132,15 +143,15 @@ struct tps80031_rtc_platform_data {
        struct rtc_time time;
 };
 
-struct tps80031_32kclock_plat_data {
-       unsigned en_clk32kao:1;
-       unsigned en_clk32kg:1;
-       unsigned en_clk32kaudio:1;
+struct tps80031_clk32k_init_data {
+       int clk32k_nr;
+       bool enable;
+       unsigned long ext_ctrl_flag;
 };
 
 struct tps80031_gpio_init_data {
        int gpio_nr;
-       enum tps80031_ext_control ext_control;
+       unsigned long ext_ctrl_flag;
 };
 
 struct tps80031_platform_data {
@@ -151,6 +162,8 @@ struct tps80031_platform_data {
        struct tps80031_32kclock_plat_data *clk32k_pdata;
        struct tps80031_gpio_init_data *gpio_init_data;
        int gpio_init_data_size;
+       struct tps80031_clk32k_init_data *clk32k_init_data;
+       int clk32k_init_data_size;
 };
 
 struct tps80031_bg_platform_data {
@@ -177,7 +190,7 @@ extern int tps80031_update(struct device *dev, int sid, int reg, uint8_t val,
 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,
+               unsigned long ext_ctrl_flag, int preq_bit,
                int state_reg_add, int trans_reg_add);
 
 extern int tps80031_power_off(void);
index d84a8c4..1670d14 100644 (file)
@@ -70,7 +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.
+ * @ext_ctrl_flag: External control flag for sleep/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.
@@ -81,7 +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 ext_ctrl_flag;
        unsigned int flags;
        int delay_us;
 };