diff options
60 files changed, 2743 insertions, 696 deletions
diff --git a/Documentation/devicetree/bindings/gpio/gpio-axp209.txt b/Documentation/devicetree/bindings/gpio/gpio-axp209.txt index a6611304dd3c..fc42b2caa06d 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-axp209.txt +++ b/Documentation/devicetree/bindings/gpio/gpio-axp209.txt @@ -1,10 +1,17 @@ -AXP209 GPIO controller +AXP209 GPIO & pinctrl controller This driver follows the usual GPIO bindings found in Documentation/devicetree/bindings/gpio/gpio.txt +This driver follows the usual pinctrl bindings found in +Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt + +This driver employs the per-pin muxing pattern. + Required properties: -- compatible: Should be "x-powers,axp209-gpio" +- compatible: Should be one of: + - "x-powers,axp209-gpio" + - "x-powers,axp813-gpio" - #gpio-cells: Should be two. The first cell is the pin number and the second is the GPIO flags. - gpio-controller: Marks the device node as a GPIO controller. @@ -28,3 +35,41 @@ axp209: pmic@34 { #gpio-cells = <2>; }; }; + +The GPIOs can be muxed to other functions and therefore, must be a subnode of +axp_gpio. + +Example: + +&axp_gpio { + gpio0_adc: gpio0-adc { + pins = "GPIO0"; + function = "adc"; + }; +}; + +&example_node { + pinctrl-names = "default"; + pinctrl-0 = <&gpio0_adc>; +}; + +GPIOs and their functions +------------------------- + +Each GPIO is independent from the other (i.e. GPIO0 in gpio_in function does +not force GPIO1 and GPIO2 to be in gpio_in function as well). + +axp209 +------ +GPIO | Functions +------------------------ +GPIO0 | gpio_in, gpio_out, ldo, adc +GPIO1 | gpio_in, gpio_out, ldo, adc +GPIO2 | gpio_in, gpio_out + +axp813 +------ +GPIO | Functions +------------------------ +GPIO0 | gpio_in, gpio_out, ldo, adc +GPIO1 | gpio_in, gpio_out, ldo diff --git a/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt b/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt index a7ac460ad657..9474138d776e 100644 --- a/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt +++ b/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt @@ -5,7 +5,7 @@ Required Properties: - compatible: should contain one or more of the following: - "renesas,gpio-r8a7743": for R8A7743 (RZ/G1M) compatible GPIO controller. - "renesas,gpio-r8a7745": for R8A7745 (RZ/G1E) compatible GPIO controller. - - "renesas,gpio-r8a7778": for R8A7778 (R-Mobile M1) compatible GPIO controller. + - "renesas,gpio-r8a7778": for R8A7778 (R-Car M1) compatible GPIO controller. - "renesas,gpio-r8a7779": for R8A7779 (R-Car H1) compatible GPIO controller. - "renesas,gpio-r8a7790": for R8A7790 (R-Car H2) compatible GPIO controller. - "renesas,gpio-r8a7791": for R8A7791 (R-Car M2-W) compatible GPIO controller. diff --git a/Documentation/gpio/board.txt b/Documentation/gpio/board.txt index a0f61898d493..659bb19f5b3c 100644 --- a/Documentation/gpio/board.txt +++ b/Documentation/gpio/board.txt @@ -2,6 +2,7 @@ GPIO Mappings ============= This document explains how GPIOs can be assigned to given devices and functions. + Note that it only applies to the new descriptor-based interface. For a description of the deprecated integer-based GPIO interface please refer to gpio-legacy.txt (actually, there is no real mapping possible with the old @@ -49,7 +50,7 @@ This property will make GPIOs 15, 16 and 17 available to the driver under the power = gpiod_get(dev, "power", GPIOD_OUT_HIGH); -The led GPIOs will be active-high, while the power GPIO will be active-low (i.e. +The led GPIOs will be active high, while the power GPIO will be active low (i.e. gpiod_is_active_low(power) will be true). The second parameter of the gpiod_get() functions, the con_id string, has to be @@ -122,9 +123,14 @@ where can be NULL, in which case it will match any function. - idx is the index of the GPIO within the function. - flags is defined to specify the following properties: - * GPIOF_ACTIVE_LOW - to configure the GPIO as active-low - * GPIOF_OPEN_DRAIN - GPIO pin is open drain type. - * GPIOF_OPEN_SOURCE - GPIO pin is open source type. + * GPIO_ACTIVE_HIGH - GPIO line is active high + * GPIO_ACTIVE_LOW - GPIO line is active low + * GPIO_OPEN_DRAIN - GPIO line is set up as open drain + * GPIO_OPEN_SOURCE - GPIO line is set up as open source + * GPIO_PERSISTENT - GPIO line is persistent during + suspend/resume and maintains its value + * GPIO_TRANSITORY - GPIO line is transitory and may loose its + electrical state during suspend/resume In the future, these flags might be extended to support more properties. diff --git a/Documentation/gpio/consumer.txt b/Documentation/gpio/consumer.txt index 63e1bd1d88e3..d53e5b5cfc9c 100644 --- a/Documentation/gpio/consumer.txt +++ b/Documentation/gpio/consumer.txt @@ -66,6 +66,15 @@ for the GPIO. Values can be: * 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. +* GPIOD_OUT_LOW_OPEN_DRAIN same as GPIOD_OUT_LOW but also enforce the line + to be electrically used with open drain. +* GPIOD_OUT_HIGH_OPEN_DRAIN same as GPIOD_OUT_HIGH but also enforce the line + to be electrically used with open drain. + +The two last flags are used for use cases where open drain is mandatory, such +as I2C: if the line is not already configured as open drain in the mappings +(see board.txt), then open drain will be enforced anyway and a warning will be +printed that the board configuration needs to be updated to match the use case. 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 @@ -184,7 +193,7 @@ A driver can also query the current direction of a GPIO: int gpiod_get_direction(const struct gpio_desc *desc) -This function will return either GPIOF_DIR_IN or GPIOF_DIR_OUT. +This function returns 0 for output, 1 for input, or an error code in case of error. Be aware that there is no default direction for GPIOs. Therefore, **using a GPIO without setting its direction first is illegal and will result in undefined @@ -240,59 +249,71 @@ that can't be accessed from hardIRQ handlers, these calls act the same as the spinlock-safe calls. -Active-low State and Raw GPIO Values ------------------------------------- -Device drivers like to manage the logical state of a GPIO, i.e. the value their -device will actually receive, no matter what lies between it and the GPIO line. -In some cases, it might make sense to control the actual GPIO line value. The -following set of calls ignore the active-low property of a GPIO and work on the -raw line value: - - int gpiod_get_raw_value(const struct gpio_desc *desc) - void gpiod_set_raw_value(struct gpio_desc *desc, int value) - int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc) - void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value) - int gpiod_direction_output_raw(struct gpio_desc *desc, int value) - -The active-low state of a GPIO can also be queried using the following call: - - int gpiod_is_active_low(const struct gpio_desc *desc) - -Note that these functions should only be used with great moderation ; a driver -should not have to care about the physical line level. - - -The active-low property ------------------------ - -As a driver should not have to care about the physical line level, all of the +The active low and open drain semantics +--------------------------------------- +As a consumer should not have to care about the physical line level, all of the gpiod_set_value_xxx() or gpiod_set_array_value_xxx() functions operate with -the *logical* value. With this they take the active-low property into account. -This means that they check whether the GPIO is configured to be active-low, +the *logical* value. With this they take the active low property into account. +This means that they check whether the GPIO is configured to be active low, and if so, they manipulate the passed value before the physical line level is driven. +The same is applicable for open drain or open source output lines: those do not +actively drive their output high (open drain) or low (open source), they just +switch their output to a high impedance value. The consumer should not need to +care. (For details read about open drain in driver.txt.) + With this, all the gpiod_set_(array)_value_xxx() functions interpret the -parameter "value" as "active" ("1") or "inactive" ("0"). The physical line +parameter "value" as "asserted" ("1") or "de-asserted" ("0"). The physical line level will be driven accordingly. -As an example, if the active-low property for a dedicated GPIO is set, and the -gpiod_set_(array)_value_xxx() passes "active" ("1"), the physical line level +As an example, if the active low property for a dedicated GPIO is set, and the +gpiod_set_(array)_value_xxx() passes "asserted" ("1"), the physical line level will be driven low. To summarize: -Function (example) active-low property physical line -gpiod_set_raw_value(desc, 0); don't care low -gpiod_set_raw_value(desc, 1); don't care high -gpiod_set_value(desc, 0); default (active-high) low -gpiod_set_value(desc, 1); default (active-high) high -gpiod_set_value(desc, 0); active-low high -gpiod_set_value(desc, 1); active-low low - -Please note again that the set_raw/get_raw functions should be avoided as much -as possible, especially by drivers which should not care about the actual -physical line level and worry about the logical value instead. +Function (example) line property physical line +gpiod_set_raw_value(desc, 0); don't care low +gpiod_set_raw_value(desc, 1); don't care high +gpiod_set_value(desc, 0); default (active high) low +gpiod_set_value(desc, 1); default (active high) high +gpiod_set_value(desc, 0); active low high +gpiod_set_value(desc, 1); active low low +gpiod_set_value(desc, 0); default (active high) low +gpiod_set_value(desc, 1); default (active high) high +gpiod_set_value(desc, 0); open drain low +gpiod_set_value(desc, 1); open drain high impedance +gpiod_set_value(desc, 0); open source high impedance +gpiod_set_value(desc, 1); open source high + +It is possible to override these semantics using the *set_raw/'get_raw functions +but it should be avoided as much as possible, especially by system-agnostic drivers +which should not need to care about the actual physical line level and worry about +the logical value instead. + + +Accessing raw GPIO values +------------------------- +Consumers exist that need to manage the logical state of a GPIO line, i.e. the value +their device will actually receive, no matter what lies between it and the GPIO +line. + +The following set of calls ignore the active-low or open drain property of a GPIO and +work on the raw line value: + + int gpiod_get_raw_value(const struct gpio_desc *desc) + void gpiod_set_raw_value(struct gpio_desc *desc, int value) + int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc) + void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value) + int gpiod_direction_output_raw(struct gpio_desc *desc, int value) + +The active low state of a GPIO can also be queried using the following call: + + int gpiod_is_active_low(const struct gpio_desc *desc) + +Note that these functions should only be used with great moderation; a driver +should not have to care about the physical line level or open drain semantics. Access multiple GPIOs with a single function call diff --git a/Documentation/gpio/driver.txt b/Documentation/gpio/driver.txt index d8de1c7de85a..3392a0fd4c23 100644 --- a/Documentation/gpio/driver.txt +++ b/Documentation/gpio/driver.txt @@ -88,6 +88,10 @@ ending up in the pin control back-end "behind" the GPIO controller, usually closer to the actual pins. This way the pin controller can manage the below listed GPIO configurations. +If a pin controller back-end is used, the GPIO controller or hardware +description needs to provide "GPIO ranges" mapping the GPIO line offsets to pin +numbers on the pin controller so they can properly cross-reference each other. + GPIOs with debounce support --------------------------- diff --git a/Documentation/gpio/sysfs.txt b/Documentation/gpio/sysfs.txt index aeab01aa4d00..6cdeab8650cd 100644 --- a/Documentation/gpio/sysfs.txt +++ b/Documentation/gpio/sysfs.txt @@ -1,6 +1,17 @@ GPIO Sysfs Interface for Userspace ================================== +THIS ABI IS DEPRECATED, THE ABI DOCUMENTATION HAS BEEN MOVED TO +Documentation/ABI/obsolete/sysfs-gpio AND NEW USERSPACE CONSUMERS +ARE SUPPOSED TO USE THE CHARACTER DEVICE ABI. THIS OLD SYSFS ABI WILL +NOT BE DEVELOPED (NO NEW FEATURES), IT WILL JUST BE MAINTAINED. + +Refer to the examples in tools/gpio/* for an introduction to the new +character device ABI. Also see the userspace header in +include/uapi/linux/gpio.h + +The deprecated sysfs ABI +------------------------ Platforms which use the "gpiolib" implementors framework may choose to configure a sysfs user interface to GPIOs. This is different from the debugfs interface, since it provides control over GPIO direction and diff --git a/Documentation/w1/masters/w1-gpio b/Documentation/w1/masters/w1-gpio index af5d3b4aa851..623961d9e83f 100644 --- a/Documentation/w1/masters/w1-gpio +++ b/Documentation/w1/masters/w1-gpio @@ -8,17 +8,27 @@ Description ----------- GPIO 1-wire bus master driver. The driver uses the GPIO API to control the -wire and the GPIO pin can be specified using platform data. +wire and the GPIO pin can be specified using GPIO machine descriptor tables. +It is also possible to define the master using device tree, see +Documentation/devicetree/bindings/w1/w1-gpio.txt Example (mach-at91) ------------------- +#include <linux/gpio/machine.h> #include <linux/w1-gpio.h> +static struct gpiod_lookup_table foo_w1_gpiod_table = { + .dev_id = "w1-gpio", + .table = { + GPIO_LOOKUP_IDX("at91-gpio", AT91_PIN_PB20, NULL, 0, + GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN), + }, +}; + static struct w1_gpio_platform_data foo_w1_gpio_pdata = { - .pin = AT91_PIN_PB20, - .is_open_drain = 1, + .ext_pullup_enable_pin = -EINVAL, }; static struct platform_device foo_w1_device = { @@ -30,4 +40,5 @@ static struct platform_device foo_w1_device = { ... at91_set_GPIO_periph(foo_w1_gpio_pdata.pin, 1); at91_set_multi_drive(foo_w1_gpio_pdata.pin, 1); + gpiod_add_lookup_table(&foo_w1_gpiod_table); platform_device_register(&foo_w1_device); diff --git a/MAINTAINERS b/MAINTAINERS index 88cdd2925cef..e26e4c7a5454 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -278,6 +278,12 @@ L: linux-gpio@vger.kernel.org S: Maintained F: drivers/gpio/gpio-pci-idio-16.c +ACCES PCIe-IDIO-24 GPIO DRIVER +M: William Breathitt Gray <vilhelm.gray@gmail.com> +L: linux-gpio@vger.kernel.org +S: Maintained +F: drivers/gpio/gpio-pcie-idio-24.c + ACENIC DRIVER M: Jes Sorensen <jes@trained-monkey.org> L: linux-acenic@sunsite.dk @@ -5979,6 +5985,7 @@ F: drivers/media/rc/gpio-ir-tx.c GPIO MOCKUP DRIVER M: Bamvor Jian Zhang <bamvor.zhangjian@linaro.org> +R: Bartosz Golaszewski <brgl@bgdev.pl> L: linux-gpio@vger.kernel.org S: Maintained F: drivers/gpio/gpio-mockup.c diff --git a/arch/arm/mach-ixp4xx/vulcan-setup.c b/arch/arm/mach-ixp4xx/vulcan-setup.c index 731fb2019ecb..2c03d2f6b647 100644 --- a/arch/arm/mach-ixp4xx/vulcan-setup.c +++ b/arch/arm/mach-ixp4xx/vulcan-setup.c @@ -16,6 +16,7 @@ #include <linux/serial_8250.h> #include <linux/io.h> #include <linux/w1-gpio.h> +#include <linux/gpio/machine.h> #include <linux/mtd/plat-ram.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> @@ -162,9 +163,16 @@ static struct platform_device vulcan_max6369 = { .num_resources = 1, }; +static struct gpiod_lookup_table vulcan_w1_gpiod_table = { + .dev_id = "w1-gpio", + .table = { + GPIO_LOOKUP_IDX("IXP4XX_GPIO_CHIP", 14, NULL, 0, + GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + }, +}; + static struct w1_gpio_platform_data vulcan_w1_gpio_pdata = { - .pin = 14, - .ext_pullup_enable_pin = -EINVAL, + /* Intentionally left blank */ }; static struct platform_device vulcan_w1_gpio = { @@ -233,6 +241,7 @@ static void __init vulcan_init(void) IXP4XX_EXP_BUS_WR_EN | IXP4XX_EXP_BUS_BYTE_EN; + gpiod_add_lookup_table(&vulcan_w1_gpiod_table); platform_add_devices(vulcan_devices, ARRAY_SIZE(vulcan_devices)); } diff --git a/arch/arm/mach-pxa/raumfeld.c b/arch/arm/mach-pxa/raumfeld.c index 9d662fed03ec..feddca7f3540 100644 --- a/arch/arm/mach-pxa/raumfeld.c +++ b/arch/arm/mach-pxa/raumfeld.c @@ -506,11 +506,16 @@ static void w1_enable_external_pullup(int enable) msleep(100); } +static struct gpiod_lookup_table raumfeld_w1_gpiod_table = { + .dev_id = "w1-gpio", + .table = { + GPIO_LOOKUP_IDX("gpio-pxa", GPIO_ONE_WIRE, NULL, 0, + GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + }, +}; + static struct w1_gpio_platform_data w1_gpio_platform_data = { - .pin = GPIO_ONE_WIRE, - .is_open_drain = 0, - .enable_external_pullup = w1_enable_external_pullup, - .ext_pullup_enable_pin = -EINVAL, + .enable_external_pullup = w1_enable_external_pullup, }; static struct platform_device raumfeld_w1_gpio_device = { @@ -523,13 +528,14 @@ static struct platform_device raumfeld_w1_gpio_device = { static void __init raumfeld_w1_init(void) { int ret = gpio_request(GPIO_W1_PULLUP_ENABLE, - "W1 external pullup enable"); + "W1 external pullup enable"); if (ret < 0) pr_warn("Unable to request GPIO_W1_PULLUP_ENABLE\n"); else gpio_direction_output(GPIO_W1_PULLUP_ENABLE, 0); + gpiod_add_lookup_table(&raumfeld_w1_gpiod_table); platform_device_register(&raumfeld_w1_gpio_device); } diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d6a8e851ad13..8dbb2280538d 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -122,12 +122,6 @@ config GPIO_ATH79 Select this option to enable GPIO driver for Atheros AR71XX/AR724X/AR913X SoC devices. -config GPIO_AXP209 - tristate "X-Powers AXP209 PMIC GPIO Support" - depends on MFD_AXP20X - help - Say yes to enable GPIO support for the AXP209 PMIC - config GPIO_BCM_KONA bool "Broadcom Kona GPIO" depends on OF_GPIO && (ARCH_BCM_MOBILE || COMPILE_TEST) @@ -704,6 +698,22 @@ config GPIO_TS5500 blocks of the TS-5500: DIO1, DIO2 and the LCD port, and the TS-5600 LCD port. +config GPIO_WINBOND + tristate "Winbond Super I/O GPIO support" + depends on ISA_BUS_API + help + This option enables support for GPIOs found on Winbond Super I/O + chips. + Currently, only W83627UHG (also known as Nuvoton NCT6627UD) is + supported. + + You will need to provide a module parameter "gpios", or a + boot-time parameter "gpio_winbond.gpios" with a bitmask of GPIO + ports to enable (bit 0 is GPIO1, bit 1 is GPIO2, etc.). + + To compile this driver as a module, choose M here: the module will + be called gpio-winbond. + config GPIO_WS16C48 tristate "WinSystems WS16C48 GPIO support" depends on ISA_BUS_API @@ -1234,6 +1244,16 @@ config GPIO_PCI_IDIO_16 low). Input filter control is not supported by this driver, and the input filters are deactivated by this driver. +config GPIO_PCIE_IDIO_24 + tristate "ACCES PCIe-IDIO-24 GPIO support" + select GPIOLIB_IRQCHIP + help + Enables GPIO support for the ACCES PCIe-IDIO-24 family (PCIe-IDIO-24, + PCIe-IDI-24, PCIe-IDO-24, PCIe-IDIO-12). An interrupt is generated + when any of the inputs change state (low to high or high to low). + Input filter control is not supported by this driver, and the input + filters are deactivated by this driver. + config GPIO_RDC321X tristate "RDC R-321x GPIO support" select MFD_CORE diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 4bc24febb889..cccb0d40846c 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -32,7 +32,6 @@ obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.o obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o obj-$(CONFIG_GPIO_ASPEED) += gpio-aspeed.o -obj-$(CONFIG_GPIO_AXP209) += gpio-axp209.o obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o @@ -96,6 +95,7 @@ obj-$(CONFIG_GPIO_PCA953X) += gpio-pca953x.o obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.o obj-$(CONFIG_GPIO_PCH) += gpio-pch.o obj-$(CONFIG_GPIO_PCI_IDIO_16) += gpio-pci-idio-16.o +obj-$(CONFIG_GPIO_PCIE_IDIO_24) += gpio-pcie-idio-24.o obj-$(CONFIG_GPIO_PISOSR) += gpio-pisosr.o obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o @@ -140,6 +140,7 @@ obj-$(CONFIG_GPIO_VIPERBOARD) += gpio-viperboard.o obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o obj-$(CONFIG_GPIO_WHISKEY_COVE) += gpio-wcove.o +obj-$(CONFIG_GPIO_WINBOND) += gpio-winbond.o obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c index afbff155a0ba..e82cc763633c 100644 --- a/drivers/gpio/devres.c +++ b/drivers/gpio/devres.c @@ -125,6 +125,48 @@ struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev, EXPORT_SYMBOL(devm_gpiod_get_index); /** + * devm_gpiod_get_from_of_node() - obtain a GPIO from an OF node + * @dev: device for lifecycle management + * @node: handle of the OF node + * @propname: name of the DT property representing the GPIO + * @index: index of the GPIO to obtain for the consumer + * @dflags: GPIO initialization flags + * @label: label to attach to the requested GPIO + * + * Returns: + * On successful request the GPIO pin is configured in accordance with + * provided @dflags. + * + * In case of error an ERR_PTR() is returned. + */ +struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev, + struct device_node *node, + const char *propname, int index, + enum gpiod_flags dflags, + const char *label) +{ + struct gpio_desc **dr; + struct gpio_desc *desc; + + dr = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc *), + GFP_KERNEL); + if (!dr) + return ERR_PTR(-ENOMEM); + + desc = gpiod_get_from_of_node(node, propname, index, dflags, label); + if (IS_ERR(desc)) { + devres_free(dr); + return desc; + } + + *dr = desc; + devres_add(dev, dr); + + return desc; +} +EXPORT_SYMBOL(devm_gpiod_get_from_of_node); + +/** * devm_fwnode_get_index_gpiod_from_child - get a GPIO descriptor from a * device's child node * @dev: GPIO consumer diff --git a/drivers/gpio/gpio-74x164.c b/drivers/gpio/gpio-74x164.c index 15a1f4b348c4..fb7b620763a2 100644 --- a/drivers/gpio/gpio-74x164.c +++ b/drivers/gpio/gpio-74x164.c @@ -9,12 +9,11 @@ * published by the Free Software Foundation. */ -#include <linux/gpio/consumer.h> #include <linux/init.h> #include <linux/mutex.h> #include <linux/spi/spi.h> -#include <linux/gpio.h> -#include <linux/of_gpio.h> +#include <linux/gpio/driver.h> +#include <linux/gpio/consumer.h> #include <linux/slab.h> #include <linux/module.h> diff --git a/drivers/gpio/gpio-adp5520.c b/drivers/gpio/gpio-adp5520.c index abf199609546..21452622d954 100644 --- a/drivers/gpio/gpio-adp5520.c +++ b/drivers/gpio/gpio-adp5520.c @@ -12,8 +12,7 @@ #include <linux/init.h> #include <linux/platform_device.h> #include <linux/mfd/adp5520.h> - -#include <linux/gpio.h> +#include <linux/gpio/driver.h> struct adp5520_gpio { struct device *master; diff --git a/drivers/gpio/gpio-adp5588.c b/drivers/gpio/gpio-adp5588.c index e717f8dc3966..3530ccd17e04 100644 --- a/drivers/gpio/gpio-adp5588.c +++ b/drivers/gpio/gpio-adp5588.c @@ -12,7 +12,7 @@ #include <linux/slab.h> #include <linux/init.h> #include <linux/i2c.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/interrupt.h> #include <linux/irq.h> diff --git a/drivers/gpio/gpio-altera.c b/drivers/gpio/gpio-altera.c index 8e76d390e653..8c3ff6e2366f 100644 --- a/drivers/gpio/gpio-altera.c +++ b/drivers/gpio/gpio-altera.c @@ -18,7 +18,8 @@ #include <linux/io.h> #include <linux/module.h> -#include <linux/of_gpio.h> +#include <linux/gpio/driver.h> +#include <linux/of_gpio.h> /* For of_mm_gpio_chip */ #include <linux/platform_device.h> #define ALTERA_GPIO_MAX_NGPIO 32 diff --git a/drivers/gpio/gpio-amd8111.c b/drivers/gpio/gpio-amd8111.c index 30ad7d7c1678..fdcebe59510d 100644 --- a/drivers/gpio/gpio-amd8111.c +++ b/drivers/gpio/gpio-amd8111.c @@ -28,7 +28,7 @@ #include <linux/ioport.h> #include <linux/module.h> #include <linux/kernel.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/pci.h> #include <linux/spinlock.h> diff --git a/drivers/gpio/gpio-arizona.c b/drivers/gpio/gpio-arizona.c index d4e6ba0301bc..ba51ea15f379 100644 --- a/drivers/gpio/gpio-arizona.c +++ b/drivers/gpio/gpio-arizona.c @@ -15,7 +15,7 @@ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/module.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/seq_file.h> diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c index 6b3ca6601af2..77e485557498 100644 --- a/drivers/gpio/gpio-aspeed.c +++ b/drivers/gpio/gpio-aspeed.c @@ -60,6 +60,7 @@ struct aspeed_gpio_bank { uint16_t val_regs; uint16_t irq_regs; uint16_t debounce_regs; + uint16_t tolerance_regs; const char names[4][3]; }; @@ -70,48 +71,56 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { .val_regs = 0x0000, .irq_regs = 0x0008, .debounce_regs = 0x0040, + .tolerance_regs = 0x001c, .names = { "A", "B", "C", "D" }, }, { .val_regs = 0x0020, .irq_regs = 0x0028, .debounce_regs = 0x0048, + .tolerance_regs = 0x003c, .names = { "E", "F", "G", "H" }, }, { .val_regs = 0x0070, .irq_regs = 0x0098, .debounce_regs = 0x00b0, + .tolerance_regs = 0x00ac, .names = { "I", "J", "K", "L" }, }, { .val_regs = 0x0078, .irq_regs = 0x00e8, .debounce_regs = 0x0100, + .tolerance_regs = 0x00fc, .names = { "M", "N", "O", "P" }, }, { .val_regs = 0x0080, .irq_regs = 0x0118, .debounce_regs = 0x0130, + .tolerance_regs = 0x012c, .names = { "Q", "R", "S", "T" }, }, { .val_regs = 0x0088, .irq_regs = 0x0148, .debounce_regs = 0x0160, + .tolerance_regs = 0x015c, .names = { "U", "V", "W", "X" }, }, { .val_regs = 0x01E0, .irq_regs = 0x0178, .debounce_regs = 0x0190, + .tolerance_regs = 0x018c, .names = { "Y", "Z", "AA", "AB" }, }, { - .val_regs = 0x01E8, - .irq_regs = 0x01A8, + .val_regs = 0x01e8, + .irq_regs = 0x01a8, .debounce_regs = 0x01c0, + .tolerance_regs = 0x01bc, .names = { "AC", "", "", "" }, }, }; @@ -140,7 +149,7 @@ static const struct aspeed_gpio_bank *to_bank(unsigned int offset) { unsigned int bank = GPIO_BANK(offset); - WARN_ON(bank > ARRAY_SIZE(aspeed_gpio_banks)); + WARN_ON(bank >= ARRAY_SIZE(aspeed_gpio_banks)); return &aspeed_gpio_banks[bank]; } @@ -534,6 +543,30 @@ static int aspeed_gpio_setup_irqs(struct aspeed_gpio *gpio, return 0; } +static int aspeed_gpio_reset_tolerance(struct gpio_chip *chip, + unsigned int offset, bool enable) +{ + struct aspeed_gpio *gpio = gpiochip_get_data(chip); + const struct aspeed_gpio_bank *bank; + unsigned long flags; + u32 val; + + bank = to_bank(offset); + + spin_lock_irqsave(&gpio->lock, flags); + val = readl(gpio->base + bank->tolerance_regs); + + if (enable) + val |= GPIO_BIT(offset); + else + val &= ~GPIO_BIT(offset); + + writel(val, gpio->base + bank->tolerance_regs); + spin_unlock_irqrestore(&gpio->lock, flags); + + return 0; +} + static int aspeed_gpio_request(struct gpio_chip *chip, unsigned int offset) { if (!have_gpio(gpiochip_get_data(chip), offset)) @@ -771,6 +804,8 @@ static int aspeed_gpio_set_config(struct gpio_chip *chip, unsigned int offset, param == PIN_CONFIG_DRIVE_OPEN_SOURCE) /* Return -ENOTSUPP to trigger emulation, as per datasheet */ return -ENOTSUPP; + else if (param == PIN_CONFIG_PERSIST_STATE) + return aspeed_gpio_reset_tolerance(chip, offset, arg); return -ENOTSUPP; } diff --git a/drivers/gpio/gpio-ath79.c b/drivers/gpio/gpio-ath79.c index 5fad89dfab7e..3ae7c1876bf4 100644 --- a/drivers/gpio/gpio-ath79.c +++ b/drivers/gpio/gpio-ath79.c @@ -324,3 +324,6 @@ static struct platform_driver ath79_gpio_driver = { }; module_platform_driver(ath79_gpio_driver); + +MODULE_DESCRIPTION("Atheros AR71XX/AR724X/AR913X GPIO API support"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/gpio-axp209.c b/drivers/gpio/gpio-axp209.c deleted file mode 100644 index 4a346b7b4172..000000000000 --- a/drivers/gpio/gpio-axp209.c +++ /dev/null @@ -1,188 +0,0 @@ -/* - * AXP20x GPIO driver - * - * Copyright (C) 2016 Maxime Ripard <maxime.ripard@free-electrons.com> - * - * 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/device.h> -#include <linux/gpio/driver.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/kernel.h> -#include <linux/mfd/axp20x.h> -#include <linux/module.h> -#include <linux/of.h> -#include <linux/platform_device.h> -#include <linux/regmap.h> -#include <linux/slab.h> - -#define AXP20X_GPIO_FUNCTIONS 0x7 -#define AXP20X_GPIO_FUNCTION_OUT_LOW 0 -#define AXP20X_GPIO_FUNCTION_OUT_HIGH 1 -#define AXP20X_GPIO_FUNCTION_INPUT 2 - -struct axp20x_gpio { - struct gpio_chip chip; - struct regmap *regmap; -}; - -static int axp20x_gpio_get_reg(unsigned offset) -{ - switch (offset) { - case 0: - return AXP20X_GPIO0_CTRL; - case 1: - return AXP20X_GPIO1_CTRL; - case 2: - return AXP20X_GPIO2_CTRL; - } - - return -EINVAL; -} - -static int axp20x_gpio_input(struct gpio_chip *chip, unsigned offset) -{ - struct axp20x_gpio *gpio = gpiochip_get_data(chip); - int reg; - - reg = axp20x_gpio_get_reg(offset); - if (reg < 0) - return reg; - - return regmap_update_bits(gpio->regmap, reg, - AXP20X_GPIO_FUNCTIONS, - AXP20X_GPIO_FUNCTION_INPUT); -} - -static int axp20x_gpio_get(struct gpio_chip *chip, unsigned offset) -{ - struct axp20x_gpio *gpio = gpiochip_get_data(chip); - unsigned int val; - int ret; - - ret = regmap_read(gpio->regmap, AXP20X_GPIO20_SS, &val); - if (ret) - return ret; - - return !!(val & BIT(offset + 4)); -} - -static int axp20x_gpio_get_direction(struct gpio_chip *chip, unsigned offset) -{ - struct axp20x_gpio *gpio = gpiochip_get_data(chip); - unsigned int val; - int reg, ret; - - reg = axp20x_gpio_get_reg(offset); - if (reg < 0) - return reg; - - ret = regmap_read(gpio->regmap, reg, &val); - if (ret) - return ret; - - /* - * This shouldn't really happen if the pin is in use already, - * or if it's not in use yet, it doesn't matter since we're - * going to change the value soon anyway. Default to output. - */ - if ((val & AXP20X_GPIO_FUNCTIONS) > 2) - return 0; - - /* - * The GPIO directions are the three lowest values. - * 2 is input, 0 and 1 are output - */ - return val & 2; -} - -static int axp20x_gpio_output(struct gpio_chip *chip, unsigned offset, - int value) -{ - struct axp20x_gpio *gpio = gpiochip_get_data(chip); - int reg; - - reg = axp20x_gpio_get_reg(offset); - if (reg < 0) - return reg; - - return regmap_update_bits(gpio->regmap, reg, - AXP20X_GPIO_FUNCTIONS, - value ? AXP20X_GPIO_FUNCTION_OUT_HIGH - : AXP20X_GPIO_FUNCTION_OUT_LOW); -} - -static void axp20x_gpio_set(struct gpio_chip *chip, unsigned offset, - int value) -{ - axp20x_gpio_output(chip, offset, value); -} - -static int axp20x_gpio_probe(struct platform_device *pdev) -{ - struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); - struct axp20x_gpio *gpio; - int ret; - - if (!of_device_is_available(pdev->dev.of_node)) - return -ENODEV; - - if (!axp20x) { - dev_err(&pdev->dev, "Parent drvdata not set\n"); - return -EINVAL; - } - - gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); - if (!gpio) - return -ENOMEM; - - gpio->chip.base = -1; - gpio->chip.can_sleep = true; - gpio->chip.parent = &pdev->dev; - gpio->chip.label = dev_name(&pdev->dev); - gpio->chip.owner = THIS_MODULE; - gpio->chip.get = axp20x_gpio_get; - gpio->chip.get_direction = axp20x_gpio_get_direction; - gpio->chip.set = axp20x_gpio_set; - gpio->chip.direction_input = axp20x_gpio_input; - gpio->chip.direction_output = axp20x_gpio_output; - gpio->chip.ngpio = 3; - - gpio->regmap = axp20x->regmap; - - ret = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio); - if (ret) { - dev_err(&pdev->dev, "Failed to register GPIO chip\n"); - return ret; - } - - dev_info(&pdev->dev, "AXP209 GPIO driver loaded\n"); - - return 0; -} - -static const struct of_device_id axp20x_gpio_match[] = { - { .compatible = "x-powers,axp209-gpio" }, - { } -}; -MODULE_DEVICE_TABLE(of, axp20x_gpio_match); - -static struct platform_driver axp20x_gpio_driver = { - .probe = axp20x_gpio_probe, - .driver = { - .name = "axp20x-gpio", - .of_match_table = axp20x_gpio_match, - }, -}; - -module_platform_driver(axp20x_gpio_driver); - -MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>"); -MODULE_DESCRIPTION("AXP20x PMIC GPIO driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c index 76861a00bb92..eb8369b21e90 100644 --- a/drivers/gpio/gpio-bcm-kona.c +++ b/drivers/gpio/gpio-bcm-kona.c @@ -17,7 +17,7 @@ #include <linux/bitops.h> #include <linux/err.h> #include <linux/io.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/of_device.h> #include <linux/of_irq.h> #include <linux/init.h> @@ -127,7 +127,7 @@ static int bcm_kona_gpio_get_dir(struct gpio_chip *chip, unsigned gpio) u32 val; val = readl(reg_base + GPIO_CONTROL(gpio)) & GPIO_GPCTR0_IOTR_MASK; - return val ? GPIOF_DIR_IN : GPIOF_DIR_OUT; + return !!val; } static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value) @@ -144,7 +144,7 @@ static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value) raw_spin_lock_irqsave(&kona_gpio->lock, flags); /* this function only applies to output pin */ - if (bcm_kona_gpio_get_dir(chip, gpio) == GPIOF_DIR_IN) + if (bcm_kona_gpio_get_dir(chip, gpio) == 1) goto out; reg_offset = value ? GPIO_OUT_SET(bank_id) : GPIO_OUT_CLEAR(bank_id); @@ -170,7 +170,7 @@ static int bcm_kona_gpio_get(struct gpio_chip *chip, unsigned gpio) reg_base = kona_gpio->reg_base; raw_spin_lock_irqsave(&kona_gpio->lock, flags); - if (bcm_kona_gpio_get_dir(chip, gpio) == GPIOF_DIR_IN) + if (bcm_kona_gpio_get_dir(chip, gpio) == 1) reg_offset = GPIO_IN_STATUS(bank_id); else reg_offset = GPIO_OUT_STATUS(bank_id); diff --git a/drivers/gpio/gpio-brcmstb.c b/drivers/gpio/gpio-brcmstb.c index bb4f8cf18bd9..16c7f9f49416 100644 --- a/drivers/gpio/gpio-brcmstb.c +++ b/drivers/gpio/gpio-brcmstb.c @@ -19,7 +19,6 @@ #include <linux/irqdomain.h> #include <linux/irqchip/chained_irq.h> #include <linux/interrupt.h> -#include <linux/bitops.h> enum gio_reg_index { GIO_REG_ODEN = 0, diff --git a/drivers/gpio/gpio-bt8xx.c b/drivers/gpio/gpio-bt8xx.c index acefb25e8eca..b8ec75cbd4b5 100644 --- a/drivers/gpio/gpio-bt8xx.c +++ b/drivers/gpio/gpio-bt8xx.c @@ -46,7 +46,7 @@ #include <linux/module.h> #include <linux/pci.h> #include <linux/spinlock.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/slab.h> /* Steal the hardware definitions from the bttv driver. */ diff --git a/drivers/gpio/gpio-crystalcove.c b/drivers/gpio/gpio-crystalcove.c index b6f0f729656c..58531d8b8c6e 100644 --- a/drivers/gpio/gpio-crystalcove.c +++ b/drivers/gpio/gpio-crystalcove.c @@ -18,7 +18,7 @@ #include <linux/interrupt.h> #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/seq_file.h> #include <linux/bitops.h> #include <linux/regmap.h> diff --git a/drivers/gpio/gpio-cs5535.c b/drivers/gpio/gpio-cs5535.c index 90278b19aa0e..8814c8f47e57 100644 --- a/drivers/gpio/gpio-cs5535.c +++ b/drivers/gpio/gpio-cs5535.c @@ -12,7 +12,7 @@ #include <linux/spinlock.h> #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/io.h> #include <linux/cs5535.h> #include <asm/msr.h> diff --git a/drivers/gpio/gpio-da9052.c b/drivers/gpio/gpio-da9052.c index dd8977cf3e85..b6d3e997eb26 100644 --- a/drivers/gpio/gpio-da9052.c +++ b/drivers/gpio/gpio-da9052.c @@ -15,7 +15,7 @@ #include <linux/fs.h> #include <linux/uaccess.h> #include <linux/platform_device.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/syscalls.h> #include <linux/seq_file.h> diff --git a/drivers/gpio/gpio-da9055.c b/drivers/gpio/gpio-da9055.c index 82053b52cba0..2f1b5d23b10c 100644 --- a/drivers/gpio/gpio-da9055.c +++ b/drivers/gpio/gpio-da9055.c @@ -13,7 +13,7 @@ */ #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/mfd/da9055/core.h> #include <linux/mfd/da9055/reg.h> diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index e4b3d7db68c9..0b951ca78ec4 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -9,7 +9,7 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/errno.h> #include <linux/kernel.h> #include <linux/clk.h> diff --git a/drivers/gpio/gpio-ftgpio010.c b/drivers/gpio/gpio-ftgpio010.c index 7b3394fdc624..b7a3a2db699b 100644 --- a/drivers/gpio/gpio-ftgpio010.c +++ b/drivers/gpio/gpio-ftgpio010.c @@ -176,8 +176,8 @@ static int ftgpio_gpio_probe(struct platform_device *pdev) return PTR_ERR(g->base); irq = platform_get_irq(pdev, 0); - if (!irq) - return -EINVAL; + if (irq <= 0) + return irq ? irq : -EINVAL; ret = bgpio_init(&g->gc, dev, 4, g->base + GPIO_DATA_IN, diff --git a/drivers/gpio/gpio-iop.c b/drivers/gpio/gpio-iop.c index 98c7ff2a76e7..8d62db447ec1 100644 --- a/drivers/gpio/gpio-iop.c +++ b/drivers/gpio/gpio-iop.c @@ -58,3 +58,7 @@ static int __init iop3xx_gpio_init(void) return platform_driver_register(&iop3xx_gpio_driver); } arch_initcall(iop3xx_gpio_init); + +MODULE_DESCRIPTION("GPIO handling for Intel IOP3xx processors"); +MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-it87.c b/drivers/gpio/gpio-it87.c index d43d0a2cc4c5..efb46edff81f 100644 --- a/drivers/gpio/gpio-it87.c +++ b/drivers/gpio/gpio-it87.c @@ -414,6 +414,6 @@ static void __exit it87_gpio_exit(void) module_init(it87_gpio_init); module_exit(it87_gpio_exit); -MODULE_AUTHOR("Diego Elio Pettenò <flameeyes@flameeyes.eu>"); +MODULE_AUTHOR("Diego Elio Pettenò <flameeyes@flameeyes.eu>"); MODULE_DESCRIPTION("GPIO interface for IT87xx Super I/O chips"); MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c index c04fae1ba32a..9d8bcc69f245 100644 --- a/drivers/gpio/gpio-max732x.c +++ b/drivers/gpio/gpio-max732x.c @@ -709,8 +709,7 @@ static int max732x_probe(struct i2c_client *client, return 0; out_failed: - if (chip->client_dummy) - i2c_unregister_device(chip->client_dummy); + i2c_unregister_device(chip->client_dummy); return ret; } @@ -734,8 +733,7 @@ static int max732x_remove(struct i2c_client *client) gpiochip_remove(&chip->gpio_chip); /* unregister any dummy i2c_client */ - if (chip->client_dummy) - i2c_unregister_device(chip->client_dummy); + i2c_unregister_device(chip->client_dummy); return 0; } diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c index 9532d86a82f7..3a545ad17817 100644 --- a/drivers/gpio/gpio-mockup.c +++ b/drivers/gpio/gpio-mockup.c @@ -27,13 +27,15 @@ #include "gpiolib.h" #define GPIO_MOCKUP_NAME "gpio-mockup" -#define GPIO_MOCKUP_MAX_GC 10 +#define GPIO_MOCKUP_MAX_GC 10 /* * We're storing two values per chip: the GPIO base and the number * of GPIO lines. */ #define GPIO_MOCKUP_MAX_RANGES (GPIO_MOCKUP_MAX_GC * 2) +#define gpio_mockup_err(...) pr_err(GPIO_MOCKUP_NAME ": " __VA_ARGS__) + enum { GPIO_MOCKUP_DIR_OUT = 0, GPIO_MOCKUP_DIR_IN = 1, @@ -46,7 +48,7 @@ enum { */ struct gpio_mockup_line_status { int dir; - bool value; + int value; }; struct gpio_mockup_chip { @@ -62,17 +64,33 @@ struct gpio_mockup_dbgfs_private { int offset; }; +struct gpio_mockup_platform_data { + int base; + int ngpio; + int index; + bool named_lines; +}; + static int gpio_mockup_ranges[GPIO_MOCKUP_MAX_RANGES]; -static int gpio_mockup_params_nr; -module_param_array(gpio_mockup_ranges, int, &gpio_mockup_params_nr, 0400); +static int gpio_mockup_num_ranges; +module_param_array(gpio_mockup_ranges, int, &gpio_mockup_num_ranges, 0400); static bool gpio_mockup_named_lines; module_param_named(gpio_mockup_named_lines, gpio_mockup_named_lines, bool, 0400); -static const char gpio_mockup_name_start = 'A'; static struct dentry *gpio_mockup_dbg_dir; +static int gpio_mockup_range_base(unsigned int index) +{ + return gpio_mockup_ranges[index * 2]; +} + +static int gpio_mockup_range_ngpio(unsigned int index) +{ + return gpio_mockup_ranges[index * 2 + 1]; +} + static int gpio_mockup_get(struct gpio_chip *gc, unsigned int offset) { struct gpio_mockup_chip *chip = gpiochip_get_data(gc); @@ -80,16 +98,26 @@ static int gpio_mockup_get(struct gpio_chip *gc, unsigned int offset) return chip->lines[offset].value; } -static void gpio_mockup_set(struct gpio_chip *gc, unsigned int offset, - int value) +static void gpio_mockup_set(struct gpio_chip *gc, + unsigned int offset, int value) { struct gpio_mockup_chip *chip = gpiochip_get_data(gc); chip->lines[offset].value = !!value; } -static int gpio_mockup_dirout(struct gpio_chip *gc, unsigned int offset, - int value) +static void gpio_mockup_set_multiple(struct gpio_chip *gc, + unsigned long *mask, unsigned long *bits) +{ + unsigned int bit; + + for_each_set_bit(bit, mask, gc->ngpio) + gpio_mockup_set(gc, bit, test_bit(bit, bits)); + +} + +static int gpio_mockup_dirout(struct gpio_chip *gc, + unsigned int offset, int value) { struct gpio_mockup_chip *chip = gpiochip_get_data(gc); @@ -115,29 +143,6 @@ static int gpio_mockup_get_direction(struct gpio_chip *gc, unsigned int offset) return chip->lines[offset].dir; } -static int gpio_mockup_name_lines(struct device *dev, - struct gpio_mockup_chip *chip) -{ - struct gpio_chip *gc = &chip->gc; - char **names; - int i; - - names = devm_kcalloc(dev, gc->ngpio, sizeof(char *), GFP_KERNEL); - if (!names) - return -ENOMEM; - - for (i = 0; i < gc->ngpio; i++) { - names[i] = devm_kasprintf(dev, GFP_KERNEL, - "%s-%d", gc->label, i); - if (!names[i]) - return -ENOMEM; - } - - gc->names = (const char *const *)names; - - return 0; -} - static int gpio_mockup_to_irq(struct gpio_chip *gc, unsigned int offset) { struct gpio_mockup_chip *chip = gpiochip_get_data(gc); @@ -188,15 +193,21 @@ static void gpio_mockup_debugfs_setup(struct device *dev, struct gpio_mockup_chip *chip) { struct gpio_mockup_dbgfs_private *priv; - struct dentry *evfile; + struct dentry *evfile, *link; struct gpio_chip *gc; + const char *devname; char *name; int i; gc = &chip->gc; + devname = dev_name(&gc->gpiodev->dev); - chip->dbg_dir = debugfs_create_dir(gc->label, gpio_mockup_dbg_dir); - if (!chip->dbg_dir) + chip->dbg_dir = debugfs_create_dir(devname, gpio_mockup_dbg_dir); + if (IS_ERR_OR_NULL(chip->dbg_dir)) + goto err; + + link = debugfs_create_symlink(gc->label, gpio_mockup_dbg_dir, devname); + if (IS_ERR_OR_NULL(link)) goto err; for (i = 0; i < gc->ngpio; i++) { @@ -214,23 +225,63 @@ static void gpio_mockup_debugfs_setup(struct device *dev, evfile = debugfs_create_file(name, 0200, chip->dbg_dir, priv, &gpio_mockup_event_ops); - if (!evfile) + if (IS_ERR_OR_NULL(evfile)) goto err; } return; err: - dev_err(dev, "error creating debugfs directory\n"); + dev_err(dev, "error creating debugfs event files\n"); } -static int gpio_mockup_add(struct device *dev, - struct gpio_mockup_chip *chip, - const char *name, int base, int ngpio) +static int gpio_mockup_name_lines(struct device *dev, + struct gpio_mockup_chip *chip) { struct gpio_chip *gc = &chip->gc; - int ret; + char **names; + int i; + + names = devm_kcalloc(dev, gc->ngpio, sizeof(char *), GFP_KERNEL); + if (!names) + return -ENOMEM; + + for (i = 0; i < gc->ngpio; i++) { + names[i] = devm_kasprintf(dev, GFP_KERNEL, + "%s-%d", gc->label, i); + if (!names[i]) + return -ENOMEM; + } + + gc->names = (const char *const *)names; + + return 0; +} + +static int gpio_mockup_probe(struct platform_device *pdev) +{ + struct gpio_mockup_platform_data *pdata; + struct gpio_mockup_chip *chip; + struct gpio_chip *gc; + int rv, base, ngpio; + struct device *dev; + char *name; + + dev = &pdev->dev; + pdata = dev_get_platdata(dev); + base = pdata->base; + ngpio = pdata->ngpio; + chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + name = devm_kasprintf(dev, GFP_KERNEL, "%s-%c", + pdev->name, pdata->index); + if (!name) + return -ENOMEM; + + gc = &chip->gc; gc->base = base; gc->ngpio = ngpio; gc->label = name; @@ -238,6 +289,7 @@ static int gpio_mockup_add(struct device *dev, gc->parent = dev; gc->get = gpio_mockup_get; gc->set = gpio_mockup_set; + gc->set_multiple = gpio_mockup_set_multiple; gc->direction_output = gpio_mockup_dirout; gc->direction_input = gpio_mockup_dirin; gc->get_direction = gpio_mockup_get_direction; @@ -248,19 +300,19 @@ static int gpio_mockup_add(struct device *dev, if (!chip->lines) return -ENOMEM; - if (gpio_mockup_named_lines) { - ret = gpio_mockup_name_lines(dev, chip); - if (ret) - return ret; + if (pdata->named_lines) { + rv = gpio_mockup_name_lines(dev, chip); + if (rv) + return rv; } - ret = devm_irq_sim_init(dev, &chip->irqsim, gc->ngpio); - if (ret) - return ret; + rv = devm_irq_sim_init(dev, &chip->irqsim, gc->ngpio); + if (rv < 0) + return rv; - ret = devm_gpiochip_add_data(dev, &chip->gc, chip); - if (ret) - return ret; + rv = devm_gpiochip_add_data(dev, &chip->gc, chip); + if (rv) + return rv; if (gpio_mockup_dbg_dir) gpio_mockup_debugfs_setup(dev, chip); @@ -268,58 +320,6 @@ static int gpio_mockup_add(struct device *dev, return 0; } -static int gpio_mockup_probe(struct platform_device *pdev) -{ - int ret, i, base, ngpio, num_chips; - struct device *dev = &pdev->dev; - struct gpio_mockup_chip *chips; - char *chip_name; - - if (gpio_mockup_params_nr < 2 || (gpio_mockup_params_nr % 2)) - return -EINVAL; - - /* Each chip is described by two values. */ - num_chips = gpio_mockup_params_nr / 2; - - chips = devm_kcalloc(dev, num_chips, sizeof(*chips), GFP_KERNEL); - if (!chips) - return -ENOMEM; - - platform_set_drvdata(pdev, chips); - - for (i = 0; i < num_chips; i++) { - base = gpio_mockup_ranges[i * 2]; - - if (base == -1) - ngpio = gpio_mockup_ranges[i * 2 + 1]; - else - ngpio = gpio_mockup_ranges[i * 2 + 1] - base; - - if (ngpio >= 0) { - chip_name = devm_kasprintf(dev, GFP_KERNEL, - "%s-%c", GPIO_MOCKUP_NAME, - gpio_mockup_name_start + i); - if (!chip_name) - return -ENOMEM; - - ret = gpio_mockup_add(dev, &chips[i], - chip_name, base, ngpio); - } else { - ret = -EINVAL; - } - - if (ret) { - dev_err(dev, - "adding gpiochip failed: %d (base: %d, ngpio: %d)\n", - ret, base, base < 0 ? ngpio : base + ngpio); - - return ret; - } - } - - return 0; -} - static struct platform_driver gpio_mockup_driver = { .driver = { .name = GPIO_MOCKUP_NAME, @@ -327,44 +327,88 @@ static struct platform_driver gpio_mockup_driver = { .probe = gpio_mockup_probe, }; -static struct platform_device *pdev; -static int __init mock_device_init(void) +static struct platform_device *gpio_mockup_pdevs[GPIO_MOCKUP_MAX_GC]; + +static void gpio_mockup_unregister_pdevs(void) { - int err; + struct platform_device *pdev; + int i; - gpio_mockup_dbg_dir = debugfs_create_dir("gpio-mockup-event", NULL); - if (!gpio_mockup_dbg_dir) - pr_err("%s: error creating debugfs directory\n", - GPIO_MOCKUP_NAME); + for (i = 0; i < GPIO_MOCKUP_MAX_GC; i++) { + pdev = gpio_mockup_pdevs[i]; - pdev = platform_device_alloc(GPIO_MOCKUP_NAME, -1); - if (!pdev) - return -ENOMEM; + if (pdev) + platform_device_unregister(pdev); + } +} - err = platform_device_add(pdev); - if (err) { - platform_device_put(pdev); - return err; +static int __init gpio_mockup_init(void) +{ + int i, num_chips, err = 0, index = 'A'; + struct gpio_mockup_platform_data pdata; + struct platform_device *pdev; + + if ((gpio_mockup_num_ranges < 2) || + (gpio_mockup_num_ranges % 2) || + (gpio_mockup_num_ranges > GPIO_MOCKUP_MAX_RANGES)) + return -EINVAL; + + /* Each chip is described by two values. */ + num_chips = gpio_mockup_num_ranges / 2; + + /* + * The second value in the <base GPIO - number of GPIOS> pair must + * always be greater than 0. + */ + for (i = 0; i < num_chips; i++) { + if (gpio_mockup_range_ngpio(i) < 0) + return -EINVAL; } + gpio_mockup_dbg_dir = debugfs_create_dir("gpio-mockup-event", NULL); + if (IS_ERR_OR_NULL(gpio_mockup_dbg_dir)) + gpio_mockup_err("error creating debugfs directory\n"); + err = platform_driver_register(&gpio_mockup_driver); if (err) { - platform_device_unregister(pdev); + gpio_mockup_err("error registering platform driver\n"); return err; } + for (i = 0; i < num_chips; i++) { + pdata.index = index++; + pdata.base = gpio_mockup_range_base(i); + pdata.ngpio = pdata.base < 0 + ? gpio_mockup_range_ngpio(i) + : gpio_mockup_range_ngpio(i) - pdata.base; + pdata.named_lines = gpio_mockup_named_lines; + + pdev = platform_device_register_resndata(NULL, + GPIO_MOCKUP_NAME, + i, NULL, 0, &pdata, + sizeof(pdata)); + if (IS_ERR(pdev)) { + gpio_mockup_err("error registering device"); + platform_driver_unregister(&gpio_mockup_driver); + gpio_mockup_unregister_pdevs(); + return PTR_ERR(pdev); + } + + gpio_mockup_pdevs[i] = pdev; + } + return 0; } -static void __exit mock_device_exit(void) +static void __exit gpio_mockup_exit(void) { debugfs_remove_recursive(gpio_mockup_dbg_dir); platform_driver_unregister(&gpio_mockup_driver); - platform_device_unregister(pdev); + gpio_mockup_unregister_pdevs(); } -module_init(mock_device_init); -module_exit(mock_device_exit); +module_init(gpio_mockup_init); +module_exit(gpio_mockup_exit); MODULE_AUTHOR("Kamlakant Patel <kamlakant.patel@broadcom.com>"); MODULE_AUTHOR("Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>"); diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index e136d666f1e5..ab5035b96886 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1058,7 +1058,9 @@ static void omap_gpio_mod_init(struct gpio_bank *bank) static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc) { + struct gpio_irq_chip *irq; static int gpio; + const char *label; int irq_base = 0; int ret; @@ -1080,21 +1082,15 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc) bank->chip.parent = &omap_mpuio_device.dev; bank->chip.base = OMAP_MPUIO(0); } else { - bank->chip.label = "gpio"; + label = devm_kasprintf(bank->chip.parent, GFP_KERNEL, "gpio-%d-%d", + gpio, gpio + bank->width - 1); + if (!label) + return -ENOMEM; + bank->chip.label = label; bank->chip.base = gpio; } bank->chip.ngpio = bank->width; - ret = gpiochip_add_data(&bank->chip, bank); - if (ret) { - dev_err(bank->chip.parent, - "Could not register gpio chip %d\n", ret); - return ret; - } - - if (!bank->is_mpuio) - gpio += bank->width; - #ifdef CONFIG_ARCH_OMAP1 /* * REVISIT: Once we have OMAP1 supporting SPARSE_IRQ, we can drop @@ -1115,25 +1111,30 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc) irqc->irq_set_wake = NULL; } - ret = gpiochip_irqchip_add(&bank->chip, irqc, - irq_base, handle_bad_irq, - IRQ_TYPE_NONE); + irq = &bank->chip.irq; + irq->chip = irqc; + irq->handler = handle_bad_irq; + irq->default_type = IRQ_TYPE_NONE; + irq->num_parents = 1; + irq->parents = &bank->irq; + irq->first = irq_base; + ret = gpiochip_add_data(&bank->chip, bank); if (ret) { dev_err(bank->chip.parent, - "Couldn't add irqchip to gpiochip %d\n", ret); - gpiochip_remove(&bank->chip); - return -ENODEV; + "Could not register gpio chip %d\n", ret); + return ret; } - gpiochip_set_chained_irqchip(&bank->chip, irqc, bank->irq, NULL); - ret = devm_request_irq(bank->chip.parent, bank->irq, omap_gpio_irq_handler, 0, dev_name(bank->chip.parent), bank); if (ret) gpiochip_remove(&bank->chip); + if (!bank->is_mpuio) + gpio += bank->width; + return ret; } diff --git a/drivers/gpio/gpio-pcie-idio-24.c b/drivers/gpio/gpio-pcie-idio-24.c new file mode 100644 index 000000000000..f666e2e69074 --- /dev/null +++ b/drivers/gpio/gpio-pcie-idio-24.c @@ -0,0 +1,447 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * GPIO driver for the ACCES PCIe-IDIO-24 family + * Copyright (C) 2018 William Breathitt Gray + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * This driver supports the following ACCES devices: PCIe-IDIO-24, + * PCIe-IDI-24, PCIe-IDO-24, and PCIe-IDIO-12. + */ +#include <linux/bitops.h> +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/gpio/driver.h> +#include <linux/interrupt.h> +#include <linux/irqdesc.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/spinlock.h> +#include <linux/types.h> + +/** + * struct idio_24_gpio_reg - GPIO device registers structure + * @out0_7: Read: FET Outputs 0-7 + * Write: FET Outputs 0-7 + * @out8_15: Read: FET Outputs 8-15 + * Write: FET Outputs 8-15 + * @out16_23: Read: FET Outputs 16-23 + * Write: FET Outputs 16-23 + * @ttl_out0_7: Read: TTL/CMOS Outputs 0-7 + * Write: TTL/CMOS Outputs 0-7 + * @in0_7: Read: Isolated Inputs 0-7 + * Write: Reserved + * @in8_15: Read: Isolated Inputs 8-15 + * Write: Reserved + * @in16_23: Read: Isolated Inputs 16-23 + * Write: Reserved + * @ttl_in0_7: Read: TTL/CMOS Inputs 0-7 + * Write: Reserved + * @cos0_7: Read: COS Status Inputs 0-7 + * Write: COS Clear Inputs 0-7 + * @cos8_15: Read: COS Status Inputs 8-15 + * Write: COS Clear Inputs 8-15 + * @cos16_23: Read: COS Status Inputs 16-23 + * Write: COS Clear Inputs 16-23 + * @cos_ttl0_7: Read: COS Status TTL/CMOS 0-7 + * Write: COS Clear TTL/CMOS 0-7 + * @ctl: Read: Control Register + * Write: Control Register + * @reserved: Read: Reserved + * Write: Reserved + * @cos_enable: Read: COS Enable + * Write: COS Enable + * @soft_reset: Read: IRQ Output Pin Status + * Write: Software Board Reset + */ +struct idio_24_gpio_reg { + u8 out0_7; + u8 out8_15; + u8 out16_23; + u8 ttl_out0_7; + u8 in0_7; + u8 in8_15; + u8 in16_23; + u8 ttl_in0_7; + u8 cos0_7; + u8 cos8_15; + u8 cos16_23; + u8 cos_ttl0_7; + u8 ctl; + u8 reserved; + u8 cos_enable; + u8 soft_reset; +}; + +/** + * struct idio_24_gpio - GPIO device private data structure + * @chip: instance of the gpio_chip + * @lock: synchronization lock to prevent I/O race conditions + * @reg: I/O address offset for the GPIO device registers + * @irq_mask: I/O bits affected by interrupts + */ +struct idio_24_gpio { + struct gpio_chip chip; + raw_spinlock_t lock; + struct idio_24_gpio_reg __iomem *reg; + unsigned long irq_mask; +}; + +static int idio_24_gpio_get_direction(struct gpio_chip *chip, + unsigned int offset) +{ + struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); + const unsigned long out_mode_mask = BIT(1); + + /* FET Outputs */ + if (offset < 24) + return 0; + + /* Isolated Inputs */ + if (offset < 48) + return 1; + + /* TTL/CMOS I/O */ + /* OUT MODE = 1 when TTL/CMOS Output Mode is set */ + return !(ioread8(&idio24gpio->reg->ctl) & out_mode_mask); +} + +static int idio_24_gpio_direction_input(struct gpio_chip *chip, + unsigned int offset) +{ + struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); + unsigned long flags; + unsigned int ctl_state; + const unsigned long out_mode_mask = BIT(1); + + /* TTL/CMOS I/O */ + if (offset > 47) { + raw_spin_lock_irqsave(&idio24gpio->lock, flags); + + /* Clear TTL/CMOS Output Mode */ + ctl_state = ioread8(&idio24gpio->reg->ctl) & ~out_mode_mask; + iowrite8(ctl_state, &idio24gpio->reg->ctl); + + raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); + } + + return 0; +} + +static int idio_24_gpio_direction_output(struct gpio_chip *chip, + unsigned int offset, int value) +{ + struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); + unsigned long flags; + unsigned int ctl_state; + const unsigned long out_mode_mask = BIT(1); + + /* TTL/CMOS I/O */ + if (offset > 47) { + raw_spin_lock_irqsave(&idio24gpio->lock, flags); + + /* Set TTL/CMOS Output Mode */ + ctl_state = ioread8(&idio24gpio->reg->ctl) | out_mode_mask; + iowrite8(ctl_state, &idio24gpio->reg->ctl); + + raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); + } + + chip->set(chip, offset, value); + return 0; +} + +static int idio_24_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); + const unsigned long offset_mask = BIT(offset % 8); + const unsigned long out_mode_mask = BIT(1); + + /* FET Outputs */ + if (offset < 8) + return !!(ioread8(&idio24gpio->reg->out0_7) & offset_mask); + + if (offset < 16) + return !!(ioread8(&idio24gpio->reg->out8_15) & offset_mask); + + if (offset < 24) + return !!(ioread8(&idio24gpio->reg->out16_23) & offset_mask); + + /* Isolated Inputs */ + if (offset < 32) + return !!(ioread8(&idio24gpio->reg->in0_7) & offset_mask); + + if (offset < 40) + return !!(ioread8(&idio24gpio->reg->in8_15) & offset_mask); + + if (offset < 48) + return !!(ioread8(&idio24gpio->reg->in16_23) & offset_mask); + + /* TTL/CMOS Outputs */ + if (ioread8(&idio24gpio->reg->ctl) & out_mode_mask) + return !!(ioread8(&idio24gpio->reg->ttl_out0_7) & offset_mask); + + /* TTL/CMOS Inputs */ + return !!(ioread8(&idio24gpio->reg->ttl_in0_7) & offset_mask); +} + +static void idio_24_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) +{ + struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); + const unsigned long out_mode_mask = BIT(1); + void __iomem *base; + const unsigned int mask = BIT(offset % 8); + unsigned long flags; + unsigned int out_state; + + /* Isolated Inputs */ + if (offset > 23 && offset < 48) + return; + + /* TTL/CMOS Inputs */ + if (offset > 47 && !(ioread8(&idio24gpio->reg->ctl) & out_mode_mask)) + return; + + /* TTL/CMOS Outputs */ + if (offset > 47) + base = &idio24gpio->reg->ttl_out0_7; + /* FET Outputs */ + else if (offset > 15) + base = &idio24gpio->reg->out16_23; + else if (offset > 7) + base = &idio24gpio->reg->out8_15; + else + base = &idio24gpio->reg->out0_7; + + raw_spin_lock_irqsave(&idio24gpio->lock, flags); + + if (value) + out_state = ioread8(base) | mask; + else + out_state = ioread8(base) & ~mask; + + iowrite8(out_state, base); + + raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); +} + +static void idio_24_irq_ack(struct irq_data *data) +{ +} + +static void idio_24_irq_mask(struct irq_data *data) +{ + struct gpio_chip *const chip = irq_data_get_irq_chip_data(data); + struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); + unsigned long flags; + const unsigned long bit_offset = irqd_to_hwirq(data) - 24; + unsigned char new_irq_mask; + const unsigned long bank_offset = bit_offset/8 * 8; + unsigned char cos_enable_state; + + raw_spin_lock_irqsave(&idio24gpio->lock, flags); + + idio24gpio->irq_mask &= BIT(bit_offset); + new_irq_mask = idio24gpio->irq_mask >> bank_offset; + + if (!new_irq_mask) { + cos_enable_state = ioread8(&idio24gpio->reg->cos_enable); + + /* Disable Rising Edge detection */ + cos_enable_state &= ~BIT(bank_offset); + /* Disable Falling Edge detection */ + cos_enable_state &= ~BIT(bank_offset + 4); + + iowrite8(cos_enable_state, &idio24gpio->reg->cos_enable); + } + + raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); +} + +static void idio_24_irq_unmask(struct irq_data *data) +{ + struct gpio_chip *const chip = irq_data_get_irq_chip_data(data); + struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); + unsigned long flags; + unsigned char prev_irq_mask; + const unsigned long bit_offset = irqd_to_hwirq(data) - 24; + const unsigned long bank_offset = bit_offset/8 * 8; + unsigned char cos_enable_state; + + raw_spin_lock_irqsave(&idio24gpio->lock, flags); + + prev_irq_mask = idio24gpio->irq_mask >> bank_offset; + idio24gpio->irq_mask |= BIT(bit_offset); + + if (!prev_irq_mask) { + cos_enable_state = ioread8(&idio24gpio->reg->cos_enable); + + /* Enable Rising Edge detection */ + cos_enable_state |= BIT(bank_offset); + /* Enable Falling Edge detection */ + cos_enable_state |= BIT(bank_offset + 4); + + iowrite8(cos_enable_state, &idio24gpio->reg->cos_enable); + } + + raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); +} + +static int idio_24_irq_set_type(struct irq_data *data, unsigned int flow_type) +{ + /* The only valid irq types are none and both-edges */ + if (flow_type != IRQ_TYPE_NONE && + (flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH) + return -EINVAL; + + return 0; +} + +static struct irq_chip idio_24_irqchip = { + .name = "pcie-idio-24", + .irq_ack = idio_24_irq_ack, + .irq_mask = idio_24_irq_mask, + .irq_unmask = idio_24_irq_unmask, + .irq_set_type = idio_24_irq_set_type +}; + +static irqreturn_t idio_24_irq_handler(int irq, void *dev_id) +{ + struct idio_24_gpio *const idio24gpio = dev_id; + unsigned long irq_status; + struct gpio_chip *const chip = &idio24gpio->chip; + unsigned long irq_mask; + int gpio; + + raw_spin_lock(&idio24gpio->lock); + + /* Read Change-Of-State status */ + irq_status = ioread32(&idio24gpio->reg->cos0_7); + + raw_spin_unlock(&idio24gpio->lock); + + /* Make sure our device generated IRQ */ + if (!irq_status) + return IRQ_NONE; + + /* Handle only unmasked IRQ */ + irq_mask = idio24gpio->irq_mask & irq_status; + + for_each_set_bit(gpio, &irq_mask, chip->ngpio - 24) + generic_handle_irq(irq_find_mapping(chip->irq.domain, + gpio + 24)); + + raw_spin_lock(&idio24gpio->lock); + + /* Clear Change-Of-State status */ + iowrite32(irq_status, &idio24gpio->reg->cos0_7); + + raw_spin_unlock(&idio24gpio->lock); + + return IRQ_HANDLED; +} + +#define IDIO_24_NGPIO 56 +static const char *idio_24_names[IDIO_24_NGPIO] = { + "OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7", + "OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15", + "OUT16", "OUT17", "OUT18", "OUT19", "OUT20", "OUT21", "OUT22", "OUT23", + "IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7", + "IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15", + "IIN16", "IIN17", "IIN18", "IIN19", "IIN20", "IIN21", "IIN22", "IIN23", + "TTL0", "TTL1", "TTL2", "TTL3", "TTL4", "TTL5", "TTL6", "TTL7" +}; + +static int idio_24_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct device *const dev = &pdev->dev; + struct idio_24_gpio *idio24gpio; + int err; + const size_t pci_bar_index = 2; + const char *const name = pci_name(pdev); + + idio24gpio = devm_kzalloc(dev, sizeof(*idio24gpio), GFP_KERNEL); + if (!idio24gpio) + return -ENOMEM; + + err = pcim_enable_device(pdev); + if (err) { + dev_err(dev, "Failed to enable PCI device (%d)\n", err); + return err; + } + + err = pcim_iomap_regions(pdev, BIT(pci_bar_index), name); + if (err) { + dev_err(dev, "Unable to map PCI I/O addresses (%d)\n", err); + return err; + } + + idio24gpio->reg = pcim_iomap_table(pdev)[pci_bar_index]; + + idio24gpio->chip.label = name; + idio24gpio->chip.parent = dev; + idio24gpio->chip.owner = THIS_MODULE; + idio24gpio->chip.base = -1; + idio24gpio->chip.ngpio = IDIO_24_NGPIO; + idio24gpio->chip.names = idio_24_names; + idio24gpio->chip.get_direction = idio_24_gpio_get_direction; + idio24gpio->chip.direction_input = idio_24_gpio_direction_input; + idio24gpio->chip.direction_output = idio_24_gpio_direction_output; + idio24gpio->chip.get = idio_24_gpio_get; + idio24gpio->chip.set = idio_24_gpio_set; + + raw_spin_lock_init(&idio24gpio->lock); + + /* Software board reset */ + iowrite8(0, &idio24gpio->reg->soft_reset); + + err = devm_gpiochip_add_data(dev, &idio24gpio->chip, idio24gpio); + if (err) { + dev_err(dev, "GPIO registering failed (%d)\n", err); + return err; + } + + err = gpiochip_irqchip_add(&idio24gpio->chip, &idio_24_irqchip, 0, + handle_edge_irq, IRQ_TYPE_NONE); + if (err) { + dev_err(dev, "Could not add irqchip (%d)\n", err); + return err; + } + + err = devm_request_irq(dev, pdev->irq, idio_24_irq_handler, IRQF_SHARED, + name, idio24gpio); + if (err) { + dev_err(dev, "IRQ handler registering failed (%d)\n", err); + return err; + } + + return 0; +} + +static const struct pci_device_id idio_24_pci_dev_id[] = { + { PCI_DEVICE(0x494F, 0x0FD0) }, { PCI_DEVICE(0x494F, 0x0BD0) }, + { PCI_DEVICE(0x494F, 0x07D0) }, { PCI_DEVICE(0x494F, 0x0FC0) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, idio_24_pci_dev_id); + +static struct pci_driver idio_24_driver = { + .name = "pcie-idio-24", + .id_table = idio_24_pci_dev_id, + .probe = idio_24_probe +}; + +module_pci_driver(idio_24_driver); + +MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); +MODULE_DESCRIPTION("ACCES PCIe-IDIO-24 GPIO driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index e6e5cca624a7..f8d7d1cd8488 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -190,6 +190,16 @@ static void stmpe_gpio_irq_sync_unlock(struct irq_data *d) }; int i, j; + /* + * STMPE1600: to be able to get IRQ from pins, + * a read must be done on GPMR register, or a write in + * GPSR or GPCR registers + */ + if (stmpe->partnum == STMPE1600) { + stmpe_reg_read(stmpe, stmpe->regs[STMPE_IDX_GPMR_LSB]); + stmpe_reg_read(stmpe, stmpe->regs[STMPE_IDX_GPMR_CSB]); + } + for (i = 0; i < CACHE_NR_REGS; i++) { /* STMPE801 and STMPE1600 don't have RE and FE registers */ if ((stmpe->partnum == STMPE801 || @@ -227,21 +237,11 @@ static void stmpe_gpio_irq_unmask(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc); - struct stmpe *stmpe = stmpe_gpio->stmpe; int offset = d->hwirq; int regoffset = offset / 8; int mask = BIT(offset % 8); stmpe_gpio->regs[REG_IE][regoffset] |= mask; - - /* - * STMPE1600 workaround: to be able to get IRQ from pins, - * a read must be done on GPMR register, or a write in - * GPSR or GPCR registers - */ - if (stmpe->partnum == STMPE1600) - stmpe_reg_read(stmpe, - stmpe->regs[STMPE_IDX_GPMR_LSB + regoffset]); } static void stmpe_dbg_show_one(struct seq_file *s, @@ -273,15 +273,21 @@ static void stmpe_dbg_show_one(struct seq_file *s, u8 fall_reg; u8 irqen_reg; - char *edge_det_values[] = {"edge-inactive", - "edge-asserted", - "not-supported"}; - char *rise_values[] = {"no-rising-edge-detection", - "rising-edge-detection", - "not-supported"}; - char *fall_values[] = {"no-falling-edge-detection", - "falling-edge-detection", - "not-supported"}; + static const char * const edge_det_values[] = { + "edge-inactive", + "edge-asserted", + "not-supported" + }; + static const char * const rise_values[] = { + "no-rising-edge-detection", + "rising-edge-detection", + "not-supported" + }; + static const char * const fall_values[] = { + "no-falling-edge-detection", + "falling-edge-detection", + "not-supported" + }; #define NOT_SUPPORTED_IDX 2 u8 edge_det = NOT_SUPPORTED_IDX; u8 rise = NOT_SUPPORTED_IDX; @@ -344,7 +350,7 @@ static void stmpe_dbg_show(struct seq_file *s, struct gpio_chip *gc) for (i = 0; i < gc->ngpio; i++, gpio++) { stmpe_dbg_show_one(s, gc, i, gpio); - seq_printf(s, "\n"); + seq_putc(s, '\n'); } } @@ -426,12 +432,9 @@ static int stmpe_gpio_probe(struct platform_device *pdev) struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent); struct device_node *np = pdev->dev.of_node; struct stmpe_gpio *stmpe_gpio; - int ret; - int irq = 0; - - irq = platform_get_irq(pdev, 0); + int ret, irq; - stmpe_gpio = kzalloc(sizeof(struct stmpe_gpio), GFP_KERNEL); + stmpe_gpio = kzalloc(sizeof(*stmpe_gpio), GFP_KERNEL); if (!stmpe_gpio) return -ENOMEM; @@ -453,6 +456,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev) if (stmpe_gpio->norequest_mask) stmpe_gpio->chip.irq.need_valid_mask = true; + irq = platform_get_irq(pdev, 0); if (irq < 0) dev_info(&pdev->dev, "device configured in no-irq mode: " diff --git a/drivers/gpio/gpio-thunderx.c b/drivers/gpio/gpio-thunderx.c index b5adb79a631a..d16e9d4a129b 100644 --- a/drivers/gpio/gpio-thunderx.c +++ b/drivers/gpio/gpio-thunderx.c @@ -553,8 +553,10 @@ static int thunderx_gpio_probe(struct pci_dev *pdev, txgpio->irqd = irq_domain_create_hierarchy(irq_get_irq_data(txgpio->msix_entries[0].vector)->domain, 0, 0, of_node_to_fwnode(dev->of_node), &thunderx_gpio_irqd_ops, txgpio); - if (!txgpio->irqd) + if (!txgpio->irqd) { + err = -ENOMEM; goto out; + } /* Push on irq_data and the domain for each line. */ for (i = 0; i < ngpio; i++) { diff --git a/drivers/gpio/gpio-winbond.c b/drivers/gpio/gpio-winbond.c new file mode 100644 index 000000000000..7f8f5b02e31d --- /dev/null +++ b/drivers/gpio/gpio-winbond.c @@ -0,0 +1,732 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * GPIO interface for Winbond Super I/O chips + * Currently, only W83627UHG (Nuvoton NCT6627UD) is supported. + * + * Author: Maciej S. Szmigiero <mail@maciej.szmigiero.name> + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/gpio/driver.h> +#include <linux/ioport.h> +#include <linux/isa.h> +#include <linux/module.h> + +#define WB_GPIO_DRIVER_NAME KBUILD_MODNAME + +#define WB_SIO_BASE 0x2e +#define WB_SIO_BASE_HIGH 0x4e + +#define WB_SIO_EXT_ENTER_KEY 0x87 +#define WB_SIO_EXT_EXIT_KEY 0xaa + +/* global chip registers */ + +#define WB_SIO_REG_LOGICAL 0x07 + +#define WB_SIO_REG_CHIP_MSB 0x20 +#define WB_SIO_REG_CHIP_LSB 0x21 + +#define WB_SIO_CHIP_ID_W83627UHG 0xa230 +#define WB_SIO_CHIP_ID_W83627UHG_MASK GENMASK(15, 4) + +#define WB_SIO_REG_DPD 0x22 +#define WB_SIO_REG_DPD_UARTA 4 +#define WB_SIO_REG_DPD_UARTB 5 + +#define WB_SIO_REG_IDPD 0x23 +#define WB_SIO_REG_IDPD_UARTC 4 +#define WB_SIO_REG_IDPD_UARTD 5 +#define WB_SIO_REG_IDPD_UARTE 6 +#define WB_SIO_REG_IDPD_UARTF 7 + +#define WB_SIO_REG_GLOBAL_OPT 0x24 +#define WB_SIO_REG_GO_ENFDC 1 + +#define WB_SIO_REG_OVTGPIO3456 0x29 +#define WB_SIO_REG_OG3456_G3PP 3 +#define WB_SIO_REG_OG3456_G4PP 4 +#define WB_SIO_REG_OG3456_G5PP 5 +#define WB_SIO_REG_OG3456_G6PP 7 + +#define WB_SIO_REG_I2C_PS 0x2a +#define WB_SIO_REG_I2CPS_I2CFS 1 + +#define WB_SIO_REG_GPIO1_MF 0x2c +#define WB_SIO_REG_G1MF_G1PP 6 +#define WB_SIO_REG_G1MF_G2PP 7 +#define WB_SIO_REG_G1MF_FS_MASK GENMASK(1, 0) +#define WB_SIO_REG_G1MF_FS_IR_OFF 0 +#define WB_SIO_REG_G1MF_FS_IR 1 +#define WB_SIO_REG_G1MF_FS_GPIO1 2 +#define WB_SIO_REG_G1MF_FS_UARTB 3 + +/* not an actual device number, just a value meaning 'no device' */ +#define WB_SIO_DEV_NONE 0xff + +/* registers with offsets >= 0x30 are specific for a particular device */ + +/* UART B logical device */ +#define WB_SIO_DEV_UARTB 0x03 +#define WB_SIO_UARTB_REG_ENABLE 0x30 +#define WB_SIO_UARTB_ENABLE_ON 0 + +/* UART C logical device */ +#define WB_SIO_DEV_UARTC 0x06 +#define WB_SIO_UARTC_REG_ENABLE 0x30 +#define WB_SIO_UARTC_ENABLE_ON 0 + +/* GPIO3, GPIO4 logical device */ +#define WB_SIO_DEV_GPIO34 0x07 +#define WB_SIO_GPIO34_REG_ENABLE 0x30 +#define WB_SIO_GPIO34_ENABLE_3 0 +#define WB_SIO_GPIO34_ENABLE_4 1 +#define WB_SIO_GPIO34_REG_IO3 0xe0 +#define WB_SIO_GPIO34_REG_DATA3 0xe1 +#define WB_SIO_GPIO34_REG_INV3 0xe2 +#define WB_SIO_GPIO34_REG_IO4 0xe4 +#define WB_SIO_GPIO34_REG_DATA4 0xe5 +#define WB_SIO_GPIO34_REG_INV4 0xe6 + +/* WDTO, PLED, GPIO5, GPIO6 logical device */ +#define WB_SIO_DEV_WDGPIO56 0x08 +#define WB_SIO_WDGPIO56_REG_ENABLE 0x30 +#define WB_SIO_WDGPIO56_ENABLE_5 1 +#define WB_SIO_WDGPIO56_ENABLE_6 2 +#define WB_SIO_WDGPIO56_REG_IO5 0xe0 +#define WB_SIO_WDGPIO56_REG_DATA5 0xe1 +#define WB_SIO_WDGPIO56_REG_INV5 0xe2 +#define WB_SIO_WDGPIO56_REG_IO6 0xe4 +#define WB_SIO_WDGPIO56_REG_DATA6 0xe5 +#define WB_SIO_WDGPIO56_REG_INV6 0xe6 + +/* GPIO1, GPIO2, SUSLED logical device */ +#define WB_SIO_DEV_GPIO12 0x09 +#define WB_SIO_GPIO12_REG_ENABLE 0x30 +#define WB_SIO_GPIO12_ENABLE_1 0 +#define WB_SIO_GPIO12_ENABLE_2 1 +#define WB_SIO_GPIO12_REG_IO1 0xe0 +#define WB_SIO_GPIO12_REG_DATA1 0xe1 +#define WB_SIO_GPIO12_REG_INV1 0xe2 +#define WB_SIO_GPIO12_REG_IO2 0xe4 +#define WB_SIO_GPIO12_REG_DATA2 0xe5 +#define WB_SIO_GPIO12_REG_INV2 0xe6 + +/* UART D logical device */ +#define WB_SIO_DEV_UARTD 0x0d +#define WB_SIO_UARTD_REG_ENABLE 0x30 +#define WB_SIO_UARTD_ENABLE_ON 0 + +/* UART E logical device */ +#define WB_SIO_DEV_UARTE 0x0e +#define WB_SIO_UARTE_REG_ENABLE 0x30 +#define WB_SIO_UARTE_ENABLE_ON 0 + +/* + * for a description what a particular field of this struct means please see + * a description of the relevant module parameter at the bottom of this file + */ +struct winbond_gpio_params { + unsigned long base; + unsigned long gpios; + unsigned long ppgpios; + unsigned long odgpios; + bool pledgpio; + bool beepgpio; + bool i2cgpio; +}; + +static struct winbond_gpio_params params; + +static int winbond_sio_enter(unsigned long base) +{ + if (!request_muxed_region(base, 2, WB_GPIO_DRIVER_NAME)) + return -EBUSY; + + /* + * datasheet says two successive writes of the "key" value are needed + * in order for chip to enter the "Extended Function Mode" + */ + outb(WB_SIO_EXT_ENTER_KEY, base); + outb(WB_SIO_EXT_ENTER_KEY, base); + + return 0; +} + +static void winbond_sio_select_logical(unsigned long base, u8 dev) +{ + outb(WB_SIO_REG_LOGICAL, base); + outb(dev, base + 1); +} + +static void winbond_sio_leave(unsigned long base) +{ + outb(WB_SIO_EXT_EXIT_KEY, base); + + release_region(base, 2); +} + +static void winbond_sio_reg_write(unsigned long base, u8 reg, u8 data) +{ + outb(reg, base); + outb(data, base + 1); +} + +static u8 winbond_sio_reg_read(unsigned long base, u8 reg) +{ + outb(reg, base); + return inb(base + 1); +} + +static void winbond_sio_reg_bset(unsigned long base, u8 reg, u8 bit) +{ + u8 val; + + val = winbond_sio_reg_read(base, reg); + val |= BIT(bit); + winbond_sio_reg_write(base, reg, val); +} + +static void winbond_sio_reg_bclear(unsigned long base, u8 reg, u8 bit) +{ + u8 val; + + val = winbond_sio_reg_read(base, reg); + val &= ~BIT(bit); + winbond_sio_reg_write(base, reg, val); +} + +static bool winbond_sio_reg_btest(unsigned long base, u8 reg, u8 bit) +{ + return winbond_sio_reg_read(base, reg) & BIT(bit); +} + +/** + * struct winbond_gpio_port_conflict - possibly conflicting device information + * @name: device name (NULL means no conflicting device defined) + * @dev: Super I/O logical device number where the testreg register + * is located (or WB_SIO_DEV_NONE - don't select any + * logical device) + * @testreg: register number where the testbit bit is located + * @testbit: index of a bit to check whether an actual conflict exists + * @warnonly: if set then a conflict isn't fatal (just warn about it), + * otherwise disable the particular GPIO port if a conflict + * is detected + */ +struct winbond_gpio_port_conflict { + const char *name; + u8 dev; + u8 testreg; + u8 testbit; + bool warnonly; +}; + +/** + * struct winbond_gpio_info - information about a particular GPIO port (device) + * @dev: Super I/O logical device number of the registers + * specified below + * @enablereg: port enable bit register number + * @enablebit: index of a port enable bit + * @outputreg: output driver mode bit register number + * @outputppbit: index of a push-pull output driver mode bit + * @ioreg: data direction register number + * @invreg: pin data inversion register number + * @datareg: pin data register number + * @conflict: description of a device that possibly conflicts with + * this port + */ +struct winbond_gpio_info { + u8 dev; + u8 enablereg; + u8 enablebit; + u8 outputreg; + u8 outputppbit; + u8 ioreg; + u8 invreg; + u8 datareg; + struct winbond_gpio_port_conflict conflict; +}; + +static const struct winbond_gpio_info winbond_gpio_infos[6] = { + { /* 0 */ + .dev = WB_SIO_DEV_GPIO12, + .enablereg = WB_SIO_GPIO12_REG_ENABLE, + .enablebit = WB_SIO_GPIO12_ENABLE_1, + .outputreg = WB_SIO_REG_GPIO1_MF, + .outputppbit = WB_SIO_REG_G1MF_G1PP, + .ioreg = WB_SIO_GPIO12_REG_IO1, + .invreg = WB_SIO_GPIO12_REG_INV1, + .datareg = WB_SIO_GPIO12_REG_DATA1, + .conflict = { + .name = "UARTB", + .dev = WB_SIO_DEV_UARTB, + .testreg = WB_SIO_UARTB_REG_ENABLE, + .testbit = WB_SIO_UARTB_ENABLE_ON, + .warnonly = true + } + }, + { /* 1 */ + .dev = WB_SIO_DEV_GPIO12, + .enablereg = WB_SIO_GPIO12_REG_ENABLE, + .enablebit = WB_SIO_GPIO12_ENABLE_2, + .outputreg = WB_SIO_REG_GPIO1_MF, + .outputppbit = WB_SIO_REG_G1MF_G2PP, + .ioreg = WB_SIO_GPIO12_REG_IO2, + .invreg = WB_SIO_GPIO12_REG_INV2, + .datareg = WB_SIO_GPIO12_REG_DATA2 + /* special conflict handling so doesn't use conflict data */ + }, + { /* 2 */ + .dev = WB_SIO_DEV_GPIO34, + .enablereg = WB_SIO_GPIO34_REG_ENABLE, + .enablebit = WB_SIO_GPIO34_ENABLE_3, + .outputreg = WB_SIO_REG_OVTGPIO3456, + .outputppbit = WB_SIO_REG_OG3456_G3PP, + .ioreg = WB_SIO_GPIO34_REG_IO3, + .invreg = WB_SIO_GPIO34_REG_INV3, + .datareg = WB_SIO_GPIO34_REG_DATA3, + .conflict = { + .name = "UARTC", + .dev = WB_SIO_DEV_UARTC, + .testreg = WB_SIO_UARTC_REG_ENABLE, + .testbit = WB_SIO_UARTC_ENABLE_ON, + .warnonly = true + } + }, + { /* 3 */ + .dev = WB_SIO_DEV_GPIO34, + .enablereg = WB_SIO_GPIO34_REG_ENABLE, + .enablebit = WB_SIO_GPIO34_ENABLE_4, + .outputreg = WB_SIO_REG_OVTGPIO3456, + .outputppbit = WB_SIO_REG_OG3456_G4PP, + .ioreg = WB_SIO_GPIO34_REG_IO4, + .invreg = WB_SIO_GPIO34_REG_INV4, + .datareg = WB_SIO_GPIO34_REG_DATA4, + .conflict = { + .name = "UARTD", + .dev = WB_SIO_DEV_UARTD, + .testreg = WB_SIO_UARTD_REG_ENABLE, + .testbit = WB_SIO_UARTD_ENABLE_ON, + .warnonly = true + } + }, + { /* 4 */ + .dev = WB_SIO_DEV_WDGPIO56, + .enablereg = WB_SIO_WDGPIO56_REG_ENABLE, + .enablebit = WB_SIO_WDGPIO56_ENABLE_5, + .outputreg = WB_SIO_REG_OVTGPIO3456, + .outputppbit = WB_SIO_REG_OG3456_G5PP, + .ioreg = WB_SIO_WDGPIO56_REG_IO5, + .invreg = WB_SIO_WDGPIO56_REG_INV5, + .datareg = WB_SIO_WDGPIO56_REG_DATA5, + .conflict = { + .name = "UARTE", + .dev = WB_SIO_DEV_UARTE, + .testreg = WB_SIO_UARTE_REG_ENABLE, + .testbit = WB_SIO_UARTE_ENABLE_ON, + .warnonly = true + } + }, + { /* 5 */ + .dev = WB_SIO_DEV_WDGPIO56, + .enablereg = WB_SIO_WDGPIO56_REG_ENABLE, + .enablebit = WB_SIO_WDGPIO56_ENABLE_6, + .outputreg = WB_SIO_REG_OVTGPIO3456, + .outputppbit = WB_SIO_REG_OG3456_G6PP, + .ioreg = WB_SIO_WDGPIO56_REG_IO6, + .invreg = WB_SIO_WDGPIO56_REG_INV6, + .datareg = WB_SIO_WDGPIO56_REG_DATA6, + .conflict = { + .name = "FDC", + .dev = WB_SIO_DEV_NONE, + .testreg = WB_SIO_REG_GLOBAL_OPT, + .testbit = WB_SIO_REG_GO_ENFDC, + .warnonly = false + } + } +}; + +/* returns whether changing a pin is allowed */ +static bool winbond_gpio_get_info(unsigned int *gpio_num, + const struct winbond_gpio_info **info) +{ + bool allow_changing = true; + unsigned long i; + + for_each_set_bit(i, ¶ms.gpios, BITS_PER_LONG) { + if (*gpio_num < 8) + break; + + *gpio_num -= 8; + } + + *info = &winbond_gpio_infos[i]; + + /* + * GPIO2 (the second port) shares some pins with a basic PC + * functionality, which is very likely controlled by the firmware. + * Don't allow changing these pins by default. + */ + if (i == 1) { + if (*gpio_num == 0 && !params.pledgpio) + allow_changing = false; + else if (*gpio_num == 1 && !params.beepgpio) + allow_changing = false; + else if ((*gpio_num == 5 || *gpio_num == 6) && !params.i2cgpio) + allow_changing = false; + } + + return allow_changing; +} + +static int winbond_gpio_get(struct gpio_chip *gc, unsigned int offset) +{ + unsigned long *base = gpiochip_get_data(gc); + const struct winbond_gpio_info *info; + bool val; + + winbond_gpio_get_info(&offset, &info); + + val = winbond_sio_enter(*base); + if (val) + return val; + + winbond_sio_select_logical(*base, info->dev); + + val = winbond_sio_reg_btest(*base, info->datareg, offset); + if (winbond_sio_reg_btest(*base, info->invreg, offset)) + val = !val; + + winbond_sio_leave(*base); + + return val; +} + +static int winbond_gpio_direction_in(struct gpio_chip *gc, unsigned int offset) +{ + unsigned long *base = gpiochip_get_data(gc); + const struct winbond_gpio_info *info; + int ret; + + if (!winbond_gpio_get_info(&offset, &info)) + return -EACCES; + + ret = winbond_sio_enter(*base); + if (ret) + return ret; + + winbond_sio_select_logical(*base, info->dev); + + winbond_sio_reg_bset(*base, info->ioreg, offset); + + winbond_sio_leave(*base); + + return 0; +} + +static int winbond_gpio_direction_out(struct gpio_chip *gc, + unsigned int offset, + int val) +{ + unsigned long *base = gpiochip_get_data(gc); + const struct winbond_gpio_info *info; + int ret; + + if (!winbond_gpio_get_info(&offset, &info)) + return -EACCES; + + ret = winbond_sio_enter(*base); + if (ret) + return ret; + + winbond_sio_select_logical(*base, info->dev); + + winbond_sio_reg_bclear(*base, info->ioreg, offset); + + if (winbond_sio_reg_btest(*base, info->invreg, offset)) + val = !val; + + if (val) + winbond_sio_reg_bset(*base, info->datareg, offset); + else + winbond_sio_reg_bclear(*base, info->datareg, offset); + + winbond_sio_leave(*base); + + return 0; +} + +static void winbond_gpio_set(struct gpio_chip *gc, unsigned int offset, + int val) +{ + unsigned long *base = gpiochip_get_data(gc); + const struct winbond_gpio_info *info; + + if (!winbond_gpio_get_info(&offset, &info)) + return; + + if (winbond_sio_enter(*base) != 0) + return; + + winbond_sio_select_logical(*base, info->dev); + + if (winbond_sio_reg_btest(*base, info->invreg, offset)) + val = !val; + + if (val) + winbond_sio_reg_bset(*base, info->datareg, offset); + else + winbond_sio_reg_bclear(*base, info->datareg, offset); + + winbond_sio_leave(*base); +} + +static struct gpio_chip winbond_gpio_chip = { + .base = -1, + .label = WB_GPIO_DRIVER_NAME, + .owner = THIS_MODULE, + .can_sleep = true, + .get = winbond_gpio_get, + .direction_input = winbond_gpio_direction_in, + .set = winbond_gpio_set, + .direction_output = winbond_gpio_direction_out, +}; + +static void winbond_gpio_configure_port0_pins(unsigned long base) +{ + unsigned int val; + + val = winbond_sio_reg_read(base, WB_SIO_REG_GPIO1_MF); + if ((val & WB_SIO_REG_G1MF_FS_MASK) == WB_SIO_REG_G1MF_FS_GPIO1) + return; + + pr_warn("GPIO1 pins were connected to something else (%.2x), fixing\n", + val); + + val &= ~WB_SIO_REG_G1MF_FS_MASK; + val |= WB_SIO_REG_G1MF_FS_GPIO1; + + winbond_sio_reg_write(base, WB_SIO_REG_GPIO1_MF, val); +} + +static void winbond_gpio_configure_port1_check_i2c(unsigned long base) +{ + params.i2cgpio = !winbond_sio_reg_btest(base, WB_SIO_REG_I2C_PS, + WB_SIO_REG_I2CPS_I2CFS); + if (!params.i2cgpio) + pr_warn("disabling GPIO2.5 and GPIO2.6 as I2C is enabled\n"); +} + +static bool winbond_gpio_configure_port(unsigned long base, unsigned int idx) +{ + const struct winbond_gpio_info *info = &winbond_gpio_infos[idx]; + const struct winbond_gpio_port_conflict *conflict = &info->conflict; + + /* is there a possible conflicting device defined? */ + if (conflict->name != NULL) { + if (conflict->dev != WB_SIO_DEV_NONE) + winbond_sio_select_logical(base, conflict->dev); + + if (winbond_sio_reg_btest(base, conflict->testreg, + conflict->testbit)) { + if (conflict->warnonly) + pr_warn("enabled GPIO%u share pins with active %s\n", + idx + 1, conflict->name); + else { + pr_warn("disabling GPIO%u as %s is enabled\n", + idx + 1, conflict->name); + return false; + } + } + } + + /* GPIO1 and GPIO2 need some (additional) special handling */ + if (idx == 0) + winbond_gpio_configure_port0_pins(base); + else if (idx == 1) + winbond_gpio_configure_port1_check_i2c(base); + + winbond_sio_select_logical(base, info->dev); + + winbond_sio_reg_bset(base, info->enablereg, info->enablebit); + + if (params.ppgpios & BIT(idx)) + winbond_sio_reg_bset(base, info->outputreg, + info->outputppbit); + else if (params.odgpios & BIT(idx)) + winbond_sio_reg_bclear(base, info->outputreg, + info->outputppbit); + else + pr_notice("GPIO%u pins are %s\n", idx + 1, + winbond_sio_reg_btest(base, info->outputreg, + info->outputppbit) ? + "push-pull" : + "open drain"); + + return true; +} + +static int winbond_gpio_configure(unsigned long base) +{ + unsigned long i; + + for_each_set_bit(i, ¶ms.gpios, BITS_PER_LONG) + if (!winbond_gpio_configure_port(base, i)) + __clear_bit(i, ¶ms.gpios); + + if (!params.gpios) { + pr_err("please use 'gpios' module parameter to select some active GPIO ports to enable\n"); + return -EINVAL; + } + + return 0; +} + +static int winbond_gpio_check_chip(unsigned long base) +{ + int ret; + unsigned int chip; + + ret = winbond_sio_enter(base); + if (ret) + return ret; + + chip = winbond_sio_reg_read(base, WB_SIO_REG_CHIP_MSB) << 8; + chip |= winbond_sio_reg_read(base, WB_SIO_REG_CHIP_LSB); + + pr_notice("chip ID at %lx is %.4x\n", base, chip); + + if ((chip & WB_SIO_CHIP_ID_W83627UHG_MASK) != + WB_SIO_CHIP_ID_W83627UHG) { + pr_err("not an our chip\n"); + ret = -ENODEV; + } + + winbond_sio_leave(base); + + return ret; +} + +static int winbond_gpio_imatch(struct device *dev, unsigned int id) +{ + unsigned long gpios_rem; + int ret; + + gpios_rem = params.gpios & ~GENMASK(ARRAY_SIZE(winbond_gpio_infos) - 1, + 0); + if (gpios_rem) { + pr_warn("unknown ports (%lx) enabled in GPIO ports bitmask\n", + gpios_rem); + params.gpios &= ~gpios_rem; + } + + if (params.ppgpios & params.odgpios) { + pr_err("some GPIO ports are set both to push-pull and open drain mode at the same time\n"); + return 0; + } + + if (params.base != 0) + return winbond_gpio_check_chip(params.base) == 0; + + /* + * if the 'base' module parameter is unset probe two chip default + * I/O port bases + */ + params.base = WB_SIO_BASE; + ret = winbond_gpio_check_chip(params.base); + if (ret == 0) + return 1; + if (ret != -ENODEV && ret != -EBUSY) + return 0; + + params.base = WB_SIO_BASE_HIGH; + return winbond_gpio_check_chip(params.base) == 0; +} + +static int winbond_gpio_iprobe(struct device *dev, unsigned int id) +{ + int ret; + + if (params.base == 0) + return -EINVAL; + + ret = winbond_sio_enter(params.base); + if (ret) + return ret; + + ret = winbond_gpio_configure(params.base); + + winbond_sio_leave(params.base); + + if (ret) + return ret; + + /* + * Add 8 gpios for every GPIO port that was enabled in gpios + * module parameter (that wasn't disabled earlier in + * winbond_gpio_configure() & co. due to, for example, a pin conflict). + */ + winbond_gpio_chip.ngpio = hweight_long(params.gpios) * 8; + + /* + * GPIO6 port has only 5 pins, so if it is enabled we have to adjust + * the total count appropriately + */ + if (params.gpios & BIT(5)) + winbond_gpio_chip.ngpio -= (8 - 5); + + winbond_gpio_chip.parent = dev; + + return devm_gpiochip_add_data(dev, &winbond_gpio_chip, ¶ms.base); +} + +static struct isa_driver winbond_gpio_idriver = { + .driver = { + .name = WB_GPIO_DRIVER_NAME, + }, + .match = winbond_gpio_imatch, + .probe = winbond_gpio_iprobe, +}; + +module_isa_driver(winbond_gpio_idriver, 1); + +module_param_named(base, params.base, ulong, 0444); +MODULE_PARM_DESC(base, + "I/O port base (when unset - probe chip default ones)"); + +/* This parameter sets which GPIO devices (ports) we enable */ +module_param_named(gpios, params.gpios, ulong, 0444); +MODULE_PARM_DESC(gpios, + "bitmask of GPIO ports to enable (bit 0 - GPIO1, bit 1 - GPIO2, etc."); + +/* + * These two parameters below set how we configure GPIO ports output drivers. + * It can't be a one bitmask since we need three values per port: push-pull, + * open-drain and keep as-is (this is the default). + */ +module_param_named(ppgpios, params.ppgpios, ulong, 0444); +MODULE_PARM_DESC(ppgpios, + "bitmask of GPIO ports to set to push-pull mode (bit 0 - GPIO1, bit 1 - GPIO2, etc."); + +module_param_named(odgpios, params.odgpios, ulong, 0444); +MODULE_PARM_DESC(odgpios, + "bitmask of GPIO ports to set to open drain mode (bit 0 - GPIO1, bit 1 - GPIO2, etc."); + +/* + * GPIO2.0 and GPIO2.1 control a basic PC functionality that we + * don't allow tinkering with by default (it is very likely that the + * firmware owns these pins). + * These two parameters below allow overriding these prohibitions. + */ +module_param_named(pledgpio, params.pledgpio, bool, 0644); +MODULE_PARM_DESC(pledgpio, + "enable changing value of GPIO2.0 bit (Power LED), default no."); + +module_param_named(beepgpio, params.beepgpio, bool, 0644); +MODULE_PARM_DESC(beepgpio, + "enable changing value of GPIO2.1 bit (BEEP), default no."); + +MODULE_AUTHOR("Maciej S. Szmigiero <mail@maciej.szmigiero.name>"); +MODULE_DESCRIPTION("GPIO interface for Winbond Super I/O chips"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index d6f3d9ee1350..0ecffd172a80 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -414,7 +414,8 @@ EXPORT_SYMBOL_GPL(devm_acpi_dev_remove_driver_gpios); static bool acpi_get_driver_gpio_data(struct acpi_device *adev, const char *name, int index, - struct acpi_reference_args *args) + struct acpi_reference_args *args, + unsigned int *quirks) { const struct acpi_gpio_mapping *gm; @@ -430,6 +431,8 @@ static bool acpi_get_driver_gpio_data(struct acpi_device *adev, args->args[1] = par->line_index; args->args[2] = par->active_low; args->nargs = 3; + + *quirks = gm->quirks; return true; } @@ -461,8 +464,8 @@ acpi_gpio_to_gpiod_flags(const struct acpi_resource_gpio *agpio) } } -int -acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, enum gpiod_flags update) +static int +__acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, enum gpiod_flags update) { int ret = 0; @@ -489,12 +492,31 @@ acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, enum gpiod_flags update) return ret; } +int +acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, struct acpi_gpio_info *info) +{ + struct device *dev = &info->adev->dev; + enum gpiod_flags old = *flags; + int ret; + + ret = __acpi_gpio_update_gpiod_flags(&old, info->flags); + if (info->quirks & ACPI_GPIO_QUIRK_NO_IO_RESTRICTION) { + if (ret) + dev_warn(dev, FW_BUG "GPIO not in correct mode, fixing\n"); + } else { + if (ret) + dev_dbg(dev, "Override GPIO initialization flags\n"); + *flags = old; + } + + return ret; +} + struct acpi_gpio_lookup { struct acpi_gpio_info info; int index; int pin_index; bool active_low; - struct acpi_device *adev; struct gpio_desc *desc; int n; }; @@ -531,8 +553,8 @@ static int acpi_populate_gpio_lookup(struct acpi_resource *ares, void *data) lookup->info.triggering = agpio->triggering; } else { lookup->info.flags = acpi_gpio_to_gpiod_flags(agpio); + lookup->info.polarity = lookup->active_low; } - } return 1; @@ -541,12 +563,13 @@ static int acpi_populate_gpio_lookup(struct acpi_resource *ares, void *data) static int acpi_gpio_resource_lookup(struct acpi_gpio_lookup *lookup, struct acpi_gpio_info *info) { + struct acpi_device *adev = lookup->info.adev; struct list_head res_list; int ret; INIT_LIST_HEAD(&res_list); - ret = acpi_dev_get_resources(lookup->adev, &res_list, + ret = acpi_dev_get_resources(adev, &res_list, acpi_populate_gpio_lookup, lookup); if (ret < 0) @@ -557,11 +580,8 @@ static int acpi_gpio_resource_lookup(struct acpi_gpio_lookup *lookup, if (!lookup->desc) return -ENOENT; - if (info) { + if (info) *info = lookup->info; - if (lookup->active_low) - info->polarity = lookup->active_low; - } return 0; } @@ -570,6 +590,7 @@ static int acpi_gpio_property_lookup(struct fwnode_handle *fwnode, struct acpi_gpio_lookup *lookup) { struct acpi_reference_args args; + unsigned int quirks = 0; int ret; memset(&args, 0, sizeof(args)); @@ -581,14 +602,14 @@ static int acpi_gpio_property_lookup(struct fwnode_handle *fwnode, if (!adev) return ret; - if (!acpi_get_driver_gpio_data(adev, propname, index, &args)) + if (!acpi_get_driver_gpio_data(adev, propname, index, &args, + &quirks)) return ret; } /* * The property was found and resolved, so need to lookup the GPIO based * on returned args. */ - lookup->adev = args.adev; if (args.nargs != 3) return -EPROTO; @@ -596,6 +617,8 @@ static int acpi_gpio_property_lookup(struct fwnode_handle *fwnode, lookup->pin_index = args.args[1]; lookup->active_low = !!args.args[2]; + lookup->info.adev = args.adev; + lookup->info.quirks = quirks; return 0; } @@ -643,11 +666,11 @@ static struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev, return ERR_PTR(ret); dev_dbg(&adev->dev, "GPIO: _DSD returned %s %d %d %u\n", - dev_name(&lookup.adev->dev), lookup.index, + dev_name(&lookup.info.adev->dev), lookup.index, lookup.pin_index, lookup.active_low); } else { dev_dbg(&adev->dev, "GPIO: looking up %d in _CRS\n", index); - lookup.adev = adev; + lookup.info.adev = adev; } ret = acpi_gpio_resource_lookup(&lookup, info); @@ -664,7 +687,6 @@ struct gpio_desc *acpi_find_gpio(struct device *dev, struct acpi_gpio_info info; struct gpio_desc *desc; char propname[32]; - int err; int i; /* Try first from _DSD */ @@ -703,10 +725,7 @@ struct gpio_desc *acpi_find_gpio(struct device *dev, if (info.polarity == GPIO_ACTIVE_LOW) *lookupflags |= GPIO_ACTIVE_LOW; - err = acpi_gpio_update_gpiod_flags(dflags, info.flags); - if (err) - dev_dbg(dev, "Override GPIO initialization flags\n"); - + acpi_gpio_update_gpiod_flags(dflags, &info); return desc; } diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 72a0695d2ac3..564bb7a31da4 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -56,6 +56,42 @@ static struct gpio_desc *of_xlate_and_get_gpiod_flags(struct gpio_chip *chip, return gpiochip_get_desc(chip, ret); } +static void of_gpio_flags_quirks(struct device_node *np, + enum of_gpio_flags *flags) +{ + /* + * Some GPIO fixed regulator quirks. + * Note that active low is the default. + */ + if (IS_ENABLED(CONFIG_REGULATOR) && + (of_device_is_compatible(np, "reg-fixed-voltage") || + of_device_is_compatible(np, "regulator-gpio"))) { + /* + * The regulator GPIO handles are specified such that the + * presence or absence of "enable-active-high" solely controls + * the polarity of the GPIO line. Any phandle flags must + * be actively ignored. + */ + if (*flags & OF_GPIO_ACTIVE_LOW) { + pr_warn("%s GPIO handle specifies active low - ignored\n", + of_node_full_name(np)); + *flags &= ~OF_GPIO_ACTIVE_LOW; + } + if (!of_property_read_bool(np, "enable-active-high")) + *flags |= OF_GPIO_ACTIVE_LOW; + } + /* + * Legacy open drain handling for fixed voltage regulators. + */ + if (IS_ENABLED(CONFIG_REGULATOR) && + of_device_is_compatible(np, "reg-fixed-voltage") && + of_property_read_bool(np, "gpio-open-drain")) { + *flags |= (OF_GPIO_SINGLE_ENDED | OF_GPIO_OPEN_DRAIN); + pr_info("%s uses legacy open drain flag - update the DTS if you can\n", + of_node_full_name(np)); + } +} + /** * of_get_named_gpiod_flags() - Get a GPIO descriptor and flags for GPIO API * @np: device node to get GPIO from @@ -93,6 +129,9 @@ struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np, if (IS_ERR(desc)) goto out; + if (flags) + of_gpio_flags_quirks(np, flags); + pr_debug("%s: parsed '%s' property of node '%pOF[%d]' - status (%d)\n", __func__, propname, np, index, PTR_ERR_OR_ZERO(desc)); @@ -117,6 +156,71 @@ int of_get_named_gpio_flags(struct device_node *np, const char *list_name, } EXPORT_SYMBOL(of_get_named_gpio_flags); +/* + * The SPI GPIO bindings happened before we managed to establish that GPIO + * properties should be named "foo-gpios" so we have this special kludge for + * them. + */ +static struct gpio_desc *of_find_spi_gpio(struct device *dev, const char *con_id, + enum of_gpio_flags *of_flags) +{ + char prop_name[32]; /* 32 is max size of property name */ + struct device_node *np = dev->of_node; + struct gpio_desc *desc; + + /* + * Hopefully the compiler stubs the rest of the function if this + * is false. + */ + if (!IS_ENABLED(CONFIG_SPI_MASTER)) + return ERR_PTR(-ENOENT); + + /* Allow this specifically for "spi-gpio" devices */ + if (!of_device_is_compatible(np, "spi-gpio") || !con_id) + return ERR_PTR(-ENOENT); + + /* Will be "gpio-sck", "gpio-mosi" or "gpio-miso" */ + snprintf(prop_name, sizeof(prop_name), "%s-%s", "gpio", con_id); + + desc = of_get_named_gpiod_flags(np, prop_name, 0, of_flags); + return desc; +} + +/* + * Some regulator bindings happened before we managed to establish that GPIO + * properties should be named "foo-gpios" so we have this special kludge for + * them. + */ +static struct gpio_desc *of_find_regulator_gpio(struct device *dev, const char *con_id, + enum of_gpio_flags *of_flags) +{ + /* These are the connection IDs we accept as legacy GPIO phandles */ + const char *whitelist[] = { + "wlf,ldoena", /* Arizona */ + "wlf,ldo1ena", /* WM8994 */ + "wlf,ldo2ena", /* WM8994 */ + }; + struct device_node *np = dev->of_node; + struct gpio_desc *desc; + int i; + + if (!IS_ENABLED(CONFIG_REGULATOR)) + return ERR_PTR(-ENOENT); + + if (!con_id) + return ERR_PTR(-ENOENT); + + for (i = 0; i < ARRAY_SIZE(whitelist); i++) + if (!strcmp(con_id, whitelist[i])) + break; + + if (i == ARRAY_SIZE(whitelist)) + return ERR_PTR(-ENOENT); + + desc = of_get_named_gpiod_flags(np, con_id, 0, of_flags); + return desc; +} + struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, unsigned int idx, enum gpio_lookup_flags *flags) @@ -126,6 +230,7 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, struct gpio_desc *desc; unsigned int i; + /* Try GPIO property "foo-gpios" and "foo-gpio" */ for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) { if (con_id) snprintf(prop_name, sizeof(prop_name), "%s-%s", con_id, @@ -140,6 +245,14 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, break; } + /* Special handling for SPI GPIOs if used */ + if (IS_ERR(desc)) + desc = of_find_spi_gpio(dev, con_id, &of_flags); + + /* Special handling for regulator GPIOs if used */ + if (IS_ERR(desc)) + desc = of_find_regulator_gpio(dev, con_id, &of_flags); + if (IS_ERR(desc)) return desc; @@ -153,8 +266,8 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, *flags |= GPIO_OPEN_SOURCE; } - if (of_flags & OF_GPIO_SLEEP_MAY_LOSE_VALUE) - *flags |= GPIO_SLEEP_MAY_LOSE_VALUE; + if (of_flags & OF_GPIO_TRANSITORY) + *flags |= GPIO_TRANSITORY; return desc; } @@ -214,6 +327,8 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np, if (xlate_flags & OF_GPIO_ACTIVE_LOW) *lflags |= GPIO_ACTIVE_LOW; + if (xlate_flags & OF_GPIO_TRANSITORY) + *lflags |= GPIO_TRANSITORY; if (of_property_read_bool(np, "input")) *dflags |= GPIOD_IN; diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c index 3f454eaf2101..3dbaf489a8a5 100644 --- a/drivers/gpio/gpiolib-sysfs.c +++ b/drivers/gpio/gpiolib-sysfs.c @@ -8,6 +8,7 @@ #include <linux/interrupt.h> #include <linux/kdev_t.h> #include <linux/slab.h> +#include <linux/ctype.h> #include "gpiolib.h" @@ -106,8 +107,14 @@ static ssize_t value_show(struct device *dev, mutex_lock(&data->mutex); - status = sprintf(buf, "%d\n", gpiod_get_value_cansleep(desc)); + status = gpiod_get_value_cansleep(desc); + if (status < 0) + goto err; + buf[0] = '0' + status; + buf[1] = '\n'; + status = 2; +err: mutex_unlock(&data->mutex); return status; @@ -118,7 +125,7 @@ static ssize_t value_store(struct device *dev, { struct gpiod_data *data = dev_get_drvdata(dev); struct gpio_desc *desc = data->desc; - ssize_t status; + ssize_t status = 0; mutex_lock(&data->mutex); @@ -127,7 +134,11 @@ static ssize_t value_store(struct device *dev, } else { long value; - status = kstrtol(buf, 0, &value); + if (size <= 2 && isdigit(buf[0]) && + (size == 1 || buf[1] == '\n')) + value = buf[0] - '0'; + else + status = kstrtol(buf, 0, &value); if (status == 0) { gpiod_set_value_cansleep(desc, value); status = size; @@ -138,7 +149,7 @@ static ssize_t value_store(struct device *dev, return status; } -static DEVICE_ATTR_RW(value); +static DEVICE_ATTR_PREALLOC(value, S_IWUSR | S_IRUGO, value_show, value_store); static irqreturn_t gpio_sysfs_irq(int irq, void *priv) { @@ -474,11 +485,15 @@ static ssize_t export_store(struct class *class, status = -ENODEV; goto done; } - status = gpiod_export(desc, true); - if (status < 0) - gpiod_free(desc); - else - set_bit(FLAG_SYSFS, &desc->flags); + + status = gpiod_set_transitory(desc, false); + if (!status) { + status = gpiod_export(desc, true); + if (status < 0) + gpiod_free(desc); + else + set_bit(FLAG_SYSFS, &desc->flags); + } done: if (status) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 5d6e8bb38ac7..36ca5064486e 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -162,7 +162,7 @@ EXPORT_SYMBOL_GPL(desc_to_gpio); */ struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc) { - if (!desc || !desc->gdev || !desc->gdev->chip) + if (!desc || !desc->gdev) return NULL; return desc->gdev->chip; } @@ -196,7 +196,7 @@ static int gpiochip_find_base(int ngpio) * gpiod_get_direction - return the current direction of a GPIO * @desc: GPIO to get the direction of * - * Return GPIOF_DIR_IN or GPIOF_DIR_OUT, or an error code in case of error. + * Returns 0 for output, 1 for input, or an error code in case of error. * * This function may sleep if gpiod_cansleep() is true. */ @@ -460,6 +460,15 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip) if (lflags & ~GPIOHANDLE_REQUEST_VALID_FLAGS) return -EINVAL; + /* + * Do not allow OPEN_SOURCE & OPEN_DRAIN flags in a single request. If + * the hardware actually supports enabling both at the same time the + * electrical result would be disastrous. + */ + if ((lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN) && + (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE)) + return -EINVAL; + /* OPEN_DRAIN and OPEN_SOURCE flags only make sense for output mode. */ if (!(lflags & GPIOHANDLE_REQUEST_OUTPUT) && ((lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN) || @@ -506,6 +515,10 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip) if (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE) set_bit(FLAG_OPEN_SOURCE, &desc->flags); + ret = gpiod_set_transitory(desc, false); + if (ret < 0) + goto out_free_descs; + /* * Lines have to be requested explicitly for input * or output, else the line will be treated "as is". @@ -588,6 +601,9 @@ out_free_lh: * @events: KFIFO for the GPIO events * @read_lock: mutex lock to protect reads from colliding with adding * new events to the FIFO + * @timestamp: cache for the timestamp storing it between hardirq + * and IRQ thread, used to bring the timestamp close to the actual + * event */ struct lineevent_state { struct gpio_device *gdev; @@ -598,6 +614,7 @@ struct lineevent_state { wait_queue_head_t wait; DECLARE_KFIFO(events, struct gpioevent_data, 16); struct mutex read_lock; + u64 timestamp; }; #define GPIOEVENT_REQUEST_VALID_FLAGS \ @@ -732,7 +749,10 @@ static irqreturn_t lineevent_irq_thread(int irq, void *p) struct gpioevent_data ge; int ret, level; - ge.timestamp = ktime_get_real_ns(); + /* Do not leak kernel stack to userspace */ + memset(&ge, 0, sizeof(ge)); + + ge.timestamp = le->timestamp; level = gpiod_get_value_cansleep(le->desc); if (le->eflags & GPIOEVENT_REQUEST_RISING_EDGE @@ -760,6 +780,19 @@ static irqreturn_t lineevent_irq_thread(int irq, void *p) return IRQ_HANDLED; } +static irqreturn_t lineevent_irq_handler(int irq, void *p) +{ + struct lineevent_state *le = p; + + /* + * Just store the timestamp in hardirq context so we get it as + * close in time as possible to the actual event. + */ + le->timestamp = ktime_get_real_ns(); + + return IRQ_WAKE_THREAD; +} + static int lineevent_create(struct gpio_device *gdev, void __user *ip) { struct gpioevent_request eventreq; @@ -852,7 +885,7 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip) /* Request a thread to read the events */ ret = request_threaded_irq(le->irq, - NULL, + lineevent_irq_handler, lineevent_irq_thread, irqflags, le->label, @@ -1050,7 +1083,7 @@ static void gpiodevice_release(struct device *dev) list_del(&gdev->list); ida_simple_remove(&gpio_ida, gdev->id); - kfree(gdev->label); + kfree_const(gdev->label); kfree(gdev->descs); kfree(gdev); } @@ -1159,10 +1192,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, goto err_free_descs; } - if (chip->label) - gdev->label = kstrdup(chip->label, GFP_KERNEL); - else - gdev->label = kstrdup("unknown", GFP_KERNEL); + gdev->label = kstrdup_const(chip->label ?: "unknown", GFP_KERNEL); if (!gdev->label) { status = -ENOMEM; goto err_free_descs; @@ -1209,31 +1239,14 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, struct gpio_desc *desc = &gdev->descs[i]; desc->gdev = gdev; - /* - * REVISIT: most hardware initializes GPIOs as inputs - * (often with pullups enabled) so power usage is - * minimized. Linux code should set the gpio direction - * first thing; but until it does, and in case - * chip->get_direction is not set, we may expose the - * wrong direction in sysfs. - */ - if (chip->get_direction) { - /* - * If we have .get_direction, set up the initial - * direction flag from the hardware. - */ - int dir = chip->get_direction(chip, i); - - if (!dir) - set_bit(FLAG_IS_OUT, &desc->flags); - } else if (!chip->direction_input) { - /* - * If the chip lacks the .direction_input callback - * we logically assume all lines are outputs. - */ - set_bit(FLAG_IS_OUT, &desc->flags); - } + /* REVISIT: most hardware initializes GPIOs as inputs (often + * with pullups enabled) so power usage is minimized. Linux + * code should set the gpio direction first thing; but until + * it does, and in case chip->get_direction is not set, we may + * expose the wrong direction in sysfs. + */ + desc->flags = !chip->direction_input ? (1 << FLAG_IS_OUT) : 0; } #ifdef CONFIG_PINCTRL @@ -1283,7 +1296,7 @@ err_remove_from_list: list_del(&gdev->list); spin_unlock_irqrestore(&gpio_lock, flags); err_free_label: - kfree(gdev->label); + kfree_const(gdev->label); err_free_descs: kfree(gdev->descs); err_free_gdev: @@ -1383,7 +1396,7 @@ static int devm_gpio_chip_match(struct device *dev, void *res, void *data) } /** - * devm_gpiochip_add_data() - Resource manager piochip_add_data() + * devm_gpiochip_add_data() - Resource manager gpiochip_add_data() * @dev: the device pointer on which irq_chip belongs to. * @chip: the chip to register, with chip->base initialized * @data: driver-private data associated with this chip @@ -1510,14 +1523,15 @@ static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip) gpiochip->irq.valid_mask = NULL; } -static bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip, - unsigned int offset) +bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip, + unsigned int offset) { /* No mask means all valid */ if (likely(!gpiochip->irq.valid_mask)) return true; return test_bit(offset, gpiochip->irq.valid_mask); } +EXPORT_SYMBOL_GPL(gpiochip_irqchip_irq_valid); /** * gpiochip_set_cascaded_irqchip() - connects a cascaded irqchip to a gpiochip @@ -2174,40 +2188,37 @@ done: * macro to avoid endless duplication. If the desc is NULL it is an * optional GPIO and calls should just bail out. */ +static int validate_desc(const struct gpio_desc *desc, const char *func) +{ + if (!desc) + return 0; + if (IS_ERR(desc)) { + pr_warn("%s: invalid GPIO (errorpointer)\n", func); + return PTR_ERR(desc); + } + if (!desc->gdev) { + pr_warn("%s: invalid GPIO (no device)\n", func); + return -EINVAL; + } + if (!desc->gdev->chip) { + dev_warn(&desc->gdev->dev, + "%s: backing chip is gone\n", func); + return 0; + } + return 1; +} + #define VALIDATE_DESC(desc) do { \ - if (!desc) \ - return 0; \ - if (IS_ERR(desc)) { \ - pr_warn("%s: invalid GPIO (errorpointer)\n", __func__); \ - return PTR_ERR(desc); \ - } \ - if (!desc->gdev) { \ - pr_warn("%s: invalid GPIO (no device)\n", __func__); \ - return -EINVAL; \ - } \ - if ( !desc->gdev->chip ) { \ - dev_warn(&desc->gdev->dev, \ - "%s: backing chip is gone\n", __func__); \ - return 0; \ - } } while (0) + int __valid = validate_desc(desc, __func__); \ + if (__valid <= 0) \ + return __valid; \ + } while (0) #define VALIDATE_DESC_VOID(desc) do { \ - if (!desc) \ - return; \ - if (IS_ERR(desc)) { \ - pr_warn("%s: invalid GPIO (errorpointer)\n", __func__); \ - return; \ - } \ - if (!desc->gdev) { \ - pr_warn("%s: invalid GPIO (no device)\n", __func__); \ - return; \ - } \ - if (!desc->gdev->chip) { \ - dev_warn(&desc->gdev->dev, \ - "%s: backing chip is gone\n", __func__); \ + int __valid = validate_desc(desc, __func__); \ + if (__valid <= 0) \ return; \ - } } while (0) - + } while (0) int gpiod_request(struct gpio_desc *desc, const char *label) { @@ -2456,7 +2467,7 @@ EXPORT_SYMBOL_GPL(gpiod_direction_output_raw); */ int gpiod_direction_output(struct gpio_desc *desc, int value) { - struct gpio_chip *gc = desc->gdev->chip; + struct gpio_chip *gc; int ret; VALIDATE_DESC(desc); @@ -2473,6 +2484,7 @@ int gpiod_direction_output(struct gpio_desc *desc, int value) return -EIO; } + gc = desc->gdev->chip; if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) { /* First see if we can enable open drain in hardware */ ret = gpio_set_drive_single_ended(gc, gpio_chip_hwgpio(desc), @@ -2530,6 +2542,50 @@ int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) EXPORT_SYMBOL_GPL(gpiod_set_debounce); /** + * gpiod_set_transitory - Lose or retain GPIO state on suspend or reset + * @desc: descriptor of the GPIO for which to configure persistence + * @transitory: True to lose state on suspend or reset, false for persistence + * + * Returns: + * 0 on success, otherwise a negative error code. + */ +int gpiod_set_transitory(struct gpio_desc *desc, bool transitory) +{ + struct gpio_chip *chip; + unsigned long packed; + int gpio; + int rc; + + VALIDATE_DESC(desc); + /* + * Handle FLAG_TRANSITORY first, enabling queries to gpiolib for + * persistence state. + */ + if (transitory) + set_bit(FLAG_TRANSITORY, &desc->flags); + else + clear_bit(FLAG_TRANSITORY, &desc->flags); + + /* If the driver supports it, set the persistence state now */ + chip = desc->gdev->chip; + if (!chip->set_config) + return 0; + + packed = pinconf_to_config_packed(PIN_CONFIG_PERSIST_STATE, + !transitory); + gpio = gpio_chip_hwgpio(desc); + rc = chip->set_config(chip, gpio, packed); + if (rc == -ENOTSUPP) { + dev_dbg(&desc->gdev->dev, "Persistence not supported for GPIO %d\n", + gpio); + return 0; + } + + return rc; +} +EXPORT_SYMBOL_GPL(gpiod_set_transitory); + +/** * gpiod_is_active_low - test whether a GPIO is active-low or not * @desc: the gpio descriptor to test * @@ -3129,8 +3185,7 @@ bool gpiochip_line_is_persistent(struct gpio_chip *chip, unsigned int offset) if (offset >= chip->ngpio) return false; - return !test_bit(FLAG_SLEEP_MAY_LOSE_VALUE, - &chip->gpiodev->descs[offset].flags); + return !test_bit(FLAG_TRANSITORY, &chip->gpiodev->descs[offset].flags); } EXPORT_SYMBOL_GPL(gpiochip_line_is_persistent); @@ -3565,8 +3620,10 @@ int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id, if (lflags & GPIO_OPEN_SOURCE) set_bit(FLAG_OPEN_SOURCE, &desc->flags); - if (lflags & GPIO_SLEEP_MAY_LOSE_VALUE) - set_bit(FLAG_SLEEP_MAY_LOSE_VALUE, &desc->flags); + + status = gpiod_set_transitory(desc, (lflags & GPIO_TRANSITORY)); + if (status < 0) + return status; /* No particular flag request, return here... */ if (!(dflags & GPIOD_FLAGS_BIT_DIR_SET)) { @@ -3606,6 +3663,8 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev, struct gpio_desc *desc = NULL; int status; enum gpio_lookup_flags lookupflags = 0; + /* Maybe we have a device name, maybe not */ + const char *devname = dev ? dev_name(dev) : "?"; dev_dbg(dev, "GPIO lookup for consumer %s\n", con_id); @@ -3634,7 +3693,11 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev, return desc; } - status = gpiod_request(desc, con_id); + /* + * If a connection label was passed use that, else attempt to use + * the device name as label + */ + status = gpiod_request(desc, con_id ? con_id : devname); if (status < 0) return ERR_PTR(status); @@ -3650,17 +3713,88 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev, EXPORT_SYMBOL_GPL(gpiod_get_index); /** + * gpiod_get_from_of_node() - obtain a GPIO from an OF node + * @node: handle of the OF node + * @propname: name of the DT property representing the GPIO + * @index: index of the GPIO to obtain for the consumer + * @dflags: GPIO initialization flags + * @label: label to attach to the requested GPIO + * + * Returns: + * On successful request the GPIO pin is configured in accordance with + * provided @dflags. If the node does not have the requested GPIO + * property, NULL is returned. + * + * In case of error an ERR_PTR() is returned. + */ +struct gpio_desc *gpiod_get_from_of_node(struct device_node *node, + const char *propname, int index, + enum gpiod_flags dflags, + const char *label) +{ + struct gpio_desc *desc; + unsigned long lflags = 0; + enum of_gpio_flags flags; + bool active_low = false; + bool single_ended = false; + bool open_drain = false; + bool transitory = false; + int ret; + + desc = of_get_named_gpiod_flags(node, propname, + index, &flags); + + if (!desc || IS_ERR(desc)) { + /* If it is not there, just return NULL */ + if (PTR_ERR(desc) == -ENOENT) + return NULL; + return desc; + } + + active_low = flags & OF_GPIO_ACTIVE_LOW; + single_ended = flags & OF_GPIO_SINGLE_ENDED; + open_drain = flags & OF_GPIO_OPEN_DRAIN; + transitory = flags & OF_GPIO_TRANSITORY; + + ret = gpiod_request(desc, label); + if (ret) + return ERR_PTR(ret); + + if (active_low) + lflags |= GPIO_ACTIVE_LOW; + + if (single_ended) { + if (open_drain) + lflags |= GPIO_OPEN_DRAIN; + else + lflags |= GPIO_OPEN_SOURCE; + } + + if (transitory) + lflags |= GPIO_TRANSITORY; + + ret = gpiod_configure_flags(desc, propname, lflags, dflags); + if (ret < 0) { + gpiod_put(desc); + return ERR_PTR(ret); + } + + return desc; +} +EXPORT_SYMBOL(gpiod_get_from_of_node); + +/** * fwnode_get_named_gpiod - obtain a GPIO from firmware node * @fwnode: handle of the firmware node * @propname: name of the firmware property representing the GPIO - * @index: index of the GPIO to obtain in the consumer + * @index: index of the GPIO to obtain for the consumer * @dflags: GPIO initialization flags * @label: label to attach to the requested GPIO * * This function can be used for drivers that get their configuration - * from firmware. + * from opaque firmware. * - * Function properly finds the corresponding GPIO using whatever is the + * The function properly finds the corresponding GPIO using whatever is the * underlying firmware interface and then makes sure that the GPIO * descriptor is requested before it is returned to the caller. * @@ -3677,53 +3811,35 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, { struct gpio_desc *desc = ERR_PTR(-ENODEV); unsigned long lflags = 0; - bool active_low = false; - bool single_ended = false; - bool open_drain = false; int ret; if (!fwnode) return ERR_PTR(-EINVAL); if (is_of_node(fwnode)) { - enum of_gpio_flags flags; - - desc = of_get_named_gpiod_flags(to_of_node(fwnode), propname, - index, &flags); - if (!IS_ERR(desc)) { - active_low = flags & OF_GPIO_ACTIVE_LOW; - single_ended = flags & OF_GPIO_SINGLE_ENDED; - open_drain = flags & OF_GPIO_OPEN_DRAIN; - } + desc = gpiod_get_from_of_node(to_of_node(fwnode), + propname, index, + dflags, + label); + return desc; } else if (is_acpi_node(fwnode)) { struct acpi_gpio_info info; desc = acpi_node_get_gpiod(fwnode, propname, index, &info); - if (!IS_ERR(desc)) { - active_low = info.polarity == GPIO_ACTIVE_LOW; - ret = acpi_gpio_update_gpiod_flags(&dflags, info.flags); - if (ret) - pr_debug("Override GPIO initialization flags\n"); - } - } + if (IS_ERR(desc)) + return desc; - if (IS_ERR(desc)) - return desc; + acpi_gpio_update_gpiod_flags(&dflags, &info); + if (info.polarity == GPIO_ACTIVE_LOW) + lflags |= GPIO_ACTIVE_LOW; + } + + /* Currently only ACPI takes this path */ ret = gpiod_request(desc, label); if (ret) return ERR_PTR(ret); - if (active_low) - lflags |= GPIO_ACTIVE_LOW; - - if (single_ended) { - if (open_drain) - lflags |= GPIO_OPEN_DRAIN; - else - lflags |= GPIO_OPEN_SOURCE; - } - ret = gpiod_configure_flags(desc, propname, lflags, dflags); if (ret < 0) { gpiod_put(desc); diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index 6c44d1652139..b17ec6795c81 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -58,7 +58,7 @@ struct gpio_device { struct gpio_desc *descs; int base; u16 ngpio; - char *label; + const char *label; void *data; struct list_head list; @@ -75,16 +75,20 @@ struct gpio_device { /** * struct acpi_gpio_info - ACPI GPIO specific information + * @adev: reference to ACPI device which consumes GPIO resource * @flags: GPIO initialization flags * @gpioint: if %true this GPIO is of type GpioInt otherwise type is GpioIo * @polarity: interrupt polarity as provided by ACPI * @triggering: triggering type as provided by ACPI + * @quirks: Linux specific quirks as provided by struct acpi_gpio_mapping */ struct acpi_gpio_info { + struct acpi_device *adev; enum gpiod_flags flags; bool gpioint; int polarity; int triggering; + unsigned int quirks; }; /* gpio suffixes used for ACPI and device tree lookup */ @@ -124,7 +128,7 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip); void acpi_gpiochip_free_interrupts(struct gpio_chip *chip); int acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, - enum gpiod_flags update); + struct acpi_gpio_info *info); struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id, @@ -149,7 +153,7 @@ static inline void acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { } static inline int -acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, enum gpiod_flags update) +acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, struct acpi_gpio_info *info) { return 0; } @@ -189,6 +193,12 @@ void gpiod_set_array_value_complex(bool raw, bool can_sleep, struct gpio_desc **desc_array, int *value_array); +/* This is just passed between gpiolib and devres */ +struct gpio_desc *gpiod_get_from_of_node(struct device_node *node, + const char *propname, int index, + enum gpiod_flags dflags, + const char *label); + extern struct spinlock gpio_lock; extern struct list_head gpio_devices; @@ -205,7 +215,7 @@ struct gpio_desc { #define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */ #define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */ #define FLAG_IS_HOGGED 11 /* GPIO is hogged */ -#define FLAG_SLEEP_MAY_LOSE_VALUE 12 /* GPIO may lose value in sleep */ +#define FLAG_TRANSITORY 12 /* GPIO may lose value in sleep or reset */ /* Connection label */ const char *label; diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 4571cc098b76..ce126955212c 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -63,6 +63,16 @@ config PINCTRL_AS3722 open drain configuration for the GPIO pins of AS3722 devices. It also supports the GPIO functionality through gpiolib. +config PINCTRL_AXP209 + tristate "X-Powers AXP209 PMIC pinctrl and GPIO Support" + depends on MFD_AXP20X + help + AXP PMICs provides multiple GPIOs that can be muxed for different + functions. This driver bundles a pinctrl driver to select the function + muxing and a GPIO driver to handle the GPIO when the GPIO function is + selected. + Say yes to enable pinctrl and GPIO support for the AXP209 PMIC + config PINCTRL_BF54x def_bool y if BF54x select PINCTRL_ADI2 diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index d0d4844f8022..4777f1595ce2 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_GENERIC_PINCONF) += pinconf-generic.o obj-$(CONFIG_PINCTRL_ADI2) += pinctrl-adi2.o obj-$(CONFIG_PINCTRL_ARTPEC6) += pinctrl-artpec6.o obj-$(CONFIG_PINCTRL_AS3722) += pinctrl-as3722.o +obj-$(CONFIG_PINCTRL_AXP209) += pinctrl-axp209.o obj-$(CONFIG_PINCTRL_BF54x) += pinctrl-adi2-bf54x.o obj-$(CONFIG_PINCTRL_BF60x) += pinctrl-adi2-bf60x.o obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o diff --git a/drivers/pinctrl/pinctrl-axp209.c b/drivers/pinctrl/pinctrl-axp209.c new file mode 100644 index 000000000000..22d3bb0bf927 --- /dev/null +++ b/drivers/pinctrl/pinctrl-axp209.c @@ -0,0 +1,476 @@ +/* + * AXP20x pinctrl and GPIO driver + * + * Copyright (C) 2016 Maxime Ripard <maxime.ripard@free-electrons.com> + * Copyright (C) 2017 Quentin Schulz <quentin.schulz@free-electrons.com> + * + * 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/device.h> +#include <linux/gpio/driver.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/mfd/axp20x.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/pinctrl/pinconf-generic.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/slab.h> + +#define AXP20X_GPIO_FUNCTIONS 0x7 +#define AXP20X_GPIO_FUNCTION_OUT_LOW 0 +#define AXP20X_GPIO_FUNCTION_OUT_HIGH 1 +#define AXP20X_GPIO_FUNCTION_INPUT 2 + +#define AXP20X_FUNC_GPIO_OUT 0 +#define AXP20X_FUNC_GPIO_IN 1 +#define AXP20X_FUNC_LDO 2 +#define AXP20X_FUNC_ADC 3 +#define AXP20X_FUNCS_NB 4 + +#define AXP20X_MUX_GPIO_OUT 0 +#define AXP20X_MUX_GPIO_IN BIT(1) +#define AXP20X_MUX_ADC BIT(2) + +#define AXP813_MUX_ADC (BIT(2) | BIT(0)) + +struct axp20x_pctrl_desc { + const struct pinctrl_pin_desc *pins; + unsigned int npins; + /* Stores the pins supporting LDO function. Bit offset is pin number. */ + u8 ldo_mask; + /* Stores the pins supporting ADC function. Bit offset is pin number. */ + u8 adc_mask; + u8 gpio_status_offset; + u8 adc_mux; +}; + +struct axp20x_pinctrl_function { + const char *name; + unsigned int muxval; + const char **groups; + unsigned int ngroups; +}; + +struct axp20x_pctl { + struct gpio_chip chip; + struct regmap *regmap; + struct pinctrl_dev *pctl_dev; + struct device *dev; + const struct axp20x_pctrl_desc *desc; + struct axp20x_pinctrl_function funcs[AXP20X_FUNCS_NB]; +}; + +static const struct pinctrl_pin_desc axp209_pins[] = { + PINCTRL_PIN(0, "GPIO0"), + PINCTRL_PIN(1, "GPIO1"), + PINCTRL_PIN(2, "GPIO2"), +}; + +static const struct pinctrl_pin_desc axp813_pins[] = { + PINCTRL_PIN(0, "GPIO0"), + PINCTRL_PIN(1, "GPIO1"), +}; + +static const struct axp20x_pctrl_desc axp20x_data = { + .pins = axp209_pins, + .npins = ARRAY_SIZE(axp209_pins), + .ldo_mask = BIT(0) | BIT(1), + .adc_mask = BIT(0) | BIT(1), + .gpio_status_offset = 4, + .adc_mux = AXP20X_MUX_ADC, +}; + +static const struct axp20x_pctrl_desc axp813_data = { + .pins = axp813_pins, + .npins = ARRAY_SIZE(axp813_pins), + .ldo_mask = BIT(0) | BIT(1), + .adc_mask = BIT(0), + .gpio_status_offset = 0, + .adc_mux = AXP813_MUX_ADC, +}; + +static int axp20x_gpio_get_reg(unsigned int offset) +{ + switch (offset) { + case 0: + return AXP20X_GPIO0_CTRL; + case 1: + return AXP20X_GPIO1_CTRL; + case 2: + return AXP20X_GPIO2_CTRL; + } + + return -EINVAL; +} + +static int axp20x_gpio_input(struct gpio_chip *chip, unsigned int offset) +{ + return pinctrl_gpio_direction_input(chip->base + offset); +} + +static int axp20x_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct axp20x_pctl *pctl = gpiochip_get_data(chip); + unsigned int val; + int ret; + + ret = regmap_read(pctl->regmap, AXP20X_GPIO20_SS, &val); + if (ret) + return ret; + + return !!(val & BIT(offset + pctl->desc->gpio_status_offset)); +} + +static int axp20x_gpio_get_direction(struct gpio_chip *chip, + unsigned int offset) +{ + struct axp20x_pctl *pctl = gpiochip_get_data(chip); + unsigned int val; + int reg, ret; + + reg = axp20x_gpio_get_reg(offset); + if (reg < 0) + return reg; + + ret = regmap_read(pctl->regmap, reg, &val); + if (ret) + return ret; + + /* + * This shouldn't really happen if the pin is in use already, + * or if it's not in use yet, it doesn't matter since we're + * going to change the value soon anyway. Default to output. + */ + if ((val & AXP20X_GPIO_FUNCTIONS) > 2) + return 0; + + /* + * The GPIO directions are the three lowest values. + * 2 is input, 0 and 1 are output + */ + return val & 2; +} + +static int axp20x_gpio_output(struct gpio_chip *chip, unsigned int offset, + int value) +{ + chip->set(chip, offset, value); + + return 0; +} + +static void axp20x_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) +{ + struct axp20x_pctl *pctl = gpiochip_get_data(chip); + int reg; + + reg = axp20x_gpio_get_reg(offset); + if (reg < 0) + return; + + regmap_update_bits(pctl->regmap, reg, + AXP20X_GPIO_FUNCTIONS, + value ? AXP20X_GPIO_FUNCTION_OUT_HIGH : + AXP20X_GPIO_FUNCTION_OUT_LOW); +} + +static int axp20x_pmx_set(struct pinctrl_dev *pctldev, unsigned int offset, + u8 config) +{ + struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev); + int reg; + + reg = axp20x_gpio_get_reg(offset); + if (reg < 0) + return reg; + + return regmap_update_bits(pctl->regmap, reg, AXP20X_GPIO_FUNCTIONS, + config); +} + +static int axp20x_pmx_func_cnt(struct pinctrl_dev *pctldev) +{ + struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev); + + return ARRAY_SIZE(pctl->funcs); +} + +static const char *axp20x_pmx_func_name(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev); + + return pctl->funcs[selector].name; +} + +static int axp20x_pmx_func_groups(struct pinctrl_dev *pctldev, + unsigned int selector, + const char * const **groups, + unsigned int *num_groups) +{ + struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev); + + *groups = pctl->funcs[selector].groups; + *num_groups = pctl->funcs[selector].ngroups; + + return 0; +} + +static int axp20x_pmx_set_mux(struct pinctrl_dev *pctldev, + unsigned int function, unsigned int group) +{ + struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev); + unsigned int mask; + + /* Every pin supports GPIO_OUT and GPIO_IN functions */ + if (function <= AXP20X_FUNC_GPIO_IN) + return axp20x_pmx_set(pctldev, group, + pctl->funcs[function].muxval); + + if (function == AXP20X_FUNC_LDO) + mask = pctl->desc->ldo_mask; + else + mask = pctl->desc->adc_mask; + + if (!(BIT(group) & mask)) + return -EINVAL; + + /* + * We let the regulator framework handle the LDO muxing as muxing bits + * are basically also regulators on/off bits. It's better not to enforce + * any state of the regulator when selecting LDO mux so that we don't + * interfere with the regulator driver. + */ + if (function == AXP20X_FUNC_LDO) + return 0; + + return axp20x_pmx_set(pctldev, group, pctl->funcs[function].muxval); +} + +static int axp20x_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int offset, bool input) +{ + struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev); + + if (input) + return axp20x_pmx_set(pctldev, offset, + pctl->funcs[AXP20X_FUNC_GPIO_IN].muxval); + + return axp20x_pmx_set(pctldev, offset, + pctl->funcs[AXP20X_FUNC_GPIO_OUT].muxval); +} + +static const struct pinmux_ops axp20x_pmx_ops = { + .get_functions_count = axp20x_pmx_func_cnt, + .get_function_name = axp20x_pmx_func_name, + .get_function_groups = axp20x_pmx_func_groups, + .set_mux = axp20x_pmx_set_mux, + .gpio_set_direction = axp20x_pmx_gpio_set_direction, + .strict = true, +}; + +static int axp20x_groups_cnt(struct pinctrl_dev *pctldev) +{ + struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev); + + return pctl->desc->npins; +} + +static int axp20x_group_pins(struct pinctrl_dev *pctldev, unsigned int selector, + const unsigned int **pins, unsigned int *num_pins) +{ + struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev); + + *pins = (unsigned int *)&pctl->desc->pins[selector]; + *num_pins = 1; + + return 0; +} + +static const char *axp20x_group_name(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev); + + return pctl->desc->pins[selector].name; +} + +static const struct pinctrl_ops axp20x_pctrl_ops = { + .dt_node_to_map = pinconf_generic_dt_node_to_map_group, + .dt_free_map = pinconf_generic_dt_free_map, + .get_groups_count = axp20x_groups_cnt, + .get_group_name = axp20x_group_name, + .get_group_pins = axp20x_group_pins, +}; + +static void axp20x_funcs_groups_from_mask(struct device *dev, unsigned int mask, + unsigned int mask_len, + struct axp20x_pinctrl_function *func, + const struct pinctrl_pin_desc *pins) +{ + unsigned long int mask_cpy = mask; + const char **group; + unsigned int ngroups = hweight8(mask); + int bit; + + func->ngroups = ngroups; + if (func->ngroups > 0) { + func->groups = devm_kzalloc(dev, ngroups * sizeof(const char *), + GFP_KERNEL); + group = func->groups; + for_each_set_bit(bit, &mask_cpy, mask_len) { + *group = pins[bit].name; + group++; + } + } +} + +static void axp20x_build_funcs_groups(struct platform_device *pdev) +{ + struct axp20x_pctl *pctl = platform_get_drvdata(pdev); + int i, pin, npins = pctl->desc->npins; + + pctl->funcs[AXP20X_FUNC_GPIO_OUT].name = "gpio_out"; + pctl->funcs[AXP20X_FUNC_GPIO_OUT].muxval = AXP20X_MUX_GPIO_OUT; + pctl->funcs[AXP20X_FUNC_GPIO_IN].name = "gpio_in"; + pctl->funcs[AXP20X_FUNC_GPIO_IN].muxval = AXP20X_MUX_GPIO_IN; + pctl->funcs[AXP20X_FUNC_LDO].name = "ldo"; + /* + * Muxval for LDO is useless as we won't use it. + * See comment in axp20x_pmx_set_mux. + */ + pctl->funcs[AXP20X_FUNC_ADC].name = "adc"; + pctl->funcs[AXP20X_FUNC_ADC].muxval = pctl->desc->adc_mux; + + /* Every pin supports GPIO_OUT and GPIO_IN functions */ + for (i = 0; i <= AXP20X_FUNC_GPIO_IN; i++) { + pctl->funcs[i].ngroups = npins; + pctl->funcs[i].groups = devm_kzalloc(&pdev->dev, + npins * sizeof(char *), + GFP_KERNEL); + for (pin = 0; pin < npins; pin++) + pctl->funcs[i].groups[pin] = pctl->desc->pins[pin].name; + } + + axp20x_funcs_groups_from_mask(&pdev->dev, pctl->desc->ldo_mask, + npins, &pctl->funcs[AXP20X_FUNC_LDO], + pctl->desc->pins); + + axp20x_funcs_groups_from_mask(&pdev->dev, pctl->desc->adc_mask, + npins, &pctl->funcs[AXP20X_FUNC_ADC], + pctl->desc->pins); +} + +static const struct of_device_id axp20x_pctl_match[] = { + { .compatible = "x-powers,axp209-gpio", .data = &axp20x_data, }, + { .compatible = "x-powers,axp813-gpio", .data = &axp813_data, }, + { } +}; +MODULE_DEVICE_TABLE(of, axp20x_pctl_match); + +static int axp20x_pctl_probe(struct platform_device *pdev) +{ + struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); + struct axp20x_pctl *pctl; + struct device *dev = &pdev->dev; + struct pinctrl_desc *pctrl_desc; + int ret; + + if (!of_device_is_available(pdev->dev.of_node)) + return -ENODEV; + + if (!axp20x) { + dev_err(&pdev->dev, "Parent drvdata not set\n"); + return -EINVAL; + } + + pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL); + if (!pctl) + return -ENOMEM; + + pctl->chip.base = -1; + pctl->chip.can_sleep = true; + pctl->chip.request = gpiochip_generic_request; + pctl->chip.free = gpiochip_generic_free; + pctl->chip.parent = &pdev->dev; + pctl->chip.label = dev_name(&pdev->dev); + pctl->chip.owner = THIS_MODULE; + pctl->chip.get = axp20x_gpio_get; + pctl->chip.get_direction = axp20x_gpio_get_direction; + pctl->chip.set = axp20x_gpio_set; + pctl->chip.direction_input = axp20x_gpio_input; + pctl->chip.direction_output = axp20x_gpio_output; + pctl->chip.ngpio = pctl->desc->npins; + + pctl->desc = (struct axp20x_pctrl_desc *)of_device_get_match_data(dev); + pctl->regmap = axp20x->regmap; + pctl->dev = &pdev->dev; + + platform_set_drvdata(pdev, pctl); + + axp20x_build_funcs_groups(pdev); + + pctrl_desc = devm_kzalloc(&pdev->dev, sizeof(*pctrl_desc), GFP_KERNEL); + if (!pctrl_desc) + return -ENOMEM; + + pctrl_desc->name = dev_name(&pdev->dev); + pctrl_desc->owner = THIS_MODULE; + pctrl_desc->pins = pctl->desc->pins; + pctrl_desc->npins = pctl->desc->npins; + pctrl_desc->pctlops = &axp20x_pctrl_ops; + pctrl_desc->pmxops = &axp20x_pmx_ops; + + pctl->pctl_dev = devm_pinctrl_register(&pdev->dev, pctrl_desc, pctl); + if (IS_ERR(pctl->pctl_dev)) { + dev_err(&pdev->dev, "couldn't register pinctrl driver\n"); + return PTR_ERR(pctl->pctl_dev); + } + + ret = devm_gpiochip_add_data(&pdev->dev, &pctl->chip, pctl); + if (ret) { + dev_err(&pdev->dev, "Failed to register GPIO chip\n"); + return ret; + } + + ret = gpiochip_add_pin_range(&pctl->chip, dev_name(&pdev->dev), + pctl->desc->pins->number, + pctl->desc->pins->number, + pctl->desc->npins); + if (ret) { + dev_err(&pdev->dev, "failed to add pin range\n"); + return ret; + } + + dev_info(&pdev->dev, "AXP209 pinctrl and GPIO driver loaded\n"); + + return 0; +} + +static struct platform_driver axp20x_pctl_driver = { + .probe = axp20x_pctl_probe, + .driver = { + .name = "axp20x-gpio", + .of_match_table = axp20x_pctl_match, + }, +}; + +module_platform_driver(axp20x_pctl_driver); + +MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>"); +MODULE_AUTHOR("Quentin Schulz <quentin.schulz@free-electrons.com>"); +MODULE_DESCRIPTION("AXP20x PMIC pinctrl and GPIO driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c index a90728ceec5a..55e11bf8ebaf 100644 --- a/drivers/w1/masters/w1-gpio.c +++ b/drivers/w1/masters/w1-gpio.c @@ -13,9 +13,8 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/w1-gpio.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/of_platform.h> -#include <linux/of_gpio.h> #include <linux/err.h> #include <linux/of.h> #include <linux/delay.h> @@ -30,11 +29,17 @@ static u8 w1_gpio_set_pullup(void *data, int delay) pdata->pullup_duration = delay; } else { if (pdata->pullup_duration) { - gpio_direction_output(pdata->pin, 1); - + /* + * This will OVERRIDE open drain emulation and force-pull + * the line high for some time. + */ + gpiod_set_raw_value(pdata->gpiod, 1); msleep(pdata->pullup_duration); - - gpio_direction_input(pdata->pin); + /* + * This will simply set the line as input since we are doing + * open drain emulation in the GPIO library. + */ + gpiod_set_value(pdata->gpiod, 1); } pdata->pullup_duration = 0; } @@ -42,28 +47,18 @@ static u8 w1_gpio_set_pullup(void *data, int delay) return 0; } -static void w1_gpio_write_bit_dir(void *data, u8 bit) -{ - struct w1_gpio_platform_data *pdata = data; - - if (bit) - gpio_direction_input(pdata->pin); - else - gpio_direction_output(pdata->pin, 0); -} - -static void w1_gpio_write_bit_val(void *data, u8 bit) +static void w1_gpio_write_bit(void *data, u8 bit) { struct w1_gpio_platform_data *pdata = data; - gpio_set_value(pdata->pin, bit); + gpiod_set_value(pdata->gpiod, bit); } static u8 w1_gpio_read_bit(void *data) { struct w1_gpio_platform_data *pdata = data; - return gpio_get_value(pdata->pin) ? 1 : 0; + return gpiod_get_value(pdata->gpiod) ? 1 : 0; } #if defined(CONFIG_OF) @@ -74,107 +69,85 @@ static const struct of_device_id w1_gpio_dt_ids[] = { MODULE_DEVICE_TABLE(of, w1_gpio_dt_ids); #endif -static int w1_gpio_probe_dt(struct platform_device *pdev) -{ - struct w1_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev); - struct device_node *np = pdev->dev.of_node; - int gpio; - - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) - return -ENOMEM; - - if (of_get_property(np, "linux,open-drain", NULL)) - pdata->is_open_drain = 1; - - gpio = of_get_gpio(np, 0); - if (gpio < 0) { - if (gpio != -EPROBE_DEFER) - dev_err(&pdev->dev, - "Failed to parse gpio property for data pin (%d)\n", - gpio); - - return gpio; - } - pdata->pin = gpio; - - gpio = of_get_gpio(np, 1); - if (gpio == -EPROBE_DEFER) - return gpio; - /* ignore other errors as the pullup gpio is optional */ - pdata->ext_pullup_enable_pin = gpio; - - pdev->dev.platform_data = pdata; - - return 0; -} - static int w1_gpio_probe(struct platform_device *pdev) { struct w1_bus_master *master; struct w1_gpio_platform_data *pdata; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + /* Enforce open drain mode by default */ + enum gpiod_flags gflags = GPIOD_OUT_LOW_OPEN_DRAIN; int err; if (of_have_populated_dt()) { - err = w1_gpio_probe_dt(pdev); - if (err < 0) - return err; + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + /* + * This parameter means that something else than the gpiolib has + * already set the line into open drain mode, so we should just + * driver it high/low like we are in full control of the line and + * open drain will happen transparently. + */ + if (of_get_property(np, "linux,open-drain", NULL)) + gflags = GPIOD_OUT_LOW; + + pdev->dev.platform_data = pdata; } - - pdata = dev_get_platdata(&pdev->dev); + pdata = dev_get_platdata(dev); if (!pdata) { - dev_err(&pdev->dev, "No configuration data\n"); + dev_err(dev, "No configuration data\n"); return -ENXIO; } - master = devm_kzalloc(&pdev->dev, sizeof(struct w1_bus_master), + master = devm_kzalloc(dev, sizeof(struct w1_bus_master), GFP_KERNEL); if (!master) { - dev_err(&pdev->dev, "Out of memory\n"); + dev_err(dev, "Out of memory\n"); return -ENOMEM; } - err = devm_gpio_request(&pdev->dev, pdata->pin, "w1"); - if (err) { - dev_err(&pdev->dev, "gpio_request (pin) failed\n"); - return err; + pdata->gpiod = devm_gpiod_get_index(dev, NULL, 0, gflags); + if (IS_ERR(pdata->gpiod)) { + dev_err(dev, "gpio_request (pin) failed\n"); + return PTR_ERR(pdata->gpiod); } - if (gpio_is_valid(pdata->ext_pullup_enable_pin)) { - err = devm_gpio_request_one(&pdev->dev, - pdata->ext_pullup_enable_pin, GPIOF_INIT_LOW, - "w1 pullup"); - if (err < 0) { - dev_err(&pdev->dev, "gpio_request_one " - "(ext_pullup_enable_pin) failed\n"); - return err; - } + pdata->pullup_gpiod = + devm_gpiod_get_index_optional(dev, NULL, 1, GPIOD_OUT_LOW); + if (IS_ERR(pdata->pullup_gpiod)) { + dev_err(dev, "gpio_request_one " + "(ext_pullup_enable_pin) failed\n"); + return PTR_ERR(pdata->pullup_gpiod); } master->data = pdata; master->read_bit = w1_gpio_read_bit; - - if (pdata->is_open_drain) { - gpio_direction_output(pdata->pin, 1); - master->write_bit = w1_gpio_write_bit_val; - } else { - gpio_direction_input(pdata->pin); - master->write_bit = w1_gpio_write_bit_dir; + gpiod_direction_output(pdata->gpiod, 1); + master->write_bit = w1_gpio_write_bit; + + /* + * If we are using open drain emulation from the GPIO library, + * we need to use this pullup function that hammers the line + * high using a raw accessor to provide pull-up for the w1 + * line. + */ + if (gflags == GPIOD_OUT_LOW_OPEN_DRAIN) master->set_pullup = w1_gpio_set_pullup; - } err = w1_add_master_device(master); if (err) { - dev_err(&pdev->dev, "w1_add_master device failed\n"); + dev_err(dev, "w1_add_master device failed\n"); return err; } if (pdata->enable_external_pullup) pdata->enable_external_pullup(1); - if (gpio_is_valid(pdata->ext_pullup_enable_pin)) - gpio_set_value(pdata->ext_pullup_enable_pin, 1); + if (pdata->pullup_gpiod) + gpiod_set_value(pdata->pullup_gpiod, 1); platform_set_drvdata(pdev, master); @@ -189,8 +162,8 @@ static int w1_gpio_remove(struct platform_device *pdev) if (pdata->enable_external_pullup) pdata->enable_external_pullup(0); - if (gpio_is_valid(pdata->ext_pullup_enable_pin)) - gpio_set_value(pdata->ext_pullup_enable_pin, 0); + if (pdata->pullup_gpiod) + gpiod_set_value(pdata->pullup_gpiod, 0); w1_remove_master_device(master); diff --git a/include/dt-bindings/gpio/gpio.h b/include/dt-bindings/gpio/gpio.h index dd549ff04295..2cc10ae4bbb7 100644 --- a/include/dt-bindings/gpio/gpio.h +++ b/include/dt-bindings/gpio/gpio.h @@ -29,8 +29,8 @@ #define GPIO_OPEN_DRAIN (GPIO_SINGLE_ENDED | GPIO_LINE_OPEN_DRAIN) #define GPIO_OPEN_SOURCE (GPIO_SINGLE_ENDED | GPIO_LINE_OPEN_SOURCE) -/* Bit 3 express GPIO suspend/resume persistence */ -#define GPIO_SLEEP_MAINTAIN_VALUE 0 -#define GPIO_SLEEP_MAY_LOSE_VALUE 8 +/* Bit 3 express GPIO suspend/resume and reset persistence */ +#define GPIO_PERSISTENT 0 +#define GPIO_TRANSITORY 8 #endif diff --git a/include/linux/acpi.h b/include/linux/acpi.h index a933f87ef98d..f0ea50ba0550 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -991,6 +991,11 @@ struct acpi_gpio_mapping { const char *name; const struct acpi_gpio_params *data; unsigned int size; + +/* Ignore IoRestriction field */ +#define ACPI_GPIO_QUIRK_NO_IO_RESTRICTION BIT(0) + + unsigned int quirks; }; #if defined(CONFIG_ACPI) && defined(CONFIG_GPIOLIB) diff --git a/include/linux/device.h b/include/linux/device.h index 9d32000725da..46ac622e5c6f 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -575,6 +575,9 @@ ssize_t device_store_bool(struct device *dev, struct device_attribute *attr, #define DEVICE_ATTR(_name, _mode, _show, _store) \ struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store) +#define DEVICE_ATTR_PREALLOC(_name, _mode, _show, _store) \ + struct device_attribute dev_attr_##_name = \ + __ATTR_PREALLOC(_name, _mode, _show, _store) #define DEVICE_ATTR_RW(_name) \ struct device_attribute dev_attr_##_name = __ATTR_RW(_name) #define DEVICE_ATTR_RO(_name) \ diff --git a/include/linux/gpio.h b/include/linux/gpio.h index 8ef7fc0ce0f0..91ed23468530 100644 --- a/include/linux/gpio.h +++ b/include/linux/gpio.h @@ -1,4 +1,14 @@ /* SPDX-License-Identifier: GPL-2.0 */ +/* + * <linux/gpio.h> + * + * This is the LEGACY GPIO bulk include file, including legacy APIs. It is + * used for GPIO drivers still referencing the global GPIO numberspace, + * and should not be included in new code. + * + * If you're implementing a GPIO driver, only include <linux/gpio/driver.h> + * If you're implementing a GPIO consumer, only include <linux/gpio/consumer.h> + */ #ifndef __LINUX_GPIO_H #define __LINUX_GPIO_H diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h index 7447d85dbe2f..dbd065963296 100644 --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h @@ -139,6 +139,7 @@ void gpiod_set_raw_array_value_cansleep(unsigned int array_size, int *value_array); int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce); +int gpiod_set_transitory(struct gpio_desc *desc, bool transitory); int gpiod_is_active_low(const struct gpio_desc *desc); int gpiod_cansleep(const struct gpio_desc *desc); @@ -150,8 +151,14 @@ struct gpio_desc *gpio_to_desc(unsigned gpio); int desc_to_gpio(const struct gpio_desc *desc); /* Child properties interface */ +struct device_node; struct fwnode_handle; +struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev, + struct device_node *node, + const char *propname, int index, + enum gpiod_flags dflags, + const char *label); struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, const char *propname, int index, enum gpiod_flags dflags, @@ -431,6 +438,13 @@ static inline int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) return -ENOSYS; } +static inline int gpiod_set_transitory(struct gpio_desc *desc, bool transitory) +{ + /* GPIO can never have been requested */ + WARN_ON(1); + return -ENOSYS; +} + static inline int gpiod_is_active_low(const struct gpio_desc *desc) { /* GPIO can never have been requested */ @@ -464,9 +478,20 @@ static inline int desc_to_gpio(const struct gpio_desc *desc) } /* Child properties interface */ +struct device_node; struct fwnode_handle; static inline +struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev, + struct device_node *node, + const char *propname, int index, + enum gpiod_flags dflags, + const char *label) +{ + return ERR_PTR(-ENOSYS); +} + +static inline struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, const char *propname, int index, enum gpiod_flags dflags, diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 7258cd676df4..1ba9a331ec51 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -436,6 +436,9 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip, struct lock_class_key *lock_key, struct lock_class_key *request_key); +bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip, + unsigned int offset); + #ifdef CONFIG_LOCKDEP /* diff --git a/include/linux/gpio/machine.h b/include/linux/gpio/machine.h index 846be7c69a52..b2f2dc638463 100644 --- a/include/linux/gpio/machine.h +++ b/include/linux/gpio/machine.h @@ -10,8 +10,8 @@ enum gpio_lookup_flags { GPIO_ACTIVE_LOW = (1 << 0), GPIO_OPEN_DRAIN = (1 << 1), GPIO_OPEN_SOURCE = (1 << 2), - GPIO_SLEEP_MAINTAIN_VALUE = (0 << 3), - GPIO_SLEEP_MAY_LOSE_VALUE = (1 << 3), + GPIO_PERSISTENT = (0 << 3), + GPIO_TRANSITORY = (1 << 3), }; /** diff --git a/include/linux/of_gpio.h b/include/linux/of_gpio.h index 1fe205582111..18a7f03e1182 100644 --- a/include/linux/of_gpio.h +++ b/include/linux/of_gpio.h @@ -31,7 +31,7 @@ enum of_gpio_flags { OF_GPIO_ACTIVE_LOW = 0x1, OF_GPIO_SINGLE_ENDED = 0x2, OF_GPIO_OPEN_DRAIN = 0x4, - OF_GPIO_SLEEP_MAY_LOSE_VALUE = 0x8, + OF_GPIO_TRANSITORY = 0x8, }; #ifdef CONFIG_OF_GPIO diff --git a/include/linux/pinctrl/pinconf-generic.h b/include/linux/pinctrl/pinconf-generic.h index ec6dadcc1fde..6c0680641108 100644 --- a/include/linux/pinctrl/pinconf-generic.h +++ b/include/linux/pinctrl/pinconf-generic.h @@ -94,6 +94,7 @@ * or latch delay (on outputs) this parameter (in a custom format) * specifies the clock skew or latch delay. It typically controls how * many double inverters are put in front of the line. + * @PIN_CONFIG_PERSIST_STATE: retain pin state across sleep or controller reset * @PIN_CONFIG_END: this is the last enumerator for pin configurations, if * you need to pass in custom configurations to the pin controller, use * PIN_CONFIG_END+1 as the base offset. @@ -122,6 +123,7 @@ enum pin_config_param { PIN_CONFIG_SLEEP_HARDWARE_STATE, PIN_CONFIG_SLEW_RATE, PIN_CONFIG_SKEW_DELAY, + PIN_CONFIG_PERSIST_STATE, PIN_CONFIG_END = 0x7F, PIN_CONFIG_MAX = 0xFF, }; diff --git a/include/linux/w1-gpio.h b/include/linux/w1-gpio.h index d58594a32324..78901ecd2f95 100644 --- a/include/linux/w1-gpio.h +++ b/include/linux/w1-gpio.h @@ -10,16 +10,15 @@ #ifndef _LINUX_W1_GPIO_H #define _LINUX_W1_GPIO_H +struct gpio_desc; + /** * struct w1_gpio_platform_data - Platform-dependent data for w1-gpio - * @pin: GPIO pin to use - * @is_open_drain: GPIO pin is configured as open drain */ struct w1_gpio_platform_data { - unsigned int pin; - unsigned int is_open_drain:1; + struct gpio_desc *gpiod; + struct gpio_desc *pullup_gpiod; void (*enable_external_pullup)(int enable); - unsigned int ext_pullup_enable_pin; unsigned int pullup_duration; }; diff --git a/tools/gpio/gpio-event-mon.c b/tools/gpio/gpio-event-mon.c index 1c14c2595158..dac4d4131d9b 100644 --- a/tools/gpio/gpio-event-mon.c +++ b/tools/gpio/gpio-event-mon.c @@ -14,6 +14,7 @@ #include <unistd.h> #include <stdlib.h> #include <stdbool.h> +#include <stdint.h> #include <stdio.h> #include <dirent.h> #include <errno.h> @@ -23,12 +24,13 @@ #include <getopt.h> #include <inttypes.h> #include <sys/ioctl.h> +#include <sys/types.h> #include <linux/gpio.h> int monitor_device(const char *device_name, unsigned int line, - u_int32_t handleflags, - u_int32_t eventflags, + uint32_t handleflags, + uint32_t eventflags, unsigned int loops) { struct gpioevent_request req; @@ -145,8 +147,8 @@ int main(int argc, char **argv) const char *device_name = NULL; unsigned int line = -1; unsigned int loops = 0; - u_int32_t handleflags = GPIOHANDLE_REQUEST_INPUT; - u_int32_t eventflags = 0; + uint32_t handleflags = GPIOHANDLE_REQUEST_INPUT; + uint32_t eventflags = 0; int c; while ((c = getopt(argc, argv, "c:n:o:dsrf?")) != -1) { |