Commit 9798f517 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'gpio-v4.16-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio

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
  ...
parents 50081e43 d58f2bf2
AXP209 GPIO controller AXP209 GPIO & pinctrl controller
This driver follows the usual GPIO bindings found in This driver follows the usual GPIO bindings found in
Documentation/devicetree/bindings/gpio/gpio.txt 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: 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 - #gpio-cells: Should be two. The first cell is the pin number and the
second is the GPIO flags. second is the GPIO flags.
- gpio-controller: Marks the device node as a GPIO controller. - gpio-controller: Marks the device node as a GPIO controller.
...@@ -28,3 +35,41 @@ axp209: pmic@34 { ...@@ -28,3 +35,41 @@ axp209: pmic@34 {
#gpio-cells = <2>; #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
...@@ -5,7 +5,7 @@ Required Properties: ...@@ -5,7 +5,7 @@ Required Properties:
- compatible: should contain one or more of the following: - compatible: should contain one or more of the following:
- "renesas,gpio-r8a7743": for R8A7743 (RZ/G1M) compatible GPIO controller. - "renesas,gpio-r8a7743": for R8A7743 (RZ/G1M) compatible GPIO controller.
- "renesas,gpio-r8a7745": for R8A7745 (RZ/G1E) 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-r8a7779": for R8A7779 (R-Car H1) compatible GPIO controller.
- "renesas,gpio-r8a7790": for R8A7790 (R-Car H2) 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. - "renesas,gpio-r8a7791": for R8A7791 (R-Car M2-W) compatible GPIO controller.
......
...@@ -2,6 +2,7 @@ GPIO Mappings ...@@ -2,6 +2,7 @@ GPIO Mappings
============= =============
This document explains how GPIOs can be assigned to given devices and functions. 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 Note that it only applies to the new descriptor-based interface. For a
description of the deprecated integer-based GPIO interface please refer to description of the deprecated integer-based GPIO interface please refer to
gpio-legacy.txt (actually, there is no real mapping possible with the old 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 ...@@ -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); 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). gpiod_is_active_low(power) will be true).
The second parameter of the gpiod_get() functions, the con_id string, has to be The second parameter of the gpiod_get() functions, the con_id string, has to be
...@@ -122,9 +123,14 @@ where ...@@ -122,9 +123,14 @@ where
can be NULL, in which case it will match any function. can be NULL, in which case it will match any function.
- idx is the index of the GPIO within the function. - idx is the index of the GPIO within the function.
- flags is defined to specify the following properties: - flags is defined to specify the following properties:
* GPIOF_ACTIVE_LOW - to configure the GPIO as active-low * GPIO_ACTIVE_HIGH - GPIO line is active high
* GPIOF_OPEN_DRAIN - GPIO pin is open drain type. * GPIO_ACTIVE_LOW - GPIO line is active low
* GPIOF_OPEN_SOURCE - GPIO pin is open source type. * 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. In the future, these flags might be extended to support more properties.
......
...@@ -66,6 +66,15 @@ for the GPIO. Values can be: ...@@ -66,6 +66,15 @@ for the GPIO. Values can be:
* GPIOD_IN to initialize the GPIO as input. * GPIOD_IN to initialize the GPIO as input.
* GPIOD_OUT_LOW to initialize the GPIO as output with a value of 0. * 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_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 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 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: ...@@ -184,7 +193,7 @@ A driver can also query the current direction of a GPIO:
int gpiod_get_direction(const struct gpio_desc *desc) 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 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 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 ...@@ -240,59 +249,71 @@ that can't be accessed from hardIRQ handlers, these calls act the same as the
spinlock-safe calls. spinlock-safe calls.
Active-low State and Raw GPIO Values The active low and open drain semantics
------------------------------------ ---------------------------------------
Device drivers like to manage the logical state of a GPIO, i.e. the value their As a consumer should not have to care about the physical line level, all of the
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
gpiod_set_value_xxx() or gpiod_set_array_value_xxx() functions operate with 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. 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, 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 and if so, they manipulate the passed value before the physical line level is
driven. 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 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. level will be driven accordingly.
As an example, if the active-low property for a dedicated GPIO is set, and the 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 gpiod_set_(array)_value_xxx() passes "asserted" ("1"), the physical line level
will be driven low. will be driven low.
To summarize: To summarize:
Function (example) active-low property physical line Function (example) line property physical line
gpiod_set_raw_value(desc, 0); don't care low gpiod_set_raw_value(desc, 0); don't care low
gpiod_set_raw_value(desc, 1); don't care high gpiod_set_raw_value(desc, 1); don't care high
gpiod_set_value(desc, 0); default (active-high) low gpiod_set_value(desc, 0); default (active high) low
gpiod_set_value(desc, 1); default (active-high) high gpiod_set_value(desc, 1); default (active high) high
gpiod_set_value(desc, 0); active-low high gpiod_set_value(desc, 0); active low high
gpiod_set_value(desc, 1); active-low low gpiod_set_value(desc, 1); active low low
gpiod_set_value(desc, 0); default (active high) low
Please note again that the set_raw/get_raw functions should be avoided as much gpiod_set_value(desc, 1); default (active high) high
as possible, especially by drivers which should not care about the actual gpiod_set_value(desc, 0); open drain low
physical line level and worry about the logical value instead. 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 Access multiple GPIOs with a single function call
......
...@@ -88,6 +88,10 @@ ending up in the pin control back-end "behind" the GPIO controller, usually ...@@ -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 closer to the actual pins. This way the pin controller can manage the below
listed GPIO configurations. 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 GPIOs with debounce support
--------------------------- ---------------------------
......
GPIO Sysfs Interface for Userspace 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 Platforms which use the "gpiolib" implementors framework may choose to
configure a sysfs user interface to GPIOs. This is different from the configure a sysfs user interface to GPIOs. This is different from the
debugfs interface, since it provides control over GPIO direction and debugfs interface, since it provides control over GPIO direction and
......
...@@ -8,17 +8,27 @@ Description ...@@ -8,17 +8,27 @@ Description
----------- -----------
GPIO 1-wire bus master driver. The driver uses the GPIO API to control the 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) Example (mach-at91)
------------------- -------------------
#include <linux/gpio/machine.h>
#include <linux/w1-gpio.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 = { static struct w1_gpio_platform_data foo_w1_gpio_pdata = {
.pin = AT91_PIN_PB20, .ext_pullup_enable_pin = -EINVAL,
.is_open_drain = 1,
}; };
static struct platform_device foo_w1_device = { static struct platform_device foo_w1_device = {
...@@ -30,4 +40,5 @@ 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_GPIO_periph(foo_w1_gpio_pdata.pin, 1);
at91_set_multi_drive(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); platform_device_register(&foo_w1_device);
...@@ -278,6 +278,12 @@ L: linux-gpio@vger.kernel.org ...@@ -278,6 +278,12 @@ L: linux-gpio@vger.kernel.org
S: Maintained S: Maintained
F: drivers/gpio/gpio-pci-idio-16.c 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 ACENIC DRIVER
M: Jes Sorensen <jes@trained-monkey.org> M: Jes Sorensen <jes@trained-monkey.org>
L: linux-acenic@sunsite.dk L: linux-acenic@sunsite.dk
...@@ -5979,6 +5985,7 @@ F: drivers/media/rc/gpio-ir-tx.c ...@@ -5979,6 +5985,7 @@ F: drivers/media/rc/gpio-ir-tx.c
GPIO MOCKUP DRIVER GPIO MOCKUP DRIVER
M: Bamvor Jian Zhang <bamvor.zhangjian@linaro.org> M: Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>
R: Bartosz Golaszewski <brgl@bgdev.pl>
L: linux-gpio@vger.kernel.org L: linux-gpio@vger.kernel.org
S: Maintained S: Maintained
F: drivers/gpio/gpio-mockup.c F: drivers/gpio/gpio-mockup.c
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/serial_8250.h> #include <linux/serial_8250.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/w1-gpio.h> #include <linux/w1-gpio.h>
#include <linux/gpio/machine.h>
#include <linux/mtd/plat-ram.h> #include <linux/mtd/plat-ram.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
#include <asm/mach/arch.h> #include <asm/mach/arch.h>
...@@ -162,9 +163,16 @@ static struct platform_device vulcan_max6369 = { ...@@ -162,9 +163,16 @@ static struct platform_device vulcan_max6369 = {
.num_resources = 1, .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 = { static struct w1_gpio_platform_data vulcan_w1_gpio_pdata = {
.pin = 14, /* Intentionally left blank */
.ext_pullup_enable_pin = -EINVAL,
}; };
static struct platform_device vulcan_w1_gpio = { static struct platform_device vulcan_w1_gpio = {
...@@ -233,6 +241,7 @@ static void __init vulcan_init(void) ...@@ -233,6 +241,7 @@ static void __init vulcan_init(void)
IXP4XX_EXP_BUS_WR_EN | IXP4XX_EXP_BUS_WR_EN |
IXP4XX_EXP_BUS_BYTE_EN; IXP4XX_EXP_BUS_BYTE_EN;
gpiod_add_lookup_table(&vulcan_w1_gpiod_table);
platform_add_devices(vulcan_devices, ARRAY_SIZE(vulcan_devices)); platform_add_devices(vulcan_devices, ARRAY_SIZE(vulcan_devices));
} }
......
...@@ -506,11 +506,16 @@ static void w1_enable_external_pullup(int enable) ...@@ -506,11 +506,16 @@ static void w1_enable_external_pullup(int enable)
msleep(100); 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 = { 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, .enable_external_pullup = w1_enable_external_pullup,
.ext_pullup_enable_pin = -EINVAL,
}; };
static struct platform_device raumfeld_w1_gpio_device = { static struct platform_device raumfeld_w1_gpio_device = {
...@@ -530,6 +535,7 @@ static void __init raumfeld_w1_init(void) ...@@ -530,6 +535,7 @@ static void __init raumfeld_w1_init(void)
else else
gpio_direction_output(GPIO_W1_PULLUP_ENABLE, 0); gpio_direction_output(GPIO_W1_PULLUP_ENABLE, 0);
gpiod_add_lookup_table(&raumfeld_w1_gpiod_table);
platform_device_register(&raumfeld_w1_gpio_device); platform_device_register(&raumfeld_w1_gpio_device);
} }
......
...@@ -122,12 +122,6 @@ config GPIO_ATH79 ...@@ -122,12 +122,6 @@ config GPIO_ATH79
Select this option to enable GPIO driver for Select this option to enable GPIO driver for
Atheros AR71XX/AR724X/AR913X SoC devices. 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 config GPIO_BCM_KONA
bool "Broadcom Kona GPIO" bool "Broadcom Kona GPIO"
depends on OF_GPIO && (ARCH_BCM_MOBILE || COMPILE_TEST) depends on OF_GPIO && (ARCH_BCM_MOBILE || COMPILE_TEST)
...@@ -704,6 +698,22 @@ config GPIO_TS5500 ...@@ -704,6 +698,22 @@ config GPIO_TS5500
blocks of the TS-5500: DIO1, DIO2 and the LCD port, and the TS-5600 blocks of the TS-5500: DIO1, DIO2 and the LCD port, and the TS-5600
LCD port. 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 config GPIO_WS16C48
tristate "WinSystems WS16C48 GPIO support" tristate "WinSystems WS16C48 GPIO support"
depends on ISA_BUS_API depends on ISA_BUS_API
...@@ -1234,6 +1244,16 @@ config GPIO_PCI_IDIO_16 ...@@ -1234,6 +1244,16 @@ config GPIO_PCI_IDIO_16
low). Input filter control is not supported by this driver, and the low). Input filter control is not supported by this driver, and the
input filters are deactivated by this driver. 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 config GPIO_RDC321X
tristate "RDC R-321x GPIO support" tristate "RDC R-321x GPIO support"
select MFD_CORE select MFD_CORE
......
...@@ -32,7 +32,6 @@ obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.o ...@@ -32,7 +32,6 @@ obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.o
obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o
obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o
obj-$(CONFIG_GPIO_ASPEED) += gpio-aspeed.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_BCM_KONA) += gpio-bcm-kona.o
obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o
obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o
...@@ -96,6 +95,7 @@ obj-$(CONFIG_GPIO_PCA953X) += gpio-pca953x.o ...@@ -96,6 +95,7 @@ obj-$(CONFIG_GPIO_PCA953X) += gpio-pca953x.o
obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.o obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.o
obj-$(CONFIG_GPIO_PCH) += gpio-pch.o obj-$(CONFIG_GPIO_PCH) += gpio-pch.o
obj-$(CONFIG_GPIO_PCI_IDIO_16) += gpio-pci-idio-16.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_PISOSR) += gpio-pisosr.o
obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o
obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o
...@@ -140,6 +140,7 @@ obj-$(CONFIG_GPIO_VIPERBOARD) += gpio-viperboard.o ...@@ -140,6 +140,7 @@ obj-$(CONFIG_GPIO_VIPERBOARD) += gpio-viperboard.o
obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o
obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o
obj-$(CONFIG_GPIO_WHISKEY_COVE) += gpio-wcove.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_WM831X) += gpio-wm831x.o
obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o
obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o
......
...@@ -124,6 +124,48 @@ struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev, ...@@ -124,6 +124,48 @@ struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev,
} }
EXPORT_SYMBOL(devm_gpiod_get_index); 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 * devm_fwnode_get_index_gpiod_from_child - get a GPIO descriptor from a
* device's child node * device's child node
......
...@@ -9,12 +9,11 @@ ...@@ -9,12 +9,11 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include <linux/gpio/consumer.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/gpio.h> #include <linux/gpio/driver.h>
#include <linux/of_gpio.h> #include <linux/gpio/consumer.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/module.h> #include <linux/module.h>
......
...@@ -12,8 +12,7 @@ ...@@ -12,8 +12,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/mfd/adp5520.h> #include <linux/mfd/adp5520.h>
#include <linux/gpio/driver.h>
#include <linux/gpio.h>
struct adp5520_gpio { struct adp5520_gpio {
struct device *master; struct device *master;
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/gpio.h> #include <linux/gpio/driver.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/irq.h> #include <linux/irq.h>
......
...@@ -18,7 +18,8 @@ ...@@ -18,7 +18,8 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/module.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> #include <linux/platform_device.h>
#define ALTERA_GPIO_MAX_NGPIO 32 #define ALTERA_GPIO_MAX_NGPIO 32
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/gpio.h> #include <linux/gpio/driver.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/gpio.h> #include <linux/gpio/driver.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
......
...@@ -60,6 +60,7 @@ struct aspeed_gpio_bank { ...@@ -60,6 +60,7 @@ struct aspeed_gpio_bank {
uint16_t val_regs; uint16_t val_regs;
uint16_t irq_regs; uint16_t irq_regs;
uint16_t debounce_regs; uint16_t debounce_regs;
uint16_t tolerance_regs;
const char names[4][3]; const char names[4][3];
}; };
...@@ -70,48 +71,56 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { ...@@ -70,48 +71,56 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = {
.val_regs = 0x0000, .val_regs = 0x0000,
.irq_regs = 0x0008, .irq_regs = 0x0008,
.debounce_regs = 0x0040, .debounce_regs = 0x0040,
.tolerance_regs = 0x001c,
.names = { "A", "B", "C", "D" }, .names = { "A", "B", "C", "D" },
}, },
{ {
.val_regs = 0x0020, .val_regs = 0x0020,
.irq_regs = 0x0028, .irq_regs = 0x0028,
.debounce_regs = 0x0048, .debounce_regs = 0x0048,
.tolerance_regs = 0x003c,
.names = { "E", "F", "G", "H" }, .names = { "E", "F", "G", "H" },
}, },
{ {
.val_regs = 0x0070, .val_regs = 0x0070,
.irq_regs = 0x0098, .irq_regs = 0x0098,
.debounce_regs = 0x00b0, .debounce_regs = 0x00b0,
.tolerance_regs = 0x00ac,
.names = { "I", "J", "K", "L" }, .names = { "I", "J", "K", "L" },
}, },
{ {
.val_regs = 0x0078, .val_regs = 0x0078,
.irq_regs = 0x00e8, .irq_regs = 0x00e8,
.debounce_regs = 0x0100, .debounce_regs = 0x0100,
.tolerance_regs = 0x00fc,
.names = { "M", "N", "O", "P" }, .names = { "M", "N", "O", "P" },
}, },
{ {
.val_regs = 0x0080, .val_regs = 0x0080,
.irq_regs = 0x0118, .irq_regs = 0x0118,
.debounce_regs = 0x0130, .debounce_regs = 0x0130,
.tolerance_regs = 0x012c,
.names = { "Q", "R", "S", "T" }, .names = { "Q", "R", "S", "T" },
}, },
{ {
.val_regs = 0x0088, .val_regs = 0x0088,
.irq_regs = 0x0148, .irq_regs = 0x0148,
.debounce_regs = 0x0160, .debounce_regs = 0x0160,
.tolerance_regs = 0x015c,
.names = { "U", "V", "W", "X" }, .names = { "U", "V", "W", "X" },
}, },
{ {
.val_regs = 0x01E0, .val_regs = 0x01E0,
.irq_regs = 0x0178, .irq_regs = 0x0178,
.debounce_regs = 0x0190, .debounce_regs = 0x0190,
.tolerance_regs = 0x018c,
.names = { "Y", "Z", "AA", "AB" }, .names = { "Y", "Z", "AA", "AB" },
}, },
{ {
.val_regs = 0x01E8, .val_regs = 0x01e8,
.irq_regs = 0x01A8, .irq_regs = 0x01a8,
.debounce_regs = 0x01c0, .debounce_regs = 0x01c0,
.tolerance_regs = 0x01bc,
.names = { "AC", "", "", "" }, .names = { "AC", "", "", "" },
}, },
}; };
...@@ -140,7 +149,7 @@ static const struct aspeed_gpio_bank *to_bank(unsigned int offset) ...@@ -140,7 +149,7 @@ static const struct aspeed_gpio_bank *to_bank(unsigned int offset)
{ {
unsigned int bank = GPIO_BANK(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]; return &aspeed_gpio_banks[bank];
} }
...@@ -534,6 +543,30 @@ static int aspeed_gpio_setup_irqs(struct aspeed_gpio *gpio, ...@@ -534,6 +543,30 @@ static int aspeed_gpio_setup_irqs(struct aspeed_gpio *gpio,
return 0; 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) static int aspeed_gpio_request(struct gpio_chip *chip, unsigned int offset)
{ {
if (!have_gpio(gpiochip_get_data(chip), 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, ...@@ -771,6 +804,8 @@ static int aspeed_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
param == PIN_CONFIG_DRIVE_OPEN_SOURCE) param == PIN_CONFIG_DRIVE_OPEN_SOURCE)
/* Return -ENOTSUPP to trigger emulation, as per datasheet */ /* Return -ENOTSUPP to trigger emulation, as per datasheet */
return -ENOTSUPP; return -ENOTSUPP;
else if (param == PIN_CONFIG_PERSIST_STATE)
return aspeed_gpio_reset_tolerance(chip, offset, arg);
return -ENOTSUPP; return -ENOTSUPP;
} }
......
...@@ -324,3 +324,6 @@ static struct platform_driver ath79_gpio_driver = { ...@@ -324,3 +324,6 @@ static struct platform_driver ath79_gpio_driver = {
}; };
module_platform_driver(ath79_gpio_driver); module_platform_driver(ath79_gpio_driver);
MODULE_DESCRIPTION("Atheros AR71XX/AR724X/AR913X GPIO API support");
MODULE_LICENSE("GPL v2");
/*
* 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");
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/gpio.h> #include <linux/gpio/driver.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -127,7 +127,7 @@ static int bcm_kona_gpio_get_dir(struct gpio_chip *chip, unsigned gpio) ...@@ -127,7 +127,7 @@ static int bcm_kona_gpio_get_dir(struct gpio_chip *chip, unsigned gpio)
u32 val; u32 val;
val = readl(reg_base + GPIO_CONTROL(gpio)) & GPIO_GPCTR0_IOTR_MASK; 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) 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) ...@@ -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); raw_spin_lock_irqsave(&kona_gpio->lock, flags);
/* this function only applies to output pin */ /* 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; goto out;
reg_offset = value ? GPIO_OUT_SET(bank_id) : GPIO_OUT_CLEAR(bank_id); 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) ...@@ -170,7 +170,7 @@ static int bcm_kona_gpio_get(struct gpio_chip *chip, unsigned gpio)
reg_base = kona_gpio->reg_base; reg_base = kona_gpio->reg_base;
raw_spin_lock_irqsave(&kona_gpio->lock, flags); 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); reg_offset = GPIO_IN_STATUS(bank_id);
else else
reg_offset = GPIO_OUT_STATUS(bank_id); reg_offset = GPIO_OUT_STATUS(bank_id);
......
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
#include <linux/irqdomain.h> #include <linux/irqdomain.h>
#include <linux/irqchip/chained_irq.h> #include <linux/irqchip/chained_irq.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/bitops.h>
enum gio_reg_index { enum gio_reg_index {
GIO_REG_ODEN = 0, GIO_REG_ODEN = 0,
......
...@@ -46,7 +46,7 @@ ...@@ -46,7 +46,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/gpio.h> #include <linux/gpio/driver.h>
#include <linux/slab.h> #include <linux/slab.h>
/* Steal the hardware definitions from the bttv driver. */ /* Steal the hardware definitions from the bttv driver. */
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/gpio.h> #include <linux/gpio/driver.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/regmap.h> #include <linux/regmap.h>
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/gpio.h> #include <linux/gpio/driver.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/cs5535.h> #include <linux/cs5535.h>
#include <asm/msr.h> #include <asm/msr.h>
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/gpio.h> #include <linux/gpio/driver.h>
#include <linux/syscalls.h> #include <linux/syscalls.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.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/core.h>
#include <linux/mfd/da9055/reg.h> #include <linux/mfd/da9055/reg.h>
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version. * (at your option) any later version.
*/ */
#include <linux/gpio.h> #include <linux/gpio/driver.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/clk.h> #include <linux/clk.h>
......
...@@ -176,8 +176,8 @@ static int ftgpio_gpio_probe(struct platform_device *pdev) ...@@ -176,8 +176,8 @@ static int ftgpio_gpio_probe(struct platform_device *pdev)
return PTR_ERR(g->base); return PTR_ERR(g->base);
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (!irq) if (irq <= 0)
return -EINVAL; return irq ? irq : -EINVAL;
ret = bgpio_init(&g->gc, dev, 4, ret = bgpio_init(&g->gc, dev, 4,
g->base + GPIO_DATA_IN, g->base + GPIO_DATA_IN,
......
...@@ -58,3 +58,7 @@ static int __init iop3xx_gpio_init(void) ...@@ -58,3 +58,7 @@ static int __init iop3xx_gpio_init(void)
return platform_driver_register(&iop3xx_gpio_driver); return platform_driver_register(&iop3xx_gpio_driver);
} }
arch_initcall(iop3xx_gpio_init); arch_initcall(iop3xx_gpio_init);
MODULE_DESCRIPTION("GPIO handling for Intel IOP3xx processors");
MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>");
MODULE_LICENSE("GPL");
...@@ -414,6 +414,6 @@ static void __exit it87_gpio_exit(void) ...@@ -414,6 +414,6 @@ static void __exit it87_gpio_exit(void)
module_init(it87_gpio_init); module_init(it87_gpio_init);
module_exit(it87_gpio_exit); module_exit(it87_gpio_exit);
MODULE_AUTHOR("Diego Elio Pettenò <flameeyes@flameeyes.eu>"); MODULE_AUTHOR("Diego Elio Pettenò <flameeyes@flameeyes.eu>");
MODULE_DESCRIPTION("GPIO interface for IT87xx Super I/O chips"); MODULE_DESCRIPTION("GPIO interface for IT87xx Super I/O chips");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -709,7 +709,6 @@ static int max732x_probe(struct i2c_client *client, ...@@ -709,7 +709,6 @@ static int max732x_probe(struct i2c_client *client,
return 0; return 0;
out_failed: out_failed:
if (chip->client_dummy)
i2c_unregister_device(chip->client_dummy); i2c_unregister_device(chip->client_dummy);
return ret; return ret;
} }
...@@ -734,7 +733,6 @@ static int max732x_remove(struct i2c_client *client) ...@@ -734,7 +733,6 @@ static int max732x_remove(struct i2c_client *client)
gpiochip_remove(&chip->gpio_chip); gpiochip_remove(&chip->gpio_chip);
/* unregister any dummy i2c_client */ /* unregister any dummy i2c_client */
if (chip->client_dummy)
i2c_unregister_device(chip->client_dummy); i2c_unregister_device(chip->client_dummy);
return 0; return 0;
......
...@@ -34,6 +34,8 @@ ...@@ -34,6 +34,8 @@
*/ */
#define GPIO_MOCKUP_MAX_RANGES (GPIO_MOCKUP_MAX_GC * 2) #define GPIO_MOCKUP_MAX_RANGES (GPIO_MOCKUP_MAX_GC * 2)
#define gpio_mockup_err(...) pr_err(GPIO_MOCKUP_NAME ": " __VA_ARGS__)
enum { enum {
GPIO_MOCKUP_DIR_OUT = 0, GPIO_MOCKUP_DIR_OUT = 0,
GPIO_MOCKUP_DIR_IN = 1, GPIO_MOCKUP_DIR_IN = 1,
...@@ -46,7 +48,7 @@ enum { ...@@ -46,7 +48,7 @@ enum {
*/ */
struct gpio_mockup_line_status { struct gpio_mockup_line_status {
int dir; int dir;
bool value; int value;
}; };
struct gpio_mockup_chip { struct gpio_mockup_chip {
...@@ -62,17 +64,33 @@ struct gpio_mockup_dbgfs_private { ...@@ -62,17 +64,33 @@ struct gpio_mockup_dbgfs_private {
int offset; 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_ranges[GPIO_MOCKUP_MAX_RANGES];
static int gpio_mockup_params_nr; static int gpio_mockup_num_ranges;
module_param_array(gpio_mockup_ranges, int, &gpio_mockup_params_nr, 0400); module_param_array(gpio_mockup_ranges, int, &gpio_mockup_num_ranges, 0400);
static bool gpio_mockup_named_lines; static bool gpio_mockup_named_lines;
module_param_named(gpio_mockup_named_lines, module_param_named(gpio_mockup_named_lines,
gpio_mockup_named_lines, bool, 0400); gpio_mockup_named_lines, bool, 0400);
static const char gpio_mockup_name_start = 'A';
static struct dentry *gpio_mockup_dbg_dir; 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) static int gpio_mockup_get(struct gpio_chip *gc, unsigned int offset)
{ {
struct gpio_mockup_chip *chip = gpiochip_get_data(gc); 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) ...@@ -80,16 +98,26 @@ static int gpio_mockup_get(struct gpio_chip *gc, unsigned int offset)
return chip->lines[offset].value; return chip->lines[offset].value;
} }
static void gpio_mockup_set(struct gpio_chip *gc, unsigned int offset, static void gpio_mockup_set(struct gpio_chip *gc,
int value) unsigned int offset, int value)
{ {
struct gpio_mockup_chip *chip = gpiochip_get_data(gc); struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
chip->lines[offset].value = !!value; chip->lines[offset].value = !!value;
} }
static int gpio_mockup_dirout(struct gpio_chip *gc, unsigned int offset, static void gpio_mockup_set_multiple(struct gpio_chip *gc,
int value) 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); 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) ...@@ -115,29 +143,6 @@ static int gpio_mockup_get_direction(struct gpio_chip *gc, unsigned int offset)
return chip->lines[offset].dir; 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) static int gpio_mockup_to_irq(struct gpio_chip *gc, unsigned int offset)
{ {
struct gpio_mockup_chip *chip = gpiochip_get_data(gc); struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
...@@ -188,15 +193,21 @@ static void gpio_mockup_debugfs_setup(struct device *dev, ...@@ -188,15 +193,21 @@ static void gpio_mockup_debugfs_setup(struct device *dev,
struct gpio_mockup_chip *chip) struct gpio_mockup_chip *chip)
{ {
struct gpio_mockup_dbgfs_private *priv; struct gpio_mockup_dbgfs_private *priv;
struct dentry *evfile; struct dentry *evfile, *link;
struct gpio_chip *gc; struct gpio_chip *gc;
const char *devname;
char *name; char *name;
int i; int i;
gc = &chip->gc; gc = &chip->gc;
devname = dev_name(&gc->gpiodev->dev);
chip->dbg_dir = debugfs_create_dir(devname, gpio_mockup_dbg_dir);
if (IS_ERR_OR_NULL(chip->dbg_dir))
goto err;
chip->dbg_dir = debugfs_create_dir(gc->label, gpio_mockup_dbg_dir); link = debugfs_create_symlink(gc->label, gpio_mockup_dbg_dir, devname);
if (!chip->dbg_dir) if (IS_ERR_OR_NULL(link))
goto err; goto err;
for (i = 0; i < gc->ngpio; i++) { for (i = 0; i < gc->ngpio; i++) {
...@@ -214,23 +225,63 @@ static void gpio_mockup_debugfs_setup(struct device *dev, ...@@ -214,23 +225,63 @@ static void gpio_mockup_debugfs_setup(struct device *dev,
evfile = debugfs_create_file(name, 0200, chip->dbg_dir, priv, evfile = debugfs_create_file(name, 0200, chip->dbg_dir, priv,
&gpio_mockup_event_ops); &gpio_mockup_event_ops);
if (!evfile) if (IS_ERR_OR_NULL(evfile))
goto err; goto err;
} }
return; return;
err: 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, static int gpio_mockup_name_lines(struct device *dev,
struct gpio_mockup_chip *chip, struct gpio_mockup_chip *chip)
const char *name, int base, int ngpio)
{ {
struct gpio_chip *gc = &chip->gc; 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->base = base;
gc->ngpio = ngpio; gc->ngpio = ngpio;
gc->label = name; gc->label = name;
...@@ -238,6 +289,7 @@ static int gpio_mockup_add(struct device *dev, ...@@ -238,6 +289,7 @@ static int gpio_mockup_add(struct device *dev,
gc->parent = dev; gc->parent = dev;
gc->get = gpio_mockup_get; gc->get = gpio_mockup_get;
gc->set = gpio_mockup_set; gc->set = gpio_mockup_set;
gc->set_multiple = gpio_mockup_set_multiple;
gc->direction_output = gpio_mockup_dirout; gc->direction_output = gpio_mockup_dirout;
gc->direction_input = gpio_mockup_dirin; gc->direction_input = gpio_mockup_dirin;
gc->get_direction = gpio_mockup_get_direction; gc->get_direction = gpio_mockup_get_direction;
...@@ -248,19 +300,19 @@ static int gpio_mockup_add(struct device *dev, ...@@ -248,19 +300,19 @@ static int gpio_mockup_add(struct device *dev,
if (!chip->lines) if (!chip->lines)
return -ENOMEM; return -ENOMEM;
if (gpio_mockup_named_lines) { if (pdata->named_lines) {
ret = gpio_mockup_name_lines(dev, chip); rv = gpio_mockup_name_lines(dev, chip);
if (ret) if (rv)
return ret; return rv;
} }
ret = devm_irq_sim_init(dev, &chip->irqsim, gc->ngpio); rv = devm_irq_sim_init(dev, &chip->irqsim, gc->ngpio);
if (ret) if (rv < 0)
return ret; return rv;
ret = devm_gpiochip_add_data(dev, &chip->gc, chip); rv = devm_gpiochip_add_data(dev, &chip->gc, chip);
if (ret) if (rv)
return ret; return rv;
if (gpio_mockup_dbg_dir) if (gpio_mockup_dbg_dir)
gpio_mockup_debugfs_setup(dev, chip); gpio_mockup_debugfs_setup(dev, chip);
...@@ -268,58 +320,6 @@ static int gpio_mockup_add(struct device *dev, ...@@ -268,58 +320,6 @@ static int gpio_mockup_add(struct device *dev,
return 0; 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 = { static struct platform_driver gpio_mockup_driver = {
.driver = { .driver = {
.name = GPIO_MOCKUP_NAME, .name = GPIO_MOCKUP_NAME,
...@@ -327,44 +327,88 @@ static struct platform_driver gpio_mockup_driver = { ...@@ -327,44 +327,88 @@ static struct platform_driver gpio_mockup_driver = {
.probe = gpio_mockup_probe, .probe = gpio_mockup_probe,
}; };
static struct platform_device *pdev; static struct platform_device *gpio_mockup_pdevs[GPIO_MOCKUP_MAX_GC];
static int __init mock_device_init(void)
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); for (i = 0; i < GPIO_MOCKUP_MAX_GC; i++) {
if (!gpio_mockup_dbg_dir) pdev = gpio_mockup_pdevs[i];
pr_err("%s: error creating debugfs directory\n",
GPIO_MOCKUP_NAME);
pdev = platform_device_alloc(GPIO_MOCKUP_NAME, -1); if (pdev)
if (!pdev) platform_device_unregister(pdev);
return -ENOMEM; }
}
err = platform_device_add(pdev); static int __init gpio_mockup_init(void)
if (err) { {
platform_device_put(pdev); int i, num_chips, err = 0, index = 'A';
return err; 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); err = platform_driver_register(&gpio_mockup_driver);
if (err) { if (err) {
platform_device_unregister(pdev); gpio_mockup_err("error registering platform driver\n");
return err; 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; return 0;
} }
static void __exit mock_device_exit(void) static void __exit gpio_mockup_exit(void)
{ {
debugfs_remove_recursive(gpio_mockup_dbg_dir); debugfs_remove_recursive(gpio_mockup_dbg_dir);
platform_driver_unregister(&gpio_mockup_driver); platform_driver_unregister(&gpio_mockup_driver);
platform_device_unregister(pdev); gpio_mockup_unregister_pdevs();
} }
module_init(mock_device_init); module_init(gpio_mockup_init);
module_exit(mock_device_exit); module_exit(gpio_mockup_exit);
MODULE_AUTHOR("Kamlakant Patel <kamlakant.patel@broadcom.com>"); MODULE_AUTHOR("Kamlakant Patel <kamlakant.patel@broadcom.com>");
MODULE_AUTHOR("Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>"); MODULE_AUTHOR("Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>");
......
...@@ -1058,7 +1058,9 @@ static void omap_gpio_mod_init(struct gpio_bank *bank) ...@@ -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) static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
{ {
struct gpio_irq_chip *irq;
static int gpio; static int gpio;
const char *label;
int irq_base = 0; int irq_base = 0;
int ret; int ret;
...@@ -1080,21 +1082,15 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc) ...@@ -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.parent = &omap_mpuio_device.dev;
bank->chip.base = OMAP_MPUIO(0); bank->chip.base = OMAP_MPUIO(0);
} else { } 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.base = gpio;
} }
bank->chip.ngpio = bank->width; 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 #ifdef CONFIG_ARCH_OMAP1
/* /*
* REVISIT: Once we have OMAP1 supporting SPARSE_IRQ, we can drop * 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) ...@@ -1115,25 +1111,30 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
irqc->irq_set_wake = NULL; irqc->irq_set_wake = NULL;
} }
ret = gpiochip_irqchip_add(&bank->chip, irqc, irq = &bank->chip.irq;
irq_base, handle_bad_irq, irq->chip = irqc;
IRQ_TYPE_NONE); 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) { if (ret) {
dev_err(bank->chip.parent, dev_err(bank->chip.parent,
"Couldn't add irqchip to gpiochip %d\n", ret); "Could not register gpio chip %d\n", ret);
gpiochip_remove(&bank->chip); return ret;
return -ENODEV;
} }
gpiochip_set_chained_irqchip(&bank->chip, irqc, bank->irq, NULL);
ret = devm_request_irq(bank->chip.parent, bank->irq, ret = devm_request_irq(bank->chip.parent, bank->irq,
omap_gpio_irq_handler, omap_gpio_irq_handler,
0, dev_name(bank->chip.parent), bank); 0, dev_name(bank->chip.parent), bank);
if (ret) if (ret)
gpiochip_remove(&bank->chip); gpiochip_remove(&bank->chip);
if (!bank->is_mpuio)
gpio += bank->width;
return ret; return ret;
} }
......
// 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");
...@@ -190,6 +190,16 @@ static void stmpe_gpio_irq_sync_unlock(struct irq_data *d) ...@@ -190,6 +190,16 @@ static void stmpe_gpio_irq_sync_unlock(struct irq_data *d)
}; };
int i, j; 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++) { for (i = 0; i < CACHE_NR_REGS; i++) {
/* STMPE801 and STMPE1600 don't have RE and FE registers */ /* STMPE801 and STMPE1600 don't have RE and FE registers */
if ((stmpe->partnum == STMPE801 || if ((stmpe->partnum == STMPE801 ||
...@@ -227,21 +237,11 @@ static void stmpe_gpio_irq_unmask(struct irq_data *d) ...@@ -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 gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc); struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc);
struct stmpe *stmpe = stmpe_gpio->stmpe;
int offset = d->hwirq; int offset = d->hwirq;
int regoffset = offset / 8; int regoffset = offset / 8;
int mask = BIT(offset % 8); int mask = BIT(offset % 8);
stmpe_gpio->regs[REG_IE][regoffset] |= mask; 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, static void stmpe_dbg_show_one(struct seq_file *s,
...@@ -273,15 +273,21 @@ 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 fall_reg;
u8 irqen_reg; u8 irqen_reg;
char *edge_det_values[] = {"edge-inactive", static const char * const edge_det_values[] = {
"edge-inactive",
"edge-asserted", "edge-asserted",
"not-supported"}; "not-supported"
char *rise_values[] = {"no-rising-edge-detection", };
static const char * const rise_values[] = {
"no-rising-edge-detection",
"rising-edge-detection", "rising-edge-detection",
"not-supported"}; "not-supported"
char *fall_values[] = {"no-falling-edge-detection", };
static const char * const fall_values[] = {
"no-falling-edge-detection",
"falling-edge-detection", "falling-edge-detection",
"not-supported"}; "not-supported"
};
#define NOT_SUPPORTED_IDX 2 #define NOT_SUPPORTED_IDX 2
u8 edge_det = NOT_SUPPORTED_IDX; u8 edge_det = NOT_SUPPORTED_IDX;
u8 rise = 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) ...@@ -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++) { for (i = 0; i < gc->ngpio; i++, gpio++) {
stmpe_dbg_show_one(s, gc, 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) ...@@ -426,12 +432,9 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent); struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent);
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
struct stmpe_gpio *stmpe_gpio; struct stmpe_gpio *stmpe_gpio;
int ret; int ret, irq;
int irq = 0;
irq = platform_get_irq(pdev, 0); stmpe_gpio = kzalloc(sizeof(*stmpe_gpio), GFP_KERNEL);
stmpe_gpio = kzalloc(sizeof(struct stmpe_gpio), GFP_KERNEL);
if (!stmpe_gpio) if (!stmpe_gpio)
return -ENOMEM; return -ENOMEM;
...@@ -453,6 +456,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev) ...@@ -453,6 +456,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
if (stmpe_gpio->norequest_mask) if (stmpe_gpio->norequest_mask)
stmpe_gpio->chip.irq.need_valid_mask = true; stmpe_gpio->chip.irq.need_valid_mask = true;
irq = platform_get_irq(pdev, 0);
if (irq < 0) if (irq < 0)
dev_info(&pdev->dev, dev_info(&pdev->dev,
"device configured in no-irq mode: " "device configured in no-irq mode: "
......
...@@ -553,8 +553,10 @@ static int thunderx_gpio_probe(struct pci_dev *pdev, ...@@ -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, 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), 0, 0, of_node_to_fwnode(dev->of_node),
&thunderx_gpio_irqd_ops, txgpio); &thunderx_gpio_irqd_ops, txgpio);
if (!txgpio->irqd) if (!txgpio->irqd) {
err = -ENOMEM;
goto out; goto out;
}
/* Push on irq_data and the domain for each line. */ /* Push on irq_data and the domain for each line. */
for (i = 0; i < ngpio; i++) { for (i = 0; i < ngpio; i++) {
......
// 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");
...@@ -414,7 +414,8 @@ EXPORT_SYMBOL_GPL(devm_acpi_dev_remove_driver_gpios); ...@@ -414,7 +414,8 @@ EXPORT_SYMBOL_GPL(devm_acpi_dev_remove_driver_gpios);
static bool acpi_get_driver_gpio_data(struct acpi_device *adev, static bool acpi_get_driver_gpio_data(struct acpi_device *adev,
const char *name, int index, const char *name, int index,
struct acpi_reference_args *args) struct acpi_reference_args *args,
unsigned int *quirks)
{ {
const struct acpi_gpio_mapping *gm; const struct acpi_gpio_mapping *gm;
...@@ -430,6 +431,8 @@ static bool acpi_get_driver_gpio_data(struct acpi_device *adev, ...@@ -430,6 +431,8 @@ static bool acpi_get_driver_gpio_data(struct acpi_device *adev,
args->args[1] = par->line_index; args->args[1] = par->line_index;
args->args[2] = par->active_low; args->args[2] = par->active_low;
args->nargs = 3; args->nargs = 3;
*quirks = gm->quirks;
return true; return true;
} }
...@@ -461,8 +464,8 @@ acpi_gpio_to_gpiod_flags(const struct acpi_resource_gpio *agpio) ...@@ -461,8 +464,8 @@ acpi_gpio_to_gpiod_flags(const struct acpi_resource_gpio *agpio)
} }
} }
int static int
acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, enum gpiod_flags update) __acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, enum gpiod_flags update)
{ {
int ret = 0; int ret = 0;
...@@ -489,12 +492,31 @@ acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, enum gpiod_flags update) ...@@ -489,12 +492,31 @@ acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, enum gpiod_flags update)
return ret; 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_lookup {
struct acpi_gpio_info info; struct acpi_gpio_info info;
int index; int index;
int pin_index; int pin_index;
bool active_low; bool active_low;
struct acpi_device *adev;
struct gpio_desc *desc; struct gpio_desc *desc;
int n; int n;
}; };
...@@ -531,8 +553,8 @@ static int acpi_populate_gpio_lookup(struct acpi_resource *ares, void *data) ...@@ -531,8 +553,8 @@ static int acpi_populate_gpio_lookup(struct acpi_resource *ares, void *data)
lookup->info.triggering = agpio->triggering; lookup->info.triggering = agpio->triggering;
} else { } else {
lookup->info.flags = acpi_gpio_to_gpiod_flags(agpio); lookup->info.flags = acpi_gpio_to_gpiod_flags(agpio);
lookup->info.polarity = lookup->active_low;
} }
} }
return 1; return 1;
...@@ -541,12 +563,13 @@ static int acpi_populate_gpio_lookup(struct acpi_resource *ares, void *data) ...@@ -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, static int acpi_gpio_resource_lookup(struct acpi_gpio_lookup *lookup,
struct acpi_gpio_info *info) struct acpi_gpio_info *info)
{ {
struct acpi_device *adev = lookup->info.adev;
struct list_head res_list; struct list_head res_list;
int ret; int ret;
INIT_LIST_HEAD(&res_list); 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, acpi_populate_gpio_lookup,
lookup); lookup);
if (ret < 0) if (ret < 0)
...@@ -557,11 +580,8 @@ static int acpi_gpio_resource_lookup(struct acpi_gpio_lookup *lookup, ...@@ -557,11 +580,8 @@ static int acpi_gpio_resource_lookup(struct acpi_gpio_lookup *lookup,
if (!lookup->desc) if (!lookup->desc)
return -ENOENT; return -ENOENT;
if (info) { if (info)
*info = lookup->info; *info = lookup->info;
if (lookup->active_low)
info->polarity = lookup->active_low;
}
return 0; return 0;
} }
...@@ -570,6 +590,7 @@ static int acpi_gpio_property_lookup(struct fwnode_handle *fwnode, ...@@ -570,6 +590,7 @@ static int acpi_gpio_property_lookup(struct fwnode_handle *fwnode,
struct acpi_gpio_lookup *lookup) struct acpi_gpio_lookup *lookup)
{ {
struct acpi_reference_args args; struct acpi_reference_args args;
unsigned int quirks = 0;
int ret; int ret;
memset(&args, 0, sizeof(args)); memset(&args, 0, sizeof(args));
...@@ -581,14 +602,14 @@ static int acpi_gpio_property_lookup(struct fwnode_handle *fwnode, ...@@ -581,14 +602,14 @@ static int acpi_gpio_property_lookup(struct fwnode_handle *fwnode,
if (!adev) if (!adev)
return ret; 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; return ret;
} }
/* /*
* The property was found and resolved, so need to lookup the GPIO based * The property was found and resolved, so need to lookup the GPIO based
* on returned args. * on returned args.
*/ */
lookup->adev = args.adev;
if (args.nargs != 3) if (args.nargs != 3)
return -EPROTO; return -EPROTO;
...@@ -596,6 +617,8 @@ static int acpi_gpio_property_lookup(struct fwnode_handle *fwnode, ...@@ -596,6 +617,8 @@ static int acpi_gpio_property_lookup(struct fwnode_handle *fwnode,
lookup->pin_index = args.args[1]; lookup->pin_index = args.args[1];
lookup->active_low = !!args.args[2]; lookup->active_low = !!args.args[2];
lookup->info.adev = args.adev;
lookup->info.quirks = quirks;
return 0; return 0;
} }
...@@ -643,11 +666,11 @@ static struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev, ...@@ -643,11 +666,11 @@ static struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
return ERR_PTR(ret); return ERR_PTR(ret);
dev_dbg(&adev->dev, "GPIO: _DSD returned %s %d %d %u\n", 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); lookup.pin_index, lookup.active_low);
} else { } else {
dev_dbg(&adev->dev, "GPIO: looking up %d in _CRS\n", index); 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); ret = acpi_gpio_resource_lookup(&lookup, info);
...@@ -664,7 +687,6 @@ struct gpio_desc *acpi_find_gpio(struct device *dev, ...@@ -664,7 +687,6 @@ struct gpio_desc *acpi_find_gpio(struct device *dev,
struct acpi_gpio_info info; struct acpi_gpio_info info;
struct gpio_desc *desc; struct gpio_desc *desc;
char propname[32]; char propname[32];
int err;
int i; int i;
/* Try first from _DSD */ /* Try first from _DSD */
...@@ -703,10 +725,7 @@ struct gpio_desc *acpi_find_gpio(struct device *dev, ...@@ -703,10 +725,7 @@ struct gpio_desc *acpi_find_gpio(struct device *dev,
if (info.polarity == GPIO_ACTIVE_LOW) if (info.polarity == GPIO_ACTIVE_LOW)
*lookupflags |= GPIO_ACTIVE_LOW; *lookupflags |= GPIO_ACTIVE_LOW;
err = acpi_gpio_update_gpiod_flags(dflags, info.flags); acpi_gpio_update_gpiod_flags(dflags, &info);
if (err)
dev_dbg(dev, "Override GPIO initialization flags\n");
return desc; return desc;
} }
......
...@@ -56,6 +56,42 @@ static struct gpio_desc *of_xlate_and_get_gpiod_flags(struct gpio_chip *chip, ...@@ -56,6 +56,42 @@ static struct gpio_desc *of_xlate_and_get_gpiod_flags(struct gpio_chip *chip,
return gpiochip_get_desc(chip, ret); 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 * of_get_named_gpiod_flags() - Get a GPIO descriptor and flags for GPIO API
* @np: device node to get GPIO from * @np: device node to get GPIO from
...@@ -93,6 +129,9 @@ struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np, ...@@ -93,6 +129,9 @@ struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
if (IS_ERR(desc)) if (IS_ERR(desc))
goto out; goto out;
if (flags)
of_gpio_flags_quirks(np, flags);
pr_debug("%s: parsed '%s' property of node '%pOF[%d]' - status (%d)\n", pr_debug("%s: parsed '%s' property of node '%pOF[%d]' - status (%d)\n",
__func__, propname, np, index, __func__, propname, np, index,
PTR_ERR_OR_ZERO(desc)); PTR_ERR_OR_ZERO(desc));
...@@ -117,6 +156,71 @@ int of_get_named_gpio_flags(struct device_node *np, const char *list_name, ...@@ -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); 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, struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
unsigned int idx, unsigned int idx,
enum gpio_lookup_flags *flags) enum gpio_lookup_flags *flags)
...@@ -126,6 +230,7 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, ...@@ -126,6 +230,7 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
struct gpio_desc *desc; struct gpio_desc *desc;
unsigned int i; unsigned int i;
/* Try GPIO property "foo-gpios" and "foo-gpio" */
for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) { for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
if (con_id) if (con_id)
snprintf(prop_name, sizeof(prop_name), "%s-%s", 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, ...@@ -140,6 +245,14 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
break; 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)) if (IS_ERR(desc))
return desc; return desc;
...@@ -153,8 +266,8 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, ...@@ -153,8 +266,8 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
*flags |= GPIO_OPEN_SOURCE; *flags |= GPIO_OPEN_SOURCE;
} }
if (of_flags & OF_GPIO_SLEEP_MAY_LOSE_VALUE) if (of_flags & OF_GPIO_TRANSITORY)
*flags |= GPIO_SLEEP_MAY_LOSE_VALUE; *flags |= GPIO_TRANSITORY;
return desc; return desc;
} }
...@@ -214,6 +327,8 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np, ...@@ -214,6 +327,8 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np,
if (xlate_flags & OF_GPIO_ACTIVE_LOW) if (xlate_flags & OF_GPIO_ACTIVE_LOW)
*lflags |= GPIO_ACTIVE_LOW; *lflags |= GPIO_ACTIVE_LOW;
if (xlate_flags & OF_GPIO_TRANSITORY)
*lflags |= GPIO_TRANSITORY;
if (of_property_read_bool(np, "input")) if (of_property_read_bool(np, "input"))
*dflags |= GPIOD_IN; *dflags |= GPIOD_IN;
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/kdev_t.h> #include <linux/kdev_t.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/ctype.h>
#include "gpiolib.h" #include "gpiolib.h"
...@@ -106,8 +107,14 @@ static ssize_t value_show(struct device *dev, ...@@ -106,8 +107,14 @@ static ssize_t value_show(struct device *dev,
mutex_lock(&data->mutex); 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); mutex_unlock(&data->mutex);
return status; return status;
...@@ -118,7 +125,7 @@ static ssize_t value_store(struct device *dev, ...@@ -118,7 +125,7 @@ static ssize_t value_store(struct device *dev,
{ {
struct gpiod_data *data = dev_get_drvdata(dev); struct gpiod_data *data = dev_get_drvdata(dev);
struct gpio_desc *desc = data->desc; struct gpio_desc *desc = data->desc;
ssize_t status; ssize_t status = 0;
mutex_lock(&data->mutex); mutex_lock(&data->mutex);
...@@ -127,6 +134,10 @@ static ssize_t value_store(struct device *dev, ...@@ -127,6 +134,10 @@ static ssize_t value_store(struct device *dev,
} else { } else {
long value; long value;
if (size <= 2 && isdigit(buf[0]) &&
(size == 1 || buf[1] == '\n'))
value = buf[0] - '0';
else
status = kstrtol(buf, 0, &value); status = kstrtol(buf, 0, &value);
if (status == 0) { if (status == 0) {
gpiod_set_value_cansleep(desc, value); gpiod_set_value_cansleep(desc, value);
...@@ -138,7 +149,7 @@ static ssize_t value_store(struct device *dev, ...@@ -138,7 +149,7 @@ static ssize_t value_store(struct device *dev,
return status; 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) static irqreturn_t gpio_sysfs_irq(int irq, void *priv)
{ {
...@@ -474,11 +485,15 @@ static ssize_t export_store(struct class *class, ...@@ -474,11 +485,15 @@ static ssize_t export_store(struct class *class,
status = -ENODEV; status = -ENODEV;
goto done; goto done;
} }
status = gpiod_set_transitory(desc, false);
if (!status) {
status = gpiod_export(desc, true); status = gpiod_export(desc, true);
if (status < 0) if (status < 0)
gpiod_free(desc); gpiod_free(desc);
else else
set_bit(FLAG_SYSFS, &desc->flags); set_bit(FLAG_SYSFS, &desc->flags);
}
done: done:
if (status) if (status)
......
...@@ -162,7 +162,7 @@ EXPORT_SYMBOL_GPL(desc_to_gpio); ...@@ -162,7 +162,7 @@ EXPORT_SYMBOL_GPL(desc_to_gpio);
*/ */
struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc) 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 NULL;
return desc->gdev->chip; return desc->gdev->chip;
} }
...@@ -196,7 +196,7 @@ static int gpiochip_find_base(int ngpio) ...@@ -196,7 +196,7 @@ static int gpiochip_find_base(int ngpio)
* gpiod_get_direction - return the current direction of a GPIO * gpiod_get_direction - return the current direction of a GPIO
* @desc: GPIO to get the direction of * @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. * This function may sleep if gpiod_cansleep() is true.
*/ */
...@@ -460,6 +460,15 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip) ...@@ -460,6 +460,15 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
if (lflags & ~GPIOHANDLE_REQUEST_VALID_FLAGS) if (lflags & ~GPIOHANDLE_REQUEST_VALID_FLAGS)
return -EINVAL; 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. */ /* OPEN_DRAIN and OPEN_SOURCE flags only make sense for output mode. */
if (!(lflags & GPIOHANDLE_REQUEST_OUTPUT) && if (!(lflags & GPIOHANDLE_REQUEST_OUTPUT) &&
((lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN) || ((lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN) ||
...@@ -506,6 +515,10 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip) ...@@ -506,6 +515,10 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
if (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE) if (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE)
set_bit(FLAG_OPEN_SOURCE, &desc->flags); 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 * Lines have to be requested explicitly for input
* or output, else the line will be treated "as is". * 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) ...@@ -588,6 +601,9 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
* @events: KFIFO for the GPIO events * @events: KFIFO for the GPIO events
* @read_lock: mutex lock to protect reads from colliding with adding * @read_lock: mutex lock to protect reads from colliding with adding
* new events to the FIFO * 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 lineevent_state {
struct gpio_device *gdev; struct gpio_device *gdev;
...@@ -598,6 +614,7 @@ struct lineevent_state { ...@@ -598,6 +614,7 @@ struct lineevent_state {
wait_queue_head_t wait; wait_queue_head_t wait;
DECLARE_KFIFO(events, struct gpioevent_data, 16); DECLARE_KFIFO(events, struct gpioevent_data, 16);
struct mutex read_lock; struct mutex read_lock;
u64 timestamp;
}; };
#define GPIOEVENT_REQUEST_VALID_FLAGS \ #define GPIOEVENT_REQUEST_VALID_FLAGS \
...@@ -732,7 +749,10 @@ static irqreturn_t lineevent_irq_thread(int irq, void *p) ...@@ -732,7 +749,10 @@ static irqreturn_t lineevent_irq_thread(int irq, void *p)
struct gpioevent_data ge; struct gpioevent_data ge;
int ret, level; 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); level = gpiod_get_value_cansleep(le->desc);
if (le->eflags & GPIOEVENT_REQUEST_RISING_EDGE if (le->eflags & GPIOEVENT_REQUEST_RISING_EDGE
...@@ -760,6 +780,19 @@ static irqreturn_t lineevent_irq_thread(int irq, void *p) ...@@ -760,6 +780,19 @@ static irqreturn_t lineevent_irq_thread(int irq, void *p)
return IRQ_HANDLED; 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) static int lineevent_create(struct gpio_device *gdev, void __user *ip)
{ {
struct gpioevent_request eventreq; struct gpioevent_request eventreq;
...@@ -852,7 +885,7 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip) ...@@ -852,7 +885,7 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
/* Request a thread to read the events */ /* Request a thread to read the events */
ret = request_threaded_irq(le->irq, ret = request_threaded_irq(le->irq,
NULL, lineevent_irq_handler,
lineevent_irq_thread, lineevent_irq_thread,
irqflags, irqflags,
le->label, le->label,
...@@ -1050,7 +1083,7 @@ static void gpiodevice_release(struct device *dev) ...@@ -1050,7 +1083,7 @@ static void gpiodevice_release(struct device *dev)
list_del(&gdev->list); list_del(&gdev->list);
ida_simple_remove(&gpio_ida, gdev->id); ida_simple_remove(&gpio_ida, gdev->id);
kfree(gdev->label); kfree_const(gdev->label);
kfree(gdev->descs); kfree(gdev->descs);
kfree(gdev); kfree(gdev);
} }
...@@ -1159,10 +1192,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, ...@@ -1159,10 +1192,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
goto err_free_descs; goto err_free_descs;
} }
if (chip->label) gdev->label = kstrdup_const(chip->label ?: "unknown", GFP_KERNEL);
gdev->label = kstrdup(chip->label, GFP_KERNEL);
else
gdev->label = kstrdup("unknown", GFP_KERNEL);
if (!gdev->label) { if (!gdev->label) {
status = -ENOMEM; status = -ENOMEM;
goto err_free_descs; goto err_free_descs;
...@@ -1209,31 +1239,14 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, ...@@ -1209,31 +1239,14 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
struct gpio_desc *desc = &gdev->descs[i]; struct gpio_desc *desc = &gdev->descs[i];
desc->gdev = gdev; 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) { /* REVISIT: most hardware initializes GPIOs as inputs (often
/* * with pullups enabled) so power usage is minimized. Linux
* If we have .get_direction, set up the initial * code should set the gpio direction first thing; but until
* direction flag from the hardware. * it does, and in case chip->get_direction is not set, we may
*/ * expose the wrong direction in sysfs.
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); desc->flags = !chip->direction_input ? (1 << FLAG_IS_OUT) : 0;
}
} }
#ifdef CONFIG_PINCTRL #ifdef CONFIG_PINCTRL
...@@ -1283,7 +1296,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, ...@@ -1283,7 +1296,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
list_del(&gdev->list); list_del(&gdev->list);
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
err_free_label: err_free_label:
kfree(gdev->label); kfree_const(gdev->label);
err_free_descs: err_free_descs:
kfree(gdev->descs); kfree(gdev->descs);
err_free_gdev: err_free_gdev:
...@@ -1383,7 +1396,7 @@ static int devm_gpio_chip_match(struct device *dev, void *res, void *data) ...@@ -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. * @dev: the device pointer on which irq_chip belongs to.
* @chip: the chip to register, with chip->base initialized * @chip: the chip to register, with chip->base initialized
* @data: driver-private data associated with this chip * @data: driver-private data associated with this chip
...@@ -1510,7 +1523,7 @@ static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip) ...@@ -1510,7 +1523,7 @@ static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip)
gpiochip->irq.valid_mask = NULL; gpiochip->irq.valid_mask = NULL;
} }
static bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip, bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip,
unsigned int offset) unsigned int offset)
{ {
/* No mask means all valid */ /* No mask means all valid */
...@@ -1518,6 +1531,7 @@ static bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip, ...@@ -1518,6 +1531,7 @@ static bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip,
return true; return true;
return test_bit(offset, gpiochip->irq.valid_mask); 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 * 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) ...@@ -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 * macro to avoid endless duplication. If the desc is NULL it is an
* optional GPIO and calls should just bail out. * 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 { \ #define VALIDATE_DESC(desc) do { \
if (!desc) \ int __valid = validate_desc(desc, __func__); \
return 0; \ if (__valid <= 0) \
if (IS_ERR(desc)) { \ return __valid; \
pr_warn("%s: invalid GPIO (errorpointer)\n", __func__); \ } while (0)
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)
#define VALIDATE_DESC_VOID(desc) do { \ #define VALIDATE_DESC_VOID(desc) do { \
if (!desc) \ int __valid = validate_desc(desc, __func__); \
return; \ if (__valid <= 0) \
if (IS_ERR(desc)) { \
pr_warn("%s: invalid GPIO (errorpointer)\n", __func__); \
return; \ return; \
} \ } while (0)
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__); \
return; \
} } while (0)
int gpiod_request(struct gpio_desc *desc, const char *label) int gpiod_request(struct gpio_desc *desc, const char *label)
{ {
...@@ -2456,7 +2467,7 @@ EXPORT_SYMBOL_GPL(gpiod_direction_output_raw); ...@@ -2456,7 +2467,7 @@ EXPORT_SYMBOL_GPL(gpiod_direction_output_raw);
*/ */
int gpiod_direction_output(struct gpio_desc *desc, int value) int gpiod_direction_output(struct gpio_desc *desc, int value)
{ {
struct gpio_chip *gc = desc->gdev->chip; struct gpio_chip *gc;
int ret; int ret;
VALIDATE_DESC(desc); VALIDATE_DESC(desc);
...@@ -2473,6 +2484,7 @@ int gpiod_direction_output(struct gpio_desc *desc, int value) ...@@ -2473,6 +2484,7 @@ int gpiod_direction_output(struct gpio_desc *desc, int value)
return -EIO; return -EIO;
} }
gc = desc->gdev->chip;
if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) { if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) {
/* First see if we can enable open drain in hardware */ /* First see if we can enable open drain in hardware */
ret = gpio_set_drive_single_ended(gc, gpio_chip_hwgpio(desc), 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) ...@@ -2529,6 +2541,50 @@ int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce)
} }
EXPORT_SYMBOL_GPL(gpiod_set_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 * gpiod_is_active_low - test whether a GPIO is active-low or not
* @desc: the gpio descriptor to test * @desc: the gpio descriptor to test
...@@ -3129,8 +3185,7 @@ bool gpiochip_line_is_persistent(struct gpio_chip *chip, unsigned int offset) ...@@ -3129,8 +3185,7 @@ bool gpiochip_line_is_persistent(struct gpio_chip *chip, unsigned int offset)
if (offset >= chip->ngpio) if (offset >= chip->ngpio)
return false; return false;
return !test_bit(FLAG_SLEEP_MAY_LOSE_VALUE, return !test_bit(FLAG_TRANSITORY, &chip->gpiodev->descs[offset].flags);
&chip->gpiodev->descs[offset].flags);
} }
EXPORT_SYMBOL_GPL(gpiochip_line_is_persistent); EXPORT_SYMBOL_GPL(gpiochip_line_is_persistent);
...@@ -3565,8 +3620,10 @@ int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id, ...@@ -3565,8 +3620,10 @@ int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,
if (lflags & GPIO_OPEN_SOURCE) if (lflags & GPIO_OPEN_SOURCE)
set_bit(FLAG_OPEN_SOURCE, &desc->flags); 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... */ /* No particular flag request, return here... */
if (!(dflags & GPIOD_FLAGS_BIT_DIR_SET)) { if (!(dflags & GPIOD_FLAGS_BIT_DIR_SET)) {
...@@ -3606,6 +3663,8 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev, ...@@ -3606,6 +3663,8 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
struct gpio_desc *desc = NULL; struct gpio_desc *desc = NULL;
int status; int status;
enum gpio_lookup_flags lookupflags = 0; 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); 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, ...@@ -3634,7 +3693,11 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
return desc; 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) if (status < 0)
return ERR_PTR(status); return ERR_PTR(status);
...@@ -3649,18 +3712,89 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev, ...@@ -3649,18 +3712,89 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
} }
EXPORT_SYMBOL_GPL(gpiod_get_index); 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_get_named_gpiod - obtain a GPIO from firmware node
* @fwnode: handle of the firmware node * @fwnode: handle of the firmware node
* @propname: name of the firmware property representing the GPIO * @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 * @dflags: GPIO initialization flags
* @label: label to attach to the requested GPIO * @label: label to attach to the requested GPIO
* *
* This function can be used for drivers that get their configuration * 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 * underlying firmware interface and then makes sure that the GPIO
* descriptor is requested before it is returned to the caller. * 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, ...@@ -3677,53 +3811,35 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
{ {
struct gpio_desc *desc = ERR_PTR(-ENODEV); struct gpio_desc *desc = ERR_PTR(-ENODEV);
unsigned long lflags = 0; unsigned long lflags = 0;
bool active_low = false;
bool single_ended = false;
bool open_drain = false;
int ret; int ret;
if (!fwnode) if (!fwnode)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
if (is_of_node(fwnode)) { if (is_of_node(fwnode)) {
enum of_gpio_flags flags; desc = gpiod_get_from_of_node(to_of_node(fwnode),
propname, index,
desc = of_get_named_gpiod_flags(to_of_node(fwnode), propname, dflags,
index, &flags); label);
if (!IS_ERR(desc)) { return desc;
active_low = flags & OF_GPIO_ACTIVE_LOW;
single_ended = flags & OF_GPIO_SINGLE_ENDED;
open_drain = flags & OF_GPIO_OPEN_DRAIN;
}
} else if (is_acpi_node(fwnode)) { } else if (is_acpi_node(fwnode)) {
struct acpi_gpio_info info; struct acpi_gpio_info info;
desc = acpi_node_get_gpiod(fwnode, propname, index, &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)) if (IS_ERR(desc))
return desc; return desc;
ret = gpiod_request(desc, label); acpi_gpio_update_gpiod_flags(&dflags, &info);
if (ret)
return ERR_PTR(ret);
if (active_low) if (info.polarity == GPIO_ACTIVE_LOW)
lflags |= GPIO_ACTIVE_LOW; lflags |= GPIO_ACTIVE_LOW;
if (single_ended) {
if (open_drain)
lflags |= GPIO_OPEN_DRAIN;
else
lflags |= GPIO_OPEN_SOURCE;
} }
/* Currently only ACPI takes this path */
ret = gpiod_request(desc, label);
if (ret)
return ERR_PTR(ret);
ret = gpiod_configure_flags(desc, propname, lflags, dflags); ret = gpiod_configure_flags(desc, propname, lflags, dflags);
if (ret < 0) { if (ret < 0) {
gpiod_put(desc); gpiod_put(desc);
......
...@@ -58,7 +58,7 @@ struct gpio_device { ...@@ -58,7 +58,7 @@ struct gpio_device {
struct gpio_desc *descs; struct gpio_desc *descs;
int base; int base;
u16 ngpio; u16 ngpio;
char *label; const char *label;
void *data; void *data;
struct list_head list; struct list_head list;
...@@ -75,16 +75,20 @@ struct gpio_device { ...@@ -75,16 +75,20 @@ struct gpio_device {
/** /**
* struct acpi_gpio_info - ACPI GPIO specific information * struct acpi_gpio_info - ACPI GPIO specific information
* @adev: reference to ACPI device which consumes GPIO resource
* @flags: GPIO initialization flags * @flags: GPIO initialization flags
* @gpioint: if %true this GPIO is of type GpioInt otherwise type is GpioIo * @gpioint: if %true this GPIO is of type GpioInt otherwise type is GpioIo
* @polarity: interrupt polarity as provided by ACPI * @polarity: interrupt polarity as provided by ACPI
* @triggering: triggering type 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_gpio_info {
struct acpi_device *adev;
enum gpiod_flags flags; enum gpiod_flags flags;
bool gpioint; bool gpioint;
int polarity; int polarity;
int triggering; int triggering;
unsigned int quirks;
}; };
/* gpio suffixes used for ACPI and device tree lookup */ /* gpio suffixes used for ACPI and device tree lookup */
...@@ -124,7 +128,7 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip); ...@@ -124,7 +128,7 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip);
void acpi_gpiochip_free_interrupts(struct gpio_chip *chip); void acpi_gpiochip_free_interrupts(struct gpio_chip *chip);
int acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, 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, struct gpio_desc *acpi_find_gpio(struct device *dev,
const char *con_id, const char *con_id,
...@@ -149,7 +153,7 @@ static inline void ...@@ -149,7 +153,7 @@ static inline void
acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { } acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { }
static inline int 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; return 0;
} }
...@@ -189,6 +193,12 @@ void gpiod_set_array_value_complex(bool raw, bool can_sleep, ...@@ -189,6 +193,12 @@ void gpiod_set_array_value_complex(bool raw, bool can_sleep,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_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 spinlock gpio_lock;
extern struct list_head gpio_devices; extern struct list_head gpio_devices;
...@@ -205,7 +215,7 @@ struct gpio_desc { ...@@ -205,7 +215,7 @@ struct gpio_desc {
#define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */ #define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */
#define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */ #define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */
#define FLAG_IS_HOGGED 11 /* GPIO is hogged */ #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 */ /* Connection label */
const char *label; const char *label;
......
...@@ -63,6 +63,16 @@ config PINCTRL_AS3722 ...@@ -63,6 +63,16 @@ config PINCTRL_AS3722
open drain configuration for the GPIO pins of AS3722 devices. It also open drain configuration for the GPIO pins of AS3722 devices. It also
supports the GPIO functionality through gpiolib. 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 config PINCTRL_BF54x
def_bool y if BF54x def_bool y if BF54x
select PINCTRL_ADI2 select PINCTRL_ADI2
......
...@@ -11,6 +11,7 @@ obj-$(CONFIG_GENERIC_PINCONF) += pinconf-generic.o ...@@ -11,6 +11,7 @@ obj-$(CONFIG_GENERIC_PINCONF) += pinconf-generic.o
obj-$(CONFIG_PINCTRL_ADI2) += pinctrl-adi2.o obj-$(CONFIG_PINCTRL_ADI2) += pinctrl-adi2.o
obj-$(CONFIG_PINCTRL_ARTPEC6) += pinctrl-artpec6.o obj-$(CONFIG_PINCTRL_ARTPEC6) += pinctrl-artpec6.o
obj-$(CONFIG_PINCTRL_AS3722) += pinctrl-as3722.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_BF54x) += pinctrl-adi2-bf54x.o
obj-$(CONFIG_PINCTRL_BF60x) += pinctrl-adi2-bf60x.o obj-$(CONFIG_PINCTRL_BF60x) += pinctrl-adi2-bf60x.o
obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o
......
/*
* 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");
...@@ -13,9 +13,8 @@ ...@@ -13,9 +13,8 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/w1-gpio.h> #include <linux/w1-gpio.h>
#include <linux/gpio.h> #include <linux/gpio/consumer.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/of_gpio.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/delay.h> #include <linux/delay.h>
...@@ -30,11 +29,17 @@ static u8 w1_gpio_set_pullup(void *data, int delay) ...@@ -30,11 +29,17 @@ static u8 w1_gpio_set_pullup(void *data, int delay)
pdata->pullup_duration = delay; pdata->pullup_duration = delay;
} else { } else {
if (pdata->pullup_duration) { 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); 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; pdata->pullup_duration = 0;
} }
...@@ -42,28 +47,18 @@ static u8 w1_gpio_set_pullup(void *data, int delay) ...@@ -42,28 +47,18 @@ static u8 w1_gpio_set_pullup(void *data, int delay)
return 0; return 0;
} }
static void w1_gpio_write_bit_dir(void *data, u8 bit) static void w1_gpio_write_bit(void *data, u8 bit)
{ {
struct w1_gpio_platform_data *pdata = data; struct w1_gpio_platform_data *pdata = data;
if (bit) gpiod_set_value(pdata->gpiod, bit);
gpio_direction_input(pdata->pin);
else
gpio_direction_output(pdata->pin, 0);
}
static void w1_gpio_write_bit_val(void *data, u8 bit)
{
struct w1_gpio_platform_data *pdata = data;
gpio_set_value(pdata->pin, bit);
} }
static u8 w1_gpio_read_bit(void *data) static u8 w1_gpio_read_bit(void *data)
{ {
struct w1_gpio_platform_data *pdata = 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) #if defined(CONFIG_OF)
...@@ -74,107 +69,85 @@ static const struct of_device_id w1_gpio_dt_ids[] = { ...@@ -74,107 +69,85 @@ static const struct of_device_id w1_gpio_dt_ids[] = {
MODULE_DEVICE_TABLE(of, w1_gpio_dt_ids); MODULE_DEVICE_TABLE(of, w1_gpio_dt_ids);
#endif #endif
static int w1_gpio_probe_dt(struct platform_device *pdev) static int w1_gpio_probe(struct platform_device *pdev)
{ {
struct w1_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev); struct w1_bus_master *master;
struct device_node *np = pdev->dev.of_node; struct w1_gpio_platform_data *pdata;
int gpio; 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()) {
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) if (!pdata)
return -ENOMEM; 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)) if (of_get_property(np, "linux,open-drain", NULL))
pdata->is_open_drain = 1; gflags = GPIOD_OUT_LOW;
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; 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;
int err;
if (of_have_populated_dt()) {
err = w1_gpio_probe_dt(pdev);
if (err < 0)
return err;
} }
pdata = dev_get_platdata(dev);
pdata = dev_get_platdata(&pdev->dev);
if (!pdata) { if (!pdata) {
dev_err(&pdev->dev, "No configuration data\n"); dev_err(dev, "No configuration data\n");
return -ENXIO; return -ENXIO;
} }
master = devm_kzalloc(&pdev->dev, sizeof(struct w1_bus_master), master = devm_kzalloc(dev, sizeof(struct w1_bus_master),
GFP_KERNEL); GFP_KERNEL);
if (!master) { if (!master) {
dev_err(&pdev->dev, "Out of memory\n"); dev_err(dev, "Out of memory\n");
return -ENOMEM; return -ENOMEM;
} }
err = devm_gpio_request(&pdev->dev, pdata->pin, "w1"); pdata->gpiod = devm_gpiod_get_index(dev, NULL, 0, gflags);
if (err) { if (IS_ERR(pdata->gpiod)) {
dev_err(&pdev->dev, "gpio_request (pin) failed\n"); dev_err(dev, "gpio_request (pin) failed\n");
return err; return PTR_ERR(pdata->gpiod);
} }
if (gpio_is_valid(pdata->ext_pullup_enable_pin)) { pdata->pullup_gpiod =
err = devm_gpio_request_one(&pdev->dev, devm_gpiod_get_index_optional(dev, NULL, 1, GPIOD_OUT_LOW);
pdata->ext_pullup_enable_pin, GPIOF_INIT_LOW, if (IS_ERR(pdata->pullup_gpiod)) {
"w1 pullup"); dev_err(dev, "gpio_request_one "
if (err < 0) {
dev_err(&pdev->dev, "gpio_request_one "
"(ext_pullup_enable_pin) failed\n"); "(ext_pullup_enable_pin) failed\n");
return err; return PTR_ERR(pdata->pullup_gpiod);
}
} }
master->data = pdata; master->data = pdata;
master->read_bit = w1_gpio_read_bit; master->read_bit = w1_gpio_read_bit;
gpiod_direction_output(pdata->gpiod, 1);
if (pdata->is_open_drain) { master->write_bit = w1_gpio_write_bit;
gpio_direction_output(pdata->pin, 1);
master->write_bit = w1_gpio_write_bit_val; /*
} else { * If we are using open drain emulation from the GPIO library,
gpio_direction_input(pdata->pin); * we need to use this pullup function that hammers the line
master->write_bit = w1_gpio_write_bit_dir; * 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; master->set_pullup = w1_gpio_set_pullup;
}
err = w1_add_master_device(master); err = w1_add_master_device(master);
if (err) { if (err) {
dev_err(&pdev->dev, "w1_add_master device failed\n"); dev_err(dev, "w1_add_master device failed\n");
return err; return err;
} }
if (pdata->enable_external_pullup) if (pdata->enable_external_pullup)
pdata->enable_external_pullup(1); pdata->enable_external_pullup(1);
if (gpio_is_valid(pdata->ext_pullup_enable_pin)) if (pdata->pullup_gpiod)
gpio_set_value(pdata->ext_pullup_enable_pin, 1); gpiod_set_value(pdata->pullup_gpiod, 1);
platform_set_drvdata(pdev, master); platform_set_drvdata(pdev, master);
...@@ -189,8 +162,8 @@ static int w1_gpio_remove(struct platform_device *pdev) ...@@ -189,8 +162,8 @@ static int w1_gpio_remove(struct platform_device *pdev)
if (pdata->enable_external_pullup) if (pdata->enable_external_pullup)
pdata->enable_external_pullup(0); pdata->enable_external_pullup(0);
if (gpio_is_valid(pdata->ext_pullup_enable_pin)) if (pdata->pullup_gpiod)
gpio_set_value(pdata->ext_pullup_enable_pin, 0); gpiod_set_value(pdata->pullup_gpiod, 0);
w1_remove_master_device(master); w1_remove_master_device(master);
......
...@@ -29,8 +29,8 @@ ...@@ -29,8 +29,8 @@
#define GPIO_OPEN_DRAIN (GPIO_SINGLE_ENDED | GPIO_LINE_OPEN_DRAIN) #define GPIO_OPEN_DRAIN (GPIO_SINGLE_ENDED | GPIO_LINE_OPEN_DRAIN)
#define GPIO_OPEN_SOURCE (GPIO_SINGLE_ENDED | GPIO_LINE_OPEN_SOURCE) #define GPIO_OPEN_SOURCE (GPIO_SINGLE_ENDED | GPIO_LINE_OPEN_SOURCE)
/* Bit 3 express GPIO suspend/resume persistence */ /* Bit 3 express GPIO suspend/resume and reset persistence */
#define GPIO_SLEEP_MAINTAIN_VALUE 0 #define GPIO_PERSISTENT 0
#define GPIO_SLEEP_MAY_LOSE_VALUE 8 #define GPIO_TRANSITORY 8
#endif #endif
...@@ -991,6 +991,11 @@ struct acpi_gpio_mapping { ...@@ -991,6 +991,11 @@ struct acpi_gpio_mapping {
const char *name; const char *name;
const struct acpi_gpio_params *data; const struct acpi_gpio_params *data;
unsigned int size; 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) #if defined(CONFIG_ACPI) && defined(CONFIG_GPIOLIB)
......
...@@ -575,6 +575,9 @@ ssize_t device_store_bool(struct device *dev, struct device_attribute *attr, ...@@ -575,6 +575,9 @@ ssize_t device_store_bool(struct device *dev, struct device_attribute *attr,
#define DEVICE_ATTR(_name, _mode, _show, _store) \ #define DEVICE_ATTR(_name, _mode, _show, _store) \
struct device_attribute dev_attr_##_name = __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) \ #define DEVICE_ATTR_RW(_name) \
struct device_attribute dev_attr_##_name = __ATTR_RW(_name) struct device_attribute dev_attr_##_name = __ATTR_RW(_name)
#define DEVICE_ATTR_RO(_name) \ #define DEVICE_ATTR_RO(_name) \
......
/* SPDX-License-Identifier: GPL-2.0 */ /* 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 #ifndef __LINUX_GPIO_H
#define __LINUX_GPIO_H #define __LINUX_GPIO_H
......
...@@ -139,6 +139,7 @@ void gpiod_set_raw_array_value_cansleep(unsigned int array_size, ...@@ -139,6 +139,7 @@ void gpiod_set_raw_array_value_cansleep(unsigned int array_size,
int *value_array); int *value_array);
int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce); 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_is_active_low(const struct gpio_desc *desc);
int gpiod_cansleep(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); ...@@ -150,8 +151,14 @@ struct gpio_desc *gpio_to_desc(unsigned gpio);
int desc_to_gpio(const struct gpio_desc *desc); int desc_to_gpio(const struct gpio_desc *desc);
/* Child properties interface */ /* Child properties interface */
struct device_node;
struct fwnode_handle; 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, struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
const char *propname, int index, const char *propname, int index,
enum gpiod_flags dflags, enum gpiod_flags dflags,
...@@ -431,6 +438,13 @@ static inline int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) ...@@ -431,6 +438,13 @@ static inline int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce)
return -ENOSYS; 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) static inline int gpiod_is_active_low(const struct gpio_desc *desc)
{ {
/* GPIO can never have been requested */ /* GPIO can never have been requested */
...@@ -464,8 +478,19 @@ static inline int desc_to_gpio(const struct gpio_desc *desc) ...@@ -464,8 +478,19 @@ static inline int desc_to_gpio(const struct gpio_desc *desc)
} }
/* Child properties interface */ /* Child properties interface */
struct device_node;
struct fwnode_handle; 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 static inline
struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
const char *propname, int index, const char *propname, int index,
......
...@@ -436,6 +436,9 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip, ...@@ -436,6 +436,9 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
struct lock_class_key *lock_key, struct lock_class_key *lock_key,
struct lock_class_key *request_key); struct lock_class_key *request_key);
bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip,
unsigned int offset);
#ifdef CONFIG_LOCKDEP #ifdef CONFIG_LOCKDEP
/* /*
......
...@@ -10,8 +10,8 @@ enum gpio_lookup_flags { ...@@ -10,8 +10,8 @@ enum gpio_lookup_flags {
GPIO_ACTIVE_LOW = (1 << 0), GPIO_ACTIVE_LOW = (1 << 0),
GPIO_OPEN_DRAIN = (1 << 1), GPIO_OPEN_DRAIN = (1 << 1),
GPIO_OPEN_SOURCE = (1 << 2), GPIO_OPEN_SOURCE = (1 << 2),
GPIO_SLEEP_MAINTAIN_VALUE = (0 << 3), GPIO_PERSISTENT = (0 << 3),
GPIO_SLEEP_MAY_LOSE_VALUE = (1 << 3), GPIO_TRANSITORY = (1 << 3),
}; };
/** /**
......
...@@ -31,7 +31,7 @@ enum of_gpio_flags { ...@@ -31,7 +31,7 @@ enum of_gpio_flags {
OF_GPIO_ACTIVE_LOW = 0x1, OF_GPIO_ACTIVE_LOW = 0x1,
OF_GPIO_SINGLE_ENDED = 0x2, OF_GPIO_SINGLE_ENDED = 0x2,
OF_GPIO_OPEN_DRAIN = 0x4, OF_GPIO_OPEN_DRAIN = 0x4,
OF_GPIO_SLEEP_MAY_LOSE_VALUE = 0x8, OF_GPIO_TRANSITORY = 0x8,
}; };
#ifdef CONFIG_OF_GPIO #ifdef CONFIG_OF_GPIO
......
...@@ -94,6 +94,7 @@ ...@@ -94,6 +94,7 @@
* or latch delay (on outputs) this parameter (in a custom format) * or latch delay (on outputs) this parameter (in a custom format)
* specifies the clock skew or latch delay. It typically controls how * specifies the clock skew or latch delay. It typically controls how
* many double inverters are put in front of the line. * 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 * @PIN_CONFIG_END: this is the last enumerator for pin configurations, if
* you need to pass in custom configurations to the pin controller, use * you need to pass in custom configurations to the pin controller, use
* PIN_CONFIG_END+1 as the base offset. * PIN_CONFIG_END+1 as the base offset.
...@@ -122,6 +123,7 @@ enum pin_config_param { ...@@ -122,6 +123,7 @@ enum pin_config_param {
PIN_CONFIG_SLEEP_HARDWARE_STATE, PIN_CONFIG_SLEEP_HARDWARE_STATE,
PIN_CONFIG_SLEW_RATE, PIN_CONFIG_SLEW_RATE,
PIN_CONFIG_SKEW_DELAY, PIN_CONFIG_SKEW_DELAY,
PIN_CONFIG_PERSIST_STATE,
PIN_CONFIG_END = 0x7F, PIN_CONFIG_END = 0x7F,
PIN_CONFIG_MAX = 0xFF, PIN_CONFIG_MAX = 0xFF,
}; };
......
...@@ -10,16 +10,15 @@ ...@@ -10,16 +10,15 @@
#ifndef _LINUX_W1_GPIO_H #ifndef _LINUX_W1_GPIO_H
#define _LINUX_W1_GPIO_H #define _LINUX_W1_GPIO_H
struct gpio_desc;
/** /**
* struct w1_gpio_platform_data - Platform-dependent data for w1-gpio * 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 { struct w1_gpio_platform_data {
unsigned int pin; struct gpio_desc *gpiod;
unsigned int is_open_drain:1; struct gpio_desc *pullup_gpiod;
void (*enable_external_pullup)(int enable); void (*enable_external_pullup)(int enable);
unsigned int ext_pullup_enable_pin;
unsigned int pullup_duration; unsigned int pullup_duration;
}; };
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <unistd.h> #include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <dirent.h> #include <dirent.h>
#include <errno.h> #include <errno.h>
...@@ -23,12 +24,13 @@ ...@@ -23,12 +24,13 @@
#include <getopt.h> #include <getopt.h>
#include <inttypes.h> #include <inttypes.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/types.h>
#include <linux/gpio.h> #include <linux/gpio.h>
int monitor_device(const char *device_name, int monitor_device(const char *device_name,
unsigned int line, unsigned int line,
u_int32_t handleflags, uint32_t handleflags,
u_int32_t eventflags, uint32_t eventflags,
unsigned int loops) unsigned int loops)
{ {
struct gpioevent_request req; struct gpioevent_request req;
...@@ -145,8 +147,8 @@ int main(int argc, char **argv) ...@@ -145,8 +147,8 @@ int main(int argc, char **argv)
const char *device_name = NULL; const char *device_name = NULL;
unsigned int line = -1; unsigned int line = -1;
unsigned int loops = 0; unsigned int loops = 0;
u_int32_t handleflags = GPIOHANDLE_REQUEST_INPUT; uint32_t handleflags = GPIOHANDLE_REQUEST_INPUT;
u_int32_t eventflags = 0; uint32_t eventflags = 0;
int c; int c;
while ((c = getopt(argc, argv, "c:n:o:dsrf?")) != -1) { while ((c = getopt(argc, argv, "c:n:o:dsrf?")) != -1) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment