gpio updates for v5.18-rc1
- 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 -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEFp3rbAvDxGAT0sefEacuoBRx13IFAmI7SAwACgkQEacuoBRx 13JJEA/+MdTAmPHyCp55POmKmxMIafejc2EXaZKYK82WhuqOBWyc4UHMzGGD/7YF TXKidJ8Bnzki2XiAJlHuyRLrBR67qUs79UkCKQPoEsaBJ4AeQj48bR8YHb+1x+gS 2LS7IqW4sFB5O61ZCB1Bg8k8Ots9E5OI4Q9+gGxyLVbCK0L8mN8U63a/Fhv4sIJU z5WBXVTOsIMrprN2N9/VxNnSUkRqaUcl78ko0yV9B6vi957pojkFApg3rdJmWqV6 RLGdrQIklY95SdlnTHuG8+7Jy0Ut/ohwdUFDpyd/Hv/qvzE/vRWdvsccSS8KHwtL dK+8sGN67QWfLmUhjqd0Y+Q/f/IIZyGHTkHWUojPE9cW6HJudgXQlCkcbjdV+tdB 2DO67wal6UKIw6efScLeBB7N/x9p8UioxVwHQiy05GBZJYTI184NWoel5hKqUbnh GZVBf30fVQxmsJoHJa7e+xPLcHOrrTU+80CR9NhZBBm6xNLbkl1MidbJWfuEgNC1 6+o6jhy5K+SS09NKQteJFNQtc7f2Mt3Rc1NQzxJc2AaQXFvqbQLC36qkk5oqeDKH Ndw4AYuxXWBU62sHZCJkWtG2CIAykvBNRoje3rXukbcv583jx18WScWJx/FKS9hh k//1hdlesCV1ouo4qDvCiEC5hby0+FQ/HWgkXGIlNC/gZ6fcrZs= =0SYv -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
ebcb577aee
|
@ -0,0 +1,66 @@
|
|||
# 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>;
|
||||
};
|
||||
|
||||
...
|
|
@ -1,27 +0,0 @@
|
|||
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>;
|
||||
};
|
|
@ -0,0 +1,65 @@
|
|||
# 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:
|
|||
- const: fsl,imx7ulp-gpio
|
||||
- const: fsl,vf610-gpio
|
||||
- items:
|
||||
- const: fsl,imx8ulp-gpio
|
||||
- enum:
|
||||
- fsl,imx93-gpio
|
||||
- fsl,imx8ulp-gpio
|
||||
- const: fsl,imx7ulp-gpio
|
||||
|
||||
reg:
|
||||
|
|
|
@ -213,7 +213,7 @@ Example of two SOC GPIO banks defined as gpio-controller nodes:
|
|||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
|
||||
line_b {
|
||||
line_b-hog {
|
||||
gpio-hog;
|
||||
gpios = <6 0>;
|
||||
output-low;
|
||||
|
|
|
@ -247,6 +247,16 @@ config GPIO_EM
|
|||
help
|
||||
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
|
||||
def_bool y
|
||||
depends on ARCH_EP93XX
|
||||
|
@ -1380,7 +1390,7 @@ config GPIO_TPS65912
|
|||
This driver supports TPS65912 GPIO chip.
|
||||
|
||||
config GPIO_TPS68470
|
||||
bool "TPS68470 GPIO"
|
||||
tristate "TPS68470 GPIO"
|
||||
depends on INTEL_SKL_INT3472
|
||||
help
|
||||
Select this option to enable GPIO driver for the TPS68470
|
||||
|
@ -1390,10 +1400,6 @@ config GPIO_TPS68470
|
|||
input or output as appropriate, the sensor related 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
|
||||
tristate "TQ-Systems QTMX86 GPIO"
|
||||
depends on MFD_TQMX86 || COMPILE_TEST
|
||||
|
|
|
@ -55,6 +55,7 @@ obj-$(CONFIG_GPIO_DLN2) += gpio-dln2.o
|
|||
obj-$(CONFIG_GPIO_DWAPB) += gpio-dwapb.o
|
||||
obj-$(CONFIG_GPIO_EIC_SPRD) += gpio-eic-sprd.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_EXAR) += gpio-exar.o
|
||||
obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/gpio/driver.h>
|
||||
#include <linux/mfd/altera-a10sr.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/property.h>
|
||||
|
||||
/**
|
||||
* 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)
|
|||
|
||||
gpio->gp = altr_a10sr_gc;
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -370,7 +370,14 @@ static int crystalcove_gpio_probe(struct platform_device *pdev)
|
|||
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 = {
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
// 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)
|
|||
int retval;
|
||||
|
||||
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++) {
|
||||
range = &mrfld_gpio_ranges[i];
|
||||
retval = gpiochip_add_pin_range(&priv->chip, pinctrl_dev_name,
|
||||
|
|
|
@ -691,7 +691,6 @@ static int tegra_gpio_probe(struct platform_device *pdev)
|
|||
tgi->gc.base = 0;
|
||||
tgi->gc.ngpio = tgi->bank_count * 32;
|
||||
tgi->gc.parent = &pdev->dev;
|
||||
tgi->gc.of_node = pdev->dev.of_node;
|
||||
|
||||
tgi->ic.name = "GPIO";
|
||||
tgi->ic.irq_ack = tegra_gpio_irq_ack;
|
||||
|
|
|
@ -154,5 +154,8 @@ static struct platform_driver tps68470_gpio_driver = {
|
|||
},
|
||||
.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");
|
||||
|
|
|
@ -1,17 +1,9 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Digital I/O driver for Technologic Systems I2C FPGA Core
|
||||
*
|
||||
* Copyright (C) 2015, 2018 Technologic Systems
|
||||
* 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>
|
||||
|
|
|
@ -711,14 +711,12 @@ static int of_gpiochip_scan_gpios(struct gpio_chip *chip)
|
|||
static void of_gpiochip_remove_hog(struct gpio_chip *chip,
|
||||
struct device_node *hog)
|
||||
{
|
||||
struct gpio_desc *descs = chip->gpiodev->descs;
|
||||
struct gpio_desc *desc;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < chip->ngpio; i++) {
|
||||
if (test_bit(FLAG_IS_HOGGED, &descs[i].flags) &&
|
||||
descs[i].hog == hog)
|
||||
gpiochip_free_own_desc(&descs[i]);
|
||||
}
|
||||
for_each_gpio_desc_with_flag(i, chip, desc, FLAG_IS_HOGGED)
|
||||
if (desc->hog == hog)
|
||||
gpiochip_free_own_desc(desc);
|
||||
}
|
||||
|
||||
static int of_gpiochip_match_node(struct gpio_chip *chip, void *data)
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "gpiolib.h"
|
||||
#include "gpiolib-sysfs.h"
|
||||
|
||||
#define GPIO_IRQF_TRIGGER_NONE 0
|
||||
#define GPIO_IRQF_TRIGGER_FALLING BIT(0)
|
||||
#define GPIO_IRQF_TRIGGER_RISING BIT(1)
|
||||
#define GPIO_IRQF_TRIGGER_BOTH (GPIO_IRQF_TRIGGER_FALLING | \
|
||||
|
@ -61,17 +62,16 @@ static ssize_t direction_show(struct device *dev,
|
|||
{
|
||||
struct gpiod_data *data = dev_get_drvdata(dev);
|
||||
struct gpio_desc *desc = data->desc;
|
||||
ssize_t status;
|
||||
int value;
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
|
||||
gpiod_get_direction(desc);
|
||||
status = sysfs_emit(buf, "%s\n",
|
||||
test_bit(FLAG_IS_OUT, &desc->flags) ? "out" : "in");
|
||||
value = !!test_bit(FLAG_IS_OUT, &desc->flags);
|
||||
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
return status;
|
||||
return sysfs_emit(buf, "%s\n", value ? "out" : "in");
|
||||
}
|
||||
|
||||
static ssize_t direction_store(struct device *dev,
|
||||
|
@ -108,12 +108,13 @@ static ssize_t value_show(struct device *dev,
|
|||
mutex_lock(&data->mutex);
|
||||
|
||||
status = gpiod_get_value_cansleep(desc);
|
||||
if (status >= 0)
|
||||
status = sysfs_emit(buf, "%zd\n", status);
|
||||
|
||||
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,
|
||||
|
@ -121,24 +122,18 @@ static ssize_t value_store(struct device *dev,
|
|||
{
|
||||
struct gpiod_data *data = dev_get_drvdata(dev);
|
||||
struct gpio_desc *desc = data->desc;
|
||||
ssize_t status = 0;
|
||||
ssize_t status;
|
||||
long value;
|
||||
|
||||
status = kstrtol(buf, 0, &value);
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
|
||||
if (!test_bit(FLAG_IS_OUT, &desc->flags)) {
|
||||
status = -EPERM;
|
||||
} else {
|
||||
long value;
|
||||
|
||||
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;
|
||||
}
|
||||
} else if (status == 0) {
|
||||
gpiod_set_value_cansleep(desc, value);
|
||||
status = size;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->mutex);
|
||||
|
@ -224,54 +219,41 @@ static void gpio_sysfs_free_irq(struct device *dev)
|
|||
sysfs_put(data->value_kn);
|
||||
}
|
||||
|
||||
static const struct {
|
||||
const char *name;
|
||||
unsigned char flags;
|
||||
} trigger_types[] = {
|
||||
{ "none", 0 },
|
||||
{ "falling", GPIO_IRQF_TRIGGER_FALLING },
|
||||
{ "rising", GPIO_IRQF_TRIGGER_RISING },
|
||||
{ "both", GPIO_IRQF_TRIGGER_BOTH },
|
||||
static const char * const trigger_names[] = {
|
||||
[GPIO_IRQF_TRIGGER_NONE] = "none",
|
||||
[GPIO_IRQF_TRIGGER_FALLING] = "falling",
|
||||
[GPIO_IRQF_TRIGGER_RISING] = "rising",
|
||||
[GPIO_IRQF_TRIGGER_BOTH] = "both",
|
||||
};
|
||||
|
||||
static ssize_t edge_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct gpiod_data *data = dev_get_drvdata(dev);
|
||||
ssize_t status = 0;
|
||||
int i;
|
||||
int flags;
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(trigger_types); i++) {
|
||||
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);
|
||||
flags = data->irq_flags;
|
||||
|
||||
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,
|
||||
struct device_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
struct gpiod_data *data = dev_get_drvdata(dev);
|
||||
unsigned char flags;
|
||||
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);
|
||||
|
||||
|
@ -324,16 +306,15 @@ static ssize_t active_low_show(struct device *dev,
|
|||
{
|
||||
struct gpiod_data *data = dev_get_drvdata(dev);
|
||||
struct gpio_desc *desc = data->desc;
|
||||
ssize_t status;
|
||||
int value;
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
|
||||
status = sysfs_emit(buf, "%d\n",
|
||||
!!test_bit(FLAG_ACTIVE_LOW, &desc->flags));
|
||||
value = !!test_bit(FLAG_ACTIVE_LOW, &desc->flags);
|
||||
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
return status;
|
||||
return sysfs_emit(buf, "%d\n", value);
|
||||
}
|
||||
|
||||
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;
|
||||
long value;
|
||||
|
||||
status = kstrtol(buf, 0, &value);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
|
||||
status = kstrtol(buf, 0, &value);
|
||||
if (status == 0)
|
||||
status = gpio_sysfs_set_active_low(dev, value);
|
||||
status = gpio_sysfs_set_active_low(dev, value);
|
||||
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
|
@ -790,11 +773,8 @@ void gpiochip_sysfs_unregister(struct gpio_device *gdev)
|
|||
mutex_unlock(&sysfs_lock);
|
||||
|
||||
/* unregister gpiod class devices owned by sysfs */
|
||||
for (i = 0; i < chip->ngpio; i++) {
|
||||
desc = &gdev->descs[i];
|
||||
if (test_and_clear_bit(FLAG_SYSFS, &desc->flags))
|
||||
gpiod_free(desc);
|
||||
}
|
||||
for_each_gpio_desc_with_flag(i, chip, desc, FLAG_SYSFS)
|
||||
gpiod_free(desc);
|
||||
}
|
||||
|
||||
static int __init gpiolib_sysfs_init(void)
|
||||
|
|
|
@ -262,14 +262,14 @@ static int gpiodev_add_to_list(struct gpio_device *gdev)
|
|||
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) {
|
||||
/* add before first entry */
|
||||
list_add(&gdev->list, &gpio_devices);
|
||||
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) {
|
||||
/* add behind last entry */
|
||||
list_add_tail(&gdev->list, &gpio_devices);
|
||||
|
@ -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
|
||||
* 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 == -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 {
|
||||
if (!(ret == -EBUSY && flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE))
|
||||
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);
|
||||
|
@ -4122,12 +4120,11 @@ int gpiod_hog(struct gpio_desc *desc, const char *name,
|
|||
*/
|
||||
static void gpiochip_free_hogs(struct gpio_chip *gc)
|
||||
{
|
||||
struct gpio_desc *desc;
|
||||
int id;
|
||||
|
||||
for (id = 0; id < gc->ngpio; id++) {
|
||||
if (test_bit(FLAG_IS_HOGGED, &gc->gpiodev->descs[id].flags))
|
||||
gpiochip_free_own_desc(&gc->gpiodev->descs[id]);
|
||||
}
|
||||
for_each_gpio_desc_with_flag(id, gc, desc, FLAG_IS_HOGGED)
|
||||
gpiochip_free_own_desc(desc);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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))
|
||||
ret = NULL;
|
||||
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);
|
||||
|
||||
s->private = "\n";
|
||||
|
|
|
@ -37,6 +37,9 @@
|
|||
* or name of the IP component in a System on Chip.
|
||||
* @data: per-instance data assigned by the driver
|
||||
* @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
|
||||
* for a GPIO device and can hold references and live on after the
|
||||
|
@ -72,6 +75,20 @@ struct gpio_device {
|
|||
/* gpio suffixes used for ACPI and device tree lookup */
|
||||
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_desc **desc;
|
||||
unsigned int size;
|
||||
|
@ -82,6 +99,13 @@ struct gpio_array {
|
|||
};
|
||||
|
||||
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,
|
||||
unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
|
@ -96,6 +120,23 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
|
|||
extern spinlock_t gpio_lock;
|
||||
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_device *gdev;
|
||||
unsigned long flags;
|
||||
|
|
|
@ -8,27 +8,16 @@
|
|||
#include <linux/err.h>
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* 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 containing an array of descriptors that can be obtained using
|
||||
* gpiod_get_array().
|
||||
* struct gpio_descs - Struct containing an array of descriptors that can be
|
||||
* 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_array *info;
|
||||
|
@ -43,8 +32,16 @@ struct gpio_descs {
|
|||
#define GPIOD_FLAGS_BIT_NONEXCLUSIVE BIT(4)
|
||||
|
||||
/**
|
||||
* Optional flags that can be passed to one of gpiod_* to configure direction
|
||||
* and output value. These values cannot be OR'd.
|
||||
* enum gpiod_flags - Optional flags that can be passed to one of gpiod_* to
|
||||
* 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 {
|
||||
GPIOD_ASIS = 0,
|
||||
|
|
Loading…
Reference in New Issue