mirror of https://gitee.com/openkylin/linux.git
This is the bulk of GPIO changes for the v5.9 kernel cycle:
Core changes: - Introduce the for_each_requested_gpio() macro to help in dependent code all over the place. Also patch a few locations to use it while we are at it. - Split out the sysfs code into its own file. - Split out the character device code into its own file, then make a set of refactorings and improvements to this code. We are setting the stage to revamp the userspace API a bit in the next cycle. - Fix a whole slew of kerneldoc that was wrong or missing. New drivers: - The PCA953x driver now supports the PCAL9535. Driver improvements: - A host of incremental modernizations and improvements to the PCA953x driver. - Incremental improvements to the Xilinx Zynq driver. - Some improvements to the GPIO aggregator driver. - I ran all over the place switching all threaded and other drivers requesting their own IRQ while using the core GPIO IRQ helpers to pass the GPIO irq chip as a template instead of calling the explicit set-up functions. Next merge window we may retire the old code altogether. -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEElDRnuGcz/wPCXQWMQRCzN7AZXXMFAl8p2cEACgkQQRCzN7AZ XXMjBBAAs4YwEALYTCvpzbXdYGAgMGIEAD84dPBZTAYj3P/iGuXPk/+wdt4wLHTD dQl0/MG6JXf+mCClgsHhC+ILPUS6YM/v/it4gnV4j6o/ugYiNPADYl4pieaq/SVb jNrSxs0tzZYTtlq6xSmRMCpA8SgP3ASWNa5dp5mDkuo3xaEJvM3cpsww7Q5GG3Fb HQD9+XgBGQx7H+6JMoNHR8/E9A5y4pwIvTlfqzTcq3UupTqlvklekgu0fTiA6D7t z/ydQpYtqevuirir7J7oMiIhTSPgTkOcUwNO6hCcwpO/a0q7jwy1DvGIyJDM2yIj UYby03SCLknFGxLwKAcavC3mnLIIor61385e5+lXBH0OS7EO8OpBoi9vAxqalcZ8 ZRrOyYrT3et40rD+ByFFwbUsrD9D4c0Ul+Ocr8upKdnGlRW/u8YahIwn82qnKjF0 ANJanZu76c8ZU8AJQyM/HD7hrcJ0MJXhECXb/JJx4O52ebi4fmOdtS/Kx2urH4KR hX3tspQM/tU89a4jW7NIzzfZKlnPI2rI3NxYgziQVgVnt+iVrkyBiYSoWhK+DEyu JJl5zXHvgb1UmejqN2Qtkq9V+3R2VEYg7WUyr6b48q4acSVI1q+NfGE7+GBT/+d4 Kt1eGz8QtEnxspDhVsQNY4WSP8QpwhmWWM2ujsO6a81vyjB4vSg= =OSvz -----END PGP SIGNATURE----- Merge tag 'gpio-v5.9-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio Pull GPIO updates from Linus Walleij: "This is the bulk of GPIO changes for the v5.9 kernel cycle. There is nothing too exciting in it, but a new macro that fixes a build failure on a minor ARM32 platform that appeared yesterday is part of it so we better merge it. Core changes: - Introduce the for_each_requested_gpio() macro to help in dependent code all over the place. Also patch a few locations to use it while we are at it. - Split out the sysfs code into its own file. - Split out the character device code into its own file, then make a set of refactorings and improvements to this code. We are setting the stage to revamp the userspace API a bit in the next cycle. - Fix a whole slew of kerneldoc that was wrong or missing. New drivers: - The PCA953x driver now supports the PCAL9535. Driver improvements: - A host of incremental modernizations and improvements to the PCA953x driver. - Incremental improvements to the Xilinx Zynq driver. - Some improvements to the GPIO aggregator driver. - I ran all over the place switching all threaded and other drivers requesting their own IRQ while using the core GPIO IRQ helpers to pass the GPIO irq chip as a template instead of calling the explicit set-up functions. Next merge window we may retire the old code altogether" * tag 'gpio-v5.9-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (97 commits) gpio: wcove: Request IRQ after all initialisation done gpio: crystalcove: Free IRQ on error path gpio: pca953x: Request IRQ after all initialisation done gpio: don't use same lockdep class for all devm_gpiochip_add_data users gpio: max732x: Use irqchip template gpio: stmpe: Move chip registration gpio: rcar: Use irqchip template gpio: regmap: fix type clash gpio: Correct kernel-doc inconsistency gpio: pci-idio-16: Use irqchip template gpio: pcie-idio-24: Use irqchip template gpio: 104-idio-16: Use irqchip template gpio: 104-idi-48: Use irqchip template gpio: 104-dio-48e: Use irqchip template gpio: ws16c48: Use irqchip template gpio: omap: improve coding style for pin config flags gpio: dln2: Use irqchip template gpio: sch: Add a blank line between declaration and code gpio: sch: changed every 'unsigned' to 'unsigned int' gpio: ich: changed every 'unsigned' to 'unsigned int' ...
This commit is contained in:
commit
1d8ce0e093
|
@ -19,6 +19,7 @@ Required properties:
|
||||||
nxp,pca9698
|
nxp,pca9698
|
||||||
nxp,pcal6416
|
nxp,pcal6416
|
||||||
nxp,pcal6524
|
nxp,pcal6524
|
||||||
|
nxp,pcal9535
|
||||||
nxp,pcal9555a
|
nxp,pcal9555a
|
||||||
maxim,max7310
|
maxim,max7310
|
||||||
maxim,max7312
|
maxim,max7312
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/gpio/gpio-pca9570.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: PCA9570 I2C GPO expander
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Sungbo Eo <mans0n@gorani.run>
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
enum:
|
||||||
|
- nxp,pca9570
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
gpio-controller: true
|
||||||
|
|
||||||
|
'#gpio-cells':
|
||||||
|
const: 2
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
- gpio-controller
|
||||||
|
- "#gpio-cells"
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
i2c0 {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
|
||||||
|
gpio@24 {
|
||||||
|
compatible = "nxp,pca9570";
|
||||||
|
reg = <0x24>;
|
||||||
|
gpio-controller;
|
||||||
|
#gpio-cells = <2>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
...
|
|
@ -6,7 +6,9 @@ Required properties:
|
||||||
- First cell is the GPIO line number
|
- First cell is the GPIO line number
|
||||||
- Second cell is used to specify optional
|
- Second cell is used to specify optional
|
||||||
parameters (unused)
|
parameters (unused)
|
||||||
- compatible : Should be "xlnx,zynq-gpio-1.0" or "xlnx,zynqmp-gpio-1.0"
|
- compatible : Should be "xlnx,zynq-gpio-1.0" or
|
||||||
|
"xlnx,zynqmp-gpio-1.0" or "xlnx,versal-gpio-1.0
|
||||||
|
or "xlnx,pmc-gpio-1.0
|
||||||
- clocks : Clock specifier (see clock bindings for details)
|
- clocks : Clock specifier (see clock bindings for details)
|
||||||
- gpio-controller : Marks the device node as a GPIO controller.
|
- gpio-controller : Marks the device node as a GPIO controller.
|
||||||
- interrupts : Interrupt specifier (see interrupt bindings for
|
- interrupts : Interrupt specifier (see interrupt bindings for
|
||||||
|
|
|
@ -89,6 +89,13 @@ hardware descriptions such as device tree or ACPI:
|
||||||
Consumer Electronics Control bus using only GPIO. It is used to communicate
|
Consumer Electronics Control bus using only GPIO. It is used to communicate
|
||||||
with devices on the HDMI bus.
|
with devices on the HDMI bus.
|
||||||
|
|
||||||
|
- gpio-charger: drivers/power/supply/gpio-charger.c is used if you need to do
|
||||||
|
battery charging and all you have to go by to check the presence of the
|
||||||
|
AC charger or more complex tasks such as indicating charging status using
|
||||||
|
nothing but GPIO lines, this driver provides that and also a clearly defined
|
||||||
|
way to pass the charging parameters from hardware descriptions such as the
|
||||||
|
device tree.
|
||||||
|
|
||||||
Apart from this there are special GPIO drivers in subsystems like MMC/SD to
|
Apart from this there are special GPIO drivers in subsystems like MMC/SD to
|
||||||
read card detect and write protect GPIO lines, and in the TTY serial subsystem
|
read card detect and write protect GPIO lines, and in the TTY serial subsystem
|
||||||
to emulate MCTRL (modem control) signals CTS/RTS by using two GPIO lines. The
|
to emulate MCTRL (modem control) signals CTS/RTS by using two GPIO lines. The
|
||||||
|
|
|
@ -410,7 +410,7 @@ config GPIO_MXS
|
||||||
|
|
||||||
config GPIO_OCTEON
|
config GPIO_OCTEON
|
||||||
tristate "Cavium OCTEON GPIO"
|
tristate "Cavium OCTEON GPIO"
|
||||||
depends on GPIOLIB && CAVIUM_OCTEON_SOC
|
depends on CAVIUM_OCTEON_SOC
|
||||||
default y
|
default y
|
||||||
help
|
help
|
||||||
Say yes here to support the on-chip GPIO lines on the OCTEON
|
Say yes here to support the on-chip GPIO lines on the OCTEON
|
||||||
|
@ -962,6 +962,14 @@ config GPIO_PCA953X_IRQ
|
||||||
Say yes here to enable the pca953x to be used as an interrupt
|
Say yes here to enable the pca953x to be used as an interrupt
|
||||||
controller. It requires the driver to be built in the kernel.
|
controller. It requires the driver to be built in the kernel.
|
||||||
|
|
||||||
|
config GPIO_PCA9570
|
||||||
|
tristate "PCA9570 4-Bit I2C GPO expander"
|
||||||
|
help
|
||||||
|
Say yes here to enable the GPO driver for the NXP PCA9570 chip.
|
||||||
|
|
||||||
|
To compile this driver as a module, choose M here: the module will
|
||||||
|
be called gpio-pca9570.
|
||||||
|
|
||||||
config GPIO_PCF857X
|
config GPIO_PCF857X
|
||||||
tristate "PCF857x, PCA{85,96}7x, and MAX732[89] I2C GPIO expanders"
|
tristate "PCF857x, PCA{85,96}7x, and MAX732[89] I2C GPIO expanders"
|
||||||
select GPIOLIB_IRQCHIP
|
select GPIOLIB_IRQCHIP
|
||||||
|
@ -1117,7 +1125,7 @@ config GPIO_DLN2
|
||||||
|
|
||||||
config HTC_EGPIO
|
config HTC_EGPIO
|
||||||
bool "HTC EGPIO support"
|
bool "HTC EGPIO support"
|
||||||
depends on GPIOLIB && ARM
|
depends on ARM
|
||||||
help
|
help
|
||||||
This driver supports the CPLD egpio chip present on
|
This driver supports the CPLD egpio chip present on
|
||||||
several HTC phones. It provides basic support for input
|
several HTC phones. It provides basic support for input
|
||||||
|
|
|
@ -7,6 +7,7 @@ obj-$(CONFIG_GPIOLIB) += gpiolib.o
|
||||||
obj-$(CONFIG_GPIOLIB) += gpiolib-devres.o
|
obj-$(CONFIG_GPIOLIB) += gpiolib-devres.o
|
||||||
obj-$(CONFIG_GPIOLIB) += gpiolib-legacy.o
|
obj-$(CONFIG_GPIOLIB) += gpiolib-legacy.o
|
||||||
obj-$(CONFIG_GPIOLIB) += gpiolib-devprop.o
|
obj-$(CONFIG_GPIOLIB) += gpiolib-devprop.o
|
||||||
|
obj-$(CONFIG_GPIOLIB) += gpiolib-cdev.o
|
||||||
obj-$(CONFIG_OF_GPIO) += gpiolib-of.o
|
obj-$(CONFIG_OF_GPIO) += gpiolib-of.o
|
||||||
obj-$(CONFIG_GPIO_SYSFS) += gpiolib-sysfs.o
|
obj-$(CONFIG_GPIO_SYSFS) += gpiolib-sysfs.o
|
||||||
obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o
|
obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o
|
||||||
|
@ -110,6 +111,7 @@ obj-$(CONFIG_GPIO_OCTEON) += gpio-octeon.o
|
||||||
obj-$(CONFIG_GPIO_OMAP) += gpio-omap.o
|
obj-$(CONFIG_GPIO_OMAP) += gpio-omap.o
|
||||||
obj-$(CONFIG_GPIO_PALMAS) += gpio-palmas.o
|
obj-$(CONFIG_GPIO_PALMAS) += gpio-palmas.o
|
||||||
obj-$(CONFIG_GPIO_PCA953X) += gpio-pca953x.o
|
obj-$(CONFIG_GPIO_PCA953X) += gpio-pca953x.o
|
||||||
|
obj-$(CONFIG_GPIO_PCA9570) += gpio-pca9570.o
|
||||||
obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.o
|
obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.o
|
||||||
obj-$(CONFIG_GPIO_PCH) += gpio-pch.o
|
obj-$(CONFIG_GPIO_PCH) += gpio-pch.o
|
||||||
obj-$(CONFIG_GPIO_PCIE_IDIO_24) += gpio-pcie-idio-24.o
|
obj-$(CONFIG_GPIO_PCIE_IDIO_24) += gpio-pcie-idio-24.o
|
||||||
|
|
|
@ -5,7 +5,7 @@ subsystem.
|
||||||
GPIO descriptors
|
GPIO descriptors
|
||||||
|
|
||||||
Starting with commit 79a9becda894 the GPIO subsystem embarked on a journey
|
Starting with commit 79a9becda894 the GPIO subsystem embarked on a journey
|
||||||
to move away from the global GPIO numberspace and toward a decriptor-based
|
to move away from the global GPIO numberspace and toward a descriptor-based
|
||||||
approach. This means that GPIO consumers, drivers and machine descriptions
|
approach. This means that GPIO consumers, drivers and machine descriptions
|
||||||
ideally have no use or idea of the global GPIO numberspace that has/was
|
ideally have no use or idea of the global GPIO numberspace that has/was
|
||||||
used in the inception of the GPIO subsystem.
|
used in the inception of the GPIO subsystem.
|
||||||
|
|
|
@ -368,10 +368,21 @@ static const char *dio48e_names[DIO48E_NGPIO] = {
|
||||||
"PPI Group 1 Port C 5", "PPI Group 1 Port C 6", "PPI Group 1 Port C 7"
|
"PPI Group 1 Port C 5", "PPI Group 1 Port C 6", "PPI Group 1 Port C 7"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int dio48e_irq_init_hw(struct gpio_chip *gc)
|
||||||
|
{
|
||||||
|
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(gc);
|
||||||
|
|
||||||
|
/* Disable IRQ by default */
|
||||||
|
inb(dio48egpio->base + 0xB);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int dio48e_probe(struct device *dev, unsigned int id)
|
static int dio48e_probe(struct device *dev, unsigned int id)
|
||||||
{
|
{
|
||||||
struct dio48e_gpio *dio48egpio;
|
struct dio48e_gpio *dio48egpio;
|
||||||
const char *const name = dev_name(dev);
|
const char *const name = dev_name(dev);
|
||||||
|
struct gpio_irq_chip *girq;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
dio48egpio = devm_kzalloc(dev, sizeof(*dio48egpio), GFP_KERNEL);
|
dio48egpio = devm_kzalloc(dev, sizeof(*dio48egpio), GFP_KERNEL);
|
||||||
|
@ -399,13 +410,17 @@ static int dio48e_probe(struct device *dev, unsigned int id)
|
||||||
dio48egpio->chip.set_multiple = dio48e_gpio_set_multiple;
|
dio48egpio->chip.set_multiple = dio48e_gpio_set_multiple;
|
||||||
dio48egpio->base = base[id];
|
dio48egpio->base = base[id];
|
||||||
|
|
||||||
raw_spin_lock_init(&dio48egpio->lock);
|
girq = &dio48egpio->chip.irq;
|
||||||
|
girq->chip = &dio48e_irqchip;
|
||||||
|
/* This will let us handle the parent IRQ in the driver */
|
||||||
|
girq->parent_handler = NULL;
|
||||||
|
girq->num_parents = 0;
|
||||||
|
girq->parents = NULL;
|
||||||
|
girq->default_type = IRQ_TYPE_NONE;
|
||||||
|
girq->handler = handle_edge_irq;
|
||||||
|
girq->init_hw = dio48e_irq_init_hw;
|
||||||
|
|
||||||
err = devm_gpiochip_add_data(dev, &dio48egpio->chip, dio48egpio);
|
raw_spin_lock_init(&dio48egpio->lock);
|
||||||
if (err) {
|
|
||||||
dev_err(dev, "GPIO registering failed (%d)\n", err);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* initialize all GPIO as output */
|
/* initialize all GPIO as output */
|
||||||
outb(0x80, base[id] + 3);
|
outb(0x80, base[id] + 3);
|
||||||
|
@ -419,13 +434,9 @@ static int dio48e_probe(struct device *dev, unsigned int id)
|
||||||
outb(0x00, base[id] + 6);
|
outb(0x00, base[id] + 6);
|
||||||
outb(0x00, base[id] + 7);
|
outb(0x00, base[id] + 7);
|
||||||
|
|
||||||
/* disable IRQ by default */
|
err = devm_gpiochip_add_data(dev, &dio48egpio->chip, dio48egpio);
|
||||||
inb(base[id] + 0xB);
|
|
||||||
|
|
||||||
err = gpiochip_irqchip_add(&dio48egpio->chip, &dio48e_irqchip, 0,
|
|
||||||
handle_edge_irq, IRQ_TYPE_NONE);
|
|
||||||
if (err) {
|
if (err) {
|
||||||
dev_err(dev, "Could not add irqchip (%d)\n", err);
|
dev_err(dev, "GPIO registering failed (%d)\n", err);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -247,10 +247,22 @@ static const char *idi48_names[IDI48_NGPIO] = {
|
||||||
"Bit 18 B", "Bit 19 B", "Bit 20 B", "Bit 21 B", "Bit 22 B", "Bit 23 B"
|
"Bit 18 B", "Bit 19 B", "Bit 20 B", "Bit 21 B", "Bit 22 B", "Bit 23 B"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int idi_48_irq_init_hw(struct gpio_chip *gc)
|
||||||
|
{
|
||||||
|
struct idi_48_gpio *const idi48gpio = gpiochip_get_data(gc);
|
||||||
|
|
||||||
|
/* Disable IRQ by default */
|
||||||
|
outb(0, idi48gpio->base + 7);
|
||||||
|
inb(idi48gpio->base + 7);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int idi_48_probe(struct device *dev, unsigned int id)
|
static int idi_48_probe(struct device *dev, unsigned int id)
|
||||||
{
|
{
|
||||||
struct idi_48_gpio *idi48gpio;
|
struct idi_48_gpio *idi48gpio;
|
||||||
const char *const name = dev_name(dev);
|
const char *const name = dev_name(dev);
|
||||||
|
struct gpio_irq_chip *girq;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
idi48gpio = devm_kzalloc(dev, sizeof(*idi48gpio), GFP_KERNEL);
|
idi48gpio = devm_kzalloc(dev, sizeof(*idi48gpio), GFP_KERNEL);
|
||||||
|
@ -275,6 +287,16 @@ static int idi_48_probe(struct device *dev, unsigned int id)
|
||||||
idi48gpio->chip.get_multiple = idi_48_gpio_get_multiple;
|
idi48gpio->chip.get_multiple = idi_48_gpio_get_multiple;
|
||||||
idi48gpio->base = base[id];
|
idi48gpio->base = base[id];
|
||||||
|
|
||||||
|
girq = &idi48gpio->chip.irq;
|
||||||
|
girq->chip = &idi_48_irqchip;
|
||||||
|
/* This will let us handle the parent IRQ in the driver */
|
||||||
|
girq->parent_handler = NULL;
|
||||||
|
girq->num_parents = 0;
|
||||||
|
girq->parents = NULL;
|
||||||
|
girq->default_type = IRQ_TYPE_NONE;
|
||||||
|
girq->handler = handle_edge_irq;
|
||||||
|
girq->init_hw = idi_48_irq_init_hw;
|
||||||
|
|
||||||
raw_spin_lock_init(&idi48gpio->lock);
|
raw_spin_lock_init(&idi48gpio->lock);
|
||||||
spin_lock_init(&idi48gpio->ack_lock);
|
spin_lock_init(&idi48gpio->ack_lock);
|
||||||
|
|
||||||
|
@ -284,17 +306,6 @@ static int idi_48_probe(struct device *dev, unsigned int id)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Disable IRQ by default */
|
|
||||||
outb(0, base[id] + 7);
|
|
||||||
inb(base[id] + 7);
|
|
||||||
|
|
||||||
err = gpiochip_irqchip_add(&idi48gpio->chip, &idi_48_irqchip, 0,
|
|
||||||
handle_edge_irq, IRQ_TYPE_NONE);
|
|
||||||
if (err) {
|
|
||||||
dev_err(dev, "Could not add irqchip (%d)\n", err);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = devm_request_irq(dev, irq[id], idi_48_irq_handler, IRQF_SHARED,
|
err = devm_request_irq(dev, irq[id], idi_48_irq_handler, IRQF_SHARED,
|
||||||
name, idi48gpio);
|
name, idi48gpio);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|
|
@ -224,10 +224,22 @@ static const char *idio_16_names[IDIO_16_NGPIO] = {
|
||||||
"IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15"
|
"IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int idio_16_irq_init_hw(struct gpio_chip *gc)
|
||||||
|
{
|
||||||
|
struct idio_16_gpio *const idio16gpio = gpiochip_get_data(gc);
|
||||||
|
|
||||||
|
/* Disable IRQ by default */
|
||||||
|
outb(0, idio16gpio->base + 2);
|
||||||
|
outb(0, idio16gpio->base + 1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int idio_16_probe(struct device *dev, unsigned int id)
|
static int idio_16_probe(struct device *dev, unsigned int id)
|
||||||
{
|
{
|
||||||
struct idio_16_gpio *idio16gpio;
|
struct idio_16_gpio *idio16gpio;
|
||||||
const char *const name = dev_name(dev);
|
const char *const name = dev_name(dev);
|
||||||
|
struct gpio_irq_chip *girq;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
idio16gpio = devm_kzalloc(dev, sizeof(*idio16gpio), GFP_KERNEL);
|
idio16gpio = devm_kzalloc(dev, sizeof(*idio16gpio), GFP_KERNEL);
|
||||||
|
@ -256,6 +268,16 @@ static int idio_16_probe(struct device *dev, unsigned int id)
|
||||||
idio16gpio->base = base[id];
|
idio16gpio->base = base[id];
|
||||||
idio16gpio->out_state = 0xFFFF;
|
idio16gpio->out_state = 0xFFFF;
|
||||||
|
|
||||||
|
girq = &idio16gpio->chip.irq;
|
||||||
|
girq->chip = &idio_16_irqchip;
|
||||||
|
/* This will let us handle the parent IRQ in the driver */
|
||||||
|
girq->parent_handler = NULL;
|
||||||
|
girq->num_parents = 0;
|
||||||
|
girq->parents = NULL;
|
||||||
|
girq->default_type = IRQ_TYPE_NONE;
|
||||||
|
girq->handler = handle_edge_irq;
|
||||||
|
girq->init_hw = idio_16_irq_init_hw;
|
||||||
|
|
||||||
raw_spin_lock_init(&idio16gpio->lock);
|
raw_spin_lock_init(&idio16gpio->lock);
|
||||||
|
|
||||||
err = devm_gpiochip_add_data(dev, &idio16gpio->chip, idio16gpio);
|
err = devm_gpiochip_add_data(dev, &idio16gpio->chip, idio16gpio);
|
||||||
|
@ -264,17 +286,6 @@ static int idio_16_probe(struct device *dev, unsigned int id)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Disable IRQ by default */
|
|
||||||
outb(0, base[id] + 2);
|
|
||||||
outb(0, base[id] + 1);
|
|
||||||
|
|
||||||
err = gpiochip_irqchip_add(&idio16gpio->chip, &idio_16_irqchip, 0,
|
|
||||||
handle_edge_irq, IRQ_TYPE_NONE);
|
|
||||||
if (err) {
|
|
||||||
dev_err(dev, "Could not add irqchip (%d)\n", err);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = devm_request_irq(dev, irq[id], idio_16_irq_handler, 0, name,
|
err = devm_request_irq(dev, irq[id], idio_16_irq_handler, 0, name,
|
||||||
idio16gpio);
|
idio16gpio);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|
|
@ -238,36 +238,6 @@ static void adnp_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
|
||||||
mutex_unlock(&adnp->i2c_lock);
|
mutex_unlock(&adnp->i2c_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
chip->direction_input = adnp_gpio_direction_input;
|
|
||||||
chip->direction_output = adnp_gpio_direction_output;
|
|
||||||
chip->get = adnp_gpio_get;
|
|
||||||
chip->set = adnp_gpio_set;
|
|
||||||
chip->can_sleep = true;
|
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_DEBUG_FS))
|
|
||||||
chip->dbg_show = adnp_gpio_dbg_show;
|
|
||||||
|
|
||||||
chip->base = -1;
|
|
||||||
chip->ngpio = num_gpios;
|
|
||||||
chip->label = adnp->client->name;
|
|
||||||
chip->parent = &adnp->client->dev;
|
|
||||||
chip->of_node = chip->parent->of_node;
|
|
||||||
chip->owner = THIS_MODULE;
|
|
||||||
|
|
||||||
err = devm_gpiochip_add_data(&adnp->client->dev, chip, adnp);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static irqreturn_t adnp_irq(int irq, void *data)
|
static irqreturn_t adnp_irq(int irq, void *data)
|
||||||
{
|
{
|
||||||
struct adnp *adnp = data;
|
struct adnp *adnp = data;
|
||||||
|
@ -464,18 +434,54 @@ static int adnp_irq_setup(struct adnp *adnp)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = gpiochip_irqchip_add_nested(chip,
|
return 0;
|
||||||
&adnp_irq_chip,
|
}
|
||||||
0,
|
|
||||||
handle_simple_irq,
|
static int adnp_gpio_setup(struct adnp *adnp, unsigned int num_gpios,
|
||||||
IRQ_TYPE_NONE);
|
bool is_irq_controller)
|
||||||
if (err) {
|
{
|
||||||
dev_err(chip->parent,
|
struct gpio_chip *chip = &adnp->gpio;
|
||||||
"could not connect irqchip to gpiochip\n");
|
int err;
|
||||||
return err;
|
|
||||||
|
adnp->reg_shift = get_count_order(num_gpios) - 3;
|
||||||
|
|
||||||
|
chip->direction_input = adnp_gpio_direction_input;
|
||||||
|
chip->direction_output = adnp_gpio_direction_output;
|
||||||
|
chip->get = adnp_gpio_get;
|
||||||
|
chip->set = adnp_gpio_set;
|
||||||
|
chip->can_sleep = true;
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_DEBUG_FS))
|
||||||
|
chip->dbg_show = adnp_gpio_dbg_show;
|
||||||
|
|
||||||
|
chip->base = -1;
|
||||||
|
chip->ngpio = num_gpios;
|
||||||
|
chip->label = adnp->client->name;
|
||||||
|
chip->parent = &adnp->client->dev;
|
||||||
|
chip->of_node = chip->parent->of_node;
|
||||||
|
chip->owner = THIS_MODULE;
|
||||||
|
|
||||||
|
if (is_irq_controller) {
|
||||||
|
struct gpio_irq_chip *girq;
|
||||||
|
|
||||||
|
err = adnp_irq_setup(adnp);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
girq = &chip->irq;
|
||||||
|
girq->chip = &adnp_irq_chip;
|
||||||
|
/* This will let us handle the parent IRQ in the driver */
|
||||||
|
girq->parent_handler = NULL;
|
||||||
|
girq->num_parents = 0;
|
||||||
|
girq->parents = NULL;
|
||||||
|
girq->default_type = IRQ_TYPE_NONE;
|
||||||
|
girq->handler = handle_simple_irq;
|
||||||
|
girq->threaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
gpiochip_set_nested_irqchip(chip, &adnp_irq_chip, adnp->client->irq);
|
err = devm_gpiochip_add_data(&adnp->client->dev, chip, adnp);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -503,16 +509,11 @@ static int adnp_i2c_probe(struct i2c_client *client,
|
||||||
mutex_init(&adnp->i2c_lock);
|
mutex_init(&adnp->i2c_lock);
|
||||||
adnp->client = client;
|
adnp->client = client;
|
||||||
|
|
||||||
err = adnp_gpio_setup(adnp, num_gpios);
|
err = adnp_gpio_setup(adnp, num_gpios,
|
||||||
|
of_property_read_bool(np, "interrupt-controller"));
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
if (of_find_property(np, "interrupt-controller", NULL)) {
|
|
||||||
err = adnp_irq_setup(adnp);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
i2c_set_clientdata(client, adnp);
|
i2c_set_clientdata(client, adnp);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -272,13 +272,24 @@ static irqreturn_t adp5588_irq_handler(int irq, void *devid)
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int adp5588_irq_init_hw(struct gpio_chip *gc)
|
||||||
|
{
|
||||||
|
struct adp5588_gpio *dev = gpiochip_get_data(gc);
|
||||||
|
/* Enable IRQs after registering chip */
|
||||||
|
adp5588_gpio_write(dev->client, CFG,
|
||||||
|
ADP5588_AUTO_INC | ADP5588_INT_CFG | ADP5588_KE_IEN);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int adp5588_irq_setup(struct adp5588_gpio *dev)
|
static int adp5588_irq_setup(struct adp5588_gpio *dev)
|
||||||
{
|
{
|
||||||
struct i2c_client *client = dev->client;
|
struct i2c_client *client = dev->client;
|
||||||
int ret;
|
int ret;
|
||||||
struct adp5588_gpio_platform_data *pdata =
|
struct adp5588_gpio_platform_data *pdata =
|
||||||
dev_get_platdata(&client->dev);
|
dev_get_platdata(&client->dev);
|
||||||
int irq_base = pdata ? pdata->irq_base : 0;
|
struct gpio_irq_chip *girq;
|
||||||
|
|
||||||
adp5588_gpio_write(client, CFG, ADP5588_AUTO_INC);
|
adp5588_gpio_write(client, CFG, ADP5588_AUTO_INC);
|
||||||
adp5588_gpio_write(client, INT_STAT, -1); /* status is W1C */
|
adp5588_gpio_write(client, INT_STAT, -1); /* status is W1C */
|
||||||
|
@ -294,21 +305,19 @@ static int adp5588_irq_setup(struct adp5588_gpio *dev)
|
||||||
client->irq);
|
client->irq);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
ret = gpiochip_irqchip_add_nested(&dev->gpio_chip,
|
|
||||||
&adp5588_irq_chip, irq_base,
|
|
||||||
handle_simple_irq,
|
|
||||||
IRQ_TYPE_NONE);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(&client->dev,
|
|
||||||
"could not connect irqchip to gpiochip\n");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
gpiochip_set_nested_irqchip(&dev->gpio_chip,
|
|
||||||
&adp5588_irq_chip,
|
|
||||||
client->irq);
|
|
||||||
|
|
||||||
adp5588_gpio_write(client, CFG,
|
/* This will be registered in the call to devm_gpiochip_add_data() */
|
||||||
ADP5588_AUTO_INC | ADP5588_INT_CFG | ADP5588_KE_IEN);
|
girq = &dev->gpio_chip.irq;
|
||||||
|
girq->chip = &adp5588_irq_chip;
|
||||||
|
/* This will let us handle the parent IRQ in the driver */
|
||||||
|
girq->parent_handler = NULL;
|
||||||
|
girq->num_parents = 0;
|
||||||
|
girq->parents = NULL;
|
||||||
|
girq->first = pdata ? pdata->irq_base : 0;
|
||||||
|
girq->default_type = IRQ_TYPE_NONE;
|
||||||
|
girq->handler = handle_simple_irq;
|
||||||
|
girq->init_hw = adp5588_irq_init_hw;
|
||||||
|
girq->threaded = true;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <linux/bitmap.h>
|
#include <linux/bitmap.h>
|
||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
#include <linux/ctype.h>
|
#include <linux/ctype.h>
|
||||||
|
#include <linux/gpio.h>
|
||||||
#include <linux/gpio/consumer.h>
|
#include <linux/gpio/consumer.h>
|
||||||
#include <linux/gpio/driver.h>
|
#include <linux/gpio/driver.h>
|
||||||
#include <linux/gpio/machine.h>
|
#include <linux/gpio/machine.h>
|
||||||
|
@ -38,9 +39,9 @@ static DEFINE_IDR(gpio_aggregator_idr);
|
||||||
|
|
||||||
static char *get_arg(char **args)
|
static char *get_arg(char **args)
|
||||||
{
|
{
|
||||||
char *start = *args, *end;
|
char *start, *end;
|
||||||
|
|
||||||
start = skip_spaces(start);
|
start = skip_spaces(*args);
|
||||||
if (!*start)
|
if (!*start)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -111,55 +112,45 @@ static int aggr_add_gpio(struct gpio_aggregator *aggr, const char *key,
|
||||||
|
|
||||||
static int aggr_parse(struct gpio_aggregator *aggr)
|
static int aggr_parse(struct gpio_aggregator *aggr)
|
||||||
{
|
{
|
||||||
unsigned int first_index, last_index, i, n = 0;
|
|
||||||
char *name, *offsets, *first, *last, *next;
|
|
||||||
char *args = aggr->args;
|
char *args = aggr->args;
|
||||||
int error;
|
unsigned long *bitmap;
|
||||||
|
unsigned int i, n = 0;
|
||||||
|
char *name, *offsets;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
bitmap = bitmap_alloc(ARCH_NR_GPIOS, GFP_KERNEL);
|
||||||
|
if (!bitmap)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
for (name = get_arg(&args), offsets = get_arg(&args); name;
|
for (name = get_arg(&args), offsets = get_arg(&args); name;
|
||||||
offsets = get_arg(&args)) {
|
offsets = get_arg(&args)) {
|
||||||
if (IS_ERR(name)) {
|
if (IS_ERR(name)) {
|
||||||
pr_err("Cannot get GPIO specifier: %pe\n", name);
|
pr_err("Cannot get GPIO specifier: %pe\n", name);
|
||||||
return PTR_ERR(name);
|
error = PTR_ERR(name);
|
||||||
|
goto free_bitmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isrange(offsets)) {
|
if (!isrange(offsets)) {
|
||||||
/* Named GPIO line */
|
/* Named GPIO line */
|
||||||
error = aggr_add_gpio(aggr, name, U16_MAX, &n);
|
error = aggr_add_gpio(aggr, name, U16_MAX, &n);
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
goto free_bitmap;
|
||||||
|
|
||||||
name = offsets;
|
name = offsets;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* GPIO chip + offset(s) */
|
/* GPIO chip + offset(s) */
|
||||||
for (first = offsets; *first; first = next) {
|
error = bitmap_parselist(offsets, bitmap, ARCH_NR_GPIOS);
|
||||||
next = strchrnul(first, ',');
|
if (error) {
|
||||||
if (*next)
|
pr_err("Cannot parse %s: %d\n", offsets, error);
|
||||||
*next++ = '\0';
|
goto free_bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
last = strchr(first, '-');
|
for_each_set_bit(i, bitmap, ARCH_NR_GPIOS) {
|
||||||
if (last)
|
error = aggr_add_gpio(aggr, name, i, &n);
|
||||||
*last++ = '\0';
|
if (error)
|
||||||
|
goto free_bitmap;
|
||||||
if (kstrtouint(first, 10, &first_index)) {
|
|
||||||
pr_err("Cannot parse GPIO index %s\n", first);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!last) {
|
|
||||||
last_index = first_index;
|
|
||||||
} else if (kstrtouint(last, 10, &last_index)) {
|
|
||||||
pr_err("Cannot parse GPIO index %s\n", last);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = first_index; i <= last_index; i++) {
|
|
||||||
error = aggr_add_gpio(aggr, name, i, &n);
|
|
||||||
if (error)
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
name = get_arg(&args);
|
name = get_arg(&args);
|
||||||
|
@ -167,10 +158,12 @@ static int aggr_parse(struct gpio_aggregator *aggr)
|
||||||
|
|
||||||
if (!n) {
|
if (!n) {
|
||||||
pr_err("No GPIOs specified\n");
|
pr_err("No GPIOs specified\n");
|
||||||
return -EINVAL;
|
error = -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
free_bitmap:
|
||||||
|
bitmap_free(bitmap);
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t new_device_store(struct device_driver *driver, const char *buf,
|
static ssize_t new_device_store(struct device_driver *driver, const char *buf,
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
* @interrupt_trigger : specifies the hardware configured IRQ trigger type
|
* @interrupt_trigger : specifies the hardware configured IRQ trigger type
|
||||||
* (rising, falling, both, high)
|
* (rising, falling, both, high)
|
||||||
* @mapped_irq : kernel mapped irq number.
|
* @mapped_irq : kernel mapped irq number.
|
||||||
|
* @irq_chip : IRQ chip configuration
|
||||||
*/
|
*/
|
||||||
struct altera_gpio_chip {
|
struct altera_gpio_chip {
|
||||||
struct of_mm_gpio_chip mmchip;
|
struct of_mm_gpio_chip mmchip;
|
||||||
|
@ -69,7 +70,7 @@ static void altera_gpio_irq_mask(struct irq_data *d)
|
||||||
raw_spin_unlock_irqrestore(&altera_gc->gpio_lock, flags);
|
raw_spin_unlock_irqrestore(&altera_gc->gpio_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* This controller's IRQ type is synthesized in hardware, so this function
|
* This controller's IRQ type is synthesized in hardware, so this function
|
||||||
* just checks if the requested set_type matches the synthesized IRQ type
|
* just checks if the requested set_type matches the synthesized IRQ type
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -129,7 +129,7 @@ static void crystalcove_update_irq_ctrl(struct crystalcove_gpio *cg, int gpio)
|
||||||
regmap_update_bits(cg->regmap, reg, CTLI_INTCNT_BE, cg->intcnt_value);
|
regmap_update_bits(cg->regmap, reg, CTLI_INTCNT_BE, cg->intcnt_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int crystalcove_gpio_dir_in(struct gpio_chip *chip, unsigned gpio)
|
static int crystalcove_gpio_dir_in(struct gpio_chip *chip, unsigned int gpio)
|
||||||
{
|
{
|
||||||
struct crystalcove_gpio *cg = gpiochip_get_data(chip);
|
struct crystalcove_gpio *cg = gpiochip_get_data(chip);
|
||||||
int reg = to_reg(gpio, CTRL_OUT);
|
int reg = to_reg(gpio, CTRL_OUT);
|
||||||
|
@ -140,7 +140,7 @@ static int crystalcove_gpio_dir_in(struct gpio_chip *chip, unsigned gpio)
|
||||||
return regmap_write(cg->regmap, reg, CTLO_INPUT_SET);
|
return regmap_write(cg->regmap, reg, CTLO_INPUT_SET);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int crystalcove_gpio_dir_out(struct gpio_chip *chip, unsigned gpio,
|
static int crystalcove_gpio_dir_out(struct gpio_chip *chip, unsigned int gpio,
|
||||||
int value)
|
int value)
|
||||||
{
|
{
|
||||||
struct crystalcove_gpio *cg = gpiochip_get_data(chip);
|
struct crystalcove_gpio *cg = gpiochip_get_data(chip);
|
||||||
|
@ -152,7 +152,7 @@ static int crystalcove_gpio_dir_out(struct gpio_chip *chip, unsigned gpio,
|
||||||
return regmap_write(cg->regmap, reg, CTLO_OUTPUT_SET | value);
|
return regmap_write(cg->regmap, reg, CTLO_OUTPUT_SET | value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int crystalcove_gpio_get(struct gpio_chip *chip, unsigned gpio)
|
static int crystalcove_gpio_get(struct gpio_chip *chip, unsigned int gpio)
|
||||||
{
|
{
|
||||||
struct crystalcove_gpio *cg = gpiochip_get_data(chip);
|
struct crystalcove_gpio *cg = gpiochip_get_data(chip);
|
||||||
unsigned int val;
|
unsigned int val;
|
||||||
|
@ -169,7 +169,7 @@ static int crystalcove_gpio_get(struct gpio_chip *chip, unsigned gpio)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void crystalcove_gpio_set(struct gpio_chip *chip,
|
static void crystalcove_gpio_set(struct gpio_chip *chip,
|
||||||
unsigned gpio, int value)
|
unsigned int gpio, int value)
|
||||||
{
|
{
|
||||||
struct crystalcove_gpio *cg = gpiochip_get_data(chip);
|
struct crystalcove_gpio *cg = gpiochip_get_data(chip);
|
||||||
int reg = to_reg(gpio, CTRL_OUT);
|
int reg = to_reg(gpio, CTRL_OUT);
|
||||||
|
@ -183,7 +183,7 @@ static void crystalcove_gpio_set(struct gpio_chip *chip,
|
||||||
regmap_update_bits(cg->regmap, reg, 1, 0);
|
regmap_update_bits(cg->regmap, reg, 1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int crystalcove_irq_type(struct irq_data *data, unsigned type)
|
static int crystalcove_irq_type(struct irq_data *data, unsigned int type)
|
||||||
{
|
{
|
||||||
struct crystalcove_gpio *cg =
|
struct crystalcove_gpio *cg =
|
||||||
gpiochip_get_data(irq_data_get_irq_chip_data(data));
|
gpiochip_get_data(irq_data_get_irq_chip_data(data));
|
||||||
|
@ -330,6 +330,7 @@ static int crystalcove_gpio_probe(struct platform_device *pdev)
|
||||||
int retval;
|
int retval;
|
||||||
struct device *dev = pdev->dev.parent;
|
struct device *dev = pdev->dev.parent;
|
||||||
struct intel_soc_pmic *pmic = dev_get_drvdata(dev);
|
struct intel_soc_pmic *pmic = dev_get_drvdata(dev);
|
||||||
|
struct gpio_irq_chip *girq;
|
||||||
|
|
||||||
if (irq < 0)
|
if (irq < 0)
|
||||||
return irq;
|
return irq;
|
||||||
|
@ -353,46 +354,39 @@ static int crystalcove_gpio_probe(struct platform_device *pdev)
|
||||||
cg->chip.dbg_show = crystalcove_gpio_dbg_show;
|
cg->chip.dbg_show = crystalcove_gpio_dbg_show;
|
||||||
cg->regmap = pmic->regmap;
|
cg->regmap = pmic->regmap;
|
||||||
|
|
||||||
|
girq = &cg->chip.irq;
|
||||||
|
girq->chip = &crystalcove_irqchip;
|
||||||
|
/* This will let us handle the parent IRQ in the driver */
|
||||||
|
girq->parent_handler = NULL;
|
||||||
|
girq->num_parents = 0;
|
||||||
|
girq->parents = NULL;
|
||||||
|
girq->default_type = IRQ_TYPE_NONE;
|
||||||
|
girq->handler = handle_simple_irq;
|
||||||
|
girq->threaded = true;
|
||||||
|
|
||||||
|
retval = devm_request_threaded_irq(&pdev->dev, irq, NULL,
|
||||||
|
crystalcove_gpio_irq_handler,
|
||||||
|
IRQF_ONESHOT, KBUILD_MODNAME, cg);
|
||||||
|
if (retval) {
|
||||||
|
dev_warn(&pdev->dev, "request irq failed: %d\n", retval);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
retval = devm_gpiochip_add_data(&pdev->dev, &cg->chip, cg);
|
retval = devm_gpiochip_add_data(&pdev->dev, &cg->chip, cg);
|
||||||
if (retval) {
|
if (retval) {
|
||||||
dev_warn(&pdev->dev, "add gpio chip error: %d\n", retval);
|
dev_warn(&pdev->dev, "add gpio chip error: %d\n", retval);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
gpiochip_irqchip_add_nested(&cg->chip, &crystalcove_irqchip, 0,
|
|
||||||
handle_simple_irq, IRQ_TYPE_NONE);
|
|
||||||
|
|
||||||
retval = request_threaded_irq(irq, NULL, crystalcove_gpio_irq_handler,
|
|
||||||
IRQF_ONESHOT, KBUILD_MODNAME, cg);
|
|
||||||
|
|
||||||
if (retval) {
|
|
||||||
dev_warn(&pdev->dev, "request irq failed: %d\n", retval);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
gpiochip_set_nested_irqchip(&cg->chip, &crystalcove_irqchip, irq);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int crystalcove_gpio_remove(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
struct crystalcove_gpio *cg = platform_get_drvdata(pdev);
|
|
||||||
int irq = platform_get_irq(pdev, 0);
|
|
||||||
|
|
||||||
if (irq >= 0)
|
|
||||||
free_irq(irq, cg);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct platform_driver crystalcove_gpio_driver = {
|
static struct platform_driver crystalcove_gpio_driver = {
|
||||||
.probe = crystalcove_gpio_probe,
|
.probe = crystalcove_gpio_probe,
|
||||||
.remove = crystalcove_gpio_remove,
|
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "crystal_cove_gpio",
|
.name = "crystal_cove_gpio",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
module_platform_driver(crystalcove_gpio_driver);
|
module_platform_driver(crystalcove_gpio_driver);
|
||||||
|
|
||||||
MODULE_AUTHOR("Yang, Bin <bin.yang@intel.com>");
|
MODULE_AUTHOR("Yang, Bin <bin.yang@intel.com>");
|
||||||
|
|
|
@ -440,6 +440,7 @@ static int dln2_gpio_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct dln2_gpio *dln2;
|
struct dln2_gpio *dln2;
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
|
struct gpio_irq_chip *girq;
|
||||||
int pins;
|
int pins;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -476,6 +477,15 @@ static int dln2_gpio_probe(struct platform_device *pdev)
|
||||||
dln2->gpio.direction_output = dln2_gpio_direction_output;
|
dln2->gpio.direction_output = dln2_gpio_direction_output;
|
||||||
dln2->gpio.set_config = dln2_gpio_set_config;
|
dln2->gpio.set_config = dln2_gpio_set_config;
|
||||||
|
|
||||||
|
girq = &dln2->gpio.irq;
|
||||||
|
girq->chip = &dln2_gpio_irqchip;
|
||||||
|
/* The event comes from the outside so no parent handler */
|
||||||
|
girq->parent_handler = NULL;
|
||||||
|
girq->num_parents = 0;
|
||||||
|
girq->parents = NULL;
|
||||||
|
girq->default_type = IRQ_TYPE_NONE;
|
||||||
|
girq->handler = handle_simple_irq;
|
||||||
|
|
||||||
platform_set_drvdata(pdev, dln2);
|
platform_set_drvdata(pdev, dln2);
|
||||||
|
|
||||||
ret = devm_gpiochip_add_data(dev, &dln2->gpio, dln2);
|
ret = devm_gpiochip_add_data(dev, &dln2->gpio, dln2);
|
||||||
|
@ -484,13 +494,6 @@ static int dln2_gpio_probe(struct platform_device *pdev)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = gpiochip_irqchip_add(&dln2->gpio, &dln2_gpio_irqchip, 0,
|
|
||||||
handle_simple_irq, IRQ_TYPE_NONE);
|
|
||||||
if (ret < 0) {
|
|
||||||
dev_err(dev, "failed to add irq chip: %d\n", ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = dln2_register_event_cb(pdev, DLN2_GPIO_CONDITION_MET_EV,
|
ret = dln2_register_event_cb(pdev, DLN2_GPIO_CONDITION_MET_EV,
|
||||||
dln2_gpio_event);
|
dln2_gpio_event);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
|
|
@ -74,8 +74,8 @@ struct ichx_desc {
|
||||||
u32 use_sel_ignore[3];
|
u32 use_sel_ignore[3];
|
||||||
|
|
||||||
/* Some chipsets have quirks, let these use their own request/get */
|
/* Some chipsets have quirks, let these use their own request/get */
|
||||||
int (*request)(struct gpio_chip *chip, unsigned offset);
|
int (*request)(struct gpio_chip *chip, unsigned int offset);
|
||||||
int (*get)(struct gpio_chip *chip, unsigned offset);
|
int (*get)(struct gpio_chip *chip, unsigned int offset);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Some chipsets don't let reading output values on GPIO_LVL register
|
* Some chipsets don't let reading output values on GPIO_LVL register
|
||||||
|
@ -100,7 +100,7 @@ static int modparam_gpiobase = -1; /* dynamic */
|
||||||
module_param_named(gpiobase, modparam_gpiobase, int, 0444);
|
module_param_named(gpiobase, modparam_gpiobase, int, 0444);
|
||||||
MODULE_PARM_DESC(gpiobase, "The GPIO number base. -1 means dynamic, which is the default.");
|
MODULE_PARM_DESC(gpiobase, "The GPIO number base. -1 means dynamic, which is the default.");
|
||||||
|
|
||||||
static int ichx_write_bit(int reg, unsigned nr, int val, int verify)
|
static int ichx_write_bit(int reg, unsigned int nr, int val, int verify)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
u32 data, tmp;
|
u32 data, tmp;
|
||||||
|
@ -132,7 +132,7 @@ static int ichx_write_bit(int reg, unsigned nr, int val, int verify)
|
||||||
return (verify && data != tmp) ? -EPERM : 0;
|
return (verify && data != tmp) ? -EPERM : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ichx_read_bit(int reg, unsigned nr)
|
static int ichx_read_bit(int reg, unsigned int nr)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
u32 data;
|
u32 data;
|
||||||
|
@ -152,12 +152,12 @@ static int ichx_read_bit(int reg, unsigned nr)
|
||||||
return !!(data & BIT(bit));
|
return !!(data & BIT(bit));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ichx_gpio_check_available(struct gpio_chip *gpio, unsigned nr)
|
static bool ichx_gpio_check_available(struct gpio_chip *gpio, unsigned int nr)
|
||||||
{
|
{
|
||||||
return !!(ichx_priv.use_gpio & BIT(nr / 32));
|
return !!(ichx_priv.use_gpio & BIT(nr / 32));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ichx_gpio_get_direction(struct gpio_chip *gpio, unsigned nr)
|
static int ichx_gpio_get_direction(struct gpio_chip *gpio, unsigned int nr)
|
||||||
{
|
{
|
||||||
if (ichx_read_bit(GPIO_IO_SEL, nr))
|
if (ichx_read_bit(GPIO_IO_SEL, nr))
|
||||||
return GPIO_LINE_DIRECTION_IN;
|
return GPIO_LINE_DIRECTION_IN;
|
||||||
|
@ -165,7 +165,7 @@ static int ichx_gpio_get_direction(struct gpio_chip *gpio, unsigned nr)
|
||||||
return GPIO_LINE_DIRECTION_OUT;
|
return GPIO_LINE_DIRECTION_OUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ichx_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
|
static int ichx_gpio_direction_input(struct gpio_chip *gpio, unsigned int nr)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Try setting pin as an input and verify it worked since many pins
|
* Try setting pin as an input and verify it worked since many pins
|
||||||
|
@ -174,7 +174,7 @@ static int ichx_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
|
||||||
return ichx_write_bit(GPIO_IO_SEL, nr, 1, 1);
|
return ichx_write_bit(GPIO_IO_SEL, nr, 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ichx_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
|
static int ichx_gpio_direction_output(struct gpio_chip *gpio, unsigned int nr,
|
||||||
int val)
|
int val)
|
||||||
{
|
{
|
||||||
/* Disable blink hardware which is available for GPIOs from 0 to 31. */
|
/* Disable blink hardware which is available for GPIOs from 0 to 31. */
|
||||||
|
@ -191,12 +191,12 @@ static int ichx_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
|
||||||
return ichx_write_bit(GPIO_IO_SEL, nr, 0, 1);
|
return ichx_write_bit(GPIO_IO_SEL, nr, 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ichx_gpio_get(struct gpio_chip *chip, unsigned nr)
|
static int ichx_gpio_get(struct gpio_chip *chip, unsigned int nr)
|
||||||
{
|
{
|
||||||
return ichx_read_bit(GPIO_LVL, nr);
|
return ichx_read_bit(GPIO_LVL, nr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ich6_gpio_get(struct gpio_chip *chip, unsigned nr)
|
static int ich6_gpio_get(struct gpio_chip *chip, unsigned int nr)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
u32 data;
|
u32 data;
|
||||||
|
@ -223,7 +223,7 @@ static int ich6_gpio_get(struct gpio_chip *chip, unsigned nr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ichx_gpio_request(struct gpio_chip *chip, unsigned nr)
|
static int ichx_gpio_request(struct gpio_chip *chip, unsigned int nr)
|
||||||
{
|
{
|
||||||
if (!ichx_gpio_check_available(chip, nr))
|
if (!ichx_gpio_check_available(chip, nr))
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
|
@ -240,7 +240,7 @@ static int ichx_gpio_request(struct gpio_chip *chip, unsigned nr)
|
||||||
return ichx_read_bit(GPIO_USE_SEL, nr) ? 0 : -ENODEV;
|
return ichx_read_bit(GPIO_USE_SEL, nr) ? 0 : -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ich6_gpio_request(struct gpio_chip *chip, unsigned nr)
|
static int ich6_gpio_request(struct gpio_chip *chip, unsigned int nr)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Fixups for bits 16 and 17 are necessary on the Intel ICH6/3100
|
* Fixups for bits 16 and 17 are necessary on the Intel ICH6/3100
|
||||||
|
@ -254,7 +254,7 @@ static int ich6_gpio_request(struct gpio_chip *chip, unsigned nr)
|
||||||
return ichx_gpio_request(chip, nr);
|
return ichx_gpio_request(chip, nr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ichx_gpio_set(struct gpio_chip *chip, unsigned nr, int val)
|
static void ichx_gpio_set(struct gpio_chip *chip, unsigned int nr, int val)
|
||||||
{
|
{
|
||||||
ichx_write_bit(GPIO_LVL, nr, val, 0);
|
ichx_write_bit(GPIO_LVL, nr, val, 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,13 +47,13 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct it87_gpio - it87-specific GPIO chip
|
* struct it87_gpio - it87-specific GPIO chip
|
||||||
* @chip the underlying gpio_chip structure
|
* @chip: the underlying gpio_chip structure
|
||||||
* @lock a lock to avoid races between operations
|
* @lock: a lock to avoid races between operations
|
||||||
* @io_base base address for gpio ports
|
* @io_base: base address for gpio ports
|
||||||
* @io_size size of the port rage starting from io_base.
|
* @io_size: size of the port rage starting from io_base.
|
||||||
* @output_base Super I/O register address for Output Enable register
|
* @output_base: Super I/O register address for Output Enable register
|
||||||
* @simple_base Super I/O 'Simple I/O' Enable register
|
* @simple_base: Super I/O 'Simple I/O' Enable register
|
||||||
* @simple_size Super IO 'Simple I/O' Enable register size; this is
|
* @simple_size: Super IO 'Simple I/O' Enable register size; this is
|
||||||
* required because IT87xx chips might only provide Simple I/O
|
* required because IT87xx chips might only provide Simple I/O
|
||||||
* switches on a subset of lines, whereas the others keep the
|
* switches on a subset of lines, whereas the others keep the
|
||||||
* same status all time.
|
* same status all time.
|
||||||
|
|
|
@ -503,6 +503,8 @@ static int max732x_irq_setup(struct max732x_chip *chip,
|
||||||
|
|
||||||
if (((pdata && pdata->irq_base) || client->irq)
|
if (((pdata && pdata->irq_base) || client->irq)
|
||||||
&& has_irq != INT_NONE) {
|
&& has_irq != INT_NONE) {
|
||||||
|
struct gpio_irq_chip *girq;
|
||||||
|
|
||||||
if (pdata)
|
if (pdata)
|
||||||
irq_base = pdata->irq_base;
|
irq_base = pdata->irq_base;
|
||||||
chip->irq_features = has_irq;
|
chip->irq_features = has_irq;
|
||||||
|
@ -517,19 +519,17 @@ static int max732x_irq_setup(struct max732x_chip *chip,
|
||||||
client->irq);
|
client->irq);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
ret = gpiochip_irqchip_add_nested(&chip->gpio_chip,
|
|
||||||
&max732x_irq_chip,
|
girq = &chip->gpio_chip.irq;
|
||||||
irq_base,
|
girq->chip = &max732x_irq_chip;
|
||||||
handle_simple_irq,
|
/* This will let us handle the parent IRQ in the driver */
|
||||||
IRQ_TYPE_NONE);
|
girq->parent_handler = NULL;
|
||||||
if (ret) {
|
girq->num_parents = 0;
|
||||||
dev_err(&client->dev,
|
girq->parents = NULL;
|
||||||
"could not connect irqchip to gpiochip\n");
|
girq->default_type = IRQ_TYPE_NONE;
|
||||||
return ret;
|
girq->handler = handle_simple_irq;
|
||||||
}
|
girq->threaded = true;
|
||||||
gpiochip_set_nested_irqchip(&chip->gpio_chip,
|
girq->first = irq_base; /* FIXME: get rid of this */
|
||||||
&max732x_irq_chip,
|
|
||||||
client->irq);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -695,15 +695,15 @@ static int max732x_probe(struct i2c_client *client,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = devm_gpiochip_add_data(&client->dev, &chip->gpio_chip, chip);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
ret = max732x_irq_setup(chip, id);
|
ret = max732x_irq_setup(chip, id);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (pdata && pdata->setup) {
|
ret = devm_gpiochip_add_data(&client->dev, &chip->gpio_chip, chip);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (pdata->setup) {
|
||||||
ret = pdata->setup(client, chip->gpio_chip.base,
|
ret = pdata->setup(client, chip->gpio_chip.base,
|
||||||
chip->gpio_chip.ngpio, pdata->context);
|
chip->gpio_chip.ngpio, pdata->context);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
|
|
@ -19,8 +19,8 @@ struct max77620_gpio {
|
||||||
struct regmap *rmap;
|
struct regmap *rmap;
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
struct mutex buslock; /* irq_bus_lock */
|
struct mutex buslock; /* irq_bus_lock */
|
||||||
unsigned int irq_type[8];
|
unsigned int irq_type[MAX77620_GPIO_NR];
|
||||||
bool irq_enabled[8];
|
bool irq_enabled[MAX77620_GPIO_NR];
|
||||||
};
|
};
|
||||||
|
|
||||||
static irqreturn_t max77620_gpio_irqhandler(int irq, void *data)
|
static irqreturn_t max77620_gpio_irqhandler(int irq, void *data)
|
||||||
|
@ -38,7 +38,7 @@ static irqreturn_t max77620_gpio_irqhandler(int irq, void *data)
|
||||||
|
|
||||||
pending = value;
|
pending = value;
|
||||||
|
|
||||||
for_each_set_bit(offset, &pending, 8) {
|
for_each_set_bit(offset, &pending, MAX77620_GPIO_NR) {
|
||||||
unsigned int virq;
|
unsigned int virq;
|
||||||
|
|
||||||
virq = irq_find_mapping(gpio->gpio_chip.irq.domain, offset);
|
virq = irq_find_mapping(gpio->gpio_chip.irq.domain, offset);
|
||||||
|
@ -260,26 +260,54 @@ static int max77620_gpio_set_config(struct gpio_chip *gc, unsigned int offset,
|
||||||
return -ENOTSUPP;
|
return -ENOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int max77620_gpio_irq_init_hw(struct gpio_chip *gc)
|
||||||
|
{
|
||||||
|
struct max77620_gpio *gpio = gpiochip_get_data(gc);
|
||||||
|
unsigned int i;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GPIO interrupts may be left ON after bootloader, hence let's
|
||||||
|
* pre-initialize hardware to the expected state by disabling all
|
||||||
|
* the interrupts.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < MAX77620_GPIO_NR; i++) {
|
||||||
|
err = regmap_update_bits(gpio->rmap, GPIO_REG_ADDR(i),
|
||||||
|
MAX77620_CNFG_GPIO_INT_MASK, 0);
|
||||||
|
if (err < 0) {
|
||||||
|
dev_err(gpio->dev,
|
||||||
|
"failed to disable interrupt: %d\n", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int max77620_gpio_probe(struct platform_device *pdev)
|
static int max77620_gpio_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct max77620_chip *chip = dev_get_drvdata(pdev->dev.parent);
|
struct max77620_chip *chip = dev_get_drvdata(pdev->dev.parent);
|
||||||
struct max77620_gpio *mgpio;
|
struct max77620_gpio *mgpio;
|
||||||
int gpio_irq;
|
struct gpio_irq_chip *girq;
|
||||||
|
unsigned int gpio_irq;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
gpio_irq = platform_get_irq(pdev, 0);
|
ret = platform_get_irq(pdev, 0);
|
||||||
if (gpio_irq <= 0)
|
if (ret < 0)
|
||||||
return -ENODEV;
|
return ret;
|
||||||
|
|
||||||
|
gpio_irq = ret;
|
||||||
|
|
||||||
mgpio = devm_kzalloc(&pdev->dev, sizeof(*mgpio), GFP_KERNEL);
|
mgpio = devm_kzalloc(&pdev->dev, sizeof(*mgpio), GFP_KERNEL);
|
||||||
if (!mgpio)
|
if (!mgpio)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
mutex_init(&mgpio->buslock);
|
||||||
mgpio->rmap = chip->rmap;
|
mgpio->rmap = chip->rmap;
|
||||||
mgpio->dev = &pdev->dev;
|
mgpio->dev = &pdev->dev;
|
||||||
|
|
||||||
mgpio->gpio_chip.label = pdev->name;
|
mgpio->gpio_chip.label = pdev->name;
|
||||||
mgpio->gpio_chip.parent = &pdev->dev;
|
mgpio->gpio_chip.parent = pdev->dev.parent;
|
||||||
mgpio->gpio_chip.direction_input = max77620_gpio_dir_input;
|
mgpio->gpio_chip.direction_input = max77620_gpio_dir_input;
|
||||||
mgpio->gpio_chip.get = max77620_gpio_get;
|
mgpio->gpio_chip.get = max77620_gpio_get;
|
||||||
mgpio->gpio_chip.direction_output = max77620_gpio_dir_output;
|
mgpio->gpio_chip.direction_output = max77620_gpio_dir_output;
|
||||||
|
@ -288,9 +316,17 @@ static int max77620_gpio_probe(struct platform_device *pdev)
|
||||||
mgpio->gpio_chip.ngpio = MAX77620_GPIO_NR;
|
mgpio->gpio_chip.ngpio = MAX77620_GPIO_NR;
|
||||||
mgpio->gpio_chip.can_sleep = 1;
|
mgpio->gpio_chip.can_sleep = 1;
|
||||||
mgpio->gpio_chip.base = -1;
|
mgpio->gpio_chip.base = -1;
|
||||||
#ifdef CONFIG_OF_GPIO
|
|
||||||
mgpio->gpio_chip.of_node = pdev->dev.parent->of_node;
|
girq = &mgpio->gpio_chip.irq;
|
||||||
#endif
|
girq->chip = &max77620_gpio_irqchip;
|
||||||
|
/* This will let us handle the parent IRQ in the driver */
|
||||||
|
girq->parent_handler = NULL;
|
||||||
|
girq->num_parents = 0;
|
||||||
|
girq->parents = NULL;
|
||||||
|
girq->default_type = IRQ_TYPE_NONE;
|
||||||
|
girq->handler = handle_edge_irq;
|
||||||
|
girq->init_hw = max77620_gpio_irq_init_hw,
|
||||||
|
girq->threaded = true;
|
||||||
|
|
||||||
platform_set_drvdata(pdev, mgpio);
|
platform_set_drvdata(pdev, mgpio);
|
||||||
|
|
||||||
|
@ -300,21 +336,14 @@ static int max77620_gpio_probe(struct platform_device *pdev)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_init(&mgpio->buslock);
|
ret = devm_request_threaded_irq(&pdev->dev, gpio_irq, NULL,
|
||||||
|
max77620_gpio_irqhandler, IRQF_ONESHOT,
|
||||||
gpiochip_irqchip_add_nested(&mgpio->gpio_chip, &max77620_gpio_irqchip,
|
"max77620-gpio", mgpio);
|
||||||
0, handle_edge_irq, IRQ_TYPE_NONE);
|
|
||||||
|
|
||||||
ret = request_threaded_irq(gpio_irq, NULL, max77620_gpio_irqhandler,
|
|
||||||
IRQF_ONESHOT, "max77620-gpio", mgpio);
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(&pdev->dev, "failed to request IRQ: %d\n", ret);
|
dev_err(&pdev->dev, "failed to request IRQ: %d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
gpiochip_set_nested_irqchip(&mgpio->gpio_chip, &max77620_gpio_irqchip,
|
|
||||||
gpio_irq);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ struct ioh_regs {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct ioh_gpio_reg_data - The register store data.
|
* struct ioh_gpio_reg_data - The register store data.
|
||||||
* @ien_reg To store contents of interrupt enable register.
|
* @ien_reg: To store contents of interrupt enable register.
|
||||||
* @imask_reg: To store contents of interrupt mask regist
|
* @imask_reg: To store contents of interrupt mask regist
|
||||||
* @po_reg: To store contents of PO register.
|
* @po_reg: To store contents of PO register.
|
||||||
* @pm_reg: To store contents of PM register.
|
* @pm_reg: To store contents of PM register.
|
||||||
|
|
|
@ -127,7 +127,7 @@ static int mlxbf_gpio_resume(struct platform_device *pdev)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const struct acpi_device_id mlxbf_gpio_acpi_match[] = {
|
static const struct acpi_device_id __maybe_unused mlxbf_gpio_acpi_match[] = {
|
||||||
{ "MLNXBF02", 0 },
|
{ "MLNXBF02", 0 },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
|
@ -149,6 +149,8 @@ static int mlxbf2_gpio_lock_acquire(struct mlxbf2_gpio_context *gs)
|
||||||
* Release the YU arm_gpio_lock after changing the direction mode.
|
* Release the YU arm_gpio_lock after changing the direction mode.
|
||||||
*/
|
*/
|
||||||
static void mlxbf2_gpio_lock_release(struct mlxbf2_gpio_context *gs)
|
static void mlxbf2_gpio_lock_release(struct mlxbf2_gpio_context *gs)
|
||||||
|
__releases(&gs->gc.bgpio_lock)
|
||||||
|
__releases(yu_arm_gpio_lock_param.lock)
|
||||||
{
|
{
|
||||||
writel(YU_ARM_GPIO_LOCK_RELEASE, yu_arm_gpio_lock_param.io);
|
writel(YU_ARM_GPIO_LOCK_RELEASE, yu_arm_gpio_lock_param.io);
|
||||||
spin_unlock(&gs->gc.bgpio_lock);
|
spin_unlock(&gs->gc.bgpio_lock);
|
||||||
|
@ -309,7 +311,7 @@ static int mlxbf2_gpio_resume(struct platform_device *pdev)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const struct acpi_device_id mlxbf2_gpio_acpi_match[] = {
|
static const struct acpi_device_id __maybe_unused mlxbf2_gpio_acpi_match[] = {
|
||||||
{ "MLNXBF22", 0 },
|
{ "MLNXBF22", 0 },
|
||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
|
|
|
@ -195,8 +195,7 @@ static int bgpio_get_multiple_be(struct gpio_chip *gc, unsigned long *mask,
|
||||||
*bits &= ~*mask;
|
*bits &= ~*mask;
|
||||||
|
|
||||||
/* Create a mirrored mask */
|
/* Create a mirrored mask */
|
||||||
bit = -1;
|
for_each_set_bit(bit, mask, gc->ngpio)
|
||||||
while ((bit = find_next_bit(mask, gc->ngpio, bit + 1)) < gc->ngpio)
|
|
||||||
readmask |= bgpio_line2mask(gc, bit);
|
readmask |= bgpio_line2mask(gc, bit);
|
||||||
|
|
||||||
/* Read the register */
|
/* Read the register */
|
||||||
|
@ -206,8 +205,7 @@ static int bgpio_get_multiple_be(struct gpio_chip *gc, unsigned long *mask,
|
||||||
* Mirror the result into the "bits" result, this will give line 0
|
* Mirror the result into the "bits" result, this will give line 0
|
||||||
* in bit 0 ... line 31 in bit 31 for a 32bit register.
|
* in bit 0 ... line 31 in bit 31 for a 32bit register.
|
||||||
*/
|
*/
|
||||||
bit = -1;
|
for_each_set_bit(bit, &val, gc->ngpio)
|
||||||
while ((bit = find_next_bit(&val, gc->ngpio, bit + 1)) < gc->ngpio)
|
|
||||||
*bits |= bgpio_line2mask(gc, bit);
|
*bits |= bgpio_line2mask(gc, bit);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -272,15 +270,11 @@ static void bgpio_multiple_get_masks(struct gpio_chip *gc,
|
||||||
*set_mask = 0;
|
*set_mask = 0;
|
||||||
*clear_mask = 0;
|
*clear_mask = 0;
|
||||||
|
|
||||||
for (i = 0; i < gc->bgpio_bits; i++) {
|
for_each_set_bit(i, mask, gc->bgpio_bits) {
|
||||||
if (*mask == 0)
|
if (test_bit(i, bits))
|
||||||
break;
|
*set_mask |= bgpio_line2mask(gc, i);
|
||||||
if (__test_and_clear_bit(i, mask)) {
|
else
|
||||||
if (test_bit(i, bits))
|
*clear_mask |= bgpio_line2mask(gc, i);
|
||||||
*set_mask |= bgpio_line2mask(gc, i);
|
|
||||||
else
|
|
||||||
*clear_mask |= bgpio_line2mask(gc, i);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -417,7 +417,7 @@ static int mpc8xxx_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
ret = devm_request_irq(&pdev->dev, mpc8xxx_gc->irqn,
|
ret = devm_request_irq(&pdev->dev, mpc8xxx_gc->irqn,
|
||||||
mpc8xxx_gpio_irq_cascade,
|
mpc8xxx_gpio_irq_cascade,
|
||||||
IRQF_NO_THREAD | IRQF_SHARED, "gpio-cascade",
|
IRQF_SHARED, "gpio-cascade",
|
||||||
mpc8xxx_gc);
|
mpc8xxx_gc);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&pdev->dev, "%s: failed to devm_request_irq(%d), ret = %d\n",
|
dev_err(&pdev->dev, "%s: failed to devm_request_irq(%d), ret = %d\n",
|
||||||
|
|
|
@ -846,6 +846,7 @@ static void mvebu_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
|
||||||
{
|
{
|
||||||
struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip);
|
struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip);
|
||||||
u32 out, io_conf, blink, in_pol, data_in, cause, edg_msk, lvl_msk;
|
u32 out, io_conf, blink, in_pol, data_in, cause, edg_msk, lvl_msk;
|
||||||
|
const char *label;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
regmap_read(mvchip->regs, GPIO_OUT_OFF + mvchip->offset, &out);
|
regmap_read(mvchip->regs, GPIO_OUT_OFF + mvchip->offset, &out);
|
||||||
|
@ -857,15 +858,10 @@ static void mvebu_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
|
||||||
edg_msk = mvebu_gpio_read_edge_mask(mvchip);
|
edg_msk = mvebu_gpio_read_edge_mask(mvchip);
|
||||||
lvl_msk = mvebu_gpio_read_level_mask(mvchip);
|
lvl_msk = mvebu_gpio_read_level_mask(mvchip);
|
||||||
|
|
||||||
for (i = 0; i < chip->ngpio; i++) {
|
for_each_requested_gpio(chip, i, label) {
|
||||||
const char *label;
|
|
||||||
u32 msk;
|
u32 msk;
|
||||||
bool is_out;
|
bool is_out;
|
||||||
|
|
||||||
label = gpiochip_is_requested(chip, i);
|
|
||||||
if (!label)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
msk = BIT(i);
|
msk = BIT(i);
|
||||||
is_out = !(io_conf & msk);
|
is_out = !(io_conf & msk);
|
||||||
|
|
||||||
|
|
|
@ -60,6 +60,7 @@ struct gpio_bank {
|
||||||
struct clk *dbck;
|
struct clk *dbck;
|
||||||
struct notifier_block nb;
|
struct notifier_block nb;
|
||||||
unsigned int is_suspended:1;
|
unsigned int is_suspended:1;
|
||||||
|
unsigned int needs_resume:1;
|
||||||
u32 mod_usage;
|
u32 mod_usage;
|
||||||
u32 irq_usage;
|
u32 irq_usage;
|
||||||
u32 dbck_enable_mask;
|
u32 dbck_enable_mask;
|
||||||
|
@ -896,12 +897,23 @@ static int omap_gpio_set_config(struct gpio_chip *chip, unsigned offset,
|
||||||
unsigned long config)
|
unsigned long config)
|
||||||
{
|
{
|
||||||
u32 debounce;
|
u32 debounce;
|
||||||
|
int ret = -ENOTSUPP;
|
||||||
|
|
||||||
if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
|
switch (pinconf_to_config_param(config)) {
|
||||||
return -ENOTSUPP;
|
case PIN_CONFIG_BIAS_DISABLE:
|
||||||
|
case PIN_CONFIG_BIAS_PULL_UP:
|
||||||
|
case PIN_CONFIG_BIAS_PULL_DOWN:
|
||||||
|
ret = gpiochip_generic_config(chip, offset, config);
|
||||||
|
break;
|
||||||
|
case PIN_CONFIG_INPUT_DEBOUNCE:
|
||||||
|
debounce = pinconf_to_config_argument(config);
|
||||||
|
ret = omap_gpio_debounce(chip, offset, debounce);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
debounce = pinconf_to_config_argument(config);
|
return ret;
|
||||||
return omap_gpio_debounce(chip, offset, debounce);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void omap_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
static void omap_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
||||||
|
@ -1504,9 +1516,34 @@ static int __maybe_unused omap_gpio_runtime_resume(struct device *dev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int omap_gpio_suspend(struct device *dev)
|
||||||
|
{
|
||||||
|
struct gpio_bank *bank = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
if (bank->is_suspended)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
bank->needs_resume = 1;
|
||||||
|
|
||||||
|
return omap_gpio_runtime_suspend(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int omap_gpio_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
struct gpio_bank *bank = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
if (!bank->needs_resume)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
bank->needs_resume = 0;
|
||||||
|
|
||||||
|
return omap_gpio_runtime_resume(dev);
|
||||||
|
}
|
||||||
|
|
||||||
static const struct dev_pm_ops gpio_pm_ops = {
|
static const struct dev_pm_ops gpio_pm_ops = {
|
||||||
SET_RUNTIME_PM_OPS(omap_gpio_runtime_suspend, omap_gpio_runtime_resume,
|
SET_RUNTIME_PM_OPS(omap_gpio_runtime_suspend, omap_gpio_runtime_resume,
|
||||||
NULL)
|
NULL)
|
||||||
|
SET_LATE_SYSTEM_SLEEP_PM_OPS(omap_gpio_suspend, omap_gpio_resume)
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct platform_driver omap_gpio_driver = {
|
static struct platform_driver omap_gpio_driver = {
|
||||||
|
|
|
@ -89,6 +89,7 @@ static const struct i2c_device_id pca953x_id[] = {
|
||||||
|
|
||||||
{ "pcal6416", 16 | PCA953X_TYPE | PCA_LATCH_INT, },
|
{ "pcal6416", 16 | PCA953X_TYPE | PCA_LATCH_INT, },
|
||||||
{ "pcal6524", 24 | PCA953X_TYPE | PCA_LATCH_INT, },
|
{ "pcal6524", 24 | PCA953X_TYPE | PCA_LATCH_INT, },
|
||||||
|
{ "pcal9535", 16 | PCA953X_TYPE | PCA_LATCH_INT, },
|
||||||
{ "pcal9555a", 16 | PCA953X_TYPE | PCA_LATCH_INT, },
|
{ "pcal9555a", 16 | PCA953X_TYPE | PCA_LATCH_INT, },
|
||||||
|
|
||||||
{ "max7310", 8 | PCA953X_TYPE, },
|
{ "max7310", 8 | PCA953X_TYPE, },
|
||||||
|
@ -833,6 +834,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, int irq_base)
|
||||||
struct irq_chip *irq_chip = &chip->irq_chip;
|
struct irq_chip *irq_chip = &chip->irq_chip;
|
||||||
DECLARE_BITMAP(reg_direction, MAX_LINE);
|
DECLARE_BITMAP(reg_direction, MAX_LINE);
|
||||||
DECLARE_BITMAP(irq_stat, MAX_LINE);
|
DECLARE_BITMAP(irq_stat, MAX_LINE);
|
||||||
|
struct gpio_irq_chip *girq;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (dmi_first_match(pca953x_dmi_acpi_irq_info)) {
|
if (dmi_first_match(pca953x_dmi_acpi_irq_info)) {
|
||||||
|
@ -863,6 +865,26 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, int irq_base)
|
||||||
bitmap_and(chip->irq_stat, irq_stat, reg_direction, chip->gpio_chip.ngpio);
|
bitmap_and(chip->irq_stat, irq_stat, reg_direction, chip->gpio_chip.ngpio);
|
||||||
mutex_init(&chip->irq_lock);
|
mutex_init(&chip->irq_lock);
|
||||||
|
|
||||||
|
irq_chip->name = dev_name(&client->dev);
|
||||||
|
irq_chip->irq_mask = pca953x_irq_mask;
|
||||||
|
irq_chip->irq_unmask = pca953x_irq_unmask;
|
||||||
|
irq_chip->irq_set_wake = pca953x_irq_set_wake;
|
||||||
|
irq_chip->irq_bus_lock = pca953x_irq_bus_lock;
|
||||||
|
irq_chip->irq_bus_sync_unlock = pca953x_irq_bus_sync_unlock;
|
||||||
|
irq_chip->irq_set_type = pca953x_irq_set_type;
|
||||||
|
irq_chip->irq_shutdown = pca953x_irq_shutdown;
|
||||||
|
|
||||||
|
girq = &chip->gpio_chip.irq;
|
||||||
|
girq->chip = irq_chip;
|
||||||
|
/* This will let us handle the parent IRQ in the driver */
|
||||||
|
girq->parent_handler = NULL;
|
||||||
|
girq->num_parents = 0;
|
||||||
|
girq->parents = NULL;
|
||||||
|
girq->default_type = IRQ_TYPE_NONE;
|
||||||
|
girq->handler = handle_simple_irq;
|
||||||
|
girq->threaded = true;
|
||||||
|
girq->first = irq_base; /* FIXME: get rid of this */
|
||||||
|
|
||||||
ret = devm_request_threaded_irq(&client->dev, client->irq,
|
ret = devm_request_threaded_irq(&client->dev, client->irq,
|
||||||
NULL, pca953x_irq_handler,
|
NULL, pca953x_irq_handler,
|
||||||
IRQF_ONESHOT | IRQF_SHARED,
|
IRQF_ONESHOT | IRQF_SHARED,
|
||||||
|
@ -873,26 +895,6 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, int irq_base)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
irq_chip->name = dev_name(&chip->client->dev);
|
|
||||||
irq_chip->irq_mask = pca953x_irq_mask;
|
|
||||||
irq_chip->irq_unmask = pca953x_irq_unmask;
|
|
||||||
irq_chip->irq_set_wake = pca953x_irq_set_wake;
|
|
||||||
irq_chip->irq_bus_lock = pca953x_irq_bus_lock;
|
|
||||||
irq_chip->irq_bus_sync_unlock = pca953x_irq_bus_sync_unlock;
|
|
||||||
irq_chip->irq_set_type = pca953x_irq_set_type;
|
|
||||||
irq_chip->irq_shutdown = pca953x_irq_shutdown;
|
|
||||||
|
|
||||||
ret = gpiochip_irqchip_add_nested(&chip->gpio_chip, irq_chip,
|
|
||||||
irq_base, handle_simple_irq,
|
|
||||||
IRQ_TYPE_NONE);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(&client->dev,
|
|
||||||
"could not connect irqchip to gpiochip\n");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
gpiochip_set_nested_irqchip(&chip->gpio_chip, irq_chip, client->irq);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1079,11 +1081,11 @@ static int pca953x_probe(struct i2c_client *client,
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_exit;
|
goto err_exit;
|
||||||
|
|
||||||
ret = devm_gpiochip_add_data(&client->dev, &chip->gpio_chip, chip);
|
ret = pca953x_irq_setup(chip, irq_base);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_exit;
|
goto err_exit;
|
||||||
|
|
||||||
ret = pca953x_irq_setup(chip, irq_base);
|
ret = devm_gpiochip_add_data(&client->dev, &chip->gpio_chip, chip);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_exit;
|
goto err_exit;
|
||||||
|
|
||||||
|
@ -1234,6 +1236,7 @@ static const struct of_device_id pca953x_dt_ids[] = {
|
||||||
|
|
||||||
{ .compatible = "nxp,pcal6416", .data = OF_953X(16, PCA_LATCH_INT), },
|
{ .compatible = "nxp,pcal6416", .data = OF_953X(16, PCA_LATCH_INT), },
|
||||||
{ .compatible = "nxp,pcal6524", .data = OF_953X(24, PCA_LATCH_INT), },
|
{ .compatible = "nxp,pcal6524", .data = OF_953X(24, PCA_LATCH_INT), },
|
||||||
|
{ .compatible = "nxp,pcal9535", .data = OF_953X(16, PCA_LATCH_INT), },
|
||||||
{ .compatible = "nxp,pcal9555a", .data = OF_953X(16, PCA_LATCH_INT), },
|
{ .compatible = "nxp,pcal9555a", .data = OF_953X(16, PCA_LATCH_INT), },
|
||||||
|
|
||||||
{ .compatible = "maxim,max7310", .data = OF_953X( 8, 0), },
|
{ .compatible = "maxim,max7310", .data = OF_953X( 8, 0), },
|
||||||
|
|
|
@ -0,0 +1,146 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
/*
|
||||||
|
* Driver for PCA9570 I2C GPO expander
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 Sungbo Eo <mans0n@gorani.run>
|
||||||
|
*
|
||||||
|
* Based on gpio-tpic2810.c
|
||||||
|
* Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
|
||||||
|
* Andrew F. Davis <afd@ti.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/gpio/driver.h>
|
||||||
|
#include <linux/i2c.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/mutex.h>
|
||||||
|
#include <linux/property.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct pca9570 - GPIO driver data
|
||||||
|
* @chip: GPIO controller chip
|
||||||
|
* @lock: Protects write sequences
|
||||||
|
* @out: Buffer for device register
|
||||||
|
*/
|
||||||
|
struct pca9570 {
|
||||||
|
struct gpio_chip chip;
|
||||||
|
struct mutex lock;
|
||||||
|
u8 out;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int pca9570_read(struct pca9570 *gpio, u8 *value)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = to_i2c_client(gpio->chip.parent);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = i2c_smbus_read_byte(client);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
*value = ret;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pca9570_write(struct pca9570 *gpio, u8 value)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = to_i2c_client(gpio->chip.parent);
|
||||||
|
|
||||||
|
return i2c_smbus_write_byte(client, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pca9570_get_direction(struct gpio_chip *chip,
|
||||||
|
unsigned offset)
|
||||||
|
{
|
||||||
|
/* This device always output */
|
||||||
|
return GPIO_LINE_DIRECTION_OUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pca9570_get(struct gpio_chip *chip, unsigned offset)
|
||||||
|
{
|
||||||
|
struct pca9570 *gpio = gpiochip_get_data(chip);
|
||||||
|
u8 buffer;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = pca9570_read(gpio, &buffer);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return !!(buffer & BIT(offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pca9570_set(struct gpio_chip *chip, unsigned offset, int value)
|
||||||
|
{
|
||||||
|
struct pca9570 *gpio = gpiochip_get_data(chip);
|
||||||
|
u8 buffer;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
mutex_lock(&gpio->lock);
|
||||||
|
|
||||||
|
buffer = gpio->out;
|
||||||
|
if (value)
|
||||||
|
buffer |= BIT(offset);
|
||||||
|
else
|
||||||
|
buffer &= ~BIT(offset);
|
||||||
|
|
||||||
|
ret = pca9570_write(gpio, buffer);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
gpio->out = buffer;
|
||||||
|
|
||||||
|
out:
|
||||||
|
mutex_unlock(&gpio->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pca9570_probe(struct i2c_client *client)
|
||||||
|
{
|
||||||
|
struct pca9570 *gpio;
|
||||||
|
|
||||||
|
gpio = devm_kzalloc(&client->dev, sizeof(*gpio), GFP_KERNEL);
|
||||||
|
if (!gpio)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
gpio->chip.label = client->name;
|
||||||
|
gpio->chip.parent = &client->dev;
|
||||||
|
gpio->chip.owner = THIS_MODULE;
|
||||||
|
gpio->chip.get_direction = pca9570_get_direction;
|
||||||
|
gpio->chip.get = pca9570_get;
|
||||||
|
gpio->chip.set = pca9570_set;
|
||||||
|
gpio->chip.base = -1;
|
||||||
|
gpio->chip.ngpio = (uintptr_t)device_get_match_data(&client->dev);
|
||||||
|
gpio->chip.can_sleep = true;
|
||||||
|
|
||||||
|
mutex_init(&gpio->lock);
|
||||||
|
|
||||||
|
/* Read the current output level */
|
||||||
|
pca9570_read(gpio, &gpio->out);
|
||||||
|
|
||||||
|
i2c_set_clientdata(client, gpio);
|
||||||
|
|
||||||
|
return devm_gpiochip_add_data(&client->dev, &gpio->chip, gpio);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct i2c_device_id pca9570_id_table[] = {
|
||||||
|
{ "pca9570", 4 },
|
||||||
|
{ /* sentinel */ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, pca9570_id_table);
|
||||||
|
|
||||||
|
static const struct of_device_id pca9570_of_match_table[] = {
|
||||||
|
{ .compatible = "nxp,pca9570", .data = (void *)4 },
|
||||||
|
{ /* sentinel */ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, pca9570_of_match_table);
|
||||||
|
|
||||||
|
static struct i2c_driver pca9570_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "pca9570",
|
||||||
|
.of_match_table = pca9570_of_match_table,
|
||||||
|
},
|
||||||
|
.probe_new = pca9570_probe,
|
||||||
|
.id_table = pca9570_id_table,
|
||||||
|
};
|
||||||
|
module_i2c_driver(pca9570_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Sungbo Eo <mans0n@gorani.run>");
|
||||||
|
MODULE_DESCRIPTION("GPIO expander driver for PCA9570");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
|
@ -334,29 +334,19 @@ static int pcf857x_probe(struct i2c_client *client,
|
||||||
gpio->out = ~n_latch;
|
gpio->out = ~n_latch;
|
||||||
gpio->status = gpio->out;
|
gpio->status = gpio->out;
|
||||||
|
|
||||||
status = devm_gpiochip_add_data(&client->dev, &gpio->chip, gpio);
|
|
||||||
if (status < 0)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
/* Enable irqchip if we have an interrupt */
|
/* Enable irqchip if we have an interrupt */
|
||||||
if (client->irq) {
|
if (client->irq) {
|
||||||
gpio->irqchip.name = "pcf857x",
|
struct gpio_irq_chip *girq;
|
||||||
gpio->irqchip.irq_enable = pcf857x_irq_enable,
|
|
||||||
gpio->irqchip.irq_disable = pcf857x_irq_disable,
|
gpio->irqchip.name = "pcf857x";
|
||||||
gpio->irqchip.irq_ack = noop,
|
gpio->irqchip.irq_enable = pcf857x_irq_enable;
|
||||||
gpio->irqchip.irq_mask = noop,
|
gpio->irqchip.irq_disable = pcf857x_irq_disable;
|
||||||
gpio->irqchip.irq_unmask = noop,
|
gpio->irqchip.irq_ack = noop;
|
||||||
gpio->irqchip.irq_set_wake = pcf857x_irq_set_wake,
|
gpio->irqchip.irq_mask = noop;
|
||||||
gpio->irqchip.irq_bus_lock = pcf857x_irq_bus_lock,
|
gpio->irqchip.irq_unmask = noop;
|
||||||
gpio->irqchip.irq_bus_sync_unlock = pcf857x_irq_bus_sync_unlock,
|
gpio->irqchip.irq_set_wake = pcf857x_irq_set_wake;
|
||||||
status = gpiochip_irqchip_add_nested(&gpio->chip,
|
gpio->irqchip.irq_bus_lock = pcf857x_irq_bus_lock;
|
||||||
&gpio->irqchip,
|
gpio->irqchip.irq_bus_sync_unlock = pcf857x_irq_bus_sync_unlock;
|
||||||
0, handle_level_irq,
|
|
||||||
IRQ_TYPE_NONE);
|
|
||||||
if (status) {
|
|
||||||
dev_err(&client->dev, "cannot add irqchip\n");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = devm_request_threaded_irq(&client->dev, client->irq,
|
status = devm_request_threaded_irq(&client->dev, client->irq,
|
||||||
NULL, pcf857x_irq, IRQF_ONESHOT |
|
NULL, pcf857x_irq, IRQF_ONESHOT |
|
||||||
|
@ -365,10 +355,21 @@ static int pcf857x_probe(struct i2c_client *client,
|
||||||
if (status)
|
if (status)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
gpiochip_set_nested_irqchip(&gpio->chip, &gpio->irqchip,
|
girq = &gpio->chip.irq;
|
||||||
client->irq);
|
girq->chip = &gpio->irqchip;
|
||||||
|
/* This will let us handle the parent IRQ in the driver */
|
||||||
|
girq->parent_handler = NULL;
|
||||||
|
girq->num_parents = 0;
|
||||||
|
girq->parents = NULL;
|
||||||
|
girq->default_type = IRQ_TYPE_NONE;
|
||||||
|
girq->handler = handle_level_irq;
|
||||||
|
girq->threaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
status = devm_gpiochip_add_data(&client->dev, &gpio->chip, gpio);
|
||||||
|
if (status < 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
/* Let platform code set up the GPIOs and their users.
|
/* Let platform code set up the GPIOs and their users.
|
||||||
* Now is the first time anyone could use them.
|
* Now is the first time anyone could use them.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -95,7 +95,7 @@ struct pch_gpio {
|
||||||
spinlock_t spinlock;
|
spinlock_t spinlock;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void pch_gpio_set(struct gpio_chip *gpio, unsigned nr, int val)
|
static void pch_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val)
|
||||||
{
|
{
|
||||||
u32 reg_val;
|
u32 reg_val;
|
||||||
struct pch_gpio *chip = gpiochip_get_data(gpio);
|
struct pch_gpio *chip = gpiochip_get_data(gpio);
|
||||||
|
@ -112,14 +112,14 @@ static void pch_gpio_set(struct gpio_chip *gpio, unsigned nr, int val)
|
||||||
spin_unlock_irqrestore(&chip->spinlock, flags);
|
spin_unlock_irqrestore(&chip->spinlock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pch_gpio_get(struct gpio_chip *gpio, unsigned nr)
|
static int pch_gpio_get(struct gpio_chip *gpio, unsigned int nr)
|
||||||
{
|
{
|
||||||
struct pch_gpio *chip = gpiochip_get_data(gpio);
|
struct pch_gpio *chip = gpiochip_get_data(gpio);
|
||||||
|
|
||||||
return !!(ioread32(&chip->reg->pi) & BIT(nr));
|
return !!(ioread32(&chip->reg->pi) & BIT(nr));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
|
static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned int nr,
|
||||||
int val)
|
int val)
|
||||||
{
|
{
|
||||||
struct pch_gpio *chip = gpiochip_get_data(gpio);
|
struct pch_gpio *chip = gpiochip_get_data(gpio);
|
||||||
|
@ -146,7 +146,7 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pch_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
|
static int pch_gpio_direction_input(struct gpio_chip *gpio, unsigned int nr)
|
||||||
{
|
{
|
||||||
struct pch_gpio *chip = gpiochip_get_data(gpio);
|
struct pch_gpio *chip = gpiochip_get_data(gpio);
|
||||||
u32 pm;
|
u32 pm;
|
||||||
|
@ -196,9 +196,10 @@ static void __maybe_unused pch_gpio_restore_reg_conf(struct pch_gpio *chip)
|
||||||
iowrite32(chip->pch_gpio_reg.gpio_use_sel_reg, &chip->reg->gpio_use_sel);
|
iowrite32(chip->pch_gpio_reg.gpio_use_sel_reg, &chip->reg->gpio_use_sel);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pch_gpio_to_irq(struct gpio_chip *gpio, unsigned offset)
|
static int pch_gpio_to_irq(struct gpio_chip *gpio, unsigned int offset)
|
||||||
{
|
{
|
||||||
struct pch_gpio *chip = gpiochip_get_data(gpio);
|
struct pch_gpio *chip = gpiochip_get_data(gpio);
|
||||||
|
|
||||||
return chip->irq_base + offset;
|
return chip->irq_base + offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,9 +305,10 @@ static irqreturn_t pch_gpio_handler(int irq, void *dev_id)
|
||||||
unsigned long reg_val = ioread32(&chip->reg->istatus);
|
unsigned long reg_val = ioread32(&chip->reg->istatus);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
dev_dbg(chip->dev, "irq=%d status=0x%lx\n", irq, reg_val);
|
dev_vdbg(chip->dev, "irq=%d status=0x%lx\n", irq, reg_val);
|
||||||
|
|
||||||
reg_val &= BIT(gpio_pins[chip->ioh]) - 1;
|
reg_val &= BIT(gpio_pins[chip->ioh]) - 1;
|
||||||
|
|
||||||
for_each_set_bit(i, ®_val, gpio_pins[chip->ioh])
|
for_each_set_bit(i, ®_val, gpio_pins[chip->ioh])
|
||||||
generic_handle_irq(chip->irq_base + i);
|
generic_handle_irq(chip->irq_base + i);
|
||||||
|
|
||||||
|
|
|
@ -280,6 +280,17 @@ static const char *idio_16_names[IDIO_16_NGPIO] = {
|
||||||
"IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15"
|
"IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int idio_16_irq_init_hw(struct gpio_chip *gc)
|
||||||
|
{
|
||||||
|
struct idio_16_gpio *const idio16gpio = gpiochip_get_data(gc);
|
||||||
|
|
||||||
|
/* Disable IRQ by default and clear any pending interrupt */
|
||||||
|
iowrite8(0, &idio16gpio->reg->irq_ctl);
|
||||||
|
iowrite8(0, &idio16gpio->reg->in0_7);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int idio_16_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
static int idio_16_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||||
{
|
{
|
||||||
struct device *const dev = &pdev->dev;
|
struct device *const dev = &pdev->dev;
|
||||||
|
@ -287,6 +298,7 @@ static int idio_16_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||||
int err;
|
int err;
|
||||||
const size_t pci_bar_index = 2;
|
const size_t pci_bar_index = 2;
|
||||||
const char *const name = pci_name(pdev);
|
const char *const name = pci_name(pdev);
|
||||||
|
struct gpio_irq_chip *girq;
|
||||||
|
|
||||||
idio16gpio = devm_kzalloc(dev, sizeof(*idio16gpio), GFP_KERNEL);
|
idio16gpio = devm_kzalloc(dev, sizeof(*idio16gpio), GFP_KERNEL);
|
||||||
if (!idio16gpio)
|
if (!idio16gpio)
|
||||||
|
@ -323,6 +335,16 @@ static int idio_16_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||||
idio16gpio->chip.set = idio_16_gpio_set;
|
idio16gpio->chip.set = idio_16_gpio_set;
|
||||||
idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;
|
idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;
|
||||||
|
|
||||||
|
girq = &idio16gpio->chip.irq;
|
||||||
|
girq->chip = &idio_16_irqchip;
|
||||||
|
/* This will let us handle the parent IRQ in the driver */
|
||||||
|
girq->parent_handler = NULL;
|
||||||
|
girq->num_parents = 0;
|
||||||
|
girq->parents = NULL;
|
||||||
|
girq->default_type = IRQ_TYPE_NONE;
|
||||||
|
girq->handler = handle_edge_irq;
|
||||||
|
girq->init_hw = idio_16_irq_init_hw;
|
||||||
|
|
||||||
raw_spin_lock_init(&idio16gpio->lock);
|
raw_spin_lock_init(&idio16gpio->lock);
|
||||||
|
|
||||||
err = devm_gpiochip_add_data(dev, &idio16gpio->chip, idio16gpio);
|
err = devm_gpiochip_add_data(dev, &idio16gpio->chip, idio16gpio);
|
||||||
|
@ -331,17 +353,6 @@ static int idio_16_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Disable IRQ by default and clear any pending interrupt */
|
|
||||||
iowrite8(0, &idio16gpio->reg->irq_ctl);
|
|
||||||
iowrite8(0, &idio16gpio->reg->in0_7);
|
|
||||||
|
|
||||||
err = gpiochip_irqchip_add(&idio16gpio->chip, &idio_16_irqchip, 0,
|
|
||||||
handle_edge_irq, IRQ_TYPE_NONE);
|
|
||||||
if (err) {
|
|
||||||
dev_err(dev, "Could not add irqchip (%d)\n", err);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = devm_request_irq(dev, pdev->irq, idio_16_irq_handler, IRQF_SHARED,
|
err = devm_request_irq(dev, pdev->irq, idio_16_irq_handler, IRQF_SHARED,
|
||||||
name, idio16gpio);
|
name, idio16gpio);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|
|
@ -457,6 +457,7 @@ static int idio_24_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||||
int err;
|
int err;
|
||||||
const size_t pci_bar_index = 2;
|
const size_t pci_bar_index = 2;
|
||||||
const char *const name = pci_name(pdev);
|
const char *const name = pci_name(pdev);
|
||||||
|
struct gpio_irq_chip *girq;
|
||||||
|
|
||||||
idio24gpio = devm_kzalloc(dev, sizeof(*idio24gpio), GFP_KERNEL);
|
idio24gpio = devm_kzalloc(dev, sizeof(*idio24gpio), GFP_KERNEL);
|
||||||
if (!idio24gpio)
|
if (!idio24gpio)
|
||||||
|
@ -490,6 +491,15 @@ static int idio_24_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||||
idio24gpio->chip.set = idio_24_gpio_set;
|
idio24gpio->chip.set = idio_24_gpio_set;
|
||||||
idio24gpio->chip.set_multiple = idio_24_gpio_set_multiple;
|
idio24gpio->chip.set_multiple = idio_24_gpio_set_multiple;
|
||||||
|
|
||||||
|
girq = &idio24gpio->chip.irq;
|
||||||
|
girq->chip = &idio_24_irqchip;
|
||||||
|
/* This will let us handle the parent IRQ in the driver */
|
||||||
|
girq->parent_handler = NULL;
|
||||||
|
girq->num_parents = 0;
|
||||||
|
girq->parents = NULL;
|
||||||
|
girq->default_type = IRQ_TYPE_NONE;
|
||||||
|
girq->handler = handle_edge_irq;
|
||||||
|
|
||||||
raw_spin_lock_init(&idio24gpio->lock);
|
raw_spin_lock_init(&idio24gpio->lock);
|
||||||
|
|
||||||
/* Software board reset */
|
/* Software board reset */
|
||||||
|
@ -501,13 +511,6 @@ static int idio_24_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = gpiochip_irqchip_add(&idio24gpio->chip, &idio_24_irqchip, 0,
|
|
||||||
handle_edge_irq, IRQ_TYPE_NONE);
|
|
||||||
if (err) {
|
|
||||||
dev_err(dev, "Could not add irqchip (%d)\n", err);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = devm_request_irq(dev, pdev->irq, idio_24_irq_handler, IRQF_SHARED,
|
err = devm_request_irq(dev, pdev->irq, idio_24_irq_handler, IRQF_SHARED,
|
||||||
name, idio24gpio);
|
name, idio24gpio);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|
|
@ -48,7 +48,7 @@ enum {
|
||||||
* struct sprd_pmic_eic - PMIC EIC controller
|
* struct sprd_pmic_eic - PMIC EIC controller
|
||||||
* @chip: the gpio_chip structure.
|
* @chip: the gpio_chip structure.
|
||||||
* @intc: the irq_chip structure.
|
* @intc: the irq_chip structure.
|
||||||
* @regmap: the regmap from the parent device.
|
* @map: the regmap from the parent device.
|
||||||
* @offset: the EIC controller's offset address of the PMIC.
|
* @offset: the EIC controller's offset address of the PMIC.
|
||||||
* @reg: the array to cache the EIC registers.
|
* @reg: the array to cache the EIC registers.
|
||||||
* @buslock: for bus lock/sync and unlock.
|
* @buslock: for bus lock/sync and unlock.
|
||||||
|
|
|
@ -438,6 +438,7 @@ static int gpio_rcar_probe(struct platform_device *pdev)
|
||||||
struct resource *irq;
|
struct resource *irq;
|
||||||
struct gpio_chip *gpio_chip;
|
struct gpio_chip *gpio_chip;
|
||||||
struct irq_chip *irq_chip;
|
struct irq_chip *irq_chip;
|
||||||
|
struct gpio_irq_chip *girq;
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
const char *name = dev_name(dev);
|
const char *name = dev_name(dev);
|
||||||
unsigned int npins;
|
unsigned int npins;
|
||||||
|
@ -496,19 +497,21 @@ static int gpio_rcar_probe(struct platform_device *pdev)
|
||||||
irq_chip->irq_set_wake = gpio_rcar_irq_set_wake;
|
irq_chip->irq_set_wake = gpio_rcar_irq_set_wake;
|
||||||
irq_chip->flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND;
|
irq_chip->flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND;
|
||||||
|
|
||||||
|
girq = &gpio_chip->irq;
|
||||||
|
girq->chip = irq_chip;
|
||||||
|
/* This will let us handle the parent IRQ in the driver */
|
||||||
|
girq->parent_handler = NULL;
|
||||||
|
girq->num_parents = 0;
|
||||||
|
girq->parents = NULL;
|
||||||
|
girq->default_type = IRQ_TYPE_NONE;
|
||||||
|
girq->handler = handle_level_irq;
|
||||||
|
|
||||||
ret = gpiochip_add_data(gpio_chip, p);
|
ret = gpiochip_add_data(gpio_chip, p);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "failed to add GPIO controller\n");
|
dev_err(dev, "failed to add GPIO controller\n");
|
||||||
goto err0;
|
goto err0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = gpiochip_irqchip_add(gpio_chip, irq_chip, 0, handle_level_irq,
|
|
||||||
IRQ_TYPE_NONE);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(dev, "cannot add irqchip\n");
|
|
||||||
goto err1;
|
|
||||||
}
|
|
||||||
|
|
||||||
p->irq_parent = irq->start;
|
p->irq_parent = irq->start;
|
||||||
if (devm_request_irq(dev, irq->start, gpio_rcar_irq_handler,
|
if (devm_request_irq(dev, irq->start, gpio_rcar_irq_handler,
|
||||||
IRQF_SHARED, name, p)) {
|
IRQF_SHARED, name, p)) {
|
||||||
|
|
|
@ -49,7 +49,7 @@ struct sama5d2_piobu {
|
||||||
struct regmap *regmap;
|
struct regmap *regmap;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* sama5d2_piobu_setup_pin() - prepares a pin for set_direction call
|
* sama5d2_piobu_setup_pin() - prepares a pin for set_direction call
|
||||||
*
|
*
|
||||||
* Do not consider pin for tamper detection (normal and backup modes)
|
* Do not consider pin for tamper detection (normal and backup modes)
|
||||||
|
@ -73,7 +73,7 @@ static int sama5d2_piobu_setup_pin(struct gpio_chip *chip, unsigned int pin)
|
||||||
return regmap_update_bits(piobu->regmap, PIOBU_WKPR, mask, 0);
|
return regmap_update_bits(piobu->regmap, PIOBU_WKPR, mask, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* sama5d2_piobu_write_value() - writes value & mask at the pin's PIOBU register
|
* sama5d2_piobu_write_value() - writes value & mask at the pin's PIOBU register
|
||||||
*/
|
*/
|
||||||
static int sama5d2_piobu_write_value(struct gpio_chip *chip, unsigned int pin,
|
static int sama5d2_piobu_write_value(struct gpio_chip *chip, unsigned int pin,
|
||||||
|
@ -88,7 +88,7 @@ static int sama5d2_piobu_write_value(struct gpio_chip *chip, unsigned int pin,
|
||||||
return regmap_update_bits(piobu->regmap, reg, mask, value);
|
return regmap_update_bits(piobu->regmap, reg, mask, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* sama5d2_piobu_read_value() - read the value with masking from the pin's PIOBU
|
* sama5d2_piobu_read_value() - read the value with masking from the pin's PIOBU
|
||||||
* register
|
* register
|
||||||
*/
|
*/
|
||||||
|
@ -108,7 +108,7 @@ static int sama5d2_piobu_read_value(struct gpio_chip *chip, unsigned int pin,
|
||||||
return val & mask;
|
return val & mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* sama5d2_piobu_get_direction() - gpiochip get_direction
|
* sama5d2_piobu_get_direction() - gpiochip get_direction
|
||||||
*/
|
*/
|
||||||
static int sama5d2_piobu_get_direction(struct gpio_chip *chip,
|
static int sama5d2_piobu_get_direction(struct gpio_chip *chip,
|
||||||
|
@ -123,7 +123,7 @@ static int sama5d2_piobu_get_direction(struct gpio_chip *chip,
|
||||||
GPIO_LINE_DIRECTION_OUT;
|
GPIO_LINE_DIRECTION_OUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* sama5d2_piobu_direction_input() - gpiochip direction_input
|
* sama5d2_piobu_direction_input() - gpiochip direction_input
|
||||||
*/
|
*/
|
||||||
static int sama5d2_piobu_direction_input(struct gpio_chip *chip,
|
static int sama5d2_piobu_direction_input(struct gpio_chip *chip,
|
||||||
|
@ -132,7 +132,7 @@ static int sama5d2_piobu_direction_input(struct gpio_chip *chip,
|
||||||
return sama5d2_piobu_write_value(chip, pin, PIOBU_DIRECTION, PIOBU_IN);
|
return sama5d2_piobu_write_value(chip, pin, PIOBU_DIRECTION, PIOBU_IN);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* sama5d2_piobu_direction_output() - gpiochip direction_output
|
* sama5d2_piobu_direction_output() - gpiochip direction_output
|
||||||
*/
|
*/
|
||||||
static int sama5d2_piobu_direction_output(struct gpio_chip *chip,
|
static int sama5d2_piobu_direction_output(struct gpio_chip *chip,
|
||||||
|
@ -147,7 +147,7 @@ static int sama5d2_piobu_direction_output(struct gpio_chip *chip,
|
||||||
val);
|
val);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* sama5d2_piobu_get() - gpiochip get
|
* sama5d2_piobu_get() - gpiochip get
|
||||||
*/
|
*/
|
||||||
static int sama5d2_piobu_get(struct gpio_chip *chip, unsigned int pin)
|
static int sama5d2_piobu_get(struct gpio_chip *chip, unsigned int pin)
|
||||||
|
@ -166,7 +166,7 @@ static int sama5d2_piobu_get(struct gpio_chip *chip, unsigned int pin)
|
||||||
return !!ret;
|
return !!ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* sama5d2_piobu_set() - gpiochip set
|
* sama5d2_piobu_set() - gpiochip set
|
||||||
*/
|
*/
|
||||||
static void sama5d2_piobu_set(struct gpio_chip *chip, unsigned int pin,
|
static void sama5d2_piobu_set(struct gpio_chip *chip, unsigned int pin,
|
||||||
|
|
|
@ -26,10 +26,10 @@ struct sch_gpio {
|
||||||
unsigned short resume_base;
|
unsigned short resume_base;
|
||||||
};
|
};
|
||||||
|
|
||||||
static unsigned sch_gpio_offset(struct sch_gpio *sch, unsigned gpio,
|
static unsigned int sch_gpio_offset(struct sch_gpio *sch, unsigned int gpio,
|
||||||
unsigned reg)
|
unsigned int reg)
|
||||||
{
|
{
|
||||||
unsigned base = 0;
|
unsigned int base = 0;
|
||||||
|
|
||||||
if (gpio >= sch->resume_base) {
|
if (gpio >= sch->resume_base) {
|
||||||
gpio -= sch->resume_base;
|
gpio -= sch->resume_base;
|
||||||
|
@ -39,14 +39,14 @@ static unsigned sch_gpio_offset(struct sch_gpio *sch, unsigned gpio,
|
||||||
return base + reg + gpio / 8;
|
return base + reg + gpio / 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned sch_gpio_bit(struct sch_gpio *sch, unsigned gpio)
|
static unsigned int sch_gpio_bit(struct sch_gpio *sch, unsigned int gpio)
|
||||||
{
|
{
|
||||||
if (gpio >= sch->resume_base)
|
if (gpio >= sch->resume_base)
|
||||||
gpio -= sch->resume_base;
|
gpio -= sch->resume_base;
|
||||||
return gpio % 8;
|
return gpio % 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sch_gpio_reg_get(struct sch_gpio *sch, unsigned gpio, unsigned reg)
|
static int sch_gpio_reg_get(struct sch_gpio *sch, unsigned int gpio, unsigned int reg)
|
||||||
{
|
{
|
||||||
unsigned short offset, bit;
|
unsigned short offset, bit;
|
||||||
u8 reg_val;
|
u8 reg_val;
|
||||||
|
@ -59,7 +59,7 @@ static int sch_gpio_reg_get(struct sch_gpio *sch, unsigned gpio, unsigned reg)
|
||||||
return reg_val;
|
return reg_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sch_gpio_reg_set(struct sch_gpio *sch, unsigned gpio, unsigned reg,
|
static void sch_gpio_reg_set(struct sch_gpio *sch, unsigned int gpio, unsigned int reg,
|
||||||
int val)
|
int val)
|
||||||
{
|
{
|
||||||
unsigned short offset, bit;
|
unsigned short offset, bit;
|
||||||
|
@ -76,7 +76,7 @@ static void sch_gpio_reg_set(struct sch_gpio *sch, unsigned gpio, unsigned reg,
|
||||||
outb((reg_val & ~BIT(bit)), sch->iobase + offset);
|
outb((reg_val & ~BIT(bit)), sch->iobase + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sch_gpio_direction_in(struct gpio_chip *gc, unsigned gpio_num)
|
static int sch_gpio_direction_in(struct gpio_chip *gc, unsigned int gpio_num)
|
||||||
{
|
{
|
||||||
struct sch_gpio *sch = gpiochip_get_data(gc);
|
struct sch_gpio *sch = gpiochip_get_data(gc);
|
||||||
|
|
||||||
|
@ -86,13 +86,14 @@ static int sch_gpio_direction_in(struct gpio_chip *gc, unsigned gpio_num)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sch_gpio_get(struct gpio_chip *gc, unsigned gpio_num)
|
static int sch_gpio_get(struct gpio_chip *gc, unsigned int gpio_num)
|
||||||
{
|
{
|
||||||
struct sch_gpio *sch = gpiochip_get_data(gc);
|
struct sch_gpio *sch = gpiochip_get_data(gc);
|
||||||
|
|
||||||
return sch_gpio_reg_get(sch, gpio_num, GLV);
|
return sch_gpio_reg_get(sch, gpio_num, GLV);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sch_gpio_set(struct gpio_chip *gc, unsigned gpio_num, int val)
|
static void sch_gpio_set(struct gpio_chip *gc, unsigned int gpio_num, int val)
|
||||||
{
|
{
|
||||||
struct sch_gpio *sch = gpiochip_get_data(gc);
|
struct sch_gpio *sch = gpiochip_get_data(gc);
|
||||||
|
|
||||||
|
@ -101,7 +102,7 @@ static void sch_gpio_set(struct gpio_chip *gc, unsigned gpio_num, int val)
|
||||||
spin_unlock(&sch->lock);
|
spin_unlock(&sch->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sch_gpio_direction_out(struct gpio_chip *gc, unsigned gpio_num,
|
static int sch_gpio_direction_out(struct gpio_chip *gc, unsigned int gpio_num,
|
||||||
int val)
|
int val)
|
||||||
{
|
{
|
||||||
struct sch_gpio *sch = gpiochip_get_data(gc);
|
struct sch_gpio *sch = gpiochip_get_data(gc);
|
||||||
|
@ -123,7 +124,7 @@ static int sch_gpio_direction_out(struct gpio_chip *gc, unsigned gpio_num,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sch_gpio_get_direction(struct gpio_chip *gc, unsigned gpio_num)
|
static int sch_gpio_get_direction(struct gpio_chip *gc, unsigned int gpio_num)
|
||||||
{
|
{
|
||||||
struct sch_gpio *sch = gpiochip_get_data(gc);
|
struct sch_gpio *sch = gpiochip_get_data(gc);
|
||||||
|
|
||||||
|
|
|
@ -500,13 +500,9 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_free;
|
goto out_free;
|
||||||
|
|
||||||
ret = gpiochip_add_data(&stmpe_gpio->chip, stmpe_gpio);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret);
|
|
||||||
goto out_disable;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (irq > 0) {
|
if (irq > 0) {
|
||||||
|
struct gpio_irq_chip *girq;
|
||||||
|
|
||||||
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
|
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
|
||||||
stmpe_gpio_irq, IRQF_ONESHOT,
|
stmpe_gpio_irq, IRQF_ONESHOT,
|
||||||
"stmpe-gpio", stmpe_gpio);
|
"stmpe-gpio", stmpe_gpio);
|
||||||
|
@ -514,20 +510,22 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
|
||||||
dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
|
dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
|
||||||
goto out_disable;
|
goto out_disable;
|
||||||
}
|
}
|
||||||
ret = gpiochip_irqchip_add_nested(&stmpe_gpio->chip,
|
|
||||||
&stmpe_gpio_irq_chip,
|
|
||||||
0,
|
|
||||||
handle_simple_irq,
|
|
||||||
IRQ_TYPE_NONE);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(&pdev->dev,
|
|
||||||
"could not connect irqchip to gpiochip\n");
|
|
||||||
goto out_disable;
|
|
||||||
}
|
|
||||||
|
|
||||||
gpiochip_set_nested_irqchip(&stmpe_gpio->chip,
|
girq = &stmpe_gpio->chip.irq;
|
||||||
&stmpe_gpio_irq_chip,
|
girq->chip = &stmpe_gpio_irq_chip;
|
||||||
irq);
|
/* This will let us handle the parent IRQ in the driver */
|
||||||
|
girq->parent_handler = NULL;
|
||||||
|
girq->num_parents = 0;
|
||||||
|
girq->parents = NULL;
|
||||||
|
girq->default_type = IRQ_TYPE_NONE;
|
||||||
|
girq->handler = handle_simple_irq;
|
||||||
|
girq->threaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = gpiochip_add_data(&stmpe_gpio->chip, stmpe_gpio);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret);
|
||||||
|
goto out_disable;
|
||||||
}
|
}
|
||||||
|
|
||||||
platform_set_drvdata(pdev, stmpe_gpio);
|
platform_set_drvdata(pdev, stmpe_gpio);
|
||||||
|
|
|
@ -24,16 +24,16 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct syscon_gpio_data - Configuration for the device.
|
* struct syscon_gpio_data - Configuration for the device.
|
||||||
* compatible: SYSCON driver compatible string.
|
* @compatible: SYSCON driver compatible string.
|
||||||
* flags: Set of GPIO_SYSCON_FEAT_ flags:
|
* @flags: Set of GPIO_SYSCON_FEAT_ flags:
|
||||||
* GPIO_SYSCON_FEAT_IN: GPIOs supports input,
|
* GPIO_SYSCON_FEAT_IN: GPIOs supports input,
|
||||||
* GPIO_SYSCON_FEAT_OUT: GPIOs supports output,
|
* GPIO_SYSCON_FEAT_OUT: GPIOs supports output,
|
||||||
* GPIO_SYSCON_FEAT_DIR: GPIOs supports switch direction.
|
* GPIO_SYSCON_FEAT_DIR: GPIOs supports switch direction.
|
||||||
* bit_count: Number of bits used as GPIOs.
|
* @bit_count: Number of bits used as GPIOs.
|
||||||
* dat_bit_offset: Offset (in bits) to the first GPIO bit.
|
* @dat_bit_offset: Offset (in bits) to the first GPIO bit.
|
||||||
* dir_bit_offset: Optional offset (in bits) to the first bit to switch
|
* @dir_bit_offset: Optional offset (in bits) to the first bit to switch
|
||||||
* GPIO direction (Used with GPIO_SYSCON_FEAT_DIR flag).
|
* GPIO direction (Used with GPIO_SYSCON_FEAT_DIR flag).
|
||||||
* set: HW specific callback to assigns output value
|
* @set: HW specific callback to assigns output value
|
||||||
* for signal "offset"
|
* for signal "offset"
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
@ -289,6 +289,7 @@ static int tc3589x_gpio_probe(struct platform_device *pdev)
|
||||||
struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent);
|
struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent);
|
||||||
struct device_node *np = pdev->dev.of_node;
|
struct device_node *np = pdev->dev.of_node;
|
||||||
struct tc3589x_gpio *tc3589x_gpio;
|
struct tc3589x_gpio *tc3589x_gpio;
|
||||||
|
struct gpio_irq_chip *girq;
|
||||||
int ret;
|
int ret;
|
||||||
int irq;
|
int irq;
|
||||||
|
|
||||||
|
@ -317,6 +318,16 @@ static int tc3589x_gpio_probe(struct platform_device *pdev)
|
||||||
tc3589x_gpio->chip.base = -1;
|
tc3589x_gpio->chip.base = -1;
|
||||||
tc3589x_gpio->chip.of_node = np;
|
tc3589x_gpio->chip.of_node = np;
|
||||||
|
|
||||||
|
girq = &tc3589x_gpio->chip.irq;
|
||||||
|
girq->chip = &tc3589x_gpio_irq_chip;
|
||||||
|
/* This will let us handle the parent IRQ in the driver */
|
||||||
|
girq->parent_handler = NULL;
|
||||||
|
girq->num_parents = 0;
|
||||||
|
girq->parents = NULL;
|
||||||
|
girq->default_type = IRQ_TYPE_NONE;
|
||||||
|
girq->handler = handle_simple_irq;
|
||||||
|
girq->threaded = true;
|
||||||
|
|
||||||
/* Bring the GPIO module out of reset */
|
/* Bring the GPIO module out of reset */
|
||||||
ret = tc3589x_set_bits(tc3589x, TC3589x_RSTCTRL,
|
ret = tc3589x_set_bits(tc3589x, TC3589x_RSTCTRL,
|
||||||
TC3589x_RSTCTRL_GPIRST, 0);
|
TC3589x_RSTCTRL_GPIRST, 0);
|
||||||
|
@ -339,21 +350,6 @@ static int tc3589x_gpio_probe(struct platform_device *pdev)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = gpiochip_irqchip_add_nested(&tc3589x_gpio->chip,
|
|
||||||
&tc3589x_gpio_irq_chip,
|
|
||||||
0,
|
|
||||||
handle_simple_irq,
|
|
||||||
IRQ_TYPE_NONE);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(&pdev->dev,
|
|
||||||
"could not connect irqchip to gpiochip\n");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
gpiochip_set_nested_irqchip(&tc3589x_gpio->chip,
|
|
||||||
&tc3589x_gpio_irq_chip,
|
|
||||||
irq);
|
|
||||||
|
|
||||||
platform_set_drvdata(pdev, tc3589x_gpio);
|
platform_set_drvdata(pdev, tc3589x_gpio);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -400,6 +400,7 @@ static int wcove_gpio_probe(struct platform_device *pdev)
|
||||||
struct wcove_gpio *wg;
|
struct wcove_gpio *wg;
|
||||||
int virq, ret, irq;
|
int virq, ret, irq;
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
|
struct gpio_irq_chip *girq;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This gpio platform device is created by a mfd device (see
|
* This gpio platform device is created by a mfd device (see
|
||||||
|
@ -442,33 +443,34 @@ static int wcove_gpio_probe(struct platform_device *pdev)
|
||||||
wg->dev = dev;
|
wg->dev = dev;
|
||||||
wg->regmap = pmic->regmap;
|
wg->regmap = pmic->regmap;
|
||||||
|
|
||||||
ret = devm_gpiochip_add_data(dev, &wg->chip, wg);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(dev, "Failed to add gpiochip: %d\n", ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = gpiochip_irqchip_add_nested(&wg->chip, &wcove_irqchip, 0,
|
|
||||||
handle_simple_irq, IRQ_TYPE_NONE);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(dev, "Failed to add irqchip: %d\n", ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
virq = regmap_irq_get_virq(wg->regmap_irq_chip, irq);
|
virq = regmap_irq_get_virq(wg->regmap_irq_chip, irq);
|
||||||
if (virq < 0) {
|
if (virq < 0) {
|
||||||
dev_err(dev, "Failed to get virq by irq %d\n", irq);
|
dev_err(dev, "Failed to get virq by irq %d\n", irq);
|
||||||
return virq;
|
return virq;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = devm_request_threaded_irq(dev, virq, NULL,
|
girq = &wg->chip.irq;
|
||||||
wcove_gpio_irq_handler, IRQF_ONESHOT, pdev->name, wg);
|
girq->chip = &wcove_irqchip;
|
||||||
|
/* This will let us handle the parent IRQ in the driver */
|
||||||
|
girq->parent_handler = NULL;
|
||||||
|
girq->num_parents = 0;
|
||||||
|
girq->parents = NULL;
|
||||||
|
girq->default_type = IRQ_TYPE_NONE;
|
||||||
|
girq->handler = handle_simple_irq;
|
||||||
|
girq->threaded = true;
|
||||||
|
|
||||||
|
ret = devm_request_threaded_irq(dev, virq, NULL, wcove_gpio_irq_handler,
|
||||||
|
IRQF_ONESHOT, pdev->name, wg);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "Failed to request irq %d\n", virq);
|
dev_err(dev, "Failed to request irq %d\n", virq);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
gpiochip_set_nested_irqchip(&wg->chip, &wcove_irqchip, virq);
|
ret = devm_gpiochip_add_data(dev, &wg->chip, wg);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "Failed to add gpiochip: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* Enable GPIO0 interrupts */
|
/* Enable GPIO0 interrupts */
|
||||||
ret = regmap_update_bits(wg->regmap, IRQ_MASK_BASE, GPIO_IRQ0_MASK,
|
ret = regmap_update_bits(wg->regmap, IRQ_MASK_BASE, GPIO_IRQ0_MASK,
|
||||||
|
|
|
@ -365,10 +365,25 @@ static const char *ws16c48_names[WS16C48_NGPIO] = {
|
||||||
"Port 5 Bit 4", "Port 5 Bit 5", "Port 5 Bit 6", "Port 5 Bit 7"
|
"Port 5 Bit 4", "Port 5 Bit 5", "Port 5 Bit 6", "Port 5 Bit 7"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int ws16c48_irq_init_hw(struct gpio_chip *gc)
|
||||||
|
{
|
||||||
|
struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(gc);
|
||||||
|
|
||||||
|
/* Disable IRQ by default */
|
||||||
|
outb(0x80, ws16c48gpio->base + 7);
|
||||||
|
outb(0, ws16c48gpio->base + 8);
|
||||||
|
outb(0, ws16c48gpio->base + 9);
|
||||||
|
outb(0, ws16c48gpio->base + 10);
|
||||||
|
outb(0xC0, ws16c48gpio->base + 7);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int ws16c48_probe(struct device *dev, unsigned int id)
|
static int ws16c48_probe(struct device *dev, unsigned int id)
|
||||||
{
|
{
|
||||||
struct ws16c48_gpio *ws16c48gpio;
|
struct ws16c48_gpio *ws16c48gpio;
|
||||||
const char *const name = dev_name(dev);
|
const char *const name = dev_name(dev);
|
||||||
|
struct gpio_irq_chip *girq;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
ws16c48gpio = devm_kzalloc(dev, sizeof(*ws16c48gpio), GFP_KERNEL);
|
ws16c48gpio = devm_kzalloc(dev, sizeof(*ws16c48gpio), GFP_KERNEL);
|
||||||
|
@ -396,6 +411,16 @@ static int ws16c48_probe(struct device *dev, unsigned int id)
|
||||||
ws16c48gpio->chip.set_multiple = ws16c48_gpio_set_multiple;
|
ws16c48gpio->chip.set_multiple = ws16c48_gpio_set_multiple;
|
||||||
ws16c48gpio->base = base[id];
|
ws16c48gpio->base = base[id];
|
||||||
|
|
||||||
|
girq = &ws16c48gpio->chip.irq;
|
||||||
|
girq->chip = &ws16c48_irqchip;
|
||||||
|
/* This will let us handle the parent IRQ in the driver */
|
||||||
|
girq->parent_handler = NULL;
|
||||||
|
girq->num_parents = 0;
|
||||||
|
girq->parents = NULL;
|
||||||
|
girq->default_type = IRQ_TYPE_NONE;
|
||||||
|
girq->handler = handle_edge_irq;
|
||||||
|
girq->init_hw = ws16c48_irq_init_hw;
|
||||||
|
|
||||||
raw_spin_lock_init(&ws16c48gpio->lock);
|
raw_spin_lock_init(&ws16c48gpio->lock);
|
||||||
|
|
||||||
err = devm_gpiochip_add_data(dev, &ws16c48gpio->chip, ws16c48gpio);
|
err = devm_gpiochip_add_data(dev, &ws16c48gpio->chip, ws16c48gpio);
|
||||||
|
@ -404,20 +429,6 @@ static int ws16c48_probe(struct device *dev, unsigned int id)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Disable IRQ by default */
|
|
||||||
outb(0x80, base[id] + 7);
|
|
||||||
outb(0, base[id] + 8);
|
|
||||||
outb(0, base[id] + 9);
|
|
||||||
outb(0, base[id] + 10);
|
|
||||||
outb(0xC0, base[id] + 7);
|
|
||||||
|
|
||||||
err = gpiochip_irqchip_add(&ws16c48gpio->chip, &ws16c48_irqchip, 0,
|
|
||||||
handle_edge_irq, IRQ_TYPE_NONE);
|
|
||||||
if (err) {
|
|
||||||
dev_err(dev, "Could not add irqchip (%d)\n", err);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = devm_request_irq(dev, irq[id], ws16c48_irq_handler, IRQF_SHARED,
|
err = devm_request_irq(dev, irq[id], ws16c48_irq_handler, IRQF_SHARED,
|
||||||
name, ws16c48gpio);
|
name, ws16c48gpio);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|
|
@ -121,6 +121,7 @@ static void xra1403_dbg_show(struct seq_file *s, struct gpio_chip *chip)
|
||||||
struct xra1403 *xra = gpiochip_get_data(chip);
|
struct xra1403 *xra = gpiochip_get_data(chip);
|
||||||
int value[XRA_LAST];
|
int value[XRA_LAST];
|
||||||
int i;
|
int i;
|
||||||
|
const char *label;
|
||||||
unsigned int gcr;
|
unsigned int gcr;
|
||||||
unsigned int gsr;
|
unsigned int gsr;
|
||||||
|
|
||||||
|
@ -136,12 +137,7 @@ static void xra1403_dbg_show(struct seq_file *s, struct gpio_chip *chip)
|
||||||
|
|
||||||
gcr = value[XRA_GCR + 1] << 8 | value[XRA_GCR];
|
gcr = value[XRA_GCR + 1] << 8 | value[XRA_GCR];
|
||||||
gsr = value[XRA_GSR + 1] << 8 | value[XRA_GSR];
|
gsr = value[XRA_GSR + 1] << 8 | value[XRA_GSR];
|
||||||
for (i = 0; i < chip->ngpio; i++) {
|
for_each_requested_gpio(chip, i, label) {
|
||||||
const char *label = gpiochip_is_requested(chip, i);
|
|
||||||
|
|
||||||
if (!label)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
seq_printf(s, " gpio-%-3d (%-12s) %s %s\n",
|
seq_printf(s, " gpio-%-3d (%-12s) %s %s\n",
|
||||||
chip->base + i, label,
|
chip->base + i, label,
|
||||||
(gcr & BIT(i)) ? "in" : "out",
|
(gcr & BIT(i)) ? "in" : "out",
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <linux/gpio/driver.h>
|
#include <linux/gpio/driver.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
|
@ -21,6 +22,9 @@
|
||||||
/* Maximum banks */
|
/* Maximum banks */
|
||||||
#define ZYNQ_GPIO_MAX_BANK 4
|
#define ZYNQ_GPIO_MAX_BANK 4
|
||||||
#define ZYNQMP_GPIO_MAX_BANK 6
|
#define ZYNQMP_GPIO_MAX_BANK 6
|
||||||
|
#define VERSAL_GPIO_MAX_BANK 4
|
||||||
|
#define PMC_GPIO_MAX_BANK 5
|
||||||
|
#define VERSAL_UNUSED_BANKS 2
|
||||||
|
|
||||||
#define ZYNQ_GPIO_BANK0_NGPIO 32
|
#define ZYNQ_GPIO_BANK0_NGPIO 32
|
||||||
#define ZYNQ_GPIO_BANK1_NGPIO 22
|
#define ZYNQ_GPIO_BANK1_NGPIO 22
|
||||||
|
@ -95,6 +99,7 @@
|
||||||
/* set to differentiate zynq from zynqmp, 0=zynqmp, 1=zynq */
|
/* set to differentiate zynq from zynqmp, 0=zynqmp, 1=zynq */
|
||||||
#define ZYNQ_GPIO_QUIRK_IS_ZYNQ BIT(0)
|
#define ZYNQ_GPIO_QUIRK_IS_ZYNQ BIT(0)
|
||||||
#define GPIO_QUIRK_DATA_RO_BUG BIT(1)
|
#define GPIO_QUIRK_DATA_RO_BUG BIT(1)
|
||||||
|
#define GPIO_QUIRK_VERSAL BIT(2)
|
||||||
|
|
||||||
struct gpio_regs {
|
struct gpio_regs {
|
||||||
u32 datamsw[ZYNQMP_GPIO_MAX_BANK];
|
u32 datamsw[ZYNQMP_GPIO_MAX_BANK];
|
||||||
|
@ -116,6 +121,7 @@ struct gpio_regs {
|
||||||
* @irq: interrupt for the GPIO device
|
* @irq: interrupt for the GPIO device
|
||||||
* @p_data: pointer to platform data
|
* @p_data: pointer to platform data
|
||||||
* @context: context registers
|
* @context: context registers
|
||||||
|
* @dirlock: lock used for direction in/out synchronization
|
||||||
*/
|
*/
|
||||||
struct zynq_gpio {
|
struct zynq_gpio {
|
||||||
struct gpio_chip chip;
|
struct gpio_chip chip;
|
||||||
|
@ -124,6 +130,7 @@ struct zynq_gpio {
|
||||||
int irq;
|
int irq;
|
||||||
const struct zynq_platform_data *p_data;
|
const struct zynq_platform_data *p_data;
|
||||||
struct gpio_regs context;
|
struct gpio_regs context;
|
||||||
|
spinlock_t dirlock; /* lock */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -196,6 +203,8 @@ static inline void zynq_gpio_get_bank_pin(unsigned int pin_num,
|
||||||
gpio->p_data->bank_min[bank];
|
gpio->p_data->bank_min[bank];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (gpio->p_data->quirks & GPIO_QUIRK_VERSAL)
|
||||||
|
bank = bank + VERSAL_UNUSED_BANKS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* default */
|
/* default */
|
||||||
|
@ -297,6 +306,7 @@ static int zynq_gpio_dir_in(struct gpio_chip *chip, unsigned int pin)
|
||||||
{
|
{
|
||||||
u32 reg;
|
u32 reg;
|
||||||
unsigned int bank_num, bank_pin_num;
|
unsigned int bank_num, bank_pin_num;
|
||||||
|
unsigned long flags;
|
||||||
struct zynq_gpio *gpio = gpiochip_get_data(chip);
|
struct zynq_gpio *gpio = gpiochip_get_data(chip);
|
||||||
|
|
||||||
zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio);
|
zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio);
|
||||||
|
@ -310,9 +320,11 @@ static int zynq_gpio_dir_in(struct gpio_chip *chip, unsigned int pin)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/* clear the bit in direction mode reg to set the pin as input */
|
/* clear the bit in direction mode reg to set the pin as input */
|
||||||
|
spin_lock_irqsave(&gpio->dirlock, flags);
|
||||||
reg = readl_relaxed(gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
|
reg = readl_relaxed(gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
|
||||||
reg &= ~BIT(bank_pin_num);
|
reg &= ~BIT(bank_pin_num);
|
||||||
writel_relaxed(reg, gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
|
writel_relaxed(reg, gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
|
||||||
|
spin_unlock_irqrestore(&gpio->dirlock, flags);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -334,11 +346,13 @@ static int zynq_gpio_dir_out(struct gpio_chip *chip, unsigned int pin,
|
||||||
{
|
{
|
||||||
u32 reg;
|
u32 reg;
|
||||||
unsigned int bank_num, bank_pin_num;
|
unsigned int bank_num, bank_pin_num;
|
||||||
|
unsigned long flags;
|
||||||
struct zynq_gpio *gpio = gpiochip_get_data(chip);
|
struct zynq_gpio *gpio = gpiochip_get_data(chip);
|
||||||
|
|
||||||
zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio);
|
zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio);
|
||||||
|
|
||||||
/* set the GPIO pin as output */
|
/* set the GPIO pin as output */
|
||||||
|
spin_lock_irqsave(&gpio->dirlock, flags);
|
||||||
reg = readl_relaxed(gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
|
reg = readl_relaxed(gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
|
||||||
reg |= BIT(bank_pin_num);
|
reg |= BIT(bank_pin_num);
|
||||||
writel_relaxed(reg, gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
|
writel_relaxed(reg, gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
|
||||||
|
@ -347,6 +361,7 @@ static int zynq_gpio_dir_out(struct gpio_chip *chip, unsigned int pin,
|
||||||
reg = readl_relaxed(gpio->base_addr + ZYNQ_GPIO_OUTEN_OFFSET(bank_num));
|
reg = readl_relaxed(gpio->base_addr + ZYNQ_GPIO_OUTEN_OFFSET(bank_num));
|
||||||
reg |= BIT(bank_pin_num);
|
reg |= BIT(bank_pin_num);
|
||||||
writel_relaxed(reg, gpio->base_addr + ZYNQ_GPIO_OUTEN_OFFSET(bank_num));
|
writel_relaxed(reg, gpio->base_addr + ZYNQ_GPIO_OUTEN_OFFSET(bank_num));
|
||||||
|
spin_unlock_irqrestore(&gpio->dirlock, flags);
|
||||||
|
|
||||||
/* set the state of the pin */
|
/* set the state of the pin */
|
||||||
zynq_gpio_set_value(chip, pin, state);
|
zynq_gpio_set_value(chip, pin, state);
|
||||||
|
@ -647,6 +662,8 @@ static void zynq_gpio_irqhandler(struct irq_desc *desc)
|
||||||
int_enb = readl_relaxed(gpio->base_addr +
|
int_enb = readl_relaxed(gpio->base_addr +
|
||||||
ZYNQ_GPIO_INTMASK_OFFSET(bank_num));
|
ZYNQ_GPIO_INTMASK_OFFSET(bank_num));
|
||||||
zynq_gpio_handle_bank_irq(gpio, bank_num, int_sts & ~int_enb);
|
zynq_gpio_handle_bank_irq(gpio, bank_num, int_sts & ~int_enb);
|
||||||
|
if (gpio->p_data->quirks & GPIO_QUIRK_VERSAL)
|
||||||
|
bank_num = bank_num + VERSAL_UNUSED_BANKS;
|
||||||
}
|
}
|
||||||
|
|
||||||
chained_irq_exit(irqchip, desc);
|
chained_irq_exit(irqchip, desc);
|
||||||
|
@ -676,6 +693,8 @@ static void zynq_gpio_save_context(struct zynq_gpio *gpio)
|
||||||
gpio->context.int_any[bank_num] =
|
gpio->context.int_any[bank_num] =
|
||||||
readl_relaxed(gpio->base_addr +
|
readl_relaxed(gpio->base_addr +
|
||||||
ZYNQ_GPIO_INTANY_OFFSET(bank_num));
|
ZYNQ_GPIO_INTANY_OFFSET(bank_num));
|
||||||
|
if (gpio->p_data->quirks & GPIO_QUIRK_VERSAL)
|
||||||
|
bank_num = bank_num + VERSAL_UNUSED_BANKS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -707,6 +726,8 @@ static void zynq_gpio_restore_context(struct zynq_gpio *gpio)
|
||||||
writel_relaxed(~(gpio->context.int_en[bank_num]),
|
writel_relaxed(~(gpio->context.int_en[bank_num]),
|
||||||
gpio->base_addr +
|
gpio->base_addr +
|
||||||
ZYNQ_GPIO_INTEN_OFFSET(bank_num));
|
ZYNQ_GPIO_INTEN_OFFSET(bank_num));
|
||||||
|
if (gpio->p_data->quirks & GPIO_QUIRK_VERSAL)
|
||||||
|
bank_num = bank_num + VERSAL_UNUSED_BANKS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -715,6 +736,9 @@ static int __maybe_unused zynq_gpio_suspend(struct device *dev)
|
||||||
struct zynq_gpio *gpio = dev_get_drvdata(dev);
|
struct zynq_gpio *gpio = dev_get_drvdata(dev);
|
||||||
struct irq_data *data = irq_get_irq_data(gpio->irq);
|
struct irq_data *data = irq_get_irq_data(gpio->irq);
|
||||||
|
|
||||||
|
if (!device_may_wakeup(dev))
|
||||||
|
disable_irq(gpio->irq);
|
||||||
|
|
||||||
if (!irqd_is_wakeup_set(data)) {
|
if (!irqd_is_wakeup_set(data)) {
|
||||||
zynq_gpio_save_context(gpio);
|
zynq_gpio_save_context(gpio);
|
||||||
return pm_runtime_force_suspend(dev);
|
return pm_runtime_force_suspend(dev);
|
||||||
|
@ -729,6 +753,9 @@ static int __maybe_unused zynq_gpio_resume(struct device *dev)
|
||||||
struct irq_data *data = irq_get_irq_data(gpio->irq);
|
struct irq_data *data = irq_get_irq_data(gpio->irq);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (!device_may_wakeup(dev))
|
||||||
|
enable_irq(gpio->irq);
|
||||||
|
|
||||||
if (!irqd_is_wakeup_set(data)) {
|
if (!irqd_is_wakeup_set(data)) {
|
||||||
ret = pm_runtime_force_resume(dev);
|
ret = pm_runtime_force_resume(dev);
|
||||||
zynq_gpio_restore_context(gpio);
|
zynq_gpio_restore_context(gpio);
|
||||||
|
@ -778,6 +805,31 @@ static const struct dev_pm_ops zynq_gpio_dev_pm_ops = {
|
||||||
zynq_gpio_runtime_resume, NULL)
|
zynq_gpio_runtime_resume, NULL)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct zynq_platform_data versal_gpio_def = {
|
||||||
|
.label = "versal_gpio",
|
||||||
|
.quirks = GPIO_QUIRK_VERSAL,
|
||||||
|
.ngpio = 58,
|
||||||
|
.max_bank = VERSAL_GPIO_MAX_BANK,
|
||||||
|
.bank_min[0] = 0,
|
||||||
|
.bank_max[0] = 25, /* 0 to 25 are connected to MIOs (26 pins) */
|
||||||
|
.bank_min[3] = 26,
|
||||||
|
.bank_max[3] = 57, /* Bank 3 is connected to FMIOs (32 pins) */
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct zynq_platform_data pmc_gpio_def = {
|
||||||
|
.label = "pmc_gpio",
|
||||||
|
.ngpio = 116,
|
||||||
|
.max_bank = PMC_GPIO_MAX_BANK,
|
||||||
|
.bank_min[0] = 0,
|
||||||
|
.bank_max[0] = 25, /* 0 to 25 are connected to MIOs (26 pins) */
|
||||||
|
.bank_min[1] = 26,
|
||||||
|
.bank_max[1] = 51, /* Bank 1 are connected to MIOs (26 pins) */
|
||||||
|
.bank_min[3] = 52,
|
||||||
|
.bank_max[3] = 83, /* Bank 3 is connected to EMIOs (32 pins) */
|
||||||
|
.bank_min[4] = 84,
|
||||||
|
.bank_max[4] = 115, /* Bank 4 is connected to EMIOs (32 pins) */
|
||||||
|
};
|
||||||
|
|
||||||
static const struct zynq_platform_data zynqmp_gpio_def = {
|
static const struct zynq_platform_data zynqmp_gpio_def = {
|
||||||
.label = "zynqmp_gpio",
|
.label = "zynqmp_gpio",
|
||||||
.quirks = GPIO_QUIRK_DATA_RO_BUG,
|
.quirks = GPIO_QUIRK_DATA_RO_BUG,
|
||||||
|
@ -815,6 +867,8 @@ static const struct zynq_platform_data zynq_gpio_def = {
|
||||||
static const struct of_device_id zynq_gpio_of_match[] = {
|
static const struct of_device_id zynq_gpio_of_match[] = {
|
||||||
{ .compatible = "xlnx,zynq-gpio-1.0", .data = &zynq_gpio_def },
|
{ .compatible = "xlnx,zynq-gpio-1.0", .data = &zynq_gpio_def },
|
||||||
{ .compatible = "xlnx,zynqmp-gpio-1.0", .data = &zynqmp_gpio_def },
|
{ .compatible = "xlnx,zynqmp-gpio-1.0", .data = &zynqmp_gpio_def },
|
||||||
|
{ .compatible = "xlnx,versal-gpio-1.0", .data = &versal_gpio_def },
|
||||||
|
{ .compatible = "xlnx,pmc-gpio-1.0", .data = &pmc_gpio_def },
|
||||||
{ /* end of table */ }
|
{ /* end of table */ }
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, zynq_gpio_of_match);
|
MODULE_DEVICE_TABLE(of, zynq_gpio_of_match);
|
||||||
|
@ -876,7 +930,8 @@ static int zynq_gpio_probe(struct platform_device *pdev)
|
||||||
/* Retrieve GPIO clock */
|
/* Retrieve GPIO clock */
|
||||||
gpio->clk = devm_clk_get(&pdev->dev, NULL);
|
gpio->clk = devm_clk_get(&pdev->dev, NULL);
|
||||||
if (IS_ERR(gpio->clk)) {
|
if (IS_ERR(gpio->clk)) {
|
||||||
dev_err(&pdev->dev, "input clock not found.\n");
|
if (PTR_ERR(gpio->clk) != -EPROBE_DEFER)
|
||||||
|
dev_err(&pdev->dev, "input clock not found.\n");
|
||||||
return PTR_ERR(gpio->clk);
|
return PTR_ERR(gpio->clk);
|
||||||
}
|
}
|
||||||
ret = clk_prepare_enable(gpio->clk);
|
ret = clk_prepare_enable(gpio->clk);
|
||||||
|
@ -885,6 +940,8 @@ static int zynq_gpio_probe(struct platform_device *pdev)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spin_lock_init(&gpio->dirlock);
|
||||||
|
|
||||||
pm_runtime_set_active(&pdev->dev);
|
pm_runtime_set_active(&pdev->dev);
|
||||||
pm_runtime_enable(&pdev->dev);
|
pm_runtime_enable(&pdev->dev);
|
||||||
ret = pm_runtime_get_sync(&pdev->dev);
|
ret = pm_runtime_get_sync(&pdev->dev);
|
||||||
|
@ -892,9 +949,12 @@ static int zynq_gpio_probe(struct platform_device *pdev)
|
||||||
goto err_pm_dis;
|
goto err_pm_dis;
|
||||||
|
|
||||||
/* disable interrupts for all banks */
|
/* disable interrupts for all banks */
|
||||||
for (bank_num = 0; bank_num < gpio->p_data->max_bank; bank_num++)
|
for (bank_num = 0; bank_num < gpio->p_data->max_bank; bank_num++) {
|
||||||
writel_relaxed(ZYNQ_GPIO_IXR_DISABLE_ALL, gpio->base_addr +
|
writel_relaxed(ZYNQ_GPIO_IXR_DISABLE_ALL, gpio->base_addr +
|
||||||
ZYNQ_GPIO_INTDIS_OFFSET(bank_num));
|
ZYNQ_GPIO_INTDIS_OFFSET(bank_num));
|
||||||
|
if (gpio->p_data->quirks & GPIO_QUIRK_VERSAL)
|
||||||
|
bank_num = bank_num + VERSAL_UNUSED_BANKS;
|
||||||
|
}
|
||||||
|
|
||||||
/* Set up the GPIO irqchip */
|
/* Set up the GPIO irqchip */
|
||||||
girq = &chip->irq;
|
girq = &chip->irq;
|
||||||
|
@ -919,6 +979,8 @@ static int zynq_gpio_probe(struct platform_device *pdev)
|
||||||
goto err_pm_put;
|
goto err_pm_put;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
irq_set_status_flags(gpio->irq, IRQ_DISABLE_UNLAZY);
|
||||||
|
device_init_wakeup(&pdev->dev, 1);
|
||||||
pm_runtime_put(&pdev->dev);
|
pm_runtime_put(&pdev->dev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,11 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
|
||||||
|
#ifndef GPIOLIB_CDEV_H
|
||||||
|
#define GPIOLIB_CDEV_H
|
||||||
|
|
||||||
|
#include <linux/device.h>
|
||||||
|
|
||||||
|
int gpiolib_cdev_register(struct gpio_device *gdev, dev_t devt);
|
||||||
|
void gpiolib_cdev_unregister(struct gpio_device *gdev);
|
||||||
|
|
||||||
|
#endif /* GPIOLIB_CDEV_H */
|
|
@ -487,10 +487,12 @@ static void devm_gpio_chip_release(struct device *dev, void *res)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* devm_gpiochip_add_data() - Resource managed gpiochip_add_data()
|
* devm_gpiochip_add_data_with_key() - Resource managed gpiochip_add_data_with_key()
|
||||||
* @dev: pointer to the device that gpio_chip belongs to.
|
* @dev: pointer to the device that gpio_chip belongs to.
|
||||||
* @gc: the GPIO chip to register
|
* @gc: the GPIO chip to register
|
||||||
* @data: driver-private data associated with this chip
|
* @data: driver-private data associated with this chip
|
||||||
|
* @lock_key: lockdep class for IRQ lock
|
||||||
|
* @request_key: lockdep class for IRQ request
|
||||||
*
|
*
|
||||||
* Context: potentially before irqs will work
|
* Context: potentially before irqs will work
|
||||||
*
|
*
|
||||||
|
@ -501,8 +503,9 @@ static void devm_gpio_chip_release(struct device *dev, void *res)
|
||||||
* gc->base is invalid or already associated with a different chip.
|
* gc->base is invalid or already associated with a different chip.
|
||||||
* Otherwise it returns zero as a success code.
|
* Otherwise it returns zero as a success code.
|
||||||
*/
|
*/
|
||||||
int devm_gpiochip_add_data(struct device *dev, struct gpio_chip *gc,
|
int devm_gpiochip_add_data_with_key(struct device *dev, struct gpio_chip *gc, void *data,
|
||||||
void *data)
|
struct lock_class_key *lock_key,
|
||||||
|
struct lock_class_key *request_key)
|
||||||
{
|
{
|
||||||
struct gpio_chip **ptr;
|
struct gpio_chip **ptr;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -512,7 +515,7 @@ int devm_gpiochip_add_data(struct device *dev, struct gpio_chip *gc,
|
||||||
if (!ptr)
|
if (!ptr)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
ret = gpiochip_add_data(gc, data);
|
ret = gpiochip_add_data_with_key(gc, data, lock_key, request_key);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
devres_free(ptr);
|
devres_free(ptr);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -523,4 +526,4 @@ int devm_gpiochip_add_data(struct device *dev, struct gpio_chip *gc,
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(devm_gpiochip_add_data);
|
EXPORT_SYMBOL_GPL(devm_gpiochip_add_data_with_key);
|
||||||
|
|
|
@ -25,6 +25,9 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* of_gpio_spi_cs_get_count() - special GPIO counting for SPI
|
* of_gpio_spi_cs_get_count() - special GPIO counting for SPI
|
||||||
|
* @dev: Consuming device
|
||||||
|
* @con_id: Function within the GPIO consumer
|
||||||
|
*
|
||||||
* Some elder GPIO controllers need special quirks. Currently we handle
|
* Some elder GPIO controllers need special quirks. Currently we handle
|
||||||
* the Freescale and PPC GPIO controller with bindings that doesn't use the
|
* the Freescale and PPC GPIO controller with bindings that doesn't use the
|
||||||
* established "cs-gpios" for chip selects but instead rely on
|
* established "cs-gpios" for chip selects but instead rely on
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <linux/ctype.h>
|
#include <linux/ctype.h>
|
||||||
|
|
||||||
#include "gpiolib.h"
|
#include "gpiolib.h"
|
||||||
|
#include "gpiolib-sysfs.h"
|
||||||
|
|
||||||
#define GPIO_IRQF_TRIGGER_FALLING BIT(0)
|
#define GPIO_IRQF_TRIGGER_FALLING BIT(0)
|
||||||
#define GPIO_IRQF_TRIGGER_RISING BIT(1)
|
#define GPIO_IRQF_TRIGGER_RISING BIT(1)
|
||||||
|
@ -365,7 +366,7 @@ static DEVICE_ATTR_RW(active_low);
|
||||||
static umode_t gpio_is_visible(struct kobject *kobj, struct attribute *attr,
|
static umode_t gpio_is_visible(struct kobject *kobj, struct attribute *attr,
|
||||||
int n)
|
int n)
|
||||||
{
|
{
|
||||||
struct device *dev = container_of(kobj, struct device, kobj);
|
struct device *dev = kobj_to_dev(kobj);
|
||||||
struct gpiod_data *data = dev_get_drvdata(dev);
|
struct gpiod_data *data = dev_get_drvdata(dev);
|
||||||
struct gpio_desc *desc = data->desc;
|
struct gpio_desc *desc = data->desc;
|
||||||
umode_t mode = attr->mode;
|
umode_t mode = attr->mode;
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
|
||||||
|
#ifndef GPIOLIB_SYSFS_H
|
||||||
|
#define GPIOLIB_SYSFS_H
|
||||||
|
|
||||||
|
#ifdef CONFIG_GPIO_SYSFS
|
||||||
|
|
||||||
|
int gpiochip_sysfs_register(struct gpio_device *gdev);
|
||||||
|
void gpiochip_sysfs_unregister(struct gpio_device *gdev);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static inline int gpiochip_sysfs_register(struct gpio_device *gdev)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void gpiochip_sysfs_unregister(struct gpio_device *gdev)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_GPIO_SYSFS */
|
||||||
|
|
||||||
|
#endif /* GPIOLIB_SYSFS_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -56,7 +56,7 @@ struct gpio_device {
|
||||||
const char *label;
|
const char *label;
|
||||||
void *data;
|
void *data;
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
struct atomic_notifier_head notifier;
|
struct blocking_notifier_head notifier;
|
||||||
|
|
||||||
#ifdef CONFIG_PINCTRL
|
#ifdef CONFIG_PINCTRL
|
||||||
/*
|
/*
|
||||||
|
@ -175,22 +175,4 @@ static inline int gpio_chip_hwgpio(const struct gpio_desc *desc)
|
||||||
#define chip_dbg(gc, fmt, ...) \
|
#define chip_dbg(gc, fmt, ...) \
|
||||||
dev_dbg(&gc->gpiodev->dev, "(%s): " fmt, gc->label, ##__VA_ARGS__)
|
dev_dbg(&gc->gpiodev->dev, "(%s): " fmt, gc->label, ##__VA_ARGS__)
|
||||||
|
|
||||||
#ifdef CONFIG_GPIO_SYSFS
|
|
||||||
|
|
||||||
int gpiochip_sysfs_register(struct gpio_device *gdev);
|
|
||||||
void gpiochip_sysfs_unregister(struct gpio_device *gdev);
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
static inline int gpiochip_sysfs_register(struct gpio_device *gdev)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void gpiochip_sysfs_unregister(struct gpio_device *gdev)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* CONFIG_GPIO_SYSFS */
|
|
||||||
|
|
||||||
#endif /* GPIOLIB_H */
|
#endif /* GPIOLIB_H */
|
||||||
|
|
|
@ -1486,14 +1486,11 @@ static void at91_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
|
||||||
int i;
|
int i;
|
||||||
struct at91_gpio_chip *at91_gpio = gpiochip_get_data(chip);
|
struct at91_gpio_chip *at91_gpio = gpiochip_get_data(chip);
|
||||||
void __iomem *pio = at91_gpio->regbase;
|
void __iomem *pio = at91_gpio->regbase;
|
||||||
|
const char *gpio_label;
|
||||||
|
|
||||||
for (i = 0; i < chip->ngpio; i++) {
|
for_each_requested_gpio(chip, i, gpio_label) {
|
||||||
unsigned mask = pin_to_mask(i);
|
unsigned mask = pin_to_mask(i);
|
||||||
const char *gpio_label;
|
|
||||||
|
|
||||||
gpio_label = gpiochip_is_requested(chip, i);
|
|
||||||
if (!gpio_label)
|
|
||||||
continue;
|
|
||||||
mode = at91_gpio->ops->get_periph(pio, mask);
|
mode = at91_gpio->ops->get_periph(pio, mask);
|
||||||
seq_printf(s, "[%s] GPIO%s%d: ",
|
seq_printf(s, "[%s] GPIO%s%d: ",
|
||||||
gpio_label, chip->label, i);
|
gpio_label, chip->label, i);
|
||||||
|
|
|
@ -474,6 +474,22 @@ struct gpio_chip {
|
||||||
extern const char *gpiochip_is_requested(struct gpio_chip *gc,
|
extern const char *gpiochip_is_requested(struct gpio_chip *gc,
|
||||||
unsigned int offset);
|
unsigned int offset);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* for_each_requested_gpio_in_range - iterates over requested GPIOs in a given range
|
||||||
|
* @chip: the chip to query
|
||||||
|
* @i: loop variable
|
||||||
|
* @base: first GPIO in the range
|
||||||
|
* @size: amount of GPIOs to check starting from @base
|
||||||
|
* @label: label of current GPIO
|
||||||
|
*/
|
||||||
|
#define for_each_requested_gpio_in_range(chip, i, base, size, label) \
|
||||||
|
for (i = 0; i < size; i++) \
|
||||||
|
if ((label = gpiochip_is_requested(chip, base + i)) == NULL) {} else
|
||||||
|
|
||||||
|
/* Iterates over all requested GPIO of the given @chip */
|
||||||
|
#define for_each_requested_gpio(chip, i, label) \
|
||||||
|
for_each_requested_gpio_in_range(chip, i, 0, chip->ngpio, label)
|
||||||
|
|
||||||
/* add/remove chips */
|
/* add/remove chips */
|
||||||
extern int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
|
extern int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
|
||||||
struct lock_class_key *lock_key,
|
struct lock_class_key *lock_key,
|
||||||
|
@ -481,25 +497,25 @@ extern int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gpiochip_add_data() - register a gpio_chip
|
* gpiochip_add_data() - register a gpio_chip
|
||||||
* @chip: the chip to register, with chip->base initialized
|
* @gc: the chip to register, with gc->base initialized
|
||||||
* @data: driver-private data associated with this chip
|
* @data: driver-private data associated with this chip
|
||||||
*
|
*
|
||||||
* Context: potentially before irqs will work
|
* Context: potentially before irqs will work
|
||||||
*
|
*
|
||||||
* When gpiochip_add_data() is called very early during boot, so that GPIOs
|
* When gpiochip_add_data() is called very early during boot, so that GPIOs
|
||||||
* can be freely used, the chip->parent device must be registered before
|
* can be freely used, the gc->parent device must be registered before
|
||||||
* the gpio framework's arch_initcall(). Otherwise sysfs initialization
|
* the gpio framework's arch_initcall(). Otherwise sysfs initialization
|
||||||
* for GPIOs will fail rudely.
|
* for GPIOs will fail rudely.
|
||||||
*
|
*
|
||||||
* gpiochip_add_data() must only be called after gpiolib initialization,
|
* gpiochip_add_data() must only be called after gpiolib initialization,
|
||||||
* ie after core_initcall().
|
* ie after core_initcall().
|
||||||
*
|
*
|
||||||
* If chip->base is negative, this requests dynamic assignment of
|
* If gc->base is negative, this requests dynamic assignment of
|
||||||
* a range of valid GPIOs.
|
* a range of valid GPIOs.
|
||||||
*
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
* A negative errno if the chip can't be registered, such as because the
|
* A negative errno if the chip can't be registered, such as because the
|
||||||
* chip->base is invalid or already associated with a different chip.
|
* gc->base is invalid or already associated with a different chip.
|
||||||
* Otherwise it returns zero as a success code.
|
* Otherwise it returns zero as a success code.
|
||||||
*/
|
*/
|
||||||
#ifdef CONFIG_LOCKDEP
|
#ifdef CONFIG_LOCKDEP
|
||||||
|
@ -509,8 +525,16 @@ extern int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
|
||||||
gpiochip_add_data_with_key(gc, data, &lock_key, \
|
gpiochip_add_data_with_key(gc, data, &lock_key, \
|
||||||
&request_key); \
|
&request_key); \
|
||||||
})
|
})
|
||||||
|
#define devm_gpiochip_add_data(dev, gc, data) ({ \
|
||||||
|
static struct lock_class_key lock_key; \
|
||||||
|
static struct lock_class_key request_key; \
|
||||||
|
devm_gpiochip_add_data_with_key(dev, gc, data, &lock_key, \
|
||||||
|
&request_key); \
|
||||||
|
})
|
||||||
#else
|
#else
|
||||||
#define gpiochip_add_data(gc, data) gpiochip_add_data_with_key(gc, data, NULL, NULL)
|
#define gpiochip_add_data(gc, data) gpiochip_add_data_with_key(gc, data, NULL, NULL)
|
||||||
|
#define devm_gpiochip_add_data(dev, gc, data) \
|
||||||
|
devm_gpiochip_add_data_with_key(dev, gc, data, NULL, NULL)
|
||||||
#endif /* CONFIG_LOCKDEP */
|
#endif /* CONFIG_LOCKDEP */
|
||||||
|
|
||||||
static inline int gpiochip_add(struct gpio_chip *gc)
|
static inline int gpiochip_add(struct gpio_chip *gc)
|
||||||
|
@ -518,8 +542,9 @@ static inline int gpiochip_add(struct gpio_chip *gc)
|
||||||
return gpiochip_add_data(gc, NULL);
|
return gpiochip_add_data(gc, NULL);
|
||||||
}
|
}
|
||||||
extern void gpiochip_remove(struct gpio_chip *gc);
|
extern void gpiochip_remove(struct gpio_chip *gc);
|
||||||
extern int devm_gpiochip_add_data(struct device *dev, struct gpio_chip *gc,
|
extern int devm_gpiochip_add_data_with_key(struct device *dev, struct gpio_chip *gc, void *data,
|
||||||
void *data);
|
struct lock_class_key *lock_key,
|
||||||
|
struct lock_class_key *request_key);
|
||||||
|
|
||||||
extern struct gpio_chip *gpiochip_find(void *data,
|
extern struct gpio_chip *gpiochip_find(void *data,
|
||||||
int (*match)(struct gpio_chip *gc, void *data));
|
int (*match)(struct gpio_chip *gc, void *data));
|
||||||
|
|
|
@ -8,7 +8,7 @@ struct gpio_regmap;
|
||||||
struct irq_domain;
|
struct irq_domain;
|
||||||
struct regmap;
|
struct regmap;
|
||||||
|
|
||||||
#define GPIO_REGMAP_ADDR_ZERO ((unsigned long)(-1))
|
#define GPIO_REGMAP_ADDR_ZERO ((unsigned int)(-1))
|
||||||
#define GPIO_REGMAP_ADDR(addr) ((addr) ? : GPIO_REGMAP_ADDR_ZERO)
|
#define GPIO_REGMAP_ADDR(addr) ((addr) ? : GPIO_REGMAP_ADDR_ZERO)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -71,8 +71,8 @@ enum {
|
||||||
* of a GPIO line
|
* of a GPIO line
|
||||||
* @info: updated line information
|
* @info: updated line information
|
||||||
* @timestamp: estimate of time of status change occurrence, in nanoseconds
|
* @timestamp: estimate of time of status change occurrence, in nanoseconds
|
||||||
* and GPIOLINE_CHANGED_CONFIG
|
|
||||||
* @event_type: one of GPIOLINE_CHANGED_REQUESTED, GPIOLINE_CHANGED_RELEASED
|
* @event_type: one of GPIOLINE_CHANGED_REQUESTED, GPIOLINE_CHANGED_RELEASED
|
||||||
|
* and GPIOLINE_CHANGED_CONFIG
|
||||||
*
|
*
|
||||||
* Note: struct gpioline_info embedded here has 32-bit alignment on its own,
|
* Note: struct gpioline_info embedded here has 32-bit alignment on its own,
|
||||||
* but it works fine with 64-bit alignment too. With its 72 byte size, we can
|
* but it works fine with 64-bit alignment too. With its 72 byte size, we can
|
||||||
|
|
|
@ -45,7 +45,7 @@ int monitor_device(const char *device_name,
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
ret = -errno;
|
ret = -errno;
|
||||||
fprintf(stderr, "Failed to open %s\n", chrdev_name);
|
fprintf(stderr, "Failed to open %s\n", chrdev_name);
|
||||||
goto exit_close_error;
|
goto exit_free_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
req.lineoffset = line;
|
req.lineoffset = line;
|
||||||
|
@ -117,6 +117,7 @@ int monitor_device(const char *device_name,
|
||||||
exit_close_error:
|
exit_close_error:
|
||||||
if (close(fd) == -1)
|
if (close(fd) == -1)
|
||||||
perror("Failed to close GPIO character device file");
|
perror("Failed to close GPIO character device file");
|
||||||
|
exit_free_name:
|
||||||
free(chrdev_name);
|
free(chrdev_name);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,7 @@ int gpiotools_request_linehandle(const char *device_name, unsigned int *lines,
|
||||||
ret = -errno;
|
ret = -errno;
|
||||||
fprintf(stderr, "Failed to open %s, %s\n",
|
fprintf(stderr, "Failed to open %s, %s\n",
|
||||||
chrdev_name, strerror(errno));
|
chrdev_name, strerror(errno));
|
||||||
goto exit_close_error;
|
goto exit_free_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < nlines; i++)
|
for (i = 0; i < nlines; i++)
|
||||||
|
@ -94,9 +94,9 @@ int gpiotools_request_linehandle(const char *device_name, unsigned int *lines,
|
||||||
"GPIO_GET_LINEHANDLE_IOCTL", ret, strerror(errno));
|
"GPIO_GET_LINEHANDLE_IOCTL", ret, strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
exit_close_error:
|
|
||||||
if (close(fd) == -1)
|
if (close(fd) == -1)
|
||||||
perror("Failed to close GPIO character device file");
|
perror("Failed to close GPIO character device file");
|
||||||
|
exit_free_name:
|
||||||
free(chrdev_name);
|
free(chrdev_name);
|
||||||
return ret < 0 ? ret : req.fd;
|
return ret < 0 ? ret : req.fd;
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,7 +94,7 @@ int list_device(const char *device_name)
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
ret = -errno;
|
ret = -errno;
|
||||||
fprintf(stderr, "Failed to open %s\n", chrdev_name);
|
fprintf(stderr, "Failed to open %s\n", chrdev_name);
|
||||||
goto exit_close_error;
|
goto exit_free_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Inspect this GPIO chip */
|
/* Inspect this GPIO chip */
|
||||||
|
@ -141,6 +141,7 @@ int list_device(const char *device_name)
|
||||||
exit_close_error:
|
exit_close_error:
|
||||||
if (close(fd) == -1)
|
if (close(fd) == -1)
|
||||||
perror("Failed to close GPIO character device file");
|
perror("Failed to close GPIO character device file");
|
||||||
|
exit_free_name:
|
||||||
free(chrdev_name);
|
free(chrdev_name);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue