pinctrl: palmas: add pincontrol driver support
Laxman Dewangan [Fri, 15 Mar 2013 13:41:06 +0000 (18:41 +0530)]
Palmas series PMIC has the pins which can work on multiple mode.
Also the pull up/down, open drain can be configured on this pins.

Add pin control driver to configure the different pads.

bug 1242260

Change-Id: I8b9f51f9799783a2e8c4f2345d63a02627a8cff6
Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Reviewed-on: http://git-master/r/209983
Reviewed-by: Naveen Kumar S <nkumars@nvidia.com>
Tested-by: Naveen Kumar S <nkumars@nvidia.com>
GVS: Gerrit_Virtual_Submit

arch/arm/mach-tegra/Kconfig
drivers/pinctrl/Kconfig
drivers/pinctrl/Makefile
drivers/pinctrl/pinctrl-palmas.c [new file with mode: 0644]
include/linux/mfd/palmas.h

index 264aaf4..02af574 100644 (file)
@@ -122,6 +122,7 @@ config ARCH_TEGRA_11x_SOC
        select TEGRA_LATENCY_ALLOWANCE if !TEGRA_FPGA_PLATFORM
        select TEGRA_MC_PTSA if !TEGRA_FPGA_PLATFORM
        select SOC_BUS
+       select PINCTRL
        select TEGRA_ISOMGR
        select TEGRA_ISOMGR_SYSFS
        select TEGRA_ISOMGR_DEBUG
index 0e890f7..05629c0 100644 (file)
@@ -89,6 +89,17 @@ config PINCTRL_COH901
          COH 901 335 and COH 901 571/3. They contain 3, 5 or 7
          ports of 8 GPIO pins each.
 
+config PINCTRL_PALMAS
+       tristate "PALMAS Pincontrol support"
+       depends on MFD_PALMAS
+       help
+         PALMAS is a PMIC series from TI for smartphone and tablets. This PMIC
+         has some pins i.e. named as GPIOx which can be act as GPIO or in
+         alternate mode for special functionality. Also these pins can be
+         configured for open drain, pullup, pull down etc.
+         Say yes here to get support for pinmux configuration for this PMIC
+         device.
+
 endmenu
 
 endif
index 530fd0c..aa52bb1 100644 (file)
@@ -21,3 +21,4 @@ obj-$(CONFIG_PINCTRL_TEGRA30) += pinctrl-tegra30.o
 obj-$(CONFIG_PINCTRL_TEGRA114) += pinctrl-tegra114.o
 obj-$(CONFIG_PINCTRL_U300)     += pinctrl-u300.o
 obj-$(CONFIG_PINCTRL_COH901)   += pinctrl-coh901.o
