#include <linux/init.h>
#include <linux/device.h>
#include <linux/slab.h>
-#include <linux/radix-tree.h>
#include <linux/err.h>
#include <linux/list.h>
-#include <linux/mutex.h>
-#include <linux/spinlock.h>
#include <linux/sysfs.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
unsigned num_maps;
};
-/* Global list of pin control devices */
-static DEFINE_MUTEX(pinctrldev_list_mutex);
+/* 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 of pin controller handles */
-static DEFINE_MUTEX(pinctrl_list_mutex);
+/* List of pin controller handles (struct pinctrl) */
static LIST_HEAD(pinctrl_list);
-/* Global pinctrl maps */
-static DEFINE_MUTEX(pinctrl_maps_mutex);
+/* List of pinctrl maps (struct pinctrl_maps) */
static LIST_HEAD(pinctrl_maps);
#define for_each_maps(_maps_node_, _i_, _map_) \
if (!devname)
return NULL;
- mutex_lock(&pinctrldev_list_mutex);
list_for_each_entry(pctldev, &pinctrldev_list, node) {
if (!strcmp(dev_name(pctldev->dev), devname)) {
/* Matched on device name */
break;
}
}
- mutex_unlock(&pinctrldev_list_mutex);
return found ? pctldev : NULL;
}
if (pin < 0)
return false;
+ mutex_lock(&pinctrl_mutex);
pindesc = pin_desc_get(pctldev, pin);
- if (pindesc == NULL)
- return false;
+ mutex_unlock(&pinctrl_mutex);
- return true;
+ return pindesc != NULL;
}
EXPORT_SYMBOL_GPL(pin_is_valid);
return -ENOMEM;
}
- spin_lock_init(&pindesc->lock);
-
/* Set owner */
pindesc->pctldev = pctldev;
struct pinctrl_gpio_range *range = NULL;
/* Loop over the ranges */
- mutex_lock(&pctldev->gpio_ranges_lock);
list_for_each_entry(range, &pctldev->gpio_ranges, node) {
/* Check if we're in the valid range */
if (gpio >= range->base &&
gpio < range->base + range->npins) {
- mutex_unlock(&pctldev->gpio_ranges_lock);
return range;
}
}
- mutex_unlock(&pctldev->gpio_ranges_lock);
return NULL;
}
struct pinctrl_dev *pctldev = NULL;
/* Loop over the pin controllers */
- mutex_lock(&pinctrldev_list_mutex);
list_for_each_entry(pctldev, &pinctrldev_list, node) {
struct pinctrl_gpio_range *range;
if (range != NULL) {
*outdev = pctldev;
*outrange = range;
- mutex_unlock(&pinctrldev_list_mutex);
return 0;
}
}
- mutex_unlock(&pinctrldev_list_mutex);
return -EINVAL;
}
void pinctrl_add_gpio_range(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range)
{
- mutex_lock(&pctldev->gpio_ranges_lock);
+ mutex_lock(&pinctrl_mutex);
list_add_tail(&range->node, &pctldev->gpio_ranges);
- mutex_unlock(&pctldev->gpio_ranges_lock);
+ mutex_unlock(&pinctrl_mutex);
}
EXPORT_SYMBOL_GPL(pinctrl_add_gpio_range);
void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range)
{
- mutex_lock(&pctldev->gpio_ranges_lock);
+ mutex_lock(&pinctrl_mutex);
list_del(&range->node);
- mutex_unlock(&pctldev->gpio_ranges_lock);
+ mutex_unlock(&pinctrl_mutex);
}
EXPORT_SYMBOL_GPL(pinctrl_remove_gpio_range);
int ret;
int pin;
+ mutex_lock(&pinctrl_mutex);
+
ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range);
- if (ret)
+ if (ret) {
+ mutex_unlock(&pinctrl_mutex);
return -EINVAL;
+ }
/* Convert to the pin controllers number space */
pin = gpio - range->base + range->pin_base;
- return pinmux_request_gpio(pctldev, range, pin, gpio);
+ ret = pinmux_request_gpio(pctldev, range, pin, gpio);
+
+ mutex_unlock(&pinctrl_mutex);
+ return ret;
}
EXPORT_SYMBOL_GPL(pinctrl_request_gpio);
int ret;
int pin;
+ mutex_lock(&pinctrl_mutex);
+
ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range);
- if (ret)
+ if (ret) {
+ mutex_unlock(&pinctrl_mutex);
return;
+ }
/* Convert to the pin controllers number space */
pin = gpio - range->base + range->pin_base;
- return pinmux_free_gpio(pctldev, pin, range);
+ pinmux_free_gpio(pctldev, pin, range);
+
+ mutex_unlock(&pinctrl_mutex);
}
EXPORT_SYMBOL_GPL(pinctrl_free_gpio);
*/
int pinctrl_gpio_direction_input(unsigned gpio)
{
- return pinctrl_gpio_direction(gpio, true);
+ int ret;
+ mutex_lock(&pinctrl_mutex);
+ ret = pinctrl_gpio_direction(gpio, true);
+ mutex_unlock(&pinctrl_mutex);
+ return ret;
}
EXPORT_SYMBOL_GPL(pinctrl_gpio_direction_input);
*/
int pinctrl_gpio_direction_output(unsigned gpio)
{
- return pinctrl_gpio_direction(gpio, false);
+ int ret;
+ mutex_lock(&pinctrl_mutex);
+ ret = pinctrl_gpio_direction(gpio, false);
+ mutex_unlock(&pinctrl_mutex);
+ return ret;
}
EXPORT_SYMBOL_GPL(pinctrl_gpio_direction_output);
dev_err(dev, "failed to alloc struct pinctrl\n");
return ERR_PTR(-ENOMEM);
}
- mutex_init(&p->mutex);
pinmux_init_pinctrl_handle(p);
/* Iterate over the pin control maps to locate the right ones */
num_maps, devname, name ? name : "(undefined)");
/* Add the pinmux to the global list */
- mutex_lock(&pinctrl_list_mutex);
list_add_tail(&p->node, &pinctrl_list);
- mutex_unlock(&pinctrl_list_mutex);
return p;
}
{
struct pinctrl *p;
- mutex_lock(&pinctrl_maps_mutex);
+ mutex_lock(&pinctrl_mutex);
p = pinctrl_get_locked(dev, name);
- mutex_unlock(&pinctrl_maps_mutex);
+ mutex_unlock(&pinctrl_mutex);
return p;
}
EXPORT_SYMBOL_GPL(pinctrl_get);
-/**
- * pinctrl_put() - release a previously claimed pin control handle
- * @p: a pin control handle previously claimed by pinctrl_get()
- */
-void pinctrl_put(struct pinctrl *p)
+static void pinctrl_put_locked(struct pinctrl *p)
{
if (p == NULL)
return;
- mutex_lock(&p->mutex);
if (p->usecount)
pr_warn("releasing pin control handle with active users!\n");
/* Free the groups and all acquired pins */
pinmux_put(p);
- mutex_unlock(&p->mutex);
/* Remove from list */
- mutex_lock(&pinctrl_list_mutex);
list_del(&p->node);
- mutex_unlock(&pinctrl_list_mutex);
kfree(p);
}
-EXPORT_SYMBOL_GPL(pinctrl_put);
/**
- * pinctrl_enable() - enable a certain pin controller setting
- * @p: the pin control handle to enable, previously claimed by pinctrl_get()
+ * pinctrl_put() - release a previously claimed pin control handle
+ * @p: a pin control handle previously claimed by pinctrl_get()
*/
-int pinctrl_enable(struct pinctrl *p)
+void pinctrl_put(struct pinctrl *p)
+{
+ mutex_lock(&pinctrl_mutex);
+ pinctrl_put(p);
+ mutex_unlock(&pinctrl_mutex);
+}
+EXPORT_SYMBOL_GPL(pinctrl_put);
+
+static int pinctrl_enable_locked(struct pinctrl *p)
{
int ret = 0;
if (p == NULL)
return -EINVAL;
- mutex_lock(&p->mutex);
+
if (p->usecount++ == 0) {
ret = pinmux_enable(p);
if (ret)
p->usecount--;
}
- mutex_unlock(&p->mutex);
+
return ret;
}
-EXPORT_SYMBOL_GPL(pinctrl_enable);
/**
- * pinctrl_disable() - disable a certain pin control setting
- * @p: the pin control handle to disable, previously claimed by pinctrl_get()
+ * pinctrl_enable() - enable a certain pin controller setting
+ * @p: the pin control handle to enable, previously claimed by pinctrl_get()
*/
-void pinctrl_disable(struct pinctrl *p)
+int pinctrl_enable(struct pinctrl *p)
+{
+ int ret;
+ mutex_lock(&pinctrl_mutex);
+ ret = pinctrl_enable_locked(p);
+ mutex_unlock(&pinctrl_mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(pinctrl_enable);
+
+static void pinctrl_disable_locked(struct pinctrl *p)
{
if (p == NULL)
return;
- mutex_lock(&p->mutex);
if (--p->usecount == 0) {
pinmux_disable(p);
}
- mutex_unlock(&p->mutex);
+}
+
+/**
+ * pinctrl_disable() - disable a certain pin control setting
+ * @p: the pin control handle to disable, previously claimed by pinctrl_get()
+ */
+void pinctrl_disable(struct pinctrl *p)
+{
+ mutex_lock(&pinctrl_mutex);
+ pinctrl_disable_locked(p);
+ mutex_unlock(&pinctrl_mutex);
}
EXPORT_SYMBOL_GPL(pinctrl_disable);
return -ENOMEM;
}
- mutex_lock(&pinctrl_maps_mutex);
+ mutex_lock(&pinctrl_mutex);
list_add_tail(&maps_node->node, &pinctrl_maps);
- mutex_unlock(&pinctrl_maps_mutex);
+ mutex_unlock(&pinctrl_mutex);
return 0;
}
seq_printf(s, "registered pins: %d\n", pctldev->desc->npins);
+ mutex_lock(&pinctrl_mutex);
+
/* The pin number can be retrived from the pin controller descriptor */
for (i = 0; i < pctldev->desc->npins; i++) {
struct pin_desc *desc;
seq_puts(s, "\n");
}
+ mutex_unlock(&pinctrl_mutex);
+
return 0;
}
if (!ops)
return 0;
+ mutex_lock(&pinctrl_mutex);
+
seq_puts(s, "registered pin groups:\n");
while (ops->list_groups(pctldev, selector) >= 0) {
const unsigned *pins;
selector++;
}
+ mutex_unlock(&pinctrl_mutex);
return 0;
}
seq_puts(s, "GPIO ranges handled:\n");
+ mutex_lock(&pinctrl_mutex);
+
/* Loop over the ranges */
- mutex_lock(&pctldev->gpio_ranges_lock);
list_for_each_entry(range, &pctldev->gpio_ranges, node) {
seq_printf(s, "%u: %s GPIOS [%u - %u] PINS [%u - %u]\n",
range->id, range->name,
range->pin_base,
(range->pin_base + range->npins - 1));
}
- mutex_unlock(&pctldev->gpio_ranges_lock);
+
+ mutex_unlock(&pinctrl_mutex);
return 0;
}
struct pinctrl_dev *pctldev;
seq_puts(s, "name [pinmux] [pinconf]\n");
- mutex_lock(&pinctrldev_list_mutex);
+
+ mutex_lock(&pinctrl_mutex);
+
list_for_each_entry(pctldev, &pinctrldev_list, node) {
seq_printf(s, "%s ", pctldev->desc->name);
if (pctldev->desc->pmxops)
seq_puts(s, "no");
seq_puts(s, "\n");
}
- mutex_unlock(&pinctrldev_list_mutex);
+
+ mutex_unlock(&pinctrl_mutex);
return 0;
}
seq_puts(s, "Pinctrl maps:\n");
- mutex_lock(&pinctrl_maps_mutex);
+ mutex_lock(&pinctrl_mutex);
+
for_each_maps(maps_node, i, map) {
seq_printf(s, "%s:\n", map->name);
seq_printf(s, " device: %s\n", map->dev_name);
seq_printf(s, " group: %s\n", map->group ? map->group :
"(default)");
}
- mutex_unlock(&pinctrl_maps_mutex);
+
+ mutex_unlock(&pinctrl_mutex);
return 0;
}
struct pinctrl *p;
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;
p->dev ? dev_name(p->dev) : "(system)");
}
+ mutex_unlock(&pinctrl_mutex);
+
return 0;
}
pctldev->driver_data = driver_data;
INIT_RADIX_TREE(&pctldev->pin_desc_tree, GFP_KERNEL);
INIT_LIST_HEAD(&pctldev->gpio_ranges);
- mutex_init(&pctldev->gpio_ranges_lock);
pctldev->dev = dev;
/* If we're implementing pinmuxing, check the ops for sanity */
goto out_err;
}
- mutex_lock(&pinctrldev_list_mutex);
+ mutex_lock(&pinctrl_mutex);
+
list_add_tail(&pctldev->node, &pinctrldev_list);
- mutex_unlock(&pinctrldev_list_mutex);
- pctldev->p = pinctrl_get(pctldev->dev, PINCTRL_STATE_DEFAULT);
+
+ pctldev->p = pinctrl_get_locked(pctldev->dev, PINCTRL_STATE_DEFAULT);
if (!IS_ERR(pctldev->p))
- pinctrl_enable(pctldev->p);
+ pinctrl_enable_locked(pctldev->p);
+
+ mutex_unlock(&pinctrl_mutex);
+
pinctrl_init_device_debugfs(pctldev);
return pctldev;
return;
pinctrl_remove_device_debugfs(pctldev);
+
+ mutex_lock(&pinctrl_mutex);
+
if (!IS_ERR(pctldev->p)) {
- pinctrl_disable(pctldev->p);
- pinctrl_put(pctldev->p);
+ pinctrl_disable_locked(pctldev->p);
+ pinctrl_put_locked(pctldev->p);
}
+
/* TODO: check that no pinmuxes are still active? */
- mutex_lock(&pinctrldev_list_mutex);
list_del(&pctldev->node);
- mutex_unlock(&pinctrldev_list_mutex);
/* Destroy descriptor tree */
pinctrl_free_pindescs(pctldev, pctldev->desc->pins,
pctldev->desc->npins);
kfree(pctldev);
+
+ mutex_unlock(&pinctrl_mutex);
}
EXPORT_SYMBOL_GPL(pinctrl_unregister);
struct pinctrl_dev *pctldev;
int pin;
+ mutex_lock(&pinctrl_mutex);
+
pctldev = get_pinctrl_dev_from_devname(dev_name);
- if (!pctldev)
- return -EINVAL;
+ if (!pctldev) {
+ pin = -EINVAL;
+ goto unlock;
+ }
pin = pin_get_from_name(pctldev, name);
if (pin < 0)
- return pin;
+ goto unlock;
- return pin_config_get_for_pin(pctldev, pin, config);
+ pin = pin_config_get_for_pin(pctldev, pin, config);
+
+unlock:
+ mutex_unlock(&pinctrl_mutex);
+ return pin;
}
EXPORT_SYMBOL(pin_config_get);
unsigned long config)
{
struct pinctrl_dev *pctldev;
- int pin;
+ int pin, ret;
+
+ mutex_lock(&pinctrl_mutex);
pctldev = get_pinctrl_dev_from_devname(dev_name);
- if (!pctldev)
- return -EINVAL;
+ if (!pctldev) {
+ ret = -EINVAL;
+ goto unlock;
+ }
pin = pin_get_from_name(pctldev, name);
- if (pin < 0)
- return pin;
+ if (pin < 0) {
+ ret = pin;
+ goto unlock;
+ }
+
+ ret = pin_config_set_for_pin(pctldev, pin, config);
- return pin_config_set_for_pin(pctldev, pin, config);
+unlock:
+ mutex_unlock(&pinctrl_mutex);
+ return ret;
}
EXPORT_SYMBOL(pin_config_set);
{
struct pinctrl_dev *pctldev;
const struct pinconf_ops *ops;
- int selector;
+ int selector, ret;
+
+ mutex_lock(&pinctrl_mutex);
pctldev = get_pinctrl_dev_from_devname(dev_name);
- if (!pctldev)
- return -EINVAL;
+ if (!pctldev) {
+ ret = -EINVAL;
+ goto unlock;
+ }
ops = pctldev->desc->confops;
if (!ops || !ops->pin_config_group_get) {
dev_err(pctldev->dev, "cannot get configuration for pin "
"group, missing group config get function in "
"driver\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto unlock;
}
selector = pinctrl_get_group_selector(pctldev, pin_group);
- if (selector < 0)
- return selector;
+ if (selector < 0) {
+ ret = selector;
+ goto unlock;
+ }
- return ops->pin_config_group_get(pctldev, selector, config);
+ ret = ops->pin_config_group_get(pctldev, selector, config);
+
+unlock:
+ mutex_unlock(&pinctrl_mutex);
+ return ret;
}
EXPORT_SYMBOL(pin_config_group_get);
int ret;
int i;
+ mutex_lock(&pinctrl_mutex);
+
pctldev = get_pinctrl_dev_from_devname(dev_name);
- if (!pctldev)
- return -EINVAL;
+ if (!pctldev) {
+ ret = -EINVAL;
+ goto unlock;
+ }
ops = pctldev->desc->confops;
pctlops = pctldev->desc->pctlops;
if (!ops || (!ops->pin_config_group_set && !ops->pin_config_set)) {
dev_err(pctldev->dev, "cannot configure pin group, missing "
"config function in driver\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto unlock;
}
selector = pinctrl_get_group_selector(pctldev, pin_group);
- if (selector < 0)
- return selector;
+ if (selector < 0) {
+ ret = selector;
+ goto unlock;
+ }
ret = pctlops->get_group_pins(pctldev, selector, &pins, &num_pins);
if (ret) {
dev_err(pctldev->dev, "cannot configure pin group, error "
"getting pins\n");
- return ret;
+ goto unlock;
}
/*
* pin-by-pin as well, it returns -EAGAIN.
*/
if (ret != -EAGAIN)
- return ret;
+ goto unlock;
}
/*
* If the controller cannot handle entire groups, we configure each pin
* individually.
*/
- if (!ops->pin_config_set)
- return 0;
+ if (!ops->pin_config_set) {
+ ret = 0;
+ goto unlock;
+ }
for (i = 0; i < num_pins; i++) {
ret = ops->pin_config_set(pctldev, pins[i], config);
if (ret < 0)
- return ret;
+ goto unlock;
}
- return 0;
+ ret = 0;
+
+unlock:
+ mutex_unlock(&pinctrl_mutex);
+
+ return ret;
}
EXPORT_SYMBOL(pin_config_group_set);
seq_puts(s, "Pin config settings per pin\n");
seq_puts(s, "Format: pin (name): pinmux setting array\n");
+ mutex_lock(&pinctrl_mutex);
+
/* The pin number can be retrived from the pin controller descriptor */
for (i = 0; i < pctldev->desc->npins; i++) {
struct pin_desc *desc;
seq_printf(s, "\n");
}
+ mutex_unlock(&pinctrl_mutex);
+
return 0;
}
seq_puts(s, "Pin config settings per pin group\n");
seq_puts(s, "Format: group (name): pinmux setting array\n");
+ mutex_lock(&pinctrl_mutex);
+
while (pctlops->list_groups(pctldev, selector) >= 0) {
const char *gname = pctlops->get_group_name(pctldev, selector);
selector++;
}
+ mutex_unlock(&pinctrl_mutex);
+
return 0;
}