summaryrefslogtreecommitdiffstats
path: root/drivers/pinctrl/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pinctrl/core.c')
-rw-r--r--drivers/pinctrl/core.c171
1 files changed, 132 insertions, 39 deletions
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
index 5327f35d9b5c..5b272bfd261d 100644
--- a/drivers/pinctrl/core.c
+++ b/drivers/pinctrl/core.c
@@ -41,13 +41,13 @@
static bool pinctrl_dummy_state;
/* Mutex taken to protect pinctrl_list */
-DEFINE_MUTEX(pinctrl_list_mutex);
+static DEFINE_MUTEX(pinctrl_list_mutex);
/* Mutex taken to protect pinctrl_maps */
DEFINE_MUTEX(pinctrl_maps_mutex);
/* Mutex taken to protect pinctrldev_list */
-DEFINE_MUTEX(pinctrldev_list_mutex);
+static DEFINE_MUTEX(pinctrldev_list_mutex);
/* Global list of pin control devices (struct pinctrl_dev) */
static LIST_HEAD(pinctrldev_list);
@@ -101,20 +101,23 @@ EXPORT_SYMBOL_GPL(pinctrl_dev_get_drvdata);
struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *devname)
{
struct pinctrl_dev *pctldev = NULL;
- bool found = false;
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 */
- found = true;
- break;
+ mutex_unlock(&pinctrldev_list_mutex);
+ return pctldev;
}
}
- return found ? pctldev : NULL;
+ mutex_unlock(&pinctrldev_list_mutex);
+
+ return NULL;
}
struct pinctrl_dev *get_pinctrl_dev_from_of_node(struct device_node *np)
@@ -280,6 +283,29 @@ static int pinctrl_register_pins(struct pinctrl_dev *pctldev,
}
/**
+ * gpio_to_pin() - GPIO range GPIO number to pin number translation
+ * @range: GPIO range used for the translation
+ * @gpio: gpio pin to translate to a pin number
+ *
+ * Finds the pin number for a given GPIO using the specified GPIO range
+ * as a base for translation. The distinction between linear GPIO ranges
+ * and pin list based GPIO ranges is managed correctly by this function.
+ *
+ * This function assumes the gpio is part of the specified GPIO range, use
+ * only after making sure this is the case (e.g. by calling it on the
+ * result of successful pinctrl_get_device_gpio_range calls)!
+ */
+static inline int gpio_to_pin(struct pinctrl_gpio_range *range,
+ unsigned int gpio)
+{
+ unsigned int offset = gpio - range->base;
+ if (range->pins)
+ return range->pins[offset];
+ else
+ return range->pin_base + offset;
+}
+
+/**
* pinctrl_match_gpio_range() - check if a certain GPIO pin is in range
* @pctldev: pin controller device to check
* @gpio: gpio pin to check taken from the global GPIO pin space
@@ -326,6 +352,8 @@ static bool pinctrl_ready_for_gpio_range(unsigned gpio)
struct pinctrl_gpio_range *range = NULL;
struct gpio_chip *chip = gpio_to_chip(gpio);
+ mutex_lock(&pinctrldev_list_mutex);
+
/* Loop over the pin controllers */
list_for_each_entry(pctldev, &pinctrldev_list, node) {
/* Loop over the ranges */
@@ -334,9 +362,13 @@ static bool pinctrl_ready_for_gpio_range(unsigned gpio)
if (range->base + range->npins - 1 < chip->base ||
range->base > chip->base + chip->ngpio - 1)
continue;
+ mutex_unlock(&pinctrldev_list_mutex);
return true;
}
}
+
+ mutex_unlock(&pinctrldev_list_mutex);
+
return false;
}
#else
@@ -408,8 +440,6 @@ struct pinctrl_dev *pinctrl_find_and_add_gpio_range(const char *devname,
{
struct pinctrl_dev *pctldev;
- mutex_lock(&pinctrldev_list_mutex);
-
pctldev = get_pinctrl_dev_from_devname(devname);
/*
@@ -418,13 +448,10 @@ struct pinctrl_dev *pinctrl_find_and_add_gpio_range(const char *devname,
* range need to defer probing.
*/
if (!pctldev) {
- mutex_unlock(&pinctrldev_list_mutex);
return ERR_PTR(-EPROBE_DEFER);
}
pinctrl_add_gpio_range(pctldev, range);
- mutex_unlock(&pinctrldev_list_mutex);
-
return pctldev;
}
EXPORT_SYMBOL_GPL(pinctrl_find_and_add_gpio_range);
@@ -438,21 +465,26 @@ struct pinctrl_gpio_range *
pinctrl_find_gpio_range_from_pin(struct pinctrl_dev *pctldev,
unsigned int pin)
{
- struct pinctrl_gpio_range *range = NULL;
+ struct pinctrl_gpio_range *range;
mutex_lock(&pctldev->mutex);
/* Loop over the ranges */
list_for_each_entry(range, &pctldev->gpio_ranges, node) {
/* Check if we're in the valid range */
- if (pin >= range->pin_base &&
- pin < range->pin_base + range->npins) {
- mutex_unlock(&pctldev->mutex);
- return range;
- }
+ if (range->pins) {
+ int a;
+ for (a = 0; a < range->npins; a++) {
+ if (range->pins[a] == pin)
+ goto out;
+ }
+ } else if (pin >= range->pin_base &&
+ pin < range->pin_base + range->npins)
+ goto out;
}
+ range = NULL;
+out:
mutex_unlock(&pctldev->mutex);
-
- return NULL;
+ return range;
}
EXPORT_SYMBOL_GPL(pinctrl_find_gpio_range_from_pin);
@@ -517,22 +549,18 @@ int pinctrl_request_gpio(unsigned gpio)
int ret;
int pin;
- mutex_lock(&pinctrldev_list_mutex);
-
ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range);
if (ret) {
if (pinctrl_ready_for_gpio_range(gpio))
ret = 0;
- mutex_unlock(&pinctrldev_list_mutex);
return ret;
}
/* Convert to the pin controllers number space */
- pin = gpio - range->base + range->pin_base;
+ pin = gpio_to_pin(range, gpio);
ret = pinmux_request_gpio(pctldev, range, pin, gpio);
- mutex_unlock(&pinctrldev_list_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(pinctrl_request_gpio);
@@ -552,22 +580,18 @@ void pinctrl_free_gpio(unsigned gpio)
int ret;
int pin;
- mutex_lock(&pinctrldev_list_mutex);
-
ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range);
if (ret) {
- mutex_unlock(&pinctrldev_list_mutex);
return;
}
mutex_lock(&pctldev->mutex);
/* Convert to the pin controllers number space */
- pin = gpio - range->base + range->pin_base;
+ pin = gpio_to_pin(range, gpio);
pinmux_free_gpio(pctldev, pin, range);
mutex_unlock(&pctldev->mutex);
- mutex_unlock(&pinctrldev_list_mutex);
}
EXPORT_SYMBOL_GPL(pinctrl_free_gpio);
@@ -578,22 +602,18 @@ static int pinctrl_gpio_direction(unsigned gpio, bool input)
int ret;
int pin;
- mutex_lock(&pinctrldev_list_mutex);
-
ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range);
if (ret) {
- mutex_unlock(&pinctrldev_list_mutex);
return ret;
}
mutex_lock(&pctldev->mutex);
/* Convert to the pin controllers number space */
- pin = gpio - range->base + range->pin_base;
+ pin = gpio_to_pin(range, gpio);
ret = pinmux_gpio_direction(pctldev, range, pin, input);
mutex_unlock(&pctldev->mutex);
- mutex_unlock(&pinctrldev_list_mutex);
return ret;
}
@@ -1204,6 +1224,69 @@ int pinctrl_force_default(struct pinctrl_dev *pctldev)
}
EXPORT_SYMBOL_GPL(pinctrl_force_default);
+#ifdef CONFIG_PM
+
+/**
+ * pinctrl_pm_select_default_state() - select default pinctrl state for PM
+ * @dev: device to select default state for
+ */
+int pinctrl_pm_select_default_state(struct device *dev)
+{
+ struct dev_pin_info *pins = dev->pins;
+ int ret;
+
+ if (!pins)
+ return 0;
+ if (IS_ERR(pins->default_state))
+ return 0; /* No default state */
+ ret = pinctrl_select_state(pins->p, pins->default_state);
+ if (ret)
+ dev_err(dev, "failed to activate default pinctrl state\n");
+ return ret;
+}
+EXPORT_SYMBOL_GPL(pinctrl_pm_select_default_state);
+
+/**
+ * pinctrl_pm_select_sleep_state() - select sleep pinctrl state for PM
+ * @dev: device to select sleep state for
+ */
+int pinctrl_pm_select_sleep_state(struct device *dev)
+{
+ struct dev_pin_info *pins = dev->pins;
+ int ret;
+
+ if (!pins)
+ return 0;
+ if (IS_ERR(pins->sleep_state))
+ return 0; /* No sleep state */
+ ret = pinctrl_select_state(pins->p, pins->sleep_state);
+ if (ret)
+ dev_err(dev, "failed to activate pinctrl sleep state\n");
+ return ret;
+}
+EXPORT_SYMBOL_GPL(pinctrl_pm_select_sleep_state);
+
+/**
+ * pinctrl_pm_select_idle_state() - select idle pinctrl state for PM
+ * @dev: device to select idle state for
+ */
+int pinctrl_pm_select_idle_state(struct device *dev)
+{
+ struct dev_pin_info *pins = dev->pins;
+ int ret;
+
+ if (!pins)
+ return 0;
+ if (IS_ERR(pins->idle_state))
+ return 0; /* No idle state */
+ ret = pinctrl_select_state(pins->p, pins->idle_state);
+ if (ret)
+ dev_err(dev, "failed to activate pinctrl idle state\n");
+ return ret;
+}
+EXPORT_SYMBOL_GPL(pinctrl_pm_select_idle_state);
+#endif
+
#ifdef CONFIG_DEBUG_FS
static int pinctrl_pins_show(struct seq_file *s, void *what)
@@ -1296,11 +1379,21 @@ static int pinctrl_gpioranges_show(struct seq_file *s, void *what)
/* Loop over the ranges */
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->base, (range->base + range->npins - 1),
- range->pin_base,
- (range->pin_base + range->npins - 1));
+ if (range->pins) {
+ int a;
+ seq_printf(s, "%u: %s GPIOS [%u - %u] PINS {",
+ range->id, range->name,
+ range->base, (range->base + range->npins - 1));
+ for (a = 0; a < range->npins - 1; a++)
+ seq_printf(s, "%u, ", range->pins[a]);
+ seq_printf(s, "%u}\n", range->pins[a]);
+ }
+ else
+ seq_printf(s, "%u: %s GPIOS [%u - %u] PINS [%u - %u]\n",
+ range->id, range->name,
+ range->base, (range->base + range->npins - 1),
+ range->pin_base,
+ (range->pin_base + range->npins - 1));
}
mutex_unlock(&pctldev->mutex);
OpenPOWER on IntegriCloud