
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