diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-20 21:23:30 +0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-20 21:23:30 +0400 |
commit | 8a3a11f91def34424b1995cb54ccd658efde8568 (patch) | |
tree | 6b97487ffea8cb7d8c280bb88fd681335f91cf73 /drivers/pinctrl/core.c | |
parent | 8909ff652ddfc83ecdf450f96629c25489d88f77 (diff) | |
parent | ade158eb53eed40f6090e9f7ee6ee3513ec1eec4 (diff) | |
download | linux-8a3a11f91def34424b1995cb54ccd658efde8568.tar.xz |
Merge tag 'pinctrl-for-v3.9' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl
Pull pinctrl changes from Linus Walleij:
"These are the main pinctrl changes for the v3.9 merge window. The
most interesting change by far is how the device core grabs pinctrl
default handles avoiding the need to stick boilerplate into driver
consumers.
- Grabbing of default pinctrl handles from the device core. These
are the hunks hitting drivers/base. All is ACKed by Greg, after a
long discussion about different alternatives.
- Some stuff also touches the MFD and ARM SoC trees, this has been
coordinated and ACKed.
- New drivers for:
- The Tegra 114 sub-SoC
- Allwinner sunxi
- New ABx500 driver and sub-SoC drivers for AB8500, AB8505, AB9540
and AB8540.
- Make it possible for hogged pins to enter a sleep mode, and make it
possible for drivers to control that mode.
- Various clean-up, extensions and device tree support to various pin
controllers."
* tag 'pinctrl-for-v3.9' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl: (68 commits)
pinctrl: tegra: add clfvs function to Tegra114 support
pinctrl: generic: rename input schmitt disable
pinctrl/pinconfig: add debug interface
pinctrl: samsung: remove duplicated line
ARM: ux500: use real AB8500 IRQ numbers instead of virtual ones
ARM: ux500: remove irq_base property from platform_data
pinctrl/abx500: use direct IRQ defines
pinctrl/abx500: replace IRQ offsets with table read-in values
pinctrl/abx500: move IRQ handling to ab8500-core
pinctrl: exynos5440: remove erroneous __init
pinctrl/abx500: adjust offset for get_mode()
pinctrl/abx500: add Device Tree support
pinctrl/abx500: align GPIO cluster boundaries
pinctrl/abx500: prevent error path from corrupting returning error
pinctrl: sunxi: add of_xlate function
pinctrl/lantiq: fix pin number in ltq_pmx_gpio_request_enable
pinctrl/lantiq: add functionality to falcon_pinconf_dbg_show
pinctrl/lantiq: fix pinconfig parameters
pinctrl/lantiq: one of the boot leds was defined incorrectly
pinctrl/lantiq: only probe available pad controllers
...
Diffstat (limited to 'drivers/pinctrl/core.c')
-rw-r--r-- | drivers/pinctrl/core.c | 118 |
1 files changed, 91 insertions, 27 deletions
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index 59f5a965bdc4..b0de6e7f1fdb 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -14,6 +14,7 @@ #define pr_fmt(fmt) "pinctrl core: " fmt #include <linux/kernel.h> +#include <linux/kref.h> #include <linux/export.h> #include <linux/init.h> #include <linux/device.h> @@ -31,17 +32,6 @@ #include "pinmux.h" #include "pinconf.h" -/** - * struct pinctrl_maps - a list item containing part of the mapping table - * @node: mapping table list node - * @maps: array of mapping table entries - * @num_maps: the number of entries in @maps - */ -struct pinctrl_maps { - struct list_head node; - struct pinctrl_map const *maps; - unsigned num_maps; -}; static bool pinctrl_dummy_state; @@ -55,13 +45,8 @@ LIST_HEAD(pinctrldev_list); static LIST_HEAD(pinctrl_list); /* List of pinctrl maps (struct pinctrl_maps) */ -static LIST_HEAD(pinctrl_maps); +LIST_HEAD(pinctrl_maps); -#define for_each_maps(_maps_node_, _i_, _map_) \ - list_for_each_entry(_maps_node_, &pinctrl_maps, node) \ - for (_i_ = 0, _map_ = &_maps_node_->maps[_i_]; \ - _i_ < _maps_node_->num_maps; \ - _i_++, _map_ = &_maps_node_->maps[_i_]) /** * pinctrl_provide_dummies() - indicate if pinctrl provides dummy state support @@ -83,6 +68,12 @@ const char *pinctrl_dev_get_name(struct pinctrl_dev *pctldev) } EXPORT_SYMBOL_GPL(pinctrl_dev_get_name); +const char *pinctrl_dev_get_devname(struct pinctrl_dev *pctldev) +{ + return dev_name(pctldev->dev); +} +EXPORT_SYMBOL_GPL(pinctrl_dev_get_devname); + void *pinctrl_dev_get_drvdata(struct pinctrl_dev *pctldev) { return pctldev->driver_data; @@ -609,13 +600,16 @@ 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_info(p->dev, "unknown pinctrl device %s in map entry, deferring probe", - map->ctrl_dev_name); kfree(setting); + /* Do not defer probing of hogs (circular loop) */ + if (!strcmp(map->ctrl_dev_name, map->dev_name)) + return -ENODEV; /* * OK let us guess that the driver is not there yet, and * let's defer obtaining this pinctrl handle to later... */ + dev_info(p->dev, "unknown pinctrl device %s in map entry, deferring probe", + map->ctrl_dev_name); return -EPROBE_DEFER; } @@ -694,11 +688,31 @@ static struct pinctrl *create_pinctrl(struct device *dev) continue; ret = add_setting(p, map); - if (ret < 0) { + /* + * At this point the adding of a setting may: + * + * - Defer, if the pinctrl device is not yet available + * - Fail, if the pinctrl device is not yet available, + * AND the setting is a hog. We cannot defer that, since + * the hog will kick in immediately after the device + * is registered. + * + * If the error returned was not -EPROBE_DEFER then we + * accumulate the errors to see if we end up with + * an -EPROBE_DEFER later, as that is the worst case. + */ + if (ret == -EPROBE_DEFER) { pinctrl_put_locked(p, false); return ERR_PTR(ret); } } + if (ret < 0) { + /* If some other error than deferral occured, return here */ + pinctrl_put_locked(p, false); + return ERR_PTR(ret); + } + + kref_init(&p->users); /* Add the pinctrl handle to the global list */ list_add_tail(&p->node, &pinctrl_list); @@ -713,9 +727,17 @@ static struct pinctrl *pinctrl_get_locked(struct device *dev) if (WARN_ON(!dev)) return ERR_PTR(-EINVAL); + /* + * See if somebody else (such as the device core) has already + * obtained a handle to the pinctrl for this device. In that case, + * return another pointer to it. + */ p = find_pinctrl(dev); - if (p != NULL) - return ERR_PTR(-EBUSY); + if (p != NULL) { + dev_dbg(dev, "obtain a copy of previously claimed pinctrl\n"); + kref_get(&p->users); + return p; + } return create_pinctrl(dev); } @@ -771,13 +793,24 @@ static void pinctrl_put_locked(struct pinctrl *p, bool inlist) } /** - * pinctrl_put() - release a previously claimed pinctrl handle + * pinctrl_release() - release the pinctrl handle + * @kref: the kref in the pinctrl being released + */ +static void pinctrl_release(struct kref *kref) +{ + struct pinctrl *p = container_of(kref, struct pinctrl, users); + + pinctrl_put_locked(p, true); +} + +/** + * pinctrl_put() - decrease use count on a previously claimed pinctrl handle * @p: the pinctrl handle to release */ void pinctrl_put(struct pinctrl *p) { mutex_lock(&pinctrl_mutex); - pinctrl_put_locked(p, true); + kref_put(&p->users, pinctrl_release); mutex_unlock(&pinctrl_mutex); } EXPORT_SYMBOL_GPL(pinctrl_put); @@ -1055,6 +1088,30 @@ void pinctrl_unregister_map(struct pinctrl_map const *map) } } +/** + * pinctrl_force_sleep() - turn a given controller device into sleep state + * @pctldev: pin controller device + */ +int pinctrl_force_sleep(struct pinctrl_dev *pctldev) +{ + if (!IS_ERR(pctldev->p) && !IS_ERR(pctldev->hog_sleep)) + return pinctrl_select_state(pctldev->p, pctldev->hog_sleep); + return 0; +} +EXPORT_SYMBOL_GPL(pinctrl_force_sleep); + +/** + * pinctrl_force_default() - turn a given controller device into default state + * @pctldev: pin controller device + */ +int pinctrl_force_default(struct pinctrl_dev *pctldev) +{ + if (!IS_ERR(pctldev->p) && !IS_ERR(pctldev->hog_default)) + return pinctrl_select_state(pctldev->p, pctldev->hog_default); + return 0; +} +EXPORT_SYMBOL_GPL(pinctrl_force_default); + #ifdef CONFIG_DEBUG_FS static int pinctrl_pins_show(struct seq_file *s, void *what) @@ -1500,16 +1557,23 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc, pctldev->p = pinctrl_get_locked(pctldev->dev); if (!IS_ERR(pctldev->p)) { - struct pinctrl_state *s = + pctldev->hog_default = pinctrl_lookup_state_locked(pctldev->p, PINCTRL_STATE_DEFAULT); - if (IS_ERR(s)) { + if (IS_ERR(pctldev->hog_default)) { dev_dbg(dev, "failed to lookup the default state\n"); } else { - if (pinctrl_select_state_locked(pctldev->p, s)) + if (pinctrl_select_state_locked(pctldev->p, + pctldev->hog_default)) dev_err(dev, "failed to select default state\n"); } + + pctldev->hog_sleep = + pinctrl_lookup_state_locked(pctldev->p, + PINCTRL_STATE_SLEEP); + if (IS_ERR(pctldev->hog_sleep)) + dev_dbg(dev, "failed to lookup the sleep state\n"); } mutex_unlock(&pinctrl_mutex); |