]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
Merge tag 'gpio-v4.16-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 31 Jan 2018 20:25:27 +0000 (12:25 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 31 Jan 2018 20:25:27 +0000 (12:25 -0800)
Pull GPIO updates from Linus Walleij:
 "The is the bulk of GPIO changes for the v4.16 kernel cycle. It is
  pretty calm this time around I think. I even got time to get to things
  like starting to clean up header includes.

  Core changes:

   - Disallow open drain and open source flags to be set simultaneously.
     This doesn't make electrical sense, and would the hardware actually
     respond to this setting, the result would be short circuit.

   - ACPI GPIO has a new core infrastructure for handling quirks. The
     quirks are there to deal with broken ACPI tables centrally instead
     of pushing the work to individual drivers. In the world of BIOS
     writers, the ACPI tables are perfect. Until they find a mistake in
     it. When such a mistake is found, we can patch it with a quirk. It
     should never happen, the problem is that it happens. So we
     accomodate for it.

   - Several documentation updates.

   - Revert the patch setting up initial direction state from reading
     the device. This was causing bad things for drivers that can't read
     status on all its pins. It is only affecting debugfs information
     quality.

   - Label descriptors with the device name if no explicit label is
     passed in.

   - Pave the ground for transitioning SPI and regulators to use GPIO
     descriptors by implementing some quirks in the device tree GPIO
     parsing code.

  New drivers:

   - New driver for the Access PCIe IDIO 24 family.

  Other:

   - Major refactorings and improvements to the GPIO mockup driver used
     for test and verification.

   - Moved the AXP209 driver over to pin control since it gained a pin
     control back-end. These patches will appear (with the same hashes)
     in the pin control pull request as well.

   - Convert the onewire GPIO driver w1-gpio to use descriptors. This is
     merged here since the W1 maintainers send very few pull requests
     and he ACKed it.

   - Start to clean up driver headers using <linux/gpio.h> to just use
     <linux/gpio/driver.h> as appropriate"

* tag 'gpio-v4.16-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (103 commits)
  gpio: Timestamp events in hardirq handler
  gpio: Fix kernel stack leak to userspace
  gpio: Fix a documentation spelling mistake
  gpio: Documentation update
  gpiolib: remove redundant initialization of pointer desc
  gpio: of: Fix NPE from OF flags
  gpio: stmpe: Delete an unnecessary variable initialisation in stmpe_gpio_probe()
  gpio: stmpe: Move an assignment in stmpe_gpio_probe()
  gpio: stmpe: Improve a size determination in stmpe_gpio_probe()
  gpio: stmpe: Use seq_putc() in stmpe_dbg_show()
  gpio: No NULL owner
  gpio: stmpe: i2c transfer are forbiden in atomic context
  gpio: davinci: Include proper header
  gpio: da905x: Include proper header
  gpio: cs5535: Include proper header
  gpio: crystalcove: Include proper header
  gpio: bt8xx: Include proper header
  gpio: bcm-kona: Include proper header
  gpio: arizona: Include proper header
  gpio: amd8111: Include proper header
  ...

