So this is the LW GPIO patch stack for v3.7:
- refactoring from Thierry Redding at Arnd Bergmann's request to use the seq_file iterator interface in gpiolib. - A new driver for Avionic Design's N-bit GPIO expander. - Two instances of mutexes replaced by spinlocks from Axel Lin to code that is supposed to be fastpath compliant. - IRQ demuxer and gpio_to_irq() support for pcf857x by Kuninori Morimoto. - Dynamic GPIO numbers, device tree support, daisy chaining and some other fixes for the 74x164 driver by Maxime Ripard. - IRQ domain and device tree support for the tc3589x driver by Lee Jones. - Some conversion to use managed resources devm_* code. - Some instances of clk_prepare() or clk_prepare_enable() added to support the new, stricter common clock framework. - Some for_each_set_bit() simplifications. - Then a lot of fixes as we fixed up all of the above tripping over our own shoelaces and that kind of thing. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.12 (GNU/Linux) iQIcBAABAgAGBQJQafMcAAoJEEEQszewGV1znvsP/2CZusf05+XiCHZO7LGsBo+h WrVNB/XxrpgW7EEqpTPJCh2leM/hXs1uOYoQq0v8ICEJLwdIox8jYsnPL7NUWpN4 mcM9YCqH65Ljt07Ec25bTRzkIy881nYfvK7nUo7DZH8sq2eX53Vxqkr/IS3ZKQVj T1Kd7GHmfje2FrnL5O0owT3zNHE9VmHm1Ct9DRCRP/U2i8CSAFERJgBsoslrut13 Cnvkvwbj9Q2LQy+kIBt3PIlKb37u1Uucqa8uExvMV9cSAzG7X9h++wSgm2RioSsR mYrCRn19qzz7EATh4yUKHe56mx0KNl+/0vapqBuziTy+r0oi40VEoiSzKyfSnhFy MYgiVVnWIH9dhOTP/0QSbrYsPEeT/ZlcJKp6uu1o1MR6z3f3058Sc6FTCzeGcW88 Ayh0kT0e8iLsQ+tRmjFEEEALLKSL9Q7StH2az7Awkve3L9JCVUVXaJwynjcSIC29 8sbAV+ENTYaKOGV8uMRH+s/WpKN6w9G2gZ/qhlXem9r4/Rd529wGBlH1or8A7uLf cNuaSquN3TM5O1i26K3+rEKp5Sd7+RIMpQCMsuiEpQd1UnbB2Z1X4xjjLYwKqHFj fVQtu7s7tQ/o/hYzTn9hP4Cqj4SDB+EaDmAqq0yJH2DNsUtvLLug62ekatvvejc/ 6HFuiVOYkigSRbl7sDoV =jbUM -----END PGP SIGNATURE----- Merge tag 'gpio-for-v3.7' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio Pull GPIO changes from Linus Walleij: "So this is the LW GPIO patch stack for v3.7: - refactoring from Thierry Redding at Arnd Bergmann's request to use the seq_file iterator interface in gpiolib. - A new driver for Avionic Design's N-bit GPIO expander. - Two instances of mutexes replaced by spinlocks from Axel Lin to code that is supposed to be fastpath compliant. - IRQ demuxer and gpio_to_irq() support for pcf857x by Kuninori Morimoto. - Dynamic GPIO numbers, device tree support, daisy chaining and some other fixes for the 74x164 driver by Maxime Ripard. - IRQ domain and device tree support for the tc3589x driver by Lee Jones. - Some conversion to use managed resources devm_* code. - Some instances of clk_prepare() or clk_prepare_enable() added to support the new, stricter common clock framework. - Some for_each_set_bit() simplifications. - Then a lot of fixes as we fixed up all of the above tripping over our own shoelaces and that kind of thing." * tag 'gpio-for-v3.7' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (34 commits) gpio: pcf857x: select IRQ_DOMAIN gpio: Document device_node's det_debounce gpio-lpc32xx: Add GPI_28 gpio: adnp: dt: Reference generic interrupt binding gpio: Add Avionic Design N-bit GPIO expander support gpio: pxa: using for_each_set_bit to simplify the code gpio_msm: using for_each_set_bit to simplify the code gpio: Enable the tc3298x GPIO expander driver for Device Tree gpio: Provide the tc3589x GPIO expander driver with an IRQ domain ARM: shmobile: kzm9g: use gpio-keys instead of gpio-keys-polled gpio: pcf857x: fixup smatch WARNING gpio: 74x164: Add support for the daisy-chaining gpio: 74x164: dts: Add documentation for the dt binding dt: Fix incorrect reference in gpio-led documentation gpio: 74x164: Add device tree support gpio: 74x164: Use dynamic gpio number assignment if no pdata is present gpio: 74x164: Use devm_kzalloc gpio: 74x164: Use module_spi_driver boiler plate function gpio: sx150x: Use irq_data_get_irq_chip_data() at appropriate places gpio: em: Use irq_data_get_irq_chip_data() at appropriate places ...
This commit is contained in:
Коммит
dff8360a4a
|
@ -0,0 +1,22 @@
|
|||
* Generic 8-bits shift register GPIO driver
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be "fairchild,74hc595"
|
||||
- reg : chip select number
|
||||
- gpio-controller : Marks the device node as a gpio controller.
|
||||
- #gpio-cells : Should be two. The first cell is the pin number and
|
||||
the second cell is used to specify the gpio polarity:
|
||||
0 = active high
|
||||
1 = active low
|
||||
- registers-number: Number of daisy-chained shift registers
|
||||
|
||||
Example:
|
||||
|
||||
gpio5: gpio5@0 {
|
||||
compatible = "fairchild,74hc595";
|
||||
reg = <0>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
registers-number = <4>;
|
||||
spi-max-frequency = <100000>;
|
||||
};
|
|
@ -0,0 +1,34 @@
|
|||
Avionic Design N-bit GPIO expander bindings
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "ad,gpio-adnp"
|
||||
- reg: The I2C slave address for this device.
|
||||
- interrupt-parent: phandle of the parent interrupt controller.
|
||||
- interrupts: Interrupt specifier for the controllers interrupt.
|
||||
- #gpio-cells: Should be 2. The first cell is the GPIO number and the
|
||||
second cell is used to specify optional parameters:
|
||||
- bit 0: polarity (0: normal, 1: inverted)
|
||||
- gpio-controller: Marks the device as a GPIO controller
|
||||
- nr-gpios: The number of pins supported by the controller.
|
||||
|
||||
The GPIO expander can optionally be used as an interrupt controller, in
|
||||
which case it uses the default two cell specifier as described in
|
||||
Documentation/devicetree/bindings/interrupt-controller/interrupts.txt.
|
||||
|
||||
Example:
|
||||
|
||||
gpioext: gpio-controller@41 {
|
||||
compatible = "ad,gpio-adnp";
|
||||
reg = <0x41>;
|
||||
|
||||
interrupt-parent = <&gpio>;
|
||||
interrupts = <160 1>;
|
||||
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
|
||||
nr-gpios = <64>;
|
||||
};
|
|
@ -8,7 +8,7 @@ node's name represents the name of the corresponding LED.
|
|||
|
||||
LED sub-node properties:
|
||||
- gpios : Should specify the LED's GPIO, see "gpios property" in
|
||||
Documentation/devicetree/gpio.txt. Active low LEDs should be
|
||||
Documentation/devicetree/bindings/gpio/gpio.txt. Active low LEDs should be
|
||||
indicated using flags in the GPIO specifier.
|
||||
- label : (optional) The label for this LED. If omitted, the label is
|
||||
taken from the node name (excluding the unit address).
|
||||
|
|
|
@ -23,7 +23,6 @@ CONFIG_MODULE_UNLOAD=y
|
|||
# CONFIG_IOSCHED_DEADLINE is not set
|
||||
# CONFIG_IOSCHED_CFQ is not set
|
||||
CONFIG_ARCH_SHMOBILE=y
|
||||
CONFIG_KEYBOARD_GPIO_POLLED=y
|
||||
CONFIG_ARCH_SH73A0=y
|
||||
CONFIG_MACH_KZM9G=y
|
||||
CONFIG_MEMORY_START=0x41000000
|
||||
|
@ -71,6 +70,7 @@ CONFIG_INPUT_SPARSEKMAP=y
|
|||
# CONFIG_INPUT_MOUSEDEV is not set
|
||||
CONFIG_INPUT_EVDEV=y
|
||||
# CONFIG_KEYBOARD_ATKBD is not set
|
||||
CONFIG_KEYBOARD_GPIO=y
|
||||
# CONFIG_INPUT_MOUSE is not set
|
||||
CONFIG_INPUT_TOUCHSCREEN=y
|
||||
CONFIG_TOUCHSCREEN_ST1232=y
|
||||
|
|
|
@ -482,12 +482,10 @@ static struct gpio_keys_button gpio_buttons[] = {
|
|||
static struct gpio_keys_platform_data gpio_key_info = {
|
||||
.buttons = gpio_buttons,
|
||||
.nbuttons = ARRAY_SIZE(gpio_buttons),
|
||||
.poll_interval = 250, /* poling at this point */
|
||||
};
|
||||
|
||||
static struct platform_device gpio_keys_device = {
|
||||
/* gpio-pcf857x.c driver doesn't support gpio_to_irq() */
|
||||
.name = "gpio-keys-polled",
|
||||
.name = "gpio-keys",
|
||||
.dev = {
|
||||
.platform_data = &gpio_key_info,
|
||||
},
|
||||
|
@ -550,6 +548,7 @@ static struct platform_device fsi_ak4648_device = {
|
|||
/* I2C */
|
||||
static struct pcf857x_platform_data pcf8575_pdata = {
|
||||
.gpio_base = GPIO_PCF8575_BASE,
|
||||
.irq = intcs_evt2irq(0x3260), /* IRQ19 */
|
||||
};
|
||||
|
||||
static struct i2c_board_info i2c0_devices[] = {
|
||||
|
|
|
@ -82,7 +82,7 @@ config GPIO_GENERIC
|
|||
|
||||
config GPIO_DA9052
|
||||
tristate "Dialog DA9052 GPIO"
|
||||
depends on PMIC_DA9052 && BROKEN
|
||||
depends on PMIC_DA9052
|
||||
help
|
||||
Say yes here to enable the GPIO driver for the DA9052 chip.
|
||||
|
||||
|
@ -330,6 +330,7 @@ config GPIO_PCA953X_IRQ
|
|||
config GPIO_PCF857X
|
||||
tristate "PCF857x, PCA{85,96}7x, and MAX732[89] I2C GPIO expanders"
|
||||
depends on I2C
|
||||
select IRQ_DOMAIN
|
||||
help
|
||||
Say yes here to provide access to most "quasi-bidirectional" I2C
|
||||
GPIO expanders used for additional digital outputs or inputs.
|
||||
|
@ -450,6 +451,17 @@ config GPIO_ADP5588_IRQ
|
|||
Say yes here to enable the adp5588 to be used as an interrupt
|
||||
controller. It requires the driver to be built in the kernel.
|
||||
|
||||
config GPIO_ADNP
|
||||
tristate "Avionic Design N-bit GPIO expander"
|
||||
depends on I2C && OF
|
||||
help
|
||||
This option enables support for N GPIOs found on Avionic Design
|
||||
I2C GPIO expanders. The register space will be extended by powers
|
||||
of two, so the controller will need to accomodate for that. For
|
||||
example: if a controller provides 48 pins, 6 registers will be
|
||||
enough to represent all pins, but the driver will assume a
|
||||
register layout for 64 pins (8 registers).
|
||||
|
||||
comment "PCI GPIO expanders:"
|
||||
|
||||
config GPIO_CS5535
|
||||
|
|
|
@ -10,6 +10,7 @@ obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o
|
|||
|
||||
obj-$(CONFIG_GPIO_74X164) += gpio-74x164.o
|
||||
obj-$(CONFIG_GPIO_AB8500) += gpio-ab8500.o
|
||||
obj-$(CONFIG_GPIO_ADNP) += gpio-adnp.o
|
||||
obj-$(CONFIG_GPIO_ADP5520) += gpio-adp5520.o
|
||||
obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o
|
||||
obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o
|
||||
|
|
|
@ -14,14 +14,18 @@
|
|||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/74x164.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#define GEN_74X164_NUMBER_GPIOS 8
|
||||
|
||||
struct gen_74x164_chip {
|
||||
struct spi_device *spi;
|
||||
u8 *buffer;
|
||||
struct gpio_chip gpio_chip;
|
||||
struct mutex lock;
|
||||
u8 port_config;
|
||||
u32 registers;
|
||||
};
|
||||
|
||||
static struct gen_74x164_chip *gpio_to_74x164_chip(struct gpio_chip *gc)
|
||||
|
@ -31,17 +35,47 @@ static struct gen_74x164_chip *gpio_to_74x164_chip(struct gpio_chip *gc)
|
|||
|
||||
static int __gen_74x164_write_config(struct gen_74x164_chip *chip)
|
||||
{
|
||||
return spi_write(chip->spi,
|
||||
&chip->port_config, sizeof(chip->port_config));
|
||||
struct spi_message message;
|
||||
struct spi_transfer *msg_buf;
|
||||
int i, ret = 0;
|
||||
|
||||
msg_buf = kzalloc(chip->registers * sizeof(struct spi_transfer),
|
||||
GFP_KERNEL);
|
||||
if (!msg_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
spi_message_init(&message);
|
||||
|
||||
/*
|
||||
* Since the registers are chained, every byte sent will make
|
||||
* the previous byte shift to the next register in the
|
||||
* chain. Thus, the first byte send will end up in the last
|
||||
* register at the end of the transfer. So, to have a logical
|
||||
* numbering, send the bytes in reverse order so that the last
|
||||
* byte of the buffer will end up in the last register.
|
||||
*/
|
||||
for (i = chip->registers - 1; i >= 0; i--) {
|
||||
msg_buf[i].tx_buf = chip->buffer +i;
|
||||
msg_buf[i].len = sizeof(u8);
|
||||
spi_message_add_tail(msg_buf + i, &message);
|
||||
}
|
||||
|
||||
ret = spi_sync(chip->spi, &message);
|
||||
|
||||
kfree(msg_buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gen_74x164_get_value(struct gpio_chip *gc, unsigned offset)
|
||||
{
|
||||
struct gen_74x164_chip *chip = gpio_to_74x164_chip(gc);
|
||||
u8 bank = offset / 8;
|
||||
u8 pin = offset % 8;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&chip->lock);
|
||||
ret = (chip->port_config >> offset) & 0x1;
|
||||
ret = (chip->buffer[bank] >> pin) & 0x1;
|
||||
mutex_unlock(&chip->lock);
|
||||
|
||||
return ret;
|
||||
|
@ -51,12 +85,14 @@ static void gen_74x164_set_value(struct gpio_chip *gc,
|
|||
unsigned offset, int val)
|
||||
{
|
||||
struct gen_74x164_chip *chip = gpio_to_74x164_chip(gc);
|
||||
u8 bank = offset / 8;
|
||||
u8 pin = offset % 8;
|
||||
|
||||
mutex_lock(&chip->lock);
|
||||
if (val)
|
||||
chip->port_config |= (1 << offset);
|
||||
chip->buffer[bank] |= (1 << pin);
|
||||
else
|
||||
chip->port_config &= ~(1 << offset);
|
||||
chip->buffer[bank] &= ~(1 << pin);
|
||||
|
||||
__gen_74x164_write_config(chip);
|
||||
mutex_unlock(&chip->lock);
|
||||
|
@ -75,9 +111,8 @@ static int __devinit gen_74x164_probe(struct spi_device *spi)
|
|||
struct gen_74x164_chip_platform_data *pdata;
|
||||
int ret;
|
||||
|
||||
pdata = spi->dev.platform_data;
|
||||
if (!pdata || !pdata->base) {
|
||||
dev_dbg(&spi->dev, "incorrect or missing platform data\n");
|
||||
if (!spi->dev.of_node) {
|
||||
dev_err(&spi->dev, "No device tree data available.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -90,10 +125,16 @@ static int __devinit gen_74x164_probe(struct spi_device *spi)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
|
||||
chip = devm_kzalloc(&spi->dev, sizeof(*chip), GFP_KERNEL);
|
||||
if (!chip)
|
||||
return -ENOMEM;
|
||||
|
||||
pdata = spi->dev.platform_data;
|
||||
if (pdata && pdata->base)
|
||||
chip->gpio_chip.base = pdata->base;
|
||||
else
|
||||
chip->gpio_chip.base = -1;
|
||||
|
||||
mutex_init(&chip->lock);
|
||||
|
||||
dev_set_drvdata(&spi->dev, chip);
|
||||
|
@ -104,8 +145,20 @@ static int __devinit gen_74x164_probe(struct spi_device *spi)
|
|||
chip->gpio_chip.direction_output = gen_74x164_direction_output;
|
||||
chip->gpio_chip.get = gen_74x164_get_value;
|
||||
chip->gpio_chip.set = gen_74x164_set_value;
|
||||
chip->gpio_chip.base = pdata->base;
|
||||
chip->gpio_chip.ngpio = 8;
|
||||
|
||||
if (of_property_read_u32(spi->dev.of_node, "registers-number", &chip->registers)) {
|
||||
dev_err(&spi->dev, "Missing registers-number property in the DT.\n");
|
||||
ret = -EINVAL;
|
||||
goto exit_destroy;
|
||||
}
|
||||
|
||||
chip->gpio_chip.ngpio = GEN_74X164_NUMBER_GPIOS * chip->registers;
|
||||
chip->buffer = devm_kzalloc(&spi->dev, chip->gpio_chip.ngpio, GFP_KERNEL);
|
||||
if (!chip->buffer) {
|
||||
ret = -ENOMEM;
|
||||
goto exit_destroy;
|
||||
}
|
||||
|
||||
chip->gpio_chip.can_sleep = 1;
|
||||
chip->gpio_chip.dev = &spi->dev;
|
||||
chip->gpio_chip.owner = THIS_MODULE;
|
||||
|
@ -125,7 +178,6 @@ static int __devinit gen_74x164_probe(struct spi_device *spi)
|
|||
exit_destroy:
|
||||
dev_set_drvdata(&spi->dev, NULL);
|
||||
mutex_destroy(&chip->lock);
|
||||
kfree(chip);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -141,36 +193,31 @@ static int __devexit gen_74x164_remove(struct spi_device *spi)
|
|||
dev_set_drvdata(&spi->dev, NULL);
|
||||
|
||||
ret = gpiochip_remove(&chip->gpio_chip);
|
||||
if (!ret) {
|
||||
if (!ret)
|
||||
mutex_destroy(&chip->lock);
|
||||
kfree(chip);
|
||||
} else
|
||||
else
|
||||
dev_err(&spi->dev, "Failed to remove the GPIO controller: %d\n",
|
||||
ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct of_device_id gen_74x164_dt_ids[] = {
|
||||
{ .compatible = "fairchild,74hc595" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, gen_74x164_dt_ids);
|
||||
|
||||
static struct spi_driver gen_74x164_driver = {
|
||||
.driver = {
|
||||
.name = "74x164",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(gen_74x164_dt_ids),
|
||||
},
|
||||
.probe = gen_74x164_probe,
|
||||
.remove = __devexit_p(gen_74x164_remove),
|
||||
};
|
||||
|
||||
static int __init gen_74x164_init(void)
|
||||
{
|
||||
return spi_register_driver(&gen_74x164_driver);
|
||||
}
|
||||
subsys_initcall(gen_74x164_init);
|
||||
|
||||
static void __exit gen_74x164_exit(void)
|
||||
{
|
||||
spi_unregister_driver(&gen_74x164_driver);
|
||||
}
|
||||
module_exit(gen_74x164_exit);
|
||||
module_spi_driver(gen_74x164_driver);
|
||||
|
||||
MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
|
||||
MODULE_AUTHOR("Miguel Gaio <miguel.gaio@efixo.com>");
|
||||
|
|
|
@ -0,0 +1,611 @@
|
|||
/*
|
||||
* Copyright (C) 2011-2012 Avionic Design GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define GPIO_DDR(gpio) (0x00 << (gpio)->reg_shift)
|
||||
#define GPIO_PLR(gpio) (0x01 << (gpio)->reg_shift)
|
||||
#define GPIO_IER(gpio) (0x02 << (gpio)->reg_shift)
|
||||
#define GPIO_ISR(gpio) (0x03 << (gpio)->reg_shift)
|
||||
#define GPIO_PTR(gpio) (0x04 << (gpio)->reg_shift)
|
||||
|
||||
struct adnp {
|
||||
struct i2c_client *client;
|
||||
struct gpio_chip gpio;
|
||||
unsigned int reg_shift;
|
||||
|
||||
struct mutex i2c_lock;
|
||||
|
||||
struct irq_domain *domain;
|
||||
struct mutex irq_lock;
|
||||
|
||||
u8 *irq_enable;
|
||||
u8 *irq_level;
|
||||
u8 *irq_rise;
|
||||
u8 *irq_fall;
|
||||
u8 *irq_high;
|
||||
u8 *irq_low;
|
||||
};
|
||||
|
||||
static inline struct adnp *to_adnp(struct gpio_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct adnp, gpio);
|
||||
}
|
||||
|
||||
static int adnp_read(struct adnp *adnp, unsigned offset, uint8_t *value)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = i2c_smbus_read_byte_data(adnp->client, offset);
|
||||
if (err < 0) {
|
||||
dev_err(adnp->gpio.dev, "%s failed: %d\n",
|
||||
"i2c_smbus_read_byte_data()", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
*value = err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adnp_write(struct adnp *adnp, unsigned offset, uint8_t value)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = i2c_smbus_write_byte_data(adnp->client, offset, value);
|
||||
if (err < 0) {
|
||||
dev_err(adnp->gpio.dev, "%s failed: %d\n",
|
||||
"i2c_smbus_write_byte_data()", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adnp_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct adnp *adnp = to_adnp(chip);
|
||||
unsigned int reg = offset >> adnp->reg_shift;
|
||||
unsigned int pos = offset & 7;
|
||||
u8 value;
|
||||
int err;
|
||||
|
||||
err = adnp_read(adnp, GPIO_PLR(adnp) + reg, &value);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return (value & BIT(pos)) ? 1 : 0;
|
||||
}
|
||||
|
||||
static void __adnp_gpio_set(struct adnp *adnp, unsigned offset, int value)
|
||||
{
|
||||
unsigned int reg = offset >> adnp->reg_shift;
|
||||
unsigned int pos = offset & 7;
|
||||
int err;
|
||||
u8 val;
|
||||
|
||||
err = adnp_read(adnp, GPIO_PLR(adnp) + reg, &val);
|
||||
if (err < 0)
|
||||
return;
|
||||
|
||||
if (value)
|
||||
val |= BIT(pos);
|
||||
else
|
||||
val &= ~BIT(pos);
|
||||
|
||||
adnp_write(adnp, GPIO_PLR(adnp) + reg, val);
|
||||
}
|
||||
|
||||
static void adnp_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
||||
{
|
||||
struct adnp *adnp = to_adnp(chip);
|
||||
|
||||
mutex_lock(&adnp->i2c_lock);
|
||||
__adnp_gpio_set(adnp, offset, value);
|
||||
mutex_unlock(&adnp->i2c_lock);
|
||||
}
|
||||
|
||||
static int adnp_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct adnp *adnp = to_adnp(chip);
|
||||
unsigned int reg = offset >> adnp->reg_shift;
|
||||
unsigned int pos = offset & 7;
|
||||
u8 value;
|
||||
int err;
|
||||
|
||||
mutex_lock(&adnp->i2c_lock);
|
||||
|
||||
err = adnp_read(adnp, GPIO_DDR(adnp) + reg, &value);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
value &= ~BIT(pos);
|
||||
|
||||
err = adnp_write(adnp, GPIO_DDR(adnp) + reg, value);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
err = adnp_read(adnp, GPIO_DDR(adnp) + reg, &value);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
if (err & BIT(pos))
|
||||
err = -EACCES;
|
||||
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
mutex_unlock(&adnp->i2c_lock);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int adnp_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
|
||||
int value)
|
||||
{
|
||||
struct adnp *adnp = to_adnp(chip);
|
||||
unsigned int reg = offset >> adnp->reg_shift;
|
||||
unsigned int pos = offset & 7;
|
||||
int err;
|
||||
u8 val;
|
||||
|
||||
mutex_lock(&adnp->i2c_lock);
|
||||
|
||||
err = adnp_read(adnp, GPIO_DDR(adnp) + reg, &val);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
val |= BIT(pos);
|
||||
|
||||
err = adnp_write(adnp, GPIO_DDR(adnp) + reg, val);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
err = adnp_read(adnp, GPIO_DDR(adnp) + reg, &val);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
if (!(val & BIT(pos))) {
|
||||
err = -EPERM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
__adnp_gpio_set(adnp, offset, value);
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
mutex_unlock(&adnp->i2c_lock);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void adnp_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
|
||||
{
|
||||
struct adnp *adnp = to_adnp(chip);
|
||||
unsigned int num_regs = 1 << adnp->reg_shift, i, j;
|
||||
int err;
|
||||
|
||||
for (i = 0; i < num_regs; i++) {
|
||||
u8 ddr, plr, ier, isr;
|
||||
|
||||
mutex_lock(&adnp->i2c_lock);
|
||||
|
||||
err = adnp_read(adnp, GPIO_DDR(adnp) + i, &ddr);
|
||||
if (err < 0) {
|
||||
mutex_unlock(&adnp->i2c_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
err = adnp_read(adnp, GPIO_PLR(adnp) + i, &plr);
|
||||
if (err < 0) {
|
||||
mutex_unlock(&adnp->i2c_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
err = adnp_read(adnp, GPIO_IER(adnp) + i, &ier);
|
||||
if (err < 0) {
|
||||
mutex_unlock(&adnp->i2c_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
err = adnp_read(adnp, GPIO_ISR(adnp) + i, &isr);
|
||||
if (err < 0) {
|
||||
mutex_unlock(&adnp->i2c_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
mutex_unlock(&adnp->i2c_lock);
|
||||
|
||||
for (j = 0; j < 8; j++) {
|
||||
unsigned int bit = (i << adnp->reg_shift) + j;
|
||||
const char *direction = "input ";
|
||||
const char *level = "low ";
|
||||
const char *interrupt = "disabled";
|
||||
const char *pending = "";
|
||||
|
||||
if (ddr & BIT(j))
|
||||
direction = "output";
|
||||
|
||||
if (plr & BIT(j))
|
||||
level = "high";
|
||||
|
||||
if (ier & BIT(j))
|
||||
interrupt = "enabled ";
|
||||
|
||||
if (isr & BIT(j))
|
||||
pending = "pending";
|
||||
|
||||
seq_printf(s, "%2u: %s %s IRQ %s %s\n", bit,
|
||||
direction, level, interrupt, pending);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int adnp_gpio_setup(struct adnp *adnp, unsigned int num_gpios)
|
||||
{
|
||||
struct gpio_chip *chip = &adnp->gpio;
|
||||
|
||||
adnp->reg_shift = get_count_order(num_gpios) - 3;
|
||||
|
||||
chip->direction_input = adnp_gpio_direction_input;
|
||||
chip->direction_output = adnp_gpio_direction_output;
|
||||
chip->get = adnp_gpio_get;
|
||||
chip->set = adnp_gpio_set;
|
||||
chip->can_sleep = 1;
|
||||
|
||||
if (IS_ENABLED(CONFIG_DEBUG_FS))
|
||||
chip->dbg_show = adnp_gpio_dbg_show;
|
||||
|
||||
chip->base = -1;
|
||||
chip->ngpio = num_gpios;
|
||||
chip->label = adnp->client->name;
|
||||
chip->dev = &adnp->client->dev;
|
||||
chip->of_node = chip->dev->of_node;
|
||||
chip->owner = THIS_MODULE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t adnp_irq(int irq, void *data)
|
||||
{
|
||||
struct adnp *adnp = data;
|
||||
unsigned int num_regs, i;
|
||||
|
||||
num_regs = 1 << adnp->reg_shift;
|
||||
|
||||
for (i = 0; i < num_regs; i++) {
|
||||
unsigned int base = i << adnp->reg_shift, bit;
|
||||
u8 changed, level, isr, ier;
|
||||
unsigned long pending;
|
||||
int err;
|
||||
|
||||
mutex_lock(&adnp->i2c_lock);
|
||||
|
||||
err = adnp_read(adnp, GPIO_PLR(adnp) + i, &level);
|
||||
if (err < 0) {
|
||||
mutex_unlock(&adnp->i2c_lock);
|
||||
continue;
|
||||
}
|
||||
|
||||
err = adnp_read(adnp, GPIO_ISR(adnp) + i, &isr);
|
||||
if (err < 0) {
|
||||
mutex_unlock(&adnp->i2c_lock);
|
||||
continue;
|
||||
}
|
||||
|
||||
err = adnp_read(adnp, GPIO_IER(adnp) + i, &ier);
|
||||
if (err < 0) {
|
||||
mutex_unlock(&adnp->i2c_lock);
|
||||
continue;
|
||||
}
|
||||
|
||||
mutex_unlock(&adnp->i2c_lock);
|
||||
|
||||
/* determine pins that changed levels */
|
||||
changed = level ^ adnp->irq_level[i];
|
||||
|
||||
/* compute edge-triggered interrupts */
|
||||
pending = changed & ((adnp->irq_fall[i] & ~level) |
|
||||
(adnp->irq_rise[i] & level));
|
||||
|
||||
/* add in level-triggered interrupts */
|
||||
pending |= (adnp->irq_high[i] & level) |
|
||||
(adnp->irq_low[i] & ~level);
|
||||
|
||||
/* mask out non-pending and disabled interrupts */
|
||||
pending &= isr & ier;
|
||||
|
||||
for_each_set_bit(bit, &pending, 8) {
|
||||
unsigned int virq;
|
||||
virq = irq_find_mapping(adnp->domain, base + bit);
|
||||
handle_nested_irq(virq);
|
||||
}
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int adnp_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct adnp *adnp = to_adnp(chip);
|
||||
return irq_create_mapping(adnp->domain, offset);
|
||||
}
|
||||
|
||||
static void adnp_irq_mask(struct irq_data *data)
|
||||
{
|
||||
struct adnp *adnp = irq_data_get_irq_chip_data(data);
|
||||
unsigned int reg = data->hwirq >> adnp->reg_shift;
|
||||
unsigned int pos = data->hwirq & 7;
|
||||
|
||||
adnp->irq_enable[reg] &= ~BIT(pos);
|
||||
}
|
||||
|
||||
static void adnp_irq_unmask(struct irq_data *data)
|
||||
{
|
||||
struct adnp *adnp = irq_data_get_irq_chip_data(data);
|
||||
unsigned int reg = data->hwirq >> adnp->reg_shift;
|
||||
unsigned int pos = data->hwirq & 7;
|
||||
|
||||
adnp->irq_enable[reg] |= BIT(pos);
|
||||
}
|
||||
|
||||
static int adnp_irq_set_type(struct irq_data *data, unsigned int type)
|
||||
{
|
||||
struct adnp *adnp = irq_data_get_irq_chip_data(data);
|
||||
unsigned int reg = data->hwirq >> adnp->reg_shift;
|
||||
unsigned int pos = data->hwirq & 7;
|
||||
|
||||
if (type & IRQ_TYPE_EDGE_RISING)
|
||||
adnp->irq_rise[reg] |= BIT(pos);
|
||||
else
|
||||
adnp->irq_rise[reg] &= ~BIT(pos);
|
||||
|
||||
if (type & IRQ_TYPE_EDGE_FALLING)
|
||||
adnp->irq_fall[reg] |= BIT(pos);
|
||||
else
|
||||
adnp->irq_fall[reg] &= ~BIT(pos);
|
||||
|
||||
if (type & IRQ_TYPE_LEVEL_HIGH)
|
||||
adnp->irq_high[reg] |= BIT(pos);
|
||||
else
|
||||
adnp->irq_high[reg] &= ~BIT(pos);
|
||||
|
||||
if (type & IRQ_TYPE_LEVEL_LOW)
|
||||
adnp->irq_low[reg] |= BIT(pos);
|
||||
else
|
||||
adnp->irq_low[reg] &= ~BIT(pos);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void adnp_irq_bus_lock(struct irq_data *data)
|
||||
{
|
||||
struct adnp *adnp = irq_data_get_irq_chip_data(data);
|
||||
|
||||
mutex_lock(&adnp->irq_lock);
|
||||
}
|
||||
|
||||
static void adnp_irq_bus_unlock(struct irq_data *data)
|
||||
{
|
||||
struct adnp *adnp = irq_data_get_irq_chip_data(data);
|
||||
unsigned int num_regs = 1 << adnp->reg_shift, i;
|
||||
|
||||
mutex_lock(&adnp->i2c_lock);
|
||||
|
||||
for (i = 0; i < num_regs; i++)
|
||||
adnp_write(adnp, GPIO_IER(adnp) + i, adnp->irq_enable[i]);
|
||||
|
||||
mutex_unlock(&adnp->i2c_lock);
|
||||
mutex_unlock(&adnp->irq_lock);
|
||||
}
|
||||
|
||||
static struct irq_chip adnp_irq_chip = {
|
||||
.name = "gpio-adnp",
|
||||
.irq_mask = adnp_irq_mask,
|
||||
.irq_unmask = adnp_irq_unmask,
|
||||
.irq_set_type = adnp_irq_set_type,
|
||||
.irq_bus_lock = adnp_irq_bus_lock,
|
||||
.irq_bus_sync_unlock = adnp_irq_bus_unlock,
|
||||
};
|
||||
|
||||
static int adnp_irq_map(struct irq_domain *domain, unsigned int irq,
|
||||
irq_hw_number_t hwirq)
|
||||
{
|
||||
irq_set_chip_data(irq, domain->host_data);
|
||||
irq_set_chip(irq, &adnp_irq_chip);
|
||||
irq_set_nested_thread(irq, true);
|
||||
|
||||
#ifdef CONFIG_ARM
|
||||
set_irq_flags(irq, IRQF_VALID);
|
||||
#else
|
||||
irq_set_noprobe(irq);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct irq_domain_ops adnp_irq_domain_ops = {
|
||||
.map = adnp_irq_map,
|
||||
.xlate = irq_domain_xlate_twocell,
|
||||
};
|
||||
|
||||
static int adnp_irq_setup(struct adnp *adnp)
|
||||
{
|
||||
unsigned int num_regs = 1 << adnp->reg_shift, i;
|
||||
struct gpio_chip *chip = &adnp->gpio;
|
||||
int err;
|
||||
|
||||
mutex_init(&adnp->irq_lock);
|
||||
|
||||
/*
|
||||
* Allocate memory to keep track of the current level and trigger
|
||||
* modes of the interrupts. To avoid multiple allocations, a single
|
||||
* large buffer is allocated and pointers are setup to point at the
|
||||
* corresponding offsets. For consistency, the layout of the buffer
|
||||
* is chosen to match the register layout of the hardware in that
|
||||
* each segment contains the corresponding bits for all interrupts.
|
||||
*/
|
||||
adnp->irq_enable = devm_kzalloc(chip->dev, num_regs * 6, GFP_KERNEL);
|
||||
if (!adnp->irq_enable)
|
||||
return -ENOMEM;
|
||||
|
||||
adnp->irq_level = adnp->irq_enable + (num_regs * 1);
|
||||
adnp->irq_rise = adnp->irq_enable + (num_regs * 2);
|
||||
adnp->irq_fall = adnp->irq_enable + (num_regs * 3);
|
||||
adnp->irq_high = adnp->irq_enable + (num_regs * 4);
|
||||
adnp->irq_low = adnp->irq_enable + (num_regs * 5);
|
||||
|
||||
for (i = 0; i < num_regs; i++) {
|
||||
/*
|
||||
* Read the initial level of all pins to allow the emulation
|
||||
* of edge triggered interrupts.
|
||||
*/
|
||||
err = adnp_read(adnp, GPIO_PLR(adnp) + i, &adnp->irq_level[i]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* disable all interrupts */
|
||||
err = adnp_write(adnp, GPIO_IER(adnp) + i, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
adnp->irq_enable[i] = 0x00;
|
||||
}
|
||||
|
||||
adnp->domain = irq_domain_add_linear(chip->of_node, chip->ngpio,
|
||||
&adnp_irq_domain_ops, adnp);
|
||||
|
||||
err = request_threaded_irq(adnp->client->irq, NULL, adnp_irq,
|
||||
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
|
||||
dev_name(chip->dev), adnp);
|
||||
if (err != 0) {
|
||||
dev_err(chip->dev, "can't request IRQ#%d: %d\n",
|
||||
adnp->client->irq, err);
|
||||
goto error;
|
||||
}
|
||||
|
||||
chip->to_irq = adnp_gpio_to_irq;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
irq_domain_remove(adnp->domain);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void adnp_irq_teardown(struct adnp *adnp)
|
||||
{
|
||||
unsigned int irq, i;
|
||||
|
||||
free_irq(adnp->client->irq, adnp);
|
||||
|
||||
for (i = 0; i < adnp->gpio.ngpio; i++) {
|
||||
irq = irq_find_mapping(adnp->domain, i);
|
||||
if (irq > 0)
|
||||
irq_dispose_mapping(irq);
|
||||
}
|
||||
|
||||
irq_domain_remove(adnp->domain);
|
||||
}
|
||||
|
||||
static __devinit int adnp_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device_node *np = client->dev.of_node;
|
||||
struct adnp *adnp;
|
||||
u32 num_gpios;
|
||||
int err;
|
||||
|
||||
err = of_property_read_u32(np, "nr-gpios", &num_gpios);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
client->irq = irq_of_parse_and_map(np, 0);
|
||||
if (!client->irq)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
adnp = devm_kzalloc(&client->dev, sizeof(*adnp), GFP_KERNEL);
|
||||
if (!adnp)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&adnp->i2c_lock);
|
||||
adnp->client = client;
|
||||
|
||||
err = adnp_gpio_setup(adnp, num_gpios);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (of_find_property(np, "interrupt-controller", NULL)) {
|
||||
err = adnp_irq_setup(adnp);
|
||||
if (err < 0)
|
||||
goto teardown;
|
||||
}
|
||||
|
||||
err = gpiochip_add(&adnp->gpio);
|
||||
if (err < 0)
|
||||
goto teardown;
|
||||
|
||||
i2c_set_clientdata(client, adnp);
|
||||
return 0;
|
||||
|
||||
teardown:
|
||||
if (of_find_property(np, "interrupt-controller", NULL))
|
||||
adnp_irq_teardown(adnp);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static __devexit int adnp_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct adnp *adnp = i2c_get_clientdata(client);
|
||||
struct device_node *np = client->dev.of_node;
|
||||
int err;
|
||||
|
||||
err = gpiochip_remove(&adnp->gpio);
|
||||
if (err < 0) {
|
||||
dev_err(&client->dev, "%s failed: %d\n", "gpiochip_remove()",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (of_find_property(np, "interrupt-controller", NULL))
|
||||
adnp_irq_teardown(adnp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id adnp_i2c_id[] __devinitconst = {
|
||||
{ "gpio-adnp" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adnp_i2c_id);
|
||||
|
||||
static const struct of_device_id adnp_of_match[] __devinitconst = {
|
||||
{ .compatible = "ad,gpio-adnp", },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, adnp_of_match);
|
||||
|
||||
static struct i2c_driver adnp_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "gpio-adnp",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(adnp_of_match),
|
||||
},
|
||||
.probe = adnp_i2c_probe,
|
||||
.remove = __devexit_p(adnp_i2c_remove),
|
||||
.id_table = adnp_i2c_id,
|
||||
};
|
||||
module_i2c_driver(adnp_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Avionic Design N-bit GPIO expander");
|
||||
MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -483,19 +483,7 @@ static struct i2c_driver adp5588_gpio_driver = {
|
|||
.id_table = adp5588_gpio_id,
|
||||
};
|
||||
|
||||
static int __init adp5588_gpio_init(void)
|
||||
{
|
||||
return i2c_add_driver(&adp5588_gpio_driver);
|
||||
}
|
||||
|
||||
module_init(adp5588_gpio_init);
|
||||
|
||||
static void __exit adp5588_gpio_exit(void)
|
||||
{
|
||||
i2c_del_driver(&adp5588_gpio_driver);
|
||||
}
|
||||
|
||||
module_exit(adp5588_gpio_exit);
|
||||
module_i2c_driver(adp5588_gpio_driver);
|
||||
|
||||
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
|
||||
MODULE_DESCRIPTION("GPIO ADP5588 Driver");
|
||||
|
|
|
@ -310,7 +310,7 @@ static int bt8xxgpio_resume(struct pci_dev *pdev)
|
|||
#define bt8xxgpio_resume NULL
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static struct pci_device_id bt8xxgpio_pci_tbl[] = {
|
||||
static DEFINE_PCI_DEVICE_TABLE(bt8xxgpio_pci_tbl) = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878) },
|
||||
|
|
|
@ -207,7 +207,7 @@ static int __devinit da9052_gpio_probe(struct platform_device *pdev)
|
|||
struct da9052_pdata *pdata;
|
||||
int ret;
|
||||
|
||||
gpio = kzalloc(sizeof(*gpio), GFP_KERNEL);
|
||||
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
|
||||
if (gpio == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -221,28 +221,19 @@ static int __devinit da9052_gpio_probe(struct platform_device *pdev)
|
|||
ret = gpiochip_add(&gpio->gp);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
|
||||
goto err_mem;
|
||||
return ret;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, gpio);
|
||||
|
||||
return 0;
|
||||
|
||||
err_mem:
|
||||
kfree(gpio);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit da9052_gpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct da9052_gpio *gpio = platform_get_drvdata(pdev);
|
||||
int ret;
|
||||
|
||||
ret = gpiochip_remove(&gpio->gp);
|
||||
if (ret == 0)
|
||||
kfree(gpio);
|
||||
|
||||
return ret;
|
||||
return gpiochip_remove(&gpio->gp);
|
||||
}
|
||||
|
||||
static struct platform_driver da9052_gpio_driver = {
|
||||
|
|
|
@ -366,7 +366,7 @@ static int __init davinci_gpio_irq_setup(void)
|
|||
PTR_ERR(clk));
|
||||
return PTR_ERR(clk);
|
||||
}
|
||||
clk_enable(clk);
|
||||
clk_prepare_enable(clk);
|
||||
|
||||
/* Arrange gpio_to_irq() support, handling either direct IRQs or
|
||||
* banked IRQs. Having GPIOs in the first GPIO bank use direct
|
||||
|
|
|
@ -85,22 +85,16 @@ static inline void em_gio_write(struct em_gio_priv *p, int offs,
|
|||
iowrite32(value, p->base1 + (offs - GIO_IDT0));
|
||||
}
|
||||
|
||||
static inline struct em_gio_priv *irq_to_priv(struct irq_data *d)
|
||||
{
|
||||
struct irq_chip *chip = irq_data_get_irq_chip(d);
|
||||
return container_of(chip, struct em_gio_priv, irq_chip);
|
||||
}
|
||||
|
||||
static void em_gio_irq_disable(struct irq_data *d)
|
||||
{
|
||||
struct em_gio_priv *p = irq_to_priv(d);
|
||||
struct em_gio_priv *p = irq_data_get_irq_chip_data(d);
|
||||
|
||||
em_gio_write(p, GIO_IDS, BIT(irqd_to_hwirq(d)));
|
||||
}
|
||||
|
||||
static void em_gio_irq_enable(struct irq_data *d)
|
||||
{
|
||||
struct em_gio_priv *p = irq_to_priv(d);
|
||||
struct em_gio_priv *p = irq_data_get_irq_chip_data(d);
|
||||
|
||||
em_gio_write(p, GIO_IEN, BIT(irqd_to_hwirq(d)));
|
||||
}
|
||||
|
@ -118,7 +112,7 @@ static unsigned char em_gio_sense_table[IRQ_TYPE_SENSE_MASK + 1] = {
|
|||
static int em_gio_irq_set_type(struct irq_data *d, unsigned int type)
|
||||
{
|
||||
unsigned char value = em_gio_sense_table[type & IRQ_TYPE_SENSE_MASK];
|
||||
struct em_gio_priv *p = irq_to_priv(d);
|
||||
struct em_gio_priv *p = irq_data_get_irq_chip_data(d);
|
||||
unsigned int reg, offset, shift;
|
||||
unsigned long flags;
|
||||
unsigned long tmp;
|
||||
|
|
|
@ -113,7 +113,8 @@ static const char *gpi_p3_names[LPC32XX_GPI_P3_MAX] = {
|
|||
NULL, NULL, NULL, "gpi15",
|
||||
"gpi16", "gpi17", "gpi18", "gpi19",
|
||||
"gpi20", "gpi21", "gpi22", "gpi23",
|
||||
"gpi24", "gpi25", "gpi26", "gpi27"
|
||||
"gpi24", "gpi25", "gpi26", "gpi27",
|
||||
"gpi28"
|
||||
};
|
||||
|
||||
static const char *gpo_p3_names[LPC32XX_GPO_P3_MAX] = {
|
||||
|
|
|
@ -91,10 +91,9 @@ static int mc9s08dz60_direction_output(struct gpio_chip *gc,
|
|||
static int mc9s08dz60_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
int ret = 0;
|
||||
struct mc9s08dz60 *mc9s;
|
||||
|
||||
mc9s = kzalloc(sizeof(*mc9s), GFP_KERNEL);
|
||||
mc9s = devm_kzalloc(&client->dev, sizeof(*mc9s), GFP_KERNEL);
|
||||
if (!mc9s)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -110,30 +109,16 @@ static int mc9s08dz60_probe(struct i2c_client *client,
|
|||
mc9s->client = client;
|
||||
i2c_set_clientdata(client, mc9s);
|
||||
|
||||
ret = gpiochip_add(&mc9s->chip);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
kfree(mc9s);
|
||||
return ret;
|
||||
return gpiochip_add(&mc9s->chip);
|
||||
}
|
||||
|
||||
static int mc9s08dz60_remove(struct i2c_client *client)
|
||||
{
|
||||
struct mc9s08dz60 *mc9s;
|
||||
int ret;
|
||||
|
||||
mc9s = i2c_get_clientdata(client);
|
||||
|
||||
ret = gpiochip_remove(&mc9s->chip);
|
||||
if (!ret)
|
||||
kfree(mc9s);
|
||||
|
||||
return ret;
|
||||
|
||||
return gpiochip_remove(&mc9s->chip);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id mc9s08dz60_id[] = {
|
||||
|
|
|
@ -87,8 +87,7 @@ struct ioh_gpio_reg_data {
|
|||
* @gpio_use_sel: Save GPIO_USE_SEL1~4 register for PM
|
||||
* @ch: Indicate GPIO channel
|
||||
* @irq_base: Save base of IRQ number for interrupt
|
||||
* @spinlock: Used for register access protection in
|
||||
* interrupt context ioh_irq_type and PM;
|
||||
* @spinlock: Used for register access protection
|
||||
*/
|
||||
struct ioh_gpio {
|
||||
void __iomem *base;
|
||||
|
@ -97,7 +96,6 @@ struct ioh_gpio {
|
|||
struct gpio_chip gpio;
|
||||
struct ioh_gpio_reg_data ioh_gpio_reg;
|
||||
u32 gpio_use_sel;
|
||||
struct mutex lock;
|
||||
int ch;
|
||||
int irq_base;
|
||||
spinlock_t spinlock;
|
||||
|
@ -109,8 +107,9 @@ static void ioh_gpio_set(struct gpio_chip *gpio, unsigned nr, int val)
|
|||
{
|
||||
u32 reg_val;
|
||||
struct ioh_gpio *chip = container_of(gpio, struct ioh_gpio, gpio);
|
||||
unsigned long flags;
|
||||
|
||||
mutex_lock(&chip->lock);
|
||||
spin_lock_irqsave(&chip->spinlock, flags);
|
||||
reg_val = ioread32(&chip->reg->regs[chip->ch].po);
|
||||
if (val)
|
||||
reg_val |= (1 << nr);
|
||||
|
@ -118,7 +117,7 @@ static void ioh_gpio_set(struct gpio_chip *gpio, unsigned nr, int val)
|
|||
reg_val &= ~(1 << nr);
|
||||
|
||||
iowrite32(reg_val, &chip->reg->regs[chip->ch].po);
|
||||
mutex_unlock(&chip->lock);
|
||||
spin_unlock_irqrestore(&chip->spinlock, flags);
|
||||
}
|
||||
|
||||
static int ioh_gpio_get(struct gpio_chip *gpio, unsigned nr)
|
||||
|
@ -134,8 +133,9 @@ static int ioh_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
|
|||
struct ioh_gpio *chip = container_of(gpio, struct ioh_gpio, gpio);
|
||||
u32 pm;
|
||||
u32 reg_val;
|
||||
unsigned long flags;
|
||||
|
||||
mutex_lock(&chip->lock);
|
||||
spin_lock_irqsave(&chip->spinlock, flags);
|
||||
pm = ioread32(&chip->reg->regs[chip->ch].pm) &
|
||||
((1 << num_ports[chip->ch]) - 1);
|
||||
pm |= (1 << nr);
|
||||
|
@ -148,7 +148,7 @@ static int ioh_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
|
|||
reg_val &= ~(1 << nr);
|
||||
iowrite32(reg_val, &chip->reg->regs[chip->ch].po);
|
||||
|
||||
mutex_unlock(&chip->lock);
|
||||
spin_unlock_irqrestore(&chip->spinlock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -157,13 +157,14 @@ static int ioh_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
|
|||
{
|
||||
struct ioh_gpio *chip = container_of(gpio, struct ioh_gpio, gpio);
|
||||
u32 pm;
|
||||
unsigned long flags;
|
||||
|
||||
mutex_lock(&chip->lock);
|
||||
spin_lock_irqsave(&chip->spinlock, flags);
|
||||
pm = ioread32(&chip->reg->regs[chip->ch].pm) &
|
||||
((1 << num_ports[chip->ch]) - 1);
|
||||
pm &= ~(1 << nr);
|
||||
iowrite32(pm, &chip->reg->regs[chip->ch].pm);
|
||||
mutex_unlock(&chip->lock);
|
||||
spin_unlock_irqrestore(&chip->spinlock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -447,7 +448,6 @@ static int __devinit ioh_gpio_probe(struct pci_dev *pdev,
|
|||
chip->base = base;
|
||||
chip->reg = chip->base;
|
||||
chip->ch = i;
|
||||
mutex_init(&chip->lock);
|
||||
spin_lock_init(&chip->spinlock);
|
||||
ioh_gpio_setup(chip, num_ports[i]);
|
||||
ret = gpiochip_add(&chip->gpio);
|
||||
|
|
|
@ -317,9 +317,7 @@ static void msm_summary_irq_handler(unsigned int irq, struct irq_desc *desc)
|
|||
|
||||
chained_irq_enter(chip, desc);
|
||||
|
||||
for (i = find_first_bit(msm_gpio.enabled_irqs, NR_GPIO_IRQS);
|
||||
i < NR_GPIO_IRQS;
|
||||
i = find_next_bit(msm_gpio.enabled_irqs, NR_GPIO_IRQS, i + 1)) {
|
||||
for_each_set_bit(i, msm_gpio.enabled_irqs, NR_GPIO_IRQS) {
|
||||
if (readl(GPIO_INTR_STATUS(i)) & BIT(INTR_STATUS))
|
||||
generic_handle_irq(msm_gpio_to_irq(&msm_gpio.gpio_chip,
|
||||
i));
|
||||
|
|
|
@ -23,7 +23,12 @@
|
|||
#include <linux/gpio.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c/pcf857x.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
|
||||
static const struct i2c_device_id pcf857x_id[] = {
|
||||
|
@ -60,7 +65,12 @@ struct pcf857x {
|
|||
struct gpio_chip chip;
|
||||
struct i2c_client *client;
|
||||
struct mutex lock; /* protect 'out' */
|
||||
struct work_struct work; /* irq demux work */
|
||||
struct irq_domain *irq_domain; /* for irq demux */
|
||||
spinlock_t slock; /* protect irq demux */
|
||||
unsigned out; /* software latch */
|
||||
unsigned status; /* current status */
|
||||
int irq; /* real irq number */
|
||||
|
||||
int (*write)(struct i2c_client *client, unsigned data);
|
||||
int (*read)(struct i2c_client *client);
|
||||
|
@ -150,6 +160,100 @@ static void pcf857x_set(struct gpio_chip *chip, unsigned offset, int value)
|
|||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int pcf857x_to_irq(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct pcf857x *gpio = container_of(chip, struct pcf857x, chip);
|
||||
|
||||
return irq_create_mapping(gpio->irq_domain, offset);
|
||||
}
|
||||
|
||||
static void pcf857x_irq_demux_work(struct work_struct *work)
|
||||
{
|
||||
struct pcf857x *gpio = container_of(work,
|
||||
struct pcf857x,
|
||||
work);
|
||||
unsigned long change, i, status, flags;
|
||||
|
||||
status = gpio->read(gpio->client);
|
||||
|
||||
spin_lock_irqsave(&gpio->slock, flags);
|
||||
|
||||
change = gpio->status ^ status;
|
||||
for_each_set_bit(i, &change, gpio->chip.ngpio)
|
||||
generic_handle_irq(irq_find_mapping(gpio->irq_domain, i));
|
||||
gpio->status = status;
|
||||
|
||||
spin_unlock_irqrestore(&gpio->slock, flags);
|
||||
}
|
||||
|
||||
static irqreturn_t pcf857x_irq_demux(int irq, void *data)
|
||||
{
|
||||
struct pcf857x *gpio = data;
|
||||
|
||||
/*
|
||||
* pcf857x can't read/write data here,
|
||||
* since i2c data access might go to sleep.
|
||||
*/
|
||||
schedule_work(&gpio->work);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int pcf857x_irq_domain_map(struct irq_domain *domain, unsigned int virq,
|
||||
irq_hw_number_t hw)
|
||||
{
|
||||
irq_set_chip_and_handler(virq,
|
||||
&dummy_irq_chip,
|
||||
handle_level_irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct irq_domain_ops pcf857x_irq_domain_ops = {
|
||||
.map = pcf857x_irq_domain_map,
|
||||
};
|
||||
|
||||
static void pcf857x_irq_domain_cleanup(struct pcf857x *gpio)
|
||||
{
|
||||
if (gpio->irq_domain)
|
||||
irq_domain_remove(gpio->irq_domain);
|
||||
|
||||
if (gpio->irq)
|
||||
free_irq(gpio->irq, gpio);
|
||||
}
|
||||
|
||||
static int pcf857x_irq_domain_init(struct pcf857x *gpio,
|
||||
struct pcf857x_platform_data *pdata,
|
||||
struct device *dev)
|
||||
{
|
||||
int status;
|
||||
|
||||
gpio->irq_domain = irq_domain_add_linear(dev->of_node,
|
||||
gpio->chip.ngpio,
|
||||
&pcf857x_irq_domain_ops,
|
||||
NULL);
|
||||
if (!gpio->irq_domain)
|
||||
goto fail;
|
||||
|
||||
/* enable real irq */
|
||||
status = request_irq(pdata->irq, pcf857x_irq_demux, 0,
|
||||
dev_name(dev), gpio);
|
||||
if (status)
|
||||
goto fail;
|
||||
|
||||
/* enable gpio_to_irq() */
|
||||
INIT_WORK(&gpio->work, pcf857x_irq_demux_work);
|
||||
gpio->chip.to_irq = pcf857x_to_irq;
|
||||
gpio->irq = pdata->irq;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
pcf857x_irq_domain_cleanup(gpio);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int pcf857x_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
|
@ -168,6 +272,7 @@ static int pcf857x_probe(struct i2c_client *client,
|
|||
return -ENOMEM;
|
||||
|
||||
mutex_init(&gpio->lock);
|
||||
spin_lock_init(&gpio->slock);
|
||||
|
||||
gpio->chip.base = pdata ? pdata->gpio_base : -1;
|
||||
gpio->chip.can_sleep = 1;
|
||||
|
@ -179,6 +284,15 @@ static int pcf857x_probe(struct i2c_client *client,
|
|||
gpio->chip.direction_output = pcf857x_output;
|
||||
gpio->chip.ngpio = id->driver_data;
|
||||
|
||||
/* enable gpio_to_irq() if platform has settings */
|
||||
if (pdata && pdata->irq) {
|
||||
status = pcf857x_irq_domain_init(gpio, pdata, &client->dev);
|
||||
if (status < 0) {
|
||||
dev_err(&client->dev, "irq_domain init failed\n");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* NOTE: the OnSemi jlc1562b is also largely compatible with
|
||||
* these parts, notably for output. It has a low-resolution
|
||||
* DAC instead of pin change IRQs; and its inputs can be the
|
||||
|
@ -248,6 +362,7 @@ static int pcf857x_probe(struct i2c_client *client,
|
|||
* all-ones reset state. Otherwise it flags pins to be driven low.
|
||||
*/
|
||||
gpio->out = pdata ? ~pdata->n_latch : ~0;
|
||||
gpio->status = gpio->out;
|
||||
|
||||
status = gpiochip_add(&gpio->chip);
|
||||
if (status < 0)
|
||||
|
@ -278,6 +393,10 @@ static int pcf857x_probe(struct i2c_client *client,
|
|||
fail:
|
||||
dev_dbg(&client->dev, "probe error %d for '%s'\n",
|
||||
status, client->name);
|
||||
|
||||
if (pdata && pdata->irq)
|
||||
pcf857x_irq_domain_cleanup(gpio);
|
||||
|
||||
kfree(gpio);
|
||||
return status;
|
||||
}
|
||||
|
@ -299,6 +418,9 @@ static int pcf857x_remove(struct i2c_client *client)
|
|||
}
|
||||
}
|
||||
|
||||
if (pdata && pdata->irq)
|
||||
pcf857x_irq_domain_cleanup(gpio);
|
||||
|
||||
status = gpiochip_remove(&gpio->chip);
|
||||
if (status == 0)
|
||||
kfree(gpio);
|
||||
|
|
|
@ -92,9 +92,7 @@ struct pch_gpio_reg_data {
|
|||
* @lock: Used for register access protection
|
||||
* @irq_base: Save base of IRQ number for interrupt
|
||||
* @ioh: IOH ID
|
||||
* @spinlock: Used for register access protection in
|
||||
* interrupt context pch_irq_mask,
|
||||
* pch_irq_unmask and pch_irq_type;
|
||||
* @spinlock: Used for register access protection
|
||||
*/
|
||||
struct pch_gpio {
|
||||
void __iomem *base;
|
||||
|
@ -102,7 +100,6 @@ struct pch_gpio {
|
|||
struct device *dev;
|
||||
struct gpio_chip gpio;
|
||||
struct pch_gpio_reg_data pch_gpio_reg;
|
||||
struct mutex lock;
|
||||
int irq_base;
|
||||
enum pch_type_t ioh;
|
||||
spinlock_t spinlock;
|
||||
|
@ -112,8 +109,9 @@ static void pch_gpio_set(struct gpio_chip *gpio, unsigned nr, int val)
|
|||
{
|
||||
u32 reg_val;
|
||||
struct pch_gpio *chip = container_of(gpio, struct pch_gpio, gpio);
|
||||
unsigned long flags;
|
||||
|
||||
mutex_lock(&chip->lock);
|
||||
spin_lock_irqsave(&chip->spinlock, flags);
|
||||
reg_val = ioread32(&chip->reg->po);
|
||||
if (val)
|
||||
reg_val |= (1 << nr);
|
||||
|
@ -121,7 +119,7 @@ static void pch_gpio_set(struct gpio_chip *gpio, unsigned nr, int val)
|
|||
reg_val &= ~(1 << nr);
|
||||
|
||||
iowrite32(reg_val, &chip->reg->po);
|
||||
mutex_unlock(&chip->lock);
|
||||
spin_unlock_irqrestore(&chip->spinlock, flags);
|
||||
}
|
||||
|
||||
static int pch_gpio_get(struct gpio_chip *gpio, unsigned nr)
|
||||
|
@ -137,8 +135,9 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
|
|||
struct pch_gpio *chip = container_of(gpio, struct pch_gpio, gpio);
|
||||
u32 pm;
|
||||
u32 reg_val;
|
||||
unsigned long flags;
|
||||
|
||||
mutex_lock(&chip->lock);
|
||||
spin_lock_irqsave(&chip->spinlock, flags);
|
||||
pm = ioread32(&chip->reg->pm) & ((1 << gpio_pins[chip->ioh]) - 1);
|
||||
pm |= (1 << nr);
|
||||
iowrite32(pm, &chip->reg->pm);
|
||||
|
@ -149,8 +148,7 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
|
|||
else
|
||||
reg_val &= ~(1 << nr);
|
||||
iowrite32(reg_val, &chip->reg->po);
|
||||
|
||||
mutex_unlock(&chip->lock);
|
||||
spin_unlock_irqrestore(&chip->spinlock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -159,12 +157,13 @@ static int pch_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
|
|||
{
|
||||
struct pch_gpio *chip = container_of(gpio, struct pch_gpio, gpio);
|
||||
u32 pm;
|
||||
unsigned long flags;
|
||||
|
||||
mutex_lock(&chip->lock);
|
||||
spin_lock_irqsave(&chip->spinlock, flags);
|
||||
pm = ioread32(&chip->reg->pm) & ((1 << gpio_pins[chip->ioh]) - 1);
|
||||
pm &= ~(1 << nr);
|
||||
iowrite32(pm, &chip->reg->pm);
|
||||
mutex_unlock(&chip->lock);
|
||||
spin_unlock_irqrestore(&chip->spinlock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -387,7 +386,6 @@ static int __devinit pch_gpio_probe(struct pci_dev *pdev,
|
|||
|
||||
chip->reg = chip->base;
|
||||
pci_set_drvdata(pdev, chip);
|
||||
mutex_init(&chip->lock);
|
||||
spin_lock_init(&chip->spinlock);
|
||||
pch_gpio_setup(chip);
|
||||
ret = gpiochip_add(&chip->gpio);
|
||||
|
|
|
@ -370,12 +370,10 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc)
|
|||
gedr = gedr & c->irq_mask;
|
||||
writel_relaxed(gedr, c->regbase + GEDR_OFFSET);
|
||||
|
||||
n = find_first_bit(&gedr, BITS_PER_LONG);
|
||||
while (n < BITS_PER_LONG) {
|
||||
for_each_set_bit(n, &gedr, BITS_PER_LONG) {
|
||||
loop = 1;
|
||||
|
||||
generic_handle_irq(gpio_to_irq(gpio_base + n));
|
||||
n = find_next_bit(&gedr, BITS_PER_LONG, n + 1);
|
||||
}
|
||||
}
|
||||
} while (loop);
|
||||
|
@ -589,19 +587,12 @@ static int __devinit pxa_gpio_probe(struct platform_device *pdev)
|
|||
iounmap(gpio_reg_base);
|
||||
return PTR_ERR(clk);
|
||||
}
|
||||
ret = clk_prepare(clk);
|
||||
ret = clk_prepare_enable(clk);
|
||||
if (ret) {
|
||||
clk_put(clk);
|
||||
iounmap(gpio_reg_base);
|
||||
return ret;
|
||||
}
|
||||
ret = clk_enable(clk);
|
||||
if (ret) {
|
||||
clk_unprepare(clk);
|
||||
clk_put(clk);
|
||||
iounmap(gpio_reg_base);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Initialize GPIO chips */
|
||||
info = dev_get_platdata(&pdev->dev);
|
||||
|
|
|
@ -270,7 +270,7 @@ static void sdv_gpio_remove(struct pci_dev *pdev)
|
|||
kfree(sd);
|
||||
}
|
||||
|
||||
static struct pci_device_id sdv_gpio_pci_ids[] __devinitdata = {
|
||||
static DEFINE_PCI_DEVICE_TABLE(sdv_gpio_pci_ids) = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_SDV_GPIO) },
|
||||
{ 0, },
|
||||
};
|
||||
|
|
|
@ -311,11 +311,9 @@ static int sx150x_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
|
|||
|
||||
static void sx150x_irq_mask(struct irq_data *d)
|
||||
{
|
||||
struct irq_chip *ic = irq_data_get_irq_chip(d);
|
||||
struct sx150x_chip *chip;
|
||||
struct sx150x_chip *chip = irq_data_get_irq_chip_data(d);
|
||||
unsigned n;
|
||||
|
||||
chip = container_of(ic, struct sx150x_chip, irq_chip);
|
||||
n = d->irq - chip->irq_base;
|
||||
chip->irq_masked |= (1 << n);
|
||||
chip->irq_update = n;
|
||||
|
@ -323,27 +321,22 @@ static void sx150x_irq_mask(struct irq_data *d)
|
|||
|
||||
static void sx150x_irq_unmask(struct irq_data *d)
|
||||
{
|
||||
struct irq_chip *ic = irq_data_get_irq_chip(d);
|
||||
struct sx150x_chip *chip;
|
||||
struct sx150x_chip *chip = irq_data_get_irq_chip_data(d);
|
||||
unsigned n;
|
||||
|
||||
chip = container_of(ic, struct sx150x_chip, irq_chip);
|
||||
n = d->irq - chip->irq_base;
|
||||
|
||||
chip->irq_masked &= ~(1 << n);
|
||||
chip->irq_update = n;
|
||||
}
|
||||
|
||||
static int sx150x_irq_set_type(struct irq_data *d, unsigned int flow_type)
|
||||
{
|
||||
struct irq_chip *ic = irq_data_get_irq_chip(d);
|
||||
struct sx150x_chip *chip;
|
||||
struct sx150x_chip *chip = irq_data_get_irq_chip_data(d);
|
||||
unsigned n, val = 0;
|
||||
|
||||
if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
|
||||
return -EINVAL;
|
||||
|
||||
chip = container_of(ic, struct sx150x_chip, irq_chip);
|
||||
n = d->irq - chip->irq_base;
|
||||
|
||||
if (flow_type & IRQ_TYPE_EDGE_RISING)
|
||||
|
@ -391,22 +384,16 @@ static irqreturn_t sx150x_irq_thread_fn(int irq, void *dev_id)
|
|||
|
||||
static void sx150x_irq_bus_lock(struct irq_data *d)
|
||||
{
|
||||
struct irq_chip *ic = irq_data_get_irq_chip(d);
|
||||
struct sx150x_chip *chip;
|
||||
|
||||
chip = container_of(ic, struct sx150x_chip, irq_chip);
|
||||
struct sx150x_chip *chip = irq_data_get_irq_chip_data(d);
|
||||
|
||||
mutex_lock(&chip->lock);
|
||||
}
|
||||
|
||||
static void sx150x_irq_bus_sync_unlock(struct irq_data *d)
|
||||
{
|
||||
struct irq_chip *ic = irq_data_get_irq_chip(d);
|
||||
struct sx150x_chip *chip;
|
||||
struct sx150x_chip *chip = irq_data_get_irq_chip_data(d);
|
||||
unsigned n;
|
||||
|
||||
chip = container_of(ic, struct sx150x_chip, irq_chip);
|
||||
|
||||
if (chip->irq_update == NO_UPDATE_PENDING)
|
||||
goto out;
|
||||
|
||||
|
@ -551,6 +538,7 @@ static int sx150x_install_irq_chip(struct sx150x_chip *chip,
|
|||
|
||||
for (n = 0; n < chip->dev_cfg->ngpios; ++n) {
|
||||
irq = irq_base + n;
|
||||
irq_set_chip_data(irq, chip);
|
||||
irq_set_chip_and_handler(irq, &chip->irq_chip, handle_edge_irq);
|
||||
irq_set_nested_thread(irq, 1);
|
||||
#ifdef CONFIG_ARM
|
||||
|
|
|
@ -11,7 +11,9 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mfd/tc3589x.h>
|
||||
|
||||
|
@ -29,6 +31,7 @@ struct tc3589x_gpio {
|
|||
struct tc3589x *tc3589x;
|
||||
struct device *dev;
|
||||
struct mutex irq_lock;
|
||||
struct irq_domain *domain;
|
||||
|
||||
int irq_base;
|
||||
|
||||
|
@ -92,11 +95,28 @@ static int tc3589x_gpio_direction_input(struct gpio_chip *chip,
|
|||
return tc3589x_set_bits(tc3589x, reg, 1 << pos, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* tc3589x_gpio_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ
|
||||
*
|
||||
* @tc3589x_gpio: tc3589x_gpio_irq controller to operate on.
|
||||
* @irq: index of the interrupt requested in the chip IRQs
|
||||
*
|
||||
* Useful for drivers to request their own IRQs.
|
||||
*/
|
||||
static int tc3589x_gpio_irq_get_virq(struct tc3589x_gpio *tc3589x_gpio,
|
||||
int irq)
|
||||
{
|
||||
if (!tc3589x_gpio)
|
||||
return -EINVAL;
|
||||
|
||||
return irq_create_mapping(tc3589x_gpio->domain, irq);
|
||||
}
|
||||
|
||||
static int tc3589x_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip);
|
||||
|
||||
return tc3589x_gpio->irq_base + offset;
|
||||
return tc3589x_gpio_irq_get_virq(tc3589x_gpio, offset);
|
||||
}
|
||||
|
||||
static struct gpio_chip template_chip = {
|
||||
|
@ -113,7 +133,7 @@ static struct gpio_chip template_chip = {
|
|||
static int tc3589x_gpio_irq_set_type(struct irq_data *d, unsigned int type)
|
||||
{
|
||||
struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d);
|
||||
int offset = d->irq - tc3589x_gpio->irq_base;
|
||||
int offset = d->hwirq;
|
||||
int regoffset = offset / 8;
|
||||
int mask = 1 << (offset % 8);
|
||||
|
||||
|
@ -175,7 +195,7 @@ static void tc3589x_gpio_irq_sync_unlock(struct irq_data *d)
|
|||
static void tc3589x_gpio_irq_mask(struct irq_data *d)
|
||||
{
|
||||
struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d);
|
||||
int offset = d->irq - tc3589x_gpio->irq_base;
|
||||
int offset = d->hwirq;
|
||||
int regoffset = offset / 8;
|
||||
int mask = 1 << (offset % 8);
|
||||
|
||||
|
@ -185,7 +205,7 @@ static void tc3589x_gpio_irq_mask(struct irq_data *d)
|
|||
static void tc3589x_gpio_irq_unmask(struct irq_data *d)
|
||||
{
|
||||
struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d);
|
||||
int offset = d->irq - tc3589x_gpio->irq_base;
|
||||
int offset = d->hwirq;
|
||||
int regoffset = offset / 8;
|
||||
int mask = 1 << (offset % 8);
|
||||
|
||||
|
@ -222,8 +242,9 @@ static irqreturn_t tc3589x_gpio_irq(int irq, void *dev)
|
|||
while (stat) {
|
||||
int bit = __ffs(stat);
|
||||
int line = i * 8 + bit;
|
||||
int virq = tc3589x_gpio_irq_get_virq(tc3589x_gpio, line);
|
||||
|
||||
handle_nested_irq(tc3589x_gpio->irq_base + line);
|
||||
handle_nested_irq(virq);
|
||||
stat &= ~(1 << bit);
|
||||
}
|
||||
|
||||
|
@ -233,51 +254,78 @@ static irqreturn_t tc3589x_gpio_irq(int irq, void *dev)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int tc3589x_gpio_irq_init(struct tc3589x_gpio *tc3589x_gpio)
|
||||
static int tc3589x_gpio_irq_map(struct irq_domain *d, unsigned int virq,
|
||||
irq_hw_number_t hwirq)
|
||||
{
|
||||
int base = tc3589x_gpio->irq_base;
|
||||
int irq;
|
||||
struct tc3589x *tc3589x_gpio = d->host_data;
|
||||
|
||||
for (irq = base; irq < base + tc3589x_gpio->chip.ngpio; irq++) {
|
||||
irq_set_chip_data(irq, tc3589x_gpio);
|
||||
irq_set_chip_and_handler(irq, &tc3589x_gpio_irq_chip,
|
||||
handle_simple_irq);
|
||||
irq_set_nested_thread(irq, 1);
|
||||
irq_set_chip_data(virq, tc3589x_gpio);
|
||||
irq_set_chip_and_handler(virq, &tc3589x_gpio_irq_chip,
|
||||
handle_simple_irq);
|
||||
irq_set_nested_thread(virq, 1);
|
||||
#ifdef CONFIG_ARM
|
||||
set_irq_flags(irq, IRQF_VALID);
|
||||
set_irq_flags(virq, IRQF_VALID);
|
||||
#else
|
||||
irq_set_noprobe(irq);
|
||||
irq_set_noprobe(virq);
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tc3589x_gpio_irq_remove(struct tc3589x_gpio *tc3589x_gpio)
|
||||
static void tc3589x_gpio_irq_unmap(struct irq_domain *d, unsigned int virq)
|
||||
{
|
||||
#ifdef CONFIG_ARM
|
||||
set_irq_flags(virq, 0);
|
||||
#endif
|
||||
irq_set_chip_and_handler(virq, NULL, NULL);
|
||||
irq_set_chip_data(virq, NULL);
|
||||
}
|
||||
|
||||
static struct irq_domain_ops tc3589x_irq_ops = {
|
||||
.map = tc3589x_gpio_irq_map,
|
||||
.unmap = tc3589x_gpio_irq_unmap,
|
||||
.xlate = irq_domain_xlate_twocell,
|
||||
};
|
||||
|
||||
static int tc3589x_gpio_irq_init(struct tc3589x_gpio *tc3589x_gpio,
|
||||
struct device_node *np)
|
||||
{
|
||||
int base = tc3589x_gpio->irq_base;
|
||||
int irq;
|
||||
|
||||
for (irq = base; irq < base + tc3589x_gpio->chip.ngpio; irq++) {
|
||||
#ifdef CONFIG_ARM
|
||||
set_irq_flags(irq, 0);
|
||||
#endif
|
||||
irq_set_chip_and_handler(irq, NULL, NULL);
|
||||
irq_set_chip_data(irq, NULL);
|
||||
if (base) {
|
||||
tc3589x_gpio->domain = irq_domain_add_legacy(
|
||||
NULL, tc3589x_gpio->chip.ngpio, base,
|
||||
0, &tc3589x_irq_ops, tc3589x_gpio);
|
||||
}
|
||||
else {
|
||||
tc3589x_gpio->domain = irq_domain_add_linear(
|
||||
np, tc3589x_gpio->chip.ngpio,
|
||||
&tc3589x_irq_ops, tc3589x_gpio);
|
||||
}
|
||||
|
||||
if (!tc3589x_gpio->domain) {
|
||||
dev_err(tc3589x_gpio->dev, "Failed to create irqdomain\n");
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit tc3589x_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent);
|
||||
struct tc3589x_gpio_platform_data *pdata;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct tc3589x_gpio *tc3589x_gpio;
|
||||
int ret;
|
||||
int irq;
|
||||
|
||||
pdata = tc3589x->pdata->gpio;
|
||||
if (!pdata)
|
||||
return -ENODEV;
|
||||
|
||||
if (!(pdata || np)) {
|
||||
dev_err(&pdev->dev, "No platform data or Device Tree found\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
|
@ -295,9 +343,14 @@ static int __devinit tc3589x_gpio_probe(struct platform_device *pdev)
|
|||
tc3589x_gpio->chip = template_chip;
|
||||
tc3589x_gpio->chip.ngpio = tc3589x->num_gpio;
|
||||
tc3589x_gpio->chip.dev = &pdev->dev;
|
||||
tc3589x_gpio->chip.base = pdata->gpio_base;
|
||||
tc3589x_gpio->chip.base = (pdata) ? pdata->gpio_base : -1;
|
||||
|
||||
tc3589x_gpio->irq_base = tc3589x->irq_base + TC3589x_INT_GPIO(0);
|
||||
#ifdef CONFIG_OF_GPIO
|
||||
tc3589x_gpio->chip.of_node = np;
|
||||
#endif
|
||||
|
||||
tc3589x_gpio->irq_base = tc3589x->irq_base ?
|
||||
tc3589x->irq_base + TC3589x_INT_GPIO(0) : 0;
|
||||
|
||||
/* Bring the GPIO module out of reset */
|
||||
ret = tc3589x_set_bits(tc3589x, TC3589x_RSTCTRL,
|
||||
|
@ -305,7 +358,7 @@ static int __devinit tc3589x_gpio_probe(struct platform_device *pdev)
|
|||
if (ret < 0)
|
||||
goto out_free;
|
||||
|
||||
ret = tc3589x_gpio_irq_init(tc3589x_gpio);
|
||||
ret = tc3589x_gpio_irq_init(tc3589x_gpio, np);
|
||||
if (ret)
|
||||
goto out_free;
|
||||
|
||||
|
@ -313,7 +366,7 @@ static int __devinit tc3589x_gpio_probe(struct platform_device *pdev)
|
|||
"tc3589x-gpio", tc3589x_gpio);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
|
||||
goto out_removeirq;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
ret = gpiochip_add(&tc3589x_gpio->chip);
|
||||
|
@ -322,7 +375,7 @@ static int __devinit tc3589x_gpio_probe(struct platform_device *pdev)
|
|||
goto out_freeirq;
|
||||
}
|
||||
|
||||
if (pdata->setup)
|
||||
if (pdata && pdata->setup)
|
||||
pdata->setup(tc3589x, tc3589x_gpio->chip.base);
|
||||
|
||||
platform_set_drvdata(pdev, tc3589x_gpio);
|
||||
|
@ -331,8 +384,6 @@ static int __devinit tc3589x_gpio_probe(struct platform_device *pdev)
|
|||
|
||||
out_freeirq:
|
||||
free_irq(irq, tc3589x_gpio);
|
||||
out_removeirq:
|
||||
tc3589x_gpio_irq_remove(tc3589x_gpio);
|
||||
out_free:
|
||||
kfree(tc3589x_gpio);
|
||||
return ret;
|
||||
|
@ -346,7 +397,7 @@ static int __devexit tc3589x_gpio_remove(struct platform_device *pdev)
|
|||
int irq = platform_get_irq(pdev, 0);
|
||||
int ret;
|
||||
|
||||
if (pdata->remove)
|
||||
if (pdata && pdata->remove)
|
||||
pdata->remove(tc3589x, tc3589x_gpio->chip.base);
|
||||
|
||||
ret = gpiochip_remove(&tc3589x_gpio->chip);
|
||||
|
@ -357,7 +408,6 @@ static int __devexit tc3589x_gpio_remove(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
free_irq(irq, tc3589x_gpio);
|
||||
tc3589x_gpio_irq_remove(tc3589x_gpio);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(tc3589x_gpio);
|
||||
|
|
|
@ -70,7 +70,6 @@ static int tps65912_gpio_input(struct gpio_chip *gc, unsigned offset)
|
|||
|
||||
return tps65912_clear_bits(tps65912, TPS65912_GPIO1 + offset,
|
||||
GPIO_CFG_MASK);
|
||||
|
||||
}
|
||||
|
||||
static struct gpio_chip template_chip = {
|
||||
|
@ -92,7 +91,8 @@ static int __devinit tps65912_gpio_probe(struct platform_device *pdev)
|
|||
struct tps65912_gpio_data *tps65912_gpio;
|
||||
int ret;
|
||||
|
||||
tps65912_gpio = kzalloc(sizeof(*tps65912_gpio), GFP_KERNEL);
|
||||
tps65912_gpio = devm_kzalloc(&pdev->dev, sizeof(*tps65912_gpio),
|
||||
GFP_KERNEL);
|
||||
if (tps65912_gpio == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -105,28 +105,19 @@ static int __devinit tps65912_gpio_probe(struct platform_device *pdev)
|
|||
ret = gpiochip_add(&tps65912_gpio->gpio_chip);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to register gpiochip, %d\n", ret);
|
||||
goto err;
|
||||
return ret;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, tps65912_gpio);
|
||||
|
||||
return ret;
|
||||
|
||||
err:
|
||||
kfree(tps65912_gpio);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit tps65912_gpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct tps65912_gpio_data *tps65912_gpio = platform_get_drvdata(pdev);
|
||||
int ret;
|
||||
|
||||
ret = gpiochip_remove(&tps65912_gpio->gpio_chip);
|
||||
if (ret == 0)
|
||||
kfree(tps65912_gpio);
|
||||
|
||||
return ret;
|
||||
return gpiochip_remove(&tps65912_gpio->gpio_chip);
|
||||
}
|
||||
|
||||
static struct platform_driver tps65912_gpio_driver = {
|
||||
|
|
|
@ -250,7 +250,8 @@ static int __devinit wm831x_gpio_probe(struct platform_device *pdev)
|
|||
struct wm831x_gpio *wm831x_gpio;
|
||||
int ret;
|
||||
|
||||
wm831x_gpio = kzalloc(sizeof(*wm831x_gpio), GFP_KERNEL);
|
||||
wm831x_gpio = devm_kzalloc(&pdev->dev, sizeof(*wm831x_gpio),
|
||||
GFP_KERNEL);
|
||||
if (wm831x_gpio == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -265,30 +266,20 @@ static int __devinit wm831x_gpio_probe(struct platform_device *pdev)
|
|||
|
||||
ret = gpiochip_add(&wm831x_gpio->gpio_chip);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Could not register gpiochip, %d\n",
|
||||
ret);
|
||||
goto err;
|
||||
dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, wm831x_gpio);
|
||||
|
||||
return ret;
|
||||
|
||||
err:
|
||||
kfree(wm831x_gpio);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit wm831x_gpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct wm831x_gpio *wm831x_gpio = platform_get_drvdata(pdev);
|
||||
int ret;
|
||||
|
||||
ret = gpiochip_remove(&wm831x_gpio->gpio_chip);
|
||||
if (ret == 0)
|
||||
kfree(wm831x_gpio);
|
||||
|
||||
return ret;
|
||||
return gpiochip_remove(&wm831x_gpio->gpio_chip);
|
||||
}
|
||||
|
||||
static struct platform_driver wm831x_gpio_driver = {
|
||||
|
|
|
@ -116,7 +116,8 @@ static int __devinit wm8350_gpio_probe(struct platform_device *pdev)
|
|||
struct wm8350_gpio_data *wm8350_gpio;
|
||||
int ret;
|
||||
|
||||
wm8350_gpio = kzalloc(sizeof(*wm8350_gpio), GFP_KERNEL);
|
||||
wm8350_gpio = devm_kzalloc(&pdev->dev, sizeof(*wm8350_gpio),
|
||||
GFP_KERNEL);
|
||||
if (wm8350_gpio == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -131,30 +132,20 @@ static int __devinit wm8350_gpio_probe(struct platform_device *pdev)
|
|||
|
||||
ret = gpiochip_add(&wm8350_gpio->gpio_chip);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Could not register gpiochip, %d\n",
|
||||
ret);
|
||||
goto err;
|
||||
dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, wm8350_gpio);
|
||||
|
||||
return ret;
|
||||
|
||||
err:
|
||||
kfree(wm8350_gpio);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit wm8350_gpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct wm8350_gpio_data *wm8350_gpio = platform_get_drvdata(pdev);
|
||||
int ret;
|
||||
|
||||
ret = gpiochip_remove(&wm8350_gpio->gpio_chip);
|
||||
if (ret == 0)
|
||||
kfree(wm8350_gpio);
|
||||
|
||||
return ret;
|
||||
return gpiochip_remove(&wm8350_gpio->gpio_chip);
|
||||
}
|
||||
|
||||
static struct platform_driver wm8350_gpio_driver = {
|
||||
|
|
|
@ -1773,56 +1773,102 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip)
|
|||
}
|
||||
}
|
||||
|
||||
static int gpiolib_show(struct seq_file *s, void *unused)
|
||||
static void *gpiolib_seq_start(struct seq_file *s, loff_t *pos)
|
||||
{
|
||||
struct gpio_chip *chip = NULL;
|
||||
unsigned gpio;
|
||||
int started = 0;
|
||||
struct gpio_chip *chip = NULL;
|
||||
unsigned int gpio;
|
||||
void *ret = NULL;
|
||||
loff_t index = 0;
|
||||
|
||||
/* REVISIT this isn't locked against gpio_chip removal ... */
|
||||
|
||||
for (gpio = 0; gpio_is_valid(gpio); gpio++) {
|
||||
struct device *dev;
|
||||
|
||||
if (chip == gpio_desc[gpio].chip)
|
||||
if (gpio_desc[gpio].chip == chip)
|
||||
continue;
|
||||
|
||||
chip = gpio_desc[gpio].chip;
|
||||
if (!chip)
|
||||
continue;
|
||||
|
||||
seq_printf(s, "%sGPIOs %d-%d",
|
||||
started ? "\n" : "",
|
||||
chip->base, chip->base + chip->ngpio - 1);
|
||||
dev = chip->dev;
|
||||
if (dev)
|
||||
seq_printf(s, ", %s/%s",
|
||||
dev->bus ? dev->bus->name : "no-bus",
|
||||
dev_name(dev));
|
||||
if (chip->label)
|
||||
seq_printf(s, ", %s", chip->label);
|
||||
if (chip->can_sleep)
|
||||
seq_printf(s, ", can sleep");
|
||||
seq_printf(s, ":\n");
|
||||
|
||||
started = 1;
|
||||
if (chip->dbg_show)
|
||||
chip->dbg_show(s, chip);
|
||||
else
|
||||
gpiolib_dbg_show(s, chip);
|
||||
if (index++ >= *pos) {
|
||||
ret = chip;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
s->private = "";
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void *gpiolib_seq_next(struct seq_file *s, void *v, loff_t *pos)
|
||||
{
|
||||
struct gpio_chip *chip = v;
|
||||
unsigned int gpio;
|
||||
void *ret = NULL;
|
||||
|
||||
/* skip GPIOs provided by the current chip */
|
||||
for (gpio = chip->base + chip->ngpio; gpio_is_valid(gpio); gpio++) {
|
||||
chip = gpio_desc[gpio].chip;
|
||||
if (chip) {
|
||||
ret = chip;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
s->private = "\n";
|
||||
++*pos;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void gpiolib_seq_stop(struct seq_file *s, void *v)
|
||||
{
|
||||
}
|
||||
|
||||
static int gpiolib_seq_show(struct seq_file *s, void *v)
|
||||
{
|
||||
struct gpio_chip *chip = v;
|
||||
struct device *dev;
|
||||
|
||||
seq_printf(s, "%sGPIOs %d-%d", (char *)s->private,
|
||||
chip->base, chip->base + chip->ngpio - 1);
|
||||
dev = chip->dev;
|
||||
if (dev)
|
||||
seq_printf(s, ", %s/%s", dev->bus ? dev->bus->name : "no-bus",
|
||||
dev_name(dev));
|
||||
if (chip->label)
|
||||
seq_printf(s, ", %s", chip->label);
|
||||
if (chip->can_sleep)
|
||||
seq_printf(s, ", can sleep");
|
||||
seq_printf(s, ":\n");
|
||||
|
||||
if (chip->dbg_show)
|
||||
chip->dbg_show(s, chip);
|
||||
else
|
||||
gpiolib_dbg_show(s, chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct seq_operations gpiolib_seq_ops = {
|
||||
.start = gpiolib_seq_start,
|
||||
.next = gpiolib_seq_next,
|
||||
.stop = gpiolib_seq_stop,
|
||||
.show = gpiolib_seq_show,
|
||||
};
|
||||
|
||||
static int gpiolib_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, gpiolib_show, NULL);
|
||||
return seq_open(file, &gpiolib_seq_ops);
|
||||
}
|
||||
|
||||
static const struct file_operations gpiolib_operations = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = gpiolib_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
.release = seq_release,
|
||||
};
|
||||
|
||||
static int __init gpiolib_debugfs_init(void)
|
||||
|
|
|
@ -60,6 +60,8 @@ struct device_node;
|
|||
* @get: returns value for signal "offset"; for output signals this
|
||||
* returns either the value actually sensed, or zero
|
||||
* @direction_output: configures signal "offset" as output, or returns error
|
||||
* @set_debounce: optional hook for setting debounce time for specified gpio in
|
||||
* interrupt triggered gpio chips
|
||||
* @set: assigns output value for signal "offset"
|
||||
* @to_irq: optional hook supporting non-static gpio_to_irq() mappings;
|
||||
* implementation may not sleep
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
* @setup: optional callback issued once the GPIOs are valid
|
||||
* @teardown: optional callback issued before the GPIOs are invalidated
|
||||
* @context: optional parameter passed to setup() and teardown()
|
||||
* @irq: optional interrupt number
|
||||
*
|
||||
* In addition to the I2C_BOARD_INFO() state appropriate to each chip,
|
||||
* the i2c_board_info used with the pcf875x driver must provide its
|
||||
|
@ -39,6 +40,8 @@ struct pcf857x_platform_data {
|
|||
int gpio, unsigned ngpio,
|
||||
void *context);
|
||||
void *context;
|
||||
|
||||
int irq;
|
||||
};
|
||||
|
||||
#endif /* __LINUX_PCF857X_H */
|
||||
|
|
Загрузка…
Ссылка в новой задаче