mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 12:28:41 +08:00
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. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.14 (GNU/Linux) iQIcBAABAgAGBQJSKZvzAAoJEEEQszewGV1zUg8QAMAqM90/U/0c73fxS28BbN6+ 5bO3a/l9JZYWHyk+739oFZqMUoPDKcq/IOSbirxdgpWE3zcF34ogNfIgSoAL77C5 3yGa2Lclkxmngo8ZXXeu6DSTq82rlaVjCcHcXw/qd6lVAZT8YaS364vGYpcENPxI s1yfrCZy89kZQufX++ytcbIUj75KXHvd9MK9IRE4BVkQMgLXAX/oSbTdB5PhFb79 J5ls0T1c8JRxI4sj32ZDh6dfeKGsRQF20z6OO5o0ZIyQ+ZGLJPlYatdivJelQz9J P67suwn86RXfABISYle2YbNmy3zX+wEyG2nHASDL7hSfWtGpZ5ANJTXqrKjwFITL sfqQhMtHDZ7fNbgA0kOyE25kgLybsJZNxR/PJGEHteT1+XZHi2nsP2NTNuxxEKjb 6NyLXrYXb0VK/poG+ZYXH2tt0C02pg3MfN9y+nfh8reG2bfeLvL/cU7DiQgMUGEf DXwgXQdgow9dHus/ZuCuWz4xqAfqk5VRS8ba6Wg2F8uLaXY1qYM6mNeatzTfP3fg 5jALMy038l7yMBMFnTp8GCb78/iIXWLtEejtgoowBuGbZtOjii8wEExHvl4tCabQ PbB9pG8+ojjiQPk2t1ZFFUqX6hCGBFrJbYnJj2vfftBHiFnz5bKrcSBOWVdTWgco YqURqegvZVin4aQNGFF2 =oEK9 -----END PGP SIGNATURE----- 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 ...
This commit is contained in:
commit
27c7651a6a
@ -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>;
|
||||
|
27
Documentation/devicetree/bindings/gpio/gpio-palmas.txt
Normal file
27
Documentation/devicetree/bindings/gpio/gpio-palmas.txt
Normal file
@ -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>;
|
||||
};
|
||||
:::::::::::
|
||||
};
|
45
Documentation/devicetree/bindings/gpio/gpio-tz1090-pdc.txt
Normal file
45
Documentation/devicetree/bindings/gpio/gpio-tz1090-pdc.txt
Normal file
@ -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>;
|
||||
};
|
88
Documentation/devicetree/bindings/gpio/gpio-tz1090.txt
Normal file
88
Documentation/devicetree/bindings/gpio/gpio-tz1090.txt
Normal file
@ -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>;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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>;
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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:
|
||||
|
469
drivers/gpio/gpio-f7188x.c
Normal file
469
drivers/gpio/gpio-f7188x.c
Normal file
@ -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");
|
@ -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;
|
||||
|
@ -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;
|
||||
|
219
drivers/gpio/gpio-kempld.c
Normal file
219
drivers/gpio/gpio-kempld.c
Normal file
@ -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");
|
@ -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");
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 = "mcp,mcp23017", .data = (void *) MCP_TYPE_017,
|
||||
.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,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
@ -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");
|
||||
|
@ -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;
|
||||
|
@ -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)))
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 */
|
||||
|
243
drivers/gpio/gpio-tz1090-pdc.c
Normal file
243
drivers/gpio/gpio-tz1090-pdc.c
Normal file
@ -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);
|
606
drivers/gpio/gpio-tz1090.c
Normal file
606
drivers/gpio/gpio-tz1090.c
Normal file
@ -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);
|
@ -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)) {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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__ */
|
||||
|
Loading…
Reference in New Issue
Block a user