From 6974f1f458b083a84778641c6a4665799d6156da Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Thu, 5 Apr 2012 17:07:23 +0800 Subject: pinctrl: fix compile error if not select PINMUX support The pinctrl_register_mappings is defined in core.c, so change the dependent macro from CONFIG_MUX to CONFIG_PINCTRL. The compile error message is: drivers/pinctrl/core.c:886: error: redefinition of 'pinctrl_register_mappings' include/linux/pinctrl/machine.h:160: note: previous definition of 'pinctrl_register_mappings' was here make[2]: *** [drivers/pinctrl/core.o] Error 1 make[1]: *** [drivers/pinctrl] Error 2 make: *** [drivers] Error 2 Acked-by: Stephen Warren Signed-off-by: Dong Aisheng Signed-off-by: Linus Walleij diff --git a/include/linux/pinctrl/machine.h b/include/linux/pinctrl/machine.h index fee4349..d32eb8c 100644 --- a/include/linux/pinctrl/machine.h +++ b/include/linux/pinctrl/machine.h @@ -148,7 +148,7 @@ struct pinctrl_map { #define PIN_MAP_CONFIGS_GROUP_HOG_DEFAULT(dev, grp, cfgs) \ PIN_MAP_CONFIGS_GROUP(dev, PINCTRL_STATE_DEFAULT, dev, grp, cfgs) -#ifdef CONFIG_PINMUX +#ifdef CONFIG_PINCTRL extern int pinctrl_register_mappings(struct pinctrl_map const *map, unsigned num_maps); -- cgit v0.10.2 From 22f099d0fcb33073a1f1f10402a16b28602e20f2 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Fri, 16 Mar 2012 14:54:23 -0600 Subject: pinctrl: include to prevent compile errors Macros in call ARRAY_SIZE(), the definition of which eventually calls BUILD_BUG_ON_ZERO(), which is defined in . Include that so that every .c file using the pinctrl macros doesn't have to do that itself. Signed-off-by: Stephen Warren Signed-off-by: Linus Walleij diff --git a/include/linux/pinctrl/machine.h b/include/linux/pinctrl/machine.h index d32eb8c..e4d1de7 100644 --- a/include/linux/pinctrl/machine.h +++ b/include/linux/pinctrl/machine.h @@ -12,6 +12,8 @@ #ifndef __LINUX_PINCTRL_MACHINE_H #define __LINUX_PINCTRL_MACHINE_H +#include + #include "pinctrl-state.h" enum pinctrl_map_type { -- cgit v0.10.2 From d26bc49fa401be2b71838b6a4b387196cd12a534 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Fri, 16 Mar 2012 14:54:25 -0600 Subject: pinctrl: implement pinctrl_check_ops Most code assumes that the pinctrl ops are present. Validate this when registering a pinctrl driver. Remove the one place in the code that was checking whether one of these non-optional ops was present. Signed-off-by: Stephen Warren Signed-off-by: Linus Walleij diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index ec3b8cc..df6296c 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -908,10 +908,6 @@ static int pinctrl_groups_show(struct seq_file *s, void *what) const struct pinctrl_ops *ops = pctldev->desc->pctlops; unsigned selector = 0; - /* No grouping */ - if (!ops) - return 0; - mutex_lock(&pinctrl_mutex); seq_puts(s, "registered pin groups:\n"); @@ -1225,6 +1221,19 @@ static void pinctrl_remove_device_debugfs(struct pinctrl_dev *pctldev) #endif +static int pinctrl_check_ops(struct pinctrl_dev *pctldev) +{ + const struct pinctrl_ops *ops = pctldev->desc->pctlops; + + if (!ops || + !ops->list_groups || + !ops->get_group_name || + !ops->get_group_pins) + return -EINVAL; + + return 0; +} + /** * pinctrl_register() - register a pin controller device * @pctldesc: descriptor for this pin controller @@ -1256,6 +1265,14 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc, INIT_LIST_HEAD(&pctldev->gpio_ranges); pctldev->dev = dev; + /* check core ops for sanity */ + ret = pinctrl_check_ops(pctldev); + if (ret) { + pr_err("%s pinctrl ops lacks necessary functions\n", + pctldesc->name); + goto out_err; + } + /* If we're implementing pinmuxing, check the ops for sanity */ if (pctldesc->pmxops) { ret = pinmux_check_ops(pctldev); -- cgit v0.10.2 From 57291ce295c0aca738dd284c4a9c591c09ebee71 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Fri, 23 Mar 2012 10:29:46 -0600 Subject: pinctrl: core device tree mapping table parsing support During pinctrl_get(), if the client device has a device tree node, look for the common pinctrl properties there. If found, parse the referenced device tree nodes, with the help of the pinctrl drivers, and generate mapping table entries from them. During pinctrl_put(), free any results of device tree parsing. Acked-by: Dong Aisheng Signed-off-by: Stephen Warren Signed-off-by: Linus Walleij diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 6d4150b..049c9fb 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -5,6 +5,7 @@ ccflags-$(CONFIG_DEBUG_PINCTRL) += -DDEBUG obj-$(CONFIG_PINCTRL) += core.o obj-$(CONFIG_PINMUX) += pinmux.o obj-$(CONFIG_PINCONF) += pinconf.o +obj-$(CONFIG_OF) += devicetree.o obj-$(CONFIG_GENERIC_PINCONF) += pinconf-generic.o obj-$(CONFIG_PINCTRL_PXA3xx) += pinctrl-pxa3xx.o obj-$(CONFIG_PINCTRL_MMP2) += pinctrl-mmp2.o diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index df6296c..832f71d 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -26,6 +26,7 @@ #include #include #include "core.h" +#include "devicetree.h" #include "pinmux.h" #include "pinconf.h" @@ -45,7 +46,7 @@ struct pinctrl_maps { DEFINE_MUTEX(pinctrl_mutex); /* Global list of pin control devices (struct pinctrl_dev) */ -static LIST_HEAD(pinctrldev_list); +LIST_HEAD(pinctrldev_list); /* List of pin controller handles (struct pinctrl) */ static LIST_HEAD(pinctrl_list); @@ -579,6 +580,13 @@ static struct pinctrl *create_pinctrl(struct device *dev) } p->dev = dev; INIT_LIST_HEAD(&p->states); + INIT_LIST_HEAD(&p->dt_maps); + + ret = pinctrl_dt_to_map(p); + if (ret < 0) { + kfree(p); + return ERR_PTR(ret); + } devname = dev_name(dev); @@ -662,6 +670,8 @@ static void pinctrl_put_locked(struct pinctrl *p, bool inlist) kfree(state); } + pinctrl_dt_free_maps(p); + if (inlist) list_del(&p->node); kfree(p); @@ -787,15 +797,8 @@ int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state) } EXPORT_SYMBOL_GPL(pinctrl_select_state); -/** - * pinctrl_register_mappings() - register a set of pin controller mappings - * @maps: the pincontrol mappings table to register. This should probably be - * marked with __initdata so it can be discarded after boot. This - * function will perform a shallow copy for the mapping entries. - * @num_maps: the number of maps in the mapping table - */ -int pinctrl_register_mappings(struct pinctrl_map const *maps, - unsigned num_maps) +int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps, + bool dup, bool locked) { int i, ret; struct pinctrl_maps *maps_node; @@ -851,20 +854,52 @@ int pinctrl_register_mappings(struct pinctrl_map const *maps, } maps_node->num_maps = num_maps; - maps_node->maps = kmemdup(maps, sizeof(*maps) * num_maps, GFP_KERNEL); - if (!maps_node->maps) { - pr_err("failed to duplicate mapping table\n"); - kfree(maps_node); - return -ENOMEM; + if (dup) { + maps_node->maps = kmemdup(maps, sizeof(*maps) * num_maps, + GFP_KERNEL); + if (!maps_node->maps) { + pr_err("failed to duplicate mapping table\n"); + kfree(maps_node); + return -ENOMEM; + } + } else { + maps_node->maps = maps; } - mutex_lock(&pinctrl_mutex); + if (!locked) + mutex_lock(&pinctrl_mutex); list_add_tail(&maps_node->node, &pinctrl_maps); - mutex_unlock(&pinctrl_mutex); + if (!locked) + mutex_unlock(&pinctrl_mutex); return 0; } +/** + * pinctrl_register_mappings() - register a set of pin controller mappings + * @maps: the pincontrol mappings table to register. This should probably be + * marked with __initdata so it can be discarded after boot. This + * function will perform a shallow copy for the mapping entries. + * @num_maps: the number of maps in the mapping table + */ +int pinctrl_register_mappings(struct pinctrl_map const *maps, + unsigned num_maps) +{ + return pinctrl_register_map(maps, num_maps, true, false); +} + +void pinctrl_unregister_map(struct pinctrl_map const *map) +{ + struct pinctrl_maps *maps_node; + + list_for_each_entry(maps_node, &pinctrl_maps, node) { + if (maps_node->maps == map) { + list_del(&maps_node->node); + return; + } + } +} + #ifdef CONFIG_DEBUG_FS static int pinctrl_pins_show(struct seq_file *s, void *what) @@ -1231,6 +1266,9 @@ static int pinctrl_check_ops(struct pinctrl_dev *pctldev) !ops->get_group_pins) return -EINVAL; + if (ops->dt_node_to_map && !ops->dt_free_map) + return -EINVAL; + return 0; } diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h index 17ecf65..98ae808 100644 --- a/drivers/pinctrl/core.h +++ b/drivers/pinctrl/core.h @@ -52,12 +52,15 @@ struct pinctrl_dev { * @dev: the device using this pin control handle * @states: a list of states for this device * @state: the current state + * @dt_maps: the mapping table chunks dynamically parsed from device tree for + * this device, if any */ struct pinctrl { struct list_head node; struct device *dev; struct list_head states; struct pinctrl_state *state; + struct list_head dt_maps; }; /** @@ -100,7 +103,8 @@ struct pinctrl_setting_configs { * struct pinctrl_setting - an individual mux or config setting * @node: list node for struct pinctrl_settings's @settings field * @type: the type of setting - * @pctldev: pin control device handling to be programmed + * @pctldev: pin control device handling to be programmed. Not used for + * PIN_MAP_TYPE_DUMMY_STATE. * @data: Data specific to the setting type */ struct pinctrl_setting { @@ -153,4 +157,9 @@ static inline struct pin_desc *pin_desc_get(struct pinctrl_dev *pctldev, return radix_tree_lookup(&pctldev->pin_desc_tree, pin); } +int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps, + bool dup, bool locked); +void pinctrl_unregister_map(struct pinctrl_map const *map); + extern struct mutex pinctrl_mutex; +extern struct list_head pinctrldev_list; diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c new file mode 100644 index 0000000..5ef2feb --- /dev/null +++ b/drivers/pinctrl/devicetree.c @@ -0,0 +1,249 @@ +/* + * Device tree integration for the pin control subsystem + * + * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include + +#include "core.h" +#include "devicetree.h" + +/** + * struct pinctrl_dt_map - mapping table chunk parsed from device tree + * @node: list node for struct pinctrl's @dt_maps field + * @pctldev: the pin controller that allocated this struct, and will free it + * @maps: the mapping table entries + */ +struct pinctrl_dt_map { + struct list_head node; + struct pinctrl_dev *pctldev; + struct pinctrl_map *map; + unsigned num_maps; +}; + +static void dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, unsigned num_maps) +{ + if (pctldev) { + struct pinctrl_ops *ops = pctldev->desc->pctlops; + ops->dt_free_map(pctldev, map, num_maps); + } else { + /* There is no pctldev for PIN_MAP_TYPE_DUMMY_STATE */ + kfree(map); + } +} + +void pinctrl_dt_free_maps(struct pinctrl *p) +{ + struct pinctrl_dt_map *dt_map, *n1; + + list_for_each_entry_safe(dt_map, n1, &p->dt_maps, node) { + pinctrl_unregister_map(dt_map->map); + list_del(&dt_map->node); + dt_free_map(dt_map->pctldev, dt_map->map, + dt_map->num_maps); + kfree(dt_map); + } + + of_node_put(p->dev->of_node); +} + +static int dt_remember_or_free_map(struct pinctrl *p, const char *statename, + struct pinctrl_dev *pctldev, + struct pinctrl_map *map, unsigned num_maps) +{ + int i; + struct pinctrl_dt_map *dt_map; + + /* Initialize common mapping table entry fields */ + for (i = 0; i < num_maps; i++) { + map[i].dev_name = dev_name(p->dev); + map[i].name = statename; + if (pctldev) + map[i].ctrl_dev_name = dev_name(pctldev->dev); + } + + /* Remember the converted mapping table entries */ + dt_map = kzalloc(sizeof(*dt_map), GFP_KERNEL); + if (!dt_map) { + dev_err(p->dev, "failed to alloc struct pinctrl_dt_map\n"); + dt_free_map(pctldev, map, num_maps); + return -ENOMEM; + } + + dt_map->pctldev = pctldev; + dt_map->map = map; + dt_map->num_maps = num_maps; + list_add_tail(&dt_map->node, &p->dt_maps); + + return pinctrl_register_map(map, num_maps, false, true); +} + +static struct pinctrl_dev *find_pinctrl_by_of_node(struct device_node *np) +{ + struct pinctrl_dev *pctldev; + + list_for_each_entry(pctldev, &pinctrldev_list, node) + if (pctldev->dev->of_node == np) + return pctldev; + + return NULL; +} + +static int dt_to_map_one_config(struct pinctrl *p, const char *statename, + struct device_node *np_config) +{ + struct device_node *np_pctldev; + struct pinctrl_dev *pctldev; + struct pinctrl_ops *ops; + int ret; + struct pinctrl_map *map; + unsigned num_maps; + + /* Find the pin controller containing np_config */ + np_pctldev = of_node_get(np_config); + for (;;) { + np_pctldev = of_get_next_parent(np_pctldev); + if (!np_pctldev || of_node_is_root(np_pctldev)) { + dev_err(p->dev, "could not find pctldev for node %s\n", + np_config->full_name); + of_node_put(np_pctldev); + /* FIXME: This should trigger deferrered probe */ + return -ENODEV; + } + pctldev = find_pinctrl_by_of_node(np_pctldev); + if (pctldev) + break; + } + of_node_put(np_pctldev); + + /* + * Call pinctrl driver to parse device tree node, and + * generate mapping table entries + */ + ops = pctldev->desc->pctlops; + if (!ops->dt_node_to_map) { + dev_err(p->dev, "pctldev %s doesn't support DT\n", + dev_name(pctldev->dev)); + return -ENODEV; + } + ret = ops->dt_node_to_map(pctldev, np_config, &map, &num_maps); + if (ret < 0) + return ret; + + /* Stash the mapping table chunk away for later use */ + return dt_remember_or_free_map(p, statename, pctldev, map, num_maps); +} + +static int dt_remember_dummy_state(struct pinctrl *p, const char *statename) +{ + struct pinctrl_map *map; + + map = kzalloc(sizeof(*map), GFP_KERNEL); + if (!map) { + dev_err(p->dev, "failed to alloc struct pinctrl_map\n"); + return -ENOMEM; + } + + /* There is no pctldev for PIN_MAP_TYPE_DUMMY_STATE */ + map->type = PIN_MAP_TYPE_DUMMY_STATE; + + return dt_remember_or_free_map(p, statename, NULL, map, 1); +} + +int pinctrl_dt_to_map(struct pinctrl *p) +{ + struct device_node *np = p->dev->of_node; + int state, ret; + char *propname; + struct property *prop; + const char *statename; + const __be32 *list; + int size, config; + phandle phandle; + struct device_node *np_config; + + /* CONFIG_OF enabled, p->dev not instantiated from DT */ + if (!np) { + dev_dbg(p->dev, "no of_node; not parsing pinctrl DT\n"); + return 0; + } + + /* We may store pointers to property names within the node */ + of_node_get(np); + + /* For each defined state ID */ + for (state = 0; ; state++) { + /* Retrieve the pinctrl-* property */ + propname = kasprintf(GFP_KERNEL, "pinctrl-%d", state); + prop = of_find_property(np, propname, &size); + kfree(propname); + if (!prop) + break; + 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; + } + + /* 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) { + dev_err(p->dev, + "prop %s index %i invalid phandle\n", + prop->name, config); + ret = -EINVAL; + goto err; + } + + /* Parse the node */ + ret = dt_to_map_one_config(p, statename, np_config); + of_node_put(np_config); + if (ret < 0) + goto err; + } + + /* No entries in DT? Generate a dummy state table entry */ + if (!size) { + ret = dt_remember_dummy_state(p, statename); + if (ret < 0) + goto err; + } + } + + return 0; + +err: + pinctrl_dt_free_maps(p); + return ret; +} diff --git a/drivers/pinctrl/devicetree.h b/drivers/pinctrl/devicetree.h new file mode 100644 index 0000000..760bc49 --- /dev/null +++ b/drivers/pinctrl/devicetree.h @@ -0,0 +1,35 @@ +/* + * Internal interface to pinctrl device tree integration + * + * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifdef CONFIG_OF + +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; +} + +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 4e9f078..aa92cde 100644 --- a/include/linux/pinctrl/pinctrl.h +++ b/include/linux/pinctrl/pinctrl.h @@ -21,9 +21,11 @@ struct device; struct pinctrl_dev; +struct pinctrl_map; struct pinmux_ops; struct pinconf_ops; struct gpio_chip; +struct device_node; /** * struct pinctrl_pin_desc - boards/machines provide information on their @@ -83,6 +85,11 @@ struct pinctrl_ops { unsigned *num_pins); void (*pin_dbg_show) (struct pinctrl_dev *pctldev, struct seq_file *s, unsigned offset); + int (*dt_node_to_map) (struct pinctrl_dev *pctldev, + struct device_node *np_config, + struct pinctrl_map **map, unsigned *num_maps); + void (*dt_free_map) (struct pinctrl_dev *pctldev, + struct pinctrl_map *map, unsigned num_maps); }; /** -- cgit v0.10.2 From eafeb7a44aa8f79c992b9d557ede740c739f4b25 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Tue, 3 Apr 2012 21:53:56 -0600 Subject: pinctrl: fix build when CONFIG_OF && !CONFIG_PINCTRL pinctrl/devicetree.c won't compile when !CONFIG_PINCTRL, since the pinctrl headers don't declare some types when !PINCTRL. Make sure pinctrl/Makefile only attempts to compile devicetree.c when OF && PINCTRL. Acked-by: Dong Aisheng Signed-off-by: Stephen Warren Signed-off-by: Linus Walleij diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 049c9fb..8e3c95a 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -5,7 +5,9 @@ ccflags-$(CONFIG_DEBUG_PINCTRL) += -DDEBUG obj-$(CONFIG_PINCTRL) += core.o obj-$(CONFIG_PINMUX) += pinmux.o obj-$(CONFIG_PINCONF) += pinconf.o -obj-$(CONFIG_OF) += devicetree.o +ifeq ($(CONFIG_OF),y) +obj-$(CONFIG_PINCTRL) += devicetree.o +endif obj-$(CONFIG_GENERIC_PINCONF) += pinconf-generic.o obj-$(CONFIG_PINCTRL_PXA3xx) += pinctrl-pxa3xx.o obj-$(CONFIG_PINCTRL_MMP2) += pinctrl-mmp2.o -- cgit v0.10.2 From eb181c3533e8e5b3eaa96d3e8ed1cf5d9a408076 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 29 Mar 2012 11:03:27 +0530 Subject: Documentation: pinctrl: add missing spi0_0 grp in example Missed one group from the documentation when proofreading. Signed-off-by: Viresh Kumar Signed-off-by: Linus Walleij diff --git a/Documentation/pinctrl.txt b/Documentation/pinctrl.txt index d97bccf..f2e27ef 100644 --- a/Documentation/pinctrl.txt +++ b/Documentation/pinctrl.txt @@ -640,7 +640,7 @@ struct foo_pmx_func { const unsigned num_groups; }; -static const char * const spi0_groups[] = { "spi0_1_grp" }; +static const char * const spi0_groups[] = { "spi0_0_grp", "spi0_1_grp" }; static const char * const i2c0_groups[] = { "i2c0_grp" }; static const char * const mmc0_groups[] = { "mmc0_1_grp", "mmc0_2_grp", "mmc0_3_grp" }; -- cgit v0.10.2 From 122dbe7e58c7d064a17eefd33205227e6bce85ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 30 Mar 2012 22:04:51 +0200 Subject: pinctrl: mark const init data with __initconst instead of __initdata MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As long as there is no other non-const variable marked __initdata in the same compilation unit it doesn't hurt. If there were one however compilation would fail with error: $variablename causes a section type conflict because a section containing const variables is marked read only and so cannot contain non-const variables. Signed-off-by: Uwe Kleine-König Cc: Randy Dunlap Signed-off-by: Linus Walleij diff --git a/Documentation/pinctrl.txt b/Documentation/pinctrl.txt index f2e27ef..2d88b3c 100644 --- a/Documentation/pinctrl.txt +++ b/Documentation/pinctrl.txt @@ -786,7 +786,7 @@ and spi on the second function mapping: #include -static const struct pinctrl_map __initdata mapping[] = { +static const struct pinctrl_map mapping[] __initconst = { { .dev_name = "foo-spi.0", .name = PINCTRL_STATE_DEFAULT, diff --git a/drivers/pinctrl/pinctrl-coh901.c b/drivers/pinctrl/pinctrl-coh901.c index 0797eba..55697a5 100644 --- a/drivers/pinctrl/pinctrl-coh901.c +++ b/drivers/pinctrl/pinctrl-coh901.c @@ -174,7 +174,7 @@ struct u300_gpio_confdata { /* Initial configuration */ -static const struct __initdata u300_gpio_confdata +static const struct __initconst u300_gpio_confdata bs335_gpio_config[BS335_GPIO_NUM_PORTS][U300_GPIO_PINS_PER_PORT] = { /* Port 0, pins 0-7 */ { @@ -255,7 +255,7 @@ bs335_gpio_config[BS335_GPIO_NUM_PORTS][U300_GPIO_PINS_PER_PORT] = { } }; -static const struct __initdata u300_gpio_confdata +static const struct __initconst u300_gpio_confdata bs365_gpio_config[BS365_GPIO_NUM_PORTS][U300_GPIO_PINS_PER_PORT] = { /* Port 0, pins 0-7 */ { -- cgit v0.10.2 From d1e90e9e7467dbfe521b25ba79f520bf676ebc36 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 30 Mar 2012 11:25:40 +0530 Subject: pinctrl: replace list_*() with get_*_count() Most of the SoC drivers implement list_groups() and list_functions() routines for pinctrl and pinmux. These routines continue returning zero until the selector argument is greater than total count of available groups or functions. This patch replaces these list_*() routines with get_*_count() routines, which returns the number of available selection for SoC driver. pinctrl layer will use this value to check the range it can choose. This patch fixes all user drivers for this change. There are other routines in user drivers, which have checks to check validity of selector passed to them. It is also no more required and hence removed. Documentation updated as well. Acked-by: Stephen Warren Signed-off-by: Viresh Kumar [Folded in fix and fixed a minor merge artifact manually] Signed-off-by: Linus Walleij diff --git a/Documentation/pinctrl.txt b/Documentation/pinctrl.txt index 2d88b3c..eb46b1c 100644 --- a/Documentation/pinctrl.txt +++ b/Documentation/pinctrl.txt @@ -152,11 +152,9 @@ static const struct foo_group foo_groups[] = { }; -static int foo_list_groups(struct pinctrl_dev *pctldev, unsigned selector) +static int foo_get_groups_count(struct pinctrl_dev *pctldev) { - if (selector >= ARRAY_SIZE(foo_groups)) - return -EINVAL; - return 0; + return ARRAY_SIZE(foo_groups); } static const char *foo_get_group_name(struct pinctrl_dev *pctldev, @@ -175,7 +173,7 @@ static int foo_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector, } static struct pinctrl_ops foo_pctrl_ops = { - .list_groups = foo_list_groups, + .get_groups_count = foo_get_groups_count, .get_group_name = foo_get_group_name, .get_group_pins = foo_get_group_pins, }; @@ -186,13 +184,12 @@ static struct pinctrl_desc foo_desc = { .pctlops = &foo_pctrl_ops, }; -The pin control subsystem will call the .list_groups() function repeatedly -beginning on 0 until it returns non-zero to determine legal selectors, then -it will call the other functions to retrieve the name and pins of the group. -Maintaining the data structure of the groups is up to the driver, this is -just a simple example - in practice you may need more entries in your group -structure, for example specific register ranges associated with each group -and so on. +The pin control subsystem will call the .get_groups_count() function to +determine total number of legal selectors, then it will call the other functions +to retrieve the name and pins of the group. Maintaining the data structure of +the groups is up to the driver, this is just a simple example - in practice you +may need more entries in your group structure, for example specific register +ranges associated with each group and so on. Pin configuration @@ -606,11 +603,9 @@ static const struct foo_group foo_groups[] = { }; -static int foo_list_groups(struct pinctrl_dev *pctldev, unsigned selector) +static int foo_get_groups_count(struct pinctrl_dev *pctldev) { - if (selector >= ARRAY_SIZE(foo_groups)) - return -EINVAL; - return 0; + return ARRAY_SIZE(foo_groups); } static const char *foo_get_group_name(struct pinctrl_dev *pctldev, @@ -629,7 +624,7 @@ static int foo_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector, } static struct pinctrl_ops foo_pctrl_ops = { - .list_groups = foo_list_groups, + .get_groups_count = foo_get_groups_count, .get_group_name = foo_get_group_name, .get_group_pins = foo_get_group_pins, }; @@ -663,11 +658,9 @@ static const struct foo_pmx_func foo_functions[] = { }, }; -int foo_list_funcs(struct pinctrl_dev *pctldev, unsigned selector) +int foo_get_functions_count(struct pinctrl_dev *pctldev) { - if (selector >= ARRAY_SIZE(foo_functions)) - return -EINVAL; - return 0; + return ARRAY_SIZE(foo_functions); } const char *foo_get_fname(struct pinctrl_dev *pctldev, unsigned selector) @@ -703,7 +696,7 @@ void foo_disable(struct pinctrl_dev *pctldev, unsigned selector, } struct pinmux_ops foo_pmxops = { - .list_functions = foo_list_funcs, + .get_functions_count = foo_get_functions_count, .get_function_name = foo_get_fname, .get_function_groups = foo_get_groups, .enable = foo_enable, diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index 832f71d..7ff8690 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -319,9 +319,10 @@ int pinctrl_get_group_selector(struct pinctrl_dev *pctldev, const char *pin_group) { const struct pinctrl_ops *pctlops = pctldev->desc->pctlops; + unsigned ngroups = pctlops->get_groups_count(pctldev); unsigned group_selector = 0; - while (pctlops->list_groups(pctldev, group_selector) >= 0) { + while (group_selector < ngroups) { const char *gname = pctlops->get_group_name(pctldev, group_selector); if (!strcmp(gname, pin_group)) { @@ -941,12 +942,13 @@ static int pinctrl_groups_show(struct seq_file *s, void *what) { struct pinctrl_dev *pctldev = s->private; const struct pinctrl_ops *ops = pctldev->desc->pctlops; - unsigned selector = 0; + unsigned ngroups, selector = 0; + ngroups = ops->get_groups_count(pctldev); mutex_lock(&pinctrl_mutex); seq_puts(s, "registered pin groups:\n"); - while (ops->list_groups(pctldev, selector) >= 0) { + while (selector < ngroups) { const unsigned *pins; unsigned num_pins; const char *gname = ops->get_group_name(pctldev, selector); @@ -1261,7 +1263,7 @@ static int pinctrl_check_ops(struct pinctrl_dev *pctldev) const struct pinctrl_ops *ops = pctldev->desc->pctlops; if (!ops || - !ops->list_groups || + !ops->get_groups_count || !ops->get_group_name || !ops->get_group_pins) return -EINVAL; diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c index 7321e86..eb3a14f 100644 --- a/drivers/pinctrl/pinconf.c +++ b/drivers/pinctrl/pinconf.c @@ -495,6 +495,7 @@ static int pinconf_groups_show(struct seq_file *s, void *what) struct pinctrl_dev *pctldev = s->private; const struct pinctrl_ops *pctlops = pctldev->desc->pctlops; const struct pinconf_ops *ops = pctldev->desc->confops; + unsigned ngroups = pctlops->get_groups_count(pctldev); unsigned selector = 0; if (!ops || !ops->pin_config_group_get) @@ -505,7 +506,7 @@ static int pinconf_groups_show(struct seq_file *s, void *what) mutex_lock(&pinctrl_mutex); - while (pctlops->list_groups(pctldev, selector) >= 0) { + while (selector < ngroups) { const char *gname = pctlops->get_group_name(pctldev, selector); seq_printf(s, "%u (%s):", selector, gname); diff --git a/drivers/pinctrl/pinctrl-pxa3xx.c b/drivers/pinctrl/pinctrl-pxa3xx.c index 079dce0..7644e42 100644 --- a/drivers/pinctrl/pinctrl-pxa3xx.c +++ b/drivers/pinctrl/pinctrl-pxa3xx.c @@ -25,20 +25,18 @@ static struct pinctrl_gpio_range pxa3xx_pinctrl_gpio_range = { .pin_base = 0, }; -static int pxa3xx_list_groups(struct pinctrl_dev *pctrldev, unsigned selector) +static int pxa3xx_get_groups_count(struct pinctrl_dev *pctrldev) { struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev); - if (selector >= info->num_grps) - return -EINVAL; - return 0; + + return info->num_grps; } static const char *pxa3xx_get_group_name(struct pinctrl_dev *pctrldev, unsigned selector) { struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev); - if (selector >= info->num_grps) - return NULL; + return info->grps[selector].name; } @@ -48,25 +46,23 @@ static int pxa3xx_get_group_pins(struct pinctrl_dev *pctrldev, unsigned *num_pins) { struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev); - if (selector >= info->num_grps) - return -EINVAL; + *pins = info->grps[selector].pins; *num_pins = info->grps[selector].npins; return 0; } static struct pinctrl_ops pxa3xx_pctrl_ops = { - .list_groups = pxa3xx_list_groups, + .get_groups_count = pxa3xx_get_groups_count, .get_group_name = pxa3xx_get_group_name, .get_group_pins = pxa3xx_get_group_pins, }; -static int pxa3xx_pmx_list_func(struct pinctrl_dev *pctrldev, unsigned func) +static int pxa3xx_pmx_get_funcs_count(struct pinctrl_dev *pctrldev) { struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev); - if (func >= info->num_funcs) - return -EINVAL; - return 0; + + return info->num_funcs; } static const char *pxa3xx_pmx_get_func_name(struct pinctrl_dev *pctrldev, @@ -170,7 +166,7 @@ static int pxa3xx_pmx_request_gpio(struct pinctrl_dev *pctrldev, } static struct pinmux_ops pxa3xx_pmx_ops = { - .list_functions = pxa3xx_pmx_list_func, + .get_functions_count = pxa3xx_pmx_get_funcs_count, .get_function_name = pxa3xx_pmx_get_func_name, .get_function_groups = pxa3xx_pmx_get_groups, .enable = pxa3xx_pmx_enable, diff --git a/drivers/pinctrl/pinctrl-sirf.c b/drivers/pinctrl/pinctrl-sirf.c index 6b3534c..ba15b1a 100644 --- a/drivers/pinctrl/pinctrl-sirf.c +++ b/drivers/pinctrl/pinctrl-sirf.c @@ -853,18 +853,14 @@ static const struct sirfsoc_pin_group sirfsoc_pin_groups[] = { SIRFSOC_PIN_GROUP("gpsgrp", gps_pins), }; -static int sirfsoc_list_groups(struct pinctrl_dev *pctldev, unsigned selector) +static int sirfsoc_get_groups_count(struct pinctrl_dev *pctldev) { - if (selector >= ARRAY_SIZE(sirfsoc_pin_groups)) - return -EINVAL; - return 0; + return ARRAY_SIZE(sirfsoc_pin_groups); } static const char *sirfsoc_get_group_name(struct pinctrl_dev *pctldev, unsigned selector) { - if (selector >= ARRAY_SIZE(sirfsoc_pin_groups)) - return NULL; return sirfsoc_pin_groups[selector].name; } @@ -872,8 +868,6 @@ static int sirfsoc_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector const unsigned **pins, unsigned *num_pins) { - if (selector >= ARRAY_SIZE(sirfsoc_pin_groups)) - return -EINVAL; *pins = sirfsoc_pin_groups[selector].pins; *num_pins = sirfsoc_pin_groups[selector].num_pins; return 0; @@ -886,7 +880,7 @@ static void sirfsoc_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s } static struct pinctrl_ops sirfsoc_pctrl_ops = { - .list_groups = sirfsoc_list_groups, + .get_groups_count = sirfsoc_get_groups_count, .get_group_name = sirfsoc_get_group_name, .get_group_pins = sirfsoc_get_group_pins, .pin_dbg_show = sirfsoc_pin_dbg_show, @@ -1033,11 +1027,9 @@ static void sirfsoc_pinmux_disable(struct pinctrl_dev *pmxdev, unsigned selector sirfsoc_pinmux_endisable(spmx, selector, false); } -static int sirfsoc_pinmux_list_funcs(struct pinctrl_dev *pmxdev, unsigned selector) +static int sirfsoc_pinmux_get_funcs_count(struct pinctrl_dev *pmxdev) { - if (selector >= ARRAY_SIZE(sirfsoc_pmx_functions)) - return -EINVAL; - return 0; + return ARRAY_SIZE(sirfsoc_pmx_functions); } static const char *sirfsoc_pinmux_get_func_name(struct pinctrl_dev *pctldev, @@ -1074,9 +1066,9 @@ static int sirfsoc_pinmux_request_gpio(struct pinctrl_dev *pmxdev, } static struct pinmux_ops sirfsoc_pinmux_ops = { - .list_functions = sirfsoc_pinmux_list_funcs, .enable = sirfsoc_pinmux_enable, .disable = sirfsoc_pinmux_disable, + .get_functions_count = sirfsoc_pinmux_get_funcs_count, .get_function_name = sirfsoc_pinmux_get_func_name, .get_function_groups = sirfsoc_pinmux_get_groups, .gpio_request_enable = sirfsoc_pinmux_request_gpio, diff --git a/drivers/pinctrl/pinctrl-tegra.c b/drivers/pinctrl/pinctrl-tegra.c index 9b32968..41311a2 100644 --- a/drivers/pinctrl/pinctrl-tegra.c +++ b/drivers/pinctrl/pinctrl-tegra.c @@ -53,15 +53,11 @@ static inline void pmx_writel(struct tegra_pmx *pmx, u32 val, u32 bank, u32 reg) writel(val, pmx->regs[bank] + reg); } -static int tegra_pinctrl_list_groups(struct pinctrl_dev *pctldev, - unsigned group) +static int tegra_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) { struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); - if (group >= pmx->soc->ngroups) - return -EINVAL; - - return 0; + return pmx->soc->ngroups; } static const char *tegra_pinctrl_get_group_name(struct pinctrl_dev *pctldev, @@ -69,9 +65,6 @@ static const char *tegra_pinctrl_get_group_name(struct pinctrl_dev *pctldev, { struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); - if (group >= pmx->soc->ngroups) - return NULL; - return pmx->soc->groups[group].name; } @@ -82,9 +75,6 @@ static int tegra_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, { struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); - if (group >= pmx->soc->ngroups) - return -EINVAL; - *pins = pmx->soc->groups[group].pins; *num_pins = pmx->soc->groups[group].npins; @@ -99,21 +89,17 @@ static void tegra_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev, } static struct pinctrl_ops tegra_pinctrl_ops = { - .list_groups = tegra_pinctrl_list_groups, + .get_groups_count = tegra_pinctrl_get_groups_count, .get_group_name = tegra_pinctrl_get_group_name, .get_group_pins = tegra_pinctrl_get_group_pins, .pin_dbg_show = tegra_pinctrl_pin_dbg_show, }; -static int tegra_pinctrl_list_funcs(struct pinctrl_dev *pctldev, - unsigned function) +static int tegra_pinctrl_get_funcs_count(struct pinctrl_dev *pctldev) { struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); - if (function >= pmx->soc->nfunctions) - return -EINVAL; - - return 0; + return pmx->soc->nfunctions; } static const char *tegra_pinctrl_get_func_name(struct pinctrl_dev *pctldev, @@ -121,9 +107,6 @@ static const char *tegra_pinctrl_get_func_name(struct pinctrl_dev *pctldev, { struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); - if (function >= pmx->soc->nfunctions) - return NULL; - return pmx->soc->functions[function].name; } @@ -134,9 +117,6 @@ static int tegra_pinctrl_get_func_groups(struct pinctrl_dev *pctldev, { struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); - if (function >= pmx->soc->nfunctions) - return -EINVAL; - *groups = pmx->soc->functions[function].groups; *num_groups = pmx->soc->functions[function].ngroups; @@ -151,8 +131,6 @@ static int tegra_pinctrl_enable(struct pinctrl_dev *pctldev, unsigned function, int i; u32 val; - if (group >= pmx->soc->ngroups) - return -EINVAL; g = &pmx->soc->groups[group]; if (g->mux_reg < 0) @@ -180,8 +158,6 @@ static void tegra_pinctrl_disable(struct pinctrl_dev *pctldev, const struct tegra_pingroup *g; u32 val; - if (group >= pmx->soc->ngroups) - return; g = &pmx->soc->groups[group]; if (g->mux_reg < 0) @@ -194,7 +170,7 @@ static void tegra_pinctrl_disable(struct pinctrl_dev *pctldev, } static struct pinmux_ops tegra_pinmux_ops = { - .list_functions = tegra_pinctrl_list_funcs, + .get_functions_count = tegra_pinctrl_get_funcs_count, .get_function_name = tegra_pinctrl_get_func_name, .get_function_groups = tegra_pinctrl_get_func_groups, .enable = tegra_pinctrl_enable, @@ -324,8 +300,6 @@ static int tegra_pinconf_group_get(struct pinctrl_dev *pctldev, s16 reg; u32 val, mask; - if (group >= pmx->soc->ngroups) - return -EINVAL; g = &pmx->soc->groups[group]; ret = tegra_pinconf_reg(pmx, g, param, &bank, ®, &bit, &width); @@ -353,8 +327,6 @@ static int tegra_pinconf_group_set(struct pinctrl_dev *pctldev, s16 reg; u32 val, mask; - if (group >= pmx->soc->ngroups) - return -EINVAL; g = &pmx->soc->groups[group]; ret = tegra_pinconf_reg(pmx, g, param, &bank, ®, &bit, &width); diff --git a/drivers/pinctrl/pinctrl-u300.c b/drivers/pinctrl/pinctrl-u300.c index 26eb8cc..05d0299 100644 --- a/drivers/pinctrl/pinctrl-u300.c +++ b/drivers/pinctrl/pinctrl-u300.c @@ -836,18 +836,14 @@ static const struct u300_pin_group u300_pin_groups[] = { }, }; -static int u300_list_groups(struct pinctrl_dev *pctldev, unsigned selector) +static int u300_get_groups_count(struct pinctrl_dev *pctldev) { - if (selector >= ARRAY_SIZE(u300_pin_groups)) - return -EINVAL; - return 0; + return ARRAY_SIZE(u300_pin_groups); } static const char *u300_get_group_name(struct pinctrl_dev *pctldev, unsigned selector) { - if (selector >= ARRAY_SIZE(u300_pin_groups)) - return NULL; return u300_pin_groups[selector].name; } @@ -855,8 +851,6 @@ static int u300_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector, const unsigned **pins, unsigned *num_pins) { - if (selector >= ARRAY_SIZE(u300_pin_groups)) - return -EINVAL; *pins = u300_pin_groups[selector].pins; *num_pins = u300_pin_groups[selector].num_pins; return 0; @@ -869,7 +863,7 @@ static void u300_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, } static struct pinctrl_ops u300_pctrl_ops = { - .list_groups = u300_list_groups, + .get_groups_count = u300_get_groups_count, .get_group_name = u300_get_group_name, .get_group_pins = u300_get_group_pins, .pin_dbg_show = u300_pin_dbg_show, @@ -991,11 +985,9 @@ static void u300_pmx_disable(struct pinctrl_dev *pctldev, unsigned selector, u300_pmx_endisable(upmx, selector, false); } -static int u300_pmx_list_funcs(struct pinctrl_dev *pctldev, unsigned selector) +static int u300_pmx_get_funcs_count(struct pinctrl_dev *pctldev) { - if (selector >= ARRAY_SIZE(u300_pmx_functions)) - return -EINVAL; - return 0; + return ARRAY_SIZE(u300_pmx_functions); } static const char *u300_pmx_get_func_name(struct pinctrl_dev *pctldev, @@ -1014,7 +1006,7 @@ static int u300_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector, } static struct pinmux_ops u300_pmx_ops = { - .list_functions = u300_pmx_list_funcs, + .get_functions_count = u300_pmx_get_funcs_count, .get_function_name = u300_pmx_get_func_name, .get_function_groups = u300_pmx_get_groups, .enable = u300_pmx_enable, diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c index 4e62783..375b214 100644 --- a/drivers/pinctrl/pinmux.c +++ b/drivers/pinctrl/pinmux.c @@ -33,10 +33,11 @@ int pinmux_check_ops(struct pinctrl_dev *pctldev) { const struct pinmux_ops *ops = pctldev->desc->pmxops; + unsigned nfuncs = ops->get_functions_count(pctldev); unsigned selector = 0; /* Check that we implement required operations */ - if (!ops->list_functions || + if (!ops->get_functions_count || !ops->get_function_name || !ops->get_function_groups || !ops->enable || @@ -44,7 +45,7 @@ int pinmux_check_ops(struct pinctrl_dev *pctldev) return -EINVAL; /* Check that all functions registered have names */ - while (ops->list_functions(pctldev, selector) >= 0) { + while (selector < nfuncs) { const char *fname = ops->get_function_name(pctldev, selector); if (!fname) { @@ -287,10 +288,11 @@ static int pinmux_func_name_to_selector(struct pinctrl_dev *pctldev, const char *function) { const struct pinmux_ops *ops = pctldev->desc->pmxops; + unsigned nfuncs = ops->get_functions_count(pctldev); unsigned selector = 0; /* See if this pctldev has this function */ - while (ops->list_functions(pctldev, selector) >= 0) { + while (selector < nfuncs) { const char *fname = ops->get_function_name(pctldev, selector); @@ -477,11 +479,12 @@ static int pinmux_functions_show(struct seq_file *s, void *what) { struct pinctrl_dev *pctldev = s->private; const struct pinmux_ops *pmxops = pctldev->desc->pmxops; + unsigned nfuncs = pmxops->get_functions_count(pctldev); unsigned func_selector = 0; mutex_lock(&pinctrl_mutex); - while (pmxops->list_functions(pctldev, func_selector) >= 0) { + while (func_selector < nfuncs) { const char *func = pmxops->get_function_name(pctldev, func_selector); const char * const *groups; diff --git a/include/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctrl.h index aa92cde..c22d040 100644 --- a/include/linux/pinctrl/pinctrl.h +++ b/include/linux/pinctrl/pinctrl.h @@ -66,9 +66,7 @@ struct pinctrl_gpio_range { /** * struct pinctrl_ops - global pin control operations, to be implemented by * pin controller drivers. - * @list_groups: list the number of selectable named groups available - * in this pinmux driver, the core will begin on 0 and call this - * repeatedly as long as it returns >= 0 to enumerate the groups + * @get_groups_count: Returns the count of total number of groups registered. * @get_group_name: return the group name of the pin group * @get_group_pins: return an array of pins corresponding to a certain * group selector @pins, and the size of the array in @num_pins @@ -76,7 +74,7 @@ struct pinctrl_gpio_range { * info for a certain pin in debugfs */ struct pinctrl_ops { - int (*list_groups) (struct pinctrl_dev *pctldev, unsigned selector); + int (*get_groups_count) (struct pinctrl_dev *pctldev); const char *(*get_group_name) (struct pinctrl_dev *pctldev, unsigned selector); int (*get_group_pins) (struct pinctrl_dev *pctldev, diff --git a/include/linux/pinctrl/pinmux.h b/include/linux/pinctrl/pinmux.h index 47e9237..dd7bef6 100644 --- a/include/linux/pinctrl/pinmux.h +++ b/include/linux/pinctrl/pinmux.h @@ -29,9 +29,8 @@ struct pinctrl_dev; * is allowed to answer "no" by returning a negative error code * @free: the reverse function of the request() callback, frees a pin after * being requested - * @list_functions: list the number of selectable named functions available - * in this pinmux driver, the core will begin on 0 and call this - * repeatedly as long as it returns >= 0 to enumerate mux settings + * @get_functions_count: returns number of selectable named functions available + * in this pinmux driver * @get_function_name: return the function name of the muxing selector, * called by the core to figure out which mux setting it shall map a * certain device to @@ -62,7 +61,7 @@ struct pinctrl_dev; struct pinmux_ops { int (*request) (struct pinctrl_dev *pctldev, unsigned offset); int (*free) (struct pinctrl_dev *pctldev, unsigned offset); - int (*list_functions) (struct pinctrl_dev *pctldev, unsigned selector); + int (*get_functions_count) (struct pinctrl_dev *pctldev); const char *(*get_function_name) (struct pinctrl_dev *pctldev, unsigned selector); int (*get_function_groups) (struct pinctrl_dev *pctldev, -- cgit v0.10.2 From a1d31f71e6ed2f714830df8885ec07dfe1f6632e Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Fri, 6 Apr 2012 20:18:09 +0800 Subject: pinctrl: fix pinmux_check_ops error checking Do not use get_functions_count before checking. Acked-by: Stephen Warren Signed-off-by: Dong Aisheng Signed-off-by: Linus Walleij diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c index 375b214..8849830 100644 --- a/drivers/pinctrl/pinmux.c +++ b/drivers/pinctrl/pinmux.c @@ -33,11 +33,12 @@ int pinmux_check_ops(struct pinctrl_dev *pctldev) { const struct pinmux_ops *ops = pctldev->desc->pmxops; - unsigned nfuncs = ops->get_functions_count(pctldev); + unsigned nfuncs; unsigned selector = 0; /* Check that we implement required operations */ - if (!ops->get_functions_count || + if (!ops || + !ops->get_functions_count || !ops->get_function_name || !ops->get_function_groups || !ops->enable || @@ -45,11 +46,12 @@ int pinmux_check_ops(struct pinctrl_dev *pctldev) return -EINVAL; /* Check that all functions registered have names */ + nfuncs = ops->get_functions_count(pctldev); while (selector < nfuncs) { const char *fname = ops->get_function_name(pctldev, selector); if (!fname) { - pr_err("pinmux ops has no name for function%u\n", + dev_err(pctldev->dev, "pinmux ops has no name for function%u\n", selector); return -EINVAL; } -- cgit v0.10.2 From ad8bb720c23a80233e45ed31d67458f5e5b7ab31 Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Tue, 10 Apr 2012 12:41:34 +0800 Subject: pinctrl: add some error checking for user interfaces This patch can avoid kernel oops in case the mux or config function is not supported by driver. Acked-by: Stephen Warren Signed-off-by: Dong Aisheng Signed-off-by: Linus Walleij diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c index eb3a14f..384dcc1 100644 --- a/drivers/pinctrl/pinconf.c +++ b/drivers/pinctrl/pinconf.c @@ -448,8 +448,12 @@ static void pinconf_dump_pin(struct pinctrl_dev *pctldev, static int pinconf_pins_show(struct seq_file *s, void *what) { struct pinctrl_dev *pctldev = s->private; + const struct pinconf_ops *ops = pctldev->desc->confops; unsigned i, pin; + if (!ops || !ops->pin_config_get) + return 0; + seq_puts(s, "Pin config settings per pin\n"); seq_puts(s, "Format: pin (name): pinmux setting array\n"); diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c index 8849830..c494c37 100644 --- a/drivers/pinctrl/pinmux.c +++ b/drivers/pinctrl/pinmux.c @@ -323,6 +323,11 @@ int pinmux_map_to_setting(struct pinctrl_map const *map, const unsigned *pins; unsigned num_pins; + if (!pmxops) { + dev_err(pctldev->dev, "does not support mux function\n"); + return -EINVAL; + } + setting->data.mux.func = pinmux_func_name_to_selector(pctldev, map->data.mux.function); if (setting->data.mux.func < 0) @@ -481,11 +486,14 @@ static int pinmux_functions_show(struct seq_file *s, void *what) { struct pinctrl_dev *pctldev = s->private; const struct pinmux_ops *pmxops = pctldev->desc->pmxops; - unsigned nfuncs = pmxops->get_functions_count(pctldev); + unsigned nfuncs; unsigned func_selector = 0; - mutex_lock(&pinctrl_mutex); + if (!pmxops) + return 0; + mutex_lock(&pinctrl_mutex); + nfuncs = pmxops->get_functions_count(pctldev); while (func_selector < nfuncs) { const char *func = pmxops->get_function_name(pctldev, func_selector); @@ -520,6 +528,9 @@ static int pinmux_pins_show(struct seq_file *s, void *what) const struct pinmux_ops *pmxops = pctldev->desc->pmxops; unsigned i, pin; + if (!pmxops) + return 0; + seq_puts(s, "Pinmux settings per pin\n"); seq_puts(s, "Format: pin (name): mux_owner gpio_owner hog?\n"); -- cgit v0.10.2 From c05127c4e2c6e7d9949347a76fd05c337bcd5e84 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 10 Apr 2012 10:00:38 +0200 Subject: pinctrl: implement pinctrl deferred probing If drivers try to obtain pinctrl handles for a pin controller that has not yet registered to the subsystem, we need to be able to back out and retry with deferred probing. So let's return -EPROBE_DEFER whenever this location fails. Also downgrade the errors to info, maybe we will even set them to debug once the deferred probing is commonplace. Cc: Arnd Bergmann Reviewed-by: Mark Brown Acked-by: Stephen Warren Signed-off-by: Linus Walleij diff --git a/Documentation/pinctrl.txt b/Documentation/pinctrl.txt index eb46b1c..4431c3e7 100644 --- a/Documentation/pinctrl.txt +++ b/Documentation/pinctrl.txt @@ -1043,6 +1043,11 @@ quickly poking some registers. The pins are allocated for your device when you issue the pinctrl_get() call, after this you should be able to see this in the debugfs listing of all pins. +NOTE: the pinctrl system will return -EPROBE_DEFER if it cannot find the +requested pinctrl handles, for example if the pinctrl driver has not yet +registered. Thus make sure that the error path in your driver gracefully +cleans up and is ready to retry the probing later in the startup process. + System pin control hogging ========================== diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index 7ff8690..59027ab 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -518,11 +518,14 @@ static int add_setting(struct pinctrl *p, struct pinctrl_map const *map) setting->pctldev = get_pinctrl_dev_from_devname(map->ctrl_dev_name); if (setting->pctldev == NULL) { - dev_err(p->dev, "unknown pinctrl device %s in map entry", + dev_info(p->dev, "unknown pinctrl device %s in map entry, deferring probe", map->ctrl_dev_name); kfree(setting); - /* Eventually, this should trigger deferred probe */ - return -ENODEV; + /* + * OK let us guess that the driver is not there yet, and + * let's defer obtaining this pinctrl handle to later... + */ + return -EPROBE_DEFER; } switch (map->type) { diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c index 5ef2feb..fcb1de4 100644 --- a/drivers/pinctrl/devicetree.c +++ b/drivers/pinctrl/devicetree.c @@ -121,11 +121,11 @@ static int dt_to_map_one_config(struct pinctrl *p, const char *statename, for (;;) { np_pctldev = of_get_next_parent(np_pctldev); if (!np_pctldev || of_node_is_root(np_pctldev)) { - dev_err(p->dev, "could not find pctldev for node %s\n", + dev_info(p->dev, "could not find pctldev for node %s, deferring probe\n", np_config->full_name); of_node_put(np_pctldev); - /* FIXME: This should trigger deferrered probe */ - return -ENODEV; + /* OK let's just assume this will appear later then */ + return -EPROBE_DEFER; } pctldev = find_pinctrl_by_of_node(np_pctldev); if (pctldev) -- cgit v0.10.2 From c541adc637066407d4cda9db14dcb0e618966a4c Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 4 Apr 2012 09:27:46 -0600 Subject: dt: add property iteration helpers This patch adds macros of_property_for_each_u32() and of_property_for_each_string(), which iterate over an array of values within a device-tree property. Usage is for example: struct property *prop; const __be32 *p; u32 u; of_property_for_each_u32(np, "propname", prop, p, u) printk("U32 value: %x\n", u); struct property *prop; const char *s; of_property_for_each_string(np, "propname", prop, s) printk("String value: %s\n", s); Based on work by Rob Herring Cc: Grant Likely Signed-off-by: Stephen Warren Acked-by: Rob Herring Signed-off-by: Linus Walleij diff --git a/drivers/of/base.c b/drivers/of/base.c index 5806449..d9bfd49 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -1260,3 +1260,44 @@ int of_alias_get_id(struct device_node *np, const char *stem) return id; } EXPORT_SYMBOL_GPL(of_alias_get_id); + +const __be32 *of_prop_next_u32(struct property *prop, const __be32 *cur, + u32 *pu) +{ + const void *curv = cur; + + if (!prop) + return NULL; + + if (!cur) { + curv = prop->value; + goto out_val; + } + + curv += sizeof(*cur); + if (curv >= prop->value + prop->length) + return NULL; + +out_val: + *pu = be32_to_cpup(curv); + return curv; +} +EXPORT_SYMBOL_GPL(of_prop_next_u32); + +const char *of_prop_next_string(struct property *prop, const char *cur) +{ + const void *curv = cur; + + if (!prop) + return NULL; + + if (!cur) + return prop->value; + + curv += strlen(cur) + 1; + if (curv >= prop->value + prop->length) + return NULL; + + return curv; +} +EXPORT_SYMBOL_GPL(of_prop_next_string); diff --git a/include/linux/of.h b/include/linux/of.h index fa7fb1d..e3f942d 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -259,6 +259,37 @@ extern void of_detach_node(struct device_node *); #endif #define of_match_ptr(_ptr) (_ptr) + +/* + * struct property *prop; + * const __be32 *p; + * u32 u; + * + * of_property_for_each_u32(np, "propname", prop, p, u) + * printk("U32 value: %x\n", u); + */ +const __be32 *of_prop_next_u32(struct property *prop, const __be32 *cur, + u32 *pu); +#define of_property_for_each_u32(np, propname, prop, p, u) \ + for (prop = of_find_property(np, propname, NULL), \ + p = of_prop_next_u32(prop, NULL, &u); \ + p; \ + p = of_prop_next_u32(prop, p, &u)) + +/* + * struct property *prop; + * const char *s; + * + * of_property_for_each_string(np, "propname", prop, s) + * printk("String value: %s\n", s); + */ +const char *of_prop_next_string(struct property *prop, const char *cur); +#define of_property_for_each_string(np, propname, prop, s) \ + for (prop = of_find_property(np, propname, NULL), \ + s = of_prop_next_string(prop, NULL); \ + s; \ + s = of_prop_next_string(prop, s)) + #else /* CONFIG_OF */ static inline bool of_have_populated_dt(void) @@ -349,6 +380,10 @@ static inline int of_machine_is_compatible(const char *compat) #define of_match_ptr(_ptr) NULL #define of_match_node(_matches, _node) NULL +#define of_property_for_each_u32(np, propname, prop, p, u) \ + while (0) +#define of_property_for_each_string(np, propname, prop, s) \ + while (0) #endif /* CONFIG_OF */ /** -- cgit v0.10.2 From 7a865277fb0f9da9e456dfc11b0a564cbfc475cd Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 4 Apr 2012 09:27:47 -0600 Subject: dt: pinctrl: Document device tree binding The core pin controller bindings define: * The fact that pin controllers expose pin configurations as nodes in device tree. * That the bindings for those pin configuration nodes is defined by the individual pin controller drivers. * A standardized set of properties for client devices to define numbered or named pin configuration states, each referring to some number of the afore-mentioned pin configuration nodes. * That the bindings for the client devices determines the set of numbered or named states that must exist. Signed-off-by: Stephen Warren Acked-by: Shawn Guo Acked-by: Tony Lindgren Acked-by: Linus Walleij Acked-by: Simon Glass Acked-by: Dong Aisheng Signed-off-by: Linus Walleij diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt new file mode 100644 index 0000000..c95ea82 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt @@ -0,0 +1,128 @@ +== Introduction == + +Hardware modules that control pin multiplexing or configuration parameters +such as pull-up/down, tri-state, drive-strength etc are designated as pin +controllers. Each pin controller must be represented as a node in device tree, +just like any other hardware module. + +Hardware modules whose signals are affected by pin configuration are +designated client devices. Again, each client device must be represented as a +node in device tree, just like any other hardware module. + +For a client device to operate correctly, certain pin controllers must +set up certain specific pin configurations. Some client devices need a +single static pin configuration, e.g. set up during initialization. Others +need to reconfigure pins at run-time, for example to tri-state pins when the +device is inactive. Hence, each client device can define a set of named +states. The number and names of those states is defined by the client device's +own binding. + +The common pinctrl bindings defined in this file provide an infrastructure +for client device device tree nodes to map those state names to the pin +configuration used by those states. + +Note that pin controllers themselves may also be client devices of themselves. +For example, a pin controller may set up its own "active" state when the +driver loads. This would allow representing a board's static pin configuration +in a single place, rather than splitting it across multiple client device +nodes. The decision to do this or not somewhat rests with the author of +individual board device tree files, and any requirements imposed by the +bindings for the individual client devices in use by that board, i.e. whether +they require certain specific named states for dynamic pin configuration. + +== Pinctrl client devices == + +For each client device individually, every pin state is assigned an integer +ID. These numbers start at 0, and are contiguous. For each state ID, a unique +property exists to define the pin configuration. Each state may also be +assigned a name. When names are used, another property exists to map from +those names to the integer IDs. + +Each client device's own binding determines the set of states the must be +defined in its device tree node, and whether to define the set of state +IDs that must be provided, or whether to define the set of state names that +must be provided. + +Required properties: +pinctrl-0: List of phandles, each pointing at a pin configuration + node. These referenced pin configuration nodes must be child + nodes of the pin controller that they configure. Multiple + entries may exist in this list so that multiple pin + controllers may be configured, or so that a state may be built + from multiple nodes for a single pin controller, each + contributing part of the overall configuration. See the next + section of this document for details of the format of these + pin configuration nodes. + + In some cases, it may be useful to define a state, but for it + to be empty. This may be required when a common IP block is + used in an SoC either without a pin controller, or where the + pin controller does not affect the HW module in question. If + the binding for that IP block requires certain pin states to + exist, they must still be defined, but may be left empty. + +Optional properties: +pinctrl-1: List of phandles, each pointing at a pin configuration + node within a pin controller. +... +pinctrl-n: List of phandles, each pointing at a pin configuration + node within a pin controller. +pinctrl-names: The list of names to assign states. List entry 0 defines the + name for integer state ID 0, list entry 1 for state ID 1, and + so on. + +For example: + + /* For a client device requiring named states */ + device { + pinctrl-names = "active", "idle"; + pinctrl-0 = <&state_0_node_a>; + pinctrl-1 = <&state_1_node_a &state_1_node_b>; + }; + + /* For the same device if using state IDs */ + device { + pinctrl-0 = <&state_0_node_a>; + pinctrl-1 = <&state_1_node_a &state_1_node_b>; + }; + + /* + * For an IP block whose binding supports pin configuration, + * but in use on an SoC that doesn't have any pin control hardware + */ + device { + pinctrl-names = "active", "idle"; + pinctrl-0 = <>; + pinctrl-1 = <>; + }; + +== Pin controller devices == + +Pin controller devices should contain the pin configuration nodes that client +devices reference. + +For example: + + pincontroller { + ... /* Standard DT properties for the device itself elided */ + + state_0_node_a { + ... + }; + state_1_node_a { + ... + }; + state_1_node_b { + ... + }; + } + +The contents of each of those pin configuration child nodes is defined +entirely by the binding for the individual pin controller device. There +exists no common standard for this content. + +The pin configuration nodes need not be direct children of the pin controller +device; they may be grandchildren, for example. Whether this is legal, and +whether there is any interaction between the child and intermediate parent +nodes, is again defined entirely by the binding for the individual pin +controller device. -- cgit v0.10.2 From e3f80045e8856cb789f0938b61c263249f420ff3 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 4 Apr 2012 09:27:48 -0600 Subject: dt: Move Tegra20 pin mux binding into new pinctrl directory This places the file in the new location for all pin controller bindings. Also, rename the file using the full compatible value for easier avoidance of conflicts between multiple bindings. Signed-off-by: Stephen Warren Signed-off-by: Linus Walleij diff --git a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra20-pinmux.txt b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra20-pinmux.txt new file mode 100644 index 0000000..36f82db --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra20-pinmux.txt @@ -0,0 +1,5 @@ +NVIDIA Tegra 2 pinmux controller + +Required properties: +- compatible : "nvidia,tegra20-pinmux" + diff --git a/Documentation/devicetree/bindings/pinmux/pinmux_nvidia.txt b/Documentation/devicetree/bindings/pinmux/pinmux_nvidia.txt deleted file mode 100644 index 36f82db..0000000 --- a/Documentation/devicetree/bindings/pinmux/pinmux_nvidia.txt +++ /dev/null @@ -1,5 +0,0 @@ -NVIDIA Tegra 2 pinmux controller - -Required properties: -- compatible : "nvidia,tegra20-pinmux" - -- cgit v0.10.2 From a3c9454e530d51fad49bbc57e19d50a30f94ce14 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 4 Apr 2012 09:27:49 -0600 Subject: dt: Document Tegra20/30 pinctrl binding Define a new binding for the Tegra pin controller, which is capable of defining all aspects of desired pin multiplexing and pin configuration. This is all based on the new common pinctrl bindings. Add Tegra30 binding based on Tegra20 binding. Add some basic stuff that was missing before: * How many and what reg property entries must be provided. * An example. Signed-off-by: Stephen Warren Acked-by: Dong Aisheng Signed-off-by: Linus Walleij diff --git a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra20-pinmux.txt b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra20-pinmux.txt index 36f82db..c8e5782 100644 --- a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra20-pinmux.txt +++ b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra20-pinmux.txt @@ -1,5 +1,132 @@ -NVIDIA Tegra 2 pinmux controller +NVIDIA Tegra20 pinmux controller Required properties: -- compatible : "nvidia,tegra20-pinmux" +- compatible: "nvidia,tegra20-pinmux" +- reg: Should contain the register physical address and length for each of + the tri-state, mux, pull-up/down, and pad control register sets. +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +Tegra's pin configuration nodes act as a container for an abitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those pin(s)/group(s), and various pin configuration +parameters, such as pull-up, tristate, drive strength, etc. + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function or tristate parameter. For this +reason, even seemingly boolean values are actually tristates in this binding: +unspecified, off, or on. Unspecified is represented as an absent property, +and off/on are represented as integer values 0 and 1. + +Required subnode-properties: +- nvidia,pins : An array of strings. Each string contains the name of a pin or + group. Valid values for these names are listed below. + +Optional subnode-properties: +- nvidia,function: A string containing the name of the function to mux to the + pin or group. Valid values for function names are listed below. See the Tegra + TRM to determine which are valid for each pin or group. +- nvidia,pull: Integer, representing the pull-down/up to apply to the pin. + 0: none, 1: down, 2: up. +- nvidia,tristate: Integer. + 0: drive, 1: tristate. +- nvidia,high-speed-mode: Integer. Enable high speed mode the pins. + 0: no, 1: yes. +- nvidia,schmitt: Integer. Enables Schmitt Trigger on the input. + 0: no, 1: yes. +- nvidia,low-power-mode: Integer. Valid values 0-3. 0 is least power, 3 is + most power. Controls the drive power or current. See "Low Power Mode" + or "LPMD1" and "LPMD0" in the Tegra TRM. +- nvidia,pull-down-strength: Integer. Controls drive strength. 0 is weakest. + The range of valid values depends on the pingroup. See "CAL_DRVDN" in the + Tegra TRM. +- nvidia,pull-up-strength: Integer. Controls drive strength. 0 is weakest. + The range of valid values depends on the pingroup. See "CAL_DRVUP" in the + Tegra TRM. +- nvidia,slew-rate-rising: Integer. Controls rising signal slew rate. 0 is + fastest. The range of valid values depends on the pingroup. See + "DRVDN_SLWR" in the Tegra TRM. +- nvidia,slew-rate-falling: Integer. Controls falling signal slew rate. 0 is + fastest. The range of valid values depends on the pingroup. See + "DRVUP_SLWF" in the Tegra TRM. + +Note that many of these properties are only valid for certain specific pins +or groups. See the Tegra TRM and various pinmux spreadsheets for complete +details regarding which groups support which functionality. The Linux pinctrl +driver may also be a useful reference, since it consolidates, disambiguates, +and corrects data from all those sources. + +Valid values for pin and group names are: + + mux groups: + + These all support nvidia,function, nvidia,tristate, and many support + nvidia,pull. + + ata, atb, atc, atd, ate, cdev1, cdev2, crtp, csus, dap1, dap2, dap3, dap4, + ddc, dta, dtb, dtc, dtd, dte, dtf, gma, gmb, gmc, gmd, gme, gpu, gpu7, + gpv, hdint, i2cp, irrx, irtx, kbca, kbcb, kbcc, kbcd, kbce, kbcf, lcsn, + ld0, ld1, ld2, ld3, ld4, ld5, ld6, ld7, ld8, ld9, ld10, ld11, ld12, ld13, + ld14, ld15, ld16, ld17, ldc, ldi, lhp0, lhp1, lhp2, lhs, lm0, lm1, lpp, + lpw0, lpw1, lpw2, lsc0, lsc1, lsck, lsda, lsdi, lspi, lvp0, lvp1, lvs, + owc, pmc, pta, rm, sdb, sdc, sdd, sdio1, slxa, slxc, slxd, slxk, spdi, + spdo, spia, spib, spic, spid, spie, spif, spig, spih, uaa, uab, uac, uad, + uca, ucb, uda. + + tristate groups: + + These only support nvidia,pull. + + ck32, ddrc, pmca, pmcb, pmcc, pmcd, pmce, xm2c, xm2d, ls, lc, ld17_0, + ld19_18, ld21_20, ld23_22. + + drive groups: + + With some exceptions, these support nvidia,high-speed-mode, + nvidia,schmitt, nvidia,low-power-mode, nvidia,pull-down-strength, + nvidia,pull-up-strength, nvidia,slew_rate-rising, nvidia,slew_rate-falling. + + drive_ao1, drive_ao2, drive_at1, drive_at2, drive_cdev1, drive_cdev2, + drive_csus, drive_dap1, drive_dap2, drive_dap3, drive_dap4, drive_dbg, + drive_lcd1, drive_lcd2, drive_sdmmc2, drive_sdmmc3, drive_spi, drive_uaa, + drive_uab, drive_uart2, drive_uart3, drive_vi1, drive_vi2, drive_xm2a, + drive_xm2c, drive_xm2d, drive_xm2clk, drive_sdio1, drive_crt, drive_ddc, + drive_gma, drive_gmb, drive_gmc, drive_gmd, drive_gme, drive_owr, + drive_uda. + +Example: + + pinctrl@70000000 { + compatible = "nvidia,tegra20-pinmux"; + reg = < 0x70000014 0x10 /* Tri-state registers */ + 0x70000080 0x20 /* Mux registers */ + 0x700000a0 0x14 /* Pull-up/down registers */ + 0x70000868 0xa8 >; /* Pad control registers */ + }; + +Example board file extract: + + pinctrl@70000000 { + sdio4_default: sdio4_default { + atb { + nvidia,pins = "atb", "gma", "gme"; + nvidia,function = "sdio4"; + nvidia,pull = <0>; + nvidia,tristate = <0>; + }; + }; + }; + + sdhci@c8000600 { + pinctrl-names = "default"; + pinctrl-0 = <&sdio4_default>; + }; diff --git a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra30-pinmux.txt b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra30-pinmux.txt new file mode 100644 index 0000000..c275b70 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra30-pinmux.txt @@ -0,0 +1,132 @@ +NVIDIA Tegra30 pinmux controller + +The Tegra30 pinctrl binding is very similar to the Tegra20 pinctrl binding, +as described in nvidia,tegra20-pinmux.txt. In fact, this document assumes +that binding as a baseline, and only documents the differences between the +two bindings. + +Required properties: +- compatible: "nvidia,tegra30-pinmux" +- reg: Should contain the register physical address and length for each of + the pad control and mux registers. + +Tegra30 adds the following optional properties for pin configuration subnodes: +- nvidia,enable-input: Integer. Enable the pin's input path. 0: no, 1: yes. +- nvidia,open-drain: Integer. Enable open drain mode. 0: no, 1: yes. +- nvidia,lock: Integer. Lock the pin configuration against further changes + until reset. 0: no, 1: yes. +- nvidia,io-reset: Integer. Reset the IO path. 0: no, 1: yes. + +As with Tegra20, see the Tegra TRM for complete details regarding which groups +support which functionality. + +Valid values for pin and group names are: + + per-pin mux groups: + + These all support nvidia,function, nvidia,tristate, nvidia,pull, + nvidia,enable-input, nvidia,lock. Some support nvidia,open-drain, + nvidia,io-reset. + + clk_32k_out_pa0, uart3_cts_n_pa1, dap2_fs_pa2, dap2_sclk_pa3, + dap2_din_pa4, dap2_dout_pa5, sdmmc3_clk_pa6, sdmmc3_cmd_pa7, gmi_a17_pb0, + gmi_a18_pb1, lcd_pwr0_pb2, lcd_pclk_pb3, sdmmc3_dat3_pb4, sdmmc3_dat2_pb5, + sdmmc3_dat1_pb6, sdmmc3_dat0_pb7, uart3_rts_n_pc0, lcd_pwr1_pc1, + uart2_txd_pc2, uart2_rxd_pc3, gen1_i2c_scl_pc4, gen1_i2c_sda_pc5, + lcd_pwr2_pc6, gmi_wp_n_pc7, sdmmc3_dat5_pd0, sdmmc3_dat4_pd1, lcd_dc1_pd2, + sdmmc3_dat6_pd3, sdmmc3_dat7_pd4, vi_d1_pd5, vi_vsync_pd6, vi_hsync_pd7, + lcd_d0_pe0, lcd_d1_pe1, lcd_d2_pe2, lcd_d3_pe3, lcd_d4_pe4, lcd_d5_pe5, + lcd_d6_pe6, lcd_d7_pe7, lcd_d8_pf0, lcd_d9_pf1, lcd_d10_pf2, lcd_d11_pf3, + lcd_d12_pf4, lcd_d13_pf5, lcd_d14_pf6, lcd_d15_pf7, gmi_ad0_pg0, + gmi_ad1_pg1, gmi_ad2_pg2, gmi_ad3_pg3, gmi_ad4_pg4, gmi_ad5_pg5, + gmi_ad6_pg6, gmi_ad7_pg7, gmi_ad8_ph0, gmi_ad9_ph1, gmi_ad10_ph2, + gmi_ad11_ph3, gmi_ad12_ph4, gmi_ad13_ph5, gmi_ad14_ph6, gmi_ad15_ph7, + gmi_wr_n_pi0, gmi_oe_n_pi1, gmi_dqs_pi2, gmi_cs6_n_pi3, gmi_rst_n_pi4, + gmi_iordy_pi5, gmi_cs7_n_pi6, gmi_wait_pi7, gmi_cs0_n_pj0, lcd_de_pj1, + gmi_cs1_n_pj2, lcd_hsync_pj3, lcd_vsync_pj4, uart2_cts_n_pj5, + uart2_rts_n_pj6, gmi_a16_pj7, gmi_adv_n_pk0, gmi_clk_pk1, gmi_cs4_n_pk2, + gmi_cs2_n_pk3, gmi_cs3_n_pk4, spdif_out_pk5, spdif_in_pk6, gmi_a19_pk7, + vi_d2_pl0, vi_d3_pl1, vi_d4_pl2, vi_d5_pl3, vi_d6_pl4, vi_d7_pl5, + vi_d8_pl6, vi_d9_pl7, lcd_d16_pm0, lcd_d17_pm1, lcd_d18_pm2, lcd_d19_pm3, + lcd_d20_pm4, lcd_d21_pm5, lcd_d22_pm6, lcd_d23_pm7, dap1_fs_pn0, + dap1_din_pn1, dap1_dout_pn2, dap1_sclk_pn3, lcd_cs0_n_pn4, lcd_sdout_pn5, + lcd_dc0_pn6, hdmi_int_pn7, ulpi_data7_po0, ulpi_data0_po1, ulpi_data1_po2, + ulpi_data2_po3, ulpi_data3_po4, ulpi_data4_po5, ulpi_data5_po6, + ulpi_data6_po7, dap3_fs_pp0, dap3_din_pp1, dap3_dout_pp2, dap3_sclk_pp3, + dap4_fs_pp4, dap4_din_pp5, dap4_dout_pp6, dap4_sclk_pp7, kb_col0_pq0, + kb_col1_pq1, kb_col2_pq2, kb_col3_pq3, kb_col4_pq4, kb_col5_pq5, + kb_col6_pq6, kb_col7_pq7, kb_row0_pr0, kb_row1_pr1, kb_row2_pr2, + kb_row3_pr3, kb_row4_pr4, kb_row5_pr5, kb_row6_pr6, kb_row7_pr7, + kb_row8_ps0, kb_row9_ps1, kb_row10_ps2, kb_row11_ps3, kb_row12_ps4, + kb_row13_ps5, kb_row14_ps6, kb_row15_ps7, vi_pclk_pt0, vi_mclk_pt1, + vi_d10_pt2, vi_d11_pt3, vi_d0_pt4, gen2_i2c_scl_pt5, gen2_i2c_sda_pt6, + sdmmc4_cmd_pt7, pu0, pu1, pu2, pu3, pu4, pu5, pu6, jtag_rtck_pu7, pv0, + pv1, pv2, pv3, ddc_scl_pv4, ddc_sda_pv5, crt_hsync_pv6, crt_vsync_pv7, + lcd_cs1_n_pw0, lcd_m1_pw1, spi2_cs1_n_pw2, spi2_cs2_n_pw3, clk1_out_pw4, + clk2_out_pw5, uart3_txd_pw6, uart3_rxd_pw7, spi2_mosi_px0, spi2_miso_px1, + spi2_sck_px2, spi2_cs0_n_px3, spi1_mosi_px4, spi1_sck_px5, spi1_cs0_n_px6, + spi1_miso_px7, ulpi_clk_py0, ulpi_dir_py1, ulpi_nxt_py2, ulpi_stp_py3, + sdmmc1_dat3_py4, sdmmc1_dat2_py5, sdmmc1_dat1_py6, sdmmc1_dat0_py7, + sdmmc1_clk_pz0, sdmmc1_cmd_pz1, lcd_sdin_pz2, lcd_wr_n_pz3, lcd_sck_pz4, + sys_clk_req_pz5, pwr_i2c_scl_pz6, pwr_i2c_sda_pz7, sdmmc4_dat0_paa0, + sdmmc4_dat1_paa1, sdmmc4_dat2_paa2, sdmmc4_dat3_paa3, sdmmc4_dat4_paa4, + sdmmc4_dat5_paa5, sdmmc4_dat6_paa6, sdmmc4_dat7_paa7, pbb0, + cam_i2c_scl_pbb1, cam_i2c_sda_pbb2, pbb3, pbb4, pbb5, pbb6, pbb7, + cam_mclk_pcc0, pcc1, pcc2, sdmmc4_rst_n_pcc3, sdmmc4_clk_pcc4, + clk2_req_pcc5, pex_l2_rst_n_pcc6, pex_l2_clkreq_n_pcc7, + pex_l0_prsnt_n_pdd0, pex_l0_rst_n_pdd1, pex_l0_clkreq_n_pdd2, + pex_wake_n_pdd3, pex_l1_prsnt_n_pdd4, pex_l1_rst_n_pdd5, + pex_l1_clkreq_n_pdd6, pex_l2_prsnt_n_pdd7, clk3_out_pee0, clk3_req_pee1, + clk1_req_pee2, hdmi_cec_pee3, clk_32k_in, core_pwr_req, cpu_pwr_req, owr, + pwr_int_n. + + drive groups: + + These all support nvidia,pull-down-strength, nvidia,pull-up-strength, + nvidia,slew_rate-rising, nvidia,slew_rate-falling. Most but not all + support nvidia,high-speed-mode, nvidia,schmitt, nvidia,low-power-mode. + + ao1, ao2, at1, at2, at3, at4, at5, cdev1, cdev2, cec, crt, csus, dap1, + dap2, dap3, dap4, dbg, ddc, dev3, gma, gmb, gmc, gmd, gme, gmf, gmg, + gmh, gpv, lcd1, lcd2, owr, sdio1, sdio2, sdio3, spi, uaa, uab, uart2, + uart3, uda, vi1. + +Example: + + pinctrl@70000000 { + compatible = "nvidia,tegra30-pinmux"; + reg = < 0x70000868 0xd0 /* Pad control registers */ + 0x70003000 0x3e0 >; /* Mux registers */ + }; + +Example board file extract: + + pinctrl@70000000 { + sdmmc4_default: pinmux { + sdmmc4_clk_pcc4 { + nvidia,pins = "sdmmc4_clk_pcc4", + "sdmmc4_rst_n_pcc3"; + nvidia,function = "sdmmc4"; + nvidia,pull = <0>; + nvidia,tristate = <0>; + }; + sdmmc4_dat0_paa0 { + nvidia,pins = "sdmmc4_dat0_paa0", + "sdmmc4_dat1_paa1", + "sdmmc4_dat2_paa2", + "sdmmc4_dat3_paa3", + "sdmmc4_dat4_paa4", + "sdmmc4_dat5_paa5", + "sdmmc4_dat6_paa6", + "sdmmc4_dat7_paa7"; + nvidia,function = "sdmmc4"; + nvidia,pull = <2>; + nvidia,tristate = <0>; + }; + }; + }; + + sdhci@78000400 { + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc4_default>; + }; -- cgit v0.10.2 From 60f7f5003d69b92558e9fc0789339f2b1d41f78d Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 4 Apr 2012 09:27:50 -0600 Subject: pinctrl: tegra: Add complete device tree support Implement pinctrl_ops dt_node_to_map() and dt_free_map(). These allow complete specification of the desired pinmux configuration using device tree. Signed-off-by: Stephen Warren Acked-by: Dong Aisheng Signed-off-by: Linus Walleij diff --git a/drivers/pinctrl/pinctrl-tegra.c b/drivers/pinctrl/pinctrl-tegra.c index 41311a2..2c98fba 100644 --- a/drivers/pinctrl/pinctrl-tegra.c +++ b/drivers/pinctrl/pinctrl-tegra.c @@ -23,9 +23,11 @@ #include #include #include +#include #include #include #include +#include #include @@ -88,11 +90,214 @@ static void tegra_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev, seq_printf(s, " " DRIVER_NAME); } +static int reserve_map(struct pinctrl_map **map, unsigned *reserved_maps, + unsigned *num_maps, unsigned reserve) +{ + unsigned old_num = *reserved_maps; + unsigned new_num = *num_maps + reserve; + struct pinctrl_map *new_map; + + if (old_num >= new_num) + return 0; + + new_map = krealloc(*map, sizeof(*new_map) * new_num, GFP_KERNEL); + if (!new_map) + return -ENOMEM; + + memset(new_map + old_num, 0, (new_num - old_num) * sizeof(*new_map)); + + *map = new_map; + *reserved_maps = new_num; + + return 0; +} + +static int add_map_mux(struct pinctrl_map **map, unsigned *reserved_maps, + unsigned *num_maps, const char *group, + const char *function) +{ + if (*num_maps == *reserved_maps) + return -ENOSPC; + + (*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP; + (*map)[*num_maps].data.mux.group = group; + (*map)[*num_maps].data.mux.function = function; + (*num_maps)++; + + return 0; +} + +static int add_map_configs(struct pinctrl_map **map, unsigned *reserved_maps, + unsigned *num_maps, const char *group, + unsigned long *configs, unsigned num_configs) +{ + unsigned long *dup_configs; + + if (*num_maps == *reserved_maps) + return -ENOSPC; + + dup_configs = kmemdup(configs, num_configs * sizeof(*dup_configs), + GFP_KERNEL); + if (!dup_configs) + return -ENOMEM; + + (*map)[*num_maps].type = PIN_MAP_TYPE_CONFIGS_GROUP; + (*map)[*num_maps].data.configs.group_or_pin = group; + (*map)[*num_maps].data.configs.configs = dup_configs; + (*map)[*num_maps].data.configs.num_configs = num_configs; + (*num_maps)++; + + return 0; +} + +static int add_config(unsigned long **configs, unsigned *num_configs, + unsigned long config) +{ + unsigned old_num = *num_configs; + unsigned new_num = old_num + 1; + unsigned long *new_configs; + + new_configs = krealloc(*configs, sizeof(*new_configs) * new_num, + GFP_KERNEL); + if (!new_configs) + return -ENOMEM; + + new_configs[old_num] = config; + + *configs = new_configs; + *num_configs = new_num; + + return 0; +} + +void tegra_pinctrl_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, unsigned num_maps) +{ + int i; + + for (i = 0; i < num_maps; i++) + if (map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP) + kfree(map[i].data.configs.configs); + + kfree(map); +} + +static const struct cfg_param { + const char *property; + enum tegra_pinconf_param param; +} cfg_params[] = { + {"nvidia,pull", TEGRA_PINCONF_PARAM_PULL}, + {"nvidia,tristate", TEGRA_PINCONF_PARAM_TRISTATE}, + {"nvidia,enable-input", TEGRA_PINCONF_PARAM_ENABLE_INPUT}, + {"nvidia,open-drain", TEGRA_PINCONF_PARAM_OPEN_DRAIN}, + {"nvidia,lock", TEGRA_PINCONF_PARAM_LOCK}, + {"nvidia,io-reset", TEGRA_PINCONF_PARAM_IORESET}, + {"nvidia,high-speed-mode", TEGRA_PINCONF_PARAM_HIGH_SPEED_MODE}, + {"nvidia,schmitt", TEGRA_PINCONF_PARAM_SCHMITT}, + {"nvidia,low-power-mode", TEGRA_PINCONF_PARAM_LOW_POWER_MODE}, + {"nvidia,pull-down-strength", TEGRA_PINCONF_PARAM_DRIVE_DOWN_STRENGTH}, + {"nvidia,pull-up-strength", TEGRA_PINCONF_PARAM_DRIVE_UP_STRENGTH}, + {"nvidia,slew-rate-falling", TEGRA_PINCONF_PARAM_SLEW_RATE_FALLING}, + {"nvidia,slew-rate-rising", TEGRA_PINCONF_PARAM_SLEW_RATE_RISING}, +}; + +int tegra_pinctrl_dt_subnode_to_map(struct device_node *np, + struct pinctrl_map **map, + unsigned *reserved_maps, + unsigned *num_maps) +{ + int ret, i; + const char *function; + u32 val; + unsigned long config; + unsigned long *configs = NULL; + unsigned num_configs = 0; + unsigned reserve; + struct property *prop; + const char *group; + + ret = of_property_read_string(np, "nvidia,function", &function); + if (ret < 0) + function = NULL; + + for (i = 0; i < ARRAY_SIZE(cfg_params); i++) { + ret = of_property_read_u32(np, cfg_params[i].property, &val); + if (!ret) { + config = TEGRA_PINCONF_PACK(cfg_params[i].param, val); + ret = add_config(&configs, &num_configs, config); + if (ret < 0) + goto exit; + } + } + + reserve = 0; + if (function != NULL) + reserve++; + if (num_configs) + reserve++; + ret = of_property_count_strings(np, "nvidia,pins"); + if (ret < 0) + goto exit; + reserve *= ret; + + ret = reserve_map(map, reserved_maps, num_maps, reserve); + if (ret < 0) + goto exit; + + of_property_for_each_string(np, "nvidia,pins", prop, group) { + if (function) { + ret = add_map_mux(map, reserved_maps, num_maps, + group, function); + if (ret < 0) + goto exit; + } + + if (num_configs) { + ret = add_map_configs(map, reserved_maps, num_maps, + group, configs, num_configs); + if (ret < 0) + goto exit; + } + } + + ret = 0; + +exit: + kfree(configs); + return ret; +} + +int tegra_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np_config, + struct pinctrl_map **map, unsigned *num_maps) +{ + unsigned reserved_maps; + struct device_node *np; + int ret; + + reserved_maps = 0; + *map = NULL; + *num_maps = 0; + + for_each_child_of_node(np_config, np) { + ret = tegra_pinctrl_dt_subnode_to_map(np, map, &reserved_maps, + num_maps); + if (ret < 0) { + tegra_pinctrl_dt_free_map(pctldev, *map, *num_maps); + return ret; + } + } + + return 0; +} + static struct pinctrl_ops tegra_pinctrl_ops = { .get_groups_count = tegra_pinctrl_get_groups_count, .get_group_name = tegra_pinctrl_get_group_name, .get_group_pins = tegra_pinctrl_get_group_pins, .pin_dbg_show = tegra_pinctrl_pin_dbg_show, + .dt_node_to_map = tegra_pinctrl_dt_node_to_map, + .dt_free_map = tegra_pinctrl_dt_free_map, }; static int tegra_pinctrl_get_funcs_count(struct pinctrl_dev *pctldev) -- cgit v0.10.2 From 630e2d0494f001cc3c435cac374f92e4bde0f518 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 12 Apr 2012 19:48:42 +0200 Subject: pinctrl: mark non-EXPERIMENTAL With the finalization of the external driver API and the device tree support, this subsystem is now mature and can be promoted to non-experimental status. Acked-by: Stephen Warren Signed-off-by: Linus Walleij diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index abfb964..f73a5ea 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -4,7 +4,6 @@ config PINCTRL bool - depends on EXPERIMENTAL if PINCTRL -- cgit v0.10.2 From c736d73c9e6d9849ecb08c34c1d3917b210e8f38 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 11 Apr 2012 16:45:45 -0600 Subject: pinctrl: ifdef CONFIG_DEBUG_FS cleanup Only provide prototypes for pin{mux,conf}.c debugfs-related functions when both CONFIG_PIN* /and/ CONFIG_DEBUG_FS are enabled, otherwise provide static inlines. Signed-off-by: Stephen Warren Signed-off-by: Linus Walleij diff --git a/drivers/pinctrl/pinconf.h b/drivers/pinctrl/pinconf.h index 54510de..32b8354 100644 --- a/drivers/pinctrl/pinconf.h +++ b/drivers/pinctrl/pinconf.h @@ -19,11 +19,6 @@ int pinconf_map_to_setting(struct pinctrl_map const *map, struct pinctrl_setting *setting); void pinconf_free_setting(struct pinctrl_setting const *setting); int pinconf_apply_setting(struct pinctrl_setting const *setting); -void pinconf_show_map(struct seq_file *s, struct pinctrl_map const *map); -void pinconf_show_setting(struct seq_file *s, - struct pinctrl_setting const *setting); -void pinconf_init_device_debugfs(struct dentry *devroot, - struct pinctrl_dev *pctldev); /* * You will only be interested in these if you're using PINCONF @@ -61,6 +56,18 @@ static inline int pinconf_apply_setting(struct pinctrl_setting const *setting) return 0; } +#endif + +#if defined(CONFIG_PINMUX) && defined(CONFIG_DEBUG_FS) + +void pinconf_show_map(struct seq_file *s, struct pinctrl_map const *map); +void pinconf_show_setting(struct seq_file *s, + struct pinctrl_setting const *setting); +void pinconf_init_device_debugfs(struct dentry *devroot, + struct pinctrl_dev *pctldev); + +#else + static inline void pinconf_show_map(struct seq_file *s, struct pinctrl_map const *map) { diff --git a/drivers/pinctrl/pinmux.h b/drivers/pinctrl/pinmux.h index 6fc4700..d1a98b1c 100644 --- a/drivers/pinctrl/pinmux.h +++ b/drivers/pinctrl/pinmux.h @@ -31,12 +31,6 @@ void pinmux_free_setting(struct pinctrl_setting const *setting); int pinmux_enable_setting(struct pinctrl_setting const *setting); void pinmux_disable_setting(struct pinctrl_setting const *setting); -void pinmux_show_map(struct seq_file *s, struct pinctrl_map const *map); -void pinmux_show_setting(struct seq_file *s, - struct pinctrl_setting const *setting); -void pinmux_init_device_debugfs(struct dentry *devroot, - struct pinctrl_dev *pctldev); - #else static inline int pinmux_check_ops(struct pinctrl_dev *pctldev) @@ -89,6 +83,18 @@ static inline void pinmux_disable_setting( { } +#endif + +#if defined(CONFIG_PINMUX) && defined(CONFIG_DEBUG_FS) + +void pinmux_show_map(struct seq_file *s, struct pinctrl_map const *map); +void pinmux_show_setting(struct seq_file *s, + struct pinctrl_setting const *setting); +void pinmux_init_device_debugfs(struct dentry *devroot, + struct pinctrl_dev *pctldev); + +#else + static inline void pinmux_show_map(struct seq_file *s, struct pinctrl_map const *map) { -- cgit v0.10.2 From 6cb4158757a8629e14851e7802f3b6bfaa7d6f00 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Fri, 13 Apr 2012 10:49:06 -0600 Subject: pinctrl: allow pctldevs to decode pin config in debugfs Add a pinconf op so that pin controller drivers can decode their pin config settings for debugfs. Signed-off-by: Stephen Warren Signed-off-by: Linus Walleij diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c index 384dcc1..0133a69 100644 --- a/drivers/pinctrl/pinconf.c +++ b/drivers/pinctrl/pinconf.c @@ -379,8 +379,16 @@ int pinconf_apply_setting(struct pinctrl_setting const *setting) void pinconf_show_map(struct seq_file *s, struct pinctrl_map const *map) { + struct pinctrl_dev *pctldev; + const struct pinconf_ops *confops; int i; + pctldev = get_pinctrl_dev_from_devname(map->ctrl_dev_name); + if (pctldev) + confops = pctldev->desc->confops; + else + confops = NULL; + switch (map->type) { case PIN_MAP_TYPE_CONFIGS_PIN: seq_printf(s, "pin "); @@ -394,8 +402,15 @@ void pinconf_show_map(struct seq_file *s, struct pinctrl_map const *map) seq_printf(s, "%s\n", map->data.configs.group_or_pin); - for (i = 0; i < map->data.configs.num_configs; i++) - seq_printf(s, "config %08lx\n", map->data.configs.configs[i]); + for (i = 0; i < map->data.configs.num_configs; i++) { + seq_printf(s, "config "); + if (confops && confops->pin_config_config_dbg_show) + confops->pin_config_config_dbg_show(pctldev, s, + map->data.configs.configs[i]); + else + seq_printf(s, "%08lx", map->data.configs.configs[i]); + seq_printf(s, "\n"); + } } void pinconf_show_setting(struct seq_file *s, @@ -403,6 +418,7 @@ void pinconf_show_setting(struct seq_file *s, { struct pinctrl_dev *pctldev = setting->pctldev; const struct pinctrl_ops *pctlops = pctldev->desc->pctlops; + const struct pinconf_ops *confops = pctldev->desc->confops; struct pin_desc *desc; int i; @@ -428,8 +444,15 @@ void pinconf_show_setting(struct seq_file *s, * FIXME: We should really get the pin controler to dump the config * values, so they can be decoded to something meaningful. */ - for (i = 0; i < setting->data.configs.num_configs; i++) - seq_printf(s, " %08lx", setting->data.configs.configs[i]); + for (i = 0; i < setting->data.configs.num_configs; i++) { + seq_printf(s, " "); + if (confops && confops->pin_config_config_dbg_show) + confops->pin_config_config_dbg_show(pctldev, s, + setting->data.configs.configs[i]); + else + seq_printf(s, "%08lx", + setting->data.configs.configs[i]); + } seq_printf(s, "\n"); } diff --git a/include/linux/pinctrl/pinconf.h b/include/linux/pinctrl/pinconf.h index ec431f0..7b9d5f0 100644 --- a/include/linux/pinctrl/pinconf.h +++ b/include/linux/pinctrl/pinconf.h @@ -33,6 +33,8 @@ struct seq_file; * per-device info for a certain pin in debugfs * @pin_config_group_dbg_show: optional debugfs display hook that will provide * per-device info for a certain group in debugfs + * @pin_config_config_dbg_show: optional debugfs display hook that will decode + * and display a driver's pin configuration parameter */ struct pinconf_ops { #ifdef CONFIG_GENERIC_PINCONF @@ -56,6 +58,9 @@ struct pinconf_ops { void (*pin_config_group_dbg_show) (struct pinctrl_dev *pctldev, struct seq_file *s, unsigned selector); + void (*pin_config_config_dbg_show) (struct pinctrl_dev *pctldev, + struct seq_file *s, + unsigned long config); }; #endif -- cgit v0.10.2 From 96593afe6d724ffca309340afa914f8e1c6719fd Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 16 Apr 2012 14:22:34 +0530 Subject: pinctrl: pinconf: fix compilation error if PINCONF is not selected When we compile pinctrl layer for platforms without CONFIG_PINCONF, we get following compilation errors: drivers/built-in.o: In function `pinctrl_show': linux-2.6/drivers/pinctrl/core.c:1116: undefined reference to `pinconf_show_setting' drivers/built-in.o: In function `pinctrl_maps_show': linux-2.6/drivers/pinctrl/core.c:1071: undefined reference to `pinconf_show_map' drivers/built-in.o: In function `pinctrl_init_device_debugfs': linux-2.6/drivers/pinctrl/core.c:1224: undefined reference to `pinconf_init_device_debugfs' make[1]: *** [.tmp_vmlinux1] Error 1 This patch fixes this. Signed-off-by: Viresh Kumar Signed-off-by: Linus Walleij diff --git a/drivers/pinctrl/pinconf.h b/drivers/pinctrl/pinconf.h index 32b8354..e3ed8cb 100644 --- a/drivers/pinctrl/pinconf.h +++ b/drivers/pinctrl/pinconf.h @@ -58,7 +58,7 @@ static inline int pinconf_apply_setting(struct pinctrl_setting const *setting) #endif -#if defined(CONFIG_PINMUX) && defined(CONFIG_DEBUG_FS) +#if defined(CONFIG_PINCONF) && defined(CONFIG_DEBUG_FS) void pinconf_show_map(struct seq_file *s, struct pinctrl_map const *map); void pinconf_show_setting(struct seq_file *s, -- cgit v0.10.2 From 2aeefe0233174015aef19dc06aac02a1119a44be Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Mon, 16 Apr 2012 22:07:24 +0800 Subject: pinctrl: a minor fix of pin config debug information Signed-off-by: Dong Aisheng Signed-off-by: Linus Walleij diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c index 0133a69..14f48c9 100644 --- a/drivers/pinctrl/pinconf.c +++ b/drivers/pinctrl/pinconf.c @@ -478,7 +478,7 @@ static int pinconf_pins_show(struct seq_file *s, void *what) return 0; seq_puts(s, "Pin config settings per pin\n"); - seq_puts(s, "Format: pin (name): pinmux setting array\n"); + seq_puts(s, "Format: pin (name): configs\n"); mutex_lock(&pinctrl_mutex); @@ -529,7 +529,7 @@ static int pinconf_groups_show(struct seq_file *s, void *what) return 0; seq_puts(s, "Pin config settings per pin group\n"); - seq_puts(s, "Format: group (name): pinmux setting array\n"); + seq_puts(s, "Format: group (name): configs\n"); mutex_lock(&pinctrl_mutex); -- cgit v0.10.2 From 6d4ca1fb467932773da7b808c52f3d7ef4461ba0 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Mon, 16 Apr 2012 10:51:00 -0600 Subject: pinctrl: implement devm_pinctrl_get()/put() These functions allow the driver core to automatically clean up any allocations made by drivers, thus leading to simplified drivers. Signed-off-by: Stephen Warren Signed-off-by: Linus Walleij diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt index 2a596a4..ef4fa7b 100644 --- a/Documentation/driver-model/devres.txt +++ b/Documentation/driver-model/devres.txt @@ -276,3 +276,7 @@ REGULATOR devm_regulator_get() devm_regulator_put() devm_regulator_bulk_get() + +PINCTRL + devm_pinctrl_get() + devm_pinctrl_put() diff --git a/Documentation/pinctrl.txt b/Documentation/pinctrl.txt index 4431c3e7..e40f4b4 100644 --- a/Documentation/pinctrl.txt +++ b/Documentation/pinctrl.txt @@ -945,13 +945,13 @@ case), we define a mapping like this: The result of grabbing this mapping from the device with something like this (see next paragraph): - p = pinctrl_get(dev); + p = devm_pinctrl_get(dev); s = pinctrl_lookup_state(p, "8bit"); ret = pinctrl_select_state(p, s); or more simply: - p = pinctrl_get_select(dev, "8bit"); + p = devm_pinctrl_get_select(dev, "8bit"); Will be that you activate all the three bottom records in the mapping at once. Since they share the same name, pin controller device, function and @@ -985,7 +985,7 @@ foo_probe() /* Allocate a state holder named "foo" etc */ struct foo_state *foo = ...; - foo->p = pinctrl_get(&device); + foo->p = devm_pinctrl_get(&device); if (IS_ERR(foo->p)) { /* FIXME: clean up "foo" here */ return PTR_ERR(foo->p); @@ -993,24 +993,17 @@ foo_probe() foo->s = pinctrl_lookup_state(foo->p, PINCTRL_STATE_DEFAULT); if (IS_ERR(foo->s)) { - pinctrl_put(foo->p); /* FIXME: clean up "foo" here */ return PTR_ERR(s); } ret = pinctrl_select_state(foo->s); if (ret < 0) { - pinctrl_put(foo->p); /* FIXME: clean up "foo" here */ return ret; } } -foo_remove() -{ - pinctrl_put(state->p); -} - This get/lookup/select/put sequence can just as well be handled by bus drivers if you don't want each and every driver to handle it and you know the arrangement on your bus. @@ -1022,6 +1015,11 @@ The semantics of the pinctrl APIs are: kernel memory to hold the pinmux state. All mapping table parsing or similar slow operations take place within this API. +- devm_pinctrl_get() is a variant of pinctrl_get() that causes pinctrl_put() + to be called automatically on the retrieved pointer when the associated + device is removed. It is recommended to use this function over plain + pinctrl_get(). + - pinctrl_lookup_state() is called in process context to obtain a handle to a specific state for a the client device. This operation may be slow too. @@ -1034,14 +1032,25 @@ The semantics of the pinctrl APIs are: - pinctrl_put() frees all information associated with a pinctrl handle. +- devm_pinctrl_put() is a variant of pinctrl_put() that may be used to + explicitly destroy a pinctrl object returned by devm_pinctrl_get(). + However, use of this function will be rare, due to the automatic cleanup + that will occur even without calling it. + + pinctrl_get() must be paired with a plain pinctrl_put(). + pinctrl_get() may not be paired with devm_pinctrl_put(). + devm_pinctrl_get() can optionally be paired with devm_pinctrl_put(). + devm_pinctrl_get() may not be paired with plain pinctrl_put(). + Usually the pin control core handled the get/put pair and call out to the device drivers bookkeeping operations, like checking available functions and the associated pins, whereas the enable/disable pass on to the pin controller driver which takes care of activating and/or deactivating the mux setting by quickly poking some registers. -The pins are allocated for your device when you issue the pinctrl_get() call, -after this you should be able to see this in the debugfs listing of all pins. +The pins are allocated for your device when you issue the devm_pinctrl_get() +call, after this you should be able to see this in the debugfs listing of all +pins. NOTE: the pinctrl system will return -EPROBE_DEFER if it cannot find the requested pinctrl handles, for example if the pinctrl driver has not yet @@ -1092,13 +1101,13 @@ it, disables and releases it, and muxes it in on the pins defined by group B: #include -foo_switch() -{ - struct pinctrl *p; - struct pinctrl_state *s1, *s2; +struct pinctrl *p; +struct pinctrl_state *s1, *s2; +foo_probe() +{ /* Setup */ - p = pinctrl_get(&device); + p = devm_pinctrl_get(&device); if (IS_ERR(p)) ... @@ -1109,7 +1118,10 @@ foo_switch() s2 = pinctrl_lookup_state(foo->p, "pos-B"); if (IS_ERR(s2)) ... +} +foo_switch() +{ /* Enable on position A */ ret = pinctrl_select_state(s1); if (ret < 0) @@ -1123,8 +1135,6 @@ foo_switch() ... ... - - pinctrl_put(p); } The above has to be done from process context. diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index 59027ab..2eaa187 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include "core.h" @@ -801,6 +802,61 @@ int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state) } EXPORT_SYMBOL_GPL(pinctrl_select_state); +static void devm_pinctrl_release(struct device *dev, void *res) +{ + pinctrl_put(*(struct pinctrl **)res); +} + +/** + * struct devm_pinctrl_get() - Resource managed pinctrl_get() + * @dev: the device to obtain the handle for + * + * If there is a need to explicitly destroy the returned struct pinctrl, + * devm_pinctrl_put() should be used, rather than plain pinctrl_put(). + */ +struct pinctrl *devm_pinctrl_get(struct device *dev) +{ + struct pinctrl **ptr, *p; + + ptr = devres_alloc(devm_pinctrl_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + p = pinctrl_get(dev); + if (!IS_ERR(p)) { + *ptr = p; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return p; +} +EXPORT_SYMBOL_GPL(devm_pinctrl_get); + +static int devm_pinctrl_match(struct device *dev, void *res, void *data) +{ + struct pinctrl **p = res; + + return *p == data; +} + +/** + * devm_pinctrl_put() - Resource managed pinctrl_put() + * @p: the pinctrl handle to release + * + * Deallocate a struct pinctrl obtained via devm_pinctrl_get(). Normally + * this function will not need to be called and the resource management + * code will ensure that the resource is freed. + */ +void devm_pinctrl_put(struct pinctrl *p) +{ + WARN_ON(devres_destroy(p->dev, devm_pinctrl_release, + devm_pinctrl_match, p)); + pinctrl_put(p); +} +EXPORT_SYMBOL_GPL(devm_pinctrl_put); + int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps, bool dup, bool locked) { diff --git a/include/linux/pinctrl/consumer.h b/include/linux/pinctrl/consumer.h index 191e726..6dd96fb 100644 --- a/include/linux/pinctrl/consumer.h +++ b/include/linux/pinctrl/consumer.h @@ -36,6 +36,9 @@ extern struct pinctrl_state * __must_check pinctrl_lookup_state( const char *name); extern int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *s); +extern struct pinctrl * __must_check devm_pinctrl_get(struct device *dev); +extern void devm_pinctrl_put(struct pinctrl *p); + #else /* !CONFIG_PINCTRL */ static inline int pinctrl_request_gpio(unsigned gpio) @@ -79,6 +82,15 @@ static inline int pinctrl_select_state(struct pinctrl *p, return 0; } +static inline struct pinctrl * __must_check devm_pinctrl_get(struct device *dev) +{ + return NULL; +} + +static inline void devm_pinctrl_put(struct pinctrl *p) +{ +} + #endif /* CONFIG_PINCTRL */ static inline struct pinctrl * __must_check pinctrl_get_select( @@ -113,6 +125,38 @@ static inline struct pinctrl * __must_check pinctrl_get_select_default( return pinctrl_get_select(dev, PINCTRL_STATE_DEFAULT); } +static inline struct pinctrl * __must_check devm_pinctrl_get_select( + struct device *dev, const char *name) +{ + struct pinctrl *p; + struct pinctrl_state *s; + int ret; + + p = devm_pinctrl_get(dev); + if (IS_ERR(p)) + return p; + + s = pinctrl_lookup_state(p, name); + if (IS_ERR(s)) { + devm_pinctrl_put(p); + return ERR_PTR(PTR_ERR(s)); + } + + ret = pinctrl_select_state(p, s); + if (ret < 0) { + devm_pinctrl_put(p); + return ERR_PTR(ret); + } + + return p; +} + +static inline struct pinctrl * __must_check devm_pinctrl_get_select_default( + struct device *dev) +{ + return devm_pinctrl_get_select(dev, PINCTRL_STATE_DEFAULT); +} + #ifdef CONFIG_PINCONF extern int pin_config_get(const char *dev_name, const char *name, -- cgit v0.10.2 From d0bd8df56ebffe4a5ca42e27aca2a1243c70ed53 Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Tue, 17 Apr 2012 15:00:45 +0800 Subject: pinctrl: show pin name when request pins Pin name is more useful to users. Acked-by: Stephen Warren Signed-off-by: Dong Aisheng Signed-off-by: Linus Walleij diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c index c494c37..fa0357b 100644 --- a/drivers/pinctrl/pinmux.c +++ b/drivers/pinctrl/pinmux.c @@ -88,8 +88,6 @@ static int pin_request(struct pinctrl_dev *pctldev, const struct pinmux_ops *ops = pctldev->desc->pmxops; int status = -EINVAL; - dev_dbg(pctldev->dev, "request pin %d for %s\n", pin, owner); - desc = pin_desc_get(pctldev, pin); if (desc == NULL) { dev_err(pctldev->dev, @@ -97,6 +95,9 @@ static int pin_request(struct pinctrl_dev *pctldev, goto out; } + dev_dbg(pctldev->dev, "request pin %d (%s) for %s\n", + pin, desc->name, owner); + if (gpio_range) { /* There's no need to support multiple GPIO requests */ if (desc->gpio_owner) { -- cgit v0.10.2 From dcb5dbc305b975cccf40942feba40964069541d3 Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Tue, 17 Apr 2012 15:00:46 +0800 Subject: pinctrl: show pin name for pingroups in sysfs Pin name is more useful to users. After change, when cat pingroups in sysfs, it becomes: root@freescale /sys/kernel/debug/pinctrl/20e0000.iomuxc$ cat pingroups registered pin groups: group: uart4grp-1 pin 219 (MX6Q_PAD_KEY_ROW0) pin 218 (MX6Q_PAD_KEY_COL0) group: usdhc4grp-1 pin 305 (MX6Q_PAD_SD4_CMD) pin 306 (MX6Q_PAD_SD4_CLK) pin 315 (MX6Q_PAD_SD4_DAT0) pin 316 (MX6Q_PAD_SD4_DAT1) pin 317 (MX6Q_PAD_SD4_DAT2) pin 318 (MX6Q_PAD_SD4_DAT3) pin 319 (MX6Q_PAD_SD4_DAT4) pin 320 (MX6Q_PAD_SD4_DAT5) pin 321 (MX6Q_PAD_SD4_DAT6) pin 322 (MX6Q_PAD_SD4_DAT7) Acked-by: Stephen Warren Signed-off-by: Dong Aisheng Signed-off-by: Linus Walleij diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index 2eaa187..5cd5a5a 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -126,6 +126,25 @@ int pin_get_from_name(struct pinctrl_dev *pctldev, const char *name) } /** + * pin_get_name_from_id() - look up a pin name from a pin id + * @pctldev: the pin control device to lookup the pin on + * @name: the name of the pin to look up + */ +const char *pin_get_name(struct pinctrl_dev *pctldev, const unsigned pin) +{ + const struct pin_desc *desc; + + desc = pin_desc_get(pctldev, pin); + if (desc == NULL) { + dev_err(pctldev->dev, "failed to get pin(%d) name\n", + pin); + return NULL; + } + + return desc->name; +} + +/** * pin_is_valid() - check if pin exists on controller * @pctldev: the pin control device to check the pin on * @pin: pin to check, use the local pin controller index number @@ -1011,6 +1030,7 @@ static int pinctrl_groups_show(struct seq_file *s, void *what) const unsigned *pins; unsigned num_pins; const char *gname = ops->get_group_name(pctldev, selector); + const char *pname; int ret; int i; @@ -1020,10 +1040,14 @@ static int pinctrl_groups_show(struct seq_file *s, void *what) seq_printf(s, "%s [ERROR GETTING PINS]\n", gname); else { - seq_printf(s, "group: %s, pins = [ ", gname); - for (i = 0; i < num_pins; i++) - seq_printf(s, "%d ", pins[i]); - seq_puts(s, "]\n"); + seq_printf(s, "group: %s\n", gname); + for (i = 0; i < num_pins; i++) { + pname = pin_get_name(pctldev, pins[i]); + if (WARN_ON(!pname)) + return -EINVAL; + seq_printf(s, "pin %d (%s)\n", pins[i], pname); + } + seq_puts(s, "\n"); } selector++; } diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h index 98ae808..1f40ff6 100644 --- a/drivers/pinctrl/core.h +++ b/drivers/pinctrl/core.h @@ -148,6 +148,7 @@ struct pin_desc { struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *dev_name); int pin_get_from_name(struct pinctrl_dev *pctldev, const char *name); +const char *pin_get_name(struct pinctrl_dev *pctldev, const unsigned pin); int pinctrl_get_group_selector(struct pinctrl_dev *pctldev, const char *pin_group); -- cgit v0.10.2