mirror of
https://github.com/a52xq-dev/kernel.git
synced 2026-10-18 21:58:11 +07:00
This is the bulk of GPIO changes for the v3.18 development
cycle:
- Increase the default ARCH_NR_GPIO from 256 to 512. This
was done to avoid having a custom <asm/gpio.h> header for
the x86 architecture - GPIO is custom and complicated
enough as it is already! We want to move to a radix to
store the descriptors going forward, and finally get rid
of this fixed array size altogether.
- Endgame patching of the gpio_remove() semantics initiated
by Abdoulaye Berthe. It is not accepted by the system that
the removal of a GPIO chip fails during e.g. reboot or
shutdown, and therefore the return value has now painfully
been refactored away. For special cases like GPIO expanders
on a hot-pluggable bus like USB, we may later add some
gpiochip_try_remove() call, but for the cases we have now,
return values are moot.
- Some incremental refactoring of the gpiolib core and ACPI
GPIO library for more descriptor usage.
- Refactor the chained IRQ handler set-up method to handle
also threaded, nested interrupts and set up the parent IRQ
correctly. Switch STMPE and TC3589x drivers to use this
registration method.
- Add a .irq_not_threaded flag to the struct gpio_chip, so
that also GPIO expanders that block but are still not
using threaded IRQ handlers.
- New drivers for the ARM64 X-Gene SoC GPIO controller.
- The syscon GPIO driver has been improved to handle the
"DSP GPIO" found on the TI Keystone 2 SoC:s.
- ADNP driver switched to use gpiolib irqchip helpers.
- Refactor the DWAPB driver to support being instantiated
from and MFD cell (platform device).
- Incremental feature improvement in the Zynq, MCP23S08,
DWAPB, OMAP, Xilinx and Crystalcove drivers.
- Various minor fixes.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1
iQIcBAABAgAGBQJUNOr0AAoJEEEQszewGV1z9toP/2ISXRnsi3+jlqVmEGm/y6EA
PPwJOiYnOhZR2/fTCHIF0PNbIi9pw7xKnzxttYCu4uCz7geHX+FfTwUZ2/KWMfqi
ZJ9kEoOVVKzKjmL/m2a2tO4IRSBHqJ8dF3yvaNjS3AL7EDfG6F5STErQurdLEynK
SeJZ2OwM/vRFCac6F7oDlqAUTu3xYGbVD8+zI0H0V/ReocosFlEwcbl2S8ctDWUd
h98M+gY+A8rxkvVMnmQ/k7rUTme/glDQ3z5xVx+uHbS2/a5M1jSM/71cXE6YnSrR
it0CK7CHomq2RzHsKf7oH7GD4kFkukMwFKeMoqz75JWz3352VZPTF53chCIqRSgO
hrgGwZ7WF6pUUUhsn1ZdZsnBPA2Fou2uwslyLSAiE+OYEH2/NSVIOUcorjQcWqU/
0Kix5yb8X1ZzRMhR+TVrTD5V0jguqp2buXq+0P2XlU6MoO2vy7iNf2eXvPg8sF8C
anjTCKgmkzy7eyT2uzfDaNZAyfSBKb1TiKiR9zA0SRChJkCi1ErJEXDGeHiptvSA
+D2k68Ils2LqsvdrnEd2XvVFMllh0iq7b+16o7D+Els0WRbnHpfYCaqfOuF5F4U0
SmeyI0ruawNDc5e9EBKXstt0/R9AMOetyTcTu29U2ZVo90zGaT1ofT8+R1jJ0kGa
bPARJZrgecgv1E9Qnnnd
=8InA
-----END PGP SIGNATURE-----
Merge tag 'gpio-v3.18-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio
Pull GPIO changes from Linus Walleij:
"This is the bulk of GPIO changes for the v3.18 development cycle:
- Increase the default ARCH_NR_GPIO from 256 to 512. This was done
to avoid having a custom <asm/gpio.h> header for the x86
architecture - GPIO is custom and complicated enough as it is
already! We want to move to a radix to store the descriptors going
forward, and finally get rid of this fixed array size altogether.
- Endgame patching of the gpio_remove() semantics initiated by
Abdoulaye Berthe. It is not accepted by the system that the
removal of a GPIO chip fails during eg reboot or shutdown, and
therefore the return value has now painfully been refactored away.
For special cases like GPIO expanders on a hot-pluggable bus like
USB, we may later add some gpiochip_try_remove() call, but for the
cases we have now, return values are moot.
- Some incremental refactoring of the gpiolib core and ACPI GPIO
library for more descriptor usage.
- Refactor the chained IRQ handler set-up method to handle also
threaded, nested interrupts and set up the parent IRQ correctly.
Switch STMPE and TC3589x drivers to use this registration method.
- Add a .irq_not_threaded flag to the struct gpio_chip, so that also
GPIO expanders that block but are still not using threaded IRQ
handlers.
- New drivers for the ARM64 X-Gene SoC GPIO controller.
- The syscon GPIO driver has been improved to handle the "DSP GPIO"
found on the TI Keystone 2 SoC:s.
- ADNP driver switched to use gpiolib irqchip helpers.
- Refactor the DWAPB driver to support being instantiated from and
MFD cell (platform device).
- Incremental feature improvement in the Zynq, MCP23S08, DWAPB, OMAP,
Xilinx and Crystalcove drivers.
- Various minor fixes"
* tag 'gpio-v3.18-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (52 commits)
gpio: pch: Build context save/restore only for PM
pinctrl: abx500: get rid of unused variable
gpio: ks8695: fix 'else should follow close brace '}''
gpio: stmpe: add verbose debug code
gpio: stmpe: fix up interrupt enable logic
gpio: staticize xway_stp_init()
gpio: handle also nested irqchips in the chained handler set-up
gpio: set parent irq on chained handlers
gpiolib: irqchip: use irq_find_mapping while removing irqchip
gpio: crystalcove: support virtual GPIO
pinctrl: bcm281xx: make Kconfig dependency more strict
gpio: kona: enable only on BCM_MOBILE or for compile testing
gpio, bcm-kona, LLVMLinux: Remove use of __initconst
gpio: Fix ngpio in gpio-xilinx driver
gpio: dwapb: fix pointer to integer cast
gpio: xgene: Remove unneeded #ifdef CONFIG_OF guard
gpio: xgene: Remove unneeded forward declation for struct xgene_gpio
gpio: xgene: Fix missing spin_lock_init()
gpio: ks8695: fix switch case indentation
gpiolib: add irq_not_threaded flag to gpio_chip
...
This commit is contained in:
commit
ea584595fc
65 changed files with 1297 additions and 659 deletions
39
Documentation/devicetree/bindings/gpio/gpio-dsp-keystone.txt
Normal file
39
Documentation/devicetree/bindings/gpio/gpio-dsp-keystone.txt
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
Keystone 2 DSP GPIO controller bindings
|
||||
|
||||
HOST OS userland running on ARM can send interrupts to DSP cores using
|
||||
the DSP GPIO controller IP. It provides 28 IRQ signals per each DSP core.
|
||||
This is one of the component used by the IPC mechanism used on Keystone SOCs.
|
||||
|
||||
For example TCI6638K2K SoC has 8 DSP GPIO controllers:
|
||||
- 8 for C66x CorePacx CPUs 0-7
|
||||
|
||||
Keystone 2 DSP GPIO controller has specific features:
|
||||
- each GPIO can be configured only as output pin;
|
||||
- setting GPIO value to 1 causes IRQ generation on target DSP core;
|
||||
- reading pin value returns 0 - if IRQ was handled or 1 - IRQ is still
|
||||
pending.
|
||||
|
||||
Required Properties:
|
||||
- compatible: should be "ti,keystone-dsp-gpio"
|
||||
- ti,syscon-dev: phandle/offset pair. The phandle to syscon used to
|
||||
access device state control registers and the offset of device's specific
|
||||
registers within device state control registers range.
|
||||
- gpio-controller: Marks the device node as a gpio controller.
|
||||
- #gpio-cells: Should be 2.
|
||||
|
||||
Please refer to gpio.txt in this directory for details of the common GPIO
|
||||
bindings used by client devices.
|
||||
|
||||
Example:
|
||||
dspgpio0: keystone_dsp_gpio@02620240 {
|
||||
compatible = "ti,keystone-dsp-gpio";
|
||||
ti,syscon-dev = <&devctrl 0x240>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
};
|
||||
|
||||
dsp0: dsp0 {
|
||||
compatible = "linux,rproc-user";
|
||||
...
|
||||
kick-gpio = <&dspgpio0 27>;
|
||||
};
|
||||
39
Documentation/devicetree/bindings/gpio/gpio-pca953x.txt
Normal file
39
Documentation/devicetree/bindings/gpio/gpio-pca953x.txt
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
* NXP PCA953x I2C GPIO multiplexer
|
||||
|
||||
Required properties:
|
||||
- compatible: Has to contain one of the following:
|
||||
nxp,pca9505
|
||||
nxp,pca9534
|
||||
nxp,pca9535
|
||||
nxp,pca9536
|
||||
nxp,pca9537
|
||||
nxp,pca9538
|
||||
nxp,pca9539
|
||||
nxp,pca9554
|
||||
nxp,pca9555
|
||||
nxp,pca9556
|
||||
nxp,pca9557
|
||||
nxp,pca9574
|
||||
nxp,pca9575
|
||||
nxp,pca9698
|
||||
maxim,max7310
|
||||
maxim,max7312
|
||||
maxim,max7313
|
||||
maxim,max7315
|
||||
ti,pca6107
|
||||
ti,tca6408
|
||||
ti,tca6416
|
||||
ti,tca6424
|
||||
exar,xra1202
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
gpio@20 {
|
||||
compatible = "nxp,pca9505";
|
||||
reg = <0x20>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_pca9505>;
|
||||
interrupt-parent = <&gpio3>;
|
||||
interrupts = <23 IRQ_TYPE_LEVEL_LOW>;
|
||||
};
|
||||
22
Documentation/devicetree/bindings/gpio/gpio-xgene.txt
Normal file
22
Documentation/devicetree/bindings/gpio/gpio-xgene.txt
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
APM X-Gene SoC GPIO controller bindings
|
||||
|
||||
This is a gpio controller that is part of the flash controller.
|
||||
This gpio controller controls a total of 48 gpios.
|
||||
|
||||
Required properties:
|
||||
- compatible: "apm,xgene-gpio" for X-Gene 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.
|
||||
|
||||
Example:
|
||||
gpio0: gpio0@1701c000 {
|
||||
compatible = "apm,xgene-gpio";
|
||||
reg = <0x0 0x1701c000 0x0 0x40>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
};
|
||||
|
|
@ -19,7 +19,7 @@ Required properties:
|
|||
- gpio-controller : Marks the device node as a gpio controller.
|
||||
- #gpio-cells : Should be one. It is the pin number.
|
||||
|
||||
Example:
|
||||
Example for a MMP platform:
|
||||
|
||||
gpio: gpio@d4019000 {
|
||||
compatible = "marvell,mmp-gpio";
|
||||
|
|
@ -32,6 +32,19 @@ Example:
|
|||
#interrupt-cells = <1>;
|
||||
};
|
||||
|
||||
Example for a PXA3xx platform:
|
||||
|
||||
gpio: gpio@40e00000 {
|
||||
compatible = "intel,pxa3xx-gpio";
|
||||
reg = <0x40e00000 0x10000>;
|
||||
interrupt-names = "gpio0", "gpio1", "gpio_mux";
|
||||
interrupts = <8 9 10>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <0x2>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <0x2>;
|
||||
};
|
||||
|
||||
* Marvell Orion GPIO Controller
|
||||
|
||||
Required properties:
|
||||
|
|
|
|||
|
|
@ -124,7 +124,8 @@ symbol:
|
|||
* gpiochip_set_chained_irqchip(): sets up a chained irq handler for a
|
||||
gpio_chip from a parent IRQ and passes the struct gpio_chip* as handler
|
||||
data. (Notice handler data, since the irqchip data is likely used by the
|
||||
parent irqchip!) This is for the chained type of chip.
|
||||
parent irqchip!) This is for the chained type of chip. This is also used
|
||||
to set up a nested irqchip if NULL is passed as handler.
|
||||
|
||||
To use the helpers please keep the following in mind:
|
||||
|
||||
|
|
@ -178,7 +179,8 @@ does not help since it pins the module to the kernel forever (it calls
|
|||
try_module_get()). A GPIO driver can use the following functions instead
|
||||
to request and free descriptors without being pinned to the kernel forever.
|
||||
|
||||
int gpiochip_request_own_desc(struct gpio_desc *desc, const char *label)
|
||||
struct gpio_desc *gpiochip_request_own_desc(struct gpio_desc *desc,
|
||||
const char *label)
|
||||
|
||||
void gpiochip_free_own_desc(struct gpio_desc *desc)
|
||||
|
||||
|
|
|
|||
|
|
@ -243,18 +243,12 @@ err_ioremap:
|
|||
static int scoop_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct scoop_dev *sdev = platform_get_drvdata(pdev);
|
||||
int ret;
|
||||
|
||||
if (!sdev)
|
||||
return -EINVAL;
|
||||
|
||||
if (sdev->gpio.base != -1) {
|
||||
ret = gpiochip_remove(&sdev->gpio);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Can't remove gpio chip: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
if (sdev->gpio.base != -1)
|
||||
gpiochip_remove(&sdev->gpio);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
iounmap(sdev->base);
|
||||
|
|
|
|||
|
|
@ -789,11 +789,11 @@ void __init txx9_iocled_init(unsigned long baseaddr,
|
|||
if (platform_device_add(pdev))
|
||||
goto out_pdev;
|
||||
return;
|
||||
|
||||
out_pdev:
|
||||
platform_device_put(pdev);
|
||||
out_gpio:
|
||||
if (gpiochip_remove(&iocled->chip))
|
||||
return;
|
||||
gpiochip_remove(&iocled->chip);
|
||||
out_unmap:
|
||||
iounmap(iocled->mmioaddr);
|
||||
out_free:
|
||||
|
|
|
|||
|
|
@ -141,7 +141,8 @@ static int mcu_gpiochip_add(struct mcu *mcu)
|
|||
|
||||
static int mcu_gpiochip_remove(struct mcu *mcu)
|
||||
{
|
||||
return gpiochip_remove(&mcu->gc);
|
||||
gpiochip_remove(&mcu->gc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mcu_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
|
|
|
|||
|
|
@ -128,10 +128,8 @@ int __init x3proto_gpio_setup(void)
|
|||
return 0;
|
||||
|
||||
err_irq:
|
||||
ret = gpiochip_remove(&x3proto_gpio_chip);
|
||||
if (unlikely(ret))
|
||||
pr_err("Failed deregistering GPIO\n");
|
||||
|
||||
gpiochip_remove(&x3proto_gpio_chip);
|
||||
ret = 0;
|
||||
err_gpio:
|
||||
synchronize_irq(ilsel);
|
||||
|
||||
|
|
|
|||
|
|
@ -255,5 +255,6 @@ int bcma_gpio_init(struct bcma_drv_cc *cc)
|
|||
int bcma_gpio_unregister(struct bcma_drv_cc *cc)
|
||||
{
|
||||
bcma_gpio_irq_domain_exit(cc);
|
||||
return gpiochip_remove(&cc->gpio);
|
||||
gpiochip_remove(&cc->gpio);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -136,7 +136,6 @@ config GPIO_DWAPB
|
|||
tristate "Synopsys DesignWare APB GPIO driver"
|
||||
select GPIO_GENERIC
|
||||
select GENERIC_IRQ_CHIP
|
||||
depends on OF_GPIO
|
||||
help
|
||||
Say Y or M here to build support for the Synopsys DesignWare APB
|
||||
GPIO block.
|
||||
|
|
@ -334,6 +333,15 @@ config GPIO_TZ1090_PDC
|
|||
help
|
||||
Say yes here to support Toumaz Xenif TZ1090 PDC GPIOs.
|
||||
|
||||
config GPIO_XGENE
|
||||
bool "APM X-Gene GPIO controller support"
|
||||
depends on ARM64 && OF_GPIO
|
||||
help
|
||||
This driver is to support the GPIO block within the APM X-Gene SoC
|
||||
platform's generic flash controller. The GPIO pins are muxed with
|
||||
the generic flash controller's address and data pins. Say yes
|
||||
here to enable the GFC GPIO functionality.
|
||||
|
||||
config GPIO_XILINX
|
||||
bool "Xilinx GPIO support"
|
||||
depends on PPC_OF || MICROBLAZE || ARCH_ZYNQ
|
||||
|
|
@ -681,6 +689,7 @@ config GPIO_ADP5588_IRQ
|
|||
config GPIO_ADNP
|
||||
tristate "Avionic Design N-bit GPIO expander"
|
||||
depends on I2C && OF_GPIO
|
||||
select GPIOLIB_IRQCHIP
|
||||
help
|
||||
This option enables support for N GPIOs found on Avionic Design
|
||||
I2C GPIO expanders. The register space will be extended by powers
|
||||
|
|
@ -796,7 +805,6 @@ config GPIO_MAX7301
|
|||
|
||||
config GPIO_MCP23S08
|
||||
tristate "Microchip MCP23xxx I/O expander"
|
||||
depends on OF_GPIO
|
||||
depends on (SPI_MASTER && !I2C) || I2C
|
||||
help
|
||||
SPI/I2C driver for Microchip MCP23S08/MCP23S17/MCP23008/MCP23017
|
||||
|
|
@ -880,7 +888,7 @@ config GPIO_MSIC
|
|||
|
||||
config GPIO_BCM_KONA
|
||||
bool "Broadcom Kona GPIO"
|
||||
depends on OF_GPIO
|
||||
depends on OF_GPIO && (ARCH_BCM_MOBILE || COMPILE_TEST)
|
||||
help
|
||||
Turn on GPIO support for Broadcom "Kona" chips.
|
||||
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o
|
|||
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_XILINX) += gpio-xilinx.o
|
||||
obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o
|
||||
obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o
|
||||
|
|
|
|||
|
|
@ -6,10 +6,9 @@
|
|||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/seq_file.h>
|
||||
|
|
@ -27,8 +26,6 @@ struct adnp {
|
|||
unsigned int reg_shift;
|
||||
|
||||
struct mutex i2c_lock;
|
||||
|
||||
struct irq_domain *domain;
|
||||
struct mutex irq_lock;
|
||||
|
||||
u8 *irq_enable;
|
||||
|
|
@ -253,6 +250,7 @@ static void adnp_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
|
|||
static int adnp_gpio_setup(struct adnp *adnp, unsigned int num_gpios)
|
||||
{
|
||||
struct gpio_chip *chip = &adnp->gpio;
|
||||
int err;
|
||||
|
||||
adnp->reg_shift = get_count_order(num_gpios) - 3;
|
||||
|
||||
|
|
@ -272,6 +270,10 @@ static int adnp_gpio_setup(struct adnp *adnp, unsigned int num_gpios)
|
|||
chip->of_node = chip->dev->of_node;
|
||||
chip->owner = THIS_MODULE;
|
||||
|
||||
err = gpiochip_add(chip);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -326,7 +328,8 @@ static irqreturn_t adnp_irq(int irq, void *data)
|
|||
|
||||
for_each_set_bit(bit, &pending, 8) {
|
||||
unsigned int child_irq;
|
||||
child_irq = irq_find_mapping(adnp->domain, base + bit);
|
||||
child_irq = irq_find_mapping(adnp->gpio.irqdomain,
|
||||
base + bit);
|
||||
handle_nested_irq(child_irq);
|
||||
}
|
||||
}
|
||||
|
|
@ -334,35 +337,32 @@ static irqreturn_t adnp_irq(int irq, void *data)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int adnp_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
|
||||
static void adnp_irq_mask(struct irq_data *d)
|
||||
{
|
||||
struct adnp *adnp = to_adnp(chip);
|
||||
return irq_create_mapping(adnp->domain, offset);
|
||||
}
|
||||
|
||||
static void adnp_irq_mask(struct irq_data *data)
|
||||
{
|
||||
struct adnp *adnp = irq_data_get_irq_chip_data(data);
|
||||
unsigned int reg = data->hwirq >> adnp->reg_shift;
|
||||
unsigned int pos = data->hwirq & 7;
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct adnp *adnp = to_adnp(gc);
|
||||
unsigned int reg = d->hwirq >> adnp->reg_shift;
|
||||
unsigned int pos = d->hwirq & 7;
|
||||
|
||||
adnp->irq_enable[reg] &= ~BIT(pos);
|
||||
}
|
||||
|
||||
static void adnp_irq_unmask(struct irq_data *data)
|
||||
static void adnp_irq_unmask(struct irq_data *d)
|
||||
{
|
||||
struct adnp *adnp = irq_data_get_irq_chip_data(data);
|
||||
unsigned int reg = data->hwirq >> adnp->reg_shift;
|
||||
unsigned int pos = data->hwirq & 7;
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct adnp *adnp = to_adnp(gc);
|
||||
unsigned int reg = d->hwirq >> adnp->reg_shift;
|
||||
unsigned int pos = d->hwirq & 7;
|
||||
|
||||
adnp->irq_enable[reg] |= BIT(pos);
|
||||
}
|
||||
|
||||
static int adnp_irq_set_type(struct irq_data *data, unsigned int type)
|
||||
static int adnp_irq_set_type(struct irq_data *d, unsigned int type)
|
||||
{
|
||||
struct adnp *adnp = irq_data_get_irq_chip_data(data);
|
||||
unsigned int reg = data->hwirq >> adnp->reg_shift;
|
||||
unsigned int pos = data->hwirq & 7;
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct adnp *adnp = to_adnp(gc);
|
||||
unsigned int reg = d->hwirq >> adnp->reg_shift;
|
||||
unsigned int pos = d->hwirq & 7;
|
||||
|
||||
if (type & IRQ_TYPE_EDGE_RISING)
|
||||
adnp->irq_rise[reg] |= BIT(pos);
|
||||
|
|
@ -387,16 +387,18 @@ static int adnp_irq_set_type(struct irq_data *data, unsigned int type)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void adnp_irq_bus_lock(struct irq_data *data)
|
||||
static void adnp_irq_bus_lock(struct irq_data *d)
|
||||
{
|
||||
struct adnp *adnp = irq_data_get_irq_chip_data(data);
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct adnp *adnp = to_adnp(gc);
|
||||
|
||||
mutex_lock(&adnp->irq_lock);
|
||||
}
|
||||
|
||||
static void adnp_irq_bus_unlock(struct irq_data *data)
|
||||
static void adnp_irq_bus_unlock(struct irq_data *d)
|
||||
{
|
||||
struct adnp *adnp = irq_data_get_irq_chip_data(data);
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct adnp *adnp = to_adnp(gc);
|
||||
unsigned int num_regs = 1 << adnp->reg_shift, i;
|
||||
|
||||
mutex_lock(&adnp->i2c_lock);
|
||||
|
|
@ -408,26 +410,6 @@ static void adnp_irq_bus_unlock(struct irq_data *data)
|
|||
mutex_unlock(&adnp->irq_lock);
|
||||
}
|
||||
|
||||
static int adnp_irq_reqres(struct irq_data *data)
|
||||
{
|
||||
struct adnp *adnp = irq_data_get_irq_chip_data(data);
|
||||
|
||||
if (gpio_lock_as_irq(&adnp->gpio, data->hwirq)) {
|
||||
dev_err(adnp->gpio.dev,
|
||||
"unable to lock HW IRQ %lu for IRQ\n",
|
||||
data->hwirq);
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void adnp_irq_relres(struct irq_data *data)
|
||||
{
|
||||
struct adnp *adnp = irq_data_get_irq_chip_data(data);
|
||||
|
||||
gpio_unlock_as_irq(&adnp->gpio, data->hwirq);
|
||||
}
|
||||
|
||||
static struct irq_chip adnp_irq_chip = {
|
||||
.name = "gpio-adnp",
|
||||
.irq_mask = adnp_irq_mask,
|
||||
|
|
@ -435,29 +417,6 @@ static struct irq_chip adnp_irq_chip = {
|
|||
.irq_set_type = adnp_irq_set_type,
|
||||
.irq_bus_lock = adnp_irq_bus_lock,
|
||||
.irq_bus_sync_unlock = adnp_irq_bus_unlock,
|
||||
.irq_request_resources = adnp_irq_reqres,
|
||||
.irq_release_resources = adnp_irq_relres,
|
||||
};
|
||||
|
||||
static int adnp_irq_map(struct irq_domain *domain, unsigned int irq,
|
||||
irq_hw_number_t hwirq)
|
||||
{
|
||||
irq_set_chip_data(irq, domain->host_data);
|
||||
irq_set_chip(irq, &adnp_irq_chip);
|
||||
irq_set_nested_thread(irq, true);
|
||||
|
||||
#ifdef CONFIG_ARM
|
||||
set_irq_flags(irq, IRQF_VALID);
|
||||
#else
|
||||
irq_set_noprobe(irq);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct irq_domain_ops adnp_irq_domain_ops = {
|
||||
.map = adnp_irq_map,
|
||||
.xlate = irq_domain_xlate_twocell,
|
||||
};
|
||||
|
||||
static int adnp_irq_setup(struct adnp *adnp)
|
||||
|
|
@ -503,35 +462,28 @@ static int adnp_irq_setup(struct adnp *adnp)
|
|||
adnp->irq_enable[i] = 0x00;
|
||||
}
|
||||
|
||||
adnp->domain = irq_domain_add_linear(chip->of_node, chip->ngpio,
|
||||
&adnp_irq_domain_ops, adnp);
|
||||
|
||||
err = request_threaded_irq(adnp->client->irq, NULL, adnp_irq,
|
||||
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
|
||||
dev_name(chip->dev), adnp);
|
||||
err = devm_request_threaded_irq(chip->dev, adnp->client->irq,
|
||||
NULL, adnp_irq,
|
||||
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
|
||||
dev_name(chip->dev), adnp);
|
||||
if (err != 0) {
|
||||
dev_err(chip->dev, "can't request IRQ#%d: %d\n",
|
||||
adnp->client->irq, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
chip->to_irq = adnp_gpio_to_irq;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void adnp_irq_teardown(struct adnp *adnp)
|
||||
{
|
||||
unsigned int irq, i;
|
||||
|
||||
free_irq(adnp->client->irq, adnp);
|
||||
|
||||
for (i = 0; i < adnp->gpio.ngpio; i++) {
|
||||
irq = irq_find_mapping(adnp->domain, i);
|
||||
if (irq > 0)
|
||||
irq_dispose_mapping(irq);
|
||||
err = gpiochip_irqchip_add(chip,
|
||||
&adnp_irq_chip,
|
||||
0,
|
||||
handle_simple_irq,
|
||||
IRQ_TYPE_NONE);
|
||||
if (err) {
|
||||
dev_err(chip->dev,
|
||||
"could not connect irqchip to gpiochip\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
irq_domain_remove(adnp->domain);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adnp_i2c_probe(struct i2c_client *client,
|
||||
|
|
@ -558,38 +510,25 @@ static int adnp_i2c_probe(struct i2c_client *client,
|
|||
adnp->client = client;
|
||||
|
||||
err = adnp_gpio_setup(adnp, num_gpios);
|
||||
if (err < 0)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (of_find_property(np, "interrupt-controller", NULL)) {
|
||||
err = adnp_irq_setup(adnp);
|
||||
if (err < 0)
|
||||
goto teardown;
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = gpiochip_add(&adnp->gpio);
|
||||
if (err < 0)
|
||||
goto teardown;
|
||||
|
||||
i2c_set_clientdata(client, adnp);
|
||||
|
||||
return 0;
|
||||
|
||||
teardown:
|
||||
if (of_find_property(np, "interrupt-controller", NULL))
|
||||
adnp_irq_teardown(adnp);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int adnp_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct adnp *adnp = i2c_get_clientdata(client);
|
||||
struct device_node *np = client->dev.of_node;
|
||||
|
||||
gpiochip_remove(&adnp->gpio);
|
||||
if (of_find_property(np, "interrupt-controller", NULL))
|
||||
adnp_irq_teardown(adnp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -496,7 +496,7 @@ static struct irq_chip bcm_gpio_irq_chip = {
|
|||
.irq_release_resources = bcm_kona_gpio_irq_relres,
|
||||
};
|
||||
|
||||
static struct __initconst of_device_id bcm_kona_gpio_of_match[] = {
|
||||
static struct of_device_id const bcm_kona_gpio_of_match[] = {
|
||||
{ .compatible = "brcm,kona-gpio" },
|
||||
{}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include <linux/mfd/intel_soc_pmic.h>
|
||||
|
||||
#define CRYSTALCOVE_GPIO_NUM 16
|
||||
#define CRYSTALCOVE_VGPIO_NUM 94
|
||||
|
||||
#define UPDATE_IRQ_TYPE BIT(0)
|
||||
#define UPDATE_IRQ_MASK BIT(1)
|
||||
|
|
@ -130,6 +131,9 @@ static int crystalcove_gpio_dir_in(struct gpio_chip *chip, unsigned gpio)
|
|||
{
|
||||
struct crystalcove_gpio *cg = to_cg(chip);
|
||||
|
||||
if (gpio > CRYSTALCOVE_VGPIO_NUM)
|
||||
return 0;
|
||||
|
||||
return regmap_write(cg->regmap, to_reg(gpio, CTRL_OUT),
|
||||
CTLO_INPUT_SET);
|
||||
}
|
||||
|
|
@ -139,6 +143,9 @@ static int crystalcove_gpio_dir_out(struct gpio_chip *chip, unsigned gpio,
|
|||
{
|
||||
struct crystalcove_gpio *cg = to_cg(chip);
|
||||
|
||||
if (gpio > CRYSTALCOVE_VGPIO_NUM)
|
||||
return 0;
|
||||
|
||||
return regmap_write(cg->regmap, to_reg(gpio, CTRL_OUT),
|
||||
CTLO_OUTPUT_SET | value);
|
||||
}
|
||||
|
|
@ -149,6 +156,9 @@ static int crystalcove_gpio_get(struct gpio_chip *chip, unsigned gpio)
|
|||
int ret;
|
||||
unsigned int val;
|
||||
|
||||
if (gpio > CRYSTALCOVE_VGPIO_NUM)
|
||||
return 0;
|
||||
|
||||
ret = regmap_read(cg->regmap, to_reg(gpio, CTRL_IN), &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -161,6 +171,9 @@ static void crystalcove_gpio_set(struct gpio_chip *chip,
|
|||
{
|
||||
struct crystalcove_gpio *cg = to_cg(chip);
|
||||
|
||||
if (gpio > CRYSTALCOVE_VGPIO_NUM)
|
||||
return;
|
||||
|
||||
if (value)
|
||||
regmap_update_bits(cg->regmap, to_reg(gpio, CTRL_OUT), 1, 1);
|
||||
else
|
||||
|
|
@ -256,7 +269,7 @@ static irqreturn_t crystalcove_gpio_irq_handler(int irq, void *data)
|
|||
|
||||
pending = p0 | p1 << 8;
|
||||
|
||||
for (gpio = 0; gpio < cg->chip.ngpio; gpio++) {
|
||||
for (gpio = 0; gpio < CRYSTALCOVE_GPIO_NUM; gpio++) {
|
||||
if (pending & BIT(gpio)) {
|
||||
virq = irq_find_mapping(cg->chip.irqdomain, gpio);
|
||||
generic_handle_irq(virq);
|
||||
|
|
@ -273,7 +286,7 @@ static void crystalcove_gpio_dbg_show(struct seq_file *s,
|
|||
int gpio, offset;
|
||||
unsigned int ctlo, ctli, mirqs0, mirqsx, irq;
|
||||
|
||||
for (gpio = 0; gpio < cg->chip.ngpio; gpio++) {
|
||||
for (gpio = 0; gpio < CRYSTALCOVE_GPIO_NUM; gpio++) {
|
||||
regmap_read(cg->regmap, to_reg(gpio, CTRL_OUT), &ctlo);
|
||||
regmap_read(cg->regmap, to_reg(gpio, CTRL_IN), &ctli);
|
||||
regmap_read(cg->regmap, gpio < 8 ? MGPIO0IRQS0 : MGPIO1IRQS0,
|
||||
|
|
@ -320,7 +333,7 @@ static int crystalcove_gpio_probe(struct platform_device *pdev)
|
|||
cg->chip.get = crystalcove_gpio_get;
|
||||
cg->chip.set = crystalcove_gpio_set;
|
||||
cg->chip.base = -1;
|
||||
cg->chip.ngpio = CRYSTALCOVE_GPIO_NUM;
|
||||
cg->chip.ngpio = CRYSTALCOVE_VGPIO_NUM;
|
||||
cg->chip.can_sleep = true;
|
||||
cg->chip.dev = dev;
|
||||
cg->chip.dbg_show = crystalcove_gpio_dbg_show;
|
||||
|
|
@ -346,7 +359,7 @@ static int crystalcove_gpio_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
|
||||
out_remove_gpio:
|
||||
WARN_ON(gpiochip_remove(&cg->chip));
|
||||
gpiochip_remove(&cg->chip);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
@ -354,14 +367,11 @@ static int crystalcove_gpio_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct crystalcove_gpio *cg = platform_get_drvdata(pdev);
|
||||
int irq = platform_get_irq(pdev, 0);
|
||||
int err;
|
||||
|
||||
err = gpiochip_remove(&cg->chip);
|
||||
|
||||
gpiochip_remove(&cg->chip);
|
||||
if (irq >= 0)
|
||||
free_irq(irq, cg);
|
||||
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver crystalcove_gpio_driver = {
|
||||
|
|
|
|||
|
|
@ -201,7 +201,8 @@ EXPORT_SYMBOL_GPL(cs5535_gpio_setup_event);
|
|||
|
||||
static int chip_gpio_request(struct gpio_chip *c, unsigned offset)
|
||||
{
|
||||
struct cs5535_gpio_chip *chip = (struct cs5535_gpio_chip *) c;
|
||||
struct cs5535_gpio_chip *chip =
|
||||
container_of(c, struct cs5535_gpio_chip, chip);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&chip->lock, flags);
|
||||
|
|
@ -241,7 +242,8 @@ static void chip_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
|
|||
|
||||
static int chip_direction_input(struct gpio_chip *c, unsigned offset)
|
||||
{
|
||||
struct cs5535_gpio_chip *chip = (struct cs5535_gpio_chip *) c;
|
||||
struct cs5535_gpio_chip *chip =
|
||||
container_of(c, struct cs5535_gpio_chip, chip);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&chip->lock, flags);
|
||||
|
|
@ -254,7 +256,8 @@ static int chip_direction_input(struct gpio_chip *c, unsigned offset)
|
|||
|
||||
static int chip_direction_output(struct gpio_chip *c, unsigned offset, int val)
|
||||
{
|
||||
struct cs5535_gpio_chip *chip = (struct cs5535_gpio_chip *) c;
|
||||
struct cs5535_gpio_chip *chip =
|
||||
container_of(c, struct cs5535_gpio_chip, chip);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&chip->lock, flags);
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@
|
|||
#include <linux/of_irq.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/platform_data/gpio-dwapb.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define GPIO_SWPORTA_DR 0x00
|
||||
#define GPIO_SWPORTA_DDR 0x04
|
||||
|
|
@ -35,6 +37,7 @@
|
|||
#define GPIO_INTTYPE_LEVEL 0x38
|
||||
#define GPIO_INT_POLARITY 0x3c
|
||||
#define GPIO_INTSTATUS 0x40
|
||||
#define GPIO_PORTA_DEBOUNCE 0x48
|
||||
#define GPIO_PORTA_EOI 0x4c
|
||||
#define GPIO_EXT_PORTA 0x50
|
||||
#define GPIO_EXT_PORTB 0x54
|
||||
|
|
@ -48,10 +51,28 @@
|
|||
|
||||
struct dwapb_gpio;
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
/* Store GPIO context across system-wide suspend/resume transitions */
|
||||
struct dwapb_context {
|
||||
u32 data;
|
||||
u32 dir;
|
||||
u32 ext;
|
||||
u32 int_en;
|
||||
u32 int_mask;
|
||||
u32 int_type;
|
||||
u32 int_pol;
|
||||
u32 int_deb;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct dwapb_gpio_port {
|
||||
struct bgpio_chip bgc;
|
||||
bool is_registered;
|
||||
struct dwapb_gpio *gpio;
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
struct dwapb_context *ctx;
|
||||
#endif
|
||||
unsigned int idx;
|
||||
};
|
||||
|
||||
struct dwapb_gpio {
|
||||
|
|
@ -62,11 +83,33 @@ struct dwapb_gpio {
|
|||
struct irq_domain *domain;
|
||||
};
|
||||
|
||||
static inline struct dwapb_gpio_port *
|
||||
to_dwapb_gpio_port(struct bgpio_chip *bgc)
|
||||
{
|
||||
return container_of(bgc, struct dwapb_gpio_port, bgc);
|
||||
}
|
||||
|
||||
static inline u32 dwapb_read(struct dwapb_gpio *gpio, unsigned int offset)
|
||||
{
|
||||
struct bgpio_chip *bgc = &gpio->ports[0].bgc;
|
||||
void __iomem *reg_base = gpio->regs;
|
||||
|
||||
return bgc->read_reg(reg_base + offset);
|
||||
}
|
||||
|
||||
static inline void dwapb_write(struct dwapb_gpio *gpio, unsigned int offset,
|
||||
u32 val)
|
||||
{
|
||||
struct bgpio_chip *bgc = &gpio->ports[0].bgc;
|
||||
void __iomem *reg_base = gpio->regs;
|
||||
|
||||
bgc->write_reg(reg_base + offset, val);
|
||||
}
|
||||
|
||||
static int dwapb_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
|
||||
{
|
||||
struct bgpio_chip *bgc = to_bgpio_chip(gc);
|
||||
struct dwapb_gpio_port *port = container_of(bgc, struct
|
||||
dwapb_gpio_port, bgc);
|
||||
struct dwapb_gpio_port *port = to_dwapb_gpio_port(bgc);
|
||||
struct dwapb_gpio *gpio = port->gpio;
|
||||
|
||||
return irq_find_mapping(gpio->domain, offset);
|
||||
|
|
@ -74,21 +117,20 @@ static int dwapb_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
|
|||
|
||||
static void dwapb_toggle_trigger(struct dwapb_gpio *gpio, unsigned int offs)
|
||||
{
|
||||
u32 v = readl(gpio->regs + GPIO_INT_POLARITY);
|
||||
u32 v = dwapb_read(gpio, GPIO_INT_POLARITY);
|
||||
|
||||
if (gpio_get_value(gpio->ports[0].bgc.gc.base + offs))
|
||||
v &= ~BIT(offs);
|
||||
else
|
||||
v |= BIT(offs);
|
||||
|
||||
writel(v, gpio->regs + GPIO_INT_POLARITY);
|
||||
dwapb_write(gpio, GPIO_INT_POLARITY, v);
|
||||
}
|
||||
|
||||
static void dwapb_irq_handler(u32 irq, struct irq_desc *desc)
|
||||
static u32 dwapb_do_irq(struct dwapb_gpio *gpio)
|
||||
{
|
||||
struct dwapb_gpio *gpio = irq_get_handler_data(irq);
|
||||
struct irq_chip *chip = irq_desc_get_chip(desc);
|
||||
u32 irq_status = readl_relaxed(gpio->regs + GPIO_INTSTATUS);
|
||||
u32 ret = irq_status;
|
||||
|
||||
while (irq_status) {
|
||||
int hwirq = fls(irq_status) - 1;
|
||||
|
|
@ -102,6 +144,16 @@ static void dwapb_irq_handler(u32 irq, struct irq_desc *desc)
|
|||
dwapb_toggle_trigger(gpio, hwirq);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dwapb_irq_handler(u32 irq, struct irq_desc *desc)
|
||||
{
|
||||
struct dwapb_gpio *gpio = irq_get_handler_data(irq);
|
||||
struct irq_chip *chip = irq_desc_get_chip(desc);
|
||||
|
||||
dwapb_do_irq(gpio);
|
||||
|
||||
if (chip->irq_eoi)
|
||||
chip->irq_eoi(irq_desc_get_irq_data(desc));
|
||||
}
|
||||
|
|
@ -115,9 +167,9 @@ static void dwapb_irq_enable(struct irq_data *d)
|
|||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&bgc->lock, flags);
|
||||
val = readl(gpio->regs + GPIO_INTEN);
|
||||
val = dwapb_read(gpio, GPIO_INTEN);
|
||||
val |= BIT(d->hwirq);
|
||||
writel(val, gpio->regs + GPIO_INTEN);
|
||||
dwapb_write(gpio, GPIO_INTEN, val);
|
||||
spin_unlock_irqrestore(&bgc->lock, flags);
|
||||
}
|
||||
|
||||
|
|
@ -130,9 +182,9 @@ static void dwapb_irq_disable(struct irq_data *d)
|
|||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&bgc->lock, flags);
|
||||
val = readl(gpio->regs + GPIO_INTEN);
|
||||
val = dwapb_read(gpio, GPIO_INTEN);
|
||||
val &= ~BIT(d->hwirq);
|
||||
writel(val, gpio->regs + GPIO_INTEN);
|
||||
dwapb_write(gpio, GPIO_INTEN, val);
|
||||
spin_unlock_irqrestore(&bgc->lock, flags);
|
||||
}
|
||||
|
||||
|
|
@ -172,8 +224,8 @@ static int dwapb_irq_set_type(struct irq_data *d, u32 type)
|
|||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&bgc->lock, flags);
|
||||
level = readl(gpio->regs + GPIO_INTTYPE_LEVEL);
|
||||
polarity = readl(gpio->regs + GPIO_INT_POLARITY);
|
||||
level = dwapb_read(gpio, GPIO_INTTYPE_LEVEL);
|
||||
polarity = dwapb_read(gpio, GPIO_INT_POLARITY);
|
||||
|
||||
switch (type) {
|
||||
case IRQ_TYPE_EDGE_BOTH:
|
||||
|
|
@ -200,29 +252,55 @@ static int dwapb_irq_set_type(struct irq_data *d, u32 type)
|
|||
|
||||
irq_setup_alt_chip(d, type);
|
||||
|
||||
writel(level, gpio->regs + GPIO_INTTYPE_LEVEL);
|
||||
writel(polarity, gpio->regs + GPIO_INT_POLARITY);
|
||||
dwapb_write(gpio, GPIO_INTTYPE_LEVEL, level);
|
||||
dwapb_write(gpio, GPIO_INT_POLARITY, polarity);
|
||||
spin_unlock_irqrestore(&bgc->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwapb_gpio_set_debounce(struct gpio_chip *gc,
|
||||
unsigned offset, unsigned debounce)
|
||||
{
|
||||
struct bgpio_chip *bgc = to_bgpio_chip(gc);
|
||||
struct dwapb_gpio_port *port = to_dwapb_gpio_port(bgc);
|
||||
struct dwapb_gpio *gpio = port->gpio;
|
||||
unsigned long flags, val_deb;
|
||||
unsigned long mask = bgc->pin2mask(bgc, offset);
|
||||
|
||||
spin_lock_irqsave(&bgc->lock, flags);
|
||||
|
||||
val_deb = dwapb_read(gpio, GPIO_PORTA_DEBOUNCE);
|
||||
if (debounce)
|
||||
dwapb_write(gpio, GPIO_PORTA_DEBOUNCE, val_deb | mask);
|
||||
else
|
||||
dwapb_write(gpio, GPIO_PORTA_DEBOUNCE, val_deb & ~mask);
|
||||
|
||||
spin_unlock_irqrestore(&bgc->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t dwapb_irq_handler_mfd(int irq, void *dev_id)
|
||||
{
|
||||
u32 worked;
|
||||
struct dwapb_gpio *gpio = dev_id;
|
||||
|
||||
worked = dwapb_do_irq(gpio);
|
||||
|
||||
return worked ? IRQ_HANDLED : IRQ_NONE;
|
||||
}
|
||||
|
||||
static void dwapb_configure_irqs(struct dwapb_gpio *gpio,
|
||||
struct dwapb_gpio_port *port)
|
||||
struct dwapb_gpio_port *port,
|
||||
struct dwapb_port_property *pp)
|
||||
{
|
||||
struct gpio_chip *gc = &port->bgc.gc;
|
||||
struct device_node *node = gc->of_node;
|
||||
struct irq_chip_generic *irq_gc;
|
||||
struct device_node *node = pp->node;
|
||||
struct irq_chip_generic *irq_gc = NULL;
|
||||
unsigned int hwirq, ngpio = gc->ngpio;
|
||||
struct irq_chip_type *ct;
|
||||
int err, irq, i;
|
||||
|
||||
irq = irq_of_parse_and_map(node, 0);
|
||||
if (!irq) {
|
||||
dev_warn(gpio->dev, "no irq for bank %s\n",
|
||||
port->bgc.gc.of_node->full_name);
|
||||
return;
|
||||
}
|
||||
int err, i;
|
||||
|
||||
gpio->domain = irq_domain_add_linear(node, ngpio,
|
||||
&irq_generic_chip_ops, gpio);
|
||||
|
|
@ -269,8 +347,24 @@ static void dwapb_configure_irqs(struct dwapb_gpio *gpio,
|
|||
irq_gc->chip_types[1].type = IRQ_TYPE_EDGE_BOTH;
|
||||
irq_gc->chip_types[1].handler = handle_edge_irq;
|
||||
|
||||
irq_set_chained_handler(irq, dwapb_irq_handler);
|
||||
irq_set_handler_data(irq, gpio);
|
||||
if (!pp->irq_shared) {
|
||||
irq_set_chained_handler(pp->irq, dwapb_irq_handler);
|
||||
irq_set_handler_data(pp->irq, gpio);
|
||||
} else {
|
||||
/*
|
||||
* Request a shared IRQ since where MFD would have devices
|
||||
* using the same irq pin
|
||||
*/
|
||||
err = devm_request_irq(gpio->dev, pp->irq,
|
||||
dwapb_irq_handler_mfd,
|
||||
IRQF_SHARED, "gpio-dwapb-mfd", gpio);
|
||||
if (err) {
|
||||
dev_err(gpio->dev, "error requesting IRQ\n");
|
||||
irq_domain_remove(gpio->domain);
|
||||
gpio->domain = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (hwirq = 0 ; hwirq < ngpio ; hwirq++)
|
||||
irq_create_mapping(gpio->domain, hwirq);
|
||||
|
|
@ -296,57 +390,53 @@ static void dwapb_irq_teardown(struct dwapb_gpio *gpio)
|
|||
}
|
||||
|
||||
static int dwapb_gpio_add_port(struct dwapb_gpio *gpio,
|
||||
struct device_node *port_np,
|
||||
struct dwapb_port_property *pp,
|
||||
unsigned int offs)
|
||||
{
|
||||
struct dwapb_gpio_port *port;
|
||||
u32 port_idx, ngpio;
|
||||
void __iomem *dat, *set, *dirout;
|
||||
int err;
|
||||
|
||||
if (of_property_read_u32(port_np, "reg", &port_idx) ||
|
||||
port_idx >= DWAPB_MAX_PORTS) {
|
||||
dev_err(gpio->dev, "missing/invalid port index for %s\n",
|
||||
port_np->full_name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
port = &gpio->ports[offs];
|
||||
port->gpio = gpio;
|
||||
port->idx = pp->idx;
|
||||
|
||||
if (of_property_read_u32(port_np, "snps,nr-gpios", &ngpio)) {
|
||||
dev_info(gpio->dev, "failed to get number of gpios for %s\n",
|
||||
port_np->full_name);
|
||||
ngpio = 32;
|
||||
}
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
port->ctx = devm_kzalloc(gpio->dev, sizeof(*port->ctx), GFP_KERNEL);
|
||||
if (!port->ctx)
|
||||
return -ENOMEM;
|
||||
#endif
|
||||
|
||||
dat = gpio->regs + GPIO_EXT_PORTA + (port_idx * GPIO_EXT_PORT_SIZE);
|
||||
set = gpio->regs + GPIO_SWPORTA_DR + (port_idx * GPIO_SWPORT_DR_SIZE);
|
||||
dat = gpio->regs + GPIO_EXT_PORTA + (pp->idx * GPIO_EXT_PORT_SIZE);
|
||||
set = gpio->regs + GPIO_SWPORTA_DR + (pp->idx * GPIO_SWPORT_DR_SIZE);
|
||||
dirout = gpio->regs + GPIO_SWPORTA_DDR +
|
||||
(port_idx * GPIO_SWPORT_DDR_SIZE);
|
||||
(pp->idx * GPIO_SWPORT_DDR_SIZE);
|
||||
|
||||
err = bgpio_init(&port->bgc, gpio->dev, 4, dat, set, NULL, dirout,
|
||||
NULL, false);
|
||||
if (err) {
|
||||
dev_err(gpio->dev, "failed to init gpio chip for %s\n",
|
||||
port_np->full_name);
|
||||
pp->name);
|
||||
return err;
|
||||
}
|
||||
|
||||
port->bgc.gc.ngpio = ngpio;
|
||||
port->bgc.gc.of_node = port_np;
|
||||
#ifdef CONFIG_OF_GPIO
|
||||
port->bgc.gc.of_node = pp->node;
|
||||
#endif
|
||||
port->bgc.gc.ngpio = pp->ngpio;
|
||||
port->bgc.gc.base = pp->gpio_base;
|
||||
|
||||
/*
|
||||
* Only port A can provide interrupts in all configurations of the IP.
|
||||
*/
|
||||
if (port_idx == 0 &&
|
||||
of_property_read_bool(port_np, "interrupt-controller"))
|
||||
dwapb_configure_irqs(gpio, port);
|
||||
/* Only port A support debounce */
|
||||
if (pp->idx == 0)
|
||||
port->bgc.gc.set_debounce = dwapb_gpio_set_debounce;
|
||||
|
||||
if (pp->irq)
|
||||
dwapb_configure_irqs(gpio, port, pp);
|
||||
|
||||
err = gpiochip_add(&port->bgc.gc);
|
||||
if (err)
|
||||
dev_err(gpio->dev, "failed to register gpiochip for %s\n",
|
||||
port_np->full_name);
|
||||
pp->name);
|
||||
else
|
||||
port->is_registered = true;
|
||||
|
||||
|
|
@ -362,25 +452,116 @@ static void dwapb_gpio_unregister(struct dwapb_gpio *gpio)
|
|||
gpiochip_remove(&gpio->ports[m].bgc.gc);
|
||||
}
|
||||
|
||||
static struct dwapb_platform_data *
|
||||
dwapb_gpio_get_pdata_of(struct device *dev)
|
||||
{
|
||||
struct device_node *node, *port_np;
|
||||
struct dwapb_platform_data *pdata;
|
||||
struct dwapb_port_property *pp;
|
||||
int nports;
|
||||
int i;
|
||||
|
||||
node = dev->of_node;
|
||||
if (!IS_ENABLED(CONFIG_OF_GPIO) || !node)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
nports = of_get_child_count(node);
|
||||
if (nports == 0)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
pdata->properties = kcalloc(nports, sizeof(*pp), GFP_KERNEL);
|
||||
if (!pdata->properties) {
|
||||
kfree(pdata);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
pdata->nports = nports;
|
||||
|
||||
i = 0;
|
||||
for_each_child_of_node(node, port_np) {
|
||||
pp = &pdata->properties[i++];
|
||||
pp->node = port_np;
|
||||
|
||||
if (of_property_read_u32(port_np, "reg", &pp->idx) ||
|
||||
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);
|
||||
}
|
||||
|
||||
if (of_property_read_u32(port_np, "snps,nr-gpios",
|
||||
&pp->ngpio)) {
|
||||
dev_info(dev, "failed to get number of gpios for %s\n",
|
||||
port_np->full_name);
|
||||
pp->ngpio = 32;
|
||||
}
|
||||
|
||||
/*
|
||||
* Only port A can provide interrupts in all configurations of
|
||||
* the IP.
|
||||
*/
|
||||
if (pp->idx == 0 &&
|
||||
of_property_read_bool(port_np, "interrupt-controller")) {
|
||||
pp->irq = irq_of_parse_and_map(port_np, 0);
|
||||
if (!pp->irq) {
|
||||
dev_warn(dev, "no irq for bank %s\n",
|
||||
port_np->full_name);
|
||||
}
|
||||
}
|
||||
|
||||
pp->irq_shared = false;
|
||||
pp->gpio_base = -1;
|
||||
pp->name = port_np->full_name;
|
||||
}
|
||||
|
||||
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;
|
||||
struct resource *res;
|
||||
struct dwapb_gpio *gpio;
|
||||
struct device_node *np;
|
||||
int err;
|
||||
unsigned int offs = 0;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct dwapb_platform_data *pdata = dev_get_platdata(dev);
|
||||
bool is_pdata_alloc = !pdata;
|
||||
|
||||
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
|
||||
if (!gpio)
|
||||
return -ENOMEM;
|
||||
gpio->dev = &pdev->dev;
|
||||
if (is_pdata_alloc) {
|
||||
pdata = dwapb_gpio_get_pdata_of(dev);
|
||||
if (IS_ERR(pdata))
|
||||
return PTR_ERR(pdata);
|
||||
}
|
||||
|
||||
gpio->nr_ports = of_get_child_count(pdev->dev.of_node);
|
||||
if (!gpio->nr_ports) {
|
||||
err = -EINVAL;
|
||||
if (!pdata->nports) {
|
||||
err = -ENODEV;
|
||||
goto out_err;
|
||||
}
|
||||
gpio->ports = devm_kzalloc(&pdev->dev, gpio->nr_ports *
|
||||
|
||||
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
|
||||
if (!gpio) {
|
||||
err = -ENOMEM;
|
||||
goto out_err;
|
||||
}
|
||||
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;
|
||||
|
|
@ -394,20 +575,23 @@ static int dwapb_gpio_probe(struct platform_device *pdev)
|
|||
goto out_err;
|
||||
}
|
||||
|
||||
for_each_child_of_node(pdev->dev.of_node, np) {
|
||||
err = dwapb_gpio_add_port(gpio, np, offs++);
|
||||
for (i = 0; i < gpio->nr_ports; i++) {
|
||||
err = dwapb_gpio_add_port(gpio, &pdata->properties[i], i);
|
||||
if (err)
|
||||
goto out_unregister;
|
||||
}
|
||||
platform_set_drvdata(pdev, gpio);
|
||||
|
||||
return 0;
|
||||
goto out_err;
|
||||
|
||||
out_unregister:
|
||||
dwapb_gpio_unregister(gpio);
|
||||
dwapb_irq_teardown(gpio);
|
||||
|
||||
out_err:
|
||||
if (is_pdata_alloc)
|
||||
dwapb_free_pdata_of(pdata);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -427,10 +611,100 @@ static const struct of_device_id dwapb_of_match[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(of, dwapb_of_match);
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int dwapb_gpio_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct dwapb_gpio *gpio = platform_get_drvdata(pdev);
|
||||
struct bgpio_chip *bgc = &gpio->ports[0].bgc;
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
spin_lock_irqsave(&bgc->lock, flags);
|
||||
for (i = 0; i < gpio->nr_ports; i++) {
|
||||
unsigned int offset;
|
||||
unsigned int idx = gpio->ports[i].idx;
|
||||
struct dwapb_context *ctx = gpio->ports[i].ctx;
|
||||
|
||||
BUG_ON(!ctx);
|
||||
|
||||
offset = GPIO_SWPORTA_DDR + idx * GPIO_SWPORT_DDR_SIZE;
|
||||
ctx->dir = dwapb_read(gpio, offset);
|
||||
|
||||
offset = GPIO_SWPORTA_DR + idx * GPIO_SWPORT_DR_SIZE;
|
||||
ctx->data = dwapb_read(gpio, offset);
|
||||
|
||||
offset = GPIO_EXT_PORTA + idx * GPIO_EXT_PORT_SIZE;
|
||||
ctx->ext = dwapb_read(gpio, offset);
|
||||
|
||||
/* Only port A can provide interrupts */
|
||||
if (idx == 0) {
|
||||
ctx->int_mask = dwapb_read(gpio, GPIO_INTMASK);
|
||||
ctx->int_en = dwapb_read(gpio, GPIO_INTEN);
|
||||
ctx->int_pol = dwapb_read(gpio, GPIO_INT_POLARITY);
|
||||
ctx->int_type = dwapb_read(gpio, GPIO_INTTYPE_LEVEL);
|
||||
ctx->int_deb = dwapb_read(gpio, GPIO_PORTA_DEBOUNCE);
|
||||
|
||||
/* Mask out interrupts */
|
||||
dwapb_write(gpio, GPIO_INTMASK, 0xffffffff);
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&bgc->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwapb_gpio_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct dwapb_gpio *gpio = platform_get_drvdata(pdev);
|
||||
struct bgpio_chip *bgc = &gpio->ports[0].bgc;
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
spin_lock_irqsave(&bgc->lock, flags);
|
||||
for (i = 0; i < gpio->nr_ports; i++) {
|
||||
unsigned int offset;
|
||||
unsigned int idx = gpio->ports[i].idx;
|
||||
struct dwapb_context *ctx = gpio->ports[i].ctx;
|
||||
|
||||
BUG_ON(!ctx);
|
||||
|
||||
offset = GPIO_SWPORTA_DR + idx * GPIO_SWPORT_DR_SIZE;
|
||||
dwapb_write(gpio, offset, ctx->data);
|
||||
|
||||
offset = GPIO_SWPORTA_DDR + idx * GPIO_SWPORT_DDR_SIZE;
|
||||
dwapb_write(gpio, offset, ctx->dir);
|
||||
|
||||
offset = GPIO_EXT_PORTA + idx * GPIO_EXT_PORT_SIZE;
|
||||
dwapb_write(gpio, offset, ctx->ext);
|
||||
|
||||
/* Only port A can provide interrupts */
|
||||
if (idx == 0) {
|
||||
dwapb_write(gpio, GPIO_INTTYPE_LEVEL, ctx->int_type);
|
||||
dwapb_write(gpio, GPIO_INT_POLARITY, ctx->int_pol);
|
||||
dwapb_write(gpio, GPIO_PORTA_DEBOUNCE, ctx->int_deb);
|
||||
dwapb_write(gpio, GPIO_INTEN, ctx->int_en);
|
||||
dwapb_write(gpio, GPIO_INTMASK, ctx->int_mask);
|
||||
|
||||
/* Clear out spurious interrupts */
|
||||
dwapb_write(gpio, GPIO_PORTA_EOI, 0xffffffff);
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&bgc->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(dwapb_gpio_pm_ops, dwapb_gpio_suspend,
|
||||
dwapb_gpio_resume);
|
||||
|
||||
static struct platform_driver dwapb_gpio_driver = {
|
||||
.driver = {
|
||||
.name = "gpio-dwapb",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &dwapb_gpio_pm_ops,
|
||||
.of_match_table = of_match_ptr(dwapb_of_match),
|
||||
},
|
||||
.probe = dwapb_gpio_probe,
|
||||
|
|
|
|||
|
|
@ -265,29 +265,27 @@ static int ks8695_gpio_show(struct seq_file *s, void *unused)
|
|||
seq_printf(s, "EXT%i ", i);
|
||||
|
||||
switch ((ctrl & intmask[i]) >> (4 * i)) {
|
||||
case IOPC_TM_LOW:
|
||||
seq_printf(s, "(Low)"); break;
|
||||
case IOPC_TM_HIGH:
|
||||
seq_printf(s, "(High)"); break;
|
||||
case IOPC_TM_RISING:
|
||||
seq_printf(s, "(Rising)"); break;
|
||||
case IOPC_TM_FALLING:
|
||||
seq_printf(s, "(Falling)"); break;
|
||||
case IOPC_TM_EDGE:
|
||||
seq_printf(s, "(Edges)"); break;
|
||||
case IOPC_TM_LOW:
|
||||
seq_printf(s, "(Low)"); break;
|
||||
case IOPC_TM_HIGH:
|
||||
seq_printf(s, "(High)"); break;
|
||||
case IOPC_TM_RISING:
|
||||
seq_printf(s, "(Rising)"); break;
|
||||
case IOPC_TM_FALLING:
|
||||
seq_printf(s, "(Falling)"); break;
|
||||
case IOPC_TM_EDGE:
|
||||
seq_printf(s, "(Edges)"); break;
|
||||
}
|
||||
}
|
||||
else
|
||||
} else
|
||||
seq_printf(s, "GPIO\t");
|
||||
}
|
||||
else if (i <= KS8695_GPIO_5) {
|
||||
} else if (i <= KS8695_GPIO_5) {
|
||||
if (ctrl & enable[i])
|
||||
seq_printf(s, "TOUT%i\t", i - KS8695_GPIO_4);
|
||||
else
|
||||
seq_printf(s, "GPIO\t");
|
||||
}
|
||||
else
|
||||
} else {
|
||||
seq_printf(s, "GPIO\t");
|
||||
}
|
||||
|
||||
seq_printf(s, "\t");
|
||||
|
||||
|
|
|
|||
|
|
@ -479,7 +479,7 @@ static int mcp23s08_irq_setup(struct mcp23s08 *mcp)
|
|||
|
||||
mutex_init(&mcp->irq_lock);
|
||||
|
||||
mcp->irq_domain = irq_domain_add_linear(chip->of_node, chip->ngpio,
|
||||
mcp->irq_domain = irq_domain_add_linear(chip->dev->of_node, chip->ngpio,
|
||||
&irq_domain_simple_ops, mcp);
|
||||
if (!mcp->irq_domain)
|
||||
return -ENODEV;
|
||||
|
|
@ -581,7 +581,7 @@ done:
|
|||
|
||||
static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
|
||||
void *data, unsigned addr, unsigned type,
|
||||
unsigned base, unsigned pullups)
|
||||
struct mcp23s08_platform_data *pdata, int cs)
|
||||
{
|
||||
int status;
|
||||
bool mirror = false;
|
||||
|
|
@ -635,7 +635,7 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
mcp->chip.base = base;
|
||||
mcp->chip.base = pdata->base;
|
||||
mcp->chip.can_sleep = true;
|
||||
mcp->chip.dev = dev;
|
||||
mcp->chip.owner = THIS_MODULE;
|
||||
|
|
@ -648,11 +648,9 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
|
|||
if (status < 0)
|
||||
goto fail;
|
||||
|
||||
mcp->irq_controller = of_property_read_bool(mcp->chip.of_node,
|
||||
"interrupt-controller");
|
||||
mcp->irq_controller = pdata->irq_controller;
|
||||
if (mcp->irq && mcp->irq_controller && (type == MCP_TYPE_017))
|
||||
mirror = of_property_read_bool(mcp->chip.of_node,
|
||||
"microchip,irq-mirror");
|
||||
mirror = pdata->mirror;
|
||||
|
||||
if ((status & IOCON_SEQOP) || !(status & IOCON_HAEN) || mirror) {
|
||||
/* mcp23s17 has IOCON twice, make sure they are in sync */
|
||||
|
|
@ -668,7 +666,7 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
|
|||
}
|
||||
|
||||
/* configure ~100K pullups */
|
||||
status = mcp->ops->write(mcp, MCP_GPPU, pullups);
|
||||
status = mcp->ops->write(mcp, MCP_GPPU, pdata->chip[cs].pullups);
|
||||
if (status < 0)
|
||||
goto fail;
|
||||
|
||||
|
|
@ -768,25 +766,29 @@ MODULE_DEVICE_TABLE(of, mcp23s08_i2c_of_match);
|
|||
static int mcp230xx_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct mcp23s08_platform_data *pdata;
|
||||
struct mcp23s08_platform_data *pdata, local_pdata;
|
||||
struct mcp23s08 *mcp;
|
||||
int status, base, pullups;
|
||||
int status;
|
||||
const struct of_device_id *match;
|
||||
|
||||
match = of_match_device(of_match_ptr(mcp23s08_i2c_of_match),
|
||||
&client->dev);
|
||||
pdata = dev_get_platdata(&client->dev);
|
||||
if (match || !pdata) {
|
||||
base = -1;
|
||||
pullups = 0;
|
||||
if (match) {
|
||||
pdata = &local_pdata;
|
||||
pdata->base = -1;
|
||||
pdata->chip[0].pullups = 0;
|
||||
pdata->irq_controller = of_property_read_bool(
|
||||
client->dev.of_node,
|
||||
"interrupt-controller");
|
||||
pdata->mirror = of_property_read_bool(client->dev.of_node,
|
||||
"microchip,irq-mirror");
|
||||
client->irq = irq_of_parse_and_map(client->dev.of_node, 0);
|
||||
} else {
|
||||
if (!gpio_is_valid(pdata->base)) {
|
||||
pdata = dev_get_platdata(&client->dev);
|
||||
if (!pdata || !gpio_is_valid(pdata->base)) {
|
||||
dev_dbg(&client->dev, "invalid platform data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
base = pdata->base;
|
||||
pullups = pdata->chip[0].pullups;
|
||||
}
|
||||
|
||||
mcp = kzalloc(sizeof(*mcp), GFP_KERNEL);
|
||||
|
|
@ -795,7 +797,7 @@ static int mcp230xx_probe(struct i2c_client *client,
|
|||
|
||||
mcp->irq = client->irq;
|
||||
status = mcp23s08_probe_one(mcp, &client->dev, client, client->addr,
|
||||
id->driver_data, base, pullups);
|
||||
id->driver_data, pdata, 0);
|
||||
if (status)
|
||||
goto fail;
|
||||
|
||||
|
|
@ -863,14 +865,12 @@ static void mcp23s08_i2c_exit(void) { }
|
|||
|
||||
static int mcp23s08_probe(struct spi_device *spi)
|
||||
{
|
||||
struct mcp23s08_platform_data *pdata;
|
||||
struct mcp23s08_platform_data *pdata, local_pdata;
|
||||
unsigned addr;
|
||||
int chips = 0;
|
||||
struct mcp23s08_driver_data *data;
|
||||
int status, type;
|
||||
unsigned base = -1,
|
||||
ngpio = 0,
|
||||
pullups[ARRAY_SIZE(pdata->chip)];
|
||||
unsigned ngpio = 0;
|
||||
const struct of_device_id *match;
|
||||
u32 spi_present_mask = 0;
|
||||
|
||||
|
|
@ -893,11 +893,18 @@ static int mcp23s08_probe(struct spi_device *spi)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
pdata = &local_pdata;
|
||||
pdata->base = -1;
|
||||
for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) {
|
||||
pullups[addr] = 0;
|
||||
pdata->chip[addr].pullups = 0;
|
||||
if (spi_present_mask & (1 << addr))
|
||||
chips++;
|
||||
}
|
||||
pdata->irq_controller = of_property_read_bool(
|
||||
spi->dev.of_node,
|
||||
"interrupt-controller");
|
||||
pdata->mirror = of_property_read_bool(spi->dev.of_node,
|
||||
"microchip,irq-mirror");
|
||||
} else {
|
||||
type = spi_get_device_id(spi)->driver_data;
|
||||
pdata = dev_get_platdata(&spi->dev);
|
||||
|
|
@ -917,10 +924,7 @@ static int mcp23s08_probe(struct spi_device *spi)
|
|||
return -EINVAL;
|
||||
}
|
||||
spi_present_mask |= 1 << addr;
|
||||
pullups[addr] = pdata->chip[addr].pullups;
|
||||
}
|
||||
|
||||
base = pdata->base;
|
||||
}
|
||||
|
||||
if (!chips)
|
||||
|
|
@ -938,13 +942,13 @@ static int mcp23s08_probe(struct spi_device *spi)
|
|||
chips--;
|
||||
data->mcp[addr] = &data->chip[chips];
|
||||
status = mcp23s08_probe_one(data->mcp[addr], &spi->dev, spi,
|
||||
0x40 | (addr << 1), type, base,
|
||||
pullups[addr]);
|
||||
0x40 | (addr << 1), type, pdata,
|
||||
addr);
|
||||
if (status < 0)
|
||||
goto fail;
|
||||
|
||||
if (base != -1)
|
||||
base += (type == MCP_TYPE_S17) ? 16 : 8;
|
||||
if (pdata->base != -1)
|
||||
pdata->base += (type == MCP_TYPE_S17) ? 16 : 8;
|
||||
ngpio += (type == MCP_TYPE_S17) ? 16 : 8;
|
||||
}
|
||||
data->ngpio = ngpio;
|
||||
|
|
|
|||
|
|
@ -857,16 +857,6 @@ static void omap_gpio_unmask_irq(struct irq_data *d)
|
|||
spin_unlock_irqrestore(&bank->lock, flags);
|
||||
}
|
||||
|
||||
static struct irq_chip gpio_irq_chip = {
|
||||
.name = "GPIO",
|
||||
.irq_shutdown = omap_gpio_irq_shutdown,
|
||||
.irq_ack = omap_gpio_ack_irq,
|
||||
.irq_mask = omap_gpio_mask_irq,
|
||||
.irq_unmask = omap_gpio_unmask_irq,
|
||||
.irq_set_type = omap_gpio_irq_type,
|
||||
.irq_set_wake = omap_gpio_wake_enable,
|
||||
};
|
||||
|
||||
/*---------------------------------------------------------------------*/
|
||||
|
||||
static int omap_mpuio_suspend_noirq(struct device *dev)
|
||||
|
|
@ -1088,7 +1078,7 @@ omap_mpuio_alloc_gc(struct gpio_bank *bank, unsigned int irq_start,
|
|||
IRQ_NOREQUEST | IRQ_NOPROBE, 0);
|
||||
}
|
||||
|
||||
static int omap_gpio_chip_init(struct gpio_bank *bank)
|
||||
static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
|
||||
{
|
||||
int j;
|
||||
static int gpio;
|
||||
|
|
@ -1137,17 +1127,17 @@ static int omap_gpio_chip_init(struct gpio_bank *bank)
|
|||
}
|
||||
#endif
|
||||
|
||||
ret = gpiochip_irqchip_add(&bank->chip, &gpio_irq_chip,
|
||||
ret = gpiochip_irqchip_add(&bank->chip, irqc,
|
||||
irq_base, omap_gpio_irq_handler,
|
||||
IRQ_TYPE_NONE);
|
||||
|
||||
if (ret) {
|
||||
dev_err(bank->dev, "Couldn't add irqchip to gpiochip %d\n", ret);
|
||||
ret = gpiochip_remove(&bank->chip);
|
||||
gpiochip_remove(&bank->chip);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
gpiochip_set_chained_irqchip(&bank->chip, &gpio_irq_chip,
|
||||
gpiochip_set_chained_irqchip(&bank->chip, irqc,
|
||||
bank->irq, omap_gpio_irq_handler);
|
||||
|
||||
for (j = 0; j < bank->width; j++) {
|
||||
|
|
@ -1172,6 +1162,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
|
|||
const struct omap_gpio_platform_data *pdata;
|
||||
struct resource *res;
|
||||
struct gpio_bank *bank;
|
||||
struct irq_chip *irqc;
|
||||
int ret;
|
||||
|
||||
match = of_match_device(of_match_ptr(omap_gpio_match), dev);
|
||||
|
|
@ -1186,6 +1177,18 @@ static int omap_gpio_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
irqc = devm_kzalloc(dev, sizeof(*irqc), GFP_KERNEL);
|
||||
if (!irqc)
|
||||
return -ENOMEM;
|
||||
|
||||
irqc->irq_shutdown = omap_gpio_irq_shutdown,
|
||||
irqc->irq_ack = omap_gpio_ack_irq,
|
||||
irqc->irq_mask = omap_gpio_mask_irq,
|
||||
irqc->irq_unmask = omap_gpio_unmask_irq,
|
||||
irqc->irq_set_type = omap_gpio_irq_type,
|
||||
irqc->irq_set_wake = omap_gpio_wake_enable,
|
||||
irqc->name = dev_name(&pdev->dev);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
if (unlikely(!res)) {
|
||||
dev_err(dev, "Invalid IRQ resource\n");
|
||||
|
|
@ -1241,7 +1244,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
|
|||
|
||||
omap_gpio_mod_init(bank);
|
||||
|
||||
ret = omap_gpio_chip_init(bank);
|
||||
ret = omap_gpio_chip_init(bank, irqc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue