Commit c0f234ff authored by Linus Torvalds's avatar Linus Torvalds

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

Pull gpio updates from Bartosz Golaszewski:
 "We have a new GPIO multiplexer driver, bunch of driver updates and
  refactoring in the core GPIO library.

  GPIO core:
   - teach gpiolib to work with software nodes for HW description
   - remove ARCH_NR_GPIOS treewide as we no longer impose any limit on
     the number of GPIOS since the allocation became entirely dynamic
   - add support for HW quirks for Cirrus CS42L56 codec, Marvell NFC
     controller, Freescale PCIe and Ethernet controller, Himax LCDs and
     Mediatek mt2701
   - refactor OF quirk code
   - some general refactoring of the OF and ACPI code, adding new
     helpers, minor tweaks and fixes, making fwnode usage consistent
     etc.

  GPIO uAPI:
   - fix an issue where the user-space can trigger a NULL-pointer
     dereference in the kernel by opening a device file, forcing a
     driver unbind and then calling one of the syscalls on the
     associated file descriptor

  New drivers:
   - add gpio-latch: a new GPIO multiplexer based on latches connected
     to other GPIOs

  Driver updates:
   - convert i2c GPIO expanders to using .probe_new()
   - drop the gpio-sta2x11 driver
   - factor out common code for the ACCES IDIO-16 family of controllers
     and use this new library wherever applicable in drivers
   - add DT support to gpio-hisi
   - allow building gpio-davinci as a module and increase its maxItems
     property
   - add support for a new model to gpio-pca9570
   - other minor changes to various drivers"

* tag 'gpio-updates-for-v6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux: (66 commits)
  gpio: sim: set a limit on the number of GPIOs
  gpiolib: protect the GPIO device against being dropped while in use by user-space
  gpiolib: cdev: fix NULL-pointer dereferences
  gpiolib: Provide to_gpio_device() helper
  gpiolib: Unify access to the device properties
  gpio: Do not include <linux/kernel.h> when not really needed.
  gpio: pcf857x: Convert to i2c's .probe_new()
  gpio: pca953x: Convert to i2c's .probe_new()
  gpio: max732x: Convert to i2c's .probe_new()
  dt-bindings: gpio: gpio-davinci: Increase maxItems in gpio-line-names
  gpiolib: ensure that fwnode is properly set
  gpio: sl28cpld: Replace irqchip mask_invert with unmask_base
  gpiolib: of: Use correct fwnode for DT-probed chips
  gpiolib: of: Drop redundant check in of_mm_gpiochip_remove()
  gpiolib: of: Prepare of_mm_gpiochip_add_data() for fwnode
  gpiolib: add support for software nodes
  gpiolib: consolidate GPIO lookups
  gpiolib: acpi: avoid leaking ACPI details into upper gpiolib layers
  gpiolib: acpi: teach acpi_find_gpio() to handle data-only nodes
  gpiolib: acpi: change acpi_find_gpio() to accept firmware node
  ...
