[U-Boot] [PATCH v2] Exynos5: Pinmux: Add fdt for pinmux

Akshay Saraswat akshay.s at samsung.com
Mon Feb 18 22:46:55 CET 2013


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: [PATCH 0/3 V2] EXYNOS5: Add GPIO numbering feature
URL: http://lists.denx.de/pipermail/u-boot/2013-January/144681.html

Signed-off-by: Akshay Saraswat <akshay.s at samsung.com>
---
Changes since v1:
	- Device tree bindings changed to linux style.
	- Added documentation for samsung pinctrl.

 arch/arm/cpu/armv7/exynos/pinmux.c           |  445 +++++++++++++----
 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, 1280 insertions(+), 96 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 c79d58e..da59483 100644
--- a/arch/arm/cpu/armv7/exynos/pinmux.c
+++ b/arch/arm/cpu/armv7/exynos/pinmux.c
@@ -23,91 +23,302 @@
 
 #include <common.h>
 #include <fdtdec.h>
+#include <linux/ctype.h>
 #include <asm/arch/gpio.h>
 #include <asm/arch/pinmux.h>
 #include <asm/arch/sromc.h>
 
-static void exynos5_uart_config(int peripheral)
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Struct for storing pin function and gpio related info */
+struct pin_group {
+	void *dev_name;
+	int npins;
+	int function;
+	enum exynos5_gpio_pin gpio[];
+};
+
+static void get_pins(const struct fdt_property *fprop, struct pin_group *pgrp)
+{
+	int i;
+
+	pgrp->npins = 0;
+
+	for (i = 0; !(fprop->data[i] == (int)NULL &&
+				fprop->data[i-1] == (int)NULL); i += 7) {
+		int pin_bank = -1;
+
+		if (strncmp(fprop->data + i, "gpa0", 4) == 0)
+			pin_bank = GPIO_A00;
+		else if (strncmp(fprop->data + i, "gpa1", 4) == 0)
+			pin_bank = GPIO_A10;
+		else if (strncmp(fprop->data + i, "gpa2", 4) == 0)
+			pin_bank = GPIO_A20;
+		else if (strncmp(fprop->data + i, "gpb0", 4) == 0)
+			pin_bank = GPIO_B00;
+		else if (strncmp(fprop->data + i, "gpb1", 4) == 0)
+			pin_bank = GPIO_B10;
+		else if (strncmp(fprop->data + i, "gpb2", 4) == 0)
+			pin_bank = GPIO_B20;
+		else if (strncmp(fprop->data + i, "gpb3", 4) == 0)
+			pin_bank = GPIO_B30;
+		else if (strncmp(fprop->data + i, "gpc0", 4) == 0)
+			pin_bank = GPIO_C00;
+		else if (strncmp(fprop->data + i, "gpc1", 4) == 0)
+			pin_bank = GPIO_C10;
+		else if (strncmp(fprop->data + i, "gpc2", 4) == 0)
+			pin_bank = GPIO_C20;
+		else if (strncmp(fprop->data + i, "gpc3", 4) == 0)
+			pin_bank = GPIO_C30;
+		else if (strncmp(fprop->data + i, "gpd0", 4) == 0)
+			pin_bank = GPIO_D00;
+		else if (strncmp(fprop->data + i, "gpd1", 4) == 0)
+			pin_bank = GPIO_D10;
+		else if (strncmp(fprop->data + i, "gpy0", 4) == 0)
+			pin_bank = GPIO_Y00;
+		else if (strncmp(fprop->data + i, "gpy1", 4) == 0)
+			pin_bank = GPIO_Y10;
+		else if (strncmp(fprop->data + i, "gpy2", 4) == 0)
+			pin_bank = GPIO_Y20;
+		else if (strncmp(fprop->data + i, "gpy3", 4) == 0)
+			pin_bank = GPIO_Y30;
+		else if (strncmp(fprop->data + i, "gpy4", 4) == 0)
+			pin_bank = GPIO_Y40;
+		else if (strncmp(fprop->data + i, "gpy5", 4) == 0)
+			pin_bank = GPIO_Y50;
+		else if (strncmp(fprop->data + i, "gpy6", 4) == 0)
+			pin_bank = GPIO_Y60;
+		else if (strncmp(fprop->data + i, "gpc4", 4) == 0)
+			pin_bank = GPIO_C40;
+		else if (strncmp(fprop->data + i, "gpx0", 4) == 0)
+			pin_bank = GPIO_X00;
+		else if (strncmp(fprop->data + i, "gpx1", 4) == 0)
+			pin_bank = GPIO_X10;
+		else if (strncmp(fprop->data + i, "gpx2", 4) == 0)
+			pin_bank = GPIO_X20;
+		else if (strncmp(fprop->data + i, "gpx3", 4) == 0)
+			pin_bank = GPIO_X30;
+		else if (strncmp(fprop->data + i, "gpe0", 4) == 0)
+			pin_bank = GPIO_E00;
+		else if (strncmp(fprop->data + i, "gpe1", 4) == 0)
+			pin_bank = GPIO_E10;
+		else if (strncmp(fprop->data + i, "gpf0", 4) == 0)
+			pin_bank = GPIO_F10;
+		else if (strncmp(fprop->data + i, "gpf1", 4) == 0)
+			pin_bank = GPIO_F10;
+		else if (strncmp(fprop->data + i, "gpg0", 4) == 0)
+			pin_bank = GPIO_G00;
+		else if (strncmp(fprop->data + i, "gpg1", 4) == 0)
+			pin_bank = GPIO_G10;
+		else if (strncmp(fprop->data + i, "gpg2", 4) == 0)
+			pin_bank = GPIO_G20;
+		else if (strncmp(fprop->data + i, "gph0", 4) == 0)
+			pin_bank = GPIO_H00;
+		else if (strncmp(fprop->data + i, "gph1", 4) == 0)
+			pin_bank = GPIO_H10;
+		else if (strncmp(fprop->data + i, "gpv0", 4) == 0)
+			pin_bank = GPIO_V00;
+		else if (strncmp(fprop->data + i, "gpv1", 4) == 0)
+			pin_bank = GPIO_V10;
+		else if (strncmp(fprop->data + i, "gpv2", 4) == 0)
+			pin_bank = GPIO_V20;
+		else if (strncmp(fprop->data + i, "gpv3", 4) == 0)
+			pin_bank = GPIO_V30;
+		else if (strncmp(fprop->data + i, "gpv4", 4) == 0)
+			pin_bank = GPIO_V40;
+		else if (strncmp(fprop->data + i, "gpz", 4) == 0)
+			pin_bank = GPIO_Z0;
+
+		if (pin_bank >= 0 && isdigit(fprop->data[i+5])) {
+			pgrp->gpio[pgrp->npins] =
+					pin_bank + (fprop->data[i+5] - '0');
+			pgrp->npins++;
+		}
+	}
+}
+
+static int get_fdt_values(struct pin_group *pgrp)
+{
+	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, pgrp->dev_name);
+		if (subnode < 0)
+			continue;
+
+		fprop = fdt_get_property(gd->fdt_blob,
+					subnode, "samsung,pins", NULL);
+		pgrp->function = fdtdec_get_int(gd->fdt_blob,
+					subnode, "samsung,pin-function", -1);
+		get_pins(fprop, pgrp);
+
+		return 0;
+	}
+
+	printf("PINCTRL: No subnode for %s", (char *)pgrp->dev_name);
+
+	return -1;
+}
+
+static int exynos5_uart_config(int peripheral)
 {
-	int i, start, count;
+	int i;
+	char *data, *fctl = NULL;
+	struct pin_group pgrp;
 
 	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, GPIO_PULL_NONE);
