提交 3cf42efc 编写于 作者: L Linus Walleij

Merge branch 'devel' into for-next

What: /sys/class/gpio/ What: /sys/class/gpio/
Date: July 2008 Date: July 2008
KernelVersion: 2.6.27 KernelVersion: 2.6.27
Contact: David Brownell <dbrownell@users.sourceforge.net> Contact: Linus Walleij <linusw@kernel.org>
Description: Description:
As a Kconfig option, individual GPIO signals may be accessed from As a Kconfig option, individual GPIO signals may be accessed from
...@@ -26,3 +26,5 @@ Description: ...@@ -26,3 +26,5 @@ Description:
/label ... (r/o) descriptive, not necessarily unique /label ... (r/o) descriptive, not necessarily unique
/ngpio ... (r/o) number of GPIOs; numbered N to N + (ngpio - 1) /ngpio ... (r/o) number of GPIOs; numbered N to N + (ngpio - 1)
This ABI is deprecated and will be removed after 2020. It is
replaced with the GPIO character device.
What: /dev/gpiochip[0-9]+
Date: November 2015
KernelVersion: 4.4
Contact: linux-gpio@vger.kernel.org
Description:
The character device files /dev/gpiochip* are the interface
between GPIO chips and userspace.
The ioctl(2)-based ABI is defined and documented in
[include/uapi]<linux/gpio.h>.
The following file operations are supported:
open(2)
Currently the only useful flags are O_RDWR.
ioctl(2)
Initiate various actions.
See the inline documentation in [include/uapi]<linux/gpio.h>
for descriptions of all ioctls.
close(2)
Stops and free up the I/O contexts that was associated
with the file descriptor.
Users: TBD
* TS-4800 FPGA's GPIO controller bindings
Required properties:
- compatible: Must be "technologic,ts4800-gpio".
- #gpio-cells: Should be two. The first cell is the pin number.
- reg: Physical base address of the controller and length
of memory mapped region.
Optional property:
- ngpios: See "gpio.txt"
Example:
gpio1: gpio {
compatible = "technologic,ts4800-gpio";
reg = <0x10020 0x6>;
ngpios = <8>;
gpio-controller;
#gpio-cells = <2>;
};
APM X-Gene Standby GPIO controller bindings APM X-Gene Standby GPIO controller bindings
This is a gpio controller in the standby domain. This is a gpio controller in the standby domain. It also supports interrupt in
some particular pins which are sourced to its parent interrupt controller
There are 20 GPIO pins from 0..21. There is no GPIO_DS14 or GPIO_DS15, as diagram below:
only GPIO_DS8..GPIO_DS13 support interrupts. The IRQ mapping +-----------------+
is currently 1-to-1 on interrupts 0x28 thru 0x2d. | X-Gene standby |
| GPIO controller +------ GPIO_0
+------------+ | | ...
| Parent IRQ | EXT_INT_0 | +------ GPIO_8/EXT_INT_0
| controller | (SPI40) | | ...
| (GICv2) +--------------+ +------ GPIO_[N+8]/EXT_INT_N
| | ... | |
| | EXT_INT_N | +------ GPIO_[N+9]
| | (SPI[40 + N])| | ...
| +--------------+ +------ GPIO_MAX
+------------+ +-----------------+
Required properties: Required properties:
- compatible: "apm,xgene-gpio-sb" for the X-Gene Standby GPIO controller - compatible: "apm,xgene-gpio-sb" for the X-Gene Standby GPIO controller
...@@ -15,10 +25,18 @@ Required properties: ...@@ -15,10 +25,18 @@ Required properties:
0 = active high 0 = active high
1 = active low 1 = active low
- gpio-controller: Marks the device node as a GPIO controller. - gpio-controller: Marks the device node as a GPIO controller.
- interrupts: Shall contain exactly 6 interrupts. - interrupts: The EXT_INT_0 parent interrupt resource must be listed first.
- interrupt-parent: Phandle of the parent interrupt controller.
- interrupt-cells: Should be two.
- first cell is 0-N coresponding for EXT_INT_0 to EXT_INT_N.
- second cell is used to specify flags.
- interrupt-controller: Marks the device node as an interrupt controller.
- apm,nr-gpios: Optional, specify number of gpios pin.
- apm,nr-irqs: Optional, specify number of interrupt pins.
- apm,irq-start: Optional, specify lowest gpio pin support interrupt.
Example: Example:
sbgpio: sbgpio@17001000 { sbgpio: gpio@17001000{
compatible = "apm,xgene-gpio-sb"; compatible = "apm,xgene-gpio-sb";
reg = <0x0 0x17001000 0x0 0x400>; reg = <0x0 0x17001000 0x0 0x400>;
#gpio-cells = <2>; #gpio-cells = <2>;
...@@ -29,4 +47,19 @@ Example: ...@@ -29,4 +47,19 @@ Example:
<0x0 0x2b 0x1>, <0x0 0x2b 0x1>,
<0x0 0x2c 0x1>, <0x0 0x2c 0x1>,
<0x0 0x2d 0x1>; <0x0 0x2d 0x1>;
interrupt-parent = <&gic>;
#interrupt-cells = <2>;
interrupt-controller;
apm,nr-gpios = <22>;
apm,nr-irqs = <6>;
apm,irq-start = <8>;
};
testuser {
compatible = "example,testuser";
/* Use the GPIO_13/EXT_INT_5 line as an active high triggered
* level interrupt
*/
interrupts = <5 4>;
interrupt-parent = <&sbgpio>;
}; };
...@@ -240,6 +240,12 @@ L: lm-sensors@lm-sensors.org ...@@ -240,6 +240,12 @@ L: lm-sensors@lm-sensors.org
S: Maintained S: Maintained
F: drivers/hwmon/abituguru3.c F: drivers/hwmon/abituguru3.c
ACCES 104-DIO-48E GPIO DRIVER
M: William Breathitt Gray <vilhelm.gray@gmail.com>
L: linux-gpio@vger.kernel.org
S: Maintained
F: drivers/gpio/gpio-104-dio-48e.c
ACCES 104-IDI-48 GPIO DRIVER ACCES 104-IDI-48 GPIO DRIVER
M: "William Breathitt Gray" <vilhelm.gray@gmail.com> M: "William Breathitt Gray" <vilhelm.gray@gmail.com>
L: linux-gpio@vger.kernel.org L: linux-gpio@vger.kernel.org
...@@ -4815,10 +4821,14 @@ L: linux-gpio@vger.kernel.org ...@@ -4815,10 +4821,14 @@ L: linux-gpio@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio.git
S: Maintained S: Maintained
F: Documentation/gpio/ F: Documentation/gpio/
F: Documentation/ABI/testing/gpio-cdev
F: Documentation/ABI/obsolete/sysfs-gpio
F: drivers/gpio/ F: drivers/gpio/
F: include/linux/gpio/ F: include/linux/gpio/
F: include/linux/gpio.h F: include/linux/gpio.h
F: include/asm-generic/gpio.h F: include/asm-generic/gpio.h
F: include/uapi/linux/gpio.h
F: tools/gpio/
GRE DEMULTIPLEXER DRIVER GRE DEMULTIPLEXER DRIVER
M: Dmitry Kozlov <xeb@mail.ru> M: Dmitry Kozlov <xeb@mail.ru>
...@@ -11871,6 +11881,12 @@ M: David Härdeman <david@hardeman.nu> ...@@ -11871,6 +11881,12 @@ M: David Härdeman <david@hardeman.nu>
S: Maintained S: Maintained
F: drivers/media/rc/winbond-cir.c F: drivers/media/rc/winbond-cir.c
WINSYSTEMS WS16C48 GPIO DRIVER
M: William Breathitt Gray <vilhelm.gray@gmail.com>
L: linux-gpio@vger.kernel.org
S: Maintained
F: drivers/gpio/gpio-ws16c48.c
WIMAX STACK WIMAX STACK
M: Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> M: Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
M: linux-wimax@intel.com M: linux-wimax@intel.com
......
#ifndef __LINUX_GPIO_H
#warning Include linux/gpio.h instead of asm/gpio.h
#include <linux/gpio.h>
#endif
...@@ -69,7 +69,7 @@ static void __scoop_gpio_set(struct scoop_dev *sdev, ...@@ -69,7 +69,7 @@ static void __scoop_gpio_set(struct scoop_dev *sdev,
static void scoop_gpio_set(struct gpio_chip *chip, unsigned offset, int value) static void scoop_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{ {
struct scoop_dev *sdev = container_of(chip, struct scoop_dev, gpio); struct scoop_dev *sdev = gpiochip_get_data(chip);
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&sdev->scoop_lock, flags); spin_lock_irqsave(&sdev->scoop_lock, flags);
...@@ -81,7 +81,7 @@ static void scoop_gpio_set(struct gpio_chip *chip, unsigned offset, int value) ...@@ -81,7 +81,7 @@ static void scoop_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
static int scoop_gpio_get(struct gpio_chip *chip, unsigned offset) static int scoop_gpio_get(struct gpio_chip *chip, unsigned offset)
{ {
struct scoop_dev *sdev = container_of(chip, struct scoop_dev, gpio); struct scoop_dev *sdev = gpiochip_get_data(chip);
/* XXX: I'm unsure, but it seems so */ /* XXX: I'm unsure, but it seems so */
return !!(ioread16(sdev->base + SCOOP_GPRR) & (1 << (offset + 1))); return !!(ioread16(sdev->base + SCOOP_GPRR) & (1 << (offset + 1)));
...@@ -90,7 +90,7 @@ static int scoop_gpio_get(struct gpio_chip *chip, unsigned offset) ...@@ -90,7 +90,7 @@ static int scoop_gpio_get(struct gpio_chip *chip, unsigned offset)
static int scoop_gpio_direction_input(struct gpio_chip *chip, static int scoop_gpio_direction_input(struct gpio_chip *chip,
unsigned offset) unsigned offset)
{ {
struct scoop_dev *sdev = container_of(chip, struct scoop_dev, gpio); struct scoop_dev *sdev = gpiochip_get_data(chip);
unsigned long flags; unsigned long flags;
unsigned short gpcr; unsigned short gpcr;
...@@ -108,7 +108,7 @@ static int scoop_gpio_direction_input(struct gpio_chip *chip, ...@@ -108,7 +108,7 @@ static int scoop_gpio_direction_input(struct gpio_chip *chip,
static int scoop_gpio_direction_output(struct gpio_chip *chip, static int scoop_gpio_direction_output(struct gpio_chip *chip,
unsigned offset, int value) unsigned offset, int value)
{ {
struct scoop_dev *sdev = container_of(chip, struct scoop_dev, gpio); struct scoop_dev *sdev = gpiochip_get_data(chip);
unsigned long flags; unsigned long flags;
unsigned short gpcr; unsigned short gpcr;
...@@ -224,7 +224,7 @@ static int scoop_probe(struct platform_device *pdev) ...@@ -224,7 +224,7 @@ static int scoop_probe(struct platform_device *pdev)
devptr->gpio.direction_input = scoop_gpio_direction_input; devptr->gpio.direction_input = scoop_gpio_direction_input;
devptr->gpio.direction_output = scoop_gpio_direction_output; devptr->gpio.direction_output = scoop_gpio_direction_output;
ret = gpiochip_add(&devptr->gpio); ret = gpiochip_add_data(&devptr->gpio, devptr);
if (ret) if (ret)
goto err_gpio; goto err_gpio;
} }
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/gpio.h> #include <linux/gpio/driver.h>
#include <mach/hardware.h> #include <mach/hardware.h>
#include <mach/irqs.h> #include <mach/irqs.h>
...@@ -227,5 +227,5 @@ void __init gemini_gpio_init(void) ...@@ -227,5 +227,5 @@ void __init gemini_gpio_init(void)
(void *)i); (void *)i);
} }
BUG_ON(gpiochip_add(&gemini_gpio_chip)); BUG_ON(gpiochip_add_data(&gemini_gpio_chip, NULL));
} }
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#include <linux/gpio/driver.h>
/* Needed for gpio_to_irq() */
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/mtd/mtd.h> #include <linux/mtd/mtd.h>
...@@ -243,7 +245,7 @@ static void __init mx27ads_regulator_init(void) ...@@ -243,7 +245,7 @@ static void __init mx27ads_regulator_init(void)
vchip->ngpio = 1; vchip->ngpio = 1;
vchip->direction_output = vgpio_dir_out; vchip->direction_output = vgpio_dir_out;
vchip->set = vgpio_set; vchip->set = vgpio_set;
gpiochip_add(vchip); gpiochip_add_data(vchip, NULL);
platform_device_register_data(NULL, "reg-fixed-voltage", platform_device_register_data(NULL, "reg-fixed-voltage",
PLATFORM_DEVID_AUTO, PLATFORM_DEVID_AUTO,
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
#include <linux/clockchips.h> #include <linux/clockchips.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/gpio.h> #include <linux/gpio/driver.h>
#include <linux/cpu.h> #include <linux/cpu.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/sched_clock.h> #include <linux/sched_clock.h>
...@@ -461,7 +461,7 @@ void __init ixp4xx_sys_init(void) ...@@ -461,7 +461,7 @@ void __init ixp4xx_sys_init(void)
platform_add_devices(ixp4xx_devices, ARRAY_SIZE(ixp4xx_devices)); platform_add_devices(ixp4xx_devices, ARRAY_SIZE(ixp4xx_devices));
gpiochip_add(&ixp4xx_gpio_chip); gpiochip_add_data(&ixp4xx_gpio_chip, NULL);
if (cpu_is_ixp46x()) { if (cpu_is_ixp46x()) {
int region; int region;
......
...@@ -664,7 +664,7 @@ static void __init h1940_map_io(void) ...@@ -664,7 +664,7 @@ static void __init h1940_map_io(void)
/* Add latch gpio chip, set latch initial value */ /* Add latch gpio chip, set latch initial value */
h1940_latch_control(0, 0); h1940_latch_control(0, 0);
WARN_ON(gpiochip_add(&h1940_latch_gpiochip)); WARN_ON(gpiochip_add_data(&h1940_latch_gpiochip, NULL));
} }
static void __init h1940_init_time(void) static void __init h1940_init_time(void)
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
#include <linux/mtd/mtd.h> #include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h> #include <linux/mtd/partitions.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/gpio.h> #include <linux/gpio/driver.h>
#include <mach/hardware.h> #include <mach/hardware.h>
#include <asm/setup.h> #include <asm/setup.h>
...@@ -369,7 +369,7 @@ static int __init simpad_init(void) ...@@ -369,7 +369,7 @@ static int __init simpad_init(void)
cs3_gpio.get = cs3_gpio_get; cs3_gpio.get = cs3_gpio_get;
cs3_gpio.direction_input = cs3_gpio_direction_input; cs3_gpio.direction_input = cs3_gpio_direction_input;
cs3_gpio.direction_output = cs3_gpio_direction_output; cs3_gpio.direction_output = cs3_gpio_direction_output;
ret = gpiochip_add(&cs3_gpio); ret = gpiochip_add_data(&cs3_gpio, NULL);
if (ret) if (ret)
printk(KERN_WARNING "simpad: Unable to register cs3 GPIO device"); printk(KERN_WARNING "simpad: Unable to register cs3 GPIO device");
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/gpio.h> #include <linux/gpio/driver.h>
#include <mach/hardware.h> #include <mach/hardware.h>
...@@ -30,7 +30,6 @@ ...@@ -30,7 +30,6 @@
#define GPIO_IN (0x0C) #define GPIO_IN (0x0C)
#define GROUPINERV (0x10) #define GROUPINERV (0x10)
#define GPIO_GPIO(Nb) (0x00000001 << (Nb)) #define GPIO_GPIO(Nb) (0x00000001 << (Nb))
#define to_nuc900_gpio_chip(c) container_of(c, struct nuc900_gpio_chip, chip)
#define NUC900_GPIO_CHIP(name, base_gpio, nr_gpio) \ #define NUC900_GPIO_CHIP(name, base_gpio, nr_gpio) \
{ \ { \
...@@ -53,7 +52,7 @@ struct nuc900_gpio_chip { ...@@ -53,7 +52,7 @@ struct nuc900_gpio_chip {
static int nuc900_gpio_get(struct gpio_chip *chip, unsigned offset) static int nuc900_gpio_get(struct gpio_chip *chip, unsigned offset)
{ {
struct nuc900_gpio_chip *nuc900_gpio = to_nuc900_gpio_chip(chip); struct nuc900_gpio_chip *nuc900_gpio = gpiochip_get_data(chip);
void __iomem *pio = nuc900_gpio->regbase + GPIO_IN; void __iomem *pio = nuc900_gpio->regbase + GPIO_IN;
unsigned int regval; unsigned int regval;
...@@ -65,7 +64,7 @@ static int nuc900_gpio_get(struct gpio_chip *chip, unsigned offset) ...@@ -65,7 +64,7 @@ static int nuc900_gpio_get(struct gpio_chip *chip, unsigned offset)
static void nuc900_gpio_set(struct gpio_chip *chip, unsigned offset, int val) static void nuc900_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
{ {
struct nuc900_gpio_chip *nuc900_gpio = to_nuc900_gpio_chip(chip); struct nuc900_gpio_chip *nuc900_gpio = gpiochip_get_data(chip);
void __iomem *pio = nuc900_gpio->regbase + GPIO_OUT; void __iomem *pio = nuc900_gpio->regbase + GPIO_OUT;
unsigned int regval; unsigned int regval;
unsigned long flags; unsigned long flags;
...@@ -86,7 +85,7 @@ static void nuc900_gpio_set(struct gpio_chip *chip, unsigned offset, int val) ...@@ -86,7 +85,7 @@ static void nuc900_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
static int nuc900_dir_input(struct gpio_chip *chip, unsigned offset) static int nuc900_dir_input(struct gpio_chip *chip, unsigned offset)
{ {
struct nuc900_gpio_chip *nuc900_gpio = to_nuc900_gpio_chip(chip); struct nuc900_gpio_chip *nuc900_gpio = gpiochip_get_data(chip);
void __iomem *pio = nuc900_gpio->regbase + GPIO_DIR; void __iomem *pio = nuc900_gpio->regbase + GPIO_DIR;
unsigned int regval; unsigned int regval;
unsigned long flags; unsigned long flags;
...@@ -104,7 +103,7 @@ static int nuc900_dir_input(struct gpio_chip *chip, unsigned offset) ...@@ -104,7 +103,7 @@ static int nuc900_dir_input(struct gpio_chip *chip, unsigned offset)
static int nuc900_dir_output(struct gpio_chip *chip, unsigned offset, int val) static int nuc900_dir_output(struct gpio_chip *chip, unsigned offset, int val)
{ {
struct nuc900_gpio_chip *nuc900_gpio = to_nuc900_gpio_chip(chip); struct nuc900_gpio_chip *nuc900_gpio = gpiochip_get_data(chip);
void __iomem *outreg = nuc900_gpio->regbase + GPIO_OUT; void __iomem *outreg = nuc900_gpio->regbase + GPIO_OUT;
void __iomem *pio = nuc900_gpio->regbase + GPIO_DIR; void __iomem *pio = nuc900_gpio->regbase + GPIO_DIR;
unsigned int regval; unsigned int regval;
...@@ -149,6 +148,6 @@ void __init nuc900_init_gpio(int nr_group) ...@@ -149,6 +148,6 @@ void __init nuc900_init_gpio(int nr_group)
gpio_chip = &nuc900_gpio[i]; gpio_chip = &nuc900_gpio[i];
spin_lock_init(&gpio_chip->gpio_lock); spin_lock_init(&gpio_chip->gpio_lock);
gpio_chip->regbase = GPIO_BASE + i * GROUPINERV; gpio_chip->regbase = GPIO_BASE + i * GROUPINERV;
gpiochip_add(&gpio_chip->chip); gpiochip_add_data(&gpio_chip->chip, gpio_chip);
} }
} }
...@@ -154,8 +154,7 @@ orion_gpio_is_valid(struct orion_gpio_chip *ochip, unsigned pin, int mode) ...@@ -154,8 +154,7 @@ orion_gpio_is_valid(struct orion_gpio_chip *ochip, unsigned pin, int mode)
*/ */
static int orion_gpio_request(struct gpio_chip *chip, unsigned pin) static int orion_gpio_request(struct gpio_chip *chip, unsigned pin)
{ {
struct orion_gpio_chip *ochip = struct orion_gpio_chip *ochip = gpiochip_get_data(chip);
container_of(chip, struct orion_gpio_chip, chip);
if (orion_gpio_is_valid(ochip, pin, GPIO_INPUT_OK) || if (orion_gpio_is_valid(ochip, pin, GPIO_INPUT_OK) ||
orion_gpio_is_valid(ochip, pin, GPIO_OUTPUT_OK)) orion_gpio_is_valid(ochip, pin, GPIO_OUTPUT_OK))
...@@ -166,8 +165,7 @@ static int orion_gpio_request(struct gpio_chip *chip, unsigned pin) ...@@ -166,8 +165,7 @@ static int orion_gpio_request(struct gpio_chip *chip, unsigned pin)
static int orion_gpio_direction_input(struct gpio_chip *chip, unsigned pin) static int orion_gpio_direction_input(struct gpio_chip *chip, unsigned pin)
{ {
struct orion_gpio_chip *ochip = struct orion_gpio_chip *ochip = gpiochip_get_data(chip);
container_of(chip, struct orion_gpio_chip, chip);
unsigned long flags; unsigned long flags;
if (!orion_gpio_is_valid(ochip, pin, GPIO_INPUT_OK)) if (!orion_gpio_is_valid(ochip, pin, GPIO_INPUT_OK))
...@@ -182,8 +180,7 @@ static int orion_gpio_direction_input(struct gpio_chip *chip, unsigned pin) ...@@ -182,8 +180,7 @@ static int orion_gpio_direction_input(struct gpio_chip *chip, unsigned pin)
static int orion_gpio_get(struct gpio_chip *chip, unsigned pin) static int orion_gpio_get(struct gpio_chip *chip, unsigned pin)
{ {
struct orion_gpio_chip *ochip = struct orion_gpio_chip *ochip = gpiochip_get_data(chip);
container_of(chip, struct orion_gpio_chip, chip);
int val; int val;
if (readl(GPIO_IO_CONF(ochip)) & (1 << pin)) { if (readl(GPIO_IO_CONF(ochip)) & (1 << pin)) {
...@@ -198,8 +195,7 @@ static int orion_gpio_get(struct gpio_chip *chip, unsigned pin) ...@@ -198,8 +195,7 @@ static int orion_gpio_get(struct gpio_chip *chip, unsigned pin)
static int static int
orion_gpio_direction_output(struct gpio_chip *chip, unsigned pin, int value) orion_gpio_direction_output(struct gpio_chip *chip, unsigned pin, int value)
{ {
struct orion_gpio_chip *ochip = struct orion_gpio_chip *ochip = gpiochip_get_data(chip);
container_of(chip, struct orion_gpio_chip, chip);
unsigned long flags; unsigned long flags;
if (!orion_gpio_is_valid(ochip, pin, GPIO_OUTPUT_OK)) if (!orion_gpio_is_valid(ochip, pin, GPIO_OUTPUT_OK))
...@@ -216,8 +212,7 @@ orion_gpio_direction_output(struct gpio_chip *chip, unsigned pin, int value) ...@@ -216,8 +212,7 @@ orion_gpio_direction_output(struct gpio_chip *chip, unsigned pin, int value)
static void orion_gpio_set(struct gpio_chip *chip, unsigned pin, int value) static void orion_gpio_set(struct gpio_chip *chip, unsigned pin, int value)
{ {
struct orion_gpio_chip *ochip = struct orion_gpio_chip *ochip = gpiochip_get_data(chip);
container_of(chip, struct orion_gpio_chip, chip);
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&ochip->lock, flags); spin_lock_irqsave(&ochip->lock, flags);
...@@ -227,8 +222,7 @@ static void orion_gpio_set(struct gpio_chip *chip, unsigned pin, int value) ...@@ -227,8 +222,7 @@ static void orion_gpio_set(struct gpio_chip *chip, unsigned pin, int value)
static int orion_gpio_to_irq(struct gpio_chip *chip, unsigned pin) static int orion_gpio_to_irq(struct gpio_chip *chip, unsigned pin)
{ {
struct orion_gpio_chip *ochip = struct orion_gpio_chip *ochip = gpiochip_get_data(chip);
container_of(chip, struct orion_gpio_chip, chip);
return irq_create_mapping(ochip->domain, return irq_create_mapping(ochip->domain,
ochip->secondary_irq_base + pin); ochip->secondary_irq_base + pin);
...@@ -445,8 +439,8 @@ static void gpio_irq_handler(struct irq_desc *desc) ...@@ -445,8 +439,8 @@ static void gpio_irq_handler(struct irq_desc *desc)
static void orion_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) static void orion_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
{ {
struct orion_gpio_chip *ochip =
container_of(chip, struct orion_gpio_chip, chip); struct orion_gpio_chip *ochip = gpiochip_get_data(chip);
u32 out, io_conf, blink, in_pol, data_in, cause, edg_msk, lvl_msk; u32 out, io_conf, blink, in_pol, data_in, cause, edg_msk, lvl_msk;
int i; int i;
...@@ -567,7 +561,7 @@ void __init orion_gpio_init(struct device_node *np, ...@@ -567,7 +561,7 @@ void __init orion_gpio_init(struct device_node *np,
ochip->mask_offset = mask_offset; ochip->mask_offset = mask_offset;
ochip->secondary_irq_base = secondary_irq_base; ochip->secondary_irq_base = secondary_irq_base;
gpiochip_add(&ochip->chip); gpiochip_add_data(&ochip->chip, ochip);
/* /*
* Mask and clear GPIO interrupts. * Mask and clear GPIO interrupts.
......
...@@ -27,7 +27,6 @@ ...@@ -27,7 +27,6 @@
#include <asm/io.h> #include <asm/io.h>
#include <asm/setup.h> #include <asm/setup.h>
#include <asm/gpio.h>
#include <mach/at32ap700x.h> #include <mach/at32ap700x.h>
#include <mach/board.h> #include <mach/board.h>
......
...@@ -14,8 +14,8 @@ ...@@ -14,8 +14,8 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/gpio.h>
#include <asm/gpio.h>
#include <asm/io.h> #include <asm/io.h>
#include <mach/portmux.h> #include <mach/portmux.h>
......
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/gpio/driver.h>
/* FIXME: consumer API required for gpio_set_value() etc, get rid of this */
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/irq.h> #include <linux/irq.h>
...@@ -1159,7 +1161,7 @@ static int bfin_gpiolib_direction_output(struct gpio_chip *chip, unsigned gpio, ...@@ -1159,7 +1161,7 @@ static int bfin_gpiolib_direction_output(struct gpio_chip *chip, unsigned gpio,
static int bfin_gpiolib_get_value(struct gpio_chip *chip, unsigned gpio) static int bfin_gpiolib_get_value(struct gpio_chip *chip, unsigned gpio)
{ {
return bfin_gpio_get_value(gpio); return !!bfin_gpio_get_value(gpio);
} }
static void bfin_gpiolib_set_value(struct gpio_chip *chip, unsigned gpio, int value) static void bfin_gpiolib_set_value(struct gpio_chip *chip, unsigned gpio, int value)
...@@ -1197,7 +1199,7 @@ static struct gpio_chip bfin_chip = { ...@@ -1197,7 +1199,7 @@ static struct gpio_chip bfin_chip = {
static int __init bfin_gpiolib_setup(void) static int __init bfin_gpiolib_setup(void)
{ {
return gpiochip_add(&bfin_chip); return gpiochip_add_data(&bfin_chip, NULL);
} }
arch_initcall(bfin_gpiolib_setup); arch_initcall(bfin_gpiolib_setup);
#endif #endif
...@@ -11,9 +11,9 @@ ...@@ -11,9 +11,9 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/i2c/bfin_twi.h> #include <linux/i2c/bfin_twi.h>
#include <linux/gpio.h>
#include <asm/blackfin.h> #include <asm/blackfin.h>
#include <asm/gpio.h>
#include <asm/gptimers.h> #include <asm/gptimers.h>
#include <asm/bfin_can.h> #include <asm/bfin_can.h>
#include <asm/bfin_dma.h> #include <asm/bfin_dma.h>
......
...@@ -15,9 +15,9 @@ ...@@ -15,9 +15,9 @@
#include <linux/spi/flash.h> #include <linux/spi/flash.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/gpio.h>
#include <asm/bfin5xx_spi.h> #include <asm/bfin5xx_spi.h>
#include <asm/dma.h> #include <asm/dma.h>
#include <asm/gpio.h>
#include <asm/nand.h> #include <asm/nand.h>
#include <asm/portmux.h> #include <asm/portmux.h>
#include <asm/dpmc.h> #include <asm/dpmc.h>
......
...@@ -8,8 +8,8 @@ ...@@ -8,8 +8,8 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/gpio.h>
#include <asm/blackfin.h> #include <asm/blackfin.h>
#include <asm/gpio.h>
#include <asm/portmux.h> #include <asm/portmux.h>
#define DEFINE_REG(reg, off) \ #define DEFINE_REG(reg, off) \
...@@ -116,9 +116,9 @@ static struct gpio_chip bf538_porte_chip = { ...@@ -116,9 +116,9 @@ static struct gpio_chip bf538_porte_chip = {
static int __init bf538_extgpio_setup(void) static int __init bf538_extgpio_setup(void)
{ {
return gpiochip_add(&bf538_portc_chip) | return gpiochip_add_data(&bf538_portc_chip, NULL) |
gpiochip_add(&bf538_portd_chip) | gpiochip_add_data(&bf538_portd_chip, NULL) |
gpiochip_add(&bf538_porte_chip); gpiochip_add_data(&bf538_porte_chip, NULL);
} }
arch_initcall(bf538_extgpio_setup); arch_initcall(bf538_extgpio_setup);
......
...@@ -17,9 +17,9 @@ ...@@ -17,9 +17,9 @@
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/usb/musb.h> #include <linux/usb/musb.h>
#include <linux/gpio.h>
#include <asm/bfin5xx_spi.h> #include <asm/bfin5xx_spi.h>
#include <asm/dma.h> #include <asm/dma.h>
#include <asm/gpio.h>
#include <asm/nand.h> #include <asm/nand.h>
#include <asm/portmux.h> #include <asm/portmux.h>
#include <asm/bfin_sdh.h> #include <asm/bfin_sdh.h>
......
...@@ -20,9 +20,9 @@ ...@@ -20,9 +20,9 @@
#include <linux/pinctrl/machine.h> #include <linux/pinctrl/machine.h>
#include <linux/pinctrl/pinconf-generic.h> #include <linux/pinctrl/pinconf-generic.h>
#include <linux/platform_data/pinctrl-adi2.h> #include <linux/platform_data/pinctrl-adi2.h>
#include <linux/gpio.h>
#include <asm/bfin5xx_spi.h> #include <asm/bfin5xx_spi.h>
#include <asm/dma.h> #include <asm/dma.h>
#include <asm/gpio.h>
#include <asm/nand.h> #include <asm/nand.h>
#include <asm/dpmc.h> #include <asm/dpmc.h>
#include <asm/bfin_sport.h> #include <asm/bfin_sport.h>
......
...@@ -21,8 +21,8 @@ ...@@ -21,8 +21,8 @@
#include <linux/pinctrl/pinconf-generic.h> #include <linux/pinctrl/pinconf-generic.h>
#include <linux/platform_data/pinctrl-adi2.h> #include <linux/platform_data/pinctrl-adi2.h>
#include <linux/spi/adi_spi3.h> #include <linux/spi/adi_spi3.h>
#include <linux/gpio.h>
#include <asm/dma.h> #include <asm/dma.h>
#include <asm/gpio.h>
#include <asm/nand.h> #include <asm/nand.h>
#include <asm/dpmc.h> #include <asm/dpmc.h>
#include <asm/portmux.h> #include <asm/portmux.h>
......
...@@ -17,13 +17,13 @@ ...@@ -17,13 +17,13 @@
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/syscore_ops.h> #include <linux/syscore_ops.h>
#include <linux/gpio.h>
#include <asm/delay.h> #include <asm/delay.h>
#ifdef CONFIG_IPIPE #ifdef CONFIG_IPIPE
#include <linux/ipipe.h> #include <linux/ipipe.h>
#endif #endif
#include <asm/traps.h> #include <asm/traps.h>
#include <asm/blackfin.h> #include <asm/blackfin.h>
#include <asm/gpio.h>
#include <asm/irq_handler.h> #include <asm/irq_handler.h>
#include <asm/dpmc.h> #include <asm/dpmc.h>
#include <asm/traps.h> #include <asm/traps.h>
......
...@@ -15,9 +15,9 @@ ...@@ -15,9 +15,9 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/gpio.h>
#include <asm/cplb.h> #include <asm/cplb.h>
#include <asm/gpio.h>
#include <asm/dma.h> #include <asm/dma.h>
#include <asm/dpmc.h> #include <asm/dpmc.h>
#include <asm/pm.h> #include <asm/pm.h>
......
#ifndef __LINUX_GPIO_H
#warning Include linux/gpio.h instead of asm/gpio.h
#include <linux/gpio.h>
#endif
...@@ -178,7 +178,7 @@ static struct gpio_chip mcfgpio_chip = { ...@@ -178,7 +178,7 @@ static struct gpio_chip mcfgpio_chip = {
static int __init mcfgpio_sysinit(void) static int __init mcfgpio_sysinit(void)
{ {
gpiochip_add(&mcfgpio_chip); gpiochip_add_data(&mcfgpio_chip, NULL);
return subsys_system_register(&mcfgpio_subsys, NULL); return subsys_system_register(&mcfgpio_subsys, NULL);
} }
......
#ifndef __LINUX_GPIO_H
#warning Include linux/gpio.h instead of asm/gpio.h
#include <linux/gpio.h>
#endif
#ifndef __LINUX_GPIO_H
#warning Include linux/gpio.h instead of asm/gpio.h
#include <linux/gpio.h>
#endif
...@@ -160,14 +160,14 @@ static int __init alchemy_gpiochip_init(void) ...@@ -160,14 +160,14 @@ static int __init alchemy_gpiochip_init(void)
switch (alchemy_get_cputype()) { switch (alchemy_get_cputype()) {
case ALCHEMY_CPU_AU1000: case ALCHEMY_CPU_AU1000:
ret = gpiochip_add(&alchemy_gpio_chip[0]); ret = gpiochip_add_data(&alchemy_gpio_chip[0], NULL);
break; break;
case ALCHEMY_CPU_AU1500...ALCHEMY_CPU_AU1200: case ALCHEMY_CPU_AU1500...ALCHEMY_CPU_AU1200:
ret = gpiochip_add(&alchemy_gpio_chip[0]); ret = gpiochip_add_data(&alchemy_gpio_chip[0], NULL);
ret |= gpiochip_add(&alchemy_gpio_chip[1]); ret |= gpiochip_add_data(&alchemy_gpio_chip[1], NULL);
break; break;
case ALCHEMY_CPU_AU1300: case ALCHEMY_CPU_AU1300:
ret = gpiochip_add(&au1300_gpiochip); ret = gpiochip_add_data(&au1300_gpiochip, NULL);
break; break;
} }
return ret; return ret;
......
...@@ -33,8 +33,7 @@ struct ar7_gpio_chip { ...@@ -33,8 +33,7 @@ struct ar7_gpio_chip {
static int ar7_gpio_get_value(struct gpio_chip *chip, unsigned gpio) static int ar7_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
{ {
struct ar7_gpio_chip *gpch = struct ar7_gpio_chip *gpch = gpiochip_get_data(chip);
container_of(chip, struct ar7_gpio_chip, chip);
void __iomem *gpio_in = gpch->regs + AR7_GPIO_INPUT; void __iomem *gpio_in = gpch->regs + AR7_GPIO_INPUT;
return !!(readl(gpio_in) & (1 << gpio)); return !!(readl(gpio_in) & (1 << gpio));
...@@ -42,8 +41,7 @@ static int ar7_gpio_get_value(struct gpio_chip *chip, unsigned gpio) ...@@ -42,8 +41,7 @@ static int ar7_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
static int titan_gpio_get_value(struct gpio_chip *chip, unsigned gpio) static int titan_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
{ {
struct ar7_gpio_chip *gpch = struct ar7_gpio_chip *gpch = gpiochip_get_data(chip);
container_of(chip, struct ar7_gpio_chip, chip);
void __iomem *gpio_in0 = gpch->regs + TITAN_GPIO_INPUT_0; void __iomem *gpio_in0 = gpch->regs + TITAN_GPIO_INPUT_0;
void __iomem *gpio_in1 = gpch->regs + TITAN_GPIO_INPUT_1; void __iomem *gpio_in1 = gpch->regs + TITAN_GPIO_INPUT_1;
...@@ -53,8 +51,7 @@ static int titan_gpio_get_value(struct gpio_chip *chip, unsigned gpio) ...@@ -53,8 +51,7 @@ static int titan_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
static void ar7_gpio_set_value(struct gpio_chip *chip, static void ar7_gpio_set_value(struct gpio_chip *chip,
unsigned gpio, int value) unsigned gpio, int value)
{ {
struct ar7_gpio_chip *gpch = struct ar7_gpio_chip *gpch = gpiochip_get_data(chip);
container_of(chip, struct ar7_gpio_chip, chip);
void __iomem *gpio_out = gpch->regs + AR7_GPIO_OUTPUT; void __iomem *gpio_out = gpch->regs + AR7_GPIO_OUTPUT;
unsigned tmp; unsigned tmp;
...@@ -67,8 +64,7 @@ static void ar7_gpio_set_value(struct gpio_chip *chip, ...@@ -67,8 +64,7 @@ static void ar7_gpio_set_value(struct gpio_chip *chip,
static void titan_gpio_set_value(struct gpio_chip *chip, static void titan_gpio_set_value(struct gpio_chip *chip,
unsigned gpio, int value) unsigned gpio, int value)
{ {
struct ar7_gpio_chip *gpch = struct ar7_gpio_chip *gpch = gpiochip_get_data(chip);
container_of(chip, struct ar7_gpio_chip, chip);
void __iomem *gpio_out0 = gpch->regs + TITAN_GPIO_OUTPUT_0; void __iomem *gpio_out0 = gpch->regs + TITAN_GPIO_OUTPUT_0;
void __iomem *gpio_out1 = gpch->regs + TITAN_GPIO_OUTPUT_1; void __iomem *gpio_out1 = gpch->regs + TITAN_GPIO_OUTPUT_1;
unsigned tmp; unsigned tmp;
...@@ -81,8 +77,7 @@ static void titan_gpio_set_value(struct gpio_chip *chip, ...@@ -81,8 +77,7 @@ static void titan_gpio_set_value(struct gpio_chip *chip,
static int ar7_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) static int ar7_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
{ {
struct ar7_gpio_chip *gpch = struct ar7_gpio_chip *gpch = gpiochip_get_data(chip);
container_of(chip, struct ar7_gpio_chip, chip);
void __iomem *gpio_dir = gpch->regs + AR7_GPIO_DIR; void __iomem *gpio_dir = gpch->regs + AR7_GPIO_DIR;
writel(readl(gpio_dir) | (1 << gpio), gpio_dir); writel(readl(gpio_dir) | (1 << gpio), gpio_dir);
...@@ -92,8 +87,7 @@ static int ar7_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) ...@@ -92,8 +87,7 @@ static int ar7_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
static int titan_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) static int titan_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
{ {
struct ar7_gpio_chip *gpch = struct ar7_gpio_chip *gpch = gpiochip_get_data(chip);
container_of(chip, struct ar7_gpio_chip, chip);
void __iomem *gpio_dir0 = gpch->regs + TITAN_GPIO_DIR_0; void __iomem *gpio_dir0 = gpch->regs + TITAN_GPIO_DIR_0;
void __iomem *gpio_dir1 = gpch->regs + TITAN_GPIO_DIR_1; void __iomem *gpio_dir1 = gpch->regs + TITAN_GPIO_DIR_1;
...@@ -108,8 +102,7 @@ static int titan_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) ...@@ -108,8 +102,7 @@ static int titan_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
static int ar7_gpio_direction_output(struct gpio_chip *chip, static int ar7_gpio_direction_output(struct gpio_chip *chip,
unsigned gpio, int value) unsigned gpio, int value)
{ {
struct ar7_gpio_chip *gpch = struct ar7_gpio_chip *gpch = gpiochip_get_data(chip);
container_of(chip, struct ar7_gpio_chip, chip);
void __iomem *gpio_dir = gpch->regs + AR7_GPIO_DIR; void __iomem *gpio_dir = gpch->regs + AR7_GPIO_DIR;
ar7_gpio_set_value(chip, gpio, value); ar7_gpio_set_value(chip, gpio, value);
...@@ -121,8 +114,7 @@ static int ar7_gpio_direction_output(struct gpio_chip *chip, ...@@ -121,8 +114,7 @@ static int ar7_gpio_direction_output(struct gpio_chip *chip,
static int titan_gpio_direction_output(struct gpio_chip *chip, static int titan_gpio_direction_output(struct gpio_chip *chip,
unsigned gpio, int value) unsigned gpio, int value)
{ {
struct ar7_gpio_chip *gpch = struct ar7_gpio_chip *gpch = gpiochip_get_data(chip);
container_of(chip, struct ar7_gpio_chip, chip);
void __iomem *gpio_dir0 = gpch->regs + TITAN_GPIO_DIR_0; void __iomem *gpio_dir0 = gpch->regs + TITAN_GPIO_DIR_0;
void __iomem *gpio_dir1 = gpch->regs + TITAN_GPIO_DIR_1; void __iomem *gpio_dir1 = gpch->regs + TITAN_GPIO_DIR_1;
...@@ -335,7 +327,7 @@ int __init ar7_gpio_init(void) ...@@ -335,7 +327,7 @@ int __init ar7_gpio_init(void)
return -ENOMEM; return -ENOMEM;
} }
ret = gpiochip_add(&gpch->chip); ret = gpiochip_add_data(&gpch->chip, gpch);
if (ret) { if (ret) {
printk(KERN_ERR "%s: failed to add gpiochip\n", printk(KERN_ERR "%s: failed to add gpiochip\n",
gpch->chip.label); gpch->chip.label);
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/gpio.h> #include <linux/gpio/driver.h>
#include <bcm63xx_cpu.h> #include <bcm63xx_cpu.h>
#include <bcm63xx_gpio.h> #include <bcm63xx_gpio.h>
...@@ -147,5 +147,5 @@ int __init bcm63xx_gpio_init(void) ...@@ -147,5 +147,5 @@ int __init bcm63xx_gpio_init(void)
bcm63xx_gpio_chip.ngpio = bcm63xx_gpio_count(); bcm63xx_gpio_chip.ngpio = bcm63xx_gpio_count();
pr_info("registering %d GPIOs\n", bcm63xx_gpio_chip.ngpio); pr_info("registering %d GPIOs\n", bcm63xx_gpio_chip.ngpio);
return gpiochip_add(&bcm63xx_gpio_chip); return gpiochip_add_data(&bcm63xx_gpio_chip, NULL);
} }
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/gpio/driver.h>
/* FIXME: needed for gpio_request(), try to remove consumer API from driver */
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
...@@ -91,9 +93,9 @@ static inline struct jz_gpio_chip *gpio_to_jz_gpio_chip(unsigned int gpio) ...@@ -91,9 +93,9 @@ static inline struct jz_gpio_chip *gpio_to_jz_gpio_chip(unsigned int gpio)
return &jz4740_gpio_chips[gpio >> 5]; return &jz4740_gpio_chips[gpio >> 5];
} }
static inline struct jz_gpio_chip *gpio_chip_to_jz_gpio_chip(struct gpio_chip *gpio_chip) static inline struct jz_gpio_chip *gpio_chip_to_jz_gpio_chip(struct gpio_chip *gc)
{ {
return container_of(gpio_chip, struct jz_gpio_chip, gpio_chip); return gpiochip_get_data(gc);
} }
static inline struct jz_gpio_chip *irq_to_jz_gpio_chip(struct irq_data *data) static inline struct jz_gpio_chip *irq_to_jz_gpio_chip(struct irq_data *data)
...@@ -234,7 +236,7 @@ static int jz_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) ...@@ -234,7 +236,7 @@ static int jz_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
static int jz_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) static int jz_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
{ {
struct jz_gpio_chip *jz_gpio = gpio_chip_to_jz_gpio_chip(chip); struct jz_gpio_chip *jz_gpio = gpiochip_get_data(chip);
return jz_gpio->irq_base + gpio; return jz_gpio->irq_base + gpio;
} }
...@@ -270,7 +272,7 @@ uint32_t jz_gpio_port_get_value(int port, uint32_t mask) ...@@ -270,7 +272,7 @@ uint32_t jz_gpio_port_get_value(int port, uint32_t mask)
} }
EXPORT_SYMBOL(jz_gpio_port_get_value); EXPORT_SYMBOL(jz_gpio_port_get_value);
#define IRQ_TO_BIT(irq) BIT(irq_to_gpio(irq) & 0x1f) #define IRQ_TO_BIT(irq) BIT((irq - JZ4740_IRQ_GPIO(0)) & 0x1f)
static void jz_gpio_check_trigger_both(struct jz_gpio_chip *chip, unsigned int irq) static void jz_gpio_check_trigger_both(struct jz_gpio_chip *chip, unsigned int irq)
{ {
...@@ -449,7 +451,7 @@ static void jz4740_gpio_chip_init(struct jz_gpio_chip *chip, unsigned int id) ...@@ -449,7 +451,7 @@ static void jz4740_gpio_chip_init(struct jz_gpio_chip *chip, unsigned int id)
irq_setup_generic_chip(gc, IRQ_MSK(chip->gpio_chip.ngpio), irq_setup_generic_chip(gc, IRQ_MSK(chip->gpio_chip.ngpio),
IRQ_GC_INIT_NESTED_LOCK, 0, IRQ_NOPROBE | IRQ_LEVEL); IRQ_GC_INIT_NESTED_LOCK, 0, IRQ_NOPROBE | IRQ_LEVEL);
gpiochip_add(&chip->gpio_chip); gpiochip_add_data(&chip->gpio_chip, chip);
} }
static int __init jz4740_gpio_init(void) static int __init jz4740_gpio_init(void)
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/gpio.h> #include <linux/gpio/driver.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/io.h> #include <linux/io.h>
#include <asm/txx9pio.h> #include <asm/txx9pio.h>
...@@ -85,5 +85,5 @@ int __init txx9_gpio_init(unsigned long baseaddr, ...@@ -85,5 +85,5 @@ int __init txx9_gpio_init(unsigned long baseaddr,
return -ENODEV; return -ENODEV;
txx9_gpio_chip.base = base; txx9_gpio_chip.base = base;
txx9_gpio_chip.ngpio = num; txx9_gpio_chip.ngpio = num;
return gpiochip_add(&txx9_gpio_chip); return gpiochip_add_data(&txx9_gpio_chip, NULL);
} }
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
#include <linux/export.h> #include <linux/export.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/gpio.h> #include <linux/gpio/driver.h>
#include <asm/mach-rc32434/rb.h> #include <asm/mach-rc32434/rb.h>
#include <asm/mach-rc32434/gpio.h> #include <asm/mach-rc32434/gpio.h>
...@@ -88,7 +88,7 @@ static int rb532_gpio_get(struct gpio_chip *chip, unsigned offset) ...@@ -88,7 +88,7 @@ static int rb532_gpio_get(struct gpio_chip *chip, unsigned offset)
{ {
struct rb532_gpio_chip *gpch; struct rb532_gpio_chip *gpch;
gpch = container_of(chip, struct rb532_gpio_chip, chip); gpch = gpiochip_get_data(chip);
return !!rb532_get_bit(offset, gpch->regbase + GPIOD); return !!rb532_get_bit(offset, gpch->regbase + GPIOD);
} }
...@@ -100,7 +100,7 @@ static void rb532_gpio_set(struct gpio_chip *chip, ...@@ -100,7 +100,7 @@ static void rb532_gpio_set(struct gpio_chip *chip,
{ {
struct rb532_gpio_chip *gpch; struct rb532_gpio_chip *gpch;
gpch = container_of(chip, struct rb532_gpio_chip, chip); gpch = gpiochip_get_data(chip);
rb532_set_bit(value, offset, gpch->regbase + GPIOD); rb532_set_bit(value, offset, gpch->regbase + GPIOD);
} }
...@@ -111,7 +111,7 @@ static int rb532_gpio_direction_input(struct gpio_chip *chip, unsigned offset) ...@@ -111,7 +111,7 @@ static int rb532_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{ {
struct rb532_gpio_chip *gpch; struct rb532_gpio_chip *gpch;
gpch = container_of(chip, struct rb532_gpio_chip, chip); gpch = gpiochip_get_data(chip);
/* disable alternate function in case it's set */ /* disable alternate function in case it's set */
rb532_set_bit(0, offset, gpch->regbase + GPIOFUNC); rb532_set_bit(0, offset, gpch->regbase + GPIOFUNC);
...@@ -128,7 +128,7 @@ static int rb532_gpio_direction_output(struct gpio_chip *chip, ...@@ -128,7 +128,7 @@ static int rb532_gpio_direction_output(struct gpio_chip *chip,
{ {
struct rb532_gpio_chip *gpch; struct rb532_gpio_chip *gpch;
gpch = container_of(chip, struct rb532_gpio_chip, chip); gpch = gpiochip_get_data(chip);
/* disable alternate function in case it's set */ /* disable alternate function in case it's set */
rb532_set_bit(0, offset, gpch->regbase + GPIOFUNC); rb532_set_bit(0, offset, gpch->regbase + GPIOFUNC);
...@@ -200,7 +200,7 @@ int __init rb532_gpio_init(void) ...@@ -200,7 +200,7 @@ int __init rb532_gpio_init(void)
} }
/* Register our GPIO chip */ /* Register our GPIO chip */
gpiochip_add(&rb532_gpio_chip->chip); gpiochip_add_data(&rb532_gpio_chip->chip, rb532_gpio_chip);
return 0; return 0;
} }
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/gpio.h> #include <linux/gpio/driver.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/serial_core.h> #include <linux/serial_core.h>
#include <linux/mtd/physmap.h> #include <linux/mtd/physmap.h>
...@@ -687,16 +687,14 @@ struct txx9_iocled_data { ...@@ -687,16 +687,14 @@ struct txx9_iocled_data {
static int txx9_iocled_get(struct gpio_chip *chip, unsigned int offset) static int txx9_iocled_get(struct gpio_chip *chip, unsigned int offset)
{ {
struct txx9_iocled_data *data = struct txx9_iocled_data *data = gpiochip_get_data(chip);
container_of(chip, struct txx9_iocled_data, chip);
return !!(data->cur_val & (1 << offset)); return !!(data->cur_val & (1 << offset));
} }
static void txx9_iocled_set(struct gpio_chip *chip, unsigned int offset, static void txx9_iocled_set(struct gpio_chip *chip, unsigned int offset,
int value) int value)
{ {
struct txx9_iocled_data *data = struct txx9_iocled_data *data = gpiochip_get_data(chip);
container_of(chip, struct txx9_iocled_data, chip);
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&txx9_iocled_lock, flags); spin_lock_irqsave(&txx9_iocled_lock, flags);
if (value) if (value)
...@@ -749,7 +747,7 @@ void __init txx9_iocled_init(unsigned long baseaddr, ...@@ -749,7 +747,7 @@ void __init txx9_iocled_init(unsigned long baseaddr,
iocled->chip.label = "iocled"; iocled->chip.label = "iocled";
iocled->chip.base = basenum; iocled->chip.base = basenum;
iocled->chip.ngpio = num; iocled->chip.ngpio = num;
if (gpiochip_add(&iocled->chip)) if (gpiochip_add_data(&iocled->chip, iocled))
goto out_unmap; goto out_unmap;
if (basenum < 0) if (basenum < 0)
basenum = iocled->chip.base; basenum = iocled->chip.base;
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/gpio/driver.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/mtd/physmap.h> #include <linux/mtd/physmap.h>
...@@ -335,7 +336,7 @@ static void __init rbtx4938_mtd_init(void) ...@@ -335,7 +336,7 @@ static void __init rbtx4938_mtd_init(void)
static void __init rbtx4938_arch_init(void) static void __init rbtx4938_arch_init(void)
{ {
gpiochip_add(&rbtx4938_spi_gpio_chip); gpiochip_add_data(&rbtx4938_spi_gpio_chip, NULL);
rbtx4938_pci_setup(); rbtx4938_pci_setup();
rbtx4938_spi_init(); rbtx4938_spi_init();
} }
......
#ifndef __LINUX_GPIO_H
#warning Include linux/gpio.h instead of asm/gpio.h
#include <linux/gpio.h>
#endif
#ifndef __LINUX_GPIO_H
#warning Include linux/gpio.h instead of asm/gpio.h
#include <linux/gpio.h>
#endif
...@@ -78,7 +78,7 @@ static int ppc4xx_gpio_get(struct gpio_chip *gc, unsigned int gpio) ...@@ -78,7 +78,7 @@ static int ppc4xx_gpio_get(struct gpio_chip *gc, unsigned int gpio)
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct ppc4xx_gpio __iomem *regs = mm_gc->regs; struct ppc4xx_gpio __iomem *regs = mm_gc->regs;
return in_be32(&regs->ir) & GPIO_MASK(gpio); return !!(in_be32(&regs->ir) & GPIO_MASK(gpio));
} }
static inline void static inline void
......
...@@ -46,7 +46,7 @@ static int u8_gpio_get(struct gpio_chip *gc, unsigned int gpio) ...@@ -46,7 +46,7 @@ static int u8_gpio_get(struct gpio_chip *gc, unsigned int gpio)
{ {
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
return in_8(mm_gc->regs) & u8_pin2mask(gpio); return !!(in_8(mm_gc->regs) & u8_pin2mask(gpio));
} }
static void u8_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) static void u8_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
#ifndef __ASM_SH_MAGICPANELR2_H #ifndef __ASM_SH_MAGICPANELR2_H
#define __ASM_SH_MAGICPANELR2_H #define __ASM_SH_MAGICPANELR2_H
#include <asm/gpio.h> #include <linux/gpio.h>
#define __IO_PREFIX mpr2 #define __IO_PREFIX mpr2
#include <asm/io_generic.h> #include <asm/io_generic.h>
......
#ifndef __LINUX_GPIO_H
#warning Include linux/gpio.h instead of asm/gpio.h
#include <linux/gpio.h>
#endif
...@@ -52,7 +52,7 @@ device_initcall(puv3_gpio_leds_init); ...@@ -52,7 +52,7 @@ device_initcall(puv3_gpio_leds_init);
static int puv3_gpio_get(struct gpio_chip *chip, unsigned offset) static int puv3_gpio_get(struct gpio_chip *chip, unsigned offset)
{ {
return readl(GPIO_GPLR) & GPIO_GPIO(offset); return !!(readl(GPIO_GPLR) & GPIO_GPIO(offset));
} }
static void puv3_gpio_set(struct gpio_chip *chip, unsigned offset, int value) static void puv3_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
......
#ifndef __LINUX_GPIO_H
#warning Include linux/gpio.h instead of asm/gpio.h
#include <linux/gpio.h>
#endif
#ifndef __LINUX_GPIO_H
#warning Include linux/gpio.h instead of asm/gpio.h
#include <linux/gpio.h>
#endif
...@@ -30,8 +30,7 @@ ...@@ -30,8 +30,7 @@
#include <linux/ata_platform.h> #include <linux/ata_platform.h>
#include <linux/platform_data/atmel.h> #include <linux/platform_data/atmel.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/gpio.h>
#include <asm/gpio.h>
#define DRV_NAME "pata_at91" #define DRV_NAME "pata_at91"
#define DRV_VERSION "0.3" #define DRV_VERSION "0.3"
......
...@@ -36,8 +36,8 @@ ...@@ -36,8 +36,8 @@
#include <scsi/scsi_host.h> #include <scsi/scsi_host.h>
#include <linux/libata.h> #include <linux/libata.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/gpio.h>
#include <asm/dma.h> #include <asm/dma.h>
#include <asm/gpio.h>
#include <asm/portmux.h> #include <asm/portmux.h>
#define DRV_NAME "pata-bf54x" #define DRV_NAME "pata-bf54x"
......
...@@ -126,6 +126,16 @@ config GPIO_AMDPT ...@@ -126,6 +126,16 @@ config GPIO_AMDPT
driver for GPIO functionality on Promontory IOHub driver for GPIO functionality on Promontory IOHub
Require ACPI ASL code to enumerate as a platform device. Require ACPI ASL code to enumerate as a platform device.
config GPIO_ATH79
tristate "Atheros AR71XX/AR724X/AR913X GPIO support"
default y if ATH79
depends on ATH79 || COMPILE_TEST
select GPIO_GENERIC
select GPIOLIB_IRQCHIP
help
Select this option to enable GPIO driver for
Atheros AR71XX/AR724X/AR913X SoC devices.
config GPIO_BCM_KONA config GPIO_BCM_KONA
bool "Broadcom Kona GPIO" bool "Broadcom Kona GPIO"
depends on OF_GPIO && (ARCH_BCM_MOBILE || COMPILE_TEST) depends on OF_GPIO && (ARCH_BCM_MOBILE || COMPILE_TEST)
...@@ -281,12 +291,14 @@ config GPIO_MPC5200 ...@@ -281,12 +291,14 @@ config GPIO_MPC5200
depends on PPC_MPC52xx depends on PPC_MPC52xx
config GPIO_MPC8XXX config GPIO_MPC8XXX
bool "MPC512x/MPC8xxx GPIO support" bool "MPC512x/MPC8xxx/QorIQ GPIO support"
depends on PPC_MPC512x || PPC_MPC831x || PPC_MPC834x || PPC_MPC837x || \ depends on PPC_MPC512x || PPC_MPC831x || PPC_MPC834x || PPC_MPC837x || \
FSL_SOC_BOOKE || PPC_86xx FSL_SOC_BOOKE || PPC_86xx || ARCH_LAYERSCAPE || ARM || \
COMPILE_TEST
select GPIO_GENERIC
help help
Say Y here if you're going to use hardware that connects to the Say Y here if you're going to use hardware that connects to the
MPC512x/831x/834x/837x/8572/8610 GPIOs. MPC512x/831x/834x/837x/8572/8610/QorIQ GPIOs.
config GPIO_MVEBU config GPIO_MVEBU
def_bool y def_bool y
...@@ -380,6 +392,13 @@ config GPIO_TB10X ...@@ -380,6 +392,13 @@ config GPIO_TB10X
select GENERIC_IRQ_CHIP select GENERIC_IRQ_CHIP
select OF_GPIO select OF_GPIO
config GPIO_TS4800
tristate "TS-4800 DIO blocks and compatibles"
depends on OF_GPIO
select GPIO_GENERIC
help
This driver support TS-4800 FPGA GPIO controllers.
config GPIO_TZ1090 config GPIO_TZ1090
bool "Toumaz Xenif TZ1090 GPIO support" bool "Toumaz Xenif TZ1090 GPIO support"
depends on SOC_TZ1090 depends on SOC_TZ1090
...@@ -487,6 +506,15 @@ endmenu ...@@ -487,6 +506,15 @@ endmenu
menu "Port-mapped I/O GPIO drivers" menu "Port-mapped I/O GPIO drivers"
depends on X86 # Unconditional I/O space access depends on X86 # Unconditional I/O space access
config GPIO_104_DIO_48E
tristate "ACCES 104-DIO-48E GPIO support"
select GPIOLIB_IRQCHIP
help
Enables GPIO support for the ACCES 104-DIO-48E family. The base port
address for the device may be configured via the dio_48e_base module
parameter. The interrupt line number for the device may be configured
via the dio_48e_irq module parameter.
config GPIO_104_IDIO_16 config GPIO_104_IDIO_16
tristate "ACCES 104-IDIO-16 GPIO support" tristate "ACCES 104-IDIO-16 GPIO support"
select GPIOLIB_IRQCHIP select GPIOLIB_IRQCHIP
...@@ -506,10 +534,10 @@ config GPIO_104_IDI_48 ...@@ -506,10 +534,10 @@ config GPIO_104_IDI_48
via the idi_48_irq module parameter. via the idi_48_irq module parameter.
config GPIO_F7188X config GPIO_F7188X
tristate "F71869, F71869A, F71882FG and F71889F GPIO support" tristate "F71869, F71869A, F71882FG, F71889F and F81866 GPIO support"
help help
This option enables support for GPIOs found on Fintek Super-I/O This option enables support for GPIOs found on Fintek Super-I/O
chips F71869, F71869A, F71882FG and F71889F. chips F71869, F71869A, F71882FG, F71889F and F81866.
To compile this driver as a module, choose M here: the module will To compile this driver as a module, choose M here: the module will
be called f7188x-gpio. be called f7188x-gpio.
...@@ -570,6 +598,15 @@ config GPIO_TS5500 ...@@ -570,6 +598,15 @@ config GPIO_TS5500
blocks of the TS-5500: DIO1, DIO2 and the LCD port, and the TS-5600 blocks of the TS-5500: DIO1, DIO2 and the LCD port, and the TS-5600
LCD port. LCD port.
config GPIO_WS16C48
tristate "WinSystems WS16C48 GPIO support"
select GPIOLIB_IRQCHIP
help
Enables GPIO support for the WinSystems WS16C48. The base port address
for the device may be configured via the ws16c48_base module
parameter. The interrupt line number for the device may be configured
via the ws16c48_irq module parameter.
endmenu endmenu
menu "I2C GPIO expanders" menu "I2C GPIO expanders"
...@@ -702,6 +739,14 @@ config GPIO_SX150X ...@@ -702,6 +739,14 @@ config GPIO_SX150X
8 bits: sx1508q 8 bits: sx1508q
16 bits: sx1509q 16 bits: sx1509q
config GPIO_TPIC2810
tristate "TPIC2810 8-Bit I2C GPO expander"
help
Say yes here to enable the GPO driver for the TI TPIC2810 chip.
To compile this driver as a module, choose M here: the module will
be called gpio-tpic2810.
endmenu endmenu
menu "MFD GPIO expanders" menu "MFD GPIO expanders"
...@@ -844,6 +889,13 @@ config GPIO_TIMBERDALE ...@@ -844,6 +889,13 @@ config GPIO_TIMBERDALE
---help--- ---help---
Add support for the GPIO IP in the timberdale FPGA. Add support for the GPIO IP in the timberdale FPGA.
config GPIO_TPS65218
tristate "TPS65218 GPIO"
depends on MFD_TPS65218
help
Select this option to enable GPIO driver for the TPS65218
chip family.
config GPIO_TPS6586X config GPIO_TPS6586X
bool "TPS6586X GPIO" bool "TPS6586X GPIO"
depends on MFD_TPS6586X depends on MFD_TPS6586X
...@@ -1011,6 +1063,12 @@ config GPIO_MC33880 ...@@ -1011,6 +1063,12 @@ config GPIO_MC33880
SPI driver for Freescale MC33880 high-side/low-side switch. SPI driver for Freescale MC33880 high-side/low-side switch.
This provides GPIO interface supporting inputs and outputs. This provides GPIO interface supporting inputs and outputs.
config GPIO_PISOSR
tristate "Generic parallel-in/serial-out shift register"
help
GPIO driver for SPI compatible parallel-in/serial-out shift
registers. These are input only devices.
endmenu endmenu
menu "SPI or I2C GPIO expanders" menu "SPI or I2C GPIO expanders"
......
...@@ -12,6 +12,7 @@ obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o ...@@ -12,6 +12,7 @@ obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o
# Device drivers. Generally keep list sorted alphabetically # Device drivers. Generally keep list sorted alphabetically
obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o
obj-$(CONFIG_GPIO_104_DIO_48E) += gpio-104-dio-48e.o
obj-$(CONFIG_GPIO_104_IDIO_16) += gpio-104-idio-16.o obj-$(CONFIG_GPIO_104_IDIO_16) += gpio-104-idio-16.o
obj-$(CONFIG_GPIO_104_IDI_48) += gpio-104-idi-48.o obj-$(CONFIG_GPIO_104_IDI_48) += gpio-104-idi-48.o
obj-$(CONFIG_GPIO_74X164) += gpio-74x164.o obj-$(CONFIG_GPIO_74X164) += gpio-74x164.o
...@@ -23,7 +24,7 @@ obj-$(CONFIG_GPIO_ALTERA) += gpio-altera.o ...@@ -23,7 +24,7 @@ obj-$(CONFIG_GPIO_ALTERA) += gpio-altera.o
obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o
obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.o obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.o
obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o
obj-$(CONFIG_ATH79) += gpio-ath79.o obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o
obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o
obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o
obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o
...@@ -75,6 +76,7 @@ obj-$(CONFIG_GPIO_OMAP) += gpio-omap.o ...@@ -75,6 +76,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_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
obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o
...@@ -95,9 +97,12 @@ obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o ...@@ -95,9 +97,12 @@ obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o
obj-$(CONFIG_ARCH_TEGRA) += gpio-tegra.o obj-$(CONFIG_ARCH_TEGRA) += gpio-tegra.o
obj-$(CONFIG_GPIO_TIMBERDALE) += gpio-timberdale.o obj-$(CONFIG_GPIO_TIMBERDALE) += gpio-timberdale.o
obj-$(CONFIG_GPIO_PALMAS) += gpio-palmas.o obj-$(CONFIG_GPIO_PALMAS) += gpio-palmas.o
obj-$(CONFIG_GPIO_TPIC2810) += gpio-tpic2810.o
obj-$(CONFIG_GPIO_TPS65218) += gpio-tps65218.o
obj-$(CONFIG_GPIO_TPS6586X) += gpio-tps6586x.o obj-$(CONFIG_GPIO_TPS6586X) += gpio-tps6586x.o
obj-$(CONFIG_GPIO_TPS65910) += gpio-tps65910.o obj-$(CONFIG_GPIO_TPS65910) += gpio-tps65910.o
obj-$(CONFIG_GPIO_TPS65912) += gpio-tps65912.o obj-$(CONFIG_GPIO_TPS65912) += gpio-tps65912.o
obj-$(CONFIG_GPIO_TS4800) += gpio-ts4800.o
obj-$(CONFIG_GPIO_TS5500) += gpio-ts5500.o obj-$(CONFIG_GPIO_TS5500) += gpio-ts5500.o
obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o
obj-$(CONFIG_GPIO_TWL6040) += gpio-twl6040.o obj-$(CONFIG_GPIO_TWL6040) += gpio-twl6040.o
...@@ -111,6 +116,7 @@ obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o ...@@ -111,6 +116,7 @@ obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o
obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o
obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o
obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o
obj-$(CONFIG_GPIO_WS16C48) += gpio-ws16c48.o
obj-$(CONFIG_GPIO_XGENE) += gpio-xgene.o obj-$(CONFIG_GPIO_XGENE) += gpio-xgene.o
obj-$(CONFIG_GPIO_XGENE_SB) += gpio-xgene-sb.o obj-$(CONFIG_GPIO_XGENE_SB) += gpio-xgene-sb.o
obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o
......
/*
* GPIO driver for the ACCES 104-DIO-48E
* Copyright (C) 2016 William Breathitt Gray
*
* 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.
*/
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/gpio/driver.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/irqdesc.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
static unsigned dio_48e_base;
module_param(dio_48e_base, uint, 0);
MODULE_PARM_DESC(dio_48e_base, "ACCES 104-DIO-48E base address");
static unsigned dio_48e_irq;
module_param(dio_48e_irq, uint, 0);
MODULE_PARM_DESC(dio_48e_irq, "ACCES 104-DIO-48E interrupt line number");
/**
* struct dio48e_gpio - GPIO device private data structure
* @chip: instance of the gpio_chip
* @io_state: bit I/O state (whether bit is set to input or output)
* @out_state: output bits state
* @control: Control registers state
* @lock: synchronization lock to prevent I/O race conditions
* @base: base port address of the GPIO device
* @irq: Interrupt line number
* @irq_mask: I/O bits affected by interrupts
*/
struct dio48e_gpio {
struct gpio_chip chip;
unsigned char io_state[6];
unsigned char out_state[6];
unsigned char control[2];
spinlock_t lock;
unsigned base;
unsigned irq;
unsigned char irq_mask;
};
static int dio48e_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
{
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
const unsigned port = offset / 8;
const unsigned mask = BIT(offset % 8);
return !!(dio48egpio->io_state[port] & mask);
}
static int dio48e_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
const unsigned io_port = offset / 8;
const unsigned control_port = io_port / 2;
const unsigned control_addr = dio48egpio->base + 3 + control_port*4;
unsigned long flags;
unsigned control;
spin_lock_irqsave(&dio48egpio->lock, flags);
/* Check if configuring Port C */
if (io_port == 2 || io_port == 5) {
/* Port C can be configured by nibble */
if (offset % 8 > 3) {
dio48egpio->io_state[io_port] |= 0xF0;
dio48egpio->control[control_port] |= BIT(3);
} else {
dio48egpio->io_state[io_port] |= 0x0F;
dio48egpio->control[control_port] |= BIT(0);
}
} else {
dio48egpio->io_state[io_port] |= 0xFF;
if (io_port == 0 || io_port == 3)
dio48egpio->control[control_port] |= BIT(4);
else
dio48egpio->control[control_port] |= BIT(1);
}
control = BIT(7) | dio48egpio->control[control_port];
outb(control, control_addr);
control &= ~BIT(7);
outb(control, control_addr);
spin_unlock_irqrestore(&dio48egpio->lock, flags);
return 0;
}
static int dio48e_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
int value)
{
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
const unsigned io_port = offset / 8;
const unsigned control_port = io_port / 2;
const unsigned mask = BIT(offset % 8);
const unsigned control_addr = dio48egpio->base + 3 + control_port*4;
const unsigned out_port = (io_port > 2) ? io_port + 1 : io_port;
unsigned long flags;
unsigned control;
spin_lock_irqsave(&dio48egpio->lock, flags);
/* Check if configuring Port C */
if (io_port == 2 || io_port == 5) {
/* Port C can be configured by nibble */
if (offset % 8 > 3) {
dio48egpio->io_state[io_port] &= 0x0F;
dio48egpio->control[control_port] &= ~BIT(3);
} else {
dio48egpio->io_state[io_port] &= 0xF0;
dio48egpio->control[control_port] &= ~BIT(0);
}
} else {
dio48egpio->io_state[io_port] &= 0x00;
if (io_port == 0 || io_port == 3)
dio48egpio->control[control_port] &= ~BIT(4);
else
dio48egpio->control[control_port] &= ~BIT(1);
}
if (value)
dio48egpio->out_state[io_port] |= mask;
else
dio48egpio->out_state[io_port] &= ~mask;
control = BIT(7) | dio48egpio->control[control_port];
outb(control, control_addr);
outb(dio48egpio->out_state[io_port], dio48egpio->base + out_port);
control &= ~BIT(7);
outb(control, control_addr);
spin_unlock_irqrestore(&dio48egpio->lock, flags);
return 0;
}
static int dio48e_gpio_get(struct gpio_chip *chip, unsigned offset)
{
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
const unsigned port = offset / 8;
const unsigned mask = BIT(offset % 8);
const unsigned in_port = (port > 2) ? port + 1 : port;
unsigned long flags;
unsigned port_state;
spin_lock_irqsave(&dio48egpio->lock, flags);
/* ensure that GPIO is set for input */
if (!(dio48egpio->io_state[port] & mask)) {
spin_unlock_irqrestore(&dio48egpio->lock, flags);
return -EINVAL;
}
port_state = inb(dio48egpio->base + in_port);
spin_unlock_irqrestore(&dio48egpio->lock, flags);
return !!(port_state & mask);
}
static void dio48e_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
const unsigned port = offset / 8;
const unsigned mask = BIT(offset % 8);
const unsigned out_port = (port > 2) ? port + 1 : port;
unsigned long flags;
spin_lock_irqsave(&dio48egpio->lock, flags);
if (value)
dio48egpio->out_state[port] |= mask;
else
dio48egpio->out_state[port] &= ~mask;
outb(dio48egpio->out_state[port], dio48egpio->base + out_port);
spin_unlock_irqrestore(&dio48egpio->lock, flags);
}
static void dio48e_irq_ack(struct irq_data *data)
{
}
static void dio48e_irq_mask(struct irq_data *data)
{
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
const unsigned long offset = irqd_to_hwirq(data);
unsigned long flags;
/* only bit 3 on each respective Port C supports interrupts */
if (offset != 19 && offset != 43)
return;
spin_lock_irqsave(&dio48egpio->lock, flags);
if (offset == 19)
dio48egpio->irq_mask &= ~BIT(0);
else
dio48egpio->irq_mask &= ~BIT(1);
if (!dio48egpio->irq_mask)
/* disable interrupts */
inb(dio48egpio->base + 0xB);
spin_unlock_irqrestore(&dio48egpio->lock, flags);
}
static void dio48e_irq_unmask(struct irq_data *data)
{
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
const unsigned long offset = irqd_to_hwirq(data);
unsigned long flags;
/* only bit 3 on each respective Port C supports interrupts */
if (offset != 19 && offset != 43)
return;
spin_lock_irqsave(&dio48egpio->lock, flags);
if (!dio48egpio->irq_mask) {
/* enable interrupts */
outb(0x00, dio48egpio->base + 0xF);
outb(0x00, dio48egpio->base + 0xB);
}
if (offset == 19)
dio48egpio->irq_mask |= BIT(0);
else
dio48egpio->irq_mask |= BIT(1);
spin_unlock_irqrestore(&dio48egpio->lock, flags);
}
static int dio48e_irq_set_type(struct irq_data *data, unsigned flow_type)
{
const unsigned long offset = irqd_to_hwirq(data);
/* only bit 3 on each respective Port C supports interrupts */
if (offset != 19 && offset != 43)
return -EINVAL;
if (flow_type != IRQ_TYPE_NONE && flow_type != IRQ_TYPE_EDGE_RISING)
return -EINVAL;
return 0;
}
static struct irq_chip dio48e_irqchip = {
.name = "104-dio-48e",
.irq_ack = dio48e_irq_ack,
.irq_mask = dio48e_irq_mask,
.irq_unmask = dio48e_irq_unmask,
.irq_set_type = dio48e_irq_set_type
};
static irqreturn_t dio48e_irq_handler(int irq, void *dev_id)
{
struct dio48e_gpio *const dio48egpio = dev_id;
struct gpio_chip *const chip = &dio48egpio->chip;
const unsigned long irq_mask = dio48egpio->irq_mask;
unsigned long gpio;
for_each_set_bit(gpio, &irq_mask, 2)
generic_handle_irq(irq_find_mapping(chip->irqdomain,
19 + gpio*24));
spin_lock(&dio48egpio->lock);
outb(0x00, dio48egpio->base + 0xF);
spin_unlock(&dio48egpio->lock);
return IRQ_HANDLED;
}
static int __init dio48e_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct dio48e_gpio *dio48egpio;
const unsigned base = dio_48e_base;
const unsigned extent = 16;
const char *const name = dev_name(dev);
int err;
const unsigned irq = dio_48e_irq;
dio48egpio = devm_kzalloc(dev, sizeof(*dio48egpio), GFP_KERNEL);
if (!dio48egpio)
return -ENOMEM;
if (!devm_request_region(dev, base, extent, name)) {
dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
base, base + extent);
return -EBUSY;
}
dio48egpio->chip.label = name;
dio48egpio->chip.parent = dev;
dio48egpio->chip.owner = THIS_MODULE;
dio48egpio->chip.base = -1;
dio48egpio->chip.ngpio = 48;
dio48egpio->chip.get_direction = dio48e_gpio_get_direction;
dio48egpio->chip.direction_input = dio48e_gpio_direction_input;
dio48egpio->chip.direction_output = dio48e_gpio_direction_output;
dio48egpio->chip.get = dio48e_gpio_get;
dio48egpio->chip.set = dio48e_gpio_set;
dio48egpio->base = base;
dio48egpio->irq = irq;
spin_lock_init(&dio48egpio->lock);
dev_set_drvdata(dev, dio48egpio);
err = gpiochip_add_data(&dio48egpio->chip, dio48egpio);
if (err) {
dev_err(dev, "GPIO registering failed (%d)\n", err);
return err;
}
/* initialize all GPIO as output */
outb(0x80, base + 3);
outb(0x00, base);
outb(0x00, base + 1);
outb(0x00, base + 2);
outb(0x00, base + 3);
outb(0x80, base + 7);
outb(0x00, base + 4);
outb(0x00, base + 5);
outb(0x00, base + 6);
outb(0x00, base + 7);
/* disable IRQ by default */
inb(base + 0xB);
err = gpiochip_irqchip_add(&dio48egpio->chip, &dio48e_irqchip, 0,
handle_edge_irq, IRQ_TYPE_NONE);
if (err) {
dev_err(dev, "Could not add irqchip (%d)\n", err);
goto err_gpiochip_remove;
}
err = request_irq(irq, dio48e_irq_handler, 0, name, dio48egpio);
if (err) {
dev_err(dev, "IRQ handler registering failed (%d)\n", err);
goto err_gpiochip_remove;
}
return 0;
err_gpiochip_remove:
gpiochip_remove(&dio48egpio->chip);
return err;
}
static int dio48e_remove(struct platform_device *pdev)
{
struct dio48e_gpio *const dio48egpio = platform_get_drvdata(pdev);
free_irq(dio48egpio->irq, dio48egpio);
gpiochip_remove(&dio48egpio->chip);
return 0;
}
static struct platform_device *dio48e_device;
static struct platform_driver dio48e_driver = {
.driver = {
.name = "104-dio-48e"
},
.remove = dio48e_remove
};
static void __exit dio48e_exit(void)
{
platform_device_unregister(dio48e_device);
platform_driver_unregister(&dio48e_driver);
}
static int __init dio48e_init(void)
{
int err;
dio48e_device = platform_device_alloc(dio48e_driver.driver.name, -1);
if (!dio48e_device)
return -ENOMEM;
err = platform_device_add(dio48e_device);
if (err)
goto err_platform_device;
err = platform_driver_probe(&dio48e_driver, dio48e_probe);
if (err)
goto err_platform_driver;
return 0;
err_platform_driver:
platform_device_del(dio48e_device);
err_platform_device:
platform_device_put(dio48e_device);
return err;
}
module_init(dio48e_init);
module_exit(dio48e_exit);
MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
MODULE_DESCRIPTION("ACCES 104-DIO-48E GPIO driver");
MODULE_LICENSE("GPL v2");
...@@ -39,7 +39,6 @@ MODULE_PARM_DESC(idi_48_irq, "ACCES 104-IDI-48 interrupt line number"); ...@@ -39,7 +39,6 @@ MODULE_PARM_DESC(idi_48_irq, "ACCES 104-IDI-48 interrupt line number");
* @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
* @extent: extent of port address region of the GPIO device
* @irq: Interrupt line number * @irq: Interrupt line number
* @cos_enb: Change-Of-State IRQ enable boundaries mask * @cos_enb: Change-Of-State IRQ enable boundaries mask
*/ */
...@@ -49,7 +48,6 @@ struct idi_48_gpio { ...@@ -49,7 +48,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 extent;
unsigned irq; unsigned irq;
unsigned char cos_enb; unsigned char cos_enb;
}; };
...@@ -227,11 +225,10 @@ static int __init idi_48_probe(struct platform_device *pdev) ...@@ -227,11 +225,10 @@ static int __init idi_48_probe(struct platform_device *pdev)
if (!idi48gpio) if (!idi48gpio)
return -ENOMEM; return -ENOMEM;
if (!request_region(base, extent, name)) { if (!devm_request_region(dev, base, extent, name)) {
dev_err(dev, "Unable to lock %s port addresses (0x%X-0x%X)\n", dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
name, base, base + extent); base, base + extent);
err = -EBUSY; return -EBUSY;
goto err_lock_io_port;
} }
idi48gpio->chip.label = name; idi48gpio->chip.label = name;
...@@ -243,7 +240,6 @@ static int __init idi_48_probe(struct platform_device *pdev) ...@@ -243,7 +240,6 @@ static int __init idi_48_probe(struct platform_device *pdev)
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; idi48gpio->base = base;
idi48gpio->extent = extent;
idi48gpio->irq = irq; idi48gpio->irq = irq;
spin_lock_init(&idi48gpio->lock); spin_lock_init(&idi48gpio->lock);
...@@ -253,7 +249,7 @@ static int __init idi_48_probe(struct platform_device *pdev) ...@@ -253,7 +249,7 @@ static int __init idi_48_probe(struct platform_device *pdev)
err = gpiochip_add_data(&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);
goto err_gpio_register; return err;
} }
/* Disable IRQ by default */ /* Disable IRQ by default */
...@@ -264,23 +260,20 @@ static int __init idi_48_probe(struct platform_device *pdev) ...@@ -264,23 +260,20 @@ static int __init idi_48_probe(struct platform_device *pdev)
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_irqchip_add; goto err_gpiochip_remove;
} }
err = request_irq(irq, idi_48_irq_handler, 0, name, idi48gpio); err = request_irq(irq, idi_48_irq_handler, IRQF_SHARED, 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_request_irq; goto err_gpiochip_remove;
} }
return 0; return 0;
err_request_irq: err_gpiochip_remove:
err_gpiochip_irqchip_add:
gpiochip_remove(&idi48gpio->chip); gpiochip_remove(&idi48gpio->chip);
err_gpio_register:
release_region(base, extent);
err_lock_io_port:
return err; return err;
} }
...@@ -290,7 +283,6 @@ static int idi_48_remove(struct platform_device *pdev) ...@@ -290,7 +283,6 @@ static int idi_48_remove(struct platform_device *pdev)
free_irq(idi48gpio->irq, idi48gpio); free_irq(idi48gpio->irq, idi48gpio);
gpiochip_remove(&idi48gpio->chip); gpiochip_remove(&idi48gpio->chip);
release_region(idi48gpio->base, idi48gpio->extent);
return 0; return 0;
} }
...@@ -340,4 +332,4 @@ module_exit(idi_48_exit); ...@@ -340,4 +332,4 @@ module_exit(idi_48_exit);
MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
MODULE_DESCRIPTION("ACCES 104-IDI-48 GPIO driver"); MODULE_DESCRIPTION("ACCES 104-IDI-48 GPIO driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL v2");
...@@ -38,7 +38,6 @@ MODULE_PARM_DESC(idio_16_irq, "ACCES 104-IDIO-16 interrupt line number"); ...@@ -38,7 +38,6 @@ MODULE_PARM_DESC(idio_16_irq, "ACCES 104-IDIO-16 interrupt line number");
* @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
* @extent: extent of port address region of the GPIO device
* @irq: Interrupt line number * @irq: Interrupt line number
* @out_state: output bits state * @out_state: output bits state
*/ */
...@@ -47,7 +46,6 @@ struct idio_16_gpio { ...@@ -47,7 +46,6 @@ struct idio_16_gpio {
spinlock_t lock; spinlock_t lock;
unsigned long irq_mask; unsigned long irq_mask;
unsigned base; unsigned base;
unsigned extent;
unsigned irq; unsigned irq;
unsigned out_state; unsigned out_state;
}; };
...@@ -201,11 +199,10 @@ static int __init idio_16_probe(struct platform_device *pdev) ...@@ -201,11 +199,10 @@ static int __init idio_16_probe(struct platform_device *pdev)
if (!idio16gpio) if (!idio16gpio)
return -ENOMEM; return -ENOMEM;
if (!request_region(base, extent, name)) { if (!devm_request_region(dev, base, extent, name)) {
dev_err(dev, "Unable to lock %s port addresses (0x%X-0x%X)\n", dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
name, base, base + extent); base, base + extent);
err = -EBUSY; return -EBUSY;
goto err_lock_io_port;
} }
idio16gpio->chip.label = name; idio16gpio->chip.label = name;
...@@ -219,7 +216,6 @@ static int __init idio_16_probe(struct platform_device *pdev) ...@@ -219,7 +216,6 @@ static int __init idio_16_probe(struct platform_device *pdev)
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->base = base; idio16gpio->base = base;
idio16gpio->extent = extent;
idio16gpio->irq = irq; idio16gpio->irq = irq;
idio16gpio->out_state = 0xFFFF; idio16gpio->out_state = 0xFFFF;
...@@ -230,7 +226,7 @@ static int __init idio_16_probe(struct platform_device *pdev) ...@@ -230,7 +226,7 @@ static int __init idio_16_probe(struct platform_device *pdev)
err = gpiochip_add_data(&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);
goto err_gpio_register; return err;
} }
/* Disable IRQ by default */ /* Disable IRQ by default */
...@@ -241,23 +237,19 @@ static int __init idio_16_probe(struct platform_device *pdev) ...@@ -241,23 +237,19 @@ static int __init idio_16_probe(struct platform_device *pdev)
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_irqchip_add; goto err_gpiochip_remove;
} }
err = request_irq(irq, idio_16_irq_handler, 0, name, idio16gpio); err = request_irq(irq, 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_request_irq; goto err_gpiochip_remove;
} }
return 0; return 0;
err_request_irq: err_gpiochip_remove:
err_gpiochip_irqchip_add:
gpiochip_remove(&idio16gpio->chip); gpiochip_remove(&idio16gpio->chip);
err_gpio_register:
release_region(base, extent);
err_lock_io_port:
return err; return err;
} }
...@@ -267,7 +259,6 @@ static int idio_16_remove(struct platform_device *pdev) ...@@ -267,7 +259,6 @@ static int idio_16_remove(struct platform_device *pdev)
free_irq(idio16gpio->irq, idio16gpio); free_irq(idio16gpio->irq, idio16gpio);
gpiochip_remove(&idio16gpio->chip); gpiochip_remove(&idio16gpio->chip);
release_region(idio16gpio->base, idio16gpio->extent);
return 0; return 0;
} }
...@@ -317,4 +308,4 @@ module_exit(idio_16_exit); ...@@ -317,4 +308,4 @@ module_exit(idio_16_exit);
MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
MODULE_DESCRIPTION("ACCES 104-IDIO-16 GPIO driver"); MODULE_DESCRIPTION("ACCES 104-IDIO-16 GPIO driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL v2");
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
* License version 2. This program is licensed "as is" without any * License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied. * warranty of any kind, whether express or implied.
*/ */
#include <linux/ioport.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/gpio.h> #include <linux/gpio.h>
...@@ -204,7 +205,8 @@ static int __init amd_gpio_init(void) ...@@ -204,7 +205,8 @@ static int __init amd_gpio_init(void)
gp.pmbase &= 0x0000FF00; gp.pmbase &= 0x0000FF00;
if (gp.pmbase == 0) if (gp.pmbase == 0)
goto out; goto out;
if (!request_region(gp.pmbase + PMBASE_OFFSET, PMBASE_SIZE, "AMD GPIO")) { if (!devm_request_region(&pdev->dev, gp.pmbase + PMBASE_OFFSET,
PMBASE_SIZE, "AMD GPIO")) {
dev_err(&pdev->dev, "AMD GPIO region 0x%x already in use!\n", dev_err(&pdev->dev, "AMD GPIO region 0x%x already in use!\n",
gp.pmbase + PMBASE_OFFSET); gp.pmbase + PMBASE_OFFSET);
err = -EBUSY; err = -EBUSY;
...@@ -213,7 +215,6 @@ static int __init amd_gpio_init(void) ...@@ -213,7 +215,6 @@ static int __init amd_gpio_init(void)
gp.pm = ioport_map(gp.pmbase + PMBASE_OFFSET, PMBASE_SIZE); gp.pm = ioport_map(gp.pmbase + PMBASE_OFFSET, PMBASE_SIZE);
if (!gp.pm) { if (!gp.pm) {
dev_err(&pdev->dev, "Couldn't map io port into io memory\n"); dev_err(&pdev->dev, "Couldn't map io port into io memory\n");
release_region(gp.pmbase + PMBASE_OFFSET, PMBASE_SIZE);
err = -ENOMEM; err = -ENOMEM;
goto out; goto out;
} }
...@@ -228,7 +229,6 @@ static int __init amd_gpio_init(void) ...@@ -228,7 +229,6 @@ static int __init amd_gpio_init(void)
printk(KERN_ERR "GPIO registering failed (%d)\n", printk(KERN_ERR "GPIO registering failed (%d)\n",
err); err);
ioport_unmap(gp.pm); ioport_unmap(gp.pm);
release_region(gp.pmbase + PMBASE_OFFSET, PMBASE_SIZE);
goto out; goto out;
} }
out: out:
...@@ -239,7 +239,6 @@ static void __exit amd_gpio_exit(void) ...@@ -239,7 +239,6 @@ static void __exit amd_gpio_exit(void)
{ {
gpiochip_remove(&gp.chip); gpiochip_remove(&gp.chip);
ioport_unmap(gp.pm); ioport_unmap(gp.pm);
release_region(gp.pmbase + PMBASE_OFFSET, PMBASE_SIZE);
} }
module_init(amd_gpio_init); module_init(amd_gpio_init);
......
/* /*
* Atheros AR71XX/AR724X/AR913X GPIO API support * Atheros AR71XX/AR724X/AR913X GPIO API support
* *
* Copyright (C) 2015 Alban Bedel <albeu@free.fr>
* Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com> * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com>
* Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
* Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
* *
* Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP
*
* This program is free software; you can redistribute it and/or modify it * 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 * under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation. * by the Free Software Foundation.
...@@ -15,118 +14,204 @@ ...@@ -15,118 +14,204 @@
#include <linux/gpio/driver.h> #include <linux/gpio/driver.h>
#include <linux/platform_data/gpio-ath79.h> #include <linux/platform_data/gpio-ath79.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#define AR71XX_GPIO_REG_OE 0x00
#define AR71XX_GPIO_REG_IN 0x04
#define AR71XX_GPIO_REG_SET 0x0c
#define AR71XX_GPIO_REG_CLEAR 0x10
#include <asm/mach-ath79/ar71xx_regs.h> #define AR71XX_GPIO_REG_INT_ENABLE 0x14
#define AR71XX_GPIO_REG_INT_TYPE 0x18
#define AR71XX_GPIO_REG_INT_POLARITY 0x1c
#define AR71XX_GPIO_REG_INT_PENDING 0x20
#define AR71XX_GPIO_REG_INT_MASK 0x24
struct ath79_gpio_ctrl { struct ath79_gpio_ctrl {
struct gpio_chip chip; struct gpio_chip gc;
void __iomem *base; void __iomem *base;
spinlock_t lock; spinlock_t lock;
unsigned long both_edges;
}; };
static void ath79_gpio_set_value(struct gpio_chip *chip, static struct ath79_gpio_ctrl *irq_data_to_ath79_gpio(struct irq_data *data)
unsigned gpio, int value)
{ {
struct ath79_gpio_ctrl *ctrl = gpiochip_get_data(chip); struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
return container_of(gc, struct ath79_gpio_ctrl, gc);
}
static u32 ath79_gpio_read(struct ath79_gpio_ctrl *ctrl, unsigned reg)
{
return readl(ctrl->base + reg);
}
if (value) static void ath79_gpio_write(struct ath79_gpio_ctrl *ctrl,
__raw_writel(BIT(gpio), ctrl->base + AR71XX_GPIO_REG_SET); unsigned reg, u32 val)
else {
__raw_writel(BIT(gpio), ctrl->base + AR71XX_GPIO_REG_CLEAR); return writel(val, ctrl->base + reg);
} }
static int ath79_gpio_get_value(struct gpio_chip *chip, unsigned gpio) static bool ath79_gpio_update_bits(
struct ath79_gpio_ctrl *ctrl, unsigned reg, u32 mask, u32 bits)
{ {
struct ath79_gpio_ctrl *ctrl = gpiochip_get_data(chip); u32 old_val, new_val;
old_val = ath79_gpio_read(ctrl, reg);
new_val = (old_val & ~mask) | (bits & mask);
return (__raw_readl(ctrl->base + AR71XX_GPIO_REG_IN) >> gpio) & 1; if (new_val != old_val)
ath79_gpio_write(ctrl, reg, new_val);
return new_val != old_val;
} }
static int ath79_gpio_direction_input(struct gpio_chip *chip, static void ath79_gpio_irq_unmask(struct irq_data *data)
unsigned offset)
{ {
struct ath79_gpio_ctrl *ctrl = gpiochip_get_data(chip); struct ath79_gpio_ctrl *ctrl = irq_data_to_ath79_gpio(data);
u32 mask = BIT(irqd_to_hwirq(data));
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&ctrl->lock, flags); spin_lock_irqsave(&ctrl->lock, flags);
ath79_gpio_update_bits(ctrl, AR71XX_GPIO_REG_INT_MASK, mask, mask);
spin_unlock_irqrestore(&ctrl->lock, flags);
}
__raw_writel( static void ath79_gpio_irq_mask(struct irq_data *data)
__raw_readl(ctrl->base + AR71XX_GPIO_REG_OE) & ~BIT(offset), {
ctrl->base + AR71XX_GPIO_REG_OE); struct ath79_gpio_ctrl *ctrl = irq_data_to_ath79_gpio(data);
u32 mask = BIT(irqd_to_hwirq(data));
unsigned long flags;
spin_lock_irqsave(&ctrl->lock, flags);
ath79_gpio_update_bits(ctrl, AR71XX_GPIO_REG_INT_MASK, mask, 0);
spin_unlock_irqrestore(&ctrl->lock, flags); spin_unlock_irqrestore(&ctrl->lock, flags);
return 0;
} }
static int ath79_gpio_direction_output(struct gpio_chip *chip, static void ath79_gpio_irq_enable(struct irq_data *data)
unsigned offset, int value)
{ {
struct ath79_gpio_ctrl *ctrl = gpiochip_get_data(chip); struct ath79_gpio_ctrl *ctrl = irq_data_to_ath79_gpio(data);
u32 mask = BIT(irqd_to_hwirq(data));
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&ctrl->lock, flags); spin_lock_irqsave(&ctrl->lock, flags);
ath79_gpio_update_bits(ctrl, AR71XX_GPIO_REG_INT_ENABLE, mask, mask);
ath79_gpio_update_bits(ctrl, AR71XX_GPIO_REG_INT_MASK, mask, mask);
spin_unlock_irqrestore(&ctrl->lock, flags);
}
if (value) static void ath79_gpio_irq_disable(struct irq_data *data)
__raw_writel(BIT(offset), ctrl->base + AR71XX_GPIO_REG_SET); {
else struct ath79_gpio_ctrl *ctrl = irq_data_to_ath79_gpio(data);
__raw_writel(BIT(offset), ctrl->base + AR71XX_GPIO_REG_CLEAR); u32 mask = BIT(irqd_to_hwirq(data));
unsigned long flags;
__raw_writel(
__raw_readl(ctrl->base + AR71XX_GPIO_REG_OE) | BIT(offset),
ctrl->base + AR71XX_GPIO_REG_OE);
spin_lock_irqsave(&ctrl->lock, flags);
ath79_gpio_update_bits(ctrl, AR71XX_GPIO_REG_INT_MASK, mask, 0);
ath79_gpio_update_bits(ctrl, AR71XX_GPIO_REG_INT_ENABLE, mask, 0);
spin_unlock_irqrestore(&ctrl->lock, flags); spin_unlock_irqrestore(&ctrl->lock, flags);
return 0;
} }
static int ar934x_gpio_direction_input(struct gpio_chip *chip, unsigned offset) static int ath79_gpio_irq_set_type(struct irq_data *data,
unsigned int flow_type)
{ {
struct ath79_gpio_ctrl *ctrl = gpiochip_get_data(chip); struct ath79_gpio_ctrl *ctrl = irq_data_to_ath79_gpio(data);
u32 mask = BIT(irqd_to_hwirq(data));
u32 type = 0, polarity = 0;
unsigned long flags; unsigned long flags;
bool disabled;
switch (flow_type) {
case IRQ_TYPE_EDGE_RISING:
polarity |= mask;
case IRQ_TYPE_EDGE_FALLING:
case IRQ_TYPE_EDGE_BOTH:
break;
case IRQ_TYPE_LEVEL_HIGH:
polarity |= mask;
case IRQ_TYPE_LEVEL_LOW:
type |= mask;
break;
default:
return -EINVAL;
}
spin_lock_irqsave(&ctrl->lock, flags); spin_lock_irqsave(&ctrl->lock, flags);
__raw_writel( if (flow_type == IRQ_TYPE_EDGE_BOTH) {
__raw_readl(ctrl->base + AR71XX_GPIO_REG_OE) | BIT(offset), ctrl->both_edges |= mask;
ctrl->base + AR71XX_GPIO_REG_OE); polarity = ~ath79_gpio_read(ctrl, AR71XX_GPIO_REG_IN);
} else {
ctrl->both_edges &= ~mask;
}
/* As the IRQ configuration can't be loaded atomically we
* have to disable the interrupt while the configuration state
* is invalid.
*/
disabled = ath79_gpio_update_bits(
ctrl, AR71XX_GPIO_REG_INT_ENABLE, mask, 0);
ath79_gpio_update_bits(
ctrl, AR71XX_GPIO_REG_INT_TYPE, mask, type);
ath79_gpio_update_bits(
ctrl, AR71XX_GPIO_REG_INT_POLARITY, mask, polarity);
if (disabled)
ath79_gpio_update_bits(
ctrl, AR71XX_GPIO_REG_INT_ENABLE, mask, mask);
spin_unlock_irqrestore(&ctrl->lock, flags); spin_unlock_irqrestore(&ctrl->lock, flags);
return 0; return 0;
} }
static int ar934x_gpio_direction_output(struct gpio_chip *chip, unsigned offset, static struct irq_chip ath79_gpio_irqchip = {
int value) .name = "gpio-ath79",
.irq_enable = ath79_gpio_irq_enable,
.irq_disable = ath79_gpio_irq_disable,
.irq_mask = ath79_gpio_irq_mask,
.irq_unmask = ath79_gpio_irq_unmask,
.irq_set_type = ath79_gpio_irq_set_type,
};
static void ath79_gpio_irq_handler(struct irq_desc *desc)
{ {
struct ath79_gpio_ctrl *ctrl = gpiochip_get_data(chip); struct gpio_chip *gc = irq_desc_get_handler_data(desc);
unsigned long flags; struct irq_chip *irqchip = irq_desc_get_chip(desc);
struct ath79_gpio_ctrl *ctrl =
container_of(gc, struct ath79_gpio_ctrl, gc);
unsigned long flags, pending;
u32 both_edges, state;
int irq;
chained_irq_enter(irqchip, desc);
spin_lock_irqsave(&ctrl->lock, flags); spin_lock_irqsave(&ctrl->lock, flags);
if (value) pending = ath79_gpio_read(ctrl, AR71XX_GPIO_REG_INT_PENDING);
__raw_writel(BIT(offset), ctrl->base + AR71XX_GPIO_REG_SET);
else
__raw_writel(BIT(offset), ctrl->base + AR71XX_GPIO_REG_CLEAR);
__raw_writel( /* Update the polarity of the both edges irqs */
__raw_readl(ctrl->base + AR71XX_GPIO_REG_OE) & ~BIT(offset), both_edges = ctrl->both_edges & pending;
ctrl->base + AR71XX_GPIO_REG_OE); if (both_edges) {
state = ath79_gpio_read(ctrl, AR71XX_GPIO_REG_IN);
ath79_gpio_update_bits(ctrl, AR71XX_GPIO_REG_INT_POLARITY,
both_edges, ~state);
}
spin_unlock_irqrestore(&ctrl->lock, flags); spin_unlock_irqrestore(&ctrl->lock, flags);
return 0; if (pending) {
} for_each_set_bit(irq, &pending, gc->ngpio)
generic_handle_irq(
irq_linear_revmap(gc->irqdomain, irq));
}
static const struct gpio_chip ath79_gpio_chip = { chained_irq_exit(irqchip, desc);
.label = "ath79", }
.get = ath79_gpio_get_value,
.set = ath79_gpio_set_value,
.direction_input = ath79_gpio_direction_input,
.direction_output = ath79_gpio_direction_output,
.base = 0,
};
static const struct of_device_id ath79_gpio_of_match[] = { static const struct of_device_id ath79_gpio_of_match[] = {
{ .compatible = "qca,ar7100-gpio" }, { .compatible = "qca,ar7100-gpio" },
...@@ -147,6 +232,7 @@ static int ath79_gpio_probe(struct platform_device *pdev) ...@@ -147,6 +232,7 @@ static int ath79_gpio_probe(struct platform_device *pdev)
ctrl = devm_kzalloc(&pdev->dev, sizeof(*ctrl), GFP_KERNEL); ctrl = devm_kzalloc(&pdev->dev, sizeof(*ctrl), GFP_KERNEL);
if (!ctrl) if (!ctrl)
return -ENOMEM; return -ENOMEM;
platform_set_drvdata(pdev, ctrl);
if (np) { if (np) {
err = of_property_read_u32(np, "ngpios", &ath79_gpio_count); err = of_property_read_u32(np, "ngpios", &ath79_gpio_count);
...@@ -174,21 +260,53 @@ static int ath79_gpio_probe(struct platform_device *pdev) ...@@ -174,21 +260,53 @@ static int ath79_gpio_probe(struct platform_device *pdev)
return -ENOMEM; return -ENOMEM;
spin_lock_init(&ctrl->lock); spin_lock_init(&ctrl->lock);
memcpy(&ctrl->chip, &ath79_gpio_chip, sizeof(ctrl->chip)); err = bgpio_init(&ctrl->gc, &pdev->dev, 4,
ctrl->chip.parent = &pdev->dev; ctrl->base + AR71XX_GPIO_REG_IN,
ctrl->chip.ngpio = ath79_gpio_count; ctrl->base + AR71XX_GPIO_REG_SET,
if (oe_inverted) { ctrl->base + AR71XX_GPIO_REG_CLEAR,
ctrl->chip.direction_input = ar934x_gpio_direction_input; oe_inverted ? NULL : ctrl->base + AR71XX_GPIO_REG_OE,
ctrl->chip.direction_output = ar934x_gpio_direction_output; oe_inverted ? ctrl->base + AR71XX_GPIO_REG_OE : NULL,
0);
if (err) {
dev_err(&pdev->dev, "bgpio_init failed\n");
return err;
} }
/* Use base 0 to stay compatible with legacy platforms */
ctrl->gc.base = 0;
err = gpiochip_add_data(&ctrl->chip, ctrl); err = gpiochip_add_data(&ctrl->gc, ctrl);
if (err) { if (err) {
dev_err(&pdev->dev, dev_err(&pdev->dev,
"cannot add AR71xx GPIO chip, error=%d", err); "cannot add AR71xx GPIO chip, error=%d", err);
return err; return err;
} }
if (np && !of_property_read_bool(np, "interrupt-controller"))
return 0;
err = gpiochip_irqchip_add(&ctrl->gc, &ath79_gpio_irqchip, 0,
handle_simple_irq, IRQ_TYPE_NONE);
if (err) {
dev_err(&pdev->dev, "failed to add gpiochip_irqchip\n");
goto gpiochip_remove;
}
gpiochip_set_chained_irqchip(&ctrl->gc, &ath79_gpio_irqchip,
platform_get_irq(pdev, 0),
ath79_gpio_irq_handler);
return 0;
gpiochip_remove:
gpiochip_remove(&ctrl->gc);
return err;
}
static int ath79_gpio_remove(struct platform_device *pdev)
{
struct ath79_gpio_ctrl *ctrl = platform_get_drvdata(pdev);
gpiochip_remove(&ctrl->gc);
return 0; return 0;
} }
...@@ -198,6 +316,7 @@ static struct platform_driver ath79_gpio_driver = { ...@@ -198,6 +316,7 @@ static struct platform_driver ath79_gpio_driver = {
.of_match_table = ath79_gpio_of_match, .of_match_table = ath79_gpio_of_match,
}, },
.probe = ath79_gpio_probe, .probe = ath79_gpio_probe,
.remove = ath79_gpio_remove,
}; };
module_platform_driver(ath79_gpio_driver); module_platform_driver(ath79_gpio_driver);
...@@ -258,6 +258,8 @@ static int davinci_gpio_probe(struct platform_device *pdev) ...@@ -258,6 +258,8 @@ static int davinci_gpio_probe(struct platform_device *pdev)
spin_lock_init(&chips[i].lock); spin_lock_init(&chips[i].lock);
regs = gpio2regs(base); regs = gpio2regs(base);
if (!regs)
return -ENXIO;
chips[i].regs = regs; chips[i].regs = regs;
chips[i].set_data = &regs->set_data; chips[i].set_data = &regs->set_data;
chips[i].clr_data = &regs->clr_data; chips[i].clr_data = &regs->clr_data;
...@@ -433,8 +435,7 @@ static struct irq_chip *davinci_gpio_get_irq_chip(unsigned int irq) ...@@ -433,8 +435,7 @@ static struct irq_chip *davinci_gpio_get_irq_chip(unsigned int irq)
{ {
static struct irq_chip_type gpio_unbanked; static struct irq_chip_type gpio_unbanked;
gpio_unbanked = *container_of(irq_get_chip(irq), gpio_unbanked = *irq_data_get_chip_type(irq_get_irq_data(irq));
struct irq_chip_type, chip);
return &gpio_unbanked.chip; return &gpio_unbanked.chip;
}; };
......
/* /*
* GPIO driver for Fintek Super-I/O F71869, F71869A, F71882 and F71889 * GPIO driver for Fintek Super-I/O F71869, F71869A, F71882, F71889 and F81866
* *
* Copyright (C) 2010-2013 LaCie * Copyright (C) 2010-2013 LaCie
* *
...@@ -36,14 +36,16 @@ ...@@ -36,14 +36,16 @@
#define SIO_F71869A_ID 0x1007 /* F71869A chipset ID */ #define SIO_F71869A_ID 0x1007 /* F71869A chipset ID */
#define SIO_F71882_ID 0x0541 /* F71882 chipset ID */ #define SIO_F71882_ID 0x0541 /* F71882 chipset ID */
#define SIO_F71889_ID 0x0909 /* F71889 chipset ID */ #define SIO_F71889_ID 0x0909 /* F71889 chipset ID */
#define SIO_F81866_ID 0x1010 /* F81866 chipset ID */
enum chips { f71869, f71869a, f71882fg, f71889f }; enum chips { f71869, f71869a, f71882fg, f71889f, f81866 };
static const char * const f7188x_names[] = { static const char * const f7188x_names[] = {
"f71869", "f71869",
"f71869a", "f71869a",
"f71882fg", "f71882fg",
"f71889f", "f71889f",
"f81866",
}; };
struct f7188x_sio { struct f7188x_sio {
...@@ -190,6 +192,18 @@ static struct f7188x_gpio_bank f71889_gpio_bank[] = { ...@@ -190,6 +192,18 @@ static struct f7188x_gpio_bank f71889_gpio_bank[] = {
F7188X_GPIO_BANK(70, 8, 0x80), F7188X_GPIO_BANK(70, 8, 0x80),
}; };
static struct f7188x_gpio_bank f81866_gpio_bank[] = {
F7188X_GPIO_BANK(0, 8, 0xF0),
F7188X_GPIO_BANK(10, 8, 0xE0),
F7188X_GPIO_BANK(20, 8, 0xD0),
F7188X_GPIO_BANK(30, 8, 0xC0),
F7188X_GPIO_BANK(40, 8, 0xB0),
F7188X_GPIO_BANK(50, 8, 0xA0),
F7188X_GPIO_BANK(60, 8, 0x90),
F7188X_GPIO_BANK(70, 8, 0x80),
F7188X_GPIO_BANK(80, 8, 0x88),
};
static int f7188x_gpio_direction_in(struct gpio_chip *chip, unsigned offset) static int f7188x_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
{ {
int err; int err;
...@@ -318,6 +332,10 @@ static int f7188x_gpio_probe(struct platform_device *pdev) ...@@ -318,6 +332,10 @@ static int f7188x_gpio_probe(struct platform_device *pdev)
data->nr_bank = ARRAY_SIZE(f71889_gpio_bank); data->nr_bank = ARRAY_SIZE(f71889_gpio_bank);
data->bank = f71889_gpio_bank; data->bank = f71889_gpio_bank;
break; break;
case f81866:
data->nr_bank = ARRAY_SIZE(f81866_gpio_bank);
data->bank = f81866_gpio_bank;
break;
default: default:
return -ENODEV; return -ENODEV;
} }
...@@ -395,6 +413,9 @@ static int __init f7188x_find(int addr, struct f7188x_sio *sio) ...@@ -395,6 +413,9 @@ static int __init f7188x_find(int addr, struct f7188x_sio *sio)
case SIO_F71889_ID: case SIO_F71889_ID:
sio->type = f71889f; sio->type = f71889f;
break; break;
case SIO_F81866_ID:
sio->type = f81866;
break;
default: default:
pr_info(DRVNAME ": Unsupported Fintek device 0x%04x\n", devid); pr_info(DRVNAME ": Unsupported Fintek device 0x%04x\n", devid);
goto err; goto err;
...@@ -485,6 +506,6 @@ static void __exit f7188x_gpio_exit(void) ...@@ -485,6 +506,6 @@ static void __exit f7188x_gpio_exit(void)
} }
module_exit(f7188x_gpio_exit); module_exit(f7188x_gpio_exit);
MODULE_DESCRIPTION("GPIO driver for Super-I/O chips F71869, F71869A, F71882FG and F71889F"); MODULE_DESCRIPTION("GPIO driver for Super-I/O chips F71869, F71869A, F71882FG, F71889F and F81866");
MODULE_AUTHOR("Simon Guinot <simon.guinot@sequanux.org>"); MODULE_AUTHOR("Simon Guinot <simon.guinot@sequanux.org>");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/ioport.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/gpio.h> #include <linux/gpio.h>
...@@ -384,8 +385,8 @@ static struct ichx_desc avoton_desc = { ...@@ -384,8 +385,8 @@ static struct ichx_desc avoton_desc = {
.use_outlvl_cache = true, .use_outlvl_cache = true,
}; };
static int ichx_gpio_request_regions(struct resource *res_base, static int ichx_gpio_request_regions(struct device *dev,
const char *name, u8 use_gpio) struct resource *res_base, const char *name, u8 use_gpio)
{ {
int i; int i;
...@@ -395,34 +396,12 @@ static int ichx_gpio_request_regions(struct resource *res_base, ...@@ -395,34 +396,12 @@ static int ichx_gpio_request_regions(struct resource *res_base,
for (i = 0; i < ARRAY_SIZE(ichx_priv.desc->regs[0]); i++) { for (i = 0; i < ARRAY_SIZE(ichx_priv.desc->regs[0]); i++) {
if (!(use_gpio & (1 << i))) if (!(use_gpio & (1 << i)))
continue; continue;
if (!request_region( if (!devm_request_region(dev,
res_base->start + ichx_priv.desc->regs[0][i], res_base->start + ichx_priv.desc->regs[0][i],
ichx_priv.desc->reglen[i], name)) ichx_priv.desc->reglen[i], name))
goto request_err; return -EBUSY;
} }
return 0; return 0;
request_err:
/* Clean up: release already requested regions, if any */
for (i--; i >= 0; i--) {
if (!(use_gpio & (1 << i)))
continue;
release_region(res_base->start + ichx_priv.desc->regs[0][i],
ichx_priv.desc->reglen[i]);
}
return -EBUSY;
}
static void ichx_gpio_release_regions(struct resource *res_base, u8 use_gpio)
{
int i;
for (i = 0; i < ARRAY_SIZE(ichx_priv.desc->regs[0]); i++) {
if (!(use_gpio & (1 << i)))
continue;
release_region(res_base->start + ichx_priv.desc->regs[0][i],
ichx_priv.desc->reglen[i]);
}
} }
static int ichx_gpio_probe(struct platform_device *pdev) static int ichx_gpio_probe(struct platform_device *pdev)
...@@ -468,7 +447,7 @@ static int ichx_gpio_probe(struct platform_device *pdev) ...@@ -468,7 +447,7 @@ static int ichx_gpio_probe(struct platform_device *pdev)
spin_lock_init(&ichx_priv.lock); spin_lock_init(&ichx_priv.lock);
res_base = platform_get_resource(pdev, IORESOURCE_IO, ICH_RES_GPIO); res_base = platform_get_resource(pdev, IORESOURCE_IO, ICH_RES_GPIO);
ichx_priv.use_gpio = ich_info->use_gpio; ichx_priv.use_gpio = ich_info->use_gpio;
err = ichx_gpio_request_regions(res_base, pdev->name, err = ichx_gpio_request_regions(&pdev->dev, res_base, pdev->name,
ichx_priv.use_gpio); ichx_priv.use_gpio);
if (err) if (err)
return err; return err;
...@@ -489,8 +468,8 @@ static int ichx_gpio_probe(struct platform_device *pdev) ...@@ -489,8 +468,8 @@ static int ichx_gpio_probe(struct platform_device *pdev)
goto init; goto init;
} }
if (!request_region(res_pm->start, resource_size(res_pm), if (!devm_request_region(&pdev->dev, res_pm->start,
pdev->name)) { resource_size(res_pm), pdev->name)) {
pr_warn("ACPI BAR is busy, GPI 0 - 15 unavailable\n"); pr_warn("ACPI BAR is busy, GPI 0 - 15 unavailable\n");
goto init; goto init;
} }
...@@ -502,31 +481,19 @@ static int ichx_gpio_probe(struct platform_device *pdev) ...@@ -502,31 +481,19 @@ static int ichx_gpio_probe(struct platform_device *pdev)
err = gpiochip_add_data(&ichx_priv.chip, NULL); err = gpiochip_add_data(&ichx_priv.chip, NULL);
if (err) { if (err) {
pr_err("Failed to register GPIOs\n"); pr_err("Failed to register GPIOs\n");
goto add_err; return err;
} }
pr_info("GPIO from %d to %d on %s\n", ichx_priv.chip.base, 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); ichx_priv.chip.base + ichx_priv.chip.ngpio - 1, DRV_NAME);
return 0; return 0;
add_err:
ichx_gpio_release_regions(ichx_priv.gpio_base, ichx_priv.use_gpio);
if (ichx_priv.pm_base)
release_region(ichx_priv.pm_base->start,
resource_size(ichx_priv.pm_base));
return err;
} }
static int ichx_gpio_remove(struct platform_device *pdev) static int ichx_gpio_remove(struct platform_device *pdev)
{ {
gpiochip_remove(&ichx_priv.chip); gpiochip_remove(&ichx_priv.chip);
ichx_gpio_release_regions(ichx_priv.gpio_base, ichx_priv.use_gpio);
if (ichx_priv.pm_base)
release_region(ichx_priv.pm_base->start,
resource_size(ichx_priv.pm_base));
return 0; return 0;
} }
......
...@@ -205,18 +205,6 @@ static int ks8695_gpio_to_irq(struct gpio_chip *gc, unsigned int pin) ...@@ -205,18 +205,6 @@ static int ks8695_gpio_to_irq(struct gpio_chip *gc, unsigned int pin)
return gpio_irq[pin]; return gpio_irq[pin];
} }
/*
* Map IRQ number to GPIO line.
*/
int irq_to_gpio(unsigned int irq)
{
if ((irq < KS8695_IRQ_EXTERN0) || (irq > KS8695_IRQ_EXTERN3))
return -EINVAL;
return (irq - KS8695_IRQ_EXTERN0);
}
EXPORT_SYMBOL(irq_to_gpio);
/* GPIOLIB interface */ /* GPIOLIB interface */
static struct gpio_chip ks8695_gpio_chip = { static struct gpio_chip ks8695_gpio_chip = {
......
...@@ -803,6 +803,8 @@ static int mcp230xx_probe(struct i2c_client *client, ...@@ -803,6 +803,8 @@ static int mcp230xx_probe(struct i2c_client *client,
pdata = devm_kzalloc(&client->dev, pdata = devm_kzalloc(&client->dev,
sizeof(struct mcp23s08_platform_data), sizeof(struct mcp23s08_platform_data),
GFP_KERNEL); GFP_KERNEL);
if (!pdata)
return -ENOMEM;
pdata->base = -1; pdata->base = -1;
} }
} }
......
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/module.h> #include <linux/module.h>
#include <asm/gpio.h>
#include <asm/mpc52xx.h> #include <asm/mpc52xx.h>
#include <sysdev/fsl_soc.h> #include <sysdev/fsl_soc.h>
......
/* /*
* GPIOs on MPC512x/8349/8572/8610 and compatible * GPIOs on MPC512x/8349/8572/8610/QorIQ and compatible
* *
* Copyright (C) 2008 Peter Korsgaard <jacmet@sunsite.dk> * Copyright (C) 2008 Peter Korsgaard <jacmet@sunsite.dk>
* Copyright (C) 2016 Freescale Semiconductor Inc.
* *
* This file is licensed under the terms of the GNU General Public License * This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any * version 2. This program is licensed "as is" without any warranty of any
...@@ -14,11 +15,12 @@ ...@@ -14,11 +15,12 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_gpio.h> #include <linux/of_gpio.h>
#include <linux/of_address.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/gpio.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/gpio/driver.h>
#define MPC8XXX_GPIO_PINS 32 #define MPC8XXX_GPIO_PINS 32
...@@ -31,32 +33,20 @@ ...@@ -31,32 +33,20 @@
#define GPIO_ICR2 0x18 #define GPIO_ICR2 0x18
struct mpc8xxx_gpio_chip { struct mpc8xxx_gpio_chip {
struct of_mm_gpio_chip mm_gc; struct gpio_chip gc;
void __iomem *regs;
raw_spinlock_t lock; raw_spinlock_t lock;
/* unsigned long (*read_reg)(void __iomem *reg);
* shadowed data register to be able to clear/set output pins in void (*write_reg)(void __iomem *reg, unsigned long data);
* open drain mode safely
*/ int (*direction_output)(struct gpio_chip *chip,
u32 data; unsigned offset, int value);
struct irq_domain *irq; struct irq_domain *irq;
unsigned int irqn; unsigned int irqn;
const void *of_dev_id_data;
}; };
static inline u32 mpc8xxx_gpio2mask(unsigned int gpio)
{
return 1u << (MPC8XXX_GPIO_PINS - 1 - gpio);
}
static void mpc8xxx_gpio_save_regs(struct of_mm_gpio_chip *mm)
{
struct mpc8xxx_gpio_chip *mpc8xxx_gc =
container_of(mm, struct mpc8xxx_gpio_chip, mm_gc);
mpc8xxx_gc->data = in_be32(mm->regs + GPIO_DAT);
}
/* Workaround GPIO 1 errata on MPC8572/MPC8536. The status of GPIOs /* Workaround GPIO 1 errata on MPC8572/MPC8536. The status of GPIOs
* defined as output cannot be determined by reading GPDAT register, * defined as output cannot be determined by reading GPDAT register,
* so we use shadow data register instead. The status of input pins * so we use shadow data register instead. The status of input pins
...@@ -65,117 +55,36 @@ static void mpc8xxx_gpio_save_regs(struct of_mm_gpio_chip *mm) ...@@ -65,117 +55,36 @@ static void mpc8xxx_gpio_save_regs(struct of_mm_gpio_chip *mm)
static int mpc8572_gpio_get(struct gpio_chip *gc, unsigned int gpio) static int mpc8572_gpio_get(struct gpio_chip *gc, unsigned int gpio)
{ {
u32 val; u32 val;
struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
struct mpc8xxx_gpio_chip *mpc8xxx_gc = gpiochip_get_data(gc); struct mpc8xxx_gpio_chip *mpc8xxx_gc = gpiochip_get_data(gc);
u32 out_mask, out_shadow; u32 out_mask, out_shadow;
out_mask = in_be32(mm->regs + GPIO_DIR); out_mask = mpc8xxx_gc->read_reg(mpc8xxx_gc->regs + GPIO_DIR);
val = mpc8xxx_gc->read_reg(mpc8xxx_gc->regs + GPIO_DAT) & ~out_mask;
val = in_be32(mm->regs + GPIO_DAT) & ~out_mask; out_shadow = gc->bgpio_data & out_mask;
out_shadow = mpc8xxx_gc->data & out_mask;
return !!((val | out_shadow) & mpc8xxx_gpio2mask(gpio)); return !!((val | out_shadow) & gc->pin2mask(gc, gpio));
} }
static int mpc8xxx_gpio_get(struct gpio_chip *gc, unsigned int gpio) static int mpc5121_gpio_dir_out(struct gpio_chip *gc,
unsigned int gpio, int val)
{ {
struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
return in_be32(mm->regs + GPIO_DAT) & mpc8xxx_gpio2mask(gpio);
}
static void mpc8xxx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
struct mpc8xxx_gpio_chip *mpc8xxx_gc = gpiochip_get_data(gc); struct mpc8xxx_gpio_chip *mpc8xxx_gc = gpiochip_get_data(gc);
unsigned long flags;
raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
if (val)
mpc8xxx_gc->data |= mpc8xxx_gpio2mask(gpio);
else
mpc8xxx_gc->data &= ~mpc8xxx_gpio2mask(gpio);
out_be32(mm->regs + GPIO_DAT, mpc8xxx_gc->data);
raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
}
static void mpc8xxx_gpio_set_multiple(struct gpio_chip *gc,
unsigned long *mask, unsigned long *bits)
{
struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
struct mpc8xxx_gpio_chip *mpc8xxx_gc = gpiochip_get_data(gc);
unsigned long flags;
int i;
raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
for (i = 0; i < gc->ngpio; i++) {
if (*mask == 0)
break;
if (__test_and_clear_bit(i, mask)) {
if (test_bit(i, bits))
mpc8xxx_gc->data |= mpc8xxx_gpio2mask(i);
else
mpc8xxx_gc->data &= ~mpc8xxx_gpio2mask(i);
}
}
out_be32(mm->regs + GPIO_DAT, mpc8xxx_gc->data);
raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
}
static int mpc8xxx_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
struct mpc8xxx_gpio_chip *mpc8xxx_gc = gpiochip_get_data(gc);
unsigned long flags;
raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
clrbits32(mm->regs + GPIO_DIR, mpc8xxx_gpio2mask(gpio));
raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
return 0;
}
static int mpc8xxx_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
struct mpc8xxx_gpio_chip *mpc8xxx_gc = gpiochip_get_data(gc);
unsigned long flags;
mpc8xxx_gpio_set(gc, gpio, val);
raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
setbits32(mm->regs + GPIO_DIR, mpc8xxx_gpio2mask(gpio));
raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
return 0;
}
static int mpc5121_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
{
/* GPIO 28..31 are input only on MPC5121 */ /* GPIO 28..31 are input only on MPC5121 */
if (gpio >= 28) if (gpio >= 28)
return -EINVAL; return -EINVAL;
return mpc8xxx_gpio_dir_out(gc, gpio, val); return mpc8xxx_gc->direction_output(gc, gpio, val);
} }
static int mpc5125_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) static int mpc5125_gpio_dir_out(struct gpio_chip *gc,
unsigned int gpio, int val)
{ {
struct mpc8xxx_gpio_chip *mpc8xxx_gc = gpiochip_get_data(gc);
/* GPIO 0..3 are input only on MPC5125 */ /* GPIO 0..3 are input only on MPC5125 */
if (gpio <= 3) if (gpio <= 3)
return -EINVAL; return -EINVAL;
return mpc8xxx_gpio_dir_out(gc, gpio, val); return mpc8xxx_gc->direction_output(gc, gpio, val);
} }
static int mpc8xxx_gpio_to_irq(struct gpio_chip *gc, unsigned offset) static int mpc8xxx_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
...@@ -192,10 +101,10 @@ static void mpc8xxx_gpio_irq_cascade(struct irq_desc *desc) ...@@ -192,10 +101,10 @@ static void mpc8xxx_gpio_irq_cascade(struct irq_desc *desc)
{ {
struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_desc_get_handler_data(desc); struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_desc_get_handler_data(desc);
struct irq_chip *chip = irq_desc_get_chip(desc); struct irq_chip *chip = irq_desc_get_chip(desc);
struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;
unsigned int mask; unsigned int mask;
mask = in_be32(mm->regs + GPIO_IER) & in_be32(mm->regs + GPIO_IMR); mask = mpc8xxx_gc->read_reg(mpc8xxx_gc->regs + GPIO_IER)
& mpc8xxx_gc->read_reg(mpc8xxx_gc->regs + GPIO_IMR);
if (mask) if (mask)
generic_handle_irq(irq_linear_revmap(mpc8xxx_gc->irq, generic_handle_irq(irq_linear_revmap(mpc8xxx_gc->irq,
32 - ffs(mask))); 32 - ffs(mask)));
...@@ -206,12 +115,14 @@ static void mpc8xxx_gpio_irq_cascade(struct irq_desc *desc) ...@@ -206,12 +115,14 @@ static void mpc8xxx_gpio_irq_cascade(struct irq_desc *desc)
static void mpc8xxx_irq_unmask(struct irq_data *d) static void mpc8xxx_irq_unmask(struct irq_data *d)
{ {
struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d); struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);
struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; struct gpio_chip *gc = &mpc8xxx_gc->gc;
unsigned long flags; unsigned long flags;
raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags); raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
setbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(irqd_to_hwirq(d))); mpc8xxx_gc->write_reg(mpc8xxx_gc->regs + GPIO_IMR,
mpc8xxx_gc->read_reg(mpc8xxx_gc->regs + GPIO_IMR)
| gc->pin2mask(gc, irqd_to_hwirq(d)));
raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
} }
...@@ -219,12 +130,14 @@ static void mpc8xxx_irq_unmask(struct irq_data *d) ...@@ -219,12 +130,14 @@ static void mpc8xxx_irq_unmask(struct irq_data *d)
static void mpc8xxx_irq_mask(struct irq_data *d) static void mpc8xxx_irq_mask(struct irq_data *d)
{ {
struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d); struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);
struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; struct gpio_chip *gc = &mpc8xxx_gc->gc;
unsigned long flags; unsigned long flags;
raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags); raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
clrbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(irqd_to_hwirq(d))); mpc8xxx_gc->write_reg(mpc8xxx_gc->regs + GPIO_IMR,
mpc8xxx_gc->read_reg(mpc8xxx_gc->regs + GPIO_IMR)
& ~(gc->pin2mask(gc, irqd_to_hwirq(d))));
raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
} }
...@@ -232,29 +145,32 @@ static void mpc8xxx_irq_mask(struct irq_data *d) ...@@ -232,29 +145,32 @@ static void mpc8xxx_irq_mask(struct irq_data *d)
static void mpc8xxx_irq_ack(struct irq_data *d) static void mpc8xxx_irq_ack(struct irq_data *d)
{ {
struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d); struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);
struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; struct gpio_chip *gc = &mpc8xxx_gc->gc;
out_be32(mm->regs + GPIO_IER, mpc8xxx_gpio2mask(irqd_to_hwirq(d))); mpc8xxx_gc->write_reg(mpc8xxx_gc->regs + GPIO_IER,
gc->pin2mask(gc, irqd_to_hwirq(d)));
} }
static int mpc8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type) static int mpc8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type)
{ {
struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d); struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);
struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; struct gpio_chip *gc = &mpc8xxx_gc->gc;
unsigned long flags; unsigned long flags;
switch (flow_type) { switch (flow_type) {
case IRQ_TYPE_EDGE_FALLING: case IRQ_TYPE_EDGE_FALLING:
raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags); raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
setbits32(mm->regs + GPIO_ICR, mpc8xxx_gc->write_reg(mpc8xxx_gc->regs + GPIO_ICR,
mpc8xxx_gpio2mask(irqd_to_hwirq(d))); mpc8xxx_gc->read_reg(mpc8xxx_gc->regs + GPIO_ICR)
| gc->pin2mask(gc, irqd_to_hwirq(d)));
raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
break; break;
case IRQ_TYPE_EDGE_BOTH: case IRQ_TYPE_EDGE_BOTH:
raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags); raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
clrbits32(mm->regs + GPIO_ICR, mpc8xxx_gc->write_reg(mpc8xxx_gc->regs + GPIO_ICR,
mpc8xxx_gpio2mask(irqd_to_hwirq(d))); mpc8xxx_gc->read_reg(mpc8xxx_gc->regs + GPIO_ICR)
& ~(gc->pin2mask(gc, irqd_to_hwirq(d))));
raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
break; break;
...@@ -268,17 +184,16 @@ static int mpc8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type) ...@@ -268,17 +184,16 @@ static int mpc8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type)
static int mpc512x_irq_set_type(struct irq_data *d, unsigned int flow_type) static int mpc512x_irq_set_type(struct irq_data *d, unsigned int flow_type)
{ {
struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d); struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);
struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;
unsigned long gpio = irqd_to_hwirq(d); unsigned long gpio = irqd_to_hwirq(d);
void __iomem *reg; void __iomem *reg;
unsigned int shift; unsigned int shift;
unsigned long flags; unsigned long flags;
if (gpio < 16) { if (gpio < 16) {
reg = mm->regs + GPIO_ICR; reg = mpc8xxx_gc->regs + GPIO_ICR;
shift = (15 - gpio) * 2; shift = (15 - gpio) * 2;
} else { } else {
reg = mm->regs + GPIO_ICR2; reg = mpc8xxx_gc->regs + GPIO_ICR2;
shift = (15 - (gpio % 16)) * 2; shift = (15 - (gpio % 16)) * 2;
} }
...@@ -286,20 +201,25 @@ static int mpc512x_irq_set_type(struct irq_data *d, unsigned int flow_type) ...@@ -286,20 +201,25 @@ static int mpc512x_irq_set_type(struct irq_data *d, unsigned int flow_type)
case IRQ_TYPE_EDGE_FALLING: case IRQ_TYPE_EDGE_FALLING:
case IRQ_TYPE_LEVEL_LOW: case IRQ_TYPE_LEVEL_LOW:
raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags); raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
clrsetbits_be32(reg, 3 << shift, 2 << shift); mpc8xxx_gc->write_reg(reg,
(mpc8xxx_gc->read_reg(reg) & ~(3 << shift))
| (2 << shift));
raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
break; break;
case IRQ_TYPE_EDGE_RISING: case IRQ_TYPE_EDGE_RISING:
case IRQ_TYPE_LEVEL_HIGH: case IRQ_TYPE_LEVEL_HIGH:
raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags); raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
clrsetbits_be32(reg, 3 << shift, 1 << shift); mpc8xxx_gc->write_reg(reg,
(mpc8xxx_gc->read_reg(reg) & ~(3 << shift))
| (1 << shift));
raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
break; break;
case IRQ_TYPE_EDGE_BOTH: case IRQ_TYPE_EDGE_BOTH:
raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags); raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
clrbits32(reg, 3 << shift); mpc8xxx_gc->write_reg(reg,
(mpc8xxx_gc->read_reg(reg) & ~(3 << shift)));
raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
break; break;
...@@ -354,8 +274,6 @@ static const struct mpc8xxx_gpio_devtype mpc8572_gpio_devtype = { ...@@ -354,8 +274,6 @@ static const struct mpc8xxx_gpio_devtype mpc8572_gpio_devtype = {
}; };
static const struct mpc8xxx_gpio_devtype mpc8xxx_gpio_devtype_default = { static const struct mpc8xxx_gpio_devtype mpc8xxx_gpio_devtype_default = {
.gpio_dir_out = mpc8xxx_gpio_dir_out,
.gpio_get = mpc8xxx_gpio_get,
.irq_set_type = mpc8xxx_irq_set_type, .irq_set_type = mpc8xxx_irq_set_type,
}; };
...@@ -374,9 +292,7 @@ static int mpc8xxx_probe(struct platform_device *pdev) ...@@ -374,9 +292,7 @@ static int mpc8xxx_probe(struct platform_device *pdev)
{ {
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
struct mpc8xxx_gpio_chip *mpc8xxx_gc; struct mpc8xxx_gpio_chip *mpc8xxx_gc;
struct of_mm_gpio_chip *mm_gc; struct gpio_chip *gc;
struct gpio_chip *gc;
const struct of_device_id *id;
const struct mpc8xxx_gpio_devtype *devtype = const struct mpc8xxx_gpio_devtype *devtype =
of_device_get_match_data(&pdev->dev); of_device_get_match_data(&pdev->dev);
int ret; int ret;
...@@ -389,12 +305,35 @@ static int mpc8xxx_probe(struct platform_device *pdev) ...@@ -389,12 +305,35 @@ static int mpc8xxx_probe(struct platform_device *pdev)
raw_spin_lock_init(&mpc8xxx_gc->lock); raw_spin_lock_init(&mpc8xxx_gc->lock);
mm_gc = &mpc8xxx_gc->mm_gc; mpc8xxx_gc->regs = of_iomap(np, 0);
gc = &mm_gc->gc; if (!mpc8xxx_gc->regs)
return -ENOMEM;
gc = &mpc8xxx_gc->gc;
if (of_property_read_bool(np, "little-endian")) {
ret = bgpio_init(gc, &pdev->dev, 4,
mpc8xxx_gc->regs + GPIO_DAT,
NULL, NULL,
mpc8xxx_gc->regs + GPIO_DIR, NULL,
BGPIOF_BIG_ENDIAN);
if (ret)
goto err;
dev_dbg(&pdev->dev, "GPIO registers are LITTLE endian\n");
} else {
ret = bgpio_init(gc, &pdev->dev, 4,
mpc8xxx_gc->regs + GPIO_DAT,
NULL, NULL,
mpc8xxx_gc->regs + GPIO_DIR, NULL,
BGPIOF_BIG_ENDIAN
| BGPIOF_BIG_ENDIAN_BYTE_ORDER);
if (ret)
goto err;
dev_dbg(&pdev->dev, "GPIO registers are BIG endian\n");
}
mm_gc->save_regs = mpc8xxx_gpio_save_regs; mpc8xxx_gc->read_reg = gc->read_reg;
gc->ngpio = MPC8XXX_GPIO_PINS; mpc8xxx_gc->write_reg = gc->write_reg;
gc->direction_input = mpc8xxx_gpio_dir_in;
if (!devtype) if (!devtype)
devtype = &mpc8xxx_gpio_devtype_default; devtype = &mpc8xxx_gpio_devtype_default;
...@@ -405,18 +344,21 @@ static int mpc8xxx_probe(struct platform_device *pdev) ...@@ -405,18 +344,21 @@ static int mpc8xxx_probe(struct platform_device *pdev)
*/ */
mpc8xxx_irq_chip.irq_set_type = devtype->irq_set_type; mpc8xxx_irq_chip.irq_set_type = devtype->irq_set_type;
gc->direction_output = devtype->gpio_dir_out ?: mpc8xxx_gpio_dir_out; gc->direction_output = devtype->gpio_dir_out ?: gc->direction_output;
gc->get = devtype->gpio_get ?: mpc8xxx_gpio_get; gc->get = devtype->gpio_get ?: gc->get;
gc->set = mpc8xxx_gpio_set;
gc->set_multiple = mpc8xxx_gpio_set_multiple;
gc->to_irq = mpc8xxx_gpio_to_irq; gc->to_irq = mpc8xxx_gpio_to_irq;
ret = of_mm_gpiochip_add_data(np, mm_gc, mpc8xxx_gc); mpc8xxx_gc->direction_output = gc->direction_output;
if (ret)
return ret; ret = gpiochip_add_data(gc, mpc8xxx_gc);
if (ret) {
pr_err("%s: GPIO chip registration failed with status %d\n",
np->full_name, ret);
goto err;
}
mpc8xxx_gc->irqn = irq_of_parse_and_map(np, 0); mpc8xxx_gc->irqn = irq_of_parse_and_map(np, 0);
if (mpc8xxx_gc->irqn == NO_IRQ) if (!mpc8xxx_gc->irqn)
return 0; return 0;
mpc8xxx_gc->irq = irq_domain_add_linear(np, MPC8XXX_GPIO_PINS, mpc8xxx_gc->irq = irq_domain_add_linear(np, MPC8XXX_GPIO_PINS,
...@@ -424,18 +366,16 @@ static int mpc8xxx_probe(struct platform_device *pdev) ...@@ -424,18 +366,16 @@ static int mpc8xxx_probe(struct platform_device *pdev)
if (!mpc8xxx_gc->irq) if (!mpc8xxx_gc->irq)
return 0; return 0;
id = of_match_node(mpc8xxx_gpio_ids, np);
if (id)
mpc8xxx_gc->of_dev_id_data = id->data;
/* ack and mask all irqs */ /* ack and mask all irqs */
out_be32(mm_gc->regs + GPIO_IER, 0xffffffff); mpc8xxx_gc->write_reg(mpc8xxx_gc->regs + GPIO_IER, 0xffffffff);
out_be32(mm_gc->regs + GPIO_IMR, 0); mpc8xxx_gc->write_reg(mpc8xxx_gc->regs + GPIO_IMR, 0);
irq_set_chained_handler_and_data(mpc8xxx_gc->irqn, irq_set_chained_handler_and_data(mpc8xxx_gc->irqn,
mpc8xxx_gpio_irq_cascade, mpc8xxx_gc); mpc8xxx_gpio_irq_cascade, mpc8xxx_gc);
return 0; return 0;
err:
iounmap(mpc8xxx_gc->regs);
return ret;
} }
static int mpc8xxx_remove(struct platform_device *pdev) static int mpc8xxx_remove(struct platform_device *pdev)
...@@ -447,7 +387,8 @@ static int mpc8xxx_remove(struct platform_device *pdev) ...@@ -447,7 +387,8 @@ static int mpc8xxx_remove(struct platform_device *pdev)
irq_domain_remove(mpc8xxx_gc->irq); irq_domain_remove(mpc8xxx_gc->irq);
} }
of_mm_gpiochip_remove(&mpc8xxx_gc->mm_gc); gpiochip_remove(&mpc8xxx_gc->gc);
iounmap(mpc8xxx_gc->regs);
return 0; return 0;
} }
......
/*
* Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
* Andrew F. Davis <afd@ti.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 "as is" WITHOUT ANY WARRANTY of any
* kind, whether expressed or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License version 2 for more details.
*/
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/spi/spi.h>
#define DEFAULT_NGPIO 8
/**
* struct pisosr_gpio - GPIO driver data
* @chip: GPIO controller chip
* @spi: SPI device pointer
* @buffer: Buffer for device reads
* @buffer_size: Size of buffer
* @load_gpio: GPIO pin used to load input into device
* @lock: Protects read sequences
*/
struct pisosr_gpio {
struct gpio_chip chip;
struct spi_device *spi;
u8 *buffer;
size_t buffer_size;
struct gpio_desc *load_gpio;
struct mutex lock;
};
static int pisosr_gpio_refresh(struct pisosr_gpio *gpio)
{
int ret;
mutex_lock(&gpio->lock);
if (gpio->load_gpio) {
gpiod_set_value(gpio->load_gpio, 1);
udelay(1); /* registers load time (~10ns) */
gpiod_set_value(gpio->load_gpio, 0);
udelay(1); /* registers recovery time (~5ns) */
}
ret = spi_read(gpio->spi, gpio->buffer, gpio->buffer_size);
mutex_unlock(&gpio->lock);
return ret;
}
static int pisosr_gpio_get_direction(struct gpio_chip *chip,
unsigned offset)
{
/* This device always input */
return 1;
}
static int pisosr_gpio_direction_input(struct gpio_chip *chip,
unsigned offset)
{
/* This device always input */
return 0;
}
static int pisosr_gpio_direction_output(struct gpio_chip *chip,
unsigned offset, int value)
{
/* This device is input only */
return -EINVAL;
}
static int pisosr_gpio_get(struct gpio_chip *chip, unsigned offset)
{
struct pisosr_gpio *gpio = gpiochip_get_data(chip);
/* Refresh may not always be needed */
pisosr_gpio_refresh(gpio);
return (gpio->buffer[offset / 8] >> (offset % 8)) & 0x1;
}
static struct gpio_chip template_chip = {
.label = "pisosr-gpio",
.owner = THIS_MODULE,
.get_direction = pisosr_gpio_get_direction,
.direction_input = pisosr_gpio_direction_input,
.direction_output = pisosr_gpio_direction_output,
.get = pisosr_gpio_get,
.base = -1,
.ngpio = DEFAULT_NGPIO,
.can_sleep = true,
};
static int pisosr_gpio_probe(struct spi_device *spi)
{
struct device *dev = &spi->dev;
struct pisosr_gpio *gpio;
int ret;
gpio = devm_kzalloc(dev, sizeof(*gpio), GFP_KERNEL);
if (!gpio)
return -ENOMEM;
spi_set_drvdata(spi, gpio);
gpio->chip = template_chip;
gpio->chip.parent = dev;
of_property_read_u16(dev->of_node, "ngpios", &gpio->chip.ngpio);
gpio->spi = spi;
gpio->buffer_size = DIV_ROUND_UP(gpio->chip.ngpio, 8);
gpio->buffer = devm_kzalloc(dev, gpio->buffer_size, GFP_KERNEL);
if (!gpio->buffer)
return -ENOMEM;
gpio->load_gpio = devm_gpiod_get(dev, "load", GPIOD_OUT_LOW);
if (IS_ERR(gpio->load_gpio)) {
ret = PTR_ERR(gpio->load_gpio);
if (ret != -ENOENT && ret != -ENOSYS) {
if (ret != -EPROBE_DEFER)
dev_err(dev, "Unable to allocate load GPIO\n");
return ret;
}
gpio->load_gpio = NULL;
}
mutex_init(&gpio->lock);
ret = gpiochip_add_data(&gpio->chip, gpio);
if (ret < 0) {
dev_err(dev, "Unable to register gpiochip\n");
return ret;
}
return 0;
}
static int pisosr_gpio_remove(struct spi_device *spi)
{
struct pisosr_gpio *gpio = spi_get_drvdata(spi);
gpiochip_remove(&gpio->chip);
mutex_destroy(&gpio->lock);
return 0;
}
static const struct spi_device_id pisosr_gpio_id_table[] = {
{ "pisosr-gpio", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(spi, pisosr_gpio_id_table);
static const struct of_device_id pisosr_gpio_of_match_table[] = {
{ .compatible = "pisosr-gpio", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, pisosr_gpio_of_match_table);
static struct spi_driver pisosr_gpio_driver = {
.driver = {
.name = "pisosr-gpio",
.of_match_table = pisosr_gpio_of_match_table,
},
.probe = pisosr_gpio_probe,
.remove = pisosr_gpio_remove,
.id_table = pisosr_gpio_id_table,
};
module_spi_driver(pisosr_gpio_driver);
MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
MODULE_DESCRIPTION("SPI Compatible PISO Shift Register GPIO Driver");
MODULE_LICENSE("GPL v2");
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
* (at your option) any later version. * (at your option) any later version.
*/ */
#include <linux/ioport.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -228,7 +229,8 @@ static int sch311x_gpio_probe(struct platform_device *pdev) ...@@ -228,7 +229,8 @@ static int sch311x_gpio_probe(struct platform_device *pdev)
int err, i; int err, i;
/* we can register all GPIO data registers at once */ /* we can register all GPIO data registers at once */
if (!request_region(pdata->runtime_reg + GP1, 6, DRV_NAME)) { if (!devm_request_region(&pdev->dev, pdata->runtime_reg + GP1, 6,
DRV_NAME)) {
dev_err(&pdev->dev, "Failed to request region 0x%04x-0x%04x.\n", dev_err(&pdev->dev, "Failed to request region 0x%04x-0x%04x.\n",
pdata->runtime_reg + GP1, pdata->runtime_reg + GP1 + 5); pdata->runtime_reg + GP1, pdata->runtime_reg + GP1 + 5);
return -EBUSY; return -EBUSY;
...@@ -273,7 +275,6 @@ static int sch311x_gpio_probe(struct platform_device *pdev) ...@@ -273,7 +275,6 @@ static int sch311x_gpio_probe(struct platform_device *pdev)
return 0; return 0;
exit_err: exit_err:
release_region(pdata->runtime_reg + GP1, 6);
/* release already registered chips */ /* release already registered chips */
for (--i; i >= 0; i--) for (--i; i >= 0; i--)
gpiochip_remove(&priv->blocks[i].chip); gpiochip_remove(&priv->blocks[i].chip);
...@@ -282,12 +283,9 @@ static int sch311x_gpio_probe(struct platform_device *pdev) ...@@ -282,12 +283,9 @@ static int sch311x_gpio_probe(struct platform_device *pdev)
static int sch311x_gpio_remove(struct platform_device *pdev) static int sch311x_gpio_remove(struct platform_device *pdev)
{ {
struct sch311x_pdev_data *pdata = dev_get_platdata(&pdev->dev);
struct sch311x_gpio_priv *priv = platform_get_drvdata(pdev); struct sch311x_gpio_priv *priv = platform_get_drvdata(pdev);
int i; int i;
release_region(pdata->runtime_reg + GP1, 6);
for (i = 0; i < ARRAY_SIZE(priv->blocks); i++) { for (i = 0; i < ARRAY_SIZE(priv->blocks); i++) {
gpiochip_remove(&priv->blocks[i].chip); gpiochip_remove(&priv->blocks[i].chip);
dev_info(&pdev->dev, dev_info(&pdev->dev,
......
/*
* Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
* Andrew F. Davis <afd@ti.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 "as is" WITHOUT ANY WARRANTY of any
* kind, whether expressed or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License version 2 for more details.
*/
#include <linux/gpio/driver.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/mutex.h>
#define TPIC2810_WS_COMMAND 0x44
/**
* struct tpic2810 - GPIO driver data
* @chip: GPIO controller chip
* @client: I2C device pointer
* @buffer: Buffer for device register
* @lock: Protects write sequences
*/
struct tpic2810 {
struct gpio_chip chip;
struct i2c_client *client;
u8 buffer;
struct mutex lock;
};
static void tpic2810_set(struct gpio_chip *chip, unsigned offset, int value);
static int tpic2810_get_direction(struct gpio_chip *chip,
unsigned offset)
{
/* This device always output */
return 0;
}
static int tpic2810_direction_input(struct gpio_chip *chip,
unsigned offset)
{
/* This device is output only */
return -EINVAL;
}
static int tpic2810_direction_output(struct gpio_chip *chip,
unsigned offset, int value)
{
/* This device always output */
tpic2810_set(chip, offset, value);
return 0;
}
static void tpic2810_set(struct gpio_chip *chip, unsigned offset, int value)
{
struct tpic2810 *gpio = gpiochip_get_data(chip);
mutex_lock(&gpio->lock);
if (value)
gpio->buffer |= BIT(offset);
else
gpio->buffer &= ~BIT(offset);
i2c_smbus_write_byte_data(gpio->client, TPIC2810_WS_COMMAND,
gpio->buffer);
mutex_unlock(&gpio->lock);
}
static void tpic2810_set_multiple(struct gpio_chip *chip, unsigned long *mask,
unsigned long *bits)
{
struct tpic2810 *gpio = gpiochip_get_data(chip);
mutex_lock(&gpio->lock);
/* clear bits under mask */
gpio->buffer &= ~(*mask);
/* set bits under mask */
gpio->buffer |= ((*mask) & (*bits));
i2c_smbus_write_byte_data(gpio->client, TPIC2810_WS_COMMAND,
gpio->buffer);
mutex_unlock(&gpio->lock);
}
static struct gpio_chip template_chip = {
.label = "tpic2810",
.owner = THIS_MODULE,
.get_direction = tpic2810_get_direction,
.direction_input = tpic2810_direction_input,
.direction_output = tpic2810_direction_output,
.set = tpic2810_set,
.set_multiple = tpic2810_set_multiple,
.base = -1,
.ngpio = 8,
.can_sleep = true,
};
static const struct of_device_id tpic2810_of_match_table[] = {
{ .compatible = "ti,tpic2810" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, tpic2810_of_match_table);
static int tpic2810_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct tpic2810 *gpio;
int ret;
gpio = devm_kzalloc(&client->dev, sizeof(*gpio), GFP_KERNEL);
if (!gpio)
return -ENOMEM;
i2c_set_clientdata(client, gpio);
gpio->chip = template_chip;
gpio->chip.parent = &client->dev;
gpio->client = client;
mutex_init(&gpio->lock);
ret = gpiochip_add_data(&gpio->chip, gpio);
if (ret < 0) {
dev_err(&client->dev, "Unable to register gpiochip\n");
return ret;
}
return 0;
}
static int tpic2810_remove(struct i2c_client *client)
{
struct tpic2810 *gpio = i2c_get_clientdata(client);
gpiochip_remove(&gpio->chip);
return 0;
}
static const struct i2c_device_id tpic2810_id_table[] = {
{ "tpic2810", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, tpic2810_id_table);
static struct i2c_driver tpic2810_driver = {
.driver = {
.name = "tpic2810",
.of_match_table = tpic2810_of_match_table,
},
.probe = tpic2810_probe,
.remove = tpic2810_remove,
.id_table = tpic2810_id_table,
};
module_i2c_driver(tpic2810_driver);
MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
MODULE_DESCRIPTION("TPIC2810 8-Bit LED Driver GPIO Driver");
MODULE_LICENSE("GPL v2");
/*
* Copyright 2015 Verifone Int.
*
* Author: Nicolas Saenz Julienne <nicolassaenzj@gmail.com>
*
* This program is free software; you can redistribute it and/or modify i t
* under the terms of the GNU General Public License as published by th e
* Free Software Foundation; either version 2 of the License, or (at you r
* option) any later version.
*
* This driver is based on the gpio-tps65912 implementation.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio/driver.h>
#include <linux/platform_device.h>
#include <linux/mfd/tps65218.h>
struct tps65218_gpio {
struct tps65218 *tps65218;
struct gpio_chip gpio_chip;
};
static int tps65218_gpio_get(struct gpio_chip *gc, unsigned offset)
{
struct tps65218_gpio *tps65218_gpio = gpiochip_get_data(gc);
struct tps65218 *tps65218 = tps65218_gpio->tps65218;
unsigned int val;
int ret;
ret = tps65218_reg_read(tps65218, TPS65218_REG_ENABLE2, &val);
if (ret)
return ret;
return !!(val & (TPS65218_ENABLE2_GPIO1 << offset));
}
static void tps65218_gpio_set(struct gpio_chip *gc, unsigned offset,
int value)
{
struct tps65218_gpio *tps65218_gpio = gpiochip_get_data(gc);
struct tps65218 *tps65218 = tps65218_gpio->tps65218;
if (value)
tps65218_set_bits(tps65218, TPS65218_REG_ENABLE2,
TPS65218_ENABLE2_GPIO1 << offset,
TPS65218_ENABLE2_GPIO1 << offset,
TPS65218_PROTECT_L1);
else
tps65218_clear_bits(tps65218, TPS65218_REG_ENABLE2,
TPS65218_ENABLE2_GPIO1 << offset,
TPS65218_PROTECT_L1);
}
static int tps65218_gpio_output(struct gpio_chip *gc, unsigned offset,
int value)
{
/* Only drives GPOs */
tps65218_gpio_set(gc, offset, value);
return 0;
}
static int tps65218_gpio_input(struct gpio_chip *gc, unsigned offset)
{
return -EPERM;
}
static int tps65218_gpio_request(struct gpio_chip *gc, unsigned offset)
{
struct tps65218_gpio *tps65218_gpio = gpiochip_get_data(gc);
struct tps65218 *tps65218 = tps65218_gpio->tps65218;
int ret;
if (gpiochip_line_is_open_source(gc, offset)) {
dev_err(gc->parent, "can't work as open source\n");
return -EINVAL;
}
switch (offset) {
case 0:
if (!gpiochip_line_is_open_drain(gc, offset)) {
dev_err(gc->parent, "GPO1 works only as open drain\n");
return -EINVAL;
}
/* Disable sequencer for GPO1 */
ret = tps65218_clear_bits(tps65218, TPS65218_REG_SEQ7,
TPS65218_SEQ7_GPO1_SEQ_MASK,
TPS65218_PROTECT_L1);
if (ret)
return ret;
/* Setup GPO1 */
ret = tps65218_clear_bits(tps65218, TPS65218_REG_CONFIG1,
TPS65218_CONFIG1_IO1_SEL,
TPS65218_PROTECT_L1);
if (ret)
return ret;
break;
case 1:
/* GP02 is push-pull by default, can be set as open drain. */
if (gpiochip_line_is_open_drain(gc, offset)) {
ret = tps65218_clear_bits(tps65218,
TPS65218_REG_CONFIG1,
TPS65218_CONFIG1_GPO2_BUF,
TPS65218_PROTECT_L1);
if (ret)
return ret;
}
/* Setup GPO2 */
ret = tps65218_clear_bits(tps65218, TPS65218_REG_CONFIG1,
TPS65218_CONFIG1_IO1_SEL,
TPS65218_PROTECT_L1);
if (ret)
return ret;
break;
case 2:
if (!gpiochip_line_is_open_drain(gc, offset)) {
dev_err(gc->parent, "GPO3 works only as open drain\n");
return -EINVAL;
}
/* Disable sequencer for GPO3 */
ret = tps65218_clear_bits(tps65218, TPS65218_REG_SEQ7,
TPS65218_SEQ7_GPO3_SEQ_MASK,
TPS65218_PROTECT_L1);
if (ret)
return ret;
/* Setup GPO3 */
ret = tps65218_clear_bits(tps65218, TPS65218_REG_CONFIG2,
TPS65218_CONFIG2_DC12_RST,
TPS65218_PROTECT_L1);
if (ret)
return ret;
break;
default:
return -EINVAL;
}
return 0;
}
static struct gpio_chip template_chip = {
.label = "gpio-tps65218",
.owner = THIS_MODULE,
.request = tps65218_gpio_request,
.direction_output = tps65218_gpio_output,
.direction_input = tps65218_gpio_input,
.get = tps65218_gpio_get,
.set = tps65218_gpio_set,
.can_sleep = true,
.ngpio = 3,
.base = -1,
};
static int tps65218_gpio_probe(struct platform_device *pdev)
{
struct tps65218 *tps65218 = dev_get_drvdata(pdev->dev.parent);
struct tps65218_gpio *tps65218_gpio;
int ret;
tps65218_gpio = devm_kzalloc(&pdev->dev, sizeof(*tps65218_gpio),
GFP_KERNEL);
if (!tps65218_gpio)
return -ENOMEM;
tps65218_gpio->tps65218 = tps65218;
tps65218_gpio->gpio_chip = template_chip;
tps65218_gpio->gpio_chip.parent = &pdev->dev;
#ifdef CONFIG_OF_GPIO
tps65218_gpio->gpio_chip.of_node = pdev->dev.of_node;
#endif
ret = gpiochip_add_data(&tps65218_gpio->gpio_chip, tps65218_gpio);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to register gpiochip, %d\n", ret);
return ret;
}
platform_set_drvdata(pdev, tps65218_gpio);
return ret;
}
static int tps65218_gpio_remove(struct platform_device *pdev)
{
struct tps65218_gpio *tps65218_gpio = platform_get_drvdata(pdev);
gpiochip_remove(&tps65218_gpio->gpio_chip);
return 0;
}
static const struct of_device_id tps65218_dt_match[] = {
{ .compatible = "ti,tps65218-gpio" },
{ }
};
MODULE_DEVICE_TABLE(of, tps65218_dt_match);
static struct platform_driver tps65218_gpio_driver = {
.driver = {
.name = "tps65218-gpio",
.of_match_table = of_match_ptr(tps65218_dt_match)
},
.probe = tps65218_gpio_probe,
.remove = tps65218_gpio_remove,
};
module_platform_driver(tps65218_gpio_driver);
MODULE_AUTHOR("Nicolas Saenz Julienne <nicolassaenzj@gmail.com>");
MODULE_DESCRIPTION("GPO interface for TPS65218 PMICs");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:tps65218-gpio");
/*
* GPIO driver for the TS-4800 board
*
* Copyright (c) 2016 - Savoir-faire Linux
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/gpio/driver.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#define DEFAULT_PIN_NUMBER 16
#define INPUT_REG_OFFSET 0x00
#define OUTPUT_REG_OFFSET 0x02
#define DIRECTION_REG_OFFSET 0x04
static int ts4800_gpio_probe(struct platform_device *pdev)
{
struct device_node *node;
struct gpio_chip *chip;
struct resource *res;
void __iomem *base_addr;
int retval;
u32 ngpios;
chip = devm_kzalloc(&pdev->dev, sizeof(struct gpio_chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base_addr = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(base_addr))
return PTR_ERR(base_addr);
node = pdev->dev.of_node;
if (!node)
return -EINVAL;
retval = of_property_read_u32(node, "ngpios", &ngpios);
if (retval == -EINVAL)
ngpios = DEFAULT_PIN_NUMBER;
else if (retval)
return retval;
retval = bgpio_init(chip, &pdev->dev, 2, base_addr + INPUT_REG_OFFSET,
base_addr + OUTPUT_REG_OFFSET, NULL,
base_addr + DIRECTION_REG_OFFSET, NULL, 0);
if (retval) {
dev_err(&pdev->dev, "bgpio_init failed\n");
return retval;
}
chip->base = -1;
chip->label = dev_name(&pdev->dev);
chip->ngpio = ngpios;
platform_set_drvdata(pdev, chip);
return gpiochip_add_data(chip, NULL);
}
static int ts4800_gpio_remove(struct platform_device *pdev)
{
struct gpio_chip *chip = platform_get_drvdata(pdev);
gpiochip_remove(chip);
return 0;
}
static const struct of_device_id ts4800_gpio_of_match[] = {
{ .compatible = "technologic,ts4800-gpio", },
{},
};
static struct platform_driver ts4800_gpio_driver = {
.driver = {
.name = "ts4800-gpio",
.of_match_table = ts4800_gpio_of_match,
},
.probe = ts4800_gpio_probe,
.remove = ts4800_gpio_remove,
};
module_platform_driver_probe(ts4800_gpio_driver, ts4800_gpio_probe);
MODULE_AUTHOR("Julien Grossholtz <julien.grossholtz@savoirfairelinux.com>");
MODULE_DESCRIPTION("TS4800 FPGA GPIO driver");
MODULE_LICENSE("GPL v2");
/*
* GPIO driver for the WinSystems WS16C48
* Copyright (C) 2016 William Breathitt Gray
*
* 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.
*/
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/gpio/driver.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/irqdesc.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
static unsigned ws16c48_base;
module_param(ws16c48_base, uint, 0);
MODULE_PARM_DESC(ws16c48_base, "WinSystems WS16C48 base address");
static unsigned ws16c48_irq;
module_param(ws16c48_irq, uint, 0);
MODULE_PARM_DESC(ws16c48_irq, "WinSystems WS16C48 interrupt line number");
/**
* struct ws16c48_gpio - GPIO device private data structure
* @chip: instance of the gpio_chip
* @io_state: bit I/O state (whether bit is set to input or output)
* @out_state: output bits state
* @lock: synchronization lock to prevent I/O race conditions
* @irq_mask: I/O bits affected by interrupts
* @flow_mask: IRQ flow type mask for the respective I/O bits
* @base: base port address of the GPIO device
* @irq: Interrupt line number
*/
struct ws16c48_gpio {
struct gpio_chip chip;
unsigned char io_state[6];
unsigned char out_state[6];
spinlock_t lock;
unsigned long irq_mask;
unsigned long flow_mask;
unsigned base;
unsigned irq;
};
static int ws16c48_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
{
struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
const unsigned port = offset / 8;
const unsigned mask = BIT(offset % 8);
return !!(ws16c48gpio->io_state[port] & mask);
}
static int ws16c48_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
const unsigned port = offset / 8;
const unsigned mask = BIT(offset % 8);
unsigned long flags;
spin_lock_irqsave(&ws16c48gpio->lock, flags);
ws16c48gpio->io_state[port] |= mask;
ws16c48gpio->out_state[port] &= ~mask;
outb(ws16c48gpio->out_state[port], ws16c48gpio->base + port);
spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
return 0;
}
static int ws16c48_gpio_direction_output(struct gpio_chip *chip,
unsigned offset, int value)
{
struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
const unsigned port = offset / 8;
const unsigned mask = BIT(offset % 8);
unsigned long flags;
spin_lock_irqsave(&ws16c48gpio->lock, flags);
ws16c48gpio->io_state[port] &= ~mask;
if (value)
ws16c48gpio->out_state[port] |= mask;
else
ws16c48gpio->out_state[port] &= ~mask;
outb(ws16c48gpio->out_state[port], ws16c48gpio->base + port);
spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
return 0;
}
static int ws16c48_gpio_get(struct gpio_chip *chip, unsigned offset)
{
struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
const unsigned port = offset / 8;
const unsigned mask = BIT(offset % 8);
unsigned long flags;
unsigned port_state;
spin_lock_irqsave(&ws16c48gpio->lock, flags);
/* ensure that GPIO is set for input */
if (!(ws16c48gpio->io_state[port] & mask)) {
spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
return -EINVAL;
}
port_state = inb(ws16c48gpio->base + port);
spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
return !!(port_state & mask);
}
static void ws16c48_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
const unsigned port = offset / 8;
const unsigned mask = BIT(offset % 8);
unsigned long flags;
spin_lock_irqsave(&ws16c48gpio->lock, flags);
/* ensure that GPIO is set for output */
if (ws16c48gpio->io_state[port] & mask) {
spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
return;
}
if (value)
ws16c48gpio->out_state[port] |= mask;
else
ws16c48gpio->out_state[port] &= ~mask;
outb(ws16c48gpio->out_state[port], ws16c48gpio->base + port);
spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
}
static void ws16c48_irq_ack(struct irq_data *data)
{
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
const unsigned long offset = irqd_to_hwirq(data);
const unsigned port = offset / 8;
const unsigned mask = BIT(offset % 8);
unsigned long flags;
unsigned port_state;
/* only the first 3 ports support interrupts */
if (port > 2)
return;
spin_lock_irqsave(&ws16c48gpio->lock, flags);
port_state = ws16c48gpio->irq_mask >> (8*port);
outb(0x80, ws16c48gpio->base + 7);
outb(port_state & ~mask, ws16c48gpio->base + 8 + port);
outb(port_state | mask, ws16c48gpio->base + 8 + port);
outb(0xC0, ws16c48gpio->base + 7);
spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
}
static void ws16c48_irq_mask(struct irq_data *data)
{
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
const unsigned long offset = irqd_to_hwirq(data);
const unsigned long mask = BIT(offset);
const unsigned port = offset / 8;
unsigned long flags;
/* only the first 3 ports support interrupts */
if (port > 2)
return;
spin_lock_irqsave(&ws16c48gpio->lock, flags);
ws16c48gpio->irq_mask &= ~mask;
outb(0x80, ws16c48gpio->base + 7);
outb(ws16c48gpio->irq_mask >> (8*port), ws16c48gpio->base + 8 + port);
outb(0xC0, ws16c48gpio->base + 7);
spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
}
static void ws16c48_irq_unmask(struct irq_data *data)
{
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
const unsigned long offset = irqd_to_hwirq(data);
const unsigned long mask = BIT(offset);
const unsigned port = offset / 8;
unsigned long flags;
/* only the first 3 ports support interrupts */
if (port > 2)
return;
spin_lock_irqsave(&ws16c48gpio->lock, flags);
ws16c48gpio->irq_mask |= mask;
outb(0x80, ws16c48gpio->base + 7);
outb(ws16c48gpio->irq_mask >> (8*port), ws16c48gpio->base + 8 + port);
outb(0xC0, ws16c48gpio->base + 7);
spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
}
static int ws16c48_irq_set_type(struct irq_data *data, unsigned flow_type)
{
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
const unsigned long offset = irqd_to_hwirq(data);
const unsigned long mask = BIT(offset);
const unsigned port = offset / 8;
unsigned long flags;
/* only the first 3 ports support interrupts */
if (port > 2)
return -EINVAL;
spin_lock_irqsave(&ws16c48gpio->lock, flags);
switch (flow_type) {
case IRQ_TYPE_NONE:
break;
case IRQ_TYPE_EDGE_RISING:
ws16c48gpio->flow_mask |= mask;
break;
case IRQ_TYPE_EDGE_FALLING:
ws16c48gpio->flow_mask &= ~mask;
break;
default:
spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
return -EINVAL;
}
outb(0x40, ws16c48gpio->base + 7);
outb(ws16c48gpio->flow_mask >> (8*port), ws16c48gpio->base + 8 + port);
outb(0xC0, ws16c48gpio->base + 7);
spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
return 0;
}
static struct irq_chip ws16c48_irqchip = {
.name = "ws16c48",
.irq_ack = ws16c48_irq_ack,
.irq_mask = ws16c48_irq_mask,
.irq_unmask = ws16c48_irq_unmask,
.irq_set_type = ws16c48_irq_set_type
};
static irqreturn_t ws16c48_irq_handler(int irq, void *dev_id)
{
struct ws16c48_gpio *const ws16c48gpio = dev_id;
struct gpio_chip *const chip = &ws16c48gpio->chip;
unsigned long int_pending;
unsigned long port;
unsigned long int_id;
unsigned long gpio;
int_pending = inb(ws16c48gpio->base + 6) & 0x7;
if (!int_pending)
return IRQ_NONE;
/* loop until all pending interrupts are handled */
do {
for_each_set_bit(port, &int_pending, 3) {
int_id = inb(ws16c48gpio->base + 8 + port);
for_each_set_bit(gpio, &int_id, 8)
generic_handle_irq(irq_find_mapping(
chip->irqdomain, gpio + 8*port));
}
int_pending = inb(ws16c48gpio->base + 6) & 0x7;
} while (int_pending);
return IRQ_HANDLED;
}
static int __init ws16c48_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct ws16c48_gpio *ws16c48gpio;
const unsigned base = ws16c48_base;
const unsigned extent = 16;
const char *const name = dev_name(dev);
int err;
const unsigned irq = ws16c48_irq;
ws16c48gpio = devm_kzalloc(dev, sizeof(*ws16c48gpio), GFP_KERNEL);
if (!ws16c48gpio)
return -ENOMEM;
if (!devm_request_region(dev, base, extent, name)) {
dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
base, base + extent);
return -EBUSY;
}
ws16c48gpio->chip.label = name;
ws16c48gpio->chip.parent = dev;
ws16c48gpio->chip.owner = THIS_MODULE;
ws16c48gpio->chip.base = -1;
ws16c48gpio->chip.ngpio = 48;
ws16c48gpio->chip.get_direction = ws16c48_gpio_get_direction;
ws16c48gpio->chip.direction_input = ws16c48_gpio_direction_input;
ws16c48gpio->chip.direction_output = ws16c48_gpio_direction_output;
ws16c48gpio->chip.get = ws16c48_gpio_get;
ws16c48gpio->chip.set = ws16c48_gpio_set;
ws16c48gpio->base = base;
ws16c48gpio->irq = irq;
spin_lock_init(&ws16c48gpio->lock);
dev_set_drvdata(dev, ws16c48gpio);
err = gpiochip_add_data(&ws16c48gpio->chip, ws16c48gpio);
if (err) {
dev_err(dev, "GPIO registering failed (%d)\n", err);
return err;
}
/* Disable IRQ by default */
outb(0x80, base + 7);
outb(0, base + 8);
outb(0, base + 9);
outb(0, base + 10);
outb(0xC0, base + 7);
err = gpiochip_irqchip_add(&ws16c48gpio->chip, &ws16c48_irqchip, 0,
handle_edge_irq, IRQ_TYPE_NONE);
if (err) {
dev_err(dev, "Could not add irqchip (%d)\n", err);
goto err_gpiochip_remove;
}
err = request_irq(irq, ws16c48_irq_handler, IRQF_SHARED, name,
ws16c48gpio);
if (err) {
dev_err(dev, "IRQ handler registering failed (%d)\n", err);
goto err_gpiochip_remove;
}
return 0;
err_gpiochip_remove:
gpiochip_remove(&ws16c48gpio->chip);
return err;
}
static int ws16c48_remove(struct platform_device *pdev)
{
struct ws16c48_gpio *const ws16c48gpio = platform_get_drvdata(pdev);
free_irq(ws16c48gpio->irq, ws16c48gpio);
gpiochip_remove(&ws16c48gpio->chip);
return 0;
}
static struct platform_device *ws16c48_device;
static struct platform_driver ws16c48_driver = {
.driver = {
.name = "ws16c48"
},
.remove = ws16c48_remove
};
static void __exit ws16c48_exit(void)
{
platform_device_unregister(ws16c48_device);
platform_driver_unregister(&ws16c48_driver);
}
static int __init ws16c48_init(void)
{
int err;
ws16c48_device = platform_device_alloc(ws16c48_driver.driver.name, -1);
if (!ws16c48_device)
return -ENOMEM;
err = platform_device_add(ws16c48_device);
if (err)
goto err_platform_device;
err = platform_driver_probe(&ws16c48_driver, ws16c48_probe);
if (err)
goto err_platform_driver;
return 0;
err_platform_driver:
platform_device_del(ws16c48_device);
err_platform_device:
platform_device_put(ws16c48_device);
return err;
}
module_init(ws16c48_init);
module_exit(ws16c48_exit);
MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
MODULE_DESCRIPTION("WinSystems WS16C48 GPIO driver");
MODULE_LICENSE("GPL v2");
...@@ -2,8 +2,9 @@ ...@@ -2,8 +2,9 @@
* AppliedMicro X-Gene SoC GPIO-Standby Driver * AppliedMicro X-Gene SoC GPIO-Standby Driver
* *
* Copyright (c) 2014, Applied Micro Circuits Corporation * Copyright (c) 2014, Applied Micro Circuits Corporation
* Author: Tin Huynh <tnhuynh@apm.com>. * Author: Tin Huynh <tnhuynh@apm.com>.
* Y Vo <yvo@apm.com>. * Y Vo <yvo@apm.com>.
* Quan Nguyen <qnguyen@apm.com>.
* *
* This program is free software; you can redistribute it and/or modify it * 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 * under the terms of the GNU General Public License as published by the
...@@ -28,9 +29,14 @@ ...@@ -28,9 +29,14 @@
#include "gpiolib.h" #include "gpiolib.h"
#define XGENE_MAX_GPIO_DS 22 /* Common property names */
#define XGENE_MAX_GPIO_DS_IRQ 6 #define XGENE_NIRQ_PROPERTY "apm,nr-irqs"
#define XGENE_NGPIO_PROPERTY "apm,nr-gpios"
#define XGENE_IRQ_START_PROPERTY "apm,irq-start"
#define XGENE_DFLT_MAX_NGPIO 22
#define XGENE_DFLT_MAX_NIRQ 6
#define XGENE_DFLT_IRQ_START_PIN 8
#define GPIO_MASK(x) (1U << ((x) % 32)) #define GPIO_MASK(x) (1U << ((x) % 32))
#define MPA_GPIO_INT_LVL 0x0290 #define MPA_GPIO_INT_LVL 0x0290
...@@ -39,19 +45,32 @@ ...@@ -39,19 +45,32 @@
#define MPA_GPIO_IN_ADDR 0x02a4 #define MPA_GPIO_IN_ADDR 0x02a4
#define MPA_GPIO_SEL_LO 0x0294 #define MPA_GPIO_SEL_LO 0x0294
#define GPIO_INT_LEVEL_H 0x000001
#define GPIO_INT_LEVEL_L 0x000000
/** /**
* struct xgene_gpio_sb - GPIO-Standby private data structure. * struct xgene_gpio_sb - GPIO-Standby private data structure.
* @gc: memory-mapped GPIO controllers. * @gc: memory-mapped GPIO controllers.
* @irq: Mapping GPIO pins and interrupt number * @regs: GPIO register base offset
* nirq: Number of GPIO pins that supports interrupt * @irq_domain: GPIO interrupt domain
* @irq_start: GPIO pin that start support interrupt
* @nirq: Number of GPIO pins that supports interrupt
* @parent_irq_base: Start parent HWIRQ
*/ */
struct xgene_gpio_sb { struct xgene_gpio_sb {
struct gpio_chip gc; struct gpio_chip gc;
u32 *irq; void __iomem *regs;
u32 nirq; struct irq_domain *irq_domain;
u16 irq_start;
u16 nirq;
u16 parent_irq_base;
}; };
static void xgene_gpio_set_bit(struct gpio_chip *gc, void __iomem *reg, u32 gpio, int val) #define HWIRQ_TO_GPIO(priv, hwirq) ((hwirq) + (priv)->irq_start)
#define GPIO_TO_HWIRQ(priv, gpio) ((gpio) - (priv)->irq_start)
static void xgene_gpio_set_bit(struct gpio_chip *gc,
void __iomem *reg, u32 gpio, int val)
{ {
u32 data; u32 data;
...@@ -63,23 +82,170 @@ static void xgene_gpio_set_bit(struct gpio_chip *gc, void __iomem *reg, u32 gpio ...@@ -63,23 +82,170 @@ static void xgene_gpio_set_bit(struct gpio_chip *gc, void __iomem *reg, u32 gpio
gc->write_reg(reg, data); gc->write_reg(reg, data);
} }
static int apm_gpio_sb_to_irq(struct gpio_chip *gc, u32 gpio) static int xgene_gpio_sb_irq_set_type(struct irq_data *d, unsigned int type)
{
struct xgene_gpio_sb *priv = irq_data_get_irq_chip_data(d);
int gpio = HWIRQ_TO_GPIO(priv, d->hwirq);
int lvl_type = GPIO_INT_LEVEL_H;
switch (type & IRQ_TYPE_SENSE_MASK) {
case IRQ_TYPE_EDGE_RISING:
case IRQ_TYPE_LEVEL_HIGH:
lvl_type = GPIO_INT_LEVEL_H;
break;
case IRQ_TYPE_EDGE_FALLING:
case IRQ_TYPE_LEVEL_LOW:
lvl_type = GPIO_INT_LEVEL_L;
break;
default:
break;
}
xgene_gpio_set_bit(&priv->gc, priv->regs + MPA_GPIO_SEL_LO,
gpio * 2, 1);
xgene_gpio_set_bit(&priv->gc, priv->regs + MPA_GPIO_INT_LVL,
d->hwirq, lvl_type);
/* Propagate IRQ type setting to parent */
if (type & IRQ_TYPE_EDGE_BOTH)
return irq_chip_set_type_parent(d, IRQ_TYPE_EDGE_RISING);
else
return irq_chip_set_type_parent(d, IRQ_TYPE_LEVEL_HIGH);
}
static struct irq_chip xgene_gpio_sb_irq_chip = {
.name = "sbgpio",
.irq_eoi = irq_chip_eoi_parent,
.irq_mask = irq_chip_mask_parent,
.irq_unmask = irq_chip_unmask_parent,
.irq_set_type = xgene_gpio_sb_irq_set_type,
};
static int xgene_gpio_sb_to_irq(struct gpio_chip *gc, u32 gpio)
{ {
struct xgene_gpio_sb *priv = gpiochip_get_data(gc); struct xgene_gpio_sb *priv = gpiochip_get_data(gc);
struct irq_fwspec fwspec;
if ((gpio < priv->irq_start) ||
(gpio > HWIRQ_TO_GPIO(priv, priv->nirq)))
return -ENXIO;
if (gc->parent->of_node)
fwspec.fwnode = of_node_to_fwnode(gc->parent->of_node);
else
fwspec.fwnode = gc->parent->fwnode;
fwspec.param_count = 2;
fwspec.param[0] = GPIO_TO_HWIRQ(priv, gpio);
fwspec.param[1] = IRQ_TYPE_NONE;
return irq_create_fwspec_mapping(&fwspec);
}
static void xgene_gpio_sb_domain_activate(struct irq_domain *d,
struct irq_data *irq_data)
{
struct xgene_gpio_sb *priv = d->host_data;
u32 gpio = HWIRQ_TO_GPIO(priv, irq_data->hwirq);
if (gpiochip_lock_as_irq(&priv->gc, gpio)) {
dev_err(priv->gc.parent,
"Unable to configure XGene GPIO standby pin %d as IRQ\n",
gpio);
return;
}
xgene_gpio_set_bit(&priv->gc, priv->regs + MPA_GPIO_SEL_LO,
gpio * 2, 1);
}
static void xgene_gpio_sb_domain_deactivate(struct irq_domain *d,
struct irq_data *irq_data)
{
struct xgene_gpio_sb *priv = d->host_data;
u32 gpio = HWIRQ_TO_GPIO(priv, irq_data->hwirq);
gpiochip_unlock_as_irq(&priv->gc, gpio);
xgene_gpio_set_bit(&priv->gc, priv->regs + MPA_GPIO_SEL_LO,
gpio * 2, 0);
}
static int xgene_gpio_sb_domain_translate(struct irq_domain *d,
struct irq_fwspec *fwspec,
unsigned long *hwirq,
unsigned int *type)
{
struct xgene_gpio_sb *priv = d->host_data;
if (priv->irq[gpio]) if ((fwspec->param_count != 2) ||
return priv->irq[gpio]; (fwspec->param[0] >= priv->nirq))
return -EINVAL;
*hwirq = fwspec->param[0];
*type = fwspec->param[1];
return 0;
}
static int xgene_gpio_sb_domain_alloc(struct irq_domain *domain,
unsigned int virq,
unsigned int nr_irqs, void *data)
{
struct irq_fwspec *fwspec = data;
struct irq_fwspec parent_fwspec;
struct xgene_gpio_sb *priv = domain->host_data;
irq_hw_number_t hwirq;
unsigned int i;
hwirq = fwspec->param[0];
for (i = 0; i < nr_irqs; i++)
irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
&xgene_gpio_sb_irq_chip, priv);
parent_fwspec.fwnode = domain->parent->fwnode;
if (is_of_node(parent_fwspec.fwnode)) {
parent_fwspec.param_count = 3;
parent_fwspec.param[0] = 0;/* SPI */
/* Skip SGIs and PPIs*/
parent_fwspec.param[1] = hwirq + priv->parent_irq_base - 32;
parent_fwspec.param[2] = fwspec->param[1];
} else if (is_fwnode_irqchip(parent_fwspec.fwnode)) {
parent_fwspec.param_count = 2;
parent_fwspec.param[0] = hwirq + priv->parent_irq_base;
parent_fwspec.param[1] = fwspec->param[1];
} else
return -EINVAL;
return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs,
&parent_fwspec);
}
static void xgene_gpio_sb_domain_free(struct irq_domain *domain,
unsigned int virq,
unsigned int nr_irqs)
{
struct irq_data *d;
unsigned int i;
return -ENXIO; for (i = 0; i < nr_irqs; i++) {
d = irq_domain_get_irq_data(domain, virq + i);
irq_domain_reset_irq_data(d);
}
} }
static const struct irq_domain_ops xgene_gpio_sb_domain_ops = {
.translate = xgene_gpio_sb_domain_translate,
.alloc = xgene_gpio_sb_domain_alloc,
.free = xgene_gpio_sb_domain_free,
.activate = xgene_gpio_sb_domain_activate,
.deactivate = xgene_gpio_sb_domain_deactivate,
};
static int xgene_gpio_sb_probe(struct platform_device *pdev) static int xgene_gpio_sb_probe(struct platform_device *pdev)
{ {
struct xgene_gpio_sb *priv; struct xgene_gpio_sb *priv;
u32 ret, i; u32 ret;
u32 default_lines[] = {0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D};
struct resource *res; struct resource *res;
void __iomem *regs; void __iomem *regs;
struct irq_domain *parent_domain = NULL;
struct fwnode_handle *fwnode;
u32 val32;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv) if (!priv)
...@@ -90,6 +256,18 @@ static int xgene_gpio_sb_probe(struct platform_device *pdev) ...@@ -90,6 +256,18 @@ static int xgene_gpio_sb_probe(struct platform_device *pdev)
if (IS_ERR(regs)) if (IS_ERR(regs))
return PTR_ERR(regs); return PTR_ERR(regs);
priv->regs = regs;
ret = platform_get_irq(pdev, 0);
if (ret > 0) {
priv->parent_irq_base = irq_get_irq_data(ret)->hwirq;
parent_domain = irq_get_irq_data(ret)->domain;
}
if (!parent_domain) {
dev_err(&pdev->dev, "unable to obtain parent domain\n");
return -ENODEV;
}
ret = bgpio_init(&priv->gc, &pdev->dev, 4, ret = bgpio_init(&priv->gc, &pdev->dev, 4,
regs + MPA_GPIO_IN_ADDR, regs + MPA_GPIO_IN_ADDR,
regs + MPA_GPIO_OUT_ADDR, NULL, regs + MPA_GPIO_OUT_ADDR, NULL,
...@@ -97,30 +275,51 @@ static int xgene_gpio_sb_probe(struct platform_device *pdev) ...@@ -97,30 +275,51 @@ static int xgene_gpio_sb_probe(struct platform_device *pdev)
if (ret) if (ret)
return ret; return ret;
priv->gc.to_irq = apm_gpio_sb_to_irq; priv->gc.to_irq = xgene_gpio_sb_to_irq;
priv->gc.ngpio = XGENE_MAX_GPIO_DS;
priv->nirq = XGENE_MAX_GPIO_DS_IRQ; /* Retrieve start irq pin, use default if property not found */
priv->irq_start = XGENE_DFLT_IRQ_START_PIN;
if (!device_property_read_u32(&pdev->dev,
XGENE_IRQ_START_PROPERTY, &val32))
priv->irq_start = val32;
priv->irq = devm_kzalloc(&pdev->dev, sizeof(u32) * XGENE_MAX_GPIO_DS, /* Retrieve number irqs, use default if property not found */
GFP_KERNEL); priv->nirq = XGENE_DFLT_MAX_NIRQ;
if (!priv->irq) if (!device_property_read_u32(&pdev->dev, XGENE_NIRQ_PROPERTY, &val32))
return -ENOMEM; priv->nirq = val32;
for (i = 0; i < priv->nirq; i++) { /* Retrieve number gpio, use default if property not found */
priv->irq[default_lines[i]] = platform_get_irq(pdev, i); priv->gc.ngpio = XGENE_DFLT_MAX_NGPIO;
xgene_gpio_set_bit(&priv->gc, regs + MPA_GPIO_SEL_LO, if (!device_property_read_u32(&pdev->dev, XGENE_NGPIO_PROPERTY, &val32))
default_lines[i] * 2, 1); priv->gc.ngpio = val32;
xgene_gpio_set_bit(&priv->gc, regs + MPA_GPIO_INT_LVL, i, 1);
} dev_info(&pdev->dev, "Support %d gpios, %d irqs start from pin %d\n",
priv->gc.ngpio, priv->nirq, priv->irq_start);
platform_set_drvdata(pdev, priv); platform_set_drvdata(pdev, priv);
ret = gpiochip_add_data(&priv->gc, priv); if (pdev->dev.of_node)
if (ret) fwnode = of_node_to_fwnode(pdev->dev.of_node);
dev_err(&pdev->dev, "failed to register X-Gene GPIO Standby driver\n");
else else
dev_info(&pdev->dev, "X-Gene GPIO Standby driver registered\n"); fwnode = pdev->dev.fwnode;
priv->irq_domain = irq_domain_create_hierarchy(parent_domain,
0, priv->nirq, fwnode,
&xgene_gpio_sb_domain_ops, priv);
if (!priv->irq_domain)
return -ENODEV;
priv->gc.irqdomain = priv->irq_domain;
ret = gpiochip_add_data(&priv->gc, priv);
if (ret) {
dev_err(&pdev->dev,
"failed to register X-Gene GPIO Standby driver\n");
irq_domain_remove(priv->irq_domain);
return ret;
}
dev_info(&pdev->dev, "X-Gene GPIO Standby driver registered\n");
if (priv->nirq > 0) { if (priv->nirq > 0) {
/* Register interrupt handlers for gpio signaled acpi events */ /* Register interrupt handlers for gpio signaled acpi events */
...@@ -138,6 +337,8 @@ static int xgene_gpio_sb_remove(struct platform_device *pdev) ...@@ -138,6 +337,8 @@ static int xgene_gpio_sb_remove(struct platform_device *pdev)
acpi_gpiochip_free_interrupts(&priv->gc); acpi_gpiochip_free_interrupts(&priv->gc);
} }
irq_domain_remove(priv->irq_domain);
gpiochip_remove(&priv->gc); gpiochip_remove(&priv->gc);
return 0; return 0;
} }
......
...@@ -71,29 +71,29 @@ static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) ...@@ -71,29 +71,29 @@ static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
* controller uses pin controller and the mapping is not contiguous the * controller uses pin controller and the mapping is not contiguous the
* offset might be different. * offset might be different.
*/ */
static int acpi_gpiochip_pin_to_gpio_offset(struct gpio_chip *chip, int pin) static int acpi_gpiochip_pin_to_gpio_offset(struct gpio_device *gdev, int pin)
{ {
struct gpio_pin_range *pin_range; struct gpio_pin_range *pin_range;
/* If there are no ranges in this chip, use 1:1 mapping */ /* If there are no ranges in this chip, use 1:1 mapping */
if (list_empty(&chip->pin_ranges)) if (list_empty(&gdev->pin_ranges))
return pin; return pin;
list_for_each_entry(pin_range, &chip->pin_ranges, node) { list_for_each_entry(pin_range, &gdev->pin_ranges, node) {
const struct pinctrl_gpio_range *range = &pin_range->range; const struct pinctrl_gpio_range *range = &pin_range->range;
int i; int i;
if (range->pins) { if (range->pins) {
for (i = 0; i < range->npins; i++) { for (i = 0; i < range->npins; i++) {
if (range->pins[i] == pin) if (range->pins[i] == pin)
return range->base + i - chip->base; return range->base + i - gdev->base;
} }
} else { } else {
if (pin >= range->pin_base && if (pin >= range->pin_base &&
pin < range->pin_base + range->npins) { pin < range->pin_base + range->npins) {
unsigned gpio_base; unsigned gpio_base;
gpio_base = range->base - chip->base; gpio_base = range->base - gdev->base;
return gpio_base + pin - range->pin_base; return gpio_base + pin - range->pin_base;
} }
} }
...@@ -102,7 +102,7 @@ static int acpi_gpiochip_pin_to_gpio_offset(struct gpio_chip *chip, int pin) ...@@ -102,7 +102,7 @@ static int acpi_gpiochip_pin_to_gpio_offset(struct gpio_chip *chip, int pin)
return -EINVAL; return -EINVAL;
} }
#else #else
static inline int acpi_gpiochip_pin_to_gpio_offset(struct gpio_chip *chip, static inline int acpi_gpiochip_pin_to_gpio_offset(struct gpio_device *gdev,
int pin) int pin)
{ {
return pin; return pin;
...@@ -134,7 +134,7 @@ static struct gpio_desc *acpi_get_gpiod(char *path, int pin) ...@@ -134,7 +134,7 @@ static struct gpio_desc *acpi_get_gpiod(char *path, int pin)
if (!chip) if (!chip)
return ERR_PTR(-EPROBE_DEFER); return ERR_PTR(-EPROBE_DEFER);
offset = acpi_gpiochip_pin_to_gpio_offset(chip, pin); offset = acpi_gpiochip_pin_to_gpio_offset(chip->gpiodev, pin);
if (offset < 0) if (offset < 0)
return ERR_PTR(offset); return ERR_PTR(offset);
...@@ -202,7 +202,7 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares, ...@@ -202,7 +202,7 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
if (!handler) if (!handler)
return AE_BAD_PARAMETER; return AE_BAD_PARAMETER;
pin = acpi_gpiochip_pin_to_gpio_offset(chip, pin); pin = acpi_gpiochip_pin_to_gpio_offset(chip->gpiodev, pin);
if (pin < 0) if (pin < 0)
return AE_BAD_PARAMETER; return AE_BAD_PARAMETER;
...@@ -673,7 +673,7 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address, ...@@ -673,7 +673,7 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
struct gpio_desc *desc; struct gpio_desc *desc;
bool found; bool found;
pin = acpi_gpiochip_pin_to_gpio_offset(chip, pin); pin = acpi_gpiochip_pin_to_gpio_offset(chip->gpiodev, pin);
if (pin < 0) { if (pin < 0) {
status = AE_BAD_PARAMETER; status = AE_BAD_PARAMETER;
goto out; goto out;
......
...@@ -180,7 +180,7 @@ static int gpio_sysfs_request_irq(struct device *dev, unsigned char flags) ...@@ -180,7 +180,7 @@ static int gpio_sysfs_request_irq(struct device *dev, unsigned char flags)
* Remove this redundant call (along with the corresponding * Remove this redundant call (along with the corresponding
* unlock) when those drivers have been fixed. * unlock) when those drivers have been fixed.
*/ */
ret = gpiochip_lock_as_irq(desc->chip, gpio_chip_hwgpio(desc)); ret = gpiochip_lock_as_irq(desc->gdev->chip, gpio_chip_hwgpio(desc));
if (ret < 0) if (ret < 0)
goto err_put_kn; goto err_put_kn;
...@@ -194,7 +194,7 @@ static int gpio_sysfs_request_irq(struct device *dev, unsigned char flags) ...@@ -194,7 +194,7 @@ static int gpio_sysfs_request_irq(struct device *dev, unsigned char flags)
return 0; return 0;
err_unlock: err_unlock:
gpiochip_unlock_as_irq(desc->chip, gpio_chip_hwgpio(desc)); gpiochip_unlock_as_irq(desc->gdev->chip, gpio_chip_hwgpio(desc));
err_put_kn: err_put_kn:
sysfs_put(data->value_kn); sysfs_put(data->value_kn);
...@@ -212,7 +212,7 @@ static void gpio_sysfs_free_irq(struct device *dev) ...@@ -212,7 +212,7 @@ static void gpio_sysfs_free_irq(struct device *dev)
data->irq_flags = 0; data->irq_flags = 0;
free_irq(data->irq, data); free_irq(data->irq, data);
gpiochip_unlock_as_irq(desc->chip, gpio_chip_hwgpio(desc)); gpiochip_unlock_as_irq(desc->gdev->chip, gpio_chip_hwgpio(desc));
sysfs_put(data->value_kn); sysfs_put(data->value_kn);
} }
...@@ -547,6 +547,7 @@ static struct class gpio_class = { ...@@ -547,6 +547,7 @@ static struct class gpio_class = {
int gpiod_export(struct gpio_desc *desc, bool direction_may_change) int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
{ {
struct gpio_chip *chip; struct gpio_chip *chip;
struct gpio_device *gdev;
struct gpiod_data *data; struct gpiod_data *data;
unsigned long flags; unsigned long flags;
int status; int status;
...@@ -565,12 +566,13 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change) ...@@ -565,12 +566,13 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
return -EINVAL; return -EINVAL;
} }
chip = desc->chip; gdev = desc->gdev;
chip = gdev->chip;
mutex_lock(&sysfs_lock); mutex_lock(&sysfs_lock);
/* check if chip is being removed */ /* check if chip is being removed */
if (!chip || !chip->cdev) { if (!chip || !gdev->mockdev) {
status = -ENODEV; status = -ENODEV;
goto err_unlock; goto err_unlock;
} }
...@@ -605,7 +607,7 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change) ...@@ -605,7 +607,7 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
if (chip->names && chip->names[offset]) if (chip->names && chip->names[offset])
ioname = chip->names[offset]; ioname = chip->names[offset];
dev = device_create_with_groups(&gpio_class, chip->parent, dev = device_create_with_groups(&gpio_class, &gdev->dev,
MKDEV(0, 0), data, gpio_groups, MKDEV(0, 0), data, gpio_groups,
ioname ? ioname : "gpio%u", ioname ? ioname : "gpio%u",
desc_to_gpio(desc)); desc_to_gpio(desc));
...@@ -716,9 +718,10 @@ void gpiod_unexport(struct gpio_desc *desc) ...@@ -716,9 +718,10 @@ void gpiod_unexport(struct gpio_desc *desc)
} }
EXPORT_SYMBOL_GPL(gpiod_unexport); EXPORT_SYMBOL_GPL(gpiod_unexport);
int gpiochip_sysfs_register(struct gpio_chip *chip) int gpiochip_sysfs_register(struct gpio_device *gdev)
{ {
struct device *dev; struct device *dev;
struct gpio_chip *chip = gdev->chip;
/* /*
* Many systems add gpio chips for SOC support very early, * Many systems add gpio chips for SOC support very early,
...@@ -730,7 +733,7 @@ int gpiochip_sysfs_register(struct gpio_chip *chip) ...@@ -730,7 +733,7 @@ int gpiochip_sysfs_register(struct gpio_chip *chip)
return 0; return 0;
/* use chip->base for the ID; it's already known to be unique */ /* use chip->base for the ID; it's already known to be unique */
dev = device_create_with_groups(&gpio_class, chip->parent, dev = device_create_with_groups(&gpio_class, &gdev->dev,
MKDEV(0, 0), MKDEV(0, 0),
chip, gpiochip_groups, chip, gpiochip_groups,
"gpiochip%d", chip->base); "gpiochip%d", chip->base);
...@@ -738,30 +741,31 @@ int gpiochip_sysfs_register(struct gpio_chip *chip) ...@@ -738,30 +741,31 @@ int gpiochip_sysfs_register(struct gpio_chip *chip)
return PTR_ERR(dev); return PTR_ERR(dev);
mutex_lock(&sysfs_lock); mutex_lock(&sysfs_lock);
chip->cdev = dev; gdev->mockdev = dev;
mutex_unlock(&sysfs_lock); mutex_unlock(&sysfs_lock);
return 0; return 0;
} }
void gpiochip_sysfs_unregister(struct gpio_chip *chip) void gpiochip_sysfs_unregister(struct gpio_device *gdev)
{ {
struct gpio_desc *desc; struct gpio_desc *desc;
struct gpio_chip *chip = gdev->chip;
unsigned int i; unsigned int i;
if (!chip->cdev) if (!gdev->mockdev)
return; return;
device_unregister(chip->cdev); device_unregister(gdev->mockdev);
/* prevent further gpiod exports */ /* prevent further gpiod exports */
mutex_lock(&sysfs_lock); mutex_lock(&sysfs_lock);
chip->cdev = NULL; gdev->mockdev = NULL;
mutex_unlock(&sysfs_lock); mutex_unlock(&sysfs_lock);
/* unregister gpiod class devices owned by sysfs */ /* unregister gpiod class devices owned by sysfs */
for (i = 0; i < chip->ngpio; i++) { for (i = 0; i < chip->ngpio; i++) {
desc = &chip->desc[i]; desc = &gdev->descs[i];
if (test_and_clear_bit(FLAG_SYSFS, &desc->flags)) if (test_and_clear_bit(FLAG_SYSFS, &desc->flags))
gpiod_free(desc); gpiod_free(desc);
} }
...@@ -771,7 +775,7 @@ static int __init gpiolib_sysfs_init(void) ...@@ -771,7 +775,7 @@ static int __init gpiolib_sysfs_init(void)
{ {
int status; int status;
unsigned long flags; unsigned long flags;
struct gpio_chip *chip; struct gpio_device *gdev;
status = class_register(&gpio_class); status = class_register(&gpio_class);
if (status < 0) if (status < 0)
...@@ -784,8 +788,8 @@ static int __init gpiolib_sysfs_init(void) ...@@ -784,8 +788,8 @@ static int __init gpiolib_sysfs_init(void)
* registered, and so arch_initcall() can always gpio_export(). * registered, and so arch_initcall() can always gpio_export().
*/ */
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
list_for_each_entry(chip, &gpio_chips, list) { list_for_each_entry(gdev, &gpio_devices, list) {
if (chip->cdev) if (gdev->mockdev)
continue; continue;
/* /*
...@@ -798,12 +802,11 @@ static int __init gpiolib_sysfs_init(void) ...@@ -798,12 +802,11 @@ static int __init gpiolib_sysfs_init(void)
* gpio_lock prevents us from doing this. * gpio_lock prevents us from doing this.
*/ */
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
status = gpiochip_sysfs_register(chip); status = gpiochip_sysfs_register(gdev);
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
} }
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
return status; return status;
} }
postcore_initcall(gpiolib_sysfs_init); postcore_initcall(gpiolib_sysfs_init);
...@@ -16,6 +16,11 @@ ...@@ -16,6 +16,11 @@
#include <linux/gpio/driver.h> #include <linux/gpio/driver.h>
#include <linux/gpio/machine.h> #include <linux/gpio/machine.h>
#include <linux/pinctrl/consumer.h> #include <linux/pinctrl/consumer.h>
#include <linux/idr.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <uapi/linux/gpio.h>
#include "gpiolib.h" #include "gpiolib.h"
...@@ -42,6 +47,14 @@ ...@@ -42,6 +47,14 @@
#define extra_checks 0 #define extra_checks 0
#endif #endif
/* Device and char device-related information */
static DEFINE_IDA(gpio_ida);
static dev_t gpio_devt;
#define GPIO_DEV_MAX 256 /* 256 GPIO chip devices supported */
static struct bus_type gpio_bus_type = {
.name = "gpio",
};
/* gpio_lock prevents conflicts during gpio_desc[] table updates. /* gpio_lock prevents conflicts during gpio_desc[] table updates.
* While any GPIO is requested, its gpio_chip is not removable; * While any GPIO is requested, its gpio_chip is not removable;
* each GPIO's "requested" flag serves as a lock and refcount. * each GPIO's "requested" flag serves as a lock and refcount.
...@@ -50,8 +63,7 @@ DEFINE_SPINLOCK(gpio_lock); ...@@ -50,8 +63,7 @@ DEFINE_SPINLOCK(gpio_lock);
static DEFINE_MUTEX(gpio_lookup_lock); static DEFINE_MUTEX(gpio_lookup_lock);
static LIST_HEAD(gpio_lookup_list); static LIST_HEAD(gpio_lookup_list);
LIST_HEAD(gpio_chips); LIST_HEAD(gpio_devices);
static void gpiochip_free_hogs(struct gpio_chip *chip); static void gpiochip_free_hogs(struct gpio_chip *chip);
static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip); static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip);
...@@ -67,15 +79,16 @@ static inline void desc_set_label(struct gpio_desc *d, const char *label) ...@@ -67,15 +79,16 @@ static inline void desc_set_label(struct gpio_desc *d, const char *label)
*/ */
struct gpio_desc *gpio_to_desc(unsigned gpio) struct gpio_desc *gpio_to_desc(unsigned gpio)
{ {
struct gpio_chip *chip; struct gpio_device *gdev;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
list_for_each_entry(chip, &gpio_chips, list) { list_for_each_entry(gdev, &gpio_devices, list) {
if (chip->base <= gpio && chip->base + chip->ngpio > gpio) { if (gdev->base <= gpio &&
gdev->base + gdev->ngpio > gpio) {
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
return &chip->desc[gpio - chip->base]; return &gdev->descs[gpio - gdev->base];
} }
} }
...@@ -94,10 +107,12 @@ EXPORT_SYMBOL_GPL(gpio_to_desc); ...@@ -94,10 +107,12 @@ EXPORT_SYMBOL_GPL(gpio_to_desc);
struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip, struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip,
u16 hwnum) u16 hwnum)
{ {
if (hwnum >= chip->ngpio) struct gpio_device *gdev = chip->gpiodev;
if (hwnum >= gdev->ngpio)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
return &chip->desc[hwnum]; return &gdev->descs[hwnum];
} }
/** /**
...@@ -107,7 +122,7 @@ struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip, ...@@ -107,7 +122,7 @@ struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip,
*/ */
int desc_to_gpio(const struct gpio_desc *desc) int desc_to_gpio(const struct gpio_desc *desc)
{ {
return desc->chip->base + (desc - &desc->chip->desc[0]); return desc->gdev->base + (desc - &desc->gdev->descs[0]);
} }
EXPORT_SYMBOL_GPL(desc_to_gpio); EXPORT_SYMBOL_GPL(desc_to_gpio);
...@@ -118,23 +133,25 @@ EXPORT_SYMBOL_GPL(desc_to_gpio); ...@@ -118,23 +133,25 @@ EXPORT_SYMBOL_GPL(desc_to_gpio);
*/ */
struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc) struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc)
{ {
return desc ? desc->chip : NULL; if (!desc || !desc->gdev || !desc->gdev->chip)
return NULL;
return desc->gdev->chip;
} }
EXPORT_SYMBOL_GPL(gpiod_to_chip); EXPORT_SYMBOL_GPL(gpiod_to_chip);
/* dynamic allocation of GPIOs, e.g. on a hotplugged device */ /* dynamic allocation of GPIOs, e.g. on a hotplugged device */
static int gpiochip_find_base(int ngpio) static int gpiochip_find_base(int ngpio)
{ {
struct gpio_chip *chip; struct gpio_device *gdev;
int base = ARCH_NR_GPIOS - ngpio; int base = ARCH_NR_GPIOS - ngpio;
list_for_each_entry_reverse(chip, &gpio_chips, list) { list_for_each_entry_reverse(gdev, &gpio_devices, list) {
/* found a free space? */ /* found a free space? */
if (chip->base + chip->ngpio <= base) if (gdev->base + gdev->ngpio <= base)
break; break;
else else
/* nope, check the space right before the chip */ /* nope, check the space right before the chip */
base = chip->base - ngpio; base = gdev->base - ngpio;
} }
if (gpio_is_valid(base)) { if (gpio_is_valid(base)) {
...@@ -187,18 +204,21 @@ EXPORT_SYMBOL_GPL(gpiod_get_direction); ...@@ -187,18 +204,21 @@ EXPORT_SYMBOL_GPL(gpiod_get_direction);
* Return -EBUSY if the new chip overlaps with some other chip's integer * Return -EBUSY if the new chip overlaps with some other chip's integer
* space. * space.
*/ */
static int gpiochip_add_to_list(struct gpio_chip *chip) static int gpiodev_add_to_list(struct gpio_device *gdev)
{ {
struct gpio_chip *iterator; struct gpio_device *iterator;
struct gpio_chip *previous = NULL; struct gpio_device *previous = NULL;
if (list_empty(&gpio_chips)) { if (!gdev->chip)
list_add_tail(&chip->list, &gpio_chips); return -EINVAL;
if (list_empty(&gpio_devices)) {
list_add_tail(&gdev->list, &gpio_devices);
return 0; return 0;
} }
list_for_each_entry(iterator, &gpio_chips, list) { list_for_each_entry(iterator, &gpio_devices, list) {
if (iterator->base >= chip->base + chip->ngpio) { if (iterator->base >= gdev->base + gdev->ngpio) {
/* /*
* Iterator is the first GPIO chip so there is no * Iterator is the first GPIO chip so there is no
* previous one * previous one
...@@ -212,7 +232,7 @@ static int gpiochip_add_to_list(struct gpio_chip *chip) ...@@ -212,7 +232,7 @@ static int gpiochip_add_to_list(struct gpio_chip *chip)
* and iterator chip. * and iterator chip.
*/ */
if (previous->base + previous->ngpio if (previous->base + previous->ngpio
<= chip->base) <= gdev->base)
goto found; goto found;
} }
} }
...@@ -225,18 +245,18 @@ static int gpiochip_add_to_list(struct gpio_chip *chip) ...@@ -225,18 +245,18 @@ static int gpiochip_add_to_list(struct gpio_chip *chip)
* Let iterator point to the last chip in the list. * Let iterator point to the last chip in the list.
*/ */
iterator = list_last_entry(&gpio_chips, struct gpio_chip, list); iterator = list_last_entry(&gpio_devices, struct gpio_device, list);
if (iterator->base + iterator->ngpio <= chip->base) { if (iterator->base + iterator->ngpio <= gdev->base) {
list_add(&chip->list, &iterator->list); list_add(&gdev->list, &iterator->list);
return 0; return 0;
} }
dev_err(chip->parent, dev_err(&gdev->dev,
"GPIO integer space overlap, cannot add chip\n"); "GPIO integer space overlap, cannot add chip\n");
return -EBUSY; return -EBUSY;
found: found:
list_add_tail(&chip->list, &iterator->list); list_add_tail(&gdev->list, &iterator->list);
return 0; return 0;
} }
...@@ -245,23 +265,23 @@ static int gpiochip_add_to_list(struct gpio_chip *chip) ...@@ -245,23 +265,23 @@ static int gpiochip_add_to_list(struct gpio_chip *chip)
*/ */
static struct gpio_desc *gpio_name_to_desc(const char * const name) static struct gpio_desc *gpio_name_to_desc(const char * const name)
{ {
struct gpio_chip *chip; struct gpio_device *gdev;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
list_for_each_entry(chip, &gpio_chips, list) { list_for_each_entry(gdev, &gpio_devices, list) {
int i; int i;
for (i = 0; i != chip->ngpio; ++i) { for (i = 0; i != gdev->ngpio; ++i) {
struct gpio_desc *gpio = &chip->desc[i]; struct gpio_desc *desc = &gdev->descs[i];
if (!gpio->name || !name) if (!desc->name || !name)
continue; continue;
if (!strcmp(gpio->name, name)) { if (!strcmp(desc->name, name)) {
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
return gpio; return desc;
} }
} }
} }
...@@ -279,6 +299,7 @@ static struct gpio_desc *gpio_name_to_desc(const char * const name) ...@@ -279,6 +299,7 @@ static struct gpio_desc *gpio_name_to_desc(const char * const name)
*/ */
static int gpiochip_set_desc_names(struct gpio_chip *gc) static int gpiochip_set_desc_names(struct gpio_chip *gc)
{ {
struct gpio_device *gdev = gc->gpiodev;
int i; int i;
if (!gc->names) if (!gc->names)
...@@ -290,18 +311,153 @@ static int gpiochip_set_desc_names(struct gpio_chip *gc) ...@@ -290,18 +311,153 @@ static int gpiochip_set_desc_names(struct gpio_chip *gc)
gpio = gpio_name_to_desc(gc->names[i]); gpio = gpio_name_to_desc(gc->names[i]);
if (gpio) if (gpio)
dev_warn(gc->parent, "Detected name collision for " dev_warn(&gdev->dev,
"GPIO name '%s'\n", "Detected name collision for GPIO name '%s'\n",
gc->names[i]); gc->names[i]);
} }
/* Then add all names to the GPIO descriptors */ /* Then add all names to the GPIO descriptors */
for (i = 0; i != gc->ngpio; ++i) for (i = 0; i != gc->ngpio; ++i)
gc->desc[i].name = gc->names[i]; gdev->descs[i].name = gc->names[i];
return 0;
}
/**
* gpio_ioctl() - ioctl handler for the GPIO chardev
*/
static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct gpio_device *gdev = filp->private_data;
struct gpio_chip *chip = gdev->chip;
int __user *ip = (int __user *)arg;
/* We fail any subsequent ioctl():s when the chip is gone */
if (!chip)
return -ENODEV;
/* Fill in the struct and pass to userspace */
if (cmd == GPIO_GET_CHIPINFO_IOCTL) {
struct gpiochip_info chipinfo;
strncpy(chipinfo.name, dev_name(&gdev->dev),
sizeof(chipinfo.name));
chipinfo.name[sizeof(chipinfo.name)-1] = '\0';
strncpy(chipinfo.label, gdev->label,
sizeof(chipinfo.label));
chipinfo.label[sizeof(chipinfo.label)-1] = '\0';
chipinfo.lines = gdev->ngpio;
if (copy_to_user(ip, &chipinfo, sizeof(chipinfo)))
return -EFAULT;
return 0;
} else if (cmd == GPIO_GET_LINEINFO_IOCTL) {
struct gpioline_info lineinfo;
struct gpio_desc *desc;
if (copy_from_user(&lineinfo, ip, sizeof(lineinfo)))
return -EFAULT;
if (lineinfo.line_offset > gdev->ngpio)
return -EINVAL;
desc = &gdev->descs[lineinfo.line_offset];
if (desc->name) {
strncpy(lineinfo.name, desc->name,
sizeof(lineinfo.name));
lineinfo.name[sizeof(lineinfo.name)-1] = '\0';
} else {
lineinfo.name[0] = '\0';
}
if (desc->label) {
strncpy(lineinfo.label, desc->label,
sizeof(lineinfo.label));
lineinfo.label[sizeof(lineinfo.label)-1] = '\0';
} else {
lineinfo.label[0] = '\0';
}
/*
* Userspace only need to know that the kernel is using
* this GPIO so it can't use it.
*/
lineinfo.flags = 0;
if (test_bit(FLAG_REQUESTED, &desc->flags) ||
test_bit(FLAG_IS_HOGGED, &desc->flags) ||
test_bit(FLAG_USED_AS_IRQ, &desc->flags) ||
test_bit(FLAG_EXPORT, &desc->flags) ||
test_bit(FLAG_SYSFS, &desc->flags))
lineinfo.flags |= GPIOLINE_FLAG_KERNEL;
if (test_bit(FLAG_IS_OUT, &desc->flags))
lineinfo.flags |= GPIOLINE_FLAG_IS_OUT;
if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
lineinfo.flags |= GPIOLINE_FLAG_ACTIVE_LOW;
if (test_bit(FLAG_OPEN_DRAIN, &desc->flags))
lineinfo.flags |= GPIOLINE_FLAG_OPEN_DRAIN;
if (test_bit(FLAG_OPEN_SOURCE, &desc->flags))
lineinfo.flags |= GPIOLINE_FLAG_OPEN_SOURCE;
if (copy_to_user(ip, &lineinfo, sizeof(lineinfo)))
return -EFAULT;
return 0;
}
return -EINVAL;
}
/**
* gpio_chrdev_open() - open the chardev for ioctl operations
* @inode: inode for this chardev
* @filp: file struct for storing private data
* Returns 0 on success
*/
static int gpio_chrdev_open(struct inode *inode, struct file *filp)
{
struct gpio_device *gdev = container_of(inode->i_cdev,
struct gpio_device, chrdev);
/* Fail on open if the backing gpiochip is gone */
if (!gdev || !gdev->chip)
return -ENODEV;
get_device(&gdev->dev);
filp->private_data = gdev;
return 0; return 0;
} }
/**
* gpio_chrdev_release() - close chardev after ioctl operations
* @inode: inode for this chardev
* @filp: file struct for storing private data
* Returns 0 on success
*/
static int gpio_chrdev_release(struct inode *inode, struct file *filp)
{
struct gpio_device *gdev = container_of(inode->i_cdev,
struct gpio_device, chrdev);
if (!gdev)
return -ENODEV;
put_device(&gdev->dev);
return 0;
}
static const struct file_operations gpio_fileops = {
.release = gpio_chrdev_release,
.open = gpio_chrdev_open,
.owner = THIS_MODULE,
.llseek = noop_llseek,
.unlocked_ioctl = gpio_ioctl,
.compat_ioctl = gpio_ioctl,
};
static void gpiodevice_release(struct device *dev)
{
struct gpio_device *gdev = dev_get_drvdata(dev);
cdev_del(&gdev->chrdev);
list_del(&gdev->list);
ida_simple_remove(&gpio_ida, gdev->id);
kfree(gdev);
}
/** /**
* gpiochip_add_data() - register a gpio_chip * gpiochip_add_data() - register a gpio_chip
* @chip: the chip to register, with chip->base initialized * @chip: the chip to register, with chip->base initialized
...@@ -323,43 +479,107 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data) ...@@ -323,43 +479,107 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data)
{ {
unsigned long flags; unsigned long flags;
int status = 0; int status = 0;
unsigned id; unsigned i;
int base = chip->base; int base = chip->base;
struct gpio_desc *descs; struct gpio_device *gdev;
descs = kcalloc(chip->ngpio, sizeof(descs[0]), GFP_KERNEL); /*
if (!descs) * First: allocate and populate the internal stat container, and
* set up the struct device.
*/
gdev = kzalloc(sizeof(*gdev), GFP_KERNEL);
if (!gdev)
return -ENOMEM; return -ENOMEM;
gdev->dev.bus = &gpio_bus_type;
gdev->chip = chip;
chip->gpiodev = gdev;
if (chip->parent) {
gdev->dev.parent = chip->parent;
gdev->dev.of_node = chip->parent->of_node;
} else {
#ifdef CONFIG_OF_GPIO
/* If the gpiochip has an assigned OF node this takes precedence */
if (chip->of_node)
gdev->dev.of_node = chip->of_node;
#endif
}
gdev->id = ida_simple_get(&gpio_ida, 0, 0, GFP_KERNEL);
if (gdev->id < 0) {
status = gdev->id;
goto err_free_gdev;
}
dev_set_name(&gdev->dev, "gpiochip%d", gdev->id);
device_initialize(&gdev->dev);
dev_set_drvdata(&gdev->dev, gdev);
if (chip->parent && chip->parent->driver)
gdev->owner = chip->parent->driver->owner;
else if (chip->owner)
/* TODO: remove chip->owner */
gdev->owner = chip->owner;
else
gdev->owner = THIS_MODULE;
chip->data = data; gdev->descs = devm_kcalloc(&gdev->dev, chip->ngpio,
sizeof(gdev->descs[0]), GFP_KERNEL);
if (!gdev->descs) {
status = -ENOMEM;
goto err_free_gdev;
}
if (chip->ngpio == 0) { if (chip->ngpio == 0) {
chip_err(chip, "tried to insert a GPIO chip with zero lines\n"); chip_err(chip, "tried to insert a GPIO chip with zero lines\n");
return -EINVAL; status = -EINVAL;
goto err_free_gdev;
} }
if (chip->label)
gdev->label = devm_kstrdup(&gdev->dev, chip->label, GFP_KERNEL);
else
gdev->label = devm_kstrdup(&gdev->dev, "unknown", GFP_KERNEL);
if (!gdev->label) {
status = -ENOMEM;
goto err_free_gdev;
}
gdev->ngpio = chip->ngpio;
gdev->data = data;
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
/*
* TODO: this allocates a Linux GPIO number base in the global
* GPIO numberspace for this chip. In the long run we want to
* get *rid* of this numberspace and use only descriptors, but
* it may be a pipe dream. It will not happen before we get rid
* of the sysfs interface anyways.
*/
if (base < 0) { if (base < 0) {
base = gpiochip_find_base(chip->ngpio); base = gpiochip_find_base(chip->ngpio);
if (base < 0) { if (base < 0) {
status = base; status = base;
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
goto err_free_descs; goto err_free_gdev;
} }
/*
* TODO: it should not be necessary to reflect the assigned
* base outside of the GPIO subsystem. Go over drivers and
* see if anyone makes use of this, else drop this and assign
* a poison instead.
*/
chip->base = base; chip->base = base;
} }
gdev->base = base;
status = gpiochip_add_to_list(chip); status = gpiodev_add_to_list(gdev);
if (status) { if (status) {
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
goto err_free_descs; goto err_free_gdev;
} }
for (id = 0; id < chip->ngpio; id++) { for (i = 0; i < chip->ngpio; i++) {
struct gpio_desc *desc = &descs[id]; struct gpio_desc *desc = &gdev->descs[i];
desc->chip = chip; desc->gdev = gdev;
/* REVISIT: most hardware initializes GPIOs as inputs (often /* REVISIT: most hardware initializes GPIOs as inputs (often
* with pullups enabled) so power usage is minimized. Linux * with pullups enabled) so power usage is minimized. Linux
...@@ -370,17 +590,12 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data) ...@@ -370,17 +590,12 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data)
desc->flags = !chip->direction_input ? (1 << FLAG_IS_OUT) : 0; desc->flags = !chip->direction_input ? (1 << FLAG_IS_OUT) : 0;
} }
chip->desc = descs;
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
#ifdef CONFIG_PINCTRL #ifdef CONFIG_PINCTRL
INIT_LIST_HEAD(&chip->pin_ranges); INIT_LIST_HEAD(&gdev->pin_ranges);
#endif #endif
if (!chip->owner && chip->parent && chip->parent->driver)
chip->owner = chip->parent->driver->owner;
status = gpiochip_set_desc_names(chip); status = gpiochip_set_desc_names(chip);
if (status) if (status)
goto err_remove_from_list; goto err_remove_from_list;
...@@ -391,36 +606,72 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data) ...@@ -391,36 +606,72 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data)
acpi_gpiochip_add(chip); acpi_gpiochip_add(chip);
status = gpiochip_sysfs_register(chip); /*
* By first adding the chardev, and then adding the device,
* we get a device node entry in sysfs under
* /sys/bus/gpio/devices/gpiochipN/dev that can be used for
* coldplug of device nodes and other udev business.
*/
cdev_init(&gdev->chrdev, &gpio_fileops);
gdev->chrdev.owner = THIS_MODULE;
gdev->chrdev.kobj.parent = &gdev->dev.kobj;
gdev->dev.devt = MKDEV(MAJOR(gpio_devt), gdev->id);
status = cdev_add(&gdev->chrdev, gdev->dev.devt, 1);
if (status < 0)
chip_warn(chip, "failed to add char device %d:%d\n",
MAJOR(gpio_devt), gdev->id);
else
chip_dbg(chip, "added GPIO chardev (%d:%d)\n",
MAJOR(gpio_devt), gdev->id);
status = device_add(&gdev->dev);
if (status)
goto err_remove_chardev;
status = gpiochip_sysfs_register(gdev);
if (status) if (status)
goto err_remove_chip; goto err_remove_device;
pr_debug("%s: registered GPIOs %d to %d on device: %s\n", __func__, /* From this point, the .release() function cleans up gpio_device */
chip->base, chip->base + chip->ngpio - 1, gdev->dev.release = gpiodevice_release;
chip->label ? : "generic"); get_device(&gdev->dev);
pr_debug("%s: registered GPIOs %d to %d on device: %s (%s)\n",
__func__, gdev->base, gdev->base + gdev->ngpio - 1,
dev_name(&gdev->dev), chip->label ? : "generic");
return 0; return 0;
err_remove_device:
device_del(&gdev->dev);
err_remove_chardev:
cdev_del(&gdev->chrdev);
err_remove_chip: err_remove_chip:
acpi_gpiochip_remove(chip); acpi_gpiochip_remove(chip);
gpiochip_free_hogs(chip); gpiochip_free_hogs(chip);
of_gpiochip_remove(chip); of_gpiochip_remove(chip);
err_remove_from_list: err_remove_from_list:
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
list_del(&chip->list); list_del(&gdev->list);
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
chip->desc = NULL; err_free_gdev:
err_free_descs: ida_simple_remove(&gpio_ida, gdev->id);
kfree(descs);
/* failures here can mean systems won't boot... */ /* failures here can mean systems won't boot... */
pr_err("%s: GPIOs %d..%d (%s) failed to register\n", __func__, pr_err("%s: GPIOs %d..%d (%s) failed to register\n", __func__,
chip->base, chip->base + chip->ngpio - 1, gdev->base, gdev->base + gdev->ngpio - 1,
chip->label ? : "generic"); chip->label ? : "generic");
kfree(gdev);
return status; return status;
} }
EXPORT_SYMBOL_GPL(gpiochip_add_data); EXPORT_SYMBOL_GPL(gpiochip_add_data);
/**
* gpiochip_get_data() - get per-subdriver data for the chip
*/
void *gpiochip_get_data(struct gpio_chip *chip)
{
return chip->gpiodev->data;
}
EXPORT_SYMBOL_GPL(gpiochip_get_data);
/** /**
* gpiochip_remove() - unregister a gpio_chip * gpiochip_remove() - unregister a gpio_chip
* @chip: the chip to unregister * @chip: the chip to unregister
...@@ -429,36 +680,46 @@ EXPORT_SYMBOL_GPL(gpiochip_add_data); ...@@ -429,36 +680,46 @@ EXPORT_SYMBOL_GPL(gpiochip_add_data);
*/ */
void gpiochip_remove(struct gpio_chip *chip) void gpiochip_remove(struct gpio_chip *chip)
{ {
struct gpio_device *gdev = chip->gpiodev;
struct gpio_desc *desc; struct gpio_desc *desc;
unsigned long flags; unsigned long flags;
unsigned id; unsigned i;
bool requested = false; bool requested = false;
gpiochip_sysfs_unregister(chip); /* FIXME: should the legacy sysfs handling be moved to gpio_device? */
gpiochip_sysfs_unregister(gdev);
/* Numb the device, cancelling all outstanding operations */
gdev->chip = NULL;
gpiochip_irqchip_remove(chip); gpiochip_irqchip_remove(chip);
acpi_gpiochip_remove(chip); acpi_gpiochip_remove(chip);
gpiochip_remove_pin_ranges(chip); gpiochip_remove_pin_ranges(chip);
gpiochip_free_hogs(chip); gpiochip_free_hogs(chip);
of_gpiochip_remove(chip); of_gpiochip_remove(chip);
/*
* We accept no more calls into the driver from this point, so
* NULL the driver data pointer
*/
gdev->data = NULL;
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
for (id = 0; id < chip->ngpio; id++) { for (i = 0; i < gdev->ngpio; i++) {
desc = &chip->desc[id]; desc = &gdev->descs[i];
desc->chip = NULL;
if (test_bit(FLAG_REQUESTED, &desc->flags)) if (test_bit(FLAG_REQUESTED, &desc->flags))
requested = true; requested = true;
} }
list_del(&chip->list);
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
if (requested) if (requested)
dev_crit(chip->parent, dev_crit(&gdev->dev,
"REMOVING GPIOCHIP WITH GPIOS STILL REQUESTED\n"); "REMOVING GPIOCHIP WITH GPIOS STILL REQUESTED\n");
kfree(chip->desc); /*
chip->desc = NULL; * The gpiochip side puts its use of the device to rest here:
* if there are no userspace clients, the chardev and device will
* be removed, else it will be dangling until the last user is
* gone.
*/
put_device(&gdev->dev);
} }
EXPORT_SYMBOL_GPL(gpiochip_remove); EXPORT_SYMBOL_GPL(gpiochip_remove);
...@@ -477,17 +738,21 @@ struct gpio_chip *gpiochip_find(void *data, ...@@ -477,17 +738,21 @@ struct gpio_chip *gpiochip_find(void *data,
int (*match)(struct gpio_chip *chip, int (*match)(struct gpio_chip *chip,
void *data)) void *data))
{ {
struct gpio_device *gdev;
struct gpio_chip *chip; struct gpio_chip *chip;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
list_for_each_entry(chip, &gpio_chips, list) list_for_each_entry(gdev, &gpio_devices, list)
if (match(chip, data)) if (match(gdev->chip, data))
break; break;
/* No match? */ /* No match? */
if (&chip->list == &gpio_chips) if (&gdev->list == &gpio_devices)
chip = NULL; chip = NULL;
else
chip = gdev->chip;
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
return chip; return chip;
...@@ -617,14 +882,14 @@ static int gpiochip_irq_reqres(struct irq_data *d) ...@@ -617,14 +882,14 @@ static int gpiochip_irq_reqres(struct irq_data *d)
{ {
struct gpio_chip *chip = irq_data_get_irq_chip_data(d); struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
if (!try_module_get(chip->owner)) if (!try_module_get(chip->gpiodev->owner))
return -ENODEV; return -ENODEV;
if (gpiochip_lock_as_irq(chip, d->hwirq)) { if (gpiochip_lock_as_irq(chip, d->hwirq)) {
chip_err(chip, chip_err(chip,
"unable to lock HW IRQ %lu for IRQ\n", "unable to lock HW IRQ %lu for IRQ\n",
d->hwirq); d->hwirq);
module_put(chip->owner); module_put(chip->gpiodev->owner);
return -EINVAL; return -EINVAL;
} }
return 0; return 0;
...@@ -635,7 +900,7 @@ static void gpiochip_irq_relres(struct irq_data *d) ...@@ -635,7 +900,7 @@ static void gpiochip_irq_relres(struct irq_data *d)
struct gpio_chip *chip = irq_data_get_irq_chip_data(d); struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
gpiochip_unlock_as_irq(chip, d->hwirq); gpiochip_unlock_as_irq(chip, d->hwirq);
module_put(chip->owner); module_put(chip->gpiodev->owner);
} }
static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset) static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
...@@ -785,7 +1050,7 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) {} ...@@ -785,7 +1050,7 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) {}
*/ */
int gpiochip_generic_request(struct gpio_chip *chip, unsigned offset) int gpiochip_generic_request(struct gpio_chip *chip, unsigned offset)
{ {
return pinctrl_request_gpio(chip->base + offset); return pinctrl_request_gpio(chip->gpiodev->base + offset);
} }
EXPORT_SYMBOL_GPL(gpiochip_generic_request); EXPORT_SYMBOL_GPL(gpiochip_generic_request);
...@@ -796,7 +1061,7 @@ EXPORT_SYMBOL_GPL(gpiochip_generic_request); ...@@ -796,7 +1061,7 @@ EXPORT_SYMBOL_GPL(gpiochip_generic_request);
*/ */
void gpiochip_generic_free(struct gpio_chip *chip, unsigned offset) void gpiochip_generic_free(struct gpio_chip *chip, unsigned offset)
{ {
pinctrl_free_gpio(chip->base + offset); pinctrl_free_gpio(chip->gpiodev->base + offset);
} }
EXPORT_SYMBOL_GPL(gpiochip_generic_free); EXPORT_SYMBOL_GPL(gpiochip_generic_free);
...@@ -814,6 +1079,7 @@ int gpiochip_add_pingroup_range(struct gpio_chip *chip, ...@@ -814,6 +1079,7 @@ int gpiochip_add_pingroup_range(struct gpio_chip *chip,
unsigned int gpio_offset, const char *pin_group) unsigned int gpio_offset, const char *pin_group)
{ {
struct gpio_pin_range *pin_range; struct gpio_pin_range *pin_range;
struct gpio_device *gdev = chip->gpiodev;
int ret; int ret;
pin_range = kzalloc(sizeof(*pin_range), GFP_KERNEL); pin_range = kzalloc(sizeof(*pin_range), GFP_KERNEL);
...@@ -826,7 +1092,7 @@ int gpiochip_add_pingroup_range(struct gpio_chip *chip, ...@@ -826,7 +1092,7 @@ int gpiochip_add_pingroup_range(struct gpio_chip *chip,
pin_range->range.id = gpio_offset; pin_range->range.id = gpio_offset;
pin_range->range.gc = chip; pin_range->range.gc = chip;
pin_range->range.name = chip->label; pin_range->range.name = chip->label;
pin_range->range.base = chip->base + gpio_offset; pin_range->range.base = gdev->base + gpio_offset;
pin_range->pctldev = pctldev; pin_range->pctldev = pctldev;
ret = pinctrl_get_group_pins(pctldev, pin_group, ret = pinctrl_get_group_pins(pctldev, pin_group,
...@@ -843,7 +1109,7 @@ int gpiochip_add_pingroup_range(struct gpio_chip *chip, ...@@ -843,7 +1109,7 @@ int gpiochip_add_pingroup_range(struct gpio_chip *chip,
gpio_offset, gpio_offset + pin_range->range.npins - 1, gpio_offset, gpio_offset + pin_range->range.npins - 1,
pinctrl_dev_get_devname(pctldev), pin_group); pinctrl_dev_get_devname(pctldev), pin_group);
list_add_tail(&pin_range->node, &chip->pin_ranges); list_add_tail(&pin_range->node, &gdev->pin_ranges);
return 0; return 0;
} }
...@@ -863,6 +1129,7 @@ int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, ...@@ -863,6 +1129,7 @@ int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
unsigned int npins) unsigned int npins)
{ {
struct gpio_pin_range *pin_range; struct gpio_pin_range *pin_range;
struct gpio_device *gdev = chip->gpiodev;
int ret; int ret;
pin_range = kzalloc(sizeof(*pin_range), GFP_KERNEL); pin_range = kzalloc(sizeof(*pin_range), GFP_KERNEL);
...@@ -875,7 +1142,7 @@ int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, ...@@ -875,7 +1142,7 @@ int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
pin_range->range.id = gpio_offset; pin_range->range.id = gpio_offset;
pin_range->range.gc = chip; pin_range->range.gc = chip;
pin_range->range.name = chip->label; pin_range->range.name = chip->label;
pin_range->range.base = chip->base + gpio_offset; pin_range->range.base = gdev->base + gpio_offset;
pin_range->range.pin_base = pin_offset; pin_range->range.pin_base = pin_offset;
pin_range->range.npins = npins; pin_range->range.npins = npins;
pin_range->pctldev = pinctrl_find_and_add_gpio_range(pinctl_name, pin_range->pctldev = pinctrl_find_and_add_gpio_range(pinctl_name,
...@@ -891,7 +1158,7 @@ int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, ...@@ -891,7 +1158,7 @@ int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
pinctl_name, pinctl_name,
pin_offset, pin_offset + npins - 1); pin_offset, pin_offset + npins - 1);
list_add_tail(&pin_range->node, &chip->pin_ranges); list_add_tail(&pin_range->node, &gdev->pin_ranges);
return 0; return 0;
} }
...@@ -904,8 +1171,9 @@ EXPORT_SYMBOL_GPL(gpiochip_add_pin_range); ...@@ -904,8 +1171,9 @@ EXPORT_SYMBOL_GPL(gpiochip_add_pin_range);
void gpiochip_remove_pin_ranges(struct gpio_chip *chip) void gpiochip_remove_pin_ranges(struct gpio_chip *chip)
{ {
struct gpio_pin_range *pin_range, *tmp; struct gpio_pin_range *pin_range, *tmp;
struct gpio_device *gdev = chip->gpiodev;
list_for_each_entry_safe(pin_range, tmp, &chip->pin_ranges, node) { list_for_each_entry_safe(pin_range, tmp, &gdev->pin_ranges, node) {
list_del(&pin_range->node); list_del(&pin_range->node);
pinctrl_remove_gpio_range(pin_range->pctldev, pinctrl_remove_gpio_range(pin_range->pctldev,
&pin_range->range); &pin_range->range);
...@@ -922,7 +1190,7 @@ EXPORT_SYMBOL_GPL(gpiochip_remove_pin_ranges); ...@@ -922,7 +1190,7 @@ EXPORT_SYMBOL_GPL(gpiochip_remove_pin_ranges);
*/ */
static int __gpiod_request(struct gpio_desc *desc, const char *label) static int __gpiod_request(struct gpio_desc *desc, const char *label)
{ {
struct gpio_chip *chip = desc->chip; struct gpio_chip *chip = desc->gdev->chip;
int status; int status;
unsigned long flags; unsigned long flags;
...@@ -971,27 +1239,50 @@ static int __gpiod_request(struct gpio_desc *desc, const char *label) ...@@ -971,27 +1239,50 @@ static int __gpiod_request(struct gpio_desc *desc, const char *label)
return status; return status;
} }
/*
* This descriptor validation needs to be inserted verbatim into each
* function taking a descriptor, so we need to use a preprocessor
* macro to avoid endless duplication.
*/
#define VALIDATE_DESC(desc) do { \
if (!desc || !desc->gdev) { \
pr_warn("%s: invalid GPIO\n", __func__); \
return -EINVAL; \
} \
if ( !desc->gdev->chip ) { \
dev_warn(&desc->gdev->dev, \
"%s: backing chip is gone\n", __func__); \
return 0; \
} } while (0)
#define VALIDATE_DESC_VOID(desc) do { \
if (!desc || !desc->gdev) { \
pr_warn("%s: invalid GPIO\n", __func__); \
return; \
} \
if (!desc->gdev->chip) { \
dev_warn(&desc->gdev->dev, \
"%s: backing chip is gone\n", __func__); \
return; \
} } while (0)
int gpiod_request(struct gpio_desc *desc, const char *label) int gpiod_request(struct gpio_desc *desc, const char *label)
{ {
int status = -EPROBE_DEFER; int status = -EPROBE_DEFER;
struct gpio_chip *chip; struct gpio_device *gdev;
if (!desc) { VALIDATE_DESC(desc);
pr_warn("%s: invalid GPIO\n", __func__); gdev = desc->gdev;
return -EINVAL;
}
chip = desc->chip; if (try_module_get(gdev->owner)) {
if (!chip)
goto done;
if (try_module_get(chip->owner)) {
status = __gpiod_request(desc, label); status = __gpiod_request(desc, label);
if (status < 0) if (status < 0)
module_put(chip->owner); module_put(gdev->owner);
else
get_device(&gdev->dev);
} }
done:
if (status) if (status)
gpiod_dbg(desc, "%s: status %d\n", __func__, status); gpiod_dbg(desc, "%s: status %d\n", __func__, status);
...@@ -1010,7 +1301,7 @@ static bool __gpiod_free(struct gpio_desc *desc) ...@@ -1010,7 +1301,7 @@ static bool __gpiod_free(struct gpio_desc *desc)
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
chip = desc->chip; chip = desc->gdev->chip;
if (chip && test_bit(FLAG_REQUESTED, &desc->flags)) { if (chip && test_bit(FLAG_REQUESTED, &desc->flags)) {
if (chip->free) { if (chip->free) {
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
...@@ -1033,10 +1324,12 @@ static bool __gpiod_free(struct gpio_desc *desc) ...@@ -1033,10 +1324,12 @@ static bool __gpiod_free(struct gpio_desc *desc)
void gpiod_free(struct gpio_desc *desc) void gpiod_free(struct gpio_desc *desc)
{ {
if (desc && __gpiod_free(desc)) if (desc && desc->gdev && __gpiod_free(desc)) {
module_put(desc->chip->owner); module_put(desc->gdev->owner);
else put_device(&desc->gdev->dev);
} else {
WARN_ON(extra_checks); WARN_ON(extra_checks);
}
} }
/** /**
...@@ -1059,7 +1352,7 @@ const char *gpiochip_is_requested(struct gpio_chip *chip, unsigned offset) ...@@ -1059,7 +1352,7 @@ const char *gpiochip_is_requested(struct gpio_chip *chip, unsigned offset)
if (offset >= chip->ngpio) if (offset >= chip->ngpio)
return NULL; return NULL;
desc = &chip->desc[offset]; desc = &chip->gpiodev->descs[offset];
if (test_bit(FLAG_REQUESTED, &desc->flags) == 0) if (test_bit(FLAG_REQUESTED, &desc->flags) == 0)
return NULL; return NULL;
...@@ -1111,7 +1404,8 @@ void gpiochip_free_own_desc(struct gpio_desc *desc) ...@@ -1111,7 +1404,8 @@ void gpiochip_free_own_desc(struct gpio_desc *desc)
} }
EXPORT_SYMBOL_GPL(gpiochip_free_own_desc); EXPORT_SYMBOL_GPL(gpiochip_free_own_desc);
/* Drivers MUST set GPIO direction before making get/set calls. In /*
* Drivers MUST set GPIO direction before making get/set calls. In
* some cases this is done in early boot, before IRQs are enabled. * some cases this is done in early boot, before IRQs are enabled.
* *
* As a rule these aren't called more than once (except for drivers * As a rule these aren't called more than once (except for drivers
...@@ -1134,12 +1428,9 @@ int gpiod_direction_input(struct gpio_desc *desc) ...@@ -1134,12 +1428,9 @@ int gpiod_direction_input(struct gpio_desc *desc)
struct gpio_chip *chip; struct gpio_chip *chip;
int status = -EINVAL; int status = -EINVAL;
if (!desc || !desc->chip) { VALIDATE_DESC(desc);
pr_warn("%s: invalid GPIO\n", __func__); chip = desc->gdev->chip;
return -EINVAL;
}
chip = desc->chip;
if (!chip->get || !chip->direction_input) { if (!chip->get || !chip->direction_input) {
gpiod_warn(desc, gpiod_warn(desc,
"%s: missing get() or direction_input() operations\n", "%s: missing get() or direction_input() operations\n",
...@@ -1178,7 +1469,7 @@ static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value) ...@@ -1178,7 +1469,7 @@ static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value)
if (!value && test_bit(FLAG_OPEN_SOURCE, &desc->flags)) if (!value && test_bit(FLAG_OPEN_SOURCE, &desc->flags))
return gpiod_direction_input(desc); return gpiod_direction_input(desc);
chip = desc->chip; chip = desc->gdev->chip;
if (!chip->set || !chip->direction_output) { if (!chip->set || !chip->direction_output) {
gpiod_warn(desc, gpiod_warn(desc,
"%s: missing set() or direction_output() operations\n", "%s: missing set() or direction_output() operations\n",
...@@ -1207,10 +1498,7 @@ static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value) ...@@ -1207,10 +1498,7 @@ static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value)
*/ */
int gpiod_direction_output_raw(struct gpio_desc *desc, int value) int gpiod_direction_output_raw(struct gpio_desc *desc, int value)
{ {
if (!desc || !desc->chip) { VALIDATE_DESC(desc);
pr_warn("%s: invalid GPIO\n", __func__);
return -EINVAL;
}
return _gpiod_direction_output_raw(desc, value); return _gpiod_direction_output_raw(desc, value);
} }
EXPORT_SYMBOL_GPL(gpiod_direction_output_raw); EXPORT_SYMBOL_GPL(gpiod_direction_output_raw);
...@@ -1229,10 +1517,7 @@ EXPORT_SYMBOL_GPL(gpiod_direction_output_raw); ...@@ -1229,10 +1517,7 @@ EXPORT_SYMBOL_GPL(gpiod_direction_output_raw);
*/ */
int gpiod_direction_output(struct gpio_desc *desc, int value) int gpiod_direction_output(struct gpio_desc *desc, int value)
{ {
if (!desc || !desc->chip) { VALIDATE_DESC(desc);
pr_warn("%s: invalid GPIO\n", __func__);
return -EINVAL;
}
if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
value = !value; value = !value;
return _gpiod_direction_output_raw(desc, value); return _gpiod_direction_output_raw(desc, value);
...@@ -1251,12 +1536,8 @@ int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) ...@@ -1251,12 +1536,8 @@ int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce)
{ {
struct gpio_chip *chip; struct gpio_chip *chip;
if (!desc || !desc->chip) { VALIDATE_DESC(desc);
pr_warn("%s: invalid GPIO\n", __func__); chip = desc->gdev->chip;
return -EINVAL;
}
chip = desc->chip;
if (!chip->set || !chip->set_debounce) { if (!chip->set || !chip->set_debounce) {
gpiod_dbg(desc, gpiod_dbg(desc,
"%s: missing set() or set_debounce() operations\n", "%s: missing set() or set_debounce() operations\n",
...@@ -1276,6 +1557,7 @@ EXPORT_SYMBOL_GPL(gpiod_set_debounce); ...@@ -1276,6 +1557,7 @@ EXPORT_SYMBOL_GPL(gpiod_set_debounce);
*/ */
int gpiod_is_active_low(const struct gpio_desc *desc) int gpiod_is_active_low(const struct gpio_desc *desc)
{ {
VALIDATE_DESC(desc);
return test_bit(FLAG_ACTIVE_LOW, &desc->flags); return test_bit(FLAG_ACTIVE_LOW, &desc->flags);
} }
EXPORT_SYMBOL_GPL(gpiod_is_active_low); EXPORT_SYMBOL_GPL(gpiod_is_active_low);
...@@ -1308,7 +1590,7 @@ static int _gpiod_get_raw_value(const struct gpio_desc *desc) ...@@ -1308,7 +1590,7 @@ static int _gpiod_get_raw_value(const struct gpio_desc *desc)
int offset; int offset;
int value; int value;
chip = desc->chip; chip = desc->gdev->chip;
offset = gpio_chip_hwgpio(desc); offset = gpio_chip_hwgpio(desc);
value = chip->get ? chip->get(chip, offset) : -EIO; value = chip->get ? chip->get(chip, offset) : -EIO;
value = value < 0 ? value : !!value; value = value < 0 ? value : !!value;
...@@ -1328,10 +1610,9 @@ static int _gpiod_get_raw_value(const struct gpio_desc *desc) ...@@ -1328,10 +1610,9 @@ static int _gpiod_get_raw_value(const struct gpio_desc *desc)
*/ */
int gpiod_get_raw_value(const struct gpio_desc *desc) int gpiod_get_raw_value(const struct gpio_desc *desc)
{ {
if (!desc) VALIDATE_DESC(desc);
return 0;
/* Should be using gpio_get_value_cansleep() */ /* Should be using gpio_get_value_cansleep() */
WARN_ON(desc->chip->can_sleep); WARN_ON(desc->gdev->chip->can_sleep);
return _gpiod_get_raw_value(desc); return _gpiod_get_raw_value(desc);
} }
EXPORT_SYMBOL_GPL(gpiod_get_raw_value); EXPORT_SYMBOL_GPL(gpiod_get_raw_value);
...@@ -1349,10 +1630,10 @@ EXPORT_SYMBOL_GPL(gpiod_get_raw_value); ...@@ -1349,10 +1630,10 @@ EXPORT_SYMBOL_GPL(gpiod_get_raw_value);
int gpiod_get_value(const struct gpio_desc *desc) int gpiod_get_value(const struct gpio_desc *desc)
{ {
int value; int value;
if (!desc)
return 0; VALIDATE_DESC(desc);
/* Should be using gpio_get_value_cansleep() */ /* Should be using gpio_get_value_cansleep() */
WARN_ON(desc->chip->can_sleep); WARN_ON(desc->gdev->chip->can_sleep);
value = _gpiod_get_raw_value(desc); value = _gpiod_get_raw_value(desc);
if (value < 0) if (value < 0)
...@@ -1373,7 +1654,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_value); ...@@ -1373,7 +1654,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_value);
static void _gpio_set_open_drain_value(struct gpio_desc *desc, bool value) static void _gpio_set_open_drain_value(struct gpio_desc *desc, bool value)
{ {
int err = 0; int err = 0;
struct gpio_chip *chip = desc->chip; struct gpio_chip *chip = desc->gdev->chip;
int offset = gpio_chip_hwgpio(desc); int offset = gpio_chip_hwgpio(desc);
if (value) { if (value) {
...@@ -1400,7 +1681,7 @@ static void _gpio_set_open_drain_value(struct gpio_desc *desc, bool value) ...@@ -1400,7 +1681,7 @@ static void _gpio_set_open_drain_value(struct gpio_desc *desc, bool value)
static void _gpio_set_open_source_value(struct gpio_desc *desc, bool value) static void _gpio_set_open_source_value(struct gpio_desc *desc, bool value)
{ {
int err = 0; int err = 0;
struct gpio_chip *chip = desc->chip; struct gpio_chip *chip = desc->gdev->chip;
int offset = gpio_chip_hwgpio(desc); int offset = gpio_chip_hwgpio(desc);
if (value) { if (value) {
...@@ -1423,7 +1704,7 @@ static void _gpiod_set_raw_value(struct gpio_desc *desc, bool value) ...@@ -1423,7 +1704,7 @@ static void _gpiod_set_raw_value(struct gpio_desc *desc, bool value)
{ {
struct gpio_chip *chip; struct gpio_chip *chip;
chip = desc->chip; chip = desc->gdev->chip;
trace_gpio_value(desc_to_gpio(desc), 0, value); trace_gpio_value(desc_to_gpio(desc), 0, value);
if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) if (test_bit(FLAG_OPEN_DRAIN, &desc->flags))
_gpio_set_open_drain_value(desc, value); _gpio_set_open_drain_value(desc, value);
...@@ -1471,7 +1752,7 @@ static void gpiod_set_array_value_priv(bool raw, bool can_sleep, ...@@ -1471,7 +1752,7 @@ static void gpiod_set_array_value_priv(bool raw, bool can_sleep,
int i = 0; int i = 0;
while (i < array_size) { while (i < array_size) {
struct gpio_chip *chip = desc_array[i]->chip; struct gpio_chip *chip = desc_array[i]->gdev->chip;
unsigned long mask[BITS_TO_LONGS(chip->ngpio)]; unsigned long mask[BITS_TO_LONGS(chip->ngpio)];
unsigned long bits[BITS_TO_LONGS(chip->ngpio)]; unsigned long bits[BITS_TO_LONGS(chip->ngpio)];
int count = 0; int count = 0;
...@@ -1505,7 +1786,8 @@ static void gpiod_set_array_value_priv(bool raw, bool can_sleep, ...@@ -1505,7 +1786,8 @@ static void gpiod_set_array_value_priv(bool raw, bool can_sleep,
count++; count++;
} }
i++; i++;
} while ((i < array_size) && (desc_array[i]->chip == chip)); } while ((i < array_size) &&
(desc_array[i]->gdev->chip == chip));
/* push collected bits to outputs */ /* push collected bits to outputs */
if (count != 0) if (count != 0)
gpio_chip_set_multiple(chip, mask, bits); gpio_chip_set_multiple(chip, mask, bits);
...@@ -1525,10 +1807,9 @@ static void gpiod_set_array_value_priv(bool raw, bool can_sleep, ...@@ -1525,10 +1807,9 @@ static void gpiod_set_array_value_priv(bool raw, bool can_sleep,
*/ */
void gpiod_set_raw_value(struct gpio_desc *desc, int value) void gpiod_set_raw_value(struct gpio_desc *desc, int value)
{ {
if (!desc) VALIDATE_DESC_VOID(desc);
return;
/* Should be using gpio_set_value_cansleep() */ /* Should be using gpio_set_value_cansleep() */
WARN_ON(desc->chip->can_sleep); WARN_ON(desc->gdev->chip->can_sleep);
_gpiod_set_raw_value(desc, value); _gpiod_set_raw_value(desc, value);
} }
EXPORT_SYMBOL_GPL(gpiod_set_raw_value); EXPORT_SYMBOL_GPL(gpiod_set_raw_value);
...@@ -1546,10 +1827,9 @@ EXPORT_SYMBOL_GPL(gpiod_set_raw_value); ...@@ -1546,10 +1827,9 @@ EXPORT_SYMBOL_GPL(gpiod_set_raw_value);
*/ */
void gpiod_set_value(struct gpio_desc *desc, int value) void gpiod_set_value(struct gpio_desc *desc, int value)
{ {
if (!desc) VALIDATE_DESC_VOID(desc);
return;
/* Should be using gpio_set_value_cansleep() */ /* Should be using gpio_set_value_cansleep() */
WARN_ON(desc->chip->can_sleep); WARN_ON(desc->gdev->chip->can_sleep);
if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
value = !value; value = !value;
_gpiod_set_raw_value(desc, value); _gpiod_set_raw_value(desc, value);
...@@ -1607,9 +1887,8 @@ EXPORT_SYMBOL_GPL(gpiod_set_array_value); ...@@ -1607,9 +1887,8 @@ EXPORT_SYMBOL_GPL(gpiod_set_array_value);
*/ */
int gpiod_cansleep(const struct gpio_desc *desc) int gpiod_cansleep(const struct gpio_desc *desc)
{ {
if (!desc) VALIDATE_DESC(desc);
return 0; return desc->gdev->chip->can_sleep;
return desc->chip->can_sleep;
} }
EXPORT_SYMBOL_GPL(gpiod_cansleep); EXPORT_SYMBOL_GPL(gpiod_cansleep);
...@@ -1625,9 +1904,8 @@ int gpiod_to_irq(const struct gpio_desc *desc) ...@@ -1625,9 +1904,8 @@ int gpiod_to_irq(const struct gpio_desc *desc)
struct gpio_chip *chip; struct gpio_chip *chip;
int offset; int offset;
if (!desc) VALIDATE_DESC(desc);
return -EINVAL; chip = desc->gdev->chip;
chip = desc->chip;
offset = gpio_chip_hwgpio(desc); offset = gpio_chip_hwgpio(desc);
return chip->to_irq ? chip->to_irq(chip, offset) : -ENXIO; return chip->to_irq ? chip->to_irq(chip, offset) : -ENXIO;
} }
...@@ -1646,14 +1924,14 @@ int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset) ...@@ -1646,14 +1924,14 @@ int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset)
if (offset >= chip->ngpio) if (offset >= chip->ngpio)
return -EINVAL; return -EINVAL;
if (test_bit(FLAG_IS_OUT, &chip->desc[offset].flags)) { if (test_bit(FLAG_IS_OUT, &chip->gpiodev->descs[offset].flags)) {
chip_err(chip, chip_err(chip,
"%s: tried to flag a GPIO set as output for IRQ\n", "%s: tried to flag a GPIO set as output for IRQ\n",
__func__); __func__);
return -EIO; return -EIO;
} }
set_bit(FLAG_USED_AS_IRQ, &chip->desc[offset].flags); set_bit(FLAG_USED_AS_IRQ, &chip->gpiodev->descs[offset].flags);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(gpiochip_lock_as_irq); EXPORT_SYMBOL_GPL(gpiochip_lock_as_irq);
...@@ -1671,10 +1949,37 @@ void gpiochip_unlock_as_irq(struct gpio_chip *chip, unsigned int offset) ...@@ -1671,10 +1949,37 @@ void gpiochip_unlock_as_irq(struct gpio_chip *chip, unsigned int offset)
if (offset >= chip->ngpio) if (offset >= chip->ngpio)
return; return;
clear_bit(FLAG_USED_AS_IRQ, &chip->desc[offset].flags); clear_bit(FLAG_USED_AS_IRQ, &chip->gpiodev->descs[offset].flags);
} }
EXPORT_SYMBOL_GPL(gpiochip_unlock_as_irq); EXPORT_SYMBOL_GPL(gpiochip_unlock_as_irq);
bool gpiochip_line_is_irq(struct gpio_chip *chip, unsigned int offset)
{
if (offset >= chip->ngpio)
return false;
return test_bit(FLAG_USED_AS_IRQ, &chip->gpiodev->descs[offset].flags);
}
EXPORT_SYMBOL_GPL(gpiochip_line_is_irq);
bool gpiochip_line_is_open_drain(struct gpio_chip *chip, unsigned int offset)
{
if (offset >= chip->ngpio)
return false;
return test_bit(FLAG_OPEN_DRAIN, &chip->gpiodev->descs[offset].flags);
}
EXPORT_SYMBOL_GPL(gpiochip_line_is_open_drain);
bool gpiochip_line_is_open_source(struct gpio_chip *chip, unsigned int offset)
{
if (offset >= chip->ngpio)
return false;
return test_bit(FLAG_OPEN_SOURCE, &chip->gpiodev->descs[offset].flags);
}
EXPORT_SYMBOL_GPL(gpiochip_line_is_open_source);
/** /**
* gpiod_get_raw_value_cansleep() - return a gpio's raw value * gpiod_get_raw_value_cansleep() - return a gpio's raw value
* @desc: gpio whose value will be returned * @desc: gpio whose value will be returned
...@@ -1687,8 +1992,7 @@ EXPORT_SYMBOL_GPL(gpiochip_unlock_as_irq); ...@@ -1687,8 +1992,7 @@ EXPORT_SYMBOL_GPL(gpiochip_unlock_as_irq);
int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc) int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc)
{ {
might_sleep_if(extra_checks); might_sleep_if(extra_checks);
if (!desc) VALIDATE_DESC(desc);
return 0;
return _gpiod_get_raw_value(desc); return _gpiod_get_raw_value(desc);
} }
EXPORT_SYMBOL_GPL(gpiod_get_raw_value_cansleep); EXPORT_SYMBOL_GPL(gpiod_get_raw_value_cansleep);
...@@ -1707,9 +2011,7 @@ int gpiod_get_value_cansleep(const struct gpio_desc *desc) ...@@ -1707,9 +2011,7 @@ int gpiod_get_value_cansleep(const struct gpio_desc *desc)
int value; int value;
might_sleep_if(extra_checks); might_sleep_if(extra_checks);
if (!desc) VALIDATE_DESC(desc);
return 0;
value = _gpiod_get_raw_value(desc); value = _gpiod_get_raw_value(desc);
if (value < 0) if (value < 0)
return value; return value;
...@@ -1734,8 +2036,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_value_cansleep); ...@@ -1734,8 +2036,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_value_cansleep);
void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value) void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value)
{ {
might_sleep_if(extra_checks); might_sleep_if(extra_checks);
if (!desc) VALIDATE_DESC_VOID(desc);
return;
_gpiod_set_raw_value(desc, value); _gpiod_set_raw_value(desc, value);
} }
EXPORT_SYMBOL_GPL(gpiod_set_raw_value_cansleep); EXPORT_SYMBOL_GPL(gpiod_set_raw_value_cansleep);
...@@ -1753,9 +2054,7 @@ EXPORT_SYMBOL_GPL(gpiod_set_raw_value_cansleep); ...@@ -1753,9 +2054,7 @@ EXPORT_SYMBOL_GPL(gpiod_set_raw_value_cansleep);
void gpiod_set_value_cansleep(struct gpio_desc *desc, int value) void gpiod_set_value_cansleep(struct gpio_desc *desc, int value)
{ {
might_sleep_if(extra_checks); might_sleep_if(extra_checks);
if (!desc) VALIDATE_DESC_VOID(desc);
return;
if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
value = !value; value = !value;
_gpiod_set_raw_value(desc, value); _gpiod_set_raw_value(desc, value);
...@@ -2358,8 +2657,8 @@ static void gpiochip_free_hogs(struct gpio_chip *chip) ...@@ -2358,8 +2657,8 @@ static void gpiochip_free_hogs(struct gpio_chip *chip)
int id; int id;
for (id = 0; id < chip->ngpio; id++) { for (id = 0; id < chip->ngpio; id++) {
if (test_bit(FLAG_IS_HOGGED, &chip->desc[id].flags)) if (test_bit(FLAG_IS_HOGGED, &chip->gpiodev->descs[id].flags))
gpiochip_free_own_desc(&chip->desc[id]); gpiochip_free_own_desc(&chip->gpiodev->descs[id]);
} }
} }
...@@ -2456,17 +2755,38 @@ void gpiod_put_array(struct gpio_descs *descs) ...@@ -2456,17 +2755,38 @@ void gpiod_put_array(struct gpio_descs *descs)
} }
EXPORT_SYMBOL_GPL(gpiod_put_array); EXPORT_SYMBOL_GPL(gpiod_put_array);
static int __init gpiolib_dev_init(void)
{
int ret;
/* Register GPIO sysfs bus */
ret = bus_register(&gpio_bus_type);
if (ret < 0) {
pr_err("gpiolib: could not register GPIO bus type\n");
return ret;
}
ret = alloc_chrdev_region(&gpio_devt, 0, GPIO_DEV_MAX, "gpiochip");
if (ret < 0) {
pr_err("gpiolib: failed to allocate char dev region\n");
bus_unregister(&gpio_bus_type);
}
return ret;
}
core_initcall(gpiolib_dev_init);
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip) static void gpiolib_dbg_show(struct seq_file *s, struct gpio_device *gdev)
{ {
unsigned i; unsigned i;
unsigned gpio = chip->base; struct gpio_chip *chip = gdev->chip;
struct gpio_desc *gdesc = &chip->desc[0]; unsigned gpio = gdev->base;
struct gpio_desc *gdesc = &gdev->descs[0];
int is_out; int is_out;
int is_irq; int is_irq;
for (i = 0; i < chip->ngpio; i++, gpio++, gdesc++) { for (i = 0; i < gdev->ngpio; i++, gpio++, gdesc++) {
if (!test_bit(FLAG_REQUESTED, &gdesc->flags)) { if (!test_bit(FLAG_REQUESTED, &gdesc->flags)) {
if (gdesc->name) { if (gdesc->name) {
seq_printf(s, " gpio-%-3d (%-20.20s)\n", seq_printf(s, " gpio-%-3d (%-20.20s)\n",
...@@ -2492,16 +2812,16 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip) ...@@ -2492,16 +2812,16 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip)
static void *gpiolib_seq_start(struct seq_file *s, loff_t *pos) static void *gpiolib_seq_start(struct seq_file *s, loff_t *pos)
{ {
unsigned long flags; unsigned long flags;
struct gpio_chip *chip = NULL; struct gpio_device *gdev = NULL;
loff_t index = *pos; loff_t index = *pos;
s->private = ""; s->private = "";
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
list_for_each_entry(chip, &gpio_chips, list) list_for_each_entry(gdev, &gpio_devices, list)
if (index-- == 0) { if (index-- == 0) {
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
return chip; return gdev;
} }
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
...@@ -2511,14 +2831,14 @@ static void *gpiolib_seq_start(struct seq_file *s, loff_t *pos) ...@@ -2511,14 +2831,14 @@ static void *gpiolib_seq_start(struct seq_file *s, loff_t *pos)
static void *gpiolib_seq_next(struct seq_file *s, void *v, loff_t *pos) static void *gpiolib_seq_next(struct seq_file *s, void *v, loff_t *pos)
{ {
unsigned long flags; unsigned long flags;
struct gpio_chip *chip = v; struct gpio_device *gdev = v;
void *ret = NULL; void *ret = NULL;
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
if (list_is_last(&chip->list, &gpio_chips)) if (list_is_last(&gdev->list, &gpio_devices))
ret = NULL; ret = NULL;
else else
ret = list_entry(chip->list.next, struct gpio_chip, list); ret = list_entry(gdev->list.next, struct gpio_device, list);
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
s->private = "\n"; s->private = "\n";
...@@ -2533,15 +2853,24 @@ static void gpiolib_seq_stop(struct seq_file *s, void *v) ...@@ -2533,15 +2853,24 @@ static void gpiolib_seq_stop(struct seq_file *s, void *v)
static int gpiolib_seq_show(struct seq_file *s, void *v) static int gpiolib_seq_show(struct seq_file *s, void *v)
{ {
struct gpio_chip *chip = v; struct gpio_device *gdev = v;
struct device *dev; struct gpio_chip *chip = gdev->chip;
struct device *parent;
if (!chip) {
seq_printf(s, "%s%s: (dangling chip)", (char *)s->private,
dev_name(&gdev->dev));
return 0;
}
seq_printf(s, "%sGPIOs %d-%d", (char *)s->private, seq_printf(s, "%s%s: GPIOs %d-%d", (char *)s->private,
chip->base, chip->base + chip->ngpio - 1); dev_name(&gdev->dev),
dev = chip->parent; gdev->base, gdev->base + gdev->ngpio - 1);
if (dev) parent = chip->parent;
seq_printf(s, ", %s/%s", dev->bus ? dev->bus->name : "no-bus", if (parent)
dev_name(dev)); seq_printf(s, ", parent: %s/%s",
parent->bus ? parent->bus->name : "no-bus",
dev_name(parent));
if (chip->label) if (chip->label)
seq_printf(s, ", %s", chip->label); seq_printf(s, ", %s", chip->label);
if (chip->can_sleep) if (chip->can_sleep)
...@@ -2551,7 +2880,7 @@ static int gpiolib_seq_show(struct seq_file *s, void *v) ...@@ -2551,7 +2880,7 @@ static int gpiolib_seq_show(struct seq_file *s, void *v)
if (chip->dbg_show) if (chip->dbg_show)
chip->dbg_show(s, chip); chip->dbg_show(s, chip);
else else
gpiolib_dbg_show(s, chip); gpiolib_dbg_show(s, gdev);
return 0; return 0;
} }
......
...@@ -12,13 +12,66 @@ ...@@ -12,13 +12,66 @@
#ifndef GPIOLIB_H #ifndef GPIOLIB_H
#define GPIOLIB_H #define GPIOLIB_H
#include <linux/gpio/driver.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/module.h>
#include <linux/cdev.h>
enum of_gpio_flags; enum of_gpio_flags;
enum gpiod_flags; enum gpiod_flags;
struct acpi_device; struct acpi_device;
/**
* struct gpio_device - internal state container for GPIO devices
* @id: numerical ID number for the GPIO chip
* @dev: the GPIO device struct
* @chrdev: character device for the GPIO device
* @mockdev: class device used by the deprecated sysfs interface (may be
* NULL)
* @owner: helps prevent removal of modules exporting active GPIOs
* @chip: pointer to the corresponding gpiochip, holding static
* data for this device
* @descs: array of ngpio descriptors.
* @ngpio: the number of GPIO lines on this GPIO device, equal to the size
* of the @descs array.
* @base: GPIO base in the DEPRECATED global Linux GPIO numberspace, assigned
* at device creation time.
* @label: a descriptive name for the GPIO device, such as the part number
* or name of the IP component in a System on Chip.
* @data: per-instance data assigned by the driver
* @list: links gpio_device:s together for traversal
*
* This state container holds most of the runtime variable data
* for a GPIO device and can hold references and live on after the
* GPIO chip has been removed, if it is still being used from
* userspace.
*/
struct gpio_device {
int id;
struct device dev;
struct cdev chrdev;
struct device *mockdev;
struct module *owner;
struct gpio_chip *chip;
struct gpio_desc *descs;
int base;
u16 ngpio;
char *label;
void *data;
struct list_head list;
#ifdef CONFIG_PINCTRL
/*
* If CONFIG_PINCTRL is enabled, then gpio controllers can optionally
* describe the actual pin range which they serve in an SoC. This
* information would be used by pinctrl subsystem to configure
* corresponding pins for gpio usage.
*/
struct list_head pin_ranges;
#endif
};
/** /**
* struct acpi_gpio_info - ACPI GPIO specific information * struct acpi_gpio_info - ACPI GPIO specific information
* @gpioint: if %true this GPIO is of type GpioInt otherwise type is GpioIo * @gpioint: if %true this GPIO is of type GpioInt otherwise type is GpioIo
...@@ -90,10 +143,10 @@ struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np, ...@@ -90,10 +143,10 @@ struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip, u16 hwnum); struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip, u16 hwnum);
extern struct spinlock gpio_lock; extern struct spinlock gpio_lock;
extern struct list_head gpio_chips; extern struct list_head gpio_devices;
struct gpio_desc { struct gpio_desc {
struct gpio_chip *chip; struct gpio_device *gdev;
unsigned long flags; unsigned long flags;
/* flag symbols are bit numbers */ /* flag symbols are bit numbers */
#define FLAG_REQUESTED 0 #define FLAG_REQUESTED 0
...@@ -122,7 +175,7 @@ int gpiod_hog(struct gpio_desc *desc, const char *name, ...@@ -122,7 +175,7 @@ int gpiod_hog(struct gpio_desc *desc, const char *name,
*/ */
static int __maybe_unused gpio_chip_hwgpio(const struct gpio_desc *desc) static int __maybe_unused gpio_chip_hwgpio(const struct gpio_desc *desc)
{ {
return desc - &desc->chip->desc[0]; return desc - &desc->gdev->descs[0];
} }
/* With descriptor prefix */ /* With descriptor prefix */
...@@ -149,31 +202,31 @@ static int __maybe_unused gpio_chip_hwgpio(const struct gpio_desc *desc) ...@@ -149,31 +202,31 @@ static int __maybe_unused gpio_chip_hwgpio(const struct gpio_desc *desc)
/* With chip prefix */ /* With chip prefix */
#define chip_emerg(chip, fmt, ...) \ #define chip_emerg(chip, fmt, ...) \
pr_emerg("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__) dev_emerg(&chip->gpiodev->dev, "(%s): " fmt, chip->label, ##__VA_ARGS__)
#define chip_crit(chip, fmt, ...) \ #define chip_crit(chip, fmt, ...) \
pr_crit("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__) dev_crit(&chip->gpiodev->dev, "(%s): " fmt, chip->label, ##__VA_ARGS__)
#define chip_err(chip, fmt, ...) \ #define chip_err(chip, fmt, ...) \
pr_err("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__) dev_err(&chip->gpiodev->dev, "(%s): " fmt, chip->label, ##__VA_ARGS__)
#define chip_warn(chip, fmt, ...) \ #define chip_warn(chip, fmt, ...) \
pr_warn("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__) dev_warn(&chip->gpiodev->dev, "(%s): " fmt, chip->label, ##__VA_ARGS__)
#define chip_info(chip, fmt, ...) \ #define chip_info(chip, fmt, ...) \
pr_info("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__) dev_info(&chip->gpiodev->dev, "(%s): " fmt, chip->label, ##__VA_ARGS__)
#define chip_dbg(chip, fmt, ...) \ #define chip_dbg(chip, fmt, ...) \
pr_debug("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__) dev_dbg(&chip->gpiodev->dev, "(%s): " fmt, chip->label, ##__VA_ARGS__)
#ifdef CONFIG_GPIO_SYSFS #ifdef CONFIG_GPIO_SYSFS
int gpiochip_sysfs_register(struct gpio_chip *chip); int gpiochip_sysfs_register(struct gpio_device *gdev);
void gpiochip_sysfs_unregister(struct gpio_chip *chip); void gpiochip_sysfs_unregister(struct gpio_device *gdev);
#else #else
static inline int gpiochip_sysfs_register(struct gpio_chip *chip) static inline int gpiochip_sysfs_register(struct gpio_device *gdev)
{ {
return 0; return 0;
} }
static inline void gpiochip_sysfs_unregister(struct gpio_chip *chip) static inline void gpiochip_sysfs_unregister(struct gpio_device *gdev)
{ {
} }
......
...@@ -42,10 +42,10 @@ ...@@ -42,10 +42,10 @@
#include <linux/bcd.h> #include <linux/bcd.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/mfd/menelaus.h> #include <linux/mfd/menelaus.h>
#include <linux/gpio.h>
#include <asm/mach/irq.h> #include <asm/mach/irq.h>
#include <asm/gpio.h>
#define DRIVER_NAME "menelaus" #define DRIVER_NAME "menelaus"
......
...@@ -35,10 +35,10 @@ ...@@ -35,10 +35,10 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/gpio.h>
#include <asm/mach/flash.h> #include <asm/mach/flash.h>
#include <linux/platform_data/mtd-onenand-omap2.h> #include <linux/platform_data/mtd-onenand-omap2.h>
#include <asm/gpio.h>
#include <linux/omap-dma.h> #include <linux/omap-dma.h>
......
...@@ -36,10 +36,10 @@ ...@@ -36,10 +36,10 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/gpio.h>
#include <pcmcia/ss.h> #include <pcmcia/ss.h>
#include <pcmcia/cisreg.h> #include <pcmcia/cisreg.h>
#include <asm/gpio.h>
#define SZ_1K 0x00000400 #define SZ_1K 0x00000400
#define SZ_8K 0x00002000 #define SZ_8K 0x00002000
......
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
#include <asm/mach-types.h> #include <asm/mach-types.h>
#include <asm/gpio.h>
#include <mach/vpac270.h> #include <mach/vpac270.h>
#include "soc_common.h" #include "soc_common.h"
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/gpio.h> #include <linux/gpio/driver.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
...@@ -98,11 +98,6 @@ struct iproc_gpio { ...@@ -98,11 +98,6 @@ struct iproc_gpio {
struct pinctrl_desc pctldesc; struct pinctrl_desc pctldesc;
}; };
static inline struct iproc_gpio *to_iproc_gpio(struct gpio_chip *gc)
{
return container_of(gc, struct iproc_gpio, gc);
}
/* /*
* Mapping from PINCONF pins to GPIO pins is 1-to-1 * Mapping from PINCONF pins to GPIO pins is 1-to-1
*/ */
...@@ -147,7 +142,7 @@ static inline bool iproc_get_bit(struct iproc_gpio *chip, unsigned int reg, ...@@ -147,7 +142,7 @@ static inline bool iproc_get_bit(struct iproc_gpio *chip, unsigned int reg,
static void iproc_gpio_irq_handler(struct irq_desc *desc) static void iproc_gpio_irq_handler(struct irq_desc *desc)
{ {
struct gpio_chip *gc = irq_desc_get_handler_data(desc); struct gpio_chip *gc = irq_desc_get_handler_data(desc);
struct iproc_gpio *chip = to_iproc_gpio(gc); struct iproc_gpio *chip = gpiochip_get_data(gc);
struct irq_chip *irq_chip = irq_desc_get_chip(desc); struct irq_chip *irq_chip = irq_desc_get_chip(desc);
int i, bit; int i, bit;
...@@ -180,7 +175,7 @@ static void iproc_gpio_irq_handler(struct irq_desc *desc) ...@@ -180,7 +175,7 @@ static void iproc_gpio_irq_handler(struct irq_desc *desc)
static void iproc_gpio_irq_ack(struct irq_data *d) static void iproc_gpio_irq_ack(struct irq_data *d)
{ {
struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct iproc_gpio *chip = to_iproc_gpio(gc); struct iproc_gpio *chip = gpiochip_get_data(gc);
unsigned gpio = d->hwirq; unsigned gpio = d->hwirq;
unsigned int offset = IPROC_GPIO_REG(gpio, unsigned int offset = IPROC_GPIO_REG(gpio,
IPROC_GPIO_INT_CLR_OFFSET); IPROC_GPIO_INT_CLR_OFFSET);
...@@ -199,7 +194,7 @@ static void iproc_gpio_irq_ack(struct irq_data *d) ...@@ -199,7 +194,7 @@ static void iproc_gpio_irq_ack(struct irq_data *d)
static void iproc_gpio_irq_set_mask(struct irq_data *d, bool unmask) static void iproc_gpio_irq_set_mask(struct irq_data *d, bool unmask)
{ {
struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct iproc_gpio *chip = to_iproc_gpio(gc); struct iproc_gpio *chip = gpiochip_get_data(gc);
unsigned gpio = d->hwirq; unsigned gpio = d->hwirq;
iproc_set_bit(chip, IPROC_GPIO_INT_MSK_OFFSET, gpio, unmask); iproc_set_bit(chip, IPROC_GPIO_INT_MSK_OFFSET, gpio, unmask);
...@@ -208,7 +203,7 @@ static void iproc_gpio_irq_set_mask(struct irq_data *d, bool unmask) ...@@ -208,7 +203,7 @@ static void iproc_gpio_irq_set_mask(struct irq_data *d, bool unmask)
static void iproc_gpio_irq_mask(struct irq_data *d) static void iproc_gpio_irq_mask(struct irq_data *d)
{ {
struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct iproc_gpio *chip = to_iproc_gpio(gc); struct iproc_gpio *chip = gpiochip_get_data(gc);
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&chip->lock, flags); spin_lock_irqsave(&chip->lock, flags);
...@@ -219,7 +214,7 @@ static void iproc_gpio_irq_mask(struct irq_data *d) ...@@ -219,7 +214,7 @@ static void iproc_gpio_irq_mask(struct irq_data *d)
static void iproc_gpio_irq_unmask(struct irq_data *d) static void iproc_gpio_irq_unmask(struct irq_data *d)
{ {
struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct iproc_gpio *chip = to_iproc_gpio(gc); struct iproc_gpio *chip = gpiochip_get_data(gc);
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&chip->lock, flags); spin_lock_irqsave(&chip->lock, flags);
...@@ -230,7 +225,7 @@ static void iproc_gpio_irq_unmask(struct irq_data *d) ...@@ -230,7 +225,7 @@ static void iproc_gpio_irq_unmask(struct irq_data *d)
static int iproc_gpio_irq_set_type(struct irq_data *d, unsigned int type) static int iproc_gpio_irq_set_type(struct irq_data *d, unsigned int type)
{ {
struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct iproc_gpio *chip = to_iproc_gpio(gc); struct iproc_gpio *chip = gpiochip_get_data(gc);
unsigned gpio = d->hwirq; unsigned gpio = d->hwirq;
bool level_triggered = false; bool level_triggered = false;
bool dual_edge = false; bool dual_edge = false;
...@@ -292,7 +287,7 @@ static struct irq_chip iproc_gpio_irq_chip = { ...@@ -292,7 +287,7 @@ static struct irq_chip iproc_gpio_irq_chip = {
*/ */
static int iproc_gpio_request(struct gpio_chip *gc, unsigned offset) static int iproc_gpio_request(struct gpio_chip *gc, unsigned offset)
{ {
struct iproc_gpio *chip = to_iproc_gpio(gc); struct iproc_gpio *chip = gpiochip_get_data(gc);
unsigned gpio = gc->base + offset; unsigned gpio = gc->base + offset;
/* not all Iproc GPIO pins can be muxed individually */ /* not all Iproc GPIO pins can be muxed individually */
...@@ -304,7 +299,7 @@ static int iproc_gpio_request(struct gpio_chip *gc, unsigned offset) ...@@ -304,7 +299,7 @@ static int iproc_gpio_request(struct gpio_chip *gc, unsigned offset)
static void iproc_gpio_free(struct gpio_chip *gc, unsigned offset) static void iproc_gpio_free(struct gpio_chip *gc, unsigned offset)
{ {
struct iproc_gpio *chip = to_iproc_gpio(gc); struct iproc_gpio *chip = gpiochip_get_data(gc);
unsigned gpio = gc->base + offset; unsigned gpio = gc->base + offset;
if (!chip->pinmux_is_supported) if (!chip->pinmux_is_supported)
...@@ -315,7 +310,7 @@ static void iproc_gpio_free(struct gpio_chip *gc, unsigned offset) ...@@ -315,7 +310,7 @@ static void iproc_gpio_free(struct gpio_chip *gc, unsigned offset)
static int iproc_gpio_direction_input(struct gpio_chip *gc, unsigned gpio) static int iproc_gpio_direction_input(struct gpio_chip *gc, unsigned gpio)
{ {
struct iproc_gpio *chip = to_iproc_gpio(gc); struct iproc_gpio *chip = gpiochip_get_data(gc);
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&chip->lock, flags); spin_lock_irqsave(&chip->lock, flags);
...@@ -330,7 +325,7 @@ static int iproc_gpio_direction_input(struct gpio_chip *gc, unsigned gpio) ...@@ -330,7 +325,7 @@ static int iproc_gpio_direction_input(struct gpio_chip *gc, unsigned gpio)
static int iproc_gpio_direction_output(struct gpio_chip *gc, unsigned gpio, static int iproc_gpio_direction_output(struct gpio_chip *gc, unsigned gpio,
int val) int val)
{ {
struct iproc_gpio *chip = to_iproc_gpio(gc); struct iproc_gpio *chip = gpiochip_get_data(gc);
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&chip->lock, flags); spin_lock_irqsave(&chip->lock, flags);
...@@ -345,7 +340,7 @@ static int iproc_gpio_direction_output(struct gpio_chip *gc, unsigned gpio, ...@@ -345,7 +340,7 @@ static int iproc_gpio_direction_output(struct gpio_chip *gc, unsigned gpio,
static void iproc_gpio_set(struct gpio_chip *gc, unsigned gpio, int val) static void iproc_gpio_set(struct gpio_chip *gc, unsigned gpio, int val)
{ {
struct iproc_gpio *chip = to_iproc_gpio(gc); struct iproc_gpio *chip = gpiochip_get_data(gc);
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&chip->lock, flags); spin_lock_irqsave(&chip->lock, flags);
...@@ -357,7 +352,7 @@ static void iproc_gpio_set(struct gpio_chip *gc, unsigned gpio, int val) ...@@ -357,7 +352,7 @@ static void iproc_gpio_set(struct gpio_chip *gc, unsigned gpio, int val)
static int iproc_gpio_get(struct gpio_chip *gc, unsigned gpio) static int iproc_gpio_get(struct gpio_chip *gc, unsigned gpio)
{ {
struct iproc_gpio *chip = to_iproc_gpio(gc); struct iproc_gpio *chip = gpiochip_get_data(gc);
unsigned int offset = IPROC_GPIO_REG(gpio, unsigned int offset = IPROC_GPIO_REG(gpio,
IPROC_GPIO_DATA_IN_OFFSET); IPROC_GPIO_DATA_IN_OFFSET);
unsigned int shift = IPROC_GPIO_SHIFT(gpio); unsigned int shift = IPROC_GPIO_SHIFT(gpio);
...@@ -706,7 +701,7 @@ static int iproc_gpio_probe(struct platform_device *pdev) ...@@ -706,7 +701,7 @@ static int iproc_gpio_probe(struct platform_device *pdev)
chip->pinmux_is_supported = of_property_read_bool(dev->of_node, chip->pinmux_is_supported = of_property_read_bool(dev->of_node,
"gpio-ranges"); "gpio-ranges");
ret = gpiochip_add(gc); ret = gpiochip_add_data(gc, chip);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "unable to add GPIO chip\n"); dev_err(dev, "unable to add GPIO chip\n");
return ret; return ret;
......
...@@ -338,7 +338,6 @@ struct atlas7_pinctrl_data { ...@@ -338,7 +338,6 @@ struct atlas7_pinctrl_data {
#define ATLAS7_GPIO_CTL_DATAIN_MASK BIT(7) #define ATLAS7_GPIO_CTL_DATAIN_MASK BIT(7)
struct atlas7_gpio_bank { struct atlas7_gpio_bank {
struct pinctrl_dev *pctldev;
int id; int id;
int irq; int irq;
void __iomem *base; void __iomem *base;
...@@ -6070,7 +6069,6 @@ static int atlas7_gpio_probe(struct platform_device *pdev) ...@@ -6070,7 +6069,6 @@ static int atlas7_gpio_probe(struct platform_device *pdev)
} }
for (idx = 0; idx < nbank; idx++) { for (idx = 0; idx < nbank; idx++) {
struct gpio_pin_range *pin_range;
struct atlas7_gpio_bank *bank; struct atlas7_gpio_bank *bank;
bank = &a7gc->banks[idx]; bank = &a7gc->banks[idx];
...@@ -6088,22 +6086,6 @@ static int atlas7_gpio_probe(struct platform_device *pdev) ...@@ -6088,22 +6086,6 @@ static int atlas7_gpio_probe(struct platform_device *pdev)
gpiochip_set_chained_irqchip(chip, &atlas7_gpio_irq_chip, gpiochip_set_chained_irqchip(chip, &atlas7_gpio_irq_chip,
bank->irq, atlas7_gpio_handle_irq); bank->irq, atlas7_gpio_handle_irq);
/* Records gpio_pin_range to a7gc */
list_for_each_entry(pin_range, &chip->pin_ranges, node) {
struct pinctrl_gpio_range *range;
range = &pin_range->range;
if (range->id == NGPIO_OF_BANK * idx) {
bank->gpio_offset = range->id;
bank->ngpio = range->npins;
bank->gpio_pins = range->pins;
bank->pctldev = pin_range->pctldev;
break;
}
}
BUG_ON(!bank->pctldev);
} }
platform_set_drvdata(pdev, a7gc); platform_set_drvdata(pdev, a7gc);
......
...@@ -457,8 +457,8 @@ static int sunxi_pinctrl_gpio_get(struct gpio_chip *chip, unsigned offset) ...@@ -457,8 +457,8 @@ static int sunxi_pinctrl_gpio_get(struct gpio_chip *chip, unsigned offset)
struct sunxi_pinctrl *pctl = gpiochip_get_data(chip); struct sunxi_pinctrl *pctl = gpiochip_get_data(chip);
u32 reg = sunxi_data_reg(offset); u32 reg = sunxi_data_reg(offset);
u8 index = sunxi_data_offset(offset); u8 index = sunxi_data_offset(offset);
u32 set_mux = pctl->desc->irq_read_needs_mux && bool set_mux = pctl->desc->irq_read_needs_mux &&
test_bit(FLAG_USED_AS_IRQ, &chip->desc[offset].flags); gpiochip_line_is_irq(chip, offset);
u32 val; u32 val;
if (set_mux) if (set_mux)
......
...@@ -63,7 +63,7 @@ static int qe_gpio_get(struct gpio_chip *gc, unsigned int gpio) ...@@ -63,7 +63,7 @@ static int qe_gpio_get(struct gpio_chip *gc, unsigned int gpio)
struct qe_pio_regs __iomem *regs = mm_gc->regs; struct qe_pio_regs __iomem *regs = mm_gc->regs;
u32 pin_mask = 1 << (QE_PIO_PINS - 1 - gpio); u32 pin_mask = 1 << (QE_PIO_PINS - 1 - gpio);
return in_be32(&regs->cpdata) & pin_mask; return !!(in_be32(&regs->cpdata) & pin_mask);
} }
static void qe_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) static void qe_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
......
...@@ -25,8 +25,6 @@ ...@@ -25,8 +25,6 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_gpio.h> #include <linux/of_gpio.h>
#include <asm/gpio.h>
#include "atmel_usba_udc.h" #include "atmel_usba_udc.h"
#ifdef CONFIG_USB_GADGET_DEBUG_FS #ifdef CONFIG_USB_GADGET_DEBUG_FS
......
...@@ -24,8 +24,6 @@ ...@@ -24,8 +24,6 @@
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/usb/hcd.h> #include <linux/usb/hcd.h>
#include <asm/gpio.h>
#include "ohci.h" #include "ohci.h"
#define valid_port(index) ((index) >= 0 && (index) < AT91_MAX_USBH_PORTS) #define valid_port(index) ((index) >= 0 && (index) < AT91_MAX_USBH_PORTS)
......
...@@ -26,8 +26,6 @@ ...@@ -26,8 +26,6 @@
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <video/videomode.h> #include <video/videomode.h>
#include <asm/gpio.h>
#include <video/atmel_lcdc.h> #include <video/atmel_lcdc.h>
struct atmel_lcdfb_config { struct atmel_lcdfb_config {
......
...@@ -22,8 +22,8 @@ ...@@ -22,8 +22,8 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/i2c/tps65010.h> #include <linux/i2c/tps65010.h>
#include <linux/gpio.h>
#include <asm/gpio.h>
#include "omapfb.h" #include "omapfb.h"
#define MODULE_NAME "omapfb-lcd_h3" #define MODULE_NAME "omapfb-lcd_h3"
......
...@@ -22,8 +22,7 @@ ...@@ -22,8 +22,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/gpio.h>
#include <asm/gpio.h>
#include <mach/hardware.h> #include <mach/hardware.h>
#include <mach/mux.h> #include <mach/mux.h>
......
...@@ -28,8 +28,8 @@ GPIO13 - screen blanking ...@@ -28,8 +28,8 @@ GPIO13 - screen blanking
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/gpio.h>
#include <asm/gpio.h>
#include "omapfb.h" #include "omapfb.h"
static int palmtt_panel_init(struct lcd_panel *panel, static int palmtt_panel_init(struct lcd_panel *panel,
......
...@@ -26,8 +26,12 @@ ...@@ -26,8 +26,12 @@
*/ */
#ifndef ARCH_NR_GPIOS #ifndef ARCH_NR_GPIOS
#if defined(CONFIG_ARCH_NR_GPIO) && CONFIG_ARCH_NR_GPIO > 0
#define ARCH_NR_GPIOS CONFIG_ARCH_NR_GPIO
#else
#define ARCH_NR_GPIOS 512 #define ARCH_NR_GPIOS 512
#endif #endif
#endif
/* /*
* "valid" GPIO numbers are nonnegative and may be passed to * "valid" GPIO numbers are nonnegative and may be passed to
......
#ifndef __LINUX_GPIO_DRIVER_H #ifndef __LINUX_GPIO_DRIVER_H
#define __LINUX_GPIO_DRIVER_H #define __LINUX_GPIO_DRIVER_H
#include <linux/device.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/irq.h> #include <linux/irq.h>
...@@ -10,22 +11,21 @@ ...@@ -10,22 +11,21 @@
#include <linux/pinctrl/pinctrl.h> #include <linux/pinctrl/pinctrl.h>
#include <linux/kconfig.h> #include <linux/kconfig.h>
struct device;
struct gpio_desc; struct gpio_desc;
struct of_phandle_args; struct of_phandle_args;
struct device_node; struct device_node;
struct seq_file; struct seq_file;
struct gpio_device;
#ifdef CONFIG_GPIOLIB #ifdef CONFIG_GPIOLIB
/** /**
* struct gpio_chip - abstract a GPIO controller * struct gpio_chip - abstract a GPIO controller
* @label: for diagnostics * @label: a functional name for the GPIO device, such as a part
* number or the name of the SoC IP-block implementing it.
* @gpiodev: the internal state holder, opaque struct
* @parent: optional parent device providing the GPIOs * @parent: optional parent device providing the GPIOs
* @cdev: class device used by sysfs interface (may be NULL)
* @owner: helps prevent removal of modules exporting active GPIOs * @owner: helps prevent removal of modules exporting active GPIOs
* @data: per-instance data assigned by the driver
* @list: links gpio_chips together for traversal
* @request: optional hook for chip-specific activation, such as * @request: optional hook for chip-specific activation, such as
* enabling module power and clock; may sleep * enabling module power and clock; may sleep
* @free: optional hook for chip-specific deactivation, such as * @free: optional hook for chip-specific deactivation, such as
...@@ -52,7 +52,6 @@ struct seq_file; ...@@ -52,7 +52,6 @@ struct seq_file;
* get rid of the static GPIO number space in the long run. * get rid of the static GPIO number space in the long run.
* @ngpio: the number of GPIOs handled by this controller; the last GPIO * @ngpio: the number of GPIOs handled by this controller; the last GPIO
* handled is (base + ngpio - 1). * handled is (base + ngpio - 1).
* @desc: array of ngpio descriptors. Private.
* @names: if set, must be an array of strings to use as alternative * @names: if set, must be an array of strings to use as alternative
* names for the GPIOs in this chip. Any entry in the array * names for the GPIOs in this chip. Any entry in the array
* may be NULL if there is no alias for the GPIO, however the * may be NULL if there is no alias for the GPIO, however the
...@@ -107,11 +106,9 @@ struct seq_file; ...@@ -107,11 +106,9 @@ struct seq_file;
*/ */
struct gpio_chip { struct gpio_chip {
const char *label; const char *label;
struct gpio_device *gpiodev;
struct device *parent; struct device *parent;
struct device *cdev;
struct module *owner; struct module *owner;
void *data;
struct list_head list;
int (*request)(struct gpio_chip *chip, int (*request)(struct gpio_chip *chip,
unsigned offset); unsigned offset);
...@@ -141,7 +138,6 @@ struct gpio_chip { ...@@ -141,7 +138,6 @@ struct gpio_chip {
struct gpio_chip *chip); struct gpio_chip *chip);
int base; int base;
u16 ngpio; u16 ngpio;
struct gpio_desc *desc;
const char *const *names; const char *const *names;
bool can_sleep; bool can_sleep;
bool irq_not_threaded; bool irq_not_threaded;
...@@ -184,15 +180,6 @@ struct gpio_chip { ...@@ -184,15 +180,6 @@ struct gpio_chip {
int (*of_xlate)(struct gpio_chip *gc, int (*of_xlate)(struct gpio_chip *gc,
const struct of_phandle_args *gpiospec, u32 *flags); const struct of_phandle_args *gpiospec, u32 *flags);
#endif #endif
#ifdef CONFIG_PINCTRL
/*
* If CONFIG_PINCTRL is enabled, then gpio controllers can optionally
* describe the actual pin range which they serve in an SoC. This
* information would be used by pinctrl subsystem to configure
* corresponding pins for gpio usage.
*/
struct list_head pin_ranges;
#endif
}; };
extern const char *gpiochip_is_requested(struct gpio_chip *chip, extern const char *gpiochip_is_requested(struct gpio_chip *chip,
...@@ -211,12 +198,14 @@ extern struct gpio_chip *gpiochip_find(void *data, ...@@ -211,12 +198,14 @@ extern struct gpio_chip *gpiochip_find(void *data,
/* lock/unlock as IRQ */ /* lock/unlock as IRQ */
int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset); int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset);
void gpiochip_unlock_as_irq(struct gpio_chip *chip, unsigned int offset); void gpiochip_unlock_as_irq(struct gpio_chip *chip, unsigned int offset);
bool gpiochip_line_is_irq(struct gpio_chip *chip, unsigned int offset);
/* Line status inquiry for drivers */
bool gpiochip_line_is_open_drain(struct gpio_chip *chip, unsigned int offset);
bool gpiochip_line_is_open_source(struct gpio_chip *chip, unsigned int offset);
/* get driver data */ /* get driver data */
static inline void *gpiochip_get_data(struct gpio_chip *chip) void *gpiochip_get_data(struct gpio_chip *chip);
{
return chip->data;
}
struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc); struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc);
......
...@@ -138,6 +138,7 @@ header-y += genetlink.h ...@@ -138,6 +138,7 @@ header-y += genetlink.h
header-y += gen_stats.h header-y += gen_stats.h
header-y += gfs2_ondisk.h header-y += gfs2_ondisk.h
header-y += gigaset_dev.h header-y += gigaset_dev.h
header-y += gpio.h
header-y += gsmmux.h header-y += gsmmux.h
header-y += hdlcdrv.h header-y += hdlcdrv.h
header-y += hdlc.h header-y += hdlc.h
......
/*
* <linux/gpio.h> - userspace ABI for the GPIO character devices
*
* Copyright (C) 2015 Linus Walleij
*
* 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.
*/
#ifndef _UAPI_GPIO_H_
#define _UAPI_GPIO_H_
#include <linux/ioctl.h>
#include <linux/types.h>
/**
* struct gpiochip_info - Information about a certain GPIO chip
* @name: the name of this GPIO chip
* @label: a functional name for this GPIO chip
* @lines: number of GPIO lines on this chip
*/
struct gpiochip_info {
char name[32];
char label[32];
__u32 lines;
};
/* Line is in use by the kernel */
#define GPIOLINE_FLAG_KERNEL (1UL << 0)
#define GPIOLINE_FLAG_IS_OUT (1UL << 1)
#define GPIOLINE_FLAG_ACTIVE_LOW (1UL << 2)
#define GPIOLINE_FLAG_OPEN_DRAIN (1UL << 3)
#define GPIOLINE_FLAG_OPEN_SOURCE (1UL << 4)
/**
* struct gpioline_info - Information about a certain GPIO line
* @line_offset: the local offset on this GPIO device, fill in when
* requesting information from the kernel
* @flags: various flags for this line
* @name: the name of this GPIO line
* @label: a functional name for this GPIO line
* @kernel: this GPIO is in use by the kernel
* @out: this GPIO is an output line (false means it is an input)
* @active_low: this GPIO is active low
*/
struct gpioline_info {
__u32 line_offset;
__u32 flags;
char name[32];
char label[32];
};
#define GPIO_GET_CHIPINFO_IOCTL _IOR('o', 0x01, struct gpiochip_info)
#define GPIO_GET_LINEINFO_IOCTL _IOWR('o', 0x02, struct gpioline_info)
#endif /* _UAPI_GPIO_H_ */
...@@ -13,6 +13,7 @@ help: ...@@ -13,6 +13,7 @@ help:
@echo ' cpupower - a tool for all things x86 CPU power' @echo ' cpupower - a tool for all things x86 CPU power'
@echo ' firewire - the userspace part of nosy, an IEEE-1394 traffic sniffer' @echo ' firewire - the userspace part of nosy, an IEEE-1394 traffic sniffer'
@echo ' freefall - laptop accelerometer program for disk protection' @echo ' freefall - laptop accelerometer program for disk protection'
@echo ' gpio - GPIO tools'
@echo ' hv - tools used when in Hyper-V clients' @echo ' hv - tools used when in Hyper-V clients'
@echo ' iio - IIO tools' @echo ' iio - IIO tools'
@echo ' lguest - a minimal 32-bit x86 hypervisor' @echo ' lguest - a minimal 32-bit x86 hypervisor'
...@@ -53,7 +54,7 @@ acpi: FORCE ...@@ -53,7 +54,7 @@ acpi: FORCE
cpupower: FORCE cpupower: FORCE
$(call descend,power/$@) $(call descend,power/$@)
cgroup firewire hv guest spi usb virtio vm net iio: FORCE cgroup firewire hv guest spi usb virtio vm net iio gpio: FORCE
$(call descend,$@) $(call descend,$@)
liblockdep: FORCE liblockdep: FORCE
...@@ -119,7 +120,7 @@ acpi_clean: ...@@ -119,7 +120,7 @@ acpi_clean:
cpupower_clean: cpupower_clean:
$(call descend,power/cpupower,clean) $(call descend,power/cpupower,clean)
cgroup_clean hv_clean firewire_clean lguest_clean spi_clean usb_clean virtio_clean vm_clean net_clean iio_clean: cgroup_clean hv_clean firewire_clean lguest_clean spi_clean usb_clean virtio_clean vm_clean net_clean iio_clean gpio_clean:
$(call descend,$(@:_clean=),clean) $(call descend,$(@:_clean=),clean)
liblockdep_clean: liblockdep_clean:
...@@ -155,6 +156,7 @@ build_clean: ...@@ -155,6 +156,7 @@ build_clean:
clean: acpi_clean cgroup_clean cpupower_clean hv_clean firewire_clean lguest_clean \ clean: acpi_clean cgroup_clean cpupower_clean hv_clean firewire_clean lguest_clean \
perf_clean selftests_clean turbostat_clean spi_clean usb_clean virtio_clean \ perf_clean selftests_clean turbostat_clean spi_clean usb_clean virtio_clean \
vm_clean net_clean iio_clean x86_energy_perf_policy_clean tmon_clean \ vm_clean net_clean iio_clean x86_energy_perf_policy_clean tmon_clean \
freefall_clean build_clean libbpf_clean libsubcmd_clean liblockdep_clean freefall_clean build_clean libbpf_clean libsubcmd_clean liblockdep_clean \
gpio_clean
.PHONY: FORCE .PHONY: FORCE
CC = $(CROSS_COMPILE)gcc
CFLAGS += -Wall -g -D_GNU_SOURCE
all: lsgpio
lsgpio: lsgpio.o gpio-utils.o
%.o: %.c gpio-utils.h
.PHONY: clean
clean:
rm -f *.o lsgpio
/*
* GPIO tools - helpers library for the GPIO tools
*
* Copyright (C) 2015 Linus Walleij
*
* 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 "gpio-utils.h"
/*
* GPIO tools - utility helpers library for the GPIO tools
*
* Copyright (C) 2015 Linus Walleij
*
* Portions copied from iio_utils and lssio:
* Copyright (c) 2010 Manuel Stahl <manuel.stahl@iis.fraunhofer.de>
* Copyright (c) 2008 Jonathan Cameron
* *
* 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.
*/
#ifndef _GPIO_UTILS_H_
#define _GPIO_UTILS_H_
#include <string.h>
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
static inline int check_prefix(const char *str, const char *prefix)
{
return strlen(str) > strlen(prefix) &&
strncmp(str, prefix, strlen(prefix)) == 0;
}
#endif /* _GPIO_UTILS_H_ */
/*
* lsgpio - example on how to list the GPIO lines on a system
*
* Copyright (C) 2015 Linus Walleij
*
* 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.
*
* Usage:
* lsgpio <-n device-name>
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>
#include <dirent.h>
#include <errno.h>
#include <string.h>
#include <poll.h>
#include <fcntl.h>
#include <getopt.h>
#include <sys/ioctl.h>
#include <linux/gpio.h>
#include "gpio-utils.h"
struct gpio_flag {
char *name;
unsigned long mask;
};
struct gpio_flag flagnames[] = {
{
.name = "kernel",
.mask = GPIOLINE_FLAG_KERNEL,
},
{
.name = "output",
.mask = GPIOLINE_FLAG_IS_OUT,
},
{
.name = "active-low",
.mask = GPIOLINE_FLAG_ACTIVE_LOW,
},
{
.name = "open-drain",
.mask = GPIOLINE_FLAG_OPEN_DRAIN,
},
{
.name = "open-source",
.mask = GPIOLINE_FLAG_OPEN_SOURCE,
},
};
void print_flags(unsigned long flags)
{
int i;
int printed = 0;
for (i = 0; i < ARRAY_SIZE(flagnames); i++) {
if (flags & flagnames[i].mask) {
if (printed)
fprintf(stdout, " ");
fprintf(stdout, "%s", flagnames[i].name);
printed++;
}
}
}
int list_device(const char *device_name)
{
struct gpiochip_info cinfo;
char *chrdev_name;
int fd;
int ret;
int i;
ret = asprintf(&chrdev_name, "/dev/%s", device_name);
if (ret < 0)
return -ENOMEM;
fd = open(chrdev_name, 0);
if (fd == -1) {
ret = -errno;
fprintf(stderr, "Failed to open %s\n", chrdev_name);
goto exit_close_error;
}
/* Inspect this GPIO chip */
ret = ioctl(fd, GPIO_GET_CHIPINFO_IOCTL, &cinfo);
if (ret == -1) {
ret = -errno;
perror("Failed to issue CHIPINFO IOCTL\n");
goto exit_close_error;
}
fprintf(stdout, "GPIO chip: %s, \"%s\", %u GPIO lines\n",
cinfo.name, cinfo.label, cinfo.lines);
/* Loop over the lines and print info */
for (i = 0; i < cinfo.lines; i++) {
struct gpioline_info linfo;
memset(&linfo, 0, sizeof(linfo));
linfo.line_offset = i;
ret = ioctl(fd, GPIO_GET_LINEINFO_IOCTL, &linfo);
if (ret == -1) {
ret = -errno;
perror("Failed to issue LINEINFO IOCTL\n");
goto exit_close_error;
}
fprintf(stdout, "\tline %d:", linfo.line_offset);
if (linfo.name[0])
fprintf(stdout, " %s", linfo.name);
else
fprintf(stdout, " unnamed");
if (linfo.label[0])
fprintf(stdout, " \"%s\"", linfo.label);
else
fprintf(stdout, " unlabeled");
if (linfo.flags) {
fprintf(stdout, " [");
print_flags(linfo.flags);
fprintf(stdout, "]");
}
fprintf(stdout, "\n");
}
exit_close_error:
if (close(fd) == -1)
perror("Failed to close GPIO character device file");
free(chrdev_name);
return ret;
}
void print_usage(void)
{
fprintf(stderr, "Usage: lsgpio [options]...\n"
"List GPIO chips, lines and states\n"
" -n <name> List GPIOs on a named device\n"
" -? This helptext\n"
);
}
int main(int argc, char **argv)
{
const char *device_name;
int ret;
int c;
while ((c = getopt(argc, argv, "n:")) != -1) {
switch (c) {
case 'n':
device_name = optarg;
break;
case '?':
print_usage();
return -1;
}
}
if (device_name)
ret = list_device(device_name);
else {
const struct dirent *ent;
DIR *dp;
/* List all GPIO devices one at a time */
dp = opendir("/dev");
if (!dp) {
ret = -errno;
goto error_out;
}
ret = -ENOENT;
while (ent = readdir(dp), ent) {
if (check_prefix(ent->d_name, "gpiochip")) {
ret = list_device(ent->d_name);
if (ret)
break;
}
}
ret = 0;
if (closedir(dp) == -1) {
perror("scanning devices: Failed to close directory");
ret = -errno;
}
}
error_out:
return ret;
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册