pinctrl: samsung: Group all drivers in a sub-dir
authorSachin Kamat <sachin.kamat@samsung.com>
Thu, 10 Jul 2014 12:03:27 +0000 (17:33 +0530)
committerLinus Walleij <linus.walleij@linaro.org>
Fri, 11 Jul 2014 12:08:40 +0000 (14:08 +0200)
Group all pin control drivers of Samsung platform together in
a sub-directory for easy maintenance.

Signed-off-by: Sachin Kamat <sachin.kamat@samsung.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
18 files changed:
drivers/pinctrl/Kconfig
drivers/pinctrl/Makefile
drivers/pinctrl/pinctrl-exynos.c [deleted file]
drivers/pinctrl/pinctrl-exynos.h [deleted file]
drivers/pinctrl/pinctrl-exynos5440.c [deleted file]
drivers/pinctrl/pinctrl-s3c24xx.c [deleted file]
drivers/pinctrl/pinctrl-s3c64xx.c [deleted file]
drivers/pinctrl/pinctrl-samsung.c [deleted file]
drivers/pinctrl/pinctrl-samsung.h [deleted file]
drivers/pinctrl/samsung/Kconfig [new file with mode: 0644]
drivers/pinctrl/samsung/Makefile [new file with mode: 0644]
drivers/pinctrl/samsung/pinctrl-exynos.c [new file with mode: 0644]
drivers/pinctrl/samsung/pinctrl-exynos.h [new file with mode: 0644]
drivers/pinctrl/samsung/pinctrl-exynos5440.c [new file with mode: 0644]
drivers/pinctrl/samsung/pinctrl-s3c24xx.c [new file with mode: 0644]
drivers/pinctrl/samsung/pinctrl-s3c64xx.c [new file with mode: 0644]
drivers/pinctrl/samsung/pinctrl-samsung.c [new file with mode: 0644]
drivers/pinctrl/samsung/pinctrl-samsung.h [new file with mode: 0644]

index e2c7e09783fa7ddecfdb2ac3abc6645021ea843f..53e07c70951f64f6b5638a13095ee94927fd24ac 100644 (file)
@@ -332,22 +332,6 @@ 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_SAMSUNG
-       bool
-       select PINMUX
-       select PINCONF
-
-config PINCTRL_EXYNOS
-       bool "Pinctrl driver data for Samsung EXYNOS SoCs other than 5440"
-       depends on OF && GPIOLIB && (ARCH_EXYNOS || ARCH_S5PV210)
-       select PINCTRL_SAMSUNG
-
-config PINCTRL_EXYNOS5440
-       bool "Samsung EXYNOS5440 SoC pinctrl driver"
-       depends on SOC_EXYNOS5440
-       select PINMUX
-       select PINCONF
-
 config PINCTRL_PALMAS
        bool "Pinctrl driver for the PALMAS Series MFD devices"
        depends on OF && MFD_PALMAS
@@ -359,19 +343,10 @@ config PINCTRL_PALMAS
          open drain configuration for the Palmas series devices like
          TPS65913, TPS80036 etc.
 
-config PINCTRL_S3C24XX
-       bool "Samsung S3C24XX SoC pinctrl driver"
-       depends on ARCH_S3C24XX
-       select PINCTRL_SAMSUNG
-
-config PINCTRL_S3C64XX
-       bool "Samsung S3C64XX SoC pinctrl driver"
-       depends on ARCH_S3C64XX
-       select PINCTRL_SAMSUNG
-
 source "drivers/pinctrl/berlin/Kconfig"
 source "drivers/pinctrl/mvebu/Kconfig"
 source "drivers/pinctrl/qcom/Kconfig"
+source "drivers/pinctrl/samsung/Kconfig"
 source "drivers/pinctrl/sh-pfc/Kconfig"
 source "drivers/pinctrl/spear/Kconfig"
 source "drivers/pinctrl/sunxi/Kconfig"
index abe17724036cba06c53384b92ba03d8426500eec..df6099df7aad1d5bb32caf2b7e259b0299d102fb 100644 (file)
@@ -56,11 +56,6 @@ obj-$(CONFIG_PINCTRL_TZ1090) += pinctrl-tz1090.o
 obj-$(CONFIG_PINCTRL_TZ1090_PDC)       += pinctrl-tz1090-pdc.o
 obj-$(CONFIG_PINCTRL_U300)     += pinctrl-u300.o
 obj-$(CONFIG_PINCTRL_COH901)   += pinctrl-coh901.o
-obj-$(CONFIG_PINCTRL_SAMSUNG)  += pinctrl-samsung.o
-obj-$(CONFIG_PINCTRL_EXYNOS)   += pinctrl-exynos.o
-obj-$(CONFIG_PINCTRL_EXYNOS5440)       += pinctrl-exynos5440.o
-obj-$(CONFIG_PINCTRL_S3C24XX)  += pinctrl-s3c24xx.o
-obj-$(CONFIG_PINCTRL_S3C64XX)  += pinctrl-s3c64xx.o
 obj-$(CONFIG_PINCTRL_XWAY)     += pinctrl-xway.o
 obj-$(CONFIG_PINCTRL_LANTIQ)   += pinctrl-lantiq.o
 obj-$(CONFIG_PINCTRL_TB10X)    += pinctrl-tb10x.o
@@ -70,8 +65,9 @@ obj-$(CONFIG_PINCTRL_VF610)   += pinctrl-vf610.o
 obj-$(CONFIG_ARCH_BERLIN)      += berlin/
 obj-$(CONFIG_PLAT_ORION)        += mvebu/
 obj-$(CONFIG_ARCH_QCOM)                += qcom/
+obj-$(CONFIG_PLAT_SAMSUNG)     += samsung/
 obj-$(CONFIG_ARCH_SHMOBILE)    += sh-pfc/
 obj-$(CONFIG_SUPERH)           += sh-pfc/
 obj-$(CONFIG_PLAT_SPEAR)       += spear/
-obj-$(CONFIG_ARCH_VT8500)      += vt8500/
 obj-$(CONFIG_ARCH_SUNXI)       += sunxi/
+obj-$(CONFIG_ARCH_VT8500)      += vt8500/
diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c
deleted file mode 100644 (file)
index 003bfd8..0000000
+++ /dev/null
@@ -1,1123 +0,0 @@
-/*
- * Exynos specific support for Samsung pinctrl/gpiolib driver with eint support.
- *
- * Copyright (c) 2012 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com
- * Copyright (c) 2012 Linaro Ltd
- *             http://www.linaro.org
- *
- * Author: Thomas Abraham <thomas.ab@samsung.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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This file contains the Samsung Exynos specific information required by the
- * the Samsung pinctrl/gpiolib driver. It also includes the implementation of
- * external gpio and wakeup interrupt support.
- */
-
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/interrupt.h>
-#include <linux/irqdomain.h>
-#include <linux/irq.h>
-#include <linux/irqchip/chained_irq.h>
-#include <linux/of_irq.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/err.h>
-
-#include "pinctrl-samsung.h"
-#include "pinctrl-exynos.h"
-
-struct exynos_irq_chip {
-       struct irq_chip chip;
-
-       u32 eint_con;
-       u32 eint_mask;
-       u32 eint_pend;
-};
-
-static inline struct exynos_irq_chip *to_exynos_irq_chip(struct irq_chip *chip)
-{
-       return container_of(chip, struct exynos_irq_chip, chip);
-}
-
-static struct samsung_pin_bank_type bank_type_off = {
-       .fld_width = { 4, 1, 2, 2, 2, 2, },
-       .reg_offset = { 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, },
-};
-
-static struct samsung_pin_bank_type bank_type_alive = {
-       .fld_width = { 4, 1, 2, 2, },
-       .reg_offset = { 0x00, 0x04, 0x08, 0x0c, },
-};
-
-/* list of external wakeup controllers supported */
-static const struct of_device_id exynos_wkup_irq_ids[] = {
-       { .compatible = "samsung,exynos4210-wakeup-eint", },
-       { }
-};
-
-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 |= 1 << irqd->hwirq;
-       writel(mask, d->virt_base + reg_mask);
-
-       spin_unlock_irqrestore(&bank->slock, flags);
-}
-
-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);
-}
-
-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;
-
-       /*
-        * Ack level interrupts right before unmask
-        *
-        * If we don't do this we'll get a double-interrupt.  Level triggered
-        * interrupts must not fire an interrupt if the level is not
-        * _currently_ active, even if it was active while the interrupt was
-        * masked.
-        */
-       if (irqd_get_trigger_type(irqd) & IRQ_TYPE_LEVEL_MASK)
-               exynos_irq_ack(irqd);
-
-       spin_lock_irqsave(&bank->slock, flags);
-
-       mask = readl(d->virt_base + reg_mask);
-       mask &= ~(1 << irqd->hwirq);
-       writel(mask, d->virt_base + reg_mask);
-
-       spin_unlock_irqrestore(&bank->slock, flags);
-}
-
-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_pin_bank_type *bank_type = bank->type;
-       struct samsung_pinctrl_drv_data *d = bank->drvdata;
-       unsigned int pin = irqd->hwirq;
-       unsigned int shift = EXYNOS_EINT_CON_LEN * pin;
-       unsigned int con, trig_type;
-       unsigned long reg_con = our_chip->eint_con + bank->eint_offset;
-       unsigned long flags;
-       unsigned int mask;
-
-       switch (type) {
-       case IRQ_TYPE_EDGE_RISING:
-               trig_type = EXYNOS_EINT_EDGE_RISING;
-               break;
-       case IRQ_TYPE_EDGE_FALLING:
-               trig_type = EXYNOS_EINT_EDGE_FALLING;
-               break;
-       case IRQ_TYPE_EDGE_BOTH:
-               trig_type = EXYNOS_EINT_EDGE_BOTH;
-               break;
-       case IRQ_TYPE_LEVEL_HIGH:
-               trig_type = EXYNOS_EINT_LEVEL_HIGH;
-               break;
-       case IRQ_TYPE_LEVEL_LOW:
-               trig_type = EXYNOS_EINT_LEVEL_LOW;
-               break;
-       default:
-               pr_err("unsupported external interrupt type\n");
-               return -EINVAL;
-       }
-
-       if (type & IRQ_TYPE_EDGE_BOTH)
-               __irq_set_handler_locked(irqd->irq, handle_edge_irq);
-       else
-               __irq_set_handler_locked(irqd->irq, handle_level_irq);
-
-       con = readl(d->virt_base + reg_con);
-       con &= ~(EXYNOS_EINT_CON_MASK << shift);
-       con |= trig_type << shift;
-       writel(con, d->virt_base + reg_con);
-
-       reg_con = bank->pctl_offset + bank_type->reg_offset[PINCFG_TYPE_FUNC];
-       shift = pin * bank_type->fld_width[PINCFG_TYPE_FUNC];
-       mask = (1 << bank_type->fld_width[PINCFG_TYPE_FUNC]) - 1;
-
-       spin_lock_irqsave(&bank->slock, flags);
-
-       con = readl(d->virt_base + reg_con);
-       con &= ~(mask << shift);
-       con |= EXYNOS_EINT_FUNC << shift;
-       writel(con, d->virt_base + reg_con);
-
-       spin_unlock_irqrestore(&bank->slock, flags);
-
-       return 0;
-}
-
-/*
- * irq_chip for gpio interrupts.
- */
-static struct exynos_irq_chip exynos_gpio_irq_chip = {
-       .chip = {
-               .name = "exynos_gpio_irq_chip",
-               .irq_unmask = exynos_irq_unmask,
-               .irq_mask = exynos_irq_mask,
-               .irq_ack = exynos_irq_ack,
-               .irq_set_type = exynos_irq_set_type,
-       },
-       .eint_con = EXYNOS_GPIO_ECON_OFFSET,
-       .eint_mask = EXYNOS_GPIO_EMASK_OFFSET,
-       .eint_pend = EXYNOS_GPIO_EPEND_OFFSET,
-};
-
-static int exynos_gpio_irq_map(struct irq_domain *h, unsigned int virq,
-                                       irq_hw_number_t hw)
-{
-       struct samsung_pin_bank *b = h->host_data;
-
-       irq_set_chip_data(virq, b);
-       irq_set_chip_and_handler(virq, &exynos_gpio_irq_chip.chip,
-                                       handle_level_irq);
-       set_irq_flags(virq, IRQF_VALID);
-       return 0;
-}
-
-/*
- * irq domain callbacks for external gpio interrupt controller.
- */
-static const struct irq_domain_ops exynos_gpio_irqd_ops = {
-       .map    = exynos_gpio_irq_map,
-       .xlate  = irq_domain_xlate_twocell,
-};
-
-static irqreturn_t exynos_eint_gpio_irq(int irq, void *data)
-{
-       struct samsung_pinctrl_drv_data *d = data;
-       struct samsung_pin_ctrl *ctrl = d->ctrl;
-       struct samsung_pin_bank *bank = ctrl->pin_banks;
-       unsigned int svc, group, pin, virq;
-
-       svc = readl(d->virt_base + EXYNOS_SVC_OFFSET);
-       group = EXYNOS_SVC_GROUP(svc);
-       pin = svc & EXYNOS_SVC_NUM_MASK;
-
-       if (!group)
-               return IRQ_HANDLED;
-       bank += (group - 1);
-
-       virq = irq_linear_revmap(bank->irq_domain, pin);
-       if (!virq)
-               return IRQ_NONE;
-       generic_handle_irq(virq);
-       return IRQ_HANDLED;
-}
-
-struct exynos_eint_gpio_save {
-       u32 eint_con;
-       u32 eint_fltcon0;
-       u32 eint_fltcon1;
-};
-
-/*
- * exynos_eint_gpio_init() - setup handling of external gpio interrupts.
- * @d: driver data of samsung pinctrl driver.
- */
-static int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d)
-{
-       struct samsung_pin_bank *bank;
-       struct device *dev = d->dev;
-       int ret;
-       int i;
-
-       if (!d->irq) {
-               dev_err(dev, "irq number not available\n");
-               return -EINVAL;
-       }
-
-       ret = devm_request_irq(dev, d->irq, exynos_eint_gpio_irq,
-                                       0, dev_name(dev), d);
-       if (ret) {
-               dev_err(dev, "irq request failed\n");
-               return -ENXIO;
-       }
-
-       bank = d->ctrl->pin_banks;
-       for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) {
-               if (bank->eint_type != EINT_TYPE_GPIO)
-                       continue;
-               bank->irq_domain = irq_domain_add_linear(bank->of_node,
-                               bank->nr_pins, &exynos_gpio_irqd_ops, bank);
-               if (!bank->irq_domain) {
-                       dev_err(dev, "gpio irq domain add failed\n");
-                       ret = -ENXIO;
-                       goto err_domains;
-               }
-
-               bank->soc_priv = devm_kzalloc(d->dev,
-                       sizeof(struct exynos_eint_gpio_save), GFP_KERNEL);
-               if (!bank->soc_priv) {
-                       irq_domain_remove(bank->irq_domain);
-                       ret = -ENOMEM;
-                       goto err_domains;
-               }
-       }
-
-       return 0;
-
-err_domains:
-       for (--i, --bank; i >= 0; --i, --bank) {
-               if (bank->eint_type != EINT_TYPE_GPIO)
-                       continue;
-               irq_domain_remove(bank->irq_domain);
-       }
-
-       return ret;
-}
-
-static u32 exynos_eint_wake_mask = 0xffffffff;
-
-u32 exynos_get_eint_wake_mask(void)
-{
-       return exynos_eint_wake_mask;
-}
-
-static int exynos_wkup_irq_set_wake(struct irq_data *irqd, unsigned int on)
-{
-       struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
-       unsigned long bit = 1UL << (2 * bank->eint_offset + irqd->hwirq);
-
-       pr_info("wake %s for irq %d\n", on ? "enabled" : "disabled", irqd->irq);
-
-       if (!on)
-               exynos_eint_wake_mask |= bit;
-       else
-               exynos_eint_wake_mask &= ~bit;
-
-       return 0;
-}
-
-/*
- * irq_chip for wakeup interrupts
- */
-static struct exynos_irq_chip exynos_wkup_irq_chip = {
-       .chip = {
-               .name = "exynos_wkup_irq_chip",
-               .irq_unmask = exynos_irq_unmask,
-               .irq_mask = exynos_irq_mask,
-               .irq_ack = exynos_irq_ack,
-               .irq_set_type = exynos_irq_set_type,
-               .irq_set_wake = exynos_wkup_irq_set_wake,
-       },
-       .eint_con = EXYNOS_WKUP_ECON_OFFSET,
-       .eint_mask = EXYNOS_WKUP_EMASK_OFFSET,
-       .eint_pend = EXYNOS_WKUP_EPEND_OFFSET,
-};
-
-/* interrupt handler for wakeup interrupts 0..15 */
-static void exynos_irq_eint0_15(unsigned int irq, struct irq_desc *desc)
-{
-       struct exynos_weint_data *eintd = irq_get_handler_data(irq);
-       struct samsung_pin_bank *bank = eintd->bank;
-       struct irq_chip *chip = irq_get_chip(irq);
-       int eint_irq;
-
-       chained_irq_enter(chip, desc);
-       chip->irq_mask(&desc->irq_data);
-
-       if (chip->irq_ack)
-               chip->irq_ack(&desc->irq_data);
-
-       eint_irq = irq_linear_revmap(bank->irq_domain, eintd->irq);
-       generic_handle_irq(eint_irq);
-       chip->irq_unmask(&desc->irq_data);
-       chained_irq_exit(chip, desc);
-}
-
-static inline void exynos_irq_demux_eint(unsigned long pend,
-                                               struct irq_domain *domain)
-{
-       unsigned int irq;
-
-       while (pend) {
-               irq = fls(pend) - 1;
-               generic_handle_irq(irq_find_mapping(domain, irq));
-               pend &= ~(1 << irq);
-       }
-}
-
-/* interrupt handler for wakeup interrupt 16 */
-static void exynos_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc)
-{
-       struct irq_chip *chip = irq_get_chip(irq);
-       struct exynos_muxed_weint_data *eintd = irq_get_handler_data(irq);
-       struct samsung_pinctrl_drv_data *d = eintd->banks[0]->drvdata;
-       unsigned long pend;
-       unsigned long mask;
-       int i;
-
-       chained_irq_enter(chip, desc);
-
-       for (i = 0; i < eintd->nr_banks; ++i) {
-               struct samsung_pin_bank *b = eintd->banks[i];
-               pend = readl(d->virt_base + EXYNOS_WKUP_EPEND_OFFSET
-                               + b->eint_offset);
-               mask = readl(d->virt_base + EXYNOS_WKUP_EMASK_OFFSET
-                               + b->eint_offset);
-               exynos_irq_demux_eint(pend & ~mask, b->irq_domain);
-       }
-
-       chained_irq_exit(chip, desc);
-}
-
-static int exynos_wkup_irq_map(struct irq_domain *h, unsigned int virq,
-                                       irq_hw_number_t hw)
-{
-       irq_set_chip_and_handler(virq, &exynos_wkup_irq_chip.chip,
-                                       handle_level_irq);
-       irq_set_chip_data(virq, h->host_data);
-       set_irq_flags(virq, IRQF_VALID);
-       return 0;
-}
-
-/*
- * irq domain callbacks for external wakeup interrupt controller.
- */
-static const struct irq_domain_ops exynos_wkup_irqd_ops = {
-       .map    = exynos_wkup_irq_map,
-       .xlate  = irq_domain_xlate_twocell,
-};
-
-/*
- * exynos_eint_wkup_init() - setup handling of external wakeup interrupts.
- * @d: driver data of samsung pinctrl driver.
- */
-static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d)
-{
-       struct device *dev = d->dev;
-       struct device_node *wkup_np = NULL;
-       struct device_node *np;
-       struct samsung_pin_bank *bank;
-       struct exynos_weint_data *weint_data;
-       struct exynos_muxed_weint_data *muxed_data;
-       unsigned int muxed_banks = 0;
-       unsigned int i;
-       int idx, irq;
-
-       for_each_child_of_node(dev->of_node, np) {
-               if (of_match_node(exynos_wkup_irq_ids, np)) {
-                       wkup_np = np;
-                       break;
-               }
-       }
-       if (!wkup_np)
-               return -ENODEV;
-
-       bank = d->ctrl->pin_banks;
-       for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) {
-               if (bank->eint_type != EINT_TYPE_WKUP)
-                       continue;
-
-               bank->irq_domain = irq_domain_add_linear(bank->of_node,
-                               bank->nr_pins, &exynos_wkup_irqd_ops, bank);
-               if (!bank->irq_domain) {
-                       dev_err(dev, "wkup irq domain add failed\n");
-                       return -ENXIO;
-               }
-
-               if (!of_find_property(bank->of_node, "interrupts", NULL)) {
-                       bank->eint_type = EINT_TYPE_WKUP_MUX;
-                       ++muxed_banks;
-                       continue;
-               }
-
-               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");
-                       return -ENOMEM;
-               }
-
-               for (idx = 0; idx < bank->nr_pins; ++idx) {
-                       irq = irq_of_parse_and_map(bank->of_node, idx);
-                       if (!irq) {
-                               dev_err(dev, "irq number for eint-%s-%d not found\n",
-                                                       bank->name, idx);
-                               continue;
-                       }
-                       weint_data[idx].irq = idx;
-                       weint_data[idx].bank = bank;
-                       irq_set_handler_data(irq, &weint_data[idx]);
-                       irq_set_chained_handler(irq, exynos_irq_eint0_15);
-               }
-       }
-
-       if (!muxed_banks)
-               return 0;
-
-       irq = irq_of_parse_and_map(wkup_np, 0);
-       if (!irq) {
-               dev_err(dev, "irq number for muxed EINTs not found\n");
-               return 0;
-       }
-
-       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");
-               return -ENOMEM;
-       }
-
-       irq_set_chained_handler(irq, exynos_irq_demux_eint16_31);
-       irq_set_handler_data(irq, muxed_data);
-
-       bank = d->ctrl->pin_banks;
-       idx = 0;
-       for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) {
-               if (bank->eint_type != EINT_TYPE_WKUP_MUX)
-                       continue;
-
-               muxed_data->banks[idx++] = bank;
-       }
-       muxed_data->nr_banks = muxed_banks;
-
-       return 0;
-}
-
-static void exynos_pinctrl_suspend_bank(
-                               struct samsung_pinctrl_drv_data *drvdata,
-                               struct samsung_pin_bank *bank)
-{
-       struct exynos_eint_gpio_save *save = bank->soc_priv;
-       void __iomem *regs = drvdata->virt_base;
-
-       save->eint_con = readl(regs + EXYNOS_GPIO_ECON_OFFSET
-                                               + bank->eint_offset);
-       save->eint_fltcon0 = readl(regs + EXYNOS_GPIO_EFLTCON_OFFSET
-                                               + 2 * bank->eint_offset);
-       save->eint_fltcon1 = readl(regs + EXYNOS_GPIO_EFLTCON_OFFSET
-                                               + 2 * bank->eint_offset + 4);
-
-       pr_debug("%s: save     con %#010x\n", bank->name, save->eint_con);
-       pr_debug("%s: save fltcon0 %#010x\n", bank->name, save->eint_fltcon0);
-       pr_debug("%s: save fltcon1 %#010x\n", bank->name, save->eint_fltcon1);
-}
-
-static void exynos_pinctrl_suspend(struct samsung_pinctrl_drv_data *drvdata)
-{
-       struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
-       struct samsung_pin_bank *bank = ctrl->pin_banks;
-       int i;
-
-       for (i = 0; i < ctrl->nr_banks; ++i, ++bank)
-               if (bank->eint_type == EINT_TYPE_GPIO)
-                       exynos_pinctrl_suspend_bank(drvdata, bank);
-}
-
-static void exynos_pinctrl_resume_bank(
-                               struct samsung_pinctrl_drv_data *drvdata,
-                               struct samsung_pin_bank *bank)
-{
-       struct exynos_eint_gpio_save *save = bank->soc_priv;
-       void __iomem *regs = drvdata->virt_base;
-
-       pr_debug("%s:     con %#010x => %#010x\n", bank->name,
-                       readl(regs + EXYNOS_GPIO_ECON_OFFSET
-                       + bank->eint_offset), save->eint_con);
-       pr_debug("%s: fltcon0 %#010x => %#010x\n", bank->name,
-                       readl(regs + EXYNOS_GPIO_EFLTCON_OFFSET
-                       + 2 * bank->eint_offset), save->eint_fltcon0);
-       pr_debug("%s: fltcon1 %#010x => %#010x\n", bank->name,
-                       readl(regs + EXYNOS_GPIO_EFLTCON_OFFSET
-                       + 2 * bank->eint_offset + 4), save->eint_fltcon1);
-
-       writel(save->eint_con, regs + EXYNOS_GPIO_ECON_OFFSET
-                                               + bank->eint_offset);
-       writel(save->eint_fltcon0, regs + EXYNOS_GPIO_EFLTCON_OFFSET
-                                               + 2 * bank->eint_offset);
-       writel(save->eint_fltcon1, regs + EXYNOS_GPIO_EFLTCON_OFFSET
-                                               + 2 * bank->eint_offset + 4);
-}
-
-static void exynos_pinctrl_resume(struct samsung_pinctrl_drv_data *drvdata)
-{
-       struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
-       struct samsung_pin_bank *bank = ctrl->pin_banks;
-       int i;
-
-       for (i = 0; i < ctrl->nr_banks; ++i, ++bank)
-               if (bank->eint_type == EINT_TYPE_GPIO)
-                       exynos_pinctrl_resume_bank(drvdata, bank);
-}
-
-/* pin banks of s5pv210 pin-controller */
-static struct samsung_pin_bank s5pv210_pin_bank[] = {
-       EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
-       EXYNOS_PIN_BANK_EINTG(4, 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(6, 0x0c0, "gpd1", 0x18),
-       EXYNOS_PIN_BANK_EINTG(8, 0x0e0, "gpe0", 0x1c),
-       EXYNOS_PIN_BANK_EINTG(5, 0x100, "gpe1", 0x20),
-       EXYNOS_PIN_BANK_EINTG(8, 0x120, "gpf0", 0x24),
-       EXYNOS_PIN_BANK_EINTG(8, 0x140, "gpf1", 0x28),
-       EXYNOS_PIN_BANK_EINTG(8, 0x160, "gpf2", 0x2c),
-       EXYNOS_PIN_BANK_EINTG(6, 0x180, "gpf3", 0x30),
-       EXYNOS_PIN_BANK_EINTG(7, 0x1a0, "gpg0", 0x34),
-       EXYNOS_PIN_BANK_EINTG(7, 0x1c0, "gpg1", 0x38),
-       EXYNOS_PIN_BANK_EINTG(7, 0x1e0, "gpg2", 0x3c),
-       EXYNOS_PIN_BANK_EINTG(7, 0x200, "gpg3", 0x40),
-       EXYNOS_PIN_BANK_EINTN(7, 0x220, "gpi"),
-       EXYNOS_PIN_BANK_EINTG(8, 0x240, "gpj0", 0x44),
-       EXYNOS_PIN_BANK_EINTG(6, 0x260, "gpj1", 0x48),
-       EXYNOS_PIN_BANK_EINTG(8, 0x280, "gpj2", 0x4c),
-       EXYNOS_PIN_BANK_EINTG(8, 0x2a0, "gpj3", 0x50),
-       EXYNOS_PIN_BANK_EINTG(5, 0x2c0, "gpj4", 0x54),
-       EXYNOS_PIN_BANK_EINTN(8, 0x2e0, "mp01"),
-       EXYNOS_PIN_BANK_EINTN(4, 0x300, "mp02"),
-       EXYNOS_PIN_BANK_EINTN(8, 0x320, "mp03"),
-       EXYNOS_PIN_BANK_EINTN(8, 0x340, "mp04"),
-       EXYNOS_PIN_BANK_EINTN(8, 0x360, "mp05"),
-       EXYNOS_PIN_BANK_EINTN(8, 0x380, "mp06"),
-       EXYNOS_PIN_BANK_EINTN(8, 0x3a0, "mp07"),
-       EXYNOS_PIN_BANK_EINTW(8, 0xc00, "gph0", 0x00),
-       EXYNOS_PIN_BANK_EINTW(8, 0xc20, "gph1", 0x04),
-       EXYNOS_PIN_BANK_EINTW(8, 0xc40, "gph2", 0x08),
-       EXYNOS_PIN_BANK_EINTW(8, 0xc60, "gph3", 0x0c),
-};
-
-struct samsung_pin_ctrl s5pv210_pin_ctrl[] = {
-       {
-               /* pin-controller instance 0 data */
-               .pin_banks      = s5pv210_pin_bank,
-               .nr_banks       = ARRAY_SIZE(s5pv210_pin_bank),
-               .eint_gpio_init = exynos_eint_gpio_init,
-               .eint_wkup_init = exynos_eint_wkup_init,
-               .suspend        = exynos_pinctrl_suspend,
-               .resume         = exynos_pinctrl_resume,
-               .label          = "s5pv210-gpio-ctrl0",
-       },
-};
-
-/* pin banks of exynos3250 pin-controller 0 */
-static struct samsung_pin_bank exynos3250_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),
-};
-
-/* pin banks of exynos3250 pin-controller 1 */
-static struct samsung_pin_bank exynos3250_pin_banks1[] = {
-       EXYNOS_PIN_BANK_EINTN(8, 0x120, "gpe0"),
-       EXYNOS_PIN_BANK_EINTN(8, 0x140, "gpe1"),
-       EXYNOS_PIN_BANK_EINTN(3, 0x180, "gpe2"),
-       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(4, 0x0c0, "gpl0", 0x18),
-       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),
-};
-
-/*
- * Samsung pinctrl driver data for Exynos3250 SoC. Exynos3250 SoC includes
- * two gpio/pin-mux/pinconfig controllers.
- */
-struct samsung_pin_ctrl exynos3250_pin_ctrl[] = {
-       {
-               /* pin-controller instance 0 data */
-               .pin_banks      = exynos3250_pin_banks0,
-               .nr_banks       = ARRAY_SIZE(exynos3250_pin_banks0),
-               .eint_gpio_init = exynos_eint_gpio_init,
-               .suspend        = exynos_pinctrl_suspend,
-               .resume         = exynos_pinctrl_resume,
-               .label          = "exynos3250-gpio-ctrl0",
-       }, {
-               /* pin-controller instance 1 data */
-               .pin_banks      = exynos3250_pin_banks1,
-               .nr_banks       = ARRAY_SIZE(exynos3250_pin_banks1),
-               .eint_gpio_init = exynos_eint_gpio_init,
-               .eint_wkup_init = exynos_eint_wkup_init,
-               .suspend        = exynos_pinctrl_suspend,
-               .resume         = exynos_pinctrl_resume,
-               .label          = "exynos3250-gpio-ctrl1",
-       },
-};
-
-/* pin banks of exynos4210 pin-controller 0 */
-static struct samsung_pin_bank exynos4210_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(5, 0x0E0, "gpe0", 0x1c),
-       EXYNOS_PIN_BANK_EINTG(8, 0x100, "gpe1", 0x20),
-       EXYNOS_PIN_BANK_EINTG(6, 0x120, "gpe2", 0x24),
-       EXYNOS_PIN_BANK_EINTG(8, 0x140, "gpe3", 0x28),
-       EXYNOS_PIN_BANK_EINTG(8, 0x160, "gpe4", 0x2c),
-       EXYNOS_PIN_BANK_EINTG(8, 0x180, "gpf0", 0x30),
-       EXYNOS_PIN_BANK_EINTG(8, 0x1A0, "gpf1", 0x34),
-       EXYNOS_PIN_BANK_EINTG(8, 0x1C0, "gpf2", 0x38),
-       EXYNOS_PIN_BANK_EINTG(6, 0x1E0, "gpf3", 0x3c),
-};
-
-/* pin banks of exynos4210 pin-controller 1 */
-static struct samsung_pin_bank exynos4210_pin_banks1[] = {
-       EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpj0", 0x00),
-       EXYNOS_PIN_BANK_EINTG(5, 0x020, "gpj1", 0x04),
-       EXYNOS_PIN_BANK_EINTG(7, 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(8, 0x0C0, "gpl0", 0x18),
-       EXYNOS_PIN_BANK_EINTG(3, 0x0E0, "gpl1", 0x1c),
-       EXYNOS_PIN_BANK_EINTG(8, 0x100, "gpl2", 0x20),
-       EXYNOS_PIN_BANK_EINTN(6, 0x120, "gpy0"),
-       EXYNOS_PIN_BANK_EINTN(4, 0x140, "gpy1"),
-       EXYNOS_PIN_BANK_EINTN(6, 0x160, "gpy2"),
-       EXYNOS_PIN_BANK_EINTN(8, 0x180, "gpy3"),
-       EXYNOS_PIN_BANK_EINTN(8, 0x1A0, "gpy4"),
-       EXYNOS_PIN_BANK_EINTN(8, 0x1C0, "gpy5"),
-       EXYNOS_PIN_BANK_EINTN(8, 0x1E0, "gpy6"),
-       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 exynos4210 pin-controller 2 */
-static struct samsung_pin_bank exynos4210_pin_banks2[] = {
-       EXYNOS_PIN_BANK_EINTN(7, 0x000, "gpz"),
-};
-
-/*
- * Samsung pinctrl driver data for Exynos4210 SoC. Exynos4210 SoC includes
- * three gpio/pin-mux/pinconfig controllers.
- */
-struct samsung_pin_ctrl exynos4210_pin_ctrl[] = {
-       {
-               /* pin-controller instance 0 data */
-               .pin_banks      = exynos4210_pin_banks0,
-               .nr_banks       = ARRAY_SIZE(exynos4210_pin_banks0),
-               .eint_gpio_init = exynos_eint_gpio_init,
-               .suspend        = exynos_pinctrl_suspend,
-               .resume         = exynos_pinctrl_resume,
-               .label          = "exynos4210-gpio-ctrl0",
-       }, {
-               /* pin-controller instance 1 data */
-               .pin_banks      = exynos4210_pin_banks1,
-               .nr_banks       = ARRAY_SIZE(exynos4210_pin_banks1),
-               .eint_gpio_init = exynos_eint_gpio_init,
-               .eint_wkup_init = exynos_eint_wkup_init,
-               .suspend        = exynos_pinctrl_suspend,
-               .resume         = exynos_pinctrl_resume,
-               .label          = "exynos4210-gpio-ctrl1",
-       }, {
-               /* pin-controller instance 2 data */
-               .pin_banks      = exynos4210_pin_banks2,
-               .nr_banks       = ARRAY_SIZE(exynos4210_pin_banks2),
-               .label          = "exynos4210-gpio-ctrl2",
-       },
-};
-
-/* pin banks of exynos4x12 pin-controller 0 */
-static struct samsung_pin_bank exynos4x12_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(8, 0x1C0, "gpf2", 0x38),
-       EXYNOS_PIN_BANK_EINTG(6, 0x1E0, "gpf3", 0x3c),
-       EXYNOS_PIN_BANK_EINTG(8, 0x240, "gpj0", 0x40),
-       EXYNOS_PIN_BANK_EINTG(5, 0x260, "gpj1", 0x44),
-};
-
-/* pin banks of exynos4x12 pin-controller 1 */
-static struct samsung_pin_bank exynos4x12_pin_banks1[] = {
-       EXYNOS_PIN_BANK_EINTG(7, 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(7, 0x0C0, "gpl0", 0x18),
-       EXYNOS_PIN_BANK_EINTG(2, 0x0E0, "gpl1", 0x1c),
-       EXYNOS_PIN_BANK_EINTG(8, 0x100, "gpl2", 0x20),
-       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_EINTN(6, 0x120, "gpy0"),
-       EXYNOS_PIN_BANK_EINTN(4, 0x140, "gpy1"),
-       EXYNOS_PIN_BANK_EINTN(6, 0x160, "gpy2"),
-       EXYNOS_PIN_BANK_EINTN(8, 0x180, "gpy3"),
-       EXYNOS_PIN_BANK_EINTN(8, 0x1A0, "gpy4"),
-       EXYNOS_PIN_BANK_EINTN(8, 0x1C0, "gpy5"),
-       EXYNOS_PIN_BANK_EINTN(8, 0x1E0, "gpy6"),
-       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 exynos4x12 pin-controller 2 */
-static struct samsung_pin_bank exynos4x12_pin_banks2[] = {
-       EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz", 0x00),
-};
-
-/* pin banks of exynos4x12 pin-controller 3 */
-static struct samsung_pin_bank exynos4x12_pin_banks3[] = {
-       EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpv0", 0x00),
-       EXYNOS_PIN_BANK_EINTG(8, 0x020, "gpv1", 0x04),
-       EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpv2", 0x08),
-       EXYNOS_PIN_BANK_EINTG(8, 0x060, "gpv3", 0x0c),
-       EXYNOS_PIN_BANK_EINTG(2, 0x080, "gpv4", 0x10),
-};
-
-/*
- * Samsung pinctrl driver data for Exynos4x12 SoC. Exynos4x12 SoC includes
- * four gpio/pin-mux/pinconfig controllers.
- */
-struct samsung_pin_ctrl exynos4x12_pin_ctrl[] = {
-       {
-               /* pin-controller instance 0 data */
-               .pin_banks      = exynos4x12_pin_banks0,
-               .nr_banks       = ARRAY_SIZE(exynos4x12_pin_banks0),
-               .eint_gpio_init = exynos_eint_gpio_init,
-               .suspend        = exynos_pinctrl_suspend,
-               .resume         = exynos_pinctrl_resume,
-               .label          = "exynos4x12-gpio-ctrl0",
-       }, {
-               /* pin-controller instance 1 data */
-               .pin_banks      = exynos4x12_pin_banks1,
-               .nr_banks       = ARRAY_SIZE(exynos4x12_pin_banks1),
-               .eint_gpio_init = exynos_eint_gpio_init,
-               .eint_wkup_init = exynos_eint_wkup_init,
-               .suspend        = exynos_pinctrl_suspend,
-               .resume         = exynos_pinctrl_resume,
-               .label          = "exynos4x12-gpio-ctrl1",
-       }, {
-               /* pin-controller instance 2 data */
-               .pin_banks      = exynos4x12_pin_banks2,
-               .nr_banks       = ARRAY_SIZE(exynos4x12_pin_banks2),
-               .eint_gpio_init = exynos_eint_gpio_init,
-               .suspend        = exynos_pinctrl_suspend,
-               .resume         = exynos_pinctrl_resume,
-               .label          = "exynos4x12-gpio-ctrl2",
-       }, {
-               /* pin-controller instance 3 data */
-               .pin_banks      = exynos4x12_pin_banks3,
-               .nr_banks       = ARRAY_SIZE(exynos4x12_pin_banks3),
-               .eint_gpio_init = exynos_eint_gpio_init,
-               .suspend        = exynos_pinctrl_suspend,
-               .resume         = exynos_pinctrl_resume,
-               .label          = "exynos4x12-gpio-ctrl3",
-       },
-};
-
-/* pin banks of exynos5250 pin-controller 0 */
-static struct samsung_pin_bank exynos5250_pin_banks0[] = {
-       EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
-       EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpa1", 0x04),
-       EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpa2", 0x08),
-       EXYNOS_PIN_BANK_EINTG(5, 0x060, "gpb0", 0x0c),
-       EXYNOS_PIN_BANK_EINTG(5, 0x080, "gpb1", 0x10),
-       EXYNOS_PIN_BANK_EINTG(4, 0x0A0, "gpb2", 0x14),
-       EXYNOS_PIN_BANK_EINTG(4, 0x0C0, "gpb3", 0x18),
-       EXYNOS_PIN_BANK_EINTG(7, 0x0E0, "gpc0", 0x1c),
-       EXYNOS_PIN_BANK_EINTG(4, 0x100, "gpc1", 0x20),
-       EXYNOS_PIN_BANK_EINTG(7, 0x120, "gpc2", 0x24),
-       EXYNOS_PIN_BANK_EINTG(7, 0x140, "gpc3", 0x28),
-       EXYNOS_PIN_BANK_EINTG(4, 0x160, "gpd0", 0x2c),
-       EXYNOS_PIN_BANK_EINTG(8, 0x180, "gpd1", 0x30),
-       EXYNOS_PIN_BANK_EINTG(7, 0x2E0, "gpc4", 0x34),
-       EXYNOS_PIN_BANK_EINTN(6, 0x1A0, "gpy0"),
-       EXYNOS_PIN_BANK_EINTN(4, 0x1C0, "gpy1"),
-       EXYNOS_PIN_BANK_EINTN(6, 0x1E0, "gpy2"),
-       EXYNOS_PIN_BANK_EINTN(8, 0x200, "gpy3"),
-       EXYNOS_PIN_BANK_EINTN(8, 0x220, "gpy4"),
-       EXYNOS_PIN_BANK_EINTN(8, 0x240, "gpy5"),
-       EXYNOS_PIN_BANK_EINTN(8, 0x260, "gpy6"),
-       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 exynos5250 pin-controller 1 */
-static struct samsung_pin_bank exynos5250_pin_banks1[] = {
-       EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpe0", 0x00),
-       EXYNOS_PIN_BANK_EINTG(2, 0x020, "gpe1", 0x04),
-       EXYNOS_PIN_BANK_EINTG(4, 0x040, "gpf0", 0x08),
-       EXYNOS_PIN_BANK_EINTG(4, 0x060, "gpf1", 0x0c),
-       EXYNOS_PIN_BANK_EINTG(8, 0x080, "gpg0", 0x10),
-       EXYNOS_PIN_BANK_EINTG(8, 0x0A0, "gpg1", 0x14),
-       EXYNOS_PIN_BANK_EINTG(2, 0x0C0, "gpg2", 0x18),
-       EXYNOS_PIN_BANK_EINTG(4, 0x0E0, "gph0", 0x1c),
-       EXYNOS_PIN_BANK_EINTG(8, 0x100, "gph1", 0x20),
-};
-
-/* pin banks of exynos5250 pin-controller 2 */
-static struct samsung_pin_bank exynos5250_pin_banks2[] = {
-       EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpv0", 0x00),
-       EXYNOS_PIN_BANK_EINTG(8, 0x020, "gpv1", 0x04),
-       EXYNOS_PIN_BANK_EINTG(8, 0x060, "gpv2", 0x08),
-       EXYNOS_PIN_BANK_EINTG(8, 0x080, "gpv3", 0x0c),
-       EXYNOS_PIN_BANK_EINTG(2, 0x0C0, "gpv4", 0x10),
-};
-
-/* pin banks of exynos5250 pin-controller 3 */
-static struct samsung_pin_bank exynos5250_pin_banks3[] = {
-       EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz", 0x00),
-};
-
-/*
- * Samsung pinctrl driver data for Exynos5250 SoC. Exynos5250 SoC includes
- * four gpio/pin-mux/pinconfig controllers.
- */
-struct samsung_pin_ctrl exynos5250_pin_ctrl[] = {
-       {
-               /* pin-controller instance 0 data */
-               .pin_banks      = exynos5250_pin_banks0,
-               .nr_banks       = ARRAY_SIZE(exynos5250_pin_banks0),
-               .eint_gpio_init = exynos_eint_gpio_init,
-               .eint_wkup_init = exynos_eint_wkup_init,
-               .suspend        = exynos_pinctrl_suspend,
-               .resume         = exynos_pinctrl_resume,
-               .label          = "exynos5250-gpio-ctrl0",
-       }, {
-               /* pin-controller instance 1 data */
-               .pin_banks      = exynos5250_pin_banks1,
-               .nr_banks       = ARRAY_SIZE(exynos5250_pin_banks1),
-               .eint_gpio_init = exynos_eint_gpio_init,
-               .suspend        = exynos_pinctrl_suspend,
-               .resume         = exynos_pinctrl_resume,
-               .label          = "exynos5250-gpio-ctrl1",
-       }, {
-               /* pin-controller instance 2 data */
-               .pin_banks      = exynos5250_pin_banks2,
-               .nr_banks       = ARRAY_SIZE(exynos5250_pin_banks2),
-               .eint_gpio_init = exynos_eint_gpio_init,
-               .suspend        = exynos_pinctrl_suspend,
-               .resume         = exynos_pinctrl_resume,
-               .label          = "exynos5250-gpio-ctrl2",
-       }, {
-               /* pin-controller instance 3 data */
-               .pin_banks      = exynos5250_pin_banks3,
-               .nr_banks       = ARRAY_SIZE(exynos5250_pin_banks3),
-               .eint_gpio_init = exynos_eint_gpio_init,
-               .suspend        = exynos_pinctrl_suspend,
-               .resume         = exynos_pinctrl_resume,
-               .label          = "exynos5250-gpio-ctrl3",
-       },
-};
-
-/* pin banks of exynos5260 pin-controller 0 */
-static struct samsung_pin_bank exynos5260_pin_banks0[] = {
-       EXYNOS_PIN_BANK_EINTG(4, 0x000, "gpa0", 0x00),
-       EXYNOS_PIN_BANK_EINTG(7, 0x020, "gpa1", 0x04),
-       EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpa2", 0x08),
-       EXYNOS_PIN_BANK_EINTG(5, 0x060, "gpb0", 0x0c),
-       EXYNOS_PIN_BANK_EINTG(4, 0x080, "gpb1", 0x10),
-       EXYNOS_PIN_BANK_EINTG(5, 0x0a0, "gpb2", 0x14),
-       EXYNOS_PIN_BANK_EINTG(8, 0x0c0, "gpb3", 0x18),
-       EXYNOS_PIN_BANK_EINTG(8, 0x0e0, "gpb4", 0x1c),
-       EXYNOS_PIN_BANK_EINTG(8, 0x100, "gpb5", 0x20),
-       EXYNOS_PIN_BANK_EINTG(8, 0x120, "gpd0", 0x24),
-       EXYNOS_PIN_BANK_EINTG(7, 0x140, "gpd1", 0x28),
-       EXYNOS_PIN_BANK_EINTG(5, 0x160, "gpd2", 0x2c),
-       EXYNOS_PIN_BANK_EINTG(8, 0x180, "gpe0", 0x30),
-       EXYNOS_PIN_BANK_EINTG(5, 0x1a0, "gpe1", 0x34),
-       EXYNOS_PIN_BANK_EINTG(4, 0x1c0, "gpf0", 0x38),
-       EXYNOS_PIN_BANK_EINTG(8, 0x1e0, "gpf1", 0x3c),
-       EXYNOS_PIN_BANK_EINTG(2, 0x200, "gpk0", 0x40),
-       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 exynos5260 pin-controller 1 */
-static struct samsung_pin_bank exynos5260_pin_banks1[] = {
-       EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpc0", 0x00),
-       EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpc1", 0x04),
-       EXYNOS_PIN_BANK_EINTG(7, 0x040, "gpc2", 0x08),
-       EXYNOS_PIN_BANK_EINTG(4, 0x060, "gpc3", 0x0c),
-       EXYNOS_PIN_BANK_EINTG(4, 0x080, "gpc4", 0x10),
-};
-
-/* pin banks of exynos5260 pin-controller 2 */
-static struct samsung_pin_bank exynos5260_pin_banks2[] = {
-       EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz0", 0x00),
-       EXYNOS_PIN_BANK_EINTG(4, 0x020, "gpz1", 0x04),
-};
-
-/*
- * Samsung pinctrl driver data for Exynos5260 SoC. Exynos5260 SoC includes
- * three gpio/pin-mux/pinconfig controllers.
- */
-struct samsung_pin_ctrl exynos5260_pin_ctrl[] = {
-       {
-               /* pin-controller instance 0 data */
-               .pin_banks      = exynos5260_pin_banks0,
-               .nr_banks       = ARRAY_SIZE(exynos5260_pin_banks0),
-               .eint_gpio_init = exynos_eint_gpio_init,
-               .eint_wkup_init = exynos_eint_wkup_init,
-               .label          = "exynos5260-gpio-ctrl0",
-       }, {
-               /* pin-controller instance 1 data */
-               .pin_banks      = exynos5260_pin_banks1,
-               .nr_banks       = ARRAY_SIZE(exynos5260_pin_banks1),
-               .eint_gpio_init = exynos_eint_gpio_init,
-               .label          = "exynos5260-gpio-ctrl1",
-       }, {
-               /* pin-controller instance 2 data */
-               .pin_banks      = exynos5260_pin_banks2,
-               .nr_banks       = ARRAY_SIZE(exynos5260_pin_banks2),
-               .eint_gpio_init = exynos_eint_gpio_init,
-               .label          = "exynos5260-gpio-ctrl2",
-       },
-};
-
-/* pin banks of exynos5420 pin-controller 0 */
-static struct samsung_pin_bank exynos5420_pin_banks0[] = {
-       EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpy7", 0x00),
-       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 exynos5420 pin-controller 1 */
-static struct samsung_pin_bank exynos5420_pin_banks1[] = {
-       EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpc0", 0x00),
-       EXYNOS_PIN_BANK_EINTG(8, 0x020, "gpc1", 0x04),
-       EXYNOS_PIN_BANK_EINTG(7, 0x040, "gpc2", 0x08),
-       EXYNOS_PIN_BANK_EINTG(4, 0x060, "gpc3", 0x0c),
-       EXYNOS_PIN_BANK_EINTG(2, 0x080, "gpc4", 0x10),
-       EXYNOS_PIN_BANK_EINTG(8, 0x0A0, "gpd1", 0x14),
-       EXYNOS_PIN_BANK_EINTN(6, 0x0C0, "gpy0"),
-       EXYNOS_PIN_BANK_EINTN(4, 0x0E0, "gpy1"),
-       EXYNOS_PIN_BANK_EINTN(6, 0x100, "gpy2"),
-       EXYNOS_PIN_BANK_EINTN(8, 0x120, "gpy3"),
-       EXYNOS_PIN_BANK_EINTN(8, 0x140, "gpy4"),
-       EXYNOS_PIN_BANK_EINTN(8, 0x160, "gpy5"),
-       EXYNOS_PIN_BANK_EINTN(8, 0x180, "gpy6"),
-};
-
-/* pin banks of exynos5420 pin-controller 2 */
-static struct samsung_pin_bank exynos5420_pin_banks2[] = {
-       EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpe0", 0x00),
-       EXYNOS_PIN_BANK_EINTG(2, 0x020, "gpe1", 0x04),
-       EXYNOS_PIN_BANK_EINTG(6, 0x040, "gpf0", 0x08),
-       EXYNOS_PIN_BANK_EINTG(8, 0x060, "gpf1", 0x0c),
-       EXYNOS_PIN_BANK_EINTG(8, 0x080, "gpg0", 0x10),
-       EXYNOS_PIN_BANK_EINTG(8, 0x0A0, "gpg1", 0x14),
-       EXYNOS_PIN_BANK_EINTG(2, 0x0C0, "gpg2", 0x18),
-       EXYNOS_PIN_BANK_EINTG(4, 0x0E0, "gpj4", 0x1c),
-};
-
-/* pin banks of exynos5420 pin-controller 3 */
-static struct samsung_pin_bank exynos5420_pin_banks3[] = {
-       EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
-       EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpa1", 0x04),
-       EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpa2", 0x08),
-       EXYNOS_PIN_BANK_EINTG(5, 0x060, "gpb0", 0x0c),
-       EXYNOS_PIN_BANK_EINTG(5, 0x080, "gpb1", 0x10),
-       EXYNOS_PIN_BANK_EINTG(4, 0x0A0, "gpb2", 0x14),
-       EXYNOS_PIN_BANK_EINTG(8, 0x0C0, "gpb3", 0x18),
-       EXYNOS_PIN_BANK_EINTG(2, 0x0E0, "gpb4", 0x1c),
-       EXYNOS_PIN_BANK_EINTG(8, 0x100, "gph0", 0x20),
-};
-
-/* pin banks of exynos5420 pin-controller 4 */
-static struct samsung_pin_bank exynos5420_pin_banks4[] = {
-       EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz", 0x00),
-};
-
-/*
- * Samsung pinctrl driver data for Exynos5420 SoC. Exynos5420 SoC includes
- * four gpio/pin-mux/pinconfig controllers.
- */
-struct samsung_pin_ctrl exynos5420_pin_ctrl[] = {
-       {
-               /* pin-controller instance 0 data */
-               .pin_banks      = exynos5420_pin_banks0,
-               .nr_banks       = ARRAY_SIZE(exynos5420_pin_banks0),
-               .eint_gpio_init = exynos_eint_gpio_init,
-               .eint_wkup_init = exynos_eint_wkup_init,
-               .label          = "exynos5420-gpio-ctrl0",
-       }, {
-               /* pin-controller instance 1 data */
-               .pin_banks      = exynos5420_pin_banks1,
-               .nr_banks       = ARRAY_SIZE(exynos5420_pin_banks1),
-               .eint_gpio_init = exynos_eint_gpio_init,
-               .label          = "exynos5420-gpio-ctrl1",
-       }, {
-               /* pin-controller instance 2 data */
-               .pin_banks      = exynos5420_pin_banks2,
-               .nr_banks       = ARRAY_SIZE(exynos5420_pin_banks2),
-               .eint_gpio_init = exynos_eint_gpio_init,
-               .label          = "exynos5420-gpio-ctrl2",
-       }, {
-               /* pin-controller instance 3 data */
-               .pin_banks      = exynos5420_pin_banks3,
-               .nr_banks       = ARRAY_SIZE(exynos5420_pin_banks3),
-               .eint_gpio_init = exynos_eint_gpio_init,
-               .label          = "exynos5420-gpio-ctrl3",
-       }, {
-               /* pin-controller instance 4 data */
-               .pin_banks      = exynos5420_pin_banks4,
-               .nr_banks       = ARRAY_SIZE(exynos5420_pin_banks4),
-               .eint_gpio_init = exynos_eint_gpio_init,
-               .label          = "exynos5420-gpio-ctrl4",
-       },
-};
diff --git a/drivers/pinctrl/pinctrl-exynos.h b/drivers/pinctrl/pinctrl-exynos.h
deleted file mode 100644 (file)
index 3c91c35..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Exynos specific definitions for Samsung pinctrl and gpiolib driver.
- *
- * Copyright (c) 2012 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com
- * Copyright (c) 2012 Linaro Ltd
- *             http://www.linaro.org
- *
- * This file contains the Exynos specific definitions for the Samsung
- * pinctrl/gpiolib interface drivers.
- *
- * Author: Thomas Abraham <thomas.ab@samsung.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; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-/* External GPIO and wakeup interrupt related definitions */
-#define EXYNOS_GPIO_ECON_OFFSET                0x700
-#define EXYNOS_GPIO_EFLTCON_OFFSET     0x800
-#define EXYNOS_GPIO_EMASK_OFFSET       0x900
-#define EXYNOS_GPIO_EPEND_OFFSET       0xA00
-#define EXYNOS_WKUP_ECON_OFFSET                0xE00
-#define EXYNOS_WKUP_EMASK_OFFSET       0xF00
-#define EXYNOS_WKUP_EPEND_OFFSET       0xF40
-#define EXYNOS_SVC_OFFSET              0xB08
-#define EXYNOS_EINT_FUNC               0xF
-
-/* helpers to access interrupt service register */
-#define EXYNOS_SVC_GROUP_SHIFT         3
-#define EXYNOS_SVC_GROUP_MASK          0x1f
-#define EXYNOS_SVC_NUM_MASK            7
-#define EXYNOS_SVC_GROUP(x)            ((x >> EXYNOS_SVC_GROUP_SHIFT) & \
-                                               EXYNOS_SVC_GROUP_MASK)
-
-/* Exynos specific external interrupt trigger types */
-#define EXYNOS_EINT_LEVEL_LOW          0
-#define EXYNOS_EINT_LEVEL_HIGH         1
-#define EXYNOS_EINT_EDGE_FALLING       2
-#define EXYNOS_EINT_EDGE_RISING                3
-#define EXYNOS_EINT_EDGE_BOTH          4
-#define EXYNOS_EINT_CON_MASK           0xF
-#define EXYNOS_EINT_CON_LEN            4
-
-#define EXYNOS_EINT_MAX_PER_BANK       8
-#define EXYNOS_EINT_NR_WKUP_EINT
-
-#define EXYNOS_PIN_BANK_EINTN(pins, reg, id)           \
-       {                                               \
-               .type           = &bank_type_off,       \
-               .pctl_offset    = reg,                  \
-               .nr_pins        = pins,                 \
-               .eint_type      = EINT_TYPE_NONE,       \
-               .name           = id                    \
-       }
-
-#define EXYNOS_PIN_BANK_EINTG(pins, reg, id, offs)     \
-       {                                               \
-               .type           = &bank_type_off,       \
-               .pctl_offset    = reg,                  \
-               .nr_pins        = pins,                 \
-               .eint_type      = EINT_TYPE_GPIO,       \
-               .eint_offset    = offs,                 \
-               .name           = id                    \
-       }
-
-#define EXYNOS_PIN_BANK_EINTW(pins, reg, id, offs)     \
-       {                                               \
-               .type           = &bank_type_alive,     \
-               .pctl_offset    = reg,                  \
-               .nr_pins        = pins,                 \
-               .eint_type      = EINT_TYPE_WKUP,       \
-               .eint_offset    = offs,                 \
-               .name           = id                    \
-       }
-
-/**
- * struct exynos_weint_data: irq specific data for all the wakeup interrupts
- * generated by the external wakeup interrupt controller.
- * @irq: interrupt number within the domain.
- * @bank: bank responsible for this interrupt
- */
-struct exynos_weint_data {
-       unsigned int irq;
-       struct samsung_pin_bank *bank;
-};
-
-/**
- * struct exynos_muxed_weint_data: irq specific data for muxed wakeup interrupts
- * generated by the external wakeup interrupt controller.
- * @nr_banks: count of banks being part of the mux
- * @banks: array of banks being part of the mux
- */
-struct exynos_muxed_weint_data {
-       unsigned int nr_banks;
-       struct samsung_pin_bank *banks[];
-};
diff --git a/drivers/pinctrl/pinctrl-exynos5440.c b/drivers/pinctrl/pinctrl-exynos5440.c
deleted file mode 100644 (file)
index 4b145b5..0000000
+++ /dev/null
@@ -1,1061 +0,0 @@
-/*
- * pin-controller/pin-mux/pin-config/gpio-driver for Samsung's EXYNOS5440 SoC.
- *
- * Copyright (c) 2012 Samsung Electronics Co., Ltd.
- *             http://www.samsung.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; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/err.h>
-#include <linux/gpio.h>
-#include <linux/device.h>
-#include <linux/pinctrl/pinctrl.h>
-#include <linux/pinctrl/pinmux.h>
-#include <linux/pinctrl/pinconf.h>
-#include <linux/interrupt.h>
-#include <linux/irqdomain.h>
-#include <linux/of_irq.h>
-#include "core.h"
-
-/* EXYNOS5440 GPIO and Pinctrl register offsets */
-#define GPIO_MUX               0x00
-#define GPIO_IE                        0x04
-#define GPIO_INT               0x08
-#define GPIO_TYPE              0x0C
-#define GPIO_VAL               0x10
-#define GPIO_OE                        0x14
-#define GPIO_IN                        0x18
-#define GPIO_PE                        0x1C
-#define GPIO_PS                        0x20
-#define GPIO_SR                        0x24
-#define GPIO_DS0               0x28
-#define GPIO_DS1               0x2C
-
-#define EXYNOS5440_MAX_PINS            23
-#define EXYNOS5440_MAX_GPIO_INT        8
-#define PIN_NAME_LENGTH                10
-
-#define GROUP_SUFFIX           "-grp"
-#define GSUFFIX_LEN            sizeof(GROUP_SUFFIX)
-#define FUNCTION_SUFFIX                "-mux"
-#define FSUFFIX_LEN            sizeof(FUNCTION_SUFFIX)
-
-/*
- * pin configuration type and its value are packed together into a 16-bits.
- * The upper 8-bits represent the configuration type and the lower 8-bits
- * hold the value of the configuration type.
- */
-#define PINCFG_TYPE_MASK               0xFF
-#define PINCFG_VALUE_SHIFT             8
-#define PINCFG_VALUE_MASK              (0xFF << PINCFG_VALUE_SHIFT)
-#define PINCFG_PACK(type, value)       (((value) << PINCFG_VALUE_SHIFT) | type)
-#define PINCFG_UNPACK_TYPE(cfg)                ((cfg) & PINCFG_TYPE_MASK)
-#define PINCFG_UNPACK_VALUE(cfg)       (((cfg) & PINCFG_VALUE_MASK) >> \
-                                               PINCFG_VALUE_SHIFT)
-
-/**
- * enum pincfg_type - possible pin configuration types supported.
- * @PINCFG_TYPE_PUD: Pull up/down configuration.
- * @PINCFG_TYPE_DRV: Drive strength configuration.
- * @PINCFG_TYPE_SKEW_RATE: Skew rate configuration.
- * @PINCFG_TYPE_INPUT_TYPE: Pin input type configuration.
- */
-enum pincfg_type {
-       PINCFG_TYPE_PUD,
-       PINCFG_TYPE_DRV,
-       PINCFG_TYPE_SKEW_RATE,
-       PINCFG_TYPE_INPUT_TYPE
-};
-
-/**
- * struct exynos5440_pin_group: represent group of pins for pincfg setting.
- * @name: name of the pin group, used to lookup the group.
- * @pins: the pins included in this group.
- * @num_pins: number of pins included in this group.
- */
-struct exynos5440_pin_group {
-       const char              *name;
-       const unsigned int      *pins;
-       u8                      num_pins;
-};
-
-/**
- * struct exynos5440_pmx_func: represent a pin function.
- * @name: name of the pin function, used to lookup the function.
- * @groups: one or more names of pin groups that provide this function.
- * @num_groups: number of groups included in @groups.
- * @function: the function number to be programmed when selected.
- */
-struct exynos5440_pmx_func {
-       const char              *name;
-       const char              **groups;
-       u8                      num_groups;
-       unsigned long           function;
-};
-
-/**
- * struct exynos5440_pinctrl_priv_data: driver's private runtime data.
- * @reg_base: ioremapped based address of the register space.
- * @gc: gpio chip registered with gpiolib.
- * @pin_groups: list of pin groups parsed from device tree.
- * @nr_groups: number of pin groups available.
- * @pmx_functions: list of pin functions parsed from device tree.
- * @nr_functions: number of pin functions available.
- */
-struct exynos5440_pinctrl_priv_data {
-       void __iomem                    *reg_base;
-       struct gpio_chip                *gc;
-       struct irq_domain               *irq_domain;
-
-       const struct exynos5440_pin_group       *pin_groups;
-       unsigned int                    nr_groups;
-       const struct exynos5440_pmx_func        *pmx_functions;
-       unsigned int                    nr_functions;
-};
-
-/**
- * struct exynos5440_gpio_intr_data: private data for gpio interrupts.
- * @priv: driver's private runtime data.
- * @gpio_int: gpio interrupt number.
- */
-struct exynos5440_gpio_intr_data {
-       struct exynos5440_pinctrl_priv_data     *priv;
-       unsigned int                            gpio_int;
-};
-
-/* list of all possible config options supported */
-static struct pin_config {
-       char            *prop_cfg;
-       unsigned int    cfg_type;
-} pcfgs[] = {
-       { "samsung,exynos5440-pin-pud", PINCFG_TYPE_PUD },
-       { "samsung,exynos5440-pin-drv", PINCFG_TYPE_DRV },
-       { "samsung,exynos5440-pin-skew-rate", PINCFG_TYPE_SKEW_RATE },
-       { "samsung,exynos5440-pin-input-type", PINCFG_TYPE_INPUT_TYPE },
-};
-
-/* check if the selector is a valid pin group selector */
-static int exynos5440_get_group_count(struct pinctrl_dev *pctldev)
-{
-       struct exynos5440_pinctrl_priv_data *priv;
-
-       priv = pinctrl_dev_get_drvdata(pctldev);
-       return priv->nr_groups;
-}
-
-/* return the name of the group selected by the group selector */
-static const char *exynos5440_get_group_name(struct pinctrl_dev *pctldev,
-                                               unsigned selector)
-{
-       struct exynos5440_pinctrl_priv_data *priv;
-
-       priv = pinctrl_dev_get_drvdata(pctldev);
-       return priv->pin_groups[selector].name;
-}
-
-/* return the pin numbers associated with the specified group */
-static int exynos5440_get_group_pins(struct pinctrl_dev *pctldev,
-               unsigned selector, const unsigned **pins, unsigned *num_pins)
-{
-       struct exynos5440_pinctrl_priv_data *priv;
-
-       priv = pinctrl_dev_get_drvdata(pctldev);
-       *pins = priv->pin_groups[selector].pins;
-       *num_pins = priv->pin_groups[selector].num_pins;
-       return 0;
-}
-
-/* create pinctrl_map entries by parsing device tree nodes */
-static int exynos5440_dt_node_to_map(struct pinctrl_dev *pctldev,
-                       struct device_node *np, struct pinctrl_map **maps,
-                       unsigned *nmaps)
-{
-       struct device *dev = pctldev->dev;
-       struct pinctrl_map *map;
-       unsigned long *cfg = NULL;
-       char *gname, *fname;
-       int cfg_cnt = 0, map_cnt = 0, idx = 0;
-
-       /* count the number of config options specfied in the node */
-       for (idx = 0; idx < ARRAY_SIZE(pcfgs); idx++)
-               if (of_find_property(np, pcfgs[idx].prop_cfg, NULL))
-                       cfg_cnt++;
-
-       /*
-        * Find out the number of map entries to create. All the config options
-        * can be accomadated into a single config map entry.
-        */
-       if (cfg_cnt)
-               map_cnt = 1;
-       if (of_find_property(np, "samsung,exynos5440-pin-function", NULL))
-               map_cnt++;
-       if (!map_cnt) {
-               dev_err(dev, "node %s does not have either config or function "
-                               "configurations\n", np->name);
-               return -EINVAL;
-       }
-
-       /* Allocate memory for pin-map entries */
-       map = kzalloc(sizeof(*map) * map_cnt, GFP_KERNEL);
-       if (!map) {
-               dev_err(dev, "could not alloc memory for pin-maps\n");
-               return -ENOMEM;
-       }
-       *nmaps = 0;
-
-       /*
-        * Allocate memory for pin group name. The pin group name is derived
-        * from the node name from which these map entries are be created.
-        */
-       gname = kzalloc(strlen(np->name) + GSUFFIX_LEN, GFP_KERNEL);
-       if (!gname) {
-               dev_err(dev, "failed to alloc memory for group name\n");
-               goto free_map;
-       }
-       snprintf(gname, strlen(np->name) + 4, "%s%s", np->name, GROUP_SUFFIX);
-
-       /*
-        * don't have config options? then skip over to creating function
-        * map entries.
-        */
-       if (!cfg_cnt)
-               goto skip_cfgs;
-
-       /* Allocate memory for config entries */
-       cfg = kzalloc(sizeof(*cfg) * cfg_cnt, GFP_KERNEL);
-       if (!cfg) {
-               dev_err(dev, "failed to alloc memory for configs\n");
-               goto free_gname;
-       }
-
-       /* Prepare a list of config settings */
-       for (idx = 0, cfg_cnt = 0; idx < ARRAY_SIZE(pcfgs); idx++) {
-               u32 value;
-               if (!of_property_read_u32(np, pcfgs[idx].prop_cfg, &value))
-                       cfg[cfg_cnt++] =
-                               PINCFG_PACK(pcfgs[idx].cfg_type, value);
-       }
-
-       /* create the config map entry */
-       map[*nmaps].data.configs.group_or_pin = gname;
-       map[*nmaps].data.configs.configs = cfg;
-       map[*nmaps].data.configs.num_configs = cfg_cnt;
-       map[*nmaps].type = PIN_MAP_TYPE_CONFIGS_GROUP;
-       *nmaps += 1;
-
-skip_cfgs:
-       /* create the function map entry */
-       if (of_find_property(np, "samsung,exynos5440-pin-function", NULL)) {
-               fname = kzalloc(strlen(np->name) + FSUFFIX_LEN, GFP_KERNEL);
-               if (!fname) {
-                       dev_err(dev, "failed to alloc memory for func name\n");
-                       goto free_cfg;
-               }
-               snprintf(fname, strlen(np->name) + 4, "%s%s", np->name,
-                        FUNCTION_SUFFIX);
-
-               map[*nmaps].data.mux.group = gname;
-               map[*nmaps].data.mux.function = fname;
-               map[*nmaps].type = PIN_MAP_TYPE_MUX_GROUP;
-               *nmaps += 1;
-       }
-
-       *maps = map;
-       return 0;
-
-free_cfg:
-       kfree(cfg);
-free_gname:
-       kfree(gname);
-free_map:
-       kfree(map);
-       return -ENOMEM;
-}
-
-/* free the memory allocated to hold the pin-map table */
-static void exynos5440_dt_free_map(struct pinctrl_dev *pctldev,
-                            struct pinctrl_map *map, unsigned num_maps)
-{
-       int idx;
-
-       for (idx = 0; idx < num_maps; idx++) {
-               if (map[idx].type == PIN_MAP_TYPE_MUX_GROUP) {
-                       kfree(map[idx].data.mux.function);
-                       if (!idx)
-                               kfree(map[idx].data.mux.group);
-               } else if (map->type == PIN_MAP_TYPE_CONFIGS_GROUP) {
-                       kfree(map[idx].data.configs.configs);
-                       if (!idx)
-                               kfree(map[idx].data.configs.group_or_pin);
-               }
-       };
-
-       kfree(map);
-}
-
-/* list of pinctrl callbacks for the pinctrl core */
-static const struct pinctrl_ops exynos5440_pctrl_ops = {
-       .get_groups_count       = exynos5440_get_group_count,
-       .get_group_name         = exynos5440_get_group_name,
-       .get_group_pins         = exynos5440_get_group_pins,
-       .dt_node_to_map         = exynos5440_dt_node_to_map,
-       .dt_free_map            = exynos5440_dt_free_map,
-};
-
-/* check if the selector is a valid pin function selector */
-static int exynos5440_get_functions_count(struct pinctrl_dev *pctldev)
-{
-       struct exynos5440_pinctrl_priv_data *priv;
-
-       priv = pinctrl_dev_get_drvdata(pctldev);
-       return priv->nr_functions;
-}
-
-/* return the name of the pin function specified */
-static const char *exynos5440_pinmux_get_fname(struct pinctrl_dev *pctldev,
-                                               unsigned selector)
-{
-       struct exynos5440_pinctrl_priv_data *priv;
-
-       priv = pinctrl_dev_get_drvdata(pctldev);
-       return priv->pmx_functions[selector].name;
-}
-
-/* return the groups associated for the specified function selector */
-static int exynos5440_pinmux_get_groups(struct pinctrl_dev *pctldev,
-               unsigned selector, const char * const **groups,
-               unsigned * const num_groups)
-{
-       struct exynos5440_pinctrl_priv_data *priv;
-
-       priv = pinctrl_dev_get_drvdata(pctldev);
-       *groups = priv->pmx_functions[selector].groups;
-       *num_groups = priv->pmx_functions[selector].num_groups;
-       return 0;
-}
-
-/* enable or disable a pinmux function */
-static void exynos5440_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector,
-                                       unsigned group, bool enable)
-{
-       struct exynos5440_pinctrl_priv_data *priv;
-       void __iomem *base;
-       u32 function;
-       u32 data;
-
-       priv = pinctrl_dev_get_drvdata(pctldev);
-       base = priv->reg_base;
-       function = priv->pmx_functions[selector].function;
-
-       data = readl(base + GPIO_MUX);
-       if (enable)
-               data |= (1 << function);
-       else
-               data &= ~(1 << function);
-       writel(data, base + GPIO_MUX);
-}
-
-/* enable a specified pinmux by writing to registers */
-static int exynos5440_pinmux_enable(struct pinctrl_dev *pctldev, unsigned selector,
-                                       unsigned group)
-{
-       exynos5440_pinmux_setup(pctldev, selector, group, true);
-       return 0;
-}
-
-/*
- * The calls to gpio_direction_output() and gpio_direction_input()
- * leads to this function call (via the pinctrl_gpio_direction_{input|output}()
- * function called from the gpiolib interface).
- */
-static int exynos5440_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev,
-               struct pinctrl_gpio_range *range, unsigned offset, bool input)
-{
-       return 0;
-}
-
-/* list of pinmux callbacks for the pinmux vertical in pinctrl core */
-static const struct pinmux_ops exynos5440_pinmux_ops = {
-       .get_functions_count    = exynos5440_get_functions_count,
-       .get_function_name      = exynos5440_pinmux_get_fname,
-       .get_function_groups    = exynos5440_pinmux_get_groups,
-       .enable                 = exynos5440_pinmux_enable,
-       .gpio_set_direction     = exynos5440_pinmux_gpio_set_direction,
-};
-
-/* set the pin config settings for a specified pin */
-static int exynos5440_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
-                               unsigned long *configs,
-                               unsigned num_configs)
-{
-       struct exynos5440_pinctrl_priv_data *priv;
-       void __iomem *base;
-       enum pincfg_type cfg_type;
-       u32 cfg_value;
-       u32 data;
-       int i;
-
-       priv = pinctrl_dev_get_drvdata(pctldev);
-       base = priv->reg_base;
-
-       for (i = 0; i < num_configs; i++) {
-               cfg_type = PINCFG_UNPACK_TYPE(configs[i]);
-               cfg_value = PINCFG_UNPACK_VALUE(configs[i]);
-
-               switch (cfg_type) {
-               case PINCFG_TYPE_PUD:
-                       /* first set pull enable/disable bit */
-                       data = readl(base + GPIO_PE);
-                       data &= ~(1 << pin);
-                       if (cfg_value)
-                               data |= (1 << pin);
-                       writel(data, base + GPIO_PE);
-
-                       /* then set pull up/down bit */
-                       data = readl(base + GPIO_PS);
-                       data &= ~(1 << pin);
-                       if (cfg_value == 2)
-                               data |= (1 << pin);
-                       writel(data, base + GPIO_PS);
-                       break;
-
-               case PINCFG_TYPE_DRV:
-                       /* set the first bit of the drive strength */
-                       data = readl(base + GPIO_DS0);
-                       data &= ~(1 << pin);
-                       data |= ((cfg_value & 1) << pin);
-                       writel(data, base + GPIO_DS0);
-                       cfg_value >>= 1;
-
-                       /* set the second bit of the driver strength */
-                       data = readl(base + GPIO_DS1);
-                       data &= ~(1 << pin);
-                       data |= ((cfg_value & 1) << pin);
-                       writel(data, base + GPIO_DS1);
-                       break;
-               case PINCFG_TYPE_SKEW_RATE:
-                       data = readl(base + GPIO_SR);
-                       data &= ~(1 << pin);
-                       data |= ((cfg_value & 1) << pin);
-                       writel(data, base + GPIO_SR);
-                       break;
-               case PINCFG_TYPE_INPUT_TYPE:
-                       data = readl(base + GPIO_TYPE);
-                       data &= ~(1 << pin);
-                       data |= ((cfg_value & 1) << pin);
-                       writel(data, base + GPIO_TYPE);
-                       break;
-               default:
-                       WARN_ON(1);
-                       return -EINVAL;
-               }
-       } /* for each config */
-
-       return 0;
-}
-
-/* get the pin config settings for a specified pin */
-static int exynos5440_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin,
-                                       unsigned long *config)
-{
-       struct exynos5440_pinctrl_priv_data *priv;
-       void __iomem *base;
-       enum pincfg_type cfg_type = PINCFG_UNPACK_TYPE(*config);
-       u32 data;
-
-       priv = pinctrl_dev_get_drvdata(pctldev);
-       base = priv->reg_base;
-
-       switch (cfg_type) {
-       case PINCFG_TYPE_PUD:
-               data = readl(base + GPIO_PE);
-               data = (data >> pin) & 1;
-               if (!data)
-                       *config = 0;
-               else
-                       *config = ((readl(base + GPIO_PS) >> pin) & 1) + 1;
-               break;
-       case PINCFG_TYPE_DRV:
-               data = readl(base + GPIO_DS0);
-               data = (data >> pin) & 1;
-               *config = data;
-               data = readl(base + GPIO_DS1);
-               data = (data >> pin) & 1;
-               *config |= (data << 1);
-               break;
-       case PINCFG_TYPE_SKEW_RATE:
-               data = readl(base + GPIO_SR);
-               *config = (data >> pin) & 1;
-               break;
-       case PINCFG_TYPE_INPUT_TYPE:
-               data = readl(base + GPIO_TYPE);
-               *config = (data >> pin) & 1;
-               break;
-       default:
-               WARN_ON(1);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-/* set the pin config settings for a specified pin group */
-static int exynos5440_pinconf_group_set(struct pinctrl_dev *pctldev,
-                       unsigned group, unsigned long *configs,
-                       unsigned num_configs)
-{
-       struct exynos5440_pinctrl_priv_data *priv;
-       const unsigned int *pins;
-       unsigned int cnt;
-
-       priv = pinctrl_dev_get_drvdata(pctldev);
-       pins = priv->pin_groups[group].pins;
-
-       for (cnt = 0; cnt < priv->pin_groups[group].num_pins; cnt++)
-               exynos5440_pinconf_set(pctldev, pins[cnt], configs,
-                                      num_configs);
-
-       return 0;
-}
-
-/* get the pin config settings for a specified pin group */
-static int exynos5440_pinconf_group_get(struct pinctrl_dev *pctldev,
-                               unsigned int group, unsigned long *config)
-{
-       struct exynos5440_pinctrl_priv_data *priv;
-       const unsigned int *pins;
-
-       priv = pinctrl_dev_get_drvdata(pctldev);
-       pins = priv->pin_groups[group].pins;
-       exynos5440_pinconf_get(pctldev, pins[0], config);
-       return 0;
-}
-
-/* list of pinconfig callbacks for pinconfig vertical in the pinctrl code */
-static const struct pinconf_ops exynos5440_pinconf_ops = {
-       .pin_config_get         = exynos5440_pinconf_get,
-       .pin_config_set         = exynos5440_pinconf_set,
-       .pin_config_group_get   = exynos5440_pinconf_group_get,
-       .pin_config_group_set   = exynos5440_pinconf_group_set,
-};
-
-/* gpiolib gpio_set callback function */
-static void exynos5440_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
-{
-       struct exynos5440_pinctrl_priv_data *priv = dev_get_drvdata(gc->dev);
-       void __iomem *base = priv->reg_base;
-       u32 data;
-
-       data = readl(base + GPIO_VAL);
-       data &= ~(1 << offset);
-       if (value)
-               data |= 1 << offset;
-       writel(data, base + GPIO_VAL);
-}
-
-/* gpiolib gpio_get callback function */
-static int exynos5440_gpio_get(struct gpio_chip *gc, unsigned offset)
-{
-       struct exynos5440_pinctrl_priv_data *priv = dev_get_drvdata(gc->dev);
-       void __iomem *base = priv->reg_base;
-       u32 data;
-
-       data = readl(base + GPIO_IN);
-       data >>= offset;
-       data &= 1;
-       return data;
-}
-
-/* gpiolib gpio_direction_input callback function */
-static int exynos5440_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
-{
-       struct exynos5440_pinctrl_priv_data *priv = dev_get_drvdata(gc->dev);
-       void __iomem *base = priv->reg_base;
-       u32 data;
-
-       /* first disable the data output enable on this pin */
-       data = readl(base + GPIO_OE);
-       data &= ~(1 << offset);
-       writel(data, base + GPIO_OE);
-
-       /* now enable input on this pin */
-       data =  readl(base + GPIO_IE);
-       data |= 1 << offset;
-       writel(data, base + GPIO_IE);
-       return 0;
-}
-
-/* gpiolib gpio_direction_output callback function */
-static int exynos5440_gpio_direction_output(struct gpio_chip *gc, unsigned offset,
-                                                       int value)
-{
-       struct exynos5440_pinctrl_priv_data *priv = dev_get_drvdata(gc->dev);
-       void __iomem *base = priv->reg_base;
-       u32 data;
-
-       exynos5440_gpio_set(gc, offset, value);
-
-       /* first disable the data input enable on this pin */
-       data = readl(base + GPIO_IE);
-       data &= ~(1 << offset);
-       writel(data, base + GPIO_IE);
-
-       /* now enable output on this pin */
-       data =  readl(base + GPIO_OE);
-       data |= 1 << offset;
-       writel(data, base + GPIO_OE);
-       return 0;
-}
-
-/* gpiolib gpio_to_irq callback function */
-static int exynos5440_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
-{
-       struct exynos5440_pinctrl_priv_data *priv = dev_get_drvdata(gc->dev);
-       unsigned int virq;
-
-       if (offset < 16 || offset > 23)
-               return -ENXIO;
-
-       if (!priv->irq_domain)
-               return -ENXIO;
-
-       virq = irq_create_mapping(priv->irq_domain, offset - 16);
-       return virq ? : -ENXIO;
-}
-
-/* parse the pin numbers listed in the 'samsung,exynos5440-pins' property */
-static int exynos5440_pinctrl_parse_dt_pins(struct platform_device *pdev,
-                       struct device_node *cfg_np, unsigned int **pin_list,
-                       unsigned int *npins)
-{
-       struct device *dev = &pdev->dev;
-       struct property *prop;
-
-       prop = of_find_property(cfg_np, "samsung,exynos5440-pins", NULL);
-       if (!prop)
-               return -ENOENT;
-
-       *npins = prop->length / sizeof(unsigned long);
-       if (!*npins) {
-               dev_err(dev, "invalid pin list in %s node", cfg_np->name);
-               return -EINVAL;
-       }
-
-       *pin_list = devm_kzalloc(dev, *npins * sizeof(**pin_list), GFP_KERNEL);
-       if (!*pin_list) {
-               dev_err(dev, "failed to allocate memory for pin list\n");
-               return -ENOMEM;
-       }
-
-       return of_property_read_u32_array(cfg_np, "samsung,exynos5440-pins",
-                       *pin_list, *npins);
-}
-
-/*
- * Parse the information about all the available pin groups and pin functions
- * from device node of the pin-controller.
- */
-static int exynos5440_pinctrl_parse_dt(struct platform_device *pdev,
-                               struct exynos5440_pinctrl_priv_data *priv)
-{
-       struct device *dev = &pdev->dev;
-       struct device_node *dev_np = dev->of_node;
-       struct device_node *cfg_np;
-       struct exynos5440_pin_group *groups, *grp;
-       struct exynos5440_pmx_func *functions, *func;
-       unsigned *pin_list;
-       unsigned int npins, grp_cnt, func_idx = 0;
-       char *gname, *fname;
-       int ret;
-
-       grp_cnt = of_get_child_count(dev_np);
-       if (!grp_cnt)
-               return -EINVAL;
-
-       groups = devm_kzalloc(dev, grp_cnt * sizeof(*groups), GFP_KERNEL);
-       if (!groups) {
-               dev_err(dev, "failed allocate memory for ping group list\n");
-               return -EINVAL;
-       }
-       grp = groups;
-
-       functions = devm_kzalloc(dev, grp_cnt * sizeof(*functions), GFP_KERNEL);
-       if (!functions) {
-               dev_err(dev, "failed to allocate memory for function list\n");
-               return -EINVAL;
-       }
-       func = functions;
-
-       /*
-        * Iterate over all the child nodes of the pin controller node
-        * and create pin groups and pin function lists.
-        */
-       for_each_child_of_node(dev_np, cfg_np) {
-               u32 function;
-
-               ret = exynos5440_pinctrl_parse_dt_pins(pdev, cfg_np,
-                                       &pin_list, &npins);
-               if (ret) {
-                       gname = NULL;
-                       goto skip_to_pin_function;
-               }
-
-               /* derive pin group name from the node name */
-               gname = devm_kzalloc(dev, strlen(cfg_np->name) + GSUFFIX_LEN,
-                                       GFP_KERNEL);
-               if (!gname) {
-                       dev_err(dev, "failed to alloc memory for group name\n");
-                       return -ENOMEM;
-               }
-               snprintf(gname, strlen(cfg_np->name) + 4, "%s%s", cfg_np->name,
-                        GROUP_SUFFIX);
-
-               grp->name = gname;
-               grp->pins = pin_list;
-               grp->num_pins = npins;
-               grp++;
-
-skip_to_pin_function:
-               ret = of_property_read_u32(cfg_np, "samsung,exynos5440-pin-function",
-                                               &function);
-               if (ret)
-                       continue;
-
-               /* derive function name from the node name */
-               fname = devm_kzalloc(dev, strlen(cfg_np->name) + FSUFFIX_LEN,
-                                       GFP_KERNEL);
-               if (!fname) {
-                       dev_err(dev, "failed to alloc memory for func name\n");
-                       return -ENOMEM;
-               }
-               snprintf(fname, strlen(cfg_np->name) + 4, "%s%s", cfg_np->name,
-                        FUNCTION_SUFFIX);
-
-               func->name = fname;
-               func->groups = devm_kzalloc(dev, sizeof(char *), GFP_KERNEL);
-               if (!func->groups) {
-                       dev_err(dev, "failed to alloc memory for group list "
-                                       "in pin function");
-                       return -ENOMEM;
-               }
-               func->groups[0] = gname;
-               func->num_groups = gname ? 1 : 0;
-               func->function = function;
-               func++;
-               func_idx++;
-       }
-
-       priv->pin_groups = groups;
-       priv->nr_groups = grp_cnt;
-       priv->pmx_functions = functions;
-       priv->nr_functions = func_idx;
-       return 0;
-}
-
-/* register the pinctrl interface with the pinctrl subsystem */
-static int exynos5440_pinctrl_register(struct platform_device *pdev,
-                               struct exynos5440_pinctrl_priv_data *priv)
-{
-       struct device *dev = &pdev->dev;
-       struct pinctrl_desc *ctrldesc;
-       struct pinctrl_dev *pctl_dev;
-       struct pinctrl_pin_desc *pindesc, *pdesc;
-       struct pinctrl_gpio_range grange;
-       char *pin_names;
-       int pin, ret;
-
-       ctrldesc = devm_kzalloc(dev, sizeof(*ctrldesc), GFP_KERNEL);
-       if (!ctrldesc) {
-               dev_err(dev, "could not allocate memory for pinctrl desc\n");
-               return -ENOMEM;
-       }
-
-       ctrldesc->name = "exynos5440-pinctrl";
-       ctrldesc->owner = THIS_MODULE;
-       ctrldesc->pctlops = &exynos5440_pctrl_ops;
-       ctrldesc->pmxops = &exynos5440_pinmux_ops;
-       ctrldesc->confops = &exynos5440_pinconf_ops;
-
-       pindesc = devm_kzalloc(&pdev->dev, sizeof(*pindesc) *
-                               EXYNOS5440_MAX_PINS, GFP_KERNEL);
-       if (!pindesc) {
-               dev_err(&pdev->dev, "mem alloc for pin descriptors failed\n");
-               return -ENOMEM;
-       }
-       ctrldesc->pins = pindesc;
-       ctrldesc->npins = EXYNOS5440_MAX_PINS;
-
-       /* dynamically populate the pin number and pin name for pindesc */
-       for (pin = 0, pdesc = pindesc; pin < ctrldesc->npins; pin++, pdesc++)
-               pdesc->number = pin;
-
-       /*
-        * allocate space for storing the dynamically generated names for all
-        * the pins which belong to this pin-controller.
-        */
-       pin_names = devm_kzalloc(&pdev->dev, sizeof(char) * PIN_NAME_LENGTH *
-                                       ctrldesc->npins, GFP_KERNEL);
-       if (!pin_names) {
-               dev_err(&pdev->dev, "mem alloc for pin names failed\n");
-               return -ENOMEM;
-       }
-
-       /* for each pin, set the name of the pin */
-       for (pin = 0; pin < ctrldesc->npins; pin++) {
-               snprintf(pin_names, 6, "gpio%02d", pin);
-               pdesc = pindesc + pin;
-               pdesc->name = pin_names;
-               pin_names += PIN_NAME_LENGTH;
-       }
-
-       ret = exynos5440_pinctrl_parse_dt(pdev, priv);
-       if (ret)
-               return ret;
-
-       pctl_dev = pinctrl_register(ctrldesc, &pdev->dev, priv);
-       if (!pctl_dev) {
-               dev_err(&pdev->dev, "could not register pinctrl driver\n");
-               return -EINVAL;
-       }
-
-       grange.name = "exynos5440-pctrl-gpio-range";
-       grange.id = 0;
-       grange.base = 0;
-       grange.npins = EXYNOS5440_MAX_PINS;
-       grange.gc = priv->gc;
-       pinctrl_add_gpio_range(pctl_dev, &grange);
-       return 0;
-}
-
-/* register the gpiolib interface with the gpiolib subsystem */
-static int exynos5440_gpiolib_register(struct platform_device *pdev,
-                               struct exynos5440_pinctrl_priv_data *priv)
-{
-       struct gpio_chip *gc;
-       int ret;
-
-       gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL);
-       if (!gc) {
-               dev_err(&pdev->dev, "mem alloc for gpio_chip failed\n");
-               return -ENOMEM;
-       }
-
-       priv->gc = gc;
-       gc->base = 0;
-       gc->ngpio = EXYNOS5440_MAX_PINS;
-       gc->dev = &pdev->dev;
-       gc->set = exynos5440_gpio_set;
-       gc->get = exynos5440_gpio_get;
-       gc->direction_input = exynos5440_gpio_direction_input;
-       gc->direction_output = exynos5440_gpio_direction_output;
-       gc->to_irq = exynos5440_gpio_to_irq;
-       gc->label = "gpiolib-exynos5440";
-       gc->owner = THIS_MODULE;
-       ret = gpiochip_add(gc);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to register gpio_chip %s, error "
-                                       "code: %d\n", gc->label, ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-/* unregister the gpiolib interface with the gpiolib subsystem */
-static int exynos5440_gpiolib_unregister(struct platform_device *pdev,
-                               struct exynos5440_pinctrl_priv_data *priv)
-{
-       int ret = gpiochip_remove(priv->gc);
-       if (ret) {
-               dev_err(&pdev->dev, "gpio chip remove failed\n");
-               return ret;
-       }
-       return 0;
-}
-
-static void exynos5440_gpio_irq_unmask(struct irq_data *irqd)
-{
-       struct exynos5440_pinctrl_priv_data *d;
-       unsigned long gpio_int;
-
-       d = irq_data_get_irq_chip_data(irqd);
-       gpio_int = readl(d->reg_base + GPIO_INT);
-       gpio_int |= 1 << irqd->hwirq;
-       writel(gpio_int, d->reg_base + GPIO_INT);
-}
-
-static void exynos5440_gpio_irq_mask(struct irq_data *irqd)
-{
-       struct exynos5440_pinctrl_priv_data *d;
-       unsigned long gpio_int;
-
-       d = irq_data_get_irq_chip_data(irqd);
-       gpio_int = readl(d->reg_base + GPIO_INT);
-       gpio_int &= ~(1 << irqd->hwirq);
-       writel(gpio_int, d->reg_base + GPIO_INT);
-}
-
-/* irq_chip for gpio interrupts */
-static struct irq_chip exynos5440_gpio_irq_chip = {
-       .name           = "exynos5440_gpio_irq_chip",
-       .irq_unmask     = exynos5440_gpio_irq_unmask,
-       .irq_mask       = exynos5440_gpio_irq_mask,
-};
-
-/* interrupt handler for GPIO interrupts 0..7 */
-static irqreturn_t exynos5440_gpio_irq(int irq, void *data)
-{
-       struct exynos5440_gpio_intr_data *intd = data;
-       struct exynos5440_pinctrl_priv_data *d = intd->priv;
-       int virq;
-
-       virq = irq_linear_revmap(d->irq_domain, intd->gpio_int);
-       if (!virq)
-               return IRQ_NONE;
-       generic_handle_irq(virq);
-       return IRQ_HANDLED;
-}
-
-static int exynos5440_gpio_irq_map(struct irq_domain *h, unsigned int virq,
-                                       irq_hw_number_t hw)
-{
-       struct exynos5440_pinctrl_priv_data *d = h->host_data;
-
-       irq_set_chip_data(virq, d);
-       irq_set_chip_and_handler(virq, &exynos5440_gpio_irq_chip,
-                                       handle_level_irq);
-       set_irq_flags(virq, IRQF_VALID);
-       return 0;
-}
-
-/* irq domain callbacks for gpio interrupt controller */
-static const struct irq_domain_ops exynos5440_gpio_irqd_ops = {
-       .map    = exynos5440_gpio_irq_map,
-       .xlate  = irq_domain_xlate_twocell,
-};
-
-/* setup handling of gpio interrupts */
-static int exynos5440_gpio_irq_init(struct platform_device *pdev,
-                               struct exynos5440_pinctrl_priv_data *priv)
-{
-       struct device *dev = &pdev->dev;
-       struct exynos5440_gpio_intr_data *intd;
-       int i, irq, ret;
-
-       intd = devm_kzalloc(dev, sizeof(*intd) * EXYNOS5440_MAX_GPIO_INT,
-                                       GFP_KERNEL);
-       if (!intd) {
-               dev_err(dev, "failed to allocate memory for gpio intr data\n");
-               return -ENOMEM;
-       }
-
-       for (i = 0; i < EXYNOS5440_MAX_GPIO_INT; i++) {
-               irq = irq_of_parse_and_map(dev->of_node, i);
-               if (irq <= 0) {
-                       dev_err(dev, "irq parsing failed\n");
-                       return -EINVAL;
-               }
-
-               intd->gpio_int = i;
-               intd->priv = priv;
-               ret = devm_request_irq(dev, irq, exynos5440_gpio_irq,
-                                       0, dev_name(dev), intd++);
-               if (ret) {
-                       dev_err(dev, "irq request failed\n");
-                       return -ENXIO;
-               }
-       }
-
-       priv->irq_domain = irq_domain_add_linear(dev->of_node,
-                               EXYNOS5440_MAX_GPIO_INT,
-                               &exynos5440_gpio_irqd_ops, priv);
-       if (!priv->irq_domain) {
-               dev_err(dev, "failed to create irq domain\n");
-               return -ENXIO;
-       }
-
-       return 0;
-}
-
-static int exynos5440_pinctrl_probe(struct platform_device *pdev)
-{
-       struct device *dev = &pdev->dev;
-       struct exynos5440_pinctrl_priv_data *priv;
-       struct resource *res;
-       int ret;
-
-       if (!dev->of_node) {
-               dev_err(dev, "device tree node not found\n");
-               return -ENODEV;
-       }
-
-       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-       if (!priv) {
-               dev_err(dev, "could not allocate memory for private data\n");
-               return -ENOMEM;
-       }
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       priv->reg_base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(priv->reg_base))
-               return PTR_ERR(priv->reg_base);
-
-       ret = exynos5440_gpiolib_register(pdev, priv);
-       if (ret)
-               return ret;
-
-       ret = exynos5440_pinctrl_register(pdev, priv);
-       if (ret) {
-               exynos5440_gpiolib_unregister(pdev, priv);
-               return ret;
-       }
-
-       ret = exynos5440_gpio_irq_init(pdev, priv);
-       if (ret) {
-               dev_err(dev, "failed to setup gpio interrupts\n");
-               return ret;
-       }
-
-       platform_set_drvdata(pdev, priv);
-       dev_info(dev, "EXYNOS5440 pinctrl driver registered\n");
-       return 0;
-}
-
-static const struct of_device_id exynos5440_pinctrl_dt_match[] = {
-       { .compatible = "samsung,exynos5440-pinctrl" },
-       {},
-};
-MODULE_DEVICE_TABLE(of, exynos5440_pinctrl_dt_match);
-
-static struct platform_driver exynos5440_pinctrl_driver = {
-       .probe          = exynos5440_pinctrl_probe,
-       .driver = {
-               .name   = "exynos5440-pinctrl",
-               .owner  = THIS_MODULE,
-               .of_match_table = exynos5440_pinctrl_dt_match,
-       },
-};
-
-static int __init exynos5440_pinctrl_drv_register(void)
-{
-       return platform_driver_register(&exynos5440_pinctrl_driver);
-}
-postcore_initcall(exynos5440_pinctrl_drv_register);
-
-static void __exit exynos5440_pinctrl_drv_unregister(void)
-{
-       platform_driver_unregister(&exynos5440_pinctrl_driver);
-}
-module_exit(exynos5440_pinctrl_drv_unregister);
-
-MODULE_AUTHOR("Thomas Abraham <thomas.ab@samsung.com>");
-MODULE_DESCRIPTION("Samsung EXYNOS5440 SoC pinctrl driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/pinctrl-s3c24xx.c b/drivers/pinctrl/pinctrl-s3c24xx.c
deleted file mode 100644 (file)
index ad3eaad..0000000
+++ /dev/null
@@ -1,651 +0,0 @@
-/*
- * S3C24XX specific support for Samsung pinctrl/gpiolib driver.
- *
- * Copyright (c) 2013 Heiko Stuebner <heiko@sntech.de>
- *
- * 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This file contains the SamsungS3C24XX specific information required by the
- * Samsung pinctrl/gpiolib driver. It also includes the implementation of
- * external gpio and wakeup interrupt support.
- */
-
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/interrupt.h>
-#include <linux/irqdomain.h>
-#include <linux/irq.h>
-#include <linux/of_irq.h>
-#include <linux/irqchip/chained_irq.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/err.h>
-
-#include "pinctrl-samsung.h"
-
-#define NUM_EINT       24
-#define NUM_EINT_IRQ   6
-#define EINT_MAX_PER_GROUP     8
-
-#define EINTPEND_REG   0xa8
-#define EINTMASK_REG   0xa4
-
-#define EINT_GROUP(i)          ((int)((i) / EINT_MAX_PER_GROUP))
-#define EINT_REG(i)            ((EINT_GROUP(i) * 4) + 0x88)
-#define EINT_OFFS(i)           ((i) % EINT_MAX_PER_GROUP * 4)
-
-#define EINT_LEVEL_LOW         0
-#define EINT_LEVEL_HIGH                1
-#define EINT_EDGE_FALLING      2
-#define EINT_EDGE_RISING       4
-#define EINT_EDGE_BOTH         6
-#define EINT_MASK              0xf
-
-static struct samsung_pin_bank_type bank_type_1bit = {
-       .fld_width = { 1, 1, },
-       .reg_offset = { 0x00, 0x04, },
-};
-
-static struct samsung_pin_bank_type bank_type_2bit = {
-       .fld_width = { 2, 1, 2, },
-       .reg_offset = { 0x00, 0x04, 0x08, },
-};
-
-#define PIN_BANK_A(pins, reg, id)              \
-       {                                               \
-               .type           = &bank_type_1bit,      \
-               .pctl_offset    = reg,                  \
-               .nr_pins        = pins,                 \
-               .eint_type      = EINT_TYPE_NONE,       \
-               .name           = id                    \
-       }
-
-#define PIN_BANK_2BIT(pins, reg, id)           \
-       {                                               \
-               .type           = &bank_type_2bit,      \
-               .pctl_offset    = reg,                  \
-               .nr_pins        = pins,                 \
-               .eint_type      = EINT_TYPE_NONE,       \
-               .name           = id                    \
-       }
-
-#define PIN_BANK_2BIT_EINTW(pins, reg, id, eoffs, emask)\
-       {                                               \
-               .type           = &bank_type_2bit,      \
-               .pctl_offset    = reg,                  \
-               .nr_pins        = pins,                 \
-               .eint_type      = EINT_TYPE_WKUP,       \
-               .eint_func      = 2,                    \
-               .eint_mask      = emask,                \
-               .eint_offset    = eoffs,                \
-               .name           = id                    \
-       }
-
-/**
- * struct s3c24xx_eint_data: EINT common data
- * @drvdata: pin controller driver data
- * @domains: IRQ domains of particular EINT interrupts
- * @parents: mapped parent irqs in the main interrupt controller
- */
-struct s3c24xx_eint_data {
-       struct samsung_pinctrl_drv_data *drvdata;
-       struct irq_domain *domains[NUM_EINT];
-       int parents[NUM_EINT_IRQ];
-};
-
-/**
- * struct s3c24xx_eint_domain_data: per irq-domain data
- * @bank: pin bank related to the domain
- * @eint_data: common data
- * eint0_3_parent_only: live eints 0-3 only in the main intc
- */
-struct s3c24xx_eint_domain_data {
-       struct samsung_pin_bank *bank;
-       struct s3c24xx_eint_data *eint_data;
-       bool eint0_3_parent_only;
-};
-
-static int s3c24xx_eint_get_trigger(unsigned int type)
-{
-       switch (type) {
-       case IRQ_TYPE_EDGE_RISING:
-               return EINT_EDGE_RISING;
-               break;
-       case IRQ_TYPE_EDGE_FALLING:
-               return EINT_EDGE_FALLING;
-               break;
-       case IRQ_TYPE_EDGE_BOTH:
-               return EINT_EDGE_BOTH;
-               break;
-       case IRQ_TYPE_LEVEL_HIGH:
-               return EINT_LEVEL_HIGH;
-               break;
-       case IRQ_TYPE_LEVEL_LOW:
-               return EINT_LEVEL_LOW;
-               break;
-       default:
-               return -EINVAL;
-       }
-}
-
-static void s3c24xx_eint_set_handler(unsigned int irq, unsigned int type)
-{
-       /* Edge- and level-triggered interrupts need different handlers */
-       if (type & IRQ_TYPE_EDGE_BOTH)
-               __irq_set_handler_locked(irq, handle_edge_irq);
-       else
-               __irq_set_handler_locked(irq, handle_level_irq);
-}
-
-static void s3c24xx_eint_set_function(struct samsung_pinctrl_drv_data *d,
-                                       struct samsung_pin_bank *bank, int pin)
-{
-       struct samsung_pin_bank_type *bank_type = bank->type;
-       unsigned long flags;
-       void __iomem *reg;
-       u8 shift;
-       u32 mask;
-       u32 val;
-
-       /* Make sure that pin is configured as interrupt */
-       reg = d->virt_base + bank->pctl_offset;
-       shift = pin * bank_type->fld_width[PINCFG_TYPE_FUNC];
-       mask = (1 << bank_type->fld_width[PINCFG_TYPE_FUNC]) - 1;
-
-       spin_lock_irqsave(&bank->slock, flags);
-
-       val = readl(reg);
-       val &= ~(mask << shift);
-       val |= bank->eint_func << shift;
-       writel(val, reg);
-
-       spin_unlock_irqrestore(&bank->slock, flags);
-}
-
-static int s3c24xx_eint_type(struct irq_data *data, unsigned int type)
-{
-       struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(data);
-       struct samsung_pinctrl_drv_data *d = bank->drvdata;
-       int index = bank->eint_offset + data->hwirq;
-       void __iomem *reg;
-       int trigger;
-       u8 shift;
-       u32 val;
-
-       trigger = s3c24xx_eint_get_trigger(type);
-       if (trigger < 0) {
-               dev_err(d->dev, "unsupported external interrupt type\n");
-               return -EINVAL;
-       }
-
-       s3c24xx_eint_set_handler(data->irq, type);
-
-       /* Set up interrupt trigger */
-       reg = d->virt_base + EINT_REG(index);
-       shift = EINT_OFFS(index);
-
-       val = readl(reg);
-       val &= ~(EINT_MASK << shift);
-       val |= trigger << shift;
-       writel(val, reg);
-
-       s3c24xx_eint_set_function(d, bank, data->hwirq);
-
-       return 0;
-}
-
-/* Handling of EINTs 0-3 on all except S3C2412 and S3C2413 */
-
-static void s3c2410_eint0_3_ack(struct irq_data *data)
-{
-       struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(data);
-       struct s3c24xx_eint_domain_data *ddata = bank->irq_domain->host_data;
-       struct s3c24xx_eint_data *eint_data = ddata->eint_data;
-       int parent_irq = eint_data->parents[data->hwirq];
-       struct irq_chip *parent_chip = irq_get_chip(parent_irq);
-
-       parent_chip->irq_ack(irq_get_irq_data(parent_irq));
-}
-
-static void s3c2410_eint0_3_mask(struct irq_data *data)
-{
-       struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(data);
-       struct s3c24xx_eint_domain_data *ddata = bank->irq_domain->host_data;
-       struct s3c24xx_eint_data *eint_data = ddata->eint_data;
-       int parent_irq = eint_data->parents[data->hwirq];
-       struct irq_chip *parent_chip = irq_get_chip(parent_irq);
-
-       parent_chip->irq_mask(irq_get_irq_data(parent_irq));
-}
-
-static void s3c2410_eint0_3_unmask(struct irq_data *data)
-{
-       struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(data);
-       struct s3c24xx_eint_domain_data *ddata = bank->irq_domain->host_data;
-       struct s3c24xx_eint_data *eint_data = ddata->eint_data;
-       int parent_irq = eint_data->parents[data->hwirq];
-       struct irq_chip *parent_chip = irq_get_chip(parent_irq);
-
-       parent_chip->irq_unmask(irq_get_irq_data(parent_irq));
-}
-
-static struct irq_chip s3c2410_eint0_3_chip = {
-       .name           = "s3c2410-eint0_3",
-       .irq_ack        = s3c2410_eint0_3_ack,
-       .irq_mask       = s3c2410_eint0_3_mask,
-       .irq_unmask     = s3c2410_eint0_3_unmask,
-       .irq_set_type   = s3c24xx_eint_type,
-};
-
-static void s3c2410_demux_eint0_3(unsigned int irq, struct irq_desc *desc)
-{
-       struct irq_data *data = irq_desc_get_irq_data(desc);
-       struct s3c24xx_eint_data *eint_data = irq_get_handler_data(irq);
-       unsigned int virq;
-
-       /* the first 4 eints have a simple 1 to 1 mapping */
-       virq = irq_linear_revmap(eint_data->domains[data->hwirq], data->hwirq);
-       /* Something must be really wrong if an unmapped EINT is unmasked */
-       BUG_ON(!virq);
-
-       generic_handle_irq(virq);
-}
-
-/* Handling of EINTs 0-3 on S3C2412 and S3C2413 */
-
-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);
-}
-
-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 |= (1UL << data->hwirq);
-       writel(mask, d->virt_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 &= ~(1UL << data->hwirq);
-       writel(mask, d->virt_base + EINTMASK_REG);
-}
-
-static struct irq_chip s3c2412_eint0_3_chip = {
-       .name           = "s3c2412-eint0_3",
-       .irq_ack        = s3c2412_eint0_3_ack,
-       .irq_mask       = s3c2412_eint0_3_mask,
-       .irq_unmask     = s3c2412_eint0_3_unmask,
-       .irq_set_type   = s3c24xx_eint_type,
-};
-
-static void s3c2412_demux_eint0_3(unsigned int irq, struct irq_desc *desc)
-{
-       struct irq_chip *chip = irq_get_chip(irq);
-       struct irq_data *data = irq_desc_get_irq_data(desc);
-       struct s3c24xx_eint_data *eint_data = irq_get_handler_data(irq);
-       unsigned int virq;
-
-       chained_irq_enter(chip, desc);
-
-       /* the first 4 eints have a simple 1 to 1 mapping */
-       virq = irq_linear_revmap(eint_data->domains[data->hwirq], data->hwirq);
-       /* Something must be really wrong if an unmapped EINT is unmasked */
-       BUG_ON(!virq);
-
-       generic_handle_irq(virq);
-
-       chained_irq_exit(chip, desc);
-}
-
-/* Handling of all other eints */
-
-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);
-}
-
-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 |= (1UL << index);
-       writel(mask, d->virt_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 &= ~(1UL << index);
-       writel(mask, d->virt_base + EINTMASK_REG);
-}
-
-static struct irq_chip s3c24xx_eint_chip = {
-       .name           = "s3c-eint",
-       .irq_ack        = s3c24xx_eint_ack,
-       .irq_mask       = s3c24xx_eint_mask,
-       .irq_unmask     = s3c24xx_eint_unmask,
-       .irq_set_type   = s3c24xx_eint_type,
-};
-
-static inline void s3c24xx_demux_eint(unsigned int irq, struct irq_desc *desc,
-                                     u32 offset, u32 range)
-{
-       struct irq_chip *chip = irq_get_chip(irq);
-       struct s3c24xx_eint_data *data = irq_get_handler_data(irq);
-       struct samsung_pinctrl_drv_data *d = data->drvdata;
-       unsigned int pend, mask;
-
-       chained_irq_enter(chip, desc);
-
-       pend = readl(d->virt_base + EINTPEND_REG);
-       mask = readl(d->virt_base + EINTMASK_REG);
-
-       pend &= ~mask;
-       pend &= range;
-
-       while (pend) {
-               unsigned int virq;
-
-               irq = __ffs(pend);
-               pend &= ~(1 << irq);
-               virq = irq_linear_revmap(data->domains[irq], irq - offset);
-               /* Something is really wrong if an unmapped EINT is unmasked */
-               BUG_ON(!virq);
-
-               generic_handle_irq(virq);
-       }
-
-       chained_irq_exit(chip, desc);
-}
-
-static void s3c24xx_demux_eint4_7(unsigned int irq, struct irq_desc *desc)
-{
-       s3c24xx_demux_eint(irq, desc, 0, 0xf0);
-}
-
-static void s3c24xx_demux_eint8_23(unsigned int irq, struct irq_desc *desc)
-{
-       s3c24xx_demux_eint(irq, desc, 8, 0xffff00);
-}
-
-static irq_flow_handler_t s3c2410_eint_handlers[NUM_EINT_IRQ] = {
-       s3c2410_demux_eint0_3,
-       s3c2410_demux_eint0_3,
-       s3c2410_demux_eint0_3,
-       s3c2410_demux_eint0_3,
-       s3c24xx_demux_eint4_7,
-       s3c24xx_demux_eint8_23,
-};
-
-static irq_flow_handler_t s3c2412_eint_handlers[NUM_EINT_IRQ] = {
-       s3c2412_demux_eint0_3,
-       s3c2412_demux_eint0_3,
-       s3c2412_demux_eint0_3,
-       s3c2412_demux_eint0_3,
-       s3c24xx_demux_eint4_7,
-       s3c24xx_demux_eint8_23,
-};
-
-static int s3c24xx_gpf_irq_map(struct irq_domain *h, unsigned int virq,
-                                       irq_hw_number_t hw)
-{
-       struct s3c24xx_eint_domain_data *ddata = h->host_data;
-       struct samsung_pin_bank *bank = ddata->bank;
-
-       if (!(bank->eint_mask & (1 << (bank->eint_offset + hw))))
-               return -EINVAL;
-
-       if (hw <= 3) {
-               if (ddata->eint0_3_parent_only)
-                       irq_set_chip_and_handler(virq, &s3c2410_eint0_3_chip,
-                                                handle_edge_irq);
-               else
-                       irq_set_chip_and_handler(virq, &s3c2412_eint0_3_chip,
-                                                handle_edge_irq);
-       } else {
-               irq_set_chip_and_handler(virq, &s3c24xx_eint_chip,
-                                        handle_edge_irq);
-       }
-       irq_set_chip_data(virq, bank);
-       set_irq_flags(virq, IRQF_VALID);
-       return 0;
-}
-
-static const struct irq_domain_ops s3c24xx_gpf_irq_ops = {
-       .map    = s3c24xx_gpf_irq_map,
-       .xlate  = irq_domain_xlate_twocell,
-};
-
-static int s3c24xx_gpg_irq_map(struct irq_domain *h, unsigned int virq,
-                                       irq_hw_number_t hw)
-{
-       struct s3c24xx_eint_domain_data *ddata = h->host_data;
-       struct samsung_pin_bank *bank = ddata->bank;
-
-       if (!(bank->eint_mask & (1 << (bank->eint_offset + hw))))
-               return -EINVAL;
-
-       irq_set_chip_and_handler(virq, &s3c24xx_eint_chip, handle_edge_irq);
-       irq_set_chip_data(virq, bank);
-       set_irq_flags(virq, IRQF_VALID);
-       return 0;
-}
-
-static const struct irq_domain_ops s3c24xx_gpg_irq_ops = {
-       .map    = s3c24xx_gpg_irq_map,
-       .xlate  = irq_domain_xlate_twocell,
-};
-
-static const struct of_device_id s3c24xx_eint_irq_ids[] = {
-       { .compatible = "samsung,s3c2410-wakeup-eint", .data = (void *)1 },
-       { .compatible = "samsung,s3c2412-wakeup-eint", .data = (void *)0 },
-       { }
-};
-
-static int s3c24xx_eint_init(struct samsung_pinctrl_drv_data *d)
-{
-       struct device *dev = d->dev;
-       const struct of_device_id *match;
-       struct device_node *eint_np = NULL;
-       struct device_node *np;
-       struct samsung_pin_bank *bank;
-       struct s3c24xx_eint_data *eint_data;
-       const struct irq_domain_ops *ops;
-       unsigned int i;
-       bool eint0_3_parent_only;
-       irq_flow_handler_t *handlers;
-
-       for_each_child_of_node(dev->of_node, np) {
-               match = of_match_node(s3c24xx_eint_irq_ids, np);
-               if (match) {
-                       eint_np = np;
-                       eint0_3_parent_only = (bool)match->data;
-                       break;
-               }
-       }
-       if (!eint_np)
-               return -ENODEV;
-
-       eint_data = devm_kzalloc(dev, sizeof(*eint_data), GFP_KERNEL);
-       if (!eint_data)
-               return -ENOMEM;
-
-       eint_data->drvdata = d;
-
-       handlers = eint0_3_parent_only ? s3c2410_eint_handlers
-                                      : s3c2412_eint_handlers;
-       for (i = 0; i < NUM_EINT_IRQ; ++i) {
-               unsigned int irq;
-
-               irq = irq_of_parse_and_map(eint_np, i);
-               if (!irq) {
-                       dev_err(dev, "failed to get wakeup EINT IRQ %d\n", i);
-                       return -ENXIO;
-               }
-
-               eint_data->parents[i] = irq;
-               irq_set_chained_handler(irq, handlers[i]);
-               irq_set_handler_data(irq, eint_data);
-       }
-
-       bank = d->ctrl->pin_banks;
-       for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) {
-               struct s3c24xx_eint_domain_data *ddata;
-               unsigned int mask;
-               unsigned int irq;
-               unsigned int pin;
-
-               if (bank->eint_type != EINT_TYPE_WKUP)
-                       continue;
-
-               ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
-               if (!ddata)
-                       return -ENOMEM;
-
-               ddata->bank = bank;
-               ddata->eint_data = eint_data;
-               ddata->eint0_3_parent_only = eint0_3_parent_only;
-
-               ops = (bank->eint_offset == 0) ? &s3c24xx_gpf_irq_ops
-                                              : &s3c24xx_gpg_irq_ops;
-
-               bank->irq_domain = irq_domain_add_linear(bank->of_node,
-                               bank->nr_pins, ops, ddata);
-               if (!bank->irq_domain) {
-                       dev_err(dev, "wkup irq domain add failed\n");
-                       return -ENXIO;
-               }
-
-               irq = bank->eint_offset;
-               mask = bank->eint_mask;
-               for (pin = 0; mask; ++pin, mask >>= 1) {
-                       if (irq >= NUM_EINT)
-                               break;
-                       if (!(mask & 1))
-                               continue;
-                       eint_data->domains[irq] = bank->irq_domain;
-                       ++irq;
-               }
-       }
-
-       return 0;
-}
-
-static struct samsung_pin_bank s3c2412_pin_banks[] = {
-       PIN_BANK_A(23, 0x000, "gpa"),
-       PIN_BANK_2BIT(11, 0x010, "gpb"),
-       PIN_BANK_2BIT(16, 0x020, "gpc"),
-       PIN_BANK_2BIT(16, 0x030, "gpd"),
-       PIN_BANK_2BIT(16, 0x040, "gpe"),
-       PIN_BANK_2BIT_EINTW(8, 0x050, "gpf", 0, 0xff),
-       PIN_BANK_2BIT_EINTW(16, 0x060, "gpg", 8, 0xffff00),
-       PIN_BANK_2BIT(11, 0x070, "gph"),
-       PIN_BANK_2BIT(13, 0x080, "gpj"),
-};
-
-struct samsung_pin_ctrl s3c2412_pin_ctrl[] = {
-       {
-               .pin_banks      = s3c2412_pin_banks,
-               .nr_banks       = ARRAY_SIZE(s3c2412_pin_banks),
-               .eint_wkup_init = s3c24xx_eint_init,
-               .label          = "S3C2412-GPIO",
-       },
-};
-
-static struct samsung_pin_bank s3c2416_pin_banks[] = {
-       PIN_BANK_A(27, 0x000, "gpa"),
-       PIN_BANK_2BIT(11, 0x010, "gpb"),
-       PIN_BANK_2BIT(16, 0x020, "gpc"),
-       PIN_BANK_2BIT(16, 0x030, "gpd"),
-       PIN_BANK_2BIT(16, 0x040, "gpe"),
-       PIN_BANK_2BIT_EINTW(8, 0x050, "gpf", 0, 0xff),
-       PIN_BANK_2BIT_EINTW(8, 0x060, "gpg", 8, 0xff00),
-       PIN_BANK_2BIT(15, 0x070, "gph"),
-       PIN_BANK_2BIT(16, 0x0e0, "gpk"),
-       PIN_BANK_2BIT(14, 0x0f0, "gpl"),
-       PIN_BANK_2BIT(2, 0x100, "gpm"),
-};
-
-struct samsung_pin_ctrl s3c2416_pin_ctrl[] = {
-       {
-               .pin_banks      = s3c2416_pin_banks,
-               .nr_banks       = ARRAY_SIZE(s3c2416_pin_banks),
-               .eint_wkup_init = s3c24xx_eint_init,
-               .label          = "S3C2416-GPIO",
-       },
-};
-
-static struct samsung_pin_bank s3c2440_pin_banks[] = {
-       PIN_BANK_A(25, 0x000, "gpa"),
-       PIN_BANK_2BIT(11, 0x010, "gpb"),
-       PIN_BANK_2BIT(16, 0x020, "gpc"),
-       PIN_BANK_2BIT(16, 0x030, "gpd"),
-       PIN_BANK_2BIT(16, 0x040, "gpe"),
-       PIN_BANK_2BIT_EINTW(8, 0x050, "gpf", 0, 0xff),
-       PIN_BANK_2BIT_EINTW(16, 0x060, "gpg", 8, 0xffff00),
-       PIN_BANK_2BIT(11, 0x070, "gph"),
-       PIN_BANK_2BIT(13, 0x0d0, "gpj"),
-};
-
-struct samsung_pin_ctrl s3c2440_pin_ctrl[] = {
-       {
-               .pin_banks      = s3c2440_pin_banks,
-               .nr_banks       = ARRAY_SIZE(s3c2440_pin_banks),
-               .eint_wkup_init = s3c24xx_eint_init,
-               .label          = "S3C2440-GPIO",
-       },
-};
-
-static struct samsung_pin_bank s3c2450_pin_banks[] = {
-       PIN_BANK_A(28, 0x000, "gpa"),
-       PIN_BANK_2BIT(11, 0x010, "gpb"),
-       PIN_BANK_2BIT(16, 0x020, "gpc"),
-       PIN_BANK_2BIT(16, 0x030, "gpd"),
-       PIN_BANK_2BIT(16, 0x040, "gpe"),
-       PIN_BANK_2BIT_EINTW(8, 0x050, "gpf", 0, 0xff),
-       PIN_BANK_2BIT_EINTW(16, 0x060, "gpg", 8, 0xffff00),
-       PIN_BANK_2BIT(15, 0x070, "gph"),
-       PIN_BANK_2BIT(16, 0x0d0, "gpj"),
-       PIN_BANK_2BIT(16, 0x0e0, "gpk"),
-       PIN_BANK_2BIT(15, 0x0f0, "gpl"),
-       PIN_BANK_2BIT(2, 0x100, "gpm"),
-};
-
-struct samsung_pin_ctrl s3c2450_pin_ctrl[] = {
-       {
-               .pin_banks      = s3c2450_pin_banks,
-               .nr_banks       = ARRAY_SIZE(s3c2450_pin_banks),
-               .eint_wkup_init = s3c24xx_eint_init,
-               .label          = "S3C2450-GPIO",
-       },
-};
diff --git a/drivers/pinctrl/pinctrl-s3c64xx.c b/drivers/pinctrl/pinctrl-s3c64xx.c
deleted file mode 100644 (file)
index 89143c9..0000000
+++ /dev/null
@@ -1,816 +0,0 @@
-/*
- * S3C64xx specific support for pinctrl-samsung driver.
- *
- * Copyright (c) 2013 Tomasz Figa <tomasz.figa@gmail.com>
- *
- * Based on pinctrl-exynos.c, please see the file for original copyrights.
- *
- * 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This file contains the Samsung S3C64xx specific information required by the
- * the Samsung pinctrl/gpiolib driver. It also includes the implementation of
- * external gpio and wakeup interrupt support.
- */
-
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/interrupt.h>
-#include <linux/irqdomain.h>
-#include <linux/irq.h>
-#include <linux/of_irq.h>
-#include <linux/io.h>
-#include <linux/irqchip/chained_irq.h>
-#include <linux/slab.h>
-#include <linux/err.h>
-
-#include "pinctrl-samsung.h"
-
-#define NUM_EINT0              28
-#define NUM_EINT0_IRQ          4
-#define EINT_MAX_PER_REG       16
-#define EINT_MAX_PER_GROUP     16
-
-/* External GPIO and wakeup interrupt related definitions */
-#define SVC_GROUP_SHIFT                4
-#define SVC_GROUP_MASK         0xf
-#define SVC_NUM_MASK           0xf
-#define SVC_GROUP(x)           ((x >> SVC_GROUP_SHIFT) & \
-                                               SVC_GROUP_MASK)
-
-#define EINT12CON_REG          0x200
-#define EINT12MASK_REG         0x240
-#define EINT12PEND_REG         0x260
-
-#define EINT_OFFS(i)           ((i) % (2 * EINT_MAX_PER_GROUP))
-#define EINT_GROUP(i)          ((i) / EINT_MAX_PER_GROUP)
-#define EINT_REG(g)            (4 * ((g) / 2))
-
-#define EINTCON_REG(i)         (EINT12CON_REG + EINT_REG(EINT_GROUP(i)))
-#define EINTMASK_REG(i)                (EINT12MASK_REG + EINT_REG(EINT_GROUP(i)))
-#define EINTPEND_REG(i)                (EINT12PEND_REG + EINT_REG(EINT_GROUP(i)))
-
-#define SERVICE_REG            0x284
-#define SERVICEPEND_REG                0x288
-
-#define EINT0CON0_REG          0x900
-#define EINT0MASK_REG          0x920
-#define EINT0PEND_REG          0x924
-
-/* S3C64xx specific external interrupt trigger types */
-#define EINT_LEVEL_LOW         0
-#define EINT_LEVEL_HIGH                1
-#define EINT_EDGE_FALLING      2
-#define EINT_EDGE_RISING       4
-#define EINT_EDGE_BOTH         6
-#define EINT_CON_MASK          0xF
-#define EINT_CON_LEN           4
-
-static 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, },
-};
-
-static struct samsung_pin_bank_type bank_type_4bit_alive = {
-       .fld_width = { 4, 1, 2, },
-       .reg_offset = { 0x00, 0x04, 0x08, },
-};
-
-static struct samsung_pin_bank_type bank_type_4bit2_off = {
-       .fld_width = { 4, 1, 2, 0, 2, 2, },
-       .reg_offset = { 0x00, 0x08, 0x0c, 0, 0x10, 0x14, },
-};
-
-static struct samsung_pin_bank_type bank_type_4bit2_alive = {
-       .fld_width = { 4, 1, 2, },
-       .reg_offset = { 0x00, 0x08, 0x0c, },
-};
-
-static struct samsung_pin_bank_type bank_type_2bit_off = {
-       .fld_width = { 2, 1, 2, 0, 2, 2, },
-       .reg_offset = { 0x00, 0x04, 0x08, 0, 0x0c, 0x10, },
-};
-
-static struct samsung_pin_bank_type bank_type_2bit_alive = {
-       .fld_width = { 2, 1, 2, },
-       .reg_offset = { 0x00, 0x04, 0x08, },
-};
-
-#define PIN_BANK_4BIT(pins, reg, id)                   \
-       {                                               \
-               .type           = &bank_type_4bit_off,  \
-               .pctl_offset    = reg,                  \
-               .nr_pins        = pins,                 \
-               .eint_type      = EINT_TYPE_NONE,       \
-               .name           = id                    \
-       }
-
-#define PIN_BANK_4BIT_EINTG(pins, reg, id, eoffs)      \
-       {                                               \
-               .type           = &bank_type_4bit_off,  \
-               .pctl_offset    = reg,                  \
-               .nr_pins        = pins,                 \
-               .eint_type      = EINT_TYPE_GPIO,       \
-               .eint_func      = 7,                    \
-               .eint_mask      = (1 << (pins)) - 1,    \
-               .eint_offset    = eoffs,                \
-               .name           = id                    \
-       }
-
-#define PIN_BANK_4BIT_EINTW(pins, reg, id, eoffs, emask) \
-       {                                               \
-               .type           = &bank_type_4bit_alive,\
-               .pctl_offset    = reg,                  \
-               .nr_pins        = pins,                 \
-               .eint_type      = EINT_TYPE_WKUP,       \
-               .eint_func      = 3,                    \
-               .eint_mask      = emask,                \
-               .eint_offset    = eoffs,                \
-               .name           = id                    \
-       }
-
-#define PIN_BANK_4BIT2_EINTG(pins, reg, id, eoffs)     \
-       {                                               \
-               .type           = &bank_type_4bit2_off, \
-               .pctl_offset    = reg,                  \
-               .nr_pins        = pins,                 \
-               .eint_type      = EINT_TYPE_GPIO,       \
-               .eint_func      = 7,                    \
-               .eint_mask      = (1 << (pins)) - 1,    \
-               .eint_offset    = eoffs,                \
-               .name           = id                    \
-       }
-
-#define PIN_BANK_4BIT2_EINTW(pins, reg, id, eoffs, emask) \
-       {                                               \
-               .type           = &bank_type_4bit2_alive,\
-               .pctl_offset    = reg,                  \
-               .nr_pins        = pins,                 \
-               .eint_type      = EINT_TYPE_WKUP,       \
-               .eint_func      = 3,                    \
-               .eint_mask      = emask,                \
-               .eint_offset    = eoffs,                \
-               .name           = id                    \
-       }
-
-#define PIN_BANK_4BIT2_ALIVE(pins, reg, id)            \
-       {                                               \
-               .type           = &bank_type_4bit2_alive,\
-               .pctl_offset    = reg,                  \
-               .nr_pins        = pins,                 \
-               .eint_type      = EINT_TYPE_NONE,       \
-               .name           = id                    \
-       }
-
-#define PIN_BANK_2BIT(pins, reg, id)                   \
-       {                                               \
-               .type           = &bank_type_2bit_off,  \
-               .pctl_offset    = reg,                  \
-               .nr_pins        = pins,                 \
-               .eint_type      = EINT_TYPE_NONE,       \
-               .name           = id                    \
-       }
-
-#define PIN_BANK_2BIT_EINTG(pins, reg, id, eoffs, emask) \
-       {                                               \
-               .type           = &bank_type_2bit_off,  \
-               .pctl_offset    = reg,                  \
-               .nr_pins        = pins,                 \
-               .eint_type      = EINT_TYPE_GPIO,       \
-               .eint_func      = 3,                    \
-               .eint_mask      = emask,                \
-               .eint_offset    = eoffs,                \
-               .name           = id                    \
-       }
-
-#define PIN_BANK_2BIT_EINTW(pins, reg, id, eoffs)      \
-       {                                               \
-               .type           = &bank_type_2bit_alive,\
-               .pctl_offset    = reg,                  \
-               .nr_pins        = pins,                 \
-               .eint_type      = EINT_TYPE_WKUP,       \
-               .eint_func      = 2,                    \
-               .eint_mask      = (1 << (pins)) - 1,    \
-               .eint_offset    = eoffs,                \
-               .name           = id                    \
-       }
-
-/**
- * struct s3c64xx_eint0_data: EINT0 common data
- * @drvdata: pin controller driver data
- * @domains: IRQ domains of particular EINT0 interrupts
- * @pins: pin offsets inside of banks of particular EINT0 interrupts
- */
-struct s3c64xx_eint0_data {
-       struct samsung_pinctrl_drv_data *drvdata;
-       struct irq_domain *domains[NUM_EINT0];
-       u8 pins[NUM_EINT0];
-};
-
-/**
- * struct s3c64xx_eint0_domain_data: EINT0 per-domain data
- * @bank: pin bank related to the domain
- * @eints: EINT0 interrupts related to the domain
- */
-struct s3c64xx_eint0_domain_data {
-       struct samsung_pin_bank *bank;
-       u8 eints[];
-};
-
-/**
- * struct s3c64xx_eint_gpio_data: GPIO EINT data
- * @drvdata: pin controller driver data
- * @domains: array of domains related to EINT interrupt groups
- */
-struct s3c64xx_eint_gpio_data {
-       struct samsung_pinctrl_drv_data *drvdata;
-       struct irq_domain *domains[];
-};
-
-/*
- * Common functions for S3C64xx EINT configuration
- */
-
-static int s3c64xx_irq_get_trigger(unsigned int type)
-{
-       int trigger;
-
-       switch (type) {
-       case IRQ_TYPE_EDGE_RISING:
-               trigger = EINT_EDGE_RISING;
-               break;
-       case IRQ_TYPE_EDGE_FALLING:
-               trigger = EINT_EDGE_FALLING;
-               break;
-       case IRQ_TYPE_EDGE_BOTH:
-               trigger = EINT_EDGE_BOTH;
-               break;
-       case IRQ_TYPE_LEVEL_HIGH:
-               trigger = EINT_LEVEL_HIGH;
-               break;
-       case IRQ_TYPE_LEVEL_LOW:
-               trigger = EINT_LEVEL_LOW;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return trigger;
-}
-
-static void s3c64xx_irq_set_handler(unsigned int irq, unsigned int type)
-{
-       /* Edge- and level-triggered interrupts need different handlers */
-       if (type & IRQ_TYPE_EDGE_BOTH)
-               __irq_set_handler_locked(irq, handle_edge_irq);
-       else
-               __irq_set_handler_locked(irq, handle_level_irq);
-}
-
-static void s3c64xx_irq_set_function(struct samsung_pinctrl_drv_data *d,
-                                       struct samsung_pin_bank *bank, int pin)
-{
-       struct samsung_pin_bank_type *bank_type = bank->type;
-       unsigned long flags;
-       void __iomem *reg;
-       u8 shift;
-       u32 mask;
-       u32 val;
-
-       /* Make sure that pin is configured as interrupt */
-       reg = d->virt_base + bank->pctl_offset;
-       shift = pin;
-       if (bank_type->fld_width[PINCFG_TYPE_FUNC] * shift >= 32) {
-               /* 4-bit bank type with 2 con regs */
-               reg += 4;
-               shift -= 8;
-       }
-
-       shift = shift * bank_type->fld_width[PINCFG_TYPE_FUNC];
-       mask = (1 << bank_type->fld_width[PINCFG_TYPE_FUNC]) - 1;
-
-       spin_lock_irqsave(&bank->slock, flags);
-
-       val = readl(reg);
-       val &= ~(mask << shift);
-       val |= bank->eint_func << shift;
-       writel(val, reg);
-
-       spin_unlock_irqrestore(&bank->slock, flags);
-}
-
-/*
- * Functions for EINT GPIO configuration (EINT groups 1-9)
- */
-
-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);
-       u32 val;
-
-       val = readl(reg);
-       if (mask)
-               val |= 1 << index;
-       else
-               val &= ~(1 << index);
-       writel(val, reg);
-}
-
-static void s3c64xx_gpio_irq_unmask(struct irq_data *irqd)
-{
-       s3c64xx_gpio_irq_set_mask(irqd, false);
-}
-
-static void s3c64xx_gpio_irq_mask(struct irq_data *irqd)
-{
-       s3c64xx_gpio_irq_set_mask(irqd, true);
-}
-
-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);
-
-       writel(1 << index, reg);
-}
-
-static int s3c64xx_gpio_irq_set_type(struct irq_data *irqd, unsigned int type)
-{
-       struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
-       struct samsung_pinctrl_drv_data *d = bank->drvdata;
-       void __iomem *reg;
-       int trigger;
-       u8 shift;
-       u32 val;
-
-       trigger = s3c64xx_irq_get_trigger(type);
-       if (trigger < 0) {
-               pr_err("unsupported external interrupt type\n");
-               return -EINVAL;
-       }
-
-       s3c64xx_irq_set_handler(irqd->irq, type);
-
-       /* Set up interrupt trigger */
-       reg = d->virt_base + EINTCON_REG(bank->eint_offset);
-       shift = EINT_OFFS(bank->eint_offset) + irqd->hwirq;
-       shift = 4 * (shift / 4); /* 4 EINTs per trigger selector */
-
-       val = readl(reg);
-       val &= ~(EINT_CON_MASK << shift);
-       val |= trigger << shift;
-       writel(val, reg);
-
-       s3c64xx_irq_set_function(d, bank, irqd->hwirq);
-
-       return 0;
-}
-
-/*
- * irq_chip for gpio interrupts.
- */
-static struct irq_chip s3c64xx_gpio_irq_chip = {
-       .name           = "GPIO",
-       .irq_unmask     = s3c64xx_gpio_irq_unmask,
-       .irq_mask       = s3c64xx_gpio_irq_mask,
-       .irq_ack        = s3c64xx_gpio_irq_ack,
-       .irq_set_type   = s3c64xx_gpio_irq_set_type,
-};
-
-static int s3c64xx_gpio_irq_map(struct irq_domain *h, unsigned int virq,
-                                       irq_hw_number_t hw)
-{
-       struct samsung_pin_bank *bank = h->host_data;
-
-       if (!(bank->eint_mask & (1 << hw)))
-               return -EINVAL;
-
-       irq_set_chip_and_handler(virq,
-                               &s3c64xx_gpio_irq_chip, handle_level_irq);
-       irq_set_chip_data(virq, bank);
-       set_irq_flags(virq, IRQF_VALID);
-
-       return 0;
-}
-
-/*
- * irq domain callbacks for external gpio interrupt controller.
- */
-static const struct irq_domain_ops s3c64xx_gpio_irqd_ops = {
-       .map    = s3c64xx_gpio_irq_map,
-       .xlate  = irq_domain_xlate_twocell,
-};
-
-static void s3c64xx_eint_gpio_irq(unsigned int irq, struct irq_desc *desc)
-{
-       struct irq_chip *chip = irq_get_chip(irq);
-       struct s3c64xx_eint_gpio_data *data = irq_get_handler_data(irq);
-       struct samsung_pinctrl_drv_data *drvdata = data->drvdata;
-
-       chained_irq_enter(chip, desc);
-
-       do {
-               unsigned int svc;
-               unsigned int group;
-               unsigned int pin;
-               unsigned int virq;
-
-               svc = readl(drvdata->virt_base + SERVICE_REG);
-               group = SVC_GROUP(svc);
-               pin = svc & SVC_NUM_MASK;
-
-               if (!group)
-                       break;
-
-               /* Group 1 is used for two pin banks */
-               if (group == 1) {
-                       if (pin < 8)
-                               group = 0;
-                       else
-                               pin -= 8;
-               }
-
-               virq = irq_linear_revmap(data->domains[group], pin);
-               /*
-                * Something must be really wrong if an unmapped EINT
-                * was unmasked...
-                */
-               BUG_ON(!virq);
-
-               generic_handle_irq(virq);
-       } while (1);
-
-       chained_irq_exit(chip, desc);
-}
-
-/**
- * s3c64xx_eint_gpio_init() - setup handling of external gpio interrupts.
- * @d: driver data of samsung pinctrl driver.
- */
-static int s3c64xx_eint_gpio_init(struct samsung_pinctrl_drv_data *d)
-{
-       struct s3c64xx_eint_gpio_data *data;
-       struct samsung_pin_bank *bank;
-       struct device *dev = d->dev;
-       unsigned int nr_domains;
-       unsigned int i;
-
-       if (!d->irq) {
-               dev_err(dev, "irq number not available\n");
-               return -EINVAL;
-       }
-
-       nr_domains = 0;
-       bank = d->ctrl->pin_banks;
-       for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) {
-               unsigned int nr_eints;
-               unsigned int mask;
-
-               if (bank->eint_type != EINT_TYPE_GPIO)
-                       continue;
-
-               mask = bank->eint_mask;
-               nr_eints = fls(mask);
-
-               bank->irq_domain = irq_domain_add_linear(bank->of_node,
-                                       nr_eints, &s3c64xx_gpio_irqd_ops, bank);
-               if (!bank->irq_domain) {
-                       dev_err(dev, "gpio irq domain add failed\n");
-                       return -ENXIO;
-               }
-
-               ++nr_domains;
-       }
-
-       data = devm_kzalloc(dev, sizeof(*data)
-                       + nr_domains * sizeof(*data->domains), GFP_KERNEL);
-       if (!data) {
-               dev_err(dev, "failed to allocate handler data\n");
-               return -ENOMEM;
-       }
-       data->drvdata = d;
-
-       bank = d->ctrl->pin_banks;
-       nr_domains = 0;
-       for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) {
-               if (bank->eint_type != EINT_TYPE_GPIO)
-                       continue;
-
-               data->domains[nr_domains++] = bank->irq_domain;
-       }
-
-       irq_set_chained_handler(d->irq, s3c64xx_eint_gpio_irq);
-       irq_set_handler_data(d->irq, data);
-
-       return 0;
-}
-
-/*
- * Functions for configuration of EINT0 wake-up interrupts
- */
-
-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;
-       u32 val;
-
-       val = readl(d->virt_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);
-}
-
-static void s3c64xx_eint0_irq_unmask(struct irq_data *irqd)
-{
-       s3c64xx_eint0_irq_set_mask(irqd, false);
-}
-
-static void s3c64xx_eint0_irq_mask(struct irq_data *irqd)
-{
-       s3c64xx_eint0_irq_set_mask(irqd, true);
-}
-
-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;
-
-       writel(1 << ddata->eints[irqd->hwirq],
-                                       d->virt_base + EINT0PEND_REG);
-}
-
-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;
-       void __iomem *reg;
-       int trigger;
-       u8 shift;
-       u32 val;
-
-       trigger = s3c64xx_irq_get_trigger(type);
-       if (trigger < 0) {
-               pr_err("unsupported external interrupt type\n");
-               return -EINVAL;
-       }
-
-       s3c64xx_irq_set_handler(irqd->irq, type);
-
-       /* Set up interrupt trigger */
-       reg = d->virt_base + EINT0CON0_REG;
-       shift = ddata->eints[irqd->hwirq];
-       if (shift >= EINT_MAX_PER_REG) {
-               reg += 4;
-               shift -= EINT_MAX_PER_REG;
-       }
-       shift = EINT_CON_LEN * (shift / 2);
-
-       val = readl(reg);
-       val &= ~(EINT_CON_MASK << shift);
-       val |= trigger << shift;
-       writel(val, reg);
-
-       s3c64xx_irq_set_function(d, bank, irqd->hwirq);
-
-       return 0;
-}
-
-/*
- * irq_chip for wakeup interrupts
- */
-static struct irq_chip s3c64xx_eint0_irq_chip = {
-       .name           = "EINT0",
-       .irq_unmask     = s3c64xx_eint0_irq_unmask,
-       .irq_mask       = s3c64xx_eint0_irq_mask,
-       .irq_ack        = s3c64xx_eint0_irq_ack,
-       .irq_set_type   = s3c64xx_eint0_irq_set_type,
-};
-
-static inline void s3c64xx_irq_demux_eint(unsigned int irq,
-                                       struct irq_desc *desc, u32 range)
-{
-       struct irq_chip *chip = irq_get_chip(irq);
-       struct s3c64xx_eint0_data *data = irq_get_handler_data(irq);
-       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 = pend & range & ~mask;
-       pend &= range;
-
-       while (pend) {
-               unsigned int virq;
-
-               irq = fls(pend) - 1;
-               pend &= ~(1 << irq);
-
-               virq = irq_linear_revmap(data->domains[irq], data->pins[irq]);
-               /*
-                * Something must be really wrong if an unmapped EINT
-                * was unmasked...
-                */
-               BUG_ON(!virq);
-
-               generic_handle_irq(virq);
-       }
-
-       chained_irq_exit(chip, desc);
-}
-
-static void s3c64xx_demux_eint0_3(unsigned int irq, struct irq_desc *desc)
-{
-       s3c64xx_irq_demux_eint(irq, desc, 0xf);
-}
-
-static void s3c64xx_demux_eint4_11(unsigned int irq, struct irq_desc *desc)
-{
-       s3c64xx_irq_demux_eint(irq, desc, 0xff0);
-}
-
-static void s3c64xx_demux_eint12_19(unsigned int irq, struct irq_desc *desc)
-{
-       s3c64xx_irq_demux_eint(irq, desc, 0xff000);
-}
-
-static void s3c64xx_demux_eint20_27(unsigned int irq, struct irq_desc *desc)
-{
-       s3c64xx_irq_demux_eint(irq, desc, 0xff00000);
-}
-
-static irq_flow_handler_t s3c64xx_eint0_handlers[NUM_EINT0_IRQ] = {
-       s3c64xx_demux_eint0_3,
-       s3c64xx_demux_eint4_11,
-       s3c64xx_demux_eint12_19,
-       s3c64xx_demux_eint20_27,
-};
-
-static int s3c64xx_eint0_irq_map(struct irq_domain *h, unsigned int virq,
-                                       irq_hw_number_t hw)
-{
-       struct s3c64xx_eint0_domain_data *ddata = h->host_data;
-       struct samsung_pin_bank *bank = ddata->bank;
-
-       if (!(bank->eint_mask & (1 << hw)))
-               return -EINVAL;
-
-       irq_set_chip_and_handler(virq,
-                               &s3c64xx_eint0_irq_chip, handle_level_irq);
-       irq_set_chip_data(virq, ddata);
-       set_irq_flags(virq, IRQF_VALID);
-
-       return 0;
-}
-
-/*
- * irq domain callbacks for external wakeup interrupt controller.
- */
-static const struct irq_domain_ops s3c64xx_eint0_irqd_ops = {
-       .map    = s3c64xx_eint0_irq_map,
-       .xlate  = irq_domain_xlate_twocell,
-};
-
-/* list of external wakeup controllers supported */
-static const struct of_device_id s3c64xx_eint0_irq_ids[] = {
-       { .compatible = "samsung,s3c64xx-wakeup-eint", },
-       { }
-};
-
-/**
- * s3c64xx_eint_eint0_init() - setup handling of external wakeup interrupts.
- * @d: driver data of samsung pinctrl driver.
- */
-static int s3c64xx_eint_eint0_init(struct samsung_pinctrl_drv_data *d)
-{
-       struct device *dev = d->dev;
-       struct device_node *eint0_np = NULL;
-       struct device_node *np;
-       struct samsung_pin_bank *bank;
-       struct s3c64xx_eint0_data *data;
-       unsigned int i;
-
-       for_each_child_of_node(dev->of_node, np) {
-               if (of_match_node(s3c64xx_eint0_irq_ids, np)) {
-                       eint0_np = np;
-                       break;
-               }
-       }
-       if (!eint0_np)
-               return -ENODEV;
-
-       data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
-       if (!data) {
-               dev_err(dev, "could not allocate memory for wkup eint data\n");
-               return -ENOMEM;
-       }
-       data->drvdata = d;
-
-       for (i = 0; i < NUM_EINT0_IRQ; ++i) {
-               unsigned int irq;
-
-               irq = irq_of_parse_and_map(eint0_np, i);
-               if (!irq) {
-                       dev_err(dev, "failed to get wakeup EINT IRQ %d\n", i);
-                       return -ENXIO;
-               }
-
-               irq_set_chained_handler(irq, s3c64xx_eint0_handlers[i]);
-               irq_set_handler_data(irq, data);
-       }
-
-       bank = d->ctrl->pin_banks;
-       for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) {
-               struct s3c64xx_eint0_domain_data *ddata;
-               unsigned int nr_eints;
-               unsigned int mask;
-               unsigned int irq;
-               unsigned int pin;
-
-               if (bank->eint_type != EINT_TYPE_WKUP)
-                       continue;
-
-               mask = bank->eint_mask;
-               nr_eints = fls(mask);
-
-               ddata = devm_kzalloc(dev,
-                               sizeof(*ddata) + nr_eints, GFP_KERNEL);
-               if (!ddata) {
-                       dev_err(dev, "failed to allocate domain data\n");
-                       return -ENOMEM;
-               }
-               ddata->bank = bank;
-
-               bank->irq_domain = irq_domain_add_linear(bank->of_node,
-                               nr_eints, &s3c64xx_eint0_irqd_ops, ddata);
-               if (!bank->irq_domain) {
-                       dev_err(dev, "wkup irq domain add failed\n");
-                       return -ENXIO;
-               }
-
-               irq = bank->eint_offset;
-               mask = bank->eint_mask;
-               for (pin = 0; mask; ++pin, mask >>= 1) {
-                       if (!(mask & 1))
-                               continue;
-                       data->domains[irq] = bank->irq_domain;
-                       data->pins[irq] = pin;
-                       ddata->eints[pin] = irq;
-                       ++irq;
-               }
-       }
-
-       return 0;
-}
-
-/* pin banks of s3c64xx pin-controller 0 */
-static struct samsung_pin_bank s3c64xx_pin_banks0[] = {
-       PIN_BANK_4BIT_EINTG(8, 0x000, "gpa", 0),
-       PIN_BANK_4BIT_EINTG(7, 0x020, "gpb", 8),
-       PIN_BANK_4BIT_EINTG(8, 0x040, "gpc", 16),
-       PIN_BANK_4BIT_EINTG(5, 0x060, "gpd", 32),
-       PIN_BANK_4BIT(5, 0x080, "gpe"),
-       PIN_BANK_2BIT_EINTG(16, 0x0a0, "gpf", 48, 0x3fff),
-       PIN_BANK_4BIT_EINTG(7, 0x0c0, "gpg", 64),
-       PIN_BANK_4BIT2_EINTG(10, 0x0e0, "gph", 80),
-       PIN_BANK_2BIT(16, 0x100, "gpi"),
-       PIN_BANK_2BIT(12, 0x120, "gpj"),
-       PIN_BANK_4BIT2_ALIVE(16, 0x800, "gpk"),
-       PIN_BANK_4BIT2_EINTW(15, 0x810, "gpl", 16, 0x7f00),
-       PIN_BANK_4BIT_EINTW(6, 0x820, "gpm", 23, 0x1f),
-       PIN_BANK_2BIT_EINTW(16, 0x830, "gpn", 0),
-       PIN_BANK_2BIT_EINTG(16, 0x140, "gpo", 96, 0xffff),
-       PIN_BANK_2BIT_EINTG(15, 0x160, "gpp", 112, 0x7fff),
-       PIN_BANK_2BIT_EINTG(9, 0x180, "gpq", 128, 0x1ff),
-};
-
-/*
- * Samsung pinctrl driver data for S3C64xx SoC. S3C64xx SoC includes
- * one gpio/pin-mux/pinconfig controller.
- */
-struct samsung_pin_ctrl s3c64xx_pin_ctrl[] = {
-       {
-               /* pin-controller instance 1 data */
-               .pin_banks      = s3c64xx_pin_banks0,
-               .nr_banks       = ARRAY_SIZE(s3c64xx_pin_banks0),
-               .eint_gpio_init = s3c64xx_eint_gpio_init,
-               .eint_wkup_init = s3c64xx_eint_eint0_init,
-               .label          = "S3C64xx-GPIO",
-       },
-};
diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c
deleted file mode 100644 (file)
index 52f849a..0000000
+++ /dev/null
@@ -1,1285 +0,0 @@
-/*
- * pin-controller/pin-mux/pin-config/gpio-driver for Samsung's SoC's.
- *
- * Copyright (c) 2012 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com
- * Copyright (c) 2012 Linaro Ltd
- *             http://www.linaro.org
- *
- * Author: Thomas Abraham <thomas.ab@samsung.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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This driver implements the Samsung pinctrl driver. It supports setting up of
- * pinmux and pinconf configurations. The gpiolib interface is also included.
- * External interrupt (gpio and wakeup) support are not included in this driver
- * but provides extensions to which platform specific implementation of the gpio
- * and wakeup interrupts can be hooked to.
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/err.h>
-#include <linux/gpio.h>
-#include <linux/irqdomain.h>
-#include <linux/spinlock.h>
-#include <linux/syscore_ops.h>
-
-#include "core.h"
-#include "pinctrl-samsung.h"
-
-#define GROUP_SUFFIX           "-grp"
-#define GSUFFIX_LEN            sizeof(GROUP_SUFFIX)
-#define FUNCTION_SUFFIX                "-mux"
-#define FSUFFIX_LEN            sizeof(FUNCTION_SUFFIX)
-
-/* list of all possible config options supported */
-static struct pin_config {
-       const char *property;
-       enum pincfg_type param;
-} cfg_params[] = {
-       { "samsung,pin-pud", PINCFG_TYPE_PUD },
-       { "samsung,pin-drv", PINCFG_TYPE_DRV },
-       { "samsung,pin-con-pdn", PINCFG_TYPE_CON_PDN },
-       { "samsung,pin-pud-pdn", PINCFG_TYPE_PUD_PDN },
-       { "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 inline struct samsung_pin_bank *gc_to_pin_bank(struct gpio_chip *gc)
-{
-       return container_of(gc, struct samsung_pin_bank, gpio_chip);
-}
-
-static int samsung_get_group_count(struct pinctrl_dev *pctldev)
-{
-       struct samsung_pinctrl_drv_data *pmx = pinctrl_dev_get_drvdata(pctldev);
-
-       return pmx->nr_groups;
-}
-
-static const char *samsung_get_group_name(struct pinctrl_dev *pctldev,
-                                               unsigned group)
-{
-       struct samsung_pinctrl_drv_data *pmx = pinctrl_dev_get_drvdata(pctldev);
-
-       return pmx->pin_groups[group].name;
-}
-
-static int samsung_get_group_pins(struct pinctrl_dev *pctldev,
-                                       unsigned group,
-                                       const unsigned **pins,
-                                       unsigned *num_pins)
-{
-       struct samsung_pinctrl_drv_data *pmx = pinctrl_dev_get_drvdata(pctldev);
-
-       *pins = pmx->pin_groups[group].pins;
-       *num_pins = pmx->pin_groups[group].num_pins;
-
-       return 0;
-}
-
-static int reserve_map(struct device *dev, struct pinctrl_map **map,
-                      unsigned *reserved_maps, unsigned *num_maps,
-                      unsigned reserve)
-{
-       unsigned old_num = *reserved_maps;
-       unsigned new_num = *num_maps + reserve;
-       struct pinctrl_map *new_map;
-
-       if (old_num >= new_num)
-               return 0;
-
-       new_map = krealloc(*map, sizeof(*new_map) * new_num, GFP_KERNEL);
-       if (!new_map) {
-               dev_err(dev, "krealloc(map) failed\n");
-               return -ENOMEM;
-       }
-
-       memset(new_map + old_num, 0, (new_num - old_num) * sizeof(*new_map));
-
-       *map = new_map;
-       *reserved_maps = new_num;
-
-       return 0;
-}
-
-static int add_map_mux(struct pinctrl_map **map, unsigned *reserved_maps,
-                      unsigned *num_maps, const char *group,
-                      const char *function)
-{
-       if (WARN_ON(*num_maps == *reserved_maps))
-               return -ENOSPC;
-
-       (*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP;
-       (*map)[*num_maps].data.mux.group = group;
-       (*map)[*num_maps].data.mux.function = function;
-       (*num_maps)++;
-
-       return 0;
-}
-
-static int add_map_configs(struct device *dev, struct pinctrl_map **map,
-                          unsigned *reserved_maps, unsigned *num_maps,
-                          const char *group, unsigned long *configs,
-                          unsigned num_configs)
-{
-       unsigned long *dup_configs;
-
-       if (WARN_ON(*num_maps == *reserved_maps))
-               return -ENOSPC;
-
-       dup_configs = kmemdup(configs, num_configs * sizeof(*dup_configs),
-                             GFP_KERNEL);
-       if (!dup_configs) {
-               dev_err(dev, "kmemdup(configs) failed\n");
-               return -ENOMEM;
-       }
-
-       (*map)[*num_maps].type = PIN_MAP_TYPE_CONFIGS_GROUP;
-       (*map)[*num_maps].data.configs.group_or_pin = group;
-       (*map)[*num_maps].data.configs.configs = dup_configs;
-       (*map)[*num_maps].data.configs.num_configs = num_configs;
-       (*num_maps)++;
-
-       return 0;
-}
-
-static int add_config(struct device *dev, unsigned long **configs,
-                     unsigned *num_configs, unsigned long config)
-{
-       unsigned old_num = *num_configs;
-       unsigned new_num = old_num + 1;
-       unsigned long *new_configs;
-
-       new_configs = krealloc(*configs, sizeof(*new_configs) * new_num,
-                              GFP_KERNEL);
-       if (!new_configs) {
-               dev_err(dev, "krealloc(configs) failed\n");
-               return -ENOMEM;
-       }
-
-       new_configs[old_num] = config;
-
-       *configs = new_configs;
-       *num_configs = new_num;
-
-       return 0;
-}
-
-static void samsung_dt_free_map(struct pinctrl_dev *pctldev,
-                                     struct pinctrl_map *map,
-                                     unsigned num_maps)
-{
-       int i;
-
-       for (i = 0; i < num_maps; i++)
-               if (map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP)
-                       kfree(map[i].data.configs.configs);
-
-       kfree(map);
-}
-
-static int samsung_dt_subnode_to_map(struct samsung_pinctrl_drv_data *drvdata,
-                                    struct device *dev,
-                                    struct device_node *np,
-                                    struct pinctrl_map **map,
-                                    unsigned *reserved_maps,
-                                    unsigned *num_maps)
-{
-       int ret, i;
-       u32 val;
-       unsigned long config;
-       unsigned long *configs = NULL;
-       unsigned num_configs = 0;
-       unsigned reserve;
-       struct property *prop;
-       const char *group;
-       bool has_func = false;
-
-       ret = of_property_read_u32(np, "samsung,pin-function", &val);
-       if (!ret)
-               has_func = true;
-
-       for (i = 0; i < ARRAY_SIZE(cfg_params); i++) {
-               ret = of_property_read_u32(np, cfg_params[i].property, &val);
-               if (!ret) {
-                       config = PINCFG_PACK(cfg_params[i].param, val);
-                       ret = add_config(dev, &configs, &num_configs, config);
-                       if (ret < 0)
-                               goto exit;
-               /* EINVAL=missing, which is fine since it's optional */
-               } else if (ret != -EINVAL) {
-                       dev_err(dev, "could not parse property %s\n",
-                               cfg_params[i].property);
-               }
-       }
-
-       reserve = 0;
-       if (has_func)
-               reserve++;
-       if (num_configs)
-               reserve++;
-       ret = of_property_count_strings(np, "samsung,pins");
-       if (ret < 0) {
-               dev_err(dev, "could not parse property samsung,pins\n");
-               goto exit;
-       }
-       reserve *= ret;
-
-       ret = reserve_map(dev, map, reserved_maps, num_maps, reserve);
-       if (ret < 0)
-               goto exit;
-
-       of_property_for_each_string(np, "samsung,pins", prop, group) {
-               if (has_func) {
-                       ret = add_map_mux(map, reserved_maps,
-                                               num_maps, group, np->full_name);
-                       if (ret < 0)
-                               goto exit;
-               }
-
-               if (num_configs) {
-                       ret = add_map_configs(dev, map, reserved_maps,
-                                             num_maps, group, configs,
-                                             num_configs);
-                       if (ret < 0)
-                               goto exit;
-               }
-       }
-
-       ret = 0;
-
-exit:
-       kfree(configs);
-       return ret;
-}
-
-static int samsung_dt_node_to_map(struct pinctrl_dev *pctldev,
-                                       struct device_node *np_config,
-                                       struct pinctrl_map **map,
-                                       unsigned *num_maps)
-{
-       struct samsung_pinctrl_drv_data *drvdata;
-       unsigned reserved_maps;
-       struct device_node *np;
-       int ret;
-
-       drvdata = pinctrl_dev_get_drvdata(pctldev);
-
-       reserved_maps = 0;
-       *map = NULL;
-       *num_maps = 0;
-
-       if (!of_get_child_count(np_config))
-               return samsung_dt_subnode_to_map(drvdata, pctldev->dev,
-                                                       np_config, map,
-                                                       &reserved_maps,
-                                                       num_maps);
-
-       for_each_child_of_node(np_config, np) {
-               ret = samsung_dt_subnode_to_map(drvdata, pctldev->dev, np, map,
-                                               &reserved_maps, num_maps);
-               if (ret < 0) {
-                       samsung_dt_free_map(pctldev, *map, *num_maps);
-                       return ret;
-               }
-       }
-
-       return 0;
-}
-
-/* list of pinctrl callbacks for the pinctrl core */
-static const struct pinctrl_ops samsung_pctrl_ops = {
-       .get_groups_count       = samsung_get_group_count,
-       .get_group_name         = samsung_get_group_name,
-       .get_group_pins         = samsung_get_group_pins,
-       .dt_node_to_map         = samsung_dt_node_to_map,
-       .dt_free_map            = samsung_dt_free_map,
-};
-
-/* check if the selector is a valid pin function selector */
-static int samsung_get_functions_count(struct pinctrl_dev *pctldev)
-{
-       struct samsung_pinctrl_drv_data *drvdata;
-
-       drvdata = pinctrl_dev_get_drvdata(pctldev);
-       return drvdata->nr_functions;
-}
-
-/* return the name of the pin function specified */
-static const char *samsung_pinmux_get_fname(struct pinctrl_dev *pctldev,
-                                               unsigned selector)
-{
-       struct samsung_pinctrl_drv_data *drvdata;
-
-       drvdata = pinctrl_dev_get_drvdata(pctldev);
-       return drvdata->pmx_functions[selector].name;
-}
-
-/* return the groups associated for the specified function selector */
-static int samsung_pinmux_get_groups(struct pinctrl_dev *pctldev,
-               unsigned selector, const char * const **groups,
-               unsigned * const num_groups)
-{
-       struct samsung_pinctrl_drv_data *drvdata;
-
-       drvdata = pinctrl_dev_get_drvdata(pctldev);
-       *groups = drvdata->pmx_functions[selector].groups;
-       *num_groups = drvdata->pmx_functions[selector].num_groups;
-       return 0;
-}
-
-/*
- * given a pin number that is local to a pin controller, find out the pin bank
- * and the register base of the pin bank.
- */
-static void pin_to_reg_bank(struct samsung_pinctrl_drv_data *drvdata,
-                       unsigned pin, void __iomem **reg, u32 *offset,
-                       struct samsung_pin_bank **bank)
-{
-       struct samsung_pin_bank *b;
-
-       b = drvdata->ctrl->pin_banks;
-
-       while ((pin >= b->pin_base) &&
-                       ((b->pin_base + b->nr_pins - 1) < pin))
-               b++;
-
-       *reg = drvdata->virt_base + b->pctl_offset;
-       *offset = pin - b->pin_base;
-       if (bank)
-               *bank = b;
-}
-
-/* enable or disable a pinmux function */
-static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector,
-                                       unsigned group, bool enable)
-{
-       struct samsung_pinctrl_drv_data *drvdata;
-       struct samsung_pin_bank_type *type;
-       struct samsung_pin_bank *bank;
-       void __iomem *reg;
-       u32 mask, shift, data, pin_offset;
-       unsigned long flags;
-       const struct samsung_pmx_func *func;
-       const struct samsung_pin_group *grp;
-
-       drvdata = pinctrl_dev_get_drvdata(pctldev);
-       func = &drvdata->pmx_functions[selector];
-       grp = &drvdata->pin_groups[group];
-
-       pin_to_reg_bank(drvdata, grp->pins[0] - drvdata->ctrl->base,
-                       &reg, &pin_offset, &bank);
-       type = bank->type;
-       mask = (1 << type->fld_width[PINCFG_TYPE_FUNC]) - 1;
-       shift = pin_offset * type->fld_width[PINCFG_TYPE_FUNC];
-       if (shift >= 32) {
-               /* Some banks have two config registers */
-               shift -= 32;
-               reg += 4;
-       }
-
-       spin_lock_irqsave(&bank->slock, flags);
-
-       data = readl(reg + type->reg_offset[PINCFG_TYPE_FUNC]);
-       data &= ~(mask << shift);
-       if (enable)
-               data |= func->val << shift;
-       writel(data, reg + type->reg_offset[PINCFG_TYPE_FUNC]);
-
-       spin_unlock_irqrestore(&bank->slock, flags);
-}
-
-/* enable a specified pinmux by writing to registers */
-static int samsung_pinmux_enable(struct pinctrl_dev *pctldev, unsigned selector,
-                                       unsigned group)
-{
-       samsung_pinmux_setup(pctldev, selector, group, true);
-       return 0;
-}
-
-/* list of pinmux callbacks for the pinmux vertical in pinctrl core */
-static const struct pinmux_ops samsung_pinmux_ops = {
-       .get_functions_count    = samsung_get_functions_count,
-       .get_function_name      = samsung_pinmux_get_fname,
-       .get_function_groups    = samsung_pinmux_get_groups,
-       .enable                 = samsung_pinmux_enable,
-};
-
-/* set or get the pin config settings for a specified pin */
-static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin,
-                               unsigned long *config, bool set)
-{
-       struct samsung_pinctrl_drv_data *drvdata;
-       struct samsung_pin_bank_type *type;
-       struct samsung_pin_bank *bank;
-       void __iomem *reg_base;
-       enum pincfg_type cfg_type = PINCFG_UNPACK_TYPE(*config);
-       u32 data, width, pin_offset, mask, shift;
-       u32 cfg_value, cfg_reg;
-       unsigned long flags;
-
-       drvdata = pinctrl_dev_get_drvdata(pctldev);
-       pin_to_reg_bank(drvdata, pin - drvdata->ctrl->base, &reg_base,
-                                       &pin_offset, &bank);
-       type = bank->type;
-
-       if (cfg_type >= PINCFG_TYPE_NUM || !type->fld_width[cfg_type])
-               return -EINVAL;
-
-       width = type->fld_width[cfg_type];
-       cfg_reg = type->reg_offset[cfg_type];
-
-       spin_lock_irqsave(&bank->slock, flags);
-
-       mask = (1 << width) - 1;
-       shift = pin_offset * width;
-       data = readl(reg_base + cfg_reg);
-
-       if (set) {
-               cfg_value = PINCFG_UNPACK_VALUE(*config);
-               data &= ~(mask << shift);
-               data |= (cfg_value << shift);
-               writel(data, reg_base + cfg_reg);
-       } else {
-               data >>= shift;
-               data &= mask;
-               *config = PINCFG_PACK(cfg_type, data);
-       }
-
-       spin_unlock_irqrestore(&bank->slock, flags);
-
-       return 0;
-}
-
-/* set the pin config settings for a specified pin */
-static int samsung_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
-                               unsigned long *configs, unsigned num_configs)
-{
-       int i, ret;
-
-       for (i = 0; i < num_configs; i++) {
-               ret = samsung_pinconf_rw(pctldev, pin, &configs[i], true);
-               if (ret < 0)
-                       return ret;
-       } /* for each config */
-
-       return 0;
-}
-
-/* get the pin config settings for a specified pin */
-static int samsung_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin,
-                                       unsigned long *config)
-{
-       return samsung_pinconf_rw(pctldev, pin, config, false);
-}
-
-/* set the pin config settings for a specified pin group */
-static int samsung_pinconf_group_set(struct pinctrl_dev *pctldev,
-                       unsigned group, unsigned long *configs,
-                       unsigned num_configs)
-{
-       struct samsung_pinctrl_drv_data *drvdata;
-       const unsigned int *pins;
-       unsigned int cnt;
-
-       drvdata = pinctrl_dev_get_drvdata(pctldev);
-       pins = drvdata->pin_groups[group].pins;
-
-       for (cnt = 0; cnt < drvdata->pin_groups[group].num_pins; cnt++)
-               samsung_pinconf_set(pctldev, pins[cnt], configs, num_configs);
-
-       return 0;
-}
-
-/* get the pin config settings for a specified pin group */
-static int samsung_pinconf_group_get(struct pinctrl_dev *pctldev,
-                               unsigned int group, unsigned long *config)
-{
-       struct samsung_pinctrl_drv_data *drvdata;
-       const unsigned int *pins;
-
-       drvdata = pinctrl_dev_get_drvdata(pctldev);
-       pins = drvdata->pin_groups[group].pins;
-       samsung_pinconf_get(pctldev, pins[0], config);
-       return 0;
-}
-
-/* list of pinconfig callbacks for pinconfig vertical in the pinctrl code */
-static const struct pinconf_ops samsung_pinconf_ops = {
-       .pin_config_get         = samsung_pinconf_get,
-       .pin_config_set         = samsung_pinconf_set,
-       .pin_config_group_get   = samsung_pinconf_group_get,
-       .pin_config_group_set   = samsung_pinconf_group_set,
-};
-
-/* gpiolib gpio_set callback function */
-static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
-{
-       struct samsung_pin_bank *bank = gc_to_pin_bank(gc);
-       struct samsung_pin_bank_type *type = bank->type;
-       unsigned long flags;
-       void __iomem *reg;
-       u32 data;
-
-       reg = bank->drvdata->virt_base + bank->pctl_offset;
-
-       spin_lock_irqsave(&bank->slock, flags);
-
-       data = readl(reg + type->reg_offset[PINCFG_TYPE_DAT]);
-       data &= ~(1 << offset);
-       if (value)
-               data |= 1 << offset;
-       writel(data, reg + type->reg_offset[PINCFG_TYPE_DAT]);
-
-       spin_unlock_irqrestore(&bank->slock, flags);
-}
-
-/* gpiolib gpio_get callback function */
-static int samsung_gpio_get(struct gpio_chip *gc, unsigned offset)
-{
-       void __iomem *reg;
-       u32 data;
-       struct samsung_pin_bank *bank = gc_to_pin_bank(gc);
-       struct samsung_pin_bank_type *type = bank->type;
-
-       reg = bank->drvdata->virt_base + bank->pctl_offset;
-
-       data = readl(reg + type->reg_offset[PINCFG_TYPE_DAT]);
-       data >>= offset;
-       data &= 1;
-       return data;
-}
-
-/*
- * The calls to gpio_direction_output() and gpio_direction_input()
- * leads to this function call.
- */
-static int samsung_gpio_set_direction(struct gpio_chip *gc,
-                                            unsigned offset, bool input)
-{
-       struct samsung_pin_bank_type *type;
-       struct samsung_pin_bank *bank;
-       struct samsung_pinctrl_drv_data *drvdata;
-       void __iomem *reg;
-       u32 data, mask, shift;
-       unsigned long flags;
-
-       bank = gc_to_pin_bank(gc);
-       type = bank->type;
-       drvdata = bank->drvdata;
-
-       reg = drvdata->virt_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];
-       if (shift >= 32) {
-               /* Some banks have two config registers */
-               shift -= 32;
-               reg += 4;
-       }
-
-       spin_lock_irqsave(&bank->slock, flags);
-
-       data = readl(reg);
-       data &= ~(mask << shift);
-       if (!input)
-               data |= FUNC_OUTPUT << shift;
-       writel(data, reg);
-
-       spin_unlock_irqrestore(&bank->slock, flags);
-
-       return 0;
-}
-
-/* gpiolib gpio_direction_input callback function. */
-static int samsung_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
-{
-       return samsung_gpio_set_direction(gc, offset, true);
-}
-
-/* gpiolib gpio_direction_output callback function. */
-static int samsung_gpio_direction_output(struct gpio_chip *gc, unsigned offset,
-                                                       int value)
-{
-       samsung_gpio_set(gc, offset, value);
-       return samsung_gpio_set_direction(gc, offset, false);
-}
-
-/*
- * gpiolib gpio_to_irq callback function. Creates a mapping between a GPIO pin
- * and a virtual IRQ, if not already present.
- */
-static int samsung_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
-{
-       struct samsung_pin_bank *bank = gc_to_pin_bank(gc);
-       unsigned int virq;
-
-       if (!bank->irq_domain)
-               return -ENXIO;
-
-       virq = irq_create_mapping(bank->irq_domain, offset);
-
-       return (virq) ? : -ENXIO;
-}
-
-static struct samsung_pin_group *samsung_pinctrl_create_groups(
-                               struct device *dev,
-                               struct samsung_pinctrl_drv_data *drvdata,
-                               unsigned int *cnt)
-{
-       struct pinctrl_desc *ctrldesc = &drvdata->pctl;
-       struct samsung_pin_group *groups, *grp;
-       const struct pinctrl_pin_desc *pdesc;
-       int i;
-
-       groups = devm_kzalloc(dev, ctrldesc->npins * sizeof(*groups),
-                               GFP_KERNEL);
-       if (!groups)
-               return ERR_PTR(-EINVAL);
-       grp = groups;
-
-       pdesc = ctrldesc->pins;
-       for (i = 0; i < ctrldesc->npins; ++i, ++pdesc, ++grp) {
-               grp->name = pdesc->name;
-               grp->pins = &pdesc->number;
-               grp->num_pins = 1;
-       }
-
-       *cnt = ctrldesc->npins;
-       return groups;
-}
-
-static int samsung_pinctrl_create_function(struct device *dev,
-                               struct samsung_pinctrl_drv_data *drvdata,
-                               struct device_node *func_np,
-                               struct samsung_pmx_func *func)
-{
-       int npins;
-       int ret;
-       int i;
-
-       if (of_property_read_u32(func_np, "samsung,pin-function", &func->val))
-               return 0;
-
-       npins = of_property_count_strings(func_np, "samsung,pins");
-       if (npins < 1) {
-               dev_err(dev, "invalid pin list in %s node", func_np->name);
-               return -EINVAL;
-       }
-
-       func->name = func_np->full_name;
-
-       func->groups = devm_kzalloc(dev, npins * sizeof(char *), GFP_KERNEL);
-       if (!func->groups)
-               return -ENOMEM;
-
-       for (i = 0; i < npins; ++i) {
-               const char *gname;
-
-               ret = of_property_read_string_index(func_np, "samsung,pins",
-                                                       i, &gname);
-               if (ret) {
-                       dev_err(dev,
-                               "failed to read pin name %d from %s node\n",
-                               i, func_np->name);
-                       return ret;
-               }
-
-               func->groups[i] = gname;
-       }
-
-       func->num_groups = npins;
-       return 1;
-}
-
-static struct samsung_pmx_func *samsung_pinctrl_create_functions(
-                               struct device *dev,
-                               struct samsung_pinctrl_drv_data *drvdata,
-                               unsigned int *cnt)
-{
-       struct samsung_pmx_func *functions, *func;
-       struct device_node *dev_np = dev->of_node;
-       struct device_node *cfg_np;
-       unsigned int func_cnt = 0;
-       int ret;
-
-       /*
-        * Iterate over all the child nodes of the pin controller node
-        * and create pin groups and pin function lists.
-        */
-       for_each_child_of_node(dev_np, cfg_np) {
-               struct device_node *func_np;
-
-               if (!of_get_child_count(cfg_np)) {
-                       if (!of_find_property(cfg_np,
-                           "samsung,pin-function", NULL))
-                               continue;
-                       ++func_cnt;
-                       continue;
-               }
-
-               for_each_child_of_node(cfg_np, func_np) {
-                       if (!of_find_property(func_np,
-                           "samsung,pin-function", NULL))
-                               continue;
-                       ++func_cnt;
-               }
-       }
-
-       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);
-       }
-       func = functions;
-
-       /*
-        * Iterate over all the child nodes of the pin controller node
-        * and create pin groups and pin function lists.
-        */
-       func_cnt = 0;
-       for_each_child_of_node(dev_np, cfg_np) {
-               struct device_node *func_np;
-
-               if (!of_get_child_count(cfg_np)) {
-                       ret = samsung_pinctrl_create_function(dev, drvdata,
-                                                       cfg_np, func);
-                       if (ret < 0)
-                               return ERR_PTR(ret);
-                       if (ret > 0) {
-                               ++func;
-                               ++func_cnt;
-                       }
-                       continue;
-               }
-
-               for_each_child_of_node(cfg_np, func_np) {
-                       ret = samsung_pinctrl_create_function(dev, drvdata,
-                                               func_np, func);
-                       if (ret < 0)
-                               return ERR_PTR(ret);
-                       if (ret > 0) {
-                               ++func;
-                               ++func_cnt;
-                       }
-               }
-       }
-
-       *cnt = func_cnt;
-       return functions;
-}
-
-/*
- * Parse the information about all the available pin groups and pin functions
- * from device node of the pin-controller. A pin group is formed with all
- * the pins listed in the "samsung,pins" property.
- */
-
-static int samsung_pinctrl_parse_dt(struct platform_device *pdev,
-                                   struct samsung_pinctrl_drv_data *drvdata)
-{
-       struct device *dev = &pdev->dev;
-       struct samsung_pin_group *groups;
-       struct samsung_pmx_func *functions;
-       unsigned int grp_cnt = 0, func_cnt = 0;
-
-       groups = samsung_pinctrl_create_groups(dev, drvdata, &grp_cnt);
-       if (IS_ERR(groups)) {
-               dev_err(dev, "failed to parse pin groups\n");
-               return PTR_ERR(groups);
-       }
-
-       functions = samsung_pinctrl_create_functions(dev, drvdata, &func_cnt);
-       if (IS_ERR(functions)) {
-               dev_err(dev, "failed to parse pin functions\n");
-               return PTR_ERR(groups);
-       }
-
-       drvdata->pin_groups = groups;
-       drvdata->nr_groups = grp_cnt;
-       drvdata->pmx_functions = functions;
-       drvdata->nr_functions = func_cnt;
-
-       return 0;
-}
-
-/* register the pinctrl interface with the pinctrl subsystem */
-static int samsung_pinctrl_register(struct platform_device *pdev,
-                                   struct samsung_pinctrl_drv_data *drvdata)
-{
-       struct pinctrl_desc *ctrldesc = &drvdata->pctl;
-       struct pinctrl_pin_desc *pindesc, *pdesc;
-       struct samsung_pin_bank *pin_bank;
-       char *pin_names;
-       int pin, bank, ret;
-
-       ctrldesc->name = "samsung-pinctrl";
-       ctrldesc->owner = THIS_MODULE;
-       ctrldesc->pctlops = &samsung_pctrl_ops;
-       ctrldesc->pmxops = &samsung_pinmux_ops;
-       ctrldesc->confops = &samsung_pinconf_ops;
-
-       pindesc = devm_kzalloc(&pdev->dev, sizeof(*pindesc) *
-                       drvdata->ctrl->nr_pins, GFP_KERNEL);
-       if (!pindesc) {
-               dev_err(&pdev->dev, "mem alloc for pin descriptors failed\n");
-               return -ENOMEM;
-       }
-       ctrldesc->pins = pindesc;
-       ctrldesc->npins = drvdata->ctrl->nr_pins;
-
-       /* dynamically populate the pin number and pin name for pindesc */
-       for (pin = 0, pdesc = pindesc; pin < ctrldesc->npins; pin++, pdesc++)
-               pdesc->number = pin + drvdata->ctrl->base;
-
-       /*
-        * allocate space for storing the dynamically generated names for all
-        * the pins which belong to this pin-controller.
-        */
-       pin_names = devm_kzalloc(&pdev->dev, sizeof(char) * PIN_NAME_LENGTH *
-                                       drvdata->ctrl->nr_pins, GFP_KERNEL);
-       if (!pin_names) {
-               dev_err(&pdev->dev, "mem alloc for pin names failed\n");
-               return -ENOMEM;
-       }
-
-       /* for each pin, the name of the pin is pin-bank name + pin number */
-       for (bank = 0; bank < drvdata->ctrl->nr_banks; bank++) {
-               pin_bank = &drvdata->ctrl->pin_banks[bank];
-               for (pin = 0; pin < pin_bank->nr_pins; pin++) {
-                       sprintf(pin_names, "%s-%d", pin_bank->name, pin);
-                       pdesc = pindesc + pin_bank->pin_base + pin;
-                       pdesc->name = pin_names;
-                       pin_names += PIN_NAME_LENGTH;
-               }
-       }
-
-       ret = samsung_pinctrl_parse_dt(pdev, drvdata);
-       if (ret)
-               return ret;
-
-       drvdata->pctl_dev = pinctrl_register(ctrldesc, &pdev->dev, drvdata);
-       if (!drvdata->pctl_dev) {
-               dev_err(&pdev->dev, "could not register pinctrl driver\n");
-               return -EINVAL;
-       }
-
-       for (bank = 0; bank < drvdata->ctrl->nr_banks; ++bank) {
-               pin_bank = &drvdata->ctrl->pin_banks[bank];
-               pin_bank->grange.name = pin_bank->name;
-               pin_bank->grange.id = bank;
-               pin_bank->grange.pin_base = drvdata->ctrl->base
-                                               + pin_bank->pin_base;
-               pin_bank->grange.base = pin_bank->gpio_chip.base;
-               pin_bank->grange.npins = pin_bank->gpio_chip.ngpio;
-               pin_bank->grange.gc = &pin_bank->gpio_chip;
-               pinctrl_add_gpio_range(drvdata->pctl_dev, &pin_bank->grange);
-       }
-
-       return 0;
-}
-
-static int samsung_gpio_request(struct gpio_chip *chip, unsigned offset)
-{
-       return pinctrl_request_gpio(chip->base + offset);
-}
-
-static void samsung_gpio_free(struct gpio_chip *chip, unsigned offset)
-{
-       pinctrl_free_gpio(chip->base + offset);
-}
-
-static const struct gpio_chip samsung_gpiolib_chip = {
-       .request = samsung_gpio_request,
-       .free = samsung_gpio_free,
-       .set = samsung_gpio_set,
-       .get = samsung_gpio_get,
-       .direction_input = samsung_gpio_direction_input,
-       .direction_output = samsung_gpio_direction_output,
-       .to_irq = samsung_gpio_to_irq,
-       .owner = THIS_MODULE,
-};
-
-/* register the gpiolib interface with the gpiolib subsystem */
-static int samsung_gpiolib_register(struct platform_device *pdev,
-                                   struct samsung_pinctrl_drv_data *drvdata)
-{
-       struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
-       struct samsung_pin_bank *bank = ctrl->pin_banks;
-       struct gpio_chip *gc;
-       int ret;
-       int i;
-
-       for (i = 0; i < ctrl->nr_banks; ++i, ++bank) {
-               bank->gpio_chip = samsung_gpiolib_chip;
-
-               gc = &bank->gpio_chip;
-               gc->base = ctrl->base + bank->pin_base;
-               gc->ngpio = bank->nr_pins;
-               gc->dev = &pdev->dev;
-               gc->of_node = bank->of_node;
-               gc->label = bank->name;
-
-               ret = gpiochip_add(gc);
-               if (ret) {
-                       dev_err(&pdev->dev, "failed to register gpio_chip %s, error code: %d\n",
-                                                       gc->label, ret);
-                       goto fail;
-               }
-       }
-
-       return 0;
-
-fail:
-       for (--i, --bank; i >= 0; --i, --bank)
-               if (gpiochip_remove(&bank->gpio_chip))
-                       dev_err(&pdev->dev, "gpio chip %s remove failed\n",
-                                                       bank->gpio_chip.label);
-       return ret;
-}
-
-/* unregister the gpiolib interface with the gpiolib subsystem */
-static int samsung_gpiolib_unregister(struct platform_device *pdev,
-                                     struct samsung_pinctrl_drv_data *drvdata)
-{
-       struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
-       struct samsung_pin_bank *bank = ctrl->pin_banks;
-       int ret = 0;
-       int i;
-
-       for (i = 0; !ret && i < ctrl->nr_banks; ++i, ++bank)
-               ret = gpiochip_remove(&bank->gpio_chip);
-
-       if (ret)
-               dev_err(&pdev->dev, "gpio chip remove failed\n");
-
-       return ret;
-}
-
-static const struct of_device_id samsung_pinctrl_dt_match[];
-
-/* retrieve the soc specific data */
-static 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;
-       struct samsung_pin_ctrl *ctrl;
-       struct samsung_pin_bank *bank;
-       int i;
-
-       id = of_alias_get_id(node, "pinctrl");
-       if (id < 0) {
-               dev_err(&pdev->dev, "failed to get alias id\n");
-               return NULL;
-       }
-       match = of_match_node(samsung_pinctrl_dt_match, node);
-       ctrl = (struct samsung_pin_ctrl *)match->data + id;
-
-       bank = ctrl->pin_banks;
-       for (i = 0; i < ctrl->nr_banks; ++i, ++bank) {
-               spin_lock_init(&bank->slock);
-               bank->drvdata = d;
-               bank->pin_base = ctrl->nr_pins;
-               ctrl->nr_pins += bank->nr_pins;
-       }
-
-       for_each_child_of_node(node, np) {
-               if (!of_find_property(np, "gpio-controller", NULL))
-                       continue;
-               bank = ctrl->pin_banks;
-               for (i = 0; i < ctrl->nr_banks; ++i, ++bank) {
-                       if (!strcmp(bank->name, np->name)) {
-                               bank->of_node = np;
-                               break;
-                       }
-               }
-       }
-
-       ctrl->base = pin_base;
-       pin_base += ctrl->nr_pins;
-
-       return ctrl;
-}
-
-static int samsung_pinctrl_probe(struct platform_device *pdev)
-{
-       struct samsung_pinctrl_drv_data *drvdata;
-       struct device *dev = &pdev->dev;
-       struct samsung_pin_ctrl *ctrl;
-       struct resource *res;
-       int ret;
-
-       if (!dev->of_node) {
-               dev_err(dev, "device tree node not found\n");
-               return -ENODEV;
-       }
-
-       drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
-       if (!drvdata) {
-               dev_err(dev, "failed to allocate memory for driver's "
-                               "private data\n");
-               return -ENOMEM;
-       }
-
-       ctrl = samsung_pinctrl_get_soc_data(drvdata, pdev);
-       if (!ctrl) {
-               dev_err(&pdev->dev, "driver data not available\n");
-               return -EINVAL;
-       }
-       drvdata->ctrl = ctrl;
-       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;
-
-       ret = samsung_gpiolib_register(pdev, drvdata);
-       if (ret)
-               return ret;
-
-       ret = samsung_pinctrl_register(pdev, drvdata);
-       if (ret) {
-               samsung_gpiolib_unregister(pdev, drvdata);
-               return ret;
-       }
-
-       if (ctrl->eint_gpio_init)
-               ctrl->eint_gpio_init(drvdata);
-       if (ctrl->eint_wkup_init)
-               ctrl->eint_wkup_init(drvdata);
-
-       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
- *
- * Save data for all banks handled by this device.
- */
-static void samsung_pinctrl_suspend_dev(
-       struct samsung_pinctrl_drv_data *drvdata)
-{
-       struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
-       void __iomem *virt_base = drvdata->virt_base;
-       int i;
-
-       for (i = 0; i < ctrl->nr_banks; i++) {
-               struct samsung_pin_bank *bank = &ctrl->pin_banks[i];
-               void __iomem *reg = virt_base + bank->pctl_offset;
-
-               u8 *offs = bank->type->reg_offset;
-               u8 *widths = bank->type->fld_width;
-               enum pincfg_type type;
-
-               /* Registers without a powerdown config aren't lost */
-               if (!widths[PINCFG_TYPE_CON_PDN])
-                       continue;
-
-               for (type = 0; type < PINCFG_TYPE_NUM; type++)
-                       if (widths[type])
-                               bank->pm_save[type] = readl(reg + offs[type]);
-
-               if (widths[PINCFG_TYPE_FUNC] * bank->nr_pins > 32) {
-                       /* Some banks have two config registers */
-                       bank->pm_save[PINCFG_TYPE_NUM] =
-                               readl(reg + offs[PINCFG_TYPE_FUNC] + 4);
-                       pr_debug("Save %s @ %p (con %#010x %08x)\n",
-                                bank->name, reg,
-                                bank->pm_save[PINCFG_TYPE_FUNC],
-                                bank->pm_save[PINCFG_TYPE_NUM]);
-               } else {
-                       pr_debug("Save %s @ %p (con %#010x)\n", bank->name,
-                                reg, bank->pm_save[PINCFG_TYPE_FUNC]);
-               }
-       }
-
-       if (ctrl->suspend)
-               ctrl->suspend(drvdata);
-}
-
-/**
- * samsung_pinctrl_resume_dev - restore pinctrl state from suspend for a device
- *
- * 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)
-{
-       struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
-       void __iomem *virt_base = drvdata->virt_base;
-       int i;
-
-       if (ctrl->resume)
-               ctrl->resume(drvdata);
-
-       for (i = 0; i < ctrl->nr_banks; i++) {
-               struct samsung_pin_bank *bank = &ctrl->pin_banks[i];
-               void __iomem *reg = virt_base + bank->pctl_offset;
-
-               u8 *offs = bank->type->reg_offset;
-               u8 *widths = bank->type->fld_width;
-               enum pincfg_type type;
-
-               /* Registers without a powerdown config aren't lost */
-               if (!widths[PINCFG_TYPE_CON_PDN])
-                       continue;
-
-               if (widths[PINCFG_TYPE_FUNC] * bank->nr_pins > 32) {
-                       /* Some banks have two config registers */
-                       pr_debug("%s @ %p (con %#010x %08x => %#010x %08x)\n",
-                                bank->name, reg,
-                                readl(reg + offs[PINCFG_TYPE_FUNC]),
-                                readl(reg + offs[PINCFG_TYPE_FUNC] + 4),
-                                bank->pm_save[PINCFG_TYPE_FUNC],
-                                bank->pm_save[PINCFG_TYPE_NUM]);
-                       writel(bank->pm_save[PINCFG_TYPE_NUM],
-                              reg + offs[PINCFG_TYPE_FUNC] + 4);
-               } else {
-                       pr_debug("%s @ %p (con %#010x => %#010x)\n", bank->name,
-                                reg, readl(reg + offs[PINCFG_TYPE_FUNC]),
-                                bank->pm_save[PINCFG_TYPE_FUNC]);
-               }
-               for (type = 0; type < PINCFG_TYPE_NUM; type++)
-                       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);
-       }
-
-       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",
-               .data = (void *)exynos3250_pin_ctrl },
-       { .compatible = "samsung,exynos4210-pinctrl",
-               .data = (void *)exynos4210_pin_ctrl },
-       { .compatible = "samsung,exynos4x12-pinctrl",
-               .data = (void *)exynos4x12_pin_ctrl },
-       { .compatible = "samsung,exynos5250-pinctrl",
-               .data = (void *)exynos5250_pin_ctrl },
-       { .compatible = "samsung,exynos5260-pinctrl",
-               .data = (void *)exynos5260_pin_ctrl },
-       { .compatible = "samsung,exynos5420-pinctrl",
-               .data = (void *)exynos5420_pin_ctrl },
-       { .compatible = "samsung,s5pv210-pinctrl",
-               .data = (void *)s5pv210_pin_ctrl },
-#endif
-#ifdef CONFIG_PINCTRL_S3C64XX
-       { .compatible = "samsung,s3c64xx-pinctrl",
-               .data = s3c64xx_pin_ctrl },
-#endif
-#ifdef CONFIG_PINCTRL_S3C24XX
-       { .compatible = "samsung,s3c2412-pinctrl",
-               .data = s3c2412_pin_ctrl },
-       { .compatible = "samsung,s3c2416-pinctrl",
-               .data = s3c2416_pin_ctrl },
-       { .compatible = "samsung,s3c2440-pinctrl",
-               .data = s3c2440_pin_ctrl },
-       { .compatible = "samsung,s3c2450-pinctrl",
-               .data = s3c2450_pin_ctrl },
-#endif
-       {},
-};
-MODULE_DEVICE_TABLE(of, samsung_pinctrl_dt_match);
-
-static struct platform_driver samsung_pinctrl_driver = {
-       .probe          = samsung_pinctrl_probe,
-       .driver = {
-               .name   = "samsung-pinctrl",
-               .owner  = THIS_MODULE,
-               .of_match_table = samsung_pinctrl_dt_match,
-       },
-};
-
-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);
-
-static void __exit samsung_pinctrl_drv_unregister(void)
-{
-       platform_driver_unregister(&samsung_pinctrl_driver);
-}
-module_exit(samsung_pinctrl_drv_unregister);
-
-MODULE_AUTHOR("Thomas Abraham <thomas.ab@samsung.com>");
-MODULE_DESCRIPTION("Samsung pinctrl driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h
deleted file mode 100644 (file)
index 2b88232..0000000
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * pin-controller/pin-mux/pin-config/gpio-driver for Samsung's SoC's.
- *
- * Copyright (c) 2012 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com
- * Copyright (c) 2012 Linaro Ltd
- *             http://www.linaro.org
- *
- * Author: Thomas Abraham <thomas.ab@samsung.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; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __PINCTRL_SAMSUNG_H
-#define __PINCTRL_SAMSUNG_H
-
-#include <linux/pinctrl/pinctrl.h>
-#include <linux/pinctrl/pinmux.h>
-#include <linux/pinctrl/pinconf.h>
-#include <linux/pinctrl/consumer.h>
-#include <linux/pinctrl/machine.h>
-
-#include <linux/gpio.h>
-
-/* pinmux function number for pin as gpio output line */
-#define FUNC_OUTPUT    0x1
-
-/**
- * enum pincfg_type - possible pin configuration types supported.
- * @PINCFG_TYPE_FUNC: Function configuration.
- * @PINCFG_TYPE_DAT: Pin value configuration.
- * @PINCFG_TYPE_PUD: Pull up/down configuration.
- * @PINCFG_TYPE_DRV: Drive strength configuration.
- * @PINCFG_TYPE_CON_PDN: Pin function in power down mode.
- * @PINCFG_TYPE_PUD_PDN: Pull up/down configuration in power down mode.
- */
-enum pincfg_type {
-       PINCFG_TYPE_FUNC,
-       PINCFG_TYPE_DAT,
-       PINCFG_TYPE_PUD,
-       PINCFG_TYPE_DRV,
-       PINCFG_TYPE_CON_PDN,
-       PINCFG_TYPE_PUD_PDN,
-
-       PINCFG_TYPE_NUM
-};
-
-/*
- * pin configuration (pull up/down and drive strength) type and its value are
- * packed together into a 16-bits. The upper 8-bits represent the configuration
- * type and the lower 8-bits hold the value of the configuration type.
- */
-#define PINCFG_TYPE_MASK               0xFF
-#define PINCFG_VALUE_SHIFT             8
-#define PINCFG_VALUE_MASK              (0xFF << PINCFG_VALUE_SHIFT)
-#define PINCFG_PACK(type, value)       (((value) << PINCFG_VALUE_SHIFT) | type)
-#define PINCFG_UNPACK_TYPE(cfg)                ((cfg) & PINCFG_TYPE_MASK)
-#define PINCFG_UNPACK_VALUE(cfg)       (((cfg) & PINCFG_VALUE_MASK) >> \
-                                               PINCFG_VALUE_SHIFT)
-/**
- * enum eint_type - possible external interrupt types.
- * @EINT_TYPE_NONE: bank does not support external interrupts
- * @EINT_TYPE_GPIO: bank supportes external gpio interrupts
- * @EINT_TYPE_WKUP: bank supportes external wakeup interrupts
- * @EINT_TYPE_WKUP_MUX: bank supports multiplexed external wakeup interrupts
- *
- * Samsung GPIO controller groups all the available pins into banks. The pins
- * in a pin bank can support external gpio interrupts or external wakeup
- * interrupts or no interrupts at all. From a software perspective, the only
- * difference between external gpio and external wakeup interrupts is that
- * the wakeup interrupts can additionally wakeup the system if it is in
- * suspended state.
- */
-enum eint_type {
-       EINT_TYPE_NONE,
-       EINT_TYPE_GPIO,
-       EINT_TYPE_WKUP,
-       EINT_TYPE_WKUP_MUX,
-};
-
-/* maximum length of a pin in pin descriptor (example: "gpa0-0") */
-#define PIN_NAME_LENGTH        10
-
-#define PIN_GROUP(n, p, f)                             \
-       {                                               \
-               .name           = n,                    \
-               .pins           = p,                    \
-               .num_pins       = ARRAY_SIZE(p),        \
-               .func           = f                     \
-       }
-
-#define PMX_FUNC(n, g)                                 \
-       {                                               \
-               .name           = n,                    \
-               .groups         = g,                    \
-               .num_groups     = ARRAY_SIZE(g),        \
-       }
-
-struct samsung_pinctrl_drv_data;
-
-/**
- * struct samsung_pin_bank_type: pin bank type description
- * @fld_width: widths of configuration bitfields (0 if unavailable)
- * @reg_offset: offsets of configuration registers (don't care of width is 0)
- */
-struct samsung_pin_bank_type {
-       u8 fld_width[PINCFG_TYPE_NUM];
-       u8 reg_offset[PINCFG_TYPE_NUM];
-};
-
-/**
- * struct samsung_pin_bank: represent a controller pin-bank.
- * @type: type of the bank (register offsets and bitfield widths)
- * @pctl_offset: starting offset of the pin-bank registers.
- * @pin_base: starting pin number of the bank.
- * @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.
- * @eint_mask: bit mask of pins which support EINT function.
- * @name: name to be prefixed for each pin in this pin bank.
- * @of_node: OF node of the bank.
- * @drvdata: link to controller driver data
- * @irq_domain: IRQ domain of the bank.
- * @gpio_chip: GPIO chip of the bank.
- * @grange: linux gpio pin range supported by this bank.
- * @slock: spinlock protecting bank registers
- * @pm_save: saved register values during suspend
- */
-struct samsung_pin_bank {
-       struct samsung_pin_bank_type *type;
-       u32             pctl_offset;
-       u32             pin_base;
-       u8              nr_pins;
-       u8              eint_func;
-       enum eint_type  eint_type;
-       u32             eint_mask;
-       u32             eint_offset;
-       char            *name;
-       void            *soc_priv;
-       struct device_node *of_node;
-       struct samsung_pinctrl_drv_data *drvdata;
-       struct irq_domain *irq_domain;
-       struct gpio_chip gpio_chip;
-       struct pinctrl_gpio_range grange;
-       spinlock_t slock;
-
-       u32 pm_save[PINCFG_TYPE_NUM + 1]; /* +1 to handle double CON registers*/
-};
-
-/**
- * struct samsung_pin_ctrl: represent a pin controller.
- * @pin_banks: list of pin banks included in this controller.
- * @nr_banks: number of pin banks.
- * @base: starting system wide pin number.
- * @nr_pins: number of pins supported by the controller.
- * @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
- *     interrupts for the controller.
- * @label: for debug information.
- */
-struct samsung_pin_ctrl {
-       struct samsung_pin_bank *pin_banks;
-       u32             nr_banks;
-
-       u32             base;
-       u32             nr_pins;
-
-       int             (*eint_gpio_init)(struct samsung_pinctrl_drv_data *);
-       int             (*eint_wkup_init)(struct samsung_pinctrl_drv_data *);
-       void            (*suspend)(struct samsung_pinctrl_drv_data *);
-       void            (*resume)(struct samsung_pinctrl_drv_data *);
-
-       char            *label;
-};
-
-/**
- * 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.
- * @pctl: pin controller descriptor registered with the pinctrl subsystem.
- * @pctl_dev: cookie representing pinctrl device instance.
- * @pin_groups: list of pin groups available to the driver.
- * @nr_groups: number of such pin groups.
- * @pmx_functions: list of pin functions available to the driver.
- * @nr_function: number of such pin functions.
- */
-struct samsung_pinctrl_drv_data {
-       struct list_head                node;
-       void __iomem                    *virt_base;
-       struct device                   *dev;
-       int                             irq;
-
-       struct samsung_pin_ctrl         *ctrl;
-       struct pinctrl_desc             pctl;
-       struct pinctrl_dev              *pctl_dev;
-
-       const struct samsung_pin_group  *pin_groups;
-       unsigned int                    nr_groups;
-       const struct samsung_pmx_func   *pmx_functions;
-       unsigned int                    nr_functions;
-};
-
-/**
- * struct samsung_pin_group: represent group of pins of a pinmux function.
- * @name: name of the pin group, used to lookup the group.
- * @pins: the pins included in this group.
- * @num_pins: number of pins included in this group.
- * @func: the function number to be programmed when selected.
- */
-struct samsung_pin_group {
-       const char              *name;
-       const unsigned int      *pins;
-       u8                      num_pins;
-       u8                      func;
-};
-
-/**
- * struct samsung_pmx_func: represent a pin function.
- * @name: name of the pin function, used to lookup the function.
- * @groups: one or more names of pin groups that provide this function.
- * @num_groups: number of groups included in @groups.
- */
-struct samsung_pmx_func {
-       const char              *name;
-       const char              **groups;
-       u8                      num_groups;
-       u32                     val;
-};
-
-/* list of all exported SoC specific data */
-extern struct samsung_pin_ctrl exynos3250_pin_ctrl[];
-extern struct samsung_pin_ctrl exynos4210_pin_ctrl[];
-extern struct samsung_pin_ctrl exynos4x12_pin_ctrl[];
-extern struct samsung_pin_ctrl exynos5250_pin_ctrl[];
-extern struct samsung_pin_ctrl exynos5260_pin_ctrl[];
-extern struct samsung_pin_ctrl exynos5420_pin_ctrl[];
-extern struct samsung_pin_ctrl s3c64xx_pin_ctrl[];
-extern struct samsung_pin_ctrl s3c2412_pin_ctrl[];
-extern struct samsung_pin_ctrl s3c2416_pin_ctrl[];
-extern struct samsung_pin_ctrl s3c2440_pin_ctrl[];
-extern struct samsung_pin_ctrl s3c2450_pin_ctrl[];
-extern struct samsung_pin_ctrl s5pv210_pin_ctrl[];
-
-#endif /* __PINCTRL_SAMSUNG_H */
diff --git a/drivers/pinctrl/samsung/Kconfig b/drivers/pinctrl/samsung/Kconfig
new file mode 100644 (file)
index 0000000..d0461cd
--- /dev/null
@@ -0,0 +1,28 @@
+#
+# Samsung Pin control drivers
+#
+config PINCTRL_SAMSUNG
+       bool
+       select PINMUX
+       select PINCONF
+
+config PINCTRL_EXYNOS
+       bool "Pinctrl driver data for Samsung EXYNOS SoCs other than 5440"
+       depends on OF && GPIOLIB && (ARCH_EXYNOS || ARCH_S5PV210)
+       select PINCTRL_SAMSUNG
+
+config PINCTRL_EXYNOS5440
+       bool "Samsung EXYNOS5440 SoC pinctrl driver"
+       depends on SOC_EXYNOS5440
+       select PINMUX
+       select PINCONF
+
+config PINCTRL_S3C24XX
+       bool "Samsung S3C24XX SoC pinctrl driver"
+       depends on ARCH_S3C24XX
+       select PINCTRL_SAMSUNG
+
+config PINCTRL_S3C64XX
+       bool "Samsung S3C64XX SoC pinctrl driver"
+       depends on ARCH_S3C64XX
+       select PINCTRL_SAMSUNG
diff --git a/drivers/pinctrl/samsung/Makefile b/drivers/pinctrl/samsung/Makefile
new file mode 100644 (file)
index 0000000..70160c0
--- /dev/null
@@ -0,0 +1,7 @@
+# Samsung pin control drivers
+
+obj-$(CONFIG_PINCTRL_SAMSUNG)  += pinctrl-samsung.o
+obj-$(CONFIG_PINCTRL_EXYNOS)   += pinctrl-exynos.o
+obj-$(CONFIG_PINCTRL_EXYNOS5440)       += pinctrl-exynos5440.o
+obj-$(CONFIG_PINCTRL_S3C24XX)  += pinctrl-s3c24xx.o
+obj-$(CONFIG_PINCTRL_S3C64XX)  += pinctrl-s3c64xx.o
diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c
new file mode 100644 (file)
index 0000000..003bfd8
--- /dev/null
@@ -0,0 +1,1123 @@
+/*
+ * Exynos specific support for Samsung pinctrl/gpiolib driver with eint support.
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ * Copyright (c) 2012 Linaro Ltd
+ *             http://www.linaro.org
+ *
+ * Author: Thomas Abraham <thomas.ab@samsung.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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This file contains the Samsung Exynos specific information required by the
+ * the Samsung pinctrl/gpiolib driver. It also includes the implementation of
+ * external gpio and wakeup interrupt support.
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/irq.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/of_irq.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/err.h>
+
+#include "pinctrl-samsung.h"
+#include "pinctrl-exynos.h"
+
+struct exynos_irq_chip {
+       struct irq_chip chip;
+
+       u32 eint_con;
+       u32 eint_mask;
+       u32 eint_pend;
+};
+
+static inline struct exynos_irq_chip *to_exynos_irq_chip(struct irq_chip *chip)
+{
+       return container_of(chip, struct exynos_irq_chip, chip);
+}
+
+static struct samsung_pin_bank_type bank_type_off = {
+       .fld_width = { 4, 1, 2, 2, 2, 2, },
+       .reg_offset = { 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, },
+};
+
+static struct samsung_pin_bank_type bank_type_alive = {
+       .fld_width = { 4, 1, 2, 2, },
+       .reg_offset = { 0x00, 0x04, 0x08, 0x0c, },
+};
+
+/* list of external wakeup controllers supported */
+static const struct of_device_id exynos_wkup_irq_ids[] = {
+       { .compatible = "samsung,exynos4210-wakeup-eint", },
+       { }
+};
+
+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 |= 1 << irqd->hwirq;
+       writel(mask, d->virt_base + reg_mask);
+
+       spin_unlock_irqrestore(&bank->slock, flags);
+}
+
+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);
+}
+
+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;
+
+       /*
+        * Ack level interrupts right before unmask
+        *
+        * If we don't do this we'll get a double-interrupt.  Level triggered
+        * interrupts must not fire an interrupt if the level is not
+        * _currently_ active, even if it was active while the interrupt was
+        * masked.
+        */
+       if (irqd_get_trigger_type(irqd) & IRQ_TYPE_LEVEL_MASK)
+               exynos_irq_ack(irqd);
+
+       spin_lock_irqsave(&bank->slock, flags);
+
+       mask = readl(d->virt_base + reg_mask);
+       mask &= ~(1 << irqd->hwirq);
+       writel(mask, d->virt_base + reg_mask);
+
+       spin_unlock_irqrestore(&bank->slock, flags);
+}
+
+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_pin_bank_type *bank_type = bank->type;
+       struct samsung_pinctrl_drv_data *d = bank->drvdata;
+       unsigned int pin = irqd->hwirq;
+       unsigned int shift = EXYNOS_EINT_CON_LEN * pin;
+       unsigned int con, trig_type;
+       unsigned long reg_con = our_chip->eint_con + bank->eint_offset;
+       unsigned long flags;
+       unsigned int mask;
+
+       switch (type) {
+       case IRQ_TYPE_EDGE_RISING:
+               trig_type = EXYNOS_EINT_EDGE_RISING;
+               break;
+       case IRQ_TYPE_EDGE_FALLING:
+               trig_type = EXYNOS_EINT_EDGE_FALLING;
+               break;
+       case IRQ_TYPE_EDGE_BOTH:
+               trig_type = EXYNOS_EINT_EDGE_BOTH;
+               break;
+       case IRQ_TYPE_LEVEL_HIGH:
+               trig_type = EXYNOS_EINT_LEVEL_HIGH;
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
+               trig_type = EXYNOS_EINT_LEVEL_LOW;
+               break;
+       default:
+               pr_err("unsupported external interrupt type\n");
+               return -EINVAL;
+       }
+
+       if (type & IRQ_TYPE_EDGE_BOTH)
+               __irq_set_handler_locked(irqd->irq, handle_edge_irq);
+       else
+               __irq_set_handler_locked(irqd->irq, handle_level_irq);
+
+       con = readl(d->virt_base + reg_con);
+       con &= ~(EXYNOS_EINT_CON_MASK << shift);
+       con |= trig_type << shift;
+       writel(con, d->virt_base + reg_con);
+
+       reg_con = bank->pctl_offset + bank_type->reg_offset[PINCFG_TYPE_FUNC];
+       shift = pin * bank_type->fld_width[PINCFG_TYPE_FUNC];
+       mask = (1 << bank_type->fld_width[PINCFG_TYPE_FUNC]) - 1;
+
+       spin_lock_irqsave(&bank->slock, flags);
+
+       con = readl(d->virt_base + reg_con);
+       con &= ~(mask << shift);
+       con |= EXYNOS_EINT_FUNC << shift;
+       writel(con, d->virt_base + reg_con);
+
+       spin_unlock_irqrestore(&bank->slock, flags);
+
+       return 0;
+}
+
+/*
+ * irq_chip for gpio interrupts.
+ */
+static struct exynos_irq_chip exynos_gpio_irq_chip = {
+       .chip = {
+               .name = "exynos_gpio_irq_chip",
+               .irq_unmask = exynos_irq_unmask,
+               .irq_mask = exynos_irq_mask,
+               .irq_ack = exynos_irq_ack,
+               .irq_set_type = exynos_irq_set_type,
+       },
+       .eint_con = EXYNOS_GPIO_ECON_OFFSET,
+       .eint_mask = EXYNOS_GPIO_EMASK_OFFSET,
+       .eint_pend = EXYNOS_GPIO_EPEND_OFFSET,
+};
+
+static int exynos_gpio_irq_map(struct irq_domain *h, unsigned int virq,
+                                       irq_hw_number_t hw)
+{
+       struct samsung_pin_bank *b = h->host_data;
+
+       irq_set_chip_data(virq, b);
+       irq_set_chip_and_handler(virq, &exynos_gpio_irq_chip.chip,
+                                       handle_level_irq);
+       set_irq_flags(virq, IRQF_VALID);
+       return 0;
+}
+
+/*
+ * irq domain callbacks for external gpio interrupt controller.
+ */
+static const struct irq_domain_ops exynos_gpio_irqd_ops = {
+       .map    = exynos_gpio_irq_map,
+       .xlate  = irq_domain_xlate_twocell,
+};
+
+static irqreturn_t exynos_eint_gpio_irq(int irq, void *data)
+{
+       struct samsung_pinctrl_drv_data *d = data;
+       struct samsung_pin_ctrl *ctrl = d->ctrl;
+       struct samsung_pin_bank *bank = ctrl->pin_banks;
+       unsigned int svc, group, pin, virq;
+
+       svc = readl(d->virt_base + EXYNOS_SVC_OFFSET);
+       group = EXYNOS_SVC_GROUP(svc);
+       pin = svc & EXYNOS_SVC_NUM_MASK;
+
+       if (!group)
+               return IRQ_HANDLED;
+       bank += (group - 1);
+
+       virq = irq_linear_revmap(bank->irq_domain, pin);
+       if (!virq)
+               return IRQ_NONE;
+       generic_handle_irq(virq);
+       return IRQ_HANDLED;
+}
+
+struct exynos_eint_gpio_save {
+       u32 eint_con;
+       u32 eint_fltcon0;
+       u32 eint_fltcon1;
+};
+
+/*
+ * exynos_eint_gpio_init() - setup handling of external gpio interrupts.
+ * @d: driver data of samsung pinctrl driver.
+ */
+static int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d)
+{
+       struct samsung_pin_bank *bank;
+       struct device *dev = d->dev;
+       int ret;
+       int i;
+
+       if (!d->irq) {
+               dev_err(dev, "irq number not available\n");
+               return -EINVAL;
+       }
+
+       ret = devm_request_irq(dev, d->irq, exynos_eint_gpio_irq,
+                                       0, dev_name(dev), d);
+       if (ret) {
+               dev_err(dev, "irq request failed\n");
+               return -ENXIO;
+       }
+
+       bank = d->ctrl->pin_banks;
+       for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) {
+               if (bank->eint_type != EINT_TYPE_GPIO)
+                       continue;
+               bank->irq_domain = irq_domain_add_linear(bank->of_node,
+                               bank->nr_pins, &exynos_gpio_irqd_ops, bank);
+               if (!bank->irq_domain) {
+                       dev_err(dev, "gpio irq domain add failed\n");
+                       ret = -ENXIO;
+                       goto err_domains;
+               }
+
+               bank->soc_priv = devm_kzalloc(d->dev,
+                       sizeof(struct exynos_eint_gpio_save), GFP_KERNEL);
+               if (!bank->soc_priv) {
+                       irq_domain_remove(bank->irq_domain);
+                       ret = -ENOMEM;
+                       goto err_domains;
+               }
+       }
+
+       return 0;
+
+err_domains:
+       for (--i, --bank; i >= 0; --i, --bank) {
+               if (bank->eint_type != EINT_TYPE_GPIO)
+                       continue;
+               irq_domain_remove(bank->irq_domain);
+       }
+
+       return ret;
+}
+
+static u32 exynos_eint_wake_mask = 0xffffffff;
+
+u32 exynos_get_eint_wake_mask(void)
+{
+       return exynos_eint_wake_mask;
+}
+
+static int exynos_wkup_irq_set_wake(struct irq_data *irqd, unsigned int on)
+{
+       struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
+       unsigned long bit = 1UL << (2 * bank->eint_offset + irqd->hwirq);
+
+       pr_info("wake %s for irq %d\n", on ? "enabled" : "disabled", irqd->irq);
+
+       if (!on)
+               exynos_eint_wake_mask |= bit;
+       else
+               exynos_eint_wake_mask &= ~bit;
+
+       return 0;
+}
+
+/*
+ * irq_chip for wakeup interrupts
+ */
+static struct exynos_irq_chip exynos_wkup_irq_chip = {
+       .chip = {
+               .name = "exynos_wkup_irq_chip",
+               .irq_unmask = exynos_irq_unmask,
+               .irq_mask = exynos_irq_mask,
+               .irq_ack = exynos_irq_ack,
+               .irq_set_type = exynos_irq_set_type,
+               .irq_set_wake = exynos_wkup_irq_set_wake,
+       },
+       .eint_con = EXYNOS_WKUP_ECON_OFFSET,
+       .eint_mask = EXYNOS_WKUP_EMASK_OFFSET,
+       .eint_pend = EXYNOS_WKUP_EPEND_OFFSET,
+};
+
+/* interrupt handler for wakeup interrupts 0..15 */
+static void exynos_irq_eint0_15(unsigned int irq, struct irq_desc *desc)
+{
+       struct exynos_weint_data *eintd = irq_get_handler_data(irq);
+       struct samsung_pin_bank *bank = eintd->bank;
+       struct irq_chip *chip = irq_get_chip(irq);
+       int eint_irq;
+
+       chained_irq_enter(chip, desc);
+       chip->irq_mask(&desc->irq_data);
+
+       if (chip->irq_ack)
+               chip->irq_ack(&desc->irq_data);
+
+       eint_irq = irq_linear_revmap(bank->irq_domain, eintd->irq);
+       generic_handle_irq(eint_irq);
+       chip->irq_unmask(&desc->irq_data);
+       chained_irq_exit(chip, desc);
+}
+
+static inline void exynos_irq_demux_eint(unsigned long pend,
+                                               struct irq_domain *domain)
+{
+       unsigned int irq;
+
+       while (pend) {
+               irq = fls(pend) - 1;
+               generic_handle_irq(irq_find_mapping(domain, irq));
+               pend &= ~(1 << irq);
+       }
+}
+
+/* interrupt handler for wakeup interrupt 16 */
+static void exynos_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc)
+{
+       struct irq_chip *chip = irq_get_chip(irq);
+       struct exynos_muxed_weint_data *eintd = irq_get_handler_data(irq);
+       struct samsung_pinctrl_drv_data *d = eintd->banks[0]->drvdata;
+       unsigned long pend;
+       unsigned long mask;
+       int i;
+
+       chained_irq_enter(chip, desc);
+
+       for (i = 0; i < eintd->nr_banks; ++i) {
+               struct samsung_pin_bank *b = eintd->banks[i];
+               pend = readl(d->virt_base + EXYNOS_WKUP_EPEND_OFFSET
+                               + b->eint_offset);
+               mask = readl(d->virt_base + EXYNOS_WKUP_EMASK_OFFSET
+                               + b->eint_offset);
+               exynos_irq_demux_eint(pend & ~mask, b->irq_domain);
+       }
+
+       chained_irq_exit(chip, desc);
+}
+
+static int exynos_wkup_irq_map(struct irq_domain *h, unsigned int virq,
+                                       irq_hw_number_t hw)
+{
+       irq_set_chip_and_handler(virq, &exynos_wkup_irq_chip.chip,
+                                       handle_level_irq);
+       irq_set_chip_data(virq, h->host_data);
+       set_irq_flags(virq, IRQF_VALID);
+       return 0;
+}
+
+/*
+ * irq domain callbacks for external wakeup interrupt controller.
+ */
+static const struct irq_domain_ops exynos_wkup_irqd_ops = {
+       .map    = exynos_wkup_irq_map,
+       .xlate  = irq_domain_xlate_twocell,
+};
+
+/*
+ * exynos_eint_wkup_init() - setup handling of external wakeup interrupts.
+ * @d: driver data of samsung pinctrl driver.
+ */
+static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d)
+{
+       struct device *dev = d->dev;
+       struct device_node *wkup_np = NULL;
+       struct device_node *np;
+       struct samsung_pin_bank *bank;
+       struct exynos_weint_data *weint_data;
+       struct exynos_muxed_weint_data *muxed_data;
+       unsigned int muxed_banks = 0;
+       unsigned int i;
+       int idx, irq;
+
+       for_each_child_of_node(dev->of_node, np) {
+               if (of_match_node(exynos_wkup_irq_ids, np)) {
+                       wkup_np = np;
+                       break;
+               }
+       }
+       if (!wkup_np)
+               return -ENODEV;
+
+       bank = d->ctrl->pin_banks;
+       for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) {
+               if (bank->eint_type != EINT_TYPE_WKUP)
+                       continue;
+
+               bank->irq_domain = irq_domain_add_linear(bank->of_node,
+                               bank->nr_pins, &exynos_wkup_irqd_ops, bank);
+               if (!bank->irq_domain) {
+                       dev_err(dev, "wkup irq domain add failed\n");
+                       return -ENXIO;
+               }
+
+               if (!of_find_property(bank->of_node, "interrupts", NULL)) {
+                       bank->eint_type = EINT_TYPE_WKUP_MUX;
+                       ++muxed_banks;
+                       continue;
+               }
+
+               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");
+                       return -ENOMEM;
+               }
+
+               for (idx = 0; idx < bank->nr_pins; ++idx) {
+                       irq = irq_of_parse_and_map(bank->of_node, idx);
+                       if (!irq) {
+                               dev_err(dev, "irq number for eint-%s-%d not found\n",
+                                                       bank->name, idx);
+                               continue;
+                       }
+                       weint_data[idx].irq = idx;
+                       weint_data[idx].bank = bank;
+                       irq_set_handler_data(irq, &weint_data[idx]);
+                       irq_set_chained_handler(irq, exynos_irq_eint0_15);
+               }
+       }
+
+       if (!muxed_banks)
+               return 0;
+
+       irq = irq_of_parse_and_map(wkup_np, 0);
+       if (!irq) {
+               dev_err(dev, "irq number for muxed EINTs not found\n");
+               return 0;
+       }
+
+       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");
+               return -ENOMEM;
+       }
+
+       irq_set_chained_handler(irq, exynos_irq_demux_eint16_31);
+       irq_set_handler_data(irq, muxed_data);
+
+       bank = d->ctrl->pin_banks;
+       idx = 0;
+       for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) {
+               if (bank->eint_type != EINT_TYPE_WKUP_MUX)
+                       continue;
+
+               muxed_data->banks[idx++] = bank;
+       }
+       muxed_data->nr_banks = muxed_banks;
+
+       return 0;
+}
+
+static void exynos_pinctrl_suspend_bank(
+                               struct samsung_pinctrl_drv_data *drvdata,
+                               struct samsung_pin_bank *bank)
+{
+       struct exynos_eint_gpio_save *save = bank->soc_priv;
+       void __iomem *regs = drvdata->virt_base;
+
+       save->eint_con = readl(regs + EXYNOS_GPIO_ECON_OFFSET
+                                               + bank->eint_offset);
+       save->eint_fltcon0 = readl(regs + EXYNOS_GPIO_EFLTCON_OFFSET
+                                               + 2 * bank->eint_offset);
+       save->eint_fltcon1 = readl(regs + EXYNOS_GPIO_EFLTCON_OFFSET
+                                               + 2 * bank->eint_offset + 4);
+
+       pr_debug("%s: save     con %#010x\n", bank->name, save->eint_con);
+       pr_debug("%s: save fltcon0 %#010x\n", bank->name, save->eint_fltcon0);
+       pr_debug("%s: save fltcon1 %#010x\n", bank->name, save->eint_fltcon1);
+}
+
+static void exynos_pinctrl_suspend(struct samsung_pinctrl_drv_data *drvdata)
+{
+       struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
+       struct samsung_pin_bank *bank = ctrl->pin_banks;
+       int i;
+
+       for (i = 0; i < ctrl->nr_banks; ++i, ++bank)
+               if (bank->eint_type == EINT_TYPE_GPIO)
+                       exynos_pinctrl_suspend_bank(drvdata, bank);
+}
+
+static void exynos_pinctrl_resume_bank(
+                               struct samsung_pinctrl_drv_data *drvdata,
+                               struct samsung_pin_bank *bank)
+{
+       struct exynos_eint_gpio_save *save = bank->soc_priv;
+       void __iomem *regs = drvdata->virt_base;
+
+       pr_debug("%s:     con %#010x => %#010x\n", bank->name,
+                       readl(regs + EXYNOS_GPIO_ECON_OFFSET
+                       + bank->eint_offset), save->eint_con);
+       pr_debug("%s: fltcon0 %#010x => %#010x\n", bank->name,
+                       readl(regs + EXYNOS_GPIO_EFLTCON_OFFSET
+                       + 2 * bank->eint_offset), save->eint_fltcon0);
+       pr_debug("%s: fltcon1 %#010x => %#010x\n", bank->name,
+                       readl(regs + EXYNOS_GPIO_EFLTCON_OFFSET
+                       + 2 * bank->eint_offset + 4), save->eint_fltcon1);
+
+       writel(save->eint_con, regs + EXYNOS_GPIO_ECON_OFFSET
+                                               + bank->eint_offset);
+       writel(save->eint_fltcon0, regs + EXYNOS_GPIO_EFLTCON_OFFSET
+                                               + 2 * bank->eint_offset);
+       writel(save->eint_fltcon1, regs + EXYNOS_GPIO_EFLTCON_OFFSET
+                                               + 2 * bank->eint_offset + 4);
+}
+
+static void exynos_pinctrl_resume(struct samsung_pinctrl_drv_data *drvdata)
+{
+       struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
+       struct samsung_pin_bank *bank = ctrl->pin_banks;
+       int i;
+
+       for (i = 0; i < ctrl->nr_banks; ++i, ++bank)
+               if (bank->eint_type == EINT_TYPE_GPIO)
+                       exynos_pinctrl_resume_bank(drvdata, bank);
+}
+
+/* pin banks of s5pv210 pin-controller */
+static struct samsung_pin_bank s5pv210_pin_bank[] = {
+       EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
+       EXYNOS_PIN_BANK_EINTG(4, 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(6, 0x0c0, "gpd1", 0x18),
+       EXYNOS_PIN_BANK_EINTG(8, 0x0e0, "gpe0", 0x1c),
+       EXYNOS_PIN_BANK_EINTG(5, 0x100, "gpe1", 0x20),
+       EXYNOS_PIN_BANK_EINTG(8, 0x120, "gpf0", 0x24),
+       EXYNOS_PIN_BANK_EINTG(8, 0x140, "gpf1", 0x28),
+       EXYNOS_PIN_BANK_EINTG(8, 0x160, "gpf2", 0x2c),
+       EXYNOS_PIN_BANK_EINTG(6, 0x180, "gpf3", 0x30),
+       EXYNOS_PIN_BANK_EINTG(7, 0x1a0, "gpg0", 0x34),
+       EXYNOS_PIN_BANK_EINTG(7, 0x1c0, "gpg1", 0x38),
+       EXYNOS_PIN_BANK_EINTG(7, 0x1e0, "gpg2", 0x3c),
+       EXYNOS_PIN_BANK_EINTG(7, 0x200, "gpg3", 0x40),
+       EXYNOS_PIN_BANK_EINTN(7, 0x220, "gpi"),
+       EXYNOS_PIN_BANK_EINTG(8, 0x240, "gpj0", 0x44),
+       EXYNOS_PIN_BANK_EINTG(6, 0x260, "gpj1", 0x48),
+       EXYNOS_PIN_BANK_EINTG(8, 0x280, "gpj2", 0x4c),
+       EXYNOS_PIN_BANK_EINTG(8, 0x2a0, "gpj3", 0x50),
+       EXYNOS_PIN_BANK_EINTG(5, 0x2c0, "gpj4", 0x54),
+       EXYNOS_PIN_BANK_EINTN(8, 0x2e0, "mp01"),
+       EXYNOS_PIN_BANK_EINTN(4, 0x300, "mp02"),
+       EXYNOS_PIN_BANK_EINTN(8, 0x320, "mp03"),
+       EXYNOS_PIN_BANK_EINTN(8, 0x340, "mp04"),
+       EXYNOS_PIN_BANK_EINTN(8, 0x360, "mp05"),
+       EXYNOS_PIN_BANK_EINTN(8, 0x380, "mp06"),
+       EXYNOS_PIN_BANK_EINTN(8, 0x3a0, "mp07"),
+       EXYNOS_PIN_BANK_EINTW(8, 0xc00, "gph0", 0x00),
+       EXYNOS_PIN_BANK_EINTW(8, 0xc20, "gph1", 0x04),
+       EXYNOS_PIN_BANK_EINTW(8, 0xc40, "gph2", 0x08),
+       EXYNOS_PIN_BANK_EINTW(8, 0xc60, "gph3", 0x0c),
+};
+
+struct samsung_pin_ctrl s5pv210_pin_ctrl[] = {
+       {
+               /* pin-controller instance 0 data */
+               .pin_banks      = s5pv210_pin_bank,
+               .nr_banks       = ARRAY_SIZE(s5pv210_pin_bank),
+               .eint_gpio_init = exynos_eint_gpio_init,
+               .eint_wkup_init = exynos_eint_wkup_init,
+               .suspend        = exynos_pinctrl_suspend,
+               .resume         = exynos_pinctrl_resume,
+               .label          = "s5pv210-gpio-ctrl0",
+       },
+};
+
+/* pin banks of exynos3250 pin-controller 0 */
+static struct samsung_pin_bank exynos3250_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),
+};
+
+/* pin banks of exynos3250 pin-controller 1 */
+static struct samsung_pin_bank exynos3250_pin_banks1[] = {
+       EXYNOS_PIN_BANK_EINTN(8, 0x120, "gpe0"),
+       EXYNOS_PIN_BANK_EINTN(8, 0x140, "gpe1"),
+       EXYNOS_PIN_BANK_EINTN(3, 0x180, "gpe2"),
+       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(4, 0x0c0, "gpl0", 0x18),
+       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),
+};
+
+/*
+ * Samsung pinctrl driver data for Exynos3250 SoC. Exynos3250 SoC includes
+ * two gpio/pin-mux/pinconfig controllers.
+ */
+struct samsung_pin_ctrl exynos3250_pin_ctrl[] = {
+       {
+               /* pin-controller instance 0 data */
+               .pin_banks      = exynos3250_pin_banks0,
+               .nr_banks       = ARRAY_SIZE(exynos3250_pin_banks0),
+               .eint_gpio_init = exynos_eint_gpio_init,
+               .suspend        = exynos_pinctrl_suspend,
+               .resume         = exynos_pinctrl_resume,
+               .label          = "exynos3250-gpio-ctrl0",
+       }, {
+               /* pin-controller instance 1 data */
+               .pin_banks      = exynos3250_pin_banks1,
+               .nr_banks       = ARRAY_SIZE(exynos3250_pin_banks1),
+               .eint_gpio_init = exynos_eint_gpio_init,
+               .eint_wkup_init = exynos_eint_wkup_init,
+               .suspend        = exynos_pinctrl_suspend,
+               .resume         = exynos_pinctrl_resume,
+               .label          = "exynos3250-gpio-ctrl1",
+       },
+};
+
+/* pin banks of exynos4210 pin-controller 0 */
+static struct samsung_pin_bank exynos4210_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(5, 0x0E0, "gpe0", 0x1c),
+       EXYNOS_PIN_BANK_EINTG(8, 0x100, "gpe1", 0x20),
+       EXYNOS_PIN_BANK_EINTG(6, 0x120, "gpe2", 0x24),
+       EXYNOS_PIN_BANK_EINTG(8, 0x140, "gpe3", 0x28),
+       EXYNOS_PIN_BANK_EINTG(8, 0x160, "gpe4", 0x2c),
+       EXYNOS_PIN_BANK_EINTG(8, 0x180, "gpf0", 0x30),
+       EXYNOS_PIN_BANK_EINTG(8, 0x1A0, "gpf1", 0x34),
+       EXYNOS_PIN_BANK_EINTG(8, 0x1C0, "gpf2", 0x38),
+       EXYNOS_PIN_BANK_EINTG(6, 0x1E0, "gpf3", 0x3c),
+};
+
+/* pin banks of exynos4210 pin-controller 1 */
+static struct samsung_pin_bank exynos4210_pin_banks1[] = {
+       EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpj0", 0x00),
+       EXYNOS_PIN_BANK_EINTG(5, 0x020, "gpj1", 0x04),
+       EXYNOS_PIN_BANK_EINTG(7, 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(8, 0x0C0, "gpl0", 0x18),
+       EXYNOS_PIN_BANK_EINTG(3, 0x0E0, "gpl1", 0x1c),
+       EXYNOS_PIN_BANK_EINTG(8, 0x100, "gpl2", 0x20),
+       EXYNOS_PIN_BANK_EINTN(6, 0x120, "gpy0"),
+       EXYNOS_PIN_BANK_EINTN(4, 0x140, "gpy1"),
+       EXYNOS_PIN_BANK_EINTN(6, 0x160, "gpy2"),
+       EXYNOS_PIN_BANK_EINTN(8, 0x180, "gpy3"),
+       EXYNOS_PIN_BANK_EINTN(8, 0x1A0, "gpy4"),
+       EXYNOS_PIN_BANK_EINTN(8, 0x1C0, "gpy5"),
+       EXYNOS_PIN_BANK_EINTN(8, 0x1E0, "gpy6"),
+       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 exynos4210 pin-controller 2 */
+static struct samsung_pin_bank exynos4210_pin_banks2[] = {
+       EXYNOS_PIN_BANK_EINTN(7, 0x000, "gpz"),
+};
+
+/*
+ * Samsung pinctrl driver data for Exynos4210 SoC. Exynos4210 SoC includes
+ * three gpio/pin-mux/pinconfig controllers.
+ */
+struct samsung_pin_ctrl exynos4210_pin_ctrl[] = {
+       {
+               /* pin-controller instance 0 data */
+               .pin_banks      = exynos4210_pin_banks0,
+               .nr_banks       = ARRAY_SIZE(exynos4210_pin_banks0),
+               .eint_gpio_init = exynos_eint_gpio_init,
+               .suspend        = exynos_pinctrl_suspend,
+               .resume         = exynos_pinctrl_resume,
+               .label          = "exynos4210-gpio-ctrl0",
+       }, {
+               /* pin-controller instance 1 data */
+               .pin_banks      = exynos4210_pin_banks1,
+               .nr_banks       = ARRAY_SIZE(exynos4210_pin_banks1),
+               .eint_gpio_init = exynos_eint_gpio_init,
+               .eint_wkup_init = exynos_eint_wkup_init,
+               .suspend        = exynos_pinctrl_suspend,
+               .resume         = exynos_pinctrl_resume,
+               .label          = "exynos4210-gpio-ctrl1",
+       }, {
+               /* pin-controller instance 2 data */
+               .pin_banks      = exynos4210_pin_banks2,
+               .nr_banks       = ARRAY_SIZE(exynos4210_pin_banks2),
+               .label          = "exynos4210-gpio-ctrl2",
+       },
+};
+
+/* pin banks of exynos4x12 pin-controller 0 */
+static struct samsung_pin_bank exynos4x12_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(8, 0x1C0, "gpf2", 0x38),
+       EXYNOS_PIN_BANK_EINTG(6, 0x1E0, "gpf3", 0x3c),
+       EXYNOS_PIN_BANK_EINTG(8, 0x240, "gpj0", 0x40),
+       EXYNOS_PIN_BANK_EINTG(5, 0x260, "gpj1", 0x44),
+};
+
+/* pin banks of exynos4x12 pin-controller 1 */
+static struct samsung_pin_bank exynos4x12_pin_banks1[] = {
+       EXYNOS_PIN_BANK_EINTG(7, 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(7, 0x0C0, "gpl0", 0x18),
+       EXYNOS_PIN_BANK_EINTG(2, 0x0E0, "gpl1", 0x1c),
+       EXYNOS_PIN_BANK_EINTG(8, 0x100, "gpl2", 0x20),
+       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_EINTN(6, 0x120, "gpy0"),
+       EXYNOS_PIN_BANK_EINTN(4, 0x140, "gpy1"),
+       EXYNOS_PIN_BANK_EINTN(6, 0x160, "gpy2"),
+       EXYNOS_PIN_BANK_EINTN(8, 0x180, "gpy3"),
+       EXYNOS_PIN_BANK_EINTN(8, 0x1A0, "gpy4"),
+       EXYNOS_PIN_BANK_EINTN(8, 0x1C0, "gpy5"),
+       EXYNOS_PIN_BANK_EINTN(8, 0x1E0, "gpy6"),
+       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 exynos4x12 pin-controller 2 */
+static struct samsung_pin_bank exynos4x12_pin_banks2[] = {
+       EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz", 0x00),
+};
+
+/* pin banks of exynos4x12 pin-controller 3 */
+static struct samsung_pin_bank exynos4x12_pin_banks3[] = {
+       EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpv0", 0x00),
+       EXYNOS_PIN_BANK_EINTG(8, 0x020, "gpv1", 0x04),
+       EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpv2", 0x08),
+       EXYNOS_PIN_BANK_EINTG(8, 0x060, "gpv3", 0x0c),
+       EXYNOS_PIN_BANK_EINTG(2, 0x080, "gpv4", 0x10),
+};
+
+/*
+ * Samsung pinctrl driver data for Exynos4x12 SoC. Exynos4x12 SoC includes
+ * four gpio/pin-mux/pinconfig controllers.
+ */
+struct samsung_pin_ctrl exynos4x12_pin_ctrl[] = {
+       {
+               /* pin-controller instance 0 data */
+               .pin_banks      = exynos4x12_pin_banks0,
+               .nr_banks       = ARRAY_SIZE(exynos4x12_pin_banks0),
+               .eint_gpio_init = exynos_eint_gpio_init,
+               .suspend        = exynos_pinctrl_suspend,
+               .resume         = exynos_pinctrl_resume,
+               .label          = "exynos4x12-gpio-ctrl0",
+       }, {
+               /* pin-controller instance 1 data */
+               .pin_banks      = exynos4x12_pin_banks1,
+               .nr_banks       = ARRAY_SIZE(exynos4x12_pin_banks1),
+               .eint_gpio_init = exynos_eint_gpio_init,
+               .eint_wkup_init = exynos_eint_wkup_init,
+               .suspend        = exynos_pinctrl_suspend,
+               .resume         = exynos_pinctrl_resume,
+               .label          = "exynos4x12-gpio-ctrl1",
+       }, {
+               /* pin-controller instance 2 data */
+               .pin_banks      = exynos4x12_pin_banks2,
+               .nr_banks       = ARRAY_SIZE(exynos4x12_pin_banks2),
+               .eint_gpio_init = exynos_eint_gpio_init,
+               .suspend        = exynos_pinctrl_suspend,
+               .resume         = exynos_pinctrl_resume,
+               .label          = "exynos4x12-gpio-ctrl2",
+       }, {
+               /* pin-controller instance 3 data */
+               .pin_banks      = exynos4x12_pin_banks3,
+               .nr_banks       = ARRAY_SIZE(exynos4x12_pin_banks3),
+               .eint_gpio_init = exynos_eint_gpio_init,
+               .suspend        = exynos_pinctrl_suspend,
+               .resume         = exynos_pinctrl_resume,
+               .label          = "exynos4x12-gpio-ctrl3",
+       },
+};
+
+/* pin banks of exynos5250 pin-controller 0 */
+static struct samsung_pin_bank exynos5250_pin_banks0[] = {
+       EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
+       EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpa1", 0x04),
+       EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpa2", 0x08),
+       EXYNOS_PIN_BANK_EINTG(5, 0x060, "gpb0", 0x0c),
+       EXYNOS_PIN_BANK_EINTG(5, 0x080, "gpb1", 0x10),
+       EXYNOS_PIN_BANK_EINTG(4, 0x0A0, "gpb2", 0x14),
+       EXYNOS_PIN_BANK_EINTG(4, 0x0C0, "gpb3", 0x18),
+       EXYNOS_PIN_BANK_EINTG(7, 0x0E0, "gpc0", 0x1c),
+       EXYNOS_PIN_BANK_EINTG(4, 0x100, "gpc1", 0x20),
+       EXYNOS_PIN_BANK_EINTG(7, 0x120, "gpc2", 0x24),
+       EXYNOS_PIN_BANK_EINTG(7, 0x140, "gpc3", 0x28),
+       EXYNOS_PIN_BANK_EINTG(4, 0x160, "gpd0", 0x2c),
+       EXYNOS_PIN_BANK_EINTG(8, 0x180, "gpd1", 0x30),
+       EXYNOS_PIN_BANK_EINTG(7, 0x2E0, "gpc4", 0x34),
+       EXYNOS_PIN_BANK_EINTN(6, 0x1A0, "gpy0"),
+       EXYNOS_PIN_BANK_EINTN(4, 0x1C0, "gpy1"),
+       EXYNOS_PIN_BANK_EINTN(6, 0x1E0, "gpy2"),
+       EXYNOS_PIN_BANK_EINTN(8, 0x200, "gpy3"),
+       EXYNOS_PIN_BANK_EINTN(8, 0x220, "gpy4"),
+       EXYNOS_PIN_BANK_EINTN(8, 0x240, "gpy5"),
+       EXYNOS_PIN_BANK_EINTN(8, 0x260, "gpy6"),
+       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 exynos5250 pin-controller 1 */
+static struct samsung_pin_bank exynos5250_pin_banks1[] = {
+       EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpe0", 0x00),
+       EXYNOS_PIN_BANK_EINTG(2, 0x020, "gpe1", 0x04),
+       EXYNOS_PIN_BANK_EINTG(4, 0x040, "gpf0", 0x08),
+       EXYNOS_PIN_BANK_EINTG(4, 0x060, "gpf1", 0x0c),
+       EXYNOS_PIN_BANK_EINTG(8, 0x080, "gpg0", 0x10),
+       EXYNOS_PIN_BANK_EINTG(8, 0x0A0, "gpg1", 0x14),
+       EXYNOS_PIN_BANK_EINTG(2, 0x0C0, "gpg2", 0x18),
+       EXYNOS_PIN_BANK_EINTG(4, 0x0E0, "gph0", 0x1c),
+       EXYNOS_PIN_BANK_EINTG(8, 0x100, "gph1", 0x20),
+};
+
+/* pin banks of exynos5250 pin-controller 2 */
+static struct samsung_pin_bank exynos5250_pin_banks2[] = {
+       EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpv0", 0x00),
+       EXYNOS_PIN_BANK_EINTG(8, 0x020, "gpv1", 0x04),
+       EXYNOS_PIN_BANK_EINTG(8, 0x060, "gpv2", 0x08),
+       EXYNOS_PIN_BANK_EINTG(8, 0x080, "gpv3", 0x0c),
+       EXYNOS_PIN_BANK_EINTG(2, 0x0C0, "gpv4", 0x10),
+};
+
+/* pin banks of exynos5250 pin-controller 3 */
+static struct samsung_pin_bank exynos5250_pin_banks3[] = {
+       EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz", 0x00),
+};
+
+/*
+ * Samsung pinctrl driver data for Exynos5250 SoC. Exynos5250 SoC includes
+ * four gpio/pin-mux/pinconfig controllers.
+ */
+struct samsung_pin_ctrl exynos5250_pin_ctrl[] = {
+       {
+               /* pin-controller instance 0 data */
+               .pin_banks      = exynos5250_pin_banks0,
+               .nr_banks       = ARRAY_SIZE(exynos5250_pin_banks0),
+               .eint_gpio_init = exynos_eint_gpio_init,
+               .eint_wkup_init = exynos_eint_wkup_init,
+               .suspend        = exynos_pinctrl_suspend,
+               .resume         = exynos_pinctrl_resume,
+               .label          = "exynos5250-gpio-ctrl0",
+       }, {
+               /* pin-controller instance 1 data */
+               .pin_banks      = exynos5250_pin_banks1,
+               .nr_banks       = ARRAY_SIZE(exynos5250_pin_banks1),
+               .eint_gpio_init = exynos_eint_gpio_init,
+               .suspend        = exynos_pinctrl_suspend,
+               .resume         = exynos_pinctrl_resume,
+               .label          = "exynos5250-gpio-ctrl1",
+       }, {
+               /* pin-controller instance 2 data */
+               .pin_banks      = exynos5250_pin_banks2,
+               .nr_banks       = ARRAY_SIZE(exynos5250_pin_banks2),
+               .eint_gpio_init = exynos_eint_gpio_init,
+               .suspend        = exynos_pinctrl_suspend,
+               .resume         = exynos_pinctrl_resume,
+               .label          = "exynos5250-gpio-ctrl2",
+       }, {
+               /* pin-controller instance 3 data */
+               .pin_banks      = exynos5250_pin_banks3,
+               .nr_banks       = ARRAY_SIZE(exynos5250_pin_banks3),
+               .eint_gpio_init = exynos_eint_gpio_init,
+               .suspend        = exynos_pinctrl_suspend,
+               .resume         = exynos_pinctrl_resume,
+               .label          = "exynos5250-gpio-ctrl3",
+       },
+};
+
+/* pin banks of exynos5260 pin-controller 0 */
+static struct samsung_pin_bank exynos5260_pin_banks0[] = {
+       EXYNOS_PIN_BANK_EINTG(4, 0x000, "gpa0", 0x00),
+       EXYNOS_PIN_BANK_EINTG(7, 0x020, "gpa1", 0x04),
+       EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpa2", 0x08),
+       EXYNOS_PIN_BANK_EINTG(5, 0x060, "gpb0", 0x0c),
+       EXYNOS_PIN_BANK_EINTG(4, 0x080, "gpb1", 0x10),
+       EXYNOS_PIN_BANK_EINTG(5, 0x0a0, "gpb2", 0x14),
+       EXYNOS_PIN_BANK_EINTG(8, 0x0c0, "gpb3", 0x18),
+       EXYNOS_PIN_BANK_EINTG(8, 0x0e0, "gpb4", 0x1c),
+       EXYNOS_PIN_BANK_EINTG(8, 0x100, "gpb5", 0x20),
+       EXYNOS_PIN_BANK_EINTG(8, 0x120, "gpd0", 0x24),
+       EXYNOS_PIN_BANK_EINTG(7, 0x140, "gpd1", 0x28),
+       EXYNOS_PIN_BANK_EINTG(5, 0x160, "gpd2", 0x2c),
+       EXYNOS_PIN_BANK_EINTG(8, 0x180, "gpe0", 0x30),
+       EXYNOS_PIN_BANK_EINTG(5, 0x1a0, "gpe1", 0x34),
+       EXYNOS_PIN_BANK_EINTG(4, 0x1c0, "gpf0", 0x38),
+       EXYNOS_PIN_BANK_EINTG(8, 0x1e0, "gpf1", 0x3c),
+       EXYNOS_PIN_BANK_EINTG(2, 0x200, "gpk0", 0x40),
+       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 exynos5260 pin-controller 1 */
+static struct samsung_pin_bank exynos5260_pin_banks1[] = {
+       EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpc0", 0x00),
+       EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpc1", 0x04),
+       EXYNOS_PIN_BANK_EINTG(7, 0x040, "gpc2", 0x08),
+       EXYNOS_PIN_BANK_EINTG(4, 0x060, "gpc3", 0x0c),
+       EXYNOS_PIN_BANK_EINTG(4, 0x080, "gpc4", 0x10),
+};
+
+/* pin banks of exynos5260 pin-controller 2 */
+static struct samsung_pin_bank exynos5260_pin_banks2[] = {
+       EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz0", 0x00),
+       EXYNOS_PIN_BANK_EINTG(4, 0x020, "gpz1", 0x04),
+};
+
+/*
+ * Samsung pinctrl driver data for Exynos5260 SoC. Exynos5260 SoC includes
+ * three gpio/pin-mux/pinconfig controllers.
+ */
+struct samsung_pin_ctrl exynos5260_pin_ctrl[] = {
+       {
+               /* pin-controller instance 0 data */
+               .pin_banks      = exynos5260_pin_banks0,
+               .nr_banks       = ARRAY_SIZE(exynos5260_pin_banks0),
+               .eint_gpio_init = exynos_eint_gpio_init,
+               .eint_wkup_init = exynos_eint_wkup_init,
+               .label          = "exynos5260-gpio-ctrl0",
+       }, {
+               /* pin-controller instance 1 data */
+               .pin_banks      = exynos5260_pin_banks1,
+               .nr_banks       = ARRAY_SIZE(exynos5260_pin_banks1),
+               .eint_gpio_init = exynos_eint_gpio_init,
+               .label          = "exynos5260-gpio-ctrl1",
+       }, {
+               /* pin-controller instance 2 data */
+               .pin_banks      = exynos5260_pin_banks2,
+               .nr_banks       = ARRAY_SIZE(exynos5260_pin_banks2),
+               .eint_gpio_init = exynos_eint_gpio_init,
+               .label          = "exynos5260-gpio-ctrl2",
+       },
+};
+
+/* pin banks of exynos5420 pin-controller 0 */
+static struct samsung_pin_bank exynos5420_pin_banks0[] = {
+       EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpy7", 0x00),
+       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 exynos5420 pin-controller 1 */
+static struct samsung_pin_bank exynos5420_pin_banks1[] = {
+       EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpc0", 0x00),
+       EXYNOS_PIN_BANK_EINTG(8, 0x020, "gpc1", 0x04),
+       EXYNOS_PIN_BANK_EINTG(7, 0x040, "gpc2", 0x08),
+       EXYNOS_PIN_BANK_EINTG(4, 0x060, "gpc3", 0x0c),
+       EXYNOS_PIN_BANK_EINTG(2, 0x080, "gpc4", 0x10),
+       EXYNOS_PIN_BANK_EINTG(8, 0x0A0, "gpd1", 0x14),
+       EXYNOS_PIN_BANK_EINTN(6, 0x0C0, "gpy0"),
+       EXYNOS_PIN_BANK_EINTN(4, 0x0E0, "gpy1"),
+       EXYNOS_PIN_BANK_EINTN(6, 0x100, "gpy2"),
+       EXYNOS_PIN_BANK_EINTN(8, 0x120, "gpy3"),
+       EXYNOS_PIN_BANK_EINTN(8, 0x140, "gpy4"),
+       EXYNOS_PIN_BANK_EINTN(8, 0x160, "gpy5"),
+       EXYNOS_PIN_BANK_EINTN(8, 0x180, "gpy6"),
+};
+
+/* pin banks of exynos5420 pin-controller 2 */
+static struct samsung_pin_bank exynos5420_pin_banks2[] = {
+       EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpe0", 0x00),
+       EXYNOS_PIN_BANK_EINTG(2, 0x020, "gpe1", 0x04),
+       EXYNOS_PIN_BANK_EINTG(6, 0x040, "gpf0", 0x08),
+       EXYNOS_PIN_BANK_EINTG(8, 0x060, "gpf1", 0x0c),
+       EXYNOS_PIN_BANK_EINTG(8, 0x080, "gpg0", 0x10),
+       EXYNOS_PIN_BANK_EINTG(8, 0x0A0, "gpg1", 0x14),
+       EXYNOS_PIN_BANK_EINTG(2, 0x0C0, "gpg2", 0x18),
+       EXYNOS_PIN_BANK_EINTG(4, 0x0E0, "gpj4", 0x1c),
+};
+
+/* pin banks of exynos5420 pin-controller 3 */
+static struct samsung_pin_bank exynos5420_pin_banks3[] = {
+       EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
+       EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpa1", 0x04),
+       EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpa2", 0x08),
+       EXYNOS_PIN_BANK_EINTG(5, 0x060, "gpb0", 0x0c),
+       EXYNOS_PIN_BANK_EINTG(5, 0x080, "gpb1", 0x10),
+       EXYNOS_PIN_BANK_EINTG(4, 0x0A0, "gpb2", 0x14),
+       EXYNOS_PIN_BANK_EINTG(8, 0x0C0, "gpb3", 0x18),
+       EXYNOS_PIN_BANK_EINTG(2, 0x0E0, "gpb4", 0x1c),
+       EXYNOS_PIN_BANK_EINTG(8, 0x100, "gph0", 0x20),
+};
+
+/* pin banks of exynos5420 pin-controller 4 */
+static struct samsung_pin_bank exynos5420_pin_banks4[] = {
+       EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz", 0x00),
+};
+
+/*
+ * Samsung pinctrl driver data for Exynos5420 SoC. Exynos5420 SoC includes
+ * four gpio/pin-mux/pinconfig controllers.
+ */
+struct samsung_pin_ctrl exynos5420_pin_ctrl[] = {
+       {
+               /* pin-controller instance 0 data */
+               .pin_banks      = exynos5420_pin_banks0,
+               .nr_banks       = ARRAY_SIZE(exynos5420_pin_banks0),
+               .eint_gpio_init = exynos_eint_gpio_init,
+               .eint_wkup_init = exynos_eint_wkup_init,
+               .label          = "exynos5420-gpio-ctrl0",
+       }, {
+               /* pin-controller instance 1 data */
+               .pin_banks      = exynos5420_pin_banks1,
+               .nr_banks       = ARRAY_SIZE(exynos5420_pin_banks1),
+               .eint_gpio_init = exynos_eint_gpio_init,
+               .label          = "exynos5420-gpio-ctrl1",
+       }, {
+               /* pin-controller instance 2 data */
+               .pin_banks      = exynos5420_pin_banks2,
+               .nr_banks       = ARRAY_SIZE(exynos5420_pin_banks2),
+               .eint_gpio_init = exynos_eint_gpio_init,
+               .label          = "exynos5420-gpio-ctrl2",
+       }, {
+               /* pin-controller instance 3 data */
+               .pin_banks      = exynos5420_pin_banks3,
+               .nr_banks       = ARRAY_SIZE(exynos5420_pin_banks3),
+               .eint_gpio_init = exynos_eint_gpio_init,
+               .label          = "exynos5420-gpio-ctrl3",
+       }, {
+               /* pin-controller instance 4 data */
+               .pin_banks      = exynos5420_pin_banks4,
+               .nr_banks       = ARRAY_SIZE(exynos5420_pin_banks4),
+               .eint_gpio_init = exynos_eint_gpio_init,
+               .label          = "exynos5420-gpio-ctrl4",
+       },
+};
diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.h b/drivers/pinctrl/samsung/pinctrl-exynos.h
new file mode 100644 (file)
index 0000000..3c91c35
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Exynos specific definitions for Samsung pinctrl and gpiolib driver.
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ * Copyright (c) 2012 Linaro Ltd
+ *             http://www.linaro.org
+ *
+ * This file contains the Exynos specific definitions for the Samsung
+ * pinctrl/gpiolib interface drivers.
+ *
+ * Author: Thomas Abraham <thomas.ab@samsung.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; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+/* External GPIO and wakeup interrupt related definitions */
+#define EXYNOS_GPIO_ECON_OFFSET                0x700
+#define EXYNOS_GPIO_EFLTCON_OFFSET     0x800
+#define EXYNOS_GPIO_EMASK_OFFSET       0x900
+#define EXYNOS_GPIO_EPEND_OFFSET       0xA00
+#define EXYNOS_WKUP_ECON_OFFSET                0xE00
+#define EXYNOS_WKUP_EMASK_OFFSET       0xF00
+#define EXYNOS_WKUP_EPEND_OFFSET       0xF40
+#define EXYNOS_SVC_OFFSET              0xB08
+#define EXYNOS_EINT_FUNC               0xF
+
+/* helpers to access interrupt service register */
+#define EXYNOS_SVC_GROUP_SHIFT         3
+#define EXYNOS_SVC_GROUP_MASK          0x1f
+#define EXYNOS_SVC_NUM_MASK            7
+#define EXYNOS_SVC_GROUP(x)            ((x >> EXYNOS_SVC_GROUP_SHIFT) & \
+                                               EXYNOS_SVC_GROUP_MASK)
+
+/* Exynos specific external interrupt trigger types */
+#define EXYNOS_EINT_LEVEL_LOW          0
+#define EXYNOS_EINT_LEVEL_HIGH         1
+#define EXYNOS_EINT_EDGE_FALLING       2
+#define EXYNOS_EINT_EDGE_RISING                3
+#define EXYNOS_EINT_EDGE_BOTH          4
+#define EXYNOS_EINT_CON_MASK           0xF
+#define EXYNOS_EINT_CON_LEN            4
+
+#define EXYNOS_EINT_MAX_PER_BANK       8
+#define EXYNOS_EINT_NR_WKUP_EINT
+
+#define EXYNOS_PIN_BANK_EINTN(pins, reg, id)           \
+       {                                               \
+               .type           = &bank_type_off,       \
+               .pctl_offset    = reg,                  \
+               .nr_pins        = pins,                 \
+               .eint_type      = EINT_TYPE_NONE,       \
+               .name           = id                    \
+       }
+
+#define EXYNOS_PIN_BANK_EINTG(pins, reg, id, offs)     \
+       {                                               \
+               .type           = &bank_type_off,       \
+               .pctl_offset    = reg,                  \
+               .nr_pins        = pins,                 \
+               .eint_type      = EINT_TYPE_GPIO,       \
+               .eint_offset    = offs,                 \
+               .name           = id                    \
+       }
+
+#define EXYNOS_PIN_BANK_EINTW(pins, reg, id, offs)     \
+       {                                               \
+               .type           = &bank_type_alive,     \
+               .pctl_offset    = reg,                  \
+               .nr_pins        = pins,                 \
+               .eint_type      = EINT_TYPE_WKUP,       \
+               .eint_offset    = offs,                 \
+               .name           = id                    \
+       }
+
+/**
+ * struct exynos_weint_data: irq specific data for all the wakeup interrupts
+ * generated by the external wakeup interrupt controller.
+ * @irq: interrupt number within the domain.
+ * @bank: bank responsible for this interrupt
+ */
+struct exynos_weint_data {
+       unsigned int irq;
+       struct samsung_pin_bank *bank;
+};
+
+/**
+ * struct exynos_muxed_weint_data: irq specific data for muxed wakeup interrupts
+ * generated by the external wakeup interrupt controller.
+ * @nr_banks: count of banks being part of the mux
+ * @banks: array of banks being part of the mux
+ */
+struct exynos_muxed_weint_data {
+       unsigned int nr_banks;
+       struct samsung_pin_bank *banks[];
+};
diff --git a/drivers/pinctrl/samsung/pinctrl-exynos5440.c b/drivers/pinctrl/samsung/pinctrl-exynos5440.c
new file mode 100644 (file)
index 0000000..603da2f
--- /dev/null
@@ -0,0 +1,1061 @@
+/*
+ * pin-controller/pin-mux/pin-config/gpio-driver for Samsung's EXYNOS5440 SoC.
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.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; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/device.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/of_irq.h>
+#include "../core.h"
+
+/* EXYNOS5440 GPIO and Pinctrl register offsets */
+#define GPIO_MUX               0x00
+#define GPIO_IE                        0x04
+#define GPIO_INT               0x08
+#define GPIO_TYPE              0x0C
+#define GPIO_VAL               0x10
+#define GPIO_OE                        0x14
+#define GPIO_IN                        0x18
+#define GPIO_PE                        0x1C
+#define GPIO_PS                        0x20
+#define GPIO_SR                        0x24
+#define GPIO_DS0               0x28
+#define GPIO_DS1               0x2C
+
+#define EXYNOS5440_MAX_PINS            23
+#define EXYNOS5440_MAX_GPIO_INT        8
+#define PIN_NAME_LENGTH                10
+
+#define GROUP_SUFFIX           "-grp"
+#define GSUFFIX_LEN            sizeof(GROUP_SUFFIX)
+#define FUNCTION_SUFFIX                "-mux"
+#define FSUFFIX_LEN            sizeof(FUNCTION_SUFFIX)
+
+/*
+ * pin configuration type and its value are packed together into a 16-bits.
+ * The upper 8-bits represent the configuration type and the lower 8-bits
+ * hold the value of the configuration type.
+ */
+#define PINCFG_TYPE_MASK               0xFF
+#define PINCFG_VALUE_SHIFT             8
+#define PINCFG_VALUE_MASK              (0xFF << PINCFG_VALUE_SHIFT)
+#define PINCFG_PACK(type, value)       (((value) << PINCFG_VALUE_SHIFT) | type)
+#define PINCFG_UNPACK_TYPE(cfg)                ((cfg) & PINCFG_TYPE_MASK)
+#define PINCFG_UNPACK_VALUE(cfg)       (((cfg) & PINCFG_VALUE_MASK) >> \
+                                               PINCFG_VALUE_SHIFT)
+
+/**
+ * enum pincfg_type - possible pin configuration types supported.
+ * @PINCFG_TYPE_PUD: Pull up/down configuration.
+ * @PINCFG_TYPE_DRV: Drive strength configuration.
+ * @PINCFG_TYPE_SKEW_RATE: Skew rate configuration.
+ * @PINCFG_TYPE_INPUT_TYPE: Pin input type configuration.
+ */
+enum pincfg_type {
+       PINCFG_TYPE_PUD,
+       PINCFG_TYPE_DRV,
+       PINCFG_TYPE_SKEW_RATE,
+       PINCFG_TYPE_INPUT_TYPE
+};
+
+/**
+ * struct exynos5440_pin_group: represent group of pins for pincfg setting.
+ * @name: name of the pin group, used to lookup the group.
+ * @pins: the pins included in this group.
+ * @num_pins: number of pins included in this group.
+ */
+struct exynos5440_pin_group {
+       const char              *name;
+       const unsigned int      *pins;
+       u8                      num_pins;
+};
+
+/**
+ * struct exynos5440_pmx_func: represent a pin function.
+ * @name: name of the pin function, used to lookup the function.
+ * @groups: one or more names of pin groups that provide this function.
+ * @num_groups: number of groups included in @groups.
+ * @function: the function number to be programmed when selected.
+ */
+struct exynos5440_pmx_func {
+       const char              *name;
+       const char              **groups;
+       u8                      num_groups;
+       unsigned long           function;
+};
+
+/**
+ * struct exynos5440_pinctrl_priv_data: driver's private runtime data.
+ * @reg_base: ioremapped based address of the register space.
+ * @gc: gpio chip registered with gpiolib.
+ * @pin_groups: list of pin groups parsed from device tree.
+ * @nr_groups: number of pin groups available.
+ * @pmx_functions: list of pin functions parsed from device tree.
+ * @nr_functions: number of pin functions available.
+ */
+struct exynos5440_pinctrl_priv_data {
+       void __iomem                    *reg_base;
+       struct gpio_chip                *gc;
+       struct irq_domain               *irq_domain;
+
+       const struct exynos5440_pin_group       *pin_groups;
+       unsigned int                    nr_groups;
+       const struct exynos5440_pmx_func        *pmx_functions;
+       unsigned int                    nr_functions;
+};
+
+/**
+ * struct exynos5440_gpio_intr_data: private data for gpio interrupts.
+ * @priv: driver's private runtime data.
+ * @gpio_int: gpio interrupt number.
+ */
+struct exynos5440_gpio_intr_data {
+       struct exynos5440_pinctrl_priv_data     *priv;
+       unsigned int                            gpio_int;
+};
+
+/* list of all possible config options supported */
+static struct pin_config {
+       char            *prop_cfg;
+       unsigned int    cfg_type;
+} pcfgs[] = {
+       { "samsung,exynos5440-pin-pud", PINCFG_TYPE_PUD },
+       { "samsung,exynos5440-pin-drv", PINCFG_TYPE_DRV },
+       { "samsung,exynos5440-pin-skew-rate", PINCFG_TYPE_SKEW_RATE },
+       { "samsung,exynos5440-pin-input-type", PINCFG_TYPE_INPUT_TYPE },
+};
+
+/* check if the selector is a valid pin group selector */
+static int exynos5440_get_group_count(struct pinctrl_dev *pctldev)
+{
+       struct exynos5440_pinctrl_priv_data *priv;
+
+       priv = pinctrl_dev_get_drvdata(pctldev);
+       return priv->nr_groups;
+}
+
+/* return the name of the group selected by the group selector */
+static const char *exynos5440_get_group_name(struct pinctrl_dev *pctldev,
+                                               unsigned selector)
+{
+       struct exynos5440_pinctrl_priv_data *priv;
+
+       priv = pinctrl_dev_get_drvdata(pctldev);
+       return priv->pin_groups[selector].name;
+}
+
+/* return the pin numbers associated with the specified group */
+static int exynos5440_get_group_pins(struct pinctrl_dev *pctldev,
+               unsigned selector, const unsigned **pins, unsigned *num_pins)
+{
+       struct exynos5440_pinctrl_priv_data *priv;
+
+       priv = pinctrl_dev_get_drvdata(pctldev);
+       *pins = priv->pin_groups[selector].pins;
+       *num_pins = priv->pin_groups[selector].num_pins;
+       return 0;
+}
+
+/* create pinctrl_map entries by parsing device tree nodes */
+static int exynos5440_dt_node_to_map(struct pinctrl_dev *pctldev,
+                       struct device_node *np, struct pinctrl_map **maps,
+                       unsigned *nmaps)
+{
+       struct device *dev = pctldev->dev;
+       struct pinctrl_map *map;
+       unsigned long *cfg = NULL;
+       char *gname, *fname;
+       int cfg_cnt = 0, map_cnt = 0, idx = 0;
+
+       /* count the number of config options specfied in the node */
+       for (idx = 0; idx < ARRAY_SIZE(pcfgs); idx++)
+               if (of_find_property(np, pcfgs[idx].prop_cfg, NULL))
+                       cfg_cnt++;
+
+       /*
+        * Find out the number of map entries to create. All the config options
+        * can be accomadated into a single config map entry.
+        */
+       if (cfg_cnt)
+               map_cnt = 1;
+       if (of_find_property(np, "samsung,exynos5440-pin-function", NULL))
+               map_cnt++;
+       if (!map_cnt) {
+               dev_err(dev, "node %s does not have either config or function "
+                               "configurations\n", np->name);
+               return -EINVAL;
+       }
+
+       /* Allocate memory for pin-map entries */
+       map = kzalloc(sizeof(*map) * map_cnt, GFP_KERNEL);
+       if (!map) {
+               dev_err(dev, "could not alloc memory for pin-maps\n");
+               return -ENOMEM;
+       }
+       *nmaps = 0;
+
+       /*
+        * Allocate memory for pin group name. The pin group name is derived
+        * from the node name from which these map entries are be created.
+        */
+       gname = kzalloc(strlen(np->name) + GSUFFIX_LEN, GFP_KERNEL);
+       if (!gname) {
+               dev_err(dev, "failed to alloc memory for group name\n");
+               goto free_map;
+       }
+       snprintf(gname, strlen(np->name) + 4, "%s%s", np->name, GROUP_SUFFIX);
+
+       /*
+        * don't have config options? then skip over to creating function
+        * map entries.
+        */
+       if (!cfg_cnt)
+               goto skip_cfgs;
+
+       /* Allocate memory for config entries */
+       cfg = kzalloc(sizeof(*cfg) * cfg_cnt, GFP_KERNEL);
+       if (!cfg) {
+               dev_err(dev, "failed to alloc memory for configs\n");
+               goto free_gname;
+       }
+
+       /* Prepare a list of config settings */
+       for (idx = 0, cfg_cnt = 0; idx < ARRAY_SIZE(pcfgs); idx++) {
+               u32 value;
+               if (!of_property_read_u32(np, pcfgs[idx].prop_cfg, &value))
+                       cfg[cfg_cnt++] =
+                               PINCFG_PACK(pcfgs[idx].cfg_type, value);
+       }
+
+       /* create the config map entry */
+       map[*nmaps].data.configs.group_or_pin = gname;
+       map[*nmaps].data.configs.configs = cfg;
+       map[*nmaps].data.configs.num_configs = cfg_cnt;
+       map[*nmaps].type = PIN_MAP_TYPE_CONFIGS_GROUP;
+       *nmaps += 1;
+
+skip_cfgs:
+       /* create the function map entry */
+       if (of_find_property(np, "samsung,exynos5440-pin-function", NULL)) {
+               fname = kzalloc(strlen(np->name) + FSUFFIX_LEN, GFP_KERNEL);
+               if (!fname) {
+                       dev_err(dev, "failed to alloc memory for func name\n");
+                       goto free_cfg;
+               }
+               snprintf(fname, strlen(np->name) + 4, "%s%s", np->name,
+                        FUNCTION_SUFFIX);
+
+               map[*nmaps].data.mux.group = gname;
+               map[*nmaps].data.mux.function = fname;
+               map[*nmaps].type = PIN_MAP_TYPE_MUX_GROUP;
+               *nmaps += 1;
+       }
+
+       *maps = map;
+       return 0;
+
+free_cfg:
+       kfree(cfg);
+free_gname:
+       kfree(gname);
+free_map:
+       kfree(map);
+       return -ENOMEM;
+}
+
+/* free the memory allocated to hold the pin-map table */
+static void exynos5440_dt_free_map(struct pinctrl_dev *pctldev,
+                            struct pinctrl_map *map, unsigned num_maps)
+{
+       int idx;
+
+       for (idx = 0; idx < num_maps; idx++) {
+               if (map[idx].type == PIN_MAP_TYPE_MUX_GROUP) {
+                       kfree(map[idx].data.mux.function);
+                       if (!idx)
+                               kfree(map[idx].data.mux.group);
+               } else if (map->type == PIN_MAP_TYPE_CONFIGS_GROUP) {
+                       kfree(map[idx].data.configs.configs);
+                       if (!idx)
+                               kfree(map[idx].data.configs.group_or_pin);
+               }
+       };
+
+       kfree(map);
+}
+
+/* list of pinctrl callbacks for the pinctrl core */
+static const struct pinctrl_ops exynos5440_pctrl_ops = {
+       .get_groups_count       = exynos5440_get_group_count,
+       .get_group_name         = exynos5440_get_group_name,
+       .get_group_pins         = exynos5440_get_group_pins,
+       .dt_node_to_map         = exynos5440_dt_node_to_map,
+       .dt_free_map            = exynos5440_dt_free_map,
+};
+
+/* check if the selector is a valid pin function selector */
+static int exynos5440_get_functions_count(struct pinctrl_dev *pctldev)
+{
+       struct exynos5440_pinctrl_priv_data *priv;
+
+       priv = pinctrl_dev_get_drvdata(pctldev);
+       return priv->nr_functions;
+}
+
+/* return the name of the pin function specified */
+static const char *exynos5440_pinmux_get_fname(struct pinctrl_dev *pctldev,
+                                               unsigned selector)
+{
+       struct exynos5440_pinctrl_priv_data *priv;
+
+       priv = pinctrl_dev_get_drvdata(pctldev);
+       return priv->pmx_functions[selector].name;
+}
+
+/* return the groups associated for the specified function selector */
+static int exynos5440_pinmux_get_groups(struct pinctrl_dev *pctldev,
+               unsigned selector, const char * const **groups,
+               unsigned * const num_groups)
+{
+       struct exynos5440_pinctrl_priv_data *priv;
+
+       priv = pinctrl_dev_get_drvdata(pctldev);
+       *groups = priv->pmx_functions[selector].groups;
+       *num_groups = priv->pmx_functions[selector].num_groups;
+       return 0;
+}
+
+/* enable or disable a pinmux function */
+static void exynos5440_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector,
+                                       unsigned group, bool enable)
+{
+       struct exynos5440_pinctrl_priv_data *priv;
+       void __iomem *base;
+       u32 function;
+       u32 data;
+
+       priv = pinctrl_dev_get_drvdata(pctldev);
+       base = priv->reg_base;
+       function = priv->pmx_functions[selector].function;
+
+       data = readl(base + GPIO_MUX);
+       if (enable)
+               data |= (1 << function);
+       else
+               data &= ~(1 << function);
+       writel(data, base + GPIO_MUX);
+}
+
+/* enable a specified pinmux by writing to registers */
+static int exynos5440_pinmux_enable(struct pinctrl_dev *pctldev, unsigned selector,
+                                       unsigned group)
+{
+       exynos5440_pinmux_setup(pctldev, selector, group, true);
+       return 0;
+}
+
+/*
+ * The calls to gpio_direction_output() and gpio_direction_input()
+ * leads to this function call (via the pinctrl_gpio_direction_{input|output}()
+ * function called from the gpiolib interface).
+ */
+static int exynos5440_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev,
+               struct pinctrl_gpio_range *range, unsigned offset, bool input)
+{
+       return 0;
+}
+
+/* list of pinmux callbacks for the pinmux vertical in pinctrl core */
+static const struct pinmux_ops exynos5440_pinmux_ops = {
+       .get_functions_count    = exynos5440_get_functions_count,
+       .get_function_name      = exynos5440_pinmux_get_fname,
+       .get_function_groups    = exynos5440_pinmux_get_groups,
+       .enable                 = exynos5440_pinmux_enable,
+       .gpio_set_direction     = exynos5440_pinmux_gpio_set_direction,
+};
+
+/* set the pin config settings for a specified pin */
+static int exynos5440_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
+                               unsigned long *configs,
+                               unsigned num_configs)
+{
+       struct exynos5440_pinctrl_priv_data *priv;
+       void __iomem *base;
+       enum pincfg_type cfg_type;
+       u32 cfg_value;
+       u32 data;
+       int i;
+
+       priv = pinctrl_dev_get_drvdata(pctldev);
+       base = priv->reg_base;
+
+       for (i = 0; i < num_configs; i++) {
+               cfg_type = PINCFG_UNPACK_TYPE(configs[i]);
+               cfg_value = PINCFG_UNPACK_VALUE(configs[i]);
+
+               switch (cfg_type) {
+               case PINCFG_TYPE_PUD:
+                       /* first set pull enable/disable bit */
+                       data = readl(base + GPIO_PE);
+                       data &= ~(1 << pin);
+                       if (cfg_value)
+                               data |= (1 << pin);
+                       writel(data, base + GPIO_PE);
+
+                       /* then set pull up/down bit */
+                       data = readl(base + GPIO_PS);
+                       data &= ~(1 << pin);
+                       if (cfg_value == 2)
+                               data |= (1 << pin);
+                       writel(data, base + GPIO_PS);
+                       break;
+
+               case PINCFG_TYPE_DRV:
+                       /* set the first bit of the drive strength */
+                       data = readl(base + GPIO_DS0);
+                       data &= ~(1 << pin);
+                       data |= ((cfg_value & 1) << pin);
+                       writel(data, base + GPIO_DS0);
+                       cfg_value >>= 1;
+
+                       /* set the second bit of the driver strength */
+                       data = readl(base + GPIO_DS1);
+                       data &= ~(1 << pin);
+                       data |= ((cfg_value & 1) << pin);
+                       writel(data, base + GPIO_DS1);
+                       break;
+               case PINCFG_TYPE_SKEW_RATE:
+                       data = readl(base + GPIO_SR);
+                       data &= ~(1 << pin);
+                       data |= ((cfg_value & 1) << pin);
+                       writel(data, base + GPIO_SR);
+                       break;
+               case PINCFG_TYPE_INPUT_TYPE:
+                       data = readl(base + GPIO_TYPE);
+                       data &= ~(1 << pin);
+                       data |= ((cfg_value & 1) << pin);
+                       writel(data, base + GPIO_TYPE);
+                       break;
+               default:
+                       WARN_ON(1);
+                       return -EINVAL;
+               }
+       } /* for each config */
+
+       return 0;
+}
+
+/* get the pin config settings for a specified pin */
+static int exynos5440_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin,
+                                       unsigned long *config)
+{
+       struct exynos5440_pinctrl_priv_data *priv;
+       void __iomem *base;
+       enum pincfg_type cfg_type = PINCFG_UNPACK_TYPE(*config);
+       u32 data;
+
+       priv = pinctrl_dev_get_drvdata(pctldev);
+       base = priv->reg_base;
+
+       switch (cfg_type) {
+       case PINCFG_TYPE_PUD:
+               data = readl(base + GPIO_PE);
+               data = (data >> pin) & 1;
+               if (!data)
+                       *config = 0;
+               else
+                       *config = ((readl(base + GPIO_PS) >> pin) & 1) + 1;
+               break;
+       case PINCFG_TYPE_DRV:
+               data = readl(base + GPIO_DS0);
+               data = (data >> pin) & 1;
+               *config = data;
+               data = readl(base + GPIO_DS1);
+               data = (data >> pin) & 1;
+               *config |= (data << 1);
+               break;
+       case PINCFG_TYPE_SKEW_RATE:
+               data = readl(base + GPIO_SR);
+               *config = (data >> pin) & 1;
+               break;
+       case PINCFG_TYPE_INPUT_TYPE:
+               data = readl(base + GPIO_TYPE);
+               *config = (data >> pin) & 1;
+               break;
+       default:
+               WARN_ON(1);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* set the pin config settings for a specified pin group */
+static int exynos5440_pinconf_group_set(struct pinctrl_dev *pctldev,
+                       unsigned group, unsigned long *configs,
+                       unsigned num_configs)
+{
+       struct exynos5440_pinctrl_priv_data *priv;
+       const unsigned int *pins;
+       unsigned int cnt;
+
+       priv = pinctrl_dev_get_drvdata(pctldev);
+       pins = priv->pin_groups[group].pins;
+
+       for (cnt = 0; cnt < priv->pin_groups[group].num_pins; cnt++)
+               exynos5440_pinconf_set(pctldev, pins[cnt], configs,
+                                      num_configs);
+
+       return 0;
+}
+
+/* get the pin config settings for a specified pin group */
+static int exynos5440_pinconf_group_get(struct pinctrl_dev *pctldev,
+                               unsigned int group, unsigned long *config)
+{
+       struct exynos5440_pinctrl_priv_data *priv;
+       const unsigned int *pins;
+
+       priv = pinctrl_dev_get_drvdata(pctldev);
+       pins = priv->pin_groups[group].pins;
+       exynos5440_pinconf_get(pctldev, pins[0], config);
+       return 0;
+}
+
+/* list of pinconfig callbacks for pinconfig vertical in the pinctrl code */
+static const struct pinconf_ops exynos5440_pinconf_ops = {
+       .pin_config_get         = exynos5440_pinconf_get,
+       .pin_config_set         = exynos5440_pinconf_set,
+       .pin_config_group_get   = exynos5440_pinconf_group_get,
+       .pin_config_group_set   = exynos5440_pinconf_group_set,
+};
+
+/* gpiolib gpio_set callback function */
+static void exynos5440_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
+{
+       struct exynos5440_pinctrl_priv_data *priv = dev_get_drvdata(gc->dev);
+       void __iomem *base = priv->reg_base;
+       u32 data;
+
+       data = readl(base + GPIO_VAL);
+       data &= ~(1 << offset);
+       if (value)
+               data |= 1 << offset;
+       writel(data, base + GPIO_VAL);
+}
+
+/* gpiolib gpio_get callback function */
+static int exynos5440_gpio_get(struct gpio_chip *gc, unsigned offset)
+{
+       struct exynos5440_pinctrl_priv_data *priv = dev_get_drvdata(gc->dev);
+       void __iomem *base = priv->reg_base;
+       u32 data;
+
+       data = readl(base + GPIO_IN);
+       data >>= offset;
+       data &= 1;
+       return data;
+}
+
+/* gpiolib gpio_direction_input callback function */
+static int exynos5440_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
+{
+       struct exynos5440_pinctrl_priv_data *priv = dev_get_drvdata(gc->dev);
+       void __iomem *base = priv->reg_base;
+       u32 data;
+
+       /* first disable the data output enable on this pin */
+       data = readl(base + GPIO_OE);
+       data &= ~(1 << offset);
+       writel(data, base + GPIO_OE);
+
+       /* now enable input on this pin */
+       data =  readl(base + GPIO_IE);
+       data |= 1 << offset;
+       writel(data, base + GPIO_IE);
+       return 0;
+}
+
+/* gpiolib gpio_direction_output callback function */
+static int exynos5440_gpio_direction_output(struct gpio_chip *gc, unsigned offset,
+                                                       int value)
+{
+       struct exynos5440_pinctrl_priv_data *priv = dev_get_drvdata(gc->dev);
+       void __iomem *base = priv->reg_base;
+       u32 data;
+
+       exynos5440_gpio_set(gc, offset, value);
+
+       /* first disable the data input enable on this pin */
+       data = readl(base + GPIO_IE);
+       data &= ~(1 << offset);
+       writel(data, base + GPIO_IE);
+
+       /* now enable output on this pin */
+       data =  readl(base + GPIO_OE);
+       data |= 1 << offset;
+       writel(data, base + GPIO_OE);
+       return 0;
+}
+
+/* gpiolib gpio_to_irq callback function */
+static int exynos5440_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
+{
+       struct exynos5440_pinctrl_priv_data *priv = dev_get_drvdata(gc->dev);
+       unsigned int virq;
+
+       if (offset < 16 || offset > 23)
+               return -ENXIO;
+
+       if (!priv->irq_domain)
+               return -ENXIO;
+
+       virq = irq_create_mapping(priv->irq_domain, offset - 16);
+       return virq ? : -ENXIO;
+}
+
+/* parse the pin numbers listed in the 'samsung,exynos5440-pins' property */
+static int exynos5440_pinctrl_parse_dt_pins(struct platform_device *pdev,
+                       struct device_node *cfg_np, unsigned int **pin_list,
+                       unsigned int *npins)
+{
+       struct device *dev = &pdev->dev;
+       struct property *prop;
+
+       prop = of_find_property(cfg_np, "samsung,exynos5440-pins", NULL);
+       if (!prop)
+               return -ENOENT;
+
+       *npins = prop->length / sizeof(unsigned long);
+       if (!*npins) {
+               dev_err(dev, "invalid pin list in %s node", cfg_np->name);
+               return -EINVAL;
+       }
+
+       *pin_list = devm_kzalloc(dev, *npins * sizeof(**pin_list), GFP_KERNEL);
+       if (!*pin_list) {
+               dev_err(dev, "failed to allocate memory for pin list\n");
+               return -ENOMEM;
+       }
+
+       return of_property_read_u32_array(cfg_np, "samsung,exynos5440-pins",
+                       *pin_list, *npins);
+}
+
+/*
+ * Parse the information about all the available pin groups and pin functions
+ * from device node of the pin-controller.
+ */
+static int exynos5440_pinctrl_parse_dt(struct platform_device *pdev,
+                               struct exynos5440_pinctrl_priv_data *priv)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *dev_np = dev->of_node;
+       struct device_node *cfg_np;
+       struct exynos5440_pin_group *groups, *grp;
+       struct exynos5440_pmx_func *functions, *func;
+       unsigned *pin_list;
+       unsigned int npins, grp_cnt, func_idx = 0;
+       char *gname, *fname;
+       int ret;
+
+       grp_cnt = of_get_child_count(dev_np);
+       if (!grp_cnt)
+               return -EINVAL;
+
+       groups = devm_kzalloc(dev, grp_cnt * sizeof(*groups), GFP_KERNEL);
+       if (!groups) {
+               dev_err(dev, "failed allocate memory for ping group list\n");
+               return -EINVAL;
+       }
+       grp = groups;
+
+       functions = devm_kzalloc(dev, grp_cnt * sizeof(*functions), GFP_KERNEL);
+       if (!functions) {
+               dev_err(dev, "failed to allocate memory for function list\n");
+               return -EINVAL;
+       }
+       func = functions;
+
+       /*
+        * Iterate over all the child nodes of the pin controller node
+        * and create pin groups and pin function lists.
+        */
+       for_each_child_of_node(dev_np, cfg_np) {
+               u32 function;
+
+               ret = exynos5440_pinctrl_parse_dt_pins(pdev, cfg_np,
+                                       &pin_list, &npins);
+               if (ret) {
+                       gname = NULL;
+                       goto skip_to_pin_function;
+               }
+
+               /* derive pin group name from the node name */
+               gname = devm_kzalloc(dev, strlen(cfg_np->name) + GSUFFIX_LEN,
+                                       GFP_KERNEL);
+               if (!gname) {
+                       dev_err(dev, "failed to alloc memory for group name\n");
+                       return -ENOMEM;
+               }
+               snprintf(gname, strlen(cfg_np->name) + 4, "%s%s", cfg_np->name,
+                        GROUP_SUFFIX);
+
+               grp->name = gname;
+               grp->pins = pin_list;
+               grp->num_pins = npins;
+               grp++;
+
+skip_to_pin_function:
+               ret = of_property_read_u32(cfg_np, "samsung,exynos5440-pin-function",
+                                               &function);
+               if (ret)
+                       continue;
+
+               /* derive function name from the node name */
+               fname = devm_kzalloc(dev, strlen(cfg_np->name) + FSUFFIX_LEN,
+                                       GFP_KERNEL);
+               if (!fname) {
+                       dev_err(dev, "failed to alloc memory for func name\n");
+                       return -ENOMEM;
+               }
+               snprintf(fname, strlen(cfg_np->name) + 4, "%s%s", cfg_np->name,
+                        FUNCTION_SUFFIX);
+
+               func->name = fname;
+               func->groups = devm_kzalloc(dev, sizeof(char *), GFP_KERNEL);
+               if (!func->groups) {
+                       dev_err(dev, "failed to alloc memory for group list "
+                                       "in pin function");
+                       return -ENOMEM;
+               }
+               func->groups[0] = gname;
+               func->num_groups = gname ? 1 : 0;
+               func->function = function;
+               func++;
+               func_idx++;
+       }
+
+       priv->pin_groups = groups;
+       priv->nr_groups = grp_cnt;
+       priv->pmx_functions = functions;
+       priv->nr_functions = func_idx;
+       return 0;
+}
+
+/* register the pinctrl interface with the pinctrl subsystem */
+static int exynos5440_pinctrl_register(struct platform_device *pdev,
+                               struct exynos5440_pinctrl_priv_data *priv)
+{
+       struct device *dev = &pdev->dev;
+       struct pinctrl_desc *ctrldesc;
+       struct pinctrl_dev *pctl_dev;
+       struct pinctrl_pin_desc *pindesc, *pdesc;
+       struct pinctrl_gpio_range grange;
+       char *pin_names;
+       int pin, ret;
+
+       ctrldesc = devm_kzalloc(dev, sizeof(*ctrldesc), GFP_KERNEL);
+       if (!ctrldesc) {
+               dev_err(dev, "could not allocate memory for pinctrl desc\n");
+               return -ENOMEM;
+       }
+
+       ctrldesc->name = "exynos5440-pinctrl";
+       ctrldesc->owner = THIS_MODULE;
+       ctrldesc->pctlops = &exynos5440_pctrl_ops;
+       ctrldesc->pmxops = &exynos5440_pinmux_ops;
+       ctrldesc->confops = &exynos5440_pinconf_ops;
+
+       pindesc = devm_kzalloc(&pdev->dev, sizeof(*pindesc) *
+                               EXYNOS5440_MAX_PINS, GFP_KERNEL);
+       if (!pindesc) {
+               dev_err(&pdev->dev, "mem alloc for pin descriptors failed\n");
+               return -ENOMEM;
+       }
+       ctrldesc->pins = pindesc;
+       ctrldesc->npins = EXYNOS5440_MAX_PINS;
+
+       /* dynamically populate the pin number and pin name for pindesc */
+       for (pin = 0, pdesc = pindesc; pin < ctrldesc->npins; pin++, pdesc++)
+               pdesc->number = pin;
+
+       /*
+        * allocate space for storing the dynamically generated names for all
+        * the pins which belong to this pin-controller.
+        */
+       pin_names = devm_kzalloc(&pdev->dev, sizeof(char) * PIN_NAME_LENGTH *
+                                       ctrldesc->npins, GFP_KERNEL);
+       if (!pin_names) {
+               dev_err(&pdev->dev, "mem alloc for pin names failed\n");
+               return -ENOMEM;
+       }
+
+       /* for each pin, set the name of the pin */
+       for (pin = 0; pin < ctrldesc->npins; pin++) {
+               snprintf(pin_names, 6, "gpio%02d", pin);
+               pdesc = pindesc + pin;
+               pdesc->name = pin_names;
+               pin_names += PIN_NAME_LENGTH;
+       }
+
+       ret = exynos5440_pinctrl_parse_dt(pdev, priv);
+       if (ret)
+               return ret;
+
+       pctl_dev = pinctrl_register(ctrldesc, &pdev->dev, priv);
+       if (!pctl_dev) {
+               dev_err(&pdev->dev, "could not register pinctrl driver\n");
+               return -EINVAL;
+       }
+
+       grange.name = "exynos5440-pctrl-gpio-range";
+       grange.id = 0;
+       grange.base = 0;
+       grange.npins = EXYNOS5440_MAX_PINS;
+       grange.gc = priv->gc;
+       pinctrl_add_gpio_range(pctl_dev, &grange);
+       return 0;
+}
+
+/* register the gpiolib interface with the gpiolib subsystem */
+static int exynos5440_gpiolib_register(struct platform_device *pdev,
+                               struct exynos5440_pinctrl_priv_data *priv)
+{
+       struct gpio_chip *gc;
+       int ret;
+
+       gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL);
+       if (!gc) {
+               dev_err(&pdev->dev, "mem alloc for gpio_chip failed\n");
+               return -ENOMEM;
+       }
+
+       priv->gc = gc;
+       gc->base = 0;
+       gc->ngpio = EXYNOS5440_MAX_PINS;
+       gc->dev = &pdev->dev;
+       gc->set = exynos5440_gpio_set;
+       gc->get = exynos5440_gpio_get;
+       gc->direction_input = exynos5440_gpio_direction_input;
+       gc->direction_output = exynos5440_gpio_direction_output;
+       gc->to_irq = exynos5440_gpio_to_irq;
+       gc->label = "gpiolib-exynos5440";
+       gc->owner = THIS_MODULE;
+       ret = gpiochip_add(gc);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to register gpio_chip %s, error "
+                                       "code: %d\n", gc->label, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+/* unregister the gpiolib interface with the gpiolib subsystem */
+static int exynos5440_gpiolib_unregister(struct platform_device *pdev,
+                               struct exynos5440_pinctrl_priv_data *priv)
+{
+       int ret = gpiochip_remove(priv->gc);
+       if (ret) {
+               dev_err(&pdev->dev, "gpio chip remove failed\n");
+               return ret;
+       }
+       return 0;
+}
+
+static void exynos5440_gpio_irq_unmask(struct irq_data *irqd)
+{
+       struct exynos5440_pinctrl_priv_data *d;
+       unsigned long gpio_int;
+
+       d = irq_data_get_irq_chip_data(irqd);
+       gpio_int = readl(d->reg_base + GPIO_INT);
+       gpio_int |= 1 << irqd->hwirq;
+       writel(gpio_int, d->reg_base + GPIO_INT);
+}
+
+static void exynos5440_gpio_irq_mask(struct irq_data *irqd)
+{
+       struct exynos5440_pinctrl_priv_data *d;
+       unsigned long gpio_int;
+
+       d = irq_data_get_irq_chip_data(irqd);
+       gpio_int = readl(d->reg_base + GPIO_INT);
+       gpio_int &= ~(1 << irqd->hwirq);
+       writel(gpio_int, d->reg_base + GPIO_INT);
+}
+
+/* irq_chip for gpio interrupts */
+static struct irq_chip exynos5440_gpio_irq_chip = {
+       .name           = "exynos5440_gpio_irq_chip",
+       .irq_unmask     = exynos5440_gpio_irq_unmask,
+       .irq_mask       = exynos5440_gpio_irq_mask,
+};
+
+/* interrupt handler for GPIO interrupts 0..7 */
+static irqreturn_t exynos5440_gpio_irq(int irq, void *data)
+{
+       struct exynos5440_gpio_intr_data *intd = data;
+       struct exynos5440_pinctrl_priv_data *d = intd->priv;
+       int virq;
+
+       virq = irq_linear_revmap(d->irq_domain, intd->gpio_int);
+       if (!virq)
+               return IRQ_NONE;
+       generic_handle_irq(virq);
+       return IRQ_HANDLED;
+}
+
+static int exynos5440_gpio_irq_map(struct irq_domain *h, unsigned int virq,
+                                       irq_hw_number_t hw)
+{
+       struct exynos5440_pinctrl_priv_data *d = h->host_data;
+
+       irq_set_chip_data(virq, d);
+       irq_set_chip_and_handler(virq, &exynos5440_gpio_irq_chip,
+                                       handle_level_irq);
+       set_irq_flags(virq, IRQF_VALID);
+       return 0;
+}
+
+/* irq domain callbacks for gpio interrupt controller */
+static const struct irq_domain_ops exynos5440_gpio_irqd_ops = {
+       .map    = exynos5440_gpio_irq_map,
+       .xlate  = irq_domain_xlate_twocell,
+};
+
+/* setup handling of gpio interrupts */
+static int exynos5440_gpio_irq_init(struct platform_device *pdev,
+                               struct exynos5440_pinctrl_priv_data *priv)
+{
+       struct device *dev = &pdev->dev;
+       struct exynos5440_gpio_intr_data *intd;
+       int i, irq, ret;
+
+       intd = devm_kzalloc(dev, sizeof(*intd) * EXYNOS5440_MAX_GPIO_INT,
+                                       GFP_KERNEL);
+       if (!intd) {
+               dev_err(dev, "failed to allocate memory for gpio intr data\n");
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < EXYNOS5440_MAX_GPIO_INT; i++) {
+               irq = irq_of_parse_and_map(dev->of_node, i);
+               if (irq <= 0) {
+                       dev_err(dev, "irq parsing failed\n");
+                       return -EINVAL;
+               }
+
+               intd->gpio_int = i;
+               intd->priv = priv;
+               ret = devm_request_irq(dev, irq, exynos5440_gpio_irq,
+                                       0, dev_name(dev), intd++);
+               if (ret) {
+                       dev_err(dev, "irq request failed\n");
+                       return -ENXIO;
+               }
+       }
+
+       priv->irq_domain = irq_domain_add_linear(dev->of_node,
+                               EXYNOS5440_MAX_GPIO_INT,
+                               &exynos5440_gpio_irqd_ops, priv);
+       if (!priv->irq_domain) {
+               dev_err(dev, "failed to create irq domain\n");
+               return -ENXIO;
+       }
+
+       return 0;
+}
+
+static int exynos5440_pinctrl_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct exynos5440_pinctrl_priv_data *priv;
+       struct resource *res;
+       int ret;
+
+       if (!dev->of_node) {
+               dev_err(dev, "device tree node not found\n");
+               return -ENODEV;
+       }
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv) {
+               dev_err(dev, "could not allocate memory for private data\n");
+               return -ENOMEM;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       priv->reg_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(priv->reg_base))
+               return PTR_ERR(priv->reg_base);
+
+       ret = exynos5440_gpiolib_register(pdev, priv);
+       if (ret)
+               return ret;
+
+       ret = exynos5440_pinctrl_register(pdev, priv);
+       if (ret) {
+               exynos5440_gpiolib_unregister(pdev, priv);
+               return ret;
+       }
+
+       ret = exynos5440_gpio_irq_init(pdev, priv);
+       if (ret) {
+               dev_err(dev, "failed to setup gpio interrupts\n");
+               return ret;
+       }
+
+       platform_set_drvdata(pdev, priv);
+       dev_info(dev, "EXYNOS5440 pinctrl driver registered\n");
+       return 0;
+}
+
+static const struct of_device_id exynos5440_pinctrl_dt_match[] = {
+       { .compatible = "samsung,exynos5440-pinctrl" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, exynos5440_pinctrl_dt_match);
+
+static struct platform_driver exynos5440_pinctrl_driver = {
+       .probe          = exynos5440_pinctrl_probe,
+       .driver = {
+               .name   = "exynos5440-pinctrl",
+               .owner  = THIS_MODULE,
+               .of_match_table = exynos5440_pinctrl_dt_match,
+       },
+};
+
+static int __init exynos5440_pinctrl_drv_register(void)
+{
+       return platform_driver_register(&exynos5440_pinctrl_driver);
+}
+postcore_initcall(exynos5440_pinctrl_drv_register);
+
+static void __exit exynos5440_pinctrl_drv_unregister(void)
+{
+       platform_driver_unregister(&exynos5440_pinctrl_driver);
+}
+module_exit(exynos5440_pinctrl_drv_unregister);
+
+MODULE_AUTHOR("Thomas Abraham <thomas.ab@samsung.com>");
+MODULE_DESCRIPTION("Samsung EXYNOS5440 SoC pinctrl driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/samsung/pinctrl-s3c24xx.c b/drivers/pinctrl/samsung/pinctrl-s3c24xx.c
new file mode 100644 (file)
index 0000000..ad3eaad
--- /dev/null
@@ -0,0 +1,651 @@
+/*
+ * S3C24XX specific support for Samsung pinctrl/gpiolib driver.
+ *
+ * Copyright (c) 2013 Heiko Stuebner <heiko@sntech.de>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This file contains the SamsungS3C24XX specific information required by the
+ * Samsung pinctrl/gpiolib driver. It also includes the implementation of
+ * external gpio and wakeup interrupt support.
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/irq.h>
+#include <linux/of_irq.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+
+#include "pinctrl-samsung.h"
+
+#define NUM_EINT       24
+#define NUM_EINT_IRQ   6
+#define EINT_MAX_PER_GROUP     8
+
+#define EINTPEND_REG   0xa8
+#define EINTMASK_REG   0xa4
+
+#define EINT_GROUP(i)          ((int)((i) / EINT_MAX_PER_GROUP))
+#define EINT_REG(i)            ((EINT_GROUP(i) * 4) + 0x88)
+#define EINT_OFFS(i)           ((i) % EINT_MAX_PER_GROUP * 4)
+
+#define EINT_LEVEL_LOW         0
+#define EINT_LEVEL_HIGH                1
+#define EINT_EDGE_FALLING      2
+#define EINT_EDGE_RISING       4
+#define EINT_EDGE_BOTH         6
+#define EINT_MASK              0xf
+
+static struct samsung_pin_bank_type bank_type_1bit = {
+       .fld_width = { 1, 1, },
+       .reg_offset = { 0x00, 0x04, },
+};
+
+static struct samsung_pin_bank_type bank_type_2bit = {
+       .fld_width = { 2, 1, 2, },
+       .reg_offset = { 0x00, 0x04, 0x08, },
+};
+
+#define PIN_BANK_A(pins, reg, id)              \
+       {                                               \
+               .type           = &bank_type_1bit,      \
+               .pctl_offset    = reg,                  \
+               .nr_pins        = pins,                 \
+               .eint_type      = EINT_TYPE_NONE,       \
+               .name           = id                    \
+       }
+
+#define PIN_BANK_2BIT(pins, reg, id)           \
+       {                                               \
+               .type           = &bank_type_2bit,      \
+               .pctl_offset    = reg,                  \
+               .nr_pins        = pins,                 \
+               .eint_type      = EINT_TYPE_NONE,       \
+               .name           = id                    \
+       }
+
+#define PIN_BANK_2BIT_EINTW(pins, reg, id, eoffs, emask)\
+       {                                               \
+               .type           = &bank_type_2bit,      \
+               .pctl_offset    = reg,                  \
+               .nr_pins        = pins,                 \
+               .eint_type      = EINT_TYPE_WKUP,       \
+               .eint_func      = 2,                    \
+               .eint_mask      = emask,                \
+               .eint_offset    = eoffs,                \
+               .name           = id                    \
+       }
+
+/**
+ * struct s3c24xx_eint_data: EINT common data
+ * @drvdata: pin controller driver data
+ * @domains: IRQ domains of particular EINT interrupts
+ * @parents: mapped parent irqs in the main interrupt controller
+ */
+struct s3c24xx_eint_data {
+       struct samsung_pinctrl_drv_data *drvdata;
+       struct irq_domain *domains[NUM_EINT];
+       int parents[NUM_EINT_IRQ];
+};
+
+/**
+ * struct s3c24xx_eint_domain_data: per irq-domain data
+ * @bank: pin bank related to the domain
+ * @eint_data: common data
+ * eint0_3_parent_only: live eints 0-3 only in the main intc
+ */
+struct s3c24xx_eint_domain_data {
+       struct samsung_pin_bank *bank;
+       struct s3c24xx_eint_data *eint_data;
+       bool eint0_3_parent_only;
+};
+
+static int s3c24xx_eint_get_trigger(unsigned int type)
+{
+       switch (type) {
+       case IRQ_TYPE_EDGE_RISING:
+               return EINT_EDGE_RISING;
+               break;
+       case IRQ_TYPE_EDGE_FALLING:
+               return EINT_EDGE_FALLING;
+               break;
+       case IRQ_TYPE_EDGE_BOTH:
+               return EINT_EDGE_BOTH;
+               break;
+       case IRQ_TYPE_LEVEL_HIGH:
+               return EINT_LEVEL_HIGH;
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
+               return EINT_LEVEL_LOW;
+               break;
+       default:
+               return -EINVAL;
+       }
+}
+
+static void s3c24xx_eint_set_handler(unsigned int irq, unsigned int type)
+{
+       /* Edge- and level-triggered interrupts need different handlers */
+       if (type & IRQ_TYPE_EDGE_BOTH)
+               __irq_set_handler_locked(irq, handle_edge_irq);
+       else
+               __irq_set_handler_locked(irq, handle_level_irq);
+}
+
+static void s3c24xx_eint_set_function(struct samsung_pinctrl_drv_data *d,
+                                       struct samsung_pin_bank *bank, int pin)
+{
+       struct samsung_pin_bank_type *bank_type = bank->type;
+       unsigned long flags;
+       void __iomem *reg;
+       u8 shift;
+       u32 mask;
+       u32 val;
+
+       /* Make sure that pin is configured as interrupt */
+       reg = d->virt_base + bank->pctl_offset;
+       shift = pin * bank_type->fld_width[PINCFG_TYPE_FUNC];
+       mask = (1 << bank_type->fld_width[PINCFG_TYPE_FUNC]) - 1;
+
+       spin_lock_irqsave(&bank->slock, flags);
+
+       val = readl(reg);
+       val &= ~(mask << shift);
+       val |= bank->eint_func << shift;
+       writel(val, reg);
+
+       spin_unlock_irqrestore(&bank->slock, flags);
+}
+
+static int s3c24xx_eint_type(struct irq_data *data, unsigned int type)
+{
+       struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(data);
+       struct samsung_pinctrl_drv_data *d = bank->drvdata;
+       int index = bank->eint_offset + data->hwirq;
+       void __iomem *reg;
+       int trigger;
+       u8 shift;
+       u32 val;
+
+       trigger = s3c24xx_eint_get_trigger(type);
+       if (trigger < 0) {
+               dev_err(d->dev, "unsupported external interrupt type\n");
+               return -EINVAL;
+       }
+
+       s3c24xx_eint_set_handler(data->irq, type);
+
+       /* Set up interrupt trigger */
+       reg = d->virt_base + EINT_REG(index);
+       shift = EINT_OFFS(index);
+
+       val = readl(reg);
+       val &= ~(EINT_MASK << shift);
+       val |= trigger << shift;
+       writel(val, reg);
+
+       s3c24xx_eint_set_function(d, bank, data->hwirq);
+
+       return 0;
+}
+
+/* Handling of EINTs 0-3 on all except S3C2412 and S3C2413 */
+
+static void s3c2410_eint0_3_ack(struct irq_data *data)
+{
+       struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(data);
+       struct s3c24xx_eint_domain_data *ddata = bank->irq_domain->host_data;
+       struct s3c24xx_eint_data *eint_data = ddata->eint_data;
+       int parent_irq = eint_data->parents[data->hwirq];
+       struct irq_chip *parent_chip = irq_get_chip(parent_irq);
+
+       parent_chip->irq_ack(irq_get_irq_data(parent_irq));
+}
+
+static void s3c2410_eint0_3_mask(struct irq_data *data)
+{
+       struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(data);
+       struct s3c24xx_eint_domain_data *ddata = bank->irq_domain->host_data;
+       struct s3c24xx_eint_data *eint_data = ddata->eint_data;
+       int parent_irq = eint_data->parents[data->hwirq];
+       struct irq_chip *parent_chip = irq_get_chip(parent_irq);
+
+       parent_chip->irq_mask(irq_get_irq_data(parent_irq));
+}
+
+static void s3c2410_eint0_3_unmask(struct irq_data *data)
+{
+       struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(data);
+       struct s3c24xx_eint_domain_data *ddata = bank->irq_domain->host_data;
+       struct s3c24xx_eint_data *eint_data = ddata->eint_data;
+       int parent_irq = eint_data->parents[data->hwirq];
+       struct irq_chip *parent_chip = irq_get_chip(parent_irq);
+
+       parent_chip->irq_unmask(irq_get_irq_data(parent_irq));
+}
+
+static struct irq_chip s3c2410_eint0_3_chip = {
+       .name           = "s3c2410-eint0_3",
+       .irq_ack        = s3c2410_eint0_3_ack,
+       .irq_mask       = s3c2410_eint0_3_mask,
+       .irq_unmask     = s3c2410_eint0_3_unmask,
+       .irq_set_type   = s3c24xx_eint_type,
+};
+
+static void s3c2410_demux_eint0_3(unsigned int irq, struct irq_desc *desc)
+{
+       struct irq_data *data = irq_desc_get_irq_data(desc);
+       struct s3c24xx_eint_data *eint_data = irq_get_handler_data(irq);
+       unsigned int virq;
+
+       /* the first 4 eints have a simple 1 to 1 mapping */
+       virq = irq_linear_revmap(eint_data->domains[data->hwirq], data->hwirq);
+       /* Something must be really wrong if an unmapped EINT is unmasked */
+       BUG_ON(!virq);
+
+       generic_handle_irq(virq);
+}
+
+/* Handling of EINTs 0-3 on S3C2412 and S3C2413 */
+
+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);
+}
+
+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 |= (1UL << data->hwirq);
+       writel(mask, d->virt_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 &= ~(1UL << data->hwirq);
+       writel(mask, d->virt_base + EINTMASK_REG);
+}
+
+static struct irq_chip s3c2412_eint0_3_chip = {
+       .name           = "s3c2412-eint0_3",
+       .irq_ack        = s3c2412_eint0_3_ack,
+       .irq_mask       = s3c2412_eint0_3_mask,
+       .irq_unmask     = s3c2412_eint0_3_unmask,
+       .irq_set_type   = s3c24xx_eint_type,
+};
+
+static void s3c2412_demux_eint0_3(unsigned int irq, struct irq_desc *desc)
+{
+       struct irq_chip *chip = irq_get_chip(irq);
+       struct irq_data *data = irq_desc_get_irq_data(desc);
+       struct s3c24xx_eint_data *eint_data = irq_get_handler_data(irq);
+       unsigned int virq;
+
+       chained_irq_enter(chip, desc);
+
+       /* the first 4 eints have a simple 1 to 1 mapping */
+       virq = irq_linear_revmap(eint_data->domains[data->hwirq], data->hwirq);
+       /* Something must be really wrong if an unmapped EINT is unmasked */
+       BUG_ON(!virq);
+
+       generic_handle_irq(virq);
+
+       chained_irq_exit(chip, desc);
+}
+
+/* Handling of all other eints */
+
+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);
+}
+
+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 |= (1UL << index);
+       writel(mask, d->virt_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 &= ~(1UL << index);
+       writel(mask, d->virt_base + EINTMASK_REG);
+}
+
+static struct irq_chip s3c24xx_eint_chip = {
+       .name           = "s3c-eint",
+       .irq_ack        = s3c24xx_eint_ack,
+       .irq_mask       = s3c24xx_eint_mask,
+       .irq_unmask     = s3c24xx_eint_unmask,
+       .irq_set_type   = s3c24xx_eint_type,
+};
+
+static inline void s3c24xx_demux_eint(unsigned int irq, struct irq_desc *desc,
+                                     u32 offset, u32 range)
+{
+       struct irq_chip *chip = irq_get_chip(irq);
+       struct s3c24xx_eint_data *data = irq_get_handler_data(irq);
+       struct samsung_pinctrl_drv_data *d = data->drvdata;
+       unsigned int pend, mask;
+
+       chained_irq_enter(chip, desc);
+
+       pend = readl(d->virt_base + EINTPEND_REG);
+       mask = readl(d->virt_base + EINTMASK_REG);
+
+       pend &= ~mask;
+       pend &= range;
+
+       while (pend) {
+               unsigned int virq;
+
+               irq = __ffs(pend);
+               pend &= ~(1 << irq);
+               virq = irq_linear_revmap(data->domains[irq], irq - offset);
+               /* Something is really wrong if an unmapped EINT is unmasked */
+               BUG_ON(!virq);
+
+               generic_handle_irq(virq);
+       }
+
+       chained_irq_exit(chip, desc);
+}
+
+static void s3c24xx_demux_eint4_7(unsigned int irq, struct irq_desc *desc)
+{
+       s3c24xx_demux_eint(irq, desc, 0, 0xf0);
+}
+
+static void s3c24xx_demux_eint8_23(unsigned int irq, struct irq_desc *desc)
+{
+       s3c24xx_demux_eint(irq, desc, 8, 0xffff00);
+}
+
+static irq_flow_handler_t s3c2410_eint_handlers[NUM_EINT_IRQ] = {
+       s3c2410_demux_eint0_3,
+       s3c2410_demux_eint0_3,
+       s3c2410_demux_eint0_3,
+       s3c2410_demux_eint0_3,
+       s3c24xx_demux_eint4_7,
+       s3c24xx_demux_eint8_23,
+};
+
+static irq_flow_handler_t s3c2412_eint_handlers[NUM_EINT_IRQ] = {
+       s3c2412_demux_eint0_3,
+       s3c2412_demux_eint0_3,
+       s3c2412_demux_eint0_3,
+       s3c2412_demux_eint0_3,
+       s3c24xx_demux_eint4_7,
+       s3c24xx_demux_eint8_23,
+};
+
+static int s3c24xx_gpf_irq_map(struct irq_domain *h, unsigned int virq,
+                                       irq_hw_number_t hw)
+{
+       struct s3c24xx_eint_domain_data *ddata = h->host_data;
+       struct samsung_pin_bank *bank = ddata->bank;
+
+       if (!(bank->eint_mask & (1 << (bank->eint_offset + hw))))
+               return -EINVAL;
+
+       if (hw <= 3) {
+               if (ddata->eint0_3_parent_only)
+                       irq_set_chip_and_handler(virq, &s3c2410_eint0_3_chip,
+                                                handle_edge_irq);
+               else
+                       irq_set_chip_and_handler(virq, &s3c2412_eint0_3_chip,
+                                                handle_edge_irq);
+       } else {
+               irq_set_chip_and_handler(virq, &s3c24xx_eint_chip,
+                                        handle_edge_irq);
+       }
+       irq_set_chip_data(virq, bank);
+       set_irq_flags(virq, IRQF_VALID);
+       return 0;
+}
+
+static const struct irq_domain_ops s3c24xx_gpf_irq_ops = {
+       .map    = s3c24xx_gpf_irq_map,
+       .xlate  = irq_domain_xlate_twocell,
+};
+
+static int s3c24xx_gpg_irq_map(struct irq_domain *h, unsigned int virq,
+                                       irq_hw_number_t hw)
+{
+       struct s3c24xx_eint_domain_data *ddata = h->host_data;
+       struct samsung_pin_bank *bank = ddata->bank;
+
+       if (!(bank->eint_mask & (1 << (bank->eint_offset + hw))))
+               return -EINVAL;
+
+       irq_set_chip_and_handler(virq, &s3c24xx_eint_chip, handle_edge_irq);
+       irq_set_chip_data(virq, bank);
+       set_irq_flags(virq, IRQF_VALID);
+       return 0;
+}
+
+static const struct irq_domain_ops s3c24xx_gpg_irq_ops = {
+       .map    = s3c24xx_gpg_irq_map,
+       .xlate  = irq_domain_xlate_twocell,
+};
+
+static const struct of_device_id s3c24xx_eint_irq_ids[] = {
+       { .compatible = "samsung,s3c2410-wakeup-eint", .data = (void *)1 },
+       { .compatible = "samsung,s3c2412-wakeup-eint", .data = (void *)0 },
+       { }
+};
+
+static int s3c24xx_eint_init(struct samsung_pinctrl_drv_data *d)
+{
+       struct device *dev = d->dev;
+       const struct of_device_id *match;
+       struct device_node *eint_np = NULL;
+       struct device_node *np;
+       struct samsung_pin_bank *bank;
+       struct s3c24xx_eint_data *eint_data;
+       const struct irq_domain_ops *ops;
+       unsigned int i;
+       bool eint0_3_parent_only;
+       irq_flow_handler_t *handlers;
+
+       for_each_child_of_node(dev->of_node, np) {
+               match = of_match_node(s3c24xx_eint_irq_ids, np);
+               if (match) {
+                       eint_np = np;
+                       eint0_3_parent_only = (bool)match->data;
+                       break;
+               }
+       }
+       if (!eint_np)
+               return -ENODEV;
+
+       eint_data = devm_kzalloc(dev, sizeof(*eint_data), GFP_KERNEL);
+       if (!eint_data)
+               return -ENOMEM;
+
+       eint_data->drvdata = d;
+
+       handlers = eint0_3_parent_only ? s3c2410_eint_handlers
+                                      : s3c2412_eint_handlers;
+       for (i = 0; i < NUM_EINT_IRQ; ++i) {
+               unsigned int irq;
+
+               irq = irq_of_parse_and_map(eint_np, i);
+               if (!irq) {
+                       dev_err(dev, "failed to get wakeup EINT IRQ %d\n", i);
+                       return -ENXIO;
+               }
+
+               eint_data->parents[i] = irq;
+               irq_set_chained_handler(irq, handlers[i]);
+               irq_set_handler_data(irq, eint_data);
+       }
+
+       bank = d->ctrl->pin_banks;
+       for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) {
+               struct s3c24xx_eint_domain_data *ddata;
+               unsigned int mask;
+               unsigned int irq;
+               unsigned int pin;
+
+               if (bank->eint_type != EINT_TYPE_WKUP)
+                       continue;
+
+               ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
+               if (!ddata)
+                       return -ENOMEM;
+
+               ddata->bank = bank;
+               ddata->eint_data = eint_data;
+               ddata->eint0_3_parent_only = eint0_3_parent_only;
+
+               ops = (bank->eint_offset == 0) ? &s3c24xx_gpf_irq_ops
+                                              : &s3c24xx_gpg_irq_ops;
+
+               bank->irq_domain = irq_domain_add_linear(bank->of_node,
+                               bank->nr_pins, ops, ddata);
+               if (!bank->irq_domain) {
+                       dev_err(dev, "wkup irq domain add failed\n");
+                       return -ENXIO;
+               }
+
+               irq = bank->eint_offset;
+               mask = bank->eint_mask;
+               for (pin = 0; mask; ++pin, mask >>= 1) {
+                       if (irq >= NUM_EINT)
+                               break;
+                       if (!(mask & 1))
+                               continue;
+                       eint_data->domains[irq] = bank->irq_domain;
+                       ++irq;
+               }
+       }
+
+       return 0;
+}
+
+static struct samsung_pin_bank s3c2412_pin_banks[] = {
+       PIN_BANK_A(23, 0x000, "gpa"),
+       PIN_BANK_2BIT(11, 0x010, "gpb"),
+       PIN_BANK_2BIT(16, 0x020, "gpc"),
+       PIN_BANK_2BIT(16, 0x030, "gpd"),
+       PIN_BANK_2BIT(16, 0x040, "gpe"),
+       PIN_BANK_2BIT_EINTW(8, 0x050, "gpf", 0, 0xff),
+       PIN_BANK_2BIT_EINTW(16, 0x060, "gpg", 8, 0xffff00),
+       PIN_BANK_2BIT(11, 0x070, "gph"),
+       PIN_BANK_2BIT(13, 0x080, "gpj"),
+};
+
+struct samsung_pin_ctrl s3c2412_pin_ctrl[] = {
+       {
+               .pin_banks      = s3c2412_pin_banks,
+               .nr_banks       = ARRAY_SIZE(s3c2412_pin_banks),
+               .eint_wkup_init = s3c24xx_eint_init,
+               .label          = "S3C2412-GPIO",
+       },
+};
+
+static struct samsung_pin_bank s3c2416_pin_banks[] = {
+       PIN_BANK_A(27, 0x000, "gpa"),
+       PIN_BANK_2BIT(11, 0x010, "gpb"),
+       PIN_BANK_2BIT(16, 0x020, "gpc"),
+       PIN_BANK_2BIT(16, 0x030, "gpd"),
+       PIN_BANK_2BIT(16, 0x040, "gpe"),
+       PIN_BANK_2BIT_EINTW(8, 0x050, "gpf", 0, 0xff),
+       PIN_BANK_2BIT_EINTW(8, 0x060, "gpg", 8, 0xff00),
+       PIN_BANK_2BIT(15, 0x070, "gph"),
+       PIN_BANK_2BIT(16, 0x0e0, "gpk"),
+       PIN_BANK_2BIT(14, 0x0f0, "gpl"),
+       PIN_BANK_2BIT(2, 0x100, "gpm"),
+};
+
+struct samsung_pin_ctrl s3c2416_pin_ctrl[] = {
+       {
+               .pin_banks      = s3c2416_pin_banks,
+               .nr_banks       = ARRAY_SIZE(s3c2416_pin_banks),
+               .eint_wkup_init = s3c24xx_eint_init,
+               .label          = "S3C2416-GPIO",
+       },
+};
+
+static struct samsung_pin_bank s3c2440_pin_banks[] = {
+       PIN_BANK_A(25, 0x000, "gpa"),
+       PIN_BANK_2BIT(11, 0x010, "gpb"),
+       PIN_BANK_2BIT(16, 0x020, "gpc"),
+       PIN_BANK_2BIT(16, 0x030, "gpd"),
+       PIN_BANK_2BIT(16, 0x040, "gpe"),
+       PIN_BANK_2BIT_EINTW(8, 0x050, "gpf", 0, 0xff),
+       PIN_BANK_2BIT_EINTW(16, 0x060, "gpg", 8, 0xffff00),
+       PIN_BANK_2BIT(11, 0x070, "gph"),
+       PIN_BANK_2BIT(13, 0x0d0, "gpj"),
+};
+
+struct samsung_pin_ctrl s3c2440_pin_ctrl[] = {
+       {
+               .pin_banks      = s3c2440_pin_banks,
+               .nr_banks       = ARRAY_SIZE(s3c2440_pin_banks),
+               .eint_wkup_init = s3c24xx_eint_init,
+               .label          = "S3C2440-GPIO",
+       },
+};
+
+static struct samsung_pin_bank s3c2450_pin_banks[] = {
+       PIN_BANK_A(28, 0x000, "gpa"),
+       PIN_BANK_2BIT(11, 0x010, "gpb"),
+       PIN_BANK_2BIT(16, 0x020, "gpc"),
+       PIN_BANK_2BIT(16, 0x030, "gpd"),
+       PIN_BANK_2BIT(16, 0x040, "gpe"),
+       PIN_BANK_2BIT_EINTW(8, 0x050, "gpf", 0, 0xff),
+       PIN_BANK_2BIT_EINTW(16, 0x060, "gpg", 8, 0xffff00),
+       PIN_BANK_2BIT(15, 0x070, "gph"),
+       PIN_BANK_2BIT(16, 0x0d0, "gpj"),
+       PIN_BANK_2BIT(16, 0x0e0, "gpk"),
+       PIN_BANK_2BIT(15, 0x0f0, "gpl"),
+       PIN_BANK_2BIT(2, 0x100, "gpm"),
+};
+
+struct samsung_pin_ctrl s3c2450_pin_ctrl[] = {
+       {
+               .pin_banks      = s3c2450_pin_banks,
+               .nr_banks       = ARRAY_SIZE(s3c2450_pin_banks),
+               .eint_wkup_init = s3c24xx_eint_init,
+               .label          = "S3C2450-GPIO",
+       },
+};
diff --git a/drivers/pinctrl/samsung/pinctrl-s3c64xx.c b/drivers/pinctrl/samsung/pinctrl-s3c64xx.c
new file mode 100644 (file)
index 0000000..89143c9
--- /dev/null
@@ -0,0 +1,816 @@
+/*
+ * S3C64xx specific support for pinctrl-samsung driver.
+ *
+ * Copyright (c) 2013 Tomasz Figa <tomasz.figa@gmail.com>
+ *
+ * Based on pinctrl-exynos.c, please see the file for original copyrights.
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This file contains the Samsung S3C64xx specific information required by the
+ * the Samsung pinctrl/gpiolib driver. It also includes the implementation of
+ * external gpio and wakeup interrupt support.
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/irq.h>
+#include <linux/of_irq.h>
+#include <linux/io.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+
+#include "pinctrl-samsung.h"
+
+#define NUM_EINT0              28
+#define NUM_EINT0_IRQ          4
+#define EINT_MAX_PER_REG       16
+#define EINT_MAX_PER_GROUP     16
+
+/* External GPIO and wakeup interrupt related definitions */
+#define SVC_GROUP_SHIFT                4
+#define SVC_GROUP_MASK         0xf
+#define SVC_NUM_MASK           0xf
+#define SVC_GROUP(x)           ((x >> SVC_GROUP_SHIFT) & \
+                                               SVC_GROUP_MASK)
+
+#define EINT12CON_REG          0x200
+#define EINT12MASK_REG         0x240
+#define EINT12PEND_REG         0x260
+
+#define EINT_OFFS(i)           ((i) % (2 * EINT_MAX_PER_GROUP))
+#define EINT_GROUP(i)          ((i) / EINT_MAX_PER_GROUP)
+#define EINT_REG(g)            (4 * ((g) / 2))
+
+#define EINTCON_REG(i)         (EINT12CON_REG + EINT_REG(EINT_GROUP(i)))
+#define EINTMASK_REG(i)                (EINT12MASK_REG + EINT_REG(EINT_GROUP(i)))
+#define EINTPEND_REG(i)                (EINT12PEND_REG + EINT_REG(EINT_GROUP(i)))
+
+#define SERVICE_REG            0x284
+#define SERVICEPEND_REG                0x288
+
+#define EINT0CON0_REG          0x900
+#define EINT0MASK_REG          0x920
+#define EINT0PEND_REG          0x924
+
+/* S3C64xx specific external interrupt trigger types */
+#define EINT_LEVEL_LOW         0
+#define EINT_LEVEL_HIGH                1
+#define EINT_EDGE_FALLING      2
+#define EINT_EDGE_RISING       4
+#define EINT_EDGE_BOTH         6
+#define EINT_CON_MASK          0xF
+#define EINT_CON_LEN           4
+
+static 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, },
+};
+
+static struct samsung_pin_bank_type bank_type_4bit_alive = {
+       .fld_width = { 4, 1, 2, },
+       .reg_offset = { 0x00, 0x04, 0x08, },
+};
+
+static struct samsung_pin_bank_type bank_type_4bit2_off = {
+       .fld_width = { 4, 1, 2, 0, 2, 2, },
+       .reg_offset = { 0x00, 0x08, 0x0c, 0, 0x10, 0x14, },
+};
+
+static struct samsung_pin_bank_type bank_type_4bit2_alive = {
+       .fld_width = { 4, 1, 2, },
+       .reg_offset = { 0x00, 0x08, 0x0c, },
+};
+
+static struct samsung_pin_bank_type bank_type_2bit_off = {
+       .fld_width = { 2, 1, 2, 0, 2, 2, },
+       .reg_offset = { 0x00, 0x04, 0x08, 0, 0x0c, 0x10, },
+};
+
+static struct samsung_pin_bank_type bank_type_2bit_alive = {
+       .fld_width = { 2, 1, 2, },
+       .reg_offset = { 0x00, 0x04, 0x08, },
+};
+
+#define PIN_BANK_4BIT(pins, reg, id)                   \
+       {                                               \
+               .type           = &bank_type_4bit_off,  \
+               .pctl_offset    = reg,                  \
+               .nr_pins        = pins,                 \
+               .eint_type      = EINT_TYPE_NONE,       \
+               .name           = id                    \
+       }
+
+#define PIN_BANK_4BIT_EINTG(pins, reg, id, eoffs)      \
+       {                                               \
+               .type           = &bank_type_4bit_off,  \
+               .pctl_offset    = reg,                  \
+               .nr_pins        = pins,                 \
+               .eint_type      = EINT_TYPE_GPIO,       \
+               .eint_func      = 7,                    \
+               .eint_mask      = (1 << (pins)) - 1,    \
+               .eint_offset    = eoffs,                \
+               .name           = id                    \
+       }
+
+#define PIN_BANK_4BIT_EINTW(pins, reg, id, eoffs, emask) \
+       {                                               \
+               .type           = &bank_type_4bit_alive,\
+               .pctl_offset    = reg,                  \
+               .nr_pins        = pins,                 \
+               .eint_type      = EINT_TYPE_WKUP,       \
+               .eint_func      = 3,                    \
+               .eint_mask      = emask,                \
+               .eint_offset    = eoffs,                \
+               .name           = id                    \
+       }
+
+#define PIN_BANK_4BIT2_EINTG(pins, reg, id, eoffs)     \
+       {                                               \
+               .type           = &bank_type_4bit2_off, \
+               .pctl_offset    = reg,                  \
+               .nr_pins        = pins,                 \
+               .eint_type      = EINT_TYPE_GPIO,       \
+               .eint_func      = 7,                    \
+               .eint_mask      = (1 << (pins)) - 1,    \
+               .eint_offset    = eoffs,                \
+               .name           = id                    \
+       }
+
+#define PIN_BANK_4BIT2_EINTW(pins, reg, id, eoffs, emask) \
+       {                                               \
+               .type           = &bank_type_4bit2_alive,\
+               .pctl_offset    = reg,                  \
+               .nr_pins        = pins,                 \
+               .eint_type      = EINT_TYPE_WKUP,       \
+               .eint_func      = 3,                    \
+               .eint_mask      = emask,                \
+               .eint_offset    = eoffs,                \
+               .name           = id                    \
+       }
+
+#define PIN_BANK_4BIT2_ALIVE(pins, reg, id)            \
+       {                                               \
+               .type           = &bank_type_4bit2_alive,\
+               .pctl_offset    = reg,                  \
+               .nr_pins        = pins,                 \
+               .eint_type      = EINT_TYPE_NONE,       \
+               .name           = id                    \
+       }
+
+#define PIN_BANK_2BIT(pins, reg, id)                   \
+       {                                               \
+               .type           = &bank_type_2bit_off,  \
+               .pctl_offset    = reg,                  \
+               .nr_pins        = pins,                 \
+               .eint_type      = EINT_TYPE_NONE,       \
+               .name           = id                    \
+       }
+
+#define PIN_BANK_2BIT_EINTG(pins, reg, id, eoffs, emask) \
+       {                                               \
+               .type           = &bank_type_2bit_off,  \
+               .pctl_offset    = reg,                  \
+               .nr_pins        = pins,                 \
+               .eint_type      = EINT_TYPE_GPIO,       \
+               .eint_func      = 3,                    \
+               .eint_mask      = emask,                \
+               .eint_offset    = eoffs,                \
+               .name           = id                    \
+       }
+
+#define PIN_BANK_2BIT_EINTW(pins, reg, id, eoffs)      \
+       {                                               \
+               .type           = &bank_type_2bit_alive,\
+               .pctl_offset    = reg,                  \
+               .nr_pins        = pins,                 \
+               .eint_type      = EINT_TYPE_WKUP,       \
+               .eint_func      = 2,                    \
+               .eint_mask      = (1 << (pins)) - 1,    \
+               .eint_offset    = eoffs,                \
+               .name           = id                    \
+       }
+
+/**
+ * struct s3c64xx_eint0_data: EINT0 common data
+ * @drvdata: pin controller driver data
+ * @domains: IRQ domains of particular EINT0 interrupts
+ * @pins: pin offsets inside of banks of particular EINT0 interrupts
+ */
+struct s3c64xx_eint0_data {
+       struct samsung_pinctrl_drv_data *drvdata;
+       struct irq_domain *domains[NUM_EINT0];
+       u8 pins[NUM_EINT0];
+};
+
+/**
+ * struct s3c64xx_eint0_domain_data: EINT0 per-domain data
+ * @bank: pin bank related to the domain
+ * @eints: EINT0 interrupts related to the domain
+ */
+struct s3c64xx_eint0_domain_data {
+       struct samsung_pin_bank *bank;
+       u8 eints[];
+};
+
+/**
+ * struct s3c64xx_eint_gpio_data: GPIO EINT data
+ * @drvdata: pin controller driver data
+ * @domains: array of domains related to EINT interrupt groups
+ */
+struct s3c64xx_eint_gpio_data {
+       struct samsung_pinctrl_drv_data *drvdata;
+       struct irq_domain *domains[];
+};
+
+/*
+ * Common functions for S3C64xx EINT configuration
+ */
+
+static int s3c64xx_irq_get_trigger(unsigned int type)
+{
+       int trigger;
+
+       switch (type) {
+       case IRQ_TYPE_EDGE_RISING:
+               trigger = EINT_EDGE_RISING;
+               break;
+       case IRQ_TYPE_EDGE_FALLING:
+               trigger = EINT_EDGE_FALLING;
+               break;
+       case IRQ_TYPE_EDGE_BOTH:
+               trigger = EINT_EDGE_BOTH;
+               break;
+       case IRQ_TYPE_LEVEL_HIGH:
+               trigger = EINT_LEVEL_HIGH;
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
+               trigger = EINT_LEVEL_LOW;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return trigger;
+}
+
+static void s3c64xx_irq_set_handler(unsigned int irq, unsigned int type)
+{
+       /* Edge- and level-triggered interrupts need different handlers */
+       if (type & IRQ_TYPE_EDGE_BOTH)
+               __irq_set_handler_locked(irq, handle_edge_irq);
+       else
+               __irq_set_handler_locked(irq, handle_level_irq);
+}
+
+static void s3c64xx_irq_set_function(struct samsung_pinctrl_drv_data *d,
+                                       struct samsung_pin_bank *bank, int pin)
+{
+       struct samsung_pin_bank_type *bank_type = bank->type;
+       unsigned long flags;
+       void __iomem *reg;
+       u8 shift;
+       u32 mask;
+       u32 val;
+
+       /* Make sure that pin is configured as interrupt */
+       reg = d->virt_base + bank->pctl_offset;
+       shift = pin;
+       if (bank_type->fld_width[PINCFG_TYPE_FUNC] * shift >= 32) {
+               /* 4-bit bank type with 2 con regs */
+               reg += 4;
+               shift -= 8;
+       }
+
+       shift = shift * bank_type->fld_width[PINCFG_TYPE_FUNC];
+       mask = (1 << bank_type->fld_width[PINCFG_TYPE_FUNC]) - 1;
+
+       spin_lock_irqsave(&bank->slock, flags);
+
+       val = readl(reg);
+       val &= ~(mask << shift);
+       val |= bank->eint_func << shift;
+       writel(val, reg);
+
+       spin_unlock_irqrestore(&bank->slock, flags);
+}
+
+/*
+ * Functions for EINT GPIO configuration (EINT groups 1-9)
+ */
+
+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);
+       u32 val;
+
+       val = readl(reg);
+       if (mask)
+               val |= 1 << index;
+       else
+               val &= ~(1 << index);
+       writel(val, reg);
+}
+
+static void s3c64xx_gpio_irq_unmask(struct irq_data *irqd)
+{
+       s3c64xx_gpio_irq_set_mask(irqd, false);
+}
+
+static void s3c64xx_gpio_irq_mask(struct irq_data *irqd)
+{
+       s3c64xx_gpio_irq_set_mask(irqd, true);
+}
+
+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);
+
+       writel(1 << index, reg);
+}
+
+static int s3c64xx_gpio_irq_set_type(struct irq_data *irqd, unsigned int type)
+{
+       struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
+       struct samsung_pinctrl_drv_data *d = bank->drvdata;
+       void __iomem *reg;
+       int trigger;
+       u8 shift;
+       u32 val;
+
+       trigger = s3c64xx_irq_get_trigger(type);
+       if (trigger < 0) {
+               pr_err("unsupported external interrupt type\n");
+               return -EINVAL;
+       }
+
+       s3c64xx_irq_set_handler(irqd->irq, type);
+
+       /* Set up interrupt trigger */
+       reg = d->virt_base + EINTCON_REG(bank->eint_offset);
+       shift = EINT_OFFS(bank->eint_offset) + irqd->hwirq;
+       shift = 4 * (shift / 4); /* 4 EINTs per trigger selector */
+
+       val = readl(reg);
+       val &= ~(EINT_CON_MASK << shift);
+       val |= trigger << shift;
+       writel(val, reg);
+
+       s3c64xx_irq_set_function(d, bank, irqd->hwirq);
+
+       return 0;
+}
+
+/*
+ * irq_chip for gpio interrupts.
+ */
+static struct irq_chip s3c64xx_gpio_irq_chip = {
+       .name           = "GPIO",
+       .irq_unmask     = s3c64xx_gpio_irq_unmask,
+       .irq_mask       = s3c64xx_gpio_irq_mask,
+       .irq_ack        = s3c64xx_gpio_irq_ack,
+       .irq_set_type   = s3c64xx_gpio_irq_set_type,
+};
+
+static int s3c64xx_gpio_irq_map(struct irq_domain *h, unsigned int virq,
+                                       irq_hw_number_t hw)
+{
+       struct samsung_pin_bank *bank = h->host_data;
+
+       if (!(bank->eint_mask & (1 << hw)))
+               return -EINVAL;
+
+       irq_set_chip_and_handler(virq,
+                               &s3c64xx_gpio_irq_chip, handle_level_irq);
+       irq_set_chip_data(virq, bank);
+       set_irq_flags(virq, IRQF_VALID);
+
+       return 0;
+}
+
+/*
+ * irq domain callbacks for external gpio interrupt controller.
+ */
+static const struct irq_domain_ops s3c64xx_gpio_irqd_ops = {
+       .map    = s3c64xx_gpio_irq_map,
+       .xlate  = irq_domain_xlate_twocell,
+};
+
+static void s3c64xx_eint_gpio_irq(unsigned int irq, struct irq_desc *desc)
+{
+       struct irq_chip *chip = irq_get_chip(irq);
+       struct s3c64xx_eint_gpio_data *data = irq_get_handler_data(irq);
+       struct samsung_pinctrl_drv_data *drvdata = data->drvdata;
+
+       chained_irq_enter(chip, desc);
+
+       do {
+               unsigned int svc;
+               unsigned int group;
+               unsigned int pin;
+               unsigned int virq;
+
+               svc = readl(drvdata->virt_base + SERVICE_REG);
+               group = SVC_GROUP(svc);
+               pin = svc & SVC_NUM_MASK;
+
+               if (!group)
+                       break;
+
+               /* Group 1 is used for two pin banks */
+               if (group == 1) {
+                       if (pin < 8)
+                               group = 0;
+                       else
+                               pin -= 8;
+               }
+
+               virq = irq_linear_revmap(data->domains[group], pin);
+               /*
+                * Something must be really wrong if an unmapped EINT
+                * was unmasked...
+                */
+               BUG_ON(!virq);
+
+               generic_handle_irq(virq);
+       } while (1);
+
+       chained_irq_exit(chip, desc);
+}
+
+/**
+ * s3c64xx_eint_gpio_init() - setup handling of external gpio interrupts.
+ * @d: driver data of samsung pinctrl driver.
+ */
+static int s3c64xx_eint_gpio_init(struct samsung_pinctrl_drv_data *d)
+{
+       struct s3c64xx_eint_gpio_data *data;
+       struct samsung_pin_bank *bank;
+       struct device *dev = d->dev;
+       unsigned int nr_domains;
+       unsigned int i;
+
+       if (!d->irq) {
+               dev_err(dev, "irq number not available\n");
+               return -EINVAL;
+       }
+
+       nr_domains = 0;
+       bank = d->ctrl->pin_banks;
+       for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) {
+               unsigned int nr_eints;
+               unsigned int mask;
+
+               if (bank->eint_type != EINT_TYPE_GPIO)
+                       continue;
+
+               mask = bank->eint_mask;
+               nr_eints = fls(mask);
+
+               bank->irq_domain = irq_domain_add_linear(bank->of_node,
+                                       nr_eints, &s3c64xx_gpio_irqd_ops, bank);
+               if (!bank->irq_domain) {
+                       dev_err(dev, "gpio irq domain add failed\n");
+                       return -ENXIO;
+               }
+
+               ++nr_domains;
+       }
+
+       data = devm_kzalloc(dev, sizeof(*data)
+                       + nr_domains * sizeof(*data->domains), GFP_KERNEL);
+       if (!data) {
+               dev_err(dev, "failed to allocate handler data\n");
+               return -ENOMEM;
+       }
+       data->drvdata = d;
+
+       bank = d->ctrl->pin_banks;
+       nr_domains = 0;
+       for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) {
+               if (bank->eint_type != EINT_TYPE_GPIO)
+                       continue;
+
+               data->domains[nr_domains++] = bank->irq_domain;
+       }
+
+       irq_set_chained_handler(d->irq, s3c64xx_eint_gpio_irq);
+       irq_set_handler_data(d->irq, data);
+
+       return 0;
+}
+
+/*
+ * Functions for configuration of EINT0 wake-up interrupts
+ */
+
+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;
+       u32 val;
+
+       val = readl(d->virt_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);
+}
+
+static void s3c64xx_eint0_irq_unmask(struct irq_data *irqd)
+{
+       s3c64xx_eint0_irq_set_mask(irqd, false);
+}
+
+static void s3c64xx_eint0_irq_mask(struct irq_data *irqd)
+{
+       s3c64xx_eint0_irq_set_mask(irqd, true);
+}
+
+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;
+
+       writel(1 << ddata->eints[irqd->hwirq],
+                                       d->virt_base + EINT0PEND_REG);
+}
+
+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;
+       void __iomem *reg;
+       int trigger;
+       u8 shift;
+       u32 val;
+
+       trigger = s3c64xx_irq_get_trigger(type);
+       if (trigger < 0) {
+               pr_err("unsupported external interrupt type\n");
+               return -EINVAL;
+       }
+
+       s3c64xx_irq_set_handler(irqd->irq, type);
+
+       /* Set up interrupt trigger */
+       reg = d->virt_base + EINT0CON0_REG;
+       shift = ddata->eints[irqd->hwirq];
+       if (shift >= EINT_MAX_PER_REG) {
+               reg += 4;
+               shift -= EINT_MAX_PER_REG;
+       }
+       shift = EINT_CON_LEN * (shift / 2);
+
+       val = readl(reg);
+       val &= ~(EINT_CON_MASK << shift);
+       val |= trigger << shift;
+       writel(val, reg);
+
+       s3c64xx_irq_set_function(d, bank, irqd->hwirq);
+
+       return 0;
+}
+
+/*
+ * irq_chip for wakeup interrupts
+ */
+static struct irq_chip s3c64xx_eint0_irq_chip = {
+       .name           = "EINT0",
+       .irq_unmask     = s3c64xx_eint0_irq_unmask,
+       .irq_mask       = s3c64xx_eint0_irq_mask,
+       .irq_ack        = s3c64xx_eint0_irq_ack,
+       .irq_set_type   = s3c64xx_eint0_irq_set_type,
+};
+
+static inline void s3c64xx_irq_demux_eint(unsigned int irq,
+                                       struct irq_desc *desc, u32 range)
+{
+       struct irq_chip *chip = irq_get_chip(irq);
+       struct s3c64xx_eint0_data *data = irq_get_handler_data(irq);
+       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 = pend & range & ~mask;
+       pend &= range;
+
+       while (pend) {
+               unsigned int virq;
+
+               irq = fls(pend) - 1;
+               pend &= ~(1 << irq);
+
+               virq = irq_linear_revmap(data->domains[irq], data->pins[irq]);
+               /*
+                * Something must be really wrong if an unmapped EINT
+                * was unmasked...
+                */
+               BUG_ON(!virq);
+
+               generic_handle_irq(virq);
+       }
+
+       chained_irq_exit(chip, desc);
+}
+
+static void s3c64xx_demux_eint0_3(unsigned int irq, struct irq_desc *desc)
+{
+       s3c64xx_irq_demux_eint(irq, desc, 0xf);
+}
+
+static void s3c64xx_demux_eint4_11(unsigned int irq, struct irq_desc *desc)
+{
+       s3c64xx_irq_demux_eint(irq, desc, 0xff0);
+}
+
+static void s3c64xx_demux_eint12_19(unsigned int irq, struct irq_desc *desc)
+{
+       s3c64xx_irq_demux_eint(irq, desc, 0xff000);
+}
+
+static void s3c64xx_demux_eint20_27(unsigned int irq, struct irq_desc *desc)
+{
+       s3c64xx_irq_demux_eint(irq, desc, 0xff00000);
+}
+
+static irq_flow_handler_t s3c64xx_eint0_handlers[NUM_EINT0_IRQ] = {
+       s3c64xx_demux_eint0_3,
+       s3c64xx_demux_eint4_11,
+       s3c64xx_demux_eint12_19,
+       s3c64xx_demux_eint20_27,
+};
+
+static int s3c64xx_eint0_irq_map(struct irq_domain *h, unsigned int virq,
+                                       irq_hw_number_t hw)
+{
+       struct s3c64xx_eint0_domain_data *ddata = h->host_data;
+       struct samsung_pin_bank *bank = ddata->bank;
+
+       if (!(bank->eint_mask & (1 << hw)))
+               return -EINVAL;
+
+       irq_set_chip_and_handler(virq,
+                               &s3c64xx_eint0_irq_chip, handle_level_irq);
+       irq_set_chip_data(virq, ddata);
+       set_irq_flags(virq, IRQF_VALID);
+
+       return 0;
+}
+
+/*
+ * irq domain callbacks for external wakeup interrupt controller.
+ */
+static const struct irq_domain_ops s3c64xx_eint0_irqd_ops = {
+       .map    = s3c64xx_eint0_irq_map,
+       .xlate  = irq_domain_xlate_twocell,
+};
+
+/* list of external wakeup controllers supported */
+static const struct of_device_id s3c64xx_eint0_irq_ids[] = {
+       { .compatible = "samsung,s3c64xx-wakeup-eint", },
+       { }
+};
+
+/**
+ * s3c64xx_eint_eint0_init() - setup handling of external wakeup interrupts.
+ * @d: driver data of samsung pinctrl driver.
+ */
+static int s3c64xx_eint_eint0_init(struct samsung_pinctrl_drv_data *d)
+{
+       struct device *dev = d->dev;
+       struct device_node *eint0_np = NULL;
+       struct device_node *np;
+       struct samsung_pin_bank *bank;
+       struct s3c64xx_eint0_data *data;
+       unsigned int i;
+
+       for_each_child_of_node(dev->of_node, np) {
+               if (of_match_node(s3c64xx_eint0_irq_ids, np)) {
+                       eint0_np = np;
+                       break;
+               }
+       }
+       if (!eint0_np)
+               return -ENODEV;
+
+       data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+       if (!data) {
+               dev_err(dev, "could not allocate memory for wkup eint data\n");
+               return -ENOMEM;
+       }
+       data->drvdata = d;
+
+       for (i = 0; i < NUM_EINT0_IRQ; ++i) {
+               unsigned int irq;
+
+               irq = irq_of_parse_and_map(eint0_np, i);
+               if (!irq) {
+                       dev_err(dev, "failed to get wakeup EINT IRQ %d\n", i);
+                       return -ENXIO;
+               }
+
+               irq_set_chained_handler(irq, s3c64xx_eint0_handlers[i]);
+               irq_set_handler_data(irq, data);
+       }
+
+       bank = d->ctrl->pin_banks;
+       for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) {
+               struct s3c64xx_eint0_domain_data *ddata;
+               unsigned int nr_eints;
+               unsigned int mask;
+               unsigned int irq;
+               unsigned int pin;
+
+               if (bank->eint_type != EINT_TYPE_WKUP)
+                       continue;
+
+               mask = bank->eint_mask;
+               nr_eints = fls(mask);
+
+               ddata = devm_kzalloc(dev,
+                               sizeof(*ddata) + nr_eints, GFP_KERNEL);
+               if (!ddata) {
+                       dev_err(dev, "failed to allocate domain data\n");
+                       return -ENOMEM;
+               }
+               ddata->bank = bank;
+
+               bank->irq_domain = irq_domain_add_linear(bank->of_node,
+                               nr_eints, &s3c64xx_eint0_irqd_ops, ddata);
+               if (!bank->irq_domain) {
+                       dev_err(dev, "wkup irq domain add failed\n");
+                       return -ENXIO;
+               }
+
+               irq = bank->eint_offset;
+               mask = bank->eint_mask;
+               for (pin = 0; mask; ++pin, mask >>= 1) {
+                       if (!(mask & 1))
+                               continue;
+                       data->domains[irq] = bank->irq_domain;
+                       data->pins[irq] = pin;
+                       ddata->eints[pin] = irq;
+                       ++irq;
+               }
+       }
+
+       return 0;
+}
+
+/* pin banks of s3c64xx pin-controller 0 */
+static struct samsung_pin_bank s3c64xx_pin_banks0[] = {
+       PIN_BANK_4BIT_EINTG(8, 0x000, "gpa", 0),
+       PIN_BANK_4BIT_EINTG(7, 0x020, "gpb", 8),
+       PIN_BANK_4BIT_EINTG(8, 0x040, "gpc", 16),
+       PIN_BANK_4BIT_EINTG(5, 0x060, "gpd", 32),
+       PIN_BANK_4BIT(5, 0x080, "gpe"),
+       PIN_BANK_2BIT_EINTG(16, 0x0a0, "gpf", 48, 0x3fff),
+       PIN_BANK_4BIT_EINTG(7, 0x0c0, "gpg", 64),
+       PIN_BANK_4BIT2_EINTG(10, 0x0e0, "gph", 80),
+       PIN_BANK_2BIT(16, 0x100, "gpi"),
+       PIN_BANK_2BIT(12, 0x120, "gpj"),
+       PIN_BANK_4BIT2_ALIVE(16, 0x800, "gpk"),
+       PIN_BANK_4BIT2_EINTW(15, 0x810, "gpl", 16, 0x7f00),
+       PIN_BANK_4BIT_EINTW(6, 0x820, "gpm", 23, 0x1f),
+       PIN_BANK_2BIT_EINTW(16, 0x830, "gpn", 0),
+       PIN_BANK_2BIT_EINTG(16, 0x140, "gpo", 96, 0xffff),
+       PIN_BANK_2BIT_EINTG(15, 0x160, "gpp", 112, 0x7fff),
+       PIN_BANK_2BIT_EINTG(9, 0x180, "gpq", 128, 0x1ff),
+};
+
+/*
+ * Samsung pinctrl driver data for S3C64xx SoC. S3C64xx SoC includes
+ * one gpio/pin-mux/pinconfig controller.
+ */
+struct samsung_pin_ctrl s3c64xx_pin_ctrl[] = {
+       {
+               /* pin-controller instance 1 data */
+               .pin_banks      = s3c64xx_pin_banks0,
+               .nr_banks       = ARRAY_SIZE(s3c64xx_pin_banks0),
+               .eint_gpio_init = s3c64xx_eint_gpio_init,
+               .eint_wkup_init = s3c64xx_eint_eint0_init,
+               .label          = "S3C64xx-GPIO",
+       },
+};
diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/samsung/pinctrl-samsung.c
new file mode 100644 (file)
index 0000000..b07406d
--- /dev/null
@@ -0,0 +1,1285 @@
+/*
+ * pin-controller/pin-mux/pin-config/gpio-driver for Samsung's SoC's.
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ * Copyright (c) 2012 Linaro Ltd
+ *             http://www.linaro.org
+ *
+ * Author: Thomas Abraham <thomas.ab@samsung.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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This driver implements the Samsung pinctrl driver. It supports setting up of
+ * pinmux and pinconf configurations. The gpiolib interface is also included.
+ * External interrupt (gpio and wakeup) support are not included in this driver
+ * but provides extensions to which platform specific implementation of the gpio
+ * and wakeup interrupts can be hooked to.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/irqdomain.h>
+#include <linux/spinlock.h>
+#include <linux/syscore_ops.h>
+
+#include "../core.h"
+#include "pinctrl-samsung.h"
+
+#define GROUP_SUFFIX           "-grp"
+#define GSUFFIX_LEN            sizeof(GROUP_SUFFIX)
+#define FUNCTION_SUFFIX                "-mux"
+#define FSUFFIX_LEN            sizeof(FUNCTION_SUFFIX)
+
+/* list of all possible config options supported */
+static struct pin_config {
+       const char *property;
+       enum pincfg_type param;
+} cfg_params[] = {
+       { "samsung,pin-pud", PINCFG_TYPE_PUD },
+       { "samsung,pin-drv", PINCFG_TYPE_DRV },
+       { "samsung,pin-con-pdn", PINCFG_TYPE_CON_PDN },
+       { "samsung,pin-pud-pdn", PINCFG_TYPE_PUD_PDN },
+       { "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 inline struct samsung_pin_bank *gc_to_pin_bank(struct gpio_chip *gc)
+{
+       return container_of(gc, struct samsung_pin_bank, gpio_chip);
+}
+
+static int samsung_get_group_count(struct pinctrl_dev *pctldev)
+{
+       struct samsung_pinctrl_drv_data *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+       return pmx->nr_groups;
+}
+
+static const char *samsung_get_group_name(struct pinctrl_dev *pctldev,
+                                               unsigned group)
+{
+       struct samsung_pinctrl_drv_data *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+       return pmx->pin_groups[group].name;
+}
+
+static int samsung_get_group_pins(struct pinctrl_dev *pctldev,
+                                       unsigned group,
+                                       const unsigned **pins,
+                                       unsigned *num_pins)
+{
+       struct samsung_pinctrl_drv_data *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+       *pins = pmx->pin_groups[group].pins;
+       *num_pins = pmx->pin_groups[group].num_pins;
+
+       return 0;
+}
+
+static int reserve_map(struct device *dev, struct pinctrl_map **map,
+                      unsigned *reserved_maps, unsigned *num_maps,
+                      unsigned reserve)
+{
+       unsigned old_num = *reserved_maps;
+       unsigned new_num = *num_maps + reserve;
+       struct pinctrl_map *new_map;
+
+       if (old_num >= new_num)
+               return 0;
+
+       new_map = krealloc(*map, sizeof(*new_map) * new_num, GFP_KERNEL);
+       if (!new_map) {
+               dev_err(dev, "krealloc(map) failed\n");
+               return -ENOMEM;
+       }
+
+       memset(new_map + old_num, 0, (new_num - old_num) * sizeof(*new_map));
+
+       *map = new_map;
+       *reserved_maps = new_num;
+
+       return 0;
+}
+
+static int add_map_mux(struct pinctrl_map **map, unsigned *reserved_maps,
+                      unsigned *num_maps, const char *group,
+                      const char *function)
+{
+       if (WARN_ON(*num_maps == *reserved_maps))
+               return -ENOSPC;
+
+       (*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP;
+       (*map)[*num_maps].data.mux.group = group;
+       (*map)[*num_maps].data.mux.function = function;
+       (*num_maps)++;
+
+       return 0;
+}
+
+static int add_map_configs(struct device *dev, struct pinctrl_map **map,
+                          unsigned *reserved_maps, unsigned *num_maps,
+                          const char *group, unsigned long *configs,
+                          unsigned num_configs)
+{
+       unsigned long *dup_configs;
+
+       if (WARN_ON(*num_maps == *reserved_maps))
+               return -ENOSPC;
+
+       dup_configs = kmemdup(configs, num_configs * sizeof(*dup_configs),
+                             GFP_KERNEL);
+       if (!dup_configs) {
+               dev_err(dev, "kmemdup(configs) failed\n");
+               return -ENOMEM;
+       }
+
+       (*map)[*num_maps].type = PIN_MAP_TYPE_CONFIGS_GROUP;
+       (*map)[*num_maps].data.configs.group_or_pin = group;
+       (*map)[*num_maps].data.configs.configs = dup_configs;
+       (*map)[*num_maps].data.configs.num_configs = num_configs;
+       (*num_maps)++;
+
+       return 0;
+}
+
+static int add_config(struct device *dev, unsigned long **configs,
+                     unsigned *num_configs, unsigned long config)
+{
+       unsigned old_num = *num_configs;
+       unsigned new_num = old_num + 1;
+       unsigned long *new_configs;
+
+       new_configs = krealloc(*configs, sizeof(*new_configs) * new_num,
+                              GFP_KERNEL);
+       if (!new_configs) {
+               dev_err(dev, "krealloc(configs) failed\n");
+               return -ENOMEM;
+       }
+
+       new_configs[old_num] = config;
+
+       *configs = new_configs;
+       *num_configs = new_num;
+
+       return 0;
+}
+
+static void samsung_dt_free_map(struct pinctrl_dev *pctldev,
+                                     struct pinctrl_map *map,
+                                     unsigned num_maps)
+{
+       int i;
+
+       for (i = 0; i < num_maps; i++)
+               if (map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP)
+                       kfree(map[i].data.configs.configs);
+
+       kfree(map);
+}
+
+static int samsung_dt_subnode_to_map(struct samsung_pinctrl_drv_data *drvdata,
+                                    struct device *dev,
+                                    struct device_node *np,
+                                    struct pinctrl_map **map,
+                                    unsigned *reserved_maps,
+                                    unsigned *num_maps)
+{
+       int ret, i;
+       u32 val;
+       unsigned long config;
+       unsigned long *configs = NULL;
+       unsigned num_configs = 0;
+       unsigned reserve;
+       struct property *prop;
+       const char *group;
+       bool has_func = false;
+
+       ret = of_property_read_u32(np, "samsung,pin-function", &val);
+       if (!ret)
+               has_func = true;
+
+       for (i = 0; i < ARRAY_SIZE(cfg_params); i++) {
+               ret = of_property_read_u32(np, cfg_params[i].property, &val);
+               if (!ret) {
+                       config = PINCFG_PACK(cfg_params[i].param, val);
+                       ret = add_config(dev, &configs, &num_configs, config);
+                       if (ret < 0)
+                               goto exit;
+               /* EINVAL=missing, which is fine since it's optional */
+               } else if (ret != -EINVAL) {
+                       dev_err(dev, "could not parse property %s\n",
+                               cfg_params[i].property);
+               }
+       }
+
+       reserve = 0;
+       if (has_func)
+               reserve++;
+       if (num_configs)
+               reserve++;
+       ret = of_property_count_strings(np, "samsung,pins");
+       if (ret < 0) {
+               dev_err(dev, "could not parse property samsung,pins\n");
+               goto exit;
+       }
+       reserve *= ret;
+
+       ret = reserve_map(dev, map, reserved_maps, num_maps, reserve);
+       if (ret < 0)
+               goto exit;
+
+       of_property_for_each_string(np, "samsung,pins", prop, group) {
+               if (has_func) {
+                       ret = add_map_mux(map, reserved_maps,
+                                               num_maps, group, np->full_name);
+                       if (ret < 0)
+                               goto exit;
+               }
+
+               if (num_configs) {
+                       ret = add_map_configs(dev, map, reserved_maps,
+                                             num_maps, group, configs,
+                                             num_configs);
+                       if (ret < 0)
+                               goto exit;
+               }
+       }
+
+       ret = 0;
+
+exit:
+       kfree(configs);
+       return ret;
+}
+
+static int samsung_dt_node_to_map(struct pinctrl_dev *pctldev,
+                                       struct device_node *np_config,
+                                       struct pinctrl_map **map,
+                                       unsigned *num_maps)
+{
+       struct samsung_pinctrl_drv_data *drvdata;
+       unsigned reserved_maps;
+       struct device_node *np;
+       int ret;
+
+       drvdata = pinctrl_dev_get_drvdata(pctldev);
+
+       reserved_maps = 0;
+       *map = NULL;
+       *num_maps = 0;
+
+       if (!of_get_child_count(np_config))
+               return samsung_dt_subnode_to_map(drvdata, pctldev->dev,
+                                                       np_config, map,
+                                                       &reserved_maps,
+                                                       num_maps);
+
+       for_each_child_of_node(np_config, np) {
+               ret = samsung_dt_subnode_to_map(drvdata, pctldev->dev, np, map,
+                                               &reserved_maps, num_maps);
+               if (ret < 0) {
+                       samsung_dt_free_map(pctldev, *map, *num_maps);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+/* list of pinctrl callbacks for the pinctrl core */
+static const struct pinctrl_ops samsung_pctrl_ops = {
+       .get_groups_count       = samsung_get_group_count,
+       .get_group_name         = samsung_get_group_name,
+       .get_group_pins         = samsung_get_group_pins,
+       .dt_node_to_map         = samsung_dt_node_to_map,
+       .dt_free_map            = samsung_dt_free_map,
+};
+
+/* check if the selector is a valid pin function selector */
+static int samsung_get_functions_count(struct pinctrl_dev *pctldev)
+{
+       struct samsung_pinctrl_drv_data *drvdata;
+
+       drvdata = pinctrl_dev_get_drvdata(pctldev);
+       return drvdata->nr_functions;
+}
+
+/* return the name of the pin function specified */
+static const char *samsung_pinmux_get_fname(struct pinctrl_dev *pctldev,
+                                               unsigned selector)
+{
+       struct samsung_pinctrl_drv_data *drvdata;
+
+       drvdata = pinctrl_dev_get_drvdata(pctldev);
+       return drvdata->pmx_functions[selector].name;
+}
+
+/* return the groups associated for the specified function selector */
+static int samsung_pinmux_get_groups(struct pinctrl_dev *pctldev,
+               unsigned selector, const char * const **groups,
+               unsigned * const num_groups)
+{
+       struct samsung_pinctrl_drv_data *drvdata;
+
+       drvdata = pinctrl_dev_get_drvdata(pctldev);
+       *groups = drvdata->pmx_functions[selector].groups;
+       *num_groups = drvdata->pmx_functions[selector].num_groups;
+       return 0;
+}
+
+/*
+ * given a pin number that is local to a pin controller, find out the pin bank
+ * and the register base of the pin bank.
+ */
+static void pin_to_reg_bank(struct samsung_pinctrl_drv_data *drvdata,
+                       unsigned pin, void __iomem **reg, u32 *offset,
+                       struct samsung_pin_bank **bank)
+{
+       struct samsung_pin_bank *b;
+
+       b = drvdata->ctrl->pin_banks;
+
+       while ((pin >= b->pin_base) &&
+                       ((b->pin_base + b->nr_pins - 1) < pin))
+               b++;
+
+       *reg = drvdata->virt_base + b->pctl_offset;
+       *offset = pin - b->pin_base;
+       if (bank)
+               *bank = b;
+}
+
+/* enable or disable a pinmux function */
+static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector,
+                                       unsigned group, bool enable)
+{
+       struct samsung_pinctrl_drv_data *drvdata;
+       struct samsung_pin_bank_type *type;
+       struct samsung_pin_bank *bank;
+       void __iomem *reg;
+       u32 mask, shift, data, pin_offset;
+       unsigned long flags;
+       const struct samsung_pmx_func *func;
+       const struct samsung_pin_group *grp;
+
+       drvdata = pinctrl_dev_get_drvdata(pctldev);
+       func = &drvdata->pmx_functions[selector];
+       grp = &drvdata->pin_groups[group];
+
+       pin_to_reg_bank(drvdata, grp->pins[0] - drvdata->ctrl->base,
+                       &reg, &pin_offset, &bank);
+       type = bank->type;
+       mask = (1 << type->fld_width[PINCFG_TYPE_FUNC]) - 1;
+       shift = pin_offset * type->fld_width[PINCFG_TYPE_FUNC];
+       if (shift >= 32) {
+               /* Some banks have two config registers */
+               shift -= 32;
+               reg += 4;
+       }
+
+       spin_lock_irqsave(&bank->slock, flags);
+
+       data = readl(reg + type->reg_offset[PINCFG_TYPE_FUNC]);
+       data &= ~(mask << shift);
+       if (enable)
+               data |= func->val << shift;
+       writel(data, reg + type->reg_offset[PINCFG_TYPE_FUNC]);
+
+       spin_unlock_irqrestore(&bank->slock, flags);
+}
+
+/* enable a specified pinmux by writing to registers */
+static int samsung_pinmux_enable(struct pinctrl_dev *pctldev, unsigned selector,
+                                       unsigned group)
+{
+       samsung_pinmux_setup(pctldev, selector, group, true);
+       return 0;
+}
+
+/* list of pinmux callbacks for the pinmux vertical in pinctrl core */
+static const struct pinmux_ops samsung_pinmux_ops = {
+       .get_functions_count    = samsung_get_functions_count,
+       .get_function_name      = samsung_pinmux_get_fname,
+       .get_function_groups    = samsung_pinmux_get_groups,
+       .enable                 = samsung_pinmux_enable,
+};
+
+/* set or get the pin config settings for a specified pin */
+static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin,
+                               unsigned long *config, bool set)
+{
+       struct samsung_pinctrl_drv_data *drvdata;
+       struct samsung_pin_bank_type *type;
+       struct samsung_pin_bank *bank;
+       void __iomem *reg_base;
+       enum pincfg_type cfg_type = PINCFG_UNPACK_TYPE(*config);
+       u32 data, width, pin_offset, mask, shift;
+       u32 cfg_value, cfg_reg;
+       unsigned long flags;
+
+       drvdata = pinctrl_dev_get_drvdata(pctldev);
+       pin_to_reg_bank(drvdata, pin - drvdata->ctrl->base, &reg_base,
+                                       &pin_offset, &bank);
+       type = bank->type;
+
+       if (cfg_type >= PINCFG_TYPE_NUM || !type->fld_width[cfg_type])
+               return -EINVAL;
+
+       width = type->fld_width[cfg_type];
+       cfg_reg = type->reg_offset[cfg_type];
+
+       spin_lock_irqsave(&bank->slock, flags);
+
+       mask = (1 << width) - 1;
+       shift = pin_offset * width;
+       data = readl(reg_base + cfg_reg);
+
+       if (set) {
+               cfg_value = PINCFG_UNPACK_VALUE(*config);
+               data &= ~(mask << shift);
+               data |= (cfg_value << shift);
+               writel(data, reg_base + cfg_reg);
+       } else {
+               data >>= shift;
+               data &= mask;
+               *config = PINCFG_PACK(cfg_type, data);
+       }
+
+       spin_unlock_irqrestore(&bank->slock, flags);
+
+       return 0;
+}
+
+/* set the pin config settings for a specified pin */
+static int samsung_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
+                               unsigned long *configs, unsigned num_configs)
+{
+       int i, ret;
+
+       for (i = 0; i < num_configs; i++) {
+               ret = samsung_pinconf_rw(pctldev, pin, &configs[i], true);
+               if (ret < 0)
+                       return ret;
+       } /* for each config */
+
+       return 0;
+}
+
+/* get the pin config settings for a specified pin */
+static int samsung_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin,
+                                       unsigned long *config)
+{
+       return samsung_pinconf_rw(pctldev, pin, config, false);
+}
+
+/* set the pin config settings for a specified pin group */
+static int samsung_pinconf_group_set(struct pinctrl_dev *pctldev,
+                       unsigned group, unsigned long *configs,
+                       unsigned num_configs)
+{
+       struct samsung_pinctrl_drv_data *drvdata;
+       const unsigned int *pins;
+       unsigned int cnt;
+
+       drvdata = pinctrl_dev_get_drvdata(pctldev);
+       pins = drvdata->pin_groups[group].pins;
+
+       for (cnt = 0; cnt < drvdata->pin_groups[group].num_pins; cnt++)
+               samsung_pinconf_set(pctldev, pins[cnt], configs, num_configs);
+
+       return 0;
+}
+
+/* get the pin config settings for a specified pin group */
+static int samsung_pinconf_group_get(struct pinctrl_dev *pctldev,
+                               unsigned int group, unsigned long *config)
+{
+       struct samsung_pinctrl_drv_data *drvdata;
+       const unsigned int *pins;
+
+       drvdata = pinctrl_dev_get_drvdata(pctldev);
+       pins = drvdata->pin_groups[group].pins;
+       samsung_pinconf_get(pctldev, pins[0], config);
+       return 0;
+}
+
+/* list of pinconfig callbacks for pinconfig vertical in the pinctrl code */
+static const struct pinconf_ops samsung_pinconf_ops = {
+       .pin_config_get         = samsung_pinconf_get,
+       .pin_config_set         = samsung_pinconf_set,
+       .pin_config_group_get   = samsung_pinconf_group_get,
+       .pin_config_group_set   = samsung_pinconf_group_set,
+};
+
+/* gpiolib gpio_set callback function */
+static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
+{
+       struct samsung_pin_bank *bank = gc_to_pin_bank(gc);
+       struct samsung_pin_bank_type *type = bank->type;
+       unsigned long flags;
+       void __iomem *reg;
+       u32 data;
+
+       reg = bank->drvdata->virt_base + bank->pctl_offset;
+
+       spin_lock_irqsave(&bank->slock, flags);
+
+       data = readl(reg + type->reg_offset[PINCFG_TYPE_DAT]);
+       data &= ~(1 << offset);
+       if (value)
+               data |= 1 << offset;
+       writel(data, reg + type->reg_offset[PINCFG_TYPE_DAT]);
+
+       spin_unlock_irqrestore(&bank->slock, flags);
+}
+
+/* gpiolib gpio_get callback function */
+static int samsung_gpio_get(struct gpio_chip *gc, unsigned offset)
+{
+       void __iomem *reg;
+       u32 data;
+       struct samsung_pin_bank *bank = gc_to_pin_bank(gc);
+       struct samsung_pin_bank_type *type = bank->type;
+
+       reg = bank->drvdata->virt_base + bank->pctl_offset;
+
+       data = readl(reg + type->reg_offset[PINCFG_TYPE_DAT]);
+       data >>= offset;
+       data &= 1;
+       return data;
+}
+
+/*
+ * The calls to gpio_direction_output() and gpio_direction_input()
+ * leads to this function call.
+ */
+static int samsung_gpio_set_direction(struct gpio_chip *gc,
+                                            unsigned offset, bool input)
+{
+       struct samsung_pin_bank_type *type;
+       struct samsung_pin_bank *bank;
+       struct samsung_pinctrl_drv_data *drvdata;
+       void __iomem *reg;
+       u32 data, mask, shift;
+       unsigned long flags;
+
+       bank = gc_to_pin_bank(gc);
+       type = bank->type;
+       drvdata = bank->drvdata;
+
+       reg = drvdata->virt_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];
+       if (shift >= 32) {
+               /* Some banks have two config registers */
+               shift -= 32;
+               reg += 4;
+       }
+
+       spin_lock_irqsave(&bank->slock, flags);
+
+       data = readl(reg);
+       data &= ~(mask << shift);
+       if (!input)
+               data |= FUNC_OUTPUT << shift;
+       writel(data, reg);
+
+       spin_unlock_irqrestore(&bank->slock, flags);
+
+       return 0;
+}
+
+/* gpiolib gpio_direction_input callback function. */
+static int samsung_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
+{
+       return samsung_gpio_set_direction(gc, offset, true);
+}
+
+/* gpiolib gpio_direction_output callback function. */
+static int samsung_gpio_direction_output(struct gpio_chip *gc, unsigned offset,
+                                                       int value)
+{
+       samsung_gpio_set(gc, offset, value);
+       return samsung_gpio_set_direction(gc, offset, false);
+}
+
+/*
+ * gpiolib gpio_to_irq callback function. Creates a mapping between a GPIO pin
+ * and a virtual IRQ, if not already present.
+ */
+static int samsung_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
+{
+       struct samsung_pin_bank *bank = gc_to_pin_bank(gc);
+       unsigned int virq;
+
+       if (!bank->irq_domain)
+               return -ENXIO;
+
+       virq = irq_create_mapping(bank->irq_domain, offset);
+
+       return (virq) ? : -ENXIO;
+}
+
+static struct samsung_pin_group *samsung_pinctrl_create_groups(
+                               struct device *dev,
+                               struct samsung_pinctrl_drv_data *drvdata,
+                               unsigned int *cnt)
+{
+       struct pinctrl_desc *ctrldesc = &drvdata->pctl;
+       struct samsung_pin_group *groups, *grp;
+       const struct pinctrl_pin_desc *pdesc;
+       int i;
+
+       groups = devm_kzalloc(dev, ctrldesc->npins * sizeof(*groups),
+                               GFP_KERNEL);
+       if (!groups)
+               return ERR_PTR(-EINVAL);
+       grp = groups;
+
+       pdesc = ctrldesc->pins;
+       for (i = 0; i < ctrldesc->npins; ++i, ++pdesc, ++grp) {
+               grp->name = pdesc->name;
+               grp->pins = &pdesc->number;
+               grp->num_pins = 1;
+       }
+
+       *cnt = ctrldesc->npins;
+       return groups;
+}
+
+static int samsung_pinctrl_create_function(struct device *dev,
+                               struct samsung_pinctrl_drv_data *drvdata,
+                               struct device_node *func_np,
+                               struct samsung_pmx_func *func)
+{
+       int npins;
+       int ret;
+       int i;
+
+       if (of_property_read_u32(func_np, "samsung,pin-function", &func->val))
+               return 0;
+
+       npins = of_property_count_strings(func_np, "samsung,pins");
+       if (npins < 1) {
+               dev_err(dev, "invalid pin list in %s node", func_np->name);
+               return -EINVAL;
+       }
+
+       func->name = func_np->full_name;
+
+       func->groups = devm_kzalloc(dev, npins * sizeof(char *), GFP_KERNEL);
+       if (!func->groups)
+               return -ENOMEM;
+
+       for (i = 0; i < npins; ++i) {
+               const char *gname;
+
+               ret = of_property_read_string_index(func_np, "samsung,pins",
+                                                       i, &gname);
+               if (ret) {
+                       dev_err(dev,
+                               "failed to read pin name %d from %s node\n",
+                               i, func_np->name);
+                       return ret;
+               }
+
+               func->groups[i] = gname;
+       }
+
+       func->num_groups = npins;
+       return 1;
+}
+
+static struct samsung_pmx_func *samsung_pinctrl_create_functions(
+                               struct device *dev,
+                               struct samsung_pinctrl_drv_data *drvdata,
+                               unsigned int *cnt)
+{
+       struct samsung_pmx_func *functions, *func;
+       struct device_node *dev_np = dev->of_node;
+       struct device_node *cfg_np;
+       unsigned int func_cnt = 0;
+       int ret;
+
+       /*
+        * Iterate over all the child nodes of the pin controller node
+        * and create pin groups and pin function lists.
+        */
+       for_each_child_of_node(dev_np, cfg_np) {
+               struct device_node *func_np;
+
+               if (!of_get_child_count(cfg_np)) {
+                       if (!of_find_property(cfg_np,
+                           "samsung,pin-function", NULL))
+                               continue;
+                       ++func_cnt;
+                       continue;
+               }
+
+               for_each_child_of_node(cfg_np, func_np) {
+                       if (!of_find_property(func_np,
+                           "samsung,pin-function", NULL))
+                               continue;
+                       ++func_cnt;
+               }
+       }
+
+       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);
+       }
+       func = functions;
+
+       /*
+        * Iterate over all the child nodes of the pin controller node
+        * and create pin groups and pin function lists.
+        */
+       func_cnt = 0;
+       for_each_child_of_node(dev_np, cfg_np) {
+               struct device_node *func_np;
+
+               if (!of_get_child_count(cfg_np)) {
+                       ret = samsung_pinctrl_create_function(dev, drvdata,
+                                                       cfg_np, func);
+                       if (ret < 0)
+                               return ERR_PTR(ret);
+                       if (ret > 0) {
+                               ++func;
+                               ++func_cnt;
+                       }
+                       continue;
+               }
+
+               for_each_child_of_node(cfg_np, func_np) {
+                       ret = samsung_pinctrl_create_function(dev, drvdata,
+                                               func_np, func);
+                       if (ret < 0)
+                               return ERR_PTR(ret);
+                       if (ret > 0) {
+                               ++func;
+                               ++func_cnt;
+                       }
+               }
+       }
+
+       *cnt = func_cnt;
+       return functions;
+}
+
+/*
+ * Parse the information about all the available pin groups and pin functions
+ * from device node of the pin-controller. A pin group is formed with all
+ * the pins listed in the "samsung,pins" property.
+ */
+
+static int samsung_pinctrl_parse_dt(struct platform_device *pdev,
+                                   struct samsung_pinctrl_drv_data *drvdata)
+{
+       struct device *dev = &pdev->dev;
+       struct samsung_pin_group *groups;
+       struct samsung_pmx_func *functions;
+       unsigned int grp_cnt = 0, func_cnt = 0;
+
+       groups = samsung_pinctrl_create_groups(dev, drvdata, &grp_cnt);
+       if (IS_ERR(groups)) {
+               dev_err(dev, "failed to parse pin groups\n");
+               return PTR_ERR(groups);
+       }
+
+       functions = samsung_pinctrl_create_functions(dev, drvdata, &func_cnt);
+       if (IS_ERR(functions)) {
+               dev_err(dev, "failed to parse pin functions\n");
+               return PTR_ERR(groups);
+       }
+
+       drvdata->pin_groups = groups;
+       drvdata->nr_groups = grp_cnt;
+       drvdata->pmx_functions = functions;
+       drvdata->nr_functions = func_cnt;
+
+       return 0;
+}
+
+/* register the pinctrl interface with the pinctrl subsystem */
+static int samsung_pinctrl_register(struct platform_device *pdev,
+                                   struct samsung_pinctrl_drv_data *drvdata)
+{
+       struct pinctrl_desc *ctrldesc = &drvdata->pctl;
+       struct pinctrl_pin_desc *pindesc, *pdesc;
+       struct samsung_pin_bank *pin_bank;
+       char *pin_names;
+       int pin, bank, ret;
+
+       ctrldesc->name = "samsung-pinctrl";
+       ctrldesc->owner = THIS_MODULE;
+       ctrldesc->pctlops = &samsung_pctrl_ops;
+       ctrldesc->pmxops = &samsung_pinmux_ops;
+       ctrldesc->confops = &samsung_pinconf_ops;
+
+       pindesc = devm_kzalloc(&pdev->dev, sizeof(*pindesc) *
+                       drvdata->ctrl->nr_pins, GFP_KERNEL);
+       if (!pindesc) {
+               dev_err(&pdev->dev, "mem alloc for pin descriptors failed\n");
+               return -ENOMEM;
+       }
+       ctrldesc->pins = pindesc;
+       ctrldesc->npins = drvdata->ctrl->nr_pins;
+
+       /* dynamically populate the pin number and pin name for pindesc */
+       for (pin = 0, pdesc = pindesc; pin < ctrldesc->npins; pin++, pdesc++)
+               pdesc->number = pin + drvdata->ctrl->base;
+
+       /*
+        * allocate space for storing the dynamically generated names for all
+        * the pins which belong to this pin-controller.
+        */
+       pin_names = devm_kzalloc(&pdev->dev, sizeof(char) * PIN_NAME_LENGTH *
+                                       drvdata->ctrl->nr_pins, GFP_KERNEL);
+       if (!pin_names) {
+               dev_err(&pdev->dev, "mem alloc for pin names failed\n");
+               return -ENOMEM;
+       }
+
+       /* for each pin, the name of the pin is pin-bank name + pin number */
+       for (bank = 0; bank < drvdata->ctrl->nr_banks; bank++) {
+               pin_bank = &drvdata->ctrl->pin_banks[bank];
+               for (pin = 0; pin < pin_bank->nr_pins; pin++) {
+                       sprintf(pin_names, "%s-%d", pin_bank->name, pin);
+                       pdesc = pindesc + pin_bank->pin_base + pin;
+                       pdesc->name = pin_names;
+                       pin_names += PIN_NAME_LENGTH;
+               }
+       }
+
+       ret = samsung_pinctrl_parse_dt(pdev, drvdata);
+       if (ret)
+               return ret;
+
+       drvdata->pctl_dev = pinctrl_register(ctrldesc, &pdev->dev, drvdata);
+       if (!drvdata->pctl_dev) {
+               dev_err(&pdev->dev, "could not register pinctrl driver\n");
+               return -EINVAL;
+       }
+
+       for (bank = 0; bank < drvdata->ctrl->nr_banks; ++bank) {
+               pin_bank = &drvdata->ctrl->pin_banks[bank];
+               pin_bank->grange.name = pin_bank->name;
+               pin_bank->grange.id = bank;
+               pin_bank->grange.pin_base = drvdata->ctrl->base
+                                               + pin_bank->pin_base;
+               pin_bank->grange.base = pin_bank->gpio_chip.base;
+               pin_bank->grange.npins = pin_bank->gpio_chip.ngpio;
+               pin_bank->grange.gc = &pin_bank->gpio_chip;
+               pinctrl_add_gpio_range(drvdata->pctl_dev, &pin_bank->grange);
+       }
+
+       return 0;
+}
+
+static int samsung_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+       return pinctrl_request_gpio(chip->base + offset);
+}
+
+static void samsung_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+       pinctrl_free_gpio(chip->base + offset);
+}
+
+static const struct gpio_chip samsung_gpiolib_chip = {
+       .request = samsung_gpio_request,
+       .free = samsung_gpio_free,
+       .set = samsung_gpio_set,
+       .get = samsung_gpio_get,
+       .direction_input = samsung_gpio_direction_input,
+       .direction_output = samsung_gpio_direction_output,
+       .to_irq = samsung_gpio_to_irq,
+       .owner = THIS_MODULE,
+};
+
+/* register the gpiolib interface with the gpiolib subsystem */
+static int samsung_gpiolib_register(struct platform_device *pdev,
+                                   struct samsung_pinctrl_drv_data *drvdata)
+{
+       struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
+       struct samsung_pin_bank *bank = ctrl->pin_banks;
+       struct gpio_chip *gc;
+       int ret;
+       int i;
+
+       for (i = 0; i < ctrl->nr_banks; ++i, ++bank) {
+               bank->gpio_chip = samsung_gpiolib_chip;
+
+               gc = &bank->gpio_chip;
+               gc->base = ctrl->base + bank->pin_base;
+               gc->ngpio = bank->nr_pins;
+               gc->dev = &pdev->dev;
+               gc->of_node = bank->of_node;
+               gc->label = bank->name;
+
+               ret = gpiochip_add(gc);
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to register gpio_chip %s, error code: %d\n",
+                                                       gc->label, ret);
+                       goto fail;
+               }
+       }
+
+       return 0;
+
+fail:
+       for (--i, --bank; i >= 0; --i, --bank)
+               if (gpiochip_remove(&bank->gpio_chip))
+                       dev_err(&pdev->dev, "gpio chip %s remove failed\n",
+                                                       bank->gpio_chip.label);
+       return ret;
+}
+
+/* unregister the gpiolib interface with the gpiolib subsystem */
+static int samsung_gpiolib_unregister(struct platform_device *pdev,
+                                     struct samsung_pinctrl_drv_data *drvdata)
+{
+       struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
+       struct samsung_pin_bank *bank = ctrl->pin_banks;
+       int ret = 0;
+       int i;
+
+       for (i = 0; !ret && i < ctrl->nr_banks; ++i, ++bank)
+               ret = gpiochip_remove(&bank->gpio_chip);
+
+       if (ret)
+               dev_err(&pdev->dev, "gpio chip remove failed\n");
+
+       return ret;
+}
+
+static const struct of_device_id samsung_pinctrl_dt_match[];
+
+/* retrieve the soc specific data */
+static 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;
+       struct samsung_pin_ctrl *ctrl;
+       struct samsung_pin_bank *bank;
+       int i;
+
+       id = of_alias_get_id(node, "pinctrl");
+       if (id < 0) {
+               dev_err(&pdev->dev, "failed to get alias id\n");
+               return NULL;
+       }
+       match = of_match_node(samsung_pinctrl_dt_match, node);
+       ctrl = (struct samsung_pin_ctrl *)match->data + id;
+
+       bank = ctrl->pin_banks;
+       for (i = 0; i < ctrl->nr_banks; ++i, ++bank) {
+               spin_lock_init(&bank->slock);
+               bank->drvdata = d;
+               bank->pin_base = ctrl->nr_pins;
+               ctrl->nr_pins += bank->nr_pins;
+       }
+
+       for_each_child_of_node(node, np) {
+               if (!of_find_property(np, "gpio-controller", NULL))
+                       continue;
+               bank = ctrl->pin_banks;
+               for (i = 0; i < ctrl->nr_banks; ++i, ++bank) {
+                       if (!strcmp(bank->name, np->name)) {
+                               bank->of_node = np;
+                               break;
+                       }
+               }
+       }
+
+       ctrl->base = pin_base;
+       pin_base += ctrl->nr_pins;
+
+       return ctrl;
+}
+
+static int samsung_pinctrl_probe(struct platform_device *pdev)
+{
+       struct samsung_pinctrl_drv_data *drvdata;
+       struct device *dev = &pdev->dev;
+       struct samsung_pin_ctrl *ctrl;
+       struct resource *res;
+       int ret;
+
+       if (!dev->of_node) {
+               dev_err(dev, "device tree node not found\n");
+               return -ENODEV;
+       }
+
+       drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+       if (!drvdata) {
+               dev_err(dev, "failed to allocate memory for driver's "
+                               "private data\n");
+               return -ENOMEM;
+       }
+
+       ctrl = samsung_pinctrl_get_soc_data(drvdata, pdev);
+       if (!ctrl) {
+               dev_err(&pdev->dev, "driver data not available\n");
+               return -EINVAL;
+       }
+       drvdata->ctrl = ctrl;
+       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;
+
+       ret = samsung_gpiolib_register(pdev, drvdata);
+       if (ret)
+               return ret;
+
+       ret = samsung_pinctrl_register(pdev, drvdata);
+       if (ret) {
+               samsung_gpiolib_unregister(pdev, drvdata);
+               return ret;
+       }
+
+       if (ctrl->eint_gpio_init)
+               ctrl->eint_gpio_init(drvdata);
+       if (ctrl->eint_wkup_init)
+               ctrl->eint_wkup_init(drvdata);
+
+       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
+ *
+ * Save data for all banks handled by this device.
+ */
+static void samsung_pinctrl_suspend_dev(
+       struct samsung_pinctrl_drv_data *drvdata)
+{
+       struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
+       void __iomem *virt_base = drvdata->virt_base;
+       int i;
+
+       for (i = 0; i < ctrl->nr_banks; i++) {
+               struct samsung_pin_bank *bank = &ctrl->pin_banks[i];
+               void __iomem *reg = virt_base + bank->pctl_offset;
+
+               u8 *offs = bank->type->reg_offset;
+               u8 *widths = bank->type->fld_width;
+               enum pincfg_type type;
+
+               /* Registers without a powerdown config aren't lost */
+               if (!widths[PINCFG_TYPE_CON_PDN])
+                       continue;
+
+               for (type = 0; type < PINCFG_TYPE_NUM; type++)
+                       if (widths[type])
+                               bank->pm_save[type] = readl(reg + offs[type]);
+
+               if (widths[PINCFG_TYPE_FUNC] * bank->nr_pins > 32) {
+                       /* Some banks have two config registers */
+                       bank->pm_save[PINCFG_TYPE_NUM] =
+                               readl(reg + offs[PINCFG_TYPE_FUNC] + 4);
+                       pr_debug("Save %s @ %p (con %#010x %08x)\n",
+                                bank->name, reg,
+                                bank->pm_save[PINCFG_TYPE_FUNC],
+                                bank->pm_save[PINCFG_TYPE_NUM]);
+               } else {
+                       pr_debug("Save %s @ %p (con %#010x)\n", bank->name,
+                                reg, bank->pm_save[PINCFG_TYPE_FUNC]);
+               }
+       }
+
+       if (ctrl->suspend)
+               ctrl->suspend(drvdata);
+}
+
+/**
+ * samsung_pinctrl_resume_dev - restore pinctrl state from suspend for a device
+ *
+ * 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)
+{
+       struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
+       void __iomem *virt_base = drvdata->virt_base;
+       int i;
+
+       if (ctrl->resume)
+               ctrl->resume(drvdata);
+
+       for (i = 0; i < ctrl->nr_banks; i++) {
+               struct samsung_pin_bank *bank = &ctrl->pin_banks[i];
+               void __iomem *reg = virt_base + bank->pctl_offset;
+
+               u8 *offs = bank->type->reg_offset;
+               u8 *widths = bank->type->fld_width;
+               enum pincfg_type type;
+
+               /* Registers without a powerdown config aren't lost */
+               if (!widths[PINCFG_TYPE_CON_PDN])
+                       continue;
+
+               if (widths[PINCFG_TYPE_FUNC] * bank->nr_pins > 32) {
+                       /* Some banks have two config registers */
+                       pr_debug("%s @ %p (con %#010x %08x => %#010x %08x)\n",
+                                bank->name, reg,
+                                readl(reg + offs[PINCFG_TYPE_FUNC]),
+                                readl(reg + offs[PINCFG_TYPE_FUNC] + 4),
+                                bank->pm_save[PINCFG_TYPE_FUNC],
+                                bank->pm_save[PINCFG_TYPE_NUM]);
+                       writel(bank->pm_save[PINCFG_TYPE_NUM],
+                              reg + offs[PINCFG_TYPE_FUNC] + 4);
+               } else {
+                       pr_debug("%s @ %p (con %#010x => %#010x)\n", bank->name,
+                                reg, readl(reg + offs[PINCFG_TYPE_FUNC]),
+                                bank->pm_save[PINCFG_TYPE_FUNC]);
+               }
+               for (type = 0; type < PINCFG_TYPE_NUM; type++)
+                       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);
+       }
+
+       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",
+               .data = (void *)exynos3250_pin_ctrl },
+       { .compatible = "samsung,exynos4210-pinctrl",
+               .data = (void *)exynos4210_pin_ctrl },
+       { .compatible = "samsung,exynos4x12-pinctrl",
+               .data = (void *)exynos4x12_pin_ctrl },
+       { .compatible = "samsung,exynos5250-pinctrl",
+               .data = (void *)exynos5250_pin_ctrl },
+       { .compatible = "samsung,exynos5260-pinctrl",
+               .data = (void *)exynos5260_pin_ctrl },
+       { .compatible = "samsung,exynos5420-pinctrl",
+               .data = (void *)exynos5420_pin_ctrl },
+       { .compatible = "samsung,s5pv210-pinctrl",
+               .data = (void *)s5pv210_pin_ctrl },
+#endif
+#ifdef CONFIG_PINCTRL_S3C64XX
+       { .compatible = "samsung,s3c64xx-pinctrl",
+               .data = s3c64xx_pin_ctrl },
+#endif
+#ifdef CONFIG_PINCTRL_S3C24XX
+       { .compatible = "samsung,s3c2412-pinctrl",
+               .data = s3c2412_pin_ctrl },
+       { .compatible = "samsung,s3c2416-pinctrl",
+               .data = s3c2416_pin_ctrl },
+       { .compatible = "samsung,s3c2440-pinctrl",
+               .data = s3c2440_pin_ctrl },
+       { .compatible = "samsung,s3c2450-pinctrl",
+               .data = s3c2450_pin_ctrl },
+#endif
+       {},
+};
+MODULE_DEVICE_TABLE(of, samsung_pinctrl_dt_match);
+
+static struct platform_driver samsung_pinctrl_driver = {
+       .probe          = samsung_pinctrl_probe,
+       .driver = {
+               .name   = "samsung-pinctrl",
+               .owner  = THIS_MODULE,
+               .of_match_table = samsung_pinctrl_dt_match,
+       },
+};
+
+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);
+
+static void __exit samsung_pinctrl_drv_unregister(void)
+{
+       platform_driver_unregister(&samsung_pinctrl_driver);
+}
+module_exit(samsung_pinctrl_drv_unregister);
+
+MODULE_AUTHOR("Thomas Abraham <thomas.ab@samsung.com>");
+MODULE_DESCRIPTION("Samsung pinctrl driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.h b/drivers/pinctrl/samsung/pinctrl-samsung.h
new file mode 100644 (file)
index 0000000..2b88232
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * pin-controller/pin-mux/pin-config/gpio-driver for Samsung's SoC's.
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ * Copyright (c) 2012 Linaro Ltd
+ *             http://www.linaro.org
+ *
+ * Author: Thomas Abraham <thomas.ab@samsung.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; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __PINCTRL_SAMSUNG_H
+#define __PINCTRL_SAMSUNG_H
+
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/pinctrl/machine.h>
+
+#include <linux/gpio.h>
+
+/* pinmux function number for pin as gpio output line */
+#define FUNC_OUTPUT    0x1
+
+/**
+ * enum pincfg_type - possible pin configuration types supported.
+ * @PINCFG_TYPE_FUNC: Function configuration.
+ * @PINCFG_TYPE_DAT: Pin value configuration.
+ * @PINCFG_TYPE_PUD: Pull up/down configuration.
+ * @PINCFG_TYPE_DRV: Drive strength configuration.
+ * @PINCFG_TYPE_CON_PDN: Pin function in power down mode.
+ * @PINCFG_TYPE_PUD_PDN: Pull up/down configuration in power down mode.
+ */
+enum pincfg_type {
+       PINCFG_TYPE_FUNC,
+       PINCFG_TYPE_DAT,
+       PINCFG_TYPE_PUD,
+       PINCFG_TYPE_DRV,
+       PINCFG_TYPE_CON_PDN,
+       PINCFG_TYPE_PUD_PDN,
+
+       PINCFG_TYPE_NUM
+};
+
+/*
+ * pin configuration (pull up/down and drive strength) type and its value are
+ * packed together into a 16-bits. The upper 8-bits represent the configuration
+ * type and the lower 8-bits hold the value of the configuration type.
+ */
+#define PINCFG_TYPE_MASK               0xFF
+#define PINCFG_VALUE_SHIFT             8
+#define PINCFG_VALUE_MASK              (0xFF << PINCFG_VALUE_SHIFT)
+#define PINCFG_PACK(type, value)       (((value) << PINCFG_VALUE_SHIFT) | type)
+#define PINCFG_UNPACK_TYPE(cfg)                ((cfg) & PINCFG_TYPE_MASK)
+#define PINCFG_UNPACK_VALUE(cfg)       (((cfg) & PINCFG_VALUE_MASK) >> \
+                                               PINCFG_VALUE_SHIFT)
+/**
+ * enum eint_type - possible external interrupt types.
+ * @EINT_TYPE_NONE: bank does not support external interrupts
+ * @EINT_TYPE_GPIO: bank supportes external gpio interrupts
+ * @EINT_TYPE_WKUP: bank supportes external wakeup interrupts
+ * @EINT_TYPE_WKUP_MUX: bank supports multiplexed external wakeup interrupts
+ *
+ * Samsung GPIO controller groups all the available pins into banks. The pins
+ * in a pin bank can support external gpio interrupts or external wakeup
+ * interrupts or no interrupts at all. From a software perspective, the only
+ * difference between external gpio and external wakeup interrupts is that
+ * the wakeup interrupts can additionally wakeup the system if it is in
+ * suspended state.
+ */
+enum eint_type {
+       EINT_TYPE_NONE,
+       EINT_TYPE_GPIO,
+       EINT_TYPE_WKUP,
+       EINT_TYPE_WKUP_MUX,
+};
+
+/* maximum length of a pin in pin descriptor (example: "gpa0-0") */
+#define PIN_NAME_LENGTH        10
+
+#define PIN_GROUP(n, p, f)                             \
+       {                                               \
+               .name           = n,                    \
+               .pins           = p,                    \
+               .num_pins       = ARRAY_SIZE(p),        \
+               .func           = f                     \
+       }
+
+#define PMX_FUNC(n, g)                                 \
+       {                                               \
+               .name           = n,                    \
+               .groups         = g,                    \
+               .num_groups     = ARRAY_SIZE(g),        \
+       }
+
+struct samsung_pinctrl_drv_data;
+
+/**
+ * struct samsung_pin_bank_type: pin bank type description
+ * @fld_width: widths of configuration bitfields (0 if unavailable)
+ * @reg_offset: offsets of configuration registers (don't care of width is 0)
+ */
+struct samsung_pin_bank_type {
+       u8 fld_width[PINCFG_TYPE_NUM];
+       u8 reg_offset[PINCFG_TYPE_NUM];
+};
+
+/**
+ * struct samsung_pin_bank: represent a controller pin-bank.
+ * @type: type of the bank (register offsets and bitfield widths)
+ * @pctl_offset: starting offset of the pin-bank registers.
+ * @pin_base: starting pin number of the bank.
+ * @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.
+ * @eint_mask: bit mask of pins which support EINT function.
+ * @name: name to be prefixed for each pin in this pin bank.
+ * @of_node: OF node of the bank.
+ * @drvdata: link to controller driver data
+ * @irq_domain: IRQ domain of the bank.
+ * @gpio_chip: GPIO chip of the bank.
+ * @grange: linux gpio pin range supported by this bank.
+ * @slock: spinlock protecting bank registers
+ * @pm_save: saved register values during suspend
+ */
+struct samsung_pin_bank {
+       struct samsung_pin_bank_type *type;
+       u32             pctl_offset;
+       u32             pin_base;
+       u8              nr_pins;
+       u8              eint_func;
+       enum eint_type  eint_type;
+       u32             eint_mask;
+       u32             eint_offset;
+       char            *name;
+       void            *soc_priv;
+       struct device_node *of_node;
+       struct samsung_pinctrl_drv_data *drvdata;
+       struct irq_domain *irq_domain;
+       struct gpio_chip gpio_chip;
+       struct pinctrl_gpio_range grange;
+       spinlock_t slock;
+
+       u32 pm_save[PINCFG_TYPE_NUM + 1]; /* +1 to handle double CON registers*/
+};
+
+/**
+ * struct samsung_pin_ctrl: represent a pin controller.
+ * @pin_banks: list of pin banks included in this controller.
+ * @nr_banks: number of pin banks.
+ * @base: starting system wide pin number.
+ * @nr_pins: number of pins supported by the controller.
+ * @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
+ *     interrupts for the controller.
+ * @label: for debug information.
+ */
+struct samsung_pin_ctrl {
+       struct samsung_pin_bank *pin_banks;
+       u32             nr_banks;
+
+       u32             base;
+       u32             nr_pins;
+
+       int             (*eint_gpio_init)(struct samsung_pinctrl_drv_data *);
+       int             (*eint_wkup_init)(struct samsung_pinctrl_drv_data *);
+       void            (*suspend)(struct samsung_pinctrl_drv_data *);
+       void            (*resume)(struct samsung_pinctrl_drv_data *);
+
+       char            *label;
+};
+
+/**
+ * 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.
+ * @pctl: pin controller descriptor registered with the pinctrl subsystem.
+ * @pctl_dev: cookie representing pinctrl device instance.
+ * @pin_groups: list of pin groups available to the driver.
+ * @nr_groups: number of such pin groups.
+ * @pmx_functions: list of pin functions available to the driver.
+ * @nr_function: number of such pin functions.
+ */
+struct samsung_pinctrl_drv_data {
+       struct list_head                node;
+       void __iomem                    *virt_base;
+       struct device                   *dev;
+       int                             irq;
+
+       struct samsung_pin_ctrl         *ctrl;
+       struct pinctrl_desc             pctl;
+       struct pinctrl_dev              *pctl_dev;
+
+       const struct samsung_pin_group  *pin_groups;
+       unsigned int                    nr_groups;
+       const struct samsung_pmx_func   *pmx_functions;
+       unsigned int                    nr_functions;
+};
+
+/**
+ * struct samsung_pin_group: represent group of pins of a pinmux function.
+ * @name: name of the pin group, used to lookup the group.
+ * @pins: the pins included in this group.
+ * @num_pins: number of pins included in this group.
+ * @func: the function number to be programmed when selected.
+ */
+struct samsung_pin_group {
+       const char              *name;
+       const unsigned int      *pins;
+       u8                      num_pins;
+       u8                      func;
+};
+
+/**
+ * struct samsung_pmx_func: represent a pin function.
+ * @name: name of the pin function, used to lookup the function.
+ * @groups: one or more names of pin groups that provide this function.
+ * @num_groups: number of groups included in @groups.
+ */
+struct samsung_pmx_func {
+       const char              *name;
+       const char              **groups;
+       u8                      num_groups;
+       u32                     val;
+};
+
+/* list of all exported SoC specific data */
+extern struct samsung_pin_ctrl exynos3250_pin_ctrl[];
+extern struct samsung_pin_ctrl exynos4210_pin_ctrl[];
+extern struct samsung_pin_ctrl exynos4x12_pin_ctrl[];
+extern struct samsung_pin_ctrl exynos5250_pin_ctrl[];
+extern struct samsung_pin_ctrl exynos5260_pin_ctrl[];
+extern struct samsung_pin_ctrl exynos5420_pin_ctrl[];
+extern struct samsung_pin_ctrl s3c64xx_pin_ctrl[];
+extern struct samsung_pin_ctrl s3c2412_pin_ctrl[];
+extern struct samsung_pin_ctrl s3c2416_pin_ctrl[];
+extern struct samsung_pin_ctrl s3c2440_pin_ctrl[];
+extern struct samsung_pin_ctrl s3c2450_pin_ctrl[];
+extern struct samsung_pin_ctrl s5pv210_pin_ctrl[];
+
+#endif /* __PINCTRL_SAMSUNG_H */