summaryrefslogtreecommitdiffstats
path: root/drivers/gpio/gpiolib.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpio/gpiolib.c')
-rw-r--r--drivers/gpio/gpiolib.c245
1 files changed, 151 insertions, 94 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 9764ddf0f0..27674af54c 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -48,6 +48,11 @@ static struct gpio_info *gpio_to_desc(unsigned gpio)
return NULL;
}
+static unsigned gpioinfo_chip_offset(struct gpio_info *gi)
+{
+ return (gi - gpio_desc) - gi->chip->base;
+}
+
static int gpio_adjust_value(struct gpio_info *gi,
int value)
{
@@ -57,16 +62,10 @@ static int gpio_adjust_value(struct gpio_info *gi,
return !!value ^ gi->active_low;
}
-int gpio_request(unsigned gpio, const char *label)
+static int gpioinfo_request(struct gpio_info *gi, const char *label)
{
- struct gpio_info *gi = gpio_to_desc(gpio);
int ret;
- if (!gi) {
- ret = -ENODEV;
- goto done;
- }
-
if (gi->requested) {
ret = -EBUSY;
goto done;
@@ -75,7 +74,8 @@ int gpio_request(unsigned gpio, const char *label)
ret = 0;
if (gi->chip->ops->request) {
- ret = gi->chip->ops->request(gi->chip, gpio - gi->chip->base);
+ ret = gi->chip->ops->request(gi->chip,
+ gpioinfo_chip_offset(gi));
if (ret)
goto done;
}
@@ -86,8 +86,8 @@ int gpio_request(unsigned gpio, const char *label)
done:
if (ret)
- pr_err("_gpio_request: gpio-%d (%s) status %d\n",
- gpio, label ? : "?", ret);
+ pr_err("_gpio_request: gpio-%td (%s) status %d\n",
+ gi - gpio_desc, label ? : "?", ret);
return ret;
}
@@ -126,18 +126,26 @@ int gpio_find_by_name(const char *name)
return -ENOENT;
}
-void gpio_free(unsigned gpio)
+int gpio_request(unsigned gpio, const char *label)
{
struct gpio_info *gi = gpio_to_desc(gpio);
- if (!gi)
- return;
+ if (!gi) {
+ pr_err("_gpio_request: gpio-%d (%s) status %d\n",
+ gpio, label ? : "?", -ENODEV);
+ return -ENODEV;
+ }
+
+ return gpioinfo_request(gi, label);
+}
+static void gpioinfo_free(struct gpio_info *gi)
+{
if (!gi->requested)
return;
if (gi->chip->ops->free)
- gi->chip->ops->free(gi->chip, gpio - gi->chip->base);
+ gi->chip->ops->free(gi->chip, gpioinfo_chip_offset(gi));
gi->requested = false;
gi->active_low = false;
@@ -145,81 +153,21 @@ void gpio_free(unsigned gpio)
gi->label = NULL;
}
-/**
- * gpio_request_one - request a single GPIO with initial configuration
- * @gpio: the GPIO number
- * @flags: GPIO configuration as specified by GPIOF_*
- * @label: a literal description string of this GPIO
- */
-int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
+void gpio_free(unsigned gpio)
{
- int err;
struct gpio_info *gi = gpio_to_desc(gpio);
- /*
- * Not all of the flags below are mulit-bit, but, for the sake
- * of consistency, the code is written as if all of them were.
- */
- const bool active_low = (flags & GPIOF_ACTIVE_LOW) == GPIOF_ACTIVE_LOW;
- const bool dir_in = (flags & GPIOF_DIR_IN) == GPIOF_DIR_IN;
- const bool logical = (flags & GPIOF_LOGICAL) == GPIOF_LOGICAL;
- const bool init_active = (flags & GPIOF_INIT_ACTIVE) == GPIOF_INIT_ACTIVE;
- const bool init_high = (flags & GPIOF_INIT_HIGH) == GPIOF_INIT_HIGH;
-
- err = gpio_request(gpio, label);
- if (err)
- return err;
-
- gi->active_low = active_low;
-
- if (dir_in)
- err = gpio_direction_input(gpio);
- else if (logical)
- err = gpio_direction_active(gpio, init_active);
- else
- err = gpio_direction_output(gpio, init_high);
-
- if (err)
- gpio_free(gpio);
-
- return err;
-}
-EXPORT_SYMBOL_GPL(gpio_request_one);
-
-/**
- * gpio_request_array - request multiple GPIOs in a single call
- * @array: array of the 'struct gpio'
- * @num: how many GPIOs in the array
- */
-int gpio_request_array(const struct gpio *array, size_t num)
-{
- int i, err;
-
- for (i = 0; i < num; i++, array++) {
- err = gpio_request_one(array->gpio, array->flags, array->label);
- if (err)
- goto err_free;
- }
- return 0;
+ if (!gi)
+ return;
-err_free:
- while (i--)
- gpio_free((--array)->gpio);
- return err;
+ gpioinfo_free(gi);
}
-EXPORT_SYMBOL_GPL(gpio_request_array);
-/**
- * gpio_free_array - release multiple GPIOs in a single call
- * @array: array of the 'struct gpio'
- * @num: how many GPIOs in the array
- */
-void gpio_free_array(const struct gpio *array, size_t num)
+static void gpioinfo_set_value(struct gpio_info *gi, int value)
{
- while (num--)
- gpio_free((array++)->gpio);
+ if (gi->chip->ops->set)
+ gi->chip->ops->set(gi->chip, gpioinfo_chip_offset(gi), value);
}
-EXPORT_SYMBOL_GPL(gpio_free_array);
void gpio_set_value(unsigned gpio, int value)
{
@@ -231,8 +179,7 @@ void gpio_set_value(unsigned gpio, int value)
if (gpio_ensure_requested(gi, gpio))
return;
- if (gi->chip->ops->set)
- gi->chip->ops->set(gi->chip, gpio - gi->chip->base, value);
+ gpioinfo_set_value(gi, value);
}
EXPORT_SYMBOL(gpio_set_value);
@@ -247,6 +194,14 @@ void gpio_set_active(unsigned gpio, bool value)
}
EXPORT_SYMBOL(gpio_set_active);
+static int gpioinfo_get_value(struct gpio_info *gi)
+{
+ if (!gi->chip->ops->get)
+ return -ENOSYS;
+
+ return gi->chip->ops->get(gi->chip, gpioinfo_chip_offset(gi));
+}
+
int gpio_get_value(unsigned gpio)
{
struct gpio_info *gi = gpio_to_desc(gpio);
@@ -259,9 +214,7 @@ int gpio_get_value(unsigned gpio)
if (ret)
return ret;
- if (!gi->chip->ops->get)
- return -ENOSYS;
- return gi->chip->ops->get(gi->chip, gpio - gi->chip->base);
+ return gpioinfo_get_value(gi);
}
EXPORT_SYMBOL(gpio_get_value);
@@ -276,6 +229,15 @@ int gpio_is_active(unsigned gpio)
}
EXPORT_SYMBOL(gpio_is_active);
+static int gpioinfo_direction_output(struct gpio_info *gi, int value)
+{
+ if (!gi->chip->ops->direction_output)
+ return -ENOSYS;
+
+ return gi->chip->ops->direction_output(gi->chip,
+ gpioinfo_chip_offset(gi), value);
+}
+
int gpio_direction_output(unsigned gpio, int value)
{
struct gpio_info *gi = gpio_to_desc(gpio);
@@ -288,13 +250,15 @@ int gpio_direction_output(unsigned gpio, int value)
if (ret)
return ret;
- if (!gi->chip->ops->direction_output)
- return -ENOSYS;
- return gi->chip->ops->direction_output(gi->chip, gpio - gi->chip->base,
- value);
+ return gpioinfo_direction_output(gi, value);
}
EXPORT_SYMBOL(gpio_direction_output);
+static int gpioinfo_direction_active(struct gpio_info *gi, bool value)
+{
+ return gpioinfo_direction_output(gi, gpio_adjust_value(gi, value));
+}
+
int gpio_direction_active(unsigned gpio, bool value)
{
struct gpio_info *gi = gpio_to_desc(gpio);
@@ -302,10 +266,19 @@ int gpio_direction_active(unsigned gpio, bool value)
if (!gi)
return -ENODEV;
- return gpio_direction_output(gpio, gpio_adjust_value(gi, value));
+ return gpioinfo_direction_active(gi, value);
}
EXPORT_SYMBOL(gpio_direction_active);
+static int gpioinfo_direction_input(struct gpio_info *gi)
+{
+ if (!gi->chip->ops->direction_input)
+ return -ENOSYS;
+
+ return gi->chip->ops->direction_input(gi->chip,
+ gpioinfo_chip_offset(gi));
+}
+
int gpio_direction_input(unsigned gpio)
{
struct gpio_info *gi = gpio_to_desc(gpio);
@@ -318,12 +291,96 @@ int gpio_direction_input(unsigned gpio)
if (ret)
return ret;
- if (!gi->chip->ops->direction_input)
- return -ENOSYS;
- return gi->chip->ops->direction_input(gi->chip, gpio - gi->chip->base);
+ return gpioinfo_direction_input(gi);
}
EXPORT_SYMBOL(gpio_direction_input);
+static int gpioinfo_request_one(struct gpio_info *gi, unsigned long flags,
+ const char *label)
+{
+ int err;
+
+ /*
+ * Not all of the flags below are mulit-bit, but, for the sake
+ * of consistency, the code is written as if all of them were.
+ */
+ const bool active_low = (flags & GPIOF_ACTIVE_LOW) == GPIOF_ACTIVE_LOW;
+ const bool dir_in = (flags & GPIOF_DIR_IN) == GPIOF_DIR_IN;
+ const bool logical = (flags & GPIOF_LOGICAL) == GPIOF_LOGICAL;
+ const bool init_active = (flags & GPIOF_INIT_ACTIVE) == GPIOF_INIT_ACTIVE;
+ const bool init_high = (flags & GPIOF_INIT_HIGH) == GPIOF_INIT_HIGH;
+
+ err = gpioinfo_request(gi, label);
+ if (err)
+ return err;
+
+ gi->active_low = active_low;
+
+ if (dir_in)
+ err = gpioinfo_direction_input(gi);
+ else if (logical)
+ err = gpioinfo_direction_active(gi, init_active);
+ else
+ err = gpioinfo_direction_output(gi, init_high);
+
+ if (err)
+ gpioinfo_free(gi);
+
+ return err;
+}
+
+/**
+ * gpio_request_one - request a single GPIO with initial configuration
+ * @gpio: the GPIO number
+ * @flags: GPIO configuration as specified by GPIOF_*
+ * @label: a literal description string of this GPIO
+ */
+int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
+{
+ struct gpio_info *gi = gpio_to_desc(gpio);
+
+ if (!gi)
+ return -ENODEV;
+
+ return gpioinfo_request_one(gi, flags, label);
+}
+EXPORT_SYMBOL_GPL(gpio_request_one);
+
+/**
+ * gpio_request_array - request multiple GPIOs in a single call
+ * @array: array of the 'struct gpio'
+ * @num: how many GPIOs in the array
+ */
+int gpio_request_array(const struct gpio *array, size_t num)
+{
+ int i, err;
+
+ for (i = 0; i < num; i++, array++) {
+ err = gpio_request_one(array->gpio, array->flags, array->label);
+ if (err)
+ goto err_free;
+ }
+ return 0;
+
+err_free:
+ while (i--)
+ gpio_free((--array)->gpio);
+ return err;
+}
+EXPORT_SYMBOL_GPL(gpio_request_array);
+
+/**
+ * gpio_free_array - release multiple GPIOs in a single call
+ * @array: array of the 'struct gpio'
+ * @num: how many GPIOs in the array
+ */
+void gpio_free_array(const struct gpio *array, size_t num)
+{
+ while (num--)
+ gpio_free((array++)->gpio);
+}
+EXPORT_SYMBOL_GPL(gpio_free_array);
+
static int gpiochip_find_base(int start, int ngpio)
{
int i;