Commit ebcb577a authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'gpio-updates-for-v5.18' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux

Pull gpio updates from Bartosz Golaszewski:
 "Relatively few updates for this release cycle. We have a single new
  driver and some minor changes in drivers, more work on limiting the
  usage of of_node in drivers and DT updates:

   - new driver: gpio-en7523

   - dt-bindings: convertion of faraday,ftgpio010 to YAML, new
     compatible string in gpio-vf610 and a bugfix in an example

   - gpiolib core: several improvements and some code shrink

   - documentation: convert all public docs into kerneldoc format

   - set IRQ bus token in gpio-crystalcove (addresses a debugfs issue)

   - add a missing return value check for kstrdup() in gpio-merrifield

   - allow gpio-tps68470 to be built as module

   - more work on limiting usage of of_node in GPIO drivers

   - several sysfs interface improvements

   - use SDPX in gpio-ts4900"

* tag 'gpio-updates-for-v5.18' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux:
  gpio: ts4900: Use SPDX header
  gpiolib: Use list_first_entry()/list_last_entry()
  gpiolib: sysfs: Simplify edge handling in the code
  gpiolib: sysfs: Move kstrtox() calls outside of the mutex lock
  gpiolib: sysfs: Move sysfs_emit() calls outside of the mutex lock
  gpiolib: make struct comments into real kernel docs
  dt-bindings: gpio: convert faraday,ftgpio01 to yaml
  dt-bindings: gpio: gpio-vf610: Add imx93 compatible string
  gpiolib: Simplify error path in gpiod_get_index() when requesting GPIO
  gpiolib: Use short form of ternary operator in gpiod_get_index()
  gpiolib: Introduce for_each_gpio_desc_with_flag() macro
  gpio: Add support for Airoha EN7523 GPIO controller
  dt-bindings: arm: airoha: Add binding for Airoha GPIO controller
  dt-bindings: gpio: fix gpio-hog example
  gpio: tps68470: Allow building as module
  gpio: tegra: Get rid of duplicate of_node assignment
  gpio: altera-a10sr: Switch to use fwnode instead of of_node
  gpio: merrifield: check the return value of devm_kstrdup()
  gpio: crystalcove: Set IRQ domain bus token to DOMAIN_BUS_WIRED
