diff options
-rw-r--r-- | drivers/pinctrl/samsung/pinctrl-exynos-arm.c | 14 | ||||
-rw-r--r-- | drivers/pinctrl/samsung/pinctrl-s3c64xx.c | 14 | ||||
-rw-r--r-- | drivers/pinctrl/samsung/pinctrl-samsung.c | 77 | ||||
-rw-r--r-- | drivers/pinctrl/samsung/pinctrl-samsung.h | 21 |
4 files changed, 126 insertions, 0 deletions
diff --git a/drivers/pinctrl/samsung/pinctrl-exynos-arm.c b/drivers/pinctrl/samsung/pinctrl-exynos-arm.c index 85ddf49a5188..d3d8672f74dc 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos-arm.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos-arm.c @@ -40,6 +40,19 @@ static const struct samsung_pin_bank_type bank_type_alive = { #define S5P_OTHERS_RET_MMC (1 << 29) #define S5P_OTHERS_RET_UART (1 << 28) +#define S5P_PIN_PULL_DISABLE 0 +#define S5P_PIN_PULL_DOWN 1 +#define S5P_PIN_PULL_UP 2 + +static void s5pv210_pud_value_init(struct samsung_pinctrl_drv_data *drvdata) +{ + unsigned int *pud_val = drvdata->pud_val; + + pud_val[PUD_PULL_DISABLE] = S5P_PIN_PULL_DISABLE; + pud_val[PUD_PULL_DOWN] = S5P_PIN_PULL_DOWN; + pud_val[PUD_PULL_UP] = S5P_PIN_PULL_UP; +} + static void s5pv210_retention_disable(struct samsung_pinctrl_drv_data *drvdata) { void __iomem *clk_base = (void __iomem *)drvdata->retention_ctrl->priv; @@ -133,6 +146,7 @@ static const struct samsung_pin_ctrl s5pv210_pin_ctrl[] __initconst = { .nr_banks = ARRAY_SIZE(s5pv210_pin_bank), .eint_gpio_init = exynos_eint_gpio_init, .eint_wkup_init = exynos_eint_wkup_init, + .pud_value_init = s5pv210_pud_value_init, .suspend = exynos_pinctrl_suspend, .resume = exynos_pinctrl_resume, .retention_data = &s5pv210_retention_data, diff --git a/drivers/pinctrl/samsung/pinctrl-s3c64xx.c b/drivers/pinctrl/samsung/pinctrl-s3c64xx.c index c5d92db4fdb1..68715c09baa9 100644 --- a/drivers/pinctrl/samsung/pinctrl-s3c64xx.c +++ b/drivers/pinctrl/samsung/pinctrl-s3c64xx.c @@ -63,6 +63,10 @@ #define EINT_CON_MASK 0xF #define EINT_CON_LEN 4 +#define S3C_PIN_PULL_DISABLE 0 +#define S3C_PIN_PULL_DOWN 1 +#define S3C_PIN_PULL_UP 2 + static const struct samsung_pin_bank_type bank_type_4bit_off = { .fld_width = { 4, 1, 2, 0, 2, 2, }, .reg_offset = { 0x00, 0x04, 0x08, 0, 0x0c, 0x10, }, @@ -255,6 +259,15 @@ static int s3c64xx_irq_get_trigger(unsigned int type) return trigger; } +static void s3c64xx_pud_value_init(struct samsung_pinctrl_drv_data *drvdata) +{ + unsigned int *pud_val = drvdata->pud_val; + + pud_val[PUD_PULL_DISABLE] = S3C_PIN_PULL_DISABLE; + pud_val[PUD_PULL_DOWN] = S3C_PIN_PULL_DOWN; + pud_val[PUD_PULL_UP] = S3C_PIN_PULL_UP; +} + static void s3c64xx_irq_set_handler(struct irq_data *d, unsigned int type) { /* Edge- and level-triggered interrupts need different handlers */ @@ -797,6 +810,7 @@ static const struct samsung_pin_ctrl s3c64xx_pin_ctrl[] __initconst = { .nr_banks = ARRAY_SIZE(s3c64xx_pin_banks0), .eint_gpio_init = s3c64xx_eint_gpio_init, .eint_wkup_init = s3c64xx_eint_eint0_init, + .pud_value_init = s3c64xx_pud_value_init, }, }; diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/samsung/pinctrl-samsung.c index 0651d8324ff2..e4464ee815f9 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.c +++ b/drivers/pinctrl/samsung/pinctrl-samsung.c @@ -988,6 +988,77 @@ static int samsung_pinctrl_unregister(struct platform_device *pdev, return 0; } +static void samsung_pud_value_init(struct samsung_pinctrl_drv_data *drvdata) +{ + unsigned int *pud_val = drvdata->pud_val; + + pud_val[PUD_PULL_DISABLE] = EXYNOS_PIN_PUD_PULL_DISABLE; + pud_val[PUD_PULL_DOWN] = EXYNOS_PIN_PID_PULL_DOWN; + pud_val[PUD_PULL_UP] = EXYNOS_PIN_PID_PULL_UP; +} + +/* + * Enable or Disable the pull-down and pull-up for the gpio pins in the + * PUD register. + */ +static void samsung_gpio_set_pud(struct gpio_chip *gc, unsigned int offset, + unsigned int value) +{ + struct samsung_pin_bank *bank = gpiochip_get_data(gc); + const struct samsung_pin_bank_type *type = bank->type; + void __iomem *reg; + unsigned int data, mask; + + reg = bank->pctl_base + bank->pctl_offset; + data = readl(reg + type->reg_offset[PINCFG_TYPE_PUD]); + mask = (1 << type->fld_width[PINCFG_TYPE_PUD]) - 1; + data &= ~(mask << (offset * type->fld_width[PINCFG_TYPE_PUD])); + data |= value << (offset * type->fld_width[PINCFG_TYPE_PUD]); + writel(data, reg + type->reg_offset[PINCFG_TYPE_PUD]); +} + +/* + * Identify the type of PUD config based on the gpiolib request to enable + * or disable the PUD config. + */ +static int samsung_gpio_set_config(struct gpio_chip *gc, unsigned int offset, + unsigned long config) +{ + struct samsung_pin_bank *bank = gpiochip_get_data(gc); + struct samsung_pinctrl_drv_data *drvdata = bank->drvdata; + unsigned int value; + int ret = 0; + unsigned long flags; + + switch (pinconf_to_config_param(config)) { + case PIN_CONFIG_BIAS_DISABLE: + value = drvdata->pud_val[PUD_PULL_DISABLE]; + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + value = drvdata->pud_val[PUD_PULL_DOWN]; + break; + case PIN_CONFIG_BIAS_PULL_UP: + value = drvdata->pud_val[PUD_PULL_UP]; + break; + default: + return -ENOTSUPP; + } + + ret = clk_enable(drvdata->pclk); + if (ret) { + dev_err(drvdata->dev, "failed to enable clock\n"); + return ret; + } + + raw_spin_lock_irqsave(&bank->slock, flags); + samsung_gpio_set_pud(gc, offset, value); + raw_spin_unlock_irqrestore(&bank->slock, flags); + + clk_disable(drvdata->pclk); + + return ret; +} + static const struct gpio_chip samsung_gpiolib_chip = { .request = gpiochip_generic_request, .free = gpiochip_generic_free, @@ -997,6 +1068,7 @@ static const struct gpio_chip samsung_gpiolib_chip = { .direction_output = samsung_gpio_direction_output, .to_irq = samsung_gpio_to_irq, .add_pin_ranges = samsung_add_pin_ranges, + .set_config = samsung_gpio_set_config, .owner = THIS_MODULE, }; @@ -1228,6 +1300,11 @@ static int samsung_pinctrl_probe(struct platform_device *pdev) if (ctrl->eint_wkup_init) ctrl->eint_wkup_init(drvdata); + if (ctrl->pud_value_init) + ctrl->pud_value_init(drvdata); + else + samsung_pud_value_init(drvdata); + ret = samsung_gpiolib_register(pdev, drvdata); if (ret) goto err_unregister; diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.h b/drivers/pinctrl/samsung/pinctrl-samsung.h index d50ba6f07d5d..a1e7377bd890 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.h +++ b/drivers/pinctrl/samsung/pinctrl-samsung.h @@ -61,6 +61,25 @@ enum pincfg_type { #define PIN_CON_FUNC_INPUT 0x0 #define PIN_CON_FUNC_OUTPUT 0x1 +/* Values for the pin PUD register */ +#define EXYNOS_PIN_PUD_PULL_DISABLE 0x0 +#define EXYNOS_PIN_PID_PULL_DOWN 0x1 +#define EXYNOS_PIN_PID_PULL_UP 0x3 + +/* + * enum pud_index - Possible index values to access the pud_val array. + * @PUD_PULL_DISABLE: Index for the value of pud disable + * @PUD_PULL_DOWN: Index for the value of pull down enable + * @PUD_PULL_UP: Index for the value of pull up enable + * @PUD_MAX: Maximum value of the index + */ +enum pud_index { + PUD_PULL_DISABLE, + PUD_PULL_DOWN, + PUD_PULL_UP, + PUD_MAX, +}; + /** * enum eint_type - possible external interrupt types. * @EINT_TYPE_NONE: bank does not support external interrupts @@ -261,6 +280,7 @@ struct samsung_pin_ctrl { int (*eint_gpio_init)(struct samsung_pinctrl_drv_data *); int (*eint_wkup_init)(struct samsung_pinctrl_drv_data *); + void (*pud_value_init)(struct samsung_pinctrl_drv_data *drvdata); void (*suspend)(struct samsung_pinctrl_drv_data *); void (*resume)(struct samsung_pinctrl_drv_data *); }; @@ -307,6 +327,7 @@ struct samsung_pinctrl_drv_data { struct samsung_pin_bank *pin_banks; unsigned int nr_banks; unsigned int nr_pins; + unsigned int pud_val[PUD_MAX]; struct samsung_retention_ctrl *retention_ctrl; |