Merge tag 'gpio-v4.11-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.11 cycle

  Core changes:

   - Augment fwnode_get_named_gpiod() to configure the GPIO pin
     immediately after requesting it like all other APIs do. This is a
     treewide change also updating all users.

   - Pass a GPIO label down to gpiod_request() from
     fwnode_get_named_gpiod(). This makes debugfs and the userspace ABI
     correctly reflect the current in-kernel consumer of a pin taken
     using this abstraction. This is a treewide change also updating all
     users.

   - Rename devm_get_gpiod_from_child() to
     devm_fwnode_get_gpiod_from_child() to reflect the fact that this
     function is operating on a fwnode object. This is a treewide change
     also updating all users.

   - Make it possible to take multiple GPIOs in a single hog of device
     tree hogs.

   - The refactorings switching GPIO chips to use the .set_config()
     callback using standard pin control properties and providing a
     backend into the pin control subsystem that were also merged into
     the pin control tree naturally appear here too.

  Testing instrumentation:

   - A whole slew of cleanups and improvements to the mockup GPIO
     driver. We now have an extended userspace test exercising the
     subsystem, and we can inject interrupts etc from userspace to fully
     test the core GPIO functionality.

  New drivers:

   - New driver for the Cortina Systems Gemini GPIO controller.

   - New driver for the Exar XR17V352/354/358 chips.

   - New driver for the ACCES PCI-IDIO-16 PCI GPIO card.

  Driver changes:

   - RCAR: set the irqchip parent device, add fine-grained runtime PM
     support.

   - pca953x: support optional RESET control line on the chip.

   - DaVinci: cleanups and simplifications. Add support for multiple
     instances.

   - .set_multiple() and naming of lines on more or less all of the
     ISA/PCI GPIO controllers.

   - mcp23s08: refactored to use regmap as a first step to further
     rewrites and modernizations"

* tag 'gpio-v4.11-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (61 commits)
  gpio: reintroduce devm_get_gpiod_from_child()
  gpio: pci-idio-16: Fix PCI BAR index
  gpio: pci-idio-16: Fix PCI device ID code
  gpio: mockup: implement event injecting over debugfs
  gpio: mockup: add a dummy irqchip
  gpio: mockup: implement naming the lines
  gpio: mockup: code shrink
  gpio: mockup: readability tweaks
  gpio: Add GPIO support for the ACCES PCI-IDIO-16
  gpio: Add the devm_fwnode_get_index_gpiod_from_child() helper
  gpio: Rename devm_get_gpiod_from_child()
  gpio: mcp23s08: Select REGMAP/REGMAP_I2C to fix build error
  gpio: ws16c48: Add support for GPIO names
  gpio: gpio-mm: Add support for GPIO names
  gpio: 104-idio-16: Add support for GPIO names
  gpio: 104-idi-48: Add support for GPIO names
  gpio: 104-dio-48e: Add support for GPIO names
  gpio: ws16c48: Remove unnecessary driver_data set
  gpio: gpio-mm: Remove unnecessary driver_data set
  gpio: 104-idio-16: Remove unnecessary driver_data set
  ...
