summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-06-16 07:30:52 +0530
committerLinus Torvalds <torvalds@linux-foundation.org>2026-06-16 07:30:52 +0530
commit77d084d66b7694e2a912abdd8b9e5a0e7a32d28e (patch)
tree1b21610ec0bfccc6fd4254c66b8ee0641c2c4333
parent6b617c82580599994c8dd078ab0dcb0375b42eda (diff)
parentf953585dafd71ecb0897f9def9c0a3702afc1bf8 (diff)
Merge tag 'gpio-updates-for-v7.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux
Pull gpio updates from Bartosz Golaszewski: "There's one new driver, one legacy driver removed, a kunit test-suite for the GPIO core, support for new models in existing drivers and a slew of various changes in many places though I can't think of anything controversial that would stand out - it's been a relatively calm cycle. GPIO core: - Add an initial set of kunit test cases for the GPIO subsystem - Use the devres owner as the GPIO chip's parent in absence of any other parent - Fix const-correctness of GPIO chip SRCU guards - Provide new GPIO consumer interfaces: gpiod_is_single_ended() and fwnode_gpiod_get() - Quarantine all legacy GPIO APIs in linux/gpio/legacy.h - Use __ro_after_init where applicable New drivers: - Add driver for the GPIO controller on Waveshare DSI TOUCH panels Removed drivers: - Remove the obsolete ts5500 GPIO driver Driver updates: - Modernize gpio-timberdale: remove platform data support and use generic device property accessors - Extend test build coverage by enabling COMPILE_TEST for more GPIO drivers - Add some missing dependencies in Kconfig - Add support for sparse fixed direction to gpio-regmap - Remove dead code from gpio-nomadik - use BIT() in gpio-mxc - use bitmap_complement() in gpio-xilinx and gpio-pca953x - Use more appropriate printing functions where applicable - Use named initializers for platform_device_id and i2c_device_id arrays - Convert gpio-altera to using the generic GPIO chip helper library - Add support for new models to gpio-dwapb, gpio-zynq, gpio-usbio and gpio-tegra186 - Unify the naming convention for Qualcomm in GPIO drivers - Fix interrupt bank mapping to GPIO chips in gpio-mt7621 - Add support for the lines-initial-states property to gpio-74x164 - Switch to using dynamic GPIO base in gpio-ixp4xx - Move the handling of an OF quirk from ASoC to gpiolib-of.c where other such quirks live - Use handle_bad_irq() in gpio-ep93xx - Some other minor tweaks and refactorings Devicetree bindings: - Document the Waveshare GPIO controller for DSI TOUCH panels - Document new models: Tegra238 in gpio-tegra186 and EIO GPIO in gpio-zynq - Add new properties for gpio-dwapb and fairchild,74hc595 - Fix whitespace issues - Sort compatibles alphabetically in gpio-zynq Documentation: - Fix kerneldoc warnings in gpio-realtek-otto Misc: - Attach software nodes representing GPIO chips to the actual struct device objects associated with them in some legacy platforms enabling real firmware node lookup instead of string matching - Drop unneeded dependencies on OF_GPIO from bus and staging drivers" * tag 'gpio-updates-for-v7.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux: (62 commits) gpio: nomadik: remove dead DB8540 code from <gpio/gpio-nomadik.h> gpio: mt7621: fix interrupt banks mapping on gpio chips bus: ts-nbus: drop unneeded dependency on OF_GPIO staging: media: max96712: drop unneeded dependency on OF_GPIO gpiolib: Replace strcpy() with memcpy() gpio: remove obsolete UAF FIXMEs from lookup paths gpio: core: fix const-correctness of gpio_chip_guard gpio: mxc: use BIT() macro gpio: realtek-otto: fix kernel-doc warnings gpio: max77620: Unify usage of space and comma in platform_device_id array gpio: Use named initializers for platform_device_id arrays gpio: cros-ec: Drop unused assignment of platform_device_id driver data ARM: omap1: enable real software node lookup of GPIOs on Nokia 770 ARM: omap1: use platform_device_register_full() for GPIO devices on OMAP 16xx ARM: omap1: drop unused variable from omap16xx_gpio_init() gpio: gpiolib: use seq_puts() for plain strings gpio: ts5500: remove obsolete driver gpio: add kunit test cases for the GPIO subsystem kunit: provide kunit_platform_device_unregister() kunit: provide kunit_platform_device_register_full() ...
-rw-r--r--Documentation/devicetree/bindings/gpio/fairchild,74hc595.yaml13
-rw-r--r--Documentation/devicetree/bindings/gpio/gpio-zynq.yaml17
-rw-r--r--Documentation/devicetree/bindings/gpio/nvidia,tegra186-gpio.yaml6
-rw-r--r--Documentation/devicetree/bindings/gpio/snps,dw-apb-gpio.yaml6
-rw-r--r--Documentation/devicetree/bindings/gpio/waveshare,dsi-touch-gpio.yaml73
-rw-r--r--arch/arm/mach-omap1/board-nokia770.c33
-rw-r--r--arch/arm/mach-omap1/common.h3
-rw-r--r--arch/arm/mach-omap1/gpio16xx.c80
-rw-r--r--drivers/bus/Kconfig2
-rw-r--r--drivers/gpio/Kconfig39
-rw-r--r--drivers/gpio/Makefile3
-rw-r--r--drivers/gpio/gpio-74x164.c17
-rw-r--r--drivers/gpio/gpio-adnp.c4
-rw-r--r--drivers/gpio/gpio-adp5585.c4
-rw-r--r--drivers/gpio/gpio-altera.c124
-rw-r--r--drivers/gpio/gpio-amd8111.c4
-rw-r--r--drivers/gpio/gpio-bd72720.c4
-rw-r--r--drivers/gpio/gpio-bd9571mwv.c4
-rw-r--r--drivers/gpio/gpio-cros-ec.c4
-rw-r--r--drivers/gpio/gpio-ds4520.c2
-rw-r--r--drivers/gpio/gpio-dwapb.c1
-rw-r--r--drivers/gpio/gpio-ep93xx.c3
-rw-r--r--drivers/gpio/gpio-fxl6408.c2
-rw-r--r--drivers/gpio/gpio-gw-pld.c2
-rw-r--r--drivers/gpio/gpio-ixp4xx.c7
-rw-r--r--drivers/gpio/gpio-lp873x.c2
-rw-r--r--drivers/gpio/gpio-lp87565.c2
-rw-r--r--drivers/gpio/gpio-max7300.c2
-rw-r--r--drivers/gpio/gpio-max732x.c20
-rw-r--r--drivers/gpio/gpio-max77620.c2
-rw-r--r--drivers/gpio/gpio-max77759.c2
-rw-r--r--drivers/gpio/gpio-mt7621.c282
-rw-r--r--drivers/gpio/gpio-mxc.c4
-rw-r--r--drivers/gpio/gpio-pca953x.c87
-rw-r--r--drivers/gpio/gpio-pca9570.c6
-rw-r--r--drivers/gpio/gpio-pcf857x.c26
-rw-r--r--drivers/gpio/gpio-pxa.c18
-rw-r--r--drivers/gpio/gpio-realtek-otto.c6
-rw-r--r--drivers/gpio/gpio-regmap.c74
-rw-r--r--drivers/gpio/gpio-sim.c24
-rw-r--r--drivers/gpio/gpio-tegra186.c69
-rw-r--r--drivers/gpio/gpio-timberdale.c26
-rw-r--r--drivers/gpio/gpio-tpic2810.c2
-rw-r--r--drivers/gpio/gpio-tps65086.c2
-rw-r--r--drivers/gpio/gpio-tps65218.c2
-rw-r--r--drivers/gpio/gpio-tps65219.c4
-rw-r--r--drivers/gpio/gpio-tps65912.c2
-rw-r--r--drivers/gpio/gpio-ts4900.c2
-rw-r--r--drivers/gpio/gpio-ts5500.c446
-rw-r--r--drivers/gpio/gpio-usbio.c1
-rw-r--r--drivers/gpio/gpio-waveshare-dsi.c208
-rw-r--r--drivers/gpio/gpio-xilinx.c6
-rw-r--r--drivers/gpio/gpio-zevio.c4
-rw-r--r--drivers/gpio/gpio-zynq.c12
-rw-r--r--drivers/gpio/gpiolib-acpi-core.c4
-rw-r--r--drivers/gpio/gpiolib-devres.c7
-rw-r--r--drivers/gpio/gpiolib-kunit.c358
-rw-r--r--drivers/gpio/gpiolib-of.c8
-rw-r--r--drivers/gpio/gpiolib-swnode.c4
-rw-r--r--drivers/gpio/gpiolib.c66
-rw-r--r--drivers/gpio/gpiolib.h2
-rw-r--r--drivers/mfd/timberdale.c33
-rw-r--r--drivers/mfd/timberdale.h1
-rw-r--r--drivers/staging/media/max96712/Kconfig1
-rw-r--r--include/dt-bindings/gpio/meson-axg-gpio.h4
-rw-r--r--include/dt-bindings/gpio/nvidia,tegra238-gpio.h58
-rw-r--r--include/kunit/platform_device.h6
-rw-r--r--include/linux/gpio.h162
-rw-r--r--include/linux/gpio/consumer.h14
-rw-r--r--include/linux/gpio/gpio-nomadik.h16
-rw-r--r--include/linux/gpio/legacy.h173
-rw-r--r--include/linux/gpio/regmap.h7
-rw-r--r--include/linux/timb_gpio.h25
-rw-r--r--lib/kunit/platform.c64
-rw-r--r--sound/soc/codecs/wsa881x.c35
75 files changed, 1721 insertions, 1127 deletions
diff --git a/Documentation/devicetree/bindings/gpio/fairchild,74hc595.yaml b/Documentation/devicetree/bindings/gpio/fairchild,74hc595.yaml
index 23410aeca300..451538df63f7 100644
--- a/Documentation/devicetree/bindings/gpio/fairchild,74hc595.yaml
+++ b/Documentation/devicetree/bindings/gpio/fairchild,74hc595.yaml
@@ -45,6 +45,18 @@ properties:
$ref: /schemas/types.yaml#/definitions/uint32
description: Number of daisy-chained shift registers
+ lines-initial-states:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ Bitmask that specifies the initial state of each output line, written
+ by the driver before the gpiochip is registered. Bit N corresponds to
+ GPIO line N, following the convention already documented for
+ nxp,pcf8575. Because the 74HC595/74LVC594 family is push-pull output
+ only, a bit set to zero drives the line low and a bit set to one
+ drives it high. The bitmask covers up to 32 lines (four cascaded
+ registers); outputs beyond that come up zeroed. When the property is
+ absent all outputs come up low, preserving the previous behaviour.
+
enable-gpios:
description: GPIO connected to the OE (Output Enable) pin.
maxItems: 1
@@ -79,6 +91,7 @@ examples:
gpio-controller;
#gpio-cells = <2>;
registers-number = <4>;
+ lines-initial-states = <0xffff0000>;
spi-max-frequency = <100000>;
};
};
diff --git a/Documentation/devicetree/bindings/gpio/gpio-zynq.yaml b/Documentation/devicetree/bindings/gpio/gpio-zynq.yaml
index 5e2496379a3c..de24bb361e9f 100644
--- a/Documentation/devicetree/bindings/gpio/gpio-zynq.yaml
+++ b/Documentation/devicetree/bindings/gpio/gpio-zynq.yaml
@@ -12,10 +12,11 @@ maintainers:
properties:
compatible:
enum:
+ - xlnx,eio-gpio-1.0
+ - xlnx,pmc-gpio-1.0
+ - xlnx,versal-gpio-1.0
- xlnx,zynq-gpio-1.0
- xlnx,zynqmp-gpio-1.0
- - xlnx,versal-gpio-1.0
- - xlnx,pmc-gpio-1.0
reg:
maxItems: 1
@@ -30,7 +31,7 @@ properties:
gpio-line-names:
description: strings describing the names of each gpio line
- minItems: 58
+ minItems: 52
maxItems: 174
interrupt-controller: true
@@ -89,6 +90,16 @@ allOf:
minItems: 116
maxItems: 116
+ - if:
+ properties:
+ compatible:
+ enum:
+ - xlnx,eio-gpio-1.0
+ then:
+ properties:
+ gpio-line-names:
+ maxItems: 52
+
required:
- compatible
- reg
diff --git a/Documentation/devicetree/bindings/gpio/nvidia,tegra186-gpio.yaml b/Documentation/devicetree/bindings/gpio/nvidia,tegra186-gpio.yaml
index 17748dd1015d..adeb3b3a2902 100644
--- a/Documentation/devicetree/bindings/gpio/nvidia,tegra186-gpio.yaml
+++ b/Documentation/devicetree/bindings/gpio/nvidia,tegra186-gpio.yaml
@@ -85,6 +85,8 @@ properties:
- nvidia,tegra194-gpio-aon
- nvidia,tegra234-gpio
- nvidia,tegra234-gpio-aon
+ - nvidia,tegra238-gpio
+ - nvidia,tegra238-gpio-aon
- nvidia,tegra256-gpio
- nvidia,tegra264-gpio
- nvidia,tegra264-gpio-uphy
@@ -163,6 +165,7 @@ allOf:
- nvidia,tegra186-gpio
- nvidia,tegra194-gpio
- nvidia,tegra234-gpio
+ - nvidia,tegra238-gpio
- nvidia,tegra256-gpio
- nvidia,tegra264-gpio
- nvidia,tegra264-gpio-uphy
@@ -180,6 +183,7 @@ allOf:
- nvidia,tegra186-gpio-aon
- nvidia,tegra194-gpio-aon
- nvidia,tegra234-gpio-aon
+ - nvidia,tegra238-gpio-aon
- nvidia,tegra264-gpio-aon
then:
properties:
@@ -192,6 +196,8 @@ allOf:
compatible:
contains:
enum:
+ - nvidia,tegra238-gpio
+ - nvidia,tegra238-gpio-aon
- nvidia,tegra264-gpio
- nvidia,tegra264-gpio-uphy
- nvidia,tegra264-gpio-aon
diff --git a/Documentation/devicetree/bindings/gpio/snps,dw-apb-gpio.yaml b/Documentation/devicetree/bindings/gpio/snps,dw-apb-gpio.yaml
index bba6f5b6606f..55069533f6d9 100644
--- a/Documentation/devicetree/bindings/gpio/snps,dw-apb-gpio.yaml
+++ b/Documentation/devicetree/bindings/gpio/snps,dw-apb-gpio.yaml
@@ -95,6 +95,12 @@ patternProperties:
'#interrupt-cells':
const: 2
+ patternProperties:
+ "^.+-hog(-[0-9]+)?$":
+ type: object
+ required:
+ - gpio-hog
+
required:
- compatible
- reg
diff --git a/Documentation/devicetree/bindings/gpio/waveshare,dsi-touch-gpio.yaml b/Documentation/devicetree/bindings/gpio/waveshare,dsi-touch-gpio.yaml
new file mode 100644
index 000000000000..091e1fffcd47
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/waveshare,dsi-touch-gpio.yaml
@@ -0,0 +1,73 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/gpio/waveshare,dsi-touch-gpio.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Waveshare GPIO controller on DSI TOUCH panels
+
+maintainers:
+ - Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
+
+description:
+ Waveshare DSI TOUCH panel kits contain separate GPIO controller for toggling
+ power supplies and panel / touchscreen resets.
+
+properties:
+ compatible:
+ const: waveshare,dsi-touch-gpio
+
+ reg:
+ maxItems: 1
+
+ gpio-controller: true
+
+ '#gpio-cells':
+ const: 2
+
+required:
+ - compatible
+ - reg
+ - gpio-controller
+ - "#gpio-cells"
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ wsgpio: gpio@45 {
+ compatible = "waveshare,dsi-touch-gpio";
+ reg = <0x45>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+ };
+
+ panel_avdd: regulator-panel-avdd {
+ compatible = "regulator-fixed";
+ regulator-name = "panel-avdd";
+ gpios = <&wsgpio 0 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
+ panel_iovcc: regulator-panel-iovcc {
+ compatible = "regulator-fixed";
+ regulator-name = "panel-iovcc";
+ gpios = <&wsgpio 4 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
+ panel_vcc: regulator-panel-vcc {
+ compatible = "regulator-fixed";
+ regulator-name = "panel-vcc";
+ gpios = <&wsgpio 8 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ regulator-always-on;
+ };
+...
diff --git a/arch/arm/mach-omap1/board-nokia770.c b/arch/arm/mach-omap1/board-nokia770.c
index a5bf5554800f..72d9e92a1071 100644
--- a/arch/arm/mach-omap1/board-nokia770.c
+++ b/arch/arm/mach-omap1/board-nokia770.c
@@ -36,27 +36,6 @@
#include "clock.h"
#include "mmc.h"
-static const struct software_node nokia770_mpuio_gpiochip_node = {
- .name = "mpuio",
-};
-
-static const struct software_node nokia770_gpiochip1_node = {
- .name = "gpio-0-15",
-};
-
-static const struct software_node nokia770_gpiochip2_node = {
- .name = "gpio-16-31",
-};
-
-static const struct software_node *nokia770_gpiochip_nodes[] = {
- &nokia770_mpuio_gpiochip_node,
- &nokia770_gpiochip1_node,
- &nokia770_gpiochip2_node,
- NULL
-};
-
-#define ADS7846_PENDOWN_GPIO 15
-
static const unsigned int nokia770_keymap[] = {
KEY(1, 0, GROUP_0 | KEY_UP),
KEY(2, 0, GROUP_1 | KEY_F5),
@@ -112,7 +91,7 @@ static const struct omap_lcd_config nokia770_lcd_config __initconst = {
};
static const struct property_entry nokia770_mipid_props[] = {
- PROPERTY_ENTRY_GPIO("reset-gpios", &nokia770_gpiochip1_node,
+ PROPERTY_ENTRY_GPIO("reset-gpios", &omap16xx_gpio1_swnode,
13, GPIO_ACTIVE_LOW),
{ }
};
@@ -138,8 +117,7 @@ static const struct property_entry nokia770_ads7846_props[] = {
PROPERTY_ENTRY_U16("ti,x-plate-ohms", 180),
PROPERTY_ENTRY_U16("ti,debounce-tol", 3),
PROPERTY_ENTRY_U16("ti,debounce-rep", 1),
- PROPERTY_ENTRY_GPIO("pendown-gpios", &nokia770_gpiochip1_node,
- ADS7846_PENDOWN_GPIO, GPIO_ACTIVE_LOW),
+ PROPERTY_ENTRY_GPIO("pendown-gpios", &omap16xx_gpio1_swnode, 15, GPIO_ACTIVE_LOW),
{ }
};
@@ -225,9 +203,9 @@ static inline void nokia770_mmc_init(void)
#if IS_ENABLED(CONFIG_I2C_CBUS_GPIO)
static const struct software_node_ref_args nokia770_cbus_gpio_refs[] = {
- SOFTWARE_NODE_REFERENCE(&nokia770_mpuio_gpiochip_node, 9, 0),
- SOFTWARE_NODE_REFERENCE(&nokia770_mpuio_gpiochip_node, 10, 0),
- SOFTWARE_NODE_REFERENCE(&nokia770_mpuio_gpiochip_node, 11, 0),
+ SOFTWARE_NODE_REFERENCE(&omap16xx_mpu_gpio_swnode, 9, 0),
+ SOFTWARE_NODE_REFERENCE(&omap16xx_mpu_gpio_swnode, 10, 0),
+ SOFTWARE_NODE_REFERENCE(&omap16xx_mpu_gpio_swnode, 11, 0),
};
static const struct property_entry nokia770_cbus_props[] = {
@@ -318,7 +296,6 @@ static void __init omap_nokia770_init(void)
/* Unmask SleepX signal */
omap_writew((omap_readw(0xfffb5004) & ~2), 0xfffb5004);
- software_node_register_node_group(nokia770_gpiochip_nodes);
platform_add_devices(nokia770_devices, ARRAY_SIZE(nokia770_devices));
gpiod_add_lookup_table(&nokia770_irq_gpio_table);
diff --git a/arch/arm/mach-omap1/common.h b/arch/arm/mach-omap1/common.h
index 7a7c3d9eb84a..c0f6e231fdb4 100644
--- a/arch/arm/mach-omap1/common.h
+++ b/arch/arm/mach-omap1/common.h
@@ -35,6 +35,9 @@
#include "soc.h"
#include "i2c.h"
+extern const struct software_node omap16xx_mpu_gpio_swnode;
+extern const struct software_node omap16xx_gpio1_swnode;
+
#ifdef CONFIG_OMAP_SERIAL_WAKE
int omap_serial_wakeup_init(void);
#else
diff --git a/arch/arm/mach-omap1/gpio16xx.c b/arch/arm/mach-omap1/gpio16xx.c
index 55acec22fef4..0f97972fd248 100644
--- a/arch/arm/mach-omap1/gpio16xx.c
+++ b/arch/arm/mach-omap1/gpio16xx.c
@@ -9,6 +9,7 @@
*/
#include <linux/platform_data/gpio-omap.h>
+#include <linux/property.h>
#include <linux/soc/ti/omap1-io.h>
#include "hardware.h"
@@ -55,14 +56,16 @@ static struct omap_gpio_platform_data omap16xx_mpu_gpio_config = {
.regs = &omap16xx_mpuio_regs,
};
-static struct platform_device omap16xx_mpu_gpio = {
+const struct software_node omap16xx_mpu_gpio_swnode = { };
+
+static const struct platform_device_info omap16xx_mpu_gpio = {
.name = "omap_gpio",
.id = 0,
- .dev = {
- .platform_data = &omap16xx_mpu_gpio_config,
- },
- .num_resources = ARRAY_SIZE(omap16xx_mpu_gpio_resources),
- .resource = omap16xx_mpu_gpio_resources,
+ .data = &omap16xx_mpu_gpio_config,
+ .size_data = sizeof(omap16xx_mpu_gpio_config),
+ .num_res = ARRAY_SIZE(omap16xx_mpu_gpio_resources),
+ .res = omap16xx_mpu_gpio_resources,
+ .swnode = &omap16xx_mpu_gpio_swnode,
};
/* gpio1 */
@@ -99,14 +102,16 @@ static struct omap_gpio_platform_data omap16xx_gpio1_config = {
.regs = &omap16xx_gpio_regs,
};
-static struct platform_device omap16xx_gpio1 = {
+const struct software_node omap16xx_gpio1_swnode = { };
+
+static const struct platform_device_info omap16xx_gpio1 = {
.name = "omap_gpio",
.id = 1,
- .dev = {
- .platform_data = &omap16xx_gpio1_config,
- },
- .num_resources = ARRAY_SIZE(omap16xx_gpio1_resources),
- .resource = omap16xx_gpio1_resources,
+ .data = &omap16xx_gpio1_config,
+ .size_data = sizeof(omap16xx_gpio1_config),
+ .num_res = ARRAY_SIZE(omap16xx_gpio1_resources),
+ .res = omap16xx_gpio1_resources,
+ .swnode = &omap16xx_gpio1_swnode,
};
/* gpio2 */
@@ -127,14 +132,13 @@ static struct omap_gpio_platform_data omap16xx_gpio2_config = {
.regs = &omap16xx_gpio_regs,
};
-static struct platform_device omap16xx_gpio2 = {
+static const struct platform_device_info omap16xx_gpio2 = {
.name = "omap_gpio",
.id = 2,
- .dev = {
- .platform_data = &omap16xx_gpio2_config,
- },
- .num_resources = ARRAY_SIZE(omap16xx_gpio2_resources),
- .resource = omap16xx_gpio2_resources,
+ .data = &omap16xx_gpio2_config,
+ .size_data = sizeof(omap16xx_gpio2_config),
+ .num_res = ARRAY_SIZE(omap16xx_gpio2_resources),
+ .res = omap16xx_gpio2_resources,
};
/* gpio3 */
@@ -155,14 +159,13 @@ static struct omap_gpio_platform_data omap16xx_gpio3_config = {
.regs = &omap16xx_gpio_regs,
};
-static struct platform_device omap16xx_gpio3 = {
+static const struct platform_device_info omap16xx_gpio3 = {
.name = "omap_gpio",
.id = 3,
- .dev = {
- .platform_data = &omap16xx_gpio3_config,
- },
- .num_resources = ARRAY_SIZE(omap16xx_gpio3_resources),
- .resource = omap16xx_gpio3_resources,
+ .data = &omap16xx_gpio3_config,
+ .size_data = sizeof(omap16xx_gpio3_config),
+ .num_res = ARRAY_SIZE(omap16xx_gpio3_resources),
+ .res = omap16xx_gpio3_resources,
};
/* gpio4 */
@@ -183,17 +186,16 @@ static struct omap_gpio_platform_data omap16xx_gpio4_config = {
.regs = &omap16xx_gpio_regs,
};
-static struct platform_device omap16xx_gpio4 = {
+static const struct platform_device_info omap16xx_gpio4 = {
.name = "omap_gpio",
.id = 4,
- .dev = {
- .platform_data = &omap16xx_gpio4_config,
- },
- .num_resources = ARRAY_SIZE(omap16xx_gpio4_resources),
- .resource = omap16xx_gpio4_resources,
+ .data = &omap16xx_gpio4_config,
+ .size_data = sizeof(omap16xx_gpio4_config),
+ .num_res = ARRAY_SIZE(omap16xx_gpio4_resources),
+ .res = omap16xx_gpio4_resources,
};
-static struct platform_device *omap16xx_gpio_dev[] __initdata = {
+static const struct platform_device_info *omap16xx_gpio_dev[] __initconst = {
&omap16xx_mpu_gpio,
&omap16xx_gpio1,
&omap16xx_gpio2,
@@ -210,9 +212,8 @@ static int __init omap16xx_gpio_init(void)
{
int i;
void __iomem *base;
- struct resource *res;
- struct platform_device *pdev;
- struct omap_gpio_platform_data *pdata;
+ const struct resource *res;
+ const struct platform_device_info *pdevinfo;
if (!cpu_is_omap16xx())
return -EINVAL;
@@ -225,25 +226,24 @@ static int __init omap16xx_gpio_init(void)
ULPD_CAM_CLK_CTRL);
for (i = 0; i < ARRAY_SIZE(omap16xx_gpio_dev); i++) {
- pdev = omap16xx_gpio_dev[i];
- pdata = pdev->dev.platform_data;
+ pdevinfo = omap16xx_gpio_dev[i];
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ res = &pdevinfo->res[0];
if (unlikely(!res)) {
- dev_err(&pdev->dev, "Invalid mem resource.\n");
+ pr_err("%s.%d: Invalid mem resource.\n", pdevinfo->name, pdevinfo->id);
return -ENODEV;
}
base = ioremap(res->start, resource_size(res));
if (unlikely(!base)) {
- dev_err(&pdev->dev, "ioremap failed.\n");
+ pr_err("%s.%d: ioremap failed.\n", pdevinfo->name, pdevinfo->id);
return -ENOMEM;
}
__raw_writel(SYSCONFIG_WORD, base + OMAP1610_GPIO_SYSCONFIG);
iounmap(base);
- platform_device_register(omap16xx_gpio_dev[i]);
+ platform_device_register_full(omap16xx_gpio_dev[i]);
}
return 0;
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
index 3181d8aa32a3..e4b1db809187 100644
--- a/drivers/bus/Kconfig
+++ b/drivers/bus/Kconfig
@@ -216,7 +216,7 @@ config TI_SYSC
config TS_NBUS
tristate "Technologic Systems NBUS Driver"
depends on SOC_IMX28
- depends on OF_GPIO && PWM
+ depends on PWM
help
Driver for the Technologic Systems NBUS which is used to interface
with the peripherals in the FPGA of the TS-4600 SoM.
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 020e51e30317..bbd0ebe2f131 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -102,6 +102,14 @@ config GPIO_CDEV_V1
This ABI version is deprecated.
Please use the latest ABI for new developments.
+config GPIO_KUNIT
+ tristate "Build GPIO Kunit test cases"
+ depends on KUNIT
+ default KUNIT_ALL_TESTS
+ help
+ Say Y here to build the module containing Kunit test cases verifying
+ the functionality of the GPIO subsystem.
+
config GPIO_GENERIC
depends on HAS_IOMEM # Only for IOMEM drivers
tristate
@@ -156,6 +164,7 @@ config GPIO_74XX_MMIO
config GPIO_ALTERA
tristate "Altera GPIO"
+ select GPIO_GENERIC
select GPIOLIB_IRQCHIP
help
Say Y or M here to build support for the Altera PIO device.
@@ -301,7 +310,7 @@ config GPIO_EM
config GPIO_EN7523
tristate "Airoha GPIO support"
- depends on ARCH_AIROHA
+ depends on ARCH_AIROHA || COMPILE_TEST
default ARCH_AIROHA
select GPIO_GENERIC
select GPIOLIB_IRQCHIP
@@ -698,7 +707,7 @@ config GPIO_SPACEMIT_K1
config GPIO_SPEAR_SPICS
bool "ST SPEAr13xx SPI Chip Select as GPIO support"
- depends on PLAT_SPEAR
+ depends on PLAT_SPEAR || COMPILE_TEST
select GENERIC_IRQ_CHIP
help
Say yes here to support ST SPEAr SPI Chip Select as GPIO device.
@@ -805,8 +814,18 @@ config GPIO_VISCONTI
help
Say yes here to support GPIO on Tohisba Visconti.
+config GPIO_WAVESHARE_DSI_TOUCH
+ tristate "Waveshare GPIO controller for DSI panels"
+ depends on BACKLIGHT_CLASS_DEVICE
+ depends on I2C
+ select REGMAP_I2C
+ help
+ Enable support for the GPIO and PWM controller found on Waveshare DSI
+ TOUCH panel kits. It provides GPIOs (used for regulator control and
+ resets) and backlight support.
+
config GPIO_WCD934X
- tristate "Qualcomm Technologies Inc WCD9340/WCD9341 GPIO controller driver"
+ tristate "Qualcomm WCD9340/WCD9341 GPIO controller driver"
depends on MFD_WCD934X
help
This driver is to support GPIO block found on the Qualcomm Technologies
@@ -814,7 +833,7 @@ config GPIO_WCD934X
config GPIO_XGENE
bool "APM X-Gene GPIO controller support"
- depends on ARM64
+ depends on ARM64 || COMPILE_TEST
help
This driver is to support the GPIO block within the APM X-Gene SoC
platform's generic flash controller. The GPIO pins are muxed with
@@ -858,7 +877,7 @@ config GPIO_XTENSA
config GPIO_ZEVIO
bool "LSI ZEVIO SoC memory mapped GPIOs"
- depends on ARM
+ depends on ARM || COMPILE_TEST
help
Say yes here to support the GPIO controller in LSI ZEVIO SoCs.
@@ -1093,15 +1112,6 @@ config GPIO_SCH311X
To compile this driver as a module, choose M here: the module will
be called gpio-sch311x.
-config GPIO_TS5500
- tristate "TS-5500 DIO blocks and compatibles"
- depends on TS5500 || COMPILE_TEST
- help
- This driver supports Digital I/O exposed by pin blocks found on some
- Technologic Systems platforms. It includes, but is not limited to, 3
- blocks of the TS-5500: DIO1, DIO2 and the LCD port, and the TS-5600
- LCD port.
-
config GPIO_WINBOND
tristate "Winbond Super I/O GPIO support"
select ISA_BUS_API
@@ -2060,6 +2070,7 @@ config GPIO_VIRTIO
config GPIO_SIM
tristate "GPIO Simulator Module"
+ depends on SYSFS
select IRQ_SIM
select CONFIGFS_FS
help
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index b267598b517d..8ec03c9aec20 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o
gpiolib-acpi-y := gpiolib-acpi-core.o gpiolib-acpi-quirks.o
obj-$(CONFIG_GPIOLIB) += gpiolib-swnode.o
obj-$(CONFIG_GPIO_SHARED) += gpiolib-shared.o
+obj-$(CONFIG_GPIO_KUNIT) += gpiolib-kunit.o
# Device drivers. Generally keep list sorted alphabetically
obj-$(CONFIG_GPIO_REGMAP) += gpio-regmap.o
@@ -194,7 +195,6 @@ obj-$(CONFIG_GPIO_TPS68470) += gpio-tps68470.o
obj-$(CONFIG_GPIO_TQMX86) += gpio-tqmx86.o
obj-$(CONFIG_GPIO_TS4800) += gpio-ts4800.o
obj-$(CONFIG_GPIO_TS4900) += gpio-ts4900.o
-obj-$(CONFIG_GPIO_TS5500) += gpio-ts5500.o
obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o
obj-$(CONFIG_GPIO_TWL6040) += gpio-twl6040.o
obj-$(CONFIG_GPIO_UNIPHIER) += gpio-uniphier.o
@@ -205,6 +205,7 @@ obj-$(CONFIG_GPIO_VIRTUSER) += gpio-virtuser.o
obj-$(CONFIG_GPIO_VIRTIO) += gpio-virtio.o
obj-$(CONFIG_GPIO_VISCONTI) += gpio-visconti.o
obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o
+obj-$(CONFIG_GPIO_WAVESHARE_DSI_TOUCH) += gpio-waveshare-dsi.o
obj-$(CONFIG_GPIO_WCD934X) += gpio-wcd934x.o
obj-$(CONFIG_GPIO_WHISKEY_COVE) += gpio-wcove.o
obj-$(CONFIG_GPIO_WINBOND) += gpio-winbond.o
diff --git a/drivers/gpio/gpio-74x164.c b/drivers/gpio/gpio-74x164.c
index c226524efeba..5ca61cf5206a 100644
--- a/drivers/gpio/gpio-74x164.c
+++ b/drivers/gpio/gpio-74x164.c
@@ -112,7 +112,7 @@ static int gen_74x164_probe(struct spi_device *spi)
{
struct device *dev = &spi->dev;
struct gen_74x164_chip *chip;
- u32 nregs;
+ u32 nregs, init_state;
int ret;
/*
@@ -134,6 +134,21 @@ static int gen_74x164_probe(struct spi_device *spi)
chip->registers = nregs;
+ /*
+ * Optionally seed the chain with a board-specified pattern so the
+ * outputs come up in a known state on the first SPI write. The
+ * property follows the nxp,pcf8575 convention where bit N maps to
+ * GPIO line N. On this output-only device, bit=0 drives the line
+ * low and bit=1 drives it high. The bitmask covers up to 32 lines;
+ * any further outputs come up zeroed by devm_kzalloc().
+ */
+ if (!device_property_read_u32(dev, "lines-initial-states", &init_state)) {
+ unsigned int i;
+
+ for (i = 0; i < min(nregs, 4U); i++)
+ chip->buffer[nregs - 1 - i] = (init_state >> (i * 8)) & 0xff;
+ }
+
chip->gpiod_oe = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW);
if (IS_ERR(chip->gpiod_oe))
return PTR_ERR(chip->gpiod_oe);
diff --git a/drivers/gpio/gpio-adnp.c b/drivers/gpio/gpio-adnp.c
index fe5bcaa90496..350feea2afa3 100644
--- a/drivers/gpio/gpio-adnp.c
+++ b/drivers/gpio/gpio-adnp.c
@@ -501,8 +501,8 @@ static int adnp_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id adnp_i2c_id[] = {
- { "gpio-adnp" },
- { },
+ { .name = "gpio-adnp" },
+ { }
};
MODULE_DEVICE_TABLE(i2c, adnp_i2c_id);
diff --git a/drivers/gpio/gpio-adp5585.c b/drivers/gpio/gpio-adp5585.c
index 0fd3cc26d017..6f10fc646008 100644
--- a/drivers/gpio/gpio-adp5585.c
+++ b/drivers/gpio/gpio-adp5585.c
@@ -507,8 +507,8 @@ static const struct adp5585_gpio_chip adp5589_gpio_chip_info = {
};
static const struct platform_device_id adp5585_gpio_id_table[] = {
- { "adp5585-gpio", (kernel_ulong_t)&adp5585_gpio_chip_info },
- { "adp5589-gpio", (kernel_ulong_t)&adp5589_gpio_chip_info },
+ { .name = "adp5585-gpio", .driver_data = (kernel_ulong_t)&adp5585_gpio_chip_info },
+ { .name = "adp5589-gpio", .driver_data = (kernel_ulong_t)&adp5589_gpio_chip_info },
{ /* Sentinel */ }
};
MODULE_DEVICE_TABLE(platform, adp5585_gpio_id_table);
diff --git a/drivers/gpio/gpio-altera.c b/drivers/gpio/gpio-altera.c
index 9508d764cce4..fe144360a88d 100644
--- a/drivers/gpio/gpio-altera.c
+++ b/drivers/gpio/gpio-altera.c
@@ -17,6 +17,7 @@
#include <linux/types.h>
#include <linux/gpio/driver.h>
+#include <linux/gpio/generic.h>
#define ALTERA_GPIO_MAX_NGPIO 32
#define ALTERA_GPIO_DATA 0x0
@@ -26,7 +27,7 @@
/**
* struct altera_gpio_chip
-* @gc : GPIO chip structure.
+* @chip : Generic GPIO chip structure.
* @regs : memory mapped IO address for the controller registers.
* @gpio_lock : synchronization lock so that new irq/set/get requests
* will be blocked until the current one completes.
@@ -34,7 +35,7 @@
* (rising, falling, both, high)
*/
struct altera_gpio_chip {
- struct gpio_chip gc;
+ struct gpio_generic_chip chip;
void __iomem *regs;
raw_spinlock_t gpio_lock;
int interrupt_trigger;
@@ -106,72 +107,6 @@ static unsigned int altera_gpio_irq_startup(struct irq_data *d)
return 0;
}
-static int altera_gpio_get(struct gpio_chip *gc, unsigned offset)
-{
- struct altera_gpio_chip *altera_gc = gpiochip_get_data(gc);
-
- return !!(readl(altera_gc->regs + ALTERA_GPIO_DATA) & BIT(offset));
-}
-
-static int altera_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
-{
- struct altera_gpio_chip *altera_gc = gpiochip_get_data(gc);
- unsigned long flags;
- unsigned int data_reg;
-
- raw_spin_lock_irqsave(&altera_gc->gpio_lock, flags);
- data_reg = readl(altera_gc->regs + ALTERA_GPIO_DATA);
- if (value)
- data_reg |= BIT(offset);
- else
- data_reg &= ~BIT(offset);
- writel(data_reg, altera_gc->regs + ALTERA_GPIO_DATA);
- raw_spin_unlock_irqrestore(&altera_gc->gpio_lock, flags);
-
- return 0;
-}
-
-static int altera_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
-{
- struct altera_gpio_chip *altera_gc = gpiochip_get_data(gc);
- unsigned long flags;
- unsigned int gpio_ddr;
-
- raw_spin_lock_irqsave(&altera_gc->gpio_lock, flags);
- /* Set pin as input, assumes software controlled IP */
- gpio_ddr = readl(altera_gc->regs + ALTERA_GPIO_DIR);
- gpio_ddr &= ~BIT(offset);
- writel(gpio_ddr, altera_gc->regs + ALTERA_GPIO_DIR);
- raw_spin_unlock_irqrestore(&altera_gc->gpio_lock, flags);
-
- return 0;
-}
-
-static int altera_gpio_direction_output(struct gpio_chip *gc,
- unsigned offset, int value)
-{
- struct altera_gpio_chip *altera_gc = gpiochip_get_data(gc);
- unsigned long flags;
- unsigned int data_reg, gpio_ddr;
-
- raw_spin_lock_irqsave(&altera_gc->gpio_lock, flags);
- /* Sets the GPIO value */
- data_reg = readl(altera_gc->regs + ALTERA_GPIO_DATA);
- if (value)
- data_reg |= BIT(offset);
- else
- data_reg &= ~BIT(offset);
- writel(data_reg, altera_gc->regs + ALTERA_GPIO_DATA);
-
- /* Set pin as output, assumes software controlled IP */
- gpio_ddr = readl(altera_gc->regs + ALTERA_GPIO_DIR);
- gpio_ddr |= BIT(offset);
- writel(gpio_ddr, altera_gc->regs + ALTERA_GPIO_DIR);
- raw_spin_unlock_irqrestore(&altera_gc->gpio_lock, flags);
-
- return 0;
-}
-
static void altera_gpio_irq_edge_handler(struct irq_desc *desc)
{
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
@@ -231,9 +166,12 @@ static const struct irq_chip altera_gpio_irq_chip = {
static int altera_gpio_probe(struct platform_device *pdev)
{
+ struct gpio_generic_chip_config config;
struct device *dev = &pdev->dev;
int reg, ret;
struct altera_gpio_chip *altera_gc;
+ struct gpio_generic_chip *chip;
+ struct gpio_chip *gc;
struct gpio_irq_chip *girq;
int mapped_irq;
@@ -243,35 +181,45 @@ static int altera_gpio_probe(struct platform_device *pdev)
raw_spin_lock_init(&altera_gc->gpio_lock);
+ altera_gc->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(altera_gc->regs))
+ return dev_err_probe(dev, PTR_ERR(altera_gc->regs),
+ "failed to ioremap memory resource\n");
+
+ chip = &altera_gc->chip;
+
+ config = (struct gpio_generic_chip_config) {
+ .dev = dev,
+ .sz = 4,
+ .dat = altera_gc->regs + ALTERA_GPIO_DATA,
+ .set = altera_gc->regs + ALTERA_GPIO_DATA,
+ .dirout = altera_gc->regs + ALTERA_GPIO_DIR,
+ };
+
+ ret = gpio_generic_chip_init(chip, &config);
+ if (ret)
+ return dev_err_probe(dev, ret, "unable to init generic GPIO\n");
+
+ gc = &chip->gc;
+
if (device_property_read_u32(dev, "altr,ngpio", &reg))
/* By default assume maximum ngpio */
- altera_gc->gc.ngpio = ALTERA_GPIO_MAX_NGPIO;
+ gc->ngpio = ALTERA_GPIO_MAX_NGPIO;
else
- altera_gc->gc.ngpio = reg;
+ gc->ngpio = reg;
- if (altera_gc->gc.ngpio > ALTERA_GPIO_MAX_NGPIO) {
+ if (gc->ngpio > ALTERA_GPIO_MAX_NGPIO) {
dev_warn(&pdev->dev,
"ngpio is greater than %d, defaulting to %d\n",
ALTERA_GPIO_MAX_NGPIO, ALTERA_GPIO_MAX_NGPIO);
- altera_gc->gc.ngpio = ALTERA_GPIO_MAX_NGPIO;
+ gc->ngpio = ALTERA_GPIO_MAX_NGPIO;
}
- altera_gc->gc.direction_input = altera_gpio_direction_input;
- altera_gc->gc.direction_output = altera_gpio_direction_output;
- altera_gc->gc.get = altera_gpio_get;
- altera_gc->gc.set = altera_gpio_set;
- altera_gc->gc.owner = THIS_MODULE;
- altera_gc->gc.parent = &pdev->dev;
- altera_gc->gc.base = -1;
-
- altera_gc->gc.label = devm_kasprintf(dev, GFP_KERNEL, "%pfw", dev_fwnode(dev));
- if (!altera_gc->gc.label)
+ gc->base = -1;
+ gc->label = devm_kasprintf(dev, GFP_KERNEL, "%pfw", dev_fwnode(dev));
+ if (!gc->label)
return -ENOMEM;
- altera_gc->regs = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(altera_gc->regs))
- return dev_err_probe(dev, PTR_ERR(altera_gc->regs), "failed to ioremap memory resource\n");
-
mapped_irq = platform_get_irq_optional(pdev, 0);
if (mapped_irq < 0)
goto skip_irq;
@@ -283,7 +231,7 @@ static int altera_gpio_probe(struct platform_device *pdev)
}
altera_gc->interrupt_trigger = reg;
- girq = &altera_gc->gc.irq;
+ girq = &gc->irq;
gpio_irq_chip_set_chip(girq, &altera_gpio_irq_chip);
if (altera_gc->interrupt_trigger == IRQ_TYPE_LEVEL_HIGH)
@@ -300,7 +248,7 @@ static int altera_gpio_probe(struct platform_device *pdev)
girq->parents[0] = mapped_irq;
skip_irq:
- ret = devm_gpiochip_add_data(dev, &altera_gc->gc, altera_gc);
+ ret = devm_gpiochip_add_data(dev, gc, altera_gc);
if (ret) {
dev_err(&pdev->dev, "Failed adding memory mapped gpiochip\n");
return ret;
diff --git a/drivers/gpio/gpio-amd8111.c b/drivers/gpio/gpio-amd8111.c
index 15fd5e210d74..8078b5d7b80c 100644
--- a/drivers/gpio/gpio-amd8111.c
+++ b/drivers/gpio/gpio-amd8111.c
@@ -59,8 +59,8 @@
* want to register another driver on the same PCI id.
*/
static const struct pci_device_id pci_tbl[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS), 0 },
- { 0, }, /* terminate list */
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS) },
+ { }, /* terminate list */
};
MODULE_DEVICE_TABLE(pci, pci_tbl);
diff --git a/drivers/gpio/gpio-bd72720.c b/drivers/gpio/gpio-bd72720.c
index d0f936ed80af..306e23411209 100644
--- a/drivers/gpio/gpio-bd72720.c
+++ b/drivers/gpio/gpio-bd72720.c
@@ -263,8 +263,8 @@ static int gpo_bd72720_probe(struct platform_device *pdev)
}
static const struct platform_device_id bd72720_gpio_id[] = {
- { "bd72720-gpio" },
- { },
+ { .name = "bd72720-gpio" },
+ { }
};
MODULE_DEVICE_TABLE(platform, bd72720_gpio_id);
diff --git a/drivers/gpio/gpio-bd9571mwv.c b/drivers/gpio/gpio-bd9571mwv.c
index cc5b1746f2fe..f829fc40c02b 100644
--- a/drivers/gpio/gpio-bd9571mwv.c
+++ b/drivers/gpio/gpio-bd9571mwv.c
@@ -110,8 +110,8 @@ static int bd9571mwv_gpio_probe(struct platform_device *pdev)
}
static const struct platform_device_id bd9571mwv_gpio_id_table[] = {
- { "bd9571mwv-gpio", ROHM_CHIP_TYPE_BD9571 },
- { "bd9574mwf-gpio", ROHM_CHIP_TYPE_BD9574 },
+ { .name = "bd9571mwv-gpio", .driver_data = ROHM_CHIP_TYPE_BD9571 },
+ { .name = "bd9574mwf-gpio", .driver_data = ROHM_CHIP_TYPE_BD9574 },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(platform, bd9571mwv_gpio_id_table);
diff --git a/drivers/gpio/gpio-cros-ec.c b/drivers/gpio/gpio-cros-ec.c
index 435483826c6e..9deda8a9d11a 100644
--- a/drivers/gpio/gpio-cros-ec.c
+++ b/drivers/gpio/gpio-cros-ec.c
@@ -196,8 +196,8 @@ static int cros_ec_gpio_probe(struct platform_device *pdev)
}
static const struct platform_device_id cros_ec_gpio_id[] = {
- { "cros-ec-gpio", 0 },
- {}
+ { .name = "cros-ec-gpio" },
+ { }
};
MODULE_DEVICE_TABLE(platform, cros_ec_gpio_id);
diff --git a/drivers/gpio/gpio-ds4520.c b/drivers/gpio/gpio-ds4520.c
index f52ecae382a4..5add662a7ef5 100644
--- a/drivers/gpio/gpio-ds4520.c
+++ b/drivers/gpio/gpio-ds4520.c
@@ -54,7 +54,7 @@ static const struct of_device_id ds4520_gpio_of_match_table[] = {
MODULE_DEVICE_TABLE(of, ds4520_gpio_of_match_table);
static const struct i2c_device_id ds4520_gpio_id_table[] = {
- { "ds4520-gpio" },
+ { .name = "ds4520-gpio" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ds4520_gpio_id_table);
diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c
index 15cebc8b5d66..c1f3d83a67c1 100644
--- a/drivers/gpio/gpio-dwapb.c
+++ b/drivers/gpio/gpio-dwapb.c
@@ -694,6 +694,7 @@ static const struct acpi_device_id dwapb_acpi_match[] = {
{"APMC0D07", GPIO_REG_OFFSET_V1},
{"APMC0D81", GPIO_REG_OFFSET_V2},
{"FUJI200A", GPIO_REG_OFFSET_V1},
+ {"LECA0001", GPIO_REG_OFFSET_V1},
{ }
};
MODULE_DEVICE_TABLE(acpi, dwapb_acpi_match);
diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c
index 1f56e44ffc9a..8784e433e1ff 100644
--- a/drivers/gpio/gpio-ep93xx.c
+++ b/drivers/gpio/gpio-ep93xx.c
@@ -323,8 +323,7 @@ static int ep93xx_setup_irqs(struct platform_device *pdev,
}
girq->default_type = IRQ_TYPE_NONE;
- /* TODO: replace with handle_bad_irq() once we are fully hierarchical */
- girq->handler = handle_simple_irq;
+ girq->handler = handle_bad_irq;
return 0;
}
diff --git a/drivers/gpio/gpio-fxl6408.c b/drivers/gpio/gpio-fxl6408.c
index afc1b8461dab..45b02d36e66f 100644
--- a/drivers/gpio/gpio-fxl6408.c
+++ b/drivers/gpio/gpio-fxl6408.c
@@ -150,7 +150,7 @@ static const __maybe_unused struct of_device_id fxl6408_dt_ids[] = {
MODULE_DEVICE_TABLE(of, fxl6408_dt_ids);
static const struct i2c_device_id fxl6408_id[] = {
- { "fxl6408" },
+ { .name = "fxl6408" },
{ }
};
MODULE_DEVICE_TABLE(i2c, fxl6408_id);
diff --git a/drivers/gpio/gpio-gw-pld.c b/drivers/gpio/gpio-gw-pld.c
index 2e5d97b7363f..bf1f91c3c4a8 100644
--- a/drivers/gpio/gpio-gw-pld.c
+++ b/drivers/gpio/gpio-gw-pld.c
@@ -109,7 +109,7 @@ static int gw_pld_probe(struct i2c_client *client)
}
static const struct i2c_device_id gw_pld_id[] = {
- { "gw-pld", },
+ { .name = "gw-pld" },
{ }
};
MODULE_DEVICE_TABLE(i2c, gw_pld_id);
diff --git a/drivers/gpio/gpio-ixp4xx.c b/drivers/gpio/gpio-ixp4xx.c
index f34d87869c8b..669b139cd499 100644
--- a/drivers/gpio/gpio-ixp4xx.c
+++ b/drivers/gpio/gpio-ixp4xx.c
@@ -311,12 +311,7 @@ static int ixp4xx_gpio_probe(struct platform_device *pdev)
}
g->chip.gc.ngpio = 16;
g->chip.gc.label = "IXP4XX_GPIO_CHIP";
- /*
- * TODO: when we have migrated to device tree and all GPIOs
- * are fetched using phandles, set this to -1 to get rid of
- * the fixed gpiochip base.
- */
- g->chip.gc.base = 0;
+ g->chip.gc.base = -1;
g->chip.gc.parent = &pdev->dev;
g->chip.gc.owner = THIS_MODULE;
diff --git a/drivers/gpio/gpio-lp873x.c b/drivers/gpio/gpio-lp873x.c
index f4413fa5a811..0d1bd9df265a 100644
--- a/drivers/gpio/gpio-lp873x.c
+++ b/drivers/gpio/gpio-lp873x.c
@@ -156,7 +156,7 @@ static int lp873x_gpio_probe(struct platform_device *pdev)
}
static const struct platform_device_id lp873x_gpio_id_table[] = {
- { "lp873x-gpio", },
+ { .name = "lp873x-gpio" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(platform, lp873x_gpio_id_table);
diff --git a/drivers/gpio/gpio-lp87565.c b/drivers/gpio/gpio-lp87565.c
index 0f337c1283b2..3ac78f2b0fa7 100644
--- a/drivers/gpio/gpio-lp87565.c
+++ b/drivers/gpio/gpio-lp87565.c
@@ -171,7 +171,7 @@ static int lp87565_gpio_probe(struct platform_device *pdev)
}
static const struct platform_device_id lp87565_gpio_id_table[] = {
- { "lp87565-q1-gpio", },
+ { .name = "lp87565-q1-gpio" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(platform, lp87565_gpio_id_table);
diff --git a/drivers/gpio/gpio-max7300.c b/drivers/gpio/gpio-max7300.c
index 621d609ece90..62f2434c0d79 100644
--- a/drivers/gpio/gpio-max7300.c
+++ b/drivers/gpio/gpio-max7300.c
@@ -53,7 +53,7 @@ static void max7300_remove(struct i2c_client *client)
}
static const struct i2c_device_id max7300_id[] = {
- { "max7300" },
+ { .name = "max7300" },
{ }
};
MODULE_DEVICE_TABLE(i2c, max7300_id);
diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c
index 281ba1740a6a..24c67c912954 100644
--- a/drivers/gpio/gpio-max732x.c
+++ b/drivers/gpio/gpio-max732x.c
@@ -103,16 +103,16 @@ static uint64_t max732x_features[] = {
};
static const struct i2c_device_id max732x_id[] = {
- { "max7319", MAX7319 },
- { "max7320", MAX7320 },
- { "max7321", MAX7321 },
- { "max7322", MAX7322 },
- { "max7323", MAX7323 },
- { "max7324", MAX7324 },
- { "max7325", MAX7325 },
- { "max7326", MAX7326 },
- { "max7327", MAX7327 },
- { },
+ { .name = "max7319", .driver_data = MAX7319 },
+ { .name = "max7320", .driver_data = MAX7320 },
+ { .name = "max7321", .driver_data = MAX7321 },
+ { .name = "max7322", .driver_data = MAX7322 },
+ { .name = "max7323", .driver_data = MAX7323 },
+ { .name = "max7324", .driver_data = MAX7324 },
+ { .name = "max7325", .driver_data = MAX7325 },
+ { .name = "max7326", .driver_data = MAX7326 },
+ { .name = "max7327", .driver_data = MAX7327 },
+ { }
};
MODULE_DEVICE_TABLE(i2c, max732x_id);
diff --git a/drivers/gpio/gpio-max77620.c b/drivers/gpio/gpio-max77620.c
index e6c85411c695..2bf3b55a61b5 100644
--- a/drivers/gpio/gpio-max77620.c
+++ b/drivers/gpio/gpio-max77620.c
@@ -367,7 +367,7 @@ static int max77620_gpio_probe(struct platform_device *pdev)
static const struct platform_device_id max77620_gpio_devtype[] = {
{ .name = "max77620-gpio", },
{ .name = "max20024-gpio", },
- {},
+ { }
};
MODULE_DEVICE_TABLE(platform, max77620_gpio_devtype);
diff --git a/drivers/gpio/gpio-max77759.c b/drivers/gpio/gpio-max77759.c
index 3bf9f23d1532..c6bdac7fb44a 100644
--- a/drivers/gpio/gpio-max77759.c
+++ b/drivers/gpio/gpio-max77759.c
@@ -502,7 +502,7 @@ static const struct of_device_id max77759_gpio_of_id[] = {
MODULE_DEVICE_TABLE(of, max77759_gpio_of_id);
static const struct platform_device_id max77759_gpio_platform_id[] = {
- { "max77759-gpio", },
+ { .name = "max77759-gpio" },
{ }
};
MODULE_DEVICE_TABLE(platform, max77759_gpio_platform_id);
diff --git a/drivers/gpio/gpio-mt7621.c b/drivers/gpio/gpio-mt7621.c
index 91230be51587..a814885ccd5d 100644
--- a/drivers/gpio/gpio-mt7621.c
+++ b/drivers/gpio/gpio-mt7621.c
@@ -29,8 +29,8 @@
#define GPIO_REG_EDGE 0xA0
struct mtk_gc {
- struct irq_chip irq_chip;
struct gpio_generic_chip chip;
+ struct mtk *parent_priv;
int bank;
u32 rising;
u32 falling;
@@ -41,20 +41,32 @@ struct mtk_gc {
/**
* struct mtk - state container for
* data of the platform driver. It is 3
- * separate gpio-chip each one with its
- * own irq_chip.
- * @dev: device instance
+ * separate gpio-chip having an IRQ
+ * linear domain shared for all of them
+ * @pdev: platform device instance
* @base: memory base address
+ * @irq_domain: IRQ linear domain shared across the three gpio chips
* @gpio_irq: irq number from the device tree
+ * @num_gpios: total number of gpio pins on the three gpio chips
* @gc_map: array of the gpio chips
*/
struct mtk {
- struct device *dev;
+ struct platform_device *pdev;
void __iomem *base;
+ struct irq_domain *irq_domain;
int gpio_irq;
+ int num_gpios;
struct mtk_gc gc_map[MTK_BANK_CNT];
};
+static inline struct mtk *
+mt7621_gpio_gc_to_priv(struct gpio_chip *gc)
+{
+ struct mtk_gc *bank = gpiochip_get_data(gc);
+
+ return bank->parent_priv;
+}
+
static inline struct mtk_gc *
to_mediatek_gpio(struct gpio_chip *chip)
{
@@ -67,7 +79,7 @@ static inline void
mtk_gpio_w32(struct mtk_gc *rg, u32 offset, u32 val)
{
struct gpio_chip *gc = &rg->chip.gc;
- struct mtk *mtk = gpiochip_get_data(gc);
+ struct mtk *mtk = mt7621_gpio_gc_to_priv(gc);
offset = (rg->bank * GPIO_BANK_STRIDE) + offset;
gpio_generic_write_reg(&rg->chip, mtk->base + offset, val);
@@ -77,41 +89,62 @@ static inline u32
mtk_gpio_r32(struct mtk_gc *rg, u32 offset)
{
struct gpio_chip *gc = &rg->chip.gc;
- struct mtk *mtk = gpiochip_get_data(gc);
+ struct mtk *mtk = mt7621_gpio_gc_to_priv(gc);
offset = (rg->bank * GPIO_BANK_STRIDE) + offset;
return gpio_generic_read_reg(&rg->chip, mtk->base + offset);
}
-static irqreturn_t
-mediatek_gpio_irq_handler(int irq, void *data)
+static void
+mt7621_gpio_irq_bank_handler(struct mtk_gc *bank)
{
- struct gpio_chip *gc = data;
- struct mtk_gc *rg = to_mediatek_gpio(gc);
- irqreturn_t ret = IRQ_NONE;
+ struct mtk *priv = bank->parent_priv;
+ struct irq_domain *domain = priv->irq_domain;
+ int hwbase = bank->chip.gc.offset;
unsigned long pending;
- int bit;
+ unsigned int offset;
+
+ pending = mtk_gpio_r32(bank, GPIO_REG_STAT);
+ if (!pending)
+ return;
+
+ mtk_gpio_w32(bank, GPIO_REG_STAT, pending);
+
+ for_each_set_bit(offset, &pending, MTK_BANK_WIDTH)
+ generic_handle_domain_irq(domain, hwbase + offset);
+}
+
+static void
+mt7621_gpio_irq_handler(struct irq_desc *desc)
+{
+ struct mtk *priv = irq_desc_get_handler_data(desc);
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ int i;
- pending = mtk_gpio_r32(rg, GPIO_REG_STAT);
+ chained_irq_enter(chip, desc);
+ for (i = 0; i < MTK_BANK_CNT; i++) {
+ struct mtk_gc *bank = &priv->gc_map[i];
- for_each_set_bit(bit, &pending, MTK_BANK_WIDTH) {
- generic_handle_domain_irq(gc->irq.domain, bit);
- mtk_gpio_w32(rg, GPIO_REG_STAT, BIT(bit));
- ret |= IRQ_HANDLED;
+ mt7621_gpio_irq_bank_handler(bank);
}
+ chained_irq_exit(chip, desc);
+}
- return ret;
+static int
+mt7621_gpio_hwirq_to_offset(irq_hw_number_t hwirq, struct mtk_gc *bank)
+{
+ return hwirq - bank->chip.gc.offset;
}
static void
mediatek_gpio_irq_unmask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct mtk_gc *rg = to_mediatek_gpio(gc);
- int pin = d->hwirq;
+ struct mtk_gc *rg = gpiochip_get_data(gc);
+ u32 mask = mt7621_gpio_hwirq_to_offset(d->hwirq, rg);
u32 rise, fall, high, low;
- gpiochip_enable_irq(gc, d->hwirq);
+ gpiochip_enable_irq(gc, mask);
guard(gpio_generic_lock_irqsave)(&rg->chip);
@@ -119,18 +152,18 @@ mediatek_gpio_irq_unmask(struct irq_data *d)
fall = mtk_gpio_r32(rg, GPIO_REG_FEDGE);
high = mtk_gpio_r32(rg, GPIO_REG_HLVL);
low = mtk_gpio_r32(rg, GPIO_REG_LLVL);
- mtk_gpio_w32(rg, GPIO_REG_REDGE, rise | (BIT(pin) & rg->rising));
- mtk_gpio_w32(rg, GPIO_REG_FEDGE, fall | (BIT(pin) & rg->falling));
- mtk_gpio_w32(rg, GPIO_REG_HLVL, high | (BIT(pin) & rg->hlevel));
- mtk_gpio_w32(rg, GPIO_REG_LLVL, low | (BIT(pin) & rg->llevel));
+ mtk_gpio_w32(rg, GPIO_REG_REDGE, rise | (BIT(mask) & rg->rising));
+ mtk_gpio_w32(rg, GPIO_REG_FEDGE, fall | (BIT(mask) & rg->falling));
+ mtk_gpio_w32(rg, GPIO_REG_HLVL, high | (BIT(mask) & rg->hlevel));
+ mtk_gpio_w32(rg, GPIO_REG_LLVL, low | (BIT(mask) & rg->llevel));
}
static void
mediatek_gpio_irq_mask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct mtk_gc *rg = to_mediatek_gpio(gc);
- int pin = d->hwirq;
+ struct mtk_gc *rg = gpiochip_get_data(gc);
+ u32 mask = mt7621_gpio_hwirq_to_offset(d->hwirq, rg);
u32 rise, fall, high, low;
scoped_guard(gpio_generic_lock_irqsave, &rg->chip) {
@@ -138,22 +171,21 @@ mediatek_gpio_irq_mask(struct irq_data *d)
fall = mtk_gpio_r32(rg, GPIO_REG_FEDGE);
high = mtk_gpio_r32(rg, GPIO_REG_HLVL);
low = mtk_gpio_r32(rg, GPIO_REG_LLVL);
- mtk_gpio_w32(rg, GPIO_REG_FEDGE, fall & ~BIT(pin));
- mtk_gpio_w32(rg, GPIO_REG_REDGE, rise & ~BIT(pin));
- mtk_gpio_w32(rg, GPIO_REG_HLVL, high & ~BIT(pin));
- mtk_gpio_w32(rg, GPIO_REG_LLVL, low & ~BIT(pin));
+ mtk_gpio_w32(rg, GPIO_REG_FEDGE, fall & ~BIT(mask));
+ mtk_gpio_w32(rg, GPIO_REG_REDGE, rise & ~BIT(mask));
+ mtk_gpio_w32(rg, GPIO_REG_HLVL, high & ~BIT(mask));
+ mtk_gpio_w32(rg, GPIO_REG_LLVL, low & ~BIT(mask));
}
- gpiochip_disable_irq(gc, d->hwirq);
+ gpiochip_disable_irq(gc, mask);
}
static int
mediatek_gpio_irq_type(struct irq_data *d, unsigned int type)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct mtk_gc *rg = to_mediatek_gpio(gc);
- int pin = d->hwirq;
- u32 mask = BIT(pin);
+ struct mtk_gc *rg = gpiochip_get_data(gc);
+ u32 mask = BIT(mt7621_gpio_hwirq_to_offset(d->hwirq, rg));
if (type == IRQ_TYPE_PROBE) {
if ((rg->rising | rg->falling |
@@ -191,6 +223,26 @@ mediatek_gpio_irq_type(struct irq_data *d, unsigned int type)
}
static int
+mt7621_gpio_irq_reqres(struct irq_data *d)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct mtk_gc *rg = gpiochip_get_data(gc);
+ unsigned int irq = mt7621_gpio_hwirq_to_offset(d->hwirq, rg);
+
+ return gpiochip_reqres_irq(gc, irq);
+}
+
+static void
+mt7621_gpio_irq_relres(struct irq_data *d)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct mtk_gc *rg = gpiochip_get_data(gc);
+ unsigned int irq = mt7621_gpio_hwirq_to_offset(d->hwirq, rg);
+
+ gpiochip_relres_irq(gc, irq);
+}
+
+static int
mediatek_gpio_xlate(struct gpio_chip *chip,
const struct of_phandle_args *spec, u32 *flags)
{
@@ -208,15 +260,124 @@ mediatek_gpio_xlate(struct gpio_chip *chip,
static const struct irq_chip mt7621_irq_chip = {
.name = "mt7621-gpio",
+ .irq_request_resources = mt7621_gpio_irq_reqres,
+ .irq_release_resources = mt7621_gpio_irq_relres,
.irq_mask_ack = mediatek_gpio_irq_mask,
.irq_mask = mediatek_gpio_irq_mask,
.irq_unmask = mediatek_gpio_irq_unmask,
.irq_set_type = mediatek_gpio_irq_type,
.flags = IRQCHIP_IMMUTABLE,
- GPIOCHIP_IRQ_RESOURCE_HELPERS,
+};
+
+static void
+mt7621_gpio_remove(struct platform_device *pdev)
+{
+ struct mtk *priv = platform_get_drvdata(pdev);
+ int offset, virq;
+
+ if (priv->gpio_irq > 0)
+ irq_set_chained_handler_and_data(priv->gpio_irq, NULL, NULL);
+
+ /* Remove all IRQ mappings and delete the domain */
+ if (priv->irq_domain) {
+ for (offset = 0; offset < priv->num_gpios; offset++) {
+ virq = irq_find_mapping(priv->irq_domain, offset);
+ irq_dispose_mapping(virq);
+ }
+ irq_domain_remove(priv->irq_domain);
+ }
+}
+
+static struct mtk_gc *
+mt7621_gpio_hwirq_to_bank(struct mtk *priv, irq_hw_number_t hwirq)
+{
+ int i;
+
+ for (i = 0; i < MTK_BANK_CNT; i++) {
+ struct mtk_gc *bank = &priv->gc_map[i];
+
+ if (hwirq >= bank->chip.gc.offset &&
+ hwirq < (bank->chip.gc.offset + bank->chip.gc.ngpio))
+ return bank;
+ }
+
+ return NULL;
+}
+
+static int
+mt7621_gpio_irq_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hwirq)
+{
+ struct mtk *priv = d->host_data;
+ struct mtk_gc *bank = mt7621_gpio_hwirq_to_bank(priv, hwirq);
+ struct platform_device *pdev = priv->pdev;
+ int ret;
+
+ if (!bank)
+ return -EINVAL;
+
+ dev_dbg(&pdev->dev, "Mapping irq %d for gpio line %d (bank %d)\n",
+ irq, (int)hwirq, bank->bank);
+
+ ret = irq_set_chip_data(irq, &bank->chip.gc);
+ if (ret < 0)
+ return ret;
+
+ irq_set_chip_and_handler(irq, &mt7621_irq_chip, handle_simple_irq);
+ irq_set_noprobe(irq);
+
+ return 0;
+}
+
+static void
+mt7621_gpio_irq_unmap(struct irq_domain *d, unsigned int irq)
+{
+ irq_set_chip_and_handler(irq, NULL, NULL);
+ irq_set_chip_data(irq, NULL);
+}
+
+static const struct irq_domain_ops mt7621_gpio_irq_domain_ops = {
+ .map = mt7621_gpio_irq_map,
+ .unmap = mt7621_gpio_irq_unmap,
+ .xlate = irq_domain_xlate_twocell,
};
static int
+mt7621_gpio_irq_setup(struct platform_device *pdev,
+ struct mtk *priv)
+{
+ struct device *dev = &pdev->dev;
+
+ priv->irq_domain = irq_domain_create_linear(dev_fwnode(dev),
+ priv->num_gpios,
+ &mt7621_gpio_irq_domain_ops,
+ priv);
+ if (!priv->irq_domain) {
+ dev_err(dev, "Couldn't allocate IRQ domain\n");
+ return -ENXIO;
+ }
+
+ irq_set_chained_handler_and_data(priv->gpio_irq,
+ mt7621_gpio_irq_handler, priv);
+ irq_set_status_flags(priv->gpio_irq, IRQ_DISABLE_UNLAZY);
+
+ return 0;
+}
+
+static int
+mt7621_gpio_to_irq(struct gpio_chip *gc, unsigned int offset)
+{
+ struct mtk *priv = mt7621_gpio_gc_to_priv(gc);
+ /* gc_offset is relative to this gpio_chip; want real offset */
+ int hwirq = offset + gc->offset;
+
+ if (hwirq >= priv->num_gpios)
+ return -ENXIO;
+
+ return irq_create_mapping(priv->irq_domain, hwirq);
+}
+
+static int
mediatek_gpio_bank_probe(struct device *dev, int bank)
{
struct gpio_generic_chip_config config;
@@ -228,6 +389,7 @@ mediatek_gpio_bank_probe(struct device *dev, int bank)
rg = &mtk->gc_map[bank];
memset(rg, 0, sizeof(*rg));
+ rg->parent_priv = mtk;
rg->bank = bank;
dat = mtk->base + GPIO_REG_DATA + (rg->bank * GPIO_BANK_STRIDE);
@@ -253,41 +415,17 @@ mediatek_gpio_bank_probe(struct device *dev, int bank)
rg->chip.gc.of_gpio_n_cells = 2;
rg->chip.gc.of_xlate = mediatek_gpio_xlate;
+ rg->chip.gc.ngpio = MTK_BANK_WIDTH;
rg->chip.gc.label = devm_kasprintf(dev, GFP_KERNEL, "%s-bank%d",
dev_name(dev), bank);
if (!rg->chip.gc.label)
return -ENOMEM;
rg->chip.gc.offset = bank * MTK_BANK_WIDTH;
+ if (mtk->gpio_irq > 0)
+ rg->chip.gc.to_irq = mt7621_gpio_to_irq;
- if (mtk->gpio_irq) {
- struct gpio_irq_chip *girq;
-
- /*
- * Directly request the irq here instead of passing
- * a flow-handler because the irq is shared.
- */
- ret = devm_request_irq(dev, mtk->gpio_irq,
- mediatek_gpio_irq_handler, IRQF_SHARED,
- rg->chip.gc.label, &rg->chip.gc);
-
- if (ret) {
- dev_err(dev, "Error requesting IRQ %d: %d\n",
- mtk->gpio_irq, ret);
- return ret;
- }
-
- girq = &rg->chip.gc.irq;
- gpio_irq_chip_set_chip(girq, &mt7621_irq_chip);
- /* This will let us handle the parent IRQ in the driver */
- girq->parent_handler = NULL;
- girq->num_parents = 0;
- girq->parents = NULL;
- girq->default_type = IRQ_TYPE_NONE;
- girq->handler = handle_simple_irq;
- }
-
- ret = devm_gpiochip_add_data(dev, &rg->chip.gc, mtk);
+ ret = devm_gpiochip_add_data(dev, &rg->chip.gc, rg);
if (ret < 0) {
dev_err(dev, "Could not register gpio %d, ret=%d\n",
rg->chip.gc.ngpio, ret);
@@ -322,7 +460,8 @@ mediatek_gpio_probe(struct platform_device *pdev)
if (mtk->gpio_irq < 0)
return mtk->gpio_irq;
- mtk->dev = dev;
+ mtk->pdev = pdev;
+ mtk->num_gpios = MTK_BANK_WIDTH * MTK_BANK_CNT;
platform_set_drvdata(pdev, mtk);
for (i = 0; i < MTK_BANK_CNT; i++) {
@@ -331,7 +470,17 @@ mediatek_gpio_probe(struct platform_device *pdev)
return ret;
}
+ if (mtk->gpio_irq > 0) {
+ ret = mt7621_gpio_irq_setup(pdev, mtk);
+ if (ret)
+ goto fail;
+ }
+
return 0;
+
+fail:
+ mt7621_gpio_remove(pdev);
+ return ret;
}
static const struct of_device_id mediatek_gpio_match[] = {
@@ -342,6 +491,7 @@ MODULE_DEVICE_TABLE(of, mediatek_gpio_match);
static struct platform_driver mediatek_gpio_driver = {
.probe = mediatek_gpio_probe,
+ .remove = mt7621_gpio_remove,
.driver = {
.name = "mt7621_gpio",
.of_match_table = mediatek_gpio_match,
diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c
index 12f11a6c9665..7e2690d92df6 100644
--- a/drivers/gpio/gpio-mxc.c
+++ b/drivers/gpio/gpio-mxc.c
@@ -330,13 +330,13 @@ static int gpio_set_wake_irq(struct irq_data *d, u32 enable)
ret = enable_irq_wake(port->irq_high);
else
ret = enable_irq_wake(port->irq);
- port->wakeup_pads |= (1 << gpio_idx);
+ port->wakeup_pads |= BIT(gpio_idx);
} else {
if (port->irq_high && (gpio_idx >= 16))
ret = disable_irq_wake(port->irq_high);
else
ret = disable_irq_wake(port->irq);
- port->wakeup_pads &= ~(1 << gpio_idx);
+ port->wakeup_pads &= ~BIT(gpio_idx);
}
return ret;
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index b9c905a0ffa9..2ee35e855e4d 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -86,49 +86,49 @@
#define PCA_CHIP_TYPE(x) ((x) & PCA_TYPE_MASK)
static const struct i2c_device_id pca953x_id[] = {
- { "pca6408", 8 | PCA953X_TYPE | PCA_INT, },
- { "pca6416", 16 | PCA953X_TYPE | PCA_INT, },
- { "pca9505", 40 | PCA953X_TYPE | PCA_INT, },
- { "pca9506", 40 | PCA953X_TYPE | PCA_INT, },
- { "pca9534", 8 | PCA953X_TYPE | PCA_INT, },
- { "pca9535", 16 | PCA953X_TYPE | PCA_INT, },
- { "pca9536", 4 | PCA953X_TYPE, },
- { "pca9537", 4 | PCA953X_TYPE | PCA_INT, },
- { "pca9538", 8 | PCA953X_TYPE | PCA_INT, },
- { "pca9539", 16 | PCA953X_TYPE | PCA_INT, },
- { "pca9554", 8 | PCA953X_TYPE | PCA_INT, },
- { "pca9555", 16 | PCA953X_TYPE | PCA_INT, },
- { "pca9556", 8 | PCA953X_TYPE, },
- { "pca9557", 8 | PCA953X_TYPE, },
- { "pca9574", 8 | PCA957X_TYPE | PCA_INT, },
- { "pca9575", 16 | PCA957X_TYPE | PCA_INT, },
- { "pca9698", 40 | PCA953X_TYPE, },
+ { .name = "pca6408", .driver_data = 8 | PCA953X_TYPE | PCA_INT },
+ { .name = "pca6416", .driver_data = 16 | PCA953X_TYPE | PCA_INT },
+ { .name = "pca9505", .driver_data = 40 | PCA953X_TYPE | PCA_INT },
+ { .name = "pca9506", .driver_data = 40 | PCA953X_TYPE | PCA_INT },
+ { .name = "pca9534", .driver_data = 8 | PCA953X_TYPE | PCA_INT },
+ { .name = "pca9535", .driver_data = 16 | PCA953X_TYPE | PCA_INT },
+ { .name = "pca9536", .driver_data = 4 | PCA953X_TYPE },
+ { .name = "pca9537", .driver_data = 4 | PCA953X_TYPE | PCA_INT },
+ { .name = "pca9538", .driver_data = 8 | PCA953X_TYPE | PCA_INT },
+ { .name = "pca9539", .driver_data = 16 | PCA953X_TYPE | PCA_INT },
+ { .name = "pca9554", .driver_data = 8 | PCA953X_TYPE | PCA_INT },
+ { .name = "pca9555", .driver_data = 16 | PCA953X_TYPE | PCA_INT },
+ { .name = "pca9556", .driver_data = 8 | PCA953X_TYPE },
+ { .name = "pca9557", .driver_data = 8 | PCA953X_TYPE },
+ { .name = "pca9574", .driver_data = 8 | PCA957X_TYPE | PCA_INT },
+ { .name = "pca9575", .driver_data = 16 | PCA957X_TYPE | PCA_INT },
+ { .name = "pca9698", .driver_data = 40 | PCA953X_TYPE },
- { "pcal6408", 8 | PCA953X_TYPE | PCA_LATCH_INT, },
- { "pcal6416", 16 | PCA953X_TYPE | PCA_LATCH_INT, },
- { "pcal6524", 24 | PCA953X_TYPE | PCA_LATCH_INT, },
- { "pcal6534", 34 | PCAL653X_TYPE | PCA_LATCH_INT, },
- { "pcal9535", 16 | PCA953X_TYPE | PCA_LATCH_INT, },
- { "pcal9554b", 8 | PCA953X_TYPE | PCA_LATCH_INT, },
- { "pcal9555a", 16 | PCA953X_TYPE | PCA_LATCH_INT, },
+ { .name = "pcal6408", .driver_data = 8 | PCA953X_TYPE | PCA_LATCH_INT },
+ { .name = "pcal6416", .driver_data = 16 | PCA953X_TYPE | PCA_LATCH_INT },
+ { .name = "pcal6524", .driver_data = 24 | PCA953X_TYPE | PCA_LATCH_INT },
+ { .name = "pcal6534", .driver_data = 34 | PCAL653X_TYPE | PCA_LATCH_INT },
+ { .name = "pcal9535", .driver_data = 16 | PCA953X_TYPE | PCA_LATCH_INT },
+ { .name = "pcal9554b", .driver_data = 8 | PCA953X_TYPE | PCA_LATCH_INT },
+ { .name = "pcal9555a", .driver_data = 16 | PCA953X_TYPE | PCA_LATCH_INT },
- { "max7310", 8 | PCA953X_TYPE, },
- { "max7312", 16 | PCA953X_TYPE | PCA_INT, },
- { "max7313", 16 | PCA953X_TYPE | PCA_INT, },
- { "max7315", 8 | PCA953X_TYPE | PCA_INT, },
- { "max7318", 16 | PCA953X_TYPE | PCA_INT, },
- { "pca6107", 8 | PCA953X_TYPE | PCA_INT, },
- { "tca6408", 8 | PCA953X_TYPE | PCA_INT, },
- { "tca6416", 16 | PCA953X_TYPE | PCA_INT, },
- { "tca6418", 18 | TCA6418_TYPE | PCA_INT, },
- { "tca6424", 24 | PCA953X_TYPE | PCA_INT, },
- { "tca9538", 8 | PCA953X_TYPE | PCA_INT, },
- { "tca9539", 16 | PCA953X_TYPE | PCA_INT, },
- { "tca9554", 8 | PCA953X_TYPE | PCA_INT, },
- { "xra1202", 8 | PCA953X_TYPE },
+ { .name = "max7310", .driver_data = 8 | PCA953X_TYPE },
+ { .name = "max7312", .driver_data = 16 | PCA953X_TYPE | PCA_INT },
+ { .name = "max7313", .driver_data = 16 | PCA953X_TYPE | PCA_INT },
+ { .name = "max7315", .driver_data = 8 | PCA953X_TYPE | PCA_INT },
+ { .name = "max7318", .driver_data = 16 | PCA953X_TYPE | PCA_INT },
+ { .name = "pca6107", .driver_data = 8 | PCA953X_TYPE | PCA_INT },
+ { .name = "tca6408", .driver_data = 8 | PCA953X_TYPE | PCA_INT },
+ { .name = "tca6416", .driver_data = 16 | PCA953X_TYPE | PCA_INT },
+ { .name = "tca6418", .driver_data = 18 | TCA6418_TYPE | PCA_INT },
+ { .name = "tca6424", .driver_data = 24 | PCA953X_TYPE | PCA_INT },
+ { .name = "tca9538", .driver_data = 8 | PCA953X_TYPE | PCA_INT },
+ { .name = "tca9539", .driver_data = 16 | PCA953X_TYPE | PCA_INT },
+ { .name = "tca9554", .driver_data = 8 | PCA953X_TYPE | PCA_INT },
+ { .name = "xra1202", .driver_data = 8 | PCA953X_TYPE },
- { "tcal6408", 8 | PCA953X_TYPE | PCA_LATCH_INT, },
- { "tcal6416", 16 | PCA953X_TYPE | PCA_LATCH_INT, },
+ { .name = "tcal6408", .driver_data = 8 | PCA953X_TYPE | PCA_LATCH_INT },
+ { .name = "tcal6416", .driver_data = 16 | PCA953X_TYPE | PCA_LATCH_INT },
{ }
};
MODULE_DEVICE_TABLE(i2c, pca953x_id);
@@ -877,11 +877,9 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
bitmap_or(irq_mask, chip->irq_trig_fall, chip->irq_trig_raise, gc->ngpio);
bitmap_or(irq_mask, irq_mask, chip->irq_trig_level_high, gc->ngpio);
bitmap_or(irq_mask, irq_mask, chip->irq_trig_level_low, gc->ngpio);
- bitmap_complement(reg_direction, reg_direction, gc->ngpio);
- bitmap_and(irq_mask, irq_mask, reg_direction, gc->ngpio);
/* Look for any newly setup interrupt */
- for_each_set_bit(level, irq_mask, gc->ngpio)
+ for_each_andnot_bit(level, irq_mask, reg_direction, gc->ngpio)
pca953x_gpio_direction_input(&chip->gpio_chip, level);
mutex_unlock(&chip->irq_lock);
@@ -1005,8 +1003,7 @@ static bool pca953x_irq_pending(struct pca953x_chip *chip, unsigned long *pendin
bitmap_and(cur_stat, cur_stat, chip->irq_mask, gc->ngpio);
bitmap_or(pending, pending, cur_stat, gc->ngpio);
- bitmap_complement(cur_stat, new_stat, gc->ngpio);
- bitmap_and(cur_stat, cur_stat, reg_direction, gc->ngpio);
+ bitmap_andnot(cur_stat, reg_direction, new_stat, gc->ngpio);
bitmap_and(old_stat, cur_stat, chip->irq_trig_level_low, gc->ngpio);
bitmap_and(old_stat, old_stat, chip->irq_mask, gc->ngpio);
bitmap_or(pending, pending, old_stat, gc->ngpio);
diff --git a/drivers/gpio/gpio-pca9570.c b/drivers/gpio/gpio-pca9570.c
index 4a368803fb03..7a47a9aa0414 100644
--- a/drivers/gpio/gpio-pca9570.c
+++ b/drivers/gpio/gpio-pca9570.c
@@ -163,9 +163,9 @@ static const struct pca9570_chip_data slg7xl45106_gpio = {
};
static const struct i2c_device_id pca9570_id_table[] = {
- { "pca9570", (kernel_ulong_t)&pca9570_gpio},
- { "pca9571", (kernel_ulong_t)&pca9571_gpio },
- { "slg7xl45106", (kernel_ulong_t)&slg7xl45106_gpio },
+ { .name = "pca9570", .driver_data = (kernel_ulong_t)&pca9570_gpio },
+ { .name = "pca9571", .driver_data = (kernel_ulong_t)&pca9571_gpio },
+ { .name = "slg7xl45106", .driver_data = (kernel_ulong_t)&slg7xl45106_gpio },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, pca9570_id_table);
diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c
index 3b9de8c3d924..c942b959571b 100644
--- a/drivers/gpio/gpio-pcf857x.c
+++ b/drivers/gpio/gpio-pcf857x.c
@@ -20,19 +20,19 @@
#include <linux/spinlock.h>
static const struct i2c_device_id pcf857x_id[] = {
- { "pcf8574", 8 },
- { "pcf8574a", 8 },
- { "pca8574", 8 },
- { "pca9670", 8 },
- { "pca9672", 8 },
- { "pca9674", 8 },
- { "pcf8575", 16 },
- { "pca8575", 16 },
- { "pca9671", 16 },
- { "pca9673", 16 },
- { "pca9675", 16 },
- { "max7328", 8 },
- { "max7329", 8 },
+ { .name = "pcf8574", .driver_data = 8 },
+ { .name = "pcf8574a", .driver_data = 8 },
+ { .name = "pca8574", .driver_data = 8 },
+ { .name = "pca9670", .driver_data = 8 },
+ { .name = "pca9672", .driver_data = 8 },
+ { .name = "pca9674", .driver_data = 8 },
+ { .name = "pcf8575", .driver_data = 16 },
+ { .name = "pca8575", .driver_data = 16 },
+ { .name = "pca9671", .driver_data = 16 },
+ { .name = "pca9673", .driver_data = 16 },
+ { .name = "pca9675", .driver_data = 16 },
+ { .name = "max7328", .driver_data = 8 },
+ { .name = "max7329", .driver_data = 8 },
{ }
};
MODULE_DEVICE_TABLE(i2c, pcf857x_id);
diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c
index 664cf1eef494..5d61053e0596 100644
--- a/drivers/gpio/gpio-pxa.c
+++ b/drivers/gpio/gpio-pxa.c
@@ -708,15 +708,15 @@ static int pxa_gpio_probe(struct platform_device *pdev)
}
static const struct platform_device_id gpio_id_table[] = {
- { "pxa25x-gpio", (unsigned long)&pxa25x_id },
- { "pxa26x-gpio", (unsigned long)&pxa26x_id },
- { "pxa27x-gpio", (unsigned long)&pxa27x_id },
- { "pxa3xx-gpio", (unsigned long)&pxa3xx_id },
- { "pxa93x-gpio", (unsigned long)&pxa93x_id },
- { "mmp-gpio", (unsigned long)&mmp_id },
- { "mmp2-gpio", (unsigned long)&mmp2_id },
- { "pxa1928-gpio", (unsigned long)&pxa1928_id },
- { },
+ { .name = "pxa25x-gpio", .driver_data = (unsigned long)&pxa25x_id },
+ { .name = "pxa26x-gpio", .driver_data = (unsigned long)&pxa26x_id },
+ { .name = "pxa27x-gpio", .driver_data = (unsigned long)&pxa27x_id },
+ { .name = "pxa3xx-gpio", .driver_data = (unsigned long)&pxa3xx_id },
+ { .name = "pxa93x-gpio", .driver_data = (unsigned long)&pxa93x_id },
+ { .name = "mmp-gpio", .driver_data = (unsigned long)&mmp_id },
+ { .name = "mmp2-gpio", .driver_data = (unsigned long)&mmp2_id },
+ { .name = "pxa1928-gpio", .driver_data = (unsigned long)&pxa1928_id },
+ { }
};
static struct platform_driver pxa_gpio_driver = {
diff --git a/drivers/gpio/gpio-realtek-otto.c b/drivers/gpio/gpio-realtek-otto.c
index 5e3152c2e51a..37ef56f45318 100644
--- a/drivers/gpio/gpio-realtek-otto.c
+++ b/drivers/gpio/gpio-realtek-otto.c
@@ -40,16 +40,18 @@
#define REALTEK_GPIO_PORTS_PER_BANK 4
/**
- * realtek_gpio_ctrl - Realtek Otto GPIO driver data
+ * struct realtek_gpio_ctrl - Realtek Otto GPIO driver data
*
* @chip: Associated gpio_generic_chip instance
* @base: Base address of the register block for a GPIO bank
+ * @cpumask_base: Base address of the per-CPU interrupt mask registers
+ * @cpu_irq_maskable: CPUs that can receive GPIO interrupts
* @lock: Lock for accessing the IRQ registers and values
* @intr_mask: Mask for interrupts lines
* @intr_type: Interrupt type selection
* @bank_read: Read a bank setting as a single 32-bit value
* @bank_write: Write a bank setting as a single 32-bit value
- * @imr_line_pos: Bit shift of an IRQ line's IMR value.
+ * @line_imr_pos: Bit shift of an IRQ line's IMR value.
*
* The DIR, DATA, and ISR registers consist of four 8-bit port values, packed
* into a single 32-bit register. Use @bank_read (@bank_write) to get (assign)
diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c
index 9ae4a41a2427..51b4d69b8740 100644
--- a/drivers/gpio/gpio-regmap.c
+++ b/drivers/gpio/gpio-regmap.c
@@ -31,6 +31,7 @@ struct gpio_regmap {
unsigned int reg_clr_base;
unsigned int reg_dir_in_base;
unsigned int reg_dir_out_base;
+ unsigned long *fixed_direction_mask;
unsigned long *fixed_direction_output;
#ifdef CONFIG_REGMAP_IRQ
@@ -138,6 +139,20 @@ static int gpio_regmap_set_with_clear(struct gpio_chip *chip,
return regmap_write(gpio->regmap, reg, mask);
}
+static bool gpio_regmap_fixed_direction(struct gpio_regmap *gpio,
+ unsigned int offset)
+{
+ if (!gpio->fixed_direction_output)
+ return false;
+
+ /* In this case only some GPIOs are fixed as input/output */
+ if (gpio->fixed_direction_mask &&
+ !test_bit(offset, gpio->fixed_direction_mask))
+ return false;
+
+ return true;
+}
+
static int gpio_regmap_get_direction(struct gpio_chip *chip,
unsigned int offset)
{
@@ -145,7 +160,7 @@ static int gpio_regmap_get_direction(struct gpio_chip *chip,
unsigned int base, val, reg, mask;
int invert, ret;
- if (gpio->fixed_direction_output) {
+ if (gpio_regmap_fixed_direction(gpio, offset)) {
if (test_bit(offset, gpio->fixed_direction_output))
return GPIO_LINE_DIRECTION_OUT;
else
@@ -181,6 +196,22 @@ static int gpio_regmap_get_direction(struct gpio_chip *chip,
return GPIO_LINE_DIRECTION_IN;
}
+static int gpio_regmap_try_direction_fixed(struct gpio_regmap *gpio,
+ unsigned int offset, bool output)
+{
+ if (test_bit(offset, gpio->fixed_direction_output)) {
+ if (output)
+ return 0;
+ else
+ return -EINVAL;
+ } else {
+ if (output)
+ return -EINVAL;
+ else
+ return 0;
+ }
+}
+
static int gpio_regmap_set_direction(struct gpio_chip *chip,
unsigned int offset, bool output)
{
@@ -188,6 +219,13 @@ static int gpio_regmap_set_direction(struct gpio_chip *chip,
unsigned int base, val, reg, mask;
int invert, ret;
+ /*
+ * If the direction is fixed, only accept the fixed
+ * direction in this call.
+ */
+ if (gpio_regmap_fixed_direction(gpio, offset))
+ return gpio_regmap_try_direction_fixed(gpio, offset, output);
+
if (gpio->reg_dir_out_base) {
base = gpio_regmap_addr(gpio->reg_dir_out_base);
invert = 0;
@@ -219,6 +257,20 @@ static int gpio_regmap_direction_input(struct gpio_chip *chip,
static int gpio_regmap_direction_output(struct gpio_chip *chip,
unsigned int offset, int value)
{
+ struct gpio_regmap *gpio = gpiochip_get_data(chip);
+ int ret;
+
+ /*
+ * First check if this is gonna work on a fixed direction line,
+ * if it doesn't (i.e. this is a fixed input line), then do not
+ * attempt to set the output value either and just bail out.
+ */
+ if (gpio_regmap_fixed_direction(gpio, offset)) {
+ ret = gpio_regmap_try_direction_fixed(gpio, offset, true);
+ if (ret)
+ return ret;
+ }
+
gpio_regmap_set(chip, offset, value);
return gpio_regmap_set_direction(chip, offset, true);
@@ -302,12 +354,23 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config
goto err_free_gpio;
}
+ if (config->fixed_direction_mask) {
+ gpio->fixed_direction_mask = bitmap_alloc(chip->ngpio,
+ GFP_KERNEL);
+ if (!gpio->fixed_direction_mask) {
+ ret = -ENOMEM;
+ goto err_free_gpio;
+ }
+ bitmap_copy(gpio->fixed_direction_mask,
+ config->fixed_direction_mask, chip->ngpio);
+ }
+
if (config->fixed_direction_output) {
gpio->fixed_direction_output = bitmap_alloc(chip->ngpio,
GFP_KERNEL);
if (!gpio->fixed_direction_output) {
ret = -ENOMEM;
- goto err_free_gpio;
+ goto err_free_bitmap_dirmask;
}
bitmap_copy(gpio->fixed_direction_output,
config->fixed_direction_output, chip->ngpio);
@@ -329,7 +392,7 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config
ret = gpiochip_add_data(chip, gpio);
if (ret < 0)
- goto err_free_bitmap;
+ goto err_free_bitmap_output;
#ifdef CONFIG_REGMAP_IRQ
if (config->regmap_irq_chip) {
@@ -355,8 +418,10 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config
err_remove_gpiochip:
gpiochip_remove(chip);
-err_free_bitmap:
+err_free_bitmap_output:
bitmap_free(gpio->fixed_direction_output);
+err_free_bitmap_dirmask:
+ bitmap_free(gpio->fixed_direction_mask);
err_free_gpio:
kfree(gpio);
return ERR_PTR(ret);
@@ -376,6 +441,7 @@ void gpio_regmap_unregister(struct gpio_regmap *gpio)
gpiochip_remove(&gpio->gpio_chip);
bitmap_free(gpio->fixed_direction_output);
+ bitmap_free(gpio->fixed_direction_mask);
kfree(gpio);
}
EXPORT_SYMBOL_GPL(gpio_regmap_unregister);
diff --git a/drivers/gpio/gpio-sim.c b/drivers/gpio/gpio-sim.c
index 0da2c5a45843..f0f570527cf2 100644
--- a/drivers/gpio/gpio-sim.c
+++ b/drivers/gpio/gpio-sim.c
@@ -695,9 +695,9 @@ static ssize_t gpio_sim_device_config_dev_name_show(struct config_item *item,
pdev = dev->pdev;
if (pdev)
- return sprintf(page, "%s\n", dev_name(&pdev->dev));
+ return sysfs_emit(page, "%s\n", dev_name(&pdev->dev));
- return sprintf(page, "gpio-sim.%d\n", dev->id);
+ return sysfs_emit(page, "gpio-sim.%d\n", dev->id);
}
CONFIGFS_ATTR_RO(gpio_sim_device_config_, dev_name);
@@ -711,7 +711,7 @@ gpio_sim_device_config_live_show(struct config_item *item, char *page)
scoped_guard(mutex, &dev->lock)
live = gpio_sim_device_is_live(dev);
- return sprintf(page, "%c\n", live ? '1' : '0');
+ return sysfs_emit(page, "%c\n", live ? '1' : '0');
}
static unsigned int gpio_sim_get_line_names_size(struct gpio_sim_bank *bank)
@@ -1059,7 +1059,7 @@ static int gpio_sim_emit_chip_name(struct device *dev, void *data)
return 0;
if (device_match_fwnode(dev, ctx->swnode))
- return sprintf(ctx->page, "%s\n", dev_name(dev));
+ return sysfs_emit(ctx->page, "%s\n", dev_name(dev));
return 0;
}
@@ -1077,7 +1077,7 @@ static ssize_t gpio_sim_bank_config_chip_name_show(struct config_item *item,
return device_for_each_child(&dev->pdev->dev, &ctx,
gpio_sim_emit_chip_name);
- return sprintf(page, "none\n");
+ return sysfs_emit(page, "none\n");
}
CONFIGFS_ATTR_RO(gpio_sim_bank_config_, chip_name);
@@ -1090,7 +1090,7 @@ gpio_sim_bank_config_label_show(struct config_item *item, char *page)
guard(mutex)(&dev->lock);
- return sprintf(page, "%s\n", bank->label ?: "");
+ return sysfs_emit(page, "%s\n", bank->label ?: "");
}
static ssize_t gpio_sim_bank_config_label_store(struct config_item *item,
@@ -1125,7 +1125,7 @@ gpio_sim_bank_config_num_lines_show(struct config_item *item, char *page)
guard(mutex)(&dev->lock);
- return sprintf(page, "%u\n", bank->num_lines);
+ return sysfs_emit(page, "%u\n", bank->num_lines);
}
static ssize_t
@@ -1171,7 +1171,7 @@ gpio_sim_line_config_name_show(struct config_item *item, char *page)
guard(mutex)(&dev->lock);
- return sprintf(page, "%s\n", line->name ?: "");
+ return sysfs_emit(page, "%s\n", line->name ?: "");
}
static ssize_t gpio_sim_line_config_name_store(struct config_item *item,
@@ -1206,7 +1206,7 @@ gpio_sim_line_config_valid_show(struct config_item *item, char *page)
guard(mutex)(&dev->lock);
- return sprintf(page, "%c\n", line->valid ? '1' : '0');
+ return sysfs_emit(page, "%c\n", line->valid ? '1' : '0');
}
static ssize_t gpio_sim_line_config_valid_store(struct config_item *item,
@@ -1244,7 +1244,7 @@ static ssize_t gpio_sim_hog_config_name_show(struct config_item *item,
guard(mutex)(&dev->lock);
- return sprintf(page, "%s\n", hog->name ?: "");
+ return sysfs_emit(page, "%s\n", hog->name ?: "");
}
static ssize_t gpio_sim_hog_config_name_store(struct config_item *item,
@@ -1298,7 +1298,7 @@ static ssize_t gpio_sim_hog_config_direction_show(struct config_item *item,
return -EINVAL;
}
- return sprintf(page, "%s\n", repr);
+ return sysfs_emit(page, "%s\n", repr);
}
static ssize_t
@@ -1338,7 +1338,7 @@ static ssize_t gpio_sim_hog_config_active_low_show(struct config_item *item,
guard(mutex)(&dev->lock);
- return sprintf(page, "%c\n", hog->active_low ? '1' : '0');
+ return sysfs_emit(page, "%c\n", hog->active_low ? '1' : '0');
}
static ssize_t
diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c
index aa7c3e44234f..d9a2dedf50ea 100644
--- a/drivers/gpio/gpio-tegra186.c
+++ b/drivers/gpio/gpio-tegra186.c
@@ -19,6 +19,7 @@
#include <dt-bindings/gpio/tegra186-gpio.h>
#include <dt-bindings/gpio/tegra194-gpio.h>
#include <dt-bindings/gpio/tegra234-gpio.h>
+#include <dt-bindings/gpio/nvidia,tegra238-gpio.h>
#include <dt-bindings/gpio/tegra241-gpio.h>
#include <dt-bindings/gpio/tegra256-gpio.h>
#include <dt-bindings/gpio/nvidia,tegra264-gpio.h>
@@ -1239,6 +1240,67 @@ static const struct tegra_gpio_soc tegra234_aon_soc = {
.has_vm_support = false,
};
+#define TEGRA238_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \
+ TEGRA_GPIO_PORT(TEGRA238_MAIN, _name, _bank, _port, _pins)
+
+static const struct tegra_gpio_port tegra238_main_ports[] = {
+ TEGRA238_MAIN_GPIO_PORT(A, 0, 0, 8),
+ TEGRA238_MAIN_GPIO_PORT(B, 0, 1, 5),
+ TEGRA238_MAIN_GPIO_PORT(C, 0, 2, 8),
+ TEGRA238_MAIN_GPIO_PORT(D, 0, 3, 8),
+ TEGRA238_MAIN_GPIO_PORT(E, 0, 4, 4),
+ TEGRA238_MAIN_GPIO_PORT(F, 0, 5, 8),
+ TEGRA238_MAIN_GPIO_PORT(G, 0, 6, 8),
+ TEGRA238_MAIN_GPIO_PORT(H, 0, 7, 6),
+ TEGRA238_MAIN_GPIO_PORT(J, 1, 0, 8),
+ TEGRA238_MAIN_GPIO_PORT(K, 1, 1, 4),
+ TEGRA238_MAIN_GPIO_PORT(L, 1, 2, 8),
+ TEGRA238_MAIN_GPIO_PORT(M, 1, 3, 8),
+ TEGRA238_MAIN_GPIO_PORT(N, 1, 4, 3),
+ TEGRA238_MAIN_GPIO_PORT(P, 1, 5, 8),
+ TEGRA238_MAIN_GPIO_PORT(Q, 1, 6, 3),
+ TEGRA238_MAIN_GPIO_PORT(R, 2, 0, 8),
+ TEGRA238_MAIN_GPIO_PORT(S, 2, 1, 8),
+ TEGRA238_MAIN_GPIO_PORT(T, 2, 2, 8),
+ TEGRA238_MAIN_GPIO_PORT(U, 2, 3, 6),
+ TEGRA238_MAIN_GPIO_PORT(V, 2, 4, 2),
+ TEGRA238_MAIN_GPIO_PORT(W, 3, 0, 8),
+ TEGRA238_MAIN_GPIO_PORT(X, 3, 1, 2)
+};
+
+static const struct tegra_gpio_soc tegra238_main_soc = {
+ .num_ports = ARRAY_SIZE(tegra238_main_ports),
+ .ports = tegra238_main_ports,
+ .name = "tegra238-gpio",
+ .instance = 0,
+ .num_irqs_per_bank = 8,
+ .has_vm_support = true,
+};
+
+#define TEGRA238_AON_GPIO_PORT(_name, _bank, _port, _pins) \
+ TEGRA_GPIO_PORT(TEGRA238_AON, _name, _bank, _port, _pins)
+
+static const struct tegra_gpio_port tegra238_aon_ports[] = {
+ TEGRA238_AON_GPIO_PORT(AA, 0, 0, 8),
+ TEGRA238_AON_GPIO_PORT(BB, 0, 1, 1),
+ TEGRA238_AON_GPIO_PORT(CC, 0, 2, 8),
+ TEGRA238_AON_GPIO_PORT(DD, 0, 3, 8),
+ TEGRA238_AON_GPIO_PORT(EE, 0, 4, 6),
+ TEGRA238_AON_GPIO_PORT(FF, 0, 5, 8),
+ TEGRA238_AON_GPIO_PORT(GG, 0, 6, 8),
+ TEGRA238_AON_GPIO_PORT(HH, 0, 7, 4)
+};
+
+static const struct tegra_gpio_soc tegra238_aon_soc = {
+ .num_ports = ARRAY_SIZE(tegra238_aon_ports),
+ .ports = tegra238_aon_ports,
+ .name = "tegra238-gpio-aon",
+ .instance = 1,
+ .num_irqs_per_bank = 8,
+ .has_gte = true,
+ .has_vm_support = false,
+};
+
#define TEGRA241_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \
TEGRA_GPIO_PORT(TEGRA241_MAIN, _name, _bank, _port, _pins)
@@ -1333,6 +1395,7 @@ static const struct tegra_gpio_soc tegra264_aon_soc = {
.name = "tegra264-gpio-aon",
.instance = 1,
.num_irqs_per_bank = 8,
+ .has_gte = true,
.has_vm_support = true,
};
@@ -1448,6 +1511,12 @@ static const struct of_device_id tegra186_gpio_of_match[] = {
.compatible = "nvidia,tegra234-gpio-aon",
.data = &tegra234_aon_soc
}, {
+ .compatible = "nvidia,tegra238-gpio",
+ .data = &tegra238_main_soc
+ }, {
+ .compatible = "nvidia,tegra238-gpio-aon",
+ .data = &tegra238_aon_soc
+ }, {
.compatible = "nvidia,tegra256-gpio",
.data = &tegra256_main_soc
}, {
diff --git a/drivers/gpio/gpio-timberdale.c b/drivers/gpio/gpio-timberdale.c
index f488939dd00a..78fe133f5d32 100644
--- a/drivers/gpio/gpio-timberdale.c
+++ b/drivers/gpio/gpio-timberdale.c
@@ -14,7 +14,6 @@
#include <linux/platform_device.h>
#include <linux/irq.h>
#include <linux/io.h>
-#include <linux/timb_gpio.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
@@ -225,19 +224,21 @@ static int timbgpio_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct gpio_chip *gc;
struct timbgpio *tgpio;
- struct timbgpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
int irq = platform_get_irq(pdev, 0);
- if (!pdata || pdata->nr_pins > 32) {
- dev_err(dev, "Invalid platform data\n");
- return -EINVAL;
- }
-
tgpio = devm_kzalloc(dev, sizeof(*tgpio), GFP_KERNEL);
if (!tgpio)
return -EINVAL;
- tgpio->irq_base = pdata->irq_base;
+ gc = &tgpio->gpio;
+
+ err = device_property_read_u32(dev, "irq-base", &tgpio->irq_base);
+ if (err)
+ return err;
+
+ err = device_property_read_u32(dev, "gpio-base", &gc->base);
+ if (err)
+ return err;
spin_lock_init(&tgpio->lock);
@@ -245,8 +246,6 @@ static int timbgpio_probe(struct platform_device *pdev)
if (IS_ERR(tgpio->membase))
return PTR_ERR(tgpio->membase);
- gc = &tgpio->gpio;
-
gc->label = dev_name(&pdev->dev);
gc->owner = THIS_MODULE;
gc->parent = &pdev->dev;
@@ -256,21 +255,22 @@ static int timbgpio_probe(struct platform_device *pdev)
gc->set = timbgpio_gpio_set;
gc->to_irq = (irq >= 0 && tgpio->irq_base > 0) ? timbgpio_to_irq : NULL;
gc->dbg_show = NULL;
- gc->base = pdata->gpio_base;
- gc->ngpio = pdata->nr_pins;
gc->can_sleep = false;
err = devm_gpiochip_add_data(&pdev->dev, gc, tgpio);
if (err)
return err;
+ if (gc->ngpio > 32)
+ return dev_err_probe(dev, -EINVAL, "Invalid number of pins\n");
+
/* make sure to disable interrupts */
iowrite32(0x0, tgpio->membase + TGPIO_IER);
if (irq < 0 || tgpio->irq_base <= 0)
return 0;
- for (i = 0; i < pdata->nr_pins; i++) {
+ for (i = 0; i < gc->ngpio; i++) {
irq_set_chip_and_handler(tgpio->irq_base + i,
&timbgpio_irqchip, handle_simple_irq);
irq_set_chip_data(tgpio->irq_base + i, tgpio);
diff --git a/drivers/gpio/gpio-tpic2810.c b/drivers/gpio/gpio-tpic2810.c
index 866ff2d436d5..c38538653e99 100644
--- a/drivers/gpio/gpio-tpic2810.c
+++ b/drivers/gpio/gpio-tpic2810.c
@@ -112,7 +112,7 @@ static int tpic2810_probe(struct i2c_client *client)
}
static const struct i2c_device_id tpic2810_id_table[] = {
- { "tpic2810", },
+ { .name = "tpic2810" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, tpic2810_id_table);
diff --git a/drivers/gpio/gpio-tps65086.c b/drivers/gpio/gpio-tps65086.c
index df770ecf28bc..f29d8485ab33 100644
--- a/drivers/gpio/gpio-tps65086.c
+++ b/drivers/gpio/gpio-tps65086.c
@@ -91,7 +91,7 @@ static int tps65086_gpio_probe(struct platform_device *pdev)
}
static const struct platform_device_id tps65086_gpio_id_table[] = {
- { "tps65086-gpio", },
+ { .name = "tps65086-gpio" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(platform, tps65086_gpio_id_table);
diff --git a/drivers/gpio/gpio-tps65218.c b/drivers/gpio/gpio-tps65218.c
index 3b4c41f5ef55..bf85663349fb 100644
--- a/drivers/gpio/gpio-tps65218.c
+++ b/drivers/gpio/gpio-tps65218.c
@@ -201,7 +201,7 @@ static const struct of_device_id tps65218_dt_match[] = {
MODULE_DEVICE_TABLE(of, tps65218_dt_match);
static const struct platform_device_id tps65218_gpio_id_table[] = {
- { "tps65218-gpio", },
+ { .name = "tps65218-gpio" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(platform, tps65218_gpio_id_table);
diff --git a/drivers/gpio/gpio-tps65219.c b/drivers/gpio/gpio-tps65219.c
index 158f63bcf10c..457fd8a589e8 100644
--- a/drivers/gpio/gpio-tps65219.c
+++ b/drivers/gpio/gpio-tps65219.c
@@ -249,8 +249,8 @@ static int tps65219_gpio_probe(struct platform_device *pdev)
}
static const struct platform_device_id tps6521x_gpio_id_table[] = {
- { "tps65214-gpio", TPS65214 },
- { "tps65219-gpio", TPS65219 },
+ { .name = "tps65214-gpio", .driver_data = TPS65214 },
+ { .name = "tps65219-gpio", .driver_data = TPS65219 },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(platform, tps6521x_gpio_id_table);
diff --git a/drivers/gpio/gpio-tps65912.c b/drivers/gpio/gpio-tps65912.c
index 7a2c5685c2fd..cf3fa49a7097 100644
--- a/drivers/gpio/gpio-tps65912.c
+++ b/drivers/gpio/gpio-tps65912.c
@@ -115,7 +115,7 @@ static int tps65912_gpio_probe(struct platform_device *pdev)
}
static const struct platform_device_id tps65912_gpio_id_table[] = {
- { "tps65912-gpio", },
+ { .name = "tps65912-gpio" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(platform, tps65912_gpio_id_table);
diff --git a/drivers/gpio/gpio-ts4900.c b/drivers/gpio/gpio-ts4900.c
index d9ee8fc77ccd..b46b48e56c56 100644
--- a/drivers/gpio/gpio-ts4900.c
+++ b/drivers/gpio/gpio-ts4900.c
@@ -175,7 +175,7 @@ static int ts4900_gpio_probe(struct i2c_client *client)
}
static const struct i2c_device_id ts4900_gpio_id_table[] = {
- { "ts4900-gpio", },
+ { .name = "ts4900-gpio" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, ts4900_gpio_id_table);
diff --git a/drivers/gpio/gpio-ts5500.c b/drivers/gpio/gpio-ts5500.c
deleted file mode 100644
index 3c7f2efe10fd..000000000000
--- a/drivers/gpio/gpio-ts5500.c
+++ /dev/null
@@ -1,446 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Digital I/O driver for Technologic Systems TS-5500
- *
- * Copyright (c) 2012 Savoir-faire Linux Inc.
- * Vivien Didelot <vivien.didelot@savoirfairelinux.com>
- *
- * Technologic Systems platforms have pin blocks, exposing several Digital
- * Input/Output lines (DIO). This driver aims to support single pin blocks.
- * In that sense, the support is not limited to the TS-5500 blocks.
- * Actually, the following platforms have DIO support:
- *
- * TS-5500:
- * Documentation: https://docs.embeddedts.com/TS-5500
- * Blocks: DIO1, DIO2 and LCD port.
- *
- * TS-5600:
- * Documentation: https://docs.embeddedts.com/TS-5600
- * Blocks: LCD port (identical to TS-5500 LCD).
- */
-
-#include <linux/bitops.h>
-#include <linux/gpio/driver.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-
-/* List of supported Technologic Systems platforms DIO blocks */
-enum ts5500_blocks { TS5500_DIO1, TS5500_DIO2, TS5500_LCD, TS5600_LCD };
-
-struct ts5500_priv {
- const struct ts5500_dio *pinout;
- struct gpio_chip gpio_chip;
- spinlock_t lock;
- bool strap;
- u8 hwirq;
-};
-
-/*
- * Hex 7D is used to control several blocks (e.g. DIO2 and LCD port).
- * This flag ensures that the region has been requested by this driver.
- */
-static bool hex7d_reserved;
-
-/*
- * This structure is used to describe capabilities of DIO lines,
- * such as available directions and connected interrupt (if any).
- */
-struct ts5500_dio {
- const u8 value_addr;
- const u8 value_mask;
- const u8 control_addr;
- const u8 control_mask;
- const bool no_input;
- const bool no_output;
- const u8 irq;
-};
-
-#define TS5500_DIO_IN_OUT(vaddr, vbit, caddr, cbit) \
- { \
- .value_addr = vaddr, \
- .value_mask = BIT(vbit), \
- .control_addr = caddr, \
- .control_mask = BIT(cbit), \
- }
-
-#define TS5500_DIO_IN(addr, bit) \
- { \
- .value_addr = addr, \
- .value_mask = BIT(bit), \
- .no_output = true, \
- }
-
-#define TS5500_DIO_IN_IRQ(addr, bit, _irq) \
- { \
- .value_addr = addr, \
- .value_mask = BIT(bit), \
- .no_output = true, \
- .irq = _irq, \
- }
-
-#define TS5500_DIO_OUT(addr, bit) \
- { \
- .value_addr = addr, \
- .value_mask = BIT(bit), \
- .no_input = true, \
- }
-
-/*
- * Input/Output DIO lines are programmed in groups of 4. Their values are
- * available through 4 consecutive bits in a value port, whereas the direction
- * of these 4 lines is driven by only 1 bit in a control port.
- */
-#define TS5500_DIO_GROUP(vaddr, vbitfrom, caddr, cbit) \
- TS5500_DIO_IN_OUT(vaddr, vbitfrom + 0, caddr, cbit), \
- TS5500_DIO_IN_OUT(vaddr, vbitfrom + 1, caddr, cbit), \
- TS5500_DIO_IN_OUT(vaddr, vbitfrom + 2, caddr, cbit), \
- TS5500_DIO_IN_OUT(vaddr, vbitfrom + 3, caddr, cbit)
-
-/*
- * TS-5500 DIO1 block
- *
- * value control dir hw
- * addr bit addr bit in out irq name pin offset
- *
- * 0x7b 0 0x7a 0 x x DIO1_0 1 0
- * 0x7b 1 0x7a 0 x x DIO1_1 3 1
- * 0x7b 2 0x7a 0 x x DIO1_2 5 2
- * 0x7b 3 0x7a 0 x x DIO1_3 7 3
- * 0x7b 4 0x7a 1 x x DIO1_4 9 4
- * 0x7b 5 0x7a 1 x x DIO1_5 11 5
- * 0x7b 6 0x7a 1 x x DIO1_6 13 6
- * 0x7b 7 0x7a 1 x x DIO1_7 15 7
- * 0x7c 0 0x7a 5 x x DIO1_8 4 8
- * 0x7c 1 0x7a 5 x x DIO1_9 6 9
- * 0x7c 2 0x7a 5 x x DIO1_10 8 10
- * 0x7c 3 0x7a 5 x x DIO1_11 10 11
- * 0x7c 4 x DIO1_12 12 12
- * 0x7c 5 x 7 DIO1_13 14 13
- */
-static const struct ts5500_dio ts5500_dio1[] = {
- TS5500_DIO_GROUP(0x7b, 0, 0x7a, 0),
- TS5500_DIO_GROUP(0x7b, 4, 0x7a, 1),
- TS5500_DIO_GROUP(0x7c, 0, 0x7a, 5),
- TS5500_DIO_IN(0x7c, 4),
- TS5500_DIO_IN_IRQ(0x7c, 5, 7),
-};
-
-/*
- * TS-5500 DIO2 block
- *
- * value control dir hw
- * addr bit addr bit in out irq name pin offset
- *
- * 0x7e 0 0x7d 0 x x DIO2_0 1 0
- * 0x7e 1 0x7d 0 x x DIO2_1 3 1
- * 0x7e 2 0x7d 0 x x DIO2_2 5 2
- * 0x7e 3 0x7d 0 x x DIO2_3 7 3
- * 0x7e 4 0x7d 1 x x DIO2_4 9 4
- * 0x7e 5 0x7d 1 x x DIO2_5 11 5
- * 0x7e 6 0x7d 1 x x DIO2_6 13 6
- * 0x7e 7 0x7d 1 x x DIO2_7 15 7
- * 0x7f 0 0x7d 5 x x DIO2_8 4 8
- * 0x7f 1 0x7d 5 x x DIO2_9 6 9
- * 0x7f 2 0x7d 5 x x DIO2_10 8 10
- * 0x7f 3 0x7d 5 x x DIO2_11 10 11
- * 0x7f 4 x 6 DIO2_13 14 12
- */
-static const struct ts5500_dio ts5500_dio2[] = {
- TS5500_DIO_GROUP(0x7e, 0, 0x7d, 0),
- TS5500_DIO_GROUP(0x7e, 4, 0x7d, 1),
- TS5500_DIO_GROUP(0x7f, 0, 0x7d, 5),
- TS5500_DIO_IN_IRQ(0x7f, 4, 6),
-};
-
-/*
- * TS-5500 LCD port used as DIO block
- * TS-5600 LCD port is identical
- *
- * value control dir hw
- * addr bit addr bit in out irq name pin offset
- *
- * 0x72 0 0x7d 2 x x LCD_0 8 0
- * 0x72 1 0x7d 2 x x LCD_1 7 1
- * 0x72 2 0x7d 2 x x LCD_2 10 2
- * 0x72 3 0x7d 2 x x LCD_3 9 3
- * 0x72 4 0x7d 3 x x LCD_4 12 4
- * 0x72 5 0x7d 3 x x LCD_5 11 5
- * 0x72 6 0x7d 3 x x LCD_6 14 6
- * 0x72 7 0x7d 3 x x LCD_7 13 7
- * 0x73 0 x LCD_EN 5 8
- * 0x73 6 x LCD_WR 6 9
- * 0x73 7 x 1 LCD_RS 3 10
- */
-static const struct ts5500_dio ts5500_lcd[] = {
- TS5500_DIO_GROUP(0x72, 0, 0x7d, 2),
- TS5500_DIO_GROUP(0x72, 4, 0x7d, 3),
- TS5500_DIO_OUT(0x73, 0),
- TS5500_DIO_IN(0x73, 6),
- TS5500_DIO_IN_IRQ(0x73, 7, 1),
-};
-
-static inline void ts5500_set_mask(u8 mask, u8 addr)
-{
- u8 val = inb(addr);
- val |= mask;
- outb(val, addr);
-}
-
-static inline void ts5500_clear_mask(u8 mask, u8 addr)
-{
- u8 val = inb(addr);
- val &= ~mask;
- outb(val, addr);
-}
-
-static int ts5500_gpio_input(struct gpio_chip *chip, unsigned offset)
-{
- struct ts5500_priv *priv = gpiochip_get_data(chip);
- const struct ts5500_dio line = priv->pinout[offset];
- unsigned long flags;
-
- if (line.no_input)
- return -ENXIO;
-
- if (line.no_output)
- return 0;
-
- spin_lock_irqsave(&priv->lock, flags);
- ts5500_clear_mask(line.control_mask, line.control_addr);
- spin_unlock_irqrestore(&priv->lock, flags);
-
- return 0;
-}
-
-static int ts5500_gpio_get(struct gpio_chip *chip, unsigned offset)
-{
- struct ts5500_priv *priv = gpiochip_get_data(chip);
- const struct ts5500_dio line = priv->pinout[offset];
-
- return !!(inb(line.value_addr) & line.value_mask);
-}
-
-static int ts5500_gpio_output(struct gpio_chip *chip, unsigned offset, int val)
-{
- struct ts5500_priv *priv = gpiochip_get_data(chip);
- const struct ts5500_dio line = priv->pinout[offset];
- unsigned long flags;
-
- if (line.no_output)
- return -ENXIO;
-
- spin_lock_irqsave(&priv->lock, flags);
- if (!line.no_input)
- ts5500_set_mask(line.control_mask, line.control_addr);
-
- if (val)
- ts5500_set_mask(line.value_mask, line.value_addr);
- else
- ts5500_clear_mask(line.value_mask, line.value_addr);
- spin_unlock_irqrestore(&priv->lock, flags);
-
- return 0;
-}
-
-static int ts5500_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
-{
- struct ts5500_priv *priv = gpiochip_get_data(chip);
- const struct ts5500_dio line = priv->pinout[offset];
- unsigned long flags;
-
- spin_lock_irqsave(&priv->lock, flags);
- if (val)
- ts5500_set_mask(line.value_mask, line.value_addr);
- else
- ts5500_clear_mask(line.value_mask, line.value_addr);
- spin_unlock_irqrestore(&priv->lock, flags);
-
- return 0;
-}
-
-static int ts5500_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
-{
- struct ts5500_priv *priv = gpiochip_get_data(chip);
- const struct ts5500_dio *block = priv->pinout;
- const struct ts5500_dio line = block[offset];
-
- /* Only one pin is connected to an interrupt */
- if (line.irq)
- return line.irq;
-
- /* As this pin is input-only, we may strap it to another in/out pin */
- if (priv->strap)
- return priv->hwirq;
-
- return -ENXIO;
-}
-
-static int ts5500_enable_irq(struct ts5500_priv *priv)
-{
- int ret = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->lock, flags);
- if (priv->hwirq == 7)
- ts5500_set_mask(BIT(7), 0x7a); /* DIO1_13 on IRQ7 */
- else if (priv->hwirq == 6)
- ts5500_set_mask(BIT(7), 0x7d); /* DIO2_13 on IRQ6 */
- else if (priv->hwirq == 1)
- ts5500_set_mask(BIT(6), 0x7d); /* LCD_RS on IRQ1 */
- else
- ret = -EINVAL;
- spin_unlock_irqrestore(&priv->lock, flags);
-
- return ret;
-}
-
-static void ts5500_disable_irq(struct ts5500_priv *priv)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&priv->lock, flags);
- if (priv->hwirq == 7)
- ts5500_clear_mask(BIT(7), 0x7a); /* DIO1_13 on IRQ7 */
- else if (priv->hwirq == 6)
- ts5500_clear_mask(BIT(7), 0x7d); /* DIO2_13 on IRQ6 */
- else if (priv->hwirq == 1)
- ts5500_clear_mask(BIT(6), 0x7d); /* LCD_RS on IRQ1 */
- else
- dev_err(priv->gpio_chip.parent, "invalid hwirq %d\n",
- priv->hwirq);
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static int ts5500_dio_probe(struct platform_device *pdev)
-{
- enum ts5500_blocks block = platform_get_device_id(pdev)->driver_data;
- struct device *dev = &pdev->dev;
- const char *name = dev_name(dev);
- struct ts5500_priv *priv;
- unsigned long flags;
- int ret;
-
- ret = platform_get_irq(pdev, 0);
- if (ret < 0)
- return ret;
-
- priv = devm_kzalloc(dev, sizeof(struct ts5500_priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
- platform_set_drvdata(pdev, priv);
- priv->hwirq = ret;
- spin_lock_init(&priv->lock);
-
- priv->gpio_chip.owner = THIS_MODULE;
- priv->gpio_chip.label = name;
- priv->gpio_chip.parent = dev;
- priv->gpio_chip.direction_input = ts5500_gpio_input;
- priv->gpio_chip.direction_output = ts5500_gpio_output;
- priv->gpio_chip.get = ts5500_gpio_get;
- priv->gpio_chip.set = ts5500_gpio_set;
- priv->gpio_chip.to_irq = ts5500_gpio_to_irq;
- priv->gpio_chip.base = -1;
-
- switch (block) {
- case TS5500_DIO1:
- priv->pinout = ts5500_dio1;
- priv->gpio_chip.ngpio = ARRAY_SIZE(ts5500_dio1);
-
- if (!devm_request_region(dev, 0x7a, 3, name)) {
- dev_err(dev, "failed to request %s ports\n", name);
- return -EBUSY;
- }
- break;
- case TS5500_DIO2:
- priv->pinout = ts5500_dio2;
- priv->gpio_chip.ngpio = ARRAY_SIZE(ts5500_dio2);
-
- if (!devm_request_region(dev, 0x7e, 2, name)) {
- dev_err(dev, "failed to request %s ports\n", name);
- return -EBUSY;
- }
-
- if (hex7d_reserved)
- break;
-
- if (!devm_request_region(dev, 0x7d, 1, name)) {
- dev_err(dev, "failed to request %s 7D\n", name);
- return -EBUSY;
- }
-
- hex7d_reserved = true;
- break;
- case TS5500_LCD:
- case TS5600_LCD:
- priv->pinout = ts5500_lcd;
- priv->gpio_chip.ngpio = ARRAY_SIZE(ts5500_lcd);
-
- if (!devm_request_region(dev, 0x72, 2, name)) {
- dev_err(dev, "failed to request %s ports\n", name);
- return -EBUSY;
- }
-
- if (!hex7d_reserved) {
- if (!devm_request_region(dev, 0x7d, 1, name)) {
- dev_err(dev, "failed to request %s 7D\n", name);
- return -EBUSY;
- }
-
- hex7d_reserved = true;
- }
-
- /* Ensure usage of LCD port as DIO */
- spin_lock_irqsave(&priv->lock, flags);
- ts5500_clear_mask(BIT(4), 0x7d);
- spin_unlock_irqrestore(&priv->lock, flags);
- break;
- }
-
- ret = devm_gpiochip_add_data(dev, &priv->gpio_chip, priv);
- if (ret) {
- dev_err(dev, "failed to register the gpio chip\n");
- return ret;
- }
-
- ret = ts5500_enable_irq(priv);
- if (ret) {
- dev_err(dev, "invalid interrupt %d\n", priv->hwirq);
- return ret;
- }
-
- return 0;
-}
-
-static void ts5500_dio_remove(struct platform_device *pdev)
-{
- struct ts5500_priv *priv = platform_get_drvdata(pdev);
-
- ts5500_disable_irq(priv);
-}
-
-static const struct platform_device_id ts5500_dio_ids[] = {
- { "ts5500-dio1", TS5500_DIO1 },
- { "ts5500-dio2", TS5500_DIO2 },
- { "ts5500-dio-lcd", TS5500_LCD },
- { "ts5600-dio-lcd", TS5600_LCD },
- { }
-};
-MODULE_DEVICE_TABLE(platform, ts5500_dio_ids);
-
-static struct platform_driver ts5500_dio_driver = {
- .driver = {
- .name = "ts5500-dio",
- },
- .probe = ts5500_dio_probe,
- .remove = ts5500_dio_remove,
- .id_table = ts5500_dio_ids,
-};
-
-module_platform_driver(ts5500_dio_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Savoir-faire Linux Inc. <kernel@savoirfairelinux.com>");
-MODULE_DESCRIPTION("Technologic Systems TS-5500 Digital I/O driver");
diff --git a/drivers/gpio/gpio-usbio.c b/drivers/gpio/gpio-usbio.c
index 34d42c743d5b..489c8ac6299e 100644
--- a/drivers/gpio/gpio-usbio.c
+++ b/drivers/gpio/gpio-usbio.c
@@ -31,6 +31,7 @@ static const struct acpi_device_id usbio_gpio_acpi_hids[] = {
{ "INTC10B5" }, /* LNL */
{ "INTC10D1" }, /* MTL-CVF */
{ "INTC10E2" }, /* PTL */
+ { "INTC1116" }, /* NVL */
{ }
};
diff --git a/drivers/gpio/gpio-waveshare-dsi.c b/drivers/gpio/gpio-waveshare-dsi.c
new file mode 100644
index 000000000000..38f52351bb58
--- /dev/null
+++ b/drivers/gpio/gpio-waveshare-dsi.c
@@ -0,0 +1,208 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2024 Waveshare International Limited
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/backlight.h>
+#include <linux/err.h>
+#include <linux/fb.h>
+#include <linux/gpio/driver.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+
+/* I2C registers of the microcontroller. */
+#define REG_TP 0x94
+#define REG_LCD 0x95
+#define REG_PWM 0x96
+#define REG_SIZE 0x97
+#define REG_ID 0x98
+#define REG_VERSION 0x99
+
+enum {
+ GPIO_AVDD = 0,
+ GPIO_PANEL_RESET = 1,
+ GPIO_BL_ENABLE = 2,
+ GPIO_IOVCC = 4,
+ GPIO_VCC = 8,
+ GPIO_TS_RESET = 9,
+};
+
+#define NUM_GPIO 16
+
+struct waveshare_gpio {
+ struct mutex dir_lock;
+ struct mutex pwr_lock;
+ struct regmap *regmap;
+ u16 poweron_state;
+
+ struct gpio_chip gc;
+};
+
+static const struct regmap_config waveshare_gpio_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = REG_VERSION,
+};
+
+static int waveshare_gpio_get(struct waveshare_gpio *state, unsigned int offset)
+{
+ u16 pwr_state;
+
+ guard(mutex)(&state->pwr_lock);
+ pwr_state = state->poweron_state & BIT(offset);
+
+ return !!pwr_state;
+}
+
+static int waveshare_gpio_set(struct waveshare_gpio *state, unsigned int offset, int value)
+{
+ u16 last_val;
+ int err;
+
+ guard(mutex)(&state->pwr_lock);
+
+ last_val = state->poweron_state;
+ if (value)
+ last_val |= BIT(offset);
+ else
+ last_val &= ~BIT(offset);
+
+ state->poweron_state = last_val;
+
+ err = regmap_write(state->regmap, REG_TP, last_val >> 8);
+ if (!err)
+ err = regmap_write(state->regmap, REG_LCD, last_val & 0xff);
+
+ return err;
+}
+
+static int waveshare_gpio_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
+{
+ return GPIO_LINE_DIRECTION_OUT;
+}
+
+static int waveshare_gpio_gpio_get(struct gpio_chip *gc, unsigned int offset)
+{
+ struct waveshare_gpio *state = gpiochip_get_data(gc);
+
+ return waveshare_gpio_get(state, offset);
+}
+
+static int waveshare_gpio_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
+{
+ struct waveshare_gpio *state = gpiochip_get_data(gc);
+
+ return waveshare_gpio_set(state, offset, value);
+}
+
+static int waveshare_gpio_update_status(struct backlight_device *bl)
+{
+ struct waveshare_gpio *state = bl_get_data(bl);
+ int brightness = backlight_get_brightness(bl);
+
+ waveshare_gpio_set(state, GPIO_BL_ENABLE, brightness);
+
+ return regmap_write(state->regmap, REG_PWM, brightness);
+}
+
+static const struct backlight_ops waveshare_gpio_bl = {
+ .update_status = waveshare_gpio_update_status,
+};
+
+static int waveshare_gpio_probe(struct i2c_client *i2c)
+{
+ struct backlight_properties props = {};
+ struct waveshare_gpio *state;
+ struct device *dev = &i2c->dev;
+ struct backlight_device *bl;
+ struct regmap *regmap;
+ unsigned int data;
+ int ret;
+
+ state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return -ENOMEM;
+
+ ret = devm_mutex_init(dev, &state->dir_lock);
+ if (ret)
+ return ret;
+
+ ret = devm_mutex_init(dev, &state->pwr_lock);
+ if (ret)
+ return ret;
+
+ regmap = devm_regmap_init_i2c(i2c, &waveshare_gpio_regmap_config);
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap), "Failed to allocate register map\n");
+
+ state->regmap = regmap;
+ i2c_set_clientdata(i2c, state);
+
+ ret = regmap_read(regmap, REG_ID, &data);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Failed to read register\n");
+
+ dev_dbg(dev, "waveshare panel hw id = 0x%x\n", data);
+
+ ret = regmap_read(regmap, REG_SIZE, &data);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Failed to read register\n");
+
+ dev_dbg(dev, "waveshare panel size = %d\n", data);
+
+ ret = regmap_read(regmap, REG_VERSION, &data);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Failed to read register\n");
+
+ dev_dbg(dev, "waveshare panel mcu version = 0x%x\n", data);
+
+ ret = waveshare_gpio_set(state, GPIO_TS_RESET, 1);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to program GPIOs\n");
+
+ msleep(20);
+
+ state->gc.parent = dev;
+ state->gc.label = i2c->name;
+ state->gc.owner = THIS_MODULE;
+ state->gc.base = -1;
+ state->gc.ngpio = NUM_GPIO;
+
+ /* it is output only */
+ state->gc.get = waveshare_gpio_gpio_get;
+ state->gc.set = waveshare_gpio_gpio_set;
+ state->gc.get_direction = waveshare_gpio_gpio_get_direction;
+ state->gc.can_sleep = true;
+
+ ret = devm_gpiochip_add_data(dev, &state->gc, state);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to create gpiochip\n");
+
+ props.type = BACKLIGHT_RAW;
+ props.max_brightness = 255;
+ props.brightness = 255;
+ bl = devm_backlight_device_register(dev, dev_name(dev), dev, state,
+ &waveshare_gpio_bl, &props);
+ return PTR_ERR_OR_ZERO(bl);
+}
+
+static const struct of_device_id waveshare_gpio_dt_ids[] = {
+ { .compatible = "waveshare,dsi-touch-gpio" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, waveshare_gpio_dt_ids);
+
+static struct i2c_driver waveshare_gpio_regulator_driver = {
+ .driver = {
+ .name = "waveshare-regulator",
+ .of_match_table = of_match_ptr(waveshare_gpio_dt_ids),
+ },
+ .probe = waveshare_gpio_probe,
+};
+
+module_i2c_driver(waveshare_gpio_regulator_driver);
+
+MODULE_DESCRIPTION("GPIO controller driver for Waveshare DSI touch panels");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c
index be4b4d730547..532205175827 100644
--- a/drivers/gpio/gpio-xilinx.c
+++ b/drivers/gpio/gpio-xilinx.c
@@ -495,13 +495,11 @@ static void xgpio_irqhandler(struct irq_desc *desc)
xgpio_read_ch_all(chip, XGPIO_DATA_OFFSET, hw);
- bitmap_complement(rising, chip->last_irq_read, 64);
- bitmap_and(rising, rising, hw, 64);
+ bitmap_andnot(rising, hw, chip->last_irq_read, 64);
bitmap_and(rising, rising, chip->enable, 64);
bitmap_and(rising, rising, chip->rising_edge, 64);
- bitmap_complement(falling, hw, 64);
- bitmap_and(falling, falling, chip->last_irq_read, 64);
+ bitmap_andnot(falling, chip->last_irq_read, hw, 64);
bitmap_and(falling, falling, chip->enable, 64);
bitmap_and(falling, falling, chip->falling_edge, 64);
diff --git a/drivers/gpio/gpio-zevio.c b/drivers/gpio/gpio-zevio.c
index 29375bea2289..af0158522ac5 100644
--- a/drivers/gpio/gpio-zevio.c
+++ b/drivers/gpio/gpio-zevio.c
@@ -64,14 +64,14 @@ static inline u32 zevio_gpio_port_get(struct zevio_gpio *c, unsigned pin,
unsigned port_offset)
{
unsigned section_offset = ((pin >> 3) & 3)*ZEVIO_GPIO_SECTION_SIZE;
- return readl(IOMEM(c->regs + section_offset + port_offset));
+ return readl(c->regs + section_offset + port_offset);
}
static inline void zevio_gpio_port_set(struct zevio_gpio *c, unsigned pin,
unsigned port_offset, u32 val)
{
unsigned section_offset = ((pin >> 3) & 3)*ZEVIO_GPIO_SECTION_SIZE;
- writel(val, IOMEM(c->regs + section_offset + port_offset));
+ writel(val, c->regs + section_offset + port_offset);
}
/* Functions for struct gpio_chip */
diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c
index fafca91128b2..15a79d9a2e9e 100644
--- a/drivers/gpio/gpio-zynq.c
+++ b/drivers/gpio/gpio-zynq.c
@@ -25,6 +25,7 @@
#define VERSAL_GPIO_MAX_BANK 4
#define PMC_GPIO_MAX_BANK 5
#define VERSAL_UNUSED_BANKS 2
+#define EIO_GPIO_MAX_BANK 2
#define ZYNQ_GPIO_BANK0_NGPIO 32
#define ZYNQ_GPIO_BANK1_NGPIO 22
@@ -818,6 +819,16 @@ static const struct dev_pm_ops zynq_gpio_dev_pm_ops = {
RUNTIME_PM_OPS(zynq_gpio_runtime_suspend, zynq_gpio_runtime_resume, NULL)
};
+static const struct zynq_platform_data eio_gpio_def = {
+ .label = "eio_gpio",
+ .ngpio = 52,
+ .max_bank = EIO_GPIO_MAX_BANK,
+ .bank_min[0] = 0,
+ .bank_max[0] = 25, /* 0 to 25 are connected to MIOs (26 pins) */
+ .bank_min[1] = 26,
+ .bank_max[1] = 51, /* Bank 1 are connected to MIOs (26 pins) */
+};
+
static const struct zynq_platform_data versal_gpio_def = {
.label = "versal_gpio",
.quirks = GPIO_QUIRK_VERSAL,
@@ -882,6 +893,7 @@ static const struct of_device_id zynq_gpio_of_match[] = {
{ .compatible = "xlnx,zynqmp-gpio-1.0", .data = &zynqmp_gpio_def },
{ .compatible = "xlnx,versal-gpio-1.0", .data = &versal_gpio_def },
{ .compatible = "xlnx,pmc-gpio-1.0", .data = &pmc_gpio_def },
+ { .compatible = "xlnx,eio-gpio-1.0", .data = &eio_gpio_def },
{ /* end of table */ }
};
MODULE_DEVICE_TABLE(of, zynq_gpio_of_match);
diff --git a/drivers/gpio/gpiolib-acpi-core.c b/drivers/gpio/gpiolib-acpi-core.c
index 09f860200a05..fbd6945726bf 100644
--- a/drivers/gpio/gpiolib-acpi-core.c
+++ b/drivers/gpio/gpiolib-acpi-core.c
@@ -142,10 +142,6 @@ static struct gpio_desc *acpi_get_gpiod(char *path, unsigned int pin)
if (!gdev)
return ERR_PTR(-EPROBE_DEFER);
- /*
- * FIXME: keep track of the reference to the GPIO device somehow
- * instead of putting it here.
- */
return gpio_device_get_desc(gdev, pin);
}
diff --git a/drivers/gpio/gpiolib-devres.c b/drivers/gpio/gpiolib-devres.c
index 72422c5db364..2ec825ffab7d 100644
--- a/drivers/gpio/gpiolib-devres.c
+++ b/drivers/gpio/gpiolib-devres.c
@@ -353,6 +353,13 @@ int devm_gpiochip_add_data_with_key(struct device *dev, struct gpio_chip *gc, vo
{
int ret;
+ /*
+ * We are passing the devres device here so if the user did not pass
+ * another parent, it's this one.
+ */
+ if (!gc->parent)
+ gc->parent = dev;
+
ret = gpiochip_add_data_with_key(gc, data, lock_key, request_key);
if (ret < 0)
return ret;
diff --git a/drivers/gpio/gpiolib-kunit.c b/drivers/gpio/gpiolib-kunit.c
new file mode 100644
index 000000000000..380b68f879e5
--- /dev/null
+++ b/drivers/gpio/gpiolib-kunit.c
@@ -0,0 +1,358 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) Qualcomm Technologies, Inc. and/or its subsidiaries
+ */
+
+#include <linux/fwnode.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/driver.h>
+#include <linux/gpio/machine.h>
+#include <linux/gpio/property.h>
+#include <linux/notifier.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+
+#include <kunit/platform_device.h>
+#include <kunit/test.h>
+
+#define GPIO_TEST_PROVIDER "gpio-test-provider"
+#define GPIO_SWNODE_TEST_CONSUMER "gpio-swnode-test-consumer"
+#define GPIO_UNBIND_TEST_CONSUMER "gpio-unbind-test-consumer"
+
+static int gpio_test_provider_get_direction(struct gpio_chip *gc, unsigned int offset)
+{
+ return GPIO_LINE_DIRECTION_OUT;
+}
+
+static int gpio_test_provider_set(struct gpio_chip *gc, unsigned int offset, int value)
+{
+ return 0;
+}
+
+static int gpio_test_provider_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct gpio_chip *gc;
+
+ gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL);
+ if (!gc)
+ return -ENOMEM;
+
+ gc->base = -1;
+ gc->ngpio = 4;
+ gc->label = "gpio-swnode-consumer-test-device";
+ gc->parent = dev;
+ gc->owner = THIS_MODULE;
+
+ gc->get_direction = gpio_test_provider_get_direction;
+ gc->set = gpio_test_provider_set;
+
+ return devm_gpiochip_add_data(dev, gc, NULL);
+}
+
+static struct platform_driver gpio_test_provider_driver = {
+ .probe = gpio_test_provider_probe,
+ .driver = {
+ .name = GPIO_TEST_PROVIDER,
+ },
+};
+
+static const struct software_node gpio_test_provider_swnode = {
+ .name = "gpio-test-provider-primary",
+};
+
+struct gpio_swnode_consumer_pdata {
+ bool gpio_ok;
+};
+
+static const struct gpio_swnode_consumer_pdata gpio_swnode_pdata_template = {
+ .gpio_ok = false,
+};
+
+static int gpio_swnode_consumer_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct gpio_swnode_consumer_pdata *pdata = dev_get_platdata(dev);
+ struct gpio_desc *desc;
+
+ desc = devm_gpiod_get(dev, "foo", GPIOD_OUT_HIGH);
+ if (IS_ERR(desc))
+ return PTR_ERR(desc);
+
+ pdata->gpio_ok = true;
+
+ return 0;
+}
+
+static struct platform_driver gpio_swnode_consumer_driver = {
+ .probe = gpio_swnode_consumer_probe,
+ .driver = {
+ .name = GPIO_SWNODE_TEST_CONSUMER,
+ },
+};
+
+static void gpio_swnode_lookup_by_primary(struct kunit *test)
+{
+ struct gpio_swnode_consumer_pdata *pdata;
+ struct platform_device_info pdevinfo;
+ struct property_entry properties[2];
+ struct platform_device *pdev;
+ bool bound = false;
+ int ret;
+
+ ret = kunit_platform_driver_register(test, &gpio_test_provider_driver);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ ret = kunit_platform_driver_register(test, &gpio_swnode_consumer_driver);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ pdevinfo = (struct platform_device_info){
+ .name = GPIO_TEST_PROVIDER,
+ .id = PLATFORM_DEVID_NONE,
+ .swnode = &gpio_test_provider_swnode,
+ };
+
+ pdev = kunit_platform_device_register_full(test, &pdevinfo);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
+
+ properties[0] = PROPERTY_ENTRY_GPIO("foo-gpios",
+ &gpio_test_provider_swnode,
+ 0, GPIO_ACTIVE_HIGH);
+ properties[1] = (struct property_entry){ };
+
+ pdevinfo = (struct platform_device_info){
+ .name = GPIO_SWNODE_TEST_CONSUMER,
+ .id = PLATFORM_DEVID_NONE,
+ .data = &gpio_swnode_pdata_template,
+ .size_data = sizeof(gpio_swnode_pdata_template),
+ .properties = properties,
+ };
+
+ pdev = kunit_platform_device_register_full(test, &pdevinfo);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
+
+ wait_for_device_probe();
+ scoped_guard(device, &pdev->dev)
+ bound = device_is_bound(&pdev->dev);
+
+ KUNIT_ASSERT_TRUE(test, bound);
+
+ pdata = dev_get_platdata(&pdev->dev);
+ KUNIT_ASSERT_TRUE(test, pdata->gpio_ok);
+}
+
+static void gpio_swnode_lookup_by_secondary(struct kunit *test)
+{
+ struct gpio_swnode_consumer_pdata *pdata;
+ struct platform_device_info pdevinfo;
+ struct property_entry properties[2];
+ struct fwnode_handle *primary;
+ struct platform_device *pdev;
+ bool bound = false;
+ int ret;
+
+ /*
+ * Can't live on the stack as it will still get referenced in cleanup
+ * path after this function returns.
+ */
+ primary = kunit_kzalloc(test, sizeof(*primary), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, primary);
+
+ ret = kunit_platform_driver_register(test, &gpio_test_provider_driver);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ ret = kunit_platform_driver_register(test, &gpio_swnode_consumer_driver);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ fwnode_init(primary, NULL);
+
+ pdevinfo = (struct platform_device_info){
+ .name = GPIO_TEST_PROVIDER,
+ .id = PLATFORM_DEVID_NONE,
+ .fwnode = primary,
+ .swnode = &gpio_test_provider_swnode,
+ };
+
+ pdev = kunit_platform_device_register_full(test, &pdevinfo);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
+
+ properties[0] = PROPERTY_ENTRY_GPIO("foo-gpios",
+ &gpio_test_provider_swnode,
+ 0, GPIO_ACTIVE_HIGH);
+ properties[1] = (struct property_entry){ };
+
+ pdevinfo = (struct platform_device_info){
+ .name = GPIO_SWNODE_TEST_CONSUMER,
+ .id = PLATFORM_DEVID_NONE,
+ .data = &gpio_swnode_pdata_template,
+ .size_data = sizeof(gpio_swnode_pdata_template),
+ .properties = properties,
+ };
+
+ pdev = kunit_platform_device_register_full(test, &pdevinfo);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
+
+ wait_for_device_probe();
+ scoped_guard(device, &pdev->dev)
+ bound = device_is_bound(&pdev->dev);
+
+ KUNIT_ASSERT_TRUE(test, bound);
+
+ pdata = dev_get_platdata(&pdev->dev);
+ KUNIT_ASSERT_TRUE(test, pdata->gpio_ok);
+}
+
+static struct kunit_case gpio_swnode_lookup_tests[] = {
+ KUNIT_CASE(gpio_swnode_lookup_by_primary),
+ KUNIT_CASE(gpio_swnode_lookup_by_secondary),
+ { }
+};
+
+static struct kunit_suite gpio_swnode_lookup_test_suite = {
+ .name = "gpio-swnode-lookup",
+ .test_cases = gpio_swnode_lookup_tests,
+};
+
+static BLOCKING_NOTIFIER_HEAD(gpio_unbind_notifier);
+
+struct gpio_unbind_consumer_drvdata {
+ struct device *dev;
+ struct gpio_desc *desc;
+ struct notifier_block nb;
+ int set_retval;
+};
+
+static int gpio_unbind_notify(struct notifier_block *nb, unsigned long action,
+ void *data)
+{
+ struct gpio_unbind_consumer_drvdata *drvdata =
+ container_of(nb, struct gpio_unbind_consumer_drvdata, nb);
+ struct device *dev = data;
+
+ if (dev != drvdata->dev)
+ return NOTIFY_DONE;
+
+ drvdata->set_retval = gpiod_set_value_cansleep(drvdata->desc, 0);
+
+ return NOTIFY_OK;
+}
+
+static void gpio_unbind_unregister_notifier(void *data)
+{
+ struct notifier_block *nb = data;
+
+ blocking_notifier_chain_unregister(&gpio_unbind_notifier, nb);
+}
+
+static int gpio_unbind_consumer_probe(struct platform_device *pdev)
+{
+ struct gpio_unbind_consumer_drvdata *data;
+ struct device *dev = &pdev->dev;
+ int ret;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->dev = dev;
+
+ data->desc = devm_gpiod_get(dev, "foo", GPIOD_OUT_HIGH);
+ if (IS_ERR(data->desc))
+ return PTR_ERR(data->desc);
+
+ data->nb.notifier_call = gpio_unbind_notify;
+ ret = blocking_notifier_chain_register(&gpio_unbind_notifier, &data->nb);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(dev, gpio_unbind_unregister_notifier, &data->nb);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, data);
+
+ return 0;
+}
+
+static struct platform_driver gpio_unbind_consumer_driver = {
+ .probe = gpio_unbind_consumer_probe,
+ .driver = {
+ .name = GPIO_UNBIND_TEST_CONSUMER,
+ },
+};
+
+static void gpio_unbind_with_consumers(struct kunit *test)
+{
+ struct gpio_unbind_consumer_drvdata *cons_data;
+ struct platform_device_info pdevinfo;
+ struct property_entry properties[2];
+ struct platform_device *prvd, *cons;
+ bool bound = false;
+ int ret;
+
+ ret = kunit_platform_driver_register(test, &gpio_test_provider_driver);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ ret = kunit_platform_driver_register(test, &gpio_unbind_consumer_driver);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ pdevinfo = (struct platform_device_info){
+ .name = GPIO_TEST_PROVIDER,
+ .id = PLATFORM_DEVID_NONE,
+ .swnode = &gpio_test_provider_swnode,
+ };
+
+ prvd = kunit_platform_device_register_full(test, &pdevinfo);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, prvd);
+
+ properties[0] = PROPERTY_ENTRY_GPIO("foo-gpios",
+ &gpio_test_provider_swnode,
+ 0, GPIO_ACTIVE_HIGH);
+ properties[1] = (struct property_entry){ };
+
+ pdevinfo = (struct platform_device_info){
+ .name = GPIO_UNBIND_TEST_CONSUMER,
+ .id = PLATFORM_DEVID_NONE,
+ .properties = properties,
+ };
+
+ cons = kunit_platform_device_register_full(test, &pdevinfo);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, cons);
+
+ wait_for_device_probe();
+ scoped_guard(device, &cons->dev)
+ bound = device_is_bound(&cons->dev);
+
+ KUNIT_ASSERT_TRUE(test, bound);
+
+ kunit_platform_device_unregister(test, prvd);
+
+ ret = blocking_notifier_call_chain(&gpio_unbind_notifier, 0, &cons->dev);
+ KUNIT_ASSERT_EQ(test, ret, NOTIFY_OK);
+
+ scoped_guard(device, &cons->dev) {
+ cons_data = platform_get_drvdata(cons);
+ ret = cons_data->set_retval;
+ }
+
+ KUNIT_ASSERT_EQ(test, ret, -ENODEV);
+}
+
+static struct kunit_case gpio_unbind_with_consumers_tests[] = {
+ KUNIT_CASE(gpio_unbind_with_consumers),
+ { }
+};
+
+static struct kunit_suite gpio_unbind_with_consumers_test_suite = {
+ .name = "gpio-unbind-with-consumers",
+ .test_cases = gpio_unbind_with_consumers_tests,
+};
+
+kunit_test_suites(
+ &gpio_swnode_lookup_test_suite,
+ &gpio_unbind_with_consumers_test_suite,
+);
+
+MODULE_DESCRIPTION("Test module for the GPIO subsystem");
+MODULE_AUTHOR("Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index 813dbcb91f6f..940b566946ce 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -241,6 +241,14 @@ static void of_gpio_try_fixup_polarity(const struct device_node *np,
*/
{ "ti,tsc2005", "reset-gpios", false },
#endif
+#if IS_ENABLED(CONFIG_SND_SOC_WSA881X)
+ /*
+ * WSA881 powerdown is always active low, but some device trees
+ * missed this when first contributed. It also has a very strange
+ * compatible.
+ */
+ { "sdw10217201000", "powerdown-gpios", false },
+#endif
};
unsigned int i;
diff --git a/drivers/gpio/gpiolib-swnode.c b/drivers/gpio/gpiolib-swnode.c
index 4374067f621e..8d9591aa9304 100644
--- a/drivers/gpio/gpiolib-swnode.c
+++ b/drivers/gpio/gpiolib-swnode.c
@@ -114,10 +114,6 @@ struct gpio_desc *swnode_find_gpio(struct fwnode_handle *fwnode,
if (IS_ERR(gdev))
return ERR_CAST(gdev);
- /*
- * FIXME: The GPIO device reference is put at return but the descriptor
- * is passed on. Find a proper solution.
- */
desc = gpio_device_get_desc(gdev, args.args[0]);
*flags = args.args[1]; /* We expect native GPIO flags */
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index c1f9c0d367d5..8a5ff78a1149 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -55,7 +55,7 @@
/* Device and char device-related information */
static DEFINE_IDA(gpio_ida);
-static dev_t gpio_devt;
+static dev_t gpio_devt __ro_after_init;
#define GPIO_DEV_MAX 256 /* 256 GPIO chip devices supported */
static int gpio_bus_match(struct device *dev, const struct device_driver *drv)
@@ -114,7 +114,7 @@ static int gpiochip_irqchip_init_hw(struct gpio_chip *gc);
static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gc);
static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gc);
-static bool gpiolib_initialized;
+static bool gpiolib_initialized __ro_after_init;
const char *gpiod_get_label(struct gpio_desc *desc)
{
@@ -143,13 +143,15 @@ static void desc_free_label(struct rcu_head *rh)
static int desc_set_label(struct gpio_desc *desc, const char *label)
{
struct gpio_desc_label *new = NULL, *old;
+ size_t len;
if (label) {
- new = kzalloc_flex(*new, str, strlen(label) + 1);
+ len = strlen(label);
+ new = kzalloc_flex(*new, str, len + 1);
if (!new)
return -ENOMEM;
- strcpy(new->str, label);
+ memcpy(new->str, label, len);
}
old = rcu_replace_pointer(desc->label, new, 1);
@@ -491,6 +493,28 @@ int gpiod_get_direction(struct gpio_desc *desc)
}
EXPORT_SYMBOL_GPL(gpiod_get_direction);
+/**
+ * gpiod_is_single_ended - check if the GPIO is configured as single-ended
+ * @desc: the GPIO descriptor to check
+ *
+ * Returns true if the GPIO is configured as either Open Drain or Open Source.
+ * In these modes, the direction of the line cannot always be reliably
+ * determined by reading hardware registers, as the "off" state (High-Z)
+ * is physically indistinguishable from an input state.
+ */
+bool gpiod_is_single_ended(struct gpio_desc *desc)
+{
+ if (!desc)
+ return false;
+
+ if (test_bit(GPIOD_FLAG_OPEN_DRAIN, &desc->flags) ||
+ test_bit(GPIOD_FLAG_OPEN_SOURCE, &desc->flags))
+ return true;
+
+ return false;
+}
+EXPORT_SYMBOL_GPL(gpiod_is_single_ended);
+
/*
* Add a new chip to the global chips list, keeping the list of chips sorted
* by range(means [base, base + ngpio - 1]) order.
@@ -3414,20 +3438,13 @@ static int gpio_chip_get_value(struct gpio_chip *gc, const struct gpio_desc *des
static int gpiod_get_raw_value_commit(const struct gpio_desc *desc)
{
- struct gpio_device *gdev;
- struct gpio_chip *gc;
int value;
- /* FIXME Unable to use gpio_chip_guard due to const desc. */
- gdev = desc->gdev;
-
- guard(srcu)(&gdev->srcu);
-
- gc = srcu_dereference(gdev->chip, &gdev->srcu);
- if (!gc)
+ CLASS(gpio_chip_guard, guard)(desc);
+ if (!guard.gc)
return -ENODEV;
- value = gpio_chip_get_value(gc, desc);
+ value = gpio_chip_get_value(guard.gc, desc);
value = value < 0 ? value : !!value;
trace_gpio_value(desc_to_gpio(desc), 1, value);
return value;
@@ -4134,8 +4151,6 @@ EXPORT_SYMBOL_GPL(gpiod_is_shared);
*/
int gpiod_to_irq(const struct gpio_desc *desc)
{
- struct gpio_device *gdev;
- struct gpio_chip *gc;
int offset;
int ret;
@@ -4143,16 +4158,13 @@ int gpiod_to_irq(const struct gpio_desc *desc)
if (ret <= 0)
return -EINVAL;
- gdev = desc->gdev;
- /* FIXME Cannot use gpio_chip_guard due to const desc. */
- guard(srcu)(&gdev->srcu);
- gc = srcu_dereference(gdev->chip, &gdev->srcu);
- if (!gc)
+ CLASS(gpio_chip_guard, guard)(desc);
+ if (!guard.gc)
return -ENODEV;
offset = gpiod_hwgpio(desc);
- if (gc->to_irq) {
- ret = gc->to_irq(gc, offset);
+ if (guard.gc->to_irq) {
+ ret = guard.gc->to_irq(guard.gc, offset);
if (ret)
return ret;
@@ -4160,7 +4172,7 @@ int gpiod_to_irq(const struct gpio_desc *desc)
return -ENXIO;
}
#ifdef CONFIG_GPIOLIB_IRQCHIP
- if (gc->irq.chip) {
+ if (guard.gc->irq.chip) {
/*
* Avoid race condition with other code, which tries to lookup
* an IRQ before the irqchip has been properly registered,
@@ -5348,7 +5360,7 @@ EXPORT_SYMBOL_GPL(gpiod_put_array);
* gpio_device of the GPIO chip with the firmware node and then simply
* bind it to this stub driver.
*/
-static struct device_driver gpio_stub_drv = {
+static struct device_driver gpio_stub_drv __ro_after_init = {
.name = "gpio_stub_drv",
.bus = &gpio_bus_type,
};
@@ -5506,8 +5518,8 @@ static int gpiolib_seq_show(struct seq_file *s, void *v)
if (gc->label)
seq_printf(s, ", %s", gc->label);
if (gc->can_sleep)
- seq_printf(s, ", can sleep");
- seq_printf(s, ":\n");
+ seq_puts(s, ", can sleep");
+ seq_puts(s, ":\n");
if (gc->dbg_show)
gc->dbg_show(s, gc);
diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
index dc4cb61a9318..650a702741df 100644
--- a/drivers/gpio/gpiolib.h
+++ b/drivers/gpio/gpiolib.h
@@ -244,7 +244,7 @@ DEFINE_CLASS(gpio_chip_guard,
_guard;
}),
- struct gpio_desc *desc)
+ const struct gpio_desc *desc)
int gpiod_request(struct gpio_desc *desc, const char *label);
int gpiod_request_commit(struct gpio_desc *desc, const char *label);
diff --git a/drivers/mfd/timberdale.c b/drivers/mfd/timberdale.c
index a4d9c070d481..e75e1d6851ab 100644
--- a/drivers/mfd/timberdale.c
+++ b/drivers/mfd/timberdale.c
@@ -15,8 +15,6 @@
#include <linux/property.h>
#include <linux/slab.h>
-#include <linux/timb_gpio.h>
-
#include <linux/i2c.h>
#include <linux/platform_data/i2c-ocores.h>
#include <linux/platform_data/i2c-xiic.h>
@@ -37,6 +35,10 @@
#define DRIVER_NAME "timberdale"
+#define GPIO_NR_PINS 16
+#define GPIO_BASE 0
+#define IRQ_BASE 200
+
struct timberdale_device {
resource_size_t ctl_mapbase;
unsigned char __iomem *ctl_membase;
@@ -174,11 +176,16 @@ static const struct resource timberdale_eth_resources[] = {
},
};
-static struct timbgpio_platform_data
- timberdale_gpio_platform_data = {
- .gpio_base = 0,
- .nr_pins = GPIO_NR_PINS,
- .irq_base = 200,
+static const struct property_entry timberdale_gpio_properties[] = {
+ PROPERTY_ENTRY_U32("ngpios", GPIO_NR_PINS),
+ PROPERTY_ENTRY_U32("gpio-base", GPIO_BASE),
+ PROPERTY_ENTRY_U32("irq-base", IRQ_BASE),
+ { }
+};
+
+static const struct software_node timberdale_gpio_swnode = {
+ .name = "timb-gpio",
+ .properties = timberdale_gpio_properties,
};
static const struct resource timberdale_gpio_resources[] = {
@@ -390,8 +397,7 @@ static const struct mfd_cell timberdale_cells_bar0_cfg0[] = {
.name = "timb-gpio",
.num_resources = ARRAY_SIZE(timberdale_gpio_resources),
.resources = timberdale_gpio_resources,
- .platform_data = &timberdale_gpio_platform_data,
- .pdata_size = sizeof(timberdale_gpio_platform_data),
+ .swnode = &timberdale_gpio_swnode,
},
{
.name = "timb-video",
@@ -452,8 +458,7 @@ static const struct mfd_cell timberdale_cells_bar0_cfg1[] = {
.name = "timb-gpio",
.num_resources = ARRAY_SIZE(timberdale_gpio_resources),
.resources = timberdale_gpio_resources,
- .platform_data = &timberdale_gpio_platform_data,
- .pdata_size = sizeof(timberdale_gpio_platform_data),
+ .swnode = &timberdale_gpio_swnode,
},
{
.name = "timb-mlogicore",
@@ -514,8 +519,7 @@ static const struct mfd_cell timberdale_cells_bar0_cfg2[] = {
.name = "timb-gpio",
.num_resources = ARRAY_SIZE(timberdale_gpio_resources),
.resources = timberdale_gpio_resources,
- .platform_data = &timberdale_gpio_platform_data,
- .pdata_size = sizeof(timberdale_gpio_platform_data),
+ .swnode = &timberdale_gpio_swnode,
},
{
.name = "timb-video",
@@ -564,8 +568,7 @@ static const struct mfd_cell timberdale_cells_bar0_cfg3[] = {
.name = "timb-gpio",
.num_resources = ARRAY_SIZE(timberdale_gpio_resources),
.resources = timberdale_gpio_resources,
- .platform_data = &timberdale_gpio_platform_data,
- .pdata_size = sizeof(timberdale_gpio_platform_data),
+ .swnode = &timberdale_gpio_swnode,
},
{
.name = "timb-video",
diff --git a/drivers/mfd/timberdale.h b/drivers/mfd/timberdale.h
index b01d2388e1af..db7b434f766d 100644
--- a/drivers/mfd/timberdale.h
+++ b/drivers/mfd/timberdale.h
@@ -113,7 +113,6 @@
#define GPIO_PIN_ASCB 8
#define GPIO_PIN_INIC_RST 14
#define GPIO_PIN_BT_RST 15
-#define GPIO_NR_PINS 16
/* DMA Channels */
#define DMA_UART_RX 0
diff --git a/drivers/staging/media/max96712/Kconfig b/drivers/staging/media/max96712/Kconfig
index 117fadf81bd0..93a2d583e90d 100644
--- a/drivers/staging/media/max96712/Kconfig
+++ b/drivers/staging/media/max96712/Kconfig
@@ -2,7 +2,6 @@
config VIDEO_MAX96712
tristate "Maxim MAX96712 Quad GMSL2 Deserializer support"
depends on I2C
- depends on OF_GPIO
depends on VIDEO_DEV
select V4L2_FWNODE
select VIDEO_V4L2_SUBDEV_API
diff --git a/include/dt-bindings/gpio/meson-axg-gpio.h b/include/dt-bindings/gpio/meson-axg-gpio.h
index 25bb1fffa97a..a0d42bcd9bd3 100644
--- a/include/dt-bindings/gpio/meson-axg-gpio.h
+++ b/include/dt-bindings/gpio/meson-axg-gpio.h
@@ -23,7 +23,7 @@
#define GPIOAO_11 11
#define GPIOAO_12 12
#define GPIOAO_13 13
-#define GPIO_TEST_N 14
+#define GPIO_TEST_N 14
/* Second GPIO chip */
#define GPIOZ_0 0
@@ -52,7 +52,7 @@
#define BOOT_12 23
#define BOOT_13 24
#define BOOT_14 25
-#define GPIOA_0 26
+#define GPIOA_0 26
#define GPIOA_1 27
#define GPIOA_2 28
#define GPIOA_3 29
diff --git a/include/dt-bindings/gpio/nvidia,tegra238-gpio.h b/include/dt-bindings/gpio/nvidia,tegra238-gpio.h
new file mode 100644
index 000000000000..8a616a1df54c
--- /dev/null
+++ b/include/dt-bindings/gpio/nvidia,tegra238-gpio.h
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
+/* Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. */
+
+/*
+ * This header provides constants for binding nvidia,tegra238-gpio*.
+ *
+ * The first cell in Tegra's GPIO specifier is the GPIO ID. The macros below
+ * provide names for this.
+ *
+ * The second cell contains standard flag values specified in gpio.h.
+ */
+
+#ifndef _DT_BINDINGS_GPIO_TEGRA238_GPIO_H
+#define _DT_BINDINGS_GPIO_TEGRA238_GPIO_H
+
+#include <dt-bindings/gpio/gpio.h>
+
+/* GPIOs implemented by main GPIO controller */
+#define TEGRA238_MAIN_GPIO_PORT_A 0
+#define TEGRA238_MAIN_GPIO_PORT_B 1
+#define TEGRA238_MAIN_GPIO_PORT_C 2
+#define TEGRA238_MAIN_GPIO_PORT_D 3
+#define TEGRA238_MAIN_GPIO_PORT_E 4
+#define TEGRA238_MAIN_GPIO_PORT_F 5
+#define TEGRA238_MAIN_GPIO_PORT_G 6
+#define TEGRA238_MAIN_GPIO_PORT_H 7
+#define TEGRA238_MAIN_GPIO_PORT_J 8
+#define TEGRA238_MAIN_GPIO_PORT_K 9
+#define TEGRA238_MAIN_GPIO_PORT_L 10
+#define TEGRA238_MAIN_GPIO_PORT_M 11
+#define TEGRA238_MAIN_GPIO_PORT_N 12
+#define TEGRA238_MAIN_GPIO_PORT_P 13
+#define TEGRA238_MAIN_GPIO_PORT_Q 14
+#define TEGRA238_MAIN_GPIO_PORT_R 15
+#define TEGRA238_MAIN_GPIO_PORT_S 16
+#define TEGRA238_MAIN_GPIO_PORT_T 17
+#define TEGRA238_MAIN_GPIO_PORT_U 18
+#define TEGRA238_MAIN_GPIO_PORT_V 19
+#define TEGRA238_MAIN_GPIO_PORT_W 20
+#define TEGRA238_MAIN_GPIO_PORT_X 21
+
+#define TEGRA238_MAIN_GPIO(port, offset) \
+ ((TEGRA238_MAIN_GPIO_PORT_##port * 8) + (offset))
+
+/* GPIOs implemented by AON GPIO controller */
+#define TEGRA238_AON_GPIO_PORT_AA 0
+#define TEGRA238_AON_GPIO_PORT_BB 1
+#define TEGRA238_AON_GPIO_PORT_CC 2
+#define TEGRA238_AON_GPIO_PORT_DD 3
+#define TEGRA238_AON_GPIO_PORT_EE 4
+#define TEGRA238_AON_GPIO_PORT_FF 5
+#define TEGRA238_AON_GPIO_PORT_GG 6
+#define TEGRA238_AON_GPIO_PORT_HH 7
+
+#define TEGRA238_AON_GPIO(port, offset) \
+ ((TEGRA238_AON_GPIO_PORT_##port * 8) + (offset))
+
+#endif
diff --git a/include/kunit/platform_device.h b/include/kunit/platform_device.h
index f8236a8536f7..eee565d5d1d3 100644
--- a/include/kunit/platform_device.h
+++ b/include/kunit/platform_device.h
@@ -6,10 +6,16 @@ struct completion;
struct kunit;
struct platform_device;
struct platform_driver;
+struct platform_device_info;
struct platform_device *
kunit_platform_device_alloc(struct kunit *test, const char *name, int id);
int kunit_platform_device_add(struct kunit *test, struct platform_device *pdev);
+struct platform_device *
+kunit_platform_device_register_full(struct kunit *test,
+ const struct platform_device_info *pdevinfo);
+void kunit_platform_device_unregister(struct kunit *test,
+ struct platform_device *pdev);
int kunit_platform_device_prepare_wait_for_probe(struct kunit *test,
struct platform_device *pdev,
diff --git a/include/linux/gpio.h b/include/linux/gpio.h
index 8f85ddb26429..b0d4942a65de 100644
--- a/include/linux/gpio.h
+++ b/include/linux/gpio.h
@@ -2,13 +2,11 @@
/*
* NOTE: This header *must not* be included.
*
- * 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>
+ * If you're using the legacy interfaces, include <linux/gpio/legacy.h>
*/
+
#ifndef __LINUX_GPIO_H
#define __LINUX_GPIO_H
@@ -18,159 +16,7 @@
#endif
#ifdef CONFIG_GPIOLIB_LEGACY
-
-struct device;
-
-/* make these flag values available regardless of GPIO kconfig options */
-#define GPIOF_IN ((1 << 0))
-#define GPIOF_OUT_INIT_LOW ((0 << 0) | (0 << 1))
-#define GPIOF_OUT_INIT_HIGH ((0 << 0) | (1 << 1))
-
-#ifdef CONFIG_GPIOLIB
-/*
- * "valid" GPIO numbers are nonnegative and may be passed to
- * setup routines like gpio_request(). Only some valid numbers
- * can successfully be requested and used.
- *
- * Invalid GPIO numbers are useful for indicating no-such-GPIO in
- * platform data and other tables.
- */
-static inline bool gpio_is_valid(int number)
-{
- /* only non-negative numbers are valid */
- return number >= 0;
-}
-
-/*
- * Platforms may implement their GPIO interface with library code,
- * at a small performance cost for non-inlined operations and some
- * extra memory (for code and for per-GPIO table entries).
- */
-
-/* Always use the library code for GPIO management calls,
- * or when sleeping may be involved.
- */
-int gpio_request(unsigned gpio, const char *label);
-void gpio_free(unsigned gpio);
-
-static inline int gpio_direction_input(unsigned gpio)
-{
- return gpiod_direction_input(gpio_to_desc(gpio));
-}
-static inline int gpio_direction_output(unsigned gpio, int value)
-{
- return gpiod_direction_output_raw(gpio_to_desc(gpio), value);
-}
-
-static inline int gpio_get_value_cansleep(unsigned gpio)
-{
- return gpiod_get_raw_value_cansleep(gpio_to_desc(gpio));
-}
-static inline void gpio_set_value_cansleep(unsigned gpio, int value)
-{
- gpiod_set_raw_value_cansleep(gpio_to_desc(gpio), value);
-}
-
-static inline int gpio_get_value(unsigned gpio)
-{
- return gpiod_get_raw_value(gpio_to_desc(gpio));
-}
-static inline void gpio_set_value(unsigned gpio, int value)
-{
- gpiod_set_raw_value(gpio_to_desc(gpio), value);
-}
-
-static inline int gpio_to_irq(unsigned gpio)
-{
- return gpiod_to_irq(gpio_to_desc(gpio));
-}
-
-int gpio_request_one(unsigned gpio, unsigned long flags, const char *label);
-
-int devm_gpio_request_one(struct device *dev, unsigned gpio,
- unsigned long flags, const char *label);
-
-#else /* ! CONFIG_GPIOLIB */
-
-#include <linux/kernel.h>
-
-#include <asm/bug.h>
-#include <asm/errno.h>
-
-static inline bool gpio_is_valid(int number)
-{
- return false;
-}
-
-static inline int gpio_request(unsigned gpio, const char *label)
-{
- return -ENOSYS;
-}
-
-static inline int gpio_request_one(unsigned gpio,
- unsigned long flags, const char *label)
-{
- return -ENOSYS;
-}
-
-static inline void gpio_free(unsigned gpio)
-{
- might_sleep();
-
- /* GPIO can never have been requested */
- WARN_ON(1);
-}
-
-static inline int gpio_direction_input(unsigned gpio)
-{
- return -ENOSYS;
-}
-
-static inline int gpio_direction_output(unsigned gpio, int value)
-{
- return -ENOSYS;
-}
-
-static inline int gpio_get_value(unsigned gpio)
-{
- /* GPIO can never have been requested or set as {in,out}put */
- WARN_ON(1);
- return 0;
-}
-
-static inline void gpio_set_value(unsigned gpio, int value)
-{
- /* GPIO can never have been requested or set as output */
- WARN_ON(1);
-}
-
-static inline int gpio_get_value_cansleep(unsigned gpio)
-{
- /* GPIO can never have been requested or set as {in,out}put */
- WARN_ON(1);
- return 0;
-}
-
-static inline void gpio_set_value_cansleep(unsigned gpio, int value)
-{
- /* GPIO can never have been requested or set as output */
- WARN_ON(1);
-}
-
-static inline int gpio_to_irq(unsigned gpio)
-{
- /* GPIO can never have been requested or set as input */
- WARN_ON(1);
- return -EINVAL;
-}
-
-static inline int devm_gpio_request_one(struct device *dev, unsigned gpio,
- unsigned long flags, const char *label)
-{
- WARN_ON(1);
- return -EINVAL;
-}
-
-#endif /* ! CONFIG_GPIOLIB */
+#include <linux/gpio/legacy.h>
#endif /* CONFIG_GPIOLIB_LEGACY */
+
#endif /* __LINUX_GPIO_H */
diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h
index 3efb5cb1e1d1..fceeefd5f893 100644
--- a/include/linux/gpio/consumer.h
+++ b/include/linux/gpio/consumer.h
@@ -111,6 +111,7 @@ void devm_gpiod_unhinge(struct device *dev, struct gpio_desc *desc);
void devm_gpiod_put_array(struct device *dev, struct gpio_descs *descs);
int gpiod_get_direction(struct gpio_desc *desc);
+bool gpiod_is_single_ended(struct gpio_desc *desc);
int gpiod_direction_input(struct gpio_desc *desc);
int gpiod_direction_output(struct gpio_desc *desc, int value);
int gpiod_direction_output_raw(struct gpio_desc *desc, int value);
@@ -337,6 +338,10 @@ static inline int gpiod_get_direction(const struct gpio_desc *desc)
WARN_ON(desc);
return -ENOSYS;
}
+static inline bool gpiod_is_single_ended(struct gpio_desc *desc)
+{
+ return false;
+}
static inline int gpiod_direction_input(struct gpio_desc *desc)
{
/* GPIO can never have been requested */
@@ -599,6 +604,15 @@ static inline int gpiod_disable_hw_timestamp_ns(struct gpio_desc *desc,
#endif /* CONFIG_GPIOLIB && CONFIG_HTE */
static inline
+struct gpio_desc *fwnode_gpiod_get(struct fwnode_handle *fwnode,
+ const char *con_id,
+ enum gpiod_flags flags,
+ const char *label)
+{
+ return fwnode_gpiod_get_index(fwnode, con_id, 0, flags, label);
+}
+
+static inline
struct gpio_desc *devm_fwnode_gpiod_get(struct device *dev,
struct fwnode_handle *fwnode,
const char *con_id,
diff --git a/include/linux/gpio/gpio-nomadik.h b/include/linux/gpio/gpio-nomadik.h
index 8061b9826361..44c47645649c 100644
--- a/include/linux/gpio/gpio-nomadik.h
+++ b/include/linux/gpio/gpio-nomadik.h
@@ -32,9 +32,6 @@ struct fwnode_handle;
#define NMK_GPIO_RWIMSC 0x50
#define NMK_GPIO_FWIMSC 0x54
#define NMK_GPIO_WKS 0x58
-/* These appear in DB8540 and later ASICs */
-#define NMK_GPIO_EDGELEVEL 0x5C
-#define NMK_GPIO_LEVEL 0x60
/* Pull up/down values */
enum nmk_gpio_pull {
@@ -236,19 +233,6 @@ nmk_pinctrl_db8500_init(const struct nmk_pinctrl_soc_data **soc)
#endif
-#ifdef CONFIG_PINCTRL_DB8540
-
-void nmk_pinctrl_db8540_init(const struct nmk_pinctrl_soc_data **soc);
-
-#else
-
-static inline void
-nmk_pinctrl_db8540_init(const struct nmk_pinctrl_soc_data **soc)
-{
-}
-
-#endif
-
struct platform_device;
#ifdef CONFIG_DEBUG_FS
diff --git a/include/linux/gpio/legacy.h b/include/linux/gpio/legacy.h
new file mode 100644
index 000000000000..557ef635935e
--- /dev/null
+++ b/include/linux/gpio/legacy.h
@@ -0,0 +1,173 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * This is the LEGACY GPIO include file, used only for legacy APIs.
+ *
+ * No new code should use this, but instead use the linux/gpio/consumer.h
+ * interfaces directly.
+ */
+
+#ifndef __LINUX_GPIO_LEGACY_H
+#define __LINUX_GPIO_LEGACY_H
+
+#include <linux/types.h>
+
+#ifdef CONFIG_GPIOLIB_LEGACY
+
+struct device;
+
+/* make these flag values available regardless of GPIO kconfig options */
+#define GPIOF_IN ((1 << 0))
+#define GPIOF_OUT_INIT_LOW ((0 << 0) | (0 << 1))
+#define GPIOF_OUT_INIT_HIGH ((0 << 0) | (1 << 1))
+
+#ifdef CONFIG_GPIOLIB
+
+#include <linux/gpio/consumer.h>
+
+/*
+ * "valid" GPIO numbers are nonnegative and may be passed to
+ * setup routines like gpio_request(). Only some valid numbers
+ * can successfully be requested and used.
+ *
+ * Invalid GPIO numbers are useful for indicating no-such-GPIO in
+ * platform data and other tables.
+ */
+static inline bool gpio_is_valid(int number)
+{
+ /* only non-negative numbers are valid */
+ return number >= 0;
+}
+
+/*
+ * Platforms may implement their GPIO interface with library code,
+ * at a small performance cost for non-inlined operations and some
+ * extra memory (for code and for per-GPIO table entries).
+ */
+
+/* Always use the library code for GPIO management calls,
+ * or when sleeping may be involved.
+ */
+int gpio_request(unsigned gpio, const char *label);
+void gpio_free(unsigned gpio);
+
+static inline int gpio_direction_input(unsigned gpio)
+{
+ return gpiod_direction_input(gpio_to_desc(gpio));
+}
+static inline int gpio_direction_output(unsigned gpio, int value)
+{
+ return gpiod_direction_output_raw(gpio_to_desc(gpio), value);
+}
+
+static inline int gpio_get_value_cansleep(unsigned gpio)
+{
+ return gpiod_get_raw_value_cansleep(gpio_to_desc(gpio));
+}
+static inline void gpio_set_value_cansleep(unsigned gpio, int value)
+{
+ gpiod_set_raw_value_cansleep(gpio_to_desc(gpio), value);
+}
+
+static inline int gpio_get_value(unsigned gpio)
+{
+ return gpiod_get_raw_value(gpio_to_desc(gpio));
+}
+static inline void gpio_set_value(unsigned gpio, int value)
+{
+ gpiod_set_raw_value(gpio_to_desc(gpio), value);
+}
+
+static inline int gpio_to_irq(unsigned gpio)
+{
+ return gpiod_to_irq(gpio_to_desc(gpio));
+}
+
+int gpio_request_one(unsigned gpio, unsigned long flags, const char *label);
+
+int devm_gpio_request_one(struct device *dev, unsigned gpio,
+ unsigned long flags, const char *label);
+
+#else /* ! CONFIG_GPIOLIB */
+
+#include <linux/kernel.h>
+
+#include <asm/bug.h>
+#include <asm/errno.h>
+
+static inline bool gpio_is_valid(int number)
+{
+ return false;
+}
+
+static inline int gpio_request(unsigned gpio, const char *label)
+{
+ return -ENOSYS;
+}
+
+static inline int gpio_request_one(unsigned gpio,
+ unsigned long flags, const char *label)
+{
+ return -ENOSYS;
+}
+
+static inline void gpio_free(unsigned gpio)
+{
+ might_sleep();
+
+ /* GPIO can never have been requested */
+ WARN_ON(1);
+}
+
+static inline int gpio_direction_input(unsigned gpio)
+{
+ return -ENOSYS;
+}
+
+static inline int gpio_direction_output(unsigned gpio, int value)
+{
+ return -ENOSYS;
+}
+
+static inline int gpio_get_value(unsigned gpio)
+{
+ /* GPIO can never have been requested or set as {in,out}put */
+ WARN_ON(1);
+ return 0;
+}
+
+static inline void gpio_set_value(unsigned gpio, int value)
+{
+ /* GPIO can never have been requested or set as output */
+ WARN_ON(1);
+}
+
+static inline int gpio_get_value_cansleep(unsigned gpio)
+{
+ /* GPIO can never have been requested or set as {in,out}put */
+ WARN_ON(1);
+ return 0;
+}
+
+static inline void gpio_set_value_cansleep(unsigned gpio, int value)
+{
+ /* GPIO can never have been requested or set as output */
+ WARN_ON(1);
+}
+
+static inline int gpio_to_irq(unsigned gpio)
+{
+ /* GPIO can never have been requested or set as input */
+ WARN_ON(1);
+ return -EINVAL;
+}
+
+static inline int devm_gpio_request_one(struct device *dev, unsigned gpio,
+ unsigned long flags, const char *label)
+{
+ WARN_ON(1);
+ return -EINVAL;
+}
+
+#endif /* ! CONFIG_GPIOLIB */
+#endif /* CONFIG_GPIOLIB_LEGACY */
+#endif /* __LINUX_GPIO_LEGAGY_H */
diff --git a/include/linux/gpio/regmap.h b/include/linux/gpio/regmap.h
index 12d154732ca9..06255756710d 100644
--- a/include/linux/gpio/regmap.h
+++ b/include/linux/gpio/regmap.h
@@ -38,6 +38,12 @@ struct regmap;
* offset to a register/bitmask pair. If not
* given the default gpio_regmap_simple_xlate()
* is used.
+ * @fixed_direction_mask:
+ * (Optional) Bitmap representing the GPIO lines that
+ * make use of the @fixed_direction_output list to
+ * enforce direction of the GPIO. If this is NULL
+ * and @fixed_direction_output is defined, ALL GPIOs
+ * are assumed to be fixed direction (out or in).
* @fixed_direction_output:
* (Optional) Bitmap representing the fixed direction of
* the GPIO lines. Useful when there are GPIO lines with a
@@ -89,6 +95,7 @@ struct gpio_regmap_config {
int reg_stride;
int ngpio_per_reg;
struct irq_domain *irq_domain;
+ unsigned long *fixed_direction_mask;
unsigned long *fixed_direction_output;
#ifdef CONFIG_REGMAP_IRQ
diff --git a/include/linux/timb_gpio.h b/include/linux/timb_gpio.h
deleted file mode 100644
index 74f5e73bf6db..000000000000
--- a/include/linux/timb_gpio.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * timb_gpio.h timberdale FPGA GPIO driver, platform data definition
- * Copyright (c) 2009 Intel Corporation
- */
-
-#ifndef _LINUX_TIMB_GPIO_H
-#define _LINUX_TIMB_GPIO_H
-
-/**
- * struct timbgpio_platform_data - Platform data of the Timberdale GPIO driver
- * @gpio_base: The number of the first GPIO pin, set to -1 for
- * dynamic number allocation.
- * @nr_pins: Number of pins that is supported by the hardware (1-32)
- * @irq_base: If IRQ is supported by the hardware, this is the base
- * number of IRQ:s. One IRQ per pin will be used. Set to
- * -1 if IRQ:s is not supported.
- */
-struct timbgpio_platform_data {
- int gpio_base;
- int nr_pins;
- int irq_base;
-};
-
-#endif
diff --git a/lib/kunit/platform.c b/lib/kunit/platform.c
index 0b518de26065..737758d710b2 100644
--- a/lib/kunit/platform.c
+++ b/lib/kunit/platform.c
@@ -6,6 +6,7 @@
#include <linux/completion.h>
#include <linux/device/bus.h>
#include <linux/device/driver.h>
+#include <linux/err.h>
#include <linux/platform_device.h>
#include <kunit/platform_device.h>
@@ -130,6 +131,69 @@ int kunit_platform_device_add(struct kunit *test, struct platform_device *pdev)
}
EXPORT_SYMBOL_GPL(kunit_platform_device_add);
+/**
+ * kunit_platform_device_register_full() - Register a KUnit test-managed platform
+ * device described by platform device info
+ * @test: test context
+ * @pdevinfo: platform device information describing the new device
+ *
+ * Register a test-managed platform device. The device is unregistered when the
+ * test completes.
+ *
+ * Return: New platform device on success, IS_ERR() on error.
+ */
+struct platform_device *
+kunit_platform_device_register_full(struct kunit *test,
+ const struct platform_device_info *pdevinfo)
+{
+ struct platform_device *pdev;
+ int ret;
+
+ pdev = platform_device_register_full(pdevinfo);
+ if (IS_ERR(pdev))
+ return pdev;
+
+ ret = kunit_add_action_or_reset(test, platform_device_unregister_wrapper, pdev);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return pdev;
+}
+EXPORT_SYMBOL_GPL(kunit_platform_device_register_full);
+
+static bool
+kunit_platform_device_add_match(struct kunit *test, struct kunit_resource *res,
+ void *match_data)
+{
+ struct platform_device *pdev = match_data;
+
+ return res->data == pdev && res->free == kunit_platform_device_add_exit;
+}
+
+/**
+ * kunit_platform_device_unregister() - Unregister a KUnit-managed platform device
+ * @test: test context
+ * @pdev: platform device to unregister
+ *
+ * Unregister a test-managed platform device and cancel its release action.
+ */
+void kunit_platform_device_unregister(struct kunit *test,
+ struct platform_device *pdev)
+{
+ struct kunit_resource *res;
+
+ res = kunit_find_resource(test, kunit_platform_device_add_match, pdev);
+ if (res) {
+ res->free = NULL;
+ kunit_put_resource(res);
+ } else {
+ kunit_remove_action(test, platform_device_unregister_wrapper, pdev);
+ }
+
+ platform_device_unregister(pdev);
+}
+EXPORT_SYMBOL_GPL(kunit_platform_device_unregister);
+
struct kunit_platform_device_probe_nb {
struct completion *x;
struct device *dev;
diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c
index 2fc234adca5f..d15fda648dad 100644
--- a/sound/soc/codecs/wsa881x.c
+++ b/sound/soc/codecs/wsa881x.c
@@ -3,7 +3,6 @@
// Copyright (c) 2019, Linaro Limited
#include <linux/bitops.h>
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/regmap.h>
@@ -672,11 +671,6 @@ struct wsa881x_priv {
struct sdw_stream_runtime *sruntime;
struct sdw_port_config port_config[WSA881X_MAX_SWR_PORTS];
struct gpio_desc *sd_n;
- /*
- * Logical state for SD_N GPIO: high for shutdown, low for enable.
- * For backwards compatibility.
- */
- unsigned int sd_n_val;
int active_ports;
bool hw_init;
bool port_prepared[WSA881X_MAX_SWR_PORTS];
@@ -1121,31 +1115,11 @@ static int wsa881x_probe(struct sdw_slave *pdev,
if (!wsa881x)
return -ENOMEM;
- wsa881x->sd_n = devm_gpiod_get_optional(dev, "powerdown", 0);
+ wsa881x->sd_n = devm_gpiod_get_optional(dev, "powerdown", GPIOD_OUT_LOW);
if (IS_ERR(wsa881x->sd_n))
return dev_err_probe(dev, PTR_ERR(wsa881x->sd_n),
"Shutdown Control GPIO not found\n");
- /*
- * Backwards compatibility work-around.
- *
- * The SD_N GPIO is active low, however upstream DTS used always active
- * high. Changing the flag in driver and DTS will break backwards
- * compatibility, so add a simple value inversion to work with both old
- * and new DTS.
- *
- * This won't work properly with DTS using the flags properly in cases:
- * 1. Old DTS with proper ACTIVE_LOW, however such case was broken
- * before as the driver required the active high.
- * 2. New DTS with proper ACTIVE_HIGH (intended), which is rare case
- * (not existing upstream) but possible. This is the price of
- * backwards compatibility, therefore this hack should be removed at
- * some point.
- */
- wsa881x->sd_n_val = gpiod_is_active_low(wsa881x->sd_n);
- if (!wsa881x->sd_n_val)
- dev_warn(dev, "Using ACTIVE_HIGH for shutdown GPIO. Your DTB might be outdated or you use unsupported configuration for the GPIO.");
-
dev_set_drvdata(dev, wsa881x);
wsa881x->slave = pdev;
wsa881x->dev = dev;
@@ -1158,7 +1132,6 @@ static int wsa881x_probe(struct sdw_slave *pdev,
pdev->prop.sink_dpn_prop = wsa_sink_dpn_prop;
pdev->prop.scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
pdev->prop.clk_stop_mode1 = true;
- gpiod_direction_output(wsa881x->sd_n, !wsa881x->sd_n_val);
wsa881x->regmap = devm_regmap_init_sdw(pdev, &wsa881x_regmap_config);
if (IS_ERR(wsa881x->regmap))
@@ -1181,7 +1154,7 @@ static int wsa881x_runtime_suspend(struct device *dev)
struct regmap *regmap = dev_get_regmap(dev, NULL);
struct wsa881x_priv *wsa881x = dev_get_drvdata(dev);
- gpiod_direction_output(wsa881x->sd_n, wsa881x->sd_n_val);
+ gpiod_direction_output(wsa881x->sd_n, 1);
regcache_cache_only(regmap, true);
regcache_mark_dirty(regmap);
@@ -1196,13 +1169,13 @@ static int wsa881x_runtime_resume(struct device *dev)
struct wsa881x_priv *wsa881x = dev_get_drvdata(dev);
unsigned long time;
- gpiod_direction_output(wsa881x->sd_n, !wsa881x->sd_n_val);
+ gpiod_direction_output(wsa881x->sd_n, 0);
time = wait_for_completion_timeout(&slave->initialization_complete,
msecs_to_jiffies(WSA881X_PROBE_TIMEOUT));
if (!time) {
dev_err(dev, "Initialization not complete, timed out\n");
- gpiod_direction_output(wsa881x->sd_n, wsa881x->sd_n_val);
+ gpiod_direction_output(wsa881x->sd_n, 1);
return -ETIMEDOUT;
}