Watch
1
Fork
You've already forked kernel_a52xq
0
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:
Linus Torvalds 2014-10-09 14:58:15 -04:00
commit ea584595fc
65 changed files with 1297 additions and 659 deletions

View 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>;
};

View 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>;
};

View 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>;
};

View file

@ -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:

View file

@ -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)

View file

@ -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);

View file

@ -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:

View file

@ -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)

View file

@ -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);

View file

@ -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;
}

View file

@ -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.

View file

@ -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

View file

@ -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;
}

View file

@ -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" },
{}
};

View file

@ -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 = {

View file

@ -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);

View file

@ -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,

View file

@ -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");

View file

@ -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;

View file

@ -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