60 files changed:
Documentation/devicetree/bindings/gpio/gpio-axp209.txt
Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt
Documentation/gpio/board.txt
Documentation/gpio/consumer.txt
Documentation/gpio/driver.txt
Documentation/gpio/sysfs.txt
Documentation/w1/masters/w1-gpio
MAINTAINERS
arch/arm/mach-ixp4xx/vulcan-setup.c
arch/arm/mach-pxa/raumfeld.c
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/devres.c
drivers/gpio/gpio-74x164.c
drivers/gpio/gpio-adp5520.c
drivers/gpio/gpio-adp5588.c
drivers/gpio/gpio-altera.c
drivers/gpio/gpio-amd8111.c
drivers/gpio/gpio-arizona.c
drivers/gpio/gpio-aspeed.c
drivers/gpio/gpio-ath79.c
drivers/gpio/gpio-axp209.c [deleted file]
drivers/gpio/gpio-bcm-kona.c
drivers/gpio/gpio-brcmstb.c
drivers/gpio/gpio-bt8xx.c
drivers/gpio/gpio-crystalcove.c
drivers/gpio/gpio-cs5535.c
drivers/gpio/gpio-da9052.c
drivers/gpio/gpio-da9055.c
drivers/gpio/gpio-davinci.c
drivers/gpio/gpio-ftgpio010.c
drivers/gpio/gpio-iop.c
drivers/gpio/gpio-it87.c
drivers/gpio/gpio-max732x.c
drivers/gpio/gpio-mockup.c
drivers/gpio/gpio-omap.c
drivers/gpio/gpio-pcie-idio-24.c [new file with mode: 0644]
drivers/gpio/gpio-stmpe.c
drivers/gpio/gpio-thunderx.c
drivers/gpio/gpio-winbond.c [new file with mode: 0644]
drivers/gpio/gpiolib-acpi.c
drivers/gpio/gpiolib-of.c
drivers/gpio/gpiolib-sysfs.c
drivers/gpio/gpiolib.c
drivers/gpio/gpiolib.h
drivers/pinctrl/Kconfig
drivers/pinctrl/Makefile
drivers/pinctrl/pinctrl-axp209.c [new file with mode: 0644]
drivers/w1/masters/w1-gpio.c
include/dt-bindings/gpio/gpio.h
include/linux/acpi.h
include/linux/device.h
include/linux/gpio.h
include/linux/gpio/consumer.h
include/linux/gpio/driver.h
include/linux/gpio/machine.h
include/linux/of_gpio.h
include/linux/pinctrl/pinconf-generic.h
include/linux/w1-gpio.h
tools/gpio/gpio-event-mon.c

index a6611304dd3c3d5545d76bc4b804bdd937f793d8..fc42b2caa06d7c88da09eb5d8553f338e62db8de 100644 (file)
@@ -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
index a7ac460ad6572526023f9a88b6b741fb20ba59e9..9474138d776ed58da02dd925105dd89daa3c6cb4 100644 (file)
@@ -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.
index a0f61898d493b720fbc014554b628f5b6e25a93f..659bb19f5b3c7affb6edbcd2eee76f09396876ca 100644 (file)
@@ -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.
 
index 63e1bd1d88e324defd01d1ed1fddac5952629d55..d53e5b5cfc9cb65040f35631d23fc36f7f166f89 100644 (file)
@@ -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
index d8de1c7de85a748b266cc2329af8af31d4fbf3f6..3392a0fd4c23c817758bd94b763022ff9cf3e309 100644 (file)
@@ -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
 ---------------------------
index aeab01aa4d00951cd1d37c00ff8fbfb3eb9b1e75..6cdeab8650cdbd20a75fed859ef1b7f9f942fdf0 100644 (file)
@@ -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
index af5d3b4aa851501da0687d6414c0f070c574a7aa..623961d9e83fd80a0a3cf4dd39de8bbef8ff605e 100644 (file)
@@ -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);
index 88cdd2925cefc76d1db7498a2f05657d2e4728d3..e26e4c7a5454ed57a610b06e7d6796021f53888d 100644 (file)
@@ -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
index 731fb2019ecb84be4e268ff6fcb9a967b8217563..2c03d2f6b6479b2b1423e347b1b69998e65810a9 100644 (file)
@@ -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));
 }
 
index 9d662fed03ec7ae7fbf05bd22775185b00e571b6..feddca7f3540e4b41e9075425dd2cfe5f0e335f3 100644 (file)
@@ -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);
 }
 
index d6a8e851ad13b8e6e5c0761474d26a8725770c83..8dbb2280538d9b1e7c83bde34c3b2b2396ed3fac 100644 (file)
@@ -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
index 4bc24febb889fc8d40eef21c353181a40b178755..cccb0d40846c174028feeeeb423c67f1d919be11 100644 (file)
@@ -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
index afbff155a0ba5629ee66fb1bdef7776da432d05a..e82cc763633cac5de63f7c1b77ddfe14daf39b9a 100644 (file)
@@ -124,6 +124,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
index 15a1f4b348c41b2915755dba173d71704a862768..fb7b620763a257658ddd60e5fd0c203248965f4d 100644 (file)
@@ -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>
 
