summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/pinctrl/core.c120
1 files changed, 75 insertions, 45 deletions
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
index feadf1c3113..50bcc511193 100644
--- a/drivers/pinctrl/core.c
+++ b/drivers/pinctrl/core.c
@@ -7,6 +7,8 @@
*
* Author: Linus Walleij <linus.walleij@linaro.org>
*
+ * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
+ *
* License terms: GNU General Public License (GPL) version 2
*/
#define pr_fmt(fmt) "pinctrl core: " fmt
@@ -31,6 +33,18 @@
#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;
+};
+
+/**
* struct pinctrl_hog - a list item to stash control hogs
* @node: pin control hog list node
* @map: map entry responsible for this hogging
@@ -51,8 +65,14 @@ static DEFINE_MUTEX(pinctrl_list_mutex);
static LIST_HEAD(pinctrl_list);
/* Global pinctrl maps */
-static struct pinctrl_map *pinctrl_maps;
-static unsigned pinctrl_maps_num;
+static DEFINE_MUTEX(pinctrl_maps_mutex);
+static 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_])
const char *pinctrl_dev_get_name(struct pinctrl_dev *pctldev)
{
@@ -454,23 +474,17 @@ int pinctrl_gpio_direction_output(unsigned gpio)
}
EXPORT_SYMBOL_GPL(pinctrl_gpio_direction_output);
-/**
- * pinctrl_get() - retrieves the pin controller handle for a certain device
- * @dev: the device to get the pin controller handle for
- * @name: an optional specific control mapping name or NULL, the name is only
- * needed if you want to have more than one mapping per device, or if you
- * need an anonymous pin control (not tied to any specific device)
- */
-struct pinctrl *pinctrl_get(struct device *dev, const char *name)
+static struct pinctrl *pinctrl_get_locked(struct device *dev, const char *name)
{
- struct pinctrl_map const *map = NULL;
struct pinctrl_dev *pctldev = NULL;
const char *devname = NULL;
struct pinctrl *p;
bool found_map;
unsigned num_maps = 0;
int ret = -ENODEV;
+ struct pinctrl_maps *maps_node;
int i;
+ struct pinctrl_map const *map;
/* We must have dev or ID or both */
if (!dev && !name)
@@ -494,8 +508,7 @@ struct pinctrl *pinctrl_get(struct device *dev, const char *name)
pinmux_init_pinctrl_handle(p);
/* Iterate over the pin control maps to locate the right ones */
- for (i = 0; i < pinctrl_maps_num; i++) {
- map = &pinctrl_maps[i];
+ for_each_maps(maps_node, i, map) {
found_map = false;
/*
@@ -515,7 +528,6 @@ struct pinctrl *pinctrl_get(struct device *dev, const char *name)
pr_debug("in map, found pctldev %s to handle function %s",
dev_name(pctldev->dev), map->function);
-
/*
* If we're looking for a specific named map, this must match,
* else we loop and look for the next.
@@ -574,6 +586,24 @@ struct pinctrl *pinctrl_get(struct device *dev, const char *name)
return p;
}
+
+/**
+ * pinctrl_get() - retrieves the pin controller handle for a certain device
+ * @dev: the device to get the pin controller handle for
+ * @name: an optional specific control mapping name or NULL, the name is only
+ * needed if you want to have more than one mapping per device, or if you
+ * need an anonymous pin control (not tied to any specific device)
+ */
+struct pinctrl *pinctrl_get(struct device *dev, const char *name)
+{
+ struct pinctrl *p;
+
+ mutex_lock(&pinctrl_maps_mutex);
+ p = pinctrl_get_locked(dev, name);
+ mutex_unlock(&pinctrl_maps_mutex);
+
+ return p;
+}
EXPORT_SYMBOL_GPL(pinctrl_get);
/**
@@ -649,8 +679,8 @@ EXPORT_SYMBOL_GPL(pinctrl_disable);
int pinctrl_register_mappings(struct pinctrl_map const *maps,
unsigned num_maps)
{
- void *tmp_maps;
int i;
+ struct pinctrl_maps *maps_node;
pr_debug("add %d pinmux maps\n", num_maps);
@@ -684,31 +714,23 @@ int pinctrl_register_mappings(struct pinctrl_map const *maps,
maps[i].function);
}
- /*
- * Make a copy of the map array - string pointers will end up in the
- * kernel const section anyway so these do not need to be deep copied.
- */
- if (!pinctrl_maps_num) {
- /* On first call, just copy them */
- tmp_maps = kmemdup(maps,
- sizeof(struct pinctrl_map) * num_maps,
- GFP_KERNEL);
- if (!tmp_maps)
- return -ENOMEM;
- } else {
- /* Subsequent calls, reallocate array to new size */
- size_t oldsize = sizeof(struct pinctrl_map) * pinctrl_maps_num;
- size_t newsize = sizeof(struct pinctrl_map) * num_maps;
+ maps_node = kzalloc(sizeof(*maps_node), GFP_KERNEL);
+ if (!maps_node) {
+ pr_err("failed to alloc struct pinctrl_maps\n");
+ return -ENOMEM;
+ }
- tmp_maps = krealloc(pinctrl_maps,
- oldsize + newsize, GFP_KERNEL);
- if (!tmp_maps)
- return -ENOMEM;
- memcpy((tmp_maps + oldsize), maps, newsize);
+ maps_node->num_maps = num_maps;
+ maps_node->maps = kmemdup(maps, sizeof(*maps) * num_maps, GFP_KERNEL);
+ if (!maps_node->maps) {
+ kfree(maps_node);
+ return -ENOMEM;
}
- pinctrl_maps = tmp_maps;
- pinctrl_maps_num += num_maps;
+ mutex_lock(&pinctrl_maps_mutex);
+ list_add_tail(&maps_node->node, &pinctrl_maps);
+ mutex_unlock(&pinctrl_maps_mutex);
+
return 0;
}
@@ -724,7 +746,7 @@ static int pinctrl_hog_map(struct pinctrl_dev *pctldev,
if (!hog)
return -ENOMEM;
- p = pinctrl_get(pctldev->dev, map->name);
+ p = pinctrl_get_locked(pctldev->dev, map->name);
if (IS_ERR(p)) {
kfree(hog);
dev_err(pctldev->dev,
@@ -768,23 +790,28 @@ int pinctrl_hog_maps(struct pinctrl_dev *pctldev)
struct device *dev = pctldev->dev;
const char *devname = dev_name(dev);
int ret;
+ struct pinctrl_maps *maps_node;
int i;
+ struct pinctrl_map const *map;
INIT_LIST_HEAD(&pctldev->pinctrl_hogs);
mutex_init(&pctldev->pinctrl_hogs_lock);
- for (i = 0; i < pinctrl_maps_num; i++) {
- struct pinctrl_map const *map = &pinctrl_maps[i];
-
+ mutex_lock(&pinctrl_maps_mutex);
+ for_each_maps(maps_node, i, map) {
if (map->ctrl_dev_name &&
!strcmp(map->ctrl_dev_name, devname) &&
!strcmp(map->dev_name, devname)) {
/* OK time to hog! */
ret = pinctrl_hog_map(pctldev, map);
- if (ret)
+ if (ret) {
+ mutex_unlock(&pinctrl_maps_mutex);
return ret;
+ }
}
}
+ mutex_unlock(&pinctrl_maps_mutex);
+
return 0;
}
@@ -900,13 +927,14 @@ static int pinctrl_gpioranges_show(struct seq_file *s, void *what)
static int pinctrl_maps_show(struct seq_file *s, void *what)
{
+ struct pinctrl_maps *maps_node;
int i;
+ struct pinctrl_map const *map;
seq_puts(s, "Pinctrl maps:\n");
- for (i = 0; i < pinctrl_maps_num; i++) {
- struct pinctrl_map const *map = &pinctrl_maps[i];
-
+ mutex_lock(&pinctrl_maps_mutex);
+ for_each_maps(maps_node, i, map) {
seq_printf(s, "%s:\n", map->name);
if (map->dev_name)
seq_printf(s, " device: %s\n",
@@ -919,6 +947,8 @@ static int pinctrl_maps_show(struct seq_file *s, void *what)
seq_printf(s, " group: %s\n", map->group ? map->group :
"(default)");
}
+ mutex_unlock(&pinctrl_maps_mutex);
+
return 0;
}