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

login
register
mail settings
Submitter Akshay Saraswat
Date Feb. 25, 2013, 6:27 p.m.
Message ID <1361816840-28217-1-git-send-email-akshay.s@samsung.com>
Download mbox | patch
Permalink /patch/222991/
State Changes Requested
Delegated to: Minkyu Kang
Headers show

Comments

Akshay Saraswat - Feb. 25, 2013, 6:27 p.m.
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 v3:
        - Added comments to reduce ambiguity and increase readability.
	- Fixed few other nits.

 arch/arm/cpu/armv7/exynos/pinmux.c           |  404 +++++++++++----
 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, 1229 insertions(+), 106 deletions(-)
 create mode 100644 arch/arm/dts/exynos5250-pinctrl.dtsi
 create mode 100644 doc/device-tree-bindings/samsung-pinctrl.txt
Simon Glass - Feb. 28, 2013, 1:10 a.m.
Hi Akshay,

On Mon, Feb 25, 2013 at 10:27 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 v3:
>         - Added comments to reduce ambiguity and increase readability.
>         - Fixed few other nits.
>
>  arch/arm/cpu/armv7/exynos/pinmux.c           |  404 +++++++++++----
>  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, 1229 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..ba34560 100644
> --- a/arch/arm/cpu/armv7/exynos/pinmux.c
> +++ b/arch/arm/cpu/armv7/exynos/pinmux.c
> @@ -27,6 +27,21 @@
>  #include <asm/arch/pinmux.h>
>  #include <asm/arch/sromc.h>
>
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +/*
> + * Struct for temporarily storing pin numbers and
> + * pin function related info.
> + */
> +struct pin_group {
> +       void *dev_name;                 /* Name of the Peripheral device */
> +       int npins;                      /* Number of pins to be configured */
> +       int function;                   /* Pin function */
> +       int pull_mode;                  /* Pin pull mode */
> +       int drive_strength;             /* Pin drive strength */
> +       enum exynos5_gpio_pin gpio[];   /* Pin numbers to be configured */
> +};
> +
>  struct gpio_name_num_table exynos5_gpio_table[] = {
>         { 'a', GPIO_A00 },
>         { 'b', GPIO_B00 },
> @@ -42,87 +57,224 @@ struct gpio_name_num_table exynos5_gpio_table[] = {
>         { 'z', GPIO_Z0 },
>  };
>
> -static void exynos5_uart_config(int peripheral)
> +/* Populate exynos5_gpio_pin array in a particular pin_group */
> +static void pinmux_get_pin_numbers(const struct fdt_property *fprop,
> +                                               struct pin_group *pingrp)

You only use fprop->data here, so you should pass that in instead of fprop.

> +{
> +       int i;
> +       char gpio[5];
> +
> +       pingrp->npins = 0;
> +
> +       /*
> +        * Get all the pin names from fdt and fill the gpio array
> +        * with corresponding enum values(Pin numbers).
> +        */
> +       for (i = 0; !(fprop->data[i] == (int)NULL &&
> +                               fprop->data[i-1] == (int)NULL); i += 7) {
> +               int pin_num = -1;
> +
> +               /*
> +                * Modify pin name retrieved from fdt,
> +                * so that name_to_gpio may understand.
> +                */
> +               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 number is valid, add it to the pin array
> +                * and increment pin count.
> +                */
> +               if (pin_num >= 0) {
> +                       pingrp->gpio[pingrp->npins] = pin_num;
> +                       pingrp->npins++;
> +               }
> +       }
> +}
> +
> +/* Extract all the config info for a node from fdt */
> +static int pinmux_get_fdt_values(struct pin_group *pingrp)
>  {
> -       int i, start, count;
> +       int node, subnode;
> +       const struct fdt_property *fprop;
> +
> +       /* Loop for all pinctrl nodes in fdt */
> +       for (node = fdtdec_next_compatible(gd->fdt_blob, 0,
> +                       COMPAT_SAMSUNG_PINCTRL); node >= 0;
> +                       node = fdtdec_next_compatible(gd->fdt_blob, node,
> +                                               COMPAT_SAMSUNG_PINCTRL)) {
> +               /* Get the subnode from FDT for this peripheral*/
> +               subnode = fdt_subnode_offset(gd->fdt_blob,
> +                                               node, pingrp->dev_name);
> +               if (subnode < 0)
> +                       continue;
> +
> +               /* Get names of pins to be configured from fdt */
> +               fprop = fdt_get_property(gd->fdt_blob,
> +                                       subnode, "samsung,pins", NULL);

Can you use fdt_getprop() here? Also you should check for a NULL return value.

> +
> +               /* Convert pin names to pin numbers */
> +               pinmux_get_pin_numbers(fprop, pingrp);
> +
> +               /* Get the pin function from fdt */
> +               pingrp->function = fdtdec_get_int(gd->fdt_blob,
> +                                       subnode, "samsung,pin-function", 0);
> +
> +               /* Get the pull mode for pins from fdt */
> +               pingrp->pull_mode = fdtdec_get_int(gd->fdt_blob,
> +                                       subnode, "samsung,pin-pud", 0);
> +
> +               /* Get the drive strength for pins from fdt */
> +               pingrp->drive_strength = fdtdec_get_int(gd->fdt_blob,
> +                                       subnode, "samsung,pin-drv", 0);
> +
> +               return 0;
> +       }
> +
> +       debug("PINCTRL: Subnode for %s is missing\n",
> +                                       (const char *)pingrp->dev_name);
> +
> +       return -1;
> +}
> +
> +/* Set configuration for all pins as per fdt node */
> +static void pinmux_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";

Is it not possible for these strings to come from the device' node
eventually? Perhaps in a future patch?

>                 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;
>         }