parents 5e206459 87ba5bad
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/gpio/airoha,en7523-gpio.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Airoha EN7523 GPIO controller
maintainers:
- John Crispin <john@phrozen.org>
description: |
Airoha's GPIO controller on their ARM EN7523 SoCs consists of two banks of 32
GPIOs.
properties:
$nodename:
pattern: "^gpio@[0-9a-f]+$"
compatible:
items:
- const: airoha,en7523-gpio
reg:
description: |
The first tuple points to the input register.
The second and third tuple point to the direction registers
The fourth tuple points to the output register
maxItems: 4
"#gpio-cells":
const: 2
gpio-controller: true
required:
- compatible
- reg
- "#gpio-cells"
- gpio-controller
additionalProperties: false
examples:
- |
gpio0: gpio@1fbf0200 {
compatible = "airoha,en7523-gpio";
reg = <0x1fbf0204 0x4>,
<0x1fbf0200 0x4>,
<0x1fbf0220 0x4>,
<0x1fbf0214 0x4>;
gpio-controller;
#gpio-cells = <2>;
};
gpio1: gpio@1fbf0270 {
compatible = "airoha,en7523-gpio";
reg = <0x1fbf0270 0x4>,
<0x1fbf0260 0x4>,
<0x1fbf0264 0x4>,
<0x1fbf0278 0x4>;
gpio-controller;
#gpio-cells = <2>;
};
...
Faraday Technology FTGPIO010 GPIO Controller
Required properties:
- compatible : Should be one of
"cortina,gemini-gpio", "faraday,ftgpio010"
"moxa,moxart-gpio", "faraday,ftgpio010"
"faraday,ftgpio010"
- reg : Should contain registers location and length
- interrupts : Should contain the interrupt line for the GPIO block
- gpio-controller : marks this as a GPIO controller
- #gpio-cells : Should be 2, see gpio/gpio.txt
- interrupt-controller : marks this as an interrupt controller
- #interrupt-cells : a standard two-cell interrupt flag, see
interrupt-controller/interrupts.txt
Example:
gpio@4d000000 {
compatible = "cortina,gemini-gpio", "faraday,ftgpio010";
reg = <0x4d000000 0x100>;
interrupts = <22 IRQ_TYPE_LEVEL_HIGH>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
};
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/gpio/faraday,ftgpio010.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Faraday Technology FTGPIO010 GPIO Controller
maintainers:
- Linus Walleij <linus.walleij@linaro.org>
properties:
compatible:
oneOf:
- items:
- const: cortina,gemini-gpio
- const: faraday,ftgpio010
- items:
- const: moxa,moxart-gpio
- const: faraday,ftgpio010
- const: faraday,ftgpio010
reg:
maxItems: 1
resets:
maxItems: 1
clocks:
maxItems: 1
interrupts:
maxItems: 1
description: Should contain the interrupt line for the GPIO block
gpio-controller: true
"#gpio-cells":
const: 2
interrupt-controller: true
"#interrupt-cells":
const: 2
required:
- compatible
- reg
- interrupts
- "#gpio-cells"
- interrupt-controller
- "#interrupt-cells"
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
gpio@4d000000 {
compatible = "cortina,gemini-gpio", "faraday,ftgpio010";
reg = <0x4d000000 0x100>;
interrupts = <22 IRQ_TYPE_LEVEL_HIGH>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
};
...@@ -25,7 +25,9 @@ properties: ...@@ -25,7 +25,9 @@ properties:
- const: fsl,imx7ulp-gpio - const: fsl,imx7ulp-gpio
- const: fsl,vf610-gpio - const: fsl,vf610-gpio
- items: - items:
- const: fsl,imx8ulp-gpio - enum:
- fsl,imx93-gpio
- fsl,imx8ulp-gpio
- const: fsl,imx7ulp-gpio - const: fsl,imx7ulp-gpio
reg: reg:
......
...@@ -213,7 +213,7 @@ Example of two SOC GPIO banks defined as gpio-controller nodes: ...@@ -213,7 +213,7 @@ Example of two SOC GPIO banks defined as gpio-controller nodes:
gpio-controller; gpio-controller;
#gpio-cells = <2>; #gpio-cells = <2>;
line_b { line_b-hog {
gpio-hog; gpio-hog;
gpios = <6 0>; gpios = <6 0>;
output-low; output-low;
......
...@@ -247,6 +247,16 @@ config GPIO_EM ...@@ -247,6 +247,16 @@ config GPIO_EM
help help
Say yes here to support GPIO on Renesas Emma Mobile SoCs. Say yes here to support GPIO on Renesas Emma Mobile SoCs.
config GPIO_EN7523
tristate "Airoha GPIO support"
depends on ARCH_AIROHA
default ARCH_AIROHA
select GPIO_GENERIC
select GPIOLIB_IRQCHIP
help
Say Y or M here to support the GPIO controller block on the
Airoha EN7523 SoC. It supports two banks of 32 GPIOs.
config GPIO_EP93XX config GPIO_EP93XX
def_bool y def_bool y
depends on ARCH_EP93XX depends on ARCH_EP93XX
...@@ -1380,7 +1390,7 @@ config GPIO_TPS65912 ...@@ -1380,7 +1390,7 @@ config GPIO_TPS65912
This driver supports TPS65912 GPIO chip. This driver supports TPS65912 GPIO chip.
config GPIO_TPS68470 config GPIO_TPS68470
bool "TPS68470 GPIO" tristate "TPS68470 GPIO"
depends on INTEL_SKL_INT3472 depends on INTEL_SKL_INT3472
help help
Select this option to enable GPIO driver for the TPS68470 Select this option to enable GPIO driver for the TPS68470
...@@ -1390,10 +1400,6 @@ config GPIO_TPS68470 ...@@ -1390,10 +1400,6 @@ config GPIO_TPS68470
input or output as appropriate, the sensor related GPIOs input or output as appropriate, the sensor related GPIOs
are "output only" GPIOs. are "output only" GPIOs.
This driver config is bool, as the GPIO functionality
of the TPS68470 must be available before dependent
drivers are loaded.
config GPIO_TQMX86 config GPIO_TQMX86
tristate "TQ-Systems QTMX86 GPIO" tristate "TQ-Systems QTMX86 GPIO"
depends on MFD_TQMX86 || COMPILE_TEST depends on MFD_TQMX86 || COMPILE_TEST
......
...@@ -55,6 +55,7 @@ obj-$(CONFIG_GPIO_DLN2) += gpio-dln2.o ...@@ -55,6 +55,7 @@ obj-$(CONFIG_GPIO_DLN2) += gpio-dln2.o
obj-$(CONFIG_GPIO_DWAPB) += gpio-dwapb.o obj-$(CONFIG_GPIO_DWAPB) += gpio-dwapb.o
obj-$(CONFIG_GPIO_EIC_SPRD) += gpio-eic-sprd.o obj-$(CONFIG_GPIO_EIC_SPRD) += gpio-eic-sprd.o
obj-$(CONFIG_GPIO_EM) += gpio-em.o obj-$(CONFIG_GPIO_EM) += gpio-em.o
obj-$(CONFIG_GPIO_EN7523) += gpio-en7523.o
obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o
obj-$(CONFIG_GPIO_EXAR) += gpio-exar.o obj-$(CONFIG_GPIO_EXAR) += gpio-exar.o
obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/gpio/driver.h> #include <linux/gpio/driver.h>
#include <linux/mfd/altera-a10sr.h> #include <linux/mfd/altera-a10sr.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/property.h>
/** /**
* struct altr_a10sr_gpio - Altera Max5 GPIO device private data structure * struct altr_a10sr_gpio - Altera Max5 GPIO device private data structure
...@@ -88,7 +89,7 @@ static int altr_a10sr_gpio_probe(struct platform_device *pdev) ...@@ -88,7 +89,7 @@ static int altr_a10sr_gpio_probe(struct platform_device *pdev)
gpio->gp = altr_a10sr_gc; gpio->gp = altr_a10sr_gc;
gpio->gp.parent = pdev->dev.parent; gpio->gp.parent = pdev->dev.parent;
gpio->gp.of_node = pdev->dev.of_node; gpio->gp.fwnode = dev_fwnode(&pdev->dev);
return devm_gpiochip_add_data(&pdev->dev, &gpio->gp, gpio); return devm_gpiochip_add_data(&pdev->dev, &gpio->gp, gpio);
} }
......
...@@ -370,7 +370,14 @@ static int crystalcove_gpio_probe(struct platform_device *pdev) ...@@ -370,7 +370,14 @@ static int crystalcove_gpio_probe(struct platform_device *pdev)
return retval; return retval;
} }
return devm_gpiochip_add_data(&pdev->dev, &cg->chip, cg); retval = devm_gpiochip_add_data(&pdev->dev, &cg->chip, cg);
if (retval)
return retval;
/* Distuingish IRQ domain from others sharing (MFD) the same fwnode */
irq_domain_update_bus_token(cg->chip.irq.domain, DOMAIN_BUS_WIRED);
return 0;
} }
static struct platform_driver crystalcove_gpio_driver = { static struct platform_driver crystalcove_gpio_driver = {
......
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/types.h>
#include <linux/io.h>
#include <linux/bits.h>
#include <linux/gpio/driver.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#define AIROHA_GPIO_MAX 32
/**
* airoha_gpio_ctrl - Airoha GPIO driver data
* @gc: Associated gpio_chip instance.
* @data: The data register.
* @dir0: The direction register for the lower 16 pins.
* @dir1: The direction register for the higher 16 pins.
* @output: The output enable register.
*/
struct airoha_gpio_ctrl {
struct gpio_chip gc;
void __iomem *data;
void __iomem *dir[2];
void __iomem *output;
};
static struct airoha_gpio_ctrl *gc_to_ctrl(struct gpio_chip *gc)
{
return container_of(gc, struct airoha_gpio_ctrl, gc);
}
static int airoha_dir_set(struct gpio_chip *gc, unsigned int gpio,
int val, int out)
{
struct airoha_gpio_ctrl *ctrl = gc_to_ctrl(gc);
u32 dir = ioread32(ctrl->dir[gpio / 16]);
u32 output = ioread32(ctrl->output);
u32 mask = BIT((gpio % 16) * 2);
if (out) {
dir |= mask;
output |= BIT(gpio);
} else {
dir &= ~mask;
output &= ~BIT(gpio);
}
iowrite32(dir, ctrl->dir[gpio / 16]);
if (out)
gc->set(gc, gpio, val);
iowrite32(output, ctrl->output);
return 0;
}
static int airoha_dir_out(struct gpio_chip *gc, unsigned int gpio,
int val)
{
return airoha_dir_set(gc, gpio, val, 1);
}
static int airoha_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
return airoha_dir_set(gc, gpio, 0, 0);
}
static int airoha_get_dir(struct gpio_chip *gc, unsigned int gpio)
{
struct airoha_gpio_ctrl *ctrl = gc_to_ctrl(gc);
u32 dir = ioread32(ctrl->dir[gpio / 16]);
u32 mask = BIT((gpio % 16) * 2);
return (dir & mask) ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN;
}
static int airoha_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct airoha_gpio_ctrl *ctrl;
int err;
ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
if (!ctrl)
return -ENOMEM;
ctrl->data = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(ctrl->data))
return PTR_ERR(ctrl->data);
ctrl->dir[0] = devm_platform_ioremap_resource(pdev, 1);
if (IS_ERR(ctrl->dir[0]))
return PTR_ERR(ctrl->dir[0]);
ctrl->dir[1] = devm_platform_ioremap_resource(pdev, 2);
if (IS_ERR(ctrl->dir[1]))
return PTR_ERR(ctrl->dir[1]);
ctrl->output = devm_platform_ioremap_resource(pdev, 3);
if (IS_ERR(ctrl->output))
return PTR_ERR(ctrl->output);
err = bgpio_init(&ctrl->gc, dev, 4, ctrl->data, NULL,
NULL, NULL, NULL, 0);
if (err)
return dev_err_probe(dev, err, "unable to init generic GPIO");
ctrl->gc.ngpio = AIROHA_GPIO_MAX;
ctrl->gc.owner = THIS_MODULE;
ctrl->gc.direction_output = airoha_dir_out;
ctrl->gc.direction_input = airoha_dir_in;
ctrl->gc.get_direction = airoha_get_dir;
return devm_gpiochip_add_data(dev, &ctrl->gc, ctrl);
}
static const struct of_device_id airoha_gpio_of_match[] = {
{ .compatible = "airoha,en7523-gpio" },
{ }
};
MODULE_DEVICE_TABLE(of, airoha_gpio_of_match);
static struct platform_driver airoha_gpio_driver = {
.driver = {
.name = "airoha-gpio",
.of_match_table = airoha_gpio_of_match,
},
.probe = airoha_gpio_probe,
};
module_platform_driver(airoha_gpio_driver);
MODULE_DESCRIPTION("Airoha GPIO support");
MODULE_AUTHOR("John Crispin <john@phrozen.org>");
MODULE_LICENSE("GPL v2");
...@@ -409,6 +409,9 @@ static int mrfld_gpio_add_pin_ranges(struct gpio_chip *chip) ...@@ -409,6 +409,9 @@ static int mrfld_gpio_add_pin_ranges(struct gpio_chip *chip)
int retval; int retval;
pinctrl_dev_name = mrfld_gpio_get_pinctrl_dev_name(priv); pinctrl_dev_name = mrfld_gpio_get_pinctrl_dev_name(priv);
if (!pinctrl_dev_name)
return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(mrfld_gpio_ranges); i++) { for (i = 0; i < ARRAY_SIZE(mrfld_gpio_ranges); i++) {
range = &mrfld_gpio_ranges[i]; range = &mrfld_gpio_ranges[i];
retval = gpiochip_add_pin_range(&priv->chip, pinctrl_dev_name, retval = gpiochip_add_pin_range(&priv->chip, pinctrl_dev_name,
......
...@@ -691,7 +691,6 @@ static int tegra_gpio_probe(struct platform_device *pdev) ...@@ -691,7 +691,6 @@ static int tegra_gpio_probe(struct platform_device *pdev)
tgi->gc.base = 0; tgi->gc.base = 0;
tgi->gc.ngpio = tgi->bank_count * 32; tgi->gc.ngpio = tgi->bank_count * 32;
tgi->gc.parent = &pdev->dev; tgi->gc.parent = &pdev->dev;
tgi->gc.of_node = pdev->dev.of_node;
tgi->ic.name = "GPIO"; tgi->ic.name = "GPIO";
tgi->ic.irq_ack = tegra_gpio_irq_ack; tgi->ic.irq_ack = tegra_gpio_irq_ack;
......
...@@ -154,5 +154,8 @@ static struct platform_driver tps68470_gpio_driver = { ...@@ -154,5 +154,8 @@ static struct platform_driver tps68470_gpio_driver = {
}, },
.probe = tps68470_gpio_probe, .probe = tps68470_gpio_probe,
}; };
module_platform_driver(tps68470_gpio_driver);
builtin_platform_driver(tps68470_gpio_driver) MODULE_ALIAS("platform:tps68470-gpio");
MODULE_DESCRIPTION("GPIO driver for TPS68470 PMIC");
MODULE_LICENSE("GPL v2");
// SPDX-License-Identifier: GPL-2.0
/* /*
* Digital I/O driver for Technologic Systems I2C FPGA Core * Digital I/O driver for Technologic Systems I2C FPGA Core
* *
* Copyright (C) 2015, 2018 Technologic Systems * Copyright (C) 2015, 2018 Technologic Systems
* Copyright (C) 2016 Savoir-Faire Linux * Copyright (C) 2016 Savoir-Faire Linux
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether expressed or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License version 2 for more details.
*/ */
#include <linux/gpio/driver.h> #include <linux/gpio/driver.h>
......
...@@ -711,14 +711,12 @@ static int of_gpiochip_scan_gpios(struct gpio_chip *chip) ...@@ -711,14 +711,12 @@ static int of_gpiochip_scan_gpios(struct gpio_chip *chip)
static void of_gpiochip_remove_hog(struct gpio_chip *chip, static void of_gpiochip_remove_hog(struct gpio_chip *chip,
struct device_node *hog) struct device_node *hog)
{ {
struct gpio_desc *descs = chip->gpiodev->descs; struct gpio_desc *desc;
unsigned int i; unsigned int i;
for (i = 0; i < chip->ngpio; i++) { for_each_gpio_desc_with_flag(i, chip, desc, FLAG_IS_HOGGED)
if (test_bit(FLAG_IS_HOGGED, &descs[i].flags) && if (desc->hog == hog)
descs[i].hog == hog) gpiochip_free_own_desc(desc);
gpiochip_free_own_desc(&descs[i]);
}
} }
static int of_gpiochip_match_node(struct gpio_chip *chip, void *data) static int of_gpiochip_match_node(struct gpio_chip *chip, void *data)
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "gpiolib.h" #include "gpiolib.h"
#include "gpiolib-sysfs.h" #include "gpiolib-sysfs.h"
#define GPIO_IRQF_TRIGGER_NONE 0
#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)
#define GPIO_IRQF_TRIGGER_BOTH (GPIO_IRQF_TRIGGER_FALLING | \ #define GPIO_IRQF_TRIGGER_BOTH (GPIO_IRQF_TRIGGER_FALLING | \
...@@ -61,17 +62,16 @@ static ssize_t direction_show(struct device *dev, ...@@ -61,17 +62,16 @@ static ssize_t direction_show(struct device *dev,
{ {
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;
ssize_t status; int value;
mutex_lock(&data->mutex); mutex_lock(&data->mutex);
gpiod_get_direction(desc); gpiod_get_direction(desc);
status = sysfs_emit(buf, "%s\n", value = !!test_bit(FLAG_IS_OUT, &desc->flags);
test_bit(FLAG_IS_OUT, &desc->flags) ? "out" : "in");
mutex_unlock(&data->mutex); mutex_unlock(&data->mutex);
return status; return sysfs_emit(buf, "%s\n", value ? "out" : "in");
} }
static ssize_t direction_store(struct device *dev, static ssize_t direction_store(struct device *dev,
...@@ -108,12 +108,13 @@ static ssize_t value_show(struct device *dev, ...@@ -108,12 +108,13 @@ static ssize_t value_show(struct device *dev,
mutex_lock(&data->mutex); mutex_lock(&data->mutex);
status = gpiod_get_value_cansleep(desc); status = gpiod_get_value_cansleep(desc);
if (status >= 0)
status = sysfs_emit(buf, "%zd\n", status);
mutex_unlock(&data->mutex); mutex_unlock(&data->mutex);
return status; if (status < 0)
return status;
return sysfs_emit(buf, "%zd\n", status);
} }
static ssize_t value_store(struct device *dev, static ssize_t value_store(struct device *dev,
...@@ -121,24 +122,18 @@ static ssize_t value_store(struct device *dev, ...@@ -121,24 +122,18 @@ static ssize_t value_store(struct device *dev,
{ {
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;
ssize_t status = 0; ssize_t status;
long value;
status = kstrtol(buf, 0, &value);
mutex_lock(&data->mutex); mutex_lock(&data->mutex);
if (!test_bit(FLAG_IS_OUT, &desc->flags)) { if (!test_bit(FLAG_IS_OUT, &desc->flags)) {
status = -EPERM; status = -EPERM;
} else { } else if (status == 0) {
long value; gpiod_set_value_cansleep(desc, value);
status = size;
if (size <= 2 && isdigit(buf[0]) &&
(size == 1 || buf[1] == '\n'))
value = buf[0] - '0';
else
status = kstrtol(buf, 0, &value);
if (status == 0) {
gpiod_set_value_cansleep(desc, value);
status = size;
}
} }
mutex_unlock(&data->mutex); mutex_unlock(&data->mutex);
...@@ -224,54 +219,41 @@ static void gpio_sysfs_free_irq(struct device *dev) ...@@ -224,54 +219,41 @@ static void gpio_sysfs_free_irq(struct device *dev)
sysfs_put(data->value_kn); sysfs_put(data->value_kn);
} }
static const struct { static const char * const trigger_names[] = {
const char *name; [GPIO_IRQF_TRIGGER_NONE] = "none",
unsigned char flags; [GPIO_IRQF_TRIGGER_FALLING] = "falling",
} trigger_types[] = { [GPIO_IRQF_TRIGGER_RISING] = "rising",
{ "none", 0 }, [GPIO_IRQF_TRIGGER_BOTH] = "both",
{ "falling", GPIO_IRQF_TRIGGER_FALLING },
{ "rising", GPIO_IRQF_TRIGGER_RISING },
{ "both", GPIO_IRQF_TRIGGER_BOTH },
}; };
static ssize_t edge_show(struct device *dev, static ssize_t edge_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct gpiod_data *data = dev_get_drvdata(dev); struct gpiod_data *data = dev_get_drvdata(dev);
ssize_t status = 0; int flags;
int i;
mutex_lock(&data->mutex); mutex_lock(&data->mutex);
for (i = 0; i < ARRAY_SIZE(trigger_types); i++) { flags = data->irq_flags;
if (data->irq_flags == trigger_types[i].flags)
break;
}
if (i < ARRAY_SIZE(trigger_types))
status = sysfs_emit(buf, "%s\n", trigger_types[i].name);
mutex_unlock(&data->mutex); mutex_unlock(&data->mutex);
return status; if (flags >= ARRAY_SIZE(trigger_names))
return 0;
return sysfs_emit(buf, "%s\n", trigger_names[flags]);
} }
static ssize_t edge_store(struct device *dev, static ssize_t edge_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size) struct device_attribute *attr, const char *buf, size_t size)
{ {
struct gpiod_data *data = dev_get_drvdata(dev); struct gpiod_data *data = dev_get_drvdata(dev);
unsigned char flags;
ssize_t status = size; ssize_t status = size;
int i; int flags;
for (i = 0; i < ARRAY_SIZE(trigger_types); i++) {
if (sysfs_streq(trigger_types[i].name, buf))
break;
}
if (i == ARRAY_SIZE(trigger_types))
return -EINVAL;
flags = trigger_types[i].flags; flags = sysfs_match_string(trigger_names, buf);
if (flags < 0)
return flags;
mutex_lock(&data->mutex); mutex_lock(&data->mutex);
...@@ -324,16 +306,15 @@ static ssize_t active_low_show(struct device *dev, ...@@ -324,16 +306,15 @@ static ssize_t active_low_show(struct device *dev,
{ {
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;
ssize_t status; int value;
mutex_lock(&data->mutex); mutex_lock(&data->mutex);
status = sysfs_emit(buf, "%d\n", value = !!test_bit(FLAG_ACTIVE_LOW, &desc->flags);
!!test_bit(FLAG_ACTIVE_LOW, &desc->flags));
mutex_unlock(&data->mutex); mutex_unlock(&data->mutex);
return status; return sysfs_emit(buf, "%d\n", value);
} }
static ssize_t active_low_store(struct device *dev, static ssize_t active_low_store(struct device *dev,
...@@ -343,11 +324,13 @@ static ssize_t active_low_store(struct device *dev, ...@@ -343,11 +324,13 @@ static ssize_t active_low_store(struct device *dev,
ssize_t status; ssize_t status;
long value; long value;
status = kstrtol(buf, 0, &value);
if (status)
return status;
mutex_lock(&data->mutex); mutex_lock(&data->mutex);
status = kstrtol(buf, 0, &value); status = gpio_sysfs_set_active_low(dev, value);
if (status == 0)
status = gpio_sysfs_set_active_low(dev, value);
mutex_unlock(&data->mutex); mutex_unlock(&data->mutex);
...@@ -790,11 +773,8 @@ void gpiochip_sysfs_unregister(struct gpio_device *gdev) ...@@ -790,11 +773,8 @@ void gpiochip_sysfs_unregister(struct gpio_device *gdev)
mutex_unlock(&sysfs_lock); mutex_unlock(&sysfs_lock);
/* unregister gpiod class devices owned by sysfs */ /* unregister gpiod class devices owned by sysfs */
for (i = 0; i < chip->ngpio; i++) { for_each_gpio_desc_with_flag(i, chip, desc, FLAG_SYSFS)
desc = &gdev->descs[i]; gpiod_free(desc);
if (test_and_clear_bit(FLAG_SYSFS, &desc->flags))
gpiod_free(desc);
}
} }
static int __init gpiolib_sysfs_init(void) static int __init gpiolib_sysfs_init(void)
......
...@@ -262,14 +262,14 @@ static int gpiodev_add_to_list(struct gpio_device *gdev) ...@@ -262,14 +262,14 @@ static int gpiodev_add_to_list(struct gpio_device *gdev)
return 0; return 0;
} }
next = list_entry(gpio_devices.next, struct gpio_device, list); next = list_first_entry(&gpio_devices, struct gpio_device, list);
if (gdev->base + gdev->ngpio <= next->base) { if (gdev->base + gdev->ngpio <= next->base) {
/* add before first entry */ /* add before first entry */
list_add(&gdev->list, &gpio_devices); list_add(&gdev->list, &gpio_devices);
return 0; return 0;
} }
prev = list_entry(gpio_devices.prev, struct gpio_device, list); prev = list_last_entry(&gpio_devices, struct gpio_device, list);
if (prev->base + prev->ngpio <= gdev->base) { if (prev->base + prev->ngpio <= gdev->base) {
/* add behind last entry */ /* add behind last entry */
list_add_tail(&gdev->list, &gpio_devices); list_add_tail(&gdev->list, &gpio_devices);
...@@ -3951,23 +3951,21 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev, ...@@ -3951,23 +3951,21 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
* If a connection label was passed use that, else attempt to use * If a connection label was passed use that, else attempt to use
* the device name as label * the device name as label
*/ */
ret = gpiod_request(desc, con_id ? con_id : devname); ret = gpiod_request(desc, con_id ?: devname);
if (ret) { if (ret) {
if (ret == -EBUSY && flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE) { if (!(ret == -EBUSY && flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE))
/*
* This happens when there are several consumers for
* the same GPIO line: we just return here without
* further initialization. It is a bit if a hack.
* This is necessary to support fixed regulators.
*
* FIXME: Make this more sane and safe.
*/
dev_info(dev, "nonexclusive access to GPIO for %s\n",
con_id ? con_id : devname);
return desc;
} else {
return ERR_PTR(ret); return ERR_PTR(ret);
}
/*
* This happens when there are several consumers for
* the same GPIO line: we just return here without
* further initialization. It is a bit of a hack.
* This is necessary to support fixed regulators.
*
* FIXME: Make this more sane and safe.
*/
dev_info(dev, "nonexclusive access to GPIO for %s\n", con_id ?: devname);
return desc;
} }
ret = gpiod_configure_flags(desc, con_id, lookupflags, flags); ret = gpiod_configure_flags(desc, con_id, lookupflags, flags);
...@@ -4122,12 +4120,11 @@ int gpiod_hog(struct gpio_desc *desc, const char *name, ...@@ -4122,12 +4120,11 @@ int gpiod_hog(struct gpio_desc *desc, const char *name,
*/ */
static void gpiochip_free_hogs(struct gpio_chip *gc) static void gpiochip_free_hogs(struct gpio_chip *gc)
{ {
struct gpio_desc *desc;
int id; int id;
for (id = 0; id < gc->ngpio; id++) { for_each_gpio_desc_with_flag(id, gc, desc, FLAG_IS_HOGGED)
if (test_bit(FLAG_IS_HOGGED, &gc->gpiodev->descs[id].flags)) gpiochip_free_own_desc(desc);
gpiochip_free_own_desc(&gc->gpiodev->descs[id]);
}
} }
/** /**
...@@ -4446,7 +4443,7 @@ static void *gpiolib_seq_next(struct seq_file *s, void *v, loff_t *pos) ...@@ -4446,7 +4443,7 @@ static void *gpiolib_seq_next(struct seq_file *s, void *v, loff_t *pos)
if (list_is_last(&gdev->list, &gpio_devices)) if (list_is_last(&gdev->list, &gpio_devices))
ret = NULL; ret = NULL;
else else
ret = list_entry(gdev->list.next, struct gpio_device, list); ret = list_first_entry(&gdev->list, struct gpio_device, list);
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
s->private = "\n"; s->private = "\n";
......
...@@ -37,6 +37,9 @@ ...@@ -37,6 +37,9 @@
* or name of the IP component in a System on Chip. * or name of the IP component in a System on Chip.
* @data: per-instance data assigned by the driver * @data: per-instance data assigned by the driver
* @list: links gpio_device:s together for traversal * @list: links gpio_device:s together for traversal
* @notifier: used to notify subscribers about lines being requested, released
* or reconfigured
* @pin_ranges: range of pins served by the GPIO driver
* *
* This state container holds most of the runtime variable data * This state container holds most of the runtime variable data
* for a GPIO device and can hold references and live on after the * for a GPIO device and can hold references and live on after the
...@@ -72,6 +75,20 @@ struct gpio_device { ...@@ -72,6 +75,20 @@ struct gpio_device {
/* gpio suffixes used for ACPI and device tree lookup */ /* gpio suffixes used for ACPI and device tree lookup */
static __maybe_unused const char * const gpio_suffixes[] = { "gpios", "gpio" }; static __maybe_unused const char * const gpio_suffixes[] = { "gpios", "gpio" };
/**
* struct gpio_array - Opaque descriptor for a structure of GPIO array attributes
*
* @desc: Array of pointers to the GPIO descriptors
* @size: Number of elements in desc
* @chip: Parent GPIO chip
* @get_mask: Get mask used in fastpath
* @set_mask: Set mask used in fastpath
* @invert_mask: Invert mask used in fastpath
*
* This structure is attached to struct gpiod_descs obtained from
* gpiod_get_array() and can be passed back to get/set array functions in order
* to activate fast processing path if applicable.
*/
struct gpio_array { struct gpio_array {
struct gpio_desc **desc; struct gpio_desc **desc;
unsigned int size; unsigned int size;
...@@ -82,6 +99,13 @@ struct gpio_array { ...@@ -82,6 +99,13 @@ struct gpio_array {
}; };
struct gpio_desc *gpiochip_get_desc(struct gpio_chip *gc, unsigned int hwnum); struct gpio_desc *gpiochip_get_desc(struct gpio_chip *gc, unsigned int hwnum);
#define for_each_gpio_desc_with_flag(i, gc, desc, flag) \
for (i = 0, desc = gpiochip_get_desc(gc, i); \
i < gc->ngpio; \
i++, desc = gpiochip_get_desc(gc, i)) \
if (!test_bit(flag, &desc->flags)) {} else
int gpiod_get_array_value_complex(bool raw, bool can_sleep, int gpiod_get_array_value_complex(bool raw, bool can_sleep,
unsigned int array_size, unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
...@@ -96,6 +120,23 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, ...@@ -96,6 +120,23 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
extern spinlock_t gpio_lock; extern spinlock_t gpio_lock;
extern struct list_head gpio_devices; extern struct list_head gpio_devices;
/**
* struct gpio_desc - Opaque descriptor for a GPIO
*
* @gdev: Pointer to the parent GPIO device
* @flags: Binary descriptor flags
* @label: Name of the consumer
* @name: Line name
* @hog: Pointer to the device node that hogs this line (if any)
* @debounce_period_us: Debounce period in microseconds
*
* These are obtained using gpiod_get() and are preferable to the old
* integer-based handles.
*
* Contrary to integers, a pointer to a &struct gpio_desc is guaranteed to be
* valid until the GPIO is released.
*/
struct gpio_desc { struct gpio_desc {
struct gpio_device *gdev; struct gpio_device *gdev;
unsigned long flags; unsigned long flags;
......
...@@ -8,27 +8,16 @@ ...@@ -8,27 +8,16 @@
#include <linux/err.h> #include <linux/err.h>
struct device; struct device;
/**
* Opaque descriptor for a GPIO. These are obtained using gpiod_get() and are
* preferable to the old integer-based handles.
*
* Contrary to integers, a pointer to a gpio_desc is guaranteed to be valid
* until the GPIO is released.
*/
struct gpio_desc; struct gpio_desc;
/**
* Opaque descriptor for a structure of GPIO array attributes. This structure
* is attached to struct gpiod_descs obtained from gpiod_get_array() and can be
* passed back to get/set array functions in order to activate fast processing
* path if applicable.
*/
struct gpio_array; struct gpio_array;
/** /**
* Struct containing an array of descriptors that can be obtained using * struct gpio_descs - Struct containing an array of descriptors that can be
* gpiod_get_array(). * obtained using gpiod_get_array()
*
* @info: Pointer to the opaque gpio_array structure
* @ndescs: Number of held descriptors
* @desc: Array of pointers to GPIO descriptors
*/ */
struct gpio_descs { struct gpio_descs {
struct gpio_array *info; struct gpio_array *info;
...@@ -43,8 +32,16 @@ struct gpio_descs { ...@@ -43,8 +32,16 @@ struct gpio_descs {
#define GPIOD_FLAGS_BIT_NONEXCLUSIVE BIT(4) #define GPIOD_FLAGS_BIT_NONEXCLUSIVE BIT(4)
/** /**
* Optional flags that can be passed to one of gpiod_* to configure direction * enum gpiod_flags - Optional flags that can be passed to one of gpiod_* to
* and output value. These values cannot be OR'd. * configure direction and output value. These values
* cannot be OR'd.
*
* @GPIOD_ASIS: Don't change anything
* @GPIOD_IN: Set lines to input mode
* @GPIOD_OUT_LOW: Set lines to output and drive them low
* @GPIOD_OUT_HIGH: Set lines to output and drive them high
* @GPIOD_OUT_LOW_OPEN_DRAIN: Set lines to open-drain output and drive them low
* @GPIOD_OUT_HIGH_OPEN_DRAIN: Set lines to open-drain output and drive them high
*/ */
enum gpiod_flags { enum gpiod_flags {
GPIOD_ASIS = 0, GPIOD_ASIS = 0,
......
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