-		gpio_cfg_pin(i, GPIO_FUNC(0x2));
+
+	pgrp.dev_name = data;
+
+	/* Retrieve gpio pins for this UART's data line */
+	if (get_fdt_values(&pgrp))
+		return -1;
+
+	/* Apply pin configurations */
+	for (i = 0; i < pgrp.npins; i++) {
+		gpio_set_pull(pgrp.gpio[i], GPIO_PULL_NONE);
+		gpio_cfg_pin(pgrp.gpio[i], GPIO_FUNC(pgrp.function));
 	}
+
+	if (peripheral != PERIPH_ID_UART3) {
+		pgrp.dev_name = fctl;
+
+		/* Retrieve gpio pins for this UART's data line */
+		if (get_fdt_values(&pgrp))
+			return -1;
+
+		/* Apply pin configurations */
+		for (i = 0; i < pgrp.npins; i++) {
+			gpio_set_pull(pgrp.gpio[i], GPIO_PULL_NONE);
+			gpio_cfg_pin(pgrp.gpio[i], GPIO_FUNC(pgrp.function));
+		}
+	}
+
+	return 0;
 }
 
 static int exynos5_mmc_config(int peripheral, int flags)
 {
-	int i, start, start_ext, gpio_func = 0;
+	int i;
+	char *clk, *cmd, *width4, *width8 = NULL;
+	struct pin_group pgrp;
 
 	switch (peripheral) {
 	case PERIPH_ID_SDMMC0:
-		start = GPIO_C00;
-		start_ext = GPIO_C10;
-		gpio_func = GPIO_FUNC(0x2);
+		clk = "sd0-clk";
+		cmd = "sd0-cmd";
+		width4 = "sd0-bus-width4";
+		width8 = "sd0-bus-width8";
 		break;
 	case PERIPH_ID_SDMMC1:
-		start = GPIO_C20;
-		start_ext = 0;
+		clk = "sd1-clk";
+		cmd = "sd1-cmd";
+		width4 = "sd1-bus-width4";
 		break;
 	case PERIPH_ID_SDMMC2:
-		start = GPIO_C30;
-		start_ext = GPIO_C43;
-		gpio_func = GPIO_FUNC(0x3);
+		clk = "sd2-clk";
+		cmd = "sd2-cmd";
+		width4 = "sd2-bus-width4";
+		width8 = "sd2-bus-width8";
 		break;
 	case PERIPH_ID_SDMMC3:
-		start = GPIO_C40;
-		start_ext = 0;
+		clk = "sd3-clk";
+		cmd = "sd3-cmd";
+		width4 = "sd3-bus-width4";
 		break;
 	}
-	if ((flags & PINMUX_FLAG_8BIT_MODE) && !start_ext) {
+
+	/* Apply pin configurations */
+	if ((flags & PINMUX_FLAG_8BIT_MODE) && width8 == NULL) {
 		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, GPIO_PULL_UP);
-			gpio_set_drv(i, GPIO_DRV_4X);
+		pgrp.dev_name = width8;
+
+		/* Retrieve gpio range and base for this SDMMC */
+		if (get_fdt_values(&pgrp))
+			return -1;
+
+		for (i = 0; i < pgrp.npins; i++) {
+			gpio_cfg_pin(pgrp.gpio[i], GPIO_FUNC(pgrp.function));
+			gpio_set_pull(pgrp.gpio[i], GPIO_PULL_UP);
+			gpio_set_drv(pgrp.gpio[i], GPIO_DRV_4X);
 		}
 	}
-	for (i = 0; i < 2; i++) {
-		gpio_cfg_pin(start + i, GPIO_FUNC(0x2));
-		gpio_set_pull(start + i, GPIO_PULL_NONE);
-		gpio_set_drv(start + i, GPIO_DRV_4X);
+
+	pgrp.dev_name = clk;
+
+	/* Retrieve gpio range and base for this SDMMC */
+	if (get_fdt_values(&pgrp))
+		return -1;
+
+	for (i = 0; i < pgrp.npins; i++) {
+		gpio_cfg_pin(pgrp.gpio[i], GPIO_FUNC(pgrp.function));
+		gpio_set_pull(pgrp.gpio[i], GPIO_PULL_NONE);
+		gpio_set_drv(pgrp.gpio[i], GPIO_DRV_4X);
 	}
-	for (i = 3; i <= 6; i++) {
-		gpio_cfg_pin(start + i, GPIO_FUNC(0x2));
-		gpio_set_pull(start + i, GPIO_PULL_UP);
-		gpio_set_drv(start + i, GPIO_DRV_4X);
+
+	pgrp.dev_name = cmd;
+
+	/* Retrieve gpio range and base for this SDMMC */
+	if (get_fdt_values(&pgrp))
+		return -1;
+
+	for (i = 0; i < pgrp.npins; i++) {
+		gpio_cfg_pin(pgrp.gpio[i], GPIO_FUNC(pgrp.function));
+		gpio_set_pull(pgrp.gpio[i], GPIO_PULL_NONE);
+		gpio_set_drv(pgrp.gpio[i], GPIO_DRV_4X);
+	}
+
+	pgrp.dev_name = width4;
+
+	/* Retrieve gpio range and base for this SDMMC */
+	if (get_fdt_values(&pgrp))
+		return -1;
+
+	for (i = 0; i < pgrp.npins ; i++) {
+		gpio_cfg_pin(pgrp.gpio[i], GPIO_FUNC(pgrp.function));
+		gpio_set_pull(pgrp.gpio[i], GPIO_PULL_UP);
+		gpio_set_drv(pgrp.gpio[i], GPIO_DRV_4X);
 	}
 
 	return 0;
 }
 
-static void exynos5_sromc_config(int flags)
+static int exynos5_sromc_config(int flags)
 {
 	int i;
+	static struct pin_group pgrp;
 
 	/*
 	 * SROM:CS1 and EBI
@@ -124,13 +335,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),
-				GPIO_FUNC(2));
-	gpio_cfg_pin(GPIO_Y04, GPIO_FUNC(2));
-	gpio_cfg_pin(GPIO_Y05, GPIO_FUNC(2));
+	pgrp.dev_name = "srom-cs1";
+
+	/* Retrieve gpio range and base for SROM CS1 */
+	if (get_fdt_values(&pgrp))
+		return -1;
+
+	/* Apply pin configurations */
+	gpio_cfg_pin(pgrp.gpio[0] + (flags & PINMUX_FLAG_BANK),
+						GPIO_FUNC(pgrp.function));
+
+	for (i = 1; i < pgrp.npins; i++)
+		gpio_cfg_pin(pgrp.gpio[i], GPIO_FUNC(pgrp.function));
 
-	for (i = 0; i < 4; i++)
-		gpio_cfg_pin(GPIO_Y10 + i, GPIO_FUNC(2));
+	pgrp.dev_name = "srom-ebi-enable";
+
+	/* Retrieve gpio range and base for SROM EBI */
+	if (get_fdt_values(&pgrp))
+		return -1;
+
+	/* Apply pin configurations */
+	for (i = 0; i < pgrp.npins; i++)
+		gpio_cfg_pin(pgrp.gpio[i], GPIO_FUNC(pgrp.function));
 
 	/*
 	 * EBI: 8 Addrss Lines
@@ -164,97 +390,126 @@ 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, GPIO_FUNC(2));
-		gpio_set_pull(GPIO_Y30 + i, GPIO_PULL_UP);
+	pgrp.dev_name = "srom-ebi-addr-lines";
 
-		gpio_cfg_pin(GPIO_Y50 + i, GPIO_FUNC(2));
-		gpio_set_pull(GPIO_Y50 + i, GPIO_PULL_UP);
+	/* Retrieve gpio range and base for SROM EBI address lines */
+	if (get_fdt_values(&pgrp))
+		return -1;
 
-		gpio_cfg_pin(GPIO_Y60 + i, GPIO_FUNC(2));
-		gpio_set_pull(GPIO_Y60 + i, GPIO_PULL_UP);
+	/* Apply pin configurations */
+	for (i = 0; i < pgrp.npins; i++) {
+		gpio_cfg_pin(pgrp.gpio[i], GPIO_FUNC(pgrp.function));
+		gpio_set_pull(pgrp.gpio[i], GPIO_PULL_UP);
 	}
+
+	pgrp.dev_name = "srom-ebi-data-lines";
+
+	/* Retrieve gpio range and base for SROM EBI data lines */
+	if (get_fdt_values(&pgrp))
+		return -1;
+
+	/* Apply pin configurations */
+	for (i = 0; i < pgrp.npins; i++) {
+		gpio_cfg_pin(pgrp.gpio[i], GPIO_FUNC(pgrp.function));
+		gpio_set_pull(pgrp.gpio[i], GPIO_PULL_UP);
+	}
+
+	return 0;
 }
 
-static void exynos5_i2c_config(int peripheral, int flags)
+static int exynos5_i2c_config(int peripheral, int flags)
 {
+	int i;
+	struct pin_group pgrp;
 
 	switch (peripheral) {
 	case PERIPH_ID_I2C0:
-		gpio_cfg_pin(GPIO_B30, GPIO_FUNC(0x2));
-		gpio_cfg_pin(GPIO_B31, GPIO_FUNC(0x2));
+		pgrp.dev_name = "i2c0-bus";
 		break;
 	case PERIPH_ID_I2C1:
-		gpio_cfg_pin(GPIO_B32, GPIO_FUNC(0x2));
-		gpio_cfg_pin(GPIO_B33, GPIO_FUNC(0x2));
+		pgrp.dev_name = "i2c1-bus";
 		break;
 	case PERIPH_ID_I2C2:
-		gpio_cfg_pin(GPIO_A06, GPIO_FUNC(0x3));
-		gpio_cfg_pin(GPIO_A07, GPIO_FUNC(0x3));
+		pgrp.dev_name = "i2c2-bus";
 		break;
 	case PERIPH_ID_I2C3:
-		gpio_cfg_pin(GPIO_A12, GPIO_FUNC(0x3));
-		gpio_cfg_pin(GPIO_A13, GPIO_FUNC(0x3));
+		pgrp.dev_name = "i2c3-bus";
 		break;
 	case PERIPH_ID_I2C4:
-		gpio_cfg_pin(GPIO_A20, GPIO_FUNC(0x3));
-		gpio_cfg_pin(GPIO_A21, GPIO_FUNC(0x3));
+		pgrp.dev_name = "i2c4-bus";
 		break;
 	case PERIPH_ID_I2C5:
-		gpio_cfg_pin(GPIO_A22, GPIO_FUNC(0x3));
-		gpio_cfg_pin(GPIO_A23, GPIO_FUNC(0x3));
+		pgrp.dev_name = "i2c5-bus";
 		break;
 	case PERIPH_ID_I2C6:
-		gpio_cfg_pin(GPIO_B13, GPIO_FUNC(0x4));
-		gpio_cfg_pin(GPIO_B14, GPIO_FUNC(0x4));
+		pgrp.dev_name = "i2c6-bus";
 		break;
 	case PERIPH_ID_I2C7:
-		gpio_cfg_pin(GPIO_B22, GPIO_FUNC(0x3));
-		gpio_cfg_pin(GPIO_B23, GPIO_FUNC(0x3));
+		pgrp.dev_name = "i2c7-bus";
 		break;
 	}
+
+	/* Retrieve gpio range and base for this I2C */
+	if (get_fdt_values(&pgrp))
+		return -1;
+
+	/* Apply pin configurations */
+	for (i = 0; i < pgrp.npins; i++)
+		gpio_cfg_pin(pgrp.gpio[i], GPIO_FUNC(pgrp.function));
+
+	return 0;
 }
 
-static void exynos5_i2s_config(int peripheral)
+static int exynos5_i2s_config(int peripheral)
 {
 	int i;
+	struct pin_group pgrp;
 
-	for (i = 0; i < 5; i++)
-		gpio_cfg_pin(GPIO_B00+i, GPIO_FUNC(0x02));
+	pgrp.dev_name = "i2s";
+
+	/* Retrieve gpio range and base for I2S */
+	if (get_fdt_values(&pgrp))
+		return -1;
+
+	/* Apply pin configurations */
+	for (i = 0; i < pgrp.npins; i++)
+		gpio_cfg_pin(pgrp.gpio[i], GPIO_FUNC(pgrp.function));
+
+	return 0;
 }
 
-void exynos5_spi_config(int peripheral)
+int exynos5_spi_config(int peripheral)
 {
-	int cfg = 0, pin = 0, i;
+	int i;
+	static struct pin_group pgrp;
 
 	switch (peripheral) {
 	case PERIPH_ID_SPI0:
-		cfg = GPIO_FUNC(0x2);
-		pin = GPIO_A20;
+		pgrp.dev_name = "spi0-bus";
 		break;
 	case PERIPH_ID_SPI1:
-		cfg = GPIO_FUNC(0x2);
-		pin = GPIO_A24;
+		pgrp.dev_name = "spi1-bus";
 		break;
 	case PERIPH_ID_SPI2:
-		cfg = GPIO_FUNC(0x5);
-		pin = GPIO_B11;
+		pgrp.dev_name = "spi2-bus";
 		break;
 	case PERIPH_ID_SPI3:
-		cfg = GPIO_FUNC(0x2);
-		pin = GPIO_F10;
+		pgrp.dev_name = "spi3-bus";
 		break;
 	case PERIPH_ID_SPI4:
-		for (i = 0; i < 2; i++) {
-			gpio_cfg_pin(GPIO_F02 + i, GPIO_FUNC(0x4));
-			gpio_cfg_pin(GPIO_E04 + i, GPIO_FUNC(0x4));
-		}
+		pgrp.dev_name = "spi4-bus";
 		break;
 	}
-	if (peripheral != PERIPH_ID_SPI4) {
-		for (i = pin; i < pin + 4; i++)
-			gpio_cfg_pin(i, cfg);
-	}
+
+	/* Retrieve gpio range and base for this SPI */
+	if (get_fdt_values(&pgrp))
+		return -1;
+
+	/* Apply pin configurations */
+	for (i = 0; i < pgrp.npins; i++)
+		gpio_cfg_pin(pgrp.gpio[i], GPIO_FUNC(pgrp.function));
+
+	return 0;
 }
 
 static int exynos5_pinmux_config(int peripheral, int flags)
@@ -264,7 +519,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:
@@ -272,7 +527,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:
@@ -282,24 +537,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..a250d7b
--- /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 at 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 = <3>;
+			samsung,pin-drv = <3>;
+		};
+
+		srom_ebi: srom-ebi-enable {
+			samsung,pins = "gpy1-0", "gpy1-1", "gpy1-2", "gpy1-3";
+			samsung,pin-function = <2>;
+			samsung,pin-pud = <3>;
+			samsung,pin-drv = <3>;
+		};
+
+		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 = <3>;
+		};
+
+		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 = <3>;
+		};
+
+		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 at 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 at 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 at 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 at 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 at 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 at 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 at 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



More information about the U-Boot mailing list