diff mbox

[U-Boot,v3] Exynos5: Pinmux: Add fdt for pinmux

Message ID 1361473546-9609-1-git-send-email-akshay.s@samsung.com
State Superseded
Delegated to: Minkyu Kang
Headers show

Commit Message

Akshay Saraswat Feb. 21, 2013, 7:05 p.m. UTC
This patch adds fdt nodes for peripherals which require
pin muxing and configuration. Device tree bindings for pinctrl
are kept same as required for Linux. Existing pinmux code
modified to retrieve gpio range and function related info from fdt.

Depends-on: [U-Boot] [PATCH 0/4 V3] EXYNOS5: Add GPIO numbering feature
URL: http://lists.denx.de/pipermail/u-boot/2013-February/146151.html

Signed-off-by: Akshay Saraswat <akshay.s@samsung.com>
---
Changes since v2:
        - Rebased as per new version of GPIO numbering patch-set.

 arch/arm/cpu/armv7/exynos/pinmux.c           |  379 +++++++++++----
 arch/arm/dts/exynos5250-pinctrl.dtsi         |  675 ++++++++++++++++++++++++++
 arch/arm/dts/exynos5250.dtsi                 |    1 +
 doc/device-tree-bindings/samsung-pinctrl.txt |  253 ++++++++++
 include/fdtdec.h                             |    1 +
 lib/fdtdec.c                                 |    1 +
 6 files changed, 1204 insertions(+), 106 deletions(-)
 create mode 100644 arch/arm/dts/exynos5250-pinctrl.dtsi
 create mode 100644 doc/device-tree-bindings/samsung-pinctrl.txt

Comments

Simon Glass Feb. 25, 2013, 4:31 a.m. UTC | #1
Hi Akshay,

On Thu, Feb 21, 2013 at 11:05 AM, Akshay Saraswat <akshay.s@samsung.com> wrote:
> This patch adds fdt nodes for peripherals which require
> pin muxing and configuration. Device tree bindings for pinctrl
> are kept same as required for Linux. Existing pinmux code
> modified to retrieve gpio range and function related info from fdt.
>
> Depends-on: [U-Boot] [PATCH 0/4 V3] EXYNOS5: Add GPIO numbering feature
> URL: http://lists.denx.de/pipermail/u-boot/2013-February/146151.html
>
> Signed-off-by: Akshay Saraswat <akshay.s@samsung.com>
> ---
> Changes since v2:
>         - Rebased as per new version of GPIO numbering patch-set.

This looks pretty reasonable to me. Please find some comment below.

As a general comment, it seems to read from the FDT each time anything
is changed. I suppose that is efficient on space, and allows it to
work prior to malloc() being available, but isn't it slow? Perhaps the
data should be cached?

