diff options
41 files changed, 1518 insertions, 793 deletions
diff --git a/Documentation/devicetree/bindings/gpio/fujitsu,mb86s70-gpio.txt b/Documentation/devicetree/bindings/gpio/fujitsu,mb86s70-gpio.txt new file mode 100644 index 0000000..bef353f --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/fujitsu,mb86s70-gpio.txt @@ -0,0 +1,20 @@ +Fujitsu MB86S7x GPIO Controller +------------------------------- + +Required properties: +- compatible: Should be "fujitsu,mb86s70-gpio" +- reg: Base address and length of register space +- clocks: Specify the clock +- gpio-controller: Marks the device node as a gpio controller. +- #gpio-cells: Should be <2>. The first cell is the pin number and the + second cell is used to specify optional parameters: + - bit 0 specifies polarity (0 for normal, 1 for inverted). + +Examples: + gpio0: gpio@31000000 { + compatible = "fujitsu,mb86s70-gpio"; + reg = <0 0x31000000 0x10000>; + gpio-controller; + #gpio-cells = <2>; + clocks = <&clk 0 2 1>; + }; diff --git a/Documentation/devicetree/bindings/gpio/gpio-max732x.txt b/Documentation/devicetree/bindings/gpio/gpio-max732x.txt new file mode 100644 index 0000000..5fdc843 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio-max732x.txt @@ -0,0 +1,59 @@ +* MAX732x-compatible I/O expanders + +Required properties: + - compatible: Should be one of the following: + - "maxim,max7319": For the Maxim MAX7319 + - "maxim,max7320": For the Maxim MAX7320 + - "maxim,max7321": For the Maxim MAX7321 + - "maxim,max7322": For the Maxim MAX7322 + - "maxim,max7323": For the Maxim MAX7323 + - "maxim,max7324": For the Maxim MAX7324 + - "maxim,max7325": For the Maxim MAX7325 + - "maxim,max7326": For the Maxim MAX7326 + - "maxim,max7327": For the Maxim MAX7327 + - reg: I2C slave address for this device. + - gpio-controller: Marks the device node as a GPIO controller. + - #gpio-cells: Should be 2. + - first cell is the GPIO number + - second cell specifies GPIO flags, as defined in <dt-bindings/gpio/gpio.h>. + Only the GPIO_ACTIVE_HIGH and GPIO_ACTIVE_LOW flags are supported. + +Optional properties: + + The I/O expander can detect input state changes, and thus optionally act as + an interrupt controller. When the expander interrupt line is connected all the + following properties must be set. For more information please see the + interrupt controller device tree bindings documentation available at + Documentation/devicetree/bindings/interrupt-controller/interrupts.txt. + + - interrupt-controller: Identifies the node as an interrupt controller. + - #interrupt-cells: Number of cells to encode an interrupt source, shall be 2. + - first cell is the pin number + - second cell is used to specify flags + - interrupt-parent: phandle of the parent interrupt controller. + - interrupts: Interrupt specifier for the controllers interrupt. + +Please refer to gpio.txt in this directory for details of the common GPIO +bindings used by client devices. + +Example 1. MAX7325 with interrupt support enabled (CONFIG_GPIO_MAX732X_IRQ=y): + + expander: max7325@6d { + compatible = "maxim,max7325"; + reg = <0x6d>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&gpio4>; + interrupts = <29 IRQ_TYPE_EDGE_FALLING>; + }; + +Example 2. MAX7325 with interrupt support disabled (CONFIG_GPIO_MAX732X_IRQ=n): + + expander: max7325@6d { + compatible = "maxim,max7325"; + reg = <0x6d>; + gpio-controller; + #gpio-cells = <2>; + }; diff --git a/Documentation/devicetree/bindings/gpio/gpio-sx150x.txt b/Documentation/devicetree/bindings/gpio/gpio-sx150x.txt new file mode 100644 index 0000000..ba2bb84 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio-sx150x.txt @@ -0,0 +1,40 @@ +SEMTECH SX150x GPIO expander bindings + + +Required properties: + +- compatible: should be "semtech,sx1506q", + "semtech,sx1508q", + "semtech,sx1509q". + +- reg: The I2C slave address for this device. + +- interrupt-parent: phandle of the parent interrupt controller. + +- interrupts: Interrupt specifier for the controllers interrupt. + +- #gpio-cells: Should be 2. The first cell is the GPIO number and the + second cell is used to specify optional parameters: + bit 0: polarity (0: normal, 1: inverted) + +- gpio-controller: Marks the device as a GPIO controller. + +- interrupt-controller: Marks the device as a interrupt controller. + +The GPIO expander can optionally be used as an interrupt controller, in +which case it uses the default two cell specifier as described in +Documentation/devicetree/bindings/interrupt-controller/interrupts.txt. + +Example: + + i2c_gpio_expander@20{ + #gpio-cells = <2>; + #interrupt-cells = <2>; + compatible = "semtech,sx1506q"; + reg = <0x20>; + interrupt-parent = <&gpio_1>; + interrupts = <16 0>; + + gpio-controller; + interrupt-controller; + }; diff --git a/Documentation/devicetree/bindings/gpio/gpio-xgene-sb.txt b/Documentation/devicetree/bindings/gpio/gpio-xgene-sb.txt new file mode 100644 index 0000000..dae1300 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio-xgene-sb.txt @@ -0,0 +1,32 @@ +APM X-Gene Standby GPIO controller bindings + +This is a gpio controller in the standby domain. + +There are 20 GPIO pins from 0..21. There is no GPIO_DS14 or GPIO_DS15, +only GPIO_DS8..GPIO_DS13 support interrupts. The IRQ mapping +is currently 1-to-1 on interrupts 0x28 thru 0x2d. + +Required properties: +- compatible: "apm,xgene-gpio-sb" for the X-Gene Standby 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. +- interrupts: Shall contain exactly 6 interrupts. + +Example: + sbgpio: sbgpio@17001000 { + compatible = "apm,xgene-gpio-sb"; + reg = <0x0 0x17001000 0x0 0x400>; + #gpio-cells = <2>; + gpio-controller; + interrupts = <0x0 0x28 0x1>, + <0x0 0x29 0x1>, + <0x0 0x2a 0x1>, + <0x0 0x2b 0x1>, + <0x0 0x2c 0x1>, + <0x0 0x2d 0x1>; + }; diff --git a/Documentation/devicetree/bindings/gpio/gpio.txt b/Documentation/devicetree/bindings/gpio/gpio.txt index b9bd1d6..f7a158d 100644 --- a/Documentation/devicetree/bindings/gpio/gpio.txt +++ b/Documentation/devicetree/bindings/gpio/gpio.txt @@ -69,7 +69,8 @@ GPIO pin number, and GPIO flags as accepted by the "qe_pio_e" gpio-controller. ---------------------------------- A gpio-specifier should contain a flag indicating the GPIO polarity; active- -high or active-low. If it does, the follow best practices should be followed: +high or active-low. If it does, the following best practices should be +followed: The gpio-specifier's polarity flag should represent the physical level at the GPIO controller that achieves (or represents, for inputs) a logically asserted @@ -147,7 +148,7 @@ contains information structures as follows: numeric-gpio-range ::= <pinctrl-phandle> <gpio-base> <pinctrl-base> <count> named-gpio-range ::= <pinctrl-phandle> <gpio-base> '<0 0>' - gpio-phandle : phandle to pin controller node. + pinctrl-phandle : phandle to pin controller node gpio-base : Base GPIO ID in the GPIO controller pinctrl-base : Base pinctrl pin ID in the pin controller count : The number of GPIOs/pins in this range diff --git a/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt b/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt index b2afdb2..67a2e4e 100644 --- a/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt +++ b/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt @@ -3,8 +3,8 @@ Required properties: - compatible : Should be "intel,pxa25x-gpio", "intel,pxa26x-gpio", "intel,pxa27x-gpio", "intel,pxa3xx-gpio", - "marvell,pxa93x-gpio", "marvell,mmp-gpio" or - "marvell,mmp2-gpio". + "marvell,pxa93x-gpio", "marvell,mmp-gpio", + "marvell,mmp2-gpio" or marvell,pxa1928-gpio. - reg : Address and length of the register set for the device - interrupts : Should be the port interrupt shared by all gpio pins. There're three gpio interrupts in arch-pxa, and they're gpio0, diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 96a1754..e344fa2 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -143,6 +143,7 @@ sandisk Sandisk Corporation sbs Smart Battery System schindler Schindler seagate Seagate Technology PLC +semtech Semtech Corporation sil Silicon Image silabs Silicon Laboratories simtek diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 633ec21..c1e2ca3 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -197,9 +197,16 @@ config GPIO_F7188X To compile this driver as a module, choose M here: the module will be called f7188x-gpio. +config GPIO_MB86S7X + bool "GPIO support for Fujitsu MB86S7x Platforms" + depends on ARCH_MB86S7X + help + Say yes here to support the GPIO controller in Fujitsu MB86S70 SoCs. + config GPIO_MOXART bool "MOXART GPIO support" depends on ARCH_MOXART + select GPIO_GENERIC help Select this option to enable GPIO driver for MOXA ART SoC devices. @@ -285,6 +292,7 @@ config GPIO_PXA config GPIO_RCAR tristate "Renesas R-Car GPIO" depends on ARM && (ARCH_SHMOBILE || COMPILE_TEST) + select GPIOLIB_IRQCHIP help Say yes here to support GPIO on Renesas R-Car SoCs. @@ -365,9 +373,17 @@ config GPIO_XGENE the generic flash controller's address and data pins. Say yes here to enable the GFC GPIO functionality. +config GPIO_XGENE_SB + tristate "APM X-Gene GPIO standby controller support" + depends on ARCH_XGENE && OF_GPIO + select GPIO_GENERIC + help + This driver supports the GPIO block within the APM X-Gene + Standby Domain. Say yes here to enable the GPIO functionality. + config GPIO_XILINX - bool "Xilinx GPIO support" - depends on PPC_OF || MICROBLAZE || ARCH_ZYNQ + tristate "Xilinx GPIO support" + depends on OF_GPIO && (PPC || MICROBLAZE || ARCH_ZYNQ || X86) help Say yes here to support the Xilinx FPGA GPIO device @@ -394,25 +410,32 @@ config GPIO_VR41XX Say yes here to support the NEC VR4100 series General-purpose I/O Uint config GPIO_SCH - tristate "Intel SCH/TunnelCreek/Centerton GPIO" + tristate "Intel SCH/TunnelCreek/Centerton/Quark X1000 GPIO" depends on PCI && X86 select MFD_CORE select LPC_SCH help Say yes here to support GPIO interface on Intel Poulsbo SCH, - Intel Tunnel Creek processor or Intel Centerton processor. + Intel Tunnel Creek processor, Intel Centerton processor or + Intel Quark X1000 SoC. + The Intel SCH contains a total of 14 GPIO pins. Ten GPIOs are powered by the core power rail and are turned off during sleep modes (S3 and higher). The remaining four GPIOs are powered by the Intel SCH suspend power supply. These GPIOs remain active during S3. The suspend powered GPIOs can be used to wake the system from the Suspend-to-RAM state. + The Intel Tunnel Creek processor has 5 GPIOs powered by the core power rail and 9 from suspend power supply. + The Intel Centerton processor has a total of 30 GPIO pins. Twenty-one are powered by the core power rail and 9 from the suspend power supply. + The Intel Quark X1000 SoC has 2 GPIOs powered by the core + power well and 6 from the suspend power well. + config GPIO_ICH tristate "Intel ICH GPIO" depends on PCI && X86 @@ -450,6 +473,7 @@ config GPIO_VX855 config GPIO_GE_FPGA bool "GE FPGA based GPIO" depends on GE_FPGA + select GPIO_GENERIC help Support for common GPIO functionality provided on some GE Single Board Computers. @@ -519,6 +543,7 @@ config GPIO_MAX7300 config GPIO_MAX732X tristate "MAX7319, MAX7320-7327 I2C Port Expanders" depends on I2C + select IRQ_DOMAIN help Say yes here to support the MAX7319, MAX7320-7327 series of I2C Port Expanders. Each IO port on these chips has a fixed role of @@ -613,6 +638,7 @@ config GPIO_RC5T583 config GPIO_SX150X bool "Semtech SX150x I2C GPIO expander" depends on I2C=y + select GPIOLIB_IRQCHIP default n help Say yes here to provide support for Semtech SX150-series I2C @@ -624,6 +650,7 @@ config GPIO_SX150X config GPIO_STMPE bool "STMPE GPIOs" depends on MFD_STMPE + depends on OF_GPIO select GPIOLIB_IRQCHIP help This enables support for the GPIOs found on the STMPE I/O diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 81755f1..bdda6a9 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o obj-$(CONFIG_GPIO_MAX7300) += gpio-max7300.o obj-$(CONFIG_GPIO_MAX7301) += gpio-max7301.o obj-$(CONFIG_GPIO_MAX732X) += gpio-max732x.o +obj-$(CONFIG_GPIO_MB86S7X) += gpio-mb86s7x.o obj-$(CONFIG_GPIO_MC33880) += gpio-mc33880.o obj-$(CONFIG_GPIO_MC9S08DZ60) += gpio-mc9s08dz60.o obj-$(CONFIG_GPIO_MCP23S08) += gpio-mcp23s08.o @@ -105,6 +106,7 @@ 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_XGENE_SB) += gpio-xgene-sb.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-amd8111.c b/drivers/gpio/gpio-amd8111.c index d3d2d10..d00d8192 100644 --- a/drivers/gpio/gpio-amd8111.c +++ b/drivers/gpio/gpio-amd8111.c @@ -213,6 +213,12 @@ found: goto out; } gp.pm = ioport_map(gp.pmbase + PMBASE_OFFSET, PMBASE_SIZE); + if (!gp.pm) { + dev_err(&pdev->dev, "Couldn't map io port into io memory\n"); + release_region(gp.pmbase + PMBASE_OFFSET, PMBASE_SIZE); + err = -ENOMEM; + goto out; + } gp.pdev = pdev; gp.chip.dev = &pdev->dev; diff --git a/drivers/gpio/gpio-dln2.c b/drivers/gpio/gpio-dln2.c index ce3c155..dbdb4de 100644 --- a/drivers/gpio/gpio-dln2.c +++ b/drivers/gpio/gpio-dln2.c @@ -396,6 +396,7 @@ static void dln2_gpio_event(struct platform_device *pdev, u16 echo, const void *data, int len) { int pin, irq; + const struct { __le16 count; __u8 type; diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index b4eb6a6..58faf04 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -469,15 +469,13 @@ dwapb_gpio_get_pdata_of(struct device *dev) if (nports == 0) return ERR_PTR(-ENODEV); - pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) return ERR_PTR(-ENOMEM); - pdata->properties = kcalloc(nports, sizeof(*pp), GFP_KERNEL); - if (!pdata->properties) { - kfree(pdata); + pdata->properties = devm_kcalloc(dev, nports, sizeof(*pp), GFP_KERNEL); + if (!pdata->properties) return ERR_PTR(-ENOMEM); - } pdata->nports = nports; @@ -490,8 +488,6 @@ dwapb_gpio_get_pdata_of(struct device *dev) 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); } @@ -523,15 +519,6 @@ dwapb_gpio_get_pdata_of(struct device *dev) 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; @@ -540,40 +527,32 @@ static int dwapb_gpio_probe(struct platform_device *pdev) int err; struct device *dev = &pdev->dev; struct dwapb_platform_data *pdata = dev_get_platdata(dev); - bool is_pdata_alloc = !pdata; - if (is_pdata_alloc) { + if (!pdata) { pdata = dwapb_gpio_get_pdata_of(dev); if (IS_ERR(pdata)) return PTR_ERR(pdata); } - if (!pdata->nports) { - err = -ENODEV; - goto out_err; - } + if (!pdata->nports) + return -ENODEV; gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); - if (!gpio) { - err = -ENOMEM; - goto out_err; - } + if (!gpio) + return -ENOMEM; + 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; - goto out_err; - } + if (!gpio->ports) + return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); gpio->regs = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(gpio->regs)) { - err = PTR_ERR(gpio->regs); - goto out_err; - } + if (IS_ERR(gpio->regs)) + return PTR_ERR(gpio->regs); for (i = 0; i < gpio->nr_ports; i++) { err = dwapb_gpio_add_port(gpio, &pdata->properties[i], i); @@ -582,16 +561,12 @@ static int dwapb_gpio_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, gpio); - goto out_err; + return 0; out_unregister: dwapb_gpio_unregister(gpio); dwapb_irq_teardown(gpio); -out_err: - if (is_pdata_alloc) - dwapb_free_pdata_of(pdata); - return err; } diff --git a/drivers/gpio/gpio-ge.c b/drivers/gpio/gpio-ge.c index aea5c2a..f9ac3f3 100644 --- a/drivers/gpio/gpio-ge.c +++ b/drivers/gpio/gpio-ge.c @@ -19,9 +19,12 @@ #include <linux/kernel.h> #include <linux/io.h> +#include <linux/slab.h> #include <linux/of_device.h> #include <linux/of_gpio.h> +#include <linux/of_address.h> #include <linux/module.h> +#include <linux/basic_mmio_gpio.h> #define GEF_GPIO_DIRECT 0x00 #define GEF_GPIO_IN 0x04 @@ -33,53 +36,6 @@ #define GEF_GPIO_OVERRUN 0x1C #define GEF_GPIO_MODE 0x20 -static void gef_gpio_set(struct gpio_chip *chip, unsigned offset, int value) -{ - struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); - unsigned int data; - - data = ioread32be(mmchip->regs + GEF_GPIO_OUT); - if (value) - data = data | BIT(offset); - else - data = data & ~BIT(offset); - iowrite32be(data, mmchip->regs + GEF_GPIO_OUT); -} - -static int gef_gpio_dir_in(struct gpio_chip *chip, unsigned offset) -{ - unsigned int data; - struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); - - data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT); - data = data | BIT(offset); - iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT); - - return 0; -} - -static int gef_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int value) -{ - unsigned int data; - struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); - - /* Set value before switching to output */ - gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value); - - data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT); - data = data & ~BIT(offset); - iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT); - - return 0; -} - -static int gef_gpio_get(struct gpio_chip *chip, unsigned offset) -{ - struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); - - return !!(ioread32be(mmchip->regs + GEF_GPIO_IN) & BIT(offset)); -} - static const struct of_device_id gef_gpio_ids[] = { { .compatible = "gef,sbc610-gpio", @@ -99,22 +55,50 @@ static int __init gef_gpio_probe(struct platform_device *pdev) { const struct of_device_id *of_id = of_match_device(gef_gpio_ids, &pdev->dev); - struct of_mm_gpio_chip *mmchip; + struct bgpio_chip *bgc; + void __iomem *regs; + int ret; - mmchip = devm_kzalloc(&pdev->dev, sizeof(*mmchip), GFP_KERNEL); - if (!mmchip) + bgc = devm_kzalloc(&pdev->dev, sizeof(*bgc), GFP_KERNEL); + if (!bgc) return -ENOMEM; + regs = of_iomap(pdev->dev.of_node, 0); + if (!regs) + return -ENOMEM; + + ret = bgpio_init(bgc, &pdev->dev, 4, regs + GEF_GPIO_IN, + regs + GEF_GPIO_OUT, NULL, NULL, + regs + GEF_GPIO_DIRECT, BGPIOF_BIG_ENDIAN_BYTE_ORDER); + if (ret) { + dev_err(&pdev->dev, "bgpio_init failed\n"); + goto err0; + } + /* Setup pointers to chip functions */ - mmchip->gc.ngpio = (u16)(uintptr_t)of_id->data; - mmchip->gc.of_gpio_n_cells = 2; - mmchip->gc.direction_input = gef_gpio_dir_in; - mmchip->gc.direction_output = gef_gpio_dir_out; - mmchip->gc.get = gef_gpio_get; - mmchip->gc.set = gef_gpio_set; + bgc->gc.label = devm_kstrdup(&pdev->dev, pdev->dev.of_node->full_name, + GFP_KERNEL); + if (!bgc->gc.label) { + ret = -ENOMEM; + goto err0; + } + + bgc->gc.base = -1; + bgc->gc.ngpio = (u16)(uintptr_t)of_id->data; + bgc->gc.of_gpio_n_cells = 2; + bgc->gc.of_node = pdev->dev.of_node; /* This function adds a memory mapped GPIO chip */ - return of_mm_gpiochip_add(pdev->dev.of_node, mmchip); + ret = gpiochip_add(&bgc->gc); + if (ret) + goto err0; + + return 0; +err0: + iounmap(regs); + pr_err("%s: GPIO chip registration failed\n", + pdev->dev.of_node->full_name); + return ret; }; static struct platform_driver gef_gpio_driver = { diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c index 16f6115..b92a690 100644 --- a/drivers/gpio/gpio-generic.c +++ b/drivers/gpio/gpio-generic.c @@ -190,6 +190,79 @@ static void bgpio_set_set(struct gpio_chip *gc, unsigned int gpio, int val) spin_unlock_irqrestore(&bgc->lock, flags); } +static void bgpio_multiple_get_masks(struct bgpio_chip *bgc, + unsigned long *mask, unsigned long *bits, + unsigned long *set_mask, + unsigned long *clear_mask) +{ + int i; + + *set_mask = 0; + *clear_mask = 0; + + for (i = 0; i < bgc->bits; i++) { + if (*mask == 0) + break; + if (__test_and_clear_bit(i, mask)) { + if (test_bit(i, bits)) + *set_mask |= bgc->pin2mask(bgc, i); + else + *clear_mask |= bgc->pin2mask(bgc, i); + } + } +} + +static void bgpio_set_multiple_single_reg(struct bgpio_chip *bgc, + unsigned long *mask, + unsigned long *bits, + void __iomem *reg) +{ + unsigned long flags; + unsigned long set_mask, clear_mask; + + spin_lock_irqsave(&bgc->lock, flags); + + bgpio_multiple_get_masks(bgc, mask, bits, &set_mask, &clear_mask); + + bgc->data |= set_mask; + bgc->data &= ~clear_mask; + + bgc->write_reg(reg, bgc->data); + + spin_unlock_irqrestore(&bgc->lock, flags); +} + +static void bgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask, + unsigned long *bits) +{ + struct bgpio_chip *bgc = to_bgpio_chip(gc); + + bgpio_set_multiple_single_reg(bgc, mask, bits, bgc->reg_dat); +} + +static void bgpio_set_multiple_set(struct gpio_chip *gc, unsigned long *mask, + unsigned long *bits) +{ + struct bgpio_chip *bgc = to_bgpio_chip(gc); + + bgpio_set_multiple_single_reg(bgc, mask, bits, bgc->reg_set); +} + +static void bgpio_set_multiple_with_clear(struct gpio_chip *gc, + unsigned long *mask, + unsigned long *bits) +{ + struct bgpio_chip *bgc = to_bgpio_chip(gc); + unsigned long set_mask, clear_mask; + + bgpio_multiple_get_masks(bgc, mask, bits, &set_mask, &clear_mask); + + if (set_mask) + bgc->write_reg(bgc->reg_set, set_mask); + if (clear_mask) + bgc->write_reg(bgc->reg_clr, clear_mask); +} + static int bgpio_simple_dir_in(struct gpio_chip *gc, unsigned int gpio) { return 0; @@ -354,11 +427,14 @@ static int bgpio_setup_io(struct bgpio_chip *bgc, bgc->reg_set = set; bgc->reg_clr = clr; bgc->gc.set = bgpio_set_with_clear; + bgc->gc.set_multiple = bgpio_set_multiple_with_clear; } else if (set && !clr) { bgc->reg_set = set; bgc->gc.set = bgpio_set_set; + bgc->gc.set_multiple = bgpio_set_multiple_set; } else { bgc->gc.set = bgpio_set; + bgc->gc.set_multiple = bgpio_set_multiple; } bgc->gc.get = bgpio_get; diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c index 3a5a710..35a0277 100644 --- a/drivers/gpio/gpio-grgpio.c +++ b/drivers/gpio/gpio-grgpio.c @@ -121,7 +121,7 @@ static int grgpio_to_irq(struct gpio_chip *gc, unsigned offset) { struct grgpio_priv *priv = grgpio_gc_to_priv(gc); - if (offset > gc->ngpio) + if (offset >= gc->ngpio) return -ENXIO; if (priv->lirqs[offset].index < 0) diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c index 6c67622..a095b23 100644 --- a/drivers/gpio/gpio-max732x.c +++ b/drivers/gpio/gpio-max732x.c @@ -19,8 +19,10 @@ #include <linux/gpio.h> #include <linux/interrupt.h> #include <linux/irq.h> +#include <linux/irqdomain.h> #include <linux/i2c.h> #include <linux/i2c/max732x.h> +#include <linux/of.h> /* @@ -116,6 +118,22 @@ static const struct i2c_device_id max732x_id[] = { }; MODULE_DEVICE_TABLE(i2c, max732x_id); +#ifdef CONFIG_OF +static const struct of_device_id max732x_of_table[] = { + { .compatible = "maxim,max7319" }, + { .compatible = "maxim,max7320" }, + { .compatible = "maxim,max7321" }, + { .compatible = "maxim,max7322" }, + { .compatible = "maxim,max7323" }, + { .compatible = "maxim,max7324" }, + { .compatible = "maxim,max7325" }, + { .compatible = "maxim,max7326" }, + { .compatible = "maxim,max7327" }, + { } +}; +MODULE_DEVICE_TABLE(of, max732x_of_table); +#endif + struct max732x_chip { struct gpio_chip gpio_chip; @@ -132,16 +150,22 @@ struct max732x_chip { uint8_t reg_out[2]; #ifdef CONFIG_GPIO_MAX732X_IRQ - struct mutex irq_lock; - int irq_base; - uint8_t irq_mask; - uint8_t irq_mask_cur; - uint8_t irq_trig_raise; - uint8_t irq_trig_fall; - uint8_t irq_features; + struct irq_domain *irq_domain; + struct mutex irq_lock; + int irq_base; + uint8_t irq_mask; + uint8_t irq_mask_cur; + uint8_t irq_trig_raise; + uint8_t irq_trig_fall; + uint8_t irq_features; #endif }; +static inline struct max732x_chip *to_max732x(struct gpio_chip *gc) +{ + return container_of(gc, struct max732x_chip, gpio_chip); +} + static int max732x_writeb(struct max732x_chip *chip, int group_a, uint8_t val) { struct i2c_client *client; @@ -180,12 +204,10 @@ static inline int is_group_a(struct max732x_chip *chip, unsigned off) static int max732x_gpio_get_value(struct gpio_chip *gc, unsigned off) { - struct max732x_chip *chip; + struct max732x_chip *chip = to_max732x(gc); uint8_t reg_val; int ret; - chip = container_of(gc, struct max732x_chip, gpio_chip); - ret = max732x_readb(chip, is_group_a(chip, off), ®_val); if (ret < 0) return 0; @@ -193,18 +215,17 @@ static int max732x_gpio_get_value(struct gpio_chip *gc, unsigned off) return reg_val & (1u << (off & 0x7)); } -static void max732x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) +static void max732x_gpio_set_mask(struct gpio_chip *gc, unsigned off, int mask, + int val) { - struct max732x_chip *chip; - uint8_t reg_out, mask = 1u << (off & 0x7); + struct max732x_chip *chip = to_max732x(gc); + uint8_t reg_out; int ret; - chip = container_of(gc, struct max732x_chip, gpio_chip); - mutex_lock(&chip->lock); reg_out = (off > 7) ? chip->reg_out[1] : chip->reg_out[0]; - reg_out = (val) ? reg_out | mask : reg_out & ~mask; + reg_out = (reg_out & ~mask) | (val & mask); ret = max732x_writeb(chip, is_group_a(chip, off), reg_out); if (ret < 0) @@ -219,13 +240,31 @@ out: mutex_unlock(&chip->lock); } +static void max732x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) +{ + unsigned base = off & ~0x7; + uint8_t mask = 1u << (off & 0x7); + + max732x_gpio_set_mask(gc, base, mask, val << (off & 0x7)); +} + +static void max732x_gpio_set_multiple(struct gpio_chip *gc, + unsigned long *mask, unsigned long *bits) +{ + unsigned mask_lo = mask[0] & 0xff; + unsigned mask_hi = (mask[0] >> 8) & 0xff; + + if (mask_lo) + max732x_gpio_set_mask(gc, 0, mask_lo, bits[0] & 0xff); + if (mask_hi) + max732x_gpio_set_mask(gc, 8, mask_hi, (bits[0] >> 8) & 0xff); +} + static int max732x_gpio_direction_input(struct gpio_chip *gc, unsigned off) { - struct max732x_chip *chip; + struct max732x_chip *chip = to_max732x(gc); unsigned int mask = 1u << off; - chip = container_of(gc, struct max732x_chip, gpio_chip); - if ((mask & chip->dir_input) == 0) { dev_dbg(&chip->client->dev, "%s port %d is output only\n", chip->client->name, off); @@ -245,11 +284,9 @@ static int max732x_gpio_direction_input(struct gpio_chip *gc, unsigned off) static int max732x_gpio_direction_output(struct gpio_chip *gc, unsigned off, int val) { - struct max732x_chip *chip; + struct max732x_chip *chip = to_max732x(gc); unsigned int mask = 1u << off; - chip = container_of(gc, struct max732x_chip, gpio_chip); - if ((mask & chip->dir_output) == 0) { dev_dbg(&chip->client->dev, "%s port %d is input only\n", chip->client->name, off); @@ -321,24 +358,28 @@ static void max732x_irq_update_mask(struct max732x_chip *chip) static int max732x_gpio_to_irq(struct gpio_chip *gc, unsigned off) { - struct max732x_chip *chip; + struct max732x_chip *chip = to_max732x(gc); - chip = container_of(gc, struct max732x_chip, gpio_chip); - return chip->irq_base + off; + if (chip->irq_domain) { + return irq_create_mapping(chip->irq_domain, + chip->irq_base + off); + } else { + return -ENXIO; + } } static void max732x_irq_mask(struct irq_data *d) { struct max732x_chip *chip = irq_data_get_irq_chip_data(d); - chip->irq_mask_cur &= ~(1 << (d->irq - chip->irq_base)); + chip->irq_mask_cur &= ~(1 << d->hwirq); } static void max732x_irq_unmask(struct irq_data *d) { struct max732x_chip *chip = irq_data_get_irq_chip_data(d); - chip->irq_mask_cur |= 1 << (d->irq - chip->irq_base); + chip->irq_mask_cur |= 1 << d->hwirq; } static void max732x_irq_bus_lock(struct irq_data *d) @@ -352,15 +393,25 @@ static void max732x_irq_bus_lock(struct irq_data *d) static void max732x_irq_bus_sync_unlock(struct irq_data *d) { struct max732x_chip *chip = irq_data_get_irq_chip_data(d); + uint16_t new_irqs; + uint16_t level; max732x_irq_update_mask(chip); + + new_irqs = chip->irq_trig_fall | chip->irq_trig_raise; + while (new_irqs) { + level = __ffs(new_irqs); + max732x_gpio_direction_input(&chip->gpio_chip, level); + new_irqs &= ~(1 << level); + } + mutex_unlock(&chip->irq_lock); } static int max732x_irq_set_type(struct irq_data *d, unsigned int type) { struct max732x_chip *chip = irq_data_get_irq_chip_data(d); - uint16_t off = d->irq - chip->irq_base; + uint16_t off = d->hwirq; uint16_t mask = 1 << off; if (!(mask & chip->dir_input)) { @@ -385,7 +436,7 @@ static int max732x_irq_set_type(struct irq_data *d, unsigned int type) else chip->irq_trig_raise &= ~mask; - return max732x_gpio_direction_input(&chip->gpio_chip, off); + return 0; } static struct irq_chip max732x_irq_chip = { @@ -441,7 +492,7 @@ static irqreturn_t max732x_irq_handler(int irq, void *devid) do { level = __ffs(pending); - handle_nested_irq(level + chip->irq_base); + handle_nested_irq(irq_find_mapping(chip->irq_domain, level)); pending &= ~(1 << level); } while (pending); @@ -449,6 +500,44 @@ static irqreturn_t max732x_irq_handler(int irq, void *devid) return IRQ_HANDLED; } +static int max732x_irq_map(struct irq_domain *h, unsigned int virq, + irq_hw_number_t hw) +{ + struct max732x_chip *chip = h->host_data; + + if (!(chip->dir_input & (1 << hw))) { + dev_err(&chip->client->dev, + "Attempt to map output line as IRQ line: %lu\n", + hw); + return -EPERM; + } + + irq_set_chip_data(virq, chip); + irq_set_chip_and_handler(virq, &max732x_irq_chip, + handle_edge_irq); + irq_set_nested_thread(virq, 1); +#ifdef CONFIG_ARM + /* ARM needs us to explicitly flag the IRQ as valid + * and will set them noprobe when we do so. */ + set_irq_flags(virq, IRQF_VALID); +#else + irq_set_noprobe(virq); +#endif + + return 0; +} + +static struct irq_domain_ops max732x_irq_domain_ops = { + .map = max732x_irq_map, + .xlate = irq_domain_xlate_twocell, +}; + +static void max732x_irq_teardown(struct max732x_chip *chip) +{ + if (chip->client->irq && chip->irq_domain) + irq_domain_remove(chip->irq_domain); +} + static int max732x_irq_setup(struct max732x_chip *chip, const struct i2c_device_id *id) { @@ -457,28 +546,19 @@ static int max732x_irq_setup(struct max732x_chip *chip, int has_irq = max732x_features[id->driver_data] >> 32; int ret; - if (pdata->irq_base && has_irq != INT_NONE) { - int lvl; - - chip->irq_base = pdata->irq_base; + if (((pdata && pdata->irq_base) || client->irq) + && has_irq != INT_NONE) { + if (pdata) + chip->irq_base = pdata->irq_base; chip->irq_features = has_irq; mutex_init(&chip->irq_lock); - for (lvl = 0; lvl < chip->gpio_chip.ngpio; lvl++) { - int irq = lvl + chip->irq_base; - - if (!(chip->dir_input & (1 << lvl))) - continue; - - irq_set_chip_data(irq, chip); - irq_set_chip_and_handler(irq, &max732x_irq_chip, - handle_edge_irq); - irq_set_nested_thread(irq, 1); -#ifdef CONFIG_ARM - set_irq_flags(irq, IRQF_VALID); -#else - irq_set_noprobe(irq); -#endif + chip->irq_domain = irq_domain_add_simple(client->dev.of_node, + chip->gpio_chip.ngpio, chip->irq_base, + &max732x_irq_domain_ops, chip); + if (!chip->irq_domain) { + dev_err(&client->dev, "Failed to create IRQ domain\n"); + return -ENOMEM; } ret = request_threaded_irq(client->irq, @@ -498,15 +578,10 @@ static int max732x_irq_setup(struct max732x_chip *chip, return 0; out_failed: - chip->irq_base = 0; + max732x_irq_teardown(chip); return ret; } -static void max732x_irq_teardown(struct max732x_chip *chip) -{ - if (chip->irq_base) - free_irq(chip->client->irq, chip); -} #else /* CONFIG_GPIO_MAX732X_IRQ */ static int max732x_irq_setup(struct max732x_chip *chip, const struct i2c_device_id *id) @@ -515,7 +590,7 @@ static int max732x_irq_setup(struct max732x_chip *chip, struct max732x_platform_data *pdata = dev_get_platdata(&client->dev); int has_irq = max732x_features[id->driver_data] >> 32; - if (pdata->irq_base && has_irq != INT_NONE) + if (((pdata && pdata->irq_base) || client->irq) && has_irq != INT_NONE) dev_warn(&client->dev, "interrupt support not compiled in\n"); return 0; @@ -562,6 +637,7 @@ static int max732x_setup_gpio(struct max732x_chip *chip, if (chip->dir_output) { gc->direction_output = max732x_gpio_direction_output; gc->set = max732x_gpio_set_value; + gc->set_multiple = max732x_gpio_set_multiple; } gc->get = max732x_gpio_get_value; gc->can_sleep = true; @@ -574,28 +650,47 @@ static int max732x_setup_gpio(struct max732x_chip *chip, return port; } +static struct max732x_platform_data *of_gpio_max732x(struct device *dev) +{ + struct max732x_platform_data *pdata; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return NULL; + + pdata->gpio_base = -1; + + return pdata; +} + static int max732x_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct max732x_platform_data *pdata; + struct device_node *node; struct max732x_chip *chip; struct i2c_client *c; uint16_t addr_a, addr_b; int ret, nr_port; pdata = dev_get_platdata(&client->dev); - if (pdata == NULL) { + node = client->dev.of_node; + + if (!pdata && node) + pdata = of_gpio_max732x(&client->dev); + + if (!pdata) { dev_dbg(&client->dev, "no platform data\n"); return -EINVAL; } - chip = devm_kzalloc(&client->dev, sizeof(struct max732x_chip), - GFP_KERNEL); + chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; chip->client = client; nr_port = max732x_setup_gpio(chip, id, pdata->gpio_base); + chip->gpio_chip.dev = &client->dev; addr_a = (client->addr & 0x0f) | 0x60; addr_b = (client->addr & 0x0f) | 0x50; @@ -643,7 +738,7 @@ static int max732x_probe(struct i2c_client *client, if (ret) goto out_failed; - if (pdata->setup) { + if (pdata && pdata->setup) { ret = pdata->setup(client, chip->gpio_chip.base, chip->gpio_chip.ngpio, pdata->context); if (ret < 0) @@ -664,9 +759,10 @@ static int max732x_remove(struct i2c_client *client) { struct max732x_platform_data *pdata = dev_get_platdata(&client->dev); struct max732x_chip *chip = i2c_get_clientdata(client); - int ret; - if (pdata->teardown) { + if (pdata && pdata->teardown) { + int ret; + ret = pdata->teardown(client, chip->gpio_chip.base, chip->gpio_chip.ngpio, pdata->context); if (ret < 0) { @@ -689,8 +785,9 @@ static int max732x_remove(struct i2c_client *client) static struct i2c_driver max732x_driver = { .driver = { - .name = "max732x", - .owner = THIS_MODULE, + .name = "max732x", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(max732x_of_table), }, .probe = max732x_probe, .remove = max732x_remove, diff --git a/drivers/gpio/gpio-mb86s7x.c b/drivers/gpio/gpio-mb86s7x.c new file mode 100644 index 0000000..21b1ce5 --- /dev/null +++ b/drivers/gpio/gpio-mb86s7x.c @@ -0,0 +1,232 @@ +/* + * linux/drivers/gpio/gpio-mb86s7x.c + * + * Copyright (C) 2015 Fujitsu Semiconductor Limited + * Copyright (C) 2015 Linaro Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * 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. + */ + +#include <linux/io.h> +#include <linux/init.h> +#include <linux/clk.h> +#include <linux/module.h> +#include <linux/err.h> +#include <linux/errno.h> +#include <linux/ioport.h> +#include <linux/of_device.h> +#include <linux/gpio/driver.h> +#include <linux/platform_device.h> +#include <linux/spinlock.h> +#include <linux/slab.h> + +/* + * Only first 8bits of a register correspond to each pin, + * so there are 4 registers for 32 pins. + */ +#define PDR(x) (0x0 + x / 8 * 4) +#define DDR(x) (0x10 + x / 8 * 4) +#define PFR(x) (0x20 + x / 8 * 4) + +#define OFFSET(x) BIT((x) % 8) + +struct mb86s70_gpio_chip { + struct gpio_chip gc; + void __iomem *base; + struct clk *clk; + spinlock_t lock; +}; + +static inline struct mb86s70_gpio_chip *chip_to_mb86s70(struct gpio_chip *gc) +{ + return container_of(gc, struct mb86s70_gpio_chip, gc); +} + +static int mb86s70_gpio_request(struct gpio_chip *gc, unsigned gpio) +{ + struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc); + unsigned long flags; + u32 val; + + spin_lock_irqsave(&gchip->lock, flags); + + val = readl(gchip->base + PFR(gpio)); + val &= ~OFFSET(gpio); + writel(val, gchip->base + PFR(gpio)); + + spin_unlock_irqrestore(&gchip->lock, flags); + + return 0; +} + +static void mb86s70_gpio_free(struct gpio_chip *gc, unsigned gpio) +{ + struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc); + unsigned long flags; + u32 val; + + spin_lock_irqsave(&gchip->lock, flags); + + val = readl(gchip->base + PFR(gpio)); + val |= OFFSET(gpio); + writel(val, gchip->base + PFR(gpio)); + + spin_unlock_irqrestore(&gchip->lock, flags); +} + +static int mb86s70_gpio_direction_input(struct gpio_chip *gc, unsigned gpio) +{ + struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc); + unsigned long flags; + unsigned char val; + + spin_lock_irqsave(&gchip->lock, flags); + + val = readl(gchip->base + DDR(gpio)); + val &= ~OFFSET(gpio); + writel(val, gchip->base + DDR(gpio)); + + spin_unlock_irqrestore(&gchip->lock, flags); + + return 0; +} + +static int mb86s70_gpio_direction_output(struct gpio_chip *gc, + unsigned gpio, int value) +{ + struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc); + unsigned long flags; + unsigned char val; + + spin_lock_irqsave(&gchip->lock, flags); + + val = readl(gchip->base + PDR(gpio)); + if (value) + val |= OFFSET(gpio); + else + val &= ~OFFSET(gpio); + writel(val, gchip->base + PDR(gpio)); + + val = readl(gchip->base + DDR(gpio)); + val |= OFFSET(gpio); + writel(val, gchip->base + DDR(gpio)); + + spin_unlock_irqrestore(&gchip->lock, flags); + + return 0; +} + +static int mb86s70_gpio_get(struct gpio_chip *gc, unsigned gpio) +{ + struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc); + + return !!(readl(gchip->base + PDR(gpio)) & OFFSET(gpio)); +} + +static void mb86s70_gpio_set(struct gpio_chip *gc, unsigned gpio, int value) +{ + struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc); + unsigned long flags; + unsigned char val; + + spin_lock_irqsave(&gchip->lock, flags); + + val = readl(gchip->base + PDR(gpio)); + if (value) + val |= OFFSET(gpio); + else + val &= ~OFFSET(gpio); + writel(val, gchip->base + PDR(gpio)); + + spin_unlock_irqrestore(&gchip->lock, flags); +} + +static int mb86s70_gpio_probe(struct platform_device *pdev) +{ + struct mb86s70_gpio_chip *gchip; + struct resource *res; + int ret; + + gchip = devm_kzalloc(&pdev->dev, sizeof(*gchip), GFP_KERNEL); + if (gchip == NULL) + return -ENOMEM; + + platform_set_drvdata(pdev, gchip); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + gchip->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(gchip->base)) + return PTR_ERR(gchip->base); + + gchip->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(gchip->clk)) + return PTR_ERR(gchip->clk); + + clk_prepare_enable(gchip->clk); + + spin_lock_init(&gchip->lock); + + gchip->gc.direction_output = mb86s70_gpio_direction_output; + gchip->gc.direction_input = mb86s70_gpio_direction_input; + gchip->gc.request = mb86s70_gpio_request; + gchip->gc.free = mb86s70_gpio_free; + gchip->gc.get = mb86s70_gpio_get; + gchip->gc.set = mb86s70_gpio_set; + gchip->gc.label = dev_name(&pdev->dev); + gchip->gc.ngpio = 32; + gchip->gc.owner = THIS_MODULE; + gchip->gc.dev = &pdev->dev; + gchip->gc.base = -1; + + platform_set_drvdata(pdev, gchip); + + ret = gpiochip_add(&gchip->gc); + if (ret) { + dev_err(&pdev->dev, "couldn't register gpio driver\n"); + clk_disable_unprepare(gchip->clk); + } + + return ret; +} + +static int mb86s70_gpio_remove(struct platform_device *pdev) +{ + struct mb86s70_gpio_chip *gchip = platform_get_drvdata(pdev); + + gpiochip_remove(&gchip->gc); + clk_disable_unprepare(gchip->clk); + + return 0; +} + +static const struct of_device_id mb86s70_gpio_dt_ids[] = { + { .compatible = "fujitsu,mb86s70-gpio" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mb86s70_gpio_dt_ids); + +static struct platform_driver mb86s70_gpio_driver = { + .driver = { + .name = "mb86s70-gpio", + .of_match_table = mb86s70_gpio_dt_ids, + }, + .probe = mb86s70_gpio_probe, + .remove = mb86s70_gpio_remove, +}; + +static int __init mb86s70_gpio_init(void) +{ + return platform_driver_register(&mb86s70_gpio_driver); +} +module_init(mb86s70_gpio_init); + +MODULE_DESCRIPTION("MB86S7x GPIO Driver"); +MODULE_ALIAS("platform:mb86s70-gpio"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-mm-lantiq.c b/drivers/gpio/gpio-mm-lantiq.c index f228b1c..f67ef22 100644 --- a/drivers/gpio/gpio-mm-lantiq.c +++ b/drivers/gpio/gpio-mm-lantiq.c @@ -104,35 +104,34 @@ static void ltq_mm_save_regs(struct of_mm_gpio_chip *mm_gc) static int ltq_mm_probe(struct platform_device *pdev) { - struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct ltq_mm *chip; - const __be32 *shadow; - int ret = 0; + u32 shadow; - if (!res) { - dev_err(&pdev->dev, "failed to get memory resource\n"); - return -ENOENT; - } - - chip = kzalloc(sizeof(*chip), GFP_KERNEL); + chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; + platform_set_drvdata(pdev, chip); + chip->mmchip.gc.ngpio = 16; - chip->mmchip.gc.label = "gpio-mm-ltq"; chip->mmchip.gc.direction_output = ltq_mm_dir_out; chip->mmchip.gc.set = ltq_mm_set; chip->mmchip.save_regs = ltq_mm_save_regs; /* store the shadow value if one was passed by the devicetree */ - shadow = of_get_property(pdev->dev.of_node, "lantiq,shadow", NULL); - if (shadow) - chip->shadow = be32_to_cpu(*shadow); - - ret = of_mm_gpiochip_add(pdev->dev.of_node, &chip->mmchip); - if (ret) - kfree(chip); - return ret; + if (!of_property_read_u32(pdev->dev.of_node, "lantiq,shadow", &shadow)) + chip->shadow = shadow; + + return of_mm_gpiochip_add(pdev->dev.of_node, &chip->mmchip); +} + +static int ltq_mm_remove(struct platform_device *pdev) +{ + struct ltq_mm *chip = platform_get_drvdata(pdev); + + of_mm_gpiochip_remove(&chip->mmchip); + + return 0; } static const struct of_device_id ltq_mm_match[] = { @@ -143,6 +142,7 @@ MODULE_DEVICE_TABLE(of, ltq_mm_match); static struct platform_driver ltq_mm_driver = { .probe = ltq_mm_probe, + .remove = ltq_mm_remove, .driver = { .name = "gpio-mm-ltq", .of_match_table = ltq_mm_match, @@ -155,3 +155,9 @@ static int __init ltq_mm_init(void) } subsys_initcall(ltq_mm_init); + +static void __exit ltq_mm_exit(void) +{ + platform_driver_unregister(<q_mm_driver); +} +module_exit(ltq_mm_exit); diff --git a/drivers/gpio/gpio-moxart.c b/drivers/gpio/gpio-moxart.c index 31e2551..c3ab46e 100644 --- a/drivers/gpio/gpio-moxart.c +++ b/drivers/gpio/gpio-moxart.c @@ -23,21 +23,12 @@ #include <linux/delay.h> #include <linux/timer.h> #include <linux/bitops.h> +#include <linux/basic_mmio_gpio.h> #define GPIO_DATA_OUT 0x00 #define GPIO_DATA_IN 0x04 #define GPIO_PIN_DIRECTION 0x08 -struct moxart_gpio_chip { - struct gpio_chip gpio; - void __iomem *base; -}; - -static inline struct moxart_gpio_chip *to_moxart_gpio(struct gpio_chip *chip) -{ - return container_of(chip, struct moxart_gpio_chip, gpio); -} - static int moxart_gpio_request(struct gpio_chip *chip, unsigned offset) { return pinctrl_request_gpio(offset); @@ -48,90 +39,60 @@ static void moxart_gpio_free(struct gpio_chip *chip, unsigned offset) pinctrl_free_gpio(offset); } -static void moxart_gpio_set(struct gpio_chip *chip, unsigned offset, int value) -{ - struct moxart_gpio_chip *gc = to_moxart_gpio(chip); - void __iomem *ioaddr = gc->base + GPIO_DATA_OUT; - u32 reg = readl(ioaddr); - - if (value) - reg = reg | BIT(offset); - else - reg = reg & ~BIT(offset); - - writel(reg, ioaddr); -} - static int moxart_gpio_get(struct gpio_chip *chip, unsigned offset) { - struct moxart_gpio_chip *gc = to_moxart_gpio(chip); - u32 ret = readl(gc->base + GPIO_PIN_DIRECTION); + struct bgpio_chip *bgc = to_bgpio_chip(chip); + u32 ret = bgc->read_reg(bgc->reg_dir); if (ret & BIT(offset)) - return !!(readl(gc->base + GPIO_DATA_OUT) & BIT(offset)); + return !!(bgc->read_reg(bgc->reg_set) & BIT(offset)); else - return !!(readl(gc->base + GPIO_DATA_IN) & BIT(offset)); -} - -static int moxart_gpio_direction_input(struct gpio_chip *chip, unsigned offset) -{ - struct moxart_gpio_chip *gc = to_moxart_gpio(chip); - void __iomem *ioaddr = gc->base + GPIO_PIN_DIRECTION; - - writel(readl(ioaddr) & ~BIT(offset), ioaddr); - return 0; -} - -static int moxart_gpio_direction_output(struct gpio_chip *chip, - unsigned offset, int value) -{ - struct moxart_gpio_chip *gc = to_moxart_gpio(chip); - void __iomem *ioaddr = gc->base + GPIO_PIN_DIRECTION; - - moxart_gpio_set(chip, offset, value); - writel(readl(ioaddr) | BIT(offset), ioaddr); - return 0; + return !!(bgc->read_reg(bgc->reg_dat) & BIT(offset)); } -static struct gpio_chip moxart_template_chip = { - .label = "moxart-gpio", - .request = moxart_gpio_request, - .free = moxart_gpio_free, - .direction_input = moxart_gpio_direction_input, - .direction_output = moxart_gpio_direction_output, - .set = moxart_gpio_set, - .get = moxart_gpio_get, - .ngpio = 32, - .owner = THIS_MODULE, -}; - static int moxart_gpio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct resource *res; - struct moxart_gpio_chip *mgc; + struct bgpio_chip *bgc; + void __iomem *base; int ret; - mgc = devm_kzalloc(dev, sizeof(*mgc), GFP_KERNEL); - if (!mgc) + bgc = devm_kzalloc(dev, sizeof(*bgc), GFP_KERNEL); + if (!bgc) return -ENOMEM; - mgc->gpio = moxart_template_chip; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - mgc->base = devm_ioremap_resource(dev, res); - if (IS_ERR(mgc->base)) - return PTR_ERR(mgc->base); + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); - mgc->gpio.dev = dev; + ret = bgpio_init(bgc, dev, 4, base + GPIO_DATA_IN, + base + GPIO_DATA_OUT, NULL, + base + GPIO_PIN_DIRECTION, NULL, 0); + if (ret) { + dev_err(&pdev->dev, "bgpio_init failed\n"); + return ret; + } - ret = gpiochip_add(&mgc->gpio); + bgc->gc.label = "moxart-gpio"; + bgc->gc.request = moxart_gpio_request; + bgc->gc.free = moxart_gpio_free; + bgc->gc.get = moxart_gpio_get; + bgc->data = bgc->read_reg(bgc->reg_set); + bgc->gc.base = 0; + bgc->gc.ngpio = 32; + bgc->gc.dev = dev; + bgc->gc.owner = THIS_MODULE; + + ret = gpiochip_add(&bgc->gc); if (ret) { dev_err(dev, "%s: gpiochip_add failed\n", dev->of_node->full_name); return ret; } - return 0; + return ret; } static const struct of_device_id moxart_gpio_match[] = { diff --git a/drivers/gpio/gpio-mpc5200.c b/drivers/gpio/gpio-mpc5200.c index 8ce6c95..4c54215 100644 --- a/drivers/gpio/gpio-mpc5200.c +++ b/drivers/gpio/gpio-mpc5200.c @@ -155,10 +155,12 @@ static int mpc52xx_wkup_gpiochip_probe(struct platform_device *ofdev) struct gpio_chip *gc; int ret; - chip = kzalloc(sizeof(*chip), GFP_KERNEL); + chip = devm_kzalloc(&ofdev->dev, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; + platform_set_drvdata(ofdev, chip); + gc = &chip->mmchip.gc; gc->ngpio = 8; @@ -181,7 +183,11 @@ static int mpc52xx_wkup_gpiochip_probe(struct platform_device *ofdev) static int mpc52xx_gpiochip_remove(struct platform_device *ofdev) { - return -EBUSY; + struct mpc52xx_gpiochip *chip = platform_get_drvdata(ofdev); + + of_mm_gpiochip_remove(&chip->mmchip); + + return 0; } static const struct of_device_id mpc52xx_wkup_gpiochip_match[] = { @@ -314,10 +320,12 @@ static int mpc52xx_simple_gpiochip_probe(struct platform_device *ofdev) struct mpc52xx_gpio __iomem *regs; int ret; - chip = kzalloc(sizeof(*chip), GFP_KERNEL); + chip = devm_kzalloc(&ofdev->dev, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; + platform_set_drvdata(ofdev, chip); + gc = &chip->mmchip.gc; gc->ngpio = 32; @@ -363,11 +371,16 @@ static int __init mpc52xx_gpio_init(void) return 0; } - /* Make sure we get initialised before anyone else tries to use us */ subsys_initcall(mpc52xx_gpio_init); -/* No exit call at the moment as we cannot unregister of gpio chips */ +static void __exit mpc52xx_gpio_exit(void) +{ + platform_driver_unregister(&mpc52xx_wkup_gpiochip_driver); + + platform_driver_unregister(&mpc52xx_simple_gpiochip_driver); +} +module_exit(mpc52xx_gpio_exit); MODULE_DESCRIPTION("Freescale MPC52xx gpio driver"); MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de"); diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index d1ff879..a6952ba3 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -15,6 +15,7 @@ #include <linux/of.h> #include <linux/of_gpio.h> #include <linux/of_irq.h> +#include <linux/of_platform.h> #include <linux/gpio.h> #include <linux/slab.h> #include <linux/irq.h> @@ -39,6 +40,7 @@ struct mpc8xxx_gpio_chip { */ u32 data; struct irq_domain *irq; + unsigned int irqn; const void *of_dev_id_data; }; @@ -342,20 +344,20 @@ static struct of_device_id mpc8xxx_gpio_ids[] __initdata = { {} }; -static void __init mpc8xxx_add_controller(struct device_node *np) +static int mpc8xxx_probe(struct platform_device *pdev) { + struct device_node *np = pdev->dev.of_node; struct mpc8xxx_gpio_chip *mpc8xxx_gc; struct of_mm_gpio_chip *mm_gc; struct gpio_chip *gc; const struct of_device_id *id; - unsigned hwirq; int ret; - mpc8xxx_gc = kzalloc(sizeof(*mpc8xxx_gc), GFP_KERNEL); - if (!mpc8xxx_gc) { - ret = -ENOMEM; - goto err; - } + mpc8xxx_gc = devm_kzalloc(&pdev->dev, sizeof(*mpc8xxx_gc), GFP_KERNEL); + if (!mpc8xxx_gc) + return -ENOMEM; + + platform_set_drvdata(pdev, mpc8xxx_gc); spin_lock_init(&mpc8xxx_gc->lock); @@ -375,16 +377,16 @@ static void __init mpc8xxx_add_controller(struct device_node *np) ret = of_mm_gpiochip_add(np, mm_gc); if (ret) - goto err; + return ret; - hwirq = irq_of_parse_and_map(np, 0); - if (hwirq == NO_IRQ) - goto skip_irq; + mpc8xxx_gc->irqn = irq_of_parse_and_map(np, 0); + if (mpc8xxx_gc->irqn == NO_IRQ) + return 0; mpc8xxx_gc->irq = irq_domain_add_linear(np, MPC8XXX_GPIO_PINS, &mpc8xxx_gpio_irq_ops, mpc8xxx_gc); if (!mpc8xxx_gc->irq) - goto skip_irq; + return 0; id = of_match_node(mpc8xxx_gpio_ids, np); if (id) @@ -394,27 +396,39 @@ static void __init mpc8xxx_add_controller(struct device_node *np) out_be32(mm_gc->regs + GPIO_IER, 0xffffffff); out_be32(mm_gc->regs + GPIO_IMR, 0); - irq_set_handler_data(hwirq, mpc8xxx_gc); - irq_set_chained_handler(hwirq, mpc8xxx_gpio_irq_cascade); - -skip_irq: - return; - -err: - pr_err("%s: registration failed with status %d\n", - np->full_name, ret); - kfree(mpc8xxx_gc); + irq_set_handler_data(mpc8xxx_gc->irqn, mpc8xxx_gc); + irq_set_chained_handler(mpc8xxx_gc->irqn, mpc8xxx_gpio_irq_cascade); - return; + return 0; } -static int __init mpc8xxx_add_gpiochips(void) +static int mpc8xxx_remove(struct platform_device *pdev) { - struct device_node *np; + struct mpc8xxx_gpio_chip *mpc8xxx_gc = platform_get_drvdata(pdev); + + if (mpc8xxx_gc->irq) { + irq_set_handler_data(mpc8xxx_gc->irqn, NULL); + irq_set_chained_handler(mpc8xxx_gc->irqn, NULL); + irq_domain_remove(mpc8xxx_gc->irq); + } - for_each_matching_node(np, mpc8xxx_gpio_ids) - mpc8xxx_add_controller(np); + of_mm_gpiochip_remove(&mpc8xxx_gc->mm_gc); return 0; } -arch_initcall(mpc8xxx_add_gpiochips); + +static struct platform_driver mpc8xxx_plat_driver = { + .probe = mpc8xxx_probe, + .remove = mpc8xxx_remove, + .driver = { + .name = "gpio-mpc8xxx", + .of_match_table = mpc8xxx_gpio_ids, + }, +}; + +static int __init mpc8xxx_init(void) +{ + return platform_driver_register(&mpc8xxx_plat_driver); +} + +arch_initcall(mpc8xxx_init); diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 7bc3e9b..d0bc123 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -59,7 +59,7 @@ #define GPIO_LEVEL_MASK_OFF 0x001c /* The MV78200 has per-CPU registers for edge mask and level mask */ -#define GPIO_EDGE_MASK_MV78200_OFF(cpu) ((cpu) ? 0x30 : 0x18) +#define GPIO_EDGE_MASK_MV78200_OFF(cpu) ((cpu) ? 0x30 : 0x18) #define GPIO_LEVEL_MASK_MV78200_OFF(cpu) ((cpu) ? 0x34 : 0x1C) /* The Armada XP has per-CPU registers for interrupt cause, interrupt @@ -69,11 +69,11 @@ #define GPIO_EDGE_MASK_ARMADAXP_OFF(cpu) (0x10 + (cpu) * 0x4) #define GPIO_LEVEL_MASK_ARMADAXP_OFF(cpu) (0x20 + (cpu) * 0x4) -#define MVEBU_GPIO_SOC_VARIANT_ORION 0x1 -#define MVEBU_GPIO_SOC_VARIANT_MV78200 0x2 +#define MVEBU_GPIO_SOC_VARIANT_ORION 0x1 +#define MVEBU_GPIO_SOC_VARIANT_MV78200 0x2 #define MVEBU_GPIO_SOC_VARIANT_ARMADAXP 0x3 -#define MVEBU_MAX_GPIO_PER_BANK 32 +#define MVEBU_MAX_GPIO_PER_BANK 32 struct mvebu_gpio_chip { struct gpio_chip chip; @@ -82,9 +82,9 @@ struct mvebu_gpio_chip { void __iomem *percpu_membase; int irqbase; struct irq_domain *domain; - int soc_variant; + int soc_variant; - /* Used to preserve GPIO registers accross suspend/resume */ + /* Used to preserve GPIO registers across suspend/resume */ u32 out_reg; u32 io_conf_reg; u32 blink_en_reg; @@ -107,7 +107,8 @@ static inline void __iomem *mvebu_gpioreg_blink(struct mvebu_gpio_chip *mvchip) return mvchip->membase + GPIO_BLINK_EN_OFF; } -static inline void __iomem *mvebu_gpioreg_io_conf(struct mvebu_gpio_chip *mvchip) +static inline void __iomem * +mvebu_gpioreg_io_conf(struct mvebu_gpio_chip *mvchip) { return mvchip->membase + GPIO_IO_CONF_OFF; } @@ -117,12 +118,14 @@ static inline void __iomem *mvebu_gpioreg_in_pol(struct mvebu_gpio_chip *mvchip) return mvchip->membase + GPIO_IN_POL_OFF; } -static inline void __iomem *mvebu_gpioreg_data_in(struct mvebu_gpio_chip *mvchip) +static inline void __iomem * +mvebu_gpioreg_data_in(struct mvebu_gpio_chip *mvchip) { return mvchip->membase + GPIO_DATA_IN_OFF; } -static inline void __iomem *mvebu_gpioreg_edge_cause(struct mvebu_gpio_chip *mvchip) +static inline void __iomem * +mvebu_gpioreg_edge_cause(struct mvebu_gpio_chip *mvchip) { int cpu; @@ -132,13 +135,15 @@ static inline void __iomem *mvebu_gpioreg_edge_cause(struct mvebu_gpio_chip *mvc return mvchip->membase + GPIO_EDGE_CAUSE_OFF; case MVEBU_GPIO_SOC_VARIANT_ARMADAXP: cpu = smp_processor_id(); - return mvchip->percpu_membase + GPIO_EDGE_CAUSE_ARMADAXP_OFF(cpu); + return mvchip->percpu_membase + + GPIO_EDGE_CAUSE_ARMADAXP_OFF(cpu); default: BUG(); } } -static inline void __iomem *mvebu_gpioreg_edge_mask(struct mvebu_gpio_chip *mvchip) +static inline void __iomem * +mvebu_gpioreg_edge_mask(struct mvebu_gpio_chip *mvchip) { int cpu; @@ -150,7 +155,8 @@ static inline void __iomem *mvebu_gpioreg_edge_mask(struct mvebu_gpio_chip *mvch return mvchip->membase + GPIO_EDGE_MASK_MV78200_OFF(cpu); case MVEBU_GPIO_SOC_VARIANT_ARMADAXP: cpu = smp_processor_id(); - return mvchip->percpu_membase + GPIO_EDGE_MASK_ARMADAXP_OFF(cpu); + return mvchip->percpu_membase + + GPIO_EDGE_MASK_ARMADAXP_OFF(cpu); default: BUG(); } @@ -168,7 +174,8 @@ static void __iomem *mvebu_gpioreg_level_mask(struct mvebu_gpio_chip *mvchip) return mvchip->membase + GPIO_LEVEL_MASK_MV78200_OFF(cpu); case MVEBU_GPIO_SOC_VARIANT_ARMADAXP: cpu = smp_processor_id(); - return mvchip->percpu_membase + GPIO_LEVEL_MASK_ARMADAXP_OFF(cpu); + return mvchip->percpu_membase + + GPIO_LEVEL_MASK_ARMADAXP_OFF(cpu); default: BUG(); } @@ -364,22 +371,22 @@ static void mvebu_gpio_level_irq_unmask(struct irq_data *d) * value of the line or the opposite value. * * Level IRQ handlers: DATA_IN is used directly as cause register. - * Interrupt are masked by LEVEL_MASK registers. + * Interrupt are masked by LEVEL_MASK registers. * Edge IRQ handlers: Change in DATA_IN are latched in EDGE_CAUSE. - * Interrupt are masked by EDGE_MASK registers. + * Interrupt are masked by EDGE_MASK registers. * Both-edge handlers: Similar to regular Edge handlers, but also swaps - * the polarity to catch the next line transaction. - * This is a race condition that might not perfectly - * work on some use cases. + * the polarity to catch the next line transaction. + * This is a race condition that might not perfectly + * work on some use cases. * * Every eight GPIO lines are grouped (OR'ed) before going up to main * cause register. * - * EDGE cause mask - * data-in /--------| |-----| |----\ - * -----| |----- ---- to main cause reg - * X \----------------| |----/ - * polarity LEVEL mask + * EDGE cause mask + * data-in /--------| |-----| |----\ + * -----| |----- ---- to main cause reg + * X \----------------| |----/ + * polarity LEVEL mask * ****************************************************************************/ @@ -394,9 +401,8 @@ static int mvebu_gpio_irq_set_type(struct irq_data *d, unsigned int type) pin = d->hwirq; u = readl_relaxed(mvebu_gpioreg_io_conf(mvchip)) & (1 << pin); - if (!u) { + if (!u) return -EINVAL; - } type &= IRQ_TYPE_SENSE_MASK; if (type == IRQ_TYPE_NONE) @@ -529,13 +535,13 @@ static void mvebu_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) (data_in ^ in_pol) & msk ? "hi" : "lo", in_pol & msk ? "lo" : "hi"); if (!((edg_msk | lvl_msk) & msk)) { - seq_printf(s, " disabled\n"); + seq_puts(s, " disabled\n"); continue; } if (edg_msk & msk) - seq_printf(s, " edge "); + seq_puts(s, " edge "); if (lvl_msk & msk) - seq_printf(s, " level"); + seq_puts(s, " level"); seq_printf(s, " (%s)\n", cause & msk ? "pending" : "clear "); } } @@ -546,15 +552,15 @@ static void mvebu_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) static const struct of_device_id mvebu_gpio_of_match[] = { { .compatible = "marvell,orion-gpio", - .data = (void *) MVEBU_GPIO_SOC_VARIANT_ORION, + .data = (void *) MVEBU_GPIO_SOC_VARIANT_ORION, }, { .compatible = "marvell,mv78200-gpio", - .data = (void *) MVEBU_GPIO_SOC_VARIANT_MV78200, + .data = (void *) MVEBU_GPIO_SOC_VARIANT_MV78200, }, { .compatible = "marvell,armadaxp-gpio", - .data = (void *) MVEBU_GPIO_SOC_VARIANT_ARMADAXP, + .data = (void *) MVEBU_GPIO_SOC_VARIANT_ARMADAXP, }, { /* sentinel */ @@ -661,6 +667,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev) unsigned int ngpios; int soc_variant; int i, cpu, id; + int err; match = of_match_device(mvebu_gpio_of_match, &pdev->dev); if (match) @@ -668,7 +675,8 @@ static int mvebu_gpio_probe(struct platform_device *pdev) else soc_variant = MVEBU_GPIO_SOC_VARIANT_ORION; - mvchip = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_gpio_chip), GFP_KERNEL); + mvchip = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_gpio_chip), + GFP_KERNEL); if (!mvchip) return -ENOMEM; @@ -767,8 +775,8 @@ static int mvebu_gpio_probe(struct platform_device *pdev) * interrupt handlers, with each handler dealing with 8 GPIO * pins. */ for (i = 0; i < 4; i++) { - int irq; - irq = platform_get_irq(pdev, i); + int irq = platform_get_irq(pdev, i); + if (irq < 0) continue; irq_set_handler_data(irq, mvchip); @@ -778,14 +786,16 @@ static int mvebu_gpio_probe(struct platform_device *pdev) mvchip->irqbase = irq_alloc_descs(-1, 0, ngpios, -1); if (mvchip->irqbase < 0) { dev_err(&pdev->dev, "no irqs\n"); - return mvchip->irqbase; + err = mvchip->irqbase; + goto err_gpiochip_add; } gc = irq_alloc_generic_chip("mvebu_gpio_irq", 2, mvchip->irqbase, mvchip->membase, handle_level_irq); if (!gc) { dev_err(&pdev->dev, "Cannot allocate generic irq_chip\n"); - return -ENOMEM; + err = -ENOMEM; + goto err_gpiochip_add; } gc->private = mvchip; @@ -816,18 +826,26 @@ static int mvebu_gpio_probe(struct platform_device *pdev) if (!mvchip->domain) { dev_err(&pdev->dev, "couldn't allocate irq domain %s (DT).\n", mvchip->chip.label); - irq_remove_generic_chip(gc, IRQ_MSK(ngpios), IRQ_NOREQUEST, - IRQ_LEVEL | IRQ_NOPROBE); - kfree(gc); - return -ENODEV; + err = -ENODEV; + goto err_generic_chip; } return 0; + +err_generic_chip: + irq_remove_generic_chip(gc, IRQ_MSK(ngpios), IRQ_NOREQUEST, + IRQ_LEVEL | IRQ_NOPROBE); + kfree(gc); + +err_gpiochip_add: + gpiochip_remove(&mvchip->chip); + + return err; } static struct platform_driver mvebu_gpio_driver = { .driver = { - .name = "mvebu-gpio", + .name = "mvebu-gpio", .of_match_table = mvebu_gpio_of_match, }, .probe = mvebu_gpio_probe, diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c index ad3feec..2fdb04b 100644 --- a/drivers/gpio/gpio-pxa.c +++ b/drivers/gpio/gpio-pxa.c @@ -17,6 +17,7 @@ #include <linux/gpio.h> #include <linux/gpio-pxa.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/irq.h> #include <linux/irqdomain.h> #include <linux/irqchip/chained_irq.h> @@ -27,8 +28,6 @@ #include <linux/syscore_ops.h> #include <linux/slab.h> -#include <mach/irqs.h> - /* * We handle the GPIOs by banks, each bank covers up to 32 GPIOs with * one set of registers. The register offsets are organized below: @@ -42,9 +41,12 @@ * BANK 4 - 0x0104 0x0110 0x011C 0x0128 0x0134 0x0140 0x014C * BANK 5 - 0x0108 0x0114 0x0120 0x012C 0x0138 0x0144 0x0150 * + * BANK 6 - 0x0200 0x020C 0x0218 0x0224 0x0230 0x023C 0x0248 + * * NOTE: * BANK 3 is only available on PXA27x and later processors. - * BANK 4 and 5 are only available on PXA935 + * BANK 4 and 5 are only available on PXA935, PXA1928 + * BANK 6 is only available on PXA1928 */ #define GPLR_OFFSET 0x00 @@ -57,7 +59,8 @@ #define GAFR_OFFSET 0x54 #define ED_MASK_OFFSET 0x9C /* GPIO edge detection for AP side */ -#define BANK_OFF(n) (((n) < 3) ? (n) << 2 : 0x100 + (((n) - 3) << 2)) +#define BANK_OFF(n) (((n) < 3) ? (n) << 2 : ((n) > 5 ? 0x200 : 0x100) \ + + (((n) % 3) << 2)) int pxa_last_gpio; static int irq_base; @@ -93,6 +96,7 @@ enum pxa_gpio_type { PXA93X_GPIO, MMP_GPIO = 0x10, MMP2_GPIO, + PXA1928_GPIO, }; struct pxa_gpio_id { @@ -140,6 +144,11 @@ static struct pxa_gpio_id mmp2_id = { .gpio_nums = 192, }; +static struct pxa_gpio_id pxa1928_id = { + .type = PXA1928_GPIO, + .gpio_nums = 224, +}; + #define for_each_gpio_chip(i, c) \ for (i = 0, c = &pxa_gpio_chips[0]; i <= pxa_last_gpio; i += 32, c++) @@ -487,6 +496,7 @@ static int pxa_gpio_nums(struct platform_device *pdev) case PXA93X_GPIO: case MMP_GPIO: case MMP2_GPIO: + case PXA1928_GPIO: gpio_type = pxa_id->type; count = pxa_id->gpio_nums - 1; break; @@ -506,6 +516,7 @@ static const struct of_device_id pxa_gpio_dt_ids[] = { { .compatible = "marvell,pxa93x-gpio", .data = &pxa93x_id, }, { .compatible = "marvell,mmp-gpio", .data = &mmp_id, }, { .compatible = "marvell,mmp2-gpio", .data = &mmp2_id, }, + { .compatible = "marvell,pxa1928-gpio", .data = &pxa1928_id, }, {} }; @@ -629,19 +640,18 @@ static int pxa_gpio_probe(struct platform_device *pdev) } if (!use_of) { -#ifdef CONFIG_ARCH_PXA - irq = gpio_to_irq(0); - irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip, - handle_edge_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); - irq_set_chained_handler(IRQ_GPIO0, pxa_gpio_demux_handler); - - irq = gpio_to_irq(1); - irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip, - handle_edge_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); - irq_set_chained_handler(IRQ_GPIO1, pxa_gpio_demux_handler); -#endif + if (irq0 > 0) { + irq = gpio_to_irq(0); + irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip, + handle_edge_irq); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + } + if (irq1 > 0) { + irq = gpio_to_irq(1); + irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip, + handle_edge_irq); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + } for (irq = gpio_to_irq(gpio_offset); irq <= gpio_to_irq(pxa_last_gpio); irq++) { @@ -649,13 +659,13 @@ static int pxa_gpio_probe(struct platform_device *pdev) handle_edge_irq); set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); } - } else { - if (irq0 > 0) - irq_set_chained_handler(irq0, pxa_gpio_demux_handler); - if (irq1 > 0) - irq_set_chained_handler(irq1, pxa_gpio_demux_handler); } + if (irq0 > 0) + irq_set_chained_handler(irq0, pxa_gpio_demux_handler); + if (irq1 > 0) + irq_set_chained_handler(irq1, pxa_gpio_demux_handler); + irq_set_chained_handler(irq_mux, pxa_gpio_demux_handler); return 0; } @@ -668,6 +678,7 @@ static const struct platform_device_id gpio_id_table[] = { { "pxa93x-gpio", (unsigned long)&pxa93x_id }, { "mmp-gpio", (unsigned long)&mmp_id }, { "mmp2-gpio", (unsigned long)&mmp2_id }, + { "pxa1928-gpio", (unsigned long)&pxa1928_id }, { }, }; diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index 584484e..c49522e 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -21,7 +21,6 @@ #include <linux/io.h> #include <linux/ioport.h> #include <linux/irq.h> -#include <linux/irqdomain.h> #include <linux/module.h> #include <linux/of.h> #include <linux/pinctrl/consumer.h> @@ -38,7 +37,6 @@ struct gpio_rcar_priv { struct platform_device *pdev; struct gpio_chip gpio_chip; struct irq_chip irq_chip; - struct irq_domain *irq_domain; }; #define IOINTSEL 0x00 @@ -82,14 +80,18 @@ static void gpio_rcar_modify_bit(struct gpio_rcar_priv *p, int offs, static void gpio_rcar_irq_disable(struct irq_data *d) { - struct gpio_rcar_priv *p = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct gpio_rcar_priv *p = container_of(gc, struct gpio_rcar_priv, + gpio_chip); gpio_rcar_write(p, INTMSK, ~BIT(irqd_to_hwirq(d))); } static void gpio_rcar_irq_enable(struct irq_data *d) { - struct gpio_rcar_priv *p = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct gpio_rcar_priv *p = container_of(gc, struct gpio_rcar_priv, + gpio_chip); gpio_rcar_write(p, MSKCLR, BIT(irqd_to_hwirq(d))); } @@ -131,7 +133,9 @@ static void gpio_rcar_config_interrupt_input_mode(struct gpio_rcar_priv *p, static int gpio_rcar_irq_set_type(struct irq_data *d, unsigned int type) { - struct gpio_rcar_priv *p = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct gpio_rcar_priv *p = container_of(gc, struct gpio_rcar_priv, + gpio_chip); unsigned int hwirq = irqd_to_hwirq(d); dev_dbg(&p->pdev->dev, "sense irq = %d, type = %d\n", hwirq, type); @@ -175,7 +179,8 @@ static irqreturn_t gpio_rcar_irq_handler(int irq, void *dev_id) gpio_rcar_read(p, INTMSK))) { offset = __ffs(pending); gpio_rcar_write(p, INTCLR, BIT(offset)); - generic_handle_irq(irq_find_mapping(p->irq_domain, offset)); + generic_handle_irq(irq_find_mapping(p->gpio_chip.irqdomain, + offset)); irqs_handled++; } @@ -265,29 +270,6 @@ static int gpio_rcar_direction_output(struct gpio_chip *chip, unsigned offset, return 0; } -static int gpio_rcar_to_irq(struct gpio_chip *chip, unsigned offset) -{ - return irq_create_mapping(gpio_to_priv(chip)->irq_domain, offset); -} - -static int gpio_rcar_irq_domain_map(struct irq_domain *h, unsigned int irq, - irq_hw_number_t hwirq) -{ - struct gpio_rcar_priv *p = h->host_data; - - dev_dbg(&p->pdev->dev, "map hw irq = %d, irq = %d\n", (int)hwirq, irq); - - irq_set_chip_data(irq, h->host_data); - irq_set_chip_and_handler(irq, &p->irq_chip, handle_level_irq); - set_irq_flags(irq, IRQF_VALID); /* kill me now */ - return 0; -} - -static struct irq_domain_ops gpio_rcar_irq_domain_ops = { - .map = gpio_rcar_irq_domain_map, - .xlate = irq_domain_xlate_twocell, -}; - struct gpio_rcar_info { bool has_both_edge_trigger; }; @@ -372,10 +354,8 @@ static int gpio_rcar_probe(struct platform_device *pdev) int ret; p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL); - if (!p) { - ret = -ENOMEM; - goto err0; - } + if (!p) + return -ENOMEM; p->pdev = pdev; spin_lock_init(&p->lock); @@ -413,7 +393,6 @@ static int gpio_rcar_probe(struct platform_device *pdev) gpio_chip->get = gpio_rcar_get; gpio_chip->direction_output = gpio_rcar_direction_output; gpio_chip->set = gpio_rcar_set; - gpio_chip->to_irq = gpio_rcar_to_irq; gpio_chip->label = name; gpio_chip->dev = dev; gpio_chip->owner = THIS_MODULE; @@ -428,16 +407,19 @@ static int gpio_rcar_probe(struct platform_device *pdev) irq_chip->flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND; - p->irq_domain = irq_domain_add_simple(pdev->dev.of_node, - p->config.number_of_pins, - p->config.irq_base, - &gpio_rcar_irq_domain_ops, p); - if (!p->irq_domain) { - ret = -ENXIO; - dev_err(dev, "cannot initialize irq domain\n"); + ret = gpiochip_add(gpio_chip); + if (ret) { + dev_err(dev, "failed to add GPIO controller\n"); goto err0; } + ret = gpiochip_irqchip_add(&p->gpio_chip, irq_chip, p->config.irq_base, + handle_level_irq, IRQ_TYPE_NONE); + if (ret) { + dev_err(dev, "cannot add irqchip\n"); + goto err1; + } + if (devm_request_irq(dev, irq->start, gpio_rcar_irq_handler, IRQF_SHARED, name, p)) { dev_err(dev, "failed to request IRQ\n"); @@ -445,17 +427,11 @@ static int gpio_rcar_probe(struct platform_device *pdev) goto err1; } - ret = gpiochip_add(gpio_chip); - if (ret) { - dev_err(dev, "failed to add GPIO controller\n"); - goto err1; - } - dev_info(dev, "driving %d GPIOs\n", p->config.number_of_pins); /* warn in case of mismatch if irq base is specified */ if (p->config.irq_base) { - ret = irq_find_mapping(p->irq_domain, 0); + ret = irq_find_mapping(p->gpio_chip.irqdomain, 0); if (p->config.irq_base != ret) dev_warn(dev, "irq base mismatch (%u/%u)\n", p->config.irq_base, ret); @@ -471,7 +447,7 @@ static int gpio_rcar_probe(struct platform_device *pdev) return 0; err1: - irq_domain_remove(p->irq_domain); + gpiochip_remove(&p->gpio_chip); err0: pm_runtime_put(dev); pm_runtime_disable(dev); @@ -484,7 +460,6 @@ static int gpio_rcar_remove(struct platform_device *pdev) gpiochip_remove(&p->gpio_chip); - irq_domain_remove(p->irq_domain); pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); return 0; diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c index 0a0cf13..b72906f 100644 --- a/drivers/gpio/gpio-sch.c +++ b/drivers/gpio/gpio-sch.c @@ -41,7 +41,7 @@ struct sch_gpio { unsigned short resume_base; }; -#define to_sch_gpio(c) container_of(c, struct sch_gpio, chip) +#define to_sch_gpio(gc) container_of(gc, struct sch_gpio, chip) static unsigned sch_gpio_offset(struct sch_gpio *sch, unsigned gpio, unsigned reg) @@ -63,75 +63,59 @@ static unsigned sch_gpio_bit(struct sch_gpio *sch, unsigned gpio) return gpio % 8; } -static void sch_gpio_enable(struct sch_gpio *sch, unsigned gpio) +static int sch_gpio_reg_get(struct gpio_chip *gc, unsigned gpio, unsigned reg) { + struct sch_gpio *sch = to_sch_gpio(gc); unsigned short offset, bit; - u8 enable; - - spin_lock(&sch->lock); + u8 reg_val; - offset = sch_gpio_offset(sch, gpio, GEN); + offset = sch_gpio_offset(sch, gpio, reg); bit = sch_gpio_bit(sch, gpio); - enable = inb(sch->iobase + offset); - if (!(enable & (1 << bit))) - outb(enable | (1 << bit), sch->iobase + offset); + reg_val = !!(inb(sch->iobase + offset) & BIT(bit)); - spin_unlock(&sch->lock); + return reg_val; } -static int sch_gpio_direction_in(struct gpio_chip *gc, unsigned gpio_num) +static void sch_gpio_reg_set(struct gpio_chip *gc, unsigned gpio, unsigned reg, + int val) { struct sch_gpio *sch = to_sch_gpio(gc); - u8 curr_dirs; unsigned short offset, bit; + u8 reg_val; - spin_lock(&sch->lock); + offset = sch_gpio_offset(sch, gpio, reg); + bit = sch_gpio_bit(sch, gpio); - offset = sch_gpio_offset(sch, gpio_num, GIO); - bit = sch_gpio_bit(sch, gpio_num); + reg_val = inb(sch->iobase + offset); - curr_dirs = inb(sch->iobase + offset); + if (val) + outb(reg_val | BIT(bit), sch->iobase + offset); + else + outb((reg_val & ~BIT(bit)), sch->iobase + offset); +} - if (!(curr_dirs & (1 << bit))) - outb(curr_dirs | (1 << bit), sch->iobase + offset); +static int sch_gpio_direction_in(struct gpio_chip *gc, unsigned gpio_num) +{ + struct sch_gpio *sch = to_sch_gpio(gc); + spin_lock(&sch->lock); + sch_gpio_reg_set(gc, gpio_num, GIO, 1); spin_unlock(&sch->lock); return 0; } static int sch_gpio_get(struct gpio_chip *gc, unsigned gpio_num) { - struct sch_gpio *sch = to_sch_gpio(gc); - int res; - unsigned short offset, bit; - - offset = sch_gpio_offset(sch, gpio_num, GLV); - bit = sch_gpio_bit(sch, gpio_num); - - res = !!(inb(sch->iobase + offset) & (1 << bit)); - - return res; + return sch_gpio_reg_get(gc, gpio_num, GLV); } static void sch_gpio_set(struct gpio_chip *gc, unsigned gpio_num, int val) { struct sch_gpio *sch = to_sch_gpio(gc); - u8 curr_vals; - unsigned short offset, bit; spin_lock(&sch->lock); - - offset = sch_gpio_offset(sch, gpio_num, GLV); - bit = sch_gpio_bit(sch, gpio_num); - - curr_vals = inb(sch->iobase + offset); - - if (val) - outb(curr_vals | (1 << bit), sch->iobase + offset); - else - outb((curr_vals & ~(1 << bit)), sch->iobase + offset); - + sch_gpio_reg_set(gc, gpio_num, GLV, val); spin_unlock(&sch->lock); } @@ -139,18 +123,9 @@ static int sch_gpio_direction_out(struct gpio_chip *gc, unsigned gpio_num, int val) { struct sch_gpio *sch = to_sch_gpio(gc); - u8 curr_dirs; - unsigned short offset, bit; spin_lock(&sch->lock); - - offset = sch_gpio_offset(sch, gpio_num, GIO); - bit = sch_gpio_bit(sch, gpio_num); - - curr_dirs = inb(sch->iobase + offset); - if (curr_dirs & (1 << bit)) - outb(curr_dirs & ~(1 << bit), sch->iobase + offset); - + sch_gpio_reg_set(gc, gpio_num, GIO, 0); spin_unlock(&sch->lock); /* @@ -209,13 +184,13 @@ static int sch_gpio_probe(struct platform_device *pdev) * GPIO7 is configured by the CMC as SLPIOVR * Enable GPIO[9:8] core powered gpios explicitly */ - sch_gpio_enable(sch, 8); - sch_gpio_enable(sch, 9); + sch_gpio_reg_set(&sch->chip, 8, GEN, 1); + sch_gpio_reg_set(&sch->chip, 9, GEN, 1); /* * SUS_GPIO[2:0] enabled by default * Enable SUS_GPIO3 resume powered gpio explicitly */ - sch_gpio_enable(sch, 13); + sch_gpio_reg_set(&sch->chip, 13, GEN, 1); break; case PCI_DEVICE_ID_INTEL_ITC_LPC: @@ -230,6 +205,12 @@ static int sch_gpio_probe(struct platform_device *pdev) sch->chip.ngpio = 30; break; + case PCI_DEVICE_ID_INTEL_QUARK_X1000_ILB: + sch->core_base = 0; + sch->resume_base = 2; + sch->chip.ngpio = 8; + break; + default: return -ENODEV; } diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index 85c5b19..dabfb99 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -30,7 +30,7 @@ struct stmpe_gpio { struct stmpe *stmpe; struct device *dev; struct mutex irq_lock; - unsigned norequest_mask; + u32 norequest_mask; /* Caches of interrupt control registers for bus_lock */ u8 regs[CACHE_NR_REGS][CACHE_NR_BANKS]; u8 oldregs[CACHE_NR_REGS][CACHE_NR_BANKS]; @@ -340,13 +340,10 @@ static int stmpe_gpio_probe(struct platform_device *pdev) { struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent); struct device_node *np = pdev->dev.of_node; - struct stmpe_gpio_platform_data *pdata; struct stmpe_gpio *stmpe_gpio; int ret; int irq = 0; - pdata = stmpe->pdata->gpio; - irq = platform_get_irq(pdev, 0); stmpe_gpio = kzalloc(sizeof(struct stmpe_gpio), GFP_KERNEL); @@ -360,19 +357,14 @@ static int stmpe_gpio_probe(struct platform_device *pdev) stmpe_gpio->chip = template_chip; stmpe_gpio->chip.ngpio = stmpe->num_gpios; stmpe_gpio->chip.dev = &pdev->dev; -#ifdef CONFIG_OF stmpe_gpio->chip.of_node = np; -#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) - of_property_read_u32(np, "st,norequest-mask", - &stmpe_gpio->norequest_mask); + of_property_read_u32(np, "st,norequest-mask", + &stmpe_gpio->norequest_mask); if (irq < 0) dev_info(&pdev->dev, @@ -414,9 +406,6 @@ static int stmpe_gpio_probe(struct platform_device *pdev) NULL); } - if (pdata && pdata->setup) - pdata->setup(stmpe, stmpe_gpio->chip.base); - platform_set_drvdata(pdev, stmpe_gpio); return 0; @@ -433,15 +422,9 @@ static int stmpe_gpio_remove(struct platform_device *pdev) { struct stmpe_gpio *stmpe_gpio = platform_get_drvdata(pdev); struct stmpe *stmpe = stmpe_gpio->stmpe; - struct stmpe_gpio_platform_data *pdata = stmpe->pdata->gpio; - - if (pdata && pdata->remove) - pdata->remove(stmpe, stmpe_gpio->chip.base); gpiochip_remove(&stmpe_gpio->chip); - stmpe_disable(stmpe, STMPE_BLOCK_GPIO); - kfree(stmpe_gpio); return 0; diff --git a/drivers/gpio/gpio-sx150x.c b/drivers/gpio/gpio-sx150x.c index bce6c61..458d9d7 100644 --- a/drivers/gpio/gpio-sx150x.c +++ b/drivers/gpio/gpio-sx150x.c @@ -23,23 +23,51 @@ #include <linux/mutex.h> #include <linux/slab.h> #include <linux/i2c/sx150x.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/of_gpio.h> +#include <linux/of_device.h> #define NO_UPDATE_PENDING -1 +/* The chip models of sx150x */ +#define SX150X_456 0 +#define SX150X_789 1 + +struct sx150x_456_pri { + u8 reg_pld_mode; + u8 reg_pld_table0; + u8 reg_pld_table1; + u8 reg_pld_table2; + u8 reg_pld_table3; + u8 reg_pld_table4; + u8 reg_advance; +}; + +struct sx150x_789_pri { + u8 reg_drain; + u8 reg_polarity; + u8 reg_clock; + u8 reg_misc; + u8 reg_reset; + u8 ngpios; +}; + struct sx150x_device_data { + u8 model; u8 reg_pullup; u8 reg_pulldn; - u8 reg_drain; - u8 reg_polarity; u8 reg_dir; u8 reg_data; u8 reg_irq_mask; u8 reg_irq_src; u8 reg_sense; - u8 reg_clock; - u8 reg_misc; - u8 reg_reset; u8 ngpios; + union { + struct sx150x_456_pri x456; + struct sx150x_789_pri x789; + } pri; }; struct sx150x_chip { @@ -59,44 +87,79 @@ struct sx150x_chip { static const struct sx150x_device_data sx150x_devices[] = { [0] = { /* sx1508q */ - .reg_pullup = 0x03, - .reg_pulldn = 0x04, - .reg_drain = 0x05, - .reg_polarity = 0x06, - .reg_dir = 0x07, - .reg_data = 0x08, - .reg_irq_mask = 0x09, - .reg_irq_src = 0x0c, - .reg_sense = 0x0b, - .reg_clock = 0x0f, - .reg_misc = 0x10, - .reg_reset = 0x7d, - .ngpios = 8 + .model = SX150X_789, + .reg_pullup = 0x03, + .reg_pulldn = 0x04, + .reg_dir = 0x07, + .reg_data = 0x08, + .reg_irq_mask = 0x09, + .reg_irq_src = 0x0c, + .reg_sense = 0x0b, + .pri.x789 = { + .reg_drain = 0x05, + .reg_polarity = 0x06, + .reg_clock = 0x0f, + .reg_misc = 0x10, + .reg_reset = 0x7d, + }, + .ngpios = 8, }, [1] = { /* sx1509q */ - .reg_pullup = 0x07, - .reg_pulldn = 0x09, - .reg_drain = 0x0b, - .reg_polarity = 0x0d, - .reg_dir = 0x0f, - .reg_data = 0x11, - .reg_irq_mask = 0x13, - .reg_irq_src = 0x19, - .reg_sense = 0x17, - .reg_clock = 0x1e, - .reg_misc = 0x1f, - .reg_reset = 0x7d, - .ngpios = 16 + .model = SX150X_789, + .reg_pullup = 0x07, + .reg_pulldn = 0x09, + .reg_dir = 0x0f, + .reg_data = 0x11, + .reg_irq_mask = 0x13, + .reg_irq_src = 0x19, + .reg_sense = 0x17, + .pri.x789 = { + .reg_drain = 0x0b, + .reg_polarity = 0x0d, + .reg_clock = 0x1e, + .reg_misc = 0x1f, + .reg_reset = 0x7d, + }, + .ngpios = 16 + }, + [2] = { /* sx1506q */ + .model = SX150X_456, + .reg_pullup = 0x05, + .reg_pulldn = 0x07, + .reg_dir = 0x03, + .reg_data = 0x01, + .reg_irq_mask = 0x09, + .reg_irq_src = 0x0f, + .reg_sense = 0x0d, + .pri.x456 = { + .reg_pld_mode = 0x21, + .reg_pld_table0 = 0x23, + .reg_pld_table1 = 0x25, + .reg_pld_table2 = 0x27, + .reg_pld_table3 = 0x29, + .reg_pld_table4 = 0x2b, + .reg_advance = 0xad, + }, + .ngpios = 16 }, }; static const struct i2c_device_id sx150x_id[] = { {"sx1508q", 0}, {"sx1509q", 1}, + {"sx1506q", 2}, {} }; MODULE_DEVICE_TABLE(i2c, sx150x_id); +static const struct of_device_id sx150x_of_match[] = { + { .compatible = "semtech,sx1508q" }, + { .compatible = "semtech,sx1509q" }, + { .compatible = "semtech,sx1506q" }, + {}, +}; +MODULE_DEVICE_TABLE(of, sx150x_of_match); + static s32 sx150x_i2c_write(struct i2c_client *client, u8 reg, u8 val) { s32 err = i2c_smbus_write_byte_data(client, reg, val); @@ -191,7 +254,7 @@ static int sx150x_get_io(struct sx150x_chip *chip, unsigned offset) static void sx150x_set_oscio(struct sx150x_chip *chip, int val) { sx150x_i2c_write(chip->client, - chip->dev_cfg->reg_clock, + chip->dev_cfg->pri.x789.reg_clock, (val ? 0x1f : 0x10)); } @@ -293,27 +356,11 @@ static int sx150x_gpio_direction_output(struct gpio_chip *gc, return status; } -static int sx150x_gpio_to_irq(struct gpio_chip *gc, unsigned offset) -{ - struct sx150x_chip *chip; - - chip = container_of(gc, struct sx150x_chip, gpio_chip); - - if (offset >= chip->dev_cfg->ngpios) - return -EINVAL; - - if (chip->irq_base < 0) - return -EINVAL; - - return chip->irq_base + offset; -} - static void sx150x_irq_mask(struct irq_data *d) { struct sx150x_chip *chip = irq_data_get_irq_chip_data(d); - unsigned n; + unsigned n = d->hwirq; - n = d->irq - chip->irq_base; chip->irq_masked |= (1 << n); chip->irq_update = n; } @@ -321,9 +368,8 @@ static void sx150x_irq_mask(struct irq_data *d) static void sx150x_irq_unmask(struct irq_data *d) { struct sx150x_chip *chip = irq_data_get_irq_chip_data(d); - unsigned n; + unsigned n = d->hwirq; - n = d->irq - chip->irq_base; chip->irq_masked &= ~(1 << n); chip->irq_update = n; } @@ -336,7 +382,7 @@ static int sx150x_irq_set_type(struct irq_data *d, unsigned int flow_type) if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) return -EINVAL; - n = d->irq - chip->irq_base; + n = d->hwirq; if (flow_type & IRQ_TYPE_EDGE_RISING) val |= 0x1; @@ -371,7 +417,9 @@ static irqreturn_t sx150x_irq_thread_fn(int irq, void *dev_id) val); for (n = 0; n < 8; ++n) { if (val & (1 << n)) { - sub_irq = chip->irq_base + (i * 8) + n; + sub_irq = irq_find_mapping( + chip->gpio_chip.irqdomain, + (i * 8) + n); handle_nested_irq(sub_irq); ++nhandled; } @@ -401,7 +449,7 @@ static void sx150x_irq_bus_sync_unlock(struct irq_data *d) /* Avoid updates if nothing changed */ if (chip->dev_sense == chip->irq_sense && - chip->dev_sense == chip->irq_masked) + chip->dev_masked == chip->irq_masked) goto out; chip->dev_sense = chip->irq_sense; @@ -428,15 +476,19 @@ static void sx150x_init_chip(struct sx150x_chip *chip, chip->client = client; chip->dev_cfg = &sx150x_devices[driver_data]; + chip->gpio_chip.dev = &client->dev; chip->gpio_chip.label = client->name; chip->gpio_chip.direction_input = sx150x_gpio_direction_input; chip->gpio_chip.direction_output = sx150x_gpio_direction_output; chip->gpio_chip.get = sx150x_gpio_get; chip->gpio_chip.set = sx150x_gpio_set; - chip->gpio_chip.to_irq = sx150x_gpio_to_irq; chip->gpio_chip.base = pdata->gpio_base; chip->gpio_chip.can_sleep = true; chip->gpio_chip.ngpio = chip->dev_cfg->ngpios; +#ifdef CONFIG_OF_GPIO + chip->gpio_chip.of_node = client->dev.of_node; + chip->gpio_chip.of_gpio_n_cells = 2; +#endif if (pdata->oscio_is_gpo) ++chip->gpio_chip.ngpio; @@ -470,13 +522,13 @@ static int sx150x_reset(struct sx150x_chip *chip) int err; err = i2c_smbus_write_byte_data(chip->client, - chip->dev_cfg->reg_reset, + chip->dev_cfg->pri.x789.reg_reset, 0x12); if (err < 0) return err; err = i2c_smbus_write_byte_data(chip->client, - chip->dev_cfg->reg_reset, + chip->dev_cfg->pri.x789.reg_reset, 0x34); return err; } @@ -492,9 +544,14 @@ static int sx150x_init_hw(struct sx150x_chip *chip, return err; } - err = sx150x_i2c_write(chip->client, - chip->dev_cfg->reg_misc, - 0x01); + if (chip->dev_cfg->model == SX150X_789) + err = sx150x_i2c_write(chip->client, + chip->dev_cfg->pri.x789.reg_misc, + 0x01); + else + err = sx150x_i2c_write(chip->client, + chip->dev_cfg->pri.x456.reg_advance, + 0x04); if (err < 0) return err; @@ -508,15 +565,27 @@ static int sx150x_init_hw(struct sx150x_chip *chip, if (err < 0) return err; - err = sx150x_init_io(chip, chip->dev_cfg->reg_drain, - pdata->io_open_drain_ena); - if (err < 0) - return err; + if (chip->dev_cfg->model == SX150X_789) { + err = sx150x_init_io(chip, + chip->dev_cfg->pri.x789.reg_drain, + pdata->io_open_drain_ena); + if (err < 0) + return err; + + err = sx150x_init_io(chip, + chip->dev_cfg->pri.x789.reg_polarity, + pdata->io_polarity); + if (err < 0) + return err; + } else { + /* Set all pins to work in normal mode */ + err = sx150x_init_io(chip, + chip->dev_cfg->pri.x456.reg_pld_mode, + 0); + if (err < 0) + return err; + } - err = sx150x_init_io(chip, chip->dev_cfg->reg_polarity, - pdata->io_polarity); - if (err < 0) - return err; if (pdata->oscio_is_gpo) sx150x_set_oscio(chip, 0); @@ -529,31 +598,24 @@ static int sx150x_install_irq_chip(struct sx150x_chip *chip, int irq_base) { int err; - unsigned n; - unsigned irq; chip->irq_summary = irq_summary; chip->irq_base = irq_base; - for (n = 0; n < chip->dev_cfg->ngpios; ++n) { - irq = irq_base + n; - irq_set_chip_data(irq, chip); - irq_set_chip_and_handler(irq, &chip->irq_chip, handle_edge_irq); - irq_set_nested_thread(irq, 1); -#ifdef CONFIG_ARM - set_irq_flags(irq, IRQF_VALID); -#else - irq_set_noprobe(irq); -#endif + /* Add gpio chip to irq subsystem */ + err = gpiochip_irqchip_add(&chip->gpio_chip, + &chip->irq_chip, chip->irq_base, + handle_edge_irq, IRQ_TYPE_EDGE_BOTH); + if (err) { + dev_err(&chip->client->dev, + "could not connect irqchip to gpiochip\n"); + return err; } err = devm_request_threaded_irq(&chip->client->dev, - irq_summary, - NULL, - sx150x_irq_thread_fn, - IRQF_SHARED | IRQF_TRIGGER_FALLING, - chip->irq_chip.name, - chip); + irq_summary, NULL, sx150x_irq_thread_fn, + IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_FALLING, + chip->irq_chip.name, chip); if (err < 0) { chip->irq_summary = -1; chip->irq_base = -1; @@ -562,17 +624,6 @@ static int sx150x_install_irq_chip(struct sx150x_chip *chip, return err; } -static void sx150x_remove_irq_chip(struct sx150x_chip *chip) -{ - unsigned n; - unsigned irq; - - for (n = 0; n < chip->dev_cfg->ngpios; ++n) { - irq = chip->irq_base + n; - irq_set_chip_and_handler(irq, NULL, NULL); - } -} - static int sx150x_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -626,16 +677,14 @@ static int sx150x_remove(struct i2c_client *client) chip = i2c_get_clientdata(client); gpiochip_remove(&chip->gpio_chip); - if (chip->irq_summary >= 0) - sx150x_remove_irq_chip(chip); - return 0; } static struct i2c_driver sx150x_driver = { .driver = { .name = "sx150x", - .owner = THIS_MODULE + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(sx150x_of_match), }, .probe = sx150x_probe, .remove = sx150x_remove, diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c index abdcf58..11aed26 100644 --- a/drivers/gpio/gpio-tc3589x.c +++ b/drivers/gpio/gpio-tc3589x.c @@ -232,16 +232,13 @@ static irqreturn_t tc3589x_gpio_irq(int irq, void *dev) static int tc3589x_gpio_probe(struct platform_device *pdev) { struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent); - struct tc3589x_gpio_platform_data *pdata; struct device_node *np = pdev->dev.of_node; struct tc3589x_gpio *tc3589x_gpio; int ret; int irq; - pdata = tc3589x->pdata->gpio; - - if (!(pdata || np)) { - dev_err(&pdev->dev, "No platform data or Device Tree found\n"); + if (!np) { + dev_err(&pdev->dev, "No Device Tree node found\n"); return -EINVAL; } @@ -305,9 +302,6 @@ static int tc3589x_gpio_probe(struct platform_device *pdev) irq, NULL); - if (pdata && pdata->setup) - pdata->setup(tc3589x, tc3589x_gpio->chip.base); - platform_set_drvdata(pdev, tc3589x_gpio); return 0; @@ -316,11 +310,6 @@ static int tc3589x_gpio_probe(struct platform_device *pdev) static int tc3589x_gpio_remove(struct platform_device *pdev) { struct tc3589x_gpio *tc3589x_gpio = platform_get_drvdata(pdev); - struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; - struct tc3589x_gpio_platform_data *pdata = tc3589x->pdata->gpio; - - if (pdata && pdata->remove) - pdata->remove(tc3589x, tc3589x_gpio->chip.base); gpiochip_remove(&tc3589x_gpio->chip); diff --git a/drivers/gpio/gpio-tz1090-pdc.c b/drivers/gpio/gpio-tz1090-pdc.c index d753622..ede7e40 100644 --- a/drivers/gpio/gpio-tz1090-pdc.c +++ b/drivers/gpio/gpio-tz1090-pdc.c @@ -190,7 +190,7 @@ static int tz1090_pdc_gpio_probe(struct platform_device *pdev) /* Ioremap the registers */ priv->reg = devm_ioremap(&pdev->dev, res_regs->start, - res_regs->end - res_regs->start); + resource_size(res_regs)); if (!priv->reg) { dev_err(&pdev->dev, "unable to ioremap registers\n"); return -ENOMEM; diff --git a/drivers/gpio/gpio-tz1090.c b/drivers/gpio/gpio-tz1090.c index e3024bb..445660a 100644 --- a/drivers/gpio/gpio-tz1090.c +++ b/drivers/gpio/gpio-tz1090.c @@ -573,7 +573,7 @@ static int tz1090_gpio_probe(struct platform_device *pdev) /* Ioremap the registers */ priv.reg = devm_ioremap(&pdev->dev, res_regs->start, - res_regs->end - res_regs->start); + resource_size(res_regs)); if (!priv.reg) { dev_err(&pdev->dev, "unable to ioremap registers\n"); return -ENOMEM; diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c index 4ee4cee..971c739 100644 --- a/drivers/gpio/gpio-vf610.c +++ b/drivers/gpio/gpio-vf610.c @@ -278,7 +278,6 @@ static int vf610_gpio_probe(struct platform_device *pdev) static struct platform_driver vf610_gpio_driver = { .driver = { .name = "gpio-vf610", - .owner = THIS_MODULE, .of_match_table = vf610_gpio_dt_ids, }, .probe = vf610_gpio_probe, diff --git a/drivers/gpio/gpio-vx855.c b/drivers/gpio/gpio-vx855.c index 9d21d2f..57b470d 100644 --- a/drivers/gpio/gpio-vx855.c +++ b/drivers/gpio/gpio-vx855.c @@ -52,8 +52,6 @@ struct vx855_gpio { spinlock_t lock; u32 io_gpi; u32 io_gpo; - bool gpi_reserved; - bool gpo_reserved; }; /* resolve a GPIx into the corresponding bit position */ @@ -224,14 +222,13 @@ static int vx855gpio_probe(struct platform_device *pdev) struct resource *res_gpi; struct resource *res_gpo; struct vx855_gpio *vg; - int ret; res_gpi = platform_get_resource(pdev, IORESOURCE_IO, 0); res_gpo = platform_get_resource(pdev, IORESOURCE_IO, 1); if (!res_gpi || !res_gpo) return -EBUSY; - vg = kzalloc(sizeof(*vg), GFP_KERNEL); + vg = devm_kzalloc(&pdev->dev, sizeof(*vg), GFP_KERNEL); if (!vg) return -ENOMEM; @@ -250,56 +247,27 @@ static int vx855gpio_probe(struct platform_device *pdev) * succeed. Ignore and continue. */ - if (!request_region(res_gpi->start, resource_size(res_gpi), - MODULE_NAME "_gpi")) + if (!devm_request_region(&pdev->dev, res_gpi->start, + resource_size(res_gpi), MODULE_NAME "_gpi")) dev_warn(&pdev->dev, "GPI I/O resource busy, probably claimed by ACPI\n"); - else - vg->gpi_reserved = true; - if (!request_region(res_gpo->start, resource_size(res_gpo), - MODULE_NAME "_gpo")) + if (!devm_request_region(&pdev->dev, res_gpo->start, + resource_size(res_gpo), MODULE_NAME "_gpo")) dev_warn(&pdev->dev, "GPO I/O resource busy, probably claimed by ACPI\n"); - else - vg->gpo_reserved = true; vx855gpio_gpio_setup(vg); - ret = gpiochip_add(&vg->gpio); - if (ret) { - dev_err(&pdev->dev, "failed to register GPIOs\n"); - goto out_release; - } - - return 0; - -out_release: - if (vg->gpi_reserved) - release_region(res_gpi->start, resource_size(res_gpi)); - if (vg->gpo_reserved) - release_region(res_gpi->start, resource_size(res_gpo)); - kfree(vg); - return ret; + return gpiochip_add(&vg->gpio); } static int vx855gpio_remove(struct platform_device *pdev) { struct vx855_gpio *vg = platform_get_drvdata(pdev); - struct resource *res; gpiochip_remove(&vg->gpio); - if (vg->gpi_reserved) { - res = platform_get_resource(pdev, IORESOURCE_IO, 0); - release_region(res->start, resource_size(res)); - } - if (vg->gpo_reserved) { - res = platform_get_resource(pdev, IORESOURCE_IO, 1); - release_region(res->start, resource_size(res)); - } - - kfree(vg); return 0; } diff --git a/drivers/gpio/gpio-xgene-sb.c b/drivers/gpio/gpio-xgene-sb.c new file mode 100644 index 0000000..b6a15c3 --- /dev/null +++ b/drivers/gpio/gpio-xgene-sb.c @@ -0,0 +1,160 @@ +/* + * AppliedMicro X-Gene SoC GPIO-Standby Driver + * + * Copyright (c) 2014, Applied Micro Circuits Corporation + * Author: Tin Huynh <tnhuynh@apm.com>. + * Y Vo <yvo@apm.com>. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * 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/io.h> +#include <linux/platform_device.h> +#include <linux/of_gpio.h> +#include <linux/gpio.h> +#include <linux/gpio/driver.h> +#include <linux/basic_mmio_gpio.h> + +#define XGENE_MAX_GPIO_DS 22 +#define XGENE_MAX_GPIO_DS_IRQ 6 + +#define GPIO_MASK(x) (1U << ((x) % 32)) + +#define MPA_GPIO_INT_LVL 0x0290 +#define MPA_GPIO_OE_ADDR 0x029c +#define MPA_GPIO_OUT_ADDR 0x02a0 +#define MPA_GPIO_IN_ADDR 0x02a4 +#define MPA_GPIO_SEL_LO 0x0294 + +/** + * struct xgene_gpio_sb - GPIO-Standby private data structure. + * @bgc: memory-mapped GPIO controllers. + * @irq: Mapping GPIO pins and interrupt number + * nirq: Number of GPIO pins that supports interrupt + */ +struct xgene_gpio_sb { + struct bgpio_chip bgc; + u32 *irq; + u32 nirq; +}; + +static inline struct xgene_gpio_sb *to_xgene_gpio_sb(struct gpio_chip *gc) +{ + struct bgpio_chip *bgc = to_bgpio_chip(gc); + + return container_of(bgc, struct xgene_gpio_sb, bgc); +} + +static void xgene_gpio_set_bit(struct bgpio_chip *bgc, void __iomem *reg, u32 gpio, int val) +{ + u32 data; + + data = bgc->read_reg(reg); + if (val) + data |= GPIO_MASK(gpio); + else + data &= ~GPIO_MASK(gpio); + bgc->write_reg(reg, data); +} + +static int apm_gpio_sb_to_irq(struct gpio_chip *gc, u32 gpio) +{ + struct xgene_gpio_sb *priv = to_xgene_gpio_sb(gc); + + if (priv->irq[gpio]) + return priv->irq[gpio]; + + return -ENXIO; +} + +static int xgene_gpio_sb_probe(struct platform_device *pdev) +{ + struct xgene_gpio_sb *priv; + u32 ret, i; + u32 default_lines[] = {0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D}; + struct resource *res; + void __iomem *regs; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + regs = devm_ioremap_resource(&pdev->dev, res); + if (!regs) + return PTR_ERR(regs); + + ret = bgpio_init(&priv->bgc, &pdev->dev, 4, + regs + MPA_GPIO_IN_ADDR, + regs + MPA_GPIO_OUT_ADDR, NULL, + regs + MPA_GPIO_OE_ADDR, NULL, 0); + if (ret) + return ret; + + priv->bgc.gc.to_irq = apm_gpio_sb_to_irq; + priv->bgc.gc.ngpio = XGENE_MAX_GPIO_DS; + + priv->nirq = XGENE_MAX_GPIO_DS_IRQ; + + priv->irq = devm_kzalloc(&pdev->dev, sizeof(u32) * XGENE_MAX_GPIO_DS, + GFP_KERNEL); + if (!priv->irq) + return -ENOMEM; + memset(priv->irq, 0, sizeof(u32) * XGENE_MAX_GPIO_DS); + + for (i = 0; i < priv->nirq; i++) { + priv->irq[default_lines[i]] = platform_get_irq(pdev, i); + xgene_gpio_set_bit(&priv->bgc, regs + MPA_GPIO_SEL_LO, + default_lines[i] * 2, 1); + xgene_gpio_set_bit(&priv->bgc, regs + MPA_GPIO_INT_LVL, i, 1); + } + + platform_set_drvdata(pdev, priv); + + ret = gpiochip_add(&priv->bgc.gc); + if (ret) + dev_err(&pdev->dev, "failed to register X-Gene GPIO Standby driver\n"); + else + dev_info(&pdev->dev, "X-Gene GPIO Standby driver registered\n"); + + return ret; +} + +static int xgene_gpio_sb_remove(struct platform_device *pdev) +{ + struct xgene_gpio_sb *priv = platform_get_drvdata(pdev); + + return bgpio_remove(&priv->bgc); +} + +static const struct of_device_id xgene_gpio_sb_of_match[] = { + {.compatible = "apm,xgene-gpio-sb", }, + {}, +}; +MODULE_DEVICE_TABLE(of, xgene_gpio_sb_of_match); + +static struct platform_driver xgene_gpio_sb_driver = { + .driver = { + .name = "xgene-gpio-sb", + .of_match_table = xgene_gpio_sb_of_match, + }, + .probe = xgene_gpio_sb_probe, + .remove = xgene_gpio_sb_remove, +}; +module_platform_driver(xgene_gpio_sb_driver); + +MODULE_AUTHOR("AppliedMicro"); +MODULE_DESCRIPTION("APM X-Gene GPIO Standby driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c index ba18b06..61243d1 100644 --- a/drivers/gpio/gpio-xilinx.c +++ b/drivers/gpio/gpio-xilinx.c @@ -30,7 +30,7 @@ #define XGPIO_CHANNEL_OFFSET 0x8 /* Read/Write access to the GPIO registers */ -#ifdef CONFIG_ARCH_ZYNQ +#if defined(CONFIG_ARCH_ZYNQ) || defined(CONFIG_X86) # define xgpio_readreg(offset) readl(offset) # define xgpio_writereg(offset, val) writel(val, offset) #else @@ -40,37 +40,66 @@ /** * struct xgpio_instance - Stores information about GPIO device - * struct of_mm_gpio_chip mmchip: OF GPIO chip for memory mapped banks - * gpio_state: GPIO state shadow register - * gpio_dir: GPIO direction shadow register - * offset: GPIO channel offset - * gpio_lock: Lock used for synchronization + * @mmchip: OF GPIO chip for memory mapped banks + * @gpio_state: GPIO state shadow register + * @gpio_dir: GPIO direction shadow register + * @gpio_lock: Lock used for synchronization + * @inited: True if the port has been inited */ struct xgpio_instance { struct of_mm_gpio_chip mmchip; - u32 gpio_state; - u32 gpio_dir; - u32 offset; - spinlock_t gpio_lock; + unsigned int gpio_width[2]; + u32 gpio_state[2]; + u32 gpio_dir[2]; + spinlock_t gpio_lock[2]; }; +static inline int xgpio_index(struct xgpio_instance *chip, int gpio) +{ + if (gpio >= chip->gpio_width[0]) + return 1; + + return 0; +} + +static inline int xgpio_regoffset(struct xgpio_instance *chip, int gpio) +{ + if (xgpio_index(chip, gpio)) + return XGPIO_CHANNEL_OFFSET; + + return 0; +} + +static inline int xgpio_offset(struct xgpio_instance *chip, int gpio) +{ + if (xgpio_index(chip, gpio)) + return gpio - chip->gpio_width[0]; + + return gpio; +} + /** * xgpio_get - Read the specified signal of the GPIO device. * @gc: Pointer to gpio_chip device structure. * @gpio: GPIO signal number. * - * This function reads the specified signal of the GPIO device. It returns 0 if - * the signal clear, 1 if signal is set or negative value on error. + * This function reads the specified signal of the GPIO device. + * + * Return: + * 0 if direction of GPIO signals is set as input otherwise it + * returns negative error value. */ static int xgpio_get(struct gpio_chip *gc, unsigned int gpio) { struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); struct xgpio_instance *chip = container_of(mm_gc, struct xgpio_instance, mmchip); + u32 val; - void __iomem *regs = mm_gc->regs + chip->offset; + val = xgpio_readreg(mm_gc->regs + XGPIO_DATA_OFFSET + + xgpio_regoffset(chip, gpio)); - return !!(xgpio_readreg(regs + XGPIO_DATA_OFFSET) & BIT(gpio)); + return !!(val & BIT(xgpio_offset(chip, gpio))); } /** @@ -88,20 +117,21 @@ static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); struct xgpio_instance *chip = container_of(mm_gc, struct xgpio_instance, mmchip); - void __iomem *regs = mm_gc->regs; + int index = xgpio_index(chip, gpio); + int offset = xgpio_offset(chip, gpio); - spin_lock_irqsave(&chip->gpio_lock, flags); + spin_lock_irqsave(&chip->gpio_lock[index], flags); /* Write to GPIO signal and set its direction to output */ if (val) - chip->gpio_state |= BIT(gpio); + chip->gpio_state[index] |= BIT(offset); else - chip->gpio_state &= ~BIT(gpio); + chip->gpio_state[index] &= ~BIT(offset); - xgpio_writereg(regs + chip->offset + XGPIO_DATA_OFFSET, - chip->gpio_state); + xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET + + xgpio_regoffset(chip, gpio), chip->gpio_state[index]); - spin_unlock_irqrestore(&chip->gpio_lock, flags); + spin_unlock_irqrestore(&chip->gpio_lock[index], flags); } /** @@ -109,9 +139,9 @@ static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) * @gc: Pointer to gpio_chip device structure. * @gpio: GPIO signal number. * - * This function sets the direction of specified GPIO signal as input. - * It returns 0 if direction of GPIO signals is set as input otherwise it - * returns negative error value. + * Return: + * 0 - if direction of GPIO signals is set as input + * otherwise it returns negative error value. */ static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) { @@ -119,15 +149,17 @@ static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); struct xgpio_instance *chip = container_of(mm_gc, struct xgpio_instance, mmchip); - void __iomem *regs = mm_gc->regs; + int index = xgpio_index(chip, gpio); + int offset = xgpio_offset(chip, gpio); - spin_lock_irqsave(&chip->gpio_lock, flags); + spin_lock_irqsave(&chip->gpio_lock[index], flags); /* Set the GPIO bit in shadow register and set direction as input */ - chip->gpio_dir |= BIT(gpio); - xgpio_writereg(regs + chip->offset + XGPIO_TRI_OFFSET, chip->gpio_dir); + chip->gpio_dir[index] |= BIT(offset); + xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET + + xgpio_regoffset(chip, gpio), chip->gpio_dir[index]); - spin_unlock_irqrestore(&chip->gpio_lock, flags); + spin_unlock_irqrestore(&chip->gpio_lock[index], flags); return 0; } @@ -138,8 +170,10 @@ static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) * @gpio: GPIO signal number. * @val: Value to be written to specified signal. * - * This function sets the direction of specified GPIO signal as output. If all - * GPIO signals of GPIO chip is configured as input then it returns + * This function sets the direction of specified GPIO signal as output. + * + * Return: + * If all GPIO signals of GPIO chip is configured as input then it returns * error otherwise it returns 0. */ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) @@ -148,80 +182,128 @@ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); struct xgpio_instance *chip = container_of(mm_gc, struct xgpio_instance, mmchip); - void __iomem *regs = mm_gc->regs; + int index = xgpio_index(chip, gpio); + int offset = xgpio_offset(chip, gpio); - spin_lock_irqsave(&chip->gpio_lock, flags); + spin_lock_irqsave(&chip->gpio_lock[index], flags); /* Write state of GPIO signal */ if (val) - chip->gpio_state |= BIT(gpio); + chip->gpio_state[index] |= BIT(offset); else - chip->gpio_state &= ~BIT(gpio); - xgpio_writereg(regs + chip->offset + XGPIO_DATA_OFFSET, - chip->gpio_state); + chip->gpio_state[index] &= ~BIT(offset); + xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET + + xgpio_regoffset(chip, gpio), chip->gpio_state[index]); /* Clear the GPIO bit in shadow register and set direction as output */ - chip->gpio_dir &= ~BIT(gpio); - xgpio_writereg(regs + chip->offset + XGPIO_TRI_OFFSET, chip->gpio_dir); + chip->gpio_dir[index] &= ~BIT(offset); + xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET + + xgpio_regoffset(chip, gpio), chip->gpio_dir[index]); - spin_unlock_irqrestore(&chip->gpio_lock, flags); + spin_unlock_irqrestore(&chip->gpio_lock[index], flags); return 0; } /** * xgpio_save_regs - Set initial values of GPIO pins - * @mm_gc: pointer to memory mapped GPIO chip structure + * @mm_gc: Pointer to memory mapped GPIO chip structure */ static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc) { struct xgpio_instance *chip = container_of(mm_gc, struct xgpio_instance, mmchip); - xgpio_writereg(mm_gc->regs + chip->offset + XGPIO_DATA_OFFSET, - chip->gpio_state); - xgpio_writereg(mm_gc->regs + chip->offset + XGPIO_TRI_OFFSET, - chip->gpio_dir); + xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state[0]); + xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir[0]); + + if (!chip->gpio_width[1]) + return; + + xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET + XGPIO_TRI_OFFSET, + chip->gpio_state[1]); + xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET + XGPIO_TRI_OFFSET, + chip->gpio_dir[1]); +} + +/** + * xgpio_remove - Remove method for the GPIO device. + * @pdev: pointer to the platform device + * + * This function remove gpiochips and frees all the allocated resources. + */ +static int xgpio_remove(struct platform_device *pdev) +{ + struct xgpio_instance *chip = platform_get_drvdata(pdev); + + of_mm_gpiochip_remove(&chip->mmchip); + + return 0; } /** * xgpio_of_probe - Probe method for the GPIO device. - * @np: pointer to device tree node + * @pdev: pointer to the platform device * - * This function probes the GPIO device in the device tree. It initializes the - * driver data structure. It returns 0, if the driver is bound to the GPIO - * device, or a negative value if there is an error. + * Return: + * It returns 0, if the driver is bound to the GPIO device, or + * a negative value if there is an error. */ -static int xgpio_of_probe(struct device_node *np) +static int xgpio_probe(struct platform_device *pdev) { struct xgpio_instance *chip; int status = 0; - const u32 *tree_info; - u32 ngpio; + struct device_node *np = pdev->dev.of_node; + u32 is_dual; - chip = kzalloc(sizeof(*chip), GFP_KERNEL); + chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; - /* Update GPIO state shadow register with default value */ - of_property_read_u32(np, "xlnx,dout-default", &chip->gpio_state); + platform_set_drvdata(pdev, chip); - /* By default, all pins are inputs */ - chip->gpio_dir = 0xFFFFFFFF; + /* Update GPIO state shadow register with default value */ + of_property_read_u32(np, "xlnx,dout-default", &chip->gpio_state[0]); /* Update GPIO direction shadow register with default value */ - of_property_read_u32(np, "xlnx,tri-default", &chip->gpio_dir); + if (of_property_read_u32(np, "xlnx,tri-default", &chip->gpio_dir[0])) + chip->gpio_dir[0] = 0xFFFFFFFF; /* * 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; + if (of_property_read_u32(np, "xlnx,gpio-width", &chip->gpio_width[0])) + chip->gpio_width[0] = 32; + + spin_lock_init(&chip->gpio_lock[0]); + + if (of_property_read_u32(np, "xlnx,is-dual", &is_dual)) + is_dual = 0; + + if (is_dual) { + /* Update GPIO state shadow register with default value */ + of_property_read_u32(np, "xlnx,dout-default-2", + &chip->gpio_state[1]); - spin_lock_init(&chip->gpio_lock); + /* Update GPIO direction shadow register with default value */ + if (of_property_read_u32(np, "xlnx,tri-default-2", + &chip->gpio_dir[1])) + chip->gpio_dir[1] = 0xFFFFFFFF; + /* + * 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", + &chip->gpio_width[1])) + chip->gpio_width[1] = 32; + + spin_lock_init(&chip->gpio_lock[1]); + } + + chip->mmchip.gc.ngpio = chip->gpio_width[0] + chip->gpio_width[1]; + chip->mmchip.gc.dev = &pdev->dev; chip->mmchip.gc.direction_input = xgpio_dir_in; chip->mmchip.gc.direction_output = xgpio_dir_out; chip->mmchip.gc.get = xgpio_get; @@ -232,63 +314,11 @@ static int xgpio_of_probe(struct device_node *np) /* Call the OF gpio helper to setup and register the GPIO device */ status = of_mm_gpiochip_add(np, &chip->mmchip); if (status) { - kfree(chip); pr_err("%s: error in probe function with status %d\n", np->full_name, status); return status; } - pr_info("XGpio: %s: registered, base is %d\n", np->full_name, - chip->mmchip.gc.base); - - tree_info = of_get_property(np, "xlnx,is-dual", NULL); - if (tree_info && be32_to_cpup(tree_info)) { - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (!chip) - return -ENOMEM; - - /* Add dual channel offset */ - chip->offset = XGPIO_CHANNEL_OFFSET; - - /* Update GPIO state shadow register with default value */ - of_property_read_u32(np, "xlnx,dout-default-2", - &chip->gpio_state); - - /* By default, all pins are inputs */ - chip->gpio_dir = 0xFFFFFFFF; - - /* Update GPIO direction shadow register with default value */ - of_property_read_u32(np, "xlnx,tri-default-2", &chip->gpio_dir); - - /* - * 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); - - chip->mmchip.gc.direction_input = xgpio_dir_in; - chip->mmchip.gc.direction_output = xgpio_dir_out; - chip->mmchip.gc.get = xgpio_get; - chip->mmchip.gc.set = xgpio_set; - - chip->mmchip.save_regs = xgpio_save_regs; - - /* Call the OF gpio helper to setup and register the GPIO dev */ - status = of_mm_gpiochip_add(np, &chip->mmchip); - if (status) { - kfree(chip); - pr_err("%s: error in probe function with status %d\n", - np->full_name, status); - return status; - } - pr_info("XGpio: %s: dual channel registered, base is %d\n", - np->full_name, chip->mmchip.gc.base); - } - return 0; } @@ -297,19 +327,29 @@ static const struct of_device_id xgpio_of_match[] = { { /* end of list */ }, }; -static int __init xgpio_init(void) -{ - struct device_node *np; +MODULE_DEVICE_TABLE(of, xgpio_of_match); - for_each_matching_node(np, xgpio_of_match) - xgpio_of_probe(np); +static struct platform_driver xgpio_plat_driver = { + .probe = xgpio_probe, + .remove = xgpio_remove, + .driver = { + .name = "gpio-xilinx", + .of_match_table = xgpio_of_match, + }, +}; - return 0; +static int __init xgpio_init(void) +{ + return platform_driver_register(&xgpio_plat_driver); } -/* Make sure we get initialized before anyone else tries to use us */ subsys_initcall(xgpio_init); -/* No exit call at the moment as we cannot unregister of GPIO chips */ + +static void __exit xgpio_exit(void) +{ + platform_driver_unregister(&xgpio_plat_driver); +} +module_exit(xgpio_exit); MODULE_AUTHOR("Xilinx, Inc."); MODULE_DESCRIPTION("Xilinx GPIO driver"); diff --git a/drivers/gpio/gpio-zevio.c b/drivers/gpio/gpio-zevio.c index f769cd5..6f02d7c 100644 --- a/drivers/gpio/gpio-zevio.c +++ b/drivers/gpio/gpio-zevio.c @@ -181,6 +181,8 @@ static int zevio_gpio_probe(struct platform_device *pdev) if (!controller) return -ENOMEM; + platform_set_drvdata(pdev, controller); + /* Copy our reference */ controller->chip.gc = zevio_gpio_chip; controller->chip.gc.dev = &pdev->dev; @@ -202,6 +204,15 @@ static int zevio_gpio_probe(struct platform_device *pdev) return 0; } +static int zevio_gpio_remove(struct platform_device *pdev) +{ + struct zevio_gpio *controller = platform_get_drvdata(pdev); + + of_mm_gpiochip_remove(&controller->chip); + + return 0; +} + static const struct of_device_id zevio_gpio_of_match[] = { { .compatible = "lsi,zevio-gpio", }, { }, @@ -215,6 +226,7 @@ static struct platform_driver zevio_gpio_driver = { .of_match_table = zevio_gpio_of_match, }, .probe = zevio_gpio_probe, + .remove = zevio_gpio_remove, }; module_platform_driver(zevio_gpio_driver); diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 08261f2..8cad8e4 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -210,6 +210,23 @@ err0: } EXPORT_SYMBOL(of_mm_gpiochip_add); +/** + * of_mm_gpiochip_remove - Remove memory mapped GPIO chip (bank) + * @mm_gc: pointer to the of_mm_gpio_chip allocated structure + */ +void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc) +{ + struct gpio_chip *gc = &mm_gc->gc; + + if (!mm_gc) + return; + + gpiochip_remove(gc); + iounmap(mm_gc->regs); + kfree(gc->label); +} +EXPORT_SYMBOL(of_mm_gpiochip_remove); + #ifdef CONFIG_PINCTRL static void of_gpiochip_add_pin_range(struct gpio_chip *chip) { diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 568aa2b..1ca9295 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1659,7 +1659,7 @@ static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, unsigned int idx, enum gpio_lookup_flags *flags) { - static const char *suffixes[] = { "gpios", "gpio" }; + static const char * const suffixes[] = { "gpios", "gpio" }; char prop_name[32]; /* 32 is max size of property name */ enum of_gpio_flags of_flags; struct gpio_desc *desc; @@ -1667,9 +1667,11 @@ static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, for (i = 0; i < ARRAY_SIZE(suffixes); i++) { if (con_id) - snprintf(prop_name, 32, "%s-%s", con_id, suffixes[i]); + snprintf(prop_name, sizeof(prop_name), "%s-%s", con_id, + suffixes[i]); else - snprintf(prop_name, 32, "%s", suffixes[i]); + snprintf(prop_name, sizeof(prop_name), "%s", + suffixes[i]); desc = of_get_named_gpiod_flags(dev->of_node, prop_name, idx, &of_flags); diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h index fd85cb1..45afc2d 100644 --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h @@ -340,31 +340,32 @@ static inline int desc_to_gpio(const struct gpio_desc *desc) * etc. */ #define __gpiod_get(dev, con_id, flags, ...) __gpiod_get(dev, con_id, flags) -#define gpiod_get(varargs...) __gpiod_get(varargs, 0) +#define gpiod_get(varargs...) __gpiod_get(varargs, GPIOD_ASIS) #define __gpiod_get_index(dev, con_id, index, flags, ...) \ __gpiod_get_index(dev, con_id, index, flags) -#define gpiod_get_index(varargs...) __gpiod_get_index(varargs, 0) +#define gpiod_get_index(varargs...) __gpiod_get_index(varargs, GPIOD_ASIS) #define __gpiod_get_optional(dev, con_id, flags, ...) \ __gpiod_get_optional(dev, con_id, flags) -#define gpiod_get_optional(varargs...) __gpiod_get_optional(varargs, 0) +#define gpiod_get_optional(varargs...) __gpiod_get_optional(varargs, GPIOD_ASIS) #define __gpiod_get_index_optional(dev, con_id, index, flags, ...) \ __gpiod_get_index_optional(dev, con_id, index, flags) #define gpiod_get_index_optional(varargs...) \ - __gpiod_get_index_optional(varargs, 0) + __gpiod_get_index_optional(varargs, GPIOD_ASIS) #define __devm_gpiod_get(dev, con_id, flags, ...) \ __devm_gpiod_get(dev, con_id, flags) -#define devm_gpiod_get(varargs...) __devm_gpiod_get(varargs, 0) +#define devm_gpiod_get(varargs...) __devm_gpiod_get(varargs, GPIOD_ASIS) #define __devm_gpiod_get_index(dev, con_id, index, flags, ...) \ __devm_gpiod_get_index(dev, con_id, index, flags) -#define devm_gpiod_get_index(varargs...) __devm_gpiod_get_index(varargs, 0) +#define devm_gpiod_get_index(varargs...) \ + __devm_gpiod_get_index(varargs, GPIOD_ASIS) #define __devm_gpiod_get_optional(dev, con_id, flags, ...) \ __devm_gpiod_get_optional(dev, con_id, flags) #define devm_gpiod_get_optional(varargs...) \ - __devm_gpiod_get_optional(varargs, 0) + __devm_gpiod_get_optional(varargs, GPIOD_ASIS) #define __devm_gpiod_get_index_optional(dev, con_id, index, flags, ...) \ __devm_gpiod_get_index_optional(dev, con_id, index, flags) #define devm_gpiod_get_index_optional(varargs...) \ - __devm_gpiod_get_index_optional(varargs, 0) + __devm_gpiod_get_index_optional(varargs, GPIOD_ASIS) #if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_GPIO_SYSFS) diff --git a/include/linux/mfd/stmpe.h b/include/linux/mfd/stmpe.h index f742b67..c9d8690 100644 --- a/include/linux/mfd/stmpe.h +++ b/include/linux/mfd/stmpe.h @@ -118,20 +118,6 @@ extern int stmpe_disable(struct stmpe *stmpe, unsigned int blocks); #define STMPE_GPIO_NOREQ_811_TOUCH (0xf0) /** - * struct stmpe_gpio_platform_data - STMPE GPIO platform data - * @norequest_mask: bitmask specifying which GPIOs should _not_ be - * requestable due to different usage (e.g. touch, keypad) - * STMPE_GPIO_NOREQ_* macros can be used here. - * @setup: board specific setup callback. - * @remove: board specific remove callback - */ -struct stmpe_gpio_platform_data { - unsigned norequest_mask; - void (*setup)(struct stmpe *stmpe, unsigned gpio_base); - void (*remove)(struct stmpe *stmpe, unsigned gpio_base); -}; - -/** * struct stmpe_ts_platform_data - stmpe811 touch screen controller platform * data * @sample_time: ADC converstion time in number of clock. @@ -182,7 +168,6 @@ struct stmpe_ts_platform_data { * @irq_over_gpio: true if gpio is used to get irq * @irq_gpio: gpio number over which irq will be requested (significant only if * irq_over_gpio is true) - * @gpio: GPIO-specific platform data * @ts: touchscreen-specific platform data */ struct stmpe_platform_data { @@ -194,7 +179,6 @@ struct stmpe_platform_data { int irq_gpio; int autosleep_timeout; - struct stmpe_gpio_platform_data *gpio; struct stmpe_ts_platform_data *ts; }; diff --git a/include/linux/mfd/tc3589x.h b/include/linux/mfd/tc3589x.h index e1c12d8..c203c9c 100644 --- a/include/linux/mfd/tc3589x.h +++ b/include/linux/mfd/tc3589x.h @@ -163,24 +163,12 @@ struct tc3589x_keypad_platform_data { }; /** - * struct tc3589x_gpio_platform_data - TC3589x GPIO platform data - * @setup: callback for board-specific initialization - * @remove: callback for board-specific teardown - */ -struct tc3589x_gpio_platform_data { - void (*setup)(struct tc3589x *tc3589x, unsigned gpio_base); - void (*remove)(struct tc3589x *tc3589x, unsigned gpio_base); -}; - -/** * struct tc3589x_platform_data - TC3589x platform data * @block: bitmask of blocks to enable (use TC3589x_BLOCK_*) - * @gpio: GPIO-specific platform data * @keypad: keypad-specific platform data */ struct tc3589x_platform_data { unsigned int block; - struct tc3589x_gpio_platform_data *gpio; const struct tc3589x_keypad_platform_data *keypad; }; diff --git a/include/linux/of_gpio.h b/include/linux/of_gpio.h index 38fc050..69dbe31 100644 --- a/include/linux/of_gpio.h +++ b/include/linux/of_gpio.h @@ -52,6 +52,7 @@ extern int of_get_named_gpio_flags(struct device_node *np, extern int of_mm_gpiochip_add(struct device_node *np, struct of_mm_gpio_chip *mm_gc); +extern void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc); extern void of_gpiochip_add(struct gpio_chip *gc); extern void of_gpiochip_remove(struct gpio_chip *gc); |