Regards,
Simon

Patch

diff --git a/arch/arm/cpu/armv7/exynos/pinmux.c b/arch/arm/cpu/armv7/exynos/pinmux.c
index a01ce0c..ba34560 100644
--- a/arch/arm/cpu/armv7/exynos/pinmux.c
+++ b/arch/arm/cpu/armv7/exynos/pinmux.c
@@ -27,6 +27,21 @@ 
 #include <asm/arch/pinmux.h>
 #include <asm/arch/sromc.h>
 
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Struct for temporarily storing pin numbers and
+ * pin function related info.
+ */
+struct pin_group {
+	void *dev_name;			/* Name of the Peripheral device */
+	int npins;			/* Number of pins to be configured */
+	int function;			/* Pin function */
+	int pull_mode;			/* Pin pull mode */
+	int drive_strength;		/* Pin drive strength */
+	enum exynos5_gpio_pin gpio[];	/* Pin numbers to be configured */
+};
+
 struct gpio_name_num_table exynos5_gpio_table[] = {
 	{ 'a', GPIO_A00 },
 	{ 'b', GPIO_B00 },
@@ -42,87 +57,224 @@  struct gpio_name_num_table exynos5_gpio_table[] = {
 	{ 'z', GPIO_Z0 },
 };
 
-static void exynos5_uart_config(int peripheral)
+/* Populate exynos5_gpio_pin array in a particular pin_group */
+static void pinmux_get_pin_numbers(const struct fdt_property *fprop,
+						struct pin_group *pingrp)
+{
+	int i;
+	char gpio[5];
+
+	pingrp->npins = 0;
+
+	/*
+	 * Get all the pin names from fdt and fill the gpio array
+	 * with corresponding enum values(Pin numbers).
+	 */
+	for (i = 0; !(fprop->data[i] == (int)NULL &&
+				fprop->data[i-1] == (int)NULL); i += 7) {
+		int pin_num = -1;
+
+		/*
+		 * Modify pin name retrieved from fdt,
+		 * so that name_to_gpio may understand.
+		 */
+		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 number is valid, add it to the pin array
+		 * and increment pin count.
+		 */
+		if (pin_num >= 0) {
+			pingrp->gpio[pingrp->npins] = pin_num;
+			pingrp->npins++;
+		}
+	}
+}
+
+/* Extract all the config info for a node from fdt */
+static int pinmux_get_fdt_values(struct pin_group *pingrp)
 {
-	int i, start, count;
+	int node, subnode;
+	const struct fdt_property *fprop;
+
+	/* Loop for all pinctrl nodes in fdt */
+	for (node = fdtdec_next_compatible(gd->fdt_blob, 0,
+			COMPAT_SAMSUNG_PINCTRL); node >= 0;
+			node = fdtdec_next_compatible(gd->fdt_blob, node,
+						COMPAT_SAMSUNG_PINCTRL)) {
+		/* Get the subnode from FDT for this peripheral*/
+		subnode = fdt_subnode_offset(gd->fdt_blob,
+						node, pingrp->dev_name);
+		if (subnode < 0)
+			continue;
+
+		/* Get names of pins to be configured from fdt */
+		fprop = fdt_get_property(gd->fdt_blob,
+					subnode, "samsung,pins", NULL);
+
+		/* Convert pin names to pin numbers */
+		pinmux_get_pin_numbers(fprop, pingrp);
+
+		/* Get the pin function from fdt */
+		pingrp->function = fdtdec_get_int(gd->fdt_blob,
+					subnode, "samsung,pin-function", 0);
+
+		/* Get the pull mode for pins from fdt */
+		pingrp->pull_mode = fdtdec_get_int(gd->fdt_blob,
+					subnode, "samsung,pin-pud", 0);
+
+		/* Get the drive strength for pins from fdt */
+		pingrp->drive_strength = fdtdec_get_int(gd->fdt_blob,
+					subnode, "samsung,pin-drv", 0);
+
+		return 0;
+	}
+
+	debug("PINCTRL: Subnode for %s is missing\n",
+					(const char *)pingrp->dev_name);
+
+	return -1;
+}
+
+/* Set configuration for all pins as per fdt node */
+static void pinmux_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 (pinmux_get_fdt_values(&pingrp))
+		return -1;
+
+	pinmux_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 (pinmux_get_fdt_values(&pingrp))
+			return -1;
+
+		pinmux_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 (pinmux_get_fdt_values(&pingrp))
+			return -1;
+
+		pinmux_group_set(&pingrp);
 	}
 
