mfd: tps80031: add option to enable internal pullup or pulldown
Tom Cherry [Fri, 23 Mar 2012 20:55:52 +0000 (13:55 -0700)]
Bug 958089

(cherry-picked from commit 7f4c6d6b9dd2b06984b59dcd60d92026cab4c87c)
Reviewed-on: http://git-master/r/92053

Change-Id: I0f2bdb5482fdcb508808d2d58771d74a05b5597f
Signed-off-by: Tom Cherry <tcherry@nvidia.com>
Reviewed-on: http://git-master/r/94117
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com>

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

index fb6ff3b..e8ea75c 100644 (file)
 #define TPS80031_PREQ3_RES_ASS_A       0xDD
 #define TPS80031_PHOENIX_MSK_TRANSITION 0x20
 
+#define TPS80031_CFG_INPUT_PUPD1 0xF0
+#define TPS80031_CFG_INPUT_PUPD2 0xF1
+#define TPS80031_CFG_INPUT_PUPD3 0xF2
+#define TPS80031_CFG_INPUT_PUPD4 0xF3
+
+struct tps80031_pupd_data {
+       u8      reg;
+       u8      pullup_bit;
+       u8      pulldown_bit;
+};
 
 static u8 pmc_ext_control_base[] = {
        REGEN1_BASE_ADD,
@@ -183,6 +193,31 @@ static const struct tps80031_irq_data tps80031_irqs[] = {
                                                MLINCH_GATED,   LINCH_GATED),
 };
 
+#define PUPD_DATA(_reg, _pulldown_bit, _pullup_bit)    \
+       {                                               \
+               .reg = TPS80031_CFG_INPUT_PUPD##_reg,   \
+               .pulldown_bit = _pulldown_bit,          \
+               .pullup_bit = _pullup_bit,              \
+       }
+
+static const struct tps80031_pupd_data tps80031_pupds[] = {
+       [TPS80031_PREQ1]                = PUPD_DATA(1, 1 << 0,  1 << 1  ),
+       [TPS80031_PREQ2A]               = PUPD_DATA(1, 1 << 2,  1 << 3  ),
+       [TPS80031_PREQ2B]               = PUPD_DATA(1, 1 << 4,  1 << 5  ),
+       [TPS80031_PREQ2C]               = PUPD_DATA(1, 1 << 6,  1 << 7  ),
+       [TPS80031_PREQ3]                = PUPD_DATA(2, 1 << 0,  1 << 1  ),
+       [TPS80031_NRES_WARM]            = PUPD_DATA(2, 0,       1 << 2  ),
+       [TPS80031_PWM_FORCE]            = PUPD_DATA(2, 1 << 5,  0       ),
+       [TPS80031_CHRG_EXT_CHRG_STATZ]  = PUPD_DATA(2, 0,       1 << 6  ),
+       [TPS80031_SIM]                  = PUPD_DATA(3, 1 << 0,  1 << 1  ),
+       [TPS80031_MMC]                  = PUPD_DATA(3, 1 << 2,  1 << 3  ),
+       [TPS80031_GPADC_START]          = PUPD_DATA(3, 1 << 4,  0       ),
+       [TPS80031_DVSI2C_SCL]           = PUPD_DATA(4, 0,       1 << 0  ),
+       [TPS80031_DVSI2C_SDA]           = PUPD_DATA(4, 0,       1 << 1  ),
+       [TPS80031_CTLI2C_SCL]           = PUPD_DATA(4, 0,       1 << 2  ),
+       [TPS80031_CTLI2C_SDA]           = PUPD_DATA(4, 0,       1 << 3  ),
+};
+
 static const int controller_stat1_irq_nr[] = {
        TPS80031_INT_BAT_TEMP_OVRANGE,
        TPS80031_INT_BAT_REMOVED,
@@ -509,6 +544,30 @@ static void tps80031_power_off(void)
        __tps80031_write(tps->client, TPS80031_PHOENIX_DEV_ON, DEVOFF);
 }
 
+static void tps80031_pupd_init(struct tps80031 *tps80031,
+                              struct tps80031_platform_data *pdata)
+{
+       struct tps80031_pupd_init_data *pupd_init_data = pdata->pupd_init_data;
+       int data_size = pdata->pupd_init_data_size;
+       int i;
+
+       for (i = 0; i < data_size; ++i) {
+               struct tps80031_pupd_init_data *pupd_init = &pupd_init_data[i];
+               const struct tps80031_pupd_data *pupd =
+                       &tps80031_pupds[pupd_init->input_pin];
+               u8 update_value = 0;
+               u8 update_mask = pupd->pulldown_bit | pupd->pullup_bit;
+
+               if (pupd_init->setting == TPS80031_PUPD_PULLDOWN)
+                       update_value = pupd->pulldown_bit;
+               else if (pupd_init->setting == TPS80031_PUPD_PULLUP)
+                       update_value = pupd->pullup_bit;
+
+               tps80031_update(tps80031->dev, SLAVE_ID1, pupd->reg,
+                               update_value, update_mask);
+       }
+}
+
 static void tps80031_init_ext_control(struct tps80031 *tps80031,
                        struct tps80031_platform_data *pdata) {
        int ret;
@@ -1197,6 +1256,9 @@ static int __devinit tps80031_i2c_probe(struct i2c_client *client,
                        goto fail;
                }
        }
+
+       tps80031_pupd_init(tps80031, pdata);
+
        tps80031_init_ext_control(tps80031, pdata);
 
        ret = tps80031_add_subdevs(tps80031, pdata);
index 1802dfe..9623a87 100644 (file)
@@ -132,6 +132,30 @@ enum tps80031_ext_control {
        PWR_ON_ON_SLEEP         = 0x00000010,
 };
 
+enum tps80031_pupd_pins {
+       TPS80031_PREQ1 = 0,
+       TPS80031_PREQ2A,
+       TPS80031_PREQ2B,
+       TPS80031_PREQ2C,
+       TPS80031_PREQ3,
+       TPS80031_NRES_WARM,
+       TPS80031_PWM_FORCE,
+       TPS80031_CHRG_EXT_CHRG_STATZ,
+       TPS80031_SIM,
+       TPS80031_MMC,
+       TPS80031_GPADC_START,
+       TPS80031_DVSI2C_SCL,
+       TPS80031_DVSI2C_SDA,
+       TPS80031_CTLI2C_SCL,
+       TPS80031_CTLI2C_SDA,
+};
+
+enum tps80031_pupd_settings {
+       TPS80031_PUPD_NORMAL,
+       TPS80031_PUPD_PULLDOWN,
+       TPS80031_PUPD_PULLUP,
+};
+
 struct tps80031_subdev_info {
        int             id;
        const char      *name;
@@ -154,6 +178,11 @@ struct tps80031_gpio_init_data {
        unsigned long ext_ctrl_flag;
 };
 
+struct tps80031_pupd_init_data {
+       int input_pin;
+       int setting;
+};
+
 struct tps80031_platform_data {
        int num_subdevs;
        struct tps80031_subdev_info *subdevs;
@@ -165,6 +194,8 @@ struct tps80031_platform_data {
        struct tps80031_clk32k_init_data *clk32k_init_data;
        int clk32k_init_data_size;
        bool use_power_off;
+       struct tps80031_pupd_init_data *pupd_init_data;
+       int pupd_init_data_size;
 };
 
 struct tps80031_bg_platform_data {