>
>  arch/arm/cpu/armv7/exynos/pinmux.c           |  379 +++++++++++----
>  arch/arm/dts/exynos5250-pinctrl.dtsi         |  675 ++++++++++++++++++++++++++
>  arch/arm/dts/exynos5250.dtsi                 |    1 +
>  doc/device-tree-bindings/samsung-pinctrl.txt |  253 ++++++++++
>  include/fdtdec.h                             |    1 +
>  lib/fdtdec.c                                 |    1 +
>  6 files changed, 1204 insertions(+), 106 deletions(-)
>  create mode 100644 arch/arm/dts/exynos5250-pinctrl.dtsi
>  create mode 100644 doc/device-tree-bindings/samsung-pinctrl.txt
>
> diff --git a/arch/arm/cpu/armv7/exynos/pinmux.c b/arch/arm/cpu/armv7/exynos/pinmux.c
> index a01ce0c..f4dccad 100644
> --- a/arch/arm/cpu/armv7/exynos/pinmux.c
> +++ b/arch/arm/cpu/armv7/exynos/pinmux.c
> @@ -27,6 +27,18 @@
>  #include <asm/arch/pinmux.h>
>  #include <asm/arch/sromc.h>
>
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +/* Struct for storing pin function and gpio related info */
> +struct pin_group {
> +       void *dev_name;

What is this for?

> +       int npins;
> +       int function;
> +       int pull_mode;
> +       int drive_strength;

Should add comments about the S5P_GPIO... defines to use in each case.

> +       enum exynos5_gpio_pin gpio[];

This array has no members?


> +};
> +
>  struct gpio_name_num_table exynos5_gpio_table[] = {
>         { 'a', GPIO_A00 },
>         { 'b', GPIO_B00 },
> @@ -42,87 +54,202 @@ struct gpio_name_num_table exynos5_gpio_table[] = {
>         { 'z', GPIO_Z0 },
>  };
>
> -static void exynos5_uart_config(int peripheral)
> +static void get_pins(const struct fdt_property *fprop, struct pin_group *pingrp)
>  {
> -       int i, start, count;
> +       int i;
> +       char gpio[5];
> +
> +       pingrp->npins = 0;
> +
> +       for (i = 0; !(fprop->data[i] == (int)NULL &&
> +                               fprop->data[i-1] == (int)NULL); i += 7) {

This is a bit obtuse - please add a comment

> +               int pin_num = -1;
> +
> +               gpio[0] = fprop->data[i];
> +               gpio[1] = fprop->data[i + 1];
> +               gpio[2] = fprop->data[i + 2];
> +               gpio[3] = fprop->data[i + 3];
> +               gpio[4] = fprop->data[i + 5];

What is this doing? Please add a comment.

> +
> +               pin_num = name_to_gpio(gpio);
> +
> +               if (pin_num >= 0) {
> +                       pingrp->gpio[pingrp->npins] = pin_num;

This seems to be assigning to something with no members.

> +                       pingrp->npins++;
> +               }
> +       }
> +}
> +
> +static int get_fdt_values(struct pin_group *pingrp)

Please add a function comment.

> +{
> +       int i;
> +       int node, subnode;
> +       const struct fdt_property *fprop;
> +
> +       for (i = 0; i < 4; i++) {

Why 4? I think you should just continue until node returns -ve.

> +               /* Get the node from FDT for pinctrl */
> +               node = fdtdec_next_compatible(gd->fdt_blob, 0,
> +                                               COMPAT_SAMSUNG_PINCTRL);
> +               if (node < 0) {
> +                       printf("PINCTRL: No node for pinctrl in device tree\n");

debug()

Only give this error if you don't find any match

> +                       return -1;
> +               }
> +
> +               subnode = fdt_subnode_offset(gd->fdt_blob,
> +                                               node, pingrp->dev_name);
> +               if (subnode < 0)
> +                       continue;
> +
> +               fprop = fdt_get_property(gd->fdt_blob,
> +                                       subnode, "samsung,pins", NULL);

Suggest you use fdt_getprop() here.

> +               pingrp->function = fdtdec_get_int(gd->fdt_blob,
> +                                       subnode, "samsung,pin-function", -1);
> +               pingrp->pull_mode = fdtdec_get_int(gd->fdt_blob,
> +                                       subnode, "samsung,pin-pud", -1);
> +               pingrp->drive_strength = fdtdec_get_int(gd->fdt_blob,
> +                                       subnode, "samsung,pin-drv", -1);

Error checking on these? Is -1 a valid value?

> +               get_pins(fprop, pingrp);
> +
> +               return 0;
> +       }
> +
> +       debug("PINCTRL: No subnode for %s\n", (char *)pingrp->dev_name);

Can dev_name be const char *?

> +
> +       return -1;
> +}
> +
> +static void pin_config_group_set(struct pin_group *pingrp)
> +{
> +       int i;
> +
> +       for (i = 0; i < pingrp->npins; i++) {
> +               gpio_cfg_pin(pingrp->gpio[i], S5P_GPIO_FUNC(pingrp->function));
> +               gpio_set_pull(pingrp->gpio[i], pingrp->pull_mode);
> +               gpio_set_drv(pingrp->gpio[i], pingrp->drive_strength);
> +       }
> +}
> +
> +static int exynos5_uart_config(int peripheral)
> +{
> +       char *data, *fctl = NULL;
> +       struct pin_group pingrp;
>
>         switch (peripheral) {
>         case PERIPH_ID_UART0:
> -               start = GPIO_A00;
> -               count = 4;
> +               data = "uart0-data";
> +               fctl = "uart0-fctl";
>                 break;
>         case PERIPH_ID_UART1:
> -               start = GPIO_D00;
> -               count = 4;
> +               data = "uart1-data";
> +               fctl = "uart1-fctl";
>                 break;
>         case PERIPH_ID_UART2:
> -               start = GPIO_A10;
> -               count = 4;
> +               data = "uart2-data";
> +               fctl = "uart2-fctl";
>                 break;
>         case PERIPH_ID_UART3:
> -               start = GPIO_A14;
> -               count = 2;
> +               data = "uart3-data";
>                 break;
>         }
> -       for (i = start; i < start + count; i++) {
> -               gpio_set_pull(i, S5P_GPIO_PULL_NONE);
> -               gpio_cfg_pin(i, S5P_GPIO_FUNC(0x2));
> +
> +       pingrp.dev_name = data;
> +
> +       /*
> +        * Retrieve and apply pin config details
> +        * from fdt for this UART's data line.
> +        */
> +       if (get_fdt_values(&pingrp))
> +               return -1;
> +
> +       pin_config_group_set(&pingrp);

Suggest you add a function which does both of thees things - i.e.
get_fdt_values() and pin_config_group_set().

Also probably should have a pinmux_ prefix on the latter, given the
name of this file.

> +
> +       if (peripheral != PERIPH_ID_UART3) {
> +               pingrp.dev_name = fctl;
> +
> +               /*
> +                * Retrieve and apply pin config details
> +                * from fdt for this UART's fctl.
> +                */
> +               if (get_fdt_values(&pingrp))
> +                       return -1;
> +
> +               pin_config_group_set(&pingrp);
>         }
> +
> +       return 0;
>  }
>
>  static int exynos5_mmc_config(int peripheral, int flags)
>  {
> -       int i, start, start_ext, gpio_func = 0;
> +       char *periph_name = NULL;
> +       struct pin_group pingrp;
>
>         switch (peripheral) {
>         case PERIPH_ID_SDMMC0:
> -               start = GPIO_C00;
> -               start_ext = GPIO_C10;
> -               gpio_func = S5P_GPIO_FUNC(0x2);
> +               periph_name = "sd0";
>                 break;
>         case PERIPH_ID_SDMMC1:
> -               start = GPIO_C20;
> -               start_ext = 0;
> +               periph_name = "sd1";
>                 break;
>         case PERIPH_ID_SDMMC2:
> -               start = GPIO_C30;
> -               start_ext = GPIO_C43;
> -               gpio_func = S5P_GPIO_FUNC(0x3);
> +               periph_name = "sd2";
>                 break;
>         case PERIPH_ID_SDMMC3:
> -               start = GPIO_C40;
> -               start_ext = 0;
> +               periph_name = "sd3";
>                 break;
>         }
> -       if ((flags & PINMUX_FLAG_8BIT_MODE) && !start_ext) {
> -               debug("SDMMC device %d does not support 8bit mode",
> -                               peripheral);
> -               return -1;
> -       }
> +
>         if (flags & PINMUX_FLAG_8BIT_MODE) {
> -               for (i = start_ext; i <= (start_ext + 3); i++) {
> -                       gpio_cfg_pin(i, gpio_func);
> -                       gpio_set_pull(i, S5P_GPIO_PULL_UP);
> -                       gpio_set_drv(i, S5P_GPIO_DRV_4X);
> -               }
> -       }
> -       for (i = 0; i < 2; i++) {
> -               gpio_cfg_pin(start + i, S5P_GPIO_FUNC(0x2));
> -               gpio_set_pull(start + i, S5P_GPIO_PULL_NONE);
> -               gpio_set_drv(start + i, S5P_GPIO_DRV_4X);
> -       }
> -       for (i = 3; i <= 6; i++) {
> -               gpio_cfg_pin(start + i, S5P_GPIO_FUNC(0x2));
> -               gpio_set_pull(start + i, S5P_GPIO_PULL_UP);
> -               gpio_set_drv(start + i, S5P_GPIO_DRV_4X);
> +               pingrp.dev_name = strcat(periph_name, "-bus-width8");
> +               /*
> +                * Retrieve and apply pin config details from fdt
> +                * for remaining 4 bits if this sd has 8-bit bus.
> +                */
> +               if (get_fdt_values(&pingrp))
> +                       return -1;
> +
> +               pin_config_group_set(&pingrp);
>         }
>
> +       pingrp.dev_name = strcat(periph_name, "-clk");
> +
> +       /*
> +        * Retrieve and apply pin config details
> +        * from fdt for this sd's clk.
> +        */
> +       if (get_fdt_values(&pingrp))
> +               return -1;
> +
> +       pin_config_group_set(&pingrp);
> +
> +       pingrp.dev_name = strcat(periph_name, "-cmd");
> +
> +       /*
> +        * Retrieve and apply pin config details
> +        * from fdt for this sd's cmd.
> +        */
> +       if (get_fdt_values(&pingrp))
> +               return -1;
> +
> +       pin_config_group_set(&pingrp);
> +
> +       pingrp.dev_name = strcat(periph_name, "-bus-width4");
> +
> +       /*
> +        * Retrieve and apply pin config details
> +        * from fdt for this sd's 4-bit bus.
> +        */
> +       if (get_fdt_values(&pingrp))
> +               return -1;
> +
> +       pin_config_group_set(&pingrp);
> +
>         return 0;
>  }
>
> -static void exynos5_sromc_config(int flags)
> +static int exynos5_sromc_config(int flags)
>  {
> -       int i;
> +       static struct pin_group pingrp;
>
>         /*
>          * SROM:CS1 and EBI
> @@ -139,13 +266,28 @@ static void exynos5_sromc_config(int flags)
>          * GPY1[2]      SROM_WAIT(2)
>          * GPY1[3]      EBI_DATA_RDn(2)
>          */
> -       gpio_cfg_pin(GPIO_Y00 + (flags & PINMUX_FLAG_BANK),
> -                               S5P_GPIO_FUNC(2));
> -       gpio_cfg_pin(GPIO_Y04, S5P_GPIO_FUNC(2));
> -       gpio_cfg_pin(GPIO_Y05, S5P_GPIO_FUNC(2));
> +       pingrp.dev_name = "srom-cs1";

All these names that you are hard-coding...is it not possible to list
them in the device node in the FDT? Perhaps the caller should pass a
node offset?

>
> -       for (i = 0; i < 4; i++)
> -               gpio_cfg_pin(GPIO_Y10 + i, S5P_GPIO_FUNC(2));
> +       /*
> +        * Retrieve and apply pin config details
> +        * from fdt to enable SROM CS1.
> +        */
> +       if (get_fdt_values(&pingrp))
> +               return -1;
> +
> +       pingrp.gpio[0] += (flags & PINMUX_FLAG_BANK);
> +       pin_config_group_set(&pingrp);
> +
> +       pingrp.dev_name = "srom-ebi-enable";
> +
> +       /*
> +        * Retrieve and apply pin config details
> +        * from fdt to enable SROM EBI.
> +        */
> +       if (get_fdt_values(&pingrp))
> +               return -1;
> +
> +       pin_config_group_set(&pingrp);
>
>         /*
>          * EBI: 8 Addrss Lines
> @@ -179,97 +321,124 @@ static void exynos5_sromc_config(int flags)
>          * GPY6[6]      EBI_DATA[14](2)
>          * GPY6[7]      EBI_DATA[15](2)
>          */
> -       for (i = 0; i < 8; i++) {
> -               gpio_cfg_pin(GPIO_Y30 + i, S5P_GPIO_FUNC(2));
> -               gpio_set_pull(GPIO_Y30 + i, S5P_GPIO_PULL_UP);
> +       pingrp.dev_name = "srom-ebi-addr-lines";
> +
> +       /*
> +        * Retrieve and apply pin config details
> +        * from fdt for EBI address lines.
> +        */
> +       if (get_fdt_values(&pingrp))
> +               return -1;
>
> -               gpio_cfg_pin(GPIO_Y50 + i, S5P_GPIO_FUNC(2));
> -               gpio_set_pull(GPIO_Y50 + i, S5P_GPIO_PULL_UP);
> +       pin_config_group_set(&pingrp);
>
> -               gpio_cfg_pin(GPIO_Y60 + i, S5P_GPIO_FUNC(2));
> -               gpio_set_pull(GPIO_Y60 + i, S5P_GPIO_PULL_UP);
> -       }
> +       pingrp.dev_name = "srom-ebi-data-lines";
> +
> +       /*
> +        * Retrieve and apply pin config details
> +        * from fdt for EBI data lines.
> +        */
> +       if (get_fdt_values(&pingrp))
> +               return -1;
> +
> +       pin_config_group_set(&pingrp);
> +
> +       return 0;
>  }
>
> -static void exynos5_i2c_config(int peripheral, int flags)
> +static int exynos5_i2c_config(int peripheral, int flags)
>  {
> +       struct pin_group pingrp;
>
>         switch (peripheral) {
>         case PERIPH_ID_I2C0:
> -               gpio_cfg_pin(GPIO_B30, S5P_GPIO_FUNC(0x2));
> -               gpio_cfg_pin(GPIO_B31, S5P_GPIO_FUNC(0x2));
> +               pingrp.dev_name = "i2c0-bus";
>                 break;
>         case PERIPH_ID_I2C1:
> -               gpio_cfg_pin(GPIO_B32, S5P_GPIO_FUNC(0x2));
> -               gpio_cfg_pin(GPIO_B33, S5P_GPIO_FUNC(0x2));
> +               pingrp.dev_name = "i2c1-bus";
>                 break;
>         case PERIPH_ID_I2C2:
> -               gpio_cfg_pin(GPIO_A06, S5P_GPIO_FUNC(0x3));
> -               gpio_cfg_pin(GPIO_A07, S5P_GPIO_FUNC(0x3));
> +               pingrp.dev_name = "i2c2-bus";
>                 break;
>         case PERIPH_ID_I2C3:
> -               gpio_cfg_pin(GPIO_A12, S5P_GPIO_FUNC(0x3));
> -               gpio_cfg_pin(GPIO_A13, S5P_GPIO_FUNC(0x3));
> +               pingrp.dev_name = "i2c3-bus";
>                 break;
>         case PERIPH_ID_I2C4:
> -               gpio_cfg_pin(GPIO_A20, S5P_GPIO_FUNC(0x3));
> -               gpio_cfg_pin(GPIO_A21, S5P_GPIO_FUNC(0x3));
> +               pingrp.dev_name = "i2c4-bus";
>                 break;
>         case PERIPH_ID_I2C5:
> -               gpio_cfg_pin(GPIO_A22, S5P_GPIO_FUNC(0x3));
> -               gpio_cfg_pin(GPIO_A23, S5P_GPIO_FUNC(0x3));
> +               pingrp.dev_name = "i2c5-bus";
>                 break;
>         case PERIPH_ID_I2C6:
> -               gpio_cfg_pin(GPIO_B13, S5P_GPIO_FUNC(0x4));
> -               gpio_cfg_pin(GPIO_B14, S5P_GPIO_FUNC(0x4));
> +               pingrp.dev_name = "i2c6-bus";
>                 break;
>         case PERIPH_ID_I2C7:
> -               gpio_cfg_pin(GPIO_B22, S5P_GPIO_FUNC(0x3));
> -               gpio_cfg_pin(GPIO_B23, S5P_GPIO_FUNC(0x3));
> +               pingrp.dev_name = "i2c7-bus";
>                 break;
>         }
> +
> +       /*
> +        * Retrieve and apply pin config details
> +        * from fdt for this i2c bus.
> +        */
> +       if (get_fdt_values(&pingrp))
> +               return -1;
> +
> +       pin_config_group_set(&pingrp);
> +
> +       return 0;
>  }
>
> -static void exynos5_i2s_config(int peripheral)
> +static int exynos5_i2s_config(int peripheral)
>  {
> -       int i;
> +       struct pin_group pingrp;
> +
> +       pingrp.dev_name = "i2s";
> +
> +       /*
> +        * Retrieve and apply pin config details
> +        * from fdt for i2s.
> +        */
> +       if (get_fdt_values(&pingrp))
> +               return -1;
> +
> +       pin_config_group_set(&pingrp);
>
> -       for (i = 0; i < 5; i++)
> -               gpio_cfg_pin(GPIO_B00+i, S5P_GPIO_FUNC(0x02));
> +       return 0;
>  }
>
> -void exynos5_spi_config(int peripheral)
> +int exynos5_spi_config(int peripheral)
>  {
> -       int cfg = 0, pin = 0, i;
> +       static struct pin_group pingrp;
>
>         switch (peripheral) {
>         case PERIPH_ID_SPI0:
> -               cfg = S5P_GPIO_FUNC(0x2);
> -               pin = GPIO_A20;
> +               pingrp.dev_name = "spi0-bus";
>                 break;
>         case PERIPH_ID_SPI1:
> -               cfg = S5P_GPIO_FUNC(0x2);
> -               pin = GPIO_A24;
> +               pingrp.dev_name = "spi1-bus";
>                 break;
>         case PERIPH_ID_SPI2:
> -               cfg = S5P_GPIO_FUNC(0x5);
> -               pin = GPIO_B11;
> +               pingrp.dev_name = "spi2-bus";
>                 break;
>         case PERIPH_ID_SPI3:
> -               cfg = S5P_GPIO_FUNC(0x2);
> -               pin = GPIO_F10;
> +               pingrp.dev_name = "spi3-bus";
>                 break;
>         case PERIPH_ID_SPI4:
> -               for (i = 0; i < 2; i++) {
> -                       gpio_cfg_pin(GPIO_F02 + i, S5P_GPIO_FUNC(0x4));
> -                       gpio_cfg_pin(GPIO_E04 + i, S5P_GPIO_FUNC(0x4));
> -               }
> +               pingrp.dev_name = "spi4-bus";
>                 break;
>         }
> -       if (peripheral != PERIPH_ID_SPI4) {
> -               for (i = pin; i < pin + 4; i++)
> -                       gpio_cfg_pin(i, cfg);
> -       }
> +
> +       /*
> +        * Retrieve and apply pin config details
> +        * from fdt for this spi.
> +        */
> +       if (get_fdt_values(&pingrp))
> +               return -1;
> +
> +       pin_config_group_set(&pingrp);
> +
> +       return 0;
>  }
>
>  static int exynos5_pinmux_config(int peripheral, int flags)
> @@ -279,7 +448,7 @@ static int exynos5_pinmux_config(int peripheral, int flags)
>         case PERIPH_ID_UART1:
>         case PERIPH_ID_UART2:
>         case PERIPH_ID_UART3:
> -               exynos5_uart_config(peripheral);
> +               return exynos5_uart_config(peripheral);
>                 break;
>         case PERIPH_ID_SDMMC0:
>         case PERIPH_ID_SDMMC1:
> @@ -287,7 +456,7 @@ static int exynos5_pinmux_config(int peripheral, int flags)
>         case PERIPH_ID_SDMMC3:
>                 return exynos5_mmc_config(peripheral, flags);
>         case PERIPH_ID_SROMC:
> -               exynos5_sromc_config(flags);
> +               return exynos5_sromc_config(flags);
>                 break;
>         case PERIPH_ID_I2C0:
>         case PERIPH_ID_I2C1:
> @@ -297,24 +466,22 @@ static int exynos5_pinmux_config(int peripheral, int flags)
>         case PERIPH_ID_I2C5:
>         case PERIPH_ID_I2C6:
>         case PERIPH_ID_I2C7:
> -               exynos5_i2c_config(peripheral, flags);
> +               return exynos5_i2c_config(peripheral, flags);
>                 break;
>         case PERIPH_ID_I2S1:
> -               exynos5_i2s_config(peripheral);
> +               return exynos5_i2s_config(peripheral);
>                 break;
>         case PERIPH_ID_SPI0:
>         case PERIPH_ID_SPI1:
>         case PERIPH_ID_SPI2:
>         case PERIPH_ID_SPI3:
>         case PERIPH_ID_SPI4:
> -               exynos5_spi_config(peripheral);
> +               return exynos5_spi_config(peripheral);
>                 break;
>         default:
>                 debug("%s: invalid peripheral %d", __func__, peripheral);
>                 return -1;
>         }
> -
> -       return 0;
>  }
>
>  static void exynos4_i2c_config(int peripheral, int flags)
> diff --git a/arch/arm/dts/exynos5250-pinctrl.dtsi b/arch/arm/dts/exynos5250-pinctrl.dtsi
> new file mode 100644
> index 0000000..efbe1be
> --- /dev/null
> +++ b/arch/arm/dts/exynos5250-pinctrl.dtsi
> @@ -0,0 +1,675 @@
> +/*
> + * Samsung's Exynos5250 SoC pin-mux and pin-config device tree source
> + *
> + * Copyright (c) 2013 Samsung Electronics Co., Ltd.
> + *             http://www.samsung.com
> + *
> + * Samsung's Exynos5250 SoC pin-mux and pin-config options are listed as device
> + * tree nodes in this file.
> + *
> + * Note: This file does not include pin-ctrl subnodes for all the controllers in
> + * Exynos5250 SoC. It can be updated as per need in future.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> +*/
> +
> +/ {
> +       pinctrl_0: pinctrl@11400000 {
> +               compatible = "samsung,pinctrl";
> +               reg = <0x11400000 0x1000>;
> +               interrupts = <0 46 0>;
> +
> +               gpa0: gpa0 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +
> +                       interrupt-controller;
> +                       #interrupt-cells = <2>;
> +               };
> +
> +               gpa1: gpa1 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +
> +                       interrupt-controller;
> +                       #interrupt-cells = <2>;
> +               };
> +
> +               gpa2: gpa2 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +
> +                       interrupt-controller;
> +                       #interrupt-cells = <2>;
> +               };
> +
> +               gpb0: gpb0 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +
> +                       interrupt-controller;
> +                       #interrupt-cells = <2>;
> +               };
> +
> +               gpb1: gpb1 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +
> +                       interrupt-controller;
> +                       #interrupt-cells = <2>;
> +               };
> +
> +               gpb2: gpb2 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +
> +                       interrupt-controller;
> +                       #interrupt-cells = <2>;
> +               };
> +
> +               gpb3: gpb3 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +
> +                       interrupt-controller;
> +                       #interrupt-cells = <2>;
> +               };
> +
> +               gpc0: gpc0 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +
> +                       interrupt-controller;
> +                       #interrupt-cells = <2>;
> +               };
> +
> +               gpc1: gpc1 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +
> +                       interrupt-controller;
> +                       #interrupt-cells = <2>;
> +               };
> +
> +               gpc2: gpc2 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +
> +                       interrupt-controller;
> +                       #interrupt-cells = <2>;
> +               };
> +
> +               gpc3: gpc3 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +
> +                       interrupt-controller;
> +                       #interrupt-cells = <2>;
> +               };
> +
> +               gpd0: gpd0 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +
> +                       interrupt-controller;
> +                       #interrupt-cells = <2>;
> +               };
> +
> +               gpd1: gpd1 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +
> +                       interrupt-controller;
> +                       #interrupt-cells = <2>;
> +               };
> +
> +               gpy0: gpy0 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +               };
> +
> +               gpy1: gpy1 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +               };
> +
> +               gpy2: gpy2 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +               };
> +
> +               gpy3: gpy3 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +               };
> +
> +               gpy4: gpy4 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +               };
> +
> +               gpy5: gpy5 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +               };
> +
> +               gpy6: gpy6 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +               };
> +
> +               gpc4: gpc4 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +
> +                       interrupt-controller;
> +                       #interrupt-cells = <2>;
> +               };
> +
> +               gpx0: gpx0 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +
> +                       interrupt-controller;
> +                       #interrupt-cells = <2>;
> +               };
> +
> +               gpx1: gpx1 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +
> +                       interrupt-controller;
> +                       #interrupt-cells = <2>;
> +               };
> +
> +               gpx2: gpx2 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +
> +                       interrupt-controller;
> +                       #interrupt-cells = <2>;
> +               };
> +
> +               gpx3: gpx3 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +
> +                       interrupt-controller;
> +                       #interrupt-cells = <2>;
> +               };
> +
> +               uart0_data: uart0-data {
> +                       samsung,pins = "gpa0-0", "gpa0-1";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <0>;
> +                       samsung,pin-drv = <0>;
> +               };
> +
> +               uart0_fctl: uart0-fctl {
> +                       samsung,pins = "gpa0-2", "gpa0-3";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <0>;
> +                       samaung,pin-drv = <0>;
> +               };
> +
> +               uart1_data: uart1-data {
> +                       samsung,pins = "gpd0-0", "gpd0-1";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <0>;
> +                       samsung,pin-drv = <0>;
> +               };
> +
> +               uart1_fctl: uart1-fctl {
> +                       samsung,pins = "gpd0-2", "gpd0-3";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <0>;
> +                       samaung,pin-drv = <0>;
> +               };
> +
> +               uart2_data: uart2-data {
> +                       samsung,pins = "gpa1-0", "gpa1-1";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <0>;
> +                       samsung,pin-drv = <0>;
> +               };
> +
> +               uart2_fctl: uart2-fctl {
> +                       samsung,pins = "gpa1-2", "gpa1-3";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <0>;
> +                       samaung,pin-drv = <0>;
> +               };
> +
> +               uart3_data: uart3-data {
> +                       samsung,pins = "gpa1-4", "gpa1-5";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <0>;
> +                       samsung,pin-drv = <0>;
> +               };
> +
> +               sd0_clk: sd0-clk {
> +                       samsung,pins = "gpc0-0";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <0>;
> +                       samsung,pin-drv = <3>;
> +               };
> +
> +               sd0_cmd: sd0-cmd {
> +                       samsung,pins = "gpc0-1";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <0>;
> +                       samsung,pin-drv = <3>;
> +               };
> +
> +               sd0_cd: sd0-cd {
> +                       samsung,pins = "gpc0-2";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <3>;
> +                       samsung,pin-drv = <3>;
> +               };
> +
> +               sd0_bus1: sd0-bus-width1 {
> +                       samsung,pins = "gpc0-3";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <3>;
> +                       samsung,pin-drv = <3>;
> +               };
> +
> +               sd0_bus4: sd0-bus-width4 {
> +                       samsung,pins = "gpc0-3", "gpc0-4", "gpc0-5", "gpc0-6";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <3>;
> +                       samsung,pin-drv = <3>;
> +               };
> +
> +               sd0_bus8: sd0-bus-width8 {
> +                       samsung,pins = "gpc1-0", "gpc1-1", "gpc1-2", "gpc1-3";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <3>;
> +                       samsung,pin-drv = <3>;
> +               };
> +
> +               sd1_clk: sd1-clk {
> +                       samsung,pins = "gpc2-0";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <0>;
> +                       samsung,pin-drv = <3>;
> +               };
> +
> +               sd1_cmd: sd1-cmd {
> +                       samsung,pins = "gpc2-1";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <0>;
> +                       samsung,pin-drv = <3>;
> +               };
> +
> +               sd1_cd: sd1-cd {
> +                       samsung,pins = "gpc2-2";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <3>;
> +                       samsung,pin-drv = <3>;
> +               };
> +
> +               sd1_bus1: sd1-bus-width1 {
> +                       samsung,pins = "gpc2-3";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <3>;
> +                       samsung,pin-drv = <3>;
> +               };
> +
> +               sd1_bus4: sd1-bus-width4 {
> +                       samsung,pins = "gpc2-3", "gpc2-4", "gpc2-5", "gpc2-6";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <3>;
> +                       samsung,pin-drv = <3>;
> +               };
> +
> +               sd2_clk: sd2-clk {
> +                       samsung,pins = "gpc3-0";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <0>;
> +                       samsung,pin-drv = <3>;
> +               };
> +
> +               sd2_cmd: sd2-cmd {
> +                       samsung,pins = "gpc3-1";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <0>;
> +                       samsung,pin-drv = <3>;
> +               };
> +
> +               sd2_cd: sd2-cd {
> +                       samsung,pins = "gpc3-2";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <3>;
> +                       samsung,pin-drv = <3>;
> +               };
> +
> +               sd2_bus1: sd2-bus-width1 {
> +                       samsung,pins = "gpc3-3";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <3>;
> +                       samsung,pin-drv = <3>;
> +               };
> +
> +               sd2_bus4: sd2-bus-width4 {
> +                       samsung,pins = "gpc3-3", "gpc3-4", "gpc3-5", "gpc3-6";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <3>;
> +                       samsung,pin-drv = <3>;
> +               };
> +
> +               sd2_bus8: sd2-bus-width8 {
> +                       samsung,pins = "gpc4-3", "gpc4-4", "gpc4-5", "gpc4-6";
> +                       samsung,pin-function = <3>;
> +                       samsung,pin-pud = <3>;
> +                       samsung,pin-drv = <3>;
> +               };
> +
> +               sd3_clk: sd3-clk {
> +                       samsung,pins = "gpc4-0";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <0>;
> +                       samsung,pin-drv = <3>;
> +               };
> +
> +               sd3_cmd: sd3-cmd {
> +                       samsung,pins = "gpc4-1";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <0>;
> +                       samsung,pin-drv = <3>;
> +               };
> +
> +               sd3_cd: sd3-cd {
> +                       samsung,pins = "gpc4-2";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <3>;
> +                       samsung,pin-drv = <3>;
> +               };
> +
> +               sd3_bus1: sd3-bus-width1 {
> +                       samsung,pins = "gpc4-3";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <3>;
> +                       samsung,pin-drv = <3>;
> +               };
> +
> +               sd3_bus4: sd3-bus-width4 {
> +                       samsung,pins = "gpc4-3", "gpc4-4", "gpc4-5", "gpc4-6";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <3>;
> +                       samsung,pin-drv = <3>;
> +               };
> +
> +               srom_cs1: srom-cs1 {
> +                       samsung,pins = "gpy0-0", "gpy0-4", "gpy0-5";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <0>;
> +                       samsung,pin-drv = <0>;
> +               };
> +
> +               srom_ebi: srom-ebi-enable {
> +                       samsung,pins = "gpy1-0", "gpy1-1", "gpy1-2", "gpy1-3";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <0>;
> +                       samsung,pin-drv = <0>;
> +               };
> +
> +               srom_ebi_a: srom-ebi-addr-lines {
> +                       samsung,pins = "gpy3-0", "gpy3-1", "gpy3-2", "gpy3-3",
> +                                       "gpy3-4", "gpy3-5", "gpy3-6", "gpy3-7";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <3>;
> +                       samsung,pin-drv = <0>;
> +               };
> +
> +               srom_ebi_d: srom-ebi-data-lines {
> +                       samsung,pins = "gpy5-0", "gpy5-1", "gpy5-2", "gpy5-3",
> +                                       "gpy5-4", "gpy5-5", "gpy5-6", "gpy5-7",
> +                                       "gpy6-0", "gpy6-1", "gpy6-2", "gpy6-3",
> +                                       "gpy6-4", "gpy6-5", "gpy6-6", "gpy6-7";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <3>;
> +                       samsung,pin-drv = <0>;
> +               };
> +
> +               i2s: i2s {
> +                       samsung,pins = "gpb0-0", "gpb0-1", "gpb0-2", "gpb0-3",
> +                                       "gpb0-4";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <0>;
> +                       samsung,pin-drv = <0>;
> +               };
> +
> +               spi0_bus: spi0-bus {
> +                       samsung,pins = "gpa2-0", "gpa2-1", "gpa2-2", "gpa2-3";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <3>;
> +                       samsung,pin-drv = <0>;
> +               };
> +
> +               spi1_bus: spi1-bus {
> +                       samsung,pins = "gpa2-4", "gpa2-5", "gpa2-6", "gpa2-7";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <3>;
> +                       samsung,pin-drv = <0>;
> +               };
> +
> +               spi2_bus: spi2-bus {
> +                       samsung,pins = "gpb1-1", "gpb1-2", "gpb1-3", "gpb1-4";
> +                       samsung,pin-function = <5>;
> +                       samsung,pin-pud = <3>;
> +                       samsung,pin-drv = <0>;
> +               };
> +
> +               i2c0_bus: i2c0-bus {
> +                       samsung,pins = "gpb3-0", "gpb3-1";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <3>;
> +                       samsung,pin-drv = <0>;
> +               };
> +
> +               i2c1_bus: i2c1-bus {
> +                       samsung,pins = "gpb3-2", "gpb3-3";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <3>;
> +                       samsung,pin-drv = <0>;
> +               };
> +
> +               i2c2_bus: i2c2-bus {
> +                       samsung,pins = "gpa0-6", "gpa0-7";
> +                       samsung,pin-function = <3>;
> +                       samsung,pin-pud = <3>;
> +                       samaung,pin-drv = <0>;
> +               };
> +
> +               i2c3_bus: i2c3-bus {
> +                       samsung,pins = "gpa1-2", "gpa1-3";
> +                       samsung,pin-function = <3>;
> +                       samsung,pin-pud = <3>;
> +                       samaung,pin-drv = <0>;
> +               };
> +
> +               i2c4_bus: i2c4-bus {
> +                       samsung,pins = "gpa2-0", "gpa2-1";
> +                       samsung,pin-function = <3>;
> +                       samsung,pin-pud = <3>;
> +                       samaung,pin-drv = <0>;
> +               };
> +
> +               i2c5_bus: i2c5-bus {
> +                       samsung,pins = "gpa2-2", "gpa2-3";
> +                       samsung,pin-function = <3>;
> +                       samsung,pin-pud = <3>;
> +                       samaung,pin-drv = <0>;
> +               };
> +
> +               i2c6_bus: i2c6-bus {
> +                       samsung,pins = "gpb1-3", "gpb1-4";
> +                       samsung,pin-function = <4>;
> +                       samsung,pin-pud = <3>;
> +                       samsung,pin-drv = <0>;
> +               };
> +
> +               i2c7_bus: i2c7-bus {
> +                       samsung,pins = "gpb2-2", "gpb2-3";
> +                       samsung,pin-function = <3>;
> +                       samsung,pin-pud = <3>;
> +                       samsung,pin-drv = <0>;
> +               };
> +       };
> +
> +       pinctrl_1: pinctrl@13400000 {
> +               compatible = "samsung,pinctrl";
> +               reg = <0x13400000 0x1000>;
> +               interrupts = <0 45 0>;
> +
> +               gpe0: gpe0 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +
> +                       interrupt-controller;
> +                       #interrupt-cells = <2>;
> +               };
> +
> +               gpe1: gpe1 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +
> +                       interrupt-controller;
> +                       #interrupt-cells = <2>;
> +               };
> +
> +               gpf0: gpf0 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +
> +                       interrupt-controller;
> +                       #interrupt-cells = <2>;
> +               };
> +
> +               gpf1: gpf1 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +
> +                       interrupt-controller;
> +                       #interrupt-cells = <2>;
> +               };
> +
> +               gpg0: gpg0 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +
> +                       interrupt-controller;
> +                       #interrupt-cells = <2>;
> +               };
> +
> +               gpg1: gpg1 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +
> +                       interrupt-controller;
> +                       #interrupt-cells = <2>;
> +               };
> +
> +               gpg2: gpg2 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +
> +                       interrupt-controller;
> +                       #interrupt-cells = <2>;
> +               };
> +
> +               gph0: gph0 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +
> +                       interrupt-controller;
> +                       #interrupt-cells = <2>;
> +               };
> +
> +               gph1: gph1 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +
> +                       interrupt-controller;
> +                       #interrupt-cells = <2>;
> +               };
> +
> +               spi3_bus: spi3-bus {
> +                       samsung,pins = "gpf1-0", "gpf1-1", "gpf1-2", "gpf1-3";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <3>;
> +                       samsung,pin-drv = <0>;
> +               };
> +
> +               spi4_bus: spi4-bus {
> +                       samsung,pins = "gpf0-2", "gpf0-3", "gpe0-4", "gpe0-5";
> +                       samsung,pin-function = <4>;
> +                       samsung,pin-pud = <3>;
> +                       samsung,pin-drv = <0>;
> +               };
> +       };
> +
> +       pinctrl_2: pinctrl@10d10000 {
> +               compatible = "samsung,pinctrl-exynos5250";
> +               reg = <0x10d10000 0x1000>;
> +               interrupts = <0 45 0>;
> +
> +               gpv0: gpv0 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +
> +                       interrupt-controller;
> +                       #interrupt-cells = <2>;
> +               };
> +
> +               gpv1: gpv1 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +
> +                       interrupt-controller;
> +                       #interrupt-cells = <2>;
> +               };
> +
> +               gpv2: gpv2 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +
> +                       interrupt-controller;
> +                       #interrupt-cells = <2>;
> +               };
> +
> +               gpv3: gpv3 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +
> +                       interrupt-controller;
> +                       #interrupt-cells = <2>;
> +               };
> +
> +               gpv4: gpv4 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +
> +                       interrupt-controller;
> +                       #interrupt-cells = <2>;
> +               };
> +       };
> +
> +       pinctrl_3: pinctrl@03680000 {
> +               compatible = "samsung,pinctrl-exynos5250";
> +               reg = <0x03680000 0x1000>;
> +               interrupts = <0 45 0>;
> +
> +               gpz: gpz {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +
> +                       interrupt-controller;
> +                       #interrupt-cells = <2>;
> +               };
> +       };
> +};
> diff --git a/arch/arm/dts/exynos5250.dtsi b/arch/arm/dts/exynos5250.dtsi
> index ed8c8dd..8fcf432 100644
> --- a/arch/arm/dts/exynos5250.dtsi
> +++ b/arch/arm/dts/exynos5250.dtsi
> @@ -18,6 +18,7 @@
>  */
>
>  /include/ "skeleton.dtsi"
> +/include/ "exynos5250-pinctrl.dtsi"
>
>  / {
>         compatible = "samsung,exynos5250";
> diff --git a/doc/device-tree-bindings/samsung-pinctrl.txt b/doc/device-tree-bindings/samsung-pinctrl.txt
> new file mode 100644
> index 0000000..708ca45
> --- /dev/null
> +++ b/doc/device-tree-bindings/samsung-pinctrl.txt
> @@ -0,0 +1,253 @@
> +Samsung GPIO and Pin Mux/Config controller
> +
> +Samsung's ARM based SoC's integrates a GPIO and Pin mux/config hardware
> +controller. It controls the input/output settings on the available pads/pins
> +and also provides ability to multiplex and configure the output of various
> +on-chip controllers onto these pads.
> +
> +Required Properties:
> +- compatible: should be one of the following.
> +  - "samsung,pinctrl": for Exynos compatible pin-controller.
> +
> +- reg: Base address of the pin controller hardware module and length of
> +  the address space it occupies.
> +
> +- Pin banks as child nodes: Pin banks of the controller are represented by child
> +  nodes of the controller node. Bank name is taken from name of the node. Each
> +  bank node must contain following properties:
> +
> +  - gpio-controller: identifies the node as a gpio controller and pin bank.
> +  - #gpio-cells: number of cells in GPIO specifier. Since the generic GPIO
> +    binding is used, the amount of cells must be specified as 2. See generic
> +    GPIO binding documentation for description of particular cells.
> +
> +- Pin mux/config groups as child nodes: The pin mux (selecting pin function
> +  mode) and pin config (pull up/down, driver strength) settings are represented
> +  as child nodes of the pin-controller node. There should be atleast one
> +  child node and there is no limit on the count of these child nodes.
> +
> +  The child node should contain a list of pin(s) on which a particular pin
> +  function selection or pin configuration (or both) have to applied. This
> +  list of pins is specified using the property name "samsung,pins". There
> +  should be atleast one pin specfied for this property and there is no upper
> +  limit on the count of pins that can be specified. The pins are specified
> +  using pin names which are derived from the hardware manual of the SoC. As
> +  an example, the pins in GPA0 bank of the pin controller can be represented
> +  as "gpa0-0", "gpa0-1", "gpa0-2" and so on. The names should be in lower case.
> +  The format of the pin names should be (as per the hardware manual)
> +  "[pin bank name]-[pin number within the bank]".
> +
> +  The pin function selection that should be applied on the pins listed in the
> +  child node is specified using the "samsung,pin-function" property. The value
> +  of this property that should be applied to each of the pins listed in the
> +  "samsung,pins" property should be picked from the hardware manual of the SoC
> +  for the specified pin group. This property is optional in the child node if
> +  no specific function selection is desired for the pins listed in the child
> +  node. The value of this property is used as-is to program the pin-controller
> +  function selector register of the pin-bank.
> +
> +  The child node can also optionally specify one or more of the pin
> +  configuration that should be applied on all the pins listed in the
> +  "samsung,pins" property of the child node. The following pin configuration
> +  properties are supported.
> +
> +  - samsung,pin-pud: Pull up/down configuration.
> +  - samsung,pin-drv: Drive strength configuration.
> +  - samsung,pin-pud-pdn: Pull up/down configuration in power down mode.
> +  - samsung,pin-drv-pdn: Drive strength configuration in power down mode.
> +
> +  The values specified by these config properties should be derived from the
> +  hardware manual and these values are programmed as-is into the pin
> +  pull up/down and driver strength register of the pin-controller.
> +
> +  Note: A child should include atleast a pin function selection property or
> +  pin configuration property (one or more) or both.
> +
> +  The client nodes that require a particular pin function selection and/or
> +  pin configuration should use the bindings listed in the "pinctrl-bindings.txt"
> +  file.
> +
> +External GPIO and Wakeup Interrupts:
> +
> +The controller supports two types of external interrupts over gpio. The first
> +is the external gpio interrupt and second is the external wakeup interrupts.
> +The difference between the two is that the external wakeup interrupts can be
> +used as system wakeup events.
> +
> +A. External GPIO Interrupts: For supporting external gpio interrupts, the
> +   following properties should be specified in the pin-controller device node.
> +
> +   - interrupt-parent: phandle of the interrupt parent to which the external
> +     GPIO interrupts are forwarded to.
> +   - interrupts: interrupt specifier for the controller. The format and value of
> +     the interrupt specifier depends on the interrupt parent for the controller.
> +
> +   In addition, following properties must be present in node of every bank
> +   of pins supporting GPIO interrupts:
> +
> +   - interrupt-controller: identifies the controller node as interrupt-parent.
> +   - #interrupt-cells: the value of this property should be 2.
> +     - First Cell: represents the external gpio interrupt number local to the
> +       external gpio interrupt space of the controller.
> +     - Second Cell: flags to identify the type of the interrupt
> +       - 1 = rising edge triggered
> +       - 2 = falling edge triggered
> +       - 3 = rising and falling edge triggered
> +       - 4 = high level triggered
> +       - 8 = low level triggered
> +
> +B. External Wakeup Interrupts: For supporting external wakeup interrupts, a
> +   child node representing the external wakeup interrupt controller should be
> +   included in the pin-controller device node. This child node should include
> +   the following properties.
> +
> +   - compatible: identifies the type of the external wakeup interrupt controller
> +     The possible values are:
> +     - samsung,wakeup-eint: represents wakeup interrupt controller
> +       found on Samsung Exynos SoC.
> +   - interrupt-parent: phandle of the interrupt parent to which the external
> +     wakeup interrupts are forwarded to.
> +   - interrupts: interrupt used by multiplexed wakeup interrupts.
> +
> +   In addition, following properties must be present in node of every bank
> +   of pins supporting wake-up interrupts:
> +
> +   - interrupt-controller: identifies the node as interrupt-parent.
> +   - #interrupt-cells: the value of this property should be 2
> +     - First Cell: represents the external wakeup interrupt number local to
> +       the external wakeup interrupt space of the controller.
> +     - Second Cell: flags to identify the type of the interrupt
> +       - 1 = rising edge triggered
> +       - 2 = falling edge triggered
> +       - 3 = rising and falling edge triggered
> +       - 4 = high level triggered
> +       - 8 = low level triggered
> +
> +   Node of every bank of pins supporting direct wake-up interrupts (without
> +   multiplexing) must contain following properties:
> +
> +   - interrupt-parent: phandle of the interrupt parent to which the external
> +     wakeup interrupts are forwarded to.
> +   - interrupts: interrupts of the interrupt parent which are used for external
> +     wakeup interrupts from pins of the bank, must contain interrupts for all
> +     pins of the bank.
> +
> +Aliases:
> +
> +All the pin controller nodes should be represented in the aliases node using
> +the following format 'pinctrl{n}' where n is a unique number for the alias.
> +
> +Example: A pin-controller node with pin banks:
> +
> +       pinctrl_0: pinctrl@11400000 {
> +               compatible = "samsung,pinctrl;
> +               reg = <0x11400000 0x1000>;
> +               interrupts = <0 47 0>;
> +
> +               /* ... */
> +
> +               /* Pin bank without external interrupts */
> +               gpy0: gpy0 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +               };
> +
> +               /* ... */
> +
> +               /* Pin bank with external GPIO or muxed wake-up interrupts */
> +               gpj0: gpj0 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +
> +                       interrupt-controller;
> +                       #interrupt-cells = <2>;
> +               };
> +
> +               /* ... */
> +
> +               /* Pin bank with external direct wake-up interrupts */
> +               gpx0: gpx0 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +
> +                       interrupt-controller;
> +                       interrupt-parent = <&gic>;
> +                       interrupts = <0 16 0>, <0 17 0>, <0 18 0>, <0 19 0>,
> +                                    <0 20 0>, <0 21 0>, <0 22 0>, <0 23 0>;
> +                       #interrupt-cells = <2>;
> +               };
> +
> +               /* ... */
> +       };
> +
> +Example 1: A pin-controller node with pin groups.
> +
> +       pinctrl_0: pinctrl@11400000 {
> +               compatible = "samsung,pinctrl";
> +               reg = <0x11400000 0x1000>;
> +               interrupts = <0 47 0>;
> +
> +               /* ... */
> +
> +               uart0_data: uart0-data {
> +                       samsung,pins = "gpa0-0", "gpa0-1";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <0>;
> +                       samsung,pin-drv = <0>;
> +               };
> +
> +               uart0_fctl: uart0-fctl {
> +                       samsung,pins = "gpa0-2", "gpa0-3";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <0>;
> +                       samsung,pin-drv = <0>;
> +               };
> +
> +               uart1_data: uart1-data {
> +                       samsung,pins = "gpa0-4", "gpa0-5";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <0>;
> +                       samsung,pin-drv = <0>;
> +               };
> +
> +               uart1_fctl: uart1-fctl {
> +                       samsung,pins = "gpa0-6", "gpa0-7";
> +                       samsung,pin-function = <2>;
> +                       samsung,pin-pud = <0>;
> +                       samsung,pin-drv = <0>;
> +               };
> +
> +               i2c2_bus: i2c2-bus {
> +                       samsung,pins = "gpa0-6", "gpa0-7";
> +                       samsung,pin-function = <3>;
> +                       samsung,pin-pud = <3>;
> +                       samsung,pin-drv = <0>;
> +               };
> +       };
> +
> +Example 2: A pin-controller node with external wakeup interrupt controller node.
> +
> +       pinctrl_1: pinctrl@11000000 {
> +               compatible = "samsung,pinctrl";
> +               reg = <0x11000000 0x1000>;
> +               interrupts = <0 46 0>
> +
> +               /* ... */
> +
> +               wakeup-interrupt-controller {
> +                       compatible = "samsung,wakeup-eint";
> +                       interrupt-parent = <&gic>;
> +                       interrupts = <0 32 0>;
> +               };
> +       };
> +
> +Example 3: A uart client node that supports 'default' and 'flow-control' states.
> +
> +       uart@13800000 {
> +               compatible = "samsung,uart";
> +               reg = <0x13800000 0x100>;
> +               interrupts = <0 52 0>;
> +               pinctrl-names = "default", "flow-control;
> +               pinctrl-0 = <&uart0_data>;
> +               pinctrl-1 = <&uart0_data &uart0_fctl>;
> +       };
> diff --git a/include/fdtdec.h b/include/fdtdec.h
> index 77f244f..9c1bd82 100644
> --- a/include/fdtdec.h
> +++ b/include/fdtdec.h
> @@ -81,6 +81,7 @@ enum fdt_compat_id {
>         COMPAT_SAMSUNG_EXYNOS_EHCI,     /* Exynos EHCI controller */
>         COMPAT_SAMSUNG_EXYNOS_USB_PHY,  /* Exynos phy controller for usb2.0 */
>         COMPAT_MAXIM_MAX77686_PMIC,     /* MAX77686 PMIC */
> +       COMPAT_SAMSUNG_PINCTRL,         /* PINCTRL */
>
>         COMPAT_COUNT,
>  };
> diff --git a/lib/fdtdec.c b/lib/fdtdec.c
> index 3ae348d..16dbdcd 100644
> --- a/lib/fdtdec.c
> +++ b/lib/fdtdec.c
> @@ -56,6 +56,7 @@ static const char * const compat_names[COMPAT_COUNT] = {
>         COMPAT(SAMSUNG_EXYNOS_EHCI, "samsung,exynos-ehci"),
>         COMPAT(SAMSUNG_EXYNOS_USB_PHY, "samsung,exynos-usb-phy"),
>         COMPAT(MAXIM_MAX77686_PMIC, "maxim,max77686_pmic"),
> +       COMPAT(SAMSUNG_PINCTRL, "samsung,pinctrl"),
>  };
>
>  const char *fdtdec_get_compatible(enum fdt_compat_id id)
> --
> 1.7.9.5
>
diff mbox

