diff options
author | Stephen Rothwell <sfr@canb.auug.org.au> | 2017-05-30 13:47:49 +1000 |
---|---|---|
committer | Stephen Rothwell <sfr@canb.auug.org.au> | 2017-05-30 13:47:49 +1000 |
commit | 59b3981f6295890195428e0b037249fb5f025aea (patch) | |
tree | 0c2d60ec951e66ef80aa47bff8a5dd011d88a563 | |
parent | 3680163378349a1d7b9f2f5d8f8c056134fc6979 (diff) | |
parent | d46c4e22d34befdbe59d0436fdfdd9dd5633026a (diff) |
Merge remote-tracking branch 'gpio/for-next'
49 files changed, 1355 insertions, 666 deletions
diff --git a/Documentation/acpi/gpio-properties.txt b/Documentation/acpi/gpio-properties.txt index 2aff0349facd..88c65cb5bf0a 100644 --- a/Documentation/acpi/gpio-properties.txt +++ b/Documentation/acpi/gpio-properties.txt @@ -156,3 +156,68 @@ pointed to by its first argument. That should be done in the driver's .probe() routine. On removal, the driver should unregister its GPIO mapping table by calling acpi_dev_remove_driver_gpios() on the ACPI device object where that table was previously registered. + +Using the _CRS fallback +----------------------- + +If a device does not have _DSD or the driver does not create ACPI GPIO +mapping, the Linux GPIO framework refuses to return any GPIOs. This is +because the driver does not know what it actually gets. For example if we +have a device like below: + + Device (BTH) + { + Name (_HID, ...) + + Name (_CRS, ResourceTemplate () { + GpioIo (Exclusive, PullNone, 0, 0, IoRestrictionNone, + "\\_SB.GPO0", 0, ResourceConsumer) {15} + GpioIo (Exclusive, PullNone, 0, 0, IoRestrictionNone, + "\\_SB.GPO0", 0, ResourceConsumer) {27} + }) + } + +The driver might expect to get the right GPIO when it does: + + desc = gpiod_get(dev, "reset", GPIOD_OUT_LOW); + +but since there is no way to know the mapping between "reset" and +the GpioIo() in _CRS desc will hold ERR_PTR(-ENOENT). + +The driver author can solve this by passing the mapping explictly +(the recommended way and documented in the above chapter). + +The ACPI GPIO mapping tables should not contaminate drivers that are not +knowing about which exact device they are servicing on. It implies that +the ACPI GPIO mapping tables are hardly linked to ACPI ID and certain +objects, as listed in the above chapter, of the device in question. + +Getting GPIO descriptor +----------------------- + +There are two main approaches to get GPIO resource from ACPI: + desc = gpiod_get(dev, connection_id, flags); + desc = gpiod_get_index(dev, connection_id, index, flags); + +We may consider two different cases here, i.e. when connection ID is +provided and otherwise. + +Case 1: + desc = gpiod_get(dev, "non-null-connection-id", flags); + desc = gpiod_get_index(dev, "non-null-connection-id", index, flags); + +Case 2: + desc = gpiod_get(dev, NULL, flags); + desc = gpiod_get_index(dev, NULL, index, flags); + +Case 1 assumes that corresponding ACPI device description must have +defined device properties and will prevent to getting any GPIO resources +otherwise. + +Case 2 explicitly tells GPIO core to look for resources in _CRS. + +Be aware that gpiod_get_index() in cases 1 and 2, assuming that there +are two versions of ACPI device description provided and no mapping is +present in the driver, will return different resources. That's why a +certain driver has to handle them carefully as explained in previous +chapter. diff --git a/Documentation/devicetree/bindings/gpio/gpio.txt b/Documentation/devicetree/bindings/gpio/gpio.txt index 84ede036f73d..802402f6cc5d 100644 --- a/Documentation/devicetree/bindings/gpio/gpio.txt +++ b/Documentation/devicetree/bindings/gpio/gpio.txt @@ -74,11 +74,14 @@ GPIO pin number, and GPIO flags as accepted by the "qe_pio_e" gpio-controller. Optional standard bitfield specifiers for the last cell: - Bit 0: 0 means active high, 1 means active low -- Bit 1: 1 means single-ended wiring, see: +- Bit 1: 0 mean push-pull wiring, see: + https://en.wikipedia.org/wiki/Push-pull_output + 1 means single-ended wiring, see: https://en.wikipedia.org/wiki/Single-ended_triode - When used with active-low, this means open drain/collector, see: +- Bit 2: 0 means open-source, 1 means open drain, see: https://en.wikipedia.org/wiki/Open_collector - When used with active-high, this means open source/emitter +- Bit 3: 0 means the output should be maintained during sleep/low-power mode + 1 means the output state can be lost during sleep/low-power mode 1.1) GPIO specifier best practices ---------------------------------- @@ -282,8 +285,8 @@ Example 1: }; Here, a single GPIO controller has GPIOs 0..9 routed to pin controller -pinctrl1's pins 20..29, and GPIOs 10..19 routed to pin controller pinctrl2's -pins 50..59. +pinctrl1's pins 20..29, and GPIOs 10..29 routed to pin controller pinctrl2's +pins 50..69. Example 2: diff --git a/MAINTAINERS b/MAINTAINERS index 3919392774a5..0bc4d8d84b7c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5692,7 +5692,6 @@ F: tools/testing/selftests/gpio/ GPIO SUBSYSTEM M: Linus Walleij <linus.walleij@linaro.org> -M: Alexandre Courbot <gnurou@gmail.com> L: linux-gpio@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio.git S: Maintained @@ -14131,6 +14130,14 @@ L: linux-kernel@vger.kernel.org S: Supported F: drivers/char/xillybus/ +XRA1403 GPIO EXPANDER +M: Nandor Han <nandor.han@ge.com> +M: Semi Malinen <semi.malinen@ge.com> +L: linux-gpio@vger.kernel.org +S: Maintained +F: drivers/gpio/gpio-xra1403.c +F: Documentation/devicetree/bindings/gpio/gpio-xra1403.txt + XTENSA XTFPGA PLATFORM SUPPORT M: Max Filippov <jcmvbkbc@gmail.com> L: linux-xtensa@linux-xtensa.org diff --git a/arch/arm/configs/lpc32xx_defconfig b/arch/arm/configs/lpc32xx_defconfig index 6ba430d2b5b2..e15fa5f168bb 100644 --- a/arch/arm/configs/lpc32xx_defconfig +++ b/arch/arm/configs/lpc32xx_defconfig @@ -112,7 +112,7 @@ CONFIG_GPIO_SX150X=y CONFIG_GPIO_74X164=y CONFIG_GPIO_MAX7301=y CONFIG_GPIO_MC33880=y -CONFIG_GPIO_MCP23S08=y +CONFIG_PINCTRL_MCP23S08=y CONFIG_SENSORS_DS620=y CONFIG_SENSORS_MAX6639=y CONFIG_WATCHDOG=y diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c index 58075627c6df..f673cd7a6766 100644 --- a/arch/arm/mach-davinci/board-da830-evm.c +++ b/arch/arm/mach-davinci/board-da830-evm.c @@ -17,7 +17,7 @@ #include <linux/gpio/machine.h> #include <linux/platform_device.h> #include <linux/i2c.h> -#include <linux/i2c/pcf857x.h> +#include <linux/platform_data/pcf857x.h> #include <linux/platform_data/at24.h> #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c index 20f1874a5657..70e00dbeec96 100644 --- a/arch/arm/mach-davinci/board-dm644x-evm.c +++ b/arch/arm/mach-davinci/board-dm644x-evm.c @@ -14,7 +14,7 @@ #include <linux/platform_device.h> #include <linux/gpio.h> #include <linux/i2c.h> -#include <linux/i2c/pcf857x.h> +#include <linux/platform_data/pcf857x.h> #include <linux/platform_data/at24.h> #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c index cb176826d1cb..ca69d0b96a4f 100644 --- a/arch/arm/mach-davinci/board-dm646x-evm.c +++ b/arch/arm/mach-davinci/board-dm646x-evm.c @@ -23,7 +23,7 @@ #include <linux/platform_device.h> #include <linux/i2c.h> #include <linux/platform_data/at24.h> -#include <linux/i2c/pcf857x.h> +#include <linux/platform_data/pcf857x.h> #include <media/i2c/tvp514x.h> #include <media/i2c/adv7343.h> diff --git a/arch/arm/mach-pxa/balloon3.c b/arch/arm/mach-pxa/balloon3.c index d452a49c0396..1467c1d1e541 100644 --- a/arch/arm/mach-pxa/balloon3.c +++ b/arch/arm/mach-pxa/balloon3.c @@ -27,7 +27,7 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> #include <linux/types.h> -#include <linux/i2c/pcf857x.h> +#include <linux/platform_data/pcf857x.h> #include <linux/i2c/pxa-i2c.h> #include <linux/mtd/nand.h> #include <linux/mtd/physmap.h> diff --git a/arch/arm/mach-pxa/littleton.c b/arch/arm/mach-pxa/littleton.c index 051c554776a6..fae38fdc8d8e 100644 --- a/arch/arm/mach-pxa/littleton.c +++ b/arch/arm/mach-pxa/littleton.c @@ -27,7 +27,7 @@ #include <linux/i2c.h> #include <linux/leds.h> #include <linux/mfd/da903x.h> -#include <linux/i2c/max732x.h> +#include <linux/platform_data/max732x.h> #include <linux/i2c/pxa-i2c.h> #include <asm/types.h> diff --git a/arch/arm/mach-pxa/stargate2.c b/arch/arm/mach-pxa/stargate2.c index 7b6610e9dae4..2d45d18b1a5e 100644 --- a/arch/arm/mach-pxa/stargate2.c +++ b/arch/arm/mach-pxa/stargate2.c @@ -26,7 +26,7 @@ #include <linux/mtd/partitions.h> #include <linux/i2c/pxa-i2c.h> -#include <linux/i2c/pcf857x.h> +#include <linux/platform_data/pcf857x.h> #include <linux/platform_data/at24.h> #include <linux/smc91x.h> #include <linux/gpio.h> diff --git a/arch/blackfin/configs/BF609-EZKIT_defconfig b/arch/blackfin/configs/BF609-EZKIT_defconfig index ba4267f658af..3ce77f07208a 100644 --- a/arch/blackfin/configs/BF609-EZKIT_defconfig +++ b/arch/blackfin/configs/BF609-EZKIT_defconfig @@ -105,7 +105,7 @@ CONFIG_SPI=y CONFIG_SPI_ADI_V3=y CONFIG_GPIOLIB=y CONFIG_GPIO_SYSFS=y -CONFIG_GPIO_MCP23S08=y +CONFIG_PINCTRL_MCP23S08=y # CONFIG_HWMON is not set CONFIG_WATCHDOG=y CONFIG_BFIN_WDT=y diff --git a/arch/blackfin/mach-bf527/boards/tll6527m.c b/arch/blackfin/mach-bf527/boards/tll6527m.c index c1acce4c2e45..ce5488e8226b 100644 --- a/arch/blackfin/mach-bf527/boards/tll6527m.c +++ b/arch/blackfin/mach-bf527/boards/tll6527m.c @@ -348,14 +348,14 @@ static struct platform_device bfin_i2s = { }; #endif -#if IS_ENABLED(CONFIG_GPIO_MCP23S08) +#if IS_ENABLED(CONFIG_PINCTRL_MCP23S08) #include <linux/spi/mcp23s08.h> static const struct mcp23s08_platform_data bfin_mcp23s08_sys_gpio_info = { - .chip[0].is_present = true, + .spi_present_mask = BIT(0), .base = 0x30, }; static const struct mcp23s08_platform_data bfin_mcp23s08_usr_gpio_info = { - .chip[2].is_present = true, + .spi_present_mask = BIT(2), .base = 0x38, }; #endif @@ -423,7 +423,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = { .mode = SPI_CPHA | SPI_CPOL, }, #endif -#if IS_ENABLED(CONFIG_GPIO_MCP23S08) +#if IS_ENABLED(CONFIG_PINCTRL_MCP23S08) { .modalias = "mcp23s08", .platform_data = &bfin_mcp23s08_sys_gpio_info, diff --git a/arch/blackfin/mach-bf537/boards/stamp.c b/arch/blackfin/mach-bf537/boards/stamp.c index eaec7b4832a2..24985e658c19 100644 --- a/arch/blackfin/mach-bf537/boards/stamp.c +++ b/arch/blackfin/mach-bf537/boards/stamp.c @@ -22,7 +22,7 @@ #include <linux/usb/isp1362.h> #endif #include <linux/i2c.h> -#include <linux/i2c/adp5588.h> +#include <linux/platform_data/adp5588.h> #include <linux/etherdevice.h> #include <linux/ata_platform.h> #include <linux/irq.h> diff --git a/arch/blackfin/mach-bf609/boards/ezkit.c b/arch/blackfin/mach-bf609/boards/ezkit.c index 9231e5a72b93..51157a255824 100644 --- a/arch/blackfin/mach-bf609/boards/ezkit.c +++ b/arch/blackfin/mach-bf609/boards/ezkit.c @@ -1887,7 +1887,7 @@ static struct platform_device i2c_bfin_twi1_device = { }; #endif -#if IS_ENABLED(CONFIG_GPIO_MCP23S08) +#if IS_ENABLED(CONFIG_PINCTRL_MCP23S08) #include <linux/spi/mcp23s08.h> static const struct mcp23s08_platform_data bfin_mcp23s08_soft_switch0 = { .base = 120, @@ -1929,7 +1929,7 @@ static struct i2c_board_info __initdata bfin_i2c_board_info0[] = { I2C_BOARD_INFO("ssm2602", 0x1b), }, #endif -#if IS_ENABLED(CONFIG_GPIO_MCP23S08) +#if IS_ENABLED(CONFIG_PINCTRL_MCP23S08) { I2C_BOARD_INFO("mcp23017", 0x21), .platform_data = (void *)&bfin_mcp23s08_soft_switch0 diff --git a/arch/mips/ath79/mach-pb44.c b/arch/mips/ath79/mach-pb44.c index 67b980d94fb7..be78298dffb4 100644 --- a/arch/mips/ath79/mach-pb44.c +++ b/arch/mips/ath79/mach-pb44.c @@ -12,7 +12,7 @@ #include <linux/platform_device.h> #include <linux/i2c.h> #include <linux/i2c-gpio.h> -#include <linux/i2c/pcf857x.h> +#include <linux/platform_data/pcf857x.h> #include "machtypes.h" #include "dev-gpio-buttons.h" diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 23ca51ee6b28..89e805fc5eba 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -326,9 +326,10 @@ config GPIO_MPC8XXX config GPIO_MVEBU def_bool y - depends on PLAT_ORION + depends on PLAT_ORION || ARCH_MVEBU depends on OF_GPIO select GENERIC_IRQ_CHIP + select REGMAP_MMIO config GPIO_MXC def_bool y @@ -504,12 +505,13 @@ config GPIO_XILINX config GPIO_XLP tristate "Netlogic XLP GPIO support" - depends on OF_GPIO && (CPU_XLP || ARCH_VULCAN || ARCH_THUNDER2 || COMPILE_TEST) + depends on OF_GPIO && (CPU_XLP || ARCH_THUNDER2 || COMPILE_TEST) select GPIOLIB_IRQCHIP help This driver provides support for GPIO interface on Netlogic XLP MIPS64 SoCs. Currently supported XLP variants are XLP8XX, XLP3XX, XLP2XX, - XLP9XX and XLP5XX. + XLP9XX and XLP5XX. The same GPIO controller block is also present in + Cavium's ThunderX2 CN99XX SoCs. If unsure, say N. @@ -1225,22 +1227,10 @@ config GPIO_PISOSR GPIO driver for SPI compatible parallel-in/serial-out shift registers. These are input only devices. -endmenu - -menu "SPI or I2C GPIO expanders" - depends on (SPI_MASTER && !I2C) || I2C - -config GPIO_MCP23S08 - tristate "Microchip MCP23xxx I/O expander" - depends on OF_GPIO - select GPIOLIB_IRQCHIP - select REGMAP_I2C if I2C - select REGMAP if SPI_MASTER +config GPIO_XRA1403 + tristate "EXAR XRA1403 16-bit GPIO expander" help - SPI/I2C driver for Microchip MCP23S08/MCP23S17/MCP23008/MCP23017 - I/O expanders. - This provides a GPIO interface supporting inputs and outputs. - The I2C versions of the chips can be used as interrupt-controller. + GPIO driver for EXAR XRA1403 16-bit SPI-based GPIO expander. endmenu diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 68b96277d9fa..43a326be2e57 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -77,7 +77,6 @@ obj-$(CONFIG_GPIO_MENZ127) += gpio-menz127.o obj-$(CONFIG_GPIO_MERRIFIELD) += gpio-merrifield.o obj-$(CONFIG_GPIO_MC33880) += gpio-mc33880.o obj-$(CONFIG_GPIO_MC9S08DZ60) += gpio-mc9s08dz60.o -obj-$(CONFIG_GPIO_MCP23S08) += gpio-mcp23s08.o obj-$(CONFIG_GPIO_ML_IOH) += gpio-ml-ioh.o obj-$(CONFIG_GPIO_MM_LANTIQ) += gpio-mm-lantiq.o obj-$(CONFIG_GPIO_MOCKUP) += gpio-mockup.o @@ -141,6 +140,7 @@ obj-$(CONFIG_GPIO_XGENE) += gpio-xgene.o obj-$(CONFIG_GPIO_XGENE_SB) += gpio-xgene-sb.o obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o obj-$(CONFIG_GPIO_XLP) += gpio-xlp.o +obj-$(CONFIG_GPIO_XRA1403) += gpio-xra1403.o obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o obj-$(CONFIG_GPIO_ZYNQ) += gpio-zynq.o diff --git a/drivers/gpio/gpio-adp5588.c b/drivers/gpio/gpio-adp5588.c index c0f718b12317..e717f8dc3966 100644 --- a/drivers/gpio/gpio-adp5588.c +++ b/drivers/gpio/gpio-adp5588.c @@ -16,7 +16,7 @@ #include <linux/interrupt.h> #include <linux/irq.h> -#include <linux/i2c/adp5588.h> +#include <linux/platform_data/adp5588.h> #define DRV_NAME "adp5588-gpio" diff --git a/drivers/gpio/gpio-arizona.c b/drivers/gpio/gpio-arizona.c index cd23fd727f95..d4e6ba0301bc 100644 --- a/drivers/gpio/gpio-arizona.c +++ b/drivers/gpio/gpio-arizona.c @@ -33,9 +33,23 @@ static int arizona_gpio_direction_in(struct gpio_chip *chip, unsigned offset) { struct arizona_gpio *arizona_gpio = gpiochip_get_data(chip); struct arizona *arizona = arizona_gpio->arizona; + bool persistent = gpiochip_line_is_persistent(chip, offset); + bool change; + int ret; - return regmap_update_bits(arizona->regmap, ARIZONA_GPIO1_CTRL + offset, - ARIZONA_GPN_DIR, ARIZONA_GPN_DIR); + ret = regmap_update_bits_check(arizona->regmap, + ARIZONA_GPIO1_CTRL + offset, + ARIZONA_GPN_DIR, ARIZONA_GPN_DIR, + &change); + if (ret < 0) + return ret; + + if (change && persistent) { + pm_runtime_mark_last_busy(chip->parent); + pm_runtime_put_autosuspend(chip->parent); + } + + return 0; } static int arizona_gpio_get(struct gpio_chip *chip, unsigned offset) @@ -85,6 +99,21 @@ static int arizona_gpio_direction_out(struct gpio_chip *chip, { struct arizona_gpio *arizona_gpio = gpiochip_get_data(chip); struct arizona *arizona = arizona_gpio->arizona; + bool persistent = gpiochip_line_is_persistent(chip, offset); + unsigned int val; + int ret; + + ret = regmap_read(arizona->regmap, ARIZONA_GPIO1_CTRL + offset, &val); + if (ret < 0) + return ret; + + if ((val & ARIZONA_GPN_DIR) && persistent) { + ret = pm_runtime_get_sync(chip->parent); + if (ret < 0) { + dev_err(chip->parent, "Failed to resume: %d\n", ret); + return ret; + } + } if (value) value = ARIZONA_GPN_LVL; @@ -158,6 +187,8 @@ static int arizona_gpio_probe(struct platform_device *pdev) else arizona_gpio->gpio_chip.base = -1; + pm_runtime_enable(&pdev->dev); + ret = devm_gpiochip_add_data(&pdev->dev, &arizona_gpio->gpio_chip, arizona_gpio); if (ret < 0) { diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c index ccea609676ee..4ca436e66bdb 100644 --- a/drivers/gpio/gpio-aspeed.c +++ b/drivers/gpio/gpio-aspeed.c @@ -646,6 +646,9 @@ static int enable_debounce(struct gpio_chip *chip, unsigned int offset, int rc; int i; + if (!gpio->clk) + return -EINVAL; + rc = usecs_to_cycles(gpio, usecs, &requested_cycles); if (rc < 0) { dev_warn(chip->parent, "Failed to convert %luus to cycles at %luHz: %d\n", diff --git a/drivers/gpio/gpio-crystalcove.c b/drivers/gpio/gpio-crystalcove.c index 2197368cc899..e60156ec0c18 100644 --- a/drivers/gpio/gpio-crystalcove.c +++ b/drivers/gpio/gpio-crystalcove.c @@ -90,8 +90,18 @@ static inline int to_reg(int gpio, enum ctrl_register reg_type) { int reg; - if (gpio == 94) - return GPIOPANELCTL; + if (gpio >= CRYSTALCOVE_GPIO_NUM) { + /* + * Virtual GPIO called from ACPI, for now we only support + * the panel ctl. + */ + switch (gpio) { + case 0x5e: + return GPIOPANELCTL; + default: + return -EOPNOTSUPP; + } + } if (reg_type == CTRL_IN) { if (gpio < 8) @@ -130,36 +140,36 @@ static void crystalcove_update_irq_ctrl(struct crystalcove_gpio *cg, int gpio) static int crystalcove_gpio_dir_in(struct gpio_chip *chip, unsigned gpio) { struct crystalcove_gpio *cg = gpiochip_get_data(chip); + int reg = to_reg(gpio, CTRL_OUT); - if (gpio > CRYSTALCOVE_VGPIO_NUM) + if (reg < 0) return 0; - return regmap_write(cg->regmap, to_reg(gpio, CTRL_OUT), - CTLO_INPUT_SET); + return regmap_write(cg->regmap, reg, CTLO_INPUT_SET); } static int crystalcove_gpio_dir_out(struct gpio_chip *chip, unsigned gpio, int value) { struct crystalcove_gpio *cg = gpiochip_get_data(chip); + int reg = to_reg(gpio, CTRL_OUT); - if (gpio > CRYSTALCOVE_VGPIO_NUM) + if (reg < 0) return 0; - return regmap_write(cg->regmap, to_reg(gpio, CTRL_OUT), - CTLO_OUTPUT_SET | value); + return regmap_write(cg->regmap, reg, CTLO_OUTPUT_SET | value); } static int crystalcove_gpio_get(struct gpio_chip *chip, unsigned gpio) { struct crystalcove_gpio *cg = gpiochip_get_data(chip); - int ret; unsigned int val; + int ret, reg = to_reg(gpio, CTRL_IN); - if (gpio > CRYSTALCOVE_VGPIO_NUM) + if (reg < 0) return 0; - ret = regmap_read(cg->regmap, to_reg(gpio, CTRL_IN), &val); + ret = regmap_read(cg->regmap, reg, &val); if (ret) return ret; @@ -170,14 +180,15 @@ static void crystalcove_gpio_set(struct gpio_chip *chip, unsigned gpio, int value) { struct crystalcove_gpio *cg = gpiochip_get_data(chip); + int reg = to_reg(gpio, CTRL_OUT); - if (gpio > CRYSTALCOVE_VGPIO_NUM) + if (reg < 0) return; if (value) - regmap_update_bits(cg->regmap, to_reg(gpio, CTRL_OUT), 1, 1); + regmap_update_bits(cg->regmap, reg, 1, 1); else - regmap_update_bits(cg->regmap, to_reg(gpio, CTRL_OUT), 1, 0); + regmap_update_bits(cg->regmap, reg, 1, 0); } static int crystalcove_irq_type(struct irq_data *data, unsigned type) @@ -185,6 +196,9 @@ static int crystalcove_irq_type(struct irq_data *data, unsigned type) struct crystalcove_gpio *cg = gpiochip_get_data(irq_data_get_irq_chip_data(data)); + if (data->hwirq >= CRYSTALCOVE_GPIO_NUM) + return 0; + switch (type) { case IRQ_TYPE_NONE: cg->intcnt_value = CTLI_INTCNT_DIS; @@ -235,8 +249,10 @@ static void crystalcove_irq_unmask(struct irq_data *data) struct crystalcove_gpio *cg = gpiochip_get_data(irq_data_get_irq_chip_data(data)); - cg->set_irq_mask = false; - cg->update |= UPDATE_IRQ_MASK; + if (data->hwirq < CRYSTALCOVE_GPIO_NUM) { + cg->set_irq_mask = false; + cg->update |= UPDATE_IRQ_MASK; + } } static void crystalcove_irq_mask(struct irq_data *data) @@ -244,8 +260,10 @@ static void crystalcove_irq_mask(struct irq_data *data) struct crystalcove_gpio *cg = gpiochip_get_data(irq_data_get_irq_chip_data(data)); - cg->set_irq_mask = true; - cg->update |= UPDATE_IRQ_MASK; + if (data->hwirq < CRYSTALCOVE_GPIO_NUM) { + cg->set_irq_mask = true; + cg->update |= UPDATE_IRQ_MASK; + } } static struct irq_chip crystalcove_irqchip = { diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index ac173575d3f6..65cb359308e3 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -437,6 +437,7 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) { unsigned gpio, bank; int irq; + int ret; struct clk *clk; u32 binten = 0; unsigned ngpio, bank_irq; @@ -480,12 +481,15 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) PTR_ERR(clk)); return PTR_ERR(clk); } - clk_prepare_enable(clk); + ret = clk_prepare_enable(clk); + if (ret) + return ret; if (!pdata->gpio_unbanked) { irq = devm_irq_alloc_descs(dev, -1, 0, ngpio, 0); if (irq < 0) { dev_err(dev, "Couldn't allocate IRQ numbers\n"); + clk_disable_unprepare(clk); return irq; } @@ -494,6 +498,7 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) chips); if (!irq_domain) { dev_err(dev, "Couldn't register an IRQ domain\n"); + clk_disable_unprepare(clk); return -ENODEV; } } @@ -562,8 +567,10 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) sizeof(struct davinci_gpio_irq_data), GFP_KERNEL); - if (!irqdata) + if (!irqdata) { + clk_disable_unprepare(clk); return -ENOMEM; + } irqdata->regs = g; irqdata->bank_num = bank; diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c index 4ea4c6a1313b..7f4d26ce5f23 100644 --- a/drivers/gpio/gpio-max732x.c +++ b/drivers/gpio/gpio-max732x.c @@ -20,7 +20,7 @@ #include <linux/gpio/driver.h> #include <linux/interrupt.h> #include <linux/i2c.h> -#include <linux/i2c/max732x.h> +#include <linux/platform_data/max732x.h> #include <linux/of.h> diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c index 78896a869fd9..74fdce096c26 100644 --- a/drivers/gpio/gpio-ml-ioh.c +++ b/drivers/gpio/gpio-ml-ioh.c @@ -385,14 +385,18 @@ static irqreturn_t ioh_gpio_handler(int irq, void *dev_id) return ret; } -static void ioh_gpio_alloc_generic_chip(struct ioh_gpio *chip, - unsigned int irq_start, unsigned int num) +static int ioh_gpio_alloc_generic_chip(struct ioh_gpio *chip, + unsigned int irq_start, + unsigned int num) { struct irq_chip_generic *gc; struct irq_chip_type *ct; gc = irq_alloc_generic_chip("ioh_gpio", 1, irq_start, chip->base, handle_simple_irq); + if (!gc) + return -ENOMEM; + gc->private = chip; ct = gc->chip_types; @@ -404,6 +408,8 @@ static void ioh_gpio_alloc_generic_chip(struct ioh_gpio *chip, irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE, IRQ_NOREQUEST | IRQ_NOPROBE, 0); + + return 0; } static int ioh_gpio_probe(struct pci_dev *pdev, @@ -468,7 +474,11 @@ static int ioh_gpio_probe(struct pci_dev *pdev, goto err_gpiochip_add; } chip->irq_base = irq_base; - ioh_gpio_alloc_generic_chip(chip, irq_base, num_ports[j]); + + ret = ioh_gpio_alloc_generic_chip(chip, + irq_base, num_ports[j]); + if (ret) + goto err_gpiochip_add; } chip = chip_save; diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c index c6dadac70593..ba8d62aa801a 100644 --- a/drivers/gpio/gpio-mockup.c +++ b/drivers/gpio/gpio-mockup.c @@ -29,8 +29,8 @@ #define GPIO_MOCKUP_MAX_GC 10 enum { - DIR_IN = 0, - DIR_OUT, + GPIO_MOCKUP_DIR_OUT = 0, + GPIO_MOCKUP_DIR_IN = 1, }; /* @@ -41,6 +41,7 @@ enum { struct gpio_mockup_line_status { int dir; bool value; + bool irq_enabled; }; struct gpio_mockup_irq_context { @@ -93,7 +94,7 @@ static int gpio_mockup_dirout(struct gpio_chip *gc, unsigned int offset, struct gpio_mockup_chip *chip = gpiochip_get_data(gc); gpio_mockup_set(gc, offset, value); - chip->lines[offset].dir = DIR_OUT; + chip->lines[offset].dir = GPIO_MOCKUP_DIR_OUT; return 0; } @@ -102,7 +103,7 @@ static int gpio_mockup_dirin(struct gpio_chip *gc, unsigned int offset) { struct gpio_mockup_chip *chip = gpiochip_get_data(gc); - chip->lines[offset].dir = DIR_IN; + chip->lines[offset].dir = GPIO_MOCKUP_DIR_IN; return 0; } @@ -142,12 +143,21 @@ static int gpio_mockup_to_irq(struct gpio_chip *chip, unsigned int offset) return chip->irq_base + offset; } -/* - * While we should generally support irqmask and irqunmask, this driver is - * for testing purposes only so we don't care. - */ -static void gpio_mockup_irqmask(struct irq_data *d) { } -static void gpio_mockup_irqunmask(struct irq_data *d) { } +static void gpio_mockup_irqmask(struct irq_data *data) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(data); + struct gpio_mockup_chip *chip = gpiochip_get_data(gc); + + chip->lines[data->irq - gc->irq_base].irq_enabled = false; +} + +static void gpio_mockup_irqunmask(struct irq_data *data) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(data); + struct gpio_mockup_chip *chip = gpiochip_get_data(gc); + + chip->lines[data->irq - gc->irq_base].irq_enabled = true; +} static struct irq_chip gpio_mockup_irqchip = { .name = GPIO_MOCKUP_NAME, @@ -178,6 +188,7 @@ static int gpio_mockup_irqchip_setup(struct device *dev, for (i = 0; i < gc->ngpio; i++) { irq_set_chip(irq_base + i, gc->irqchip); + irq_set_chip_data(irq_base + i, gc); irq_set_handler(irq_base + i, &handle_simple_irq); irq_modify_status(irq_base + i, IRQ_NOREQUEST | IRQ_NOAUTOEN, IRQ_NOPROBE); @@ -206,6 +217,9 @@ static ssize_t gpio_mockup_event_write(struct file *file, chip = priv->chip; gc = &chip->gc; + if (!chip->lines[priv->offset].irq_enabled) + return size; + if (copy_from_user(&buf, usr_buf, 1)) return -EFAULT; @@ -364,9 +378,6 @@ static int gpio_mockup_probe(struct platform_device *pdev) return ret; } - - dev_info(dev, "gpio<%d..%d> add successful!", - base, base + ngpio); } return 0; diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 19a92efabbef..3d03740a20e7 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -33,21 +33,22 @@ * interrupts. */ +#include <linux/bitops.h> +#include <linux/clk.h> #include <linux/err.h> -#include <linux/init.h> #include <linux/gpio.h> +#include <linux/init.h> +#include <linux/io.h> #include <linux/irq.h> -#include <linux/slab.h> +#include <linux/irqchip/chained_irq.h> #include <linux/irqdomain.h> -#include <linux/io.h> -#include <linux/of_irq.h> #include <linux/of_device.h> -#include <linux/pwm.h> -#include <linux/clk.h> +#include <linux/of_irq.h> #include <linux/pinctrl/consumer.h> -#include <linux/irqchip/chained_irq.h> #include <linux/platform_device.h> -#include <linux/bitops.h> +#include <linux/pwm.h> +#include <linux/regmap.h> +#include <linux/slab.h> #include "gpiolib.h" @@ -106,9 +107,8 @@ struct mvebu_pwm { struct mvebu_gpio_chip { struct gpio_chip chip; - spinlock_t lock; - void __iomem *membase; - void __iomem *percpu_membase; + struct regmap *regs; + struct regmap *percpu_regs; int irqbase; struct irq_domain *domain; int soc_variant; @@ -130,92 +130,149 @@ struct mvebu_gpio_chip { * Functions returning addresses of individual registers for a given * GPIO controller. */ -static void __iomem *mvebu_gpioreg_out(struct mvebu_gpio_chip *mvchip) -{ - return mvchip->membase + GPIO_OUT_OFF; -} -static void __iomem *mvebu_gpioreg_blink(struct mvebu_gpio_chip *mvchip) +static void mvebu_gpioreg_edge_cause(struct mvebu_gpio_chip *mvchip, + struct regmap **map, unsigned int *offset) { - return mvchip->membase + GPIO_BLINK_EN_OFF; -} + int cpu; -static void __iomem *mvebu_gpioreg_blink_counter_select(struct mvebu_gpio_chip - *mvchip) -{ - return mvchip->membase + GPIO_BLINK_CNT_SELECT_OFF; + switch (mvchip->soc_variant) { + case MVEBU_GPIO_SOC_VARIANT_ORION: + case MVEBU_GPIO_SOC_VARIANT_MV78200: + *map = mvchip->regs; + *offset = GPIO_EDGE_CAUSE_OFF; + break; + case MVEBU_GPIO_SOC_VARIANT_ARMADAXP: + cpu = smp_processor_id(); + *map = mvchip->percpu_regs; + *offset = GPIO_EDGE_CAUSE_ARMADAXP_OFF(cpu); + break; + default: + BUG(); + } } -static void __iomem *mvebu_gpioreg_io_conf(struct mvebu_gpio_chip *mvchip) +static u32 +mvebu_gpio_read_edge_cause(struct mvebu_gpio_chip *mvchip) { - return mvchip->membase + GPIO_IO_CONF_OFF; -} + struct regmap *map; + unsigned int offset; + u32 val; -static void __iomem *mvebu_gpioreg_in_pol(struct mvebu_gpio_chip *mvchip) -{ - return mvchip->membase + GPIO_IN_POL_OFF; + mvebu_gpioreg_edge_cause(mvchip, &map, &offset); + regmap_read(map, offset, &val); + + return val; } -static void __iomem *mvebu_gpioreg_data_in(struct mvebu_gpio_chip *mvchip) +static void +mvebu_gpio_write_edge_cause(struct mvebu_gpio_chip *mvchip, u32 val) { - return mvchip->membase + GPIO_DATA_IN_OFF; + struct regmap *map; + unsigned int offset; + + mvebu_gpioreg_edge_cause(mvchip, &map, &offset); + regmap_write(map, offset, val); } -static void __iomem *mvebu_gpioreg_edge_cause(struct mvebu_gpio_chip *mvchip) +static inline void +mvebu_gpioreg_edge_mask(struct mvebu_gpio_chip *mvchip, + struct regmap **map, unsigned int *offset) { int cpu; switch (mvchip->soc_variant) { case MVEBU_GPIO_SOC_VARIANT_ORION: + *map = mvchip->regs; + *offset = GPIO_EDGE_MASK_OFF; + break; case MVEBU_GPIO_SOC_VARIANT_MV78200: - return mvchip->membase + GPIO_EDGE_CAUSE_OFF; + cpu = smp_processor_id(); + *map = mvchip->regs; + *offset = GPIO_EDGE_MASK_MV78200_OFF(cpu); + break; case MVEBU_GPIO_SOC_VARIANT_ARMADAXP: cpu = smp_processor_id(); - return mvchip->percpu_membase + - GPIO_EDGE_CAUSE_ARMADAXP_OFF(cpu); + *map = mvchip->percpu_regs; + *offset = GPIO_EDGE_MASK_ARMADAXP_OFF(cpu); + break; default: BUG(); } } -static void __iomem *mvebu_gpioreg_edge_mask(struct mvebu_gpio_chip *mvchip) +static u32 +mvebu_gpio_read_edge_mask(struct mvebu_gpio_chip *mvchip) { - int cpu; + struct regmap *map; + unsigned int offset; + u32 val; - switch (mvchip->soc_variant) { - case MVEBU_GPIO_SOC_VARIANT_ORION: - return mvchip->membase + GPIO_EDGE_MASK_OFF; - case MVEBU_GPIO_SOC_VARIANT_MV78200: - cpu = smp_processor_id(); - return mvchip->membase + GPIO_EDGE_MASK_MV78200_OFF(cpu); - case MVEBU_GPIO_SOC_VARIANT_ARMADAXP: - cpu = smp_processor_id(); - return mvchip->percpu_membase + - GPIO_EDGE_MASK_ARMADAXP_OFF(cpu); - default: - BUG(); - } + mvebu_gpioreg_edge_mask(mvchip, &map, &offset); + regmap_read(map, offset, &val); + + return val; } -static void __iomem *mvebu_gpioreg_level_mask(struct mvebu_gpio_chip *mvchip) +static void +mvebu_gpio_write_edge_mask(struct mvebu_gpio_chip *mvchip, u32 val) +{ + struct regmap *map; + unsigned int offset; + + mvebu_gpioreg_edge_mask(mvchip, &map, &offset); + regmap_write(map, offset, val); +} + +static void +mvebu_gpioreg_level_mask(struct mvebu_gpio_chip *mvchip, + struct regmap **map, unsigned int *offset) { int cpu; switch (mvchip->soc_variant) { case MVEBU_GPIO_SOC_VARIANT_ORION: - return mvchip->membase + GPIO_LEVEL_MASK_OFF; + *map = mvchip->regs; + *offset = GPIO_LEVEL_MASK_OFF; + break; case MVEBU_GPIO_SOC_VARIANT_MV78200: cpu = smp_processor_id(); - return mvchip->membase + GPIO_LEVEL_MASK_MV78200_OFF(cpu); + *map = mvchip->regs; + *offset = GPIO_LEVEL_MASK_MV78200_OFF(cpu); + break; case MVEBU_GPIO_SOC_VARIANT_ARMADAXP: cpu = smp_processor_id(); - return mvchip->percpu_membase + - GPIO_LEVEL_MASK_ARMADAXP_OFF(cpu); + *map = mvchip->percpu_regs; + *offset = GPIO_LEVEL_MASK_ARMADAXP_OFF(cpu); + break; default: BUG(); } } +static u32 +mvebu_gpio_read_level_mask(struct mvebu_gpio_chip *mvchip) +{ + struct regmap *map; + unsigned int offset; + u32 val; + + mvebu_gpioreg_level_mask(mvchip, &map, &offset); + regmap_read(map, offset, &val); + + return val; +} + +static void +mvebu_gpio_write_level_mask(struct mvebu_gpio_chip *mvchip, u32 val) +{ + struct regmap *map; + unsigned int offset; + + mvebu_gpioreg_level_mask(mvchip, &map, &offset); + regmap_write(map, offset, val); +} + /* * Functions returning addresses of individual registers for a given * PWM controller. @@ -236,17 +293,9 @@ static void __iomem *mvebu_pwmreg_blink_off_duration(struct mvebu_pwm *mvpwm) static void mvebu_gpio_set(struct gpio_chip *chip, unsigned int pin, int value) { struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip); - unsigned long flags; - u32 u; - spin_lock_irqsave(&mvchip->lock, flags); - u = readl_relaxed(mvebu_gpioreg_out(mvchip)); - if (value) - u |= BIT(pin); - else - u &= ~BIT(pin); - writel_relaxed(u, mvebu_gpioreg_out(mvchip)); - spin_unlock_irqrestore(&mvchip->lock, flags); + regmap_update_bits(mvchip->regs, GPIO_OUT_OFF, + BIT(pin), value ? BIT(pin) : 0); } static int mvebu_gpio_get(struct gpio_chip *chip, unsigned int pin) @@ -254,11 +303,16 @@ static int mvebu_gpio_get(struct gpio_chip *chip, unsigned int pin) struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip); u32 u; - if (readl_relaxed(mvebu_gpioreg_io_conf(mvchip)) & BIT(pin)) { - u = readl_relaxed(mvebu_gpioreg_data_in(mvchip)) ^ - readl_relaxed(mvebu_gpioreg_in_pol(mvchip)); + regmap_read(mvchip->regs, GPIO_IO_CONF_OFF, &u); + + if (u & BIT(pin)) { + u32 data_in, in_pol; + + regmap_read(mvchip->regs, GPIO_DATA_IN_OFF, &data_in); + regmap_read(mvchip->regs, GPIO_IN_POL_OFF, &in_pol); + u = data_in ^ in_pol; } else { - u = readl_relaxed(mvebu_gpioreg_out(mvchip)); + regmap_read(mvchip->regs, GPIO_OUT_OFF, &u); } return (u >> pin) & 1; @@ -268,25 +322,15 @@ static void mvebu_gpio_blink(struct gpio_chip *chip, unsigned int pin, int value) { struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip); - unsigned long flags; - u32 u; - spin_lock_irqsave(&mvchip->lock, flags); - u = readl_relaxed(mvebu_gpioreg_blink(mvchip)); - if (value) - u |= BIT(pin); - else - u &= ~BIT(pin); - writel_relaxed(u, mvebu_gpioreg_blink(mvchip)); - spin_unlock_irqrestore(&mvchip->lock, flags); + regmap_update_bits(mvchip->regs, GPIO_BLINK_EN_OFF, + BIT(pin), value ? BIT(pin) : 0); } static int mvebu_gpio_direction_input(struct gpio_chip *chip, unsigned int pin) { struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip); - unsigned long flags; int ret; - u32 u; /* * Check with the pinctrl driver whether this pin is usable as @@ -296,11 +340,8 @@ static int mvebu_gpio_direction_input(struct gpio_chip *chip, unsigned int pin) if (ret) return ret; - spin_lock_irqsave(&mvchip->lock, flags); - u = readl_relaxed(mvebu_gpioreg_io_conf(mvchip)); - u |= BIT(pin); - writel_relaxed(u, mvebu_gpioreg_io_conf(mvchip)); - spin_unlock_irqrestore(&mvchip->lock, flags); + regmap_update_bits(mvchip->regs, GPIO_IO_CONF_OFF, + BIT(pin), 1); return 0; } @@ -309,9 +350,7 @@ static int mvebu_gpio_direction_output(struct gpio_chip *chip, unsigned int pin, int value) { struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip); - unsigned long flags; int ret; - u32 u; /* * Check with the pinctrl driver whether this pin is usable as @@ -324,11 +363,8 @@ static int mvebu_gpio_direction_output(struct gpio_chip *chip, unsigned int pin, mvebu_gpio_blink(chip, pin, 0); mvebu_gpio_set(chip, pin, value); - spin_lock_irqsave(&mvchip->lock, flags); - u = readl_relaxed(mvebu_gpioreg_io_conf(mvchip)); - u &= ~BIT(pin); - writel_relaxed(u, mvebu_gpioreg_io_conf(mvchip)); - spin_unlock_irqrestore(&mvchip->lock, flags); + regmap_update_bits(mvchip->regs, GPIO_IO_CONF_OFF, + BIT(pin), 0); return 0; } @@ -350,7 +386,7 @@ static void mvebu_gpio_irq_ack(struct irq_data *d) u32 mask = d->mask; irq_gc_lock(gc); - writel_relaxed(~mask, mvebu_gpioreg_edge_cause(mvchip)); + mvebu_gpio_write_edge_cause(mvchip, ~mask); irq_gc_unlock(gc); } @@ -363,8 +399,7 @@ static void mvebu_gpio_edge_irq_mask(struct irq_data *d) irq_gc_lock(gc); ct->mask_cache_priv &= ~mask; - - writel_relaxed(ct->mask_cache_priv, mvebu_gpioreg_edge_mask(mvchip)); + mvebu_gpio_write_edge_mask(mvchip, ct->mask_cache_priv); irq_gc_unlock(gc); } @@ -377,7 +412,7 @@ static void mvebu_gpio_edge_irq_unmask(struct irq_data *d) irq_gc_lock(gc); ct->mask_cache_priv |= mask; - writel_relaxed(ct->mask_cache_priv, mvebu_gpioreg_edge_mask(mvchip)); + mvebu_gpio_write_edge_mask(mvchip, ct->mask_cache_priv); irq_gc_unlock(gc); } @@ -390,7 +425,7 @@ static void mvebu_gpio_level_irq_mask(struct irq_data *d) irq_gc_lock(gc); ct->mask_cache_priv &= ~mask; - writel_relaxed(ct->mask_cache_priv, mvebu_gpioreg_level_mask(mvchip)); + mvebu_gpio_write_level_mask(mvchip, ct->mask_cache_priv); irq_gc_unlock(gc); } @@ -403,7 +438,7 @@ static void mvebu_gpio_level_irq_unmask(struct irq_data *d) irq_gc_lock(gc); ct->mask_cache_priv |= mask; - writel_relaxed(ct->mask_cache_priv, mvebu_gpioreg_level_mask(mvchip)); + mvebu_gpio_write_level_mask(mvchip, ct->mask_cache_priv); irq_gc_unlock(gc); } @@ -443,8 +478,8 @@ static int mvebu_gpio_irq_set_type(struct irq_data *d, unsigned int type) pin = d->hwirq; - u = readl_relaxed(mvebu_gpioreg_io_conf(mvchip)) & BIT(pin); - if (!u) + regmap_read(mvchip->regs, GPIO_IO_CONF_OFF, &u); + if ((u & BIT(pin)) == 0) return -EINVAL; type &= IRQ_TYPE_SENSE_MASK; @@ -462,31 +497,30 @@ static int mvebu_gpio_irq_set_type(struct irq_data *d, unsigned int type) switch (type) { case IRQ_TYPE_EDGE_RISING: case IRQ_TYPE_LEVEL_HIGH: - u = readl_relaxed(mvebu_gpioreg_in_pol(mvchip)); - u &= ~BIT(pin); - writel_relaxed(u, mvebu_gpioreg_in_pol(mvchip)); + regmap_update_bits(mvchip->regs, GPIO_IN_POL_OFF, + BIT(pin), 0); break; case IRQ_TYPE_EDGE_FALLING: case IRQ_TYPE_LEVEL_LOW: - u = readl_relaxed(mvebu_gpioreg_in_pol(mvchip)); - u |= BIT(pin); - writel_relaxed(u, mvebu_gpioreg_in_pol(mvchip)); + regmap_update_bits(mvchip->regs, GPIO_IN_POL_OFF, + BIT(pin), 1); break; case IRQ_TYPE_EDGE_BOTH: { - u32 v; + u32 data_in, in_pol, val; - v = readl_relaxed(mvebu_gpioreg_in_pol(mvchip)) ^ - readl_relaxed(mvebu_gpioreg_data_in(mvchip)); + regmap_read(mvchip->regs, GPIO_IN_POL_OFF, &in_pol); + regmap_read(mvchip->regs, GPIO_DATA_IN_OFF, &data_in); /* * set initial polarity based on current input level */ - u = readl_relaxed(mvebu_gpioreg_in_pol(mvchip)); - if (v & BIT(pin)) - u |= BIT(pin); /* falling */ + if ((data_in ^ in_pol) & BIT(pin)) + val = BIT(pin); /* falling */ else - u &= ~BIT(pin); /* rising */ - writel_relaxed(u, mvebu_gpioreg_in_pol(mvchip)); + val = 0; /* raising */ + + regmap_update_bits(mvchip->regs, GPIO_IN_POL_OFF, + BIT(pin), val); break; } } @@ -497,7 +531,7 @@ static void mvebu_gpio_irq_handler(struct irq_desc *desc) { struct mvebu_gpio_chip *mvchip = irq_desc_get_handler_data(desc); struct irq_chip *chip = irq_desc_get_chip(desc); - u32 cause, type; + u32 cause, type, data_in, level_mask, edge_cause, edge_mask; int i; if (mvchip == NULL) @@ -505,10 +539,12 @@ static void mvebu_gpio_irq_handler(struct irq_desc *desc) chained_irq_enter(chip, desc); - cause = readl_relaxed(mvebu_gpioreg_data_in(mvchip)) & - readl_relaxed(mvebu_gpioreg_level_mask(mvchip)); - cause |= readl_relaxed(mvebu_gpioreg_edge_cause(mvchip)) & - readl_relaxed(mvebu_gpioreg_edge_mask(mvchip)); + regmap_read(mvchip->regs, GPIO_DATA_IN_OFF, &data_in); + level_mask = mvebu_gpio_read_level_mask(mvchip); + edge_cause = mvebu_gpio_read_edge_cause(mvchip); + edge_mask = mvebu_gpio_read_edge_mask(mvchip); + + cause = (data_in ^ level_mask) | (edge_cause & edge_mask); for (i = 0; i < mvchip->chip.ngpio; i++) { int irq; @@ -523,9 +559,9 @@ static void mvebu_gpio_irq_handler(struct irq_desc *desc) /* Swap polarity (race with GPIO line) */ u32 polarity; - polarity = readl_relaxed(mvebu_gpioreg_in_pol(mvchip)); + regmap_read(mvchip->regs, GPIO_IN_POL_OFF, &polarity); polarity ^= BIT(i); - writel_relaxed(polarity, mvebu_gpioreg_in_pol(mvchip)); + regmap_write(mvchip->regs, GPIO_IN_POL_OFF, polarity); } generic_handle_irq(irq); @@ -628,7 +664,7 @@ static void mvebu_pwm_get_state(struct pwm_chip *chip, state->period = 1; } - u = readl_relaxed(mvebu_gpioreg_blink(mvchip)); + regmap_read(mvchip->regs, GPIO_BLINK_EN_OFF, &u); if (u) state->enabled = true; else @@ -691,8 +727,8 @@ static void __maybe_unused mvebu_pwm_suspend(struct mvebu_gpio_chip *mvchip) { struct mvebu_pwm *mvpwm = mvchip->mvpwm; - mvpwm->blink_select = - readl_relaxed(mvebu_gpioreg_blink_counter_select(mvchip)); + regmap_read(mvchip->regs, GPIO_BLINK_CNT_SELECT_OFF, + &mvpwm->blink_select); mvpwm->blink_on_duration = readl_relaxed(mvebu_pwmreg_blink_on_duration(mvpwm)); mvpwm->blink_off_duration = @@ -703,8 +739,8 @@ static void __maybe_unused mvebu_pwm_resume(struct mvebu_gpio_chip *mvchip) { struct mvebu_pwm *mvpwm = mvchip->mvpwm; - writel_relaxed(mvpwm->blink_select, - mvebu_gpioreg_blink_counter_select(mvchip)); + regmap_write(mvchip->regs, GPIO_BLINK_CNT_SELECT_OFF, + mvpwm->blink_select); writel_relaxed(mvpwm->blink_on_duration, mvebu_pwmreg_blink_on_duration(mvpwm)); writel_relaxed(mvpwm->blink_off_duration, @@ -747,7 +783,7 @@ static int mvebu_pwm_probe(struct platform_device *pdev, set = U32_MAX; else return -EINVAL; - writel_relaxed(0, mvebu_gpioreg_blink_counter_select(mvchip)); + regmap_write(mvchip->regs, GPIO_BLINK_CNT_SELECT_OFF, 0); mvpwm = devm_kzalloc(dev, sizeof(struct mvebu_pwm), GFP_KERNEL); if (!mvpwm) @@ -783,14 +819,14 @@ static void mvebu_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) u32 out, io_conf, blink, in_pol, data_in, cause, edg_msk, lvl_msk; int i; - out = readl_relaxed(mvebu_gpioreg_out(mvchip)); - io_conf = readl_relaxed(mvebu_gpioreg_io_conf(mvchip)); - blink = readl_relaxed(mvebu_gpioreg_blink(mvchip)); - in_pol = readl_relaxed(mvebu_gpioreg_in_pol(mvchip)); - data_in = readl_relaxed(mvebu_gpioreg_data_in(mvchip)); - cause = readl_relaxed(mvebu_gpioreg_edge_cause(mvchip)); - edg_msk = readl_relaxed(mvebu_gpioreg_edge_mask(mvchip)); - lvl_msk = readl_relaxed(mvebu_gpioreg_level_mask(mvchip)); + regmap_read(mvchip->regs, GPIO_OUT_OFF, &out); + regmap_read(mvchip->regs, GPIO_IO_CONF_OFF, &io_conf); + regmap_read(mvchip->regs, GPIO_BLINK_EN_OFF, &blink); + regmap_read(mvchip->regs, GPIO_IN_POL_OFF, &in_pol); + regmap_read(mvchip->regs, GPIO_DATA_IN_OFF, &data_in); + cause = mvebu_gpio_read_edge_cause(mvchip); + edg_msk = mvebu_gpio_read_edge_mask(mvchip); + lvl_msk = mvebu_gpio_read_level_mask(mvchip); for (i = 0; i < chip->ngpio; i++) { const char *label; @@ -858,36 +894,36 @@ static int mvebu_gpio_suspend(struct platform_device *pdev, pm_message_t state) struct mvebu_gpio_chip *mvchip = platform_get_drvdata(pdev); int i; - mvchip->out_reg = readl(mvebu_gpioreg_out(mvchip)); - mvchip->io_conf_reg = readl(mvebu_gpioreg_io_conf(mvchip)); - mvchip->blink_en_reg = readl(mvebu_gpioreg_blink(mvchip)); - mvchip->in_pol_reg = readl(mvebu_gpioreg_in_pol(mvchip)); + regmap_read(mvchip->regs, GPIO_OUT_OFF, &mvchip->out_reg); + regmap_read(mvchip->regs, GPIO_IO_CONF_OFF, &mvchip->io_conf_reg); + regmap_read(mvchip->regs, GPIO_BLINK_EN_OFF, &mvchip->blink_en_reg); + regmap_read(mvchip->regs, GPIO_IN_POL_OFF, &mvchip->in_pol_reg); switch (mvchip->soc_variant) { case MVEBU_GPIO_SOC_VARIANT_ORION: - mvchip->edge_mask_regs[0] = - readl(mvchip->membase + GPIO_EDGE_MASK_OFF); - mvchip->level_mask_regs[0] = - readl(mvchip->membase + GPIO_LEVEL_MASK_OFF); + regmap_read(mvchip->regs, GPIO_EDGE_MASK_OFF, + &mvchip->edge_mask_regs[0]); + regmap_read(mvchip->regs, GPIO_LEVEL_MASK_OFF, + &mvchip->level_mask_regs[0]); break; case MVEBU_GPIO_SOC_VARIANT_MV78200: for (i = 0; i < 2; i++) { - mvchip->edge_mask_regs[i] = - readl(mvchip->membase + - GPIO_EDGE_MASK_MV78200_OFF(i)); - mvchip->level_mask_regs[i] = - readl(mvchip->membase + - GPIO_LEVEL_MASK_MV78200_OFF(i)); + regmap_read(mvchip->regs, + GPIO_EDGE_MASK_MV78200_OFF(i), + &mvchip->edge_mask_regs[i]); + regmap_read(mvchip->regs, + GPIO_LEVEL_MASK_MV78200_OFF(i), + &mvchip->level_mask_regs[i]); } break; case MVEBU_GPIO_SOC_VARIANT_ARMADAXP: for (i = 0; i < 4; i++) { - mvchip->edge_mask_regs[i] = - readl(mvchip->membase + - GPIO_EDGE_MASK_ARMADAXP_OFF(i)); - mvchip->level_mask_regs[i] = - readl(mvchip->membase + - GPIO_LEVEL_MASK_ARMADAXP_OFF(i)); + regmap_read(mvchip->regs, + GPIO_EDGE_MASK_ARMADAXP_OFF(i), + &mvchip->edge_mask_regs[i]); + regmap_read(mvchip->regs, + GPIO_LEVEL_MASK_ARMADAXP_OFF(i), + &mvchip->level_mask_regs[i]); } break; default: @@ -905,35 +941,36 @@ static int mvebu_gpio_resume(struct platform_device *pdev) struct mvebu_gpio_chip *mvchip = platform_get_drvdata(pdev); int i; - writel(mvchip->out_reg, mvebu_gpioreg_out(mvchip)); - writel(mvchip->io_conf_reg, mvebu_gpioreg_io_conf(mvchip)); - writel(mvchip->blink_en_reg, mvebu_gpioreg_blink(mvchip)); - writel(mvchip->in_pol_reg, mvebu_gpioreg_in_pol(mvchip)); + regmap_write(mvchip->regs, GPIO_OUT_OFF, mvchip->out_reg); + regmap_write(mvchip->regs, GPIO_IO_CONF_OFF, mvchip->io_conf_reg); + regmap_write(mvchip->regs, GPIO_BLINK_EN_OFF, mvchip->blink_en_reg); + regmap_write(mvchip->regs, GPIO_IN_POL_OFF, mvchip->in_pol_reg); switch (mvchip->soc_variant) { case MVEBU_GPIO_SOC_VARIANT_ORION: - writel(mvchip->edge_mask_regs[0], - mvchip->membase + GPIO_EDGE_MASK_OFF); - writel(mvchip->level_mask_regs[0], - mvchip->membase + GPIO_LEVEL_MASK_OFF); + regmap_write(mvchip->regs, GPIO_EDGE_MASK_OFF, + mvchip->edge_mask_regs[0]); + regmap_write(mvchip->regs, GPIO_LEVEL_MASK_OFF, + mvchip->level_mask_regs[0]); break; case MVEBU_GPIO_SOC_VARIANT_MV78200: for (i = 0; i < 2; i++) { - writel(mvchip->edge_mask_regs[i], - mvchip->membase + GPIO_EDGE_MASK_MV78200_OFF(i)); - writel(mvchip->level_mask_regs[i], - mvchip->membase + - GPIO_LEVEL_MASK_MV78200_OFF(i)); + regmap_write(mvchip->regs, + GPIO_EDGE_MASK_MV78200_OFF(i), + mvchip->edge_mask_regs[i]); + regmap_write(mvchip->regs, + GPIO_LEVEL_MASK_MV78200_OFF(i), + mvchip->level_mask_regs[i]); } break; case MVEBU_GPIO_SOC_VARIANT_ARMADAXP: for (i = 0; i < 4; i++) { - writel(mvchip->edge_mask_regs[i], - mvchip->membase + - GPIO_EDGE_MASK_ARMADAXP_OFF(i)); - writel(mvchip->level_mask_regs[i], - mvchip->membase + - GPIO_LEVEL_MASK_ARMADAXP_OFF(i)); + regmap_write(mvchip->regs, + GPIO_EDGE_MASK_ARMADAXP_OFF(i), + mvchip->edge_mask_regs[i]); + regmap_write(mvchip->regs, + GPIO_LEVEL_MASK_ARMADAXP_OFF(i), + mvchip->level_mask_regs[i]); } break; default: @@ -946,6 +983,13 @@ static int mvebu_gpio_resume(struct platform_device *pdev) return 0; } +static const struct regmap_config mvebu_gpio_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .fast_io = true, +}; + static int mvebu_gpio_probe(struct platform_device *pdev) { struct mvebu_gpio_chip *mvchip; @@ -954,6 +998,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev) struct resource *res; struct irq_chip_generic *gc; struct irq_chip_type *ct; + void __iomem *base; unsigned int ngpios; bool have_irqs; int soc_variant; @@ -1009,11 +1054,15 @@ static int mvebu_gpio_probe(struct platform_device *pdev) mvchip->chip.of_node = np; mvchip->chip.dbg_show = mvebu_gpio_dbg_show; - spin_lock_init(&mvchip->lock); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - mvchip->membase = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(mvchip->membase)) - return PTR_ERR(mvchip->membase); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + mvchip->regs = devm_regmap_init_mmio(&pdev->dev, base, + &mvebu_gpio_regmap_config); + if (IS_ERR(mvchip->regs)) + return PTR_ERR(mvchip->regs); /* * The Armada XP has a second range of registers for the @@ -1021,10 +1070,15 @@ static int mvebu_gpio_probe(struct platform_device *pdev) */ if (soc_variant == MVEBU_GPIO_SOC_VARIANT_ARMADAXP) { res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - mvchip->percpu_membase = devm_ioremap_resource(&pdev->dev, - res); - if (IS_ERR(mvchip->percpu_membase)) - return PTR_ERR(mvchip->percpu_membase); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + mvchip->percpu_regs = + devm_regmap_init_mmio(&pdev->dev, base, + &mvebu_gpio_regmap_config); + if (IS_ERR(mvchip->percpu_regs)) + return PTR_ERR(mvchip->percpu_regs); } /* @@ -1032,30 +1086,30 @@ static int mvebu_gpio_probe(struct platform_device *pdev) */ switch (soc_variant) { case MVEBU_GPIO_SOC_VARIANT_ORION: - writel_relaxed(0, mvchip->membase + GPIO_EDGE_CAUSE_OFF); - writel_relaxed(0, mvchip->membase + GPIO_EDGE_MASK_OFF); - writel_relaxed(0, mvchip->membase + GPIO_LEVEL_MASK_OFF); + regmap_write(mvchip->regs, GPIO_EDGE_CAUSE_OFF, 0); + regmap_write(mvchip->regs, GPIO_EDGE_MASK_OFF, 0); + regmap_write(mvchip->regs, GPIO_LEVEL_MASK_OFF, 0); break; case MVEBU_GPIO_SOC_VARIANT_MV78200: - writel_relaxed(0, mvchip->membase + GPIO_EDGE_CAUSE_OFF); + regmap_write(mvchip->regs, GPIO_EDGE_CAUSE_OFF, 0); for (cpu = 0; cpu < 2; cpu++) { - writel_relaxed(0, mvchip->membase + - GPIO_EDGE_MASK_MV78200_OFF(cpu)); - writel_relaxed(0, mvchip->membase + - GPIO_LEVEL_MASK_MV78200_OFF(cpu)); + regmap_write(mvchip->regs, + GPIO_EDGE_MASK_MV78200_OFF(cpu), 0); + regmap_write(mvchip->regs, + GPIO_LEVEL_MASK_MV78200_OFF(cpu), 0); } break; case MVEBU_GPIO_SOC_VARIANT_ARMADAXP: - writel_relaxed(0, mvchip->membase + GPIO_EDGE_CAUSE_OFF); - writel_relaxed(0, mvchip->membase + GPIO_EDGE_MASK_OFF); - writel_relaxed(0, mvchip->membase + GPIO_LEVEL_MASK_OFF); + regmap_write(mvchip->regs, GPIO_EDGE_CAUSE_OFF, 0); + regmap_write(mvchip->regs, GPIO_EDGE_MASK_OFF, 0); + regmap_write(mvchip->regs, GPIO_LEVEL_MASK_OFF, 0); for (cpu = 0; cpu < 4; cpu++) { - writel_relaxed(0, mvchip->percpu_membase + - GPIO_EDGE_CAUSE_ARMADAXP_OFF(cpu)); - writel_relaxed(0, mvchip->percpu_membase + - GPIO_EDGE_MASK_ARMADAXP_OFF(cpu)); - writel_relaxed(0, mvchip->percpu_membase + - GPIO_LEVEL_MASK_ARMADAXP_OFF(cpu)); + regmap_write(mvchip->percpu_regs, + GPIO_EDGE_CAUSE_ARMADAXP_OFF(cpu), 0); + regmap_write(mvchip->percpu_regs, + GPIO_EDGE_MASK_ARMADAXP_OFF(cpu), 0); + regmap_write(mvchip->percpu_regs, + GPIO_LEVEL_MASK_ARMADAXP_OFF(cpu), 0); } break; default: diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index 8ddf9302ce3b..a4fd78b9c0e4 100644 --- a/drivers/gpio/gpio-pcf857x.c +++ b/drivers/gpio/gpio-pcf857x.c @@ -20,7 +20,7 @@ #include <linux/gpio.h> #include <linux/i2c.h> -#include <linux/i2c/pcf857x.h> +#include <linux/platform_data/pcf857x.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/irqdomain.h> diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c index 71bc6da11337..f6600f8ada52 100644 --- a/drivers/gpio/gpio-pch.c +++ b/drivers/gpio/gpio-pch.c @@ -331,14 +331,18 @@ static irqreturn_t pch_gpio_handler(int irq, void *dev_id) return ret; } -static void pch_gpio_alloc_generic_chip(struct pch_gpio *chip, - unsigned int irq_start, unsigned int num) +static int pch_gpio_alloc_generic_chip(struct pch_gpio *chip, + unsigned int irq_start, + unsigned int num) { struct irq_chip_generic *gc; struct irq_chip_type *ct; gc = irq_alloc_generic_chip("pch_gpio", 1, irq_start, chip->base, handle_simple_irq); + if (!gc) + return -ENOMEM; + gc->private = chip; ct = gc->chip_types; @@ -349,6 +353,8 @@ static void pch_gpio_alloc_generic_chip(struct pch_gpio *chip, irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE, IRQ_NOREQUEST | IRQ_NOPROBE, 0); + + return 0; } static int pch_gpio_probe(struct pci_dev *pdev, @@ -425,7 +431,10 @@ static int pch_gpio_probe(struct pci_dev *pdev, goto err_request_irq; } - pch_gpio_alloc_generic_chip(chip, irq_base, gpio_pins[chip->ioh]); + ret = pch_gpio_alloc_generic_chip(chip, irq_base, + gpio_pins[chip->ioh]); + if (ret) + goto err_request_irq; end: return 0; diff --git a/drivers/gpio/gpio-sta2x11.c b/drivers/gpio/gpio-sta2x11.c index 39df0620fa38..9e705162da8d 100644 --- a/drivers/gpio/gpio-sta2x11.c +++ b/drivers/gpio/gpio-sta2x11.c @@ -320,13 +320,16 @@ static irqreturn_t gsta_gpio_handler(int irq, void *dev_id) return ret; } -static void gsta_alloc_irq_chip(struct gsta_gpio *chip) +static int gsta_alloc_irq_chip(struct gsta_gpio *chip) { struct irq_chip_generic *gc; struct irq_chip_type *ct; gc = irq_alloc_generic_chip(KBUILD_MODNAME, 1, chip->irq_base, chip->reg_base, handle_simple_irq); + if (!gc) + return -ENOMEM; + gc->private = chip; ct = gc->chip_types; @@ -350,6 +353,8 @@ static void gsta_alloc_irq_chip(struct gsta_gpio *chip) } gc->irq_cnt = i - gc->irq_base; } + + return 0; } /* The platform device used here is instantiated by the MFD device */ @@ -400,7 +405,10 @@ static int gsta_probe(struct platform_device *dev) return err; } chip->irq_base = err; - gsta_alloc_irq_chip(chip); + + err = gsta_alloc_irq_chip(chip); + if (err) + return err; err = devm_request_irq(&dev->dev, pdev->irq, gsta_gpio_handler, IRQF_SHARED, KBUILD_MODNAME, chip); diff --git a/drivers/gpio/gpio-xra1403.c b/drivers/gpio/gpio-xra1403.c new file mode 100644 index 000000000000..0230e4b7a2fb --- /dev/null +++ b/drivers/gpio/gpio-xra1403.c @@ -0,0 +1,237 @@ +/* + * GPIO driver for EXAR XRA1403 16-bit GPIO expander + * + * Copyright (c) 2017, General Electric Company + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/bitops.h> +#include <linux/gpio/driver.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/of_device.h> +#include <linux/of_gpio.h> +#include <linux/seq_file.h> +#include <linux/spi/spi.h> +#include <linux/regmap.h> + +/* XRA1403 registers */ +#define XRA_GSR 0x00 /* GPIO State */ +#define XRA_OCR 0x02 /* Output Control */ +#define XRA_PIR 0x04 /* Input Polarity Inversion */ +#define XRA_GCR 0x06 /* GPIO Configuration */ +#define XRA_PUR 0x08 /* Input Internal Pull-up Resistor Enable/Disable */ +#define XRA_IER 0x0A /* Input Interrupt Enable */ +#define XRA_TSCR 0x0C /* Output Three-State Control */ +#define XRA_ISR 0x0E /* Input Interrupt Status */ +#define XRA_REIR 0x10 /* Input Rising Edge Interrupt Enable */ +#define XRA_FEIR 0x12 /* Input Falling Edge Interrupt Enable */ +#define XRA_IFR 0x14 /* Input Filter Enable/Disable */ + +struct xra1403 { + struct gpio_chip chip; + struct regmap *regmap; +}; + +static const struct regmap_config xra1403_regmap_cfg = { + .reg_bits = 7, + .pad_bits = 1, + .val_bits = 8, + + .max_register = XRA_IFR | 0x01, +}; + +static unsigned int to_reg(unsigned int reg, unsigned int offset) +{ + return reg + (offset > 7); +} + +static int xra1403_direction_input(struct gpio_chip *chip, unsigned int offset) +{ + struct xra1403 *xra = gpiochip_get_data(chip); + + return regmap_update_bits(xra->regmap, to_reg(XRA_GCR, offset), + BIT(offset % 8), BIT(offset % 8)); +} + +static int xra1403_direction_output(struct gpio_chip *chip, unsigned int offset, + int value) +{ + int ret; + struct xra1403 *xra = gpiochip_get_data(chip); + + ret = regmap_update_bits(xra->regmap, to_reg(XRA_GCR, offset), + BIT(offset % 8), 0); + if (ret) + return ret; + + ret = regmap_update_bits(xra->regmap, to_reg(XRA_OCR, offset), + BIT(offset % 8), value ? BIT(offset % 8) : 0); + + return ret; +} + +static int xra1403_get_direction(struct gpio_chip *chip, unsigned int offset) +{ + int ret; + unsigned int val; + struct xra1403 *xra = gpiochip_get_data(chip); + + ret = regmap_read(xra->regmap, to_reg(XRA_GCR, offset), &val); + if (ret) + return ret; + + return !!(val & BIT(offset % 8)); +} + +static int xra1403_get(struct gpio_chip *chip, unsigned int offset) +{ + int ret; + unsigned int val; + struct xra1403 *xra = gpiochip_get_data(chip); + + ret = regmap_read(xra->regmap, to_reg(XRA_GSR, offset), &val); + if (ret) + return ret; + + return !!(val & BIT(offset % 8)); +} + +static void xra1403_set(struct gpio_chip *chip, unsigned int offset, int value) +{ + int ret; + struct xra1403 *xra = gpiochip_get_data(chip); + + ret = regmap_update_bits(xra->regmap, to_reg(XRA_OCR, offset), + BIT(offset % 8), value ? BIT(offset % 8) : 0); + if (ret) + dev_err(chip->parent, "Failed to set pin: %d, ret: %d\n", + offset, ret); +} + +#ifdef CONFIG_DEBUG_FS +static void xra1403_dbg_show(struct seq_file *s, struct gpio_chip *chip) +{ + int reg; + struct xra1403 *xra = gpiochip_get_data(chip); + int value[xra1403_regmap_cfg.max_register]; + int i; + unsigned int gcr; + unsigned int gsr; + + seq_puts(s, "xra reg:"); + for (reg = 0; reg <= xra1403_regmap_cfg.max_register; reg++) + seq_printf(s, " %2.2x", reg); + seq_puts(s, "\n value:"); + for (reg = 0; reg < xra1403_regmap_cfg.max_register; reg++) { + regmap_read(xra->regmap, reg, &value[reg]); + seq_printf(s, " %2.2x", value[reg]); + } + seq_puts(s, "\n"); + + gcr = value[XRA_GCR + 1] << 8 | value[XRA_GCR]; + gsr = value[XRA_GSR + 1] << 8 | value[XRA_GSR]; + for (i = 0; i < chip->ngpio; i++) { + const char *label = gpiochip_is_requested(chip, i); + + if (!label) + continue; + + seq_printf(s, " gpio-%-3d (%-12s) %s %s\n", + chip->base + i, label, + (gcr & BIT(i)) ? "in" : "out", + (gsr & BIT(i)) ? "hi" : "lo"); + } +} +#else +#define xra1403_dbg_show NULL +#endif + +static int xra1403_probe(struct spi_device *spi) +{ + struct xra1403 *xra; + struct gpio_desc *reset_gpio; + int ret; + + xra = devm_kzalloc(&spi->dev, sizeof(*xra), GFP_KERNEL); + if (!xra) + return -ENOMEM; + + /* bring the chip out of reset if reset pin is provided*/ + reset_gpio = devm_gpiod_get_optional(&spi->dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(reset_gpio)) + dev_warn(&spi->dev, "Could not get reset-gpios\n"); + + xra->chip.direction_input = xra1403_direction_input; + xra->chip.direction_output = xra1403_direction_output; + xra->chip.get_direction = xra1403_get_direction; + xra->chip.get = xra1403_get; + xra->chip.set = xra1403_set; + + xra->chip.dbg_show = xra1403_dbg_show; + + xra->chip.ngpio = 16; + xra->chip.label = "xra1403"; + + xra->chip.base = -1; + xra->chip.can_sleep = true; + xra->chip.parent = &spi->dev; + xra->chip.owner = THIS_MODULE; + + xra->regmap = devm_regmap_init_spi(spi, &xra1403_regmap_cfg); + if (IS_ERR(xra->regmap)) { + ret = PTR_ERR(xra->regmap); + dev_err(&spi->dev, "Failed to allocate regmap: %d\n", ret); + return ret; + } + + ret = devm_gpiochip_add_data(&spi->dev, &xra->chip, xra); + if (ret < 0) { + dev_err(&spi->dev, "Unable to register gpiochip\n"); + return ret; + } + + spi_set_drvdata(spi, xra); + + return 0; +} + +static const struct spi_device_id xra1403_ids[] = { + { "xra1403" }, + {}, +}; +MODULE_DEVICE_TABLE(spi, xra1403_ids); + +static const struct of_device_id xra1403_spi_of_match[] = { + { .compatible = "exar,xra1403" }, + {}, +}; +MODULE_DEVICE_TABLE(of, xra1403_spi_of_match); + +static struct spi_driver xra1403_driver = { + .probe = xra1403_probe, + .id_table = xra1403_ids, + .driver = { + .name = "xra1403", + .of_match_table = of_match_ptr(xra1403_spi_of_match), + }, +}; + +module_spi_driver(xra1403_driver); + +MODULE_AUTHOR("Nandor Han <nandor.han@ge.com>"); +MODULE_AUTHOR("Semi Malinen <semi.malinen@ge.com>"); +MODULE_DESCRIPTION("GPIO expander driver for EXAR XRA1403"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c index 6b4d10d6e10f..ed87c9a6e0e6 100644 --- a/drivers/gpio/gpio-zynq.c +++ b/drivers/gpio/gpio-zynq.c @@ -651,9 +651,8 @@ static const struct zynq_platform_data zynq_gpio_def = { }; static const struct of_device_id zynq_gpio_of_match[] = { - { .compatible = "xlnx,zynq-gpio-1.0", .data = (void *)&zynq_gpio_def }, - { .compatible = "xlnx,zynqmp-gpio-1.0", - .data = (void *)&zynqmp_gpio_def }, + { .compatible = "xlnx,zynq-gpio-1.0", .data = &zynq_gpio_def }, + { .compatible = "xlnx,zynqmp-gpio-1.0", .data = &zynqmp_gpio_def }, { /* end of table */ } }; MODULE_DEVICE_TABLE(of, zynq_gpio_of_match); diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 2185232da823..6bea176b066c 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -165,6 +165,23 @@ static void acpi_gpio_chip_dh(acpi_handle handle, void *data) /* The address of this function is used as a key. */ } +bool acpi_gpio_get_irq_resource(struct acpi_resource *ares, + struct acpi_resource_gpio **agpio) +{ + struct acpi_resource_gpio *gpio; + + if (ares->type != ACPI_RESOURCE_TYPE_GPIO) + return false; + + gpio = &ares->data.gpio; + if (gpio->connection_type != ACPI_RESOURCE_GPIO_TYPE_INT) + return false; + + *agpio = gpio; + return true; +} +EXPORT_SYMBOL_GPL(acpi_gpio_get_irq_resource); + static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares, void *context) { @@ -178,11 +195,7 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares, unsigned long irqflags; int ret, pin, irq; - if (ares->type != ACPI_RESOURCE_TYPE_GPIO) - return AE_OK; - - agpio = &ares->data.gpio; - if (agpio->connection_type != ACPI_RESOURCE_GPIO_TYPE_INT) + if (!acpi_gpio_get_irq_resource(ares, &agpio)) return AE_OK; handle = ACPI_HANDLE(chip->parent); @@ -423,6 +436,59 @@ static bool acpi_get_driver_gpio_data(struct acpi_device *adev, return false; } +static enum gpiod_flags +acpi_gpio_to_gpiod_flags(const struct acpi_resource_gpio *agpio) +{ + bool pull_up = agpio->pin_config == ACPI_PIN_CONFIG_PULLUP; + + switch (agpio->io_restriction) { + case ACPI_IO_RESTRICT_INPUT: + return GPIOD_IN; + case ACPI_IO_RESTRICT_OUTPUT: + /* + * ACPI GPIO resources don't contain an initial value for the + * GPIO. Therefore we deduce that value from the pull field + * instead. If the pin is pulled up we assume default to be + * high, otherwise low. + */ + return pull_up ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW; + default: + /* + * Assume that the BIOS has configured the direction and pull + * accordingly. + */ + return GPIOD_ASIS; + } +} + +int +acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, enum gpiod_flags update) +{ + int ret = 0; + + /* + * Check if the BIOS has IoRestriction with explicitly set direction + * and update @flags accordingly. Otherwise use whatever caller asked + * for. + */ + if (update & GPIOD_FLAGS_BIT_DIR_SET) { + enum gpiod_flags diff = *flags ^ update; + + /* + * Check if caller supplied incompatible GPIO initialization + * flags. + * + * Return %-EINVAL to notify that firmware has different + * settings and we are going to use them. + */ + if (((*flags & GPIOD_FLAGS_BIT_DIR_SET) && (diff & GPIOD_FLAGS_BIT_DIR_OUT)) || + ((*flags & GPIOD_FLAGS_BIT_DIR_OUT) && (diff & GPIOD_FLAGS_BIT_DIR_VAL))) + ret = -EINVAL; + *flags = update; + } + return ret; +} + struct acpi_gpio_lookup { struct acpi_gpio_info info; int index; @@ -460,8 +526,11 @@ static int acpi_populate_gpio_lookup(struct acpi_resource *ares, void *data) * - ACPI_ACTIVE_HIGH == GPIO_ACTIVE_HIGH */ if (lookup->info.gpioint) { + lookup->info.flags = GPIOD_IN; lookup->info.polarity = agpio->polarity; lookup->info.triggering = agpio->triggering; + } else { + lookup->info.flags = acpi_gpio_to_gpiod_flags(agpio); } } @@ -588,18 +657,19 @@ static struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev, struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id, unsigned int idx, - enum gpiod_flags flags, + enum gpiod_flags *dflags, enum gpio_lookup_flags *lookupflags) { struct acpi_device *adev = ACPI_COMPANION(dev); struct acpi_gpio_info info; struct gpio_desc *desc; char propname[32]; + int err; int i; /* Try first from _DSD */ for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) { - if (con_id && strcmp(con_id, "gpios")) { + if (con_id) { snprintf(propname, sizeof(propname), "%s-%s", con_id, gpio_suffixes[i]); } else { @@ -622,17 +692,21 @@ struct gpio_desc *acpi_find_gpio(struct device *dev, desc = acpi_get_gpiod_by_index(adev, NULL, idx, &info); if (IS_ERR(desc)) return desc; + } - if ((flags == GPIOD_OUT_LOW || flags == GPIOD_OUT_HIGH) && - info.gpioint) { - dev_dbg(dev, "refusing GpioInt() entry when doing GPIOD_OUT_* lookup\n"); - return ERR_PTR(-ENOENT); - } + if (info.gpioint && + (*dflags == GPIOD_OUT_LOW || *dflags == GPIOD_OUT_HIGH)) { + dev_dbg(dev, "refusing GpioInt() entry when doing GPIOD_OUT_* lookup\n"); + return ERR_PTR(-ENOENT); } if (info.polarity == GPIO_ACTIVE_LOW) *lookupflags |= GPIO_ACTIVE_LOW; + err = acpi_gpio_update_gpiod_flags(dflags, info.flags); + if (err) + dev_dbg(dev, "Override GPIO initialization flags\n"); + return desc; } @@ -686,12 +760,16 @@ struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode, * used to translate from the GPIO offset in the resource to the Linux IRQ * number. * + * The function is idempotent, though each time it runs it will configure GPIO + * pin direction according to the flags in GpioInt resource. + * * Return: Linux IRQ number (>%0) on success, negative errno on failure. */ int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index) { int idx, i; unsigned int irq_flags; + int ret; for (i = 0, idx = 0; idx <= index; i++) { struct acpi_gpio_info info; @@ -704,6 +782,7 @@ int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index) return PTR_ERR(desc); if (info.gpioint && idx++ == index) { + char label[32]; int irq; if (IS_ERR(desc)) @@ -713,6 +792,11 @@ int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index) if (irq < 0) return irq; + snprintf(label, sizeof(label), "GpioInt() %d", index); + ret = gpiod_configure_flags(desc, label, 0, info.flags); + if (ret < 0) + return ret; + irq_flags = acpi_dev_get_irq_type(info.triggering, info.polarity); @@ -740,7 +824,6 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address, struct acpi_resource *ares; int pin_index = (int)address; acpi_status status; - bool pull_up; int length; int i; @@ -755,7 +838,6 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address, } agpio = &ares->data.gpio; - pull_up = agpio->pin_config == ACPI_PIN_CONFIG_PULLUP; if (WARN_ON(agpio->io_restriction == ACPI_IO_RESTRICT_INPUT && function == ACPI_WRITE)) { @@ -806,35 +888,23 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address, } if (!found) { - desc = gpiochip_request_own_desc(chip, pin, - "ACPI:OpRegion"); + enum gpiod_flags flags = acpi_gpio_to_gpiod_flags(agpio); + const char *label = "ACPI:OpRegion"; + int err; + + desc = gpiochip_request_own_desc(chip, pin, label); if (IS_ERR(desc)) { status = AE_ERROR; mutex_unlock(&achip->conn_lock); goto out; } - switch (agpio->io_restriction) { - case ACPI_IO_RESTRICT_INPUT: - gpiod_direction_input(desc); - break; - case ACPI_IO_RESTRICT_OUTPUT: - /* - * ACPI GPIO resources don't contain an - * initial value for the GPIO. Therefore we - * deduce that value from the pull field - * instead. If the pin is pulled up we - * assume default to be high, otherwise - * low. - */ - gpiod_direction_output(desc, pull_up); - break; - default: - /* - * Assume that the BIOS has configured the - * direction and pull accordingly. - */ - break; + err = gpiod_configure_flags(desc, label, 0, flags); + if (err < 0) { + status = AE_NOT_CONFIGURED; + gpiochip_free_own_desc(desc); + mutex_unlock(&achip->conn_lock); + goto out; } conn = kzalloc(sizeof(*conn), GFP_KERNEL); @@ -1089,7 +1159,7 @@ int acpi_gpio_count(struct device *dev, const char *con_id) /* Try first from _DSD */ for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) { - if (con_id && strcmp(con_id, "gpios")) + if (con_id) snprintf(propname, sizeof(propname), "%s-%s", con_id, gpio_suffixes[i]); else @@ -1119,6 +1189,9 @@ int acpi_gpio_count(struct device *dev, const char *con_id) struct list_head resource_list; unsigned int crs_count = 0; + if (!acpi_can_fallback_to_crs(adev, con_id)) + return count; + INIT_LIST_HEAD(&resource_list); acpi_dev_get_resources(adev, &resource_list, acpi_find_gpio_count, &crs_count); @@ -1129,45 +1202,11 @@ int acpi_gpio_count(struct device *dev, const char *con_id) return count ? count : -ENOENT; } -struct acpi_crs_lookup { - struct list_head node; - struct acpi_device *adev; - const char *con_id; -}; - -static DEFINE_MUTEX(acpi_crs_lookup_lock); -static LIST_HEAD(acpi_crs_lookup_list); - bool acpi_can_fallback_to_crs(struct acpi_device *adev, const char *con_id) { - struct acpi_crs_lookup *l, *lookup = NULL; - /* Never allow fallback if the device has properties */ if (adev->data.properties || adev->driver_gpios) return false; - mutex_lock(&acpi_crs_lookup_lock); - - list_for_each_entry(l, &acpi_crs_lookup_list, node) { - if (l->adev == adev) { - lookup = l; - break; - } - } - - if (!lookup) { - lookup = kmalloc(sizeof(*lookup), GFP_KERNEL); - if (lookup) { - lookup->adev = adev; - lookup->con_id = kstrdup(con_id, GFP_KERNEL); - list_add_tail(&lookup->node, &acpi_crs_lookup_list); - } - } - - mutex_unlock(&acpi_crs_lookup_lock); - - return lookup && - ((!lookup->con_id && !con_id) || - (lookup->con_id && con_id && - strcmp(lookup->con_id, con_id) == 0)); + return con_id == NULL; } diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index b13b7c7c335f..e2abf0eabaf8 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -153,6 +153,9 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, *flags |= GPIO_OPEN_SOURCE; } + if (of_flags & OF_GPIO_SLEEP_MAY_LOOSE_VALUE) + *flags |= GPIO_SLEEP_MAY_LOOSE_VALUE; + return desc; } diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 5db44139cef8..be8097097326 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1,4 +1,4 @@ -#include <linux/bitops.h> +#include <linux/bitmap.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/interrupt.h> @@ -1482,8 +1482,7 @@ static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip) return -ENOMEM; /* Assume by default all GPIOs are valid */ - for (i = 0; i < gpiochip->ngpio; i++) - set_bit(i, gpiochip->irq_valid_mask); + bitmap_fill(gpiochip->irq_valid_mask, gpiochip->ngpio); return 0; } @@ -2869,6 +2868,16 @@ bool gpiochip_line_is_open_source(struct gpio_chip *chip, unsigned int offset) } EXPORT_SYMBOL_GPL(gpiochip_line_is_open_source); +bool gpiochip_line_is_persistent(struct gpio_chip *chip, unsigned int offset) +{ + if (offset >= chip->ngpio) + return false; + + return !test_bit(FLAG_SLEEP_MAY_LOOSE_VALUE, + &chip->gpiodev->descs[offset].flags); +} +EXPORT_SYMBOL_GPL(gpiochip_line_is_persistent); + /** * gpiod_get_raw_value_cansleep() - return a gpio's raw value * @desc: gpio whose value will be returned @@ -3008,6 +3017,7 @@ void gpiod_add_lookup_table(struct gpiod_lookup_table *table) mutex_unlock(&gpio_lookup_lock); } +EXPORT_SYMBOL_GPL(gpiod_add_lookup_table); /** * gpiod_remove_lookup_table() - unregister GPIO device consumers @@ -3021,6 +3031,7 @@ void gpiod_remove_lookup_table(struct gpiod_lookup_table *table) mutex_unlock(&gpio_lookup_lock); } +EXPORT_SYMBOL_GPL(gpiod_remove_lookup_table); static struct gpiod_lookup_table *gpiod_find_lookup_table(struct device *dev) { @@ -3212,7 +3223,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_optional); * requested function and/or index, or another IS_ERR() code if an error * occurred while trying to acquire the GPIO. */ -static int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id, +int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id, unsigned long lflags, enum gpiod_flags dflags) { int status; @@ -3223,6 +3234,8 @@ static int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id, set_bit(FLAG_OPEN_DRAIN, &desc->flags); if (lflags & GPIO_OPEN_SOURCE) set_bit(FLAG_OPEN_SOURCE, &desc->flags); + if (lflags & GPIO_SLEEP_MAY_LOOSE_VALUE) + set_bit(FLAG_SLEEP_MAY_LOOSE_VALUE, &desc->flags); /* No particular flag request, return here... */ if (!(dflags & GPIOD_FLAGS_BIT_DIR_SET)) { @@ -3272,7 +3285,7 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev, desc = of_find_gpio(dev, con_id, idx, &lookupflags); } else if (ACPI_COMPANION(dev)) { dev_dbg(dev, "using ACPI for GPIO lookup\n"); - desc = acpi_find_gpio(dev, con_id, idx, flags, &lookupflags); + desc = acpi_find_gpio(dev, con_id, idx, &flags, &lookupflags); } } @@ -3353,8 +3366,12 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, struct acpi_gpio_info info; desc = acpi_node_get_gpiod(fwnode, propname, index, &info); - if (!IS_ERR(desc)) + if (!IS_ERR(desc)) { active_low = info.polarity == GPIO_ACTIVE_LOW; + ret = acpi_gpio_update_gpiod_flags(&dflags, info.flags); + if (ret) + pr_debug("Override GPIO initialization flags\n"); + } } if (IS_ERR(desc)) diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index 2495b7ee1b42..a8be286eff86 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -75,11 +75,13 @@ struct gpio_device { /** * struct acpi_gpio_info - ACPI GPIO specific information + * @flags: GPIO initialization flags * @gpioint: if %true this GPIO is of type GpioInt otherwise type is GpioIo * @polarity: interrupt polarity as provided by ACPI * @triggering: triggering type as provided by ACPI */ struct acpi_gpio_info { + enum gpiod_flags flags; bool gpioint; int polarity; int triggering; @@ -121,10 +123,13 @@ void acpi_gpiochip_remove(struct gpio_chip *chip); void acpi_gpiochip_request_interrupts(struct gpio_chip *chip); void acpi_gpiochip_free_interrupts(struct gpio_chip *chip); +int acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, + enum gpiod_flags update); + struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id, unsigned int idx, - enum gpiod_flags flags, + enum gpiod_flags *dflags, enum gpio_lookup_flags *lookupflags); struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode, const char *propname, int index, @@ -143,9 +148,15 @@ acpi_gpiochip_request_interrupts(struct gpio_chip *chip) { } static inline void acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { } +static inline int +acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, enum gpiod_flags update) +{ + return 0; +} + static inline struct gpio_desc * acpi_find_gpio(struct device *dev, const char *con_id, - unsigned int idx, enum gpiod_flags flags, + unsigned int idx, enum gpiod_flags *dflags, enum gpio_lookup_flags *lookupflags) { return ERR_PTR(-ENOENT); @@ -190,6 +201,7 @@ struct gpio_desc { #define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */ #define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */ #define FLAG_IS_HOGGED 11 /* GPIO is hogged */ +#define FLAG_SLEEP_MAY_LOOSE_VALUE 12 /* GPIO may loose value in sleep */ /* Connection label */ const char *label; @@ -199,6 +211,8 @@ struct gpio_desc { int gpiod_request(struct gpio_desc *desc, const char *label); void gpiod_free(struct gpio_desc *desc); +int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id, + unsigned long lflags, enum gpiod_flags dflags); int gpiod_hog(struct gpio_desc *desc, const char *name, unsigned long lflags, enum gpiod_flags dflags); diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c index 53fe9a3fb620..f9d273c8b306 100644 --- a/drivers/input/keyboard/adp5588-keys.c +++ b/drivers/input/keyboard/adp5588-keys.c @@ -20,7 +20,7 @@ #include <linux/gpio.h> #include <linux/slab.h> -#include <linux/i2c/adp5588.h> +#include <linux/platform_data/adp5588.h> /* Key Event Register xy */ #define KEY_EV_PRESSED (1 << 7) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 37af5e3029d5..1c80b970554e 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -146,6 +146,19 @@ config PINCTRL_FALCON depends on SOC_FALCON depends on PINCTRL_LANTIQ +config PINCTRL_MCP23S08 + tristate "Microchip MCP23xxx I/O expander" + depends on SPI_MASTER || I2C + select GPIOLIB_IRQCHIP + select REGMAP_I2C if I2C + select REGMAP_SPI if SPI_MASTER + select GENERIC_PINCONF + help + SPI/I2C driver for Microchip MCP23S08/MCP23S17/MCP23008/MCP23017 + I/O expanders. + This provides a GPIO interface supporting inputs and outputs. + The I2C versions of the chips can be used as interrupt-controller. + config PINCTRL_MESON bool depends on OF diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 0e9b2226a7c2..59d793aa3db3 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_PINCTRL_DA850_PUPD) += pinctrl-da850-pupd.o obj-$(CONFIG_PINCTRL_DIGICOLOR) += pinctrl-digicolor.o obj-$(CONFIG_PINCTRL_FALCON) += pinctrl-falcon.o obj-$(CONFIG_PINCTRL_MAX77620) += pinctrl-max77620.o +obj-$(CONFIG_PINCTRL_MCP23S08) += pinctrl-mcp23s08.o obj-$(CONFIG_PINCTRL_MESON) += meson/ obj-$(CONFIG_PINCTRL_OXNAS) += pinctrl-oxnas.o obj-$(CONFIG_PINCTRL_PALMAS) += pinctrl-palmas.o diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/pinctrl/pinctrl-mcp23s08.c index 2a57d024481d..3e40d4245512 100644 --- a/drivers/gpio/gpio-mcp23s08.c +++ b/drivers/pinctrl/pinctrl-mcp23s08.c @@ -1,14 +1,4 @@ -/* - * MCP23S08 SPI/I2C GPIO gpio expander driver - * - * The inputs and outputs of the mcp23s08, mcp23s17, mcp23008 and mcp23017 are - * supported. - * For the I2C versions of the chips (mcp23008 and mcp23017) generation of - * interrupts is also supported. - * The hardware of the SPI versions of the chips (mcp23s08 and mcp23s17) is - * also capable of generating interrupts, but the linux driver does not - * support that yet. - */ +/* MCP23S08 SPI/I2C GPIO driver */ #include <linux/kernel.h> #include <linux/device.h> @@ -21,11 +11,13 @@ #include <linux/slab.h> #include <asm/byteorder.h> #include <linux/interrupt.h> -#include <linux/of_irq.h> #include <linux/of_device.h> #include <linux/regmap.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinconf.h> +#include <linux/pinctrl/pinconf-generic.h> -/** +/* * MCP types supported by driver */ #define MCP_TYPE_S08 0 @@ -34,6 +26,8 @@ #define MCP_TYPE_017 3 #define MCP_TYPE_S18 4 +#define MCP_MAX_DEV_PER_CS 8 + /* Registers are all 8 bits wide. * * The mcp23s17 has twice as many bits, and can be configured to work @@ -64,19 +58,52 @@ struct mcp23s08 { bool irq_active_high; bool reg_shift; - u16 cache[11]; u16 irq_rise; u16 irq_fall; int irq; bool irq_controller; - /* lock protects the cached values */ + int cached_gpio; + /* lock protects regmap access with bypass/cache flags */ struct mutex lock; - struct mutex irq_lock; struct gpio_chip chip; struct regmap *regmap; struct device *dev; + + struct pinctrl_dev *pctldev; + struct pinctrl_desc pinctrl_desc; +}; + +static const struct reg_default mcp23x08_defaults[] = { + {.reg = MCP_IODIR, .def = 0xff}, + {.reg = MCP_IPOL, .def = 0x00}, + {.reg = MCP_GPINTEN, .def = 0x00}, + {.reg = MCP_DEFVAL, .def = 0x00}, + {.reg = MCP_INTCON, .def = 0x00}, + {.reg = MCP_IOCON, .def = 0x00}, + {.reg = MCP_GPPU, .def = 0x00}, + {.reg = MCP_OLAT, .def = 0x00}, +}; + +static const struct regmap_range mcp23x08_volatile_range = { + .range_min = MCP_INTF, + .range_max = MCP_GPIO, +}; + +static const struct regmap_access_table mcp23x08_volatile_table = { + .yes_ranges = &mcp23x08_volatile_range, + .n_yes_ranges = 1, +}; + +static const struct regmap_range mcp23x08_precious_range = { + .range_min = MCP_GPIO, + .range_max = MCP_GPIO, +}; + +static const struct regmap_access_table mcp23x08_precious_table = { + .yes_ranges = &mcp23x08_precious_range, + .n_yes_ranges = 1, }; static const struct regmap_config mcp23x08_regmap = { @@ -84,18 +111,203 @@ static const struct regmap_config mcp23x08_regmap = { .val_bits = 8, .reg_stride = 1, + .volatile_table = &mcp23x08_volatile_table, + .precious_table = &mcp23x08_precious_table, + .reg_defaults = mcp23x08_defaults, + .num_reg_defaults = ARRAY_SIZE(mcp23x08_defaults), + .cache_type = REGCACHE_FLAT, .max_register = MCP_OLAT, }; +static const struct reg_default mcp23x16_defaults[] = { + {.reg = MCP_IODIR << 1, .def = 0xffff}, + {.reg = MCP_IPOL << 1, .def = 0x0000}, + {.reg = MCP_GPINTEN << 1, .def = 0x0000}, + {.reg = MCP_DEFVAL << 1, .def = 0x0000}, + {.reg = MCP_INTCON << 1, .def = 0x0000}, + {.reg = MCP_IOCON << 1, .def = 0x0000}, + {.reg = MCP_GPPU << 1, .def = 0x0000}, + {.reg = MCP_OLAT << 1, .def = 0x0000}, +}; + +static const struct regmap_range mcp23x16_volatile_range = { + .range_min = MCP_INTF << 1, + .range_max = MCP_GPIO << 1, +}; + +static const struct regmap_access_table mcp23x16_volatile_table = { + .yes_ranges = &mcp23x16_volatile_range, + .n_yes_ranges = 1, +}; + +static const struct regmap_range mcp23x16_precious_range = { + .range_min = MCP_GPIO << 1, + .range_max = MCP_GPIO << 1, +}; + +static const struct regmap_access_table mcp23x16_precious_table = { + .yes_ranges = &mcp23x16_precious_range, + .n_yes_ranges = 1, +}; + static const struct regmap_config mcp23x17_regmap = { .reg_bits = 8, .val_bits = 16, .reg_stride = 2, .max_register = MCP_OLAT << 1, + .volatile_table = &mcp23x16_volatile_table, + .precious_table = &mcp23x16_precious_table, + .reg_defaults = mcp23x16_defaults, + .num_reg_defaults = ARRAY_SIZE(mcp23x16_defaults), + .cache_type = REGCACHE_FLAT, .val_format_endian = REGMAP_ENDIAN_LITTLE, }; +static int mcp_read(struct mcp23s08 *mcp, unsigned int reg, unsigned int *val) +{ + return regmap_read(mcp->regmap, reg << mcp->reg_shift, val); +} + +static int mcp_write(struct mcp23s08 *mcp, unsigned int reg, unsigned int val) +{ + return regmap_write(mcp->regmap, reg << mcp->reg_shift, val); +} + +static int mcp_set_mask(struct mcp23s08 *mcp, unsigned int reg, + unsigned int mask, bool enabled) +{ + u16 val = enabled ? 0xffff : 0x0000; + return regmap_update_bits(mcp->regmap, reg << mcp->reg_shift, + mask, val); +} + +static int mcp_set_bit(struct mcp23s08 *mcp, unsigned int reg, + unsigned int pin, bool enabled) +{ + u16 mask = BIT(pin); + return mcp_set_mask(mcp, reg, mask, enabled); +} + +static const struct pinctrl_pin_desc mcp23x08_pins[] = { + PINCTRL_PIN(0, "gpio0"), + PINCTRL_PIN(1, "gpio1"), + PINCTRL_PIN(2, "gpio2"), + PINCTRL_PIN(3, "gpio3"), + PINCTRL_PIN(4, "gpio4"), + PINCTRL_PIN(5, "gpio5"), + PINCTRL_PIN(6, "gpio6"), + PINCTRL_PIN(7, "gpio7"), +}; + +static const struct pinctrl_pin_desc mcp23x17_pins[] = { + PINCTRL_PIN(0, "gpio0"), + PINCTRL_PIN(1, "gpio1"), + PINCTRL_PIN(2, "gpio2"), + PINCTRL_PIN(3, "gpio3"), + PINCTRL_PIN(4, "gpio4"), + PINCTRL_PIN(5, "gpio5"), + PINCTRL_PIN(6, "gpio6"), + PINCTRL_PIN(7, "gpio7"), + PINCTRL_PIN(8, "gpio8"), + PINCTRL_PIN(9, "gpio9"), + PINCTRL_PIN(10, "gpio10"), + PINCTRL_PIN(11, "gpio11"), + PINCTRL_PIN(12, "gpio12"), + PINCTRL_PIN(13, "gpio13"), + PINCTRL_PIN(14, "gpio14"), + PINCTRL_PIN(15, "gpio15"), +}; + +static int mcp_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) +{ + return 0; +} + +static const char *mcp_pinctrl_get_group_name(struct pinctrl_dev *pctldev, + unsigned int group) +{ + return NULL; +} + +static int mcp_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, + unsigned int group, + const unsigned int **pins, + unsigned int *num_pins) +{ + return -ENOTSUPP; +} + +static const struct pinctrl_ops mcp_pinctrl_ops = { + .get_groups_count = mcp_pinctrl_get_groups_count, + .get_group_name = mcp_pinctrl_get_group_name, + .get_group_pins = mcp_pinctrl_get_group_pins, +#ifdef CONFIG_OF + .dt_node_to_map = pinconf_generic_dt_node_to_map_pin, + .dt_free_map = pinconf_generic_dt_free_map, +#endif +}; + +static int mcp_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin, + unsigned long *config) +{ + struct mcp23s08 *mcp = pinctrl_dev_get_drvdata(pctldev); + enum pin_config_param param = pinconf_to_config_param(*config); + unsigned int data, status; + int ret; + + switch (param) { + case PIN_CONFIG_BIAS_PULL_UP: + ret = mcp_read(mcp, MCP_GPPU, &data); + if (ret < 0) + return ret; + status = (data & BIT(pin)) ? 1 : 0; + break; + default: + dev_err(mcp->dev, "Invalid config param %04x\n", param); + return -ENOTSUPP; + } + + *config = 0; + + return status ? 0 : -EINVAL; +} + +static int mcp_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, + unsigned long *configs, unsigned int num_configs) +{ + struct mcp23s08 *mcp = pinctrl_dev_get_drvdata(pctldev); + enum pin_config_param param; + u32 arg, mask; + u16 val; + int ret = 0; + int i; + + for (i = 0; i < num_configs; i++) { + param = pinconf_to_config_param(configs[i]); + arg = pinconf_to_config_argument(configs[i]); + + switch (param) { + case PIN_CONFIG_BIAS_PULL_UP: + val = arg ? 0xFFFF : 0x0000; + mask = BIT(pin); + ret = mcp_set_bit(mcp, MCP_GPPU, pin, arg); + break; + default: + dev_err(mcp->dev, "Invalid config param %04x\n", param); + return -ENOTSUPP; + } + } + + return ret; +} + +static const struct pinconf_ops mcp_pinconf_ops = { + .pin_config_get = mcp_pinconf_get, + .pin_config_set = mcp_pinconf_set, + .is_generic = true, +}; + /*----------------------------------------------------------------------*/ #ifdef CONFIG_SPI_MASTER @@ -158,30 +370,6 @@ static const struct regmap_bus mcp23sxx_spi_regmap = { #endif /* CONFIG_SPI_MASTER */ -static int mcp_read(struct mcp23s08 *mcp, unsigned int reg, unsigned int *val) -{ - return regmap_read(mcp->regmap, reg << mcp->reg_shift, val); -} - -static int mcp_write(struct mcp23s08 *mcp, unsigned int reg, unsigned int val) -{ - return regmap_write(mcp->regmap, reg << mcp->reg_shift, val); -} - -static int mcp_update_cache(struct mcp23s08 *mcp) -{ - int ret, reg, i; - - for (i = 0; i < ARRAY_SIZE(mcp->cache); i++) { - ret = mcp_read(mcp, i, ®); - if (ret < 0) - return ret; - mcp->cache[i] = reg; - } - - return 0; -} - /*----------------------------------------------------------------------*/ /* A given spi_device can represent up to eight mcp23sxx chips @@ -202,9 +390,9 @@ static int mcp23s08_direction_input(struct gpio_chip *chip, unsigned offset) int status; mutex_lock(&mcp->lock); - mcp->cache[MCP_IODIR] |= (1 << offset); - status = mcp_write(mcp, MCP_IODIR, mcp->cache[MCP_IODIR]); + status = mcp_set_bit(mcp, MCP_IODIR, offset, true); mutex_unlock(&mcp->lock); + return status; } @@ -219,33 +407,27 @@ static int mcp23s08_get(struct gpio_chip *chip, unsigned offset) ret = mcp_read(mcp, MCP_GPIO, &status); if (ret < 0) status = 0; - else { - mcp->cache[MCP_GPIO] = status; + else status = !!(status & (1 << offset)); - } + + mcp->cached_gpio = status; + mutex_unlock(&mcp->lock); return status; } -static int __mcp23s08_set(struct mcp23s08 *mcp, unsigned mask, int value) +static int __mcp23s08_set(struct mcp23s08 *mcp, unsigned mask, bool value) { - unsigned olat = mcp->cache[MCP_OLAT]; - - if (value) - olat |= mask; - else - olat &= ~mask; - mcp->cache[MCP_OLAT] = olat; - return mcp_write(mcp, MCP_OLAT, olat); + return mcp_set_mask(mcp, MCP_OLAT, mask, value); } static void mcp23s08_set(struct gpio_chip *chip, unsigned offset, int value) { struct mcp23s08 *mcp = gpiochip_get_data(chip); - unsigned mask = 1 << offset; + unsigned mask = BIT(offset); mutex_lock(&mcp->lock); - __mcp23s08_set(mcp, mask, value); + __mcp23s08_set(mcp, mask, !!value); mutex_unlock(&mcp->lock); } @@ -253,14 +435,13 @@ static int mcp23s08_direction_output(struct gpio_chip *chip, unsigned offset, int value) { struct mcp23s08 *mcp = gpiochip_get_data(chip); - unsigned mask = 1 << offset; + unsigned mask = BIT(offset); int status; mutex_lock(&mcp->lock); status = __mcp23s08_set(mcp, mask, value); if (status == 0) { - mcp->cache[MCP_IODIR] &= ~mask; - status = mcp_write(mcp, MCP_IODIR, mcp->cache[MCP_IODIR]); + status = mcp_set_mask(mcp, MCP_IODIR, mask, false); } mutex_unlock(&mcp->lock); return status; @@ -270,7 +451,7 @@ mcp23s08_direction_output(struct gpio_chip *chip, unsigned offset, int value) static irqreturn_t mcp23s08_irq(int irq, void *data) { struct mcp23s08 *mcp = data; - int intcap, intf, i, gpio, gpio_orig, intcap_mask; + int intcap, intcon, intf, i, gpio, gpio_orig, intcap_mask, defval; unsigned int child_irq; bool intf_set, intcap_changed, gpio_bit_changed, defval_changed, gpio_set; @@ -281,25 +462,31 @@ static irqreturn_t mcp23s08_irq(int irq, void *data) return IRQ_HANDLED; } - mcp->cache[MCP_INTF] = intf; - if (mcp_read(mcp, MCP_INTCAP, &intcap) < 0) { mutex_unlock(&mcp->lock); return IRQ_HANDLED; } - mcp->cache[MCP_INTCAP] = intcap; + if (mcp_read(mcp, MCP_INTCON, &intcon) < 0) { + mutex_unlock(&mcp->lock); + return IRQ_HANDLED; + } + + if (mcp_read(mcp, MCP_DEFVAL, &defval) < 0) { + mutex_unlock(&mcp->lock); + return IRQ_HANDLED; + } /* This clears the interrupt(configurable on S18) */ if (mcp_read(mcp, MCP_GPIO, &gpio) < 0) { mutex_unlock(&mcp->lock); return IRQ_HANDLED; } - gpio_orig = mcp->cache[MCP_GPIO]; - mcp->cache[MCP_GPIO] = gpio; + gpio_orig = mcp->cached_gpio; + mcp->cached_gpio = gpio; mutex_unlock(&mcp->lock); - if (mcp->cache[MCP_INTF] == 0) { + if (intf == 0) { /* There is no interrupt pending */ return IRQ_HANDLED; } @@ -327,7 +514,7 @@ static irqreturn_t mcp23s08_irq(int irq, void *data) * to see if the input has changed. */ - intf_set = BIT(i) & mcp->cache[MCP_INTF]; + intf_set = intf & BIT(i); if (i < 8 && intf_set) intcap_mask = 0x00FF; else if (i >= 8 && intf_set) @@ -336,14 +523,14 @@ static irqreturn_t mcp23s08_irq(int irq, void *data) intcap_mask = 0x00; intcap_changed = (intcap_mask & - (BIT(i) & mcp->cache[MCP_INTCAP])) != + (intcap & BIT(i))) != (intcap_mask & (BIT(i) & gpio_orig)); - gpio_set = BIT(i) & mcp->cache[MCP_GPIO]; + gpio_set = BIT(i) & gpio; gpio_bit_changed = (BIT(i) & gpio_orig) != - (BIT(i) & mcp->cache[MCP_GPIO]); - defval_changed = (BIT(i) & mcp->cache[MCP_INTCON]) && - ((BIT(i) & mcp->cache[MCP_GPIO]) != - (BIT(i) & mcp->cache[MCP_DEFVAL])); + (BIT(i) & gpio); + defval_changed = (BIT(i) & intcon) && + ((BIT(i) & gpio) != + (BIT(i) & defval)); if (((gpio_bit_changed || intcap_changed) && (BIT(i) & mcp->irq_rise) && gpio_set) || @@ -364,7 +551,7 @@ static void mcp23s08_irq_mask(struct irq_data *data) struct mcp23s08 *mcp = gpiochip_get_data(gc); unsigned int pos = data->hwirq; - mcp->cache[MCP_GPINTEN] &= ~BIT(pos); + mcp_set_bit(mcp, MCP_GPINTEN, pos, false); } static void mcp23s08_irq_unmask(struct irq_data *data) @@ -373,7 +560,7 @@ static void mcp23s08_irq_unmask(struct irq_data *data) struct mcp23s08 *mcp = gpiochip_get_data(gc); unsigned int pos = data->hwirq; - mcp->cache[MCP_GPINTEN] |= BIT(pos); + mcp_set_bit(mcp, MCP_GPINTEN, pos, true); } static int mcp23s08_irq_set_type(struct irq_data *data, unsigned int type) @@ -384,23 +571,23 @@ static int mcp23s08_irq_set_type(struct irq_data *data, unsigned int type) int status = 0; if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) { - mcp->cache[MCP_INTCON] &= ~BIT(pos); + mcp_set_bit(mcp, MCP_INTCON, pos, false); mcp->irq_rise |= BIT(pos); mcp->irq_fall |= BIT(pos); } else if (type & IRQ_TYPE_EDGE_RISING) { - mcp->cache[MCP_INTCON] &= ~BIT(pos); + mcp_set_bit(mcp, MCP_INTCON, pos, false); mcp->irq_rise |= BIT(pos); mcp->irq_fall &= ~BIT(pos); } else if (type & IRQ_TYPE_EDGE_FALLING) { - mcp->cache[MCP_INTCON] &= ~BIT(pos); + mcp_set_bit(mcp, MCP_INTCON, pos, false); mcp->irq_rise &= ~BIT(pos); mcp->irq_fall |= BIT(pos); } else if (type & IRQ_TYPE_LEVEL_HIGH) { - mcp->cache[MCP_INTCON] |= BIT(pos); - mcp->cache[MCP_DEFVAL] &= ~BIT(pos); + mcp_set_bit(mcp, MCP_INTCON, pos, true); + mcp_set_bit(mcp, MCP_DEFVAL, pos, false); } else if (type & IRQ_TYPE_LEVEL_LOW) { - mcp->cache[MCP_INTCON] |= BIT(pos); - mcp->cache[MCP_DEFVAL] |= BIT(pos); + mcp_set_bit(mcp, MCP_INTCON, pos, true); + mcp_set_bit(mcp, MCP_DEFVAL, pos, true); } else return -EINVAL; @@ -412,7 +599,8 @@ static void mcp23s08_irq_bus_lock(struct irq_data *data) struct gpio_chip *gc = irq_data_get_irq_chip_data(data); struct mcp23s08 *mcp = gpiochip_get_data(gc); - mutex_lock(&mcp->irq_lock); + mutex_lock(&mcp->lock); + regcache_cache_only(mcp->regmap, true); } static void mcp23s08_irq_bus_unlock(struct irq_data *data) @@ -420,12 +608,10 @@ static void mcp23s08_irq_bus_unlock(struct irq_data *data) struct gpio_chip *gc = irq_data_get_irq_chip_data(data); struct mcp23s08 *mcp = gpiochip_get_data(gc); - mutex_lock(&mcp->lock); - mcp_write(mcp, MCP_GPINTEN, mcp->cache[MCP_GPINTEN]); - mcp_write(mcp, MCP_DEFVAL, mcp->cache[MCP_DEFVAL]); - mcp_write(mcp, MCP_INTCON, mcp->cache[MCP_INTCON]); + regcache_cache_only(mcp->regmap, false); + regcache_sync(mcp->regmap); + mutex_unlock(&mcp->lock); - mutex_unlock(&mcp->irq_lock); } static struct irq_chip mcp23s08_irq_chip = { @@ -443,8 +629,6 @@ static int mcp23s08_irq_setup(struct mcp23s08 *mcp) int err; unsigned long irqflags = IRQF_ONESHOT | IRQF_SHARED; - mutex_init(&mcp->irq_lock); - if (mcp->irq_active_high) irqflags |= IRQF_TRIGGER_HIGH; else @@ -484,6 +668,47 @@ static int mcp23s08_irq_setup(struct mcp23s08 *mcp) #include <linux/seq_file.h> /* + * This compares the chip's registers with the register + * cache and corrects any incorrectly set register. This + * can be used to fix state for MCP23xxx, that temporary + * lost its power supply. + */ +#define MCP23S08_CONFIG_REGS 8 +static int __check_mcp23s08_reg_cache(struct mcp23s08 *mcp) +{ + int cached[MCP23S08_CONFIG_REGS]; + int err = 0, i; + + /* read cached config registers */ + for (i = 0; i < MCP23S08_CONFIG_REGS; i++) { + err = mcp_read(mcp, i, &cached[i]); + if (err) + goto out; + } + + regcache_cache_bypass(mcp->regmap, true); + + for (i = 0; i < MCP23S08_CONFIG_REGS; i++) { + int uncached; + err = mcp_read(mcp, i, &uncached); + if (err) + goto out; + + if (uncached != cached[i]) { + dev_err(mcp->dev, "restoring reg 0x%02x from 0x%04x to 0x%04x (power-loss?)\n", + i, uncached, cached[i]); + mcp_write(mcp, i, cached[i]); + } + } + +out: + if (err) + dev_err(mcp->dev, "read error: reg=%02x, err=%d", i, err); + regcache_cache_bypass(mcp->regmap, false); + return err; +} + +/* * This shows more info than the generic gpio dump code: * pullups, deglitching, open drain drive. */ @@ -493,6 +718,7 @@ static void mcp23s08_dbg_show(struct seq_file *s, struct gpio_chip *chip) char bank; int t; unsigned mask; + int iodir, gpio, gppu; mcp = gpiochip_get_data(chip); @@ -500,14 +726,30 @@ static void mcp23s08_dbg_show(struct seq_file *s, struct gpio_chip *chip) bank = '0' + ((mcp->addr >> 1) & 0x7); mutex_lock(&mcp->lock); - t = mcp_update_cache(mcp); - if (t < 0) { - seq_printf(s, " I/O ERROR %d\n", t); + + t = __check_mcp23s08_reg_cache(mcp); + if (t) { + seq_printf(s, " I/O Error\n"); + goto done; + } + t = mcp_read(mcp, MCP_IODIR, &iodir); + if (t) { + seq_printf(s, " I/O Error\n"); + goto done; + } + t = mcp_read(mcp, MCP_GPIO, &gpio); + if (t) { + seq_printf(s, " I/O Error\n"); + goto done; + } + t = mcp_read(mcp, MCP_GPPU, &gppu); + if (t) { + seq_printf(s, " I/O Error\n"); goto done; } - for (t = 0, mask = 1; t < chip->ngpio; t++, mask <<= 1) { - const char *label; + for (t = 0, mask = BIT(0); t < chip->ngpio; t++, mask <<= 1) { + const char *label; label = gpiochip_is_requested(chip, t); if (!label) @@ -515,9 +757,9 @@ static void mcp23s08_dbg_show(struct seq_file *s, struct gpio_chip *chip) seq_printf(s, " gpio-%-3d P%c.%d (%-12s) %s %s %s", chip->base + t, bank, t, label, - (mcp->cache[MCP_IODIR] & mask) ? "in " : "out", - (mcp->cache[MCP_GPIO] & mask) ? "hi" : "lo", - (mcp->cache[MCP_GPPU] & mask) ? "up" : " "); + (iodir & mask) ? "in " : "out", + (gpio & mask) ? "hi" : "lo", + (gppu & mask) ? "up" : " "); /* NOTE: ignoring the irq-related registers */ seq_puts(s, "\n"); } @@ -533,7 +775,7 @@ done: static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, void *data, unsigned addr, unsigned type, - struct mcp23s08_platform_data *pdata, int cs) + unsigned int base, int cs) { int status, ret; bool mirror = false; @@ -605,7 +847,7 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, if (IS_ERR(mcp->regmap)) return PTR_ERR(mcp->regmap); - mcp->chip.base = pdata->base; + mcp->chip.base = base; mcp->chip.can_sleep = true; mcp->chip.parent = dev; mcp->chip.owner = THIS_MODULE; @@ -618,13 +860,14 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, if (ret < 0) goto fail; - mcp->irq_controller = pdata->irq_controller; + mcp->irq_controller = + device_property_read_bool(dev, "interrupt-controller"); if (mcp->irq && mcp->irq_controller) { mcp->irq_active_high = - of_property_read_bool(mcp->chip.parent->of_node, + device_property_read_bool(dev, "microchip,irq-active-high"); - mirror = pdata->mirror; + mirror = device_property_read_bool(dev, "microchip,irq-mirror"); } if ((status & IOCON_SEQOP) || !(status & IOCON_HAEN) || mirror || @@ -648,32 +891,7 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, goto fail; } - /* configure ~100K pullups */ - ret = mcp_write(mcp, MCP_GPPU, pdata->chip[cs].pullups); - if (ret < 0) - goto fail; - - ret = mcp_update_cache(mcp); - if (ret < 0) - goto fail; - - /* disable inverter on input */ - if (mcp->cache[MCP_IPOL] != 0) { - mcp->cache[MCP_IPOL] = 0; - ret = mcp_write(mcp, MCP_IPOL, 0); - if (ret < 0) - goto fail; - } - - /* disable irqs */ - if (mcp->cache[MCP_GPINTEN] != 0) { - mcp->cache[MCP_GPINTEN] = 0; - ret = mcp_write(mcp, MCP_GPINTEN, 0); - if (ret < 0) - goto fail; - } - - ret = gpiochip_add_data(&mcp->chip, mcp); + ret = devm_gpiochip_add_data(dev, &mcp->chip, mcp); if (ret < 0) goto fail; @@ -682,6 +900,23 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, if (ret) goto fail; } + + mcp->pinctrl_desc.name = "mcp23xxx-pinctrl"; + mcp->pinctrl_desc.pctlops = &mcp_pinctrl_ops; + mcp->pinctrl_desc.confops = &mcp_pinconf_ops; + mcp->pinctrl_desc.npins = mcp->chip.ngpio; + if (mcp->pinctrl_desc.npins == 8) + mcp->pinctrl_desc.pins = mcp23x08_pins; + else if (mcp->pinctrl_desc.npins == 16) + mcp->pinctrl_desc.pins = mcp23x17_pins; + mcp->pinctrl_desc.owner = THIS_MODULE; + + mcp->pctldev = devm_pinctrl_register(dev, &mcp->pinctrl_desc, mcp); + if (IS_ERR(mcp->pctldev)) { + ret = PTR_ERR(mcp->pctldev); + goto fail; + } + fail: if (ret < 0) dev_dbg(dev, "can't setup chip %d, --> %d\n", addr, ret); @@ -753,60 +988,26 @@ static int mcp230xx_probe(struct i2c_client *client, struct mcp23s08_platform_data *pdata, local_pdata; struct mcp23s08 *mcp; int status; - const struct of_device_id *match; - match = of_match_device(of_match_ptr(mcp23s08_i2c_of_match), - &client->dev); - if (match) { + pdata = dev_get_platdata(&client->dev); + if (!pdata) { pdata = &local_pdata; pdata->base = -1; - pdata->chip[0].pullups = 0; - pdata->irq_controller = of_property_read_bool( - client->dev.of_node, - "interrupt-controller"); - pdata->mirror = of_property_read_bool(client->dev.of_node, - "microchip,irq-mirror"); - client->irq = irq_of_parse_and_map(client->dev.of_node, 0); - } else { - pdata = dev_get_platdata(&client->dev); - if (!pdata) { - pdata = devm_kzalloc(&client->dev, - sizeof(struct mcp23s08_platform_data), - GFP_KERNEL); - if (!pdata) - return -ENOMEM; - pdata->base = -1; - } } - mcp = kzalloc(sizeof(*mcp), GFP_KERNEL); + mcp = devm_kzalloc(&client->dev, sizeof(*mcp), GFP_KERNEL); if (!mcp) return -ENOMEM; mcp->irq = client->irq; status = mcp23s08_probe_one(mcp, &client->dev, client, client->addr, - id->driver_data, pdata, 0); + id->driver_data, pdata->base, 0); if (status) - goto fail; + return status; i2c_set_clientdata(client, mcp); return 0; - -fail: - kfree(mcp); - - return status; -} - -static int mcp230xx_remove(struct i2c_client *client) -{ - struct mcp23s08 *mcp = i2c_get_clientdata(client); - - gpiochip_remove(&mcp->chip); - kfree(mcp); - - return 0; } static const struct i2c_device_id mcp230xx_id[] = { @@ -822,7 +1023,6 @@ static struct i2c_driver mcp230xx_driver = { .of_match_table = of_match_ptr(mcp23s08_i2c_of_match), }, .probe = mcp230xx_probe, - .remove = mcp230xx_remove, .id_table = mcp230xx_id, }; @@ -856,60 +1056,40 @@ static int mcp23s08_probe(struct spi_device *spi) int status, type; unsigned ngpio = 0; const struct of_device_id *match; - u32 spi_present_mask = 0; match = of_match_device(of_match_ptr(mcp23s08_spi_of_match), &spi->dev); - if (match) { + if (match) type = (int)(uintptr_t)match->data; - status = of_property_read_u32(spi->dev.of_node, - "microchip,spi-present-mask", &spi_present_mask); + else + type = spi_get_device_id(spi)->driver_data; + + pdata = dev_get_platdata(&spi->dev); + if (!pdata) { + pdata = &local_pdata; + pdata->base = -1; + + status = device_property_read_u32(&spi->dev, + "microchip,spi-present-mask", &pdata->spi_present_mask); if (status) { - status = of_property_read_u32(spi->dev.of_node, - "mcp,spi-present-mask", &spi_present_mask); + status = device_property_read_u32(&spi->dev, + "mcp,spi-present-mask", + &pdata->spi_present_mask); + if (status) { - dev_err(&spi->dev, - "DT has no spi-present-mask\n"); + dev_err(&spi->dev, "missing spi-present-mask"); return -ENODEV; } } - if ((spi_present_mask <= 0) || (spi_present_mask >= 256)) { - dev_err(&spi->dev, "invalid spi-present-mask\n"); - return -ENODEV; - } + } - pdata = &local_pdata; - pdata->base = -1; - for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) { - pdata->chip[addr].pullups = 0; - if (spi_present_mask & (1 << addr)) - chips++; - } - pdata->irq_controller = of_property_read_bool( - spi->dev.of_node, - "interrupt-controller"); - pdata->mirror = of_property_read_bool(spi->dev.of_node, - "microchip,irq-mirror"); - } else { - type = spi_get_device_id(spi)->driver_data; - pdata = dev_get_platdata(&spi->dev); - if (!pdata) { - pdata = devm_kzalloc(&spi->dev, - sizeof(struct mcp23s08_platform_data), - GFP_KERNEL); - pdata->base = -1; - } + if (!pdata->spi_present_mask || pdata->spi_present_mask > 0xff) { + dev_err(&spi->dev, "invalid spi-present-mask"); + return -ENODEV; + } - for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) { - if (!pdata->chip[addr].is_present) - continue; + for (addr = 0; addr < MCP_MAX_DEV_PER_CS; addr++) { + if (pdata->spi_present_mask & BIT(addr)) chips++; - if ((type == MCP_TYPE_S08) && (addr > 3)) { - dev_err(&spi->dev, - "mcp23s08 only supports address 0..3\n"); - return -EINVAL; - } - spi_present_mask |= 1 << addr; - } } if (!chips) @@ -923,19 +1103,17 @@ static int mcp23s08_probe(struct spi_device *spi) spi_set_drvdata(spi, data); - spi->irq = irq_of_parse_and_map(spi->dev.of_node, 0); - - for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) { - if (!(spi_present_mask & (1 << addr))) + for (addr = 0; addr < MCP_MAX_DEV_PER_CS; addr++) { + if (!(pdata->spi_present_mask & BIT(addr))) continue; chips--; data->mcp[addr] = &data->chip[chips]; data->mcp[addr]->irq = spi->irq; status = mcp23s08_probe_one(data->mcp[addr], &spi->dev, spi, - 0x40 | (addr << 1), type, pdata, - addr); + 0x40 | (addr << 1), type, + pdata->base, addr); if (status < 0) - goto fail; + return status; if (pdata->base != -1) pdata->base += data->mcp[addr]->chip.ngpio; @@ -943,36 +1121,6 @@ static int mcp23s08_probe(struct spi_device *spi) } data->ngpio = ngpio; - /* NOTE: these chips have a relatively sane IRQ framework, with - * per-signal masking and level/edge triggering. It's not yet - * handled here... - */ - - return 0; - -fail: - for (addr = 0; addr < ARRAY_SIZE(data->mcp); addr++) { - - if (!data->mcp[addr]) - continue; - gpiochip_remove(&data->mcp[addr]->chip); - } - return status; -} - -static int mcp23s08_remove(struct spi_device *spi) -{ - struct mcp23s08_driver_data *data = spi_get_drvdata(spi); - unsigned addr; - - for (addr = 0; addr < ARRAY_SIZE(data->mcp); addr++) { - - if (!data->mcp[addr]) - continue; - - gpiochip_remove(&data->mcp[addr]->chip); - } - return 0; } @@ -986,7 +1134,6 @@ MODULE_DEVICE_TABLE(spi, mcp23s08_ids); static struct spi_driver mcp23s08_driver = { .probe = mcp23s08_probe, - .remove = mcp23s08_remove, .id_table = mcp23s08_ids, .driver = { .name = "mcp23s08", diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c index 4b717c699313..43d8ed577e70 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c @@ -15,10 +15,6 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <linux/kernel.h> #include <linux/acpi.h> @@ -149,8 +145,8 @@ static int vendor_resource_matches(struct pnp_dev *dev, uuid_len == sizeof(match->data) && memcmp(uuid, match->data, uuid_len) == 0) { if (expected_len && expected_len != actual_len) { - dev_err(&dev->dev, "wrong vendor descriptor size; " - "expected %d, found %d bytes\n", + dev_err(&dev->dev, + "wrong vendor descriptor size; expected %d, found %d bytes\n", expected_len, actual_len); return 0; } @@ -180,6 +176,7 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, struct pnp_dev *dev = data; struct acpi_resource_dma *dma; struct acpi_resource_vendor_typed *vendor_typed; + struct acpi_resource_gpio *gpio; struct resource_win win = {{0}, 0}; struct resource *r = &win.res; int i, flags; @@ -203,13 +200,27 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, * one interrupt, we won't be able to re-encode it. */ if (pnp_can_write(dev)) { - dev_warn(&dev->dev, "multiple interrupts in " - "_CRS descriptor; configuration can't " - "be changed\n"); + dev_warn(&dev->dev, + "multiple interrupts in _CRS descriptor; configuration can't be changed\n"); dev->capabilities &= ~PNP_WRITE; } } return AE_OK; + } else if (acpi_gpio_get_irq_resource(res, &gpio)) { + /* + * If the resource is GpioInt() type then extract the IRQ + * from GPIO resource and fill it into IRQ resource type. + */ + i = acpi_dev_gpio_irq_get(dev->data, 0); + if (i >= 0) { + flags = acpi_dev_irq_flags(gpio->triggering, + gpio->polarity, + gpio->sharable); + } else { + flags = IORESOURCE_DISABLED; + } + pnp_add_irq_resource(dev, i, flags); + return AE_OK; } else if (r->flags & IORESOURCE_DISABLED) { pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED); return AE_OK; @@ -331,8 +342,8 @@ static __init void pnpacpi_parse_ext_irq_option(struct pnp_dev *dev, if (p->interrupts[i] < PNP_IRQ_NR) __set_bit(p->interrupts[i], map.bits); else - dev_err(&dev->dev, "ignoring IRQ %d option " - "(too large for %d entry bitmap)\n", + dev_err(&dev->dev, + "ignoring IRQ %d option (too large for %d entry bitmap)\n", p->interrupts[i], PNP_IRQ_NR); } } @@ -933,8 +944,9 @@ int pnpacpi_encode_resources(struct pnp_dev *dev, struct acpi_buffer *buffer) case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: case ACPI_RESOURCE_TYPE_GENERIC_REGISTER: default: /* other type */ - dev_warn(&dev->dev, "can't encode unknown resource " - "type %d\n", resource->type); + dev_warn(&dev->dev, + "can't encode unknown resource type %d\n", + resource->type); return -EINVAL; } resource++; diff --git a/include/dt-bindings/gpio/gpio.h b/include/dt-bindings/gpio/gpio.h index b4f54da694eb..c5074584561d 100644 --- a/include/dt-bindings/gpio/gpio.h +++ b/include/dt-bindings/gpio/gpio.h @@ -28,4 +28,8 @@ #define GPIO_OPEN_DRAIN (GPIO_SINGLE_ENDED | GPIO_LINE_OPEN_DRAIN) #define GPIO_OPEN_SOURCE (GPIO_SINGLE_ENDED | GPIO_LINE_OPEN_SOURCE) +/* Bit 3 express GPIO suspend/resume persistence */ +#define GPIO_SLEEP_MAINTAIN_VALUE 0 +#define GPIO_SLEEP_MAY_LOOSE_VALUE 8 + #endif diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 137e4a3d89c5..d5aa3c42f64d 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -964,6 +964,8 @@ int devm_acpi_dev_add_driver_gpios(struct device *dev, const struct acpi_gpio_mapping *gpios); void devm_acpi_dev_remove_driver_gpios(struct device *dev); +bool acpi_gpio_get_irq_resource(struct acpi_resource *ares, + struct acpi_resource_gpio **agpio); int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index); #else static inline int acpi_dev_add_driver_gpios(struct acpi_device *adev, @@ -980,6 +982,11 @@ static inline int devm_acpi_dev_add_driver_gpios(struct device *dev, } static inline void devm_acpi_dev_remove_driver_gpios(struct device *dev) {} +static inline bool acpi_gpio_get_irq_resource(struct acpi_resource *ares, + struct acpi_resource_gpio **agpio) +{ + return false; +} static inline int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index) { return -ENXIO; diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 393582867afd..af20369ec8e7 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -213,6 +213,9 @@ bool gpiochip_line_is_irq(struct gpio_chip *chip, unsigned int offset); bool gpiochip_line_is_open_drain(struct gpio_chip *chip, unsigned int offset); bool gpiochip_line_is_open_source(struct gpio_chip *chip, unsigned int offset); +/* Sleep persistence inquiry for drivers */ +bool gpiochip_line_is_persistent(struct gpio_chip *chip, unsigned int offset); + /* get driver data */ void *gpiochip_get_data(struct gpio_chip *chip); diff --git a/include/linux/gpio/machine.h b/include/linux/gpio/machine.h index f738d50cc17d..6e76b16fcade 100644 --- a/include/linux/gpio/machine.h +++ b/include/linux/gpio/machine.h @@ -9,6 +9,8 @@ enum gpio_lookup_flags { GPIO_ACTIVE_LOW = (1 << 0), GPIO_OPEN_DRAIN = (1 << 1), GPIO_OPEN_SOURCE = (1 << 2), + GPIO_SLEEP_MAINTAIN_VALUE = (0 << 3), + GPIO_SLEEP_MAY_LOOSE_VALUE = (1 << 3), }; /** diff --git a/include/linux/of_gpio.h b/include/linux/of_gpio.h index 1e089d5a182b..ca10f43564de 100644 --- a/include/linux/of_gpio.h +++ b/include/linux/of_gpio.h @@ -31,6 +31,7 @@ enum of_gpio_flags { OF_GPIO_ACTIVE_LOW = 0x1, OF_GPIO_SINGLE_ENDED = 0x2, OF_GPIO_OPEN_DRAIN = 0x4, + OF_GPIO_SLEEP_MAY_LOOSE_VALUE = 0x8, }; #ifdef CONFIG_OF_GPIO diff --git a/include/linux/i2c/adp5588.h b/include/linux/platform_data/adp5588.h index c2153049cfbd..c2153049cfbd 100644 --- a/include/linux/i2c/adp5588.h +++ b/include/linux/platform_data/adp5588.h diff --git a/include/linux/i2c/max732x.h b/include/linux/platform_data/max732x.h index c04bac8bf2fe..c04bac8bf2fe 100644 --- a/include/linux/i2c/max732x.h +++ b/include/linux/platform_data/max732x.h diff --git a/include/linux/i2c/pcf857x.h b/include/linux/platform_data/pcf857x.h index 0767a2a6b2f1..0767a2a6b2f1 100644 --- a/include/linux/i2c/pcf857x.h +++ b/include/linux/platform_data/pcf857x.h diff --git a/include/linux/spi/mcp23s08.h b/include/linux/spi/mcp23s08.h index aa07d7b32568..82d96a346e6f 100644 --- a/include/linux/spi/mcp23s08.h +++ b/include/linux/spi/mcp23s08.h @@ -1,11 +1,3 @@ - -/* FIXME driver should be able to handle IRQs... */ - -struct mcp23s08_chip_info { - bool is_present; /* true if populated */ - unsigned pullups; /* BIT(x) means enable pullup x */ -}; - struct mcp23s08_platform_data { /* For mcp23s08, up to 4 slaves (numbered 0..3) can share one SPI * chipselect, each providing 1 gpio_chip instance with 8 gpios. @@ -13,31 +5,13 @@ struct mcp23s08_platform_data { * chipselect, each providing 1 gpio_chip (port A + port B) with * 16 gpios. */ - struct mcp23s08_chip_info chip[8]; + u32 spi_present_mask; - /* "base" is the number of the first GPIO. Dynamic assignment is - * not currently supported, and even if there are gaps in chip - * addressing the GPIO numbers are sequential .. so for example - * if only slaves 0 and 3 are present, their GPIOs range from - * base to base+15 (or base+31 for s17 variant). + /* "base" is the number of the first GPIO or -1 for dynamic + * assignment. If there are gaps in chip addressing the GPIO + * numbers are sequential .. so for example if only slaves 0 + * and 3 are present, their GPIOs range from base to base+15 + * (or base+31 for s17 variant). */ unsigned base; - /* Marks the device as a interrupt controller. - * NOTE: The interrupt functionality is only supported for i2c - * versions of the chips. The spi chips can also do the interrupts, - * but this is not supported by the linux driver yet. - */ - bool irq_controller; - - /* Sets the mirror flag in the IOCON register. Devices - * with two interrupt outputs (these are the devices ending with 17 and - * those that have 16 IOs) have two IO banks: IO 0-7 form bank 1 and - * IO 8-15 are bank 2. These chips have two different interrupt outputs: - * One for bank 1 and another for bank 2. If irq-mirror is set, both - * interrupts are generated regardless of the bank that an input change - * occurred on. If it is not set, the interrupt are only generated for - * the bank they belong to. - * On devices with only one interrupt output this property is useless. - */ - bool mirror; }; |