diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2013-05-06 09:30:37 +0200 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2013-05-06 09:30:37 +0200 |
commit | 579b794b5d13e4a1ffa21d2426bfab7050eaba9d (patch) | |
tree | fb7aec42846fb17498f1371363f474691fdbf4d4 | |
parent | 646a0d058dd206ee978803aaeb53c886cbc5ad9f (diff) | |
parent | 32dc070fd499a8a0bc4bc434fe74319c7463a97a (diff) | |
download | barebox-579b794b5d13e4a1ffa21d2426bfab7050eaba9d.tar.gz barebox-579b794b5d13e4a1ffa21d2426bfab7050eaba9d.tar.xz |
Merge branch 'for-next/of'
Conflicts:
arch/arm/mach-imx/Makefile
-rw-r--r-- | arch/arm/mach-imx/Kconfig | 9 | ||||
-rw-r--r-- | arch/arm/mach-imx/Makefile | 18 | ||||
-rw-r--r-- | arch/arm/mach-imx/iomux-v3.c | 107 | ||||
-rw-r--r-- | drivers/Kconfig | 1 | ||||
-rw-r--r-- | drivers/Makefile | 1 | ||||
-rw-r--r-- | drivers/base/driver.c | 3 | ||||
-rw-r--r-- | drivers/of/base.c | 133 | ||||
-rw-r--r-- | drivers/of/partition.c | 13 | ||||
-rw-r--r-- | drivers/pinctrl/Kconfig | 28 | ||||
-rw-r--r-- | drivers/pinctrl/Makefile | 4 | ||||
-rw-r--r-- | drivers/pinctrl/imx-iomux-v1.c (renamed from arch/arm/mach-imx/iomux-v1.c) | 0 | ||||
-rw-r--r-- | drivers/pinctrl/imx-iomux-v2.c (renamed from arch/arm/mach-imx/iomux-v2.c) | 0 | ||||
-rw-r--r-- | drivers/pinctrl/imx-iomux-v3.c | 212 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl.c | 149 | ||||
-rw-r--r-- | include/of.h | 10 | ||||
-rw-r--r-- | include/pinctrl.h | 35 |
16 files changed, 575 insertions, 148 deletions
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index eee6acd04e..359b5cd091 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -165,44 +165,53 @@ choice config ARCH_IMX1 bool "i.MX1" select CPU_ARM920T + select PINCTRL_IMX_IOMUX_V1 config ARCH_IMX21 bool "i.MX21" select CPU_ARM926T + select PINCTRL_IMX_IOMUX_V1 config ARCH_IMX25 bool "i.MX25" select CPU_ARM926T select ARCH_HAS_FEC_IMX + select PINCTRL_IMX_IOMUX_V3 config ARCH_IMX27 bool "i.MX27" select CPU_ARM926T select ARCH_HAS_FEC_IMX + select PINCTRL_IMX_IOMUX_V1 config ARCH_IMX31 select CPU_V6 bool "i.MX31" + select PINCTRL_IMX_IOMUX_V2 config ARCH_IMX35 bool "i.MX35" select CPU_V6 select ARCH_HAS_FEC_IMX + select PINCTRL_IMX_IOMUX_V3 config ARCH_IMX51 bool "i.MX51" select CPU_V7 select ARCH_HAS_FEC_IMX + select PINCTRL_IMX_IOMUX_V3 config ARCH_IMX53 bool "i.MX53" select CPU_V7 select ARCH_HAS_FEC_IMX + select PINCTRL_IMX_IOMUX_V3 config ARCH_IMX6 bool "i.MX6" select ARCH_HAS_FEC_IMX select CPU_V7 + select PINCTRL_IMX_IOMUX_V3 endchoice diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index b703ed1dcd..72125e775b 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -1,14 +1,14 @@ obj-y += clocksource.o -obj-$(CONFIG_ARCH_IMX1) += imx1.o iomux-v1.o clk-imx1.o -obj-$(CONFIG_ARCH_IMX25) += imx25.o iomux-v3.o clk-imx25.o -obj-$(CONFIG_ARCH_IMX21) += imx21.o iomux-v1.o clk-imx21.o -obj-$(CONFIG_ARCH_IMX27) += imx27.o iomux-v1.o clk-imx27.o -obj-$(CONFIG_ARCH_IMX31) += imx31.o iomux-v2.o clk-imx31.o -obj-$(CONFIG_ARCH_IMX35) += imx35.o iomux-v3.o clk-imx35.o -obj-$(CONFIG_ARCH_IMX51) += imx51.o iomux-v3.o imx5.o clk-imx5.o -obj-$(CONFIG_ARCH_IMX53) += imx53.o iomux-v3.o imx5.o clk-imx5.o esdctl-v4.o +obj-$(CONFIG_ARCH_IMX1) += imx1.o clk-imx1.o +obj-$(CONFIG_ARCH_IMX25) += imx25.o clk-imx25.o +obj-$(CONFIG_ARCH_IMX21) += imx21.o clk-imx21.o +obj-$(CONFIG_ARCH_IMX27) += imx27.o clk-imx27.o +obj-$(CONFIG_ARCH_IMX31) += imx31.o clk-imx31.o +obj-$(CONFIG_ARCH_IMX35) += imx35.o clk-imx35.o +obj-$(CONFIG_ARCH_IMX51) += imx51.o imx5.o clk-imx5.o +obj-$(CONFIG_ARCH_IMX53) += imx53.o imx5.o clk-imx5.o esdctl-v4.o pbl-$(CONFIG_ARCH_IMX53) += imx53.o imx5.o esdctl-v4.o -obj-$(CONFIG_ARCH_IMX6) += imx6.o iomux-v3.o usb-imx6.o clk-imx6.o +obj-$(CONFIG_ARCH_IMX6) += imx6.o usb-imx6.o clk-imx6.o lwl-$(CONFIG_ARCH_IMX6) += imx6-mmdc.o obj-$(CONFIG_IMX_IIM) += iim.o obj-$(CONFIG_NAND_IMX) += nand.o diff --git a/arch/arm/mach-imx/iomux-v3.c b/arch/arm/mach-imx/iomux-v3.c deleted file mode 100644 index 8a6064da6c..0000000000 --- a/arch/arm/mach-imx/iomux-v3.c +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2004-2006 Freescale Semiconductor, Inc. All Rights Reserved. - * Copyright (C) 2008 by Sascha Hauer <kernel@pengutronix.de> - * Copyright (C) 2009 by Jan Weitzel Phytec Messtechnik GmbH, - * <armlinux@phytec.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ -#include <common.h> -#include <init.h> -#include <io.h> -#include <mach/iomux-v3.h> - -static void __iomem *base; - -/* - * configures a single pad in the iomuxer - */ -int mxc_iomux_v3_setup_pad(iomux_v3_cfg_t pad) -{ - u32 mux_ctrl_ofs = (pad & MUX_CTRL_OFS_MASK) >> MUX_CTRL_OFS_SHIFT; - u32 mux_mode = (pad & MUX_MODE_MASK) >> MUX_MODE_SHIFT; - u32 sel_input_ofs = (pad & MUX_SEL_INPUT_OFS_MASK) >> MUX_SEL_INPUT_OFS_SHIFT; - u32 sel_input = (pad & MUX_SEL_INPUT_MASK) >> MUX_SEL_INPUT_SHIFT; - u32 pad_ctrl_ofs = (pad & MUX_PAD_CTRL_OFS_MASK) >> MUX_PAD_CTRL_OFS_SHIFT; - u32 pad_ctrl = (pad & MUX_PAD_CTRL_MASK) >> MUX_PAD_CTRL_SHIFT; - - if (!base) - return -EINVAL; - - debug("%s: mux 0x%08x -> 0x%04x pad: 0x%08x -> 0x%04x sel_inp: 0x%08x -> 0x%04x\n", - __func__, mux_mode, mux_ctrl_ofs, pad_ctrl, pad_ctrl_ofs, sel_input, - sel_input_ofs); - - if (mux_ctrl_ofs) - __raw_writel(mux_mode, base + mux_ctrl_ofs); - - if (sel_input_ofs) - __raw_writel(sel_input, base + sel_input_ofs); - - if (!(pad_ctrl & NO_PAD_CTRL) && pad_ctrl_ofs) - __raw_writel(pad_ctrl, base + pad_ctrl_ofs); - - return 0; -} -EXPORT_SYMBOL(mxc_iomux_v3_setup_pad); - - -int mxc_iomux_v3_setup_multiple_pads(iomux_v3_cfg_t *pad_list, unsigned count) -{ - iomux_v3_cfg_t *p = pad_list; - int i; - int ret; - - for (i = 0; i < count; i++) { - ret = mxc_iomux_v3_setup_pad(*p); - if (ret) - return ret; - p++; - } - return 0; -} -EXPORT_SYMBOL(mxc_iomux_v3_setup_multiple_pads); - -static int imx_iomux_probe(struct device_d *dev) -{ - base = dev_request_mem_region(dev, 0); - - return 0; -} - -static __maybe_unused struct of_device_id imx_iomux_dt_ids[] = { - { - .compatible = "fsl,imx35-iomux", - }, { - /* sentinel */ - } -}; - -static struct platform_device_id imx_iomux_ids[] = { - { - .name = "imx35-iomux", - }, { - /* sentinel */ - }, -}; - -static struct driver_d imx_iomux_driver = { - .name = "imx-iomuxv3", - .probe = imx_iomux_probe, - .of_compatible = DRV_OF_COMPAT(imx_iomux_dt_ids), - .id_table = imx_iomux_ids, -}; - -static int imx_iomux_init(void) -{ - return platform_driver_register(&imx_iomux_driver); -} -postcore_initcall(imx_iomux_init); diff --git a/drivers/Kconfig b/drivers/Kconfig index b213849af0..3a95e5140d 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -23,5 +23,6 @@ source "drivers/pwm/Kconfig" source "drivers/dma/Kconfig" source "drivers/gpio/Kconfig" source "drivers/w1/Kconfig" +source "drivers/pinctrl/Kconfig" endmenu diff --git a/drivers/Makefile b/drivers/Makefile index 03a10fbf2d..daf821c83c 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -22,3 +22,4 @@ obj-y += watchdog/ obj-y += gpio/ obj-$(CONFIG_OFTREE) += of/ obj-$(CONFIG_W1) += w1/ +obj-y += pinctrl/ diff --git a/drivers/base/driver.c b/drivers/base/driver.c index 487f478d69..edd49b367f 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -31,6 +31,7 @@ #include <fs.h> #include <linux/list.h> #include <complete.h> +#include <pinctrl.h> LIST_HEAD(device_list); EXPORT_SYMBOL(device_list); @@ -79,6 +80,8 @@ int device_probe(struct device_d *dev) { int ret; + pinctrl_select_state_default(dev); + ret = dev->bus->probe(dev); if (ret) { dev_err(dev, "probe failed: %s\n", strerror(-ret)); diff --git a/drivers/of/base.c b/drivers/of/base.c index 1dad8e0660..8383549821 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -579,6 +579,52 @@ int of_property_read_string(struct device_node *np, const char *propname, } EXPORT_SYMBOL_GPL(of_property_read_string); +/** + * of_property_read_string_index - Find and read a string from a multiple + * strings property. + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * @index: index of the string in the list of strings + * @out_string: pointer to null terminated return string, modified only if + * return value is 0. + * + * Search for a property in a device tree node and retrieve a null + * terminated string value (pointer to data, not a copy) in the list of strings + * contained in that property. + * Returns 0 on success, -EINVAL if the property does not exist, -ENODATA if + * property does not have a value, and -EILSEQ if the string is not + * null-terminated within the length of the property data. + * + * The out_string pointer is modified only if a valid string can be decoded. + */ +int of_property_read_string_index(struct device_node *np, const char *propname, + int index, const char **output) +{ + struct property *prop = of_find_property(np, propname); + int i = 0; + size_t l = 0, total = 0; + const char *p; + + if (!prop) + return -EINVAL; + if (!prop->value) + return -ENODATA; + if (strnlen(prop->value, prop->length) >= prop->length) + return -EILSEQ; + + p = prop->value; + + for (i = 0; total < prop->length; total += l, p += l) { + l = strlen(p) + 1; + if (i++ == index) { + *output = p; + return 0; + } + } + return -ENODATA; +} +EXPORT_SYMBOL_GPL(of_property_read_string_index); + struct device_node *of_get_root_node(void) { return root_node; @@ -782,7 +828,7 @@ static struct device_d *add_of_platform_device(struct device_node *node) dev->id = DEVICE_ID_SINGLE; dev->resource = node->resource; - dev->num_resources = 1; + dev->num_resources = node->num_resource; dev->device_node = node; node->device = dev; @@ -869,32 +915,52 @@ int of_add_memory(struct device_node *node, bool dump) static int add_of_device_resource(struct device_node *node) { - struct property *reg; - u64 address, size; - struct resource *res; + u64 address = 0, size; + struct resource *res, *resp; struct device_d *dev; - phandle phandle; - int ret; - - ret = of_property_read_u32(node, "phandle", &phandle); - if (!ret) { - node->phandle = phandle; - list_add_tail(&node->phandles, &phandle_list); - } + const __be32 *endp, *reg; + const char *resname; + int na, nc, n_resources; + int ret, len, index; ret = of_add_memory(node, false); if (ret != -ENXIO) return ret; - reg = of_find_property(node, "reg"); + reg = of_get_property(node, "reg", &len); if (!reg) - return -ENODEV; - - address = of_translate_address(node, reg->value); - if (address == OF_BAD_ADDR) return -EINVAL; - size = be32_to_cpu(((u32 *)reg->value)[1]); + of_bus_count_cells(node, &na, &nc); + + n_resources = (len / sizeof(__be32)) / (na + nc); + + res = resp = xzalloc(sizeof(*res) * n_resources); + + endp = reg + (len / sizeof(__be32)); + + index = 0; + + while ((endp - reg) >= (na + nc)) { + address = of_translate_address(node, reg); + if (address == OF_BAD_ADDR) { + ret = -EINVAL; + goto err_free; + } + + reg += na; + size = dt_mem_next_cell(nc, ®); + + resp->start = address; + resp->end = address + size - 1; + resname = NULL; + of_property_read_string_index(node, "reg-names", index, &resname); + if (resname) + resp->name = xstrdup(resname); + resp->flags = IORESOURCE_MEM; + resp++; + index++; + } /* * A device may already be registered as platform_device. @@ -909,20 +975,22 @@ static int add_of_device_resource(struct device_node *node) node->device = dev; dev->device_node = node; node->resource = dev->resource; - return 0; + ret = 0; + goto err_free; } } - res = xzalloc(sizeof(*res)); - res->start = address; - res->end = address + size - 1; - res->flags = IORESOURCE_MEM; - node->resource = res; + node->num_resource = n_resources; add_of_device(node); return 0; + +err_free: + free(res); + + return ret; } void of_free(struct device_node *node) @@ -975,6 +1043,22 @@ static void __of_probe(struct device_node *node) __of_probe(n); } +static void __of_parse_phandles(struct device_node *node) +{ + struct device_node *n; + phandle phandle; + int ret; + + ret = of_property_read_u32(node, "phandle", &phandle); + if (!ret) { + node->phandle = phandle; + list_add_tail(&node->phandles, &phandle_list); + } + + list_for_each_entry(n, &node->children, parent_list) + __of_parse_phandles(n); +} + struct device_node *of_chosen; const char *of_model; @@ -991,6 +1075,7 @@ int of_probe(void) of_chosen = of_find_node_by_path(root_node, "/chosen"); of_property_read_string(root_node, "model", &of_model); + __of_parse_phandles(root_node); __of_probe(root_node); return 0; diff --git a/drivers/of/partition.c b/drivers/of/partition.c index 6a57a6036e..2d70cf5353 100644 --- a/drivers/of/partition.c +++ b/drivers/of/partition.c @@ -21,9 +21,9 @@ #include <of.h> #include <malloc.h> #include <linux/mtd/mtd.h> +#include <nand.h> -int of_parse_partitions(const char *cdevname, - struct device_node *node) +int of_parse_partitions(struct cdev *cdev, struct device_node *node) { struct device_node *n; const char *partname; @@ -48,14 +48,17 @@ int of_parse_partitions(const char *cdevname, partname = of_get_property(n, "name", &len); name = (char *)partname; - debug("add partition: %s.%s 0x%08lx 0x%08lx\n", cdevname, partname, offset, size); + debug("add partition: %s.%s 0x%08lx 0x%08lx\n", cdev->name, partname, offset, size); if (of_get_property(n, "read-only", &len)) flags = DEVFS_PARTITION_READONLY; - filename = asprintf("%s.%s", cdevname, partname); + filename = asprintf("%s.%s", cdev->name, partname); - devfs_add_partition(cdevname, offset, size, flags, filename); + devfs_add_partition(cdev->name, offset, size, flags, filename); + + if (cdev->mtd && cdev->mtd->type == MTD_NANDFLASH) + dev_add_bb_dev(filename, NULL); free(filename); } diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig new file mode 100644 index 0000000000..e6aee50a5f --- /dev/null +++ b/drivers/pinctrl/Kconfig @@ -0,0 +1,28 @@ +menu "Pin controllers" + +config PINCTRL + bool "Pin controller core support" + depends on OFDEVICE + help + Pincontrollers allow to setup the iomux unit of SoCs. The pin + controller core is needed when pin muxing shall be configured + from the devicetree. Legacy drivers here may not need this core + support but instead provide their own SoC specific APIs + +config PINCTRL_IMX_IOMUX_V1 + bool "i.MX iomux v1" + help + This iomux controller is found on i.MX1,21,27. + +config PINCTRL_IMX_IOMUX_V2 + bool "i.MX iomux v2" + help + This iomux controller is found on i.MX31. + +config PINCTRL_IMX_IOMUX_V3 + select PINCTRL if OFDEVICE + bool "i.MX iomux v3" + help + This iomux controller is found on i.MX25,35,51,53,6. + +endmenu diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile new file mode 100644 index 0000000000..e9272d0fb0 --- /dev/null +++ b/drivers/pinctrl/Makefile @@ -0,0 +1,4 @@ +obj-$(CONFIG_PINCTRL) += pinctrl.o +obj-$(CONFIG_PINCTRL_IMX_IOMUX_V1) += imx-iomux-v1.o +obj-$(CONFIG_PINCTRL_IMX_IOMUX_V2) += imx-iomux-v2.o +obj-$(CONFIG_PINCTRL_IMX_IOMUX_V3) += imx-iomux-v3.o diff --git a/arch/arm/mach-imx/iomux-v1.c b/drivers/pinctrl/imx-iomux-v1.c index f8f90615c6..f8f90615c6 100644 --- a/arch/arm/mach-imx/iomux-v1.c +++ b/drivers/pinctrl/imx-iomux-v1.c diff --git a/arch/arm/mach-imx/iomux-v2.c b/drivers/pinctrl/imx-iomux-v2.c index cef0340909..cef0340909 100644 --- a/arch/arm/mach-imx/iomux-v2.c +++ b/drivers/pinctrl/imx-iomux-v2.c diff --git a/drivers/pinctrl/imx-iomux-v3.c b/drivers/pinctrl/imx-iomux-v3.c new file mode 100644 index 0000000000..3ff3c1571d --- /dev/null +++ b/drivers/pinctrl/imx-iomux-v3.c @@ -0,0 +1,212 @@ +/* + * imx-iomux-v3.c - i.MX iomux-v3 pinctrl support + * + * Copyright (c) 2013 Sascha Hauer <s.hauer@pengutronix.de> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <common.h> +#include <init.h> +#include <io.h> +#include <pinctrl.h> +#include <malloc.h> +#include <mach/iomux-v3.h> + +struct imx_iomux_v3 { + void __iomem *base; + struct pinctrl_device pinctrl; +}; + +static void __iomem *iomuxv3_base; +static struct device_d *iomuxv3_dev; + +static void imx_iomuxv3_setup_single(void __iomem *base, struct device_d *dev, + u32 mux_reg, u32 conf_reg, u32 input_reg, + u32 mux_val, u32 conf_val, u32 input_val) +{ + dev_dbg(dev, + "mux: 0x%08x -> 0x%04x, conf: 0x%08x -> 0x%04x input: 0x%08x -> 0x%04x\n", + mux_val, mux_reg, conf_val, conf_reg, input_val, input_reg); + + if (mux_reg) + writel(mux_val, base + mux_reg); + if (conf_reg) + writel(conf_val, base + conf_reg); + if (input_reg) + writel(input_val, base + input_reg); +} + +/* + * configures a single pad in the iomuxer + */ +int mxc_iomux_v3_setup_pad(iomux_v3_cfg_t pad) +{ + u32 mux_reg = (pad & MUX_CTRL_OFS_MASK) >> MUX_CTRL_OFS_SHIFT; + u32 mux_val = (pad & MUX_MODE_MASK) >> MUX_MODE_SHIFT; + u32 input_reg = (pad & MUX_SEL_INPUT_OFS_MASK) >> MUX_SEL_INPUT_OFS_SHIFT; + u32 input_val = (pad & MUX_SEL_INPUT_MASK) >> MUX_SEL_INPUT_SHIFT; + u32 conf_reg = (pad & MUX_PAD_CTRL_OFS_MASK) >> MUX_PAD_CTRL_OFS_SHIFT; + u32 conf_val = (pad & MUX_PAD_CTRL_MASK) >> MUX_PAD_CTRL_SHIFT; + + if (!iomuxv3_base) + return -EINVAL; + + if (conf_val & NO_PAD_CTRL) + conf_reg = 0; + + imx_iomuxv3_setup_single(iomuxv3_base, iomuxv3_dev, + mux_reg, conf_reg, input_reg, + mux_val, conf_val, input_val); + + return 0; +} +EXPORT_SYMBOL(mxc_iomux_v3_setup_pad); + + +int mxc_iomux_v3_setup_multiple_pads(iomux_v3_cfg_t *pad_list, unsigned count) +{ + iomux_v3_cfg_t *p = pad_list; + int i; + int ret; + + for (i = 0; i < count; i++) { + ret = mxc_iomux_v3_setup_pad(*p); + if (ret) + return ret; + p++; + } + return 0; +} +EXPORT_SYMBOL(mxc_iomux_v3_setup_multiple_pads); + +/* + * Each pin represented in fsl,pins consists of 5 u32 PIN_FUNC_ID and + * 1 u32 CONFIG, so 24 types in total for each pin. + */ +#define FSL_PIN_SIZE 24 + +#define IMX_DT_NO_PAD_CTL (1 << 31) +#define IMX_PAD_SION (1 << 30) + +#define IOMUXC_CONFIG_SION (0x1 << 4) + +static int imx_iomux_v3_set_state(struct pinctrl_device *pdev, struct device_node *np) +{ + struct imx_iomux_v3 *iomux = container_of(pdev, struct imx_iomux_v3, pinctrl); + const __be32 *list; + int npins, size, i; + + dev_dbg(iomux->pinctrl.dev, "set state: %s\n", np->full_name); + + list = of_get_property(np, "fsl,pins", &size); + if (!list) + return -EINVAL; + + + if (!size || size % FSL_PIN_SIZE) { + dev_err(iomux->pinctrl.dev, "Invalid fsl,pins property\n"); + return -EINVAL; + } + + npins = size / FSL_PIN_SIZE; + + for (i = 0; i < npins; i++) { + u32 mux_reg = be32_to_cpu(*list++); + u32 conf_reg = be32_to_cpu(*list++); + u32 input_reg = be32_to_cpu(*list++); + u32 mux_val = be32_to_cpu(*list++); + u32 input_val = be32_to_cpu(*list++); + u32 conf_val = be32_to_cpu(*list++); + + if (conf_val & IMX_PAD_SION) + mux_val |= IOMUXC_CONFIG_SION; + + if (conf_val & IMX_DT_NO_PAD_CTL) + conf_reg = 0; + + imx_iomuxv3_setup_single(iomux->base, iomux->pinctrl.dev, + mux_reg, conf_reg, input_reg, + mux_val, conf_val, input_val); + } + + return 0; +} + +static struct pinctrl_ops imx_iomux_v3_ops = { + .set_state = imx_iomux_v3_set_state, +}; + +static int imx_pinctrl_dt(struct device_d *dev, void __iomem *base) +{ + struct imx_iomux_v3 *iomux; + int ret; + + iomux = xzalloc(sizeof(*iomux)); + + iomux->base = base; + + iomux->pinctrl.dev = dev; + iomux->pinctrl.ops = &imx_iomux_v3_ops; + + ret = pinctrl_register(&iomux->pinctrl); + if (ret) + free(iomux); + + return ret; +} + +static int imx_iomux_v3_probe(struct device_d *dev) +{ + int ret = 0; + + if (iomuxv3_base) + return -EBUSY; + + iomuxv3_base = dev_request_mem_region(dev, 0); + iomuxv3_dev = dev; + + if (IS_ENABLED(CONFIG_PINCTRL)) + ret = imx_pinctrl_dt(dev, iomuxv3_base); + + return ret; +} + +static __maybe_unused struct of_device_id imx_iomux_v3_dt_ids[] = { + { + .compatible = "fsl,imx25-iomuxc", + }, { + .compatible = "fsl,imx35-iomuxc", + }, { + .compatible = "fsl,imx51-iomuxc", + }, { + .compatible = "fsl,imx53-iomuxc", + }, { + .compatible = "fsl,imx6q-iomuxc", + }, { + /* sentinel */ + } +}; + +static struct driver_d imx_iomux_v3_driver = { + .name = "imx-iomuxv3", + .probe = imx_iomux_v3_probe, + .of_compatible = DRV_OF_COMPAT(imx_iomux_v3_dt_ids), +}; + +static int imx_iomux_v3_init(void) +{ + return platform_driver_register(&imx_iomux_v3_driver); +} +postcore_initcall(imx_iomux_v3_init); diff --git a/drivers/pinctrl/pinctrl.c b/drivers/pinctrl/pinctrl.c new file mode 100644 index 0000000000..fa979a1b78 --- /dev/null +++ b/drivers/pinctrl/pinctrl.c @@ -0,0 +1,149 @@ +/* + * pinctrl.c - barebox pinctrl support + * + * Copyright (c) 2013 Sascha Hauer <s.hauer@pengutronix.de> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include <common.h> +#include <malloc.h> +#include <pinctrl.h> + +static LIST_HEAD(pinctrl_list); + +static struct pinctrl_device *find_pinctrl(struct device_node *node) +{ + struct pinctrl_device *pdev; + + list_for_each_entry(pdev, &pinctrl_list, list) + if (pdev->node == node) + return pdev; + return NULL; +} + +static int pinctrl_config_one(struct device_node *np) +{ + struct pinctrl_device *pdev; + struct device_node *pinctrl_node = np; + + while (1) { + pinctrl_node = pinctrl_node->parent; + if (!pinctrl_node) + return -ENODEV; + pdev = find_pinctrl(pinctrl_node); + if (pdev) + break; + } + + return pdev->ops->set_state(pdev, np); +} + +int pinctrl_select_state(struct device_d *dev, const char *name) +{ + int state, ret; + char *propname; + struct property *prop; + const __be32 *list; + int size, config; + phandle phandle; + struct device_node *np_config, *np; + const char *statename; + + np = dev->device_node; + if (!np) + return 0; + + if (!of_find_property(np, "pinctrl-0")) + return 0; + + /* For each defined state ID */ + for (state = 0; ; state++) { + /* Retrieve the pinctrl-* property */ + propname = asprintf("pinctrl-%d", state); + prop = of_find_property(np, propname); + free(propname); + + if (!prop) { + ret = -ENODEV; + break; + } + + size = prop->length; + + list = prop->value; + size /= sizeof(*list); + + /* Determine whether pinctrl-names property names the state */ + ret = of_property_read_string_index(np, "pinctrl-names", + state, &statename); + /* + * If not, statename is just the integer state ID. But rather + * than dynamically allocate it and have to free it later, + * just point part way into the property name for the string. + */ + if (ret < 0) { + /* strlen("pinctrl-") == 8 */ + statename = prop->name + 8; + } + + if (strcmp(name, statename)) + continue; + + /* For every referenced pin configuration node in it */ + for (config = 0; config < size; config++) { + phandle = be32_to_cpup(list++); + + /* Look up the pin configuration node */ + np_config = of_find_node_by_phandle(phandle); + if (!np_config) { + pr_err("prop %s %s index %i invalid phandle\n", + np->full_name, prop->name, config); + ret = -EINVAL; + goto err; + } + + /* Parse the node */ + ret = pinctrl_config_one(np_config); + if (ret < 0) + goto err; + } + + return 0; + } +err: + return ret; +} + +int pinctrl_select_state_default(struct device_d *dev) +{ + return pinctrl_select_state(dev, "default"); +} + +int pinctrl_register(struct pinctrl_device *pdev) +{ + BUG_ON(!pdev->dev->device_node); + + list_add_tail(&pdev->list, &pinctrl_list); + + pdev->node = pdev->dev->device_node; + + pinctrl_select_state_default(pdev->dev); + + return 0; +} + +void pinctrl_unregister(struct pinctrl_device *pdev) +{ + list_del(&pdev->list); +} diff --git a/include/of.h b/include/of.h index 94ccfd8739..4dcf37e140 100644 --- a/include/of.h +++ b/include/of.h @@ -26,6 +26,7 @@ struct device_node { struct list_head parent_list; struct list_head list; struct resource *resource; + int num_resource; struct device_d *device; struct list_head phandles; phandle phandle; @@ -160,6 +161,8 @@ void of_delete_property(struct property *pp); int of_property_read_string(struct device_node *np, const char *propname, const char **out_string); +int of_property_read_string_index(struct device_node *np, const char *propname, + int index, const char **output); int of_set_property(struct device_node *node, const char *p, const void *val, int len, int create); struct device_node *of_create_node(struct device_node *root, const char *path); @@ -167,9 +170,10 @@ struct device_node *of_create_node(struct device_node *root, const char *path); struct device_node *of_get_root_node(void); int of_set_root_node(struct device_node *); +struct cdev; + #ifdef CONFIG_OFTREE -int of_parse_partitions(const char *cdevname, - struct device_node *node); +int of_parse_partitions(struct cdev *cdev, struct device_node *node); int of_alias_get_id(struct device_node *np, const char *stem); int of_device_is_stdout_path(struct device_d *dev); @@ -177,7 +181,7 @@ const char *of_get_model(void); void *of_flatten_dtb(struct device_node *node); int of_add_memory(struct device_node *node, bool dump); #else -static inline int of_parse_partitions(const char *cdevname, +static inline int of_parse_partitions(struct cdev *cdev, struct device_node *node) { return -EINVAL; diff --git a/include/pinctrl.h b/include/pinctrl.h new file mode 100644 index 0000000000..7323f8b2f2 --- /dev/null +++ b/include/pinctrl.h @@ -0,0 +1,35 @@ +#ifndef PINCTRL_H +#define PINCTRL_H + +struct pinctrl_device; + +struct pinctrl_ops { + int (*set_state)(struct pinctrl_device *, struct device_node *); +}; + +struct pinctrl_device { + struct device_d *dev; + struct pinctrl_ops *ops; + struct list_head list; + struct device_node *node; +}; + +int pinctrl_register(struct pinctrl_device *pdev); +void pinctrl_unregister(struct pinctrl_device *pdev); + +#ifdef CONFIG_PINCTRL +int pinctrl_select_state(struct device_d *dev, const char *state); +int pinctrl_select_state_default(struct device_d *dev); +#else +static inline int pinctrl_select_state(struct device_d *dev, const char *state) +{ + return -ENODEV; +} + +static inline int pinctrl_select_state_default(struct device_d *dev) +{ + return -ENODEV; +} +#endif + +#endif /* PINCTRL_H */ |