Commit 1d8ce0e0 authored by Linus Torvalds's avatar Linus Torvalds

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'
  ...
parents 58552408 22cc4220
...@@ -19,6 +19,7 @@ Required properties: ...@@ -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
......
# 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: ...@@ -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: ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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. ...@@ -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] = { ...@@ -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) ...@@ -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) ...@@ -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] = { ...@@ -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) ...@@ -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) ...@@ -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] = { ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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;
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; 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,15 +509,10 @@ static int adnp_i2c_probe(struct i2c_client *client, ...@@ -503,15 +509,10 @@ 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,
if (err) of_property_read_bool(np, "interrupt-controller"));
return err;
if (of_find_property(np, "interrupt-controller", NULL)) {
err = adnp_irq_setup(adnp);
if (err) if (err)
return err; return err;
}
i2c_set_clientdata(client, adnp); i2c_set_clientdata(client, adnp);
......
...@@ -272,13 +272,24 @@ static irqreturn_t adp5588_irq_handler(int irq, void *devid) ...@@ -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) ...@@ -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 @@ ...@@ -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); ...@@ -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, ...@@ -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, '-');
if (last)
*last++ = '\0';
if (kstrtouint(first, 10, &first_index)) {
pr_err("Cannot parse GPIO index %s\n", first);
return -EINVAL;
} }
if (!last) { for_each_set_bit(i, bitmap, ARCH_NR_GPIOS) {
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); error = aggr_add_gpio(aggr, name, i, &n);
if (error) if (error)
return error; goto free_bitmap;
}
} }
name = get_arg(&args); name = get_arg(&args);
...@@ -167,10 +158,12 @@ static int aggr_parse(struct gpio_aggregator *aggr) ...@@ -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 @@ ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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;
retval = devm_gpiochip_add_data(&pdev->dev, &cg->chip, cg); 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) { if (retval) {
dev_warn(&pdev->dev, "add gpio chip error: %d\n", retval); dev_warn(&pdev->dev, "request irq failed: %d\n", retval);
return retval; return retval;
} }
gpiochip_irqchip_add_nested(&cg->chip, &crystalcove_irqchip, 0, retval = devm_gpiochip_add_data(&pdev->dev, &cg->chip, cg);
handle_simple_irq, IRQ_TYPE_NONE);
retval = request_threaded_irq(irq, NULL, crystalcove_gpio_irq_handler,
IRQF_ONESHOT, KBUILD_MODNAME, cg);
if (retval) { if (retval) {
dev_warn(&pdev->dev, "request irq failed: %d\n", retval); dev_warn(&pdev->dev, "add gpio chip error: %d\n", retval);
return 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) ...@@ -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) ...@@ -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) ...@@ -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 { ...@@ -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 */ ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 @@ ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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); ret = max732x_irq_setup(chip, id);
if (ret) if (ret)
return ret; return ret;
ret = max732x_irq_setup(chip, id); ret = devm_gpiochip_add_data(&client->dev, &chip->gpio_chip, chip);
if (ret) if (ret)
return ret; return ret;
if (pdata && pdata->setup) { 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 { ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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 { ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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,16 +270,12 @@ static void bgpio_multiple_get_masks(struct gpio_chip *gc, ...@@ -272,16 +270,12 @@ 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)
break;
if (__test_and_clear_bit(i, mask)) {
if (test_bit(i, bits)) if (test_bit(i, bits))
*set_mask |= bgpio_line2mask(gc, i); *set_mask |= bgpio_line2mask(gc, i);
else else
*clear_mask |= bgpio_line2mask(gc, i); *clear_mask |= bgpio_line2mask(gc, i);
} }
}
} }
static void bgpio_set_multiple_single_reg(struct gpio_chip *gc, static void bgpio_set_multiple_single_reg(struct gpio_chip *gc,
......
...@@ -417,7 +417,7 @@ static int mpc8xxx_probe(struct platform_device *pdev) ...@@ -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) ...@@ -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) ...@@ -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 { ...@@ -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, ...@@ -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); debounce = pinconf_to_config_argument(config);
return omap_gpio_debounce(chip, offset, debounce); ret = omap_gpio_debounce(chip, offset, debounce);
break;
default:
break;
}
return ret;
} }
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) ...@@ -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[] = { ...@@ -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) ...@@ -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,17 +865,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, int irq_base) ...@@ -863,17 +865,7 @@ 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);
ret = devm_request_threaded_irq(&client->dev, client->irq, irq_chip->name = dev_name(&client->dev);
NULL, pca953x_irq_handler,
IRQF_ONESHOT | IRQF_SHARED,
dev_name(&client->dev), chip);
if (ret) {
dev_err(&client->dev, "failed to request irq %d\n",
client->irq);
return ret;
}
irq_chip->name = dev_name(&chip->client->dev);
irq_chip->irq_mask = pca953x_irq_mask; irq_chip->irq_mask = pca953x_irq_mask;
irq_chip->irq_unmask = pca953x_irq_unmask; irq_chip->irq_unmask = pca953x_irq_unmask;
irq_chip->irq_set_wake = pca953x_irq_set_wake; irq_chip->irq_set_wake = pca953x_irq_set_wake;
...@@ -882,17 +874,27 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, int irq_base) ...@@ -882,17 +874,27 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, int irq_base)
irq_chip->irq_set_type = pca953x_irq_set_type; irq_chip->irq_set_type = pca953x_irq_set_type;
irq_chip->irq_shutdown = pca953x_irq_shutdown; irq_chip->irq_shutdown = pca953x_irq_shutdown;
ret = gpiochip_irqchip_add_nested(&chip->gpio_chip, irq_chip, girq = &chip->gpio_chip.irq;
irq_base, handle_simple_irq, girq->chip = irq_chip;
IRQ_TYPE_NONE); /* 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,
NULL, pca953x_irq_handler,
IRQF_ONESHOT | IRQF_SHARED,
dev_name(&client->dev), chip);
if (ret) { if (ret) {
dev_err(&client->dev, dev_err(&client->dev, "failed to request irq %d\n",
"could not connect irqchip to gpiochip\n"); client->irq);
return ret; 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, ...@@ -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[] = { ...@@ -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), },
......
// 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, ...@@ -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, ...@@ -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 { ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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, &reg_val, gpio_pins[chip->ioh]) for_each_set_bit(i, &reg_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] = { ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 { ...@@ -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) ...@@ -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) ...@@ -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 { ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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 { ...@@ -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, ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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, girq = &stmpe_gpio->chip.irq;
0, girq->chip = &stmpe_gpio_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(&pdev->dev, girq->parents = NULL;
"could not connect irqchip to gpiochip\n"); girq->default_type = IRQ_TYPE_NONE;
goto out_disable; girq->handler = handle_simple_irq;
girq->threaded = true;
} }
gpiochip_set_nested_irqchip(&stmpe_gpio->chip, ret = gpiochip_add_data(&stmpe_gpio->chip, stmpe_gpio);
&stmpe_gpio_irq_chip, if (ret) {
irq); 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 @@ ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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] = { ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 { ...@@ -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 { ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 = { ...@@ -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 = { ...@@ -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,6 +930,7 @@ static int zynq_gpio_probe(struct platform_device *pdev) ...@@ -876,6 +930,7 @@ 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)) {
if (PTR_ERR(gpio->clk) != -EPROBE_DEFER)
dev_err(&pdev->dev, "input clock not found.\n"); dev_err(&pdev->dev, "input clock not found.\n");
return PTR_ERR(gpio->clk); return PTR_ERR(gpio->clk);
} }
...@@ -885,6 +940,8 @@ static int zynq_gpio_probe(struct platform_device *pdev) ...@@ -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) ...@@ -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) ...@@ -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;
......
// SPDX-License-Identifier: GPL-2.0
#include <linux/anon_inodes.h>
#include <linux/bitmap.h>
#include <linux/cdev.h>
#include <linux/compat.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/file.h>
#include <linux/gpio.h>
#include <linux/gpio/driver.h>
#include <linux/interrupt.h>
#include <linux/irqreturn.h>
#include <linux/kernel.h>
#include <linux/kfifo.h>
#include <linux/module.h>
#include <linux/pinctrl/consumer.h>
#include <linux/poll.h>
#include <linux/spinlock.h>
#include <linux/timekeeping.h>
#include <linux/uaccess.h>
#include <uapi/linux/gpio.h>
#include "gpiolib.h"
#include "gpiolib-cdev.h"
/* Character device interface to GPIO.
*
* The GPIO character device, /dev/gpiochipN, provides userspace an
* interface to gpiolib GPIOs via ioctl()s.
*/
/*
* GPIO line handle management
*/
/**
* struct linehandle_state - contains the state of a userspace handle
* @gdev: the GPIO device the handle pertains to
* @label: consumer label used to tag descriptors
* @descs: the GPIO descriptors held by this handle
* @num_descs: the number of descriptors held in the descs array
*/
struct linehandle_state {
struct gpio_device *gdev;
const char *label;
struct gpio_desc *descs[GPIOHANDLES_MAX];
u32 num_descs;
};
#define GPIOHANDLE_REQUEST_VALID_FLAGS \
(GPIOHANDLE_REQUEST_INPUT | \
GPIOHANDLE_REQUEST_OUTPUT | \
GPIOHANDLE_REQUEST_ACTIVE_LOW | \
GPIOHANDLE_REQUEST_BIAS_PULL_UP | \
GPIOHANDLE_REQUEST_BIAS_PULL_DOWN | \
GPIOHANDLE_REQUEST_BIAS_DISABLE | \
GPIOHANDLE_REQUEST_OPEN_DRAIN | \
GPIOHANDLE_REQUEST_OPEN_SOURCE)
static int linehandle_validate_flags(u32 flags)
{
/* Return an error if an unknown flag is set */
if (flags & ~GPIOHANDLE_REQUEST_VALID_FLAGS)
return -EINVAL;
/*
* Do not allow both INPUT & OUTPUT flags to be set as they are
* contradictory.
*/
if ((flags & GPIOHANDLE_REQUEST_INPUT) &&
(flags & GPIOHANDLE_REQUEST_OUTPUT))
return -EINVAL;
/*
* Do not allow OPEN_SOURCE & OPEN_DRAIN flags in a single request. If
* the hardware actually supports enabling both at the same time the
* electrical result would be disastrous.
*/
if ((flags & GPIOHANDLE_REQUEST_OPEN_DRAIN) &&
(flags & GPIOHANDLE_REQUEST_OPEN_SOURCE))
return -EINVAL;
/* OPEN_DRAIN and OPEN_SOURCE flags only make sense for output mode. */
if (!(flags & GPIOHANDLE_REQUEST_OUTPUT) &&
((flags & GPIOHANDLE_REQUEST_OPEN_DRAIN) ||
(flags & GPIOHANDLE_REQUEST_OPEN_SOURCE)))
return -EINVAL;
/* Bias flags only allowed for input or output mode. */
if (!((flags & GPIOHANDLE_REQUEST_INPUT) ||
(flags & GPIOHANDLE_REQUEST_OUTPUT)) &&
((flags & GPIOHANDLE_REQUEST_BIAS_DISABLE) ||
(flags & GPIOHANDLE_REQUEST_BIAS_PULL_UP) ||
(flags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN)))
return -EINVAL;
/* Only one bias flag can be set. */
if (((flags & GPIOHANDLE_REQUEST_BIAS_DISABLE) &&
(flags & (GPIOHANDLE_REQUEST_BIAS_PULL_DOWN |
GPIOHANDLE_REQUEST_BIAS_PULL_UP))) ||
((flags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN) &&
(flags & GPIOHANDLE_REQUEST_BIAS_PULL_UP)))
return -EINVAL;
return 0;
}
static void linehandle_flags_to_desc_flags(u32 lflags, unsigned long *flagsp)
{
assign_bit(FLAG_ACTIVE_LOW, flagsp,
lflags & GPIOHANDLE_REQUEST_ACTIVE_LOW);
assign_bit(FLAG_OPEN_DRAIN, flagsp,
lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN);
assign_bit(FLAG_OPEN_SOURCE, flagsp,
lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE);
assign_bit(FLAG_PULL_UP, flagsp,
lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP);
assign_bit(FLAG_PULL_DOWN, flagsp,
lflags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN);
assign_bit(FLAG_BIAS_DISABLE, flagsp,
lflags & GPIOHANDLE_REQUEST_BIAS_DISABLE);
}
static long linehandle_set_config(struct linehandle_state *lh,
void __user *ip)
{
struct gpiohandle_config gcnf;
struct gpio_desc *desc;
int i, ret;
u32 lflags;
if (copy_from_user(&gcnf, ip, sizeof(gcnf)))
return -EFAULT;
lflags = gcnf.flags;
ret = linehandle_validate_flags(lflags);
if (ret)
return ret;
for (i = 0; i < lh->num_descs; i++) {
desc = lh->descs[i];
linehandle_flags_to_desc_flags(gcnf.flags, &desc->flags);
/*
* Lines have to be requested explicitly for input
* or output, else the line will be treated "as is".
*/
if (lflags & GPIOHANDLE_REQUEST_OUTPUT) {
int val = !!gcnf.default_values[i];
ret = gpiod_direction_output(desc, val);
if (ret)
return ret;
} else if (lflags & GPIOHANDLE_REQUEST_INPUT) {
ret = gpiod_direction_input(desc);
if (ret)
return ret;
}
blocking_notifier_call_chain(&desc->gdev->notifier,
GPIOLINE_CHANGED_CONFIG, desc);
}
return 0;
}
static long linehandle_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct linehandle_state *lh = file->private_data;
void __user *ip = (void __user *)arg;
struct gpiohandle_data ghd;
DECLARE_BITMAP(vals, GPIOHANDLES_MAX);
int i;
if (cmd == GPIOHANDLE_GET_LINE_VALUES_IOCTL) {
/* NOTE: It's ok to read values of output lines. */
int ret = gpiod_get_array_value_complex(false,
true,
lh->num_descs,
lh->descs,
NULL,
vals);
if (ret)
return ret;
memset(&ghd, 0, sizeof(ghd));
for (i = 0; i < lh->num_descs; i++)
ghd.values[i] = test_bit(i, vals);
if (copy_to_user(ip, &ghd, sizeof(ghd)))
return -EFAULT;
return 0;
} else if (cmd == GPIOHANDLE_SET_LINE_VALUES_IOCTL) {
/*
* All line descriptors were created at once with the same
* flags so just check if the first one is really output.
*/
if (!test_bit(FLAG_IS_OUT, &lh->descs[0]->flags))
return -EPERM;
if (copy_from_user(&ghd, ip, sizeof(ghd)))
return -EFAULT;
/* Clamp all values to [0,1] */
for (i = 0; i < lh->num_descs; i++)
__assign_bit(i, vals, ghd.values[i]);
/* Reuse the array setting function */
return gpiod_set_array_value_complex(false,
true,
lh->num_descs,
lh->descs,
NULL,
vals);
} else if (cmd == GPIOHANDLE_SET_CONFIG_IOCTL) {
return linehandle_set_config(lh, ip);
}
return -EINVAL;
}
#ifdef CONFIG_COMPAT
static long linehandle_ioctl_compat(struct file *file, unsigned int cmd,
unsigned long arg)
{
return linehandle_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
}
#endif
static void linehandle_free(struct linehandle_state *lh)
{
int i;
for (i = 0; i < lh->num_descs; i++)
if (lh->descs[i])
gpiod_free(lh->descs[i]);
kfree(lh->label);
put_device(&lh->gdev->dev);
kfree(lh);
}
static int linehandle_release(struct inode *inode, struct file *file)
{
linehandle_free(file->private_data);
return 0;
}
static const struct file_operations linehandle_fileops = {
.release = linehandle_release,
.owner = THIS_MODULE,
.llseek = noop_llseek,
.unlocked_ioctl = linehandle_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = linehandle_ioctl_compat,
#endif
};
static int linehandle_create(struct gpio_device *gdev, void __user *ip)
{
struct gpiohandle_request handlereq;
struct linehandle_state *lh;
struct file *file;
int fd, i, ret;
u32 lflags;
if (copy_from_user(&handlereq, ip, sizeof(handlereq)))
return -EFAULT;
if ((handlereq.lines == 0) || (handlereq.lines > GPIOHANDLES_MAX))
return -EINVAL;
lflags = handlereq.flags;
ret = linehandle_validate_flags(lflags);
if (ret)
return ret;
lh = kzalloc(sizeof(*lh), GFP_KERNEL);
if (!lh)
return -ENOMEM;
lh->gdev = gdev;
get_device(&gdev->dev);
/* Make sure this is terminated */
handlereq.consumer_label[sizeof(handlereq.consumer_label)-1] = '\0';
if (strlen(handlereq.consumer_label)) {
lh->label = kstrdup(handlereq.consumer_label,
GFP_KERNEL);
if (!lh->label) {
ret = -ENOMEM;
goto out_free_lh;
}
}
lh->num_descs = handlereq.lines;
/* Request each GPIO */
for (i = 0; i < handlereq.lines; i++) {
u32 offset = handlereq.lineoffsets[i];
struct gpio_desc *desc = gpiochip_get_desc(gdev->chip, offset);
if (IS_ERR(desc)) {
ret = PTR_ERR(desc);
goto out_free_lh;
}
ret = gpiod_request(desc, lh->label);
if (ret)
goto out_free_lh;
lh->descs[i] = desc;
linehandle_flags_to_desc_flags(handlereq.flags, &desc->flags);
ret = gpiod_set_transitory(desc, false);
if (ret < 0)
goto out_free_lh;
/*
* Lines have to be requested explicitly for input
* or output, else the line will be treated "as is".
*/
if (lflags & GPIOHANDLE_REQUEST_OUTPUT) {
int val = !!handlereq.default_values[i];
ret = gpiod_direction_output(desc, val);
if (ret)
goto out_free_lh;
} else if (lflags & GPIOHANDLE_REQUEST_INPUT) {
ret = gpiod_direction_input(desc);
if (ret)
goto out_free_lh;
}
blocking_notifier_call_chain(&desc->gdev->notifier,
GPIOLINE_CHANGED_REQUESTED, desc);
dev_dbg(&gdev->dev, "registered chardev handle for line %d\n",
offset);
}
fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC);
if (fd < 0) {
ret = fd;
goto out_free_lh;
}
file = anon_inode_getfile("gpio-linehandle",
&linehandle_fileops,
lh,
O_RDONLY | O_CLOEXEC);
if (IS_ERR(file)) {
ret = PTR_ERR(file);
goto out_put_unused_fd;
}
handlereq.fd = fd;
if (copy_to_user(ip, &handlereq, sizeof(handlereq))) {
/*
* fput() will trigger the release() callback, so do not go onto
* the regular error cleanup path here.
*/
fput(file);
put_unused_fd(fd);
return -EFAULT;
}
fd_install(fd, file);
dev_dbg(&gdev->dev, "registered chardev handle for %d lines\n",
lh->num_descs);
return 0;
out_put_unused_fd:
put_unused_fd(fd);
out_free_lh:
linehandle_free(lh);
return ret;
}
/*
* GPIO line event management
*/
/**
* struct lineevent_state - contains the state of a userspace event
* @gdev: the GPIO device the event pertains to
* @label: consumer label used to tag descriptors
* @desc: the GPIO descriptor held by this event
* @eflags: the event flags this line was requested with
* @irq: the interrupt that trigger in response to events on this GPIO
* @wait: wait queue that handles blocking reads of events
* @events: KFIFO for the GPIO events
* @timestamp: cache for the timestamp storing it between hardirq
* and IRQ thread, used to bring the timestamp close to the actual
* event
*/
struct lineevent_state {
struct gpio_device *gdev;
const char *label;
struct gpio_desc *desc;
u32 eflags;
int irq;
wait_queue_head_t wait;
DECLARE_KFIFO(events, struct gpioevent_data, 16);
u64 timestamp;
};
#define GPIOEVENT_REQUEST_VALID_FLAGS \
(GPIOEVENT_REQUEST_RISING_EDGE | \
GPIOEVENT_REQUEST_FALLING_EDGE)
static __poll_t lineevent_poll(struct file *file,
struct poll_table_struct *wait)
{
struct lineevent_state *le = file->private_data;
__poll_t events = 0;
poll_wait(file, &le->wait, wait);
if (!kfifo_is_empty_spinlocked_noirqsave(&le->events, &le->wait.lock))
events = EPOLLIN | EPOLLRDNORM;
return events;
}
static ssize_t lineevent_read(struct file *file,
char __user *buf,
size_t count,
loff_t *f_ps)
{
struct lineevent_state *le = file->private_data;
struct gpioevent_data ge;
ssize_t bytes_read = 0;
int ret;
if (count < sizeof(ge))
return -EINVAL;
do {
spin_lock(&le->wait.lock);
if (kfifo_is_empty(&le->events)) {
if (bytes_read) {
spin_unlock(&le->wait.lock);
return bytes_read;
}
if (file->f_flags & O_NONBLOCK) {
spin_unlock(&le->wait.lock);
return -EAGAIN;
}
ret = wait_event_interruptible_locked(le->wait,
!kfifo_is_empty(&le->events));
if (ret) {
spin_unlock(&le->wait.lock);
return ret;
}
}
ret = kfifo_out(&le->events, &ge, 1);
spin_unlock(&le->wait.lock);
if (ret != 1) {
/*
* This should never happen - we were holding the lock
* from the moment we learned the fifo is no longer
* empty until now.
*/
ret = -EIO;
break;
}
if (copy_to_user(buf + bytes_read, &ge, sizeof(ge)))
return -EFAULT;
bytes_read += sizeof(ge);
} while (count >= bytes_read + sizeof(ge));
return bytes_read;
}
static void lineevent_free(struct lineevent_state *le)
{
if (le->irq)
free_irq(le->irq, le);
if (le->desc)
gpiod_free(le->desc);
kfree(le->label);
put_device(&le->gdev->dev);
kfree(le);
}
static int lineevent_release(struct inode *inode, struct file *file)
{
lineevent_free(file->private_data);
return 0;
}
static long lineevent_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct lineevent_state *le = file->private_data;
void __user *ip = (void __user *)arg;
struct gpiohandle_data ghd;
/*
* We can get the value for an event line but not set it,
* because it is input by definition.
*/
if (cmd == GPIOHANDLE_GET_LINE_VALUES_IOCTL) {
int val;
memset(&ghd, 0, sizeof(ghd));
val = gpiod_get_value_cansleep(le->desc);
if (val < 0)
return val;
ghd.values[0] = val;
if (copy_to_user(ip, &ghd, sizeof(ghd)))
return -EFAULT;
return 0;
}
return -EINVAL;
}
#ifdef CONFIG_COMPAT
static long lineevent_ioctl_compat(struct file *file, unsigned int cmd,
unsigned long arg)
{
return lineevent_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
}
#endif
static const struct file_operations lineevent_fileops = {
.release = lineevent_release,
.read = lineevent_read,
.poll = lineevent_poll,
.owner = THIS_MODULE,
.llseek = noop_llseek,
.unlocked_ioctl = lineevent_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = lineevent_ioctl_compat,
#endif
};
static irqreturn_t lineevent_irq_thread(int irq, void *p)
{
struct lineevent_state *le = p;
struct gpioevent_data ge;
int ret;
/* Do not leak kernel stack to userspace */
memset(&ge, 0, sizeof(ge));
/*
* We may be running from a nested threaded interrupt in which case
* we didn't get the timestamp from lineevent_irq_handler().
*/
if (!le->timestamp)
ge.timestamp = ktime_get_ns();
else
ge.timestamp = le->timestamp;
if (le->eflags & GPIOEVENT_REQUEST_RISING_EDGE
&& le->eflags & GPIOEVENT_REQUEST_FALLING_EDGE) {
int level = gpiod_get_value_cansleep(le->desc);
if (level)
/* Emit low-to-high event */
ge.id = GPIOEVENT_EVENT_RISING_EDGE;
else
/* Emit high-to-low event */
ge.id = GPIOEVENT_EVENT_FALLING_EDGE;
} else if (le->eflags & GPIOEVENT_REQUEST_RISING_EDGE) {
/* Emit low-to-high event */
ge.id = GPIOEVENT_EVENT_RISING_EDGE;
} else if (le->eflags & GPIOEVENT_REQUEST_FALLING_EDGE) {
/* Emit high-to-low event */
ge.id = GPIOEVENT_EVENT_FALLING_EDGE;
} else {
return IRQ_NONE;
}
ret = kfifo_in_spinlocked_noirqsave(&le->events, &ge,
1, &le->wait.lock);
if (ret)
wake_up_poll(&le->wait, EPOLLIN);
else
pr_debug_ratelimited("event FIFO is full - event dropped\n");
return IRQ_HANDLED;
}
static irqreturn_t lineevent_irq_handler(int irq, void *p)
{
struct lineevent_state *le = p;
/*
* Just store the timestamp in hardirq context so we get it as
* close in time as possible to the actual event.
*/
le->timestamp = ktime_get_ns();
return IRQ_WAKE_THREAD;
}
static int lineevent_create(struct gpio_device *gdev, void __user *ip)
{
struct gpioevent_request eventreq;
struct lineevent_state *le;
struct gpio_desc *desc;
struct file *file;
u32 offset;
u32 lflags;
u32 eflags;
int fd;
int ret;
int irq, irqflags = 0;
if (copy_from_user(&eventreq, ip, sizeof(eventreq)))
return -EFAULT;
offset = eventreq.lineoffset;
lflags = eventreq.handleflags;
eflags = eventreq.eventflags;
desc = gpiochip_get_desc(gdev->chip, offset);
if (IS_ERR(desc))
return PTR_ERR(desc);
/* Return an error if a unknown flag is set */
if ((lflags & ~GPIOHANDLE_REQUEST_VALID_FLAGS) ||
(eflags & ~GPIOEVENT_REQUEST_VALID_FLAGS))
return -EINVAL;
/* This is just wrong: we don't look for events on output lines */
if ((lflags & GPIOHANDLE_REQUEST_OUTPUT) ||
(lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN) ||
(lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE))
return -EINVAL;
/* Only one bias flag can be set. */
if (((lflags & GPIOHANDLE_REQUEST_BIAS_DISABLE) &&
(lflags & (GPIOHANDLE_REQUEST_BIAS_PULL_DOWN |
GPIOHANDLE_REQUEST_BIAS_PULL_UP))) ||
((lflags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN) &&
(lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP)))
return -EINVAL;
le = kzalloc(sizeof(*le), GFP_KERNEL);
if (!le)
return -ENOMEM;
le->gdev = gdev;
get_device(&gdev->dev);
/* Make sure this is terminated */
eventreq.consumer_label[sizeof(eventreq.consumer_label)-1] = '\0';
if (strlen(eventreq.consumer_label)) {
le->label = kstrdup(eventreq.consumer_label,
GFP_KERNEL);
if (!le->label) {
ret = -ENOMEM;
goto out_free_le;
}
}
ret = gpiod_request(desc, le->label);
if (ret)
goto out_free_le;
le->desc = desc;
le->eflags = eflags;
linehandle_flags_to_desc_flags(lflags, &desc->flags);
ret = gpiod_direction_input(desc);
if (ret)
goto out_free_le;
blocking_notifier_call_chain(&desc->gdev->notifier,
GPIOLINE_CHANGED_REQUESTED, desc);
irq = gpiod_to_irq(desc);
if (irq <= 0) {
ret = -ENODEV;
goto out_free_le;
}
le->irq = irq;
if (eflags & GPIOEVENT_REQUEST_RISING_EDGE)
irqflags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ?
IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;
if (eflags & GPIOEVENT_REQUEST_FALLING_EDGE)
irqflags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ?
IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING;
irqflags |= IRQF_ONESHOT;
INIT_KFIFO(le->events);
init_waitqueue_head(&le->wait);
/* Request a thread to read the events */
ret = request_threaded_irq(le->irq,
lineevent_irq_handler,
lineevent_irq_thread,
irqflags,
le->label,
le);
if (ret)
goto out_free_le;
fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC);
if (fd < 0) {
ret = fd;
goto out_free_le;
}
file = anon_inode_getfile("gpio-event",
&lineevent_fileops,
le,
O_RDONLY | O_CLOEXEC);
if (IS_ERR(file)) {
ret = PTR_ERR(file);
goto out_put_unused_fd;
}
eventreq.fd = fd;
if (copy_to_user(ip, &eventreq, sizeof(eventreq))) {
/*
* fput() will trigger the release() callback, so do not go onto
* the regular error cleanup path here.
*/
fput(file);
put_unused_fd(fd);
return -EFAULT;
}
fd_install(fd, file);
return 0;
out_put_unused_fd:
put_unused_fd(fd);
out_free_le:
lineevent_free(le);
return ret;
}
static void gpio_desc_to_lineinfo(struct gpio_desc *desc,
struct gpioline_info *info)
{
struct gpio_chip *gc = desc->gdev->chip;
bool ok_for_pinctrl;
unsigned long flags;
/*
* This function takes a mutex so we must check this before taking
* the spinlock.
*
* FIXME: find a non-racy way to retrieve this information. Maybe a
* lock common to both frameworks?
*/
ok_for_pinctrl =
pinctrl_gpio_can_use_line(gc->base + info->line_offset);
spin_lock_irqsave(&gpio_lock, flags);
if (desc->name) {
strncpy(info->name, desc->name, sizeof(info->name));
info->name[sizeof(info->name) - 1] = '\0';
} else {
info->name[0] = '\0';
}
if (desc->label) {
strncpy(info->consumer, desc->label, sizeof(info->consumer));
info->consumer[sizeof(info->consumer) - 1] = '\0';
} else {
info->consumer[0] = '\0';
}
/*
* Userspace only need to know that the kernel is using this GPIO so
* it can't use it.
*/
info->flags = 0;
if (test_bit(FLAG_REQUESTED, &desc->flags) ||
test_bit(FLAG_IS_HOGGED, &desc->flags) ||
test_bit(FLAG_USED_AS_IRQ, &desc->flags) ||
test_bit(FLAG_EXPORT, &desc->flags) ||
test_bit(FLAG_SYSFS, &desc->flags) ||
!ok_for_pinctrl)
info->flags |= GPIOLINE_FLAG_KERNEL;
if (test_bit(FLAG_IS_OUT, &desc->flags))
info->flags |= GPIOLINE_FLAG_IS_OUT;
if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
info->flags |= GPIOLINE_FLAG_ACTIVE_LOW;
if (test_bit(FLAG_OPEN_DRAIN, &desc->flags))
info->flags |= (GPIOLINE_FLAG_OPEN_DRAIN |
GPIOLINE_FLAG_IS_OUT);
if (test_bit(FLAG_OPEN_SOURCE, &desc->flags))
info->flags |= (GPIOLINE_FLAG_OPEN_SOURCE |
GPIOLINE_FLAG_IS_OUT);
if (test_bit(FLAG_BIAS_DISABLE, &desc->flags))
info->flags |= GPIOLINE_FLAG_BIAS_DISABLE;
if (test_bit(FLAG_PULL_DOWN, &desc->flags))
info->flags |= GPIOLINE_FLAG_BIAS_PULL_DOWN;
if (test_bit(FLAG_PULL_UP, &desc->flags))
info->flags |= GPIOLINE_FLAG_BIAS_PULL_UP;
spin_unlock_irqrestore(&gpio_lock, flags);
}
struct gpio_chardev_data {
struct gpio_device *gdev;
wait_queue_head_t wait;
DECLARE_KFIFO(events, struct gpioline_info_changed, 32);
struct notifier_block lineinfo_changed_nb;
unsigned long *watched_lines;
};
/*
* gpio_ioctl() - ioctl handler for the GPIO chardev
*/
static long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct gpio_chardev_data *cdev = file->private_data;
struct gpio_device *gdev = cdev->gdev;
struct gpio_chip *gc = gdev->chip;
void __user *ip = (void __user *)arg;
struct gpio_desc *desc;
__u32 offset;
/* We fail any subsequent ioctl():s when the chip is gone */
if (!gc)
return -ENODEV;
/* Fill in the struct and pass to userspace */
if (cmd == GPIO_GET_CHIPINFO_IOCTL) {
struct gpiochip_info chipinfo;
memset(&chipinfo, 0, sizeof(chipinfo));
strncpy(chipinfo.name, dev_name(&gdev->dev),
sizeof(chipinfo.name));
chipinfo.name[sizeof(chipinfo.name)-1] = '\0';
strncpy(chipinfo.label, gdev->label,
sizeof(chipinfo.label));
chipinfo.label[sizeof(chipinfo.label)-1] = '\0';
chipinfo.lines = gdev->ngpio;
if (copy_to_user(ip, &chipinfo, sizeof(chipinfo)))
return -EFAULT;
return 0;
} else if (cmd == GPIO_GET_LINEINFO_IOCTL) {
struct gpioline_info lineinfo;
if (copy_from_user(&lineinfo, ip, sizeof(lineinfo)))
return -EFAULT;
/* this doubles as a range check on line_offset */
desc = gpiochip_get_desc(gc, lineinfo.line_offset);
if (IS_ERR(desc))
return PTR_ERR(desc);
gpio_desc_to_lineinfo(desc, &lineinfo);
if (copy_to_user(ip, &lineinfo, sizeof(lineinfo)))
return -EFAULT;
return 0;
} else if (cmd == GPIO_GET_LINEHANDLE_IOCTL) {
return linehandle_create(gdev, ip);
} else if (cmd == GPIO_GET_LINEEVENT_IOCTL) {
return lineevent_create(gdev, ip);
} else if (cmd == GPIO_GET_LINEINFO_WATCH_IOCTL) {
struct gpioline_info lineinfo;
if (copy_from_user(&lineinfo, ip, sizeof(lineinfo)))
return -EFAULT;
/* this doubles as a range check on line_offset */
desc = gpiochip_get_desc(gc, lineinfo.line_offset);
if (IS_ERR(desc))
return PTR_ERR(desc);
if (test_and_set_bit(lineinfo.line_offset, cdev->watched_lines))
return -EBUSY;
gpio_desc_to_lineinfo(desc, &lineinfo);
if (copy_to_user(ip, &lineinfo, sizeof(lineinfo))) {
clear_bit(lineinfo.line_offset, cdev->watched_lines);
return -EFAULT;
}
return 0;
} else if (cmd == GPIO_GET_LINEINFO_UNWATCH_IOCTL) {
if (copy_from_user(&offset, ip, sizeof(offset)))
return -EFAULT;
if (offset >= cdev->gdev->ngpio)
return -EINVAL;
if (!test_and_clear_bit(offset, cdev->watched_lines))
return -EBUSY;
return 0;
}
return -EINVAL;
}
#ifdef CONFIG_COMPAT
static long gpio_ioctl_compat(struct file *file, unsigned int cmd,
unsigned long arg)
{
return gpio_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
}
#endif
static struct gpio_chardev_data *
to_gpio_chardev_data(struct notifier_block *nb)
{
return container_of(nb, struct gpio_chardev_data, lineinfo_changed_nb);
}
static int lineinfo_changed_notify(struct notifier_block *nb,
unsigned long action, void *data)
{
struct gpio_chardev_data *cdev = to_gpio_chardev_data(nb);
struct gpioline_info_changed chg;
struct gpio_desc *desc = data;
int ret;
if (!test_bit(gpio_chip_hwgpio(desc), cdev->watched_lines))
return NOTIFY_DONE;
memset(&chg, 0, sizeof(chg));
chg.info.line_offset = gpio_chip_hwgpio(desc);
chg.event_type = action;
chg.timestamp = ktime_get_ns();
gpio_desc_to_lineinfo(desc, &chg.info);
ret = kfifo_in_spinlocked(&cdev->events, &chg, 1, &cdev->wait.lock);
if (ret)
wake_up_poll(&cdev->wait, EPOLLIN);
else
pr_debug_ratelimited("lineinfo event FIFO is full - event dropped\n");
return NOTIFY_OK;
}
static __poll_t lineinfo_watch_poll(struct file *file,
struct poll_table_struct *pollt)
{
struct gpio_chardev_data *cdev = file->private_data;
__poll_t events = 0;
poll_wait(file, &cdev->wait, pollt);
if (!kfifo_is_empty_spinlocked_noirqsave(&cdev->events,
&cdev->wait.lock))
events = EPOLLIN | EPOLLRDNORM;
return events;
}
static ssize_t lineinfo_watch_read(struct file *file, char __user *buf,
size_t count, loff_t *off)
{
struct gpio_chardev_data *cdev = file->private_data;
struct gpioline_info_changed event;
ssize_t bytes_read = 0;
int ret;
if (count < sizeof(event))
return -EINVAL;
do {
spin_lock(&cdev->wait.lock);
if (kfifo_is_empty(&cdev->events)) {
if (bytes_read) {
spin_unlock(&cdev->wait.lock);
return bytes_read;
}
if (file->f_flags & O_NONBLOCK) {
spin_unlock(&cdev->wait.lock);
return -EAGAIN;
}
ret = wait_event_interruptible_locked(cdev->wait,
!kfifo_is_empty(&cdev->events));
if (ret) {
spin_unlock(&cdev->wait.lock);
return ret;
}
}
ret = kfifo_out(&cdev->events, &event, 1);
spin_unlock(&cdev->wait.lock);
if (ret != 1) {
ret = -EIO;
break;
/* We should never get here. See lineevent_read(). */
}
if (copy_to_user(buf + bytes_read, &event, sizeof(event)))
return -EFAULT;
bytes_read += sizeof(event);
} while (count >= bytes_read + sizeof(event));
return bytes_read;
}
/**
* gpio_chrdev_open() - open the chardev for ioctl operations
* @inode: inode for this chardev
* @file: file struct for storing private data
* Returns 0 on success
*/
static int gpio_chrdev_open(struct inode *inode, struct file *file)
{
struct gpio_device *gdev = container_of(inode->i_cdev,
struct gpio_device, chrdev);
struct gpio_chardev_data *cdev;
int ret = -ENOMEM;
/* Fail on open if the backing gpiochip is gone */
if (!gdev->chip)
return -ENODEV;
cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
if (!cdev)
return -ENOMEM;
cdev->watched_lines = bitmap_zalloc(gdev->chip->ngpio, GFP_KERNEL);
if (!cdev->watched_lines)
goto out_free_cdev;
init_waitqueue_head(&cdev->wait);
INIT_KFIFO(cdev->events);
cdev->gdev = gdev;
cdev->lineinfo_changed_nb.notifier_call = lineinfo_changed_notify;
ret = blocking_notifier_chain_register(&gdev->notifier,
&cdev->lineinfo_changed_nb);
if (ret)
goto out_free_bitmap;
get_device(&gdev->dev);
file->private_data = cdev;
ret = nonseekable_open(inode, file);
if (ret)
goto out_unregister_notifier;
return ret;
out_unregister_notifier:
blocking_notifier_chain_unregister(&gdev->notifier,
&cdev->lineinfo_changed_nb);
out_free_bitmap:
bitmap_free(cdev->watched_lines);
out_free_cdev:
kfree(cdev);
return ret;
}
/**
* gpio_chrdev_release() - close chardev after ioctl operations
* @inode: inode for this chardev
* @file: file struct for storing private data
* Returns 0 on success
*/
static int gpio_chrdev_release(struct inode *inode, struct file *file)
{
struct gpio_chardev_data *cdev = file->private_data;
struct gpio_device *gdev = cdev->gdev;
bitmap_free(cdev->watched_lines);
blocking_notifier_chain_unregister(&gdev->notifier,
&cdev->lineinfo_changed_nb);
put_device(&gdev->dev);
kfree(cdev);
return 0;
}
static const struct file_operations gpio_fileops = {
.release = gpio_chrdev_release,
.open = gpio_chrdev_open,
.poll = lineinfo_watch_poll,
.read = lineinfo_watch_read,
.owner = THIS_MODULE,
.llseek = no_llseek,
.unlocked_ioctl = gpio_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = gpio_ioctl_compat,
#endif
};
int gpiolib_cdev_register(struct gpio_device *gdev, dev_t devt)
{
int ret;
cdev_init(&gdev->chrdev, &gpio_fileops);
gdev->chrdev.owner = THIS_MODULE;
gdev->dev.devt = MKDEV(MAJOR(devt), gdev->id);
ret = cdev_device_add(&gdev->chrdev, &gdev->dev);
if (ret)
return ret;
chip_dbg(gdev->chip, "added GPIO chardev (%d:%d)\n",
MAJOR(devt), gdev->id);
return 0;
}
void gpiolib_cdev_unregister(struct gpio_device *gdev)
{
cdev_device_del(&gdev->chrdev, &gdev->dev);
}
/* 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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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 @@ ...@@ -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 @@ ...@@ -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); ...@@ -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;
......
/* 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 */
...@@ -17,20 +17,16 @@ ...@@ -17,20 +17,16 @@
#include <linux/gpio/driver.h> #include <linux/gpio/driver.h>
#include <linux/gpio/machine.h> #include <linux/gpio/machine.h>
#include <linux/pinctrl/consumer.h> #include <linux/pinctrl/consumer.h>
#include <linux/cdev.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/compat.h> #include <linux/compat.h>
#include <linux/anon_inodes.h>
#include <linux/file.h> #include <linux/file.h>
#include <linux/kfifo.h>
#include <linux/poll.h>
#include <linux/timekeeping.h>
#include <uapi/linux/gpio.h> #include <uapi/linux/gpio.h>
#include "gpiolib.h" #include "gpiolib.h"
#include "gpiolib-of.h" #include "gpiolib-of.h"
#include "gpiolib-acpi.h" #include "gpiolib-acpi.h"
#include "gpiolib-cdev.h"
#include "gpiolib-sysfs.h"
#define CREATE_TRACE_POINTS #define CREATE_TRACE_POINTS
#include <trace/events/gpio.h> #include <trace/events/gpio.h>
...@@ -425,1105 +421,6 @@ bool gpiochip_line_is_valid(const struct gpio_chip *gc, ...@@ -425,1105 +421,6 @@ bool gpiochip_line_is_valid(const struct gpio_chip *gc,
} }
EXPORT_SYMBOL_GPL(gpiochip_line_is_valid); EXPORT_SYMBOL_GPL(gpiochip_line_is_valid);
/*
* GPIO line handle management
*/
/**
* struct linehandle_state - contains the state of a userspace handle
* @gdev: the GPIO device the handle pertains to
* @label: consumer label used to tag descriptors
* @descs: the GPIO descriptors held by this handle
* @numdescs: the number of descriptors held in the descs array
*/
struct linehandle_state {
struct gpio_device *gdev;
const char *label;
struct gpio_desc *descs[GPIOHANDLES_MAX];
u32 numdescs;
};
#define GPIOHANDLE_REQUEST_VALID_FLAGS \
(GPIOHANDLE_REQUEST_INPUT | \
GPIOHANDLE_REQUEST_OUTPUT | \
GPIOHANDLE_REQUEST_ACTIVE_LOW | \
GPIOHANDLE_REQUEST_BIAS_PULL_UP | \
GPIOHANDLE_REQUEST_BIAS_PULL_DOWN | \
GPIOHANDLE_REQUEST_BIAS_DISABLE | \
GPIOHANDLE_REQUEST_OPEN_DRAIN | \
GPIOHANDLE_REQUEST_OPEN_SOURCE)
static int linehandle_validate_flags(u32 flags)
{
/* Return an error if an unknown flag is set */
if (flags & ~GPIOHANDLE_REQUEST_VALID_FLAGS)
return -EINVAL;
/*
* Do not allow both INPUT & OUTPUT flags to be set as they are
* contradictory.
*/
if ((flags & GPIOHANDLE_REQUEST_INPUT) &&
(flags & GPIOHANDLE_REQUEST_OUTPUT))
return -EINVAL;
/*
* Do not allow OPEN_SOURCE & OPEN_DRAIN flags in a single request. If
* the hardware actually supports enabling both at the same time the
* electrical result would be disastrous.
*/
if ((flags & GPIOHANDLE_REQUEST_OPEN_DRAIN) &&
(flags & GPIOHANDLE_REQUEST_OPEN_SOURCE))
return -EINVAL;
/* OPEN_DRAIN and OPEN_SOURCE flags only make sense for output mode. */
if (!(flags & GPIOHANDLE_REQUEST_OUTPUT) &&
((flags & GPIOHANDLE_REQUEST_OPEN_DRAIN) ||
(flags & GPIOHANDLE_REQUEST_OPEN_SOURCE)))
return -EINVAL;
/* Bias flags only allowed for input or output mode. */
if (!((flags & GPIOHANDLE_REQUEST_INPUT) ||
(flags & GPIOHANDLE_REQUEST_OUTPUT)) &&
((flags & GPIOHANDLE_REQUEST_BIAS_DISABLE) ||
(flags & GPIOHANDLE_REQUEST_BIAS_PULL_UP) ||
(flags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN)))
return -EINVAL;
/* Only one bias flag can be set. */
if (((flags & GPIOHANDLE_REQUEST_BIAS_DISABLE) &&
(flags & (GPIOHANDLE_REQUEST_BIAS_PULL_DOWN |
GPIOHANDLE_REQUEST_BIAS_PULL_UP))) ||
((flags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN) &&
(flags & GPIOHANDLE_REQUEST_BIAS_PULL_UP)))
return -EINVAL;
return 0;
}
static long linehandle_set_config(struct linehandle_state *lh,
void __user *ip)
{
struct gpiohandle_config gcnf;
struct gpio_desc *desc;
int i, ret;
u32 lflags;
unsigned long *flagsp;
if (copy_from_user(&gcnf, ip, sizeof(gcnf)))
return -EFAULT;
lflags = gcnf.flags;
ret = linehandle_validate_flags(lflags);
if (ret)
return ret;
for (i = 0; i < lh->numdescs; i++) {
desc = lh->descs[i];
flagsp = &desc->flags;
assign_bit(FLAG_ACTIVE_LOW, flagsp,
lflags & GPIOHANDLE_REQUEST_ACTIVE_LOW);
assign_bit(FLAG_OPEN_DRAIN, flagsp,
lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN);
assign_bit(FLAG_OPEN_SOURCE, flagsp,
lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE);
assign_bit(FLAG_PULL_UP, flagsp,
lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP);
assign_bit(FLAG_PULL_DOWN, flagsp,
lflags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN);
assign_bit(FLAG_BIAS_DISABLE, flagsp,
lflags & GPIOHANDLE_REQUEST_BIAS_DISABLE);
/*
* Lines have to be requested explicitly for input
* or output, else the line will be treated "as is".
*/
if (lflags & GPIOHANDLE_REQUEST_OUTPUT) {
int val = !!gcnf.default_values[i];
ret = gpiod_direction_output(desc, val);
if (ret)
return ret;
} else if (lflags & GPIOHANDLE_REQUEST_INPUT) {
ret = gpiod_direction_input(desc);
if (ret)
return ret;
}
atomic_notifier_call_chain(&desc->gdev->notifier,
GPIOLINE_CHANGED_CONFIG, desc);
}
return 0;
}
static long linehandle_ioctl(struct file *filep, unsigned int cmd,
unsigned long arg)
{
struct linehandle_state *lh = filep->private_data;
void __user *ip = (void __user *)arg;
struct gpiohandle_data ghd;
DECLARE_BITMAP(vals, GPIOHANDLES_MAX);
int i;
if (cmd == GPIOHANDLE_GET_LINE_VALUES_IOCTL) {
/* NOTE: It's ok to read values of output lines. */
int ret = gpiod_get_array_value_complex(false,
true,
lh->numdescs,
lh->descs,
NULL,
vals);
if (ret)
return ret;
memset(&ghd, 0, sizeof(ghd));
for (i = 0; i < lh->numdescs; i++)
ghd.values[i] = test_bit(i, vals);
if (copy_to_user(ip, &ghd, sizeof(ghd)))
return -EFAULT;
return 0;
} else if (cmd == GPIOHANDLE_SET_LINE_VALUES_IOCTL) {
/*
* All line descriptors were created at once with the same
* flags so just check if the first one is really output.
*/
if (!test_bit(FLAG_IS_OUT, &lh->descs[0]->flags))
return -EPERM;
if (copy_from_user(&ghd, ip, sizeof(ghd)))
return -EFAULT;
/* Clamp all values to [0,1] */
for (i = 0; i < lh->numdescs; i++)
__assign_bit(i, vals, ghd.values[i]);
/* Reuse the array setting function */
return gpiod_set_array_value_complex(false,
true,
lh->numdescs,
lh->descs,
NULL,
vals);
} else if (cmd == GPIOHANDLE_SET_CONFIG_IOCTL) {
return linehandle_set_config(lh, ip);
}
return -EINVAL;
}
#ifdef CONFIG_COMPAT
static long linehandle_ioctl_compat(struct file *filep, unsigned int cmd,
unsigned long arg)
{
return linehandle_ioctl(filep, cmd, (unsigned long)compat_ptr(arg));
}
#endif
static int linehandle_release(struct inode *inode, struct file *filep)
{
struct linehandle_state *lh = filep->private_data;
struct gpio_device *gdev = lh->gdev;
int i;
for (i = 0; i < lh->numdescs; i++)
gpiod_free(lh->descs[i]);
kfree(lh->label);
kfree(lh);
put_device(&gdev->dev);
return 0;
}
static const struct file_operations linehandle_fileops = {
.release = linehandle_release,
.owner = THIS_MODULE,
.llseek = noop_llseek,
.unlocked_ioctl = linehandle_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = linehandle_ioctl_compat,
#endif
};
static int linehandle_create(struct gpio_device *gdev, void __user *ip)
{
struct gpiohandle_request handlereq;
struct linehandle_state *lh;
struct file *file;
int fd, i, count = 0, ret;
u32 lflags;
if (copy_from_user(&handlereq, ip, sizeof(handlereq)))
return -EFAULT;
if ((handlereq.lines == 0) || (handlereq.lines > GPIOHANDLES_MAX))
return -EINVAL;
lflags = handlereq.flags;
ret = linehandle_validate_flags(lflags);
if (ret)
return ret;
lh = kzalloc(sizeof(*lh), GFP_KERNEL);
if (!lh)
return -ENOMEM;
lh->gdev = gdev;
get_device(&gdev->dev);
/* Make sure this is terminated */
handlereq.consumer_label[sizeof(handlereq.consumer_label)-1] = '\0';
if (strlen(handlereq.consumer_label)) {
lh->label = kstrdup(handlereq.consumer_label,
GFP_KERNEL);
if (!lh->label) {
ret = -ENOMEM;
goto out_free_lh;
}
}
/* Request each GPIO */
for (i = 0; i < handlereq.lines; i++) {
u32 offset = handlereq.lineoffsets[i];
struct gpio_desc *desc = gpiochip_get_desc(gdev->chip, offset);
if (IS_ERR(desc)) {
ret = PTR_ERR(desc);
goto out_free_descs;
}
ret = gpiod_request(desc, lh->label);
if (ret)
goto out_free_descs;
lh->descs[i] = desc;
count = i + 1;
if (lflags & GPIOHANDLE_REQUEST_ACTIVE_LOW)
set_bit(FLAG_ACTIVE_LOW, &desc->flags);
if (lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN)
set_bit(FLAG_OPEN_DRAIN, &desc->flags);
if (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE)
set_bit(FLAG_OPEN_SOURCE, &desc->flags);
if (lflags & GPIOHANDLE_REQUEST_BIAS_DISABLE)
set_bit(FLAG_BIAS_DISABLE, &desc->flags);
if (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN)
set_bit(FLAG_PULL_DOWN, &desc->flags);
if (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP)
set_bit(FLAG_PULL_UP, &desc->flags);
ret = gpiod_set_transitory(desc, false);
if (ret < 0)
goto out_free_descs;
/*
* Lines have to be requested explicitly for input
* or output, else the line will be treated "as is".
*/
if (lflags & GPIOHANDLE_REQUEST_OUTPUT) {
int val = !!handlereq.default_values[i];
ret = gpiod_direction_output(desc, val);
if (ret)
goto out_free_descs;
} else if (lflags & GPIOHANDLE_REQUEST_INPUT) {
ret = gpiod_direction_input(desc);
if (ret)
goto out_free_descs;
}
atomic_notifier_call_chain(&desc->gdev->notifier,
GPIOLINE_CHANGED_REQUESTED, desc);
dev_dbg(&gdev->dev, "registered chardev handle for line %d\n",
offset);
}
/* Let i point at the last handle */
i--;
lh->numdescs = handlereq.lines;
fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC);
if (fd < 0) {
ret = fd;
goto out_free_descs;
}
file = anon_inode_getfile("gpio-linehandle",
&linehandle_fileops,
lh,
O_RDONLY | O_CLOEXEC);
if (IS_ERR(file)) {
ret = PTR_ERR(file);
goto out_put_unused_fd;
}
handlereq.fd = fd;
if (copy_to_user(ip, &handlereq, sizeof(handlereq))) {
/*
* fput() will trigger the release() callback, so do not go onto
* the regular error cleanup path here.
*/
fput(file);
put_unused_fd(fd);
return -EFAULT;
}
fd_install(fd, file);
dev_dbg(&gdev->dev, "registered chardev handle for %d lines\n",
lh->numdescs);
return 0;
out_put_unused_fd:
put_unused_fd(fd);
out_free_descs:
for (i = 0; i < count; i++)
gpiod_free(lh->descs[i]);
kfree(lh->label);
out_free_lh:
kfree(lh);
put_device(&gdev->dev);
return ret;
}
/*
* GPIO line event management
*/
/**
* struct lineevent_state - contains the state of a userspace event
* @gdev: the GPIO device the event pertains to
* @label: consumer label used to tag descriptors
* @desc: the GPIO descriptor held by this event
* @eflags: the event flags this line was requested with
* @irq: the interrupt that trigger in response to events on this GPIO
* @wait: wait queue that handles blocking reads of events
* @events: KFIFO for the GPIO events
* @timestamp: cache for the timestamp storing it between hardirq
* and IRQ thread, used to bring the timestamp close to the actual
* event
*/
struct lineevent_state {
struct gpio_device *gdev;
const char *label;
struct gpio_desc *desc;
u32 eflags;
int irq;
wait_queue_head_t wait;
DECLARE_KFIFO(events, struct gpioevent_data, 16);
u64 timestamp;
};
#define GPIOEVENT_REQUEST_VALID_FLAGS \
(GPIOEVENT_REQUEST_RISING_EDGE | \
GPIOEVENT_REQUEST_FALLING_EDGE)
static __poll_t lineevent_poll(struct file *filep,
struct poll_table_struct *wait)
{
struct lineevent_state *le = filep->private_data;
__poll_t events = 0;
poll_wait(filep, &le->wait, wait);
if (!kfifo_is_empty_spinlocked_noirqsave(&le->events, &le->wait.lock))
events = EPOLLIN | EPOLLRDNORM;
return events;
}
static ssize_t lineevent_read(struct file *filep,
char __user *buf,
size_t count,
loff_t *f_ps)
{
struct lineevent_state *le = filep->private_data;
struct gpioevent_data ge;
ssize_t bytes_read = 0;
int ret;
if (count < sizeof(ge))
return -EINVAL;
do {
spin_lock(&le->wait.lock);
if (kfifo_is_empty(&le->events)) {
if (bytes_read) {
spin_unlock(&le->wait.lock);
return bytes_read;
}
if (filep->f_flags & O_NONBLOCK) {
spin_unlock(&le->wait.lock);
return -EAGAIN;
}
ret = wait_event_interruptible_locked(le->wait,
!kfifo_is_empty(&le->events));
if (ret) {
spin_unlock(&le->wait.lock);
return ret;
}
}
ret = kfifo_out(&le->events, &ge, 1);
spin_unlock(&le->wait.lock);
if (ret != 1) {
/*
* This should never happen - we were holding the lock
* from the moment we learned the fifo is no longer
* empty until now.
*/
ret = -EIO;
break;
}
if (copy_to_user(buf + bytes_read, &ge, sizeof(ge)))
return -EFAULT;
bytes_read += sizeof(ge);
} while (count >= bytes_read + sizeof(ge));
return bytes_read;
}
static int lineevent_release(struct inode *inode, struct file *filep)
{
struct lineevent_state *le = filep->private_data;
struct gpio_device *gdev = le->gdev;
free_irq(le->irq, le);
gpiod_free(le->desc);
kfree(le->label);
kfree(le);
put_device(&gdev->dev);
return 0;
}
static long lineevent_ioctl(struct file *filep, unsigned int cmd,
unsigned long arg)
{
struct lineevent_state *le = filep->private_data;
void __user *ip = (void __user *)arg;
struct gpiohandle_data ghd;
/*
* We can get the value for an event line but not set it,
* because it is input by definition.
*/
if (cmd == GPIOHANDLE_GET_LINE_VALUES_IOCTL) {
int val;
memset(&ghd, 0, sizeof(ghd));
val = gpiod_get_value_cansleep(le->desc);
if (val < 0)
return val;
ghd.values[0] = val;
if (copy_to_user(ip, &ghd, sizeof(ghd)))
return -EFAULT;
return 0;
}
return -EINVAL;
}
#ifdef CONFIG_COMPAT
static long lineevent_ioctl_compat(struct file *filep, unsigned int cmd,
unsigned long arg)
{
return lineevent_ioctl(filep, cmd, (unsigned long)compat_ptr(arg));
}
#endif
static const struct file_operations lineevent_fileops = {
.release = lineevent_release,
.read = lineevent_read,
.poll = lineevent_poll,
.owner = THIS_MODULE,
.llseek = noop_llseek,
.unlocked_ioctl = lineevent_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = lineevent_ioctl_compat,
#endif
};
static irqreturn_t lineevent_irq_thread(int irq, void *p)
{
struct lineevent_state *le = p;
struct gpioevent_data ge;
int ret;
/* Do not leak kernel stack to userspace */
memset(&ge, 0, sizeof(ge));
/*
* We may be running from a nested threaded interrupt in which case
* we didn't get the timestamp from lineevent_irq_handler().
*/
if (!le->timestamp)
ge.timestamp = ktime_get_ns();
else
ge.timestamp = le->timestamp;
if (le->eflags & GPIOEVENT_REQUEST_RISING_EDGE
&& le->eflags & GPIOEVENT_REQUEST_FALLING_EDGE) {
int level = gpiod_get_value_cansleep(le->desc);
if (level)
/* Emit low-to-high event */
ge.id = GPIOEVENT_EVENT_RISING_EDGE;
else
/* Emit high-to-low event */
ge.id = GPIOEVENT_EVENT_FALLING_EDGE;
} else if (le->eflags & GPIOEVENT_REQUEST_RISING_EDGE) {
/* Emit low-to-high event */
ge.id = GPIOEVENT_EVENT_RISING_EDGE;
} else if (le->eflags & GPIOEVENT_REQUEST_FALLING_EDGE) {
/* Emit high-to-low event */
ge.id = GPIOEVENT_EVENT_FALLING_EDGE;
} else {
return IRQ_NONE;
}
ret = kfifo_in_spinlocked_noirqsave(&le->events, &ge,
1, &le->wait.lock);
if (ret)
wake_up_poll(&le->wait, EPOLLIN);
else
pr_debug_ratelimited("event FIFO is full - event dropped\n");
return IRQ_HANDLED;
}
static irqreturn_t lineevent_irq_handler(int irq, void *p)
{
struct lineevent_state *le = p;
/*
* Just store the timestamp in hardirq context so we get it as
* close in time as possible to the actual event.
*/
le->timestamp = ktime_get_ns();
return IRQ_WAKE_THREAD;
}
static int lineevent_create(struct gpio_device *gdev, void __user *ip)
{
struct gpioevent_request eventreq;
struct lineevent_state *le;
struct gpio_desc *desc;
struct file *file;
u32 offset;
u32 lflags;
u32 eflags;
int fd;
int ret;
int irqflags = 0;
if (copy_from_user(&eventreq, ip, sizeof(eventreq)))
return -EFAULT;
offset = eventreq.lineoffset;
lflags = eventreq.handleflags;
eflags = eventreq.eventflags;
desc = gpiochip_get_desc(gdev->chip, offset);
if (IS_ERR(desc))
return PTR_ERR(desc);
/* Return an error if a unknown flag is set */
if ((lflags & ~GPIOHANDLE_REQUEST_VALID_FLAGS) ||
(eflags & ~GPIOEVENT_REQUEST_VALID_FLAGS))
return -EINVAL;
/* This is just wrong: we don't look for events on output lines */
if ((lflags & GPIOHANDLE_REQUEST_OUTPUT) ||
(lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN) ||
(lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE))
return -EINVAL;
/* Only one bias flag can be set. */
if (((lflags & GPIOHANDLE_REQUEST_BIAS_DISABLE) &&
(lflags & (GPIOHANDLE_REQUEST_BIAS_PULL_DOWN |
GPIOHANDLE_REQUEST_BIAS_PULL_UP))) ||
((lflags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN) &&
(lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP)))
return -EINVAL;
le = kzalloc(sizeof(*le), GFP_KERNEL);
if (!le)
return -ENOMEM;
le->gdev = gdev;
get_device(&gdev->dev);
/* Make sure this is terminated */
eventreq.consumer_label[sizeof(eventreq.consumer_label)-1] = '\0';
if (strlen(eventreq.consumer_label)) {
le->label = kstrdup(eventreq.consumer_label,
GFP_KERNEL);
if (!le->label) {
ret = -ENOMEM;
goto out_free_le;
}
}
ret = gpiod_request(desc, le->label);
if (ret)
goto out_free_label;
le->desc = desc;
le->eflags = eflags;
if (lflags & GPIOHANDLE_REQUEST_ACTIVE_LOW)
set_bit(FLAG_ACTIVE_LOW, &desc->flags);
if (lflags & GPIOHANDLE_REQUEST_BIAS_DISABLE)
set_bit(FLAG_BIAS_DISABLE, &desc->flags);
if (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN)
set_bit(FLAG_PULL_DOWN, &desc->flags);
if (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP)
set_bit(FLAG_PULL_UP, &desc->flags);
ret = gpiod_direction_input(desc);
if (ret)
goto out_free_desc;
atomic_notifier_call_chain(&desc->gdev->notifier,
GPIOLINE_CHANGED_REQUESTED, desc);
le->irq = gpiod_to_irq(desc);
if (le->irq <= 0) {
ret = -ENODEV;
goto out_free_desc;
}
if (eflags & GPIOEVENT_REQUEST_RISING_EDGE)
irqflags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ?
IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;
if (eflags & GPIOEVENT_REQUEST_FALLING_EDGE)
irqflags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ?
IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING;
irqflags |= IRQF_ONESHOT;
INIT_KFIFO(le->events);
init_waitqueue_head(&le->wait);
/* Request a thread to read the events */
ret = request_threaded_irq(le->irq,
lineevent_irq_handler,
lineevent_irq_thread,
irqflags,
le->label,
le);
if (ret)
goto out_free_desc;
fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC);
if (fd < 0) {
ret = fd;
goto out_free_irq;
}
file = anon_inode_getfile("gpio-event",
&lineevent_fileops,
le,
O_RDONLY | O_CLOEXEC);
if (IS_ERR(file)) {
ret = PTR_ERR(file);
goto out_put_unused_fd;
}
eventreq.fd = fd;
if (copy_to_user(ip, &eventreq, sizeof(eventreq))) {
/*
* fput() will trigger the release() callback, so do not go onto
* the regular error cleanup path here.
*/
fput(file);
put_unused_fd(fd);
return -EFAULT;
}
fd_install(fd, file);
return 0;
out_put_unused_fd:
put_unused_fd(fd);
out_free_irq:
free_irq(le->irq, le);
out_free_desc:
gpiod_free(le->desc);
out_free_label:
kfree(le->label);
out_free_le:
kfree(le);
put_device(&gdev->dev);
return ret;
}
static void gpio_desc_to_lineinfo(struct gpio_desc *desc,
struct gpioline_info *info)
{
struct gpio_chip *gc = desc->gdev->chip;
bool ok_for_pinctrl;
unsigned long flags;
/*
* This function takes a mutex so we must check this before taking
* the spinlock.
*
* FIXME: find a non-racy way to retrieve this information. Maybe a
* lock common to both frameworks?
*/
ok_for_pinctrl =
pinctrl_gpio_can_use_line(gc->base + info->line_offset);
spin_lock_irqsave(&gpio_lock, flags);
if (desc->name) {
strncpy(info->name, desc->name, sizeof(info->name));
info->name[sizeof(info->name) - 1] = '\0';
} else {
info->name[0] = '\0';
}
if (desc->label) {
strncpy(info->consumer, desc->label, sizeof(info->consumer));
info->consumer[sizeof(info->consumer) - 1] = '\0';
} else {
info->consumer[0] = '\0';
}
/*
* Userspace only need to know that the kernel is using this GPIO so
* it can't use it.
*/
info->flags = 0;
if (test_bit(FLAG_REQUESTED, &desc->flags) ||
test_bit(FLAG_IS_HOGGED, &desc->flags) ||
test_bit(FLAG_USED_AS_IRQ, &desc->flags) ||
test_bit(FLAG_EXPORT, &desc->flags) ||
test_bit(FLAG_SYSFS, &desc->flags) ||
!ok_for_pinctrl)
info->flags |= GPIOLINE_FLAG_KERNEL;
if (test_bit(FLAG_IS_OUT, &desc->flags))
info->flags |= GPIOLINE_FLAG_IS_OUT;
if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
info->flags |= GPIOLINE_FLAG_ACTIVE_LOW;
if (test_bit(FLAG_OPEN_DRAIN, &desc->flags))
info->flags |= (GPIOLINE_FLAG_OPEN_DRAIN |
GPIOLINE_FLAG_IS_OUT);
if (test_bit(FLAG_OPEN_SOURCE, &desc->flags))
info->flags |= (GPIOLINE_FLAG_OPEN_SOURCE |
GPIOLINE_FLAG_IS_OUT);
if (test_bit(FLAG_BIAS_DISABLE, &desc->flags))
info->flags |= GPIOLINE_FLAG_BIAS_DISABLE;
if (test_bit(FLAG_PULL_DOWN, &desc->flags))
info->flags |= GPIOLINE_FLAG_BIAS_PULL_DOWN;
if (test_bit(FLAG_PULL_UP, &desc->flags))
info->flags |= GPIOLINE_FLAG_BIAS_PULL_UP;
spin_unlock_irqrestore(&gpio_lock, flags);
}
struct gpio_chardev_data {
struct gpio_device *gdev;
wait_queue_head_t wait;
DECLARE_KFIFO(events, struct gpioline_info_changed, 32);
struct notifier_block lineinfo_changed_nb;
unsigned long *watched_lines;
};
/*
* gpio_ioctl() - ioctl handler for the GPIO chardev
*/
static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct gpio_chardev_data *priv = filp->private_data;
struct gpio_device *gdev = priv->gdev;
struct gpio_chip *gc = gdev->chip;
void __user *ip = (void __user *)arg;
struct gpio_desc *desc;
__u32 offset;
int hwgpio;
/* We fail any subsequent ioctl():s when the chip is gone */
if (!gc)
return -ENODEV;
/* Fill in the struct and pass to userspace */
if (cmd == GPIO_GET_CHIPINFO_IOCTL) {
struct gpiochip_info chipinfo;
memset(&chipinfo, 0, sizeof(chipinfo));
strncpy(chipinfo.name, dev_name(&gdev->dev),
sizeof(chipinfo.name));
chipinfo.name[sizeof(chipinfo.name)-1] = '\0';
strncpy(chipinfo.label, gdev->label,
sizeof(chipinfo.label));
chipinfo.label[sizeof(chipinfo.label)-1] = '\0';
chipinfo.lines = gdev->ngpio;
if (copy_to_user(ip, &chipinfo, sizeof(chipinfo)))
return -EFAULT;
return 0;
} else if (cmd == GPIO_GET_LINEINFO_IOCTL) {
struct gpioline_info lineinfo;
if (copy_from_user(&lineinfo, ip, sizeof(lineinfo)))
return -EFAULT;
desc = gpiochip_get_desc(gc, lineinfo.line_offset);
if (IS_ERR(desc))
return PTR_ERR(desc);
hwgpio = gpio_chip_hwgpio(desc);
gpio_desc_to_lineinfo(desc, &lineinfo);
if (copy_to_user(ip, &lineinfo, sizeof(lineinfo)))
return -EFAULT;
return 0;
} else if (cmd == GPIO_GET_LINEHANDLE_IOCTL) {
return linehandle_create(gdev, ip);
} else if (cmd == GPIO_GET_LINEEVENT_IOCTL) {
return lineevent_create(gdev, ip);
} else if (cmd == GPIO_GET_LINEINFO_WATCH_IOCTL) {
struct gpioline_info lineinfo;
if (copy_from_user(&lineinfo, ip, sizeof(lineinfo)))
return -EFAULT;
desc = gpiochip_get_desc(gc, lineinfo.line_offset);
if (IS_ERR(desc))
return PTR_ERR(desc);
hwgpio = gpio_chip_hwgpio(desc);
if (test_bit(hwgpio, priv->watched_lines))
return -EBUSY;
gpio_desc_to_lineinfo(desc, &lineinfo);
if (copy_to_user(ip, &lineinfo, sizeof(lineinfo)))
return -EFAULT;
set_bit(hwgpio, priv->watched_lines);
return 0;
} else if (cmd == GPIO_GET_LINEINFO_UNWATCH_IOCTL) {
if (copy_from_user(&offset, ip, sizeof(offset)))
return -EFAULT;
desc = gpiochip_get_desc(gc, offset);
if (IS_ERR(desc))
return PTR_ERR(desc);
hwgpio = gpio_chip_hwgpio(desc);
if (!test_bit(hwgpio, priv->watched_lines))
return -EBUSY;
clear_bit(hwgpio, priv->watched_lines);
return 0;
}
return -EINVAL;
}
#ifdef CONFIG_COMPAT
static long gpio_ioctl_compat(struct file *filp, unsigned int cmd,
unsigned long arg)
{
return gpio_ioctl(filp, cmd, (unsigned long)compat_ptr(arg));
}
#endif
static struct gpio_chardev_data *
to_gpio_chardev_data(struct notifier_block *nb)
{
return container_of(nb, struct gpio_chardev_data, lineinfo_changed_nb);
}
static int lineinfo_changed_notify(struct notifier_block *nb,
unsigned long action, void *data)
{
struct gpio_chardev_data *priv = to_gpio_chardev_data(nb);
struct gpioline_info_changed chg;
struct gpio_desc *desc = data;
int ret;
if (!test_bit(gpio_chip_hwgpio(desc), priv->watched_lines))
return NOTIFY_DONE;
memset(&chg, 0, sizeof(chg));
chg.info.line_offset = gpio_chip_hwgpio(desc);
chg.event_type = action;
chg.timestamp = ktime_get_ns();
gpio_desc_to_lineinfo(desc, &chg.info);
ret = kfifo_in_spinlocked(&priv->events, &chg, 1, &priv->wait.lock);
if (ret)
wake_up_poll(&priv->wait, EPOLLIN);
else
pr_debug_ratelimited("lineinfo event FIFO is full - event dropped\n");
return NOTIFY_OK;
}
static __poll_t lineinfo_watch_poll(struct file *filep,
struct poll_table_struct *pollt)
{
struct gpio_chardev_data *priv = filep->private_data;
__poll_t events = 0;
poll_wait(filep, &priv->wait, pollt);
if (!kfifo_is_empty_spinlocked_noirqsave(&priv->events,
&priv->wait.lock))
events = EPOLLIN | EPOLLRDNORM;
return events;
}
static ssize_t lineinfo_watch_read(struct file *filep, char __user *buf,
size_t count, loff_t *off)
{
struct gpio_chardev_data *priv = filep->private_data;
struct gpioline_info_changed event;
ssize_t bytes_read = 0;
int ret;
if (count < sizeof(event))
return -EINVAL;
do {
spin_lock(&priv->wait.lock);
if (kfifo_is_empty(&priv->events)) {
if (bytes_read) {
spin_unlock(&priv->wait.lock);
return bytes_read;
}
if (filep->f_flags & O_NONBLOCK) {
spin_unlock(&priv->wait.lock);
return -EAGAIN;
}
ret = wait_event_interruptible_locked(priv->wait,
!kfifo_is_empty(&priv->events));
if (ret) {
spin_unlock(&priv->wait.lock);
return ret;
}
}
ret = kfifo_out(&priv->events, &event, 1);
spin_unlock(&priv->wait.lock);
if (ret != 1) {
ret = -EIO;
break;
/* We should never get here. See lineevent_read(). */
}
if (copy_to_user(buf + bytes_read, &event, sizeof(event)))
return -EFAULT;
bytes_read += sizeof(event);
} while (count >= bytes_read + sizeof(event));
return bytes_read;
}
/**
* gpio_chrdev_open() - open the chardev for ioctl operations
* @inode: inode for this chardev
* @filp: file struct for storing private data
* Returns 0 on success
*/
static int gpio_chrdev_open(struct inode *inode, struct file *filp)
{
struct gpio_device *gdev = container_of(inode->i_cdev,
struct gpio_device, chrdev);
struct gpio_chardev_data *priv;
int ret = -ENOMEM;
/* Fail on open if the backing gpiochip is gone */
if (!gdev->chip)
return -ENODEV;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->watched_lines = bitmap_zalloc(gdev->chip->ngpio, GFP_KERNEL);
if (!priv->watched_lines)
goto out_free_priv;
init_waitqueue_head(&priv->wait);
INIT_KFIFO(priv->events);
priv->gdev = gdev;
priv->lineinfo_changed_nb.notifier_call = lineinfo_changed_notify;
ret = atomic_notifier_chain_register(&gdev->notifier,
&priv->lineinfo_changed_nb);
if (ret)
goto out_free_bitmap;
get_device(&gdev->dev);
filp->private_data = priv;
ret = nonseekable_open(inode, filp);
if (ret)
goto out_unregister_notifier;
return ret;
out_unregister_notifier:
atomic_notifier_chain_unregister(&gdev->notifier,
&priv->lineinfo_changed_nb);
out_free_bitmap:
bitmap_free(priv->watched_lines);
out_free_priv:
kfree(priv);
return ret;
}
/**
* gpio_chrdev_release() - close chardev after ioctl operations
* @inode: inode for this chardev
* @filp: file struct for storing private data
* Returns 0 on success
*/
static int gpio_chrdev_release(struct inode *inode, struct file *filp)
{
struct gpio_chardev_data *priv = filp->private_data;
struct gpio_device *gdev = priv->gdev;
bitmap_free(priv->watched_lines);
atomic_notifier_chain_unregister(&gdev->notifier,
&priv->lineinfo_changed_nb);
put_device(&gdev->dev);
kfree(priv);
return 0;
}
static const struct file_operations gpio_fileops = {
.release = gpio_chrdev_release,
.open = gpio_chrdev_open,
.poll = lineinfo_watch_poll,
.read = lineinfo_watch_read,
.owner = THIS_MODULE,
.llseek = no_llseek,
.unlocked_ioctl = gpio_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = gpio_ioctl_compat,
#endif
};
static void gpiodevice_release(struct device *dev) static void gpiodevice_release(struct device *dev)
{ {
struct gpio_device *gdev = dev_get_drvdata(dev); struct gpio_device *gdev = dev_get_drvdata(dev);
...@@ -1539,17 +436,10 @@ static int gpiochip_setup_dev(struct gpio_device *gdev) ...@@ -1539,17 +436,10 @@ static int gpiochip_setup_dev(struct gpio_device *gdev)
{ {
int ret; int ret;
cdev_init(&gdev->chrdev, &gpio_fileops); ret = gpiolib_cdev_register(gdev, gpio_devt);
gdev->chrdev.owner = THIS_MODULE;
gdev->dev.devt = MKDEV(MAJOR(gpio_devt), gdev->id);
ret = cdev_device_add(&gdev->chrdev, &gdev->dev);
if (ret) if (ret)
return ret; return ret;
chip_dbg(gdev->chip, "added GPIO chardev (%d:%d)\n",
MAJOR(gpio_devt), gdev->id);
ret = gpiochip_sysfs_register(gdev); ret = gpiochip_sysfs_register(gdev);
if (ret) if (ret)
goto err_remove_device; goto err_remove_device;
...@@ -1562,7 +452,7 @@ static int gpiochip_setup_dev(struct gpio_device *gdev) ...@@ -1562,7 +452,7 @@ static int gpiochip_setup_dev(struct gpio_device *gdev)
return 0; return 0;
err_remove_device: err_remove_device:
cdev_device_del(&gdev->chrdev, &gdev->dev); gpiolib_cdev_unregister(gdev);
return ret; return ret;
} }
...@@ -1725,7 +615,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, ...@@ -1725,7 +615,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
ATOMIC_INIT_NOTIFIER_HEAD(&gdev->notifier); BLOCKING_INIT_NOTIFIER_HEAD(&gdev->notifier);
#ifdef CONFIG_PINCTRL #ifdef CONFIG_PINCTRL
INIT_LIST_HEAD(&gdev->pin_ranges); INIT_LIST_HEAD(&gdev->pin_ranges);
...@@ -1884,7 +774,7 @@ void gpiochip_remove(struct gpio_chip *gc) ...@@ -1884,7 +774,7 @@ void gpiochip_remove(struct gpio_chip *gc)
* be removed, else it will be dangling until the last user is * be removed, else it will be dangling until the last user is
* gone. * gone.
*/ */
cdev_device_del(&gdev->chrdev, &gdev->dev); gpiolib_cdev_unregister(gdev);
put_device(&gdev->dev); put_device(&gdev->dev);
} }
EXPORT_SYMBOL_GPL(gpiochip_remove); EXPORT_SYMBOL_GPL(gpiochip_remove);
...@@ -3159,7 +2049,7 @@ static bool gpiod_free_commit(struct gpio_desc *desc) ...@@ -3159,7 +2049,7 @@ static bool gpiod_free_commit(struct gpio_desc *desc)
} }
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
atomic_notifier_call_chain(&desc->gdev->notifier, blocking_notifier_call_chain(&desc->gdev->notifier,
GPIOLINE_CHANGED_RELEASED, desc); GPIOLINE_CHANGED_RELEASED, desc);
return ret; return ret;
...@@ -3705,10 +2595,9 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep, ...@@ -3705,10 +2595,9 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep,
bitmap_xor(value_bitmap, value_bitmap, bitmap_xor(value_bitmap, value_bitmap,
array_info->invert_mask, array_size); array_info->invert_mask, array_size);
if (bitmap_full(array_info->get_mask, array_size))
return 0;
i = find_first_zero_bit(array_info->get_mask, array_size); i = find_first_zero_bit(array_info->get_mask, array_size);
if (i == array_size)
return 0;
} else { } else {
array_info = NULL; array_info = NULL;
} }
...@@ -3989,10 +2878,9 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, ...@@ -3989,10 +2878,9 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
gpio_chip_set_multiple(array_info->chip, array_info->set_mask, gpio_chip_set_multiple(array_info->chip, array_info->set_mask,
value_bitmap); value_bitmap);
if (bitmap_full(array_info->set_mask, array_size))
return 0;
i = find_first_zero_bit(array_info->set_mask, array_size); i = find_first_zero_bit(array_info->set_mask, array_size);
if (i == array_size)
return 0;
} else { } else {
array_info = NULL; array_info = NULL;
} }
...@@ -5039,7 +3927,7 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev, ...@@ -5039,7 +3927,7 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
return ERR_PTR(ret); return ERR_PTR(ret);
} }
atomic_notifier_call_chain(&desc->gdev->notifier, blocking_notifier_call_chain(&desc->gdev->notifier,
GPIOLINE_CHANGED_REQUESTED, desc); GPIOLINE_CHANGED_REQUESTED, desc);
return desc; return desc;
...@@ -5107,7 +3995,7 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, ...@@ -5107,7 +3995,7 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
return ERR_PTR(ret); return ERR_PTR(ret);
} }
atomic_notifier_call_chain(&desc->gdev->notifier, blocking_notifier_call_chain(&desc->gdev->notifier,
GPIOLINE_CHANGED_REQUESTED, desc); GPIOLINE_CHANGED_REQUESTED, desc);
return desc; return desc;
......
...@@ -56,7 +56,7 @@ struct gpio_device { ...@@ -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) ...@@ -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) ...@@ -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 { ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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; ...@@ -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 { ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment