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 + +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 + + 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 +#include #include #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 #include +#include #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", ®)) /* 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(rg, GPIO_REG_STAT); + pending = mtk_gpio_r32(bank, GPIO_REG_STAT); + if (!pending) + return; - 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; + 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; + + chained_irq_enter(chip, desc); + for (i = 0; i < MTK_BANK_CNT; i++) { + struct mtk_gc *bank = &priv->gc_map[i]; + + 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 | @@ -190,6 +222,26 @@ mediatek_gpio_irq_type(struct irq_data *d, unsigned int type) return 0; } +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,14 +260,123 @@ 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) { @@ -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 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 #include #include +#include #include #include #include @@ -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, }; @@ -1447,6 +1510,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 #include #include -#include #include #include @@ -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 - * - * 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 -#include -#include -#include -#include -#include - -/* 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. "); -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 +#include +#include +#include +#include +#include +#include + +/* 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 "); +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 @@ -240,6 +240,14 @@ static void of_gpio_try_fixup_polarity(const struct device_node *np, * treats it as "active low". */ { "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 #include -#include - #include #include #include @@ -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 + +/* 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 * If you're implementing a GPIO consumer, only include + * If you're using the legacy interfaces, include */ + #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 - -#include -#include - -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 #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 */ @@ -598,6 +603,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, 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 + +#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 + +/* + * "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 + +#include +#include + +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 #include #include +#include #include #include @@ -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 -#include #include #include #include @@ -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; }