+	pingrp.dev_name = strcat(periph_name, "-clk");
+
+	/*
+	 * Retrieve and apply pin config details
+	 * from fdt for this sd's clk.
+	 */
+	if (pinmux_get_fdt_values(&pingrp))
+		return -1;
+
+	pinmux_group_set(&pingrp);
+
+	pingrp.dev_name = strcat(periph_name, "-cmd");
+
+	/*
+	 * Retrieve and apply pin config details
+	 * from fdt for this sd's cmd.
+	 */
+	if (pinmux_get_fdt_values(&pingrp))
+		return -1;
+
+	pinmux_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 (pinmux_get_fdt_values(&pingrp))
+		return -1;
+
+	pinmux_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 +291,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";
+
+	/*
+	 * Retrieve and apply pin config details
+	 * from fdt to enable SROM CS1.
+	 */
+	if (pinmux_get_fdt_values(&pingrp))
+		return -1;
+
+	pingrp.gpio[0] += (flags & PINMUX_FLAG_BANK);
+	pinmux_group_set(&pingrp);
+
+	pingrp.dev_name = "srom-ebi-enable";
+
+	/*
+	 * Retrieve and apply pin config details
+	 * from fdt to enable SROM EBI.
+	 */
+	if (pinmux_get_fdt_values(&pingrp))
+		return -1;
 
-	for (i = 0; i < 4; i++)
-		gpio_cfg_pin(GPIO_Y10 + i, S5P_GPIO_FUNC(2));
+	pinmux_group_set(&pingrp);
 
 	/*
 	 * EBI: 8 Addrss Lines
@@ -179,97 +346,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";
 
-		gpio_cfg_pin(GPIO_Y50 + i, S5P_GPIO_FUNC(2));
-		gpio_set_pull(GPIO_Y50 + i, S5P_GPIO_PULL_UP);
+	/*
+	 * Retrieve and apply pin config details
+	 * from fdt for EBI address lines.
+	 */
+	if (pinmux_get_fdt_values(&pingrp))
+		return -1;
 
-		gpio_cfg_pin(GPIO_Y60 + i, S5P_GPIO_FUNC(2));
-		gpio_set_pull(GPIO_Y60 + i, S5P_GPIO_PULL_UP);
-	}
+	pinmux_group_set(&pingrp);
+
+	pingrp.dev_name = "srom-ebi-data-lines";
+
+	/*
+	 * Retrieve and apply pin config details
+	 * from fdt for EBI data lines.
+	 */
+	if (pinmux_get_fdt_values(&pingrp))
+		return -1;
+
+	pinmux_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 (pinmux_get_fdt_values(&pingrp))
+		return -1;
+
+	pinmux_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";
 
-	for (i = 0; i < 5; i++)
-		gpio_cfg_pin(GPIO_B00+i, S5P_GPIO_FUNC(0x02));
+	/*
+	 * Retrieve and apply pin config details
+	 * from fdt for i2s.
+	 */
+	if (pinmux_get_fdt_values(&pingrp))
+		return -1;
+
+	pinmux_group_set(&pingrp);
+
+	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 (pinmux_get_fdt_values(&pingrp))
+		return -1;
+
+	pinmux_group_set(&pingrp);
+
+	return 0;
 }
 
 static int exynos5_pinmux_config(int peripheral, int flags)
@@ -279,7 +473,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 +481,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 +491,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)