index abf1996095465d6be5f8ec4caccbbcfaf1af1066..21452622d954249e9b46423234bb14acbe535329 100644 (file)
@@ -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;
index e717f8dc39667c8839e85aedd910ae1c34007782..3530ccd17e04487153cb5d1cff0b9796ca38673a 100644 (file)
@@ -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>
 
index 8e76d390e65388b57865b46daa535679033696d9..8c3ff6e2366fe974e6aa6242964b583d59924282 100644 (file)
@@ -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
index 30ad7d7c167801548b91e96af8a08b9e3d33ca10..fdcebe59510dd798c651993a4b805439cdd7a2b1 100644 (file)
@@ -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>
 
index d4e6ba0301bc317b3bf3d6c9fbd767efb93b32fd..ba51ea15f379490a70380a7f7878e08661fb6ad3 100644 (file)
@@ -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>
index 6b3ca6601af2dd8b1a38fa688e913726873fe82d..77e485557498329193fd291194cc037de55c8160 100644 (file)
@@ -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;
 }
index 5fad89dfab7ef57b8293930c5ae9fb0637a424a6..3ae7c1876bf4c0ad64a4a5392c11999c585a2e21 100644 (file)
@@ -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 (file)
index 4a346b7..0000000
+++ /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");
index 76861a00bb92c4b449f346433f282da8e6cb82c9..eb8369b21e9074d65599c1cafbc37e05a35e12d9 100644 (file)
@@ -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);
index bb4f8cf18bd9f6c7e47328aaf2ec1cdd3dfc3d6b..16c7f9f4941644b64c8fa71f4b0b2c7393e99b6a 100644 (file)
@@ -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,
index acefb25e8eca43b46bc9f4a97286b030d6b0959a..b8ec75cbd4b53cf34ded259d652f410946d41904 100644 (file)
@@ -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. */
index b6f0f729656c2968a8d48906e85b31db7c03fbde..58531d8b8c6e4e1f12037a3e99fa725da43349d1 100644 (file)
@@ -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>
index 90278b19aa0e27574528d055e773b716ad5dd134..8814c8f47e575c657efe4c5094bb0c0b6016028f 100644 (file)
@@ -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>
index dd8977cf3e854fae4259d01e89a1bbf62e0b3ff2..b6d3e997eb261ac4e76cb09f90897b95e5f510b1 100644 (file)
@@ -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>
 
index 82053b52cba03d7cb998ca4ed38f3b243b255c7a..2f1b5d23b10ca3708dd624eabbcfdd44e497ee06 100644 (file)
@@ -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>
index e4b3d7db68c95a2d87b9766e54f688fe2dd13f36..0b951ca78ec40c529b3df803249152d251d1e823 100644 (file)
@@ -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>
index 7b3394fdc624d17d24628f8a184dd6386b86ad87..b7a3a2db699b76c6abb2df04a6e28e23b3875d88 100644 (file)
@@ -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,
index 98c7ff2a76e76a24194f2c3278af42f5d5c4ff9c..8d62db447ec1baff473836ee75b33fdda64c2d7d 100644 (file)
@@ -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");
index d43d0a2cc4c5c0b73b75cf6f1d367b3d6c136014..efb46edff81fb2e5c9225195017160c2ebfbf7dd 100644 (file)
@@ -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Ã\83² <flameeyes@flameeyes.eu>");
+MODULE_AUTHOR("Diego Elio Pettenò <flameeyes@flameeyes.eu>");
 MODULE_DESCRIPTION("GPIO interface for IT87xx Super I/O chips");
 MODULE_LICENSE("GPL");
index c04fae1ba32a42d66d27f619bd616acb7862a9ab..9d8bcc69f2454439feb901bfa7274651d3fbbcb1 100644 (file)
@@ -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;
 }
index 9532d86a82f7c8595a0a7fe0e7222937fde15acf..3a545ad1781744ac3b92f2dc49a161ec479740e1 100644 (file)
 #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>");