+obj-$(CONFIG_PINCTRL_PALMAS)   += pinctrl-palmas.o
diff --git a/drivers/pinctrl/pinctrl-palmas.c b/drivers/pinctrl/pinctrl-palmas.c
new file mode 100644 (file)
index 0000000..82d0c2b
--- /dev/null
@@ -0,0 +1,500 @@
+/*
+ * pinctrl-palmas.c -- TI PALMAS series pin control driver.
+ *
+ * Copyright (c) 2013, NVIDIA Corporation.
+ *
+ * Author: Laxman Dewangan <ldewangan@nvidia.com>
+ *
+ * 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 Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
+ * whether express or implied; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307, USA
+ */
+#include <linux/delay.h>
+#include <linux/mfd/palmas.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/slab.h>
+
+struct palmas_pinctrl {
+       struct device   *dev;
+       struct palmas   *palmas;
+};
+
+struct palmas_pins_pullup_dn_info {
+       int pullup_dn_reg_base;
+       int pullup_dn_reg_add;
+       int pullup_dn_mask;
+       int normal_val;
+       int pull_up_val;
+       int pull_dn_val;
+};
+
+struct palmas_pins_od_info {
+       int od_reg_base;
+       int od_reg_add;
+       int od_mask;
+       int od_enable;
+       int od_disable;
+};
+
+struct palmas_pin_info {
+       int mux_opt;
+       struct palmas_pins_pullup_dn_info *pud_info;
+       struct palmas_pins_od_info *od_info;
+};
+
+struct palmas_pinctrl_info {
+       const char *pin_name;
+       int pin_id;
+       int pin_rg_base;
+       int pin_reg_add;
+       int pin_reg_mask;
+       int pin_bit_shift;
+       struct palmas_pin_info *opt1;
+       struct palmas_pin_info *opt2;
+       struct palmas_pin_info *opt3;
+       struct palmas_pin_info *opt4;
+};
+
+#define PALMAS_NONE_BASE       -1
+
+#define PULL_UP_DN(_name, _rbase, _add, _mask, _nv, _uv, _dv)  \
+static struct palmas_pins_pullup_dn_info pu_pd_##_name##_info = {      \
+       .pullup_dn_reg_base = PALMAS_##_rbase##_BASE,           \
+       .pullup_dn_reg_add = _add,                              \
+       .pullup_dn_mask = _mask,                                \
+       .normal_val = _nv,                                      \
+       .pull_up_val = _uv,                                     \
+       .pull_dn_val = _dv,                                     \
+}
+
+PULL_UP_DN(NRESWARM, PU_PD_OD, 0x0, 0x2, 0x0, 0x2, -1);
+PULL_UP_DN(PWRDOWN, PU_PD_OD, 0x0, 0x4, 0x0, -1, 0x4);
+PULL_UP_DN(GPADC_START, PU_PD_OD, 0x0, 0x30, 0x0, 0x20, 0x10);
+PULL_UP_DN(RESET_IN, PU_PD_OD, 0x0, 0x40, 0x0, -1, 0x40);
+PULL_UP_DN(NSLEEP, PU_PD_OD, 0x1, 0x3, 0x0, 0x2, 0x1);
+PULL_UP_DN(ENABLE1, PU_PD_OD, 0x1, 0xC, 0x0, 0x8, 0x4);
+PULL_UP_DN(ENABLE2, PU_PD_OD, 0x1, 0x30, 0x0, 0x20, 0x10);
+PULL_UP_DN(VACOK, PU_PD_OD, 0x2, 0x40, 0x0, -1, 0x40);
+PULL_UP_DN(CHRG_DET, PU_PD_OD, 0x2, 0x10, 0x0, -1, 0x10);
+PULL_UP_DN(PWRHOLD, PU_PD_OD, 0x2, 0x4, 0x0, -1, 0x4);
+PULL_UP_DN(MSECURE, PU_PD_OD, 0x2, 0x1, 0x0, -1, 0x1);
+PULL_UP_DN(GPIO0, GPIO, 0x06, 0x04, 0, -1, 1);
+PULL_UP_DN(GPIO1, GPIO, 0x06, 0x0C, 0, 0x8, 0x4);
+PULL_UP_DN(GPIO2, GPIO, 0x06, 0x30, 0x0, 0x20, 0x10);
+PULL_UP_DN(GPIO3, GPIO, 0x06, 0x40, 0x0, -1, 0x40);
+PULL_UP_DN(GPIO4, GPIO, 0x07, 0x03, 0x0, 0x2, 0x1);
+PULL_UP_DN(GPIO5, GPIO, 0x07, 0x0c, 0x0, 0x8, 0x4);
+PULL_UP_DN(GPIO6, GPIO, 0x07, 0x30, 0x0, 0x20, 0x10);
+PULL_UP_DN(GPIO7, GPIO, 0x07, 0x40, 0x0, -1, 0x40);
+
+#define OD_INFO(_name, _rbase, _add, _mask, _ev, _dv)          \
+static struct palmas_pins_od_info od_##_name##_info = {                \
+       .od_reg_base = PALMAS_##_rbase##_BASE,                  \
+       .od_reg_add = _add,                                     \
+       .od_mask = _mask,                                       \
+       .od_enable = _ev,                                       \
+       .od_disable = _dv,                                      \
+}
+
+OD_INFO(GPIO1, GPIO, 0x8, 0x1, 0x1, 0x0);
+OD_INFO(GPIO2, GPIO, 0x8, 0x2, 0x2, 0x0);
+OD_INFO(GPIO5, GPIO, 0x8, 0x20, 0x20, 0x0);
+OD_INFO(INT, PU_PD_OD, 0x4, 0x8, 0x8, 0x0);
+OD_INFO(PWM1, PU_PD_OD, 0x4, 0x20, 0x20, 0x0);
+OD_INFO(VBUS_DET, PU_PD_OD, 0x4, 0x40, 0x40, 0x0);
+OD_INFO(PWM2, PU_PD_OD, 0x4, 0x80, 0x80, 0x0);
+
+#define PIN_INFO(_name, _id, _pud_info, _od_info)              \
+static struct palmas_pin_info pin_##_name##_info = {           \
+       .mux_opt = PALMAS_PINMUX_##_id,                         \
+       .pud_info = _pud_info,                                  \
+       .od_info = _od_info                                     \
+}
+
+PIN_INFO(GPIO0,                GPIO,           &pu_pd_GPIO0_info,      NULL);
+PIN_INFO(GPIO1,                GPIO,           &pu_pd_GPIO1_info,      &od_GPIO1_info);
+PIN_INFO(GPIO2,                GPIO,           &pu_pd_GPIO2_info,      &od_GPIO2_info);
+PIN_INFO(GPIO3,                GPIO,           &pu_pd_GPIO3_info,      NULL);
+PIN_INFO(GPIO4,                GPIO,           &pu_pd_GPIO4_info,      NULL);
+PIN_INFO(GPIO5,                GPIO,           &pu_pd_GPIO5_info,      &od_GPIO5_info);
+PIN_INFO(GPIO6,                GPIO,           &pu_pd_GPIO6_info,      NULL);
+PIN_INFO(GPIO7,                GPIO,           &pu_pd_GPIO7_info,      NULL);
+PIN_INFO(ID,           ID,             NULL,                   NULL);
+PIN_INFO(LED1,         LED,            NULL,                   NULL);
+PIN_INFO(LED2,         LED,            NULL,                   NULL);
+PIN_INFO(REGEN,                REGEN,          NULL,                   NULL);
+PIN_INFO(SYSEN1,       SYSEN,          NULL,                   NULL);
+PIN_INFO(SYSEN2,       SYSEN,          NULL,                   NULL);
+PIN_INFO(INT,          INT,            NULL,                   &od_INT_info);
+PIN_INFO(PWM1,         PWM,            NULL,                   &od_PWM1_info);
+PIN_INFO(PWM2,         PWM,            NULL,                   &od_PWM2_info);
+PIN_INFO(VACOK,                VACOK,          &pu_pd_VACOK_info,      NULL);
+PIN_INFO(CHRG_DET,     CHRG_DET,       &pu_pd_CHRG_DET_info,   NULL);
+PIN_INFO(PWRHOLD,      PWRHOLD,        &pu_pd_PWRHOLD_info,    NULL);
+PIN_INFO(MSECURE,      MSECURE,        &pu_pd_MSECURE_info,    NULL);
+PIN_INFO(NRESWARM,     RESVD,          &pu_pd_NRESWARM_info,   NULL);
+PIN_INFO(PWRDOWN,      RESVD,          &pu_pd_PWRDOWN_info,    NULL);
+PIN_INFO(GPADC_START,  RESVD,          &pu_pd_GPADC_START_info, NULL);
+PIN_INFO(RESET_IN,     RESVD,          &pu_pd_RESET_IN_info,   NULL);
+PIN_INFO(NSLEEP,       RESVD,          &pu_pd_NSLEEP_info,     NULL);
+PIN_INFO(ENABLE1,      RESVD,          &pu_pd_ENABLE1_info,    NULL);
+PIN_INFO(ENABLE2,      RESVD,          &pu_pd_ENABLE2_info,    NULL);
+PIN_INFO(CLK32KGAUDIO, CLK32KGAUDIO,   NULL,                   NULL);
+PIN_INFO(USB_PSEL,     USB_PSEL,       NULL,                   NULL);
+PIN_INFO(VAC,          VAC,            NULL,                   NULL);
+PIN_INFO(POWERGOOD,    POWERGOOD,      NULL,                   NULL);
+PIN_INFO(VBUS_DET,     VBUS_DET,       NULL,           &od_VBUS_DET_info);
+
+#define PALMAS_PIN(_pin, _rbase, _add, _mask, _bshift, o1, o2, o3, o4) \
+[PALMAS_PIN_NAME_##_pin] = {                                   \
+               .pin_name = "palmas_pin_"#_pin,                 \
+               .pin_id = PALMAS_PIN_NAME_##_pin,               \
+               .pin_rg_base = PALMAS_##_rbase##_BASE,          \
+               .pin_reg_add = _add,                            \
+               .pin_reg_mask = _mask,                          \
+               .pin_bit_shift = _bshift,                       \
+               .opt1 = o1,                                     \
+               .opt2 = o2,                                     \
+               .opt3 = o3,                                     \
+               .opt4 = o4,                                     \
+}
+
+static struct palmas_pinctrl_info palmas_pinctrl_info[PALMAS_PIN_NAME_MAX] = {
+       PALMAS_PIN(GPIO0, PU_PD_OD, 0x6, 0x04, 0x2,
+               &pin_GPIO0_info, &pin_ID_info, NULL, NULL),
+       PALMAS_PIN(GPIO1, PU_PD_OD, 0x6, 0x18, 0x3,
+               &pin_GPIO1_info, &pin_VBUS_DET_info, &pin_LED1_info,
+               &pin_PWM1_info),
+       PALMAS_PIN(GPIO2, PU_PD_OD, 0x6, 0x60, 0x5,
+               &pin_GPIO2_info, &pin_REGEN_info, &pin_LED2_info,
+               &pin_PWM2_info),
+       PALMAS_PIN(GPIO3, PU_PD_OD, 0x6, 0x80, 0x7,
+               &pin_GPIO3_info, &pin_CHRG_DET_info, NULL, NULL),
+       PALMAS_PIN(GPIO4, PU_PD_OD, 0x7, 0x01, 0x0,
+               &pin_GPIO4_info, &pin_SYSEN1_info, NULL, NULL),
+       PALMAS_PIN(GPIO5, PU_PD_OD, 0x7, 0x06, 0x1,
+               &pin_GPIO5_info, &pin_CLK32KGAUDIO_info, &pin_USB_PSEL_info,
+               NULL),
+       PALMAS_PIN(GPIO6, PU_PD_OD, 0x7, 0x8, 3,
+                &pin_GPIO6_info, &pin_SYSEN2_info, NULL, NULL),
+       PALMAS_PIN(GPIO7, PU_PD_OD, 0x7, 0x30, 4,
+               &pin_GPIO7_info, &pin_MSECURE_info, &pin_PWRHOLD_info, NULL),
+       PALMAS_PIN(VAC, PU_PD_OD, 0x6, 0x2, 1,
+               &pin_VAC_info, &pin_VACOK_info, NULL, NULL),
+       PALMAS_PIN(POWERGOOD, PU_PD_OD, 0x6, 0x1, 0,
+               &pin_POWERGOOD_info, &pin_USB_PSEL_info, NULL, NULL),
+       PALMAS_PIN(NRESWARM, NONE, 0, 0, 0,
+               &pin_NRESWARM_info, NULL, NULL, NULL),
+       PALMAS_PIN(PWRDOWN, NONE, 0, 0, 0,
+               &pin_PWRDOWN_info, NULL, NULL, NULL),
+       PALMAS_PIN(GPADC_START, NONE, 0, 0, 0,
+               &pin_GPADC_START_info, NULL, NULL, NULL),
+       PALMAS_PIN(RESET_IN, NONE, 0, 0, 0,
+               &pin_RESET_IN_info, NULL, NULL, NULL),
+       PALMAS_PIN(NSLEEP, NONE, 0, 0, 0,
+               &pin_NSLEEP_info, NULL, NULL, NULL),
+       PALMAS_PIN(ENABLE1, NONE, 0, 0, 0,
+               &pin_ENABLE1_info, NULL, NULL, NULL),
+       PALMAS_PIN(ENABLE2, NONE, 0, 0, 0,
+               &pin_ENABLE2_info, NULL, NULL, NULL),
+       PALMAS_PIN(INT, NONE, 0, 0, 0,
+               &pin_INT_info, NULL, NULL, NULL),
+};
+
+static int palmas_set_single_pin_config(struct palmas_pinctrl *pinctrl,
+       struct palmas_pinctrl_config *muxcfg)
+{
+       int pin_id = muxcfg->pin_name;
+       int pin_option = muxcfg->pin_mux_option;
+       int pull_up_dn = muxcfg->pin_pull_up_dn;
+       int od_config = muxcfg->open_drain_state;
+       struct palmas_pin_info *opt;
+       struct palmas_pinctrl_info *pin_cfg;
+       struct palmas_pins_pullup_dn_info *pud_info;
+       struct palmas_pins_od_info *od_info;
+       int opt_nr;
+       int ret = 0;
+       int val;
+
+       if ((pin_id < 0) || (pin_id >= PALMAS_PIN_NAME_MAX)) {
+               dev_err(pinctrl->dev, "Pin id %d is out of range\n", pin_id);
+               return -EINVAL;
+       }
+
+       pin_cfg = &palmas_pinctrl_info[pin_id];
+       if (pin_id != pin_cfg->pin_id) {
+               dev_err(pinctrl->dev,
+                       "Pin Config table for pin %s is out of sync\n",
+                       pin_cfg->pin_name);
+               return -EINVAL;
+       }
+
+       opt = NULL;
+       opt_nr = -1;
+       if (pin_cfg->opt1 && (pin_cfg->opt1->mux_opt == pin_option)) {
+               opt = pin_cfg->opt1;
+               opt_nr = 0;
+       } else if (pin_cfg->opt2 && (pin_cfg->opt2->mux_opt == pin_option)) {
+               opt = pin_cfg->opt2;
+               opt_nr = 1;
+       } else if (pin_cfg->opt3 && (pin_cfg->opt3->mux_opt == pin_option)) {
+               opt = pin_cfg->opt3;
+               opt_nr = 2;
+       } else if (pin_cfg->opt4 && (pin_cfg->opt4->mux_opt == pin_option)) {
+               opt = pin_cfg->opt4;
+               opt_nr = 1;
+       }
+
+       if (!opt) {
+               dev_err(pinctrl->dev, "Pin %s does not have pinmux option %d\n",
+                       pin_cfg->pin_name, pin_option);
+               return -EINVAL;
+       }
+
+       if (pin_cfg->pin_rg_base == PALMAS_NONE_BASE)
+               goto skip_pinmux_config;
+
+       ret = palmas_update_bits(pinctrl->palmas, pin_cfg->pin_rg_base,
+                       pin_cfg->pin_reg_add, pin_cfg->pin_reg_mask,
+                       opt_nr << pin_cfg->pin_bit_shift);
+       if (ret < 0) {
+               dev_err(pinctrl->dev, "Reg 0x%03x update failed, %d\n",
+                       pin_cfg->pin_rg_base + pin_cfg->pin_reg_add, ret);
+               return ret;
+       }
+
+skip_pinmux_config:
+       pud_info = opt->pud_info;
+       if (pull_up_dn == PALMAS_PIN_CONFIG_DEFAULT)
+               goto skip_pud_config;
+
+       if (pud_info->pullup_dn_reg_base == PALMAS_NONE_BASE) {
+               dev_err(pinctrl->dev, "Pin %s up/dn option not available\n",
+                       pin_cfg->pin_name);
+               return -EINVAL;
+       }
+
+       switch (pull_up_dn) {
+       case PALMAS_PIN_CONFIG_NORMAL:
+               val = pud_info->normal_val;
+               break;
+       case PALMAS_PIN_CONFIG_PULL_UP:
+               val = pud_info->pull_up_val;
+               break;
+       case PALMAS_PIN_CONFIG_PULL_DOWN:
+               val = pud_info->pull_dn_val;
+               break;
+       default:
+               dev_err(pinctrl->dev, "Invalid option of pull-up-dn %d\n",
+                       pull_up_dn);
+               return -EINVAL;
+       }
+       if (val == -1) {
+               dev_err(pinctrl->dev,
+                       "Pull up/dn option %d is not supported\n", pull_up_dn);
+               return -EINVAL;
+       }
+
+       ret = palmas_update_bits(pinctrl->palmas, pud_info->pullup_dn_reg_base,
+                       pud_info->pullup_dn_reg_add, pud_info->pullup_dn_mask,
+                       val);
+       if (ret < 0) {
+               dev_err(pinctrl->dev, "reg 0x%03x update failed %d\n",
+                       pud_info->pullup_dn_reg_base +
+                               pud_info->pullup_dn_reg_add, ret);
+               return ret;
+       }
+
+skip_pud_config:
+       od_info = opt->od_info;
+       if (od_config == PALMAS_PIN_CONFIG_OD_DEFAULT)
+               goto skip_od_config;
+
+       switch (od_config) {
+       case PALMAS_PIN_CONFIG_OD_ENABLE:
+               val = opt->od_info->od_enable;
+               break;
+       case PALMAS_PIN_CONFIG_OD_DISABLE:
+               val = opt->od_info->od_disable;
+               break;
+       default:
+               dev_err(pinctrl->dev, "Invalid option of OD %d\n", od_config);
+               return -EINVAL;
+       }
+
+       if (opt->od_info->od_reg_base == PALMAS_NONE_BASE) {
+               dev_err(pinctrl->dev, "Pin %s OD option not available\n",
+                       pin_cfg->pin_name);
+               return -EINVAL;
+       }
+
+       ret = palmas_update_bits(pinctrl->palmas, od_info->od_reg_base,
+               od_info->od_reg_add, od_info->od_mask, val);
+       if (ret < 0) {
+               dev_err(pinctrl->dev, "Reg 0x%03x update failed. %d\n",
+                       od_info->od_reg_base + od_info->od_reg_add, ret);
+               return ret;
+       }
+
+skip_od_config:
+       return ret;
+}
+
+static int palmas_set_dvfs1(struct palmas_pinctrl *pinctrl, bool enable)
+{
+       int ret;
+       int val;
+
+       val = (enable) ? PALMAS_PRIMARY_SECONDARY_PAD3_DVFS1 : 0;
+       ret = palmas_update_bits(pinctrl->palmas, PALMAS_PU_PD_OD_BASE,
+                       PALMAS_PRIMARY_SECONDARY_PAD3,
+                       PALMAS_PRIMARY_SECONDARY_PAD3_DVFS1, val);
+       if (ret < 0)
+               dev_err(pinctrl->dev, "SECONDARY_PAD3 update failed %d\n", ret);
+       return ret;
+}
+
+static int palmas_set_dvfs2(struct palmas_pinctrl *pinctrl, bool enable)
+{
+       int ret;
+       int val;
+
+       val = (enable) ? PALMAS_PRIMARY_SECONDARY_PAD3_DVFS2 : 0;
+       ret = palmas_update_bits(pinctrl->palmas, PALMAS_PU_PD_OD_BASE,
+                       PALMAS_PRIMARY_SECONDARY_PAD3,
+                       PALMAS_PRIMARY_SECONDARY_PAD3_DVFS2, val);
+       if (ret < 0)
+               dev_err(pinctrl->dev, "SECONDARY_PAD3 update failed %d\n", ret);
+       return ret;
+}
+
+static int __devinit palmas_pinctrl_probe(struct platform_device *pdev)
+{
+       struct palmas_platform_data *pdata;
+       struct palmas_pinctrl_platform_data *pctrl_pdata;
+       struct palmas_pinctrl *pinctrl;
+       struct palmas *palmas = dev_get_drvdata(pdev->dev.parent);
+       int i;
+       int ret;
+       unsigned int reg;
+
+       pdata = dev_get_platdata(pdev->dev.parent);
+       if (!pdata || !pdata->pinctrl_pdata) {
+               dev_err(&pdev->dev, "No Platform data\n");
+               return -EINVAL;
+       }
+
+       pinctrl = devm_kzalloc(&pdev->dev, sizeof(*pinctrl), GFP_KERNEL);
+       if (!pinctrl) {
+               dev_err(&pdev->dev, "Memory allocation for pinctrl failed\n");
+               return -ENOMEM;
+       }
+
+       pinctrl->dev = &pdev->dev;
+       pinctrl->palmas = palmas;
+       pctrl_pdata = pdata->pinctrl_pdata;
+       for (i = 0; i < pctrl_pdata->num_pinctrl; ++i) {
+               struct palmas_pinctrl_config *pcfg =  &pctrl_pdata->pincfg[i];
+
+               palmas_set_single_pin_config(pinctrl, pcfg);
+       }
+
+       palmas_set_dvfs1(pinctrl, pctrl_pdata->dvfs1_enable);
+       palmas_set_dvfs2(pinctrl, pctrl_pdata->dvfs2_enable);
+
+       /* PAD1 muxing */
+       ret = palmas_read(pinctrl->palmas, PALMAS_PU_PD_OD_BASE,
+                               PALMAS_PRIMARY_SECONDARY_PAD1, &reg);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "SECONDARY_PAD1 read failed %d\n", ret);
+               return ret;
+       }
+       if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_0))
+               palmas->gpio_muxed |= PALMAS_GPIO_0_MUXED;
+       if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_MASK))
+               palmas->gpio_muxed |= PALMAS_GPIO_1_MUXED;
+       else if ((reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_MASK) ==
+                       (2 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_SHIFT))
+               palmas->led_muxed |= PALMAS_LED1_MUXED;
+       else if ((reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_MASK) ==
+                       (3 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_SHIFT))
+               palmas->pwm_muxed |= PALMAS_PWM1_MUXED;
+       if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_MASK))
+               palmas->gpio_muxed |= PALMAS_GPIO_2_MUXED;
+       else if ((reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_MASK) ==
+                       (2 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_SHIFT))
+               palmas->led_muxed |= PALMAS_LED2_MUXED;
+       else if ((reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_MASK) ==
+                       (3 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_SHIFT))
+               palmas->pwm_muxed |= PALMAS_PWM2_MUXED;
+       if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_3))
+               palmas->gpio_muxed |= PALMAS_GPIO_3_MUXED;
+
+       /* PAD2 muxing */
+       ret = palmas_read(pinctrl->palmas, PALMAS_PU_PD_OD_BASE,
+                               PALMAS_PRIMARY_SECONDARY_PAD2, &reg);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "SECONDARY_PAD2 read failed %d\n", ret);
+               return ret;
+       }
+       if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_4))
+               palmas->gpio_muxed |= PALMAS_GPIO_4_MUXED;
+       if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_5_MASK))
+               palmas->gpio_muxed |= PALMAS_GPIO_5_MUXED;
+       if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_6))
+               palmas->gpio_muxed |= PALMAS_GPIO_6_MUXED;
+       if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_7_MASK))
+               palmas->gpio_muxed |= PALMAS_GPIO_7_MUXED;
+
+       /* PAD3 muxing */
+       ret = palmas_read(pinctrl->palmas, PALMAS_PU_PD_OD_BASE,
+                               PALMAS_PRIMARY_SECONDARY_PAD3, &reg);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "SECONDARY_PAD3 read failed %d\n", ret);
+               return ret;
+       }
+       if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD3_DVFS2))
+               palmas->gpio_muxed |= PALMAS_GPIO_6_MUXED;
+
+       dev_info(palmas->dev, "Muxing GPIO %x, PWM %x, LED %x\n",
+               palmas->gpio_muxed, palmas->pwm_muxed, palmas->led_muxed);
+
+       return 0;
+}
+
+static struct platform_driver palmas_pinctrl_driver = {
+       .probe = palmas_pinctrl_probe,
+       .driver = {
+               .name = "palmas-pinctrl",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init palmas_pinctrl_init(void)
+{
+       return platform_driver_register(&palmas_pinctrl_driver);
+}
+subsys_initcall(palmas_pinctrl_init);
+
+static void __exit palmas_pinctrl_exit(void)
+{
+       platform_driver_unregister(&palmas_pinctrl_driver);
+}
+module_exit(palmas_pinctrl_exit);
+
+MODULE_DESCRIPTION("palmas pin control driver");
+MODULE_AUTHOR("Laxman Dewangan<ldewangan@nvidia.com>");
+MODULE_ALIAS("platform:palmas-pinctrl");
+MODULE_LICENSE("GPL v2");
index 8fd2ae1..bb4270e 100644 (file)
@@ -207,6 +207,20 @@ struct palmas_gpadc_platform_data {
        int channel3_current_uA;
 };
 
+struct palmas_pinctrl_config {
+       int pin_name;
+       int pin_mux_option;
+       int open_drain_state;
+       int pin_pull_up_dn;
+};
+
+struct palmas_pinctrl_platform_data {
+       struct palmas_pinctrl_config *pincfg;
+       int num_pinctrl;
+       bool dvfs1_enable;
+       bool dvfs2_enable;
+};
+
 struct palmas_platform_data {
        int gpio_base;
        int irq_base;
@@ -230,6 +244,8 @@ struct palmas_platform_data {
        int clk32k_init_data_size;
        bool use_power_off;
 
+       struct palmas_pinctrl_platform_data *pinctrl_pdata;
+
        int watchdog_timer_initial_period;
 };
 
@@ -2785,6 +2801,73 @@ enum {
        PALMAS_SLEEP_REQSTR_ID_MAX,
 };
 
+/* Palmas Pinmux option */
+enum {
+       PALMAS_PINMUX_GPIO = 0,
+       PALMAS_PINMUX_LED,
+       PALMAS_PINMUX_PWM,
+       PALMAS_PINMUX_REGEN,
+       PALMAS_PINMUX_SYSEN,
+       PALMAS_PINMUX_CLK32KGAUDIO,
+       PALMAS_PINMUX_ID,
+       PALMAS_PINMUX_VBUS_DET,
+       PALMAS_PINMUX_CHRG_DET,
+       PALMAS_PINMUX_VAC,
+       PALMAS_PINMUX_VACOK,
+       PALMAS_PINMUX_POWERGOOD,
+       PALMAS_PINMUX_USB_PSEL,
+       PALMAS_PINMUX_MSECURE,
+       PALMAS_PINMUX_PWRHOLD,
+       PALMAS_PINMUX_INT,
+       PALMAS_PINMUX_DVFS2,
+       PALMAS_PINMUX_DVFS1,
+       PALMAS_PINMUX_NRESWARM,
+       PALMAS_PINMUX_PWRDOWN,
+       PALMAS_PINMUX_GPADC_START,
+       PALMAS_PINMUX_RESET_IN,
+       PALMAS_PINMUX_NSLEEP,
+       PALMAS_PINMUX_ENABLE1,
+       PALMAS_PINMUX_ENABLE2,
+       PALMAS_PINMUX_RESVD = 0x2000,
+       PALMAS_PINMUX_DEFAULT = 0x4000,
+       PALMAS_PINMUX_INVALID = 0x8000,
+};
+
+/* Palmas Pinmux Pullup/pulldown/opendrain configuration. */
+enum {
+       PALMAS_PIN_CONFIG_DEFAULT,
+       PALMAS_PIN_CONFIG_NORMAL,
+       PALMAS_PIN_CONFIG_PULL_UP,
+       PALMAS_PIN_CONFIG_PULL_DOWN,
+
+       PALMAS_PIN_CONFIG_OD_DEFAULT,
+       PALMAS_PIN_CONFIG_OD_ENABLE,
+       PALMAS_PIN_CONFIG_OD_DISABLE,
+};
+
+/* Palmas Pins name */
+enum {
+       PALMAS_PIN_NAME_GPIO0,
+       PALMAS_PIN_NAME_GPIO1,
+       PALMAS_PIN_NAME_GPIO2,
+       PALMAS_PIN_NAME_GPIO3,
+       PALMAS_PIN_NAME_GPIO4,
+       PALMAS_PIN_NAME_GPIO5,
+       PALMAS_PIN_NAME_GPIO6,
+       PALMAS_PIN_NAME_GPIO7,
+       PALMAS_PIN_NAME_VAC,
+       PALMAS_PIN_NAME_POWERGOOD,
+       PALMAS_PIN_NAME_NRESWARM,
+       PALMAS_PIN_NAME_PWRDOWN,
+       PALMAS_PIN_NAME_GPADC_START,
+       PALMAS_PIN_NAME_RESET_IN,
+       PALMAS_PIN_NAME_NSLEEP,
+       PALMAS_PIN_NAME_ENABLE1,
+       PALMAS_PIN_NAME_ENABLE2,
+       PALMAS_PIN_NAME_INT,
+       PALMAS_PIN_NAME_MAX,
+};
+
 extern int palmas_ext_power_req_config(struct palmas *palmas,
                int id,  int ext_pwr_ctrl, bool enable);