This commit is contained in:
Linus Torvalds
2017-02-23 08:46:04 -08:00
37 changed files with 1871 additions and 628 deletions
@@ -0,0 +1,24 @@
Cortina Systems Gemini GPIO Controller
Required properties:
- compatible : Must be "cortina,gemini-gpio"
- reg : Should contain registers location and length
- interrupts : Should contain the interrupt line for the GPIO block
- gpio-controller : marks this as a GPIO controller
- #gpio-cells : Should be 2, see gpio/gpio.txt
- interrupt-controller : marks this as an interrupt controller
- #interrupt-cells : a standard two-cell interrupt flag, see
interrupt-controller/interrupts.txt
Example:
gpio@4d000000 {
compatible = "cortina,gemini-gpio";
reg = <0x4d000000 0x100>;
interrupts = <22 IRQ_TYPE_LEVEL_HIGH>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
};
@@ -29,6 +29,10 @@ Required properties:
onsemi,pca9654 onsemi,pca9654
exar,xra1202 exar,xra1202
Optional properties:
- reset-gpios: GPIO specification for the RESET input. This is an
active low signal to the PCA953x.
Example: Example:
@@ -187,10 +187,10 @@ gpio-controller's driver probe function.
Each GPIO hog definition is represented as a child node of the GPIO controller. Each GPIO hog definition is represented as a child node of the GPIO controller.
Required properties: Required properties:
- gpio-hog: A property specifying that this child node represent a GPIO hog. - gpio-hog: A property specifying that this child node represents a GPIO hog.
- gpios: Store the GPIO information (id, flags, ...). Shall contain the - gpios: Store the GPIO information (id, flags, ...) for each GPIO to
number of cells specified in its parent node (GPIO controller affect. Shall contain an integer multiple of the number of cells
node). specified in its parent node (GPIO controller node).
Only one of the following properties scanned in the order shown below. Only one of the following properties scanned in the order shown below.
This means that when multiple properties are present they will be searched This means that when multiple properties are present they will be searched
in the order presented below and the first match is taken as the intended in the order presented below and the first match is taken as the intended
+46 -9
View File
@@ -41,34 +41,71 @@ In the gpiolib framework each GPIO controller is packaged as a "struct
gpio_chip" (see linux/gpio/driver.h for its complete definition) with members gpio_chip" (see linux/gpio/driver.h for its complete definition) with members
common to each controller of that type: common to each controller of that type:
- methods to establish GPIO direction - methods to establish GPIO line direction
- methods used to access GPIO values - methods used to access GPIO line values
- method to return the IRQ number associated to a given GPIO - method to set electrical configuration to a a given GPIO line
- method to return the IRQ number associated to a given GPIO line
- flag saying whether calls to its methods may sleep - flag saying whether calls to its methods may sleep
- optional line names array to identify lines
- optional debugfs dump method (showing extra state like pullup config) - optional debugfs dump method (showing extra state like pullup config)
- optional base number (will be automatically assigned if omitted) - optional base number (will be automatically assigned if omitted)
- label for diagnostics and GPIOs mapping using platform data - optional label for diagnostics and GPIO chip mapping using platform data
The code implementing a gpio_chip should support multiple instances of the The code implementing a gpio_chip should support multiple instances of the
controller, possibly using the driver model. That code will configure each controller, possibly using the driver model. That code will configure each
gpio_chip and issue gpiochip_add(). Removing a GPIO controller should be rare; gpio_chip and issue gpiochip_add[_data]() or devm_gpiochip_add_data().
use gpiochip_remove() when it is unavoidable. Removing a GPIO controller should be rare; use [devm_]gpiochip_remove() when
it is unavoidable.
Most often a gpio_chip is part of an instance-specific structure with state not Often a gpio_chip is part of an instance-specific structure with states not
exposed by the GPIO interfaces, such as addressing, power management, and more. exposed by the GPIO interfaces, such as addressing, power management, and more.
Chips such as codecs will have complex non-GPIO state. Chips such as audio codecs will have complex non-GPIO states.
Any debugfs dump method should normally ignore signals which haven't been Any debugfs dump method should normally ignore signals which haven't been
requested as GPIOs. They can use gpiochip_is_requested(), which returns either requested as GPIOs. They can use gpiochip_is_requested(), which returns either
NULL or the label associated with that GPIO when it was requested. NULL or the label associated with that GPIO when it was requested.
RT_FULL: GPIO driver should not use spinlock_t or any sleepable APIs RT_FULL: the GPIO driver should not use spinlock_t or any sleepable APIs
(like PM runtime) in its gpio_chip implementation (.get/.set and direction (like PM runtime) in its gpio_chip implementation (.get/.set and direction
control callbacks) if it is expected to call GPIO APIs from atomic context control callbacks) if it is expected to call GPIO APIs from atomic context
on -RT (inside hard IRQ handlers and similar contexts). Normally this should on -RT (inside hard IRQ handlers and similar contexts). Normally this should
not be required. not be required.
GPIO electrical configuration
-----------------------------
GPIOs can be configured for several electrical modes of operation by using the
.set_config() callback. Currently this API supports setting debouncing and
single-ended modes (open drain/open source). These settings are described
below.
The .set_config() callback uses the same enumerators and configuration
semantics as the generic pin control drivers. This is not a coincidence: it is
possible to assign the .set_config() to the function gpiochip_generic_config()
which will result in pinctrl_gpio_set_config() being called and eventually
ending up in the pin control back-end "behind" the GPIO controller, usually
closer to the actual pins. This way the pin controller can manage the below
listed GPIO configurations.
GPIOs with debounce support
---------------------------
Debouncing is a configuration set to a pin indicating that it is connected to
a mechanical switch or button, or similar that may bounce. Bouncing means the
line is pulled high/low quickly at very short intervals for mechanical
reasons. This can result in the value being unstable or irqs fireing repeatedly
unless the line is debounced.
Debouncing in practice involves setting up a timer when something happens on
the line, wait a little while and then sample the line again, so see if it
still has the same value (low or high). This could also be repeated by a clever
state machine, waiting for a line to become stable. In either case, it sets
a certain number of milliseconds for debouncing, or just "on/off" if that time
is not configurable.
GPIOs with open drain/source support GPIOs with open drain/source support
------------------------------------ ------------------------------------
+6
View File
@@ -265,6 +265,12 @@ L: linux-iio@vger.kernel.org
S: Maintained S: Maintained
F: drivers/iio/counter/104-quad-8.c F: drivers/iio/counter/104-quad-8.c
ACCES PCI-IDIO-16 GPIO DRIVER
M: William Breathitt Gray <vilhelm.gray@gmail.com>
L: linux-gpio@vger.kernel.org
S: Maintained
F: drivers/gpio/gpio-pci-idio-16.c
ACENIC DRIVER ACENIC DRIVER
M: Jes Sorensen <jes@trained-monkey.org> M: Jes Sorensen <jes@trained-monkey.org>
L: linux-acenic@sunsite.dk L: linux-acenic@sunsite.dk
+29
View File
@@ -185,6 +185,13 @@ config GPIO_ETRAXFS
help help
Say yes here to support the GPIO controller on Axis ETRAX FS SoCs. Say yes here to support the GPIO controller on Axis ETRAX FS SoCs.
config GPIO_EXAR
tristate "Support for GPIO pins on XR17V352/354/358"
depends on SERIAL_8250_EXAR
help
Selecting this option will enable handling of GPIO pins present
on Exar XR17V352/354/358 chips.
config GPIO_GE_FPGA config GPIO_GE_FPGA
bool "GE FPGA based GPIO" bool "GE FPGA based GPIO"
depends on GE_FPGA depends on GE_FPGA
@@ -197,6 +204,15 @@ config GPIO_GE_FPGA
and write pin state) for GPIO implemented in a number of GE single and write pin state) for GPIO implemented in a number of GE single
board computers. board computers.
config GPIO_GEMINI
bool "Gemini GPIO"
depends on ARCH_GEMINI
depends on OF_GPIO
select GPIO_GENERIC
select GPIOLIB_IRQCHIP
help
Support for common GPIOs found in Cortina systems Gemini platforms.
config GPIO_GENERIC_PLATFORM config GPIO_GENERIC_PLATFORM
tristate "Generic memory-mapped GPIO controller support (MMIO platform device)" tristate "Generic memory-mapped GPIO controller support (MMIO platform device)"
select GPIO_GENERIC select GPIO_GENERIC
@@ -282,6 +298,8 @@ config GPIO_MOCKUP
tristate "GPIO Testing Driver" tristate "GPIO Testing Driver"
depends on GPIOLIB && SYSFS depends on GPIOLIB && SYSFS
select GPIO_SYSFS select GPIO_SYSFS
select GPIOLIB_IRQCHIP
select IRQ_WORK
help help
This enables GPIO Testing driver, which provides a way to test GPIO This enables GPIO Testing driver, which provides a way to test GPIO
subsystem through sysfs(or char device) and debugfs. GPIO_SYSFS subsystem through sysfs(or char device) and debugfs. GPIO_SYSFS
@@ -1141,6 +1159,15 @@ config GPIO_PCH
ML7223/ML7831 is companion chip for Intel Atom E6xx series. ML7223/ML7831 is companion chip for Intel Atom E6xx series.
ML7223/ML7831 is completely compatible for Intel EG20T PCH. ML7223/ML7831 is completely compatible for Intel EG20T PCH.
config GPIO_PCI_IDIO_16
tristate "ACCES PCI-IDIO-16 GPIO support"
select GPIOLIB_IRQCHIP
help
Enables GPIO support for the ACCES PCI-IDIO-16. An interrupt is
generated when any of the inputs change state (low to high or high to
low). Input filter control is not supported by this driver, and the
input filters are deactivated by this driver.
config GPIO_RDC321X config GPIO_RDC321X
tristate "RDC R-321x GPIO support" tristate "RDC R-321x GPIO support"
select MFD_CORE select MFD_CORE
@@ -1197,6 +1224,8 @@ config GPIO_MCP23S08
tristate "Microchip MCP23xxx I/O expander" tristate "Microchip MCP23xxx I/O expander"
depends on OF_GPIO depends on OF_GPIO
select GPIOLIB_IRQCHIP select GPIOLIB_IRQCHIP
select REGMAP_I2C if I2C
select REGMAP if SPI_MASTER
help help
SPI/I2C driver for Microchip MCP23S08/MCP23S17/MCP23008/MCP23017 SPI/I2C driver for Microchip MCP23S08/MCP23S17/MCP23008/MCP23017
I/O expanders. I/O expanders.
+3
View File
@@ -46,8 +46,10 @@ obj-$(CONFIG_GPIO_DWAPB) += gpio-dwapb.o
obj-$(CONFIG_GPIO_EM) += gpio-em.o obj-$(CONFIG_GPIO_EM) += gpio-em.o
obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o
obj-$(CONFIG_GPIO_ETRAXFS) += gpio-etraxfs.o obj-$(CONFIG_GPIO_ETRAXFS) += gpio-etraxfs.o
obj-$(CONFIG_GPIO_EXAR) += gpio-exar.o
obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o
obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o
obj-$(CONFIG_GPIO_GEMINI) += gpio-gemini.o
obj-$(CONFIG_GPIO_GPIO_MM) += gpio-gpio-mm.o obj-$(CONFIG_GPIO_GPIO_MM) += gpio-gpio-mm.o
obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o
obj-$(CONFIG_HTC_EGPIO) += gpio-htc-egpio.o obj-$(CONFIG_HTC_EGPIO) += gpio-htc-egpio.o
@@ -90,6 +92,7 @@ obj-$(CONFIG_GPIO_OMAP) += gpio-omap.o
obj-$(CONFIG_GPIO_PCA953X) += gpio-pca953x.o obj-$(CONFIG_GPIO_PCA953X) += gpio-pca953x.o
obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.o obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.o
obj-$(CONFIG_GPIO_PCH) += gpio-pch.o obj-$(CONFIG_GPIO_PCH) += gpio-pch.o
obj-$(CONFIG_GPIO_PCI_IDIO_16) += gpio-pci-idio-16.o
obj-$(CONFIG_GPIO_PISOSR) += gpio-pisosr.o obj-$(CONFIG_GPIO_PISOSR) += gpio-pisosr.o
obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o
obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o
+21 -11
View File
@@ -11,7 +11,7 @@
* *
* This file is based on kernel/irq/devres.c * This file is based on kernel/irq/devres.c
* *
* Copyright (c) 2011 John Crispin <blogic@openwrt.org> * Copyright (c) 2011 John Crispin <john@phrozen.org>
*/ */
#include <linux/module.h> #include <linux/module.h>
@@ -21,6 +21,8 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/gfp.h> #include <linux/gfp.h>
#include "gpiolib.h"
static void devm_gpiod_release(struct device *dev, void *res) static void devm_gpiod_release(struct device *dev, void *res)
{ {
struct gpio_desc **desc = res; struct gpio_desc **desc = res;
@@ -123,19 +125,26 @@ struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev,
EXPORT_SYMBOL(devm_gpiod_get_index); EXPORT_SYMBOL(devm_gpiod_get_index);
/** /**
* devm_get_gpiod_from_child - get a GPIO descriptor from a device's child node * devm_fwnode_get_index_gpiod_from_child - get a GPIO descriptor from a
* device's child node
* @dev: GPIO consumer * @dev: GPIO consumer
* @con_id: function within the GPIO consumer * @con_id: function within the GPIO consumer
* @index: index of the GPIO to obtain in the consumer
* @child: firmware node (child of @dev) * @child: firmware node (child of @dev)
* @flags: GPIO initialization flags
* *
* GPIO descriptors returned from this function are automatically disposed on * GPIO descriptors returned from this function are automatically disposed on
* driver detach. * driver detach.
*
* On successfull request the GPIO pin is configured in accordance with
* provided @flags.
*/ */
struct gpio_desc *devm_get_gpiod_from_child(struct device *dev, struct gpio_desc *devm_fwnode_get_index_gpiod_from_child(struct device *dev,
const char *con_id, const char *con_id, int index,
struct fwnode_handle *child) struct fwnode_handle *child,
enum gpiod_flags flags,
const char *label)
{ {
static const char * const suffixes[] = { "gpios", "gpio" };
char prop_name[32]; /* 32 is max size of property name */ char prop_name[32]; /* 32 is max size of property name */
struct gpio_desc **dr; struct gpio_desc **dr;
struct gpio_desc *desc; struct gpio_desc *desc;
@@ -146,15 +155,16 @@ struct gpio_desc *devm_get_gpiod_from_child(struct device *dev,
if (!dr) if (!dr)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
for (i = 0; i < ARRAY_SIZE(suffixes); i++) { for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
if (con_id) if (con_id)
snprintf(prop_name, sizeof(prop_name), "%s-%s", snprintf(prop_name, sizeof(prop_name), "%s-%s",
con_id, suffixes[i]); con_id, gpio_suffixes[i]);
else else
snprintf(prop_name, sizeof(prop_name), "%s", snprintf(prop_name, sizeof(prop_name), "%s",
suffixes[i]); gpio_suffixes[i]);
desc = fwnode_get_named_gpiod(child, prop_name); desc = fwnode_get_named_gpiod(child, prop_name, index, flags,
label);
if (!IS_ERR(desc) || (PTR_ERR(desc) != -ENOENT)) if (!IS_ERR(desc) || (PTR_ERR(desc) != -ENOENT))
break; break;
} }
@@ -168,7 +178,7 @@ struct gpio_desc *devm_get_gpiod_from_child(struct device *dev,
return desc; return desc;
} }
EXPORT_SYMBOL(devm_get_gpiod_from_child); EXPORT_SYMBOL(devm_fwnode_get_index_gpiod_from_child);
/** /**
* devm_gpiod_get_index_optional - Resource-managed gpiod_get_index_optional() * devm_gpiod_get_index_optional - Resource-managed gpiod_get_index_optional()
+66 -25
View File
@@ -48,7 +48,6 @@ MODULE_PARM_DESC(irq, "ACCES 104-DIO-48E interrupt line numbers");
* @control: Control registers state * @control: Control registers state
* @lock: synchronization lock to prevent I/O race conditions * @lock: synchronization lock to prevent I/O race conditions
* @base: base port address of the GPIO device * @base: base port address of the GPIO device
* @irq: Interrupt line number
* @irq_mask: I/O bits affected by interrupts * @irq_mask: I/O bits affected by interrupts
*/ */
struct dio48e_gpio { struct dio48e_gpio {
@@ -58,7 +57,6 @@ struct dio48e_gpio {
unsigned char control[2]; unsigned char control[2];
spinlock_t lock; spinlock_t lock;
unsigned base; unsigned base;
unsigned irq;
unsigned char irq_mask; unsigned char irq_mask;
}; };
@@ -204,6 +202,44 @@ static void dio48e_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
spin_unlock_irqrestore(&dio48egpio->lock, flags); spin_unlock_irqrestore(&dio48egpio->lock, flags);
} }
static void dio48e_gpio_set_multiple(struct gpio_chip *chip,
unsigned long *mask, unsigned long *bits)
{
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
unsigned int i;
const unsigned int gpio_reg_size = 8;
unsigned int port;
unsigned int out_port;
unsigned int bitmask;
unsigned long flags;
/* set bits are evaluated a gpio register size at a time */
for (i = 0; i < chip->ngpio; i += gpio_reg_size) {
/* no more set bits in this mask word; skip to the next word */
if (!mask[BIT_WORD(i)]) {
i = (BIT_WORD(i) + 1) * BITS_PER_LONG - gpio_reg_size;
continue;
}
port = i / gpio_reg_size;
out_port = (port > 2) ? port + 1 : port;
bitmask = mask[BIT_WORD(i)] & bits[BIT_WORD(i)];
spin_lock_irqsave(&dio48egpio->lock, flags);
/* update output state data and set device gpio register */
dio48egpio->out_state[port] &= ~mask[BIT_WORD(i)];
dio48egpio->out_state[port] |= bitmask;
outb(dio48egpio->out_state[port], dio48egpio->base + out_port);
spin_unlock_irqrestore(&dio48egpio->lock, flags);
/* prepare for next gpio register set */
mask[BIT_WORD(i)] >>= gpio_reg_size;
bits[BIT_WORD(i)] >>= gpio_reg_size;
}
}
static void dio48e_irq_ack(struct irq_data *data) static void dio48e_irq_ack(struct irq_data *data)
{ {
} }
@@ -302,6 +338,26 @@ static irqreturn_t dio48e_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
#define DIO48E_NGPIO 48
static const char *dio48e_names[DIO48E_NGPIO] = {
"PPI Group 0 Port A 0", "PPI Group 0 Port A 1", "PPI Group 0 Port A 2",
"PPI Group 0 Port A 3", "PPI Group 0 Port A 4", "PPI Group 0 Port A 5",
"PPI Group 0 Port A 6", "PPI Group 0 Port A 7", "PPI Group 0 Port B 0",
"PPI Group 0 Port B 1", "PPI Group 0 Port B 2", "PPI Group 0 Port B 3",
"PPI Group 0 Port B 4", "PPI Group 0 Port B 5", "PPI Group 0 Port B 6",
"PPI Group 0 Port B 7", "PPI Group 0 Port C 0", "PPI Group 0 Port C 1",
"PPI Group 0 Port C 2", "PPI Group 0 Port C 3", "PPI Group 0 Port C 4",
"PPI Group 0 Port C 5", "PPI Group 0 Port C 6", "PPI Group 0 Port C 7",
"PPI Group 1 Port A 0", "PPI Group 1 Port A 1", "PPI Group 1 Port A 2",
"PPI Group 1 Port A 3", "PPI Group 1 Port A 4", "PPI Group 1 Port A 5",
"PPI Group 1 Port A 6", "PPI Group 1 Port A 7", "PPI Group 1 Port B 0",
"PPI Group 1 Port B 1", "PPI Group 1 Port B 2", "PPI Group 1 Port B 3",
"PPI Group 1 Port B 4", "PPI Group 1 Port B 5", "PPI Group 1 Port B 6",
"PPI Group 1 Port B 7", "PPI Group 1 Port C 0", "PPI Group 1 Port C 1",
"PPI Group 1 Port C 2", "PPI Group 1 Port C 3", "PPI Group 1 Port C 4",
"PPI Group 1 Port C 5", "PPI Group 1 Port C 6", "PPI Group 1 Port C 7"
};
static int dio48e_probe(struct device *dev, unsigned int id) static int dio48e_probe(struct device *dev, unsigned int id)
{ {
struct dio48e_gpio *dio48egpio; struct dio48e_gpio *dio48egpio;
@@ -322,20 +378,19 @@ static int dio48e_probe(struct device *dev, unsigned int id)
dio48egpio->chip.parent = dev; dio48egpio->chip.parent = dev;
dio48egpio->chip.owner = THIS_MODULE; dio48egpio->chip.owner = THIS_MODULE;
dio48egpio->chip.base = -1; dio48egpio->chip.base = -1;
dio48egpio->chip.ngpio = 48; dio48egpio->chip.ngpio = DIO48E_NGPIO;
dio48egpio->chip.names = dio48e_names;
dio48egpio->chip.get_direction = dio48e_gpio_get_direction; dio48egpio->chip.get_direction = dio48e_gpio_get_direction;
dio48egpio->chip.direction_input = dio48e_gpio_direction_input; dio48egpio->chip.direction_input = dio48e_gpio_direction_input;
dio48egpio->chip.direction_output = dio48e_gpio_direction_output; dio48egpio->chip.direction_output = dio48e_gpio_direction_output;
dio48egpio->chip.get = dio48e_gpio_get; dio48egpio->chip.get = dio48e_gpio_get;
dio48egpio->chip.set = dio48e_gpio_set; dio48egpio->chip.set = dio48e_gpio_set;
dio48egpio->chip.set_multiple = dio48e_gpio_set_multiple;
dio48egpio->base = base[id]; dio48egpio->base = base[id];
dio48egpio->irq = irq[id];
spin_lock_init(&dio48egpio->lock); spin_lock_init(&dio48egpio->lock);
dev_set_drvdata(dev, dio48egpio); err = devm_gpiochip_add_data(dev, &dio48egpio->chip, dio48egpio);
err = gpiochip_add_data(&dio48egpio->chip, dio48egpio);
if (err) { if (err) {
dev_err(dev, "GPIO registering failed (%d)\n", err); dev_err(dev, "GPIO registering failed (%d)\n", err);
return err; return err;
@@ -360,29 +415,16 @@ static int dio48e_probe(struct device *dev, unsigned int id)
handle_edge_irq, IRQ_TYPE_NONE); handle_edge_irq, IRQ_TYPE_NONE);
if (err) { if (err) {
dev_err(dev, "Could not add irqchip (%d)\n", err); dev_err(dev, "Could not add irqchip (%d)\n", err);
goto err_gpiochip_remove; return err;
} }
err = request_irq(irq[id], dio48e_irq_handler, 0, name, dio48egpio); err = devm_request_irq(dev, irq[id], dio48e_irq_handler, 0, name,
dio48egpio);
if (err) { if (err) {
dev_err(dev, "IRQ handler registering failed (%d)\n", err); dev_err(dev, "IRQ handler registering failed (%d)\n", err);
goto err_gpiochip_remove; return err;
} }
return 0;
err_gpiochip_remove:
gpiochip_remove(&dio48egpio->chip);
return err;
}
static int dio48e_remove(struct device *dev, unsigned int id)
{
struct dio48e_gpio *const dio48egpio = dev_get_drvdata(dev);
free_irq(dio48egpio->irq, dio48egpio);
gpiochip_remove(&dio48egpio->chip);
return 0; return 0;
} }
@@ -391,7 +433,6 @@ static struct isa_driver dio48e_driver = {
.driver = { .driver = {
.name = "104-dio-48e" .name = "104-dio-48e"
}, },
.remove = dio48e_remove
}; };
module_isa_driver(dio48e_driver, num_dio48e); module_isa_driver(dio48e_driver, num_dio48e);
+19 -26
View File
@@ -47,7 +47,6 @@ MODULE_PARM_DESC(irq, "ACCES 104-IDI-48 interrupt line numbers");
* @ack_lock: synchronization lock to prevent IRQ handler race conditions * @ack_lock: synchronization lock to prevent IRQ handler race conditions
* @irq_mask: input bits affected by interrupts * @irq_mask: input bits affected by interrupts
* @base: base port address of the GPIO device * @base: base port address of the GPIO device
* @irq: Interrupt line number
* @cos_enb: Change-Of-State IRQ enable boundaries mask * @cos_enb: Change-Of-State IRQ enable boundaries mask
*/ */
struct idi_48_gpio { struct idi_48_gpio {
@@ -56,7 +55,6 @@ struct idi_48_gpio {
spinlock_t ack_lock; spinlock_t ack_lock;
unsigned char irq_mask[6]; unsigned char irq_mask[6];
unsigned base; unsigned base;
unsigned irq;
unsigned char cos_enb; unsigned char cos_enb;
}; };
@@ -219,6 +217,18 @@ static irqreturn_t idi_48_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
#define IDI48_NGPIO 48
static const char *idi48_names[IDI48_NGPIO] = {
"Bit 0 A", "Bit 1 A", "Bit 2 A", "Bit 3 A", "Bit 4 A", "Bit 5 A",
"Bit 6 A", "Bit 7 A", "Bit 8 A", "Bit 9 A", "Bit 10 A", "Bit 11 A",
"Bit 12 A", "Bit 13 A", "Bit 14 A", "Bit 15 A", "Bit 16 A", "Bit 17 A",
"Bit 18 A", "Bit 19 A", "Bit 20 A", "Bit 21 A", "Bit 22 A", "Bit 23 A",
"Bit 0 B", "Bit 1 B", "Bit 2 B", "Bit 3 B", "Bit 4 B", "Bit 5 B",
"Bit 6 B", "Bit 7 B", "Bit 8 B", "Bit 9 B", "Bit 10 B", "Bit 11 B",
"Bit 12 B", "Bit 13 B", "Bit 14 B", "Bit 15 B", "Bit 16 B", "Bit 17 B",
"Bit 18 B", "Bit 19 B", "Bit 20 B", "Bit 21 B", "Bit 22 B", "Bit 23 B"
};
static int idi_48_probe(struct device *dev, unsigned int id) static int idi_48_probe(struct device *dev, unsigned int id)
{ {
struct idi_48_gpio *idi48gpio; struct idi_48_gpio *idi48gpio;
@@ -239,19 +249,17 @@ static int idi_48_probe(struct device *dev, unsigned int id)
idi48gpio->chip.parent = dev; idi48gpio->chip.parent = dev;
idi48gpio->chip.owner = THIS_MODULE; idi48gpio->chip.owner = THIS_MODULE;
idi48gpio->chip.base = -1; idi48gpio->chip.base = -1;
idi48gpio->chip.ngpio = 48; idi48gpio->chip.ngpio = IDI48_NGPIO;
idi48gpio->chip.names = idi48_names;
idi48gpio->chip.get_direction = idi_48_gpio_get_direction; idi48gpio->chip.get_direction = idi_48_gpio_get_direction;
idi48gpio->chip.direction_input = idi_48_gpio_direction_input; idi48gpio->chip.direction_input = idi_48_gpio_direction_input;
idi48gpio->chip.get = idi_48_gpio_get; idi48gpio->chip.get = idi_48_gpio_get;
idi48gpio->base = base[id]; idi48gpio->base = base[id];
idi48gpio->irq = irq[id];
spin_lock_init(&idi48gpio->lock); spin_lock_init(&idi48gpio->lock);
spin_lock_init(&idi48gpio->ack_lock); spin_lock_init(&idi48gpio->ack_lock);
dev_set_drvdata(dev, idi48gpio); err = devm_gpiochip_add_data(dev, &idi48gpio->chip, idi48gpio);
err = gpiochip_add_data(&idi48gpio->chip, idi48gpio);
if (err) { if (err) {
dev_err(dev, "GPIO registering failed (%d)\n", err); dev_err(dev, "GPIO registering failed (%d)\n", err);
return err; return err;
@@ -265,30 +273,16 @@ static int idi_48_probe(struct device *dev, unsigned int id)
handle_edge_irq, IRQ_TYPE_NONE); handle_edge_irq, IRQ_TYPE_NONE);
if (err) { if (err) {
dev_err(dev, "Could not add irqchip (%d)\n", err); dev_err(dev, "Could not add irqchip (%d)\n", err);
goto err_gpiochip_remove; return err;
} }
err = request_irq(irq[id], idi_48_irq_handler, IRQF_SHARED, name, err = devm_request_irq(dev, irq[id], idi_48_irq_handler, IRQF_SHARED,
idi48gpio); name, idi48gpio);
if (err) { if (err) {
dev_err(dev, "IRQ handler registering failed (%d)\n", err); dev_err(dev, "IRQ handler registering failed (%d)\n", err);
goto err_gpiochip_remove; return err;
} }
return 0;
err_gpiochip_remove:
gpiochip_remove(&idi48gpio->chip);
return err;
}
static int idi_48_remove(struct device *dev, unsigned int id)
{
struct idi_48_gpio *const idi48gpio = dev_get_drvdata(dev);
free_irq(idi48gpio->irq, idi48gpio);
gpiochip_remove(&idi48gpio->chip);
return 0; return 0;
} }
@@ -297,7 +291,6 @@ static struct isa_driver idi_48_driver = {
.driver = { .driver = {
.name = "104-idi-48" .name = "104-idi-48"
}, },
.remove = idi_48_remove
}; };
module_isa_driver(idi_48_driver, num_idi_48); module_isa_driver(idi_48_driver, num_idi_48);
+35 -25
View File
@@ -46,7 +46,6 @@ MODULE_PARM_DESC(irq, "ACCES 104-IDIO-16 interrupt line numbers");
* @lock: synchronization lock to prevent I/O race conditions * @lock: synchronization lock to prevent I/O race conditions
* @irq_mask: I/O bits affected by interrupts * @irq_mask: I/O bits affected by interrupts
* @base: base port address of the GPIO device * @base: base port address of the GPIO device
* @irq: Interrupt line number
* @out_state: output bits state * @out_state: output bits state
*/ */
struct idio_16_gpio { struct idio_16_gpio {
@@ -54,7 +53,6 @@ struct idio_16_gpio {
spinlock_t lock; spinlock_t lock;
unsigned long irq_mask; unsigned long irq_mask;
unsigned base; unsigned base;
unsigned irq;
unsigned out_state; unsigned out_state;
}; };
@@ -116,6 +114,25 @@ static void idio_16_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
spin_unlock_irqrestore(&idio16gpio->lock, flags); spin_unlock_irqrestore(&idio16gpio->lock, flags);
} }
static void idio_16_gpio_set_multiple(struct gpio_chip *chip,
unsigned long *mask, unsigned long *bits)
{
struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
unsigned long flags;
spin_lock_irqsave(&idio16gpio->lock, flags);
idio16gpio->out_state &= ~*mask;
idio16gpio->out_state |= *mask & *bits;
if (*mask & 0xFF)
outb(idio16gpio->out_state, idio16gpio->base);
if ((*mask >> 8) & 0xFF)
outb(idio16gpio->out_state >> 8, idio16gpio->base + 4);
spin_unlock_irqrestore(&idio16gpio->lock, flags);
}
static void idio_16_irq_ack(struct irq_data *data) static void idio_16_irq_ack(struct irq_data *data)
{ {
} }
@@ -193,6 +210,14 @@ static irqreturn_t idio_16_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
#define IDIO_16_NGPIO 32
static const char *idio_16_names[IDIO_16_NGPIO] = {
"OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7",
"OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15",
"IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7",
"IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15"
};
static int idio_16_probe(struct device *dev, unsigned int id) static int idio_16_probe(struct device *dev, unsigned int id)
{ {
struct idio_16_gpio *idio16gpio; struct idio_16_gpio *idio16gpio;
@@ -213,21 +238,20 @@ static int idio_16_probe(struct device *dev, unsigned int id)
idio16gpio->chip.parent = dev; idio16gpio->chip.parent = dev;
idio16gpio->chip.owner = THIS_MODULE; idio16gpio->chip.owner = THIS_MODULE;
idio16gpio->chip.base = -1; idio16gpio->chip.base = -1;
idio16gpio->chip.ngpio = 32; idio16gpio->chip.ngpio = IDIO_16_NGPIO;
idio16gpio->chip.names = idio_16_names;
idio16gpio->chip.get_direction = idio_16_gpio_get_direction; idio16gpio->chip.get_direction = idio_16_gpio_get_direction;
idio16gpio->chip.direction_input = idio_16_gpio_direction_input; idio16gpio->chip.direction_input = idio_16_gpio_direction_input;
idio16gpio->chip.direction_output = idio_16_gpio_direction_output; idio16gpio->chip.direction_output = idio_16_gpio_direction_output;
idio16gpio->chip.get = idio_16_gpio_get; idio16gpio->chip.get = idio_16_gpio_get;
idio16gpio->chip.set = idio_16_gpio_set; idio16gpio->chip.set = idio_16_gpio_set;
idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;
idio16gpio->base = base[id]; idio16gpio->base = base[id];
idio16gpio->irq = irq[id];
idio16gpio->out_state = 0xFFFF; idio16gpio->out_state = 0xFFFF;
spin_lock_init(&idio16gpio->lock); spin_lock_init(&idio16gpio->lock);
dev_set_drvdata(dev, idio16gpio); err = devm_gpiochip_add_data(dev, &idio16gpio->chip, idio16gpio);
err = gpiochip_add_data(&idio16gpio->chip, idio16gpio);
if (err) { if (err) {
dev_err(dev, "GPIO registering failed (%d)\n", err); dev_err(dev, "GPIO registering failed (%d)\n", err);
return err; return err;
@@ -241,29 +265,16 @@ static int idio_16_probe(struct device *dev, unsigned int id)
handle_edge_irq, IRQ_TYPE_NONE); handle_edge_irq, IRQ_TYPE_NONE);
if (err) { if (err) {
dev_err(dev, "Could not add irqchip (%d)\n", err); dev_err(dev, "Could not add irqchip (%d)\n", err);
goto err_gpiochip_remove; return err;
} }
err = request_irq(irq[id], idio_16_irq_handler, 0, name, idio16gpio); err = devm_request_irq(dev, irq[id], idio_16_irq_handler, 0, name,
idio16gpio);
if (err) { if (err) {
dev_err(dev, "IRQ handler registering failed (%d)\n", err); dev_err(dev, "IRQ handler registering failed (%d)\n", err);
goto err_gpiochip_remove; return err;
} }
return 0;
err_gpiochip_remove:
gpiochip_remove(&idio16gpio->chip);
return err;
}
static int idio_16_remove(struct device *dev, unsigned int id)
{
struct idio_16_gpio *const idio16gpio = dev_get_drvdata(dev);
free_irq(idio16gpio->irq, idio16gpio);
gpiochip_remove(&idio16gpio->chip);
return 0; return 0;
} }
@@ -272,7 +283,6 @@ static struct isa_driver idio_16_driver = {
.driver = { .driver = {
.name = "104-idio-16" .name = "104-idio-16"
}, },
.remove = idio_16_remove
}; };
module_isa_driver(idio_16_driver, num_idio_16); module_isa_driver(idio_16_driver, num_idio_16);
+80 -97
View File
@@ -43,25 +43,7 @@ typedef struct irq_chip *(*gpio_get_irq_chip_cb_t)(unsigned int irq);
#define MAX_LABEL_SIZE 20 #define MAX_LABEL_SIZE 20
static void __iomem *gpio_base; static void __iomem *gpio_base;
static unsigned int offset_array[5] = {0x10, 0x38, 0x60, 0x88, 0xb0};
static struct davinci_gpio_regs __iomem *gpio2regs(unsigned gpio)
{
void __iomem *ptr;
if (gpio < 32 * 1)
ptr = gpio_base + 0x10;
else if (gpio < 32 * 2)
ptr = gpio_base + 0x38;
else if (gpio < 32 * 3)
ptr = gpio_base + 0x60;
else if (gpio < 32 * 4)
ptr = gpio_base + 0x88;
else if (gpio < 32 * 5)
ptr = gpio_base + 0xb0;
else
ptr = NULL;
return ptr;
}
static inline struct davinci_gpio_regs __iomem *irq2regs(struct irq_data *d) static inline struct davinci_gpio_regs __iomem *irq2regs(struct irq_data *d)
{ {
@@ -81,11 +63,13 @@ static inline int __davinci_direction(struct gpio_chip *chip,
unsigned offset, bool out, int value) unsigned offset, bool out, int value)
{ {
struct davinci_gpio_controller *d = gpiochip_get_data(chip); struct davinci_gpio_controller *d = gpiochip_get_data(chip);
struct davinci_gpio_regs __iomem *g = d->regs; struct davinci_gpio_regs __iomem *g;
unsigned long flags; unsigned long flags;
u32 temp; u32 temp;
u32 mask = 1 << offset; int bank = offset / 32;
u32 mask = __gpio_mask(offset);
g = d->regs[bank];
spin_lock_irqsave(&d->lock, flags); spin_lock_irqsave(&d->lock, flags);
temp = readl_relaxed(&g->dir); temp = readl_relaxed(&g->dir);
if (out) { if (out) {
@@ -121,9 +105,12 @@ davinci_direction_out(struct gpio_chip *chip, unsigned offset, int value)
static int davinci_gpio_get(struct gpio_chip *chip, unsigned offset) static int davinci_gpio_get(struct gpio_chip *chip, unsigned offset)
{ {
struct davinci_gpio_controller *d = gpiochip_get_data(chip); struct davinci_gpio_controller *d = gpiochip_get_data(chip);
struct davinci_gpio_regs __iomem *g = d->regs; struct davinci_gpio_regs __iomem *g;
int bank = offset / 32;
return !!((1 << offset) & readl_relaxed(&g->in_data)); g = d->regs[bank];
return !!(__gpio_mask(offset) & readl_relaxed(&g->in_data));
} }
/* /*
@@ -133,9 +120,13 @@ static void
davinci_gpio_set(struct gpio_chip *chip, unsigned offset, int value) davinci_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{ {
struct davinci_gpio_controller *d = gpiochip_get_data(chip); struct davinci_gpio_controller *d = gpiochip_get_data(chip);
struct davinci_gpio_regs __iomem *g = d->regs; struct davinci_gpio_regs __iomem *g;
int bank = offset / 32;
writel_relaxed((1 << offset), value ? &g->set_data : &g->clr_data); g = d->regs[bank];
writel_relaxed(__gpio_mask(offset),
value ? &g->set_data : &g->clr_data);
} }
static struct davinci_gpio_platform_data * static struct davinci_gpio_platform_data *
@@ -172,34 +163,13 @@ of_err:
return NULL; return NULL;
} }
#ifdef CONFIG_OF_GPIO
static int davinci_gpio_of_xlate(struct gpio_chip *gc,
const struct of_phandle_args *gpiospec,
u32 *flags)
{
struct davinci_gpio_controller *chips = dev_get_drvdata(gc->parent);
struct davinci_gpio_platform_data *pdata = dev_get_platdata(gc->parent);
if (gpiospec->args[0] > pdata->ngpio)
return -EINVAL;
if (gc != &chips[gpiospec->args[0] / 32].chip)
return -EINVAL;
if (flags)
*flags = gpiospec->args[1];
return gpiospec->args[0] % 32;
}
#endif
static int davinci_gpio_probe(struct platform_device *pdev) static int davinci_gpio_probe(struct platform_device *pdev)
{ {
int i, base; static int ctrl_num, bank_base;
int gpio, bank;
unsigned ngpio, nbank; unsigned ngpio, nbank;
struct davinci_gpio_controller *chips; struct davinci_gpio_controller *chips;
struct davinci_gpio_platform_data *pdata; struct davinci_gpio_platform_data *pdata;
struct davinci_gpio_regs __iomem *regs;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct resource *res; struct resource *res;
char label[MAX_LABEL_SIZE]; char label[MAX_LABEL_SIZE];
@@ -238,41 +208,31 @@ static int davinci_gpio_probe(struct platform_device *pdev)
if (IS_ERR(gpio_base)) if (IS_ERR(gpio_base))
return PTR_ERR(gpio_base); return PTR_ERR(gpio_base);
for (i = 0, base = 0; base < ngpio; i++, base += 32) { snprintf(label, MAX_LABEL_SIZE, "davinci_gpio.%d", ctrl_num++);
snprintf(label, MAX_LABEL_SIZE, "davinci_gpio.%d", i); chips->chip.label = devm_kstrdup(dev, label, GFP_KERNEL);
chips[i].chip.label = devm_kstrdup(dev, label, GFP_KERNEL); if (!chips->chip.label)
if (!chips[i].chip.label)
return -ENOMEM; return -ENOMEM;
chips[i].chip.direction_input = davinci_direction_in; chips->chip.direction_input = davinci_direction_in;
chips[i].chip.get = davinci_gpio_get; chips->chip.get = davinci_gpio_get;
chips[i].chip.direction_output = davinci_direction_out; chips->chip.direction_output = davinci_direction_out;
chips[i].chip.set = davinci_gpio_set; chips->chip.set = davinci_gpio_set;
chips[i].chip.base = base; chips->chip.ngpio = ngpio;
chips[i].chip.ngpio = ngpio - base; chips->chip.base = bank_base;
if (chips[i].chip.ngpio > 32)
chips[i].chip.ngpio = 32;
#ifdef CONFIG_OF_GPIO #ifdef CONFIG_OF_GPIO
chips[i].chip.of_gpio_n_cells = 2; chips->chip.of_gpio_n_cells = 2;
chips[i].chip.of_xlate = davinci_gpio_of_xlate; chips->chip.parent = dev;
chips[i].chip.parent = dev; chips->chip.of_node = dev->of_node;
chips[i].chip.of_node = dev->of_node;
#endif #endif
spin_lock_init(&chips[i].lock); spin_lock_init(&chips->lock);
bank_base += ngpio;
regs = gpio2regs(base); for (gpio = 0, bank = 0; gpio < ngpio; gpio += 32, bank++)
if (!regs) chips->regs[bank] = gpio_base + offset_array[bank];
return -ENXIO;
chips[i].regs = regs;
chips[i].set_data = &regs->set_data;
chips[i].clr_data = &regs->clr_data;
chips[i].in_data = &regs->in_data;
gpiochip_add_data(&chips[i].chip, &chips[i]);
}
gpiochip_add_data(&chips->chip, chips);
platform_set_drvdata(pdev, chips); platform_set_drvdata(pdev, chips);
davinci_gpio_irq_setup(pdev); davinci_gpio_irq_setup(pdev);
return 0; return 0;
@@ -333,16 +293,19 @@ static struct irq_chip gpio_irqchip = {
static void gpio_irq_handler(struct irq_desc *desc) static void gpio_irq_handler(struct irq_desc *desc)
{ {
unsigned int irq = irq_desc_get_irq(desc);
struct davinci_gpio_regs __iomem *g; struct davinci_gpio_regs __iomem *g;
u32 mask = 0xffff; u32 mask = 0xffff;
int bank_num;
struct davinci_gpio_controller *d; struct davinci_gpio_controller *d;
struct davinci_gpio_irq_data *irqdata;
d = (struct davinci_gpio_controller *)irq_desc_get_handler_data(desc); irqdata = (struct davinci_gpio_irq_data *)irq_desc_get_handler_data(desc);
g = (struct davinci_gpio_regs __iomem *)d->regs; bank_num = irqdata->bank_num;
g = irqdata->regs;
d = irqdata->chip;
/* we only care about one bank */ /* we only care about one bank */
if (irq & 1) if ((bank_num % 2) == 1)
mask <<= 16; mask <<= 16;
/* temporarily mask (level sensitive) parent IRQ */ /* temporarily mask (level sensitive) parent IRQ */
@@ -350,6 +313,7 @@ static void gpio_irq_handler(struct irq_desc *desc)
while (1) { while (1) {
u32 status; u32 status;
int bit; int bit;
irq_hw_number_t hw_irq;
/* ack any irqs */ /* ack any irqs */
status = readl_relaxed(&g->intstat) & mask; status = readl_relaxed(&g->intstat) & mask;
@@ -362,9 +326,13 @@ static void gpio_irq_handler(struct irq_desc *desc)
while (status) { while (status) {
bit = __ffs(status); bit = __ffs(status);
status &= ~BIT(bit); status &= ~BIT(bit);
/* Max number of gpios per controller is 144 so
* hw_irq will be in [0..143]
*/
hw_irq = (bank_num / 2) * 32 + bit;
generic_handle_irq( generic_handle_irq(
irq_find_mapping(d->irq_domain, irq_find_mapping(d->irq_domain, hw_irq));
d->chip.base + bit));
} }
} }
chained_irq_exit(irq_desc_get_chip(desc), desc); chained_irq_exit(irq_desc_get_chip(desc), desc);
@@ -376,7 +344,7 @@ static int gpio_to_irq_banked(struct gpio_chip *chip, unsigned offset)
struct davinci_gpio_controller *d = gpiochip_get_data(chip); struct davinci_gpio_controller *d = gpiochip_get_data(chip);
if (d->irq_domain) if (d->irq_domain)
return irq_create_mapping(d->irq_domain, d->chip.base + offset); return irq_create_mapping(d->irq_domain, offset);
else else
return -ENXIO; return -ENXIO;
} }
@@ -390,7 +358,7 @@ static int gpio_to_irq_unbanked(struct gpio_chip *chip, unsigned offset)
* can provide direct-mapped IRQs to AINTC (up to 32 GPIOs). * can provide direct-mapped IRQs to AINTC (up to 32 GPIOs).
*/ */
if (offset < d->gpio_unbanked) if (offset < d->gpio_unbanked)
return d->gpio_irq + offset; return d->base_irq + offset;
else else
return -ENODEV; return -ENODEV;
} }
@@ -403,7 +371,7 @@ static int gpio_irq_type_unbanked(struct irq_data *data, unsigned trigger)
d = (struct davinci_gpio_controller *)irq_data_get_irq_handler_data(data); d = (struct davinci_gpio_controller *)irq_data_get_irq_handler_data(data);
g = (struct davinci_gpio_regs __iomem *)d->regs; g = (struct davinci_gpio_regs __iomem *)d->regs;
mask = __gpio_mask(data->irq - d->gpio_irq); mask = __gpio_mask(data->irq - d->base_irq);
if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
return -EINVAL; return -EINVAL;
@@ -420,7 +388,9 @@ static int
davinci_gpio_irq_map(struct irq_domain *d, unsigned int irq, davinci_gpio_irq_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hw) irq_hw_number_t hw)
{ {
struct davinci_gpio_regs __iomem *g = gpio2regs(hw); struct davinci_gpio_controller *chips =
(struct davinci_gpio_controller *)d->host_data;
struct davinci_gpio_regs __iomem *g = chips->regs[hw / 32];
irq_set_chip_and_handler_name(irq, &gpio_irqchip, handle_simple_irq, irq_set_chip_and_handler_name(irq, &gpio_irqchip, handle_simple_irq,
"davinci_gpio"); "davinci_gpio");
@@ -478,6 +448,7 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev)
struct irq_domain *irq_domain = NULL; struct irq_domain *irq_domain = NULL;
const struct of_device_id *match; const struct of_device_id *match;
struct irq_chip *irq_chip; struct irq_chip *irq_chip;
struct davinci_gpio_irq_data *irqdata;
gpio_get_irq_chip_cb_t gpio_get_irq_chip; gpio_get_irq_chip_cb_t gpio_get_irq_chip;
/* /*
@@ -533,10 +504,8 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev)
* IRQs, while the others use banked IRQs, would need some setup * IRQs, while the others use banked IRQs, would need some setup
* tweaks to recognize hardware which can do that. * tweaks to recognize hardware which can do that.
*/ */
for (gpio = 0, bank = 0; gpio < ngpio; bank++, gpio += 32) { chips->chip.to_irq = gpio_to_irq_banked;
chips[bank].chip.to_irq = gpio_to_irq_banked; chips->irq_domain = irq_domain;
chips[bank].irq_domain = irq_domain;
}
/* /*
* AINTC can handle direct/unbanked IRQs for GPIOs, with the GPIO * AINTC can handle direct/unbanked IRQs for GPIOs, with the GPIO
@@ -545,9 +514,9 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev)
*/ */
if (pdata->gpio_unbanked) { if (pdata->gpio_unbanked) {
/* pass "bank 0" GPIO IRQs to AINTC */ /* pass "bank 0" GPIO IRQs to AINTC */
chips[0].chip.to_irq = gpio_to_irq_unbanked; chips->chip.to_irq = gpio_to_irq_unbanked;
chips[0].gpio_irq = bank_irq; chips->base_irq = bank_irq;
chips[0].gpio_unbanked = pdata->gpio_unbanked; chips->gpio_unbanked = pdata->gpio_unbanked;
binten = GENMASK(pdata->gpio_unbanked / 16, 0); binten = GENMASK(pdata->gpio_unbanked / 16, 0);
/* AINTC handles mask/unmask; GPIO handles triggering */ /* AINTC handles mask/unmask; GPIO handles triggering */
@@ -557,14 +526,14 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev)
irq_chip->irq_set_type = gpio_irq_type_unbanked; irq_chip->irq_set_type = gpio_irq_type_unbanked;
/* default trigger: both edges */ /* default trigger: both edges */
g = gpio2regs(0); g = chips->regs[0];
writel_relaxed(~0, &g->set_falling); writel_relaxed(~0, &g->set_falling);
writel_relaxed(~0, &g->set_rising); writel_relaxed(~0, &g->set_rising);
/* set the direct IRQs up to use that irqchip */ /* set the direct IRQs up to use that irqchip */
for (gpio = 0; gpio < pdata->gpio_unbanked; gpio++, irq++) { for (gpio = 0; gpio < pdata->gpio_unbanked; gpio++, irq++) {
irq_set_chip(irq, irq_chip); irq_set_chip(irq, irq_chip);
irq_set_handler_data(irq, &chips[gpio / 32]); irq_set_handler_data(irq, chips);
irq_set_status_flags(irq, IRQ_TYPE_EDGE_BOTH); irq_set_status_flags(irq, IRQ_TYPE_EDGE_BOTH);
} }
@@ -576,8 +545,11 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev)
* then chain through our own handler. * then chain through our own handler.
*/ */
for (gpio = 0, bank = 0; gpio < ngpio; bank++, bank_irq++, gpio += 16) { for (gpio = 0, bank = 0; gpio < ngpio; bank++, bank_irq++, gpio += 16) {
/* disabled by default, enabled only as needed */ /* disabled by default, enabled only as needed
g = gpio2regs(gpio); * There are register sets for 32 GPIOs. 2 banks of 16
* GPIOs are covered by each set of registers hence divide by 2
*/
g = chips->regs[bank / 2];
writel_relaxed(~0, &g->clr_falling); writel_relaxed(~0, &g->clr_falling);
writel_relaxed(~0, &g->clr_rising); writel_relaxed(~0, &g->clr_rising);
@@ -586,8 +558,19 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev)
* gpio irqs. Pass the irq bank's corresponding controller to * gpio irqs. Pass the irq bank's corresponding controller to
* the chained irq handler. * the chained irq handler.
*/ */
irqdata = devm_kzalloc(&pdev->dev,
sizeof(struct
davinci_gpio_irq_data),
GFP_KERNEL);
if (!irqdata)
return -ENOMEM;
irqdata->regs = g;
irqdata->bank_num = bank;
irqdata->chip = chips;
irq_set_chained_handler_and_data(bank_irq, gpio_irq_handler, irq_set_chained_handler_and_data(bank_irq, gpio_irq_handler,
&chips[gpio / 32]); irqdata);
binten |= BIT(bank); binten |= BIT(bank);
} }
+200
View File
@@ -0,0 +1,200 @@
/*
* GPIO driver for Exar XR17V35X chip
*
* Copyright (C) 2015 Sudip Mukherjee <sudip.mukherjee@codethink.co.uk>
*
* 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/bitops.h>
#include <linux/device.h>
#include <linux/gpio/driver.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#define EXAR_OFFSET_MPIOLVL_LO 0x90
#define EXAR_OFFSET_MPIOSEL_LO 0x93
#define EXAR_OFFSET_MPIOLVL_HI 0x96
#define EXAR_OFFSET_MPIOSEL_HI 0x99
#define DRIVER_NAME "gpio_exar"
static DEFINE_IDA(ida_index);
struct exar_gpio_chip {
struct gpio_chip gpio_chip;
struct mutex lock;
int index;
void __iomem *regs;
char name[20];
};
static void exar_update(struct gpio_chip *chip, unsigned int reg, int val,
unsigned int offset)
{
struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
int temp;
mutex_lock(&exar_gpio->lock);
temp = readb(exar_gpio->regs + reg);
temp &= ~BIT(offset);
if (val)
temp |= BIT(offset);
writeb(temp, exar_gpio->regs + reg);
mutex_unlock(&exar_gpio->lock);
}
static int exar_set_direction(struct gpio_chip *chip, int direction,
unsigned int offset)
{
unsigned int bank = offset / 8;
unsigned int addr;
addr = bank ? EXAR_OFFSET_MPIOSEL_HI : EXAR_OFFSET_MPIOSEL_LO;
exar_update(chip, addr, direction, offset % 8);
return 0;
}
static int exar_direction_output(struct gpio_chip *chip, unsigned int offset,
int value)
{
return exar_set_direction(chip, 0, offset);
}
static int exar_direction_input(struct gpio_chip *chip, unsigned int offset)
{
return exar_set_direction(chip, 1, offset);
}
static int exar_get(struct gpio_chip *chip, unsigned int reg)
{
struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
int value;
mutex_lock(&exar_gpio->lock);
value = readb(exar_gpio->regs + reg);
mutex_unlock(&exar_gpio->lock);
return !!value;
}
static int exar_get_direction(struct gpio_chip *chip, unsigned int offset)
{
unsigned int bank = offset / 8;
unsigned int addr;
int val;
addr = bank ? EXAR_OFFSET_MPIOSEL_HI : EXAR_OFFSET_MPIOSEL_LO;
val = exar_get(chip, addr) >> (offset % 8);
return !!val;
}
static int exar_get_value(struct gpio_chip *chip, unsigned int offset)
{
unsigned int bank = offset / 8;
unsigned int addr;
int val;
addr = bank ? EXAR_OFFSET_MPIOLVL_LO : EXAR_OFFSET_MPIOLVL_HI;
val = exar_get(chip, addr) >> (offset % 8);
return !!val;
}
static void exar_set_value(struct gpio_chip *chip, unsigned int offset,
int value)
{
unsigned int bank = offset / 8;
unsigned int addr;
addr = bank ? EXAR_OFFSET_MPIOLVL_HI : EXAR_OFFSET_MPIOLVL_LO;
exar_update(chip, addr, value, offset % 8);
}
static int gpio_exar_probe(struct platform_device *pdev)
{
struct pci_dev *pcidev = platform_get_drvdata(pdev);
struct exar_gpio_chip *exar_gpio;
void __iomem *p;
int index, ret;
if (pcidev->vendor != PCI_VENDOR_ID_EXAR)
return -ENODEV;
/*
* Map the pci device to get the register addresses.
* We will need to read and write those registers to control
* the GPIO pins.
* Using managed functions will save us from unmaping on exit.
* As the device is enabled using managed functions by the
* UART driver we can also use managed functions here.
*/
p = pcim_iomap(pcidev, 0, 0);
if (!p)
return -ENOMEM;
exar_gpio = devm_kzalloc(&pcidev->dev, sizeof(*exar_gpio), GFP_KERNEL);
if (!exar_gpio)
return -ENOMEM;
mutex_init(&exar_gpio->lock);
index = ida_simple_get(&ida_index, 0, 0, GFP_KERNEL);
sprintf(exar_gpio->name, "exar_gpio%d", index);
exar_gpio->gpio_chip.label = exar_gpio->name;
exar_gpio->gpio_chip.parent = &pcidev->dev;
exar_gpio->gpio_chip.direction_output = exar_direction_output;
exar_gpio->gpio_chip.direction_input = exar_direction_input;
exar_gpio->gpio_chip.get_direction = exar_get_direction;
exar_gpio->gpio_chip.get = exar_get_value;
exar_gpio->gpio_chip.set = exar_set_value;
exar_gpio->gpio_chip.base = -1;
exar_gpio->gpio_chip.ngpio = 16;
exar_gpio->regs = p;
exar_gpio->index = index;
ret = devm_gpiochip_add_data(&pcidev->dev,
&exar_gpio->gpio_chip, exar_gpio);
if (ret)
goto err_destroy;
platform_set_drvdata(pdev, exar_gpio);
return 0;
err_destroy:
ida_simple_remove(&ida_index, index);
mutex_destroy(&exar_gpio->lock);
return ret;
}
static int gpio_exar_remove(struct platform_device *pdev)
{
struct exar_gpio_chip *exar_gpio = platform_get_drvdata(pdev);
ida_simple_remove(&ida_index, exar_gpio->index);
mutex_destroy(&exar_gpio->lock);
return 0;
}
static struct platform_driver gpio_exar_driver = {
.probe = gpio_exar_probe,
.remove = gpio_exar_remove,
.driver = {
.name = DRIVER_NAME,
},
};
module_platform_driver(gpio_exar_driver);
MODULE_ALIAS("platform:" DRIVER_NAME);
MODULE_DESCRIPTION("Exar GPIO driver");
MODULE_AUTHOR("Sudip Mukherjee <sudip.mukherjee@codethink.co.uk>");
MODULE_LICENSE("GPL");
+236
View File
@@ -0,0 +1,236 @@
/*
* Gemini gpiochip and interrupt routines
* Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
*
* Based on arch/arm/mach-gemini/gpio.c:
* Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
*
* Based on plat-mxc/gpio.c:
* MXC GPIO support. (c) 2008 Daniel Mack <daniel@caiaq.de>
* Copyright 2008 Juergen Beisert, kernel@pengutronix.de
*/
#include <linux/gpio/driver.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/bitops.h>
/* GPIO registers definition */
#define GPIO_DATA_OUT 0x00
#define GPIO_DATA_IN 0x04
#define GPIO_DIR 0x08
#define GPIO_DATA_SET 0x10
#define GPIO_DATA_CLR 0x14
#define GPIO_PULL_EN 0x18
#define GPIO_PULL_TYPE 0x1C
#define GPIO_INT_EN 0x20
#define GPIO_INT_STAT 0x24
#define GPIO_INT_MASK 0x2C
#define GPIO_INT_CLR 0x30
#define GPIO_INT_TYPE 0x34
#define GPIO_INT_BOTH_EDGE 0x38
#define GPIO_INT_LEVEL 0x3C
#define GPIO_DEBOUNCE_EN 0x40
#define GPIO_DEBOUNCE_PRESCALE 0x44
/**
* struct gemini_gpio - Gemini GPIO state container
* @dev: containing device for this instance
* @gc: gpiochip for this instance
*/
struct gemini_gpio {
struct device *dev;
struct gpio_chip gc;
void __iomem *base;
};
static void gemini_gpio_ack_irq(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct gemini_gpio *g = gpiochip_get_data(gc);
writel(BIT(irqd_to_hwirq(d)), g->base + GPIO_INT_CLR);
}
static void gemini_gpio_mask_irq(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct gemini_gpio *g = gpiochip_get_data(gc);
u32 val;
val = readl(g->base + GPIO_INT_EN);
val &= ~BIT(irqd_to_hwirq(d));
writel(val, g->base + GPIO_INT_EN);
}
static void gemini_gpio_unmask_irq(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct gemini_gpio *g = gpiochip_get_data(gc);
u32 val;
val = readl(g->base + GPIO_INT_EN);
val |= BIT(irqd_to_hwirq(d));
writel(val, g->base + GPIO_INT_EN);
}
static int gemini_gpio_set_irq_type(struct irq_data *d, unsigned int type)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct gemini_gpio *g = gpiochip_get_data(gc);
u32 mask = BIT(irqd_to_hwirq(d));
u32 reg_both, reg_level, reg_type;
reg_type = readl(g->base + GPIO_INT_TYPE);
reg_level = readl(g->base + GPIO_INT_LEVEL);
reg_both = readl(g->base + GPIO_INT_BOTH_EDGE);
switch (type) {
case IRQ_TYPE_EDGE_BOTH:
irq_set_handler_locked(d, handle_edge_irq);
reg_type &= ~mask;
reg_both |= mask;
break;
case IRQ_TYPE_EDGE_RISING:
irq_set_handler_locked(d, handle_edge_irq);
reg_type &= ~mask;
reg_both &= ~mask;
reg_level &= ~mask;
break;
case IRQ_TYPE_EDGE_FALLING:
irq_set_handler_locked(d, handle_edge_irq);
reg_type &= ~mask;
reg_both &= ~mask;
reg_level |= mask;
break;
case IRQ_TYPE_LEVEL_HIGH:
irq_set_handler_locked(d, handle_level_irq);
reg_type |= mask;
reg_level &= ~mask;
break;
case IRQ_TYPE_LEVEL_LOW:
irq_set_handler_locked(d, handle_level_irq);
reg_type |= mask;
reg_level |= mask;
break;
default:
irq_set_handler_locked(d, handle_bad_irq);
return -EINVAL;
}
writel(reg_type, g->base + GPIO_INT_TYPE);
writel(reg_level, g->base + GPIO_INT_LEVEL);
writel(reg_both, g->base + GPIO_INT_BOTH_EDGE);
gemini_gpio_ack_irq(d);
return 0;
}
static struct irq_chip gemini_gpio_irqchip = {
.name = "GPIO",
.irq_ack = gemini_gpio_ack_irq,
.irq_mask = gemini_gpio_mask_irq,
.irq_unmask = gemini_gpio_unmask_irq,
.irq_set_type = gemini_gpio_set_irq_type,
};
static void gemini_gpio_irq_handler(struct irq_desc *desc)
{
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
struct gemini_gpio *g = gpiochip_get_data(gc);
struct irq_chip *irqchip = irq_desc_get_chip(desc);
int offset;
unsigned long stat;
chained_irq_enter(irqchip, desc);
stat = readl(g->base + GPIO_INT_STAT);
if (stat)
for_each_set_bit(offset, &stat, gc->ngpio)
generic_handle_irq(irq_find_mapping(gc->irqdomain,
offset));
chained_irq_exit(irqchip, desc);
}
static int gemini_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct resource *res;
struct gemini_gpio *g;
int irq;
int ret;
g = devm_kzalloc(dev, sizeof(*g), GFP_KERNEL);
if (!g)
return -ENOMEM;
g->dev = dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
g->base = devm_ioremap_resource(dev, res);
if (IS_ERR(g->base))
return PTR_ERR(g->base);
irq = platform_get_irq(pdev, 0);
if (!irq)
return -EINVAL;
ret = bgpio_init(&g->gc, dev, 4,
g->base + GPIO_DATA_IN,
g->base + GPIO_DATA_SET,
g->base + GPIO_DATA_CLR,
g->base + GPIO_DIR,
NULL,
0);
if (ret) {
dev_err(dev, "unable to init generic GPIO\n");
return ret;
}
g->gc.label = "Gemini";
g->gc.base = -1;
g->gc.parent = dev;
g->gc.owner = THIS_MODULE;
/* ngpio is set by bgpio_init() */
ret = devm_gpiochip_add_data(dev, &g->gc, g);
if (ret)
return ret;
/* Disable, unmask and clear all interrupts */
writel(0x0, g->base + GPIO_INT_EN);
writel(0x0, g->base + GPIO_INT_MASK);
writel(~0x0, g->base + GPIO_INT_CLR);
ret = gpiochip_irqchip_add(&g->gc, &gemini_gpio_irqchip,
0, handle_bad_irq,
IRQ_TYPE_NONE);
if (ret) {
dev_info(dev, "could not add irqchip\n");
return ret;
}
gpiochip_set_chained_irqchip(&g->gc, &gemini_gpio_irqchip,
irq, gemini_gpio_irq_handler);
dev_info(dev, "Gemini GPIO @%p registered\n", g->base);
return 0;
}
static const struct of_device_id gemini_gpio_of_match[] = {
{
.compatible = "cortina,gemini-gpio",
},
{},
};
static struct platform_driver gemini_gpio_driver = {
.driver = {
.name = "gemini-gpio",
.of_match_table = of_match_ptr(gemini_gpio_of_match),
},
.probe = gemini_gpio_probe,
};
builtin_platform_driver(gemini_gpio_driver);
+54 -14
View File
@@ -192,6 +192,56 @@ static void gpiomm_gpio_set(struct gpio_chip *chip, unsigned int offset,
spin_unlock_irqrestore(&gpiommgpio->lock, flags); spin_unlock_irqrestore(&gpiommgpio->lock, flags);
} }
static void gpiomm_gpio_set_multiple(struct gpio_chip *chip,
unsigned long *mask, unsigned long *bits)
{
struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
unsigned int i;
const unsigned int gpio_reg_size = 8;
unsigned int port;
unsigned int out_port;
unsigned int bitmask;
unsigned long flags;
/* set bits are evaluated a gpio register size at a time */
for (i = 0; i < chip->ngpio; i += gpio_reg_size) {
/* no more set bits in this mask word; skip to the next word */
if (!mask[BIT_WORD(i)]) {
i = (BIT_WORD(i) + 1) * BITS_PER_LONG - gpio_reg_size;
continue;
}
port = i / gpio_reg_size;
out_port = (port > 2) ? port + 1 : port;
bitmask = mask[BIT_WORD(i)] & bits[BIT_WORD(i)];
spin_lock_irqsave(&gpiommgpio->lock, flags);
/* update output state data and set device gpio register */
gpiommgpio->out_state[port] &= ~mask[BIT_WORD(i)];
gpiommgpio->out_state[port] |= bitmask;
outb(gpiommgpio->out_state[port], gpiommgpio->base + out_port);
spin_unlock_irqrestore(&gpiommgpio->lock, flags);
/* prepare for next gpio register set */
mask[BIT_WORD(i)] >>= gpio_reg_size;
bits[BIT_WORD(i)] >>= gpio_reg_size;
}
}
#define GPIOMM_NGPIO 48
static const char *gpiomm_names[GPIOMM_NGPIO] = {
"Port 1A0", "Port 1A1", "Port 1A2", "Port 1A3", "Port 1A4", "Port 1A5",
"Port 1A6", "Port 1A7", "Port 1B0", "Port 1B1", "Port 1B2", "Port 1B3",
"Port 1B4", "Port 1B5", "Port 1B6", "Port 1B7", "Port 1C0", "Port 1C1",
"Port 1C2", "Port 1C3", "Port 1C4", "Port 1C5", "Port 1C6", "Port 1C7",
"Port 2A0", "Port 2A1", "Port 2A2", "Port 2A3", "Port 2A4", "Port 2A5",
"Port 2A6", "Port 2A7", "Port 2B0", "Port 2B1", "Port 2B2", "Port 2B3",
"Port 2B4", "Port 2B5", "Port 2B6", "Port 2B7", "Port 2C0", "Port 2C1",
"Port 2C2", "Port 2C3", "Port 2C4", "Port 2C5", "Port 2C6", "Port 2C7",
};
static int gpiomm_probe(struct device *dev, unsigned int id) static int gpiomm_probe(struct device *dev, unsigned int id)
{ {
struct gpiomm_gpio *gpiommgpio; struct gpiomm_gpio *gpiommgpio;
@@ -212,19 +262,19 @@ static int gpiomm_probe(struct device *dev, unsigned int id)
gpiommgpio->chip.parent = dev; gpiommgpio->chip.parent = dev;
gpiommgpio->chip.owner = THIS_MODULE; gpiommgpio->chip.owner = THIS_MODULE;
gpiommgpio->chip.base = -1; gpiommgpio->chip.base = -1;
gpiommgpio->chip.ngpio = 48; gpiommgpio->chip.ngpio = GPIOMM_NGPIO;
gpiommgpio->chip.names = gpiomm_names;
gpiommgpio->chip.get_direction = gpiomm_gpio_get_direction; gpiommgpio->chip.get_direction = gpiomm_gpio_get_direction;
gpiommgpio->chip.direction_input = gpiomm_gpio_direction_input; gpiommgpio->chip.direction_input = gpiomm_gpio_direction_input;
gpiommgpio->chip.direction_output = gpiomm_gpio_direction_output; gpiommgpio->chip.direction_output = gpiomm_gpio_direction_output;
gpiommgpio->chip.get = gpiomm_gpio_get; gpiommgpio->chip.get = gpiomm_gpio_get;
gpiommgpio->chip.set = gpiomm_gpio_set; gpiommgpio->chip.set = gpiomm_gpio_set;
gpiommgpio->chip.set_multiple = gpiomm_gpio_set_multiple;
gpiommgpio->base = base[id]; gpiommgpio->base = base[id];
spin_lock_init(&gpiommgpio->lock); spin_lock_init(&gpiommgpio->lock);
dev_set_drvdata(dev, gpiommgpio); err = devm_gpiochip_add_data(dev, &gpiommgpio->chip, gpiommgpio);
err = gpiochip_add_data(&gpiommgpio->chip, gpiommgpio);
if (err) { if (err) {
dev_err(dev, "GPIO registering failed (%d)\n", err); dev_err(dev, "GPIO registering failed (%d)\n", err);
return err; return err;
@@ -243,21 +293,11 @@ static int gpiomm_probe(struct device *dev, unsigned int id)
return 0; return 0;
} }
static int gpiomm_remove(struct device *dev, unsigned int id)
{
struct gpiomm_gpio *const gpiommgpio = dev_get_drvdata(dev);
gpiochip_remove(&gpiommgpio->chip);
return 0;
}
static struct isa_driver gpiomm_driver = { static struct isa_driver gpiomm_driver = {
.probe = gpiomm_probe, .probe = gpiomm_probe,
.driver = { .driver = {
.name = "gpio-mm" .name = "gpio-mm"
}, },
.remove = gpiomm_remove
}; };
module_isa_driver(gpiomm_driver, num_gpiomm); module_isa_driver(gpiomm_driver, num_gpiomm);
+1 -1
View File
@@ -321,7 +321,7 @@ static void intel_mid_irq_init_hw(struct intel_mid_gpio *priv)
} }
} }
static int intel_gpio_runtime_idle(struct device *dev) static int __maybe_unused intel_gpio_runtime_idle(struct device *dev)
{ {
int err = pm_schedule_suspend(dev, 500); int err = pm_schedule_suspend(dev, 500);
return err ?: -EBUSY; return err ?: -EBUSY;
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -3,7 +3,7 @@
* under the terms of the GNU General Public License version 2 as published * under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation. * by the Free Software Foundation.
* *
* Copyright (C) 2012 John Crispin <blogic@openwrt.org> * Copyright (C) 2012 John Crispin <john@phrozen.org>
*/ */
#include <linux/init.h> #include <linux/init.h>
+302 -77
View File
@@ -14,14 +14,23 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/gpio/driver.h> #include <linux/gpio/driver.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irq_work.h>
#include <linux/debugfs.h>
#include <linux/uaccess.h>
#define GPIO_NAME "gpio-mockup" #include "gpiolib.h"
#define MAX_GC 10
enum direction { #define GPIO_MOCKUP_NAME "gpio-mockup"
OUT, #define GPIO_MOCKUP_MAX_GC 10
IN
enum {
DIR_IN = 0,
DIR_OUT,
}; };
/* /*
@@ -29,150 +38,360 @@ enum direction {
* @dir: Configures direction of gpio as "in" or "out", 0=in, 1=out * @dir: Configures direction of gpio as "in" or "out", 0=in, 1=out
* @value: Configures status of the gpio as 0(low) or 1(high) * @value: Configures status of the gpio as 0(low) or 1(high)
*/ */
struct gpio_pin_status { struct gpio_mockup_line_status {
enum direction dir; int dir;
bool value; bool value;
}; };
struct mockup_gpio_controller { struct gpio_mockup_irq_context {
struct gpio_chip gc; struct irq_work work;
struct gpio_pin_status *stats; int irq;
}; };
static int gpio_mockup_ranges[MAX_GC << 1]; struct gpio_mockup_chip {
struct gpio_chip gc;
struct gpio_mockup_line_status *lines;
struct gpio_mockup_irq_context irq_ctx;
struct dentry *dbg_dir;
};
struct gpio_mockup_dbgfs_private {
struct gpio_mockup_chip *chip;
struct gpio_desc *desc;
int offset;
};
static int gpio_mockup_ranges[GPIO_MOCKUP_MAX_GC << 1];
static int gpio_mockup_params_nr; static int gpio_mockup_params_nr;
module_param_array(gpio_mockup_ranges, int, &gpio_mockup_params_nr, 0400); module_param_array(gpio_mockup_ranges, int, &gpio_mockup_params_nr, 0400);
const char pins_name_start = 'A'; static bool gpio_mockup_named_lines;
module_param_named(gpio_mockup_named_lines,
gpio_mockup_named_lines, bool, 0400);
static int mockup_gpio_get(struct gpio_chip *gc, unsigned int offset) static const char gpio_mockup_name_start = 'A';
static struct dentry *gpio_mockup_dbg_dir;
static int gpio_mockup_get(struct gpio_chip *gc, unsigned int offset)
{ {
struct mockup_gpio_controller *cntr = gpiochip_get_data(gc); struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
return cntr->stats[offset].value; return chip->lines[offset].value;
} }
static void mockup_gpio_set(struct gpio_chip *gc, unsigned int offset, static void gpio_mockup_set(struct gpio_chip *gc, unsigned int offset,
int value) int value)
{ {
struct mockup_gpio_controller *cntr = gpiochip_get_data(gc); struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
cntr->stats[offset].value = !!value; chip->lines[offset].value = !!value;
} }
static int mockup_gpio_dirout(struct gpio_chip *gc, unsigned int offset, static int gpio_mockup_dirout(struct gpio_chip *gc, unsigned int offset,
int value) int value)
{ {
struct mockup_gpio_controller *cntr = gpiochip_get_data(gc); struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
gpio_mockup_set(gc, offset, value);
chip->lines[offset].dir = DIR_OUT;
mockup_gpio_set(gc, offset, value);
cntr->stats[offset].dir = OUT;
return 0; return 0;
} }
static int mockup_gpio_dirin(struct gpio_chip *gc, unsigned int offset) static int gpio_mockup_dirin(struct gpio_chip *gc, unsigned int offset)
{ {
struct mockup_gpio_controller *cntr = gpiochip_get_data(gc); struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
chip->lines[offset].dir = DIR_IN;
cntr->stats[offset].dir = IN;
return 0; return 0;
} }
static int mockup_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) static int gpio_mockup_get_direction(struct gpio_chip *gc, unsigned int offset)
{ {
struct mockup_gpio_controller *cntr = gpiochip_get_data(gc); struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
return cntr->stats[offset].dir; return chip->lines[offset].dir;
} }
static int mockup_gpio_add(struct device *dev, static int gpio_mockup_name_lines(struct device *dev,
struct mockup_gpio_controller *cntr, struct gpio_mockup_chip *chip)
{
struct gpio_chip *gc = &chip->gc;
char **names;
int i;
names = devm_kzalloc(dev, sizeof(char *) * gc->ngpio, GFP_KERNEL);
if (!names)
return -ENOMEM;
for (i = 0; i < gc->ngpio; i++) {
names[i] = devm_kasprintf(dev, GFP_KERNEL,
"%s-%d", gc->label, i);
if (!names[i])
return -ENOMEM;
}
gc->names = (const char *const *)names;
return 0;
}
static int gpio_mockup_to_irq(struct gpio_chip *chip, unsigned int offset)
{
return chip->irq_base + offset;
}
/*
* While we should generally support irqmask and irqunmask, this driver is
* for testing purposes only so we don't care.
*/
static void gpio_mockup_irqmask(struct irq_data *d) { }
static void gpio_mockup_irqunmask(struct irq_data *d) { }
static struct irq_chip gpio_mockup_irqchip = {
.name = GPIO_MOCKUP_NAME,
.irq_mask = gpio_mockup_irqmask,
.irq_unmask = gpio_mockup_irqunmask,
};
static void gpio_mockup_handle_irq(struct irq_work *work)
{
struct gpio_mockup_irq_context *irq_ctx;
irq_ctx = container_of(work, struct gpio_mockup_irq_context, work);
handle_simple_irq(irq_to_desc(irq_ctx->irq));
}
static int gpio_mockup_irqchip_setup(struct device *dev,
struct gpio_mockup_chip *chip)
{
struct gpio_chip *gc = &chip->gc;
int irq_base, i;
irq_base = irq_alloc_descs(-1, 0, gc->ngpio, 0);
if (irq_base < 0)
return irq_base;
gc->irq_base = irq_base;
gc->irqchip = &gpio_mockup_irqchip;
for (i = 0; i < gc->ngpio; i++) {
irq_set_chip(irq_base + i, gc->irqchip);
irq_set_handler(irq_base + i, &handle_simple_irq);
irq_modify_status(irq_base + i,
IRQ_NOREQUEST | IRQ_NOAUTOEN, IRQ_NOPROBE);
}
init_irq_work(&chip->irq_ctx.work, gpio_mockup_handle_irq);
return 0;
}
static ssize_t gpio_mockup_event_write(struct file *file,
const char __user *usr_buf,
size_t size, loff_t *ppos)
{
struct gpio_mockup_dbgfs_private *priv;
struct gpio_mockup_chip *chip;
struct seq_file *sfile;
struct gpio_desc *desc;
struct gpio_chip *gc;
int status, val;
char buf;
sfile = file->private_data;
priv = sfile->private;
desc = priv->desc;
chip = priv->chip;
gc = &chip->gc;
status = copy_from_user(&buf, usr_buf, 1);
if (status)
return status;
if (buf == '0')
val = 0;
else if (buf == '1')
val = 1;
else
return -EINVAL;
gpiod_set_value_cansleep(desc, val);
priv->chip->irq_ctx.irq = gc->irq_base + priv->offset;
irq_work_queue(&priv->chip->irq_ctx.work);
return size;
}
static int gpio_mockup_event_open(struct inode *inode, struct file *file)
{
return single_open(file, NULL, inode->i_private);
}
static const struct file_operations gpio_mockup_event_ops = {
.owner = THIS_MODULE,
.open = gpio_mockup_event_open,
.write = gpio_mockup_event_write,
.llseek = no_llseek,
};
static void gpio_mockup_debugfs_setup(struct device *dev,
struct gpio_mockup_chip *chip)
{
struct gpio_mockup_dbgfs_private *priv;
struct dentry *evfile;
struct gpio_chip *gc;
char *name;
int i;
gc = &chip->gc;
chip->dbg_dir = debugfs_create_dir(gc->label, gpio_mockup_dbg_dir);
if (!chip->dbg_dir)
goto err;
for (i = 0; i < gc->ngpio; i++) {
name = devm_kasprintf(dev, GFP_KERNEL, "%d", i);
if (!name)
goto err;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
goto err;
priv->chip = chip;
priv->offset = i;
priv->desc = &gc->gpiodev->descs[i];
evfile = debugfs_create_file(name, 0200, chip->dbg_dir, priv,
&gpio_mockup_event_ops);
if (!evfile)
goto err;
}
return;
err:
dev_err(dev, "error creating debugfs directory\n");
}
static int gpio_mockup_add(struct device *dev,
struct gpio_mockup_chip *chip,
const char *name, int base, int ngpio) const char *name, int base, int ngpio)
{ {
struct gpio_chip *gc = &chip->gc;
int ret; int ret;
cntr->gc.base = base; gc->base = base;
cntr->gc.ngpio = ngpio; gc->ngpio = ngpio;
cntr->gc.label = name; gc->label = name;
cntr->gc.owner = THIS_MODULE; gc->owner = THIS_MODULE;
cntr->gc.parent = dev; gc->parent = dev;
cntr->gc.get = mockup_gpio_get; gc->get = gpio_mockup_get;
cntr->gc.set = mockup_gpio_set; gc->set = gpio_mockup_set;
cntr->gc.direction_output = mockup_gpio_dirout; gc->direction_output = gpio_mockup_dirout;
cntr->gc.direction_input = mockup_gpio_dirin; gc->direction_input = gpio_mockup_dirin;
cntr->gc.get_direction = mockup_gpio_get_direction; gc->get_direction = gpio_mockup_get_direction;
cntr->stats = devm_kzalloc(dev, sizeof(*cntr->stats) * cntr->gc.ngpio, gc->to_irq = gpio_mockup_to_irq;
chip->lines = devm_kzalloc(dev, sizeof(*chip->lines) * gc->ngpio,
GFP_KERNEL); GFP_KERNEL);
if (!cntr->stats) { if (!chip->lines)
ret = -ENOMEM; return -ENOMEM;
goto err;
if (gpio_mockup_named_lines) {
ret = gpio_mockup_name_lines(dev, chip);
if (ret)
return ret;
} }
ret = devm_gpiochip_add_data(dev, &cntr->gc, cntr);
ret = gpio_mockup_irqchip_setup(dev, chip);
if (ret) if (ret)
goto err; return ret;
ret = devm_gpiochip_add_data(dev, &chip->gc, chip);
if (ret)
return ret;
if (gpio_mockup_dbg_dir)
gpio_mockup_debugfs_setup(dev, chip);
dev_info(dev, "gpio<%d..%d> add successful!", base, base + ngpio);
return 0; return 0;
err:
dev_err(dev, "gpio<%d..%d> add failed!", base, base + ngpio);
return ret;
} }
static int mockup_gpio_probe(struct platform_device *pdev) static int gpio_mockup_probe(struct platform_device *pdev)
{ {
struct gpio_mockup_chip *chips;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct mockup_gpio_controller *cntr; int ret, i, base, ngpio;
int ret; char *chip_name;
int i;
int base;
int ngpio;
char chip_name[sizeof(GPIO_NAME) + 3];
if (gpio_mockup_params_nr < 2) if (gpio_mockup_params_nr < 2)
return -EINVAL; return -EINVAL;
cntr = devm_kzalloc(dev, sizeof(*cntr) * (gpio_mockup_params_nr >> 1), chips = devm_kzalloc(dev,
GFP_KERNEL); sizeof(*chips) * (gpio_mockup_params_nr >> 1),
if (!cntr) GFP_KERNEL);
if (!chips)
return -ENOMEM; return -ENOMEM;
platform_set_drvdata(pdev, cntr); platform_set_drvdata(pdev, chips);
for (i = 0; i < gpio_mockup_params_nr >> 1; i++) { for (i = 0; i < gpio_mockup_params_nr >> 1; i++) {
base = gpio_mockup_ranges[i * 2]; base = gpio_mockup_ranges[i * 2];
if (base == -1) if (base == -1)
ngpio = gpio_mockup_ranges[i * 2 + 1]; ngpio = gpio_mockup_ranges[i * 2 + 1];
else else
ngpio = gpio_mockup_ranges[i * 2 + 1] - base; ngpio = gpio_mockup_ranges[i * 2 + 1] - base;
if (ngpio >= 0) { if (ngpio >= 0) {
sprintf(chip_name, "%s-%c", GPIO_NAME, chip_name = devm_kasprintf(dev, GFP_KERNEL,
pins_name_start + i); "%s-%c", GPIO_MOCKUP_NAME,
ret = mockup_gpio_add(dev, &cntr[i], gpio_mockup_name_start + i);
if (!chip_name)
return -ENOMEM;
ret = gpio_mockup_add(dev, &chips[i],
chip_name, base, ngpio); chip_name, base, ngpio);
} else { } else {
ret = -1; ret = -1;
} }
if (ret) { if (ret) {
if (base < 0) dev_err(dev, "gpio<%d..%d> add failed\n",
dev_err(dev, "gpio<%d..%d> add failed\n", base, base < 0 ? ngpio : base + ngpio);
base, ngpio);
else
dev_err(dev, "gpio<%d..%d> add failed\n",
base, base + ngpio);
return ret; return ret;
} }
dev_info(dev, "gpio<%d..%d> add successful!",
base, base + ngpio);
} }
return 0; return 0;
} }
static struct platform_driver mockup_gpio_driver = { static int gpio_mockup_remove(struct platform_device *pdev)
{
struct gpio_mockup_chip *chips;
int i;
chips = platform_get_drvdata(pdev);
for (i = 0; i < gpio_mockup_params_nr >> 1; i++)
irq_free_descs(chips[i].gc.irq_base, chips[i].gc.ngpio);
return 0;
}
static struct platform_driver gpio_mockup_driver = {
.driver = { .driver = {
.name = GPIO_NAME, .name = GPIO_MOCKUP_NAME,
}, },
.probe = mockup_gpio_probe, .probe = gpio_mockup_probe,
.remove = gpio_mockup_remove,
}; };
static struct platform_device *pdev; static struct platform_device *pdev;
@@ -180,7 +399,12 @@ static int __init mock_device_init(void)
{ {
int err; int err;
pdev = platform_device_alloc(GPIO_NAME, -1); gpio_mockup_dbg_dir = debugfs_create_dir("gpio-mockup-event", NULL);
if (!gpio_mockup_dbg_dir)
pr_err("%s: error creating debugfs directory\n",
GPIO_MOCKUP_NAME);
pdev = platform_device_alloc(GPIO_MOCKUP_NAME, -1);
if (!pdev) if (!pdev)
return -ENOMEM; return -ENOMEM;
@@ -190,7 +414,7 @@ static int __init mock_device_init(void)
return err; return err;
} }
err = platform_driver_register(&mockup_gpio_driver); err = platform_driver_register(&gpio_mockup_driver);
if (err) { if (err) {
platform_device_unregister(pdev); platform_device_unregister(pdev);
return err; return err;
@@ -201,7 +425,8 @@ static int __init mock_device_init(void)
static void __exit mock_device_exit(void) static void __exit mock_device_exit(void)
{ {
platform_driver_unregister(&mockup_gpio_driver); debugfs_remove_recursive(gpio_mockup_dbg_dir);
platform_driver_unregister(&gpio_mockup_driver);
platform_device_unregister(pdev); platform_device_unregister(pdev);
} }
+1 -1
View File
@@ -659,7 +659,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
match = of_match_device(mvebu_gpio_of_match, &pdev->dev); match = of_match_device(mvebu_gpio_of_match, &pdev->dev);
if (match) if (match)
soc_variant = (int) match->data; soc_variant = (unsigned long) match->data;
else else
soc_variant = MVEBU_GPIO_SOC_VARIANT_ORION; soc_variant = MVEBU_GPIO_SOC_VARIANT_ORION;

Some files were not shown because too many files have changed in this diff Show More