From 47bd38a31adcd5b92f5e11919a101a310305dbb1 Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Thu, 8 Dec 2016 18:32:27 +0100 Subject: gpio: rcar: set IRQ chip parent_device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This enables Runtime PM handling for interrupts. By setting the parent_device in struct irq_chip genirq will call the pm_runtime_get/put APIs when an IRQ is requested/freed. Signed-off-by: Niklas Söderlund Reviewed-by: Laurent Pinchart Reviewed-by: Geert Uytterhoeven Signed-off-by: Linus Walleij --- drivers/gpio/gpio-rcar.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index 2be48f5eba36..3b77c10c16f5 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -460,6 +460,7 @@ static int gpio_rcar_probe(struct platform_device *pdev) irq_chip = &p->irq_chip; irq_chip->name = name; + irq_chip->parent_device = dev; irq_chip->irq_mask = gpio_rcar_irq_disable; irq_chip->irq_unmask = gpio_rcar_irq_enable; irq_chip->irq_set_type = gpio_rcar_irq_set_type; -- cgit v1.2.3 From 2d65472bcb3f2e1f305529655bb06054dc9e2804 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 8 Dec 2016 18:32:28 +0100 Subject: gpio: rcar: Fine-grained Runtime PM support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently gpio modules are runtime-resumed at probe time. This means the gpio module will be active all the time (except during system suspend, if not configured as a wake-up source). While an R-Car Gen2 gpio module retains pins configured for output at the requested level while put in standby mode, gpio register cannot be accessed while suspended. Unfortunately pm_runtime_get_sync() cannot be called from all contexts where gpio register access is needed. Hence move the Runtime PM handling from probe/remove time to gpio request/free time, which is probably the best we can do. On r8a7791/koelsch, gpio modules 0, 1, 3, and 4 are now suspended during normal use (gpio2 is used for LEDs and regulators, gpio5 for keys, gpio6 for SD-Card CD & WP, gpio7 for keys and regulators). Signed-off-by: Geert Uytterhoeven [Niklas: s/gpio_to_priv(chip)/gpiochip_get_data(chip)/] Signed-off-by: Niklas Söderlund Reviewed-by: Laurent Pinchart Signed-off-by: Linus Walleij --- drivers/gpio/gpio-rcar.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index 3b77c10c16f5..31ad288846af 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -242,11 +242,24 @@ static void gpio_rcar_config_general_input_output_mode(struct gpio_chip *chip, static int gpio_rcar_request(struct gpio_chip *chip, unsigned offset) { - return pinctrl_request_gpio(chip->base + offset); + struct gpio_rcar_priv *p = gpiochip_get_data(chip); + int error; + + error = pm_runtime_get_sync(&p->pdev->dev); + if (error < 0) + return error; + + error = pinctrl_request_gpio(chip->base + offset); + if (error) + pm_runtime_put(&p->pdev->dev); + + return error; } static void gpio_rcar_free(struct gpio_chip *chip, unsigned offset) { + struct gpio_rcar_priv *p = gpiochip_get_data(chip); + pinctrl_free_gpio(chip->base + offset); /* @@ -254,6 +267,8 @@ static void gpio_rcar_free(struct gpio_chip *chip, unsigned offset) * drive the GPIO pin as an output. */ gpio_rcar_config_general_input_output_mode(chip, offset, false); + + pm_runtime_put(&p->pdev->dev); } static int gpio_rcar_direction_input(struct gpio_chip *chip, unsigned offset) @@ -426,7 +441,6 @@ static int gpio_rcar_probe(struct platform_device *pdev) } pm_runtime_enable(dev); - pm_runtime_get_sync(dev); io = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); @@ -495,7 +509,6 @@ static int gpio_rcar_probe(struct platform_device *pdev) err1: gpiochip_remove(gpio_chip); err0: - pm_runtime_put(dev); pm_runtime_disable(dev); return ret; } @@ -506,7 +519,6 @@ static int gpio_rcar_remove(struct platform_device *pdev) gpiochip_remove(&p->gpio_chip); - pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); return 0; } -- cgit v1.2.3 From e53c60289dfaba57fd8bf108406b94a71bb9bac1 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Tue, 20 Dec 2016 12:28:18 +0100 Subject: gpio: mockup: make pins_name_start static This variable is not used outside this module. Make it static. Signed-off-by: Bartosz Golaszewski Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mockup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c index 1ef85b0c2b1f..af0c1e835605 100644 --- a/drivers/gpio/gpio-mockup.c +++ b/drivers/gpio/gpio-mockup.c @@ -43,7 +43,7 @@ static int gpio_mockup_ranges[MAX_GC << 1]; static int gpio_mockup_params_nr; module_param_array(gpio_mockup_ranges, int, &gpio_mockup_params_nr, 0400); -const char pins_name_start = 'A'; +static const char pins_name_start = 'A'; static int mockup_gpio_get(struct gpio_chip *gc, unsigned int offset) { -- cgit v1.2.3 From ad6d8004fa29a8958381b60215e32d1e903b0492 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Tue, 20 Dec 2016 12:28:19 +0100 Subject: gpio: mockup: dynamically allocate memory for chip name Currently the chip name buffer is allocated on the stack and the address of the buffer is passed to the gpio framework. It's invalid after probe() returns, so the sysfs label attribute displays garbage. Use devm_kasprintf() for each string instead. Signed-off-by: Bartosz Golaszewski Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mockup.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c index af0c1e835605..10f6bf6f1660 100644 --- a/drivers/gpio/gpio-mockup.c +++ b/drivers/gpio/gpio-mockup.c @@ -126,7 +126,7 @@ static int mockup_gpio_probe(struct platform_device *pdev) int i; int base; int ngpio; - char chip_name[sizeof(GPIO_NAME) + 3]; + char *chip_name; if (gpio_mockup_params_nr < 2) return -EINVAL; @@ -146,8 +146,12 @@ static int mockup_gpio_probe(struct platform_device *pdev) ngpio = gpio_mockup_ranges[i * 2 + 1] - base; if (ngpio >= 0) { - sprintf(chip_name, "%s-%c", GPIO_NAME, - pins_name_start + i); + chip_name = devm_kasprintf(dev, GFP_KERNEL, + "%s-%c", GPIO_NAME, + pins_name_start + i); + if (!chip_name) + return -ENOMEM; + ret = mockup_gpio_add(dev, &cntr[i], chip_name, base, ngpio); } else { -- cgit v1.2.3 From 364ac45655f10217d3fadc013347fde49f870f39 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Tue, 20 Dec 2016 12:28:20 +0100 Subject: gpio: mockup: coding style fixes Fix whitespace errors and arrange local variables for better readability. Signed-off-by: Bartosz Golaszewski Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mockup.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c index 10f6bf6f1660..82a9efd021db 100644 --- a/drivers/gpio/gpio-mockup.c +++ b/drivers/gpio/gpio-mockup.c @@ -120,12 +120,9 @@ err: static int mockup_gpio_probe(struct platform_device *pdev) { - struct device *dev = &pdev->dev; struct mockup_gpio_controller *cntr; - int ret; - int i; - int base; - int ngpio; + struct device *dev = &pdev->dev; + int ret, i, base, ngpio; char *chip_name; if (gpio_mockup_params_nr < 2) @@ -174,8 +171,8 @@ static int mockup_gpio_probe(struct platform_device *pdev) static struct platform_driver mockup_gpio_driver = { .driver = { - .name = GPIO_NAME, - }, + .name = GPIO_NAME, + }, .probe = mockup_gpio_probe, }; -- cgit v1.2.3 From baddc7ca446c18c68a0c8b298fd9920bf049efce Mon Sep 17 00:00:00 2001 From: John Crispin Date: Tue, 20 Dec 2016 19:57:55 +0100 Subject: gpio: update my email address This patch updates my email address as I no longer have access to the old one. Signed-off-by: John Crispin Signed-off-by: Linus Walleij --- drivers/gpio/devres.c | 2 +- drivers/gpio/gpio-mm-lantiq.c | 2 +- drivers/gpio/gpio-stp-xway.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c index b760cbbb41d8..b1c41db52089 100644 --- a/drivers/gpio/devres.c +++ b/drivers/gpio/devres.c @@ -11,7 +11,7 @@ * * This file is based on kernel/irq/devres.c * - * Copyright (c) 2011 John Crispin + * Copyright (c) 2011 John Crispin */ #include diff --git a/drivers/gpio/gpio-mm-lantiq.c b/drivers/gpio/gpio-mm-lantiq.c index 54e5d8257d34..b1cf76dd84ba 100644 --- a/drivers/gpio/gpio-mm-lantiq.c +++ b/drivers/gpio/gpio-mm-lantiq.c @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2012 John Crispin + * Copyright (C) 2012 John Crispin */ #include diff --git a/drivers/gpio/gpio-stp-xway.c b/drivers/gpio/gpio-stp-xway.c index 19e654f88b3a..c07385b71403 100644 --- a/drivers/gpio/gpio-stp-xway.c +++ b/drivers/gpio/gpio-stp-xway.c @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2012 John Crispin + * Copyright (C) 2012 John Crispin * */ -- cgit v1.2.3 From a79fead50f06886311f37777d03b20b058749ce1 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 19 Dec 2016 19:21:34 +0100 Subject: gpio: of: Add support for multiple GPIOs in a single GPIO hog When listing multiple GPIOs in the "gpios" property of a GPIO hog, only the first GPIO is affected. The user is left clueless about the dysfunctioning of the other GPIOs specified. Fix this by adding and documenting support for specifying multiple GPIOs in a single GPIO hog. Signed-off-by: Geert Uytterhoeven Acked-by: Rob Herring Signed-off-by: Linus Walleij --- Documentation/devicetree/bindings/gpio/gpio.txt | 8 +++---- drivers/gpio/gpiolib-of.c | 31 ++++++++++++++++--------- 2 files changed, 24 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/gpio/gpio.txt b/Documentation/devicetree/bindings/gpio/gpio.txt index 68d28f62a6f4..84ede036f73d 100644 --- a/Documentation/devicetree/bindings/gpio/gpio.txt +++ b/Documentation/devicetree/bindings/gpio/gpio.txt @@ -187,10 +187,10 @@ gpio-controller's driver probe function. Each GPIO hog definition is represented as a child node of the GPIO controller. Required properties: -- gpio-hog: A property specifying that this child node represent a GPIO hog. -- gpios: Store the GPIO information (id, flags, ...). Shall contain the - number of cells specified in its parent node (GPIO controller - node). +- gpio-hog: A property specifying that this child node represents a GPIO hog. +- gpios: Store the GPIO information (id, flags, ...) for each GPIO to + affect. Shall contain an integer multiple of the number of cells + specified in its parent node (GPIO controller node). Only one of the following properties scanned in the order shown below. This means that when multiple properties are present they will be searched in the order presented below and the first match is taken as the intended diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 92b185f19232..975b9f6cf408 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -160,6 +160,7 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, * of_parse_own_gpio() - Get a GPIO hog descriptor, names and flags for GPIO API * @np: device node to get GPIO from * @chip: GPIO chip whose hog is parsed + * @idx: Index of the GPIO to parse * @name: GPIO line name * @lflags: gpio_lookup_flags - returned from of_find_gpio() or * of_parse_own_gpio() @@ -170,7 +171,7 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, */ static struct gpio_desc *of_parse_own_gpio(struct device_node *np, struct gpio_chip *chip, - const char **name, + unsigned int idx, const char **name, enum gpio_lookup_flags *lflags, enum gpiod_flags *dflags) { @@ -178,6 +179,7 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np, enum of_gpio_flags xlate_flags; struct of_phandle_args gpiospec; struct gpio_desc *desc; + unsigned int i; u32 tmp; int ret; @@ -196,9 +198,12 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np, gpiospec.np = chip_np; gpiospec.args_count = tmp; - ret = of_property_read_u32_array(np, "gpios", gpiospec.args, tmp); - if (ret) - return ERR_PTR(ret); + for (i = 0; i < tmp; i++) { + ret = of_property_read_u32_index(np, "gpios", idx * tmp + i, + &gpiospec.args[i]); + if (ret) + return ERR_PTR(ret); + } desc = of_xlate_and_get_gpiod_flags(chip, &gpiospec, &xlate_flags); if (IS_ERR(desc)) @@ -240,20 +245,24 @@ static int of_gpiochip_scan_gpios(struct gpio_chip *chip) const char *name; enum gpio_lookup_flags lflags; enum gpiod_flags dflags; + unsigned int i; int ret; for_each_available_child_of_node(chip->of_node, np) { if (!of_property_read_bool(np, "gpio-hog")) continue; - desc = of_parse_own_gpio(np, chip, &name, &lflags, &dflags); - if (IS_ERR(desc)) - continue; + for (i = 0;; i++) { + desc = of_parse_own_gpio(np, chip, i, &name, &lflags, + &dflags); + if (IS_ERR(desc)) + break; - ret = gpiod_hog(desc, name, lflags, dflags); - if (ret < 0) { - of_node_put(np); - return ret; + ret = gpiod_hog(desc, name, lflags, dflags); + if (ret < 0) { + of_node_put(np); + return ret; + } } } -- cgit v1.2.3 From 200d0177b4623cf218239ad7a21466459c174bff Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 3 Jan 2017 19:00:20 +0200 Subject: gpio: devres: Use global array of gpio suffixes We have already a global array of possible GPIO suffixes. Use it here instead of another copy of them. Unfortunately this will not reduce the memory footprint, though allows to easy maintain list in only one place. Signed-off-by: Andy Shevchenko Signed-off-by: Linus Walleij --- drivers/gpio/devres.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c index b1c41db52089..2c49a8bc9e3f 100644 --- a/drivers/gpio/devres.c +++ b/drivers/gpio/devres.c @@ -21,6 +21,8 @@ #include #include +#include "gpiolib.h" + static void devm_gpiod_release(struct device *dev, void *res) { struct gpio_desc **desc = res; @@ -135,7 +137,6 @@ struct gpio_desc *devm_get_gpiod_from_child(struct device *dev, const char *con_id, struct fwnode_handle *child) { - static const char * const suffixes[] = { "gpios", "gpio" }; char prop_name[32]; /* 32 is max size of property name */ struct gpio_desc **dr; struct gpio_desc *desc; @@ -146,13 +147,13 @@ struct gpio_desc *devm_get_gpiod_from_child(struct device *dev, if (!dr) return ERR_PTR(-ENOMEM); - for (i = 0; i < ARRAY_SIZE(suffixes); i++) { + for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) { if (con_id) snprintf(prop_name, sizeof(prop_name), "%s-%s", - con_id, suffixes[i]); + con_id, gpio_suffixes[i]); else snprintf(prop_name, sizeof(prop_name), "%s", - suffixes[i]); + gpio_suffixes[i]); desc = fwnode_get_named_gpiod(child, prop_name); if (!IS_ERR(desc) || (PTR_ERR(desc) != -ENOENT)) -- cgit v1.2.3 From bb5b06750f1d9b2d632d942d8a72b35a4dd930b9 Mon Sep 17 00:00:00 2001 From: Keerthy Date: Wed, 4 Jan 2017 13:56:28 +0530 Subject: gpio: davinci: Remove redundant members davinci_gpio_controller stuct davinci_gpio_controller struct has set_data, in_data, clr_data members that are assigned and never used. Signed-off-by: Keerthy Signed-off-by: Linus Walleij --- drivers/gpio/gpio-davinci.c | 3 --- include/linux/platform_data/gpio-davinci.h | 3 --- 2 files changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index 9191056548fe..163f81e3db83 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -266,9 +266,6 @@ static int davinci_gpio_probe(struct platform_device *pdev) if (!regs) return -ENXIO; chips[i].regs = regs; - chips[i].set_data = ®s->set_data; - chips[i].clr_data = ®s->clr_data; - chips[i].in_data = ®s->in_data; gpiochip_add_data(&chips[i].chip, &chips[i]); } diff --git a/include/linux/platform_data/gpio-davinci.h b/include/linux/platform_data/gpio-davinci.h index 6ace3fd32b6a..44ca5303849c 100644 --- a/include/linux/platform_data/gpio-davinci.h +++ b/include/linux/platform_data/gpio-davinci.h @@ -33,9 +33,6 @@ struct davinci_gpio_controller { /* Serialize access to GPIO registers */ spinlock_t lock; void __iomem *regs; - void __iomem *set_data; - void __iomem *clr_data; - void __iomem *in_data; int gpio_unbanked; unsigned gpio_irq; }; -- cgit v1.2.3 From 5e4e6fb3ff31b44d94ffcc34ae4f3af476104863 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 3 Jan 2017 19:01:17 +0200 Subject: gpiolib: Switch to for_each_set_bit() The macro for_each_set_bit() effectively looks up to the next set bit in array of bits. Instead of open coding that switch to for_each_set_bit() in gpio_chip_set_multiple(). While here, make gpio_chip_set_multiple() non-destructive against its parameters. We are safe since all callers, i.e. gpiod_set_array_value_complex(), handle that already. Signed-off-by: Andy Shevchenko Reviewed-by: Mika Westerberg Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index f4c26c7826cd..7f51c9bf5533 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -2570,18 +2571,11 @@ static void gpio_chip_set_multiple(struct gpio_chip *chip, if (chip->set_multiple) { chip->set_multiple(chip, mask, bits); } else { - int i; - for (i = 0; i < chip->ngpio; i++) { - if (mask[BIT_WORD(i)] == 0) { - /* no more set bits in this mask word; - * skip ahead to the next word */ - i = (BIT_WORD(i) + 1) * BITS_PER_LONG - 1; - continue; - } - /* set outputs if the corresponding mask bit is set */ - if (__test_and_clear_bit(i, mask)) - chip->set(chip, i, test_bit(i, bits)); - } + unsigned int i; + + /* set outputs if the corresponding mask bit is set */ + for_each_set_bit(i, mask, chip->ngpio) + chip->set(chip, i, test_bit(i, bits)); } } -- cgit v1.2.3 From e567c35f4909b6e752f63412ed6038c4d9aa9ede Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 3 Jan 2017 19:01:18 +0200 Subject: gpiolib: Update documentation of struct acpi_gpio_info It seems the code had been changed, but description left untouched. Update description of the struct acpi_gpio_info and relative comments accordingly. Fixes: commit 52044723cd27 ("ACPI / gpio: Add irq_type when a GPIO is used as an interrupt") Cc: Christophe RICARD Signed-off-by: Andy Shevchenko Acked-by: Mika Westerberg Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-acpi.c | 5 ++--- drivers/gpio/gpiolib.h | 3 ++- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index a3faefa44f68..9b37a3692b3f 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -416,9 +416,8 @@ static int acpi_populate_gpio_lookup(struct acpi_resource *ares, void *data) agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT; /* - * ActiveLow is only specified for GpioInt resource. If - * GpioIo is used then the only way to set the flag is - * to use _DSD "gpios" property. + * Polarity and triggering are only specified for GpioInt + * resource. * Note: we expect here: * - ACPI_ACTIVE_LOW == GPIO_ACTIVE_LOW * - ACPI_ACTIVE_HIGH == GPIO_ACTIVE_HIGH diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index d10eaf520860..2495b7ee1b42 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -76,7 +76,8 @@ struct gpio_device { /** * struct acpi_gpio_info - ACPI GPIO specific information * @gpioint: if %true this GPIO is of type GpioInt otherwise type is GpioIo - * @active_low: in case of @gpioint, the pin is active low + * @polarity: interrupt polarity as provided by ACPI + * @triggering: triggering type as provided by ACPI */ struct acpi_gpio_info { bool gpioint; -- cgit v1.2.3 From fb505747c06b8894bccb18457fd11bad047384f4 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Mon, 9 Jan 2017 11:47:44 -0800 Subject: gpio: Remove impossible checks on container_of() result container_of() does pointer math on the pointer that's passed in. If it were to return a NULL pointer the value passed in would need to be perfectly offset from 0 to make that so. Remove these checks because they don't make sense. Signed-off-by: Stephen Boyd Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 7f51c9bf5533..c76fa4ffb59c 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -983,7 +983,7 @@ static int gpio_chrdev_open(struct inode *inode, struct file *filp) struct gpio_device, chrdev); /* Fail on open if the backing gpiochip is gone */ - if (!gdev || !gdev->chip) + if (!gdev->chip) return -ENODEV; get_device(&gdev->dev); filp->private_data = gdev; @@ -1002,8 +1002,6 @@ static int gpio_chrdev_release(struct inode *inode, struct file *filp) struct gpio_device *gdev = container_of(inode->i_cdev, struct gpio_device, chrdev); - if (!gdev) - return -ENODEV; put_device(&gdev->dev); return 0; } -- cgit v1.2.3 From 054ccdef8b2850be3aee8cbd49000e6d61f837b2 Mon Sep 17 00:00:00 2001 From: Steve Longerbeam Date: Tue, 10 Jan 2017 11:29:51 -0800 Subject: gpio: pca953x: Add optional reset gpio control Add optional reset-gpios pin control. If present, de-assert the specified reset gpio pin to bring the chip out of reset. v2: - Specify that reset signal to PCA953x chip is active low, in binding doc. - reorder includes in gpio-pca953x.c. - remove dev_err() on devm_gpiod_get_optional() error return. Cc: Alexandre Courbot Cc: linux-gpio@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Steve Longerbeam Reviewed-by: Andy Shevchenko Reviewed-by: Vladimir Zapolskiy Signed-off-by: Linus Walleij --- Documentation/devicetree/bindings/gpio/gpio-pca953x.txt | 4 ++++ drivers/gpio/gpio-pca953x.c | 9 +++++++++ 2 files changed, 13 insertions(+) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/gpio/gpio-pca953x.txt b/Documentation/devicetree/bindings/gpio/gpio-pca953x.txt index 08dd15f89ba9..e63935710011 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-pca953x.txt +++ b/Documentation/devicetree/bindings/gpio/gpio-pca953x.txt @@ -29,6 +29,10 @@ Required properties: onsemi,pca9654 exar,xra1202 +Optional properties: + - reset-gpios: GPIO specification for the RESET input. This is an + active low signal to the PCA953x. + Example: diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index d5d72d84b719..d44232aadb6c 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -754,8 +755,16 @@ static int pca953x_probe(struct i2c_client *client, invert = pdata->invert; chip->names = pdata->names; } else { + struct gpio_desc *reset_gpio; + chip->gpio_start = -1; irq_base = 0; + + /* See if we need to de-assert a reset pin */ + reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(reset_gpio)) + return PTR_ERR(reset_gpio); } chip->client = client; -- cgit v1.2.3 From f0d50460753d1444e681dc59352773f120846912 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 10 Jan 2017 22:53:28 +0000 Subject: gpio: mvebu: fix warning when building on 64-bit Casting a pointer to an int is not portable, and provokes a compiler warning. Cast to unsigned long instead to avoid the warning. drivers/gpio/gpio-mvebu.c: In function 'mvebu_gpio_probe': drivers/gpio/gpio-mvebu.c:662:17: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] soc_variant = (int) match->data; ^ This will be needed when building gpio-mvebu for Armada 7k/8k ARM64 SoCs. Signed-off-by: Russell King Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mvebu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 1ed6132b993c..a649556ac3ca 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -659,7 +659,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev) match = of_match_device(mvebu_gpio_of_match, &pdev->dev); if (match) - soc_variant = (int) match->data; + soc_variant = (unsigned long) match->data; else soc_variant = MVEBU_GPIO_SOC_VARIANT_ORION; -- cgit v1.2.3 From a264d10ff45c688293d9112fddd8d29c819e0853 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 9 Jan 2017 16:02:28 +0200 Subject: gpiolib: Convert fwnode_get_named_gpiod() to configure GPIO Make fwnode_get_named_gpiod() consistent with the rest of gpiod_get() like API, i.e. configure GPIO pin immediately after request. Besides obvious clean up it will help to configure pins based on firmware provided resources. Reviewed-by: Mika Westerberg Signed-off-by: Andy Shevchenko Signed-off-by: Linus Walleij --- drivers/gpio/devres.c | 9 +++++++-- drivers/gpio/gpiolib.c | 20 ++++++++++++++++---- drivers/input/keyboard/gpio_keys.c | 9 +-------- drivers/input/keyboard/gpio_keys_polled.c | 11 ++--------- drivers/leds/leds-gpio.c | 2 +- drivers/video/fbdev/amba-clcd-nomadik.c | 15 +++++---------- include/linux/gpio/consumer.h | 19 +++++++++++++------ 7 files changed, 45 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c index b760cbbb41d8..5e0b41b5e554 100644 --- a/drivers/gpio/devres.c +++ b/drivers/gpio/devres.c @@ -127,13 +127,18 @@ EXPORT_SYMBOL(devm_gpiod_get_index); * @dev: GPIO consumer * @con_id: function within the GPIO consumer * @child: firmware node (child of @dev) + * @flags: GPIO initialization flags * * GPIO descriptors returned from this function are automatically disposed on * driver detach. + * + * On successfull request the GPIO pin is configured in accordance with + * provided @flags. */ struct gpio_desc *devm_get_gpiod_from_child(struct device *dev, const char *con_id, - struct fwnode_handle *child) + struct fwnode_handle *child, + enum gpiod_flags flags) { static const char * const suffixes[] = { "gpios", "gpio" }; char prop_name[32]; /* 32 is max size of property name */ @@ -154,7 +159,7 @@ struct gpio_desc *devm_get_gpiod_from_child(struct device *dev, snprintf(prop_name, sizeof(prop_name), "%s", suffixes[i]); - desc = fwnode_get_named_gpiod(child, prop_name); + desc = fwnode_get_named_gpiod(child, prop_name, flags); if (!IS_ERR(desc) || (PTR_ERR(desc) != -ENOENT)) break; } diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index f4c26c7826cd..bb3d3a7edc45 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -3309,6 +3309,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_index); * fwnode_get_named_gpiod - obtain a GPIO from firmware node * @fwnode: handle of the firmware node * @propname: name of the firmware property representing the GPIO + * @dflags: GPIO initialization flags * * This function can be used for drivers that get their configuration * from firmware. @@ -3317,12 +3318,17 @@ EXPORT_SYMBOL_GPL(gpiod_get_index); * underlying firmware interface and then makes sure that the GPIO * descriptor is requested before it is returned to the caller. * + * On successfull request the GPIO pin is configured in accordance with + * provided @dflags. + * * In case of error an ERR_PTR() is returned. */ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, - const char *propname) + const char *propname, + enum gpiod_flags dflags) { struct gpio_desc *desc = ERR_PTR(-ENODEV); + unsigned long lflags = 0; bool active_low = false; bool single_ended = false; int ret; @@ -3355,13 +3361,19 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, return ERR_PTR(ret); if (active_low) - set_bit(FLAG_ACTIVE_LOW, &desc->flags); + lflags |= GPIO_ACTIVE_LOW; if (single_ended) { if (active_low) - set_bit(FLAG_OPEN_DRAIN, &desc->flags); + lflags |= GPIO_OPEN_DRAIN; else - set_bit(FLAG_OPEN_SOURCE, &desc->flags); + lflags |= GPIO_OPEN_SOURCE; + } + + ret = gpiod_configure_flags(desc, propname, lflags, dflags); + if (ret < 0) { + gpiod_put(desc); + return ERR_PTR(ret); } return desc; diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 582462d0af75..9de4b876100a 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -481,7 +481,7 @@ static int gpio_keys_setup_key(struct platform_device *pdev, spin_lock_init(&bdata->lock); if (child) { - bdata->gpiod = devm_get_gpiod_from_child(dev, NULL, child); + bdata->gpiod = devm_get_gpiod_from_child(dev, NULL, child, GPIOD_IN); if (IS_ERR(bdata->gpiod)) { error = PTR_ERR(bdata->gpiod); if (error == -ENOENT) { @@ -496,13 +496,6 @@ static int gpio_keys_setup_key(struct platform_device *pdev, error); return error; } - } else { - error = gpiod_direction_input(bdata->gpiod); - if (error) { - dev_err(dev, "Failed to configure GPIO %d as input: %d\n", - desc_to_gpio(bdata->gpiod), error); - return error; - } } } else if (gpio_is_valid(button->gpio)) { /* diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c index bed4f2086158..fd7ab4dad87b 100644 --- a/drivers/input/keyboard/gpio_keys_polled.c +++ b/drivers/input/keyboard/gpio_keys_polled.c @@ -304,7 +304,8 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) } bdata->gpiod = devm_get_gpiod_from_child(dev, NULL, - child); + child, + GPIOD_IN); if (IS_ERR(bdata->gpiod)) { error = PTR_ERR(bdata->gpiod); if (error != -EPROBE_DEFER) @@ -314,14 +315,6 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) fwnode_handle_put(child); return error; } - - error = gpiod_direction_input(bdata->gpiod); - if (error) { - dev_err(dev, "Failed to configure GPIO %d as input: %d\n", - desc_to_gpio(bdata->gpiod), error); - fwnode_handle_put(child); - return error; - } } else if (gpio_is_valid(button->gpio)) { /* * Legacy GPIO number so request the GPIO here and diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c index d400dcaf4d29..00cc671cddcc 100644 --- a/drivers/leds/leds-gpio.c +++ b/drivers/leds/leds-gpio.c @@ -174,7 +174,7 @@ static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev) const char *state = NULL; struct device_node *np = to_of_node(child); - led.gpiod = devm_get_gpiod_from_child(dev, NULL, child); + led.gpiod = devm_get_gpiod_from_child(dev, NULL, child, GPIOD_ASIS); if (IS_ERR(led.gpiod)) { fwnode_handle_put(child); return ERR_CAST(led.gpiod); diff --git a/drivers/video/fbdev/amba-clcd-nomadik.c b/drivers/video/fbdev/amba-clcd-nomadik.c index 0c06fcaaa6e8..2e800d70b0e5 100644 --- a/drivers/video/fbdev/amba-clcd-nomadik.c +++ b/drivers/video/fbdev/amba-clcd-nomadik.c @@ -184,32 +184,27 @@ static void tpg110_init(struct device *dev, struct device_node *np, { dev_info(dev, "TPG110 display init\n"); - grestb = devm_get_gpiod_from_child(dev, "grestb", &np->fwnode); + /* This asserts the GRESTB signal, putting the display into reset */ + grestb = devm_get_gpiod_from_child(dev, "grestb", &np->fwnode, GPIOD_OUT_HIGH); if (IS_ERR(grestb)) { dev_err(dev, "no GRESTB GPIO\n"); return; } - /* This asserts the GRESTB signal, putting the display into reset */ - gpiod_direction_output(grestb, 1); - - scen = devm_get_gpiod_from_child(dev, "scen", &np->fwnode); + scen = devm_get_gpiod_from_child(dev, "scen", &np->fwnode, GPIOD_OUT_LOW); if (IS_ERR(scen)) { dev_err(dev, "no SCEN GPIO\n"); return; } - gpiod_direction_output(scen, 0); - scl = devm_get_gpiod_from_child(dev, "scl", &np->fwnode); + scl = devm_get_gpiod_from_child(dev, "scl", &np->fwnode, GPIOD_OUT_LOW); if (IS_ERR(scl)) { dev_err(dev, "no SCL GPIO\n"); return; } - gpiod_direction_output(scl, 0); - sda = devm_get_gpiod_from_child(dev, "sda", &np->fwnode); + sda = devm_get_gpiod_from_child(dev, "sda", &np->fwnode, GPIOD_OUT_LOW); if (IS_ERR(sda)) { dev_err(dev, "no SDA GPIO\n"); return; } - gpiod_direction_output(sda, 0); board->enable = tpg110_enable; board->disable = tpg110_disable; } diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h index fb0fde686cb1..930d10049d8d 100644 --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h @@ -135,10 +135,12 @@ int desc_to_gpio(const struct gpio_desc *desc); struct fwnode_handle; struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, - const char *propname); + const char *propname, + enum gpiod_flags dflags); struct gpio_desc *devm_get_gpiod_from_child(struct device *dev, const char *con_id, - struct fwnode_handle *child); + struct fwnode_handle *child, + enum gpiod_flags flags); #else /* CONFIG_GPIOLIB */ static inline int gpiod_count(struct device *dev, const char *con_id) @@ -411,14 +413,19 @@ static inline int desc_to_gpio(const struct gpio_desc *desc) /* Child properties interface */ struct fwnode_handle; -static inline struct gpio_desc *fwnode_get_named_gpiod( - struct fwnode_handle *fwnode, const char *propname) +static inline +struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, + const char *propname, + enum gpiod_flags dflags) { return ERR_PTR(-ENOSYS); } -static inline struct gpio_desc *devm_get_gpiod_from_child( - struct device *dev, const char *con_id, struct fwnode_handle *child) +static inline +struct gpio_desc *devm_get_gpiod_from_child(struct device *dev, + const char *con_id, + struct fwnode_handle *child, + enum gpiod_flags flags) { return ERR_PTR(-ENOSYS); } -- cgit v1.2.3 From b2987d7438e0ca949d81774ca8b43d370a1f9947 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Thu, 12 Jan 2017 17:39:24 +0100 Subject: gpio: Pass GPIO label down to gpiod_request Currently all users of fwnode_get_named_gpiod() have no way to specify a label for the GPIO. So GPIOs listed in debugfs are shown with label "?". With this change a proper label is used. Also adjust all users so they can pass a label, properly retrieved from device tree properties. Signed-off-by: Alexander Stein Cc: Andy Shevchenko Acked-by: Jacek Anaszewski Acked-by: Bartlomiej Zolnierkiewicz Acked-by: Dmitry Torokhov Signed-off-by: Linus Walleij --- drivers/gpio/devres.c | 5 +++-- drivers/gpio/gpiolib.c | 5 +++-- drivers/input/keyboard/gpio_keys.c | 3 ++- drivers/input/keyboard/gpio_keys_polled.c | 3 ++- drivers/leds/leds-gpio.c | 13 +++++++------ drivers/video/fbdev/amba-clcd-nomadik.c | 12 ++++++++---- include/linux/gpio/consumer.h | 12 ++++++++---- 7 files changed, 33 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c index 5e0b41b5e554..89969e887e5d 100644 --- a/drivers/gpio/devres.c +++ b/drivers/gpio/devres.c @@ -138,7 +138,8 @@ EXPORT_SYMBOL(devm_gpiod_get_index); struct gpio_desc *devm_get_gpiod_from_child(struct device *dev, const char *con_id, struct fwnode_handle *child, - enum gpiod_flags flags) + enum gpiod_flags flags, + const char *label) { static const char * const suffixes[] = { "gpios", "gpio" }; char prop_name[32]; /* 32 is max size of property name */ @@ -159,7 +160,7 @@ struct gpio_desc *devm_get_gpiod_from_child(struct device *dev, snprintf(prop_name, sizeof(prop_name), "%s", suffixes[i]); - desc = fwnode_get_named_gpiod(child, prop_name, flags); + desc = fwnode_get_named_gpiod(child, prop_name, flags, label); if (!IS_ERR(desc) || (PTR_ERR(desc) != -ENOENT)) break; } diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index bb3d3a7edc45..20c6c51cbe10 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -3325,7 +3325,8 @@ EXPORT_SYMBOL_GPL(gpiod_get_index); */ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, const char *propname, - enum gpiod_flags dflags) + enum gpiod_flags dflags, + const char *label) { struct gpio_desc *desc = ERR_PTR(-ENODEV); unsigned long lflags = 0; @@ -3356,7 +3357,7 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, if (IS_ERR(desc)) return desc; - ret = gpiod_request(desc, NULL); + ret = gpiod_request(desc, label); if (ret) return ERR_PTR(ret); diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 9de4b876100a..2ec74d90ef78 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -481,7 +481,8 @@ static int gpio_keys_setup_key(struct platform_device *pdev, spin_lock_init(&bdata->lock); if (child) { - bdata->gpiod = devm_get_gpiod_from_child(dev, NULL, child, GPIOD_IN); + bdata->gpiod = devm_get_gpiod_from_child(dev, NULL, child, + GPIOD_IN, desc); if (IS_ERR(bdata->gpiod)) { error = PTR_ERR(bdata->gpiod); if (error == -ENOENT) { diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c index fd7ab4dad87b..5e35c565e341 100644 --- a/drivers/input/keyboard/gpio_keys_polled.c +++ b/drivers/input/keyboard/gpio_keys_polled.c @@ -305,7 +305,8 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) bdata->gpiod = devm_get_gpiod_from_child(dev, NULL, child, - GPIOD_IN); + GPIOD_IN, + button->desc); if (IS_ERR(bdata->gpiod)) { error = PTR_ERR(bdata->gpiod); if (error != -EPROBE_DEFER) diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c index 00cc671cddcc..6c4825d96693 100644 --- a/drivers/leds/leds-gpio.c +++ b/drivers/leds/leds-gpio.c @@ -174,12 +174,6 @@ static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev) const char *state = NULL; struct device_node *np = to_of_node(child); - led.gpiod = devm_get_gpiod_from_child(dev, NULL, child, GPIOD_ASIS); - if (IS_ERR(led.gpiod)) { - fwnode_handle_put(child); - return ERR_CAST(led.gpiod); - } - ret = fwnode_property_read_string(child, "label", &led.name); if (ret && IS_ENABLED(CONFIG_OF) && np) led.name = np->name; @@ -188,6 +182,13 @@ static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev) return ERR_PTR(-EINVAL); } + led.gpiod = devm_get_gpiod_from_child(dev, NULL, child, + GPIOD_ASIS, led.name); + if (IS_ERR(led.gpiod)) { + fwnode_handle_put(child); + return ERR_CAST(led.gpiod); + } + fwnode_property_read_string(child, "linux,default-trigger", &led.default_trigger); diff --git a/drivers/video/fbdev/amba-clcd-nomadik.c b/drivers/video/fbdev/amba-clcd-nomadik.c index 2e800d70b0e5..9175ad9034e1 100644 --- a/drivers/video/fbdev/amba-clcd-nomadik.c +++ b/drivers/video/fbdev/amba-clcd-nomadik.c @@ -185,22 +185,26 @@ static void tpg110_init(struct device *dev, struct device_node *np, dev_info(dev, "TPG110 display init\n"); /* This asserts the GRESTB signal, putting the display into reset */ - grestb = devm_get_gpiod_from_child(dev, "grestb", &np->fwnode, GPIOD_OUT_HIGH); + grestb = devm_get_gpiod_from_child(dev, "grestb", &np->fwnode, + GPIOD_OUT_HIGH, "grestb"); if (IS_ERR(grestb)) { dev_err(dev, "no GRESTB GPIO\n"); return; } - scen = devm_get_gpiod_from_child(dev, "scen", &np->fwnode, GPIOD_OUT_LOW); + scen = devm_get_gpiod_from_child(dev, "scen", &np->fwnode, + GPIOD_OUT_LOW, "scen"); if (IS_ERR(scen)) { dev_err(dev, "no SCEN GPIO\n"); return; } - scl = devm_get_gpiod_from_child(dev, "scl", &np->fwnode, GPIOD_OUT_LOW); + scl = devm_get_gpiod_from_child(dev, "scl", &np->fwnode, GPIOD_OUT_LOW, + "scl"); if (IS_ERR(scl)) { dev_err(dev, "no SCL GPIO\n"); return; } - sda = devm_get_gpiod_from_child(dev, "sda", &np->fwnode, GPIOD_OUT_LOW); + sda = devm_get_gpiod_from_child(dev, "sda", &np->fwnode, GPIOD_OUT_LOW, + "sda"); if (IS_ERR(sda)) { dev_err(dev, "no SDA GPIO\n"); return; diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h index 930d10049d8d..80bad7ebde04 100644 --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h @@ -136,11 +136,13 @@ struct fwnode_handle; struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, const char *propname, - enum gpiod_flags dflags); + enum gpiod_flags dflags, + const char *label); struct gpio_desc *devm_get_gpiod_from_child(struct device *dev, const char *con_id, struct fwnode_handle *child, - enum gpiod_flags flags); + enum gpiod_flags flags, + const char *label); #else /* CONFIG_GPIOLIB */ static inline int gpiod_count(struct device *dev, const char *con_id) @@ -416,7 +418,8 @@ struct fwnode_handle; static inline struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, const char *propname, - enum gpiod_flags dflags) + enum gpiod_flags dflags, + const char *label) { return ERR_PTR(-ENOSYS); } @@ -425,7 +428,8 @@ static inline struct gpio_desc *devm_get_gpiod_from_child(struct device *dev, const char *con_id, struct fwnode_handle *child, - enum gpiod_flags flags) + enum gpiod_flags flags, + const char *label) { return ERR_PTR(-ENOSYS); } -- cgit v1.2.3 From fbc2a294f29e726787a0f5238b27137904f26b81 Mon Sep 17 00:00:00 2001 From: Augusto Mecking Caringi Date: Mon, 16 Jan 2017 14:30:41 +0000 Subject: gpio: intel-mid: Fix build warning when !CONFIG_PM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The only usage of function intel_gpio_runtime_idle() is here (in the same file): static const struct dev_pm_ops intel_gpio_pm_ops = { SET_RUNTIME_PM_OPS(NULL, NULL, intel_gpio_runtime_idle) }; And when CONFIG_PM is not set, the macro SET_RUNTIME_PM_OPS expands to nothing, causing the following compiler warning: drivers/gpio/gpio-intel-mid.c:324:12: warning: ‘intel_gpio_runtime_idle’ defined but not used [-Wunused-function] static int intel_gpio_runtime_idle(struct device *dev) Fix it by annotating the function with __maybe_unused. Signed-off-by: Augusto Mecking Caringi Acked-by: Andy Shevchenko Signed-off-by: Linus Walleij --- drivers/gpio/gpio-intel-mid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-intel-mid.c b/drivers/gpio/gpio-intel-mid.c index a1e44c221f66..b76ecee82c3f 100644 --- a/drivers/gpio/gpio-intel-mid.c +++ b/drivers/gpio/gpio-intel-mid.c @@ -321,7 +321,7 @@ static void intel_mid_irq_init_hw(struct intel_mid_gpio *priv) } } -static int intel_gpio_runtime_idle(struct device *dev) +static int __maybe_unused intel_gpio_runtime_idle(struct device *dev) { int err = pm_schedule_suspend(dev, 500); return err ?: -EBUSY; -- cgit v1.2.3 From 8f7cf8c65746d94d58fa94edc134a22a7e528de4 Mon Sep 17 00:00:00 2001 From: Keerthy Date: Tue, 17 Jan 2017 21:49:11 +0530 Subject: gpio: davinci: Remove gpio2regs function gpio2regs is written making an assumption that driver supports only one instance of gpio controller. Removing this and adding a generic array so as to support multiple instances of gpio controllers. Signed-off-by: Keerthy Reviewed-by: Grygorii Strashko Signed-off-by: Linus Walleij --- drivers/gpio/gpio-davinci.c | 35 +++++++++++------------------------ 1 file changed, 11 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index 163f81e3db83..bb47de3daafa 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -43,25 +43,7 @@ typedef struct irq_chip *(*gpio_get_irq_chip_cb_t)(unsigned int irq); #define MAX_LABEL_SIZE 20 static void __iomem *gpio_base; - -static struct davinci_gpio_regs __iomem *gpio2regs(unsigned gpio) -{ - void __iomem *ptr; - - if (gpio < 32 * 1) - ptr = gpio_base + 0x10; - else if (gpio < 32 * 2) - ptr = gpio_base + 0x38; - else if (gpio < 32 * 3) - ptr = gpio_base + 0x60; - else if (gpio < 32 * 4) - ptr = gpio_base + 0x88; - else if (gpio < 32 * 5) - ptr = gpio_base + 0xb0; - else - ptr = NULL; - return ptr; -} +static unsigned int offset_array[5] = {0x10, 0x38, 0x60, 0x88, 0xb0}; static inline struct davinci_gpio_regs __iomem *irq2regs(struct irq_data *d) { @@ -262,7 +244,7 @@ static int davinci_gpio_probe(struct platform_device *pdev) #endif spin_lock_init(&chips[i].lock); - regs = gpio2regs(base); + regs = gpio_base + offset_array[i]; if (!regs) return -ENXIO; chips[i].regs = regs; @@ -417,7 +399,9 @@ static int davinci_gpio_irq_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) { - struct davinci_gpio_regs __iomem *g = gpio2regs(hw); + struct davinci_gpio_controller *chips = + (struct davinci_gpio_controller *)d->host_data; + struct davinci_gpio_regs __iomem *g = chips[hw / 32].regs; irq_set_chip_and_handler_name(irq, &gpio_irqchip, handle_simple_irq, "davinci_gpio"); @@ -554,7 +538,7 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) irq_chip->irq_set_type = gpio_irq_type_unbanked; /* default trigger: both edges */ - g = gpio2regs(0); + g = chips[0].regs; writel_relaxed(~0, &g->set_falling); writel_relaxed(~0, &g->set_rising); @@ -573,8 +557,11 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) * then chain through our own handler. */ for (gpio = 0, bank = 0; gpio < ngpio; bank++, bank_irq++, gpio += 16) { - /* disabled by default, enabled only as needed */ - g = gpio2regs(gpio); + /* disabled by default, enabled only as needed + * There are register sets for 32 GPIOs. 2 banks of 16 + * GPIOs are covered by each set of registers hence divide by 2 + */ + g = chips[bank / 2].regs; writel_relaxed(~0, &g->clr_falling); writel_relaxed(~0, &g->clr_rising); -- cgit v1.2.3 From b5cf3fd827d2e11355c126b44ea625650ebf4d39 Mon Sep 17 00:00:00 2001 From: Keerthy Date: Fri, 13 Jan 2017 09:50:12 +0530 Subject: gpio: davinci: Redesign driver to accommodate ngpios in one gpio chip The Davinci GPIO driver is implemented to work with one monolithic Davinci GPIO platform device which may have up to Y(144) gpios. The Davinci GPIO driver instantiates number of GPIO chips with max 32 gpio pins per each during initialization and one IRQ domain. So, the current GPIO's opjects structure is: Davinci GPIO controller |- ------| ... |--- irq_domain (hwirq [0..143]) |- ------| Current driver creates one chip for every 32 GPIOs in a controller. This was a limitation earlier now there is no need for that. Hence redesigning the driver to create one gpio chip for all the ngpio in the controller. |- ------|--- irq_domain (hwirq [0..143]). The previous discussion on this can be found here: https://www.spinics.net/lists/linux-omap/msg132869.html Signed-off-by: Keerthy Signed-off-by: Linus Walleij --- drivers/gpio/gpio-davinci.c | 127 +++++++++++++++++------------ include/linux/platform_data/gpio-davinci.h | 12 ++- 2 files changed, 83 insertions(+), 56 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index bb47de3daafa..446df4ece915 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -63,11 +63,13 @@ static inline int __davinci_direction(struct gpio_chip *chip, unsigned offset, bool out, int value) { struct davinci_gpio_controller *d = gpiochip_get_data(chip); - struct davinci_gpio_regs __iomem *g = d->regs; + struct davinci_gpio_regs __iomem *g; unsigned long flags; u32 temp; - u32 mask = 1 << offset; + int bank = offset / 32; + u32 mask = __gpio_mask(offset); + g = d->regs[bank]; spin_lock_irqsave(&d->lock, flags); temp = readl_relaxed(&g->dir); if (out) { @@ -103,9 +105,12 @@ davinci_direction_out(struct gpio_chip *chip, unsigned offset, int value) static int davinci_gpio_get(struct gpio_chip *chip, unsigned offset) { struct davinci_gpio_controller *d = gpiochip_get_data(chip); - struct davinci_gpio_regs __iomem *g = d->regs; + struct davinci_gpio_regs __iomem *g; + int bank = offset / 32; - return !!((1 << offset) & readl_relaxed(&g->in_data)); + g = d->regs[bank]; + + return !!(__gpio_mask(offset) & readl_relaxed(&g->in_data)); } /* @@ -115,9 +120,13 @@ static void davinci_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { struct davinci_gpio_controller *d = gpiochip_get_data(chip); - struct davinci_gpio_regs __iomem *g = d->regs; + struct davinci_gpio_regs __iomem *g; + int bank = offset / 32; - writel_relaxed((1 << offset), value ? &g->set_data : &g->clr_data); + g = d->regs[bank]; + + writel_relaxed(__gpio_mask(offset), + value ? &g->set_data : &g->clr_data); } static struct davinci_gpio_platform_data * @@ -165,7 +174,7 @@ static int davinci_gpio_of_xlate(struct gpio_chip *gc, if (gpiospec->args[0] > pdata->ngpio) return -EINVAL; - if (gc != &chips[gpiospec->args[0] / 32].chip) + if (gc != &chips->chip) return -EINVAL; if (flags) @@ -177,11 +186,11 @@ static int davinci_gpio_of_xlate(struct gpio_chip *gc, static int davinci_gpio_probe(struct platform_device *pdev) { - int i, base; + static int ctrl_num; + int gpio, bank; unsigned ngpio, nbank; struct davinci_gpio_controller *chips; struct davinci_gpio_platform_data *pdata; - struct davinci_gpio_regs __iomem *regs; struct device *dev = &pdev->dev; struct resource *res; char label[MAX_LABEL_SIZE]; @@ -220,38 +229,30 @@ static int davinci_gpio_probe(struct platform_device *pdev) if (IS_ERR(gpio_base)) return PTR_ERR(gpio_base); - for (i = 0, base = 0; base < ngpio; i++, base += 32) { - snprintf(label, MAX_LABEL_SIZE, "davinci_gpio.%d", i); - chips[i].chip.label = devm_kstrdup(dev, label, GFP_KERNEL); - if (!chips[i].chip.label) + snprintf(label, MAX_LABEL_SIZE, "davinci_gpio.%d", ctrl_num++); + chips->chip.label = devm_kstrdup(dev, label, GFP_KERNEL); + if (!chips->chip.label) return -ENOMEM; - chips[i].chip.direction_input = davinci_direction_in; - chips[i].chip.get = davinci_gpio_get; - chips[i].chip.direction_output = davinci_direction_out; - chips[i].chip.set = davinci_gpio_set; + chips->chip.direction_input = davinci_direction_in; + chips->chip.get = davinci_gpio_get; + chips->chip.direction_output = davinci_direction_out; + chips->chip.set = davinci_gpio_set; - chips[i].chip.base = base; - chips[i].chip.ngpio = ngpio - base; - if (chips[i].chip.ngpio > 32) - chips[i].chip.ngpio = 32; + chips->chip.ngpio = ngpio; #ifdef CONFIG_OF_GPIO - chips[i].chip.of_gpio_n_cells = 2; - chips[i].chip.of_xlate = davinci_gpio_of_xlate; - chips[i].chip.parent = dev; - chips[i].chip.of_node = dev->of_node; + chips->chip.of_gpio_n_cells = 2; + chips->chip.of_xlate = davinci_gpio_of_xlate; + chips->chip.parent = dev; + chips->chip.of_node = dev->of_node; #endif - spin_lock_init(&chips[i].lock); - - regs = gpio_base + offset_array[i]; - if (!regs) - return -ENXIO; - chips[i].regs = regs; + spin_lock_init(&chips->lock); - gpiochip_add_data(&chips[i].chip, &chips[i]); - } + for (gpio = 0, bank = 0; gpio < ngpio; gpio += 32, bank++) + chips->regs[bank] = gpio_base + offset_array[bank]; + gpiochip_add_data(&chips->chip, chips); platform_set_drvdata(pdev, chips); davinci_gpio_irq_setup(pdev); return 0; @@ -312,16 +313,19 @@ static struct irq_chip gpio_irqchip = { static void gpio_irq_handler(struct irq_desc *desc) { - unsigned int irq = irq_desc_get_irq(desc); struct davinci_gpio_regs __iomem *g; u32 mask = 0xffff; + int bank_num; struct davinci_gpio_controller *d; + struct davinci_gpio_irq_data *irqdata; - d = (struct davinci_gpio_controller *)irq_desc_get_handler_data(desc); - g = (struct davinci_gpio_regs __iomem *)d->regs; + irqdata = (struct davinci_gpio_irq_data *)irq_desc_get_handler_data(desc); + bank_num = irqdata->bank_num; + g = irqdata->regs; + d = irqdata->chip; /* we only care about one bank */ - if (irq & 1) + if ((bank_num % 2) == 1) mask <<= 16; /* temporarily mask (level sensitive) parent IRQ */ @@ -329,6 +333,7 @@ static void gpio_irq_handler(struct irq_desc *desc) while (1) { u32 status; int bit; + irq_hw_number_t hw_irq; /* ack any irqs */ status = readl_relaxed(&g->intstat) & mask; @@ -341,9 +346,13 @@ static void gpio_irq_handler(struct irq_desc *desc) while (status) { bit = __ffs(status); status &= ~BIT(bit); + /* Max number of gpios per controller is 144 so + * hw_irq will be in [0..143] + */ + hw_irq = (bank_num / 2) * 32 + bit; + generic_handle_irq( - irq_find_mapping(d->irq_domain, - d->chip.base + bit)); + irq_find_mapping(d->irq_domain, hw_irq)); } } chained_irq_exit(irq_desc_get_chip(desc), desc); @@ -355,7 +364,7 @@ static int gpio_to_irq_banked(struct gpio_chip *chip, unsigned offset) struct davinci_gpio_controller *d = gpiochip_get_data(chip); if (d->irq_domain) - return irq_create_mapping(d->irq_domain, d->chip.base + offset); + return irq_create_mapping(d->irq_domain, offset); else return -ENXIO; } @@ -369,7 +378,7 @@ static int gpio_to_irq_unbanked(struct gpio_chip *chip, unsigned offset) * can provide direct-mapped IRQs to AINTC (up to 32 GPIOs). */ if (offset < d->gpio_unbanked) - return d->gpio_irq + offset; + return d->base_irq + offset; else return -ENODEV; } @@ -382,7 +391,7 @@ static int gpio_irq_type_unbanked(struct irq_data *data, unsigned trigger) d = (struct davinci_gpio_controller *)irq_data_get_irq_handler_data(data); g = (struct davinci_gpio_regs __iomem *)d->regs; - mask = __gpio_mask(data->irq - d->gpio_irq); + mask = __gpio_mask(data->irq - d->base_irq); if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) return -EINVAL; @@ -401,7 +410,7 @@ davinci_gpio_irq_map(struct irq_domain *d, unsigned int irq, { struct davinci_gpio_controller *chips = (struct davinci_gpio_controller *)d->host_data; - struct davinci_gpio_regs __iomem *g = chips[hw / 32].regs; + struct davinci_gpio_regs __iomem *g = chips->regs[hw / 32]; irq_set_chip_and_handler_name(irq, &gpio_irqchip, handle_simple_irq, "davinci_gpio"); @@ -459,6 +468,7 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) struct irq_domain *irq_domain = NULL; const struct of_device_id *match; struct irq_chip *irq_chip; + struct davinci_gpio_irq_data *irqdata; gpio_get_irq_chip_cb_t gpio_get_irq_chip; /* @@ -514,10 +524,8 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) * IRQs, while the others use banked IRQs, would need some setup * tweaks to recognize hardware which can do that. */ - for (gpio = 0, bank = 0; gpio < ngpio; bank++, gpio += 32) { - chips[bank].chip.to_irq = gpio_to_irq_banked; - chips[bank].irq_domain = irq_domain; - } + chips->chip.to_irq = gpio_to_irq_banked; + chips->irq_domain = irq_domain; /* * AINTC can handle direct/unbanked IRQs for GPIOs, with the GPIO @@ -526,9 +534,9 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) */ if (pdata->gpio_unbanked) { /* pass "bank 0" GPIO IRQs to AINTC */ - chips[0].chip.to_irq = gpio_to_irq_unbanked; - chips[0].gpio_irq = bank_irq; - chips[0].gpio_unbanked = pdata->gpio_unbanked; + chips->chip.to_irq = gpio_to_irq_unbanked; + chips->base_irq = bank_irq; + chips->gpio_unbanked = pdata->gpio_unbanked; binten = GENMASK(pdata->gpio_unbanked / 16, 0); /* AINTC handles mask/unmask; GPIO handles triggering */ @@ -538,14 +546,14 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) irq_chip->irq_set_type = gpio_irq_type_unbanked; /* default trigger: both edges */ - g = chips[0].regs; + g = chips->regs[0]; writel_relaxed(~0, &g->set_falling); writel_relaxed(~0, &g->set_rising); /* set the direct IRQs up to use that irqchip */ for (gpio = 0; gpio < pdata->gpio_unbanked; gpio++, irq++) { irq_set_chip(irq, irq_chip); - irq_set_handler_data(irq, &chips[gpio / 32]); + irq_set_handler_data(irq, chips); irq_set_status_flags(irq, IRQ_TYPE_EDGE_BOTH); } @@ -561,7 +569,7 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) * There are register sets for 32 GPIOs. 2 banks of 16 * GPIOs are covered by each set of registers hence divide by 2 */ - g = chips[bank / 2].regs; + g = chips->regs[bank / 2]; writel_relaxed(~0, &g->clr_falling); writel_relaxed(~0, &g->clr_rising); @@ -570,8 +578,19 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) * gpio irqs. Pass the irq bank's corresponding controller to * the chained irq handler. */ + irqdata = devm_kzalloc(&pdev->dev, + sizeof(struct + davinci_gpio_irq_data), + GFP_KERNEL); + if (!irqdata) + return -ENOMEM; + + irqdata->regs = g; + irqdata->bank_num = bank; + irqdata->chip = chips; + irq_set_chained_handler_and_data(bank_irq, gpio_irq_handler, - &chips[gpio / 32]); + irqdata); binten |= BIT(bank); } diff --git a/include/linux/platform_data/gpio-davinci.h b/include/linux/platform_data/gpio-davinci.h index 18127c4aa4ba..c62a9438976d 100644 --- a/include/linux/platform_data/gpio-davinci.h +++ b/include/linux/platform_data/gpio-davinci.h @@ -21,19 +21,27 @@ #include +#define MAX_REGS_BANKS 5 + struct davinci_gpio_platform_data { u32 ngpio; u32 gpio_unbanked; }; +struct davinci_gpio_irq_data { + void __iomem *regs; + struct davinci_gpio_controller *chip; + int bank_num; +}; + struct davinci_gpio_controller { struct gpio_chip chip; struct irq_domain *irq_domain; /* Serialize access to GPIO registers */ spinlock_t lock; - void __iomem *regs; + void __iomem *regs[MAX_REGS_BANKS]; int gpio_unbanked; - unsigned gpio_irq; + unsigned int base_irq; }; /* -- cgit v1.2.3 From 8e11047b8f3cc0dc6df956cf01915077a574168e Mon Sep 17 00:00:00 2001 From: Keerthy Date: Tue, 17 Jan 2017 21:49:14 +0530 Subject: gpio: davinci: Add support for multiple GPIO controllers Update GPIO driver to support Multiple GPIO controllers by updating the base of subsequent GPIO chips with total of previous chips gpio count so that gpio_add_chip gets unique numbers. Signed-off-by: Keerthy Reviewed-by: Grygorii Strashko Signed-off-by: Linus Walleij --- drivers/gpio/gpio-davinci.c | 4 +++- include/linux/platform_data/gpio-davinci.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index 446df4ece915..2f0b6fdbcddb 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -186,7 +186,7 @@ static int davinci_gpio_of_xlate(struct gpio_chip *gc, static int davinci_gpio_probe(struct platform_device *pdev) { - static int ctrl_num; + static int ctrl_num, bank_base; int gpio, bank; unsigned ngpio, nbank; struct davinci_gpio_controller *chips; @@ -240,6 +240,7 @@ static int davinci_gpio_probe(struct platform_device *pdev) chips->chip.set = davinci_gpio_set; chips->chip.ngpio = ngpio; + chips->chip.base = bank_base; #ifdef CONFIG_OF_GPIO chips->chip.of_gpio_n_cells = 2; @@ -248,6 +249,7 @@ static int davinci_gpio_probe(struct platform_device *pdev) chips->chip.of_node = dev->of_node; #endif spin_lock_init(&chips->lock); + bank_base += ngpio; for (gpio = 0, bank = 0; gpio < ngpio; gpio += 32, bank++) chips->regs[bank] = gpio_base + offset_array[bank]; diff --git a/include/linux/platform_data/gpio-davinci.h b/include/linux/platform_data/gpio-davinci.h index c62a9438976d..90ae19ca828f 100644 --- a/include/linux/platform_data/gpio-davinci.h +++ b/include/linux/platform_data/gpio-davinci.h @@ -42,6 +42,7 @@ struct davinci_gpio_controller { void __iomem *regs[MAX_REGS_BANKS]; int gpio_unbanked; unsigned int base_irq; + unsigned int base; }; /* -- cgit v1.2.3 From 035a86b85790ffc8491c6d41cbbb5e74d6a17504 Mon Sep 17 00:00:00 2001 From: Keerthy Date: Tue, 17 Jan 2017 21:59:14 +0530 Subject: gpio: davinci: Remove custom .xlate With the current redesign of driver it's not necessary to have custom .xlate() as the gpiolib will assign default of_gpio_simple_xlate(). Suggested-by: Grygorii Strashko Signed-off-by: Keerthy Reviewed-by: Grygorii Strashko Signed-off-by: Linus Walleij --- drivers/gpio/gpio-davinci.c | 22 ---------------------- 1 file changed, 22 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index 2f0b6fdbcddb..72f49d1e110d 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -163,27 +163,6 @@ of_err: return NULL; } -#ifdef CONFIG_OF_GPIO -static int davinci_gpio_of_xlate(struct gpio_chip *gc, - const struct of_phandle_args *gpiospec, - u32 *flags) -{ - struct davinci_gpio_controller *chips = dev_get_drvdata(gc->parent); - struct davinci_gpio_platform_data *pdata = dev_get_platdata(gc->parent); - - if (gpiospec->args[0] > pdata->ngpio) - return -EINVAL; - - if (gc != &chips->chip) - return -EINVAL; - - if (flags) - *flags = gpiospec->args[1]; - - return gpiospec->args[0] % 32; -} -#endif - static int davinci_gpio_probe(struct platform_device *pdev) { static int ctrl_num, bank_base; @@ -244,7 +223,6 @@ static int davinci_gpio_probe(struct platform_device *pdev) #ifdef CONFIG_OF_GPIO chips->chip.of_gpio_n_cells = 2; - chips->chip.of_xlate = davinci_gpio_of_xlate; chips->chip.parent = dev; chips->chip.of_node = dev->of_node; #endif -- cgit v1.2.3 From 49cec4d8326b27e64779f888c680466d7863558f Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sun, 22 Jan 2017 13:18:44 +0100 Subject: gpio: Add a driver for Cortina Systems Gemini GPIO This is a heavy edit/rewrite of the GPIO driver for the Gemini SoC from arch/arm/mach-gemini/gpio.c. This rewrite uses all the best-in-class helper like generic GPIO and GPIOLIB_IRQCHIP and has been tested on ITian Square One Gemini-based NAS/router. Cc: Janos Laube Cc: Paulius Zaleckas Cc: Hans Ulli Kroll Cc: Florian Fainelli Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 9 ++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-gemini.c | 236 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 246 insertions(+) create mode 100644 drivers/gpio/gpio-gemini.c (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d5d36549ecc1..701809b1a105 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -197,6 +197,15 @@ config GPIO_GE_FPGA and write pin state) for GPIO implemented in a number of GE single board computers. +config GPIO_GEMINI + bool "Gemini GPIO" + depends on ARCH_GEMINI + depends on OF_GPIO + select GPIO_GENERIC + select GPIOLIB_IRQCHIP + help + Support for common GPIOs found in Cortina systems Gemini platforms. + config GPIO_GENERIC_PLATFORM tristate "Generic memory-mapped GPIO controller support (MMIO platform device)" select GPIO_GENERIC diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index a7676b82de6f..de45957b9b62 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o obj-$(CONFIG_GPIO_ETRAXFS) += gpio-etraxfs.o obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o +obj-$(CONFIG_GPIO_GEMINI) += gpio-gemini.o obj-$(CONFIG_GPIO_GPIO_MM) += gpio-gpio-mm.o obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o obj-$(CONFIG_HTC_EGPIO) += gpio-htc-egpio.o diff --git a/drivers/gpio/gpio-gemini.c b/drivers/gpio/gpio-gemini.c new file mode 100644 index 000000000000..962485163b7f --- /dev/null +++ b/drivers/gpio/gpio-gemini.c @@ -0,0 +1,236 @@ +/* + * Gemini gpiochip and interrupt routines + * Copyright (C) 2017 Linus Walleij + * + * Based on arch/arm/mach-gemini/gpio.c: + * Copyright (C) 2008-2009 Paulius Zaleckas + * + * Based on plat-mxc/gpio.c: + * MXC GPIO support. (c) 2008 Daniel Mack + * Copyright 2008 Juergen Beisert, kernel@pengutronix.de + */ +#include +#include +#include +#include +#include +#include + +/* GPIO registers definition */ +#define GPIO_DATA_OUT 0x00 +#define GPIO_DATA_IN 0x04 +#define GPIO_DIR 0x08 +#define GPIO_DATA_SET 0x10 +#define GPIO_DATA_CLR 0x14 +#define GPIO_PULL_EN 0x18 +#define GPIO_PULL_TYPE 0x1C +#define GPIO_INT_EN 0x20 +#define GPIO_INT_STAT 0x24 +#define GPIO_INT_MASK 0x2C +#define GPIO_INT_CLR 0x30 +#define GPIO_INT_TYPE 0x34 +#define GPIO_INT_BOTH_EDGE 0x38 +#define GPIO_INT_LEVEL 0x3C +#define GPIO_DEBOUNCE_EN 0x40 +#define GPIO_DEBOUNCE_PRESCALE 0x44 + +/** + * struct gemini_gpio - Gemini GPIO state container + * @dev: containing device for this instance + * @gc: gpiochip for this instance + */ +struct gemini_gpio { + struct device *dev; + struct gpio_chip gc; + void __iomem *base; +}; + +static void gemini_gpio_ack_irq(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct gemini_gpio *g = gpiochip_get_data(gc); + + writel(BIT(irqd_to_hwirq(d)), g->base + GPIO_INT_CLR); +} + +static void gemini_gpio_mask_irq(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct gemini_gpio *g = gpiochip_get_data(gc); + u32 val; + + val = readl(g->base + GPIO_INT_EN); + val &= ~BIT(irqd_to_hwirq(d)); + writel(val, g->base + GPIO_INT_EN); +} + +static void gemini_gpio_unmask_irq(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct gemini_gpio *g = gpiochip_get_data(gc); + u32 val; + + val = readl(g->base + GPIO_INT_EN); + val |= BIT(irqd_to_hwirq(d)); + writel(val, g->base + GPIO_INT_EN); +} + +static int gemini_gpio_set_irq_type(struct irq_data *d, unsigned int type) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct gemini_gpio *g = gpiochip_get_data(gc); + u32 mask = BIT(irqd_to_hwirq(d)); + u32 reg_both, reg_level, reg_type; + + reg_type = readl(g->base + GPIO_INT_TYPE); + reg_level = readl(g->base + GPIO_INT_LEVEL); + reg_both = readl(g->base + GPIO_INT_BOTH_EDGE); + + switch (type) { + case IRQ_TYPE_EDGE_BOTH: + irq_set_handler_locked(d, handle_edge_irq); + reg_type &= ~mask; + reg_both |= mask; + break; + case IRQ_TYPE_EDGE_RISING: + irq_set_handler_locked(d, handle_edge_irq); + reg_type &= ~mask; + reg_both &= ~mask; + reg_level &= ~mask; + break; + case IRQ_TYPE_EDGE_FALLING: + irq_set_handler_locked(d, handle_edge_irq); + reg_type &= ~mask; + reg_both &= ~mask; + reg_level |= mask; + break; + case IRQ_TYPE_LEVEL_HIGH: + irq_set_handler_locked(d, handle_level_irq); + reg_type |= mask; + reg_level &= ~mask; + break; + case IRQ_TYPE_LEVEL_LOW: + irq_set_handler_locked(d, handle_level_irq); + reg_type |= mask; + reg_level |= mask; + break; + default: + irq_set_handler_locked(d, handle_bad_irq); + return -EINVAL; + } + + writel(reg_type, g->base + GPIO_INT_TYPE); + writel(reg_level, g->base + GPIO_INT_LEVEL); + writel(reg_both, g->base + GPIO_INT_BOTH_EDGE); + + gemini_gpio_ack_irq(d); + + return 0; +} + +static struct irq_chip gemini_gpio_irqchip = { + .name = "GPIO", + .irq_ack = gemini_gpio_ack_irq, + .irq_mask = gemini_gpio_mask_irq, + .irq_unmask = gemini_gpio_unmask_irq, + .irq_set_type = gemini_gpio_set_irq_type, +}; + +static void gemini_gpio_irq_handler(struct irq_desc *desc) +{ + struct gpio_chip *gc = irq_desc_get_handler_data(desc); + struct gemini_gpio *g = gpiochip_get_data(gc); + struct irq_chip *irqchip = irq_desc_get_chip(desc); + int offset; + unsigned long stat; + + chained_irq_enter(irqchip, desc); + + stat = readl(g->base + GPIO_INT_STAT); + if (stat) + for_each_set_bit(offset, &stat, gc->ngpio) + generic_handle_irq(irq_find_mapping(gc->irqdomain, + offset)); + + chained_irq_exit(irqchip, desc); +} + +static int gemini_gpio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct resource *res; + struct gemini_gpio *g; + int irq; + int ret; + + g = devm_kzalloc(dev, sizeof(*g), GFP_KERNEL); + if (!g) + return -ENOMEM; + + g->dev = dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + g->base = devm_ioremap_resource(dev, res); + if (IS_ERR(g->base)) + return PTR_ERR(g->base); + + irq = platform_get_irq(pdev, 0); + if (!irq) + return -EINVAL; + + ret = bgpio_init(&g->gc, dev, 4, + g->base + GPIO_DATA_IN, + g->base + GPIO_DATA_SET, + g->base + GPIO_DATA_CLR, + g->base + GPIO_DIR, + NULL, + 0); + if (ret) { + dev_err(dev, "unable to init generic GPIO\n"); + return ret; + } + g->gc.label = "Gemini"; + g->gc.base = -1; + g->gc.parent = dev; + g->gc.owner = THIS_MODULE; + /* ngpio is set by bgpio_init() */ + + ret = devm_gpiochip_add_data(dev, &g->gc, g); + if (ret) + return ret; + + /* Disable, unmask and clear all interrupts */ + writel(0x0, g->base + GPIO_INT_EN); + writel(0x0, g->base + GPIO_INT_MASK); + writel(~0x0, g->base + GPIO_INT_CLR); + + ret = gpiochip_irqchip_add(&g->gc, &gemini_gpio_irqchip, + 0, handle_bad_irq, + IRQ_TYPE_NONE); + if (ret) { + dev_info(dev, "could not add irqchip\n"); + return ret; + } + gpiochip_set_chained_irqchip(&g->gc, &gemini_gpio_irqchip, + irq, gemini_gpio_irq_handler); + + dev_info(dev, "Gemini GPIO @%p registered\n", g->base); + + return 0; +} + +static const struct of_device_id gemini_gpio_of_match[] = { + { + .compatible = "cortina,gemini-gpio", + }, + {}, +}; + +static struct platform_driver gemini_gpio_driver = { + .driver = { + .name = "gemini-gpio", + .of_match_table = of_match_ptr(gemini_gpio_of_match), + }, + .probe = gemini_gpio_probe, +}; +builtin_platform_driver(gemini_gpio_driver); -- cgit v1.2.3 From be18320222811fcb4fea752b57e2b4fb504db3b4 Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Thu, 19 Jan 2017 10:05:27 -0500 Subject: gpio: 104-dio-48e: Add set_multiple callback function support The ACCES 104-DIO-48E series provides registers where 8 lines of GPIO may be set at a time. This patch add support for the set_multiple callback function, thus allowing multiple GPIO output lines to be set more efficiently in groups. Signed-off-by: William Breathitt Gray Signed-off-by: Linus Walleij --- drivers/gpio/gpio-104-dio-48e.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-104-dio-48e.c b/drivers/gpio/gpio-104-dio-48e.c index fcf776971ca9..7bc891f1d11a 100644 --- a/drivers/gpio/gpio-104-dio-48e.c +++ b/drivers/gpio/gpio-104-dio-48e.c @@ -204,6 +204,44 @@ static void dio48e_gpio_set(struct gpio_chip *chip, unsigned offset, int value) spin_unlock_irqrestore(&dio48egpio->lock, flags); } +static void dio48e_gpio_set_multiple(struct gpio_chip *chip, + unsigned long *mask, unsigned long *bits) +{ + struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip); + unsigned int i; + const unsigned int gpio_reg_size = 8; + unsigned int port; + unsigned int out_port; + unsigned int bitmask; + unsigned long flags; + + /* set bits are evaluated a gpio register size at a time */ + for (i = 0; i < chip->ngpio; i += gpio_reg_size) { + /* no more set bits in this mask word; skip to the next word */ + if (!mask[BIT_WORD(i)]) { + i = (BIT_WORD(i) + 1) * BITS_PER_LONG - gpio_reg_size; + continue; + } + + port = i / gpio_reg_size; + out_port = (port > 2) ? port + 1 : port; + bitmask = mask[BIT_WORD(i)] & bits[BIT_WORD(i)]; + + spin_lock_irqsave(&dio48egpio->lock, flags); + + /* update output state data and set device gpio register */ + dio48egpio->out_state[port] &= ~mask[BIT_WORD(i)]; + dio48egpio->out_state[port] |= bitmask; + outb(dio48egpio->out_state[port], dio48egpio->base + out_port); + + spin_unlock_irqrestore(&dio48egpio->lock, flags); + + /* prepare for next gpio register set */ + mask[BIT_WORD(i)] >>= gpio_reg_size; + bits[BIT_WORD(i)] >>= gpio_reg_size; + } +} + static void dio48e_irq_ack(struct irq_data *data) { } @@ -328,6 +366,7 @@ static int dio48e_probe(struct device *dev, unsigned int id) dio48egpio->chip.direction_output = dio48e_gpio_direction_output; dio48egpio->chip.get = dio48e_gpio_get; dio48egpio->chip.set = dio48e_gpio_set; + dio48egpio->chip.set_multiple = dio48e_gpio_set_multiple; dio48egpio->base = base[id]; dio48egpio->irq = irq[id]; -- cgit v1.2.3 From 9d7ae8127ff9eea84375dd8d962ce776a3734119 Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Thu, 19 Jan 2017 10:05:37 -0500 Subject: gpio: 104-idio-16: Add set_multiple callback function support The ACCES 104-IDIO-16 series provides registers where 8 lines of GPIO may be set at a time. This patch add support for the set_multiple callback function, thus allowing multiple GPIO output lines to be set more efficiently in groups. Signed-off-by: William Breathitt Gray Signed-off-by: Linus Walleij --- drivers/gpio/gpio-104-idio-16.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-104-idio-16.c b/drivers/gpio/gpio-104-idio-16.c index 6787b8fcf0d8..a57900fd0dc7 100644 --- a/drivers/gpio/gpio-104-idio-16.c +++ b/drivers/gpio/gpio-104-idio-16.c @@ -116,6 +116,25 @@ static void idio_16_gpio_set(struct gpio_chip *chip, unsigned offset, int value) spin_unlock_irqrestore(&idio16gpio->lock, flags); } +static void idio_16_gpio_set_multiple(struct gpio_chip *chip, + unsigned long *mask, unsigned long *bits) +{ + struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); + unsigned long flags; + + spin_lock_irqsave(&idio16gpio->lock, flags); + + idio16gpio->out_state &= ~*mask; + idio16gpio->out_state |= *mask & *bits; + + if (*mask & 0xFF) + outb(idio16gpio->out_state, idio16gpio->base); + if ((*mask >> 8) & 0xFF) + outb(idio16gpio->out_state >> 8, idio16gpio->base + 4); + + spin_unlock_irqrestore(&idio16gpio->lock, flags); +} + static void idio_16_irq_ack(struct irq_data *data) { } @@ -219,6 +238,7 @@ static int idio_16_probe(struct device *dev, unsigned int id) idio16gpio->chip.direction_output = idio_16_gpio_direction_output; idio16gpio->chip.get = idio_16_gpio_get; idio16gpio->chip.set = idio_16_gpio_set; + idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple; idio16gpio->base = base[id]; idio16gpio->irq = irq[id]; idio16gpio->out_state = 0xFFFF; -- cgit v1.2.3 From 65502a12adc343037e8a1e6e936dd8c01f4117b2 Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Thu, 19 Jan 2017 10:05:48 -0500 Subject: gpio: gpio-mm: Add set_multiple callback function support The Diamond Systems GPIO-MM series provides registers where 8 lines of GPIO may be set at a time. This patch add support for the set_multiple callback function, thus allowing multiple GPIO output lines to be set more efficiently in groups. Signed-off-by: William Breathitt Gray Signed-off-by: Linus Walleij --- drivers/gpio/gpio-gpio-mm.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-gpio-mm.c b/drivers/gpio/gpio-gpio-mm.c index 1e7def9449ce..093489556c54 100644 --- a/drivers/gpio/gpio-gpio-mm.c +++ b/drivers/gpio/gpio-gpio-mm.c @@ -192,6 +192,44 @@ static void gpiomm_gpio_set(struct gpio_chip *chip, unsigned int offset, spin_unlock_irqrestore(&gpiommgpio->lock, flags); } +static void gpiomm_gpio_set_multiple(struct gpio_chip *chip, + unsigned long *mask, unsigned long *bits) +{ + struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); + unsigned int i; + const unsigned int gpio_reg_size = 8; + unsigned int port; + unsigned int out_port; + unsigned int bitmask; + unsigned long flags; + + /* set bits are evaluated a gpio register size at a time */ + for (i = 0; i < chip->ngpio; i += gpio_reg_size) { + /* no more set bits in this mask word; skip to the next word */ + if (!mask[BIT_WORD(i)]) { + i = (BIT_WORD(i) + 1) * BITS_PER_LONG - gpio_reg_size; + continue; + } + + port = i / gpio_reg_size; + out_port = (port > 2) ? port + 1 : port; + bitmask = mask[BIT_WORD(i)] & bits[BIT_WORD(i)]; + + spin_lock_irqsave(&gpiommgpio->lock, flags); + + /* update output state data and set device gpio register */ + gpiommgpio->out_state[port] &= ~mask[BIT_WORD(i)]; + gpiommgpio->out_state[port] |= bitmask; + outb(gpiommgpio->out_state[port], gpiommgpio->base + out_port); + + spin_unlock_irqrestore(&gpiommgpio->lock, flags); + + /* prepare for next gpio register set */ + mask[BIT_WORD(i)] >>= gpio_reg_size; + bits[BIT_WORD(i)] >>= gpio_reg_size; + } +} + static int gpiomm_probe(struct device *dev, unsigned int id) { struct gpiomm_gpio *gpiommgpio; @@ -218,6 +256,7 @@ static int gpiomm_probe(struct device *dev, unsigned int id) gpiommgpio->chip.direction_output = gpiomm_gpio_direction_output; gpiommgpio->chip.get = gpiomm_gpio_get; gpiommgpio->chip.set = gpiomm_gpio_set; + gpiommgpio->chip.set_multiple = gpiomm_gpio_set_multiple; gpiommgpio->base = base[id]; spin_lock_init(&gpiommgpio->lock); -- cgit v1.2.3 From 99c8ac957e6b7c670b78ad7b8667051de8624d37 Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Thu, 19 Jan 2017 10:05:59 -0500 Subject: gpio: ws16c48: Add set_multiple callback function support The WinSystems WS16C48 provides registers where 8 lines of GPIO may be set at a time. This patch add support for the set_multiple callback function, thus allowing multiple GPIO output lines to be set more efficiently in groups. Signed-off-by: William Breathitt Gray Signed-off-by: Linus Walleij --- drivers/gpio/gpio-ws16c48.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-ws16c48.c b/drivers/gpio/gpio-ws16c48.c index eaa71d440ccf..25e539530c08 100644 --- a/drivers/gpio/gpio-ws16c48.c +++ b/drivers/gpio/gpio-ws16c48.c @@ -155,6 +155,46 @@ static void ws16c48_gpio_set(struct gpio_chip *chip, unsigned offset, int value) spin_unlock_irqrestore(&ws16c48gpio->lock, flags); } +static void ws16c48_gpio_set_multiple(struct gpio_chip *chip, + unsigned long *mask, unsigned long *bits) +{ + struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip); + unsigned int i; + const unsigned int gpio_reg_size = 8; + unsigned int port; + unsigned int iomask; + unsigned int bitmask; + unsigned long flags; + + /* set bits are evaluated a gpio register size at a time */ + for (i = 0; i < chip->ngpio; i += gpio_reg_size) { + /* no more set bits in this mask word; skip to the next word */ + if (!mask[BIT_WORD(i)]) { + i = (BIT_WORD(i) + 1) * BITS_PER_LONG - gpio_reg_size; + continue; + } + + port = i / gpio_reg_size; + + /* mask out GPIO configured for input */ + iomask = mask[BIT_WORD(i)] & ~ws16c48gpio->io_state[port]; + bitmask = iomask & bits[BIT_WORD(i)]; + + spin_lock_irqsave(&ws16c48gpio->lock, flags); + + /* update output state data and set device gpio register */ + ws16c48gpio->out_state[port] &= ~iomask; + ws16c48gpio->out_state[port] |= bitmask; + outb(ws16c48gpio->out_state[port], ws16c48gpio->base + port); + + spin_unlock_irqrestore(&ws16c48gpio->lock, flags); + + /* prepare for next gpio register set */ + mask[BIT_WORD(i)] >>= gpio_reg_size; + bits[BIT_WORD(i)] >>= gpio_reg_size; + } +} + static void ws16c48_irq_ack(struct irq_data *data) { struct gpio_chip *chip = irq_data_get_irq_chip_data(data); @@ -329,6 +369,7 @@ static int ws16c48_probe(struct device *dev, unsigned int id) ws16c48gpio->chip.direction_output = ws16c48_gpio_direction_output; ws16c48gpio->chip.get = ws16c48_gpio_get; ws16c48gpio->chip.set = ws16c48_gpio_set; + ws16c48gpio->chip.set_multiple = ws16c48_gpio_set_multiple; ws16c48gpio->base = base[id]; ws16c48gpio->irq = irq[id]; -- cgit v1.2.3 From 6596e59e63cd4c0c0b787ce8c1e8bdd1d957b16e Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Thu, 19 Jan 2017 22:23:20 +0000 Subject: gpio: exar: add gpio for exar cards Exar XR17V352/354/358 chips have 16 multi-purpose inputs/outputs which can be controlled using gpio interface. Add the gpio specific code. Signed-off-by: Sudip Mukherjee Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 7 ++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-exar.c | 200 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 208 insertions(+) create mode 100644 drivers/gpio/gpio-exar.c (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 701809b1a105..2d7739222cdb 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -185,6 +185,13 @@ config GPIO_ETRAXFS help Say yes here to support the GPIO controller on Axis ETRAX FS SoCs. +config GPIO_EXAR + tristate "Support for GPIO pins on XR17V352/354/358" + depends on SERIAL_8250_EXAR + help + Selecting this option will enable handling of GPIO pins present + on Exar XR17V352/354/358 chips. + config GPIO_GE_FPGA bool "GE FPGA based GPIO" depends on GE_FPGA diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index de45957b9b62..ee8b0dcac623 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -46,6 +46,7 @@ obj-$(CONFIG_GPIO_DWAPB) += gpio-dwapb.o obj-$(CONFIG_GPIO_EM) += gpio-em.o obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o obj-$(CONFIG_GPIO_ETRAXFS) += gpio-etraxfs.o +obj-$(CONFIG_GPIO_EXAR) += gpio-exar.o obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o obj-$(CONFIG_GPIO_GEMINI) += gpio-gemini.o diff --git a/drivers/gpio/gpio-exar.c b/drivers/gpio/gpio-exar.c new file mode 100644 index 000000000000..05c8946d6446 --- /dev/null +++ b/drivers/gpio/gpio-exar.c @@ -0,0 +1,200 @@ +/* + * GPIO driver for Exar XR17V35X chip + * + * Copyright (C) 2015 Sudip Mukherjee + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#define EXAR_OFFSET_MPIOLVL_LO 0x90 +#define EXAR_OFFSET_MPIOSEL_LO 0x93 +#define EXAR_OFFSET_MPIOLVL_HI 0x96 +#define EXAR_OFFSET_MPIOSEL_HI 0x99 + +#define DRIVER_NAME "gpio_exar" + +static DEFINE_IDA(ida_index); + +struct exar_gpio_chip { + struct gpio_chip gpio_chip; + struct mutex lock; + int index; + void __iomem *regs; + char name[20]; +}; + +static void exar_update(struct gpio_chip *chip, unsigned int reg, int val, + unsigned int offset) +{ + struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip); + int temp; + + mutex_lock(&exar_gpio->lock); + temp = readb(exar_gpio->regs + reg); + temp &= ~BIT(offset); + if (val) + temp |= BIT(offset); + writeb(temp, exar_gpio->regs + reg); + mutex_unlock(&exar_gpio->lock); +} + +static int exar_set_direction(struct gpio_chip *chip, int direction, + unsigned int offset) +{ + unsigned int bank = offset / 8; + unsigned int addr; + + addr = bank ? EXAR_OFFSET_MPIOSEL_HI : EXAR_OFFSET_MPIOSEL_LO; + exar_update(chip, addr, direction, offset % 8); + return 0; +} + +static int exar_direction_output(struct gpio_chip *chip, unsigned int offset, + int value) +{ + return exar_set_direction(chip, 0, offset); +} + +static int exar_direction_input(struct gpio_chip *chip, unsigned int offset) +{ + return exar_set_direction(chip, 1, offset); +} + +static int exar_get(struct gpio_chip *chip, unsigned int reg) +{ + struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip); + int value; + + mutex_lock(&exar_gpio->lock); + value = readb(exar_gpio->regs + reg); + mutex_unlock(&exar_gpio->lock); + + return !!value; +} + +static int exar_get_direction(struct gpio_chip *chip, unsigned int offset) +{ + unsigned int bank = offset / 8; + unsigned int addr; + int val; + + addr = bank ? EXAR_OFFSET_MPIOSEL_HI : EXAR_OFFSET_MPIOSEL_LO; + val = exar_get(chip, addr) >> (offset % 8); + + return !!val; +} + +static int exar_get_value(struct gpio_chip *chip, unsigned int offset) +{ + unsigned int bank = offset / 8; + unsigned int addr; + int val; + + addr = bank ? EXAR_OFFSET_MPIOLVL_LO : EXAR_OFFSET_MPIOLVL_HI; + val = exar_get(chip, addr) >> (offset % 8); + + return !!val; +} + +static void exar_set_value(struct gpio_chip *chip, unsigned int offset, + int value) +{ + unsigned int bank = offset / 8; + unsigned int addr; + + addr = bank ? EXAR_OFFSET_MPIOLVL_HI : EXAR_OFFSET_MPIOLVL_LO; + exar_update(chip, addr, value, offset % 8); +} + +static int gpio_exar_probe(struct platform_device *pdev) +{ + struct pci_dev *pcidev = platform_get_drvdata(pdev); + struct exar_gpio_chip *exar_gpio; + void __iomem *p; + int index, ret; + + if (pcidev->vendor != PCI_VENDOR_ID_EXAR) + return -ENODEV; + + /* + * Map the pci device to get the register addresses. + * We will need to read and write those registers to control + * the GPIO pins. + * Using managed functions will save us from unmaping on exit. + * As the device is enabled using managed functions by the + * UART driver we can also use managed functions here. + */ + p = pcim_iomap(pcidev, 0, 0); + if (!p) + return -ENOMEM; + + exar_gpio = devm_kzalloc(&pcidev->dev, sizeof(*exar_gpio), GFP_KERNEL); + if (!exar_gpio) + return -ENOMEM; + + mutex_init(&exar_gpio->lock); + + index = ida_simple_get(&ida_index, 0, 0, GFP_KERNEL); + + sprintf(exar_gpio->name, "exar_gpio%d", index); + exar_gpio->gpio_chip.label = exar_gpio->name; + exar_gpio->gpio_chip.parent = &pcidev->dev; + exar_gpio->gpio_chip.direction_output = exar_direction_output; + exar_gpio->gpio_chip.direction_input = exar_direction_input; + exar_gpio->gpio_chip.get_direction = exar_get_direction; + exar_gpio->gpio_chip.get = exar_get_value; + exar_gpio->gpio_chip.set = exar_set_value; + exar_gpio->gpio_chip.base = -1; + exar_gpio->gpio_chip.ngpio = 16; + exar_gpio->regs = p; + exar_gpio->index = index; + + ret = devm_gpiochip_add_data(&pcidev->dev, + &exar_gpio->gpio_chip, exar_gpio); + if (ret) + goto err_destroy; + + platform_set_drvdata(pdev, exar_gpio); + + return 0; + +err_destroy: + ida_simple_remove(&ida_index, index); + mutex_destroy(&exar_gpio->lock); + return ret; +} + +static int gpio_exar_remove(struct platform_device *pdev) +{ + struct exar_gpio_chip *exar_gpio = platform_get_drvdata(pdev); + + ida_simple_remove(&ida_index, exar_gpio->index); + mutex_destroy(&exar_gpio->lock); + + return 0; +} + +static struct platform_driver gpio_exar_driver = { + .probe = gpio_exar_probe, + .remove = gpio_exar_remove, + .driver = { + .name = DRIVER_NAME, + }, +}; + +module_platform_driver(gpio_exar_driver); + +MODULE_ALIAS("platform:" DRIVER_NAME); +MODULE_DESCRIPTION("Exar GPIO driver"); +MODULE_AUTHOR("Sudip Mukherjee "); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 00de1a518aebed3bcf44389cd5dae12a77ade726 Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Tue, 24 Jan 2017 15:00:31 -0500 Subject: gpio: 104-dio-48e: Utilize devm_ functions in driver probe callback The devm_ resource manager functions allow memory to be automatically released when a device is unbound. This patch takes advantage of the resource manager functions and replaces the gpiochip_add_data call and request_irq call with the devm_gpiochip_add_data call and devm_request_irq call respectively. In addition, the dio48e_remove function has been removed as no longer necessary due to the use of the relevant devm_ resource manager functions. Signed-off-by: William Breathitt Gray Signed-off-by: Linus Walleij --- drivers/gpio/gpio-104-dio-48e.c | 27 +++++---------------------- 1 file changed, 5 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-104-dio-48e.c b/drivers/gpio/gpio-104-dio-48e.c index 7bc891f1d11a..221243f17d4e 100644 --- a/drivers/gpio/gpio-104-dio-48e.c +++ b/drivers/gpio/gpio-104-dio-48e.c @@ -48,7 +48,6 @@ MODULE_PARM_DESC(irq, "ACCES 104-DIO-48E interrupt line numbers"); * @control: Control registers state * @lock: synchronization lock to prevent I/O race conditions * @base: base port address of the GPIO device - * @irq: Interrupt line number * @irq_mask: I/O bits affected by interrupts */ struct dio48e_gpio { @@ -58,7 +57,6 @@ struct dio48e_gpio { unsigned char control[2]; spinlock_t lock; unsigned base; - unsigned irq; unsigned char irq_mask; }; @@ -368,13 +366,12 @@ static int dio48e_probe(struct device *dev, unsigned int id) dio48egpio->chip.set = dio48e_gpio_set; dio48egpio->chip.set_multiple = dio48e_gpio_set_multiple; dio48egpio->base = base[id]; - dio48egpio->irq = irq[id]; spin_lock_init(&dio48egpio->lock); dev_set_drvdata(dev, dio48egpio); - err = gpiochip_add_data(&dio48egpio->chip, dio48egpio); + err = devm_gpiochip_add_data(dev, &dio48egpio->chip, dio48egpio); if (err) { dev_err(dev, "GPIO registering failed (%d)\n", err); return err; @@ -399,29 +396,16 @@ static int dio48e_probe(struct device *dev, unsigned int id) handle_edge_irq, IRQ_TYPE_NONE); if (err) { dev_err(dev, "Could not add irqchip (%d)\n", err); - goto err_gpiochip_remove; + return err; } - err = request_irq(irq[id], dio48e_irq_handler, 0, name, dio48egpio); + err = devm_request_irq(dev, irq[id], dio48e_irq_handler, 0, name, + dio48egpio); if (err) { dev_err(dev, "IRQ handler registering failed (%d)\n", err); - goto err_gpiochip_remove; + return err; } - return 0; - -err_gpiochip_remove: - gpiochip_remove(&dio48egpio->chip); - return err; -} - -static int dio48e_remove(struct device *dev, unsigned int id) -{ - struct dio48e_gpio *const dio48egpio = dev_get_drvdata(dev); - - free_irq(dio48egpio->irq, dio48egpio); - gpiochip_remove(&dio48egpio->chip); - return 0; } @@ -430,7 +414,6 @@ static struct isa_driver dio48e_driver = { .driver = { .name = "104-dio-48e" }, - .remove = dio48e_remove }; module_isa_driver(dio48e_driver, num_dio48e); -- cgit v1.2.3 From e43fee60344ae4b64cfb4ddeb5355c86606681fa Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Tue, 24 Jan 2017 15:00:43 -0500 Subject: gpio: 104-idi-48: Utilize devm_ functions in driver probe callback The devm_ resource manager functions allow memory to be automatically released when a device is unbound. This patch takes advantage of the resource manager functions and replaces the gpiochip_add_data call and request_irq call with the devm_gpiochip_add_data call and devm_request_irq call respectively. In addition, the idi_48_remove function has been removed as no longer necessary due to the use of the relevant devm_ resource manager functions. Signed-off-by: William Breathitt Gray Signed-off-by: Linus Walleij --- drivers/gpio/gpio-104-idi-48.c | 28 +++++----------------------- 1 file changed, 5 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-104-idi-48.c b/drivers/gpio/gpio-104-idi-48.c index 2d2763ea1a68..eafbf053f3e8 100644 --- a/drivers/gpio/gpio-104-idi-48.c +++ b/drivers/gpio/gpio-104-idi-48.c @@ -47,7 +47,6 @@ MODULE_PARM_DESC(irq, "ACCES 104-IDI-48 interrupt line numbers"); * @ack_lock: synchronization lock to prevent IRQ handler race conditions * @irq_mask: input bits affected by interrupts * @base: base port address of the GPIO device - * @irq: Interrupt line number * @cos_enb: Change-Of-State IRQ enable boundaries mask */ struct idi_48_gpio { @@ -56,7 +55,6 @@ struct idi_48_gpio { spinlock_t ack_lock; unsigned char irq_mask[6]; unsigned base; - unsigned irq; unsigned char cos_enb; }; @@ -244,14 +242,13 @@ static int idi_48_probe(struct device *dev, unsigned int id) idi48gpio->chip.direction_input = idi_48_gpio_direction_input; idi48gpio->chip.get = idi_48_gpio_get; idi48gpio->base = base[id]; - idi48gpio->irq = irq[id]; spin_lock_init(&idi48gpio->lock); spin_lock_init(&idi48gpio->ack_lock); dev_set_drvdata(dev, idi48gpio); - err = gpiochip_add_data(&idi48gpio->chip, idi48gpio); + err = devm_gpiochip_add_data(dev, &idi48gpio->chip, idi48gpio); if (err) { dev_err(dev, "GPIO registering failed (%d)\n", err); return err; @@ -265,30 +262,16 @@ static int idi_48_probe(struct device *dev, unsigned int id) handle_edge_irq, IRQ_TYPE_NONE); if (err) { dev_err(dev, "Could not add irqchip (%d)\n", err); - goto err_gpiochip_remove; + return err; } - err = request_irq(irq[id], idi_48_irq_handler, IRQF_SHARED, name, - idi48gpio); + err = devm_request_irq(dev, irq[id], idi_48_irq_handler, IRQF_SHARED, + name, idi48gpio); if (err) { dev_err(dev, "IRQ handler registering failed (%d)\n", err); - goto err_gpiochip_remove; + return err; } - return 0; - -err_gpiochip_remove: - gpiochip_remove(&idi48gpio->chip); - return err; -} - -static int idi_48_remove(struct device *dev, unsigned int id) -{ - struct idi_48_gpio *const idi48gpio = dev_get_drvdata(dev); - - free_irq(idi48gpio->irq, idi48gpio); - gpiochip_remove(&idi48gpio->chip); - return 0; } @@ -297,7 +280,6 @@ static struct isa_driver idi_48_driver = { .driver = { .name = "104-idi-48" }, - .remove = idi_48_remove }; module_isa_driver(idi_48_driver, num_idi_48); -- cgit v1.2.3 From 837143d356fd066ed6fb0a3a91700d66a7916841 Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Tue, 24 Jan 2017 15:00:54 -0500 Subject: gpio: 104-idio-16: Utilize devm_ functions in driver probe callback The devm_ resource manager functions allow memory to be automatically released when a device is unbound. This patch takes advantage of the resource manager functions and replaces the gpiochip_add_data call and request_irq call with the devm_gpiochip_add_data call and devm_request_irq call respectively. In addition, the idio_16_remove function has been removed as no longer necessary due to the use of the relevant devm_ resource manager functions. Signed-off-by: William Breathitt Gray Signed-off-by: Linus Walleij --- drivers/gpio/gpio-104-idio-16.c | 27 +++++---------------------- 1 file changed, 5 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-104-idio-16.c b/drivers/gpio/gpio-104-idio-16.c index a57900fd0dc7..01a091e17614 100644 --- a/drivers/gpio/gpio-104-idio-16.c +++ b/drivers/gpio/gpio-104-idio-16.c @@ -46,7 +46,6 @@ MODULE_PARM_DESC(irq, "ACCES 104-IDIO-16 interrupt line numbers"); * @lock: synchronization lock to prevent I/O race conditions * @irq_mask: I/O bits affected by interrupts * @base: base port address of the GPIO device - * @irq: Interrupt line number * @out_state: output bits state */ struct idio_16_gpio { @@ -54,7 +53,6 @@ struct idio_16_gpio { spinlock_t lock; unsigned long irq_mask; unsigned base; - unsigned irq; unsigned out_state; }; @@ -240,14 +238,13 @@ static int idio_16_probe(struct device *dev, unsigned int id) idio16gpio->chip.set = idio_16_gpio_set; idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple; idio16gpio->base = base[id]; - idio16gpio->irq = irq[id]; idio16gpio->out_state = 0xFFFF; spin_lock_init(&idio16gpio->lock); dev_set_drvdata(dev, idio16gpio); - err = gpiochip_add_data(&idio16gpio->chip, idio16gpio); + err = devm_gpiochip_add_data(dev, &idio16gpio->chip, idio16gpio); if (err) { dev_err(dev, "GPIO registering failed (%d)\n", err); return err; @@ -261,29 +258,16 @@ static int idio_16_probe(struct device *dev, unsigned int id) handle_edge_irq, IRQ_TYPE_NONE); if (err) { dev_err(dev, "Could not add irqchip (%d)\n", err); - goto err_gpiochip_remove; + return err; } - err = request_irq(irq[id], idio_16_irq_handler, 0, name, idio16gpio); + err = devm_request_irq(dev, irq[id], idio_16_irq_handler, 0, name, + idio16gpio); if (err) { dev_err(dev, "IRQ handler registering failed (%d)\n", err); - goto err_gpiochip_remove; + return err; } - return 0; - -err_gpiochip_remove: - gpiochip_remove(&idio16gpio->chip); - return err; -} - -static int idio_16_remove(struct device *dev, unsigned int id) -{ - struct idio_16_gpio *const idio16gpio = dev_get_drvdata(dev); - - free_irq(idio16gpio->irq, idio16gpio); - gpiochip_remove(&idio16gpio->chip); - return 0; } @@ -292,7 +276,6 @@ static struct isa_driver idio_16_driver = { .driver = { .name = "104-idio-16" }, - .remove = idio_16_remove }; module_isa_driver(idio_16_driver, num_idio_16); -- cgit v1.2.3 From 2141b0a1d718d5f75b581530ef4f9641c7c4284c Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Tue, 24 Jan 2017 15:01:04 -0500 Subject: gpio: gpio-mm: Utilize devm_ functions in driver probe callback The devm_ resource manager functions allow memory to be automatically released when a device is unbound. This patch takes advantage of the resource manager functions and replaces the gpiochip_add_data call with the devm_gpiochip_add_data call. In addition, the gpiomm_remove function has been removed as no longer necessary due to the use of the relevant devm_ resource manager functions. Signed-off-by: William Breathitt Gray Signed-off-by: Linus Walleij --- drivers/gpio/gpio-gpio-mm.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-gpio-mm.c b/drivers/gpio/gpio-gpio-mm.c index 093489556c54..393c8f9cf30d 100644 --- a/drivers/gpio/gpio-gpio-mm.c +++ b/drivers/gpio/gpio-gpio-mm.c @@ -263,7 +263,7 @@ static int gpiomm_probe(struct device *dev, unsigned int id) dev_set_drvdata(dev, gpiommgpio); - err = gpiochip_add_data(&gpiommgpio->chip, gpiommgpio); + err = devm_gpiochip_add_data(dev, &gpiommgpio->chip, gpiommgpio); if (err) { dev_err(dev, "GPIO registering failed (%d)\n", err); return err; @@ -282,21 +282,11 @@ static int gpiomm_probe(struct device *dev, unsigned int id) return 0; } -static int gpiomm_remove(struct device *dev, unsigned int id) -{ - struct gpiomm_gpio *const gpiommgpio = dev_get_drvdata(dev); - - gpiochip_remove(&gpiommgpio->chip); - - return 0; -} - static struct isa_driver gpiomm_driver = { .probe = gpiomm_probe, .driver = { .name = "gpio-mm" }, - .remove = gpiomm_remove }; module_isa_driver(gpiomm_driver, num_gpiomm); -- cgit v1.2.3 From b4cad1bc5ff63881b92a0fe9683723b4379d8c40 Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Tue, 24 Jan 2017 15:01:15 -0500 Subject: gpio: ws16c48: Utilize devm_ functions in driver probe callback The devm_ resource manager functions allow memory to be automatically released when a device is unbound. This patch takes advantage of the resource manager functions and replaces the gpiochip_add_data call and request_irq call with the devm_gpiochip_add_data call and devm_request_irq call respectively. In addition, the ws16c48_remove function has been removed as no longer necessary due to the use of the relevant devm_ resource manager functions. Signed-off-by: William Breathitt Gray Signed-off-by: Linus Walleij --- drivers/gpio/gpio-ws16c48.c | 28 +++++----------------------- 1 file changed, 5 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-ws16c48.c b/drivers/gpio/gpio-ws16c48.c index 25e539530c08..65de20dfbe7a 100644 --- a/drivers/gpio/gpio-ws16c48.c +++ b/drivers/gpio/gpio-ws16c48.c @@ -46,7 +46,6 @@ MODULE_PARM_DESC(irq, "WinSystems WS16C48 interrupt line numbers"); * @irq_mask: I/O bits affected by interrupts * @flow_mask: IRQ flow type mask for the respective I/O bits * @base: base port address of the GPIO device - * @irq: Interrupt line number */ struct ws16c48_gpio { struct gpio_chip chip; @@ -56,7 +55,6 @@ struct ws16c48_gpio { unsigned long irq_mask; unsigned long flow_mask; unsigned base; - unsigned irq; }; static int ws16c48_gpio_get_direction(struct gpio_chip *chip, unsigned offset) @@ -371,13 +369,12 @@ static int ws16c48_probe(struct device *dev, unsigned int id) ws16c48gpio->chip.set = ws16c48_gpio_set; ws16c48gpio->chip.set_multiple = ws16c48_gpio_set_multiple; ws16c48gpio->base = base[id]; - ws16c48gpio->irq = irq[id]; spin_lock_init(&ws16c48gpio->lock); dev_set_drvdata(dev, ws16c48gpio); - err = gpiochip_add_data(&ws16c48gpio->chip, ws16c48gpio); + err = devm_gpiochip_add_data(dev, &ws16c48gpio->chip, ws16c48gpio); if (err) { dev_err(dev, "GPIO registering failed (%d)\n", err); return err; @@ -394,30 +391,16 @@ static int ws16c48_probe(struct device *dev, unsigned int id) handle_edge_irq, IRQ_TYPE_NONE); if (err) { dev_err(dev, "Could not add irqchip (%d)\n", err); - goto err_gpiochip_remove; + return err; } - err = request_irq(irq[id], ws16c48_irq_handler, IRQF_SHARED, name, - ws16c48gpio); + err = devm_request_irq(dev, irq[id], ws16c48_irq_handler, IRQF_SHARED, + name, ws16c48gpio); if (err) { dev_err(dev, "IRQ handler registering failed (%d)\n", err); - goto err_gpiochip_remove; + return err; } - return 0; - -err_gpiochip_remove: - gpiochip_remove(&ws16c48gpio->chip); - return err; -} - -static int ws16c48_remove(struct device *dev, unsigned int id) -{ - struct ws16c48_gpio *const ws16c48gpio = dev_get_drvdata(dev); - - free_irq(ws16c48gpio->irq, ws16c48gpio); - gpiochip_remove(&ws16c48gpio->chip); - return 0; } @@ -426,7 +409,6 @@ static struct isa_driver ws16c48_driver = { .driver = { .name = "ws16c48" }, - .remove = ws16c48_remove }; module_isa_driver(ws16c48_driver, num_ws16c48); -- cgit v1.2.3 From 3d84fdb3f0b5367248b403b6d4da11e124eb71fa Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Fri, 27 Jan 2017 15:47:37 +0100 Subject: gpio: mcp23s08: use regmap Use regmap API to save some lines of codes and have debugfs support for all of the MCP's registers. Signed-off-by: Sebastian Reichel Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mcp23s08.c | 320 ++++++++++++++++++------------------------- 1 file changed, 130 insertions(+), 190 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c index 504550665091..bdb692345428 100644 --- a/drivers/gpio/gpio-mcp23s08.c +++ b/drivers/gpio/gpio-mcp23s08.c @@ -23,6 +23,7 @@ #include #include #include +#include /** * MCP types supported by driver @@ -58,16 +59,10 @@ struct mcp23s08; -struct mcp23s08_ops { - int (*read)(struct mcp23s08 *mcp, unsigned reg); - int (*write)(struct mcp23s08 *mcp, unsigned reg, unsigned val); - int (*read_regs)(struct mcp23s08 *mcp, unsigned reg, - u16 *vals, unsigned n); -}; - struct mcp23s08 { u8 addr; bool irq_active_high; + bool reg_shift; u16 cache[11]; u16 irq_rise; @@ -80,188 +75,126 @@ struct mcp23s08 { struct gpio_chip chip; - const struct mcp23s08_ops *ops; - void *data; /* ops specific data */ + struct regmap *regmap; + struct device *dev; }; -/* A given spi_device can represent up to eight mcp23sxx chips - * sharing the same chipselect but using different addresses - * (e.g. chips #0 and #3 might be populated, but not #1 or $2). - * Driver data holds all the per-chip data. - */ -struct mcp23s08_driver_data { - unsigned ngpio; - struct mcp23s08 *mcp[8]; - struct mcp23s08 chip[]; -}; +static const struct regmap_config mcp23x08_regmap = { + .reg_bits = 8, + .val_bits = 8, -/*----------------------------------------------------------------------*/ - -#if IS_ENABLED(CONFIG_I2C) - -static int mcp23008_read(struct mcp23s08 *mcp, unsigned reg) -{ - return i2c_smbus_read_byte_data(mcp->data, reg); -} - -static int mcp23008_write(struct mcp23s08 *mcp, unsigned reg, unsigned val) -{ - return i2c_smbus_write_byte_data(mcp->data, reg, val); -} - -static int -mcp23008_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n) -{ - while (n--) { - int ret = mcp23008_read(mcp, reg++); - if (ret < 0) - return ret; - *vals++ = ret; - } - - return 0; -} - -static int mcp23017_read(struct mcp23s08 *mcp, unsigned reg) -{ - return i2c_smbus_read_word_data(mcp->data, reg << 1); -} - -static int mcp23017_write(struct mcp23s08 *mcp, unsigned reg, unsigned val) -{ - return i2c_smbus_write_word_data(mcp->data, reg << 1, val); -} - -static int -mcp23017_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n) -{ - while (n--) { - int ret = mcp23017_read(mcp, reg++); - if (ret < 0) - return ret; - *vals++ = ret; - } - - return 0; -} - -static const struct mcp23s08_ops mcp23008_ops = { - .read = mcp23008_read, - .write = mcp23008_write, - .read_regs = mcp23008_read_regs, + .reg_stride = 1, + .max_register = MCP_OLAT, }; -static const struct mcp23s08_ops mcp23017_ops = { - .read = mcp23017_read, - .write = mcp23017_write, - .read_regs = mcp23017_read_regs, -}; +static const struct regmap_config mcp23x17_regmap = { + .reg_bits = 8, + .val_bits = 16, -#endif /* CONFIG_I2C */ + .reg_stride = 2, + .max_register = MCP_OLAT << 1, + .val_format_endian = REGMAP_ENDIAN_LITTLE, +}; /*----------------------------------------------------------------------*/ #ifdef CONFIG_SPI_MASTER -static int mcp23s08_read(struct mcp23s08 *mcp, unsigned reg) +static int mcp23sxx_spi_write(void *context, const void *data, size_t count) { - u8 tx[2], rx[1]; - int status; + struct mcp23s08 *mcp = context; + struct spi_device *spi = to_spi_device(mcp->dev); + struct spi_message m; + struct spi_transfer t[2] = { { .tx_buf = &mcp->addr, .len = 1, }, + { .tx_buf = data, .len = count, }, }; - tx[0] = mcp->addr | 0x01; - tx[1] = reg; - status = spi_write_then_read(mcp->data, tx, sizeof(tx), rx, sizeof(rx)); - return (status < 0) ? status : rx[0]; + spi_message_init(&m); + spi_message_add_tail(&t[0], &m); + spi_message_add_tail(&t[1], &m); + + return spi_sync(spi, &m); } -static int mcp23s08_write(struct mcp23s08 *mcp, unsigned reg, unsigned val) +static int mcp23sxx_spi_gather_write(void *context, + const void *reg, size_t reg_size, + const void *val, size_t val_size) { - u8 tx[3]; + struct mcp23s08 *mcp = context; + struct spi_device *spi = to_spi_device(mcp->dev); + struct spi_message m; + struct spi_transfer t[3] = { { .tx_buf = &mcp->addr, .len = 1, }, + { .tx_buf = reg, .len = reg_size, }, + { .tx_buf = val, .len = val_size, }, }; - tx[0] = mcp->addr; - tx[1] = reg; - tx[2] = val; - return spi_write_then_read(mcp->data, tx, sizeof(tx), NULL, 0); + spi_message_init(&m); + spi_message_add_tail(&t[0], &m); + spi_message_add_tail(&t[1], &m); + spi_message_add_tail(&t[2], &m); + + return spi_sync(spi, &m); } -static int -mcp23s08_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n) +static int mcp23sxx_spi_read(void *context, const void *reg, size_t reg_size, + void *val, size_t val_size) { - u8 tx[2], *tmp; - int status; + struct mcp23s08 *mcp = context; + struct spi_device *spi = to_spi_device(mcp->dev); + u8 tx[2]; - if ((n + reg) > sizeof(mcp->cache)) + if (reg_size != 1) return -EINVAL; + tx[0] = mcp->addr | 0x01; - tx[1] = reg; + tx[1] = *((u8 *) reg); - tmp = (u8 *)vals; - status = spi_write_then_read(mcp->data, tx, sizeof(tx), tmp, n); - if (status >= 0) { - while (n--) - vals[n] = tmp[n]; /* expand to 16bit */ - } - return status; + return spi_write_then_read(spi, tx, sizeof(tx), val, val_size); } -static int mcp23s17_read(struct mcp23s08 *mcp, unsigned reg) -{ - u8 tx[2], rx[2]; - int status; +static const struct regmap_bus mcp23sxx_spi_regmap = { + .write = mcp23sxx_spi_write, + .gather_write = mcp23sxx_spi_gather_write, + .read = mcp23sxx_spi_read, +}; - tx[0] = mcp->addr | 0x01; - tx[1] = reg << 1; - status = spi_write_then_read(mcp->data, tx, sizeof(tx), rx, sizeof(rx)); - return (status < 0) ? status : (rx[0] | (rx[1] << 8)); -} +#endif /* CONFIG_SPI_MASTER */ -static int mcp23s17_write(struct mcp23s08 *mcp, unsigned reg, unsigned val) +static int mcp_read(struct mcp23s08 *mcp, unsigned int reg, unsigned int *val) { - u8 tx[4]; - - tx[0] = mcp->addr; - tx[1] = reg << 1; - tx[2] = val; - tx[3] = val >> 8; - return spi_write_then_read(mcp->data, tx, sizeof(tx), NULL, 0); + return regmap_read(mcp->regmap, reg << mcp->reg_shift, val); } -static int -mcp23s17_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n) +static int mcp_write(struct mcp23s08 *mcp, unsigned int reg, unsigned int val) { - u8 tx[2]; - int status; + return regmap_write(mcp->regmap, reg << mcp->reg_shift, val); +} - if ((n + reg) > sizeof(mcp->cache)) - return -EINVAL; - tx[0] = mcp->addr | 0x01; - tx[1] = reg << 1; +static int mcp_update_cache(struct mcp23s08 *mcp) +{ + int ret, reg, i; - status = spi_write_then_read(mcp->data, tx, sizeof(tx), - (u8 *)vals, n * 2); - if (status >= 0) { - while (n--) - vals[n] = __le16_to_cpu((__le16)vals[n]); + for (i = 0; i < ARRAY_SIZE(mcp->cache); i++) { + ret = mcp_read(mcp, i, ®); + if (ret < 0) + return ret; + mcp->cache[i] = reg; } - return status; + return 0; } -static const struct mcp23s08_ops mcp23s08_ops = { - .read = mcp23s08_read, - .write = mcp23s08_write, - .read_regs = mcp23s08_read_regs, -}; +/*----------------------------------------------------------------------*/ -static const struct mcp23s08_ops mcp23s17_ops = { - .read = mcp23s17_read, - .write = mcp23s17_write, - .read_regs = mcp23s17_read_regs, +/* A given spi_device can represent up to eight mcp23sxx chips + * sharing the same chipselect but using different addresses + * (e.g. chips #0 and #3 might be populated, but not #1 or $2). + * Driver data holds all the per-chip data. + */ +struct mcp23s08_driver_data { + unsigned ngpio; + struct mcp23s08 *mcp[8]; + struct mcp23s08 chip[]; }; -#endif /* CONFIG_SPI_MASTER */ - -/*----------------------------------------------------------------------*/ static int mcp23s08_direction_input(struct gpio_chip *chip, unsigned offset) { @@ -270,7 +203,7 @@ static int mcp23s08_direction_input(struct gpio_chip *chip, unsigned offset) mutex_lock(&mcp->lock); mcp->cache[MCP_IODIR] |= (1 << offset); - status = mcp->ops->write(mcp, MCP_IODIR, mcp->cache[MCP_IODIR]); + status = mcp_write(mcp, MCP_IODIR, mcp->cache[MCP_IODIR]); mutex_unlock(&mcp->lock); return status; } @@ -278,13 +211,13 @@ static int mcp23s08_direction_input(struct gpio_chip *chip, unsigned offset) static int mcp23s08_get(struct gpio_chip *chip, unsigned offset) { struct mcp23s08 *mcp = gpiochip_get_data(chip); - int status; + int status, ret; mutex_lock(&mcp->lock); /* REVISIT reading this clears any IRQ ... */ - status = mcp->ops->read(mcp, MCP_GPIO); - if (status < 0) + ret = mcp_read(mcp, MCP_GPIO, &status); + if (ret < 0) status = 0; else { mcp->cache[MCP_GPIO] = status; @@ -303,7 +236,7 @@ static int __mcp23s08_set(struct mcp23s08 *mcp, unsigned mask, int value) else olat &= ~mask; mcp->cache[MCP_OLAT] = olat; - return mcp->ops->write(mcp, MCP_OLAT, olat); + return mcp_write(mcp, MCP_OLAT, olat); } static void mcp23s08_set(struct gpio_chip *chip, unsigned offset, int value) @@ -327,7 +260,7 @@ mcp23s08_direction_output(struct gpio_chip *chip, unsigned offset, int value) status = __mcp23s08_set(mcp, mask, value); if (status == 0) { mcp->cache[MCP_IODIR] &= ~mask; - status = mcp->ops->write(mcp, MCP_IODIR, mcp->cache[MCP_IODIR]); + status = mcp_write(mcp, MCP_IODIR, mcp->cache[MCP_IODIR]); } mutex_unlock(&mcp->lock); return status; @@ -341,16 +274,14 @@ static irqreturn_t mcp23s08_irq(int irq, void *data) unsigned int child_irq; mutex_lock(&mcp->lock); - intf = mcp->ops->read(mcp, MCP_INTF); - if (intf < 0) { + if (mcp_read(mcp, MCP_INTF, &intf) < 0) { mutex_unlock(&mcp->lock); return IRQ_HANDLED; } mcp->cache[MCP_INTF] = intf; - intcap = mcp->ops->read(mcp, MCP_INTCAP); - if (intcap < 0) { + if (mcp_read(mcp, MCP_INTCAP, &intcap) < 0) { mutex_unlock(&mcp->lock); return IRQ_HANDLED; } @@ -435,9 +366,9 @@ static void mcp23s08_irq_bus_unlock(struct irq_data *data) struct mcp23s08 *mcp = gpiochip_get_data(gc); mutex_lock(&mcp->lock); - mcp->ops->write(mcp, MCP_GPINTEN, mcp->cache[MCP_GPINTEN]); - mcp->ops->write(mcp, MCP_DEFVAL, mcp->cache[MCP_DEFVAL]); - mcp->ops->write(mcp, MCP_INTCON, mcp->cache[MCP_INTCON]); + mcp_write(mcp, MCP_GPINTEN, mcp->cache[MCP_GPINTEN]); + mcp_write(mcp, MCP_DEFVAL, mcp->cache[MCP_DEFVAL]); + mcp_write(mcp, MCP_INTCON, mcp->cache[MCP_INTCON]); mutex_unlock(&mcp->lock); mutex_unlock(&mcp->irq_lock); } @@ -514,7 +445,7 @@ static void mcp23s08_dbg_show(struct seq_file *s, struct gpio_chip *chip) bank = '0' + ((mcp->addr >> 1) & 0x7); mutex_lock(&mcp->lock); - t = mcp->ops->read_regs(mcp, 0, mcp->cache, ARRAY_SIZE(mcp->cache)); + t = mcp_update_cache(mcp); if (t < 0) { seq_printf(s, " I/O ERROR %d\n", t); goto done; @@ -549,12 +480,12 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, void *data, unsigned addr, unsigned type, struct mcp23s08_platform_data *pdata, int cs) { - int status; + int status, ret; bool mirror = false; mutex_init(&mcp->lock); - mcp->data = data; + mcp->dev = dev; mcp->addr = addr; mcp->irq_active_high = false; @@ -571,19 +502,25 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, switch (type) { #ifdef CONFIG_SPI_MASTER case MCP_TYPE_S08: - mcp->ops = &mcp23s08_ops; + mcp->regmap = devm_regmap_init(dev, &mcp23sxx_spi_regmap, mcp, + &mcp23x08_regmap); + mcp->reg_shift = 0; mcp->chip.ngpio = 8; mcp->chip.label = "mcp23s08"; break; case MCP_TYPE_S17: - mcp->ops = &mcp23s17_ops; + mcp->regmap = devm_regmap_init(dev, &mcp23sxx_spi_regmap, mcp, + &mcp23x17_regmap); + mcp->reg_shift = 1; mcp->chip.ngpio = 16; mcp->chip.label = "mcp23s17"; break; case MCP_TYPE_S18: - mcp->ops = &mcp23s17_ops; + mcp->regmap = devm_regmap_init(dev, &mcp23sxx_spi_regmap, mcp, + &mcp23x17_regmap); + mcp->reg_shift = 1; mcp->chip.ngpio = 16; mcp->chip.label = "mcp23s18"; break; @@ -591,13 +528,15 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, #if IS_ENABLED(CONFIG_I2C) case MCP_TYPE_008: - mcp->ops = &mcp23008_ops; + mcp->regmap = devm_regmap_init_i2c(data, &mcp23x08_regmap); + mcp->reg_shift = 0; mcp->chip.ngpio = 8; mcp->chip.label = "mcp23008"; break; case MCP_TYPE_017: - mcp->ops = &mcp23017_ops; + mcp->regmap = devm_regmap_init_i2c(data, &mcp23x17_regmap); + mcp->reg_shift = 1; mcp->chip.ngpio = 16; mcp->chip.label = "mcp23017"; break; @@ -608,6 +547,9 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, return -EINVAL; } + if (IS_ERR(mcp->regmap)) + return PTR_ERR(mcp->regmap); + mcp->chip.base = pdata->base; mcp->chip.can_sleep = true; mcp->chip.parent = dev; @@ -617,8 +559,8 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, * and MCP_IOCON.HAEN = 1, so we work with all chips. */ - status = mcp->ops->read(mcp, MCP_IOCON); - if (status < 0) + ret = mcp_read(mcp, MCP_IOCON, &status); + if (ret < 0) goto fail; mcp->irq_controller = pdata->irq_controller; @@ -646,51 +588,49 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, if (type == MCP_TYPE_S18) status |= IOCON_INTCC | (IOCON_INTCC << 8); - status = mcp->ops->write(mcp, MCP_IOCON, status); - if (status < 0) + ret = mcp_write(mcp, MCP_IOCON, status); + if (ret < 0) goto fail; } /* configure ~100K pullups */ - status = mcp->ops->write(mcp, MCP_GPPU, pdata->chip[cs].pullups); - if (status < 0) + ret = mcp_write(mcp, MCP_GPPU, pdata->chip[cs].pullups); + if (ret < 0) goto fail; - status = mcp->ops->read_regs(mcp, 0, mcp->cache, ARRAY_SIZE(mcp->cache)); - if (status < 0) + ret = mcp_update_cache(mcp); + if (ret < 0) goto fail; /* disable inverter on input */ if (mcp->cache[MCP_IPOL] != 0) { mcp->cache[MCP_IPOL] = 0; - status = mcp->ops->write(mcp, MCP_IPOL, 0); - if (status < 0) + ret = mcp_write(mcp, MCP_IPOL, 0); + if (ret < 0) goto fail; } /* disable irqs */ if (mcp->cache[MCP_GPINTEN] != 0) { mcp->cache[MCP_GPINTEN] = 0; - status = mcp->ops->write(mcp, MCP_GPINTEN, 0); - if (status < 0) + ret = mcp_write(mcp, MCP_GPINTEN, 0); + if (ret < 0) goto fail; } - status = gpiochip_add_data(&mcp->chip, mcp); - if (status < 0) + ret = gpiochip_add_data(&mcp->chip, mcp); + if (ret < 0) goto fail; if (mcp->irq && mcp->irq_controller) { - status = mcp23s08_irq_setup(mcp); - if (status) { + ret = mcp23s08_irq_setup(mcp); + if (ret) goto fail; - } } fail: - if (status < 0) - dev_dbg(dev, "can't setup chip %d, --> %d\n", - addr, status); - return status; + if (ret < 0) + dev_dbg(dev, "can't setup chip %d, --> %d\n", addr, ret); + return ret; } /*----------------------------------------------------------------------*/ -- cgit v1.2.3 From 3988d663c02fc050afddb78953e8b0cad83e9905 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Fri, 27 Jan 2017 12:56:42 +0100 Subject: gpiolib: Fix a WARN_ON that can never trigger "if (!x) WARN_ON(x)" can never trigger. Signed-off-by: Christophe JAILLET Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 18a173fc4a21..385df5241e5d 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1422,8 +1422,7 @@ void devm_gpiochip_remove(struct device *dev, struct gpio_chip *chip) ret = devres_release(dev, devm_gpio_chip_release, devm_gpio_chip_match, chip); - if (!ret) - WARN_ON(ret); + WARN_ON(ret); } EXPORT_SYMBOL_GPL(devm_gpiochip_remove); -- cgit v1.2.3 From 3547f1405d0346d5c10c377762a70b7090f8ed7b Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Mon, 30 Jan 2017 09:39:37 -0500 Subject: gpio: 104-dio-48e: Remove unnecessary driver_data set Setting driver_data was necessary to access private data in the dio48e_remove function. Now that the dio48e_remove function is gone, driver_data is no longer used. This patch removes the relevant code. Signed-off-by: William Breathitt Gray Signed-off-by: Linus Walleij --- drivers/gpio/gpio-104-dio-48e.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-104-dio-48e.c b/drivers/gpio/gpio-104-dio-48e.c index 221243f17d4e..b6b0378166c4 100644 --- a/drivers/gpio/gpio-104-dio-48e.c +++ b/drivers/gpio/gpio-104-dio-48e.c @@ -369,8 +369,6 @@ static int dio48e_probe(struct device *dev, unsigned int id) spin_lock_init(&dio48egpio->lock); - dev_set_drvdata(dev, dio48egpio); - err = devm_gpiochip_add_data(dev, &dio48egpio->chip, dio48egpio); if (err) { dev_err(dev, "GPIO registering failed (%d)\n", err); -- cgit v1.2.3 From b4e73edee51a3c1c00186fe86b51f6626757ffc3 Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Mon, 30 Jan 2017 09:39:47 -0500 Subject: gpio: 104-idi-48: Remove unnecessary driver_data set Setting driver_data was necessary to access private data in the idi_48_remove function. Now that the idi_48_remove function is gone, driver_data is no longer used. This patch removes the relevant code. Signed-off-by: William Breathitt Gray Signed-off-by: Linus Walleij --- drivers/gpio/gpio-104-idi-48.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-104-idi-48.c b/drivers/gpio/gpio-104-idi-48.c index eafbf053f3e8..dc100dff6e13 100644 --- a/drivers/gpio/gpio-104-idi-48.c +++ b/drivers/gpio/gpio-104-idi-48.c @@ -246,8 +246,6 @@ static int idi_48_probe(struct device *dev, unsigned int id) spin_lock_init(&idi48gpio->lock); spin_lock_init(&idi48gpio->ack_lock); - dev_set_drvdata(dev, idi48gpio); - err = devm_gpiochip_add_data(dev, &idi48gpio->chip, idi48gpio); if (err) { dev_err(dev, "GPIO registering failed (%d)\n", err); -- cgit v1.2.3 From c74f04d4b5b5049d6bd94bdc85a9da7b5896ca4b Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Mon, 30 Jan 2017 09:39:57 -0500 Subject: gpio: 104-idio-16: Remove unnecessary driver_data set Setting driver_data was necessary to access private data in the idio_16_remove function. Now that the idio_16_remove function is gone, driver_data is no longer used. This patch removes the relevant code. Signed-off-by: William Breathitt Gray Signed-off-by: Linus Walleij --- drivers/gpio/gpio-104-idio-16.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-104-idio-16.c b/drivers/gpio/gpio-104-idio-16.c index 01a091e17614..67068b61b90b 100644 --- a/drivers/gpio/gpio-104-idio-16.c +++ b/drivers/gpio/gpio-104-idio-16.c @@ -242,8 +242,6 @@ static int idio_16_probe(struct device *dev, unsigned int id) spin_lock_init(&idio16gpio->lock); - dev_set_drvdata(dev, idio16gpio); - err = devm_gpiochip_add_data(dev, &idio16gpio->chip, idio16gpio); if (err) { dev_err(dev, "GPIO registering failed (%d)\n", err); -- cgit v1.2.3 From 232a448706a2ad102b3689687c1ba99e67847e68 Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Mon, 30 Jan 2017 09:40:15 -0500 Subject: gpio: gpio-mm: Remove unnecessary driver_data set Setting driver_data was necessary to access private data in the gpiomm_remove function. Now that the gpiomm_remove function is gone, driver_data is no longer used. This patch removes the relevant code. Signed-off-by: William Breathitt Gray Signed-off-by: Linus Walleij --- drivers/gpio/gpio-gpio-mm.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-gpio-mm.c b/drivers/gpio/gpio-gpio-mm.c index 393c8f9cf30d..60017425b49f 100644 --- a/drivers/gpio/gpio-gpio-mm.c +++ b/drivers/gpio/gpio-gpio-mm.c @@ -261,8 +261,6 @@ static int gpiomm_probe(struct device *dev, unsigned int id) spin_lock_init(&gpiommgpio->lock); - dev_set_drvdata(dev, gpiommgpio); - err = devm_gpiochip_add_data(dev, &gpiommgpio->chip, gpiommgpio); if (err) { dev_err(dev, "GPIO registering failed (%d)\n", err); -- cgit v1.2.3 From 9e1b487bb494f1fd45ce4952aa665ba1611d34b4 Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Mon, 30 Jan 2017 09:40:26 -0500 Subject: gpio: ws16c48: Remove unnecessary driver_data set Setting driver_data was necessary to access private data in the ws16c48_remove function. Now that the ws16c48_remove function is gone, driver_data is no longer used. This patch removes the relevant code. Signed-off-by: William Breathitt Gray Signed-off-by: Linus Walleij --- drivers/gpio/gpio-ws16c48.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-ws16c48.c b/drivers/gpio/gpio-ws16c48.c index 65de20dfbe7a..48b35589b7d6 100644 --- a/drivers/gpio/gpio-ws16c48.c +++ b/drivers/gpio/gpio-ws16c48.c @@ -372,8 +372,6 @@ static int ws16c48_probe(struct device *dev, unsigned int id) spin_lock_init(&ws16c48gpio->lock); - dev_set_drvdata(dev, ws16c48gpio); - err = devm_gpiochip_add_data(dev, &ws16c48gpio->chip, ws16c48gpio); if (err) { dev_err(dev, "GPIO registering failed (%d)\n", err); -- cgit v1.2.3 From 7bdba73effe286fd607da9bb7448dd07a4452a33 Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Mon, 30 Jan 2017 13:32:58 -0500 Subject: gpio: 104-dio-48e: Add support for GPIO names This patch sets the gpio_chip names option with an array of GPIO line names that match the manual documentation for the ACCES 104-DIO-48E. This should make it easier for users to identify which GPIO line corresponds to a respective GPIO pin on the device. Signed-off-by: William Breathitt Gray Signed-off-by: Linus Walleij --- drivers/gpio/gpio-104-dio-48e.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-104-dio-48e.c b/drivers/gpio/gpio-104-dio-48e.c index b6b0378166c4..17bd2ab4ebe2 100644 --- a/drivers/gpio/gpio-104-dio-48e.c +++ b/drivers/gpio/gpio-104-dio-48e.c @@ -338,6 +338,26 @@ static irqreturn_t dio48e_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } +#define DIO48E_NGPIO 48 +static const char *dio48e_names[DIO48E_NGPIO] = { + "PPI Group 0 Port A 0", "PPI Group 0 Port A 1", "PPI Group 0 Port A 2", + "PPI Group 0 Port A 3", "PPI Group 0 Port A 4", "PPI Group 0 Port A 5", + "PPI Group 0 Port A 6", "PPI Group 0 Port A 7", "PPI Group 0 Port B 0", + "PPI Group 0 Port B 1", "PPI Group 0 Port B 2", "PPI Group 0 Port B 3", + "PPI Group 0 Port B 4", "PPI Group 0 Port B 5", "PPI Group 0 Port B 6", + "PPI Group 0 Port B 7", "PPI Group 0 Port C 0", "PPI Group 0 Port C 1", + "PPI Group 0 Port C 2", "PPI Group 0 Port C 3", "PPI Group 0 Port C 4", + "PPI Group 0 Port C 5", "PPI Group 0 Port C 6", "PPI Group 0 Port C 7", + "PPI Group 1 Port A 0", "PPI Group 1 Port A 1", "PPI Group 1 Port A 2", + "PPI Group 1 Port A 3", "PPI Group 1 Port A 4", "PPI Group 1 Port A 5", + "PPI Group 1 Port A 6", "PPI Group 1 Port A 7", "PPI Group 1 Port B 0", + "PPI Group 1 Port B 1", "PPI Group 1 Port B 2", "PPI Group 1 Port B 3", + "PPI Group 1 Port B 4", "PPI Group 1 Port B 5", "PPI Group 1 Port B 6", + "PPI Group 1 Port B 7", "PPI Group 1 Port C 0", "PPI Group 1 Port C 1", + "PPI Group 1 Port C 2", "PPI Group 1 Port C 3", "PPI Group 1 Port C 4", + "PPI Group 1 Port C 5", "PPI Group 1 Port C 6", "PPI Group 1 Port C 7" +}; + static int dio48e_probe(struct device *dev, unsigned int id) { struct dio48e_gpio *dio48egpio; @@ -358,7 +378,8 @@ static int dio48e_probe(struct device *dev, unsigned int id) dio48egpio->chip.parent = dev; dio48egpio->chip.owner = THIS_MODULE; dio48egpio->chip.base = -1; - dio48egpio->chip.ngpio = 48; + dio48egpio->chip.ngpio = DIO48E_NGPIO; + dio48egpio->chip.names = dio48e_names; dio48egpio->chip.get_direction = dio48e_gpio_get_direction; dio48egpio->chip.direction_input = dio48e_gpio_direction_input; dio48egpio->chip.direction_output = dio48e_gpio_direction_output; -- cgit v1.2.3 From a71dc2537a1ad792d6c3dc6129c60ec28447f215 Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Mon, 30 Jan 2017 13:33:11 -0500 Subject: gpio: 104-idi-48: Add support for GPIO names This patch sets the gpio_chip names option with an array of GPIO line names that match the manual documentation for the ACCES 104-IDI-48. This should make it easier for users to identify which GPIO line corresponds to a respective GPIO pin on the device. Signed-off-by: William Breathitt Gray Signed-off-by: Linus Walleij --- drivers/gpio/gpio-104-idi-48.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-104-idi-48.c b/drivers/gpio/gpio-104-idi-48.c index dc100dff6e13..568375a7ebc2 100644 --- a/drivers/gpio/gpio-104-idi-48.c +++ b/drivers/gpio/gpio-104-idi-48.c @@ -217,6 +217,18 @@ static irqreturn_t idi_48_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } +#define IDI48_NGPIO 48 +static const char *idi48_names[IDI48_NGPIO] = { + "Bit 0 A", "Bit 1 A", "Bit 2 A", "Bit 3 A", "Bit 4 A", "Bit 5 A", + "Bit 6 A", "Bit 7 A", "Bit 8 A", "Bit 9 A", "Bit 10 A", "Bit 11 A", + "Bit 12 A", "Bit 13 A", "Bit 14 A", "Bit 15 A", "Bit 16 A", "Bit 17 A", + "Bit 18 A", "Bit 19 A", "Bit 20 A", "Bit 21 A", "Bit 22 A", "Bit 23 A", + "Bit 0 B", "Bit 1 B", "Bit 2 B", "Bit 3 B", "Bit 4 B", "Bit 5 B", + "Bit 6 B", "Bit 7 B", "Bit 8 B", "Bit 9 B", "Bit 10 B", "Bit 11 B", + "Bit 12 B", "Bit 13 B", "Bit 14 B", "Bit 15 B", "Bit 16 B", "Bit 17 B", + "Bit 18 B", "Bit 19 B", "Bit 20 B", "Bit 21 B", "Bit 22 B", "Bit 23 B" +}; + static int idi_48_probe(struct device *dev, unsigned int id) { struct idi_48_gpio *idi48gpio; @@ -237,7 +249,8 @@ static int idi_48_probe(struct device *dev, unsigned int id) idi48gpio->chip.parent = dev; idi48gpio->chip.owner = THIS_MODULE; idi48gpio->chip.base = -1; - idi48gpio->chip.ngpio = 48; + idi48gpio->chip.ngpio = IDI48_NGPIO; + idi48gpio->chip.names = idi48_names; idi48gpio->chip.get_direction = idi_48_gpio_get_direction; idi48gpio->chip.direction_input = idi_48_gpio_direction_input; idi48gpio->chip.get = idi_48_gpio_get; -- cgit v1.2.3 From e0af4b5e248bcfbdb056691c9b12ee697b07c213 Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Mon, 30 Jan 2017 13:33:21 -0500 Subject: gpio: 104-idio-16: Add support for GPIO names This patch sets the gpio_chip names option with an array of GPIO line names that match the manual documentation for the ACCES 104-IDIO-16. This should make it easier for users to identify which GPIO line corresponds to a respective GPIO pin on the device. Signed-off-by: William Breathitt Gray Signed-off-by: Linus Walleij --- drivers/gpio/gpio-104-idio-16.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-104-idio-16.c b/drivers/gpio/gpio-104-idio-16.c index 67068b61b90b..7053cf736648 100644 --- a/drivers/gpio/gpio-104-idio-16.c +++ b/drivers/gpio/gpio-104-idio-16.c @@ -210,6 +210,14 @@ static irqreturn_t idio_16_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } +#define IDIO_16_NGPIO 32 +static const char *idio_16_names[IDIO_16_NGPIO] = { + "OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7", + "OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15", + "IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7", + "IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15" +}; + static int idio_16_probe(struct device *dev, unsigned int id) { struct idio_16_gpio *idio16gpio; @@ -230,7 +238,8 @@ static int idio_16_probe(struct device *dev, unsigned int id) idio16gpio->chip.parent = dev; idio16gpio->chip.owner = THIS_MODULE; idio16gpio->chip.base = -1; - idio16gpio->chip.ngpio = 32; + idio16gpio->chip.ngpio = IDIO_16_NGPIO; + idio16gpio->chip.names = idio_16_names; idio16gpio->chip.get_direction = idio_16_gpio_get_direction; idio16gpio->chip.direction_input = idio_16_gpio_direction_input; idio16gpio->chip.direction_output = idio_16_gpio_direction_output; -- cgit v1.2.3 From 210b4bde5fc9974e60a912f9a17c014c7cbf5b75 Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Mon, 30 Jan 2017 13:33:37 -0500 Subject: gpio: gpio-mm: Add support for GPIO names This patch sets the gpio_chip names option with an array of GPIO line names that match the manual documentation for the Diamond Systems GPIO-MM. This should make it easier for users to identify which GPIO line corresponds to a respective GPIO pin on the device. Signed-off-by: William Breathitt Gray Signed-off-by: Linus Walleij --- drivers/gpio/gpio-gpio-mm.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-gpio-mm.c b/drivers/gpio/gpio-gpio-mm.c index 60017425b49f..fa4baa2543db 100644 --- a/drivers/gpio/gpio-gpio-mm.c +++ b/drivers/gpio/gpio-gpio-mm.c @@ -230,6 +230,18 @@ static void gpiomm_gpio_set_multiple(struct gpio_chip *chip, } } +#define GPIOMM_NGPIO 48 +static const char *gpiomm_names[GPIOMM_NGPIO] = { + "Port 1A0", "Port 1A1", "Port 1A2", "Port 1A3", "Port 1A4", "Port 1A5", + "Port 1A6", "Port 1A7", "Port 1B0", "Port 1B1", "Port 1B2", "Port 1B3", + "Port 1B4", "Port 1B5", "Port 1B6", "Port 1B7", "Port 1C0", "Port 1C1", + "Port 1C2", "Port 1C3", "Port 1C4", "Port 1C5", "Port 1C6", "Port 1C7", + "Port 2A0", "Port 2A1", "Port 2A2", "Port 2A3", "Port 2A4", "Port 2A5", + "Port 2A6", "Port 2A7", "Port 2B0", "Port 2B1", "Port 2B2", "Port 2B3", + "Port 2B4", "Port 2B5", "Port 2B6", "Port 2B7", "Port 2C0", "Port 2C1", + "Port 2C2", "Port 2C3", "Port 2C4", "Port 2C5", "Port 2C6", "Port 2C7", +}; + static int gpiomm_probe(struct device *dev, unsigned int id) { struct gpiomm_gpio *gpiommgpio; @@ -250,7 +262,8 @@ static int gpiomm_probe(struct device *dev, unsigned int id) gpiommgpio->chip.parent = dev; gpiommgpio->chip.owner = THIS_MODULE; gpiommgpio->chip.base = -1; - gpiommgpio->chip.ngpio = 48; + gpiommgpio->chip.ngpio = GPIOMM_NGPIO; + gpiommgpio->chip.names = gpiomm_names; gpiommgpio->chip.get_direction = gpiomm_gpio_get_direction; gpiommgpio->chip.direction_input = gpiomm_gpio_direction_input; gpiommgpio->chip.direction_output = gpiomm_gpio_direction_output; -- cgit v1.2.3 From 5238f60feb408efbb5ad212d9b5b98a44d97af3a Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Mon, 30 Jan 2017 13:33:47 -0500 Subject: gpio: ws16c48: Add support for GPIO names This patch sets the gpio_chip names option with an array of GPIO line names that match the manual documentation for the WinSystems WS16C48. This should make it easier for users to identify which GPIO line corresponds to a respective GPIO pin on the device. Signed-off-by: William Breathitt Gray Signed-off-by: Linus Walleij --- drivers/gpio/gpio-ws16c48.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-ws16c48.c b/drivers/gpio/gpio-ws16c48.c index 48b35589b7d6..901b5ccb032d 100644 --- a/drivers/gpio/gpio-ws16c48.c +++ b/drivers/gpio/gpio-ws16c48.c @@ -341,6 +341,22 @@ static irqreturn_t ws16c48_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } +#define WS16C48_NGPIO 48 +static const char *ws16c48_names[WS16C48_NGPIO] = { + "Port 0 Bit 0", "Port 0 Bit 1", "Port 0 Bit 2", "Port 0 Bit 3", + "Port 0 Bit 4", "Port 0 Bit 5", "Port 0 Bit 6", "Port 0 Bit 7", + "Port 1 Bit 0", "Port 1 Bit 1", "Port 1 Bit 2", "Port 1 Bit 3", + "Port 1 Bit 4", "Port 1 Bit 5", "Port 1 Bit 6", "Port 1 Bit 7", + "Port 2 Bit 0", "Port 2 Bit 1", "Port 2 Bit 2", "Port 2 Bit 3", + "Port 2 Bit 4", "Port 2 Bit 5", "Port 2 Bit 6", "Port 2 Bit 7", + "Port 3 Bit 0", "Port 3 Bit 1", "Port 3 Bit 2", "Port 3 Bit 3", + "Port 3 Bit 4", "Port 3 Bit 5", "Port 3 Bit 6", "Port 3 Bit 7", + "Port 4 Bit 0", "Port 4 Bit 1", "Port 4 Bit 2", "Port 4 Bit 3", + "Port 4 Bit 4", "Port 4 Bit 5", "Port 4 Bit 6", "Port 4 Bit 7", + "Port 5 Bit 0", "Port 5 Bit 1", "Port 5 Bit 2", "Port 5 Bit 3", + "Port 5 Bit 4", "Port 5 Bit 5", "Port 5 Bit 6", "Port 5 Bit 7" +}; + static int ws16c48_probe(struct device *dev, unsigned int id) { struct ws16c48_gpio *ws16c48gpio; @@ -361,7 +377,8 @@ static int ws16c48_probe(struct device *dev, unsigned int id) ws16c48gpio->chip.parent = dev; ws16c48gpio->chip.owner = THIS_MODULE; ws16c48gpio->chip.base = -1; - ws16c48gpio->chip.ngpio = 48; + ws16c48gpio->chip.ngpio = WS16C48_NGPIO; + ws16c48gpio->chip.names = ws16c48_names; ws16c48gpio->chip.get_direction = ws16c48_gpio_get_direction; ws16c48gpio->chip.direction_input = ws16c48_gpio_direction_input; ws16c48gpio->chip.direction_output = ws16c48_gpio_direction_output; -- cgit v1.2.3 From e8e1a5b5679b1ae1ff03a3883b011b84e7226171 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 2 Feb 2017 18:13:06 +0800 Subject: gpio: mcp23s08: Select REGMAP/REGMAP_I2C to fix build error This driver now using devm_regmap_init/devm_regmap_init_i2c, so it needs to select REGMAP/REGMAP_I2C accordingly. Fixes: ("3d84fdb3f0b5 gpio: mcp23s08: use regmap") Signed-off-by: Axel Lin Acked-By: Sebastian Reichel Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 2d7739222cdb..28e621900a14 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1213,6 +1213,8 @@ config GPIO_MCP23S08 tristate "Microchip MCP23xxx I/O expander" depends on OF_GPIO select GPIOLIB_IRQCHIP + select REGMAP_I2C if I2C + select REGMAP if SPI_MASTER help SPI/I2C driver for Microchip MCP23S08/MCP23S17/MCP23008/MCP23017 I/O expanders. -- cgit v1.2.3 From 4b0947974e593d52aace18ca5c7e2746fdebae60 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Thu, 2 Feb 2017 14:53:10 +0100 Subject: gpio: Rename devm_get_gpiod_from_child() Rename devm_get_gpiod_from_child() into devm_fwnode_get_gpiod_from_child() to reflect the fact that this function is operating on a fwnode object. Signed-off-by: Boris Brezillon Acked-by: Jacek Anaszewski Acked-by: Dmitry Torokhov Signed-off-by: Linus Walleij --- drivers/gpio/devres.c | 15 ++++++++------- drivers/input/keyboard/gpio_keys.c | 6 ++++-- drivers/input/keyboard/gpio_keys_polled.c | 8 ++++---- drivers/leds/leds-gpio.c | 5 +++-- drivers/video/fbdev/amba-clcd-nomadik.c | 16 ++++++++-------- include/linux/gpio/consumer.h | 20 ++++++++++---------- 6 files changed, 37 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c index 89969e887e5d..cd1bd1c3d2c0 100644 --- a/drivers/gpio/devres.c +++ b/drivers/gpio/devres.c @@ -123,7 +123,8 @@ struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev, EXPORT_SYMBOL(devm_gpiod_get_index); /** - * devm_get_gpiod_from_child - get a GPIO descriptor from a device's child node + * devm_fwnode_get_gpiod_from_child - get a GPIO descriptor from a device's + * child node * @dev: GPIO consumer * @con_id: function within the GPIO consumer * @child: firmware node (child of @dev) @@ -135,11 +136,11 @@ EXPORT_SYMBOL(devm_gpiod_get_index); * On successfull request the GPIO pin is configured in accordance with * provided @flags. */ -struct gpio_desc *devm_get_gpiod_from_child(struct device *dev, - const char *con_id, - struct fwnode_handle *child, - enum gpiod_flags flags, - const char *label) +struct gpio_desc *devm_fwnode_get_gpiod_from_child(struct device *dev, + const char *con_id, + struct fwnode_handle *child, + enum gpiod_flags flags, + const char *label) { static const char * const suffixes[] = { "gpios", "gpio" }; char prop_name[32]; /* 32 is max size of property name */ @@ -174,7 +175,7 @@ struct gpio_desc *devm_get_gpiod_from_child(struct device *dev, return desc; } -EXPORT_SYMBOL(devm_get_gpiod_from_child); +EXPORT_SYMBOL(devm_fwnode_get_gpiod_from_child); /** * devm_gpiod_get_index_optional - Resource-managed gpiod_get_index_optional() diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 2ec74d90ef78..13372782dffe 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -481,8 +481,10 @@ static int gpio_keys_setup_key(struct platform_device *pdev, spin_lock_init(&bdata->lock); if (child) { - bdata->gpiod = devm_get_gpiod_from_child(dev, NULL, child, - GPIOD_IN, desc); + bdata->gpiod = devm_fwnode_get_gpiod_from_child(dev, NULL, + child, + GPIOD_IN, + desc); if (IS_ERR(bdata->gpiod)) { error = PTR_ERR(bdata->gpiod); if (error == -ENOENT) { diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c index 5e35c565e341..b3c8d5e7985c 100644 --- a/drivers/input/keyboard/gpio_keys_polled.c +++ b/drivers/input/keyboard/gpio_keys_polled.c @@ -303,10 +303,10 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) return -EINVAL; } - bdata->gpiod = devm_get_gpiod_from_child(dev, NULL, - child, - GPIOD_IN, - button->desc); + bdata->gpiod = devm_fwnode_get_gpiod_from_child(dev, + NULL, child, + GPIOD_IN, + button->desc); if (IS_ERR(bdata->gpiod)) { error = PTR_ERR(bdata->gpiod); if (error != -EPROBE_DEFER) diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c index 6c4825d96693..066fc7590729 100644 --- a/drivers/leds/leds-gpio.c +++ b/drivers/leds/leds-gpio.c @@ -182,8 +182,9 @@ static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev) return ERR_PTR(-EINVAL); } - led.gpiod = devm_get_gpiod_from_child(dev, NULL, child, - GPIOD_ASIS, led.name); + led.gpiod = devm_fwnode_get_gpiod_from_child(dev, NULL, child, + GPIOD_ASIS, + led.name); if (IS_ERR(led.gpiod)) { fwnode_handle_put(child); return ERR_CAST(led.gpiod); diff --git a/drivers/video/fbdev/amba-clcd-nomadik.c b/drivers/video/fbdev/amba-clcd-nomadik.c index 9175ad9034e1..476ff3f4d466 100644 --- a/drivers/video/fbdev/amba-clcd-nomadik.c +++ b/drivers/video/fbdev/amba-clcd-nomadik.c @@ -185,26 +185,26 @@ static void tpg110_init(struct device *dev, struct device_node *np, dev_info(dev, "TPG110 display init\n"); /* This asserts the GRESTB signal, putting the display into reset */ - grestb = devm_get_gpiod_from_child(dev, "grestb", &np->fwnode, - GPIOD_OUT_HIGH, "grestb"); + grestb = devm_fwnode_get_gpiod_from_child(dev, "grestb", &np->fwnode, + GPIOD_OUT_HIGH, "grestb"); if (IS_ERR(grestb)) { dev_err(dev, "no GRESTB GPIO\n"); return; } - scen = devm_get_gpiod_from_child(dev, "scen", &np->fwnode, - GPIOD_OUT_LOW, "scen"); + scen = devm_fwnode_get_gpiod_from_child(dev, "scen", &np->fwnode, + GPIOD_OUT_LOW, "scen"); if (IS_ERR(scen)) { dev_err(dev, "no SCEN GPIO\n"); return; } - scl = devm_get_gpiod_from_child(dev, "scl", &np->fwnode, GPIOD_OUT_LOW, - "scl"); + scl = devm_fwnode_get_gpiod_from_child(dev, "scl", &np->fwnode, + GPIOD_OUT_LOW, "scl"); if (IS_ERR(scl)) { dev_err(dev, "no SCL GPIO\n"); return; } - sda = devm_get_gpiod_from_child(dev, "sda", &np->fwnode, GPIOD_OUT_LOW, - "sda"); + sda = devm_fwnode_get_gpiod_from_child(dev, "sda", &np->fwnode, + GPIOD_OUT_LOW, "sda"); if (IS_ERR(sda)) { dev_err(dev, "no SDA GPIO\n"); return; diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h index 80bad7ebde04..f32f49e96c0b 100644 --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h @@ -138,11 +138,11 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, const char *propname, enum gpiod_flags dflags, const char *label); -struct gpio_desc *devm_get_gpiod_from_child(struct device *dev, - const char *con_id, - struct fwnode_handle *child, - enum gpiod_flags flags, - const char *label); +struct gpio_desc *devm_fwnode_get_gpiod_from_child(struct device *dev, + const char *con_id, + struct fwnode_handle *child, + enum gpiod_flags flags, + const char *label); #else /* CONFIG_GPIOLIB */ static inline int gpiod_count(struct device *dev, const char *con_id) @@ -425,11 +425,11 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, } static inline -struct gpio_desc *devm_get_gpiod_from_child(struct device *dev, - const char *con_id, - struct fwnode_handle *child, - enum gpiod_flags flags, - const char *label) +struct gpio_desc *devm_fwnode_get_gpiod_from_child(struct device *dev, + const char *con_id, + struct fwnode_handle *child, + enum gpiod_flags flags, + const char *label) { return ERR_PTR(-ENOSYS); } -- cgit v1.2.3 From 537b94dafce29af6a3e923d216472cfc2f3659af Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Thu, 2 Feb 2017 14:53:11 +0100 Subject: gpio: Add the devm_fwnode_get_index_gpiod_from_child() helper devm_fwnode_get_gpiod_from_child() currently allows GPIO users to request a GPIO that is defined in a child fwnode instead of directly in the device fwnode. Extend this API by adding the devm_fwnode_get_index_gpiod_from_child() helper which does the same except you can also specify an index in case the 'xx-gpios' property describe several GPIOs. Signed-off-by: Boris Brezillon Signed-off-by: Linus Walleij --- drivers/gpio/devres.c | 20 +++++++++++--------- drivers/gpio/gpiolib.c | 9 +++++---- include/linux/gpio/consumer.h | 31 +++++++++++++++++++++---------- 3 files changed, 37 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c index cd1bd1c3d2c0..b2bbcaae6a1f 100644 --- a/drivers/gpio/devres.c +++ b/drivers/gpio/devres.c @@ -123,10 +123,11 @@ struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev, EXPORT_SYMBOL(devm_gpiod_get_index); /** - * devm_fwnode_get_gpiod_from_child - get a GPIO descriptor from a device's - * child node + * devm_fwnode_get_index_gpiod_from_child - get a GPIO descriptor from a + * device's child node * @dev: GPIO consumer * @con_id: function within the GPIO consumer + * @index: index of the GPIO to obtain in the consumer * @child: firmware node (child of @dev) * @flags: GPIO initialization flags * @@ -136,11 +137,11 @@ EXPORT_SYMBOL(devm_gpiod_get_index); * On successfull request the GPIO pin is configured in accordance with * provided @flags. */ -struct gpio_desc *devm_fwnode_get_gpiod_from_child(struct device *dev, - const char *con_id, - struct fwnode_handle *child, - enum gpiod_flags flags, - const char *label) +struct gpio_desc *devm_fwnode_get_index_gpiod_from_child(struct device *dev, + const char *con_id, int index, + struct fwnode_handle *child, + enum gpiod_flags flags, + const char *label) { static const char * const suffixes[] = { "gpios", "gpio" }; char prop_name[32]; /* 32 is max size of property name */ @@ -161,7 +162,8 @@ struct gpio_desc *devm_fwnode_get_gpiod_from_child(struct device *dev, snprintf(prop_name, sizeof(prop_name), "%s", suffixes[i]); - desc = fwnode_get_named_gpiod(child, prop_name, flags, label); + desc = fwnode_get_named_gpiod(child, prop_name, index, flags, + label); if (!IS_ERR(desc) || (PTR_ERR(desc) != -ENOENT)) break; } @@ -175,7 +177,7 @@ struct gpio_desc *devm_fwnode_get_gpiod_from_child(struct device *dev, return desc; } -EXPORT_SYMBOL(devm_fwnode_get_gpiod_from_child); +EXPORT_SYMBOL(devm_fwnode_get_index_gpiod_from_child); /** * devm_gpiod_get_index_optional - Resource-managed gpiod_get_index_optional() diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 20c6c51cbe10..5e5d48c3512c 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -3309,6 +3309,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_index); * fwnode_get_named_gpiod - obtain a GPIO from firmware node * @fwnode: handle of the firmware node * @propname: name of the firmware property representing the GPIO + * @index: index of the GPIO to obtain in the consumer * @dflags: GPIO initialization flags * * This function can be used for drivers that get their configuration @@ -3324,7 +3325,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_index); * In case of error an ERR_PTR() is returned. */ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, - const char *propname, + const char *propname, int index, enum gpiod_flags dflags, const char *label) { @@ -3340,8 +3341,8 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, if (is_of_node(fwnode)) { enum of_gpio_flags flags; - desc = of_get_named_gpiod_flags(to_of_node(fwnode), propname, 0, - &flags); + desc = of_get_named_gpiod_flags(to_of_node(fwnode), propname, + index, &flags); if (!IS_ERR(desc)) { active_low = flags & OF_GPIO_ACTIVE_LOW; single_ended = flags & OF_GPIO_SINGLE_ENDED; @@ -3349,7 +3350,7 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, } else if (is_acpi_node(fwnode)) { struct acpi_gpio_info info; - desc = acpi_node_get_gpiod(fwnode, propname, 0, &info); + desc = acpi_node_get_gpiod(fwnode, propname, index, &info); if (!IS_ERR(desc)) active_low = info.polarity == GPIO_ACTIVE_LOW; } diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h index f32f49e96c0b..ea9b01d40017 100644 --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h @@ -135,14 +135,14 @@ int desc_to_gpio(const struct gpio_desc *desc); struct fwnode_handle; struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, - const char *propname, + const char *propname, int index, enum gpiod_flags dflags, const char *label); -struct gpio_desc *devm_fwnode_get_gpiod_from_child(struct device *dev, - const char *con_id, - struct fwnode_handle *child, - enum gpiod_flags flags, - const char *label); +struct gpio_desc *devm_fwnode_get_index_gpiod_from_child(struct device *dev, + const char *con_id, int index, + struct fwnode_handle *child, + enum gpiod_flags flags, + const char *label); #else /* CONFIG_GPIOLIB */ static inline int gpiod_count(struct device *dev, const char *con_id) @@ -417,13 +417,25 @@ struct fwnode_handle; static inline struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, - const char *propname, + const char *propname, int index, enum gpiod_flags dflags, const char *label) { return ERR_PTR(-ENOSYS); } +static inline +struct gpio_desc *devm_fwnode_get_index_gpiod_from_child(struct device *dev, + const char *con_id, int index, + struct fwnode_handle *child, + enum gpiod_flags flags, + const char *label) +{ + return ERR_PTR(-ENOSYS); +} + +#endif /* CONFIG_GPIOLIB */ + static inline struct gpio_desc *devm_fwnode_get_gpiod_from_child(struct device *dev, const char *con_id, @@ -431,11 +443,10 @@ struct gpio_desc *devm_fwnode_get_gpiod_from_child(struct device *dev, enum gpiod_flags flags, const char *label) { - return ERR_PTR(-ENOSYS); + return devm_fwnode_get_index_gpiod_from_child(dev, con_id, 0, child, + flags, label); } -#endif /* CONFIG_GPIOLIB */ - #if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_GPIO_SYSFS) int gpiod_export(struct gpio_desc *desc, bool direction_may_change); -- cgit v1.2.3 From 02e74fc0401ae3f952423b04bea773195f2372ce Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Wed, 1 Feb 2017 15:37:55 -0500 Subject: gpio: Add GPIO support for the ACCES PCI-IDIO-16 The ACCES PCI-IDIO-16 device provides 32 lines of digital I/O (16 lines of optically-isolated digital inputs for AC and DC control signals, and 16 lines of solid state switch digital outputs). An interrupt is generated when any of the inputs change state (low to high or high to low). Input filter control is not supported by this driver, and input filters are deactivated by this driver. Signed-off-by: William Breathitt Gray Signed-off-by: Linus Walleij --- MAINTAINERS | 6 + drivers/gpio/Kconfig | 9 ++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-pci-idio-16.c | 348 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 364 insertions(+) create mode 100644 drivers/gpio/gpio-pci-idio-16.c (limited to 'drivers') diff --git a/MAINTAINERS b/MAINTAINERS index cfff2c9e3d94..25bf100967de 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -266,6 +266,12 @@ L: linux-iio@vger.kernel.org S: Maintained F: drivers/iio/counter/104-quad-8.c +ACCES PCI-IDIO-16 GPIO DRIVER +M: William Breathitt Gray +L: linux-gpio@vger.kernel.org +S: Maintained +F: drivers/gpio/gpio-pci-idio-16.c + ACENIC DRIVER M: Jes Sorensen L: linux-acenic@sunsite.dk diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 28e621900a14..d4cec615a71e 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1157,6 +1157,15 @@ config GPIO_PCH ML7223/ML7831 is companion chip for Intel Atom E6xx series. ML7223/ML7831 is completely compatible for Intel EG20T PCH. +config GPIO_PCI_IDIO_16 + tristate "ACCES PCI-IDIO-16 GPIO support" + select GPIOLIB_IRQCHIP + help + Enables GPIO support for the ACCES PCI-IDIO-16. An interrupt is + generated when any of the inputs change state (low to high or high to + low). Input filter control is not supported by this driver, and the + input filters are deactivated by this driver. + config GPIO_RDC321X tristate "RDC R-321x GPIO support" select MFD_CORE diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index ee8b0dcac623..becb96c724fe 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -92,6 +92,7 @@ obj-$(CONFIG_GPIO_OMAP) += gpio-omap.o obj-$(CONFIG_GPIO_PCA953X) += gpio-pca953x.o obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.o obj-$(CONFIG_GPIO_PCH) += gpio-pch.o +obj-$(CONFIG_GPIO_PCI_IDIO_16) += gpio-pci-idio-16.o obj-$(CONFIG_GPIO_PISOSR) += gpio-pisosr.o obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o diff --git a/drivers/gpio/gpio-pci-idio-16.c b/drivers/gpio/gpio-pci-idio-16.c new file mode 100644 index 000000000000..0220787240ce --- /dev/null +++ b/drivers/gpio/gpio-pci-idio-16.c @@ -0,0 +1,348 @@ +/* + * GPIO driver for the ACCES PCI-IDIO-16 + * Copyright (C) 2017 William Breathitt Gray + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * struct idio_16_gpio_reg - GPIO device registers structure + * @out0_7: Read: FET Drive Outputs 0-7 + * Write: FET Drive Outputs 0-7 + * @in0_7: Read: Isolated Inputs 0-7 + * Write: Clear Interrupt + * @irq_ctl: Read: Enable IRQ + * Write: Disable IRQ + * @filter_ctl: Read: Activate Input Filters 0-15 + * Write: Deactivate Input Filters 0-15 + * @out8_15: Read: FET Drive Outputs 8-15 + * Write: FET Drive Outputs 8-15 + * @in8_15: Read: Isolated Inputs 8-15 + * Write: Unused + * @irq_status: Read: Interrupt status + * Write: Unused + */ +struct idio_16_gpio_reg { + u8 out0_7; + u8 in0_7; + u8 irq_ctl; + u8 filter_ctl; + u8 out8_15; + u8 in8_15; + u8 irq_status; +}; + +/** + * struct idio_16_gpio - GPIO device private data structure + * @chip: instance of the gpio_chip + * @lock: synchronization lock to prevent I/O race conditions + * @reg: I/O address offset for the GPIO device registers + * @irq_mask: I/O bits affected by interrupts + */ +struct idio_16_gpio { + struct gpio_chip chip; + spinlock_t lock; + struct idio_16_gpio_reg __iomem *reg; + unsigned long irq_mask; +}; + +static int idio_16_gpio_get_direction(struct gpio_chip *chip, + unsigned int offset) +{ + if (offset > 15) + return 1; + + return 0; +} + +static int idio_16_gpio_direction_input(struct gpio_chip *chip, + unsigned int offset) +{ + return 0; +} + +static int idio_16_gpio_direction_output(struct gpio_chip *chip, + unsigned int offset, int value) +{ + chip->set(chip, offset, value); + return 0; +} + +static int idio_16_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); + unsigned long mask = BIT(offset); + + if (offset < 8) + return !!(ioread8(&idio16gpio->reg->out0_7) & mask); + + if (offset < 16) + return !!(ioread8(&idio16gpio->reg->out8_15) & (mask >> 8)); + + if (offset < 24) + return !!(ioread8(&idio16gpio->reg->in0_7) & (mask >> 16)); + + return !!(ioread8(&idio16gpio->reg->in8_15) & (mask >> 24)); +} + +static void idio_16_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) +{ + struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); + unsigned int mask = BIT(offset); + void __iomem *base; + unsigned long flags; + unsigned int out_state; + + if (offset > 15) + return; + + if (offset > 7) { + mask >>= 8; + base = &idio16gpio->reg->out8_15; + } else + base = &idio16gpio->reg->out0_7; + + spin_lock_irqsave(&idio16gpio->lock, flags); + + if (value) + out_state = ioread8(base) | mask; + else + out_state = ioread8(base) & ~mask; + + iowrite8(out_state, base); + + spin_unlock_irqrestore(&idio16gpio->lock, flags); +} + +static void idio_16_gpio_set_multiple(struct gpio_chip *chip, + unsigned long *mask, unsigned long *bits) +{ + struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); + unsigned long flags; + unsigned int out_state; + + spin_lock_irqsave(&idio16gpio->lock, flags); + + /* process output lines 0-7 */ + if (*mask & 0xFF) { + out_state = ioread8(&idio16gpio->reg->out0_7) & ~*mask; + out_state |= *mask & *bits; + iowrite8(out_state, &idio16gpio->reg->out0_7); + } + + /* shift to next output line word */ + *mask >>= 8; + + /* process output lines 8-15 */ + if (*mask & 0xFF) { + *bits >>= 8; + out_state = ioread8(&idio16gpio->reg->out8_15) & ~*mask; + out_state |= *mask & *bits; + iowrite8(out_state, &idio16gpio->reg->out8_15); + } + + spin_unlock_irqrestore(&idio16gpio->lock, flags); +} + +static void idio_16_irq_ack(struct irq_data *data) +{ +} + +static void idio_16_irq_mask(struct irq_data *data) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); + const unsigned long mask = BIT(irqd_to_hwirq(data)); + unsigned long flags; + + idio16gpio->irq_mask &= ~mask; + + if (!idio16gpio->irq_mask) { + spin_lock_irqsave(&idio16gpio->lock, flags); + + iowrite8(0, &idio16gpio->reg->irq_ctl); + + spin_unlock_irqrestore(&idio16gpio->lock, flags); + } +} + +static void idio_16_irq_unmask(struct irq_data *data) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); + const unsigned long mask = BIT(irqd_to_hwirq(data)); + const unsigned long prev_irq_mask = idio16gpio->irq_mask; + unsigned long flags; + + idio16gpio->irq_mask |= mask; + + if (!prev_irq_mask) { + spin_lock_irqsave(&idio16gpio->lock, flags); + + ioread8(&idio16gpio->reg->irq_ctl); + + spin_unlock_irqrestore(&idio16gpio->lock, flags); + } +} + +static int idio_16_irq_set_type(struct irq_data *data, unsigned int flow_type) +{ + /* The only valid irq types are none and both-edges */ + if (flow_type != IRQ_TYPE_NONE && + (flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH) + return -EINVAL; + + return 0; +} + +static struct irq_chip idio_16_irqchip = { + .name = "pci-idio-16", + .irq_ack = idio_16_irq_ack, + .irq_mask = idio_16_irq_mask, + .irq_unmask = idio_16_irq_unmask, + .irq_set_type = idio_16_irq_set_type +}; + +static irqreturn_t idio_16_irq_handler(int irq, void *dev_id) +{ + struct idio_16_gpio *const idio16gpio = dev_id; + unsigned int irq_status; + struct gpio_chip *const chip = &idio16gpio->chip; + int gpio; + + spin_lock(&idio16gpio->lock); + + irq_status = ioread8(&idio16gpio->reg->irq_status); + + spin_unlock(&idio16gpio->lock); + + /* Make sure our device generated IRQ */ + if (!(irq_status & 0x3) || !(irq_status & 0x4)) + return IRQ_NONE; + + for_each_set_bit(gpio, &idio16gpio->irq_mask, chip->ngpio) + generic_handle_irq(irq_find_mapping(chip->irqdomain, gpio)); + + spin_lock(&idio16gpio->lock); + + /* Clear interrupt */ + iowrite8(0, &idio16gpio->reg->in0_7); + + spin_unlock(&idio16gpio->lock); + + return IRQ_HANDLED; +} + +#define IDIO_16_NGPIO 32 +static const char *idio_16_names[IDIO_16_NGPIO] = { + "OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7", + "OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15", + "IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7", + "IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15" +}; + +static int idio_16_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct device *const dev = &pdev->dev; + struct idio_16_gpio *idio16gpio; + int err; + const char *const name = pci_name(pdev); + + idio16gpio = devm_kzalloc(dev, sizeof(*idio16gpio), GFP_KERNEL); + if (!idio16gpio) + return -ENOMEM; + + err = pcim_enable_device(pdev); + if (err) { + dev_err(dev, "Failed to enable PCI device (%d)\n", err); + return err; + } + + err = pcim_iomap_regions(pdev, 0x1, name); + if (err) { + dev_err(dev, "Unable to map PCI I/O addresses (%d)\n", err); + return err; + } + + idio16gpio->reg = pcim_iomap_table(pdev)[0]; + + /* Deactivate input filters */ + iowrite8(0, &idio16gpio->reg->filter_ctl); + + idio16gpio->chip.label = name; + idio16gpio->chip.parent = dev; + idio16gpio->chip.owner = THIS_MODULE; + idio16gpio->chip.base = -1; + idio16gpio->chip.ngpio = IDIO_16_NGPIO; + idio16gpio->chip.names = idio_16_names; + idio16gpio->chip.get_direction = idio_16_gpio_get_direction; + idio16gpio->chip.direction_input = idio_16_gpio_direction_input; + idio16gpio->chip.direction_output = idio_16_gpio_direction_output; + idio16gpio->chip.get = idio_16_gpio_get; + idio16gpio->chip.set = idio_16_gpio_set; + idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple; + + spin_lock_init(&idio16gpio->lock); + + err = devm_gpiochip_add_data(dev, &idio16gpio->chip, idio16gpio); + if (err) { + dev_err(dev, "GPIO registering failed (%d)\n", err); + return err; + } + + /* Disable IRQ by default and clear any pending interrupt */ + iowrite8(0, &idio16gpio->reg->irq_ctl); + iowrite8(0, &idio16gpio->reg->in0_7); + + err = gpiochip_irqchip_add(&idio16gpio->chip, &idio_16_irqchip, 0, + handle_edge_irq, IRQ_TYPE_NONE); + if (err) { + dev_err(dev, "Could not add irqchip (%d)\n", err); + return err; + } + + err = devm_request_irq(dev, pdev->irq, idio_16_irq_handler, IRQF_SHARED, + name, idio16gpio); + if (err) { + dev_err(dev, "IRQ handler registering failed (%d)\n", err); + return err; + } + + return 0; +} + +static const struct pci_device_id idio_16_pci_dev_id[] = { + { PCI_DEVICE(0x494F, 0x0F00) }, { 0 } +}; +MODULE_DEVICE_TABLE(pci, idio_16_pci_dev_id); + +static struct pci_driver idio_16_driver = { + .name = "pci-idio-16", + .id_table = idio_16_pci_dev_id, + .probe = idio_16_probe +}; + +module_pci_driver(idio_16_driver); + +MODULE_AUTHOR("William Breathitt Gray "); +MODULE_DESCRIPTION("ACCES PCI-IDIO-16 GPIO driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From ca4091607847d25778db1b701a6e14dcc87a55ff Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 6 Feb 2017 13:10:35 +0100 Subject: gpio: mockup: readability tweaks The following patch tries to improve the readability of the mockup driver. The driver is called gpio-mockup, so add the same prefix to all functions and structures. Add some newlines and use a temporary pointer in gpio_mockup_add(). Drop the name of the direction enum and rename the enum values to better reflect their purpose. Signed-off-by: Bartosz Golaszewski Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mockup.c | 123 ++++++++++++++++++++++++--------------------- 1 file changed, 66 insertions(+), 57 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c index 82a9efd021db..5f6ed4b24b75 100644 --- a/drivers/gpio/gpio-mockup.c +++ b/drivers/gpio/gpio-mockup.c @@ -16,12 +16,12 @@ #include #include -#define GPIO_NAME "gpio-mockup" -#define MAX_GC 10 +#define GPIO_MOCKUP_NAME "gpio-mockup" +#define GPIO_MOCKUP_MAX_GC 10 -enum direction { - OUT, - IN +enum { + DIR_IN = 0, + DIR_OUT, }; /* @@ -29,98 +29,104 @@ enum direction { * @dir: Configures direction of gpio as "in" or "out", 0=in, 1=out * @value: Configures status of the gpio as 0(low) or 1(high) */ -struct gpio_pin_status { - enum direction dir; +struct gpio_mockup_line_status { + int dir; bool value; }; -struct mockup_gpio_controller { +struct gpio_mockup_chip { struct gpio_chip gc; - struct gpio_pin_status *stats; + struct gpio_mockup_line_status *lines; }; -static int gpio_mockup_ranges[MAX_GC << 1]; +static int gpio_mockup_ranges[GPIO_MOCKUP_MAX_GC << 1]; static int gpio_mockup_params_nr; module_param_array(gpio_mockup_ranges, int, &gpio_mockup_params_nr, 0400); -static const char pins_name_start = 'A'; +static const char gpio_mockup_name_start = 'A'; -static int mockup_gpio_get(struct gpio_chip *gc, unsigned int offset) +static int gpio_mockup_get(struct gpio_chip *gc, unsigned int offset) { - struct mockup_gpio_controller *cntr = gpiochip_get_data(gc); + struct gpio_mockup_chip *chip = gpiochip_get_data(gc); - return cntr->stats[offset].value; + return chip->lines[offset].value; } -static void mockup_gpio_set(struct gpio_chip *gc, unsigned int offset, +static void gpio_mockup_set(struct gpio_chip *gc, unsigned int offset, int value) { - struct mockup_gpio_controller *cntr = gpiochip_get_data(gc); + struct gpio_mockup_chip *chip = gpiochip_get_data(gc); - cntr->stats[offset].value = !!value; + chip->lines[offset].value = !!value; } -static int mockup_gpio_dirout(struct gpio_chip *gc, unsigned int offset, +static int gpio_mockup_dirout(struct gpio_chip *gc, unsigned int offset, int value) { - struct mockup_gpio_controller *cntr = gpiochip_get_data(gc); + struct gpio_mockup_chip *chip = gpiochip_get_data(gc); + + gpio_mockup_set(gc, offset, value); + chip->lines[offset].dir = DIR_OUT; - mockup_gpio_set(gc, offset, value); - cntr->stats[offset].dir = OUT; return 0; } -static int mockup_gpio_dirin(struct gpio_chip *gc, unsigned int offset) +static int gpio_mockup_dirin(struct gpio_chip *gc, unsigned int offset) { - struct mockup_gpio_controller *cntr = gpiochip_get_data(gc); + struct gpio_mockup_chip *chip = gpiochip_get_data(gc); + + chip->lines[offset].dir = DIR_IN; - cntr->stats[offset].dir = IN; return 0; } -static int mockup_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) +static int gpio_mockup_get_direction(struct gpio_chip *gc, unsigned int offset) { - struct mockup_gpio_controller *cntr = gpiochip_get_data(gc); + struct gpio_mockup_chip *chip = gpiochip_get_data(gc); - return cntr->stats[offset].dir; + return chip->lines[offset].dir; } -static int mockup_gpio_add(struct device *dev, - struct mockup_gpio_controller *cntr, +static int gpio_mockup_add(struct device *dev, + struct gpio_mockup_chip *chip, const char *name, int base, int ngpio) { + struct gpio_chip *gc = &chip->gc; int ret; - cntr->gc.base = base; - cntr->gc.ngpio = ngpio; - cntr->gc.label = name; - cntr->gc.owner = THIS_MODULE; - cntr->gc.parent = dev; - cntr->gc.get = mockup_gpio_get; - cntr->gc.set = mockup_gpio_set; - cntr->gc.direction_output = mockup_gpio_dirout; - cntr->gc.direction_input = mockup_gpio_dirin; - cntr->gc.get_direction = mockup_gpio_get_direction; - cntr->stats = devm_kzalloc(dev, sizeof(*cntr->stats) * cntr->gc.ngpio, + gc->base = base; + gc->ngpio = ngpio; + gc->label = name; + gc->owner = THIS_MODULE; + gc->parent = dev; + gc->get = gpio_mockup_get; + gc->set = gpio_mockup_set; + gc->direction_output = gpio_mockup_dirout; + gc->direction_input = gpio_mockup_dirin; + gc->get_direction = gpio_mockup_get_direction; + + chip->lines = devm_kzalloc(dev, sizeof(*chip->lines) * gc->ngpio, GFP_KERNEL); - if (!cntr->stats) { + if (!chip->lines) { ret = -ENOMEM; goto err; } - ret = devm_gpiochip_add_data(dev, &cntr->gc, cntr); + + ret = devm_gpiochip_add_data(dev, &chip->gc, chip); if (ret) goto err; dev_info(dev, "gpio<%d..%d> add successful!", base, base + ngpio); return 0; + err: dev_err(dev, "gpio<%d..%d> add failed!", base, base + ngpio); return ret; } -static int mockup_gpio_probe(struct platform_device *pdev) +static int gpio_mockup_probe(struct platform_device *pdev) { - struct mockup_gpio_controller *cntr; + struct gpio_mockup_chip *chips; struct device *dev = &pdev->dev; int ret, i, base, ngpio; char *chip_name; @@ -128,15 +134,17 @@ static int mockup_gpio_probe(struct platform_device *pdev) if (gpio_mockup_params_nr < 2) return -EINVAL; - cntr = devm_kzalloc(dev, sizeof(*cntr) * (gpio_mockup_params_nr >> 1), - GFP_KERNEL); - if (!cntr) + chips = devm_kzalloc(dev, + sizeof(*chips) * (gpio_mockup_params_nr >> 1), + GFP_KERNEL); + if (!chips) return -ENOMEM; - platform_set_drvdata(pdev, cntr); + platform_set_drvdata(pdev, chips); for (i = 0; i < gpio_mockup_params_nr >> 1; i++) { base = gpio_mockup_ranges[i * 2]; + if (base == -1) ngpio = gpio_mockup_ranges[i * 2 + 1]; else @@ -144,16 +152,17 @@ static int mockup_gpio_probe(struct platform_device *pdev) if (ngpio >= 0) { chip_name = devm_kasprintf(dev, GFP_KERNEL, - "%s-%c", GPIO_NAME, - pins_name_start + i); + "%s-%c", GPIO_MOCKUP_NAME, + gpio_mockup_name_start + i); if (!chip_name) return -ENOMEM; - ret = mockup_gpio_add(dev, &cntr[i], + ret = gpio_mockup_add(dev, &chips[i], chip_name, base, ngpio); } else { ret = -1; } + if (ret) { if (base < 0) dev_err(dev, "gpio<%d..%d> add failed\n", @@ -169,11 +178,11 @@ static int mockup_gpio_probe(struct platform_device *pdev) return 0; } -static struct platform_driver mockup_gpio_driver = { +static struct platform_driver gpio_mockup_driver = { .driver = { - .name = GPIO_NAME, + .name = GPIO_MOCKUP_NAME, }, - .probe = mockup_gpio_probe, + .probe = gpio_mockup_probe, }; static struct platform_device *pdev; @@ -181,7 +190,7 @@ static int __init mock_device_init(void) { int err; - pdev = platform_device_alloc(GPIO_NAME, -1); + pdev = platform_device_alloc(GPIO_MOCKUP_NAME, -1); if (!pdev) return -ENOMEM; @@ -191,7 +200,7 @@ static int __init mock_device_init(void) return err; } - err = platform_driver_register(&mockup_gpio_driver); + err = platform_driver_register(&gpio_mockup_driver); if (err) { platform_device_unregister(pdev); return err; @@ -202,7 +211,7 @@ static int __init mock_device_init(void) static void __exit mock_device_exit(void) { - platform_driver_unregister(&mockup_gpio_driver); + platform_driver_unregister(&gpio_mockup_driver); platform_device_unregister(pdev); } -- cgit v1.2.3 From e4ba07bf8d1481e440d1f49652c96567f9560fdc Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 6 Feb 2017 13:10:36 +0100 Subject: gpio: mockup: code shrink Moving a couple of lines around allows us to shrink the code a bit while keeping the same functionality. Signed-off-by: Bartosz Golaszewski Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mockup.c | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c index 5f6ed4b24b75..d42560113c1b 100644 --- a/drivers/gpio/gpio-mockup.c +++ b/drivers/gpio/gpio-mockup.c @@ -92,7 +92,6 @@ static int gpio_mockup_add(struct device *dev, const char *name, int base, int ngpio) { struct gpio_chip *gc = &chip->gc; - int ret; gc->base = base; gc->ngpio = ngpio; @@ -107,21 +106,10 @@ static int gpio_mockup_add(struct device *dev, chip->lines = devm_kzalloc(dev, sizeof(*chip->lines) * gc->ngpio, GFP_KERNEL); - if (!chip->lines) { - ret = -ENOMEM; - goto err; - } - - ret = devm_gpiochip_add_data(dev, &chip->gc, chip); - if (ret) - goto err; - - dev_info(dev, "gpio<%d..%d> add successful!", base, base + ngpio); - return 0; + if (!chip->lines) + return -ENOMEM; -err: - dev_err(dev, "gpio<%d..%d> add failed!", base, base + ngpio); - return ret; + return devm_gpiochip_add_data(dev, &chip->gc, chip); } static int gpio_mockup_probe(struct platform_device *pdev) @@ -164,15 +152,14 @@ static int gpio_mockup_probe(struct platform_device *pdev) } if (ret) { - if (base < 0) - dev_err(dev, "gpio<%d..%d> add failed\n", - base, ngpio); - else - dev_err(dev, "gpio<%d..%d> add failed\n", - base, base + ngpio); + dev_err(dev, "gpio<%d..%d> add failed\n", + base, base < 0 ? ngpio : base + ngpio); return ret; } + + dev_info(dev, "gpio<%d..%d> add successful!", + base, base + ngpio); } return 0; -- cgit v1.2.3 From 8a68ea00a62e7ec33e9e4e7f3d9c2a845943c58d Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 6 Feb 2017 13:10:37 +0100 Subject: gpio: mockup: implement naming the lines In order to allow testing line lookup by name from user space, add a new boolean parameter that indicates whether we want the lines to be named. The name is created by concatenating the chip name and the line offset value. Signed-off-by: Bartosz Golaszewski Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mockup.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c index d42560113c1b..0ce9acc3550e 100644 --- a/drivers/gpio/gpio-mockup.c +++ b/drivers/gpio/gpio-mockup.c @@ -15,6 +15,7 @@ #include #include #include +#include #define GPIO_MOCKUP_NAME "gpio-mockup" #define GPIO_MOCKUP_MAX_GC 10 @@ -43,6 +44,10 @@ static int gpio_mockup_ranges[GPIO_MOCKUP_MAX_GC << 1]; static int gpio_mockup_params_nr; module_param_array(gpio_mockup_ranges, int, &gpio_mockup_params_nr, 0400); +static bool gpio_mockup_named_lines; +module_param_named(gpio_mockup_named_lines, + gpio_mockup_named_lines, bool, 0400); + static const char gpio_mockup_name_start = 'A'; static int gpio_mockup_get(struct gpio_chip *gc, unsigned int offset) @@ -87,11 +92,35 @@ static int gpio_mockup_get_direction(struct gpio_chip *gc, unsigned int offset) return chip->lines[offset].dir; } +static int gpio_mockup_name_lines(struct device *dev, + struct gpio_mockup_chip *chip) +{ + struct gpio_chip *gc = &chip->gc; + char **names; + int i; + + names = devm_kzalloc(dev, sizeof(char *) * gc->ngpio, GFP_KERNEL); + if (!names) + return -ENOMEM; + + for (i = 0; i < gc->ngpio; i++) { + names[i] = devm_kasprintf(dev, GFP_KERNEL, + "%s-%d", gc->label, i); + if (!names[i]) + return -ENOMEM; + } + + gc->names = (const char *const *)names; + + return 0; +} + static int gpio_mockup_add(struct device *dev, struct gpio_mockup_chip *chip, const char *name, int base, int ngpio) { struct gpio_chip *gc = &chip->gc; + int ret; gc->base = base; gc->ngpio = ngpio; @@ -109,6 +138,12 @@ static int gpio_mockup_add(struct device *dev, if (!chip->lines) return -ENOMEM; + if (gpio_mockup_named_lines) { + ret = gpio_mockup_name_lines(dev, chip); + if (ret) + return ret; + } + return devm_gpiochip_add_data(dev, &chip->gc, chip); } -- cgit v1.2.3 From e2ff7408953f6fe8a341b31ed2d848f73606bbf4 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 6 Feb 2017 15:11:07 +0100 Subject: gpio: mockup: add a dummy irqchip Setup a dummy irqchip that will allow us to inject line events for testing purposes. Signed-off-by: Bartosz Golaszewski Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 2 ++ drivers/gpio/gpio-mockup.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d4cec615a71e..05043071fc98 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -298,6 +298,8 @@ config GPIO_MOCKUP tristate "GPIO Testing Driver" depends on GPIOLIB && SYSFS select GPIO_SYSFS + select GPIOLIB_IRQCHIP + select IRQ_WORK help This enables GPIO Testing driver, which provides a way to test GPIO subsystem through sysfs(or char device) and debugfs. GPIO_SYSFS diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c index 0ce9acc3550e..03beadb20dee 100644 --- a/drivers/gpio/gpio-mockup.c +++ b/drivers/gpio/gpio-mockup.c @@ -16,6 +16,9 @@ #include #include #include +#include +#include +#include #define GPIO_MOCKUP_NAME "gpio-mockup" #define GPIO_MOCKUP_MAX_GC 10 @@ -35,9 +38,15 @@ struct gpio_mockup_line_status { bool value; }; +struct gpio_mockup_irq_context { + struct irq_work work; + int irq; +}; + struct gpio_mockup_chip { struct gpio_chip gc; struct gpio_mockup_line_status *lines; + struct gpio_mockup_irq_context irq_ctx; }; static int gpio_mockup_ranges[GPIO_MOCKUP_MAX_GC << 1]; @@ -115,6 +124,57 @@ static int gpio_mockup_name_lines(struct device *dev, return 0; } +static int gpio_mockup_to_irq(struct gpio_chip *chip, unsigned int offset) +{ + return chip->irq_base + offset; +} + +/* + * While we should generally support irqmask and irqunmask, this driver is + * for testing purposes only so we don't care. + */ +static void gpio_mockup_irqmask(struct irq_data *d) { } +static void gpio_mockup_irqunmask(struct irq_data *d) { } + +static struct irq_chip gpio_mockup_irqchip = { + .name = GPIO_MOCKUP_NAME, + .irq_mask = gpio_mockup_irqmask, + .irq_unmask = gpio_mockup_irqunmask, +}; + +static void gpio_mockup_handle_irq(struct irq_work *work) +{ + struct gpio_mockup_irq_context *irq_ctx; + + irq_ctx = container_of(work, struct gpio_mockup_irq_context, work); + handle_simple_irq(irq_to_desc(irq_ctx->irq)); +} + +static int gpio_mockup_irqchip_setup(struct device *dev, + struct gpio_mockup_chip *chip) +{ + struct gpio_chip *gc = &chip->gc; + int irq_base, i; + + irq_base = irq_alloc_descs(-1, 0, gc->ngpio, 0); + if (irq_base < 0) + return irq_base; + + gc->irq_base = irq_base; + gc->irqchip = &gpio_mockup_irqchip; + + for (i = 0; i < gc->ngpio; i++) { + irq_set_chip(irq_base + i, gc->irqchip); + irq_set_handler(irq_base + i, &handle_simple_irq); + irq_modify_status(irq_base + i, + IRQ_NOREQUEST | IRQ_NOAUTOEN, IRQ_NOPROBE); + } + + init_irq_work(&chip->irq_ctx.work, gpio_mockup_handle_irq); + + return 0; +} + static int gpio_mockup_add(struct device *dev, struct gpio_mockup_chip *chip, const char *name, int base, int ngpio) @@ -132,6 +192,7 @@ static int gpio_mockup_add(struct device *dev, gc->direction_output = gpio_mockup_dirout; gc->direction_input = gpio_mockup_dirin; gc->get_direction = gpio_mockup_get_direction; + gc->to_irq = gpio_mockup_to_irq; chip->lines = devm_kzalloc(dev, sizeof(*chip->lines) * gc->ngpio, GFP_KERNEL); @@ -144,6 +205,10 @@ static int gpio_mockup_add(struct device *dev, return ret; } + ret = gpio_mockup_irqchip_setup(dev, chip); + if (ret) + return ret; + return devm_gpiochip_add_data(dev, &chip->gc, chip); } @@ -200,11 +265,25 @@ static int gpio_mockup_probe(struct platform_device *pdev) return 0; } +static int gpio_mockup_remove(struct platform_device *pdev) +{ + struct gpio_mockup_chip *chips; + int i; + + chips = platform_get_drvdata(pdev); + + for (i = 0; i < gpio_mockup_params_nr >> 1; i++) + irq_free_descs(chips[i].gc.irq_base, chips[i].gc.ngpio); + + return 0; +} + static struct platform_driver gpio_mockup_driver = { .driver = { .name = GPIO_MOCKUP_NAME, }, .probe = gpio_mockup_probe, + .remove = gpio_mockup_remove, }; static struct platform_device *pdev; -- cgit v1.2.3 From 9202ba2397d1ded79078606c6921787b27a85e1a Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 6 Feb 2017 15:11:08 +0100 Subject: gpio: mockup: implement event injecting over debugfs Create a debugfs directory for every mockup chip and a single file for every line. Writing (0 or 1) to these files allows the user to inject line events (falling or rising edge respectively). Signed-off-by: Bartosz Golaszewski Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mockup.c | 116 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 115 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c index 03beadb20dee..06dac72cb69c 100644 --- a/drivers/gpio/gpio-mockup.c +++ b/drivers/gpio/gpio-mockup.c @@ -14,11 +14,16 @@ #include #include #include +#include #include #include #include #include #include +#include +#include + +#include "gpiolib.h" #define GPIO_MOCKUP_NAME "gpio-mockup" #define GPIO_MOCKUP_MAX_GC 10 @@ -47,6 +52,13 @@ struct gpio_mockup_chip { struct gpio_chip gc; struct gpio_mockup_line_status *lines; struct gpio_mockup_irq_context irq_ctx; + struct dentry *dbg_dir; +}; + +struct gpio_mockup_dbgfs_private { + struct gpio_mockup_chip *chip; + struct gpio_desc *desc; + int offset; }; static int gpio_mockup_ranges[GPIO_MOCKUP_MAX_GC << 1]; @@ -58,6 +70,7 @@ module_param_named(gpio_mockup_named_lines, gpio_mockup_named_lines, bool, 0400); static const char gpio_mockup_name_start = 'A'; +static struct dentry *gpio_mockup_dbg_dir; static int gpio_mockup_get(struct gpio_chip *gc, unsigned int offset) { @@ -175,6 +188,94 @@ static int gpio_mockup_irqchip_setup(struct device *dev, return 0; } +static ssize_t gpio_mockup_event_write(struct file *file, + const char __user *usr_buf, + size_t size, loff_t *ppos) +{ + struct gpio_mockup_dbgfs_private *priv; + struct gpio_mockup_chip *chip; + struct seq_file *sfile; + struct gpio_desc *desc; + struct gpio_chip *gc; + int status, val; + char buf; + + sfile = file->private_data; + priv = sfile->private; + desc = priv->desc; + chip = priv->chip; + gc = &chip->gc; + + status = copy_from_user(&buf, usr_buf, 1); + if (status) + return status; + + if (buf == '0') + val = 0; + else if (buf == '1') + val = 1; + else + return -EINVAL; + + gpiod_set_value_cansleep(desc, val); + priv->chip->irq_ctx.irq = gc->irq_base + priv->offset; + irq_work_queue(&priv->chip->irq_ctx.work); + + return size; +} + +static int gpio_mockup_event_open(struct inode *inode, struct file *file) +{ + return single_open(file, NULL, inode->i_private); +} + +static const struct file_operations gpio_mockup_event_ops = { + .owner = THIS_MODULE, + .open = gpio_mockup_event_open, + .write = gpio_mockup_event_write, + .llseek = no_llseek, +}; + +static void gpio_mockup_debugfs_setup(struct device *dev, + struct gpio_mockup_chip *chip) +{ + struct gpio_mockup_dbgfs_private *priv; + struct dentry *evfile; + struct gpio_chip *gc; + char *name; + int i; + + gc = &chip->gc; + + chip->dbg_dir = debugfs_create_dir(gc->label, gpio_mockup_dbg_dir); + if (!chip->dbg_dir) + goto err; + + for (i = 0; i < gc->ngpio; i++) { + name = devm_kasprintf(dev, GFP_KERNEL, "%d", i); + if (!name) + goto err; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + goto err; + + priv->chip = chip; + priv->offset = i; + priv->desc = &gc->gpiodev->descs[i]; + + evfile = debugfs_create_file(name, 0200, chip->dbg_dir, priv, + &gpio_mockup_event_ops); + if (!evfile) + goto err; + } + + return; + +err: + dev_err(dev, "error creating debugfs directory\n"); +} + static int gpio_mockup_add(struct device *dev, struct gpio_mockup_chip *chip, const char *name, int base, int ngpio) @@ -209,7 +310,14 @@ static int gpio_mockup_add(struct device *dev, if (ret) return ret; - return devm_gpiochip_add_data(dev, &chip->gc, chip); + ret = devm_gpiochip_add_data(dev, &chip->gc, chip); + if (ret) + return ret; + + if (gpio_mockup_dbg_dir) + gpio_mockup_debugfs_setup(dev, chip); + + return 0; } static int gpio_mockup_probe(struct platform_device *pdev) @@ -291,6 +399,11 @@ static int __init mock_device_init(void) { int err; + gpio_mockup_dbg_dir = debugfs_create_dir("gpio-mockup-event", NULL); + if (!gpio_mockup_dbg_dir) + pr_err("%s: error creating debugfs directory\n", + GPIO_MOCKUP_NAME); + pdev = platform_device_alloc(GPIO_MOCKUP_NAME, -1); if (!pdev) return -ENOMEM; @@ -312,6 +425,7 @@ static int __init mock_device_init(void) static void __exit mock_device_exit(void) { + debugfs_remove_recursive(gpio_mockup_dbg_dir); platform_driver_unregister(&gpio_mockup_driver); platform_device_unregister(pdev); } -- cgit v1.2.3 From fd254a23cadaa4513f248a5f6b211ea63fdabe91 Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Tue, 7 Feb 2017 11:51:19 -0500 Subject: gpio: pci-idio-16: Fix PCI device ID code The ACCES PCI-IDIO-16 has a PCI device ID code of 0x0DC8. It is incorrect to use the PCI device ID code of the ACCES PCI-IIRO-8 (0x0F00). This patch fixes the said PCI device ID code mismatch. Fixes: 02e74fc0401a ("gpio: Add GPIO support for the ACCES PCI-IDIO-16") Signed-off-by: William Breathitt Gray Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pci-idio-16.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-pci-idio-16.c b/drivers/gpio/gpio-pci-idio-16.c index 0220787240ce..b10f3cf7044a 100644 --- a/drivers/gpio/gpio-pci-idio-16.c +++ b/drivers/gpio/gpio-pci-idio-16.c @@ -331,7 +331,7 @@ static int idio_16_probe(struct pci_dev *pdev, const struct pci_device_id *id) } static const struct pci_device_id idio_16_pci_dev_id[] = { - { PCI_DEVICE(0x494F, 0x0F00) }, { 0 } + { PCI_DEVICE(0x494F, 0x0DC8) }, { 0 } }; MODULE_DEVICE_TABLE(pci, idio_16_pci_dev_id); -- cgit v1.2.3 From deab2b0524aa1d7d081a1b17d283a76f11c45b1b Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Wed, 8 Feb 2017 08:32:46 -0500 Subject: gpio: pci-idio-16: Fix PCI BAR index The PCI BAR0 and BAR1 for the PCI-IDIO-16 hold information for the PLX 9052 bridge chip on the device. The PCI BAR2 holds the necessary base address for I/O control of the PCI-IDIO-16. This patch corrects the PCI BAR index mismatch for the PCI-IDIO-16 GPIO driver. Fixes: 02e74fc0401a ("gpio: Add GPIO support for the ACCES PCI-IDIO-16") Signed-off-by: William Breathitt Gray Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pci-idio-16.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-pci-idio-16.c b/drivers/gpio/gpio-pci-idio-16.c index b10f3cf7044a..269ab628634b 100644 --- a/drivers/gpio/gpio-pci-idio-16.c +++ b/drivers/gpio/gpio-pci-idio-16.c @@ -265,6 +265,7 @@ static int idio_16_probe(struct pci_dev *pdev, const struct pci_device_id *id) struct device *const dev = &pdev->dev; struct idio_16_gpio *idio16gpio; int err; + const size_t pci_bar_index = 2; const char *const name = pci_name(pdev); idio16gpio = devm_kzalloc(dev, sizeof(*idio16gpio), GFP_KERNEL); @@ -277,13 +278,13 @@ static int idio_16_probe(struct pci_dev *pdev, const struct pci_device_id *id) return err; } - err = pcim_iomap_regions(pdev, 0x1, name); + err = pcim_iomap_regions(pdev, BIT(pci_bar_index), name); if (err) { dev_err(dev, "Unable to map PCI I/O addresses (%d)\n", err); return err; } - idio16gpio->reg = pcim_iomap_table(pdev)[0]; + idio16gpio->reg = pcim_iomap_table(pdev)[pci_bar_index]; /* Deactivate input filters */ iowrite8(0, &idio16gpio->reg->filter_ctl); -- cgit v1.2.3