aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpio/gpiolib.c
diff options
context:
space:
mode:
authorBartosz Golaszewski <brgl@bgdev.pl>2018-04-10 22:30:28 +0200
committerLinus Walleij <linus.walleij@linaro.org>2018-05-16 14:35:24 +0200
commita411e81e61df24023f40255145d8f023402002c9 (patch)
tree9fce75978e1553b206fea79511034453a174b5b7 /drivers/gpio/gpiolib.c
parentgpio: 104-dio-48e: make array 'ports' static, shrinks object size (diff)
downloadlinux-dev-a411e81e61df24023f40255145d8f023402002c9.tar.xz
linux-dev-a411e81e61df24023f40255145d8f023402002c9.zip
gpiolib: add hogs support for machine code
Board files constitute a significant part of the users of the legacy GPIO framework. In many cases they only export a line and set its desired value. We could use GPIO hogs for that like we do for DT and ACPI but there's no support for that in machine code. This patch proposes to extend the machine.h API with support for registering hog tables in board files. Signed-off-by: Bartosz Golaszewski <brgl@bgdev.pl> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/gpio/gpiolib.c')
-rw-r--r--drivers/gpio/gpiolib.c67
1 files changed, 67 insertions, 0 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 43aeb07343ec..547adc149b62 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -71,6 +71,9 @@ static DEFINE_MUTEX(gpio_lookup_lock);
static LIST_HEAD(gpio_lookup_list);
LIST_HEAD(gpio_devices);
+static DEFINE_MUTEX(gpio_machine_hogs_mutex);
+static LIST_HEAD(gpio_machine_hogs);
+
static void gpiochip_free_hogs(struct gpio_chip *chip);
static int gpiochip_add_irqchip(struct gpio_chip *gpiochip,
struct lock_class_key *lock_key,
@@ -1171,6 +1174,41 @@ err_remove_device:
return status;
}
+static void gpiochip_machine_hog(struct gpio_chip *chip, struct gpiod_hog *hog)
+{
+ struct gpio_desc *desc;
+ int rv;
+
+ desc = gpiochip_get_desc(chip, hog->chip_hwnum);
+ if (IS_ERR(desc)) {
+ pr_err("%s: unable to get GPIO desc: %ld\n",
+ __func__, PTR_ERR(desc));
+ return;
+ }
+
+ if (desc->flags & FLAG_IS_HOGGED)
+ return;
+
+ rv = gpiod_hog(desc, hog->line_name, hog->lflags, hog->dflags);
+ if (rv)
+ pr_err("%s: unable to hog GPIO line (%s:%u): %d\n",
+ __func__, chip->label, hog->chip_hwnum, rv);
+}
+
+static void machine_gpiochip_add(struct gpio_chip *chip)
+{
+ struct gpiod_hog *hog;
+
+ mutex_lock(&gpio_machine_hogs_mutex);
+
+ list_for_each_entry(hog, &gpio_machine_hogs, list) {
+ if (!strcmp(chip->label, hog->chip_label))
+ gpiochip_machine_hog(chip, hog);
+ }
+
+ mutex_unlock(&gpio_machine_hogs_mutex);
+}
+
static void gpiochip_setup_devs(void)
{
struct gpio_device *gdev;
@@ -1326,6 +1364,8 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
acpi_gpiochip_add(chip);
+ machine_gpiochip_add(chip);
+
/*
* By first adding the chardev, and then adding the device,
* we get a device node entry in sysfs under
@@ -3462,6 +3502,33 @@ void gpiod_remove_lookup_table(struct gpiod_lookup_table *table)
}
EXPORT_SYMBOL_GPL(gpiod_remove_lookup_table);
+/**
+ * gpiod_add_hogs() - register a set of GPIO hogs from machine code
+ * @hogs: table of gpio hog entries with a zeroed sentinel at the end
+ */
+void gpiod_add_hogs(struct gpiod_hog *hogs)
+{
+ struct gpio_chip *chip;
+ struct gpiod_hog *hog;
+
+ mutex_lock(&gpio_machine_hogs_mutex);
+
+ for (hog = &hogs[0]; hog->chip_label; hog++) {
+ list_add_tail(&hog->list, &gpio_machine_hogs);
+
+ /*
+ * The chip may have been registered earlier, so check if it
+ * exists and, if so, try to hog the line now.
+ */
+ chip = find_chip_by_name(hog->chip_label);
+ if (chip)
+ gpiochip_machine_hog(chip, hog);
+ }
+
+ mutex_unlock(&gpio_machine_hogs_mutex);
+}
+EXPORT_SYMBOL_GPL(gpiod_add_hogs);
+
static struct gpiod_lookup_table *gpiod_find_lookup_table(struct device *dev)
{
const char *dev_id = dev ? dev_name(dev) : NULL;