diff options
Diffstat (limited to 'drivers/gpio')
88 files changed, 4543 insertions, 1665 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 0f0444475bf..4a1b5113e52 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -55,6 +55,10 @@ config GPIO_ACPI def_bool y depends on ACPI +config GPIOLIB_IRQCHIP + select IRQ_DOMAIN + bool + config DEBUG_GPIO bool "Debug GPIO calls" depends on DEBUG_KERNEL @@ -110,17 +114,33 @@ comment "Memory mapped GPIO drivers:" config GPIO_CLPS711X tristate "CLPS711X GPIO support" - depends on ARCH_CLPS711X + depends on ARCH_CLPS711X || COMPILE_TEST select GPIO_GENERIC help Say yes here to support GPIO on CLPS711X SoCs. +config GPIO_DAVINCI + bool "TI Davinci/Keystone GPIO support" + default y if ARCH_DAVINCI + depends on ARM && (ARCH_DAVINCI || ARCH_KEYSTONE) + help + Say yes here to enable GPIO support for TI Davinci/Keystone SoCs. + config GPIO_GENERIC_PLATFORM tristate "Generic memory-mapped GPIO controller support (MMIO platform device)" select GPIO_GENERIC help Say yes here to support basic platform_device memory-mapped GPIO controllers. +config GPIO_DWAPB + tristate "Synopsys DesignWare APB GPIO driver" + select GPIO_GENERIC + select GENERIC_IRQ_CHIP + depends on OF_GPIO + help + Say Y or M here to build support for the Synopsys DesignWare APB + GPIO block. + config GPIO_IT8761E tristate "IT8761E GPIO support" depends on X86 # unconditional access to IO space. @@ -138,6 +158,12 @@ config GPIO_EP93XX depends on ARCH_EP93XX select GPIO_GENERIC +config GPIO_ZEVIO + bool "LSI ZEVIO SoC memory mapped GPIOs" + depends on ARM && OF_GPIO + help + Say yes here to support the GPIO controller in LSI ZEVIO SoCs. + config GPIO_MM_LANTIQ bool "Lantiq Memory mapped GPIOs" depends on LANTIQ && SOC_XWAY @@ -156,6 +182,13 @@ config GPIO_F7188X To compile this driver as a module, choose M here: the module will be called f7188x-gpio. +config GPIO_MOXART + bool "MOXART GPIO support" + depends on ARCH_MOXART + help + Select this option to enable GPIO driver for + MOXA ART SoC devices. + config GPIO_MPC5200 def_bool y depends on PPC_MPC52xx @@ -178,7 +211,7 @@ config GPIO_MSM_V1 config GPIO_MSM_V2 tristate "Qualcomm MSM GPIO v2" - depends on GPIOLIB && OF && ARCH_MSM + depends on GPIOLIB && OF && ARCH_QCOM help Say yes here to support the GPIO interface on ARM v7 based Qualcomm MSM chips. Most of the pins on the MSM can be @@ -211,10 +244,20 @@ config GPIO_OCTEON Say yes here to support the on-chip GPIO lines on the OCTEON family of SOCs. +config GPIO_OMAP + bool "TI OMAP GPIO support" if COMPILE_TEST && !ARCH_OMAP2PLUS + default y if ARCH_OMAP + depends on ARM + select GENERIC_IRQ_CHIP + select GPIOLIB_IRQCHIP + help + Say yes here to enable GPIO support for TI OMAP SoCs. + config GPIO_PL061 bool "PrimeCell PL061 GPIO support" depends on ARM_AMBA - select GENERIC_IRQ_CHIP + select IRQ_DOMAIN + select GPIOLIB_IRQCHIP help Say yes here to support the PrimeCell PL061 GPIO device @@ -226,7 +269,7 @@ config GPIO_PXA config GPIO_RCAR tristate "Renesas R-Car GPIO" - depends on ARM + depends on ARM && (ARCH_SHMOBILE || COMPILE_TEST) help Say yes here to support GPIO on Renesas R-Car SoCs. @@ -237,6 +280,15 @@ config GPIO_SAMSUNG Legacy GPIO support. Use only for platforms without support for pinctrl. +config GPIO_SCH311X + tristate "SMSC SCH311x SuperI/O GPIO" + help + Driver to enable the GPIOs found on SMSC SMSC SCH3112, SCH3114 and + SCH3116 "Super I/O" chipsets. + + To compile this driver as a module, choose M here: the module will + be called gpio-sch311x. + config GPIO_SPEAR_SPICS bool "ST SPEAr13xx SPI Chip Select as GPIO support" depends on PLAT_SPEAR @@ -252,8 +304,15 @@ config GPIO_STA2X11 Say yes here to support the STA2x11/ConneXt GPIO device. The GPIO module has 128 GPIO pins with alternate functions. +config GPIO_SYSCON + tristate "GPIO based on SYSCON" + depends on MFD_SYSCON && OF + help + Say yes here to support GPIO functionality though SYSCON driver. + config GPIO_TS5500 tristate "TS-5500 DIO blocks and compatibles" + depends on TS5500 || COMPILE_TEST help This driver supports Digital I/O exposed by pin blocks found on some Technologic Systems platforms. It includes, but is not limited to, 3 @@ -281,6 +340,15 @@ config GPIO_XILINX help Say yes here to support the Xilinx FPGA GPIO device +config GPIO_XTENSA + bool "Xtensa GPIO32 support" + depends on XTENSA + depends on HAVE_XTENSA_GPIO32 + depends on !SMP + help + Say yes here to support the Xtensa internal GPIO32 IMPWIRE (input) + and EXPSTATE (output) ports + config GPIO_VR41XX tristate "NEC VR4100 series General-purpose I/O Uint support" depends on CPU_VR41XX @@ -353,7 +421,7 @@ config GPIO_GE_FPGA board computers. config GPIO_LYNXPOINT - bool "Intel Lynxpoint GPIO support" + tristate "Intel Lynxpoint GPIO support" depends on ACPI && X86 select IRQ_DOMAIN help @@ -371,6 +439,7 @@ config GPIO_GRGPIO config GPIO_TB10X bool + select GENERIC_IRQ_CHIP select OF_GPIO comment "I2C GPIO expanders:" @@ -381,6 +450,14 @@ config GPIO_ARIZONA help Support for GPIOs on Wolfson Arizona class devices. +config GPIO_LP3943 + tristate "TI/National Semiconductor LP3943 GPIO expander" + depends on MFD_LP3943 + help + GPIO driver for LP3943 MFD. + LP3943 can be used as a GPIO expander which provides up to 16 GPIOs. + Open drain outputs are required for this usage. + config GPIO_MAX7300 tristate "Maxim MAX7300 GPIO expander" depends on I2C @@ -421,7 +498,7 @@ config GPIO_MC9S08DZ60 Select this to enable the MC9S08DZ60 GPIO driver config GPIO_PCA953X - tristate "PCA953x, PCA955x, PCA957x, TCA64xx, and MAX7310 I/O ports" + tristate "PCA95[357]x, PCA9698, TCA64xx, and MAX7310 I/O ports" depends on I2C help Say yes here to provide access to several register-oriented @@ -431,14 +508,19 @@ config GPIO_PCA953X 4 bits: pca9536, pca9537 8 bits: max7310, max7315, pca6107, pca9534, pca9538, pca9554, - pca9556, pca9557, pca9574, tca6408 + pca9556, pca9557, pca9574, tca6408, xra1202 16 bits: max7312, max7313, pca9535, pca9539, pca9555, pca9575, tca6416 + 24 bits: tca6424 + + 40 bits: pca9505, pca9698 + config GPIO_PCA953X_IRQ bool "Interrupt controller support for PCA953x" depends on GPIO_PCA953X=y + select GPIOLIB_IRQCHIP help Say yes here to enable the pca953x to be used as an interrupt controller. It requires the driver to be built in the kernel. @@ -508,6 +590,7 @@ config GPIO_STP_XWAY config GPIO_TC3589X bool "TC3589X GPIOs" depends on MFD_TC3589X + select GPIOLIB_IRQCHIP help This enables support for the GPIOs found on the TC3589X I/O Expander. @@ -589,7 +672,7 @@ comment "PCI GPIO expanders:" config GPIO_CS5535 tristate "AMD CS5535/CS5536 GPIO support" - depends on PCI && X86 && MFD_CS5535 + depends on MFD_CS5535 help The AMD CS5535 and CS5536 southbridges support 28 GPIO pins that can be used for quite a number of things. The CS5535/6 is found on @@ -601,7 +684,7 @@ config GPIO_BT8XX tristate "BT8XX GPIO abuser" depends on PCI && VIDEO_BT848=n help - The BT8xx frame grabber chip has 24 GPIO pins than can be abused + The BT8xx frame grabber chip has 24 GPIO pins that can be abused as a cheap PCI GPIO card. This chip can be found on Miro, Hauppauge and STB TV-cards. @@ -628,13 +711,13 @@ config GPIO_AMD8111 config GPIO_INTEL_MID bool "Intel Mid GPIO support" depends on PCI && X86 - select IRQ_DOMAIN + select GPIOLIB_IRQCHIP help Say Y here to support Intel Mid GPIO. config GPIO_PCH tristate "Intel EG20T PCH/LAPIS Semiconductor IOH(ML7223/ML7831) GPIO" - depends on PCI && X86 + depends on PCI && (X86_32 || COMPILE_TEST) select GENERIC_IRQ_CHIP help This driver is for PCH(Platform controller Hub) GPIO of Intel Topcliff @@ -668,7 +751,7 @@ config GPIO_SODAVILLE config GPIO_TIMBERDALE bool "Support for timberdale GPIO IP" - depends on MFD_TIMBERDALE && HAS_IOMEM + depends on MFD_TIMBERDALE ---help--- Add support for the GPIO IP in the timberdale FPGA. @@ -692,11 +775,13 @@ config GPIO_MAX7301 config GPIO_MCP23S08 tristate "Microchip MCP23xxx I/O expander" + depends on OF_GPIO depends on (SPI_MASTER && !I2C) || I2C 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 GPIO_MC33880 tristate "Freescale MC33880 high-side/low-side switch" @@ -707,10 +792,10 @@ config GPIO_MC33880 config GPIO_74X164 tristate "74x164 serial-in/parallel-out 8-bits shift register" - depends on SPI_MASTER + depends on SPI_MASTER && OF help - Platform driver for 74x164 compatible serial-in/parallel-out - 8-outputs shift registers. This driver can be used to provide access + Driver for 74x164 compatible serial-in/parallel-out 8-outputs + shift registers. This driver can be used to provide access to more gpio outputs. comment "AC97 GPIO expanders:" diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 7971e36b8b1..d10f6a9d875 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -22,7 +22,8 @@ obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o obj-$(CONFIG_GPIO_DA9055) += gpio-da9055.o -obj-$(CONFIG_ARCH_DAVINCI) += gpio-davinci.o +obj-$(CONFIG_GPIO_DAVINCI) += gpio-davinci.o +obj-$(CONFIG_GPIO_DWAPB) += gpio-dwapb.o obj-$(CONFIG_GPIO_EM) += gpio-em.o obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o @@ -35,6 +36,7 @@ obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o obj-$(CONFIG_GPIO_KEMPLD) += gpio-kempld.o obj-$(CONFIG_ARCH_KS8695) += gpio-ks8695.o obj-$(CONFIG_GPIO_INTEL_MID) += gpio-intel-mid.o +obj-$(CONFIG_GPIO_LP3943) += gpio-lp3943.o obj-$(CONFIG_ARCH_LPC32XX) += gpio-lpc32xx.o obj-$(CONFIG_GPIO_LYNXPOINT) += gpio-lynxpoint.o obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o @@ -46,6 +48,7 @@ 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_MOXART) += gpio-moxart.o obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o obj-$(CONFIG_GPIO_MPC8XXX) += gpio-mpc8xxx.o obj-$(CONFIG_GPIO_MSIC) += gpio-msic.o @@ -55,7 +58,7 @@ obj-$(CONFIG_GPIO_MVEBU) += gpio-mvebu.o obj-$(CONFIG_GPIO_MXC) += gpio-mxc.o obj-$(CONFIG_GPIO_MXS) += gpio-mxs.o obj-$(CONFIG_GPIO_OCTEON) += gpio-octeon.o -obj-$(CONFIG_ARCH_OMAP) += gpio-omap.o +obj-$(CONFIG_GPIO_OMAP) += gpio-omap.o obj-$(CONFIG_GPIO_PCA953X) += gpio-pca953x.o obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.o obj-$(CONFIG_GPIO_PCH) += gpio-pch.o @@ -67,17 +70,18 @@ obj-$(CONFIG_GPIO_RCAR) += gpio-rcar.o obj-$(CONFIG_GPIO_SAMSUNG) += gpio-samsung.o obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o obj-$(CONFIG_GPIO_SCH) += gpio-sch.o +obj-$(CONFIG_GPIO_SCH311X) += gpio-sch311x.o obj-$(CONFIG_GPIO_SODAVILLE) += gpio-sodaville.o obj-$(CONFIG_GPIO_SPEAR_SPICS) += gpio-spear-spics.o obj-$(CONFIG_GPIO_STA2X11) += gpio-sta2x11.o obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o obj-$(CONFIG_GPIO_STP_XWAY) += gpio-stp-xway.o obj-$(CONFIG_GPIO_SX150X) += gpio-sx150x.o +obj-$(CONFIG_GPIO_SYSCON) += gpio-syscon.o obj-$(CONFIG_GPIO_TB10X) += gpio-tb10x.o obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o obj-$(CONFIG_ARCH_TEGRA) += gpio-tegra.o obj-$(CONFIG_GPIO_TIMBERDALE) += gpio-timberdale.o -obj-$(CONFIG_ARCH_DAVINCI_TNETV107X) += gpio-tnetv107x.o obj-$(CONFIG_GPIO_PALMAS) += gpio-palmas.o obj-$(CONFIG_GPIO_TPS6586X) += gpio-tps6586x.o obj-$(CONFIG_GPIO_TPS65910) += gpio-tps65910.o @@ -95,3 +99,5 @@ obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o +obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o +obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c index 307464fd015..65978cf85f7 100644 --- a/drivers/gpio/devres.c +++ b/drivers/gpio/devres.c @@ -52,6 +52,22 @@ struct gpio_desc *__must_check devm_gpiod_get(struct device *dev, EXPORT_SYMBOL(devm_gpiod_get); /** + * devm_gpiod_get_optional - Resource-managed gpiod_get_optional() + * @dev: GPIO consumer + * @con_id: function within the GPIO consumer + * + * Managed gpiod_get_optional(). GPIO descriptors returned from this function + * are automatically disposed on driver detach. See gpiod_get_optional() for + * detailed information about behavior and return values. + */ +struct gpio_desc *__must_check devm_gpiod_get_optional(struct device *dev, + const char *con_id) +{ + return devm_gpiod_get_index_optional(dev, con_id, 0); +} +EXPORT_SYMBOL(devm_gpiod_get_optional); + +/** * devm_gpiod_get_index - Resource-managed gpiod_get_index() * @dev: GPIO consumer * @con_id: function within the GPIO consumer @@ -87,6 +103,33 @@ struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev, EXPORT_SYMBOL(devm_gpiod_get_index); /** + * devm_gpiod_get_index_optional - Resource-managed gpiod_get_index_optional() + * @dev: GPIO consumer + * @con_id: function within the GPIO consumer + * @index: index of the GPIO to obtain in the consumer + * + * Managed gpiod_get_index_optional(). GPIO descriptors returned from this + * function are automatically disposed on driver detach. See + * gpiod_get_index_optional() for detailed information about behavior and + * return values. + */ +struct gpio_desc *__must_check devm_gpiod_get_index_optional(struct device *dev, + const char *con_id, + unsigned int index) +{ + struct gpio_desc *desc; + + desc = devm_gpiod_get_index(dev, con_id, index); + if (IS_ERR(desc)) { + if (PTR_ERR(desc) == -ENOENT) + return NULL; + } + + return desc; +} +EXPORT_SYMBOL(devm_gpiod_get_index_optional); + +/** * devm_gpiod_put - Resource-managed gpiod_put() * @desc: GPIO descriptor to dispose of * diff --git a/drivers/gpio/gpio-74x164.c b/drivers/gpio/gpio-74x164.c index 1e04bf91328..e4ae29824c3 100644 --- a/drivers/gpio/gpio-74x164.c +++ b/drivers/gpio/gpio-74x164.c @@ -12,7 +12,6 @@ #include <linux/init.h> #include <linux/mutex.h> #include <linux/spi/spi.h> -#include <linux/spi/74x164.h> #include <linux/gpio.h> #include <linux/of_gpio.h> #include <linux/slab.h> @@ -21,7 +20,6 @@ #define GEN_74X164_NUMBER_GPIOS 8 struct gen_74x164_chip { - struct spi_device *spi; u8 *buffer; struct gpio_chip gpio_chip; struct mutex lock; @@ -35,6 +33,7 @@ static struct gen_74x164_chip *gpio_to_74x164_chip(struct gpio_chip *gc) static int __gen_74x164_write_config(struct gen_74x164_chip *chip) { + struct spi_device *spi = to_spi_device(chip->gpio_chip.dev); struct spi_message message; struct spi_transfer *msg_buf; int i, ret = 0; @@ -55,12 +54,12 @@ static int __gen_74x164_write_config(struct gen_74x164_chip *chip) * byte of the buffer will end up in the last register. */ for (i = chip->registers - 1; i >= 0; i--) { - msg_buf[i].tx_buf = chip->buffer +i; + msg_buf[i].tx_buf = chip->buffer + i; msg_buf[i].len = sizeof(u8); spi_message_add_tail(msg_buf + i, &message); } - ret = spi_sync(chip->spi, &message); + ret = spi_sync(spi, &message); kfree(msg_buf); @@ -108,14 +107,8 @@ static int gen_74x164_direction_output(struct gpio_chip *gc, static int gen_74x164_probe(struct spi_device *spi) { struct gen_74x164_chip *chip; - struct gen_74x164_chip_platform_data *pdata; int ret; - if (!spi->dev.of_node) { - dev_err(&spi->dev, "No device tree data available.\n"); - return -EINVAL; - } - /* * bits_per_word cannot be configured in platform data */ @@ -129,40 +122,32 @@ static int gen_74x164_probe(struct spi_device *spi) if (!chip) return -ENOMEM; - pdata = dev_get_platdata(&spi->dev); - if (pdata && pdata->base) - chip->gpio_chip.base = pdata->base; - else - chip->gpio_chip.base = -1; - - mutex_init(&chip->lock); - spi_set_drvdata(spi, chip); - chip->spi = spi; - chip->gpio_chip.label = spi->modalias; chip->gpio_chip.direction_output = gen_74x164_direction_output; chip->gpio_chip.get = gen_74x164_get_value; chip->gpio_chip.set = gen_74x164_set_value; + chip->gpio_chip.base = -1; - if (of_property_read_u32(spi->dev.of_node, "registers-number", &chip->registers)) { - dev_err(&spi->dev, "Missing registers-number property in the DT.\n"); - ret = -EINVAL; - goto exit_destroy; + if (of_property_read_u32(spi->dev.of_node, "registers-number", + &chip->registers)) { + dev_err(&spi->dev, + "Missing registers-number property in the DT.\n"); + return -EINVAL; } chip->gpio_chip.ngpio = GEN_74X164_NUMBER_GPIOS * chip->registers; chip->buffer = devm_kzalloc(&spi->dev, chip->registers, GFP_KERNEL); - if (!chip->buffer) { - ret = -ENOMEM; - goto exit_destroy; - } + if (!chip->buffer) + return -ENOMEM; - chip->gpio_chip.can_sleep = 1; + chip->gpio_chip.can_sleep = true; chip->gpio_chip.dev = &spi->dev; chip->gpio_chip.owner = THIS_MODULE; + mutex_init(&chip->lock); + ret = __gen_74x164_write_config(chip); if (ret) { dev_err(&spi->dev, "Failed writing: %d\n", ret); @@ -170,31 +155,23 @@ static int gen_74x164_probe(struct spi_device *spi) } ret = gpiochip_add(&chip->gpio_chip); - if (ret) - goto exit_destroy; - - return ret; + if (!ret) + return 0; exit_destroy: mutex_destroy(&chip->lock); + return ret; } static int gen_74x164_remove(struct spi_device *spi) { - struct gen_74x164_chip *chip; + struct gen_74x164_chip *chip = spi_get_drvdata(spi); int ret; - chip = spi_get_drvdata(spi); - if (chip == NULL) - return -ENODEV; - ret = gpiochip_remove(&chip->gpio_chip); if (!ret) mutex_destroy(&chip->lock); - else - dev_err(&spi->dev, "Failed to remove the GPIO controller: %d\n", - ret); return ret; } diff --git a/drivers/gpio/gpio-adnp.c b/drivers/gpio/gpio-adnp.c index b204033acae..b2239d678d0 100644 --- a/drivers/gpio/gpio-adnp.c +++ b/drivers/gpio/gpio-adnp.c @@ -260,7 +260,7 @@ static int adnp_gpio_setup(struct adnp *adnp, unsigned int num_gpios) chip->direction_output = adnp_gpio_direction_output; chip->get = adnp_gpio_get; chip->set = adnp_gpio_set; - chip->can_sleep = 1; + chip->can_sleep = true; if (IS_ENABLED(CONFIG_DEBUG_FS)) chip->dbg_show = adnp_gpio_dbg_show; @@ -408,6 +408,26 @@ static void adnp_irq_bus_unlock(struct irq_data *data) mutex_unlock(&adnp->irq_lock); } +static int adnp_irq_reqres(struct irq_data *data) +{ + struct adnp *adnp = irq_data_get_irq_chip_data(data); + + if (gpio_lock_as_irq(&adnp->gpio, data->hwirq)) { + dev_err(adnp->gpio.dev, + "unable to lock HW IRQ %lu for IRQ\n", + data->hwirq); + return -EINVAL; + } + return 0; +} + +static void adnp_irq_relres(struct irq_data *data) +{ + struct adnp *adnp = irq_data_get_irq_chip_data(data); + + gpio_unlock_as_irq(&adnp->gpio, data->hwirq); +} + static struct irq_chip adnp_irq_chip = { .name = "gpio-adnp", .irq_mask = adnp_irq_mask, @@ -415,6 +435,8 @@ static struct irq_chip adnp_irq_chip = { .irq_set_type = adnp_irq_set_type, .irq_bus_lock = adnp_irq_bus_lock, .irq_bus_sync_unlock = adnp_irq_bus_unlock, + .irq_request_resources = adnp_irq_reqres, + .irq_release_resources = adnp_irq_relres, }; static int adnp_irq_map(struct irq_domain *domain, unsigned int irq, diff --git a/drivers/gpio/gpio-adp5520.c b/drivers/gpio/gpio-adp5520.c index 084337d5514..f1ade8fa321 100644 --- a/drivers/gpio/gpio-adp5520.c +++ b/drivers/gpio/gpio-adp5520.c @@ -106,10 +106,8 @@ static int adp5520_gpio_probe(struct platform_device *pdev) } dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); - if (dev == NULL) { - dev_err(&pdev->dev, "failed to alloc memory\n"); + if (dev == NULL) return -ENOMEM; - } dev->master = pdev->dev.parent; @@ -127,7 +125,7 @@ static int adp5520_gpio_probe(struct platform_device *pdev) gc->direction_output = adp5520_gpio_direction_output; gc->get = adp5520_gpio_get_value; gc->set = adp5520_gpio_set_value; - gc->can_sleep = 1; + gc->can_sleep = true; gc->base = pdata->gpio_start; gc->ngpio = gpios; diff --git a/drivers/gpio/gpio-adp5588.c b/drivers/gpio/gpio-adp5588.c index 90fc4c99c02..ef19bc33f2b 100644 --- a/drivers/gpio/gpio-adp5588.c +++ b/drivers/gpio/gpio-adp5588.c @@ -67,9 +67,20 @@ static int adp5588_gpio_get_value(struct gpio_chip *chip, unsigned off) { struct adp5588_gpio *dev = container_of(chip, struct adp5588_gpio, gpio_chip); + unsigned bank = ADP5588_BANK(off); + unsigned bit = ADP5588_BIT(off); + int val; - return !!(adp5588_gpio_read(dev->client, - GPIO_DAT_STAT1 + ADP5588_BANK(off)) & ADP5588_BIT(off)); + mutex_lock(&dev->lock); + + if (dev->dir[bank] & bit) + val = dev->dat_out[bank]; + else + val = adp5588_gpio_read(dev->client, GPIO_DAT_STAT1 + bank); + + mutex_unlock(&dev->lock); + + return !!(val & bit); } static void adp5588_gpio_set_value(struct gpio_chip *chip, @@ -368,10 +379,8 @@ static int adp5588_gpio_probe(struct i2c_client *client, } dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (dev == NULL) { - dev_err(&client->dev, "failed to alloc memory\n"); + if (dev == NULL) return -ENOMEM; - } dev->client = client; @@ -380,12 +389,13 @@ static int adp5588_gpio_probe(struct i2c_client *client, gc->direction_output = adp5588_gpio_direction_output; gc->get = adp5588_gpio_get_value; gc->set = adp5588_gpio_set_value; - gc->can_sleep = 1; + gc->can_sleep = true; gc->base = pdata->gpio_start; gc->ngpio = ADP5588_MAXGPIO; gc->label = client->name; gc->owner = THIS_MODULE; + gc->names = pdata->names; mutex_init(&dev->lock); diff --git a/drivers/gpio/gpio-amd8111.c b/drivers/gpio/gpio-amd8111.c index 710fafcdd1b..94e9992f890 100644 --- a/drivers/gpio/gpio-amd8111.c +++ b/drivers/gpio/gpio-amd8111.c @@ -60,7 +60,7 @@ * register a pci_driver, because someone else might one day * want to register another driver on the same PCI id. */ -static DEFINE_PCI_DEVICE_TABLE(pci_tbl) = { +static const struct pci_device_id pci_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS), 0 }, { 0, }, /* terminate list */ }; diff --git a/drivers/gpio/gpio-arizona.c b/drivers/gpio/gpio-arizona.c index dceb5dcf9d1..29bdff55898 100644 --- a/drivers/gpio/gpio-arizona.c +++ b/drivers/gpio/gpio-arizona.c @@ -91,7 +91,7 @@ static struct gpio_chip template_chip = { .get = arizona_gpio_get, .direction_output = arizona_gpio_direction_out, .set = arizona_gpio_set, - .can_sleep = 1, + .can_sleep = true, }; static int arizona_gpio_probe(struct platform_device *pdev) diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c index 54c18c220a6..3f6b33ce9bd 100644 --- a/drivers/gpio/gpio-bcm-kona.c +++ b/drivers/gpio/gpio-bcm-kona.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2013 Broadcom Corporation + * Copyright (C) 2012-2014 Broadcom Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -28,6 +28,10 @@ #define GPIO_BANK(gpio) ((gpio) >> 5) #define GPIO_BIT(gpio) ((gpio) & (GPIO_PER_BANK - 1)) +/* There is a GPIO control register for each GPIO */ +#define GPIO_CONTROL(gpio) (0x00000100 + ((gpio) << 2)) + +/* The remaining registers are per GPIO bank */ #define GPIO_OUT_STATUS(bank) (0x00000000 + ((bank) << 2)) #define GPIO_IN_STATUS(bank) (0x00000020 + ((bank) << 2)) #define GPIO_OUT_SET(bank) (0x00000040 + ((bank) << 2)) @@ -35,7 +39,6 @@ #define GPIO_INT_STATUS(bank) (0x00000080 + ((bank) << 2)) #define GPIO_INT_MASK(bank) (0x000000a0 + ((bank) << 2)) #define GPIO_INT_MSKCLR(bank) (0x000000c0 + ((bank) << 2)) -#define GPIO_CONTROL(bank) (0x00000100 + ((bank) << 2)) #define GPIO_PWD_STATUS(bank) (0x00000500 + ((bank) << 2)) #define GPIO_GPPWR_OFFSET 0x00000520 @@ -80,22 +83,43 @@ static inline struct bcm_kona_gpio *to_kona_gpio(struct gpio_chip *chip) return container_of(chip, struct bcm_kona_gpio, gpio_chip); } -static void bcm_kona_gpio_set_lockcode_bank(void __iomem *reg_base, - int bank_id, int lockcode) +static inline void bcm_kona_gpio_write_lock_regs(void __iomem *reg_base, + int bank_id, u32 lockcode) { writel(BCM_GPIO_PASSWD, reg_base + GPIO_GPPWR_OFFSET); writel(lockcode, reg_base + GPIO_PWD_STATUS(bank_id)); } -static inline void bcm_kona_gpio_lock_bank(void __iomem *reg_base, int bank_id) +static void bcm_kona_gpio_lock_gpio(struct bcm_kona_gpio *kona_gpio, + unsigned gpio) { - bcm_kona_gpio_set_lockcode_bank(reg_base, bank_id, LOCK_CODE); + u32 val; + unsigned long flags; + int bank_id = GPIO_BANK(gpio); + + spin_lock_irqsave(&kona_gpio->lock, flags); + + val = readl(kona_gpio->reg_base + GPIO_PWD_STATUS(bank_id)); + val |= BIT(gpio); + bcm_kona_gpio_write_lock_regs(kona_gpio->reg_base, bank_id, val); + + spin_unlock_irqrestore(&kona_gpio->lock, flags); } -static inline void bcm_kona_gpio_unlock_bank(void __iomem *reg_base, - int bank_id) +static void bcm_kona_gpio_unlock_gpio(struct bcm_kona_gpio *kona_gpio, + unsigned gpio) { - bcm_kona_gpio_set_lockcode_bank(reg_base, bank_id, UNLOCK_CODE); + u32 val; + unsigned long flags; + int bank_id = GPIO_BANK(gpio); + + spin_lock_irqsave(&kona_gpio->lock, flags); + + val = readl(kona_gpio->reg_base + GPIO_PWD_STATUS(bank_id)); + val &= ~BIT(gpio); + bcm_kona_gpio_write_lock_regs(kona_gpio->reg_base, bank_id, val); + + spin_unlock_irqrestore(&kona_gpio->lock, flags); } static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value) @@ -110,7 +134,6 @@ static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value) kona_gpio = to_kona_gpio(chip); reg_base = kona_gpio->reg_base; spin_lock_irqsave(&kona_gpio->lock, flags); - bcm_kona_gpio_unlock_bank(reg_base, bank_id); /* determine the GPIO pin direction */ val = readl(reg_base + GPIO_CONTROL(gpio)); @@ -127,7 +150,6 @@ static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value) writel(val, reg_base + reg_offset); out: - bcm_kona_gpio_lock_bank(reg_base, bank_id); spin_unlock_irqrestore(&kona_gpio->lock, flags); } @@ -143,7 +165,6 @@ static int bcm_kona_gpio_get(struct gpio_chip *chip, unsigned gpio) kona_gpio = to_kona_gpio(chip); reg_base = kona_gpio->reg_base; spin_lock_irqsave(&kona_gpio->lock, flags); - bcm_kona_gpio_unlock_bank(reg_base, bank_id); /* determine the GPIO pin direction */ val = readl(reg_base + GPIO_CONTROL(gpio)); @@ -154,32 +175,43 @@ static int bcm_kona_gpio_get(struct gpio_chip *chip, unsigned gpio) GPIO_IN_STATUS(bank_id) : GPIO_OUT_STATUS(bank_id); val = readl(reg_base + reg_offset); - bcm_kona_gpio_lock_bank(reg_base, bank_id); spin_unlock_irqrestore(&kona_gpio->lock, flags); /* return the specified bit status */ return !!(val & BIT(bit)); } +static int bcm_kona_gpio_request(struct gpio_chip *chip, unsigned gpio) +{ + struct bcm_kona_gpio *kona_gpio = to_kona_gpio(chip); + + bcm_kona_gpio_unlock_gpio(kona_gpio, gpio); + return 0; +} + +static void bcm_kona_gpio_free(struct gpio_chip *chip, unsigned gpio) +{ + struct bcm_kona_gpio *kona_gpio = to_kona_gpio(chip); + + bcm_kona_gpio_lock_gpio(kona_gpio, gpio); +} + static int bcm_kona_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) { struct bcm_kona_gpio *kona_gpio; void __iomem *reg_base; u32 val; unsigned long flags; - int bank_id = GPIO_BANK(gpio); kona_gpio = to_kona_gpio(chip); reg_base = kona_gpio->reg_base; spin_lock_irqsave(&kona_gpio->lock, flags); - bcm_kona_gpio_unlock_bank(reg_base, bank_id); val = readl(reg_base + GPIO_CONTROL(gpio)); val &= ~GPIO_GPCTR0_IOTR_MASK; val |= GPIO_GPCTR0_IOTR_CMD_INPUT; writel(val, reg_base + GPIO_CONTROL(gpio)); - bcm_kona_gpio_lock_bank(reg_base, bank_id); spin_unlock_irqrestore(&kona_gpio->lock, flags); return 0; @@ -198,7 +230,6 @@ static int bcm_kona_gpio_direction_output(struct gpio_chip *chip, kona_gpio = to_kona_gpio(chip); reg_base = kona_gpio->reg_base; spin_lock_irqsave(&kona_gpio->lock, flags); - bcm_kona_gpio_unlock_bank(reg_base, bank_id); val = readl(reg_base + GPIO_CONTROL(gpio)); val &= ~GPIO_GPCTR0_IOTR_MASK; @@ -210,7 +241,6 @@ static int bcm_kona_gpio_direction_output(struct gpio_chip *chip, val |= BIT(bit); writel(val, reg_base + reg_offset); - bcm_kona_gpio_lock_bank(reg_base, bank_id); spin_unlock_irqrestore(&kona_gpio->lock, flags); return 0; @@ -233,7 +263,6 @@ static int bcm_kona_gpio_set_debounce(struct gpio_chip *chip, unsigned gpio, void __iomem *reg_base; u32 val, res; unsigned long flags; - int bank_id = GPIO_BANK(gpio); kona_gpio = to_kona_gpio(chip); reg_base = kona_gpio->reg_base; @@ -257,7 +286,6 @@ static int bcm_kona_gpio_set_debounce(struct gpio_chip *chip, unsigned gpio, /* spin lock for read-modify-write of the GPIO register */ spin_lock_irqsave(&kona_gpio->lock, flags); - bcm_kona_gpio_unlock_bank(reg_base, bank_id); val = readl(reg_base + GPIO_CONTROL(gpio)); val &= ~GPIO_GPCTR0_DBR_MASK; @@ -272,7 +300,6 @@ static int bcm_kona_gpio_set_debounce(struct gpio_chip *chip, unsigned gpio, writel(val, reg_base + GPIO_CONTROL(gpio)); - bcm_kona_gpio_lock_bank(reg_base, bank_id); spin_unlock_irqrestore(&kona_gpio->lock, flags); return 0; @@ -281,6 +308,8 @@ static int bcm_kona_gpio_set_debounce(struct gpio_chip *chip, unsigned gpio, static struct gpio_chip template_chip = { .label = "bcm-kona-gpio", .owner = THIS_MODULE, + .request = bcm_kona_gpio_request, + .free = bcm_kona_gpio_free, .direction_input = bcm_kona_gpio_direction_input, .get = bcm_kona_gpio_get, .direction_output = bcm_kona_gpio_direction_output, @@ -294,7 +323,7 @@ static void bcm_kona_gpio_irq_ack(struct irq_data *d) { struct bcm_kona_gpio *kona_gpio; void __iomem *reg_base; - int gpio = d->hwirq; + unsigned gpio = d->hwirq; int bank_id = GPIO_BANK(gpio); int bit = GPIO_BIT(gpio); u32 val; @@ -303,13 +332,11 @@ static void bcm_kona_gpio_irq_ack(struct irq_data *d) kona_gpio = irq_data_get_irq_chip_data(d); reg_base = kona_gpio->reg_base; spin_lock_irqsave(&kona_gpio->lock, flags); - bcm_kona_gpio_unlock_bank(reg_base, bank_id); val = readl(reg_base + GPIO_INT_STATUS(bank_id)); val |= BIT(bit); writel(val, reg_base + GPIO_INT_STATUS(bank_id)); - bcm_kona_gpio_lock_bank(reg_base, bank_id); spin_unlock_irqrestore(&kona_gpio->lock, flags); } @@ -317,7 +344,7 @@ static void bcm_kona_gpio_irq_mask(struct irq_data *d) { struct bcm_kona_gpio *kona_gpio; void __iomem *reg_base; - int gpio = d->hwirq; + unsigned gpio = d->hwirq; int bank_id = GPIO_BANK(gpio); int bit = GPIO_BIT(gpio); u32 val; @@ -326,13 +353,11 @@ static void bcm_kona_gpio_irq_mask(struct irq_data *d) kona_gpio = irq_data_get_irq_chip_data(d); reg_base = kona_gpio->reg_base; spin_lock_irqsave(&kona_gpio->lock, flags); - bcm_kona_gpio_unlock_bank(reg_base, bank_id); val = readl(reg_base + GPIO_INT_MASK(bank_id)); val |= BIT(bit); writel(val, reg_base + GPIO_INT_MASK(bank_id)); - bcm_kona_gpio_lock_bank(reg_base, bank_id); spin_unlock_irqrestore(&kona_gpio->lock, flags); } @@ -340,7 +365,7 @@ static void bcm_kona_gpio_irq_unmask(struct irq_data *d) { struct bcm_kona_gpio *kona_gpio; void __iomem *reg_base; - int gpio = d->hwirq; + unsigned gpio = d->hwirq; int bank_id = GPIO_BANK(gpio); int bit = GPIO_BIT(gpio); u32 val; @@ -349,13 +374,11 @@ static void bcm_kona_gpio_irq_unmask(struct irq_data *d) kona_gpio = irq_data_get_irq_chip_data(d); reg_base = kona_gpio->reg_base; spin_lock_irqsave(&kona_gpio->lock, flags); - bcm_kona_gpio_unlock_bank(reg_base, bank_id); val = readl(reg_base + GPIO_INT_MSKCLR(bank_id)); val |= BIT(bit); writel(val, reg_base + GPIO_INT_MSKCLR(bank_id)); - bcm_kona_gpio_lock_bank(reg_base, bank_id); spin_unlock_irqrestore(&kona_gpio->lock, flags); } @@ -363,11 +386,10 @@ static int bcm_kona_gpio_irq_set_type(struct irq_data *d, unsigned int type) { struct bcm_kona_gpio *kona_gpio; void __iomem *reg_base; - int gpio = d->hwirq; + unsigned gpio = d->hwirq; u32 lvl_type; u32 val; unsigned long flags; - int bank_id = GPIO_BANK(gpio); kona_gpio = irq_data_get_irq_chip_data(d); reg_base = kona_gpio->reg_base; @@ -394,14 +416,12 @@ static int bcm_kona_gpio_irq_set_type(struct irq_data *d, unsigned int type) } spin_lock_irqsave(&kona_gpio->lock, flags); - bcm_kona_gpio_unlock_bank(reg_base, bank_id); val = readl(reg_base + GPIO_CONTROL(gpio)); val &= ~GPIO_GPCTR0_ITR_MASK; val |= lvl_type << GPIO_GPCTR0_ITR_SHIFT; writel(val, reg_base + GPIO_CONTROL(gpio)); - bcm_kona_gpio_lock_bank(reg_base, bank_id); spin_unlock_irqrestore(&kona_gpio->lock, flags); return 0; @@ -424,7 +444,6 @@ static void bcm_kona_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) */ reg_base = bank->kona_gpio->reg_base; bank_id = bank->id; - bcm_kona_gpio_unlock_bank(reg_base, bank_id); while ((sta = readl(reg_base + GPIO_INT_STATUS(bank_id)) & (~(readl(reg_base + GPIO_INT_MASK(bank_id)))))) { @@ -444,17 +463,37 @@ static void bcm_kona_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) } } - bcm_kona_gpio_lock_bank(reg_base, bank_id); - chained_irq_exit(chip, desc); } +static int bcm_kona_gpio_irq_reqres(struct irq_data *d) +{ + struct bcm_kona_gpio *kona_gpio = irq_data_get_irq_chip_data(d); + + if (gpio_lock_as_irq(&kona_gpio->gpio_chip, d->hwirq)) { + dev_err(kona_gpio->gpio_chip.dev, + "unable to lock HW IRQ %lu for IRQ\n", + d->hwirq); + return -EINVAL; + } + return 0; +} + +static void bcm_kona_gpio_irq_relres(struct irq_data *d) +{ + struct bcm_kona_gpio *kona_gpio = irq_data_get_irq_chip_data(d); + + gpio_unlock_as_irq(&kona_gpio->gpio_chip, d->hwirq); +} + static struct irq_chip bcm_gpio_irq_chip = { .name = "bcm-kona-gpio", .irq_ack = bcm_kona_gpio_irq_ack, .irq_mask = bcm_kona_gpio_irq_mask, .irq_unmask = bcm_kona_gpio_irq_unmask, .irq_set_type = bcm_kona_gpio_irq_set_type, + .irq_request_resources = bcm_kona_gpio_irq_reqres, + .irq_release_resources = bcm_kona_gpio_irq_relres, }; static struct __initconst of_device_id bcm_kona_gpio_of_match[] = { @@ -509,10 +548,12 @@ static void bcm_kona_gpio_reset(struct bcm_kona_gpio *kona_gpio) reg_base = kona_gpio->reg_base; /* disable interrupts and clear status */ for (i = 0; i < kona_gpio->num_bank; i++) { - bcm_kona_gpio_unlock_bank(reg_base, i); + /* Unlock the entire bank first */ + bcm_kona_gpio_write_lock_regs(kona_gpio, i, UNLOCK_CODE); writel(0xffffffff, reg_base + GPIO_INT_MASK(i)); writel(0xffffffff, reg_base + GPIO_INT_STATUS(i)); - bcm_kona_gpio_lock_bank(reg_base, i); + /* Now re-lock the bank */ + bcm_kona_gpio_write_lock_regs(kona_gpio, i, LOCK_CODE); } } @@ -635,6 +676,6 @@ static struct platform_driver bcm_kona_gpio_driver = { module_platform_driver(bcm_kona_gpio_driver); -MODULE_AUTHOR("Broadcom"); +MODULE_AUTHOR("Broadcom Corporation <bcm-kernel-feedback-list@broadcom.com>"); MODULE_DESCRIPTION("Broadcom Kona GPIO Driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/gpio-bt8xx.c b/drivers/gpio/gpio-bt8xx.c index 9dfe36fd8ba..6557147d933 100644 --- a/drivers/gpio/gpio-bt8xx.c +++ b/drivers/gpio/gpio-bt8xx.c @@ -169,7 +169,7 @@ static void bt8xxgpio_gpio_setup(struct bt8xxgpio *bg) c->dbg_show = NULL; c->base = modparam_gpiobase; c->ngpio = BT8XXGPIO_NR_GPIOS; - c->can_sleep = 0; + c->can_sleep = false; } static int bt8xxgpio_probe(struct pci_dev *dev, @@ -178,7 +178,7 @@ static int bt8xxgpio_probe(struct pci_dev *dev, struct bt8xxgpio *bg; int err; - bg = kzalloc(sizeof(*bg), GFP_KERNEL); + bg = devm_kzalloc(&dev->dev, sizeof(struct bt8xxgpio), GFP_KERNEL); if (!bg) return -ENOMEM; @@ -188,9 +188,9 @@ static int bt8xxgpio_probe(struct pci_dev *dev, err = pci_enable_device(dev); if (err) { printk(KERN_ERR "bt8xxgpio: Can't enable device.\n"); - goto err_freebg; + return err; } - if (!request_mem_region(pci_resource_start(dev, 0), + if (!devm_request_mem_region(&dev->dev, pci_resource_start(dev, 0), pci_resource_len(dev, 0), "bt8xxgpio")) { printk(KERN_WARNING "bt8xxgpio: Can't request iomem (0x%llx).\n", @@ -201,11 +201,11 @@ static int bt8xxgpio_probe(struct pci_dev *dev, pci_set_master(dev); pci_set_drvdata(dev, bg); - bg->mmio = ioremap(pci_resource_start(dev, 0), 0x1000); + bg->mmio = devm_ioremap(&dev->dev, pci_resource_start(dev, 0), 0x1000); if (!bg->mmio) { printk(KERN_ERR "bt8xxgpio: ioremap() failed\n"); err = -EIO; - goto err_release_mem; + goto err_disable; } /* Disable interrupts */ @@ -220,18 +220,13 @@ static int bt8xxgpio_probe(struct pci_dev *dev, err = gpiochip_add(&bg->gpio); if (err) { printk(KERN_ERR "bt8xxgpio: Failed to register GPIOs\n"); - goto err_release_mem; + goto err_disable; } return 0; -err_release_mem: - release_mem_region(pci_resource_start(dev, 0), - pci_resource_len(dev, 0)); err_disable: pci_disable_device(dev); -err_freebg: - kfree(bg); return err; } @@ -250,8 +245,6 @@ static void bt8xxgpio_remove(struct pci_dev *pdev) release_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); pci_disable_device(pdev); - - kfree(bg); } #ifdef CONFIG_PM @@ -308,7 +301,7 @@ static int bt8xxgpio_resume(struct pci_dev *pdev) #define bt8xxgpio_resume NULL #endif /* CONFIG_PM */ -static DEFINE_PCI_DEVICE_TABLE(bt8xxgpio_pci_tbl) = { +static const struct pci_device_id bt8xxgpio_pci_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848) }, { PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849) }, { PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878) }, diff --git a/drivers/gpio/gpio-clps711x.c b/drivers/gpio/gpio-clps711x.c index 0924f20fa47..e1e861239e9 100644 --- a/drivers/gpio/gpio-clps711x.c +++ b/drivers/gpio/gpio-clps711x.c @@ -65,6 +65,7 @@ static int clps711x_gpio_probe(struct platform_device *pdev) } bgc->gc.base = id * 8; + bgc->gc.owner = THIS_MODULE; platform_set_drvdata(pdev, bgc); return gpiochip_add(&bgc->gc); @@ -77,7 +78,7 @@ static int clps711x_gpio_remove(struct platform_device *pdev) return bgpio_remove(bgc); } -static const struct of_device_id clps711x_gpio_ids[] = { +static const struct of_device_id __maybe_unused clps711x_gpio_ids[] = { { .compatible = "cirrus,clps711x-gpio" }, { } }; @@ -87,7 +88,7 @@ static struct platform_driver clps711x_gpio_driver = { .driver = { .name = "clps711x-gpio", .owner = THIS_MODULE, - .of_match_table = clps711x_gpio_ids, + .of_match_table = of_match_ptr(clps711x_gpio_ids), }, .probe = clps711x_gpio_probe, .remove = clps711x_gpio_remove, @@ -97,3 +98,4 @@ module_platform_driver(clps711x_gpio_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>"); MODULE_DESCRIPTION("CLPS711X GPIO driver"); +MODULE_ALIAS("platform:clps711x-gpio"); diff --git a/drivers/gpio/gpio-da9052.c b/drivers/gpio/gpio-da9052.c index 9b77dc05d4a..416cdf786b0 100644 --- a/drivers/gpio/gpio-da9052.c +++ b/drivers/gpio/gpio-da9052.c @@ -200,7 +200,7 @@ static struct gpio_chip reference_gp = { .direction_input = da9052_gpio_direction_input, .direction_output = da9052_gpio_direction_output, .to_irq = da9052_gpio_to_irq, - .can_sleep = 1, + .can_sleep = true, .ngpio = 16, .base = -1, }; diff --git a/drivers/gpio/gpio-da9055.c b/drivers/gpio/gpio-da9055.c index 7ef0820032b..f992997bc30 100644 --- a/drivers/gpio/gpio-da9055.c +++ b/drivers/gpio/gpio-da9055.c @@ -134,7 +134,7 @@ static struct gpio_chip reference_gp = { .direction_input = da9055_gpio_direction_input, .direction_output = da9055_gpio_direction_output, .to_irq = da9055_gpio_to_irq, - .can_sleep = 1, + .can_sleep = true, .ngpio = 3, .base = -1, }; diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index 84be70157ad..9f0682534e2 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -16,8 +16,13 @@ #include <linux/err.h> #include <linux/io.h> #include <linux/irq.h> +#include <linux/irqdomain.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/platform_data/gpio-davinci.h> +#include <linux/irqchip/chained_irq.h> struct davinci_gpio_regs { u32 dir; @@ -32,6 +37,8 @@ struct davinci_gpio_regs { u32 intstat; }; +typedef struct irq_chip *(*gpio_get_irq_chip_cb_t)(unsigned int irq); + #define BINTEN 0x8 /* GPIO Interrupt Per-Bank Enable Register */ #define chip2controller(chip) \ @@ -82,14 +89,14 @@ static inline int __davinci_direction(struct gpio_chip *chip, u32 mask = 1 << offset; spin_lock_irqsave(&d->lock, flags); - temp = __raw_readl(&g->dir); + temp = readl_relaxed(&g->dir); if (out) { temp &= ~mask; - __raw_writel(mask, value ? &g->set_data : &g->clr_data); + writel_relaxed(mask, value ? &g->set_data : &g->clr_data); } else { temp |= mask; } - __raw_writel(temp, &g->dir); + writel_relaxed(temp, &g->dir); spin_unlock_irqrestore(&d->lock, flags); return 0; @@ -118,7 +125,7 @@ static int davinci_gpio_get(struct gpio_chip *chip, unsigned offset) struct davinci_gpio_controller *d = chip2controller(chip); struct davinci_gpio_regs __iomem *g = d->regs; - return (1 << offset) & __raw_readl(&g->in_data); + return (1 << offset) & readl_relaxed(&g->in_data); } /* @@ -130,8 +137,63 @@ davinci_gpio_set(struct gpio_chip *chip, unsigned offset, int value) struct davinci_gpio_controller *d = chip2controller(chip); struct davinci_gpio_regs __iomem *g = d->regs; - __raw_writel((1 << offset), value ? &g->set_data : &g->clr_data); + writel_relaxed((1 << offset), value ? &g->set_data : &g->clr_data); +} + +static struct davinci_gpio_platform_data * +davinci_gpio_get_pdata(struct platform_device *pdev) +{ + struct device_node *dn = pdev->dev.of_node; + struct davinci_gpio_platform_data *pdata; + int ret; + u32 val; + + if (!IS_ENABLED(CONFIG_OF) || !pdev->dev.of_node) + return pdev->dev.platform_data; + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return NULL; + + ret = of_property_read_u32(dn, "ti,ngpio", &val); + if (ret) + goto of_err; + + pdata->ngpio = val; + + ret = of_property_read_u32(dn, "ti,davinci-gpio-unbanked", &val); + if (ret) + goto of_err; + + pdata->gpio_unbanked = val; + + return pdata; + +of_err: + dev_err(&pdev->dev, "Populating pdata from DT failed: err %d\n", ret); + return NULL; +} + +#ifdef CONFIG_OF_GPIO +static int davinci_gpio_of_xlate(struct gpio_chip *gc, + const struct of_phandle_args *gpiospec, + u32 *flags) +{ + struct davinci_gpio_controller *chips = dev_get_drvdata(gc->dev); + struct davinci_gpio_platform_data *pdata = dev_get_platdata(gc->dev); + + if (gpiospec->args[0] > pdata->ngpio) + return -EINVAL; + + if (gc != &chips[gpiospec->args[0] / 32].chip) + return -EINVAL; + + if (flags) + *flags = gpiospec->args[1]; + + return gpiospec->args[0] % 32; } +#endif static int davinci_gpio_probe(struct platform_device *pdev) { @@ -143,12 +205,14 @@ static int davinci_gpio_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct resource *res; - pdata = dev->platform_data; + pdata = davinci_gpio_get_pdata(pdev); if (!pdata) { dev_err(dev, "No platform data found\n"); return -EINVAL; } + dev->platform_data = pdata; + /* * The gpio banks conceptually expose a segmented bitmap, * and "ngpio" is one more than the largest zero-based @@ -160,16 +224,14 @@ static int davinci_gpio_probe(struct platform_device *pdev) return -EINVAL; } - if (WARN_ON(DAVINCI_N_GPIO < ngpio)) - ngpio = DAVINCI_N_GPIO; + if (WARN_ON(ARCH_NR_GPIOS < ngpio)) + ngpio = ARCH_NR_GPIOS; chips = devm_kzalloc(dev, ngpio * sizeof(struct davinci_gpio_controller), GFP_KERNEL); - if (!chips) { - dev_err(dev, "Memory allocation failed\n"); + if (!chips) return -ENOMEM; - } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { @@ -194,6 +256,12 @@ static int davinci_gpio_probe(struct platform_device *pdev) if (chips[i].chip.ngpio > 32) chips[i].chip.ngpio = 32; +#ifdef CONFIG_OF_GPIO + chips[i].chip.of_gpio_n_cells = 2; + chips[i].chip.of_xlate = davinci_gpio_of_xlate; + chips[i].chip.dev = dev; + chips[i].chip.of_node = dev->of_node; +#endif spin_lock_init(&chips[i].lock); regs = gpio2regs(base); @@ -227,8 +295,8 @@ static void gpio_irq_disable(struct irq_data *d) struct davinci_gpio_regs __iomem *g = irq2regs(d->irq); u32 mask = (u32) irq_data_get_irq_handler_data(d); - __raw_writel(mask, &g->clr_falling); - __raw_writel(mask, &g->clr_rising); + writel_relaxed(mask, &g->clr_falling); + writel_relaxed(mask, &g->clr_rising); } static void gpio_irq_enable(struct irq_data *d) @@ -242,9 +310,9 @@ static void gpio_irq_enable(struct irq_data *d) status = IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING; if (status & IRQ_TYPE_EDGE_FALLING) - __raw_writel(mask, &g->set_falling); + writel_relaxed(mask, &g->set_falling); if (status & IRQ_TYPE_EDGE_RISING) - __raw_writel(mask, &g->set_rising); + writel_relaxed(mask, &g->set_rising); } static int gpio_irq_type(struct irq_data *d, unsigned trigger) @@ -278,34 +346,28 @@ gpio_irq_handler(unsigned irq, struct irq_desc *desc) mask <<= 16; /* temporarily mask (level sensitive) parent IRQ */ - desc->irq_data.chip->irq_mask(&desc->irq_data); - desc->irq_data.chip->irq_ack(&desc->irq_data); + chained_irq_enter(irq_desc_get_chip(desc), desc); while (1) { u32 status; - int n; - int res; + int bit; /* ack any irqs */ - status = __raw_readl(&g->intstat) & mask; + status = readl_relaxed(&g->intstat) & mask; if (!status) break; - __raw_writel(status, &g->intstat); + writel_relaxed(status, &g->intstat); /* now demux them to the right lowlevel handler */ - n = d->irq_base; - if (irq & 1) { - n += 16; - status >>= 16; - } while (status) { - res = ffs(status); - n += res; - generic_handle_irq(n - 1); - status >>= res; + bit = __ffs(status); + status &= ~BIT(bit); + generic_handle_irq( + irq_find_mapping(d->irq_domain, + d->chip.base + bit)); } } - desc->irq_data.chip->irq_unmask(&desc->irq_data); + chained_irq_exit(irq_desc_get_chip(desc), desc); /* now it may re-trigger */ } @@ -313,10 +375,10 @@ static int gpio_to_irq_banked(struct gpio_chip *chip, unsigned offset) { struct davinci_gpio_controller *d = chip2controller(chip); - if (d->irq_base >= 0) - return d->irq_base + offset; + if (d->irq_domain) + return irq_create_mapping(d->irq_domain, d->chip.base + offset); else - return -ENODEV; + return -ENXIO; } static int gpio_to_irq_unbanked(struct gpio_chip *chip, unsigned offset) @@ -346,14 +408,55 @@ static int gpio_irq_type_unbanked(struct irq_data *data, unsigned trigger) if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) return -EINVAL; - __raw_writel(mask, (trigger & IRQ_TYPE_EDGE_FALLING) + writel_relaxed(mask, (trigger & IRQ_TYPE_EDGE_FALLING) ? &g->set_falling : &g->clr_falling); - __raw_writel(mask, (trigger & IRQ_TYPE_EDGE_RISING) + writel_relaxed(mask, (trigger & IRQ_TYPE_EDGE_RISING) ? &g->set_rising : &g->clr_rising); return 0; } +static int +davinci_gpio_irq_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hw) +{ + struct davinci_gpio_regs __iomem *g = gpio2regs(hw); + + irq_set_chip_and_handler_name(irq, &gpio_irqchip, handle_simple_irq, + "davinci_gpio"); + irq_set_irq_type(irq, IRQ_TYPE_NONE); + irq_set_chip_data(irq, (__force void *)g); + irq_set_handler_data(irq, (void *)__gpio_mask(hw)); + set_irq_flags(irq, IRQF_VALID); + + return 0; +} + +static const struct irq_domain_ops davinci_gpio_irq_ops = { + .map = davinci_gpio_irq_map, + .xlate = irq_domain_xlate_onetwocell, +}; + +static struct irq_chip *davinci_gpio_get_irq_chip(unsigned int irq) +{ + static struct irq_chip_type gpio_unbanked; + + gpio_unbanked = *container_of(irq_get_chip(irq), + struct irq_chip_type, chip); + + return &gpio_unbanked.chip; +}; + +static struct irq_chip *keystone_gpio_get_irq_chip(unsigned int irq) +{ + static struct irq_chip gpio_unbanked; + + gpio_unbanked = *irq_get_chip(irq); + return &gpio_unbanked; +}; + +static const struct of_device_id davinci_gpio_ids[]; + /* * NOTE: for suspend/resume, probably best to make a platform_device with * suspend_late/resume_resume calls hooking into results of the set_wake() @@ -364,7 +467,8 @@ static int gpio_irq_type_unbanked(struct irq_data *data, unsigned trigger) static int davinci_gpio_irq_setup(struct platform_device *pdev) { - unsigned gpio, irq, bank; + unsigned gpio, bank; + int irq; struct clk *clk; u32 binten = 0; unsigned ngpio, bank_irq; @@ -373,6 +477,19 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) struct davinci_gpio_controller *chips = platform_get_drvdata(pdev); struct davinci_gpio_platform_data *pdata = dev->platform_data; struct davinci_gpio_regs __iomem *g; + struct irq_domain *irq_domain = NULL; + const struct of_device_id *match; + struct irq_chip *irq_chip; + gpio_get_irq_chip_cb_t gpio_get_irq_chip; + + /* + * Use davinci_gpio_get_irq_chip by default to handle non DT cases + */ + gpio_get_irq_chip = davinci_gpio_get_irq_chip; + match = of_match_device(of_match_ptr(davinci_gpio_ids), + dev); + if (match) + gpio_get_irq_chip = (gpio_get_irq_chip_cb_t)match->data; ngpio = pdata->ngpio; res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); @@ -396,6 +513,22 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) } clk_prepare_enable(clk); + if (!pdata->gpio_unbanked) { + irq = irq_alloc_descs(-1, 0, ngpio, 0); + if (irq < 0) { + dev_err(dev, "Couldn't allocate IRQ numbers\n"); + return irq; + } + + irq_domain = irq_domain_add_legacy(NULL, ngpio, irq, 0, + &davinci_gpio_irq_ops, + chips); + if (!irq_domain) { + dev_err(dev, "Couldn't register an IRQ domain\n"); + return -ENODEV; + } + } + /* * Arrange gpio_to_irq() support, handling either direct IRQs or * banked IRQs. Having GPIOs in the first GPIO bank use direct @@ -404,9 +537,7 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) */ for (gpio = 0, bank = 0; gpio < ngpio; bank++, gpio += 32) { chips[bank].chip.to_irq = gpio_to_irq_banked; - chips[bank].irq_base = pdata->gpio_unbanked - ? -EINVAL - : (pdata->intc_irq_num + gpio); + chips[bank].irq_domain = irq_domain; } /* @@ -415,8 +546,6 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) * IRQ mux conflicts; gpio_irq_type_unbanked() is only for GPIOs. */ if (pdata->gpio_unbanked) { - static struct irq_chip_type gpio_unbanked; - /* pass "bank 0" GPIO IRQs to AINTC */ chips[0].chip.to_irq = gpio_to_irq_unbanked; chips[0].gpio_irq = bank_irq; @@ -425,19 +554,18 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) /* AINTC handles mask/unmask; GPIO handles triggering */ irq = bank_irq; - gpio_unbanked = *container_of(irq_get_chip(irq), - struct irq_chip_type, chip); - gpio_unbanked.chip.name = "GPIO-AINTC"; - gpio_unbanked.chip.irq_set_type = gpio_irq_type_unbanked; + irq_chip = gpio_get_irq_chip(irq); + irq_chip->name = "GPIO-AINTC"; + irq_chip->irq_set_type = gpio_irq_type_unbanked; /* default trigger: both edges */ g = gpio2regs(0); - __raw_writel(~0, &g->set_falling); - __raw_writel(~0, &g->set_rising); + writel_relaxed(~0, &g->set_falling); + writel_relaxed(~0, &g->set_rising); /* set the direct IRQs up to use that irqchip */ for (gpio = 0; gpio < pdata->gpio_unbanked; gpio++, irq++) { - irq_set_chip(irq, &gpio_unbanked.chip); + irq_set_chip(irq, irq_chip); irq_set_handler_data(irq, &chips[gpio / 32]); irq_set_status_flags(irq, IRQ_TYPE_EDGE_BOTH); } @@ -449,15 +577,11 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) * Or, AINTC can handle IRQs for banks of 16 GPIO IRQs, which we * then chain through our own handler. */ - for (gpio = 0, irq = gpio_to_irq(0), bank = 0; - gpio < ngpio; - bank++, bank_irq++) { - unsigned i; - + for (gpio = 0, bank = 0; gpio < ngpio; bank++, bank_irq++, gpio += 16) { /* disabled by default, enabled only as needed */ g = gpio2regs(gpio); - __raw_writel(~0, &g->clr_falling); - __raw_writel(~0, &g->clr_rising); + writel_relaxed(~0, &g->clr_falling); + writel_relaxed(~0, &g->clr_rising); /* set up all irqs in this bank */ irq_set_chained_handler(bank_irq, gpio_irq_handler); @@ -469,14 +593,6 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) */ irq_set_handler_data(bank_irq, &chips[gpio / 32]); - for (i = 0; i < 16 && gpio < ngpio; i++, irq++, gpio++) { - irq_set_chip(irq, &gpio_irqchip); - irq_set_chip_data(irq, (__force void *)g); - irq_set_handler_data(irq, (void *)__gpio_mask(gpio)); - irq_set_handler(irq, handle_simple_irq); - set_irq_flags(irq, IRQF_VALID); - } - binten |= BIT(bank); } @@ -485,18 +601,26 @@ done: * BINTEN -- per-bank interrupt enable. genirq would also let these * bits be set/cleared dynamically. */ - __raw_writel(binten, gpio_base + BINTEN); - - printk(KERN_INFO "DaVinci: %d gpio irqs\n", irq - gpio_to_irq(0)); + writel_relaxed(binten, gpio_base + BINTEN); return 0; } +#if IS_ENABLED(CONFIG_OF) +static const struct of_device_id davinci_gpio_ids[] = { + { .compatible = "ti,keystone-gpio", keystone_gpio_get_irq_chip}, + { .compatible = "ti,dm6441-gpio", davinci_gpio_get_irq_chip}, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, davinci_gpio_ids); +#endif + static struct platform_driver davinci_gpio_driver = { .probe = davinci_gpio_probe, .driver = { - .name = "davinci_gpio", - .owner = THIS_MODULE, + .name = "davinci_gpio", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(davinci_gpio_ids), }, }; diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c new file mode 100644 index 00000000000..cd3b8143527 --- /dev/null +++ b/drivers/gpio/gpio-dwapb.c @@ -0,0 +1,444 @@ +/* + * Copyright (c) 2011 Jamie Iles + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * All enquiries to support@picochip.com + */ +#include <linux/basic_mmio_gpio.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/ioport.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/platform_device.h> +#include <linux/spinlock.h> + +#define GPIO_SWPORTA_DR 0x00 +#define GPIO_SWPORTA_DDR 0x04 +#define GPIO_SWPORTB_DR 0x0c +#define GPIO_SWPORTB_DDR 0x10 +#define GPIO_SWPORTC_DR 0x18 +#define GPIO_SWPORTC_DDR 0x1c +#define GPIO_SWPORTD_DR 0x24 +#define GPIO_SWPORTD_DDR 0x28 +#define GPIO_INTEN 0x30 +#define GPIO_INTMASK 0x34 +#define GPIO_INTTYPE_LEVEL 0x38 +#define GPIO_INT_POLARITY 0x3c +#define GPIO_INTSTATUS 0x40 +#define GPIO_PORTA_EOI 0x4c +#define GPIO_EXT_PORTA 0x50 +#define GPIO_EXT_PORTB 0x54 +#define GPIO_EXT_PORTC 0x58 +#define GPIO_EXT_PORTD 0x5c + +#define DWAPB_MAX_PORTS 4 +#define GPIO_EXT_PORT_SIZE (GPIO_EXT_PORTB - GPIO_EXT_PORTA) +#define GPIO_SWPORT_DR_SIZE (GPIO_SWPORTB_DR - GPIO_SWPORTA_DR) +#define GPIO_SWPORT_DDR_SIZE (GPIO_SWPORTB_DDR - GPIO_SWPORTA_DDR) + +struct dwapb_gpio; + +struct dwapb_gpio_port { + struct bgpio_chip bgc; + bool is_registered; + struct dwapb_gpio *gpio; +}; + +struct dwapb_gpio { + struct device *dev; + void __iomem *regs; + struct dwapb_gpio_port *ports; + unsigned int nr_ports; + struct irq_domain *domain; +}; + +static int dwapb_gpio_to_irq(struct gpio_chip *gc, unsigned offset) +{ + struct bgpio_chip *bgc = to_bgpio_chip(gc); + struct dwapb_gpio_port *port = container_of(bgc, struct + dwapb_gpio_port, bgc); + struct dwapb_gpio *gpio = port->gpio; + + return irq_find_mapping(gpio->domain, offset); +} + +static void dwapb_toggle_trigger(struct dwapb_gpio *gpio, unsigned int offs) +{ + u32 v = readl(gpio->regs + GPIO_INT_POLARITY); + + if (gpio_get_value(gpio->ports[0].bgc.gc.base + offs)) + v &= ~BIT(offs); + else + v |= BIT(offs); + + writel(v, gpio->regs + GPIO_INT_POLARITY); +} + +static void dwapb_irq_handler(u32 irq, struct irq_desc *desc) +{ + struct dwapb_gpio *gpio = irq_get_handler_data(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); + u32 irq_status = readl_relaxed(gpio->regs + GPIO_INTSTATUS); + + while (irq_status) { + int hwirq = fls(irq_status) - 1; + int gpio_irq = irq_find_mapping(gpio->domain, hwirq); + + generic_handle_irq(gpio_irq); + irq_status &= ~BIT(hwirq); + + if ((irq_get_trigger_type(gpio_irq) & IRQ_TYPE_SENSE_MASK) + == IRQ_TYPE_EDGE_BOTH) + dwapb_toggle_trigger(gpio, hwirq); + } + + if (chip->irq_eoi) + chip->irq_eoi(irq_desc_get_irq_data(desc)); +} + +static void dwapb_irq_enable(struct irq_data *d) +{ + struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d); + struct dwapb_gpio *gpio = igc->private; + struct bgpio_chip *bgc = &gpio->ports[0].bgc; + unsigned long flags; + u32 val; + + spin_lock_irqsave(&bgc->lock, flags); + val = readl(gpio->regs + GPIO_INTEN); + val |= BIT(d->hwirq); + writel(val, gpio->regs + GPIO_INTEN); + spin_unlock_irqrestore(&bgc->lock, flags); +} + +static void dwapb_irq_disable(struct irq_data *d) +{ + struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d); + struct dwapb_gpio *gpio = igc->private; + struct bgpio_chip *bgc = &gpio->ports[0].bgc; + unsigned long flags; + u32 val; + + spin_lock_irqsave(&bgc->lock, flags); + val = readl(gpio->regs + GPIO_INTEN); + val &= ~BIT(d->hwirq); + writel(val, gpio->regs + GPIO_INTEN); + spin_unlock_irqrestore(&bgc->lock, flags); +} + +static int dwapb_irq_reqres(struct irq_data *d) +{ + struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d); + struct dwapb_gpio *gpio = igc->private; + struct bgpio_chip *bgc = &gpio->ports[0].bgc; + + if (gpio_lock_as_irq(&bgc->gc, irqd_to_hwirq(d))) { + dev_err(gpio->dev, "unable to lock HW IRQ %lu for IRQ\n", + irqd_to_hwirq(d)); + return -EINVAL; + } + return 0; +} + +static void dwapb_irq_relres(struct irq_data *d) +{ + struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d); + struct dwapb_gpio *gpio = igc->private; + struct bgpio_chip *bgc = &gpio->ports[0].bgc; + + gpio_unlock_as_irq(&bgc->gc, irqd_to_hwirq(d)); +} + +static int dwapb_irq_set_type(struct irq_data *d, u32 type) +{ + struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d); + struct dwapb_gpio *gpio = igc->private; + struct bgpio_chip *bgc = &gpio->ports[0].bgc; + int bit = d->hwirq; + unsigned long level, polarity, flags; + + if (type & ~(IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING | + IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) + return -EINVAL; + + spin_lock_irqsave(&bgc->lock, flags); + level = readl(gpio->regs + GPIO_INTTYPE_LEVEL); + polarity = readl(gpio->regs + GPIO_INT_POLARITY); + + switch (type) { + case IRQ_TYPE_EDGE_BOTH: + level |= BIT(bit); + dwapb_toggle_trigger(gpio, bit); + break; + case IRQ_TYPE_EDGE_RISING: + level |= BIT(bit); + polarity |= BIT(bit); + break; + case IRQ_TYPE_EDGE_FALLING: + level |= BIT(bit); + polarity &= ~BIT(bit); + break; + case IRQ_TYPE_LEVEL_HIGH: + level &= ~BIT(bit); + polarity |= BIT(bit); + break; + case IRQ_TYPE_LEVEL_LOW: + level &= ~BIT(bit); + polarity &= ~BIT(bit); + break; + } + + irq_setup_alt_chip(d, type); + + writel(level, gpio->regs + GPIO_INTTYPE_LEVEL); + writel(polarity, gpio->regs + GPIO_INT_POLARITY); + spin_unlock_irqrestore(&bgc->lock, flags); + + return 0; +} + +static void dwapb_configure_irqs(struct dwapb_gpio *gpio, + struct dwapb_gpio_port *port) +{ + struct gpio_chip *gc = &port->bgc.gc; + struct device_node *node = gc->of_node; + struct irq_chip_generic *irq_gc; + unsigned int hwirq, ngpio = gc->ngpio; + struct irq_chip_type *ct; + int err, irq, i; + + irq = irq_of_parse_and_map(node, 0); + if (!irq) { + dev_warn(gpio->dev, "no irq for bank %s\n", + port->bgc.gc.of_node->full_name); + return; + } + + gpio->domain = irq_domain_add_linear(node, ngpio, + &irq_generic_chip_ops, gpio); + if (!gpio->domain) + return; + + err = irq_alloc_domain_generic_chips(gpio->domain, ngpio, 2, + "gpio-dwapb", handle_level_irq, + IRQ_NOREQUEST, 0, + IRQ_GC_INIT_NESTED_LOCK); + if (err) { + dev_info(gpio->dev, "irq_alloc_domain_generic_chips failed\n"); + irq_domain_remove(gpio->domain); + gpio->domain = NULL; + return; + } + + irq_gc = irq_get_domain_generic_chip(gpio->domain, 0); + if (!irq_gc) { + irq_domain_remove(gpio->domain); + gpio->domain = NULL; + return; + } + + irq_gc->reg_base = gpio->regs; + irq_gc->private = gpio; + + for (i = 0; i < 2; i++) { + ct = &irq_gc->chip_types[i]; + ct->chip.irq_ack = irq_gc_ack_set_bit; + ct->chip.irq_mask = irq_gc_mask_set_bit; + ct->chip.irq_unmask = irq_gc_mask_clr_bit; + ct->chip.irq_set_type = dwapb_irq_set_type; + ct->chip.irq_enable = dwapb_irq_enable; + ct->chip.irq_disable = dwapb_irq_disable; + ct->chip.irq_request_resources = dwapb_irq_reqres; + ct->chip.irq_release_resources = dwapb_irq_relres; + ct->regs.ack = GPIO_PORTA_EOI; + ct->regs.mask = GPIO_INTMASK; + ct->type = IRQ_TYPE_LEVEL_MASK; + } + + irq_gc->chip_types[0].type = IRQ_TYPE_LEVEL_MASK; + irq_gc->chip_types[1].type = IRQ_TYPE_EDGE_BOTH; + irq_gc->chip_types[1].handler = handle_edge_irq; + + irq_set_chained_handler(irq, dwapb_irq_handler); + irq_set_handler_data(irq, gpio); + + for (hwirq = 0 ; hwirq < ngpio ; hwirq++) + irq_create_mapping(gpio->domain, hwirq); + + port->bgc.gc.to_irq = dwapb_gpio_to_irq; +} + +static void dwapb_irq_teardown(struct dwapb_gpio *gpio) +{ + struct dwapb_gpio_port *port = &gpio->ports[0]; + struct gpio_chip *gc = &port->bgc.gc; + unsigned int ngpio = gc->ngpio; + irq_hw_number_t hwirq; + + if (!gpio->domain) + return; + + for (hwirq = 0 ; hwirq < ngpio ; hwirq++) + irq_dispose_mapping(irq_find_mapping(gpio->domain, hwirq)); + + irq_domain_remove(gpio->domain); + gpio->domain = NULL; +} + +static int dwapb_gpio_add_port(struct dwapb_gpio *gpio, + struct device_node *port_np, + unsigned int offs) +{ + struct dwapb_gpio_port *port; + u32 port_idx, ngpio; + void __iomem *dat, *set, *dirout; + int err; + + if (of_property_read_u32(port_np, "reg", &port_idx) || + port_idx >= DWAPB_MAX_PORTS) { + dev_err(gpio->dev, "missing/invalid port index for %s\n", + port_np->full_name); + return -EINVAL; + } + + port = &gpio->ports[offs]; + port->gpio = gpio; + + if (of_property_read_u32(port_np, "snps,nr-gpios", &ngpio)) { + dev_info(gpio->dev, "failed to get number of gpios for %s\n", + port_np->full_name); + ngpio = 32; + } + + dat = gpio->regs + GPIO_EXT_PORTA + (port_idx * GPIO_EXT_PORT_SIZE); + set = gpio->regs + GPIO_SWPORTA_DR + (port_idx * GPIO_SWPORT_DR_SIZE); + dirout = gpio->regs + GPIO_SWPORTA_DDR + + (port_idx * GPIO_SWPORT_DDR_SIZE); + + err = bgpio_init(&port->bgc, gpio->dev, 4, dat, set, NULL, dirout, + NULL, false); + if (err) { + dev_err(gpio->dev, "failed to init gpio chip for %s\n", + port_np->full_name); + return err; + } + + port->bgc.gc.ngpio = ngpio; + port->bgc.gc.of_node = port_np; + + /* + * Only port A can provide interrupts in all configurations of the IP. + */ + if (port_idx == 0 && + of_property_read_bool(port_np, "interrupt-controller")) + dwapb_configure_irqs(gpio, port); + + err = gpiochip_add(&port->bgc.gc); + if (err) + dev_err(gpio->dev, "failed to register gpiochip for %s\n", + port_np->full_name); + else + port->is_registered = true; + + return err; +} + +static void dwapb_gpio_unregister(struct dwapb_gpio *gpio) +{ + unsigned int m; + + for (m = 0; m < gpio->nr_ports; ++m) + if (gpio->ports[m].is_registered) + WARN_ON(gpiochip_remove(&gpio->ports[m].bgc.gc)); +} + +static int dwapb_gpio_probe(struct platform_device *pdev) +{ + struct resource *res; + struct dwapb_gpio *gpio; + struct device_node *np; + int err; + unsigned int offs = 0; + + gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); + if (!gpio) + return -ENOMEM; + gpio->dev = &pdev->dev; + + gpio->nr_ports = of_get_child_count(pdev->dev.of_node); + if (!gpio->nr_ports) { + err = -EINVAL; + goto out_err; + } + gpio->ports = devm_kzalloc(&pdev->dev, gpio->nr_ports * + sizeof(*gpio->ports), GFP_KERNEL); + if (!gpio->ports) { + err = -ENOMEM; + goto out_err; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + gpio->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(gpio->regs)) { + err = PTR_ERR(gpio->regs); + goto out_err; + } + + for_each_child_of_node(pdev->dev.of_node, np) { + err = dwapb_gpio_add_port(gpio, np, offs++); + if (err) + goto out_unregister; + } + platform_set_drvdata(pdev, gpio); + + return 0; + +out_unregister: + dwapb_gpio_unregister(gpio); + dwapb_irq_teardown(gpio); + +out_err: + return err; +} + +static int dwapb_gpio_remove(struct platform_device *pdev) +{ + struct dwapb_gpio *gpio = platform_get_drvdata(pdev); + + dwapb_gpio_unregister(gpio); + dwapb_irq_teardown(gpio); + + return 0; +} + +static const struct of_device_id dwapb_of_match[] = { + { .compatible = "snps,dw-apb-gpio" }, + { /* Sentinel */ } +}; +MODULE_DEVICE_TABLE(of, dwapb_of_match); + +static struct platform_driver dwapb_gpio_driver = { + .driver = { + .name = "gpio-dwapb", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(dwapb_of_match), + }, + .probe = dwapb_gpio_probe, + .remove = dwapb_gpio_remove, +}; + +module_platform_driver(dwapb_gpio_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jamie Iles"); +MODULE_DESCRIPTION("Synopsys DesignWare APB GPIO driver"); diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index ec190361bf2..cde36054c38 100644 --- a/drivers/gpio/gpio-em.c +++ b/drivers/gpio/gpio-em.c @@ -99,6 +99,27 @@ static void em_gio_irq_enable(struct irq_data *d) em_gio_write(p, GIO_IEN, BIT(irqd_to_hwirq(d))); } +static int em_gio_irq_reqres(struct irq_data *d) +{ + struct em_gio_priv *p = irq_data_get_irq_chip_data(d); + + if (gpio_lock_as_irq(&p->gpio_chip, irqd_to_hwirq(d))) { + dev_err(p->gpio_chip.dev, + "unable to lock HW IRQ %lu for IRQ\n", + irqd_to_hwirq(d)); + return -EINVAL; + } + return 0; +} + +static void em_gio_irq_relres(struct irq_data *d) +{ + struct em_gio_priv *p = irq_data_get_irq_chip_data(d); + + gpio_unlock_as_irq(&p->gpio_chip, irqd_to_hwirq(d)); +} + + #define GIO_ASYNC(x) (x + 8) static unsigned char em_gio_sense_table[IRQ_TYPE_SENSE_MASK + 1] = { @@ -191,7 +212,7 @@ static void __em_gio_set(struct gpio_chip *chip, unsigned int reg, { /* upper 16 bits contains mask and lower 16 actual value */ em_gio_write(gpio_to_priv(chip), reg, - (1 << (shift + 16)) | (value << shift)); + (BIT(shift + 16)) | (value << shift)); } static void em_gio_set(struct gpio_chip *chip, unsigned offset, int value) @@ -263,7 +284,6 @@ static int em_gio_probe(struct platform_device *pdev) p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); if (!p) { - dev_err(&pdev->dev, "failed to allocate driver data\n"); ret = -ENOMEM; goto err0; } @@ -328,6 +348,7 @@ static int em_gio_probe(struct platform_device *pdev) gpio_chip->request = em_gio_request; gpio_chip->free = em_gio_free; gpio_chip->label = name; + gpio_chip->dev = &pdev->dev; gpio_chip->owner = THIS_MODULE; gpio_chip->base = pdata->gpio_base; gpio_chip->ngpio = pdata->number_of_pins; @@ -336,10 +357,10 @@ static int em_gio_probe(struct platform_device *pdev) irq_chip->name = name; irq_chip->irq_mask = em_gio_irq_disable; irq_chip->irq_unmask = em_gio_irq_enable; - irq_chip->irq_enable = em_gio_irq_enable; - irq_chip->irq_disable = em_gio_irq_disable; irq_chip->irq_set_type = em_gio_irq_set_type; - irq_chip->flags = IRQCHIP_SKIP_SET_WAKE; + irq_chip->irq_request_resources = em_gio_irq_reqres; + irq_chip->irq_release_resources = em_gio_irq_relres; + irq_chip->flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND; p->irq_domain = irq_domain_add_simple(pdev->dev.of_node, pdata->number_of_pins, diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c index 80829f3c654..dcc2bb4074e 100644 --- a/drivers/gpio/gpio-ep93xx.c +++ b/drivers/gpio/gpio-ep93xx.c @@ -344,37 +344,24 @@ static int ep93xx_gpio_probe(struct platform_device *pdev) { struct ep93xx_gpio *ep93xx_gpio; struct resource *res; - void __iomem *mmio; int i; - int ret; + struct device *dev = &pdev->dev; - ep93xx_gpio = kzalloc(sizeof(*ep93xx_gpio), GFP_KERNEL); + ep93xx_gpio = devm_kzalloc(dev, sizeof(struct ep93xx_gpio), GFP_KERNEL); if (!ep93xx_gpio) return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - ret = -ENXIO; - goto exit_free; - } - - if (!request_mem_region(res->start, resource_size(res), pdev->name)) { - ret = -EBUSY; - goto exit_free; - } - - mmio = ioremap(res->start, resource_size(res)); - if (!mmio) { - ret = -ENXIO; - goto exit_release; - } - ep93xx_gpio->mmio_base = mmio; + ep93xx_gpio->mmio_base = devm_ioremap_resource(dev, res); + if (IS_ERR(ep93xx_gpio->mmio_base)) + return PTR_ERR(ep93xx_gpio->mmio_base); for (i = 0; i < ARRAY_SIZE(ep93xx_gpio_banks); i++) { struct bgpio_chip *bgc = &ep93xx_gpio->bgc[i]; struct ep93xx_gpio_bank *bank = &ep93xx_gpio_banks[i]; - if (ep93xx_gpio_add_bank(bgc, &pdev->dev, mmio, bank)) + if (ep93xx_gpio_add_bank(bgc, &pdev->dev, + ep93xx_gpio->mmio_base, bank)) dev_warn(&pdev->dev, "Unable to add gpio bank %s\n", bank->label); } @@ -382,13 +369,6 @@ static int ep93xx_gpio_probe(struct platform_device *pdev) ep93xx_gpio_init_irq(); return 0; - -exit_release: - release_mem_region(res->start, resource_size(res)); -exit_free: - kfree(ep93xx_gpio); - dev_info(&pdev->dev, "%s failed with errno %d\n", __func__, ret); - return ret; } static struct platform_driver ep93xx_gpio_driver = { diff --git a/drivers/gpio/gpio-f7188x.c b/drivers/gpio/gpio-f7188x.c index 9cb8320e118..8f73ee09373 100644 --- a/drivers/gpio/gpio-f7188x.c +++ b/drivers/gpio/gpio-f7188x.c @@ -135,6 +135,7 @@ static void f7188x_gpio_set(struct gpio_chip *chip, unsigned offset, int value); .set = f7188x_gpio_set, \ .base = _base, \ .ngpio = _ngpio, \ + .can_sleep = true, \ }, \ .regbase = _regbase, \ } diff --git a/drivers/gpio/gpio-ge.c b/drivers/gpio/gpio-ge.c index 7b95a4a8318..1237a73c3c9 100644 --- a/drivers/gpio/gpio-ge.c +++ b/drivers/gpio/gpio-ge.c @@ -18,15 +18,9 @@ */ #include <linux/kernel.h> -#include <linux/compiler.h> -#include <linux/init.h> #include <linux/io.h> -#include <linux/of.h> #include <linux/of_device.h> -#include <linux/of_platform.h> #include <linux/of_gpio.h> -#include <linux/gpio.h> -#include <linux/slab.h> #include <linux/module.h> #define GEF_GPIO_DIRECT 0x00 @@ -39,28 +33,26 @@ #define GEF_GPIO_OVERRUN 0x1C #define GEF_GPIO_MODE 0x20 -static void _gef_gpio_set(void __iomem *reg, unsigned int offset, int value) +static void gef_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { + struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); unsigned int data; - data = ioread32be(reg); - /* value: 0=low; 1=high */ - if (value & 0x1) - data = data | (0x1 << offset); + data = ioread32be(mmchip->regs + GEF_GPIO_OUT); + if (value) + data = data | BIT(offset); else - data = data & ~(0x1 << offset); - - iowrite32be(data, reg); + data = data & ~BIT(offset); + iowrite32be(data, mmchip->regs + GEF_GPIO_OUT); } - static int gef_gpio_dir_in(struct gpio_chip *chip, unsigned offset) { unsigned int data; struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT); - data = data | (0x1 << offset); + data = data | BIT(offset); iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT); return 0; @@ -71,11 +63,11 @@ static int gef_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int value) unsigned int data; struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); - /* Set direction before switching to input */ - _gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value); + /* Set value before switching to output */ + gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value); data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT); - data = data & ~(0x1 << offset); + data = data & ~BIT(offset); iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT); return 0; @@ -83,116 +75,56 @@ static int gef_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int value) static int gef_gpio_get(struct gpio_chip *chip, unsigned offset) { - unsigned int data; - int state = 0; struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); - data = ioread32be(mmchip->regs + GEF_GPIO_IN); - state = (int)((data >> offset) & 0x1); - - return state; + return !!(ioread32be(mmchip->regs + GEF_GPIO_IN) & BIT(offset)); } -static void gef_gpio_set(struct gpio_chip *chip, unsigned offset, int value) -{ - struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); - - _gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value); -} +static const struct of_device_id gef_gpio_ids[] = { + { + .compatible = "gef,sbc610-gpio", + .data = (void *)19, + }, { + .compatible = "gef,sbc310-gpio", + .data = (void *)6, + }, { + .compatible = "ge,imp3a-gpio", + .data = (void *)16, + }, + { } +}; +MODULE_DEVICE_TABLE(of, gef_gpio_ids); -static int __init gef_gpio_init(void) +static int __init gef_gpio_probe(struct platform_device *pdev) { - struct device_node *np; - int retval; - struct of_mm_gpio_chip *gef_gpio_chip; - - for_each_compatible_node(np, NULL, "gef,sbc610-gpio") { - - pr_debug("%s: Initialising GEF GPIO\n", np->full_name); - - /* Allocate chip structure */ - gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL); - if (!gef_gpio_chip) { - pr_err("%s: Unable to allocate structure\n", - np->full_name); - continue; - } - - /* Setup pointers to chip functions */ - gef_gpio_chip->gc.of_gpio_n_cells = 2; - gef_gpio_chip->gc.ngpio = 19; - gef_gpio_chip->gc.direction_input = gef_gpio_dir_in; - gef_gpio_chip->gc.direction_output = gef_gpio_dir_out; - gef_gpio_chip->gc.get = gef_gpio_get; - gef_gpio_chip->gc.set = gef_gpio_set; - - /* This function adds a memory mapped GPIO chip */ - retval = of_mm_gpiochip_add(np, gef_gpio_chip); - if (retval) { - kfree(gef_gpio_chip); - pr_err("%s: Unable to add GPIO\n", np->full_name); - } - } - - for_each_compatible_node(np, NULL, "gef,sbc310-gpio") { - - pr_debug("%s: Initialising GEF GPIO\n", np->full_name); - - /* Allocate chip structure */ - gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL); - if (!gef_gpio_chip) { - pr_err("%s: Unable to allocate structure\n", - np->full_name); - continue; - } - - /* Setup pointers to chip functions */ - gef_gpio_chip->gc.of_gpio_n_cells = 2; - gef_gpio_chip->gc.ngpio = 6; - gef_gpio_chip->gc.direction_input = gef_gpio_dir_in; - gef_gpio_chip->gc.direction_output = gef_gpio_dir_out; - gef_gpio_chip->gc.get = gef_gpio_get; - gef_gpio_chip->gc.set = gef_gpio_set; - - /* This function adds a memory mapped GPIO chip */ - retval = of_mm_gpiochip_add(np, gef_gpio_chip); - if (retval) { - kfree(gef_gpio_chip); - pr_err("%s: Unable to add GPIO\n", np->full_name); - } - } - - for_each_compatible_node(np, NULL, "ge,imp3a-gpio") { - - pr_debug("%s: Initialising GE GPIO\n", np->full_name); - - /* Allocate chip structure */ - gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL); - if (!gef_gpio_chip) { - pr_err("%s: Unable to allocate structure\n", - np->full_name); - continue; - } - - /* Setup pointers to chip functions */ - gef_gpio_chip->gc.of_gpio_n_cells = 2; - gef_gpio_chip->gc.ngpio = 16; - gef_gpio_chip->gc.direction_input = gef_gpio_dir_in; - gef_gpio_chip->gc.direction_output = gef_gpio_dir_out; - gef_gpio_chip->gc.get = gef_gpio_get; - gef_gpio_chip->gc.set = gef_gpio_set; - - /* This function adds a memory mapped GPIO chip */ - retval = of_mm_gpiochip_add(np, gef_gpio_chip); - if (retval) { - kfree(gef_gpio_chip); - pr_err("%s: Unable to add GPIO\n", np->full_name); - } - } + const struct of_device_id *of_id = + of_match_device(gef_gpio_ids, &pdev->dev); + struct of_mm_gpio_chip *mmchip; + + mmchip = devm_kzalloc(&pdev->dev, sizeof(*mmchip), GFP_KERNEL); + if (!mmchip) + return -ENOMEM; + + /* Setup pointers to chip functions */ + mmchip->gc.ngpio = (u16)(uintptr_t)of_id->data; + mmchip->gc.of_gpio_n_cells = 2; + mmchip->gc.direction_input = gef_gpio_dir_in; + mmchip->gc.direction_output = gef_gpio_dir_out; + mmchip->gc.get = gef_gpio_get; + mmchip->gc.set = gef_gpio_set; + + /* This function adds a memory mapped GPIO chip */ + return of_mm_gpiochip_add(pdev->dev.of_node, mmchip); +}; - return 0; +static struct platform_driver gef_gpio_driver = { + .driver = { + .name = "gef-gpio", + .owner = THIS_MODULE, + .of_match_table = gef_gpio_ids, + }, }; -arch_initcall(gef_gpio_init); +module_platform_driver_probe(gef_gpio_driver, gef_gpio_probe); MODULE_DESCRIPTION("GE I/O FPGA GPIO driver"); MODULE_AUTHOR("Martyn Welch <martyn.welch@ge.com"); diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c index d2196bf7384..fea8c82bb8f 100644 --- a/drivers/gpio/gpio-generic.c +++ b/drivers/gpio/gpio-generic.c @@ -139,7 +139,7 @@ static int bgpio_get(struct gpio_chip *gc, unsigned int gpio) { struct bgpio_chip *bgc = to_bgpio_chip(gc); - return bgc->read_reg(bgc->reg_dat) & bgc->pin2mask(bgc, gpio); + return !!(bgc->read_reg(bgc->reg_dat) & bgc->pin2mask(bgc, gpio)); } static void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) @@ -388,6 +388,14 @@ static int bgpio_setup_direction(struct bgpio_chip *bgc, return 0; } +static int bgpio_request(struct gpio_chip *chip, unsigned gpio_pin) +{ + if (gpio_pin < chip->ngpio) + return 0; + + return -EINVAL; +} + int bgpio_remove(struct bgpio_chip *bgc) { return gpiochip_remove(&bgc->gc); @@ -413,6 +421,7 @@ int bgpio_init(struct bgpio_chip *bgc, struct device *dev, bgc->gc.label = dev_name(dev); bgc->gc.base = -1; bgc->gc.ngpio = bgc->bits; + bgc->gc.request = bgpio_request; ret = bgpio_setup_io(bgc, dat, set, clr); if (ret) @@ -488,7 +497,7 @@ static int bgpio_pdev_probe(struct platform_device *pdev) void __iomem *dirout; void __iomem *dirin; unsigned long sz; - unsigned long flags = 0; + unsigned long flags = pdev->id_entry->driver_data; int err; struct bgpio_chip *bgc; struct bgpio_pdata *pdata = dev_get_platdata(dev); @@ -519,9 +528,6 @@ static int bgpio_pdev_probe(struct platform_device *pdev) if (err) return err; - if (!strcmp(platform_get_device_id(pdev)->name, "basic-mmio-gpio-be")) - flags |= BGPIOF_BIG_ENDIAN; - bgc = devm_kzalloc(&pdev->dev, sizeof(*bgc), GFP_KERNEL); if (!bgc) return -ENOMEM; @@ -531,6 +537,8 @@ static int bgpio_pdev_probe(struct platform_device *pdev) return err; if (pdata) { + if (pdata->label) + bgc->gc.label = pdata->label; bgc->gc.base = pdata->base; if (pdata->ngpio > 0) bgc->gc.ngpio = pdata->ngpio; @@ -549,9 +557,14 @@ static int bgpio_pdev_remove(struct platform_device *pdev) } static const struct platform_device_id bgpio_id_table[] = { - { "basic-mmio-gpio", }, - { "basic-mmio-gpio-be", }, - {}, + { + .name = "basic-mmio-gpio", + .driver_data = 0, + }, { + .name = "basic-mmio-gpio-be", + .driver_data = BGPIOF_BIG_ENDIAN, + }, + { } }; MODULE_DEVICE_TABLE(platform, bgpio_id_table); diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c index 84d2478ec29..3c3f515b791 100644 --- a/drivers/gpio/gpio-grgpio.c +++ b/drivers/gpio/gpio-grgpio.c @@ -481,7 +481,7 @@ out: return ret; } -static struct of_device_id grgpio_match[] = { +static const struct of_device_id grgpio_match[] = { {.name = "GAISLER_GPIO"}, {.name = "01_01a"}, {}, diff --git a/drivers/gpio/gpio-ich.c b/drivers/gpio/gpio-ich.c index 814addb62d2..70304220a47 100644 --- a/drivers/gpio/gpio-ich.c +++ b/drivers/gpio/gpio-ich.c @@ -1,5 +1,5 @@ /* - * Intel ICH6-10, Series 5 and 6 GPIO driver + * Intel ICH6-10, Series 5 and 6, Atom C2000 (Avoton/Rangeley) GPIO driver * * Copyright (C) 2010 Extreme Engineering Solutions. * @@ -55,6 +55,16 @@ static const u8 ichx_reglen[3] = { 0x30, 0x10, 0x10, }; +static const u8 avoton_regs[4][3] = { + {0x00, 0x80, 0x00}, + {0x04, 0x84, 0x00}, + {0x08, 0x88, 0x00}, +}; + +static const u8 avoton_reglen[3] = { + 0x10, 0x10, 0x00, +}; + #define ICHX_WRITE(val, reg, base_res) outl(val, (reg) + (base_res)->start) #define ICHX_READ(reg, base_res) inl((reg) + (base_res)->start) @@ -62,6 +72,13 @@ struct ichx_desc { /* Max GPIO pins the chipset can have */ uint ngpio; + /* chipset registers */ + const u8 (*regs)[3]; + const u8 *reglen; + + /* GPO_BLINK is available on this chipset */ + bool have_blink; + /* Whether the chipset has GPIO in GPE0_STS in the PM IO region */ bool uses_gpe0; @@ -71,6 +88,12 @@ struct ichx_desc { /* Some chipsets have quirks, let these use their own request/get */ int (*request)(struct gpio_chip *chip, unsigned offset); int (*get)(struct gpio_chip *chip, unsigned offset); + + /* + * Some chipsets don't let reading output values on GPIO_LVL register + * this option allows driver caching written output values + */ + bool use_outlvl_cache; }; static struct { @@ -82,6 +105,7 @@ static struct { struct ichx_desc *desc; /* Pointer to chipset-specific description */ u32 orig_gpio_ctrl; /* Orig CTRL value, used to restore on exit */ u8 use_gpio; /* Which GPIO groups are usable */ + int outlvl_cache[3]; /* cached output values */ } ichx_priv; static int modparam_gpiobase = -1; /* dynamic */ @@ -99,13 +123,23 @@ static int ichx_write_bit(int reg, unsigned nr, int val, int verify) spin_lock_irqsave(&ichx_priv.lock, flags); - data = ICHX_READ(ichx_regs[reg][reg_nr], ichx_priv.gpio_base); + if (reg == GPIO_LVL && ichx_priv.desc->use_outlvl_cache) + data = ichx_priv.outlvl_cache[reg_nr]; + else + data = ICHX_READ(ichx_priv.desc->regs[reg][reg_nr], + ichx_priv.gpio_base); + if (val) data |= 1 << bit; else data &= ~(1 << bit); - ICHX_WRITE(data, ichx_regs[reg][reg_nr], ichx_priv.gpio_base); - tmp = ICHX_READ(ichx_regs[reg][reg_nr], ichx_priv.gpio_base); + ICHX_WRITE(data, ichx_priv.desc->regs[reg][reg_nr], + ichx_priv.gpio_base); + if (reg == GPIO_LVL && ichx_priv.desc->use_outlvl_cache) + ichx_priv.outlvl_cache[reg_nr] = data; + + tmp = ICHX_READ(ichx_priv.desc->regs[reg][reg_nr], + ichx_priv.gpio_base); if (verify && data != tmp) ret = -EPERM; @@ -123,7 +157,11 @@ static int ichx_read_bit(int reg, unsigned nr) spin_lock_irqsave(&ichx_priv.lock, flags); - data = ICHX_READ(ichx_regs[reg][reg_nr], ichx_priv.gpio_base); + data = ICHX_READ(ichx_priv.desc->regs[reg][reg_nr], + ichx_priv.gpio_base); + + if (reg == GPIO_LVL && ichx_priv.desc->use_outlvl_cache) + data = ichx_priv.outlvl_cache[reg_nr] | data; spin_unlock_irqrestore(&ichx_priv.lock, flags); @@ -151,7 +189,7 @@ static int ichx_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, int val) { /* Disable blink hardware which is available for GPIOs from 0 to 31. */ - if (nr < 32) + if (nr < 32 && ichx_priv.desc->have_blink) ichx_write_bit(GPO_BLINK, nr, 0, 0); /* Set GPIO output value. */ @@ -252,7 +290,7 @@ static void ichx_gpiolib_setup(struct gpio_chip *chip) chip->direction_output = ichx_gpio_direction_output; chip->base = modparam_gpiobase; chip->ngpio = ichx_priv.desc->ngpio; - chip->can_sleep = 0; + chip->can_sleep = false; chip->dbg_show = NULL; } @@ -266,6 +304,9 @@ static struct ichx_desc ich6_desc = { .uses_gpe0 = true, .ngpio = 50, + .have_blink = true, + .regs = ichx_regs, + .reglen = ichx_reglen, }; /* Intel 3100 */ @@ -285,29 +326,56 @@ static struct ichx_desc i3100_desc = { .uses_gpe0 = true, .ngpio = 50, + .regs = ichx_regs, + .reglen = ichx_reglen, }; /* ICH7 and ICH8-based */ static struct ichx_desc ich7_desc = { .ngpio = 50, + .have_blink = true, + .regs = ichx_regs, + .reglen = ichx_reglen, }; /* ICH9-based */ static struct ichx_desc ich9_desc = { .ngpio = 61, + .have_blink = true, + .regs = ichx_regs, + .reglen = ichx_reglen, }; /* ICH10-based - Consumer/corporate versions have different amount of GPIO */ static struct ichx_desc ich10_cons_desc = { .ngpio = 61, + .have_blink = true, + .regs = ichx_regs, + .reglen = ichx_reglen, }; static struct ichx_desc ich10_corp_desc = { .ngpio = 72, + .have_blink = true, + .regs = ichx_regs, + .reglen = ichx_reglen, }; /* Intel 5 series, 6 series, 3400 series, and C200 series */ static struct ichx_desc intel5_desc = { .ngpio = 76, + .regs = ichx_regs, + .reglen = ichx_reglen, +}; + +/* Avoton */ +static struct ichx_desc avoton_desc = { + /* Avoton has only 59 GPIOs, but we assume the first set of register + * (Core) has 32 instead of 31 to keep gpio-ich compliance + */ + .ngpio = 60, + .regs = avoton_regs, + .reglen = avoton_reglen, + .use_outlvl_cache = true, }; static int ichx_gpio_request_regions(struct resource *res_base, @@ -318,11 +386,12 @@ static int ichx_gpio_request_regions(struct resource *res_base, if (!res_base || !res_base->start || !res_base->end) return -ENODEV; - for (i = 0; i < ARRAY_SIZE(ichx_regs[0]); i++) { + for (i = 0; i < ARRAY_SIZE(ichx_priv.desc->regs[0]); i++) { if (!(use_gpio & (1 << i))) continue; - if (!request_region(res_base->start + ichx_regs[0][i], - ichx_reglen[i], name)) + if (!request_region( + res_base->start + ichx_priv.desc->regs[0][i], + ichx_priv.desc->reglen[i], name)) goto request_err; } return 0; @@ -332,8 +401,8 @@ request_err: for (i--; i >= 0; i--) { if (!(use_gpio & (1 << i))) continue; - release_region(res_base->start + ichx_regs[0][i], - ichx_reglen[i]); + release_region(res_base->start + ichx_priv.desc->regs[0][i], + ichx_priv.desc->reglen[i]); } return -EBUSY; } @@ -342,11 +411,11 @@ static void ichx_gpio_release_regions(struct resource *res_base, u8 use_gpio) { int i; - for (i = 0; i < ARRAY_SIZE(ichx_regs[0]); i++) { + for (i = 0; i < ARRAY_SIZE(ichx_priv.desc->regs[0]); i++) { if (!(use_gpio & (1 << i))) continue; - release_region(res_base->start + ichx_regs[0][i], - ichx_reglen[i]); + release_region(res_base->start + ichx_priv.desc->regs[0][i], + ichx_priv.desc->reglen[i]); } } @@ -383,6 +452,9 @@ static int ichx_gpio_probe(struct platform_device *pdev) case ICH_V10CONS_GPIO: ichx_priv.desc = &ich10_cons_desc; break; + case AVOTON_GPIO: + ichx_priv.desc = &avoton_desc; + break; default: return -ENODEV; } diff --git a/drivers/gpio/gpio-intel-mid.c b/drivers/gpio/gpio-intel-mid.c index be803af658a..118a6bf455d 100644 --- a/drivers/gpio/gpio-intel-mid.c +++ b/drivers/gpio/gpio-intel-mid.c @@ -1,7 +1,7 @@ /* - * Moorestown platform Langwell chip GPIO driver + * Intel MID GPIO driver * - * Copyright (c) 2008, 2009, 2013, Intel Corporation. + * Copyright (c) 2008-2014 Intel Corporation. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -11,10 +11,6 @@ * 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, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Supports: @@ -235,11 +231,33 @@ static void intel_mid_irq_mask(struct irq_data *d) { } +static int intel_mid_irq_reqres(struct irq_data *d) +{ + struct intel_mid_gpio *priv = irq_data_get_irq_chip_data(d); + + if (gpio_lock_as_irq(&priv->chip, irqd_to_hwirq(d))) { + dev_err(priv->chip.dev, + "unable to lock HW IRQ %lu for IRQ\n", + irqd_to_hwirq(d)); + return -EINVAL; + } + return 0; +} + +static void intel_mid_irq_relres(struct irq_data *d) +{ + struct intel_mid_gpio *priv = irq_data_get_irq_chip_data(d); + + gpio_unlock_as_irq(&priv->chip, irqd_to_hwirq(d)); +} + static struct irq_chip intel_mid_irqchip = { .name = "INTEL_MID-GPIO", .irq_mask = intel_mid_irq_mask, .irq_unmask = intel_mid_irq_unmask, .irq_set_type = intel_mid_irq_type, + .irq_request_resources = intel_mid_irq_reqres, + .irq_release_resources = intel_mid_irq_relres, }; static const struct intel_mid_gpio_ddata gpio_lincroft = { @@ -275,7 +293,7 @@ static const struct intel_mid_gpio_ddata gpio_tangier = { .chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE, }; -static DEFINE_PCI_DEVICE_TABLE(intel_gpio_ids) = { +static const struct pci_device_id intel_gpio_ids[] = { { /* Lincroft */ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080f), @@ -358,8 +376,7 @@ static int intel_gpio_irq_map(struct irq_domain *d, unsigned int irq, { struct intel_mid_gpio *priv = d->host_data; - irq_set_chip_and_handler_name(irq, &intel_mid_irqchip, - handle_simple_irq, "demux"); + irq_set_chip_and_handler(irq, &intel_mid_irqchip, handle_simple_irq); irq_set_chip_data(irq, priv); irq_set_irq_type(irq, IRQ_TYPE_NONE); @@ -373,8 +390,8 @@ static const struct irq_domain_ops intel_gpio_irq_ops = { static int intel_gpio_runtime_idle(struct device *dev) { - pm_schedule_suspend(dev, 500); - return -EBUSY; + int err = pm_schedule_suspend(dev, 500); + return err ?: -EBUSY; } static const struct dev_pm_ops intel_gpio_pm_ops = { @@ -418,6 +435,7 @@ static int intel_gpio_probe(struct pci_dev *pdev, priv->reg_base = pcim_iomap_table(pdev)[0]; priv->chip.label = dev_name(&pdev->dev); + priv->chip.dev = &pdev->dev; priv->chip.request = intel_gpio_request; priv->chip.direction_input = intel_gpio_direction_input; priv->chip.direction_output = intel_gpio_direction_output; @@ -426,7 +444,7 @@ static int intel_gpio_probe(struct pci_dev *pdev, priv->chip.to_irq = intel_gpio_to_irq; priv->chip.base = gpio_base; priv->chip.ngpio = ddata->ngpio; - priv->chip.can_sleep = 0; + priv->chip.can_sleep = false; priv->pdev = pdev; spin_lock_init(&priv->lock); diff --git a/drivers/gpio/gpio-iop.c b/drivers/gpio/gpio-iop.c index c22a61be3a9..0a5e9d3f308 100644 --- a/drivers/gpio/gpio-iop.c +++ b/drivers/gpio/gpio-iop.c @@ -111,6 +111,8 @@ static int iop3xx_gpio_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); return gpiochip_add(&iop3xx_chip); } diff --git a/drivers/gpio/gpio-janz-ttl.c b/drivers/gpio/gpio-janz-ttl.c index 2ecd3a09c74..42852eaaf02 100644 --- a/drivers/gpio/gpio-janz-ttl.c +++ b/drivers/gpio/gpio-janz-ttl.c @@ -152,34 +152,21 @@ static int ttl_probe(struct platform_device *pdev) pdata = dev_get_platdata(&pdev->dev); if (!pdata) { dev_err(dev, "no platform data\n"); - ret = -ENXIO; - goto out_return; + return -ENXIO; } - mod = kzalloc(sizeof(*mod), GFP_KERNEL); - if (!mod) { - dev_err(dev, "unable to allocate private data\n"); - ret = -ENOMEM; - goto out_return; - } + mod = devm_kzalloc(dev, sizeof(*mod), GFP_KERNEL); + if (!mod) + return -ENOMEM; platform_set_drvdata(pdev, mod); spin_lock_init(&mod->lock); /* get access to the MODULbus registers for this module */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "MODULbus registers not found\n"); - ret = -ENODEV; - goto out_free_mod; - } - - mod->regs = ioremap(res->start, resource_size(res)); - if (!mod->regs) { - dev_err(dev, "MODULbus registers not ioremap\n"); - ret = -ENOMEM; - goto out_free_mod; - } + mod->regs = devm_ioremap_resource(dev, res); + if (IS_ERR(mod->regs)) + return PTR_ERR(mod->regs); ttl_setup_device(mod); @@ -198,17 +185,10 @@ static int ttl_probe(struct platform_device *pdev) ret = gpiochip_add(gpio); if (ret) { dev_err(dev, "unable to add GPIO chip\n"); - goto out_iounmap_regs; + return ret; } return 0; - -out_iounmap_regs: - iounmap(mod->regs); -out_free_mod: - kfree(mod); -out_return: - return ret; } static int ttl_remove(struct platform_device *pdev) @@ -223,8 +203,6 @@ static int ttl_remove(struct platform_device *pdev) return ret; } - iounmap(mod->regs); - kfree(mod); return 0; } diff --git a/drivers/gpio/gpio-kempld.c b/drivers/gpio/gpio-kempld.c index efdc3924d7d..1e5e51987d3 100644 --- a/drivers/gpio/gpio-kempld.c +++ b/drivers/gpio/gpio-kempld.c @@ -24,7 +24,7 @@ #include <linux/mfd/kempld.h> #define KEMPLD_GPIO_MAX_NUM 16 -#define KEMPLD_GPIO_MASK(x) (1 << ((x) % 8)) +#define KEMPLD_GPIO_MASK(x) (BIT((x) % 8)) #define KEMPLD_GPIO_DIR_NUM(x) (0x40 + (x) / 8) #define KEMPLD_GPIO_LVL_NUM(x) (0x42 + (x) / 8) #define KEMPLD_GPIO_EVT_LVL_EDGE 0x46 @@ -167,7 +167,7 @@ static int kempld_gpio_probe(struct platform_device *pdev) chip->label = "gpio-kempld"; chip->owner = THIS_MODULE; chip->dev = dev; - chip->can_sleep = 1; + chip->can_sleep = true; if (pdata && pdata->gpio_base) chip->base = pdata->gpio_base; else @@ -216,4 +216,4 @@ module_platform_driver(kempld_gpio_driver); MODULE_DESCRIPTION("KEM PLD GPIO Driver"); MODULE_AUTHOR("Michael Brunner <michael.brunner@kontron.com>"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:gpio-kempld"); +MODULE_ALIAS("platform:kempld-gpio"); diff --git a/drivers/gpio/gpio-ks8695.c b/drivers/gpio/gpio-ks8695.c index a3ac66ea364..464a83de0d6 100644 --- a/drivers/gpio/gpio-ks8695.c +++ b/drivers/gpio/gpio-ks8695.c @@ -228,7 +228,7 @@ static struct gpio_chip ks8695_gpio_chip = { .to_irq = ks8695_gpio_to_irq, .base = 0, .ngpio = 16, - .can_sleep = 0, + .can_sleep = false, }; /* Register the GPIOs */ diff --git a/drivers/gpio/gpio-lp3943.c b/drivers/gpio/gpio-lp3943.c new file mode 100644 index 00000000000..a0341c92bcb --- /dev/null +++ b/drivers/gpio/gpio-lp3943.c @@ -0,0 +1,242 @@ +/* + * TI/National Semiconductor LP3943 GPIO driver + * + * Copyright 2013 Texas Instruments + * + * Author: Milo Kim <milo.kim@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2. + */ + +#include <linux/bitops.h> +#include <linux/err.h> +#include <linux/gpio.h> +#include <linux/i2c.h> +#include <linux/mfd/lp3943.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +enum lp3943_gpios { + LP3943_GPIO1, + LP3943_GPIO2, + LP3943_GPIO3, + LP3943_GPIO4, + LP3943_GPIO5, + LP3943_GPIO6, + LP3943_GPIO7, + LP3943_GPIO8, + LP3943_GPIO9, + LP3943_GPIO10, + LP3943_GPIO11, + LP3943_GPIO12, + LP3943_GPIO13, + LP3943_GPIO14, + LP3943_GPIO15, + LP3943_GPIO16, + LP3943_MAX_GPIO, +}; + +struct lp3943_gpio { + struct gpio_chip chip; + struct lp3943 *lp3943; + u16 input_mask; /* 1 = GPIO is input direction, 0 = output */ +}; + +static inline struct lp3943_gpio *to_lp3943_gpio(struct gpio_chip *_chip) +{ + return container_of(_chip, struct lp3943_gpio, chip); +} + +static int lp3943_gpio_request(struct gpio_chip *chip, unsigned offset) +{ + struct lp3943_gpio *lp3943_gpio = to_lp3943_gpio(chip); + struct lp3943 *lp3943 = lp3943_gpio->lp3943; + + /* Return an error if the pin is already assigned */ + if (test_and_set_bit(offset, &lp3943->pin_used)) + return -EBUSY; + + return 0; +} + +static void lp3943_gpio_free(struct gpio_chip *chip, unsigned offset) +{ + struct lp3943_gpio *lp3943_gpio = to_lp3943_gpio(chip); + struct lp3943 *lp3943 = lp3943_gpio->lp3943; + + clear_bit(offset, &lp3943->pin_used); +} + +static int lp3943_gpio_set_mode(struct lp3943_gpio *lp3943_gpio, u8 offset, + u8 val) +{ + struct lp3943 *lp3943 = lp3943_gpio->lp3943; + const struct lp3943_reg_cfg *mux = lp3943->mux_cfg; + + return lp3943_update_bits(lp3943, mux[offset].reg, mux[offset].mask, + val << mux[offset].shift); +} + +static int lp3943_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + struct lp3943_gpio *lp3943_gpio = to_lp3943_gpio(chip); + + lp3943_gpio->input_mask |= BIT(offset); + + return lp3943_gpio_set_mode(lp3943_gpio, offset, LP3943_GPIO_IN); +} + +static int lp3943_get_gpio_in_status(struct lp3943_gpio *lp3943_gpio, + struct gpio_chip *chip, unsigned offset) +{ + u8 addr, read; + int err; + + switch (offset) { + case LP3943_GPIO1 ... LP3943_GPIO8: + addr = LP3943_REG_GPIO_A; + break; + case LP3943_GPIO9 ... LP3943_GPIO16: + addr = LP3943_REG_GPIO_B; + offset = offset - 8; + break; + default: + return -EINVAL; + } + + err = lp3943_read_byte(lp3943_gpio->lp3943, addr, &read); + if (err) + return err; + + return !!(read & BIT(offset)); +} + +static int lp3943_get_gpio_out_status(struct lp3943_gpio *lp3943_gpio, + struct gpio_chip *chip, unsigned offset) +{ + struct lp3943 *lp3943 = lp3943_gpio->lp3943; + const struct lp3943_reg_cfg *mux = lp3943->mux_cfg; + u8 read; + int err; + + err = lp3943_read_byte(lp3943, mux[offset].reg, &read); + if (err) + return err; + + read = (read & mux[offset].mask) >> mux[offset].shift; + + if (read == LP3943_GPIO_OUT_HIGH) + return 1; + else if (read == LP3943_GPIO_OUT_LOW) + return 0; + else + return -EINVAL; +} + +static int lp3943_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct lp3943_gpio *lp3943_gpio = to_lp3943_gpio(chip); + + /* + * Limitation: + * LP3943 doesn't have the GPIO direction register. It provides + * only input and output status registers. + * So, direction info is required to handle the 'get' operation. + * This variable is updated whenever the direction is changed and + * it is used here. + */ + + if (lp3943_gpio->input_mask & BIT(offset)) + return lp3943_get_gpio_in_status(lp3943_gpio, chip, offset); + else + return lp3943_get_gpio_out_status(lp3943_gpio, chip, offset); +} + +static void lp3943_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct lp3943_gpio *lp3943_gpio = to_lp3943_gpio(chip); + u8 data; + + if (value) + data = LP3943_GPIO_OUT_HIGH; + else + data = LP3943_GPIO_OUT_LOW; + + lp3943_gpio_set_mode(lp3943_gpio, offset, data); +} + +static int lp3943_gpio_direction_output(struct gpio_chip *chip, unsigned offset, + int value) +{ + struct lp3943_gpio *lp3943_gpio = to_lp3943_gpio(chip); + + lp3943_gpio_set(chip, offset, value); + lp3943_gpio->input_mask &= ~BIT(offset); + + return 0; +} + +static const struct gpio_chip lp3943_gpio_chip = { + .label = "lp3943", + .owner = THIS_MODULE, + .request = lp3943_gpio_request, + .free = lp3943_gpio_free, + .direction_input = lp3943_gpio_direction_input, + .get = lp3943_gpio_get, + .direction_output = lp3943_gpio_direction_output, + .set = lp3943_gpio_set, + .base = -1, + .ngpio = LP3943_MAX_GPIO, + .can_sleep = 1, +}; + +static int lp3943_gpio_probe(struct platform_device *pdev) +{ + struct lp3943 *lp3943 = dev_get_drvdata(pdev->dev.parent); + struct lp3943_gpio *lp3943_gpio; + + lp3943_gpio = devm_kzalloc(&pdev->dev, sizeof(*lp3943_gpio), + GFP_KERNEL); + if (!lp3943_gpio) + return -ENOMEM; + + lp3943_gpio->lp3943 = lp3943; + lp3943_gpio->chip = lp3943_gpio_chip; + lp3943_gpio->chip.dev = &pdev->dev; + + platform_set_drvdata(pdev, lp3943_gpio); + + return gpiochip_add(&lp3943_gpio->chip); +} + +static int lp3943_gpio_remove(struct platform_device *pdev) +{ + struct lp3943_gpio *lp3943_gpio = platform_get_drvdata(pdev); + + return gpiochip_remove(&lp3943_gpio->chip); +} + +static const struct of_device_id lp3943_gpio_of_match[] = { + { .compatible = "ti,lp3943-gpio", }, + { } +}; +MODULE_DEVICE_TABLE(of, lp3943_gpio_of_match); + +static struct platform_driver lp3943_gpio_driver = { + .probe = lp3943_gpio_probe, + .remove = lp3943_gpio_remove, + .driver = { + .name = "lp3943-gpio", + .owner = THIS_MODULE, + .of_match_table = lp3943_gpio_of_match, + }, +}; +module_platform_driver(lp3943_gpio_driver); + +MODULE_DESCRIPTION("LP3943 GPIO driver"); +MODULE_ALIAS("platform:lp3943-gpio"); +MODULE_AUTHOR("Milo Kim"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-lpc32xx.c b/drivers/gpio/gpio-lpc32xx.c index 2d5555decf0..225344d6640 100644 --- a/drivers/gpio/gpio-lpc32xx.c +++ b/drivers/gpio/gpio-lpc32xx.c @@ -25,10 +25,10 @@ #include <linux/of_gpio.h> #include <linux/platform_device.h> #include <linux/module.h> +#include <linux/platform_data/gpio-lpc32xx.h> #include <mach/hardware.h> #include <mach/platform.h> -#include <mach/gpio-lpc32xx.h> #include <mach/irqs.h> #define LPC32XX_GPIO_P3_INP_STATE _GPREG(0x000) @@ -448,7 +448,7 @@ static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = { .base = LPC32XX_GPIO_P0_GRP, .ngpio = LPC32XX_GPIO_P0_MAX, .names = gpio_p0_names, - .can_sleep = 0, + .can_sleep = false, }, .gpio_grp = &gpio_grp_regs_p0, }, @@ -464,7 +464,7 @@ static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = { .base = LPC32XX_GPIO_P1_GRP, .ngpio = LPC32XX_GPIO_P1_MAX, .names = gpio_p1_names, - .can_sleep = 0, + .can_sleep = false, }, .gpio_grp = &gpio_grp_regs_p1, }, @@ -479,7 +479,7 @@ static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = { .base = LPC32XX_GPIO_P2_GRP, .ngpio = LPC32XX_GPIO_P2_MAX, .names = gpio_p2_names, - .can_sleep = 0, + .can_sleep = false, }, .gpio_grp = &gpio_grp_regs_p2, }, @@ -495,7 +495,7 @@ static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = { .base = LPC32XX_GPIO_P3_GRP, .ngpio = LPC32XX_GPIO_P3_MAX, .names = gpio_p3_names, - .can_sleep = 0, + .can_sleep = false, }, .gpio_grp = &gpio_grp_regs_p3, }, @@ -509,7 +509,7 @@ static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = { .base = LPC32XX_GPI_P3_GRP, .ngpio = LPC32XX_GPI_P3_MAX, .names = gpi_p3_names, - .can_sleep = 0, + .can_sleep = false, }, .gpio_grp = &gpio_grp_regs_p3, }, @@ -523,7 +523,7 @@ static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = { .base = LPC32XX_GPO_P3_GRP, .ngpio = LPC32XX_GPO_P3_MAX, .names = gpo_p3_names, - .can_sleep = 0, + .can_sleep = false, }, .gpio_grp = &gpio_grp_regs_p3, }, diff --git a/drivers/gpio/gpio-lynxpoint.c b/drivers/gpio/gpio-lynxpoint.c index a0804740a0b..2bea89b7250 100644 --- a/drivers/gpio/gpio-lynxpoint.c +++ b/drivers/gpio/gpio-lynxpoint.c @@ -188,7 +188,7 @@ static int lp_irq_type(struct irq_data *d, unsigned type) static int lp_gpio_get(struct gpio_chip *chip, unsigned offset) { unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1); - return inl(reg) & IN_LVL_BIT; + return !!(inl(reg) & IN_LVL_BIT); } static void lp_gpio_set(struct gpio_chip *chip, unsigned offset, int value) @@ -301,6 +301,26 @@ static void lp_irq_disable(struct irq_data *d) spin_unlock_irqrestore(&lg->lock, flags); } +static int lp_irq_reqres(struct irq_data *d) +{ + struct lp_gpio *lg = irq_data_get_irq_chip_data(d); + + if (gpio_lock_as_irq(&lg->chip, irqd_to_hwirq(d))) { + dev_err(lg->chip.dev, + "unable to lock HW IRQ %lu for IRQ\n", + irqd_to_hwirq(d)); + return -EINVAL; + } + return 0; +} + +static void lp_irq_relres(struct irq_data *d) +{ + struct lp_gpio *lg = irq_data_get_irq_chip_data(d); + + gpio_unlock_as_irq(&lg->chip, irqd_to_hwirq(d)); +} + static struct irq_chip lp_irqchip = { .name = "LP-GPIO", .irq_mask = lp_irq_mask, @@ -308,6 +328,8 @@ static struct irq_chip lp_irqchip = { .irq_enable = lp_irq_enable, .irq_disable = lp_irq_disable, .irq_set_type = lp_irq_type, + .irq_request_resources = lp_irq_reqres, + .irq_release_resources = lp_irq_relres, .flags = IRQCHIP_SKIP_SET_WAKE, }; @@ -331,8 +353,7 @@ static int lp_gpio_irq_map(struct irq_domain *d, unsigned int irq, { struct lp_gpio *lg = d->host_data; - irq_set_chip_and_handler_name(irq, &lp_irqchip, handle_simple_irq, - "demux"); + irq_set_chip_and_handler(irq, &lp_irqchip, handle_simple_irq); irq_set_chip_data(irq, lg); irq_set_irq_type(irq, IRQ_TYPE_NONE); @@ -354,10 +375,8 @@ static int lp_gpio_probe(struct platform_device *pdev) int ret = -ENODEV; lg = devm_kzalloc(dev, sizeof(struct lp_gpio), GFP_KERNEL); - if (!lg) { - dev_err(dev, "can't allocate lp_gpio chip data\n"); + if (!lg) return -ENOMEM; - } lg->pdev = pdev; platform_set_drvdata(pdev, lg); @@ -392,7 +411,7 @@ static int lp_gpio_probe(struct platform_device *pdev) gc->set = lp_gpio_set; gc->base = -1; gc->ngpio = LP_NUM_GPIO; - gc->can_sleep = 0; + gc->can_sleep = false; gc->dev = dev; /* set up interrupts */ @@ -438,6 +457,7 @@ static const struct dev_pm_ops lp_gpio_pm_ops = { static const struct acpi_device_id lynxpoint_gpio_acpi_match[] = { { "INT33C7", 0 }, + { "INT3437", 0 }, { } }; MODULE_DEVICE_TABLE(acpi, lynxpoint_gpio_acpi_match); @@ -469,4 +489,15 @@ static int __init lp_gpio_init(void) return platform_driver_register(&lp_gpio_driver); } +static void __exit lp_gpio_exit(void) +{ + platform_driver_unregister(&lp_gpio_driver); +} + subsys_initcall(lp_gpio_init); +module_exit(lp_gpio_exit); + +MODULE_AUTHOR("Mathias Nyman (Intel)"); +MODULE_DESCRIPTION("GPIO interface for Intel Lynxpoint"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:lp_gpio"); diff --git a/drivers/gpio/gpio-max730x.c b/drivers/gpio/gpio-max730x.c index f4f4ed19bdc..0814584fcdc 100644 --- a/drivers/gpio/gpio-max730x.c +++ b/drivers/gpio/gpio-max730x.c @@ -188,7 +188,7 @@ int __max730x_probe(struct max7301 *ts) ts->chip.set = max7301_set; ts->chip.ngpio = PIN_NUMBER; - ts->chip.can_sleep = 1; + ts->chip.can_sleep = true; ts->chip.dev = dev; ts->chip.owner = THIS_MODULE; @@ -220,7 +220,6 @@ int __max730x_probe(struct max7301 *ts) return ret; exit_destroy: - dev_set_drvdata(dev, NULL); mutex_destroy(&ts->lock); return ret; } @@ -234,16 +233,13 @@ int __max730x_remove(struct device *dev) if (ts == NULL) return -ENODEV; - dev_set_drvdata(dev, NULL); - /* Power down the chip and disable IRQ output */ ts->write(dev, 0x04, 0x00); ret = gpiochip_remove(&ts->chip); - if (!ret) { + if (!ret) mutex_destroy(&ts->lock); - kfree(ts); - } else + else dev_err(dev, "Failed to remove GPIO controller: %d\n", ret); return ret; diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c index 91ad74dea8c..7c36f2b0983 100644 --- a/drivers/gpio/gpio-max732x.c +++ b/drivers/gpio/gpio-max732x.c @@ -564,7 +564,7 @@ static int max732x_setup_gpio(struct max732x_chip *chip, gc->set = max732x_gpio_set_value; } gc->get = max732x_gpio_get_value; - gc->can_sleep = 1; + gc->can_sleep = true; gc->base = gpio_start; gc->ngpio = port; @@ -622,6 +622,13 @@ static int max732x_probe(struct i2c_client *client, goto out_failed; } + if (nr_port > 8 && !chip->client_dummy) { + dev_err(&client->dev, + "Failed to allocate second group I2C device\n"); + ret = -ENODEV; + goto out_failed; + } + mutex_init(&chip->lock); max732x_readb(chip, is_group_a(chip, 0), &chip->reg_out[0]); @@ -647,6 +654,8 @@ static int max732x_probe(struct i2c_client *client, return 0; out_failed: + if (chip->client_dummy) + i2c_unregister_device(chip->client_dummy); max732x_irq_teardown(chip); return ret; } diff --git a/drivers/gpio/gpio-mc33880.c b/drivers/gpio/gpio-mc33880.c index c0b7835f513..553a80a5eaf 100644 --- a/drivers/gpio/gpio-mc33880.c +++ b/drivers/gpio/gpio-mc33880.c @@ -115,7 +115,7 @@ static int mc33880_probe(struct spi_device *spi) mc->chip.set = mc33880_set; mc->chip.base = pdata->base; mc->chip.ngpio = PIN_NUMBER; - mc->chip.can_sleep = 1; + mc->chip.can_sleep = true; mc->chip.dev = &spi->dev; mc->chip.owner = THIS_MODULE; diff --git a/drivers/gpio/gpio-mc9s08dz60.c b/drivers/gpio/gpio-mc9s08dz60.c index 0ab700046a2..dce35ff00db 100644 --- a/drivers/gpio/gpio-mc9s08dz60.c +++ b/drivers/gpio/gpio-mc9s08dz60.c @@ -102,7 +102,7 @@ static int mc9s08dz60_probe(struct i2c_client *client, mc9s->chip.dev = &client->dev; mc9s->chip.owner = THIS_MODULE; mc9s->chip.ngpio = GPIO_NUM; - mc9s->chip.can_sleep = 1; + mc9s->chip.can_sleep = true; mc9s->chip.get = mc9s08dz60_get_value; mc9s->chip.set = mc9s08dz60_set_value; mc9s->chip.direction_output = mc9s08dz60_direction_output; diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c index 2deb0c5e54a..57adbc90fda 100644 --- a/drivers/gpio/gpio-mcp23s08.c +++ b/drivers/gpio/gpio-mcp23s08.c @@ -1,5 +1,13 @@ /* - * MCP23S08 SPI/GPIO gpio expander driver + * 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. */ #include <linux/kernel.h> @@ -12,7 +20,8 @@ #include <linux/spi/mcp23s08.h> #include <linux/slab.h> #include <asm/byteorder.h> -#include <linux/of.h> +#include <linux/interrupt.h> +#include <linux/of_irq.h> #include <linux/of_device.h> /** @@ -34,6 +43,7 @@ #define MCP_DEFVAL 0x03 #define MCP_INTCON 0x04 #define MCP_IOCON 0x05 +# define IOCON_MIRROR (1 << 6) # define IOCON_SEQOP (1 << 5) # define IOCON_HAEN (1 << 3) # define IOCON_ODR (1 << 2) @@ -57,8 +67,14 @@ struct mcp23s08 { u8 addr; u16 cache[11]; + u16 irq_rise; + u16 irq_fall; + int irq; + bool irq_controller; /* lock protects the cached values */ struct mutex lock; + struct mutex irq_lock; + struct irq_domain *irq_domain; struct gpio_chip chip; @@ -77,6 +93,11 @@ struct mcp23s08_driver_data { struct mcp23s08 chip[]; }; +/* This lock class tells lockdep that GPIO irqs are in a different + * category than their parents, so it won't report false recursion. + */ +static struct lock_class_key gpio_lock_class; + /*----------------------------------------------------------------------*/ #if IS_ENABLED(CONFIG_I2C) @@ -152,7 +173,7 @@ static int mcp23s08_read(struct mcp23s08 *mcp, unsigned reg) tx[0] = mcp->addr | 0x01; tx[1] = reg; - status = spi_write_then_read(mcp->data, tx, sizeof tx, rx, sizeof rx); + status = spi_write_then_read(mcp->data, tx, sizeof(tx), rx, sizeof(rx)); return (status < 0) ? status : rx[0]; } @@ -163,7 +184,7 @@ static int mcp23s08_write(struct mcp23s08 *mcp, unsigned reg, unsigned val) tx[0] = mcp->addr; tx[1] = reg; tx[2] = val; - return spi_write_then_read(mcp->data, tx, sizeof tx, NULL, 0); + return spi_write_then_read(mcp->data, tx, sizeof(tx), NULL, 0); } static int @@ -172,13 +193,13 @@ mcp23s08_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n) u8 tx[2], *tmp; int status; - if ((n + reg) > sizeof mcp->cache) + if ((n + reg) > sizeof(mcp->cache)) return -EINVAL; tx[0] = mcp->addr | 0x01; tx[1] = reg; tmp = (u8 *)vals; - status = spi_write_then_read(mcp->data, tx, sizeof tx, tmp, n); + status = spi_write_then_read(mcp->data, tx, sizeof(tx), tmp, n); if (status >= 0) { while (n--) vals[n] = tmp[n]; /* expand to 16bit */ @@ -193,7 +214,7 @@ static int mcp23s17_read(struct mcp23s08 *mcp, unsigned reg) tx[0] = mcp->addr | 0x01; tx[1] = reg << 1; - status = spi_write_then_read(mcp->data, tx, sizeof tx, rx, sizeof rx); + status = spi_write_then_read(mcp->data, tx, sizeof(tx), rx, sizeof(rx)); return (status < 0) ? status : (rx[0] | (rx[1] << 8)); } @@ -205,7 +226,7 @@ static int mcp23s17_write(struct mcp23s08 *mcp, unsigned reg, unsigned val) tx[1] = reg << 1; tx[2] = val; tx[3] = val >> 8; - return spi_write_then_read(mcp->data, tx, sizeof tx, NULL, 0); + return spi_write_then_read(mcp->data, tx, sizeof(tx), NULL, 0); } static int @@ -214,12 +235,12 @@ mcp23s17_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n) u8 tx[2]; int status; - if ((n + reg) > sizeof mcp->cache) + if ((n + reg) > sizeof(mcp->cache)) return -EINVAL; tx[0] = mcp->addr | 0x01; tx[1] = reg << 1; - status = spi_write_then_read(mcp->data, tx, sizeof tx, + status = spi_write_then_read(mcp->data, tx, sizeof(tx), (u8 *)vals, n * 2); if (status >= 0) { while (n--) @@ -316,6 +337,195 @@ 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; + unsigned int child_irq; + + mutex_lock(&mcp->lock); + intf = mcp->ops->read(mcp, MCP_INTF); + if (intf < 0) { + mutex_unlock(&mcp->lock); + return IRQ_HANDLED; + } + + mcp->cache[MCP_INTF] = intf; + + intcap = mcp->ops->read(mcp, MCP_INTCAP); + if (intcap < 0) { + mutex_unlock(&mcp->lock); + return IRQ_HANDLED; + } + + mcp->cache[MCP_INTCAP] = intcap; + mutex_unlock(&mcp->lock); + + + for (i = 0; i < mcp->chip.ngpio; i++) { + if ((BIT(i) & mcp->cache[MCP_INTF]) && + ((BIT(i) & intcap & mcp->irq_rise) || + (mcp->irq_fall & ~intcap & BIT(i)))) { + child_irq = irq_find_mapping(mcp->irq_domain, i); + handle_nested_irq(child_irq); + } + } + + return IRQ_HANDLED; +} + +static int mcp23s08_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct mcp23s08 *mcp = container_of(chip, struct mcp23s08, chip); + + return irq_find_mapping(mcp->irq_domain, offset); +} + +static void mcp23s08_irq_mask(struct irq_data *data) +{ + struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data); + unsigned int pos = data->hwirq; + + mcp->cache[MCP_GPINTEN] &= ~BIT(pos); +} + +static void mcp23s08_irq_unmask(struct irq_data *data) +{ + struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data); + unsigned int pos = data->hwirq; + + mcp->cache[MCP_GPINTEN] |= BIT(pos); +} + +static int mcp23s08_irq_set_type(struct irq_data *data, unsigned int type) +{ + struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data); + unsigned int pos = data->hwirq; + int status = 0; + + if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) { + mcp->cache[MCP_INTCON] &= ~BIT(pos); + mcp->irq_rise |= BIT(pos); + mcp->irq_fall |= BIT(pos); + } else if (type & IRQ_TYPE_EDGE_RISING) { + mcp->cache[MCP_INTCON] &= ~BIT(pos); + mcp->irq_rise |= BIT(pos); + mcp->irq_fall &= ~BIT(pos); + } else if (type & IRQ_TYPE_EDGE_FALLING) { + mcp->cache[MCP_INTCON] &= ~BIT(pos); + mcp->irq_rise &= ~BIT(pos); + mcp->irq_fall |= BIT(pos); + } else + return -EINVAL; + + return status; +} + +static void mcp23s08_irq_bus_lock(struct irq_data *data) +{ + struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data); + + mutex_lock(&mcp->irq_lock); +} + +static void mcp23s08_irq_bus_unlock(struct irq_data *data) +{ + struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data); + + mutex_lock(&mcp->lock); + mcp->ops->write(mcp, MCP_GPINTEN, mcp->cache[MCP_GPINTEN]); + mcp->ops->write(mcp, MCP_DEFVAL, mcp->cache[MCP_DEFVAL]); + mcp->ops->write(mcp, MCP_INTCON, mcp->cache[MCP_INTCON]); + mutex_unlock(&mcp->lock); + mutex_unlock(&mcp->irq_lock); +} + +static int mcp23s08_irq_reqres(struct irq_data *data) +{ + struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data); + + if (gpio_lock_as_irq(&mcp->chip, data->hwirq)) { + dev_err(mcp->chip.dev, + "unable to lock HW IRQ %lu for IRQ usage\n", + data->hwirq); + return -EINVAL; + } + + return 0; +} + +static void mcp23s08_irq_relres(struct irq_data *data) +{ + struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data); + + gpio_unlock_as_irq(&mcp->chip, data->hwirq); +} + +static struct irq_chip mcp23s08_irq_chip = { + .name = "gpio-mcp23xxx", + .irq_mask = mcp23s08_irq_mask, + .irq_unmask = mcp23s08_irq_unmask, + .irq_set_type = mcp23s08_irq_set_type, + .irq_bus_lock = mcp23s08_irq_bus_lock, + .irq_bus_sync_unlock = mcp23s08_irq_bus_unlock, + .irq_request_resources = mcp23s08_irq_reqres, + .irq_release_resources = mcp23s08_irq_relres, +}; + +static int mcp23s08_irq_setup(struct mcp23s08 *mcp) +{ + struct gpio_chip *chip = &mcp->chip; + int err, irq, j; + + mutex_init(&mcp->irq_lock); + + mcp->irq_domain = irq_domain_add_linear(chip->of_node, chip->ngpio, + &irq_domain_simple_ops, mcp); + if (!mcp->irq_domain) + return -ENODEV; + + err = devm_request_threaded_irq(chip->dev, mcp->irq, NULL, mcp23s08_irq, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + dev_name(chip->dev), mcp); + if (err != 0) { + dev_err(chip->dev, "unable to request IRQ#%d: %d\n", + mcp->irq, err); + return err; + } + + chip->to_irq = mcp23s08_gpio_to_irq; + + for (j = 0; j < mcp->chip.ngpio; j++) { + irq = irq_create_mapping(mcp->irq_domain, j); + irq_set_lockdep_class(irq, &gpio_lock_class); + irq_set_chip_data(irq, mcp); + irq_set_chip(irq, &mcp23s08_irq_chip); + irq_set_nested_thread(irq, true); +#ifdef CONFIG_ARM + set_irq_flags(irq, IRQF_VALID); +#else + irq_set_noprobe(irq); +#endif + } + return 0; +} + +static void mcp23s08_irq_teardown(struct mcp23s08 *mcp) +{ + unsigned int irq, i; + + free_irq(mcp->irq, mcp); + + for (i = 0; i < mcp->chip.ngpio; i++) { + irq = irq_find_mapping(mcp->irq_domain, i); + if (irq > 0) + irq_dispose_mapping(irq); + } + + irq_domain_remove(mcp->irq_domain); +} + +/*----------------------------------------------------------------------*/ #ifdef CONFIG_DEBUG_FS @@ -357,7 +567,7 @@ static void mcp23s08_dbg_show(struct seq_file *s, struct gpio_chip *chip) (mcp->cache[MCP_GPIO] & mask) ? "hi" : "lo", (mcp->cache[MCP_GPPU] & mask) ? "up" : " "); /* NOTE: ignoring the irq-related registers */ - seq_printf(s, "\n"); + seq_puts(s, "\n"); } done: mutex_unlock(&mcp->lock); @@ -370,10 +580,11 @@ done: /*----------------------------------------------------------------------*/ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, - void *data, unsigned addr, - unsigned type, unsigned base, unsigned pullups) + void *data, unsigned addr, unsigned type, + unsigned base, unsigned pullups) { int status; + bool mirror = false; mutex_init(&mcp->lock); @@ -425,20 +636,32 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, } mcp->chip.base = base; - mcp->chip.can_sleep = 1; + mcp->chip.can_sleep = true; mcp->chip.dev = dev; mcp->chip.owner = THIS_MODULE; /* verify MCP_IOCON.SEQOP = 0, so sequential reads work, * and MCP_IOCON.HAEN = 1, so we work with all chips. */ + status = mcp->ops->read(mcp, MCP_IOCON); if (status < 0) goto fail; - if ((status & IOCON_SEQOP) || !(status & IOCON_HAEN)) { + + mcp->irq_controller = of_property_read_bool(mcp->chip.of_node, + "interrupt-controller"); + if (mcp->irq && mcp->irq_controller && (type == MCP_TYPE_017)) + mirror = of_property_read_bool(mcp->chip.of_node, + "microchip,irq-mirror"); + + if ((status & IOCON_SEQOP) || !(status & IOCON_HAEN) || mirror) { /* mcp23s17 has IOCON twice, make sure they are in sync */ status &= ~(IOCON_SEQOP | (IOCON_SEQOP << 8)); status |= IOCON_HAEN | (IOCON_HAEN << 8); + status &= ~(IOCON_INTPOL | (IOCON_INTPOL << 8)); + if (mirror) + status |= IOCON_MIRROR | (IOCON_MIRROR << 8); + status = mcp->ops->write(mcp, MCP_IOCON, status); if (status < 0) goto fail; @@ -470,6 +693,16 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, } status = gpiochip_add(&mcp->chip); + if (status < 0) + goto fail; + + if (mcp->irq && mcp->irq_controller) { + status = mcp23s08_irq_setup(mcp); + if (status) { + mcp23s08_irq_teardown(mcp); + goto fail; + } + } fail: if (status < 0) dev_dbg(dev, "can't setup chip %d, --> %d\n", @@ -481,7 +714,7 @@ fail: #ifdef CONFIG_OF #ifdef CONFIG_SPI_MASTER -static struct of_device_id mcp23s08_spi_of_match[] = { +static const struct of_device_id mcp23s08_spi_of_match[] = { { .compatible = "microchip,mcp23s08", .data = (void *) MCP_TYPE_S08, @@ -505,7 +738,7 @@ MODULE_DEVICE_TABLE(of, mcp23s08_spi_of_match); #endif #if IS_ENABLED(CONFIG_I2C) -static struct of_device_id mcp23s08_i2c_of_match[] = { +static const struct of_device_id mcp23s08_i2c_of_match[] = { { .compatible = "microchip,mcp23008", .data = (void *) MCP_TYPE_008, @@ -546,6 +779,7 @@ static int mcp230xx_probe(struct i2c_client *client, if (match || !pdata) { base = -1; pullups = 0; + client->irq = irq_of_parse_and_map(client->dev.of_node, 0); } else { if (!gpio_is_valid(pdata->base)) { dev_dbg(&client->dev, "invalid platform data\n"); @@ -555,10 +789,11 @@ static int mcp230xx_probe(struct i2c_client *client, pullups = pdata->chip[0].pullups; } - mcp = kzalloc(sizeof *mcp, GFP_KERNEL); + mcp = kzalloc(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, base, pullups); if (status) @@ -579,6 +814,9 @@ static int mcp230xx_remove(struct i2c_client *client) struct mcp23s08 *mcp = i2c_get_clientdata(client); int status; + if (client->irq && mcp->irq_controller) + mcp23s08_irq_teardown(mcp); + status = gpiochip_remove(&mcp->chip); if (status == 0) kfree(mcp); @@ -629,7 +867,7 @@ static int mcp23s08_probe(struct spi_device *spi) { struct mcp23s08_platform_data *pdata; unsigned addr; - unsigned chips = 0; + int chips = 0; struct mcp23s08_driver_data *data; int status, type; unsigned base = -1, @@ -640,7 +878,7 @@ static int mcp23s08_probe(struct spi_device *spi) match = of_match_device(of_match_ptr(mcp23s08_spi_of_match), &spi->dev); if (match) { - type = (int)match->data; + type = (int)(uintptr_t)match->data; status = of_property_read_u32(spi->dev.of_node, "microchip,spi-present-mask", &spi_present_mask); if (status) { @@ -657,8 +895,11 @@ static int mcp23s08_probe(struct spi_device *spi) return -ENODEV; } - for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) + for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) { pullups[addr] = 0; + if (spi_present_mask & (1 << addr)) + chips++; + } } else { type = spi_get_device_id(spi)->driver_data; pdata = dev_get_platdata(&spi->dev); @@ -681,13 +922,13 @@ static int mcp23s08_probe(struct spi_device *spi) pullups[addr] = pdata->chip[addr].pullups; } - if (!chips) - return -ENODEV; - base = pdata->base; } - data = kzalloc(sizeof *data + chips * sizeof(struct mcp23s08), + if (!chips) + return -ENODEV; + + data = kzalloc(sizeof(*data) + chips * sizeof(struct mcp23s08), GFP_KERNEL); if (!data) return -ENOMEM; diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c index 6da6d7667c6..d51329d23d3 100644 --- a/drivers/gpio/gpio-ml-ioh.c +++ b/drivers/gpio/gpio-ml-ioh.c @@ -242,7 +242,7 @@ static void ioh_gpio_setup(struct ioh_gpio *chip, int num_port) gpio->dbg_show = NULL; gpio->base = -1; gpio->ngpio = num_port; - gpio->can_sleep = 0; + gpio->can_sleep = false; gpio->to_irq = ioh_gpio_to_irq; } @@ -596,7 +596,7 @@ static int ioh_gpio_resume(struct pci_dev *pdev) #define ioh_gpio_resume NULL #endif -static DEFINE_PCI_DEVICE_TABLE(ioh_gpio_pcidev_id) = { +static const struct pci_device_id ioh_gpio_pcidev_id[] = { { PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x802E) }, { 0, } }; diff --git a/drivers/gpio/gpio-moxart.c b/drivers/gpio/gpio-moxart.c new file mode 100644 index 00000000000..4661e181be0 --- /dev/null +++ b/drivers/gpio/gpio-moxart.c @@ -0,0 +1,154 @@ +/* + * MOXA ART SoCs GPIO driver. + * + * Copyright (C) 2013 Jonas Jensen + * + * Jonas Jensen <jonas.jensen@gmail.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/err.h> +#include <linux/init.h> +#include <linux/irq.h> +#include <linux/io.h> +#include <linux/gpio.h> +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/of_address.h> +#include <linux/of_gpio.h> +#include <linux/pinctrl/consumer.h> +#include <linux/delay.h> +#include <linux/timer.h> +#include <linux/bitops.h> + +#define GPIO_DATA_OUT 0x00 +#define GPIO_DATA_IN 0x04 +#define GPIO_PIN_DIRECTION 0x08 + +struct moxart_gpio_chip { + struct gpio_chip gpio; + void __iomem *base; +}; + +static inline struct moxart_gpio_chip *to_moxart_gpio(struct gpio_chip *chip) +{ + return container_of(chip, struct moxart_gpio_chip, gpio); +} + +static int moxart_gpio_request(struct gpio_chip *chip, unsigned offset) +{ + return pinctrl_request_gpio(offset); +} + +static void moxart_gpio_free(struct gpio_chip *chip, unsigned offset) +{ + pinctrl_free_gpio(offset); +} + +static void moxart_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct moxart_gpio_chip *gc = to_moxart_gpio(chip); + void __iomem *ioaddr = gc->base + GPIO_DATA_OUT; + u32 reg = readl(ioaddr); + + if (value) + reg = reg | BIT(offset); + else + reg = reg & ~BIT(offset); + + writel(reg, ioaddr); +} + +static int moxart_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct moxart_gpio_chip *gc = to_moxart_gpio(chip); + u32 ret = readl(gc->base + GPIO_PIN_DIRECTION); + + if (ret & BIT(offset)) + return !!(readl(gc->base + GPIO_DATA_OUT) & BIT(offset)); + else + return !!(readl(gc->base + GPIO_DATA_IN) & BIT(offset)); +} + +static int moxart_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + struct moxart_gpio_chip *gc = to_moxart_gpio(chip); + void __iomem *ioaddr = gc->base + GPIO_PIN_DIRECTION; + + writel(readl(ioaddr) & ~BIT(offset), ioaddr); + return 0; +} + +static int moxart_gpio_direction_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct moxart_gpio_chip *gc = to_moxart_gpio(chip); + void __iomem *ioaddr = gc->base + GPIO_PIN_DIRECTION; + + moxart_gpio_set(chip, offset, value); + writel(readl(ioaddr) | BIT(offset), ioaddr); + return 0; +} + +static struct gpio_chip moxart_template_chip = { + .label = "moxart-gpio", + .request = moxart_gpio_request, + .free = moxart_gpio_free, + .direction_input = moxart_gpio_direction_input, + .direction_output = moxart_gpio_direction_output, + .set = moxart_gpio_set, + .get = moxart_gpio_get, + .ngpio = 32, + .owner = THIS_MODULE, +}; + +static int moxart_gpio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct resource *res; + struct moxart_gpio_chip *mgc; + int ret; + + mgc = devm_kzalloc(dev, sizeof(*mgc), GFP_KERNEL); + if (!mgc) + return -ENOMEM; + mgc->gpio = moxart_template_chip; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + mgc->base = devm_ioremap_resource(dev, res); + if (IS_ERR(mgc->base)) + return PTR_ERR(mgc->base); + + mgc->gpio.dev = dev; + + ret = gpiochip_add(&mgc->gpio); + if (ret) { + dev_err(dev, "%s: gpiochip_add failed\n", + dev->of_node->full_name); + return ret; + } + + return 0; +} + +static const struct of_device_id moxart_gpio_match[] = { + { .compatible = "moxa,moxart-gpio" }, + { } +}; + +static struct platform_driver moxart_gpio_driver = { + .driver = { + .name = "moxart-gpio", + .owner = THIS_MODULE, + .of_match_table = moxart_gpio_match, + }, + .probe = moxart_gpio_probe, +}; +module_platform_driver(moxart_gpio_driver); + +MODULE_DESCRIPTION("MOXART GPIO chip driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jonas Jensen <jonas.jensen@gmail.com>"); diff --git a/drivers/gpio/gpio-msic.c b/drivers/gpio/gpio-msic.c index d75eaa3a1dc..8f70ded82a2 100644 --- a/drivers/gpio/gpio-msic.c +++ b/drivers/gpio/gpio-msic.c @@ -292,7 +292,7 @@ static int platform_msic_gpio_probe(struct platform_device *pdev) mg->chip.to_irq = msic_gpio_to_irq; mg->chip.base = pdata->gpio_base; mg->chip.ngpio = MSIC_NUM_GPIO; - mg->chip.can_sleep = 1; + mg->chip.can_sleep = true; mg->chip.dev = dev; mutex_init(&mg->buslock); @@ -305,10 +305,9 @@ static int platform_msic_gpio_probe(struct platform_device *pdev) for (i = 0; i < mg->chip.ngpio; i++) { irq_set_chip_data(i + mg->irq_base, mg); - irq_set_chip_and_handler_name(i + mg->irq_base, - &msic_irqchip, - handle_simple_irq, - "demux"); + irq_set_chip_and_handler(i + mg->irq_base, + &msic_irqchip, + handle_simple_irq); } irq_set_chained_handler(mg->irq, msic_gpio_irq_handler); irq_set_handler_data(mg->irq, mg); diff --git a/drivers/gpio/gpio-msm-v2.c b/drivers/gpio/gpio-msm-v2.c index 2baf0ddf7e0..a3351acd496 100644 --- a/drivers/gpio/gpio-msm-v2.c +++ b/drivers/gpio/gpio-msm-v2.c @@ -430,10 +430,11 @@ static int msm_gpio_probe(struct platform_device *pdev) return 0; } -static struct of_device_id msm_gpio_of_match[] = { +static const struct of_device_id msm_gpio_of_match[] = { { .compatible = "qcom,msm-gpio", }, { }, }; +MODULE_DEVICE_TABLE(of, msm_gpio_of_match); static int msm_gpio_remove(struct platform_device *dev) { diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index db3129043e6..418e3865036 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -44,6 +44,7 @@ #include <linux/of_device.h> #include <linux/clk.h> #include <linux/pinctrl/consumer.h> +#include <linux/irqchip/chained_irq.h> /* * GPIO unit register offsets. @@ -438,12 +439,15 @@ static int mvebu_gpio_irq_set_type(struct irq_data *d, unsigned int type) static void mvebu_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) { struct mvebu_gpio_chip *mvchip = irq_get_handler_data(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); u32 cause, type; int i; if (mvchip == NULL) return; + 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)) & @@ -466,8 +470,11 @@ static void mvebu_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) polarity ^= 1 << i; writel_relaxed(polarity, mvebu_gpioreg_in_pol(mvchip)); } + generic_handle_irq(irq); } + + chained_irq_exit(chip, desc); } #ifdef CONFIG_DEBUG_FS @@ -528,7 +535,7 @@ static void mvebu_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) #define mvebu_gpio_dbg_show NULL #endif -static struct of_device_id mvebu_gpio_of_match[] = { +static const struct of_device_id mvebu_gpio_of_match[] = { { .compatible = "marvell,orion-gpio", .data = (void *) MVEBU_GPIO_SOC_VARIANT_ORION, @@ -567,10 +574,8 @@ static int mvebu_gpio_probe(struct platform_device *pdev) soc_variant = MVEBU_GPIO_SOC_VARIANT_ORION; mvchip = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_gpio_chip), GFP_KERNEL); - if (!mvchip) { - dev_err(&pdev->dev, "Cannot allocate memory\n"); + if (!mvchip) return -ENOMEM; - } if (of_property_read_u32(pdev->dev.of_node, "ngpios", &ngpios)) { dev_err(&pdev->dev, "Missing ngpios OF property\n"); @@ -600,7 +605,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev) mvchip->chip.to_irq = mvebu_gpio_to_irq; mvchip->chip.base = id * MVEBU_MAX_GPIO_PER_BANK; mvchip->chip.ngpio = ngpios; - mvchip->chip.can_sleep = 0; + mvchip->chip.can_sleep = false; mvchip->chip.of_node = np; mvchip->chip.dbg_show = mvebu_gpio_dbg_show; @@ -676,7 +681,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev) mvchip->irqbase = irq_alloc_descs(-1, 0, ngpios, -1); if (mvchip->irqbase < 0) { dev_err(&pdev->dev, "no irqs\n"); - return -ENOMEM; + return mvchip->irqbase; } gc = irq_alloc_generic_chip("mvebu_gpio_irq", 2, mvchip->irqbase, @@ -731,9 +736,4 @@ static struct platform_driver mvebu_gpio_driver = { }, .probe = mvebu_gpio_probe, }; - -static int __init mvebu_gpio_init(void) -{ - return platform_driver_register(&mvebu_gpio_driver); -} -postcore_initcall(mvebu_gpio_init); +module_platform_driver(mvebu_gpio_driver); diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c index 3307f6db3a9..db83b3c0a44 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c @@ -422,7 +422,7 @@ static int mxc_gpio_probe(struct platform_device *pdev) port->irq_high = platform_get_irq(pdev, 1); port->irq = platform_get_irq(pdev, 0); if (port->irq < 0) - return -EINVAL; + return port->irq; /* disable the interrupt and clear the status */ writel(0, port->base + GPIO_IMR); diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c index 532bcb336ef..8ffdd7d2bad 100644 --- a/drivers/gpio/gpio-mxs.c +++ b/drivers/gpio/gpio-mxs.c @@ -214,7 +214,8 @@ static void __init mxs_gpio_init_gc(struct mxs_gpio_port *port, int irq_base) ct->regs.ack = PINCTRL_IRQSTAT(port) + MXS_CLR; ct->regs.mask = PINCTRL_IRQEN(port); - irq_setup_generic_chip(gc, IRQ_MSK(32), 0, IRQ_NOREQUEST, 0); + irq_setup_generic_chip(gc, IRQ_MSK(32), IRQ_GC_INIT_NESTED_LOCK, + IRQ_NOREQUEST, 0); } static int mxs_gpio_to_irq(struct gpio_chip *gc, unsigned offset) diff --git a/drivers/gpio/gpio-octeon.c b/drivers/gpio/gpio-octeon.c index 71a4a318315..dbb08546b9e 100644 --- a/drivers/gpio/gpio-octeon.c +++ b/drivers/gpio/gpio-octeon.c @@ -111,7 +111,7 @@ static int octeon_gpio_probe(struct platform_device *pdev) chip->dev = &pdev->dev; chip->owner = THIS_MODULE; chip->base = 0; - chip->can_sleep = 0; + chip->can_sleep = false; chip->ngpio = 20; chip->direction_input = octeon_gpio_dir_in; chip->get = octeon_gpio_get; diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index f319c9ffd4a..00f29aa1fb9 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -24,9 +24,9 @@ #include <linux/pm.h> #include <linux/of.h> #include <linux/of_device.h> -#include <linux/irqdomain.h> #include <linux/irqchip/chained_irq.h> #include <linux/gpio.h> +#include <linux/bitops.h> #include <linux/platform_data/gpio-omap.h> #define OFF_MODE 1 @@ -52,7 +52,6 @@ struct gpio_bank { struct list_head node; void __iomem *base; u16 irq; - struct irq_domain *domain; u32 non_wakeup_gpios; u32 enabled_non_wakeup_gpios; struct gpio_regs context; @@ -84,22 +83,21 @@ struct gpio_bank { }; #define GPIO_INDEX(bank, gpio) (gpio % bank->width) -#define GPIO_BIT(bank, gpio) (1 << GPIO_INDEX(bank, gpio)) +#define GPIO_BIT(bank, gpio) (BIT(GPIO_INDEX(bank, gpio))) #define GPIO_MOD_CTRL_BIT BIT(0) #define BANK_USED(bank) (bank->mod_usage || bank->irq_usage) -#define LINE_USED(line, offset) (line & (1 << offset)) +#define LINE_USED(line, offset) (line & (BIT(offset))) static int irq_to_gpio(struct gpio_bank *bank, unsigned int gpio_irq) { return bank->chip.base + gpio_irq; } -static int omap_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +static inline struct gpio_bank *_irq_data_get_bank(struct irq_data *d) { - struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip); - - return irq_find_mapping(bank->domain, offset); + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + return container_of(chip, struct gpio_bank, chip); } static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input) @@ -108,12 +106,12 @@ static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input) u32 l; reg += bank->regs->direction; - l = __raw_readl(reg); + l = readl_relaxed(reg); if (is_input) - l |= 1 << gpio; + l |= BIT(gpio); else - l &= ~(1 << gpio); - __raw_writel(l, reg); + l &= ~(BIT(gpio)); + writel_relaxed(l, reg); bank->context.oe = l; } @@ -132,7 +130,7 @@ static void _set_gpio_dataout_reg(struct gpio_bank *bank, int gpio, int enable) bank->context.dataout &= ~l; } - __raw_writel(l, reg); + writel_relaxed(l, reg); } /* set data out value using mask register */ @@ -142,12 +140,12 @@ static void _set_gpio_dataout_mask(struct gpio_bank *bank, int gpio, int enable) u32 gpio_bit = GPIO_BIT(bank, gpio); u32 l; - l = __raw_readl(reg); + l = readl_relaxed(reg); if (enable) l |= gpio_bit; else l &= ~gpio_bit; - __raw_writel(l, reg); + writel_relaxed(l, reg); bank->context.dataout = l; } @@ -155,35 +153,35 @@ static int _get_gpio_datain(struct gpio_bank *bank, int offset) { void __iomem *reg = bank->base + bank->regs->datain; - return (__raw_readl(reg) & (1 << offset)) != 0; + return (readl_relaxed(reg) & (BIT(offset))) != 0; } static int _get_gpio_dataout(struct gpio_bank *bank, int offset) { void __iomem *reg = bank->base + bank->regs->dataout; - return (__raw_readl(reg) & (1 << offset)) != 0; + return (readl_relaxed(reg) & (BIT(offset))) != 0; } static inline void _gpio_rmw(void __iomem *base, u32 reg, u32 mask, bool set) { - int l = __raw_readl(base + reg); + int l = readl_relaxed(base + reg); if (set) l |= mask; else l &= ~mask; - __raw_writel(l, base + reg); + writel_relaxed(l, base + reg); } static inline void _gpio_dbck_enable(struct gpio_bank *bank) { if (bank->dbck_enable_mask && !bank->dbck_enabled) { - clk_enable(bank->dbck); + clk_prepare_enable(bank->dbck); bank->dbck_enabled = true; - __raw_writel(bank->dbck_enable_mask, + writel_relaxed(bank->dbck_enable_mask, bank->base + bank->regs->debounce_en); } } @@ -196,9 +194,9 @@ static inline void _gpio_dbck_disable(struct gpio_bank *bank) * enabled but the clock is not, GPIO module seems to be unable * to detect events and generate interrupts at least on OMAP3. */ - __raw_writel(0, bank->base + bank->regs->debounce_en); + writel_relaxed(0, bank->base + bank->regs->debounce_en); - clk_disable(bank->dbck); + clk_disable_unprepare(bank->dbck); bank->dbck_enabled = false; } } @@ -231,12 +229,12 @@ static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio, l = GPIO_BIT(bank, gpio); - clk_enable(bank->dbck); + clk_prepare_enable(bank->dbck); reg = bank->base + bank->regs->debounce; - __raw_writel(debounce, reg); + writel_relaxed(debounce, reg); reg = bank->base + bank->regs->debounce_en; - val = __raw_readl(reg); + val = readl_relaxed(reg); if (debounce) val |= l; @@ -244,8 +242,8 @@ static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio, val &= ~l; bank->dbck_enable_mask = val; - __raw_writel(val, reg); - clk_disable(bank->dbck); + writel_relaxed(val, reg); + clk_disable_unprepare(bank->dbck); /* * Enable debounce clock per module. * This call is mandatory because in omap_gpio_request() when @@ -283,14 +281,14 @@ static void _clear_gpio_debounce(struct gpio_bank *bank, unsigned gpio) bank->dbck_enable_mask &= ~gpio_bit; bank->context.debounce_en &= ~gpio_bit; - __raw_writel(bank->context.debounce_en, + writel_relaxed(bank->context.debounce_en, bank->base + bank->regs->debounce_en); if (!bank->dbck_enable_mask) { bank->context.debounce = 0; - __raw_writel(bank->context.debounce, bank->base + + writel_relaxed(bank->context.debounce, bank->base + bank->regs->debounce); - clk_disable(bank->dbck); + clk_disable_unprepare(bank->dbck); bank->dbck_enabled = false; } } @@ -299,7 +297,7 @@ static inline void set_gpio_trigger(struct gpio_bank *bank, int gpio, unsigned trigger) { void __iomem *base = bank->base; - u32 gpio_bit = 1 << gpio; + u32 gpio_bit = BIT(gpio); _gpio_rmw(base, bank->regs->leveldetect0, gpio_bit, trigger & IRQ_TYPE_LEVEL_LOW); @@ -311,18 +309,18 @@ static inline void set_gpio_trigger(struct gpio_bank *bank, int gpio, trigger & IRQ_TYPE_EDGE_FALLING); bank->context.leveldetect0 = - __raw_readl(bank->base + bank->regs->leveldetect0); + readl_relaxed(bank->base + bank->regs->leveldetect0); bank->context.leveldetect1 = - __raw_readl(bank->base + bank->regs->leveldetect1); + readl_relaxed(bank->base + bank->regs->leveldetect1); bank->context.risingdetect = - __raw_readl(bank->base + bank->regs->risingdetect); + readl_relaxed(bank->base + bank->regs->risingdetect); bank->context.fallingdetect = - __raw_readl(bank->base + bank->regs->fallingdetect); + readl_relaxed(bank->base + bank->regs->fallingdetect); if (likely(!(bank->non_wakeup_gpios & gpio_bit))) { _gpio_rmw(base, bank->regs->wkup_en, gpio_bit, trigger != 0); bank->context.wake_en = - __raw_readl(bank->base + bank->regs->wkup_en); + readl_relaxed(bank->base + bank->regs->wkup_en); } /* This part needs to be executed always for OMAP{34xx, 44xx} */ @@ -347,8 +345,8 @@ static inline void set_gpio_trigger(struct gpio_bank *bank, int gpio, exit: bank->level_mask = - __raw_readl(bank->base + bank->regs->leveldetect0) | - __raw_readl(bank->base + bank->regs->leveldetect1); + readl_relaxed(bank->base + bank->regs->leveldetect0) | + readl_relaxed(bank->base + bank->regs->leveldetect1); } #ifdef CONFIG_ARCH_OMAP1 @@ -366,13 +364,13 @@ static void _toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio) reg += bank->regs->irqctrl; - l = __raw_readl(reg); + l = readl_relaxed(reg); if ((l >> gpio) & 1) - l &= ~(1 << gpio); + l &= ~(BIT(gpio)); else - l |= 1 << gpio; + l |= BIT(gpio); - __raw_writel(l, reg); + writel_relaxed(l, reg); } #else static void _toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio) {} @@ -390,17 +388,17 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, } else if (bank->regs->irqctrl) { reg += bank->regs->irqctrl; - l = __raw_readl(reg); + l = readl_relaxed(reg); if ((trigger & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) - bank->toggle_mask |= 1 << gpio; + bank->toggle_mask |= BIT(gpio); if (trigger & IRQ_TYPE_EDGE_RISING) - l |= 1 << gpio; + l |= BIT(gpio); else if (trigger & IRQ_TYPE_EDGE_FALLING) - l &= ~(1 << gpio); + l &= ~(BIT(gpio)); else return -EINVAL; - __raw_writel(l, reg); + writel_relaxed(l, reg); } else if (bank->regs->edgectrl1) { if (gpio & 0x08) reg += bank->regs->edgectrl2; @@ -408,18 +406,18 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, reg += bank->regs->edgectrl1; gpio &= 0x07; - l = __raw_readl(reg); + l = readl_relaxed(reg); l &= ~(3 << (gpio << 1)); if (trigger & IRQ_TYPE_EDGE_RISING) l |= 2 << (gpio << 1); if (trigger & IRQ_TYPE_EDGE_FALLING) - l |= 1 << (gpio << 1); + l |= BIT(gpio << 1); /* Enable wake-up during idle for dynamic tick */ - _gpio_rmw(base, bank->regs->wkup_en, 1 << gpio, trigger); + _gpio_rmw(base, bank->regs->wkup_en, BIT(gpio), trigger); bank->context.wake_en = - __raw_readl(bank->base + bank->regs->wkup_en); - __raw_writel(l, reg); + readl_relaxed(bank->base + bank->regs->wkup_en); + writel_relaxed(l, reg); } return 0; } @@ -430,17 +428,17 @@ static void _enable_gpio_module(struct gpio_bank *bank, unsigned offset) void __iomem *reg = bank->base + bank->regs->pinctrl; /* Claim the pin for MPU */ - __raw_writel(__raw_readl(reg) | (1 << offset), reg); + writel_relaxed(readl_relaxed(reg) | (BIT(offset)), reg); } if (bank->regs->ctrl && !BANK_USED(bank)) { void __iomem *reg = bank->base + bank->regs->ctrl; u32 ctrl; - ctrl = __raw_readl(reg); + ctrl = readl_relaxed(reg); /* Module is enabled, clocks are not gated */ ctrl &= ~GPIO_MOD_CTRL_BIT; - __raw_writel(ctrl, reg); + writel_relaxed(ctrl, reg); bank->context.ctrl = ctrl; } } @@ -453,19 +451,19 @@ static void _disable_gpio_module(struct gpio_bank *bank, unsigned offset) !LINE_USED(bank->mod_usage, offset) && !LINE_USED(bank->irq_usage, offset)) { /* Disable wake-up during idle for dynamic tick */ - _gpio_rmw(base, bank->regs->wkup_en, 1 << offset, 0); + _gpio_rmw(base, bank->regs->wkup_en, BIT(offset), 0); bank->context.wake_en = - __raw_readl(bank->base + bank->regs->wkup_en); + readl_relaxed(bank->base + bank->regs->wkup_en); } if (bank->regs->ctrl && !BANK_USED(bank)) { void __iomem *reg = bank->base + bank->regs->ctrl; u32 ctrl; - ctrl = __raw_readl(reg); + ctrl = readl_relaxed(reg); /* Module is disabled, clocks are gated */ ctrl |= GPIO_MOD_CTRL_BIT; - __raw_writel(ctrl, reg); + writel_relaxed(ctrl, reg); bank->context.ctrl = ctrl; } } @@ -474,12 +472,12 @@ static int gpio_is_input(struct gpio_bank *bank, int mask) { void __iomem *reg = bank->base + bank->regs->direction; - return __raw_readl(reg) & mask; + return readl_relaxed(reg) & mask; } static int gpio_irq_type(struct irq_data *d, unsigned type) { - struct gpio_bank *bank = irq_data_get_irq_chip_data(d); + struct gpio_bank *bank = _irq_data_get_bank(d); unsigned gpio = 0; int retval; unsigned long flags; @@ -509,20 +507,12 @@ static int gpio_irq_type(struct irq_data *d, unsigned type) if (!LINE_USED(bank->mod_usage, offset)) { _enable_gpio_module(bank, offset); _set_gpio_direction(bank, offset, 1); - } else if (!gpio_is_input(bank, 1 << offset)) { + } else if (!gpio_is_input(bank, BIT(offset))) { spin_unlock_irqrestore(&bank->lock, flags); return -EINVAL; } - retval = gpio_lock_as_irq(&bank->chip, offset); - if (retval) { - dev_err(bank->dev, "unable to lock offset %d for IRQ\n", - offset); - spin_unlock_irqrestore(&bank->lock, flags); - return retval; - } - - bank->irq_usage |= 1 << GPIO_INDEX(bank, gpio); + bank->irq_usage |= BIT(GPIO_INDEX(bank, gpio)); spin_unlock_irqrestore(&bank->lock, flags); if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) @@ -538,16 +528,16 @@ static void _clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) void __iomem *reg = bank->base; reg += bank->regs->irqstatus; - __raw_writel(gpio_mask, reg); + writel_relaxed(gpio_mask, reg); /* Workaround for clearing DSP GPIO interrupts to allow retention */ if (bank->regs->irqstatus2) { reg = bank->base + bank->regs->irqstatus2; - __raw_writel(gpio_mask, reg); + writel_relaxed(gpio_mask, reg); } /* Flush posted write for the irq status to avoid spurious interrupts */ - __raw_readl(reg); + readl_relaxed(reg); } static inline void _clear_gpio_irqstatus(struct gpio_bank *bank, int gpio) @@ -559,10 +549,10 @@ static u32 _get_gpio_irqbank_mask(struct gpio_bank *bank) { void __iomem *reg = bank->base; u32 l; - u32 mask = (1 << bank->width) - 1; + u32 mask = (BIT(bank->width)) - 1; reg += bank->regs->irqenable; - l = __raw_readl(reg); + l = readl_relaxed(reg); if (bank->regs->irqenable_inv) l = ~l; l &= mask; @@ -580,7 +570,7 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) bank->context.irqenable1 |= gpio_mask; } else { reg += bank->regs->irqenable; - l = __raw_readl(reg); + l = readl_relaxed(reg); if (bank->regs->irqenable_inv) l &= ~gpio_mask; else @@ -588,7 +578,7 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) bank->context.irqenable1 = l; } - __raw_writel(l, reg); + writel_relaxed(l, reg); } static void _disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) @@ -602,7 +592,7 @@ static void _disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) bank->context.irqenable1 &= ~gpio_mask; } else { reg += bank->regs->irqenable; - l = __raw_readl(reg); + l = readl_relaxed(reg); if (bank->regs->irqenable_inv) l |= gpio_mask; else @@ -610,7 +600,7 @@ static void _disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) bank->context.irqenable1 = l; } - __raw_writel(l, reg); + writel_relaxed(l, reg); } static inline void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int enable) @@ -646,7 +636,7 @@ static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable) else bank->context.wake_en &= ~gpio_bit; - __raw_writel(bank->context.wake_en, bank->base + bank->regs->wkup_en); + writel_relaxed(bank->context.wake_en, bank->base + bank->regs->wkup_en); spin_unlock_irqrestore(&bank->lock, flags); return 0; @@ -664,7 +654,7 @@ static void _reset_gpio(struct gpio_bank *bank, int gpio) /* Use disable_irq_wake() and enable_irq_wake() functions from drivers */ static int gpio_wake_enable(struct irq_data *d, unsigned int enable) { - struct gpio_bank *bank = irq_data_get_irq_chip_data(d); + struct gpio_bank *bank = _irq_data_get_bank(d); unsigned int gpio = irq_to_gpio(bank, d->hwirq); return _set_gpio_wakeup(bank, gpio, enable); @@ -691,7 +681,7 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset) _set_gpio_triggering(bank, offset, IRQ_TYPE_NONE); _enable_gpio_module(bank, offset); } - bank->mod_usage |= 1 << offset; + bank->mod_usage |= BIT(offset); spin_unlock_irqrestore(&bank->lock, flags); return 0; @@ -703,7 +693,7 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset) unsigned long flags; spin_lock_irqsave(&bank->lock, flags); - bank->mod_usage &= ~(1 << offset); + bank->mod_usage &= ~(BIT(offset)); _disable_gpio_module(bank, offset); _reset_gpio(bank, bank->chip.base + offset); spin_unlock_irqrestore(&bank->lock, flags); @@ -732,11 +722,12 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) unsigned int bit; struct gpio_bank *bank; int unmasked = 0; - struct irq_chip *chip = irq_desc_get_chip(desc); + struct irq_chip *irqchip = irq_desc_get_chip(desc); + struct gpio_chip *chip = irq_get_handler_data(irq); - chained_irq_enter(chip, desc); + chained_irq_enter(irqchip, desc); - bank = irq_get_handler_data(irq); + bank = container_of(chip, struct gpio_bank, chip); isr_reg = bank->base + bank->regs->irqstatus; pm_runtime_get_sync(bank->dev); @@ -748,7 +739,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) u32 enabled; enabled = _get_gpio_irqbank_mask(bank); - isr_saved = isr = __raw_readl(isr_reg) & enabled; + isr_saved = isr = readl_relaxed(isr_reg) & enabled; if (bank->level_mask) level_mask = bank->level_mask & enabled; @@ -764,7 +755,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) configured, we could unmask GPIO bank interrupt immediately */ if (!level_mask && !unmasked) { unmasked = 1; - chained_irq_exit(chip, desc); + chained_irq_exit(irqchip, desc); } if (!isr) @@ -772,7 +763,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) while (isr) { bit = __ffs(isr); - isr &= ~(1 << bit); + isr &= ~(BIT(bit)); /* * Some chips can't respond to both rising and falling @@ -781,10 +772,11 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) * to respond to the IRQ for the opposite direction. * This will be indicated in the bank toggle_mask. */ - if (bank->toggle_mask & (1 << bit)) + if (bank->toggle_mask & (BIT(bit))) _toggle_gpio_edge_triggering(bank, bit); - generic_handle_irq(irq_find_mapping(bank->domain, bit)); + generic_handle_irq(irq_find_mapping(bank->chip.irqdomain, + bit)); } } /* if bank has any level sensitive GPIO pin interrupt @@ -793,20 +785,20 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) interrupt */ exit: if (!unmasked) - chained_irq_exit(chip, desc); + chained_irq_exit(irqchip, desc); pm_runtime_put(bank->dev); } static void gpio_irq_shutdown(struct irq_data *d) { - struct gpio_bank *bank = irq_data_get_irq_chip_data(d); + struct gpio_bank *bank = _irq_data_get_bank(d); unsigned int gpio = irq_to_gpio(bank, d->hwirq); unsigned long flags; unsigned offset = GPIO_INDEX(bank, gpio); spin_lock_irqsave(&bank->lock, flags); gpio_unlock_as_irq(&bank->chip, offset); - bank->irq_usage &= ~(1 << offset); + bank->irq_usage &= ~(BIT(offset)); _disable_gpio_module(bank, offset); _reset_gpio(bank, gpio); spin_unlock_irqrestore(&bank->lock, flags); @@ -821,7 +813,7 @@ static void gpio_irq_shutdown(struct irq_data *d) static void gpio_ack_irq(struct irq_data *d) { - struct gpio_bank *bank = irq_data_get_irq_chip_data(d); + struct gpio_bank *bank = _irq_data_get_bank(d); unsigned int gpio = irq_to_gpio(bank, d->hwirq); _clear_gpio_irqstatus(bank, gpio); @@ -829,7 +821,7 @@ static void gpio_ack_irq(struct irq_data *d) static void gpio_mask_irq(struct irq_data *d) { - struct gpio_bank *bank = irq_data_get_irq_chip_data(d); + struct gpio_bank *bank = _irq_data_get_bank(d); unsigned int gpio = irq_to_gpio(bank, d->hwirq); unsigned long flags; @@ -841,7 +833,7 @@ static void gpio_mask_irq(struct irq_data *d) static void gpio_unmask_irq(struct irq_data *d) { - struct gpio_bank *bank = irq_data_get_irq_chip_data(d); + struct gpio_bank *bank = _irq_data_get_bank(d); unsigned int gpio = irq_to_gpio(bank, d->hwirq); unsigned int irq_mask = GPIO_BIT(bank, gpio); u32 trigger = irqd_get_trigger_type(d); @@ -883,7 +875,7 @@ static int omap_mpuio_suspend_noirq(struct device *dev) unsigned long flags; spin_lock_irqsave(&bank->lock, flags); - __raw_writel(0xffff & ~bank->context.wake_en, mask_reg); + writel_relaxed(0xffff & ~bank->context.wake_en, mask_reg); spin_unlock_irqrestore(&bank->lock, flags); return 0; @@ -898,7 +890,7 @@ static int omap_mpuio_resume_noirq(struct device *dev) unsigned long flags; spin_lock_irqsave(&bank->lock, flags); - __raw_writel(bank->context.wake_en, mask_reg); + writel_relaxed(bank->context.wake_en, mask_reg); spin_unlock_irqrestore(&bank->lock, flags); return 0; @@ -936,6 +928,21 @@ static inline void mpuio_init(struct gpio_bank *bank) /*---------------------------------------------------------------------*/ +static int gpio_get_direction(struct gpio_chip *chip, unsigned offset) +{ + struct gpio_bank *bank; + unsigned long flags; + void __iomem *reg; + int dir; + + bank = container_of(chip, struct gpio_bank, chip); + reg = bank->base + bank->regs->direction; + spin_lock_irqsave(&bank->lock, flags); + dir = !!(readl_relaxed(reg) & BIT(offset)); + spin_unlock_irqrestore(&bank->lock, flags); + return dir; +} + static int gpio_input(struct gpio_chip *chip, unsigned offset) { struct gpio_bank *bank; @@ -954,7 +961,7 @@ static int gpio_get(struct gpio_chip *chip, unsigned offset) u32 mask; bank = container_of(chip, struct gpio_bank, chip); - mask = (1 << offset); + mask = (BIT(offset)); if (gpio_is_input(bank, mask)) return _get_gpio_datain(bank, offset); @@ -1011,7 +1018,7 @@ static void __init omap_gpio_show_rev(struct gpio_bank *bank) if (called || bank->regs->revision == USHRT_MAX) return; - rev = __raw_readw(bank->base + bank->regs->revision); + rev = readw_relaxed(bank->base + bank->regs->revision); pr_info("OMAP GPIO hardware version %d.%d\n", (rev >> 4) & 0x0f, rev & 0x0f); @@ -1032,20 +1039,20 @@ static void omap_gpio_mod_init(struct gpio_bank *bank) l = 0xffff; if (bank->is_mpuio) { - __raw_writel(l, bank->base + bank->regs->irqenable); + writel_relaxed(l, bank->base + bank->regs->irqenable); return; } _gpio_rmw(base, bank->regs->irqenable, l, bank->regs->irqenable_inv); _gpio_rmw(base, bank->regs->irqstatus, l, !bank->regs->irqenable_inv); if (bank->regs->debounce_en) - __raw_writel(0, base + bank->regs->debounce_en); + writel_relaxed(0, base + bank->regs->debounce_en); /* Save OE default value (0xffffffff) in the context */ - bank->context.oe = __raw_readl(bank->base + bank->regs->direction); + bank->context.oe = readl_relaxed(bank->base + bank->regs->direction); /* Initialize interface clk ungated, module enabled */ if (bank->regs->ctrl) - __raw_writel(0, base + bank->regs->ctrl); + writel_relaxed(0, base + bank->regs->ctrl); bank->dbck = clk_get(bank->dev, "dbclk"); if (IS_ERR(bank->dbck)) @@ -1081,10 +1088,12 @@ omap_mpuio_alloc_gc(struct gpio_bank *bank, unsigned int irq_start, IRQ_NOREQUEST | IRQ_NOPROBE, 0); } -static void omap_gpio_chip_init(struct gpio_bank *bank) +static int omap_gpio_chip_init(struct gpio_bank *bank) { int j; static int gpio; + int irq_base = 0; + int ret; /* * REVISIT eventually switch from OMAP-specific gpio structs @@ -1092,12 +1101,12 @@ static void omap_gpio_chip_init(struct gpio_bank *bank) */ bank->chip.request = omap_gpio_request; bank->chip.free = omap_gpio_free; + bank->chip.get_direction = gpio_get_direction; bank->chip.direction_input = gpio_input; bank->chip.get = gpio_get; bank->chip.direction_output = gpio_output; bank->chip.set_debounce = gpio_debounce; bank->chip.set = gpio_set; - bank->chip.to_irq = omap_gpio_to_irq; if (bank->is_mpuio) { bank->chip.label = "mpuio"; if (bank->regs->wkup_en) @@ -1110,22 +1119,48 @@ static void omap_gpio_chip_init(struct gpio_bank *bank) } bank->chip.ngpio = bank->width; - gpiochip_add(&bank->chip); + ret = gpiochip_add(&bank->chip); + if (ret) { + dev_err(bank->dev, "Could not register gpio chip %d\n", ret); + return ret; + } + +#ifdef CONFIG_ARCH_OMAP1 + /* + * REVISIT: Once we have OMAP1 supporting SPARSE_IRQ, we can drop + * irq_alloc_descs() since a base IRQ offset will no longer be needed. + */ + irq_base = irq_alloc_descs(-1, 0, bank->width, 0); + if (irq_base < 0) { + dev_err(bank->dev, "Couldn't allocate IRQ numbers\n"); + return -ENODEV; + } +#endif + + ret = gpiochip_irqchip_add(&bank->chip, &gpio_irq_chip, + irq_base, gpio_irq_handler, + IRQ_TYPE_NONE); + + if (ret) { + dev_err(bank->dev, "Couldn't add irqchip to gpiochip %d\n", ret); + ret = gpiochip_remove(&bank->chip); + return -ENODEV; + } + + gpiochip_set_chained_irqchip(&bank->chip, &gpio_irq_chip, + bank->irq, gpio_irq_handler); for (j = 0; j < bank->width; j++) { - int irq = irq_create_mapping(bank->domain, j); + int irq = irq_find_mapping(bank->chip.irqdomain, j); irq_set_lockdep_class(irq, &gpio_lock_class); - irq_set_chip_data(irq, bank); if (bank->is_mpuio) { omap_mpuio_alloc_gc(bank, irq, bank->width); - } else { - irq_set_chip_and_handler(irq, &gpio_irq_chip, - handle_simple_irq); - set_irq_flags(irq, IRQF_VALID); + irq_set_chip_and_handler(irq, NULL, NULL); + set_irq_flags(irq, 0); } } - irq_set_chained_handler(bank->irq, gpio_irq_handler); - irq_set_handler_data(bank->irq, bank); + + return 0; } static const struct of_device_id omap_gpio_match[]; @@ -1138,9 +1173,7 @@ static int omap_gpio_probe(struct platform_device *pdev) const struct omap_gpio_platform_data *pdata; struct resource *res; struct gpio_bank *bank; -#ifdef CONFIG_ARCH_OMAP1 - int irq_base; -#endif + int ret; match = of_match_device(of_match_ptr(omap_gpio_match), dev); @@ -1162,6 +1195,7 @@ static int omap_gpio_probe(struct platform_device *pdev) bank->irq = res->start; bank->dev = dev; + bank->chip.dev = dev; bank->dbck_flag = pdata->dbck_flag; bank->stride = pdata->bank_stride; bank->width = pdata->bank_width; @@ -1182,29 +1216,6 @@ static int omap_gpio_probe(struct platform_device *pdev) pdata->get_context_loss_count; } -#ifdef CONFIG_ARCH_OMAP1 - /* - * REVISIT: Once we have OMAP1 supporting SPARSE_IRQ, we can drop - * irq_alloc_descs() and irq_domain_add_legacy() and just use a - * linear IRQ domain mapping for all OMAP platforms. - */ - irq_base = irq_alloc_descs(-1, 0, bank->width, 0); - if (irq_base < 0) { - dev_err(dev, "Couldn't allocate IRQ numbers\n"); - return -ENODEV; - } - - bank->domain = irq_domain_add_legacy(node, bank->width, irq_base, - 0, &irq_domain_simple_ops, NULL); -#else - bank->domain = irq_domain_add_linear(node, bank->width, - &irq_domain_simple_ops, NULL); -#endif - if (!bank->domain) { - dev_err(dev, "Couldn't register an IRQ domain\n"); - return -ENODEV; - } - if (bank->regs->set_dataout && bank->regs->clr_dataout) bank->set_dataout = _set_gpio_dataout_reg; else @@ -1214,24 +1225,10 @@ static int omap_gpio_probe(struct platform_device *pdev) /* Static mapping, never released */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (unlikely(!res)) { - dev_err(dev, "Invalid mem resource\n"); - irq_domain_remove(bank->domain); - return -ENODEV; - } - - if (!devm_request_mem_region(dev, res->start, resource_size(res), - pdev->name)) { - dev_err(dev, "Region already claimed\n"); - irq_domain_remove(bank->domain); - return -EBUSY; - } - - bank->base = devm_ioremap(dev, res->start, resource_size(res)); - if (!bank->base) { - dev_err(dev, "Could not ioremap\n"); - irq_domain_remove(bank->domain); - return -ENOMEM; + bank->base = devm_ioremap_resource(dev, res); + if (IS_ERR(bank->base)) { + irq_domain_remove(bank->chip.irqdomain); + return PTR_ERR(bank->base); } platform_set_drvdata(pdev, bank); @@ -1244,7 +1241,11 @@ static int omap_gpio_probe(struct platform_device *pdev) mpuio_init(bank); omap_gpio_mod_init(bank); - omap_gpio_chip_init(bank); + + ret = omap_gpio_chip_init(bank); + if (ret) + return ret; + omap_gpio_show_rev(bank); pm_runtime_put(bank->dev); @@ -1282,11 +1283,11 @@ static int omap_gpio_runtime_suspend(struct device *dev) */ wake_low = bank->context.leveldetect0 & bank->context.wake_en; if (wake_low) - __raw_writel(wake_low | bank->context.fallingdetect, + writel_relaxed(wake_low | bank->context.fallingdetect, bank->base + bank->regs->fallingdetect); wake_hi = bank->context.leveldetect1 & bank->context.wake_en; if (wake_hi) - __raw_writel(wake_hi | bank->context.risingdetect, + writel_relaxed(wake_hi | bank->context.risingdetect, bank->base + bank->regs->risingdetect); if (!bank->enabled_non_wakeup_gpios) @@ -1301,7 +1302,7 @@ static int omap_gpio_runtime_suspend(struct device *dev) * non-wakeup GPIOs. Otherwise spurious IRQs will be * generated. See OMAP2420 Errata item 1.101. */ - bank->saved_datain = __raw_readl(bank->base + + bank->saved_datain = readl_relaxed(bank->base + bank->regs->datain); l1 = bank->context.fallingdetect; l2 = bank->context.risingdetect; @@ -1309,8 +1310,8 @@ static int omap_gpio_runtime_suspend(struct device *dev) l1 &= ~bank->enabled_non_wakeup_gpios; l2 &= ~bank->enabled_non_wakeup_gpios; - __raw_writel(l1, bank->base + bank->regs->fallingdetect); - __raw_writel(l2, bank->base + bank->regs->risingdetect); + writel_relaxed(l1, bank->base + bank->regs->fallingdetect); + writel_relaxed(l2, bank->base + bank->regs->risingdetect); bank->workaround_enabled = true; @@ -1358,9 +1359,9 @@ static int omap_gpio_runtime_resume(struct device *dev) * generate a PRCM wakeup. Here we restore the * pre-runtime_suspend() values for edge triggering. */ - __raw_writel(bank->context.fallingdetect, + writel_relaxed(bank->context.fallingdetect, bank->base + bank->regs->fallingdetect); - __raw_writel(bank->context.risingdetect, + writel_relaxed(bank->context.risingdetect, bank->base + bank->regs->risingdetect); if (bank->loses_context) { @@ -1382,7 +1383,7 @@ static int omap_gpio_runtime_resume(struct device *dev) return 0; } - l = __raw_readl(bank->base + bank->regs->datain); + l = readl_relaxed(bank->base + bank->regs->datain); /* * Check if any of the non-wakeup interrupt GPIOs have changed @@ -1412,24 +1413,24 @@ static int omap_gpio_runtime_resume(struct device *dev) if (gen) { u32 old0, old1; - old0 = __raw_readl(bank->base + bank->regs->leveldetect0); - old1 = __raw_readl(bank->base + bank->regs->leveldetect1); + old0 = readl_relaxed(bank->base + bank->regs->leveldetect0); + old1 = readl_relaxed(bank->base + bank->regs->leveldetect1); if (!bank->regs->irqstatus_raw0) { - __raw_writel(old0 | gen, bank->base + + writel_relaxed(old0 | gen, bank->base + bank->regs->leveldetect0); - __raw_writel(old1 | gen, bank->base + + writel_relaxed(old1 | gen, bank->base + bank->regs->leveldetect1); } if (bank->regs->irqstatus_raw0) { - __raw_writel(old0 | l, bank->base + + writel_relaxed(old0 | l, bank->base + bank->regs->leveldetect0); - __raw_writel(old1 | l, bank->base + + writel_relaxed(old1 | l, bank->base + bank->regs->leveldetect1); } - __raw_writel(old0, bank->base + bank->regs->leveldetect0); - __raw_writel(old1, bank->base + bank->regs->leveldetect1); + writel_relaxed(old0, bank->base + bank->regs->leveldetect0); + writel_relaxed(old1, bank->base + bank->regs->leveldetect1); } bank->workaround_enabled = false; @@ -1471,55 +1472,55 @@ static void omap_gpio_init_context(struct gpio_bank *p) struct omap_gpio_reg_offs *regs = p->regs; void __iomem *base = p->base; - p->context.ctrl = __raw_readl(base + regs->ctrl); - p->context.oe = __raw_readl(base + regs->direction); - p->context.wake_en = __raw_readl(base + regs->wkup_en); - p->context.leveldetect0 = __raw_readl(base + regs->leveldetect0); - p->context.leveldetect1 = __raw_readl(base + regs->leveldetect1); - p->context.risingdetect = __raw_readl(base + regs->risingdetect); - p->context.fallingdetect = __raw_readl(base + regs->fallingdetect); - p->context.irqenable1 = __raw_readl(base + regs->irqenable); - p->context.irqenable2 = __raw_readl(base + regs->irqenable2); + p->context.ctrl = readl_relaxed(base + regs->ctrl); + p->context.oe = readl_relaxed(base + regs->direction); + p->context.wake_en = readl_relaxed(base + regs->wkup_en); + p->context.leveldetect0 = readl_relaxed(base + regs->leveldetect0); + p->context.leveldetect1 = readl_relaxed(base + regs->leveldetect1); + p->context.risingdetect = readl_relaxed(base + regs->risingdetect); + p->context.fallingdetect = readl_relaxed(base + regs->fallingdetect); + p->context.irqenable1 = readl_relaxed(base + regs->irqenable); + p->context.irqenable2 = readl_relaxed(base + regs->irqenable2); if (regs->set_dataout && p->regs->clr_dataout) - p->context.dataout = __raw_readl(base + regs->set_dataout); + p->context.dataout = readl_relaxed(base + regs->set_dataout); else - p->context.dataout = __raw_readl(base + regs->dataout); + p->context.dataout = readl_relaxed(base + regs->dataout); p->context_valid = true; } static void omap_gpio_restore_context(struct gpio_bank *bank) { - __raw_writel(bank->context.wake_en, + writel_relaxed(bank->context.wake_en, bank->base + bank->regs->wkup_en); - __raw_writel(bank->context.ctrl, bank->base + bank->regs->ctrl); - __raw_writel(bank->context.leveldetect0, + writel_relaxed(bank->context.ctrl, bank->base + bank->regs->ctrl); + writel_relaxed(bank->context.leveldetect0, bank->base + bank->regs->leveldetect0); - __raw_writel(bank->context.leveldetect1, + writel_relaxed(bank->context.leveldetect1, bank->base + bank->regs->leveldetect1); - __raw_writel(bank->context.risingdetect, + writel_relaxed(bank->context.risingdetect, bank->base + bank->regs->risingdetect); - __raw_writel(bank->context.fallingdetect, + writel_relaxed(bank->context.fallingdetect, bank->base + bank->regs->fallingdetect); if (bank->regs->set_dataout && bank->regs->clr_dataout) - __raw_writel(bank->context.dataout, + writel_relaxed(bank->context.dataout, bank->base + bank->regs->set_dataout); else - __raw_writel(bank->context.dataout, + writel_relaxed(bank->context.dataout, bank->base + bank->regs->dataout); - __raw_writel(bank->context.oe, bank->base + bank->regs->direction); + writel_relaxed(bank->context.oe, bank->base + bank->regs->direction); if (bank->dbck_enable_mask) { - __raw_writel(bank->context.debounce, bank->base + + writel_relaxed(bank->context.debounce, bank->base + bank->regs->debounce); - __raw_writel(bank->context.debounce_en, + writel_relaxed(bank->context.debounce_en, bank->base + bank->regs->debounce_en); } - __raw_writel(bank->context.irqenable1, + writel_relaxed(bank->context.irqenable1, bank->base + bank->regs->irqenable); - __raw_writel(bank->context.irqenable2, + writel_relaxed(bank->context.irqenable2, bank->base + bank->regs->irqenable2); } #endif /* CONFIG_PM_RUNTIME */ diff --git a/drivers/gpio/gpio-palmas.c b/drivers/gpio/gpio-palmas.c index 11801e986dd..86bdbe36206 100644 --- a/drivers/gpio/gpio-palmas.c +++ b/drivers/gpio/gpio-palmas.c @@ -148,7 +148,7 @@ static const struct palmas_device_data tps80036_dev_data = { .ngpio = 16, }; -static struct of_device_id of_palmas_gpio_match[] = { +static const struct of_device_id of_palmas_gpio_match[] = { { .compatible = "ti,palmas-gpio", .data = &palmas_dev_data,}, { .compatible = "ti,tps65913-gpio", .data = &palmas_dev_data,}, { .compatible = "ti,tps65914-gpio", .data = &palmas_dev_data,}, @@ -173,16 +173,14 @@ static int palmas_gpio_probe(struct platform_device *pdev) palmas_gpio = devm_kzalloc(&pdev->dev, sizeof(*palmas_gpio), GFP_KERNEL); - if (!palmas_gpio) { - dev_err(&pdev->dev, "Could not allocate palmas_gpio\n"); + if (!palmas_gpio) return -ENOMEM; - } palmas_gpio->palmas = palmas; palmas_gpio->gpio_chip.owner = THIS_MODULE; palmas_gpio->gpio_chip.label = dev_name(&pdev->dev); palmas_gpio->gpio_chip.ngpio = dev_data->ngpio; - palmas_gpio->gpio_chip.can_sleep = 1; + palmas_gpio->gpio_chip.can_sleep = true; palmas_gpio->gpio_chip.direction_input = palmas_gpio_input; palmas_gpio->gpio_chip.direction_output = palmas_gpio_output; palmas_gpio->gpio_chip.to_irq = palmas_gpio_to_irq; diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 6e48c07e3d8..e721a37c347 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -1,5 +1,5 @@ /* - * PCA953x 4/8/16 bit I/O ports + * PCA953x 4/8/16/24/40 bit I/O ports * * Copyright (C) 2005 Ben Gardner <bgardner@wabtec.com> * Copyright (C) 2007 Marvell International Ltd. @@ -15,8 +15,6 @@ #include <linux/init.h> #include <linux/gpio.h> #include <linux/interrupt.h> -#include <linux/irq.h> -#include <linux/irqdomain.h> #include <linux/i2c.h> #include <linux/platform_data/pca953x.h> #include <linux/slab.h> @@ -59,6 +57,7 @@ static const struct i2c_device_id pca953x_id[] = { { "pca9557", 8 | PCA953X_TYPE, }, { "pca9574", 8 | PCA957X_TYPE | PCA_INT, }, { "pca9575", 16 | PCA957X_TYPE | PCA_INT, }, + { "pca9698", 40 | PCA953X_TYPE, }, { "max7310", 8 | PCA953X_TYPE, }, { "max7312", 16 | PCA953X_TYPE | PCA_INT, }, @@ -68,6 +67,7 @@ static const struct i2c_device_id pca953x_id[] = { { "tca6408", 8 | PCA953X_TYPE | PCA_INT, }, { "tca6416", 16 | PCA953X_TYPE | PCA_INT, }, { "tca6424", 24 | PCA953X_TYPE | PCA_INT, }, + { "xra1202", 8 | PCA953X_TYPE }, { } }; MODULE_DEVICE_TABLE(i2c, pca953x_id); @@ -89,7 +89,6 @@ struct pca953x_chip { u8 irq_stat[MAX_BANK]; u8 irq_trig_raise[MAX_BANK]; u8 irq_trig_fall[MAX_BANK]; - struct irq_domain *domain; #endif struct i2c_client *client; @@ -98,6 +97,11 @@ struct pca953x_chip { int chip_type; }; +static inline struct pca953x_chip *to_pca(struct gpio_chip *gc) +{ + return container_of(gc, struct pca953x_chip, gpio_chip); +} + static int pca953x_read_single(struct pca953x_chip *chip, int reg, u32 *val, int off) { @@ -200,12 +204,10 @@ static int pca953x_read_regs(struct pca953x_chip *chip, int reg, u8 *val) static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off) { - struct pca953x_chip *chip; + struct pca953x_chip *chip = to_pca(gc); u8 reg_val; int ret, offset = 0; - chip = container_of(gc, struct pca953x_chip, gpio_chip); - mutex_lock(&chip->i2c_lock); reg_val = chip->reg_direction[off / BANK_SZ] | (1u << (off % BANK_SZ)); @@ -231,12 +233,10 @@ exit: static int pca953x_gpio_direction_output(struct gpio_chip *gc, unsigned off, int val) { - struct pca953x_chip *chip; + struct pca953x_chip *chip = to_pca(gc); u8 reg_val; int ret, offset = 0; - chip = container_of(gc, struct pca953x_chip, gpio_chip); - mutex_lock(&chip->i2c_lock); /* set output level */ if (val) @@ -283,12 +283,10 @@ exit: static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off) { - struct pca953x_chip *chip; + struct pca953x_chip *chip = to_pca(gc); u32 reg_val; int ret, offset = 0; - chip = container_of(gc, struct pca953x_chip, gpio_chip); - mutex_lock(&chip->i2c_lock); switch (chip->chip_type) { case PCA953X_TYPE: @@ -313,12 +311,10 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off) static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) { - struct pca953x_chip *chip; + struct pca953x_chip *chip = to_pca(gc); u8 reg_val; int ret, offset = 0; - chip = container_of(gc, struct pca953x_chip, gpio_chip); - mutex_lock(&chip->i2c_lock); if (val) reg_val = chip->reg_output[off / BANK_SZ] @@ -354,7 +350,7 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios) gc->direction_output = pca953x_gpio_direction_output; gc->get = pca953x_gpio_get_value; gc->set = pca953x_gpio_set_value; - gc->can_sleep = 1; + gc->can_sleep = true; gc->base = chip->gpio_start; gc->ngpio = gpios; @@ -365,38 +361,34 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios) } #ifdef CONFIG_GPIO_PCA953X_IRQ -static int pca953x_gpio_to_irq(struct gpio_chip *gc, unsigned off) -{ - struct pca953x_chip *chip; - - chip = container_of(gc, struct pca953x_chip, gpio_chip); - return irq_create_mapping(chip->domain, off); -} - static void pca953x_irq_mask(struct irq_data *d) { - struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct pca953x_chip *chip = to_pca(gc); chip->irq_mask[d->hwirq / BANK_SZ] &= ~(1 << (d->hwirq % BANK_SZ)); } static void pca953x_irq_unmask(struct irq_data *d) { - struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct pca953x_chip *chip = to_pca(gc); chip->irq_mask[d->hwirq / BANK_SZ] |= 1 << (d->hwirq % BANK_SZ); } static void pca953x_irq_bus_lock(struct irq_data *d) { - struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct pca953x_chip *chip = to_pca(gc); mutex_lock(&chip->irq_lock); } static void pca953x_irq_bus_sync_unlock(struct irq_data *d) { - struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct pca953x_chip *chip = to_pca(gc); u8 new_irqs; int level, i; @@ -418,7 +410,8 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d) static int pca953x_irq_set_type(struct irq_data *d, unsigned int type) { - struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct pca953x_chip *chip = to_pca(gc); int bank_nb = d->hwirq / BANK_SZ; u8 mask = 1 << (d->hwirq % BANK_SZ); @@ -501,44 +494,25 @@ static irqreturn_t pca953x_irq_handler(int irq, void *devid) struct pca953x_chip *chip = devid; u8 pending[MAX_BANK]; u8 level; + unsigned nhandled = 0; int i; if (!pca953x_irq_pending(chip, pending)) - return IRQ_HANDLED; + return IRQ_NONE; for (i = 0; i < NBANK(chip); i++) { while (pending[i]) { level = __ffs(pending[i]); - handle_nested_irq(irq_find_mapping(chip->domain, + handle_nested_irq(irq_find_mapping(chip->gpio_chip.irqdomain, level + (BANK_SZ * i))); pending[i] &= ~(1 << level); + nhandled++; } } - return IRQ_HANDLED; + return (nhandled > 0) ? IRQ_HANDLED : IRQ_NONE; } -static int pca953x_gpio_irq_map(struct irq_domain *d, unsigned int irq, - irq_hw_number_t hwirq) -{ - irq_clear_status_flags(irq, IRQ_NOREQUEST); - irq_set_chip_data(irq, d->host_data); - irq_set_chip(irq, &pca953x_irq_chip); - irq_set_nested_thread(irq, true); -#ifdef CONFIG_ARM - set_irq_flags(irq, IRQF_VALID); -#else - irq_set_noprobe(irq); -#endif - - return 0; -} - -static const struct irq_domain_ops pca953x_irq_simple_ops = { - .map = pca953x_gpio_irq_map, - .xlate = irq_domain_xlate_twocell, -}; - static int pca953x_irq_setup(struct pca953x_chip *chip, const struct i2c_device_id *id, int irq_base) @@ -570,19 +544,12 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, chip->irq_stat[i] &= chip->reg_direction[i]; mutex_init(&chip->irq_lock); - chip->domain = irq_domain_add_simple(client->dev.of_node, - chip->gpio_chip.ngpio, - irq_base, - &pca953x_irq_simple_ops, - chip); - if (!chip->domain) - return -ENODEV; - ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, pca953x_irq_handler, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, + IRQF_TRIGGER_LOW | IRQF_ONESHOT | + IRQF_SHARED, dev_name(&client->dev), chip); if (ret) { dev_err(&client->dev, "failed to request irq %d\n", @@ -590,7 +557,16 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, return ret; } - chip->gpio_chip.to_irq = pca953x_gpio_to_irq; + ret = gpiochip_irqchip_add(&chip->gpio_chip, + &pca953x_irq_chip, + irq_base, + handle_simple_irq, + IRQ_TYPE_NONE); + if (ret) { + dev_err(&client->dev, + "could not connect irqchip to gpiochip\n"); + return ret; + } } return 0; @@ -625,11 +601,12 @@ pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, u32 *invert) const __be32 *val; int size; + *gpio_base = -1; + node = client->dev.of_node; if (node == NULL) return; - *gpio_base = -1; val = of_get_property(node, "linux,gpio-base", &size); WARN(val, "%s: device-tree property 'linux,gpio-base' is deprecated!", __func__); if (val) { @@ -753,11 +730,11 @@ static int pca953x_probe(struct i2c_client *client, if (ret) return ret; - ret = pca953x_irq_setup(chip, id, irq_base); + ret = gpiochip_add(&chip->gpio_chip); if (ret) return ret; - ret = gpiochip_add(&chip->gpio_chip); + ret = pca953x_irq_setup(chip, id, irq_base); if (ret) return ret; @@ -812,6 +789,7 @@ static const struct of_device_id pca953x_dt_ids[] = { { .compatible = "nxp,pca9557", }, { .compatible = "nxp,pca9574", }, { .compatible = "nxp,pca9575", }, + { .compatible = "nxp,pca9698", }, { .compatible = "maxim,max7310", }, { .compatible = "maxim,max7312", }, @@ -822,6 +800,8 @@ static const struct of_device_id pca953x_dt_ids[] = { { .compatible = "ti,tca6408", }, { .compatible = "ti,tca6416", }, { .compatible = "ti,tca6424", }, + + { .compatible = "exar,xra1202", }, { } }; diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index 1535686e74e..27b46751ea7 100644 --- a/drivers/gpio/gpio-pcf857x.c +++ b/drivers/gpio/gpio-pcf857x.c @@ -262,7 +262,7 @@ static int pcf857x_irq_domain_init(struct pcf857x *gpio, /* enable real irq */ status = devm_request_threaded_irq(&client->dev, client->irq, NULL, pcf857x_irq, IRQF_ONESHOT | - IRQF_TRIGGER_FALLING, + IRQF_TRIGGER_FALLING | IRQF_SHARED, dev_name(&client->dev), gpio); if (status) @@ -305,7 +305,7 @@ static int pcf857x_probe(struct i2c_client *client, spin_lock_init(&gpio->slock); gpio->chip.base = pdata ? pdata->gpio_base : -1; - gpio->chip.can_sleep = 1; + gpio->chip.can_sleep = true; gpio->chip.dev = &client->dev; gpio->chip.owner = THIS_MODULE; gpio->chip.get = pcf857x_get; @@ -319,7 +319,7 @@ static int pcf857x_probe(struct i2c_client *client, status = pcf857x_irq_domain_init(gpio, client); if (status < 0) { dev_err(&client->dev, "irq_domain init failed\n"); - goto fail; + goto fail_irq_domain; } } @@ -414,12 +414,13 @@ static int pcf857x_probe(struct i2c_client *client, return 0; fail: - dev_dbg(&client->dev, "probe error %d for '%s'\n", - status, client->name); - if (client->irq) pcf857x_irq_domain_cleanup(gpio); +fail_irq_domain: + dev_dbg(&client->dev, "probe error %d for '%s'\n", + status, client->name); + return status; } diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c index 0fec097e838..d6eac9b17db 100644 --- a/drivers/gpio/gpio-pch.c +++ b/drivers/gpio/gpio-pch.c @@ -20,6 +20,7 @@ #include <linux/gpio.h> #include <linux/interrupt.h> #include <linux/irq.h> +#include <linux/slab.h> #define PCH_EDGE_FALLING 0 #define PCH_EDGE_RISING BIT(0) @@ -138,9 +139,6 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, unsigned long flags; spin_lock_irqsave(&chip->spinlock, flags); - pm = ioread32(&chip->reg->pm) & ((1 << gpio_pins[chip->ioh]) - 1); - pm |= (1 << nr); - iowrite32(pm, &chip->reg->pm); reg_val = ioread32(&chip->reg->po); if (val) @@ -148,6 +146,11 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, else reg_val &= ~(1 << nr); iowrite32(reg_val, &chip->reg->po); + + pm = ioread32(&chip->reg->pm) & ((1 << gpio_pins[chip->ioh]) - 1); + pm |= (1 << nr); + iowrite32(pm, &chip->reg->pm); + spin_unlock_irqrestore(&chip->spinlock, flags); return 0; @@ -224,7 +227,7 @@ static void pch_gpio_setup(struct pch_gpio *chip) gpio->dbg_show = NULL; gpio->base = -1; gpio->ngpio = gpio_pins[chip->ioh]; - gpio->can_sleep = 0; + gpio->can_sleep = false; gpio->to_irq = pch_gpio_to_irq; } @@ -518,7 +521,7 @@ static int pch_gpio_resume(struct pci_dev *pdev) #endif #define PCI_VENDOR_ID_ROHM 0x10DB -static DEFINE_PCI_DEVICE_TABLE(pch_gpio_pcidev_id) = { +static const struct pci_device_id pch_gpio_pcidev_id[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8803) }, { PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8014) }, { PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8043) }, diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index b4d42112d02..84b49cfb81a 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -15,10 +15,8 @@ #include <linux/io.h> #include <linux/ioport.h> #include <linux/irq.h> -#include <linux/irqdomain.h> #include <linux/irqchip/chained_irq.h> #include <linux/bitops.h> -#include <linux/workqueue.h> #include <linux/gpio.h> #include <linux/device.h> #include <linux/amba/bus.h> @@ -53,7 +51,6 @@ struct pl061_gpio { spinlock_t lock; void __iomem *base; - struct irq_domain *domain; struct gpio_chip gc; #ifdef CONFIG_PM @@ -90,7 +87,7 @@ static int pl061_direction_input(struct gpio_chip *gc, unsigned offset) spin_lock_irqsave(&chip->lock, flags); gpiodir = readb(chip->base + GPIODIR); - gpiodir &= ~(1 << offset); + gpiodir &= ~(BIT(offset)); writeb(gpiodir, chip->base + GPIODIR); spin_unlock_irqrestore(&chip->lock, flags); @@ -108,16 +105,16 @@ static int pl061_direction_output(struct gpio_chip *gc, unsigned offset, return -EINVAL; spin_lock_irqsave(&chip->lock, flags); - writeb(!!value << offset, chip->base + (1 << (offset + 2))); + writeb(!!value << offset, chip->base + (BIT(offset + 2))); gpiodir = readb(chip->base + GPIODIR); - gpiodir |= 1 << offset; + gpiodir |= BIT(offset); writeb(gpiodir, chip->base + GPIODIR); /* * gpio value is set again, because pl061 doesn't allow to set value of * a gpio pin before configuring it in OUT mode. */ - writeb(!!value << offset, chip->base + (1 << (offset + 2))); + writeb(!!value << offset, chip->base + (BIT(offset + 2))); spin_unlock_irqrestore(&chip->lock, flags); return 0; @@ -127,29 +124,24 @@ static int pl061_get_value(struct gpio_chip *gc, unsigned offset) { struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); - return !!readb(chip->base + (1 << (offset + 2))); + return !!readb(chip->base + (BIT(offset + 2))); } static void pl061_set_value(struct gpio_chip *gc, unsigned offset, int value) { struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); - writeb(!!value << offset, chip->base + (1 << (offset + 2))); -} - -static int pl061_to_irq(struct gpio_chip *gc, unsigned offset) -{ - struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); - - return irq_create_mapping(chip->domain, offset); + writeb(!!value << offset, chip->base + (BIT(offset + 2))); } static int pl061_irq_type(struct irq_data *d, unsigned trigger) { - struct pl061_gpio *chip = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); int offset = irqd_to_hwirq(d); unsigned long flags; u8 gpiois, gpioibe, gpioiev; + u8 bit = BIT(offset); if (offset < 0 || offset >= PL061_GPIO_NR) return -EINVAL; @@ -157,30 +149,31 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger) spin_lock_irqsave(&chip->lock, flags); gpioiev = readb(chip->base + GPIOIEV); - gpiois = readb(chip->base + GPIOIS); + gpioibe = readb(chip->base + GPIOIBE); + if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) { - gpiois |= 1 << offset; + gpiois |= bit; if (trigger & IRQ_TYPE_LEVEL_HIGH) - gpioiev |= 1 << offset; + gpioiev |= bit; else - gpioiev &= ~(1 << offset); + gpioiev &= ~bit; } else - gpiois &= ~(1 << offset); - writeb(gpiois, chip->base + GPIOIS); + gpiois &= ~bit; - gpioibe = readb(chip->base + GPIOIBE); if ((trigger & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) - gpioibe |= 1 << offset; + /* Setting this makes GPIOEV be ignored */ + gpioibe |= bit; else { - gpioibe &= ~(1 << offset); + gpioibe &= ~bit; if (trigger & IRQ_TYPE_EDGE_RISING) - gpioiev |= 1 << offset; + gpioiev |= bit; else if (trigger & IRQ_TYPE_EDGE_FALLING) - gpioiev &= ~(1 << offset); + gpioiev &= ~bit; } - writeb(gpioibe, chip->base + GPIOIBE); + writeb(gpiois, chip->base + GPIOIS); + writeb(gpioibe, chip->base + GPIOIBE); writeb(gpioiev, chip->base + GPIOIEV); spin_unlock_irqrestore(&chip->lock, flags); @@ -192,7 +185,8 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc) { unsigned long pending; int offset; - struct pl061_gpio *chip = irq_desc_get_handler_data(desc); + struct gpio_chip *gc = irq_desc_get_handler_data(desc); + struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); struct irq_chip *irqchip = irq_desc_get_chip(desc); chained_irq_enter(irqchip, desc); @@ -201,7 +195,8 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc) writeb(pending, chip->base + GPIOIC); if (pending) { for_each_set_bit(offset, &pending, PL061_GPIO_NR) - generic_handle_irq(pl061_to_irq(&chip->gc, offset)); + generic_handle_irq(irq_find_mapping(gc->irqdomain, + offset)); } chained_irq_exit(irqchip, desc); @@ -209,8 +204,9 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc) static void pl061_irq_mask(struct irq_data *d) { - struct pl061_gpio *chip = irq_data_get_irq_chip_data(d); - u8 mask = 1 << (irqd_to_hwirq(d) % PL061_GPIO_NR); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); + u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR); u8 gpioie; spin_lock(&chip->lock); @@ -221,8 +217,9 @@ static void pl061_irq_mask(struct irq_data *d) static void pl061_irq_unmask(struct irq_data *d) { - struct pl061_gpio *chip = irq_data_get_irq_chip_data(d); - u8 mask = 1 << (irqd_to_hwirq(d) % PL061_GPIO_NR); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); + u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR); u8 gpioie; spin_lock(&chip->lock); @@ -232,30 +229,12 @@ static void pl061_irq_unmask(struct irq_data *d) } static struct irq_chip pl061_irqchip = { - .name = "pl061 gpio", + .name = "pl061", .irq_mask = pl061_irq_mask, .irq_unmask = pl061_irq_unmask, .irq_set_type = pl061_irq_type, }; -static int pl061_irq_map(struct irq_domain *d, unsigned int irq, - irq_hw_number_t hwirq) -{ - struct pl061_gpio *chip = d->host_data; - - irq_set_chip_and_handler_name(irq, &pl061_irqchip, handle_simple_irq, - "pl061"); - irq_set_chip_data(irq, chip); - irq_set_irq_type(irq, IRQ_TYPE_NONE); - - return 0; -} - -static const struct irq_domain_ops pl061_domain_ops = { - .map = pl061_irq_map, - .xlate = irq_domain_xlate_twocell, -}; - static int pl061_probe(struct amba_device *adev, const struct amba_id *id) { struct device *dev = &adev->dev; @@ -270,21 +249,18 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id) if (pdata) { chip->gc.base = pdata->gpio_base; irq_base = pdata->irq_base; - if (irq_base <= 0) + if (irq_base <= 0) { + dev_err(&adev->dev, "invalid IRQ base in pdata\n"); return -ENODEV; + } } else { chip->gc.base = -1; irq_base = 0; } - if (!devm_request_mem_region(dev, adev->res.start, - resource_size(&adev->res), "pl061")) - return -EBUSY; - - chip->base = devm_ioremap(dev, adev->res.start, - resource_size(&adev->res)); - if (!chip->base) - return -ENOMEM; + chip->base = devm_ioremap_resource(dev, &adev->res); + if (IS_ERR(chip->base)) + return PTR_ERR(chip->base); spin_lock_init(&chip->lock); @@ -294,7 +270,6 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id) chip->gc.direction_output = pl061_direction_output; chip->gc.get = pl061_get_value; chip->gc.set = pl061_set_value; - chip->gc.to_irq = pl061_to_irq; chip->gc.ngpio = PL061_GPIO_NR; chip->gc.label = dev_name(dev); chip->gc.dev = dev; @@ -309,28 +284,34 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id) */ writeb(0, chip->base + GPIOIE); /* disable irqs */ irq = adev->irq[0]; - if (irq < 0) + if (irq < 0) { + dev_err(&adev->dev, "invalid IRQ\n"); return -ENODEV; + } - irq_set_chained_handler(irq, pl061_irq_handler); - irq_set_handler_data(irq, chip); - - chip->domain = irq_domain_add_simple(adev->dev.of_node, PL061_GPIO_NR, - irq_base, &pl061_domain_ops, chip); - if (!chip->domain) - return -ENODEV; + ret = gpiochip_irqchip_add(&chip->gc, &pl061_irqchip, + irq_base, handle_simple_irq, + IRQ_TYPE_NONE); + if (ret) { + dev_info(&adev->dev, "could not add irqchip\n"); + return ret; + } + gpiochip_set_chained_irqchip(&chip->gc, &pl061_irqchip, + irq, pl061_irq_handler); for (i = 0; i < PL061_GPIO_NR; i++) { if (pdata) { - if (pdata->directions & (1 << i)) + if (pdata->directions & (BIT(i))) pl061_direction_output(&chip->gc, i, - pdata->values & (1 << i)); + pdata->values & (BIT(i))); else pl061_direction_input(&chip->gc, i); } } amba_set_drvdata(adev, chip); + dev_info(&adev->dev, "PL061 GPIO chip @%pa registered\n", + &adev->res.start); return 0; } @@ -349,7 +330,7 @@ static int pl061_suspend(struct device *dev) chip->csave_regs.gpio_ie = readb(chip->base + GPIOIE); for (offset = 0; offset < PL061_GPIO_NR; offset++) { - if (chip->csave_regs.gpio_dir & (1 << offset)) + if (chip->csave_regs.gpio_dir & (BIT(offset))) chip->csave_regs.gpio_data |= pl061_get_value(&chip->gc, offset) << offset; } @@ -363,10 +344,10 @@ static int pl061_resume(struct device *dev) int offset; for (offset = 0; offset < PL061_GPIO_NR; offset++) { - if (chip->csave_regs.gpio_dir & (1 << offset)) + if (chip->csave_regs.gpio_dir & (BIT(offset))) pl061_direction_output(&chip->gc, offset, chip->csave_regs.gpio_data & - (1 << offset)); + (BIT(offset))); else pl061_direction_input(&chip->gc, offset); } diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c index cc13d1b74fa..42e6e64f212 100644 --- a/drivers/gpio/gpio-pxa.c +++ b/drivers/gpio/gpio-pxa.c @@ -263,7 +263,8 @@ static int pxa_gpio_direction_output(struct gpio_chip *chip, static int pxa_gpio_get(struct gpio_chip *chip, unsigned offset) { - return readl_relaxed(gpio_chip_base(chip) + GPLR_OFFSET) & (1 << offset); + u32 gplr = readl_relaxed(gpio_chip_base(chip) + GPLR_OFFSET); + return !!(gplr & (1 << offset)); } static void pxa_gpio_set(struct gpio_chip *chip, unsigned offset, int value) diff --git a/drivers/gpio/gpio-rc5t583.c b/drivers/gpio/gpio-rc5t583.c index e63d6a397e1..562b0c4d9cc 100644 --- a/drivers/gpio/gpio-rc5t583.c +++ b/drivers/gpio/gpio-rc5t583.c @@ -97,7 +97,7 @@ static int rc5t583_gpio_to_irq(struct gpio_chip *gc, unsigned offset) { struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc); - if ((offset >= 0) && (offset < 8)) + if (offset < RC5T583_MAX_GPIO) return rc5t583_gpio->rc5t583->irq_base + RC5T583_IRQ_GPIO0 + offset; return -EINVAL; @@ -119,10 +119,8 @@ static int rc5t583_gpio_probe(struct platform_device *pdev) rc5t583_gpio = devm_kzalloc(&pdev->dev, sizeof(*rc5t583_gpio), GFP_KERNEL); - if (!rc5t583_gpio) { - dev_warn(&pdev->dev, "Mem allocation for rc5t583_gpio failed"); + if (!rc5t583_gpio) return -ENOMEM; - } rc5t583_gpio->gpio_chip.label = "gpio-rc5t583", rc5t583_gpio->gpio_chip.owner = THIS_MODULE, @@ -133,7 +131,7 @@ static int rc5t583_gpio_probe(struct platform_device *pdev) rc5t583_gpio->gpio_chip.get = rc5t583_gpio_get, rc5t583_gpio->gpio_chip.to_irq = rc5t583_gpio_to_irq, rc5t583_gpio->gpio_chip.ngpio = RC5T583_MAX_GPIO, - rc5t583_gpio->gpio_chip.can_sleep = 1, + rc5t583_gpio->gpio_chip.can_sleep = true, rc5t583_gpio->gpio_chip.dev = &pdev->dev; rc5t583_gpio->gpio_chip.base = -1; rc5t583_gpio->rc5t583 = rc5t583; diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index 8b7e719a68c..b6ae89ea881 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -26,6 +26,7 @@ #include <linux/pinctrl/consumer.h> #include <linux/platform_data/gpio-rcar.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/spinlock.h> #include <linux/slab.h> @@ -283,9 +284,37 @@ static int gpio_rcar_irq_domain_map(struct irq_domain *h, unsigned int irq, static struct irq_domain_ops gpio_rcar_irq_domain_ops = { .map = gpio_rcar_irq_domain_map, + .xlate = irq_domain_xlate_twocell, }; -static void gpio_rcar_parse_pdata(struct gpio_rcar_priv *p) +struct gpio_rcar_info { + bool has_both_edge_trigger; +}; + +static const struct of_device_id gpio_rcar_of_table[] = { + { + .compatible = "renesas,gpio-r8a7790", + .data = (void *)&(const struct gpio_rcar_info) { + .has_both_edge_trigger = true, + }, + }, { + .compatible = "renesas,gpio-r8a7791", + .data = (void *)&(const struct gpio_rcar_info) { + .has_both_edge_trigger = true, + }, + }, { + .compatible = "renesas,gpio-rcar", + .data = (void *)&(const struct gpio_rcar_info) { + .has_both_edge_trigger = false, + }, + }, { + /* Terminator */ + }, +}; + +MODULE_DEVICE_TABLE(of, gpio_rcar_of_table); + +static int gpio_rcar_parse_pdata(struct gpio_rcar_priv *p) { struct gpio_rcar_config *pdata = dev_get_platdata(&p->pdev->dev); struct device_node *np = p->pdev->dev.of_node; @@ -295,11 +324,21 @@ static void gpio_rcar_parse_pdata(struct gpio_rcar_priv *p) if (pdata) { p->config = *pdata; } else if (IS_ENABLED(CONFIG_OF) && np) { + const struct of_device_id *match; + const struct gpio_rcar_info *info; + + match = of_match_node(gpio_rcar_of_table, np); + if (!match) + return -EINVAL; + + info = match->data; + ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, 0, &args); p->config.number_of_pins = ret == 0 ? args.args[2] : RCAR_MAX_GPIO_PER_BANK; p->config.gpio_base = -1; + p->config.has_both_edge_trigger = info->has_both_edge_trigger; } if (p->config.number_of_pins == 0 || @@ -309,6 +348,8 @@ static void gpio_rcar_parse_pdata(struct gpio_rcar_priv *p) p->config.number_of_pins, RCAR_MAX_GPIO_PER_BANK); p->config.number_of_pins = RCAR_MAX_GPIO_PER_BANK; } + + return 0; } static int gpio_rcar_probe(struct platform_device *pdev) @@ -317,12 +358,12 @@ static int gpio_rcar_probe(struct platform_device *pdev) struct resource *io, *irq; struct gpio_chip *gpio_chip; struct irq_chip *irq_chip; - const char *name = dev_name(&pdev->dev); + struct device *dev = &pdev->dev; + const char *name = dev_name(dev); int ret; - p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); + p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL); if (!p) { - dev_err(&pdev->dev, "failed to allocate driver data\n"); ret = -ENOMEM; goto err0; } @@ -331,23 +372,27 @@ static int gpio_rcar_probe(struct platform_device *pdev) spin_lock_init(&p->lock); /* Get device configuration from DT node or platform data. */ - gpio_rcar_parse_pdata(p); + ret = gpio_rcar_parse_pdata(p); + if (ret < 0) + return ret; platform_set_drvdata(pdev, p); + pm_runtime_enable(dev); + pm_runtime_get_sync(dev); + io = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!io || !irq) { - dev_err(&pdev->dev, "missing IRQ or IOMEM\n"); + dev_err(dev, "missing IRQ or IOMEM\n"); ret = -EINVAL; goto err0; } - p->base = devm_ioremap_nocache(&pdev->dev, io->start, - resource_size(io)); + p->base = devm_ioremap_nocache(dev, io->start, resource_size(io)); if (!p->base) { - dev_err(&pdev->dev, "failed to remap I/O memory\n"); + dev_err(dev, "failed to remap I/O memory\n"); ret = -ENXIO; goto err0; } @@ -361,7 +406,7 @@ static int gpio_rcar_probe(struct platform_device *pdev) gpio_chip->set = gpio_rcar_set; gpio_chip->to_irq = gpio_rcar_to_irq; gpio_chip->label = name; - gpio_chip->dev = &pdev->dev; + gpio_chip->dev = dev; gpio_chip->owner = THIS_MODULE; gpio_chip->base = p->config.gpio_base; gpio_chip->ngpio = p->config.number_of_pins; @@ -370,10 +415,9 @@ static int gpio_rcar_probe(struct platform_device *pdev) irq_chip->name = name; irq_chip->irq_mask = gpio_rcar_irq_disable; irq_chip->irq_unmask = gpio_rcar_irq_enable; - irq_chip->irq_enable = gpio_rcar_irq_enable; - irq_chip->irq_disable = gpio_rcar_irq_disable; irq_chip->irq_set_type = gpio_rcar_irq_set_type; - irq_chip->flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_SET_TYPE_MASKED; + irq_chip->flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_SET_TYPE_MASKED + | IRQCHIP_MASK_ON_SUSPEND; p->irq_domain = irq_domain_add_simple(pdev->dev.of_node, p->config.number_of_pins, @@ -381,30 +425,30 @@ static int gpio_rcar_probe(struct platform_device *pdev) &gpio_rcar_irq_domain_ops, p); if (!p->irq_domain) { ret = -ENXIO; - dev_err(&pdev->dev, "cannot initialize irq domain\n"); + dev_err(dev, "cannot initialize irq domain\n"); goto err0; } - if (devm_request_irq(&pdev->dev, irq->start, - gpio_rcar_irq_handler, IRQF_SHARED, name, p)) { - dev_err(&pdev->dev, "failed to request IRQ\n"); + if (devm_request_irq(dev, irq->start, gpio_rcar_irq_handler, + IRQF_SHARED, name, p)) { + dev_err(dev, "failed to request IRQ\n"); ret = -ENOENT; goto err1; } ret = gpiochip_add(gpio_chip); if (ret) { - dev_err(&pdev->dev, "failed to add GPIO controller\n"); + dev_err(dev, "failed to add GPIO controller\n"); goto err1; } - dev_info(&pdev->dev, "driving %d GPIOs\n", p->config.number_of_pins); + dev_info(dev, "driving %d GPIOs\n", p->config.number_of_pins); /* warn in case of mismatch if irq base is specified */ if (p->config.irq_base) { ret = irq_find_mapping(p->irq_domain, 0); if (p->config.irq_base != ret) - dev_warn(&pdev->dev, "irq base mismatch (%u/%u)\n", + dev_warn(dev, "irq base mismatch (%u/%u)\n", p->config.irq_base, ret); } @@ -412,7 +456,7 @@ static int gpio_rcar_probe(struct platform_device *pdev) ret = gpiochip_add_pin_range(gpio_chip, p->config.pctl_name, 0, gpio_chip->base, gpio_chip->ngpio); if (ret < 0) - dev_warn(&pdev->dev, "failed to add pin range\n"); + dev_warn(dev, "failed to add pin range\n"); } return 0; @@ -420,6 +464,8 @@ static int gpio_rcar_probe(struct platform_device *pdev) err1: irq_domain_remove(p->irq_domain); err0: + pm_runtime_put(dev); + pm_runtime_disable(dev); return ret; } @@ -433,20 +479,11 @@ static int gpio_rcar_remove(struct platform_device *pdev) return ret; irq_domain_remove(p->irq_domain); + pm_runtime_put(&pdev->dev); + pm_runtime_disable(&pdev->dev); return 0; } -#ifdef CONFIG_OF -static const struct of_device_id gpio_rcar_of_table[] = { - { - .compatible = "renesas,gpio-rcar", - }, - { }, -}; - -MODULE_DEVICE_TABLE(of, gpio_rcar_of_table); -#endif - static struct platform_driver gpio_rcar_device_driver = { .probe = gpio_rcar_probe, .remove = gpio_rcar_remove, diff --git a/drivers/gpio/gpio-rdc321x.c b/drivers/gpio/gpio-rdc321x.c index 88577c3272a..9fa7e53331c 100644 --- a/drivers/gpio/gpio-rdc321x.c +++ b/drivers/gpio/gpio-rdc321x.c @@ -141,17 +141,15 @@ static int rdc321x_gpio_probe(struct platform_device *pdev) return -ENODEV; } - rdc321x_gpio_dev = kzalloc(sizeof(struct rdc321x_gpio), GFP_KERNEL); - if (!rdc321x_gpio_dev) { - dev_err(&pdev->dev, "failed to allocate private data\n"); + rdc321x_gpio_dev = devm_kzalloc(&pdev->dev, sizeof(struct rdc321x_gpio), + GFP_KERNEL); + if (!rdc321x_gpio_dev) return -ENOMEM; - } r = platform_get_resource_byname(pdev, IORESOURCE_IO, "gpio-reg1"); if (!r) { dev_err(&pdev->dev, "failed to get gpio-reg1 resource\n"); - err = -ENODEV; - goto out_free; + return -ENODEV; } spin_lock_init(&rdc321x_gpio_dev->lock); @@ -162,8 +160,7 @@ static int rdc321x_gpio_probe(struct platform_device *pdev) r = platform_get_resource_byname(pdev, IORESOURCE_IO, "gpio-reg2"); if (!r) { dev_err(&pdev->dev, "failed to get gpio-reg2 resource\n"); - err = -ENODEV; - goto out_free; + return -ENODEV; } rdc321x_gpio_dev->reg2_ctrl_base = r->start; @@ -187,21 +184,17 @@ static int rdc321x_gpio_probe(struct platform_device *pdev) rdc321x_gpio_dev->reg1_data_base, &rdc321x_gpio_dev->data_reg[0]); if (err) - goto out_free; + return err; err = pci_read_config_dword(rdc321x_gpio_dev->sb_pdev, rdc321x_gpio_dev->reg2_data_base, &rdc321x_gpio_dev->data_reg[1]); if (err) - goto out_free; + return err; dev_info(&pdev->dev, "registering %d GPIOs\n", rdc321x_gpio_dev->chip.ngpio); return gpiochip_add(&rdc321x_gpio_dev->chip); - -out_free: - kfree(rdc321x_gpio_dev); - return err; } static int rdc321x_gpio_remove(struct platform_device *pdev) @@ -213,8 +206,6 @@ static int rdc321x_gpio_remove(struct platform_device *pdev) if (ret) dev_err(&pdev->dev, "failed to unregister chip\n"); - kfree(rdc321x_gpio_dev); - return ret; } diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c index 76e02b9460e..07105ee5c9a 100644 --- a/drivers/gpio/gpio-samsung.c +++ b/drivers/gpio/gpio-samsung.c @@ -30,10 +30,13 @@ #include <asm/irq.h> -#include <mach/hardware.h> #include <mach/map.h> #include <mach/regs-gpio.h> +#if defined(CONFIG_ARCH_S3C24XX) || defined(CONFIG_ARCH_S3C64XX) +#include <mach/gpio-samsung.h> +#endif + #include <plat/cpu.h> #include <plat/gpio-core.h> #include <plat/gpio-cfg.h> @@ -376,6 +379,7 @@ static int s5p64x0_gpio_setcfg_rbank(struct samsung_gpio_chip *chip, case 6: shift = ((off + 1) & 7) * 4; reg -= 4; + break; default: shift = ((off + 1) & 7) * 4; break; @@ -1053,7 +1057,7 @@ struct samsung_gpio_chip s3c24xx_gpios[] = { .base = S3C2410_GPA(0), .owner = THIS_MODULE, .label = "GPIOA", - .ngpio = 24, + .ngpio = 27, .direction_input = s3c24xx_gpiolib_banka_input, .direction_output = s3c24xx_gpiolib_banka_output, }, @@ -1062,7 +1066,7 @@ struct samsung_gpio_chip s3c24xx_gpios[] = { .base = S3C2410_GPB(0), .owner = THIS_MODULE, .label = "GPIOB", - .ngpio = 16, + .ngpio = 11, }, }, { .chip = { @@ -1107,7 +1111,7 @@ struct samsung_gpio_chip s3c24xx_gpios[] = { .base = S3C2410_GPH(0), .owner = THIS_MODULE, .label = "GPIOH", - .ngpio = 11, + .ngpio = 15, }, }, /* GPIOS for the S3C2443 and later devices. */ diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c index 5af65719b95..a9b1cd16c84 100644 --- a/drivers/gpio/gpio-sch.c +++ b/drivers/gpio/gpio-sch.c @@ -97,8 +97,6 @@ static int sch_gpio_core_direction_out(struct gpio_chip *gc, u8 curr_dirs; unsigned short offset, bit; - sch_gpio_core_set(gc, gpio_num, val); - spin_lock(&gpio_lock); offset = CGIO + gpio_num / 8; @@ -109,6 +107,17 @@ static int sch_gpio_core_direction_out(struct gpio_chip *gc, outb(curr_dirs & ~(1 << bit), gpio_ba + offset); spin_unlock(&gpio_lock); + + /* + * according to the datasheet, writing to the level register has no + * effect when GPIO is programmed as input. + * Actually the the level register is read-only when configured as input. + * Thus presetting the output level before switching to output is _NOT_ possible. + * Hence we set the level after configuring the GPIO as output. + * But we cannot prevent a short low pulse if direction is set to high + * and an external pull-up is connected. + */ + sch_gpio_core_set(gc, gpio_num, val); return 0; } @@ -178,8 +187,6 @@ static int sch_gpio_resume_direction_out(struct gpio_chip *gc, u8 curr_dirs; unsigned short offset, bit; - sch_gpio_resume_set(gc, gpio_num, val); - offset = RGIO + gpio_num / 8; bit = gpio_num % 8; @@ -190,6 +197,17 @@ static int sch_gpio_resume_direction_out(struct gpio_chip *gc, outb(curr_dirs & ~(1 << bit), gpio_ba + offset); spin_unlock(&gpio_lock); + + /* + * according to the datasheet, writing to the level register has no + * effect when GPIO is programmed as input. + * Actually the the level register is read-only when configured as input. + * Thus presetting the output level before switching to output is _NOT_ possible. + * Hence we set the level after configuring the GPIO as output. + * But we cannot prevent a short low pulse if direction is set to high + * and an external pull-up is connected. + */ + sch_gpio_resume_set(gc, gpio_num, val); return 0; } diff --git a/drivers/gpio/gpio-sch311x.c b/drivers/gpio/gpio-sch311x.c new file mode 100644 index 00000000000..f942b80ee40 --- /dev/null +++ b/drivers/gpio/gpio-sch311x.c @@ -0,0 +1,440 @@ +/* + * GPIO driver for the SMSC SCH311x Super-I/O chips + * + * Copyright (C) 2013 Bruno Randolf <br1@einfach.org> + * + * SuperIO functions and chip detection: + * (c) Copyright 2008 Wim Van Sebroeck <wim@iguana.be>. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/gpio.h> +#include <linux/bitops.h> +#include <linux/io.h> + +#define DRV_NAME "gpio-sch311x" + +#define SCH311X_GPIO_CONF_OUT 0x00 +#define SCH311X_GPIO_CONF_IN 0x01 +#define SCH311X_GPIO_CONF_INVERT 0x02 +#define SCH311X_GPIO_CONF_OPEN_DRAIN 0x80 + +#define SIO_CONFIG_KEY_ENTER 0x55 +#define SIO_CONFIG_KEY_EXIT 0xaa + +#define GP1 0x4b + +static int sch311x_ioports[] = { 0x2e, 0x4e, 0x162e, 0x164e }; + +static struct platform_device *sch311x_gpio_pdev; + +struct sch311x_pdev_data { /* platform device data */ + unsigned short runtime_reg; /* runtime register base address */ +}; + +struct sch311x_gpio_block { /* one GPIO block runtime data */ + struct gpio_chip chip; + unsigned short data_reg; /* from definition below */ + unsigned short *config_regs; /* pointer to definition below */ + unsigned short runtime_reg; /* runtime register */ + spinlock_t lock; /* lock for this GPIO block */ +}; + +struct sch311x_gpio_priv { /* driver private data */ + struct sch311x_gpio_block blocks[6]; +}; + +struct sch311x_gpio_block_def { /* register address definitions */ + unsigned short data_reg; + unsigned short config_regs[8]; + unsigned short base; +}; + +/* Note: some GPIOs are not available, these are marked with 0x00 */ + +static struct sch311x_gpio_block_def sch311x_gpio_blocks[] = { + { + .data_reg = 0x4b, /* GP1 */ + .config_regs = {0x23, 0x24, 0x25, 0x26, 0x27, 0x29, 0x2a, 0x2b}, + .base = 10, + }, + { + .data_reg = 0x4c, /* GP2 */ + .config_regs = {0x00, 0x2c, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x32}, + .base = 20, + }, + { + .data_reg = 0x4d, /* GP3 */ + .config_regs = {0x33, 0x34, 0x35, 0x36, 0x37, 0x00, 0x39, 0x3a}, + .base = 30, + }, + { + .data_reg = 0x4e, /* GP4 */ + .config_regs = {0x3b, 0x00, 0x3d, 0x00, 0x6e, 0x6f, 0x72, 0x73}, + .base = 40, + }, + { + .data_reg = 0x4f, /* GP5 */ + .config_regs = {0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46}, + .base = 50, + }, + { + .data_reg = 0x50, /* GP6 */ + .config_regs = {0x47, 0x48, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59}, + .base = 60, + }, +}; + +static inline struct sch311x_gpio_block * +to_sch311x_gpio_block(struct gpio_chip *chip) +{ + return container_of(chip, struct sch311x_gpio_block, chip); +} + + +/* + * Super-IO functions + */ + +static inline int sch311x_sio_enter(int sio_config_port) +{ + /* Don't step on other drivers' I/O space by accident. */ + if (!request_muxed_region(sio_config_port, 2, DRV_NAME)) { + pr_err(DRV_NAME "I/O address 0x%04x already in use\n", + sio_config_port); + return -EBUSY; + } + + outb(SIO_CONFIG_KEY_ENTER, sio_config_port); + return 0; +} + +static inline void sch311x_sio_exit(int sio_config_port) +{ + outb(SIO_CONFIG_KEY_EXIT, sio_config_port); + release_region(sio_config_port, 2); +} + +static inline int sch311x_sio_inb(int sio_config_port, int reg) +{ + outb(reg, sio_config_port); + return inb(sio_config_port + 1); +} + +static inline void sch311x_sio_outb(int sio_config_port, int reg, int val) +{ + outb(reg, sio_config_port); + outb(val, sio_config_port + 1); +} + + +/* + * GPIO functions + */ + +static int sch311x_gpio_request(struct gpio_chip *chip, unsigned offset) +{ + struct sch311x_gpio_block *block = to_sch311x_gpio_block(chip); + + if (block->config_regs[offset] == 0) /* GPIO is not available */ + return -ENODEV; + + if (!request_region(block->runtime_reg + block->config_regs[offset], + 1, DRV_NAME)) { + dev_err(chip->dev, "Failed to request region 0x%04x.\n", + block->runtime_reg + block->config_regs[offset]); + return -EBUSY; + } + return 0; +} + +static void sch311x_gpio_free(struct gpio_chip *chip, unsigned offset) +{ + struct sch311x_gpio_block *block = to_sch311x_gpio_block(chip); + + if (block->config_regs[offset] == 0) /* GPIO is not available */ + return; + + release_region(block->runtime_reg + block->config_regs[offset], 1); +} + +static int sch311x_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct sch311x_gpio_block *block = to_sch311x_gpio_block(chip); + unsigned char data; + + spin_lock(&block->lock); + data = inb(block->runtime_reg + block->data_reg); + spin_unlock(&block->lock); + + return !!(data & BIT(offset)); +} + +static void __sch311x_gpio_set(struct sch311x_gpio_block *block, + unsigned offset, int value) +{ + unsigned char data = inb(block->runtime_reg + block->data_reg); + if (value) + data |= BIT(offset); + else + data &= ~BIT(offset); + outb(data, block->runtime_reg + block->data_reg); +} + +static void sch311x_gpio_set(struct gpio_chip *chip, unsigned offset, + int value) +{ + struct sch311x_gpio_block *block = to_sch311x_gpio_block(chip); + + spin_lock(&block->lock); + __sch311x_gpio_set(block, offset, value); + spin_unlock(&block->lock); +} + +static int sch311x_gpio_direction_in(struct gpio_chip *chip, unsigned offset) +{ + struct sch311x_gpio_block *block = to_sch311x_gpio_block(chip); + + spin_lock(&block->lock); + outb(SCH311X_GPIO_CONF_IN, block->runtime_reg + + block->config_regs[offset]); + spin_unlock(&block->lock); + + return 0; +} + +static int sch311x_gpio_direction_out(struct gpio_chip *chip, unsigned offset, + int value) +{ + struct sch311x_gpio_block *block = to_sch311x_gpio_block(chip); + + spin_lock(&block->lock); + + outb(SCH311X_GPIO_CONF_OUT, block->runtime_reg + + block->config_regs[offset]); + + __sch311x_gpio_set(block, offset, value); + + spin_unlock(&block->lock); + return 0; +} + +static int sch311x_gpio_probe(struct platform_device *pdev) +{ + struct sch311x_pdev_data *pdata = pdev->dev.platform_data; + struct sch311x_gpio_priv *priv; + struct sch311x_gpio_block *block; + int err, i; + + /* we can register all GPIO data registers at once */ + if (!request_region(pdata->runtime_reg + GP1, 6, DRV_NAME)) { + dev_err(&pdev->dev, "Failed to request region 0x%04x-0x%04x.\n", + pdata->runtime_reg + GP1, pdata->runtime_reg + GP1 + 5); + return -EBUSY; + } + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + platform_set_drvdata(pdev, priv); + + for (i = 0; i < ARRAY_SIZE(priv->blocks); i++) { + block = &priv->blocks[i]; + + spin_lock_init(&block->lock); + + block->chip.label = DRV_NAME; + block->chip.owner = THIS_MODULE; + block->chip.request = sch311x_gpio_request; + block->chip.free = sch311x_gpio_free; + block->chip.direction_input = sch311x_gpio_direction_in; + block->chip.direction_output = sch311x_gpio_direction_out; + block->chip.get = sch311x_gpio_get; + block->chip.set = sch311x_gpio_set; + block->chip.ngpio = 8; + block->chip.dev = &pdev->dev; + block->chip.base = sch311x_gpio_blocks[i].base; + block->config_regs = sch311x_gpio_blocks[i].config_regs; + block->data_reg = sch311x_gpio_blocks[i].data_reg; + block->runtime_reg = pdata->runtime_reg; + + err = gpiochip_add(&block->chip); + if (err < 0) { + dev_err(&pdev->dev, + "Could not register gpiochip, %d\n", err); + goto exit_err; + } + dev_info(&pdev->dev, + "SMSC SCH311x GPIO block %d registered.\n", i); + } + + return 0; + +exit_err: + release_region(pdata->runtime_reg + GP1, 6); + /* release already registered chips */ + for (--i; i >= 0; i--) + gpiochip_remove(&priv->blocks[i].chip); + return err; +} + +static int sch311x_gpio_remove(struct platform_device *pdev) +{ + struct sch311x_pdev_data *pdata = pdev->dev.platform_data; + struct sch311x_gpio_priv *priv = platform_get_drvdata(pdev); + int err, i; + + release_region(pdata->runtime_reg + GP1, 6); + + for (i = 0; i < ARRAY_SIZE(priv->blocks); i++) { + err = gpiochip_remove(&priv->blocks[i].chip); + if (err) + return err; + dev_info(&pdev->dev, + "SMSC SCH311x GPIO block %d unregistered.\n", i); + } + return 0; +} + +static struct platform_driver sch311x_gpio_driver = { + .driver.name = DRV_NAME, + .driver.owner = THIS_MODULE, + .probe = sch311x_gpio_probe, + .remove = sch311x_gpio_remove, +}; + + +/* + * Init & exit routines + */ + +static int __init sch311x_detect(int sio_config_port, unsigned short *addr) +{ + int err = 0, reg; + unsigned short base_addr; + unsigned char dev_id; + + err = sch311x_sio_enter(sio_config_port); + if (err) + return err; + + /* Check device ID. */ + reg = sch311x_sio_inb(sio_config_port, 0x20); + switch (reg) { + case 0x7c: /* SCH3112 */ + dev_id = 2; + break; + case 0x7d: /* SCH3114 */ + dev_id = 4; + break; + case 0x7f: /* SCH3116 */ + dev_id = 6; + break; + default: + err = -ENODEV; + goto exit; + } + + /* Select logical device A (runtime registers) */ + sch311x_sio_outb(sio_config_port, 0x07, 0x0a); + + /* Check if Logical Device Register is currently active */ + if ((sch311x_sio_inb(sio_config_port, 0x30) & 0x01) == 0) + pr_info("Seems that LDN 0x0a is not active...\n"); + + /* Get the base address of the runtime registers */ + base_addr = (sch311x_sio_inb(sio_config_port, 0x60) << 8) | + sch311x_sio_inb(sio_config_port, 0x61); + if (!base_addr) { + pr_err("Base address not set\n"); + err = -ENODEV; + goto exit; + } + *addr = base_addr; + + pr_info("Found an SMSC SCH311%d chip at 0x%04x\n", dev_id, base_addr); + +exit: + sch311x_sio_exit(sio_config_port); + return err; +} + +static int __init sch311x_gpio_pdev_add(const unsigned short addr) +{ + struct sch311x_pdev_data pdata; + int err; + + pdata.runtime_reg = addr; + + sch311x_gpio_pdev = platform_device_alloc(DRV_NAME, -1); + if (!sch311x_gpio_pdev) + return -ENOMEM; + + err = platform_device_add_data(sch311x_gpio_pdev, + &pdata, sizeof(pdata)); + if (err) { + pr_err(DRV_NAME "Platform data allocation failed\n"); + goto err; + } + + err = platform_device_add(sch311x_gpio_pdev); + if (err) { + pr_err(DRV_NAME "Device addition failed\n"); + goto err; + } + return 0; + +err: + platform_device_put(sch311x_gpio_pdev); + return err; +} + +static int __init sch311x_gpio_init(void) +{ + int err, i; + unsigned short addr = 0; + + for (i = 0; i < ARRAY_SIZE(sch311x_ioports); i++) + if (sch311x_detect(sch311x_ioports[i], &addr) == 0) + break; + + if (!addr) + return -ENODEV; + + err = platform_driver_register(&sch311x_gpio_driver); + if (err) + return err; + + err = sch311x_gpio_pdev_add(addr); + if (err) + goto unreg_platform_driver; + + return 0; + +unreg_platform_driver: + platform_driver_unregister(&sch311x_gpio_driver); + return err; +} + +static void __exit sch311x_gpio_exit(void) +{ + platform_device_unregister(sch311x_gpio_pdev); + platform_driver_unregister(&sch311x_gpio_driver); +} + +module_init(sch311x_gpio_init); +module_exit(sch311x_gpio_exit); + +MODULE_AUTHOR("Bruno Randolf <br1@einfach.org>"); +MODULE_DESCRIPTION("SMSC SCH311x GPIO Driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:gpio-sch311x"); diff --git a/drivers/gpio/gpio-sodaville.c b/drivers/gpio/gpio-sodaville.c index 88f374ac775..7c6c518929b 100644 --- a/drivers/gpio/gpio-sodaville.c +++ b/drivers/gpio/gpio-sodaville.c @@ -176,8 +176,10 @@ static int sdv_register_irqsupport(struct sdv_gpio_chip_data *sd, sd->id = irq_domain_add_legacy(pdev->dev.of_node, SDV_NUM_PUB_GPIOS, sd->irq_base, 0, &irq_domain_sdv_ops, sd); - if (!sd->id) + if (!sd->id) { + ret = -ENODEV; goto out_free_irq; + } return 0; out_free_irq: free_irq(pdev->irq, sd); @@ -212,8 +214,10 @@ static int sdv_gpio_probe(struct pci_dev *pdev, } addr = pci_resource_start(pdev, GPIO_BAR); - if (!addr) + if (!addr) { + ret = -ENODEV; goto release_reg; + } sd->gpio_pub_base = ioremap(addr, pci_resource_len(pdev, GPIO_BAR)); prop = of_get_property(pdev->dev.of_node, "intel,muxctl", &len); @@ -270,7 +274,7 @@ static void sdv_gpio_remove(struct pci_dev *pdev) kfree(sd); } -static DEFINE_PCI_DEVICE_TABLE(sdv_gpio_pci_ids) = { +static const struct pci_device_id sdv_gpio_pci_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_SDV_GPIO) }, { 0, }, }; diff --git a/drivers/gpio/gpio-spear-spics.c b/drivers/gpio/gpio-spear-spics.c index e9a0415834e..353263c85d2 100644 --- a/drivers/gpio/gpio-spear-spics.c +++ b/drivers/gpio/gpio-spear-spics.c @@ -2,7 +2,7 @@ * SPEAr platform SPI chipselect abstraction over gpiolib * * Copyright (C) 2012 ST Microelectronics - * Shiraz Hashim <shiraz.hashim@st.com> + * Shiraz Hashim <shiraz.linux.kernel@gmail.com> * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any @@ -129,10 +129,8 @@ static int spics_gpio_probe(struct platform_device *pdev) int ret; spics = devm_kzalloc(&pdev->dev, sizeof(*spics), GFP_KERNEL); - if (!spics) { - dev_err(&pdev->dev, "memory allocation fail\n"); + if (!spics) return -ENOMEM; - } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); spics->base = devm_ioremap_resource(&pdev->dev, res); @@ -205,6 +203,6 @@ static int __init spics_gpio_init(void) } subsys_initcall(spics_gpio_init); -MODULE_AUTHOR("Shiraz Hashim <shiraz.hashim@st.com>"); +MODULE_AUTHOR("Shiraz Hashim <shiraz.linux.kernel@gmail.com>"); MODULE_DESCRIPTION("ST Microlectronics SPEAr SPI Chip Select Abstraction"); MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-sta2x11.c b/drivers/gpio/gpio-sta2x11.c index f2fb12c18da..68e3fcb1ace 100644 --- a/drivers/gpio/gpio-sta2x11.c +++ b/drivers/gpio/gpio-sta2x11.c @@ -146,7 +146,7 @@ static void gsta_gpio_setup(struct gsta_gpio *chip) /* called from probe */ gpio->dbg_show = NULL; gpio->base = gpio_base; gpio->ngpio = GSTA_NR_GPIO; - gpio->can_sleep = 0; + gpio->can_sleep = false; gpio->to_irq = gsta_gpio_to_irq; /* diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index 2647e243d47..628b5849429 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -23,7 +23,8 @@ enum { REG_RE, REG_FE, REG_IE }; #define CACHE_NR_REGS 3 -#define CACHE_NR_BANKS (STMPE_NR_GPIOS / 8) +/* No variant has more than 24 GPIOs */ +#define CACHE_NR_BANKS (24 / 8) struct stmpe_gpio { struct gpio_chip chip; @@ -31,8 +32,6 @@ struct stmpe_gpio { struct device *dev; struct mutex irq_lock; struct irq_domain *domain; - - int irq_base; unsigned norequest_mask; /* Caches of interrupt control registers for bus_lock */ @@ -129,7 +128,7 @@ static struct gpio_chip template_chip = { .set = stmpe_gpio_set, .to_irq = stmpe_gpio_to_irq, .request = stmpe_gpio_request, - .can_sleep = 1, + .can_sleep = true, }; static int stmpe_gpio_irq_set_type(struct irq_data *d, unsigned int type) @@ -311,13 +310,8 @@ static const struct irq_domain_ops stmpe_gpio_irq_simple_ops = { static int stmpe_gpio_irq_init(struct stmpe_gpio *stmpe_gpio, struct device_node *np) { - int base = 0; - - if (!np) - base = stmpe_gpio->irq_base; - stmpe_gpio->domain = irq_domain_add_simple(np, - stmpe_gpio->chip.ngpio, base, + stmpe_gpio->chip.ngpio, 0, &stmpe_gpio_irq_simple_ops, stmpe_gpio); if (!stmpe_gpio->domain) { dev_err(stmpe_gpio->dev, "failed to create irqdomain\n"); @@ -354,7 +348,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev) #ifdef CONFIG_OF stmpe_gpio->chip.of_node = np; #endif - stmpe_gpio->chip.base = pdata ? pdata->gpio_base : -1; + stmpe_gpio->chip.base = -1; if (pdata) stmpe_gpio->norequest_mask = pdata->norequest_mask; @@ -362,9 +356,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev) of_property_read_u32(np, "st,norequest-mask", &stmpe_gpio->norequest_mask); - if (irq >= 0) - stmpe_gpio->irq_base = stmpe->irq_base + STMPE_INT_GPIO(0); - else + if (irq < 0) dev_info(&pdev->dev, "device configured in no-irq mode; " "irqs are not available\n"); diff --git a/drivers/gpio/gpio-sx150x.c b/drivers/gpio/gpio-sx150x.c index d2983e9ad6a..b51ca9f5c14 100644 --- a/drivers/gpio/gpio-sx150x.c +++ b/drivers/gpio/gpio-sx150x.c @@ -22,7 +22,6 @@ #include <linux/module.h> #include <linux/mutex.h> #include <linux/slab.h> -#include <linux/workqueue.h> #include <linux/i2c/sx150x.h> #define NO_UPDATE_PENDING -1 @@ -436,7 +435,7 @@ static void sx150x_init_chip(struct sx150x_chip *chip, chip->gpio_chip.set = sx150x_gpio_set; chip->gpio_chip.to_irq = sx150x_gpio_to_irq; chip->gpio_chip.base = pdata->gpio_base; - chip->gpio_chip.can_sleep = 1; + chip->gpio_chip.can_sleep = true; chip->gpio_chip.ngpio = chip->dev_cfg->ngpios; if (pdata->oscio_is_gpo) ++chip->gpio_chip.ngpio; diff --git a/drivers/gpio/gpio-syscon.c b/drivers/gpio/gpio-syscon.c new file mode 100644 index 00000000000..b50fe129774 --- /dev/null +++ b/drivers/gpio/gpio-syscon.c @@ -0,0 +1,191 @@ +/* + * SYSCON GPIO driver + * + * Copyright (C) 2014 Alexander Shiyan <shc_work@mail.ru> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/err.h> +#include <linux/gpio.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/mfd/syscon.h> + +#define GPIO_SYSCON_FEAT_IN BIT(0) +#define GPIO_SYSCON_FEAT_OUT BIT(1) +#define GPIO_SYSCON_FEAT_DIR BIT(2) + +/* SYSCON driver is designed to use 32-bit wide registers */ +#define SYSCON_REG_SIZE (4) +#define SYSCON_REG_BITS (SYSCON_REG_SIZE * 8) + +/** + * struct syscon_gpio_data - Configuration for the device. + * compatible: SYSCON driver compatible string. + * flags: Set of GPIO_SYSCON_FEAT_ flags: + * GPIO_SYSCON_FEAT_IN: GPIOs supports input, + * GPIO_SYSCON_FEAT_OUT: GPIOs supports output, + * GPIO_SYSCON_FEAT_DIR: GPIOs supports switch direction. + * bit_count: Number of bits used as GPIOs. + * dat_bit_offset: Offset (in bits) to the first GPIO bit. + * dir_bit_offset: Optional offset (in bits) to the first bit to switch + * GPIO direction (Used with GPIO_SYSCON_FEAT_DIR flag). + */ + +struct syscon_gpio_data { + const char *compatible; + unsigned int flags; + unsigned int bit_count; + unsigned int dat_bit_offset; + unsigned int dir_bit_offset; +}; + +struct syscon_gpio_priv { + struct gpio_chip chip; + struct regmap *syscon; + const struct syscon_gpio_data *data; +}; + +static inline struct syscon_gpio_priv *to_syscon_gpio(struct gpio_chip *chip) +{ + return container_of(chip, struct syscon_gpio_priv, chip); +} + +static int syscon_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct syscon_gpio_priv *priv = to_syscon_gpio(chip); + unsigned int val, offs = priv->data->dat_bit_offset + offset; + int ret; + + ret = regmap_read(priv->syscon, + (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, &val); + if (ret) + return ret; + + return !!(val & BIT(offs % SYSCON_REG_BITS)); +} + +static void syscon_gpio_set(struct gpio_chip *chip, unsigned offset, int val) +{ + struct syscon_gpio_priv *priv = to_syscon_gpio(chip); + unsigned int offs = priv->data->dat_bit_offset + offset; + + regmap_update_bits(priv->syscon, + (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, + BIT(offs % SYSCON_REG_BITS), + val ? BIT(offs % SYSCON_REG_BITS) : 0); +} + +static int syscon_gpio_dir_in(struct gpio_chip *chip, unsigned offset) +{ + struct syscon_gpio_priv *priv = to_syscon_gpio(chip); + + if (priv->data->flags & GPIO_SYSCON_FEAT_DIR) { + unsigned int offs = priv->data->dir_bit_offset + offset; + + regmap_update_bits(priv->syscon, + (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, + BIT(offs % SYSCON_REG_BITS), 0); + } + + return 0; +} + +static int syscon_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int val) +{ + struct syscon_gpio_priv *priv = to_syscon_gpio(chip); + + if (priv->data->flags & GPIO_SYSCON_FEAT_DIR) { + unsigned int offs = priv->data->dir_bit_offset + offset; + + regmap_update_bits(priv->syscon, + (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, + BIT(offs % SYSCON_REG_BITS), + BIT(offs % SYSCON_REG_BITS)); + } + + syscon_gpio_set(chip, offset, val); + + return 0; +} + +static const struct syscon_gpio_data clps711x_mctrl_gpio = { + /* ARM CLPS711X SYSFLG1 Bits 8-10 */ + .compatible = "cirrus,clps711x-syscon1", + .flags = GPIO_SYSCON_FEAT_IN, + .bit_count = 3, + .dat_bit_offset = 0x40 * 8 + 8, +}; + +static const struct of_device_id syscon_gpio_ids[] = { + { + .compatible = "cirrus,clps711x-mctrl-gpio", + .data = &clps711x_mctrl_gpio, + }, + { } +}; +MODULE_DEVICE_TABLE(of, syscon_gpio_ids); + +static int syscon_gpio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct of_device_id *of_id = of_match_device(syscon_gpio_ids, dev); + struct syscon_gpio_priv *priv; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->data = of_id->data; + + priv->syscon = + syscon_regmap_lookup_by_compatible(priv->data->compatible); + if (IS_ERR(priv->syscon)) + return PTR_ERR(priv->syscon); + + priv->chip.dev = dev; + priv->chip.owner = THIS_MODULE; + priv->chip.label = dev_name(dev); + priv->chip.base = -1; + priv->chip.ngpio = priv->data->bit_count; + priv->chip.get = syscon_gpio_get; + if (priv->data->flags & GPIO_SYSCON_FEAT_IN) + priv->chip.direction_input = syscon_gpio_dir_in; + if (priv->data->flags & GPIO_SYSCON_FEAT_OUT) { + priv->chip.set = syscon_gpio_set; + priv->chip.direction_output = syscon_gpio_dir_out; + } + + platform_set_drvdata(pdev, priv); + + return gpiochip_add(&priv->chip); +} + +static int syscon_gpio_remove(struct platform_device *pdev) +{ + struct syscon_gpio_priv *priv = platform_get_drvdata(pdev); + + return gpiochip_remove(&priv->chip); +} + +static struct platform_driver syscon_gpio_driver = { + .driver = { + .name = "gpio-syscon", + .owner = THIS_MODULE, + .of_match_table = syscon_gpio_ids, + }, + .probe = syscon_gpio_probe, + .remove = syscon_gpio_remove, +}; +module_platform_driver(syscon_gpio_driver); + +MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>"); +MODULE_DESCRIPTION("SYSCON GPIO driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-tb10x.c b/drivers/gpio/gpio-tb10x.c index da071ddbad9..07bce97647a 100644 --- a/drivers/gpio/gpio-tb10x.c +++ b/drivers/gpio/gpio-tb10x.c @@ -222,7 +222,7 @@ static int tb10x_gpio_probe(struct platform_device *pdev) tb10x_gpio->gc.free = tb10x_gpio_free; tb10x_gpio->gc.base = -1; tb10x_gpio->gc.ngpio = ngpio; - tb10x_gpio->gc.can_sleep = 0; + tb10x_gpio->gc.can_sleep = false; ret = gpiochip_add(&tb10x_gpio->gc); @@ -318,7 +318,7 @@ static struct platform_driver tb10x_gpio_driver = { .remove = tb10x_gpio_remove, .driver = { .name = "tb10x-gpio", - .of_match_table = of_match_ptr(tb10x_gpio_dt_ids), + .of_match_table = tb10x_gpio_dt_ids, .owner = THIS_MODULE, } }; diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c index ddb5fefaa71..51f7cbd9ff7 100644 --- a/drivers/gpio/gpio-tc3589x.c +++ b/drivers/gpio/gpio-tc3589x.c @@ -12,8 +12,6 @@ #include <linux/slab.h> #include <linux/gpio.h> #include <linux/of.h> -#include <linux/irq.h> -#include <linux/irqdomain.h> #include <linux/interrupt.h> #include <linux/mfd/tc3589x.h> @@ -31,10 +29,6 @@ struct tc3589x_gpio { struct tc3589x *tc3589x; struct device *dev; struct mutex irq_lock; - struct irq_domain *domain; - - int irq_base; - /* Caches of interrupt control registers for bus_lock */ u8 regs[CACHE_NR_REGS][CACHE_NR_BANKS]; u8 oldregs[CACHE_NR_REGS][CACHE_NR_BANKS]; @@ -95,30 +89,6 @@ static int tc3589x_gpio_direction_input(struct gpio_chip *chip, return tc3589x_set_bits(tc3589x, reg, 1 << pos, 0); } -/** - * tc3589x_gpio_irq_get_irq(): Map a hardware IRQ on a chip to a Linux IRQ - * - * @tc3589x_gpio: tc3589x_gpio_irq controller to operate on. - * @irq: index of the hardware interrupt requested in the chip IRQs - * - * Useful for drivers to request their own IRQs. - */ -static int tc3589x_gpio_irq_get_irq(struct tc3589x_gpio *tc3589x_gpio, - int hwirq) -{ - if (!tc3589x_gpio) - return -EINVAL; - - return irq_create_mapping(tc3589x_gpio->domain, hwirq); -} - -static int tc3589x_gpio_to_irq(struct gpio_chip *chip, unsigned offset) -{ - struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip); - - return tc3589x_gpio_irq_get_irq(tc3589x_gpio, offset); -} - static struct gpio_chip template_chip = { .label = "tc3589x", .owner = THIS_MODULE, @@ -126,13 +96,13 @@ static struct gpio_chip template_chip = { .get = tc3589x_gpio_get, .direction_output = tc3589x_gpio_direction_output, .set = tc3589x_gpio_set, - .to_irq = tc3589x_gpio_to_irq, - .can_sleep = 1, + .can_sleep = true, }; static int tc3589x_gpio_irq_set_type(struct irq_data *d, unsigned int type) { - struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip); int offset = d->hwirq; int regoffset = offset / 8; int mask = 1 << (offset % 8); @@ -159,14 +129,16 @@ static int tc3589x_gpio_irq_set_type(struct irq_data *d, unsigned int type) static void tc3589x_gpio_irq_lock(struct irq_data *d) { - struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip); mutex_lock(&tc3589x_gpio->irq_lock); } static void tc3589x_gpio_irq_sync_unlock(struct irq_data *d) { - struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip); struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; static const u8 regmap[] = { [REG_IBE] = TC3589x_GPIOIBE0, @@ -194,7 +166,8 @@ static void tc3589x_gpio_irq_sync_unlock(struct irq_data *d) static void tc3589x_gpio_irq_mask(struct irq_data *d) { - struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip); int offset = d->hwirq; int regoffset = offset / 8; int mask = 1 << (offset % 8); @@ -204,7 +177,8 @@ static void tc3589x_gpio_irq_mask(struct irq_data *d) static void tc3589x_gpio_irq_unmask(struct irq_data *d) { - struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip); int offset = d->hwirq; int regoffset = offset / 8; int mask = 1 << (offset % 8); @@ -242,7 +216,8 @@ static irqreturn_t tc3589x_gpio_irq(int irq, void *dev) while (stat) { int bit = __ffs(stat); int line = i * 8 + bit; - int irq = tc3589x_gpio_irq_get_irq(tc3589x_gpio, line); + int irq = irq_find_mapping(tc3589x_gpio->chip.irqdomain, + line); handle_nested_irq(irq); stat &= ~(1 << bit); @@ -254,61 +229,6 @@ static irqreturn_t tc3589x_gpio_irq(int irq, void *dev) return IRQ_HANDLED; } -static int tc3589x_gpio_irq_map(struct irq_domain *d, unsigned int irq, - irq_hw_number_t hwirq) -{ - struct tc3589x *tc3589x_gpio = d->host_data; - - irq_set_chip_data(irq, tc3589x_gpio); - irq_set_chip_and_handler(irq, &tc3589x_gpio_irq_chip, - handle_simple_irq); - irq_set_nested_thread(irq, 1); -#ifdef CONFIG_ARM - set_irq_flags(irq, IRQF_VALID); -#else - irq_set_noprobe(irq); -#endif - - return 0; -} - -static void tc3589x_gpio_irq_unmap(struct irq_domain *d, unsigned int irq) -{ -#ifdef CONFIG_ARM - set_irq_flags(irq, 0); -#endif - irq_set_chip_and_handler(irq, NULL, NULL); - irq_set_chip_data(irq, NULL); -} - -static struct irq_domain_ops tc3589x_irq_ops = { - .map = tc3589x_gpio_irq_map, - .unmap = tc3589x_gpio_irq_unmap, - .xlate = irq_domain_xlate_twocell, -}; - -static int tc3589x_gpio_irq_init(struct tc3589x_gpio *tc3589x_gpio, - struct device_node *np) -{ - int base = tc3589x_gpio->irq_base; - - /* - * If this results in a linear domain, irq_create_mapping() will - * take care of allocating IRQ descriptors at runtime. When a base - * is provided, the IRQ descriptors will be allocated when the - * domain is instantiated. - */ - tc3589x_gpio->domain = irq_domain_add_simple(np, - tc3589x_gpio->chip.ngpio, base, &tc3589x_irq_ops, - tc3589x_gpio); - if (!tc3589x_gpio->domain) { - dev_err(tc3589x_gpio->dev, "Failed to create irqdomain\n"); - return -ENOSYS; - } - - return 0; -} - static int tc3589x_gpio_probe(struct platform_device *pdev) { struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent); @@ -329,7 +249,8 @@ static int tc3589x_gpio_probe(struct platform_device *pdev) if (irq < 0) return irq; - tc3589x_gpio = kzalloc(sizeof(struct tc3589x_gpio), GFP_KERNEL); + tc3589x_gpio = devm_kzalloc(&pdev->dev, sizeof(struct tc3589x_gpio), + GFP_KERNEL); if (!tc3589x_gpio) return -ENOMEM; @@ -347,30 +268,36 @@ static int tc3589x_gpio_probe(struct platform_device *pdev) tc3589x_gpio->chip.of_node = np; #endif - tc3589x_gpio->irq_base = tc3589x->irq_base ? - tc3589x->irq_base + TC3589x_INT_GPIO(0) : 0; - /* Bring the GPIO module out of reset */ ret = tc3589x_set_bits(tc3589x, TC3589x_RSTCTRL, TC3589x_RSTCTRL_GPIRST, 0); if (ret < 0) - goto out_free; - - ret = tc3589x_gpio_irq_init(tc3589x_gpio, np); - if (ret) - goto out_free; + return ret; - ret = request_threaded_irq(irq, NULL, tc3589x_gpio_irq, IRQF_ONESHOT, - "tc3589x-gpio", tc3589x_gpio); + ret = devm_request_threaded_irq(&pdev->dev, + irq, NULL, tc3589x_gpio_irq, + IRQF_ONESHOT, "tc3589x-gpio", + tc3589x_gpio); if (ret) { dev_err(&pdev->dev, "unable to get irq: %d\n", ret); - goto out_free; + return ret; } ret = gpiochip_add(&tc3589x_gpio->chip); if (ret) { dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret); - goto out_freeirq; + return ret; + } + + ret = gpiochip_irqchip_add(&tc3589x_gpio->chip, + &tc3589x_gpio_irq_chip, + 0, + handle_simple_irq, + IRQ_TYPE_NONE); + if (ret) { + dev_err(&pdev->dev, + "could not connect irqchip to gpiochip\n"); + return ret; } if (pdata && pdata->setup) @@ -379,12 +306,6 @@ static int tc3589x_gpio_probe(struct platform_device *pdev) platform_set_drvdata(pdev, tc3589x_gpio); return 0; - -out_freeirq: - free_irq(irq, tc3589x_gpio); -out_free: - kfree(tc3589x_gpio); - return ret; } static int tc3589x_gpio_remove(struct platform_device *pdev) @@ -392,7 +313,6 @@ static int tc3589x_gpio_remove(struct platform_device *pdev) struct tc3589x_gpio *tc3589x_gpio = platform_get_drvdata(pdev); struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; struct tc3589x_gpio_platform_data *pdata = tc3589x->pdata->gpio; - int irq = platform_get_irq(pdev, 0); int ret; if (pdata && pdata->remove) @@ -405,10 +325,6 @@ static int tc3589x_gpio_remove(struct platform_device *pdev) return ret; } - free_irq(irq, tc3589x_gpio); - - kfree(tc3589x_gpio); - return 0; } diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index cfd3b9037bc..4e8fb8261a8 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -408,7 +408,7 @@ static struct tegra_gpio_soc_config tegra30_gpio_config = { .upper_offset = 0x80, }; -static struct of_device_id tegra_gpio_of_match[] = { +static const struct of_device_id tegra_gpio_of_match[] = { { .compatible = "nvidia,tegra30-gpio", .data = &tegra30_gpio_config }, { .compatible = "nvidia,tegra20-gpio", .data = &tegra20_gpio_config }, { }, @@ -425,6 +425,7 @@ static int tegra_gpio_probe(struct platform_device *pdev) struct tegra_gpio_soc_config *config; struct resource *res; struct tegra_gpio_bank *bank; + int ret; int gpio; int i; int j; @@ -457,10 +458,8 @@ static int tegra_gpio_probe(struct platform_device *pdev) tegra_gpio_banks = devm_kzalloc(&pdev->dev, tegra_gpio_bank_count * sizeof(*tegra_gpio_banks), GFP_KERNEL); - if (!tegra_gpio_banks) { - dev_err(&pdev->dev, "Couldn't allocate bank structure\n"); + if (!tegra_gpio_banks) return -ENODEV; - } irq_domain = irq_domain_add_linear(pdev->dev.of_node, tegra_gpio_chip.ngpio, @@ -494,7 +493,11 @@ static int tegra_gpio_probe(struct platform_device *pdev) tegra_gpio_chip.of_node = pdev->dev.of_node; - gpiochip_add(&tegra_gpio_chip); + ret = gpiochip_add(&tegra_gpio_chip); + if (ret < 0) { + irq_domain_remove(irq_domain); + return ret; + } for (gpio = 0; gpio < tegra_gpio_chip.ngpio; gpio++) { int irq = irq_create_mapping(irq_domain, gpio); diff --git a/drivers/gpio/gpio-timberdale.c b/drivers/gpio/gpio-timberdale.c index 7a0e956ef1e..efc7c129016 100644 --- a/drivers/gpio/gpio-timberdale.c +++ b/drivers/gpio/gpio-timberdale.c @@ -224,6 +224,7 @@ static struct irq_chip timbgpio_irqchip = { static int timbgpio_probe(struct platform_device *pdev) { int err, i; + struct device *dev = &pdev->dev; struct gpio_chip *gc; struct timbgpio *tgpio; struct resource *iomem; @@ -231,35 +232,35 @@ static int timbgpio_probe(struct platform_device *pdev) int irq = platform_get_irq(pdev, 0); if (!pdata || pdata->nr_pins > 32) { - err = -EINVAL; - goto err_mem; + dev_err(dev, "Invalid platform data\n"); + return -EINVAL; } iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!iomem) { - err = -EINVAL; - goto err_mem; + dev_err(dev, "Unable to get resource\n"); + return -EINVAL; } - tgpio = kzalloc(sizeof(*tgpio), GFP_KERNEL); + tgpio = devm_kzalloc(dev, sizeof(struct timbgpio), GFP_KERNEL); if (!tgpio) { - err = -EINVAL; - goto err_mem; + dev_err(dev, "Memory alloc failed\n"); + return -EINVAL; } tgpio->irq_base = pdata->irq_base; spin_lock_init(&tgpio->lock); - if (!request_mem_region(iomem->start, resource_size(iomem), - DRIVER_NAME)) { - err = -EBUSY; - goto err_request; + if (!devm_request_mem_region(dev, iomem->start, resource_size(iomem), + DRIVER_NAME)) { + dev_err(dev, "Region already claimed\n"); + return -EBUSY; } - tgpio->membase = ioremap(iomem->start, resource_size(iomem)); + tgpio->membase = devm_ioremap(dev, iomem->start, resource_size(iomem)); if (!tgpio->membase) { - err = -ENOMEM; - goto err_ioremap; + dev_err(dev, "Cannot ioremap\n"); + return -ENOMEM; } gc = &tgpio->gpio; @@ -275,11 +276,11 @@ static int timbgpio_probe(struct platform_device *pdev) gc->dbg_show = NULL; gc->base = pdata->gpio_base; gc->ngpio = pdata->nr_pins; - gc->can_sleep = 0; + gc->can_sleep = false; err = gpiochip_add(gc); if (err) - goto err_chipadd; + return err; platform_set_drvdata(pdev, tgpio); @@ -290,8 +291,8 @@ static int timbgpio_probe(struct platform_device *pdev) return 0; for (i = 0; i < pdata->nr_pins; i++) { - irq_set_chip_and_handler_name(tgpio->irq_base + i, - &timbgpio_irqchip, handle_simple_irq, "mux"); + irq_set_chip_and_handler(tgpio->irq_base + i, + &timbgpio_irqchip, handle_simple_irq); irq_set_chip_data(tgpio->irq_base + i, tgpio); #ifdef CONFIG_ARM set_irq_flags(tgpio->irq_base + i, IRQF_VALID | IRQF_PROBE); @@ -302,17 +303,6 @@ static int timbgpio_probe(struct platform_device *pdev) irq_set_chained_handler(irq, timbgpio_irq); return 0; - -err_chipadd: - iounmap(tgpio->membase); -err_ioremap: - release_mem_region(iomem->start, resource_size(iomem)); -err_request: - kfree(tgpio); -err_mem: - printk(KERN_ERR DRIVER_NAME": Failed to register GPIOs: %d\n", err); - - return err; } static int timbgpio_remove(struct platform_device *pdev) @@ -320,7 +310,6 @@ static int timbgpio_remove(struct platform_device *pdev) int err; struct timbgpio_platform_data *pdata = dev_get_platdata(&pdev->dev); struct timbgpio *tgpio = platform_get_drvdata(pdev); - struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); int irq = platform_get_irq(pdev, 0); if (irq >= 0 && tgpio->irq_base > 0) { @@ -338,10 +327,6 @@ static int timbgpio_remove(struct platform_device *pdev) if (err) printk(KERN_ERR DRIVER_NAME": failed to remove gpio_chip\n"); - iounmap(tgpio->membase); - release_mem_region(iomem->start, resource_size(iomem)); - kfree(tgpio); - return 0; } diff --git a/drivers/gpio/gpio-tnetv107x.c b/drivers/gpio/gpio-tnetv107x.c deleted file mode 100644 index 58445bb6910..00000000000 --- a/drivers/gpio/gpio-tnetv107x.c +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Texas Instruments TNETV107X GPIO Controller - * - * Copyright (C) 2010 Texas Instruments - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/gpio.h> -#include <linux/platform_data/gpio-davinci.h> - -#include <mach/common.h> -#include <mach/tnetv107x.h> - -struct tnetv107x_gpio_regs { - u32 idver; - u32 data_in[3]; - u32 data_out[3]; - u32 direction[3]; - u32 enable[3]; -}; - -#define gpio_reg_index(gpio) ((gpio) >> 5) -#define gpio_reg_bit(gpio) BIT((gpio) & 0x1f) - -#define gpio_reg_rmw(reg, mask, val) \ - __raw_writel((__raw_readl(reg) & ~(mask)) | (val), (reg)) - -#define gpio_reg_set_bit(reg, gpio) \ - gpio_reg_rmw((reg) + gpio_reg_index(gpio), 0, gpio_reg_bit(gpio)) - -#define gpio_reg_clear_bit(reg, gpio) \ - gpio_reg_rmw((reg) + gpio_reg_index(gpio), gpio_reg_bit(gpio), 0) - -#define gpio_reg_get_bit(reg, gpio) \ - (__raw_readl((reg) + gpio_reg_index(gpio)) & gpio_reg_bit(gpio)) - -#define chip2controller(chip) \ - container_of(chip, struct davinci_gpio_controller, chip) - -#define TNETV107X_GPIO_CTLRS DIV_ROUND_UP(TNETV107X_N_GPIO, 32) - -static struct davinci_gpio_controller chips[TNETV107X_GPIO_CTLRS]; - -static int tnetv107x_gpio_request(struct gpio_chip *chip, unsigned offset) -{ - struct davinci_gpio_controller *ctlr = chip2controller(chip); - struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs; - unsigned gpio = chip->base + offset; - unsigned long flags; - - spin_lock_irqsave(&ctlr->lock, flags); - - gpio_reg_set_bit(regs->enable, gpio); - - spin_unlock_irqrestore(&ctlr->lock, flags); - - return 0; -} - -static void tnetv107x_gpio_free(struct gpio_chip *chip, unsigned offset) -{ - struct davinci_gpio_controller *ctlr = chip2controller(chip); - struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs; - unsigned gpio = chip->base + offset; - unsigned long flags; - - spin_lock_irqsave(&ctlr->lock, flags); - - gpio_reg_clear_bit(regs->enable, gpio); - - spin_unlock_irqrestore(&ctlr->lock, flags); -} - -static int tnetv107x_gpio_dir_in(struct gpio_chip *chip, unsigned offset) -{ - struct davinci_gpio_controller *ctlr = chip2controller(chip); - struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs; - unsigned gpio = chip->base + offset; - unsigned long flags; - - spin_lock_irqsave(&ctlr->lock, flags); - - gpio_reg_set_bit(regs->direction, gpio); - - spin_unlock_irqrestore(&ctlr->lock, flags); - - return 0; -} - -static int tnetv107x_gpio_dir_out(struct gpio_chip *chip, - unsigned offset, int value) -{ - struct davinci_gpio_controller *ctlr = chip2controller(chip); - struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs; - unsigned gpio = chip->base + offset; - unsigned long flags; - - spin_lock_irqsave(&ctlr->lock, flags); - - if (value) - gpio_reg_set_bit(regs->data_out, gpio); - else - gpio_reg_clear_bit(regs->data_out, gpio); - - gpio_reg_clear_bit(regs->direction, gpio); - - spin_unlock_irqrestore(&ctlr->lock, flags); - - return 0; -} - -static int tnetv107x_gpio_get(struct gpio_chip *chip, unsigned offset) -{ - struct davinci_gpio_controller *ctlr = chip2controller(chip); - struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs; - unsigned gpio = chip->base + offset; - int ret; - - ret = gpio_reg_get_bit(regs->data_in, gpio); - - return ret ? 1 : 0; -} - -static void tnetv107x_gpio_set(struct gpio_chip *chip, - unsigned offset, int value) -{ - struct davinci_gpio_controller *ctlr = chip2controller(chip); - struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs; - unsigned gpio = chip->base + offset; - unsigned long flags; - - spin_lock_irqsave(&ctlr->lock, flags); - - if (value) - gpio_reg_set_bit(regs->data_out, gpio); - else - gpio_reg_clear_bit(regs->data_out, gpio); - - spin_unlock_irqrestore(&ctlr->lock, flags); -} - -static int __init tnetv107x_gpio_setup(void) -{ - int i, base; - unsigned ngpio; - struct davinci_soc_info *soc_info = &davinci_soc_info; - struct tnetv107x_gpio_regs *regs; - struct davinci_gpio_controller *ctlr; - - if (soc_info->gpio_type != GPIO_TYPE_TNETV107X) - return 0; - - ngpio = soc_info->gpio_num; - if (ngpio == 0) { - pr_err("GPIO setup: how many GPIOs?\n"); - return -EINVAL; - } - - if (WARN_ON(TNETV107X_N_GPIO < ngpio)) - ngpio = TNETV107X_N_GPIO; - - regs = ioremap(soc_info->gpio_base, SZ_4K); - if (WARN_ON(!regs)) - return -EINVAL; - - for (i = 0, base = 0; base < ngpio; i++, base += 32) { - ctlr = &chips[i]; - - ctlr->chip.label = "tnetv107x"; - ctlr->chip.can_sleep = 0; - ctlr->chip.base = base; - ctlr->chip.ngpio = ngpio - base; - if (ctlr->chip.ngpio > 32) - ctlr->chip.ngpio = 32; - - ctlr->chip.request = tnetv107x_gpio_request; - ctlr->chip.free = tnetv107x_gpio_free; - ctlr->chip.direction_input = tnetv107x_gpio_dir_in; - ctlr->chip.get = tnetv107x_gpio_get; - ctlr->chip.direction_output = tnetv107x_gpio_dir_out; - ctlr->chip.set = tnetv107x_gpio_set; - - spin_lock_init(&ctlr->lock); - - ctlr->regs = regs; - ctlr->set_data = ®s->data_out[i]; - ctlr->clr_data = ®s->data_out[i]; - ctlr->in_data = ®s->data_in[i]; - - gpiochip_add(&ctlr->chip); - } - - soc_info->gpio_ctlrs = chips; - soc_info->gpio_ctlrs_num = DIV_ROUND_UP(ngpio, 32); - return 0; -} -pure_initcall(tnetv107x_gpio_setup); diff --git a/drivers/gpio/gpio-tps6586x.c b/drivers/gpio/gpio-tps6586x.c index 29e8e750bd4..a69fbea4125 100644 --- a/drivers/gpio/gpio-tps6586x.c +++ b/drivers/gpio/gpio-tps6586x.c @@ -97,10 +97,8 @@ static int tps6586x_gpio_probe(struct platform_device *pdev) pdata = dev_get_platdata(pdev->dev.parent); tps6586x_gpio = devm_kzalloc(&pdev->dev, sizeof(*tps6586x_gpio), GFP_KERNEL); - if (!tps6586x_gpio) { - dev_err(&pdev->dev, "Could not allocate tps6586x_gpio\n"); + if (!tps6586x_gpio) return -ENOMEM; - } tps6586x_gpio->parent = pdev->dev.parent; @@ -108,7 +106,7 @@ static int tps6586x_gpio_probe(struct platform_device *pdev) tps6586x_gpio->gpio_chip.label = pdev->name; tps6586x_gpio->gpio_chip.dev = &pdev->dev; tps6586x_gpio->gpio_chip.ngpio = 4; - tps6586x_gpio->gpio_chip.can_sleep = 1; + tps6586x_gpio->gpio_chip.can_sleep = true; /* FIXME: add handling of GPIOs as dedicated inputs */ tps6586x_gpio->gpio_chip.direction_output = tps6586x_gpio_output; diff --git a/drivers/gpio/gpio-tps65910.c b/drivers/gpio/gpio-tps65910.c index 06146219d9d..e2f8cda235e 100644 --- a/drivers/gpio/gpio-tps65910.c +++ b/drivers/gpio/gpio-tps65910.c @@ -123,10 +123,8 @@ static int tps65910_gpio_probe(struct platform_device *pdev) tps65910_gpio = devm_kzalloc(&pdev->dev, sizeof(*tps65910_gpio), GFP_KERNEL); - if (!tps65910_gpio) { - dev_err(&pdev->dev, "Could not allocate tps65910_gpio\n"); + if (!tps65910_gpio) return -ENOMEM; - } tps65910_gpio->tps65910 = tps65910; @@ -143,7 +141,7 @@ static int tps65910_gpio_probe(struct platform_device *pdev) default: return -EINVAL; } - tps65910_gpio->gpio_chip.can_sleep = 1; + tps65910_gpio->gpio_chip.can_sleep = true; tps65910_gpio->gpio_chip.direction_input = tps65910_gpio_input; tps65910_gpio->gpio_chip.direction_output = tps65910_gpio_output; tps65910_gpio->gpio_chip.set = tps65910_gpio_set; diff --git a/drivers/gpio/gpio-tps65912.c b/drivers/gpio/gpio-tps65912.c index 276a4229b03..59ee486cb8b 100644 --- a/drivers/gpio/gpio-tps65912.c +++ b/drivers/gpio/gpio-tps65912.c @@ -79,7 +79,7 @@ static struct gpio_chip template_chip = { .direction_output = tps65912_gpio_output, .get = tps65912_gpio_get, .set = tps65912_gpio_set, - .can_sleep = 1, + .can_sleep = true, .ngpio = 5, .base = -1, }; diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index f9996899c1f..3ebb1a5ff22 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c @@ -139,7 +139,6 @@ static u8 cached_leden; static void twl4030_led_set_value(int led, int value) { u8 mask = LEDEN_LEDAON | LEDEN_LEDAPWM; - int status; if (led) mask <<= 1; @@ -148,8 +147,9 @@ static void twl4030_led_set_value(int led, int value) cached_leden &= ~mask; else cached_leden |= mask; - status = twl_i2c_write_u8(TWL4030_MODULE_LED, cached_leden, - TWL4030_LED_LEDEN_REG); + + WARN_ON_ONCE(twl_i2c_write_u8(TWL4030_MODULE_LED, cached_leden, + TWL4030_LED_LEDEN_REG)); } static int twl4030_set_gpio_direction(int gpio, int is_input) @@ -396,7 +396,7 @@ static struct gpio_chip template_chip = { .direction_output = twl_direction_out, .set = twl_set, .to_irq = twl_to_irq, - .can_sleep = 1, + .can_sleep = true, }; /*----------------------------------------------------------------------*/ diff --git a/drivers/gpio/gpio-twl6040.c b/drivers/gpio/gpio-twl6040.c index d420d30b86e..0caf5cd1b47 100644 --- a/drivers/gpio/gpio-twl6040.c +++ b/drivers/gpio/gpio-twl6040.c @@ -77,7 +77,7 @@ static struct gpio_chip twl6040gpo_chip = { .get = twl6040gpo_get, .direction_output = twl6040gpo_direction_out, .set = twl6040gpo_set, - .can_sleep = 1, + .can_sleep = true, }; /*----------------------------------------------------------------------*/ diff --git a/drivers/gpio/gpio-tz1090.c b/drivers/gpio/gpio-tz1090.c index 23e06139241..5246a60eff6 100644 --- a/drivers/gpio/gpio-tz1090.c +++ b/drivers/gpio/gpio-tz1090.c @@ -488,26 +488,26 @@ static int tz1090_gpio_bank_probe(struct tz1090_gpio_bank_info *info) gc->chip_types[0].handler = handle_level_irq; gc->chip_types[0].regs.ack = REG_GPIO_IRQ_STS; gc->chip_types[0].regs.mask = REG_GPIO_IRQ_EN; - gc->chip_types[0].chip.irq_startup = gpio_startup_irq, - gc->chip_types[0].chip.irq_ack = irq_gc_ack_clr_bit, - gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit, - gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit, - gc->chip_types[0].chip.irq_set_type = gpio_set_irq_type, - gc->chip_types[0].chip.irq_set_wake = gpio_set_irq_wake, - gc->chip_types[0].chip.flags = IRQCHIP_MASK_ON_SUSPEND, + gc->chip_types[0].chip.irq_startup = gpio_startup_irq; + gc->chip_types[0].chip.irq_ack = irq_gc_ack_clr_bit; + gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit; + gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit; + gc->chip_types[0].chip.irq_set_type = gpio_set_irq_type; + gc->chip_types[0].chip.irq_set_wake = gpio_set_irq_wake; + gc->chip_types[0].chip.flags = IRQCHIP_MASK_ON_SUSPEND; /* edge chip type */ gc->chip_types[1].type = IRQ_TYPE_EDGE_BOTH; gc->chip_types[1].handler = handle_edge_irq; gc->chip_types[1].regs.ack = REG_GPIO_IRQ_STS; gc->chip_types[1].regs.mask = REG_GPIO_IRQ_EN; - gc->chip_types[1].chip.irq_startup = gpio_startup_irq, - gc->chip_types[1].chip.irq_ack = irq_gc_ack_clr_bit, - gc->chip_types[1].chip.irq_mask = irq_gc_mask_clr_bit, - gc->chip_types[1].chip.irq_unmask = irq_gc_mask_set_bit, - gc->chip_types[1].chip.irq_set_type = gpio_set_irq_type, - gc->chip_types[1].chip.irq_set_wake = gpio_set_irq_wake, - gc->chip_types[1].chip.flags = IRQCHIP_MASK_ON_SUSPEND, + gc->chip_types[1].chip.irq_startup = gpio_startup_irq; + gc->chip_types[1].chip.irq_ack = irq_gc_ack_clr_bit; + gc->chip_types[1].chip.irq_mask = irq_gc_mask_clr_bit; + gc->chip_types[1].chip.irq_unmask = irq_gc_mask_set_bit; + gc->chip_types[1].chip.irq_set_type = gpio_set_irq_type; + gc->chip_types[1].chip.irq_set_wake = gpio_set_irq_wake; + gc->chip_types[1].chip.flags = IRQCHIP_MASK_ON_SUSPEND; /* Setup chained handler for this GPIO bank */ irq_set_handler_data(bank->irq, bank); diff --git a/drivers/gpio/gpio-ucb1400.c b/drivers/gpio/gpio-ucb1400.c index 06fb5cf99de..2445fe77117 100644 --- a/drivers/gpio/gpio-ucb1400.c +++ b/drivers/gpio/gpio-ucb1400.c @@ -64,7 +64,7 @@ static int ucb1400_gpio_probe(struct platform_device *dev) ucb->gc.direction_output = ucb1400_gpio_dir_out; ucb->gc.get = ucb1400_gpio_get; ucb->gc.set = ucb1400_gpio_set; - ucb->gc.can_sleep = 1; + ucb->gc.can_sleep = true; err = gpiochip_add(&ucb->gc); if (err) diff --git a/drivers/gpio/gpio-viperboard.c b/drivers/gpio/gpio-viperboard.c index 5ac2919197f..79e3b583671 100644 --- a/drivers/gpio/gpio-viperboard.c +++ b/drivers/gpio/gpio-viperboard.c @@ -413,7 +413,7 @@ static int vprbrd_gpio_probe(struct platform_device *pdev) vb_gpio->gpioa.owner = THIS_MODULE; vb_gpio->gpioa.base = -1; vb_gpio->gpioa.ngpio = 16; - vb_gpio->gpioa.can_sleep = 1; + vb_gpio->gpioa.can_sleep = true; vb_gpio->gpioa.set = vprbrd_gpioa_set; vb_gpio->gpioa.get = vprbrd_gpioa_get; vb_gpio->gpioa.direction_input = vprbrd_gpioa_direction_input; @@ -430,7 +430,7 @@ static int vprbrd_gpio_probe(struct platform_device *pdev) vb_gpio->gpiob.owner = THIS_MODULE; vb_gpio->gpiob.base = -1; vb_gpio->gpiob.ngpio = 16; - vb_gpio->gpiob.can_sleep = 1; + vb_gpio->gpiob.can_sleep = true; vb_gpio->gpiob.set = vprbrd_gpiob_set; vb_gpio->gpiob.get = vprbrd_gpiob_get; vb_gpio->gpiob.direction_input = vprbrd_gpiob_direction_input; diff --git a/drivers/gpio/gpio-vr41xx.c b/drivers/gpio/gpio-vr41xx.c index 9902732a382..66cbcc108e6 100644 --- a/drivers/gpio/gpio-vr41xx.c +++ b/drivers/gpio/gpio-vr41xx.c @@ -81,6 +81,7 @@ static DEFINE_SPINLOCK(giu_lock); static unsigned long giu_flags; static void __iomem *giu_base; +static struct gpio_chip vr41xx_gpio_chip; #define giu_read(offset) readw(giu_base + (offset)) #define giu_write(offset, value) writew((value), giu_base + (offset)) @@ -135,12 +136,31 @@ static void unmask_giuint_low(struct irq_data *d) giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(d->irq)); } +static unsigned int startup_giuint(struct irq_data *data) +{ + if (gpio_lock_as_irq(&vr41xx_gpio_chip, data->hwirq)) + dev_err(vr41xx_gpio_chip.dev, + "unable to lock HW IRQ %lu for IRQ\n", + data->hwirq); + /* Satisfy the .enable semantics by unmasking the line */ + unmask_giuint_low(data); + return 0; +} + +static void shutdown_giuint(struct irq_data *data) +{ + mask_giuint_low(data); + gpio_unlock_as_irq(&vr41xx_gpio_chip, data->hwirq); +} + static struct irq_chip giuint_low_irq_chip = { .name = "GIUINTL", .irq_ack = ack_giuint_low, .irq_mask = mask_giuint_low, .irq_mask_ack = mask_ack_giuint_low, .irq_unmask = unmask_giuint_low, + .irq_startup = startup_giuint, + .irq_shutdown = shutdown_giuint, }; static void ack_giuint_high(struct irq_data *d) diff --git a/drivers/gpio/gpio-vx855.c b/drivers/gpio/gpio-vx855.c index cddfa22edb4..0fd23b6a753 100644 --- a/drivers/gpio/gpio-vx855.c +++ b/drivers/gpio/gpio-vx855.c @@ -214,7 +214,7 @@ static void vx855gpio_gpio_setup(struct vx855_gpio *vg) c->dbg_show = NULL; c->base = 0; c->ngpio = NR_VX855_GP; - c->can_sleep = 0; + c->can_sleep = false; c->names = vx855gpio_names; } diff --git a/drivers/gpio/gpio-wm831x.c b/drivers/gpio/gpio-wm831x.c index 456000c5c45..b18a1a26425 100644 --- a/drivers/gpio/gpio-wm831x.c +++ b/drivers/gpio/gpio-wm831x.c @@ -240,7 +240,7 @@ static struct gpio_chip template_chip = { .to_irq = wm831x_gpio_to_irq, .set_debounce = wm831x_gpio_set_debounce, .dbg_show = wm831x_gpio_dbg_show, - .can_sleep = 1, + .can_sleep = true, }; static int wm831x_gpio_probe(struct platform_device *pdev) diff --git a/drivers/gpio/gpio-wm8350.c b/drivers/gpio/gpio-wm8350.c index fc49154be7b..2487f9d575d 100644 --- a/drivers/gpio/gpio-wm8350.c +++ b/drivers/gpio/gpio-wm8350.c @@ -106,7 +106,7 @@ static struct gpio_chip template_chip = { .direction_output = wm8350_gpio_direction_out, .set = wm8350_gpio_set, .to_irq = wm8350_gpio_to_irq, - .can_sleep = 1, + .can_sleep = true, }; static int wm8350_gpio_probe(struct platform_device *pdev) diff --git a/drivers/gpio/gpio-wm8994.c b/drivers/gpio/gpio-wm8994.c index a53dbdefc7e..d93b6b58167 100644 --- a/drivers/gpio/gpio-wm8994.c +++ b/drivers/gpio/gpio-wm8994.c @@ -242,7 +242,7 @@ static struct gpio_chip template_chip = { .set = wm8994_gpio_set, .to_irq = wm8994_gpio_to_irq, .dbg_show = wm8994_gpio_dbg_show, - .can_sleep = 1, + .can_sleep = true, }; static int wm8994_gpio_probe(struct platform_device *pdev) diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c index 792a05ad464..12481867daf 100644 --- a/drivers/gpio/gpio-xilinx.c +++ b/drivers/gpio/gpio-xilinx.c @@ -289,7 +289,7 @@ static int xgpio_of_probe(struct device_node *np) return 0; } -static struct of_device_id xgpio_of_match[] = { +static const struct of_device_id xgpio_of_match[] = { { .compatible = "xlnx,xps-gpio-1.00.a", }, { /* end of list */ }, }; diff --git a/drivers/gpio/gpio-xtensa.c b/drivers/gpio/gpio-xtensa.c new file mode 100644 index 00000000000..7081304d679 --- /dev/null +++ b/drivers/gpio/gpio-xtensa.c @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2013 TangoTec Ltd. + * Author: Baruch Siach <baruch@tkos.co.il> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Driver for the Xtensa LX4 GPIO32 Option + * + * Documentation: Xtensa LX4 Microprocessor Data Book, Section 2.22 + * + * GPIO32 is a standard optional extension to the Xtensa architecture core that + * provides preconfigured output and input ports for intra SoC signaling. The + * GPIO32 option is implemented as 32bit Tensilica Instruction Extension (TIE) + * output state called EXPSTATE, and 32bit input wire called IMPWIRE. This + * driver treats input and output states as two distinct devices. + * + * Access to GPIO32 specific instructions is controlled by the CPENABLE + * (Coprocessor Enable Bits) register. By default Xtensa Linux startup code + * disables access to all coprocessors. This driver sets the CPENABLE bit + * corresponding to GPIO32 before any GPIO32 specific instruction, and restores + * CPENABLE state after that. + * + * This driver is currently incompatible with SMP. The GPIO32 extension is not + * guaranteed to be available in all cores. Moreover, each core controls a + * different set of IO wires. A theoretical SMP aware version of this driver + * would need to have a per core workqueue to do the actual GPIO manipulation. + */ + +#include <linux/err.h> +#include <linux/module.h> +#include <linux/gpio.h> +#include <linux/bitops.h> +#include <linux/platform_device.h> + +#include <asm/coprocessor.h> /* CPENABLE read/write macros */ + +#ifndef XCHAL_CP_ID_XTIOP +#error GPIO32 option is not enabled for your xtensa core variant +#endif + +#if XCHAL_HAVE_CP + +static inline unsigned long enable_cp(unsigned long *cpenable) +{ + unsigned long flags; + + local_irq_save(flags); + RSR_CPENABLE(*cpenable); + WSR_CPENABLE(*cpenable | BIT(XCHAL_CP_ID_XTIOP)); + + return flags; +} + +static inline void disable_cp(unsigned long flags, unsigned long cpenable) +{ + WSR_CPENABLE(cpenable); + local_irq_restore(flags); +} + +#else + +static inline unsigned long enable_cp(unsigned long *cpenable) +{ + *cpenable = 0; /* avoid uninitialized value warning */ + return 0; +} + +static inline void disable_cp(unsigned long flags, unsigned long cpenable) +{ +} + +#endif /* XCHAL_HAVE_CP */ + +static int xtensa_impwire_get_direction(struct gpio_chip *gc, unsigned offset) +{ + return 1; /* input only */ +} + +static int xtensa_impwire_get_value(struct gpio_chip *gc, unsigned offset) +{ + unsigned long flags, saved_cpenable; + u32 impwire; + + flags = enable_cp(&saved_cpenable); + __asm__ __volatile__("read_impwire %0" : "=a" (impwire)); + disable_cp(flags, saved_cpenable); + + return !!(impwire & BIT(offset)); +} + +static void xtensa_impwire_set_value(struct gpio_chip *gc, unsigned offset, + int value) +{ + BUG(); /* output only; should never be called */ +} + +static int xtensa_expstate_get_direction(struct gpio_chip *gc, unsigned offset) +{ + return 0; /* output only */ +} + +static int xtensa_expstate_get_value(struct gpio_chip *gc, unsigned offset) +{ + unsigned long flags, saved_cpenable; + u32 expstate; + + flags = enable_cp(&saved_cpenable); + __asm__ __volatile__("rur.expstate %0" : "=a" (expstate)); + disable_cp(flags, saved_cpenable); + + return !!(expstate & BIT(offset)); +} + +static void xtensa_expstate_set_value(struct gpio_chip *gc, unsigned offset, + int value) +{ + unsigned long flags, saved_cpenable; + u32 mask = BIT(offset); + u32 val = value ? BIT(offset) : 0; + + flags = enable_cp(&saved_cpenable); + __asm__ __volatile__("wrmsk_expstate %0, %1" + :: "a" (val), "a" (mask)); + disable_cp(flags, saved_cpenable); +} + +static struct gpio_chip impwire_chip = { + .label = "impwire", + .base = -1, + .ngpio = 32, + .get_direction = xtensa_impwire_get_direction, + .get = xtensa_impwire_get_value, + .set = xtensa_impwire_set_value, +}; + +static struct gpio_chip expstate_chip = { + .label = "expstate", + .base = -1, + .ngpio = 32, + .get_direction = xtensa_expstate_get_direction, + .get = xtensa_expstate_get_value, + .set = xtensa_expstate_set_value, +}; + +static int xtensa_gpio_probe(struct platform_device *pdev) +{ + int ret; + + ret = gpiochip_add(&impwire_chip); + if (ret) + return ret; + return gpiochip_add(&expstate_chip); +} + +static struct platform_driver xtensa_gpio_driver = { + .driver = { + .name = "xtensa-gpio", + .owner = THIS_MODULE, + }, + .probe = xtensa_gpio_probe, +}; + +static int __init xtensa_gpio_init(void) +{ + struct platform_device *pdev; + + pdev = platform_device_register_simple("xtensa-gpio", 0, NULL, 0); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + return platform_driver_register(&xtensa_gpio_driver); +} +device_initcall(xtensa_gpio_init); + +MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>"); +MODULE_DESCRIPTION("Xtensa LX4 GPIO32 driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-zevio.c b/drivers/gpio/gpio-zevio.c new file mode 100644 index 00000000000..54e54e4cc6c --- /dev/null +++ b/drivers/gpio/gpio-zevio.c @@ -0,0 +1,224 @@ +/* + * GPIO controller in LSI ZEVIO SoCs. + * + * Author: Fabian Vogt <fabian@ritter-vogt.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/spinlock.h> +#include <linux/errno.h> +#include <linux/module.h> +#include <linux/bitops.h> +#include <linux/io.h> +#include <linux/of_device.h> +#include <linux/of_gpio.h> +#include <linux/slab.h> +#include <linux/gpio.h> + +/* + * Memory layout: + * This chip has four gpio sections, each controls 8 GPIOs. + * Bit 0 in section 0 is GPIO 0, bit 2 in section 1 is GPIO 10. + * Disclaimer: Reverse engineered! + * For more information refer to: + * http://hackspire.unsads.com/wiki/index.php/Memory-mapped_I/O_ports#90000000_-_General_Purpose_I.2FO_.28GPIO.29 + * + * 0x00-0x3F: Section 0 + * +0x00: Masked interrupt status (read-only) + * +0x04: R: Interrupt status W: Reset interrupt status + * +0x08: R: Interrupt mask W: Mask interrupt + * +0x0C: W: Unmask interrupt (write-only) + * +0x10: Direction: I/O=1/0 + * +0x14: Output + * +0x18: Input (read-only) + * +0x20: R: Level interrupt W: Set as level interrupt + * 0x40-0x7F: Section 1 + * 0x80-0xBF: Section 2 + * 0xC0-0xFF: Section 3 + */ + +#define ZEVIO_GPIO_SECTION_SIZE 0x40 + +/* Offsets to various registers */ +#define ZEVIO_GPIO_INT_MASKED_STATUS 0x00 +#define ZEVIO_GPIO_INT_STATUS 0x04 +#define ZEVIO_GPIO_INT_UNMASK 0x08 +#define ZEVIO_GPIO_INT_MASK 0x0C +#define ZEVIO_GPIO_DIRECTION 0x10 +#define ZEVIO_GPIO_OUTPUT 0x14 +#define ZEVIO_GPIO_INPUT 0x18 +#define ZEVIO_GPIO_INT_STICKY 0x20 + +#define to_zevio_gpio(chip) container_of(to_of_mm_gpio_chip(chip), \ + struct zevio_gpio, chip) + +/* Bit number of GPIO in its section */ +#define ZEVIO_GPIO_BIT(gpio) (gpio&7) + +struct zevio_gpio { + spinlock_t lock; + struct of_mm_gpio_chip chip; +}; + +static inline u32 zevio_gpio_port_get(struct zevio_gpio *c, unsigned pin, + unsigned port_offset) +{ + unsigned section_offset = ((pin >> 3) & 3)*ZEVIO_GPIO_SECTION_SIZE; + return readl(IOMEM(c->chip.regs + section_offset + port_offset)); +} + +static inline void zevio_gpio_port_set(struct zevio_gpio *c, unsigned pin, + unsigned port_offset, u32 val) +{ + unsigned section_offset = ((pin >> 3) & 3)*ZEVIO_GPIO_SECTION_SIZE; + writel(val, IOMEM(c->chip.regs + section_offset + port_offset)); +} + +/* Functions for struct gpio_chip */ +static int zevio_gpio_get(struct gpio_chip *chip, unsigned pin) +{ + struct zevio_gpio *controller = to_zevio_gpio(chip); + u32 val, dir; + + spin_lock(&controller->lock); + dir = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_DIRECTION); + if (dir & BIT(ZEVIO_GPIO_BIT(pin))) + val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_INPUT); + else + val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_OUTPUT); + spin_unlock(&controller->lock); + + return (val >> ZEVIO_GPIO_BIT(pin)) & 0x1; +} + +static void zevio_gpio_set(struct gpio_chip *chip, unsigned pin, int value) +{ + struct zevio_gpio *controller = to_zevio_gpio(chip); + u32 val; + + spin_lock(&controller->lock); + val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_OUTPUT); + if (value) + val |= BIT(ZEVIO_GPIO_BIT(pin)); + else + val &= ~BIT(ZEVIO_GPIO_BIT(pin)); + + zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_OUTPUT, val); + spin_unlock(&controller->lock); +} + +static int zevio_gpio_direction_input(struct gpio_chip *chip, unsigned pin) +{ + struct zevio_gpio *controller = to_zevio_gpio(chip); + u32 val; + + spin_lock(&controller->lock); + + val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_DIRECTION); + val |= BIT(ZEVIO_GPIO_BIT(pin)); + zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_DIRECTION, val); + + spin_unlock(&controller->lock); + + return 0; +} + +static int zevio_gpio_direction_output(struct gpio_chip *chip, + unsigned pin, int value) +{ + struct zevio_gpio *controller = to_zevio_gpio(chip); + u32 val; + + spin_lock(&controller->lock); + val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_OUTPUT); + if (value) + val |= BIT(ZEVIO_GPIO_BIT(pin)); + else + val &= ~BIT(ZEVIO_GPIO_BIT(pin)); + + zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_OUTPUT, val); + val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_DIRECTION); + val &= ~BIT(ZEVIO_GPIO_BIT(pin)); + zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_DIRECTION, val); + + spin_unlock(&controller->lock); + + return 0; +} + +static int zevio_gpio_to_irq(struct gpio_chip *chip, unsigned pin) +{ + /* + * TODO: Implement IRQs. + * Not implemented yet due to weird lockups + */ + + return -ENXIO; +} + +static struct gpio_chip zevio_gpio_chip = { + .direction_input = zevio_gpio_direction_input, + .direction_output = zevio_gpio_direction_output, + .set = zevio_gpio_set, + .get = zevio_gpio_get, + .to_irq = zevio_gpio_to_irq, + .base = 0, + .owner = THIS_MODULE, + .ngpio = 32, + .of_gpio_n_cells = 2, +}; + +/* Initialization */ +static int zevio_gpio_probe(struct platform_device *pdev) +{ + struct zevio_gpio *controller; + int status, i; + + controller = devm_kzalloc(&pdev->dev, sizeof(*controller), GFP_KERNEL); + if (!controller) + return -ENOMEM; + + /* Copy our reference */ + controller->chip.gc = zevio_gpio_chip; + controller->chip.gc.dev = &pdev->dev; + + status = of_mm_gpiochip_add(pdev->dev.of_node, &(controller->chip)); + if (status) { + dev_err(&pdev->dev, "failed to add gpiochip: %d\n", status); + return status; + } + + spin_lock_init(&controller->lock); + + /* Disable interrupts, they only cause errors */ + for (i = 0; i < controller->chip.gc.ngpio; i += 8) + zevio_gpio_port_set(controller, i, ZEVIO_GPIO_INT_MASK, 0xFF); + + dev_dbg(controller->chip.gc.dev, "ZEVIO GPIO controller set up!\n"); + + return 0; +} + +static const struct of_device_id zevio_gpio_of_match[] = { + { .compatible = "lsi,zevio-gpio", }, + { }, +}; + +MODULE_DEVICE_TABLE(of, zevio_gpio_of_match); + +static struct platform_driver zevio_gpio_driver = { + .driver = { + .name = "gpio-zevio", + .owner = THIS_MODULE, + .of_match_table = zevio_gpio_of_match, + }, + .probe = zevio_gpio_probe, +}; +module_platform_driver(zevio_gpio_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Fabian Vogt <fabian@ritter-vogt.de>"); +MODULE_DESCRIPTION("LSI ZEVIO SoC GPIO driver"); diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index ae0ffdce8bd..4a987917c18 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -12,18 +12,39 @@ #include <linux/errno.h> #include <linux/gpio/consumer.h> +#include <linux/gpio/driver.h> #include <linux/export.h> -#include <linux/acpi_gpio.h> #include <linux/acpi.h> #include <linux/interrupt.h> +#include <linux/mutex.h> -struct acpi_gpio_evt_pin { +#include "gpiolib.h" + +struct acpi_gpio_event { struct list_head node; - acpi_handle *evt_handle; + acpi_handle handle; unsigned int pin; unsigned int irq; }; +struct acpi_gpio_connection { + struct list_head node; + struct gpio_desc *desc; +}; + +struct acpi_gpio_chip { + /* + * ACPICA requires that the first field of the context parameter + * passed to acpi_install_address_space_handler() is large enough + * to hold struct acpi_connection_info. + */ + struct acpi_connection_info conn_info; + struct list_head conns; + struct mutex conn_lock; + struct gpio_chip *chip; + struct list_head events; +}; + static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) { if (!gc->dev) @@ -58,179 +79,196 @@ static struct gpio_desc *acpi_get_gpiod(char *path, int pin) if (pin < 0 || pin > chip->ngpio) return ERR_PTR(-EINVAL); - return gpio_to_desc(chip->base + pin); + return gpiochip_get_desc(chip, pin); } static irqreturn_t acpi_gpio_irq_handler(int irq, void *data) { - acpi_handle handle = data; + struct acpi_gpio_event *event = data; - acpi_evaluate_object(handle, NULL, NULL, NULL); + acpi_evaluate_object(event->handle, NULL, NULL, NULL); return IRQ_HANDLED; } static irqreturn_t acpi_gpio_irq_handler_evt(int irq, void *data) { - struct acpi_gpio_evt_pin *evt_pin = data; + struct acpi_gpio_event *event = data; - acpi_execute_simple_method(evt_pin->evt_handle, NULL, evt_pin->pin); + acpi_execute_simple_method(event->handle, NULL, event->pin); return IRQ_HANDLED; } -static void acpi_gpio_evt_dh(acpi_handle handle, void *data) +static void acpi_gpio_chip_dh(acpi_handle handle, void *data) { /* The address of this function is used as a key. */ } -/** - * acpi_gpiochip_request_interrupts() - Register isr for gpio chip ACPI events - * @chip: gpio chip - * - * ACPI5 platforms can use GPIO signaled ACPI events. These GPIO interrupts are - * handled by ACPI event methods which need to be called from the GPIO - * chip's interrupt handler. acpi_gpiochip_request_interrupts finds out which - * gpio pins have acpi event methods and assigns interrupt handlers that calls - * the acpi event methods for those pins. - */ -void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) +static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares, + void *context) { - struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; - struct acpi_resource *res; + struct acpi_gpio_chip *acpi_gpio = context; + struct gpio_chip *chip = acpi_gpio->chip; + struct acpi_resource_gpio *agpio; acpi_handle handle, evt_handle; - struct list_head *evt_pins = NULL; - acpi_status status; - unsigned int pin; - int irq, ret; - char ev_name[5]; + struct acpi_gpio_event *event; + irq_handler_t handler = NULL; + struct gpio_desc *desc; + unsigned long irqflags; + int ret, pin, irq; - if (!chip->dev || !chip->to_irq) - return; + if (ares->type != ACPI_RESOURCE_TYPE_GPIO) + return AE_OK; - handle = ACPI_HANDLE(chip->dev); - if (!handle) - return; + agpio = &ares->data.gpio; + if (agpio->connection_type != ACPI_RESOURCE_GPIO_TYPE_INT) + return AE_OK; - status = acpi_get_event_resources(handle, &buf); - if (ACPI_FAILURE(status)) - return; + handle = ACPI_HANDLE(chip->dev); + pin = agpio->pin_table[0]; + + if (pin <= 255) { + char ev_name[5]; + sprintf(ev_name, "_%c%02X", + agpio->triggering == ACPI_EDGE_SENSITIVE ? 'E' : 'L', + pin); + if (ACPI_SUCCESS(acpi_get_handle(handle, ev_name, &evt_handle))) + handler = acpi_gpio_irq_handler; + } + if (!handler) { + if (ACPI_SUCCESS(acpi_get_handle(handle, "_EVT", &evt_handle))) + handler = acpi_gpio_irq_handler_evt; + } + if (!handler) + return AE_BAD_PARAMETER; - status = acpi_get_handle(handle, "_EVT", &evt_handle); - if (ACPI_SUCCESS(status)) { - evt_pins = kzalloc(sizeof(*evt_pins), GFP_KERNEL); - if (evt_pins) { - INIT_LIST_HEAD(evt_pins); - status = acpi_attach_data(handle, acpi_gpio_evt_dh, - evt_pins); - if (ACPI_FAILURE(status)) { - kfree(evt_pins); - evt_pins = NULL; - } - } + desc = gpiochip_get_desc(chip, pin); + if (IS_ERR(desc)) { + dev_err(chip->dev, "Failed to get GPIO descriptor\n"); + return AE_ERROR; } - /* - * If a GPIO interrupt has an ACPI event handler method, or _EVT is - * present, set up an interrupt handler that calls the ACPI event - * handler. - */ - for (res = buf.pointer; - res && (res->type != ACPI_RESOURCE_TYPE_END_TAG); - res = ACPI_NEXT_RESOURCE(res)) { - irq_handler_t handler = NULL; - void *data; - - if (res->type != ACPI_RESOURCE_TYPE_GPIO || - res->data.gpio.connection_type != - ACPI_RESOURCE_GPIO_TYPE_INT) - continue; + ret = gpiochip_request_own_desc(desc, "ACPI:Event"); + if (ret) { + dev_err(chip->dev, "Failed to request GPIO\n"); + return AE_ERROR; + } - pin = res->data.gpio.pin_table[0]; - if (pin > chip->ngpio) - continue; + gpiod_direction_input(desc); - irq = chip->to_irq(chip, pin); - if (irq < 0) - continue; + ret = gpiod_lock_as_irq(desc); + if (ret) { + dev_err(chip->dev, "Failed to lock GPIO as interrupt\n"); + goto fail_free_desc; + } - if (pin <= 255) { - acpi_handle ev_handle; + irq = gpiod_to_irq(desc); + if (irq < 0) { + dev_err(chip->dev, "Failed to translate GPIO to IRQ\n"); + goto fail_unlock_irq; + } - sprintf(ev_name, "_%c%02X", - res->data.gpio.triggering ? 'E' : 'L', pin); - status = acpi_get_handle(handle, ev_name, &ev_handle); - if (ACPI_SUCCESS(status)) { - handler = acpi_gpio_irq_handler; - data = ev_handle; - } + irqflags = IRQF_ONESHOT; + if (agpio->triggering == ACPI_LEVEL_SENSITIVE) { + if (agpio->polarity == ACPI_ACTIVE_HIGH) + irqflags |= IRQF_TRIGGER_HIGH; + else + irqflags |= IRQF_TRIGGER_LOW; + } else { + switch (agpio->polarity) { + case ACPI_ACTIVE_HIGH: + irqflags |= IRQF_TRIGGER_RISING; + break; + case ACPI_ACTIVE_LOW: + irqflags |= IRQF_TRIGGER_FALLING; + break; + default: + irqflags |= IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING; + break; } - if (!handler && evt_pins) { - struct acpi_gpio_evt_pin *evt_pin; + } - evt_pin = kzalloc(sizeof(*evt_pin), GFP_KERNEL); - if (!evt_pin) - continue; + event = kzalloc(sizeof(*event), GFP_KERNEL); + if (!event) + goto fail_unlock_irq; - list_add_tail(&evt_pin->node, evt_pins); - evt_pin->evt_handle = evt_handle; - evt_pin->pin = pin; - evt_pin->irq = irq; - handler = acpi_gpio_irq_handler_evt; - data = evt_pin; - } - if (!handler) - continue; + event->handle = evt_handle; + event->irq = irq; + event->pin = pin; - /* Assume BIOS sets the triggering, so no flags */ - ret = devm_request_threaded_irq(chip->dev, irq, NULL, handler, - 0, "GPIO-signaled-ACPI-event", - data); - if (ret) - dev_err(chip->dev, - "Failed to request IRQ %d ACPI event handler\n", - irq); + ret = request_threaded_irq(event->irq, NULL, handler, irqflags, + "ACPI:Event", event); + if (ret) { + dev_err(chip->dev, "Failed to setup interrupt handler for %d\n", + event->irq); + goto fail_free_event; } + + list_add_tail(&event->node, &acpi_gpio->events); + return AE_OK; + +fail_free_event: + kfree(event); +fail_unlock_irq: + gpiod_unlock_as_irq(desc); +fail_free_desc: + gpiochip_free_own_desc(desc); + + return AE_ERROR; } -EXPORT_SYMBOL(acpi_gpiochip_request_interrupts); /** - * acpi_gpiochip_free_interrupts() - Free GPIO _EVT ACPI event interrupts. - * @chip: gpio chip - * - * Free interrupts associated with the _EVT method for the given GPIO chip. + * acpi_gpiochip_request_interrupts() - Register isr for gpio chip ACPI events + * @acpi_gpio: ACPI GPIO chip * - * The remaining ACPI event interrupts associated with the chip are freed - * automatically. + * ACPI5 platforms can use GPIO signaled ACPI events. These GPIO interrupts are + * handled by ACPI event methods which need to be called from the GPIO + * chip's interrupt handler. acpi_gpiochip_request_interrupts finds out which + * gpio pins have acpi event methods and assigns interrupt handlers that calls + * the acpi event methods for those pins. */ -void acpi_gpiochip_free_interrupts(struct gpio_chip *chip) +static void acpi_gpiochip_request_interrupts(struct acpi_gpio_chip *acpi_gpio) { - acpi_handle handle; - acpi_status status; - struct list_head *evt_pins; - struct acpi_gpio_evt_pin *evt_pin, *ep; + struct gpio_chip *chip = acpi_gpio->chip; - if (!chip->dev || !chip->to_irq) + if (!chip->to_irq) return; - handle = ACPI_HANDLE(chip->dev); - if (!handle) - return; + INIT_LIST_HEAD(&acpi_gpio->events); + acpi_walk_resources(ACPI_HANDLE(chip->dev), "_AEI", + acpi_gpiochip_request_interrupt, acpi_gpio); +} - status = acpi_get_data(handle, acpi_gpio_evt_dh, (void **)&evt_pins); - if (ACPI_FAILURE(status)) +/** + * acpi_gpiochip_free_interrupts() - Free GPIO ACPI event interrupts. + * @acpi_gpio: ACPI GPIO chip + * + * Free interrupts associated with GPIO ACPI event method for the given + * GPIO chip. + */ +static void acpi_gpiochip_free_interrupts(struct acpi_gpio_chip *acpi_gpio) +{ + struct acpi_gpio_event *event, *ep; + struct gpio_chip *chip = acpi_gpio->chip; + + if (!chip->to_irq) return; - list_for_each_entry_safe_reverse(evt_pin, ep, evt_pins, node) { - devm_free_irq(chip->dev, evt_pin->irq, evt_pin); - list_del(&evt_pin->node); - kfree(evt_pin); - } + list_for_each_entry_safe_reverse(event, ep, &acpi_gpio->events, node) { + struct gpio_desc *desc; - acpi_detach_data(handle, acpi_gpio_evt_dh); - kfree(evt_pins); + free_irq(event->irq, event); + desc = gpiochip_get_desc(chip, event->pin); + if (WARN_ON(IS_ERR(desc))) + continue; + gpiod_unlock_as_irq(desc); + gpiochip_free_own_desc(desc); + list_del(&event->node); + kfree(event); + } } -EXPORT_SYMBOL(acpi_gpiochip_free_interrupts); struct acpi_gpio_lookup { struct acpi_gpio_info info; @@ -307,6 +345,212 @@ struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index, if (lookup.desc && info) *info = lookup.info; - return lookup.desc ? lookup.desc : ERR_PTR(-ENODEV); + return lookup.desc ? lookup.desc : ERR_PTR(-ENOENT); +} + +static acpi_status +acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address, + u32 bits, u64 *value, void *handler_context, + void *region_context) +{ + struct acpi_gpio_chip *achip = region_context; + struct gpio_chip *chip = achip->chip; + struct acpi_resource_gpio *agpio; + struct acpi_resource *ares; + acpi_status status; + bool pull_up; + int i; + + status = acpi_buffer_to_resource(achip->conn_info.connection, + achip->conn_info.length, &ares); + if (ACPI_FAILURE(status)) + return status; + + if (WARN_ON(ares->type != ACPI_RESOURCE_TYPE_GPIO)) { + ACPI_FREE(ares); + return AE_BAD_PARAMETER; + } + + 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)) { + ACPI_FREE(ares); + return AE_BAD_PARAMETER; + } + + for (i = 0; i < agpio->pin_table_length; i++) { + unsigned pin = agpio->pin_table[i]; + struct acpi_gpio_connection *conn; + struct gpio_desc *desc; + bool found; + + desc = gpiochip_get_desc(chip, pin); + if (IS_ERR(desc)) { + status = AE_ERROR; + goto out; + } + + mutex_lock(&achip->conn_lock); + + found = false; + list_for_each_entry(conn, &achip->conns, node) { + if (conn->desc == desc) { + found = true; + break; + } + } + if (!found) { + int ret; + + ret = gpiochip_request_own_desc(desc, "ACPI:OpRegion"); + if (ret) { + 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; + } + + conn = kzalloc(sizeof(*conn), GFP_KERNEL); + if (!conn) { + status = AE_NO_MEMORY; + gpiochip_free_own_desc(desc); + mutex_unlock(&achip->conn_lock); + goto out; + } + + conn->desc = desc; + list_add_tail(&conn->node, &achip->conns); + } + + mutex_unlock(&achip->conn_lock); + + if (function == ACPI_WRITE) + gpiod_set_raw_value_cansleep(desc, + !!((1 << i) & *value)); + else + *value |= (u64)gpiod_get_raw_value_cansleep(desc) << i; + } + +out: + ACPI_FREE(ares); + return status; +} + +static void acpi_gpiochip_request_regions(struct acpi_gpio_chip *achip) +{ + struct gpio_chip *chip = achip->chip; + acpi_handle handle = ACPI_HANDLE(chip->dev); + acpi_status status; + + INIT_LIST_HEAD(&achip->conns); + mutex_init(&achip->conn_lock); + status = acpi_install_address_space_handler(handle, ACPI_ADR_SPACE_GPIO, + acpi_gpio_adr_space_handler, + NULL, achip); + if (ACPI_FAILURE(status)) + dev_err(chip->dev, "Failed to install GPIO OpRegion handler\n"); +} + +static void acpi_gpiochip_free_regions(struct acpi_gpio_chip *achip) +{ + struct gpio_chip *chip = achip->chip; + acpi_handle handle = ACPI_HANDLE(chip->dev); + struct acpi_gpio_connection *conn, *tmp; + acpi_status status; + + status = acpi_remove_address_space_handler(handle, ACPI_ADR_SPACE_GPIO, + acpi_gpio_adr_space_handler); + if (ACPI_FAILURE(status)) { + dev_err(chip->dev, "Failed to remove GPIO OpRegion handler\n"); + return; + } + + list_for_each_entry_safe_reverse(conn, tmp, &achip->conns, node) { + gpiochip_free_own_desc(conn->desc); + list_del(&conn->node); + kfree(conn); + } +} + +void acpi_gpiochip_add(struct gpio_chip *chip) +{ + struct acpi_gpio_chip *acpi_gpio; + acpi_handle handle; + acpi_status status; + + if (!chip || !chip->dev) + return; + + handle = ACPI_HANDLE(chip->dev); + if (!handle) + return; + + acpi_gpio = kzalloc(sizeof(*acpi_gpio), GFP_KERNEL); + if (!acpi_gpio) { + dev_err(chip->dev, + "Failed to allocate memory for ACPI GPIO chip\n"); + return; + } + + acpi_gpio->chip = chip; + + status = acpi_attach_data(handle, acpi_gpio_chip_dh, acpi_gpio); + if (ACPI_FAILURE(status)) { + dev_err(chip->dev, "Failed to attach ACPI GPIO chip\n"); + kfree(acpi_gpio); + return; + } + + acpi_gpiochip_request_interrupts(acpi_gpio); + acpi_gpiochip_request_regions(acpi_gpio); +} + +void acpi_gpiochip_remove(struct gpio_chip *chip) +{ + struct acpi_gpio_chip *acpi_gpio; + acpi_handle handle; + acpi_status status; + + if (!chip || !chip->dev) + return; + + handle = ACPI_HANDLE(chip->dev); + if (!handle) + return; + + status = acpi_get_data(handle, acpi_gpio_chip_dh, (void **)&acpi_gpio); + if (ACPI_FAILURE(status)) { + dev_warn(chip->dev, "Failed to retrieve ACPI GPIO chip\n"); + return; + } + + acpi_gpiochip_free_regions(acpi_gpio); + acpi_gpiochip_free_interrupts(acpi_gpio); + + acpi_detach_data(handle, acpi_gpio_chip_dh); + kfree(acpi_gpio); } -EXPORT_SYMBOL_GPL(acpi_get_gpiod_by_index); diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index e0a98f581f5..af7e25c9a9a 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -12,6 +12,7 @@ */ #include <linux/device.h> +#include <linux/err.h> #include <linux/errno.h> #include <linux/module.h> #include <linux/io.h> @@ -47,7 +48,7 @@ static int of_gpiochip_find_and_xlate(struct gpio_chip *gc, void *data) if (ret < 0) return false; - gg_data->out_gpio = gpio_to_desc(ret + gc->base); + gg_data->out_gpio = gpiochip_get_desc(gc, ret); return true; } @@ -90,11 +91,25 @@ struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np, of_node_put(gg_data.gpiospec.np); pr_debug("%s exited with status %d\n", __func__, - PTR_RET(gg_data.out_gpio)); + PTR_ERR_OR_ZERO(gg_data.out_gpio)); return gg_data.out_gpio; } EXPORT_SYMBOL(of_get_named_gpiod_flags); +int of_get_named_gpio_flags(struct device_node *np, const char *list_name, + int index, enum of_gpio_flags *flags) +{ + struct gpio_desc *desc; + + desc = of_get_named_gpiod_flags(np, list_name, index, flags); + + if (IS_ERR(desc)) + return PTR_ERR(desc); + else + return desc_to_gpio(desc); +} +EXPORT_SYMBOL(of_get_named_gpio_flags); + /** * of_gpio_simple_xlate - translate gpio_spec to the GPIO number and flags * @gc: pointer to the gpio_chip structure diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index c8a7c810bad..2ebc9071e35 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -10,12 +10,13 @@ #include <linux/seq_file.h> #include <linux/gpio.h> #include <linux/of_gpio.h> -#include <linux/acpi_gpio.h> #include <linux/idr.h> #include <linux/slab.h> #include <linux/acpi.h> #include <linux/gpio/driver.h> +#include "gpiolib.h" + #define CREATE_TRACE_POINTS #include <trace/events/gpio.h> @@ -84,40 +85,57 @@ static DEFINE_IDR(dirent_idr); static int gpiod_request(struct gpio_desc *desc, const char *label); static void gpiod_free(struct gpio_desc *desc); +/* With descriptor prefix */ + #ifdef CONFIG_DEBUG_FS -#define gpiod_emerg(desc, fmt, ...) \ - pr_emerg("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label, \ +#define gpiod_emerg(desc, fmt, ...) \ + pr_emerg("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?",\ ##__VA_ARGS__) -#define gpiod_crit(desc, fmt, ...) \ - pr_crit("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label, \ +#define gpiod_crit(desc, fmt, ...) \ + pr_crit("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \ ##__VA_ARGS__) -#define gpiod_err(desc, fmt, ...) \ - pr_err("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label, \ +#define gpiod_err(desc, fmt, ...) \ + pr_err("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \ ##__VA_ARGS__) -#define gpiod_warn(desc, fmt, ...) \ - pr_warn("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label, \ +#define gpiod_warn(desc, fmt, ...) \ + pr_warn("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \ ##__VA_ARGS__) -#define gpiod_info(desc, fmt, ...) \ - pr_info("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label, \ +#define gpiod_info(desc, fmt, ...) \ + pr_info("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \ ##__VA_ARGS__) -#define gpiod_dbg(desc, fmt, ...) \ - pr_debug("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label, \ +#define gpiod_dbg(desc, fmt, ...) \ + pr_debug("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?",\ ##__VA_ARGS__) #else -#define gpiod_emerg(desc, fmt, ...) \ +#define gpiod_emerg(desc, fmt, ...) \ pr_emerg("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) -#define gpiod_crit(desc, fmt, ...) \ +#define gpiod_crit(desc, fmt, ...) \ pr_crit("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) -#define gpiod_err(desc, fmt, ...) \ +#define gpiod_err(desc, fmt, ...) \ pr_err("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) -#define gpiod_warn(desc, fmt, ...) \ +#define gpiod_warn(desc, fmt, ...) \ pr_warn("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) -#define gpiod_info(desc, fmt, ...) \ +#define gpiod_info(desc, fmt, ...) \ pr_info("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) -#define gpiod_dbg(desc, fmt, ...) \ +#define gpiod_dbg(desc, fmt, ...) \ pr_debug("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) #endif +/* With chip prefix */ + +#define chip_emerg(chip, fmt, ...) \ + pr_emerg("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__) +#define chip_crit(chip, fmt, ...) \ + pr_crit("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__) +#define chip_err(chip, fmt, ...) \ + pr_err("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__) +#define chip_warn(chip, fmt, ...) \ + pr_warn("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__) +#define chip_info(chip, fmt, ...) \ + pr_info("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__) +#define chip_dbg(chip, fmt, ...) \ + pr_debug("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__) + static inline void desc_set_label(struct gpio_desc *d, const char *label) { #ifdef CONFIG_DEBUG_FS @@ -146,15 +164,17 @@ struct gpio_desc *gpio_to_desc(unsigned gpio) EXPORT_SYMBOL_GPL(gpio_to_desc); /** - * Convert an offset on a certain chip to a corresponding descriptor + * Get the GPIO descriptor corresponding to the given hw number for this chip. */ -static struct gpio_desc *gpiochip_offset_to_desc(struct gpio_chip *chip, - unsigned int offset) +struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip, + u16 hwnum) { - unsigned int gpio = chip->base + offset; + if (hwnum >= chip->ngpio) + return ERR_PTR(-EINVAL); - return gpio_to_desc(gpio); + return &chip->desc[hwnum]; } +EXPORT_SYMBOL_GPL(gpiochip_get_desc); /** * Convert a GPIO descriptor to the integer namespace. @@ -187,7 +207,8 @@ static int gpio_ensure_requested(struct gpio_desc *desc) if (WARN(test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0, "autorequest GPIO-%d\n", gpio)) { if (!try_module_get(chip->owner)) { - pr_err("GPIO-%d: module can't be gotten \n", gpio); + gpiod_err(desc, "%s: module can't be gotten\n", + __func__); clear_bit(FLAG_REQUESTED, &desc->flags); /* lose */ return -EIO; @@ -330,9 +351,9 @@ static ssize_t gpio_direction_store(struct device *dev, if (!test_bit(FLAG_EXPORT, &desc->flags)) status = -EIO; else if (sysfs_streq(buf, "high")) - status = gpiod_direction_output(desc, 1); + status = gpiod_direction_output_raw(desc, 1); else if (sysfs_streq(buf, "out") || sysfs_streq(buf, "low")) - status = gpiod_direction_output(desc, 0); + status = gpiod_direction_output_raw(desc, 0); else if (sysfs_streq(buf, "in")) status = gpiod_direction_input(desc); else @@ -808,8 +829,8 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change) if (!test_bit(FLAG_REQUESTED, &desc->flags) || test_bit(FLAG_EXPORT, &desc->flags)) { spin_unlock_irqrestore(&gpio_lock, flags); - pr_debug("%s: gpio %d unavailable (requested=%d, exported=%d)\n", - __func__, desc_to_gpio(desc), + gpiod_dbg(desc, "%s: unavailable (requested=%d, exported=%d)\n", + __func__, test_bit(FLAG_REQUESTED, &desc->flags), test_bit(FLAG_EXPORT, &desc->flags)); status = -EPERM; @@ -857,8 +878,7 @@ fail_unregister_device: device_unregister(dev); fail_unlock: mutex_unlock(&sysfs_lock); - pr_debug("%s: gpio%d status %d\n", __func__, desc_to_gpio(desc), - status); + gpiod_dbg(desc, "%s: status %d\n", __func__, status); return status; } EXPORT_SYMBOL_GPL(gpiod_export); @@ -906,8 +926,7 @@ int gpiod_export_link(struct device *dev, const char *name, mutex_unlock(&sysfs_lock); if (status) - pr_debug("%s: gpio%d status %d\n", __func__, desc_to_gpio(desc), - status); + gpiod_dbg(desc, "%s: status %d\n", __func__, status); return status; } @@ -951,8 +970,7 @@ unlock: mutex_unlock(&sysfs_lock); if (status) - pr_debug("%s: gpio%d status %d\n", __func__, desc_to_gpio(desc), - status); + gpiod_dbg(desc, "%s: status %d\n", __func__, status); return status; } @@ -994,8 +1012,7 @@ void gpiod_unexport(struct gpio_desc *desc) } if (status) - pr_debug("%s: gpio%d status %d\n", __func__, desc_to_gpio(desc), - status); + gpiod_dbg(desc, "%s: status %d\n", __func__, status); } EXPORT_SYMBOL_GPL(gpiod_unexport); @@ -1034,8 +1051,7 @@ static int gpiochip_export(struct gpio_chip *chip) chip->desc[gpio++].chip = NULL; spin_unlock_irqrestore(&gpio_lock, flags); - pr_debug("%s: chip %s status %d\n", __func__, - chip->label, status); + chip_dbg(chip, "%s: status %d\n", __func__, status); } return status; @@ -1051,15 +1067,14 @@ static void gpiochip_unexport(struct gpio_chip *chip) if (dev) { put_device(dev); device_unregister(dev); - chip->exported = 0; + chip->exported = false; status = 0; } else status = -ENODEV; mutex_unlock(&sysfs_lock); if (status) - pr_debug("%s: chip %s status %d\n", __func__, - chip->label, status); + chip_dbg(chip, "%s: status %d\n", __func__, status); } static int __init gpiolib_sysfs_init(void) @@ -1213,6 +1228,7 @@ int gpiochip_add(struct gpio_chip *chip) #endif of_gpiochip_add(chip); + acpi_gpiochip_add(chip); if (status) goto fail; @@ -1221,7 +1237,7 @@ int gpiochip_add(struct gpio_chip *chip) if (status) goto fail; - pr_debug("gpiochip_add: registered GPIOs %d to %d on device: %s\n", + pr_debug("%s: registered GPIOs %d to %d on device: %s\n", __func__, chip->base, chip->base + chip->ngpio - 1, chip->label ? : "generic"); @@ -1231,13 +1247,16 @@ unlock: spin_unlock_irqrestore(&gpio_lock, flags); fail: /* failures here can mean systems won't boot... */ - pr_err("gpiochip_add: gpios %d..%d (%s) failed to register\n", + pr_err("%s: GPIOs %d..%d (%s) failed to register\n", __func__, chip->base, chip->base + chip->ngpio - 1, chip->label ? : "generic"); return status; } EXPORT_SYMBOL_GPL(gpiochip_add); +/* Forward-declaration */ +static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip); + /** * gpiochip_remove() - unregister a gpio_chip * @chip: the chip to unregister @@ -1250,8 +1269,11 @@ int gpiochip_remove(struct gpio_chip *chip) int status = 0; unsigned id; + acpi_gpiochip_remove(chip); + spin_lock_irqsave(&gpio_lock, flags); + gpiochip_irqchip_remove(chip); gpiochip_remove_pin_ranges(chip); of_gpiochip_remove(chip); @@ -1321,6 +1343,240 @@ static struct gpio_chip *find_chip_by_name(const char *name) return gpiochip_find((void *)name, gpiochip_match_name); } +#ifdef CONFIG_GPIOLIB_IRQCHIP + +/* + * The following is irqchip helper code for gpiochips. + */ + +/** + * gpiochip_add_chained_irqchip() - adds a chained irqchip to a gpiochip + * @gpiochip: the gpiochip to add the irqchip to + * @irqchip: the irqchip to add to the gpiochip + * @parent_irq: the irq number corresponding to the parent IRQ for this + * chained irqchip + * @parent_handler: the parent interrupt handler for the accumulated IRQ + * coming out of the gpiochip + */ +void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip, + struct irq_chip *irqchip, + int parent_irq, + irq_flow_handler_t parent_handler) +{ + if (gpiochip->can_sleep) { + chip_err(gpiochip, "you cannot have chained interrupts on a chip that may sleep\n"); + return; + } + + irq_set_chained_handler(parent_irq, parent_handler); + /* + * The parent irqchip is already using the chip_data for this + * irqchip, so our callbacks simply use the handler_data. + */ + irq_set_handler_data(parent_irq, gpiochip); +} +EXPORT_SYMBOL_GPL(gpiochip_set_chained_irqchip); + +/* + * This lock class tells lockdep that GPIO irqs are in a different + * category than their parents, so it won't report false recursion. + */ +static struct lock_class_key gpiochip_irq_lock_class; + +/** + * gpiochip_irq_map() - maps an IRQ into a GPIO irqchip + * @d: the irqdomain used by this irqchip + * @irq: the global irq number used by this GPIO irqchip irq + * @hwirq: the local IRQ/GPIO line offset on this gpiochip + * + * This function will set up the mapping for a certain IRQ line on a + * gpiochip by assigning the gpiochip as chip data, and using the irqchip + * stored inside the gpiochip. + */ +static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) +{ + struct gpio_chip *chip = d->host_data; + + irq_set_chip_data(irq, chip); + irq_set_lockdep_class(irq, &gpiochip_irq_lock_class); + irq_set_chip_and_handler(irq, chip->irqchip, chip->irq_handler); + /* Chips that can sleep need nested thread handlers */ + if (chip->can_sleep) + irq_set_nested_thread(irq, 1); +#ifdef CONFIG_ARM + set_irq_flags(irq, IRQF_VALID); +#else + irq_set_noprobe(irq); +#endif + /* + * No set-up of the hardware will happen if IRQ_TYPE_NONE + * is passed as default type. + */ + if (chip->irq_default_type != IRQ_TYPE_NONE) + irq_set_irq_type(irq, chip->irq_default_type); + + return 0; +} + +static void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq) +{ + struct gpio_chip *chip = d->host_data; + +#ifdef CONFIG_ARM + set_irq_flags(irq, 0); +#endif + if (chip->can_sleep) + irq_set_nested_thread(irq, 0); + irq_set_chip_and_handler(irq, NULL, NULL); + irq_set_chip_data(irq, NULL); +} + +static const struct irq_domain_ops gpiochip_domain_ops = { + .map = gpiochip_irq_map, + .unmap = gpiochip_irq_unmap, + /* Virtually all GPIO irqchips are twocell:ed */ + .xlate = irq_domain_xlate_twocell, +}; + +static int gpiochip_irq_reqres(struct irq_data *d) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + + if (gpio_lock_as_irq(chip, d->hwirq)) { + chip_err(chip, + "unable to lock HW IRQ %lu for IRQ\n", + d->hwirq); + return -EINVAL; + } + return 0; +} + +static void gpiochip_irq_relres(struct irq_data *d) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + + gpio_unlock_as_irq(chip, d->hwirq); +} + +static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset) +{ + return irq_find_mapping(chip->irqdomain, offset); +} + +/** + * gpiochip_irqchip_remove() - removes an irqchip added to a gpiochip + * @gpiochip: the gpiochip to remove the irqchip from + * + * This is called only from gpiochip_remove() + */ +static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) +{ + unsigned int offset; + + /* Remove all IRQ mappings and delete the domain */ + if (gpiochip->irqdomain) { + for (offset = 0; offset < gpiochip->ngpio; offset++) + irq_dispose_mapping(gpiochip->irq_base + offset); + irq_domain_remove(gpiochip->irqdomain); + } + + if (gpiochip->irqchip) { + gpiochip->irqchip->irq_request_resources = NULL; + gpiochip->irqchip->irq_release_resources = NULL; + gpiochip->irqchip = NULL; + } +} + +/** + * gpiochip_irqchip_add() - adds an irqchip to a gpiochip + * @gpiochip: the gpiochip to add the irqchip to + * @irqchip: the irqchip to add to the gpiochip + * @first_irq: if not dynamically assigned, the base (first) IRQ to + * allocate gpiochip irqs from + * @handler: the irq handler to use (often a predefined irq core function) + * @type: the default type for IRQs on this irqchip, pass IRQ_TYPE_NONE + * to have the core avoid setting up any default type in the hardware. + * + * This function closely associates a certain irqchip with a certain + * gpiochip, providing an irq domain to translate the local IRQs to + * global irqs in the gpiolib core, and making sure that the gpiochip + * is passed as chip data to all related functions. Driver callbacks + * need to use container_of() to get their local state containers back + * from the gpiochip passed as chip data. An irqdomain will be stored + * in the gpiochip that shall be used by the driver to handle IRQ number + * translation. The gpiochip will need to be initialized and registered + * before calling this function. + * + * This function will handle two cell:ed simple IRQs and assumes all + * the pins on the gpiochip can generate a unique IRQ. Everything else + * need to be open coded. + */ +int gpiochip_irqchip_add(struct gpio_chip *gpiochip, + struct irq_chip *irqchip, + unsigned int first_irq, + irq_flow_handler_t handler, + unsigned int type) +{ + struct device_node *of_node; + unsigned int offset; + unsigned irq_base = 0; + + if (!gpiochip || !irqchip) + return -EINVAL; + + if (!gpiochip->dev) { + pr_err("missing gpiochip .dev parent pointer\n"); + return -EINVAL; + } + of_node = gpiochip->dev->of_node; +#ifdef CONFIG_OF_GPIO + /* + * If the gpiochip has an assigned OF node this takes precendence + * FIXME: get rid of this and use gpiochip->dev->of_node everywhere + */ + if (gpiochip->of_node) + of_node = gpiochip->of_node; +#endif + gpiochip->irqchip = irqchip; + gpiochip->irq_handler = handler; + gpiochip->irq_default_type = type; + gpiochip->to_irq = gpiochip_to_irq; + gpiochip->irqdomain = irq_domain_add_simple(of_node, + gpiochip->ngpio, first_irq, + &gpiochip_domain_ops, gpiochip); + if (!gpiochip->irqdomain) { + gpiochip->irqchip = NULL; + return -EINVAL; + } + irqchip->irq_request_resources = gpiochip_irq_reqres; + irqchip->irq_release_resources = gpiochip_irq_relres; + + /* + * Prepare the mapping since the irqchip shall be orthogonal to + * any gpiochip calls. If the first_irq was zero, this is + * necessary to allocate descriptors for all IRQs. + */ + for (offset = 0; offset < gpiochip->ngpio; offset++) { + irq_base = irq_create_mapping(gpiochip->irqdomain, offset); + if (offset == 0) + /* + * Store the base into the gpiochip to be used when + * unmapping the irqs. + */ + gpiochip->irq_base = irq_base; + } + + return 0; +} +EXPORT_SYMBOL_GPL(gpiochip_irqchip_add); + +#else /* CONFIG_GPIOLIB_IRQCHIP */ + +static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) {} + +#endif /* CONFIG_GPIOLIB_IRQCHIP */ + #ifdef CONFIG_PINCTRL /** @@ -1339,8 +1595,7 @@ int gpiochip_add_pingroup_range(struct gpio_chip *chip, pin_range = kzalloc(sizeof(*pin_range), GFP_KERNEL); if (!pin_range) { - pr_err("%s: GPIO chip: failed to allocate pin ranges\n", - chip->label); + chip_err(chip, "failed to allocate pin ranges\n"); return -ENOMEM; } @@ -1361,9 +1616,8 @@ int gpiochip_add_pingroup_range(struct gpio_chip *chip, pinctrl_add_gpio_range(pctldev, &pin_range->range); - pr_debug("GPIO chip %s: created GPIO range %d->%d ==> %s PINGRP %s\n", - chip->label, gpio_offset, - gpio_offset + pin_range->range.npins - 1, + chip_dbg(chip, "created GPIO range %d->%d ==> %s PINGRP %s\n", + gpio_offset, gpio_offset + pin_range->range.npins - 1, pinctrl_dev_get_devname(pctldev), pin_group); list_add_tail(&pin_range->node, &chip->pin_ranges); @@ -1390,8 +1644,7 @@ int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, pin_range = kzalloc(sizeof(*pin_range), GFP_KERNEL); if (!pin_range) { - pr_err("%s: GPIO chip: failed to allocate pin ranges\n", - chip->label); + chip_err(chip, "failed to allocate pin ranges\n"); return -ENOMEM; } @@ -1406,13 +1659,12 @@ int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, &pin_range->range); if (IS_ERR(pin_range->pctldev)) { ret = PTR_ERR(pin_range->pctldev); - pr_err("%s: GPIO chip: could not create pin range\n", - chip->label); + chip_err(chip, "could not create pin range\n"); kfree(pin_range); return ret; } - pr_debug("GPIO chip %s: created GPIO range %d->%d ==> %s PIN %d->%d\n", - chip->label, gpio_offset, gpio_offset + npins - 1, + chip_dbg(chip, "created GPIO range %d->%d ==> %s PIN %d->%d\n", + gpio_offset, gpio_offset + npins - 1, pinctl_name, pin_offset, pin_offset + npins - 1); @@ -1445,26 +1697,14 @@ EXPORT_SYMBOL_GPL(gpiochip_remove_pin_ranges); * on each other, and help provide better diagnostics in debugfs. * They're called even less than the "set direction" calls. */ -static int gpiod_request(struct gpio_desc *desc, const char *label) +static int __gpiod_request(struct gpio_desc *desc, const char *label) { - struct gpio_chip *chip; - int status = -EPROBE_DEFER; + struct gpio_chip *chip = desc->chip; + int status; unsigned long flags; - if (!desc) { - pr_warn("%s: invalid GPIO\n", __func__); - return -EINVAL; - } - spin_lock_irqsave(&gpio_lock, flags); - chip = desc->chip; - if (chip == NULL) - goto done; - - if (!try_module_get(chip->owner)) - goto done; - /* NOTE: gpio_request() can be called in early boot, * before IRQs are enabled, for non-sleeping (SOC) GPIOs. */ @@ -1474,7 +1714,6 @@ static int gpiod_request(struct gpio_desc *desc, const char *label) status = 0; } else { status = -EBUSY; - module_put(chip->owner); goto done; } @@ -1486,7 +1725,6 @@ static int gpiod_request(struct gpio_desc *desc, const char *label) if (status < 0) { desc_set_label(desc, NULL); - module_put(chip->owner); clear_bit(FLAG_REQUESTED, &desc->flags); goto done; } @@ -1498,31 +1736,51 @@ static int gpiod_request(struct gpio_desc *desc, const char *label) spin_lock_irqsave(&gpio_lock, flags); } done: - if (status) - pr_debug("_gpio_request: gpio-%d (%s) status %d\n", - desc_to_gpio(desc), label ? : "?", status); spin_unlock_irqrestore(&gpio_lock, flags); return status; } +static int gpiod_request(struct gpio_desc *desc, const char *label) +{ + int status = -EPROBE_DEFER; + struct gpio_chip *chip; + + if (!desc) { + pr_warn("%s: invalid GPIO\n", __func__); + return -EINVAL; + } + + chip = desc->chip; + if (!chip) + goto done; + + if (try_module_get(chip->owner)) { + status = __gpiod_request(desc, label); + if (status < 0) + module_put(chip->owner); + } + +done: + if (status) + gpiod_dbg(desc, "%s: status %d\n", __func__, status); + + return status; +} + int gpio_request(unsigned gpio, const char *label) { return gpiod_request(gpio_to_desc(gpio), label); } EXPORT_SYMBOL_GPL(gpio_request); -static void gpiod_free(struct gpio_desc *desc) +static bool __gpiod_free(struct gpio_desc *desc) { + bool ret = false; unsigned long flags; struct gpio_chip *chip; might_sleep(); - if (!desc) { - WARN_ON(extra_checks); - return; - } - gpiod_unexport(desc); spin_lock_irqsave(&gpio_lock, flags); @@ -1536,15 +1794,23 @@ static void gpiod_free(struct gpio_desc *desc) spin_lock_irqsave(&gpio_lock, flags); } desc_set_label(desc, NULL); - module_put(desc->chip->owner); clear_bit(FLAG_ACTIVE_LOW, &desc->flags); clear_bit(FLAG_REQUESTED, &desc->flags); clear_bit(FLAG_OPEN_DRAIN, &desc->flags); clear_bit(FLAG_OPEN_SOURCE, &desc->flags); - } else - WARN_ON(extra_checks); + ret = true; + } spin_unlock_irqrestore(&gpio_lock, flags); + return ret; +} + +static void gpiod_free(struct gpio_desc *desc) +{ + if (desc && __gpiod_free(desc)) + module_put(desc->chip->owner); + else + WARN_ON(extra_checks); } void gpio_free(unsigned gpio) @@ -1579,7 +1845,7 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label) if (flags & GPIOF_DIR_IN) err = gpiod_direction_input(desc); else - err = gpiod_direction_output(desc, + err = gpiod_direction_output_raw(desc, (flags & GPIOF_INIT_HIGH) ? 1 : 0); if (err) @@ -1666,6 +1932,37 @@ const char *gpiochip_is_requested(struct gpio_chip *chip, unsigned offset) } EXPORT_SYMBOL_GPL(gpiochip_is_requested); +/** + * gpiochip_request_own_desc - Allow GPIO chip to request its own descriptor + * @desc: GPIO descriptor to request + * @label: label for the GPIO + * + * Function allows GPIO chip drivers to request and use their own GPIO + * descriptors via gpiolib API. Difference to gpiod_request() is that this + * function will not increase reference count of the GPIO chip module. This + * allows the GPIO chip module to be unloaded as needed (we assume that the + * GPIO chip driver handles freeing the GPIOs it has requested). + */ +int gpiochip_request_own_desc(struct gpio_desc *desc, const char *label) +{ + if (!desc || !desc->chip) + return -EINVAL; + + return __gpiod_request(desc, label); +} + +/** + * gpiochip_free_own_desc - Free GPIO requested by the chip driver + * @desc: GPIO descriptor to free + * + * Function frees the given GPIO requested previously with + * gpiochip_request_own_desc(). + */ +void gpiochip_free_own_desc(struct gpio_desc *desc) +{ + if (desc) + __gpiod_free(desc); +} /* Drivers MUST set GPIO direction before making get/set calls. In * some cases this is done in early boot, before IRQs are enabled. @@ -1701,7 +1998,7 @@ int gpiod_direction_input(struct gpio_desc *desc) if (!chip->get || !chip->direction_input) { gpiod_warn(desc, "%s: missing get() or direction_input() operations\n", - __func__); + __func__); return -EIO; } @@ -1721,7 +2018,8 @@ int gpiod_direction_input(struct gpio_desc *desc) if (status) { status = chip->request(chip, offset); if (status < 0) { - gpiod_dbg(desc, "chip request fail, %d\n", status); + gpiod_dbg(desc, "%s: chip request fail, %d\n", + __func__, status); /* and it's not available to anyone else ... * gpio_request() is the fully clean solution. */ @@ -1739,33 +2037,18 @@ lose: fail: spin_unlock_irqrestore(&gpio_lock, flags); if (status) - gpiod_dbg(desc, "%s status %d\n", __func__, status); + gpiod_dbg(desc, "%s: status %d\n", __func__, status); return status; } EXPORT_SYMBOL_GPL(gpiod_direction_input); -/** - * gpiod_direction_output - set the GPIO direction to input - * @desc: GPIO to set to output - * @value: initial output value of the GPIO - * - * Set the direction of the passed GPIO to output, such as gpiod_set_value() can - * be called safely on it. The initial value of the output must be specified. - * - * Return 0 in case of success, else an error code. - */ -int gpiod_direction_output(struct gpio_desc *desc, int value) +static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value) { unsigned long flags; struct gpio_chip *chip; int status = -EINVAL; int offset; - if (!desc || !desc->chip) { - pr_warn("%s: invalid GPIO\n", __func__); - return -EINVAL; - } - /* GPIOs used for IRQs shall not be set as output */ if (test_bit(FLAG_USED_AS_IRQ, &desc->flags)) { gpiod_err(desc, @@ -1806,7 +2089,8 @@ int gpiod_direction_output(struct gpio_desc *desc, int value) if (status) { status = chip->request(chip, offset); if (status < 0) { - gpiod_dbg(desc, "chip request fail, %d\n", status); + gpiod_dbg(desc, "%s: chip request fail, %d\n", + __func__, status); /* and it's not available to anyone else ... * gpio_request() is the fully clean solution. */ @@ -1827,6 +2111,50 @@ fail: gpiod_dbg(desc, "%s: gpio status %d\n", __func__, status); return status; } + +/** + * gpiod_direction_output_raw - set the GPIO direction to output + * @desc: GPIO to set to output + * @value: initial output value of the GPIO + * + * Set the direction of the passed GPIO to output, such as gpiod_set_value() can + * be called safely on it. The initial value of the output must be specified + * as raw value on the physical line without regard for the ACTIVE_LOW status. + * + * Return 0 in case of success, else an error code. + */ +int gpiod_direction_output_raw(struct gpio_desc *desc, int value) +{ + if (!desc || !desc->chip) { + pr_warn("%s: invalid GPIO\n", __func__); + return -EINVAL; + } + return _gpiod_direction_output_raw(desc, value); +} +EXPORT_SYMBOL_GPL(gpiod_direction_output_raw); + +/** + * gpiod_direction_output - set the GPIO direction to output + * @desc: GPIO to set to output + * @value: initial output value of the GPIO + * + * Set the direction of the passed GPIO to output, such as gpiod_set_value() can + * be called safely on it. The initial value of the output must be specified + * as the logical value of the GPIO, i.e. taking its ACTIVE_LOW status into + * account. + * + * Return 0 in case of success, else an error code. + */ +int gpiod_direction_output(struct gpio_desc *desc, int value) +{ + if (!desc || !desc->chip) { + pr_warn("%s: invalid GPIO\n", __func__); + return -EINVAL; + } + if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) + value = !value; + return _gpiod_direction_output_raw(desc, value); +} EXPORT_SYMBOL_GPL(gpiod_direction_output); /** @@ -1915,15 +2243,15 @@ EXPORT_SYMBOL_GPL(gpiod_is_active_low); * that the GPIO was actually requested. */ -static int _gpiod_get_raw_value(const struct gpio_desc *desc) +static bool _gpiod_get_raw_value(const struct gpio_desc *desc) { struct gpio_chip *chip; - int value; + bool value; int offset; chip = desc->chip; offset = gpio_chip_hwgpio(desc); - value = chip->get ? chip->get(chip, offset) : 0; + value = chip->get ? chip->get(chip, offset) : false; trace_gpio_value(desc_to_gpio(desc), 1, value); return value; } @@ -1979,7 +2307,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_value); * @desc: gpio descriptor whose state need to be set. * @value: Non-zero for setting it HIGH otherise it will set to LOW. */ -static void _gpio_set_open_drain_value(struct gpio_desc *desc, int value) +static void _gpio_set_open_drain_value(struct gpio_desc *desc, bool value) { int err = 0; struct gpio_chip *chip = desc->chip; @@ -2006,7 +2334,7 @@ static void _gpio_set_open_drain_value(struct gpio_desc *desc, int value) * @desc: gpio descriptor whose state need to be set. * @value: Non-zero for setting it HIGH otherise it will set to LOW. */ -static void _gpio_set_open_source_value(struct gpio_desc *desc, int value) +static void _gpio_set_open_source_value(struct gpio_desc *desc, bool value) { int err = 0; struct gpio_chip *chip = desc->chip; @@ -2028,7 +2356,7 @@ static void _gpio_set_open_source_value(struct gpio_desc *desc, int value) __func__, err); } -static void _gpiod_set_raw_value(struct gpio_desc *desc, int value) +static void _gpiod_set_raw_value(struct gpio_desc *desc, bool value) { struct gpio_chip *chip; @@ -2124,10 +2452,7 @@ EXPORT_SYMBOL_GPL(gpiod_to_irq); * @gpio: the GPIO line to lock as used for IRQ * * This is used directly by GPIO drivers that want to lock down - * a certain GPIO line to be used as IRQs, for example in the - * .to_irq() callback of their gpio_chip, or in the .irq_enable() - * of its irq_chip implementation if the GPIO is known from that - * code. + * a certain GPIO line to be used for IRQs. */ int gpiod_lock_as_irq(struct gpio_desc *desc) { @@ -2148,7 +2473,7 @@ EXPORT_SYMBOL_GPL(gpiod_lock_as_irq); int gpio_lock_as_irq(struct gpio_chip *chip, unsigned int offset) { - return gpiod_lock_as_irq(gpiochip_offset_to_desc(chip, offset)); + return gpiod_lock_as_irq(gpiochip_get_desc(chip, offset)); } EXPORT_SYMBOL_GPL(gpio_lock_as_irq); @@ -2170,7 +2495,7 @@ EXPORT_SYMBOL_GPL(gpiod_unlock_as_irq); void gpio_unlock_as_irq(struct gpio_chip *chip, unsigned int offset) { - return gpiod_unlock_as_irq(gpiochip_offset_to_desc(chip, offset)); + return gpiod_unlock_as_irq(gpiochip_get_desc(chip, offset)); } EXPORT_SYMBOL_GPL(gpio_unlock_as_irq); @@ -2259,38 +2584,39 @@ void gpiod_set_value_cansleep(struct gpio_desc *desc, int value) EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep); /** - * gpiod_add_table() - register GPIO device consumers - * @table: array of consumers to register - * @num: number of consumers in table + * gpiod_add_lookup_table() - register GPIO device consumers + * @table: table of consumers to register */ -void gpiod_add_table(struct gpiod_lookup *table, size_t size) +void gpiod_add_lookup_table(struct gpiod_lookup_table *table) { mutex_lock(&gpio_lookup_lock); - while (size--) { - list_add_tail(&table->list, &gpio_lookup_list); - table++; - } + list_add_tail(&table->list, &gpio_lookup_list); mutex_unlock(&gpio_lookup_lock); } -#ifdef CONFIG_OF static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, unsigned int idx, enum gpio_lookup_flags *flags) { + static const char *suffixes[] = { "gpios", "gpio" }; char prop_name[32]; /* 32 is max size of property name */ enum of_gpio_flags of_flags; struct gpio_desc *desc; + unsigned int i; - if (con_id) - snprintf(prop_name, 32, "%s-gpios", con_id); - else - snprintf(prop_name, 32, "gpios"); + for (i = 0; i < ARRAY_SIZE(suffixes); i++) { + if (con_id) + snprintf(prop_name, 32, "%s-%s", con_id, suffixes[i]); + else + snprintf(prop_name, 32, "%s", suffixes[i]); - desc = of_get_named_gpiod_flags(dev->of_node, prop_name, idx, - &of_flags); + desc = of_get_named_gpiod_flags(dev->of_node, prop_name, idx, + &of_flags); + if (!IS_ERR(desc) || (PTR_ERR(desc) == -EPROBE_DEFER)) + break; + } if (IS_ERR(desc)) return desc; @@ -2300,14 +2626,6 @@ static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, return desc; } -#else -static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, - unsigned int idx, - enum gpio_lookup_flags *flags) -{ - return ERR_PTR(-ENODEV); -} -#endif static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id, unsigned int idx, @@ -2326,76 +2644,92 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id, return desc; } -static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, - unsigned int idx, - enum gpio_lookup_flags *flags) +static struct gpiod_lookup_table *gpiod_find_lookup_table(struct device *dev) { const char *dev_id = dev ? dev_name(dev) : NULL; - struct gpio_desc *desc = ERR_PTR(-ENODEV); - unsigned int match, best = 0; - struct gpiod_lookup *p; + struct gpiod_lookup_table *table; mutex_lock(&gpio_lookup_lock); - list_for_each_entry(p, &gpio_lookup_list, list) { - match = 0; + list_for_each_entry(table, &gpio_lookup_list, list) { + if (table->dev_id && dev_id) { + /* + * Valid strings on both ends, must be identical to have + * a match + */ + if (!strcmp(table->dev_id, dev_id)) + goto found; + } else { + /* + * One of the pointers is NULL, so both must be to have + * a match + */ + if (dev_id == table->dev_id) + goto found; + } + } + table = NULL; - if (p->dev_id) { - if (!dev_id || strcmp(p->dev_id, dev_id)) - continue; +found: + mutex_unlock(&gpio_lookup_lock); + return table; +} - match += 2; - } +static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, + unsigned int idx, + enum gpio_lookup_flags *flags) +{ + struct gpio_desc *desc = ERR_PTR(-ENOENT); + struct gpiod_lookup_table *table; + struct gpiod_lookup *p; - if (p->con_id) { - if (!con_id || strcmp(p->con_id, con_id)) - continue; + table = gpiod_find_lookup_table(dev); + if (!table) + return desc; - match += 1; - } + for (p = &table->table[0]; p->chip_label; p++) { + struct gpio_chip *chip; + /* idx must always match exactly */ if (p->idx != idx) continue; - if (match > best) { - struct gpio_chip *chip; + /* If the lookup entry has a con_id, require exact match */ + if (p->con_id && (!con_id || strcmp(p->con_id, con_id))) + continue; - chip = find_chip_by_name(p->chip_label); + chip = find_chip_by_name(p->chip_label); - if (!chip) { - dev_warn(dev, "cannot find GPIO chip %s\n", - p->chip_label); - continue; - } + if (!chip) { + dev_err(dev, "cannot find GPIO chip %s\n", + p->chip_label); + return ERR_PTR(-ENODEV); + } - if (chip->ngpio <= p->chip_hwnum) { - dev_warn(dev, "GPIO chip %s has %d GPIOs\n", - chip->label, chip->ngpio); - continue; - } + if (chip->ngpio <= p->chip_hwnum) { + dev_err(dev, + "requested GPIO %d is out of range [0..%d] for chip %s\n", + idx, chip->ngpio, chip->label); + return ERR_PTR(-EINVAL); + } - desc = gpio_to_desc(chip->base + p->chip_hwnum); - *flags = p->flags; + desc = gpiochip_get_desc(chip, p->chip_hwnum); + *flags = p->flags; - if (match != 3) - best = match; - else - break; - } + return desc; } - mutex_unlock(&gpio_lookup_lock); - return desc; } /** - * gpio_get - obtain a GPIO for a given GPIO function - * @dev: GPIO consumer + * gpiod_get - obtain a GPIO for a given GPIO function + * @dev: GPIO consumer, can be NULL for system-global GPIOs * @con_id: function within the GPIO consumer * * Return the GPIO descriptor corresponding to the function con_id of device - * dev, or an IS_ERR() condition if an error occured. + * dev, -ENOENT if no GPIO has been assigned to the requested function, or + * another IS_ERR() code if an error occured while trying to acquire the GPIO. */ struct gpio_desc *__must_check gpiod_get(struct device *dev, const char *con_id) { @@ -2404,15 +2738,33 @@ struct gpio_desc *__must_check gpiod_get(struct device *dev, const char *con_id) EXPORT_SYMBOL_GPL(gpiod_get); /** + * gpiod_get_optional - obtain an optional GPIO for a given GPIO function + * @dev: GPIO consumer, can be NULL for system-global GPIOs + * @con_id: function within the GPIO consumer + * + * This is equivalent to gpiod_get(), except that when no GPIO was assigned to + * the requested function it will return NULL. This is convenient for drivers + * that need to handle optional GPIOs. + */ +struct gpio_desc *__must_check gpiod_get_optional(struct device *dev, + const char *con_id) +{ + return gpiod_get_index_optional(dev, con_id, 0); +} +EXPORT_SYMBOL_GPL(gpiod_get_optional); + +/** * gpiod_get_index - obtain a GPIO from a multi-index GPIO function - * @dev: GPIO consumer + * @dev: GPIO consumer, can be NULL for system-global GPIOs * @con_id: function within the GPIO consumer * @idx: index of the GPIO to obtain in the consumer * * This variant of gpiod_get() allows to access GPIOs other than the first * defined one for functions that define several GPIOs. * - * Return a valid GPIO descriptor, or an IS_ERR() condition in case of error. + * Return a valid GPIO descriptor, -ENOENT if no GPIO has been assigned to the + * requested function and/or index, or another IS_ERR() code if an error + * occured while trying to acquire the GPIO. */ struct gpio_desc *__must_check gpiod_get_index(struct device *dev, const char *con_id, @@ -2437,13 +2789,9 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev, * Either we are not using DT or ACPI, or their lookup did not return * a result. In that case, use platform lookup as a fallback. */ - if (!desc || IS_ERR(desc)) { - struct gpio_desc *pdesc; + if (!desc || desc == ERR_PTR(-ENOENT)) { dev_dbg(dev, "using lookup tables for GPIO lookup"); - pdesc = gpiod_find(dev, con_id, idx, &flags); - /* If used as fallback, do not replace the previous error */ - if (!IS_ERR(pdesc) || !desc) - desc = pdesc; + desc = gpiod_find(dev, con_id, idx, &flags); } if (IS_ERR(desc)) { @@ -2468,6 +2816,33 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev, EXPORT_SYMBOL_GPL(gpiod_get_index); /** + * gpiod_get_index_optional - obtain an optional GPIO from a multi-index GPIO + * function + * @dev: GPIO consumer, can be NULL for system-global GPIOs + * @con_id: function within the GPIO consumer + * @index: index of the GPIO to obtain in the consumer + * + * This is equivalent to gpiod_get_index(), except that when no GPIO with the + * specified index was assigned to the requested function it will return NULL. + * This is convenient for drivers that need to handle optional GPIOs. + */ +struct gpio_desc *__must_check gpiod_get_index_optional(struct device *dev, + const char *con_id, + unsigned int index) +{ + struct gpio_desc *desc; + + desc = gpiod_get_index(dev, con_id, index); + if (IS_ERR(desc)) { + if (PTR_ERR(desc) == -ENOENT) + return NULL; + } + + return desc; +} +EXPORT_SYMBOL_GPL(gpiod_get_index_optional); + +/** * gpiod_put - dispose of a GPIO descriptor * @desc: GPIO descriptor to dispose of * diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h new file mode 100644 index 00000000000..1a4103dd38d --- /dev/null +++ b/drivers/gpio/gpiolib.h @@ -0,0 +1,54 @@ +/* + * Internal GPIO functions. + * + * Copyright (C) 2013, Intel Corporation + * Author: Mika Westerberg <mika.westerberg@linux.intel.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef GPIOLIB_H +#define GPIOLIB_H + +#include <linux/err.h> +#include <linux/device.h> + +enum of_gpio_flags; + +/** + * struct acpi_gpio_info - ACPI GPIO specific information + * @gpioint: if %true this GPIO is of type GpioInt otherwise type is GpioIo + * @active_low: in case of @gpioint, the pin is active low + */ +struct acpi_gpio_info { + bool gpioint; + bool active_low; +}; + +#ifdef CONFIG_ACPI +void acpi_gpiochip_add(struct gpio_chip *chip); +void acpi_gpiochip_remove(struct gpio_chip *chip); + +struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index, + struct acpi_gpio_info *info); +#else +static inline void acpi_gpiochip_add(struct gpio_chip *chip) { } +static inline void acpi_gpiochip_remove(struct gpio_chip *chip) { } + +static inline struct gpio_desc * +acpi_get_gpiod_by_index(struct device *dev, int index, + struct acpi_gpio_info *info) +{ + return ERR_PTR(-ENOSYS); +} +#endif + +int gpiochip_request_own_desc(struct gpio_desc *desc, const char *label); +void gpiochip_free_own_desc(struct gpio_desc *desc); + +struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np, + const char *list_name, int index, enum of_gpio_flags *flags); + +#endif /* GPIOLIB_H */ |