Patch

diff --git a/arch/arm/cpu/armv7/exynos/pinmux.c b/arch/arm/cpu/armv7/exynos/pinmux.c
index a01ce0c..f4dccad 100644
--- a/arch/arm/cpu/armv7/exynos/pinmux.c
+++ b/arch/arm/cpu/armv7/exynos/pinmux.c
@@ -27,6 +27,18 @@ 
 #include <asm/arch/pinmux.h>
 #include <asm/arch/sromc.h>
 
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Struct for storing pin function and gpio related info */
+struct pin_group {
+	void *dev_name;
+	int npins;
+	int function;
+	int pull_mode;
+	int drive_strength;
+	enum exynos5_gpio_pin gpio[];
+};
+
 struct gpio_name_num_table exynos5_gpio_table[] = {
 	{ 'a', GPIO_A00 },
 	{ 'b', GPIO_B00 },
@@ -42,87 +54,202 @@  struct gpio_name_num_table exynos5_gpio_table[] = {
 	{ 'z', GPIO_Z0 },
 };
 
-static void exynos5_uart_config(int peripheral)
+static void get_pins(const struct fdt_property *fprop, struct pin_group *pingrp)
 {
-	int i, start, count;
+	int i;
+	char gpio[5];
+
+	pingrp->npins = 0;
+
+	for (i = 0; !(fprop->data[i] == (int)NULL &&
+				fprop->data[i-1] == (int)NULL); i += 7) {
+		int pin_num = -1;
+
+		gpio[0] = fprop->data[i];
+		gpio[1] = fprop->data[i + 1];
+		gpio[2] = fprop->data[i + 2];
+		gpio[3] = fprop->data[i + 3];
+		gpio[4] = fprop->data[i + 5];
+
+		pin_num = name_to_gpio(gpio);
+
+		if (pin_num >= 0) {
+			pingrp->gpio[pingrp->npins] = pin_num;
+			pingrp->npins++;
+		}
+	}
+}
+
+static int get_fdt_values(struct pin_group *pingrp)
+{
+	int i;
+	int node, subnode;
+	const struct fdt_property *fprop;
+
+	for (i = 0; i < 4; i++) {
+		/* Get the node from FDT for pinctrl */
+		node = fdtdec_next_compatible(gd->fdt_blob, 0,
+						COMPAT_SAMSUNG_PINCTRL);
+		if (node < 0) {
+			printf("PINCTRL: No node for pinctrl in device tree\n");
+			return -1;
+		}
+
+		subnode = fdt_subnode_offset(gd->fdt_blob,
+						node, pingrp->dev_name);
+		if (subnode < 0)
+			continue;
+
+		fprop = fdt_get_property(gd->fdt_blob,
+					subnode, "samsung,pins", NULL);
+		pingrp->function = fdtdec_get_int(gd->fdt_blob,
+					subnode, "samsung,pin-function", -1);
+		pingrp->pull_mode = fdtdec_get_int(gd->fdt_blob,
+					subnode, "samsung,pin-pud", -1);
+		pingrp->drive_strength = fdtdec_get_int(gd->fdt_blob,
+					subnode, "samsung,pin-drv", -1);
+		get_pins(fprop, pingrp);
+
+		return 0;
+	}
+
+	debug("PINCTRL: No subnode for %s\n", (char *)pingrp->dev_name);
+
+	return -1;
+}
+
+static void pin_config_group_set(struct pin_group *pingrp)
+{
+	int i;
+
+	for (i = 0; i < pingrp->npins; i++) {
+		gpio_cfg_pin(pingrp->gpio[i], S5P_GPIO_FUNC(pingrp->function));
+		gpio_set_pull(pingrp->gpio[i], pingrp->pull_mode);
+		gpio_set_drv(pingrp->gpio[i], pingrp->drive_strength);
+	}
+}
+
+static int exynos5_uart_config(int peripheral)
+{
+	char *data, *fctl = NULL;
+	struct pin_group pingrp;
 
 	switch (peripheral) {
 	case PERIPH_ID_UART0:
-		start = GPIO_A00;
-		count = 4;
+		data = "uart0-data";
+		fctl = "uart0-fctl";
 		break;
 	case PERIPH_ID_UART1:
-		start = GPIO_D00;
-		count = 4;
+		data = "uart1-data";
+		fctl = "uart1-fctl";
 		break;
 	case PERIPH_ID_UART2:
-		start = GPIO_A10;
-		count = 4;
+		data = "uart2-data";
+		fctl = "uart2-fctl";
 		break;
 	case PERIPH_ID_UART3:
-		start = GPIO_A14;
-		count = 2;
+		data = "uart3-data";
 		break;
 	}
-	for (i = start; i < start + count; i++) {
-		gpio_set_pull(i, S5P_GPIO_PULL_NONE);
-		gpio_cfg_pin(i, S5P_GPIO_FUNC(0x2));
+
+	pingrp.dev_name = data;
+
+	/*
+	 * Retrieve and apply pin config details
+	 * from fdt for this UART's data line.
+	 */
+	if (get_fdt_values(&pingrp))
+		return -1;
+
+	pin_config_group_set(&pingrp);
+
+	if (peripheral != PERIPH_ID_UART3) {
+		pingrp.dev_name = fctl;
+
+		/*
+		 * Retrieve and apply pin config details
+		 * from fdt for this UART's fctl.
+		 */
+		if (get_fdt_values(&pingrp))
+			return -1;
+
+		pin_config_group_set(&pingrp);
 	}
+
+	return 0;
 }
 
 static int exynos5_mmc_config(int peripheral, int flags)
 {
-	int i, start, start_ext, gpio_func = 0;
+	char *periph_name = NULL;
+	struct pin_group pingrp;
 
 	switch (peripheral) {
 	case PERIPH_ID_SDMMC0:
-		start = GPIO_C00;
-		start_ext = GPIO_C10;
-		gpio_func = S5P_GPIO_FUNC(0x2);
+		periph_name = "sd0";
 		break;
 	case PERIPH_ID_SDMMC1:
-		start = GPIO_C20;
-		start_ext = 0;
+		periph_name = "sd1";
 		break;
 	case PERIPH_ID_SDMMC2:
-		start = GPIO_C30;
-		start_ext = GPIO_C43;
-		gpio_func = S5P_GPIO_FUNC(0x3);
+		periph_name = "sd2";
 		break;
 	case PERIPH_ID_SDMMC3:
-		start = GPIO_C40;
-		start_ext = 0;
+		periph_name = "sd3";
 		break;
 	}
-	if ((flags & PINMUX_FLAG_8BIT_MODE) && !start_ext) {
-		debug("SDMMC device %d does not support 8bit mode",
-				peripheral);
-		return -1;
-	}
+
 	if (flags & PINMUX_FLAG_8BIT_MODE) {
-		for (i = start_ext; i <= (start_ext + 3); i++) {
-			gpio_cfg_pin(i, gpio_func);
-			gpio_set_pull(i, S5P_GPIO_PULL_UP);
-			gpio_set_drv(i, S5P_GPIO_DRV_4X);
-		}
-	}
-	for (i = 0; i < 2; i++) {
-		gpio_cfg_pin(start + i, S5P_GPIO_FUNC(0x2));
-		gpio_set_pull(start + i, S5P_GPIO_PULL_NONE);
-		gpio_set_drv(start + i, S5P_GPIO_DRV_4X);
-	}
-	for (i = 3; i <= 6; i++) {
-		gpio_cfg_pin(start + i, S5P_GPIO_FUNC(0x2));
-		gpio_set_pull(start + i, S5P_GPIO_PULL_UP);
-		gpio_set_drv(start + i, S5P_GPIO_DRV_4X);
+		pingrp.dev_name = strcat(periph_name, "-bus-width8");
+		/*
+		 * Retrieve and apply pin config details from fdt
+		 * for remaining 4 bits if this sd has 8-bit bus.
+		 */
+		if (get_fdt_values(&pingrp))
+			return -1;
+
+		pin_config_group_set(&pingrp);
 	}
 
+	pingrp.dev_name = strcat(periph_name, "-clk");
+
+	/*
+	 * Retrieve and apply pin config details
+	 * from fdt for this sd's clk.
+	 */
+	if (get_fdt_values(&pingrp))
+		return -1;
+
+	pin_config_group_set(&pingrp);
+
+	pingrp.dev_name = strcat(periph_name, "-cmd");
+
+	/*
+	 * Retrieve and apply pin config details
+	 * from fdt for this sd's cmd.
+	 */
+	if (get_fdt_values(&pingrp))
+		return -1;
+
+	pin_config_group_set(&pingrp);
+
+	pingrp.dev_name = strcat(periph_name, "-bus-width4");
+
+	/*
+	 * Retrieve and apply pin config details
+	 * from fdt for this sd's 4-bit bus.
+	 */
+	if (get_fdt_values(&pingrp))
+		return -1;
+
+	pin_config_group_set(&pingrp);
+
 	return 0;
 }
 
-static void exynos5_sromc_config(int flags)
+static int exynos5_sromc_config(int flags)
 {
-	int i;
+	static struct pin_group pingrp;
 
 	/*
 	 * SROM:CS1 and EBI
@@ -139,13 +266,28 @@  static void exynos5_sromc_config(int flags)
 	 * GPY1[2]	SROM_WAIT(2)
 	 * GPY1[3]	EBI_DATA_RDn(2)
 	 */
-	gpio_cfg_pin(GPIO_Y00 + (flags & PINMUX_FLAG_BANK),
-				S5P_GPIO_FUNC(2));
-	gpio_cfg_pin(GPIO_Y04, S5P_GPIO_FUNC(2));
-	gpio_cfg_pin(GPIO_Y05, S5P_GPIO_FUNC(2));
+	pingrp.dev_name = "srom-cs1";
 
-	for (i = 0; i < 4; i++)
-		gpio_cfg_pin(GPIO_Y10 + i, S5P_GPIO_FUNC(2));
+	/*
+	 * Retrieve and apply pin config details
+	 * from fdt to enable SROM CS1.
+	 */
+	if (get_fdt_values(&pingrp))
+		return -1;
+
+	pingrp.gpio[0] += (flags & PINMUX_FLAG_BANK);
+	pin_config_group_set(&pingrp);
+
+	pingrp.dev_name = "srom-ebi-enable";
+
+	/*
+	 * Retrieve and apply pin config details
+	 * from fdt to enable SROM EBI.
+	 */
+	if (get_fdt_values(&pingrp))
+		return -1;
+
+	pin_config_group_set(&pingrp);
 
 	/*
 	 * EBI: 8 Addrss Lines
@@ -179,97 +321,124 @@  static void exynos5_sromc_config(int flags)
 	 * GPY6[6]	EBI_DATA[14](2)
 	 * GPY6[7]	EBI_DATA[15](2)
 	 */
-	for (i = 0; i < 8; i++) {
-		gpio_cfg_pin(GPIO_Y30 + i, S5P_GPIO_FUNC(2));
-		gpio_set_pull(GPIO_Y30 + i, S5P_GPIO_PULL_UP);
+	pingrp.dev_name = "srom-ebi-addr-lines";
+
+	/*
+	 * Retrieve and apply pin config details
+	 * from fdt for EBI address lines.
+	 */
+	if (get_fdt_values(&pingrp))
+		return -1;
 
-		gpio_cfg_pin(GPIO_Y50 + i, S5P_GPIO_FUNC(2));
-		gpio_set_pull(GPIO_Y50 + i, S5P_GPIO_PULL_UP);
+	pin_config_group_set(&pingrp);
 
-		gpio_cfg_pin(GPIO_Y60 + i, S5P_GPIO_FUNC(2));
-		gpio_set_pull(GPIO_Y60 + i, S5P_GPIO_PULL_UP);
-	}
+	pingrp.dev_name = "srom-ebi-data-lines";
+
+	/*
+	 * Retrieve and apply pin config details
+	 * from fdt for EBI data lines.
+	 */
+	if (get_fdt_values(&pingrp))
+		return -1;
+
+	pin_config_group_set(&pingrp);
+
+	return 0;
 }
 
-static void exynos5_i2c_config(int peripheral, int flags)
+static int exynos5_i2c_config(int peripheral, int flags)
 {
+	struct pin_group pingrp;
 
 	switch (peripheral) {
 	case PERIPH_ID_I2C0:
-		gpio_cfg_pin(GPIO_B30, S5P_GPIO_FUNC(0x2));
-		gpio_cfg_pin(GPIO_B31, S5P_GPIO_FUNC(0x2));
+		pingrp.dev_name = "i2c0-bus";
 		break;
 	case PERIPH_ID_I2C1:
-		gpio_cfg_pin(GPIO_B32, S5P_GPIO_FUNC(0x2));
-		gpio_cfg_pin(GPIO_B33, S5P_GPIO_FUNC(0x2));
+		pingrp.dev_name = "i2c1-bus";
 		break;
 	case PERIPH_ID_I2C2:
-		gpio_cfg_pin(GPIO_A06, S5P_GPIO_FUNC(0x3));
-		gpio_cfg_pin(GPIO_A07, S5P_GPIO_FUNC(0x3));
+		pingrp.dev_name = "i2c2-bus";
 		break;
 	case PERIPH_ID_I2C3:
-		gpio_cfg_pin(GPIO_A12, S5P_GPIO_FUNC(0x3));
-		gpio_cfg_pin(GPIO_A13, S5P_GPIO_FUNC(0x3));
+		pingrp.dev_name = "i2c3-bus";
 		break;
 	case PERIPH_ID_I2C4:
-		gpio_cfg_pin(GPIO_A20, S5P_GPIO_FUNC(0x3));
-		gpio_cfg_pin(GPIO_A21, S5P_GPIO_FUNC(0x3));
+		pingrp.dev_name = "i2c4-bus";
 		break;
 	case PERIPH_ID_I2C5:
-		gpio_cfg_pin(GPIO_A22, S5P_GPIO_FUNC(0x3));
-		gpio_cfg_pin(GPIO_A23, S5P_GPIO_FUNC(0x3));
+		pingrp.dev_name = "i2c5-bus";
 		break;
 	case PERIPH_ID_I2C6:
-		gpio_cfg_pin(GPIO_B13, S5P_GPIO_FUNC(0x4));
-		gpio_cfg_pin(GPIO_B14, S5P_GPIO_FUNC(0x4));
+		pingrp.dev_name = "i2c6-bus";
 		break;
 	case PERIPH_ID_I2C7:
-		gpio_cfg_pin(GPIO_B22, S5P_GPIO_FUNC(0x3));
-		gpio_cfg_pin(GPIO_B23, S5P_GPIO_FUNC(0x3));
+		pingrp.dev_name = "i2c7-bus";
 		break;
 	}
+
+	/*
+	 * Retrieve and apply pin config details
+	 * from fdt for this i2c bus.
+	 */
+	if (get_fdt_values(&pingrp))
+		return -1;
+
+	pin_config_group_set(&pingrp);
+
+	return 0;
 }
 
-static void exynos5_i2s_config(int peripheral)
+static int exynos5_i2s_config(int peripheral)
 {
-	int i;
+	struct pin_group pingrp;
+
+	pingrp.dev_name = "i2s";
+
+	/*
+	 * Retrieve and apply pin config details
+	 * from fdt for i2s.
+	 */
+	if (get_fdt_values(&pingrp))
+		return -1;
+
+	pin_config_group_set(&pingrp);
 
-	for (i = 0; i < 5; i++)
-		gpio_cfg_pin(GPIO_B00+i, S5P_GPIO_FUNC(0x02));
+	return 0;
 }
 
-void exynos5_spi_config(int peripheral)
+int exynos5_spi_config(int peripheral)
 {
-	int cfg = 0, pin = 0, i;
+	static struct pin_group pingrp;
 
 	switch (peripheral) {
 	case PERIPH_ID_SPI0:
-		cfg = S5P_GPIO_FUNC(0x2);
-		pin = GPIO_A20;
+		pingrp.dev_name = "spi0-bus";
 		break;
 	case PERIPH_ID_SPI1:
-		cfg = S5P_GPIO_FUNC(0x2);
-		pin = GPIO_A24;
+		pingrp.dev_name = "spi1-bus";
 		break;
 	case PERIPH_ID_SPI2:
-		cfg = S5P_GPIO_FUNC(0x5);
-		pin = GPIO_B11;
+		pingrp.dev_name = "spi2-bus";
 		break;
 	case PERIPH_ID_SPI3:
-		cfg = S5P_GPIO_FUNC(0x2);
-		pin = GPIO_F10;
+		pingrp.dev_name = "spi3-bus";
 		break;
 	case PERIPH_ID_SPI4:
-		for (i = 0; i < 2; i++) {
-			gpio_cfg_pin(GPIO_F02 + i, S5P_GPIO_FUNC(0x4));
-			gpio_cfg_pin(GPIO_E04 + i, S5P_GPIO_FUNC(0x4));
-		}
+		pingrp.dev_name = "spi4-bus";
 		break;
 	}
-	if (peripheral != PERIPH_ID_SPI4) {
-		for (i = pin; i < pin + 4; i++)
-			gpio_cfg_pin(i, cfg);
-	}
+
+	/*
+	 * Retrieve and apply pin config details
+	 * from fdt for this spi.
+	 */
+	if (get_fdt_values(&pingrp))
+		return -1;
+
+	pin_config_group_set(&pingrp);
+
+	return 0;
 }
 
 static int exynos5_pinmux_config(int peripheral, int flags)
@@ -279,7 +448,7 @@  static int exynos5_pinmux_config(int peripheral, int flags)
 	case PERIPH_ID_UART1:
 	case PERIPH_ID_UART2:
 	case PERIPH_ID_UART3:
-		exynos5_uart_config(peripheral);
+		return exynos5_uart_config(peripheral);
 		break;
 	case PERIPH_ID_SDMMC0:
 	case PERIPH_ID_SDMMC1:
@@ -287,7 +456,7 @@  static int exynos5_pinmux_config(int peripheral, int flags)
 	case PERIPH_ID_SDMMC3:
 		return exynos5_mmc_config(peripheral, flags);
 	case PERIPH_ID_SROMC:
-		exynos5_sromc_config(flags);
+		return exynos5_sromc_config(flags);
 		break;
 	case PERIPH_ID_I2C0:
 	case PERIPH_ID_I2C1:
@@ -297,24 +466,22 @@  static int exynos5_pinmux_config(int peripheral, int flags)
 	case PERIPH_ID_I2C5:
 	case PERIPH_ID_I2C6:
 	case PERIPH_ID_I2C7:
-		exynos5_i2c_config(peripheral, flags);
+		return exynos5_i2c_config(peripheral, flags);
 		break;
 	case PERIPH_ID_I2S1:
-		exynos5_i2s_config(peripheral);
+		return exynos5_i2s_config(peripheral);
 		break;
 	case PERIPH_ID_SPI0:
 	case PERIPH_ID_SPI1:
 	case PERIPH_ID_SPI2:
 	case PERIPH_ID_SPI3:
 	case PERIPH_ID_SPI4:
-		exynos5_spi_config(peripheral);
+		return exynos5_spi_config(peripheral);
 		break;
 	default:
 		debug("%s: invalid peripheral %d", __func__, peripheral);
 		return -1;
 	}
-
-	return 0;
 }
 
 static void exynos4_i2c_config(int peripheral, int flags)