index e136d666f1e5bfa913c155cb323549812916c27e..ab5035b968866ef8d6892d67816292582557bfe5 100644 (file)
@@ -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 (file)
index 0000000..f666e2e
--- /dev/null
@@ -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");
index e6e5cca624a7d8c9b733134c2c4276b89b98db94..f8d7d1cd8488ebe0a905b15ce69870003018ac06 100644 (file)
@@ -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: "
index b5adb79a631a6d88b3921d5210ddf72bc26a4c59..d16e9d4a129bdd86874305d3d443b9eed9f9df7f 100644 (file)
@@ -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 (file)
index 0000000..7f8f5b0
--- /dev/null
@@ -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, &params.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, &params.gpios, BITS_PER_LONG)
+               if (!winbond_gpio_configure_port(base, i))
+                       __clear_bit(i, &params.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, &params.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");
index d6f3d9ee1350e422e3f373427d55d6ce8b6be565..0ecffd172a80045722aa9a0fa2b6facdc0292e38 100644 (file)
@@ -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;
 }
 
index 72a0695d2ac3a3d3217462ff4ea85147921f5dcd..564bb7a31da43b4e924daf7501c36ec9a4eb8fc2 100644 (file)
@@ -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;
index 3f454eaf2101fcce2da580216ba8932d31ce70f3..3dbaf489a8a52146aacdf2dbec23af18f5bb3b0a 100644 (file)
@@ -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)
index 5d6e8bb38ac717fe75e8eb10be6ac3ecbf7e8ee9..36ca5064486e88acb70390480a83be85e3615bb0 100644 (file)
@@ -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 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
  * @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 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
        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 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label)
  * 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),
@@ -2529,6 +2541,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);
 
@@ -3649,18 +3712,89 @@ 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);
index 6c44d165213910a259ee94c85731ab4d1ca68431..b17ec6795c81e921460b4b33fd5c2889ebbf797b 100644 (file)
@@ -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;
index 4571cc098b7628961c6b27682e1fdf238a8bcb82..ce126955212ccbe716d4990f2d540f68a9d8524c 100644 (file)
@@ -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
index d0d4844f80221689d5378cdde1ba0797d9429d6b..4777f1595ce203681cb466c828dcf760d21971f0 100644 (file)
@@ -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 (file)
index 0000000..22d3bb0
--- /dev/null
@@ -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");
index a90728ceec5ad8968489021f9da44e161f399998..55e11bf8ebaf37732c6566aec0ee1e335e9cfdb9 100644 (file)
@@ -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);
 
index dd549ff04295367d22d8f75696cf02c0066b6a20..2cc10ae4bbb7ba29bb7503992e1bd5c0036acc27 100644 (file)
@@ -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
index a933f87ef98d54100e25e71985cfb8e16c62c06e..f0ea50ba0550ded8c74d846267b544fcb42c20b5 100644 (file)
@@ -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)
index 9d32000725da8452fdac148700c16315715bec07..46ac622e5c6ffa7c41eb08e0a8b26786cdb2c443 100644 (file)
@@ -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) \
index 8ef7fc0ce0f0cb408bf04a9a01cea0eb2309815b..91ed23468530d3a7df959fc2e99a501e78c231f1 100644 (file)
@@ -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
 
index 7447d85dbe2f8f387d282c83e11da308895f7f14..dbd06596329661dee0a84170c0bdf2fc4b7d853a 100644 (file)
@@ -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,8 +478,19 @@ 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,
index 7258cd676df42c3ea77700d1a6ed15e7957e4f37..1ba9a331ec515d5a26d994eb512fa712db3f6b15 100644 (file)
@@ -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
 
 /*
index 846be7c69a52bd6a59c877208befe4efbfd58c77..b2f2dc638463ce9da4c0fc0feaf8f391d11927d3 100644 (file)
@@ -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),
 };
 
 /**
index 1fe205582111489d4efac1cce323a06ab404212c..18a7f03e11826ff545bc979f99983f5eaabbaa9e 100644 (file)
@@ -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
index ec6dadcc1fde81cd2ef36d6a055c499275efb9a4..6c06806411084d1e7da6abbf5bce7012dc53c172 100644 (file)
@@ -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,
 };
index d58594a3232492e33f1dd4babd3798b03e0f0203..78901ecd2f957a0ca171ac980cb77b7166a2f047 100644 (file)
 #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;
 };
 
index 1c14c25951583611167fe0d48ab00479d108232a..dac4d4131d9b250cec8d724bc919a58da554ab61 100644 (file)
@@ -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>
 #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) {