diff options
Diffstat (limited to 'drivers/pinctrl/core.c')
-rw-r--r-- | drivers/pinctrl/core.c | 244 |
1 files changed, 196 insertions, 48 deletions
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index df6296c5f47b..c3b331b74fa0 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -23,9 +23,11 @@ #include <linux/sysfs.h> #include <linux/debugfs.h> #include <linux/seq_file.h> +#include <linux/pinctrl/consumer.h> #include <linux/pinctrl/pinctrl.h> #include <linux/pinctrl/machine.h> #include "core.h" +#include "devicetree.h" #include "pinmux.h" #include "pinconf.h" @@ -41,11 +43,13 @@ struct pinctrl_maps { unsigned num_maps; }; +static bool pinctrl_dummy_state; + /* Mutex taken by all entry points */ 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); @@ -59,6 +63,19 @@ static LIST_HEAD(pinctrl_maps); _i_ < _maps_node_->num_maps; \ i++, _map_ = &_maps_node_->maps[_i_]) +/** + * pinctrl_provide_dummies() - indicate if pinctrl provides dummy state support + * + * Usually this function is called by platforms without pinctrl driver support + * but run with some shared drivers using pinctrl APIs. + * After calling this function, the pinctrl core will return successfully + * with creating a dummy state for the driver to keep going smoothly. + */ +void pinctrl_provide_dummies(void) +{ + pinctrl_dummy_state = true; +} + const char *pinctrl_dev_get_name(struct pinctrl_dev *pctldev) { /* We're not allowed to register devices without name */ @@ -124,6 +141,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 @@ -255,7 +291,8 @@ pinctrl_match_gpio_range(struct pinctrl_dev *pctldev, unsigned gpio) * * Find the pin controller handling a certain GPIO pin from the pinspace of * the GPIO subsystem, return the device and the matching GPIO range. Returns - * negative if the GPIO range could not be found in any device. + * -EPROBE_DEFER if the GPIO range could not be found in any device since it + * may still have not been registered. */ static int pinctrl_get_device_gpio_range(unsigned gpio, struct pinctrl_dev **outdev, @@ -275,7 +312,7 @@ static int pinctrl_get_device_gpio_range(unsigned gpio, } } - return -EINVAL; + return -EPROBE_DEFER; } /** @@ -318,9 +355,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)) { @@ -360,7 +398,7 @@ int pinctrl_request_gpio(unsigned gpio) ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range); if (ret) { mutex_unlock(&pinctrl_mutex); - return -EINVAL; + return ret; } /* Convert to the pin controllers number space */ @@ -516,11 +554,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) { @@ -579,6 +620,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 +710,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); @@ -685,8 +735,18 @@ static struct pinctrl_state *pinctrl_lookup_state_locked(struct pinctrl *p, struct pinctrl_state *state; state = find_state(p, name); - if (!state) - return ERR_PTR(-ENODEV); + if (!state) { + if (pinctrl_dummy_state) { + /* create dummy state */ + dev_dbg(p->dev, "using pinctrl dummy state (%s)\n", + name); + state = create_state(p, name); + if (IS_ERR(state)) + return state; + } else { + return ERR_PTR(-ENODEV); + } + } return state; } @@ -787,15 +847,63 @@ 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); +} + /** - * 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 + * 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(). */ -int pinctrl_register_mappings(struct pinctrl_map const *maps, - unsigned num_maps) +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) { int i, ret; struct pinctrl_maps *maps_node; @@ -829,13 +937,13 @@ int pinctrl_register_mappings(struct pinctrl_map const *maps, case PIN_MAP_TYPE_MUX_GROUP: ret = pinmux_validate_map(&maps[i], i); if (ret < 0) - return 0; + return ret; break; case PIN_MAP_TYPE_CONFIGS_PIN: case PIN_MAP_TYPE_CONFIGS_GROUP: ret = pinconf_validate_map(&maps[i], i); if (ret < 0) - return 0; + return ret; break; default: pr_err("failed to register map %s (%d): invalid type given\n", @@ -851,20 +959,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) @@ -906,15 +1046,17 @@ 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); + const char *pname; int ret; int i; @@ -924,10 +1066,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++; } @@ -1226,11 +1372,14 @@ 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; + if (ops->dt_node_to_map && !ops->dt_free_map) + return -EINVAL; + return 0; } @@ -1268,37 +1417,29 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc, /* check core ops for sanity */ ret = pinctrl_check_ops(pctldev); if (ret) { - pr_err("%s pinctrl ops lacks necessary functions\n", - pctldesc->name); + dev_err(dev, "pinctrl ops lacks necessary functions\n"); goto out_err; } /* If we're implementing pinmuxing, check the ops for sanity */ if (pctldesc->pmxops) { ret = pinmux_check_ops(pctldev); - if (ret) { - pr_err("%s pinmux ops lacks necessary functions\n", - pctldesc->name); + if (ret) goto out_err; - } } /* If we're implementing pinconfig, check the ops for sanity */ if (pctldesc->confops) { ret = pinconf_check_ops(pctldev); - if (ret) { - pr_err("%s pin config ops lacks necessary functions\n", - pctldesc->name); + if (ret) goto out_err; - } } /* Register all the pins */ - pr_debug("try to register %d pins on %s...\n", - pctldesc->npins, pctldesc->name); + dev_dbg(dev, "try to register %d pins ...\n", pctldesc->npins); ret = pinctrl_register_pins(pctldev, pctldesc->pins, pctldesc->npins); if (ret) { - pr_err("error during pin registration\n"); + dev_err(dev, "error during pin registration\n"); pinctrl_free_pindescs(pctldev, pctldesc->pins, pctldesc->npins); goto out_err; @@ -1313,8 +1454,15 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc, struct pinctrl_state *s = pinctrl_lookup_state_locked(pctldev->p, PINCTRL_STATE_DEFAULT); - if (!IS_ERR(s)) - pinctrl_select_state_locked(pctldev->p, s); + if (IS_ERR(s)) { + dev_dbg(dev, "failed to lookup the default state\n"); + } else { + ret = pinctrl_select_state_locked(pctldev->p, s); + if (ret) { + dev_err(dev, + "failed to select default state\n"); + } + } } mutex_unlock(&pinctrl_mutex); |