diff --git a/arch/arm/dts/exynos5250-pinctrl.dtsi b/arch/arm/dts/exynos5250-pinctrl.dtsi
new file mode 100644
index 0000000..efbe1be
--- /dev/null
+++ b/arch/arm/dts/exynos5250-pinctrl.dtsi
@@ -0,0 +1,675 @@ 
+/*
+ * Samsung's Exynos5250 SoC pin-mux and pin-config device tree source
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Samsung's Exynos5250 SoC pin-mux and pin-config options are listed as device
+ * tree nodes in this file.
+ *
+ * Note: This file does not include pin-ctrl subnodes for all the controllers in
+ * Exynos5250 SoC. It can be updated as per need in future.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+/ {
+	pinctrl_0: pinctrl@11400000 {
+		compatible = "samsung,pinctrl";
+		reg = <0x11400000 0x1000>;
+		interrupts = <0 46 0>;
+
+		gpa0: gpa0 {
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+		};
+
+		gpa1: gpa1 {
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+		};
+
+		gpa2: gpa2 {
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+		};
+
+		gpb0: gpb0 {
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+		};
+
+		gpb1: gpb1 {
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+		};
+
+		gpb2: gpb2 {
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+		};
+
+		gpb3: gpb3 {
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+		};
+
+		gpc0: gpc0 {
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+		};
+
+		gpc1: gpc1 {
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+		};
+
+		gpc2: gpc2 {
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+		};
+
+		gpc3: gpc3 {
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+		};
+
+		gpd0: gpd0 {
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+		};
+
+		gpd1: gpd1 {
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+		};
+
+		gpy0: gpy0 {
+			gpio-controller;
+			#gpio-cells = <2>;
+		};
+
+		gpy1: gpy1 {
+			gpio-controller;
+			#gpio-cells = <2>;
+		};
+
+		gpy2: gpy2 {
+			gpio-controller;
+			#gpio-cells = <2>;
+		};
+
+		gpy3: gpy3 {
+			gpio-controller;
+			#gpio-cells = <2>;
+		};
+
+		gpy4: gpy4 {
+			gpio-controller;
+			#gpio-cells = <2>;
+		};
+
+		gpy5: gpy5 {
+			gpio-controller;
+			#gpio-cells = <2>;
+		};
+
+		gpy6: gpy6 {
+			gpio-controller;
+			#gpio-cells = <2>;
+		};
+
+		gpc4: gpc4 {
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+		};
+
+		gpx0: gpx0 {
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+		};
+
+		gpx1: gpx1 {
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+		};
+
+		gpx2: gpx2 {
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+		};
+
+		gpx3: gpx3 {
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+		};
+
+		uart0_data: uart0-data {
+			samsung,pins = "gpa0-0", "gpa0-1";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <0>;
+			samsung,pin-drv = <0>;
+		};
+
+		uart0_fctl: uart0-fctl {
+			samsung,pins = "gpa0-2", "gpa0-3";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <0>;
+			samaung,pin-drv = <0>;
+		};
+
+		uart1_data: uart1-data {
+			samsung,pins = "gpd0-0", "gpd0-1";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <0>;
+			samsung,pin-drv = <0>;
+		};
+
+		uart1_fctl: uart1-fctl {
+			samsung,pins = "gpd0-2", "gpd0-3";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <0>;
+			samaung,pin-drv = <0>;
+		};
+
+		uart2_data: uart2-data {
+			samsung,pins = "gpa1-0", "gpa1-1";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <0>;
+			samsung,pin-drv = <0>;
+		};
+
+		uart2_fctl: uart2-fctl {
+			samsung,pins = "gpa1-2", "gpa1-3";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <0>;
+			samaung,pin-drv = <0>;
+		};
+
+		uart3_data: uart3-data {
+			samsung,pins = "gpa1-4", "gpa1-5";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <0>;
+			samsung,pin-drv = <0>;
+		};
+
+		sd0_clk: sd0-clk {
+			samsung,pins = "gpc0-0";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <0>;
+			samsung,pin-drv = <3>;
+		};
+
+		sd0_cmd: sd0-cmd {
+			samsung,pins = "gpc0-1";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <0>;
+			samsung,pin-drv = <3>;
+		};
+
+		sd0_cd: sd0-cd {
+			samsung,pins = "gpc0-2";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <3>;
+			samsung,pin-drv = <3>;
+		};
+
+		sd0_bus1: sd0-bus-width1 {
+			samsung,pins = "gpc0-3";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <3>;
+			samsung,pin-drv = <3>;
+		};
+
+		sd0_bus4: sd0-bus-width4 {
+			samsung,pins = "gpc0-3", "gpc0-4", "gpc0-5", "gpc0-6";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <3>;
+			samsung,pin-drv = <3>;
+		};
+
+		sd0_bus8: sd0-bus-width8 {
+			samsung,pins = "gpc1-0", "gpc1-1", "gpc1-2", "gpc1-3";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <3>;
+			samsung,pin-drv = <3>;
+		};
+
+		sd1_clk: sd1-clk {
+			samsung,pins = "gpc2-0";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <0>;
+			samsung,pin-drv = <3>;
+		};
+
+		sd1_cmd: sd1-cmd {
+			samsung,pins = "gpc2-1";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <0>;
+			samsung,pin-drv = <3>;
+		};
+
+		sd1_cd: sd1-cd {
+			samsung,pins = "gpc2-2";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <3>;
+			samsung,pin-drv = <3>;
+		};
+
+		sd1_bus1: sd1-bus-width1 {
+			samsung,pins = "gpc2-3";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <3>;
+			samsung,pin-drv = <3>;
+		};
+
+		sd1_bus4: sd1-bus-width4 {
+			samsung,pins = "gpc2-3", "gpc2-4", "gpc2-5", "gpc2-6";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <3>;
+			samsung,pin-drv = <3>;
+		};
+
+		sd2_clk: sd2-clk {
+			samsung,pins = "gpc3-0";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <0>;
+			samsung,pin-drv = <3>;
+		};
+
+		sd2_cmd: sd2-cmd {
+			samsung,pins = "gpc3-1";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <0>;
+			samsung,pin-drv = <3>;
+		};
+
+		sd2_cd: sd2-cd {
+			samsung,pins = "gpc3-2";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <3>;
+			samsung,pin-drv = <3>;
+		};
+
+		sd2_bus1: sd2-bus-width1 {
+			samsung,pins = "gpc3-3";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <3>;
+			samsung,pin-drv = <3>;
+		};
+
+		sd2_bus4: sd2-bus-width4 {
+			samsung,pins = "gpc3-3", "gpc3-4", "gpc3-5", "gpc3-6";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <3>;
+			samsung,pin-drv = <3>;
+		};
+
+		sd2_bus8: sd2-bus-width8 {
+			samsung,pins = "gpc4-3", "gpc4-4", "gpc4-5", "gpc4-6";
+			samsung,pin-function = <3>;
+			samsung,pin-pud = <3>;
+			samsung,pin-drv = <3>;
+		};
+
+		sd3_clk: sd3-clk {
+			samsung,pins = "gpc4-0";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <0>;
+			samsung,pin-drv = <3>;
+		};
+
+		sd3_cmd: sd3-cmd {
+			samsung,pins = "gpc4-1";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <0>;
+			samsung,pin-drv = <3>;
+		};
+
+		sd3_cd: sd3-cd {
+			samsung,pins = "gpc4-2";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <3>;
+			samsung,pin-drv = <3>;
+		};
+
+		sd3_bus1: sd3-bus-width1 {
+			samsung,pins = "gpc4-3";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <3>;
+			samsung,pin-drv = <3>;
+		};
+
+		sd3_bus4: sd3-bus-width4 {
+			samsung,pins = "gpc4-3", "gpc4-4", "gpc4-5", "gpc4-6";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <3>;
+			samsung,pin-drv = <3>;
+		};
+
+		srom_cs1: srom-cs1 {
+			samsung,pins = "gpy0-0", "gpy0-4", "gpy0-5";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <0>;
+			samsung,pin-drv = <0>;
+		};
+
+		srom_ebi: srom-ebi-enable {
+			samsung,pins = "gpy1-0", "gpy1-1", "gpy1-2", "gpy1-3";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <0>;
+			samsung,pin-drv = <0>;
+		};
+
+		srom_ebi_a: srom-ebi-addr-lines {
+			samsung,pins = "gpy3-0", "gpy3-1", "gpy3-2", "gpy3-3",
+					"gpy3-4", "gpy3-5", "gpy3-6", "gpy3-7";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <3>;
+			samsung,pin-drv = <0>;
+		};
+
+		srom_ebi_d: srom-ebi-data-lines {
+			samsung,pins = "gpy5-0", "gpy5-1", "gpy5-2", "gpy5-3",
+					"gpy5-4", "gpy5-5", "gpy5-6", "gpy5-7",
+					"gpy6-0", "gpy6-1", "gpy6-2", "gpy6-3",
+					"gpy6-4", "gpy6-5", "gpy6-6", "gpy6-7";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <3>;
+			samsung,pin-drv = <0>;
+		};
+
+		i2s: i2s {
+			samsung,pins = "gpb0-0", "gpb0-1", "gpb0-2", "gpb0-3",
+					"gpb0-4";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <0>;
+			samsung,pin-drv = <0>;
+		};
+
+		spi0_bus: spi0-bus {
+			samsung,pins = "gpa2-0", "gpa2-1", "gpa2-2", "gpa2-3";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <3>;
+			samsung,pin-drv = <0>;
+		};
+
+		spi1_bus: spi1-bus {
+			samsung,pins = "gpa2-4", "gpa2-5", "gpa2-6", "gpa2-7";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <3>;
+			samsung,pin-drv = <0>;
+		};
+
+		spi2_bus: spi2-bus {
+			samsung,pins = "gpb1-1", "gpb1-2", "gpb1-3", "gpb1-4";
+			samsung,pin-function = <5>;
+			samsung,pin-pud = <3>;
+			samsung,pin-drv = <0>;
+		};
+
+		i2c0_bus: i2c0-bus {
+			samsung,pins = "gpb3-0", "gpb3-1";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <3>;
+			samsung,pin-drv = <0>;
+		};
+
+		i2c1_bus: i2c1-bus {
+			samsung,pins = "gpb3-2", "gpb3-3";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <3>;
+			samsung,pin-drv = <0>;
+		};
+
+		i2c2_bus: i2c2-bus {
+			samsung,pins = "gpa0-6", "gpa0-7";
+			samsung,pin-function = <3>;
+			samsung,pin-pud = <3>;
+			samaung,pin-drv = <0>;
+		};
+
+		i2c3_bus: i2c3-bus {
+			samsung,pins = "gpa1-2", "gpa1-3";
+			samsung,pin-function = <3>;
+			samsung,pin-pud = <3>;
+			samaung,pin-drv = <0>;
+		};
+
+		i2c4_bus: i2c4-bus {
+			samsung,pins = "gpa2-0", "gpa2-1";
+			samsung,pin-function = <3>;
+			samsung,pin-pud = <3>;
+			samaung,pin-drv = <0>;
+		};
+
+		i2c5_bus: i2c5-bus {
+			samsung,pins = "gpa2-2", "gpa2-3";
+			samsung,pin-function = <3>;
+			samsung,pin-pud = <3>;
+			samaung,pin-drv = <0>;
+		};
+
+		i2c6_bus: i2c6-bus {
+			samsung,pins = "gpb1-3", "gpb1-4";
+			samsung,pin-function = <4>;
+			samsung,pin-pud = <3>;
+			samsung,pin-drv = <0>;
+		};
+
+		i2c7_bus: i2c7-bus {
+			samsung,pins = "gpb2-2", "gpb2-3";
+			samsung,pin-function = <3>;
+			samsung,pin-pud = <3>;
+			samsung,pin-drv = <0>;
+		};
+	};
+
+	pinctrl_1: pinctrl@13400000 {
+		compatible = "samsung,pinctrl";
+		reg = <0x13400000 0x1000>;
+		interrupts = <0 45 0>;
+
+		gpe0: gpe0 {
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+		};
+
+		gpe1: gpe1 {
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+		};
+
+		gpf0: gpf0 {
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+		};
+
+		gpf1: gpf1 {
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+		};
+
+		gpg0: gpg0 {
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+		};
+
+		gpg1: gpg1 {
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+		};
+
+		gpg2: gpg2 {
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+		};
+
+		gph0: gph0 {
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+		};
+
+		gph1: gph1 {
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+		};
+
+		spi3_bus: spi3-bus {
+			samsung,pins = "gpf1-0", "gpf1-1", "gpf1-2", "gpf1-3";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <3>;
+			samsung,pin-drv = <0>;
+		};
+
+		spi4_bus: spi4-bus {
+			samsung,pins = "gpf0-2", "gpf0-3", "gpe0-4", "gpe0-5";
+			samsung,pin-function = <4>;
+			samsung,pin-pud = <3>;
+			samsung,pin-drv = <0>;
+		};
+	};
+
+	pinctrl_2: pinctrl@10d10000 {
+		compatible = "samsung,pinctrl-exynos5250";
+		reg = <0x10d10000 0x1000>;
+		interrupts = <0 45 0>;
+
+		gpv0: gpv0 {
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+		};
+
+		gpv1: gpv1 {
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+		};
+
+		gpv2: gpv2 {
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+		};
+
+		gpv3: gpv3 {
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+		};
+
+		gpv4: gpv4 {
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+		};
+	};
+
+	pinctrl_3: pinctrl@03680000 {
+		compatible = "samsung,pinctrl-exynos5250";
+		reg = <0x03680000 0x1000>;
+		interrupts = <0 45 0>;
+
+		gpz: gpz {
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+		};
+	};
+};
diff --git a/arch/arm/dts/exynos5250.dtsi b/arch/arm/dts/exynos5250.dtsi
index ed8c8dd..8fcf432 100644
--- a/arch/arm/dts/exynos5250.dtsi
+++ b/arch/arm/dts/exynos5250.dtsi
@@ -18,6 +18,7 @@ 
 */
 
 /include/ "skeleton.dtsi"
