diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-08 18:00:35 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-08 18:00:35 -0700 |
commit | 06b49ea43c0cdd22625883e555e45e66ef29e201 (patch) | |
tree | 9c72c88541e2bec5a95354504708a066fd8e50aa | |
parent | 664fb23070ae66a023250a83870a5bae7cd0efeb (diff) | |
parent | bdc6e95e1273b5cef01590273c1a240c53ceeea0 (diff) |
Merge tag 'gpio-v3.17-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio
Pull GPIO update from Linus Walleij:
"This is the bulk of GPIO changes for the v3.17 development cycle, and
this time we got a lot of action going on and it will continue:
- The core GPIO library implementation has been split up in three
different files:
- gpiolib.c for the latest and greatest and shiny GPIO library code
using GPIO descriptors only
- gpiolib-legacy.c for the old integer number space API that we are
phasing out gradually
- gpiolib-sysfs.c for the sysfs interface that we are not entirely
happy with, but has to live on for ABI compatibility
- Add a flags argument to *gpiod_get* functions, with some
backward-compatibility macros to ease transitions. We should have
had the flags there from the beginning it seems, now we need to
clean up the mess. There is a plan on how to move forward here
devised by Alexandre Courbot and Mark Brown
- Split off a special <linux/gpio/machine.h> header for the board
gpio table registration, as per example from the regulator
subsystem
- Start to kill off the return value from gpiochip_remove() by
removing the __must_check attribute and removing all checks inside
the drivers/gpio directory. The rationale is: well what were we
supposed to do if there is an error code? Not much: print an error
message. And gpiolib already does that. So make this function
return void eventually
- Some cleanups of hairy gpiolib code, make some functions not to be
used outside the library private and make sure they are not
exported, remove gpiod_lock/unlock_as_irq() as the existing
function is for driver-internal use and fine as it is, delete
gpio_ensure_requested() as it is not meaningful anymore
- Support the GPIOF_ACTIVE_LOW flag from gpio_request_one() function
calls, which is logical since this is already supported when
referencing GPIOs from e.g. device trees
- Switch STMPE, intel-mid, lynxpoint and ACPI (!) to use the gpiolib
irqchip helpers cutting down on GPIO irqchip boilerplate a bit more
- New driver for the Zynq GPIO block
- The usual incremental improvements around a bunch of drivers
- Janitorial syntactic and semantic cleanups by Jingoo Han, and
Rickard Strandqvist especially"
* tag 'gpio-v3.17-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (37 commits)
MAINTAINERS: update GPIO include files
gpio: add missing includes in machine.h
gpio: add flags argument to gpiod_get*() functions
MAINTAINERS: Update Samsung pin control entry
gpio / ACPI: Move event handling registration to gpiolib irqchip helpers
gpio: lynxpoint: Convert to use gpiolib irqchip
gpio: split gpiod board registration into machine header
gpio: remove gpio_ensure_requested()
gpio: remove useless check in gpiolib_sysfs_init()
gpiolib: Export gpiochip_request_own_desc and gpiochip_free_own_desc
gpio: move gpio_ensure_requested() into legacy C file
gpio: remove gpiod_lock/unlock_as_irq()
gpio: make gpiochip_get_desc() gpiolib-private
gpio: simplify gpiochip_export()
gpio: remove export of private of_get_named_gpio_flags()
gpio: Add support for GPIOF_ACTIVE_LOW to gpio_request_one functions
gpio: zynq: Clear pending interrupt when enabling a IRQ
gpio: drop retval check enforcing from gpiochip_remove()
gpio: remove all usage of gpio_remove retval in driver/gpio
devicetree: Add Zynq GPIO devicetree bindings documentation
...
84 files changed, 2411 insertions, 1929 deletions
diff --git a/Documentation/devicetree/bindings/gpio/gpio-zynq.txt b/Documentation/devicetree/bindings/gpio/gpio-zynq.txt new file mode 100644 index 000000000000..986371a4be2c --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio-zynq.txt @@ -0,0 +1,26 @@ +Xilinx Zynq GPIO controller Device Tree Bindings +------------------------------------------- + +Required properties: +- #gpio-cells : Should be two + - First cell is the GPIO line number + - Second cell is used to specify optional + parameters (unused) +- compatible : Should be "xlnx,zynq-gpio-1.0" +- clocks : Clock specifier (see clock bindings for details) +- gpio-controller : Marks the device node as a GPIO controller. +- interrupts : Interrupt specifier (see interrupt bindings for + details) +- interrupt-parent : Must be core interrupt controller +- reg : Address and length of the register set for the device + +Example: + gpio@e000a000 { + #gpio-cells = <2>; + compatible = "xlnx,zynq-gpio-1.0"; + clocks = <&clkc 42>; + gpio-controller; + interrupt-parent = <&intc>; + interrupts = <0 20 4>; + reg = <0xe000a000 0x1000>; + }; diff --git a/Documentation/gpio/board.txt b/Documentation/gpio/board.txt index ba169faad5c6..4452786225b8 100644 --- a/Documentation/gpio/board.txt +++ b/Documentation/gpio/board.txt @@ -60,7 +60,7 @@ Platform Data Finally, GPIOs can be bound to devices and functions using platform data. Board files that desire to do so need to include the following header: - #include <linux/gpio/driver.h> + #include <linux/gpio/machine.h> GPIOs are mapped by the means of tables of lookups, containing instances of the gpiod_lookup structure. Two macros are defined to help declaring such mappings: diff --git a/Documentation/gpio/consumer.txt b/Documentation/gpio/consumer.txt index d8abfc31abbe..76546324e968 100644 --- a/Documentation/gpio/consumer.txt +++ b/Documentation/gpio/consumer.txt @@ -29,13 +29,24 @@ gpiod_get() functions. Like many other kernel subsystems, gpiod_get() takes the device that will use the GPIO and the function the requested GPIO is supposed to fulfill: - struct gpio_desc *gpiod_get(struct device *dev, const char *con_id) + struct gpio_desc *gpiod_get(struct device *dev, const char *con_id, + enum gpiod_flags flags) If a function is implemented by using several GPIOs together (e.g. a simple LED device that displays digits), an additional index argument can be specified: struct gpio_desc *gpiod_get_index(struct device *dev, - const char *con_id, unsigned int idx) + const char *con_id, unsigned int idx, + enum gpiod_flags flags) + +The flags parameter is used to optionally specify a direction and initial value +for the GPIO. Values can be: + +* GPIOD_ASIS or 0 to not initialize the GPIO at all. The direction must be set + later with one of the dedicated functions. +* GPIOD_IN to initialize the GPIO as input. +* GPIOD_OUT_LOW to initialize the GPIO as output with a value of 0. +* GPIOD_OUT_HIGH to initialize the GPIO as output with a value of 1. Both functions return either a valid GPIO descriptor, or an error code checkable with IS_ERR() (they will never return a NULL pointer). -ENOENT will be returned @@ -46,11 +57,13 @@ errors and an absence of GPIO for optional GPIO parameters. Device-managed variants of these functions are also defined: - struct gpio_desc *devm_gpiod_get(struct device *dev, const char *con_id) + struct gpio_desc *devm_gpiod_get(struct device *dev, const char *con_id, + enum gpiod_flags flags) struct gpio_desc *devm_gpiod_get_index(struct device *dev, const char *con_id, - unsigned int idx) + unsigned int idx, + enum gpiod_flags flags) A GPIO descriptor can be disposed of using the gpiod_put() function: @@ -67,8 +80,9 @@ Using GPIOs Setting Direction ----------------- -The first thing a driver must do with a GPIO is setting its direction. This is -done by invoking one of the gpiod_direction_*() functions: +The first thing a driver must do with a GPIO is setting its direction. If no +direction-setting flags have been given to gpiod_get*(), this is done by +invoking one of the gpiod_direction_*() functions: int gpiod_direction_input(struct gpio_desc *desc) int gpiod_direction_output(struct gpio_desc *desc, int value) diff --git a/Documentation/gpio/driver.txt b/Documentation/gpio/driver.txt index fa9a0a8b3734..18790c237977 100644 --- a/Documentation/gpio/driver.txt +++ b/Documentation/gpio/driver.txt @@ -157,13 +157,34 @@ Locking IRQ usage Input GPIOs can be used as IRQ signals. When this happens, a driver is requested to mark the GPIO as being used as an IRQ: - int gpiod_lock_as_irq(struct gpio_desc *desc) + int gpio_lock_as_irq(struct gpio_chip *chip, unsigned int offset) This will prevent the use of non-irq related GPIO APIs until the GPIO IRQ lock is released: - void gpiod_unlock_as_irq(struct gpio_desc *desc) + void gpio_unlock_as_irq(struct gpio_chip *chip, unsigned int offset) When implementing an irqchip inside a GPIO driver, these two functions should typically be called in the .startup() and .shutdown() callbacks from the irqchip. + + +Requesting self-owned GPIO pins +------------------------------- + +Sometimes it is useful to allow a GPIO chip driver to request its own GPIO +descriptors through the gpiolib API. Using gpio_request() for this purpose +does not help since it pins the module to the kernel forever (it calls +try_module_get()). A GPIO driver can use the following functions instead +to request and free descriptors without being pinned to the kernel forever. + + int gpiochip_request_own_desc(struct gpio_desc *desc, const char *label) + + void gpiochip_free_own_desc(struct gpio_desc *desc) + +Descriptors requested with gpiochip_request_own_desc() must be released with +gpiochip_free_own_desc(). + +These functions must be used with care since they do not affect module use +count. Do not use the functions to request gpio descriptors not owned by the +calling driver. diff --git a/MAINTAINERS b/MAINTAINERS index 3bb6df5d9094..a0abe7c1a8ea 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4031,7 +4031,8 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio.git S: Maintained F: Documentation/gpio/ F: drivers/gpio/ -F: include/linux/gpio* +F: include/linux/gpio/ +F: include/linux/gpio.h F: include/asm-generic/gpio.h GRE DEMULTIPLEXER DRIVER @@ -7002,9 +7003,7 @@ M: Thomas Abraham <thomas.abraham@linaro.org> L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers) S: Maintained -F: drivers/pinctrl/pinctrl-exynos.* -F: drivers/pinctrl/pinctrl-s3c* -F: drivers/pinctrl/pinctrl-samsung.* +F: drivers/pinctrl/samsung/ PIN CONTROLLER - ST SPEAR M: Viresh Kumar <viresh.linux@gmail.com> diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c index 3f4bb58aea54..74f1eaf97801 100644 --- a/arch/arm/mach-at91/at91rm9200_devices.c +++ b/arch/arm/mach-at91/at91rm9200_devices.c @@ -15,7 +15,7 @@ #include <linux/dma-mapping.h> #include <linux/gpio.h> -#include <linux/gpio/driver.h> +#include <linux/gpio/machine.h> #include <linux/platform_device.h> #include <linux/i2c-gpio.h> diff --git a/arch/arm/mach-tegra/board-paz00.c b/arch/arm/mach-tegra/board-paz00.c index bb4782a32713..fbe74c6806f3 100644 --- a/arch/arm/mach-tegra/board-paz00.c +++ b/arch/arm/mach-tegra/board-paz00.c @@ -17,7 +17,7 @@ * */ -#include <linux/gpio/driver.h> +#include <linux/gpio/machine.h> #include <linux/platform_device.h> #include <linux/rfkill-gpio.h> diff --git a/arch/mips/jz4740/board-qi_lb60.c b/arch/mips/jz4740/board-qi_lb60.c index 088e92a79ae6..c454525e7695 100644 --- a/arch/mips/jz4740/board-qi_lb60.c +++ b/arch/mips/jz4740/board-qi_lb60.c @@ -15,6 +15,7 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/gpio.h> +#include <linux/gpio/machine.h> #include <linux/input.h> #include <linux/gpio_keys.h> diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 4a065b45330f..9de1515e5808 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -340,6 +340,13 @@ config GPIO_XILINX help Say yes here to support the Xilinx FPGA GPIO device +config GPIO_ZYNQ + tristate "Xilinx Zynq GPIO support" + depends on ARCH_ZYNQ + select GPIOLIB_IRQCHIP + help + Say yes here to support Xilinx Zynq GPIO controller. + config GPIO_XTENSA bool "Xtensa GPIO32 support" depends on XTENSA @@ -423,7 +430,7 @@ config GPIO_GE_FPGA config GPIO_LYNXPOINT tristate "Intel Lynxpoint GPIO support" depends on ACPI && X86 - select IRQ_DOMAIN + select GPIOLIB_IRQCHIP help driver for GPIO functionality on Intel Lynxpoint PCH chipset Requires ACPI device enumeration code to set up a platform device. @@ -586,6 +593,7 @@ config GPIO_SX150X config GPIO_STMPE bool "STMPE GPIOs" depends on MFD_STMPE + select GPIOLIB_IRQCHIP help This enables support for the GPIOs found on the STMPE I/O Expanders. diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index e18e9564b073..5d024e396622 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -4,7 +4,9 @@ ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG obj-$(CONFIG_GPIO_DEVRES) += devres.o obj-$(CONFIG_GPIOLIB) += gpiolib.o +obj-$(CONFIG_GPIOLIB) += gpiolib-legacy.o obj-$(CONFIG_OF_GPIO) += gpiolib-of.o +obj-$(CONFIG_GPIO_SYSFS) += gpiolib-sysfs.o obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o # Device drivers. Generally keep list sorted alphabetically @@ -102,3 +104,4 @@ obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o +obj-$(CONFIG_GPIO_ZYNQ) += gpio-zynq.o diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c index 65978cf85f79..41b2f40578d5 100644 --- a/drivers/gpio/devres.c +++ b/drivers/gpio/devres.c @@ -39,47 +39,53 @@ static int devm_gpiod_match(struct device *dev, void *res, void *data) * devm_gpiod_get - Resource-managed gpiod_get() * @dev: GPIO consumer * @con_id: function within the GPIO consumer + * @flags: optional GPIO initialization flags * * Managed gpiod_get(). GPIO descriptors returned from this function are * automatically disposed on driver detach. See gpiod_get() for detailed * information about behavior and return values. */ -struct gpio_desc *__must_check devm_gpiod_get(struct device *dev, - const char *con_id) +struct gpio_desc *__must_check __devm_gpiod_get(struct device *dev, + const char *con_id, + enum gpiod_flags flags) { - return devm_gpiod_get_index(dev, con_id, 0); + return devm_gpiod_get_index(dev, con_id, 0, flags); } -EXPORT_SYMBOL(devm_gpiod_get); +EXPORT_SYMBOL(__devm_gpiod_get); /** * devm_gpiod_get_optional - Resource-managed gpiod_get_optional() * @dev: GPIO consumer * @con_id: function within the GPIO consumer + * @flags: optional GPIO initialization flags * * Managed gpiod_get_optional(). GPIO descriptors returned from this function * are automatically disposed on driver detach. See gpiod_get_optional() for * detailed information about behavior and return values. */ -struct gpio_desc *__must_check devm_gpiod_get_optional(struct device *dev, - const char *con_id) +struct gpio_desc *__must_check __devm_gpiod_get_optional(struct device *dev, + const char *con_id, + enum gpiod_flags flags) { - return devm_gpiod_get_index_optional(dev, con_id, 0); + return devm_gpiod_get_index_optional(dev, con_id, 0, flags); } -EXPORT_SYMBOL(devm_gpiod_get_optional); +EXPORT_SYMBOL(__devm_gpiod_get_optional); /** * devm_gpiod_get_index - Resource-managed gpiod_get_index() * @dev: GPIO consumer * @con_id: function within the GPIO consumer * @idx: index of the GPIO to obtain in the consumer + * @flags: optional GPIO initialization flags * * Managed gpiod_get_index(). GPIO descriptors returned from this function are * automatically disposed on driver detach. See gpiod_get_index() for detailed * information about behavior and return values. */ -struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev, +struct gpio_desc *__must_check __devm_gpiod_get_index(struct device *dev, const char *con_id, - unsigned int idx) + unsigned int idx, + enum gpiod_flags flags) { struct gpio_desc **dr; struct gpio_desc *desc; @@ -89,7 +95,7 @@ struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev, if (!dr) return ERR_PTR(-ENOMEM); - desc = gpiod_get_index(dev, con_id, idx); + desc = gpiod_get_index(dev, con_id, idx, flags); if (IS_ERR(desc)) { devres_free(dr); return desc; @@ -100,26 +106,28 @@ struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev, return desc; } -EXPORT_SYMBOL(devm_gpiod_get_index); +EXPORT_SYMBOL(__devm_gpiod_get_index); /** * devm_gpiod_get_index_optional - Resource-managed gpiod_get_index_optional() * @dev: GPIO consumer * @con_id: function within the GPIO consumer * @index: index of the GPIO to obtain in the consumer + * @flags: optional GPIO initialization flags * * Managed gpiod_get_index_optional(). GPIO descriptors returned from this * function are automatically disposed on driver detach. See * gpiod_get_index_optional() for detailed information about behavior and * return values. */ -struct gpio_desc *__must_check devm_gpiod_get_index_optional(struct device *dev, +struct gpio_desc *__must_check __devm_gpiod_get_index_optional(struct device *dev, const char *con_id, - unsigned int index) + unsigned int index, + enum gpiod_flags flags) { struct gpio_desc *desc; - desc = devm_gpiod_get_index(dev, con_id, index); + desc = devm_gpiod_get_index(dev, con_id, index, flags); if (IS_ERR(desc)) { if (PTR_ERR(desc) == -ENOENT) return NULL; @@ -127,7 +135,7 @@ struct gpio_desc *__must_check devm_gpiod_get_index_optional(struct device *dev, return desc; } -EXPORT_SYMBOL(devm_gpiod_get_index_optional); +EXPORT_SYMBOL(__devm_gpiod_get_index_optional); /** * devm_gpiod_put - Resource-managed gpiod_put() diff --git a/drivers/gpio/gpio-74x164.c b/drivers/gpio/gpio-74x164.c index e4ae29824c32..e3d968f751f1 100644 --- a/drivers/gpio/gpio-74x164.c +++ b/drivers/gpio/gpio-74x164.c @@ -167,13 +167,11 @@ exit_destroy: static int gen_74x164_remove(struct spi_device *spi) { struct gen_74x164_chip *chip = spi_get_drvdata(spi); - int ret; - ret = gpiochip_remove(&chip->gpio_chip); - if (!ret) - mutex_destroy(&chip->lock); + gpiochip_remove(&chip->gpio_chip); + mutex_destroy(&chip->lock); - return ret; + return 0; } static const struct of_device_id gen_74x164_dt_ids[] = { diff --git a/drivers/gpio/gpio-adnp.c b/drivers/gpio/gpio-adnp.c index b2239d678d01..416b2200d4f1 100644 --- a/drivers/gpio/gpio-adnp.c +++ b/drivers/gpio/gpio-adnp.c @@ -585,15 +585,8 @@ static int adnp_i2c_remove(struct i2c_client *client) { struct adnp *adnp = i2c_get_clientdata(client); struct device_node *np = client->dev.of_node; - int err; - - err = gpiochip_remove(&adnp->gpio); - if (err < 0) { - dev_err(&client->dev, "%s failed: %d\n", "gpiochip_remove()", - err); - return err; - } + gpiochip_remove(&adnp->gpio); if (of_find_property(np, "interrupt-controller", NULL)) adnp_irq_teardown(adnp); diff --git a/drivers/gpio/gpio-adp5520.c b/drivers/gpio/gpio-adp5520.c index f1ade8fa3218..b08bd169e568 100644 --- a/drivers/gpio/gpio-adp5520.c +++ b/drivers/gpio/gpio-adp5520.c @@ -167,15 +167,9 @@ err: static int adp5520_gpio_remove(struct platform_device *pdev) { struct adp5520_gpio *dev; - int ret; dev = platform_get_drvdata(pdev); - ret = gpiochip_remove(&dev->gpio_chip); - if (ret) { - dev_err(&pdev->dev, "%s failed, %d\n", - "gpiochip_remove()", ret); - return ret; - } + gpiochip_remove(&dev->gpio_chip); return 0; } diff --git a/drivers/gpio/gpio-adp5588.c b/drivers/gpio/gpio-adp5588.c index ef19bc33f2bd..3beed6ea8c65 100644 --- a/drivers/gpio/gpio-adp5588.c +++ b/drivers/gpio/gpio-adp5588.c @@ -470,11 +470,7 @@ static int adp5588_gpio_remove(struct i2c_client *client) if (dev->irq_base) free_irq(dev->client->irq, dev); - ret = gpiochip_remove(&dev->gpio_chip); - if (ret) { - dev_err(&client->dev, "gpiochip_remove failed %d\n", ret); - return ret; - } + gpiochip_remove(&dev->gpio_chip); kfree(dev); return 0; diff --git a/drivers/gpio/gpio-amd8111.c b/drivers/gpio/gpio-amd8111.c index 94e9992f8904..3c09f1a6872a 100644 --- a/drivers/gpio/gpio-amd8111.c +++ b/drivers/gpio/gpio-amd8111.c @@ -232,8 +232,7 @@ out: static void __exit amd_gpio_exit(void) { - int err = gpiochip_remove(&gp.chip); - WARN_ON(err); + gpiochip_remove(&gp.chip); ioport_unmap(gp.pm); release_region(gp.pmbase + PMBASE_OFFSET, PMBASE_SIZE); } diff --git a/drivers/gpio/gpio-arizona.c b/drivers/gpio/gpio-arizona.c index 29bdff558981..fe369f5c7fa6 100644 --- a/drivers/gpio/gpio-arizona.c +++ b/drivers/gpio/gpio-arizona.c @@ -149,7 +149,8 @@ static int arizona_gpio_remove(struct platform_device *pdev) { struct arizona_gpio *arizona_gpio = platform_get_drvdata(pdev); - return gpiochip_remove(&arizona_gpio->gpio_chip); + gpiochip_remove(&arizona_gpio->gpio_chip); + return 0; } static struct platform_driver arizona_gpio_driver = { diff --git a/drivers/gpio/gpio-cs5535.c b/drivers/gpio/gpio-cs5535.c index c0a3aeba6f21..92ec58fa9236 100644 --- a/drivers/gpio/gpio-cs5535.c +++ b/drivers/gpio/gpio-cs5535.c @@ -358,14 +358,8 @@ done: static int cs5535_gpio_remove(struct platform_device *pdev) { struct resource *r; - int err; - err = gpiochip_remove(&cs5535_gpio_chip.chip); - if (err) { - /* uhh? */ - dev_err(&pdev->dev, "unable to remove gpio_chip?\n"); - return err; - } + gpiochip_remove(&cs5535_gpio_chip.chip); r = platform_get_resource(pdev, IORESOURCE_IO, 0); release_region(r->start, resource_size(r)); diff --git a/drivers/gpio/gpio-da9052.c b/drivers/gpio/gpio-da9052.c index 416cdf786b05..c5bccd4dec96 100644 --- a/drivers/gpio/gpio-da9052.c +++ b/drivers/gpio/gpio-da9052.c @@ -237,7 +237,8 @@ static int da9052_gpio_remove(struct platform_device *pdev) { struct da9052_gpio *gpio = platform_get_drvdata(pdev); - return gpiochip_remove(&gpio->gp); + gpiochip_remove(&gpio->gp); + return 0; } static struct platform_driver da9052_gpio_driver = { diff --git a/drivers/gpio/gpio-da9055.c b/drivers/gpio/gpio-da9055.c index f992997bc301..9167c4331081 100644 --- a/drivers/gpio/gpio-da9055.c +++ b/drivers/gpio/gpio-da9055.c @@ -174,7 +174,8 @@ static int da9055_gpio_remove(struct platform_device *pdev) { struct da9055_gpio *gpio = platform_get_drvdata(pdev); - return gpiochip_remove(&gpio->gp); + gpiochip_remove(&gpio->gp); + return 0; } static struct platform_driver da9055_gpio_driver = { diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index cd3b81435274..d6618a6e2399 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -359,7 +359,7 @@ static void dwapb_gpio_unregister(struct dwapb_gpio *gpio) for (m = 0; m < gpio->nr_ports; ++m) if (gpio->ports[m].is_registered) - WARN_ON(gpiochip_remove(&gpio->ports[m].bgc.gc)); + gpiochip_remove(&gpio->ports[m].bgc.gc); } static int dwapb_gpio_probe(struct platform_device *pdev) diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index cde36054c387..fe49ec3cdb7d 100644 --- a/drivers/gpio/gpio-em.c +++ b/drivers/gpio/gpio-em.c @@ -409,11 +409,8 @@ err0: static int em_gio_remove(struct platform_device *pdev) { struct em_gio_priv *p = platform_get_drvdata(pdev); - int ret; - ret = gpiochip_remove(&p->gpio_chip); - if (ret) - return ret; + gpiochip_remove(&p->gpio_chip); irq_domain_remove(p->irq_domain); return 0; diff --git a/drivers/gpio/gpio-f7188x.c b/drivers/gpio/gpio-f7188x.c index 8f73ee093739..fd3202f968ff 100644 --- a/drivers/gpio/gpio-f7188x.c +++ b/drivers/gpio/gpio-f7188x.c @@ -317,13 +317,7 @@ static int f7188x_gpio_probe(struct platform_device *pdev) err_gpiochip: for (i = i - 1; i >= 0; i--) { struct f7188x_gpio_bank *bank = &data->bank[i]; - int tmp; - - tmp = gpiochip_remove(&bank->chip); - if (tmp < 0) - dev_err(&pdev->dev, - "Failed to remove gpiochip %d: %d\n", - i, tmp); + gpiochip_remove(&bank->chip); } return err; @@ -331,20 +325,12 @@ err_gpiochip: static int f7188x_gpio_remove(struct platform_device *pdev) { - int err; int i; struct f7188x_gpio_data *data = platform_get_drvdata(pdev); for (i = 0; i < data->nr_bank; i++) { struct f7188x_gpio_bank *bank = &data->bank[i]; - - err = gpiochip_remove(&bank->chip); - if (err) { - dev_err(&pdev->dev, - "Failed to remove GPIO gpiochip %d: %d\n", - i, err); - return err; - } + gpiochip_remove(&bank->chip); } return 0; diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c index fea8c82bb8fc..16f6115e5bdb 100644 --- a/drivers/gpio/gpio-generic.c +++ b/drivers/gpio/gpio-generic.c @@ -398,7 +398,8 @@ static int bgpio_request(struct gpio_chip *chip, unsigned gpio_pin) int bgpio_remove(struct bgpio_chip *bgc) { - return gpiochip_remove(&bgc->gc); + gpiochip_remove(&bgc->gc); + return 0; } EXPORT_SYMBOL_GPL(bgpio_remove); diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c index 3c3f515b7916..66ad3df9d9cf 100644 --- a/drivers/gpio/gpio-grgpio.c +++ b/drivers/gpio/gpio-grgpio.c @@ -468,9 +468,7 @@ static int grgpio_remove(struct platform_device *ofdev) } } - ret = gpiochip_remove(&priv->bgc.gc); - if (ret) - goto out; + gpiochip_remove(&priv->bgc.gc); if (priv->domain) irq_domain_remove(priv->domain); diff --git a/drivers/gpio/gpio-ich.c b/drivers/gpio/gpio-ich.c index 70304220a479..3784e81e7762 100644 --- a/drivers/gpio/gpio-ich.c +++ b/drivers/gpio/gpio-ich.c @@ -514,14 +514,7 @@ add_err: static int ichx_gpio_remove(struct platform_device *pdev) { - int err; - - err = gpiochip_remove(&ichx_priv.chip); - if (err) { - dev_err(&pdev->dev, "%s failed, %d\n", - "gpiochip_remove()", err); - return err; - } + gpiochip_remove(&ichx_priv.chip); ichx_gpio_release_regions(ichx_priv.gpio_base, ichx_priv.use_gpio); if (ichx_priv.pm_base) diff --git a/drivers/gpio/gpio-intel-mid.c b/drivers/gpio/gpio-intel-mid.c index 118a6bf455d9..aa28c65eb6b4 100644 --- a/drivers/gpio/gpio-intel-mid.c +++ b/drivers/gpio/gpio-intel-mid.c @@ -28,12 +28,10 @@ #include <linux/stddef.h> #include <linux/interrupt.h> #include <linux/init.h> -#include <linux/irq.h> #include <linux/io.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/slab.h> #include <linux/pm_runtime.h> -#include <linux/irqdomain.h> #define INTEL_MID_IRQ_TYPE_EDGE (1 << 0) #define INTEL_MID_IRQ_TYPE_LEVEL (1 << 1) @@ -78,10 +76,12 @@ struct intel_mid_gpio { void __iomem *reg_base; spinlock_t lock; struct pci_dev *pdev; - struct irq_domain *domain; }; -#define to_intel_gpio_priv(chip) container_of(chip, struct intel_mid_gpio, chip) +static inline struct intel_mid_gpio *to_intel_gpio_priv(struct gpio_chip *gc) +{ + return container_of(gc, struct intel_mid_gpio, chip); +} static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset, enum GPIO_REG reg_type) @@ -182,15 +182,10 @@ static int intel_gpio_direction_output(struct gpio_chip *chip, return 0; } -static int intel_gpio_to_irq(struct gpio_chip *chip, unsigned offset) -{ - struct intel_mid_gpio *priv = to_intel_gpio_priv(chip); - return irq_create_mapping(priv->domain, offset); -} - static int intel_mid_irq_type(struct irq_data *d, unsigned type) { - struct intel_mid_gpio *priv = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct intel_mid_gpio *priv = to_intel_gpio_priv(gc); u32 gpio = irqd_to_hwirq(d); unsigned long flags; u32 value; @@ -231,33 +226,11 @@ static void intel_mid_irq_mask(struct irq_data *d) { } -static int intel_mid_irq_reqres(struct irq_data *d) -{ - struct intel_mid_gpio *priv = irq_data_get_irq_chip_data(d); - - if (gpio_lock_as_irq(&priv->chip, irqd_to_hwirq(d))) { - dev_err(priv->chip.dev, - "unable to lock HW IRQ %lu for IRQ\n", - irqd_to_hwirq(d)); - return -EINVAL; - } - return 0; -} - -static void intel_mid_irq_relres(struct irq_data *d) -{ - struct intel_mid_gpio *priv = irq_data_get_irq_chip_data(d); - - gpio_unlock_as_irq(&priv->chip, irqd_to_hwirq(d)); -} - static struct irq_chip intel_mid_irqchip = { .name = "INTEL_MID-GPIO", .irq_mask = intel_mid_irq_mask, .irq_unmask = intel_mid_irq_unmask, .irq_set_type = intel_mid_irq_type, - .irq_request_resources = intel_mid_irq_reqres, - .irq_release_resources = intel_mid_irq_relres, }; static const struct intel_mid_gpio_ddata gpio_lincroft = { @@ -330,8 +303,9 @@ MODULE_DEVICE_TABLE(pci, intel_gpio_ids); static void intel_mid_irq_handler(unsigned irq, struct irq_desc *desc) { + struct gpio_chip *gc = irq_desc_get_handler_data(desc); + struct intel_mid_gpio *priv = to_intel_gpio_priv(gc); struct irq_data *data = irq_desc_get_irq_data(desc); - struct intel_mid_gpio *priv = irq_data_get_irq_handler_data(data); struct irq_chip *chip = irq_data_get_irq_chip(data); u32 base, gpio, mask; unsigned long pending; @@ -345,7 +319,7 @@ static void intel_mid_irq_handler(unsigned irq, struct irq_desc *desc) mask = BIT(gpio); /* Clear before handling so we can't lose an edge */ writel(mask, gedr); - generic_handle_irq(irq_find_mapping(priv->domain, + generic_handle_irq(irq_find_mapping(gc->irqdomain, base + gpio)); } } @@ -371,23 +345,6 @@ static void intel_mid_irq_init_hw(struct intel_mid_gpio *priv) } } -static int intel_gpio_irq_map(struct irq_domain *d, unsigned int irq, - irq_hw_number_t hwirq) -{ - struct intel_mid_gpio *priv = d->host_data; - - irq_set_chip_and_handler(irq, &intel_mid_irqchip, handle_simple_irq); - irq_set_chip_data(irq, priv); - irq_set_irq_type(irq, IRQ_TYPE_NONE); - - return 0; -} - -static const struct irq_domain_ops intel_gpio_irq_ops = { - .map = intel_gpio_irq_map, - .xlate = irq_domain_xlate_twocell, -}; - static int intel_gpio_runtime_idle(struct device *dev) { int err = pm_schedule_suspend(dev, 500); @@ -441,7 +398,6 @@ static int intel_gpio_probe(struct pci_dev *pdev, priv->chip.direction_output = intel_gpio_direction_output; priv->chip.get = intel_gpio_get; priv->chip.set = intel_gpio_set; - priv->chip.to_irq = intel_gpio_to_irq; priv->chip.base = gpio_base; priv->chip.ngpio = ddata->ngpio; priv->chip.can_sleep = false; @@ -449,11 +405,6 @@ static int intel_gpio_probe(struct pci_dev *pdev, spin_lock_init(&priv->lock); - priv->domain = irq_domain_add_simple(pdev->dev.of_node, ddata->ngpio, - irq_base, &intel_gpio_irq_ops, priv); - if (!priv->domain) - return -ENOMEM; - pci_set_drvdata(pdev, priv); retval = gpiochip_add(&priv->chip); if (retval) { @@ -461,10 +412,23 @@ static int intel_gpio_probe(struct pci_dev *pdev, return retval; } + retval = gpiochip_irqchip_add(&priv->chip, + &intel_mid_irqchip, + irq_base, + handle_simple_irq, + IRQ_TYPE_NONE); + if (retval) { + dev_err(&pdev->dev, + "could not connect irqchip to gpiochip\n"); + return retval; + } + intel_mid_irq_init_hw(priv); - irq_set_handler_data(pdev->irq, priv); - irq_set_chained_handler(pdev->irq, intel_mid_irq_handler); + gpiochip_set_chained_irqchip(&priv->chip, + &intel_mid_irqchip, + pdev->irq, + intel_mid_irq_handler); pm_runtime_put_noidle(&pdev->dev); pm_runtime_allow(&pdev->dev); diff --git a/drivers/gpio/gpio-it8761e.c b/drivers/gpio/gpio-it8761e.c index 278b81317010..dadfc245cf09 100644 --- a/drivers/gpio/gpio-it8761e.c +++ b/drivers/gpio/gpio-it8761e.c @@ -217,11 +217,7 @@ gpiochip_add_err: static void __exit it8761e_gpio_exit(void) { if (gpio_ba) { - int ret = gpiochip_remove(&it8761e_gpio_chip); - - WARN(ret, "%s(): gpiochip_remove() failed, ret=%d\n", - __func__, ret); - + gpiochip_remove(&it8761e_gpio_chip); release_region(gpio_ba, GPIO_IOSIZE); gpio_ba = 0; } diff --git a/drivers/gpio/gpio-janz-ttl.c b/drivers/gpio/gpio-janz-ttl.c index 42852eaaf020..29ffe22ad97a 100644 --- a/drivers/gpio/gpio-janz-ttl.c +++ b/drivers/gpio/gpio-janz-ttl.c @@ -194,14 +194,8 @@ static int ttl_probe(struct platform_device *pdev) static int ttl_remove(struct platform_device *pdev) { struct ttl_module *mod = platform_get_drvdata(pdev); - struct device *dev = &pdev->dev; - int ret; - ret = gpiochip_remove(&mod->gpio); - if (ret) { - dev_err(dev, "unable to remove GPIO chip\n"); - return ret; - } + gpiochip_remove(&mod->gpio); return 0; } diff --git a/drivers/gpio/gpio-kempld.c b/drivers/gpio/gpio-kempld.c index 1e5e51987d31..fd150adeebf9 100644 --- a/drivers/gpio/gpio-kempld.c +++ b/drivers/gpio/gpio-kempld.c @@ -199,7 +199,8 @@ static int kempld_gpio_remove(struct platform_device *pdev) { struct kempld_gpio_data *gpio = platform_get_drvdata(pdev); - return gpiochip_remove(&gpio->chip); + gpiochip_remove(&gpio->chip); + return 0; } static struct platform_driver kempld_gpio_driver = { diff --git a/drivers/gpio/gpio-lp3943.c b/drivers/gpio/gpio-lp3943.c index a0341c92bcb4..6bbdad805b78 100644 --- a/drivers/gpio/gpio-lp3943.c +++ b/drivers/gpio/gpio-lp3943.c @@ -216,7 +216,8 @@ static int lp3943_gpio_remove(struct platform_device *pdev) { struct lp3943_gpio *lp3943_gpio = platform_get_drvdata(pdev); - return gpiochip_remove(&lp3943_gpio->chip); + gpiochip_remove(&lp3943_gpio->chip); + return 0; } static const struct of_device_id lp3943_gpio_of_match[] = { diff --git a/drivers/gpio/gpio-lpc32xx.c b/drivers/gpio/gpio-lpc32xx.c index 225344d66404..b9b9799b368b 100644 --- a/drivers/gpio/gpio-lpc32xx.c +++ b/drivers/gpio/gpio-lpc32xx.c @@ -560,7 +560,7 @@ static int lpc32xx_gpio_probe(struct platform_device *pdev) } #ifdef CONFIG_OF -static struct of_device_id lpc32xx_gpio_of_match[] = { +static const struct of_device_id lpc32xx_gpio_of_match[] = { { .compatible = "nxp,lpc3220-gpio", }, { }, }; diff --git a/drivers/gpio/gpio-lynxpoint.c b/drivers/gpio/gpio-lynxpoint.c index 2bea89b72508..ff9eb911b5e4 100644 --- a/drivers/gpio/gpio-lynxpoint.c +++ b/drivers/gpio/gpio-lynxpoint.c @@ -25,9 +25,7 @@ #include <linux/types.h> #include <linux/bitops.h> #include <linux/interrupt.h> -#include <linux/irq.h> #include <linux/gpio.h> -#include <linux/irqdomain.h> #include <linux/slab.h> #include <linux/acpi.h> #include <linux/platform_device.h> @@ -62,7 +60,6 @@ struct lp_gpio { struct gpio_chip chip; - struct irq_domain *domain; struct platform_device *pdev; spinlock_t lock; unsigned long reg_base; @@ -151,7 +148,8 @@ static void lp_gpio_free(struct gpio_chip *chip, unsigned offset) static int lp_irq_type(struct irq_data *d, unsigned type) { - struct lp_gpio *lg = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct lp_gpio *lg = container_of(gc, struct lp_gpio, chip); u32 hwirq = irqd_to_hwirq(d); unsigned long flags; u32 value; @@ -236,16 +234,11 @@ static int lp_gpio_direction_output(struct gpio_chip *chip, return 0; } -static int lp_gpio_to_irq(struct gpio_chip *chip, unsigned offset) -{ - struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip); - return irq_create_mapping(lg->domain, offset); -} - static void lp_gpio_irq_handler(unsigned hwirq, struct irq_desc *desc) { struct irq_data *data = irq_desc_get_irq_data(desc); - struct lp_gpio *lg = irq_data_get_irq_handler_data(data); + struct gpio_chip *gc = irq_desc_get_handler_data(desc); + struct lp_gpio *lg = container_of(gc, struct lp_gpio, chip); struct irq_chip *chip = irq_data_get_irq_chip(data); u32 base, pin, mask; unsigned long reg, ena, pending; @@ -262,7 +255,7 @@ static void lp_gpio_irq_handler(unsigned hwirq, struct irq_desc *desc) mask = BIT(pin); /* Clear before handling so we don't lose an edge */ outl(mask, reg); - irq = irq_find_mapping(lg->domain, base + pin); + irq = irq_find_mapping(lg->chip.irqdomain, base + pin); generic_handle_irq(irq); } } @@ -279,7 +272,8 @@ static void lp_irq_mask(struct irq_data *d) static void lp_irq_enable(struct irq_data *d) { - struct lp_gpio *lg = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct lp_gpio *lg = container_of(gc, struct lp_gpio, chip); u32 hwirq = irqd_to_hwirq(d); unsigned long reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_ENABLE); unsigned long flags; @@ -291,7 +285,8 @@ static void lp_irq_enable(struct irq_data *d) static void lp_irq_disable(struct irq_data *d) { - struct lp_gpio *lg = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct lp_gpio *lg = container_of(gc, struct lp_gpio, chip); u32 hwirq = irqd_to_hwirq(d); unsigned long reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_ENABLE); unsigned long flags; @@ -301,26 +296,6 @@ static void lp_irq_disable(struct irq_data *d) spin_unlock_irqrestore(&lg->lock, flags); } -static int lp_irq_reqres(struct irq_data *d) -{ - struct lp_gpio *lg = irq_data_get_irq_chip_data(d); - - if (gpio_lock_as_irq(&lg->chip, irqd_to_hwirq(d))) { - dev_err(lg->chip.dev, - "unable to lock HW IRQ %lu for IRQ\n", - irqd_to_hwirq(d)); - return -EINVAL; - } - return 0; -} - -static void lp_irq_relres(struct irq_data *d) -{ - struct lp_gpio *lg = irq_data_get_irq_chip_data(d); - - gpio_unlock_as_irq(&lg->chip, irqd_to_hwirq(d)); -} - static struct irq_chip lp_irqchip = { .name = "LP-GPIO", .irq_mask = lp_irq_mask, @@ -328,8 +303,6 @@ static struct irq_chip lp_irqchip = { .irq_enable = lp_irq_enable, .irq_disable = lp_irq_disable, .irq_set_type = lp_irq_type, - .irq_request_resources = lp_irq_reqres, - .irq_release_resources = lp_irq_relres, .flags = IRQCHIP_SKIP_SET_WAKE, }; @@ -348,22 +321,6 @@ static void lp_gpio_irq_init_hw(struct lp_gpio *lg) } } -static int lp_gpio_irq_map(struct irq_domain *d, unsigned int irq, - irq_hw_number_t hwirq) -{ - struct lp_gpio *lg = d->host_data; - - irq_set_chip_and_handler(irq, &lp_irqchip, handle_simple_irq); - irq_set_chip_data(irq, lg); - irq_set_irq_type(irq, IRQ_TYPE_NONE); - - return 0; -} - -static const struct irq_domain_ops lp_gpio_irq_ops = { - .map = lp_gpio_irq_map, -}; - static int lp_gpio_probe(struct platform_device *pdev) { struct lp_gpio *lg; @@ -371,7 +328,6 @@ static int lp_gpio_probe(struct platform_device *pdev) struct resource *io_rc, *irq_rc; struct device *dev = &pdev->dev; unsigned long reg_len; - unsigned hwirq; int ret = -ENODEV; lg = devm_kzalloc(dev, sizeof(struct lp_gpio), GFP_KERNEL); @@ -414,27 +370,28 @@ static int lp_gpio_probe(struct platform_device *pdev) gc->can_sleep = false; gc->dev = dev; + ret = gpiochip_add(gc); + if (ret) { + dev_err(dev, "failed adding lp-gpio chip\n"); + return ret; + } + /* set up interrupts */ if (irq_rc && irq_rc->start) { - hwirq = irq_rc->start; - gc->to_irq = lp_gpio_to_irq; - - lg->domain = irq_domain_add_linear(NULL, LP_NUM_GPIO, - &lp_gpio_irq_ops, lg); - if (!lg->domain) - return -ENXIO; - lp_gpio_irq_init_hw(lg); + ret = gpiochip_irqchip_add(gc, &lp_irqchip, 0, + handle_simple_irq, IRQ_TYPE_NONE); + if (ret) { + dev_err(dev, "failed to add irqchip\n"); + gpiochip_remove(gc); + return ret; + } - irq_set_handler_data(hwirq, lg); - irq_set_chained_handler(hwirq, lp_gpio_irq_handler); + gpiochip_set_chained_irqchip(gc, &lp_irqchip, + (unsigned)irq_rc->start, + lp_gpio_irq_handler); } - ret = gpiochip_add(gc); - if (ret) { - dev_err(dev, "failed adding lp-gpio chip\n"); - return ret; - } pm_runtime_enable(dev); return 0; @@ -465,11 +422,8 @@ MODULE_DEVICE_TABLE(acpi, lynxpoint_gpio_acpi_match); static int lp_gpio_remove(struct platform_device *pdev) { struct lp_gpio *lg = platform_get_drvdata(pdev); - int err; pm_runtime_disable(&pdev->dev); - err = gpiochip_remove(&lg->chip); - if (err) - dev_warn(&pdev->dev, "failed to remove gpio_chip.\n"); + gpiochip_remove(&lg->chip); return 0; } diff --git a/drivers/gpio/gpio-max730x.c b/drivers/gpio/gpio-max730x.c index 0814584fcdc1..18ab89e20806 100644 --- a/drivers/gpio/gpio-max730x.c +++ b/drivers/gpio/gpio-max730x.c @@ -228,21 +228,16 @@ EXPORT_SYMBOL_GPL(__max730x_probe); int __max730x_remove(struct device *dev) { struct max7301 *ts = dev_get_drvdata(dev); - int ret; if (ts == NULL) return -ENODEV; /* Power down the chip and disable IRQ output */ ts->write(dev, 0x04, 0x00); - - ret = gpiochip_remove(&ts->chip); - if (!ret) - mutex_destroy(&ts->lock); - else - dev_err(dev, "Failed to remove GPIO controller: %d\n", ret); - - return ret; + gpiochip_remove(&ts->chip); + mutex_destroy(&ts->lock); + kfree(ts); + return 0; } EXPORT_SYMBOL_GPL(__max730x_remove); diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c index 7c36f2b0983d..6c676225b886 100644 --- a/drivers/gpio/gpio-max732x.c +++ b/drivers/gpio/gpio-max732x.c @@ -676,12 +676,7 @@ static int max732x_remove(struct i2c_client *client) } } - ret = gpiochip_remove(&chip->gpio_chip); - if (ret) { - dev_err(&client->dev, "%s failed, %d\n", - "gpiochip_remove()", ret); - return ret; - } + gpiochip_remove(&chip->gpio_chip); max732x_irq_teardown(chip); diff --git a/drivers/gpio/gpio-mc33880.c b/drivers/gpio/gpio-mc33880.c index 553a80a5eaf3..4e3e160e5db2 100644 --- a/drivers/gpio/gpio-mc33880.c +++ b/drivers/gpio/gpio-mc33880.c @@ -149,20 +149,15 @@ exit_destroy: static int mc33880_remove(struct spi_device *spi) { struct mc33880 *mc; - int ret; mc = spi_get_drvdata(spi); if (mc == NULL) return -ENODEV; - ret = gpiochip_remove(&mc->chip); - if (!ret) - mutex_destroy(&mc->lock); - else - dev_err(&spi->dev, "Failed to remove the GPIO controller: %d\n", - ret); + gpiochip_remove(&mc->chip); + mutex_destroy(&mc->lock); - return ret; + return 0; } static struct spi_driver mc33880_driver = { diff --git a/drivers/gpio/gpio-mc9s08dz60.c b/drivers/gpio/gpio-mc9s08dz60.c index dce35ff00db7..d62b4f8182bf 100644 --- a/drivers/gpio/gpio-mc9s08dz60.c +++ b/drivers/gpio/gpio-mc9s08dz60.c @@ -118,7 +118,8 @@ static int mc9s08dz60_remove(struct i2c_client *client) mc9s = i2c_get_clientdata(client); - return gpiochip_remove(&mc9s->chip); + gpiochip_remove(&mc9s->chip); + return 0; } static const struct i2c_device_id mc9s08dz60_id[] = { diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c index 57adbc90fdad..6f183d9b487e 100644 --- a/drivers/gpio/gpio-mcp23s08.c +++ b/drivers/gpio/gpio-mcp23s08.c @@ -812,16 +812,14 @@ fail: static int mcp230xx_remove(struct i2c_client *client) { struct mcp23s08 *mcp = i2c_get_clientdata(client); - int status; if (client->irq && mcp->irq_controller) mcp23s08_irq_teardown(mcp); - status = gpiochip_remove(&mcp->chip); - if (status == 0) - kfree(mcp); + gpiochip_remove(&mcp->chip); + kfree(mcp); - return status; + return 0; } static const struct i2c_device_id mcp230xx_id[] = { @@ -960,13 +958,10 @@ static int mcp23s08_probe(struct spi_device *spi) fail: for (addr = 0; addr < ARRAY_SIZE(data->mcp); addr++) { - int tmp; if (!data->mcp[addr]) continue; - tmp = gpiochip_remove(&data->mcp[addr]->chip); - if (tmp < 0) - dev_err(&spi->dev, "%s --> %d\n", "remove", tmp); + gpiochip_remove(&data->mcp[addr]->chip); } kfree(data); return status; @@ -976,23 +971,16 @@ static int mcp23s08_remove(struct spi_device *spi) { struct mcp23s08_driver_data *data = spi_get_drvdata(spi); unsigned addr; - int status = 0; for (addr = 0; addr < ARRAY_SIZE(data->mcp); addr++) { - int tmp; if (!data->mcp[addr]) continue; - tmp = gpiochip_remove(&data->mcp[addr]->chip); - if (tmp < 0) { - dev_err(&spi->dev, "%s --> %d\n", "remove", tmp); - status = tmp; - } + gpiochip_remove(&data->mcp[addr]->chip); } - if (status == 0) - kfree(data); - return status; + kfree(data); + return 0; } static const struct spi_device_id mcp23s08_ids[] = { diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c index d51329d23d38..5536108aa9db 100644 --- a/drivers/gpio/gpio-ml-ioh.c +++ b/drivers/gpio/gpio-ml-ioh.c @@ -497,8 +497,7 @@ err_irq_alloc_descs: err_gpiochip_add: while (--i >= 0) { chip--; - if (gpiochip_remove(&chip->gpio)) - dev_err(&pdev->dev, "Failed gpiochip_remove(%d)\n", i); + gpiochip_remove(&chip->gpio); } kfree(chip_save); @@ -519,7 +518,6 @@ err_pci_enable: static void ioh_gpio_remove(struct pci_dev *pdev) { - int err; int i; struct ioh_gpio *chip = pci_get_drvdata(pdev); void *chip_save; @@ -530,9 +528,7 @@ static void ioh_gpio_remove(struct pci_dev *pdev) for (i = 0; i < 8; i++, chip++) { irq_free_descs(chip->irq_base, num_ports[i]); - err = gpiochip_remove(&chip->gpio); - if (err) - dev_err(&pdev->dev, "Failed gpiochip_remove\n"); + gpiochip_remove(&chip->gpio); } chip = chip_save; diff --git a/drivers/gpio/gpio-msm-v2.c b/drivers/gpio/gpio-msm-v2.c index a3351acd4963..94f57670df9a 100644 --- a/drivers/gpio/gpio-msm-v2.c +++ b/drivers/gpio/gpio-msm-v2.c @@ -438,10 +438,7 @@ MODULE_DEVICE_TABLE(of, msm_gpio_of_match); static int msm_gpio_remove(struct platform_device *dev) { - int ret = gpiochip_remove(&msm_gpio.gpio_chip); - - if (ret < 0) - return ret; + gpiochip_remove(&msm_gpio.gpio_chip); irq_set_handler(msm_gpio.summary_irq, NULL); diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c index db83b3c0a449..f4e54a92e04a 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c @@ -485,7 +485,7 @@ static int mxc_gpio_probe(struct platform_device *pdev) out_irqdesc_free: irq_free_descs(irq_base, 32); out_gpiochip_remove: - WARN_ON(gpiochip_remove(&port->bgc.gc) < 0); + gpiochip_remove(&port->bgc.gc); out_bgpio_remove: bgpio_remove(&port->bgc); out_bgio: diff --git a/drivers/gpio/gpio-octeon.c b/drivers/gpio/gpio-octeon.c index dbb08546b9ec..5c5770c99c80 100644 --- a/drivers/gpio/gpio-octeon.c +++ b/drivers/gpio/gpio-octeon.c @@ -129,7 +129,8 @@ out: static int octeon_gpio_remove(struct platform_device *pdev) { struct gpio_chip *chip = pdev->dev.platform_data; - return gpiochip_remove(chip); + gpiochip_remove(chip); + return 0; } static struct of_device_id octeon_gpio_match[] = { diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 00f29aa1fb9d..174932165fcb 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -24,7 +24,6 @@ #include <linux/pm.h> #include <linux/of.h> #include <linux/of_device.h> -#include <linux/irqchip/chained_irq.h> #include <linux/gpio.h> #include <linux/bitops.h> #include <linux/platform_data/gpio-omap.h> @@ -89,18 +88,19 @@ struct gpio_bank { #define BANK_USED(bank) (bank->mod_usage || bank->irq_usage) #define LINE_USED(line, offset) (line & (BIT(offset))) -static int irq_to_gpio(struct gpio_bank *bank, unsigned int gpio_irq) +static int omap_irq_to_gpio(struct gpio_bank *bank, unsigned int gpio_irq) { return bank->chip.base + gpio_irq; } -static inline struct gpio_bank *_irq_data_get_bank(struct irq_data *d) +static inline struct gpio_bank *omap_irq_data_get_bank(struct irq_data *d) { struct gpio_chip *chip = irq_data_get_irq_chip_data(d); return container_of(chip, struct gpio_bank, chip); } -static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input) +static void omap_set_gpio_direction(struct gpio_bank *bank, int gpio, + int is_input) { void __iomem *reg = bank->base; u32 l; @@ -117,7 +117,8 @@ static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input) /* set data out value using dedicate set/clear register */ -static void _set_gpio_dataout_reg(struct gpio_bank *bank, int gpio, int enable) +static void omap_set_gpio_dataout_reg(struct gpio_bank *bank, int gpio, + int enable) { void __iomem *reg = bank->base; u32 l = GPIO_BIT(bank, gpio); @@ -134,7 +135,8 @@ static void _set_gpio_dataout_reg(struct gpio_bank *bank, int gpio, int enable) } /* set data out value using mask register */ -static void _set_gpio_dataout_mask(struct gpio_bank *bank, int gpio, int enable) +static void omap_set_gpio_dataout_mask(struct gpio_bank *bank, int gpio, + int enable) { void __iomem *reg = bank->base + bank->regs->dataout; u32 gpio_bit = GPIO_BIT(bank, gpio); @@ -149,21 +151,21 @@ static void _set_gpio_dataout_mask(struct gpio_bank *bank, int gpio, int enable) bank->context.dataout = l; } -static int _get_gpio_datain(struct gpio_bank *bank, int offset) +static int omap_get_gpio_datain(struct gpio_bank *bank, int offset) { void __iomem *reg = bank->base + bank->regs->datain; return (readl_relaxed(reg) & (BIT(offset))) != 0; } -static int _get_gpio_dataout(struct gpio_bank *bank, int offset) +static int omap_get_gpio_dataout(struct gpio_bank *bank, int offset) { void __iomem *reg = bank->base + bank->regs->dataout; return (readl_relaxed(reg) & (BIT(offset))) != 0; } -static inline void _gpio_rmw(void __iomem *base, u32 reg, u32 mask, bool set) +static inline void omap_gpio_rmw(void __iomem *base, u32 reg, u32 mask, bool set) { int l = readl_relaxed(base + reg); @@ -175,7 +177,7 @@ static inline void _gpio_rmw(void __iomem *base, u32 reg, u32 mask, bool set) writel_relaxed(l, base + reg); } -static inline void _gpio_dbck_enable(struct gpio_bank *bank) +static inline void omap_gpio_dbck_enable(struct gpio_bank *bank) { if (bank->dbck_enable_mask && !bank->dbck_enabled) { clk_prepare_enable(bank->dbck); @@ -186,7 +188,7 @@ static inline void _gpio_dbck_enable(struct gpio_bank *bank) } } -static inline void _gpio_dbck_disable(struct gpio_bank *bank) +static inline void omap_gpio_dbck_disable(struct gpio_bank *bank) { if (bank->dbck_enable_mask && bank->dbck_enabled) { /* @@ -202,7 +204,7 @@ static inline void _gpio_dbck_disable(struct gpio_bank *bank) } /** - * _set_gpio_debounce - low level gpio debounce time + * omap2_set_gpio_debounce - low level gpio debounce time * @bank: the gpio bank we're acting upon * @gpio: the gpio number on this @gpio * @debounce: debounce time to use @@ -210,8 +212,8 @@ static inline void _gpio_dbck_disable(struct gpio_bank *bank) * OMAP's debounce time is in 31us steps so we need * to convert and round up to the closest unit. */ -static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio, - unsigned debounce) +static void omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned gpio, + unsigned debounce) { void __iomem *reg; u32 val; @@ -252,7 +254,7 @@ static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio, * used within _gpio_dbck_enable() is still not initialized at * that point. Therefore we have to enable dbck here. */ - _gpio_dbck_enable(bank); + omap_gpio_dbck_enable(bank); if (bank->dbck_enable_mask) { bank->context.debounce = debounce; bank->context.debounce_en = val; @@ -260,7 +262,7 @@ static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio, } /** - * _clear_gpio_debounce - clear debounce settings for a gpio + * omap_clear_gpio_debounce - clear debounce settings for a gpio * @bank: the gpio bank we're acting upon * @gpio: the gpio number on this @gpio * @@ -269,7 +271,7 @@ static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio, * time too. The debounce clock will also be disabled when calling this function * if this is the only gpio in the bank using debounce. */ -static void _clear_gpio_debounce(struct gpio_bank *bank, unsigned gpio) +static void omap_clear_gpio_debounce(struct gpio_bank *bank, unsigned gpio) { u32 gpio_bit = GPIO_BIT(bank, gpio); @@ -293,20 +295,20 @@ static void _clear_gpio_debounce(struct gpio_bank *bank, unsigned gpio) } } -static inline void set_gpio_trigger(struct gpio_bank *bank, int gpio, +static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio, unsigned trigger) { void __iomem *base = bank->base; u32 gpio_bit = BIT(gpio); - _gpio_rmw(base, bank->regs->leveldetect0, gpio_bit, - trigger & IRQ_TYPE_LEVEL_LOW); - _gpio_rmw(base, bank->regs->leveldetect1, gpio_bit, - trigger & IRQ_TYPE_LEVEL_HIGH); - _gpio_rmw(base, bank->regs->risingdetect, gpio_bit, - trigger & IRQ_TYPE_EDGE_RISING); - _gpio_rmw(base, bank->regs->fallingdetect, gpio_bit, - trigger & IRQ_TYPE_EDGE_FALLING); + omap_gpio_rmw(base, bank->regs->leveldetect0, gpio_bit, + trigger & IRQ_TYPE_LEVEL_LOW); + omap_gpio_rmw(base, bank->regs->leveldetect1, gpio_bit, + trigger & IRQ_TYPE_LEVEL_HIGH); + omap_gpio_rmw(base, bank->regs->risingdetect, gpio_bit, + trigger & IRQ_TYPE_EDGE_RISING); + omap_gpio_rmw(base, bank->regs->fallingdetect, gpio_bit, + trigger & IRQ_TYPE_EDGE_FALLING); bank->context.leveldetect0 = readl_relaxed(bank->base + bank->regs->leveldetect0); @@ -318,7 +320,7 @@ static inline void set_gpio_trigger(struct gpio_bank *bank, int gpio, readl_relaxed(bank->base + bank->regs->fallingdetect); if (likely(!(bank->non_wakeup_gpios & gpio_bit))) { - _gpio_rmw(base, bank->regs->wkup_en, gpio_bit, trigger != 0); + omap_gpio_rmw(base, bank->regs->wkup_en, gpio_bit, trigger != 0); bank->context.wake_en = readl_relaxed(bank->base + bank->regs->wkup_en); } @@ -354,7 +356,7 @@ exit: * This only applies to chips that can't do both rising and falling edge * detection at once. For all other chips, this function is a noop. */ -static void _toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio) +static void omap_toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio) { void __iomem *reg = bank->base; u32 l = 0; @@ -373,18 +375,18 @@ static void _toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio) writel_relaxed(l, reg); } #else -static void _toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio) {} +static void omap_toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio) {} #endif -static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, - unsigned trigger) +static int omap_set_gpio_triggering(struct gpio_bank *bank, int gpio, + unsigned trigger) { void __iomem *reg = bank->base; void __iomem *base = bank->base; u32 l = 0; if (bank->regs->leveldetect0 && bank->regs->wkup_en) { - set_gpio_trigger(bank, gpio, trigger); + omap_set_gpio_trigger(bank, gpio, trigger); } else if (bank->regs->irqctrl) { reg += bank->regs->irqctrl; @@ -414,7 +416,7 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, l |= BIT(gpio << 1); /* Enable wake-up during idle for dynamic tick */ - _gpio_rmw(base, bank->regs->wkup_en, BIT(gpio), trigger); + omap_gpio_rmw(base, bank->regs->wkup_en, BIT(gpio), trigger); bank->context.wake_en = readl_relaxed(bank->base + bank->regs->wkup_en); writel_relaxed(l, reg); @@ -422,7 +424,7 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, return 0; } -static void _enable_gpio_module(struct gpio_bank *bank, unsigned offset) +static void omap_enable_gpio_module(struct gpio_bank *bank, unsigned offset) { if (bank->regs->pinctrl) { void __iomem *reg = bank->base + bank->regs->pinctrl; @@ -443,7 +445,7 @@ static void _enable_gpio_module(struct gpio_bank *bank, unsigned offset) } } -static void _disable_gpio_module(struct gpio_bank *bank, unsigned offset) +static void omap_disable_gpio_module(struct gpio_bank *bank, unsigned offset) { void __iomem *base = bank->base; @@ -451,7 +453,7 @@ static void _disable_gpio_module(struct gpio_bank *bank, unsigned offset) !LINE_USED(bank->mod_usage, offset) && !LINE_USED(bank->irq_usage, offset)) { /* Disable wake-up during idle for dynamic tick */ - _gpio_rmw(base, bank->regs->wkup_en, BIT(offset), 0); + omap_gpio_rmw(base, bank->regs->wkup_en, BIT(offset), 0); bank->context.wake_en = readl_relaxed(bank->base + bank->regs->wkup_en); } @@ -468,16 +470,16 @@ static void _disable_gpio_module(struct gpio_bank *bank, unsigned offset) } } -static int gpio_is_input(struct gpio_bank *bank, int mask) +static int omap_gpio_is_input(struct gpio_bank *bank, int mask) { void __iomem *reg = bank->base + bank->regs->direction; return readl_relaxed(reg) & mask; } -static int gpio_irq_type(struct irq_data *d, unsigned type) +static int omap_gpio_irq_type(struct irq_data *d, unsigned type) { - struct gpio_bank *bank = _irq_data_get_bank(d); + struct gpio_bank *bank = omap_irq_data_get_bank(d); unsigned gpio = 0; int retval; unsigned long flags; @@ -492,7 +494,7 @@ static int gpio_irq_type(struct irq_data *d, unsigned type) #endif if (!gpio) - gpio = irq_to_gpio(bank, d->hwirq); + gpio = omap_irq_to_gpio(bank, d->hwirq); if (type & ~IRQ_TYPE_SENSE_MASK) return -EINVAL; @@ -503,11 +505,11 @@ static int gpio_irq_type(struct irq_data *d, unsigned type) spin_lock_irqsave(&bank->lock, flags); offset = GPIO_INDEX(bank, gpio); - retval = _set_gpio_triggering(bank, offset, type); + retval = omap_set_gpio_triggering(bank, offset, type); if (!LINE_USED(bank->mod_usage, offset)) { - _enable_gpio_module(bank, offset); - _set_gpio_direction(bank, offset, 1); - } else if (!gpio_is_input(bank, BIT(offset))) { + omap_enable_gpio_module(bank, offset); + omap_set_gpio_direction(bank, offset, 1); + } else if (!omap_gpio_is_input(bank, BIT(offset))) { spin_unlock_irqrestore(&bank->lock, flags); return -EINVAL; } @@ -523,7 +525,7 @@ static int gpio_irq_type(struct irq_data *d, unsigned type) return retval; } -static void _clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) +static void omap_clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) { void __iomem *reg = bank->base; @@ -540,12 +542,12 @@ static void _clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) readl_relaxed(reg); } -static inline void _clear_gpio_irqstatus(struct gpio_bank *bank, int gpio) +static inline void omap_clear_gpio_irqstatus(struct gpio_bank *bank, int gpio) { - _clear_gpio_irqbank(bank, GPIO_BIT(bank, gpio)); + omap_clear_gpio_irqbank(bank, GPIO_BIT(bank, gpio)); } -static u32 _get_gpio_irqbank_mask(struct gpio_bank *bank) +static u32 omap_get_gpio_irqbank_mask(struct gpio_bank *bank) { void __iomem *reg = bank->base; u32 l; @@ -559,7 +561,7 @@ static u32 _get_gpio_irqbank_mask(struct gpio_bank *bank) return l; } -static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) +static void omap_enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) { void __iomem *reg = bank->base; u32 l; @@ -581,7 +583,7 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) writel_relaxed(l, reg); } -static void _disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) +static void omap_disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) { void __iomem *reg = bank->base; u32 l; @@ -603,12 +605,13 @@ static void _disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) writel_relaxed(l, reg); } -static inline void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int enable) +static inline void omap_set_gpio_irqenable(struct gpio_bank *bank, int gpio, + int enable) { if (enable) - _enable_gpio_irqbank(bank, GPIO_BIT(bank, gpio)); + omap_enable_gpio_irqbank(bank, GPIO_BIT(bank, gpio)); else - _disable_gpio_irqbank(bank, GPIO_BIT(bank, gpio)); + omap_disable_gpio_irqbank(bank, GPIO_BIT(bank, gpio)); } /* @@ -619,7 +622,7 @@ static inline void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int ena * enabled. When system is suspended, only selected GPIO interrupts need * to have wake-up enabled. */ -static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable) +static int omap_set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable) { u32 gpio_bit = GPIO_BIT(bank, gpio); unsigned long flags; @@ -642,22 +645,22 @@ static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable) return 0; } -static void _reset_gpio(struct gpio_bank *bank, int gpio) +static void omap_reset_gpio(struct gpio_bank *bank, int gpio) { - _set_gpio_direction(bank, GPIO_INDEX(bank, gpio), 1); - _set_gpio_irqenable(bank, gpio, 0); - _clear_gpio_irqstatus(bank, gpio); - _set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), IRQ_TYPE_NONE); - _clear_gpio_debounce(bank, gpio); + omap_set_gpio_direction(bank, GPIO_INDEX(bank, gpio), 1); + omap_set_gpio_irqenable(bank, gpio, 0); + omap_clear_gpio_irqstatus(bank, gpio); + omap_set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), IRQ_TYPE_NONE); + omap_clear_gpio_debounce(bank, gpio); } /* Use disable_irq_wake() and enable_irq_wake() functions from drivers */ -static int gpio_wake_enable(struct irq_data *d, unsigned int enable) +static int omap_gpio_wake_enable(struct irq_data *d, unsigned int enable) { - struct gpio_bank *bank = _irq_data_get_bank(d); - unsigned int gpio = irq_to_gpio(bank, d->hwirq); + struct gpio_bank *bank = omap_irq_data_get_bank(d); + unsigned int gpio = omap_irq_to_gpio(bank, d->hwirq); - return _set_gpio_wakeup(bank, gpio, enable); + return omap_set_gpio_wakeup(bank, gpio, enable); } static int omap_gpio_request(struct gpio_chip *chip, unsigned offset) @@ -678,8 +681,8 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset) * not already been requested. */ if (!LINE_USED(bank->irq_usage, offset)) { - _set_gpio_triggering(bank, offset, IRQ_TYPE_NONE); - _enable_gpio_module(bank, offset); + omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE); + omap_enable_gpio_module(bank, offset); } bank->mod_usage |= BIT(offset); spin_unlock_irqrestore(&bank->lock, flags); @@ -694,8 +697,8 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset) spin_lock_irqsave(&bank->lock, flags); bank->mod_usage &= ~(BIT(offset)); - _disable_gpio_module(bank, offset); - _reset_gpio(bank, bank->chip.base + offset); + omap_disable_gpio_module(bank, offset); + omap_reset_gpio(bank, bank->chip.base + offset); spin_unlock_irqrestore(&bank->lock, flags); /* @@ -715,7 +718,7 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset) * line's interrupt handler has been run, we may miss some nested * interrupts. */ -static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) +static void omap_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) { void __iomem *isr_reg = NULL; u32 isr; @@ -738,7 +741,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) u32 isr_saved, level_mask = 0; u32 enabled; - enabled = _get_gpio_irqbank_mask(bank); + enabled = omap_get_gpio_irqbank_mask(bank); isr_saved = isr = readl_relaxed(isr_reg) & enabled; if (bank->level_mask) @@ -747,9 +750,9 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) /* clear edge sensitive interrupts before handler(s) are called so that we don't miss any interrupt occurred while executing them */ - _disable_gpio_irqbank(bank, isr_saved & ~level_mask); - _clear_gpio_irqbank(bank, isr_saved & ~level_mask); - _enable_gpio_irqbank(bank, isr_saved & ~level_mask); + omap_disable_gpio_irqbank(bank, isr_saved & ~level_mask); + omap_clear_gpio_irqbank(bank, isr_saved & ~level_mask); + omap_enable_gpio_irqbank(bank, isr_saved & ~level_mask); /* if there is only edge sensitive GPIO pin interrupts configured, we could unmask GPIO bank interrupt immediately */ @@ -773,7 +776,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) * This will be indicated in the bank toggle_mask. */ if (bank->toggle_mask & (BIT(bit))) - _toggle_gpio_edge_triggering(bank, bit); + omap_toggle_gpio_edge_triggering(bank, bit); generic_handle_irq(irq_find_mapping(bank->chip.irqdomain, bit)); @@ -789,18 +792,18 @@ exit: pm_runtime_put(bank->dev); } -static void gpio_irq_shutdown(struct irq_data *d) +static void omap_gpio_irq_shutdown(struct irq_data *d) { - struct gpio_bank *bank = _irq_data_get_bank(d); - unsigned int gpio = irq_to_gpio(bank, d->hwirq); + struct gpio_bank *bank = omap_irq_data_get_bank(d); + unsigned int gpio = omap_irq_to_gpio(bank, d->hwirq); unsigned long flags; unsigned offset = GPIO_INDEX(bank, gpio); spin_lock_irqsave(&bank->lock, flags); gpio_unlock_as_irq(&bank->chip, offset); bank->irq_usage &= ~(BIT(offset)); - _disable_gpio_module(bank, offset); - _reset_gpio(bank, gpio); + omap_disable_gpio_module(bank, offset); + omap_reset_gpio(bank, gpio); spin_unlock_irqrestore(&bank->lock, flags); /* @@ -811,57 +814,57 @@ static void gpio_irq_shutdown(struct irq_data *d) pm_runtime_put(bank->dev); } -static void gpio_ack_irq(struct irq_data *d) +static void omap_gpio_ack_irq(struct irq_data *d) { - struct gpio_bank *bank = _irq_data_get_bank(d); - unsigned int gpio = irq_to_gpio(bank, d->hwirq); + struct gpio_bank *bank = omap_irq_data_get_bank(d); + unsigned int gpio = omap_irq_to_gpio(bank, d->hwirq); - _clear_gpio_irqstatus(bank, gpio); + omap_clear_gpio_irqstatus(bank, gpio); } -static void gpio_mask_irq(struct irq_data *d) +static void omap_gpio_mask_irq(struct irq_data *d) { - struct gpio_bank *bank = _irq_data_get_bank(d); - unsigned int gpio = irq_to_gpio(bank, d->hwirq); + struct gpio_bank *bank = omap_irq_data_get_bank(d); + unsigned int gpio = omap_irq_to_gpio(bank, d->hwirq); unsigned long flags; spin_lock_irqsave(&bank->lock, flags); - _set_gpio_irqenable(bank, gpio, 0); - _set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), IRQ_TYPE_NONE); + omap_set_gpio_irqenable(bank, gpio, 0); + omap_set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), IRQ_TYPE_NONE); spin_unlock_irqrestore(&bank->lock, flags); } -static void gpio_unmask_irq(struct irq_data *d) +static void omap_gpio_unmask_irq(struct irq_data *d) { - struct gpio_bank *bank = _irq_data_get_bank(d); - unsigned int gpio = irq_to_gpio(bank, d->hwirq); + struct gpio_bank *bank = omap_irq_data_get_bank(d); + unsigned int gpio = omap_irq_to_gpio(bank, d->hwirq); unsigned int irq_mask = GPIO_BIT(bank, gpio); u32 trigger = irqd_get_trigger_type(d); unsigned long flags; spin_lock_irqsave(&bank->lock, flags); if (trigger) - _set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), trigger); + omap_set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), trigger); /* For level-triggered GPIOs, the clearing must be done after * the HW source is cleared, thus after the handler has run */ if (bank->level_mask & irq_mask) { - _set_gpio_irqenable(bank, gpio, 0); - _clear_gpio_irqstatus(bank, gpio); + omap_set_gpio_irqenable(bank, gpio, 0); + omap_clear_gpio_irqstatus(bank, gpio); } - _set_gpio_irqenable(bank, gpio, 1); + omap_set_gpio_irqenable(bank, gpio, 1); spin_unlock_irqrestore(&bank->lock, flags); } static struct irq_chip gpio_irq_chip = { .name = "GPIO", - .irq_shutdown = gpio_irq_shutdown, - .irq_ack = gpio_ack_irq, - .irq_mask = gpio_mask_irq, - .irq_unmask = gpio_unmask_irq, - .irq_set_type = gpio_irq_type, - .irq_set_wake = gpio_wake_enable, + .irq_shutdown = omap_gpio_irq_shutdown, + .irq_ack = omap_gpio_ack_irq, + .irq_mask = omap_gpio_mask_irq, + .irq_unmask = omap_gpio_unmask_irq, + .irq_set_type = omap_gpio_irq_type, + .irq_set_wake = omap_gpio_wake_enable, }; /*---------------------------------------------------------------------*/ @@ -918,7 +921,7 @@ static struct platform_device omap_mpuio_device = { /* could list the /proc/iomem resources */ }; -static inline void mpuio_init(struct gpio_bank *bank) +static inline void omap_mpuio_init(struct gpio_bank *bank) { platform_set_drvdata(&omap_mpuio_device, bank); @@ -928,7 +931,7 @@ static inline void mpuio_init(struct gpio_bank *bank) /*---------------------------------------------------------------------*/ -static int gpio_get_direction(struct gpio_chip *chip, unsigned offset) +static int omap_gpio_get_direction(struct gpio_chip *chip, unsigned offset) { struct gpio_bank *bank; unsigned long flags; @@ -943,19 +946,19 @@ static int gpio_get_direction(struct gpio_chip *chip, unsigned offset) return dir; } -static int gpio_input(struct gpio_chip *chip, unsigned offset) +static int omap_gpio_input(struct gpio_chip *chip, unsigned offset) { struct gpio_bank *bank; unsigned long flags; bank = container_of(chip, struct gpio_bank, chip); spin_lock_irqsave(&bank->lock, flags); - _set_gpio_direction(bank, offset, 1); + omap_set_gpio_direction(bank, offset, 1); spin_unlock_irqrestore(&bank->lock, flags); return 0; } -static int gpio_get(struct gpio_chip *chip, unsigned offset) +static int omap_gpio_get(struct gpio_chip *chip, unsigned offset) { struct gpio_bank *bank; u32 mask; @@ -963,13 +966,13 @@ static int gpio_get(struct gpio_chip *chip, unsigned offset) bank = container_of(chip, struct gpio_bank, chip); mask = (BIT(offset)); - if (gpio_is_input(bank, mask)) - return _get_gpio_datain(bank, offset); + if (omap_gpio_is_input(bank, mask)) + return omap_get_gpio_datain(bank, offset); else - return _get_gpio_dataout(bank, offset); + return omap_get_gpio_dataout(bank, offset); } -static int gpio_output(struct gpio_chip *chip, unsigned offset, int value) +static int omap_gpio_output(struct gpio_chip *chip, unsigned offset, int value) { struct gpio_bank *bank; unsigned long flags; @@ -977,13 +980,13 @@ static int gpio_output(struct gpio_chip *chip, unsigned offset, int value) bank = container_of(chip, struct gpio_bank, chip); spin_lock_irqsave(&bank->lock, flags); bank->set_dataout(bank, offset, value); - _set_gpio_direction(bank, offset, 0); + omap_set_gpio_direction(bank, offset, 0); spin_unlock_irqrestore(&bank->lock, flags); return 0; } -static int gpio_debounce(struct gpio_chip *chip, unsigned offset, - unsigned debounce) +static int omap_gpio_debounce(struct gpio_chip *chip, unsigned offset, + unsigned debounce) { struct gpio_bank *bank; unsigned long flags; @@ -991,13 +994,13 @@ static int gpio_debounce(struct gpio_chip *chip, unsigned offset, bank = container_of(chip, struct gpio_bank, chip); spin_lock_irqsave(&bank->lock, flags); - _set_gpio_debounce(bank, offset, debounce); + omap2_set_gpio_debounce(bank, offset, debounce); spin_unlock_irqrestore(&bank->lock, flags); return 0; } -static void gpio_set(struct gpio_chip *chip, unsigned offset, int value) +static void omap_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { struct gpio_bank *bank; unsigned long flags; @@ -1025,11 +1028,6 @@ static void __init omap_gpio_show_rev(struct gpio_bank *bank) called = true; } -/* This lock class tells lockdep that GPIO irqs are in a different - * category than their parents, so it won't report false recursion. - */ -static struct lock_class_key gpio_lock_class; - static void omap_gpio_mod_init(struct gpio_bank *bank) { void __iomem *base = bank->base; @@ -1043,8 +1041,10 @@ static void omap_gpio_mod_init(struct gpio_bank *bank) return; } - _gpio_rmw(base, bank->regs->irqenable, l, bank->regs->irqenable_inv); - _gpio_rmw(base, bank->regs->irqstatus, l, !bank->regs->irqenable_inv); + omap_gpio_rmw(base, bank->regs->irqenable, l, + bank->regs->irqenable_inv); + omap_gpio_rmw(base, bank->regs->irqstatus, l, + !bank->regs->irqenable_inv); if (bank->regs->debounce_en) writel_relaxed(0, base + bank->regs->debounce_en); @@ -1078,10 +1078,10 @@ omap_mpuio_alloc_gc(struct gpio_bank *bank, unsigned int irq_start, /* NOTE: No ack required, reading IRQ status clears it. */ ct->chip.irq_mask = irq_gc_mask_set_bit; ct->chip.irq_unmask = irq_gc_mask_clr_bit; - ct->chip.irq_set_type = gpio_irq_type; + ct->chip.irq_set_type = omap_gpio_irq_type; if (bank->regs->wkup_en) - ct->chip.irq_set_wake = gpio_wake_enable; + ct->chip.irq_set_wake = omap_gpio_wake_enable; ct->regs.mask = OMAP_MPUIO_GPIO_INT / bank->stride; irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE, @@ -1101,12 +1101,12 @@ static int omap_gpio_chip_init(struct gpio_bank *bank) */ bank->chip.request = omap_gpio_request; bank->chip.free = omap_gpio_free; - bank->chip.get_direction = gpio_get_direction; - bank->chip.direction_input = gpio_input; - bank->chip.get = gpio_get; - bank->chip.direction_output = gpio_output; - bank->chip.set_debounce = gpio_debounce; - bank->chip.set = gpio_set; + bank->chip.get_direction = omap_gpio_get_direction; + bank->chip.direction_input = omap_gpio_input; + bank->chip.get = omap_gpio_get; + bank->chip.direction_output = omap_gpio_output; + bank->chip.set_debounce = omap_gpio_debounce; + bank->chip.set = omap_gpio_set; if (bank->is_mpuio) { bank->chip.label = "mpuio"; if (bank->regs->wkup_en) @@ -1138,7 +1138,7 @@ static int omap_gpio_chip_init(struct gpio_bank *bank) #endif ret = gpiochip_irqchip_add(&bank->chip, &gpio_irq_chip, - irq_base, gpio_irq_handler, + irq_base, omap_gpio_irq_handler, IRQ_TYPE_NONE); if (ret) { @@ -1148,11 +1148,10 @@ static int omap_gpio_chip_init(struct gpio_bank *bank) } gpiochip_set_chained_irqchip(&bank->chip, &gpio_irq_chip, - bank->irq, gpio_irq_handler); + bank->irq, omap_gpio_irq_handler); for (j = 0; j < bank->width; j++) { int irq = irq_find_mapping(bank->chip.irqdomain, j); - irq_set_lockdep_class(irq, &gpio_lock_class); if (bank->is_mpuio) { omap_mpuio_alloc_gc(bank, irq, bank->width); irq_set_chip_and_handler(irq, NULL, NULL); @@ -1217,9 +1216,9 @@ static int omap_gpio_probe(struct platform_device *pdev) } if (bank->regs->set_dataout && bank->regs->clr_dataout) - bank->set_dataout = _set_gpio_dataout_reg; + bank->set_dataout = omap_set_gpio_dataout_reg; else - bank->set_dataout = _set_gpio_dataout_mask; + bank->set_dataout = omap_set_gpio_dataout_mask; spin_lock_init(&bank->lock); @@ -1238,7 +1237,7 @@ static int omap_gpio_probe(struct platform_device *pdev) pm_runtime_get_sync(bank->dev); if (bank->is_mpuio) - mpuio_init(bank); + omap_mpuio_init(bank); omap_gpio_mod_init(bank); @@ -1320,7 +1319,7 @@ update_gpio_context_count: bank->context_loss_count = bank->get_context_loss_count(bank->dev); - _gpio_dbck_disable(bank); + omap_gpio_dbck_disable(bank); spin_unlock_irqrestore(&bank->lock, flags); return 0; @@ -1351,7 +1350,7 @@ static int omap_gpio_runtime_resume(struct device *dev) bank->get_context_loss_count(bank->dev); } - _gpio_dbck_enable(bank); + omap_gpio_dbck_enable(bank); /* * In ->runtime_suspend(), level-triggered, wakeup-enabled diff --git a/drivers/gpio/gpio-palmas.c b/drivers/gpio/gpio-palmas.c index 86bdbe362068..171a6389f9ce 100644 --- a/drivers/gpio/gpio-palmas.c +++ b/drivers/gpio/gpio-palmas.c @@ -210,7 +210,8 @@ static int palmas_gpio_remove(struct platform_device *pdev) { struct palmas_gpio *palmas_gpio = platform_get_drvdata(pdev); - return gpiochip_remove(&palmas_gpio->gpio_chip); + gpiochip_remove(&palmas_gpio->gpio_chip); + return 0; } static struct platform_driver palmas_gpio_driver = { diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index e721a37c3473..f9961eea2120 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -765,12 +765,7 @@ static int pca953x_remove(struct i2c_client *client) } } - ret = gpiochip_remove(&chip->gpio_chip); - if (ret) { - dev_err(&client->dev, "%s failed, %d\n", - "gpiochip_remove()", ret); - return ret; - } + gpiochip_remove(&chip->gpio_chip); return 0; } diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index 27b46751ea7e..236708ad0a5b 100644 --- a/drivers/gpio/gpio-pcf857x.c +++ b/drivers/gpio/gpio-pcf857x.c @@ -444,9 +444,7 @@ static int pcf857x_remove(struct i2c_client *client) if (client->irq) pcf857x_irq_domain_cleanup(gpio); - status = gpiochip_remove(&gpio->chip); - if (status) - dev_err(&client->dev, "%s --> %d\n", "remove", status); + gpiochip_remove(&gpio->chip); return status; } diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c index d6eac9b17db9..e0ac549dccb5 100644 --- a/drivers/gpio/gpio-pch.c +++ b/drivers/gpio/gpio-pch.c @@ -426,9 +426,7 @@ end: err_request_irq: irq_free_descs(irq_base, gpio_pins[chip->ioh]); - - if (gpiochip_remove(&chip->gpio)) - dev_err(&pdev->dev, "%s gpiochip_remove failed\n", __func__); + gpiochip_remove(&chip->gpio); err_gpiochip_add: pci_iounmap(pdev, chip->base); @@ -447,7 +445,6 @@ err_pci_enable: static void pch_gpio_remove(struct pci_dev *pdev) { - int err; struct pch_gpio *chip = pci_get_drvdata(pdev); if (chip->irq_base != -1) { @@ -456,10 +453,7 @@ static void pch_gpio_remove(struct pci_dev *pdev) irq_free_descs(chip->irq_base, gpio_pins[chip->ioh]); } - err = gpiochip_remove(&chip->gpio); - if (err) - dev_err(&pdev->dev, "Failed gpiochip_remove\n"); - + gpiochip_remove(&chip->gpio); pci_iounmap(pdev, chip->base); pci_release_regions(pdev); pci_disable_device(pdev); diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c index 42e6e64f2120..ad3feec0075e 100644 --- a/drivers/gpio/gpio-pxa.c +++ b/drivers/gpio/gpio-pxa.c @@ -498,7 +498,7 @@ static int pxa_gpio_nums(struct platform_device *pdev) } #ifdef CONFIG_OF -static struct of_device_id pxa_gpio_dt_ids[] = { +static const struct of_device_id pxa_gpio_dt_ids[] = { { .compatible = "intel,pxa25x-gpio", .data = &pxa25x_id, }, { .compatible = "intel,pxa26x-gpio", .data = &pxa26x_id, }, { .compatible = "intel,pxa27x-gpio", .data = &pxa27x_id, }, @@ -649,6 +649,11 @@ static int pxa_gpio_probe(struct platform_device *pdev) handle_edge_irq); set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); } + } else { + if (irq0 > 0) + irq_set_chained_handler(irq0, pxa_gpio_demux_handler); + if (irq1 > 0) + irq_set_chained_handler(irq1, pxa_gpio_demux_handler); } irq_set_chained_handler(irq_mux, pxa_gpio_demux_handler); diff --git a/drivers/gpio/gpio-rc5t583.c b/drivers/gpio/gpio-rc5t583.c index 562b0c4d9cc8..769233d2da6d 100644 --- a/drivers/gpio/gpio-rc5t583.c +++ b/drivers/gpio/gpio-rc5t583.c @@ -148,7 +148,8 @@ static int rc5t583_gpio_remove(struct platform_device *pdev) { struct rc5t583_gpio *rc5t583_gpio = platform_get_drvdata(pdev); - return gpiochip_remove(&rc5t583_gpio->gpio_chip); + gpiochip_remove(&rc5t583_gpio->gpio_chip); + return 0; } static struct platform_driver rc5t583_gpio_driver = { diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index b6ae89ea8811..bf6c09450fee 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -240,9 +240,9 @@ static int gpio_rcar_get(struct gpio_chip *chip, unsigned offset) /* testing on r8a7790 shows that INDT does not show correct pin state * when configured as output, so use OUTDT in case of output pins */ if (gpio_rcar_read(gpio_to_priv(chip), INOUTSEL) & bit) - return (int)(gpio_rcar_read(gpio_to_priv(chip), OUTDT) & bit); + return !!(gpio_rcar_read(gpio_to_priv(chip), OUTDT) & bit); else - return (int)(gpio_rcar_read(gpio_to_priv(chip), INDT) & bit); + return !!(gpio_rcar_read(gpio_to_priv(chip), INDT) & bit); } static void gpio_rcar_set(struct gpio_chip *chip, unsigned offset, int value) @@ -472,11 +472,8 @@ err0: static int gpio_rcar_remove(struct platform_device *pdev) { struct gpio_rcar_priv *p = platform_get_drvdata(pdev); - int ret; - ret = gpiochip_remove(&p->gpio_chip); - if (ret) - return ret; + gpiochip_remove(&p->gpio_chip); irq_domain_remove(p->irq_domain); pm_runtime_put(&pdev->dev); diff --git a/drivers/gpio/gpio-rdc321x.c b/drivers/gpio/gpio-rdc321x.c index 9fa7e53331c9..d729bc8a554d 100644 --- a/drivers/gpio/gpio-rdc321x.c +++ b/drivers/gpio/gpio-rdc321x.c @@ -199,14 +199,11 @@ static int rdc321x_gpio_probe(struct platform_device *pdev) static int rdc321x_gpio_remove(struct platform_device *pdev) { - int ret; struct rdc321x_gpio *rdc321x_gpio_dev = platform_get_drvdata(pdev); - ret = gpiochip_remove(&rdc321x_gpio_dev->chip); - if (ret) - dev_err(&pdev->dev, "failed to unregister chip\n"); + gpiochip_remove(&rdc321x_gpio_dev->chip); - return ret; + return 0; } static struct platform_driver rdc321x_gpio_driver = { diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c index a9b1cd16c848..41e91d70301e 100644 --- a/drivers/gpio/gpio-sch.c +++ b/drivers/gpio/gpio-sch.c @@ -290,8 +290,7 @@ static int sch_gpio_probe(struct platform_device *pdev) return 0; err_sch_gpio_resume: - if (gpiochip_remove(&sch_gpio_core)) - dev_err(&pdev->dev, "%s gpiochip_remove failed\n", __func__); + gpiochip_remove(&sch_gpio_core); err_sch_gpio_core: release_region(res->start, resource_size(res)); @@ -304,23 +303,14 @@ static int sch_gpio_remove(struct platform_device *pdev) { struct resource *res; if (gpio_ba) { - int err; - err = gpiochip_remove(&sch_gpio_core); - if (err) - dev_err(&pdev->dev, "%s failed, %d\n", - "gpiochip_remove()", err); - err = gpiochip_remove(&sch_gpio_resume); - if (err) - dev_err(&pdev->dev, "%s failed, %d\n", - "gpiochip_remove()", err); + gpiochip_remove(&sch_gpio_core); + gpiochip_remove(&sch_gpio_resume); res = platform_get_resource(pdev, IORESOURCE_IO, 0); release_region(res->start, resource_size(res)); gpio_ba = 0; - - return err; } return 0; diff --git a/drivers/gpio/gpio-sch311x.c b/drivers/gpio/gpio-sch311x.c index f942b80ee403..0cb11413e814 100644 --- a/drivers/gpio/gpio-sch311x.c +++ b/drivers/gpio/gpio-sch311x.c @@ -291,14 +291,12 @@ static int sch311x_gpio_remove(struct platform_device *pdev) { struct sch311x_pdev_data *pdata = pdev->dev.platform_data; struct sch311x_gpio_priv *priv = platform_get_drvdata(pdev); - int err, i; + int i; release_region(pdata->runtime_reg + GP1, 6); for (i = 0; i < ARRAY_SIZE(priv->blocks); i++) { - err = gpiochip_remove(&priv->blocks[i].chip); - if (err) - return err; + gpiochip_remove(&priv->blocks[i].chip); dev_info(&pdev->dev, "SMSC SCH311x GPIO block %d unregistered.\n", i); } diff --git a/drivers/gpio/gpio-sodaville.c b/drivers/gpio/gpio-sodaville.c index 7c6c518929bc..d8da36cd8123 100644 --- a/drivers/gpio/gpio-sodaville.c +++ b/drivers/gpio/gpio-sodaville.c @@ -265,9 +265,7 @@ static void sdv_gpio_remove(struct pci_dev *pdev) free_irq(pdev->irq, sd); irq_free_descs(sd->irq_base, SDV_NUM_PUB_GPIOS); - if (gpiochip_remove(&sd->bgpio.gc)) - dev_err(&pdev->dev, "gpiochip_remove() failed.\n"); - + gpiochip_remove(&sd->bgpio.gc); pci_release_region(pdev, GPIO_BAR); iounmap(sd->gpio_pub_base); pci_disable_device(pdev); diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index 628b58494294..845025a57240 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -10,8 +10,6 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/gpio.h> -#include <linux/irq.h> -#include <linux/irqdomain.h> #include <linux/interrupt.h> #include <linux/of.h> #include <linux/mfd/stmpe.h> @@ -31,9 +29,7 @@ struct stmpe_gpio { struct stmpe *stmpe; struct device *dev; struct mutex irq_lock; - struct irq_domain *domain; unsigned norequest_mask; - /* Caches of interrupt control registers for bus_lock */ u8 regs[CACHE_NR_REGS][CACHE_NR_BANKS]; u8 oldregs[CACHE_NR_REGS][CACHE_NR_BANKS]; @@ -101,13 +97,6 @@ static int stmpe_gpio_direction_input(struct gpio_chip *chip, return stmpe_set_bits(stmpe, reg, mask, 0); } -static int stmpe_gpio_to_irq(struct gpio_chip *chip, unsigned offset) -{ - struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip); - - return irq_create_mapping(stmpe_gpio->domain, offset); -} - static int stmpe_gpio_request(struct gpio_chip *chip, unsigned offset) { struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip); @@ -126,14 +115,14 @@ static struct gpio_chip template_chip = { .get = stmpe_gpio_get, .direction_output = stmpe_gpio_direction_output, .set = stmpe_gpio_set, - .to_irq = stmpe_gpio_to_irq, .request = stmpe_gpio_request, .can_sleep = true, }; static int stmpe_gpio_irq_set_type(struct irq_data *d, unsigned int type) { - struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(gc); int offset = d->hwirq; int regoffset = offset / 8; int mask = 1 << (offset % 8); @@ -160,14 +149,16 @@ static int stmpe_gpio_irq_set_type(struct irq_data *d, unsigned int type) static void stmpe_gpio_irq_lock(struct irq_data *d) { - struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(gc); mutex_lock(&stmpe_gpio->irq_lock); } static void stmpe_gpio_irq_sync_unlock(struct irq_data *d) { - struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(gc); struct stmpe *stmpe = stmpe_gpio->stmpe; int num_banks = DIV_ROUND_UP(stmpe->num_gpios, 8); static const u8 regmap[] = { @@ -200,7 +191,8 @@ static void stmpe_gpio_irq_sync_unlock(struct irq_data *d) static void stmpe_gpio_irq_mask(struct irq_data *d) { - struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(gc); int offset = d->hwirq; int regoffset = offset / 8; int mask = 1 << (offset % 8); @@ -210,7 +202,8 @@ static void stmpe_gpio_irq_mask(struct irq_data *d) static void stmpe_gpio_irq_unmask(struct irq_data *d) { - struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(gc); int offset = d->hwirq; int regoffset = offset / 8; int mask = 1 << (offset % 8); @@ -253,7 +246,7 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev) while (stat) { int bit = __ffs(stat); int line = bank * 8 + bit; - int child_irq = irq_find_mapping(stmpe_gpio->domain, + int child_irq = irq_find_mapping(stmpe_gpio->chip.irqdomain, line); handle_nested_irq(child_irq); @@ -271,56 +264,6 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev) return IRQ_HANDLED; } -static int stmpe_gpio_irq_map(struct irq_domain *d, unsigned int irq, - irq_hw_number_t hwirq) -{ - struct stmpe_gpio *stmpe_gpio = d->host_data; - - if (!stmpe_gpio) - return -EINVAL; - - irq_set_chip_data(irq, stmpe_gpio); - irq_set_chip_and_handler(irq, &stmpe_gpio_irq_chip, - handle_simple_irq); - irq_set_nested_thread(irq, 1); -#ifdef CONFIG_ARM - set_irq_flags(irq, IRQF_VALID); -#else - irq_set_noprobe(irq); -#endif - - return 0; -} - -static void stmpe_gpio_irq_unmap(struct irq_domain *d, unsigned int irq) -{ -#ifdef CONFIG_ARM - set_irq_flags(irq, 0); -#endif - irq_set_chip_and_handler(irq, NULL, NULL); - irq_set_chip_data(irq, NULL); -} - -static const struct irq_domain_ops stmpe_gpio_irq_simple_ops = { - .unmap = stmpe_gpio_irq_unmap, - .map = stmpe_gpio_irq_map, - .xlate = irq_domain_xlate_twocell, -}; - -static int stmpe_gpio_irq_init(struct stmpe_gpio *stmpe_gpio, - struct device_node *np) -{ - stmpe_gpio->domain = irq_domain_add_simple(np, - stmpe_gpio->chip.ngpio, 0, - &stmpe_gpio_irq_simple_ops, stmpe_gpio); - if (!stmpe_gpio->domain) { - dev_err(stmpe_gpio->dev, "failed to create irqdomain\n"); - return -ENOSYS; - } - - return 0; -} - static int stmpe_gpio_probe(struct platform_device *pdev) { struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent); @@ -358,30 +301,37 @@ static int stmpe_gpio_probe(struct platform_device *pdev) if (irq < 0) dev_info(&pdev->dev, - "device configured in no-irq mode; " + "device configured in no-irq mode: " "irqs are not available\n"); ret = stmpe_enable(stmpe, STMPE_BLOCK_GPIO); if (ret) goto out_free; - if (irq >= 0) { - ret = stmpe_gpio_irq_init(stmpe_gpio, np); - if (ret) - goto out_disable; - - ret = request_threaded_irq(irq, NULL, stmpe_gpio_irq, - IRQF_ONESHOT, "stmpe-gpio", stmpe_gpio); + if (irq > 0) { + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, + stmpe_gpio_irq, IRQF_ONESHOT, + "stmpe-gpio", stmpe_gpio); if (ret) { dev_err(&pdev->dev, "unable to get irq: %d\n", ret); goto out_disable; } + ret = gpiochip_irqchip_add(&stmpe_gpio->chip, + &stmpe_gpio_irq_chip, + 0, + handle_simple_irq, + IRQ_TYPE_NONE); + if (ret) { + dev_err(&pdev->dev, + "could not connect irqchip to gpiochip\n"); + return ret; + } } ret = gpiochip_add(&stmpe_gpio->chip); if (ret) { dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret); - goto out_freeirq; + goto out_disable; } if (pdata && pdata->setup) @@ -391,9 +341,6 @@ static int stmpe_gpio_probe(struct platform_device *pdev) return 0; -out_freeirq: - if (irq >= 0) - free_irq(irq, stmpe_gpio); out_disable: stmpe_disable(stmpe, STMPE_BLOCK_GPIO); out_free: @@ -406,24 +353,14 @@ static int stmpe_gpio_remove(struct platform_device *pdev) struct stmpe_gpio *stmpe_gpio = platform_get_drvdata(pdev); struct stmpe *stmpe = stmpe_gpio->stmpe; struct stmpe_gpio_platform_data *pdata = stmpe->pdata->gpio; - int irq = platform_get_irq(pdev, 0); - int ret; if (pdata && pdata->remove) pdata->remove(stmpe, stmpe_gpio->chip.base); - ret = gpiochip_remove(&stmpe_gpio->chip); - if (ret < 0) { - dev_err(stmpe_gpio->dev, - "unable to remove gpiochip: %d\n", ret); - return ret; - } + gpiochip_remove(&stmpe_gpio->chip); stmpe_disable(stmpe, STMPE_BLOCK_GPIO); - if (irq >= 0) - free_irq(irq, stmpe_gpio); - kfree(stmpe_gpio); return 0; diff --git a/drivers/gpio/gpio-sx150x.c b/drivers/gpio/gpio-sx150x.c index b51ca9f5c140..bce6c6108f20 100644 --- a/drivers/gpio/gpio-sx150x.c +++ b/drivers/gpio/gpio-sx150x.c @@ -615,19 +615,16 @@ static int sx150x_probe(struct i2c_client *client, return 0; probe_fail_post_gpiochip_add: - WARN_ON(gpiochip_remove(&chip->gpio_chip) < 0); + gpiochip_remove(&chip->gpio_chip); return rc; } static int sx150x_remove(struct i2c_client *client) { struct sx150x_chip *chip; - int rc; chip = i2c_get_clientdata(client); - rc = gpiochip_remove(&chip->gpio_chip); - if (rc < 0) - return rc; + gpiochip_remove(&chip->gpio_chip); if (chip->irq_summary >= 0) sx150x_remove_irq_chip(chip); diff --git a/drivers/gpio/gpio-syscon.c b/drivers/gpio/gpio-syscon.c index b50fe1297748..30884fbc750d 100644 --- a/drivers/gpio/gpio-syscon.c +++ b/drivers/gpio/gpio-syscon.c @@ -172,7 +172,8 @@ static int syscon_gpio_remove(struct platform_device *pdev) { struct syscon_gpio_priv *priv = platform_get_drvdata(pdev); - return gpiochip_remove(&priv->chip); + gpiochip_remove(&priv->chip); + return 0; } static struct platform_driver syscon_gpio_driver = { diff --git a/drivers/gpio/gpio-tb10x.c b/drivers/gpio/gpio-tb10x.c index 07bce97647a6..9e615be8032c 100644 --- a/drivers/gpio/gpio-tb10x.c +++ b/drivers/gpio/gpio-tb10x.c @@ -291,7 +291,6 @@ fail_ioremap: static int __exit tb10x_gpio_remove(struct platform_device *pdev) { struct tb10x_gpio *tb10x_gpio = platform_get_drvdata(pdev); - int ret; if (tb10x_gpio->gc.to_irq) { irq_remove_generic_chip(tb10x_gpio->domain->gc->gc[0], @@ -300,9 +299,7 @@ static int __exit tb10x_gpio_remove(struct platform_device *pdev) irq_domain_remove(tb10x_gpio->domain); free_irq(tb10x_gpio->irq, tb10x_gpio); } - ret = gpiochip_remove(&tb10x_gpio->gc); - if (ret) - return ret; + gpiochip_remove(&tb10x_gpio->gc); return 0; } diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c index 51f7cbd9ff71..7324869c38e0 100644 --- a/drivers/gpio/gpio-tc3589x.c +++ b/drivers/gpio/gpio-tc3589x.c @@ -313,17 +313,11 @@ static int tc3589x_gpio_remove(struct platform_device *pdev) struct tc3589x_gpio *tc3589x_gpio = platform_get_drvdata(pdev); struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; struct tc3589x_gpio_platform_data *pdata = tc3589x->pdata->gpio; - int ret; if (pdata && pdata->remove) pdata->remove(tc3589x, tc3589x_gpio->chip.base); - ret = gpiochip_remove(&tc3589x_gpio->chip); - if (ret < 0) { - dev_err(tc3589x_gpio->dev, - "unable to remove gpiochip: %d\n", ret); - return ret; - } + gpiochip_remove(&tc3589x_gpio->chip); return 0; } diff --git a/drivers/gpio/gpio-timberdale.c b/drivers/gpio/gpio-timberdale.c index efc7c129016d..a685a3cbbc81 100644 --- a/drivers/gpio/gpio-timberdale.c +++ b/drivers/gpio/gpio-timberdale.c @@ -307,7 +307,6 @@ static int timbgpio_probe(struct platform_device *pdev) static int timbgpio_remove(struct platform_device *pdev) { - int err; struct timbgpio_platform_data *pdata = dev_get_platdata(&pdev->dev); struct timbgpio *tgpio = platform_get_drvdata(pdev); int irq = platform_get_irq(pdev, 0); @@ -323,9 +322,7 @@ static int timbgpio_remove(struct platform_device *pdev) irq_set_handler_data(irq, NULL); } - err = gpiochip_remove(&tgpio->gpio); - if (err) - printk(KERN_ERR DRIVER_NAME": failed to remove gpio_chip\n"); + gpiochip_remove(&tgpio->gpio); return 0; } diff --git a/drivers/gpio/gpio-tps6586x.c b/drivers/gpio/gpio-tps6586x.c index a69fbea41253..9c9238e838a9 100644 --- a/drivers/gpio/gpio-tps6586x.c +++ b/drivers/gpio/gpio-tps6586x.c @@ -137,7 +137,8 @@ static int tps6586x_gpio_remove(struct platform_device *pdev) { struct tps6586x_gpio *tps6586x_gpio = platform_get_drvdata(pdev); - return gpiochip_remove(&tps6586x_gpio->gpio_chip); + gpiochip_remove(&tps6586x_gpio->gpio_chip); + return 0; } static struct platform_driver tps6586x_gpio_driver = { diff --git a/drivers/gpio/gpio-tps65910.c b/drivers/gpio/gpio-tps65910.c index e2f8cda235ea..88f1f5ff4e96 100644 --- a/drivers/gpio/gpio-tps65910.c +++ b/drivers/gpio/gpio-tps65910.c @@ -190,7 +190,8 @@ static int tps65910_gpio_remove(struct platform_device *pdev) { struct tps65910_gpio *tps65910_gpio = platform_get_drvdata(pdev); - return gpiochip_remove(&tps65910_gpio->gpio_chip); + gpiochip_remove(&tps65910_gpio->gpio_chip); + return 0; } static struct platform_driver tps65910_gpio_driver = { diff --git a/drivers/gpio/gpio-tps65912.c b/drivers/gpio/gpio-tps65912.c index 59ee486cb8b9..22052d84c63b 100644 --- a/drivers/gpio/gpio-tps65912.c +++ b/drivers/gpio/gpio-tps65912.c @@ -117,7 +117,8 @@ static int tps65912_gpio_remove(struct platform_device *pdev) { struct tps65912_gpio_data *tps65912_gpio = platform_get_drvdata(pdev); - return gpiochip_remove(&tps65912_gpio->gpio_chip); + gpiochip_remove(&tps65912_gpio->gpio_chip); + return 0; } static struct platform_driver tps65912_gpio_driver = { diff --git a/drivers/gpio/gpio-ts5500.c b/drivers/gpio/gpio-ts5500.c index 3df3ebdb3e52..de18591ff11e 100644 --- a/drivers/gpio/gpio-ts5500.c +++ b/drivers/gpio/gpio-ts5500.c @@ -427,8 +427,7 @@ static int ts5500_dio_probe(struct platform_device *pdev) return 0; cleanup: - if (gpiochip_remove(&priv->gpio_chip)) - dev_err(dev, "failed to remove gpio chip\n"); + gpiochip_remove(&priv->gpio_chip); return ret; } @@ -437,7 +436,8 @@ static int ts5500_dio_remove(struct platform_device *pdev) struct ts5500_priv *priv = platform_get_drvdata(pdev); ts5500_disable_irq(priv); - return gpiochip_remove(&priv->gpio_chip); + gpiochip_remove(&priv->gpio_chip); + return 0; } static struct platform_device_id ts5500_dio_ids[] = { diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index 3ebb1a5ff22e..118828b3736f 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c @@ -554,7 +554,7 @@ no_irqs: platform_set_drvdata(pdev, priv); - if (pdata && pdata->setup) { + if (pdata->setup) { int status; status = pdata->setup(&pdev->dev, priv->gpio_chip.base, @@ -583,9 +583,7 @@ static int gpio_twl4030_remove(struct platform_device *pdev) } } - status = gpiochip_remove(&priv->gpio_chip); - if (status < 0) - return status; + gpiochip_remove(&priv->gpio_chip); if (is_module()) return 0; diff --git a/drivers/gpio/gpio-twl6040.c b/drivers/gpio/gpio-twl6040.c index 0caf5cd1b47d..f28e04b88aa9 100644 --- a/drivers/gpio/gpio-twl6040.c +++ b/drivers/gpio/gpio-twl6040.c @@ -111,7 +111,8 @@ static int gpo_twl6040_probe(struct platform_device *pdev) static int gpo_twl6040_remove(struct platform_device *pdev) { - return gpiochip_remove(&twl6040gpo_chip); + gpiochip_remove(&twl6040gpo_chip); + return 0; } /* Note: this hardware lives inside an I2C-based multi-function device. */ diff --git a/drivers/gpio/gpio-ucb1400.c b/drivers/gpio/gpio-ucb1400.c index 2445fe771179..d502825159b9 100644 --- a/drivers/gpio/gpio-ucb1400.c +++ b/drivers/gpio/gpio-ucb1400.c @@ -70,7 +70,7 @@ static int ucb1400_gpio_probe(struct platform_device *dev) if (err) goto err; - if (ucb && ucb->gpio_setup) + if (ucb->gpio_setup) err = ucb->gpio_setup(&dev->dev, ucb->gc.ngpio); err: @@ -89,7 +89,7 @@ static int ucb1400_gpio_remove(struct platform_device *dev) return err; } - err = gpiochip_remove(&ucb->gc); + gpiochip_remove(&ucb->gc); return err; } diff --git a/drivers/gpio/gpio-viperboard.c b/drivers/gpio/gpio-viperboard.c index 79e3b5836712..e2a11f27807f 100644 --- a/drivers/gpio/gpio-viperboard.c +++ b/drivers/gpio/gpio-viperboard.c @@ -446,8 +446,7 @@ static int vprbrd_gpio_probe(struct platform_device *pdev) return ret; err_gpiob: - if (gpiochip_remove(&vb_gpio->gpioa)) - dev_err(&pdev->dev, "%s gpiochip_remove failed\n", __func__); + gpiochip_remove(&vb_gpio->gpioa); err_gpioa: return ret; @@ -456,13 +455,10 @@ err_gpioa: static int vprbrd_gpio_remove(struct platform_device *pdev) { struct vprbrd_gpio *vb_gpio = platform_get_drvdata(pdev); - int ret; - ret = gpiochip_remove(&vb_gpio->gpiob); - if (ret == 0) - ret = gpiochip_remove(&vb_gpio->gpioa); + gpiochip_remove(&vb_gpio->gpiob); - return ret; + return 0; } static struct platform_driver vprbrd_gpio_driver = { diff --git a/drivers/gpio/gpio-vr41xx.c b/drivers/gpio/gpio-vr41xx.c index 66cbcc108e62..dbf28fa03f67 100644 --- a/drivers/gpio/gpio-vr41xx.c +++ b/drivers/gpio/gpio-vr41xx.c @@ -515,7 +515,7 @@ static int giu_probe(struct platform_device *pdev) struct resource *res; unsigned int trigger, i, pin; struct irq_chip *chip; - int irq, retval; + int irq, ret; switch (pdev->id) { case GPIO_50PINS_PULLUPDOWN: @@ -544,7 +544,11 @@ static int giu_probe(struct platform_device *pdev) vr41xx_gpio_chip.dev = &pdev->dev; - retval = gpiochip_add(&vr41xx_gpio_chip); + ret = gpiochip_add(&vr41xx_gpio_chip); + if (!ret) { + iounmap(giu_base); + return -ENODEV; + } giu_write(GIUINTENL, 0); giu_write(GIUINTENH, 0); diff --git a/drivers/gpio/gpio-vx855.c b/drivers/gpio/gpio-vx855.c index 0fd23b6a753d..85971d4e23c1 100644 --- a/drivers/gpio/gpio-vx855.c +++ b/drivers/gpio/gpio-vx855.c @@ -288,8 +288,7 @@ static int vx855gpio_remove(struct platform_device *pdev) struct vx855_gpio *vg = platform_get_drvdata(pdev); struct resource *res; - if (gpiochip_remove(&vg->gpio)) - dev_err(&pdev->dev, "unable to remove gpio_chip?\n"); + gpiochip_remove(&vg->gpio); if (vg->gpi_reserved) { res = platform_get_resource(pdev, IORESOURCE_IO, 0); diff --git a/drivers/gpio/gpio-wm831x.c b/drivers/gpio/gpio-wm831x.c index b18a1a26425e..58ce75c188b7 100644 --- a/drivers/gpio/gpio-wm831x.c +++ b/drivers/gpio/gpio-wm831x.c @@ -279,7 +279,8 @@ static int wm831x_gpio_remove(struct platform_device *pdev) { struct wm831x_gpio *wm831x_gpio = platform_get_drvdata(pdev); - return gpiochip_remove(&wm831x_gpio->gpio_chip); + gpiochip_remove(&wm831x_gpio->gpio_chip); + return 0; } static struct platform_driver wm831x_gpio_driver = { diff --git a/drivers/gpio/gpio-wm8350.c b/drivers/gpio/gpio-wm8350.c index 2487f9d575d3..060b89303bb6 100644 --- a/drivers/gpio/gpio-wm8350.c +++ b/drivers/gpio/gpio-wm8350.c @@ -145,7 +145,8 @@ static int wm8350_gpio_remove(struct platform_device *pdev) { struct wm8350_gpio_data *wm8350_gpio = platform_get_drvdata(pdev); - return gpiochip_remove(&wm8350_gpio->gpio_chip); + gpiochip_remove(&wm8350_gpio->gpio_chip); + return 0; } static struct platform_driver wm8350_gpio_driver = { diff --git a/drivers/gpio/gpio-wm8994.c b/drivers/gpio/gpio-wm8994.c index d93b6b581677..6f5e42db4b9e 100644 --- a/drivers/gpio/gpio-wm8994.c +++ b/drivers/gpio/gpio-wm8994.c @@ -285,7 +285,8 @@ static int wm8994_gpio_remove(struct platform_device *pdev) { struct wm8994_gpio *wm8994_gpio = platform_get_drvdata(pdev); - return gpiochip_remove(&wm8994_gpio->gpio_chip); + gpiochip_remove(&wm8994_gpio->gpio_chip); + return 0; } static struct platform_driver wm8994_gpio_driver = { diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c new file mode 100644 index 000000000000..c3145f91fda3 --- /dev/null +++ b/drivers/gpio/gpio-zynq.c @@ -0,0 +1,692 @@ +/* + * Xilinx Zynq GPIO device driver + * + * Copyright (C) 2009 - 2014 Xilinx, Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + */ + +#include <linux/bitops.h> +#include <linux/clk.h> +#include <linux/gpio/driver.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> + +#define DRIVER_NAME "zynq-gpio" + +/* Maximum banks */ +#define ZYNQ_GPIO_MAX_BANK 4 + +#define ZYNQ_GPIO_BANK0_NGPIO 32 +#define ZYNQ_GPIO_BANK1_NGPIO 22 +#define ZYNQ_GPIO_BANK2_NGPIO 32 +#define ZYNQ_GPIO_BANK3_NGPIO 32 + +#define ZYNQ_GPIO_NR_GPIOS (ZYNQ_GPIO_BANK0_NGPIO + \ + ZYNQ_GPIO_BANK1_NGPIO + \ + ZYNQ_GPIO_BANK2_NGPIO + \ + ZYNQ_GPIO_BANK3_NGPIO) + +#define ZYNQ_GPIO_BANK0_PIN_MIN 0 +#define ZYNQ_GPIO_BANK0_PIN_MAX (ZYNQ_GPIO_BANK0_PIN_MIN + \ + ZYNQ_GPIO_BANK0_NGPIO - 1) +#define ZYNQ_GPIO_BANK1_PIN_MIN (ZYNQ_GPIO_BANK0_PIN_MAX + 1) +#define ZYNQ_GPIO_BANK1_PIN_MAX (ZYNQ_GPIO_BANK1_PIN_MIN + \ + ZYNQ_GPIO_BANK1_NGPIO - 1) +#define ZYNQ_GPIO_BANK2_PIN_MIN (ZYNQ_GPIO_BANK1_PIN_MAX + 1) +#define ZYNQ_GPIO_BANK2_PIN_MAX (ZYNQ_GPIO_BANK2_PIN_MIN + \ + ZYNQ_GPIO_BANK2_NGPIO - 1) +#define ZYNQ_GPIO_BANK3_PIN_MIN (ZYNQ_GPIO_BANK2_PIN_MAX + 1) +#define ZYNQ_GPIO_BANK3_PIN_MAX (ZYNQ_GPIO_BANK3_PIN_MIN + \ + ZYNQ_GPIO_BANK3_NGPIO - 1) + + +/* Register offsets for the GPIO device */ +/* LSW Mask & Data -WO */ +#define ZYNQ_GPIO_DATA_LSW_OFFSET(BANK) (0x000 + (8 * BANK)) +/* MSW Mask & Data -WO */ +#define ZYNQ_GPIO_DATA_MSW_OFFSET(BANK) (0x004 + (8 * BANK)) +/* Data Register-RW */ +#define ZYNQ_GPIO_DATA_RO_OFFSET(BANK) (0x060 + (4 * BANK)) +/* Direction mode reg-RW */ +#define ZYNQ_GPIO_DIRM_OFFSET(BANK) (0x204 + (0x40 * BANK)) +/* Output enable reg-RW */ +#define ZYNQ_GPIO_OUTEN_OFFSET(BANK) (0x208 + (0x40 * BANK)) +/* Interrupt mask reg-RO */ +#define ZYNQ_GPIO_INTMASK_OFFSET(BANK) (0x20C + (0x40 * BANK)) +/* Interrupt enable reg-WO */ +#define ZYNQ_GPIO_INTEN_OFFSET(BANK) (0x210 + (0x40 * BANK)) +/* Interrupt disable reg-WO */ +#define ZYNQ_GPIO_INTDIS_OFFSET(BANK) (0x214 + (0x40 * BANK)) +/* Interrupt status reg-RO */ +#define ZYNQ_GPIO_INTSTS_OFFSET(BANK) (0x218 + (0x40 * BANK)) +/* Interrupt type reg-RW */ +#define ZYNQ_GPIO_INTTYPE_OFFSET(BANK) (0x21C + (0x40 * BANK)) +/* Interrupt polarity reg-RW */ +#define ZYNQ_GPIO_INTPOL_OFFSET(BANK) (0x220 + (0x40 * BANK)) +/* Interrupt on any, reg-RW */ +#define ZYNQ_GPIO_INTANY_OFFSET(BANK) (0x224 + (0x40 * BANK)) + +/* Disable all interrupts mask */ +#define ZYNQ_GPIO_IXR_DISABLE_ALL 0xFFFFFFFF + +/* Mid pin number of a bank */ +#define ZYNQ_GPIO_MID_PIN_NUM 16 + +/* GPIO upper 16 bit mask */ +#define ZYNQ_GPIO_UPPER_MASK 0xFFFF0000 + +/** + * struct zynq_gpio - gpio device private data structure + * @chip: instance of the gpio_chip + * @base_addr: base address of the GPIO device + * @clk: clock resource for this controller + */ +struct zynq_gpio { + struct gpio_chip chip; + void __iomem *base_addr; + struct clk *clk; +}; + +/** + * zynq_gpio_get_bank_pin - Get the bank number and pin number within that bank + * for a given pin in the GPIO device + * @pin_num: gpio pin number within the device + * @bank_num: an output parameter used to return the bank number of the gpio + * pin + * @bank_pin_num: an output parameter used to return pin number within a bank + * for the given gpio pin + * + * Returns the bank number and pin offset within the bank. + */ +static inline void zynq_gpio_get_bank_pin(unsigned int pin_num, + unsigned int *bank_num, + unsigned int *bank_pin_num) +{ + switch (pin_num) { + case ZYNQ_GPIO_BANK0_PIN_MIN ... ZYNQ_GPIO_BANK0_PIN_MAX: + *bank_num = 0; + *bank_pin_num = pin_num; + break; + case ZYNQ_GPIO_BANK1_PIN_MIN ... ZYNQ_GPIO_BANK1_PIN_MAX: + *bank_num = 1; + *bank_pin_num = pin_num - ZYNQ_GPIO_BANK1_PIN_MIN; + break; + case ZYNQ_GPIO_BANK2_PIN_MIN ... ZYNQ_GPIO_BANK2_PIN_MAX: + *bank_num = 2; + *bank_pin_num = pin_num - ZYNQ_GPIO_BANK2_PIN_MIN; + break; + case ZYNQ_GPIO_BANK3_PIN_MIN ... ZYNQ_GPIO_BANK3_PIN_MAX: + *bank_num = 3; + *bank_pin_num = pin_num - ZYNQ_GPIO_BANK3_PIN_MIN; + break; + default: + WARN(true, "invalid GPIO pin number: %u", pin_num); + *bank_num = 0; + *bank_pin_num = 0; + break; + } +} + +/** + * zynq_gpio_get_value - Get the state of the specified pin of GPIO device + * @chip: gpio_chip instance to be worked on + * @pin: gpio pin number within the device + * + * This function reads the state of the specified pin of the GPIO device. + * + * Return: 0 if the pin is low, 1 if pin is high. + */ +static int zynq_gpio_get_value(struct gpio_chip *chip, unsigned int pin) +{ + u32 data; + unsigned int bank_num, bank_pin_num; + struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip); + + zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num); + + data = readl_relaxed(gpio->base_addr + + ZYNQ_GPIO_DATA_RO_OFFSET(bank_num)); + + return (data >> bank_pin_num) & 1; +} + +/** + * zynq_gpio_set_value - Modify the state of the pin with specified value + * @chip: gpio_chip instance to be worked on + * @pin: gpio pin number within the device + * @state: value used to modify the state of the specified pin + * + * This function calculates the register offset (i.e to lower 16 bits or + * upper 16 bits) based on the given pin number and sets the state of a + * gpio pin to the specified value. The state is either 0 or non-zero. + */ +static void zynq_gpio_set_value(struct gpio_chip *chip, unsigned int pin, + int state) +{ + unsigned int reg_offset, bank_num, bank_pin_num; + struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip); + + zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num); + + if (bank_pin_num >= ZYNQ_GPIO_MID_PIN_NUM) { + /* only 16 data bits in bit maskable reg */ + bank_pin_num -= ZYNQ_GPIO_MID_PIN_NUM; + reg_offset = ZYNQ_GPIO_DATA_MSW_OFFSET(bank_num); + } else { + reg_offset = ZYNQ_GPIO_DATA_LSW_OFFSET(bank_num); + } + + /* + * get the 32 bit value to be written to the mask/data register where + * the upper 16 bits is the mask and lower 16 bits is the data + */ + state = !!state; + state = ~(1 << (bank_pin_num + ZYNQ_GPIO_MID_PIN_NUM)) & + ((state << bank_pin_num) | ZYNQ_GPIO_UPPER_MASK); + + writel_relaxed(state, gpio->base_addr + reg_offset); +} + +/** + * zynq_gpio_dir_in - Set the direction of the specified GPIO pin as input + * @chip: gpio_chip instance to be worked on + * @pin: gpio pin number within the device + * + * This function uses the read-modify-write sequence to set the direction of + * the gpio pin as input. + * + * Return: 0 always + */ +static int zynq_gpio_dir_in(struct gpio_chip *chip, unsigned int pin) +{ + u32 reg; + unsigned int bank_num, bank_pin_num; + struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip); + + zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num); + + /* bank 0 pins 7 and 8 are special and cannot be used as inputs */ + if (bank_num == 0 && (bank_pin_num == 7 || bank_pin_num == 8)) + return -EINVAL; + + /* clear the bit in direction mode reg to set the pin as input */ + reg = readl_relaxed(gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num)); + reg &= ~BIT(bank_pin_num); + writel_relaxed(reg, gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num)); + + return 0; +} + +/** + * zynq_gpio_dir_out - Set the direction of the specified GPIO pin as output + * @chip: gpio_chip instance to be worked on + * @pin: gpio pin number within the device + * @state: value to be written to specified pin + * + * This function sets the direction of specified GPIO pin as output, configures + * the Output Enable register for the pin and uses zynq_gpio_set to set + * the state of the pin to the value specified. + * + * Return: 0 always + */ +static int zynq_gpio_dir_out(struct gpio_chip *chip, unsigned int pin, + int state) +{ + u32 reg; + unsigned int bank_num, bank_pin_num; + struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip); + + zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num); + + /* set the GPIO pin as output */ + reg = readl_relaxed(gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num)); + reg |= BIT(bank_pin_num); + writel_relaxed(reg, gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num)); + + /* configure the output enable reg for the pin */ + reg = readl_relaxed(gpio->base_addr + ZYNQ_GPIO_OUTEN_OFFSET(bank_num)); + reg |= BIT(bank_pin_num); + writel_relaxed(reg, gpio->base_addr + ZYNQ_GPIO_OUTEN_OFFSET(bank_num)); + + /* set the state of the pin */ + zynq_gpio_set_value(chip, pin, state); + return 0; +} + +/** + * zynq_gpio_irq_mask - Disable the interrupts for a gpio pin + * @irq_data: per irq and chip data passed down to chip functions + * + * This function calculates gpio pin number from irq number and sets the + * bit in the Interrupt Disable register of the corresponding bank to disable + * interrupts for that pin. + */ +static void zynq_gpio_irq_mask(struct irq_data *irq_data) +{ + unsigned int device_pin_num, bank_num, bank_pin_num; + struct zynq_gpio *gpio = irq_data_get_irq_chip_data(irq_data); + + device_pin_num = irq_data->hwirq; + zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num); + writel_relaxed(BIT(bank_pin_num), + gpio->base_addr + ZYNQ_GPIO_INTDIS_OFFSET(bank_num)); +} + +/** + * zynq_gpio_irq_unmask - Enable the interrupts for a gpio pin + * @irq_data: irq data containing irq number of gpio pin for the interrupt + * to enable + * + * This function calculates the gpio pin number from irq number and sets the + * bit in the Interrupt Enable register of the corresponding bank to enable + * interrupts for that pin. + */ +static void zynq_gpio_irq_unmask(struct irq_data *irq_data) +{ + unsigned int device_pin_num, bank_num, bank_pin_num; + struct zynq_gpio *gpio = irq_data_get_irq_chip_data(irq_data); + + device_pin_num = irq_data->hwirq; + zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num); + writel_relaxed(BIT(bank_pin_num), + gpio->base_addr + ZYNQ_GPIO_INTEN_OFFSET(bank_num)); +} + +/** + * zynq_gpio_irq_ack - Acknowledge the interrupt of a gpio pin + * @irq_data: irq data containing irq number of gpio pin for the interrupt + * to ack + * + * This function calculates gpio pin number from irq number and sets the bit + * in the Interrupt Status Register of the corresponding bank, to ACK the irq. + */ +static void zynq_gpio_irq_ack(struct irq_data *irq_data) +{ + unsigned int device_pin_num, bank_num, bank_pin_num; + struct zynq_gpio *gpio = irq_data_get_irq_chip_data(irq_data); + + device_pin_num = irq_data->hwirq; + zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num); + writel_relaxed(BIT(bank_pin_num), + gpio->base_addr + ZYNQ_GPIO_INTSTS_OFFSET(bank_num)); +} + +/** + * zynq_gpio_irq_enable - Enable the interrupts for a gpio pin + * @irq_data: irq data containing irq number of gpio pin for the interrupt + * to enable + * + * Clears the INTSTS bit and unmasks the given interrrupt. + */ +static void zynq_gpio_irq_enable(struct irq_data *irq_data) +{ + /* + * The Zynq GPIO controller does not disable interrupt detection when + * the interrupt is masked and only disables the propagation of the + * interrupt. This means when the controller detects an interrupt + * condition while the interrupt is logically disabled it will propagate + * that interrupt event once the interrupt is enabled. This will cause + * the interrupt consumer to see spurious interrupts to prevent this + * first make sure that the interrupt is not asserted and then enable + * it. + */ + zynq_gpio_irq_ack(irq_data); + zynq_gpio_irq_unmask(irq_data); +} + +/** + * zynq_gpio_set_irq_type - Set the irq type for a gpio pin + * @irq_data: irq data containing irq number of gpio pin + * @type: interrupt type that is to be set for the gpio pin + * + * This function gets the gpio pin number and its bank from the gpio pin number + * and configures the INT_TYPE, INT_POLARITY and INT_ANY registers. + * + * Return: 0, negative error otherwise. + * TYPE-EDGE_RISING, INT_TYPE - 1, INT_POLARITY - 1, INT_ANY - 0; + * TYPE-EDGE_FALLING, INT_TYPE - 1, INT_POLARITY - 0, INT_ANY - 0; + * TYPE-EDGE_BOTH, INT_TYPE - 1, INT_POLARITY - NA, INT_ANY - 1; + * TYPE-LEVEL_HIGH, INT_TYPE - 0, INT_POLARITY - 1, INT_ANY - NA; + * TYPE-LEVEL_LOW, INT_TYPE - 0, INT_POLARITY - 0, INT_ANY - NA + */ +static int zynq_gpio_set_irq_type(struct irq_data *irq_data, unsigned int type) +{ + u32 int_type, int_pol, int_any; + unsigned int device_pin_num, bank_num, bank_pin_num; + struct zynq_gpio *gpio = irq_data_get_irq_chip_data(irq_data); + + device_pin_num = irq_data->hwirq; + zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num); + + int_type = readl_relaxed(gpio->base_addr + + ZYNQ_GPIO_INTTYPE_OFFSET(bank_num)); + int_pol = readl_relaxed(gpio->base_addr + + ZYNQ_GPIO_INTPOL_OFFSET(bank_num)); + int_any = readl_relaxed(gpio->base_addr + + ZYNQ_GPIO_INTANY_OFFSET(bank_num)); + + /* + * based on the type requested, configure the INT_TYPE, INT_POLARITY + * and INT_ANY registers + */ + switch (type) { + case IRQ_TYPE_EDGE_RISING: + int_type |= BIT(bank_pin_num); + int_pol |= BIT(bank_pin_num); + int_any &= ~BIT(bank_pin_num); + break; + case IRQ_TYPE_EDGE_FALLING: + int_type |= BIT(bank_pin_num); + int_pol &= ~BIT(bank_pin_num); + int_any &= ~BIT(bank_pin_num); + break; + case IRQ_TYPE_EDGE_BOTH: + int_type |= BIT(bank_pin_num); + int_any |= BIT(bank_pin_num); + break; + case IRQ_TYPE_LEVEL_HIGH: + int_type &= ~BIT(bank_pin_num); + int_pol |= BIT(bank_pin_num); + break; + case IRQ_TYPE_LEVEL_LOW: + int_type &= ~BIT(bank_pin_num); + int_pol &= ~BIT(bank_pin_num); + break; + default: + return -EINVAL; + } + + writel_relaxed(int_type, + gpio->base_addr + ZYNQ_GPIO_INTTYPE_OFFSET(bank_num)); + writel_relaxed(int_pol, + gpio->base_addr + ZYNQ_GPIO_INTPOL_OFFSET(bank_num)); + writel_relaxed(int_any, + gpio->base_addr + ZYNQ_GPIO_INTANY_OFFSET(bank_num)); + return 0; +} + +static int zynq_gpio_set_wake(struct irq_data *data, unsigned int on) +{ + if (on) + zynq_gpio_irq_unmask(data); + else + zynq_gpio_irq_mask(data); + + return 0; +} + +/* irq chip descriptor */ +static struct irq_chip zynq_gpio_irqchip = { + .name = DRIVER_NAME, + .irq_enable = zynq_gpio_irq_enable, + .irq_mask = zynq_gpio_irq_mask, + .irq_unmask = zynq_gpio_irq_unmask, + .irq_set_type = zynq_gpio_set_irq_type, + .irq_set_wake = zynq_gpio_set_wake, +}; + +/** + * zynq_gpio_irqhandler - IRQ handler for the gpio banks of a gpio device + * @irq: irq number of the gpio bank where interrupt has occurred + * @desc: irq descriptor instance of the 'irq' + * + * This function reads the Interrupt Status Register of each bank to get the + * gpio pin number which has triggered an interrupt. It then acks the triggered + * interrupt and calls the pin specific handler set by the higher layer + * application for that pin. + * Note: A bug is reported if no handler is set for the gpio pin. + */ +static void zynq_gpio_irqhandler(unsigned int irq, struct irq_desc *desc) +{ + u32 int_sts, int_enb; + unsigned int bank_num; + struct zynq_gpio *gpio = irq_get_handler_data(irq); + struct irq_chip *irqchip = irq_desc_get_chip(desc); + + chained_irq_enter(irqchip, desc); + + for (bank_num = 0; bank_num < ZYNQ_GPIO_MAX_BANK; bank_num++) { + int_sts = readl_relaxed(gpio->base_addr + + ZYNQ_GPIO_INTSTS_OFFSET(bank_num)); + int_enb = readl_relaxed(gpio->base_addr + + ZYNQ_GPIO_INTMASK_OFFSET(bank_num)); + int_sts &= ~int_enb; + if (int_sts) { + int offset; + unsigned long pending = int_sts; + + for_each_set_bit(offset, &pending, 32) { + unsigned int gpio_irq = + irq_find_mapping(gpio->chip.irqdomain, + offset); + generic_handle_irq(gpio_irq); + } + + /* clear IRQ in HW */ + writel_relaxed(int_sts, gpio->base_addr + + ZYNQ_GPIO_INTSTS_OFFSET(bank_num)); + } + } + + chained_irq_exit(irqchip, desc); +} + +static int __maybe_unused zynq_gpio_suspend(struct device *dev) +{ + if (!device_may_wakeup(dev)) + return pm_runtime_force_suspend(dev); + + return 0; +} + +static int __maybe_unused zynq_gpio_resume(struct device *dev) +{ + if (!device_may_wakeup(dev)) + return pm_runtime_force_resume(dev); + + return 0; +} + +static int __maybe_unused zynq_gpio_runtime_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct zynq_gpio *gpio = platform_get_drvdata(pdev); + + clk_disable_unprepare(gpio->clk); + + return 0; +} + +static int __maybe_unused zynq_gpio_runtime_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct zynq_gpio *gpio = platform_get_drvdata(pdev); + + return clk_prepare_enable(gpio->clk); +} + +static int zynq_gpio_request(struct gpio_chip *chip, unsigned offset) +{ + int ret; + + ret = pm_runtime_get_sync(chip->dev); + + /* + * If the device is already active pm_runtime_get() will return 1 on + * success, but gpio_request still needs to return 0. + */ + return ret < 0 ? ret : 0; +} + +static void zynq_gpio_free(struct gpio_chip *chip, unsigned offset) +{ + pm_runtime_put(chip->dev); +} + +static const struct dev_pm_ops zynq_gpio_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(zynq_gpio_suspend, zynq_gpio_resume) + SET_PM_RUNTIME_PM_OPS(zynq_gpio_runtime_suspend, + zynq_gpio_runtime_resume, NULL) +}; + +/** + * zynq_gpio_probe - Initialization method for a zynq_gpio device + * @pdev: platform device instance + * + * This function allocates memory resources for the gpio device and registers + * all the banks of the device. It will also set up interrupts for the gpio + * pins. + * Note: Interrupts are disabled for all the banks during initialization. + * + * Return: 0 on success, negative error otherwise. + */ +static int zynq_gpio_probe(struct platform_device *pdev) +{ + int ret, bank_num, irq; + struct zynq_gpio *gpio; + struct gpio_chip *chip; + struct resource *res; + + gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); + if (!gpio) + return -ENOMEM; + + platform_set_drvdata(pdev, gpio); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + gpio->base_addr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(gpio->base_addr)) + return PTR_ERR(gpio->base_addr); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "invalid IRQ\n"); + return irq; + } + + /* configure the gpio chip */ + chip = &gpio->chip; + chip->label = "zynq_gpio"; + chip->owner = THIS_MODULE; + chip->dev = &pdev->dev; + chip->get = zynq_gpio_get_value; + chip->set = zynq_gpio_set_value; + chip->request = zynq_gpio_request; + chip->free = zynq_gpio_free; + chip->direction_input = zynq_gpio_dir_in; + chip->direction_output = zynq_gpio_dir_out; + chip->base = -1; + chip->ngpio = ZYNQ_GPIO_NR_GPIOS; + + /* Enable GPIO clock */ + gpio->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(gpio->clk)) { + dev_err(&pdev->dev, "input clock not found.\n"); + return PTR_ERR(gpio->clk); + } + ret = clk_prepare_enable(gpio->clk); + if (ret) { + dev_err(&pdev->dev, "Unable to enable clock.\n"); + return ret; + } + + /* report a bug if gpio chip registration fails */ + ret = gpiochip_add(chip); + if (ret) { + dev_err(&pdev->dev, "Failed to add gpio chip\n"); + goto err_disable_clk; + } + + /* disable interrupts for all banks */ + for (bank_num = 0; bank_num < ZYNQ_GPIO_MAX_BANK; bank_num++) + writel_relaxed(ZYNQ_GPIO_IXR_DISABLE_ALL, gpio->base_addr + + ZYNQ_GPIO_INTDIS_OFFSET(bank_num)); + + ret = gpiochip_irqchip_add(chip, &zynq_gpio_irqchip, 0, + handle_simple_irq, IRQ_TYPE_NONE); + if (ret) { + dev_err(&pdev->dev, "Failed to add irq chip\n"); + goto err_rm_gpiochip; + } + + gpiochip_set_chained_irqchip(chip, &zynq_gpio_irqchip, irq, + zynq_gpio_irqhandler); + + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + + device_set_wakeup_capable(&pdev->dev, 1); + + return 0; + +err_rm_gpiochip: + if (gpiochip_remove(chip)) + dev_err(&pdev->dev, "Failed to remove gpio chip\n"); +err_disable_clk: + clk_disable_unprepare(gpio->clk); + + return ret; +} + +/** + * zynq_gpio_remove - Driver removal function + * @pdev: platform device instance + * + * Return: 0 always + */ +static int zynq_gpio_remove(struct platform_device *pdev) +{ + int ret; + struct zynq_gpio *gpio = platform_get_drvdata(pdev); + + pm_runtime_get_sync(&pdev->dev); + + ret = gpiochip_remove(&gpio->chip); + if (ret) { + dev_err(&pdev->dev, "Failed to remove gpio chip\n"); + return ret; + } + clk_disable_unprepare(gpio->clk); + device_set_wakeup_capable(&pdev->dev, 0); + return 0; +} + +static struct of_device_id zynq_gpio_of_match[] = { + { .compatible = "xlnx,zynq-gpio-1.0", }, + { /* end of table */ } +}; +MODULE_DEVICE_TABLE(of, zynq_gpio_of_match); + +static struct platform_driver zynq_gpio_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .pm = &zynq_gpio_dev_pm_ops, + .of_match_table = zynq_gpio_of_match, + }, + .probe = zynq_gpio_probe, + .remove = zynq_gpio_remove, +}; + +/** + * zynq_gpio_init - Initial driver registration call + * + * Return: value from platform_driver_register + */ +static int __init zynq_gpio_init(void) +{ + return platform_driver_register(&zynq_gpio_driver); +} +postcore_initcall(zynq_gpio_init); + +MODULE_AUTHOR("Xilinx Inc."); +MODULE_DESCRIPTION("Zynq GPIO driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 4a987917c186..d62eaaa75397 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -157,7 +157,7 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares, gpiod_direction_input(desc); - ret = gpiod_lock_as_irq(desc); + ret = gpio_lock_as_irq(chip, pin); if (ret) { dev_err(chip->dev, "Failed to lock GPIO as interrupt\n"); goto fail_free_desc; @@ -212,7 +212,7 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares, fail_free_event: kfree(event); fail_unlock_irq: - gpiod_unlock_as_irq(desc); + gpio_unlock_as_irq(chip, pin); fail_free_desc: gpiochip_free_own_desc(desc); @@ -221,7 +221,7 @@ fail_free_desc: /** * acpi_gpiochip_request_interrupts() - Register isr for gpio chip ACPI events - * @acpi_gpio: ACPI GPIO chip + * @chip: GPIO chip * * ACPI5 platforms can use GPIO signaled ACPI events. These GPIO interrupts are * handled by ACPI event methods which need to be called from the GPIO @@ -229,11 +229,21 @@ fail_free_desc: * gpio pins have acpi event methods and assigns interrupt handlers that calls * the acpi event methods for those pins. */ -static void acpi_gpiochip_request_interrupts(struct acpi_gpio_chip *acpi_gpio) +void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) { - struct gpio_chip *chip = acpi_gpio->chip; + struct acpi_gpio_chip *acpi_gpio; + acpi_handle handle; + acpi_status status; + + if (!chip->dev || !chip->to_irq) + return; - if (!chip->to_irq) + handle = ACPI_HANDLE(chip->dev); + if (!handle) + return; + + status = acpi_get_data(handle, acpi_gpio_chip_dh, (void **)&acpi_gpio); + if (ACPI_FAILURE(status)) return; INIT_LIST_HEAD(&acpi_gpio->events); @@ -243,17 +253,27 @@ static void acpi_gpiochip_request_interrupts(struct acpi_gpio_chip *acpi_gpio) /** * acpi_gpiochip_free_interrupts() - Free GPIO ACPI event interrupts. - * @acpi_gpio: ACPI GPIO chip + * @chip: GPIO chip * * Free interrupts associated with GPIO ACPI event method for the given * GPIO chip. */ -static void acpi_gpiochip_free_interrupts(struct acpi_gpio_chip *acpi_gpio) +void acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { + struct acpi_gpio_chip *acpi_gpio; struct acpi_gpio_event *event, *ep; - struct gpio_chip *chip = acpi_gpio->chip; + acpi_handle handle; + acpi_status status; + + if (!chip->dev || !chip->to_irq) + return; - if (!chip->to_irq) + handle = ACPI_HANDLE(chip->dev); + if (!handle) + return; + + status = acpi_get_data(handle, acpi_gpio_chip_dh, (void **)&acpi_gpio); + if (ACPI_FAILURE(status)) return; list_for_each_entry_safe_reverse(event, ep, &acpi_gpio->events, node) { @@ -263,7 +283,7 @@ static void acpi_gpiochip_free_interrupts(struct acpi_gpio_chip *acpi_gpio) desc = gpiochip_get_desc(chip, event->pin); if (WARN_ON(IS_ERR(desc))) continue; - gpiod_unlock_as_irq(desc); + gpio_unlock_as_irq(chip, event->pin); gpiochip_free_own_desc(desc); list_del(&event->node); kfree(event); @@ -525,7 +545,6 @@ void acpi_gpiochip_add(struct gpio_chip *chip) return; } - acpi_gpiochip_request_interrupts(acpi_gpio); acpi_gpiochip_request_regions(acpi_gpio); } @@ -549,7 +568,6 @@ void acpi_gpiochip_remove(struct gpio_chip *chip) } acpi_gpiochip_free_regions(acpi_gpio); - acpi_gpiochip_free_interrupts(acpi_gpio); acpi_detach_data(handle, acpi_gpio_chip_dh); kfree(acpi_gpio); diff --git a/drivers/gpio/gpiolib-legacy.c b/drivers/gpio/gpiolib-legacy.c new file mode 100644 index 000000000000..078ae6c2df79 --- /dev/null +++ b/drivers/gpio/gpiolib-legacy.c @@ -0,0 +1,102 @@ +#include <linux/gpio/consumer.h> +#include <linux/gpio/driver.h> + +#include <linux/gpio.h> + +#include "gpiolib.h" + +void gpio_free(unsigned gpio) +{ + gpiod_free(gpio_to_desc(gpio)); +} +EXPORT_SYMBOL_GPL(gpio_free); + +/** + * gpio_request_one - request a single GPIO with initial configuration + * @gpio: the GPIO number + * @flags: GPIO configuration as specified by GPIOF_* + * @label: a literal description string of this GPIO + */ +int gpio_request_one(unsigned gpio, unsigned long flags, const char *label) +{ + struct gpio_desc *desc; + int err; + + desc = gpio_to_desc(gpio); + + err = gpiod_request(desc, label); + if (err) + return err; + + if (flags & GPIOF_OPEN_DRAIN) + set_bit(FLAG_OPEN_DRAIN, &desc->flags); + + if (flags & GPIOF_OPEN_SOURCE) + set_bit(FLAG_OPEN_SOURCE, &desc->flags); + + if (flags & GPIOF_ACTIVE_LOW) + set_bit(FLAG_ACTIVE_LOW, &desc->flags); + + if (flags & GPIOF_DIR_IN) + err = gpiod_direction_input(desc); + else + err = gpiod_direction_output_raw(desc, + (flags & GPIOF_INIT_HIGH) ? 1 : 0); + + if (err) + goto free_gpio; + + if (flags & GPIOF_EXPORT) { + err = gpiod_export(desc, flags & GPIOF_EXPORT_CHANGEABLE); + if (err) + goto free_gpio; + } + + return 0; + + free_gpio: + gpiod_free(desc); + return err; +} +EXPORT_SYMBOL_GPL(gpio_request_one); + +int gpio_request(unsigned gpio, const char *label) +{ + return gpiod_request(gpio_to_desc(gpio), label); +} +EXPORT_SYMBOL_GPL(gpio_request); + +/** + * gpio_request_array - request multiple GPIOs in a single call + * @array: array of the 'struct gpio' + * @num: how many GPIOs in the array + */ +int gpio_request_array(const struct gpio *array, size_t num) +{ + int i, err; + + for (i = 0; i < num; i++, array++) { + err = gpio_request_one(array->gpio, array->flags, array->label); + if (err) + goto err_free; + } + return 0; + +err_free: + while (i--) + gpio_free((--array)->gpio); + return err; +} +EXPORT_SYMBOL_GPL(gpio_request_array); + +/** + * gpio_free_array - release multiple GPIOs in a single call + * @array: array of the 'struct gpio' + * @num: how many GPIOs in the array + */ +void gpio_free_array(const struct gpio *array, size_t num) +{ + while (num--) + gpio_free((array++)->gpio); +} +EXPORT_SYMBOL_GPL(gpio_free_array); diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index af7e25c9a9ae..7cfdc2278905 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -23,7 +23,7 @@ #include <linux/pinctrl/pinctrl.h> #include <linux/slab.h> -struct gpio_desc; +#include "gpiolib.h" /* Private data structure for of_gpiochip_find_and_xlate */ struct gg_data { @@ -82,19 +82,19 @@ struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np, ret = of_parse_phandle_with_args(np, propname, "#gpio-cells", index, &gg_data.gpiospec); if (ret) { - pr_debug("%s: can't parse gpios property of node '%s[%d]'\n", - __func__, np->full_name, index); + pr_debug("%s: can't parse '%s' property of node '%s[%d]'\n", + __func__, propname, np->full_name, index); return ERR_PTR(ret); } gpiochip_find(&gg_data, of_gpiochip_find_and_xlate); of_node_put(gg_data.gpiospec.np); - pr_debug("%s exited with status %d\n", __func__, + pr_debug("%s: parsed '%s' property of node '%s[%d]' - status (%d)\n", + __func__, propname, np->full_name, index, PTR_ERR_OR_ZERO(gg_data.out_gpio)); return gg_data.out_gpio; } -EXPORT_SYMBOL(of_get_named_gpiod_flags); int of_get_named_gpio_flags(struct device_node *np, const char *list_name, int index, enum of_gpio_flags *flags) diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c new file mode 100644 index 000000000000..5f2150b619a7 --- /dev/null +++ b/drivers/gpio/gpiolib-sysfs.c @@ -0,0 +1,827 @@ +#include <linux/idr.h> +#include <linux/mutex.h> +#include <linux/device.h> +#include <linux/sysfs.h> +#include <linux/gpio/consumer.h> +#include <linux/gpio/driver.h> +#include <linux/interrupt.h> +#include <linux/kdev_t.h> + +#include "gpiolib.h" + +static DEFINE_IDR(dirent_idr); + + +/* lock protects against unexport_gpio() being called while + * sysfs files are active. + */ +static DEFINE_MUTEX(sysfs_lock); + +/* + * /sys/class/gpio/gpioN... only for GPIOs that are exported + * /direction + * * MAY BE OMITTED if kernel won't allow direction changes + * * is read/write as "in" or "out" + * * may also be written as "high" or "low", initializing + * output value as specified ("out" implies "low") + * /value + * * always readable, subject to hardware behavior + * * may be writable, as zero/nonzero + * /edge + * * configures behavior of poll(2) on /value + * * available only if pin can generate IRQs on input + * * is read/write as "none", "falling", "rising", or "both" + * /active_low + * * configures polarity of /value + * * is read/write as zero/nonzero + * * also affects existing and subsequent "falling" and "rising" + * /edge configuration + */ + +static ssize_t gpio_direction_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + const struct gpio_desc *desc = dev_get_drvdata(dev); + ssize_t status; + + mutex_lock(&sysfs_lock); + + if (!test_bit(FLAG_EXPORT, &desc->flags)) { + status = -EIO; + } else { + gpiod_get_direction(desc); + status = sprintf(buf, "%s\n", + test_bit(FLAG_IS_OUT, &desc->flags) + ? "out" : "in"); + } + + mutex_unlock(&sysfs_lock); + return status; +} + +static ssize_t gpio_direction_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct gpio_desc *desc = dev_get_drvdata(dev); + ssize_t status; + + mutex_lock(&sysfs_lock); + + if (!test_bit(FLAG_EXPORT, &desc->flags)) + status = -EIO; + else if (sysfs_streq(buf, "high")) + status = gpiod_direction_output_raw(desc, 1); + else if (sysfs_streq(buf, "out") || sysfs_streq(buf, "low")) + status = gpiod_direction_output_raw(desc, 0); + else if (sysfs_streq(buf, "in")) + status = gpiod_direction_input(desc); + else + status = -EINVAL; + + mutex_unlock(&sysfs_lock); + return status ? : size; +} + +static /* const */ DEVICE_ATTR(direction, 0644, + gpio_direction_show, gpio_direction_store); + +static ssize_t gpio_value_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct gpio_desc *desc = dev_get_drvdata(dev); + ssize_t status; + + mutex_lock(&sysfs_lock); + + if (!test_bit(FLAG_EXPORT, &desc->flags)) + status = -EIO; + else + status = sprintf(buf, "%d\n", gpiod_get_value_cansleep(desc)); + + mutex_unlock(&sysfs_lock); + return status; +} + +static ssize_t gpio_value_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct gpio_desc *desc = dev_get_drvdata(dev); + ssize_t status; + + mutex_lock(&sysfs_lock); + + if (!test_bit(FLAG_EXPORT, &desc->flags)) + status = -EIO; + else if (!test_bit(FLAG_IS_OUT, &desc->flags)) + status = -EPERM; + else { + long value; + + status = kstrtol(buf, 0, &value); + if (status == 0) { + gpiod_set_value_cansleep(desc, value); + status = size; + } + } + + mutex_unlock(&sysfs_lock); + return status; +} + +static const DEVICE_ATTR(value, 0644, + gpio_value_show, gpio_value_store); + +static irqreturn_t gpio_sysfs_irq(int irq, void *priv) +{ + struct kernfs_node *value_sd = priv; + + sysfs_notify_dirent(value_sd); + return IRQ_HANDLED; +} + +static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev, + unsigned long gpio_flags) +{ + struct kernfs_node *value_sd; + unsigned long irq_flags; + int ret, irq, id; + + if ((desc->flags & GPIO_TRIGGER_MASK) == gpio_flags) + return 0; + + irq = gpiod_to_irq(desc); + if (irq < 0) + return -EIO; + + id = desc->flags >> ID_SHIFT; + value_sd = idr_find(&dirent_idr, id); + if (value_sd) + free_irq(irq, value_sd); + + desc->flags &= ~GPIO_TRIGGER_MASK; + + if (!gpio_flags) { + gpio_unlock_as_irq(desc->chip, gpio_chip_hwgpio(desc)); + ret = 0; + goto free_id; + } + + irq_flags = IRQF_SHARED; + if (test_bit(FLAG_TRIG_FALL, &gpio_flags)) + irq_flags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ? + IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING; + if (test_bit(FLAG_TRIG_RISE, &gpio_flags)) + irq_flags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ? + IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING; + + if (!value_sd) { + value_sd = sysfs_get_dirent(dev->kobj.sd, "value"); + if (!value_sd) { + ret = -ENODEV; + goto err_out; + } + + ret = idr_alloc(&dirent_idr, value_sd, 1, 0, GFP_KERNEL); + if (ret < 0) + goto free_sd; + id = ret; + + desc->flags &= GPIO_FLAGS_MASK; + desc->flags |= (unsigned long)id << ID_SHIFT; + + if (desc->flags >> ID_SHIFT != id) { + ret = -ERANGE; + goto free_id; + } + } + + ret = request_any_context_irq(irq, gpio_sysfs_irq, irq_flags, + "gpiolib", value_sd); + if (ret < 0) + goto free_id; + + ret = gpio_lock_as_irq(desc->chip, gpio_chip_hwgpio(desc)); + if (ret < 0) { + gpiod_warn(desc, "failed to flag the GPIO for IRQ\n"); + goto free_id; + } + + desc->flags |= gpio_flags; + return 0; + +free_id: + idr_remove(&dirent_idr, id); + desc->flags &= GPIO_FLAGS_MASK; +free_sd: + if (value_sd) + sysfs_put(value_sd); +err_out: + return ret; +} + +static const struct { + const char *name; + unsigned long flags; +} trigger_types[] = { + { "none", 0 }, + { "falling", BIT(FLAG_TRIG_FALL) }, + { "rising", BIT(FLAG_TRIG_RISE) }, + { "both", BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE) }, +}; + +static ssize_t gpio_edge_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + const struct gpio_desc *desc = dev_get_drvdata(dev); + ssize_t status; + + mutex_lock(&sysfs_lock); + + if (!test_bit(FLAG_EXPORT, &desc->flags)) + status = -EIO; + else { + int i; + + status = 0; + for (i = 0; i < ARRAY_SIZE(trigger_types); i++) + if ((desc->flags & GPIO_TRIGGER_MASK) + == trigger_types[i].flags) { + status = sprintf(buf, "%s\n", + trigger_types[i].name); + break; + } + } + + mutex_unlock(&sysfs_lock); + return status; +} + +static ssize_t gpio_edge_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct gpio_desc *desc = dev_get_drvdata(dev); + ssize_t status; + int i; + + for (i = 0; i < ARRAY_SIZE(trigger_types); i++) + if (sysfs_streq(trigger_types[i].name, buf)) + goto found; + return -EINVAL; + +found: + mutex_lock(&sysfs_lock); + + if (!test_bit(FLAG_EXPORT, &desc->flags)) + status = -EIO; + else { + status = gpio_setup_irq(desc, dev, trigger_types[i].flags); + if (!status) + status = size; + } + + mutex_unlock(&sysfs_lock); + + return status; +} + +static DEVICE_ATTR(edge, 0644, gpio_edge_show, gpio_edge_store); + +static int sysfs_set_active_low(struct gpio_desc *desc, struct device *dev, + int value) +{ + int status = 0; + + if (!!test_bit(FLAG_ACTIVE_LOW, &desc->flags) == !!value) + return 0; + + if (value) + set_bit(FLAG_ACTIVE_LOW, &desc->flags); + else + clear_bit(FLAG_ACTIVE_LOW, &desc->flags); + + /* reconfigure poll(2) support if enabled on one edge only */ + if (dev != NULL && (!!test_bit(FLAG_TRIG_RISE, &desc->flags) ^ + !!test_bit(FLAG_TRIG_FALL, &desc->flags))) { + unsigned long trigger_flags = desc->flags & GPIO_TRIGGER_MASK; + + gpio_setup_irq(desc, dev, 0); + status = gpio_setup_irq(desc, dev, trigger_flags); + } + + return status; +} + +static ssize_t gpio_active_low_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + const struct gpio_desc *desc = dev_get_drvdata(dev); + ssize_t status; + + mutex_lock(&sysfs_lock); + + if (!test_bit(FLAG_EXPORT, &desc->flags)) + status = -EIO; + else + status = sprintf(buf, "%d\n", + !!test_bit(FLAG_ACTIVE_LOW, &desc->flags)); + + mutex_unlock(&sysfs_lock); + + return status; +} + +static ssize_t gpio_active_low_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct gpio_desc *desc = dev_get_drvdata(dev); + ssize_t status; + + mutex_lock(&sysfs_lock); + + if (!test_bit(FLAG_EXPORT, &desc->flags)) { + status = -EIO; + } else { + long value; + + status = kstrtol(buf, 0, &value); + if (status == 0) + status = sysfs_set_active_low(desc, dev, value != 0); + } + + mutex_unlock(&sysfs_lock); + + return status ? : size; +} + +static const DEVICE_ATTR(active_low, 0644, + gpio_active_low_show, gpio_active_low_store); + +static const struct attribute *gpio_attrs[] = { + &dev_attr_value.attr, + &dev_attr_active_low.attr, + NULL, +}; + +static const struct attribute_group gpio_attr_group = { + .attrs = (struct attribute **) gpio_attrs, +}; + +/* + * /sys/class/gpio/gpiochipN/ + * /base ... matching gpio_chip.base (N) + * /label ... matching gpio_chip.label + * /ngpio ... matching gpio_chip.ngpio + */ + +static ssize_t chip_base_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + const struct gpio_chip *chip = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", chip->base); +} +static DEVICE_ATTR(base, 0444, chip_base_show, NULL); + +static ssize_t chip_label_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + const struct gpio_chip *chip = dev_get_drvdata(dev); + + return sprintf(buf, "%s\n", chip->label ? : ""); +} +static DEVICE_ATTR(label, 0444, chip_label_show, NULL); + +static ssize_t chip_ngpio_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + const struct gpio_chip *chip = dev_get_drvdata(dev); + + return sprintf(buf, "%u\n", chip->ngpio); +} +static DEVICE_ATTR(ngpio, 0444, chip_ngpio_show, NULL); + +static const struct attribute *gpiochip_attrs[] = { + &dev_attr_base.attr, + &dev_attr_label.attr, + &dev_attr_ngpio.attr, + NULL, +}; + +static const struct attribute_group gpiochip_attr_group = { + .attrs = (struct attribute **) gpiochip_attrs, +}; + +/* + * /sys/class/gpio/export ... write-only + * integer N ... number of GPIO to export (full access) + * /sys/class/gpio/unexport ... write-only + * integer N ... number of GPIO to unexport + */ +static ssize_t export_store(struct class *class, + struct class_attribute *attr, + const char *buf, size_t len) +{ + long gpio; + struct gpio_desc *desc; + int status; + + status = kstrtol(buf, 0, &gpio); + if (status < 0) + goto done; + + desc = gpio_to_desc(gpio); + /* reject invalid GPIOs */ + if (!desc) { + pr_warn("%s: invalid GPIO %ld\n", __func__, gpio); + return -EINVAL; + } + + /* No extra locking here; FLAG_SYSFS just signifies that the + * request and export were done by on behalf of userspace, so + * they may be undone on its behalf too. + */ + + status = gpiod_request(desc, "sysfs"); + if (status < 0) { + if (status == -EPROBE_DEFER) + status = -ENODEV; + goto done; + } + status = gpiod_export(desc, true); + if (status < 0) + gpiod_free(desc); + else + set_bit(FLAG_SYSFS, &desc->flags); + +done: + if (status) + pr_debug("%s: status %d\n", __func__, status); + return status ? : len; +} + +static ssize_t unexport_store(struct class *class, + struct class_attribute *attr, + const char *buf, size_t len) +{ + long gpio; + struct gpio_desc *desc; + int status; + + status = kstrtol(buf, 0, &gpio); + if (status < 0) + goto done; + + desc = gpio_to_desc(gpio); + /* reject bogus commands (gpio_unexport ignores them) */ + if (!desc) { + pr_warn("%s: invalid GPIO %ld\n", __func__, gpio); + return -EINVAL; + } + + status = -EINVAL; + + /* No extra locking here; FLAG_SYSFS just signifies that the + * request and export were done by on behalf of userspace, so + * they may be undone on its behalf too. + */ + if (test_and_clear_bit(FLAG_SYSFS, &desc->flags)) { + status = 0; + gpiod_free(desc); + } +done: + if (status) + pr_debug("%s: status %d\n", __func__, status); + return status ? : len; +} + +static struct class_attribute gpio_class_attrs[] = { + __ATTR(export, 0200, NULL, export_store), + __ATTR(unexport, 0200, NULL, unexport_store), + __ATTR_NULL, +}; + +static struct class gpio_class = { + .name = "gpio", + .owner = THIS_MODULE, + + .class_attrs = gpio_class_attrs, +}; + + +/** + * gpiod_export - export a GPIO through sysfs + * @gpio: gpio to make available, already requested + * @direction_may_change: true if userspace may change gpio direction + * Context: arch_initcall or later + * + * When drivers want to make a GPIO accessible to userspace after they + * have requested it -- perhaps while debugging, or as part of their + * public interface -- they may use this routine. If the GPIO can + * change direction (some can't) and the caller allows it, userspace + * will see "direction" sysfs attribute which may be used to change + * the gpio's direction. A "value" attribute will always be provided. + * + * Returns zero on success, else an error. + */ +int gpiod_export(struct gpio_desc *desc, bool direction_may_change) +{ + unsigned long flags; + int status; + const char *ioname = NULL; + struct device *dev; + int offset; + + /* can't export until sysfs is available ... */ + if (!gpio_class.p) { + pr_debug("%s: called too early!\n", __func__); + return -ENOENT; + } + + if (!desc) { + pr_debug("%s: invalid gpio descriptor\n", __func__); + return -EINVAL; + } + + mutex_lock(&sysfs_lock); + + spin_lock_irqsave(&gpio_lock, flags); + if (!test_bit(FLAG_REQUESTED, &desc->flags) || + test_bit(FLAG_EXPORT, &desc->flags)) { + spin_unlock_irqrestore(&gpio_lock, flags); + gpiod_dbg(desc, "%s: unavailable (requested=%d, exported=%d)\n", + __func__, + test_bit(FLAG_REQUESTED, &desc->flags), + test_bit(FLAG_EXPORT, &desc->flags)); + status = -EPERM; + goto fail_unlock; + } + + if (!desc->chip->direction_input || !desc->chip->direction_output) + direction_may_change = false; + spin_unlock_irqrestore(&gpio_lock, flags); + + offset = gpio_chip_hwgpio(desc); + if (desc->chip->names && desc->chip->names[offset]) + ioname = desc->chip->names[offset]; + + dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0), + desc, ioname ? ioname : "gpio%u", + desc_to_gpio(desc)); + if (IS_ERR(dev)) { + status = PTR_ERR(dev); + goto fail_unlock; + } + + status = sysfs_create_group(&dev->kobj, &gpio_attr_group); + if (status) + goto fail_unregister_device; + + if (direction_may_change) { + status = device_create_file(dev, &dev_attr_direction); + if (status) + goto fail_unregister_device; + } + + if (gpiod_to_irq(desc) >= 0 && (direction_may_change || + !test_bit(FLAG_IS_OUT, &desc->flags))) { + status = device_create_file(dev, &dev_attr_edge); + if (status) + goto fail_unregister_device; + } + + set_bit(FLAG_EXPORT, &desc->flags); + mutex_unlock(&sysfs_lock); + return 0; + +fail_unregister_device: + device_unregister(dev); +fail_unlock: + mutex_unlock(&sysfs_lock); + gpiod_dbg(desc, "%s: status %d\n", __func__, status); + return status; +} +EXPORT_SYMBOL_GPL(gpiod_export); + +static int match_export(struct device *dev, const void *data) +{ + return dev_get_drvdata(dev) == data; +} + +/** + * gpiod_export_link - create a sysfs link to an exported GPIO node + * @dev: device under which to create symlink + * @name: name of the symlink + * @gpio: gpio to create symlink to, already exported + * + * Set up a symlink from /sys/.../dev/name to /sys/class/gpio/gpioN + * node. Caller is responsible for unlinking. + * + * Returns zero on success, else an error. + */ +int gpiod_export_link(struct device *dev, const char *name, + struct gpio_desc *desc) +{ + int status = -EINVAL; + + if (!desc) { + pr_warn("%s: invalid GPIO\n", __func__); + return -EINVAL; + } + + mutex_lock(&sysfs_lock); + + if (test_bit(FLAG_EXPORT, &desc->flags)) { + struct device *tdev; + + tdev = class_find_device(&gpio_class, NULL, desc, match_export); + if (tdev != NULL) { + status = sysfs_create_link(&dev->kobj, &tdev->kobj, + name); + } else { + status = -ENODEV; + } + } + + mutex_unlock(&sysfs_lock); + + if (status) + gpiod_dbg(desc, "%s: status %d\n", __func__, status); + + return status; +} +EXPORT_SYMBOL_GPL(gpiod_export_link); + +/** + * gpiod_sysfs_set_active_low - set the polarity of gpio sysfs value + * @gpio: gpio to change + * @value: non-zero to use active low, i.e. inverted values + * + * Set the polarity of /sys/class/gpio/gpioN/value sysfs attribute. + * The GPIO does not have to be exported yet. If poll(2) support has + * been enabled for either rising or falling edge, it will be + * reconfigured to follow the new polarity. + * + * Returns zero on success, else an error. + */ +int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value) +{ + struct device *dev = NULL; + int status = -EINVAL; + + if (!desc) { + pr_warn("%s: invalid GPIO\n", __func__); + return -EINVAL; + } + + mutex_lock(&sysfs_lock); + + if (test_bit(FLAG_EXPORT, &desc->flags)) { + dev = class_find_device(&gpio_class, NULL, desc, match_export); + if (dev == NULL) { + status = -ENODEV; + goto unlock; + } + } + + status = sysfs_set_active_low(desc, dev, value); + +unlock: + mutex_unlock(&sysfs_lock); + + if (status) + gpiod_dbg(desc, "%s: status %d\n", __func__, status); + + return status; +} +EXPORT_SYMBOL_GPL(gpiod_sysfs_set_active_low); + +/** + * gpiod_unexport - reverse effect of gpio_export() + * @gpio: gpio to make unavailable + * + * This is implicit on gpio_free(). + */ +void gpiod_unexport(struct gpio_desc *desc) +{ + int status = 0; + struct device *dev = NULL; + + if (!desc) { + pr_warn("%s: invalid GPIO\n", __func__); + return; + } + + mutex_lock(&sysfs_lock); + + if (test_bit(FLAG_EXPORT, &desc->flags)) { + + dev = class_find_device(&gpio_class, NULL, desc, match_export); + if (dev) { + gpio_setup_irq(desc, dev, 0); + clear_bit(FLAG_EXPORT, &desc->flags); + } else + status = -ENODEV; + } + + mutex_unlock(&sysfs_lock); + + if (dev) { + device_unregister(dev); + put_device(dev); + } + + if (status) + gpiod_dbg(desc, "%s: status %d\n", __func__, status); +} +EXPORT_SYMBOL_GPL(gpiod_unexport); + +int gpiochip_export(struct gpio_chip *chip) +{ + int status; + struct device *dev; + + /* Many systems register gpio chips for SOC support very early, + * before driver model support is available. In those cases we + * export this later, in gpiolib_sysfs_init() ... here we just + * verify that _some_ field of gpio_class got initialized. + */ + if (!gpio_class.p) + return 0; + + /* use chip->base for the ID; it's already known to be unique */ + mutex_lock(&sysfs_lock); + dev = device_create(&gpio_class, chip->dev, MKDEV(0, 0), chip, + "gpiochip%d", chip->base); + if (!IS_ERR(dev)) { + status = sysfs_create_group(&dev->kobj, + &gpiochip_attr_group); + } else + status = PTR_ERR(dev); + chip->exported = (status == 0); + mutex_unlock(&sysfs_lock); + + if (status) + chip_dbg(chip, "%s: status %d\n", __func__, status); + + return status; +} + +void gpiochip_unexport(struct gpio_chip *chip) +{ + int status; + struct device *dev; + + mutex_lock(&sysfs_lock); + dev = class_find_device(&gpio_class, NULL, chip, match_export); + if (dev) { + put_device(dev); + device_unregister(dev); + chip->exported = false; + status = 0; + } else + status = -ENODEV; + mutex_unlock(&sysfs_lock); + + if (status) + chip_dbg(chip, "%s: status %d\n", __func__, status); +} + +static int __init gpiolib_sysfs_init(void) +{ + int status; + unsigned long flags; + struct gpio_chip *chip; + + status = class_register(&gpio_class); + if (status < 0) + return status; + + /* Scan and register the gpio_chips which registered very + * early (e.g. before the class_register above was called). + * + * We run before arch_initcall() so chip->dev nodes can have + * registered, and so arch_initcall() can always gpio_export(). + */ + spin_lock_irqsave(&gpio_lock, flags); + list_for_each_entry(chip, &gpio_chips, list) { + if (chip->exported) + continue; + + /* + * TODO we yield gpio_lock here because gpiochip_export() + * acquires a mutex. This is unsafe and needs to be fixed. + * + * Also it would be nice to use gpiochip_find() here so we + * can keep gpio_chips local to gpiolib.c, but the yield of + * gpio_lock prevents us from doing this. + */ + spin_unlock_irqrestore(&gpio_lock, flags); + status = gpiochip_export(chip); + spin_lock_irqsave(&gpio_lock, flags); + } + spin_unlock_irqrestore(&gpio_lock, flags); + + + return status; +} +postcore_initcall(gpiolib_sysfs_init); diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 2ebc9071e354..15cc0bb65dda 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -14,6 +14,7 @@ #include <linux/slab.h> #include <linux/acpi.h> #include <linux/gpio/driver.h> +#include <linux/gpio/machine.h> #include "gpiolib.h" @@ -44,111 +45,19 @@ * While any GPIO is requested, its gpio_chip is not removable; * each GPIO's "requested" flag serves as a lock and refcount. */ -static DEFINE_SPINLOCK(gpio_lock); +DEFINE_SPINLOCK(gpio_lock); -struct gpio_desc { - struct gpio_chip *chip; - unsigned long flags; -/* flag symbols are bit numbers */ -#define FLAG_REQUESTED 0 -#define FLAG_IS_OUT 1 -#define FLAG_EXPORT 2 /* protected by sysfs_lock */ -#define FLAG_SYSFS 3 /* exported via /sys/class/gpio/control */ -#define FLAG_TRIG_FALL 4 /* trigger on falling edge */ -#define FLAG_TRIG_RISE 5 /* trigger on rising edge */ -#define FLAG_ACTIVE_LOW 6 /* value has active low */ -#define FLAG_OPEN_DRAIN 7 /* Gpio is open drain type */ -#define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */ -#define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */ - -#define ID_SHIFT 16 /* add new flags before this one */ - -#define GPIO_FLAGS_MASK ((1 << ID_SHIFT) - 1) -#define GPIO_TRIGGER_MASK (BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE)) - -#ifdef CONFIG_DEBUG_FS - const char *label; -#endif -}; static struct gpio_desc gpio_desc[ARCH_NR_GPIOS]; #define GPIO_OFFSET_VALID(chip, offset) (offset >= 0 && offset < chip->ngpio) static DEFINE_MUTEX(gpio_lookup_lock); static LIST_HEAD(gpio_lookup_list); -static LIST_HEAD(gpio_chips); - -#ifdef CONFIG_GPIO_SYSFS -static DEFINE_IDR(dirent_idr); -#endif - -static int gpiod_request(struct gpio_desc *desc, const char *label); -static void gpiod_free(struct gpio_desc *desc); - -/* With descriptor prefix */ - -#ifdef CONFIG_DEBUG_FS -#define gpiod_emerg(desc, fmt, ...) \ - pr_emerg("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?",\ - ##__VA_ARGS__) -#define gpiod_crit(desc, fmt, ...) \ - pr_crit("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \ - ##__VA_ARGS__) -#define gpiod_err(desc, fmt, ...) \ - pr_err("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \ - ##__VA_ARGS__) -#define gpiod_warn(desc, fmt, ...) \ - pr_warn("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \ - ##__VA_ARGS__) -#define gpiod_info(desc, fmt, ...) \ - pr_info("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \ - ##__VA_ARGS__) -#define gpiod_dbg(desc, fmt, ...) \ - pr_debug("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?",\ - ##__VA_ARGS__) -#else -#define gpiod_emerg(desc, fmt, ...) \ - pr_emerg("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) -#define gpiod_crit(desc, fmt, ...) \ - pr_crit("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) -#define gpiod_err(desc, fmt, ...) \ - pr_err("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) -#define gpiod_warn(desc, fmt, ...) \ - pr_warn("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) -#define gpiod_info(desc, fmt, ...) \ - pr_info("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) -#define gpiod_dbg(desc, fmt, ...) \ - pr_debug("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) -#endif - -/* With chip prefix */ - -#define chip_emerg(chip, fmt, ...) \ - pr_emerg("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__) -#define chip_crit(chip, fmt, ...) \ - pr_crit("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__) -#define chip_err(chip, fmt, ...) \ - pr_err("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__) -#define chip_warn(chip, fmt, ...) \ - pr_warn("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__) -#define chip_info(chip, fmt, ...) \ - pr_info("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__) -#define chip_dbg(chip, fmt, ...) \ - pr_debug("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__) +LIST_HEAD(gpio_chips); static inline void desc_set_label(struct gpio_desc *d, const char *label) { -#ifdef CONFIG_DEBUG_FS d->label = label; -#endif -} - -/* - * Return the GPIO number of the passed descriptor relative to its chip - */ -static int gpio_chip_hwgpio(const struct gpio_desc *desc) -{ - return desc - &desc->chip->desc[0]; } /** @@ -174,7 +83,6 @@ struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip, return &chip->desc[hwnum]; } -EXPORT_SYMBOL_GPL(gpiochip_get_desc); /** * Convert a GPIO descriptor to the integer namespace. @@ -188,39 +96,6 @@ int desc_to_gpio(const struct gpio_desc *desc) EXPORT_SYMBOL_GPL(desc_to_gpio); -/* Warn when drivers omit gpio_request() calls -- legal but ill-advised - * when setting direction, and otherwise illegal. Until board setup code - * and drivers use explicit requests everywhere (which won't happen when - * those calls have no teeth) we can't avoid autorequesting. This nag - * message should motivate switching to explicit requests... so should - * the weaker cleanup after faults, compared to gpio_request(). - * - * NOTE: the autorequest mechanism is going away; at this point it's - * only "legal" in the sense that (old) code using it won't break yet, - * but instead only triggers a WARN() stack dump. - */ -static int gpio_ensure_requested(struct gpio_desc *desc) -{ - const struct gpio_chip *chip = desc->chip; - const int gpio = desc_to_gpio(desc); - - if (WARN(test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0, - "autorequest GPIO-%d\n", gpio)) { - if (!try_module_get(chip->owner)) { - gpiod_err(desc, "%s: module can't be gotten\n", - __func__); - clear_bit(FLAG_REQUESTED, &desc->flags); - /* lose */ - return -EIO; - } - desc_set_label(desc, "[auto]"); - /* caller must chip->request() w/o spinlock */ - if (chip->request) - return 1; - } - return 0; -} - /** * gpiod_to_chip - Return the GPIO chip to which a GPIO descriptor belongs * @desc: descriptor to return the chip of @@ -291,836 +166,6 @@ int gpiod_get_direction(const struct gpio_desc *desc) } EXPORT_SYMBOL_GPL(gpiod_get_direction); -#ifdef CONFIG_GPIO_SYSFS - -/* lock protects against unexport_gpio() being called while - * sysfs files are active. - */ -static DEFINE_MUTEX(sysfs_lock); - -/* - * /sys/class/gpio/gpioN... only for GPIOs that are exported - * /direction - * * MAY BE OMITTED if kernel won't allow direction changes - * * is read/write as "in" or "out" - * * may also be written as "high" or "low", initializing - * output value as specified ("out" implies "low") - * /value - * * always readable, subject to hardware behavior - * * may be writable, as zero/nonzero - * /edge - * * configures behavior of poll(2) on /value - * * available only if pin can generate IRQs on input - * * is read/write as "none", "falling", "rising", or "both" - * /active_low - * * configures polarity of /value - * * is read/write as zero/nonzero - * * also affects existing and subsequent "falling" and "rising" - * /edge configuration - */ - -static ssize_t gpio_direction_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - const struct gpio_desc *desc = dev_get_drvdata(dev); - ssize_t status; - - mutex_lock(&sysfs_lock); - - if (!test_bit(FLAG_EXPORT, &desc->flags)) { - status = -EIO; - } else { - gpiod_get_direction(desc); - status = sprintf(buf, "%s\n", - test_bit(FLAG_IS_OUT, &desc->flags) - ? "out" : "in"); - } - - mutex_unlock(&sysfs_lock); - return status; -} - -static ssize_t gpio_direction_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - struct gpio_desc *desc = dev_get_drvdata(dev); - ssize_t status; - - mutex_lock(&sysfs_lock); - - if (!test_bit(FLAG_EXPORT, &desc->flags)) - status = -EIO; - else if (sysfs_streq(buf, "high")) - status = gpiod_direction_output_raw(desc, 1); - else if (sysfs_streq(buf, "out") || sysfs_streq(buf, "low")) - status = gpiod_direction_output_raw(desc, 0); - else if (sysfs_streq(buf, "in")) - status = gpiod_direction_input(desc); - else - status = -EINVAL; - - mutex_unlock(&sysfs_lock); - return status ? : size; -} - -static /* const */ DEVICE_ATTR(direction, 0644, - gpio_direction_show, gpio_direction_store); - -static ssize_t gpio_value_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct gpio_desc *desc = dev_get_drvdata(dev); - ssize_t status; - - mutex_lock(&sysfs_lock); - - if (!test_bit(FLAG_EXPORT, &desc->flags)) - status = -EIO; - else - status = sprintf(buf, "%d\n", gpiod_get_value_cansleep(desc)); - - mutex_unlock(&sysfs_lock); - return status; -} - -static ssize_t gpio_value_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - struct gpio_desc *desc = dev_get_drvdata(dev); - ssize_t status; - - mutex_lock(&sysfs_lock); - - if (!test_bit(FLAG_EXPORT, &desc->flags)) - status = -EIO; - else if (!test_bit(FLAG_IS_OUT, &desc->flags)) - status = -EPERM; - else { - long value; - - status = kstrtol(buf, 0, &value); - if (status == 0) { - gpiod_set_value_cansleep(desc, value); - status = size; - } - } - - mutex_unlock(&sysfs_lock); - return status; -} - -static const DEVICE_ATTR(value, 0644, - gpio_value_show, gpio_value_store); - -static irqreturn_t gpio_sysfs_irq(int irq, void *priv) -{ - struct kernfs_node *value_sd = priv; - - sysfs_notify_dirent(value_sd); - return IRQ_HANDLED; -} - -static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev, - unsigned long gpio_flags) -{ - struct kernfs_node *value_sd; - unsigned long irq_flags; - int ret, irq, id; - - if ((desc->flags & GPIO_TRIGGER_MASK) == gpio_flags) - return 0; - - irq = gpiod_to_irq(desc); - if (irq < 0) - return -EIO; - - id = desc->flags >> ID_SHIFT; - value_sd = idr_find(&dirent_idr, id); - if (value_sd) - free_irq(irq, value_sd); - - desc->flags &= ~GPIO_TRIGGER_MASK; - - if (!gpio_flags) { - gpiod_unlock_as_irq(desc); - ret = 0; - goto free_id; - } - - irq_flags = IRQF_SHARED; - if (test_bit(FLAG_TRIG_FALL, &gpio_flags)) - irq_flags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ? - IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING; - if (test_bit(FLAG_TRIG_RISE, &gpio_flags)) - irq_flags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ? - IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING; - - if (!value_sd) { - value_sd = sysfs_get_dirent(dev->kobj.sd, "value"); - if (!value_sd) { - ret = -ENODEV; - goto err_out; - } - - ret = idr_alloc(&dirent_idr, value_sd, 1, 0, GFP_KERNEL); - if (ret < 0) - goto free_sd; - id = ret; - - desc->flags &= GPIO_FLAGS_MASK; - desc->flags |= (unsigned long)id << ID_SHIFT; - - if (desc->flags >> ID_SHIFT != id) { - ret = -ERANGE; - goto free_id; - } - } - - ret = request_any_context_irq(irq, gpio_sysfs_irq, irq_flags, - "gpiolib", value_sd); - if (ret < 0) - goto free_id; - - ret = gpiod_lock_as_irq(desc); - if (ret < 0) { - gpiod_warn(desc, "failed to flag the GPIO for IRQ\n"); - goto free_id; - } - - desc->flags |= gpio_flags; - return 0; - -free_id: - idr_remove(&dirent_idr, id); - desc->flags &= GPIO_FLAGS_MASK; -free_sd: - if (value_sd) - sysfs_put(value_sd); -err_out: - return ret; -} - -static const struct { - const char *name; - unsigned long flags; -} trigger_types[] = { - { "none", 0 }, - { "falling", BIT(FLAG_TRIG_FALL) }, - { "rising", BIT(FLAG_TRIG_RISE) }, - { "both", BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE) }, -}; - -static ssize_t gpio_edge_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - const struct gpio_desc *desc = dev_get_drvdata(dev); - ssize_t status; - - mutex_lock(&sysfs_lock); - - if (!test_bit(FLAG_EXPORT, &desc->flags)) - status = -EIO; - else { - int i; - - status = 0; - for (i = 0; i < ARRAY_SIZE(trigger_types); i++) - if ((desc->flags & GPIO_TRIGGER_MASK) - == trigger_types[i].flags) { - status = sprintf(buf, "%s\n", - trigger_types[i].name); - break; - } - } - - mutex_unlock(&sysfs_lock); - return status; -} - -static ssize_t gpio_edge_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - struct gpio_desc *desc = dev_get_drvdata(dev); - ssize_t status; - int i; - - for (i = 0; i < ARRAY_SIZE(trigger_types); i++) - if (sysfs_streq(trigger_types[i].name, buf)) - goto found; - return -EINVAL; - -found: - mutex_lock(&sysfs_lock); - - if (!test_bit(FLAG_EXPORT, &desc->flags)) - status = -EIO; - else { - status = gpio_setup_irq(desc, dev, trigger_types[i].flags); - if (!status) - status = size; - } - - mutex_unlock(&sysfs_lock); - - return status; -} - -static DEVICE_ATTR(edge, 0644, gpio_edge_show, gpio_edge_store); - -static int sysfs_set_active_low(struct gpio_desc *desc, struct device *dev, - int value) -{ - int status = 0; - - if (!!test_bit(FLAG_ACTIVE_LOW, &desc->flags) == !!value) - return 0; - - if (value) - set_bit(FLAG_ACTIVE_LOW, &desc->flags); - else - clear_bit(FLAG_ACTIVE_LOW, &desc->flags); - - /* reconfigure poll(2) support if enabled on one edge only */ - if (dev != NULL && (!!test_bit(FLAG_TRIG_RISE, &desc->flags) ^ - !!test_bit(FLAG_TRIG_FALL, &desc->flags))) { - unsigned long trigger_flags = desc->flags & GPIO_TRIGGER_MASK; - - gpio_setup_irq(desc, dev, 0); - status = gpio_setup_irq(desc, dev, trigger_flags); - } - - return status; -} - -static ssize_t gpio_active_low_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - const struct gpio_desc *desc = dev_get_drvdata(dev); - ssize_t status; - - mutex_lock(&sysfs_lock); - - if (!test_bit(FLAG_EXPORT, &desc->flags)) - status = -EIO; - else - status = sprintf(buf, "%d\n", - !!test_bit(FLAG_ACTIVE_LOW, &desc->flags)); - - mutex_unlock(&sysfs_lock); - - return status; -} - -static ssize_t gpio_active_low_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - struct gpio_desc *desc = dev_get_drvdata(dev); - ssize_t status; - - mutex_lock(&sysfs_lock); - - if (!test_bit(FLAG_EXPORT, &desc->flags)) { - status = -EIO; - } else { - long value; - - status = kstrtol(buf, 0, &value); - if (status == 0) - status = sysfs_set_active_low(desc, dev, value != 0); - } - - mutex_unlock(&sysfs_lock); - - return status ? : size; -} - -static const DEVICE_ATTR(active_low, 0644, - gpio_active_low_show, gpio_active_low_store); - -static const struct attribute *gpio_attrs[] = { - &dev_attr_value.attr, - &dev_attr_active_low.attr, - NULL, -}; - -static const struct attribute_group gpio_attr_group = { - .attrs = (struct attribute **) gpio_attrs, -}; - -/* - * /sys/class/gpio/gpiochipN/ - * /base ... matching gpio_chip.base (N) - * /label ... matching gpio_chip.label - * /ngpio ... matching gpio_chip.ngpio - */ - -static ssize_t chip_base_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - const struct gpio_chip *chip = dev_get_drvdata(dev); - - return sprintf(buf, "%d\n", chip->base); -} -static DEVICE_ATTR(base, 0444, chip_base_show, NULL); - -static ssize_t chip_label_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - const struct gpio_chip *chip = dev_get_drvdata(dev); - - return sprintf(buf, "%s\n", chip->label ? : ""); -} -static DEVICE_ATTR(label, 0444, chip_label_show, NULL); - -static ssize_t chip_ngpio_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - const struct gpio_chip *chip = dev_get_drvdata(dev); - - return sprintf(buf, "%u\n", chip->ngpio); -} -static DEVICE_ATTR(ngpio, 0444, chip_ngpio_show, NULL); - -static const struct attribute *gpiochip_attrs[] = { - &dev_attr_base.attr, - &dev_attr_label.attr, - &dev_attr_ngpio.attr, - NULL, -}; - -static const struct attribute_group gpiochip_attr_group = { - .attrs = (struct attribute **) gpiochip_attrs, -}; - -/* - * /sys/class/gpio/export ... write-only - * integer N ... number of GPIO to export (full access) - * /sys/class/gpio/unexport ... write-only - * integer N ... number of GPIO to unexport - */ -static ssize_t export_store(struct class *class, - struct class_attribute *attr, - const char *buf, size_t len) -{ - long gpio; - struct gpio_desc *desc; - int status; - - status = kstrtol(buf, 0, &gpio); - if (status < 0) - goto done; - - desc = gpio_to_desc(gpio); - /* reject invalid GPIOs */ - if (!desc) { - pr_warn("%s: invalid GPIO %ld\n", __func__, gpio); - return -EINVAL; - } - - /* No extra locking here; FLAG_SYSFS just signifies that the - * request and export were done by on behalf of userspace, so - * they may be undone on its behalf too. - */ - - status = gpiod_request(desc, "sysfs"); - if (status < 0) { - if (status == -EPROBE_DEFER) - status = -ENODEV; - goto done; - } - status = gpiod_export(desc, true); - if (status < 0) - gpiod_free(desc); - else - set_bit(FLAG_SYSFS, &desc->flags); - -done: - if (status) - pr_debug("%s: status %d\n", __func__, status); - return status ? : len; -} - -static ssize_t unexport_store(struct class *class, - struct class_attribute *attr, - const char *buf, size_t len) -{ - long gpio; - struct gpio_desc *desc; - int status; - - status = kstrtol(buf, 0, &gpio); - if (status < 0) - goto done; - - desc = gpio_to_desc(gpio); - /* reject bogus commands (gpio_unexport ignores them) */ - if (!desc) { - pr_warn("%s: invalid GPIO %ld\n", __func__, gpio); - return -EINVAL; - } - - status = -EINVAL; - - /* No extra locking here; FLAG_SYSFS just signifies that the - * request and export were done by on behalf of userspace, so - * they may be undone on its behalf too. - */ - if (test_and_clear_bit(FLAG_SYSFS, &desc->flags)) { - status = 0; - gpiod_free(desc); - } -done: - if (status) - pr_debug("%s: status %d\n", __func__, status); - return status ? : len; -} - -static struct class_attribute gpio_class_attrs[] = { - __ATTR(export, 0200, NULL, export_store), - __ATTR(unexport, 0200, NULL, unexport_store), - __ATTR_NULL, -}; - -static struct class gpio_class = { - .name = "gpio", - .owner = THIS_MODULE, - - .class_attrs = gpio_class_attrs, -}; - - -/** - * gpiod_export - export a GPIO through sysfs - * @gpio: gpio to make available, already requested - * @direction_may_change: true if userspace may change gpio direction - * Context: arch_initcall or later - * - * When drivers want to make a GPIO accessible to userspace after they - * have requested it -- perhaps while debugging, or as part of their - * public interface -- they may use this routine. If the GPIO can - * change direction (some can't) and the caller allows it, userspace - * will see "direction" sysfs attribute which may be used to change - * the gpio's direction. A "value" attribute will always be provided. - * - * Returns zero on success, else an error. - */ -int gpiod_export(struct gpio_desc *desc, bool direction_may_change) -{ - unsigned long flags; - int status; - const char *ioname = NULL; - struct device *dev; - int offset; - - /* can't export until sysfs is available ... */ - if (!gpio_class.p) { - pr_debug("%s: called too early!\n", __func__); - return -ENOENT; - } - - if (!desc) { - pr_debug("%s: invalid gpio descriptor\n", __func__); - return -EINVAL; - } - - mutex_lock(&sysfs_lock); - - spin_lock_irqsave(&gpio_lock, flags); - if (!test_bit(FLAG_REQUESTED, &desc->flags) || - test_bit(FLAG_EXPORT, &desc->flags)) { - spin_unlock_irqrestore(&gpio_lock, flags); - gpiod_dbg(desc, "%s: unavailable (requested=%d, exported=%d)\n", - __func__, - test_bit(FLAG_REQUESTED, &desc->flags), - test_bit(FLAG_EXPORT, &desc->flags)); - status = -EPERM; - goto fail_unlock; - } - - if (!desc->chip->direction_input || !desc->chip->direction_output) - direction_may_change = false; - spin_unlock_irqrestore(&gpio_lock, flags); - - offset = gpio_chip_hwgpio(desc); - if (desc->chip->names && desc->chip->names[offset]) - ioname = desc->chip->names[offset]; - - dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0), - desc, ioname ? ioname : "gpio%u", - desc_to_gpio(desc)); - if (IS_ERR(dev)) { - status = PTR_ERR(dev); - goto fail_unlock; - } - - status = sysfs_create_group(&dev->kobj, &gpio_attr_group); - if (status) - goto fail_unregister_device; - - if (direction_may_change) { - status = device_create_file(dev, &dev_attr_direction); - if (status) - goto fail_unregister_device; - } - - if (gpiod_to_irq(desc) >= 0 && (direction_may_change || - !test_bit(FLAG_IS_OUT, &desc->flags))) { - status = device_create_file(dev, &dev_attr_edge); - if (status) - goto fail_unregister_device; - } - - set_bit(FLAG_EXPORT, &desc->flags); - mutex_unlock(&sysfs_lock); - return 0; - -fail_unregister_device: - device_unregister(dev); -fail_unlock: - mutex_unlock(&sysfs_lock); - gpiod_dbg(desc, "%s: status %d\n", __func__, status); - return status; -} -EXPORT_SYMBOL_GPL(gpiod_export); - -static int match_export(struct device *dev, const void *data) -{ - return dev_get_drvdata(dev) == data; -} - -/** - * gpiod_export_link - create a sysfs link to an exported GPIO node - * @dev: device under which to create symlink - * @name: name of the symlink - * @gpio: gpio to create symlink to, already exported - * - * Set up a symlink from /sys/.../dev/name to /sys/class/gpio/gpioN - * node. Caller is responsible for unlinking. - * - * Returns zero on success, else an error. - */ -int gpiod_export_link(struct device *dev, const char *name, - struct gpio_desc *desc) -{ - int status = -EINVAL; - - if (!desc) { - pr_warn("%s: invalid GPIO\n", __func__); - return -EINVAL; - } - - mutex_lock(&sysfs_lock); - - if (test_bit(FLAG_EXPORT, &desc->flags)) { - struct device *tdev; - - tdev = class_find_device(&gpio_class, NULL, desc, match_export); - if (tdev != NULL) { - status = sysfs_create_link(&dev->kobj, &tdev->kobj, - name); - } else { - status = -ENODEV; - } - } - - mutex_unlock(&sysfs_lock); - - if (status) - gpiod_dbg(desc, "%s: status %d\n", __func__, status); - - return status; -} -EXPORT_SYMBOL_GPL(gpiod_export_link); - -/** - * gpiod_sysfs_set_active_low - set the polarity of gpio sysfs value - * @gpio: gpio to change - * @value: non-zero to use active low, i.e. inverted values - * - * Set the polarity of /sys/class/gpio/gpioN/value sysfs attribute. - * The GPIO does not have to be exported yet. If poll(2) support has - * been enabled for either rising or falling edge, it will be - * reconfigured to follow the new polarity. - * - * Returns zero on success, else an error. - */ -int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value) -{ - struct device *dev = NULL; - int status = -EINVAL; - - if (!desc) { - pr_warn("%s: invalid GPIO\n", __func__); - return -EINVAL; - } - - mutex_lock(&sysfs_lock); - - if (test_bit(FLAG_EXPORT, &desc->flags)) { - dev = class_find_device(&gpio_class, NULL, desc, match_export); - if (dev == NULL) { - status = -ENODEV; - goto unlock; - } - } - - status = sysfs_set_active_low(desc, dev, value); - -unlock: - mutex_unlock(&sysfs_lock); - - if (status) - gpiod_dbg(desc, "%s: status %d\n", __func__, status); - - return status; -} -EXPORT_SYMBOL_GPL(gpiod_sysfs_set_active_low); - -/** - * gpiod_unexport - reverse effect of gpio_export() - * @gpio: gpio to make unavailable - * - * This is implicit on gpio_free(). - */ -void gpiod_unexport(struct gpio_desc *desc) -{ - int status = 0; - struct device *dev = NULL; - - if (!desc) { - pr_warn("%s: invalid GPIO\n", __func__); - return; - } - - mutex_lock(&sysfs_lock); - - if (test_bit(FLAG_EXPORT, &desc->flags)) { - - dev = class_find_device(&gpio_class, NULL, desc, match_export); - if (dev) { - gpio_setup_irq(desc, dev, 0); - clear_bit(FLAG_EXPORT, &desc->flags); - } else - status = -ENODEV; - } - - mutex_unlock(&sysfs_lock); - - if (dev) { - device_unregister(dev); - put_device(dev); - } - - if (status) - gpiod_dbg(desc, "%s: status %d\n", __func__, status); -} -EXPORT_SYMBOL_GPL(gpiod_unexport); - -static int gpiochip_export(struct gpio_chip *chip) -{ - int status; - struct device *dev; - - /* Many systems register gpio chips for SOC support very early, - * before driver model support is available. In those cases we - * export this later, in gpiolib_sysfs_init() ... here we just - * verify that _some_ field of gpio_class got initialized. - */ - if (!gpio_class.p) - return 0; - - /* use chip->base for the ID; it's already known to be unique */ - mutex_lock(&sysfs_lock); - dev = device_create(&gpio_class, chip->dev, MKDEV(0, 0), chip, - "gpiochip%d", chip->base); - if (!IS_ERR(dev)) { - status = sysfs_create_group(&dev->kobj, - &gpiochip_attr_group); - } else - status = PTR_ERR(dev); - chip->exported = (status == 0); - mutex_unlock(&sysfs_lock); - - if (status) { - unsigned long flags; - unsigned gpio; - - spin_lock_irqsave(&gpio_lock, flags); - gpio = 0; - while (gpio < chip->ngpio) - chip->desc[gpio++].chip = NULL; - spin_unlock_irqrestore(&gpio_lock, flags); - - chip_dbg(chip, "%s: status %d\n", __func__, status); - } - - return status; -} - -static void gpiochip_unexport(struct gpio_chip *chip) -{ - int status; - struct device *dev; - - mutex_lock(&sysfs_lock); - dev = class_find_device(&gpio_class, NULL, chip, match_export); - if (dev) { - put_device(dev); - device_unregister(dev); - chip->exported = false; - status = 0; - } else - status = -ENODEV; - mutex_unlock(&sysfs_lock); - - if (status) - chip_dbg(chip, "%s: status %d\n", __func__, status); -} - -static int __init gpiolib_sysfs_init(void) -{ - int status; - unsigned long flags; - struct gpio_chip *chip; - - status = class_register(&gpio_class); - if (status < 0) - return status; - - /* Scan and register the gpio_chips which registered very - * early (e.g. before the class_register above was called). - * - * We run before arch_initcall() so chip->dev nodes can have - * registered, and so arch_initcall() can always gpio_export(). - */ - spin_lock_irqsave(&gpio_lock, flags); - list_for_each_entry(chip, &gpio_chips, list) { - if (!chip || chip->exported) - continue; - - spin_unlock_irqrestore(&gpio_lock, flags); - status = gpiochip_export(chip); - spin_lock_irqsave(&gpio_lock, flags); - } - spin_unlock_irqrestore(&gpio_lock, flags); - - - return status; -} -postcore_initcall(gpiolib_sysfs_init); - -#else -static inline int gpiochip_export(struct gpio_chip *chip) -{ - return 0; -} - -static inline void gpiochip_unexport(struct gpio_chip *chip) -{ -} - -#endif /* CONFIG_GPIO_SYSFS */ - /* * Add a new chip to the global chips list, keeping the list of chips sorted * by base order. @@ -1474,6 +519,8 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) { unsigned int offset; + acpi_gpiochip_free_interrupts(gpiochip); + /* Remove all IRQ mappings and delete the domain */ if (gpiochip->irqdomain) { for (offset = 0; offset < gpiochip->ngpio; offset++) @@ -1567,6 +614,8 @@ int gpiochip_irqchip_add(struct gpio_chip *gpiochip, gpiochip->irq_base = irq_base; } + acpi_gpiochip_request_interrupts(gpiochip); + return 0; } EXPORT_SYMBOL_GPL(gpiochip_irqchip_add); @@ -1740,7 +789,7 @@ done: return status; } -static int gpiod_request(struct gpio_desc *desc, const char *label) +int gpiod_request(struct gpio_desc *desc, const char *label) { int status = -EPROBE_DEFER; struct gpio_chip *chip; @@ -1767,12 +816,6 @@ done: return status; } -int gpio_request(unsigned gpio, const char *label) -{ - return gpiod_request(gpio_to_desc(gpio), label); -} -EXPORT_SYMBOL_GPL(gpio_request); - static bool __gpiod_free(struct gpio_desc *desc) { bool ret = false; @@ -1805,7 +848,7 @@ static bool __gpiod_free(struct gpio_desc *desc) return ret; } -static void gpiod_free(struct gpio_desc *desc) +void gpiod_free(struct gpio_desc *desc) { if (desc && __gpiod_free(desc)) module_put(desc->chip->owner); @@ -1813,101 +856,14 @@ static void gpiod_free(struct gpio_desc *desc) WARN_ON(extra_checks); } -void gpio_free(unsigned gpio) -{ - gpiod_free(gpio_to_desc(gpio)); -} -EXPORT_SYMBOL_GPL(gpio_free); - -/** - * gpio_request_one - request a single GPIO with initial configuration - * @gpio: the GPIO number - * @flags: GPIO configuration as specified by GPIOF_* - * @label: a literal description string of this GPIO - */ -int gpio_request_one(unsigned gpio, unsigned long flags, const char *label) -{ - struct gpio_desc *desc; - int err; - - desc = gpio_to_desc(gpio); - - err = gpiod_request(desc, label); - if (err) - return err; - - if (flags & GPIOF_OPEN_DRAIN) - set_bit(FLAG_OPEN_DRAIN, &desc->flags); - - if (flags & GPIOF_OPEN_SOURCE) - set_bit(FLAG_OPEN_SOURCE, &desc->flags); - - if (flags & GPIOF_DIR_IN) - err = gpiod_direction_input(desc); - else - err = gpiod_direction_output_raw(desc, - (flags & GPIOF_INIT_HIGH) ? 1 : 0); - - if (err) - goto free_gpio; - - if (flags & GPIOF_EXPORT) { - err = gpiod_export(desc, flags & GPIOF_EXPORT_CHANGEABLE); - if (err) - goto free_gpio; - } - - return 0; - - free_gpio: - gpiod_free(desc); - return err; -} -EXPORT_SYMBOL_GPL(gpio_request_one); - -/** - * gpio_request_array - request multiple GPIOs in a single call - * @array: array of the 'struct gpio' - * @num: how many GPIOs in the array - */ -int gpio_request_array(const struct gpio *array, size_t num) -{ - int i, err; - - for (i = 0; i < num; i++, array++) { - err = gpio_request_one(array->gpio, array->flags, array->label); - if (err) - goto err_free; - } - return 0; - -err_free: - while (i--) - gpio_free((--array)->gpio); - return err; -} -EXPORT_SYMBOL_GPL(gpio_request_array); - -/** - * gpio_free_array - release multiple GPIOs in a single call - * @array: array of the 'struct gpio' - * @num: how many GPIOs in the array - */ -void gpio_free_array(const struct gpio *array, size_t num) -{ - while (num--) - gpio_free((array++)->gpio); -} -EXPORT_SYMBOL_GPL(gpio_free_array); - /** * gpiochip_is_requested - return string iff signal was requested * @chip: controller managing the signal * @offset: of signal within controller's 0..(ngpio - 1) range * * Returns NULL if the GPIO is not currently requested, else a string. - * If debugfs support is enabled, the string returned is the label passed - * to gpio_request(); otherwise it is a meaningless constant. + * The string returned is the label passed to gpio_request(); if none has been + * passed it is a meaningless, non-NULL constant. * * This function is for use by GPIO controller drivers. The label can * help with diagnostics, and knowing that the signal is used as a GPIO @@ -1924,11 +880,7 @@ const char *gpiochip_is_requested(struct gpio_chip *chip, unsigned offset) if (test_bit(FLAG_REQUESTED, &desc->flags) == 0) return NULL; -#ifdef CONFIG_DEBUG_FS return desc->label; -#else - return "?"; -#endif } EXPORT_SYMBOL_GPL(gpiochip_is_requested); @@ -1950,6 +902,7 @@ int gpiochip_request_own_desc(struct gpio_desc *desc, const char *label) return __gpiod_request(desc, label); } +EXPORT_SYMBOL_GPL(gpiochip_request_own_desc); /** * gpiochip_free_own_desc - Free GPIO requested by the chip driver @@ -1963,6 +916,7 @@ void gpiochip_free_own_desc(struct gpio_desc *desc) if (desc) __gpiod_free(desc); } +EXPORT_SYMBOL_GPL(gpiochip_free_own_desc); /* Drivers MUST set GPIO direction before making get/set calls. In * some cases this is done in early boot, before IRQs are enabled. @@ -1984,10 +938,8 @@ void gpiochip_free_own_desc(struct gpio_desc *desc) */ int gpiod_direction_input(struct gpio_desc *desc) { - unsigned long flags; struct gpio_chip *chip; int status = -EINVAL; - int offset; if (!desc || !desc->chip) { pr_warn("%s: invalid GPIO\n", __func__); @@ -2002,52 +954,20 @@ int gpiod_direction_input(struct gpio_desc *desc) return -EIO; } - spin_lock_irqsave(&gpio_lock, flags); - - status = gpio_ensure_requested(desc); - if (status < 0) - goto fail; - - /* now we know the gpio is valid and chip won't vanish */ - - spin_unlock_irqrestore(&gpio_lock, flags); - - might_sleep_if(chip->can_sleep); - - offset = gpio_chip_hwgpio(desc); - if (status) { - status = chip->request(chip, offset); - if (status < 0) { - gpiod_dbg(desc, "%s: chip request fail, %d\n", - __func__, status); - /* and it's not available to anyone else ... - * gpio_request() is the fully clean solution. - */ - goto lose; - } - } - - status = chip->direction_input(chip, offset); + status = chip->direction_input(chip, gpio_chip_hwgpio(desc)); if (status == 0) clear_bit(FLAG_IS_OUT, &desc->flags); trace_gpio_direction(desc_to_gpio(desc), 1, status); -lose: - return status; -fail: - spin_unlock_irqrestore(&gpio_lock, flags); - if (status) - gpiod_dbg(desc, "%s: status %d\n", __func__, status); + return status; } EXPORT_SYMBOL_GPL(gpiod_direction_input); static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value) { - unsigned long flags; struct gpio_chip *chip; int status = -EINVAL; - int offset; /* GPIOs used for IRQs shall not be set as output */ if (test_bit(FLAG_USED_AS_IRQ, &desc->flags)) { @@ -2073,42 +993,11 @@ static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value) return -EIO; } - spin_lock_irqsave(&gpio_lock, flags); - - status = gpio_ensure_requested(desc); - if (status < 0) - goto fail; - - /* now we know the gpio is valid and chip won't vanish */ - - spin_unlock_irqrestore(&gpio_lock, flags); - - might_sleep_if(chip->can_sleep); - - offset = gpio_chip_hwgpio(desc); - if (status) { - status = chip->request(chip, offset); - if (status < 0) { - gpiod_dbg(desc, "%s: chip request fail, %d\n", - __func__, status); - /* and it's not available to anyone else ... - * gpio_request() is the fully clean solution. - */ - goto lose; - } - } - - status = chip->direction_output(chip, offset, value); + status = chip->direction_output(chip, gpio_chip_hwgpio(desc), value); if (status == 0) set_bit(FLAG_IS_OUT, &desc->flags); trace_gpio_value(desc_to_gpio(desc), 0, value); trace_gpio_direction(desc_to_gpio(desc), 0, status); -lose: - return status; -fail: - spin_unlock_irqrestore(&gpio_lock, flags); - if (status) - gpiod_dbg(desc, "%s: gpio status %d\n", __func__, status); return status; } @@ -2167,10 +1056,7 @@ EXPORT_SYMBOL_GPL(gpiod_direction_output); */ int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) { - unsigned long flags; struct gpio_chip *chip; - int status = -EINVAL; - int offset; if (!desc || !desc->chip) { pr_warn("%s: invalid GPIO\n", __func__); @@ -2185,27 +1071,7 @@ int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) return -ENOTSUPP; } - spin_lock_irqsave(&gpio_lock, flags); - - status = gpio_ensure_requested(desc); - if (status < 0) - goto fail; - - /* now we know the gpio is valid and chip won't vanish */ - - spin_unlock_irqrestore(&gpio_lock, flags); - - might_sleep_if(chip->can_sleep); - - offset = gpio_chip_hwgpio(desc); - return chip->set_debounce(chip, offset, debounce); - -fail: - spin_unlock_irqrestore(&gpio_lock, flags); - if (status) - gpiod_dbg(desc, "%s: status %d\n", __func__, status); - - return status; + return chip->set_debounce(chip, gpio_chip_hwgpio(desc), debounce); } EXPORT_SYMBOL_GPL(gpiod_set_debounce); @@ -2448,54 +1314,44 @@ int gpiod_to_irq(const struct gpio_desc *desc) EXPORT_SYMBOL_GPL(gpiod_to_irq); /** - * gpiod_lock_as_irq() - lock a GPIO to be used as IRQ - * @gpio: the GPIO line to lock as used for IRQ + * gpio_lock_as_irq() - lock a GPIO to be used as IRQ + * @chip: the chip the GPIO to lock belongs to + * @offset: the offset of the GPIO to lock as IRQ * * This is used directly by GPIO drivers that want to lock down * a certain GPIO line to be used for IRQs. */ -int gpiod_lock_as_irq(struct gpio_desc *desc) +int gpio_lock_as_irq(struct gpio_chip *chip, unsigned int offset) { - if (!desc) + if (offset >= chip->ngpio) return -EINVAL; - if (test_bit(FLAG_IS_OUT, &desc->flags)) { - gpiod_err(desc, + if (test_bit(FLAG_IS_OUT, &chip->desc[offset].flags)) { + chip_err(chip, "%s: tried to flag a GPIO set as output for IRQ\n", __func__); return -EIO; } - set_bit(FLAG_USED_AS_IRQ, &desc->flags); + set_bit(FLAG_USED_AS_IRQ, &chip->desc[offset].flags); return 0; } -EXPORT_SYMBOL_GPL(gpiod_lock_as_irq); - -int gpio_lock_as_irq(struct gpio_chip *chip, unsigned int offset) -{ - return gpiod_lock_as_irq(gpiochip_get_desc(chip, offset)); -} EXPORT_SYMBOL_GPL(gpio_lock_as_irq); /** - * gpiod_unlock_as_irq() - unlock a GPIO used as IRQ - * @gpio: the GPIO line to unlock from IRQ usage + * gpio_unlock_as_irq() - unlock a GPIO used as IRQ + * @chip: the chip the GPIO to lock belongs to + * @offset: the offset of the GPIO to lock as IRQ * * This is used directly by GPIO drivers that want to indicate * that a certain GPIO is no longer used exclusively for IRQ. */ -void gpiod_unlock_as_irq(struct gpio_desc *desc) +void gpio_unlock_as_irq(struct gpio_chip *chip, unsigned int offset) { - if (!desc) + if (offset >= chip->ngpio) return; - clear_bit(FLAG_USED_AS_IRQ, &desc->flags); -} -EXPORT_SYMBOL_GPL(gpiod_unlock_as_irq); - -void gpio_unlock_as_irq(struct gpio_chip *chip, unsigned int offset) -{ - return gpiod_unlock_as_irq(gpiochip_get_desc(chip, offset)); + clear_bit(FLAG_USED_AS_IRQ, &chip->desc[offset].flags); } EXPORT_SYMBOL_GPL(gpio_unlock_as_irq); @@ -2726,38 +1582,43 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, * gpiod_get - obtain a GPIO for a given GPIO function * @dev: GPIO consumer, can be NULL for system-global GPIOs * @con_id: function within the GPIO consumer + * @flags: optional GPIO initialization flags * * Return the GPIO descriptor corresponding to the function con_id of device * dev, -ENOENT if no GPIO has been assigned to the requested function, or * another IS_ERR() code if an error occured while trying to acquire the GPIO. */ -struct gpio_desc *__must_check gpiod_get(struct device *dev, const char *con_id) +struct gpio_desc *__must_check __gpiod_get(struct device *dev, const char *con_id, + enum gpiod_flags flags) { - return gpiod_get_index(dev, con_id, 0); + return gpiod_get_index(dev, con_id, 0, flags); } -EXPORT_SYMBOL_GPL(gpiod_get); +EXPORT_SYMBOL_GPL(__gpiod_get); /** * gpiod_get_optional - obtain an optional GPIO for a given GPIO function * @dev: GPIO consumer, can be NULL for system-global GPIOs * @con_id: function within the GPIO consumer + * @flags: optional GPIO initialization flags * * This is equivalent to gpiod_get(), except that when no GPIO was assigned to * the requested function it will return NULL. This is convenient for drivers * that need to handle optional GPIOs. */ -struct gpio_desc *__must_check gpiod_get_optional(struct device *dev, - const char *con_id) +struct gpio_desc *__must_check __gpiod_get_optional(struct device *dev, + const char *con_id, + enum gpiod_flags flags) { - return gpiod_get_index_optional(dev, con_id, 0); + return gpiod_get_index_optional(dev, con_id, 0, flags); } -EXPORT_SYMBOL_GPL(gpiod_get_optional); +EXPORT_SYMBOL_GPL(__gpiod_get_optional); /** * gpiod_get_index - obtain a GPIO from a multi-index GPIO function * @dev: GPIO consumer, can be NULL for system-global GPIOs * @con_id: function within the GPIO consumer * @idx: index of the GPIO to obtain in the consumer + * @flags: optional GPIO initialization flags * * This variant of gpiod_get() allows to access GPIOs other than the first * defined one for functions that define several GPIOs. @@ -2766,23 +1627,24 @@ EXPORT_SYMBOL_GPL(gpiod_get_optional); * requested function and/or index, or another IS_ERR() code if an error * occured while trying to acquire the GPIO. */ -struct gpio_desc *__must_check gpiod_get_index(struct device *dev, +struct gpio_desc *__must_check __gpiod_get_index(struct device *dev, const char *con_id, - unsigned int idx) + unsigned int idx, + enum gpiod_flags flags) { struct gpio_desc *desc = NULL; int status; - enum gpio_lookup_flags flags = 0; + enum gpio_lookup_flags lookupflags = 0; dev_dbg(dev, "GPIO lookup for consumer %s\n", con_id); /* Using device tree? */ if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node) { dev_dbg(dev, "using device tree for GPIO lookup\n"); - desc = of_find_gpio(dev, con_id, idx, &flags); + desc = of_find_gpio(dev, con_id, idx, &lookupflags); } else if (IS_ENABLED(CONFIG_ACPI) && dev && ACPI_HANDLE(dev)) { dev_dbg(dev, "using ACPI for GPIO lookup\n"); - desc = acpi_find_gpio(dev, con_id, idx, &flags); + desc = acpi_find_gpio(dev, con_id, idx, &lookupflags); } /* @@ -2791,7 +1653,7 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev, */ if (!desc || desc == ERR_PTR(-ENOENT)) { dev_dbg(dev, "using lookup tables for GPIO lookup"); - desc = gpiod_find(dev, con_id, idx, &flags); + desc = gpiod_find(dev, con_id, idx, &lookupflags); } if (IS_ERR(desc)) { @@ -2804,16 +1666,33 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev, if (status < 0) return ERR_PTR(status); - if (flags & GPIO_ACTIVE_LOW) + if (lookupflags & GPIO_ACTIVE_LOW) set_bit(FLAG_ACTIVE_LOW, &desc->flags); - if (flags & GPIO_OPEN_DRAIN) + if (lookupflags & GPIO_OPEN_DRAIN) set_bit(FLAG_OPEN_DRAIN, &desc->flags); - if (flags & GPIO_OPEN_SOURCE) + if (lookupflags & GPIO_OPEN_SOURCE) set_bit(FLAG_OPEN_SOURCE, &desc->flags); + /* No particular flag request, return here... */ + if (flags & GPIOD_FLAGS_BIT_DIR_SET) + return desc; + + /* Process flags */ + if (flags & GPIOD_FLAGS_BIT_DIR_OUT) + status = gpiod_direction_output(desc, + flags & GPIOD_FLAGS_BIT_DIR_VAL); + else + status = gpiod_direction_input(desc); + + if (status < 0) { + dev_dbg(dev, "setup of GPIO %s failed\n", con_id); + gpiod_put(desc); + return ERR_PTR(status); + } + return desc; } -EXPORT_SYMBOL_GPL(gpiod_get_index); +EXPORT_SYMBOL_GPL(__gpiod_get_index); /** * gpiod_get_index_optional - obtain an optional GPIO from a multi-index GPIO @@ -2821,18 +1700,20 @@ EXPORT_SYMBOL_GPL(gpiod_get_index); * @dev: GPIO consumer, can be NULL for system-global GPIOs * @con_id: function within the GPIO consumer * @index: index of the GPIO to obtain in the consumer + * @flags: optional GPIO initialization flags * * This is equivalent to gpiod_get_index(), except that when no GPIO with the * specified index was assigned to the requested function it will return NULL. * This is convenient for drivers that need to handle optional GPIOs. */ -struct gpio_desc *__must_check gpiod_get_index_optional(struct device *dev, +struct gpio_desc *__must_check __gpiod_get_index_optional(struct device *dev, const char *con_id, - unsigned int index) + unsigned int index, + enum gpiod_flags flags) { struct gpio_desc *desc; - desc = gpiod_get_index(dev, con_id, index); + desc = gpiod_get_index(dev, con_id, index, flags); if (IS_ERR(desc)) { if (PTR_ERR(desc) == -ENOENT) return NULL; @@ -2840,7 +1721,7 @@ struct gpio_desc *__must_check gpiod_get_index_optional(struct device *dev, return desc; } -EXPORT_SYMBOL_GPL(gpiod_get_index_optional); +EXPORT_SYMBOL_GPL(__gpiod_get_index_optional); /** * gpiod_put - dispose of a GPIO descriptor diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index 1a4103dd38df..9db2b6a71c5d 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -31,12 +31,21 @@ struct acpi_gpio_info { void acpi_gpiochip_add(struct gpio_chip *chip); void acpi_gpiochip_remove(struct gpio_chip *chip); +void acpi_gpiochip_request_interrupts(struct gpio_chip *chip); +void acpi_gpiochip_free_interrupts(struct gpio_chip *chip); + struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index, struct acpi_gpio_info *info); #else static inline void acpi_gpiochip_add(struct gpio_chip *chip) { } static inline void acpi_gpiochip_remove(struct gpio_chip *chip) { } +static inline void +acpi_gpiochip_request_interrupts(struct gpio_chip *chip) { } + +static inline void +acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { } + static inline struct gpio_desc * acpi_get_gpiod_by_index(struct device *dev, int index, struct acpi_gpio_info *info) @@ -45,10 +54,100 @@ acpi_get_gpiod_by_index(struct device *dev, int index, } #endif -int gpiochip_request_own_desc(struct gpio_desc *desc, const char *label); -void gpiochip_free_own_desc(struct gpio_desc *desc); - struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np, const char *list_name, int index, enum of_gpio_flags *flags); +struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip, u16 hwnum); + +extern struct spinlock gpio_lock; +extern struct list_head gpio_chips; + +struct gpio_desc { + struct gpio_chip *chip; + unsigned long flags; +/* flag symbols are bit numbers */ +#define FLAG_REQUESTED 0 +#define FLAG_IS_OUT 1 +#define FLAG_EXPORT 2 /* protected by sysfs_lock */ +#define FLAG_SYSFS 3 /* exported via /sys/class/gpio/control */ +#define FLAG_TRIG_FALL 4 /* trigger on falling edge */ +#define FLAG_TRIG_RISE 5 /* trigger on rising edge */ +#define FLAG_ACTIVE_LOW 6 /* value has active low */ +#define FLAG_OPEN_DRAIN 7 /* Gpio is open drain type */ +#define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */ +#define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */ + +#define ID_SHIFT 16 /* add new flags before this one */ + +#define GPIO_FLAGS_MASK ((1 << ID_SHIFT) - 1) +#define GPIO_TRIGGER_MASK (BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE)) + + const char *label; +}; + +int gpiod_request(struct gpio_desc *desc, const char *label); +void gpiod_free(struct gpio_desc *desc); + +/* + * Return the GPIO number of the passed descriptor relative to its chip + */ +static int __maybe_unused gpio_chip_hwgpio(const struct gpio_desc *desc) +{ + return desc - &desc->chip->desc[0]; +} + +/* With descriptor prefix */ + +#define gpiod_emerg(desc, fmt, ...) \ + pr_emerg("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?",\ + ##__VA_ARGS__) +#define gpiod_crit(desc, fmt, ...) \ + pr_crit("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \ + ##__VA_ARGS__) +#define gpiod_err(desc, fmt, ...) \ + pr_err("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \ + ##__VA_ARGS__) +#define gpiod_warn(desc, fmt, ...) \ + pr_warn("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \ + ##__VA_ARGS__) +#define gpiod_info(desc, fmt, ...) \ + pr_info("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \ + ##__VA_ARGS__) +#define gpiod_dbg(desc, fmt, ...) \ + pr_debug("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?",\ + ##__VA_ARGS__) + +/* With chip prefix */ + +#define chip_emerg(chip, fmt, ...) \ + pr_emerg("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__) +#define chip_crit(chip, fmt, ...) \ + pr_crit("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__) +#define chip_err(chip, fmt, ...) \ + pr_err("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__) +#define chip_warn(chip, fmt, ...) \ + pr_warn("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__) +#define chip_info(chip, fmt, ...) \ + pr_info("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__) +#define chip_dbg(chip, fmt, ...) \ + pr_debug("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__) + +#ifdef CONFIG_GPIO_SYSFS + +int gpiochip_export(struct gpio_chip *chip); +void gpiochip_unexport(struct gpio_chip *chip); + +#else + +static inline int gpiochip_export(struct gpio_chip *chip) +{ + return 0; +} + +static inline void gpiochip_unexport(struct gpio_chip *chip) +{ +} + +#endif /* CONFIG_GPIO_SYSFS */ + #endif /* GPIOLIB_H */ diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index 23e364538ab5..c1d4105e1c1d 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -110,9 +110,6 @@ static inline int __gpio_to_irq(unsigned gpio) return gpiod_to_irq(gpio_to_desc(gpio)); } -extern int gpio_lock_as_irq(struct gpio_chip *chip, unsigned int offset); -extern void gpio_unlock_as_irq(struct gpio_chip *chip, unsigned int offset); - extern int gpio_request_one(unsigned gpio, unsigned long flags, const char *label); extern int gpio_request_array(const struct gpio *array, size_t num); extern void gpio_free_array(const struct gpio *array, size_t num); diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h index 05e53ccb708b..b7ce0c64c6f3 100644 --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h @@ -18,30 +18,79 @@ struct gpio_desc; #ifdef CONFIG_GPIOLIB +#define GPIOD_FLAGS_BIT_DIR_SET BIT(0) +#define GPIOD_FLAGS_BIT_DIR_OUT BIT(1) +#define GPIOD_FLAGS_BIT_DIR_VAL BIT(2) + +/** + * Optional flags that can be passed to one of gpiod_* to configure direction + * and output value. These values cannot be OR'd. + */ +enum gpiod_flags { + GPIOD_ASIS = 0, + GPIOD_IN = GPIOD_FLAGS_BIT_DIR_SET, + GPIOD_OUT_LOW = GPIOD_FLAGS_BIT_DIR_SET | GPIOD_FLAGS_BIT_DIR_OUT, + GPIOD_OUT_HIGH = GPIOD_FLAGS_BIT_DIR_SET | GPIOD_FLAGS_BIT_DIR_OUT | + GPIOD_FLAGS_BIT_DIR_VAL, +}; + /* Acquire and dispose GPIOs */ -struct gpio_desc *__must_check gpiod_get(struct device *dev, - const char *con_id); -struct gpio_desc *__must_check gpiod_get_index(struct device *dev, +struct gpio_desc *__must_check __gpiod_get(struct device *dev, + const char *con_id, + enum gpiod_flags flags); +#define __gpiod_get(dev, con_id, flags, ...) __gpiod_get(dev, con_id, flags) +#define gpiod_get(varargs...) __gpiod_get(varargs, 0) +struct gpio_desc *__must_check __gpiod_get_index(struct device *dev, const char *con_id, - unsigned int idx); -struct gpio_desc *__must_check gpiod_get_optional(struct device *dev, - const char *con_id); -struct gpio_desc *__must_check gpiod_get_index_optional(struct device *dev, + unsigned int idx, + enum gpiod_flags flags); +#define __gpiod_get_index(dev, con_id, index, flags, ...) \ + __gpiod_get_index(dev, con_id, index, flags) +#define gpiod_get_index(varargs...) __gpiod_get_index(varargs, 0) +struct gpio_desc *__must_check __gpiod_get_optional(struct device *dev, + const char *con_id, + enum gpiod_flags flags); +#define __gpiod_get_optional(dev, con_id, flags, ...) \ + __gpiod_get_optional(dev, con_id, flags) +#define gpiod_get_optional(varargs...) __gpiod_get_optional(varargs, 0) +struct gpio_desc *__must_check __gpiod_get_index_optional(struct device *dev, const char *con_id, - unsigned int index); + unsigned int index, + enum gpiod_flags flags); +#define __gpiod_get_index_optional(dev, con_id, index, flags, ...) \ + __gpiod_get_index_optional(dev, con_id, index, flags) +#define gpiod_get_index_optional(varargs...) \ + __gpiod_get_index_optional(varargs, 0) void gpiod_put(struct gpio_desc *desc); -struct gpio_desc *__must_check devm_gpiod_get(struct device *dev, - const char *con_id); -struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev, +struct gpio_desc *__must_check __devm_gpiod_get(struct device *dev, + const char *con_id, + enum gpiod_flags flags); +#define __devm_gpiod_get(dev, con_id, flags, ...) \ + __devm_gpiod_get(dev, con_id, flags) +#define devm_gpiod_get(varargs...) __devm_gpiod_get(varargs, 0) +struct gpio_desc *__must_check __devm_gpiod_get_index(struct device *dev, const char *con_id, - unsigned int idx); -struct gpio_desc *__must_check devm_gpiod_get_optional(struct device *dev, - const char *con_id); + unsigned int idx, + enum gpiod_flags flags); +#define __devm_gpiod_get_index(dev, con_id, index, flags, ...) \ + __devm_gpiod_get_index(dev, con_id, index, flags) +#define devm_gpiod_get_index(varargs...) __devm_gpiod_get_index(varargs, 0) +struct gpio_desc *__must_check __devm_gpiod_get_optional(struct device *dev, + const char *con_id, + enum gpiod_flags flags); +#define __devm_gpiod_get_optional(dev, con_id, flags, ...) \ + __devm_gpiod_get_optional(dev, con_id, flags) +#define devm_gpiod_get_optional(varargs...) \ + __devm_gpiod_get_optional(varargs, 0) struct gpio_desc *__must_check -devm_gpiod_get_index_optional(struct device *dev, const char *con_id, - unsigned int index); +__devm_gpiod_get_index_optional(struct device *dev, const char *con_id, + unsigned int index, enum gpiod_flags flags); +#define __devm_gpiod_get_index_optional(dev, con_id, index, flags, ...) \ + __devm_gpiod_get_index_optional(dev, con_id, index, flags) +#define devm_gpiod_get_index_optional(varargs...) \ + __devm_gpiod_get_index_optional(varargs, 0) void devm_gpiod_put(struct device *dev, struct gpio_desc *desc); diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 573e4f3243d0..e78a2373e374 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -141,73 +141,16 @@ extern const char *gpiochip_is_requested(struct gpio_chip *chip, /* add/remove chips */ extern int gpiochip_add(struct gpio_chip *chip); -extern int __must_check gpiochip_remove(struct gpio_chip *chip); +extern int gpiochip_remove(struct gpio_chip *chip); extern struct gpio_chip *gpiochip_find(void *data, int (*match)(struct gpio_chip *chip, void *data)); /* lock/unlock as IRQ */ -int gpiod_lock_as_irq(struct gpio_desc *desc); -void gpiod_unlock_as_irq(struct gpio_desc *desc); +int gpio_lock_as_irq(struct gpio_chip *chip, unsigned int offset); +void gpio_unlock_as_irq(struct gpio_chip *chip, unsigned int offset); struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc); -struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip, - u16 hwnum); - -enum gpio_lookup_flags { - GPIO_ACTIVE_HIGH = (0 << 0), - GPIO_ACTIVE_LOW = (1 << 0), - GPIO_OPEN_DRAIN = (1 << 1), - GPIO_OPEN_SOURCE = (1 << 2), -}; - -/** - * struct gpiod_lookup - lookup table - * @chip_label: name of the chip the GPIO belongs to - * @chip_hwnum: hardware number (i.e. relative to the chip) of the GPIO - * @con_id: name of the GPIO from the device's point of view - * @idx: index of the GPIO in case several GPIOs share the same name - * @flags: mask of GPIO_* values - * - * gpiod_lookup is a lookup table for associating GPIOs to specific devices and - * functions using platform data. - */ -struct gpiod_lookup { - const char *chip_label; - u16 chip_hwnum; - const char *con_id; - unsigned int idx; - enum gpio_lookup_flags flags; -}; - -struct gpiod_lookup_table { - struct list_head list; - const char *dev_id; - struct gpiod_lookup table[]; -}; - -/* - * Simple definition of a single GPIO under a con_id - */ -#define GPIO_LOOKUP(_chip_label, _chip_hwnum, _con_id, _flags) \ - GPIO_LOOKUP_IDX(_chip_label, _chip_hwnum, _con_id, 0, _flags) - -/* - * Use this macro if you need to have several GPIOs under the same con_id. - * Each GPIO needs to use a different index and can be accessed using - * gpiod_get_index() - */ -#define GPIO_LOOKUP_IDX(_chip_label, _chip_hwnum, _con_id, _idx, _flags) \ -{ \ - .chip_label = _chip_label, \ - .chip_hwnum = _chip_hwnum, \ - .con_id = _con_id, \ - .idx = _idx, \ - .flags = _flags, \ -} - -void gpiod_add_lookup_table(struct gpiod_lookup_table *table); - #ifdef CONFIG_GPIOLIB_IRQCHIP void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip, @@ -223,6 +166,9 @@ int gpiochip_irqchip_add(struct gpio_chip *gpiochip, #endif /* CONFIG_GPIO_IRQCHIP */ +int gpiochip_request_own_desc(struct gpio_desc *desc, const char *label); +void gpiochip_free_own_desc(struct gpio_desc *desc); + #else /* CONFIG_GPIOLIB */ static inline struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc) diff --git a/include/linux/gpio/machine.h b/include/linux/gpio/machine.h new file mode 100644 index 000000000000..e2706140eaff --- /dev/null +++ b/include/linux/gpio/machine.h @@ -0,0 +1,61 @@ +#ifndef __LINUX_GPIO_MACHINE_H +#define __LINUX_GPIO_MACHINE_H + +#include <linux/types.h> +#include <linux/list.h> + +enum gpio_lookup_flags { + GPIO_ACTIVE_HIGH = (0 << 0), + GPIO_ACTIVE_LOW = (1 << 0), + GPIO_OPEN_DRAIN = (1 << 1), + GPIO_OPEN_SOURCE = (1 << 2), +}; + +/** + * struct gpiod_lookup - lookup table + * @chip_label: name of the chip the GPIO belongs to + * @chip_hwnum: hardware number (i.e. relative to the chip) of the GPIO + * @con_id: name of the GPIO from the device's point of view + * @idx: index of the GPIO in case several GPIOs share the same name + * @flags: mask of GPIO_* values + * + * gpiod_lookup is a lookup table for associating GPIOs to specific devices and + * functions using platform data. + */ +struct gpiod_lookup { + const char *chip_label; + u16 chip_hwnum; + const char *con_id; + unsigned int idx; + enum gpio_lookup_flags flags; +}; + +struct gpiod_lookup_table { + struct list_head list; + const char *dev_id; + struct gpiod_lookup table[]; +}; + +/* + * Simple definition of a single GPIO under a con_id + */ +#define GPIO_LOOKUP(_chip_label, _chip_hwnum, _con_id, _flags) \ + GPIO_LOOKUP_IDX(_chip_label, _chip_hwnum, _con_id, 0, _flags) + +/* + * Use this macro if you need to have several GPIOs under the same con_id. + * Each GPIO needs to use a different index and can be accessed using + * gpiod_get_index() + */ +#define GPIO_LOOKUP_IDX(_chip_label, _chip_hwnum, _con_id, _idx, _flags) \ +{ \ + .chip_label = _chip_label, \ + .chip_hwnum = _chip_hwnum, \ + .con_id = _con_id, \ + .idx = _idx, \ + .flags = _flags, \ +} + +void gpiod_add_lookup_table(struct gpiod_lookup_table *table); + +#endif /* __LINUX_GPIO_MACHINE_H */ |