Commit 24dc8363 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'gpio-v4.21-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio

Pull GPIO updates from Linus Walleij:
 "This is the bulk of GPIO changes for the v4.21 kernel series.

  Core changes:

   - Some core changes are already in outside of this pull request as
     they came through the regulator tree, most notably
     devm_gpiod_unhinge() that removes devres refcount management from a
     GPIO descriptor. This is needed in subsystems such as regulators
     where the regulator core need to take over the reference counting
     and lifecycle management for a GPIO descriptor.

   - We dropped devm_gpiochip_remove() and devm_gpio_chip_match() as
     nothing needs it. We can bring it back if need be.

   - Add a global TODO so people see where we are going. This helps
     setting the direction now that we are two GPIO maintainers.

   - Handle the MMC CD/WP properties in the device tree core. (The bulk
     of patches activating this code is already merged through the
     MMC/SD tree.)

   - Augment gpiochip_request_own_desc() to pass a flag so we as
     gpiochips can request lines as active low or open drain etc even
     from ourselves.

  New drivers:

   - New driver for Cadence GPIO blocks.

   - New driver for Atmel SAMA5D2 PIOBU GPIO lines.

  Driver improvements:

   - A major refactoring of the PCA953x driver - this driver has been
     around for ages, and is now modernized to reduce code duplication
     that has stacked up and is using regmap to read write and cache
     registers.

   - Intel drivers are now maintained in a separate tree and start with
     a round of cleanups and unifications"

* tag 'gpio-v4.21-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (99 commits)
  gpio: sama5d2-piobu: Depend on OF_GPIO
  gpio: Add Cadence GPIO driver
  dt-bindings: gpio: Add bindings for Cadence GPIO
  gpiolib-acpi: remove unused variable 'err', cleans up build warning
  gpio: mxs: read pin level directly instead of using .get
  gpio: aspeed: remove duplicated statement
  gpio: add driver for SAMA5D2 PIOBU pins
  dt-bindings: arm: atmel: describe SECUMOD usage as a GPIO controller
  gpio/mmc/of: Respect polarity in the device tree
  dt-bindings: gpio: rcar: Add r8a774c0 (RZ/G2E) support
  memory: omap-gpmc: Get the header of the enum
  ARM: omap1: Fix new user of gpiochip_request_own_desc()
  gpio: pca953x: Add regmap dependency for PCA953x driver
  gpio: raspberrypi-exp: decrease refcount on firmware dt node
  gpiolib: Fix return value of gpio_to_desc() stub if !GPIOLIB
  gpio: pca953x: Restore registers after suspend/resume cycle
  gpio: pca953x: Zap single use of pca953x_read_single()
  gpio: pca953x: Zap ad-hoc reg_output cache
  gpio: pca953x: Zap ad-hoc reg_direction cache
  gpio: pca953x: Perform basic regmap conversion
  ...