parents 9fa4abc9 11e47bbd
......@@ -35,7 +35,7 @@ properties:
gpio-line-names:
description: strings describing the names of each gpio line.
minItems: 1
maxItems: 100
maxItems: 144
"#gpio-cells":
const: 2
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/gpio/gpio-latch.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: GPIO latch controller
maintainers:
- Sascha Hauer <s.hauer@pengutronix.de>
description: |
This binding describes a GPIO multiplexer based on latches connected to
other GPIOs, like this:
CLK0 ----------------------. ,--------.
CLK1 -------------------. `--------|> #0 |
| | |
OUT0 ----------------+--|-----------|D0 Q0|-----|<
OUT1 --------------+-|--|-----------|D1 Q1|-----|<
OUT2 ------------+-|-|--|-----------|D2 Q2|-----|<
OUT3 ----------+-|-|-|--|-----------|D3 Q3|-----|<
OUT4 --------+-|-|-|-|--|-----------|D4 Q4|-----|<
OUT5 ------+-|-|-|-|-|--|-----------|D5 Q5|-----|<
OUT6 ----+-|-|-|-|-|-|--|-----------|D6 Q6|-----|<
OUT7 --+-|-|-|-|-|-|-|--|-----------|D7 Q7|-----|<
| | | | | | | | | `--------'
| | | | | | | | |
| | | | | | | | | ,--------.
| | | | | | | | `-----------|> #1 |
| | | | | | | | | |
| | | | | | | `--------------|D0 Q0|-----|<
| | | | | | `----------------|D1 Q1|-----|<
| | | | | `------------------|D2 Q2|-----|<
| | | | `--------------------|D3 Q3|-----|<
| | | `----------------------|D4 Q4|-----|<
| | `------------------------|D5 Q5|-----|<
| `--------------------------|D6 Q6|-----|<
`----------------------------|D7 Q7|-----|<
`--------'
The number of clk-gpios and latched-gpios is not fixed. The actual number
of number of latches and the number of inputs per latch is derived from
the number of GPIOs given in the corresponding device tree properties.
properties:
compatible:
const: gpio-latch
"#gpio-cells":
const: 2
clk-gpios:
description: Array of GPIOs to be used to clock a latch
latched-gpios:
description: Array of GPIOs to be used as inputs per latch
setup-duration-ns:
description: Delay in nanoseconds to wait after the latch inputs have been
set up
clock-duration-ns:
description: Delay in nanoseconds to wait between clock output changes
gpio-controller: true
gpio-line-names: true
required:
- compatible
- "#gpio-cells"
- gpio-controller
- clk-gpios
- latched-gpios
additionalProperties: false
examples:
- |
gpio-latch {
#gpio-cells = <2>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_di_do_leds>;
compatible = "gpio-latch";
gpio-controller;
setup-duration-ns = <100>;
clock-duration-ns = <100>;
clk-gpios = <&gpio3 7 0>, <&gpio3 8 0>;
latched-gpios = <&gpio3 21 0>, <&gpio3 22 0>,
<&gpio3 23 0>, <&gpio3 24 0>,
<&gpio3 25 0>, <&gpio3 26 0>,
<&gpio3 27 0>, <&gpio3 28 0>;
};
......@@ -12,6 +12,7 @@ maintainers:
properties:
compatible:
enum:
- dlg,slg7xl45106
- nxp,pca9570
- nxp,pca9571
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/gpio/hisilicon,ascend910-gpio.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: HiSilicon common GPIO controller
maintainers:
- Jay Fang <f.fangjian@huawei.com>
description:
The HiSilicon common GPIO controller can be used for many different
types of SoC such as Huawei Ascend AI series chips.
properties:
compatible:
const: hisilicon,ascend910-gpio
reg:
maxItems: 1
interrupts:
maxItems: 1
gpio-controller: true
"#gpio-cells":
const: 2
ngpios:
minimum: 1
maximum: 32
required:
- compatible
- reg
- interrupts
- gpio-controller
- "#gpio-cells"
- ngpios
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
gpio@840d0000 {
compatible = "hisilicon,ascend910-gpio";
reg = <0x840d0000 0x1000>;
ngpios = <32>;
gpio-controller;
#gpio-cells = <2>;
interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
};
......@@ -558,11 +558,6 @@ Platform Support
To force-enable this framework, a platform's Kconfig will "select" GPIOLIB,
else it is up to the user to configure support for GPIO.
It may also provide a custom value for ARCH_NR_GPIOS, so that it better
reflects the number of GPIOs in actual use on that platform, without
wasting static table space. (It should count both built-in/SoC GPIOs and
also ones on GPIO expanders.
If neither of these options are selected, the platform does not support
GPIOs through GPIO-lib and the code cannot be enabled by the user.
......
......@@ -312,6 +312,13 @@ L: linux-iio@vger.kernel.org
S: Maintained
F: drivers/counter/104-quad-8.c
ACCES IDIO-16 GPIO LIBRARY
M: William Breathitt Gray <william.gray@linaro.org>
L: linux-gpio@vger.kernel.org
S: Maintained
F: drivers/gpio/gpio-idio-16.c
F: drivers/gpio/gpio-idio-16.h
ACCES PCI-IDIO-16 GPIO DRIVER
M: William Breathitt Gray <william.gray@linaro.org>
L: linux-gpio@vger.kernel.org
......@@ -9266,6 +9273,7 @@ HISILICON GPIO DRIVER
M: Jay Fang <f.fangjian@huawei.com>
L: linux-gpio@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/gpio/hisilicon,ascend910-gpio.yaml
F: drivers/gpio/gpio-hisi.c
HISILICON HIGH PERFORMANCE RSA ENGINE DRIVER (HPRE)
......
......@@ -1158,27 +1158,6 @@ config ARM_PSCI
0022A ("Power State Coordination Interface System Software on
ARM processors").
# The GPIO number here must be sorted by descending number. In case of
# a multiplatform kernel, we just want the highest value required by the
# selected platforms.
config ARCH_NR_GPIO
int
default 2048 if ARCH_INTEL_SOCFPGA
default 1024 if ARCH_BRCMSTB || ARCH_RENESAS || ARCH_TEGRA || \
ARCH_ZYNQ || ARCH_ASPEED
default 512 if ARCH_EXYNOS || ARCH_KEYSTONE || SOC_OMAP5 || \
SOC_DRA7XX || ARCH_S3C24XX || ARCH_S3C64XX || ARCH_S5PV210
default 416 if ARCH_SUNXI
default 392 if ARCH_U8500
default 352 if ARCH_VT8500
default 288 if ARCH_ROCKCHIP
default 264 if MACH_H4700
default 0
help
Maximum number of GPIOs in the system.
If unsure, leave the default value.
config HZ_FIXED
int
default 128 if SOC_AT91RM9200
......
......@@ -2,7 +2,6 @@
#ifndef _ARCH_ARM_GPIO_H
#define _ARCH_ARM_GPIO_H
/* Note: this may rely upon the value of ARCH_NR_GPIOS set in mach/gpio.h */
#include <asm-generic/gpio.h>
/* The trivial gpiolib dispatchers */
......
......@@ -2168,18 +2168,6 @@ config STACKPROTECTOR_PER_TASK
def_bool y
depends on STACKPROTECTOR && CC_HAVE_STACKPROTECTOR_SYSREG
# The GPIO number here must be sorted by descending number. In case of
# a multiplatform kernel, we just want the highest value required by the
# selected platforms.
config ARCH_NR_GPIO
int
default 2048 if ARCH_APPLE
default 0
help
Maximum number of GPIOs in the system.
If unsure, leave the default value.
config UNWIND_PATCH_PAC_INTO_SCS
bool "Enable shadow call stack dynamically using code patching"
# needs Clang with https://reviews.llvm.org/D111780 incorporated
......
......@@ -361,11 +361,6 @@ config ARCH_HAS_CPU_RELAX
config ARCH_HIBERNATION_POSSIBLE
def_bool y
config ARCH_NR_GPIO
int
default 1024 if X86_64
default 512
config ARCH_SUSPEND_POSSIBLE
def_bool y
......
......@@ -109,6 +109,15 @@ config GPIO_REGMAP
config GPIO_MAX730X
tristate
config GPIO_IDIO_16
tristate
help
Enables support for the idio-16 library functions. The idio-16 library
provides functions to facilitate communication with devices within the
ACCES IDIO-16 family such as the 104-IDIO-16 and the PCI-IDIO-16.
If built as a module its name will be gpio-idio-16.
menu "Memory mapped GPIO drivers"
depends on HAS_IOMEM
......@@ -219,7 +228,7 @@ config GPIO_CLPS711X
Say yes here to support GPIO on CLPS711X SoCs.
config GPIO_DAVINCI
bool "TI Davinci/Keystone GPIO support"
tristate "TI Davinci/Keystone GPIO support"
default y if ARCH_DAVINCI
depends on (ARM || ARM64) && (ARCH_DAVINCI || ARCH_KEYSTONE || ARCH_K3)
help
......@@ -310,7 +319,7 @@ config GPIO_GRGPIO
config GPIO_HISI
tristate "HiSilicon GPIO controller driver"
depends on (ARM64 && ACPI) || COMPILE_TEST
depends on ARM64 || COMPILE_TEST
select GPIO_GENERIC
select GPIOLIB_IRQCHIP
help
......@@ -600,14 +609,6 @@ config GPIO_SPRD
help
Say yes here to support Spreadtrum GPIO device.
config GPIO_STA2X11
bool "STA2x11/ConneXt GPIO support"
depends on MFD_STA2X11
select GENERIC_IRQ_CHIP
help
Say yes here to support the STA2x11/ConneXt GPIO device.
The GPIO module has 128 GPIO pins with alternate functions.
config GPIO_STP_XWAY
bool "XWAY STP GPIOs"
depends on SOC_XWAY || COMPILE_TEST
......@@ -857,6 +858,7 @@ config GPIO_104_IDIO_16
depends on PC104
select ISA_BUS_API
select GPIOLIB_IRQCHIP
select GPIO_IDIO_16
help
Enables GPIO support for the ACCES 104-IDIO-16 family (104-IDIO-16,
104-IDIO-16E, 104-IDO-16, 104-IDIO-8, 104-IDIO-8E, 104-IDO-8). The
......@@ -1561,6 +1563,7 @@ config GPIO_PCH
config GPIO_PCI_IDIO_16
tristate "ACCES PCI-IDIO-16 GPIO support"
select GPIOLIB_IRQCHIP
select GPIO_IDIO_16
help
Enables GPIO support for the ACCES PCI-IDIO-16. An interrupt is
generated when any of the inputs change state (low to high or high to
......@@ -1681,6 +1684,12 @@ config GPIO_AGGREGATOR
industrial control context, to be operated from userspace using
the GPIO chardev interface.
config GPIO_LATCH
tristate "GPIO latch driver"
help
Say yes here to enable a driver for GPIO multiplexers based on latches
connected to other GPIOs.
config GPIO_MOCKUP
tristate "GPIO Testing Driver"
select IRQ_SIM
......
......@@ -10,6 +10,7 @@ obj-$(CONFIG_OF_GPIO) += gpiolib-of.o
obj-$(CONFIG_GPIO_CDEV) += gpiolib-cdev.o
obj-$(CONFIG_GPIO_SYSFS) += gpiolib-sysfs.o
obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o
obj-$(CONFIG_GPIOLIB) += gpiolib-swnode.o
# Device drivers. Generally keep list sorted alphabetically
obj-$(CONFIG_GPIO_REGMAP) += gpio-regmap.o
......@@ -68,6 +69,7 @@ obj-$(CONFIG_GPIO_HLWD) += gpio-hlwd.o
obj-$(CONFIG_HTC_EGPIO) += gpio-htc-egpio.o
obj-$(CONFIG_GPIO_I8255) += gpio-i8255.o
obj-$(CONFIG_GPIO_ICH) += gpio-ich.o
obj-$(CONFIG_GPIO_IDIO_16) += gpio-idio-16.o
obj-$(CONFIG_GPIO_IDT3243X) += gpio-idt3243x.o
obj-$(CONFIG_GPIO_IMX_SCU) += gpio-imx-scu.o
obj-$(CONFIG_GPIO_IOP) += gpio-iop.o
......@@ -75,6 +77,7 @@ obj-$(CONFIG_GPIO_IT87) += gpio-it87.o
obj-$(CONFIG_GPIO_IXP4XX) += gpio-ixp4xx.o
obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o
obj-$(CONFIG_GPIO_KEMPLD) += gpio-kempld.o
obj-$(CONFIG_GPIO_LATCH) += gpio-latch.o
obj-$(CONFIG_GPIO_LOGICVC) += gpio-logicvc.o
obj-$(CONFIG_GPIO_LOONGSON1) += gpio-loongson1.o
obj-$(CONFIG_GPIO_LOONGSON) += gpio-loongson.o
......@@ -140,7 +143,6 @@ obj-$(CONFIG_GPIO_SL28CPLD) += gpio-sl28cpld.o
obj-$(CONFIG_GPIO_SODAVILLE) += gpio-sodaville.o
obj-$(CONFIG_GPIO_SPEAR_SPICS) += gpio-spear-spics.o
obj-$(CONFIG_GPIO_SPRD) += gpio-sprd.o
obj-$(CONFIG_GPIO_STA2X11) += gpio-sta2x11.o
obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o
obj-$(CONFIG_GPIO_STP_XWAY) += gpio-stp-xway.o
obj-$(CONFIG_GPIO_SYSCON) += gpio-syscon.o
......
......@@ -124,6 +124,13 @@ Work items:
this with dry-coding and sending to maintainers to test
Generic regmap GPIO
In the very similar way to Generic MMIO GPIO convert the users which can
take advantage of using regmap over direct IO accessors. Note, even in
MMIO case the regmap MMIO with gpio-regmap.c is preferable over gpio-mmio.c.
GPIOLIB irqchip
The GPIOLIB irqchip is a helper irqchip for "simple cases" that should
......
......@@ -6,7 +6,7 @@
* This driver supports the following ACCES devices: 104-IDIO-16,
* 104-IDIO-16E, 104-IDO-16, 104-IDIO-8, 104-IDIO-8E, and 104-IDO-8.
*/
#include <linux/bits.h>
#include <linux/bitmap.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/gpio/driver.h>
......@@ -21,6 +21,8 @@
#include <linux/spinlock.h>
#include <linux/types.h>
#include "gpio-idio-16.h"
#define IDIO_16_EXTENT 8
#define MAX_NUM_IDIO_16 max_num_isa_dev(IDIO_16_EXTENT)
......@@ -34,49 +36,26 @@ static unsigned int num_irq;
module_param_hw_array(irq, uint, irq, &num_irq, 0);
MODULE_PARM_DESC(irq, "ACCES 104-IDIO-16 interrupt line numbers");
/**
* struct idio_16_reg - device registers structure
* @out0_7: Read: N/A
* Write: FET Drive Outputs 0-7
* @in0_7: Read: Isolated Inputs 0-7
* Write: Clear Interrupt
* @irq_ctl: Read: Enable IRQ
* Write: Disable IRQ
* @unused: N/A
* @out8_15: Read: N/A
* Write: FET Drive Outputs 8-15
* @in8_15: Read: Isolated Inputs 8-15
* Write: N/A
*/
struct idio_16_reg {
u8 out0_7;
u8 in0_7;
u8 irq_ctl;
u8 unused;
u8 out8_15;
u8 in8_15;
};
/**
* struct idio_16_gpio - GPIO device private data structure
* @chip: instance of the gpio_chip
* @lock: synchronization lock to prevent I/O race conditions
* @irq_mask: I/O bits affected by interrupts
* @reg: I/O address offset for the device registers
* @out_state: output bits state
* @state: ACCES IDIO-16 device state
*/
struct idio_16_gpio {
struct gpio_chip chip;
raw_spinlock_t lock;
unsigned long irq_mask;
struct idio_16_reg __iomem *reg;
unsigned int out_state;
struct idio_16 __iomem *reg;
struct idio_16_state state;
};
static int idio_16_gpio_get_direction(struct gpio_chip *chip,
unsigned int offset)
{
if (offset > 15)
if (idio_16_get_direction(offset))
return GPIO_LINE_DIRECTION_IN;
return GPIO_LINE_DIRECTION_OUT;
......@@ -98,15 +77,8 @@ static int idio_16_gpio_direction_output(struct gpio_chip *chip,
static int idio_16_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
const unsigned int mask = BIT(offset-16);
if (offset < 16)
return -EINVAL;
if (offset < 24)
return !!(ioread8(&idio16gpio->reg->in0_7) & mask);
return !!(ioread8(&idio16gpio->reg->in8_15) & (mask>>8));
return idio_16_get(idio16gpio->reg, &idio16gpio->state, offset);
}
static int idio_16_gpio_get_multiple(struct gpio_chip *chip,
......@@ -114,11 +86,7 @@ static int idio_16_gpio_get_multiple(struct gpio_chip *chip,
{
struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
*bits = 0;
if (*mask & GENMASK(23, 16))
*bits |= (unsigned long)ioread8(&idio16gpio->reg->in0_7) << 16;
if (*mask & GENMASK(31, 24))
*bits |= (unsigned long)ioread8(&idio16gpio->reg->in8_15) << 24;
idio_16_get_multiple(idio16gpio->reg, &idio16gpio->state, mask, bits);
return 0;
}
......@@ -127,44 +95,16 @@ static void idio_16_gpio_set(struct gpio_chip *chip, unsigned int offset,
int value)
{
struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
const unsigned int mask = BIT(offset);
unsigned long flags;
if (offset > 15)
return;
raw_spin_lock_irqsave(&idio16gpio->lock, flags);
if (value)
idio16gpio->out_state |= mask;
else
idio16gpio->out_state &= ~mask;
if (offset > 7)
iowrite8(idio16gpio->out_state >> 8, &idio16gpio->reg->out8_15);
else
iowrite8(idio16gpio->out_state, &idio16gpio->reg->out0_7);
raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
idio_16_set(idio16gpio->reg, &idio16gpio->state, offset, value);
}
static void idio_16_gpio_set_multiple(struct gpio_chip *chip,
unsigned long *mask, unsigned long *bits)
{
struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
unsigned long flags;
raw_spin_lock_irqsave(&idio16gpio->lock, flags);
idio16gpio->out_state &= ~*mask;
idio16gpio->out_state |= *mask & *bits;
if (*mask & 0xFF)
iowrite8(idio16gpio->out_state, &idio16gpio->reg->out0_7);
if ((*mask >> 8) & 0xFF)
iowrite8(idio16gpio->out_state >> 8, &idio16gpio->reg->out8_15);
raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
idio_16_set_multiple(idio16gpio->reg, &idio16gpio->state, mask, bits);
}
static void idio_16_irq_ack(struct irq_data *data)
......@@ -301,7 +241,10 @@ static int idio_16_probe(struct device *dev, unsigned int id)
idio16gpio->chip.get_multiple = idio_16_gpio_get_multiple;
idio16gpio->chip.set = idio_16_gpio_set;
idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;
idio16gpio->out_state = 0xFFFF;
idio_16_state_init(&idio16gpio->state);
/* FET off states are represented by bit values of "1" */
bitmap_fill(idio16gpio->state.out_state, IDIO_16_NOUT);
girq = &idio16gpio->chip.irq;
gpio_irq_chip_set_chip(girq, &idio_16_irqchip);
......@@ -343,3 +286,4 @@ module_isa_driver_with_irq(idio_16_driver, num_idio_16, num_irq);
MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
MODULE_DESCRIPTION("ACCES 104-IDIO-16 GPIO driver");
MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS(GPIO_IDIO_16);
......@@ -23,6 +23,7 @@
#include <linux/spinlock.h>
#include <linux/string.h>
#define AGGREGATOR_MAX_GPIOS 512
/*
* GPIO Aggregator sysfs interface
......@@ -64,7 +65,7 @@ static int aggr_parse(struct gpio_aggregator *aggr)
unsigned int i, n = 0;
int error = 0;
bitmap = bitmap_alloc(ARCH_NR_GPIOS, GFP_KERNEL);
bitmap = bitmap_alloc(AGGREGATOR_MAX_GPIOS, GFP_KERNEL);
if (!bitmap)
return -ENOMEM;
......@@ -84,13 +85,13 @@ static int aggr_parse(struct gpio_aggregator *aggr)
}
/* GPIO chip + offset(s) */
error = bitmap_parselist(offsets, bitmap, ARCH_NR_GPIOS);
error = bitmap_parselist(offsets, bitmap, AGGREGATOR_MAX_GPIOS);
if (error) {
pr_err("Cannot parse %s: %d\n", offsets, error);
goto free_bitmap;
}
for_each_set_bit(i, bitmap, ARCH_NR_GPIOS) {
for_each_set_bit(i, bitmap, AGGREGATOR_MAX_GPIOS) {
error = aggr_add_gpio(aggr, name, i, &n);
if (error)
goto free_bitmap;
......
......@@ -217,9 +217,6 @@ static int davinci_gpio_probe(struct platform_device *pdev)
return -EINVAL;
}
if (WARN_ON(ARCH_NR_GPIOS < ngpio))
ngpio = ARCH_NR_GPIOS;
/*
* If there are unbanked interrupts then the number of
* interrupts is equal to number of gpios else all are banked so
......@@ -730,3 +727,14 @@ static int __init davinci_gpio_drv_reg(void)
return platform_driver_register(&davinci_gpio_driver);
}
postcore_initcall(davinci_gpio_drv_reg);
static void __exit davinci_gpio_exit(void)
{
platform_driver_unregister(&davinci_gpio_driver);
}
module_exit(davinci_gpio_exit);
MODULE_AUTHOR("Jan Kotas <jank@cadence.com>");
MODULE_DESCRIPTION("DAVINCI GPIO driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:gpio-davinci");
......@@ -141,6 +141,7 @@ static const struct regmap_config exar_regmap_config = {
.name = "exar-gpio",
.reg_bits = 16,
.val_bits = 8,
.io_port = true,
};
static int gpio_exar_probe(struct platform_device *pdev)
......
......@@ -277,7 +277,7 @@ static int ftgpio_gpio_probe(struct platform_device *pdev)
dev_err(dev, "unable to init generic GPIO\n");
goto dis_clk;
}
g->gc.label = "FTGPIO010";
g->gc.label = dev_name(dev);
g->gc.base = -1;
g->gc.parent = dev;
g->gc.owner = THIS_MODULE;
......
......@@ -67,8 +67,7 @@ static void gw_pld_set8(struct gpio_chip *gc, unsigned offset, int value)
gw_pld_output8(gc, offset, value);
}
static int gw_pld_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static int gw_pld_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct gw_pld *gw;
......@@ -126,7 +125,7 @@ static struct i2c_driver gw_pld_driver = {
.name = "gw_pld",
.of_match_table = gw_pld_dt_ids,
},
.probe = gw_pld_probe,
.probe_new = gw_pld_probe,
.id_table = gw_pld_id,
};
module_i2c_driver(gw_pld_driver);
......
......@@ -221,6 +221,12 @@ static const struct acpi_device_id hisi_gpio_acpi_match[] = {
};
MODULE_DEVICE_TABLE(acpi, hisi_gpio_acpi_match);
static const struct of_device_id hisi_gpio_dts_match[] = {
{ .compatible = "hisilicon,ascend910-gpio", },
{ }
};
MODULE_DEVICE_TABLE(of, hisi_gpio_dts_match);
static void hisi_gpio_get_pdata(struct device *dev,
struct hisi_gpio *hisi_gpio)
{
......@@ -311,6 +317,7 @@ static struct platform_driver hisi_gpio_driver = {
.driver = {
.name = HISI_GPIO_DRIVER_NAME,
.acpi_match_table = hisi_gpio_acpi_match,
.of_match_table = hisi_gpio_dts_match,
},
.probe = hisi_gpio_probe,
};
......
// SPDX-License-Identifier: GPL-2.0
/*
* GPIO library for the ACCES IDIO-16 family
* Copyright (C) 2022 William Breathitt Gray
*/
#include <linux/bitmap.h>
#include <linux/export.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include "gpio-idio-16.h"
#define DEFAULT_SYMBOL_NAMESPACE GPIO_IDIO_16
/**
* idio_16_get - get signal value at signal offset
* @reg: ACCES IDIO-16 device registers
* @state: ACCES IDIO-16 device state
* @offset: offset of signal to get
*
* Returns the signal value (0=low, 1=high) for the signal at @offset.
*/
int idio_16_get(struct idio_16 __iomem *const reg,
struct idio_16_state *const state, const unsigned long offset)
{
const unsigned long mask = BIT(offset);
if (offset < IDIO_16_NOUT)
return test_bit(offset, state->out_state);
if (offset < 24)
return !!(ioread8(&reg->in0_7) & (mask >> IDIO_16_NOUT));
if (offset < 32)
return !!(ioread8(&reg->in8_15) & (mask >> 24));
return -EINVAL;
}
EXPORT_SYMBOL_GPL(idio_16_get);
/**
* idio_16_get_multiple - get multiple signal values at multiple signal offsets
* @reg: ACCES IDIO-16 device registers
* @state: ACCES IDIO-16 device state
* @mask: mask of signals to get
* @bits: bitmap to store signal values
*
* Stores in @bits the values (0=low, 1=high) for the signals defined by @mask.
*/
void idio_16_get_multiple(struct idio_16 __iomem *const reg,
struct idio_16_state *const state,
const unsigned long *const mask,
unsigned long *const bits)
{
unsigned long flags;
const unsigned long out_mask = GENMASK(IDIO_16_NOUT - 1, 0);
spin_lock_irqsave(&state->lock, flags);
bitmap_replace(bits, bits, state->out_state, &out_mask, IDIO_16_NOUT);
if (*mask & GENMASK(23, 16))
bitmap_set_value8(bits, ioread8(&reg->in0_7), 16);
if (*mask & GENMASK(31, 24))
bitmap_set_value8(bits, ioread8(&reg->in8_15), 24);
spin_unlock_irqrestore(&state->lock, flags);
}
EXPORT_SYMBOL_GPL(idio_16_get_multiple);
/**
* idio_16_set - set signal value at signal offset
* @reg: ACCES IDIO-16 device registers
* @state: ACCES IDIO-16 device state
* @offset: offset of signal to set
* @value: value of signal to set
*
* Assigns output @value for the signal at @offset.
*/
void idio_16_set(struct idio_16 __iomem *const reg,
struct idio_16_state *const state, const unsigned long offset,
const unsigned long value)
{
unsigned long flags;
if (offset >= IDIO_16_NOUT)
return;
spin_lock_irqsave(&state->lock, flags);
__assign_bit(offset, state->out_state, value);
if (offset < 8)
iowrite8(bitmap_get_value8(state->out_state, 0), &reg->out0_7);
else
iowrite8(bitmap_get_value8(state->out_state, 8), &reg->out8_15);
spin_unlock_irqrestore(&state->lock, flags);
}
EXPORT_SYMBOL_GPL(idio_16_set);
/**
* idio_16_set_multiple - set signal values at multiple signal offsets
* @reg: ACCES IDIO-16 device registers
* @state: ACCES IDIO-16 device state
* @mask: mask of signals to set
* @bits: bitmap of signal output values
*
* Assigns output values defined by @bits for the signals defined by @mask.
*/
void idio_16_set_multiple(struct idio_16 __iomem *const reg,
struct idio_16_state *const state,
const unsigned long *const mask,
const unsigned long *const bits)
{
unsigned long flags;
spin_lock_irqsave(&state->lock, flags);
bitmap_replace(state->out_state, state->out_state, bits, mask,
IDIO_16_NOUT);
if (*mask & GENMASK(7, 0))
iowrite8(bitmap_get_value8(state->out_state, 0), &reg->out0_7);
if (*mask & GENMASK(15, 8))
iowrite8(bitmap_get_value8(state->out_state, 8), &reg->out8_15);
spin_unlock_irqrestore(&state->lock, flags);
}
EXPORT_SYMBOL_GPL(idio_16_set_multiple);
/**
* idio_16_state_init - initialize idio_16_state structure
* @state: ACCES IDIO-16 device state
*
* Initializes the ACCES IDIO-16 device @state for use in idio-16 library
* functions.
*/
void idio_16_state_init(struct idio_16_state *const state)
{
spin_lock_init(&state->lock);
}
EXPORT_SYMBOL_GPL(idio_16_state_init);
MODULE_AUTHOR("William Breathitt Gray");
MODULE_DESCRIPTION("ACCES IDIO-16 GPIO Library");
MODULE_LICENSE("GPL");
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright 2022 William Breathitt Gray */
#ifndef _IDIO_16_H_
#define _IDIO_16_H_
#include <linux/spinlock.h>
#include <linux/types.h>
/**
* struct idio_16 - IDIO-16 registers structure
* @out0_7: Read: FET Drive Outputs 0-7
* Write: FET Drive Outputs 0-7
* @in0_7: Read: Isolated Inputs 0-7
* Write: Clear Interrupt
* @irq_ctl: Read: Enable IRQ
* Write: Disable IRQ
* @filter_ctl: Read: Activate Input Filters 0-15
* Write: Deactivate Input Filters 0-15
* @out8_15: Read: FET Drive Outputs 8-15
* Write: FET Drive Outputs 8-15
* @in8_15: Read: Isolated Inputs 8-15
* Write: Unused
* @irq_status: Read: Interrupt status
* Write: Unused
*/
struct idio_16 {
u8 out0_7;
u8 in0_7;
u8 irq_ctl;
u8 filter_ctl;
u8 out8_15;
u8 in8_15;
u8 irq_status;
};
#define IDIO_16_NOUT 16
/**
* struct idio_16_state - IDIO-16 state structure
* @lock: synchronization lock for accessing device state
* @out_state: output signals state
*/
struct idio_16_state {
spinlock_t lock;
DECLARE_BITMAP(out_state, IDIO_16_NOUT);
};
/**
* idio_16_get_direction - get the I/O direction for a signal offset
* @offset: offset of signal to get direction
*
* Returns the signal direction (0=output, 1=input) for the signal at @offset.
*/
static inline int idio_16_get_direction(const unsigned long offset)
{
return (offset >= IDIO_16_NOUT) ? 1 : 0;
}
int idio_16_get(struct idio_16 __iomem *reg, struct idio_16_state *state,
unsigned long offset);
void idio_16_get_multiple(struct idio_16 __iomem *reg,
struct idio_16_state *state,
const unsigned long *mask, unsigned long *bits);
void idio_16_set(struct idio_16 __iomem *reg, struct idio_16_state *state,
unsigned long offset, unsigned long value);
void idio_16_set_multiple(struct idio_16 __iomem *reg,
struct idio_16_state *state,
const unsigned long *mask, const unsigned long *bits);
void idio_16_state_init(struct idio_16_state *state);
#endif /* _IDIO_16_H_ */
// SPDX-License-Identifier: GPL-2.0
/*
* GPIO latch driver
*
* Copyright (C) 2022 Sascha Hauer <s.hauer@pengutronix.de>
*
* This driver implements a GPIO (or better GPO as there is no input)
* multiplexer based on latches like this:
*
* CLK0 ----------------------. ,--------.
* CLK1 -------------------. `--------|> #0 |
* | | |
* OUT0 ----------------+--|-----------|D0 Q0|-----|<
* OUT1 --------------+-|--|-----------|D1 Q1|-----|<
* OUT2 ------------+-|-|--|-----------|D2 Q2|-----|<
* OUT3 ----------+-|-|-|--|-----------|D3 Q3|-----|<
* OUT4 --------+-|-|-|-|--|-----------|D4 Q4|-----|<
* OUT5 ------+-|-|-|-|-|--|-----------|D5 Q5|-----|<
* OUT6 ----+-|-|-|-|-|-|--|-----------|D6 Q6|-----|<
* OUT7 --+-|-|-|-|-|-|-|--|-----------|D7 Q7|-----|<
* | | | | | | | | | `--------'
* | | | | | | | | |
* | | | | | | | | | ,--------.
* | | | | | | | | `-----------|> #1 |
* | | | | | | | | | |
* | | | | | | | `--------------|D0 Q0|-----|<
* | | | | | | `----------------|D1 Q1|-----|<
* | | | | | `------------------|D2 Q2|-----|<
* | | | | `--------------------|D3 Q3|-----|<
* | | | `----------------------|D4 Q4|-----|<
* | | `------------------------|D5 Q5|-----|<
* | `--------------------------|D6 Q6|-----|<
* `----------------------------|D7 Q7|-----|<
* `--------'
*
* The above is just an example. The actual number of number of latches and
* the number of inputs per latch is derived from the number of GPIOs given
* in the corresponding device tree properties.
*/
#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include "gpiolib.h"
struct gpio_latch_priv {
struct gpio_chip gc;
struct gpio_descs *clk_gpios;
struct gpio_descs *latched_gpios;
int n_latched_gpios;
unsigned int setup_duration_ns;
unsigned int clock_duration_ns;
unsigned long *shadow;
/*
* Depending on whether any of the underlying GPIOs may sleep we either
* use a mutex or a spinlock to protect our shadow map.
*/
union {
struct mutex mutex; /* protects @shadow */
spinlock_t spinlock; /* protects @shadow */
};
};
static int gpio_latch_get_direction(struct gpio_chip *gc, unsigned int offset)
{
return GPIO_LINE_DIRECTION_OUT;
}
static void gpio_latch_set_unlocked(struct gpio_latch_priv *priv,
void (*set)(struct gpio_desc *desc, int value),
unsigned int offset, bool val)
{
int latch = offset / priv->n_latched_gpios;
int i;
assign_bit(offset, priv->shadow, val);
for (i = 0; i < priv->n_latched_gpios; i++)
set(priv->latched_gpios->desc[i],
test_bit(latch * priv->n_latched_gpios + i, priv->shadow));
ndelay(priv->setup_duration_ns);
set(priv->clk_gpios->desc[latch], 1);
ndelay(priv->clock_duration_ns);
set(priv->clk_gpios->desc[latch], 0);
}
static void gpio_latch_set(struct gpio_chip *gc, unsigned int offset, int val)
{
struct gpio_latch_priv *priv = gpiochip_get_data(gc);
unsigned long flags;
spin_lock_irqsave(&priv->spinlock, flags);
gpio_latch_set_unlocked(priv, gpiod_set_value, offset, val);
spin_unlock_irqrestore(&priv->spinlock, flags);
}
static void gpio_latch_set_can_sleep(struct gpio_chip *gc, unsigned int offset, int val)
{
struct gpio_latch_priv *priv = gpiochip_get_data(gc);
mutex_lock(&priv->mutex);
gpio_latch_set_unlocked(priv, gpiod_set_value_cansleep, offset, val);
mutex_unlock(&priv->mutex);
}
static bool gpio_latch_can_sleep(struct gpio_latch_priv *priv, unsigned int n_latches)
{
int i;
for (i = 0; i < n_latches; i++)
if (gpiod_cansleep(priv->clk_gpios->desc[i]))
return true;
for (i = 0; i < priv->n_latched_gpios; i++)
if (gpiod_cansleep(priv->latched_gpios->desc[i]))
return true;
return false;
}
/*
* Some value which is still acceptable to delay in atomic context.
* If we need to go higher we might have to switch to usleep_range(),
* but that cannot ne used in atomic context and the driver would have
* to be adjusted to support that.
*/
#define DURATION_NS_MAX 5000
static int gpio_latch_probe(struct platform_device *pdev)
{
struct gpio_latch_priv *priv;
unsigned int n_latches;
struct device_node *np = pdev->dev.of_node;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->clk_gpios = devm_gpiod_get_array(&pdev->dev, "clk", GPIOD_OUT_LOW);
if (IS_ERR(priv->clk_gpios))
return PTR_ERR(priv->clk_gpios);
priv->latched_gpios = devm_gpiod_get_array(&pdev->dev, "latched", GPIOD_OUT_LOW);
if (IS_ERR(priv->latched_gpios))
return PTR_ERR(priv->latched_gpios);
n_latches = priv->clk_gpios->ndescs;
priv->n_latched_gpios = priv->latched_gpios->ndescs;
priv->shadow = devm_bitmap_zalloc(&pdev->dev, n_latches * priv->n_latched_gpios,
GFP_KERNEL);
if (!priv->shadow)
return -ENOMEM;
if (gpio_latch_can_sleep(priv, n_latches)) {
priv->gc.can_sleep = true;
priv->gc.set = gpio_latch_set_can_sleep;
mutex_init(&priv->mutex);
} else {
priv->gc.can_sleep = false;
priv->gc.set = gpio_latch_set;
spin_lock_init(&priv->spinlock);
}
of_property_read_u32(np, "setup-duration-ns", &priv->setup_duration_ns);
if (priv->setup_duration_ns > DURATION_NS_MAX) {
dev_warn(&pdev->dev, "setup-duration-ns too high, limit to %d\n",
DURATION_NS_MAX);
priv->setup_duration_ns = DURATION_NS_MAX;
}
of_property_read_u32(np, "clock-duration-ns", &priv->clock_duration_ns);
if (priv->clock_duration_ns > DURATION_NS_MAX) {
dev_warn(&pdev->dev, "clock-duration-ns too high, limit to %d\n",
DURATION_NS_MAX);
priv->clock_duration_ns = DURATION_NS_MAX;
}
priv->gc.get_direction = gpio_latch_get_direction;
priv->gc.ngpio = n_latches * priv->n_latched_gpios;
priv->gc.owner = THIS_MODULE;
priv->gc.base = -1;
priv->gc.parent = &pdev->dev;
platform_set_drvdata(pdev, priv);
return devm_gpiochip_add_data(&pdev->dev, &priv->gc, priv);
}
static const struct of_device_id gpio_latch_ids[] = {
{
.compatible = "gpio-latch",
},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, gpio_latch_ids);
static struct platform_driver gpio_latch_driver = {
.driver = {
.name = "gpio-latch",
.of_match_table = gpio_latch_ids,
},
.probe = gpio_latch_probe,
};
module_platform_driver(gpio_latch_driver);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
MODULE_DESCRIPTION("GPIO latch driver");
......@@ -28,8 +28,7 @@ static int max7300_i2c_read(struct device *dev, unsigned int reg)
return i2c_smbus_read_byte_data(client, reg);
}
static int max7300_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static int max7300_probe(struct i2c_client *client)
{
struct max7301 *ts;
......@@ -63,7 +62,7 @@ static struct i2c_driver max7300_driver = {
.driver = {
.name = "max7300",
},
.probe = max7300_probe,
.probe_new = max7300_probe,
.remove = max7300_remove,
.id_table = max7300_id,
};
......
......@@ -608,9 +608,9 @@ static struct max732x_platform_data *of_gpio_max732x(struct device *dev)
return pdata;
}
static int max732x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static int max732x_probe(struct i2c_client *client)
{
const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct max732x_platform_data *pdata;
struct device_node *node;
struct max732x_chip *chip;
......@@ -707,7 +707,7 @@ static struct i2c_driver max732x_driver = {
.name = "max732x",
.of_match_table = of_match_ptr(max732x_of_table),
},
.probe = max732x_probe,
.probe_new = max732x_probe,
.id_table = max732x_id,
};
......
......@@ -14,6 +14,7 @@
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/pinctrl/consumer.h>
#include <linux/string_helpers.h>
#define GCCR 0x000 /* controller configuration */
#define GPLR 0x004 /* pin level r/o */
......@@ -331,7 +332,7 @@ static int mrfld_irq_set_wake(struct irq_data *d, unsigned int on)
raw_spin_unlock_irqrestore(&priv->lock, flags);
dev_dbg(priv->dev, "%sable wake for gpio %u\n", on ? "en" : "dis", gpio);
dev_dbg(priv->dev, "%s wake for gpio %u\n", str_enable_disable(on), gpio);
return 0;
}
......
......@@ -1050,9 +1050,9 @@ static int device_pca957x_init(struct pca953x_chip *chip, u32 invert)
return ret;
}
static int pca953x_probe(struct i2c_client *client,
const struct i2c_device_id *i2c_id)
static int pca953x_probe(struct i2c_client *client)
{
const struct i2c_device_id *i2c_id = i2c_client_get_device_id(client);
struct pca953x_platform_data *pdata;
struct pca953x_chip *chip;
int irq_base = 0;
......@@ -1376,7 +1376,7 @@ static struct i2c_driver pca953x_driver = {
.of_match_table = pca953x_dt_ids,
.acpi_match_table = pca953x_acpi_ids,
},
.probe = pca953x_probe,
.probe_new = pca953x_probe,
.remove = pca953x_remove,
.id_table = pca953x_id,
};
......
......@@ -15,14 +15,28 @@
#include <linux/mutex.h>
#include <linux/property.h>
#define SLG7XL45106_GPO_REG 0xDB
/**
* struct pca9570_platform_data - GPIO platformdata
* @ngpio: no of gpios
* @command: Command to be sent
*/
struct pca9570_platform_data {
u16 ngpio;
u32 command;
};
/**
* struct pca9570 - GPIO driver data
* @chip: GPIO controller chip
* @p_data: GPIO controller platform data
* @lock: Protects write sequences
* @out: Buffer for device register
*/
struct pca9570 {
struct gpio_chip chip;
const struct pca9570_platform_data *p_data;
struct mutex lock;
u8 out;
};
......@@ -32,7 +46,11 @@ 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 (gpio->p_data->command != 0)
ret = i2c_smbus_read_byte_data(client, gpio->p_data->command);
else
ret = i2c_smbus_read_byte(client);
if (ret < 0)
return ret;
......@@ -44,6 +62,9 @@ static int pca9570_write(struct pca9570 *gpio, u8 value)
{
struct i2c_client *client = to_i2c_client(gpio->chip.parent);
if (gpio->p_data->command != 0)
return i2c_smbus_write_byte_data(client, gpio->p_data->command, value);
return i2c_smbus_write_byte(client, value);
}
......@@ -106,7 +127,8 @@ static int pca9570_probe(struct i2c_client *client)
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->p_data = device_get_match_data(&client->dev);
gpio->chip.ngpio = gpio->p_data->ngpio;
gpio->chip.can_sleep = true;
mutex_init(&gpio->lock);
......@@ -119,16 +141,31 @@ static int pca9570_probe(struct i2c_client *client)
return devm_gpiochip_add_data(&client->dev, &gpio->chip, gpio);
}
static const struct pca9570_platform_data pca9570_gpio = {
.ngpio = 4,
};
static const struct pca9570_platform_data pca9571_gpio = {
.ngpio = 8,
};
static const struct pca9570_platform_data slg7xl45106_gpio = {
.ngpio = 8,
.command = SLG7XL45106_GPO_REG,
};
static const struct i2c_device_id pca9570_id_table[] = {
{ "pca9570", 4 },
{ "pca9571", 8 },
{ "pca9570", (kernel_ulong_t)&pca9570_gpio},
{ "pca9571", (kernel_ulong_t)&pca9571_gpio },
{ "slg7xl45106", (kernel_ulong_t)&slg7xl45106_gpio },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, pca9570_id_table);
static const struct of_device_id pca9570_of_match_table[] = {
{ .compatible = "nxp,pca9570", .data = (void *)4 },
{ .compatible = "nxp,pca9571", .data = (void *)8 },
{ .compatible = "dlg,slg7xl45106", .data = &slg7xl45106_gpio},
{ .compatible = "nxp,pca9570", .data = &pca9570_gpio },
{ .compatible = "nxp,pca9571", .data = &pca9571_gpio },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, pca9570_of_match_table);
......
......@@ -247,9 +247,9 @@ static const struct irq_chip pcf857x_irq_chip = {
/*-------------------------------------------------------------------------*/
static int pcf857x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static int pcf857x_probe(struct i2c_client *client)
{
const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct pcf857x_platform_data *pdata = dev_get_platdata(&client->dev);
struct device_node *np = client->dev.of_node;
struct pcf857x *gpio;
......@@ -422,7 +422,7 @@ static struct i2c_driver pcf857x_driver = {
.name = "pcf857x",
.of_match_table = of_match_ptr(pcf857x_of_table),
},
.probe = pcf857x_probe,
.probe_new = pcf857x_probe,
.remove = pcf857x_remove,
.shutdown = pcf857x_shutdown,
.id_table = pcf857x_id,
......
......@@ -3,8 +3,7 @@
* GPIO driver for the ACCES PCI-IDIO-16
* Copyright (C) 2017 William Breathitt Gray
*/
#include <linux/bitmap.h>
#include <linux/bitops.h>
#include <linux/bits.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/gpio/driver.h>
......@@ -16,51 +15,28 @@
#include <linux/spinlock.h>
#include <linux/types.h>
/**
* struct idio_16_gpio_reg - GPIO device registers structure
* @out0_7: Read: FET Drive Outputs 0-7
* Write: FET Drive Outputs 0-7
* @in0_7: Read: Isolated Inputs 0-7
* Write: Clear Interrupt
* @irq_ctl: Read: Enable IRQ
* Write: Disable IRQ
* @filter_ctl: Read: Activate Input Filters 0-15
* Write: Deactivate Input Filters 0-15
* @out8_15: Read: FET Drive Outputs 8-15
* Write: FET Drive Outputs 8-15
* @in8_15: Read: Isolated Inputs 8-15
* Write: Unused
* @irq_status: Read: Interrupt status
* Write: Unused
*/
struct idio_16_gpio_reg {
u8 out0_7;
u8 in0_7;
u8 irq_ctl;
u8 filter_ctl;
u8 out8_15;
u8 in8_15;
u8 irq_status;
};
#include "gpio-idio-16.h"
/**
* struct idio_16_gpio - GPIO device private data structure
* @chip: instance of the gpio_chip
* @lock: synchronization lock to prevent I/O race conditions
* @reg: I/O address offset for the GPIO device registers
* @state: ACCES IDIO-16 device state
* @irq_mask: I/O bits affected by interrupts
*/
struct idio_16_gpio {
struct gpio_chip chip;
raw_spinlock_t lock;
struct idio_16_gpio_reg __iomem *reg;
struct idio_16 __iomem *reg;
struct idio_16_state state;
unsigned long irq_mask;
};
static int idio_16_gpio_get_direction(struct gpio_chip *chip,
unsigned int offset)
{
if (offset > 15)
if (idio_16_get_direction(offset))
return GPIO_LINE_DIRECTION_IN;
return GPIO_LINE_DIRECTION_OUT;
......@@ -82,43 +58,16 @@ static int idio_16_gpio_direction_output(struct gpio_chip *chip,
static int idio_16_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
unsigned long mask = BIT(offset);
if (offset < 8)
return !!(ioread8(&idio16gpio->reg->out0_7) & mask);
if (offset < 16)
return !!(ioread8(&idio16gpio->reg->out8_15) & (mask >> 8));
if (offset < 24)
return !!(ioread8(&idio16gpio->reg->in0_7) & (mask >> 16));
return !!(ioread8(&idio16gpio->reg->in8_15) & (mask >> 24));
return idio_16_get(idio16gpio->reg, &idio16gpio->state, offset);
}
static int idio_16_gpio_get_multiple(struct gpio_chip *chip,
unsigned long *mask, unsigned long *bits)
{
struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
unsigned long offset;
unsigned long gpio_mask;
void __iomem *ports[] = {
&idio16gpio->reg->out0_7, &idio16gpio->reg->out8_15,
&idio16gpio->reg->in0_7, &idio16gpio->reg->in8_15,
};
void __iomem *port_addr;
unsigned long port_state;
/* clear bits array to a clean slate */
bitmap_zero(bits, chip->ngpio);
for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) {
port_addr = ports[offset / 8];
port_state = ioread8(port_addr) & gpio_mask;
bitmap_set_value8(bits, port_state, offset);
}
idio_16_get_multiple(idio16gpio->reg, &idio16gpio->state, mask, bits);
return 0;
}
......@@ -126,61 +75,16 @@ static void idio_16_gpio_set(struct gpio_chip *chip, unsigned int offset,
int value)
{
struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
unsigned int mask = BIT(offset);
void __iomem *base;
unsigned long flags;
unsigned int out_state;
if (offset > 15)
return;
if (offset > 7) {
mask >>= 8;
base = &idio16gpio->reg->out8_15;
} else
base = &idio16gpio->reg->out0_7;
raw_spin_lock_irqsave(&idio16gpio->lock, flags);
if (value)
out_state = ioread8(base) | mask;
else
out_state = ioread8(base) & ~mask;
iowrite8(out_state, base);
raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
idio_16_set(idio16gpio->reg, &idio16gpio->state, offset, value);
}
static void idio_16_gpio_set_multiple(struct gpio_chip *chip,
unsigned long *mask, unsigned long *bits)
{
struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
unsigned long offset;
unsigned long gpio_mask;
void __iomem *ports[] = {
&idio16gpio->reg->out0_7, &idio16gpio->reg->out8_15,
};
size_t index;
void __iomem *port_addr;
unsigned long bitmask;
unsigned long flags;
unsigned long out_state;
for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) {
index = offset / 8;
port_addr = ports[index];
bitmask = bitmap_get_value8(bits, offset) & gpio_mask;
raw_spin_lock_irqsave(&idio16gpio->lock, flags);
out_state = ioread8(port_addr) & ~gpio_mask;
out_state |= bitmask;
iowrite8(out_state, port_addr);
raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
}
idio_16_set_multiple(idio16gpio->reg, &idio16gpio->state, mask, bits);
}
static void idio_16_irq_ack(struct irq_data *data)
......@@ -335,6 +239,8 @@ 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_multiple = idio_16_gpio_set_multiple;
idio_16_state_init(&idio16gpio->state);
girq = &idio16gpio->chip.irq;
girq->chip = &idio_16_irqchip;
/* This will let us handle the parent IRQ in the driver */
......@@ -379,3 +285,4 @@ module_pci_driver(idio_16_driver);
MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
MODULE_DESCRIPTION("ACCES PCI-IDIO-16 GPIO driver");
MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS(GPIO_IDIO_16);
......@@ -31,6 +31,7 @@
#include "gpiolib.h"
#define GPIO_SIM_NGPIO_MAX 1024
#define GPIO_SIM_PROP_MAX 4 /* Max 3 properties + sentinel. */
#define GPIO_SIM_NUM_ATTRS 3 /* value, pull and sentinel */
......@@ -371,6 +372,9 @@ static int gpio_sim_add_bank(struct fwnode_handle *swnode, struct device *dev)
if (ret)
return ret;
if (num_lines > GPIO_SIM_NGPIO_MAX)
return -ERANGE;
ret = fwnode_property_read_string(swnode, "gpio-sim,label", &label);
if (ret) {
label = devm_kasprintf(dev, GFP_KERNEL, "%s-%s",
......
......@@ -70,8 +70,7 @@ static int sl28cpld_gpio_irq_init(struct platform_device *pdev,
irq_chip->num_irqs = ARRAY_SIZE(sl28cpld_gpio_irqs);
irq_chip->num_regs = 1;
irq_chip->status_base = base + GPIO_REG_IP;
irq_chip->mask_base = base + GPIO_REG_IE;
irq_chip->mask_invert = true;
irq_chip->unmask_base = base + GPIO_REG_IE;
irq_chip->ack_base = base + GPIO_REG_IP;
ret = devm_regmap_add_irq_chip_fwnode(dev, dev_fwnode(dev),
......
// SPDX-License-Identifier: GPL-2.0-only
/*
* STMicroelectronics ConneXt (STA2X11) GPIO driver
*
* Copyright 2012 ST Microelectronics (Alessandro Rubini)
* Based on gpio-ml-ioh.c, Copyright 2010 OKI Semiconductors Ltd.
* Also based on previous sta2x11 work, Copyright 2011 Wind River Systems, Inc.
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/gpio/driver.h>
#include <linux/bitops.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/mfd/sta2x11-mfd.h>
struct gsta_regs {
u32 dat; /* 0x00 */
u32 dats;
u32 datc;
u32 pdis;
u32 dir; /* 0x10 */
u32 dirs;
u32 dirc;
u32 unused_1c;
u32 afsela; /* 0x20 */
u32 unused_24[7];
u32 rimsc; /* 0x40 */
u32 fimsc;
u32 is;
u32 ic;
};
struct gsta_gpio {
spinlock_t lock;
struct device *dev;
void __iomem *reg_base;
struct gsta_regs __iomem *regs[GSTA_NR_BLOCKS];
struct gpio_chip gpio;
int irq_base;
/* FIXME: save the whole config here (AF, ...) */
unsigned irq_type[GSTA_NR_GPIO];
};
/*
* gpio methods
*/
static void gsta_gpio_set(struct gpio_chip *gpio, unsigned nr, int val)
{
struct gsta_gpio *chip = gpiochip_get_data(gpio);
struct gsta_regs __iomem *regs = chip->regs[nr / GSTA_GPIO_PER_BLOCK];
u32 bit = BIT(nr % GSTA_GPIO_PER_BLOCK);
if (val)
writel(bit, &regs->dats);
else
writel(bit, &regs->datc);
}
static int gsta_gpio_get(struct gpio_chip *gpio, unsigned nr)
{
struct gsta_gpio *chip = gpiochip_get_data(gpio);
struct gsta_regs __iomem *regs = chip->regs[nr / GSTA_GPIO_PER_BLOCK];
u32 bit = BIT(nr % GSTA_GPIO_PER_BLOCK);
return !!(readl(&regs->dat) & bit);
}
static int gsta_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
int val)
{
struct gsta_gpio *chip = gpiochip_get_data(gpio);
struct gsta_regs __iomem *regs = chip->regs[nr / GSTA_GPIO_PER_BLOCK];
u32 bit = BIT(nr % GSTA_GPIO_PER_BLOCK);
writel(bit, &regs->dirs);
/* Data register after direction, otherwise pullup/down is selected */
if (val)
writel(bit, &regs->dats);
else
writel(bit, &regs->datc);
return 0;
}
static int gsta_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
{
struct gsta_gpio *chip = gpiochip_get_data(gpio);
struct gsta_regs __iomem *regs = chip->regs[nr / GSTA_GPIO_PER_BLOCK];
u32 bit = BIT(nr % GSTA_GPIO_PER_BLOCK);
writel(bit, &regs->dirc);
return 0;
}
static int gsta_gpio_to_irq(struct gpio_chip *gpio, unsigned offset)
{
struct gsta_gpio *chip = gpiochip_get_data(gpio);
return chip->irq_base + offset;
}
static void gsta_gpio_setup(struct gsta_gpio *chip) /* called from probe */
{
struct gpio_chip *gpio = &chip->gpio;
/*
* ARCH_NR_GPIOS is currently 256 and dynamic allocation starts
* from the end. However, for compatibility, we need the first
* ConneXt device to start from gpio 0: it's the main chipset
* on most boards so documents and drivers assume gpio0..gpio127
*/
static int gpio_base;
gpio->label = dev_name(chip->dev);
gpio->owner = THIS_MODULE;
gpio->direction_input = gsta_gpio_direction_input;
gpio->get = gsta_gpio_get;
gpio->direction_output = gsta_gpio_direction_output;
gpio->set = gsta_gpio_set;
gpio->dbg_show = NULL;
gpio->base = gpio_base;
gpio->ngpio = GSTA_NR_GPIO;
gpio->can_sleep = false;
gpio->to_irq = gsta_gpio_to_irq;
/*
* After the first device, turn to dynamic gpio numbers.
* For example, with ARCH_NR_GPIOS = 256 we can fit two cards
*/
if (!gpio_base)
gpio_base = -1;
}
/*
* Special method: alternate functions and pullup/pulldown. This is only
* invoked on startup to configure gpio's according to platform data.
* FIXME : this functionality shall be managed (and exported to other drivers)
* via the pin control subsystem.
*/
static void gsta_set_config(struct gsta_gpio *chip, int nr, unsigned cfg)
{
struct gsta_regs __iomem *regs = chip->regs[nr / GSTA_GPIO_PER_BLOCK];
unsigned long flags;
u32 bit = BIT(nr % GSTA_GPIO_PER_BLOCK);
u32 val;
int err = 0;
pr_info("%s: %p %i %i\n", __func__, chip, nr, cfg);
if (cfg == PINMUX_TYPE_NONE)
return;
/* Alternate function or not? */
spin_lock_irqsave(&chip->lock, flags);
val = readl(&regs->afsela);
if (cfg == PINMUX_TYPE_FUNCTION)
val |= bit;
else
val &= ~bit;
writel(val | bit, &regs->afsela);
if (cfg == PINMUX_TYPE_FUNCTION) {
spin_unlock_irqrestore(&chip->lock, flags);
return;
}
/* not alternate function: set details */
switch (cfg) {
case PINMUX_TYPE_OUTPUT_LOW:
writel(bit, &regs->dirs);
writel(bit, &regs->datc);
break;
case PINMUX_TYPE_OUTPUT_HIGH:
writel(bit, &regs->dirs);
writel(bit, &regs->dats);
break;
case PINMUX_TYPE_INPUT:
writel(bit, &regs->dirc);
val = readl(&regs->pdis) | bit;
writel(val, &regs->pdis);
break;
case PINMUX_TYPE_INPUT_PULLUP:
writel(bit, &regs->dirc);
val = readl(&regs->pdis) & ~bit;
writel(val, &regs->pdis);
writel(bit, &regs->dats);
break;
case PINMUX_TYPE_INPUT_PULLDOWN:
writel(bit, &regs->dirc);
val = readl(&regs->pdis) & ~bit;
writel(val, &regs->pdis);
writel(bit, &regs->datc);
break;
default:
err = 1;
}
spin_unlock_irqrestore(&chip->lock, flags);
if (err)
pr_err("%s: chip %p, pin %i, cfg %i is invalid\n",
__func__, chip, nr, cfg);
}
/*
* Irq methods
*/
static void gsta_irq_disable(struct irq_data *data)
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
struct gsta_gpio *chip = gc->private;
int nr = data->irq - chip->irq_base;
struct gsta_regs __iomem *regs = chip->regs[nr / GSTA_GPIO_PER_BLOCK];
u32 bit = BIT(nr % GSTA_GPIO_PER_BLOCK);
u32 val;
unsigned long flags;
spin_lock_irqsave(&chip->lock, flags);
if (chip->irq_type[nr] & IRQ_TYPE_EDGE_RISING) {
val = readl(&regs->rimsc) & ~bit;
writel(val, &regs->rimsc);
}
if (chip->irq_type[nr] & IRQ_TYPE_EDGE_FALLING) {
val = readl(&regs->fimsc) & ~bit;
writel(val, &regs->fimsc);
}
spin_unlock_irqrestore(&chip->lock, flags);
return;
}
static void gsta_irq_enable(struct irq_data *data)
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
struct gsta_gpio *chip = gc->private;
int nr = data->irq - chip->irq_base;
struct gsta_regs __iomem *regs = chip->regs[nr / GSTA_GPIO_PER_BLOCK];
u32 bit = BIT(nr % GSTA_GPIO_PER_BLOCK);
u32 val;
int type;
unsigned long flags;
type = chip->irq_type[nr];
spin_lock_irqsave(&chip->lock, flags);
val = readl(&regs->rimsc);
if (type & IRQ_TYPE_EDGE_RISING)
writel(val | bit, &regs->rimsc);
else
writel(val & ~bit, &regs->rimsc);
val = readl(&regs->rimsc);
if (type & IRQ_TYPE_EDGE_FALLING)
writel(val | bit, &regs->fimsc);
else
writel(val & ~bit, &regs->fimsc);
spin_unlock_irqrestore(&chip->lock, flags);
return;
}
static int gsta_irq_type(struct irq_data *d, unsigned int type)
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
struct gsta_gpio *chip = gc->private;
int nr = d->irq - chip->irq_base;
/* We only support edge interrupts */
if (!(type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))) {
pr_debug("%s: unsupported type 0x%x\n", __func__, type);
return -EINVAL;
}
chip->irq_type[nr] = type; /* used for enable/disable */
gsta_irq_enable(d);
return 0;
}
static irqreturn_t gsta_gpio_handler(int irq, void *dev_id)
{
struct gsta_gpio *chip = dev_id;
struct gsta_regs __iomem *regs;
u32 is;
int i, nr, base;
irqreturn_t ret = IRQ_NONE;
for (i = 0; i < GSTA_NR_BLOCKS; i++) {
regs = chip->regs[i];
base = chip->irq_base + i * GSTA_GPIO_PER_BLOCK;
while ((is = readl(&regs->is))) {
nr = __ffs(is);
irq = base + nr;
generic_handle_irq(irq);
writel(1 << nr, &regs->ic);
ret = IRQ_HANDLED;
}
}
return ret;
}
static int gsta_alloc_irq_chip(struct gsta_gpio *chip)
{
struct irq_chip_generic *gc;
struct irq_chip_type *ct;
int rv;
gc = devm_irq_alloc_generic_chip(chip->dev, KBUILD_MODNAME, 1,
chip->irq_base,
chip->reg_base, handle_simple_irq);
if (!gc)
return -ENOMEM;
gc->private = chip;
ct = gc->chip_types;
ct->chip.irq_set_type = gsta_irq_type;
ct->chip.irq_disable = gsta_irq_disable;
ct->chip.irq_enable = gsta_irq_enable;
/* FIXME: this makes at most 32 interrupts. Request 0 by now */
rv = devm_irq_setup_generic_chip(chip->dev, gc,
0 /* IRQ_MSK(GSTA_GPIO_PER_BLOCK) */,
0, IRQ_NOREQUEST | IRQ_NOPROBE, 0);
if (rv)
return rv;
/* Set up all 128 interrupts: code from setup_generic_chip */
{
struct irq_chip_type *ct = gc->chip_types;
int i, j;
for (j = 0; j < GSTA_NR_GPIO; j++) {
i = chip->irq_base + j;
irq_set_chip_and_handler(i, &ct->chip, ct->handler);
irq_set_chip_data(i, gc);
irq_clear_status_flags(i, IRQ_NOREQUEST | IRQ_NOPROBE);
}
gc->irq_cnt = i - gc->irq_base;
}
return 0;
}
/* The platform device used here is instantiated by the MFD device */
static int gsta_probe(struct platform_device *dev)
{
int i, err;
struct pci_dev *pdev;
struct sta2x11_gpio_pdata *gpio_pdata;
struct gsta_gpio *chip;
pdev = *(struct pci_dev **)dev_get_platdata(&dev->dev);
gpio_pdata = dev_get_platdata(&pdev->dev);
if (gpio_pdata == NULL)
dev_err(&dev->dev, "no gpio config\n");
pr_debug("gpio config: %p\n", gpio_pdata);
chip = devm_kzalloc(&dev->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
chip->dev = &dev->dev;
chip->reg_base = devm_platform_ioremap_resource(dev, 0);
if (IS_ERR(chip->reg_base))
return PTR_ERR(chip->reg_base);
for (i = 0; i < GSTA_NR_BLOCKS; i++) {
chip->regs[i] = chip->reg_base + i * 4096;
/* disable all irqs */
writel(0, &chip->regs[i]->rimsc);
writel(0, &chip->regs[i]->fimsc);
writel(~0, &chip->regs[i]->ic);
}
spin_lock_init(&chip->lock);
gsta_gpio_setup(chip);
if (gpio_pdata)
for (i = 0; i < GSTA_NR_GPIO; i++)
gsta_set_config(chip, i, gpio_pdata->pinconfig[i]);
/* 384 was used in previous code: be compatible for other drivers */
err = devm_irq_alloc_descs(&dev->dev, -1, 384,
GSTA_NR_GPIO, NUMA_NO_NODE);
if (err < 0) {
dev_warn(&dev->dev, "sta2x11 gpio: Can't get irq base (%i)\n",
-err);
return err;
}
chip->irq_base = err;
err = gsta_alloc_irq_chip(chip);
if (err)
return err;
err = devm_request_irq(&dev->dev, pdev->irq, gsta_gpio_handler,
IRQF_SHARED, KBUILD_MODNAME, chip);
if (err < 0) {
dev_err(&dev->dev, "sta2x11 gpio: Can't request irq (%i)\n",
-err);
return err;
}
return devm_gpiochip_add_data(&dev->dev, &chip->gpio, chip);
}
static struct platform_driver sta2x11_gpio_platform_driver = {
.driver = {
.name = "sta2x11-gpio",
.suppress_bind_attrs = true,
},
.probe = gsta_probe,
};
builtin_platform_driver(sta2x11_gpio_platform_driver);
......@@ -98,8 +98,7 @@ static const struct of_device_id tpic2810_of_match_table[] = {
};
MODULE_DEVICE_TABLE(of, tpic2810_of_match_table);
static int tpic2810_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static int tpic2810_probe(struct i2c_client *client)
{
struct tpic2810 *gpio;
int ret;
......@@ -144,7 +143,7 @@ static struct i2c_driver tpic2810_driver = {
.name = "tpic2810",
.of_match_table = tpic2810_of_match_table,
},
.probe = tpic2810_probe,
.probe_new = tpic2810_probe,
.remove = tpic2810_remove,
.id_table = tpic2810_id_table,
};
......
......@@ -136,8 +136,7 @@ static const struct of_device_id ts4900_gpio_of_match_table[] = {
};
MODULE_DEVICE_TABLE(of, ts4900_gpio_of_match_table);
static int ts4900_gpio_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static int ts4900_gpio_probe(struct i2c_client *client)
{
struct ts4900_gpio_priv *priv;
u32 ngpio;
......@@ -186,7 +185,7 @@ static struct i2c_driver ts4900_gpio_driver = {
.name = "ts4900-gpio",
.of_match_table = ts4900_gpio_of_match_table,
},
.probe = ts4900_gpio_probe,
.probe_new = ts4900_gpio_probe,
.id_table = ts4900_gpio_id_table,
};
module_i2c_driver(ts4900_gpio_driver);
......
......@@ -89,6 +89,30 @@ struct acpi_gpio_chip {
struct list_head deferred_req_irqs_list_entry;
};
/**
* struct acpi_gpio_info - ACPI GPIO specific information
* @adev: reference to ACPI device which consumes GPIO resource
* @flags: GPIO initialization flags
* @gpioint: if %true this GPIO is of type GpioInt otherwise type is GpioIo
* @pin_config: pin bias as provided by ACPI
* @polarity: interrupt polarity as provided by ACPI
* @triggering: triggering type as provided by ACPI
* @wake_capable: wake capability as provided by ACPI
* @debounce: debounce timeout as provided by ACPI
* @quirks: Linux specific quirks as provided by struct acpi_gpio_mapping
*/
struct acpi_gpio_info {
struct acpi_device *adev;
enum gpiod_flags flags;
bool gpioint;
int pin_config;
int polarity;
int triggering;
bool wake_capable;
unsigned int debounce;
unsigned int quirks;
};
/*
* For GPIO chips which call acpi_gpiochip_request_interrupts() before late_init
* (so builtin drivers) we register the ACPI GpioInt IRQ handlers from a
......@@ -512,7 +536,7 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)
if (ACPI_FAILURE(status))
return;
acpi_walk_resources(handle, "_AEI",
acpi_walk_resources(handle, METHOD_NAME__AEI,
acpi_gpiochip_alloc_event, acpi_gpio);
mutex_lock(&acpi_gpio_deferred_req_irqs_lock);
......@@ -670,8 +694,8 @@ __acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, enum gpiod_flags update)
return ret;
}
int
acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, struct acpi_gpio_info *info)
static int acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags,
struct acpi_gpio_info *info)
{
struct device *dev = &info->adev->dev;
enum gpiod_flags old = *flags;
......@@ -690,8 +714,8 @@ acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, struct acpi_gpio_info *inf
return ret;
}
int acpi_gpio_update_gpiod_lookup_flags(unsigned long *lookupflags,
struct acpi_gpio_info *info)
static int acpi_gpio_update_gpiod_lookup_flags(unsigned long *lookupflags,
struct acpi_gpio_info *info)
{
switch (info->pin_config) {
case ACPI_PIN_CONFIG_PULLUP:
......@@ -864,8 +888,9 @@ static int acpi_gpio_property_lookup(struct fwnode_handle *fwnode,
* function only returns the first.
*/
static struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
const char *propname, int index,
struct acpi_gpio_info *info)
const char *propname,
int index,
struct acpi_gpio_info *info)
{
struct acpi_gpio_lookup lookup;
int ret;
......@@ -896,6 +921,44 @@ static struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
return ret ? ERR_PTR(ret) : lookup.desc;
}
/**
* acpi_get_gpiod_from_data() - get a GPIO descriptor from ACPI data node
* @fwnode: pointer to an ACPI firmware node to get the GPIO information from
* @propname: Property name of the GPIO
* @index: index of GpioIo/GpioInt resource (starting from %0)
* @info: info pointer to fill in (optional)
*
* This function uses the property-based GPIO lookup to get to the GPIO
* resource with the relevant information from a data-only ACPI firmware node
* and uses that to obtain the GPIO descriptor to return.
*
* If the GPIO cannot be translated or there is an error an ERR_PTR is
* returned.
*/
static struct gpio_desc *acpi_get_gpiod_from_data(struct fwnode_handle *fwnode,
const char *propname,
int index,
struct acpi_gpio_info *info)
{
struct acpi_gpio_lookup lookup;
int ret;
if (!is_acpi_data_node(fwnode))
return ERR_PTR(-ENODEV);
if (!propname)
return ERR_PTR(-EINVAL);
lookup.index = index;
ret = acpi_gpio_property_lookup(fwnode, propname, index, &lookup);
if (ret)
return ERR_PTR(ret);
ret = acpi_gpio_resource_lookup(&lookup, info);
return ret ? ERR_PTR(ret) : lookup.desc;
}
static bool acpi_can_fallback_to_crs(struct acpi_device *adev,
const char *con_id)
{
......@@ -906,13 +969,13 @@ static bool acpi_can_fallback_to_crs(struct acpi_device *adev,
return con_id == NULL;
}
struct gpio_desc *acpi_find_gpio(struct device *dev,
struct gpio_desc *acpi_find_gpio(struct fwnode_handle *fwnode,
const char *con_id,
unsigned int idx,
enum gpiod_flags *dflags,
unsigned long *lookupflags)
{
struct acpi_device *adev = ACPI_COMPANION(dev);
struct acpi_device *adev = to_acpi_device_node(fwnode);
struct acpi_gpio_info info;
struct gpio_desc *desc;
char propname[32];
......@@ -928,7 +991,12 @@ struct gpio_desc *acpi_find_gpio(struct device *dev,
gpio_suffixes[i]);
}
desc = acpi_get_gpiod_by_index(adev, propname, idx, &info);
if (adev)
desc = acpi_get_gpiod_by_index(adev,
propname, idx, &info);
else
desc = acpi_get_gpiod_from_data(fwnode,
propname, idx, &info);
if (!IS_ERR(desc))
break;
if (PTR_ERR(desc) == -EPROBE_DEFER)
......@@ -937,7 +1005,7 @@ struct gpio_desc *acpi_find_gpio(struct device *dev,
/* Then from plain _CRS GPIOs */
if (IS_ERR(desc)) {
if (!acpi_can_fallback_to_crs(adev, con_id))
if (!adev || !acpi_can_fallback_to_crs(adev, con_id))
return ERR_PTR(-ENOENT);
desc = acpi_get_gpiod_by_index(adev, NULL, idx, &info);
......@@ -956,50 +1024,6 @@ struct gpio_desc *acpi_find_gpio(struct device *dev,
return desc;
}
/**
* acpi_node_get_gpiod() - get a GPIO descriptor from ACPI resources
* @fwnode: pointer to an ACPI firmware node to get the GPIO information from
* @propname: Property name of the GPIO
* @index: index of GpioIo/GpioInt resource (starting from %0)
* @info: info pointer to fill in (optional)
*
* If @fwnode is an ACPI device object, call acpi_get_gpiod_by_index() for it.
* Otherwise (i.e. it is a data-only non-device object), use the property-based
* GPIO lookup to get to the GPIO resource with the relevant information and use
* that to obtain the GPIO descriptor to return.
*
* If the GPIO cannot be translated or there is an error an ERR_PTR is
* returned.
*/
struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode,
const char *propname, int index,
struct acpi_gpio_info *info)
{
struct acpi_gpio_lookup lookup;
struct acpi_device *adev;
int ret;
adev = to_acpi_device_node(fwnode);
if (adev)
return acpi_get_gpiod_by_index(adev, propname, index, info);
if (!is_acpi_data_node(fwnode))
return ERR_PTR(-ENODEV);
if (!propname)
return ERR_PTR(-EINVAL);
memset(&lookup, 0, sizeof(lookup));
lookup.index = index;
ret = acpi_gpio_property_lookup(fwnode, propname, index, &lookup);
if (ret)
return ERR_PTR(ret);
ret = acpi_gpio_resource_lookup(&lookup, info);
return ret ? ERR_PTR(ret) : lookup.desc;
}
/**
* acpi_dev_gpio_irq_wake_get_by() - Find GpioInt and translate it to Linux IRQ number
* @adev: pointer to a ACPI device to get IRQ from
......
......@@ -22,30 +22,6 @@ struct gpio_chip;
struct gpio_desc;
struct gpio_device;
/**
* struct acpi_gpio_info - ACPI GPIO specific information
* @adev: reference to ACPI device which consumes GPIO resource
* @flags: GPIO initialization flags
* @gpioint: if %true this GPIO is of type GpioInt otherwise type is GpioIo
* @pin_config: pin bias as provided by ACPI
* @polarity: interrupt polarity as provided by ACPI
* @triggering: triggering type as provided by ACPI
* @wake_capable: wake capability as provided by ACPI
* @debounce: debounce timeout as provided by ACPI
* @quirks: Linux specific quirks as provided by struct acpi_gpio_mapping
*/
struct acpi_gpio_info {
struct acpi_device *adev;
enum gpiod_flags flags;
bool gpioint;
int pin_config;
int polarity;
int triggering;
bool wake_capable;
unsigned int debounce;
unsigned int quirks;
};
#ifdef CONFIG_ACPI
void acpi_gpiochip_add(struct gpio_chip *chip);
void acpi_gpiochip_remove(struct gpio_chip *chip);
......@@ -55,19 +31,11 @@ void acpi_gpio_dev_init(struct gpio_chip *gc, struct gpio_device *gdev);
void acpi_gpiochip_request_interrupts(struct gpio_chip *chip);
void acpi_gpiochip_free_interrupts(struct gpio_chip *chip);
int acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags,
struct acpi_gpio_info *info);
int acpi_gpio_update_gpiod_lookup_flags(unsigned long *lookupflags,
struct acpi_gpio_info *info);
struct gpio_desc *acpi_find_gpio(struct device *dev,
struct gpio_desc *acpi_find_gpio(struct fwnode_handle *fwnode,
const char *con_id,
unsigned int idx,
enum gpiod_flags *dflags,
unsigned long *lookupflags);
struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode,
const char *propname, int index,
struct acpi_gpio_info *info);
int acpi_gpio_count(struct device *dev, const char *con_id);
#else
......@@ -82,31 +50,13 @@ acpi_gpiochip_request_interrupts(struct gpio_chip *chip) { }
static inline void
acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { }
static inline int
acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, struct acpi_gpio_info *info)
{
return 0;
}
static inline int
acpi_gpio_update_gpiod_lookup_flags(unsigned long *lookupflags,
struct acpi_gpio_info *info)
{
return 0;
}
static inline struct gpio_desc *
acpi_find_gpio(struct device *dev, const char *con_id,
acpi_find_gpio(struct fwnode_handle *fwnode, const char *con_id,
unsigned int idx, enum gpiod_flags *dflags,
unsigned long *lookupflags)
{
return ERR_PTR(-ENOENT);
}
static inline struct gpio_desc *
acpi_node_get_gpiod(struct fwnode_handle *fwnode, const char *propname,
int index, struct acpi_gpio_info *info)
{
return ERR_PTR(-ENXIO);
}
static inline int acpi_gpio_count(struct device *dev, const char *con_id)
{
return -ENODEV;
......
......@@ -57,6 +57,50 @@ static_assert(IS_ALIGNED(sizeof(struct gpio_v2_line_values), 8));
* interface to gpiolib GPIOs via ioctl()s.
*/
typedef __poll_t (*poll_fn)(struct file *, struct poll_table_struct *);
typedef long (*ioctl_fn)(struct file *, unsigned int, unsigned long);
typedef ssize_t (*read_fn)(struct file *, char __user *,
size_t count, loff_t *);
static __poll_t call_poll_locked(struct file *file,
struct poll_table_struct *wait,
struct gpio_device *gdev, poll_fn func)
{
__poll_t ret;
down_read(&gdev->sem);
ret = func(file, wait);
up_read(&gdev->sem);
return ret;
}
static long call_ioctl_locked(struct file *file, unsigned int cmd,
unsigned long arg, struct gpio_device *gdev,
ioctl_fn func)
{
long ret;
down_read(&gdev->sem);
ret = func(file, cmd, arg);
up_read(&gdev->sem);
return ret;
}
static ssize_t call_read_locked(struct file *file, char __user *buf,
size_t count, loff_t *f_ps,
struct gpio_device *gdev, read_fn func)
{
ssize_t ret;
down_read(&gdev->sem);
ret = func(file, buf, count, f_ps);
up_read(&gdev->sem);
return ret;
}
/*
* GPIO line handle management
*/
......@@ -193,8 +237,8 @@ static long linehandle_set_config(struct linehandle_state *lh,
return 0;
}
static long linehandle_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
static long linehandle_ioctl_unlocked(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct linehandle_state *lh = file->private_data;
void __user *ip = (void __user *)arg;
......@@ -203,6 +247,9 @@ static long linehandle_ioctl(struct file *file, unsigned int cmd,
unsigned int i;
int ret;
if (!lh->gdev->chip)
return -ENODEV;
switch (cmd) {
case GPIOHANDLE_GET_LINE_VALUES_IOCTL:
/* NOTE: It's okay to read values of output lines */
......@@ -249,6 +296,15 @@ static long linehandle_ioctl(struct file *file, unsigned int cmd,
}
}
static long linehandle_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct linehandle_state *lh = file->private_data;
return call_ioctl_locked(file, cmd, arg, lh->gdev,
linehandle_ioctl_unlocked);
}
#ifdef CONFIG_COMPAT
static long linehandle_ioctl_compat(struct file *file, unsigned int cmd,
unsigned long arg)
......@@ -412,7 +468,7 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
* @desc: the GPIO descriptor for this line.
* @req: the corresponding line request
* @irq: the interrupt triggered in response to events on this GPIO
* @eflags: the edge flags, GPIO_V2_LINE_FLAG_EDGE_RISING and/or
* @edflags: the edge flags, GPIO_V2_LINE_FLAG_EDGE_RISING and/or
* GPIO_V2_LINE_FLAG_EDGE_FALLING, indicating the edge detection applied
* @timestamp_ns: cache for the timestamp storing it between hardirq and
* IRQ thread, used to bring the timestamp close to the actual event
......@@ -1380,12 +1436,15 @@ static long linereq_set_config(struct linereq *lr, void __user *ip)
return ret;
}
static long linereq_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
static long linereq_ioctl_unlocked(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct linereq *lr = file->private_data;
void __user *ip = (void __user *)arg;
if (!lr->gdev->chip)
return -ENODEV;
switch (cmd) {
case GPIO_V2_LINE_GET_VALUES_IOCTL:
return linereq_get_values(lr, ip);
......@@ -1398,6 +1457,15 @@ static long linereq_ioctl(struct file *file, unsigned int cmd,
}
}
static long linereq_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct linereq *lr = file->private_data;
return call_ioctl_locked(file, cmd, arg, lr->gdev,
linereq_ioctl_unlocked);
}
#ifdef CONFIG_COMPAT
static long linereq_ioctl_compat(struct file *file, unsigned int cmd,
unsigned long arg)
......@@ -1406,12 +1474,15 @@ static long linereq_ioctl_compat(struct file *file, unsigned int cmd,
}
#endif
static __poll_t linereq_poll(struct file *file,
struct poll_table_struct *wait)
static __poll_t linereq_poll_unlocked(struct file *file,
struct poll_table_struct *wait)
{
struct linereq *lr = file->private_data;
__poll_t events = 0;
if (!lr->gdev->chip)
return EPOLLHUP | EPOLLERR;
poll_wait(file, &lr->wait, wait);
if (!kfifo_is_empty_spinlocked_noirqsave(&lr->events,
......@@ -1421,16 +1492,25 @@ static __poll_t linereq_poll(struct file *file,
return events;
}
static ssize_t linereq_read(struct file *file,
char __user *buf,
size_t count,
loff_t *f_ps)
static __poll_t linereq_poll(struct file *file,
struct poll_table_struct *wait)
{
struct linereq *lr = file->private_data;
return call_poll_locked(file, wait, lr->gdev, linereq_poll_unlocked);
}
static ssize_t linereq_read_unlocked(struct file *file, char __user *buf,
size_t count, loff_t *f_ps)
{
struct linereq *lr = file->private_data;
struct gpio_v2_line_event le;
ssize_t bytes_read = 0;
int ret;
if (!lr->gdev->chip)
return -ENODEV;
if (count < sizeof(le))
return -EINVAL;
......@@ -1475,6 +1555,15 @@ static ssize_t linereq_read(struct file *file,
return bytes_read;
}
static ssize_t linereq_read(struct file *file, char __user *buf,
size_t count, loff_t *f_ps)
{
struct linereq *lr = file->private_data;
return call_read_locked(file, buf, count, f_ps, lr->gdev,
linereq_read_unlocked);
}
static void linereq_free(struct linereq *lr)
{
unsigned int i;
......@@ -1712,12 +1801,15 @@ struct lineevent_state {
(GPIOEVENT_REQUEST_RISING_EDGE | \
GPIOEVENT_REQUEST_FALLING_EDGE)
static __poll_t lineevent_poll(struct file *file,
struct poll_table_struct *wait)
static __poll_t lineevent_poll_unlocked(struct file *file,
struct poll_table_struct *wait)
{
struct lineevent_state *le = file->private_data;
__poll_t events = 0;
if (!le->gdev->chip)
return EPOLLHUP | EPOLLERR;
poll_wait(file, &le->wait, wait);
if (!kfifo_is_empty_spinlocked_noirqsave(&le->events, &le->wait.lock))
......@@ -1726,15 +1818,21 @@ static __poll_t lineevent_poll(struct file *file,
return events;
}
static __poll_t lineevent_poll(struct file *file,
struct poll_table_struct *wait)
{
struct lineevent_state *le = file->private_data;
return call_poll_locked(file, wait, le->gdev, lineevent_poll_unlocked);
}
struct compat_gpioeevent_data {
compat_u64 timestamp;
u32 id;
};
static ssize_t lineevent_read(struct file *file,
char __user *buf,
size_t count,
loff_t *f_ps)
static ssize_t lineevent_read_unlocked(struct file *file, char __user *buf,
size_t count, loff_t *f_ps)
{
struct lineevent_state *le = file->private_data;
struct gpioevent_data ge;
......@@ -1742,6 +1840,9 @@ static ssize_t lineevent_read(struct file *file,
ssize_t ge_size;
int ret;
if (!le->gdev->chip)
return -ENODEV;
/*
* When compatible system call is being used the struct gpioevent_data,
* in case of at least ia32, has different size due to the alignment
......@@ -1799,6 +1900,15 @@ static ssize_t lineevent_read(struct file *file,
return bytes_read;
}
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;
return call_read_locked(file, buf, count, f_ps, le->gdev,
lineevent_read_unlocked);
}
static void lineevent_free(struct lineevent_state *le)
{
if (le->irq)
......@@ -1816,13 +1926,16 @@ static int lineevent_release(struct inode *inode, struct file *file)
return 0;
}
static long lineevent_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
static long lineevent_ioctl_unlocked(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;
if (!le->gdev->chip)
return -ENODEV;
/*
* We can get the value for an event line but not set it,
* because it is input by definition.
......@@ -1845,6 +1958,15 @@ static long lineevent_ioctl(struct file *file, unsigned int cmd,
return -EINVAL;
}
static long lineevent_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct lineevent_state *le = file->private_data;
return call_ioctl_locked(file, cmd, arg, le->gdev,
lineevent_ioctl_unlocked);
}
#ifdef CONFIG_COMPAT
static long lineevent_ioctl_compat(struct file *file, unsigned int cmd,
unsigned long arg)
......@@ -2403,12 +2525,15 @@ static int lineinfo_changed_notify(struct notifier_block *nb,
return NOTIFY_OK;
}
static __poll_t lineinfo_watch_poll(struct file *file,
struct poll_table_struct *pollt)
static __poll_t lineinfo_watch_poll_unlocked(struct file *file,
struct poll_table_struct *pollt)
{
struct gpio_chardev_data *cdev = file->private_data;
__poll_t events = 0;
if (!cdev->gdev->chip)
return EPOLLHUP | EPOLLERR;
poll_wait(file, &cdev->wait, pollt);
if (!kfifo_is_empty_spinlocked_noirqsave(&cdev->events,
......@@ -2418,8 +2543,17 @@ static __poll_t lineinfo_watch_poll(struct file *file,
return events;
}
static ssize_t lineinfo_watch_read(struct file *file, char __user *buf,
size_t count, loff_t *off)
static __poll_t lineinfo_watch_poll(struct file *file,
struct poll_table_struct *pollt)
{
struct gpio_chardev_data *cdev = file->private_data;
return call_poll_locked(file, pollt, cdev->gdev,
lineinfo_watch_poll_unlocked);
}
static ssize_t lineinfo_watch_read_unlocked(struct file *file, char __user *buf,
size_t count, loff_t *off)
{
struct gpio_chardev_data *cdev = file->private_data;
struct gpio_v2_line_info_changed event;
......@@ -2427,6 +2561,9 @@ static ssize_t lineinfo_watch_read(struct file *file, char __user *buf,
int ret;
size_t event_size;
if (!cdev->gdev->chip)
return -ENODEV;
#ifndef CONFIG_GPIO_CDEV_V1
event_size = sizeof(struct gpio_v2_line_info_changed);
if (count < event_size)
......@@ -2494,6 +2631,15 @@ static ssize_t lineinfo_watch_read(struct file *file, char __user *buf,
return bytes_read;
}
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;
return call_read_locked(file, buf, count, off, cdev->gdev,
lineinfo_watch_read_unlocked);
}
/**
* gpio_chrdev_open() - open the chardev for ioctl operations
* @inode: inode for this chardev
......@@ -2507,13 +2653,17 @@ static int gpio_chrdev_open(struct inode *inode, struct file *file)
struct gpio_chardev_data *cdev;
int ret = -ENOMEM;
down_read(&gdev->sem);
/* Fail on open if the backing gpiochip is gone */
if (!gdev->chip)
return -ENODEV;
if (!gdev->chip) {
ret = -ENODEV;
goto out_unlock;
}
cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
if (!cdev)
return -ENOMEM;
goto out_unlock;
cdev->watched_lines = bitmap_zalloc(gdev->chip->ngpio, GFP_KERNEL);
if (!cdev->watched_lines)
......@@ -2536,6 +2686,8 @@ static int gpio_chrdev_open(struct inode *inode, struct file *file)
if (ret)
goto out_unregister_notifier;
up_read(&gdev->sem);
return ret;
out_unregister_notifier:
......@@ -2545,6 +2697,8 @@ static int gpio_chrdev_open(struct inode *inode, struct file *file)
bitmap_free(cdev->watched_lines);
out_free_cdev:
kfree(cdev);
out_unlock:
up_read(&gdev->sem);
return ret;
}
......
......@@ -85,7 +85,7 @@ static int of_gpiochip_match_node_and_xlate(struct gpio_chip *chip, void *data)
{
struct of_phandle_args *gpiospec = data;
return chip->gpiodev->dev.of_node == gpiospec->np &&
return device_match_of_node(&chip->gpiodev->dev, gpiospec->np) &&
chip->of_xlate &&
chip->of_xlate(chip, gpiospec, NULL) >= 0;
}
......@@ -112,55 +112,133 @@ static struct gpio_desc *of_xlate_and_get_gpiod_flags(struct gpio_chip *chip,
return gpiochip_get_desc(chip, ret);
}
/**
* of_gpio_need_valid_mask() - figure out if the OF GPIO driver needs
* to set the .valid_mask
* @gc: the target gpio_chip
*
* Return: true if the valid mask needs to be set
/*
* Overrides stated polarity of a gpio line and warns when there is a
* discrepancy.
*/
bool of_gpio_need_valid_mask(const struct gpio_chip *gc)
static void of_gpio_quirk_polarity(const struct device_node *np,
bool active_high,
enum of_gpio_flags *flags)
{
int size;
const struct device_node *np = gc->of_node;
if (active_high) {
if (*flags & OF_GPIO_ACTIVE_LOW) {
pr_warn("%s GPIO handle specifies active low - ignored\n",
of_node_full_name(np));
*flags &= ~OF_GPIO_ACTIVE_LOW;
}
} else {
if (!(*flags & OF_GPIO_ACTIVE_LOW))
pr_info("%s enforce active low on GPIO handle\n",
of_node_full_name(np));
*flags |= OF_GPIO_ACTIVE_LOW;
}
}
size = of_property_count_u32_elems(np, "gpio-reserved-ranges");
if (size > 0 && size % 2 == 0)
return true;
return false;
/*
* This quirk does static polarity overrides in cases where existing
* DTS specified incorrect polarity.
*/
static void of_gpio_try_fixup_polarity(const struct device_node *np,
const char *propname,
enum of_gpio_flags *flags)
{
static const struct {
const char *compatible;
const char *propname;
bool active_high;
} gpios[] = {
#if !IS_ENABLED(CONFIG_LCD_HX8357)
/*
* Himax LCD controllers used incorrectly named
* "gpios-reset" property and also specified wrong
* polarity.
*/
{ "himax,hx8357", "gpios-reset", false },
{ "himax,hx8369", "gpios-reset", false },
#endif
};
unsigned int i;
for (i = 0; i < ARRAY_SIZE(gpios); i++) {
if (of_device_is_compatible(np, gpios[i].compatible) &&
!strcmp(propname, gpios[i].propname)) {
of_gpio_quirk_polarity(np, gpios[i].active_high, flags);
break;
}
}
}
static void of_gpio_flags_quirks(const struct device_node *np,
const char *propname,
enum of_gpio_flags *flags,
int index)
static void of_gpio_set_polarity_by_property(const struct device_node *np,
const char *propname,
enum of_gpio_flags *flags)
{
/*
* Some GPIO fixed regulator quirks.
* Note that active low is the default.
*/
if (IS_ENABLED(CONFIG_REGULATOR) &&
(of_device_is_compatible(np, "regulator-fixed") ||
of_device_is_compatible(np, "reg-fixed-voltage") ||
(!(strcmp(propname, "enable-gpio") &&
strcmp(propname, "enable-gpios")) &&
of_device_is_compatible(np, "regulator-gpio")))) {
bool active_low = !of_property_read_bool(np,
"enable-active-high");
static const struct {
const char *compatible;
const char *gpio_propname;
const char *polarity_propname;
} gpios[] = {
#if IS_ENABLED(CONFIG_FEC)
/* Freescale Fast Ethernet Controller */
{ "fsl,imx25-fec", "phy-reset-gpios", "phy-reset-active-high" },
{ "fsl,imx27-fec", "phy-reset-gpios", "phy-reset-active-high" },
{ "fsl,imx28-fec", "phy-reset-gpios", "phy-reset-active-high" },
{ "fsl,imx6q-fec", "phy-reset-gpios", "phy-reset-active-high" },
{ "fsl,mvf600-fec", "phy-reset-gpios", "phy-reset-active-high" },
{ "fsl,imx6sx-fec", "phy-reset-gpios", "phy-reset-active-high" },
{ "fsl,imx6ul-fec", "phy-reset-gpios", "phy-reset-active-high" },
{ "fsl,imx8mq-fec", "phy-reset-gpios", "phy-reset-active-high" },
{ "fsl,imx8qm-fec", "phy-reset-gpios", "phy-reset-active-high" },
{ "fsl,s32v234-fec", "phy-reset-gpios", "phy-reset-active-high" },
#endif
#if IS_ENABLED(CONFIG_PCI_IMX6)
{ "fsl,imx6q-pcie", "reset-gpio", "reset-gpio-active-high" },
{ "fsl,imx6sx-pcie", "reset-gpio", "reset-gpio-active-high" },
{ "fsl,imx6qp-pcie", "reset-gpio", "reset-gpio-active-high" },
{ "fsl,imx7d-pcie", "reset-gpio", "reset-gpio-active-high" },
{ "fsl,imx8mq-pcie", "reset-gpio", "reset-gpio-active-high" },
{ "fsl,imx8mm-pcie", "reset-gpio", "reset-gpio-active-high" },
{ "fsl,imx8mp-pcie", "reset-gpio", "reset-gpio-active-high" },
#endif
/*
* The regulator GPIO handles are specified such that the
* presence or absence of "enable-active-high" solely controls
* the polarity of the GPIO line. Any phandle flags must
* be actively ignored.
*/
if ((*flags & OF_GPIO_ACTIVE_LOW) && !active_low) {
pr_warn("%s GPIO handle specifies active low - ignored\n",
of_node_full_name(np));
*flags &= ~OF_GPIO_ACTIVE_LOW;
#if IS_ENABLED(CONFIG_REGULATOR_FIXED_VOLTAGE)
{ "regulator-fixed", "gpios", "enable-active-high" },
{ "regulator-fixed", "gpio", "enable-active-high" },
{ "reg-fixed-voltage", "gpios", "enable-active-high" },
{ "reg-fixed-voltage", "gpio", "enable-active-high" },
#endif
#if IS_ENABLED(CONFIG_REGULATOR_GPIO)
{ "regulator-gpio", "enable-gpio", "enable-active-high" },
{ "regulator-gpio", "enable-gpios", "enable-active-high" },
#endif
};
unsigned int i;
bool active_high;
for (i = 0; i < ARRAY_SIZE(gpios); i++) {
if (of_device_is_compatible(np, gpios[i].compatible) &&
!strcmp(propname, gpios[i].gpio_propname)) {
active_high = of_property_read_bool(np,
gpios[i].polarity_propname);
of_gpio_quirk_polarity(np, active_high, flags);
break;
}
if (active_low)
*flags |= OF_GPIO_ACTIVE_LOW;
}
}
static void of_gpio_flags_quirks(const struct device_node *np,
const char *propname,
enum of_gpio_flags *flags,
int index)
{
of_gpio_try_fixup_polarity(np, propname, flags);
of_gpio_set_polarity_by_property(np, propname, flags);
/*
* Legacy open drain handling for fixed voltage regulators.
*/
......@@ -200,18 +278,10 @@ static void of_gpio_flags_quirks(const struct device_node *np,
* conflict and the "spi-cs-high" flag will
* take precedence.
*/
if (of_property_read_bool(child, "spi-cs-high")) {
if (*flags & OF_GPIO_ACTIVE_LOW) {
pr_warn("%s GPIO handle specifies active low - ignored\n",
of_node_full_name(child));
*flags &= ~OF_GPIO_ACTIVE_LOW;
}
} else {
if (!(*flags & OF_GPIO_ACTIVE_LOW))
pr_info("%s enforce active low on chipselect handle\n",
of_node_full_name(child));
*flags |= OF_GPIO_ACTIVE_LOW;
}
bool active_high = of_property_read_bool(child,
"spi-cs-high");
of_gpio_quirk_polarity(child, active_high,
flags);
of_node_put(child);
break;
}
......@@ -365,127 +435,164 @@ struct gpio_desc *gpiod_get_from_of_node(const struct device_node *node,
}
EXPORT_SYMBOL_GPL(gpiod_get_from_of_node);
/*
* The SPI GPIO bindings happened before we managed to establish that GPIO
* properties should be named "foo-gpios" so we have this special kludge for
* them.
*/
static struct gpio_desc *of_find_spi_gpio(struct device_node *np,
const char *con_id,
unsigned int idx,
enum of_gpio_flags *of_flags)
{
char prop_name[32]; /* 32 is max size of property name */
/*
* Hopefully the compiler stubs the rest of the function if this
* is false.
*/
if (!IS_ENABLED(CONFIG_SPI_MASTER))
return ERR_PTR(-ENOENT);
/* Allow this specifically for "spi-gpio" devices */
if (!of_device_is_compatible(np, "spi-gpio") || !con_id)
return ERR_PTR(-ENOENT);
/* Will be "gpio-sck", "gpio-mosi" or "gpio-miso" */
snprintf(prop_name, sizeof(prop_name), "%s-%s", "gpio", con_id);
return of_get_named_gpiod_flags(np, prop_name, idx, of_flags);
}
/*
* The old Freescale bindings use simply "gpios" as name for the chip select
* lines rather than "cs-gpios" like all other SPI hardware. Account for this
* with a special quirk.
*/
static struct gpio_desc *of_find_spi_cs_gpio(struct device_node *np,
static struct gpio_desc *of_find_gpio_rename(struct device_node *np,
const char *con_id,
unsigned int idx,
enum of_gpio_flags *of_flags)
{
if (!IS_ENABLED(CONFIG_SPI_MASTER))
return ERR_PTR(-ENOENT);
static const struct of_rename_gpio {
const char *con_id;
const char *legacy_id; /* NULL - same as con_id */
/*
* Compatible string can be set to NULL in case where
* matching to a particular compatible is not practical,
* but it should only be done for gpio names that have
* vendor prefix to reduce risk of false positives.
* Addition of such entries is strongly discouraged.
*/
const char *compatible;
} gpios[] = {
#if !IS_ENABLED(CONFIG_LCD_HX8357)
/* Himax LCD controllers used "gpios-reset" */
{ "reset", "gpios-reset", "himax,hx8357" },
{ "reset", "gpios-reset", "himax,hx8369" },
#endif
#if IS_ENABLED(CONFIG_MFD_ARIZONA)
{ "wlf,reset", NULL, NULL },
#endif
#if IS_ENABLED(CONFIG_RTC_DRV_MOXART)
{ "rtc-data", "gpio-rtc-data", "moxa,moxart-rtc" },
{ "rtc-sclk", "gpio-rtc-sclk", "moxa,moxart-rtc" },
{ "rtc-reset", "gpio-rtc-reset", "moxa,moxart-rtc" },
#endif
#if IS_ENABLED(CONFIG_NFC_MRVL_I2C)
{ "reset", "reset-n-io", "marvell,nfc-i2c" },
#endif
#if IS_ENABLED(CONFIG_NFC_MRVL_SPI)
{ "reset", "reset-n-io", "marvell,nfc-spi" },
#endif
#if IS_ENABLED(CONFIG_NFC_MRVL_UART)
{ "reset", "reset-n-io", "marvell,nfc-uart" },
{ "reset", "reset-n-io", "mrvl,nfc-uart" },
#endif
#if !IS_ENABLED(CONFIG_PCI_LANTIQ)
/* MIPS Lantiq PCI */
{ "reset", "gpios-reset", "lantiq,pci-xway" },
#endif
/* Allow this specifically for Freescale and PPC devices */
if (!of_device_is_compatible(np, "fsl,spi") &&
!of_device_is_compatible(np, "aeroflexgaisler,spictrl") &&
!of_device_is_compatible(np, "ibm,ppc4xx-spi"))
return ERR_PTR(-ENOENT);
/* Allow only if asking for "cs-gpios" */
if (!con_id || strcmp(con_id, "cs"))
return ERR_PTR(-ENOENT);
/*
* Some regulator bindings happened before we managed to
* establish that GPIO properties should be named
* "foo-gpios" so we have this special kludge for them.
*/
#if IS_ENABLED(CONFIG_REGULATOR_ARIZONA_LDO1)
{ "wlf,ldoena", NULL, NULL }, /* Arizona */
#endif
#if IS_ENABLED(CONFIG_REGULATOR_WM8994)
{ "wlf,ldo1ena", NULL, NULL }, /* WM8994 */
{ "wlf,ldo2ena", NULL, NULL }, /* WM8994 */
#endif
/*
* While all other SPI controllers use "cs-gpios" the Freescale
* uses just "gpios" so translate to that when "cs-gpios" is
* requested.
*/
return of_get_named_gpiod_flags(np, "gpios", idx, of_flags);
}
#if IS_ENABLED(CONFIG_SND_SOC_CS42L56)
{ "reset", "cirrus,gpio-nreset", "cirrus,cs42l56" },
#endif
#if IS_ENABLED(CONFIG_SND_SOC_TLV320AIC3X)
{ "reset", "gpio-reset", "ti,tlv320aic3x" },
{ "reset", "gpio-reset", "ti,tlv320aic33" },
{ "reset", "gpio-reset", "ti,tlv320aic3007" },
{ "reset", "gpio-reset", "ti,tlv320aic3104" },
{ "reset", "gpio-reset", "ti,tlv320aic3106" },
#endif
#if IS_ENABLED(CONFIG_SPI_GPIO)
/*
* The SPI GPIO bindings happened before we managed to
* establish that GPIO properties should be named
* "foo-gpios" so we have this special kludge for them.
*/
{ "miso", "gpio-miso", "spi-gpio" },
{ "mosi", "gpio-mosi", "spi-gpio" },
{ "sck", "gpio-sck", "spi-gpio" },
#endif
/*
* Some regulator bindings happened before we managed to establish that GPIO
* properties should be named "foo-gpios" so we have this special kludge for
* them.
*/
static struct gpio_desc *of_find_regulator_gpio(struct device_node *np,
const char *con_id,
unsigned int idx,
enum of_gpio_flags *of_flags)
{
/* These are the connection IDs we accept as legacy GPIO phandles */
const char *whitelist[] = {
"wlf,ldoena", /* Arizona */
"wlf,ldo1ena", /* WM8994 */
"wlf,ldo2ena", /* WM8994 */
};
int i;
/*
* The old Freescale bindings use simply "gpios" as name
* for the chip select lines rather than "cs-gpios" like
* all other SPI hardware. Allow this specifically for
* Freescale and PPC devices.
*/
#if IS_ENABLED(CONFIG_SPI_FSL_SPI)
{ "cs", "gpios", "fsl,spi" },
{ "cs", "gpios", "aeroflexgaisler,spictrl" },
#endif
#if IS_ENABLED(CONFIG_SPI_PPC4xx)
{ "cs", "gpios", "ibm,ppc4xx-spi" },
#endif
if (!IS_ENABLED(CONFIG_REGULATOR))
return ERR_PTR(-ENOENT);
#if IS_ENABLED(CONFIG_TYPEC_FUSB302)
/*
* Fairchild FUSB302 host is using undocumented "fcs,int_n"
* property without the compulsory "-gpios" suffix.
*/
{ "fcs,int_n", NULL, "fcs,fusb302" },
#endif
};
struct gpio_desc *desc;
const char *legacy_id;
unsigned int i;
if (!con_id)
return ERR_PTR(-ENOENT);
i = match_string(whitelist, ARRAY_SIZE(whitelist), con_id);
if (i < 0)
return ERR_PTR(-ENOENT);
for (i = 0; i < ARRAY_SIZE(gpios); i++) {
if (strcmp(con_id, gpios[i].con_id))
continue;
if (gpios[i].compatible &&
!of_device_is_compatible(np, gpios[i].compatible))
continue;
legacy_id = gpios[i].legacy_id ?: gpios[i].con_id;
desc = of_get_named_gpiod_flags(np, legacy_id, idx, of_flags);
if (!gpiod_not_found(desc)) {
pr_info("%s uses legacy gpio name '%s' instead of '%s-gpios'\n",
of_node_full_name(np), legacy_id, con_id);
return desc;
}
}
return of_get_named_gpiod_flags(np, con_id, idx, of_flags);
return ERR_PTR(-ENOENT);
}
static struct gpio_desc *of_find_arizona_gpio(struct device_node *np,
const char *con_id,
unsigned int idx,
enum of_gpio_flags *of_flags)
static struct gpio_desc *of_find_mt2701_gpio(struct device_node *np,
const char *con_id,
unsigned int idx,
enum of_gpio_flags *of_flags)
{
if (!IS_ENABLED(CONFIG_MFD_ARIZONA))
return ERR_PTR(-ENOENT);
struct gpio_desc *desc;
const char *legacy_id;
if (!con_id || strcmp(con_id, "wlf,reset"))
if (!IS_ENABLED(CONFIG_SND_SOC_MT2701_CS42448))
return ERR_PTR(-ENOENT);
return of_get_named_gpiod_flags(np, con_id, idx, of_flags);
}
if (!of_device_is_compatible(np, "mediatek,mt2701-cs42448-machine"))
return ERR_PTR(-ENOENT);
static struct gpio_desc *of_find_usb_gpio(struct device_node *np,
const char *con_id,
unsigned int idx,
enum of_gpio_flags *of_flags)
{
/*
* Currently this USB quirk is only for the Fairchild FUSB302 host
* which is using an undocumented DT GPIO line named "fcs,int_n"
* without the compulsory "-gpios" suffix.
*/
if (!IS_ENABLED(CONFIG_TYPEC_FUSB302))
if (!con_id || strcmp(con_id, "i2s1-in-sel"))
return ERR_PTR(-ENOENT);
if (!con_id || strcmp(con_id, "fcs,int_n"))
if (idx == 0)
legacy_id = "i2s1-in-sel-gpio1";
else if (idx == 1)
legacy_id = "i2s1-in-sel-gpio2";
else
return ERR_PTR(-ENOENT);
return of_get_named_gpiod_flags(np, con_id, idx, of_flags);
desc = of_get_named_gpiod_flags(np, legacy_id, 0, of_flags);
if (!gpiod_not_found(desc))
pr_info("%s is using legacy gpio name '%s' instead of '%s-gpios'\n",
of_node_full_name(np), legacy_id, con_id);
return desc;
}
typedef struct gpio_desc *(*of_find_gpio_quirk)(struct device_node *np,
......@@ -493,15 +600,12 @@ typedef struct gpio_desc *(*of_find_gpio_quirk)(struct device_node *np,
unsigned int idx,
enum of_gpio_flags *of_flags);
static const of_find_gpio_quirk of_find_gpio_quirks[] = {
of_find_spi_gpio,
of_find_spi_cs_gpio,
of_find_regulator_gpio,
of_find_arizona_gpio,
of_find_usb_gpio,
of_find_gpio_rename,
of_find_mt2701_gpio,
NULL
};
struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
struct gpio_desc *of_find_gpio(struct device_node *np, const char *con_id,
unsigned int idx, unsigned long *flags)
{
char prop_name[32]; /* 32 is max size of property name */
......@@ -519,8 +623,7 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
snprintf(prop_name, sizeof(prop_name), "%s",
gpio_suffixes[i]);
desc = of_get_named_gpiod_flags(dev->of_node, prop_name, idx,
&of_flags);
desc = of_get_named_gpiod_flags(np, prop_name, idx, &of_flags);
if (!gpiod_not_found(desc))
break;
......@@ -528,7 +631,7 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
/* Properly named GPIO was not found, try workarounds */
for (q = of_find_gpio_quirks; gpiod_not_found(desc) && *q; q++)
desc = (*q)(dev->of_node, con_id, idx, &of_flags);
desc = (*q)(np, con_id, idx, &of_flags);
if (IS_ERR(desc))
return desc;
......@@ -831,8 +934,8 @@ int of_mm_gpiochip_add_data(struct device_node *np,
if (mm_gc->save_regs)
mm_gc->save_regs(mm_gc);
of_node_put(mm_gc->gc.of_node);
mm_gc->gc.of_node = of_node_get(np);
fwnode_handle_put(mm_gc->gc.fwnode);
mm_gc->gc.fwnode = fwnode_handle_get(of_fwnode_handle(np));
ret = gpiochip_add_data(gc, data);
if (ret)
......@@ -858,37 +961,12 @@ void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc)
{
struct gpio_chip *gc = &mm_gc->gc;
if (!mm_gc)
return;
gpiochip_remove(gc);
iounmap(mm_gc->regs);
kfree(gc->label);
}
EXPORT_SYMBOL_GPL(of_mm_gpiochip_remove);
static void of_gpiochip_init_valid_mask(struct gpio_chip *chip)
{
int len, i;
u32 start, count;
struct device_node *np = chip->of_node;
len = of_property_count_u32_elems(np, "gpio-reserved-ranges");
if (len < 0 || len % 2 != 0)
return;
for (i = 0; i < len; i += 2) {
of_property_read_u32_index(np, "gpio-reserved-ranges",
i, &start);
of_property_read_u32_index(np, "gpio-reserved-ranges",
i + 1, &count);
if (start >= chip->ngpio || start + count > chip->ngpio)
continue;
bitmap_clear(chip->valid_mask, start, count);
}
};
#ifdef CONFIG_PINCTRL
static int of_gpiochip_add_pin_range(struct gpio_chip *chip)
{
......@@ -982,9 +1060,11 @@ static int of_gpiochip_add_pin_range(struct gpio_chip *chip) { return 0; }
int of_gpiochip_add(struct gpio_chip *chip)
{
struct device_node *np;
int ret;
if (!chip->of_node)
np = to_of_node(dev_fwnode(&chip->gpiodev->dev));
if (!np)
return 0;
if (!chip->of_xlate) {
......@@ -995,24 +1075,22 @@ int of_gpiochip_add(struct gpio_chip *chip)
if (chip->of_gpio_n_cells > MAX_PHANDLE_ARGS)
return -EINVAL;
of_gpiochip_init_valid_mask(chip);
ret = of_gpiochip_add_pin_range(chip);
if (ret)
return ret;
of_node_get(chip->of_node);
fwnode_handle_get(chip->fwnode);
ret = of_gpiochip_scan_gpios(chip);
if (ret)
of_node_put(chip->of_node);
fwnode_handle_put(chip->fwnode);
return ret;
}
void of_gpiochip_remove(struct gpio_chip *chip)
{
of_node_put(chip->of_node);
fwnode_handle_put(chip->fwnode);
}
void of_gpio_dev_init(struct gpio_chip *gc, struct gpio_device *gdev)
......
......@@ -16,17 +16,16 @@ struct gpio_desc;
struct gpio_device;
#ifdef CONFIG_OF_GPIO
struct gpio_desc *of_find_gpio(struct device *dev,
struct gpio_desc *of_find_gpio(struct device_node *np,
const char *con_id,
unsigned int idx,
unsigned long *lookupflags);
int of_gpiochip_add(struct gpio_chip *gc);
void of_gpiochip_remove(struct gpio_chip *gc);
int of_gpio_get_count(struct device *dev, const char *con_id);
bool of_gpio_need_valid_mask(const struct gpio_chip *gc);
void of_gpio_dev_init(struct gpio_chip *gc, struct gpio_device *gdev);
#else
static inline struct gpio_desc *of_find_gpio(struct device *dev,
static inline struct gpio_desc *of_find_gpio(struct device_node *np,
const char *con_id,
unsigned int idx,
unsigned long *lookupflags)
......@@ -39,10 +38,6 @@ static inline int of_gpio_get_count(struct device *dev, const char *con_id)
{
return 0;
}
static inline bool of_gpio_need_valid_mask(const struct gpio_chip *gc)
{
return false;
}
static inline void of_gpio_dev_init(struct gpio_chip *gc,
struct gpio_device *gdev)
{
......
// SPDX-License-Identifier: GPL-2.0+
/*
* Software Node helpers for the GPIO API
*
* Copyright 2022 Google LLC
*/
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h>
#include <linux/kernel.h>
#include <linux/printk.h>
#include <linux/property.h>
#include <linux/string.h>
#include "gpiolib.h"
#include "gpiolib-swnode.h"
static void swnode_format_propname(const char *con_id, char *propname,
size_t max_size)
{
/*
* Note we do not need to try both -gpios and -gpio suffixes,
* as, unlike OF and ACPI, we can fix software nodes to conform
* to the proper binding.
*/
if (con_id)
snprintf(propname, max_size, "%s-gpios", con_id);
else
strscpy(propname, "gpios", max_size);
}
static int swnode_gpiochip_match_name(struct gpio_chip *chip, void *data)
{
return !strcmp(chip->label, data);
}
static struct gpio_chip *swnode_get_chip(struct fwnode_handle *fwnode)
{
const struct software_node *chip_node;
struct gpio_chip *chip;
chip_node = to_software_node(fwnode);
if (!chip_node || !chip_node->name)
return ERR_PTR(-EINVAL);
chip = gpiochip_find((void *)chip_node->name, swnode_gpiochip_match_name);
return chip ?: ERR_PTR(-EPROBE_DEFER);
}
struct gpio_desc *swnode_find_gpio(struct fwnode_handle *fwnode,
const char *con_id, unsigned int idx,
unsigned long *flags)
{
const struct software_node *swnode;
struct fwnode_reference_args args;
struct gpio_chip *chip;
struct gpio_desc *desc;
char propname[32]; /* 32 is max size of property name */
int error;
swnode = to_software_node(fwnode);
if (!swnode)
return ERR_PTR(-EINVAL);
swnode_format_propname(con_id, propname, sizeof(propname));
/*
* We expect all swnode-described GPIOs have GPIO number and
* polarity arguments, hence nargs is set to 2.
*/
error = fwnode_property_get_reference_args(fwnode, propname, NULL, 2, idx, &args);
if (error) {
pr_debug("%s: can't parse '%s' property of node '%pfwP[%d]'\n",
__func__, propname, fwnode, idx);
return ERR_PTR(error);
}
chip = swnode_get_chip(args.fwnode);
fwnode_handle_put(args.fwnode);
if (IS_ERR(chip))
return ERR_CAST(chip);
desc = gpiochip_get_desc(chip, args.args[0]);
*flags = args.args[1]; /* We expect native GPIO flags */
pr_debug("%s: parsed '%s' property of node '%pfwP[%d]' - status (%d)\n",
__func__, propname, fwnode, idx, PTR_ERR_OR_ZERO(desc));
return desc;
}
/**
* swnode_gpio_count - count the GPIOs associated with a device / function
* @fwnode: firmware node of the GPIO consumer, can be %NULL for
* system-global GPIOs
* @con_id: function within the GPIO consumer
*
* Return:
* The number of GPIOs associated with a device / function or %-ENOENT,
* if no GPIO has been assigned to the requested function.
*/
int swnode_gpio_count(const struct fwnode_handle *fwnode, const char *con_id)
{
struct fwnode_reference_args args;
char propname[32];
int count;
swnode_format_propname(con_id, propname, sizeof(propname));
/*
* This is not very efficient, but GPIO lists usually have only
* 1 or 2 entries.
*/
count = 0;
while (fwnode_property_get_reference_args(fwnode, propname, NULL, 0,
count, &args) == 0) {
fwnode_handle_put(args.fwnode);
count++;
}
return count ?: -ENOENT;
}
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef GPIOLIB_SWNODE_H
#define GPIOLIB_SWNODE_H
struct fwnode_handle;
struct gpio_desc;
struct gpio_desc *swnode_find_gpio(struct fwnode_handle *fwnode,
const char *con_id, unsigned int idx,
unsigned long *flags);
int swnode_gpio_count(const struct fwnode_handle *fwnode, const char *con_id);
#endif /* GPIOLIB_SWNODE_H */
......@@ -26,6 +26,7 @@
#include "gpiolib.h"
#include "gpiolib-of.h"
#include "gpiolib-acpi.h"
#include "gpiolib-swnode.h"
#include "gpiolib-cdev.h"
#include "gpiolib-sysfs.h"
......@@ -183,14 +184,14 @@ EXPORT_SYMBOL_GPL(gpiod_to_chip);
static int gpiochip_find_base(int ngpio)
{
struct gpio_device *gdev;
int base = ARCH_NR_GPIOS - ngpio;
int base = GPIO_DYNAMIC_BASE;
list_for_each_entry_reverse(gdev, &gpio_devices, list) {
list_for_each_entry(gdev, &gpio_devices, list) {
/* found a free space? */
if (gdev->base + gdev->ngpio <= base)
if (gdev->base >= base + ngpio)
break;
/* nope, check the space right before the chip */
base = gdev->base - ngpio;
/* nope, check the space right after the chip */
base = gdev->base + gdev->ngpio;
}
if (gpio_is_valid(base)) {
......@@ -366,12 +367,12 @@ static int gpiochip_set_desc_names(struct gpio_chip *gc)
static int devprop_gpiochip_set_names(struct gpio_chip *chip)
{
struct gpio_device *gdev = chip->gpiodev;
struct fwnode_handle *fwnode = dev_fwnode(&gdev->dev);
struct device *dev = &gdev->dev;
const char **names;
int ret, i;
int count;
count = fwnode_property_string_array_count(fwnode, "gpio-line-names");
count = device_property_string_array_count(dev, "gpio-line-names");
if (count < 0)
return 0;
......@@ -384,7 +385,7 @@ static int devprop_gpiochip_set_names(struct gpio_chip *chip)
* gpiochips.
*/
if (count <= chip->offset) {
dev_warn(&gdev->dev, "gpio-line-names too short (length %d), cannot map names for the gpiochip at offset %u\n",
dev_warn(dev, "gpio-line-names too short (length %d), cannot map names for the gpiochip at offset %u\n",
count, chip->offset);
return 0;
}
......@@ -393,10 +394,10 @@ static int devprop_gpiochip_set_names(struct gpio_chip *chip)
if (!names)
return -ENOMEM;
ret = fwnode_property_read_string_array(fwnode, "gpio-line-names",
ret = device_property_read_string_array(dev, "gpio-line-names",
names, count);
if (ret < 0) {
dev_warn(&gdev->dev, "failed to read GPIO line names\n");
dev_warn(dev, "failed to read GPIO line names\n");
kfree(names);
return ret;
}
......@@ -445,9 +446,22 @@ static unsigned long *gpiochip_allocate_mask(struct gpio_chip *gc)
return p;
}
static unsigned int gpiochip_count_reserved_ranges(struct gpio_chip *gc)
{
struct device *dev = &gc->gpiodev->dev;
int size;
/* Format is "start, count, ..." */
size = device_property_count_u32(dev, "gpio-reserved-ranges");
if (size > 0 && size % 2 == 0)
return size;
return 0;
}
static int gpiochip_alloc_valid_mask(struct gpio_chip *gc)
{
if (!(of_gpio_need_valid_mask(gc) || gc->init_valid_mask))
if (!(gpiochip_count_reserved_ranges(gc) || gc->init_valid_mask))
return 0;
gc->valid_mask = gpiochip_allocate_mask(gc);
......@@ -457,8 +471,50 @@ static int gpiochip_alloc_valid_mask(struct gpio_chip *gc)
return 0;
}
static int gpiochip_apply_reserved_ranges(struct gpio_chip *gc)
{
struct device *dev = &gc->gpiodev->dev;
unsigned int size;
u32 *ranges;
int ret;
size = gpiochip_count_reserved_ranges(gc);
if (size == 0)
return 0;
ranges = kmalloc_array(size, sizeof(*ranges), GFP_KERNEL);
if (!ranges)
return -ENOMEM;
ret = device_property_read_u32_array(dev, "gpio-reserved-ranges",
ranges, size);
if (ret) {
kfree(ranges);
return ret;
}
while (size) {
u32 count = ranges[--size];
u32 start = ranges[--size];
if (start >= gc->ngpio || start + count > gc->ngpio)
continue;
bitmap_clear(gc->valid_mask, start, count);
}
kfree(ranges);
return 0;
}
static int gpiochip_init_valid_mask(struct gpio_chip *gc)
{
int ret;
ret = gpiochip_apply_reserved_ranges(gc);
if (ret)
return ret;
if (gc->init_valid_mask)
return gc->init_valid_mask(gc,
gc->valid_mask,
......@@ -493,7 +549,7 @@ EXPORT_SYMBOL_GPL(gpiochip_line_is_valid);
static void gpiodevice_release(struct device *dev)
{
struct gpio_device *gdev = container_of(dev, struct gpio_device, dev);
struct gpio_device *gdev = to_gpio_device(dev);
unsigned long flags;
spin_lock_irqsave(&gpio_lock, flags);
......@@ -627,7 +683,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
* Assign fwnode depending on the result of the previous calls,
* if none of them succeed, assign it to the parent's one.
*/
gdev->dev.fwnode = dev_fwnode(&gdev->dev) ?: fwnode;
gc->fwnode = gdev->dev.fwnode = dev_fwnode(&gdev->dev) ?: fwnode;
gdev->id = ida_alloc(&gpio_ida, GFP_KERNEL);
if (gdev->id < 0) {
......@@ -719,6 +775,9 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
* a poison instead.
*/
gc->base = base;
} else {
dev_warn(&gdev->dev,
"Static allocation of GPIO base is deprecated, use dynamic allocation.\n");
}
gdev->base = base;
......@@ -735,6 +794,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
spin_unlock_irqrestore(&gpio_lock, flags);
BLOCKING_INIT_NOTIFIER_HEAD(&gdev->notifier);
init_rwsem(&gdev->sem);
#ifdef CONFIG_PINCTRL
INIT_LIST_HEAD(&gdev->pin_ranges);
......@@ -875,6 +935,8 @@ void gpiochip_remove(struct gpio_chip *gc)
unsigned long flags;
unsigned int i;
down_write(&gdev->sem);
/* FIXME: should the legacy sysfs handling be moved to gpio_device? */
gpiochip_sysfs_unregister(gdev);
gpiochip_free_hogs(gc);
......@@ -909,6 +971,7 @@ void gpiochip_remove(struct gpio_chip *gc)
* gone.
*/
gcdev_unregister(gdev);
up_write(&gdev->sem);
put_device(&gdev->dev);
}
EXPORT_SYMBOL_GPL(gpiochip_remove);
......@@ -3808,62 +3871,88 @@ static int platform_gpio_count(struct device *dev, const char *con_id)
return count;
}
/**
* fwnode_get_named_gpiod - obtain a GPIO from firmware node
* @fwnode: handle of the firmware node
* @propname: name of the firmware property representing the GPIO
* @index: index of the GPIO to obtain for the consumer
* @dflags: GPIO initialization flags
* @label: label to attach to the requested GPIO
*
* This function can be used for drivers that get their configuration
* from opaque firmware.
*
* The function properly finds the corresponding GPIO using whatever is the
* underlying firmware interface and then makes sure that the GPIO
* descriptor is requested before it is returned to the caller.
*
* Returns:
* On successful request the GPIO pin is configured in accordance with
* provided @dflags.
*
* In case of error an ERR_PTR() is returned.
*/
static struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
const char *propname, int index,
enum gpiod_flags dflags,
const char *label)
static struct gpio_desc *gpiod_find_by_fwnode(struct fwnode_handle *fwnode,
struct device *consumer,
const char *con_id,
unsigned int idx,
enum gpiod_flags *flags,
unsigned long *lookupflags)
{
unsigned long lflags = GPIO_LOOKUP_FLAGS_DEFAULT;
struct gpio_desc *desc = ERR_PTR(-ENODEV);
int ret;
struct gpio_desc *desc = ERR_PTR(-ENOENT);
if (is_of_node(fwnode)) {
desc = gpiod_get_from_of_node(to_of_node(fwnode),
propname, index,
dflags,
label);
return desc;
dev_dbg(consumer, "using DT '%pfw' for '%s' GPIO lookup\n",
fwnode, con_id);
desc = of_find_gpio(to_of_node(fwnode), con_id, idx, lookupflags);
} else if (is_acpi_node(fwnode)) {
struct acpi_gpio_info info;
dev_dbg(consumer, "using ACPI '%pfw' for '%s' GPIO lookup\n",
fwnode, con_id);
desc = acpi_find_gpio(fwnode, con_id, idx, flags, lookupflags);
} else if (is_software_node(fwnode)) {
dev_dbg(consumer, "using swnode '%pfw' for '%s' GPIO lookup\n",
fwnode, con_id);
desc = swnode_find_gpio(fwnode, con_id, idx, lookupflags);
}
desc = acpi_node_get_gpiod(fwnode, propname, index, &info);
if (IS_ERR(desc))
return desc;
return desc;
}
acpi_gpio_update_gpiod_flags(&dflags, &info);
acpi_gpio_update_gpiod_lookup_flags(&lflags, &info);
} else {
return ERR_PTR(-EINVAL);
static struct gpio_desc *gpiod_find_and_request(struct device *consumer,
struct fwnode_handle *fwnode,
const char *con_id,
unsigned int idx,
enum gpiod_flags flags,
const char *label,
bool platform_lookup_allowed)
{
struct gpio_desc *desc = ERR_PTR(-ENOENT);
unsigned long lookupflags;
int ret;
if (!IS_ERR_OR_NULL(fwnode))
desc = gpiod_find_by_fwnode(fwnode, consumer, con_id, idx,
&flags, &lookupflags);
if (gpiod_not_found(desc) && platform_lookup_allowed) {
/*
* Either we are not using DT or ACPI, or their lookup did not
* return a result. In that case, use platform lookup as a
* fallback.
*/
dev_dbg(consumer, "using lookup tables for GPIO lookup\n");
desc = gpiod_find(consumer, con_id, idx, &lookupflags);
}
/* Currently only ACPI takes this path */
if (IS_ERR(desc)) {
dev_dbg(consumer, "No GPIO consumer %s found\n", con_id);
return desc;
}
/*
* If a connection label was passed use that, else attempt to use
* the device name as label
*/
ret = gpiod_request(desc, label);
if (ret)
return ERR_PTR(ret);
if (ret) {
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(consumer,
"nonexclusive access to GPIO for %s\n", con_id);
return desc;
}
ret = gpiod_configure_flags(desc, propname, lflags, dflags);
ret = gpiod_configure_flags(desc, con_id, lookupflags, flags);
if (ret < 0) {
dev_dbg(consumer, "setup of GPIO %s failed\n", con_id);
gpiod_put(desc);
return ERR_PTR(ret);
}
......@@ -3896,29 +3985,12 @@ static struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
* In case of error an ERR_PTR() is returned.
*/
struct gpio_desc *fwnode_gpiod_get_index(struct fwnode_handle *fwnode,
const char *con_id, int index,
const char *con_id,
int index,
enum gpiod_flags flags,
const char *label)
{
struct gpio_desc *desc;
char prop_name[32]; /* 32 is max size of property name */
unsigned int i;
for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
if (con_id)
snprintf(prop_name, sizeof(prop_name), "%s-%s",
con_id, gpio_suffixes[i]);
else
snprintf(prop_name, sizeof(prop_name), "%s",
gpio_suffixes[i]);
desc = fwnode_get_named_gpiod(fwnode, prop_name, index, flags,
label);
if (!gpiod_not_found(desc))
break;
}
return desc;
return gpiod_find_and_request(NULL, fwnode, con_id, index, flags, label, false);
}
EXPORT_SYMBOL_GPL(fwnode_gpiod_get_index);
......@@ -3937,6 +4009,8 @@ int gpiod_count(struct device *dev, const char *con_id)
count = of_gpio_get_count(dev, con_id);
else if (is_acpi_node(fwnode))
count = acpi_gpio_count(dev, con_id);
else if (is_software_node(fwnode))
count = swnode_gpio_count(fwnode, con_id);
if (count < 0)
count = platform_gpio_count(dev, con_id);
......@@ -4072,70 +4146,11 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
unsigned int idx,
enum gpiod_flags flags)
{
unsigned long lookupflags = GPIO_LOOKUP_FLAGS_DEFAULT;
struct gpio_desc *desc = NULL;
int ret;
/* Maybe we have a device name, maybe not */
struct fwnode_handle *fwnode = dev ? dev_fwnode(dev) : NULL;
const char *devname = dev ? dev_name(dev) : "?";
const struct fwnode_handle *fwnode = dev ? dev_fwnode(dev) : NULL;
dev_dbg(dev, "GPIO lookup for consumer %s\n", con_id);
/* Using device tree? */
if (is_of_node(fwnode)) {
dev_dbg(dev, "using device tree for GPIO lookup\n");
desc = of_find_gpio(dev, con_id, idx, &lookupflags);
} else if (is_acpi_node(fwnode)) {
dev_dbg(dev, "using ACPI for GPIO lookup\n");
desc = acpi_find_gpio(dev, con_id, idx, &flags, &lookupflags);
}
/*
* Either we are not using DT or ACPI, or their lookup did not return
* a result. In that case, use platform lookup as a fallback.
*/
if (!desc || gpiod_not_found(desc)) {
dev_dbg(dev, "using lookup tables for GPIO lookup\n");
desc = gpiod_find(dev, con_id, idx, &lookupflags);
}
if (IS_ERR(desc)) {
dev_dbg(dev, "No GPIO consumer %s found\n", con_id);
return desc;
}
/*
* If a connection label was passed use that, else attempt to use
* the device name as label
*/
ret = gpiod_request(desc, con_id ?: devname);
if (ret) {
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);
if (ret < 0) {
dev_dbg(dev, "setup of GPIO %s failed\n", con_id);
gpiod_put(desc);
return ERR_PTR(ret);
}
const char *label = con_id ?: devname;
blocking_notifier_call_chain(&desc->gdev->notifier,
GPIOLINE_CHANGED_REQUESTED, desc);
return desc;
return gpiod_find_and_request(dev, fwnode, con_id, idx, flags, label, true);
}
EXPORT_SYMBOL_GPL(gpiod_get_index);
......
......@@ -15,14 +15,15 @@
#include <linux/device.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/rwsem.h>
#define GPIOCHIP_NAME "gpiochip"
/**
* struct gpio_device - internal state container for GPIO devices
* @id: numerical ID number for the GPIO chip
* @dev: the GPIO device struct
* @chrdev: character device for the GPIO device
* @id: numerical ID number for the GPIO chip
* @mockdev: class device used by the deprecated sysfs interface (may be
* NULL)
* @owner: helps prevent removal of modules exporting active GPIOs
......@@ -39,6 +40,9 @@
* @list: links gpio_device:s together for traversal
* @notifier: used to notify subscribers about lines being requested, released
* or reconfigured
* @sem: protects the structure from a NULL-pointer dereference of @chip by
* user-space operations when the device gets unregistered during
* a hot-unplug event
* @pin_ranges: range of pins served by the GPIO driver
*
* This state container holds most of the runtime variable data
......@@ -47,9 +51,9 @@
* userspace.
*/
struct gpio_device {
int id;
struct device dev;
struct cdev chrdev;
int id;
struct device *mockdev;
struct module *owner;
struct gpio_chip *chip;
......@@ -60,6 +64,7 @@ struct gpio_device {
void *data;
struct list_head list;
struct blocking_notifier_head notifier;
struct rw_semaphore sem;
#ifdef CONFIG_PINCTRL
/*
......@@ -72,6 +77,11 @@ struct gpio_device {
#endif
};
static inline struct gpio_device *to_gpio_device(struct device *dev)
{
return container_of(dev, struct gpio_device, dev);
}
/* gpio suffixes used for ACPI and device tree lookup */
static __maybe_unused const char * const gpio_suffixes[] = { "gpios", "gpio" };
......
......@@ -635,9 +635,8 @@ __sso_led_dt_parse(struct sso_led_priv *priv, struct fwnode_handle *fw_ssoled)
led->priv = priv;
desc = &led->desc;
led->gpiod = devm_fwnode_get_gpiod_from_child(dev, NULL,
fwnode_child,
GPIOD_ASIS, NULL);
led->gpiod = devm_fwnode_gpiod_get(dev, fwnode_child, NULL,
GPIOD_ASIS, NULL);
if (IS_ERR(led->gpiod)) {
ret = dev_err_probe(dev, PTR_ERR(led->gpiod), "led: get gpio fail!\n");
goto __dt_err;
......
......@@ -151,9 +151,8 @@ static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev)
* will be updated after LED class device is registered,
* Only then the final LED name is known.
*/
led.gpiod = devm_fwnode_get_gpiod_from_child(dev, NULL, child,
GPIOD_ASIS,
NULL);
led.gpiod = devm_fwnode_gpiod_get(dev, child, NULL, GPIOD_ASIS,
NULL);
if (IS_ERR(led.gpiod)) {
fwnode_handle_put(child);
return ERR_CAST(led.gpiod);
......
......@@ -11,40 +11,18 @@
#include <linux/gpio/driver.h>
#include <linux/gpio/consumer.h>
/* Platforms may implement their GPIO interface with library code,
/*
* Platforms may implement their GPIO interface with library code,
* at a small performance cost for non-inlined operations and some
* extra memory (for code and for per-GPIO table entries).
*
* While the GPIO programming interface defines valid GPIO numbers
* to be in the range 0..MAX_INT, this library restricts them to the
* smaller range 0..ARCH_NR_GPIOS-1.
*
* ARCH_NR_GPIOS is somewhat arbitrary; it usually reflects the sum of
* builtin/SoC GPIOs plus a number of GPIOs on expanders; the latter is
* actually an estimate of a board-specific value.
*/
#ifndef ARCH_NR_GPIOS
#if defined(CONFIG_ARCH_NR_GPIO) && CONFIG_ARCH_NR_GPIO > 0
#define ARCH_NR_GPIOS CONFIG_ARCH_NR_GPIO
#else
#define ARCH_NR_GPIOS 512
#endif
#endif
/*
* "valid" GPIO numbers are nonnegative and may be passed to
* setup routines like gpio_request(). only some valid numbers
* can successfully be requested and used.
*
* Invalid GPIO numbers are useful for indicating no-such-GPIO in
* platform data and other tables.
* At the end we want all GPIOs to be dynamically allocated from 0.
* However, some legacy drivers still perform fixed allocation.
* Until they are all fixed, leave 0-512 space for them.
*/
static inline bool gpio_is_valid(int number)
{
return number >= 0 && number < ARCH_NR_GPIOS;
}
#define GPIO_DYNAMIC_BASE 512
struct device;
struct gpio;
......@@ -140,12 +118,6 @@ static inline void gpio_unexport(unsigned gpio)
#include <linux/kernel.h>
static inline bool gpio_is_valid(int number)
{
/* only non-negative numbers are valid */
return number >= 0;
}
/* platforms that don't directly support access to GPIOs through I2C, SPI,
* or other blocking infrastructure can use these wrappers.
*/
......@@ -169,4 +141,19 @@ static inline void gpio_set_value_cansleep(unsigned gpio, int value)
#endif /* !CONFIG_GPIOLIB */
/*
* "valid" GPIO numbers are nonnegative and may be passed to
* setup routines like gpio_request(). only some valid numbers
* can successfully be requested and used.
*
* Invalid GPIO numbers are useful for indicating no-such-GPIO in
* platform data and other tables.
*/
static inline bool gpio_is_valid(int number)
{
/* only non-negative numbers are valid */
return number >= 0;
}
#endif /* _ASM_GENERIC_GPIO_H */
......@@ -581,27 +581,6 @@ struct gpio_desc *devm_fwnode_gpiod_get(struct device *dev,
flags, label);
}
static inline
struct gpio_desc *devm_fwnode_get_index_gpiod_from_child(struct device *dev,
const char *con_id, int index,
struct fwnode_handle *child,
enum gpiod_flags flags,
const char *label)
{
return devm_fwnode_gpiod_get_index(dev, child, con_id, index,
flags, label);
}
static inline
struct gpio_desc *devm_fwnode_get_gpiod_from_child(struct device *dev,
const char *con_id,
struct fwnode_handle *child,
enum gpiod_flags flags,
const char *label)
{
return devm_fwnode_gpiod_get_index(dev, child, con_id, 0, flags, label);
}
#if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_OF_GPIO)
struct device_node;
......
// SPDX-License-Identifier: GPL-2.0+
#ifndef __LINUX_GPIO_PROPERTY_H
#define __LINUX_GPIO_PROPERTY_H
#include <dt-bindings/gpio/gpio.h> /* for GPIO_* flags */
#include <linux/property.h>
#define PROPERTY_ENTRY_GPIO(_name_, _chip_node_, _idx_, _flags_) \
PROPERTY_ENTRY_REF(_name_, _chip_node_, _idx_, _flags_)
#endif /* __LINUX_GPIO_PROPERTY_H */
......@@ -34,7 +34,7 @@ enum of_gpio_flags {
#ifdef CONFIG_OF_GPIO
#include <linux/kernel.h>
#include <linux/container_of.h>
/*
* OF GPIO chip for memory mapped banks
......
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