lists.openwall.net | lists / announce owl-users owl-dev john-users john-dev passwdqc-users yescrypt popa3d-users / oss-security kernel-hardening musl sabotage tlsify passwords / crypt-dev xvendor / Bugtraq Full-Disclosure linux-kernel linux-netdev linux-ext4 linux-hardening linux-cve-announce PHC | |
Open Source and information security mailing list archives
| ||
|
Date: Fri, 18 May 2012 21:12:35 +0800 From: Dong Aisheng <b29396@...escale.com> To: <linux-kernel@...r.kernel.org> CC: <linux-arm-kernel@...ts.infradead.org>, <linus.walleij@...ricsson.com>, <swarren@...dotorg.org> Subject: [PATCH RFC v2 2/2] pinctrl: add pinctrl gpio binding support From: Dong Aisheng <dong.aisheng@...aro.org> The gpio ranges standard dt binding format is <&gpio $gpio_offset $pin_offset $npin> The core will parse and register the pinctrl gpio ranges from device tree. TODO: add binding doc. Signed-off-by: Dong Aisheng <dong.aisheng@...aro.org> --- ChangeLog v1->v2: * introduce standard binding for gpio range. --- drivers/pinctrl/devicetree.c | 95 +++++++++++++++++++++++++++++++++++++++ drivers/pinctrl/devicetree.h | 3 - include/linux/pinctrl/pinctrl.h | 22 +++++++++ 3 files changed, 117 insertions(+), 3 deletions(-) diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c index fcb1de4..c1b87e6 100644 --- a/drivers/pinctrl/devicetree.c +++ b/drivers/pinctrl/devicetree.c @@ -17,7 +17,9 @@ */ #include <linux/device.h> +#include <linux/module.h> #include <linux/of.h> +#include <linux/of_gpio.h> #include <linux/pinctrl/pinctrl.h> #include <linux/slab.h> @@ -247,3 +249,96 @@ err: pinctrl_dt_free_maps(p); return ret; } + +/* + * pinctrl_dt_add_gpio_range() - parse and register GPIO ranges from device tree + * @pctldev: pin controller device to add the range to + * @np: the device node contains the property @propname + * @propname: a list of phandles of gpios and corresponding data. + * The format is: <&gpio0 $gpio_offset $pin_offset $count> + */ +int pinctrl_dt_add_gpio_ranges(struct pinctrl_dev *pctldev, + struct device_node *np, + const char *propname) +{ + struct pinctrl_gpio_range *ranges; + unsigned int gpio_offset, pin_offset, npins; + struct device_node *np_gpio; + struct property *prop; + const __be32 *list; + phandle phandle; + int nranges; + int size; + int i; + + if (!np || !propname) { + dev_err(pctldev->dev, "no device node or gpios propname\n"); + return -EINVAL; + } + + prop = of_find_property(np, propname, &size); + if (!prop) + return -ENODEV; + + list = prop->value; + size /= sizeof(*list); + if (size % 4) { + dev_err(pctldev->dev, "wrong gpio range table format\n"); + return -EINVAL; + } + + nranges = size /4; + ranges = devm_kzalloc(pctldev->dev, nranges * sizeof(*ranges), + GFP_KERNEL); + for (i = 0; i < nranges; i++) { + phandle = be32_to_cpup(list++); + np_gpio = of_find_node_by_phandle(phandle); + if (!np_gpio) { + dev_err(pctldev->dev, + "failed to find gpio node(%s)\n", + np_gpio->name); + return -ENODEV; + } + + ranges[i].gc = of_node_to_gpiochip(np_gpio); + if (!ranges[i].gc) { + dev_err(pctldev->dev, + "can not find gpio chip of node(%s)\n", + np->name); + of_node_put(np_gpio); + return -ENODEV; + } + + gpio_offset = be32_to_cpu(*list++); + pin_offset = be32_to_cpu(*list++); + npins = be32_to_cpu(*list++); + + if (gpio_offset < 0 || + gpio_offset > ranges[i].gc->ngpio || + pin_offset < 0 || npins < 0) { + dev_err(pctldev->dev, + "wrong data in the gpio range table\n"); + of_node_put(np_gpio); + return -ENODEV; + } + + ranges[i].name = dev_name(pctldev->dev); + ranges[i].base = ranges[i].gc->base + gpio_offset; + ranges[i].pin_base = pin_offset; + ranges[i].npins = npins; + of_node_put(np_gpio); + } + + pinctrl_add_gpio_ranges(pctldev, ranges, nranges); + + return 0; +} +EXPORT_SYMBOL_GPL(pinctrl_dt_add_gpio_ranges); + +void pinctrl_dt_remove_gpio_ranges(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *ranges, + unsigned nranges) +{ + pinctrl_remove_gpio_ranges(pctldev, ranges, nranges); +} +EXPORT_SYMBOL_GPL(pinctrl_dt_remove_gpio_ranges); diff --git a/drivers/pinctrl/devicetree.h b/drivers/pinctrl/devicetree.h index 760bc49..9f79657 100644 --- a/drivers/pinctrl/devicetree.h +++ b/drivers/pinctrl/devicetree.h @@ -20,9 +20,7 @@ void pinctrl_dt_free_maps(struct pinctrl *p); int pinctrl_dt_to_map(struct pinctrl *p); - #else - static inline int pinctrl_dt_to_map(struct pinctrl *p) { return 0; @@ -31,5 +29,4 @@ static inline int pinctrl_dt_to_map(struct pinctrl *p) static inline void pinctrl_dt_free_maps(struct pinctrl *p) { } - #endif diff --git a/include/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctrl.h index 6a29965..98d77b4 100644 --- a/include/linux/pinctrl/pinctrl.h +++ b/include/linux/pinctrl/pinctrl.h @@ -141,6 +141,28 @@ extern void pinctrl_remove_gpio_ranges(struct pinctrl_dev *pctldev, unsigned nranges); extern const char *pinctrl_dev_get_name(struct pinctrl_dev *pctldev); extern void *pinctrl_dev_get_drvdata(struct pinctrl_dev *pctldev); + +#ifdef CONFIG_OF +extern int pinctrl_dt_add_gpio_ranges(struct pinctrl_dev *pctldev, + struct device_node *np, + const char *propname); +extern void pinctrl_dt_remove_gpio_ranges(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *ranges, + unsigned nranges); +#else +static inline int pinctrl_dt_add_gpio_ranges(struct pinctrl_dev *pctldev, + struct device_node *np, + const char *propname) +{ + return 0; +} +static void pinctrl_dt_remove_gpio_ranges(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *ranges, + unsigned nranges) +{ +} +#endif /* !CONFIG_OF */ + #else struct pinctrl_dev; -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@...r.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists