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.c960
1 files changed, 788 insertions, 172 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index f96009896a..a70e13eafc 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
#define pr_fmt(fmt) "gpiolib: " fmt
#include <init.h>
@@ -6,37 +7,70 @@
#include <complete.h>
#include <gpio.h>
#include <of_gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/overflow.h>
#include <errno.h>
#include <malloc.h>
static LIST_HEAD(chip_list);
-struct gpio_info {
+struct gpio_desc {
struct gpio_chip *chip;
bool requested;
bool active_low;
char *label;
+ const char *name;
};
-static struct gpio_info *gpio_desc;
+/*
+ * This descriptor validation needs to be inserted verbatim into each
+ * function taking a descriptor, so we need to use a preprocessor
+ * macro to avoid endless duplication. If the desc is NULL it is an
+ * optional GPIO and calls should just bail out.
+ */
+static int validate_desc(const struct gpio_desc *desc, const char *func)
+{
+ if (!desc)
+ return 0;
+ if (IS_ERR(desc)) {
+ pr_warn("%s: invalid GPIO (errorpointer)\n", func);
+ return PTR_ERR(desc);
+ }
+
+ return 1;
+}
+
+#define VALIDATE_DESC(desc) do { \
+ int __valid = validate_desc(desc, __func__); \
+ if (__valid <= 0) \
+ return __valid; \
+ } while (0)
+
+#define VALIDATE_DESC_VOID(desc) do { \
+ int __valid = validate_desc(desc, __func__); \
+ if (__valid <= 0) \
+ return; \
+ } while (0)
+
+static struct gpio_desc *gpio_desc;
static int gpio_desc_alloc(void)
{
- gpio_desc = xzalloc(sizeof(struct gpio_info) * ARCH_NR_GPIOS);
+ gpio_desc = xzalloc(sizeof(struct gpio_desc) * ARCH_NR_GPIOS);
return 0;
}
pure_initcall(gpio_desc_alloc);
-static int gpio_ensure_requested(struct gpio_info *gi, int gpio)
+static int gpio_ensure_requested(struct gpio_desc *desc, int gpio)
{
- if (gi->requested)
+ if (desc->requested)
return 0;
return gpio_request(gpio, "gpio");
}
-static struct gpio_info *gpio_to_desc(unsigned gpio)
+static struct gpio_desc *gpio_to_desc(unsigned gpio)
{
if (gpio_is_valid(gpio))
if (gpio_desc[gpio].chip)
@@ -47,46 +81,46 @@ static struct gpio_info *gpio_to_desc(unsigned gpio)
return NULL;
}
-static int gpio_adjust_value(struct gpio_info *gi,
+static unsigned gpiodesc_chip_offset(const struct gpio_desc *desc)
+{
+ return (desc - gpio_desc) - desc->chip->base;
+}
+
+static int gpio_adjust_value(const struct gpio_desc *desc,
int value)
{
if (value < 0)
return value;
- return !!value ^ gi->active_low;
+ return !!value ^ desc->active_low;
}
-int gpio_request(unsigned gpio, const char *label)
+static int gpiodesc_request(struct gpio_desc *desc, const char *label)
{
- struct gpio_info *gi = gpio_to_desc(gpio);
int ret;
- if (!gi) {
- ret = -ENODEV;
- goto done;
- }
-
- if (gi->requested) {
+ if (desc->requested) {
ret = -EBUSY;
goto done;
}
ret = 0;
- if (gi->chip->ops->request) {
- ret = gi->chip->ops->request(gi->chip, gpio - gi->chip->base);
+ if (desc->chip->ops->request) {
+ ret = desc->chip->ops->request(desc->chip,
+ gpiodesc_chip_offset(desc));
if (ret)
goto done;
}
- gi->requested = true;
- gi->active_low = false;
- gi->label = xstrdup(label);
+ desc->requested = true;
+ desc->active_low = false;
+ desc->label = xstrdup(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",
+ desc - gpio_desc, label ? : "?", ret);
return ret;
}
@@ -96,7 +130,7 @@ int gpio_find_by_label(const char *label)
int i;
for (i = 0; i < ARCH_NR_GPIOS; i++) {
- struct gpio_info *info = &gpio_desc[i];
+ struct gpio_desc *info = &gpio_desc[i];
if (!info->requested || !info->chip || !info->label)
continue;
@@ -108,225 +142,460 @@ int gpio_find_by_label(const char *label)
return -ENOENT;
}
-void gpio_free(unsigned gpio)
+int gpio_find_by_name(const char *name)
{
- struct gpio_info *gi = gpio_to_desc(gpio);
+ int i;
- if (!gi)
- return;
+ for (i = 0; i < ARCH_NR_GPIOS; i++) {
+ struct gpio_desc *info = &gpio_desc[i];
- if (!gi->requested)
- return;
+ if (!info->chip || !info->name)
+ continue;
- if (gi->chip->ops->free)
- gi->chip->ops->free(gi->chip, gpio - gi->chip->base);
+ if (!strcmp(info->name, name))
+ return i;
+ }
- gi->requested = false;
- gi->active_low = false;
- free(gi->label);
- gi->label = NULL;
+ return -ENOENT;
}
-/**
- * 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)
+int gpio_request(unsigned gpio, const char *label)
{
- int err;
- struct gpio_info *gi = gpio_to_desc(gpio);
+ struct gpio_desc *desc = 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;
+ if (!desc) {
+ pr_err("_gpio_request: gpio-%d (%s) status %d\n",
+ gpio, label ? : "?", -ENODEV);
+ return -ENODEV;
+ }
- err = gpio_request(gpio, label);
- if (err)
- return err;
+ return gpiodesc_request(desc, label);
+}
- gi->active_low = active_low;
+bool gpiod_slice_acquired(struct gpio_desc *desc)
+{
+ if (!desc)
+ return false;
- 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);
+ return slice_acquired(&desc->chip->slice);
+}
- if (err)
- gpio_free(gpio);
+bool gpio_slice_acquired(unsigned gpio)
+{
+ struct gpio_desc *desc = gpio_to_desc(gpio);
- return err;
+ return gpiod_slice_acquired(desc);
+}
+
+static void gpiodesc_free(struct gpio_desc *desc)
+{
+ if (!desc->requested)
+ return;
+
+ if (desc->chip->ops->free)
+ desc->chip->ops->free(desc->chip, gpiodesc_chip_offset(desc));
+
+ desc->requested = false;
+ desc->active_low = false;
+ free(desc->label);
+ desc->label = NULL;
+}
+
+void gpio_free(unsigned gpio)
+{
+ struct gpio_desc *desc = gpio_to_desc(gpio);
+
+ gpiodesc_free(desc);
}
-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
+ * gpiod_put - dispose of a GPIO descriptor
+ * @desc: GPIO descriptor to dispose of
+ *
+ * No descriptor can be used after gpiod_put() has been called on it.
*/
-int gpio_request_array(const struct gpio *array, size_t num)
+void gpiod_put(struct gpio_desc *desc)
{
- int i, err;
+ if (!desc)
+ return;
- for (i = 0; i < num; i++, array++) {
- err = gpio_request_one(array->gpio, array->flags, array->label);
- if (err)
- goto err_free;
- }
- return 0;
+ gpiodesc_free(desc);
+}
+EXPORT_SYMBOL(gpiod_put);
-err_free:
- while (i--)
- gpio_free((--array)->gpio);
- return err;
+/**
+ * gpiod_put_array - dispose of multiple GPIO descriptors
+ * @descs: struct gpio_descs containing an array of descriptors
+ */
+void gpiod_put_array(struct gpio_descs *descs)
+{
+ unsigned int i;
+
+ for (i = 0; i < descs->ndescs; i++)
+ gpiod_put(descs->desc[i]);
+
+ kfree(descs);
}
-EXPORT_SYMBOL_GPL(gpio_request_array);
+EXPORT_SYMBOL_GPL(gpiod_put_array);
/**
- * gpio_free_array - release multiple GPIOs in a single call
- * @array: array of the 'struct gpio'
- * @num: how many GPIOs in the array
+ * gpiod_set_raw_value() - assign a gpio's raw value
+ * @desc: gpio whose value will be assigned
+ * @value: value to assign
+ *
+ * Set the raw value of the GPIO, i.e. the value of its physical line without
+ * regard for its ACTIVE_LOW status.
*/
-void gpio_free_array(const struct gpio *array, size_t num)
+void gpiod_set_raw_value(struct gpio_desc *desc, int value)
{
- while (num--)
- gpio_free((array++)->gpio);
+ VALIDATE_DESC_VOID(desc);
+
+ if (desc->chip->ops->set)
+ desc->chip->ops->set(desc->chip, gpiodesc_chip_offset(desc), value);
}
-EXPORT_SYMBOL_GPL(gpio_free_array);
+EXPORT_SYMBOL(gpiod_set_raw_value);
void gpio_set_value(unsigned gpio, int value)
{
- struct gpio_info *gi = gpio_to_desc(gpio);
+ struct gpio_desc *desc = gpio_to_desc(gpio);
- if (!gi)
+ if (!desc)
return;
- if (gpio_ensure_requested(gi, gpio))
+ if (gpio_ensure_requested(desc, gpio))
return;
- if (gi->chip->ops->set)
- gi->chip->ops->set(gi->chip, gpio - gi->chip->base, value);
+ gpiod_set_raw_value(desc, value);
}
EXPORT_SYMBOL(gpio_set_value);
+/**
+ * gpiod_set_value() - assign a gpio's value
+ * @desc: gpio whose value will be assigned
+ * @value: value to assign
+ *
+ * Set the logical value of the GPIO, i.e. taking its ACTIVE_LOW,
+ * OPEN_DRAIN and OPEN_SOURCE flags into account.
+ */
+void gpiod_set_value(struct gpio_desc *desc, int value)
+{
+ VALIDATE_DESC_VOID(desc);
+ gpiod_set_raw_value(desc, gpio_adjust_value(desc, value));
+}
+EXPORT_SYMBOL_GPL(gpiod_set_value);
+
void gpio_set_active(unsigned gpio, bool value)
{
- struct gpio_info *gi = gpio_to_desc(gpio);
+ struct gpio_desc *desc = gpio_to_desc(gpio);
- if (!gi)
+ if (!desc)
return;
- gpio_set_value(gpio, gpio_adjust_value(gi, value));
+ gpiod_set_value(desc, value);
}
EXPORT_SYMBOL(gpio_set_active);
+/**
+ * gpiod_get_raw_value() - return a gpio's raw value
+ * @desc: gpio whose value will be returned
+ *
+ * Return the GPIO's raw value, i.e. the value of the physical line disregarding
+ * its ACTIVE_LOW status, or negative errno on failure.
+ */
+int gpiod_get_raw_value(const struct gpio_desc *desc)
+{
+ VALIDATE_DESC(desc);
+
+ if (!desc->chip->ops->get)
+ return -ENOSYS;
+
+ return desc->chip->ops->get(desc->chip, gpiodesc_chip_offset(desc));
+}
+EXPORT_SYMBOL_GPL(gpiod_get_raw_value);
+
int gpio_get_value(unsigned gpio)
{
- struct gpio_info *gi = gpio_to_desc(gpio);
+ struct gpio_desc *desc = gpio_to_desc(gpio);
int ret;
- if (!gi)
+ if (!desc)
return -ENODEV;
- ret = gpio_ensure_requested(gi, gpio);
+ ret = gpio_ensure_requested(desc, gpio);
if (ret)
return ret;
- if (!gi->chip->ops->get)
- return -ENOSYS;
- return gi->chip->ops->get(gi->chip, gpio - gi->chip->base);
+ return gpiod_get_raw_value(desc);
}
EXPORT_SYMBOL(gpio_get_value);
+/**
+ * gpiod_get_value() - return a gpio's value
+ * @desc: gpio whose value will be returned
+ *
+ * Return the GPIO's logical value, i.e. taking the ACTIVE_LOW status into
+ * account, or negative errno on failure.
+ */
+int gpiod_get_value(const struct gpio_desc *desc)
+{
+ VALIDATE_DESC(desc);
+
+ return gpio_adjust_value(desc, gpiod_get_raw_value(desc));
+}
+EXPORT_SYMBOL_GPL(gpiod_get_value);
+
int gpio_is_active(unsigned gpio)
{
- struct gpio_info *gi = gpio_to_desc(gpio);
+ struct gpio_desc *desc = gpio_to_desc(gpio);
- if (!gi)
+ if (!desc)
return -ENODEV;
- return gpio_adjust_value(gi, gpio_get_value(gpio));
+ return gpiod_get_value(desc);
}
EXPORT_SYMBOL(gpio_is_active);
+/**
+ * gpiod_direction_output_raw - set the GPIO direction to output
+ * @desc: GPIO to set to output
+ * @value: initial output value of the GPIO
+ *
+ * Set the direction of the passed GPIO to output, such as gpiod_set_value() can
+ * be called safely on it. The initial value of the output must be specified
+ * as raw value on the physical line without regard for the ACTIVE_LOW status.
+ *
+ * Return 0 in case of success, else an error code.
+ */
+int gpiod_direction_output_raw(struct gpio_desc *desc, int value)
+{
+ VALIDATE_DESC(desc);
+
+ if (!desc->chip->ops->direction_output)
+ return -ENOSYS;
+
+ return desc->chip->ops->direction_output(desc->chip,
+ gpiodesc_chip_offset(desc), value);
+}
+EXPORT_SYMBOL(gpiod_direction_output_raw);
+
int gpio_direction_output(unsigned gpio, int value)
{
- struct gpio_info *gi = gpio_to_desc(gpio);
+ struct gpio_desc *desc = gpio_to_desc(gpio);
int ret;
- if (!gi)
+ if (!desc)
return -ENODEV;
- ret = gpio_ensure_requested(gi, gpio);
+ ret = gpio_ensure_requested(desc, gpio);
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 gpiod_direction_output_raw(desc, value);
}
EXPORT_SYMBOL(gpio_direction_output);
+/**
+ * gpiod_direction_output - set the GPIO direction to output
+ * @desc: GPIO to set to output
+ * @value: initial output value of the GPIO
+ *
+ * Set the direction of the passed GPIO to output, such as gpiod_set_value() can
+ * be called safely on it. The initial value of the output must be specified
+ * as the logical value of the GPIO, i.e. taking its ACTIVE_LOW status into
+ * account.
+ *
+ * Return 0 in case of success, else an error code.
+ */
+int gpiod_direction_output(struct gpio_desc *desc, int value)
+{
+ VALIDATE_DESC(desc);
+
+ return gpiod_direction_output_raw(desc, gpio_adjust_value(desc, value));
+}
+
int gpio_direction_active(unsigned gpio, bool value)
{
- struct gpio_info *gi = gpio_to_desc(gpio);
+ struct gpio_desc *desc = gpio_to_desc(gpio);
- if (!gi)
+ if (!desc)
return -ENODEV;
- return gpio_direction_output(gpio, gpio_adjust_value(gi, value));
+ return gpiod_direction_output(desc, value);
}
EXPORT_SYMBOL(gpio_direction_active);
+/**
+ * gpiod_direction_input - set the GPIO direction to input
+ * @desc: GPIO to set to input
+ *
+ * Set the direction of the passed GPIO to input, such as gpiod_get_value() can
+ * be called safely on it.
+ *
+ * Return 0 in case of success, else an error code.
+ */
+int gpiod_direction_input(struct gpio_desc *desc)
+{
+ VALIDATE_DESC(desc);
+
+ if (!desc->chip->ops->direction_input)
+ return -ENOSYS;
+
+ return desc->chip->ops->direction_input(desc->chip,
+ gpiodesc_chip_offset(desc));
+}
+EXPORT_SYMBOL(gpiod_direction_input);
+
int gpio_direction_input(unsigned gpio)
{
- struct gpio_info *gi = gpio_to_desc(gpio);
+ struct gpio_desc *desc = gpio_to_desc(gpio);
int ret;
- if (!gi)
+ if (!desc)
return -ENODEV;
- ret = gpio_ensure_requested(gi, gpio);
+ ret = gpio_ensure_requested(desc, 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 gpiod_direction_input(desc);
}
EXPORT_SYMBOL(gpio_direction_input);
-static int gpiochip_find_base(int start, int ngpio)
+static int gpiodesc_request_one(struct gpio_desc *desc, 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 = gpiodesc_request(desc, label);
+ if (err)
+ return err;
+
+ desc->active_low = active_low;
+
+ if (dir_in)
+ err = gpiod_direction_input(desc);
+ else if (logical)
+ err = gpiod_direction_output(desc, init_active);
+ else
+ err = gpiod_direction_output_raw(desc, init_high);
+
+ if (err)
+ gpiodesc_free(desc);
+
+ 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_desc *desc = gpio_to_desc(gpio);
+
+ if (!desc)
+ return -ENODEV;
+
+ return gpiodesc_request_one(desc, 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);
+
+int gpio_array_to_id(const struct gpio *array, size_t num, u32 *val)
+{
+ u32 id = 0;
+ int ret, i;
+
+ if (num > 32)
+ return -EOVERFLOW;
+
+ ret = gpio_request_array(array, num);
+ if (ret)
+ return ret;
+
+ /* Wait until logic level will be stable */
+ udelay(5);
+ for (i = 0; i < num; i++) {
+ ret = gpio_is_active(array[i].gpio);
+ if (ret < 0)
+ goto free_array;
+ if (ret)
+ id |= 1UL << i;
+ }
+
+ *val = id;
+ ret = 0;
+
+free_array:
+ gpio_free_array(array, num);
+ return ret;
+}
+EXPORT_SYMBOL(gpio_array_to_id);
+
+static int gpiochip_find_base(int ngpio)
{
int i;
int spare = 0;
int base = -ENOSPC;
- if (start < 0)
- start = 0;
-
- for (i = start; i < ARCH_NR_GPIOS; i++) {
+ for (i = ARCH_NR_GPIOS - 1; i >= 0; i--) {
struct gpio_chip *chip = gpio_desc[i].chip;
if (!chip) {
spare++;
if (spare == ngpio) {
- base = i + 1 - ngpio;
+ base = i;
break;
}
} else {
spare = 0;
- i += chip->ngpio - 1;
+ i -= chip->ngpio - 1;
}
}
@@ -335,10 +604,12 @@ static int gpiochip_find_base(int start, int ngpio)
return base;
}
+#ifdef CONFIG_OF_GPIO
+
static int of_hog_gpio(struct device_node *np, struct gpio_chip *chip,
unsigned int idx)
{
- struct device_node *chip_np = chip->dev->device_node;
+ struct device_node *chip_np = chip->dev->of_node;
unsigned long flags = 0;
u32 gpio_cells, gpio_num, gpio_flags;
int ret, gpio;
@@ -412,10 +683,7 @@ static int of_gpiochip_scan_hogs(struct gpio_chip *chip)
struct device_node *np;
int ret, i;
- if (!IS_ENABLED(CONFIG_OFDEVICE) || !chip->dev->device_node)
- return 0;
-
- for_each_available_child_of_node(chip->dev->device_node, np) {
+ for_each_available_child_of_node(chip->dev->of_node, np) {
if (!of_property_read_bool(np, "gpio-hog"))
continue;
@@ -434,25 +702,340 @@ static int of_gpiochip_scan_hogs(struct gpio_chip *chip)
return 0;
}
-int gpiochip_add(struct gpio_chip *chip)
+/*
+ * of_gpiochip_set_names - Set GPIO line names using OF properties
+ * @chip: GPIO chip whose lines should be named, if possible
+ *
+ * Looks for device property "gpio-line-names" and if it exists assigns
+ * GPIO line names for the chip. The memory allocated for the assigned
+ * names belong to the underlying firmware node and should not be released
+ * by the caller.
+ */
+static int of_gpiochip_set_names(struct gpio_chip *chip)
+{
+ struct device_node *np = dev_of_node(chip->dev);
+ const char **names;
+ int ret, i, count;
+
+ count = of_property_count_strings(np, "gpio-line-names");
+ if (count < 0)
+ return 0;
+
+ names = kcalloc(count, sizeof(*names), GFP_KERNEL);
+ if (!names)
+ return -ENOMEM;
+
+ ret = of_property_read_string_array(np, "gpio-line-names",
+ names, count);
+ if (ret < 0) {
+ kfree(names);
+ return ret;
+ }
+
+ /*
+ * Since property 'gpio-line-names' cannot contains gaps, we
+ * have to be sure we only assign those pins that really exists
+ * since chip->ngpio can be less.
+ */
+ if (count > chip->ngpio)
+ count = chip->ngpio;
+
+ for (i = 0; i < count; i++) {
+ /*
+ * Allow overriding "fixed" names provided by the GPIO
+ * provider. The "fixed" names are more often than not
+ * generic and less informative than the names given in
+ * device properties.
+ */
+ if (names[i] && names[i][0])
+ gpio_desc[chip->base + i].name = names[i];
+ }
+
+ free(names);
+
+ return 0;
+}
+
+/**
+ * of_gpio_simple_xlate - translate gpiospec to the GPIO number and flags
+ * @gc: pointer to the gpio_chip structure
+ * @gpiospec: GPIO specifier as found in the device tree
+ * @flags: a flags pointer to fill in
+ *
+ * This is simple translation function, suitable for the most 1:1 mapped
+ * GPIO chips. This function performs only one sanity check: whether GPIO
+ * is less than ngpios (that is specified in the gpio_chip).
+ */
+static int of_gpio_simple_xlate(struct gpio_chip *gc,
+ const struct of_phandle_args *gpiospec,
+ u32 *flags)
+{
+ /*
+ * We're discouraging gpio_cells < 2, since that way you'll have to
+ * write your own xlate function (that will have to retrieve the GPIO
+ * number and the flags from a single gpio cell -- this is possible,
+ * but not recommended).
+ */
+ if (WARN_ON(gc->of_gpio_n_cells < 2))
+ return -EINVAL;
+
+ if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells))
+ return -EINVAL;
+
+ if (gpiospec->args[0] >= gc->ngpio)
+ return -EINVAL;
+
+ if (flags)
+ *flags = gpiospec->args[1];
+
+ return gc->base + gpiospec->args[0];
+}
+
+static int of_gpiochip_add(struct gpio_chip *chip)
+{
+ struct device_node *np;
+ int ret;
+
+ np = dev_of_node(chip->dev);
+ if (!np)
+ return 0;
+
+ if (!chip->ops->of_xlate)
+ chip->ops->of_xlate = of_gpio_simple_xlate;
+
+ /*
+ * Separate check since the 'struct gpio_ops' is always the same for
+ * every 'struct gpio_chip' of the same instance (e.g. 'struct
+ * imx_gpio_chip').
+ */
+ if (chip->ops->of_xlate == of_gpio_simple_xlate)
+ chip->of_gpio_n_cells = 2;
+
+ if (chip->of_gpio_n_cells > MAX_PHANDLE_ARGS)
+ return -EINVAL;
+
+ ret = of_gpiochip_set_names(chip);
+ if (ret)
+ return ret;
+
+ return of_gpiochip_scan_hogs(chip);
+}
+#else
+static int of_gpiochip_add(struct gpio_chip *chip)
+{
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_OFDEVICE
+static const char *gpio_suffixes[] = {
+ "gpios",
+ "gpio",
+};
+
+static struct property *of_find_gpio_property(struct device_node *np,
+ const char *_con_id)
+{
+ struct property *pp = NULL;
+ char *con_id;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
+ if (_con_id)
+ con_id = basprintf("%s-%s", _con_id, gpio_suffixes[i]);
+ else
+ con_id = basprintf("%s", gpio_suffixes[i]);
+
+ if (!con_id)
+ return ERR_PTR(-ENOMEM);
+
+ pp = of_find_property(np, con_id, NULL);
+ free(con_id);
+
+ if (pp)
+ return pp;
+ }
+
+ return NULL;
+}
+
+/* Linux compatibility helper: Get a GPIO descriptor from device tree */
+struct gpio_desc *dev_gpiod_get_index(struct device *dev,
+ struct device_node *np,
+ const char *con_id, int index,
+ enum gpiod_flags flags,
+ const char *label)
+{
+ struct gpio_desc *desc = NULL;
+ enum of_gpio_flags of_flags;
+ struct property *pp;
+ char *buf = NULL;
+ int gpio;
+ int ret;
+
+ if (!np)
+ return ERR_PTR(-ENODEV);
+
+ pp = of_find_gpio_property(np, con_id);
+ if (!pp)
+ return ERR_PTR(-ENOENT);
+
+ gpio = of_get_named_gpio_flags(dev->device_node, pp->name,
+ index, &of_flags);
+ if (!gpio_is_valid(gpio))
+ return ERR_PTR(gpio < 0 ? gpio : -EINVAL);
+
+ desc = gpio_to_desc(gpio);
+
+ if (of_flags & OF_GPIO_ACTIVE_LOW)
+ flags |= GPIOF_ACTIVE_LOW;
+
+ buf = NULL;
+
+ if (!label) {
+ if (con_id)
+ label = buf = basprintf("%s-%s", dev_name(dev), con_id);
+ else
+ label = dev_name(dev);
+ }
+
+ ret = gpiodesc_request_one(desc, flags, label);
+ free(buf);
+
+ return ret ? ERR_PTR(ret): desc;
+}
+
+/**
+ * gpiod_count - return the number of GPIOs associated with a device / function
+ * or -ENOENT if no GPIO has been assigned to the requested function
+ * @dev: GPIO consumer, can be NULL for system-global GPIOs
+ * @_con_id: function within the GPIO consumer
+ */
+int gpiod_count(struct device *dev, const char *con_id)
+{
+ struct device_node *np = dev_of_node(dev);
+ struct property *pp;
+
+ if (!np)
+ return -ENODEV;
+
+ pp = of_find_gpio_property(np, con_id);
+ if (!pp)
+ return -ENOENT;
+
+ return of_gpio_named_count(np, pp->name);
+}
+EXPORT_SYMBOL_GPL(gpiod_count);
+
+/**
+ * gpiod_get_array - obtain multiple GPIOs from a multi-index GPIO function
+ * @dev: GPIO consumer, can be NULL for system-global GPIOs
+ * @con_id: function within the GPIO consumer
+ * @flags: optional GPIO initialization flags
+ *
+ * This function acquires all the GPIOs defined under a given function.
+ *
+ * Return a struct gpio_descs containing an array of descriptors, -ENOENT if
+ * no GPIO has been assigned to the requested function, or another IS_ERR()
+ * code if an error occurred while trying to acquire the GPIOs.
+ */
+struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
+ const char *con_id,
+ enum gpiod_flags flags)
+{
+ struct gpio_desc *desc;
+ struct gpio_descs *descs;
+ int count;
+
+ count = gpiod_count(dev, con_id);
+ if (count < 0)
+ return ERR_PTR(count);
+
+ descs = kzalloc(struct_size(descs, desc, count), GFP_KERNEL);
+ if (!descs)
+ return ERR_PTR(-ENOMEM);
+
+ for (descs->ndescs = 0; descs->ndescs < count; descs->ndescs++) {
+ desc = dev_gpiod_get_index(dev, dev_of_node(dev), con_id,
+ descs->ndescs, flags, NULL);
+ if (IS_ERR(desc)) {
+ gpiod_put_array(descs);
+ return ERR_CAST(desc);
+ }
+
+ descs->desc[descs->ndescs] = desc;
+ }
+
+ return descs;
+}
+EXPORT_SYMBOL_GPL(gpiod_get_array);
+
+#endif
+
+static int gpiod_set_array_value_complex(bool raw,
+ unsigned int array_size,
+ struct gpio_desc **desc_array,
+ struct gpio_array *array_info,
+ unsigned long *value_bitmap)
+{
+ int i;
+
+ BUG_ON(array_info != NULL);
+
+ for (i = 0; i < array_size; i++)
+ gpiod_set_value(desc_array[i], test_bit(i, value_bitmap));
+
+ return 0;
+}
+
+/**
+ * gpiod_set_array_value() - assign values to an array of GPIOs
+ * @array_size: number of elements in the descriptor array / value bitmap
+ * @desc_array: array of GPIO descriptors whose values will be assigned
+ * @array_info: information on applicability of fast bitmap processing path
+ * @value_bitmap: bitmap of values to assign
+ *
+ * Set the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status
+ * into account. NOTE: This function has no special handling for GPIOs
+ * in the same bank that could've been set atomically: GPIO sequencing
+ * is not guaranteed to always remain in the same order.
+ */
+int gpiod_set_array_value(unsigned int array_size,
+ struct gpio_desc **desc_array,
+ struct gpio_array *array_info,
+ unsigned long *value_bitmap)
{
- int base, i;
+ if (!desc_array)
+ return -EINVAL;
+ return gpiod_set_array_value_complex(false, array_size,
+ desc_array, array_info,
+ value_bitmap);
+}
+EXPORT_SYMBOL_GPL(gpiod_set_array_value);
- base = gpiochip_find_base(chip->base, chip->ngpio);
- if (base < 0)
- return base;
+int gpiochip_add(struct gpio_chip *chip)
+{
+ int i;
- if (chip->base >= 0 && chip->base != base)
- return -EBUSY;
+ if (chip->base >= 0) {
+ for (i = 0; i < chip->ngpio; i++) {
+ if (gpio_desc[chip->base + i].chip)
+ return -EBUSY;
+ }
+ } else {
+ chip->base = gpiochip_find_base(chip->ngpio);
+ if (chip->base < 0)
+ return -ENOSPC;
+ }
- chip->base = base;
+ slice_init(&chip->slice, dev_name(chip->dev));
list_add_tail(&chip->list, &chip_list);
for (i = chip->base; i < chip->base + chip->ngpio; i++)
gpio_desc[i].chip = chip;
- return of_gpiochip_scan_hogs(chip);
+ return of_gpiochip_add(chip);
}
void gpiochip_remove(struct gpio_chip *chip)
@@ -460,61 +1043,93 @@ void gpiochip_remove(struct gpio_chip *chip)
list_del(&chip->list);
}
-int gpio_get_num(struct device_d *dev, int gpio)
+struct gpio_chip *gpio_get_chip_by_dev(struct device *dev)
{
struct gpio_chip *chip;
- if (!dev)
- return -ENODEV;
-
list_for_each_entry(chip, &chip_list, list) {
if (chip->dev == dev)
- return chip->base + gpio;
+ return chip;
}
- return -EPROBE_DEFER;
+ return NULL;
+}
+
+int gpio_get_num(struct device *dev, int gpio)
+{
+ struct gpio_chip *chip;
+
+ if (!dev)
+ return -ENODEV;
+
+ chip = gpio_get_chip_by_dev(dev);
+ if (!chip)
+ return -EPROBE_DEFER;
+
+ return chip->base + gpio;
}
struct gpio_chip *gpio_get_chip(int gpio)
{
- struct gpio_info *gi = gpio_to_desc(gpio);
+ struct gpio_desc *desc = gpio_to_desc(gpio);
- return gi ? gi->chip : NULL;
+ return desc ? desc->chip : NULL;
}
#ifdef CONFIG_CMD_GPIO
static int do_gpiolib(int argc, char *argv[])
{
+ struct gpio_chip *chip = NULL;
int i;
+ if (argc > 2)
+ return COMMAND_ERROR_USAGE;
+
+ if (argc > 1) {
+ struct device *dev;
+
+ dev = find_device(argv[1]);
+ if (!dev)
+ return -ENODEV;
+
+ chip = gpio_get_chip_by_dev(dev);
+ if (!chip)
+ return -EINVAL;
+ }
+
for (i = 0; i < ARCH_NR_GPIOS; i++) {
- struct gpio_info *gi = &gpio_desc[i];
+ struct gpio_desc *desc = &gpio_desc[i];
int val = -1, dir = -1;
+ int idx;
+
+ if (!desc->chip)
+ continue;
- if (!gi->chip)
+ if (chip && chip != desc->chip)
continue;
/* print chip information and header on first gpio */
- if (gi->chip->base == i) {
+ if (desc->chip->base == i) {
printf("\nGPIOs %u-%u, chip %s:\n",
- gi->chip->base,
- gi->chip->base + gi->chip->ngpio - 1,
- gi->chip->dev->name);
- printf("%*cdir val requested label\n", 13, ' ');
+ desc->chip->base,
+ desc->chip->base + desc->chip->ngpio - 1,
+ dev_name(desc->chip->dev));
+ printf(" %-3s %-3s %-9s %-20s %-20s\n", "dir", "val", "requested", "name", "label");
}
- if (gi->chip->ops->get_direction)
- dir = gi->chip->ops->get_direction(gi->chip,
- i - gi->chip->base);
- if (gi->chip->ops->get)
- val = gi->chip->ops->get(gi->chip,
- i - gi->chip->base);
-
- printf(" GPIO %*d: %*s %*s %*s %s\n", 4, i,
- 3, (dir < 0) ? "unk" : ((dir == GPIOF_DIR_IN) ? "in" : "out"),
- 3, (val < 0) ? "unk" : ((val == 0) ? "lo" : "hi"),
- 12, gi->requested ? (gi->active_low ? "active low" : "true") : "false",
- (gi->requested && gi->label) ? gi->label : "");
+ idx = i - desc->chip->base;
+
+ if (desc->chip->ops->get_direction)
+ dir = desc->chip->ops->get_direction(desc->chip, idx);
+ if (desc->chip->ops->get)
+ val = desc->chip->ops->get(desc->chip, idx);
+
+ printf(" GPIO %4d: %-3s %-3s %-9s %-20s %-20s\n", chip ? idx : i,
+ (dir < 0) ? "unk" : ((dir == GPIOF_DIR_IN) ? "in" : "out"),
+ (val < 0) ? "unk" : ((val == 0) ? "lo" : "hi"),
+ desc->requested ? (desc->active_low ? "active low" : "true") : "false",
+ desc->name ? desc->name : "",
+ desc->label ? desc->label : "");
}
return 0;
@@ -523,6 +1138,7 @@ static int do_gpiolib(int argc, char *argv[])
BAREBOX_CMD_START(gpioinfo)
.cmd = do_gpiolib,
BAREBOX_CMD_DESC("list registered GPIOs")
+ BAREBOX_CMD_OPTS("[CONTROLLER]")
BAREBOX_CMD_GROUP(CMD_GRP_INFO)
BAREBOX_CMD_COMPLETE(empty_complete)
BAREBOX_CMD_END