parents 7e59fad9 a7c23f8d
......@@ -158,14 +158,24 @@ Security Module (SECUMOD)
The Security Module macrocell provides all necessary secure functions to avoid
voltage, temperature, frequency and mechanical attacks on the chip. It also
embeds secure memories that can be scrambled
embeds secure memories that can be scrambled.
The Security Module also offers the PIOBU pins which can be used as GPIO pins.
Note that they maintain their voltage during Backup/Self-refresh.
required properties:
- compatible: Should be "atmel,<chip>-secumod", "syscon".
<chip> can be "sama5d2".
- reg: Should contain registers location and length
- gpio-controller: Marks the port as GPIO controller.
- #gpio-cells: There are 2. The pin number is the
first, the second represents additional
parameters such as GPIO_ACTIVE_HIGH/LOW.
secumod@fc040000 {
compatible = "atmel,sama5d2-secumod", "syscon";
reg = <0xfc040000 0x100>;
gpio-controller;
#gpio-cells = <2>;
};
Cadence GPIO controller bindings
Required properties:
- compatible: should be "cdns,gpio-r1p02".
- reg: the register base address and size.
- #gpio-cells: should be 2.
* first cell is the GPIO number.
* second cell specifies the GPIO flags, as defined in
<dt-bindings/gpio/gpio.h>. Only the GPIO_ACTIVE_HIGH
and GPIO_ACTIVE_LOW flags are supported.
- gpio-controller: marks the device as a GPIO controller.
- clocks: should contain one entry referencing the peripheral clock driving
the GPIO controller.
Optional properties:
- ngpios: integer number of gpio lines supported by this controller, up to 32.
- interrupts: interrupt specifier for the controllers interrupt.
- interrupt-controller: marks the device as an interrupt controller. When
defined, interrupts, interrupt-parent and #interrupt-cells
are required.
- interrupt-cells: should be 2.
* first cell is the GPIO number you want to use as an IRQ source.
* second cell specifies the IRQ type, as defined in
<dt-bindings/interrupt-controller/irq.h>.
Currently only level sensitive IRQs are supported.
Example:
gpio0: gpio-controller@fd060000 {
compatible = "cdns,gpio-r1p02";
reg =<0xfd060000 0x1000>;
clocks = <&gpio_clk>;
interrupt-parent = <&gic>;
interrupts = <0 5 IRQ_TYPE_LEVEL_HIGH>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
};
......@@ -24,6 +24,12 @@ Required properties for GPIO node:
4 = active high level-sensitive.
8 = active low level-sensitive.
Optional properties:
-clocks: Must contain an entry for each entry in clock-names.
See common clock-bindings.txt for details.
-clock-names: A list of clock names. For imx7ulp, it must contain
"gpio", "port".
Note: Each GPIO port should have an alias correctly numbered in "aliases"
node.
......
......@@ -3,12 +3,24 @@ NXP LPC18xx/43xx GPIO controller Device Tree Bindings
Required properties:
- compatible : Should be "nxp,lpc1850-gpio"
- reg : Address and length of the register set for the device
- clocks : Clock specifier (see clock bindings for details)
- gpio-controller : Marks the device node as a GPIO controller.
- #gpio-cells : Should be two
- First cell is the GPIO line number
- Second cell is used to specify polarity
- reg : List of addresses and lengths of the GPIO controller
register sets
- reg-names : Should be "gpio", "gpio-pin-ic", "gpio-group0-ic" and
"gpio-gpoup1-ic"
- clocks : Phandle and clock specifier pair for GPIO controller
- resets : Phandle and reset specifier pair for GPIO controller
- gpio-controller : Marks the device node as a GPIO controller
- #gpio-cells : Should be two:
- The first cell is the GPIO line number
- The second cell is used to specify polarity
- interrupt-controller : Marks the device node as an interrupt controller
- #interrupt-cells : Should be two:
- The first cell is an interrupt number within
0..9 range, for GPIO pin interrupts it is equal
to 'nxp,gpio-pin-interrupt' property value of
GPIO pin configuration, 8 is for GPIO GROUP0
interrupt, 9 is for GPIO GROUP1 interrupt
- The second cell is used to specify interrupt type
Optional properties:
- gpio-ranges : Mapping between GPIO and pinctrl
......@@ -19,21 +31,29 @@ Example:
gpio: gpio@400f4000 {
compatible = "nxp,lpc1850-gpio";
reg = <0x400f4000 0x4000>;
reg = <0x400f4000 0x4000>, <0x40087000 0x1000>,
<0x40088000 0x1000>, <0x40089000 0x1000>;
reg-names = "gpio", "gpio-pin-ic",
"gpio-group0-ic", "gpio-gpoup1-ic";
clocks = <&ccu1 CLK_CPU_GPIO>;
resets = <&rgu 28>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
gpio-ranges = <&pinctrl LPC_GPIO(0,0) LPC_PIN(0,0) 2>,
...
<&pinctrl LPC_GPIO(7,19) LPC_PIN(f,5) 7>;
};
gpio_joystick {
compatible = "gpio-keys-polled";
compatible = "gpio-keys";
...
button@0 {
button0 {
...
interrupt-parent = <&gpio>;
interrupts = <1 IRQ_TYPE_EDGE_BOTH>;
gpios = <&gpio LPC_GPIO(4,8) GPIO_ACTIVE_LOW>;
};
};
......@@ -8,6 +8,7 @@ Required Properties:
- "renesas,gpio-r8a7745": for R8A7745 (RZ/G1E) compatible GPIO controller.
- "renesas,gpio-r8a77470": for R8A77470 (RZ/G1C) compatible GPIO controller.
- "renesas,gpio-r8a774a1": for R8A774A1 (RZ/G2M) compatible GPIO controller.
- "renesas,gpio-r8a774c0": for R8A774C0 (RZ/G2E) compatible GPIO controller.
- "renesas,gpio-r8a7778": for R8A7778 (R-Car M1) compatible GPIO controller.
- "renesas,gpio-r8a7779": for R8A7779 (R-Car H1) compatible GPIO controller.
- "renesas,gpio-r8a7790": for R8A7790 (R-Car H2) compatible GPIO controller.
......
......@@ -43,7 +43,7 @@ gpio: gpio@20000 {
#address-cells = <1>;
#size-cells = <0>;
porta: gpio-controller@0 {
porta: gpio@0 {
compatible = "snps,dw-apb-gpio-port";
gpio-controller;
#gpio-cells = <2>;
......@@ -55,7 +55,7 @@ gpio: gpio@20000 {
interrupts = <0>;
};
portb: gpio-controller@1 {
portb: gpio@1 {
compatible = "snps,dw-apb-gpio-port";
gpio-controller;
#gpio-cells = <2>;
......
......@@ -434,7 +434,9 @@ try_module_get()). A GPIO driver can use the following functions instead
to request and free descriptors without being pinned to the kernel forever::
struct gpio_desc *gpiochip_request_own_desc(struct gpio_desc *desc,
const char *label)
u16 hwnum,
const char *label,
enum gpiod_flags flags)
void gpiochip_free_own_desc(struct gpio_desc *desc)
......
......@@ -256,7 +256,6 @@ GPIO
devm_gpiod_put()
devm_gpiod_unhinge()
devm_gpiochip_add_data()
devm_gpiochip_remove()
devm_gpio_request()
devm_gpio_request_one()
devm_gpio_free()
......
......@@ -6412,7 +6412,6 @@ F: drivers/media/rc/gpio-ir-tx.c
GPIO MOCKUP DRIVER
M: Bamvor Jian Zhang <bamv2005@gmail.com>
R: Bartosz Golaszewski <brgl@bgdev.pl>
L: linux-gpio@vger.kernel.org
S: Maintained
F: drivers/gpio/gpio-mockup.c
......@@ -9933,6 +9932,12 @@ M: Nicolas Ferre <nicolas.ferre@microchip.com>
S: Supported
F: drivers/power/reset/at91-sama5d2_shdwc.c
MICROCHIP SAMA5D2-COMPATIBLE PIOBU GPIO
M: Andrei Stefanescu <andrei.stefanescu@microchip.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
L: linux-gpio@vger.kernel.org
F: drivers/gpio/gpio-sama5d2-piobu.c
MICROCHIP SPI DRIVER
M: Nicolas Ferre <nicolas.ferre@microchip.com>
S: Supported
......
......@@ -103,7 +103,7 @@ void __init ams_delta_init_fiq(struct gpio_chip *chip,
}
for (i = 0; i < ARRAY_SIZE(irq_data); i++) {
gpiod = gpiochip_request_own_desc(chip, i, pin_name[i]);
gpiod = gpiochip_request_own_desc(chip, i, pin_name[i], 0);
if (IS_ERR(gpiod)) {
pr_err("%s: failed to get GPIO pin %d (%ld)\n",
__func__, i, PTR_ERR(gpiod));
......
......@@ -601,7 +601,7 @@ static void __init modem_assign_irq(struct gpio_chip *chip)
struct gpio_desc *gpiod;
gpiod = gpiochip_request_own_desc(chip, AMS_DELTA_GPIO_PIN_MODEM_IRQ,
"modem_irq");
"modem_irq", 0);
if (IS_ERR(gpiod)) {
pr_err("%s: modem IRQ GPIO request failed (%ld)\n", __func__,
PTR_ERR(gpiod));
......@@ -809,7 +809,7 @@ static void __init ams_delta_led_init(struct gpio_chip *chip)
int i;
for (i = LATCH1_PIN_LED_CAMERA; i < LATCH1_PIN_DOCKIT1; i++) {
gpiod = gpiochip_request_own_desc(chip, i, NULL);
gpiod = gpiochip_request_own_desc(chip, i, "camera-led", 0);
if (IS_ERR(gpiod)) {
pr_warn("%s: %s GPIO %d request failed (%ld)\n",
__func__, LATCH1_LABEL, i, PTR_ERR(gpiod));
......
......@@ -160,6 +160,14 @@ config GPIO_BRCMSTB
help
Say yes here to enable GPIO support for Broadcom STB (BCM7XXX) SoCs.
config GPIO_CADENCE
tristate "Cadence GPIO support"
depends on OF_GPIO
select GPIO_GENERIC
select GPIOLIB_IRQCHIP
help
Say yes here to enable support for Cadence GPIO controller.
config GPIO_CLPS711X
tristate "CLPS711X GPIO support"
depends on ARCH_CLPS711X || COMPILE_TEST
......@@ -288,6 +296,7 @@ config GPIO_LPC18XX
tristate "NXP LPC18XX/43XX GPIO support"
default y if ARCH_LPC18XX
depends on OF_GPIO && (ARCH_LPC18XX || COMPILE_TEST)
select IRQ_DOMAIN_HIERARCHY
help
Select this option to enable GPIO driver for
NXP LPC18XX/43XX devices.
......@@ -429,6 +438,18 @@ config GPIO_REG
A 32-bit single register GPIO fixed in/out implementation. This
can be used to represent any register as a set of GPIO signals.
config GPIO_SAMA5D2_PIOBU
tristate "SAMA5D2 PIOBU GPIO support"
depends on MFD_SYSCON
depends on OF_GPIO
select GPIO_SYSCON
help
Say yes here to use the PIOBU pins as GPIOs.
PIOBU pins on the SAMA5D2 can be used as GPIOs.
The difference from regular GPIOs is that they
maintain their value during backup/self-refresh.
config GPIO_SIOX
tristate "SIOX GPIO support"
depends on SIOX
......@@ -849,6 +870,7 @@ config GPIO_MC9S08DZ60
config GPIO_PCA953X
tristate "PCA95[357]x, PCA9698, TCA64xx, and MAX7310 I/O ports"
select REGMAP_I2C
help
Say yes here to provide access to several register-oriented
SMBus I/O expanders, made mostly by NXP or TI. Compatible
......
......@@ -37,6 +37,7 @@ obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o
obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o
obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o
obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o
obj-$(CONFIG_GPIO_CADENCE) += gpio-cadence.o
obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o
obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o
obj-$(CONFIG_GPIO_CRYSTAL_COVE) += gpio-crystalcove.o
......@@ -108,6 +109,7 @@ obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o
obj-$(CONFIG_GPIO_RCAR) += gpio-rcar.o
obj-$(CONFIG_GPIO_REG) += gpio-reg.o
obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o
obj-$(CONFIG_GPIO_SAMA5D2_PIOBU) += gpio-sama5d2-piobu.o
obj-$(CONFIG_GPIO_SCH) += gpio-sch.o
obj-$(CONFIG_GPIO_SCH311X) += gpio-sch311x.o
obj-$(CONFIG_GPIO_SNPS_CREG) += gpio-creg-snps.o
......
This is a place for planning the ongoing long-term work in the GPIO
subsystem.
GPIO descriptors
Starting with commit 79a9becda894 the GPIO subsystem embarked on a journey
to move away from the global GPIO numberspace and toward a decriptor-based
approach. This means that GPIO consumers, drivers and machine descriptions
ideally have no use or idea of the global GPIO numberspace that has/was
used in the inception of the GPIO subsystem.
Work items:
- Convert all GPIO device drivers to only #include <linux/gpio/driver.h>
- Convert all consumer drivers to only #include <linux/gpio/consumer.h>
- Convert all machine descriptors in "boardfiles" to only
#include <linux/gpio/machine.h>, the other option being to convert it
to a machine description such as device tree, ACPI or fwnode that
implicitly does not use global GPIO numbers.
- When this work is complete (will require some of the items in the
following ongoing work as well) we can delete the old global
numberspace accessors from <linux/gpio.h> and eventually delete
<linux/gpio.h> altogether.
Get rid of <linux/of_gpio.h>
This header and helpers appeared at one point when there was no proper
driver infrastructure for doing simpler MMIO GPIO devices and there was
no core support for parsing device tree GPIOs from the core library with
the [devm_]gpiod_get() calls we have today that will implicitly go into
the device tree back-end.
Work items:
- Get rid of struct of_mm_gpio_chip altogether: use the generic MMIO
GPIO for all current users (see below). Delete struct of_mm_gpio_chip,
to_of_mm_gpio_chip(), of_mm_gpiochip_add_data(), of_mm_gpiochip_add()
of_mm_gpiochip_remove() from the kernel.
- Change all consumer drivers that #include <linux/of_gpio.h> to
#include <linux/gpio/consumer.h> and stop doing custom parsing of the
GPIO lines from the device tree. This can be tricky and often ivolves
changing boardfiles, etc.
- Pull semantics for legacy device tree (OF) GPIO lookups into
gpiolib-of.c: in some cases subsystems are doing custom flags and
lookups for polarity inversion, open drain and what not. As we now
handle this with generic OF bindings, pull all legacy handling into
gpiolib so the library API becomes narrow and deep and handle all
legacy bindings internally. (See e.g. commits 6953c57ab172,
6a537d48461d etc)
- Delete <linux/of_gpio.h> when all the above is complete and everything
uses <linux/gpio/consumer.h> or <linux/gpio/driver.h> instead.
Collect drivers
Collect GPIO drivers from arch/* and other places that should be placed
in drivers/gpio/gpio-*. Augment platforms to create platform devices or
similar and probe a proper driver in the gpiolib subsystem.
In some cases it makes sense to create a GPIO chip from the local driver
for a few GPIOs. Those should stay where they are.
Generic MMIO GPIO
The GPIO drivers can utilize the generic MMIO helper library in many
cases, and the helper library should be as helpful as possible for MMIO
drivers. (drivers/gpio/gpio-mmio.c)
Work items:
- Look over and identify any remaining easily converted drivers and
dry-code conversions to MMIO GPIO for maintainers to test
- Expand the MMIO GPIO or write a new library for port-mapped I/O
helpers (x86 inb()/outb()) and convert port-mapped I/O drivers to use
this with dry-coding and sending to maintainers to test
GPIOLIB irqchip
The GPIOLIB irqchip is a helper irqchip for "simple cases" that should
try to cover any generic kind of irqchip cascaded from a GPIO.
- Look over and identify any remaining easily converted drivers and
dry-code conversions to gpiolib irqchip for maintainers to test
- Support generic hierarchical GPIO interrupts: these are for the
non-cascading case where there is one IRQ per GPIO line, there is
currently no common infrastructure for this.
Increase integration with pin control
There are already ways to use pin control as back-end for GPIO and
it may make sense to bring these subsystems closer. One reason for
creating pin control as its own subsystem was that we could avoid any
use of the global GPIO numbers. Once the above is complete, it may
make sense to simply join the subsystems into one and make pin
multiplexing, pin configuration, GPIO, etc selectable options in one
and the same pin control and GPIO subsystem.
......@@ -222,7 +222,7 @@ static int dio48e_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
port_state = inb(dio48egpio->base + ports[i]);
/* store acquired bits at respective bits array offset */
bits[word_index] |= port_state << word_offset;
bits[word_index] |= (port_state << word_offset) & word_mask;
}
return 0;
......
......@@ -128,7 +128,7 @@ static int idi_48_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
port_state = inb(idi48gpio->base + ports[i]);
/* store acquired bits at respective bits array offset */
bits[word_index] |= port_state << word_offset;
bits[word_index] |= (port_state << word_offset) & word_mask;
}
return 0;
......
......@@ -1185,7 +1185,6 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
gpio->chip.parent = &pdev->dev;
gpio->chip.ngpio = gpio->config->nr_gpios;
gpio->chip.parent = &pdev->dev;
gpio->chip.direction_input = aspeed_gpio_dir_in;
gpio->chip.direction_output = aspeed_gpio_dir_out;
gpio->chip.get_direction = aspeed_gpio_get_direction;
......
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2017-2018 Cadence
*
* Authors:
* Jan Kotas <jank@cadence.com>
* Boris Brezillon <boris.brezillon@free-electrons.com>
*/
#include <linux/gpio/driver.h>
#include <linux/clk.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
#define CDNS_GPIO_BYPASS_MODE 0x00
#define CDNS_GPIO_DIRECTION_MODE 0x04
#define CDNS_GPIO_OUTPUT_EN 0x08
#define CDNS_GPIO_OUTPUT_VALUE 0x0c
#define CDNS_GPIO_INPUT_VALUE 0x10
#define CDNS_GPIO_IRQ_MASK 0x14
#define CDNS_GPIO_IRQ_EN 0x18
#define CDNS_GPIO_IRQ_DIS 0x1c
#define CDNS_GPIO_IRQ_STATUS 0x20
#define CDNS_GPIO_IRQ_TYPE 0x24
#define CDNS_GPIO_IRQ_VALUE 0x28
#define CDNS_GPIO_IRQ_ANY_EDGE 0x2c
struct cdns_gpio_chip {
struct gpio_chip gc;
struct clk *pclk;
void __iomem *regs;
u32 bypass_orig;
};
static int cdns_gpio_request(struct gpio_chip *chip, unsigned int offset)
{
struct cdns_gpio_chip *cgpio = gpiochip_get_data(chip);
unsigned long flags;
spin_lock_irqsave(&chip->bgpio_lock, flags);
iowrite32(ioread32(cgpio->regs + CDNS_GPIO_BYPASS_MODE) & ~BIT(offset),
cgpio->regs + CDNS_GPIO_BYPASS_MODE);
spin_unlock_irqrestore(&chip->bgpio_lock, flags);
return 0;
}
static void cdns_gpio_free(struct gpio_chip *chip, unsigned int offset)
{
struct cdns_gpio_chip *cgpio = gpiochip_get_data(chip);
unsigned long flags;
spin_lock_irqsave(&chip->bgpio_lock, flags);
iowrite32(ioread32(cgpio->regs + CDNS_GPIO_BYPASS_MODE) |
(BIT(offset) & cgpio->bypass_orig),
cgpio->regs + CDNS_GPIO_BYPASS_MODE);
spin_unlock_irqrestore(&chip->bgpio_lock, flags);
}
static void cdns_gpio_irq_mask(struct irq_data *d)
{
struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
struct cdns_gpio_chip *cgpio = gpiochip_get_data(chip);
iowrite32(BIT(d->hwirq), cgpio->regs + CDNS_GPIO_IRQ_DIS);
}
static void cdns_gpio_irq_unmask(struct irq_data *d)
{
struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
struct cdns_gpio_chip *cgpio = gpiochip_get_data(chip);
iowrite32(BIT(d->hwirq), cgpio->regs + CDNS_GPIO_IRQ_EN);
}
static int cdns_gpio_irq_set_type(struct irq_data *d, unsigned int type)
{
struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
struct cdns_gpio_chip *cgpio = gpiochip_get_data(chip);
unsigned long flags;
u32 int_value;
u32 int_type;
u32 mask = BIT(d->hwirq);
int ret = 0;
spin_lock_irqsave(&chip->bgpio_lock, flags);
int_value = ioread32(cgpio->regs + CDNS_GPIO_IRQ_VALUE) & ~mask;
int_type = ioread32(cgpio->regs + CDNS_GPIO_IRQ_TYPE) & ~mask;
/*
* The GPIO controller doesn't have an ACK register.
* All interrupt statuses are cleared on a status register read.
* Don't support edge interrupts for now.
*/
if (type == IRQ_TYPE_LEVEL_HIGH) {
int_type |= mask;
int_value |= mask;
} else if (type == IRQ_TYPE_LEVEL_LOW) {
int_type |= mask;
} else {
ret = -EINVAL;
goto err_irq_type;
}
iowrite32(int_value, cgpio->regs + CDNS_GPIO_IRQ_VALUE);
iowrite32(int_type, cgpio->regs + CDNS_GPIO_IRQ_TYPE);
err_irq_type:
spin_unlock_irqrestore(&chip->bgpio_lock, flags);
return ret;
}
static void cdns_gpio_irq_handler(struct irq_desc *desc)
{
struct gpio_chip *chip = irq_desc_get_handler_data(desc);
struct cdns_gpio_chip *cgpio = gpiochip_get_data(chip);
struct irq_chip *irqchip = irq_desc_get_chip(desc);
unsigned long status;
int hwirq;
chained_irq_enter(irqchip, desc);
status = ioread32(cgpio->regs + CDNS_GPIO_IRQ_STATUS) &
~ioread32(cgpio->regs + CDNS_GPIO_IRQ_MASK);
for_each_set_bit(hwirq, &status, chip->ngpio)
generic_handle_irq(irq_find_mapping(chip->irq.domain, hwirq));
chained_irq_exit(irqchip, desc);
}
static struct irq_chip cdns_gpio_irqchip = {
.name = "cdns-gpio",
.irq_mask = cdns_gpio_irq_mask,
.irq_unmask = cdns_gpio_irq_unmask,
.irq_set_type = cdns_gpio_irq_set_type
};
static int cdns_gpio_probe(struct platform_device *pdev)
{
struct cdns_gpio_chip *cgpio;
struct resource *res;
int ret, irq;
u32 dir_prev;
u32 num_gpios = 32;
cgpio = devm_kzalloc(&pdev->dev, sizeof(*cgpio), GFP_KERNEL);
if (!cgpio)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
cgpio->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(cgpio->regs))
return PTR_ERR(cgpio->regs);
of_property_read_u32(pdev->dev.of_node, "ngpios", &num_gpios);
if (num_gpios > 32) {
dev_err(&pdev->dev, "ngpios must be less or equal 32\n");
return -EINVAL;
}
/*
* Set all pins as inputs by default, otherwise:
* gpiochip_lock_as_irq:
* tried to flag a GPIO set as output for IRQ
* Generic GPIO driver stores the direction value internally,
* so it needs to be changed before bgpio_init() is called.
*/
dir_prev = ioread32(cgpio->regs + CDNS_GPIO_DIRECTION_MODE);
iowrite32(GENMASK(num_gpios - 1, 0),
cgpio->regs + CDNS_GPIO_DIRECTION_MODE);
ret = bgpio_init(&cgpio->gc, &pdev->dev, 4,
cgpio->regs + CDNS_GPIO_INPUT_VALUE,
cgpio->regs + CDNS_GPIO_OUTPUT_VALUE,
NULL,
NULL,
cgpio->regs + CDNS_GPIO_DIRECTION_MODE,
BGPIOF_READ_OUTPUT_REG_SET);
if (ret) {
dev_err(&pdev->dev, "Failed to register generic gpio, %d\n",
ret);
goto err_revert_dir;
}
cgpio->gc.label = dev_name(&pdev->dev);
cgpio->gc.ngpio = num_gpios;
cgpio->gc.parent = &pdev->dev;
cgpio->gc.base = -1;
cgpio->gc.owner = THIS_MODULE;
cgpio->gc.request = cdns_gpio_request;
cgpio->gc.free = cdns_gpio_free;
cgpio->pclk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(cgpio->pclk)) {
ret = PTR_ERR(cgpio->pclk);
dev_err(&pdev->dev,
"Failed to retrieve peripheral clock, %d\n", ret);
goto err_revert_dir;
}
ret = clk_prepare_enable(cgpio->pclk);
if (ret) {
dev_err(&pdev->dev,
"Failed to enable the peripheral clock, %d\n", ret);
goto err_revert_dir;
}
ret = devm_gpiochip_add_data(&pdev->dev, &cgpio->gc, cgpio);
if (ret < 0) {
dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
goto err_disable_clk;
}
/*
* irq_chip support
*/
irq = platform_get_irq(pdev, 0);
if (irq >= 0) {
ret = gpiochip_irqchip_add(&cgpio->gc, &cdns_gpio_irqchip,
0, handle_level_irq,
IRQ_TYPE_NONE);
if (ret) {
dev_err(&pdev->dev, "Could not add irqchip, %d\n",
ret);
goto err_disable_clk;
}
gpiochip_set_chained_irqchip(&cgpio->gc, &cdns_gpio_irqchip,
irq, cdns_gpio_irq_handler);
}
cgpio->bypass_orig = ioread32(cgpio->regs + CDNS_GPIO_BYPASS_MODE);
/*
* Enable gpio outputs, ignored for input direction
*/
iowrite32(GENMASK(num_gpios - 1, 0),
cgpio->regs + CDNS_GPIO_OUTPUT_EN);
iowrite32(0, cgpio->regs + CDNS_GPIO_BYPASS_MODE);
platform_set_drvdata(pdev, cgpio);
return 0;
err_disable_clk:
clk_disable_unprepare(cgpio->pclk);
err_revert_dir:
iowrite32(dir_prev, cgpio->regs + CDNS_GPIO_DIRECTION_MODE);
return ret;
}
static int cdns_gpio_remove(struct platform_device *pdev)
{
struct cdns_gpio_chip *cgpio = platform_get_drvdata(pdev);
iowrite32(cgpio->bypass_orig, cgpio->regs + CDNS_GPIO_BYPASS_MODE);
clk_disable_unprepare(cgpio->pclk);
return 0;
}
static const struct of_device_id cdns_of_ids[] = {
{ .compatible = "cdns,gpio-r1p02" },
{ /* sentinel */ },
};
static struct platform_driver cdns_gpio_driver = {
.driver = {
.name = "cdns-gpio",
.of_match_table = cdns_of_ids,
},
.probe = cdns_gpio_probe,
.remove = cdns_gpio_remove,
};
module_platform_driver(cdns_gpio_driver);
MODULE_AUTHOR("Jan Kotas <jank@cadence.com>");
MODULE_DESCRIPTION("Cadence GPIO driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:cdns-gpio");
......@@ -748,8 +748,7 @@ static int dwapb_gpio_remove(struct platform_device *pdev)
#ifdef CONFIG_PM_SLEEP
static int dwapb_gpio_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct dwapb_gpio *gpio = platform_get_drvdata(pdev);
struct dwapb_gpio *gpio = dev_get_drvdata(dev);
struct gpio_chip *gc = &gpio->ports[0].gc;
unsigned long flags;
int i;
......@@ -793,8 +792,7 @@ static int dwapb_gpio_suspend(struct device *dev)
static int dwapb_gpio_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct dwapb_gpio *gpio = platform_get_drvdata(pdev);
struct dwapb_gpio *gpio = dev_get_drvdata(dev);
struct gpio_chip *gc = &gpio->ports[0].gc;
unsigned long flags;
int i;
......
......@@ -211,7 +211,7 @@ static int gpiomm_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
port_state = inb(gpiommgpio->base + ports[i]);
/* store acquired bits at respective bits array offset */
bits[word_index] |= port_state << word_offset;
bits[word_index] |= (port_state << word_offset) & word_mask;
}
return 0;
......
......@@ -30,7 +30,6 @@
#include <linux/gpio/driver.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/gpio/driver.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
......
// SPDX-License-Identifier: GPL-2.0+
/*
* Intel ICH6-10, Series 5 and 6, Atom C2000 (Avoton/Rangeley) GPIO driver
*
* Copyright (C) 2010 Extreme Engineering Solutions.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/bitops.h>
#include <linux/gpio/driver.h>
#include <linux/ioport.h>
#include <linux/mfd/lpc_ich.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/gpio/driver.h>
#include <linux/platform_device.h>
#include <linux/mfd/lpc_ich.h>
#include <linux/bitops.h>
#define DRV_NAME "gpio_ich"
......@@ -100,7 +86,7 @@ struct ichx_desc {
static struct {
spinlock_t lock;
struct platform_device *dev;
struct device *dev;
struct gpio_chip chip;
struct resource *gpio_base; /* GPIO IO base */
struct resource *pm_base; /* Power Mangagment IO base */
......@@ -112,8 +98,7 @@ static struct {
static int modparam_gpiobase = -1; /* dynamic */
module_param_named(gpiobase, modparam_gpiobase, int, 0444);
MODULE_PARM_DESC(gpiobase, "The GPIO number base. -1 means dynamic, "
"which is the default.");
MODULE_PARM_DESC(gpiobase, "The GPIO number base. -1 means dynamic, which is the default.");
static int ichx_write_bit(int reg, unsigned nr, int val, int verify)
{
......@@ -121,7 +106,6 @@ static int ichx_write_bit(int reg, unsigned nr, int val, int verify)
u32 data, tmp;
int reg_nr = nr / 32;
int bit = nr & 0x1f;
int ret = 0;
spin_lock_irqsave(&ichx_priv.lock, flags);
......@@ -142,12 +126,10 @@ static int ichx_write_bit(int reg, unsigned nr, int val, int verify)
tmp = ICHX_READ(ichx_priv.desc->regs[reg][reg_nr],
ichx_priv.gpio_base);
if (verify && data != tmp)
ret = -EPERM;
spin_unlock_irqrestore(&ichx_priv.lock, flags);
return ret;
return (verify && data != tmp) ? -EPERM : 0;
}
static int ichx_read_bit(int reg, unsigned nr)
......@@ -186,10 +168,7 @@ static int ichx_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
* Try setting pin as an input and verify it worked since many pins
* are output-only.
*/
if (ichx_write_bit(GPIO_IO_SEL, nr, 1, 1))
return -EINVAL;
return 0;
return ichx_write_bit(GPIO_IO_SEL, nr, 1, 1);
}
static int ichx_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
......@@ -206,10 +185,7 @@ static int ichx_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
* Try setting pin as an output and verify it worked since many pins
* are input-only.
*/
if (ichx_write_bit(GPIO_IO_SEL, nr, 0, 1))
return -EINVAL;
return 0;
return ichx_write_bit(GPIO_IO_SEL, nr, 0, 1);
}
static int ichx_gpio_get(struct gpio_chip *chip, unsigned nr)
......@@ -284,7 +260,7 @@ static void ichx_gpiolib_setup(struct gpio_chip *chip)
{
chip->owner = THIS_MODULE;
chip->label = DRV_NAME;
chip->parent = &ichx_priv.dev->dev;
chip->parent = ichx_priv.dev;
/* Allow chip-specific overrides of request()/get() */
chip->request = ichx_priv.desc->request ?
......@@ -407,15 +383,14 @@ static int ichx_gpio_request_regions(struct device *dev,
static int ichx_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct lpc_ich_info *ich_info = dev_get_platdata(dev);
struct resource *res_base, *res_pm;
int err;
struct lpc_ich_info *ich_info = dev_get_platdata(&pdev->dev);
if (!ich_info)
return -ENODEV;
ichx_priv.dev = pdev;
switch (ich_info->gpio_version) {
case ICH_I3100_GPIO:
ichx_priv.desc = &i3100_desc;
......@@ -445,19 +420,21 @@ static int ichx_gpio_probe(struct platform_device *pdev)
return -ENODEV;
}
ichx_priv.dev = dev;
spin_lock_init(&ichx_priv.lock);
res_base = platform_get_resource(pdev, IORESOURCE_IO, ICH_RES_GPIO);
ichx_priv.use_gpio = ich_info->use_gpio;
err = ichx_gpio_request_regions(&pdev->dev, res_base, pdev->name,
ichx_priv.use_gpio);
err = ichx_gpio_request_regions(dev, res_base, pdev->name,
ich_info->use_gpio);
if (err)
return err;
ichx_priv.gpio_base = res_base;
ichx_priv.use_gpio = ich_info->use_gpio;
/*
* If necessary, determine the I/O address of ACPI/power management
* registers which are needed to read the the GPE0 register for GPI pins
* registers which are needed to read the GPE0 register for GPI pins
* 0 - 15 on some chipsets.
*/
if (!ichx_priv.desc->uses_gpe0)
......@@ -465,13 +442,13 @@ static int ichx_gpio_probe(struct platform_device *pdev)
res_pm = platform_get_resource(pdev, IORESOURCE_IO, ICH_RES_GPE0);
if (!res_pm) {
pr_warn("ACPI BAR is unavailable, GPI 0 - 15 unavailable\n");
dev_warn(dev, "ACPI BAR is unavailable, GPI 0 - 15 unavailable\n");
goto init;
}
if (!devm_request_region(&pdev->dev, res_pm->start,
resource_size(res_pm), pdev->name)) {
pr_warn("ACPI BAR is busy, GPI 0 - 15 unavailable\n");
if (!devm_request_region(dev, res_pm->start, resource_size(res_pm),
pdev->name)) {
dev_warn(dev, "ACPI BAR is busy, GPI 0 - 15 unavailable\n");
goto init;
}
......@@ -481,12 +458,12 @@ static int ichx_gpio_probe(struct platform_device *pdev)
ichx_gpiolib_setup(&ichx_priv.chip);
err = gpiochip_add_data(&ichx_priv.chip, NULL);
if (err) {
pr_err("Failed to register GPIOs\n");
dev_err(dev, "Failed to register GPIOs\n");
return err;
}
pr_info("GPIO from %d to %d on %s\n", ichx_priv.chip.base,
ichx_priv.chip.base + ichx_priv.chip.ngpio - 1, DRV_NAME);
dev_info(dev, "GPIO from %d to %d\n", ichx_priv.chip.base,
ichx_priv.chip.base + ichx_priv.chip.ngpio - 1);
return 0;
}
......
// SPDX-License-Identifier: GPL-2.0
/*
* Intel MID GPIO driver
*
* Copyright (c) 2008-2014,2016 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/* Supports:
......@@ -20,12 +12,11 @@
*/
#include <linux/delay.h>
#include <linux/gpio/driver.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/gpio/driver.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
......@@ -273,9 +264,8 @@ static const struct pci_device_id intel_gpio_ids[] = {
PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08f7),
.driver_data = (kernel_ulong_t)&gpio_cloverview_core,
},
{ 0 }
{ }
};
MODULE_DEVICE_TABLE(pci, intel_gpio_ids);
static void intel_mid_irq_handler(struct irq_desc *desc)
{
......
......@@ -282,22 +282,13 @@ static int ks8695_gpio_show(struct seq_file *s, void *unused)
return 0;
}
static int ks8695_gpio_open(struct inode *inode, struct file *file)
{
return single_open(file, ks8695_gpio_show, NULL);
}
static const struct file_operations ks8695_gpio_operations = {
.open = ks8695_gpio_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
DEFINE_SHOW_ATTRIBUTE(ks8695_gpio);
static int __init ks8695_gpio_debugfs_init(void)
{
/* /sys/kernel/debug/ks8695_gpio */
(void) debugfs_create_file("ks8695_gpio", S_IFREG | S_IRUGO, NULL, NULL, &ks8695_gpio_operations);
debugfs_create_file("ks8695_gpio", S_IFREG | S_IRUGO, NULL, NULL,
&ks8695_gpio_fops);
return 0;
}
postcore_initcall(ks8695_gpio_debugfs_init);
......
// SPDX-License-Identifier: GPL-2.0
/*
* GPIO driver for NXP LPC18xx/43xx.
*
* Copyright (C) 2018 Vladimir Zapolskiy <vz@mleia.com>
* Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/clk.h>
#include <linux/gpio/driver.h>
#include <linux/io.h>
#include <linux/irqdomain.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
......@@ -24,13 +25,246 @@
#define LPC18XX_MAX_PORTS 8
#define LPC18XX_PINS_PER_PORT 32
/* LPC18xx GPIO pin interrupt controller register offsets */
#define LPC18XX_GPIO_PIN_IC_ISEL 0x00
#define LPC18XX_GPIO_PIN_IC_IENR 0x04
#define LPC18XX_GPIO_PIN_IC_SIENR 0x08
#define LPC18XX_GPIO_PIN_IC_CIENR 0x0c
#define LPC18XX_GPIO_PIN_IC_IENF 0x10
#define LPC18XX_GPIO_PIN_IC_SIENF 0x14
#define LPC18XX_GPIO_PIN_IC_CIENF 0x18
#define LPC18XX_GPIO_PIN_IC_RISE 0x1c
#define LPC18XX_GPIO_PIN_IC_FALL 0x20
#define LPC18XX_GPIO_PIN_IC_IST 0x24
#define NR_LPC18XX_GPIO_PIN_IC_IRQS 8
struct lpc18xx_gpio_pin_ic {
void __iomem *base;
struct irq_domain *domain;
struct raw_spinlock lock;
};
struct lpc18xx_gpio_chip {
struct gpio_chip gpio;
void __iomem *base;
struct clk *clk;
struct lpc18xx_gpio_pin_ic *pin_ic;
spinlock_t lock;
};
static inline void lpc18xx_gpio_pin_ic_isel(struct lpc18xx_gpio_pin_ic *ic,
u32 pin, bool set)
{
u32 val = readl_relaxed(ic->base + LPC18XX_GPIO_PIN_IC_ISEL);
if (set)
val &= ~BIT(pin);
else
val |= BIT(pin);
writel_relaxed(val, ic->base + LPC18XX_GPIO_PIN_IC_ISEL);
}
static inline void lpc18xx_gpio_pin_ic_set(struct lpc18xx_gpio_pin_ic *ic,
u32 pin, u32 reg)
{
writel_relaxed(BIT(pin), ic->base + reg);
}
static void lpc18xx_gpio_pin_ic_mask(struct irq_data *d)
{
struct lpc18xx_gpio_pin_ic *ic = d->chip_data;
u32 type = irqd_get_trigger_type(d);
raw_spin_lock(&ic->lock);
if (type & IRQ_TYPE_LEVEL_MASK || type & IRQ_TYPE_EDGE_RISING)
lpc18xx_gpio_pin_ic_set(ic, d->hwirq,
LPC18XX_GPIO_PIN_IC_CIENR);
if (type & IRQ_TYPE_EDGE_FALLING)
lpc18xx_gpio_pin_ic_set(ic, d->hwirq,
LPC18XX_GPIO_PIN_IC_CIENF);
raw_spin_unlock(&ic->lock);
irq_chip_mask_parent(d);
}
static void lpc18xx_gpio_pin_ic_unmask(struct irq_data *d)
{
struct lpc18xx_gpio_pin_ic *ic = d->chip_data;
u32 type = irqd_get_trigger_type(d);
raw_spin_lock(&ic->lock);
if (type & IRQ_TYPE_LEVEL_MASK || type & IRQ_TYPE_EDGE_RISING)
lpc18xx_gpio_pin_ic_set(ic, d->hwirq,
LPC18XX_GPIO_PIN_IC_SIENR);
if (type & IRQ_TYPE_EDGE_FALLING)
lpc18xx_gpio_pin_ic_set(ic, d->hwirq,
LPC18XX_GPIO_PIN_IC_SIENF);
raw_spin_unlock(&ic->lock);
irq_chip_unmask_parent(d);
}
static void lpc18xx_gpio_pin_ic_eoi(struct irq_data *d)
{
struct lpc18xx_gpio_pin_ic *ic = d->chip_data;
u32 type = irqd_get_trigger_type(d);
raw_spin_lock(&ic->lock);
if (type & IRQ_TYPE_EDGE_BOTH)
lpc18xx_gpio_pin_ic_set(ic, d->hwirq,
LPC18XX_GPIO_PIN_IC_IST);
raw_spin_unlock(&ic->lock);
irq_chip_eoi_parent(d);
}
static int lpc18xx_gpio_pin_ic_set_type(struct irq_data *d, unsigned int type)
{
struct lpc18xx_gpio_pin_ic *ic = d->chip_data;
raw_spin_lock(&ic->lock);
if (type & IRQ_TYPE_LEVEL_HIGH) {
lpc18xx_gpio_pin_ic_isel(ic, d->hwirq, true);
lpc18xx_gpio_pin_ic_set(ic, d->hwirq,
LPC18XX_GPIO_PIN_IC_SIENF);
} else if (type & IRQ_TYPE_LEVEL_LOW) {
lpc18xx_gpio_pin_ic_isel(ic, d->hwirq, true);
lpc18xx_gpio_pin_ic_set(ic, d->hwirq,
LPC18XX_GPIO_PIN_IC_CIENF);
} else {
lpc18xx_gpio_pin_ic_isel(ic, d->hwirq, false);
}
raw_spin_unlock(&ic->lock);
return 0;
}
static struct irq_chip lpc18xx_gpio_pin_ic = {
.name = "LPC18xx GPIO pin",
.irq_mask = lpc18xx_gpio_pin_ic_mask,
.irq_unmask = lpc18xx_gpio_pin_ic_unmask,
.irq_eoi = lpc18xx_gpio_pin_ic_eoi,
.irq_set_type = lpc18xx_gpio_pin_ic_set_type,
.flags = IRQCHIP_SET_TYPE_MASKED,
};
static int lpc18xx_gpio_pin_ic_domain_alloc(struct irq_domain *domain,
unsigned int virq,
unsigned int nr_irqs, void *data)
{
struct irq_fwspec parent_fwspec, *fwspec = data;
struct lpc18xx_gpio_pin_ic *ic = domain->host_data;
irq_hw_number_t hwirq;
int ret;
if (nr_irqs != 1)
return -EINVAL;
hwirq = fwspec->param[0];
if (hwirq >= NR_LPC18XX_GPIO_PIN_IC_IRQS)
return -EINVAL;
/*
* All LPC18xx/LPC43xx GPIO pin hardware interrupts are translated
* into edge interrupts 32...39 on parent Cortex-M3/M4 NVIC
*/
parent_fwspec.fwnode = domain->parent->fwnode;
parent_fwspec.param_count = 1;
parent_fwspec.param[0] = hwirq + 32;
ret = irq_domain_alloc_irqs_parent(domain, virq, 1, &parent_fwspec);
if (ret < 0) {
pr_err("failed to allocate parent irq %u: %d\n",
parent_fwspec.param[0], ret);
return ret;
}
return irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
&lpc18xx_gpio_pin_ic, ic);
}
static const struct irq_domain_ops lpc18xx_gpio_pin_ic_domain_ops = {
.alloc = lpc18xx_gpio_pin_ic_domain_alloc,
.xlate = irq_domain_xlate_twocell,
.free = irq_domain_free_irqs_common,
};
static int lpc18xx_gpio_pin_ic_probe(struct lpc18xx_gpio_chip *gc)
{
struct device *dev = gc->gpio.parent;
struct irq_domain *parent_domain;
struct device_node *parent_node;
struct lpc18xx_gpio_pin_ic *ic;
struct resource res;
int ret, index;
parent_node = of_irq_find_parent(dev->of_node);
if (!parent_node)
return -ENXIO;
parent_domain = irq_find_host(parent_node);
of_node_put(parent_node);
if (!parent_domain)
return -ENXIO;
ic = devm_kzalloc(dev, sizeof(*ic), GFP_KERNEL);
if (!ic)
return -ENOMEM;
index = of_property_match_string(dev->of_node, "reg-names",
"gpio-pin-ic");
if (index < 0) {
ret = -ENODEV;
goto free_ic;
}
ret = of_address_to_resource(dev->of_node, index, &res);
if (ret < 0)
goto free_ic;
ic->base = devm_ioremap_resource(dev, &res);
if (IS_ERR(ic->base)) {
ret = PTR_ERR(ic->base);
goto free_ic;
}
raw_spin_lock_init(&ic->lock);
ic->domain = irq_domain_add_hierarchy(parent_domain, 0,
NR_LPC18XX_GPIO_PIN_IC_IRQS,
dev->of_node,
&lpc18xx_gpio_pin_ic_domain_ops,
ic);
if (!ic->domain) {
pr_err("unable to add irq domain\n");
ret = -ENODEV;
goto free_iomap;
}
gc->pin_ic = ic;
return 0;
free_iomap:
devm_iounmap(dev, ic->base);
free_ic:
devm_kfree(dev, ic);
return ret;
}
static void lpc18xx_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
struct lpc18xx_gpio_chip *gc = gpiochip_get_data(chip);
......@@ -92,45 +326,62 @@ static const struct gpio_chip lpc18xx_chip = {
static int lpc18xx_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct lpc18xx_gpio_chip *gc;
struct resource *res;
int ret;
int index, ret;
gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL);
gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL);
if (!gc)
return -ENOMEM;
gc->gpio = lpc18xx_chip;
platform_set_drvdata(pdev, gc);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
gc->base = devm_ioremap_resource(&pdev->dev, res);
index = of_property_match_string(dev->of_node, "reg-names", "gpio");
if (index < 0) {
/* To support backward compatibility take the first resource */
struct resource *res;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
gc->base = devm_ioremap_resource(dev, res);
} else {
struct resource res;
ret = of_address_to_resource(dev->of_node, index, &res);
if (ret < 0)
return ret;
gc->base = devm_ioremap_resource(dev, &res);
}
if (IS_ERR(gc->base))
return PTR_ERR(gc->base);
gc->clk = devm_clk_get(&pdev->dev, NULL);
gc->clk = devm_clk_get(dev, NULL);
if (IS_ERR(gc->clk)) {
dev_err(&pdev->dev, "input clock not found\n");
dev_err(dev, "input clock not found\n");
return PTR_ERR(gc->clk);
}
ret = clk_prepare_enable(gc->clk);
if (ret) {
dev_err(&pdev->dev, "unable to enable clock\n");
dev_err(dev, "unable to enable clock\n");
return ret;
}
spin_lock_init(&gc->lock);
gc->gpio.parent = &pdev->dev;
gc->gpio.parent = dev;
ret = gpiochip_add_data(&gc->gpio, gc);
ret = devm_gpiochip_add_data(dev, &gc->gpio, gc);
if (ret) {
dev_err(&pdev->dev, "failed to add gpio chip\n");
dev_err(dev, "failed to add gpio chip\n");
clk_disable_unprepare(gc->clk);
return ret;
}
/* On error GPIO pin interrupt controller just won't be registered */
lpc18xx_gpio_pin_ic_probe(gc);
return 0;
}
......@@ -138,7 +389,9 @@ static int lpc18xx_gpio_remove(struct platform_device *pdev)
{
struct lpc18xx_gpio_chip *gc = platform_get_drvdata(pdev);
gpiochip_remove(&gc->gpio);
if (gc->pin_ic)
irq_domain_remove(gc->pin_ic->domain);
clk_disable_unprepare(gc->clk);
return 0;
......@@ -161,5 +414,6 @@ static struct platform_driver lpc18xx_gpio_driver = {
module_platform_driver(lpc18xx_gpio_driver);
MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>");
MODULE_AUTHOR("Vladimir Zapolskiy <vz@mleia.com>");
MODULE_DESCRIPTION("GPIO driver for LPC18xx/43xx");
MODULE_LICENSE("GPL v2");
// SPDX-License-Identifier: GPL-2.0
/*
* GPIO controller driver for Intel Lynxpoint PCH chipset>
* Copyright (c) 2012, Intel Corporation.
*
* Author: Mathias Nyman <mathias.nyman@linux.intel.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/acpi.h>
#include <linux/bitops.h>
#include <linux/interrupt.h>
#include <linux/gpio/driver.h>
#include <linux/slab.h>
#include <linux/acpi.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/types.h>
/* LynxPoint chipset has support for 94 gpio pins */
......@@ -240,21 +226,23 @@ static void lp_gpio_irq_handler(struct irq_desc *desc)
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
struct lp_gpio *lg = gpiochip_get_data(gc);
struct irq_chip *chip = irq_data_get_irq_chip(data);
u32 base, pin, mask;
unsigned long reg, ena, pending;
u32 base, pin;
/* check from GPIO controller which pin triggered the interrupt */
for (base = 0; base < lg->chip.ngpio; base += 32) {
reg = lp_gpio_reg(&lg->chip, base, LP_INT_STAT);
ena = lp_gpio_reg(&lg->chip, base, LP_INT_ENABLE);
while ((pending = (inl(reg) & inl(ena)))) {
/* Only interrupts that are enabled */
pending = inl(reg) & inl(ena);
for_each_set_bit(pin, &pending, 32) {
unsigned irq;
pin = __ffs(pending);
mask = BIT(pin);
/* Clear before handling so we don't lose an edge */
outl(mask, reg);
outl(BIT(pin), reg);
irq = irq_find_mapping(lg->chip.irq.domain, base + pin);
generic_handle_irq(irq);
}
......@@ -408,8 +396,7 @@ static int lp_gpio_runtime_resume(struct device *dev)
static int lp_gpio_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct lp_gpio *lg = platform_get_drvdata(pdev);
struct lp_gpio *lg = dev_get_drvdata(dev);
unsigned long reg;
int i;
......@@ -467,5 +454,5 @@ module_exit(lp_gpio_exit);
MODULE_AUTHOR("Mathias Nyman (Intel)");
MODULE_DESCRIPTION("GPIO interface for Intel Lynxpoint");
MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:lp_gpio");
// SPDX-License-Identifier: GPL-2.0
/*
* Intel Merrifield SoC GPIO driver
*
* Copyright (c) 2016 Intel Corporation.
* Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/acpi.h>
#include <linux/bitops.h>
#include <linux/gpio/driver.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
......
......@@ -244,6 +244,8 @@ mediatek_gpio_bank_probe(struct device *dev,
rg->chip.of_xlate = mediatek_gpio_xlate;
rg->chip.label = devm_kasprintf(dev, GFP_KERNEL, "%s-bank%d",
dev_name(dev), bank);
if (!rg->chip.label)
return -ENOMEM;
ret = devm_gpiochip_add_data(dev, &rg->chip, mtk);
if (ret < 0) {
......@@ -295,6 +297,7 @@ mediatek_gpio_probe(struct platform_device *pdev)
struct device_node *np = dev->of_node;
struct mtk *mtk;
int i;
int ret;
mtk = devm_kzalloc(dev, sizeof(*mtk), GFP_KERNEL);
if (!mtk)
......@@ -309,8 +312,11 @@ mediatek_gpio_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, mtk);
mediatek_gpio_irq_chip.name = dev_name(dev);
for (i = 0; i < MTK_BANK_CNT; i++)
mediatek_gpio_bank_probe(dev, np, i);
for (i = 0; i < MTK_BANK_CNT; i++) {
ret = mediatek_gpio_bank_probe(dev, np, i);
if (ret)
return ret;
}
return 0;
}
......
......@@ -608,7 +608,7 @@ static int mvebu_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
ret = -EBUSY;
} else {
desc = gpiochip_request_own_desc(&mvchip->chip,
pwm->hwpwm, "mvebu-pwm");
pwm->hwpwm, "mvebu-pwm", 0);
if (IS_ERR(desc)) {
ret = PTR_ERR(desc);
goto out;
......
......@@ -17,6 +17,7 @@
#include <linux/irqchip/chained_irq.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/syscore_ops.h>
#include <linux/gpio/driver.h>
#include <linux/of.h>
#include <linux/of_device.h>
......@@ -550,33 +551,38 @@ static void mxc_gpio_restore_regs(struct mxc_gpio_port *port)
writel(port->gpio_saved_reg.dr, port->base + GPIO_DR);
}
static int __maybe_unused mxc_gpio_noirq_suspend(struct device *dev)
static int mxc_gpio_syscore_suspend(void)
{
struct platform_device *pdev = to_platform_device(dev);
struct mxc_gpio_port *port = platform_get_drvdata(pdev);
struct mxc_gpio_port *port;
mxc_gpio_save_regs(port);
clk_disable_unprepare(port->clk);
/* walk through all ports */
list_for_each_entry(port, &mxc_gpio_ports, node) {
mxc_gpio_save_regs(port);
clk_disable_unprepare(port->clk);
}
return 0;
}
static int __maybe_unused mxc_gpio_noirq_resume(struct device *dev)
static void mxc_gpio_syscore_resume(void)
{
struct platform_device *pdev = to_platform_device(dev);
struct mxc_gpio_port *port = platform_get_drvdata(pdev);
struct mxc_gpio_port *port;
int ret;
ret = clk_prepare_enable(port->clk);
if (ret)
return ret;
mxc_gpio_restore_regs(port);
return 0;
/* walk through all ports */
list_for_each_entry(port, &mxc_gpio_ports, node) {
ret = clk_prepare_enable(port->clk);
if (ret) {
pr_err("mxc: failed to enable gpio clock %d\n", ret);
return;
}
mxc_gpio_restore_regs(port);
}
}
static const struct dev_pm_ops mxc_gpio_dev_pm_ops = {
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mxc_gpio_noirq_suspend, mxc_gpio_noirq_resume)
static struct syscore_ops mxc_gpio_syscore_ops = {
.suspend = mxc_gpio_syscore_suspend,
.resume = mxc_gpio_syscore_resume,
};
static struct platform_driver mxc_gpio_driver = {
......@@ -584,7 +590,6 @@ static struct platform_driver mxc_gpio_driver = {
.name = "gpio-mxc",
.of_match_table = mxc_gpio_dt_ids,
.suppress_bind_attrs = true,
.pm = &mxc_gpio_dev_pm_ops,
},
.probe = mxc_gpio_probe,
.id_table = mxc_gpio_devtype,
......@@ -592,6 +597,8 @@ static struct platform_driver mxc_gpio_driver = {
static int __init gpio_mxc_init(void)
{
register_syscore_ops(&mxc_gpio_syscore_ops);
return platform_driver_register(&mxc_gpio_driver);
}
subsys_initcall(gpio_mxc_init);
......@@ -84,7 +84,7 @@ static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type)
port->both_edges &= ~pin_mask;
switch (type) {
case IRQ_TYPE_EDGE_BOTH:
val = port->gc.get(&port->gc, d->hwirq);
val = readl(port->base + PINCTRL_DIN(port)) & pin_mask;
if (val)
edge = GPIO_INT_FALL_EDGE;
else
......
......@@ -936,8 +936,7 @@ omap2_gpio_disable_level_quirk(struct gpio_bank *bank)
static int omap_mpuio_suspend_noirq(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct gpio_bank *bank = platform_get_drvdata(pdev);
struct gpio_bank *bank = dev_get_drvdata(dev);
void __iomem *mask_reg = bank->base +
OMAP_MPUIO_GPIO_MASKIT / bank->stride;
unsigned long flags;
......@@ -951,8 +950,7 @@ static int omap_mpuio_suspend_noirq(struct device *dev)
static int omap_mpuio_resume_noirq(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct gpio_bank *bank = platform_get_drvdata(pdev);
struct gpio_bank *bank = dev_get_drvdata(dev);
void __iomem *mask_reg = bank->base +
OMAP_MPUIO_GPIO_MASKIT / bank->stride;
unsigned long flags;
......@@ -1635,8 +1633,7 @@ static void omap_gpio_restore_context(struct gpio_bank *bank)
static int __maybe_unused omap_gpio_runtime_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct gpio_bank *bank = platform_get_drvdata(pdev);
struct gpio_bank *bank = dev_get_drvdata(dev);
unsigned long flags;
int error = 0;
......@@ -1656,8 +1653,7 @@ static int __maybe_unused omap_gpio_runtime_suspend(struct device *dev)
static int __maybe_unused omap_gpio_runtime_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct gpio_bank *bank = platform_get_drvdata(pdev);
struct gpio_bank *bank = dev_get_drvdata(dev);
unsigned long flags;
int error = 0;
......
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2011 LAPIS Semiconductor Co., Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/gpio/driver.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/slab.h>
#define PCH_EDGE_FALLING 0
......@@ -171,11 +159,10 @@ static int pch_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
return 0;
}
#ifdef CONFIG_PM
/*
* Save register configuration and disable interrupts.
*/
static void pch_gpio_save_reg_conf(struct pch_gpio *chip)
static void __maybe_unused pch_gpio_save_reg_conf(struct pch_gpio *chip)
{
chip->pch_gpio_reg.ien_reg = ioread32(&chip->reg->ien);
chip->pch_gpio_reg.imask_reg = ioread32(&chip->reg->imask);
......@@ -185,14 +172,13 @@ static void pch_gpio_save_reg_conf(struct pch_gpio *chip)
if (chip->ioh == INTEL_EG20T_PCH)
chip->pch_gpio_reg.im1_reg = ioread32(&chip->reg->im1);
if (chip->ioh == OKISEMI_ML7223n_IOH)
chip->pch_gpio_reg.gpio_use_sel_reg =\
ioread32(&chip->reg->gpio_use_sel);
chip->pch_gpio_reg.gpio_use_sel_reg = ioread32(&chip->reg->gpio_use_sel);
}
/*
* This function restores the register configuration of the GPIO device.
*/
static void pch_gpio_restore_reg_conf(struct pch_gpio *chip)
static void __maybe_unused pch_gpio_restore_reg_conf(struct pch_gpio *chip)
{
iowrite32(chip->pch_gpio_reg.ien_reg, &chip->reg->ien);
iowrite32(chip->pch_gpio_reg.imask_reg, &chip->reg->imask);
......@@ -204,10 +190,8 @@ static void pch_gpio_restore_reg_conf(struct pch_gpio *chip)
if (chip->ioh == INTEL_EG20T_PCH)
iowrite32(chip->pch_gpio_reg.im1_reg, &chip->reg->im1);
if (chip->ioh == OKISEMI_ML7223n_IOH)
iowrite32(chip->pch_gpio_reg.gpio_use_sel_reg,
&chip->reg->gpio_use_sel);
iowrite32(chip->pch_gpio_reg.gpio_use_sel_reg, &chip->reg->gpio_use_sel);
}
#endif
static int pch_gpio_to_irq(struct gpio_chip *gpio, unsigned offset)
{
......@@ -226,7 +210,6 @@ static void pch_gpio_setup(struct pch_gpio *chip)
gpio->get = pch_gpio_get;
gpio->direction_output = pch_gpio_direction_output;
gpio->set = pch_gpio_set;
gpio->dbg_show = NULL;
gpio->base = -1;
gpio->ngpio = gpio_pins[chip->ioh];
gpio->can_sleep = false;
......@@ -250,8 +233,7 @@ static int pch_irq_type(struct irq_data *d, unsigned int type)
im_reg = &chip->reg->im1;
im_pos = ch - 8;
}
dev_dbg(chip->dev, "%s:irq=%d type=%d ch=%d pos=%d\n",
__func__, irq, type, ch, im_pos);
dev_dbg(chip->dev, "irq=%d type=%d ch=%d pos=%d\n", irq, type, ch, im_pos);
spin_lock_irqsave(&chip->spinlock, flags);
......@@ -317,16 +299,13 @@ static void pch_irq_ack(struct irq_data *d)
static irqreturn_t pch_gpio_handler(int irq, void *dev_id)
{
struct pch_gpio *chip = dev_id;
u32 reg_val = ioread32(&chip->reg->istatus);
unsigned long reg_val = ioread32(&chip->reg->istatus);
int i, ret = IRQ_NONE;
for (i = 0; i < gpio_pins[chip->ioh]; i++) {
if (reg_val & BIT(i)) {
dev_dbg(chip->dev, "%s:[%d]:irq=%d status=0x%x\n",
__func__, i, irq, reg_val);
generic_handle_irq(chip->irq_base + i);
ret = IRQ_HANDLED;
}
for_each_set_bit(i, &reg_val, gpio_pins[chip->ioh]) {
dev_dbg(chip->dev, "[%d]:irq=%d status=0x%lx\n", i, irq, reg_val);
generic_handle_irq(chip->irq_base + i);
ret = IRQ_HANDLED;
}
return ret;
}
......@@ -367,29 +346,24 @@ static int pch_gpio_probe(struct pci_dev *pdev,
int irq_base;
u32 msk;
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
if (chip == NULL)
return -ENOMEM;
chip->dev = &pdev->dev;
ret = pci_enable_device(pdev);
ret = pcim_enable_device(pdev);
if (ret) {
dev_err(&pdev->dev, "%s : pci_enable_device FAILED", __func__);
goto err_pci_enable;
dev_err(&pdev->dev, "pci_enable_device FAILED");
return ret;
}
ret = pci_request_regions(pdev, KBUILD_MODNAME);
ret = pcim_iomap_regions(pdev, 1 << 1, KBUILD_MODNAME);
if (ret) {
dev_err(&pdev->dev, "pci_request_regions FAILED-%d", ret);
goto err_request_regions;
return ret;
}
chip->base = pci_iomap(pdev, 1, 0);
if (!chip->base) {
dev_err(&pdev->dev, "%s : pci_iomap FAILED", __func__);
ret = -ENOMEM;
goto err_iomap;
}
chip->base = pcim_iomap_table(pdev)[1];
if (pdev->device == 0x8803)
chip->ioh = INTEL_EG20T_PCH;
......@@ -402,13 +376,11 @@ static int pch_gpio_probe(struct pci_dev *pdev,
pci_set_drvdata(pdev, chip);
spin_lock_init(&chip->spinlock);
pch_gpio_setup(chip);
#ifdef CONFIG_OF_GPIO
chip->gpio.of_node = pdev->dev.of_node;
#endif
ret = gpiochip_add_data(&chip->gpio, chip);
ret = devm_gpiochip_add_data(&pdev->dev, &chip->gpio, chip);
if (ret) {
dev_err(&pdev->dev, "PCH gpio: Failed to register GPIO\n");
goto err_gpiochip_add;
return ret;
}
irq_base = devm_irq_alloc_descs(&pdev->dev, -1, 0,
......@@ -416,7 +388,7 @@ static int pch_gpio_probe(struct pci_dev *pdev,
if (irq_base < 0) {
dev_warn(&pdev->dev, "PCH gpio: Failed to get IRQ base num\n");
chip->irq_base = -1;
goto end;
return 0;
}
chip->irq_base = irq_base;
......@@ -427,53 +399,17 @@ static int pch_gpio_probe(struct pci_dev *pdev,
ret = devm_request_irq(&pdev->dev, pdev->irq, pch_gpio_handler,
IRQF_SHARED, KBUILD_MODNAME, chip);
if (ret != 0) {
dev_err(&pdev->dev,
"%s request_irq failed\n", __func__);
goto err_request_irq;
if (ret) {
dev_err(&pdev->dev, "request_irq failed\n");
return ret;
}
ret = pch_gpio_alloc_generic_chip(chip, irq_base,
gpio_pins[chip->ioh]);
if (ret)
goto err_request_irq;
end:
return 0;
err_request_irq:
gpiochip_remove(&chip->gpio);
err_gpiochip_add:
pci_iounmap(pdev, chip->base);
err_iomap:
pci_release_regions(pdev);
err_request_regions:
pci_disable_device(pdev);
err_pci_enable:
kfree(chip);
dev_err(&pdev->dev, "%s Failed returns %d\n", __func__, ret);
return ret;
}
static void pch_gpio_remove(struct pci_dev *pdev)
{
struct pch_gpio *chip = pci_get_drvdata(pdev);
gpiochip_remove(&chip->gpio);
pci_iounmap(pdev, chip->base);
pci_release_regions(pdev);
pci_disable_device(pdev);
kfree(chip);
return pch_gpio_alloc_generic_chip(chip, irq_base, gpio_pins[chip->ioh]);
}
#ifdef CONFIG_PM
static int pch_gpio_suspend(struct pci_dev *pdev, pm_message_t state)
static int __maybe_unused pch_gpio_suspend(struct device *dev)
{
s32 ret;
struct pci_dev *pdev = to_pci_dev(dev);
struct pch_gpio *chip = pci_get_drvdata(pdev);
unsigned long flags;
......@@ -481,36 +417,15 @@ static int pch_gpio_suspend(struct pci_dev *pdev, pm_message_t state)
pch_gpio_save_reg_conf(chip);
spin_unlock_irqrestore(&chip->spinlock, flags);
ret = pci_save_state(pdev);
if (ret) {
dev_err(&pdev->dev, "pci_save_state Failed-%d\n", ret);
return ret;
}
pci_disable_device(pdev);
pci_set_power_state(pdev, PCI_D0);
ret = pci_enable_wake(pdev, PCI_D0, 1);
if (ret)
dev_err(&pdev->dev, "pci_enable_wake Failed -%d\n", ret);
return 0;
}
static int pch_gpio_resume(struct pci_dev *pdev)
static int __maybe_unused pch_gpio_resume(struct device *dev)
{
s32 ret;
struct pci_dev *pdev = to_pci_dev(dev);
struct pch_gpio *chip = pci_get_drvdata(pdev);
unsigned long flags;
ret = pci_enable_wake(pdev, PCI_D0, 0);
pci_set_power_state(pdev, PCI_D0);
ret = pci_enable_device(pdev);
if (ret) {
dev_err(&pdev->dev, "pci_enable_device Failed-%d ", ret);
return ret;
}
pci_restore_state(pdev);
spin_lock_irqsave(&chip->spinlock, flags);
iowrite32(0x01, &chip->reg->reset);
iowrite32(0x00, &chip->reg->reset);
......@@ -519,10 +434,8 @@ static int pch_gpio_resume(struct pci_dev *pdev)
return 0;
}
#else
#define pch_gpio_suspend NULL
#define pch_gpio_resume NULL
#endif
static SIMPLE_DEV_PM_OPS(pch_gpio_pm_ops, pch_gpio_suspend, pch_gpio_resume);
#define PCI_VENDOR_ID_ROHM 0x10DB
static const struct pci_device_id pch_gpio_pcidev_id[] = {
......@@ -538,12 +451,12 @@ static struct pci_driver pch_gpio_driver = {
.name = "pch_gpio",
.id_table = pch_gpio_pcidev_id,
.probe = pch_gpio_probe,
.remove = pch_gpio_remove,
.suspend = pch_gpio_suspend,
.resume = pch_gpio_resume
.driver = {
.pm = &pch_gpio_pm_ops,
},
};
module_pci_driver(pch_gpio_driver);
MODULE_DESCRIPTION("PCH GPIO PCI Driver");
MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL v2");
......@@ -146,7 +146,7 @@ static int idio_16_gpio_get_multiple(struct gpio_chip *chip,
port_state = ioread8(ports[i]);
/* store acquired bits at respective bits array offset */
bits[word_index] |= port_state << word_offset;
bits[word_index] |= (port_state << word_offset) & word_mask;
}
return 0;
......
......@@ -243,7 +243,7 @@ static int idio_24_gpio_get_multiple(struct gpio_chip *chip,
port_state = ioread8(&idio24gpio->reg->ttl_in0_7);
/* store acquired bits at respective bits array offset */
bits[word_index] |= port_state << word_offset;
bits[word_index] |= (port_state << word_offset) & word_mask;
}
return 0;
......
......@@ -54,6 +54,7 @@ struct pl061 {
void __iomem *base;
struct gpio_chip gc;
struct irq_chip irq_chip;
int parent_irq;
#ifdef CONFIG_PM
......@@ -281,15 +282,6 @@ static int pl061_irq_set_wake(struct irq_data *d, unsigned int state)
return irq_set_irq_wake(pl061->parent_irq, state);
}
static struct irq_chip pl061_irqchip = {
.name = "pl061",
.irq_ack = pl061_irq_ack,
.irq_mask = pl061_irq_mask,
.irq_unmask = pl061_irq_unmask,
.irq_set_type = pl061_irq_type,
.irq_set_wake = pl061_irq_set_wake,
};
static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
{
struct device *dev = &adev->dev;
......@@ -328,6 +320,13 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
/*
* irq_chip support
*/
pl061->irq_chip.name = dev_name(dev);
pl061->irq_chip.irq_ack = pl061_irq_ack;
pl061->irq_chip.irq_mask = pl061_irq_mask;
pl061->irq_chip.irq_unmask = pl061_irq_unmask;
pl061->irq_chip.irq_set_type = pl061_irq_type;
pl061->irq_chip.irq_set_wake = pl061_irq_set_wake;
writeb(0, pl061->base + GPIOIE); /* disable irqs */
irq = adev->irq[0];
if (irq < 0) {
......@@ -336,14 +335,14 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
}
pl061->parent_irq = irq;
ret = gpiochip_irqchip_add(&pl061->gc, &pl061_irqchip,
ret = gpiochip_irqchip_add(&pl061->gc, &pl061->irq_chip,
0, handle_bad_irq,
IRQ_TYPE_NONE);
if (ret) {
dev_info(&adev->dev, "could not add irqchip\n");
return ret;
}
gpiochip_set_chained_irqchip(&pl061->gc, &pl061_irqchip,
gpiochip_set_chained_irqchip(&pl061->gc, &pl061->irq_chip,
irq, pl061_irq_handler);
amba_set_drvdata(adev, pl061);
......
......@@ -206,6 +206,7 @@ static int rpi_exp_gpio_probe(struct platform_device *pdev)
}
fw = rpi_firmware_get(fw_node);
of_node_put(fw_node);
if (!fw)
return -EPROBE_DEFER;
......
// SPDX-License-Identifier: GPL-2.0
/*
* Renesas R-Car GPIO Support
*
* Copyright (C) 2014 Renesas Electronics Corporation
* Copyright (C) 2013 Magnus Damm
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/err.h>
......@@ -43,7 +35,7 @@ struct gpio_rcar_bank_info {
struct gpio_rcar_priv {
void __iomem *base;
spinlock_t lock;
struct platform_device *pdev;
struct device *dev;
struct gpio_chip gpio_chip;
struct irq_chip irq_chip;
unsigned int irq_parent;
......@@ -148,7 +140,7 @@ static int gpio_rcar_irq_set_type(struct irq_data *d, unsigned int type)
struct gpio_rcar_priv *p = gpiochip_get_data(gc);
unsigned int hwirq = irqd_to_hwirq(d);
dev_dbg(&p->pdev->dev, "sense irq = %d, type = %d\n", hwirq, type);
dev_dbg(p->dev, "sense irq = %d, type = %d\n", hwirq, type);
switch (type & IRQ_TYPE_SENSE_MASK) {
case IRQ_TYPE_LEVEL_HIGH:
......@@ -188,8 +180,7 @@ static int gpio_rcar_irq_set_wake(struct irq_data *d, unsigned int on)
if (p->irq_parent) {
error = irq_set_irq_wake(p->irq_parent, on);
if (error) {
dev_dbg(&p->pdev->dev,
"irq %u doesn't support irq_set_wake\n",
dev_dbg(p->dev, "irq %u doesn't support irq_set_wake\n",
p->irq_parent);
p->irq_parent = 0;
}
......@@ -252,13 +243,13 @@ static int gpio_rcar_request(struct gpio_chip *chip, unsigned offset)
struct gpio_rcar_priv *p = gpiochip_get_data(chip);
int error;
error = pm_runtime_get_sync(&p->pdev->dev);
error = pm_runtime_get_sync(p->dev);
if (error < 0)
return error;
error = pinctrl_gpio_request(chip->base + offset);
if (error)
pm_runtime_put(&p->pdev->dev);
pm_runtime_put(p->dev);
return error;
}
......@@ -275,7 +266,7 @@ static void gpio_rcar_free(struct gpio_chip *chip, unsigned offset)
*/
gpio_rcar_config_general_input_output_mode(chip, offset, false);
pm_runtime_put(&p->pdev->dev);
pm_runtime_put(p->dev);
}
static int gpio_rcar_get_direction(struct gpio_chip *chip, unsigned int offset)
......@@ -406,21 +397,20 @@ MODULE_DEVICE_TABLE(of, gpio_rcar_of_table);
static int gpio_rcar_parse_dt(struct gpio_rcar_priv *p, unsigned int *npins)
{
struct device_node *np = p->pdev->dev.of_node;
struct device_node *np = p->dev->of_node;
const struct gpio_rcar_info *info;
struct of_phandle_args args;
int ret;
info = of_device_get_match_data(&p->pdev->dev);
info = of_device_get_match_data(p->dev);
ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, 0, &args);
*npins = ret == 0 ? args.args[2] : RCAR_MAX_GPIO_PER_BANK;
p->has_both_edge_trigger = info->has_both_edge_trigger;
if (*npins == 0 || *npins > RCAR_MAX_GPIO_PER_BANK) {
dev_warn(&p->pdev->dev,
"Invalid number of gpio lines %u, using %u\n", *npins,
RCAR_MAX_GPIO_PER_BANK);
dev_warn(p->dev, "Invalid number of gpio lines %u, using %u\n",
*npins, RCAR_MAX_GPIO_PER_BANK);
*npins = RCAR_MAX_GPIO_PER_BANK;
}
......@@ -442,7 +432,7 @@ static int gpio_rcar_probe(struct platform_device *pdev)
if (!p)
return -ENOMEM;
p->pdev = pdev;
p->dev = dev;
spin_lock_init(&p->lock);
/* Get device configuration from DT node */
......
// SPDX-License-Identifier: GPL-2.0
/*
* SAMA5D2 PIOBU GPIO controller
*
* Copyright (C) 2018 Microchip Technology Inc. and its subsidiaries
*
* Author: Andrei Stefanescu <andrei.stefanescu@microchip.com>
*
*/
#include <linux/bits.h>
#include <linux/gpio/driver.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#define PIOBU_NUM 8
#define PIOBU_REG_SIZE 4
/*
* backup mode protection register for tamper detection
* normal mode protection register for tamper detection
* wakeup signal generation
*/
#define PIOBU_BMPR 0x7C
#define PIOBU_NMPR 0x80
#define PIOBU_WKPR 0x90
#define PIOBU_BASE 0x18 /* PIOBU offset from SECUMOD base register address. */
#define PIOBU_DET_OFFSET 16
/* In the datasheet this bit is called OUTPUT */
#define PIOBU_DIRECTION BIT(8)
#define PIOBU_OUT BIT(8)
#define PIOBU_IN 0
#define PIOBU_SOD BIT(9)
#define PIOBU_PDS BIT(10)
#define PIOBU_HIGH BIT(9)
#define PIOBU_LOW 0
struct sama5d2_piobu {
struct gpio_chip chip;
struct regmap *regmap;
};
/**
* sama5d2_piobu_setup_pin() - prepares a pin for set_direction call
*
* Do not consider pin for tamper detection (normal and backup modes)
* Do not consider pin as tamper wakeup interrupt source
*/
static int sama5d2_piobu_setup_pin(struct gpio_chip *chip, unsigned int pin)
{
int ret;
struct sama5d2_piobu *piobu = container_of(chip, struct sama5d2_piobu,
chip);
unsigned int mask = BIT(PIOBU_DET_OFFSET + pin);
ret = regmap_update_bits(piobu->regmap, PIOBU_BMPR, mask, 0);
if (ret)
return ret;
ret = regmap_update_bits(piobu->regmap, PIOBU_NMPR, mask, 0);
if (ret)
return ret;
return regmap_update_bits(piobu->regmap, PIOBU_WKPR, mask, 0);
}
/**
* sama5d2_piobu_write_value() - writes value & mask at the pin's PIOBU register
*/
static int sama5d2_piobu_write_value(struct gpio_chip *chip, unsigned int pin,
unsigned int mask, unsigned int value)
{
int reg;
struct sama5d2_piobu *piobu = container_of(chip, struct sama5d2_piobu,
chip);
reg = PIOBU_BASE + pin * PIOBU_REG_SIZE;
return regmap_update_bits(piobu->regmap, reg, mask, value);
}
/**
* sama5d2_piobu_read_value() - read the value with masking from the pin's PIOBU
* register
*/
static int sama5d2_piobu_read_value(struct gpio_chip *chip, unsigned int pin,
unsigned int mask)
{
struct sama5d2_piobu *piobu = container_of(chip, struct sama5d2_piobu,
chip);
unsigned int val, reg;
int ret;
reg = PIOBU_BASE + pin * PIOBU_REG_SIZE;
ret = regmap_read(piobu->regmap, reg, &val);
if (ret < 0)
return ret;
return val & mask;
}
/**
* sama5d2_piobu_set_direction() - mark pin as input or output
*/
static int sama5d2_piobu_set_direction(struct gpio_chip *chip,
unsigned int direction,
unsigned int pin)
{
return sama5d2_piobu_write_value(chip, pin, PIOBU_DIRECTION, direction);
}
/**
* sama5d2_piobu_get_direction() - gpiochip get_direction
*/
static int sama5d2_piobu_get_direction(struct gpio_chip *chip,
unsigned int pin)
{
int ret = sama5d2_piobu_read_value(chip, pin, PIOBU_DIRECTION);
if (ret < 0)
return ret;
return (ret == PIOBU_IN) ? 1 : 0;
}
/**
* sama5d2_piobu_direction_input() - gpiochip direction_input
*/
static int sama5d2_piobu_direction_input(struct gpio_chip *chip,
unsigned int pin)
{
return sama5d2_piobu_set_direction(chip, PIOBU_IN, pin);
}
/**
* sama5d2_piobu_direction_output() - gpiochip direction_output
*/
static int sama5d2_piobu_direction_output(struct gpio_chip *chip,
unsigned int pin, int value)
{
return sama5d2_piobu_set_direction(chip, PIOBU_OUT, pin);
}
/**
* sama5d2_piobu_get() - gpiochip get
*/
static int sama5d2_piobu_get(struct gpio_chip *chip, unsigned int pin)
{
/* if pin is input, read value from PDS else read from SOD */
int ret = sama5d2_piobu_get_direction(chip, pin);
if (ret == 1)
ret = sama5d2_piobu_read_value(chip, pin, PIOBU_PDS);
else if (!ret)
ret = sama5d2_piobu_read_value(chip, pin, PIOBU_SOD);
if (ret < 0)
return ret;
return !!ret;
}
/**
* sama5d2_piobu_set() - gpiochip set
*/
static void sama5d2_piobu_set(struct gpio_chip *chip, unsigned int pin,
int value)
{
if (!value)
value = PIOBU_LOW;
else
value = PIOBU_HIGH;
sama5d2_piobu_write_value(chip, pin, PIOBU_SOD, value);
}
static int sama5d2_piobu_probe(struct platform_device *pdev)
{
struct sama5d2_piobu *piobu;
int ret, i;
piobu = devm_kzalloc(&pdev->dev, sizeof(*piobu), GFP_KERNEL);
if (!piobu)
return -ENOMEM;
platform_set_drvdata(pdev, piobu);
piobu->chip.label = pdev->name;
piobu->chip.parent = &pdev->dev;
piobu->chip.of_node = pdev->dev.of_node;
piobu->chip.owner = THIS_MODULE,
piobu->chip.get_direction = sama5d2_piobu_get_direction,
piobu->chip.direction_input = sama5d2_piobu_direction_input,
piobu->chip.direction_output = sama5d2_piobu_direction_output,
piobu->chip.get = sama5d2_piobu_get,
piobu->chip.set = sama5d2_piobu_set,
piobu->chip.base = -1,
piobu->chip.ngpio = PIOBU_NUM,
piobu->chip.can_sleep = 0,
piobu->regmap = syscon_node_to_regmap(pdev->dev.of_node);
if (IS_ERR(piobu->regmap)) {
dev_err(&pdev->dev, "Failed to get syscon regmap %ld\n",
PTR_ERR(piobu->regmap));
return PTR_ERR(piobu->regmap);
}
ret = devm_gpiochip_add_data(&pdev->dev, &piobu->chip, piobu);
if (ret) {
dev_err(&pdev->dev, "Failed to add gpiochip %d\n", ret);
return ret;
}
for (i = 0; i < PIOBU_NUM; ++i) {
ret = sama5d2_piobu_setup_pin(&piobu->chip, i);
if (ret) {
dev_err(&pdev->dev, "Failed to setup pin: %d %d\n",
i, ret);
return ret;
}
}
return 0;
}
static const struct of_device_id sama5d2_piobu_ids[] = {
{ .compatible = "atmel,sama5d2-secumod" },
{},
};
MODULE_DEVICE_TABLE(of, sama5d2_piobu_ids);
static struct platform_driver sama5d2_piobu_driver = {
.driver = {
.name = "sama5d2-piobu",
.of_match_table = of_match_ptr(sama5d2_piobu_ids)
},
.probe = sama5d2_piobu_probe,
};
module_platform_driver(sama5d2_piobu_driver);
MODULE_VERSION("1.0");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("SAMA5D2 PIOBU controller driver");
MODULE_AUTHOR("Andrei Stefanescu <andrei.stefanescu@microchip.com>");
// SPDX-License-Identifier: GPL-2.0
/*
* GPIO interface for Intel Poulsbo SCH
*
* Copyright (c) 2010 CompuLab Ltd
* Author: Denis Turischev <denis@compulab.co.il>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License 2 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/init.h>
#include <linux/acpi.h>
#include <linux/errno.h>
#include <linux/gpio/driver.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/io.h>
#include <linux/errno.h>
#include <linux/acpi.h>
#include <linux/platform_device.h>
#include <linux/pci_ids.h>
#include <linux/gpio/driver.h>
#include <linux/platform_device.h>
#define GEN 0x00
#define GIO 0x04
......@@ -235,5 +222,5 @@ module_platform_driver(sch_gpio_driver);
MODULE_AUTHOR("Denis Turischev <denis@compulab.co.il>");
MODULE_DESCRIPTION("GPIO interface for Intel Poulsbo SCH");
MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:sch_gpio");
......@@ -188,7 +188,7 @@ static void sch311x_gpio_set(struct gpio_chip *chip, unsigned offset,
struct sch311x_gpio_block *block = gpiochip_get_data(chip);
spin_lock(&block->lock);
__sch311x_gpio_set(block, offset, value);
__sch311x_gpio_set(block, offset, value);
spin_unlock(&block->lock);
}
......
// SPDX-License-Identifier: GPL-2.0
/*
* GPIO interface for Intel Sodaville SoCs.
*
* Copyright (c) 2010, 2011 Intel Corporation
*
* Author: Hans J. Koch <hjk@linutronix.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License 2 as published
* by the Free Software Foundation.
*
*/
#include <linux/errno.h>
#include <linux/gpio/driver.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/of_irq.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/of_irq.h>
#include <linux/gpio/driver.h>
#define DRV_NAME "sdv_gpio"
#define SDV_NUM_PUB_GPIOS 12
......@@ -80,18 +76,15 @@ static int sdv_gpio_pub_set_type(struct irq_data *d, unsigned int type)
static irqreturn_t sdv_gpio_pub_irq_handler(int irq, void *data)
{
struct sdv_gpio_chip_data *sd = data;
u32 irq_stat = readl(sd->gpio_pub_base + GPSTR);
unsigned long irq_stat = readl(sd->gpio_pub_base + GPSTR);
int irq_bit;
irq_stat &= readl(sd->gpio_pub_base + GPIO_INT);
if (!irq_stat)
return IRQ_NONE;
while (irq_stat) {
u32 irq_bit = __fls(irq_stat);
irq_stat &= ~BIT(irq_bit);
for_each_set_bit(irq_bit, &irq_stat, 32)
generic_handle_irq(irq_find_mapping(sd->id, irq_bit));
}
return IRQ_HANDLED;
}
......@@ -155,8 +148,10 @@ static int sdv_register_irqsupport(struct sdv_gpio_chip_data *sd,
* we unmask & ACK the IRQ before the source of the interrupt is gone
* then the interrupt is active again.
*/
sd->gc = irq_alloc_generic_chip("sdv-gpio", 1, sd->irq_base,
sd->gpio_pub_base, handle_fasteoi_irq);
sd->gc = devm_irq_alloc_generic_chip(&pdev->dev, "sdv-gpio", 1,
sd->irq_base,
sd->gpio_pub_base,
handle_fasteoi_irq);
if (!sd->gc)
return -ENOMEM;
......@@ -186,70 +181,52 @@ static int sdv_gpio_probe(struct pci_dev *pdev,
const struct pci_device_id *pci_id)
{
struct sdv_gpio_chip_data *sd;
unsigned long addr;
const void *prop;
int len;
int ret;
u32 mux_val;
sd = kzalloc(sizeof(struct sdv_gpio_chip_data), GFP_KERNEL);
sd = devm_kzalloc(&pdev->dev, sizeof(*sd), GFP_KERNEL);
if (!sd)
return -ENOMEM;
ret = pci_enable_device(pdev);
ret = pcim_enable_device(pdev);
if (ret) {
dev_err(&pdev->dev, "can't enable device.\n");
goto done;
return ret;
}
ret = pci_request_region(pdev, GPIO_BAR, DRV_NAME);
ret = pcim_iomap_regions(pdev, 1 << GPIO_BAR, DRV_NAME);
if (ret) {
dev_err(&pdev->dev, "can't alloc PCI BAR #%d\n", GPIO_BAR);
goto disable_pci;
return ret;
}
addr = pci_resource_start(pdev, GPIO_BAR);
if (!addr) {
ret = -ENODEV;
goto release_reg;
}
sd->gpio_pub_base = ioremap(addr, pci_resource_len(pdev, GPIO_BAR));
sd->gpio_pub_base = pcim_iomap_table(pdev)[GPIO_BAR];
prop = of_get_property(pdev->dev.of_node, "intel,muxctl", &len);
if (prop && len == 4) {
mux_val = of_read_number(prop, 1);
ret = of_property_read_u32(pdev->dev.of_node, "intel,muxctl", &mux_val);
if (!ret)
writel(mux_val, sd->gpio_pub_base + GPMUXCTL);
}
ret = bgpio_init(&sd->chip, &pdev->dev, 4,
sd->gpio_pub_base + GPINR, sd->gpio_pub_base + GPOUTR,
NULL, sd->gpio_pub_base + GPOER, NULL, 0);
if (ret)
goto unmap;
return ret;
sd->chip.ngpio = SDV_NUM_PUB_GPIOS;
ret = gpiochip_add_data(&sd->chip, sd);
ret = devm_gpiochip_add_data(&pdev->dev, &sd->chip, sd);
if (ret < 0) {
dev_err(&pdev->dev, "gpiochip_add() failed.\n");
goto unmap;
return ret;
}
ret = sdv_register_irqsupport(sd, pdev);
if (ret)
goto unmap;
return ret;
pci_set_drvdata(pdev, sd);
dev_info(&pdev->dev, "Sodaville GPIO driver registered.\n");
return 0;
unmap:
iounmap(sd->gpio_pub_base);
release_reg:
pci_release_region(pdev, GPIO_BAR);
disable_pci:
pci_disable_device(pdev);
done:
kfree(sd);
return ret;
}
static const struct pci_device_id sdv_gpio_pci_ids[] = {
......
......@@ -404,8 +404,7 @@ static void tegra_gpio_irq_handler(struct irq_desc *desc)
#ifdef CONFIG_PM_SLEEP
static int tegra_gpio_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct tegra_gpio_info *tgi = platform_get_drvdata(pdev);
struct tegra_gpio_info *tgi = dev_get_drvdata(dev);
unsigned long flags;
unsigned int b, p;
......@@ -444,8 +443,7 @@ static int tegra_gpio_resume(struct device *dev)
static int tegra_gpio_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct tegra_gpio_info *tgi = platform_get_drvdata(pdev);
struct tegra_gpio_info *tgi = dev_get_drvdata(dev);
unsigned long flags;
unsigned int b, p;
......
......@@ -279,7 +279,7 @@ static void tegra186_irq_unmask(struct irq_data *data)
writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG);
}
static int tegra186_irq_set_type(struct irq_data *data, unsigned int flow)
static int tegra186_irq_set_type(struct irq_data *data, unsigned int type)
{
struct tegra_gpio *gpio = irq_data_get_irq_chip_data(data);
void __iomem *base;
......@@ -293,7 +293,7 @@ static int tegra186_irq_set_type(struct irq_data *data, unsigned int flow)
value &= ~TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_MASK;
value &= ~TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_LEVEL;
switch (flow & IRQ_TYPE_SENSE_MASK) {
switch (type & IRQ_TYPE_SENSE_MASK) {
case IRQ_TYPE_NONE:
break;
......@@ -325,7 +325,7 @@ static int tegra186_irq_set_type(struct irq_data *data, unsigned int flow)
writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG);
if ((flow & IRQ_TYPE_EDGE_BOTH) == 0)
if ((type & IRQ_TYPE_EDGE_BOTH) == 0)
irq_set_handler_locked(data, handle_level_irq);
else
irq_set_handler_locked(data, handle_edge_irq);
......
/*
* Copyright (C) 2017 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
// SPDX-License-Identifier: GPL-2.0
//
// Copyright (C) 2017 Socionext Inc.
// Author: Masahiro Yamada <yamada.masahiro@socionext.com>
#include <linux/bits.h>
#include <linux/gpio/driver.h>
......
......@@ -7,6 +7,7 @@
* Author: Stefan Agner <stefan@agner.ch>.
*/
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/gpio/driver.h>
#include <linux/init.h>
......@@ -32,6 +33,8 @@ struct vf610_gpio_port {
void __iomem *gpio_base;
const struct fsl_gpio_soc_data *sdata;
u8 irqc[VF610_GPIO_PER_PORT];
struct clk *clk_port;
struct clk *clk_gpio;
int irq;
};
......@@ -271,6 +274,33 @@ static int vf610_gpio_probe(struct platform_device *pdev)
if (port->irq < 0)
return port->irq;
port->clk_port = devm_clk_get(&pdev->dev, "port");
if (!IS_ERR(port->clk_port)) {
ret = clk_prepare_enable(port->clk_port);
if (ret)
return ret;
} else if (port->clk_port == ERR_PTR(-EPROBE_DEFER)) {
/*
* Percolate deferrals, for anything else,
* just live without the clocking.
*/
return PTR_ERR(port->clk_port);
}
port->clk_gpio = devm_clk_get(&pdev->dev, "gpio");
if (!IS_ERR(port->clk_gpio)) {
ret = clk_prepare_enable(port->clk_gpio);
if (ret) {
clk_disable_unprepare(port->clk_port);
return ret;
}
} else if (port->clk_gpio == ERR_PTR(-EPROBE_DEFER)) {
clk_disable_unprepare(port->clk_port);
return PTR_ERR(port->clk_gpio);
}
platform_set_drvdata(pdev, port);
gc = &port->gc;
gc->of_node = np;
gc->parent = dev;
......@@ -305,12 +335,26 @@ static int vf610_gpio_probe(struct platform_device *pdev)
return 0;
}
static int vf610_gpio_remove(struct platform_device *pdev)
{
struct vf610_gpio_port *port = platform_get_drvdata(pdev);
gpiochip_remove(&port->gc);
if (!IS_ERR(port->clk_port))
clk_disable_unprepare(port->clk_port);
if (!IS_ERR(port->clk_gpio))
clk_disable_unprepare(port->clk_gpio);
return 0;
}
static struct platform_driver vf610_gpio_driver = {
.driver = {
.name = "gpio-vf610",
.of_match_table = vf610_gpio_dt_ids,
},
.probe = vf610_gpio_probe,
.remove = vf610_gpio_remove,
};
builtin_platform_driver(vf610_gpio_driver);
......@@ -169,7 +169,7 @@ static int ws16c48_gpio_get_multiple(struct gpio_chip *chip,
port_state = inb(ws16c48gpio->base + i);
/* store acquired bits at respective bits array offset */
bits[word_index] |= port_state << word_offset;
bits[word_index] |= (port_state << word_offset) & word_mask;
}
return 0;
......
......@@ -357,6 +357,28 @@ static int zynq_gpio_dir_out(struct gpio_chip *chip, unsigned int pin,
return 0;
}
/**
* zynq_gpio_get_direction - Read the direction of the specified GPIO pin
* @chip: gpio_chip instance to be worked on
* @pin: gpio pin number within the device
*
* This function returns the direction of the specified GPIO.
*
* Return: 0 for output, 1 for input
*/
static int zynq_gpio_get_direction(struct gpio_chip *chip, unsigned int pin)
{
u32 reg;
unsigned int bank_num, bank_pin_num;
struct zynq_gpio *gpio = gpiochip_get_data(chip);
zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio);
reg = readl_relaxed(gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
return !(reg & BIT(bank_pin_num));
}
/**
* zynq_gpio_irq_mask - Disable the interrupts for a gpio pin
* @irq_data: per irq and chip data passed down to chip functions
......@@ -693,8 +715,7 @@ static int __maybe_unused zynq_gpio_resume(struct device *dev)
static int __maybe_unused zynq_gpio_runtime_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct zynq_gpio *gpio = platform_get_drvdata(pdev);
struct zynq_gpio *gpio = dev_get_drvdata(dev);
clk_disable_unprepare(gpio->clk);
......@@ -703,8 +724,7 @@ static int __maybe_unused zynq_gpio_runtime_suspend(struct device *dev)
static int __maybe_unused zynq_gpio_runtime_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct zynq_gpio *gpio = platform_get_drvdata(pdev);
struct zynq_gpio *gpio = dev_get_drvdata(dev);
return clk_prepare_enable(gpio->clk);
}
......@@ -827,6 +847,7 @@ static int zynq_gpio_probe(struct platform_device *pdev)
chip->free = zynq_gpio_free;
chip->direction_input = zynq_gpio_dir_in;
chip->direction_output = zynq_gpio_dir_out;
chip->get_direction = zynq_gpio_get_direction;
chip->base = of_alias_get_id(pdev->dev.of_node, "gpio");
chip->ngpio = gpio->p_data->ngpio;
......
......@@ -217,7 +217,7 @@ static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares,
if (!handler)
return AE_OK;
desc = gpiochip_request_own_desc(chip, pin, "ACPI:Event");
desc = gpiochip_request_own_desc(chip, pin, "ACPI:Event", 0);
if (IS_ERR(desc)) {
dev_err(chip->parent, "Failed to request GPIO\n");
return AE_ERROR;
......@@ -913,23 +913,15 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
if (!found) {
enum gpiod_flags flags = acpi_gpio_to_gpiod_flags(agpio);
const char *label = "ACPI:OpRegion";
int err;
desc = gpiochip_request_own_desc(chip, pin, label);
desc = gpiochip_request_own_desc(chip, pin, label,
flags);
if (IS_ERR(desc)) {
status = AE_ERROR;
mutex_unlock(&achip->conn_lock);
goto out;
}
err = gpiod_configure_flags(desc, label, 0, flags);
if (err < 0) {
status = AE_NOT_CONFIGURED;
gpiochip_free_own_desc(desc);
mutex_unlock(&achip->conn_lock);
goto out;
}
conn = kzalloc(sizeof(*conn), GFP_KERNEL);
if (!conn) {
status = AE_NO_MEMORY;
......
// SPDX-License-Identifier: GPL-2.0
// SPDX-License-Identifier: GPL-2.0+
/*
* OF helpers for the GPIO API
*
......@@ -54,9 +54,31 @@ static struct gpio_desc *of_xlate_and_get_gpiod_flags(struct gpio_chip *chip,
}
static void of_gpio_flags_quirks(struct device_node *np,
const char *propname,
enum of_gpio_flags *flags,
int index)
{
/*
* Handle MMC "cd-inverted" and "wp-inverted" semantics.
*/
if (IS_ENABLED(CONFIG_MMC)) {
/*
* Active low is the default according to the
* SDHCI specification and the device tree
* bindings. However the code in the current
* kernel was written such that the phandle
* flags were always respected, and "cd-inverted"
* would invert the flag from the device phandle.
*/
if (!strcmp(propname, "cd-gpios")) {
if (of_property_read_bool(np, "cd-inverted"))
*flags ^= OF_GPIO_ACTIVE_LOW;
}
if (!strcmp(propname, "wp-gpios")) {
if (of_property_read_bool(np, "wp-inverted"))
*flags ^= OF_GPIO_ACTIVE_LOW;
}
}
/*
* Some GPIO fixed regulator quirks.
* Note that active low is the default.
......@@ -174,7 +196,7 @@ struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
goto out;
if (flags)
of_gpio_flags_quirks(np, flags, index);
of_gpio_flags_quirks(np, propname, flags, index);
pr_debug("%s: parsed '%s' property of node '%pOF[%d]' - status (%d)\n",
__func__, propname, np, index,
......
......@@ -1512,19 +1512,6 @@ static void devm_gpio_chip_release(struct device *dev, void *res)
gpiochip_remove(chip);
}
static int devm_gpio_chip_match(struct device *dev, void *res, void *data)
{
struct gpio_chip **r = res;
if (!r || !*r) {
WARN_ON(!r || !*r);
return 0;
}
return *r == data;
}
/**
* devm_gpiochip_add_data() - Resource manager gpiochip_add_data()
* @dev: pointer to the device that gpio_chip belongs to.
......@@ -1564,23 +1551,6 @@ int devm_gpiochip_add_data(struct device *dev, struct gpio_chip *chip,
}
EXPORT_SYMBOL_GPL(devm_gpiochip_add_data);
/**
* devm_gpiochip_remove() - Resource manager of gpiochip_remove()
* @dev: device for which which resource was allocated
* @chip: the chip to remove
*
* A gpio_chip with any GPIOs still requested may not be removed.
*/
void devm_gpiochip_remove(struct device *dev, struct gpio_chip *chip)
{
int ret;
ret = devres_release(dev, devm_gpio_chip_release,
devm_gpio_chip_match, chip);
WARN_ON(ret);
}
EXPORT_SYMBOL_GPL(devm_gpiochip_remove);
/**
* gpiochip_find() - iterator for locating a specific gpio_chip
* @data: data to pass to match function
......@@ -2299,6 +2269,12 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label)
unsigned long flags;
unsigned offset;
if (label) {
label = kstrdup_const(label, GFP_KERNEL);
if (!label)
return -ENOMEM;
}
spin_lock_irqsave(&gpio_lock, flags);
/* NOTE: gpio_request() can be called in early boot,
......@@ -2309,6 +2285,7 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label)
desc_set_label(desc, label ? : "?");
status = 0;
} else {
kfree_const(label);
status = -EBUSY;
goto done;
}
......@@ -2325,6 +2302,7 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label)
if (status < 0) {
desc_set_label(desc, NULL);
kfree_const(label);
clear_bit(FLAG_REQUESTED, &desc->flags);
goto done;
}
......@@ -2420,6 +2398,7 @@ static bool gpiod_free_commit(struct gpio_desc *desc)
chip->free(chip, gpio_chip_hwgpio(desc));
spin_lock_irqsave(&gpio_lock, flags);
}
kfree_const(desc->label);
desc_set_label(desc, NULL);
clear_bit(FLAG_ACTIVE_LOW, &desc->flags);
clear_bit(FLAG_REQUESTED, &desc->flags);
......@@ -2476,6 +2455,7 @@ EXPORT_SYMBOL_GPL(gpiochip_is_requested);
* @chip: GPIO chip
* @hwnum: hardware number of the GPIO for which to request the descriptor
* @label: label for the GPIO
* @flags: flags for this GPIO or 0 if default
*
* Function allows GPIO chip drivers to request and use their own GPIO
* descriptors via gpiolib API. Difference to gpiod_request() is that this
......@@ -2488,7 +2468,8 @@ EXPORT_SYMBOL_GPL(gpiochip_is_requested);
* code on failure.
*/
struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *chip, u16 hwnum,
const char *label)
const char *label,
enum gpiod_flags flags)
{
struct gpio_desc *desc = gpiochip_get_desc(chip, hwnum);
int err;
......@@ -2502,6 +2483,13 @@ struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *chip, u16 hwnum,
if (err < 0)
return ERR_PTR(err);
err = gpiod_configure_flags(desc, label, 0, flags);
if (err) {
chip_err(chip, "setup of own GPIO %s failed\n", label);
gpiod_free_commit(desc);
return ERR_PTR(err);
}
return desc;
}
EXPORT_SYMBOL_GPL(gpiochip_request_own_desc);
......@@ -3375,11 +3363,19 @@ EXPORT_SYMBOL_GPL(gpiod_cansleep);
* @desc: gpio to set the consumer name on
* @name: the new consumer name
*/
void gpiod_set_consumer_name(struct gpio_desc *desc, const char *name)
int gpiod_set_consumer_name(struct gpio_desc *desc, const char *name)
{
VALIDATE_DESC_VOID(desc);
/* Just overwrite whatever the previous name was */
desc->label = name;
VALIDATE_DESC(desc);
if (name) {
name = kstrdup_const(name, GFP_KERNEL);
if (!name)
return -ENOMEM;
}
kfree_const(desc->label);
desc_set_label(desc, name);
return 0;
}
EXPORT_SYMBOL_GPL(gpiod_set_consumer_name);
......@@ -4348,7 +4344,15 @@ int gpiod_hog(struct gpio_desc *desc, const char *name,
chip = gpiod_to_chip(desc);
hwnum = gpio_chip_hwgpio(desc);
local_desc = gpiochip_request_own_desc(chip, hwnum, name);
/*
* FIXME: not very elegant that we call gpiod_configure_flags()
* twice here (once inside gpiochip_request_own_desc() and
* again here), but the gpiochip_request_own_desc() is external
* and cannot really pass the lflags so this is the lesser evil
* at the moment. Pass zero as dflags on this first call so we
* don't screw anything up.
*/
local_desc = gpiochip_request_own_desc(chip, hwnum, name, 0);
if (IS_ERR(local_desc)) {
status = PTR_ERR(local_desc);
pr_err("requesting hog GPIO %s (chip %s, offset %d) failed, %d\n",
......
......@@ -1203,7 +1203,7 @@ static int __maybe_unused cp2112_allocate_irq(struct cp2112_device *dev,
return -EINVAL;
dev->desc[pin] = gpiochip_request_own_desc(&dev->gc, pin,
"HID/I2C:Event");
"HID/I2C:Event", 0);
if (IS_ERR(dev->desc[pin])) {
dev_err(dev->gc.parent, "Failed to request GPIO\n");
return PTR_ERR(dev->desc[pin]);
......
......@@ -21,6 +21,7 @@
#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/gpio/driver.h>
#include <linux/gpio/consumer.h> /* GPIO descriptor enum */
#include <linux/interrupt.h>
#include <linux/irqdomain.h>
#include <linux/platform_device.h>
......@@ -2170,7 +2171,8 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
unsigned int wait_pin = gpmc_s.wait_pin;
waitpin_desc = gpiochip_request_own_desc(&gpmc->gpio_chip,
wait_pin, "WAITPIN");
wait_pin, "WAITPIN",
0);
if (IS_ERR(waitpin_desc)) {
dev_err(&pdev->dev, "invalid wait-pin: %d\n", wait_pin);
ret = PTR_ERR(waitpin_desc);
......
......@@ -14,6 +14,34 @@
#include <dt-bindings/gpio/gpio.h>
/* GPIOs implemented by main GPIO controller */
#define TEGRA186_MAIN_GPIO_PORT_A 0
#define TEGRA186_MAIN_GPIO_PORT_B 1
#define TEGRA186_MAIN_GPIO_PORT_C 2
#define TEGRA186_MAIN_GPIO_PORT_D 3
#define TEGRA186_MAIN_GPIO_PORT_E 4
#define TEGRA186_MAIN_GPIO_PORT_F 5
#define TEGRA186_MAIN_GPIO_PORT_G 6
#define TEGRA186_MAIN_GPIO_PORT_H 7
#define TEGRA186_MAIN_GPIO_PORT_I 8
#define TEGRA186_MAIN_GPIO_PORT_J 9
#define TEGRA186_MAIN_GPIO_PORT_K 10
#define TEGRA186_MAIN_GPIO_PORT_L 11
#define TEGRA186_MAIN_GPIO_PORT_M 12
#define TEGRA186_MAIN_GPIO_PORT_N 13
#define TEGRA186_MAIN_GPIO_PORT_O 14
#define TEGRA186_MAIN_GPIO_PORT_P 15
#define TEGRA186_MAIN_GPIO_PORT_Q 16
#define TEGRA186_MAIN_GPIO_PORT_R 17
#define TEGRA186_MAIN_GPIO_PORT_T 18
#define TEGRA186_MAIN_GPIO_PORT_X 19
#define TEGRA186_MAIN_GPIO_PORT_Y 20
#define TEGRA186_MAIN_GPIO_PORT_BB 21
#define TEGRA186_MAIN_GPIO_PORT_CC 22
#define TEGRA186_MAIN_GPIO(port, offset) \
((TEGRA186_MAIN_GPIO_PORT_##port * 8) + offset)
/* need to keep these for backwards-compatibility */
#define TEGRA_MAIN_GPIO_PORT_A 0
#define TEGRA_MAIN_GPIO_PORT_B 1
#define TEGRA_MAIN_GPIO_PORT_C 2
......@@ -42,6 +70,19 @@
((TEGRA_MAIN_GPIO_PORT_##port * 8) + offset)
/* GPIOs implemented by AON GPIO controller */
#define TEGRA186_AON_GPIO_PORT_S 0
#define TEGRA186_AON_GPIO_PORT_U 1
#define TEGRA186_AON_GPIO_PORT_V 2
#define TEGRA186_AON_GPIO_PORT_W 3
#define TEGRA186_AON_GPIO_PORT_Z 4
#define TEGRA186_AON_GPIO_PORT_AA 5
#define TEGRA186_AON_GPIO_PORT_EE 6
#define TEGRA186_AON_GPIO_PORT_FF 7
#define TEGRA186_AON_GPIO(port, offset) \
((TEGRA186_AON_GPIO_PORT_##port * 8) + offset)
/* need to keep these for backwards-compatibility */
#define TEGRA_AON_GPIO_PORT_S 0
#define TEGRA_AON_GPIO_PORT_U 1
#define TEGRA_AON_GPIO_PORT_V 2
......
......@@ -163,7 +163,7 @@ int gpiod_is_active_low(const struct gpio_desc *desc);
int gpiod_cansleep(const struct gpio_desc *desc);
int gpiod_to_irq(const struct gpio_desc *desc);
void gpiod_set_consumer_name(struct gpio_desc *desc, const char *name);
int gpiod_set_consumer_name(struct gpio_desc *desc, const char *name);
/* Convert between the old gpio_ and new gpiod_ interfaces */
struct gpio_desc *gpio_to_desc(unsigned gpio);
......@@ -509,15 +509,17 @@ static inline int gpiod_to_irq(const struct gpio_desc *desc)
return -EINVAL;
}
static inline void gpiod_set_consumer_name(struct gpio_desc *desc, const char *name)
static inline int gpiod_set_consumer_name(struct gpio_desc *desc,
const char *name)
{
/* GPIO can never have been requested */
WARN_ON(1);
return -EINVAL;
}
static inline struct gpio_desc *gpio_to_desc(unsigned gpio)
{
return ERR_PTR(-EINVAL);
return NULL;
}
static inline int desc_to_gpio(const struct gpio_desc *desc)
......
......@@ -17,6 +17,7 @@ struct device_node;
struct seq_file;
struct gpio_device;
struct module;
enum gpiod_flags;
#ifdef CONFIG_GPIOLIB
......@@ -166,11 +167,6 @@ struct gpio_irq_chip {
*/
void (*irq_disable)(struct irq_data *data);
};
static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
{
return container_of(chip, struct gpio_irq_chip, chip);
}
#endif
/**
......@@ -422,7 +418,6 @@ static inline int gpiochip_add(struct gpio_chip *chip)
extern void gpiochip_remove(struct gpio_chip *chip);
extern int devm_gpiochip_add_data(struct device *dev, struct gpio_chip *chip,
void *data);
extern void devm_gpiochip_remove(struct device *dev, struct gpio_chip *chip);
extern struct gpio_chip *gpiochip_find(void *data,
int (*match)(struct gpio_chip *chip, void *data));
......@@ -610,7 +605,8 @@ gpiochip_remove_pin_ranges(struct gpio_chip *chip)
#endif /* CONFIG_PINCTRL */
struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *chip, u16 hwnum,
const char *label);
const char *label,
enum gpiod_flags flags);
void gpiochip_free_own_desc(struct gpio_desc *desc);
#else /* CONFIG_GPIOLIB */
......
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