diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-07 10:53:00 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-07 10:53:00 -0700 |
commit | 27c7651a6a5f143eccd66db38c7a3035e1f8bcfb (patch) | |
tree | c20d3525a2933a8ea7e9ab03022c432b18e0e48a | |
parent | 8b8a7df9a1d87ba413fce246b11f54c636bb456a (diff) | |
parent | 65d876564e989b63b0f769e0e06b9830db97b2d9 (diff) |
Merge tag 'gpio-v3.12-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio
Pull GPIO updates from Linus Walleij:
"This is the bulk of GPIO changes for the v3.12 series:
- A new driver for the TZ1090 PDC which is used on the metag
architecture.
- A new driver for the Kontron ETX or COMexpress GPIO block. This is
found on some ETX x86 devices.
- A new driver for the Fintek Super-I/O chips, used on some x86
boards.
- Added device tree probing on a few select GPIO blocks.
- Drop the Exynos support from the Samsung GPIO driver.
The Samsung maintainers have moved over to use the modernized pin
control driver to provide GPIO for the modern platforms instead.
- The usual bunch of non-critical fixes and cleanups"
* tag 'gpio-v3.12-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (36 commits)
gpio: return -ENOTSUPP if debounce cannot be set
gpio: improve error path in gpiolib
gpio: add GPIO support for F71882FG and F71889F
of: add vendor prefix for Microchip Technology Inc
gpio: mcp23s08: rename the device tree property
gpio: samsung: Drop support for Exynos SoCs
gpio: pcf857x: Remove pdata argument to pcf857x_irq_domain_init()
gpio: pcf857x: Sort headers alphabetically
gpio: max7301: Reverting "Do not force SPI speed when using OF Platform"
gpio: Fix bit masking in Kontron PLD GPIO driver
gpio: pca953x: fix gpio input on gpio offsets >= 8
drivers/gpio: simplify use of devm_ioremap_resource
drivers/gpio/gpio-omap.c: convert comma to semicolon
gpio-lynxpoint: Fix warning about unbalanced pm_runtime_enable
gpio: Fix platform driver name in Kontron PLD GPIO driver
gpio: adnp: Fix segfault if request_threaded_irq fails
gpio: msm: Staticize local variable 'msm_gpio'
gpio: gpiolib-of.c: make error message more meaningful by adding the node name and index
gpio: use dev_get_platdata()
gpio/mxc: add chained_irq_enter/exit() to mx2_gpio_irq_handler
...
58 files changed, 1967 insertions, 1031 deletions
diff --git a/Documentation/devicetree/bindings/gpio/gpio-mcp23s08.txt b/Documentation/devicetree/bindings/gpio/gpio-mcp23s08.txt index 629d0ef17308..daa30174bcc1 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-mcp23s08.txt +++ b/Documentation/devicetree/bindings/gpio/gpio-mcp23s08.txt @@ -3,10 +3,17 @@ Microchip MCP2308/MCP23S08/MCP23017/MCP23S17 driver for Required properties: - compatible : Should be - - "mcp,mcp23s08" for 8 GPIO SPI version - - "mcp,mcp23s17" for 16 GPIO SPI version - - "mcp,mcp23008" for 8 GPIO I2C version or - - "mcp,mcp23017" for 16 GPIO I2C version of the chip + - "mcp,mcp23s08" (DEPRECATED) for 8 GPIO SPI version + - "mcp,mcp23s17" (DEPRECATED) for 16 GPIO SPI version + - "mcp,mcp23008" (DEPRECATED) for 8 GPIO I2C version or + - "mcp,mcp23017" (DEPRECATED) for 16 GPIO I2C version of the chip + + - "microchip,mcp23s08" for 8 GPIO SPI version + - "microchip,mcp23s17" for 16 GPIO SPI version + - "microchip,mcp23008" for 8 GPIO I2C version or + - "microchip,mcp23017" for 16 GPIO I2C version of the chip + NOTE: Do not use the old mcp prefix any more. It is deprecated and will be + removed. - #gpio-cells : Should be two. - first cell is the pin number - second cell is used to specify flags. Flags are currently unused. @@ -15,10 +22,11 @@ Required properties: SPI uses this to specify the chipselect line which the chip is connected to. The driver and the SPI variant of the chip support multiple chips on the same chipselect. Have a look at - mcp,spi-present-mask below. + microchip,spi-present-mask below. Required device specific properties (only for SPI chips): -- mcp,spi-present-mask : This is a present flag, that makes only sense for SPI +- mcp,spi-present-mask (DEPRECATED) +- microchip,spi-present-mask : This is a present flag, that makes only sense for SPI chips - as the name suggests. Multiple SPI chips can share the same SPI chipselect. Set a bit in bit0-7 in this mask to 1 if there is a chip connected with the corresponding spi address set. For example if @@ -26,11 +34,13 @@ Required device specific properties (only for SPI chips): which is 0x08. mcp23s08 chip variant only supports bits 0-3. It is not possible to mix mcp23s08 and mcp23s17 on the same chipselect. Set at least one bit to 1 for SPI chips. + NOTE: Do not use the old mcp prefix any more. It is deprecated and will be + removed. - spi-max-frequency = The maximum frequency this chip is able to handle Example I2C: gpiom1: gpio@20 { - compatible = "mcp,mcp23017"; + compatible = "microchip,mcp23017"; gpio-controller; #gpio-cells = <2>; reg = <0x20>; @@ -38,7 +48,7 @@ gpiom1: gpio@20 { Example SPI: gpiom1: gpio@0 { - compatible = "mcp,mcp23s17"; + compatible = "microchip,mcp23s17"; gpio-controller; #gpio-cells = <2>; spi-present-mask = <0x01>; diff --git a/Documentation/devicetree/bindings/gpio/gpio-palmas.txt b/Documentation/devicetree/bindings/gpio/gpio-palmas.txt new file mode 100644 index 000000000000..08b5b52a3ae0 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio-palmas.txt @@ -0,0 +1,27 @@ +Palmas GPIO controller bindings + +Required properties: +- compatible: + - "ti,palams-gpio" for palma series of the GPIO controller + - "ti,tps80036-gpio" for Palma series device TPS80036. + - "ti,tps65913-gpio" for palma series device TPS65913. + - "ti,tps65914-gpio" for palma series device TPS65914. +- #gpio-cells : Should be two. + - first cell is the gpio 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. + +Note: This gpio node will be sub node of palmas node. + +Example: + palmas: tps65913@58 { + ::::::::::: + palmas_gpio: palmas_gpio { + compatible = "ti,palmas-gpio"; + gpio-controller; + #gpio-cells = <2>; + }; + ::::::::::: + }; diff --git a/Documentation/devicetree/bindings/gpio/gpio-tz1090-pdc.txt b/Documentation/devicetree/bindings/gpio/gpio-tz1090-pdc.txt new file mode 100644 index 000000000000..1fd98ffa8cb7 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio-tz1090-pdc.txt @@ -0,0 +1,45 @@ +ImgTec TZ1090 PDC GPIO Controller + +Required properties: +- compatible: Compatible property value should be "img,tz1090-pdc-gpio". + +- reg: Physical base address of the controller and length of memory mapped + region. This starts at and cover the SOC_GPIO_CONTROL registers. + +- gpio-controller: Specifies that the node is a gpio controller. + +- #gpio-cells: Should be 2. The syntax of the gpio specifier used by client + nodes should have the following values. + <[phandle of the gpio controller node] + [PDC gpio number] + [gpio flags]> + + Values for gpio specifier: + - GPIO number: a value in the range 0 to 6. + - GPIO flags: bit field of flags, as defined in <dt-bindings/gpio/gpio.h>. + Only the following flags are supported: + GPIO_ACTIVE_HIGH + GPIO_ACTIVE_LOW + +Optional properties: +- gpio-ranges: Mapping to pin controller pins (as described in + Documentation/devicetree/bindings/gpio/gpio.txt) + +- interrupts: Individual syswake interrupts (other GPIOs cannot interrupt) + + +Example: + + pdc_gpios: gpio-controller@02006500 { + gpio-controller; + #gpio-cells = <2>; + + compatible = "img,tz1090-pdc-gpio"; + reg = <0x02006500 0x100>; + + interrupt-parent = <&pdc>; + interrupts = <8 IRQ_TYPE_NONE>, /* Syswake 0 */ + <9 IRQ_TYPE_NONE>, /* Syswake 1 */ + <10 IRQ_TYPE_NONE>; /* Syswake 2 */ + gpio-ranges = <&pdc_pinctrl 0 0 7>; + }; diff --git a/Documentation/devicetree/bindings/gpio/gpio-tz1090.txt b/Documentation/devicetree/bindings/gpio/gpio-tz1090.txt new file mode 100644 index 000000000000..174cdf309170 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio-tz1090.txt @@ -0,0 +1,88 @@ +ImgTec TZ1090 GPIO Controller + +Required properties: +- compatible: Compatible property value should be "img,tz1090-gpio". + +- reg: Physical base address of the controller and length of memory mapped + region. + +- #address-cells: Should be 1 (for bank subnodes) + +- #size-cells: Should be 0 (for bank subnodes) + +- Each bank of GPIOs should have a subnode to represent it. + + Bank subnode required properties: + - reg: Index of bank in the range 0 to 2. + + - gpio-controller: Specifies that the node is a gpio controller. + + - #gpio-cells: Should be 2. The syntax of the gpio specifier used by client + nodes should have the following values. + <[phandle of the gpio controller node] + [gpio number within the gpio bank] + [gpio flags]> + + Values for gpio specifier: + - GPIO number: a value in the range 0 to 29. + - GPIO flags: bit field of flags, as defined in <dt-bindings/gpio/gpio.h>. + Only the following flags are supported: + GPIO_ACTIVE_HIGH + GPIO_ACTIVE_LOW + + Bank subnode optional properties: + - gpio-ranges: Mapping to pin controller pins (as described in + Documentation/devicetree/bindings/gpio/gpio.txt) + + - interrupts: Interrupt for the entire bank + + - interrupt-controller: Specifies that the node is an interrupt controller + + - #interrupt-cells: Should be 2. The syntax of the interrupt specifier used by + client nodes should have the following values. + <[phandle of the interurupt controller] + [gpio number within the gpio bank] + [irq flags]> + + Values for irq specifier: + - GPIO number: a value in the range 0 to 29 + - IRQ flags: value to describe edge and level triggering, as defined in + <dt-bindings/interrupt-controller/irq.h>. Only the following flags are + supported: + IRQ_TYPE_EDGE_RISING + IRQ_TYPE_EDGE_FALLING + IRQ_TYPE_EDGE_BOTH + IRQ_TYPE_LEVEL_HIGH + IRQ_TYPE_LEVEL_LOW + + + +Example: + + gpios: gpio-controller@02005800 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "img,tz1090-gpio"; + reg = <0x02005800 0x90>; + + /* bank 0 with an interrupt */ + gpios0: bank@0 { + #gpio-cells = <2>; + #interrupt-cells = <2>; + reg = <0>; + interrupts = <13 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + gpio-ranges = <&pinctrl 0 0 30>; + interrupt-controller; + }; + + /* bank 2 without interrupt */ + gpios2: bank@2 { + #gpio-cells = <2>; + reg = <2>; + gpio-controller; + gpio-ranges = <&pinctrl 0 60 30>; + }; + }; + + diff --git a/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt b/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt index 9b3f1d4a88d6..66416261e14d 100644 --- a/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt +++ b/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt @@ -10,8 +10,9 @@ Required properties: There're three gpio interrupts in arch-pxa, and they're gpio0, gpio1 and gpio_mux. There're only one gpio interrupt in arch-mmp, gpio_mux. -- interrupt-name : Should be the name of irq resource. Each interrupt - binds its interrupt-name. +- interrupt-names : Should be the names of irq resources. Each interrupt + uses its own interrupt name, so there should be as many interrupt names + as referenced interrups. - interrupt-controller : Identifies the node as an interrupt controller. - #interrupt-cells: Specifies the number of cells needed to encode an interrupt source. @@ -24,7 +25,7 @@ Example: compatible = "marvell,mmp-gpio"; reg = <0xd4019000 0x1000>; interrupts = <49>; - interrupt-name = "gpio_mux"; + interrupt-names = "gpio_mux"; gpio-controller; #gpio-cells = <1>; interrupt-controller; diff --git a/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt b/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt index cb3dc7bcd8e6..8655df9440d5 100644 --- a/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt +++ b/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt @@ -23,6 +23,10 @@ Required Properties: Please refer to gpio.txt in this directory for details of gpio-ranges property and the common GPIO bindings used by client devices. +The GPIO controller also acts as an interrupt controller. It uses the default +two cells specifier as described in Documentation/devicetree/bindings/ +interrupt-controller/interrupts.txt. + Example: R8A7779 (R-Car H1) GPIO controller nodes gpio0: gpio@ffc40000 { @@ -33,6 +37,8 @@ Example: R8A7779 (R-Car H1) GPIO controller nodes #gpio-cells = <2>; gpio-controller; gpio-ranges = <&pfc 0 0 32>; + interrupt-controller; + #interrupt-cells = <2>; }; ... gpio6: gpio@ffc46000 { @@ -43,4 +49,6 @@ Example: R8A7779 (R-Car H1) GPIO controller nodes #gpio-cells = <2>; gpio-controller; gpio-ranges = <&pfc 0 192 9>; + interrupt-controller; + #interrupt-cells = <2>; }; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index b571560ed5f9..2956800f0240 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -38,6 +38,7 @@ linux Linux-specific binding lsi LSI Corp. (LSI Logic) marvell Marvell Technology Group Ltd. maxim Maxim Integrated Products +microchip Microchip Technology Inc. mosaixtech Mosaix Technologies, Inc. national National Semiconductor nintendo Nintendo diff --git a/MAINTAINERS b/MAINTAINERS index e775ecaf5d1f..b6b29c38b6b6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1320,7 +1320,6 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: arch/arm/mach-vt8500/ F: drivers/clocksource/vt8500_timer.c -F: drivers/gpio/gpio-vt8500.c F: drivers/i2c/busses/i2c-wmt.c F: drivers/mmc/host/wmt-sdmmc.c F: drivers/pwm/pwm-vt8500.c diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index b2450ba14138..349b16160ac9 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -146,6 +146,16 @@ config GPIO_MM_LANTIQ (EBU) found on Lantiq SoCs. The gpios are output only as they are created by attaching a 16bit latch to the bus. +config GPIO_F7188X + tristate "F71882FG and F71889F GPIO support" + depends on X86 + help + This option enables support for GPIOs found on Fintek Super-I/O + chips F71882FG and F71889F. + + To compile this driver as a module, choose M here: the module will + be called f7188x-gpio. + config GPIO_MPC5200 def_bool y depends on PPC_MPC52xx @@ -242,6 +252,21 @@ config GPIO_TS5500 blocks of the TS-5500: DIO1, DIO2 and the LCD port, and the TS-5600 LCD port. +config GPIO_TZ1090 + bool "Toumaz Xenif TZ1090 GPIO support" + depends on SOC_TZ1090 + select GENERIC_IRQ_CHIP + default y + help + Say yes here to support Toumaz Xenif TZ1090 GPIOs. + +config GPIO_TZ1090_PDC + bool "Toumaz Xenif TZ1090 PDC GPIO support" + depends on SOC_TZ1090 + default y + help + Say yes here to support Toumaz Xenif TZ1090 PDC GPIOs. + config GPIO_XILINX bool "Xilinx GPIO support" depends on PPC_OF || MICROBLAZE || ARCH_ZYNQ @@ -676,6 +701,18 @@ config GPIO_UCB1400 This enables support for the Philips UCB1400 GPIO pins. The UCB1400 is an AC97 audio codec. +comment "LPC GPIO expanders:" + +config GPIO_KEMPLD + tristate "Kontron ETX / COMexpress GPIO" + depends on MFD_KEMPLD + help + This enables support for the PLD GPIO interface on some Kontron ETX + and COMexpress (ETXexpress) modules. + + This driver can also be built as a module. If so, the module will be + called gpio-kempld. + comment "MODULbus GPIO expanders:" config GPIO_JANZ_TTL diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index ef3e983a2f1e..97438bf8434a 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -24,11 +24,13 @@ obj-$(CONFIG_GPIO_DA9055) += gpio-da9055.o obj-$(CONFIG_ARCH_DAVINCI) += gpio-davinci.o obj-$(CONFIG_GPIO_EM) += gpio-em.o obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o +obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o obj-$(CONFIG_GPIO_ICH) += gpio-ich.o obj-$(CONFIG_GPIO_IT8761E) += gpio-it8761e.o obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o +obj-$(CONFIG_GPIO_KEMPLD) += gpio-kempld.o obj-$(CONFIG_ARCH_KS8695) += gpio-ks8695.o obj-$(CONFIG_GPIO_LANGWELL) += gpio-langwell.o obj-$(CONFIG_ARCH_LPC32XX) += gpio-lpc32xx.o @@ -79,6 +81,8 @@ obj-$(CONFIG_GPIO_TPS65912) += gpio-tps65912.o obj-$(CONFIG_GPIO_TS5500) += gpio-ts5500.o obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o obj-$(CONFIG_GPIO_TWL6040) += gpio-twl6040.o +obj-$(CONFIG_GPIO_TZ1090) += gpio-tz1090.o +obj-$(CONFIG_GPIO_TZ1090_PDC) += gpio-tz1090-pdc.o obj-$(CONFIG_GPIO_UCB1400) += gpio-ucb1400.o obj-$(CONFIG_GPIO_VIPERBOARD) += gpio-viperboard.o obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o diff --git a/drivers/gpio/gpio-74x164.c b/drivers/gpio/gpio-74x164.c index 721607904d0a..5d518d5db7a0 100644 --- a/drivers/gpio/gpio-74x164.c +++ b/drivers/gpio/gpio-74x164.c @@ -129,7 +129,7 @@ static int gen_74x164_probe(struct spi_device *spi) if (!chip) return -ENOMEM; - pdata = spi->dev.platform_data; + pdata = dev_get_platdata(&spi->dev); if (pdata && pdata->base) chip->gpio_chip.base = pdata->base; else diff --git a/drivers/gpio/gpio-adnp.c b/drivers/gpio/gpio-adnp.c index e60567fc5073..c0f3fc44ab0e 100644 --- a/drivers/gpio/gpio-adnp.c +++ b/drivers/gpio/gpio-adnp.c @@ -490,15 +490,11 @@ static int adnp_irq_setup(struct adnp *adnp) if (err != 0) { dev_err(chip->dev, "can't request IRQ#%d: %d\n", adnp->client->irq, err); - goto error; + return err; } chip->to_irq = adnp_gpio_to_irq; return 0; - -error: - irq_domain_remove(adnp->domain); - return err; } static void adnp_irq_teardown(struct adnp *adnp) diff --git a/drivers/gpio/gpio-adp5520.c b/drivers/gpio/gpio-adp5520.c index f33f78dcadaa..084337d5514d 100644 --- a/drivers/gpio/gpio-adp5520.c +++ b/drivers/gpio/gpio-adp5520.c @@ -89,7 +89,7 @@ static int adp5520_gpio_direction_output(struct gpio_chip *chip, static int adp5520_gpio_probe(struct platform_device *pdev) { - struct adp5520_gpio_platform_data *pdata = pdev->dev.platform_data; + struct adp5520_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev); struct adp5520_gpio *dev; struct gpio_chip *gc; int ret, i, gpios; diff --git a/drivers/gpio/gpio-adp5588.c b/drivers/gpio/gpio-adp5588.c index 2ba56987db04..90fc4c99c024 100644 --- a/drivers/gpio/gpio-adp5588.c +++ b/drivers/gpio/gpio-adp5588.c @@ -276,7 +276,8 @@ static irqreturn_t adp5588_irq_handler(int irq, void *devid) static int adp5588_irq_setup(struct adp5588_gpio *dev) { struct i2c_client *client = dev->client; - struct adp5588_gpio_platform_data *pdata = client->dev.platform_data; + struct adp5588_gpio_platform_data *pdata = + dev_get_platdata(&client->dev); unsigned gpio; int ret; @@ -349,7 +350,8 @@ static void adp5588_irq_teardown(struct adp5588_gpio *dev) static int adp5588_gpio_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct adp5588_gpio_platform_data *pdata = client->dev.platform_data; + struct adp5588_gpio_platform_data *pdata = + dev_get_platdata(&client->dev); struct adp5588_gpio *dev; struct gpio_chip *gc; int ret, i, revid; @@ -440,7 +442,8 @@ err: static int adp5588_gpio_remove(struct i2c_client *client) { - struct adp5588_gpio_platform_data *pdata = client->dev.platform_data; + struct adp5588_gpio_platform_data *pdata = + dev_get_platdata(&client->dev); struct adp5588_gpio *dev = i2c_get_clientdata(client); int ret; diff --git a/drivers/gpio/gpio-arizona.c b/drivers/gpio/gpio-arizona.c index 0ea853f68db2..fa8b6a762761 100644 --- a/drivers/gpio/gpio-arizona.c +++ b/drivers/gpio/gpio-arizona.c @@ -97,7 +97,7 @@ static struct gpio_chip template_chip = { static int arizona_gpio_probe(struct platform_device *pdev) { struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); - struct arizona_pdata *pdata = arizona->dev->platform_data; + struct arizona_pdata *pdata = dev_get_platdata(arizona->dev); struct arizona_gpio *arizona_gpio; int ret; diff --git a/drivers/gpio/gpio-da9052.c b/drivers/gpio/gpio-da9052.c index 29b11e9b6a78..9b77dc05d4ad 100644 --- a/drivers/gpio/gpio-da9052.c +++ b/drivers/gpio/gpio-da9052.c @@ -216,7 +216,7 @@ static int da9052_gpio_probe(struct platform_device *pdev) return -ENOMEM; gpio->da9052 = dev_get_drvdata(pdev->dev.parent); - pdata = gpio->da9052->dev->platform_data; + pdata = dev_get_platdata(gpio->da9052->dev); gpio->gp = reference_gp; if (pdata && pdata->gpio_base) diff --git a/drivers/gpio/gpio-da9055.c b/drivers/gpio/gpio-da9055.c index fd6dfe382f13..7ef0820032bd 100644 --- a/drivers/gpio/gpio-da9055.c +++ b/drivers/gpio/gpio-da9055.c @@ -150,7 +150,7 @@ static int da9055_gpio_probe(struct platform_device *pdev) return -ENOMEM; gpio->da9055 = dev_get_drvdata(pdev->dev.parent); - pdata = gpio->da9055->dev->platform_data; + pdata = dev_get_platdata(gpio->da9055->dev); gpio->gp = reference_gp; if (pdata && pdata->gpio_base) diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index 5cba855638bf..c6e1f086efe8 100644 --- a/drivers/gpio/gpio-em.c +++ b/drivers/gpio/gpio-em.c @@ -30,6 +30,7 @@ #include <linux/gpio.h> #include <linux/slab.h> #include <linux/module.h> +#include <linux/pinctrl/consumer.h> #include <linux/platform_data/gpio-em.h> struct em_gio_priv { @@ -216,6 +217,21 @@ static int em_gio_to_irq(struct gpio_chip *chip, unsigned offset) return irq_create_mapping(gpio_to_priv(chip)->irq_domain, offset); } +static int em_gio_request(struct gpio_chip *chip, unsigned offset) +{ + return pinctrl_request_gpio(chip->base + offset); +} + +static void em_gio_free(struct gpio_chip *chip, unsigned offset) +{ + pinctrl_free_gpio(chip->base + offset); + + /* Set the GPIO as an input to ensure that the next GPIO request won't + * drive the GPIO pin as an output. + */ + em_gio_direction_input(chip, offset); +} + static int em_gio_irq_domain_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { @@ -237,7 +253,7 @@ static struct irq_domain_ops em_gio_irq_domain_ops = { static int em_gio_probe(struct platform_device *pdev) { struct gpio_em_config pdata_dt; - struct gpio_em_config *pdata = pdev->dev.platform_data; + struct gpio_em_config *pdata = dev_get_platdata(&pdev->dev); struct em_gio_priv *p; struct resource *io[2], *irq[2]; struct gpio_chip *gpio_chip; @@ -308,6 +324,8 @@ static int em_gio_probe(struct platform_device *pdev) gpio_chip->direction_output = em_gio_direction_output; gpio_chip->set = em_gio_set; gpio_chip->to_irq = em_gio_to_irq; + gpio_chip->request = em_gio_request; + gpio_chip->free = em_gio_free; gpio_chip->label = name; gpio_chip->owner = THIS_MODULE; gpio_chip->base = pdata->gpio_base; @@ -351,6 +369,13 @@ static int em_gio_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to add GPIO controller\n"); goto err1; } + + if (pdata->pctl_name) { + ret = gpiochip_add_pin_range(gpio_chip, pdata->pctl_name, 0, + gpio_chip->base, gpio_chip->ngpio); + if (ret < 0) + dev_warn(&pdev->dev, "failed to add pin range\n"); + } return 0; err1: diff --git a/drivers/gpio/gpio-f7188x.c b/drivers/gpio/gpio-f7188x.c new file mode 100644 index 000000000000..9cb8320e1181 --- /dev/null +++ b/drivers/gpio/gpio-f7188x.c @@ -0,0 +1,469 @@ +/* + * GPIO driver for Fintek Super-I/O F71882 and F71889 + * + * Copyright (C) 2010-2013 LaCie + * + * Author: Simon Guinot <simon.guinot@sequanux.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/gpio.h> + +#define DRVNAME "gpio-f7188x" + +/* + * Super-I/O registers + */ +#define SIO_LDSEL 0x07 /* Logical device select */ +#define SIO_DEVID 0x20 /* Device ID (2 bytes) */ +#define SIO_DEVREV 0x22 /* Device revision */ +#define SIO_MANID 0x23 /* Fintek ID (2 bytes) */ + +#define SIO_LD_GPIO 0x06 /* GPIO logical device */ +#define SIO_UNLOCK_KEY 0x87 /* Key to enable Super-I/O */ +#define SIO_LOCK_KEY 0xAA /* Key to disable Super-I/O */ + +#define SIO_FINTEK_ID 0x1934 /* Manufacturer ID */ +#define SIO_F71882_ID 0x0541 /* F71882 chipset ID */ +#define SIO_F71889_ID 0x0909 /* F71889 chipset ID */ + +enum chips { f71882fg, f71889f }; + +static const char * const f7188x_names[] = { + "f71882fg", + "f71889f", +}; + +struct f7188x_sio { + int addr; + enum chips type; +}; + +struct f7188x_gpio_bank { + struct gpio_chip chip; + unsigned int regbase; + struct f7188x_gpio_data *data; +}; + +struct f7188x_gpio_data { + struct f7188x_sio *sio; + int nr_bank; + struct f7188x_gpio_bank *bank; +}; + +/* + * Super-I/O functions. + */ + +static inline int superio_inb(int base, int reg) +{ + outb(reg, base); + return inb(base + 1); +} + +static int superio_inw(int base, int reg) +{ + int val; + + outb(reg++, base); + val = inb(base + 1) << 8; + outb(reg, base); + val |= inb(base + 1); + + return val; +} + +static inline void superio_outb(int base, int reg, int val) +{ + outb(reg, base); + outb(val, base + 1); +} + +static inline int superio_enter(int base) +{ + /* Don't step on other drivers' I/O space by accident. */ + if (!request_muxed_region(base, 2, DRVNAME)) { + pr_err(DRVNAME "I/O address 0x%04x already in use\n", base); + return -EBUSY; + } + + /* According to the datasheet the key must be send twice. */ + outb(SIO_UNLOCK_KEY, base); + outb(SIO_UNLOCK_KEY, base); + + return 0; +} + +static inline void superio_select(int base, int ld) +{ + outb(SIO_LDSEL, base); + outb(ld, base + 1); +} + +static inline void superio_exit(int base) +{ + outb(SIO_LOCK_KEY, base); + release_region(base, 2); +} + +/* + * GPIO chip. + */ + +static int f7188x_gpio_direction_in(struct gpio_chip *chip, unsigned offset); +static int f7188x_gpio_get(struct gpio_chip *chip, unsigned offset); +static int f7188x_gpio_direction_out(struct gpio_chip *chip, + unsigned offset, int value); +static void f7188x_gpio_set(struct gpio_chip *chip, unsigned offset, int value); + +#define F7188X_GPIO_BANK(_base, _ngpio, _regbase) \ + { \ + .chip = { \ + .label = DRVNAME, \ + .owner = THIS_MODULE, \ + .direction_input = f7188x_gpio_direction_in, \ + .get = f7188x_gpio_get, \ + .direction_output = f7188x_gpio_direction_out, \ + .set = f7188x_gpio_set, \ + .base = _base, \ + .ngpio = _ngpio, \ + }, \ + .regbase = _regbase, \ + } + +#define gpio_dir(base) (base + 0) +#define gpio_data_out(base) (base + 1) +#define gpio_data_in(base) (base + 2) +/* Output mode register (0:open drain 1:push-pull). */ +#define gpio_out_mode(base) (base + 3) + +static struct f7188x_gpio_bank f71882_gpio_bank[] = { + F7188X_GPIO_BANK(0 , 8, 0xF0), + F7188X_GPIO_BANK(10, 8, 0xE0), + F7188X_GPIO_BANK(20, 8, 0xD0), + F7188X_GPIO_BANK(30, 4, 0xC0), + F7188X_GPIO_BANK(40, 4, 0xB0), +}; + +static struct f7188x_gpio_bank f71889_gpio_bank[] = { + F7188X_GPIO_BANK(0 , 7, 0xF0), + F7188X_GPIO_BANK(10, 7, 0xE0), + F7188X_GPIO_BANK(20, 8, 0xD0), + F7188X_GPIO_BANK(30, 8, 0xC0), + F7188X_GPIO_BANK(40, 8, 0xB0), + F7188X_GPIO_BANK(50, 5, 0xA0), + F7188X_GPIO_BANK(60, 8, 0x90), + F7188X_GPIO_BANK(70, 8, 0x80), +}; + +static int f7188x_gpio_direction_in(struct gpio_chip *chip, unsigned offset) +{ + int err; + struct f7188x_gpio_bank *bank = + container_of(chip, struct f7188x_gpio_bank, chip); + struct f7188x_sio *sio = bank->data->sio; + u8 dir; + + err = superio_enter(sio->addr); + if (err) + return err; + superio_select(sio->addr, SIO_LD_GPIO); + + dir = superio_inb(sio->addr, gpio_dir(bank->regbase)); + dir &= ~(1 << offset); + superio_outb(sio->addr, gpio_dir(bank->regbase), dir); + + superio_exit(sio->addr); + + return 0; +} + +static int f7188x_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + int err; + struct f7188x_gpio_bank *bank = + container_of(chip, struct f7188x_gpio_bank, chip); + struct f7188x_sio *sio = bank->data->sio; + u8 dir, data; + + err = superio_enter(sio->addr); + if (err) + return err; + superio_select(sio->addr, SIO_LD_GPIO); + + dir = superio_inb(sio->addr, gpio_dir(bank->regbase)); + dir = !!(dir & (1 << offset)); + if (dir) + data = superio_inb(sio->addr, gpio_data_out(bank->regbase)); + else + data = superio_inb(sio->addr, gpio_data_in(bank->regbase)); + + superio_exit(sio->addr); + + return !!(data & 1 << offset); +} + +static int f7188x_gpio_direction_out(struct gpio_chip *chip, + unsigned offset, int value) +{ + int err; + struct f7188x_gpio_bank *bank = + container_of(chip, struct f7188x_gpio_bank, chip); + struct f7188x_sio *sio = bank->data->sio; + u8 dir, data_out; + + err = superio_enter(sio->addr); + if (err) + return err; + superio_select(sio->addr, SIO_LD_GPIO); + + data_out = superio_inb(sio->addr, gpio_data_out(bank->regbase)); + if (value) + data_out |= (1 << offset); + else + data_out &= ~(1 << offset); + superio_outb(sio->addr, gpio_data_out(bank->regbase), data_out); + + dir = superio_inb(sio->addr, gpio_dir(bank->regbase)); + dir |= (1 << offset); + superio_outb(sio->addr, gpio_dir(bank->regbase), dir); + + superio_exit(sio->addr); + + return 0; +} + +static void f7188x_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + int err; + struct f7188x_gpio_bank *bank = + container_of(chip, struct f7188x_gpio_bank, chip); + struct f7188x_sio *sio = bank->data->sio; + u8 data_out; + + err = superio_enter(sio->addr); + if (err) + return; + superio_select(sio->addr, SIO_LD_GPIO); + + data_out = superio_inb(sio->addr, gpio_data_out(bank->regbase)); + if (value) + data_out |= (1 << offset); + else + data_out &= ~(1 << offset); + superio_outb(sio->addr, gpio_data_out(bank->regbase), data_out); + + superio_exit(sio->addr); +} + +/* + * Platform device and driver. + */ + +static int f7188x_gpio_probe(struct platform_device *pdev) +{ + int err; + int i; + struct f7188x_sio *sio = pdev->dev.platform_data; + struct f7188x_gpio_data *data; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + switch (sio->type) { + case f71882fg: + data->nr_bank = ARRAY_SIZE(f71882_gpio_bank); + data->bank = f71882_gpio_bank; + break; + case f71889f: + data->nr_bank = ARRAY_SIZE(f71889_gpio_bank); + data->bank = f71889_gpio_bank; + break; + default: + return -ENODEV; + } + data->sio = sio; + + platform_set_drvdata(pdev, data); + + /* For each GPIO bank, register a GPIO chip. */ + for (i = 0; i < data->nr_bank; i++) { + struct f7188x_gpio_bank *bank = &data->bank[i]; + + bank->chip.dev = &pdev->dev; + bank->data = data; + + err = gpiochip_add(&bank->chip); + if (err) { + dev_err(&pdev->dev, + "Failed to register gpiochip %d: %d\n", + i, err); + goto err_gpiochip; + } + } + + return 0; + +err_gpiochip: + for (i = i - 1; i >= 0; i--) { + struct f7188x_gpio_bank *bank = &data->bank[i]; + int tmp; + + tmp = gpiochip_remove(&bank->chip); + if (tmp < 0) + dev_err(&pdev->dev, + "Failed to remove gpiochip %d: %d\n", + i, tmp); + } + + return err; +} + +static int f7188x_gpio_remove(struct platform_device *pdev) +{ + int err; + int i; + struct f7188x_gpio_data *data = platform_get_drvdata(pdev); + + for (i = 0; i < data->nr_bank; i++) { + struct f7188x_gpio_bank *bank = &data->bank[i]; + + err = gpiochip_remove(&bank->chip); + if (err) { + dev_err(&pdev->dev, + "Failed to remove GPIO gpiochip %d: %d\n", + i, err); + return err; + } + } + + return 0; +} + +static int __init f7188x_find(int addr, struct f7188x_sio *sio) +{ + int err; + u16 devid; + + err = superio_enter(addr); + if (err) + return err; + + err = -ENODEV; + devid = superio_inw(addr, SIO_MANID); + if (devid != SIO_FINTEK_ID) { + pr_debug(DRVNAME ": Not a Fintek device at 0x%08x\n", addr); + goto err; + } + + devid = superio_inw(addr, SIO_DEVID); + switch (devid) { + case SIO_F71882_ID: + sio->type = f71882fg; + break; + case SIO_F71889_ID: + sio->type = f71889f; + break; + default: + pr_info(DRVNAME ": Unsupported Fintek device 0x%04x\n", devid); + goto err; + } + sio->addr = addr; + err = 0; + + pr_info(DRVNAME ": Found %s at %#x, revision %d\n", + f7188x_names[sio->type], + (unsigned int) addr, + (int) superio_inb(addr, SIO_DEVREV)); + +err: + superio_exit(addr); + return err; +} + +static struct platform_device *f7188x_gpio_pdev; + +static int __init +f7188x_gpio_device_add(const struct f7188x_sio *sio) +{ + int err; + + f7188x_gpio_pdev = platform_device_alloc(DRVNAME, -1); + if (!f7188x_gpio_pdev) + return -ENOMEM; + + err = platform_device_add_data(f7188x_gpio_pdev, + sio, sizeof(*sio)); + if (err) { + pr_err(DRVNAME "Platform data allocation failed\n"); + goto err; + } + + err = platform_device_add(f7188x_gpio_pdev); + if (err) { + pr_err(DRVNAME "Device addition failed\n"); + goto err; + } + + return 0; + +err: + platform_device_put(f7188x_gpio_pdev); + + return err; +} + +/* + * Try to match a supported Fintech device by reading the (hard-wired) + * configuration I/O ports. If available, then register both the platform + * device and driver to support the GPIOs. + */ + +static struct platform_driver f7188x_gpio_driver = { + .driver = { + .owner = THIS_MODULE, + .name = DRVNAME, + }, + .probe = f7188x_gpio_probe, + .remove = f7188x_gpio_remove, +}; + +static int __init f7188x_gpio_init(void) +{ + int err; + struct f7188x_sio sio; + + if (f7188x_find(0x2e, &sio) && + f7188x_find(0x4e, &sio)) + return -ENODEV; + + err = platform_driver_register(&f7188x_gpio_driver); + if (!err) { + err = f7188x_gpio_device_add(&sio); + if (err) + platform_driver_unregister(&f7188x_gpio_driver); + } + + return err; +} +subsys_initcall(f7188x_gpio_init); + +static void __exit f7188x_gpio_exit(void) +{ + platform_device_unregister(f7188x_gpio_pdev); + platform_driver_unregister(&f7188x_gpio_driver); +} +module_exit(f7188x_gpio_exit); + +MODULE_DESCRIPTION("GPIO driver for Super-I/O chips F71882FG and F71889F"); +MODULE_AUTHOR("Simon Guinot <simon.guinot@sequanux.org>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-ich.c b/drivers/gpio/gpio-ich.c index 2729e3d2d5bb..814addb62d2c 100644 --- a/drivers/gpio/gpio-ich.c +++ b/drivers/gpio/gpio-ich.c @@ -354,7 +354,7 @@ static int ichx_gpio_probe(struct platform_device *pdev) { struct resource *res_base, *res_pm; int err; - struct lpc_ich_info *ich_info = pdev->dev.platform_data; + struct lpc_ich_info *ich_info = dev_get_platdata(&pdev->dev); if (!ich_info) return -ENODEV; diff --git a/drivers/gpio/gpio-janz-ttl.c b/drivers/gpio/gpio-janz-ttl.c index 7d0a04169a35..2ecd3a09c743 100644 --- a/drivers/gpio/gpio-janz-ttl.c +++ b/drivers/gpio/gpio-janz-ttl.c @@ -149,7 +149,7 @@ static int ttl_probe(struct platform_device *pdev) struct resource *res; int ret; - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); if (!pdata) { dev_err(dev, "no platform data\n"); ret = -ENXIO; diff --git a/drivers/gpio/gpio-kempld.c b/drivers/gpio/gpio-kempld.c new file mode 100644 index 000000000000..efdc3924d7df --- /dev/null +++ b/drivers/gpio/gpio-kempld.c @@ -0,0 +1,219 @@ +/* + * Kontron PLD GPIO driver + * + * Copyright (c) 2010-2013 Kontron Europe GmbH + * Author: Michael Brunner <michael.brunner@kontron.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/bitops.h> +#include <linux/errno.h> +#include <linux/platform_device.h> +#include <linux/gpio.h> +#include <linux/mfd/kempld.h> + +#define KEMPLD_GPIO_MAX_NUM 16 +#define KEMPLD_GPIO_MASK(x) (1 << ((x) % 8)) +#define KEMPLD_GPIO_DIR_NUM(x) (0x40 + (x) / 8) +#define KEMPLD_GPIO_LVL_NUM(x) (0x42 + (x) / 8) +#define KEMPLD_GPIO_EVT_LVL_EDGE 0x46 +#define KEMPLD_GPIO_IEN 0x4A + +struct kempld_gpio_data { + struct gpio_chip chip; + struct kempld_device_data *pld; +}; + +/* + * Set or clear GPIO bit + * kempld_get_mutex must be called prior to calling this function. + */ +static void kempld_gpio_bitop(struct kempld_device_data *pld, + u8 reg, u8 bit, u8 val) +{ + u8 status; + + status = kempld_read8(pld, reg); + if (val) + status |= KEMPLD_GPIO_MASK(bit); + else + status &= ~KEMPLD_GPIO_MASK(bit); + kempld_write8(pld, reg, status); +} + +static int kempld_gpio_get_bit(struct kempld_device_data *pld, u8 reg, u8 bit) +{ + u8 status; + + kempld_get_mutex(pld); + status = kempld_read8(pld, reg); + kempld_release_mutex(pld); + + return !!(status & KEMPLD_GPIO_MASK(bit)); +} + +static int kempld_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct kempld_gpio_data *gpio + = container_of(chip, struct kempld_gpio_data, chip); + struct kempld_device_data *pld = gpio->pld; + + return kempld_gpio_get_bit(pld, KEMPLD_GPIO_LVL_NUM(offset), offset); +} + +static void kempld_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct kempld_gpio_data *gpio + = container_of(chip, struct kempld_gpio_data, chip); + struct kempld_device_data *pld = gpio->pld; + + kempld_get_mutex(pld); + kempld_gpio_bitop(pld, KEMPLD_GPIO_LVL_NUM(offset), offset, value); + kempld_release_mutex(pld); +} + +static int kempld_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + struct kempld_gpio_data *gpio + = container_of(chip, struct kempld_gpio_data, chip); + struct kempld_device_data *pld = gpio->pld; + + kempld_get_mutex(pld); + kempld_gpio_bitop(pld, KEMPLD_GPIO_DIR_NUM(offset), offset, 0); + kempld_release_mutex(pld); + + return 0; +} + +static int kempld_gpio_direction_output(struct gpio_chip *chip, unsigned offset, + int value) +{ + struct kempld_gpio_data *gpio + = container_of(chip, struct kempld_gpio_data, chip); + struct kempld_device_data *pld = gpio->pld; + + kempld_get_mutex(pld); + kempld_gpio_bitop(pld, KEMPLD_GPIO_LVL_NUM(offset), offset, value); + kempld_gpio_bitop(pld, KEMPLD_GPIO_DIR_NUM(offset), offset, 1); + kempld_release_mutex(pld); + + return 0; +} + +static int kempld_gpio_get_direction(struct gpio_chip *chip, unsigned offset) +{ + struct kempld_gpio_data *gpio + = container_of(chip, struct kempld_gpio_data, chip); + struct kempld_device_data *pld = gpio->pld; + + return kempld_gpio_get_bit(pld, KEMPLD_GPIO_DIR_NUM(offset), offset); +} + +static int kempld_gpio_pincount(struct kempld_device_data *pld) +{ + u16 evt, evt_back; + + kempld_get_mutex(pld); + + /* Backup event register as it might be already initialized */ + evt_back = kempld_read16(pld, KEMPLD_GPIO_EVT_LVL_EDGE); + /* Clear event register */ + kempld_write16(pld, KEMPLD_GPIO_EVT_LVL_EDGE, 0x0000); + /* Read back event register */ + evt = kempld_read16(pld, KEMPLD_GPIO_EVT_LVL_EDGE); + /* Restore event register */ + kempld_write16(pld, KEMPLD_GPIO_EVT_LVL_EDGE, evt_back); + + kempld_release_mutex(pld); + + return evt ? __ffs(evt) : 16; +} + +static int kempld_gpio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct kempld_device_data *pld = dev_get_drvdata(dev->parent); + struct kempld_platform_data *pdata = dev_get_platdata(pld->dev); + struct kempld_gpio_data *gpio; + struct gpio_chip *chip; + int ret; + + if (pld->info.spec_major < 2) { + dev_err(dev, + "Driver only supports GPIO devices compatible to PLD spec. rev. 2.0 or higher\n"); + return -ENODEV; + } + + gpio = devm_kzalloc(dev, sizeof(*gpio), GFP_KERNEL); + if (gpio == NULL) + return -ENOMEM; + + gpio->pld = pld; + + platform_set_drvdata(pdev, gpio); + + chip = &gpio->chip; + chip->label = "gpio-kempld"; + chip->owner = THIS_MODULE; + chip->dev = dev; + chip->can_sleep = 1; + if (pdata && pdata->gpio_base) + chip->base = pdata->gpio_base; + else + chip->base = -1; + chip->direction_input = kempld_gpio_direction_input; + chip->direction_output = kempld_gpio_direction_output; + chip->get_direction = kempld_gpio_get_direction; + chip->get = kempld_gpio_get; + chip->set = kempld_gpio_set; + chip->ngpio = kempld_gpio_pincount(pld); + if (chip->ngpio == 0) { + dev_err(dev, "No GPIO pins detected\n"); + return -ENODEV; + } + + ret = gpiochip_add(chip); + if (ret) { + dev_err(dev, "Could not register GPIO chip\n"); + return ret; + } + + dev_info(dev, "GPIO functionality initialized with %d pins\n", + chip->ngpio); + + return 0; +} + +static int kempld_gpio_remove(struct platform_device *pdev) +{ + struct kempld_gpio_data *gpio = platform_get_drvdata(pdev); + + return gpiochip_remove(&gpio->chip); +} + +static struct platform_driver kempld_gpio_driver = { + .driver = { + .name = "kempld-gpio", + .owner = THIS_MODULE, + }, + .probe = kempld_gpio_probe, + .remove = kempld_gpio_remove, +}; + +module_platform_driver(kempld_gpio_driver); + +MODULE_DESCRIPTION("KEM PLD GPIO Driver"); +MODULE_AUTHOR("Michael Brunner <michael.brunner@kontron.com>"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:gpio-kempld"); diff --git a/drivers/gpio/gpio-lynxpoint.c b/drivers/gpio/gpio-lynxpoint.c index 761c4705dfbb..2d9ca6055e5e 100644 --- a/drivers/gpio/gpio-lynxpoint.c +++ b/drivers/gpio/gpio-lynxpoint.c @@ -444,6 +444,7 @@ static int lp_gpio_remove(struct platform_device *pdev) { struct lp_gpio *lg = platform_get_drvdata(pdev); int err; + pm_runtime_disable(&pdev->dev); err = gpiochip_remove(&lg->chip); if (err) dev_warn(&pdev->dev, "failed to remove gpio_chip.\n"); diff --git a/drivers/gpio/gpio-max7301.c b/drivers/gpio/gpio-max7301.c index 3b16ab701630..6e1c984a75d4 100644 --- a/drivers/gpio/gpio-max7301.c +++ b/drivers/gpio/gpio-max7301.c @@ -56,8 +56,7 @@ static int max7301_probe(struct spi_device *spi) int ret; /* bits_per_word cannot be configured in platform data */ - if (spi->dev.platform_data) - spi->bits_per_word = 16; + spi->bits_per_word = 16; ret = spi_setup(spi); if (ret < 0) return ret; diff --git a/drivers/gpio/gpio-max730x.c b/drivers/gpio/gpio-max730x.c index 00092342b84c..f4f4ed19bdc1 100644 --- a/drivers/gpio/gpio-max730x.c +++ b/drivers/gpio/gpio-max730x.c @@ -166,7 +166,7 @@ int __max730x_probe(struct max7301 *ts) struct max7301_platform_data *pdata; int i, ret; - pdata = dev->platform_data; + pdata = dev_get_platdata(dev); mutex_init(&ts->lock); dev_set_drvdata(dev, ts); diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c index d4b51b163b03..91ad74dea8ce 100644 --- a/drivers/gpio/gpio-max732x.c +++ b/drivers/gpio/gpio-max732x.c @@ -453,7 +453,7 @@ static int max732x_irq_setup(struct max732x_chip *chip, const struct i2c_device_id *id) { struct i2c_client *client = chip->client; - struct max732x_platform_data *pdata = client->dev.platform_data; + struct max732x_platform_data *pdata = dev_get_platdata(&client->dev); int has_irq = max732x_features[id->driver_data] >> 32; int ret; @@ -512,7 +512,7 @@ static int max732x_irq_setup(struct max732x_chip *chip, const struct i2c_device_id *id) { struct i2c_client *client = chip->client; - struct max732x_platform_data *pdata = client->dev.platform_data; + 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) @@ -583,7 +583,7 @@ static int max732x_probe(struct i2c_client *client, uint16_t addr_a, addr_b; int ret, nr_port; - pdata = client->dev.platform_data; + pdata = dev_get_platdata(&client->dev); if (pdata == NULL) { dev_dbg(&client->dev, "no platform data\n"); return -EINVAL; @@ -653,7 +653,7 @@ out_failed: static int max732x_remove(struct i2c_client *client) { - struct max732x_platform_data *pdata = client->dev.platform_data; + struct max732x_platform_data *pdata = dev_get_platdata(&client->dev); struct max732x_chip *chip = i2c_get_clientdata(client); int ret; diff --git a/drivers/gpio/gpio-mc33880.c b/drivers/gpio/gpio-mc33880.c index 63a7a1bfb2d9..3fd2caa4a2e0 100644 --- a/drivers/gpio/gpio-mc33880.c +++ b/drivers/gpio/gpio-mc33880.c @@ -86,7 +86,7 @@ static int mc33880_probe(struct spi_device *spi) struct mc33880_platform_data *pdata; int ret; - pdata = spi->dev.platform_data; + pdata = dev_get_platdata(&spi->dev); if (!pdata || !pdata->base) { dev_dbg(&spi->dev, "incorrect or missing platform data\n"); return -EINVAL; diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c index 6a4470b84488..2deb0c5e54a4 100644 --- a/drivers/gpio/gpio-mcp23s08.c +++ b/drivers/gpio/gpio-mcp23s08.c @@ -483,10 +483,21 @@ fail: #ifdef CONFIG_SPI_MASTER static struct of_device_id mcp23s08_spi_of_match[] = { { - .compatible = "mcp,mcp23s08", .data = (void *) MCP_TYPE_S08, + .compatible = "microchip,mcp23s08", + .data = (void *) MCP_TYPE_S08, }, { - .compatible = "mcp,mcp23s17", .data = (void *) MCP_TYPE_S17, + .compatible = "microchip,mcp23s17", + .data = (void *) MCP_TYPE_S17, + }, +/* NOTE: The use of the mcp prefix is deprecated and will be removed. */ + { + .compatible = "mcp,mcp23s08", + .data = (void *) MCP_TYPE_S08, + }, + { + .compatible = "mcp,mcp23s17", + .data = (void *) MCP_TYPE_S17, }, { }, }; @@ -496,10 +507,21 @@ MODULE_DEVICE_TABLE(of, mcp23s08_spi_of_match); #if IS_ENABLED(CONFIG_I2C) static struct of_device_id mcp23s08_i2c_of_match[] = { { - .compatible = "mcp,mcp23008", .data = (void *) MCP_TYPE_008, + .compatible = "microchip,mcp23008", + .data = (void *) MCP_TYPE_008, + }, + { + .compatible = "microchip,mcp23017", + .data = (void *) MCP_TYPE_017, + }, +/* NOTE: The use of the mcp prefix is deprecated and will be removed. */ + { + .compatible = "mcp,mcp23008", + .data = (void *) MCP_TYPE_008, }, { - .compatible = "mcp,mcp23017", .data = (void *) MCP_TYPE_017, + .compatible = "mcp,mcp23017", + .data = (void *) MCP_TYPE_017, }, { }, }; @@ -520,14 +542,13 @@ static int mcp230xx_probe(struct i2c_client *client, match = of_match_device(of_match_ptr(mcp23s08_i2c_of_match), &client->dev); - if (match) { + pdata = dev_get_platdata(&client->dev); + if (match || !pdata) { base = -1; pullups = 0; } else { - pdata = client->dev.platform_data; - if (!pdata || !gpio_is_valid(pdata->base)) { - dev_dbg(&client->dev, - "invalid or missing platform data\n"); + if (!gpio_is_valid(pdata->base)) { + dev_dbg(&client->dev, "invalid platform data\n"); return -EINVAL; } base = pdata->base; @@ -621,10 +642,15 @@ static int mcp23s08_probe(struct spi_device *spi) if (match) { type = (int)match->data; status = of_property_read_u32(spi->dev.of_node, - "mcp,spi-present-mask", &spi_present_mask); + "microchip,spi-present-mask", &spi_present_mask); if (status) { - dev_err(&spi->dev, "DT has no spi-present-mask\n"); - return -ENODEV; + status = of_property_read_u32(spi->dev.of_node, + "mcp,spi-present-mask", &spi_present_mask); + if (status) { + dev_err(&spi->dev, + "DT has no spi-present-mask\n"); + return -ENODEV; + } } if ((spi_present_mask <= 0) || (spi_present_mask >= 256)) { dev_err(&spi->dev, "invalid spi-present-mask\n"); @@ -635,7 +661,7 @@ static int mcp23s08_probe(struct spi_device *spi) pullups[addr] = 0; } else { type = spi_get_device_id(spi)->driver_data; - pdata = spi->dev.platform_data; + pdata = dev_get_platdata(&spi->dev); if (!pdata || !gpio_is_valid(pdata->base)) { dev_dbg(&spi->dev, "invalid or missing platform data\n"); diff --git a/drivers/gpio/gpio-msic.c b/drivers/gpio/gpio-msic.c index 27ea7b9257ff..d75eaa3a1dcc 100644 --- a/drivers/gpio/gpio-msic.c +++ b/drivers/gpio/gpio-msic.c @@ -259,7 +259,7 @@ static void msic_gpio_irq_handler(unsigned irq, struct irq_desc *desc) static int platform_msic_gpio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct intel_msic_gpio_pdata *pdata = dev->platform_data; + struct intel_msic_gpio_pdata *pdata = dev_get_platdata(dev); struct msic_gpio *mg; int irq = platform_get_irq(pdev, 0); int retval; diff --git a/drivers/gpio/gpio-msm-v2.c b/drivers/gpio/gpio-msm-v2.c index c2fa77086eb5..f7a0cc4da950 100644 --- a/drivers/gpio/gpio-msm-v2.c +++ b/drivers/gpio/gpio-msm-v2.c @@ -106,7 +106,7 @@ struct msm_gpio_dev { void __iomem *msm_tlmm_base; }; -struct msm_gpio_dev msm_gpio; +static struct msm_gpio_dev msm_gpio; #define GPIO_INTR_CFG_SU(gpio) (msm_gpio.msm_tlmm_base + 0x0400 + \ (0x04 * (gpio))) diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 80ad35e2a8cd..3c3321f94053 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -566,12 +566,6 @@ static int mvebu_gpio_probe(struct platform_device *pdev) else soc_variant = MVEBU_GPIO_SOC_VARIANT_ORION; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "Cannot get memory resource\n"); - return -ENODEV; - } - mvchip = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_gpio_chip), GFP_KERNEL); if (!mvchip) { dev_err(&pdev->dev, "Cannot allocate memory\n"); @@ -611,6 +605,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev) mvchip->chip.dbg_show = mvebu_gpio_dbg_show; spin_lock_init(&mvchip->lock); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); mvchip->membase = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(mvchip->membase)) return PTR_ERR(mvchip->membase); diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c index 7176743915d3..3307f6db3a92 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c @@ -19,6 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include <linux/err.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/io.h> @@ -291,6 +292,9 @@ static void mx2_gpio_irq_handler(u32 irq, struct irq_desc *desc) { u32 irq_msk, irq_stat; struct mxc_gpio_port *port; + struct irq_chip *chip = irq_get_chip(irq); + + chained_irq_enter(chip, desc); /* walk through all interrupt status registers */ list_for_each_entry(port, &mxc_gpio_ports, node) { @@ -302,6 +306,7 @@ static void mx2_gpio_irq_handler(u32 irq, struct irq_desc *desc) if (irq_stat) mxc_gpio_irq_handler(port, irq_stat); } + chained_irq_exit(chip, desc); } /* @@ -405,34 +410,19 @@ static int mxc_gpio_probe(struct platform_device *pdev) mxc_gpio_get_hw(pdev); - port = kzalloc(sizeof(struct mxc_gpio_port), GFP_KERNEL); + port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL); if (!port) return -ENOMEM; iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!iores) { - err = -ENODEV; - goto out_kfree; - } - - if (!request_mem_region(iores->start, resource_size(iores), - pdev->name)) { - err = -EBUSY; - goto out_kfree; - } - - port->base = ioremap(iores->start, resource_size(iores)); - if (!port->base) { - err = -ENOMEM; - goto out_release_mem; - } + port->base = devm_ioremap_resource(&pdev->dev, iores); + if (IS_ERR(port->base)) + return PTR_ERR(port->base); port->irq_high = platform_get_irq(pdev, 1); port->irq = platform_get_irq(pdev, 0); - if (port->irq < 0) { - err = -EINVAL; - goto out_iounmap; - } + if (port->irq < 0) + return -EINVAL; /* disable the interrupt and clear the status */ writel(0, port->base + GPIO_IMR); @@ -462,7 +452,7 @@ static int mxc_gpio_probe(struct platform_device *pdev) port->base + GPIO_DR, NULL, port->base + GPIO_GDIR, NULL, 0); if (err) - goto out_iounmap; + goto out_bgio; port->bgc.gc.to_irq = mxc_gpio_to_irq; port->bgc.gc.base = (pdev->id < 0) ? of_alias_get_id(np, "gpio") * 32 : @@ -498,12 +488,7 @@ out_gpiochip_remove: WARN_ON(gpiochip_remove(&port->bgc.gc) < 0); out_bgpio_remove: bgpio_remove(&port->bgc); -out_iounmap: - iounmap(port->base); -out_release_mem: - release_mem_region(iores->start, resource_size(iores)); -out_kfree: - kfree(port); +out_bgio: dev_info(&pdev->dev, "%s failed with errno %d\n", __func__, err); return err; } diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index dfeb3a3a8f20..0ff43552d472 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1030,7 +1030,7 @@ omap_mpuio_alloc_gc(struct gpio_bank *bank, unsigned int irq_start, ct->chip.irq_set_type = gpio_irq_type; if (bank->regs->wkup_en) - ct->chip.irq_set_wake = gpio_wake_enable, + ct->chip.irq_set_wake = gpio_wake_enable; ct->regs.mask = OMAP_MPUIO_GPIO_INT / bank->stride; irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE, @@ -1100,7 +1100,7 @@ static int omap_gpio_probe(struct platform_device *pdev) match = of_match_device(of_match_ptr(omap_gpio_match), dev); - pdata = match ? match->data : dev->platform_data; + pdata = match ? match->data : dev_get_platdata(dev); if (!pdata) return -EINVAL; diff --git a/drivers/gpio/gpio-palmas.c b/drivers/gpio/gpio-palmas.c index e3a4e56f5a42..8588af0f7661 100644 --- a/drivers/gpio/gpio-palmas.c +++ b/drivers/gpio/gpio-palmas.c @@ -43,9 +43,22 @@ static int palmas_gpio_get(struct gpio_chip *gc, unsigned offset) unsigned int val; int ret; - ret = palmas_read(palmas, PALMAS_GPIO_BASE, PALMAS_GPIO_DATA_IN, &val); + ret = palmas_read(palmas, PALMAS_GPIO_BASE, PALMAS_GPIO_DATA_DIR, &val); if (ret < 0) { - dev_err(gc->dev, "GPIO_DATA_IN read failed, err = %d\n", ret); + dev_err(gc->dev, "GPIO_DATA_DIR read failed, err = %d\n", ret); + return ret; + } + + if (val & (1 << offset)) { + ret = palmas_read(palmas, PALMAS_GPIO_BASE, + PALMAS_GPIO_DATA_OUT, &val); + } else { + ret = palmas_read(palmas, PALMAS_GPIO_BASE, + PALMAS_GPIO_DATA_IN, &val); + } + if (ret < 0) { + dev_err(gc->dev, "GPIO_DATA_IN/OUT read failed, err = %d\n", + ret); return ret; } return !!(val & BIT(offset)); @@ -134,7 +147,7 @@ static int palmas_gpio_probe(struct platform_device *pdev) palmas_gpio->gpio_chip.get = palmas_gpio_get; palmas_gpio->gpio_chip.dev = &pdev->dev; #ifdef CONFIG_OF_GPIO - palmas_gpio->gpio_chip.of_node = palmas->dev->of_node; + palmas_gpio->gpio_chip.of_node = pdev->dev.of_node; #endif palmas_pdata = dev_get_platdata(palmas->dev); if (palmas_pdata && palmas_pdata->gpio_base) @@ -159,9 +172,19 @@ static int palmas_gpio_remove(struct platform_device *pdev) return gpiochip_remove(&palmas_gpio->gpio_chip); } +static struct of_device_id of_palmas_gpio_match[] = { + { .compatible = "ti,palmas-gpio"}, + { .compatible = "ti,tps65913-gpio"}, + { .compatible = "ti,tps65914-gpio"}, + { .compatible = "ti,tps80036-gpio"}, + { }, +}; +MODULE_DEVICE_TABLE(of, of_palmas_gpio_match); + static struct platform_driver palmas_gpio_driver = { .driver.name = "palmas-gpio", .driver.owner = THIS_MODULE, + .driver.of_match_table = of_palmas_gpio_match, .probe = palmas_gpio_probe, .remove = palmas_gpio_remove, }; diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 8804aec2950f..cdd1aa12b895 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -308,7 +308,7 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off) return 0; } - return (reg_val & (1u << off)) ? 1 : 0; + return (reg_val & (1u << (off % BANK_SZ))) ? 1 : 0; } static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) @@ -731,7 +731,7 @@ static int pca953x_probe(struct i2c_client *client, if (chip == NULL) return -ENOMEM; - pdata = client->dev.platform_data; + pdata = dev_get_platdata(&client->dev); if (pdata) { irq_base = pdata->irq_base; chip->gpio_start = pdata->gpio_base; @@ -785,7 +785,7 @@ static int pca953x_probe(struct i2c_client *client, static int pca953x_remove(struct i2c_client *client) { - struct pca953x_platform_data *pdata = client->dev.platform_data; + struct pca953x_platform_data *pdata = dev_get_platdata(&client->dev); struct pca953x_chip *chip = i2c_get_clientdata(client); int ret = 0; diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index e8faf53f3875..9e61bb0719d0 100644 --- a/drivers/gpio/gpio-pcf857x.c +++ b/drivers/gpio/gpio-pcf857x.c @@ -18,15 +18,15 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/kernel.h> -#include <linux/slab.h> #include <linux/gpio.h> #include <linux/i2c.h> #include <linux/i2c/pcf857x.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/irqdomain.h> +#include <linux/kernel.h> #include <linux/module.h> +#include <linux/slab.h> #include <linux/spinlock.h> #include <linux/workqueue.h> @@ -223,7 +223,6 @@ static void pcf857x_irq_domain_cleanup(struct pcf857x *gpio) } static int pcf857x_irq_domain_init(struct pcf857x *gpio, - struct pcf857x_platform_data *pdata, struct i2c_client *client) { int status; @@ -262,7 +261,7 @@ static int pcf857x_probe(struct i2c_client *client, struct pcf857x *gpio; int status; - pdata = client->dev.platform_data; + pdata = dev_get_platdata(&client->dev); if (!pdata) { dev_dbg(&client->dev, "no platform data\n"); } @@ -286,8 +285,8 @@ static int pcf857x_probe(struct i2c_client *client, gpio->chip.ngpio = id->driver_data; /* enable gpio_to_irq() if platform has settings */ - if (pdata && client->irq) { - status = pcf857x_irq_domain_init(gpio, pdata, client); + if (client->irq) { + status = pcf857x_irq_domain_init(gpio, client); if (status < 0) { dev_err(&client->dev, "irq_domain init failed\n"); goto fail; @@ -388,7 +387,7 @@ fail: dev_dbg(&client->dev, "probe error %d for '%s'\n", status, client->name); - if (pdata && client->irq) + if (client->irq) pcf857x_irq_domain_cleanup(gpio); return status; @@ -396,7 +395,7 @@ fail: static int pcf857x_remove(struct i2c_client *client) { - struct pcf857x_platform_data *pdata = client->dev.platform_data; + struct pcf857x_platform_data *pdata = dev_get_platdata(&client->dev); struct pcf857x *gpio = i2c_get_clientdata(client); int status = 0; @@ -411,7 +410,7 @@ static int pcf857x_remove(struct i2c_client *client) } } - if (pdata && client->irq) + if (client->irq) pcf857x_irq_domain_cleanup(gpio); status = gpiochip_remove(&gpio->chip); diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index 6a4bd0dae0ce..4274e2e70ef8 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -259,7 +259,7 @@ static const struct irq_domain_ops pl061_domain_ops = { static int pl061_probe(struct amba_device *adev, const struct amba_id *id) { struct device *dev = &adev->dev; - struct pl061_platform_data *pdata = dev->platform_data; + struct pl061_platform_data *pdata = dev_get_platdata(dev); struct pl061_gpio *chip; int ret, irq, i, irq_base; diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c index df2199dd1499..cc13d1b74fad 100644 --- a/drivers/gpio/gpio-pxa.c +++ b/drivers/gpio/gpio-pxa.c @@ -524,8 +524,8 @@ const struct irq_domain_ops pxa_irq_domain_ops = { static int pxa_gpio_probe_dt(struct platform_device *pdev) { - int ret, nr_gpios; - struct device_node *prev, *next, *np = pdev->dev.of_node; + int ret = 0, nr_gpios; + struct device_node *np = pdev->dev.of_node; const struct of_device_id *of_id = of_match_device(pxa_gpio_dt_ids, &pdev->dev); const struct pxa_gpio_id *gpio_id; @@ -537,20 +537,13 @@ static int pxa_gpio_probe_dt(struct platform_device *pdev) gpio_id = of_id->data; gpio_type = gpio_id->type; - next = of_get_next_child(np, NULL); - prev = next; - if (!next) { - dev_err(&pdev->dev, "Failed to find child gpio node\n"); - ret = -EINVAL; - goto err; - } - of_node_put(prev); nr_gpios = gpio_id->gpio_nums; pxa_last_gpio = nr_gpios - 1; irq_base = irq_alloc_descs(-1, 0, nr_gpios, 0); if (irq_base < 0) { dev_err(&pdev->dev, "Failed to allocate IRQ numbers\n"); + ret = irq_base; goto err; } domain = irq_domain_add_legacy(np, nr_gpios, irq_base, 0, diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index e8198dd68615..e3745eb07570 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -285,7 +285,7 @@ static struct irq_domain_ops gpio_rcar_irq_domain_ops = { static void gpio_rcar_parse_pdata(struct gpio_rcar_priv *p) { - struct gpio_rcar_config *pdata = p->pdev->dev.platform_data; + struct gpio_rcar_config *pdata = dev_get_platdata(&p->pdev->dev); struct device_node *np = p->pdev->dev.of_node; struct of_phandle_args args; int ret; diff --git a/drivers/gpio/gpio-rdc321x.c b/drivers/gpio/gpio-rdc321x.c index 368c3c00fca5..88577c3272a5 100644 --- a/drivers/gpio/gpio-rdc321x.c +++ b/drivers/gpio/gpio-rdc321x.c @@ -135,7 +135,7 @@ static int rdc321x_gpio_probe(struct platform_device *pdev) struct rdc321x_gpio *rdc321x_gpio_dev; struct rdc321x_gpio_pdata *pdata; - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); if (!pdata) { dev_err(&pdev->dev, "no platform data supplied\n"); return -ENODEV; diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c index a1392f47bbda..358a21c2d811 100644 --- a/drivers/gpio/gpio-samsung.c +++ b/drivers/gpio/gpio-samsung.c @@ -161,28 +161,6 @@ int s3c24xx_gpio_setpull_1down(struct samsung_gpio_chip *chip, return s3c24xx_gpio_setpull_1(chip, off, pull, S3C_GPIO_PULL_DOWN); } -static int exynos_gpio_setpull(struct samsung_gpio_chip *chip, - unsigned int off, samsung_gpio_pull_t pull) -{ - if (pull == S3C_GPIO_PULL_UP) - pull = 3; - - return samsung_gpio_setpull_updown(chip, off, pull); -} - -static samsung_gpio_pull_t exynos_gpio_getpull(struct samsung_gpio_chip *chip, - unsigned int off) -{ - samsung_gpio_pull_t pull; - - pull = samsung_gpio_getpull_updown(chip, off); - - if (pull == 3) - pull = S3C_GPIO_PULL_UP; - - return pull; -} - /* * samsung_gpio_setcfg_2bit - Samsung 2bit style GPIO configuration. * @chip: The gpio chip that is being configured. @@ -444,15 +422,6 @@ static struct samsung_gpio_cfg s3c24xx_gpiocfg_banka = { }; #endif -#if defined(CONFIG_ARCH_EXYNOS4) || defined(CONFIG_SOC_EXYNOS5250) -static struct samsung_gpio_cfg exynos_gpio_cfg = { - .set_pull = exynos_gpio_setpull, - .get_pull = exynos_gpio_getpull, - .set_config = samsung_gpio_setcfg_4bit, - .get_config = samsung_gpio_getcfg_4bit, -}; -#endif - #if defined(CONFIG_CPU_S5P6440) || defined(CONFIG_CPU_S5P6450) static struct samsung_gpio_cfg s5p64x0_gpio_cfg_rbank = { .cfg_eint = 0x3, @@ -495,15 +464,6 @@ static struct samsung_gpio_cfg samsung_gpio_cfgs[] = { .set_config = samsung_gpio_setcfg_2bit, .get_config = samsung_gpio_getcfg_2bit, }, - [8] = { - .set_pull = exynos_gpio_setpull, - .get_pull = exynos_gpio_getpull, - }, - [9] = { - .cfg_eint = 0x3, - .set_pull = exynos_gpio_setpull, - .get_pull = exynos_gpio_getpull, - } }; /* @@ -2115,833 +2075,6 @@ static struct samsung_gpio_chip s5pv210_gpios_4bit[] = { #endif }; -/* - * Followings are the gpio banks in EXYNOS SoCs - * - * The 'config' member when left to NULL, is initialized to the default - * structure exynos_gpio_cfg in the init function below. - * - * The 'base' member is also initialized in the init function below. - * Note: The initialization of 'base' member of samsung_gpio_chip structure - * uses the above macro and depends on the banks being listed in order here. - */ - -#ifdef CONFIG_ARCH_EXYNOS4 -static struct samsung_gpio_chip exynos4_gpios_1[] = { - { - .chip = { - .base = EXYNOS4_GPA0(0), - .ngpio = EXYNOS4_GPIO_A0_NR, - .label = "GPA0", - }, - }, { - .chip = { - .base = EXYNOS4_GPA1(0), - .ngpio = EXYNOS4_GPIO_A1_NR, - .label = "GPA1", - }, - }, { - .chip = { - .base = EXYNOS4_GPB(0), - .ngpio = EXYNOS4_GPIO_B_NR, - .label = "GPB", - }, - }, { - .chip = { - .base = EXYNOS4_GPC0(0), - .ngpio = EXYNOS4_GPIO_C0_NR, - .label = "GPC0", - }, - }, { - .chip = { - .base = EXYNOS4_GPC1(0), - .ngpio = EXYNOS4_GPIO_C1_NR, - .label = "GPC1", - }, - }, { - .chip = { - .base = EXYNOS4_GPD0(0), - .ngpio = EXYNOS4_GPIO_D0_NR, - .label = "GPD0", - }, - }, { - .chip = { - .base = EXYNOS4_GPD1(0), - .ngpio = EXYNOS4_GPIO_D1_NR, - .label = "GPD1", - }, - }, { - .chip = { - .base = EXYNOS4_GPE0(0), - .ngpio = EXYNOS4_GPIO_E0_NR, - .label = "GPE0", - }, - }, { - .chip = { - .base = EXYNOS4_GPE1(0), - .ngpio = EXYNOS4_GPIO_E1_NR, - .label = "GPE1", - }, - }, { - .chip = { - .base = EXYNOS4_GPE2(0), - .ngpio = EXYNOS4_GPIO_E2_NR, - .label = "GPE2", - }, - }, { - .chip = { - .base = EXYNOS4_GPE3(0), - .ngpio = EXYNOS4_GPIO_E3_NR, - .label = "GPE3", - }, - }, { - .chip = { - .base = EXYNOS4_GPE4(0), - .ngpio = EXYNOS4_GPIO_E4_NR, - .label = "GPE4", - }, - }, { - .chip = { - .base = EXYNOS4_GPF0(0), - .ngpio = EXYNOS4_GPIO_F0_NR, - .label = "GPF0", - }, - }, { - .chip = { - .base = EXYNOS4_GPF1(0), - .ngpio = EXYNOS4_GPIO_F1_NR, - .label = "GPF1", - }, - }, { - .chip = { - .base = EXYNOS4_GPF2(0), - .ngpio = EXYNOS4_GPIO_F2_NR, - .label = "GPF2", - }, - }, { - .chip = { - .base = EXYNOS4_GPF3(0), - .ngpio = EXYNOS4_GPIO_F3_NR, - .label = "GPF3", - }, - }, -}; -#endif - -#ifdef CONFIG_ARCH_EXYNOS4 -static struct samsung_gpio_chip exynos4_gpios_2[] = { - { - .chip = { - .base = EXYNOS4_GPJ0(0), - .ngpio = EXYNOS4_GPIO_J0_NR, - .label = "GPJ0", - }, - }, { - .chip = { - .base = EXYNOS4_GPJ1(0), - .ngpio = EXYNOS4_GPIO_J1_NR, - .label = "GPJ1", - }, - }, { - .chip = { - .base = EXYNOS4_GPK0(0), - .ngpio = EXYNOS4_GPIO_K0_NR, - .label = "GPK0", - }, - }, { - .chip = { - .base = EXYNOS4_GPK1(0), - .ngpio = EXYNOS4_GPIO_K1_NR, - .label = "GPK1", - }, - }, { - .chip = { - .base = EXYNOS4_GPK2(0), - .ngpio = EXYNOS4_GPIO_K2_NR, - .label = "GPK2", - }, - }, { - .chip = { - .base = EXYNOS4_GPK3(0), - .ngpio = EXYNOS4_GPIO_K3_NR, - .label = "GPK3", - }, - }, { - .chip = { - .base = EXYNOS4_GPL0(0), - .ngpio = EXYNOS4_GPIO_L0_NR, - .label = "GPL0", - }, - }, { - .chip = { - .base = EXYNOS4_GPL1(0), - .ngpio = EXYNOS4_GPIO_L1_NR, - .label = "GPL1", - }, - }, { - .chip = { - .base = EXYNOS4_GPL2(0), - .ngpio = EXYNOS4_GPIO_L2_NR, - .label = "GPL2", - }, - }, { - .config = &samsung_gpio_cfgs[8], - .chip = { - .base = EXYNOS4_GPY0(0), - .ngpio = EXYNOS4_GPIO_Y0_NR, - .label = "GPY0", - }, - }, { - .config = &samsung_gpio_cfgs[8], - .chip = { - .base = EXYNOS4_GPY1(0), - .ngpio = EXYNOS4_GPIO_Y1_NR, - .label = "GPY1", - }, - }, { - .config = &samsung_gpio_cfgs[8], - .chip = { - .base = EXYNOS4_GPY2(0), - .ngpio = EXYNOS4_GPIO_Y2_NR, - .label = "GPY2", - }, - }, { - .config = &samsung_gpio_cfgs[8], - .chip = { - .base = EXYNOS4_GPY3(0), - .ngpio = EXYNOS4_GPIO_Y3_NR, - .label = "GPY3", - }, - }, { - .config = &samsung_gpio_cfgs[8], - .chip = { - .base = EXYNOS4_GPY4(0), - .ngpio = EXYNOS4_GPIO_Y4_NR, - .label = "GPY4", - }, - }, { - .config = &samsung_gpio_cfgs[8], - .chip = { - .base = EXYNOS4_GPY5(0), - .ngpio = EXYNOS4_GPIO_Y5_NR, - .label = "GPY5", - }, - }, { - .config = &samsung_gpio_cfgs[8], - .chip = { - .base = EXYNOS4_GPY6(0), - .ngpio = EXYNOS4_GPIO_Y6_NR, - .label = "GPY6", - }, - }, { - .config = &samsung_gpio_cfgs[9], - .irq_base = IRQ_EINT(0), - .chip = { - .base = EXYNOS4_GPX0(0), - .ngpio = EXYNOS4_GPIO_X0_NR, - .label = "GPX0", - .to_irq = samsung_gpiolib_to_irq, - }, - }, { - .config = &samsung_gpio_cfgs[9], - .irq_base = IRQ_EINT(8), - .chip = { - .base = EXYNOS4_GPX1(0), - .ngpio = EXYNOS4_GPIO_X1_NR, - .label = "GPX1", - .to_irq = samsung_gpiolib_to_irq, - }, - }, { - .config = &samsung_gpio_cfgs[9], - .irq_base = IRQ_EINT(16), - .chip = { - .base = EXYNOS4_GPX2(0), - .ngpio = EXYNOS4_GPIO_X2_NR, - .label = "GPX2", - .to_irq = samsung_gpiolib_to_irq, - }, - }, { - .config = &samsung_gpio_cfgs[9], - .irq_base = IRQ_EINT(24), - .chip = { - .base = EXYNOS4_GPX3(0), - .ngpio = EXYNOS4_GPIO_X3_NR, - .label = "GPX3", - .to_irq = samsung_gpiolib_to_irq, - }, - }, -}; -#endif - -#ifdef CONFIG_ARCH_EXYNOS4 -static struct samsung_gpio_chip exynos4_gpios_3[] = { - { - .chip = { - .base = EXYNOS4_GPZ(0), - .ngpio = EXYNOS4_GPIO_Z_NR, - .label = "GPZ", - }, - }, -}; -#endif - -#ifdef CONFIG_SOC_EXYNOS5250 -static struct samsung_gpio_chip exynos5_gpios_1[] = { - { - .chip = { - .base = EXYNOS5_GPA0(0), - .ngpio = EXYNOS5_GPIO_A0_NR, - .label = "GPA0", - }, - }, { - .chip = { - .base = EXYNOS5_GPA1(0), - .ngpio = EXYNOS5_GPIO_A1_NR, - .label = "GPA1", - }, - }, { - .chip = { - .base = EXYNOS5_GPA2(0), - .ngpio = EXYNOS5_GPIO_A2_NR, - .label = "GPA2", - }, - }, { - .chip = { - .base = EXYNOS5_GPB0(0), - .ngpio = EXYNOS5_GPIO_B0_NR, - .label = "GPB0", - }, - }, { - .chip = { - .base = EXYNOS5_GPB1(0), - .ngpio = EXYNOS5_GPIO_B1_NR, - .label = "GPB1", - }, - }, { - .chip = { - .base = EXYNOS5_GPB2(0), - .ngpio = EXYNOS5_GPIO_B2_NR, - .label = "GPB2", - }, - }, { - .chip = { - .base = EXYNOS5_GPB3(0), - .ngpio = EXYNOS5_GPIO_B3_NR, - .label = "GPB3", - }, - }, { - .chip = { - .base = EXYNOS5_GPC0(0), - .ngpio = EXYNOS5_GPIO_C0_NR, - .label = "GPC0", - }, - }, { - .chip = { - .base = EXYNOS5_GPC1(0), - .ngpio = EXYNOS5_GPIO_C1_NR, - .label = "GPC1", - }, - }, { - .chip = { - .base = EXYNOS5_GPC2(0), - .ngpio = EXYNOS5_GPIO_C2_NR, - .label = "GPC2", - }, - }, { - .chip = { - .base = EXYNOS5_GPC3(0), - .ngpio = EXYNOS5_GPIO_C3_NR, - .label = "GPC3", - }, - }, { - .chip = { - .base = EXYNOS5_GPD0(0), - .ngpio = EXYNOS5_GPIO_D0_NR, - .label = "GPD0", - }, - }, { - .chip = { - .base = EXYNOS5_GPD1(0), - .ngpio = EXYNOS5_GPIO_D1_NR, - .label = "GPD1", - }, - }, { - .chip = { - .base = EXYNOS5_GPY0(0), - .ngpio = EXYNOS5_GPIO_Y0_NR, - .label = "GPY0", - }, - }, { - .chip = { - .base = EXYNOS5_GPY1(0), - .ngpio = EXYNOS5_GPIO_Y1_NR, - .label = "GPY1", - }, - }, { - .chip = { - .base = EXYNOS5_GPY2(0), - .ngpio = EXYNOS5_GPIO_Y2_NR, - .label = "GPY2", - }, - }, { - .chip = { - .base = EXYNOS5_GPY3(0), - .ngpio = EXYNOS5_GPIO_Y3_NR, - .label = "GPY3", - }, - }, { - .chip = { - .base = EXYNOS5_GPY4(0), - .ngpio = EXYNOS5_GPIO_Y4_NR, - .label = "GPY4", - }, - }, { - .chip = { - .base = EXYNOS5_GPY5(0), - .ngpio = EXYNOS5_GPIO_Y5_NR, - .label = "GPY5", - }, - }, { - .chip = { - .base = EXYNOS5_GPY6(0), - .ngpio = EXYNOS5_GPIO_Y6_NR, - .label = "GPY6", - }, - }, { - .chip = { - .base = EXYNOS5_GPC4(0), - .ngpio = EXYNOS5_GPIO_C4_NR, - .label = "GPC4", - }, - }, { - .config = &samsung_gpio_cfgs[9], - .irq_base = IRQ_EINT(0), - .chip = { - .base = EXYNOS5_GPX0(0), - .ngpio = EXYNOS5_GPIO_X0_NR, - .label = "GPX0", - .to_irq = samsung_gpiolib_to_irq, - }, - }, { - .config = &samsung_gpio_cfgs[9], - .irq_base = IRQ_EINT(8), - .chip = { - .base = EXYNOS5_GPX1(0), - .ngpio = EXYNOS5_GPIO_X1_NR, - .label = "GPX1", - .to_irq = samsung_gpiolib_to_irq, - }, - }, { - .config = &samsung_gpio_cfgs[9], - .irq_base = IRQ_EINT(16), - .chip = { - .base = EXYNOS5_GPX2(0), - .ngpio = EXYNOS5_GPIO_X2_NR, - .label = "GPX2", - .to_irq = samsung_gpiolib_to_irq, - }, - }, { - .config = &samsung_gpio_cfgs[9], - .irq_base = IRQ_EINT(24), - .chip = { - .base = EXYNOS5_GPX3(0), - .ngpio = EXYNOS5_GPIO_X3_NR, - .label = "GPX3", - .to_irq = samsung_gpiolib_to_irq, - }, - }, -}; -#endif - -#ifdef CONFIG_SOC_EXYNOS5250 -static struct samsung_gpio_chip exynos5_gpios_2[] = { - { - .chip = { - .base = EXYNOS5_GPE0(0), - .ngpio = EXYNOS5_GPIO_E0_NR, - .label = "GPE0", - }, - }, { - .chip = { - .base = EXYNOS5_GPE1(0), - .ngpio = EXYNOS5_GPIO_E1_NR, - .label = "GPE1", - }, - }, { - .chip = { - .base = EXYNOS5_GPF0(0), - .ngpio = EXYNOS5_GPIO_F0_NR, - .label = "GPF0", - }, - }, { - .chip = { - .base = EXYNOS5_GPF1(0), - .ngpio = EXYNOS5_GPIO_F1_NR, - .label = "GPF1", - }, - }, { - .chip = { - .base = EXYNOS5_GPG0(0), - .ngpio = EXYNOS5_GPIO_G0_NR, - .label = "GPG0", - }, - }, { - .chip = { - .base = EXYNOS5_GPG1(0), - .ngpio = EXYNOS5_GPIO_G1_NR, - .label = "GPG1", - }, - }, { - .chip = { - .base = EXYNOS5_GPG2(0), - .ngpio = EXYNOS5_GPIO_G2_NR, - .label = "GPG2", - }, - }, { - .chip = { - .base = EXYNOS5_GPH0(0), - .ngpio = EXYNOS5_GPIO_H0_NR, - .label = "GPH0", - }, - }, { - .chip = { - .base = EXYNOS5_GPH1(0), - .ngpio = EXYNOS5_GPIO_H1_NR, - .label = "GPH1", - - }, - }, -}; -#endif - -#ifdef CONFIG_SOC_EXYNOS5250 -static struct samsung_gpio_chip exynos5_gpios_3[] = { - { - .chip = { - .base = EXYNOS5_GPV0(0), - .ngpio = EXYNOS5_GPIO_V0_NR, - .label = "GPV0", - }, - }, { - .chip = { - .base = EXYNOS5_GPV1(0), - .ngpio = EXYNOS5_GPIO_V1_NR, - .label = "GPV1", - }, - }, { - .chip = { - .base = EXYNOS5_GPV2(0), - .ngpio = EXYNOS5_GPIO_V2_NR, - .label = "GPV2", - }, - }, { - .chip = { - .base = EXYNOS5_GPV3(0), - .ngpio = EXYNOS5_GPIO_V3_NR, - .label = "GPV3", - }, - }, { - .chip = { - .base = EXYNOS5_GPV4(0), - .ngpio = EXYNOS5_GPIO_V4_NR, - .label = "GPV4", - }, - }, -}; -#endif - -#ifdef CONFIG_SOC_EXYNOS5250 -static struct samsung_gpio_chip exynos5_gpios_4[] = { - { - .chip = { - .base = EXYNOS5_GPZ(0), - .ngpio = EXYNOS5_GPIO_Z_NR, - .label = "GPZ", - }, - }, -}; -#endif - - -#if defined(CONFIG_ARCH_EXYNOS) && defined(CONFIG_OF) -static int exynos_gpio_xlate(struct gpio_chip *gc, - const struct of_phandle_args *gpiospec, u32 *flags) -{ - unsigned int pin; - - if (WARN_ON(gc->of_gpio_n_cells < 4)) - return -EINVAL; - - if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells)) - return -EINVAL; - - if (gpiospec->args[0] > gc->ngpio) - return -EINVAL; - - pin = gc->base + gpiospec->args[0]; - - if (s3c_gpio_cfgpin(pin, S3C_GPIO_SFN(gpiospec->args[1]))) - pr_warn("gpio_xlate: failed to set pin function\n"); - if (s3c_gpio_setpull(pin, gpiospec->args[2] & 0xffff)) - pr_warn("gpio_xlate: failed to set pin pull up/down\n"); - if (s5p_gpio_set_drvstr(pin, gpiospec->args[3])) - pr_warn("gpio_xlate: failed to set pin drive strength\n"); - - if (flags) - *flags = gpiospec->args[2] >> 16; - - return gpiospec->args[0]; -} - -static const struct of_device_id exynos_gpio_dt_match[] __initdata = { - { .compatible = "samsung,exynos4-gpio", }, - {} -}; - -static __init void exynos_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip, - u64 base, u64 offset) -{ - struct gpio_chip *gc = &chip->chip; - u64 address; - - if (!of_have_populated_dt()) - return; - - address = chip->base ? base + ((u32)chip->base & 0xfff) : base + offset; - gc->of_node = of_find_matching_node_by_address(NULL, - exynos_gpio_dt_match, address); - if (!gc->of_node) { - pr_info("gpio: device tree node not found for gpio controller" - " with base address %08llx\n", address); - return; - } - gc->of_gpio_n_cells = 4; - gc->of_xlate = exynos_gpio_xlate; -} -#elif defined(CONFIG_ARCH_EXYNOS) -static __init void exynos_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip, - u64 base, u64 offset) -{ - return; -} -#endif /* defined(CONFIG_ARCH_EXYNOS) && defined(CONFIG_OF) */ - -static __init void exynos4_gpiolib_init(void) -{ -#ifdef CONFIG_CPU_EXYNOS4210 - struct samsung_gpio_chip *chip; - int i, nr_chips; - void __iomem *gpio_base1, *gpio_base2, *gpio_base3; - int group = 0; - void __iomem *gpx_base; - - /* gpio part1 */ - gpio_base1 = ioremap(EXYNOS4_PA_GPIO1, SZ_4K); - if (gpio_base1 == NULL) { - pr_err("unable to ioremap for gpio_base1\n"); - goto err_ioremap1; - } - - chip = exynos4_gpios_1; - nr_chips = ARRAY_SIZE(exynos4_gpios_1); - - for (i = 0; i < nr_chips; i++, chip++) { - if (!chip->config) { - chip->config = &exynos_gpio_cfg; - chip->group = group++; - } - exynos_gpiolib_attach_ofnode(chip, - EXYNOS4_PA_GPIO1, i * 0x20); - } - samsung_gpiolib_add_4bit_chips(exynos4_gpios_1, - nr_chips, gpio_base1); - - /* gpio part2 */ - gpio_base2 = ioremap(EXYNOS4_PA_GPIO2, SZ_4K); - if (gpio_base2 == NULL) { - pr_err("unable to ioremap for gpio_base2\n"); - goto err_ioremap2; - } - - /* need to set base address for gpx */ - chip = &exynos4_gpios_2[16]; - gpx_base = gpio_base2 + 0xC00; - for (i = 0; i < 4; i++, chip++, gpx_base += 0x20) - chip->base = gpx_base; - - chip = exynos4_gpios_2; - nr_chips = ARRAY_SIZE(exynos4_gpios_2); - - for (i = 0; i < nr_chips; i++, chip++) { - if (!chip->config) { - chip->config = &exynos_gpio_cfg; - chip->group = group++; - } - exynos_gpiolib_attach_ofnode(chip, - EXYNOS4_PA_GPIO2, i * 0x20); - } - samsung_gpiolib_add_4bit_chips(exynos4_gpios_2, - nr_chips, gpio_base2); - - /* gpio part3 */ - gpio_base3 = ioremap(EXYNOS4_PA_GPIO3, SZ_256); - if (gpio_base3 == NULL) { - pr_err("unable to ioremap for gpio_base3\n"); - goto err_ioremap3; - } - - chip = exynos4_gpios_3; - nr_chips = ARRAY_SIZE(exynos4_gpios_3); - - for (i = 0; i < nr_chips; i++, chip++) { - if (!chip->config) { - chip->config = &exynos_gpio_cfg; - chip->group = group++; - } - exynos_gpiolib_attach_ofnode(chip, - EXYNOS4_PA_GPIO3, i * 0x20); - } - samsung_gpiolib_add_4bit_chips(exynos4_gpios_3, - nr_chips, gpio_base3); - -#if defined(CONFIG_CPU_EXYNOS4210) && defined(CONFIG_S5P_GPIO_INT) - s5p_register_gpioint_bank(IRQ_GPIO_XA, 0, IRQ_GPIO1_NR_GROUPS); - s5p_register_gpioint_bank(IRQ_GPIO_XB, IRQ_GPIO1_NR_GROUPS, IRQ_GPIO2_NR_GROUPS); -#endif - - return; - -err_ioremap3: - iounmap(gpio_base2); -err_ioremap2: - iounmap(gpio_base1); -err_ioremap1: - return; -#endif /* CONFIG_CPU_EXYNOS4210 */ -} - -static __init void exynos5_gpiolib_init(void) -{ -#ifdef CONFIG_SOC_EXYNOS5250 - struct samsung_gpio_chip *chip; - int i, nr_chips; - void __iomem *gpio_base1, *gpio_base2, *gpio_base3, *gpio_base4; - int group = 0; - void __iomem *gpx_base; - - /* gpio part1 */ - gpio_base1 = ioremap(EXYNOS5_PA_GPIO1, SZ_4K); - if (gpio_base1 == NULL) { - pr_err("unable to ioremap for gpio_base1\n"); - goto err_ioremap1; - } - - /* need to set base address for gpc4 */ - exynos5_gpios_1[20].base = gpio_base1 + 0x2E0; - - /* need to set base address for gpx */ - chip = &exynos5_gpios_1[21]; - gpx_base = gpio_base1 + 0xC00; - for (i = 0; i < 4; i++, chip++, gpx_base += 0x20) - chip->base = gpx_base; - - chip = exynos5_gpios_1; - nr_chips = ARRAY_SIZE(exynos5_gpios_1); - - for (i = 0; i < nr_chips; i++, chip++) { - if (!chip->config) { - chip->config = &exynos_gpio_cfg; - chip->group = group++; - } - exynos_gpiolib_attach_ofnode(chip, - EXYNOS5_PA_GPIO1, i * 0x20); - } - samsung_gpiolib_add_4bit_chips(exynos5_gpios_1, - nr_chips, gpio_base1); - - /* gpio part2 */ - gpio_base2 = ioremap(EXYNOS5_PA_GPIO2, SZ_4K); - if (gpio_base2 == NULL) { - pr_err("unable to ioremap for gpio_base2\n"); - goto err_ioremap2; - } - - chip = exynos5_gpios_2; - nr_chips = ARRAY_SIZE(exynos5_gpios_2); - - for (i = 0; i < nr_chips; i++, chip++) { - if (!chip->config) { - chip->config = &exynos_gpio_cfg; - chip->group = group++; - } - exynos_gpiolib_attach_ofnode(chip, - EXYNOS5_PA_GPIO2, i * 0x20); - } - samsung_gpiolib_add_4bit_chips(exynos5_gpios_2, - nr_chips, gpio_base2); - - /* gpio part3 */ - gpio_base3 = ioremap(EXYNOS5_PA_GPIO3, SZ_4K); - if (gpio_base3 == NULL) { - pr_err("unable to ioremap for gpio_base3\n"); - goto err_ioremap3; - } - - /* need to set base address for gpv */ - exynos5_gpios_3[0].base = gpio_base3; - exynos5_gpios_3[1].base = gpio_base3 + 0x20; - exynos5_gpios_3[2].base = gpio_base3 + 0x60; - exynos5_gpios_3[3].base = gpio_base3 + 0x80; - exynos5_gpios_3[4].base = gpio_base3 + 0xC0; - - chip = exynos5_gpios_3; - nr_chips = ARRAY_SIZE(exynos5_gpios_3); - - for (i = 0; i < nr_chips; i++, chip++) { - if (!chip->config) { - chip->config = &exynos_gpio_cfg; - chip->group = group++; - } - exynos_gpiolib_attach_ofnode(chip, - EXYNOS5_PA_GPIO3, i * 0x20); - } - samsung_gpiolib_add_4bit_chips(exynos5_gpios_3, - nr_chips, gpio_base3); - - /* gpio part4 */ - gpio_base4 = ioremap(EXYNOS5_PA_GPIO4, SZ_4K); - if (gpio_base4 == NULL) { - pr_err("unable to ioremap for gpio_base4\n"); - goto err_ioremap4; - } - - chip = exynos5_gpios_4; - nr_chips = ARRAY_SIZE(exynos5_gpios_4); - - for (i = 0; i < nr_chips; i++, chip++) { - if (!chip->config) { - chip->config = &exynos_gpio_cfg; - chip->group = group++; - } - exynos_gpiolib_attach_ofnode(chip, - EXYNOS5_PA_GPIO4, i * 0x20); - } - samsung_gpiolib_add_4bit_chips(exynos5_gpios_4, - nr_chips, gpio_base4); - return; - -err_ioremap4: - iounmap(gpio_base3); -err_ioremap3: - iounmap(gpio_base2); -err_ioremap2: - iounmap(gpio_base1); -err_ioremap1: - return; - -#endif /* CONFIG_SOC_EXYNOS5250 */ -} - /* TODO: cleanup soc_is_* */ static __init int samsung_gpiolib_init(void) { @@ -3040,10 +2173,6 @@ static __init int samsung_gpiolib_init(void) #if defined(CONFIG_CPU_S5PV210) && defined(CONFIG_S5P_GPIO_INT) s5p_register_gpioint_bank(IRQ_GPIOINT, 0, S5P_GPIOINT_GROUP_MAXNR); #endif - } else if (soc_is_exynos4210()) { - exynos4_gpiolib_init(); - } else if (soc_is_exynos5250()) { - exynos5_gpiolib_init(); } else { WARN(1, "Unknown SoC in gpio-samsung, no GPIOs added\n"); return -ENODEV; diff --git a/drivers/gpio/gpio-spear-spics.c b/drivers/gpio/gpio-spear-spics.c index 7a4bf7c0d98f..e9a0415834ea 100644 --- a/drivers/gpio/gpio-spear-spics.c +++ b/drivers/gpio/gpio-spear-spics.c @@ -128,18 +128,13 @@ static int spics_gpio_probe(struct platform_device *pdev) struct resource *res; int ret; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "invalid IORESOURCE_MEM\n"); - return -EBUSY; - } - spics = devm_kzalloc(&pdev->dev, sizeof(*spics), GFP_KERNEL); if (!spics) { dev_err(&pdev->dev, "memory allocation fail\n"); return -ENOMEM; } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); spics->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(spics->base)) return PTR_ERR(spics->base); diff --git a/drivers/gpio/gpio-sta2x11.c b/drivers/gpio/gpio-sta2x11.c index f43ab6aea281..f2fb12c18da9 100644 --- a/drivers/gpio/gpio-sta2x11.c +++ b/drivers/gpio/gpio-sta2x11.c @@ -361,7 +361,7 @@ static int gsta_probe(struct platform_device *dev) struct gsta_gpio *chip; struct resource *res; - pdev = *(struct pci_dev **)(dev->dev.platform_data); + pdev = *(struct pci_dev **)dev_get_platdata(&dev->dev); gpio_pdata = dev_get_platdata(&pdev->dev); if (gpio_pdata == NULL) diff --git a/drivers/gpio/gpio-sx150x.c b/drivers/gpio/gpio-sx150x.c index f371732591d2..d2983e9ad6af 100644 --- a/drivers/gpio/gpio-sx150x.c +++ b/drivers/gpio/gpio-sx150x.c @@ -583,7 +583,7 @@ static int sx150x_probe(struct i2c_client *client, struct sx150x_chip *chip; int rc; - pdata = client->dev.platform_data; + pdata = dev_get_platdata(&client->dev); if (!pdata) return -EINVAL; diff --git a/drivers/gpio/gpio-timberdale.c b/drivers/gpio/gpio-timberdale.c index 4c65f8883204..7a0e956ef1ed 100644 --- a/drivers/gpio/gpio-timberdale.c +++ b/drivers/gpio/gpio-timberdale.c @@ -227,7 +227,7 @@ static int timbgpio_probe(struct platform_device *pdev) struct gpio_chip *gc; struct timbgpio *tgpio; struct resource *iomem; - struct timbgpio_platform_data *pdata = pdev->dev.platform_data; + struct timbgpio_platform_data *pdata = dev_get_platdata(&pdev->dev); int irq = platform_get_irq(pdev, 0); if (!pdata || pdata->nr_pins > 32) { @@ -318,7 +318,7 @@ err_mem: static int timbgpio_remove(struct platform_device *pdev) { int err; - struct timbgpio_platform_data *pdata = pdev->dev.platform_data; + struct timbgpio_platform_data *pdata = dev_get_platdata(&pdev->dev); struct timbgpio *tgpio = platform_get_drvdata(pdev); struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); int irq = platform_get_irq(pdev, 0); diff --git a/drivers/gpio/gpio-tps65912.c b/drivers/gpio/gpio-tps65912.c index 30a5844a7dca..276a4229b032 100644 --- a/drivers/gpio/gpio-tps65912.c +++ b/drivers/gpio/gpio-tps65912.c @@ -87,7 +87,7 @@ static struct gpio_chip template_chip = { static int tps65912_gpio_probe(struct platform_device *pdev) { struct tps65912 *tps65912 = dev_get_drvdata(pdev->dev.parent); - struct tps65912_board *pdata = tps65912->dev->platform_data; + struct tps65912_board *pdata = dev_get_platdata(tps65912->dev); struct tps65912_gpio_data *tps65912_gpio; int ret; diff --git a/drivers/gpio/gpio-ts5500.c b/drivers/gpio/gpio-ts5500.c index cc53cab8df2a..3df3ebdb3e52 100644 --- a/drivers/gpio/gpio-ts5500.c +++ b/drivers/gpio/gpio-ts5500.c @@ -322,7 +322,7 @@ static void ts5500_disable_irq(struct ts5500_priv *priv) static int ts5500_dio_probe(struct platform_device *pdev) { enum ts5500_blocks block = platform_get_device_id(pdev)->driver_data; - struct ts5500_dio_platform_data *pdata = pdev->dev.platform_data; + struct ts5500_dio_platform_data *pdata = dev_get_platdata(&pdev->dev); struct device *dev = &pdev->dev; const char *name = dev_name(dev); struct ts5500_priv *priv; diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index 4d330e36da1d..d8e4f6efcb29 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c @@ -256,7 +256,7 @@ static int twl_request(struct gpio_chip *chip, unsigned offset) /* optionally have the first two GPIOs switch vMMC1 * and vMMC2 power supplies based on card presence. */ - pdata = chip->dev->platform_data; + pdata = dev_get_platdata(chip->dev); if (pdata) value |= pdata->mmc_cd & 0x03; @@ -460,7 +460,7 @@ static struct twl4030_gpio_platform_data *of_gpio_twl4030(struct device *dev) static int gpio_twl4030_probe(struct platform_device *pdev) { - struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data; + struct twl4030_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev); struct device_node *node = pdev->dev.of_node; struct gpio_twl4030_priv *priv; int ret, irq_base; @@ -556,7 +556,7 @@ out: /* Cannot use as gpio_twl4030_probe() calls us */ static int gpio_twl4030_remove(struct platform_device *pdev) { - struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data; + struct twl4030_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev); struct gpio_twl4030_priv *priv = platform_get_drvdata(pdev); int status; diff --git a/drivers/gpio/gpio-twl6040.c b/drivers/gpio/gpio-twl6040.c index 0be82c6dd796..d420d30b86e7 100644 --- a/drivers/gpio/gpio-twl6040.c +++ b/drivers/gpio/gpio-twl6040.c @@ -84,15 +84,11 @@ static struct gpio_chip twl6040gpo_chip = { static int gpo_twl6040_probe(struct platform_device *pdev) { - struct twl6040_gpo_data *pdata = pdev->dev.platform_data; struct device *twl6040_core_dev = pdev->dev.parent; struct twl6040 *twl6040 = dev_get_drvdata(twl6040_core_dev); int ret; - if (pdata) - twl6040gpo_chip.base = pdata->gpio_base; - else - twl6040gpo_chip.base = -1; + twl6040gpo_chip.base = -1; if (twl6040_get_revid(twl6040) < TWL6041_REV_ES2_0) twl6040gpo_chip.ngpio = 3; /* twl6040 have 3 GPO */ diff --git a/drivers/gpio/gpio-tz1090-pdc.c b/drivers/gpio/gpio-tz1090-pdc.c new file mode 100644 index 000000000000..f512da299b3d --- /dev/null +++ b/drivers/gpio/gpio-tz1090-pdc.c @@ -0,0 +1,243 @@ +/* + * Toumaz Xenif TZ1090 PDC GPIO handling. + * + * Copyright (C) 2012-2013 Imagination Technologies Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/bitops.h> +#include <linux/gpio.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of_irq.h> +#include <linux/pinctrl/consumer.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/syscore_ops.h> +#include <asm/global_lock.h> + +/* Register offsets from SOC_GPIO_CONTROL0 */ +#define REG_SOC_GPIO_CONTROL0 0x00 +#define REG_SOC_GPIO_CONTROL1 0x04 +#define REG_SOC_GPIO_CONTROL2 0x08 +#define REG_SOC_GPIO_CONTROL3 0x0c +#define REG_SOC_GPIO_STATUS 0x80 + +/* PDC GPIOs go after normal GPIOs */ +#define GPIO_PDC_BASE 90 +#define GPIO_PDC_NGPIO 7 + +/* Out of PDC gpios, only syswakes have irqs */ +#define GPIO_PDC_IRQ_FIRST 2 +#define GPIO_PDC_NIRQ 3 + +/** + * struct tz1090_pdc_gpio - GPIO bank private data + * @chip: Generic GPIO chip for GPIO bank + * @reg: Base of registers, offset for this GPIO bank + * @irq: IRQ numbers for Syswake GPIOs + * + * This is the main private data for the PDC GPIO driver. It encapsulates a + * gpio_chip, and the callbacks for the gpio_chip can access the private data + * with the to_pdc() macro below. + */ +struct tz1090_pdc_gpio { + struct gpio_chip chip; + void __iomem *reg; + int irq[GPIO_PDC_NIRQ]; +}; +#define to_pdc(c) container_of(c, struct tz1090_pdc_gpio, chip) + +/* Register accesses into the PDC MMIO area */ + +static inline void pdc_write(struct tz1090_pdc_gpio *priv, unsigned int reg_offs, + unsigned int data) +{ + writel(data, priv->reg + reg_offs); +} + +static inline unsigned int pdc_read(struct tz1090_pdc_gpio *priv, + unsigned int reg_offs) +{ + return readl(priv->reg + reg_offs); +} + +/* Generic GPIO interface */ + +static int tz1090_pdc_gpio_direction_input(struct gpio_chip *chip, + unsigned int offset) +{ + struct tz1090_pdc_gpio *priv = to_pdc(chip); + u32 value; + int lstat; + + __global_lock2(lstat); + value = pdc_read(priv, REG_SOC_GPIO_CONTROL1); + value |= BIT(offset); + pdc_write(priv, REG_SOC_GPIO_CONTROL1, value); + __global_unlock2(lstat); + + return 0; +} + +static int tz1090_pdc_gpio_direction_output(struct gpio_chip *chip, + unsigned int offset, + int output_value) +{ + struct tz1090_pdc_gpio *priv = to_pdc(chip); + u32 value; + int lstat; + + __global_lock2(lstat); + /* EXT_POWER doesn't seem to have an output value bit */ + if (offset < 6) { + value = pdc_read(priv, REG_SOC_GPIO_CONTROL0); + if (output_value) + value |= BIT(offset); + else + value &= ~BIT(offset); + pdc_write(priv, REG_SOC_GPIO_CONTROL0, value); + } + + value = pdc_read(priv, REG_SOC_GPIO_CONTROL1); + value &= ~BIT(offset); + pdc_write(priv, REG_SOC_GPIO_CONTROL1, value); + __global_unlock2(lstat); + + return 0; +} + +static int tz1090_pdc_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct tz1090_pdc_gpio *priv = to_pdc(chip); + return pdc_read(priv, REG_SOC_GPIO_STATUS) & BIT(offset); +} + +static void tz1090_pdc_gpio_set(struct gpio_chip *chip, unsigned int offset, + int output_value) +{ + struct tz1090_pdc_gpio *priv = to_pdc(chip); + u32 value; + int lstat; + + /* EXT_POWER doesn't seem to have an output value bit */ + if (offset >= 6) + return; + + __global_lock2(lstat); + value = pdc_read(priv, REG_SOC_GPIO_CONTROL0); + if (output_value) + value |= BIT(offset); + else + value &= ~BIT(offset); + pdc_write(priv, REG_SOC_GPIO_CONTROL0, value); + __global_unlock2(lstat); +} + +static int tz1090_pdc_gpio_request(struct gpio_chip *chip, unsigned int offset) +{ + return pinctrl_request_gpio(chip->base + offset); +} + +static void tz1090_pdc_gpio_free(struct gpio_chip *chip, unsigned int offset) +{ + pinctrl_free_gpio(chip->base + offset); +} + +static int tz1090_pdc_gpio_to_irq(struct gpio_chip *chip, unsigned int offset) +{ + struct tz1090_pdc_gpio *priv = to_pdc(chip); + unsigned int syswake = offset - GPIO_PDC_IRQ_FIRST; + int irq; + + /* only syswakes have irqs */ + if (syswake >= GPIO_PDC_NIRQ) + return -EINVAL; + + irq = priv->irq[syswake]; + if (!irq) + return -EINVAL; + + return irq; +} + +static int tz1090_pdc_gpio_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct resource *res_regs; + struct tz1090_pdc_gpio *priv; + unsigned int i; + + if (!np) { + dev_err(&pdev->dev, "must be instantiated via devicetree\n"); + return -ENOENT; + } + + res_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res_regs) { + dev_err(&pdev->dev, "cannot find registers resource\n"); + return -ENOENT; + } + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) { + dev_err(&pdev->dev, "unable to allocate driver data\n"); + return -ENOMEM; + } + + /* Ioremap the registers */ + priv->reg = devm_ioremap(&pdev->dev, res_regs->start, + res_regs->end - res_regs->start); + if (!priv->reg) { + dev_err(&pdev->dev, "unable to ioremap registers\n"); + return -ENOMEM; + } + + /* Set up GPIO chip */ + priv->chip.label = "tz1090-pdc-gpio"; + priv->chip.dev = &pdev->dev; + priv->chip.direction_input = tz1090_pdc_gpio_direction_input; + priv->chip.direction_output = tz1090_pdc_gpio_direction_output; + priv->chip.get = tz1090_pdc_gpio_get; + priv->chip.set = tz1090_pdc_gpio_set; + priv->chip.free = tz1090_pdc_gpio_free; + priv->chip.request = tz1090_pdc_gpio_request; + priv->chip.to_irq = tz1090_pdc_gpio_to_irq; + priv->chip.of_node = np; + + /* GPIO numbering */ + priv->chip.base = GPIO_PDC_BASE; + priv->chip.ngpio = GPIO_PDC_NGPIO; + + /* Map the syswake irqs */ + for (i = 0; i < GPIO_PDC_NIRQ; ++i) + priv->irq[i] = irq_of_parse_and_map(np, i); + + /* Add the GPIO bank */ + gpiochip_add(&priv->chip); + + return 0; +} + +static struct of_device_id tz1090_pdc_gpio_of_match[] = { + { .compatible = "img,tz1090-pdc-gpio" }, + { }, +}; + +static struct platform_driver tz1090_pdc_gpio_driver = { + .driver = { + .name = "tz1090-pdc-gpio", + .owner = THIS_MODULE, + .of_match_table = tz1090_pdc_gpio_of_match, + }, + .probe = tz1090_pdc_gpio_probe, +}; + +static int __init tz1090_pdc_gpio_init(void) +{ + return platform_driver_register(&tz1090_pdc_gpio_driver); +} +subsys_initcall(tz1090_pdc_gpio_init); diff --git a/drivers/gpio/gpio-tz1090.c b/drivers/gpio/gpio-tz1090.c new file mode 100644 index 000000000000..23e061392411 --- /dev/null +++ b/drivers/gpio/gpio-tz1090.c @@ -0,0 +1,606 @@ +/* + * Toumaz Xenif TZ1090 GPIO handling. + * + * Copyright (C) 2008-2013 Imagination Technologies Ltd. + * + * Based on ARM PXA code and others. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/bitops.h> +#include <linux/export.h> +#include <linux/gpio.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> +#include <linux/kernel.h> +#include <linux/of_irq.h> +#include <linux/pinctrl/consumer.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/syscore_ops.h> +#include <asm/global_lock.h> + +/* Register offsets from bank base address */ +#define REG_GPIO_DIR 0x00 +#define REG_GPIO_IRQ_PLRT 0x20 +#define REG_GPIO_IRQ_TYPE 0x30 +#define REG_GPIO_IRQ_EN 0x40 +#define REG_GPIO_IRQ_STS 0x50 +#define REG_GPIO_BIT_EN 0x60 +#define REG_GPIO_DIN 0x70 +#define REG_GPIO_DOUT 0x80 + +/* REG_GPIO_IRQ_PLRT */ +#define REG_GPIO_IRQ_PLRT_LOW 0 +#define REG_GPIO_IRQ_PLRT_HIGH 1 + +/* REG_GPIO_IRQ_TYPE */ +#define REG_GPIO_IRQ_TYPE_LEVEL 0 +#define REG_GPIO_IRQ_TYPE_EDGE 1 + +/** + * struct tz1090_gpio_bank - GPIO bank private data + * @chip: Generic GPIO chip for GPIO bank + * @domain: IRQ domain for GPIO bank (may be NULL) + * @reg: Base of registers, offset for this GPIO bank + * @irq: IRQ number for GPIO bank + * @label: Debug GPIO bank label, used for storage of chip->label + * + * This is the main private data for a GPIO bank. It encapsulates a gpio_chip, + * and the callbacks for the gpio_chip can access the private data with the + * to_bank() macro below. + */ +struct tz1090_gpio_bank { + struct gpio_chip chip; + struct irq_domain *domain; + void __iomem *reg; + int irq; + char label[16]; +}; +#define to_bank(c) container_of(c, struct tz1090_gpio_bank, chip) + +/** + * struct tz1090_gpio - Overall GPIO device private data + * @dev: Device (from platform device) + * @reg: Base of GPIO registers + * + * Represents the overall GPIO device. This structure is actually only + * temporary, and used during init. + */ +struct tz1090_gpio { + struct device *dev; + void __iomem *reg; +}; + +/** + * struct tz1090_gpio_bank_info - Temporary registration info for GPIO bank + * @priv: Overall GPIO device private data + * @node: Device tree node specific to this GPIO bank + * @index: Index of bank in range 0-2 + */ +struct tz1090_gpio_bank_info { + struct tz1090_gpio *priv; + struct device_node *node; + unsigned int index; +}; + +/* Convenience register accessors */ +static inline void tz1090_gpio_write(struct tz1090_gpio_bank *bank, + unsigned int reg_offs, u32 data) +{ + iowrite32(data, bank->reg + reg_offs); +} + +static inline u32 tz1090_gpio_read(struct tz1090_gpio_bank *bank, + unsigned int reg_offs) +{ + return ioread32(bank->reg + reg_offs); +} + +/* caller must hold LOCK2 */ +static inline void _tz1090_gpio_clear_bit(struct tz1090_gpio_bank *bank, + unsigned int reg_offs, + unsigned int offset) +{ + u32 value; + + value = tz1090_gpio_read(bank, reg_offs); + value &= ~BIT(offset); + tz1090_gpio_write(bank, reg_offs, value); +} + +static void tz1090_gpio_clear_bit(struct tz1090_gpio_bank *bank, + unsigned int reg_offs, + unsigned int offset) +{ + int lstat; + + __global_lock2(lstat); + _tz1090_gpio_clear_bit(bank, reg_offs, offset); + __global_unlock2(lstat); +} + +/* caller must hold LOCK2 */ +static inline void _tz1090_gpio_set_bit(struct tz1090_gpio_bank *bank, + unsigned int reg_offs, + unsigned int offset) +{ + u32 value; + + value = tz1090_gpio_read(bank, reg_offs); + value |= BIT(offset); + tz1090_gpio_write(bank, reg_offs, value); +} + +static void tz1090_gpio_set_bit(struct tz1090_gpio_bank *bank, + unsigned int reg_offs, + unsigned int offset) +{ + int lstat; + + __global_lock2(lstat); + _tz1090_gpio_set_bit(bank, reg_offs, offset); + __global_unlock2(lstat); +} + +/* caller must hold LOCK2 */ +static inline void _tz1090_gpio_mod_bit(struct tz1090_gpio_bank *bank, + unsigned int reg_offs, + unsigned int offset, + bool val) +{ + u32 value; + + value = tz1090_gpio_read(bank, reg_offs); + value &= ~BIT(offset); + if (val) + value |= BIT(offset); + tz1090_gpio_write(bank, reg_offs, value); +} + +static void tz1090_gpio_mod_bit(struct tz1090_gpio_bank *bank, + unsigned int reg_offs, + unsigned int offset, + bool val) +{ + int lstat; + + __global_lock2(lstat); + _tz1090_gpio_mod_bit(bank, reg_offs, offset, val); + __global_unlock2(lstat); +} + +static inline int tz1090_gpio_read_bit(struct tz1090_gpio_bank *bank, + unsigned int reg_offs, + unsigned int offset) +{ + return tz1090_gpio_read(bank, reg_offs) & BIT(offset); +} + +/* GPIO chip callbacks */ + +static int tz1090_gpio_direction_input(struct gpio_chip *chip, + unsigned int offset) +{ + struct tz1090_gpio_bank *bank = to_bank(chip); + tz1090_gpio_set_bit(bank, REG_GPIO_DIR, offset); + + return 0; +} + +static int tz1090_gpio_direction_output(struct gpio_chip *chip, + unsigned int offset, int output_value) +{ + struct tz1090_gpio_bank *bank = to_bank(chip); + int lstat; + + __global_lock2(lstat); + _tz1090_gpio_mod_bit(bank, REG_GPIO_DOUT, offset, output_value); + _tz1090_gpio_clear_bit(bank, REG_GPIO_DIR, offset); + __global_unlock2(lstat); + + return 0; +} + +/* + * Return GPIO level + */ +static int tz1090_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct tz1090_gpio_bank *bank = to_bank(chip); + + return tz1090_gpio_read_bit(bank, REG_GPIO_DIN, offset); +} + +/* + * Set output GPIO level + */ +static void tz1090_gpio_set(struct gpio_chip *chip, unsigned int offset, + int output_value) +{ + struct tz1090_gpio_bank *bank = to_bank(chip); + + tz1090_gpio_mod_bit(bank, REG_GPIO_DOUT, offset, output_value); +} + +static int tz1090_gpio_request(struct gpio_chip *chip, unsigned int offset) +{ + struct tz1090_gpio_bank *bank = to_bank(chip); + int ret; + + ret = pinctrl_request_gpio(chip->base + offset); + if (ret) + return ret; + + tz1090_gpio_set_bit(bank, REG_GPIO_DIR, offset); + tz1090_gpio_set_bit(bank, REG_GPIO_BIT_EN, offset); + + return 0; +} + +static void tz1090_gpio_free(struct gpio_chip *chip, unsigned int offset) +{ + struct tz1090_gpio_bank *bank = to_bank(chip); + + pinctrl_free_gpio(chip->base + offset); + + tz1090_gpio_clear_bit(bank, REG_GPIO_BIT_EN, offset); +} + +static int tz1090_gpio_to_irq(struct gpio_chip *chip, unsigned int offset) +{ + struct tz1090_gpio_bank *bank = to_bank(chip); + + if (!bank->domain) + return -EINVAL; + + return irq_create_mapping(bank->domain, offset); +} + +/* IRQ chip handlers */ + +/* Get TZ1090 GPIO chip from irq data provided to generic IRQ callbacks */ +static inline struct tz1090_gpio_bank *irqd_to_gpio_bank(struct irq_data *data) +{ + return (struct tz1090_gpio_bank *)data->domain->host_data; +} + +static void tz1090_gpio_irq_polarity(struct tz1090_gpio_bank *bank, + unsigned int offset, unsigned int polarity) +{ + tz1090_gpio_mod_bit(bank, REG_GPIO_IRQ_PLRT, offset, polarity); +} + +static void tz1090_gpio_irq_type(struct tz1090_gpio_bank *bank, + unsigned int offset, unsigned int type) +{ + tz1090_gpio_mod_bit(bank, REG_GPIO_IRQ_TYPE, offset, type); +} + +/* set polarity to trigger on next edge, whether rising or falling */ +static void tz1090_gpio_irq_next_edge(struct tz1090_gpio_bank *bank, + unsigned int offset) +{ + unsigned int value_p, value_i; + int lstat; + + /* + * Set the GPIO's interrupt polarity to the opposite of the current + * input value so that the next edge triggers an interrupt. + */ + __global_lock2(lstat); + value_i = ~tz1090_gpio_read(bank, REG_GPIO_DIN); + value_p = tz1090_gpio_read(bank, REG_GPIO_IRQ_PLRT); + value_p &= ~BIT(offset); + value_p |= value_i & BIT(offset); + tz1090_gpio_write(bank, REG_GPIO_IRQ_PLRT, value_p); + __global_unlock2(lstat); +} + +static unsigned int gpio_startup_irq(struct irq_data *data) +{ + /* + * This warning indicates that the type of the irq hasn't been set + * before enabling the irq. This would normally be done by passing some + * trigger flags to request_irq(). + */ + WARN(irqd_get_trigger_type(data) == IRQ_TYPE_NONE, + "irq type not set before enabling gpio irq %d", data->irq); + + irq_gc_ack_clr_bit(data); + irq_gc_mask_set_bit(data); + return 0; +} + +static int gpio_set_irq_type(struct irq_data *data, unsigned int flow_type) +{ + struct tz1090_gpio_bank *bank = irqd_to_gpio_bank(data); + unsigned int type; + unsigned int polarity; + + switch (flow_type) { + case IRQ_TYPE_EDGE_BOTH: + type = REG_GPIO_IRQ_TYPE_EDGE; + polarity = REG_GPIO_IRQ_PLRT_LOW; + break; + case IRQ_TYPE_EDGE_RISING: + type = REG_GPIO_IRQ_TYPE_EDGE; + polarity = REG_GPIO_IRQ_PLRT_HIGH; + break; + case IRQ_TYPE_EDGE_FALLING: + type = REG_GPIO_IRQ_TYPE_EDGE; + polarity = REG_GPIO_IRQ_PLRT_LOW; + break; + case IRQ_TYPE_LEVEL_HIGH: + type = REG_GPIO_IRQ_TYPE_LEVEL; + polarity = REG_GPIO_IRQ_PLRT_HIGH; + break; + case IRQ_TYPE_LEVEL_LOW: + type = REG_GPIO_IRQ_TYPE_LEVEL; + polarity = REG_GPIO_IRQ_PLRT_LOW; + break; + default: + return -EINVAL; + } + + tz1090_gpio_irq_type(bank, data->hwirq, type); + irq_setup_alt_chip(data, flow_type); + + if (flow_type == IRQ_TYPE_EDGE_BOTH) + tz1090_gpio_irq_next_edge(bank, data->hwirq); + else + tz1090_gpio_irq_polarity(bank, data->hwirq, polarity); + + return 0; +} + +#ifdef CONFIG_SUSPEND +static int gpio_set_irq_wake(struct irq_data *data, unsigned int on) +{ + struct tz1090_gpio_bank *bank = irqd_to_gpio_bank(data); + +#ifdef CONFIG_PM_DEBUG + pr_info("irq_wake irq%d state:%d\n", data->irq, on); +#endif + + /* wake on gpio block interrupt */ + return irq_set_irq_wake(bank->irq, on); +} +#else +#define gpio_set_irq_wake NULL +#endif + +static void tz1090_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) +{ + irq_hw_number_t hw; + unsigned int irq_stat, irq_no; + struct tz1090_gpio_bank *bank; + struct irq_desc *child_desc; + + bank = (struct tz1090_gpio_bank *)irq_desc_get_handler_data(desc); + irq_stat = tz1090_gpio_read(bank, REG_GPIO_DIR) & + tz1090_gpio_read(bank, REG_GPIO_IRQ_STS) & + tz1090_gpio_read(bank, REG_GPIO_IRQ_EN) & + 0x3FFFFFFF; /* 30 bits only */ + + for (hw = 0; irq_stat; irq_stat >>= 1, ++hw) { + if (!(irq_stat & 1)) + continue; + + irq_no = irq_linear_revmap(bank->domain, hw); + child_desc = irq_to_desc(irq_no); + + /* Toggle edge for pin with both edges triggering enabled */ + if (irqd_get_trigger_type(&child_desc->irq_data) + == IRQ_TYPE_EDGE_BOTH) + tz1090_gpio_irq_next_edge(bank, hw); + + generic_handle_irq_desc(irq_no, child_desc); + } +} + +static int tz1090_gpio_bank_probe(struct tz1090_gpio_bank_info *info) +{ + struct device_node *np = info->node; + struct device *dev = info->priv->dev; + struct tz1090_gpio_bank *bank; + struct irq_chip_generic *gc; + int err; + + bank = devm_kzalloc(dev, sizeof(*bank), GFP_KERNEL); + if (!bank) { + dev_err(dev, "unable to allocate driver data\n"); + return -ENOMEM; + } + + /* Offset the main registers to the first register in this bank */ + bank->reg = info->priv->reg + info->index * 4; + + /* Set up GPIO chip */ + snprintf(bank->label, sizeof(bank->label), "tz1090-gpio-%u", + info->index); + bank->chip.label = bank->label; + bank->chip.dev = dev; + bank->chip.direction_input = tz1090_gpio_direction_input; + bank->chip.direction_output = tz1090_gpio_direction_output; + bank->chip.get = tz1090_gpio_get; + bank->chip.set = tz1090_gpio_set; + bank->chip.free = tz1090_gpio_free; + bank->chip.request = tz1090_gpio_request; + bank->chip.to_irq = tz1090_gpio_to_irq; + bank->chip.of_node = np; + + /* GPIO numbering from 0 */ + bank->chip.base = info->index * 30; + bank->chip.ngpio = 30; + + /* Add the GPIO bank */ + gpiochip_add(&bank->chip); + + /* Get the GPIO bank IRQ if provided */ + bank->irq = irq_of_parse_and_map(np, 0); + + /* The interrupt is optional (it may be used by another core on chip) */ + if (bank->irq < 0) { + dev_info(dev, "IRQ not provided for bank %u, IRQs disabled\n", + info->index); + return 0; + } + + dev_info(dev, "Setting up IRQs for GPIO bank %u\n", + info->index); + + /* + * Initialise all interrupts to disabled so we don't get + * spurious ones on a dirty boot and hit the BUG_ON in the + * handler. + */ + tz1090_gpio_write(bank, REG_GPIO_IRQ_EN, 0); + + /* Add a virtual IRQ for each GPIO */ + bank->domain = irq_domain_add_linear(np, + bank->chip.ngpio, + &irq_generic_chip_ops, + bank); + + /* Set up a generic irq chip with 2 chip types (level and edge) */ + err = irq_alloc_domain_generic_chips(bank->domain, bank->chip.ngpio, 2, + bank->label, handle_bad_irq, 0, 0, + IRQ_GC_INIT_NESTED_LOCK); + if (err) { + dev_info(dev, + "irq_alloc_domain_generic_chips failed for bank %u, IRQs disabled\n", + info->index); + irq_domain_remove(bank->domain); + return 0; + } + + gc = irq_get_domain_generic_chip(bank->domain, 0); + gc->reg_base = bank->reg; + + /* level chip type */ + gc->chip_types[0].type = IRQ_TYPE_LEVEL_MASK; + gc->chip_types[0].handler = handle_level_irq; + gc->chip_types[0].regs.ack = REG_GPIO_IRQ_STS; + gc->chip_types[0].regs.mask = REG_GPIO_IRQ_EN; + gc->chip_types[0].chip.irq_startup = gpio_startup_irq, + gc->chip_types[0].chip.irq_ack = irq_gc_ack_clr_bit, + gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit, + gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit, + gc->chip_types[0].chip.irq_set_type = gpio_set_irq_type, + gc->chip_types[0].chip.irq_set_wake = gpio_set_irq_wake, + gc->chip_types[0].chip.flags = IRQCHIP_MASK_ON_SUSPEND, + + /* edge chip type */ + gc->chip_types[1].type = IRQ_TYPE_EDGE_BOTH; + gc->chip_types[1].handler = handle_edge_irq; + gc->chip_types[1].regs.ack = REG_GPIO_IRQ_STS; + gc->chip_types[1].regs.mask = REG_GPIO_IRQ_EN; + gc->chip_types[1].chip.irq_startup = gpio_startup_irq, + gc->chip_types[1].chip.irq_ack = irq_gc_ack_clr_bit, + gc->chip_types[1].chip.irq_mask = irq_gc_mask_clr_bit, + gc->chip_types[1].chip.irq_unmask = irq_gc_mask_set_bit, + gc->chip_types[1].chip.irq_set_type = gpio_set_irq_type, + gc->chip_types[1].chip.irq_set_wake = gpio_set_irq_wake, + gc->chip_types[1].chip.flags = IRQCHIP_MASK_ON_SUSPEND, + + /* Setup chained handler for this GPIO bank */ + irq_set_handler_data(bank->irq, bank); + irq_set_chained_handler(bank->irq, tz1090_gpio_irq_handler); + + return 0; +} + +static void tz1090_gpio_register_banks(struct tz1090_gpio *priv) +{ + struct device_node *np = priv->dev->of_node; + struct device_node *node; + + for_each_available_child_of_node(np, node) { + struct tz1090_gpio_bank_info info; + u32 addr; + int ret; + + ret = of_property_read_u32(node, "reg", &addr); + if (ret) { + dev_err(priv->dev, "invalid reg on %s\n", + node->full_name); + continue; + } + if (addr >= 3) { + dev_err(priv->dev, "index %u in %s out of range\n", + addr, node->full_name); + continue; + } + + info.index = addr; + info.node = of_node_get(node); + info.priv = priv; + + ret = tz1090_gpio_bank_probe(&info); + if (ret) { + dev_err(priv->dev, "failure registering %s\n", + node->full_name); + of_node_put(node); + continue; + } + } +} + +static int tz1090_gpio_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct resource *res_regs; + struct tz1090_gpio priv; + + if (!np) { + dev_err(&pdev->dev, "must be instantiated via devicetree\n"); + return -ENOENT; + } + + res_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res_regs) { + dev_err(&pdev->dev, "cannot find registers resource\n"); + return -ENOENT; + } + + priv.dev = &pdev->dev; + + /* Ioremap the registers */ + priv.reg = devm_ioremap(&pdev->dev, res_regs->start, + res_regs->end - res_regs->start); + if (!priv.reg) { + dev_err(&pdev->dev, "unable to ioremap registers\n"); + return -ENOMEM; + } + + /* Look for banks */ + tz1090_gpio_register_banks(&priv); + + return 0; +} + +static struct of_device_id tz1090_gpio_of_match[] = { + { .compatible = "img,tz1090-gpio" }, + { }, +}; + +static struct platform_driver tz1090_gpio_driver = { + .driver = { + .name = "tz1090-gpio", + .owner = THIS_MODULE, + .of_match_table = tz1090_gpio_of_match, + }, + .probe = tz1090_gpio_probe, +}; + +static int __init tz1090_gpio_init(void) +{ + return platform_driver_register(&tz1090_gpio_driver); +} +subsys_initcall(tz1090_gpio_init); diff --git a/drivers/gpio/gpio-ucb1400.c b/drivers/gpio/gpio-ucb1400.c index 6d0feb234d3c..1a605f2a0f55 100644 --- a/drivers/gpio/gpio-ucb1400.c +++ b/drivers/gpio/gpio-ucb1400.c @@ -45,7 +45,7 @@ static void ucb1400_gpio_set(struct gpio_chip *gc, unsigned off, int val) static int ucb1400_gpio_probe(struct platform_device *dev) { - struct ucb1400_gpio *ucb = dev->dev.platform_data; + struct ucb1400_gpio *ucb = dev_get_platdata(&dev->dev); int err = 0; if (!(ucb && ucb->gpio_offset)) { diff --git a/drivers/gpio/gpio-wm831x.c b/drivers/gpio/gpio-wm831x.c index 2a743e10ecb6..456000c5c457 100644 --- a/drivers/gpio/gpio-wm831x.c +++ b/drivers/gpio/gpio-wm831x.c @@ -246,7 +246,7 @@ static struct gpio_chip template_chip = { static int wm831x_gpio_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); - struct wm831x_pdata *pdata = wm831x->dev->platform_data; + struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev); struct wm831x_gpio *wm831x_gpio; int ret; diff --git a/drivers/gpio/gpio-wm8350.c b/drivers/gpio/gpio-wm8350.c index 0b598cf3df9d..fc49154be7b1 100644 --- a/drivers/gpio/gpio-wm8350.c +++ b/drivers/gpio/gpio-wm8350.c @@ -112,7 +112,7 @@ static struct gpio_chip template_chip = { static int wm8350_gpio_probe(struct platform_device *pdev) { struct wm8350 *wm8350 = dev_get_drvdata(pdev->dev.parent); - struct wm8350_platform_data *pdata = wm8350->dev->platform_data; + struct wm8350_platform_data *pdata = dev_get_platdata(wm8350->dev); struct wm8350_gpio_data *wm8350_gpio; int ret; diff --git a/drivers/gpio/gpio-wm8994.c b/drivers/gpio/gpio-wm8994.c index ae409fd94af7..a53dbdefc7ee 100644 --- a/drivers/gpio/gpio-wm8994.c +++ b/drivers/gpio/gpio-wm8994.c @@ -248,7 +248,7 @@ static struct gpio_chip template_chip = { static int wm8994_gpio_probe(struct platform_device *pdev) { struct wm8994 *wm8994 = dev_get_drvdata(pdev->dev.parent); - struct wm8994_pdata *pdata = wm8994->dev->platform_data; + struct wm8994_pdata *pdata = dev_get_platdata(wm8994->dev); struct wm8994_gpio *wm8994_gpio; int ret; diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 665f9530c950..ba9876ffb017 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -76,7 +76,8 @@ int of_get_named_gpio_flags(struct device_node *np, const char *propname, ret = of_parse_phandle_with_args(np, propname, "#gpio-cells", index, &gg_data.gpiospec); if (ret) { - pr_debug("%s: can't parse gpios property\n", __func__); + pr_debug("%s: can't parse gpios property of node '%s[%d]'\n", + __func__, np->full_name, index); return ret; } diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index ff0fd655729f..86ef3461ec06 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -349,7 +349,7 @@ static ssize_t gpio_value_store(struct device *dev, else { long value; - status = strict_strtol(buf, 0, &value); + status = kstrtol(buf, 0, &value); if (status == 0) { if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) value = !value; @@ -570,7 +570,7 @@ static ssize_t gpio_active_low_store(struct device *dev, } else { long value; - status = strict_strtol(buf, 0, &value); + status = kstrtol(buf, 0, &value); if (status == 0) status = sysfs_set_active_low(desc, dev, value != 0); } @@ -652,7 +652,7 @@ static ssize_t export_store(struct class *class, struct gpio_desc *desc; int status; - status = strict_strtol(buf, 0, &gpio); + status = kstrtol(buf, 0, &gpio); if (status < 0) goto done; @@ -694,7 +694,7 @@ static ssize_t unexport_store(struct class *class, struct gpio_desc *desc; int status; - status = strict_strtol(buf, 0, &gpio); + status = kstrtol(buf, 0, &gpio); if (status < 0) goto done; @@ -1398,7 +1398,7 @@ static int gpiod_request(struct gpio_desc *desc, const char *label) int status = -EPROBE_DEFER; unsigned long flags; - if (!desc) { + if (!desc || !desc->chip) { pr_warn("%s: invalid GPIO\n", __func__); return -EINVAL; } @@ -1406,8 +1406,6 @@ static int gpiod_request(struct gpio_desc *desc, const char *label) spin_lock_irqsave(&gpio_lock, flags); chip = desc->chip; - if (chip == NULL) - goto done; if (!try_module_get(chip->owner)) goto done; @@ -1630,16 +1628,20 @@ static int gpiod_direction_input(struct gpio_desc *desc) int status = -EINVAL; int offset; - if (!desc) { + if (!desc || !desc->chip) { pr_warn("%s: invalid GPIO\n", __func__); return -EINVAL; } + chip = desc->chip; + if (!chip->get || !chip->direction_input) { + pr_warn("%s: missing get() or direction_input() operations\n", + __func__); + return -EIO; + } + spin_lock_irqsave(&gpio_lock, flags); - chip = desc->chip; - if (!chip || !chip->get || !chip->direction_input) - goto fail; status = gpio_ensure_requested(desc); if (status < 0) goto fail; @@ -1691,7 +1693,7 @@ static int gpiod_direction_output(struct gpio_desc *desc, int value) int status = -EINVAL; int offset; - if (!desc) { + if (!desc || !desc->chip) { pr_warn("%s: invalid GPIO\n", __func__); return -EINVAL; } @@ -1704,11 +1706,15 @@ static int gpiod_direction_output(struct gpio_desc *desc, int value) if (!value && test_bit(FLAG_OPEN_SOURCE, &desc->flags)) return gpiod_direction_input(desc); + chip = desc->chip; + if (!chip->set || !chip->direction_output) { + pr_warn("%s: missing set() or direction_output() operations\n", + __func__); + return -EIO; + } + spin_lock_irqsave(&gpio_lock, flags); - chip = desc->chip; - if (!chip || !chip->set || !chip->direction_output) - goto fail; status = gpio_ensure_requested(desc); if (status < 0) goto fail; @@ -1757,6 +1763,9 @@ EXPORT_SYMBOL_GPL(gpio_direction_output); * gpio_set_debounce - sets @debounce time for a @gpio * @gpio: the gpio to set debounce time * @debounce: debounce time is microseconds + * + * returns -ENOTSUPP if the controller does not support setting + * debounce. */ static int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) { @@ -1765,16 +1774,19 @@ static int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) int status = -EINVAL; int offset; - if (!desc) { + if (!desc || !desc->chip) { pr_warn("%s: invalid GPIO\n", __func__); return -EINVAL; } - spin_lock_irqsave(&gpio_lock, flags); - chip = desc->chip; - if (!chip || !chip->set || !chip->set_debounce) - goto fail; + if (!chip->set || !chip->set_debounce) { + pr_debug("%s: missing set() or set_debounce() operations\n", + __func__); + return -ENOTSUPP; + } + + spin_lock_irqsave(&gpio_lock, flags); status = gpio_ensure_requested(desc); if (status < 0) diff --git a/include/linux/platform_data/gpio-em.h b/include/linux/platform_data/gpio-em.h index 573edfb046c4..7c5a519d2dcd 100644 --- a/include/linux/platform_data/gpio-em.h +++ b/include/linux/platform_data/gpio-em.h @@ -5,6 +5,7 @@ struct gpio_em_config { unsigned int gpio_base; unsigned int irq_base; unsigned int number_of_pins; + const char *pctl_name; }; #endif /* __GPIO_EM_H__ */ |