+/include/ "exynos5250-pinctrl.dtsi"
 
 / {
 	compatible = "samsung,exynos5250";
diff --git a/doc/device-tree-bindings/samsung-pinctrl.txt b/doc/device-tree-bindings/samsung-pinctrl.txt
new file mode 100644
index 0000000..708ca45
--- /dev/null
+++ b/doc/device-tree-bindings/samsung-pinctrl.txt
@@ -0,0 +1,253 @@ 
+Samsung GPIO and Pin Mux/Config controller
+
+Samsung's ARM based SoC's integrates a GPIO and Pin mux/config hardware
+controller. It controls the input/output settings on the available pads/pins
+and also provides ability to multiplex and configure the output of various
+on-chip controllers onto these pads.
+
+Required Properties:
+- compatible: should be one of the following.
+  - "samsung,pinctrl": for Exynos compatible pin-controller.
+
+- reg: Base address of the pin controller hardware module and length of
+  the address space it occupies.
+
+- Pin banks as child nodes: Pin banks of the controller are represented by child
+  nodes of the controller node. Bank name is taken from name of the node. Each
+  bank node must contain following properties:
+
+  - gpio-controller: identifies the node as a gpio controller and pin bank.
+  - #gpio-cells: number of cells in GPIO specifier. Since the generic GPIO
+    binding is used, the amount of cells must be specified as 2. See generic
+    GPIO binding documentation for description of particular cells.
+
+- Pin mux/config groups as child nodes: The pin mux (selecting pin function
+  mode) and pin config (pull up/down, driver strength) settings are represented
+  as child nodes of the pin-controller node. There should be atleast one
+  child node and there is no limit on the count of these child nodes.
+
+  The child node should contain a list of pin(s) on which a particular pin
+  function selection or pin configuration (or both) have to applied. This
+  list of pins is specified using the property name "samsung,pins". There
+  should be atleast one pin specfied for this property and there is no upper
+  limit on the count of pins that can be specified. The pins are specified
+  using pin names which are derived from the hardware manual of the SoC. As
+  an example, the pins in GPA0 bank of the pin controller can be represented
+  as "gpa0-0", "gpa0-1", "gpa0-2" and so on. The names should be in lower case.
+  The format of the pin names should be (as per the hardware manual)
+  "[pin bank name]-[pin number within the bank]".
+
+  The pin function selection that should be applied on the pins listed in the
+  child node is specified using the "samsung,pin-function" property. The value
+  of this property that should be applied to each of the pins listed in the
+  "samsung,pins" property should be picked from the hardware manual of the SoC
+  for the specified pin group. This property is optional in the child node if
+  no specific function selection is desired for the pins listed in the child
+  node. The value of this property is used as-is to program the pin-controller
+  function selector register of the pin-bank.
+
+  The child node can also optionally specify one or more of the pin
+  configuration that should be applied on all the pins listed in the
+  "samsung,pins" property of the child node. The following pin configuration
+  properties are supported.
+
+  - samsung,pin-pud: Pull up/down configuration.
+  - samsung,pin-drv: Drive strength configuration.
+  - samsung,pin-pud-pdn: Pull up/down configuration in power down mode.
+  - samsung,pin-drv-pdn: Drive strength configuration in power down mode.
+
+  The values specified by these config properties should be derived from the
+  hardware manual and these values are programmed as-is into the pin
+  pull up/down and driver strength register of the pin-controller.
+
+  Note: A child should include atleast a pin function selection property or
+  pin configuration property (one or more) or both.
+
+  The client nodes that require a particular pin function selection and/or
+  pin configuration should use the bindings listed in the "pinctrl-bindings.txt"
+  file.
+
+External GPIO and Wakeup Interrupts:
+
+The controller supports two types of external interrupts over gpio. The first
+is the external gpio interrupt and second is the external wakeup interrupts.
+The difference between the two is that the external wakeup interrupts can be
+used as system wakeup events.
+
+A. External GPIO Interrupts: For supporting external gpio interrupts, the
+   following properties should be specified in the pin-controller device node.
+
+   - interrupt-parent: phandle of the interrupt parent to which the external
+     GPIO interrupts are forwarded to.
+   - interrupts: interrupt specifier for the controller. The format and value of
+     the interrupt specifier depends on the interrupt parent for the controller.
+
+   In addition, following properties must be present in node of every bank
+   of pins supporting GPIO interrupts:
+
+   - interrupt-controller: identifies the controller node as interrupt-parent.
+   - #interrupt-cells: the value of this property should be 2.
+     - First Cell: represents the external gpio interrupt number local to the
+       external gpio interrupt space of the controller.
+     - Second Cell: flags to identify the type of the interrupt
+       - 1 = rising edge triggered
+       - 2 = falling edge triggered
+       - 3 = rising and falling edge triggered
+       - 4 = high level triggered
+       - 8 = low level triggered
+
+B. External Wakeup Interrupts: For supporting external wakeup interrupts, a
+   child node representing the external wakeup interrupt controller should be
+   included in the pin-controller device node. This child node should include
+   the following properties.
+
+   - compatible: identifies the type of the external wakeup interrupt controller
+     The possible values are:
+     - samsung,wakeup-eint: represents wakeup interrupt controller
+       found on Samsung Exynos SoC.
+   - interrupt-parent: phandle of the interrupt parent to which the external
+     wakeup interrupts are forwarded to.
+   - interrupts: interrupt used by multiplexed wakeup interrupts.
+
+   In addition, following properties must be present in node of every bank
+   of pins supporting wake-up interrupts:
+
+   - interrupt-controller: identifies the node as interrupt-parent.
+   - #interrupt-cells: the value of this property should be 2
+     - First Cell: represents the external wakeup interrupt number local to
+       the external wakeup interrupt space of the controller.
+     - Second Cell: flags to identify the type of the interrupt
+       - 1 = rising edge triggered
+       - 2 = falling edge triggered
+       - 3 = rising and falling edge triggered
+       - 4 = high level triggered
+       - 8 = low level triggered
+
+   Node of every bank of pins supporting direct wake-up interrupts (without
+   multiplexing) must contain following properties:
+
+   - interrupt-parent: phandle of the interrupt parent to which the external
+     wakeup interrupts are forwarded to.
+   - interrupts: interrupts of the interrupt parent which are used for external
+     wakeup interrupts from pins of the bank, must contain interrupts for all
+     pins of the bank.
+
+Aliases:
+
+All the pin controller nodes should be represented in the aliases node using
+the following format 'pinctrl{n}' where n is a unique number for the alias.
+
+Example: A pin-controller node with pin banks:
+
+	pinctrl_0: pinctrl@11400000 {
+		compatible = "samsung,pinctrl;
+		reg = <0x11400000 0x1000>;
+		interrupts = <0 47 0>;
+
+		/* ... */
+
+		/* Pin bank without external interrupts */
+		gpy0: gpy0 {
+			gpio-controller;
+			#gpio-cells = <2>;
+		};
+
+		/* ... */
+
+		/* Pin bank with external GPIO or muxed wake-up interrupts */
+		gpj0: gpj0 {
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+		};
+
+		/* ... */
+
+		/* Pin bank with external direct wake-up interrupts */
+		gpx0: gpx0 {
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			interrupt-parent = <&gic>;
+			interrupts = <0 16 0>, <0 17 0>, <0 18 0>, <0 19 0>,
+				     <0 20 0>, <0 21 0>, <0 22 0>, <0 23 0>;
+			#interrupt-cells = <2>;
+		};
+
+		/* ... */
+	};
+
+Example 1: A pin-controller node with pin groups.
+
+	pinctrl_0: pinctrl@11400000 {
+		compatible = "samsung,pinctrl";
+		reg = <0x11400000 0x1000>;
+		interrupts = <0 47 0>;
+
+		/* ... */
+
+		uart0_data: uart0-data {
+			samsung,pins = "gpa0-0", "gpa0-1";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <0>;
+			samsung,pin-drv = <0>;
+		};
+
+		uart0_fctl: uart0-fctl {
+			samsung,pins = "gpa0-2", "gpa0-3";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <0>;
+			samsung,pin-drv = <0>;
+		};
+
+		uart1_data: uart1-data {
+			samsung,pins = "gpa0-4", "gpa0-5";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <0>;
+			samsung,pin-drv = <0>;
+		};
+
+		uart1_fctl: uart1-fctl {
+			samsung,pins = "gpa0-6", "gpa0-7";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <0>;
+			samsung,pin-drv = <0>;
+		};
+
+		i2c2_bus: i2c2-bus {
+			samsung,pins = "gpa0-6", "gpa0-7";
+			samsung,pin-function = <3>;
+			samsung,pin-pud = <3>;
+			samsung,pin-drv = <0>;
+		};
+	};
+
+Example 2: A pin-controller node with external wakeup interrupt controller node.
+
+	pinctrl_1: pinctrl@11000000 {
+		compatible = "samsung,pinctrl";
+		reg = <0x11000000 0x1000>;
+		interrupts = <0 46 0>
+
+		/* ... */
+
+		wakeup-interrupt-controller {
+			compatible = "samsung,wakeup-eint";
+			interrupt-parent = <&gic>;
+			interrupts = <0 32 0>;
+		};
+	};
+
+Example 3: A uart client node that supports 'default' and 'flow-control' states.
+
+	uart@13800000 {
+		compatible = "samsung,uart";
+		reg = <0x13800000 0x100>;
+		interrupts = <0 52 0>;
+		pinctrl-names = "default", "flow-control;
+		pinctrl-0 = <&uart0_data>;
+		pinctrl-1 = <&uart0_data &uart0_fctl>;
+	};
diff --git a/include/fdtdec.h b/include/fdtdec.h
index 77f244f..9c1bd82 100644
--- a/include/fdtdec.h
+++ b/include/fdtdec.h
@@ -81,6 +81,7 @@  enum fdt_compat_id {
 	COMPAT_SAMSUNG_EXYNOS_EHCI,	/* Exynos EHCI controller */
 	COMPAT_SAMSUNG_EXYNOS_USB_PHY,	/* Exynos phy controller for usb2.0 */
 	COMPAT_MAXIM_MAX77686_PMIC,	/* MAX77686 PMIC */
+	COMPAT_SAMSUNG_PINCTRL,		/* PINCTRL */
 
 	COMPAT_COUNT,
 };
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index 3ae348d..16dbdcd 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -56,6 +56,7 @@  static const char * const compat_names[COMPAT_COUNT] = {
 	COMPAT(SAMSUNG_EXYNOS_EHCI, "samsung,exynos-ehci"),
 	COMPAT(SAMSUNG_EXYNOS_USB_PHY, "samsung,exynos-usb-phy"),
 	COMPAT(MAXIM_MAX77686_PMIC, "maxim,max77686_pmic"),
+	COMPAT(SAMSUNG_PINCTRL, "samsung,pinctrl"),
 };
 
 const char *fdtdec_get_compatible(enum fdt_compat_id id)