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