summaryrefslogtreecommitdiffstats
path: root/drivers/pinctrl/core.c
diff options
context:
space:
mode:
authorStephen Warren <swarren@nvidia.com>2012-03-02 13:05:45 -0700
committerLinus Walleij <linus.walleij@linaro.org>2012-03-05 11:20:50 +0100
commit7ecdb16fe63e5b356335ebdc236adfb48cef31e1 (patch)
tree036d9939c64f98e1f85343f15c12ad83c9a2a890 /drivers/pinctrl/core.c
parent57b676f9c1b7cd84397fe5a86c9bd2788ac4bd32 (diff)
downloadlinux-7ecdb16fe63e5b356335ebdc236adfb48cef31e1.tar.bz2
pinctrl: refactor struct pinctrl handling in core.c vs pinmux.c
This change separates two aspects of struct pinctrl: a) The data representation of the parsed mapping table, into: 1) The top-level struct pinctrl object, a single entity returned by pinctrl_get(). 2) The parsed version of each mapping table entry, struct pinctrl_setting, of which there is one per mapping table entry. b) The code that handles this; the code for (1) above is in core.c, and the code to parse/execute each entry in (2) above is in pinmux.c, while the iteration over multiple settings is lifted to core.c. This will allow the following future changes: 1) pinctrl_get() API rework, so that struct pinctrl represents all states for the device, and the device can select between them without calling put()/get() again. 2) To support that, a struct pinctrl_state object will be inserted into the data model between the struct pinctrl and struct pinctrl_setting. 3) The mapping table will be extended to allow specification of pin config settings too. To support this, struct pinctrl_setting will be enhanced to store either mux settings or config settings, and functions will be added to pinconf.c to parse/execute pin configuration settings. Signed-off-by: Stephen Warren <swarren@nvidia.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Acked-by: Dong Aisheng <dong.aisheng@linaro.org> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/pinctrl/core.c')
-rw-r--r--drivers/pinctrl/core.c105
1 files changed, 66 insertions, 39 deletions
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
index aefc3394db91..535f8d53c289 100644
--- a/drivers/pinctrl/core.c
+++ b/drivers/pinctrl/core.c
@@ -460,14 +460,15 @@ EXPORT_SYMBOL_GPL(pinctrl_gpio_direction_output);
static struct pinctrl *pinctrl_get_locked(struct device *dev, const char *name)
{
- struct pinctrl_dev *pctldev = NULL;
+ struct pinctrl_dev *pctldev;
const char *devname;
struct pinctrl *p;
unsigned num_maps = 0;
- int ret = -ENODEV;
+ int ret;
struct pinctrl_maps *maps_node;
int i;
struct pinctrl_map const *map;
+ struct pinctrl_setting *setting;
/* We must have both a dev and state name */
if (WARN_ON(!dev || !name))
@@ -487,39 +488,50 @@ static struct pinctrl *pinctrl_get_locked(struct device *dev, const char *name)
dev_err(dev, "failed to alloc struct pinctrl\n");
return ERR_PTR(-ENOMEM);
}
- pinmux_init_pinctrl_handle(p);
+ p->dev = dev;
+ p->state = name;
+ INIT_LIST_HEAD(&p->settings);
/* Iterate over the pin control maps to locate the right ones */
for_each_maps(maps_node, i, map) {
+ /* Map must be for this device */
+ if (strcmp(map->dev_name, devname))
+ continue;
+
+ /* State name must be the one we're looking for */
+ if (strcmp(map->name, name))
+ continue;
+
/*
- * First, try to find the pctldev given in the map
+ * Try to find the pctldev given in the map
*/
pctldev = get_pinctrl_dev_from_devname(map->ctrl_dev_name);
if (!pctldev) {
dev_err(dev, "unknown pinctrl device %s in map entry",
map->ctrl_dev_name);
- pinmux_put(p);
- kfree(p);
/* Eventually, this should trigger deferred probe */
- return ERR_PTR(-ENODEV);
+ ret = -ENODEV;
+ goto error;
}
dev_dbg(dev, "in map, found pctldev %s to handle function %s",
dev_name(pctldev->dev), map->function);
- /* Map must be for this device */
- if (strcmp(map->dev_name, devname))
- continue;
+ setting = kzalloc(sizeof(*setting), GFP_KERNEL);
+ if (setting == NULL) {
+ dev_err(dev,
+ "failed to alloc struct pinctrl_setting\n");
+ ret = -ENOMEM;
+ goto error;
+ }
- /* State name must be the one we're looking for */
- if (strcmp(map->name, name))
- continue;
+ setting->pctldev = pctldev;
+ ret = pinmux_map_to_setting(map, setting);
+ if (ret < 0)
+ goto error;
+
+ list_add_tail(&setting->node, &p->settings);
- ret = pinmux_apply_muxmap(pctldev, p, dev, devname, map);
- if (ret) {
- kfree(p);
- return ERR_PTR(ret);
- }
num_maps++;
}
@@ -541,6 +553,14 @@ static struct pinctrl *pinctrl_get_locked(struct device *dev, const char *name)
list_add_tail(&p->node, &pinctrl_list);
return p;
+
+error:
+ list_for_each_entry(setting, &p->settings, node)
+ pinmux_free_setting(setting);
+
+ kfree(p);
+
+ return ERR_PTR(ret);
}
/**
@@ -564,13 +584,18 @@ EXPORT_SYMBOL_GPL(pinctrl_get);
static void pinctrl_put_locked(struct pinctrl *p)
{
+ struct pinctrl_setting *setting, *n;
+
if (p == NULL)
return;
if (p->usecount)
pr_warn("releasing pin control handle with active users!\n");
- /* Free the groups and all acquired pins */
- pinmux_put(p);
+ list_for_each_entry_safe(setting, n, &p->settings, node) {
+ pinmux_free_setting(setting);
+ list_del(&setting->node);
+ kfree(setting);
+ }
/* Remove from list */
list_del(&p->node);
@@ -592,18 +617,24 @@ EXPORT_SYMBOL_GPL(pinctrl_put);
static int pinctrl_enable_locked(struct pinctrl *p)
{
- int ret = 0;
+ struct pinctrl_setting *setting;
+ int ret;
if (p == NULL)
return -EINVAL;
if (p->usecount++ == 0) {
- ret = pinmux_enable(p);
- if (ret)
- p->usecount--;
+ list_for_each_entry(setting, &p->settings, node) {
+ ret = pinmux_enable_setting(setting);
+ if (ret < 0) {
+ /* FIXME: Difficult to return to prev state */
+ p->usecount--;
+ return ret;
+ }
+ }
}
- return ret;
+ return 0;
}
/**
@@ -622,11 +653,14 @@ EXPORT_SYMBOL_GPL(pinctrl_enable);
static void pinctrl_disable_locked(struct pinctrl *p)
{
+ struct pinctrl_setting *setting;
+
if (p == NULL)
return;
if (--p->usecount == 0) {
- pinmux_disable(p);
+ list_for_each_entry(setting, &p->settings, node)
+ pinmux_disable_setting(setting);
}
}
@@ -857,27 +891,20 @@ static int pinctrl_maps_show(struct seq_file *s, void *what)
static int pinctrl_show(struct seq_file *s, void *what)
{
struct pinctrl *p;
+ struct pinctrl_setting *setting;
seq_puts(s, "Requested pin control handlers their pinmux maps:\n");
mutex_lock(&pinctrl_mutex);
list_for_each_entry(p, &pinctrl_list, node) {
- struct pinctrl_dev *pctldev = p->pctldev;
+ seq_printf(s, "device: %s state: %s users: %u\n",
+ dev_name(p->dev), p->state, p->usecount);
- if (!pctldev) {
- seq_puts(s, "NO PIN CONTROLLER DEVICE\n");
- continue;
+ list_for_each_entry(setting, &p->settings, node) {
+ seq_printf(s, " ");
+ pinmux_dbg_show(s, setting);
}
-
- seq_printf(s, "device: %s",
- pinctrl_dev_get_name(p->pctldev));
-
- pinmux_dbg_show(s, p);
-
- seq_printf(s, " users: %u map-> %s\n",
- p->usecount,
- p->dev ? dev_name(p->dev) : "(system)");
}
mutex_unlock(&pinctrl_mutex);