mirror of
https://github.com/torvalds/linux.git
synced 2024-12-27 13:22:23 +00: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
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;
|
||||
|
||||
|
@ -520,7 +520,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
|
||||
struct i2c_client *client = chip->client;
|
||||
int ret, i, offset = 0;
|
||||
|
||||
if (irq_base != -1
|
||||
if (client->irq && irq_base != -1
|
||||
&& (id->driver_data & PCA_INT)) {
|
||||
|
||||
switch (chip->chip_type) {
|
||||
@ -586,50 +586,6 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Handlers for alternative sources of platform_data
|
||||
*/
|
||||
#ifdef CONFIG_OF_GPIO
|
||||
/*
|
||||
* Translate OpenFirmware node properties into platform_data
|
||||
* WARNING: This is DEPRECATED and will be removed eventually!
|
||||
*/
|
||||
static void
|
||||
pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, u32 *invert)
|
||||
{
|
||||
struct device_node *node;
|
||||
const __be32 *val;
|
||||
int size;
|
||||
|
||||
*gpio_base = -1;
|
||||
|
||||
node = client->dev.of_node;
|
||||
if (node == NULL)
|
||||
return;
|
||||
|
||||
val = of_get_property(node, "linux,gpio-base", &size);
|
||||
WARN(val, "%s: device-tree property 'linux,gpio-base' is deprecated!", __func__);
|
||||
if (val) {
|
||||
if (size != sizeof(*val))
|
||||
dev_warn(&client->dev, "%s: wrong linux,gpio-base\n",
|
||||
node->full_name);
|
||||
else
|
||||
*gpio_base = be32_to_cpup(val);
|
||||
}
|
||||
|
||||
val = of_get_property(node, "polarity", NULL);
|
||||
WARN(val, "%s: device-tree property 'polarity' is deprecated!", __func__);
|
||||
if (val)
|
||||
*invert = *val;
|
||||
}
|
||||
#else
|
||||
static void
|
||||
pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, u32 *invert)
|
||||
{
|
||||
*gpio_base = -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int device_pca953x_init(struct pca953x_chip *chip, u32 invert)
|
||||
{
|
||||
int ret;
|
||||
@ -704,12 +660,8 @@ static int pca953x_probe(struct i2c_client *client,
|
||||
invert = pdata->invert;
|
||||
chip->names = pdata->names;
|
||||
} else {
|
||||
pca953x_get_alt_pdata(client, &chip->gpio_start, &invert);
|
||||
#ifdef CONFIG_OF_GPIO
|
||||
/* If I2C node has no interrupts property, disable GPIO interrupts */
|
||||
if (of_find_property(client->dev.of_node, "interrupts", NULL) == NULL)
|
||||
irq_base = -1;
|
||||
#endif
|
||||
chip->gpio_start = -1;
|
||||
irq_base = 0;
|
||||
}
|
||||
|
||||
chip->client = client;
|
||||
|
@ -171,6 +171,7 @@ static int pch_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
/*
|
||||
* Save register configuration and disable interrupts.
|
||||
*/
|
||||
@ -206,6 +207,7 @@ static void pch_gpio_restore_reg_conf(struct pch_gpio *chip)
|
||||
iowrite32(chip->pch_gpio_reg.gpio_use_sel_reg,
|
||||
&chip->reg->gpio_use_sel);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int pch_gpio_to_irq(struct gpio_chip *gpio, unsigned offset)
|
||||
{
|
||||
|
@ -1309,56 +1309,6 @@ samsung_gpio_pull_t s3c_gpio_getpull(unsigned int pin)
|
||||
}
|
||||
EXPORT_SYMBOL(s3c_gpio_getpull);
|
||||
|
||||
#ifdef CONFIG_S5P_GPIO_DRVSTR
|
||||
s5p_gpio_drvstr_t s5p_gpio_get_drvstr(unsigned int pin)
|
||||
{
|
||||
struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin);
|
||||
unsigned int off;
|
||||
void __iomem *reg;
|
||||
int shift;
|
||||
u32 drvstr;
|
||||
|
||||
if (!chip)
|
||||
return -EINVAL;
|
||||
|
||||
off = pin - chip->chip.base;
|
||||
shift = off * 2;
|
||||
reg = chip->base + 0x0C;
|
||||
|
||||
drvstr = __raw_readl(reg);
|
||||
drvstr = drvstr >> shift;
|
||||
drvstr &= 0x3;
|
||||
|
||||
return (__force s5p_gpio_drvstr_t)drvstr;
|
||||
}
|
||||
EXPORT_SYMBOL(s5p_gpio_get_drvstr);
|
||||
|
||||
int s5p_gpio_set_drvstr(unsigned int pin, s5p_gpio_drvstr_t drvstr)
|
||||
{
|
||||
struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin);
|
||||
unsigned int off;
|
||||
void __iomem *reg;
|
||||
int shift;
|
||||
u32 tmp;
|
||||
|
||||
if (!chip)
|
||||
return -EINVAL;
|
||||
|
||||
off = pin - chip->chip.base;
|
||||
shift = off * 2;
|
||||
reg = chip->base + 0x0C;
|
||||
|
||||
tmp = __raw_readl(reg);
|
||||
tmp &= ~(0x3 << shift);
|
||||
tmp |= drvstr << shift;
|
||||
|
||||
__raw_writel(tmp, reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(s5p_gpio_set_drvstr);
|
||||
#endif /* CONFIG_S5P_GPIO_DRVSTR */
|
||||
|
||||
#ifdef CONFIG_PLAT_S3C24XX
|
||||
unsigned int s3c2410_modify_misccr(unsigned int clear, unsigned int change)
|
||||
{
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/mfd/stmpe.h>
|
||||
#include <linux/seq_file.h>
|
||||
|
||||
/*
|
||||
* These registers are modified under the irq bus lock and cached to avoid
|
||||
@ -127,19 +128,19 @@ static int stmpe_gpio_irq_set_type(struct irq_data *d, unsigned int type)
|
||||
int regoffset = offset / 8;
|
||||
int mask = 1 << (offset % 8);
|
||||
|
||||
if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_LEVEL_HIGH)
|
||||
if (type & IRQ_TYPE_LEVEL_LOW || type & IRQ_TYPE_LEVEL_HIGH)
|
||||
return -EINVAL;
|
||||
|
||||
/* STMPE801 doesn't have RE and FE registers */
|
||||
if (stmpe_gpio->stmpe->partnum == STMPE801)
|
||||
return 0;
|
||||
|
||||
if (type == IRQ_TYPE_EDGE_RISING)
|
||||
if (type & IRQ_TYPE_EDGE_RISING)
|
||||
stmpe_gpio->regs[REG_RE][regoffset] |= mask;
|
||||
else
|
||||
stmpe_gpio->regs[REG_RE][regoffset] &= ~mask;
|
||||
|
||||
if (type == IRQ_TYPE_EDGE_FALLING)
|
||||
if (type & IRQ_TYPE_EDGE_FALLING)
|
||||
stmpe_gpio->regs[REG_FE][regoffset] |= mask;
|
||||
else
|
||||
stmpe_gpio->regs[REG_FE][regoffset] &= ~mask;
|
||||
@ -211,6 +212,77 @@ static void stmpe_gpio_irq_unmask(struct irq_data *d)
|
||||
stmpe_gpio->regs[REG_IE][regoffset] |= mask;
|
||||
}
|
||||
|
||||
static void stmpe_dbg_show_one(struct seq_file *s,
|
||||
struct gpio_chip *gc,
|
||||
unsigned offset, unsigned gpio)
|
||||
{
|
||||
struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(gc);
|
||||
struct stmpe *stmpe = stmpe_gpio->stmpe;
|
||||
const char *label = gpiochip_is_requested(gc, offset);
|
||||
int num_banks = DIV_ROUND_UP(stmpe->num_gpios, 8);
|
||||
bool val = !!stmpe_gpio_get(gc, offset);
|
||||
u8 dir_reg = stmpe->regs[STMPE_IDX_GPDR_LSB] - (offset / 8);
|
||||
u8 mask = 1 << (offset % 8);
|
||||
int ret;
|
||||
u8 dir;
|
||||
|
||||
ret = stmpe_reg_read(stmpe, dir_reg);
|
||||
if (ret < 0)
|
||||
return;
|
||||
dir = !!(ret & mask);
|
||||
|
||||
if (dir) {
|
||||
seq_printf(s, " gpio-%-3d (%-20.20s) out %s",
|
||||
gpio, label ?: "(none)",
|
||||
val ? "hi" : "lo");
|
||||
} else {
|
||||
u8 edge_det_reg = stmpe->regs[STMPE_IDX_GPEDR_MSB] + num_banks - 1 - (offset / 8);
|
||||
u8 rise_reg = stmpe->regs[STMPE_IDX_GPRER_LSB] - (offset / 8);
|
||||
u8 fall_reg = stmpe->regs[STMPE_IDX_GPFER_LSB] - (offset / 8);
|
||||
u8 irqen_reg = stmpe->regs[STMPE_IDX_IEGPIOR_LSB] - (offset / 8);
|
||||
bool edge_det;
|
||||
bool rise;
|
||||
bool fall;
|
||||
bool irqen;
|
||||
|
||||
ret = stmpe_reg_read(stmpe, edge_det_reg);
|
||||
if (ret < 0)
|
||||
return;
|
||||
edge_det = !!(ret & mask);
|
||||
ret = stmpe_reg_read(stmpe, rise_reg);
|
||||
if (ret < 0)
|
||||
return;
|
||||
rise = !!(ret & mask);
|
||||
ret = stmpe_reg_read(stmpe, fall_reg);
|
||||
if (ret < 0)
|
||||
return;
|
||||
fall = !!(ret & mask);
|
||||
ret = stmpe_reg_read(stmpe, irqen_reg);
|
||||
if (ret < 0)
|
||||
return;
|
||||
irqen = !!(ret & mask);
|
||||
|
||||
seq_printf(s, " gpio-%-3d (%-20.20s) in %s %s %s%s%s",
|
||||
gpio, label ?: "(none)",
|
||||
val ? "hi" : "lo",
|
||||
edge_det ? "edge-asserted" : "edge-inactive",
|
||||
irqen ? "IRQ-enabled" : "",
|
||||
rise ? " rising-edge-detection" : "",
|
||||
fall ? " falling-edge-detection" : "");
|
||||
}
|
||||
}
|
||||
|
||||
static void stmpe_dbg_show(struct seq_file *s, struct gpio_chip *gc)
|
||||
{
|
||||
unsigned i;
|
||||
unsigned gpio = gc->base;
|
||||
|
||||
for (i = 0; i < gc->ngpio; i++, gpio++) {
|
||||
stmpe_dbg_show_one(s, gc, i, gpio);
|
||||
seq_printf(s, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
static struct irq_chip stmpe_gpio_irq_chip = {
|
||||
.name = "stmpe-gpio",
|
||||
.irq_bus_lock = stmpe_gpio_irq_lock,
|
||||
@ -293,6 +365,9 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
|
||||
#endif
|
||||
stmpe_gpio->chip.base = -1;
|
||||
|
||||
if (IS_ENABLED(CONFIG_DEBUG_FS))
|
||||
stmpe_gpio->chip.dbg_show = stmpe_dbg_show;
|
||||
|
||||
if (pdata)
|
||||
stmpe_gpio->norequest_mask = pdata->norequest_mask;
|
||||
else if (np)
|
||||
@ -308,6 +383,12 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
goto out_free;
|
||||
|
||||
ret = gpiochip_add(&stmpe_gpio->chip);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret);
|
||||
goto out_disable;
|
||||
}
|
||||
|
||||
if (irq > 0) {
|
||||
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
|
||||
stmpe_gpio_irq, IRQF_ONESHOT,
|
||||
@ -324,14 +405,13 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"could not connect irqchip to gpiochip\n");
|
||||
return ret;
|
||||
goto out_disable;
|
||||
}
|
||||
}
|
||||
|
||||
ret = gpiochip_add(&stmpe_gpio->chip);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret);
|
||||
goto out_disable;
|
||||
gpiochip_set_chained_irqchip(&stmpe_gpio->chip,
|
||||
&stmpe_gpio_irq_chip,
|
||||
irq,
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (pdata && pdata->setup)
|
||||
@ -343,6 +423,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
|
||||
|
||||
out_disable:
|
||||
stmpe_disable(stmpe, STMPE_BLOCK_GPIO);
|
||||
gpiochip_remove(&stmpe_gpio->chip);
|
||||
out_free:
|
||||
kfree(stmpe_gpio);
|
||||
return ret;
|
||||
|
@ -292,7 +292,7 @@ static struct platform_driver xway_stp_driver = {
|
||||
},
|
||||
};
|
||||
|
||||
int __init xway_stp_init(void)
|
||||
static int __init xway_stp_init(void)
|
||||
{
|
||||
return platform_driver_register(&xway_stp_driver);
|
||||
}
|
||||
|
@ -37,6 +37,8 @@
|
||||
* dat_bit_offset: Offset (in bits) to the first GPIO bit.
|
||||
* dir_bit_offset: Optional offset (in bits) to the first bit to switch
|
||||
* GPIO direction (Used with GPIO_SYSCON_FEAT_DIR flag).
|
||||
* set: HW specific callback to assigns output value
|
||||
* for signal "offset"
|
||||
*/
|
||||
|
||||
struct syscon_gpio_data {
|
||||
@ -45,12 +47,16 @@ struct syscon_gpio_data {
|
||||
unsigned int bit_count;
|
||||
unsigned int dat_bit_offset;
|
||||
unsigned int dir_bit_offset;
|
||||
void (*set)(struct gpio_chip *chip,
|
||||
unsigned offset, int value);
|
||||
};
|
||||
|
||||
struct syscon_gpio_priv {
|
||||
struct gpio_chip chip;
|
||||
struct regmap *syscon;
|
||||
const struct syscon_gpio_data *data;
|
||||
u32 dreg_offset;
|
||||
u32 dir_reg_offset;
|
||||
};
|
||||
|
||||
static inline struct syscon_gpio_priv *to_syscon_gpio(struct gpio_chip *chip)
|
||||
@ -61,9 +67,11 @@ static inline struct syscon_gpio_priv *to_syscon_gpio(struct gpio_chip *chip)
|
||||
static int syscon_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct syscon_gpio_priv *priv = to_syscon_gpio(chip);
|
||||
unsigned int val, offs = priv->data->dat_bit_offset + offset;
|
||||
unsigned int val, offs;
|
||||
int ret;
|
||||
|
||||
offs = priv->dreg_offset + priv->data->dat_bit_offset + offset;
|
||||
|
||||
ret = regmap_read(priv->syscon,
|
||||
(offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, &val);
|
||||
if (ret)
|
||||
@ -75,7 +83,9 @@ static int syscon_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||
static void syscon_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
|
||||
{
|
||||
struct syscon_gpio_priv *priv = to_syscon_gpio(chip);
|
||||
unsigned int offs = priv->data->dat_bit_offset + offset;
|
||||
unsigned int offs;
|
||||
|
||||
offs = priv->dreg_offset + priv->data->dat_bit_offset + offset;
|
||||
|
||||
regmap_update_bits(priv->syscon,
|
||||
(offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE,
|
||||
@ -88,7 +98,10 @@ static int syscon_gpio_dir_in(struct gpio_chip *chip, unsigned offset)
|
||||
struct syscon_gpio_priv *priv = to_syscon_gpio(chip);
|
||||
|
||||
if (priv->data->flags & GPIO_SYSCON_FEAT_DIR) {
|
||||
unsigned int offs = priv->data->dir_bit_offset + offset;
|
||||
unsigned int offs;
|
||||
|
||||
offs = priv->dir_reg_offset +
|
||||
priv->data->dir_bit_offset + offset;
|
||||
|
||||
regmap_update_bits(priv->syscon,
|
||||
(offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE,
|
||||
@ -103,7 +116,10 @@ static int syscon_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int val)
|
||||
struct syscon_gpio_priv *priv = to_syscon_gpio(chip);
|
||||
|
||||
if (priv->data->flags & GPIO_SYSCON_FEAT_DIR) {
|
||||
unsigned int offs = priv->data->dir_bit_offset + offset;
|
||||
unsigned int offs;
|
||||
|
||||
offs = priv->dir_reg_offset +
|
||||
priv->data->dir_bit_offset + offset;
|
||||
|
||||
regmap_update_bits(priv->syscon,
|
||||
(offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE,
|
||||
@ -111,7 +127,7 @@ static int syscon_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int val)
|
||||
BIT(offs % SYSCON_REG_BITS));
|
||||
}
|
||||
|
||||
syscon_gpio_set(chip, offset, val);
|
||||
priv->data->set(chip, offset, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -124,11 +140,46 @@ static const struct syscon_gpio_data clps711x_mctrl_gpio = {
|
||||
.dat_bit_offset = 0x40 * 8 + 8,
|
||||
};
|
||||
|
||||
#define KEYSTONE_LOCK_BIT BIT(0)
|
||||
|
||||
static void keystone_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
|
||||
{
|
||||
struct syscon_gpio_priv *priv = to_syscon_gpio(chip);
|
||||
unsigned int offs;
|
||||
int ret;
|
||||
|
||||
offs = priv->dreg_offset + priv->data->dat_bit_offset + offset;
|
||||
|
||||
if (!val)
|
||||
return;
|
||||
|
||||
ret = regmap_update_bits(
|
||||
priv->syscon,
|
||||
(offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE,
|
||||
BIT(offs % SYSCON_REG_BITS) | KEYSTONE_LOCK_BIT,
|
||||
BIT(offs % SYSCON_REG_BITS) | KEYSTONE_LOCK_BIT);
|
||||
if (ret < 0)
|
||||
dev_err(chip->dev, "gpio write failed ret(%d)\n", ret);
|
||||
}
|
||||
|
||||
static const struct syscon_gpio_data keystone_dsp_gpio = {
|
||||
/* ARM Keystone 2 */
|
||||
.compatible = NULL,
|
||||
.flags = GPIO_SYSCON_FEAT_OUT,
|
||||
.bit_count = 28,
|
||||
.dat_bit_offset = 4,
|
||||
.set = keystone_gpio_set,
|
||||
};
|
||||
|
||||
static const struct of_device_id syscon_gpio_ids[] = {
|
||||
{
|
||||
.compatible = "cirrus,clps711x-mctrl-gpio",
|
||||
.data = &clps711x_mctrl_gpio,
|
||||
},
|
||||
{
|
||||
.compatible = "ti,keystone-dsp-gpio",
|
||||
.data = &keystone_dsp_gpio,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, syscon_gpio_ids);
|
||||
@ -138,6 +189,8 @@ static int syscon_gpio_probe(struct platform_device *pdev)
|
||||
struct device *dev = &pdev->dev;
|
||||
const struct of_device_id *of_id = of_match_device(syscon_gpio_ids, dev);
|
||||
struct syscon_gpio_priv *priv;
|
||||
struct device_node *np = dev->of_node;
|
||||
int ret;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
@ -145,10 +198,31 @@ static int syscon_gpio_probe(struct platform_device *pdev)
|
||||
|
||||
priv->data = of_id->data;
|
||||
|
||||
priv->syscon =
|
||||
syscon_regmap_lookup_by_compatible(priv->data->compatible);
|
||||
if (IS_ERR(priv->syscon))
|
||||
return PTR_ERR(priv->syscon);
|
||||
if (priv->data->compatible) {
|
||||
priv->syscon = syscon_regmap_lookup_by_compatible(
|
||||
priv->data->compatible);
|
||||
if (IS_ERR(priv->syscon))
|
||||
return PTR_ERR(priv->syscon);
|
||||
} else {
|
||||
priv->syscon =
|
||||
syscon_regmap_lookup_by_phandle(np, "gpio,syscon-dev");
|
||||
if (IS_ERR(priv->syscon))
|
||||
return PTR_ERR(priv->syscon);
|
||||
|
||||
ret = of_property_read_u32_index(np, "gpio,syscon-dev", 1,
|
||||
&priv->dreg_offset);
|
||||
if (ret)
|
||||
dev_err(dev, "can't read the data register offset!\n");
|
||||
|
||||
priv->dreg_offset <<= 3;
|
||||
|
||||
ret = of_property_read_u32_index(np, "gpio,syscon-dev", 2,
|
||||
&priv->dir_reg_offset);
|
||||
if (ret)
|
||||
dev_err(dev, "can't read the dir register offset!\n");
|
||||
|
||||
priv->dir_reg_offset <<= 3;
|
||||
}
|
||||
|
||||
priv->chip.dev = dev;
|
||||
priv->chip.owner = THIS_MODULE;
|
||||
@ -159,7 +233,7 @@ static int syscon_gpio_probe(struct platform_device *pdev)
|
||||
if (priv->data->flags & GPIO_SYSCON_FEAT_IN)
|
||||
priv->chip.direction_input = syscon_gpio_dir_in;
|
||||
if (priv->data->flags & GPIO_SYSCON_FEAT_OUT) {
|
||||
priv->chip.set = syscon_gpio_set;
|
||||
priv->chip.set = priv->data->set ? : syscon_gpio_set;
|
||||
priv->chip.direction_output = syscon_gpio_dir_out;
|
||||
}
|
||||
|
||||
|
@ -300,6 +300,11 @@ static int tc3589x_gpio_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
gpiochip_set_chained_irqchip(&tc3589x_gpio->chip,
|
||||
&tc3589x_gpio_irq_chip,
|
||||
irq,
|
||||
NULL);
|
||||
|
||||
if (pdata && pdata->setup)
|
||||
pdata->setup(tc3589x, tc3589x_gpio->chip.base);
|
||||
|
||||
|
244
drivers/gpio/gpio-xgene.c
Normal file
244
drivers/gpio/gpio-xgene.c
Normal file
@ -0,0 +1,244 @@
|
||||
/*
|
||||
* AppliedMicro X-Gene SoC GPIO Driver
|
||||
*
|
||||
* Copyright (c) 2014, Applied Micro Circuits Corporation
|
||||
* Author: Feng Kan <fkan@apm.com>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#define GPIO_SET_DR_OFFSET 0x0C
|
||||
#define GPIO_DATA_OFFSET 0x14
|
||||
#define GPIO_BANK_STRIDE 0x0C
|
||||
|
||||
#define XGENE_GPIOS_PER_BANK 16
|
||||
#define XGENE_MAX_GPIO_BANKS 3
|
||||
#define XGENE_MAX_GPIOS (XGENE_GPIOS_PER_BANK * XGENE_MAX_GPIO_BANKS)
|
||||
|
||||
#define GPIO_BIT_OFFSET(x) (x % XGENE_GPIOS_PER_BANK)
|
||||
#define GPIO_BANK_OFFSET(x) ((x / XGENE_GPIOS_PER_BANK) * GPIO_BANK_STRIDE)
|
||||
|
||||
struct xgene_gpio {
|
||||
struct gpio_chip chip;
|
||||
void __iomem *base;
|
||||
spinlock_t lock;
|
||||
#ifdef CONFIG_PM
|
||||
u32 set_dr_val[XGENE_MAX_GPIO_BANKS];
|
||||
#endif
|
||||
};
|
||||
|
||||
static inline struct xgene_gpio *to_xgene_gpio(struct gpio_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct xgene_gpio, chip);
|
||||
}
|
||||
|
||||
static int xgene_gpio_get(struct gpio_chip *gc, unsigned int offset)
|
||||
{
|
||||
struct xgene_gpio *chip = to_xgene_gpio(gc);
|
||||
unsigned long bank_offset;
|
||||
u32 bit_offset;
|
||||
|
||||
bank_offset = GPIO_DATA_OFFSET + GPIO_BANK_OFFSET(offset);
|
||||
bit_offset = GPIO_BIT_OFFSET(offset);
|
||||
return !!(ioread32(chip->base + bank_offset) & BIT(bit_offset));
|
||||
}
|
||||
|
||||
static void __xgene_gpio_set(struct gpio_chip *gc, unsigned int offset, int val)
|
||||
{
|
||||
struct xgene_gpio *chip = to_xgene_gpio(gc);
|
||||
unsigned long bank_offset;
|
||||
u32 setval, bit_offset;
|
||||
|
||||
bank_offset = GPIO_SET_DR_OFFSET + GPIO_BANK_OFFSET(offset);
|
||||
bit_offset = GPIO_BIT_OFFSET(offset) + XGENE_GPIOS_PER_BANK;
|
||||
|
||||
setval = ioread32(chip->base + bank_offset);
|
||||
if (val)
|
||||
setval |= BIT(bit_offset);
|
||||
else
|
||||
setval &= ~BIT(bit_offset);
|
||||
iowrite32(setval, chip->base + bank_offset);
|
||||
}
|
||||
|
||||
static void xgene_gpio_set(struct gpio_chip *gc, unsigned int offset, int val)
|
||||
{
|
||||
struct xgene_gpio *chip = to_xgene_gpio(gc);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&chip->lock, flags);
|
||||
__xgene_gpio_set(gc, offset, val);
|
||||
spin_unlock_irqrestore(&chip->lock, flags);
|
||||
}
|
||||
|
||||
static int xgene_gpio_dir_in(struct gpio_chip *gc, unsigned int offset)
|
||||
{
|
||||
struct xgene_gpio *chip = to_xgene_gpio(gc);
|
||||
unsigned long flags, bank_offset;
|
||||
u32 dirval, bit_offset;
|
||||
|
||||
bank_offset = GPIO_SET_DR_OFFSET + GPIO_BANK_OFFSET(offset);
|
||||
bit_offset = GPIO_BIT_OFFSET(offset);
|
||||
|
||||
spin_lock_irqsave(&chip->lock, flags);
|
||||
|
||||
dirval = ioread32(chip->base + bank_offset);
|
||||
dirval |= BIT(bit_offset);
|
||||
iowrite32(dirval, chip->base + bank_offset);
|
||||
|
||||
spin_unlock_irqrestore(&chip->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xgene_gpio_dir_out(struct gpio_chip *gc,
|
||||
unsigned int offset, int val)
|
||||
{
|
||||
struct xgene_gpio *chip = to_xgene_gpio(gc);
|
||||
unsigned long flags, bank_offset;
|
||||
u32 dirval, bit_offset;
|
||||
|
||||
bank_offset = GPIO_SET_DR_OFFSET + GPIO_BANK_OFFSET(offset);
|
||||
bit_offset = GPIO_BIT_OFFSET(offset);
|
||||
|
||||
spin_lock_irqsave(&chip->lock, flags);
|
||||
|
||||
dirval = ioread32(chip->base + bank_offset);
|
||||
dirval &= ~BIT(bit_offset);
|
||||
iowrite32(dirval, chip->base + bank_offset);
|
||||
__xgene_gpio_set(gc, offset, val);
|
||||
|
||||
spin_unlock_irqrestore(&chip->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int xgene_gpio_suspend(struct device *dev)
|
||||
{
|
||||
struct xgene_gpio *gpio = dev_get_drvdata(dev);
|
||||
unsigned long bank_offset;
|
||||
unsigned int bank;
|
||||
|
||||
for (bank = 0; bank < XGENE_MAX_GPIO_BANKS; bank++) {
|
||||
bank_offset = GPIO_SET_DR_OFFSET + bank * GPIO_BANK_STRIDE;
|
||||
gpio->set_dr_val[bank] = ioread32(gpio->base + bank_offset);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xgene_gpio_resume(struct device *dev)
|
||||
{
|
||||
struct xgene_gpio *gpio = dev_get_drvdata(dev);
|
||||
unsigned long bank_offset;
|
||||
unsigned int bank;
|
||||
|
||||
for (bank = 0; bank < XGENE_MAX_GPIO_BANKS; bank++) {
|
||||
bank_offset = GPIO_SET_DR_OFFSET + bank * GPIO_BANK_STRIDE;
|
||||
iowrite32(gpio->set_dr_val[bank], gpio->base + bank_offset);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(xgene_gpio_pm, xgene_gpio_suspend, xgene_gpio_resume);
|
||||
#define XGENE_GPIO_PM_OPS (&xgene_gpio_pm)
|
||||
#else
|
||||
#define XGENE_GPIO_PM_OPS NULL
|
||||
#endif
|
||||
|
||||
static int xgene_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
struct xgene_gpio *gpio;
|
||||
int err = 0;
|
||||
|
||||
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
|
||||
if (!gpio) {
|
||||
err = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
gpio->base = devm_ioremap_nocache(&pdev->dev, res->start,
|
||||
resource_size(res));
|
||||
if (!gpio->base) {
|
||||
err = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
gpio->chip.ngpio = XGENE_MAX_GPIOS;
|
||||
|
||||
spin_lock_init(&gpio->lock);
|
||||
gpio->chip.dev = &pdev->dev;
|
||||
gpio->chip.direction_input = xgene_gpio_dir_in;
|
||||
gpio->chip.direction_output = xgene_gpio_dir_out;
|
||||
gpio->chip.get = xgene_gpio_get;
|
||||
gpio->chip.set = xgene_gpio_set;
|
||||
gpio->chip.label = dev_name(&pdev->dev);
|
||||
gpio->chip.base = -1;
|
||||
|
||||
platform_set_drvdata(pdev, gpio);
|
||||
|
||||
err = gpiochip_add(&gpio->chip);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to register gpiochip.\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
dev_info(&pdev->dev, "X-Gene GPIO driver registered.\n");
|
||||
return 0;
|
||||
err:
|
||||
dev_err(&pdev->dev, "X-Gene GPIO driver registration failed.\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
static int xgene_gpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct xgene_gpio *gpio = platform_get_drvdata(pdev);
|
||||
|
||||
gpiochip_remove(&gpio->chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id xgene_gpio_of_match[] = {
|
||||
{ .compatible = "apm,xgene-gpio", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, xgene_gpio_of_match);
|
||||
|
||||
static struct platform_driver xgene_gpio_driver = {
|
||||
.driver = {
|
||||
.name = "xgene-gpio",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = xgene_gpio_of_match,
|
||||
.pm = XGENE_GPIO_PM_OPS,
|
||||
},
|
||||
.probe = xgene_gpio_probe,
|
||||
.remove = xgene_gpio_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(xgene_gpio_driver);
|
||||
|
||||
MODULE_AUTHOR("Feng Kan <fkan@apm.com>");
|
||||
MODULE_DESCRIPTION("APM X-Gene GPIO driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -197,6 +197,7 @@ static int xgpio_of_probe(struct device_node *np)
|
||||
struct xgpio_instance *chip;
|
||||
int status = 0;
|
||||
const u32 *tree_info;
|
||||
u32 ngpio;
|
||||
|
||||
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
|
||||
if (!chip)
|
||||
@ -211,12 +212,13 @@ static int xgpio_of_probe(struct device_node *np)
|
||||
/* Update GPIO direction shadow register with default value */
|
||||
of_property_read_u32(np, "xlnx,tri-default", &chip->gpio_dir);
|
||||
|
||||
/* By default assume full GPIO controller */
|
||||
chip->mmchip.gc.ngpio = 32;
|
||||
|
||||
/* Check device node and parent device node for device width */
|
||||
of_property_read_u32(np, "xlnx,gpio-width",
|
||||
(u32 *)&chip->mmchip.gc.ngpio);
|
||||
/*
|
||||
* Check device node and parent device node for device width
|
||||
* and assume default width of 32
|
||||
*/
|
||||
if (of_property_read_u32(np, "xlnx,gpio-width", &ngpio))
|
||||
ngpio = 32;
|
||||
chip->mmchip.gc.ngpio = (u16)ngpio;
|
||||
|
||||
spin_lock_init(&chip->gpio_lock);
|
||||
|
||||
@ -258,12 +260,13 @@ static int xgpio_of_probe(struct device_node *np)
|
||||
/* Update GPIO direction shadow register with default value */
|
||||
of_property_read_u32(np, "xlnx,tri-default-2", &chip->gpio_dir);
|
||||
|
||||
/* By default assume full GPIO controller */
|
||||
chip->mmchip.gc.ngpio = 32;
|
||||
|
||||
/* Check device node and parent device node for device width */
|
||||
of_property_read_u32(np, "xlnx,gpio2-width",
|
||||
(u32 *)&chip->mmchip.gc.ngpio);
|
||||
/*
|
||||
* Check device node and parent device node for device width
|
||||
* and assume default width of 32
|
||||
*/
|
||||
if (of_property_read_u32(np, "xlnx,gpio2-width", &ngpio))
|
||||
ngpio = 32;
|
||||
chip->mmchip.gc.ngpio = (u16)ngpio;
|
||||
|
||||
spin_lock_init(&chip->gpio_lock);
|
||||
|
||||
|
@ -88,16 +88,17 @@
|
||||
* @chip: instance of the gpio_chip
|
||||
* @base_addr: base address of the GPIO device
|
||||
* @clk: clock resource for this controller
|
||||
* @irq: interrupt for the GPIO device
|
||||
*/
|
||||
struct zynq_gpio {
|
||||
struct gpio_chip chip;
|
||||
void __iomem *base_addr;
|
||||
struct clk *clk;
|
||||
int irq;
|
||||
};
|
||||
|
||||
static struct irq_chip zynq_gpio_level_irqchip;
|
||||
static struct irq_chip zynq_gpio_edge_irqchip;
|
||||
|
||||
/**
|
||||
* zynq_gpio_get_bank_pin - Get the bank number and pin number within that bank
|
||||
* for a given pin in the GPIO device
|
||||
@ -138,6 +139,13 @@ static inline void zynq_gpio_get_bank_pin(unsigned int pin_num,
|
||||
}
|
||||
}
|
||||
|
||||
static const unsigned int zynq_gpio_bank_offset[] = {
|
||||
ZYNQ_GPIO_BANK0_PIN_MIN,
|
||||
ZYNQ_GPIO_BANK1_PIN_MIN,
|
||||
ZYNQ_GPIO_BANK2_PIN_MIN,
|
||||
ZYNQ_GPIO_BANK3_PIN_MIN,
|
||||
};
|
||||
|
||||
/**
|
||||
* zynq_gpio_get_value - Get the state of the specified pin of GPIO device
|
||||
* @chip: gpio_chip instance to be worked on
|
||||
@ -427,10 +435,9 @@ static int zynq_gpio_set_irq_type(struct irq_data *irq_data, unsigned int type)
|
||||
|
||||
static int zynq_gpio_set_wake(struct irq_data *data, unsigned int on)
|
||||
{
|
||||
if (on)
|
||||
zynq_gpio_irq_unmask(data);
|
||||
else
|
||||
zynq_gpio_irq_mask(data);
|
||||
struct zynq_gpio *gpio = irq_data_get_irq_chip_data(data);
|
||||
|
||||
irq_set_irq_wake(gpio->irq, on);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -444,7 +451,8 @@ static struct irq_chip zynq_gpio_level_irqchip = {
|
||||
.irq_unmask = zynq_gpio_irq_unmask,
|
||||
.irq_set_type = zynq_gpio_set_irq_type,
|
||||
.irq_set_wake = zynq_gpio_set_wake,
|
||||
.flags = IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED,
|
||||
.flags = IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED |
|
||||
IRQCHIP_MASK_ON_SUSPEND,
|
||||
};
|
||||
|
||||
static struct irq_chip zynq_gpio_edge_irqchip = {
|
||||
@ -455,8 +463,28 @@ static struct irq_chip zynq_gpio_edge_irqchip = {
|
||||
.irq_unmask = zynq_gpio_irq_unmask,
|
||||
.irq_set_type = zynq_gpio_set_irq_type,
|
||||
.irq_set_wake = zynq_gpio_set_wake,
|
||||
.flags = IRQCHIP_MASK_ON_SUSPEND,
|
||||
};
|
||||
|
||||
static void zynq_gpio_handle_bank_irq(struct zynq_gpio *gpio,
|
||||
unsigned int bank_num,
|
||||
unsigned long pending)
|
||||
{
|
||||
unsigned int bank_offset = zynq_gpio_bank_offset[bank_num];
|
||||
struct irq_domain *irqdomain = gpio->chip.irqdomain;
|
||||
int offset;
|
||||
|
||||
if (!pending)
|
||||
return;
|
||||
|
||||
for_each_set_bit(offset, &pending, 32) {
|
||||
unsigned int gpio_irq;
|
||||
|
||||
gpio_irq = irq_find_mapping(irqdomain, offset + bank_offset);
|
||||
generic_handle_irq(gpio_irq);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* zynq_gpio_irqhandler - IRQ handler for the gpio banks of a gpio device
|
||||
* @irq: irq number of the gpio bank where interrupt has occurred
|
||||
@ -482,18 +510,7 @@ static void zynq_gpio_irqhandler(unsigned int irq, struct irq_desc *desc)
|
||||
ZYNQ_GPIO_INTSTS_OFFSET(bank_num));
|
||||
int_enb = readl_relaxed(gpio->base_addr +
|
||||
ZYNQ_GPIO_INTMASK_OFFSET(bank_num));
|
||||
int_sts &= ~int_enb;
|
||||
if (int_sts) {
|
||||
int offset;
|
||||
unsigned long pending = int_sts;
|
||||
|
||||
for_each_set_bit(offset, &pending, 32) {
|
||||
unsigned int gpio_irq =
|
||||
irq_find_mapping(gpio->chip.irqdomain,
|
||||
offset);
|
||||
generic_handle_irq(gpio_irq);
|
||||
}
|
||||
}
|
||||
zynq_gpio_handle_bank_irq(gpio, bank_num, int_sts & ~int_enb);
|
||||
}
|
||||
|
||||
chained_irq_exit(irqchip, desc);
|
||||
@ -501,7 +518,11 @@ static void zynq_gpio_irqhandler(unsigned int irq, struct irq_desc *desc)
|
||||
|
||||
static int __maybe_unused zynq_gpio_suspend(struct device *dev)
|
||||
{
|
||||
if (!device_may_wakeup(dev))
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
int irq = platform_get_irq(pdev, 0);
|
||||
struct irq_data *data = irq_get_irq_data(irq);
|
||||
|
||||
if (!irqd_is_wakeup_set(data))
|
||||
return pm_runtime_force_suspend(dev);
|
||||
|
||||
return 0;
|
||||
@ -509,7 +530,11 @@ static int __maybe_unused zynq_gpio_suspend(struct device *dev)
|
||||
|
||||
static int __maybe_unused zynq_gpio_resume(struct device *dev)
|
||||
{
|
||||
if (!device_may_wakeup(dev))
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
int irq = platform_get_irq(pdev, 0);
|
||||
struct irq_data *data = irq_get_irq_data(irq);
|
||||
|
||||
if (!irqd_is_wakeup_set(data))
|
||||
return pm_runtime_force_resume(dev);
|
||||
|
||||
return 0;
|
||||
@ -570,7 +595,7 @@ static const struct dev_pm_ops zynq_gpio_dev_pm_ops = {
|
||||
*/
|
||||
static int zynq_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret, bank_num, irq;
|
||||
int ret, bank_num;
|
||||
struct zynq_gpio *gpio;
|
||||
struct gpio_chip *chip;
|
||||
struct resource *res;
|
||||
@ -586,10 +611,10 @@ static int zynq_gpio_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(gpio->base_addr))
|
||||
return PTR_ERR(gpio->base_addr);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
gpio->irq = platform_get_irq(pdev, 0);
|
||||
if (gpio->irq < 0) {
|
||||
dev_err(&pdev->dev, "invalid IRQ\n");
|
||||
return irq;
|
||||
return gpio->irq;
|
||||
}
|
||||
|
||||
/* configure the gpio chip */
|
||||
@ -637,19 +662,16 @@ static int zynq_gpio_probe(struct platform_device *pdev)
|
||||
goto err_rm_gpiochip;
|
||||
}
|
||||
|
||||
gpiochip_set_chained_irqchip(chip, &zynq_gpio_edge_irqchip, irq,
|
||||
gpiochip_set_chained_irqchip(chip, &zynq_gpio_edge_irqchip, gpio->irq,
|
||||
zynq_gpio_irqhandler);
|
||||
|
||||
pm_runtime_set_active(&pdev->dev);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
device_set_wakeup_capable(&pdev->dev, 1);
|
||||
|
||||
return 0;
|
||||
|
||||
err_rm_gpiochip:
|
||||
if (gpiochip_remove(chip))
|
||||
dev_err(&pdev->dev, "Failed to remove gpio chip\n");
|
||||
gpiochip_remove(chip);
|
||||
err_disable_clk:
|
||||
clk_disable_unprepare(gpio->clk);
|
||||
|
||||
@ -664,16 +686,10 @@ err_disable_clk:
|
||||
*/
|
||||
static int zynq_gpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct zynq_gpio *gpio = platform_get_drvdata(pdev);
|
||||
|
||||
pm_runtime_get_sync(&pdev->dev);
|
||||
|
||||
ret = gpiochip_remove(&gpio->chip);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to remove gpio chip\n");
|
||||
return ret;
|
||||
}
|
||||
gpiochip_remove(&gpio->chip);
|
||||
clk_disable_unprepare(gpio->clk);
|
||||
device_set_wakeup_capable(&pdev->dev, 0);
|
||||
return 0;
|
||||
@ -688,7 +704,6 @@ MODULE_DEVICE_TABLE(of, zynq_gpio_of_match);
|
||||
static struct platform_driver zynq_gpio_driver = {
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &zynq_gpio_dev_pm_ops,
|
||||
.of_match_table = zynq_gpio_of_match,
|
||||
},
|
||||
|
@ -25,10 +25,12 @@ struct acpi_gpio_event {
|
||||
acpi_handle handle;
|
||||
unsigned int pin;
|
||||
unsigned int irq;
|
||||
struct gpio_desc *desc;
|
||||
};
|
||||
|
||||
struct acpi_gpio_connection {
|
||||
struct list_head node;
|
||||
unsigned int pin;
|
||||
struct gpio_desc *desc;
|
||||
};
|
||||
|
||||
@ -143,14 +145,8 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
|
||||
if (!handler)
|
||||
return AE_BAD_PARAMETER;
|
||||
|
||||
desc = gpiochip_get_desc(chip, pin);
|
||||
desc = gpiochip_request_own_desc(chip, pin, "ACPI:Event");
|
||||
if (IS_ERR(desc)) {
|
||||
dev_err(chip->dev, "Failed to get GPIO descriptor\n");
|
||||
return AE_ERROR;
|
||||
}
|
||||
|
||||
ret = gpiochip_request_own_desc(desc, "ACPI:Event");
|
||||
if (ret) {
|
||||
dev_err(chip->dev, "Failed to request GPIO\n");
|
||||
return AE_ERROR;
|
||||
}
|
||||
@ -197,6 +193,7 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
|
||||
event->handle = evt_handle;
|
||||
event->irq = irq;
|
||||
event->pin = pin;
|
||||
event->desc = desc;
|
||||
|
||||
ret = request_threaded_irq(event->irq, NULL, handler, irqflags,
|
||||
"ACPI:Event", event);
|
||||
@ -280,7 +277,7 @@ void acpi_gpiochip_free_interrupts(struct gpio_chip *chip)
|
||||
struct gpio_desc *desc;
|
||||
|
||||
free_irq(event->irq, event);
|
||||
desc = gpiochip_get_desc(chip, event->pin);
|
||||
desc = event->desc;
|
||||
if (WARN_ON(IS_ERR(desc)))
|
||||
continue;
|
||||
gpio_unlock_as_irq(chip, event->pin);
|
||||
@ -409,26 +406,20 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
|
||||
struct gpio_desc *desc;
|
||||
bool found;
|
||||
|
||||
desc = gpiochip_get_desc(chip, pin);
|
||||
if (IS_ERR(desc)) {
|
||||
status = AE_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
mutex_lock(&achip->conn_lock);
|
||||
|
||||
found = false;
|
||||
list_for_each_entry(conn, &achip->conns, node) {
|
||||
if (conn->desc == desc) {
|
||||
if (conn->pin == pin) {
|
||||
found = true;
|
||||
desc = conn->desc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
int ret;
|
||||
|
||||
ret = gpiochip_request_own_desc(desc, "ACPI:OpRegion");
|
||||
if (ret) {
|
||||
desc = gpiochip_request_own_desc(chip, pin,
|
||||
"ACPI:OpRegion");
|
||||
if (IS_ERR(desc)) {
|
||||
status = AE_ERROR;
|
||||
mutex_unlock(&achip->conn_lock);
|
||||
goto out;
|
||||
@ -465,6 +456,7 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
|
||||
goto out;
|
||||
}
|
||||
|
||||
conn->pin = pin;
|
||||
conn->desc = desc;
|
||||
list_add_tail(&conn->node, &achip->conns);
|
||||
}
|
||||
|
@ -308,10 +308,9 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip);
|
||||
*
|
||||
* A gpio_chip with any GPIOs still requested may not be removed.
|
||||
*/
|
||||
int gpiochip_remove(struct gpio_chip *chip)
|
||||
void gpiochip_remove(struct gpio_chip *chip)
|
||||
{
|
||||
unsigned long flags;
|
||||
int status = 0;
|
||||
unsigned id;
|
||||
|
||||
acpi_gpiochip_remove(chip);
|
||||
@ -323,24 +322,15 @@ int gpiochip_remove(struct gpio_chip *chip)
|
||||
of_gpiochip_remove(chip);
|
||||
|
||||
for (id = 0; id < chip->ngpio; id++) {
|
||||
if (test_bit(FLAG_REQUESTED, &chip->desc[id].flags)) {
|
||||
status = -EBUSY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (status == 0) {
|
||||
for (id = 0; id < chip->ngpio; id++)
|
||||
chip->desc[id].chip = NULL;
|
||||
|
||||
list_del(&chip->list);
|
||||
if (test_bit(FLAG_REQUESTED, &chip->desc[id].flags))
|
||||
dev_crit(chip->dev, "REMOVING GPIOCHIP WITH GPIOS STILL REQUESTED\n");
|
||||
}
|
||||
for (id = 0; id < chip->ngpio; id++)
|
||||
chip->desc[id].chip = NULL;
|
||||
|
||||
list_del(&chip->list);
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
|
||||
if (status == 0)
|
||||
gpiochip_unexport(chip);
|
||||
|
||||
return status;
|
||||
gpiochip_unexport(chip);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiochip_remove);
|
||||
|
||||
@ -395,30 +385,47 @@ static struct gpio_chip *find_chip_by_name(const char *name)
|
||||
*/
|
||||
|
||||
/**
|
||||
* gpiochip_add_chained_irqchip() - adds a chained irqchip to a gpiochip
|
||||
* @gpiochip: the gpiochip to add the irqchip to
|
||||
* @irqchip: the irqchip to add to the gpiochip
|
||||
* gpiochip_set_chained_irqchip() - sets a chained irqchip to a gpiochip
|
||||
* @gpiochip: the gpiochip to set the irqchip chain to
|
||||
* @irqchip: the irqchip to chain to the gpiochip
|
||||
* @parent_irq: the irq number corresponding to the parent IRQ for this
|
||||
* chained irqchip
|
||||
* @parent_handler: the parent interrupt handler for the accumulated IRQ
|
||||
* coming out of the gpiochip
|
||||
* coming out of the gpiochip. If the interrupt is nested rather than
|
||||
* cascaded, pass NULL in this handler argument
|
||||
*/
|
||||
void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
|
||||
struct irq_chip *irqchip,
|
||||
int parent_irq,
|
||||
irq_flow_handler_t parent_handler)
|
||||
{
|
||||
if (gpiochip->can_sleep) {
|
||||
chip_err(gpiochip, "you cannot have chained interrupts on a chip that may sleep\n");
|
||||
unsigned int offset;
|
||||
|
||||
if (!gpiochip->irqdomain) {
|
||||
chip_err(gpiochip, "called %s before setting up irqchip\n",
|
||||
__func__);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* The parent irqchip is already using the chip_data for this
|
||||
* irqchip, so our callbacks simply use the handler_data.
|
||||
*/
|
||||
irq_set_handler_data(parent_irq, gpiochip);
|
||||
irq_set_chained_handler(parent_irq, parent_handler);
|
||||
if (parent_handler) {
|
||||
if (gpiochip->can_sleep) {
|
||||
chip_err(gpiochip,
|
||||
"you cannot have chained interrupts on a "
|
||||
"chip that may sleep\n");
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* The parent irqchip is already using the chip_data for this
|
||||
* irqchip, so our callbacks simply use the handler_data.
|
||||
*/
|
||||
irq_set_handler_data(parent_irq, gpiochip);
|
||||
irq_set_chained_handler(parent_irq, parent_handler);
|
||||
}
|
||||
|
||||
/* Set the parent IRQ for all affected IRQs */
|
||||
for (offset = 0; offset < gpiochip->ngpio; offset++)
|
||||
irq_set_parent(irq_find_mapping(gpiochip->irqdomain, offset),
|
||||
parent_irq);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiochip_set_chained_irqchip);
|
||||
|
||||
@ -447,7 +454,7 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
|
||||
irq_set_lockdep_class(irq, &gpiochip_irq_lock_class);
|
||||
irq_set_chip_and_handler(irq, chip->irqchip, chip->irq_handler);
|
||||
/* Chips that can sleep need nested thread handlers */
|
||||
if (chip->can_sleep)
|
||||
if (chip->can_sleep && !chip->irq_not_threaded)
|
||||
irq_set_nested_thread(irq, 1);
|
||||
#ifdef CONFIG_ARM
|
||||
set_irq_flags(irq, IRQF_VALID);
|
||||
@ -524,7 +531,8 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
|
||||
/* Remove all IRQ mappings and delete the domain */
|
||||
if (gpiochip->irqdomain) {
|
||||
for (offset = 0; offset < gpiochip->ngpio; offset++)
|
||||
irq_dispose_mapping(gpiochip->irq_base + offset);
|
||||
irq_dispose_mapping(
|
||||
irq_find_mapping(gpiochip->irqdomain, offset));
|
||||
irq_domain_remove(gpiochip->irqdomain);
|
||||
}
|
||||
|
||||
@ -895,12 +903,22 @@ EXPORT_SYMBOL_GPL(gpiochip_is_requested);
|
||||
* allows the GPIO chip module to be unloaded as needed (we assume that the
|
||||
* GPIO chip driver handles freeing the GPIOs it has requested).
|
||||
*/
|
||||
int gpiochip_request_own_desc(struct gpio_desc *desc, const char *label)
|
||||
struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *chip, u16 hwnum,
|
||||
const char *label)
|
||||
{
|
||||
if (!desc || !desc->chip)
|
||||
return -EINVAL;
|
||||
struct gpio_desc *desc = gpiochip_get_desc(chip, hwnum);
|
||||
int err;
|
||||
|
||||
return __gpiod_request(desc, label);
|
||||
if (IS_ERR(desc)) {
|
||||
chip_err(chip, "failed to get GPIO descriptor\n");
|
||||
return desc;
|
||||
}
|
||||
|
||||
err = __gpiod_request(desc, label);
|
||||
if (err < 0)
|
||||
return ERR_PTR(err);
|
||||
|
||||
return desc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiochip_request_own_desc);
|
||||
|
||||
@ -1652,7 +1670,7 @@ struct gpio_desc *__must_check __gpiod_get_index(struct device *dev,
|
||||
* a result. In that case, use platform lookup as a fallback.
|
||||
*/
|
||||
if (!desc || desc == ERR_PTR(-ENOENT)) {
|
||||
dev_dbg(dev, "using lookup tables for GPIO lookup");
|
||||
dev_dbg(dev, "using lookup tables for GPIO lookup\n");
|
||||
desc = gpiod_find(dev, con_id, idx, &lookupflags);
|
||||
}
|
||||
|
||||
|
@ -1069,8 +1069,7 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
return ret;
|
||||
|
||||
err_gpiochip_remove:
|
||||
if (gpiochip_remove(&dev->gc) < 0)
|
||||
hid_err(hdev, "error removing gpio chip\n");
|
||||
gpiochip_remove(&dev->gc);
|
||||
err_free_i2c:
|
||||
i2c_del_adapter(&dev->adap);
|
||||
err_free_dev:
|
||||
@ -1089,8 +1088,7 @@ static void cp2112_remove(struct hid_device *hdev)
|
||||
struct cp2112_device *dev = hid_get_drvdata(hdev);
|
||||
|
||||
sysfs_remove_group(&hdev->dev.kobj, &cp2112_attr_group);
|
||||
if (gpiochip_remove(&dev->gc))
|
||||
hid_err(hdev, "unable to remove gpio chip\n");
|
||||
gpiochip_remove(&dev->gc);
|
||||
i2c_del_adapter(&dev->adap);
|
||||
/* i2c_del_adapter has finished removing all i2c devices from our
|
||||
* adapter. Well behaved devices should no longer call our cp2112_xfer
|
||||
|
@ -251,9 +251,7 @@ static void adp5588_gpio_remove(struct adp5588_kpad *kpad)
|
||||
dev_warn(dev, "teardown failed %d\n", error);
|
||||
}
|
||||
|
||||
error = gpiochip_remove(&kpad->gc);
|
||||
if (error)
|
||||
dev_warn(dev, "gpiochip_remove failed %d\n", error);
|
||||
gpiochip_remove(&kpad->gc);
|
||||
}
|
||||
#else
|
||||
static inline int adp5588_gpio_add(struct adp5588_kpad *kpad)
|
||||
|
@ -567,9 +567,7 @@ static void adp5589_gpio_remove(struct adp5589_kpad *kpad)
|
||||
dev_warn(dev, "teardown failed %d\n", error);
|
||||
}
|
||||
|
||||
error = gpiochip_remove(&kpad->gc);
|
||||
if (error)
|
||||
dev_warn(dev, "gpiochip_remove failed %d\n", error);
|
||||
gpiochip_remove(&kpad->gc);
|
||||
}
|
||||
#else
|
||||
static inline int adp5589_gpio_add(struct adp5589_kpad *kpad)
|
||||
|
@ -470,14 +470,10 @@ static int ad7879_gpio_add(struct ad7879 *ts,
|
||||
static void ad7879_gpio_remove(struct ad7879 *ts)
|
||||
{
|
||||
const struct ad7879_platform_data *pdata = dev_get_platdata(ts->dev);
|
||||
int ret;
|
||||
|
||||
if (pdata->gpio_export) {
|
||||
ret = gpiochip_remove(&ts->gc);
|
||||
if (ret)
|
||||
dev_err(ts->dev, "failed to remove gpio %d\n",
|
||||
ts->gc.base);
|
||||
}
|
||||
if (pdata->gpio_export)
|
||||
gpiochip_remove(&ts->gc);
|
||||
|
||||
}
|
||||
#else
|
||||
static inline int ad7879_gpio_add(struct ad7879 *ts,
|
||||
|
@ -319,14 +319,8 @@ static int pca9532_destroy_devices(struct pca9532_data *data, int n_devs)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_LEDS_PCA9532_GPIO
|
||||
if (data->gpio.dev) {
|
||||
int err = gpiochip_remove(&data->gpio);
|
||||
if (err) {
|
||||
dev_err(&data->client->dev, "%s failed, %d\n",
|
||||
"gpiochip_remove()", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
if (data->gpio.dev)
|
||||
gpiochip_remove(&data->gpio);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
@ -667,11 +667,8 @@ static int tca6507_probe_gpios(struct i2c_client *client,
|
||||
|
||||
static void tca6507_remove_gpio(struct tca6507_chip *tca)
|
||||
{
|
||||
if (tca->gpio.ngpio) {
|
||||
int err = gpiochip_remove(&tca->gpio);
|
||||
dev_err(&tca->client->dev, "%s failed, %d\n",
|
||||
"gpiochip_remove()", err);
|
||||
}
|
||||
if (tca->gpio.ngpio)
|
||||
gpiochip_remove(&tca->gpio);
|
||||
}
|
||||
#else /* CONFIG_GPIOLIB */
|
||||
static int tca6507_probe_gpios(struct i2c_client *client,
|
||||
|
@ -584,18 +584,14 @@ static int cxd2820r_get_frontend_algo(struct dvb_frontend *fe)
|
||||
static void cxd2820r_release(struct dvb_frontend *fe)
|
||||
{
|
||||
struct cxd2820r_priv *priv = fe->demodulator_priv;
|
||||
int uninitialized_var(ret); /* silence compiler warning */
|
||||
|
||||
dev_dbg(&priv->i2c->dev, "%s\n", __func__);
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
/* remove GPIOs */
|
||||
if (priv->gpio_chip.label) {
|
||||
ret = gpiochip_remove(&priv->gpio_chip);
|
||||
if (ret)
|
||||
dev_err(&priv->i2c->dev, "%s: gpiochip_remove() " \
|
||||
"failed=%d\n", KBUILD_MODNAME, ret);
|
||||
}
|
||||
if (priv->gpio_chip.label)
|
||||
gpiochip_remove(&priv->gpio_chip);
|
||||
|
||||
#endif
|
||||
kfree(priv);
|
||||
return;
|
||||
|
@ -605,7 +605,8 @@ static int asic3_gpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct asic3 *asic = platform_get_drvdata(pdev);
|
||||
|
||||
return gpiochip_remove(&asic->gpio);
|
||||
gpiochip_remove(&asic->gpio);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void asic3_clk_enable(struct asic3 *asic, struct asic3_clk *clk)
|
||||
|
@ -481,15 +481,9 @@ static int htcpld_register_chip_gpio(
|
||||
|
||||
ret = gpiochip_add(&(chip->chip_in));
|
||||
if (ret) {
|
||||
int error;
|
||||
|
||||
dev_warn(dev, "Unable to register input GPIOs for 0x%x: %d\n",
|
||||
plat_chip_data->addr, ret);
|
||||
|
||||
error = gpiochip_remove(&(chip->chip_out));
|
||||
if (error)
|
||||
dev_warn(dev, "Error while trying to unregister gpio chip: %d\n", error);
|
||||
|
||||
gpiochip_remove(&(chip->chip_out));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1047,7 +1047,6 @@ static int sm501_register_gpio(struct sm501_devdata *sm)
|
||||
struct sm501_gpio *gpio = &sm->gpio;
|
||||
resource_size_t iobase = sm->io_res->start + SM501_GPIO;
|
||||
int ret;
|
||||
int tmp;
|
||||
|
||||
dev_dbg(sm->dev, "registering gpio block %08llx\n",
|
||||
(unsigned long long)iobase);
|
||||
@ -1086,11 +1085,7 @@ static int sm501_register_gpio(struct sm501_devdata *sm)
|
||||
return 0;
|
||||
|
||||
err_low_chip:
|
||||
tmp = gpiochip_remove(&gpio->low.gpio);
|
||||
if (tmp) {
|
||||
dev_err(sm->dev, "cannot remove low chip, cannot tidy up\n");
|
||||
return ret;
|
||||
}
|
||||
gpiochip_remove(&gpio->low.gpio);
|
||||
|
||||
err_mapped:
|
||||
iounmap(gpio->regs);
|
||||
@ -1105,18 +1100,12 @@ static int sm501_register_gpio(struct sm501_devdata *sm)
|
||||
static void sm501_gpio_remove(struct sm501_devdata *sm)
|
||||
{
|
||||
struct sm501_gpio *gpio = &sm->gpio;
|
||||
int ret;
|
||||
|
||||
if (!sm->gpio.registered)
|
||||
return;
|
||||
|
||||
ret = gpiochip_remove(&gpio->low.gpio);
|
||||
if (ret)
|
||||
dev_err(sm->dev, "cannot remove low chip, cannot tidy up\n");
|
||||
|
||||
ret = gpiochip_remove(&gpio->high.gpio);
|
||||
if (ret)
|
||||
dev_err(sm->dev, "cannot remove high chip, cannot tidy up\n");
|
||||
gpiochip_remove(&gpio->low.gpio);
|
||||
gpiochip_remove(&gpio->high.gpio);
|
||||
|
||||
iounmap(gpio->regs);
|
||||
release_resource(gpio->regs_res);
|
||||
|
@ -607,7 +607,7 @@ static int tc6393xb_probe(struct platform_device *dev)
|
||||
struct tc6393xb_platform_data *tcpd = dev_get_platdata(&dev->dev);
|
||||
struct tc6393xb *tc6393xb;
|
||||
struct resource *iomem, *rscr;
|
||||
int ret, temp;
|
||||
int ret;
|
||||
|
||||
iomem = platform_get_resource(dev, IORESOURCE_MEM, 0);
|
||||
if (!iomem)
|
||||
@ -714,7 +714,7 @@ err_setup:
|
||||
|
||||
err_gpio_add:
|
||||
if (tc6393xb->gpio.base != -1)
|
||||
temp = gpiochip_remove(&tc6393xb->gpio);
|
||||
gpiochip_remove(&tc6393xb->gpio);
|
||||
tcpd->disable(dev);
|
||||
err_enable:
|
||||
clk_disable(tc6393xb->clk);
|
||||
@ -744,13 +744,8 @@ static int tc6393xb_remove(struct platform_device *dev)
|
||||
|
||||
tc6393xb_detach_irq(dev);
|
||||
|
||||
if (tc6393xb->gpio.base != -1) {
|
||||
ret = gpiochip_remove(&tc6393xb->gpio);
|
||||
if (ret) {
|
||||
dev_err(&dev->dev, "Can't remove gpio chip: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
if (tc6393xb->gpio.base != -1)
|
||||
gpiochip_remove(&tc6393xb->gpio);
|
||||
|
||||
ret = tcpd->disable(dev);
|
||||
clk_disable(tc6393xb->clk);
|
||||
|
@ -621,7 +621,6 @@ static void ucb1x00_remove(struct mcp *mcp)
|
||||
struct ucb1x00_plat_data *pdata = mcp->attached_device.platform_data;
|
||||
struct ucb1x00 *ucb = mcp_get_drvdata(mcp);
|
||||
struct list_head *l, *n;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&ucb1x00_mutex);
|
||||
list_del(&ucb->node);
|
||||
@ -631,11 +630,8 @@ static void ucb1x00_remove(struct mcp *mcp)
|
||||
}
|
||||
mutex_unlock(&ucb1x00_mutex);
|
||||
|
||||
if (ucb->gpio.base != -1) {
|
||||
ret = gpiochip_remove(&ucb->gpio);
|
||||
if (ret)
|
||||
dev_err(&ucb->dev, "Can't remove gpio chip: %d\n", ret);
|
||||
}
|
||||
if (ucb->gpio.base != -1)
|
||||
gpiochip_remove(&ucb->gpio);
|
||||
|
||||
irq_set_chained_handler(ucb->irq, NULL);
|
||||
irq_free_descs(ucb->irq_base, 16);
|
||||
|
@ -86,7 +86,7 @@ config PINCTRL_BCM2835
|
||||
|
||||
config PINCTRL_BCM281XX
|
||||
bool "Broadcom BCM281xx pinctrl driver"
|
||||
depends on OF
|
||||
depends on OF && (ARCH_BCM_MOBILE || COMPILE_TEST)
|
||||
select PINMUX
|
||||
select PINCONF
|
||||
select GENERIC_PINCONF
|
||||
|
@ -1174,7 +1174,7 @@ static int abx500_gpio_probe(struct platform_device *pdev)
|
||||
const struct of_device_id *match;
|
||||
struct abx500_pinctrl *pct;
|
||||
unsigned int id = -1;
|
||||
int ret, err;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
if (!np) {
|
||||
@ -1266,10 +1266,7 @@ static int abx500_gpio_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
|
||||
out_rem_chip:
|
||||
err = gpiochip_remove(&pct->chip);
|
||||
if (err)
|
||||
dev_info(&pdev->dev, "failed to remove gpiochip\n");
|
||||
|
||||
gpiochip_remove(&pct->chip);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1280,15 +1277,8 @@ out_rem_chip:
|
||||
static int abx500_gpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct abx500_pinctrl *pct = platform_get_drvdata(pdev);
|
||||
int ret;
|
||||
|
||||
ret = gpiochip_remove(&pct->chip);
|
||||
if (ret < 0) {
|
||||
dev_err(pct->dev, "unable to remove gpiochip: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
gpiochip_remove(&pct->chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1276,7 +1276,7 @@ static int nmk_gpio_probe(struct platform_device *dev)
|
||||
IRQ_TYPE_EDGE_FALLING);
|
||||
if (ret) {
|
||||
dev_err(&dev->dev, "could not add irqchip\n");
|
||||
ret = gpiochip_remove(&nmk_chip->chip);
|
||||
gpiochip_remove(&nmk_chip->chip);
|
||||
return -ENODEV;
|
||||
}
|
||||
/* Then register the chain on the parent IRQ */
|
||||
|
@ -936,14 +936,8 @@ EXPORT_SYMBOL(msm_pinctrl_probe);
|
||||
int msm_pinctrl_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct msm_pinctrl *pctrl = platform_get_drvdata(pdev);
|
||||
int ret;
|
||||
|
||||
ret = gpiochip_remove(&pctrl->chip);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to remove gpiochip\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
gpiochip_remove(&pctrl->chip);
|
||||
pinctrl_unregister(pctrl->pctrl);
|
||||
|
||||
unregister_restart_handler(&pctrl->restart_nb);
|
||||
|
@ -874,11 +874,7 @@ static int exynos5440_gpiolib_register(struct platform_device *pdev,
|
||||
static int exynos5440_gpiolib_unregister(struct platform_device *pdev,
|
||||
struct exynos5440_pinctrl_priv_data *priv)
|
||||
{
|
||||
int ret = gpiochip_remove(priv->gc);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "gpio chip remove failed\n");
|
||||
return ret;
|
||||
}
|
||||
gpiochip_remove(priv->gc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -946,9 +946,7 @@ static int samsung_gpiolib_register(struct platform_device *pdev,
|
||||
|
||||
fail:
|
||||
for (--i, --bank; i >= 0; --i, --bank)
|
||||
if (gpiochip_remove(&bank->gpio_chip))
|
||||
dev_err(&pdev->dev, "gpio chip %s remove failed\n",
|
||||
bank->gpio_chip.label);
|
||||
gpiochip_remove(&bank->gpio_chip);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -958,16 +956,11 @@ static int samsung_gpiolib_unregister(struct platform_device *pdev,
|
||||
{
|
||||
struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
|
||||
struct samsung_pin_bank *bank = ctrl->pin_banks;
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; !ret && i < ctrl->nr_banks; ++i, ++bank)
|
||||
ret = gpiochip_remove(&bank->gpio_chip);
|
||||
|
||||
if (ret)
|
||||
dev_err(&pdev->dev, "gpio chip remove failed\n");
|
||||
|
||||
return ret;
|
||||
for (i = 0; i < ctrl->nr_banks; ++i, ++bank)
|
||||
gpiochip_remove(&bank->gpio_chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id samsung_pinctrl_dt_match[];
|
||||
|
@ -891,8 +891,7 @@ static int sirfsoc_gpio_probe(struct device_node *np)
|
||||
|
||||
out_no_range:
|
||||
out_banks:
|
||||
if (gpiochip_remove(&sgpio->chip.gc))
|
||||
dev_err(&pdev->dev, "could not remove gpio chip\n");
|
||||
gpiochip_remove(&sgpio->chip.gc);
|
||||
out:
|
||||
iounmap(regs);
|
||||
return err;
|
||||
|
@ -301,8 +301,7 @@ static int platform_pmic_gpio_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
|
||||
fail_request_irq:
|
||||
if (gpiochip_remove(&pg->chip))
|
||||
pr_err("gpiochip_remove failed\n");
|
||||
gpiochip_remove(&pg->chip);
|
||||
err:
|
||||
iounmap(pg->gpiointr);
|
||||
err2:
|
||||
|
@ -475,7 +475,8 @@ int ssb_gpio_unregister(struct ssb_bus *bus)
|
||||
{
|
||||
if (ssb_chipco_available(&bus->chipco) ||
|
||||
ssb_extif_available(&bus->extif)) {
|
||||
return gpiochip_remove(&bus->gpio);
|
||||
gpiochip_remove(&bus->gpio);
|
||||
return 0;
|
||||
} else {
|
||||
SSB_WARN_ON(1);
|
||||
}
|
||||
|
@ -221,9 +221,7 @@ void pio2_gpio_exit(struct pio2_card *card)
|
||||
{
|
||||
const char *label = card->gc.label;
|
||||
|
||||
if (gpiochip_remove(&(card->gc)))
|
||||
dev_err(&card->vdev->dev, "Failed to remove GPIO\n");
|
||||
|
||||
gpiochip_remove(&(card->gc));
|
||||
kfree(label);
|
||||
}
|
||||
|
||||
|
@ -1248,7 +1248,7 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype,
|
||||
mutex_destroy(&s->mutex);
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
WARN_ON(gpiochip_remove(&s->gpio));
|
||||
gpiochip_remove(&s->gpio);
|
||||
|
||||
out_uart:
|
||||
#endif
|
||||
@ -1263,12 +1263,10 @@ out_clk:
|
||||
static int max310x_remove(struct device *dev)
|
||||
{
|
||||
struct max310x_port *s = dev_get_drvdata(dev);
|
||||
int i, ret = 0;
|
||||
int i;
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
ret = gpiochip_remove(&s->gpio);
|
||||
if (ret)
|
||||
return ret;
|
||||
gpiochip_remove(&s->gpio);
|
||||
#endif
|
||||
|
||||
for (i = 0; i < s->uart.nr; i++) {
|
||||
@ -1282,7 +1280,7 @@ static int max310x_remove(struct device *dev)
|
||||
uart_unregister_driver(&s->uart);
|
||||
clk_disable_unprepare(s->clk);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id __maybe_unused max310x_dt_ids[] = {
|
||||
|
@ -1157,7 +1157,7 @@ static int sc16is7xx_probe(struct device *dev,
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
if (devtype->nr_gpio)
|
||||
WARN_ON(gpiochip_remove(&s->gpio));
|
||||
gpiochip_remove(&s->gpio);
|
||||
|
||||
out_uart:
|
||||
#endif
|
||||
@ -1173,14 +1173,11 @@ out_clk:
|
||||
static int sc16is7xx_remove(struct device *dev)
|
||||
{
|
||||
struct sc16is7xx_port *s = dev_get_drvdata(dev);
|
||||
int i, ret = 0;
|
||||
int i;
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
if (s->devtype->nr_gpio) {
|
||||
ret = gpiochip_remove(&s->gpio);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
if (s->devtype->nr_gpio)
|
||||
gpiochip_remove(&s->gpio);
|
||||
#endif
|
||||
|
||||
for (i = 0; i < s->uart.nr; i++) {
|
||||
@ -1195,7 +1192,7 @@ static int sc16is7xx_remove(struct device *dev)
|
||||
if (!IS_ERR(s->clk))
|
||||
clk_disable_unprepare(s->clk);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id __maybe_unused sc16is7xx_dt_ids[] = {
|
||||
|
@ -270,7 +270,7 @@ static int viafb_gpio_probe(struct platform_device *platdev)
|
||||
static int viafb_gpio_remove(struct platform_device *platdev)
|
||||
{
|
||||
unsigned long flags;
|
||||
int ret = 0, i;
|
||||
int i;
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
viafb_pm_unregister(&viafb_gpio_pm_hooks);
|
||||
@ -280,11 +280,7 @@ static int viafb_gpio_remove(struct platform_device *platdev)
|
||||
* Get unregistered.
|
||||
*/
|
||||
if (viafb_gpio_config.gpio_chip.ngpio > 0) {
|
||||
ret = gpiochip_remove(&viafb_gpio_config.gpio_chip);
|
||||
if (ret) { /* Somebody still using it? */
|
||||
printk(KERN_ERR "Viafb: GPIO remove failed\n");
|
||||
return ret;
|
||||
}
|
||||
gpiochip_remove(&viafb_gpio_config.gpio_chip);
|
||||
}
|
||||
/*
|
||||
* Disable the ports.
|
||||
@ -294,7 +290,7 @@ static int viafb_gpio_remove(struct platform_device *platdev)
|
||||
viafb_gpio_disable(viafb_gpio_config.active_gpios[i]);
|
||||
viafb_gpio_config.gpio_chip.ngpio = 0;
|
||||
spin_unlock_irqrestore(&viafb_gpio_config.vdev->reg_lock, flags);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver via_gpio_driver = {
|
||||
|
@ -27,7 +27,7 @@
|
||||
*/
|
||||
|
||||
#ifndef ARCH_NR_GPIOS
|
||||
#define ARCH_NR_GPIOS 256
|
||||
#define ARCH_NR_GPIOS 512
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -56,6 +56,8 @@ struct seq_file;
|
||||
* as the chip access may sleep when e.g. reading out the IRQ status
|
||||
* registers.
|
||||
* @exported: flags if the gpiochip is exported for use from sysfs. Private.
|
||||
* @irq_not_threaded: flag must be set if @can_sleep is set but the
|
||||
* IRQs don't need to be threaded
|
||||
*
|
||||
* A gpio_chip can help platforms abstract various sources of GPIOs so
|
||||
* they can all be accessed through a common programing interface.
|
||||
@ -101,6 +103,7 @@ struct gpio_chip {
|
||||
struct gpio_desc *desc;
|
||||
const char *const *names;
|
||||
bool can_sleep;
|
||||
bool irq_not_threaded;
|
||||
bool exported;
|
||||
|
||||
#ifdef CONFIG_GPIOLIB_IRQCHIP
|
||||
@ -141,7 +144,7 @@ extern const char *gpiochip_is_requested(struct gpio_chip *chip,
|
||||
|
||||
/* add/remove chips */
|
||||
extern int gpiochip_add(struct gpio_chip *chip);
|
||||
extern int gpiochip_remove(struct gpio_chip *chip);
|
||||
extern void gpiochip_remove(struct gpio_chip *chip);
|
||||
extern struct gpio_chip *gpiochip_find(void *data,
|
||||
int (*match)(struct gpio_chip *chip, void *data));
|
||||
|
||||
@ -166,7 +169,8 @@ int gpiochip_irqchip_add(struct gpio_chip *gpiochip,
|
||||
|
||||
#endif /* CONFIG_GPIOLIB_IRQCHIP */
|
||||
|
||||
int gpiochip_request_own_desc(struct gpio_desc *desc, const char *label);
|
||||
struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *chip, u16 hwnum,
|
||||
const char *label);
|
||||
void gpiochip_free_own_desc(struct gpio_desc *desc);
|
||||
|
||||
#else /* CONFIG_GPIOLIB */
|
||||
|
32
include/linux/platform_data/gpio-dwapb.h
Normal file
32
include/linux/platform_data/gpio-dwapb.h
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright(c) 2014 Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
#ifndef GPIO_DW_APB_H
|
||||
#define GPIO_DW_APB_H
|
||||
|
||||
struct dwapb_port_property {
|
||||
struct device_node *node;
|
||||
const char *name;
|
||||
unsigned int idx;
|
||||
unsigned int ngpio;
|
||||
unsigned int gpio_base;
|
||||
unsigned int irq;
|
||||
bool irq_shared;
|
||||
};
|
||||
|
||||
struct dwapb_platform_data {
|
||||
struct dwapb_port_property *properties;
|
||||
unsigned int nports;
|
||||
};
|
||||
|
||||
#endif
|
@ -22,4 +22,22 @@ struct mcp23s08_platform_data {
|
||||
* base to base+15 (or base+31 for s17 variant).
|
||||
*/
|
||||
unsigned base;
|
||||
/* Marks the device as a interrupt controller.
|
||||
* NOTE: The interrupt functionality is only supported for i2c
|
||||
* versions of the chips. The spi chips can also do the interrupts,
|
||||
* but this is not supported by the linux driver yet.
|
||||
*/
|
||||
bool irq_controller;
|
||||
|
||||
/* Sets the mirror flag in the IOCON register. Devices
|
||||
* with two interrupt outputs (these are the devices ending with 17 and
|
||||
* those that have 16 IOs) have two IO banks: IO 0-7 form bank 1 and
|
||||
* IO 8-15 are bank 2. These chips have two different interrupt outputs:
|
||||
* One for bank 1 and another for bank 2. If irq-mirror is set, both
|
||||
* interrupts are generated regardless of the bank that an input change
|
||||
* occurred on. If it is not set, the interrupt are only generated for
|
||||
* the bank they belong to.
|
||||
* On devices with only one interrupt output this property is useless.
|
||||
*/
|
||||
bool mirror;
|
||||
};
|
||||
|
@ -2319,11 +2319,8 @@ static void wm5100_init_gpio(struct i2c_client *i2c)
|
||||
static void wm5100_free_gpio(struct i2c_client *i2c)
|
||||
{
|
||||
struct wm5100_priv *wm5100 = i2c_get_clientdata(i2c);
|
||||
int ret;
|
||||
|
||||
ret = gpiochip_remove(&wm5100->gpio_chip);
|
||||
if (ret != 0)
|
||||
dev_err(&i2c->dev, "Failed to remove GPIOs: %d\n", ret);
|
||||
gpiochip_remove(&wm5100->gpio_chip);
|
||||
}
|
||||
#else
|
||||
static void wm5100_init_gpio(struct i2c_client *i2c)
|
||||
|
@ -1877,11 +1877,7 @@ static void wm8903_init_gpio(struct wm8903_priv *wm8903)
|
||||
|
||||
static void wm8903_free_gpio(struct wm8903_priv *wm8903)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = gpiochip_remove(&wm8903->gpio_chip);
|
||||
if (ret != 0)
|
||||
dev_err(wm8903->dev, "Failed to remove GPIOs: %d\n", ret);
|
||||
gpiochip_remove(&wm8903->gpio_chip);
|
||||
}
|
||||
#else
|
||||
static void wm8903_init_gpio(struct wm8903_priv *wm8903)
|
||||
|
@ -3398,11 +3398,8 @@ static void wm8962_init_gpio(struct snd_soc_codec *codec)
|
||||
static void wm8962_free_gpio(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
ret = gpiochip_remove(&wm8962->gpio_chip);
|
||||
if (ret != 0)
|
||||
dev_err(codec->dev, "Failed to remove GPIOs: %d\n", ret);
|
||||
gpiochip_remove(&wm8962->gpio_chip);
|
||||
}
|
||||
#else
|
||||
static void wm8962_init_gpio(struct snd_soc_codec *codec)
|
||||
|
@ -2216,11 +2216,7 @@ static void wm8996_init_gpio(struct wm8996_priv *wm8996)
|
||||
|
||||
static void wm8996_free_gpio(struct wm8996_priv *wm8996)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = gpiochip_remove(&wm8996->gpio_chip);
|
||||
if (ret != 0)
|
||||
dev_err(wm8996->dev, "Failed to remove GPIOs: %d\n", ret);
|
||||
gpiochip_remove(&wm8996->gpio_chip);
|
||||
}
|
||||
#else
|
||||
static void wm8996_init_gpio(struct wm8996_priv *wm8996)
|
||||
|
Loading…
Reference in New Issue
Block a user