diff options
Diffstat (limited to 'drivers/pinctrl/samsung')
-rw-r--r-- | drivers/pinctrl/samsung/pinctrl-exynos.c | 362 | ||||
-rw-r--r-- | drivers/pinctrl/samsung/pinctrl-exynos.h | 42 | ||||
-rw-r--r-- | drivers/pinctrl/samsung/pinctrl-s3c24xx.c | 37 | ||||
-rw-r--r-- | drivers/pinctrl/samsung/pinctrl-s3c64xx.c | 52 | ||||
-rw-r--r-- | drivers/pinctrl/samsung/pinctrl-samsung.c | 166 | ||||
-rw-r--r-- | drivers/pinctrl/samsung/pinctrl-samsung.h | 53 |
6 files changed, 443 insertions, 269 deletions
diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c index d32fa2b5ff82..f9b49967f512 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos.c @@ -24,11 +24,15 @@ #include <linux/irqdomain.h> #include <linux/irq.h> #include <linux/irqchip/chained_irq.h> +#include <linux/of_address.h> #include <linux/of_irq.h> #include <linux/io.h> #include <linux/slab.h> #include <linux/spinlock.h> +#include <linux/regmap.h> #include <linux/err.h> +#include <linux/soc/samsung/exynos-pmu.h> +#include <linux/soc/samsung/exynos-regs-pmu.h> #include "pinctrl-samsung.h" #include "pinctrl-exynos.h" @@ -56,21 +60,31 @@ static const struct samsung_pin_bank_type bank_type_alive = { .reg_offset = { 0x00, 0x04, 0x08, 0x0c, }, }; +/* Exynos5433 has the 4bit widths for PINCFG_TYPE_DRV bitfields. */ +static const struct samsung_pin_bank_type exynos5433_bank_type_off = { + .fld_width = { 4, 1, 2, 4, 2, 2, }, + .reg_offset = { 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, }, +}; + +static const struct samsung_pin_bank_type exynos5433_bank_type_alive = { + .fld_width = { 4, 1, 2, 4, }, + .reg_offset = { 0x00, 0x04, 0x08, 0x0c, }, +}; + static void exynos_irq_mask(struct irq_data *irqd) { struct irq_chip *chip = irq_data_get_irq_chip(irqd); struct exynos_irq_chip *our_chip = to_exynos_irq_chip(chip); struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd); - struct samsung_pinctrl_drv_data *d = bank->drvdata; unsigned long reg_mask = our_chip->eint_mask + bank->eint_offset; unsigned long mask; unsigned long flags; spin_lock_irqsave(&bank->slock, flags); - mask = readl(d->virt_base + reg_mask); + mask = readl(bank->eint_base + reg_mask); mask |= 1 << irqd->hwirq; - writel(mask, d->virt_base + reg_mask); + writel(mask, bank->eint_base + reg_mask); spin_unlock_irqrestore(&bank->slock, flags); } @@ -80,10 +94,9 @@ static void exynos_irq_ack(struct irq_data *irqd) struct irq_chip *chip = irq_data_get_irq_chip(irqd); struct exynos_irq_chip *our_chip = to_exynos_irq_chip(chip); struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd); - struct samsung_pinctrl_drv_data *d = bank->drvdata; unsigned long reg_pend = our_chip->eint_pend + bank->eint_offset; - writel(1 << irqd->hwirq, d->virt_base + reg_pend); + writel(1 << irqd->hwirq, bank->eint_base + reg_pend); } static void exynos_irq_unmask(struct irq_data *irqd) @@ -91,7 +104,6 @@ static void exynos_irq_unmask(struct irq_data *irqd) struct irq_chip *chip = irq_data_get_irq_chip(irqd); struct exynos_irq_chip *our_chip = to_exynos_irq_chip(chip); struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd); - struct samsung_pinctrl_drv_data *d = bank->drvdata; unsigned long reg_mask = our_chip->eint_mask + bank->eint_offset; unsigned long mask; unsigned long flags; @@ -109,9 +121,9 @@ static void exynos_irq_unmask(struct irq_data *irqd) spin_lock_irqsave(&bank->slock, flags); - mask = readl(d->virt_base + reg_mask); + mask = readl(bank->eint_base + reg_mask); mask &= ~(1 << irqd->hwirq); - writel(mask, d->virt_base + reg_mask); + writel(mask, bank->eint_base + reg_mask); spin_unlock_irqrestore(&bank->slock, flags); } @@ -121,7 +133,6 @@ static int exynos_irq_set_type(struct irq_data *irqd, unsigned int type) struct irq_chip *chip = irq_data_get_irq_chip(irqd); struct exynos_irq_chip *our_chip = to_exynos_irq_chip(chip); struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd); - struct samsung_pinctrl_drv_data *d = bank->drvdata; unsigned int shift = EXYNOS_EINT_CON_LEN * irqd->hwirq; unsigned int con, trig_type; unsigned long reg_con = our_chip->eint_con + bank->eint_offset; @@ -152,10 +163,10 @@ static int exynos_irq_set_type(struct irq_data *irqd, unsigned int type) else irq_set_handler_locked(irqd, handle_level_irq); - con = readl(d->virt_base + reg_con); + con = readl(bank->eint_base + reg_con); con &= ~(EXYNOS_EINT_CON_MASK << shift); con |= trig_type << shift; - writel(con, d->virt_base + reg_con); + writel(con, bank->eint_base + reg_con); return 0; } @@ -166,7 +177,6 @@ static int exynos_irq_request_resources(struct irq_data *irqd) struct exynos_irq_chip *our_chip = to_exynos_irq_chip(chip); struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd); const struct samsung_pin_bank_type *bank_type = bank->type; - struct samsung_pinctrl_drv_data *d = bank->drvdata; unsigned int shift = EXYNOS_EINT_CON_LEN * irqd->hwirq; unsigned long reg_con = our_chip->eint_con + bank->eint_offset; unsigned long flags; @@ -188,10 +198,10 @@ static int exynos_irq_request_resources(struct irq_data *irqd) spin_lock_irqsave(&bank->slock, flags); - con = readl(d->virt_base + reg_con); + con = readl(bank->eint_base + reg_con); con &= ~(mask << shift); con |= EXYNOS_EINT_FUNC << shift; - writel(con, d->virt_base + reg_con); + writel(con, bank->eint_base + reg_con); spin_unlock_irqrestore(&bank->slock, flags); @@ -206,7 +216,6 @@ static void exynos_irq_release_resources(struct irq_data *irqd) struct exynos_irq_chip *our_chip = to_exynos_irq_chip(chip); struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd); const struct samsung_pin_bank_type *bank_type = bank->type; - struct samsung_pinctrl_drv_data *d = bank->drvdata; unsigned int shift = EXYNOS_EINT_CON_LEN * irqd->hwirq; unsigned long reg_con = our_chip->eint_con + bank->eint_offset; unsigned long flags; @@ -221,10 +230,10 @@ static void exynos_irq_release_resources(struct irq_data *irqd) spin_lock_irqsave(&bank->slock, flags); - con = readl(d->virt_base + reg_con); + con = readl(bank->eint_base + reg_con); con &= ~(mask << shift); con |= FUNC_INPUT << shift; - writel(con, d->virt_base + reg_con); + writel(con, bank->eint_base + reg_con); spin_unlock_irqrestore(&bank->slock, flags); @@ -274,7 +283,7 @@ static irqreturn_t exynos_eint_gpio_irq(int irq, void *data) struct samsung_pin_bank *bank = d->pin_banks; unsigned int svc, group, pin, virq; - svc = readl(d->virt_base + EXYNOS_SVC_OFFSET); + svc = readl(bank->eint_base + EXYNOS_SVC_OFFSET); group = EXYNOS_SVC_GROUP(svc); pin = svc & EXYNOS_SVC_NUM_MASK; @@ -452,7 +461,6 @@ static void exynos_irq_demux_eint16_31(struct irq_desc *desc) { struct irq_chip *chip = irq_desc_get_chip(desc); struct exynos_muxed_weint_data *eintd = irq_desc_get_handler_data(desc); - struct samsung_pinctrl_drv_data *d = eintd->banks[0]->drvdata; unsigned long pend; unsigned long mask; int i; @@ -461,9 +469,9 @@ static void exynos_irq_demux_eint16_31(struct irq_desc *desc) for (i = 0; i < eintd->nr_banks; ++i) { struct samsung_pin_bank *b = eintd->banks[i]; - pend = readl(d->virt_base + b->irq_chip->eint_pend + pend = readl(b->eint_base + b->irq_chip->eint_pend + b->eint_offset); - mask = readl(d->virt_base + b->irq_chip->eint_mask + mask = readl(b->eint_base + b->irq_chip->eint_mask + b->eint_offset); exynos_irq_demux_eint(pend & ~mask, b->irq_domain); } @@ -524,10 +532,8 @@ static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d) weint_data = devm_kzalloc(dev, bank->nr_pins * sizeof(*weint_data), GFP_KERNEL); - if (!weint_data) { - dev_err(dev, "could not allocate memory for weint_data\n"); + if (!weint_data) return -ENOMEM; - } for (idx = 0; idx < bank->nr_pins; ++idx) { irq = irq_of_parse_and_map(bank->of_node, idx); @@ -555,10 +561,8 @@ static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d) muxed_data = devm_kzalloc(dev, sizeof(*muxed_data) + muxed_banks*sizeof(struct samsung_pin_bank *), GFP_KERNEL); - if (!muxed_data) { - dev_err(dev, "could not allocate memory for muxed_data\n"); + if (!muxed_data) return -ENOMEM; - } irq_set_chained_handler_and_data(irq, exynos_irq_demux_eint16_31, muxed_data); @@ -581,7 +585,7 @@ static void exynos_pinctrl_suspend_bank( struct samsung_pin_bank *bank) { struct exynos_eint_gpio_save *save = bank->soc_priv; - void __iomem *regs = drvdata->virt_base; + void __iomem *regs = bank->eint_base; save->eint_con = readl(regs + EXYNOS_GPIO_ECON_OFFSET + bank->eint_offset); @@ -610,7 +614,7 @@ static void exynos_pinctrl_resume_bank( struct samsung_pin_bank *bank) { struct exynos_eint_gpio_save *save = bank->soc_priv; - void __iomem *regs = drvdata->virt_base; + void __iomem *regs = bank->eint_base; pr_debug("%s: con %#010x => %#010x\n", bank->name, readl(regs + EXYNOS_GPIO_ECON_OFFSET @@ -640,6 +644,60 @@ static void exynos_pinctrl_resume(struct samsung_pinctrl_drv_data *drvdata) exynos_pinctrl_resume_bank(drvdata, bank); } +/* Retention control for S5PV210 are located at the end of clock controller */ +#define S5P_OTHERS 0xE000 + +#define S5P_OTHERS_RET_IO (1 << 31) +#define S5P_OTHERS_RET_CF (1 << 30) +#define S5P_OTHERS_RET_MMC (1 << 29) +#define S5P_OTHERS_RET_UART (1 << 28) + +static void s5pv210_retention_disable(struct samsung_pinctrl_drv_data *drvdata) +{ + void *clk_base = drvdata->retention_ctrl->priv; + u32 tmp; + + tmp = __raw_readl(clk_base + S5P_OTHERS); + tmp |= (S5P_OTHERS_RET_IO | S5P_OTHERS_RET_CF | S5P_OTHERS_RET_MMC | + S5P_OTHERS_RET_UART); + __raw_writel(tmp, clk_base + S5P_OTHERS); +} + +static struct samsung_retention_ctrl * +s5pv210_retention_init(struct samsung_pinctrl_drv_data *drvdata, + const struct samsung_retention_data *data) +{ + struct samsung_retention_ctrl *ctrl; + struct device_node *np; + void *clk_base; + + ctrl = devm_kzalloc(drvdata->dev, sizeof(*ctrl), GFP_KERNEL); + if (!ctrl) + return ERR_PTR(-ENOMEM); + + np = of_find_compatible_node(NULL, NULL, "samsung,s5pv210-clock"); + if (!np) { + pr_err("%s: failed to find clock controller DT node\n", + __func__); + return ERR_PTR(-ENODEV); + } + + clk_base = of_iomap(np, 0); + if (!clk_base) { + pr_err("%s: failed to map clock registers\n", __func__); + return ERR_PTR(-EINVAL); + } + + ctrl->priv = clk_base; + ctrl->disable = s5pv210_retention_disable; + + return ctrl; +} + +static const struct samsung_retention_data s5pv210_retention_data __initconst = { + .init = s5pv210_retention_init, +}; + /* pin banks of s5pv210 pin-controller */ static const struct samsung_pin_bank_data s5pv210_pin_bank[] __initconst = { EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00), @@ -687,9 +745,58 @@ const struct samsung_pin_ctrl s5pv210_pin_ctrl[] __initconst = { .eint_wkup_init = exynos_eint_wkup_init, .suspend = exynos_pinctrl_suspend, .resume = exynos_pinctrl_resume, + .retention_data = &s5pv210_retention_data, }, }; +/* Pad retention control code for accessing PMU regmap */ +static atomic_t exynos_shared_retention_refcnt; + +static void exynos_retention_enable(struct samsung_pinctrl_drv_data *drvdata) +{ + if (drvdata->retention_ctrl->refcnt) + atomic_inc(drvdata->retention_ctrl->refcnt); +} + +static void exynos_retention_disable(struct samsung_pinctrl_drv_data *drvdata) +{ + struct samsung_retention_ctrl *ctrl = drvdata->retention_ctrl; + struct regmap *pmu_regs = ctrl->priv; + int i; + + if (ctrl->refcnt && !atomic_dec_and_test(ctrl->refcnt)) + return; + + for (i = 0; i < ctrl->nr_regs; i++) + regmap_write(pmu_regs, ctrl->regs[i], ctrl->value); +} + +static struct samsung_retention_ctrl * +exynos_retention_init(struct samsung_pinctrl_drv_data *drvdata, + const struct samsung_retention_data *data) +{ + struct samsung_retention_ctrl *ctrl; + struct regmap *pmu_regs; + + ctrl = devm_kzalloc(drvdata->dev, sizeof(*ctrl), GFP_KERNEL); + if (!ctrl) + return ERR_PTR(-ENOMEM); + + pmu_regs = exynos_get_pmu_regmap(); + if (IS_ERR(pmu_regs)) + return ERR_CAST(pmu_regs); + + ctrl->priv = pmu_regs; + ctrl->regs = data->regs; + ctrl->nr_regs = data->nr_regs; + ctrl->value = data->value; + ctrl->refcnt = data->refcnt; + ctrl->enable = exynos_retention_enable; + ctrl->disable = exynos_retention_disable; + + return ctrl; +} + /* pin banks of exynos3250 pin-controller 0 */ static const struct samsung_pin_bank_data exynos3250_pin_banks0[] __initconst = { EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00), @@ -722,6 +829,30 @@ static const struct samsung_pin_bank_data exynos3250_pin_banks1[] __initconst = }; /* + * PMU pad retention groups for Exynos3250 doesn't match pin banks, so handle + * them all together + */ +static const u32 exynos3250_retention_regs[] = { + S5P_PAD_RET_MAUDIO_OPTION, + S5P_PAD_RET_GPIO_OPTION, + S5P_PAD_RET_UART_OPTION, + S5P_PAD_RET_MMCA_OPTION, + S5P_PAD_RET_MMCB_OPTION, + S5P_PAD_RET_EBIA_OPTION, + S5P_PAD_RET_EBIB_OPTION, + S5P_PAD_RET_MMC2_OPTION, + S5P_PAD_RET_SPI_OPTION, +}; + +static const struct samsung_retention_data exynos3250_retention_data __initconst = { + .regs = exynos3250_retention_regs, + .nr_regs = ARRAY_SIZE(exynos3250_retention_regs), + .value = EXYNOS_WAKEUP_FROM_LOWPWR, + .refcnt = &exynos_shared_retention_refcnt, + .init = exynos_retention_init, +}; + +/* * Samsung pinctrl driver data for Exynos3250 SoC. Exynos3250 SoC includes * two gpio/pin-mux/pinconfig controllers. */ @@ -733,6 +864,7 @@ const struct samsung_pin_ctrl exynos3250_pin_ctrl[] __initconst = { .eint_gpio_init = exynos_eint_gpio_init, .suspend = exynos_pinctrl_suspend, .resume = exynos_pinctrl_resume, + .retention_data = &exynos3250_retention_data, }, { /* pin-controller instance 1 data */ .pin_banks = exynos3250_pin_banks1, @@ -741,6 +873,7 @@ const struct samsung_pin_ctrl exynos3250_pin_ctrl[] __initconst = { .eint_wkup_init = exynos_eint_wkup_init, .suspend = exynos_pinctrl_suspend, .resume = exynos_pinctrl_resume, + .retention_data = &exynos3250_retention_data, }, }; @@ -793,6 +926,36 @@ static const struct samsung_pin_bank_data exynos4210_pin_banks2[] __initconst = EXYNOS_PIN_BANK_EINTN(7, 0x000, "gpz"), }; +/* PMU pad retention groups registers for Exynos4 (without audio) */ +static const u32 exynos4_retention_regs[] = { + S5P_PAD_RET_GPIO_OPTION, + S5P_PAD_RET_UART_OPTION, + S5P_PAD_RET_MMCA_OPTION, + S5P_PAD_RET_MMCB_OPTION, + S5P_PAD_RET_EBIA_OPTION, + S5P_PAD_RET_EBIB_OPTION, +}; + +static const struct samsung_retention_data exynos4_retention_data __initconst = { + .regs = exynos4_retention_regs, + .nr_regs = ARRAY_SIZE(exynos4_retention_regs), + .value = EXYNOS_WAKEUP_FROM_LOWPWR, + .refcnt = &exynos_shared_retention_refcnt, + .init = exynos_retention_init, +}; + +/* PMU retention control for audio pins can be tied to audio pin bank */ +static const u32 exynos4_audio_retention_regs[] = { + S5P_PAD_RET_MAUDIO_OPTION, +}; + +static const struct samsung_retention_data exynos4_audio_retention_data __initconst = { + .regs = exynos4_audio_retention_regs, + .nr_regs = ARRAY_SIZE(exynos4_audio_retention_regs), + .value = EXYNOS_WAKEUP_FROM_LOWPWR, + .init = exynos_retention_init, +}; + /* * Samsung pinctrl driver data for Exynos4210 SoC. Exynos4210 SoC includes * three gpio/pin-mux/pinconfig controllers. @@ -805,6 +968,7 @@ const struct samsung_pin_ctrl exynos4210_pin_ctrl[] __initconst = { .eint_gpio_init = exynos_eint_gpio_init, .suspend = exynos_pinctrl_suspend, .resume = exynos_pinctrl_resume, + .retention_data = &exynos4_retention_data, }, { /* pin-controller instance 1 data */ .pin_banks = exynos4210_pin_banks1, @@ -813,10 +977,12 @@ const struct samsung_pin_ctrl exynos4210_pin_ctrl[] __initconst = { .eint_wkup_init = exynos_eint_wkup_init, .suspend = exynos_pinctrl_suspend, .resume = exynos_pinctrl_resume, + .retention_data = &exynos4_retention_data, }, { /* pin-controller instance 2 data */ .pin_banks = exynos4210_pin_banks2, .nr_banks = ARRAY_SIZE(exynos4210_pin_banks2), + .retention_data = &exynos4_audio_retention_data, }, }; @@ -890,6 +1056,7 @@ const struct samsung_pin_ctrl exynos4x12_pin_ctrl[] __initconst = { .eint_gpio_init = exynos_eint_gpio_init, .suspend = exynos_pinctrl_suspend, .resume = exynos_pinctrl_resume, + .retention_data = &exynos4_retention_data, }, { /* pin-controller instance 1 data */ .pin_banks = exynos4x12_pin_banks1, @@ -898,6 +1065,7 @@ const struct samsung_pin_ctrl exynos4x12_pin_ctrl[] __initconst = { .eint_wkup_init = exynos_eint_wkup_init, .suspend = exynos_pinctrl_suspend, .resume = exynos_pinctrl_resume, + .retention_data = &exynos4_retention_data, }, { /* pin-controller instance 2 data */ .pin_banks = exynos4x12_pin_banks2, @@ -905,6 +1073,7 @@ const struct samsung_pin_ctrl exynos4x12_pin_ctrl[] __initconst = { .eint_gpio_init = exynos_eint_gpio_init, .suspend = exynos_pinctrl_suspend, .resume = exynos_pinctrl_resume, + .retention_data = &exynos4_audio_retention_data, }, { /* pin-controller instance 3 data */ .pin_banks = exynos4x12_pin_banks3, @@ -915,81 +1084,6 @@ const struct samsung_pin_ctrl exynos4x12_pin_ctrl[] __initconst = { }, }; -/* pin banks of exynos4415 pin-controller 0 */ -static const struct samsung_pin_bank_data exynos4415_pin_banks0[] = { - EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00), - EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpa1", 0x04), - EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpb", 0x08), - EXYNOS_PIN_BANK_EINTG(5, 0x060, "gpc0", 0x0c), - EXYNOS_PIN_BANK_EINTG(5, 0x080, "gpc1", 0x10), - EXYNOS_PIN_BANK_EINTG(4, 0x0A0, "gpd0", 0x14), - EXYNOS_PIN_BANK_EINTG(4, 0x0C0, "gpd1", 0x18), - EXYNOS_PIN_BANK_EINTG(8, 0x180, "gpf0", 0x30), - EXYNOS_PIN_BANK_EINTG(8, 0x1A0, "gpf1", 0x34), - EXYNOS_PIN_BANK_EINTG(1, 0x1C0, "gpf2", 0x38), -}; - -/* pin banks of exynos4415 pin-controller 1 */ -static const struct samsung_pin_bank_data exynos4415_pin_banks1[] = { - EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpk0", 0x08), - EXYNOS_PIN_BANK_EINTG(7, 0x060, "gpk1", 0x0c), - EXYNOS_PIN_BANK_EINTG(7, 0x080, "gpk2", 0x10), - EXYNOS_PIN_BANK_EINTG(7, 0x0A0, "gpk3", 0x14), - EXYNOS_PIN_BANK_EINTG(4, 0x0C0, "gpl0", 0x18), - EXYNOS_PIN_BANK_EINTN(6, 0x120, "mp00"), - EXYNOS_PIN_BANK_EINTN(4, 0x140, "mp01"), - EXYNOS_PIN_BANK_EINTN(6, 0x160, "mp02"), - EXYNOS_PIN_BANK_EINTN(8, 0x180, "mp03"), - EXYNOS_PIN_BANK_EINTN(8, 0x1A0, "mp04"), - EXYNOS_PIN_BANK_EINTN(8, 0x1C0, "mp05"), - EXYNOS_PIN_BANK_EINTN(8, 0x1E0, "mp06"), - EXYNOS_PIN_BANK_EINTG(8, 0x260, "gpm0", 0x24), - EXYNOS_PIN_BANK_EINTG(7, 0x280, "gpm1", 0x28), - EXYNOS_PIN_BANK_EINTG(5, 0x2A0, "gpm2", 0x2c), - EXYNOS_PIN_BANK_EINTG(8, 0x2C0, "gpm3", 0x30), - EXYNOS_PIN_BANK_EINTG(8, 0x2E0, "gpm4", 0x34), - EXYNOS_PIN_BANK_EINTW(8, 0xC00, "gpx0", 0x00), - EXYNOS_PIN_BANK_EINTW(8, 0xC20, "gpx1", 0x04), - EXYNOS_PIN_BANK_EINTW(8, 0xC40, "gpx2", 0x08), - EXYNOS_PIN_BANK_EINTW(8, 0xC60, "gpx3", 0x0c), -}; - -/* pin banks of exynos4415 pin-controller 2 */ -static const struct samsung_pin_bank_data exynos4415_pin_banks2[] = { - EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz", 0x00), - EXYNOS_PIN_BANK_EINTN(2, 0x000, "etc1"), -}; - -/* - * Samsung pinctrl driver data for Exynos4415 SoC. Exynos4415 SoC includes - * three gpio/pin-mux/pinconfig controllers. - */ -const struct samsung_pin_ctrl exynos4415_pin_ctrl[] = { - { - /* pin-controller instance 0 data */ - .pin_banks = exynos4415_pin_banks0, - .nr_banks = ARRAY_SIZE(exynos4415_pin_banks0), - .eint_gpio_init = exynos_eint_gpio_init, - .suspend = exynos_pinctrl_suspend, - .resume = exynos_pinctrl_resume, - }, { - /* pin-controller instance 1 data */ - .pin_banks = exynos4415_pin_banks1, - .nr_banks = ARRAY_SIZE(exynos4415_pin_banks1), - .eint_gpio_init = exynos_eint_gpio_init, - .eint_wkup_init = exynos_eint_wkup_init, - .suspend = exynos_pinctrl_suspend, - .resume = exynos_pinctrl_resume, - }, { - /* pin-controller instance 2 data */ - .pin_banks = exynos4415_pin_banks2, - .nr_banks = ARRAY_SIZE(exynos4415_pin_banks2), - .eint_gpio_init = exynos_eint_gpio_init, - .suspend = exynos_pinctrl_suspend, - .resume = exynos_pinctrl_resume, - }, -}; - /* pin banks of exynos5250 pin-controller 0 */ static const struct samsung_pin_bank_data exynos5250_pin_banks0[] __initconst = { EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00), @@ -1059,6 +1153,7 @@ const struct samsung_pin_ctrl exynos5250_pin_ctrl[] __initconst = { .eint_wkup_init = exynos_eint_wkup_init, .suspend = exynos_pinctrl_suspend, .resume = exynos_pinctrl_resume, + .retention_data = &exynos4_retention_data, }, { /* pin-controller instance 1 data */ .pin_banks = exynos5250_pin_banks1, @@ -1066,6 +1161,7 @@ const struct samsung_pin_ctrl exynos5250_pin_ctrl[] __initconst = { .eint_gpio_init = exynos_eint_gpio_init, .suspend = exynos_pinctrl_suspend, .resume = exynos_pinctrl_resume, + .retention_data = &exynos4_retention_data, }, { /* pin-controller instance 2 data */ .pin_banks = exynos5250_pin_banks2, @@ -1080,6 +1176,7 @@ const struct samsung_pin_ctrl exynos5250_pin_ctrl[] __initconst = { .eint_gpio_init = exynos_eint_gpio_init, .suspend = exynos_pinctrl_suspend, .resume = exynos_pinctrl_resume, + .retention_data = &exynos4_audio_retention_data, }, }; @@ -1306,6 +1403,30 @@ static const struct samsung_pin_bank_data exynos5420_pin_banks4[] __initconst = EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz", 0x00), }; +/* PMU pad retention groups registers for Exynos5420 (without audio) */ +static const u32 exynos5420_retention_regs[] = { + EXYNOS_PAD_RET_DRAM_OPTION, + EXYNOS_PAD_RET_JTAG_OPTION, + EXYNOS5420_PAD_RET_GPIO_OPTION, + EXYNOS5420_PAD_RET_UART_OPTION, + EXYNOS5420_PAD_RET_MMCA_OPTION, + EXYNOS5420_PAD_RET_MMCB_OPTION, + EXYNOS5420_PAD_RET_MMCC_OPTION, + EXYNOS5420_PAD_RET_HSI_OPTION, + EXYNOS_PAD_RET_EBIA_OPTION, + EXYNOS_PAD_RET_EBIB_OPTION, + EXYNOS5420_PAD_RET_SPI_OPTION, + EXYNOS5420_PAD_RET_DRAM_COREBLK_OPTION, +}; + +static const struct samsung_retention_data exynos5420_retention_data __initconst = { + .regs = exynos5420_retention_regs, + .nr_regs = ARRAY_SIZE(exynos5420_retention_regs), + .value = EXYNOS_WAKEUP_FROM_LOWPWR, + .refcnt = &exynos_shared_retention_refcnt, + .init = exynos_retention_init, +}; + /* * Samsung pinctrl driver data for Exynos5420 SoC. Exynos5420 SoC includes * four gpio/pin-mux/pinconfig controllers. @@ -1317,60 +1438,70 @@ const struct samsung_pin_ctrl exynos5420_pin_ctrl[] __initconst = { .nr_banks = ARRAY_SIZE(exynos5420_pin_banks0), .eint_gpio_init = exynos_eint_gpio_init, .eint_wkup_init = exynos_eint_wkup_init, + .retention_data = &exynos5420_retention_data, }, { /* pin-controller instance 1 data */ .pin_banks = exynos5420_pin_banks1, .nr_banks = ARRAY_SIZE(exynos5420_pin_banks1), .eint_gpio_init = exynos_eint_gpio_init, + .retention_data = &exynos5420_retention_data, }, { /* pin-controller instance 2 data */ .pin_banks = exynos5420_pin_banks2, .nr_banks = ARRAY_SIZE(exynos5420_pin_banks2), .eint_gpio_init = exynos_eint_gpio_init, + .retention_data = &exynos5420_retention_data, }, { /* pin-controller instance 3 data */ .pin_banks = exynos5420_pin_banks3, .nr_banks = ARRAY_SIZE(exynos5420_pin_banks3), .eint_gpio_init = exynos_eint_gpio_init, + .retention_data = &exynos5420_retention_data, }, { /* pin-controller instance 4 data */ .pin_banks = exynos5420_pin_banks4, .nr_banks = ARRAY_SIZE(exynos5420_pin_banks4), .eint_gpio_init = exynos_eint_gpio_init, + .retention_data = &exynos4_audio_retention_data, }, }; /* pin banks of exynos5433 pin-controller - ALIVE */ -static const struct samsung_pin_bank_data exynos5433_pin_banks0[] = { +static const struct samsung_pin_bank_data exynos5433_pin_banks0[] __initconst = { EXYNOS_PIN_BANK_EINTW(8, 0x000, "gpa0", 0x00), EXYNOS_PIN_BANK_EINTW(8, 0x020, "gpa1", 0x04), EXYNOS_PIN_BANK_EINTW(8, 0x040, "gpa2", 0x08), EXYNOS_PIN_BANK_EINTW(8, 0x060, "gpa3", 0x0c), + EXYNOS_PIN_BANK_EINTW_EXT(8, 0x020, "gpf1", 0x1004, 1), + EXYNOS_PIN_BANK_EINTW_EXT(4, 0x040, "gpf2", 0x1008, 1), + EXYNOS_PIN_BANK_EINTW_EXT(4, 0x060, "gpf3", 0x100c, 1), + EXYNOS_PIN_BANK_EINTW_EXT(8, 0x080, "gpf4", 0x1010, 1), + EXYNOS_PIN_BANK_EINTW_EXT(8, 0x0a0, "gpf5", 0x1014, 1), }; /* pin banks of exynos5433 pin-controller - AUD */ -static const struct samsung_pin_bank_data exynos5433_pin_banks1[] = { +static const struct samsung_pin_bank_data exynos5433_pin_banks1[] __initconst = { EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz0", 0x00), EXYNOS_PIN_BANK_EINTG(4, 0x020, "gpz1", 0x04), }; /* pin banks of exynos5433 pin-controller - CPIF */ -static const struct samsung_pin_bank_data exynos5433_pin_banks2[] = { +static const struct samsung_pin_bank_data exynos5433_pin_banks2[] __initconst = { EXYNOS_PIN_BANK_EINTG(2, 0x000, "gpv6", 0x00), }; /* pin banks of exynos5433 pin-controller - eSE */ -static const struct samsung_pin_bank_data exynos5433_pin_banks3[] = { +static const struct samsung_pin_bank_data exynos5433_pin_banks3[] __initconst = { EXYNOS_PIN_BANK_EINTG(3, 0x000, "gpj2", 0x00), }; /* pin banks of exynos5433 pin-controller - FINGER */ -static const struct samsung_pin_bank_data exynos5433_pin_banks4[] = { +static const struct samsung_pin_bank_data exynos5433_pin_banks4[] __initconst = { EXYNOS_PIN_BANK_EINTG(4, 0x000, "gpd5", 0x00), }; /* pin banks of exynos5433 pin-controller - FSYS */ -static const struct samsung_pin_bank_data exynos5433_pin_banks5[] = { +static const struct samsung_pin_bank_data exynos5433_pin_banks5[] __initconst = { EXYNOS_PIN_BANK_EINTG(6, 0x000, "gph1", 0x00), EXYNOS_PIN_BANK_EINTG(7, 0x020, "gpr4", 0x04), EXYNOS_PIN_BANK_EINTG(5, 0x040, "gpr0", 0x08), @@ -1380,17 +1511,17 @@ static const struct samsung_pin_bank_data exynos5433_pin_banks5[] = { }; /* pin banks of exynos5433 pin-controller - IMEM */ -static const struct samsung_pin_bank_data exynos5433_pin_banks6[] = { +static const struct samsung_pin_bank_data exynos5433_pin_banks6[] __initconst = { EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpf0", 0x00), }; /* pin banks of exynos5433 pin-controller - NFC */ -static const struct samsung_pin_bank_data exynos5433_pin_banks7[] = { +static const struct samsung_pin_bank_data exynos5433_pin_banks7[] __initconst = { EXYNOS_PIN_BANK_EINTG(3, 0x000, "gpj0", 0x00), }; /* pin banks of exynos5433 pin-controller - PERIC */ -static const struct samsung_pin_bank_data exynos5433_pin_banks8[] = { +static const struct samsung_pin_bank_data exynos5433_pin_banks8[] __initconst = { EXYNOS_PIN_BANK_EINTG(6, 0x000, "gpv7", 0x00), EXYNOS_PIN_BANK_EINTG(5, 0x020, "gpb0", 0x04), EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpc0", 0x08), @@ -1411,7 +1542,7 @@ static const struct samsung_pin_bank_data exynos5433_pin_banks8[] = { }; /* pin banks of exynos5433 pin-controller - TOUCH */ -static const struct samsung_pin_bank_data exynos5433_pin_banks9[] = { +static const struct samsung_pin_bank_data exynos5433_pin_banks9[] __initconst = { EXYNOS_PIN_BANK_EINTG(3, 0x000, "gpj1", 0x00), }; @@ -1419,7 +1550,7 @@ static const struct samsung_pin_bank_data exynos5433_pin_banks9[] = { * Samsung pinctrl driver data for Exynos5433 SoC. Exynos5433 SoC includes * ten gpio/pin-mux/pinconfig controllers. */ -const struct samsung_pin_ctrl exynos5433_pin_ctrl[] = { +const struct samsung_pin_ctrl exynos5433_pin_ctrl[] __initconst = { { /* pin-controller instance 0 data */ .pin_banks = exynos5433_pin_banks0, @@ -1427,6 +1558,7 @@ const struct samsung_pin_ctrl exynos5433_pin_ctrl[] = { .eint_wkup_init = exynos_eint_wkup_init, .suspend = exynos_pinctrl_suspend, .resume = exynos_pinctrl_resume, + .nr_ext_resources = 1, }, { /* pin-controller instance 1 data */ .pin_banks = exynos5433_pin_banks1, diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.h b/drivers/pinctrl/samsung/pinctrl-exynos.h index 0f0f7cedb2dc..a473092fb8d2 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos.h +++ b/drivers/pinctrl/samsung/pinctrl-exynos.h @@ -79,6 +79,48 @@ .name = id \ } +#define EXYNOS_PIN_BANK_EINTW_EXT(pins, reg, id, offs, pctl_idx) \ + { \ + .type = &bank_type_alive, \ + .pctl_offset = reg, \ + .nr_pins = pins, \ + .eint_type = EINT_TYPE_WKUP, \ + .eint_offset = offs, \ + .name = id, \ + .pctl_res_idx = pctl_idx, \ + } \ + +#define EXYNOS5433_PIN_BANK_EINTG(pins, reg, id, offs) \ + { \ + .type = &exynos5433_bank_type_off, \ + .pctl_offset = reg, \ + .nr_pins = pins, \ + .eint_type = EINT_TYPE_GPIO, \ + .eint_offset = offs, \ + .name = id \ + } + +#define EXYNOS5433_PIN_BANK_EINTW(pins, reg, id, offs) \ + { \ + .type = &exynos5433_bank_type_alive, \ + .pctl_offset = reg, \ + .nr_pins = pins, \ + .eint_type = EINT_TYPE_WKUP, \ + .eint_offset = offs, \ + .name = id \ + } + +#define EXYNOS5433_PIN_BANK_EINTW_EXT(pins, reg, id, offs, pctl_idx) \ + { \ + .type = &exynos5433_bank_type_alive, \ + .pctl_offset = reg, \ + .nr_pins = pins, \ + .eint_type = EINT_TYPE_WKUP, \ + .eint_offset = offs, \ + .name = id, \ + .pctl_res_idx = pctl_idx, \ + } \ + /** * struct exynos_weint_data: irq specific data for all the wakeup interrupts * generated by the external wakeup interrupt controller. diff --git a/drivers/pinctrl/samsung/pinctrl-s3c24xx.c b/drivers/pinctrl/samsung/pinctrl-s3c24xx.c index 3d92f827da7a..b82a003546ae 100644 --- a/drivers/pinctrl/samsung/pinctrl-s3c24xx.c +++ b/drivers/pinctrl/samsung/pinctrl-s3c24xx.c @@ -151,7 +151,7 @@ static void s3c24xx_eint_set_function(struct samsung_pinctrl_drv_data *d, u32 val; /* Make sure that pin is configured as interrupt */ - reg = d->virt_base + bank->pctl_offset; + reg = bank->pctl_base + bank->pctl_offset; shift = pin * bank_type->fld_width[PINCFG_TYPE_FUNC]; mask = (1 << bank_type->fld_width[PINCFG_TYPE_FUNC]) - 1; @@ -184,7 +184,7 @@ static int s3c24xx_eint_type(struct irq_data *data, unsigned int type) s3c24xx_eint_set_handler(data, type); /* Set up interrupt trigger */ - reg = d->virt_base + EINT_REG(index); + reg = bank->eint_base + EINT_REG(index); shift = EINT_OFFS(index); val = readl(reg); @@ -259,32 +259,29 @@ static void s3c2410_demux_eint0_3(struct irq_desc *desc) static void s3c2412_eint0_3_ack(struct irq_data *data) { struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(data); - struct samsung_pinctrl_drv_data *d = bank->drvdata; unsigned long bitval = 1UL << data->hwirq; - writel(bitval, d->virt_base + EINTPEND_REG); + writel(bitval, bank->eint_base + EINTPEND_REG); } static void s3c2412_eint0_3_mask(struct irq_data *data) { struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(data); - struct samsung_pinctrl_drv_data *d = bank->drvdata; unsigned long mask; - mask = readl(d->virt_base + EINTMASK_REG); + mask = readl(bank->eint_base + EINTMASK_REG); mask |= (1UL << data->hwirq); - writel(mask, d->virt_base + EINTMASK_REG); + writel(mask, bank->eint_base + EINTMASK_REG); } static void s3c2412_eint0_3_unmask(struct irq_data *data) { struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(data); - struct samsung_pinctrl_drv_data *d = bank->drvdata; unsigned long mask; - mask = readl(d->virt_base + EINTMASK_REG); + mask = readl(bank->eint_base + EINTMASK_REG); mask &= ~(1UL << data->hwirq); - writel(mask, d->virt_base + EINTMASK_REG); + writel(mask, bank->eint_base + EINTMASK_REG); } static struct irq_chip s3c2412_eint0_3_chip = { @@ -319,34 +316,31 @@ static void s3c2412_demux_eint0_3(struct irq_desc *desc) static void s3c24xx_eint_ack(struct irq_data *data) { struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(data); - struct samsung_pinctrl_drv_data *d = bank->drvdata; unsigned char index = bank->eint_offset + data->hwirq; - writel(1UL << index, d->virt_base + EINTPEND_REG); + writel(1UL << index, bank->eint_base + EINTPEND_REG); } static void s3c24xx_eint_mask(struct irq_data *data) { struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(data); - struct samsung_pinctrl_drv_data *d = bank->drvdata; unsigned char index = bank->eint_offset + data->hwirq; unsigned long mask; - mask = readl(d->virt_base + EINTMASK_REG); + mask = readl(bank->eint_base + EINTMASK_REG); mask |= (1UL << index); - writel(mask, d->virt_base + EINTMASK_REG); + writel(mask, bank->eint_base + EINTMASK_REG); } static void s3c24xx_eint_unmask(struct irq_data *data) { struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(data); - struct samsung_pinctrl_drv_data *d = bank->drvdata; unsigned char index = bank->eint_offset + data->hwirq; unsigned long mask; - mask = readl(d->virt_base + EINTMASK_REG); + mask = readl(bank->eint_base + EINTMASK_REG); mask &= ~(1UL << index); - writel(mask, d->virt_base + EINTMASK_REG); + writel(mask, bank->eint_base + EINTMASK_REG); } static struct irq_chip s3c24xx_eint_chip = { @@ -362,13 +356,14 @@ static inline void s3c24xx_demux_eint(struct irq_desc *desc, { struct s3c24xx_eint_data *data = irq_desc_get_handler_data(desc); struct irq_chip *chip = irq_desc_get_chip(desc); - struct samsung_pinctrl_drv_data *d = data->drvdata; + struct irq_data *irqd = irq_desc_get_irq_data(desc); + struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd); unsigned int pend, mask; chained_irq_enter(chip, desc); - pend = readl(d->virt_base + EINTPEND_REG); - mask = readl(d->virt_base + EINTMASK_REG); + pend = readl(bank->eint_base + EINTPEND_REG); + mask = readl(bank->eint_base + EINTMASK_REG); pend &= ~mask; pend &= range; diff --git a/drivers/pinctrl/samsung/pinctrl-s3c64xx.c b/drivers/pinctrl/samsung/pinctrl-s3c64xx.c index 43407ab248f5..f17890aa6e25 100644 --- a/drivers/pinctrl/samsung/pinctrl-s3c64xx.c +++ b/drivers/pinctrl/samsung/pinctrl-s3c64xx.c @@ -280,7 +280,7 @@ static void s3c64xx_irq_set_function(struct samsung_pinctrl_drv_data *d, u32 val; /* Make sure that pin is configured as interrupt */ - reg = d->virt_base + bank->pctl_offset; + reg = bank->pctl_base + bank->pctl_offset; shift = pin; if (bank_type->fld_width[PINCFG_TYPE_FUNC] * shift >= 32) { /* 4-bit bank type with 2 con regs */ @@ -308,9 +308,8 @@ static void s3c64xx_irq_set_function(struct samsung_pinctrl_drv_data *d, static inline void s3c64xx_gpio_irq_set_mask(struct irq_data *irqd, bool mask) { struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd); - struct samsung_pinctrl_drv_data *d = bank->drvdata; unsigned char index = EINT_OFFS(bank->eint_offset) + irqd->hwirq; - void __iomem *reg = d->virt_base + EINTMASK_REG(bank->eint_offset); + void __iomem *reg = bank->eint_base + EINTMASK_REG(bank->eint_offset); u32 val; val = readl(reg); @@ -334,9 +333,8 @@ static void s3c64xx_gpio_irq_mask(struct irq_data *irqd) static void s3c64xx_gpio_irq_ack(struct irq_data *irqd) { struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd); - struct samsung_pinctrl_drv_data *d = bank->drvdata; unsigned char index = EINT_OFFS(bank->eint_offset) + irqd->hwirq; - void __iomem *reg = d->virt_base + EINTPEND_REG(bank->eint_offset); + void __iomem *reg = bank->eint_base + EINTPEND_REG(bank->eint_offset); writel(1 << index, reg); } @@ -359,7 +357,7 @@ static int s3c64xx_gpio_irq_set_type(struct irq_data *irqd, unsigned int type) s3c64xx_irq_set_handler(irqd, type); /* Set up interrupt trigger */ - reg = d->virt_base + EINTCON_REG(bank->eint_offset); + reg = bank->eint_base + EINTCON_REG(bank->eint_offset); shift = EINT_OFFS(bank->eint_offset) + irqd->hwirq; shift = 4 * (shift / 4); /* 4 EINTs per trigger selector */ @@ -411,7 +409,8 @@ static void s3c64xx_eint_gpio_irq(struct irq_desc *desc) { struct irq_chip *chip = irq_desc_get_chip(desc); struct s3c64xx_eint_gpio_data *data = irq_desc_get_handler_data(desc); - struct samsung_pinctrl_drv_data *drvdata = data->drvdata; + struct irq_data *irqd = irq_desc_get_irq_data(desc); + struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd); chained_irq_enter(chip, desc); @@ -421,7 +420,7 @@ static void s3c64xx_eint_gpio_irq(struct irq_desc *desc) unsigned int pin; unsigned int virq; - svc = readl(drvdata->virt_base + SERVICE_REG); + svc = readl(bank->eint_base + SERVICE_REG); group = SVC_GROUP(svc); pin = svc & SVC_NUM_MASK; @@ -490,10 +489,8 @@ static int s3c64xx_eint_gpio_init(struct samsung_pinctrl_drv_data *d) data = devm_kzalloc(dev, sizeof(*data) + nr_domains * sizeof(*data->domains), GFP_KERNEL); - if (!data) { - dev_err(dev, "failed to allocate handler data\n"); + if (!data) return -ENOMEM; - } data->drvdata = d; bank = d->pin_banks; @@ -518,15 +515,15 @@ static inline void s3c64xx_eint0_irq_set_mask(struct irq_data *irqd, bool mask) { struct s3c64xx_eint0_domain_data *ddata = irq_data_get_irq_chip_data(irqd); - struct samsung_pinctrl_drv_data *d = ddata->bank->drvdata; + struct samsung_pin_bank *bank = ddata->bank; u32 val; - val = readl(d->virt_base + EINT0MASK_REG); + val = readl(bank->eint_base + EINT0MASK_REG); if (mask) val |= 1 << ddata->eints[irqd->hwirq]; else val &= ~(1 << ddata->eints[irqd->hwirq]); - writel(val, d->virt_base + EINT0MASK_REG); + writel(val, bank->eint_base + EINT0MASK_REG); } static void s3c64xx_eint0_irq_unmask(struct irq_data *irqd) @@ -543,10 +540,10 @@ static void s3c64xx_eint0_irq_ack(struct irq_data *irqd) { struct s3c64xx_eint0_domain_data *ddata = irq_data_get_irq_chip_data(irqd); - struct samsung_pinctrl_drv_data *d = ddata->bank->drvdata; + struct samsung_pin_bank *bank = ddata->bank; writel(1 << ddata->eints[irqd->hwirq], - d->virt_base + EINT0PEND_REG); + bank->eint_base + EINT0PEND_REG); } static int s3c64xx_eint0_irq_set_type(struct irq_data *irqd, unsigned int type) @@ -554,7 +551,7 @@ static int s3c64xx_eint0_irq_set_type(struct irq_data *irqd, unsigned int type) struct s3c64xx_eint0_domain_data *ddata = irq_data_get_irq_chip_data(irqd); struct samsung_pin_bank *bank = ddata->bank; - struct samsung_pinctrl_drv_data *d = bank->drvdata; + struct samsung_pinctrl_drv_data *d = ddata->bank->drvdata; void __iomem *reg; int trigger; u8 shift; @@ -569,7 +566,7 @@ static int s3c64xx_eint0_irq_set_type(struct irq_data *irqd, unsigned int type) s3c64xx_irq_set_handler(irqd, type); /* Set up interrupt trigger */ - reg = d->virt_base + EINT0CON0_REG; + reg = bank->eint_base + EINT0CON0_REG; shift = ddata->eints[irqd->hwirq]; if (shift >= EINT_MAX_PER_REG) { reg += 4; @@ -601,14 +598,19 @@ static struct irq_chip s3c64xx_eint0_irq_chip = { static inline void s3c64xx_irq_demux_eint(struct irq_desc *desc, u32 range) { struct irq_chip *chip = irq_desc_get_chip(desc); + struct irq_data *irqd = irq_desc_get_irq_data(desc); + struct s3c64xx_eint0_domain_data *ddata = + irq_data_get_irq_chip_data(irqd); + struct samsung_pin_bank *bank = ddata->bank; + struct s3c64xx_eint0_data *data = irq_desc_get_handler_data(desc); - struct samsung_pinctrl_drv_data *drvdata = data->drvdata; + unsigned int pend, mask; chained_irq_enter(chip, desc); - pend = readl(drvdata->virt_base + EINT0PEND_REG); - mask = readl(drvdata->virt_base + EINT0MASK_REG); + pend = readl(bank->eint_base + EINT0PEND_REG); + mask = readl(bank->eint_base + EINT0MASK_REG); pend = pend & range & ~mask; pend &= range; @@ -711,10 +713,8 @@ static int s3c64xx_eint_eint0_init(struct samsung_pinctrl_drv_data *d) return -ENODEV; data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); - if (!data) { - dev_err(dev, "could not allocate memory for wkup eint data\n"); + if (!data) return -ENOMEM; - } data->drvdata = d; for (i = 0; i < NUM_EINT0_IRQ; ++i) { @@ -747,10 +747,8 @@ static int s3c64xx_eint_eint0_init(struct samsung_pinctrl_drv_data *d) ddata = devm_kzalloc(dev, sizeof(*ddata) + nr_eints, GFP_KERNEL); - if (!ddata) { - dev_err(dev, "failed to allocate domain data\n"); + if (!ddata) return -ENOMEM; - } ddata->bank = bank; bank->irq_domain = irq_domain_add_linear(bank->of_node, diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/samsung/pinctrl-samsung.c index 620727fabe64..f9ddba7decc1 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.c +++ b/drivers/pinctrl/samsung/pinctrl-samsung.c @@ -27,12 +27,15 @@ #include <linux/err.h> #include <linux/gpio.h> #include <linux/irqdomain.h> +#include <linux/of_device.h> #include <linux/spinlock.h> -#include <linux/syscore_ops.h> #include "../core.h" #include "pinctrl-samsung.h" +/* maximum number of the memory resources */ +#define SAMSUNG_PINCTRL_NUM_RESOURCES 2 + /* list of all possible config options supported */ static struct pin_config { const char *property; @@ -45,9 +48,6 @@ static struct pin_config { { "samsung,pin-val", PINCFG_TYPE_DAT }, }; -/* Global list of devices (struct samsung_pinctrl_drv_data) */ -static LIST_HEAD(drvdata_list); - static unsigned int pin_base; static int samsung_get_group_count(struct pinctrl_dev *pctldev) @@ -90,10 +90,8 @@ static int reserve_map(struct device *dev, struct pinctrl_map **map, return 0; new_map = krealloc(*map, sizeof(*new_map) * new_num, GFP_KERNEL); - if (!new_map) { - dev_err(dev, "krealloc(map) failed\n"); + if (!new_map) return -ENOMEM; - } memset(new_map + old_num, 0, (new_num - old_num) * sizeof(*new_map)); @@ -130,10 +128,8 @@ static int add_map_configs(struct device *dev, struct pinctrl_map **map, dup_configs = kmemdup(configs, num_configs * sizeof(*dup_configs), GFP_KERNEL); - if (!dup_configs) { - dev_err(dev, "kmemdup(configs) failed\n"); + if (!dup_configs) return -ENOMEM; - } (*map)[*num_maps].type = PIN_MAP_TYPE_CONFIGS_GROUP; (*map)[*num_maps].data.configs.group_or_pin = group; @@ -153,10 +149,8 @@ static int add_config(struct device *dev, unsigned long **configs, new_configs = krealloc(*configs, sizeof(*new_configs) * new_num, GFP_KERNEL); - if (!new_configs) { - dev_err(dev, "krealloc(configs) failed\n"); + if (!new_configs) return -ENOMEM; - } new_configs[old_num] = config; @@ -345,7 +339,7 @@ static void pin_to_reg_bank(struct samsung_pinctrl_drv_data *drvdata, ((b->pin_base + b->nr_pins - 1) < pin)) b++; - *reg = drvdata->virt_base + b->pctl_offset; + *reg = b->pctl_base + b->pctl_offset; *offset = pin - b->pin_base; if (bank) *bank = b; @@ -353,7 +347,7 @@ static void pin_to_reg_bank(struct samsung_pinctrl_drv_data *drvdata, /* enable or disable a pinmux function */ static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector, - unsigned group, bool enable) + unsigned group) { struct samsung_pinctrl_drv_data *drvdata; const struct samsung_pin_bank_type *type; @@ -383,8 +377,7 @@ static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector, data = readl(reg + type->reg_offset[PINCFG_TYPE_FUNC]); data &= ~(mask << shift); - if (enable) - data |= func->val << shift; + data |= func->val << shift; writel(data, reg + type->reg_offset[PINCFG_TYPE_FUNC]); spin_unlock_irqrestore(&bank->slock, flags); @@ -395,7 +388,7 @@ static int samsung_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned selector, unsigned group) { - samsung_pinmux_setup(pctldev, selector, group, true); + samsung_pinmux_setup(pctldev, selector, group); return 0; } @@ -526,7 +519,7 @@ static void samsung_gpio_set_value(struct gpio_chip *gc, void __iomem *reg; u32 data; - reg = bank->drvdata->virt_base + bank->pctl_offset; + reg = bank->pctl_base + bank->pctl_offset; data = readl(reg + type->reg_offset[PINCFG_TYPE_DAT]); data &= ~(1 << offset); @@ -554,7 +547,7 @@ static int samsung_gpio_get(struct gpio_chip *gc, unsigned offset) struct samsung_pin_bank *bank = gpiochip_get_data(gc); const struct samsung_pin_bank_type *type = bank->type; - reg = bank->drvdata->virt_base + bank->pctl_offset; + reg = bank->pctl_base + bank->pctl_offset; data = readl(reg + type->reg_offset[PINCFG_TYPE_DAT]); data >>= offset; @@ -581,8 +574,8 @@ static int samsung_gpio_set_direction(struct gpio_chip *gc, type = bank->type; drvdata = bank->drvdata; - reg = drvdata->virt_base + bank->pctl_offset + - type->reg_offset[PINCFG_TYPE_FUNC]; + reg = bank->pctl_base + bank->pctl_offset + + type->reg_offset[PINCFG_TYPE_FUNC]; mask = (1 << type->fld_width[PINCFG_TYPE_FUNC]) - 1; shift = offset * type->fld_width[PINCFG_TYPE_FUNC]; @@ -753,10 +746,8 @@ static struct samsung_pmx_func *samsung_pinctrl_create_functions( functions = devm_kzalloc(dev, func_cnt * sizeof(*functions), GFP_KERNEL); - if (!functions) { - dev_err(dev, "failed to allocate memory for function list\n"); - return ERR_PTR(-EINVAL); - } + if (!functions) + return ERR_PTR(-ENOMEM); func = functions; /* @@ -847,10 +838,8 @@ static int samsung_pinctrl_register(struct platform_device *pdev, pindesc = devm_kzalloc(&pdev->dev, sizeof(*pindesc) * drvdata->nr_pins, GFP_KERNEL); - if (!pindesc) { - dev_err(&pdev->dev, "mem alloc for pin descriptors failed\n"); + if (!pindesc) return -ENOMEM; - } ctrldesc->pins = pindesc; ctrldesc->npins = drvdata->nr_pins; @@ -864,10 +853,8 @@ static int samsung_pinctrl_register(struct platform_device *pdev, */ pin_names = devm_kzalloc(&pdev->dev, sizeof(char) * PIN_NAME_LENGTH * drvdata->nr_pins, GFP_KERNEL); - if (!pin_names) { - dev_err(&pdev->dev, "mem alloc for pin names failed\n"); + if (!pin_names) return -ENOMEM; - } /* for each pin, the name of the pin is pin-bank name + pin number */ for (bank = 0; bank < drvdata->nr_banks; bank++) { @@ -965,20 +952,19 @@ static int samsung_gpiolib_unregister(struct platform_device *pdev, return 0; } -static const struct of_device_id samsung_pinctrl_dt_match[]; - /* retrieve the soc specific data */ static const struct samsung_pin_ctrl * samsung_pinctrl_get_soc_data(struct samsung_pinctrl_drv_data *d, struct platform_device *pdev) { int id; - const struct of_device_id *match; struct device_node *node = pdev->dev.of_node; struct device_node *np; const struct samsung_pin_bank_data *bdata; const struct samsung_pin_ctrl *ctrl; struct samsung_pin_bank *bank; + struct resource *res; + void __iomem *virt_base[SAMSUNG_PINCTRL_NUM_RESOURCES]; int i; id = of_alias_get_id(node, "pinctrl"); @@ -986,8 +972,8 @@ samsung_pinctrl_get_soc_data(struct samsung_pinctrl_drv_data *d, dev_err(&pdev->dev, "failed to get alias id\n"); return ERR_PTR(-ENOENT); } - match = of_match_node(samsung_pinctrl_dt_match, node); - ctrl = (struct samsung_pin_ctrl *)match->data + id; + ctrl = of_device_get_match_data(&pdev->dev); + ctrl += id; d->suspend = ctrl->suspend; d->resume = ctrl->resume; @@ -997,6 +983,16 @@ samsung_pinctrl_get_soc_data(struct samsung_pinctrl_drv_data *d, if (!d->pin_banks) return ERR_PTR(-ENOMEM); + if (ctrl->nr_ext_resources + 1 > SAMSUNG_PINCTRL_NUM_RESOURCES) + return ERR_PTR(-EINVAL); + + for (i = 0; i < ctrl->nr_ext_resources + 1; i++) { + res = platform_get_resource(pdev, IORESOURCE_MEM, i); + virt_base[i] = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(virt_base[i])) + return ERR_CAST(virt_base[i]); + } + bank = d->pin_banks; bdata = ctrl->pin_banks; for (i = 0; i < ctrl->nr_banks; ++i, ++bdata, ++bank) { @@ -1013,6 +1009,9 @@ samsung_pinctrl_get_soc_data(struct samsung_pinctrl_drv_data *d, bank->drvdata = d; bank->pin_base = d->nr_pins; d->nr_pins += bank->nr_pins; + + bank->eint_base = virt_base[0]; + bank->pctl_base = virt_base[bdata->pctl_res_idx]; } for_each_child_of_node(node, np) { @@ -1052,15 +1051,17 @@ static int samsung_pinctrl_probe(struct platform_device *pdev) } drvdata->dev = dev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - drvdata->virt_base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(drvdata->virt_base)) - return PTR_ERR(drvdata->virt_base); - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (res) drvdata->irq = res->start; + if (ctrl->retention_data) { + drvdata->retention_ctrl = ctrl->retention_data->init(drvdata, + ctrl->retention_data); + if (IS_ERR(drvdata->retention_ctrl)) + return PTR_ERR(drvdata->retention_ctrl); + } + ret = samsung_gpiolib_register(pdev, drvdata); if (ret) return ret; @@ -1078,28 +1079,22 @@ static int samsung_pinctrl_probe(struct platform_device *pdev) platform_set_drvdata(pdev, drvdata); - /* Add to the global list */ - list_add_tail(&drvdata->node, &drvdata_list); - return 0; } -#ifdef CONFIG_PM - /** - * samsung_pinctrl_suspend_dev - save pinctrl state for suspend for a device + * samsung_pinctrl_suspend - save pinctrl state for suspend * * Save data for all banks handled by this device. */ -static void samsung_pinctrl_suspend_dev( - struct samsung_pinctrl_drv_data *drvdata) +static int __maybe_unused samsung_pinctrl_suspend(struct device *dev) { - void __iomem *virt_base = drvdata->virt_base; + struct samsung_pinctrl_drv_data *drvdata = dev_get_drvdata(dev); int i; for (i = 0; i < drvdata->nr_banks; i++) { struct samsung_pin_bank *bank = &drvdata->pin_banks[i]; - void __iomem *reg = virt_base + bank->pctl_offset; + void __iomem *reg = bank->pctl_base + bank->pctl_offset; const u8 *offs = bank->type->reg_offset; const u8 *widths = bank->type->fld_width; enum pincfg_type type; @@ -1128,19 +1123,23 @@ static void samsung_pinctrl_suspend_dev( if (drvdata->suspend) drvdata->suspend(drvdata); + if (drvdata->retention_ctrl && drvdata->retention_ctrl->enable) + drvdata->retention_ctrl->enable(drvdata); + + return 0; } /** - * samsung_pinctrl_resume_dev - restore pinctrl state from suspend for a device + * samsung_pinctrl_resume - restore pinctrl state from suspend * * Restore one of the banks that was saved during suspend. * * We don't bother doing anything complicated to avoid glitching lines since * we're called before pad retention is turned off. */ -static void samsung_pinctrl_resume_dev(struct samsung_pinctrl_drv_data *drvdata) +static int __maybe_unused samsung_pinctrl_resume(struct device *dev) { - void __iomem *virt_base = drvdata->virt_base; + struct samsung_pinctrl_drv_data *drvdata = dev_get_drvdata(dev); int i; if (drvdata->resume) @@ -1148,7 +1147,7 @@ static void samsung_pinctrl_resume_dev(struct samsung_pinctrl_drv_data *drvdata) for (i = 0; i < drvdata->nr_banks; i++) { struct samsung_pin_bank *bank = &drvdata->pin_banks[i]; - void __iomem *reg = virt_base + bank->pctl_offset; + void __iomem *reg = bank->pctl_base + bank->pctl_offset; const u8 *offs = bank->type->reg_offset; const u8 *widths = bank->type->fld_width; enum pincfg_type type; @@ -1176,48 +1175,13 @@ static void samsung_pinctrl_resume_dev(struct samsung_pinctrl_drv_data *drvdata) if (widths[type]) writel(bank->pm_save[type], reg + offs[type]); } -} -/** - * samsung_pinctrl_suspend - save pinctrl state for suspend - * - * Save data for all banks across all devices. - */ -static int samsung_pinctrl_suspend(void) -{ - struct samsung_pinctrl_drv_data *drvdata; - - list_for_each_entry(drvdata, &drvdata_list, node) { - samsung_pinctrl_suspend_dev(drvdata); - } + if (drvdata->retention_ctrl && drvdata->retention_ctrl->disable) + drvdata->retention_ctrl->disable(drvdata); return 0; } -/** - * samsung_pinctrl_resume - restore pinctrl state for suspend - * - * Restore data for all banks across all devices. - */ -static void samsung_pinctrl_resume(void) -{ - struct samsung_pinctrl_drv_data *drvdata; - - list_for_each_entry_reverse(drvdata, &drvdata_list, node) { - samsung_pinctrl_resume_dev(drvdata); - } -} - -#else -#define samsung_pinctrl_suspend NULL -#define samsung_pinctrl_resume NULL -#endif - -static struct syscore_ops samsung_pinctrl_syscore_ops = { - .suspend = samsung_pinctrl_suspend, - .resume = samsung_pinctrl_resume, -}; - static const struct of_device_id samsung_pinctrl_dt_match[] = { #ifdef CONFIG_PINCTRL_EXYNOS { .compatible = "samsung,exynos3250-pinctrl", @@ -1226,8 +1190,6 @@ static const struct of_device_id samsung_pinctrl_dt_match[] = { .data = (void *)exynos4210_pin_ctrl }, { .compatible = "samsung,exynos4x12-pinctrl", .data = (void *)exynos4x12_pin_ctrl }, - { .compatible = "samsung,exynos4415-pinctrl", - .data = (void *)exynos4415_pin_ctrl }, { .compatible = "samsung,exynos5250-pinctrl", .data = (void *)exynos5250_pin_ctrl }, { .compatible = "samsung,exynos5260-pinctrl", @@ -1261,25 +1223,23 @@ static const struct of_device_id samsung_pinctrl_dt_match[] = { }; MODULE_DEVICE_TABLE(of, samsung_pinctrl_dt_match); +static const struct dev_pm_ops samsung_pinctrl_pm_ops = { + SET_LATE_SYSTEM_SLEEP_PM_OPS(samsung_pinctrl_suspend, + samsung_pinctrl_resume) +}; + static struct platform_driver samsung_pinctrl_driver = { .probe = samsung_pinctrl_probe, .driver = { .name = "samsung-pinctrl", .of_match_table = samsung_pinctrl_dt_match, .suppress_bind_attrs = true, + .pm = &samsung_pinctrl_pm_ops, }, }; static int __init samsung_pinctrl_drv_register(void) { - /* - * Register syscore ops for save/restore of registers across suspend. - * It's important to ensure that this driver is running at an earlier - * initcall level than any arch-specific init calls that install syscore - * ops that turn off pad retention (like exynos_pm_resume). - */ - register_syscore_ops(&samsung_pinctrl_syscore_ops); - return platform_driver_register(&samsung_pinctrl_driver); } postcore_initcall(samsung_pinctrl_drv_register); diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.h b/drivers/pinctrl/samsung/pinctrl-samsung.h index cd31bfaf62cb..515a61035e54 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.h +++ b/drivers/pinctrl/samsung/pinctrl-samsung.h @@ -116,6 +116,7 @@ struct samsung_pin_bank_type { * struct samsung_pin_bank_data: represent a controller pin-bank (init data). * @type: type of the bank (register offsets and bitfield widths) * @pctl_offset: starting offset of the pin-bank registers. + * @pctl_res_idx: index of base address for pin-bank registers. * @nr_pins: number of pins included in this bank. * @eint_func: function to set in CON register to configure pin as EINT. * @eint_type: type of the external interrupt supported by the bank. @@ -126,6 +127,7 @@ struct samsung_pin_bank_type { struct samsung_pin_bank_data { const struct samsung_pin_bank_type *type; u32 pctl_offset; + u8 pctl_res_idx; u8 nr_pins; u8 eint_func; enum eint_type eint_type; @@ -137,8 +139,10 @@ struct samsung_pin_bank_data { /** * struct samsung_pin_bank: represent a controller pin-bank. * @type: type of the bank (register offsets and bitfield widths) + * @pctl_base: base address of the pin-bank registers * @pctl_offset: starting offset of the pin-bank registers. * @nr_pins: number of pins included in this bank. + * @eint_base: base address of the pin-bank EINT registers. * @eint_func: function to set in CON register to configure pin as EINT. * @eint_type: type of the external interrupt supported by the bank. * @eint_mask: bit mask of pins which support EINT function. @@ -157,8 +161,10 @@ struct samsung_pin_bank_data { */ struct samsung_pin_bank { const struct samsung_pin_bank_type *type; + void __iomem *pctl_base; u32 pctl_offset; u8 nr_pins; + void __iomem *eint_base; u8 eint_func; enum eint_type eint_type; u32 eint_mask; @@ -179,9 +185,48 @@ struct samsung_pin_bank { }; /** + * struct samsung_retention_data: runtime pin-bank retention control data. + * @regs: array of PMU registers to control pad retention. + * @nr_regs: number of registers in @regs array. + * @value: value to store to registers to turn off retention. + * @refcnt: atomic counter if retention control affects more than one bank. + * @priv: retention control code private data + * @enable: platform specific callback to enter retention mode. + * @disable: platform specific callback to exit retention mode. + **/ +struct samsung_retention_ctrl { + const u32 *regs; + int nr_regs; + u32 value; + atomic_t *refcnt; + void *priv; + void (*enable)(struct samsung_pinctrl_drv_data *); + void (*disable)(struct samsung_pinctrl_drv_data *); +}; + +/** + * struct samsung_retention_data: represent a pin-bank retention control data. + * @regs: array of PMU registers to control pad retention. + * @nr_regs: number of registers in @regs array. + * @value: value to store to registers to turn off retention. + * @refcnt: atomic counter if retention control affects more than one bank. + * @init: platform specific callback to initialize retention control. + **/ +struct samsung_retention_data { + const u32 *regs; + int nr_regs; + u32 value; + atomic_t *refcnt; + struct samsung_retention_ctrl *(*init)(struct samsung_pinctrl_drv_data *, + const struct samsung_retention_data *); +}; + +/** * struct samsung_pin_ctrl: represent a pin controller. * @pin_banks: list of pin banks included in this controller. * @nr_banks: number of pin banks. + * @nr_ext_resources: number of the extra base address for pin banks. + * @retention_data: configuration data for retention control. * @eint_gpio_init: platform specific callback to setup the external gpio * interrupts for the controller. * @eint_wkup_init: platform specific callback to setup the external wakeup @@ -190,6 +235,8 @@ struct samsung_pin_bank { struct samsung_pin_ctrl { const struct samsung_pin_bank_data *pin_banks; u32 nr_banks; + int nr_ext_resources; + const struct samsung_retention_data *retention_data; int (*eint_gpio_init)(struct samsung_pinctrl_drv_data *); int (*eint_wkup_init)(struct samsung_pinctrl_drv_data *); @@ -200,7 +247,6 @@ struct samsung_pin_ctrl { /** * struct samsung_pinctrl_drv_data: wrapper for holding driver data together. * @node: global list node - * @virt_base: register base address of the controller. * @dev: device instance representing the controller. * @irq: interrpt number used by the controller to notify gpio interrupts. * @ctrl: pin controller instance managed by the driver. @@ -212,10 +258,10 @@ struct samsung_pin_ctrl { * @nr_function: number of such pin functions. * @pin_base: starting system wide pin number. * @nr_pins: number of pins supported by the controller. + * @retention_ctrl: retention control runtime data. */ struct samsung_pinctrl_drv_data { struct list_head node; - void __iomem *virt_base; struct device *dev; int irq; @@ -232,6 +278,8 @@ struct samsung_pinctrl_drv_data { unsigned int pin_base; unsigned int nr_pins; + struct samsung_retention_ctrl *retention_ctrl; + void (*suspend)(struct samsung_pinctrl_drv_data *); void (*resume)(struct samsung_pinctrl_drv_data *); }; @@ -267,7 +315,6 @@ struct samsung_pmx_func { extern const struct samsung_pin_ctrl exynos3250_pin_ctrl[]; extern const struct samsung_pin_ctrl exynos4210_pin_ctrl[]; extern const struct samsung_pin_ctrl exynos4x12_pin_ctrl[]; -extern const struct samsung_pin_ctrl exynos4415_pin_ctrl[]; extern const struct samsung_pin_ctrl exynos5250_pin_ctrl[]; extern const struct samsung_pin_ctrl exynos5260_pin_ctrl[]; extern const struct samsung_pin_ctrl exynos5410_pin_ctrl[]; |