diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2020-06-05 23:00:30 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2020-06-05 23:00:30 +0200 |
commit | 3f7e82379fc91102d82ed89822bd4242c83e40d5 (patch) | |
tree | f0be8a42c4de8009b4d9d37f401b5087d999a147 /drivers/gpio/gpiolib.c | |
parent | Merge tag 'for-linus-5.8-1' of git://github.com/cminyard/linux-ipmi (diff) | |
parent | gpio: pca953x: Drop unneeded ACPI_PTR() (diff) | |
download | linux-3f7e82379fc91102d82ed89822bd4242c83e40d5.tar.xz linux-3f7e82379fc91102d82ed89822bd4242c83e40d5.zip |
Merge tag 'gpio-v5.8-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio
Pull GPIO updates from Linus Walleij:
"This is the bulk of GPIO changes for the v5.8 kernel cycle.
Core changes:
- A new GPIO aggregator driver has been merged: this can join a few
select GPIO lines into a new aggregated GPIO chip. This can be used
for security: a process can be granted access to only these lines,
for example for industrial control. Another way to use this is to
reexpose certain select lines to a virtual machine or container.
- Warn if the gpio-line-names is too long in he DT parser core.
- GPIO lines can now be looked up by line name in addition to being
looked up by offset.
New drivers:
- A new generic regmap GPIO driver has been merged. Too many regmap
drivers are starting to look like each other so we need to create
some common ground and try to move drivers over to using that.
- The F7188X driver now supports F81865.
Driver improvements:
- Large improvements to the PCA953x expander, get multiple lines and
several cleanups.
- Large improvements to the DesignWare DWAPB driver, and Sergey Semin
has volunteered to maintain it.
- PL061 can now be built as a module, this is part of a bigger effort
to make the ARM platforms more modular"
* tag 'gpio-v5.8-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (77 commits)
gpio: pca953x: Drop unneeded ACPI_PTR()
MAINTAINERS: Add gpio regmap section
gpio: add a reusable generic gpio_chip using regmap
gpiolib: Introduce gpiochip_irqchip_add_domain()
gpio: gpiolib: Allow GPIO IRQs to lazy disable
gpiolib: Separate GPIO_GET_LINEINFO_WATCH_IOCTL conditional
gpio: rcar: Fix runtime PM imbalance on error
gpio: pca935x: Allow IRQ support for driver built as a module
gpio: pxa: Add COMPILE_TEST support
dt-bindings: gpio: Add renesas,em-gio bindings
MAINTAINERS: Fix file name for DesignWare GPIO DT schema
gpio: dwapb: Remove unneeded has_irq member in struct dwapb_port_property
gpio: dwapb: Don't use IRQ 0 as valid Linux interrupt
gpio: dwapb: avoid error message for optional IRQ
gpio: dwapb: Call acpi_gpiochip_free_interrupts() on GPIO chip de-registration
gpio: max730x: bring gpiochip_add_data after port config
MAINTAINERS: Add GPIO Aggregator section
docs: gpio: Add GPIO Aggregator documentation
gpio: Add GPIO Aggregator
gpiolib: Add support for GPIO lookup by line name
...
Diffstat (limited to 'drivers/gpio/gpiolib.c')
-rw-r--r-- | drivers/gpio/gpiolib.c | 165 |
1 files changed, 115 insertions, 50 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index c14f0784274a..4fa075d49fbc 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -296,6 +296,9 @@ static int gpiodev_add_to_list(struct gpio_device *gdev) /* * Convert a GPIO name to its descriptor + * Note that there is no guarantee that GPIO names are globally unique! + * Hence this function will return, if it exists, a reference to the first GPIO + * line found that matches the given name. */ static struct gpio_desc *gpio_name_to_desc(const char * const name) { @@ -329,10 +332,12 @@ static struct gpio_desc *gpio_name_to_desc(const char * const name) } /* - * Takes the names from gc->names and checks if they are all unique. If they - * are, they are assigned to their gpio descriptors. + * Take the names from gc->names and assign them to their GPIO descriptors. + * Warn if a name is already used for a GPIO line on a different GPIO chip. * - * Warning if one of the names is already used for a different GPIO. + * Note that: + * 1. Non-unique names are still accepted, + * 2. Name collisions within the same GPIO chip are not reported. */ static int gpiochip_set_desc_names(struct gpio_chip *gc) { @@ -1267,8 +1272,7 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (copy_to_user(ip, &chipinfo, sizeof(chipinfo))) return -EFAULT; return 0; - } else if (cmd == GPIO_GET_LINEINFO_IOCTL || - cmd == GPIO_GET_LINEINFO_WATCH_IOCTL) { + } else if (cmd == GPIO_GET_LINEINFO_IOCTL) { struct gpioline_info lineinfo; if (copy_from_user(&lineinfo, ip, sizeof(lineinfo))) @@ -1280,23 +1284,37 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) hwgpio = gpio_chip_hwgpio(desc); - if (cmd == GPIO_GET_LINEINFO_WATCH_IOCTL && - test_bit(hwgpio, priv->watched_lines)) - return -EBUSY; - gpio_desc_to_lineinfo(desc, &lineinfo); if (copy_to_user(ip, &lineinfo, sizeof(lineinfo))) return -EFAULT; - - if (cmd == GPIO_GET_LINEINFO_WATCH_IOCTL) - set_bit(hwgpio, priv->watched_lines); - return 0; } else if (cmd == GPIO_GET_LINEHANDLE_IOCTL) { return linehandle_create(gdev, ip); } else if (cmd == GPIO_GET_LINEEVENT_IOCTL) { return lineevent_create(gdev, ip); + } else if (cmd == GPIO_GET_LINEINFO_WATCH_IOCTL) { + struct gpioline_info lineinfo; + + if (copy_from_user(&lineinfo, ip, sizeof(lineinfo))) + return -EFAULT; + + desc = gpiochip_get_desc(gc, lineinfo.line_offset); + if (IS_ERR(desc)) + return PTR_ERR(desc); + + hwgpio = gpio_chip_hwgpio(desc); + + if (test_bit(hwgpio, priv->watched_lines)) + return -EBUSY; + + gpio_desc_to_lineinfo(desc, &lineinfo); + + if (copy_to_user(ip, &lineinfo, sizeof(lineinfo))) + return -EFAULT; + + set_bit(hwgpio, priv->watched_lines); + return 0; } else if (cmd == GPIO_GET_LINEINFO_UNWATCH_IOCTL) { if (copy_from_user(&offset, ip, sizeof(offset))) return -EFAULT; @@ -1538,9 +1556,8 @@ static int gpiochip_setup_dev(struct gpio_device *gdev) /* From this point, the .release() function cleans up gpio_device */ gdev->dev.release = gpiodevice_release; - pr_debug("%s: registered GPIOs %d to %d on device: %s (%s)\n", - __func__, gdev->base, gdev->base + gdev->ngpio - 1, - dev_name(&gdev->dev), gdev->chip->label ? : "generic"); + dev_dbg(&gdev->dev, "registered GPIOs %d to %d on %s\n", gdev->base, + gdev->base + gdev->ngpio - 1, gdev->chip->label ? : "generic"); return 0; @@ -1556,8 +1573,8 @@ static void gpiochip_machine_hog(struct gpio_chip *gc, struct gpiod_hog *hog) desc = gpiochip_get_desc(gc, hog->chip_hwnum); if (IS_ERR(desc)) { - pr_err("%s: unable to get GPIO desc: %ld\n", - __func__, PTR_ERR(desc)); + chip_err(gc, "%s: unable to get GPIO desc: %ld\n", __func__, + PTR_ERR(desc)); return; } @@ -1566,8 +1583,8 @@ static void gpiochip_machine_hog(struct gpio_chip *gc, struct gpiod_hog *hog) 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__, gc->label, hog->chip_hwnum, rv); + gpiod_err(desc, "%s: unable to hog GPIO line (%s:%u): %d\n", + __func__, gc->label, hog->chip_hwnum, rv); } static void machine_gpiochip_add(struct gpio_chip *gc) @@ -1592,8 +1609,8 @@ static void gpiochip_setup_devs(void) list_for_each_entry(gdev, &gpio_devices, list) { ret = gpiochip_setup_dev(gdev); if (ret) - pr_err("%s: Failed to initialize gpio device (%d)\n", - dev_name(&gdev->dev), ret); + dev_err(&gdev->dev, + "Failed to initialize gpio device (%d)\n", ret); } } @@ -2461,32 +2478,37 @@ static void gpiochip_irq_relres(struct irq_data *d) gpiochip_relres_irq(gc, d->hwirq); } +static void gpiochip_irq_mask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + + if (gc->irq.irq_mask) + gc->irq.irq_mask(d); + gpiochip_disable_irq(gc, d->hwirq); +} + +static void gpiochip_irq_unmask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + + gpiochip_enable_irq(gc, d->hwirq); + if (gc->irq.irq_unmask) + gc->irq.irq_unmask(d); +} + static void gpiochip_irq_enable(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); gpiochip_enable_irq(gc, d->hwirq); - if (gc->irq.irq_enable) - gc->irq.irq_enable(d); - else - gc->irq.chip->irq_unmask(d); + gc->irq.irq_enable(d); } static void gpiochip_irq_disable(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - /* - * Since we override .irq_disable() we need to mimic the - * behaviour of __irq_disable() in irq/chip.c. - * First call .irq_disable() if it exists, else mimic the - * behaviour of mask_irq() which calls .irq_mask() if - * it exists. - */ - if (gc->irq.irq_disable) - gc->irq.irq_disable(d); - else if (gc->irq.chip->irq_mask) - gc->irq.chip->irq_mask(d); + gc->irq.irq_disable(d); gpiochip_disable_irq(gc, d->hwirq); } @@ -2511,10 +2533,22 @@ static void gpiochip_set_irq_hooks(struct gpio_chip *gc) "detected irqchip that is shared with multiple gpiochips: please fix the driver.\n"); return; } - gc->irq.irq_enable = irqchip->irq_enable; - gc->irq.irq_disable = irqchip->irq_disable; - irqchip->irq_enable = gpiochip_irq_enable; - irqchip->irq_disable = gpiochip_irq_disable; + + if (irqchip->irq_disable) { + gc->irq.irq_disable = irqchip->irq_disable; + irqchip->irq_disable = gpiochip_irq_disable; + } else { + gc->irq.irq_mask = irqchip->irq_mask; + irqchip->irq_mask = gpiochip_irq_mask; + } + + if (irqchip->irq_enable) { + gc->irq.irq_enable = irqchip->irq_enable; + irqchip->irq_enable = gpiochip_irq_enable; + } else { + gc->irq.irq_unmask = irqchip->irq_unmask; + irqchip->irq_unmask = gpiochip_irq_unmask; + } } /** @@ -2702,7 +2736,7 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gc, return -EINVAL; if (!gc->parent) { - pr_err("missing gpiochip .dev parent pointer\n"); + chip_err(gc, "missing gpiochip .dev parent pointer\n"); return -EINVAL; } gc->irq.threaded = threaded; @@ -2752,6 +2786,26 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gc, } EXPORT_SYMBOL_GPL(gpiochip_irqchip_add_key); +/** + * gpiochip_irqchip_add_domain() - adds an irqdomain to a gpiochip + * @gc: the gpiochip to add the irqchip to + * @domain: the irqdomain to add to the gpiochip + * + * This function adds an IRQ domain to the gpiochip. + */ +int gpiochip_irqchip_add_domain(struct gpio_chip *gc, + struct irq_domain *domain) +{ + if (!domain) + return -EINVAL; + + gc->to_irq = gpiochip_to_irq; + gc->irq.domain = domain; + + return 0; +} +EXPORT_SYMBOL_GPL(gpiochip_irqchip_add_domain); + #else /* CONFIG_GPIOLIB_IRQCHIP */ static inline int gpiochip_add_irqchip(struct gpio_chip *gc, @@ -4653,7 +4707,7 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, if (!table) return desc; - for (p = &table->table[0]; p->chip_label; p++) { + for (p = &table->table[0]; p->key; p++) { struct gpio_chip *gc; /* idx must always match exactly */ @@ -4664,18 +4718,30 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, if (p->con_id && (!con_id || strcmp(p->con_id, con_id))) continue; - gc = find_chip_by_name(p->chip_label); + if (p->chip_hwnum == U16_MAX) { + desc = gpio_name_to_desc(p->key); + if (desc) { + *flags = p->flags; + return desc; + } + + dev_warn(dev, "cannot find GPIO line %s, deferring\n", + p->key); + return ERR_PTR(-EPROBE_DEFER); + } + + gc = find_chip_by_name(p->key); if (!gc) { /* * As the lookup table indicates a chip with - * p->chip_label should exist, assume it may + * p->key should exist, assume it may * still appear later and let the interested * consumer be probed again or let the Deferred * Probe infrastructure handle the error. */ dev_warn(dev, "cannot find GPIO chip %s, deferring\n", - p->chip_label); + p->key); return ERR_PTR(-EPROBE_DEFER); } @@ -4706,7 +4772,7 @@ static int platform_gpio_count(struct device *dev, const char *con_id) if (!table) return -ENOENT; - for (p = &table->table[0]; p->chip_label; p++) { + for (p = &table->table[0]; p->key; p++) { if ((con_id && p->con_id && !strcmp(con_id, p->con_id)) || (!con_id && !p->con_id)) count++; @@ -4877,7 +4943,7 @@ int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id, /* No particular flag request, return here... */ if (!(dflags & GPIOD_FLAGS_BIT_DIR_SET)) { - pr_debug("no flags found for %s\n", con_id); + gpiod_dbg(desc, "no flags found for %s\n", con_id); return 0; } @@ -5108,8 +5174,7 @@ int gpiod_hog(struct gpio_desc *desc, const char *name, /* Mark GPIO as hogged so it can be identified and removed later */ set_bit(FLAG_IS_HOGGED, &desc->flags); - pr_info("GPIO line %d (%s) hogged as %s%s\n", - desc_to_gpio(desc), name, + gpiod_info(desc, "hogged as %s%s\n", (dflags & GPIOD_FLAGS_BIT_DIR_OUT) ? "output" : "input", (dflags & GPIOD_FLAGS_BIT_DIR_OUT) ? (dflags & GPIOD_FLAGS_BIT_DIR_VAL) ? "/high" : "/low" : ""); |