diff options
65 files changed, 1297 insertions, 659 deletions
diff --git a/Documentation/devicetree/bindings/gpio/gpio-dsp-keystone.txt b/Documentation/devicetree/bindings/gpio/gpio-dsp-keystone.txt new file mode 100644 index 0000000..6c7e6c7 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio-dsp-keystone.txt @@ -0,0 +1,39 @@ +Keystone 2 DSP GPIO controller bindings + +HOST OS userland running on ARM can send interrupts to DSP cores using +the DSP GPIO controller IP. It provides 28 IRQ signals per each DSP core. +This is one of the component used by the IPC mechanism used on Keystone SOCs. + +For example TCI6638K2K SoC has 8 DSP GPIO controllers: + - 8 for C66x CorePacx CPUs 0-7 + +Keystone 2 DSP GPIO controller has specific features: +- each GPIO can be configured only as output pin; +- setting GPIO value to 1 causes IRQ generation on target DSP core; +- reading pin value returns 0 - if IRQ was handled or 1 - IRQ is still + pending. + +Required Properties: +- compatible: should be "ti,keystone-dsp-gpio" +- ti,syscon-dev: phandle/offset pair. The phandle to syscon used to + access device state control registers and the offset of device's specific + registers within device state control registers range. +- gpio-controller: Marks the device node as a gpio controller. +- #gpio-cells: Should be 2. + +Please refer to gpio.txt in this directory for details of the common GPIO +bindings used by client devices. + +Example: + dspgpio0: keystone_dsp_gpio@02620240 { + compatible = "ti,keystone-dsp-gpio"; + ti,syscon-dev = <&devctrl 0x240>; + gpio-controller; + #gpio-cells = <2>; + }; + + dsp0: dsp0 { + compatible = "linux,rproc-user"; + ... + kick-gpio = <&dspgpio0 27>; + }; diff --git a/Documentation/devicetree/bindings/gpio/gpio-pca953x.txt b/Documentation/devicetree/bindings/gpio/gpio-pca953x.txt new file mode 100644 index 0000000..b9a42f2 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio-pca953x.txt @@ -0,0 +1,39 @@ +* NXP PCA953x I2C GPIO multiplexer + +Required properties: + - compatible: Has to contain one of the following: + nxp,pca9505 + nxp,pca9534 + nxp,pca9535 + nxp,pca9536 + nxp,pca9537 + nxp,pca9538 + nxp,pca9539 + nxp,pca9554 + nxp,pca9555 + nxp,pca9556 + nxp,pca9557 + nxp,pca9574 + nxp,pca9575 + nxp,pca9698 + maxim,max7310 + maxim,max7312 + maxim,max7313 + maxim,max7315 + ti,pca6107 + ti,tca6408 + ti,tca6416 + ti,tca6424 + exar,xra1202 + +Example: + + + gpio@20 { + compatible = "nxp,pca9505"; + reg = <0x20>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pca9505>; + interrupt-parent = <&gpio3>; + interrupts = <23 IRQ_TYPE_LEVEL_LOW>; + }; diff --git a/Documentation/devicetree/bindings/gpio/gpio-xgene.txt b/Documentation/devicetree/bindings/gpio/gpio-xgene.txt new file mode 100644 index 0000000..86dbb05 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio-xgene.txt @@ -0,0 +1,22 @@ +APM X-Gene SoC GPIO controller bindings + +This is a gpio controller that is part of the flash controller. +This gpio controller controls a total of 48 gpios. + +Required properties: +- compatible: "apm,xgene-gpio" for X-Gene GPIO controller +- reg: Physical base address and size of the controller's registers +- #gpio-cells: Should be two. + - first cell is the pin number + - second cell is used to specify the gpio polarity: + 0 = active high + 1 = active low +- gpio-controller: Marks the device node as a GPIO controller. + +Example: + gpio0: gpio0@1701c000 { + compatible = "apm,xgene-gpio"; + reg = <0x0 0x1701c000 0x0 0x40>; + gpio-controller; + #gpio-cells = <2>; + }; diff --git a/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt b/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt index 6641626..b2afdb2 100644 --- a/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt +++ b/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt @@ -19,7 +19,7 @@ Required properties: - gpio-controller : Marks the device node as a gpio controller. - #gpio-cells : Should be one. It is the pin number. -Example: +Example for a MMP platform: gpio: gpio@d4019000 { compatible = "marvell,mmp-gpio"; @@ -32,6 +32,19 @@ Example: #interrupt-cells = <1>; }; +Example for a PXA3xx platform: + + gpio: gpio@40e00000 { + compatible = "intel,pxa3xx-gpio"; + reg = <0x40e00000 0x10000>; + interrupt-names = "gpio0", "gpio1", "gpio_mux"; + interrupts = <8 9 10>; + gpio-controller; + #gpio-cells = <0x2>; + interrupt-controller; + #interrupt-cells = <0x2>; + }; + * Marvell Orion GPIO Controller Required properties: diff --git a/Documentation/gpio/driver.txt b/Documentation/gpio/driver.txt index 18790c2..31e0b5d 100644 --- a/Documentation/gpio/driver.txt +++ b/Documentation/gpio/driver.txt @@ -124,7 +124,8 @@ symbol: * gpiochip_set_chained_irqchip(): sets up a chained irq handler for a gpio_chip from a parent IRQ and passes the struct gpio_chip* as handler data. (Notice handler data, since the irqchip data is likely used by the - parent irqchip!) This is for the chained type of chip. + parent irqchip!) This is for the chained type of chip. This is also used + to set up a nested irqchip if NULL is passed as handler. To use the helpers please keep the following in mind: @@ -178,7 +179,8 @@ does not help since it pins the module to the kernel forever (it calls try_module_get()). A GPIO driver can use the following functions instead to request and free descriptors without being pinned to the kernel forever. - int gpiochip_request_own_desc(struct gpio_desc *desc, const char *label) + struct gpio_desc *gpiochip_request_own_desc(struct gpio_desc *desc, + const char *label) void gpiochip_free_own_desc(struct gpio_desc *desc) diff --git a/arch/arm/common/scoop.c b/arch/arm/common/scoop.c index a20fa80..45f4c21 100644 --- a/arch/arm/common/scoop.c +++ b/arch/arm/common/scoop.c @@ -243,18 +243,12 @@ err_ioremap: static int scoop_remove(struct platform_device *pdev) { struct scoop_dev *sdev = platform_get_drvdata(pdev); - int ret; if (!sdev) return -EINVAL; - if (sdev->gpio.base != -1) { - ret = gpiochip_remove(&sdev->gpio); - if (ret) { - dev_err(&pdev->dev, "Can't remove gpio chip: %d\n", ret); - return ret; - } - } + if (sdev->gpio.base != -1) + gpiochip_remove(&sdev->gpio); platform_set_drvdata(pdev, NULL); iounmap(sdev->base); diff --git a/arch/mips/txx9/generic/setup.c b/arch/mips/txx9/generic/setup.c index 9ff200a..2791b86 100644 --- a/arch/mips/txx9/generic/setup.c +++ b/arch/mips/txx9/generic/setup.c @@ -789,11 +789,11 @@ void __init txx9_iocled_init(unsigned long baseaddr, if (platform_device_add(pdev)) goto out_pdev; return; + out_pdev: platform_device_put(pdev); out_gpio: - if (gpiochip_remove(&iocled->chip)) - return; + gpiochip_remove(&iocled->chip); out_unmap: iounmap(iocled->mmioaddr); out_free: diff --git a/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c b/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c index e238b6a..7399702 100644 --- a/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c +++ b/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c @@ -141,7 +141,8 @@ static int mcu_gpiochip_add(struct mcu *mcu) static int mcu_gpiochip_remove(struct mcu *mcu) { - return gpiochip_remove(&mcu->gc); + gpiochip_remove(&mcu->gc); + return 0; } static int mcu_probe(struct i2c_client *client, const struct i2c_device_id *id) diff --git a/arch/sh/boards/mach-x3proto/gpio.c b/arch/sh/boards/mach-x3proto/gpio.c index 3ea65e9..f035a7a 100644 --- a/arch/sh/boards/mach-x3proto/gpio.c +++ b/arch/sh/boards/mach-x3proto/gpio.c @@ -128,10 +128,8 @@ int __init x3proto_gpio_setup(void) return 0; err_irq: - ret = gpiochip_remove(&x3proto_gpio_chip); - if (unlikely(ret)) - pr_err("Failed deregistering GPIO\n"); - + gpiochip_remove(&x3proto_gpio_chip); + ret = 0; err_gpio: synchronize_irq(ilsel); diff --git a/drivers/bcma/driver_gpio.c b/drivers/bcma/driver_gpio.c index 57ce5fe..706b9ae 100644 --- a/drivers/bcma/driver_gpio.c +++ b/drivers/bcma/driver_gpio.c @@ -255,5 +255,6 @@ int bcma_gpio_init(struct bcma_drv_cc *cc) int bcma_gpio_unregister(struct bcma_drv_cc *cc) { bcma_gpio_irq_domain_exit(cc); - return gpiochip_remove(&cc->gpio); + gpiochip_remove(&cc->gpio); + return 0; } diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 9de1515..0959ca9 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -136,7 +136,6 @@ 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. @@ -334,6 +333,15 @@ config GPIO_TZ1090_PDC help Say yes here to support Toumaz Xenif TZ1090 PDC GPIOs. +config GPIO_XGENE + bool "APM X-Gene GPIO controller support" + depends on ARM64 && OF_GPIO + help + This driver is to support the GPIO block within the APM X-Gene SoC + platform's generic flash controller. The GPIO pins are muxed with + the generic flash controller's address and data pins. Say yes + here to enable the GFC GPIO functionality. + config GPIO_XILINX bool "Xilinx GPIO support" depends on PPC_OF || MICROBLAZE || ARCH_ZYNQ @@ -681,6 +689,7 @@ config GPIO_ADP5588_IRQ config GPIO_ADNP tristate "Avionic Design N-bit GPIO expander" depends on I2C && OF_GPIO + select GPIOLIB_IRQCHIP help This option enables support for N GPIOs found on Avionic Design I2C GPIO expanders. The register space will be extended by powers @@ -796,7 +805,6 @@ 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 @@ -880,7 +888,7 @@ config GPIO_MSIC config GPIO_BCM_KONA bool "Broadcom Kona GPIO" - depends on OF_GPIO + depends on OF_GPIO && (ARCH_BCM_MOBILE || COMPILE_TEST) help Turn on GPIO support for Broadcom "Kona" chips. diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 5d024e3..e5d346c 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -101,6 +101,7 @@ obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o +obj-$(CONFIG_GPIO_XGENE) += gpio-xgene.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/gpio-adnp.c b/drivers/gpio/gpio-adnp.c index 416b220..d3d0a90 100644 --- a/drivers/gpio/gpio-adnp.c +++ b/drivers/gpio/gpio-adnp.c @@ -6,10 +6,9 @@ * published by the Free Software Foundation. */ -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/i2c.h> #include <linux/interrupt.h> -#include <linux/irqdomain.h> #include <linux/module.h> #include <linux/of_irq.h> #include <linux/seq_file.h> @@ -27,8 +26,6 @@ struct adnp { unsigned int reg_shift; struct mutex i2c_lock; - - struct irq_domain *domain; struct mutex irq_lock; u8 *irq_enable; @@ -253,6 +250,7 @@ static void adnp_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) static int adnp_gpio_setup(struct adnp *adnp, unsigned int num_gpios) { struct gpio_chip *chip = &adnp->gpio; + int err; adnp->reg_shift = get_count_order(num_gpios) - 3; @@ -272,6 +270,10 @@ static int adnp_gpio_setup(struct adnp *adnp, unsigned int num_gpios) chip->of_node = chip->dev->of_node; chip->owner = THIS_MODULE; + err = gpiochip_add(chip); + if (err) + return err; + return 0; } @@ -326,7 +328,8 @@ static irqreturn_t adnp_irq(int irq, void *data) for_each_set_bit(bit, &pending, 8) { unsigned int child_irq; - child_irq = irq_find_mapping(adnp->domain, base + bit); + child_irq = irq_find_mapping(adnp->gpio.irqdomain, + base + bit); handle_nested_irq(child_irq); } } @@ -334,35 +337,32 @@ static irqreturn_t adnp_irq(int irq, void *data) return IRQ_HANDLED; } -static int adnp_gpio_to_irq(struct gpio_chip *chip, unsigned offset) -{ - struct adnp *adnp = to_adnp(chip); - return irq_create_mapping(adnp->domain, offset); -} - -static void adnp_irq_mask(struct irq_data *data) +static void adnp_irq_mask(struct irq_data *d) { - struct adnp *adnp = irq_data_get_irq_chip_data(data); - unsigned int reg = data->hwirq >> adnp->reg_shift; - unsigned int pos = data->hwirq & 7; + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct adnp *adnp = to_adnp(gc); + unsigned int reg = d->hwirq >> adnp->reg_shift; + unsigned int pos = d->hwirq & 7; adnp->irq_enable[reg] &= ~BIT(pos); } -static void adnp_irq_unmask(struct irq_data *data) +static void adnp_irq_unmask(struct irq_data *d) { - struct adnp *adnp = irq_data_get_irq_chip_data(data); - unsigned int reg = data->hwirq >> adnp->reg_shift; - unsigned int pos = data->hwirq & 7; + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct adnp *adnp = to_adnp(gc); + unsigned int reg = d->hwirq >> adnp->reg_shift; + unsigned int pos = d->hwirq & 7; adnp->irq_enable[reg] |= BIT(pos); } -static int adnp_irq_set_type(struct irq_data *data, unsigned int type) +static int adnp_irq_set_type(struct irq_data *d, unsigned int type) { - struct adnp *adnp = irq_data_get_irq_chip_data(data); - unsigned int reg = data->hwirq >> adnp->reg_shift; - unsigned int pos = data->hwirq & 7; + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct adnp *adnp = to_adnp(gc); + unsigned int reg = d->hwirq >> adnp->reg_shift; + unsigned int pos = d->hwirq & 7; if (type & IRQ_TYPE_EDGE_RISING) adnp->irq_rise[reg] |= BIT(pos); @@ -387,16 +387,18 @@ static int adnp_irq_set_type(struct irq_data *data, unsigned int type) return 0; } -static void adnp_irq_bus_lock(struct irq_data *data) +static void adnp_irq_bus_lock(struct irq_data *d) { - struct adnp *adnp = irq_data_get_irq_chip_data(data); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct adnp *adnp = to_adnp(gc); mutex_lock(&adnp->irq_lock); } -static void adnp_irq_bus_unlock(struct irq_data *data) +static void adnp_irq_bus_unlock(struct irq_data *d) { - struct adnp *adnp = irq_data_get_irq_chip_data(data); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct adnp *adnp = to_adnp(gc); unsigned int num_regs = 1 << adnp->reg_shift, i; mutex_lock(&adnp->i2c_lock); @@ -408,26 +410,6 @@ 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, @@ -435,29 +417,6 @@ 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, - irq_hw_number_t hwirq) -{ - irq_set_chip_data(irq, domain->host_data); - irq_set_chip(irq, &adnp_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 adnp_irq_domain_ops = { - .map = adnp_irq_map, - .xlate = irq_domain_xlate_twocell, }; static int adnp_irq_setup(struct adnp *adnp) @@ -503,35 +462,28 @@ static int adnp_irq_setup(struct adnp *adnp) adnp->irq_enable[i] = 0x00; } - adnp->domain = irq_domain_add_linear(chip->of_node, chip->ngpio, - &adnp_irq_domain_ops, adnp); - - err = request_threaded_irq(adnp->client->irq, NULL, adnp_irq, - IRQF_TRIGGER_RISING | IRQF_ONESHOT, - dev_name(chip->dev), adnp); + err = devm_request_threaded_irq(chip->dev, adnp->client->irq, + NULL, adnp_irq, + IRQF_TRIGGER_RISING | IRQF_ONESHOT, + dev_name(chip->dev), adnp); if (err != 0) { dev_err(chip->dev, "can't request IRQ#%d: %d\n", adnp->client->irq, err); return err; } - chip->to_irq = adnp_gpio_to_irq; - return 0; -} - -static void adnp_irq_teardown(struct adnp *adnp) -{ - unsigned int irq, i; - - free_irq(adnp->client->irq, adnp); - - for (i = 0; i < adnp->gpio.ngpio; i++) { - irq = irq_find_mapping(adnp->domain, i); - if (irq > 0) - irq_dispose_mapping(irq); + err = gpiochip_irqchip_add(chip, + &adnp_irq_chip, + 0, + handle_simple_irq, + IRQ_TYPE_NONE); + if (err) { + dev_err(chip->dev, + "could not connect irqchip to gpiochip\n"); + return err; } - irq_domain_remove(adnp->domain); + return 0; } static int adnp_i2c_probe(struct i2c_client *client, @@ -558,38 +510,25 @@ static int adnp_i2c_probe(struct i2c_client *client, adnp->client = client; err = adnp_gpio_setup(adnp, num_gpios); - if (err < 0) + if (err) return err; if (of_find_property(np, "interrupt-controller", NULL)) { err = adnp_irq_setup(adnp); - if (err < 0) - goto teardown; + if (err) + return err; } - err = gpiochip_add(&adnp->gpio); - if (err < 0) - goto teardown; - i2c_set_clientdata(client, adnp); - return 0; -teardown: - if (of_find_property(np, "interrupt-controller", NULL)) - adnp_irq_teardown(adnp); - - return err; + return 0; } static int adnp_i2c_remove(struct i2c_client *client) { struct adnp *adnp = i2c_get_clientdata(client); - struct device_node *np = client->dev.of_node; gpiochip_remove(&adnp->gpio); - if (of_find_property(np, "interrupt-controller", NULL)) - adnp_irq_teardown(adnp); - return 0; } diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c index 3f6b33c..de0801e 100644 --- a/drivers/gpio/gpio-bcm-kona.c +++ b/drivers/gpio/gpio-bcm-kona.c @@ -496,7 +496,7 @@ static struct irq_chip bcm_gpio_irq_chip = { .irq_release_resources = bcm_kona_gpio_irq_relres, }; -static struct __initconst of_device_id bcm_kona_gpio_of_match[] = { +static struct of_device_id const bcm_kona_gpio_of_match[] = { { .compatible = "brcm,kona-gpio" }, {} }; diff --git a/drivers/gpio/gpio-crystalcove.c b/drivers/gpio/gpio-crystalcove.c index 934462f..bbfe7f5 100644 --- a/drivers/gpio/gpio-crystalcove.c +++ b/drivers/gpio/gpio-crystalcove.c @@ -24,6 +24,7 @@ #include <linux/mfd/intel_soc_pmic.h> #define CRYSTALCOVE_GPIO_NUM 16 +#define CRYSTALCOVE_VGPIO_NUM 94 #define UPDATE_IRQ_TYPE BIT(0) #define UPDATE_IRQ_MASK BIT(1) @@ -130,6 +131,9 @@ static int crystalcove_gpio_dir_in(struct gpio_chip *chip, unsigned gpio) { struct crystalcove_gpio *cg = to_cg(chip); + if (gpio > CRYSTALCOVE_VGPIO_NUM) + return 0; + return regmap_write(cg->regmap, to_reg(gpio, CTRL_OUT), CTLO_INPUT_SET); } @@ -139,6 +143,9 @@ static int crystalcove_gpio_dir_out(struct gpio_chip *chip, unsigned gpio, { struct crystalcove_gpio *cg = to_cg(chip); + if (gpio > CRYSTALCOVE_VGPIO_NUM) + return 0; + return regmap_write(cg->regmap, to_reg(gpio, CTRL_OUT), CTLO_OUTPUT_SET | value); } @@ -149,6 +156,9 @@ static int crystalcove_gpio_get(struct gpio_chip *chip, unsigned gpio) int ret; unsigned int val; + if (gpio > CRYSTALCOVE_VGPIO_NUM) + return 0; + ret = regmap_read(cg->regmap, to_reg(gpio, CTRL_IN), &val); if (ret) return ret; @@ -161,6 +171,9 @@ static void crystalcove_gpio_set(struct gpio_chip *chip, { struct crystalcove_gpio *cg = to_cg(chip); + if (gpio > CRYSTALCOVE_VGPIO_NUM) + return; + if (value) regmap_update_bits(cg->regmap, to_reg(gpio, CTRL_OUT), 1, 1); else @@ -256,7 +269,7 @@ static irqreturn_t crystalcove_gpio_irq_handler(int irq, void *data) pending = p0 | p1 << 8; - for (gpio = 0; gpio < cg->chip.ngpio; gpio++) { + for (gpio = 0; gpio < CRYSTALCOVE_GPIO_NUM; gpio++) { if (pending & BIT(gpio)) { virq = irq_find_mapping(cg->chip.irqdomain, gpio); generic_handle_irq(virq); @@ -273,7 +286,7 @@ static void crystalcove_gpio_dbg_show(struct seq_file *s, int gpio, offset; unsigned int ctlo, ctli, mirqs0, mirqsx, irq; - for (gpio = 0; gpio < cg->chip.ngpio; gpio++) { + for (gpio = 0; gpio < CRYSTALCOVE_GPIO_NUM; gpio++) { regmap_read(cg->regmap, to_reg(gpio, CTRL_OUT), &ctlo); regmap_read(cg->regmap, to_reg(gpio, CTRL_IN), &ctli); regmap_read(cg->regmap, gpio < 8 ? MGPIO0IRQS0 : MGPIO1IRQS0, @@ -320,7 +333,7 @@ static int crystalcove_gpio_probe(struct platform_device *pdev) cg->chip.get = crystalcove_gpio_get; cg->chip.set = crystalcove_gpio_set; cg->chip.base = -1; - cg->chip.ngpio = CRYSTALCOVE_GPIO_NUM; + cg->chip.ngpio = CRYSTALCOVE_VGPIO_NUM; cg->chip.can_sleep = true; cg->chip.dev = dev; cg->chip.dbg_show = crystalcove_gpio_dbg_show; @@ -346,7 +359,7 @@ static int crystalcove_gpio_probe(struct platform_device *pdev) return 0; out_remove_gpio: - WARN_ON(gpiochip_remove(&cg->chip)); + gpiochip_remove(&cg->chip); return retval; } @@ -354,14 +367,11 @@ static int crystalcove_gpio_remove(struct platform_device *pdev) { struct crystalcove_gpio *cg = platform_get_drvdata(pdev); int irq = platform_get_irq(pdev, 0); - int err; - - err = gpiochip_remove(&cg->chip); + gpiochip_remove(&cg->chip); if (irq >= 0) free_irq(irq, cg); - - return err; + return 0; } static struct platform_driver crystalcove_gpio_driver = { diff --git a/drivers/gpio/gpio-cs5535.c b/drivers/gpio/gpio-cs5535.c index 92ec58f..668127f 100644 --- a/drivers/gpio/gpio-cs5535.c +++ b/drivers/gpio/gpio-cs5535.c @@ -201,7 +201,8 @@ EXPORT_SYMBOL_GPL(cs5535_gpio_setup_event); static int chip_gpio_request(struct gpio_chip *c, unsigned offset) { - struct cs5535_gpio_chip *chip = (struct cs5535_gpio_chip *) c; + struct cs5535_gpio_chip *chip = + container_of(c, struct cs5535_gpio_chip, chip); unsigned long flags; spin_lock_irqsave(&chip->lock, flags); @@ -241,7 +242,8 @@ static void chip_gpio_set(struct gpio_chip *chip, unsigned offset, int val) static int chip_direction_input(struct gpio_chip *c, unsigned offset) { - struct cs5535_gpio_chip *chip = (struct cs5535_gpio_chip *) c; + struct cs5535_gpio_chip *chip = + container_of(c, struct cs5535_gpio_chip, chip); unsigned long flags; spin_lock_irqsave(&chip->lock, flags); @@ -254,7 +256,8 @@ static int chip_direction_input(struct gpio_chip *c, unsigned offset) static int chip_direction_output(struct gpio_chip *c, unsigned offset, int val) { - struct cs5535_gpio_chip *chip = (struct cs5535_gpio_chip *) c; + struct cs5535_gpio_chip *chip = + container_of(c, struct cs5535_gpio_chip, chip); unsigned long flags; spin_lock_irqsave(&chip->lock, flags); diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index d6618a6..b43cd84 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -21,6 +21,8 @@ #include <linux/of_irq.h> #include <linux/platform_device.h> #include <linux/spinlock.h> +#include <linux/platform_data/gpio-dwapb.h> +#include <linux/slab.h> #define GPIO_SWPORTA_DR 0x00 #define GPIO_SWPORTA_DDR 0x04 @@ -35,6 +37,7 @@ #define GPIO_INTTYPE_LEVEL 0x38 #define GPIO_INT_POLARITY 0x3c #define GPIO_INTSTATUS 0x40 +#define GPIO_PORTA_DEBOUNCE 0x48 #define GPIO_PORTA_EOI 0x4c #define GPIO_EXT_PORTA 0x50 #define GPIO_EXT_PORTB 0x54 @@ -48,10 +51,28 @@ struct dwapb_gpio; +#ifdef CONFIG_PM_SLEEP +/* Store GPIO context across system-wide suspend/resume transitions */ +struct dwapb_context { + u32 data; + u32 dir; + u32 ext; + u32 int_en; + u32 int_mask; + u32 int_type; + u32 int_pol; + u32 int_deb; +}; +#endif + struct dwapb_gpio_port { struct bgpio_chip bgc; bool is_registered; struct dwapb_gpio *gpio; +#ifdef CONFIG_PM_SLEEP + struct dwapb_context *ctx; +#endif + unsigned int idx; }; struct dwapb_gpio { @@ -62,11 +83,33 @@ struct dwapb_gpio { struct irq_domain *domain; }; +static inline struct dwapb_gpio_port * +to_dwapb_gpio_port(struct bgpio_chip *bgc) +{ + return container_of(bgc, struct dwapb_gpio_port, bgc); +} + +static inline u32 dwapb_read(struct dwapb_gpio *gpio, unsigned int offset) +{ + struct bgpio_chip *bgc = &gpio->ports[0].bgc; + void __iomem *reg_base = gpio->regs; + + return bgc->read_reg(reg_base + offset); +} + +static inline void dwapb_write(struct dwapb_gpio *gpio, unsigned int offset, + u32 val) +{ + struct bgpio_chip *bgc = &gpio->ports[0].bgc; + void __iomem *reg_base = gpio->regs; + + bgc->write_reg(reg_base + offset, val); +} + 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_port *port = to_dwapb_gpio_port(bgc); struct dwapb_gpio *gpio = port->gpio; return irq_find_mapping(gpio->domain, offset); @@ -74,21 +117,20 @@ static int dwapb_gpio_to_irq(struct gpio_chip *gc, unsigned offset) static void dwapb_toggle_trigger(struct dwapb_gpio *gpio, unsigned int offs) { - u32 v = readl(gpio->regs + GPIO_INT_POLARITY); + u32 v = dwapb_read(gpio, 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); + dwapb_write(gpio, GPIO_INT_POLARITY, v); } -static void dwapb_irq_handler(u32 irq, struct irq_desc *desc) +static u32 dwapb_do_irq(struct dwapb_gpio *gpio) { - 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); + u32 ret = irq_status; while (irq_status) { int hwirq = fls(irq_status) - 1; @@ -102,6 +144,16 @@ static void dwapb_irq_handler(u32 irq, struct irq_desc *desc) dwapb_toggle_trigger(gpio, hwirq); } + return ret; +} + +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); + + dwapb_do_irq(gpio); + if (chip->irq_eoi) chip->irq_eoi(irq_desc_get_irq_data(desc)); } @@ -115,9 +167,9 @@ static void dwapb_irq_enable(struct irq_data *d) u32 val; spin_lock_irqsave(&bgc->lock, flags); - val = readl(gpio->regs + GPIO_INTEN); + val = dwapb_read(gpio, GPIO_INTEN); val |= BIT(d->hwirq); - writel(val, gpio->regs + GPIO_INTEN); + dwapb_write(gpio, GPIO_INTEN, val); spin_unlock_irqrestore(&bgc->lock, flags); } @@ -130,9 +182,9 @@ static void dwapb_irq_disable(struct irq_data *d) u32 val; spin_lock_irqsave(&bgc->lock, flags); - val = readl(gpio->regs + GPIO_INTEN); + val = dwapb_read(gpio, GPIO_INTEN); val &= ~BIT(d->hwirq); - writel(val, gpio->regs + GPIO_INTEN); + dwapb_write(gpio, GPIO_INTEN, val); spin_unlock_irqrestore(&bgc->lock, flags); } @@ -172,8 +224,8 @@ static int dwapb_irq_set_type(struct irq_data *d, u32 type) return -EINVAL; spin_lock_irqsave(&bgc->lock, flags); - level = readl(gpio->regs + GPIO_INTTYPE_LEVEL); - polarity = readl(gpio->regs + GPIO_INT_POLARITY); + level = dwapb_read(gpio, GPIO_INTTYPE_LEVEL); + polarity = dwapb_read(gpio, GPIO_INT_POLARITY); switch (type) { case IRQ_TYPE_EDGE_BOTH: @@ -200,29 +252,55 @@ static int dwapb_irq_set_type(struct irq_data *d, u32 type) irq_setup_alt_chip(d, type); - writel(level, gpio->regs + GPIO_INTTYPE_LEVEL); - writel(polarity, gpio->regs + GPIO_INT_POLARITY); + dwapb_write(gpio, GPIO_INTTYPE_LEVEL, level); + dwapb_write(gpio, GPIO_INT_POLARITY, polarity); + spin_unlock_irqrestore(&bgc->lock, flags); + + return 0; +} + +static int dwapb_gpio_set_debounce(struct gpio_chip *gc, + unsigned offset, unsigned debounce) +{ + struct bgpio_chip *bgc = to_bgpio_chip(gc); + struct dwapb_gpio_port *port = to_dwapb_gpio_port(bgc); + struct dwapb_gpio *gpio = port->gpio; + unsigned long flags, val_deb; + unsigned long mask = bgc->pin2mask(bgc, offset); + + spin_lock_irqsave(&bgc->lock, flags); + + val_deb = dwapb_read(gpio, GPIO_PORTA_DEBOUNCE); + if (debounce) + dwapb_write(gpio, GPIO_PORTA_DEBOUNCE, val_deb | mask); + else + dwapb_write(gpio, GPIO_PORTA_DEBOUNCE, val_deb & ~mask); + spin_unlock_irqrestore(&bgc->lock, flags); return 0; } +static irqreturn_t dwapb_irq_handler_mfd(int irq, void *dev_id) +{ + u32 worked; + struct dwapb_gpio *gpio = dev_id; + + worked = dwapb_do_irq(gpio); + + return worked ? IRQ_HANDLED : IRQ_NONE; +} + static void dwapb_configure_irqs(struct dwapb_gpio *gpio, - struct dwapb_gpio_port *port) + struct dwapb_gpio_port *port, + struct dwapb_port_property *pp) { struct gpio_chip *gc = &port->bgc.gc; - struct device_node *node = gc->of_node; - struct irq_chip_generic *irq_gc; + struct device_node *node = pp->node; + struct irq_chip_generic *irq_gc = NULL; 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; - } + int err, i; gpio->domain = irq_domain_add_linear(node, ngpio, &irq_generic_chip_ops, gpio); @@ -269,8 +347,24 @@ static void dwapb_configure_irqs(struct dwapb_gpio *gpio, 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); + if (!pp->irq_shared) { + irq_set_chained_handler(pp->irq, dwapb_irq_handler); + irq_set_handler_data(pp->irq, gpio); + } else { + /* + * Request a shared IRQ since where MFD would have devices + * using the same irq pin + */ + err = devm_request_irq(gpio->dev, pp->irq, + dwapb_irq_handler_mfd, + IRQF_SHARED, "gpio-dwapb-mfd", gpio); + if (err) { + dev_err(gpio->dev, "error requesting IRQ\n"); + irq_domain_remove(gpio->domain); + gpio->domain = NULL; + return; + } + } for (hwirq = 0 ; hwirq < ngpio ; hwirq++) irq_create_mapping(gpio->domain, hwirq); @@ -296,57 +390,53 @@ static void dwapb_irq_teardown(struct dwapb_gpio *gpio) } static int dwapb_gpio_add_port(struct dwapb_gpio *gpio, - struct device_node *port_np, + struct dwapb_port_property *pp, 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; + port->idx = pp->idx; - 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; - } +#ifdef CONFIG_PM_SLEEP + port->ctx = devm_kzalloc(gpio->dev, sizeof(*port->ctx), GFP_KERNEL); + if (!port->ctx) + return -ENOMEM; +#endif - dat = gpio->regs + GPIO_EXT_PORTA + (port_idx * GPIO_EXT_PORT_SIZE); - set = gpio->regs + GPIO_SWPORTA_DR + (port_idx * GPIO_SWPORT_DR_SIZE); + dat = gpio->regs + GPIO_EXT_PORTA + (pp->idx * GPIO_EXT_PORT_SIZE); + set = gpio->regs + GPIO_SWPORTA_DR + (pp->idx * GPIO_SWPORT_DR_SIZE); dirout = gpio->regs + GPIO_SWPORTA_DDR + - (port_idx * GPIO_SWPORT_DDR_SIZE); + (pp->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); + pp->name); return err; } - port->bgc.gc.ngpio = ngpio; - port->bgc.gc.of_node = port_np; +#ifdef CONFIG_OF_GPIO + port->bgc.gc.of_node = pp->node; +#endif + port->bgc.gc.ngpio = pp->ngpio; + port->bgc.gc.base = pp->gpio_base; - /* - * 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); + /* Only port A support debounce */ + if (pp->idx == 0) + port->bgc.gc.set_debounce = dwapb_gpio_set_debounce; + + if (pp->irq) + dwapb_configure_irqs(gpio, port, pp); err = gpiochip_add(&port->bgc.gc); if (err) dev_err(gpio->dev, "failed to register gpiochip for %s\n", - port_np->full_name); + pp->name); else port->is_registered = true; @@ -362,25 +452,116 @@ static void dwapb_gpio_unregister(struct dwapb_gpio *gpio) gpiochip_remove(&gpio->ports[m].bgc.gc); } +static struct dwapb_platform_data * +dwapb_gpio_get_pdata_of(struct device *dev) +{ + struct device_node *node, *port_np; + struct dwapb_platform_data *pdata; + struct dwapb_port_property *pp; + int nports; + int i; + + node = dev->of_node; + if (!IS_ENABLED(CONFIG_OF_GPIO) || !node) + return ERR_PTR(-ENODEV); + + nports = of_get_child_count(node); + if (nports == 0) + return ERR_PTR(-ENODEV); + + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return ERR_PTR(-ENOMEM); + + pdata->properties = kcalloc(nports, sizeof(*pp), GFP_KERNEL); + if (!pdata->properties) { + kfree(pdata); + return ERR_PTR(-ENOMEM); + } + + pdata->nports = nports; + + i = 0; + for_each_child_of_node(node, port_np) { + pp = &pdata->properties[i++]; + pp->node = port_np; + + if (of_property_read_u32(port_np, "reg", &pp->idx) || + pp->idx >= DWAPB_MAX_PORTS) { + dev_err(dev, "missing/invalid port index for %s\n", + port_np->full_name); + kfree(pdata->properties); + kfree(pdata); + return ERR_PTR(-EINVAL); + } + + if (of_property_read_u32(port_np, "snps,nr-gpios", + &pp->ngpio)) { + dev_info(dev, "failed to get number of gpios for %s\n", + port_np->full_name); + pp->ngpio = 32; + } + + /* + * Only port A can provide interrupts in all configurations of + * the IP. + */ + if (pp->idx == 0 && + of_property_read_bool(port_np, "interrupt-controller")) { + pp->irq = irq_of_parse_and_map(port_np, 0); + if (!pp->irq) { + dev_warn(dev, "no irq for bank %s\n", + port_np->full_name); + } + } + + pp->irq_shared = false; + pp->gpio_base = -1; + pp->name = port_np->full_name; + } + + return pdata; +} + +static inline void dwapb_free_pdata_of(struct dwapb_platform_data *pdata) +{ + if (!IS_ENABLED(CONFIG_OF_GPIO) || !pdata) + return; + + kfree(pdata->properties); + kfree(pdata); +} + static int dwapb_gpio_probe(struct platform_device *pdev) { + unsigned int i; struct resource *res; struct dwapb_gpio *gpio; - struct device_node *np; int err; - unsigned int offs = 0; + struct device *dev = &pdev->dev; + struct dwapb_platform_data *pdata = dev_get_platdata(dev); + bool is_pdata_alloc = !pdata; + + if (is_pdata_alloc) { + pdata = dwapb_gpio_get_pdata_of(dev); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); + } - gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); - if (!gpio) - return -ENOMEM; - gpio->dev = &pdev->dev; + if (!pdata->nports) { + err = -ENODEV; + goto out_err; + } - gpio->nr_ports = of_get_child_count(pdev->dev.of_node); - if (!gpio->nr_ports) { - err = -EINVAL; + gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); + if (!gpio) { + err = -ENOMEM; goto out_err; } - gpio->ports = devm_kzalloc(&pdev->dev, gpio->nr_ports * + gpio->dev = &pdev->dev; + gpio->nr_ports = pdata->nports; + + gpio->ports = devm_kcalloc(&pdev->dev, gpio->nr_ports, sizeof(*gpio->ports), GFP_KERNEL); if (!gpio->ports) { err = -ENOMEM; @@ -394,20 +575,23 @@ static int dwapb_gpio_probe(struct platform_device *pdev) goto out_err; } - for_each_child_of_node(pdev->dev.of_node, np) { - err = dwapb_gpio_add_port(gpio, np, offs++); + for (i = 0; i < gpio->nr_ports; i++) { + err = dwapb_gpio_add_port(gpio, &pdata->properties[i], i); if (err) goto out_unregister; } platform_set_drvdata(pdev, gpio); - return 0; + goto out_err; out_unregister: dwapb_gpio_unregister(gpio); dwapb_irq_teardown(gpio); out_err: + if (is_pdata_alloc) + dwapb_free_pdata_of(pdata); + return err; } @@ -427,10 +611,100 @@ static const struct of_device_id dwapb_of_match[] = { }; MODULE_DEVICE_TABLE(of, dwapb_of_match); +#ifdef CONFIG_PM_SLEEP +static int dwapb_gpio_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct dwapb_gpio *gpio = platform_get_drvdata(pdev); + struct bgpio_chip *bgc = &gpio->ports[0].bgc; + unsigned long flags; + int i; + + spin_lock_irqsave(&bgc->lock, flags); + for (i = 0; i < gpio->nr_ports; i++) { + unsigned int offset; + unsigned int idx = gpio->ports[i].idx; + struct dwapb_context *ctx = gpio->ports[i].ctx; + + BUG_ON(!ctx); + + offset = GPIO_SWPORTA_DDR + idx * GPIO_SWPORT_DDR_SIZE; + ctx->dir = dwapb_read(gpio, offset); + + offset = GPIO_SWPORTA_DR + idx * GPIO_SWPORT_DR_SIZE; + ctx->data = dwapb_read(gpio, offset); + + offset = GPIO_EXT_PORTA + idx * GPIO_EXT_PORT_SIZE; + ctx->ext = dwapb_read(gpio, offset); + + /* Only port A can provide interrupts */ + if (idx == 0) { + ctx->int_mask = dwapb_read(gpio, GPIO_INTMASK); + ctx->int_en = dwapb_read(gpio, GPIO_INTEN); + ctx->int_pol = dwapb_read(gpio, GPIO_INT_POLARITY); + ctx->int_type = dwapb_read(gpio, GPIO_INTTYPE_LEVEL); + ctx->int_deb = dwapb_read(gpio, GPIO_PORTA_DEBOUNCE); + + /* Mask out interrupts */ + dwapb_write(gpio, GPIO_INTMASK, 0xffffffff); + } + } + spin_unlock_irqrestore(&bgc->lock, flags); + + return 0; +} + +static int dwapb_gpio_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct dwapb_gpio *gpio = platform_get_drvdata(pdev); + struct bgpio_chip *bgc = &gpio->ports[0].bgc; + unsigned long flags; + int i; + + spin_lock_irqsave(&bgc->lock, flags); + for (i = 0; i < gpio->nr_ports; i++) { + unsigned int offset; + unsigned int idx = gpio->ports[i].idx; + struct dwapb_context *ctx = gpio->ports[i].ctx; + + BUG_ON(!ctx); + + offset = GPIO_SWPORTA_DR + idx * GPIO_SWPORT_DR_SIZE; + dwapb_write(gpio, offset, ctx->data); + + offset = GPIO_SWPORTA_DDR + idx * GPIO_SWPORT_DDR_SIZE; + dwapb_write(gpio, offset, ctx->dir); + + offset = GPIO_EXT_PORTA + idx * GPIO_EXT_PORT_SIZE; + dwapb_write(gpio, offset, ctx->ext); + + /* Only port A can provide interrupts */ + if (idx == 0) { + dwapb_write(gpio, GPIO_INTTYPE_LEVEL, ctx->int_type); + dwapb_write(gpio, GPIO_INT_POLARITY, ctx->int_pol); + dwapb_write(gpio, GPIO_PORTA_DEBOUNCE, ctx->int_deb); + dwapb_write(gpio, GPIO_INTEN, ctx->int_en); + dwapb_write(gpio, GPIO_INTMASK, ctx->int_mask); + + /* Clear out spurious interrupts */ + dwapb_write(gpio, GPIO_PORTA_EOI, 0xffffffff); + } + } + spin_unlock_irqrestore(&bgc->lock, flags); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(dwapb_gpio_pm_ops, dwapb_gpio_suspend, + dwapb_gpio_resume); + static struct platform_driver dwapb_gpio_driver = { .driver = { .name = "gpio-dwapb", .owner = THIS_MODULE, + .pm = &dwapb_gpio_pm_ops, .of_match_table = of_match_ptr(dwapb_of_match), }, .probe = dwapb_gpio_probe, diff --git a/drivers/gpio/gpio-ks8695.c b/drivers/gpio/gpio-ks8695.c index 464a83d..cc09b23 100644 --- a/drivers/gpio/gpio-ks8695.c +++ b/drivers/gpio/gpio-ks8695.c @@ -265,29 +265,27 @@ static int ks8695_gpio_show(struct seq_file *s, void *unused) seq_printf(s, "EXT%i ", i); switch ((ctrl & intmask[i]) >> (4 * i)) { - case IOPC_TM_LOW: - seq_printf(s, "(Low)"); break; - case IOPC_TM_HIGH: - seq_printf(s, "(High)"); break; - case IOPC_TM_RISING: - seq_printf(s, "(Rising)"); break; - case IOPC_TM_FALLING: - seq_printf(s, "(Falling)"); break; - case IOPC_TM_EDGE: - seq_printf(s, "(Edges)"); break; + case IOPC_TM_LOW: + seq_printf(s, "(Low)"); break; + case IOPC_TM_HIGH: + seq_printf(s, "(High)"); break; + case IOPC_TM_RISING: + seq_printf(s, "(Rising)"); break; + case IOPC_TM_FALLING: + seq_printf(s, "(Falling)"); break; + case IOPC_TM_EDGE: + seq_printf(s, "(Edges)"); break; } - } - else + } else seq_printf(s, "GPIO\t"); - } - else if (i <= KS8695_GPIO_5) { + } else if (i <= KS8695_GPIO_5) { if (ctrl & enable[i]) seq_printf(s, "TOUT%i\t", i - KS8695_GPIO_4); else seq_printf(s, "GPIO\t"); - } - else + } else { seq_printf(s, "GPIO\t"); + } seq_printf(s, "\t"); diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c index 6f183d9..8488e2f 100644 --- a/drivers/gpio/gpio-mcp23s08.c +++ b/drivers/gpio/gpio-mcp23s08.c @@ -479,7 +479,7 @@ static int mcp23s08_irq_setup(struct mcp23s08 *mcp) mutex_init(&mcp->irq_lock); - mcp->irq_domain = irq_domain_add_linear(chip->of_node, chip->ngpio, + mcp->irq_domain = irq_domain_add_linear(chip->dev->of_node, chip->ngpio, &irq_domain_simple_ops, mcp); if (!mcp->irq_domain) return -ENODEV; @@ -581,7 +581,7 @@ done: static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, void *data, unsigned addr, unsigned type, - unsigned base, unsigned pullups) + struct mcp23s08_platform_data *pdata, int cs) { int status; bool mirror = false; @@ -635,7 +635,7 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, return -EINVAL; } - mcp->chip.base = base; + mcp->chip.base = pdata->base; mcp->chip.can_sleep = true; mcp->chip.dev = dev; mcp->chip.owner = THIS_MODULE; @@ -648,11 +648,9 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, if (status < 0) goto fail; - mcp->irq_controller = of_property_read_bool(mcp->chip.of_node, - "interrupt-controller"); + mcp->irq_controller = pdata->irq_controller; if (mcp->irq && mcp->irq_controller && (type == MCP_TYPE_017)) - mirror = of_property_read_bool(mcp->chip.of_node, - "microchip,irq-mirror"); + mirror = pdata->mirror; if ((status & IOCON_SEQOP) || !(status & IOCON_HAEN) || mirror) { /* mcp23s17 has IOCON twice, make sure they are in sync */ @@ -668,7 +666,7 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, } /* configure ~100K pullups */ - status = mcp->ops->write(mcp, MCP_GPPU, pullups); + status = mcp->ops->write(mcp, MCP_GPPU, pdata->chip[cs].pullups); if (status < 0) goto fail; @@ -768,25 +766,29 @@ MODULE_DEVICE_TABLE(of, mcp23s08_i2c_of_match); static int mcp230xx_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct mcp23s08_platform_data *pdata; + struct mcp23s08_platform_data *pdata, local_pdata; struct mcp23s08 *mcp; - int status, base, pullups; + int status; const struct of_device_id *match; match = of_match_device(of_match_ptr(mcp23s08_i2c_of_match), &client->dev); - pdata = dev_get_platdata(&client->dev); - if (match || !pdata) { - base = -1; - pullups = 0; + if (match) { + pdata = &local_pdata; + pdata->base = -1; + pdata->chip[0].pullups = 0; + pdata->irq_controller = of_property_read_bool( + client->dev.of_node, + "interrupt-controller"); + pdata->mirror = of_property_read_bool(client->dev.of_node, + "microchip,irq-mirror"); client->irq = irq_of_parse_and_map(client->dev.of_node, 0); } else { - if (!gpio_is_valid(pdata->base)) { + pdata = dev_get_platdata(&client->dev); + if (!pdata || !gpio_is_valid(pdata->base)) { dev_dbg(&client->dev, "invalid platform data\n"); return -EINVAL; } - base = pdata->base; - pullups = pdata->chip[0].pullups; } mcp = kzalloc(sizeof(*mcp), GFP_KERNEL); @@ -795,7 +797,7 @@ static int mcp230xx_probe(struct i2c_client *client, mcp->irq = client->irq; status = mcp23s08_probe_one(mcp, &client->dev, client, client->addr, - id->driver_data, base, pullups); + id->driver_data, pdata, 0); if (status) goto fail; @@ -863,14 +865,12 @@ static void mcp23s08_i2c_exit(void) { } static int mcp23s08_probe(struct spi_device *spi) { - struct mcp23s08_platform_data *pdata; + struct mcp23s08_platform_data *pdata, local_pdata; unsigned addr; int chips = 0; struct mcp23s08_driver_data *data; int status, type; - unsigned base = -1, - ngpio = 0, - pullups[ARRAY_SIZE(pdata->chip)]; + unsigned ngpio = 0; const struct of_device_id *match; u32 spi_present_mask = 0; @@ -893,11 +893,18 @@ static int mcp23s08_probe(struct spi_device *spi) return -ENODEV; } + pdata = &local_pdata; + pdata->base = -1; for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) { - pullups[addr] = 0; + pdata->chip[addr].pullups = 0; if (spi_present_mask & (1 << addr)) chips++; } + pdata->irq_controller = of_property_read_bool( + spi->dev.of_node, + "interrupt-controller"); + pdata->mirror = of_property_read_bool(spi->dev.of_node, + "microchip,irq-mirror"); } else { type = spi_get_device_id(spi)->driver_data; pdata = dev_get_platdata(&spi->dev); @@ -917,10 +924,7 @@ static int mcp23s08_probe(struct spi_device *spi) return -EINVAL; } spi_present_mask |= 1 << addr; - pullups[addr] = pdata->chip[addr].pullups; } - - base = pdata->base; } if (!chips) @@ -938,13 +942,13 @@ static int mcp23s08_probe(struct spi_device *spi) chips--; data->mcp[addr] = &data->chip[chips]; status = mcp23s08_probe_one(data->mcp[addr], &spi->dev, spi, - 0x40 | (addr << 1), type, base, - pullups[addr]); + 0x40 | (addr << 1), type, pdata, + addr); if (status < 0) goto fail; - if (base != -1) - base += (type == MCP_TYPE_S17) ? 16 : 8; + if (pdata->base != -1) + pdata->base += (type == MCP_TYPE_S17) ? 16 : 8; ngpio += (type == MCP_TYPE_S17) ? 16 : 8; } data->ngpio = ngpio; diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 1749321..415682f 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -857,16 +857,6 @@ static void omap_gpio_unmask_irq(struct irq_data *d) spin_unlock_irqrestore(&bank->lock, flags); } -static struct irq_chip gpio_irq_chip = { - .name = "GPIO", - .irq_shutdown = omap_gpio_irq_shutdown, - .irq_ack = omap_gpio_ack_irq, - .irq_mask = omap_gpio_mask_irq, - .irq_unmask = omap_gpio_unmask_irq, - .irq_set_type = omap_gpio_irq_type, - .irq_set_wake = omap_gpio_wake_enable, -}; - /*---------------------------------------------------------------------*/ static int omap_mpuio_suspend_noirq(struct device *dev) @@ -1088,7 +1078,7 @@ omap_mpuio_alloc_gc(struct gpio_bank *bank, unsigned int irq_start, IRQ_NOREQUEST | IRQ_NOPROBE, 0); } -static int omap_gpio_chip_init(struct gpio_bank *bank) +static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc) { int j; static int gpio; @@ -1137,17 +1127,17 @@ static int omap_gpio_chip_init(struct gpio_bank *bank) } #endif - ret = gpiochip_irqchip_add(&bank->chip, &gpio_irq_chip, + ret = gpiochip_irqchip_add(&bank->chip, irqc, irq_base, omap_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); + gpiochip_remove(&bank->chip); return -ENODEV; } - gpiochip_set_chained_irqchip(&bank->chip, &gpio_irq_chip, + gpiochip_set_chained_irqchip(&bank->chip, irqc, bank->irq, omap_gpio_irq_handler); for (j = 0; j < bank->width; j++) { @@ -1172,6 +1162,7 @@ static int omap_gpio_probe(struct platform_device *pdev) const struct omap_gpio_platform_data *pdata; struct resource *res; struct gpio_bank *bank; + struct irq_chip *irqc; int ret; match = of_match_device(of_match_ptr(omap_gpio_match), dev); @@ -1186,6 +1177,18 @@ static int omap_gpio_probe(struct platform_device *pdev) return -ENOMEM; } + irqc = devm_kzalloc(dev, sizeof(*irqc), GFP_KERNEL); + if (!irqc) + return -ENOMEM; + + irqc->irq_shutdown = omap_gpio_irq_shutdown, + irqc->irq_ack = omap_gpio_ack_irq, + irqc->irq_mask = omap_gpio_mask_irq, + irqc->irq_unmask = omap_gpio_unmask_irq, + irqc->irq_set_type = omap_gpio_irq_type, + irqc->irq_set_wake = omap_gpio_wake_enable, + irqc->name = dev_name(&pdev->dev); + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (unlikely(!res)) { dev_err(dev, "Invalid IRQ resource\n"); @@ -1241,7 +1244,7 @@ static int omap_gpio_probe(struct platform_device *pdev) omap_gpio_mod_init(bank); - ret = omap_gpio_chip_init(bank); + ret = omap_gpio_chip_init(bank, irqc); if (ret) return ret; diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index f9961ee..e2da64a 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -520,7 +520,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, struct i2c_client *client = chip->client; int ret, i, offset = 0; - if (irq_base != -1 + if (client->irq && irq_base != -1 && (id->driver_data & PCA_INT)) { switch (chip->chip_type) { @@ -586,50 +586,6 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, } #endif -/* - * Handlers for alternative sources of platform_data - */ -#ifdef CONFIG_OF_GPIO -/* - * Translate OpenFirmware node properties into platform_data - * WARNING: This is DEPRECATED and will be removed eventually! - */ -static void -pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, u32 *invert) -{ - struct device_node *node; - const __be32 *val; - int size; - - *gpio_base = -1; - - node = client->dev.of_node; - if (node == NULL) - return; - - val = of_get_property(node, "linux,gpio-base", &size); - WARN(val, "%s: device-tree property 'linux,gpio-base' is deprecated!", __func__); - if (val) { - if (size != sizeof(*val)) - dev_warn(&client->dev, "%s: wrong linux,gpio-base\n", - node->full_name); - else - *gpio_base = be32_to_cpup(val); - } - - val = of_get_property(node, "polarity", NULL); - WARN(val, "%s: device-tree property 'polarity' is deprecated!", __func__); - if (val) - *invert = *val; -} -#else -static void -pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, u32 *invert) -{ - *gpio_base = -1; -} -#endif - static int device_pca953x_init(struct pca953x_chip *chip, u32 invert) { int ret; @@ -704,12 +660,8 @@ static int pca953x_probe(struct i2c_client *client, invert = pdata->invert; chip->names = pdata->names; } else { - pca953x_get_alt_pdata(client, &chip->gpio_start, &invert); -#ifdef CONFIG_OF_GPIO - /* If I2C node has no interrupts property, disable GPIO interrupts */ - if (of_find_property(client->dev.of_node, "interrupts", NULL) == NULL) - irq_base = -1; -#endif + chip->gpio_start = -1; + irq_base = 0; } chip->client = client; diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c index e0ac549..2d9a950 100644 --- a/drivers/gpio/gpio-pch.c +++ b/drivers/gpio/gpio-pch.c @@ -171,6 +171,7 @@ static int pch_gpio_direction_input(struct gpio_chip *gpio, unsigned nr) return 0; } +#ifdef CONFIG_PM /* * Save register configuration and disable interrupts. */ @@ -206,6 +207,7 @@ static void pch_gpio_restore_reg_conf(struct pch_gpio *chip) iowrite32(chip->pch_gpio_reg.gpio_use_sel_reg, &chip->reg->gpio_use_sel); } +#endif static int pch_gpio_to_irq(struct gpio_chip *gpio, unsigned offset) { diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c index 3810da4..7c288ba 100644 --- a/drivers/gpio/gpio-samsung.c +++ b/drivers/gpio/gpio-samsung.c @@ -1309,56 +1309,6 @@ samsung_gpio_pull_t s3c_gpio_getpull(unsigned int pin) } EXPORT_SYMBOL(s3c_gpio_getpull); -#ifdef CONFIG_S5P_GPIO_DRVSTR -s5p_gpio_drvstr_t s5p_gpio_get_drvstr(unsigned int pin) -{ - struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin); - unsigned int off; - void __iomem *reg; - int shift; - u32 drvstr; - - if (!chip) - return -EINVAL; - - off = pin - chip->chip.base; - shift = off * 2; - reg = chip->base + 0x0C; - - drvstr = __raw_readl(reg); - drvstr = drvstr >> shift; - drvstr &= 0x3; - - return (__force s5p_gpio_drvstr_t)drvstr; -} -EXPORT_SYMBOL(s5p_gpio_get_drvstr); - -int s5p_gpio_set_drvstr(unsigned int pin, s5p_gpio_drvstr_t drvstr) -{ - struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin); - unsigned int off; - void __iomem *reg; - int shift; - u32 tmp; - - if (!chip) - return -EINVAL; - - off = pin - chip->chip.base; - shift = off * 2; - reg = chip->base + 0x0C; - - tmp = __raw_readl(reg); - tmp &= ~(0x3 << shift); - tmp |= drvstr << shift; - - __raw_writel(tmp, reg); - - return 0; -} -EXPORT_SYMBOL(s5p_gpio_set_drvstr); -#endif /* CONFIG_S5P_GPIO_DRVSTR */ - #ifdef CONFIG_PLAT_S3C24XX unsigned int s3c2410_modify_misccr(unsigned int clear, unsigned int change) { diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index 845025a..85c5b19 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -13,6 +13,7 @@ #include <linux/interrupt.h> #include <linux/of.h> #include <linux/mfd/stmpe.h> +#include <linux/seq_file.h> /* * These registers are modified under the irq bus lock and cached to avoid @@ -127,19 +128,19 @@ static int stmpe_gpio_irq_set_type(struct irq_data *d, unsigned int type) int regoffset = offset / 8; int mask = 1 << (offset % 8); - if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_LEVEL_HIGH) + if (type & IRQ_TYPE_LEVEL_LOW || type & IRQ_TYPE_LEVEL_HIGH) return -EINVAL; /* STMPE801 doesn't have RE and FE registers */ if (stmpe_gpio->stmpe->partnum == STMPE801) return 0; - if (type == IRQ_TYPE_EDGE_RISING) + if (type & IRQ_TYPE_EDGE_RISING) stmpe_gpio->regs[REG_RE][regoffset] |= mask; else stmpe_gpio->regs[REG_RE][regoffset] &= ~mask; - if (type == IRQ_TYPE_EDGE_FALLING) + if (type & IRQ_TYPE_EDGE_FALLING) stmpe_gpio->regs[REG_FE][regoffset] |= mask; else stmpe_gpio->regs[REG_FE][regoffset] &= ~mask; @@ -211,6 +212,77 @@ static void stmpe_gpio_irq_unmask(struct irq_data *d) stmpe_gpio->regs[REG_IE][regoffset] |= mask; } +static void stmpe_dbg_show_one(struct seq_file *s, + struct gpio_chip *gc, + unsigned offset, unsigned gpio) +{ + struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(gc); + struct stmpe *stmpe = stmpe_gpio->stmpe; + const char *label = gpiochip_is_requested(gc, offset); + int num_banks = DIV_ROUND_UP(stmpe->num_gpios, 8); + bool val = !!stmpe_gpio_get(gc, offset); + u8 dir_reg = stmpe->regs[STMPE_IDX_GPDR_LSB] - (offset / 8); + u8 mask = 1 << (offset % 8); + int ret; + u8 dir; + + ret = stmpe_reg_read(stmpe, dir_reg); + if (ret < 0) + return; + dir = !!(ret & mask); + + if (dir) { + seq_printf(s, " gpio-%-3d (%-20.20s) out %s", + gpio, label ?: "(none)", + val ? "hi" : "lo"); + } else { + u8 edge_det_reg = stmpe->regs[STMPE_IDX_GPEDR_MSB] + num_banks - 1 - (offset / 8); + u8 rise_reg = stmpe->regs[STMPE_IDX_GPRER_LSB] - (offset / 8); + u8 fall_reg = stmpe->regs[STMPE_IDX_GPFER_LSB] - (offset / 8); + u8 irqen_reg = stmpe->regs[STMPE_IDX_IEGPIOR_LSB] - (offset / 8); + bool edge_det; + bool rise; + bool fall; + bool irqen; + + ret = stmpe_reg_read(stmpe, edge_det_reg); + if (ret < 0) + return; + edge_det = !!(ret & mask); + ret = stmpe_reg_read(stmpe, rise_reg); + if (ret < 0) + return; + rise = !!(ret & mask); + ret = stmpe_reg_read(stmpe, fall_reg); + if (ret < 0) + return; + fall = !!(ret & mask); + ret = stmpe_reg_read(stmpe, irqen_reg); + if (ret < 0) + return; + irqen = !!(ret & mask); + + seq_printf(s, " gpio-%-3d (%-20.20s) in %s %s %s%s%s", + gpio, label ?: "(none)", + val ? "hi" : "lo", + edge_det ? "edge-asserted" : "edge-inactive", + irqen ? "IRQ-enabled" : "", + rise ? " rising-edge-detection" : "", + fall ? " falling-edge-detection" : ""); + } +} + +static void stmpe_dbg_show(struct seq_file *s, struct gpio_chip *gc) +{ + unsigned i; + unsigned gpio = gc->base; + + for (i = 0; i < gc->ngpio; i++, gpio++) { + stmpe_dbg_show_one(s, gc, i, gpio); + seq_printf(s, "\n"); + } +} + static struct irq_chip stmpe_gpio_irq_chip = { .name = "stmpe-gpio", .irq_bus_lock = stmpe_gpio_irq_lock, @@ -293,6 +365,9 @@ static int stmpe_gpio_probe(struct platform_device *pdev) #endif stmpe_gpio->chip.base = -1; + if (IS_ENABLED(CONFIG_DEBUG_FS)) + stmpe_gpio->chip.dbg_show = stmpe_dbg_show; + if (pdata) stmpe_gpio->norequest_mask = pdata->norequest_mask; else if (np) @@ -308,6 +383,12 @@ static int stmpe_gpio_probe(struct platform_device *pdev) if (ret) goto out_free; + ret = gpiochip_add(&stmpe_gpio->chip); + if (ret) { + dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret); + goto out_disable; + } + if (irq > 0) { ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, stmpe_gpio_irq, IRQF_ONESHOT, @@ -324,14 +405,13 @@ static int stmpe_gpio_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "could not connect irqchip to gpiochip\n"); - return ret; + goto out_disable; } - } - ret = gpiochip_add(&stmpe_gpio->chip); - if (ret) { - dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret); - goto out_disable; + gpiochip_set_chained_irqchip(&stmpe_gpio->chip, + &stmpe_gpio_irq_chip, + irq, + NULL); } if (pdata && pdata->setup) @@ -343,6 +423,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev) out_disable: stmpe_disable(stmpe, STMPE_BLOCK_GPIO); + gpiochip_remove(&stmpe_gpio->chip); out_free: kfree(stmpe_gpio); return ret; diff --git a/drivers/gpio/gpio-stp-xway.c b/drivers/gpio/gpio-stp-xway.c index 04882a9..7e359b7 100644 --- a/drivers/gpio/gpio-stp-xway.c +++ b/drivers/gpio/gpio-stp-xway.c @@ -292,7 +292,7 @@ static struct platform_driver xway_stp_driver = { }, }; -int __init xway_stp_init(void) +static int __init xway_stp_init(void) { return platform_driver_register(&xway_stp_driver); } diff --git a/drivers/gpio/gpio-syscon.c b/drivers/gpio/gpio-syscon.c index 30884fb..e82fde4 100644 --- a/drivers/gpio/gpio-syscon.c +++ b/drivers/gpio/gpio-syscon.c @@ -37,6 +37,8 @@ * 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). + * set: HW specific callback to assigns output value + * for signal "offset" */ struct syscon_gpio_data { @@ -45,12 +47,16 @@ struct syscon_gpio_data { unsigned int bit_count; unsigned int dat_bit_offset; unsigned int dir_bit_offset; + void (*set)(struct gpio_chip *chip, + unsigned offset, int value); }; struct syscon_gpio_priv { struct gpio_chip chip; struct regmap *syscon; const struct syscon_gpio_data *data; + u32 dreg_offset; + u32 dir_reg_offset; }; static inline struct syscon_gpio_priv *to_syscon_gpio(struct gpio_chip *chip) @@ -61,9 +67,11 @@ static inline struct syscon_gpio_priv *to_syscon_gpio(struct gpio_chip *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; + unsigned int val, offs; int ret; + offs = priv->dreg_offset + priv->data->dat_bit_offset + offset; + ret = regmap_read(priv->syscon, (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, &val); if (ret) @@ -75,7 +83,9 @@ static int syscon_gpio_get(struct gpio_chip *chip, unsigned offset) 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; + unsigned int offs; + + offs = priv->dreg_offset + priv->data->dat_bit_offset + offset; regmap_update_bits(priv->syscon, (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, @@ -88,7 +98,10 @@ 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; + unsigned int offs; + + offs = priv->dir_reg_offset + + priv->data->dir_bit_offset + offset; regmap_update_bits(priv->syscon, (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, @@ -103,7 +116,10 @@ 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; + unsigned int offs; + + offs = priv->dir_reg_offset + + priv->data->dir_bit_offset + offset; regmap_update_bits(priv->syscon, (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, @@ -111,7 +127,7 @@ static int syscon_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int val) BIT(offs % SYSCON_REG_BITS)); } - syscon_gpio_set(chip, offset, val); + priv->data->set(chip, offset, val); return 0; } @@ -124,11 +140,46 @@ static const struct syscon_gpio_data clps711x_mctrl_gpio = { .dat_bit_offset = 0x40 * 8 + 8, }; +#define KEYSTONE_LOCK_BIT BIT(0) + +static void keystone_gpio_set(struct gpio_chip *chip, unsigned offset, int val) +{ + struct syscon_gpio_priv *priv = to_syscon_gpio(chip); + unsigned int offs; + int ret; + + offs = priv->dreg_offset + priv->data->dat_bit_offset + offset; + + if (!val) + return; + + ret = regmap_update_bits( + priv->syscon, + (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, + BIT(offs % SYSCON_REG_BITS) | KEYSTONE_LOCK_BIT, + BIT(offs % SYSCON_REG_BITS) | KEYSTONE_LOCK_BIT); + if (ret < 0) + dev_err(chip->dev, "gpio write failed ret(%d)\n", ret); +} + +static const struct syscon_gpio_data keystone_dsp_gpio = { + /* ARM Keystone 2 */ + .compatible = NULL, + .flags = GPIO_SYSCON_FEAT_OUT, + .bit_count = 28, + .dat_bit_offset = 4, + .set = keystone_gpio_set, +}; + static const struct of_device_id syscon_gpio_ids[] = { { .compatible = "cirrus,clps711x-mctrl-gpio", .data = &clps711x_mctrl_gpio, }, + { + .compatible = "ti,keystone-dsp-gpio", + .data = &keystone_dsp_gpio, + }, { } }; MODULE_DEVICE_TABLE(of, syscon_gpio_ids); @@ -138,6 +189,8 @@ 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; + struct device_node *np = dev->of_node; + int ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -145,10 +198,31 @@ static int syscon_gpio_probe(struct platform_device *pdev) 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); + if (priv->data->compatible) { + priv->syscon = syscon_regmap_lookup_by_compatible( + priv->data->compatible); + if (IS_ERR(priv->syscon)) + return PTR_ERR(priv->syscon); + } else { + priv->syscon = + syscon_regmap_lookup_by_phandle(np, "gpio,syscon-dev"); + if (IS_ERR(priv->syscon)) + return PTR_ERR(priv->syscon); + + ret = of_property_read_u32_index(np, "gpio,syscon-dev", 1, + &priv->dreg_offset); + if (ret) + dev_err(dev, "can't read the data register offset!\n"); + + priv->dreg_offset <<= 3; + + ret = of_property_read_u32_index(np, "gpio,syscon-dev", 2, + &priv->dir_reg_offset); + if (ret) + dev_err(dev, "can't read the dir register offset!\n"); + + priv->dir_reg_offset <<= 3; + } priv->chip.dev = dev; priv->chip.owner = THIS_MODULE; @@ -159,7 +233,7 @@ static int syscon_gpio_probe(struct platform_device *pdev) 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.set = priv->data->set ? : syscon_gpio_set; priv->chip.direction_output = syscon_gpio_dir_out; } diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c index 7324869..ae0f646 100644 --- a/drivers/gpio/gpio-tc3589x.c +++ b/drivers/gpio/gpio-tc3589x.c @@ -300,6 +300,11 @@ static int tc3589x_gpio_probe(struct platform_device *pdev) return ret; } + gpiochip_set_chained_irqchip(&tc3589x_gpio->chip, + &tc3589x_gpio_irq_chip, + irq, + NULL); + if (pdata && pdata->setup) pdata->setup(tc3589x, tc3589x_gpio->chip.base); diff --git a/drivers/gpio/gpio-xgene.c b/drivers/gpio/gpio-xgene.c new file mode 100644 index 0000000..7d48922 --- /dev/null +++ b/drivers/gpio/gpio-xgene.c @@ -0,0 +1,244 @@ +/* + * AppliedMicro X-Gene SoC GPIO Driver + * + * Copyright (c) 2014, Applied Micro Circuits Corporation + * Author: Feng Kan <fkan@apm.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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/spinlock.h> +#include <linux/platform_device.h> +#include <linux/gpio/driver.h> +#include <linux/types.h> +#include <linux/bitops.h> + +#define GPIO_SET_DR_OFFSET 0x0C +#define GPIO_DATA_OFFSET 0x14 +#define GPIO_BANK_STRIDE 0x0C + +#define XGENE_GPIOS_PER_BANK 16 +#define XGENE_MAX_GPIO_BANKS 3 +#define XGENE_MAX_GPIOS (XGENE_GPIOS_PER_BANK * XGENE_MAX_GPIO_BANKS) + +#define GPIO_BIT_OFFSET(x) (x % XGENE_GPIOS_PER_BANK) +#define GPIO_BANK_OFFSET(x) ((x / XGENE_GPIOS_PER_BANK) * GPIO_BANK_STRIDE) + +struct xgene_gpio { + struct gpio_chip chip; + void __iomem *base; + spinlock_t lock; +#ifdef CONFIG_PM + u32 set_dr_val[XGENE_MAX_GPIO_BANKS]; +#endif +}; + +static inline struct xgene_gpio *to_xgene_gpio(struct gpio_chip *chip) +{ + return container_of(chip, struct xgene_gpio, chip); +} + +static int xgene_gpio_get(struct gpio_chip *gc, unsigned int offset) +{ + struct xgene_gpio *chip = to_xgene_gpio(gc); + unsigned long bank_offset; + u32 bit_offset; + + bank_offset = GPIO_DATA_OFFSET + GPIO_BANK_OFFSET(offset); + bit_offset = GPIO_BIT_OFFSET(offset); + return !!(ioread32(chip->base + bank_offset) & BIT(bit_offset)); +} + +static void __xgene_gpio_set(struct gpio_chip *gc, unsigned int offset, int val) +{ + struct xgene_gpio *chip = to_xgene_gpio(gc); + unsigned long bank_offset; + u32 setval, bit_offset; + + bank_offset = GPIO_SET_DR_OFFSET + GPIO_BANK_OFFSET(offset); + bit_offset = GPIO_BIT_OFFSET(offset) + XGENE_GPIOS_PER_BANK; + + setval = ioread32(chip->base + bank_offset); + if (val) + setval |= BIT(bit_offset); + else + setval &= ~BIT(bit_offset); + iowrite32(setval, chip->base + bank_offset); +} + +static void xgene_gpio_set(struct gpio_chip *gc, unsigned int offset, int val) +{ + struct xgene_gpio *chip = to_xgene_gpio(gc); + unsigned long flags; + + spin_lock_irqsave(&chip->lock, flags); + __xgene_gpio_set(gc, offset, val); + spin_unlock_irqrestore(&chip->lock, flags); +} + +static int xgene_gpio_dir_in(struct gpio_chip *gc, unsigned int offset) +{ + struct xgene_gpio *chip = to_xgene_gpio(gc); + unsigned long flags, bank_offset; + u32 dirval, bit_offset; + + bank_offset = GPIO_SET_DR_OFFSET + GPIO_BANK_OFFSET(offset); + bit_offset = GPIO_BIT_OFFSET(offset); + + spin_lock_irqsave(&chip->lock, flags); + + dirval = ioread32(chip->base + bank_offset); + dirval |= BIT(bit_offset); + iowrite32(dirval, chip->base + bank_offset); + + spin_unlock_irqrestore(&chip->lock, flags); + + return 0; +} + +static int xgene_gpio_dir_out(struct gpio_chip *gc, + unsigned int offset, int val) +{ + struct xgene_gpio *chip = to_xgene_gpio(gc); + unsigned long flags, bank_offset; + u32 dirval, bit_offset; + + bank_offset = GPIO_SET_DR_OFFSET + GPIO_BANK_OFFSET(offset); + bit_offset = GPIO_BIT_OFFSET(offset); + + spin_lock_irqsave(&chip->lock, flags); + + dirval = ioread32(chip->base + bank_offset); + dirval &= ~BIT(bit_offset); + iowrite32(dirval, chip->base + bank_offset); + __xgene_gpio_set(gc, offset, val); + + spin_unlock_irqrestore(&chip->lock, flags); + + return 0; +} + +#ifdef CONFIG_PM +static int xgene_gpio_suspend(struct device *dev) +{ + struct xgene_gpio *gpio = dev_get_drvdata(dev); + unsigned long bank_offset; + unsigned int bank; + + for (bank = 0; bank < XGENE_MAX_GPIO_BANKS; bank++) { + bank_offset = GPIO_SET_DR_OFFSET + bank * GPIO_BANK_STRIDE; + gpio->set_dr_val[bank] = ioread32(gpio->base + bank_offset); + } + return 0; +} + +static int xgene_gpio_resume(struct device *dev) +{ + struct xgene_gpio *gpio = dev_get_drvdata(dev); + unsigned long bank_offset; + unsigned int bank; + + for (bank = 0; bank < XGENE_MAX_GPIO_BANKS; bank++) { + bank_offset = GPIO_SET_DR_OFFSET + bank * GPIO_BANK_STRIDE; + iowrite32(gpio->set_dr_val[bank], gpio->base + bank_offset); + } + return 0; +} + +static SIMPLE_DEV_PM_OPS(xgene_gpio_pm, xgene_gpio_suspend, xgene_gpio_resume); +#define XGENE_GPIO_PM_OPS (&xgene_gpio_pm) +#else +#define XGENE_GPIO_PM_OPS NULL +#endif + +static int xgene_gpio_probe(struct platform_device *pdev) +{ + struct resource *res; + struct xgene_gpio *gpio; + int err = 0; + + gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); + if (!gpio) { + err = -ENOMEM; + goto err; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + gpio->base = devm_ioremap_nocache(&pdev->dev, res->start, + resource_size(res)); + if (!gpio->base) { + err = -ENOMEM; + goto err; + } + + gpio->chip.ngpio = XGENE_MAX_GPIOS; + + spin_lock_init(&gpio->lock); + gpio->chip.dev = &pdev->dev; + gpio->chip.direction_input = xgene_gpio_dir_in; + gpio->chip.direction_output = xgene_gpio_dir_out; + gpio->chip.get = xgene_gpio_get; + gpio->chip.set = xgene_gpio_set; + gpio->chip.label = dev_name(&pdev->dev); + gpio->chip.base = -1; + + platform_set_drvdata(pdev, gpio); + + err = gpiochip_add(&gpio->chip); + if (err) { + dev_err(&pdev->dev, + "failed to register gpiochip.\n"); + goto err; + } + + dev_info(&pdev->dev, "X-Gene GPIO driver registered.\n"); + return 0; +err: + dev_err(&pdev->dev, "X-Gene GPIO driver registration failed.\n"); + return err; +} + +static int xgene_gpio_remove(struct platform_device *pdev) +{ + struct xgene_gpio *gpio = platform_get_drvdata(pdev); + + gpiochip_remove(&gpio->chip); + return 0; +} + +static const struct of_device_id xgene_gpio_of_match[] = { + { .compatible = "apm,xgene-gpio", }, + {}, +}; +MODULE_DEVICE_TABLE(of, xgene_gpio_of_match); + +static struct platform_driver xgene_gpio_driver = { + .driver = { + .name = "xgene-gpio", + .owner = THIS_MODULE, + .of_match_table = xgene_gpio_of_match, + .pm = XGENE_GPIO_PM_OPS, + }, + .probe = xgene_gpio_probe, + .remove = xgene_gpio_remove, +}; + +module_platform_driver(xgene_gpio_driver); + +MODULE_AUTHOR("Feng Kan <fkan@apm.com>"); +MODULE_DESCRIPTION("APM X-Gene GPIO driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c index 1248186..ba18b06 100644 --- a/drivers/gpio/gpio-xilinx.c +++ b/drivers/gpio/gpio-xilinx.c @@ -197,6 +197,7 @@ static int xgpio_of_probe(struct device_node *np) struct xgpio_instance *chip; int status = 0; const u32 *tree_info; + u32 ngpio; chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (!chip) @@ -211,12 +212,13 @@ static int xgpio_of_probe(struct device_node *np) /* Update GPIO direction shadow register with default value */ of_property_read_u32(np, "xlnx,tri-default", &chip->gpio_dir); - /* By default assume full GPIO controller */ - chip->mmchip.gc.ngpio = 32; - - /* Check device node and parent device node for device width */ - of_property_read_u32(np, "xlnx,gpio-width", - (u32 *)&chip->mmchip.gc.ngpio); + /* + * Check device node and parent device node for device width + * and assume default width of 32 + */ + if (of_property_read_u32(np, "xlnx,gpio-width", &ngpio)) + ngpio = 32; + chip->mmchip.gc.ngpio = (u16)ngpio; spin_lock_init(&chip->gpio_lock); @@ -258,12 +260,13 @@ static int xgpio_of_probe(struct device_node *np) /* Update GPIO direction shadow register with default value */ of_property_read_u32(np, "xlnx,tri-default-2", &chip->gpio_dir); - /* By default assume full GPIO controller */ - chip->mmchip.gc.ngpio = 32; - - /* Check device node and parent device node for device width */ - of_property_read_u32(np, "xlnx,gpio2-width", - (u32 *)&chip->mmchip.gc.ngpio); + /* + * Check device node and parent device node for device width + * and assume default width of 32 + */ + if (of_property_read_u32(np, "xlnx,gpio2-width", &ngpio)) + ngpio = 32; + chip->mmchip.gc.ngpio = (u16)ngpio; spin_lock_init(&chip->gpio_lock); diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c index 31ad5df..74cd480 100644 --- a/drivers/gpio/gpio-zynq.c +++ b/drivers/gpio/gpio-zynq.c @@ -88,16 +88,17 @@ * @chip: instance of the gpio_chip * @base_addr: base address of the GPIO device * @clk: clock resource for this controller + * @irq: interrupt for the GPIO device */ struct zynq_gpio { struct gpio_chip chip; void __iomem *base_addr; struct clk *clk; + int irq; }; static struct irq_chip zynq_gpio_level_irqchip; static struct irq_chip zynq_gpio_edge_irqchip; - /** * zynq_gpio_get_bank_pin - Get the bank number and pin number within that bank * for a given pin in the GPIO device @@ -138,6 +139,13 @@ static inline void zynq_gpio_get_bank_pin(unsigned int pin_num, } } +static const unsigned int zynq_gpio_bank_offset[] = { + ZYNQ_GPIO_BANK0_PIN_MIN, + ZYNQ_GPIO_BANK1_PIN_MIN, + ZYNQ_GPIO_BANK2_PIN_MIN, + ZYNQ_GPIO_BANK3_PIN_MIN, +}; + /** * zynq_gpio_get_value - Get the state of the specified pin of GPIO device * @chip: gpio_chip instance to be worked on @@ -427,10 +435,9 @@ static int zynq_gpio_set_irq_type(struct irq_data *irq_data, unsigned int type) static int zynq_gpio_set_wake(struct irq_data *data, unsigned int on) { - if (on) - zynq_gpio_irq_unmask(data); - else - zynq_gpio_irq_mask(data); + struct zynq_gpio *gpio = irq_data_get_irq_chip_data(data); + + irq_set_irq_wake(gpio->irq, on); return 0; } @@ -444,7 +451,8 @@ static struct irq_chip zynq_gpio_level_irqchip = { .irq_unmask = zynq_gpio_irq_unmask, .irq_set_type = zynq_gpio_set_irq_type, .irq_set_wake = zynq_gpio_set_wake, - .flags = IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED, + .flags = IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED | + IRQCHIP_MASK_ON_SUSPEND, }; static struct irq_chip zynq_gpio_edge_irqchip = { @@ -455,8 +463,28 @@ static struct irq_chip zynq_gpio_edge_irqchip = { .irq_unmask = zynq_gpio_irq_unmask, .irq_set_type = zynq_gpio_set_irq_type, .irq_set_wake = zynq_gpio_set_wake, + .flags = IRQCHIP_MASK_ON_SUSPEND, }; +static void zynq_gpio_handle_bank_irq(struct zynq_gpio *gpio, + unsigned int bank_num, + unsigned long pending) +{ + unsigned int bank_offset = zynq_gpio_bank_offset[bank_num]; + struct irq_domain *irqdomain = gpio->chip.irqdomain; + int offset; + + if (!pending) + return; + + for_each_set_bit(offset, &pending, 32) { + unsigned int gpio_irq; + + gpio_irq = irq_find_mapping(irqdomain, offset + bank_offset); + generic_handle_irq(gpio_irq); + } +} + /** * zynq_gpio_irqhandler - IRQ handler for the gpio banks of a gpio device * @irq: irq number of the gpio bank where interrupt has occurred @@ -482,18 +510,7 @@ static void zynq_gpio_irqhandler(unsigned int irq, struct irq_desc *desc) ZYNQ_GPIO_INTSTS_OFFSET(bank_num)); int_enb = readl_relaxed(gpio->base_addr + ZYNQ_GPIO_INTMASK_OFFSET(bank_num)); - int_sts &= ~int_enb; - if (int_sts) { - int offset; - unsigned long pending = int_sts; - - for_each_set_bit(offset, &pending, 32) { - unsigned int gpio_irq = - irq_find_mapping(gpio->chip.irqdomain, - offset); - generic_handle_irq(gpio_irq); - } - } + zynq_gpio_handle_bank_irq(gpio, bank_num, int_sts & ~int_enb); } chained_irq_exit(irqchip, desc); @@ -501,7 +518,11 @@ static void zynq_gpio_irqhandler(unsigned int irq, struct irq_desc *desc) static int __maybe_unused zynq_gpio_suspend(struct device *dev) { - if (!device_may_wakeup(dev)) + struct platform_device *pdev = to_platform_device(dev); + int irq = platform_get_irq(pdev, 0); + struct irq_data *data = irq_get_irq_data(irq); + + if (!irqd_is_wakeup_set(data)) return pm_runtime_force_suspend(dev); return 0; @@ -509,7 +530,11 @@ static int __maybe_unused zynq_gpio_suspend(struct device *dev) static int __maybe_unused zynq_gpio_resume(struct device *dev) { - if (!device_may_wakeup(dev)) + struct platform_device *pdev = to_platform_device(dev); + int irq = platform_get_irq(pdev, 0); + struct irq_data *data = irq_get_irq_data(irq); + + if (!irqd_is_wakeup_set(data)) return pm_runtime_force_resume(dev); return 0; @@ -570,7 +595,7 @@ static const struct dev_pm_ops zynq_gpio_dev_pm_ops = { */ static int zynq_gpio_probe(struct platform_device *pdev) { - int ret, bank_num, irq; + int ret, bank_num; struct zynq_gpio *gpio; struct gpio_chip *chip; struct resource *res; @@ -586,10 +611,10 @@ static int zynq_gpio_probe(struct platform_device *pdev) if (IS_ERR(gpio->base_addr)) return PTR_ERR(gpio->base_addr); - irq = platform_get_irq(pdev, 0); - if (irq < 0) { + gpio->irq = platform_get_irq(pdev, 0); + if (gpio->irq < 0) { dev_err(&pdev->dev, "invalid IRQ\n"); - return irq; + return gpio->irq; } /* configure the gpio chip */ @@ -637,19 +662,16 @@ static int zynq_gpio_probe(struct platform_device *pdev) goto err_rm_gpiochip; } - gpiochip_set_chained_irqchip(chip, &zynq_gpio_edge_irqchip, irq, + gpiochip_set_chained_irqchip(chip, &zynq_gpio_edge_irqchip, gpio->irq, zynq_gpio_irqhandler); pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); - device_set_wakeup_capable(&pdev->dev, 1); - return 0; err_rm_gpiochip: - if (gpiochip_remove(chip)) - dev_err(&pdev->dev, "Failed to remove gpio chip\n"); + gpiochip_remove(chip); err_disable_clk: clk_disable_unprepare(gpio->clk); @@ -664,16 +686,10 @@ err_disable_clk: */ static int zynq_gpio_remove(struct platform_device *pdev) { - int ret; struct zynq_gpio *gpio = platform_get_drvdata(pdev); pm_runtime_get_sync(&pdev->dev); - - ret = gpiochip_remove(&gpio->chip); - if (ret) { - dev_err(&pdev->dev, "Failed to remove gpio chip\n"); - return ret; - } + gpiochip_remove(&gpio->chip); clk_disable_unprepare(gpio->clk); device_set_wakeup_capable(&pdev->dev, 0); return 0; @@ -688,7 +704,6 @@ MODULE_DEVICE_TABLE(of, zynq_gpio_of_match); static struct platform_driver zynq_gpio_driver = { .driver = { .name = DRIVER_NAME, - .owner = THIS_MODULE, .pm = &zynq_gpio_dev_pm_ops, .of_match_table = zynq_gpio_of_match, }, diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 687476f..05c6275 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -25,10 +25,12 @@ struct acpi_gpio_event { acpi_handle handle; unsigned int pin; unsigned int irq; + struct gpio_desc *desc; }; struct acpi_gpio_connection { struct list_head node; + unsigned int pin; struct gpio_desc *desc; }; @@ -143,14 +145,8 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares, if (!handler) return AE_BAD_PARAMETER; - desc = gpiochip_get_desc(chip, pin); + desc = gpiochip_request_own_desc(chip, pin, "ACPI:Event"); if (IS_ERR(desc)) { - dev_err(chip->dev, "Failed to get GPIO descriptor\n"); - return AE_ERROR; - } - - ret = gpiochip_request_own_desc(desc, "ACPI:Event"); - if (ret) { dev_err(chip->dev, "Failed to request GPIO\n"); return AE_ERROR; } @@ -197,6 +193,7 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares, event->handle = evt_handle; event->irq = irq; event->pin = pin; + event->desc = desc; ret = request_threaded_irq(event->irq, NULL, handler, irqflags, "ACPI:Event", event); @@ -280,7 +277,7 @@ void acpi_gpiochip_free_interrupts(struct gpio_chip *chip) struct gpio_desc *desc; free_irq(event->irq, event); - desc = gpiochip_get_desc(chip, event->pin); + desc = event->desc; if (WARN_ON(IS_ERR(desc))) continue; gpio_unlock_as_irq(chip, event->pin); @@ -409,26 +406,20 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address, 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) { + if (conn->pin == pin) { found = true; + desc = conn->desc; break; } } if (!found) { - int ret; - - ret = gpiochip_request_own_desc(desc, "ACPI:OpRegion"); - if (ret) { + desc = gpiochip_request_own_desc(chip, pin, + "ACPI:OpRegion"); + if (IS_ERR(desc)) { status = AE_ERROR; mutex_unlock(&achip->conn_lock); goto out; @@ -465,6 +456,7 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address, goto out; } + conn->pin = pin; conn->desc = desc; list_add_tail(&conn->node, &achip->conns); } diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index c68d037..e8e98ca 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -308,10 +308,9 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip); * * A gpio_chip with any GPIOs still requested may not be removed. */ -int gpiochip_remove(struct gpio_chip *chip) +void gpiochip_remove(struct gpio_chip *chip) { unsigned long flags; - int status = 0; unsigned id; acpi_gpiochip_remove(chip); @@ -323,24 +322,15 @@ int gpiochip_remove(struct gpio_chip *chip) of_gpiochip_remove(chip); for (id = 0; id < chip->ngpio; id++) { - if (test_bit(FLAG_REQUESTED, &chip->desc[id].flags)) { - status = -EBUSY; - break; - } - } - if (status == 0) { - for (id = 0; id < chip->ngpio; id++) - chip->desc[id].chip = NULL; - - list_del(&chip->list); + if (test_bit(FLAG_REQUESTED, &chip->desc[id].flags)) + dev_crit(chip->dev, "REMOVING GPIOCHIP WITH GPIOS STILL REQUESTED\n"); } + for (id = 0; id < chip->ngpio; id++) + chip->desc[id].chip = NULL; + list_del(&chip->list); spin_unlock_irqrestore(&gpio_lock, flags); - - if (status == 0) - gpiochip_unexport(chip); - - return status; + gpiochip_unexport(chip); } EXPORT_SYMBOL_GPL(gpiochip_remove); @@ -395,30 +385,47 @@ static struct gpio_chip *find_chip_by_name(const char *name) */ /** - * 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 + * gpiochip_set_chained_irqchip() - sets a chained irqchip to a gpiochip + * @gpiochip: the gpiochip to set the irqchip chain to + * @irqchip: the irqchip to chain 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 + * coming out of the gpiochip. If the interrupt is nested rather than + * cascaded, pass NULL in this handler argument */ 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"); + unsigned int offset; + + if (!gpiochip->irqdomain) { + chip_err(gpiochip, "called %s before setting up irqchip\n", + __func__); return; } - /* - * 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); - irq_set_chained_handler(parent_irq, parent_handler); + if (parent_handler) { + if (gpiochip->can_sleep) { + chip_err(gpiochip, + "you cannot have chained interrupts on a " + "chip that may sleep\n"); + return; + } + /* + * 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); + irq_set_chained_handler(parent_irq, parent_handler); + } + + /* Set the parent IRQ for all affected IRQs */ + for (offset = 0; offset < gpiochip->ngpio; offset++) + irq_set_parent(irq_find_mapping(gpiochip->irqdomain, offset), + parent_irq); } EXPORT_SYMBOL_GPL(gpiochip_set_chained_irqchip); @@ -447,7 +454,7 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq, 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) + if (chip->can_sleep && !chip->irq_not_threaded) irq_set_nested_thread(irq, 1); #ifdef CONFIG_ARM set_irq_flags(irq, IRQF_VALID); @@ -524,7 +531,8 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) /* 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_dispose_mapping( + irq_find_mapping(gpiochip->irqdomain, offset)); irq_domain_remove(gpiochip->irqdomain); } @@ -895,12 +903,22 @@ EXPORT_SYMBOL_GPL(gpiochip_is_requested); * 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) +struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *chip, u16 hwnum, + const char *label) { - if (!desc || !desc->chip) - return -EINVAL; + struct gpio_desc *desc = gpiochip_get_desc(chip, hwnum); + int err; - return __gpiod_request(desc, label); + if (IS_ERR(desc)) { + chip_err(chip, "failed to get GPIO descriptor\n"); + return desc; + } + + err = __gpiod_request(desc, label); + if (err < 0) + return ERR_PTR(err); + + return desc; } EXPORT_SYMBOL_GPL(gpiochip_request_own_desc); @@ -1652,7 +1670,7 @@ struct gpio_desc *__must_check __gpiod_get_index(struct device *dev, * a result. In that case, use platform lookup as a fallback. */ if (!desc || desc == ERR_PTR(-ENOENT)) { - dev_dbg(dev, "using lookup tables for GPIO lookup"); + dev_dbg(dev, "using lookup tables for GPIO lookup\n"); desc = gpiod_find(dev, con_id, idx, &lookupflags); } diff --git a/drivers/hid/hid-cp2112.c b/drivers/hid/hid-cp2112.c index a822db5..3318de6 100644 --- a/drivers/hid/hid-cp2112.c +++ b/drivers/hid/hid-cp2112.c @@ -1069,8 +1069,7 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id) return ret; err_gpiochip_remove: - if (gpiochip_remove(&dev->gc) < 0) - hid_err(hdev, "error removing gpio chip\n"); + gpiochip_remove(&dev->gc); err_free_i2c: i2c_del_adapter(&dev->adap); err_free_dev: @@ -1089,8 +1088,7 @@ static void cp2112_remove(struct hid_device *hdev) struct cp2112_device *dev = hid_get_drvdata(hdev); sysfs_remove_group(&hdev->dev.kobj, &cp2112_attr_group); - if (gpiochip_remove(&dev->gc)) - hid_err(hdev, "unable to remove gpio chip\n"); + gpiochip_remove(&dev->gc); i2c_del_adapter(&dev->adap); /* i2c_del_adapter has finished removing all i2c devices from our * adapter. Well behaved devices should no longer call our cp2112_xfer diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c index 5ef7fcf..b97ed44 100644 --- a/drivers/input/keyboard/adp5588-keys.c +++ b/drivers/input/keyboard/adp5588-keys.c @@ -251,9 +251,7 @@ static void adp5588_gpio_remove(struct adp5588_kpad *kpad) dev_warn(dev, "teardown failed %d\n", error); } - error = gpiochip_remove(&kpad->gc); - if (error) - dev_warn(dev, "gpiochip_remove failed %d\n", error); + gpiochip_remove(&kpad->gc); } #else static inline int adp5588_gpio_add(struct adp5588_kpad *kpad) diff --git a/drivers/input/keyboard/adp5589-keys.c b/drivers/input/keyboard/adp5589-keys.c index 6329549..a452677 100644 --- a/drivers/input/keyboard/adp5589-keys.c +++ b/drivers/input/keyboard/adp5589-keys.c @@ -567,9 +567,7 @@ static void adp5589_gpio_remove(struct adp5589_kpad *kpad) dev_warn(dev, "teardown failed %d\n", error); } - error = gpiochip_remove(&kpad->gc); - if (error) - dev_warn(dev, "gpiochip_remove failed %d\n", error); + gpiochip_remove(&kpad->gc); } #else static inline int adp5589_gpio_add(struct adp5589_kpad *kpad) diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c index fce5906..1eb9d3c 100644 --- a/drivers/input/touchscreen/ad7879.c +++ b/drivers/input/touchscreen/ad7879.c @@ -470,14 +470,10 @@ static int ad7879_gpio_add(struct ad7879 *ts, static void ad7879_gpio_remove(struct ad7879 *ts) { const struct ad7879_platform_data *pdata = dev_get_platdata(ts->dev); - int ret; - if (pdata->gpio_export) { - ret = gpiochip_remove(&ts->gc); - if (ret) - dev_err(ts->dev, "failed to remove gpio %d\n", - ts->gc.base); - } + if (pdata->gpio_export) + gpiochip_remove(&ts->gc); + } #else static inline int ad7879_gpio_add(struct ad7879 *ts, diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c index 4a0e786..5a6363d 100644 --- a/drivers/leds/leds-pca9532.c +++ b/drivers/leds/leds-pca9532.c @@ -319,14 +319,8 @@ static int pca9532_destroy_devices(struct pca9532_data *data, int n_devs) } #ifdef CONFIG_LEDS_PCA9532_GPIO - if (data->gpio.dev) { - int err = gpiochip_remove(&data->gpio); - if (err) { - dev_err(&data->client->dev, "%s failed, %d\n", - "gpiochip_remove()", err); - return err; - } - } + if (data->gpio.dev) + gpiochip_remove(&data->gpio); #endif return 0; diff --git a/drivers/leds/leds-tca6507.c b/drivers/leds/leds-tca6507.c index 3d9e267..20fa8e7 100644 --- a/drivers/leds/leds-tca6507.c +++ b/drivers/leds/leds-tca6507.c @@ -667,11 +667,8 @@ static int tca6507_probe_gpios(struct i2c_client *client, static void tca6507_remove_gpio(struct tca6507_chip *tca) { - if (tca->gpio.ngpio) { - int err = gpiochip_remove(&tca->gpio); - dev_err(&tca->client->dev, "%s failed, %d\n", - "gpiochip_remove()", err); - } + if (tca->gpio.ngpio) + gpiochip_remove(&tca->gpio); } #else /* CONFIG_GPIOLIB */ static int tca6507_probe_gpios(struct i2c_client *client, diff --git a/drivers/media/dvb-frontends/cxd2820r_core.c b/drivers/media/dvb-frontends/cxd2820r_core.c index 03930d5..51ef8931 100644 --- a/drivers/media/dvb-frontends/cxd2820r_core.c +++ b/drivers/media/dvb-frontends/cxd2820r_core.c @@ -584,18 +584,14 @@ static int cxd2820r_get_frontend_algo(struct dvb_frontend *fe) static void cxd2820r_release(struct dvb_frontend *fe) { struct cxd2820r_priv *priv = fe->demodulator_priv; - int uninitialized_var(ret); /* silence compiler warning */ dev_dbg(&priv->i2c->dev, "%s\n", __func__); #ifdef CONFIG_GPIOLIB /* remove GPIOs */ - if (priv->gpio_chip.label) { - ret = gpiochip_remove(&priv->gpio_chip); - if (ret) - dev_err(&priv->i2c->dev, "%s: gpiochip_remove() " \ - "failed=%d\n", KBUILD_MODNAME, ret); - } + if (priv->gpio_chip.label) + gpiochip_remove(&priv->gpio_chip); + #endif kfree(priv); return; diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index 9fc4186..977bd3a 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c @@ -605,7 +605,8 @@ static int asic3_gpio_remove(struct platform_device *pdev) { struct asic3 *asic = platform_get_drvdata(pdev); - return gpiochip_remove(&asic->gpio); + gpiochip_remove(&asic->gpio); + return 0; } static void asic3_clk_enable(struct asic3 *asic, struct asic3_clk *clk) diff --git a/drivers/mfd/htc-i2cpld.c b/drivers/mfd/htc-i2cpld.c index 6bdb78c..adbbce0 100644 --- a/drivers/mfd/htc-i2cpld.c +++ b/drivers/mfd/htc-i2cpld.c @@ -481,15 +481,9 @@ static int htcpld_register_chip_gpio( ret = gpiochip_add(&(chip->chip_in)); if (ret) { - int error; - dev_warn(dev, "Unable to register input GPIOs for 0x%x: %d\n", plat_chip_data->addr, ret); - - error = gpiochip_remove(&(chip->chip_out)); - if (error) - dev_warn(dev, "Error while trying to unregister gpio chip: %d\n", error); - + gpiochip_remove(&(chip->chip_out)); return ret; } diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c index 81e6d09..02027b7 100644 --- a/drivers/mfd/sm501.c +++ b/drivers/mfd/sm501.c @@ -1047,7 +1047,6 @@ static int sm501_register_gpio(struct sm501_devdata *sm) struct sm501_gpio *gpio = &sm->gpio; resource_size_t iobase = sm->io_res->start + SM501_GPIO; int ret; - int tmp; dev_dbg(sm->dev, "registering gpio block %08llx\n", (unsigned long long)iobase); @@ -1086,11 +1085,7 @@ static int sm501_register_gpio(struct sm501_devdata *sm) return 0; err_low_chip: - tmp = gpiochip_remove(&gpio->low.gpio); - if (tmp) { - dev_err(sm->dev, "cannot remove low chip, cannot tidy up\n"); - return ret; - } + gpiochip_remove(&gpio->low.gpio); err_mapped: iounmap(gpio->regs); @@ -1105,18 +1100,12 @@ static int sm501_register_gpio(struct sm501_devdata *sm) static void sm501_gpio_remove(struct sm501_devdata *sm) { struct sm501_gpio *gpio = &sm->gpio; - int ret; if (!sm->gpio.registered) return; - ret = gpiochip_remove(&gpio->low.gpio); - if (ret) - dev_err(sm->dev, "cannot remove low chip, cannot tidy up\n"); - - ret = gpiochip_remove(&gpio->high.gpio); - if (ret) - dev_err(sm->dev, "cannot remove high chip, cannot tidy up\n"); + gpiochip_remove(&gpio->low.gpio); + gpiochip_remove(&gpio->high.gpio); iounmap(gpio->regs); release_resource(gpio->regs_res); diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c index 11c19e5..4fac16b 100644 --- a/drivers/mfd/tc6393xb.c +++ b/drivers/mfd/tc6393xb.c @@ -607,7 +607,7 @@ static int tc6393xb_probe(struct platform_device *dev) struct tc6393xb_platform_data *tcpd = dev_get_platdata(&dev->dev); struct tc6393xb *tc6393xb; struct resource *iomem, *rscr; - int ret, temp; + int ret; iomem = platform_get_resource(dev, IORESOURCE_MEM, 0); if (!iomem) @@ -714,7 +714,7 @@ err_setup: err_gpio_add: if (tc6393xb->gpio.base != -1) - temp = gpiochip_remove(&tc6393xb->gpio); + gpiochip_remove(&tc6393xb->gpio); tcpd->disable(dev); err_enable: clk_disable(tc6393xb->clk); @@ -744,13 +744,8 @@ static int tc6393xb_remove(struct platform_device *dev) tc6393xb_detach_irq(dev); - if (tc6393xb->gpio.base != -1) { - ret = gpiochip_remove(&tc6393xb->gpio); - if (ret) { - dev_err(&dev->dev, "Can't remove gpio chip: %d\n", ret); - return ret; - } - } + if (tc6393xb->gpio.base != -1) + gpiochip_remove(&tc6393xb->gpio); ret = tcpd->disable(dev); clk_disable(tc6393xb->clk); diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c index 153d595..58ea9fd 100644 --- a/drivers/mfd/ucb1x00-core.c +++ b/drivers/mfd/ucb1x00-core.c @@ -621,7 +621,6 @@ static void ucb1x00_remove(struct mcp *mcp) struct ucb1x00_plat_data *pdata = mcp->attached_device.platform_data; struct ucb1x00 *ucb = mcp_get_drvdata(mcp); struct list_head *l, *n; - int ret; mutex_lock(&ucb1x00_mutex); list_del(&ucb->node); @@ -631,11 +630,8 @@ static void ucb1x00_remove(struct mcp *mcp) } mutex_unlock(&ucb1x00_mutex); - if (ucb->gpio.base != -1) { - ret = gpiochip_remove(&ucb->gpio); - if (ret) - dev_err(&ucb->dev, "Can't remove gpio chip: %d\n", ret); - } + if (ucb->gpio.base != -1) + gpiochip_remove(&ucb->gpio); irq_set_chained_handler(ucb->irq, NULL); irq_free_descs(ucb->irq_base, 16); diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 64d06b5..c6a66de 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -86,7 +86,7 @@ config PINCTRL_BCM2835 config PINCTRL_BCM281XX bool "Broadcom BCM281xx pinctrl driver" - depends on OF + depends on OF && (ARCH_BCM_MOBILE || COMPILE_TEST) select PINMUX select PINCONF select GENERIC_PINCONF diff --git a/drivers/pinctrl/nomadik/pinctrl-abx500.c b/drivers/pinctrl/nomadik/pinctrl-abx500.c index 47f4931..2289728 100644 --- a/drivers/pinctrl/nomadik/pinctrl-abx500.c +++ b/drivers/pinctrl/nomadik/pinctrl-abx500.c @@ -1174,7 +1174,7 @@ static int abx500_gpio_probe(struct platform_device *pdev) const struct of_device_id *match; struct abx500_pinctrl *pct; unsigned int id = -1; - int ret, err; + int ret; int i; if (!np) { @@ -1266,10 +1266,7 @@ static int abx500_gpio_probe(struct platform_device *pdev) return 0; out_rem_chip: - err = gpiochip_remove(&pct->chip); - if (err) - dev_info(&pdev->dev, "failed to remove gpiochip\n"); - + gpiochip_remove(&pct->chip); return ret; } @@ -1280,15 +1277,8 @@ out_rem_chip: static int abx500_gpio_remove(struct platform_device *pdev) { struct abx500_pinctrl *pct = platform_get_drvdata(pdev); - int ret; - - ret = gpiochip_remove(&pct->chip); - if (ret < 0) { - dev_err(pct->dev, "unable to remove gpiochip: %d\n", - ret); - return ret; - } + gpiochip_remove(&pct->chip); return 0; } diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik.c b/drivers/pinctrl/nomadik/pinctrl-nomadik.c index 3c29d91..746db6a 100644 --- a/drivers/pinctrl/nomadik/pinctrl-nomadik.c +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik.c @@ -1276,7 +1276,7 @@ static int nmk_gpio_probe(struct platform_device *dev) IRQ_TYPE_EDGE_FALLING); if (ret) { dev_err(&dev->dev, "could not add irqchip\n"); - ret = gpiochip_remove(&nmk_chip->chip); + gpiochip_remove(&nmk_chip->chip); return -ENODEV; } /* Then register the chain on the parent IRQ */ diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c index d30dddd..e730935 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.c +++ b/drivers/pinctrl/qcom/pinctrl-msm.c @@ -936,14 +936,8 @@ EXPORT_SYMBOL(msm_pinctrl_probe); int msm_pinctrl_remove(struct platform_device *pdev) { struct msm_pinctrl *pctrl = platform_get_drvdata(pdev); - int ret; - - ret = gpiochip_remove(&pctrl->chip); - if (ret) { - dev_err(&pdev->dev, "Failed to remove gpiochip\n"); - return ret; - } + gpiochip_remove(&pctrl->chip); pinctrl_unregister(pctrl->pctrl); unregister_restart_handler(&pctrl->restart_nb); diff --git a/drivers/pinctrl/samsung/pinctrl-exynos5440.c b/drivers/pinctrl/samsung/pinctrl-exynos5440.c index b995ec2..88acfc0 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos5440.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos5440.c @@ -874,11 +874,7 @@ static int exynos5440_gpiolib_register(struct platform_device *pdev, static int exynos5440_gpiolib_unregister(struct platform_device *pdev, struct exynos5440_pinctrl_priv_data *priv) { - int ret = gpiochip_remove(priv->gc); - if (ret) { - dev_err(&pdev->dev, "gpio chip remove failed\n"); - return ret; - } + gpiochip_remove(priv->gc); return 0; } diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/samsung/pinctrl-samsung.c index 4a47691..2d37c8f 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.c +++ b/drivers/pinctrl/samsung/pinctrl-samsung.c @@ -946,9 +946,7 @@ static int samsung_gpiolib_register(struct platform_device *pdev, fail: for (--i, --bank; i >= 0; --i, --bank) - if (gpiochip_remove(&bank->gpio_chip)) - dev_err(&pdev->dev, "gpio chip %s remove failed\n", - bank->gpio_chip.label); + gpiochip_remove(&bank->gpio_chip); return ret; } @@ -958,16 +956,11 @@ static int samsung_gpiolib_unregister(struct platform_device *pdev, { struct samsung_pin_ctrl *ctrl = drvdata->ctrl; struct samsung_pin_bank *bank = ctrl->pin_banks; - int ret = 0; int i; - for (i = 0; !ret && i < ctrl->nr_banks; ++i, ++bank) - ret = gpiochip_remove(&bank->gpio_chip); - - if (ret) - dev_err(&pdev->dev, "gpio chip remove failed\n"); - - return ret; + for (i = 0; i < ctrl->nr_banks; ++i, ++bank) + gpiochip_remove(&bank->gpio_chip); + return 0; } static const struct of_device_id samsung_pinctrl_dt_match[]; diff --git a/drivers/pinctrl/sirf/pinctrl-sirf.c b/drivers/pinctrl/sirf/pinctrl-sirf.c index b713bd5..4c831fd 100644 --- a/drivers/pinctrl/sirf/pinctrl-sirf.c +++ b/drivers/pinctrl/sirf/pinctrl-sirf.c @@ -891,8 +891,7 @@ static int sirfsoc_gpio_probe(struct device_node *np) out_no_range: out_banks: - if (gpiochip_remove(&sgpio->chip.gc)) - dev_err(&pdev->dev, "could not remove gpio chip\n"); + gpiochip_remove(&sgpio->chip.gc); out: iounmap(regs); return err; diff --git a/drivers/platform/x86/intel_pmic_gpio.c b/drivers/platform/x86/intel_pmic_gpio.c index 40929e4..04fed00 100644 --- a/drivers/platform/x86/intel_pmic_gpio.c +++ b/drivers/platform/x86/intel_pmic_gpio.c @@ -301,8 +301,7 @@ static int platform_pmic_gpio_probe(struct platform_device *pdev) return 0; fail_request_irq: - if (gpiochip_remove(&pg->chip)) - pr_err("gpiochip_remove failed\n"); + gpiochip_remove(&pg->chip); err: iounmap(pg->gpiointr); err2: diff --git a/drivers/ssb/driver_gpio.c b/drivers/ssb/driver_gpio.c index ba350d2..f92e266 100644 --- a/drivers/ssb/driver_gpio.c +++ b/drivers/ssb/driver_gpio.c @@ -475,7 +475,8 @@ int ssb_gpio_unregister(struct ssb_bus *bus) { if (ssb_chipco_available(&bus->chipco) || ssb_extif_available(&bus->extif)) { - return gpiochip_remove(&bus->gpio); + gpiochip_remove(&bus->gpio); + return 0; } else { SSB_WARN_ON(1); } diff --git a/drivers/staging/vme/devices/vme_pio2_gpio.c b/drivers/staging/vme/devices/vme_pio2_gpio.c index d8a118d..c64776f 100644 --- a/drivers/staging/vme/devices/vme_pio2_gpio.c +++ b/drivers/staging/vme/devices/vme_pio2_gpio.c @@ -221,9 +221,7 @@ void pio2_gpio_exit(struct pio2_card *card) { const char *label = card->gc.label; - if (gpiochip_remove(&(card->gc))) - dev_err(&card->vdev->dev, "Failed to remove GPIO\n"); - + gpiochip_remove(&(card->gc)); kfree(label); } diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 82573dc..0041a64 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1248,7 +1248,7 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, mutex_destroy(&s->mutex); #ifdef CONFIG_GPIOLIB - WARN_ON(gpiochip_remove(&s->gpio)); + gpiochip_remove(&s->gpio); out_uart: #endif @@ -1263,12 +1263,10 @@ out_clk: static int max310x_remove(struct device *dev) { struct max310x_port *s = dev_get_drvdata(dev); - int i, ret = 0; + int i; #ifdef CONFIG_GPIOLIB - ret = gpiochip_remove(&s->gpio); - if (ret) - return ret; + gpiochip_remove(&s->gpio); #endif for (i = 0; i < s->uart.nr; i++) { @@ -1282,7 +1280,7 @@ static int max310x_remove(struct device *dev) uart_unregister_driver(&s->uart); clk_disable_unprepare(s->clk); - return ret; + return 0; } static const struct of_device_id __maybe_unused max310x_dt_ids[] = { diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 3284c31..6246820d 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -1157,7 +1157,7 @@ static int sc16is7xx_probe(struct device *dev, #ifdef CONFIG_GPIOLIB if (devtype->nr_gpio) - WARN_ON(gpiochip_remove(&s->gpio)); + gpiochip_remove(&s->gpio); out_uart: #endif @@ -1173,14 +1173,11 @@ out_clk: static int sc16is7xx_remove(struct device *dev) { struct sc16is7xx_port *s = dev_get_drvdata(dev); - int i, ret = 0; + int i; #ifdef CONFIG_GPIOLIB - if (s->devtype->nr_gpio) { - ret = gpiochip_remove(&s->gpio); - if (ret) - return ret; - } + if (s->devtype->nr_gpio) + gpiochip_remove(&s->gpio); #endif for (i = 0; i < s->uart.nr; i++) { @@ -1195,7 +1192,7 @@ static int sc16is7xx_remove(struct device *dev) if (!IS_ERR(s->clk)) clk_disable_unprepare(s->clk); - return ret; + return 0; } static const struct of_device_id __maybe_unused sc16is7xx_dt_ids[] = { diff --git a/drivers/video/fbdev/via/via-gpio.c b/drivers/video/fbdev/via/via-gpio.c index e408679..6f433b8 100644 --- a/drivers/video/fbdev/via/via-gpio.c +++ b/drivers/video/fbdev/via/via-gpio.c @@ -270,7 +270,7 @@ static int viafb_gpio_probe(struct platform_device *platdev) static int viafb_gpio_remove(struct platform_device *platdev) { unsigned long flags; - int ret = 0, i; + int i; #ifdef CONFIG_PM viafb_pm_unregister(&viafb_gpio_pm_hooks); @@ -280,11 +280,7 @@ static int viafb_gpio_remove(struct platform_device *platdev) * Get unregistered. */ if (viafb_gpio_config.gpio_chip.ngpio > 0) { - ret = gpiochip_remove(&viafb_gpio_config.gpio_chip); - if (ret) { /* Somebody still using it? */ - printk(KERN_ERR "Viafb: GPIO remove failed\n"); - return ret; - } + gpiochip_remove(&viafb_gpio_config.gpio_chip); } /* * Disable the ports. @@ -294,7 +290,7 @@ static int viafb_gpio_remove(struct platform_device *platdev) viafb_gpio_disable(viafb_gpio_config.active_gpios[i]); viafb_gpio_config.gpio_chip.ngpio = 0; spin_unlock_irqrestore(&viafb_gpio_config.vdev->reg_lock, flags); - return ret; + return 0; } static struct platform_driver via_gpio_driver = { diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index c1d4105..383ade1 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -27,7 +27,7 @@ */ #ifndef ARCH_NR_GPIOS -#define ARCH_NR_GPIOS 256 +#define ARCH_NR_GPIOS 512 #endif /* diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index c5e41da..249db30 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -56,6 +56,8 @@ struct seq_file; * as the chip access may sleep when e.g. reading out the IRQ status * registers. * @exported: flags if the gpiochip is exported for use from sysfs. Private. + * @irq_not_threaded: flag must be set if @can_sleep is set but the + * IRQs don't need to be threaded * * A gpio_chip can help platforms abstract various sources of GPIOs so * they can all be accessed through a common programing interface. @@ -101,6 +103,7 @@ struct gpio_chip { struct gpio_desc *desc; const char *const *names; bool can_sleep; + bool irq_not_threaded; bool exported; #ifdef CONFIG_GPIOLIB_IRQCHIP @@ -141,7 +144,7 @@ extern const char *gpiochip_is_requested(struct gpio_chip *chip, /* add/remove chips */ extern int gpiochip_add(struct gpio_chip *chip); -extern int gpiochip_remove(struct gpio_chip *chip); +extern void gpiochip_remove(struct gpio_chip *chip); extern struct gpio_chip *gpiochip_find(void *data, int (*match)(struct gpio_chip *chip, void *data)); @@ -166,7 +169,8 @@ int gpiochip_irqchip_add(struct gpio_chip *gpiochip, #endif /* CONFIG_GPIOLIB_IRQCHIP */ -int gpiochip_request_own_desc(struct gpio_desc *desc, const char *label); +struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *chip, u16 hwnum, + const char *label); void gpiochip_free_own_desc(struct gpio_desc *desc); #else /* CONFIG_GPIOLIB */ diff --git a/include/linux/platform_data/gpio-dwapb.h b/include/linux/platform_data/gpio-dwapb.h new file mode 100644 index 0000000..28702c8 --- /dev/null +++ b/include/linux/platform_data/gpio-dwapb.h @@ -0,0 +1,32 @@ +/* + * Copyright(c) 2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#ifndef GPIO_DW_APB_H +#define GPIO_DW_APB_H + +struct dwapb_port_property { + struct device_node *node; + const char *name; + unsigned int idx; + unsigned int ngpio; + unsigned int gpio_base; + unsigned int irq; + bool irq_shared; +}; + +struct dwapb_platform_data { + struct dwapb_port_property *properties; + unsigned int nports; +}; + +#endif diff --git a/include/linux/spi/mcp23s08.h b/include/linux/spi/mcp23s08.h index 2d676d5..aa07d7b 100644 --- a/include/linux/spi/mcp23s08.h +++ b/include/linux/spi/mcp23s08.h @@ -22,4 +22,22 @@ struct mcp23s08_platform_data { * base to base+15 (or base+31 for s17 variant). */ unsigned base; + /* Marks the device as a interrupt controller. + * NOTE: The interrupt functionality is only supported for i2c + * versions of the chips. The spi chips can also do the interrupts, + * but this is not supported by the linux driver yet. + */ + bool irq_controller; + + /* Sets the mirror flag in the IOCON register. Devices + * with two interrupt outputs (these are the devices ending with 17 and + * those that have 16 IOs) have two IO banks: IO 0-7 form bank 1 and + * IO 8-15 are bank 2. These chips have two different interrupt outputs: + * One for bank 1 and another for bank 2. If irq-mirror is set, both + * interrupts are generated regardless of the bank that an input change + * occurred on. If it is not set, the interrupt are only generated for + * the bank they belong to. + * On devices with only one interrupt output this property is useless. + */ + bool mirror; }; diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index 7bb0d36..a01ad62 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -2319,11 +2319,8 @@ static void wm5100_init_gpio(struct i2c_client *i2c) static void wm5100_free_gpio(struct i2c_client *i2c) { struct wm5100_priv *wm5100 = i2c_get_clientdata(i2c); - int ret; - ret = gpiochip_remove(&wm5100->gpio_chip); - if (ret != 0) - dev_err(&i2c->dev, "Failed to remove GPIOs: %d\n", ret); + gpiochip_remove(&wm5100->gpio_chip); } #else static void wm5100_init_gpio(struct i2c_client *i2c) diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index aa09848..c038b3e 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -1877,11 +1877,7 @@ static void wm8903_init_gpio(struct wm8903_priv *wm8903) static void wm8903_free_gpio(struct wm8903_priv *wm8903) { - int ret; - - ret = gpiochip_remove(&wm8903->gpio_chip); - if (ret != 0) - dev_err(wm8903->dev, "Failed to remove GPIOs: %d\n", ret); + gpiochip_remove(&wm8903->gpio_chip); } #else static void wm8903_init_gpio(struct wm8903_priv *wm8903) diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 1098ae3..9077411 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -3398,11 +3398,8 @@ static void wm8962_init_gpio(struct snd_soc_codec *codec) static void wm8962_free_gpio(struct snd_soc_codec *codec) { struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); - int ret; - ret = gpiochip_remove(&wm8962->gpio_chip); - if (ret != 0) - dev_err(codec->dev, "Failed to remove GPIOs: %d\n", ret); + gpiochip_remove(&wm8962->gpio_chip); } #else static void wm8962_init_gpio(struct snd_soc_codec *codec) diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index f16ff4f..b1dcc11 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c @@ -2216,11 +2216,7 @@ static void wm8996_init_gpio(struct wm8996_priv *wm8996) static void wm8996_free_gpio(struct wm8996_priv *wm8996) { - int ret; - - ret = gpiochip_remove(&wm8996->gpio_chip); - if (ret != 0) - dev_err(wm8996->dev, "Failed to remove GPIOs: %d\n", ret); + gpiochip_remove(&wm8996->gpio_chip); } #else static void wm8996_init_gpio(struct wm8996_priv *wm8996) |