Merge branch 'devel' into for-next
This commit is contained in:
commit
3cf42efc34
@ -1,7 +1,7 @@
|
||||
What: /sys/class/gpio/
|
||||
Date: July 2008
|
||||
KernelVersion: 2.6.27
|
||||
Contact: David Brownell <dbrownell@users.sourceforge.net>
|
||||
Contact: Linus Walleij <linusw@kernel.org>
|
||||
Description:
|
||||
|
||||
As a Kconfig option, individual GPIO signals may be accessed from
|
||||
@ -26,3 +26,5 @@ Description:
|
||||
/label ... (r/o) descriptive, not necessarily unique
|
||||
/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.
|
26
Documentation/ABI/testing/gpio-cdev
Normal file
26
Documentation/ABI/testing/gpio-cdev
Normal file
@ -0,0 +1,26 @@
|
||||
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
|
20
Documentation/devicetree/bindings/gpio/gpio-ts4800.txt
Normal file
20
Documentation/devicetree/bindings/gpio/gpio-ts4800.txt
Normal file
@ -0,0 +1,20 @@
|
||||
* 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>;
|
||||
};
|
@ -1,10 +1,20 @@
|
||||
APM X-Gene Standby GPIO controller bindings
|
||||
|
||||
This is a gpio controller in the standby domain.
|
||||
|
||||
There are 20 GPIO pins from 0..21. There is no GPIO_DS14 or GPIO_DS15,
|
||||
only GPIO_DS8..GPIO_DS13 support interrupts. The IRQ mapping
|
||||
is currently 1-to-1 on interrupts 0x28 thru 0x2d.
|
||||
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
|
||||
as diagram below:
|
||||
+-----------------+
|
||||
| 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:
|
||||
- compatible: "apm,xgene-gpio-sb" for the X-Gene Standby GPIO controller
|
||||
@ -15,10 +25,18 @@ Required properties:
|
||||
0 = active high
|
||||
1 = active low
|
||||
- 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:
|
||||
sbgpio: sbgpio@17001000 {
|
||||
sbgpio: gpio@17001000{
|
||||
compatible = "apm,xgene-gpio-sb";
|
||||
reg = <0x0 0x17001000 0x0 0x400>;
|
||||
#gpio-cells = <2>;
|
||||
@ -29,4 +47,19 @@ Example:
|
||||
<0x0 0x2b 0x1>,
|
||||
<0x0 0x2c 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>;
|
||||
};
|
||||
|
16
MAINTAINERS
16
MAINTAINERS
@ -240,6 +240,12 @@ L: lm-sensors@lm-sensors.org
|
||||
S: Maintained
|
||||
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
|
||||
M: "William Breathitt Gray" <vilhelm.gray@gmail.com>
|
||||
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
|
||||
S: Maintained
|
||||
F: Documentation/gpio/
|
||||
F: Documentation/ABI/testing/gpio-cdev
|
||||
F: Documentation/ABI/obsolete/sysfs-gpio
|
||||
F: drivers/gpio/
|
||||
F: include/linux/gpio/
|
||||
F: include/linux/gpio.h
|
||||
F: include/asm-generic/gpio.h
|
||||
F: include/uapi/linux/gpio.h
|
||||
F: tools/gpio/
|
||||
|
||||
GRE DEMULTIPLEXER DRIVER
|
||||
M: Dmitry Kozlov <xeb@mail.ru>
|
||||
@ -11871,6 +11881,12 @@ M: David Härdeman <david@hardeman.nu>
|
||||
S: Maintained
|
||||
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
|
||||
M: Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
|
||||
M: linux-wimax@intel.com
|
||||
|
@ -1,4 +0,0 @@
|
||||
#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,
|
||||
|
||||
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;
|
||||
|
||||
spin_lock_irqsave(&sdev->scoop_lock, flags);
|
||||
@ -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)
|
||||
{
|
||||
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 */
|
||||
return !!(ioread16(sdev->base + SCOOP_GPRR) & (1 << (offset + 1)));
|
||||
@ -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,
|
||||
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 short gpcr;
|
||||
|
||||
@ -108,7 +108,7 @@ static int scoop_gpio_direction_input(struct gpio_chip *chip,
|
||||
static int scoop_gpio_direction_output(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 short gpcr;
|
||||
|
||||
@ -224,7 +224,7 @@ static int scoop_probe(struct platform_device *pdev)
|
||||
devptr->gpio.direction_input = scoop_gpio_direction_input;
|
||||
devptr->gpio.direction_output = scoop_gpio_direction_output;
|
||||
|
||||
ret = gpiochip_add(&devptr->gpio);
|
||||
ret = gpiochip_add_data(&devptr->gpio, devptr);
|
||||
if (ret)
|
||||
goto err_gpio;
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/irqs.h>
|
||||
@ -227,5 +227,5 @@ void __init gemini_gpio_init(void)
|
||||
(void *)i);
|
||||
}
|
||||
|
||||
BUG_ON(gpiochip_add(&gemini_gpio_chip));
|
||||
BUG_ON(gpiochip_add_data(&gemini_gpio_chip, NULL));
|
||||
}
|
||||
|
@ -13,6 +13,8 @@
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
#include <linux/gpio/driver.h>
|
||||
/* Needed for gpio_to_irq() */
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
@ -243,7 +245,7 @@ static void __init mx27ads_regulator_init(void)
|
||||
vchip->ngpio = 1;
|
||||
vchip->direction_output = vgpio_dir_out;
|
||||
vchip->set = vgpio_set;
|
||||
gpiochip_add(vchip);
|
||||
gpiochip_add_data(vchip, NULL);
|
||||
|
||||
platform_device_register_data(NULL, "reg-fixed-voltage",
|
||||
PLATFORM_DEVID_AUTO,
|
||||
|
@ -27,7 +27,7 @@
|
||||
#include <linux/clockchips.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/sched_clock.h>
|
||||
@ -461,7 +461,7 @@ void __init ixp4xx_sys_init(void)
|
||||
|
||||
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()) {
|
||||
int region;
|
||||
|
@ -664,7 +664,7 @@ static void __init h1940_map_io(void)
|
||||
|
||||
/* Add latch gpio chip, set latch initial value */
|
||||
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)
|
||||
|
@ -15,7 +15,7 @@
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <asm/setup.h>
|
||||
@ -369,7 +369,7 @@ static int __init simpad_init(void)
|
||||
cs3_gpio.get = cs3_gpio_get;
|
||||
cs3_gpio.direction_input = cs3_gpio_direction_input;
|
||||
cs3_gpio.direction_output = cs3_gpio_direction_output;
|
||||
ret = gpiochip_add(&cs3_gpio);
|
||||
ret = gpiochip_add_data(&cs3_gpio, NULL);
|
||||
if (ret)
|
||||
printk(KERN_WARNING "simpad: Unable to register cs3 GPIO device");
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
|
||||
@ -30,7 +30,6 @@
|
||||
#define GPIO_IN (0x0C)
|
||||
#define GROUPINERV (0x10)
|
||||
#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) \
|
||||
{ \
|
||||
@ -53,7 +52,7 @@ struct nuc900_gpio_chip {
|
||||
|
||||
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;
|
||||
unsigned int regval;
|
||||
|
||||
@ -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)
|
||||
{
|
||||
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;
|
||||
unsigned int regval;
|
||||
unsigned long flags;
|
||||
@ -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)
|
||||
{
|
||||
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;
|
||||
unsigned int regval;
|
||||
unsigned long flags;
|
||||
@ -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)
|
||||
{
|
||||
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 *pio = nuc900_gpio->regbase + GPIO_DIR;
|
||||
unsigned int regval;
|
||||
@ -149,6 +148,6 @@ void __init nuc900_init_gpio(int nr_group)
|
||||
gpio_chip = &nuc900_gpio[i];
|
||||
spin_lock_init(&gpio_chip->gpio_lock);
|
||||
gpio_chip->regbase = GPIO_BASE + i * GROUPINERV;
|
||||
gpiochip_add(&gpio_chip->chip);
|
||||
gpiochip_add_data(&gpio_chip->chip, gpio_chip);
|
||||
}
|
||||
}
|
||||
|
@ -154,8 +154,7 @@ err_out:
|
||||
*/
|
||||
static int orion_gpio_request(struct gpio_chip *chip, unsigned pin)
|
||||
{
|
||||
struct orion_gpio_chip *ochip =
|
||||
container_of(chip, struct orion_gpio_chip, chip);
|
||||
struct orion_gpio_chip *ochip = gpiochip_get_data(chip);
|
||||
|
||||
if (orion_gpio_is_valid(ochip, pin, GPIO_INPUT_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)
|
||||
|
||||
static int orion_gpio_direction_input(struct gpio_chip *chip, unsigned pin)
|
||||
{
|
||||
struct orion_gpio_chip *ochip =
|
||||
container_of(chip, struct orion_gpio_chip, chip);
|
||||
struct orion_gpio_chip *ochip = gpiochip_get_data(chip);
|
||||
unsigned long flags;
|
||||
|
||||
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)
|
||||
|
||||
static int orion_gpio_get(struct gpio_chip *chip, unsigned pin)
|
||||
{
|
||||
struct orion_gpio_chip *ochip =
|
||||
container_of(chip, struct orion_gpio_chip, chip);
|
||||
struct orion_gpio_chip *ochip = gpiochip_get_data(chip);
|
||||
int val;
|
||||
|
||||
if (readl(GPIO_IO_CONF(ochip)) & (1 << pin)) {
|
||||
@ -198,8 +195,7 @@ static int orion_gpio_get(struct gpio_chip *chip, unsigned pin)
|
||||
static int
|
||||
orion_gpio_direction_output(struct gpio_chip *chip, unsigned pin, int value)
|
||||
{
|
||||
struct orion_gpio_chip *ochip =
|
||||
container_of(chip, struct orion_gpio_chip, chip);
|
||||
struct orion_gpio_chip *ochip = gpiochip_get_data(chip);
|
||||
unsigned long flags;
|
||||
|
||||
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)
|
||||
|
||||
static void orion_gpio_set(struct gpio_chip *chip, unsigned pin, int value)
|
||||
{
|
||||
struct orion_gpio_chip *ochip =
|
||||
container_of(chip, struct orion_gpio_chip, chip);
|
||||
struct orion_gpio_chip *ochip = gpiochip_get_data(chip);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ochip->lock, flags);
|
||||
@ -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)
|
||||
{
|
||||
struct orion_gpio_chip *ochip =
|
||||
container_of(chip, struct orion_gpio_chip, chip);
|
||||
struct orion_gpio_chip *ochip = gpiochip_get_data(chip);
|
||||
|
||||
return irq_create_mapping(ochip->domain,
|
||||
ochip->secondary_irq_base + pin);
|
||||
@ -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)
|
||||
{
|
||||
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;
|
||||
int i;
|
||||
|
||||
@ -567,7 +561,7 @@ void __init orion_gpio_init(struct device_node *np,
|
||||
ochip->mask_offset = mask_offset;
|
||||
ochip->secondary_irq_base = secondary_irq_base;
|
||||
|
||||
gpiochip_add(&ochip->chip);
|
||||
gpiochip_add_data(&ochip->chip, ochip);
|
||||
|
||||
/*
|
||||
* Mask and clear GPIO interrupts.
|
||||
|
@ -27,7 +27,6 @@
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/gpio.h>
|
||||
|
||||
#include <mach/at32ap700x.h>
|
||||
#include <mach/board.h>
|
||||
|
@ -14,8 +14,8 @@
|
||||
#include <linux/fs.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include <mach/portmux.h>
|
||||
|
@ -11,6 +11,8 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/proc_fs.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/irq.h>
|
||||
|
||||
@ -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)
|
||||
{
|
||||
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)
|
||||
@ -1197,7 +1199,7 @@ static struct gpio_chip bfin_chip = {
|
||||
|
||||
static int __init bfin_gpiolib_setup(void)
|
||||
{
|
||||
return gpiochip_add(&bfin_chip);
|
||||
return gpiochip_add_data(&bfin_chip, NULL);
|
||||
}
|
||||
arch_initcall(bfin_gpiolib_setup);
|
||||
#endif
|
||||
|
@ -11,9 +11,9 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c/bfin_twi.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <asm/blackfin.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/gptimers.h>
|
||||
#include <asm/bfin_can.h>
|
||||
#include <asm/bfin_dma.h>
|
||||
|
@ -15,9 +15,9 @@
|
||||
#include <linux/spi/flash.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <asm/bfin5xx_spi.h>
|
||||
#include <asm/dma.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/nand.h>
|
||||
#include <asm/portmux.h>
|
||||
#include <asm/dpmc.h>
|
||||
|
@ -8,8 +8,8 @@
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <asm/blackfin.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/portmux.h>
|
||||
|
||||
#define DEFINE_REG(reg, off) \
|
||||
@ -116,9 +116,9 @@ static struct gpio_chip bf538_porte_chip = {
|
||||
|
||||
static int __init bf538_extgpio_setup(void)
|
||||
{
|
||||
return gpiochip_add(&bf538_portc_chip) |
|
||||
gpiochip_add(&bf538_portd_chip) |
|
||||
gpiochip_add(&bf538_porte_chip);
|
||||
return gpiochip_add_data(&bf538_portc_chip, NULL) |
|
||||
gpiochip_add_data(&bf538_portd_chip, NULL) |
|
||||
gpiochip_add_data(&bf538_porte_chip, NULL);
|
||||
}
|
||||
arch_initcall(bf538_extgpio_setup);
|
||||
|
||||
|
@ -17,9 +17,9 @@
|
||||
#include <linux/irq.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/usb/musb.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <asm/bfin5xx_spi.h>
|
||||
#include <asm/dma.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/nand.h>
|
||||
#include <asm/portmux.h>
|
||||
#include <asm/bfin_sdh.h>
|
||||
|
@ -20,9 +20,9 @@
|
||||
#include <linux/pinctrl/machine.h>
|
||||
#include <linux/pinctrl/pinconf-generic.h>
|
||||
#include <linux/platform_data/pinctrl-adi2.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <asm/bfin5xx_spi.h>
|
||||
#include <asm/dma.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/nand.h>
|
||||
#include <asm/dpmc.h>
|
||||
#include <asm/bfin_sport.h>
|
||||
|
@ -21,8 +21,8 @@
|
||||
#include <linux/pinctrl/pinconf-generic.h>
|
||||
#include <linux/platform_data/pinctrl-adi2.h>
|
||||
#include <linux/spi/adi_spi3.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <asm/dma.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/nand.h>
|
||||
#include <asm/dpmc.h>
|
||||
#include <asm/portmux.h>
|
||||
|
@ -17,13 +17,13 @@
|
||||
#include <linux/irq.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <asm/delay.h>
|
||||
#ifdef CONFIG_IPIPE
|
||||
#include <linux/ipipe.h>
|
||||
#endif
|
||||
#include <asm/traps.h>
|
||||
#include <asm/blackfin.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/irq_handler.h>
|
||||
#include <asm/dpmc.h>
|
||||
#include <asm/traps.h>
|
||||
|
@ -15,9 +15,9 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <asm/cplb.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/dma.h>
|
||||
#include <asm/dpmc.h>
|
||||
#include <asm/pm.h>
|
||||
|
@ -1,4 +0,0 @@
|
||||
#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 = {
|
||||
|
||||
static int __init mcfgpio_sysinit(void)
|
||||
{
|
||||
gpiochip_add(&mcfgpio_chip);
|
||||
gpiochip_add_data(&mcfgpio_chip, NULL);
|
||||
return subsys_system_register(&mcfgpio_subsys, NULL);
|
||||
}
|
||||
|
||||
|
@ -1,4 +0,0 @@
|
||||
#ifndef __LINUX_GPIO_H
|
||||
#warning Include linux/gpio.h instead of asm/gpio.h
|
||||
#include <linux/gpio.h>
|
||||
#endif
|
@ -1,4 +0,0 @@
|
||||
#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)
|
||||
|
||||
switch (alchemy_get_cputype()) {
|
||||
case ALCHEMY_CPU_AU1000:
|
||||
ret = gpiochip_add(&alchemy_gpio_chip[0]);
|
||||
ret = gpiochip_add_data(&alchemy_gpio_chip[0], NULL);
|
||||
break;
|
||||
case ALCHEMY_CPU_AU1500...ALCHEMY_CPU_AU1200:
|
||||
ret = gpiochip_add(&alchemy_gpio_chip[0]);
|
||||
ret |= gpiochip_add(&alchemy_gpio_chip[1]);
|
||||
ret = gpiochip_add_data(&alchemy_gpio_chip[0], NULL);
|
||||
ret |= gpiochip_add_data(&alchemy_gpio_chip[1], NULL);
|
||||
break;
|
||||
case ALCHEMY_CPU_AU1300:
|
||||
ret = gpiochip_add(&au1300_gpiochip);
|
||||
ret = gpiochip_add_data(&au1300_gpiochip, NULL);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
|
@ -33,8 +33,7 @@ struct ar7_gpio_chip {
|
||||
|
||||
static int ar7_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
|
||||
{
|
||||
struct ar7_gpio_chip *gpch =
|
||||
container_of(chip, struct ar7_gpio_chip, chip);
|
||||
struct ar7_gpio_chip *gpch = gpiochip_get_data(chip);
|
||||
void __iomem *gpio_in = gpch->regs + AR7_GPIO_INPUT;
|
||||
|
||||
return !!(readl(gpio_in) & (1 << 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)
|
||||
{
|
||||
struct ar7_gpio_chip *gpch =
|
||||
container_of(chip, struct ar7_gpio_chip, chip);
|
||||
struct ar7_gpio_chip *gpch = gpiochip_get_data(chip);
|
||||
void __iomem *gpio_in0 = gpch->regs + TITAN_GPIO_INPUT_0;
|
||||
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)
|
||||
static void ar7_gpio_set_value(struct gpio_chip *chip,
|
||||
unsigned gpio, int value)
|
||||
{
|
||||
struct ar7_gpio_chip *gpch =
|
||||
container_of(chip, struct ar7_gpio_chip, chip);
|
||||
struct ar7_gpio_chip *gpch = gpiochip_get_data(chip);
|
||||
void __iomem *gpio_out = gpch->regs + AR7_GPIO_OUTPUT;
|
||||
unsigned tmp;
|
||||
|
||||
@ -67,8 +64,7 @@ static void ar7_gpio_set_value(struct gpio_chip *chip,
|
||||
static void titan_gpio_set_value(struct gpio_chip *chip,
|
||||
unsigned gpio, int value)
|
||||
{
|
||||
struct ar7_gpio_chip *gpch =
|
||||
container_of(chip, struct ar7_gpio_chip, chip);
|
||||
struct ar7_gpio_chip *gpch = gpiochip_get_data(chip);
|
||||
void __iomem *gpio_out0 = gpch->regs + TITAN_GPIO_OUTPUT_0;
|
||||
void __iomem *gpio_out1 = gpch->regs + TITAN_GPIO_OUTPUT_1;
|
||||
unsigned tmp;
|
||||
@ -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)
|
||||
{
|
||||
struct ar7_gpio_chip *gpch =
|
||||
container_of(chip, struct ar7_gpio_chip, chip);
|
||||
struct ar7_gpio_chip *gpch = gpiochip_get_data(chip);
|
||||
void __iomem *gpio_dir = gpch->regs + AR7_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)
|
||||
|
||||
static int titan_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
|
||||
{
|
||||
struct ar7_gpio_chip *gpch =
|
||||
container_of(chip, struct ar7_gpio_chip, chip);
|
||||
struct ar7_gpio_chip *gpch = gpiochip_get_data(chip);
|
||||
void __iomem *gpio_dir0 = gpch->regs + TITAN_GPIO_DIR_0;
|
||||
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)
|
||||
static int ar7_gpio_direction_output(struct gpio_chip *chip,
|
||||
unsigned gpio, int value)
|
||||
{
|
||||
struct ar7_gpio_chip *gpch =
|
||||
container_of(chip, struct ar7_gpio_chip, chip);
|
||||
struct ar7_gpio_chip *gpch = gpiochip_get_data(chip);
|
||||
void __iomem *gpio_dir = gpch->regs + AR7_GPIO_DIR;
|
||||
|
||||
ar7_gpio_set_value(chip, gpio, value);
|
||||
@ -121,8 +114,7 @@ static int ar7_gpio_direction_output(struct gpio_chip *chip,
|
||||
static int titan_gpio_direction_output(struct gpio_chip *chip,
|
||||
unsigned gpio, int value)
|
||||
{
|
||||
struct ar7_gpio_chip *gpch =
|
||||
container_of(chip, struct ar7_gpio_chip, chip);
|
||||
struct ar7_gpio_chip *gpch = gpiochip_get_data(chip);
|
||||
void __iomem *gpio_dir0 = gpch->regs + TITAN_GPIO_DIR_0;
|
||||
void __iomem *gpio_dir1 = gpch->regs + TITAN_GPIO_DIR_1;
|
||||
|
||||
@ -335,7 +327,7 @@ int __init ar7_gpio_init(void)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = gpiochip_add(&gpch->chip);
|
||||
ret = gpiochip_add_data(&gpch->chip, gpch);
|
||||
if (ret) {
|
||||
printk(KERN_ERR "%s: failed to add gpiochip\n",
|
||||
gpch->chip.label);
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
|
||||
#include <bcm63xx_cpu.h>
|
||||
#include <bcm63xx_gpio.h>
|
||||
@ -147,5 +147,5 @@ int __init bcm63xx_gpio_init(void)
|
||||
bcm63xx_gpio_chip.ngpio = bcm63xx_gpio_count();
|
||||
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 @@
|
||||
#include <linux/init.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/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
@ -91,9 +93,9 @@ static inline struct jz_gpio_chip *gpio_to_jz_gpio_chip(unsigned int gpio)
|
||||
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)
|
||||
@ -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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
@ -270,7 +272,7 @@ uint32_t jz_gpio_port_get_value(int port, uint32_t mask)
|
||||
}
|
||||
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)
|
||||
{
|
||||
@ -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_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)
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/io.h>
|
||||
#include <asm/txx9pio.h>
|
||||
@ -85,5 +85,5 @@ int __init txx9_gpio_init(unsigned long baseaddr,
|
||||
return -ENODEV;
|
||||
txx9_gpio_chip.base = base;
|
||||
txx9_gpio_chip.ngpio = num;
|
||||
return gpiochip_add(&txx9_gpio_chip);
|
||||
return gpiochip_add_data(&txx9_gpio_chip, NULL);
|
||||
}
|
||||
|
@ -32,7 +32,7 @@
|
||||
#include <linux/export.h>
|
||||
#include <linux/spinlock.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/gpio.h>
|
||||
@ -88,7 +88,7 @@ static int rb532_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
@ -100,7 +100,7 @@ static void rb532_gpio_set(struct gpio_chip *chip,
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
@ -111,7 +111,7 @@ static int rb532_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
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 */
|
||||
rb532_set_bit(0, offset, gpch->regbase + GPIOFUNC);
|
||||
@ -128,7 +128,7 @@ static int rb532_gpio_direction_output(struct gpio_chip *chip,
|
||||
{
|
||||
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 */
|
||||
rb532_set_bit(0, offset, gpch->regbase + GPIOFUNC);
|
||||
@ -200,7 +200,7 @@ int __init rb532_gpio_init(void)
|
||||
}
|
||||
|
||||
/* Register our GPIO chip */
|
||||
gpiochip_add(&rb532_gpio_chip->chip);
|
||||
gpiochip_add_data(&rb532_gpio_chip->chip, rb532_gpio_chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/mtd/physmap.h>
|
||||
@ -687,16 +687,14 @@ struct txx9_iocled_data {
|
||||
|
||||
static int txx9_iocled_get(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct txx9_iocled_data *data =
|
||||
container_of(chip, struct txx9_iocled_data, chip);
|
||||
struct txx9_iocled_data *data = gpiochip_get_data(chip);
|
||||
return !!(data->cur_val & (1 << offset));
|
||||
}
|
||||
|
||||
static void txx9_iocled_set(struct gpio_chip *chip, unsigned int offset,
|
||||
int value)
|
||||
{
|
||||
struct txx9_iocled_data *data =
|
||||
container_of(chip, struct txx9_iocled_data, chip);
|
||||
struct txx9_iocled_data *data = gpiochip_get_data(chip);
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&txx9_iocled_lock, flags);
|
||||
if (value)
|
||||
@ -749,7 +747,7 @@ void __init txx9_iocled_init(unsigned long baseaddr,
|
||||
iocled->chip.label = "iocled";
|
||||
iocled->chip.base = basenum;
|
||||
iocled->chip.ngpio = num;
|
||||
if (gpiochip_add(&iocled->chip))
|
||||
if (gpiochip_add_data(&iocled->chip, iocled))
|
||||
goto out_unmap;
|
||||
if (basenum < 0)
|
||||
basenum = iocled->chip.base;
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/mtd/physmap.h>
|
||||
|
||||
@ -335,7 +336,7 @@ static void __init rbtx4938_mtd_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_spi_init();
|
||||
}
|
||||
|
@ -1,4 +0,0 @@
|
||||
#ifndef __LINUX_GPIO_H
|
||||
#warning Include linux/gpio.h instead of asm/gpio.h
|
||||
#include <linux/gpio.h>
|
||||
#endif
|
@ -1,4 +0,0 @@
|
||||
#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)
|
||||
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
|
||||
struct ppc4xx_gpio __iomem *regs = mm_gc->regs;
|
||||
|
||||
return in_be32(®s->ir) & GPIO_MASK(gpio);
|
||||
return !!(in_be32(®s->ir) & GPIO_MASK(gpio));
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
@ -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);
|
||||
|
||||
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)
|
||||
|
@ -13,7 +13,7 @@
|
||||
#ifndef __ASM_SH_MAGICPANELR2_H
|
||||
#define __ASM_SH_MAGICPANELR2_H
|
||||
|
||||
#include <asm/gpio.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#define __IO_PREFIX mpr2
|
||||
#include <asm/io_generic.h>
|
||||
|
@ -1,4 +0,0 @@
|
||||
#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);
|
||||
|
||||
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)
|
||||
|
@ -1,4 +0,0 @@
|
||||
#ifndef __LINUX_GPIO_H
|
||||
#warning Include linux/gpio.h instead of asm/gpio.h
|
||||
#include <linux/gpio.h>
|
||||
#endif
|
@ -1,4 +0,0 @@
|
||||
#ifndef __LINUX_GPIO_H
|
||||
#warning Include linux/gpio.h instead of asm/gpio.h
|
||||
#include <linux/gpio.h>
|
||||
#endif
|
@ -30,8 +30,7 @@
|
||||
#include <linux/ata_platform.h>
|
||||
#include <linux/platform_data/atmel.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include <asm/gpio.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#define DRV_NAME "pata_at91"
|
||||
#define DRV_VERSION "0.3"
|
||||
|
@ -36,8 +36,8 @@
|
||||
#include <scsi/scsi_host.h>
|
||||
#include <linux/libata.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <asm/dma.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/portmux.h>
|
||||
|
||||
#define DRV_NAME "pata-bf54x"
|
||||
|
@ -126,6 +126,16 @@ config GPIO_AMDPT
|
||||
driver for GPIO functionality on Promontory IOHub
|
||||
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
|
||||
bool "Broadcom Kona GPIO"
|
||||
depends on OF_GPIO && (ARCH_BCM_MOBILE || COMPILE_TEST)
|
||||
@ -281,12 +291,14 @@ config GPIO_MPC5200
|
||||
depends on PPC_MPC52xx
|
||||
|
||||
config GPIO_MPC8XXX
|
||||
bool "MPC512x/MPC8xxx GPIO support"
|
||||
bool "MPC512x/MPC8xxx/QorIQ GPIO support"
|
||||
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
|
||||
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
|
||||
def_bool y
|
||||
@ -380,6 +392,13 @@ config GPIO_TB10X
|
||||
select GENERIC_IRQ_CHIP
|
||||
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
|
||||
bool "Toumaz Xenif TZ1090 GPIO support"
|
||||
depends on SOC_TZ1090
|
||||
@ -487,6 +506,15 @@ endmenu
|
||||
menu "Port-mapped I/O GPIO drivers"
|
||||
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
|
||||
tristate "ACCES 104-IDIO-16 GPIO support"
|
||||
select GPIOLIB_IRQCHIP
|
||||
@ -506,10 +534,10 @@ config GPIO_104_IDI_48
|
||||
via the idi_48_irq module parameter.
|
||||
|
||||
config GPIO_F7188X
|
||||
tristate "F71869, F71869A, F71882FG and F71889F GPIO support"
|
||||
tristate "F71869, F71869A, F71882FG, F71889F and F81866 GPIO support"
|
||||
help
|
||||
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
|
||||
be called f7188x-gpio.
|
||||
@ -570,6 +598,15 @@ config GPIO_TS5500
|
||||
blocks of the TS-5500: DIO1, DIO2 and the LCD port, and the TS-5600
|
||||
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
|
||||
|
||||
menu "I2C GPIO expanders"
|
||||
@ -702,6 +739,14 @@ config GPIO_SX150X
|
||||
8 bits: sx1508q
|
||||
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
|
||||
|
||||
menu "MFD GPIO expanders"
|
||||
@ -844,6 +889,13 @@ config GPIO_TIMBERDALE
|
||||
---help---
|
||||
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
|
||||
bool "TPS6586X GPIO"
|
||||
depends on MFD_TPS6586X
|
||||
@ -1011,6 +1063,12 @@ config GPIO_MC33880
|
||||
SPI driver for Freescale MC33880 high-side/low-side switch.
|
||||
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
|
||||
|
||||
menu "SPI or I2C GPIO expanders"
|
||||
|
@ -12,6 +12,7 @@ obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o
|
||||
# Device drivers. Generally keep list sorted alphabetically
|
||||
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_IDI_48) += gpio-104-idi-48.o
|
||||
obj-$(CONFIG_GPIO_74X164) += gpio-74x164.o
|
||||
@ -23,7 +24,7 @@ obj-$(CONFIG_GPIO_ALTERA) += gpio-altera.o
|
||||
obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o
|
||||
obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.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_BRCMSTB) += gpio-brcmstb.o
|
||||
obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o
|
||||
@ -75,6 +76,7 @@ obj-$(CONFIG_GPIO_OMAP) += gpio-omap.o
|
||||
obj-$(CONFIG_GPIO_PCA953X) += gpio-pca953x.o
|
||||
obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.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_PXA) += gpio-pxa.o
|
||||
obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o
|
||||
@ -95,9 +97,12 @@ obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o
|
||||
obj-$(CONFIG_ARCH_TEGRA) += gpio-tegra.o
|
||||
obj-$(CONFIG_GPIO_TIMBERDALE) += gpio-timberdale.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_TPS65910) += gpio-tps65910.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_TWL4030) += gpio-twl4030.o
|
||||
obj-$(CONFIG_GPIO_TWL6040) += gpio-twl6040.o
|
||||
@ -111,6 +116,7 @@ obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o
|
||||
obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o
|
||||
obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.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_SB) += gpio-xgene-sb.o
|
||||
obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o
|
||||
|
430
drivers/gpio/gpio-104-dio-48e.c
Normal file
430
drivers/gpio/gpio-104-dio-48e.c
Normal file
@ -0,0 +1,430 @@
|
||||
/*
|
||||
* 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");
|
||||
* @ack_lock: synchronization lock to prevent IRQ handler race conditions
|
||||
* @irq_mask: input bits affected by interrupts
|
||||
* @base: base port address of the GPIO device
|
||||
* @extent: extent of port address region of the GPIO device
|
||||
* @irq: Interrupt line number
|
||||
* @cos_enb: Change-Of-State IRQ enable boundaries mask
|
||||
*/
|
||||
@ -49,7 +48,6 @@ struct idi_48_gpio {
|
||||
spinlock_t ack_lock;
|
||||
unsigned char irq_mask[6];
|
||||
unsigned base;
|
||||
unsigned extent;
|
||||
unsigned irq;
|
||||
unsigned char cos_enb;
|
||||
};
|
||||
@ -227,11 +225,10 @@ static int __init idi_48_probe(struct platform_device *pdev)
|
||||
if (!idi48gpio)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!request_region(base, extent, name)) {
|
||||
dev_err(dev, "Unable to lock %s port addresses (0x%X-0x%X)\n",
|
||||
name, base, base + extent);
|
||||
err = -EBUSY;
|
||||
goto err_lock_io_port;
|
||||
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;
|
||||
}
|
||||
|
||||
idi48gpio->chip.label = name;
|
||||
@ -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.get = idi_48_gpio_get;
|
||||
idi48gpio->base = base;
|
||||
idi48gpio->extent = extent;
|
||||
idi48gpio->irq = irq;
|
||||
|
||||
spin_lock_init(&idi48gpio->lock);
|
||||
@ -253,7 +249,7 @@ static int __init idi_48_probe(struct platform_device *pdev)
|
||||
err = gpiochip_add_data(&idi48gpio->chip, idi48gpio);
|
||||
if (err) {
|
||||
dev_err(dev, "GPIO registering failed (%d)\n", err);
|
||||
goto err_gpio_register;
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Disable IRQ by default */
|
||||
@ -264,23 +260,20 @@ static int __init idi_48_probe(struct platform_device *pdev)
|
||||
handle_edge_irq, IRQ_TYPE_NONE);
|
||||
if (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) {
|
||||
dev_err(dev, "IRQ handler registering failed (%d)\n", err);
|
||||
goto err_request_irq;
|
||||
goto err_gpiochip_remove;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_request_irq:
|
||||
err_gpiochip_irqchip_add:
|
||||
err_gpiochip_remove:
|
||||
gpiochip_remove(&idi48gpio->chip);
|
||||
err_gpio_register:
|
||||
release_region(base, extent);
|
||||
err_lock_io_port:
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -290,7 +283,6 @@ static int idi_48_remove(struct platform_device *pdev)
|
||||
|
||||
free_irq(idi48gpio->irq, idi48gpio);
|
||||
gpiochip_remove(&idi48gpio->chip);
|
||||
release_region(idi48gpio->base, idi48gpio->extent);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -340,4 +332,4 @@ module_exit(idi_48_exit);
|
||||
|
||||
MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
|
||||
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");
|
||||
* @lock: synchronization lock to prevent I/O race conditions
|
||||
* @irq_mask: I/O bits affected by interrupts
|
||||
* @base: base port address of the GPIO device
|
||||
* @extent: extent of port address region of the GPIO device
|
||||
* @irq: Interrupt line number
|
||||
* @out_state: output bits state
|
||||
*/
|
||||
@ -47,7 +46,6 @@ struct idio_16_gpio {
|
||||
spinlock_t lock;
|
||||
unsigned long irq_mask;
|
||||
unsigned base;
|
||||
unsigned extent;
|
||||
unsigned irq;
|
||||
unsigned out_state;
|
||||
};
|
||||
@ -201,11 +199,10 @@ static int __init idio_16_probe(struct platform_device *pdev)
|
||||
if (!idio16gpio)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!request_region(base, extent, name)) {
|
||||
dev_err(dev, "Unable to lock %s port addresses (0x%X-0x%X)\n",
|
||||
name, base, base + extent);
|
||||
err = -EBUSY;
|
||||
goto err_lock_io_port;
|
||||
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;
|
||||
}
|
||||
|
||||
idio16gpio->chip.label = name;
|
||||
@ -219,7 +216,6 @@ static int __init idio_16_probe(struct platform_device *pdev)
|
||||
idio16gpio->chip.get = idio_16_gpio_get;
|
||||
idio16gpio->chip.set = idio_16_gpio_set;
|
||||
idio16gpio->base = base;
|
||||
idio16gpio->extent = extent;
|
||||
idio16gpio->irq = irq;
|
||||
idio16gpio->out_state = 0xFFFF;
|
||||
|
||||
@ -230,7 +226,7 @@ static int __init idio_16_probe(struct platform_device *pdev)
|
||||
err = gpiochip_add_data(&idio16gpio->chip, idio16gpio);
|
||||
if (err) {
|
||||
dev_err(dev, "GPIO registering failed (%d)\n", err);
|
||||
goto err_gpio_register;
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Disable IRQ by default */
|
||||
@ -241,23 +237,19 @@ static int __init idio_16_probe(struct platform_device *pdev)
|
||||
handle_edge_irq, IRQ_TYPE_NONE);
|
||||
if (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);
|
||||
if (err) {
|
||||
dev_err(dev, "IRQ handler registering failed (%d)\n", err);
|
||||
goto err_request_irq;
|
||||
goto err_gpiochip_remove;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_request_irq:
|
||||
err_gpiochip_irqchip_add:
|
||||
err_gpiochip_remove:
|
||||
gpiochip_remove(&idio16gpio->chip);
|
||||
err_gpio_register:
|
||||
release_region(base, extent);
|
||||
err_lock_io_port:
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -267,7 +259,6 @@ static int idio_16_remove(struct platform_device *pdev)
|
||||
|
||||
free_irq(idio16gpio->irq, idio16gpio);
|
||||
gpiochip_remove(&idio16gpio->chip);
|
||||
release_region(idio16gpio->base, idio16gpio->extent);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -317,4 +308,4 @@ module_exit(idio_16_exit);
|
||||
|
||||
MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
|
||||
MODULE_DESCRIPTION("ACCES 104-IDIO-16 GPIO driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -25,6 +25,7 @@
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/gpio.h>
|
||||
@ -204,7 +205,8 @@ found:
|
||||
gp.pmbase &= 0x0000FF00;
|
||||
if (gp.pmbase == 0)
|
||||
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",
|
||||
gp.pmbase + PMBASE_OFFSET);
|
||||
err = -EBUSY;
|
||||
@ -213,7 +215,6 @@ found:
|
||||
gp.pm = ioport_map(gp.pmbase + PMBASE_OFFSET, PMBASE_SIZE);
|
||||
if (!gp.pm) {
|
||||
dev_err(&pdev->dev, "Couldn't map io port into io memory\n");
|
||||
release_region(gp.pmbase + PMBASE_OFFSET, PMBASE_SIZE);
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
@ -228,7 +229,6 @@ found:
|
||||
printk(KERN_ERR "GPIO registering failed (%d)\n",
|
||||
err);
|
||||
ioport_unmap(gp.pm);
|
||||
release_region(gp.pmbase + PMBASE_OFFSET, PMBASE_SIZE);
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
@ -239,7 +239,6 @@ static void __exit amd_gpio_exit(void)
|
||||
{
|
||||
gpiochip_remove(&gp.chip);
|
||||
ioport_unmap(gp.pm);
|
||||
release_region(gp.pmbase + PMBASE_OFFSET, PMBASE_SIZE);
|
||||
}
|
||||
|
||||
module_init(amd_gpio_init);
|
||||
|
@ -1,12 +1,11 @@
|
||||
/*
|
||||
* 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) 2008-2011 Gabor Juhos <juhosg@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
|
||||
* under the terms of the GNU General Public License version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
@ -15,119 +14,205 @@
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/platform_data/gpio-ath79.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
|
||||
#include <asm/mach-ath79/ar71xx_regs.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
|
||||
|
||||
#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 gpio_chip chip;
|
||||
struct gpio_chip gc;
|
||||
void __iomem *base;
|
||||
spinlock_t lock;
|
||||
unsigned long both_edges;
|
||||
};
|
||||
|
||||
static void ath79_gpio_set_value(struct gpio_chip *chip,
|
||||
unsigned gpio, int value)
|
||||
static struct ath79_gpio_ctrl *irq_data_to_ath79_gpio(struct irq_data *data)
|
||||
{
|
||||
struct ath79_gpio_ctrl *ctrl = gpiochip_get_data(chip);
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
|
||||
|
||||
if (value)
|
||||
__raw_writel(BIT(gpio), ctrl->base + AR71XX_GPIO_REG_SET);
|
||||
else
|
||||
__raw_writel(BIT(gpio), ctrl->base + AR71XX_GPIO_REG_CLEAR);
|
||||
return container_of(gc, struct ath79_gpio_ctrl, gc);
|
||||
}
|
||||
|
||||
static int ath79_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
|
||||
static u32 ath79_gpio_read(struct ath79_gpio_ctrl *ctrl, unsigned reg)
|
||||
{
|
||||
struct ath79_gpio_ctrl *ctrl = gpiochip_get_data(chip);
|
||||
|
||||
return (__raw_readl(ctrl->base + AR71XX_GPIO_REG_IN) >> gpio) & 1;
|
||||
return readl(ctrl->base + reg);
|
||||
}
|
||||
|
||||
static int ath79_gpio_direction_input(struct gpio_chip *chip,
|
||||
unsigned offset)
|
||||
static void ath79_gpio_write(struct ath79_gpio_ctrl *ctrl,
|
||||
unsigned reg, u32 val)
|
||||
{
|
||||
struct ath79_gpio_ctrl *ctrl = gpiochip_get_data(chip);
|
||||
return writel(val, ctrl->base + reg);
|
||||
}
|
||||
|
||||
static bool ath79_gpio_update_bits(
|
||||
struct ath79_gpio_ctrl *ctrl, unsigned reg, u32 mask, u32 bits)
|
||||
{
|
||||
u32 old_val, new_val;
|
||||
|
||||
old_val = ath79_gpio_read(ctrl, reg);
|
||||
new_val = (old_val & ~mask) | (bits & mask);
|
||||
|
||||
if (new_val != old_val)
|
||||
ath79_gpio_write(ctrl, reg, new_val);
|
||||
|
||||
return new_val != old_val;
|
||||
}
|
||||
|
||||
static void ath79_gpio_irq_unmask(struct irq_data *data)
|
||||
{
|
||||
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, mask);
|
||||
spin_unlock_irqrestore(&ctrl->lock, flags);
|
||||
}
|
||||
|
||||
__raw_writel(
|
||||
__raw_readl(ctrl->base + AR71XX_GPIO_REG_OE) & ~BIT(offset),
|
||||
ctrl->base + AR71XX_GPIO_REG_OE);
|
||||
static void ath79_gpio_irq_mask(struct irq_data *data)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
static void ath79_gpio_irq_enable(struct irq_data *data)
|
||||
{
|
||||
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_ENABLE, mask, mask);
|
||||
ath79_gpio_update_bits(ctrl, AR71XX_GPIO_REG_INT_MASK, mask, mask);
|
||||
spin_unlock_irqrestore(&ctrl->lock, flags);
|
||||
}
|
||||
|
||||
static void ath79_gpio_irq_disable(struct irq_data *data)
|
||||
{
|
||||
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);
|
||||
ath79_gpio_update_bits(ctrl, AR71XX_GPIO_REG_INT_ENABLE, mask, 0);
|
||||
spin_unlock_irqrestore(&ctrl->lock, flags);
|
||||
}
|
||||
|
||||
static int ath79_gpio_irq_set_type(struct irq_data *data,
|
||||
unsigned int flow_type)
|
||||
{
|
||||
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;
|
||||
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);
|
||||
|
||||
if (flow_type == IRQ_TYPE_EDGE_BOTH) {
|
||||
ctrl->both_edges |= mask;
|
||||
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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath79_gpio_direction_output(struct gpio_chip *chip,
|
||||
unsigned offset, int value)
|
||||
{
|
||||
struct ath79_gpio_ctrl *ctrl = gpiochip_get_data(chip);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ctrl->lock, flags);
|
||||
|
||||
if (value)
|
||||
__raw_writel(BIT(offset), ctrl->base + AR71XX_GPIO_REG_SET);
|
||||
else
|
||||
__raw_writel(BIT(offset), ctrl->base + AR71XX_GPIO_REG_CLEAR);
|
||||
|
||||
__raw_writel(
|
||||
__raw_readl(ctrl->base + AR71XX_GPIO_REG_OE) | BIT(offset),
|
||||
ctrl->base + AR71XX_GPIO_REG_OE);
|
||||
|
||||
spin_unlock_irqrestore(&ctrl->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ar934x_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct ath79_gpio_ctrl *ctrl = gpiochip_get_data(chip);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ctrl->lock, flags);
|
||||
|
||||
__raw_writel(
|
||||
__raw_readl(ctrl->base + AR71XX_GPIO_REG_OE) | BIT(offset),
|
||||
ctrl->base + AR71XX_GPIO_REG_OE);
|
||||
|
||||
spin_unlock_irqrestore(&ctrl->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ar934x_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
|
||||
int value)
|
||||
{
|
||||
struct ath79_gpio_ctrl *ctrl = gpiochip_get_data(chip);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ctrl->lock, flags);
|
||||
|
||||
if (value)
|
||||
__raw_writel(BIT(offset), ctrl->base + AR71XX_GPIO_REG_SET);
|
||||
else
|
||||
__raw_writel(BIT(offset), ctrl->base + AR71XX_GPIO_REG_CLEAR);
|
||||
|
||||
__raw_writel(
|
||||
__raw_readl(ctrl->base + AR71XX_GPIO_REG_OE) & ~BIT(offset),
|
||||
ctrl->base + AR71XX_GPIO_REG_OE);
|
||||
|
||||
spin_unlock_irqrestore(&ctrl->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct gpio_chip ath79_gpio_chip = {
|
||||
.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 struct irq_chip ath79_gpio_irqchip = {
|
||||
.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 gpio_chip *gc = irq_desc_get_handler_data(desc);
|
||||
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);
|
||||
|
||||
pending = ath79_gpio_read(ctrl, AR71XX_GPIO_REG_INT_PENDING);
|
||||
|
||||
/* Update the polarity of the both edges irqs */
|
||||
both_edges = ctrl->both_edges & pending;
|
||||
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);
|
||||
|
||||
if (pending) {
|
||||
for_each_set_bit(irq, &pending, gc->ngpio)
|
||||
generic_handle_irq(
|
||||
irq_linear_revmap(gc->irqdomain, irq));
|
||||
}
|
||||
|
||||
chained_irq_exit(irqchip, desc);
|
||||
}
|
||||
|
||||
static const struct of_device_id ath79_gpio_of_match[] = {
|
||||
{ .compatible = "qca,ar7100-gpio" },
|
||||
{ .compatible = "qca,ar9340-gpio" },
|
||||
@ -147,6 +232,7 @@ static int ath79_gpio_probe(struct platform_device *pdev)
|
||||
ctrl = devm_kzalloc(&pdev->dev, sizeof(*ctrl), GFP_KERNEL);
|
||||
if (!ctrl)
|
||||
return -ENOMEM;
|
||||
platform_set_drvdata(pdev, ctrl);
|
||||
|
||||
if (np) {
|
||||
err = of_property_read_u32(np, "ngpios", &ath79_gpio_count);
|
||||
@ -174,21 +260,53 @@ static int ath79_gpio_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&ctrl->lock);
|
||||
memcpy(&ctrl->chip, &ath79_gpio_chip, sizeof(ctrl->chip));
|
||||
ctrl->chip.parent = &pdev->dev;
|
||||
ctrl->chip.ngpio = ath79_gpio_count;
|
||||
if (oe_inverted) {
|
||||
ctrl->chip.direction_input = ar934x_gpio_direction_input;
|
||||
ctrl->chip.direction_output = ar934x_gpio_direction_output;
|
||||
err = bgpio_init(&ctrl->gc, &pdev->dev, 4,
|
||||
ctrl->base + AR71XX_GPIO_REG_IN,
|
||||
ctrl->base + AR71XX_GPIO_REG_SET,
|
||||
ctrl->base + AR71XX_GPIO_REG_CLEAR,
|
||||
oe_inverted ? NULL : ctrl->base + AR71XX_GPIO_REG_OE,
|
||||
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) {
|
||||
dev_err(&pdev->dev,
|
||||
"cannot add AR71xx GPIO chip, error=%d", 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;
|
||||
}
|
||||
|
||||
@ -198,6 +316,7 @@ static struct platform_driver ath79_gpio_driver = {
|
||||
.of_match_table = ath79_gpio_of_match,
|
||||
},
|
||||
.probe = ath79_gpio_probe,
|
||||
.remove = ath79_gpio_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(ath79_gpio_driver);
|
||||
|
@ -258,6 +258,8 @@ static int davinci_gpio_probe(struct platform_device *pdev)
|
||||
spin_lock_init(&chips[i].lock);
|
||||
|
||||
regs = gpio2regs(base);
|
||||
if (!regs)
|
||||
return -ENXIO;
|
||||
chips[i].regs = regs;
|
||||
chips[i].set_data = ®s->set_data;
|
||||
chips[i].clr_data = ®s->clr_data;
|
||||
@ -433,8 +435,7 @@ static struct irq_chip *davinci_gpio_get_irq_chip(unsigned int irq)
|
||||
{
|
||||
static struct irq_chip_type gpio_unbanked;
|
||||
|
||||
gpio_unbanked = *container_of(irq_get_chip(irq),
|
||||
struct irq_chip_type, chip);
|
||||
gpio_unbanked = *irq_data_get_chip_type(irq_get_irq_data(irq));
|
||||
|
||||
return &gpio_unbanked.chip;
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
@ -36,14 +36,16 @@
|
||||
#define SIO_F71869A_ID 0x1007 /* F71869A chipset ID */
|
||||
#define SIO_F71882_ID 0x0541 /* F71882 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[] = {
|
||||
"f71869",
|
||||
"f71869a",
|
||||
"f71882fg",
|
||||
"f71889f",
|
||||
"f81866",
|
||||
};
|
||||
|
||||
struct f7188x_sio {
|
||||
@ -190,6 +192,18 @@ static struct f7188x_gpio_bank f71889_gpio_bank[] = {
|
||||
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)
|
||||
{
|
||||
int err;
|
||||
@ -318,6 +332,10 @@ static int f7188x_gpio_probe(struct platform_device *pdev)
|
||||
data->nr_bank = ARRAY_SIZE(f71889_gpio_bank);
|
||||
data->bank = f71889_gpio_bank;
|
||||
break;
|
||||
case f81866:
|
||||
data->nr_bank = ARRAY_SIZE(f81866_gpio_bank);
|
||||
data->bank = f81866_gpio_bank;
|
||||
break;
|
||||
default:
|
||||
return -ENODEV;
|
||||
}
|
||||
@ -395,6 +413,9 @@ static int __init f7188x_find(int addr, struct f7188x_sio *sio)
|
||||
case SIO_F71889_ID:
|
||||
sio->type = f71889f;
|
||||
break;
|
||||
case SIO_F81866_ID:
|
||||
sio->type = f81866;
|
||||
break;
|
||||
default:
|
||||
pr_info(DRVNAME ": Unsupported Fintek device 0x%04x\n", devid);
|
||||
goto err;
|
||||
@ -485,6 +506,6 @@ static void __exit f7188x_gpio_exit(void)
|
||||
}
|
||||
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_LICENSE("GPL");
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/gpio.h>
|
||||
@ -384,8 +385,8 @@ static struct ichx_desc avoton_desc = {
|
||||
.use_outlvl_cache = true,
|
||||
};
|
||||
|
||||
static int ichx_gpio_request_regions(struct resource *res_base,
|
||||
const char *name, u8 use_gpio)
|
||||
static int ichx_gpio_request_regions(struct device *dev,
|
||||
struct resource *res_base, const char *name, u8 use_gpio)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -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++) {
|
||||
if (!(use_gpio & (1 << i)))
|
||||
continue;
|
||||
if (!request_region(
|
||||
if (!devm_request_region(dev,
|
||||
res_base->start + ichx_priv.desc->regs[0][i],
|
||||
ichx_priv.desc->reglen[i], name))
|
||||
goto request_err;
|
||||
return -EBUSY;
|
||||
}
|
||||
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)
|
||||
@ -468,7 +447,7 @@ static int ichx_gpio_probe(struct platform_device *pdev)
|
||||
spin_lock_init(&ichx_priv.lock);
|
||||
res_base = platform_get_resource(pdev, IORESOURCE_IO, ICH_RES_GPIO);
|
||||
ichx_priv.use_gpio = ich_info->use_gpio;
|
||||
err = ichx_gpio_request_regions(res_base, pdev->name,
|
||||
err = ichx_gpio_request_regions(&pdev->dev, res_base, pdev->name,
|
||||
ichx_priv.use_gpio);
|
||||
if (err)
|
||||
return err;
|
||||
@ -489,8 +468,8 @@ static int ichx_gpio_probe(struct platform_device *pdev)
|
||||
goto init;
|
||||
}
|
||||
|
||||
if (!request_region(res_pm->start, resource_size(res_pm),
|
||||
pdev->name)) {
|
||||
if (!devm_request_region(&pdev->dev, res_pm->start,
|
||||
resource_size(res_pm), pdev->name)) {
|
||||
pr_warn("ACPI BAR is busy, GPI 0 - 15 unavailable\n");
|
||||
goto init;
|
||||
}
|
||||
@ -502,31 +481,19 @@ init:
|
||||
err = gpiochip_add_data(&ichx_priv.chip, NULL);
|
||||
if (err) {
|
||||
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,
|
||||
ichx_priv.chip.base + ichx_priv.chip.ngpio - 1, DRV_NAME);
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -205,18 +205,6 @@ static int ks8695_gpio_to_irq(struct gpio_chip *gc, unsigned int 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 */
|
||||
|
||||
static struct gpio_chip ks8695_gpio_chip = {
|
||||
|
@ -803,6 +803,8 @@ static int mcp230xx_probe(struct i2c_client *client,
|
||||
pdata = devm_kzalloc(&client->dev,
|
||||
sizeof(struct mcp23s08_platform_data),
|
||||
GFP_KERNEL);
|
||||
if (!pdata)
|
||||
return -ENOMEM;
|
||||
pdata->base = -1;
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,6 @@
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/mpc52xx.h>
|
||||
#include <sysdev/fsl_soc.h>
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
/*
|
||||
* 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) 2016 Freescale Semiconductor Inc.
|
||||
*
|
||||
* 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
|
||||
@ -14,11 +15,12 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
|
||||
#define MPC8XXX_GPIO_PINS 32
|
||||
|
||||
@ -31,32 +33,20 @@
|
||||
#define GPIO_ICR2 0x18
|
||||
|
||||
struct mpc8xxx_gpio_chip {
|
||||
struct of_mm_gpio_chip mm_gc;
|
||||
struct gpio_chip gc;
|
||||
void __iomem *regs;
|
||||
raw_spinlock_t lock;
|
||||
|
||||
/*
|
||||
* shadowed data register to be able to clear/set output pins in
|
||||
* open drain mode safely
|
||||
*/
|
||||
u32 data;
|
||||
unsigned long (*read_reg)(void __iomem *reg);
|
||||
void (*write_reg)(void __iomem *reg, unsigned long data);
|
||||
|
||||
int (*direction_output)(struct gpio_chip *chip,
|
||||
unsigned offset, int value);
|
||||
|
||||
struct irq_domain *irq;
|
||||
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
|
||||
* defined as output cannot be determined by reading GPDAT register,
|
||||
* 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)
|
||||
static int mpc8572_gpio_get(struct gpio_chip *gc, unsigned int gpio)
|
||||
{
|
||||
u32 val;
|
||||
struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
|
||||
struct mpc8xxx_gpio_chip *mpc8xxx_gc = gpiochip_get_data(gc);
|
||||
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;
|
||||
out_shadow = gc->bgpio_data & out_mask;
|
||||
|
||||
val = in_be32(mm->regs + GPIO_DAT) & ~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);
|
||||
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 */
|
||||
if (gpio >= 28)
|
||||
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 */
|
||||
if (gpio <= 3)
|
||||
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)
|
||||
@ -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 irq_chip *chip = irq_desc_get_chip(desc);
|
||||
struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;
|
||||
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)
|
||||
generic_handle_irq(irq_linear_revmap(mpc8xxx_gc->irq,
|
||||
32 - ffs(mask)));
|
||||
@ -206,12 +115,14 @@ static void mpc8xxx_gpio_irq_cascade(struct irq_desc *desc)
|
||||
static void mpc8xxx_irq_unmask(struct irq_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;
|
||||
|
||||
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);
|
||||
}
|
||||
@ -219,12 +130,14 @@ static void mpc8xxx_irq_unmask(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 of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;
|
||||
struct gpio_chip *gc = &mpc8xxx_gc->gc;
|
||||
unsigned long 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);
|
||||
}
|
||||
@ -232,29 +145,32 @@ static void mpc8xxx_irq_mask(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 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)
|
||||
{
|
||||
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;
|
||||
|
||||
switch (flow_type) {
|
||||
case IRQ_TYPE_EDGE_FALLING:
|
||||
raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
|
||||
setbits32(mm->regs + GPIO_ICR,
|
||||
mpc8xxx_gpio2mask(irqd_to_hwirq(d)));
|
||||
mpc8xxx_gc->write_reg(mpc8xxx_gc->regs + GPIO_ICR,
|
||||
mpc8xxx_gc->read_reg(mpc8xxx_gc->regs + GPIO_ICR)
|
||||
| gc->pin2mask(gc, irqd_to_hwirq(d)));
|
||||
raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
|
||||
break;
|
||||
|
||||
case IRQ_TYPE_EDGE_BOTH:
|
||||
raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
|
||||
clrbits32(mm->regs + GPIO_ICR,
|
||||
mpc8xxx_gpio2mask(irqd_to_hwirq(d)));
|
||||
mpc8xxx_gc->write_reg(mpc8xxx_gc->regs + GPIO_ICR,
|
||||
mpc8xxx_gc->read_reg(mpc8xxx_gc->regs + GPIO_ICR)
|
||||
& ~(gc->pin2mask(gc, irqd_to_hwirq(d))));
|
||||
raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
|
||||
break;
|
||||
|
||||
@ -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)
|
||||
{
|
||||
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);
|
||||
void __iomem *reg;
|
||||
unsigned int shift;
|
||||
unsigned long flags;
|
||||
|
||||
if (gpio < 16) {
|
||||
reg = mm->regs + GPIO_ICR;
|
||||
reg = mpc8xxx_gc->regs + GPIO_ICR;
|
||||
shift = (15 - gpio) * 2;
|
||||
} else {
|
||||
reg = mm->regs + GPIO_ICR2;
|
||||
reg = mpc8xxx_gc->regs + GPIO_ICR2;
|
||||
shift = (15 - (gpio % 16)) * 2;
|
||||
}
|
||||
|
||||
@ -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_LEVEL_LOW:
|
||||
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);
|
||||
break;
|
||||
|
||||
case IRQ_TYPE_EDGE_RISING:
|
||||
case IRQ_TYPE_LEVEL_HIGH:
|
||||
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);
|
||||
break;
|
||||
|
||||
case IRQ_TYPE_EDGE_BOTH:
|
||||
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);
|
||||
break;
|
||||
|
||||
@ -354,8 +274,6 @@ static const struct mpc8xxx_gpio_devtype mpc8572_gpio_devtype = {
|
||||
};
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
@ -374,9 +292,7 @@ static int mpc8xxx_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct mpc8xxx_gpio_chip *mpc8xxx_gc;
|
||||
struct of_mm_gpio_chip *mm_gc;
|
||||
struct gpio_chip *gc;
|
||||
const struct of_device_id *id;
|
||||
struct gpio_chip *gc;
|
||||
const struct mpc8xxx_gpio_devtype *devtype =
|
||||
of_device_get_match_data(&pdev->dev);
|
||||
int ret;
|
||||
@ -389,12 +305,35 @@ static int mpc8xxx_probe(struct platform_device *pdev)
|
||||
|
||||
raw_spin_lock_init(&mpc8xxx_gc->lock);
|
||||
|
||||
mm_gc = &mpc8xxx_gc->mm_gc;
|
||||
gc = &mm_gc->gc;
|
||||
mpc8xxx_gc->regs = of_iomap(np, 0);
|
||||
if (!mpc8xxx_gc->regs)
|
||||
return -ENOMEM;
|
||||
|
||||
mm_gc->save_regs = mpc8xxx_gpio_save_regs;
|
||||
gc->ngpio = MPC8XXX_GPIO_PINS;
|
||||
gc->direction_input = mpc8xxx_gpio_dir_in;
|
||||
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");
|
||||
}
|
||||
|
||||
mpc8xxx_gc->read_reg = gc->read_reg;
|
||||
mpc8xxx_gc->write_reg = gc->write_reg;
|
||||
|
||||
if (!devtype)
|
||||
devtype = &mpc8xxx_gpio_devtype_default;
|
||||
@ -405,18 +344,21 @@ static int mpc8xxx_probe(struct platform_device *pdev)
|
||||
*/
|
||||
mpc8xxx_irq_chip.irq_set_type = devtype->irq_set_type;
|
||||
|
||||
gc->direction_output = devtype->gpio_dir_out ?: mpc8xxx_gpio_dir_out;
|
||||
gc->get = devtype->gpio_get ?: mpc8xxx_gpio_get;
|
||||
gc->set = mpc8xxx_gpio_set;
|
||||
gc->set_multiple = mpc8xxx_gpio_set_multiple;
|
||||
gc->direction_output = devtype->gpio_dir_out ?: gc->direction_output;
|
||||
gc->get = devtype->gpio_get ?: gc->get;
|
||||
gc->to_irq = mpc8xxx_gpio_to_irq;
|
||||
|
||||
ret = of_mm_gpiochip_add_data(np, mm_gc, mpc8xxx_gc);
|
||||
if (ret)
|
||||
return ret;
|
||||
mpc8xxx_gc->direction_output = gc->direction_output;
|
||||
|
||||
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);
|
||||
if (mpc8xxx_gc->irqn == NO_IRQ)
|
||||
if (!mpc8xxx_gc->irqn)
|
||||
return 0;
|
||||
|
||||
mpc8xxx_gc->irq = irq_domain_add_linear(np, MPC8XXX_GPIO_PINS,
|
||||
@ -424,18 +366,16 @@ static int mpc8xxx_probe(struct platform_device *pdev)
|
||||
if (!mpc8xxx_gc->irq)
|
||||
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 */
|
||||
out_be32(mm_gc->regs + GPIO_IER, 0xffffffff);
|
||||
out_be32(mm_gc->regs + GPIO_IMR, 0);
|
||||
mpc8xxx_gc->write_reg(mpc8xxx_gc->regs + GPIO_IER, 0xffffffff);
|
||||
mpc8xxx_gc->write_reg(mpc8xxx_gc->regs + GPIO_IMR, 0);
|
||||
|
||||
irq_set_chained_handler_and_data(mpc8xxx_gc->irqn,
|
||||
mpc8xxx_gpio_irq_cascade, mpc8xxx_gc);
|
||||
|
||||
return 0;
|
||||
err:
|
||||
iounmap(mpc8xxx_gc->regs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
of_mm_gpiochip_remove(&mpc8xxx_gc->mm_gc);
|
||||
gpiochip_remove(&mpc8xxx_gc->gc);
|
||||
iounmap(mpc8xxx_gc->regs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
186
drivers/gpio/gpio-pisosr.c
Normal file
186
drivers/gpio/gpio-pisosr.c
Normal file
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* 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 @@
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
@ -228,7 +229,8 @@ static int sch311x_gpio_probe(struct platform_device *pdev)
|
||||
int err, i;
|
||||
|
||||
/* 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",
|
||||
pdata->runtime_reg + GP1, pdata->runtime_reg + GP1 + 5);
|
||||
return -EBUSY;
|
||||
@ -273,7 +275,6 @@ static int sch311x_gpio_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
|
||||
exit_err:
|
||||
release_region(pdata->runtime_reg + GP1, 6);
|
||||
/* release already registered chips */
|
||||
for (--i; i >= 0; i--)
|
||||
gpiochip_remove(&priv->blocks[i].chip);
|
||||
@ -282,12 +283,9 @@ exit_err:
|
||||
|
||||
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);
|
||||
int i;
|
||||
|
||||
release_region(pdata->runtime_reg + GP1, 6);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(priv->blocks); i++) {
|
||||
gpiochip_remove(&priv->blocks[i].chip);
|
||||
dev_info(&pdev->dev,
|
||||
|
170
drivers/gpio/gpio-tpic2810.c
Normal file
170
drivers/gpio/gpio-tpic2810.c
Normal file
@ -0,0 +1,170 @@
|
||||
/*
|
||||
* 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");
|
222
drivers/gpio/gpio-tps65218.c
Normal file
222
drivers/gpio/gpio-tps65218.c
Normal file
@ -0,0 +1,222 @@
|
||||
/*
|
||||
* 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");
|
93
drivers/gpio/gpio-ts4800.c
Normal file
93
drivers/gpio/gpio-ts4800.c
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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");
|
427
drivers/gpio/gpio-ws16c48.c
Normal file
427
drivers/gpio/gpio-ws16c48.c
Normal file
@ -0,0 +1,427 @@
|
||||
/*
|
||||
* 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 @@
|
||||
* AppliedMicro X-Gene SoC GPIO-Standby Driver
|
||||
*
|
||||
* Copyright (c) 2014, Applied Micro Circuits Corporation
|
||||
* Author: Tin Huynh <tnhuynh@apm.com>.
|
||||
* Y Vo <yvo@apm.com>.
|
||||
* Author: Tin Huynh <tnhuynh@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
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@ -28,9 +29,14 @@
|
||||
|
||||
#include "gpiolib.h"
|
||||
|
||||
#define XGENE_MAX_GPIO_DS 22
|
||||
#define XGENE_MAX_GPIO_DS_IRQ 6
|
||||
/* Common property names */
|
||||
#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 MPA_GPIO_INT_LVL 0x0290
|
||||
@ -39,19 +45,32 @@
|
||||
#define MPA_GPIO_IN_ADDR 0x02a4
|
||||
#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.
|
||||
* @gc: memory-mapped GPIO controllers.
|
||||
* @irq: Mapping GPIO pins and interrupt number
|
||||
* nirq: Number of GPIO pins that supports interrupt
|
||||
* @regs: GPIO register base offset
|
||||
* @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 gpio_chip gc;
|
||||
u32 *irq;
|
||||
u32 nirq;
|
||||
void __iomem *regs;
|
||||
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;
|
||||
|
||||
@ -63,23 +82,170 @@ static void xgene_gpio_set_bit(struct gpio_chip *gc, void __iomem *reg, u32 gpio
|
||||
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 irq_fwspec fwspec;
|
||||
|
||||
if (priv->irq[gpio])
|
||||
return priv->irq[gpio];
|
||||
if ((gpio < priv->irq_start) ||
|
||||
(gpio > HWIRQ_TO_GPIO(priv, priv->nirq)))
|
||||
return -ENXIO;
|
||||
|
||||
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 ((fwspec->param_count != 2) ||
|
||||
(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;
|
||||
|
||||
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)
|
||||
{
|
||||
struct xgene_gpio_sb *priv;
|
||||
u32 ret, i;
|
||||
u32 default_lines[] = {0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D};
|
||||
u32 ret;
|
||||
struct resource *res;
|
||||
void __iomem *regs;
|
||||
struct irq_domain *parent_domain = NULL;
|
||||
struct fwnode_handle *fwnode;
|
||||
u32 val32;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
@ -90,6 +256,18 @@ static int xgene_gpio_sb_probe(struct platform_device *pdev)
|
||||
if (IS_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,
|
||||
regs + MPA_GPIO_IN_ADDR,
|
||||
regs + MPA_GPIO_OUT_ADDR, NULL,
|
||||
@ -97,30 +275,51 @@ static int xgene_gpio_sb_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
priv->gc.to_irq = apm_gpio_sb_to_irq;
|
||||
priv->gc.ngpio = XGENE_MAX_GPIO_DS;
|
||||
priv->gc.to_irq = xgene_gpio_sb_to_irq;
|
||||
|
||||
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,
|
||||
GFP_KERNEL);
|
||||
if (!priv->irq)
|
||||
return -ENOMEM;
|
||||
/* Retrieve number irqs, use default if property not found */
|
||||
priv->nirq = XGENE_DFLT_MAX_NIRQ;
|
||||
if (!device_property_read_u32(&pdev->dev, XGENE_NIRQ_PROPERTY, &val32))
|
||||
priv->nirq = val32;
|
||||
|
||||
for (i = 0; i < priv->nirq; i++) {
|
||||
priv->irq[default_lines[i]] = platform_get_irq(pdev, i);
|
||||
xgene_gpio_set_bit(&priv->gc, regs + MPA_GPIO_SEL_LO,
|
||||
default_lines[i] * 2, 1);
|
||||
xgene_gpio_set_bit(&priv->gc, regs + MPA_GPIO_INT_LVL, i, 1);
|
||||
}
|
||||
/* Retrieve number gpio, use default if property not found */
|
||||
priv->gc.ngpio = XGENE_DFLT_MAX_NGPIO;
|
||||
if (!device_property_read_u32(&pdev->dev, XGENE_NGPIO_PROPERTY, &val32))
|
||||
priv->gc.ngpio = val32;
|
||||
|
||||
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);
|
||||
|
||||
ret = gpiochip_add_data(&priv->gc, priv);
|
||||
if (ret)
|
||||
dev_err(&pdev->dev, "failed to register X-Gene GPIO Standby driver\n");
|
||||
if (pdev->dev.of_node)
|
||||
fwnode = of_node_to_fwnode(pdev->dev.of_node);
|
||||
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) {
|
||||
/* Register interrupt handlers for gpio signaled acpi events */
|
||||
@ -138,6 +337,8 @@ static int xgene_gpio_sb_remove(struct platform_device *pdev)
|
||||
acpi_gpiochip_free_interrupts(&priv->gc);
|
||||
}
|
||||
|
||||
irq_domain_remove(priv->irq_domain);
|
||||
|
||||
gpiochip_remove(&priv->gc);
|
||||
return 0;
|
||||
}
|
||||
|
@ -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
|
||||
* 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;
|
||||
|
||||
/* 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;
|
||||
|
||||
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;
|
||||
int i;
|
||||
|
||||
if (range->pins) {
|
||||
for (i = 0; i < range->npins; i++) {
|
||||
if (range->pins[i] == pin)
|
||||
return range->base + i - chip->base;
|
||||
return range->base + i - gdev->base;
|
||||
}
|
||||
} else {
|
||||
if (pin >= range->pin_base &&
|
||||
pin < range->pin_base + range->npins) {
|
||||
unsigned gpio_base;
|
||||
|
||||
gpio_base = range->base - chip->base;
|
||||
gpio_base = range->base - gdev->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)
|
||||
return -EINVAL;
|
||||
}
|
||||
#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)
|
||||
{
|
||||
return pin;
|
||||
@ -134,7 +134,7 @@ static struct gpio_desc *acpi_get_gpiod(char *path, int pin)
|
||||
if (!chip)
|
||||
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)
|
||||
return ERR_PTR(offset);
|
||||
|
||||
@ -202,7 +202,7 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
|
||||
if (!handler)
|
||||
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)
|
||||
return AE_BAD_PARAMETER;
|
||||
|
||||
@ -673,7 +673,7 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
|
||||
struct gpio_desc *desc;
|
||||
bool found;
|
||||
|
||||
pin = acpi_gpiochip_pin_to_gpio_offset(chip, pin);
|
||||
pin = acpi_gpiochip_pin_to_gpio_offset(chip->gpiodev, pin);
|
||||
if (pin < 0) {
|
||||
status = AE_BAD_PARAMETER;
|
||||
goto out;
|
||||
|
@ -180,7 +180,7 @@ static int gpio_sysfs_request_irq(struct device *dev, unsigned char flags)
|
||||
* Remove this redundant call (along with the corresponding
|
||||
* 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)
|
||||
goto err_put_kn;
|
||||
|
||||
@ -194,7 +194,7 @@ static int gpio_sysfs_request_irq(struct device *dev, unsigned char flags)
|
||||
return 0;
|
||||
|
||||
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:
|
||||
sysfs_put(data->value_kn);
|
||||
|
||||
@ -212,7 +212,7 @@ static void gpio_sysfs_free_irq(struct device *dev)
|
||||
|
||||
data->irq_flags = 0;
|
||||
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);
|
||||
}
|
||||
|
||||
@ -547,6 +547,7 @@ static struct class gpio_class = {
|
||||
int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
|
||||
{
|
||||
struct gpio_chip *chip;
|
||||
struct gpio_device *gdev;
|
||||
struct gpiod_data *data;
|
||||
unsigned long flags;
|
||||
int status;
|
||||
@ -565,12 +566,13 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chip = desc->chip;
|
||||
gdev = desc->gdev;
|
||||
chip = gdev->chip;
|
||||
|
||||
mutex_lock(&sysfs_lock);
|
||||
|
||||
/* check if chip is being removed */
|
||||
if (!chip || !chip->cdev) {
|
||||
if (!chip || !gdev->mockdev) {
|
||||
status = -ENODEV;
|
||||
goto err_unlock;
|
||||
}
|
||||
@ -605,7 +607,7 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
|
||||
if (chip->names && 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,
|
||||
ioname ? ioname : "gpio%u",
|
||||
desc_to_gpio(desc));
|
||||
@ -716,9 +718,10 @@ err_unlock:
|
||||
}
|
||||
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 gpio_chip *chip = gdev->chip;
|
||||
|
||||
/*
|
||||
* Many systems add gpio chips for SOC support very early,
|
||||
@ -730,7 +733,7 @@ int gpiochip_sysfs_register(struct gpio_chip *chip)
|
||||
return 0;
|
||||
|
||||
/* 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),
|
||||
chip, gpiochip_groups,
|
||||
"gpiochip%d", chip->base);
|
||||
@ -738,30 +741,31 @@ int gpiochip_sysfs_register(struct gpio_chip *chip)
|
||||
return PTR_ERR(dev);
|
||||
|
||||
mutex_lock(&sysfs_lock);
|
||||
chip->cdev = dev;
|
||||
gdev->mockdev = dev;
|
||||
mutex_unlock(&sysfs_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gpiochip_sysfs_unregister(struct gpio_chip *chip)
|
||||
void gpiochip_sysfs_unregister(struct gpio_device *gdev)
|
||||
{
|
||||
struct gpio_desc *desc;
|
||||
struct gpio_chip *chip = gdev->chip;
|
||||
unsigned int i;
|
||||
|
||||
if (!chip->cdev)
|
||||
if (!gdev->mockdev)
|
||||
return;
|
||||
|
||||
device_unregister(chip->cdev);
|
||||
device_unregister(gdev->mockdev);
|
||||
|
||||
/* prevent further gpiod exports */
|
||||
mutex_lock(&sysfs_lock);
|
||||
chip->cdev = NULL;
|
||||
gdev->mockdev = NULL;
|
||||
mutex_unlock(&sysfs_lock);
|
||||
|
||||
/* unregister gpiod class devices owned by sysfs */
|
||||
for (i = 0; i < chip->ngpio; i++) {
|
||||
desc = &chip->desc[i];
|
||||
desc = &gdev->descs[i];
|
||||
if (test_and_clear_bit(FLAG_SYSFS, &desc->flags))
|
||||
gpiod_free(desc);
|
||||
}
|
||||
@ -771,7 +775,7 @@ static int __init gpiolib_sysfs_init(void)
|
||||
{
|
||||
int status;
|
||||
unsigned long flags;
|
||||
struct gpio_chip *chip;
|
||||
struct gpio_device *gdev;
|
||||
|
||||
status = class_register(&gpio_class);
|
||||
if (status < 0)
|
||||
@ -784,8 +788,8 @@ static int __init gpiolib_sysfs_init(void)
|
||||
* registered, and so arch_initcall() can always gpio_export().
|
||||
*/
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
list_for_each_entry(chip, &gpio_chips, list) {
|
||||
if (chip->cdev)
|
||||
list_for_each_entry(gdev, &gpio_devices, list) {
|
||||
if (gdev->mockdev)
|
||||
continue;
|
||||
|
||||
/*
|
||||
@ -798,12 +802,11 @@ static int __init gpiolib_sysfs_init(void)
|
||||
* gpio_lock prevents us from doing this.
|
||||
*/
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
status = gpiochip_sysfs_register(chip);
|
||||
status = gpiochip_sysfs_register(gdev);
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
}
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
|
||||
|
||||
return status;
|
||||
}
|
||||
postcore_initcall(gpiolib_sysfs_init);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -12,13 +12,66 @@
|
||||
#ifndef GPIOLIB_H
|
||||
#define GPIOLIB_H
|
||||
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/cdev.h>
|
||||
|
||||
enum of_gpio_flags;
|
||||
enum gpiod_flags;
|
||||
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
|
||||
* @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,
|
||||
struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip, u16 hwnum);
|
||||
|
||||
extern struct spinlock gpio_lock;
|
||||
extern struct list_head gpio_chips;
|
||||
extern struct list_head gpio_devices;
|
||||
|
||||
struct gpio_desc {
|
||||
struct gpio_chip *chip;
|
||||
struct gpio_device *gdev;
|
||||
unsigned long flags;
|
||||
/* flag symbols are bit numbers */
|
||||
#define FLAG_REQUESTED 0
|
||||
@ -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)
|
||||
{
|
||||
return desc - &desc->chip->desc[0];
|
||||
return desc - &desc->gdev->descs[0];
|
||||
}
|
||||
|
||||
/* With descriptor prefix */
|
||||
@ -149,31 +202,31 @@ static int __maybe_unused gpio_chip_hwgpio(const struct gpio_desc *desc)
|
||||
/* With chip prefix */
|
||||
|
||||
#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, ...) \
|
||||
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, ...) \
|
||||
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, ...) \
|
||||
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, ...) \
|
||||
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, ...) \
|
||||
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
|
||||
|
||||
int gpiochip_sysfs_register(struct gpio_chip *chip);
|
||||
void gpiochip_sysfs_unregister(struct gpio_chip *chip);
|
||||
int gpiochip_sysfs_register(struct gpio_device *gdev);
|
||||
void gpiochip_sysfs_unregister(struct gpio_device *gdev);
|
||||
|
||||
#else
|
||||
|
||||
static inline int gpiochip_sysfs_register(struct gpio_chip *chip)
|
||||
static inline int gpiochip_sysfs_register(struct gpio_device *gdev)
|
||||
{
|
||||
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 @@
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mfd/menelaus.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <asm/mach/irq.h>
|
||||
|
||||
#include <asm/gpio.h>
|
||||
|
||||
#define DRIVER_NAME "menelaus"
|
||||
|
||||
|
@ -35,10 +35,10 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <asm/mach/flash.h>
|
||||
#include <linux/platform_data/mtd-onenand-omap2.h>
|
||||
#include <asm/gpio.h>
|
||||
|
||||
#include <linux/omap-dma.h>
|
||||
|
||||
|
@ -36,10 +36,10 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <pcmcia/ss.h>
|
||||
#include <pcmcia/cisreg.h>
|
||||
#include <asm/gpio.h>
|
||||
|
||||
#define SZ_1K 0x00000400
|
||||
#define SZ_8K 0x00002000
|
||||
|
@ -17,7 +17,6 @@
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
|
||||
#include <asm/gpio.h>
|
||||
#include <mach/vpac270.h>
|
||||
|
||||
#include "soc_common.h"
|
||||
|
@ -26,7 +26,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_irq.h>
|
||||
@ -98,11 +98,6 @@ struct iproc_gpio {
|
||||
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
|
||||
*/
|
||||
@ -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)
|
||||
{
|
||||
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);
|
||||
int i, bit;
|
||||
|
||||
@ -180,7 +175,7 @@ static void iproc_gpio_irq_handler(struct irq_desc *desc)
|
||||
static void iproc_gpio_irq_ack(struct irq_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 int offset = IPROC_GPIO_REG(gpio,
|
||||
IPROC_GPIO_INT_CLR_OFFSET);
|
||||
@ -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)
|
||||
{
|
||||
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;
|
||||
|
||||
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)
|
||||
static void iproc_gpio_irq_mask(struct irq_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;
|
||||
|
||||
spin_lock_irqsave(&chip->lock, flags);
|
||||
@ -219,7 +214,7 @@ static void iproc_gpio_irq_mask(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 iproc_gpio *chip = to_iproc_gpio(gc);
|
||||
struct iproc_gpio *chip = gpiochip_get_data(gc);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&chip->lock, flags);
|
||||
@ -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)
|
||||
{
|
||||
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;
|
||||
bool level_triggered = false;
|
||||
bool dual_edge = false;
|
||||
@ -292,7 +287,7 @@ static struct irq_chip iproc_gpio_irq_chip = {
|
||||
*/
|
||||
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;
|
||||
|
||||
/* not all Iproc GPIO pins can be muxed individually */
|
||||
@ -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)
|
||||
{
|
||||
struct iproc_gpio *chip = to_iproc_gpio(gc);
|
||||
struct iproc_gpio *chip = gpiochip_get_data(gc);
|
||||
unsigned gpio = gc->base + offset;
|
||||
|
||||
if (!chip->pinmux_is_supported)
|
||||
@ -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)
|
||||
{
|
||||
struct iproc_gpio *chip = to_iproc_gpio(gc);
|
||||
struct iproc_gpio *chip = gpiochip_get_data(gc);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&chip->lock, flags);
|
||||
@ -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,
|
||||
int val)
|
||||
{
|
||||
struct iproc_gpio *chip = to_iproc_gpio(gc);
|
||||
struct iproc_gpio *chip = gpiochip_get_data(gc);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&chip->lock, flags);
|
||||
@ -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)
|
||||
{
|
||||
struct iproc_gpio *chip = to_iproc_gpio(gc);
|
||||
struct iproc_gpio *chip = gpiochip_get_data(gc);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&chip->lock, flags);
|
||||
@ -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)
|
||||
{
|
||||
struct iproc_gpio *chip = to_iproc_gpio(gc);
|
||||
struct iproc_gpio *chip = gpiochip_get_data(gc);
|
||||
unsigned int offset = IPROC_GPIO_REG(gpio,
|
||||
IPROC_GPIO_DATA_IN_OFFSET);
|
||||
unsigned int shift = IPROC_GPIO_SHIFT(gpio);
|
||||
@ -706,7 +701,7 @@ static int iproc_gpio_probe(struct platform_device *pdev)
|
||||
chip->pinmux_is_supported = of_property_read_bool(dev->of_node,
|
||||
"gpio-ranges");
|
||||
|
||||
ret = gpiochip_add(gc);
|
||||
ret = gpiochip_add_data(gc, chip);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "unable to add GPIO chip\n");
|
||||
return ret;
|
||||
|
@ -338,7 +338,6 @@ struct atlas7_pinctrl_data {
|
||||
#define ATLAS7_GPIO_CTL_DATAIN_MASK BIT(7)
|
||||
|
||||
struct atlas7_gpio_bank {
|
||||
struct pinctrl_dev *pctldev;
|
||||
int id;
|
||||
int irq;
|
||||
void __iomem *base;
|
||||
@ -6070,7 +6069,6 @@ static int atlas7_gpio_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
for (idx = 0; idx < nbank; idx++) {
|
||||
struct gpio_pin_range *pin_range;
|
||||
struct atlas7_gpio_bank *bank;
|
||||
|
||||
bank = &a7gc->banks[idx];
|
||||
@ -6088,22 +6086,6 @@ static int atlas7_gpio_probe(struct platform_device *pdev)
|
||||
|
||||
gpiochip_set_chained_irqchip(chip, &atlas7_gpio_irq_chip,
|
||||
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);
|
||||
|
@ -457,8 +457,8 @@ static int sunxi_pinctrl_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||
struct sunxi_pinctrl *pctl = gpiochip_get_data(chip);
|
||||
u32 reg = sunxi_data_reg(offset);
|
||||
u8 index = sunxi_data_offset(offset);
|
||||
u32 set_mux = pctl->desc->irq_read_needs_mux &&
|
||||
test_bit(FLAG_USED_AS_IRQ, &chip->desc[offset].flags);
|
||||
bool set_mux = pctl->desc->irq_read_needs_mux &&
|
||||
gpiochip_line_is_irq(chip, offset);
|
||||
u32 val;
|
||||
|
||||
if (set_mux)
|
||||
|
@ -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;
|
||||
u32 pin_mask = 1 << (QE_PIO_PINS - 1 - gpio);
|
||||
|
||||
return in_be32(®s->cpdata) & pin_mask;
|
||||
return !!(in_be32(®s->cpdata) & pin_mask);
|
||||
}
|
||||
|
||||
static void qe_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||
|
@ -25,8 +25,6 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
|
||||
#include <asm/gpio.h>
|
||||
|
||||
#include "atmel_usba_udc.h"
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_DEBUG_FS
|
||||
|
@ -24,8 +24,6 @@
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/hcd.h>
|
||||
|
||||
#include <asm/gpio.h>
|
||||
|
||||
#include "ohci.h"
|
||||
|
||||
#define valid_port(index) ((index) >= 0 && (index) < AT91_MAX_USBH_PORTS)
|
||||
|
@ -26,8 +26,6 @@
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <video/videomode.h>
|
||||
|
||||
#include <asm/gpio.h>
|
||||
|
||||
#include <video/atmel_lcdc.h>
|
||||
|
||||
struct atmel_lcdfb_config {
|
||||
|
@ -22,8 +22,8 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/i2c/tps65010.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <asm/gpio.h>
|
||||
#include "omapfb.h"
|
||||
|
||||
#define MODULE_NAME "omapfb-lcd_h3"
|
||||
|
@ -22,8 +22,7 @@
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <asm/gpio.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/mux.h>
|
||||
|
@ -28,8 +28,8 @@ GPIO13 - screen blanking
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <asm/gpio.h>
|
||||
#include "omapfb.h"
|
||||
|
||||
static int palmtt_panel_init(struct lcd_panel *panel,
|
||||
|
@ -26,8 +26,12 @@
|
||||
*/
|
||||
|
||||
#ifndef ARCH_NR_GPIOS
|
||||
#if defined(CONFIG_ARCH_NR_GPIO) && CONFIG_ARCH_NR_GPIO > 0
|
||||
#define ARCH_NR_GPIOS CONFIG_ARCH_NR_GPIO
|
||||
#else
|
||||
#define ARCH_NR_GPIOS 512
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* "valid" GPIO numbers are nonnegative and may be passed to
|
||||
|
@ -1,6 +1,7 @@
|
||||
#ifndef __LINUX_GPIO_DRIVER_H
|
||||
#define __LINUX_GPIO_DRIVER_H
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/irq.h>
|
||||
@ -10,22 +11,21 @@
|
||||
#include <linux/pinctrl/pinctrl.h>
|
||||
#include <linux/kconfig.h>
|
||||
|
||||
struct device;
|
||||
struct gpio_desc;
|
||||
struct of_phandle_args;
|
||||
struct device_node;
|
||||
struct seq_file;
|
||||
struct gpio_device;
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @cdev: class device used by sysfs interface (may be NULL)
|
||||
* @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
|
||||
* enabling module power and clock; may sleep
|
||||
* @free: optional hook for chip-specific deactivation, such as
|
||||
@ -52,7 +52,6 @@ struct seq_file;
|
||||
* get rid of the static GPIO number space in the long run.
|
||||
* @ngpio: the number of GPIOs handled by this controller; the last GPIO
|
||||
* 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 for the GPIOs in this chip. Any entry in the array
|
||||
* may be NULL if there is no alias for the GPIO, however the
|
||||
@ -107,11 +106,9 @@ struct seq_file;
|
||||
*/
|
||||
struct gpio_chip {
|
||||
const char *label;
|
||||
struct gpio_device *gpiodev;
|
||||
struct device *parent;
|
||||
struct device *cdev;
|
||||
struct module *owner;
|
||||
void *data;
|
||||
struct list_head list;
|
||||
|
||||
int (*request)(struct gpio_chip *chip,
|
||||
unsigned offset);
|
||||
@ -141,7 +138,6 @@ struct gpio_chip {
|
||||
struct gpio_chip *chip);
|
||||
int base;
|
||||
u16 ngpio;
|
||||
struct gpio_desc *desc;
|
||||
const char *const *names;
|
||||
bool can_sleep;
|
||||
bool irq_not_threaded;
|
||||
@ -184,15 +180,6 @@ struct gpio_chip {
|
||||
int (*of_xlate)(struct gpio_chip *gc,
|
||||
const struct of_phandle_args *gpiospec, u32 *flags);
|
||||
#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,
|
||||
@ -211,12 +198,14 @@ extern struct gpio_chip *gpiochip_find(void *data,
|
||||
/* lock/unlock as IRQ */
|
||||
int gpiochip_lock_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 */
|
||||
static inline void *gpiochip_get_data(struct gpio_chip *chip)
|
||||
{
|
||||
return chip->data;
|
||||
}
|
||||
void *gpiochip_get_data(struct gpio_chip *chip);
|
||||
|
||||
struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc);
|
||||
|
||||
|
@ -138,6 +138,7 @@ header-y += genetlink.h
|
||||
header-y += gen_stats.h
|
||||
header-y += gfs2_ondisk.h
|
||||
header-y += gigaset_dev.h
|
||||
header-y += gpio.h
|
||||
header-y += gsmmux.h
|
||||
header-y += hdlcdrv.h
|
||||
header-y += hdlc.h
|
||||
|
56
include/uapi/linux/gpio.h
Normal file
56
include/uapi/linux/gpio.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* <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:
|
||||
@echo ' cpupower - a tool for all things x86 CPU power'
|
||||
@echo ' firewire - the userspace part of nosy, an IEEE-1394 traffic sniffer'
|
||||
@echo ' freefall - laptop accelerometer program for disk protection'
|
||||
@echo ' gpio - GPIO tools'
|
||||
@echo ' hv - tools used when in Hyper-V clients'
|
||||
@echo ' iio - IIO tools'
|
||||
@echo ' lguest - a minimal 32-bit x86 hypervisor'
|
||||
@ -53,7 +54,7 @@ acpi: FORCE
|
||||
cpupower: FORCE
|
||||
$(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,$@)
|
||||
|
||||
liblockdep: FORCE
|
||||
@ -119,7 +120,7 @@ acpi_clean:
|
||||
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)
|
||||
|
||||
liblockdep_clean:
|
||||
@ -155,6 +156,7 @@ build_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 \
|
||||
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
|
||||
|
12
tools/gpio/Makefile
Normal file
12
tools/gpio/Makefile
Normal file
@ -0,0 +1,12 @@
|
||||
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
|
11
tools/gpio/gpio-utils.c
Normal file
11
tools/gpio/gpio-utils.c
Normal file
@ -0,0 +1,11 @@
|
||||
/*
|
||||
* 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"
|
27
tools/gpio/gpio-utils.h
Normal file
27
tools/gpio/gpio-utils.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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_ */
|
195
tools/gpio/lsgpio.c
Normal file
195
tools/gpio/lsgpio.c
Normal file
@ -0,0 +1,195 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user