mirror of
https://github.com/armbian/linux.git
synced 2026-01-06 10:13:00 -08:00
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:
@@ -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");
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user