Commit 0fa2fd9a authored by Grant Likely's avatar Grant Likely

Merge branch 'linusw/devel' of...

Merge branch 'linusw/devel' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio.git into gpio/next

Device driver features, cleanups and bug fixes.
Signed-off-by: default avatarGrant Likely <grant.likely@secretlab.ca>
parents 46ebfbc3 476171ce
...@@ -927,8 +927,6 @@ static void tosa_restart(char mode, const char *cmd) ...@@ -927,8 +927,6 @@ static void tosa_restart(char mode, const char *cmd)
static void __init tosa_init(void) static void __init tosa_init(void)
{ {
int dummy;
pxa2xx_mfp_config(ARRAY_AND_SIZE(tosa_pin_config)); pxa2xx_mfp_config(ARRAY_AND_SIZE(tosa_pin_config));
pxa_set_ffuart_info(NULL); pxa_set_ffuart_info(NULL);
...@@ -947,10 +945,6 @@ static void __init tosa_init(void) ...@@ -947,10 +945,6 @@ static void __init tosa_init(void)
/* enable batt_fault */ /* enable batt_fault */
PMCR = 0x01; PMCR = 0x01;
dummy = gpiochip_reserve(TOSA_SCOOP_GPIO_BASE, 12);
dummy = gpiochip_reserve(TOSA_SCOOP_JC_GPIO_BASE, 12);
dummy = gpiochip_reserve(TOSA_TC6393XB_GPIO_BASE, 16);
pxa_set_mci_info(&tosa_mci_platform_data); pxa_set_mci_info(&tosa_mci_platform_data);
pxa_set_ficp_info(&tosa_ficp_platform_data); pxa_set_ficp_info(&tosa_ficp_platform_data);
pxa_set_i2c_info(NULL); pxa_set_i2c_info(NULL);
......
...@@ -30,6 +30,9 @@ config ARCH_REQUIRE_GPIOLIB ...@@ -30,6 +30,9 @@ config ARCH_REQUIRE_GPIOLIB
Selecting this from the architecture code will cause the gpiolib Selecting this from the architecture code will cause the gpiolib
code to always get built in. code to always get built in.
config GPIO_DEVRES
def_bool y
depends on HAS_IOMEM
menuconfig GPIOLIB menuconfig GPIOLIB
......
...@@ -2,7 +2,8 @@ ...@@ -2,7 +2,8 @@
ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG
obj-$(CONFIG_GPIOLIB) += gpiolib.o devres.o obj-$(CONFIG_GPIO_DEVRES) += devres.o
obj-$(CONFIG_GPIOLIB) += gpiolib.o
obj-$(CONFIG_OF_GPIO) += gpiolib-of.o obj-$(CONFIG_OF_GPIO) += gpiolib-of.o
obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o
......
...@@ -292,7 +292,6 @@ static int mpc8xxx_gpio_irq_map(struct irq_domain *h, unsigned int virq, ...@@ -292,7 +292,6 @@ static int mpc8xxx_gpio_irq_map(struct irq_domain *h, unsigned int virq,
irq_set_chip_data(virq, h->host_data); irq_set_chip_data(virq, h->host_data);
irq_set_chip_and_handler(virq, &mpc8xxx_irq_chip, handle_level_irq); irq_set_chip_and_handler(virq, &mpc8xxx_irq_chip, handle_level_irq);
irq_set_irq_type(virq, IRQ_TYPE_NONE);
return 0; return 0;
} }
......
...@@ -65,6 +65,7 @@ struct mxs_gpio_port { ...@@ -65,6 +65,7 @@ struct mxs_gpio_port {
struct irq_domain *domain; struct irq_domain *domain;
struct bgpio_chip bgc; struct bgpio_chip bgc;
enum mxs_gpio_id devid; enum mxs_gpio_id devid;
u32 both_edges;
}; };
static inline int is_imx23_gpio(struct mxs_gpio_port *port) static inline int is_imx23_gpio(struct mxs_gpio_port *port)
...@@ -81,13 +82,23 @@ static inline int is_imx28_gpio(struct mxs_gpio_port *port) ...@@ -81,13 +82,23 @@ static inline int is_imx28_gpio(struct mxs_gpio_port *port)
static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type) static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type)
{ {
u32 val;
u32 pin_mask = 1 << d->hwirq; u32 pin_mask = 1 << d->hwirq;
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
struct mxs_gpio_port *port = gc->private; struct mxs_gpio_port *port = gc->private;
void __iomem *pin_addr; void __iomem *pin_addr;
int edge; int edge;
port->both_edges &= ~pin_mask;
switch (type) { switch (type) {
case IRQ_TYPE_EDGE_BOTH:
val = gpio_get_value(port->bgc.gc.base + d->hwirq);
if (val)
edge = GPIO_INT_FALL_EDGE;
else
edge = GPIO_INT_RISE_EDGE;
port->both_edges |= pin_mask;
break;
case IRQ_TYPE_EDGE_RISING: case IRQ_TYPE_EDGE_RISING:
edge = GPIO_INT_RISE_EDGE; edge = GPIO_INT_RISE_EDGE;
break; break;
...@@ -124,6 +135,23 @@ static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type) ...@@ -124,6 +135,23 @@ static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type)
return 0; return 0;
} }
static void mxs_flip_edge(struct mxs_gpio_port *port, u32 gpio)
{
u32 bit, val, edge;
void __iomem *pin_addr;
bit = 1 << gpio;
pin_addr = port->base + PINCTRL_IRQPOL(port);
val = readl(pin_addr);
edge = val & bit;
if (edge)
writel(bit, pin_addr + MXS_CLR);
else
writel(bit, pin_addr + MXS_SET);
}
/* MXS has one interrupt *per* gpio port */ /* MXS has one interrupt *per* gpio port */
static void mxs_gpio_irq_handler(u32 irq, struct irq_desc *desc) static void mxs_gpio_irq_handler(u32 irq, struct irq_desc *desc)
{ {
...@@ -137,6 +165,9 @@ static void mxs_gpio_irq_handler(u32 irq, struct irq_desc *desc) ...@@ -137,6 +165,9 @@ static void mxs_gpio_irq_handler(u32 irq, struct irq_desc *desc)
while (irq_stat != 0) { while (irq_stat != 0) {
int irqoffset = fls(irq_stat) - 1; int irqoffset = fls(irq_stat) - 1;
if (port->both_edges & (1 << irqoffset))
mxs_flip_edge(port, irqoffset);
generic_handle_irq(irq_find_mapping(port->domain, irqoffset)); generic_handle_irq(irq_find_mapping(port->domain, irqoffset));
irq_stat &= ~(1 << irqoffset); irq_stat &= ~(1 << irqoffset);
} }
......
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
#define PCA957X_TYPE 0x2000 #define PCA957X_TYPE 0x2000
static const struct i2c_device_id pca953x_id[] = { static const struct i2c_device_id pca953x_id[] = {
{ "pca9505", 40 | PCA953X_TYPE | PCA_INT, },
{ "pca9534", 8 | PCA953X_TYPE | PCA_INT, }, { "pca9534", 8 | PCA953X_TYPE | PCA_INT, },
{ "pca9535", 16 | PCA953X_TYPE | PCA_INT, }, { "pca9535", 16 | PCA953X_TYPE | PCA_INT, },
{ "pca9536", 4 | PCA953X_TYPE, }, { "pca9536", 4 | PCA953X_TYPE, },
...@@ -71,19 +72,23 @@ static const struct i2c_device_id pca953x_id[] = { ...@@ -71,19 +72,23 @@ static const struct i2c_device_id pca953x_id[] = {
}; };
MODULE_DEVICE_TABLE(i2c, pca953x_id); MODULE_DEVICE_TABLE(i2c, pca953x_id);
#define MAX_BANK 5
#define BANK_SZ 8
#define NBANK(chip) (chip->gpio_chip.ngpio / BANK_SZ)
struct pca953x_chip { struct pca953x_chip {
unsigned gpio_start; unsigned gpio_start;
u32 reg_output; u8 reg_output[MAX_BANK];
u32 reg_direction; u8 reg_direction[MAX_BANK];
struct mutex i2c_lock; struct mutex i2c_lock;
#ifdef CONFIG_GPIO_PCA953X_IRQ #ifdef CONFIG_GPIO_PCA953X_IRQ
struct mutex irq_lock; struct mutex irq_lock;
u32 irq_mask; u8 irq_mask[MAX_BANK];
u32 irq_stat; u8 irq_stat[MAX_BANK];
u32 irq_trig_raise; u8 irq_trig_raise[MAX_BANK];
u32 irq_trig_fall; u8 irq_trig_fall[MAX_BANK];
int irq_base;
struct irq_domain *domain; struct irq_domain *domain;
#endif #endif
...@@ -93,33 +98,69 @@ struct pca953x_chip { ...@@ -93,33 +98,69 @@ struct pca953x_chip {
int chip_type; int chip_type;
}; };
static int pca953x_write_reg(struct pca953x_chip *chip, int reg, u32 val) static int pca953x_read_single(struct pca953x_chip *chip, int reg, u32 *val,
int off)
{
int ret;
int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
int offset = off / BANK_SZ;
ret = i2c_smbus_read_byte_data(chip->client,
(reg << bank_shift) + offset);
*val = ret;
if (ret < 0) {
dev_err(&chip->client->dev, "failed reading register\n");
return ret;
}
return 0;
}
static int pca953x_write_single(struct pca953x_chip *chip, int reg, u32 val,
int off)
{
int ret = 0;
int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
int offset = off / BANK_SZ;
ret = i2c_smbus_write_byte_data(chip->client,
(reg << bank_shift) + offset, val);
if (ret < 0) {
dev_err(&chip->client->dev, "failed writing register\n");
return ret;
}
return 0;
}
static int pca953x_write_regs(struct pca953x_chip *chip, int reg, u8 *val)
{ {
int ret = 0; int ret = 0;
if (chip->gpio_chip.ngpio <= 8) if (chip->gpio_chip.ngpio <= 8)
ret = i2c_smbus_write_byte_data(chip->client, reg, val); ret = i2c_smbus_write_byte_data(chip->client, reg, *val);
else if (chip->gpio_chip.ngpio == 24) { else if (chip->gpio_chip.ngpio >= 24) {
cpu_to_le32s(&val); int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
ret = i2c_smbus_write_i2c_block_data(chip->client, ret = i2c_smbus_write_i2c_block_data(chip->client,
(reg << 2) | REG_ADDR_AI, (reg << bank_shift) | REG_ADDR_AI,
3, NBANK(chip), val);
(u8 *) &val);
} }
else { else {
switch (chip->chip_type) { switch (chip->chip_type) {
case PCA953X_TYPE: case PCA953X_TYPE:
ret = i2c_smbus_write_word_data(chip->client, ret = i2c_smbus_write_word_data(chip->client,
reg << 1, val); reg << 1, (u16) *val);
break; break;
case PCA957X_TYPE: case PCA957X_TYPE:
ret = i2c_smbus_write_byte_data(chip->client, reg << 1, ret = i2c_smbus_write_byte_data(chip->client, reg << 1,
val & 0xff); val[0]);
if (ret < 0) if (ret < 0)
break; break;
ret = i2c_smbus_write_byte_data(chip->client, ret = i2c_smbus_write_byte_data(chip->client,
(reg << 1) + 1, (reg << 1) + 1,
(val & 0xff00) >> 8); val[1]);
break; break;
} }
} }
...@@ -132,26 +173,24 @@ static int pca953x_write_reg(struct pca953x_chip *chip, int reg, u32 val) ...@@ -132,26 +173,24 @@ static int pca953x_write_reg(struct pca953x_chip *chip, int reg, u32 val)
return 0; return 0;
} }
static int pca953x_read_reg(struct pca953x_chip *chip, int reg, u32 *val) static int pca953x_read_regs(struct pca953x_chip *chip, int reg, u8 *val)
{ {
int ret; int ret;
if (chip->gpio_chip.ngpio <= 8) { if (chip->gpio_chip.ngpio <= 8) {
ret = i2c_smbus_read_byte_data(chip->client, reg); ret = i2c_smbus_read_byte_data(chip->client, reg);
*val = ret; *val = ret;
} } else if (chip->gpio_chip.ngpio >= 24) {
else if (chip->gpio_chip.ngpio == 24) { int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
*val = 0;
ret = i2c_smbus_read_i2c_block_data(chip->client, ret = i2c_smbus_read_i2c_block_data(chip->client,
(reg << 2) | REG_ADDR_AI, (reg << bank_shift) | REG_ADDR_AI,
3, NBANK(chip), val);
(u8 *) val);
le32_to_cpus(val);
} else { } else {
ret = i2c_smbus_read_word_data(chip->client, reg << 1); ret = i2c_smbus_read_word_data(chip->client, reg << 1);
*val = ret; val[0] = (u16)ret & 0xFF;
val[1] = (u16)ret >> 8;
} }
if (ret < 0) { if (ret < 0) {
dev_err(&chip->client->dev, "failed reading register\n"); dev_err(&chip->client->dev, "failed reading register\n");
return ret; return ret;
...@@ -163,13 +202,13 @@ static int pca953x_read_reg(struct pca953x_chip *chip, int reg, u32 *val) ...@@ -163,13 +202,13 @@ static int pca953x_read_reg(struct pca953x_chip *chip, int reg, u32 *val)
static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off) static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
{ {
struct pca953x_chip *chip; struct pca953x_chip *chip;
uint reg_val; u8 reg_val;
int ret, offset = 0; int ret, offset = 0;
chip = container_of(gc, struct pca953x_chip, gpio_chip); chip = container_of(gc, struct pca953x_chip, gpio_chip);
mutex_lock(&chip->i2c_lock); mutex_lock(&chip->i2c_lock);
reg_val = chip->reg_direction | (1u << off); reg_val = chip->reg_direction[off / BANK_SZ] | (1u << (off % BANK_SZ));
switch (chip->chip_type) { switch (chip->chip_type) {
case PCA953X_TYPE: case PCA953X_TYPE:
...@@ -179,11 +218,11 @@ static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off) ...@@ -179,11 +218,11 @@ static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
offset = PCA957X_CFG; offset = PCA957X_CFG;
break; break;
} }
ret = pca953x_write_reg(chip, offset, reg_val); ret = pca953x_write_single(chip, offset, reg_val, off);
if (ret) if (ret)
goto exit; goto exit;
chip->reg_direction = reg_val; chip->reg_direction[off / BANK_SZ] = reg_val;
ret = 0; ret = 0;
exit: exit:
mutex_unlock(&chip->i2c_lock); mutex_unlock(&chip->i2c_lock);
...@@ -194,7 +233,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, ...@@ -194,7 +233,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
unsigned off, int val) unsigned off, int val)
{ {
struct pca953x_chip *chip; struct pca953x_chip *chip;
uint reg_val; u8 reg_val;
int ret, offset = 0; int ret, offset = 0;
chip = container_of(gc, struct pca953x_chip, gpio_chip); chip = container_of(gc, struct pca953x_chip, gpio_chip);
...@@ -202,9 +241,11 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, ...@@ -202,9 +241,11 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
mutex_lock(&chip->i2c_lock); mutex_lock(&chip->i2c_lock);
/* set output level */ /* set output level */
if (val) if (val)
reg_val = chip->reg_output | (1u << off); reg_val = chip->reg_output[off / BANK_SZ]
| (1u << (off % BANK_SZ));
else else
reg_val = chip->reg_output & ~(1u << off); reg_val = chip->reg_output[off / BANK_SZ]
& ~(1u << (off % BANK_SZ));
switch (chip->chip_type) { switch (chip->chip_type) {
case PCA953X_TYPE: case PCA953X_TYPE:
...@@ -214,14 +255,14 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, ...@@ -214,14 +255,14 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
offset = PCA957X_OUT; offset = PCA957X_OUT;
break; break;
} }
ret = pca953x_write_reg(chip, offset, reg_val); ret = pca953x_write_single(chip, offset, reg_val, off);
if (ret) if (ret)
goto exit; goto exit;
chip->reg_output = reg_val; chip->reg_output[off / BANK_SZ] = reg_val;
/* then direction */ /* then direction */
reg_val = chip->reg_direction & ~(1u << off); reg_val = chip->reg_direction[off / BANK_SZ] & ~(1u << (off % BANK_SZ));
switch (chip->chip_type) { switch (chip->chip_type) {
case PCA953X_TYPE: case PCA953X_TYPE:
offset = PCA953X_DIRECTION; offset = PCA953X_DIRECTION;
...@@ -230,11 +271,11 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, ...@@ -230,11 +271,11 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
offset = PCA957X_CFG; offset = PCA957X_CFG;
break; break;
} }
ret = pca953x_write_reg(chip, offset, reg_val); ret = pca953x_write_single(chip, offset, reg_val, off);
if (ret) if (ret)
goto exit; goto exit;
chip->reg_direction = reg_val; chip->reg_direction[off / BANK_SZ] = reg_val;
ret = 0; ret = 0;
exit: exit:
mutex_unlock(&chip->i2c_lock); mutex_unlock(&chip->i2c_lock);
...@@ -258,7 +299,7 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off) ...@@ -258,7 +299,7 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
offset = PCA957X_IN; offset = PCA957X_IN;
break; break;
} }
ret = pca953x_read_reg(chip, offset, &reg_val); ret = pca953x_read_single(chip, offset, &reg_val, off);
mutex_unlock(&chip->i2c_lock); mutex_unlock(&chip->i2c_lock);
if (ret < 0) { if (ret < 0) {
/* NOTE: diagnostic already emitted; that's all we should /* NOTE: diagnostic already emitted; that's all we should
...@@ -274,16 +315,18 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off) ...@@ -274,16 +315,18 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
{ {
struct pca953x_chip *chip; struct pca953x_chip *chip;
u32 reg_val; u8 reg_val;
int ret, offset = 0; int ret, offset = 0;
chip = container_of(gc, struct pca953x_chip, gpio_chip); chip = container_of(gc, struct pca953x_chip, gpio_chip);
mutex_lock(&chip->i2c_lock); mutex_lock(&chip->i2c_lock);
if (val) if (val)
reg_val = chip->reg_output | (1u << off); reg_val = chip->reg_output[off / BANK_SZ]
| (1u << (off % BANK_SZ));
else else
reg_val = chip->reg_output & ~(1u << off); reg_val = chip->reg_output[off / BANK_SZ]
& ~(1u << (off % BANK_SZ));
switch (chip->chip_type) { switch (chip->chip_type) {
case PCA953X_TYPE: case PCA953X_TYPE:
...@@ -293,11 +336,11 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) ...@@ -293,11 +336,11 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
offset = PCA957X_OUT; offset = PCA957X_OUT;
break; break;
} }
ret = pca953x_write_reg(chip, offset, reg_val); ret = pca953x_write_single(chip, offset, reg_val, off);
if (ret) if (ret)
goto exit; goto exit;
chip->reg_output = reg_val; chip->reg_output[off / BANK_SZ] = reg_val;
exit: exit:
mutex_unlock(&chip->i2c_lock); mutex_unlock(&chip->i2c_lock);
} }
...@@ -328,21 +371,21 @@ static int pca953x_gpio_to_irq(struct gpio_chip *gc, unsigned off) ...@@ -328,21 +371,21 @@ static int pca953x_gpio_to_irq(struct gpio_chip *gc, unsigned off)
struct pca953x_chip *chip; struct pca953x_chip *chip;
chip = container_of(gc, struct pca953x_chip, gpio_chip); chip = container_of(gc, struct pca953x_chip, gpio_chip);
return chip->irq_base + off; return irq_create_mapping(chip->domain, off);
} }
static void pca953x_irq_mask(struct irq_data *d) static void pca953x_irq_mask(struct irq_data *d)
{ {
struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
chip->irq_mask &= ~(1 << d->hwirq); chip->irq_mask[d->hwirq / BANK_SZ] &= ~(1 << (d->hwirq % BANK_SZ));
} }
static void pca953x_irq_unmask(struct irq_data *d) static void pca953x_irq_unmask(struct irq_data *d)
{ {
struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
chip->irq_mask |= 1 << d->hwirq; chip->irq_mask[d->hwirq / BANK_SZ] |= 1 << (d->hwirq % BANK_SZ);
} }
static void pca953x_irq_bus_lock(struct irq_data *d) static void pca953x_irq_bus_lock(struct irq_data *d)
...@@ -355,17 +398,20 @@ static void pca953x_irq_bus_lock(struct irq_data *d) ...@@ -355,17 +398,20 @@ static void pca953x_irq_bus_lock(struct irq_data *d)
static void pca953x_irq_bus_sync_unlock(struct irq_data *d) static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
{ {
struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
u32 new_irqs; u8 new_irqs;
u32 level; int level, i;
/* Look for any newly setup interrupt */ /* Look for any newly setup interrupt */
new_irqs = chip->irq_trig_fall | chip->irq_trig_raise; for (i = 0; i < NBANK(chip); i++) {
new_irqs &= ~chip->reg_direction; new_irqs = chip->irq_trig_fall[i] | chip->irq_trig_raise[i];
new_irqs &= ~chip->reg_direction[i];
while (new_irqs) {
level = __ffs(new_irqs); while (new_irqs) {
pca953x_gpio_direction_input(&chip->gpio_chip, level); level = __ffs(new_irqs);
new_irqs &= ~(1 << level); pca953x_gpio_direction_input(&chip->gpio_chip,
level + (BANK_SZ * i));
new_irqs &= ~(1 << level);
}
} }
mutex_unlock(&chip->irq_lock); mutex_unlock(&chip->irq_lock);
...@@ -374,7 +420,8 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d) ...@@ -374,7 +420,8 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
static int pca953x_irq_set_type(struct irq_data *d, unsigned int type) static int pca953x_irq_set_type(struct irq_data *d, unsigned int type)
{ {
struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
u32 mask = 1 << d->hwirq; int bank_nb = d->hwirq / BANK_SZ;
u8 mask = 1 << (d->hwirq % BANK_SZ);
if (!(type & IRQ_TYPE_EDGE_BOTH)) { if (!(type & IRQ_TYPE_EDGE_BOTH)) {
dev_err(&chip->client->dev, "irq %d: unsupported type %d\n", dev_err(&chip->client->dev, "irq %d: unsupported type %d\n",
...@@ -383,14 +430,14 @@ static int pca953x_irq_set_type(struct irq_data *d, unsigned int type) ...@@ -383,14 +430,14 @@ static int pca953x_irq_set_type(struct irq_data *d, unsigned int type)
} }
if (type & IRQ_TYPE_EDGE_FALLING) if (type & IRQ_TYPE_EDGE_FALLING)
chip->irq_trig_fall |= mask; chip->irq_trig_fall[bank_nb] |= mask;
else else
chip->irq_trig_fall &= ~mask; chip->irq_trig_fall[bank_nb] &= ~mask;
if (type & IRQ_TYPE_EDGE_RISING) if (type & IRQ_TYPE_EDGE_RISING)
chip->irq_trig_raise |= mask; chip->irq_trig_raise[bank_nb] |= mask;
else else
chip->irq_trig_raise &= ~mask; chip->irq_trig_raise[bank_nb] &= ~mask;
return 0; return 0;
} }
...@@ -404,13 +451,13 @@ static struct irq_chip pca953x_irq_chip = { ...@@ -404,13 +451,13 @@ static struct irq_chip pca953x_irq_chip = {
.irq_set_type = pca953x_irq_set_type, .irq_set_type = pca953x_irq_set_type,
}; };
static u32 pca953x_irq_pending(struct pca953x_chip *chip) static u8 pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
{ {
u32 cur_stat; u8 cur_stat[MAX_BANK];
u32 old_stat; u8 old_stat[MAX_BANK];
u32 pending; u8 pendings = 0;
u32 trigger; u8 trigger[MAX_BANK], triggers = 0;
int ret, offset = 0; int ret, i, offset = 0;
switch (chip->chip_type) { switch (chip->chip_type) {
case PCA953X_TYPE: case PCA953X_TYPE:
...@@ -420,60 +467,88 @@ static u32 pca953x_irq_pending(struct pca953x_chip *chip) ...@@ -420,60 +467,88 @@ static u32 pca953x_irq_pending(struct pca953x_chip *chip)
offset = PCA957X_IN; offset = PCA957X_IN;
break; break;
} }
ret = pca953x_read_reg(chip, offset, &cur_stat); ret = pca953x_read_regs(chip, offset, cur_stat);
if (ret) if (ret)
return 0; return 0;
/* Remove output pins from the equation */ /* Remove output pins from the equation */
cur_stat &= chip->reg_direction; for (i = 0; i < NBANK(chip); i++)
cur_stat[i] &= chip->reg_direction[i];
memcpy(old_stat, chip->irq_stat, NBANK(chip));
old_stat = chip->irq_stat; for (i = 0; i < NBANK(chip); i++) {
trigger = (cur_stat ^ old_stat) & chip->irq_mask; trigger[i] = (cur_stat[i] ^ old_stat[i]) & chip->irq_mask[i];
triggers += trigger[i];
}
if (!trigger) if (!triggers)
return 0; return 0;
chip->irq_stat = cur_stat; memcpy(chip->irq_stat, cur_stat, NBANK(chip));
pending = (old_stat & chip->irq_trig_fall) | for (i = 0; i < NBANK(chip); i++) {
(cur_stat & chip->irq_trig_raise); pending[i] = (old_stat[i] & chip->irq_trig_fall[i]) |
pending &= trigger; (cur_stat[i] & chip->irq_trig_raise[i]);
pending[i] &= trigger[i];
pendings += pending[i];
}
return pending; return pendings;
} }
static irqreturn_t pca953x_irq_handler(int irq, void *devid) static irqreturn_t pca953x_irq_handler(int irq, void *devid)
{ {
struct pca953x_chip *chip = devid; struct pca953x_chip *chip = devid;
u32 pending; u8 pending[MAX_BANK];
u32 level; u8 level;
int i;
pending = pca953x_irq_pending(chip);
if (!pending) if (!pca953x_irq_pending(chip, pending))
return IRQ_HANDLED; return IRQ_HANDLED;
do { for (i = 0; i < NBANK(chip); i++) {
level = __ffs(pending); while (pending[i]) {
handle_nested_irq(irq_find_mapping(chip->domain, level)); level = __ffs(pending[i]);
handle_nested_irq(irq_find_mapping(chip->domain,
pending &= ~(1 << level); level + (BANK_SZ * i)));
} while (pending); pending[i] &= ~(1 << level);
}
}
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static int pca953x_gpio_irq_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hwirq)
{
irq_clear_status_flags(irq, IRQ_NOREQUEST);
irq_set_chip_data(irq, d->host_data);
irq_set_chip(irq, &pca953x_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 pca953x_irq_simple_ops = {
.map = pca953x_gpio_irq_map,
.xlate = irq_domain_xlate_twocell,
};
static int pca953x_irq_setup(struct pca953x_chip *chip, static int pca953x_irq_setup(struct pca953x_chip *chip,
const struct i2c_device_id *id, const struct i2c_device_id *id,
int irq_base) int irq_base)
{ {
struct i2c_client *client = chip->client; struct i2c_client *client = chip->client;
int ret, offset = 0; int ret, i, offset = 0;
u32 temporary;
if (irq_base != -1 if (irq_base != -1
&& (id->driver_data & PCA_INT)) { && (id->driver_data & PCA_INT)) {
int lvl;
switch (chip->chip_type) { switch (chip->chip_type) {
case PCA953X_TYPE: case PCA953X_TYPE:
...@@ -483,49 +558,29 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, ...@@ -483,49 +558,29 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
offset = PCA957X_IN; offset = PCA957X_IN;
break; break;
} }
ret = pca953x_read_reg(chip, offset, &temporary); ret = pca953x_read_regs(chip, offset, chip->irq_stat);
chip->irq_stat = temporary;
if (ret) if (ret)
goto out_failed; return ret;
/* /*
* There is no way to know which GPIO line generated the * There is no way to know which GPIO line generated the
* interrupt. We have to rely on the previous read for * interrupt. We have to rely on the previous read for
* this purpose. * this purpose.
*/ */
chip->irq_stat &= chip->reg_direction; for (i = 0; i < NBANK(chip); i++)
chip->irq_stat[i] &= chip->reg_direction[i];
mutex_init(&chip->irq_lock); mutex_init(&chip->irq_lock);
chip->irq_base = irq_alloc_descs(-1, irq_base, chip->gpio_chip.ngpio, -1); chip->domain = irq_domain_add_simple(client->dev.of_node,
if (chip->irq_base < 0)
goto out_failed;
chip->domain = irq_domain_add_legacy(client->dev.of_node,
chip->gpio_chip.ngpio, chip->gpio_chip.ngpio,
chip->irq_base, irq_base,
0, &pca953x_irq_simple_ops,
&irq_domain_simple_ops,
NULL); NULL);
if (!chip->domain) { if (!chip->domain)
ret = -ENODEV; return -ENODEV;
goto out_irqdesc_free;
}
for (lvl = 0; lvl < chip->gpio_chip.ngpio; lvl++) { ret = devm_request_threaded_irq(&client->dev,
int irq = lvl + chip->irq_base; client->irq,
irq_clear_status_flags(irq, IRQ_NOREQUEST);
irq_set_chip_data(irq, chip);
irq_set_chip(irq, &pca953x_irq_chip);
irq_set_nested_thread(irq, true);
#ifdef CONFIG_ARM
set_irq_flags(irq, IRQF_VALID);
#else
irq_set_noprobe(irq);
#endif
}
ret = request_threaded_irq(client->irq,
NULL, NULL,
pca953x_irq_handler, pca953x_irq_handler,
IRQF_TRIGGER_LOW | IRQF_ONESHOT, IRQF_TRIGGER_LOW | IRQF_ONESHOT,
...@@ -533,28 +588,15 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, ...@@ -533,28 +588,15 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
if (ret) { if (ret) {
dev_err(&client->dev, "failed to request irq %d\n", dev_err(&client->dev, "failed to request irq %d\n",
client->irq); client->irq);
goto out_irqdesc_free; return ret;
} }
chip->gpio_chip.to_irq = pca953x_gpio_to_irq; chip->gpio_chip.to_irq = pca953x_gpio_to_irq;
} }
return 0; return 0;
out_irqdesc_free:
irq_free_descs(chip->irq_base, chip->gpio_chip.ngpio);
out_failed:
chip->irq_base = -1;
return ret;
} }
static void pca953x_irq_teardown(struct pca953x_chip *chip)
{
if (chip->irq_base != -1) {
irq_free_descs(chip->irq_base, chip->gpio_chip.ngpio);
free_irq(chip->client->irq, chip);
}
}
#else /* CONFIG_GPIO_PCA953X_IRQ */ #else /* CONFIG_GPIO_PCA953X_IRQ */
static int pca953x_irq_setup(struct pca953x_chip *chip, static int pca953x_irq_setup(struct pca953x_chip *chip,
const struct i2c_device_id *id, const struct i2c_device_id *id,
...@@ -567,10 +609,6 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, ...@@ -567,10 +609,6 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
return 0; return 0;
} }
static void pca953x_irq_teardown(struct pca953x_chip *chip)
{
}
#endif #endif
/* /*
...@@ -619,18 +657,24 @@ pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, u32 *invert) ...@@ -619,18 +657,24 @@ pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, u32 *invert)
static int device_pca953x_init(struct pca953x_chip *chip, u32 invert) static int device_pca953x_init(struct pca953x_chip *chip, u32 invert)
{ {
int ret; int ret;
u8 val[MAX_BANK];
ret = pca953x_read_reg(chip, PCA953X_OUTPUT, &chip->reg_output); ret = pca953x_read_regs(chip, PCA953X_OUTPUT, chip->reg_output);
if (ret) if (ret)
goto out; goto out;
ret = pca953x_read_reg(chip, PCA953X_DIRECTION, ret = pca953x_read_regs(chip, PCA953X_DIRECTION,
&chip->reg_direction); chip->reg_direction);
if (ret) if (ret)
goto out; goto out;
/* set platform specific polarity inversion */ /* set platform specific polarity inversion */
ret = pca953x_write_reg(chip, PCA953X_INVERT, invert); if (invert)
memset(val, 0xFF, NBANK(chip));
else
memset(val, 0, NBANK(chip));
ret = pca953x_write_regs(chip, PCA953X_INVERT, val);
out: out:
return ret; return ret;
} }
...@@ -638,28 +682,36 @@ static int device_pca953x_init(struct pca953x_chip *chip, u32 invert) ...@@ -638,28 +682,36 @@ static int device_pca953x_init(struct pca953x_chip *chip, u32 invert)
static int device_pca957x_init(struct pca953x_chip *chip, u32 invert) static int device_pca957x_init(struct pca953x_chip *chip, u32 invert)
{ {
int ret; int ret;
u32 val = 0; u8 val[MAX_BANK];
/* Let every port in proper state, that could save power */ /* Let every port in proper state, that could save power */
pca953x_write_reg(chip, PCA957X_PUPD, 0x0); memset(val, 0, NBANK(chip));
pca953x_write_reg(chip, PCA957X_CFG, 0xffff); pca953x_write_regs(chip, PCA957X_PUPD, val);
pca953x_write_reg(chip, PCA957X_OUT, 0x0); memset(val, 0xFF, NBANK(chip));
pca953x_write_regs(chip, PCA957X_CFG, val);
ret = pca953x_read_reg(chip, PCA957X_IN, &val); memset(val, 0, NBANK(chip));
pca953x_write_regs(chip, PCA957X_OUT, val);
ret = pca953x_read_regs(chip, PCA957X_IN, val);
if (ret) if (ret)
goto out; goto out;
ret = pca953x_read_reg(chip, PCA957X_OUT, &chip->reg_output); ret = pca953x_read_regs(chip, PCA957X_OUT, chip->reg_output);
if (ret) if (ret)
goto out; goto out;
ret = pca953x_read_reg(chip, PCA957X_CFG, &chip->reg_direction); ret = pca953x_read_regs(chip, PCA957X_CFG, chip->reg_direction);
if (ret) if (ret)
goto out; goto out;
/* set platform specific polarity inversion */ /* set platform specific polarity inversion */
pca953x_write_reg(chip, PCA957X_INVRT, invert); if (invert)
memset(val, 0xFF, NBANK(chip));
else
memset(val, 0, NBANK(chip));
pca953x_write_regs(chip, PCA957X_INVRT, val);
/* To enable register 6, 7 to controll pull up and pull down */ /* To enable register 6, 7 to controll pull up and pull down */
pca953x_write_reg(chip, PCA957X_BKEN, 0x202); memset(val, 0x02, NBANK(chip));
pca953x_write_regs(chip, PCA957X_BKEN, val);
return 0; return 0;
out: out:
...@@ -675,7 +727,8 @@ static int pca953x_probe(struct i2c_client *client, ...@@ -675,7 +727,8 @@ static int pca953x_probe(struct i2c_client *client,
int ret; int ret;
u32 invert = 0; u32 invert = 0;
chip = kzalloc(sizeof(struct pca953x_chip), GFP_KERNEL); chip = devm_kzalloc(&client->dev,
sizeof(struct pca953x_chip), GFP_KERNEL);
if (chip == NULL) if (chip == NULL)
return -ENOMEM; return -ENOMEM;
...@@ -710,15 +763,15 @@ static int pca953x_probe(struct i2c_client *client, ...@@ -710,15 +763,15 @@ static int pca953x_probe(struct i2c_client *client,
else else
ret = device_pca957x_init(chip, invert); ret = device_pca957x_init(chip, invert);
if (ret) if (ret)
goto out_failed; return ret;
ret = pca953x_irq_setup(chip, id, irq_base); ret = pca953x_irq_setup(chip, id, irq_base);
if (ret) if (ret)
goto out_failed; return ret;
ret = gpiochip_add(&chip->gpio_chip); ret = gpiochip_add(&chip->gpio_chip);
if (ret) if (ret)
goto out_failed_irq; return ret;
if (pdata && pdata->setup) { if (pdata && pdata->setup) {
ret = pdata->setup(client, chip->gpio_chip.base, ret = pdata->setup(client, chip->gpio_chip.base,
...@@ -729,12 +782,6 @@ static int pca953x_probe(struct i2c_client *client, ...@@ -729,12 +782,6 @@ static int pca953x_probe(struct i2c_client *client,
i2c_set_clientdata(client, chip); i2c_set_clientdata(client, chip);
return 0; return 0;
out_failed_irq:
pca953x_irq_teardown(chip);
out_failed:
kfree(chip);
return ret;
} }
static int pca953x_remove(struct i2c_client *client) static int pca953x_remove(struct i2c_client *client)
...@@ -760,12 +807,11 @@ static int pca953x_remove(struct i2c_client *client) ...@@ -760,12 +807,11 @@ static int pca953x_remove(struct i2c_client *client)
return ret; return ret;
} }
pca953x_irq_teardown(chip);
kfree(chip);
return 0; return 0;
} }
static const struct of_device_id pca953x_dt_ids[] = { static const struct of_device_id pca953x_dt_ids[] = {
{ .compatible = "nxp,pca9505", },
{ .compatible = "nxp,pca9534", }, { .compatible = "nxp,pca9534", },
{ .compatible = "nxp,pca9535", }, { .compatible = "nxp,pca9535", },
{ .compatible = "nxp,pca9536", }, { .compatible = "nxp,pca9536", },
......
...@@ -365,7 +365,7 @@ static int __init pl061_gpio_init(void) ...@@ -365,7 +365,7 @@ static int __init pl061_gpio_init(void)
{ {
return amba_driver_register(&pl061_gpio_driver); return amba_driver_register(&pl061_gpio_driver);
} }
subsys_initcall(pl061_gpio_init); module_init(pl061_gpio_init);
MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>"); MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
MODULE_DESCRIPTION("PL061 GPIO driver"); MODULE_DESCRIPTION("PL061 GPIO driver");
......
...@@ -642,12 +642,7 @@ static struct platform_driver pxa_gpio_driver = { ...@@ -642,12 +642,7 @@ static struct platform_driver pxa_gpio_driver = {
.of_match_table = of_match_ptr(pxa_gpio_dt_ids), .of_match_table = of_match_ptr(pxa_gpio_dt_ids),
}, },
}; };
module_platform_driver(pxa_gpio_driver);
static int __init pxa_gpio_init(void)
{
return platform_driver_register(&pxa_gpio_driver);
}
postcore_initcall(pxa_gpio_init);
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int pxa_gpio_suspend(void) static int pxa_gpio_suspend(void)
......
...@@ -37,7 +37,6 @@ ...@@ -37,7 +37,6 @@
#include <linux/i2c/twl.h> #include <linux/i2c/twl.h>
/* /*
* The GPIO "subchip" supports 18 GPIOs which can be configured as * The GPIO "subchip" supports 18 GPIOs which can be configured as
* inputs or outputs, with pullups or pulldowns on each pin. Each * inputs or outputs, with pullups or pulldowns on each pin. Each
...@@ -49,11 +48,6 @@ ...@@ -49,11 +48,6 @@
* There are also two LED pins used sometimes as output-only GPIOs. * There are also two LED pins used sometimes as output-only GPIOs.
*/ */
static struct gpio_chip twl_gpiochip;
static int twl4030_gpio_base;
static int twl4030_gpio_irq_base;
/* genirq interfaces are not available to modules */ /* genirq interfaces are not available to modules */
#ifdef MODULE #ifdef MODULE
#define is_module() true #define is_module() true
...@@ -69,14 +63,24 @@ static int twl4030_gpio_irq_base; ...@@ -69,14 +63,24 @@ static int twl4030_gpio_irq_base;
/* Mask for GPIO registers when aggregated into a 32-bit integer */ /* Mask for GPIO registers when aggregated into a 32-bit integer */
#define GPIO_32_MASK 0x0003ffff #define GPIO_32_MASK 0x0003ffff
/* Data structures */ struct gpio_twl4030_priv {
static DEFINE_MUTEX(gpio_lock); struct gpio_chip gpio_chip;
struct mutex mutex;
int irq_base;
/* store usage of each GPIO. - each bit represents one GPIO */ /* Bitfields for state caching */
static unsigned int gpio_usage_count; unsigned int usage_count;
unsigned int direction;
unsigned int out_state;
};
/*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/
static inline struct gpio_twl4030_priv *to_gpio_twl4030(struct gpio_chip *chip)
{
return container_of(chip, struct gpio_twl4030_priv, gpio_chip);
}
/* /*
* To configure TWL4030 GPIO module registers * To configure TWL4030 GPIO module registers
*/ */
...@@ -126,7 +130,7 @@ static inline int gpio_twl4030_read(u8 address) ...@@ -126,7 +130,7 @@ static inline int gpio_twl4030_read(u8 address)
/*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/
static u8 cached_leden; /* protected by gpio_lock */ static u8 cached_leden;
/* The LED lines are open drain outputs ... a FET pulls to GND, so an /* The LED lines are open drain outputs ... a FET pulls to GND, so an
* external pullup is needed. We could also expose the integrated PWM * external pullup is needed. We could also expose the integrated PWM
...@@ -140,14 +144,12 @@ static void twl4030_led_set_value(int led, int value) ...@@ -140,14 +144,12 @@ static void twl4030_led_set_value(int led, int value)
if (led) if (led)
mask <<= 1; mask <<= 1;
mutex_lock(&gpio_lock);
if (value) if (value)
cached_leden &= ~mask; cached_leden &= ~mask;
else else
cached_leden |= mask; cached_leden |= mask;
status = twl_i2c_write_u8(TWL4030_MODULE_LED, cached_leden, status = twl_i2c_write_u8(TWL4030_MODULE_LED, cached_leden,
TWL4030_LED_LEDEN_REG); TWL4030_LED_LEDEN_REG);
mutex_unlock(&gpio_lock);
} }
static int twl4030_set_gpio_direction(int gpio, int is_input) static int twl4030_set_gpio_direction(int gpio, int is_input)
...@@ -158,7 +160,6 @@ static int twl4030_set_gpio_direction(int gpio, int is_input) ...@@ -158,7 +160,6 @@ static int twl4030_set_gpio_direction(int gpio, int is_input)
u8 base = REG_GPIODATADIR1 + d_bnk; u8 base = REG_GPIODATADIR1 + d_bnk;
int ret = 0; int ret = 0;
mutex_lock(&gpio_lock);
ret = gpio_twl4030_read(base); ret = gpio_twl4030_read(base);
if (ret >= 0) { if (ret >= 0) {
if (is_input) if (is_input)
...@@ -168,7 +169,6 @@ static int twl4030_set_gpio_direction(int gpio, int is_input) ...@@ -168,7 +169,6 @@ static int twl4030_set_gpio_direction(int gpio, int is_input)
ret = gpio_twl4030_write(base, reg); ret = gpio_twl4030_write(base, reg);
} }
mutex_unlock(&gpio_lock);
return ret; return ret;
} }
...@@ -193,10 +193,6 @@ static int twl4030_get_gpio_datain(int gpio) ...@@ -193,10 +193,6 @@ static int twl4030_get_gpio_datain(int gpio)
u8 base = 0; u8 base = 0;
int ret = 0; int ret = 0;
if (unlikely((gpio >= TWL4030_GPIO_MAX)
|| !(gpio_usage_count & BIT(gpio))))
return -EPERM;
base = REG_GPIODATAIN1 + d_bnk; base = REG_GPIODATAIN1 + d_bnk;
ret = gpio_twl4030_read(base); ret = gpio_twl4030_read(base);
if (ret > 0) if (ret > 0)
...@@ -209,9 +205,10 @@ static int twl4030_get_gpio_datain(int gpio) ...@@ -209,9 +205,10 @@ static int twl4030_get_gpio_datain(int gpio)
static int twl_request(struct gpio_chip *chip, unsigned offset) static int twl_request(struct gpio_chip *chip, unsigned offset)
{ {
struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
int status = 0; int status = 0;
mutex_lock(&gpio_lock); mutex_lock(&priv->mutex);
/* Support the two LED outputs as output-only GPIOs. */ /* Support the two LED outputs as output-only GPIOs. */
if (offset >= TWL4030_GPIO_MAX) { if (offset >= TWL4030_GPIO_MAX) {
...@@ -252,7 +249,7 @@ static int twl_request(struct gpio_chip *chip, unsigned offset) ...@@ -252,7 +249,7 @@ static int twl_request(struct gpio_chip *chip, unsigned offset)
} }
/* on first use, turn GPIO module "on" */ /* on first use, turn GPIO module "on" */
if (!gpio_usage_count) { if (!priv->usage_count) {
struct twl4030_gpio_platform_data *pdata; struct twl4030_gpio_platform_data *pdata;
u8 value = MASK_GPIO_CTRL_GPIO_ON; u8 value = MASK_GPIO_CTRL_GPIO_ON;
...@@ -266,79 +263,120 @@ static int twl_request(struct gpio_chip *chip, unsigned offset) ...@@ -266,79 +263,120 @@ static int twl_request(struct gpio_chip *chip, unsigned offset)
status = gpio_twl4030_write(REG_GPIO_CTRL, value); status = gpio_twl4030_write(REG_GPIO_CTRL, value);
} }
done:
if (!status) if (!status)
gpio_usage_count |= (0x1 << offset); priv->usage_count |= BIT(offset);
done: mutex_unlock(&priv->mutex);
mutex_unlock(&gpio_lock);
return status; return status;
} }
static void twl_free(struct gpio_chip *chip, unsigned offset) static void twl_free(struct gpio_chip *chip, unsigned offset)
{ {
struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
mutex_lock(&priv->mutex);
if (offset >= TWL4030_GPIO_MAX) { if (offset >= TWL4030_GPIO_MAX) {
twl4030_led_set_value(offset - TWL4030_GPIO_MAX, 1); twl4030_led_set_value(offset - TWL4030_GPIO_MAX, 1);
return; goto out;
} }
mutex_lock(&gpio_lock); priv->usage_count &= ~BIT(offset);
gpio_usage_count &= ~BIT(offset);
/* on last use, switch off GPIO module */ /* on last use, switch off GPIO module */
if (!gpio_usage_count) if (!priv->usage_count)
gpio_twl4030_write(REG_GPIO_CTRL, 0x0); gpio_twl4030_write(REG_GPIO_CTRL, 0x0);
mutex_unlock(&gpio_lock); out:
mutex_unlock(&priv->mutex);
} }
static int twl_direction_in(struct gpio_chip *chip, unsigned offset) static int twl_direction_in(struct gpio_chip *chip, unsigned offset)
{ {
return (offset < TWL4030_GPIO_MAX) struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
? twl4030_set_gpio_direction(offset, 1) int ret;
: -EINVAL;
mutex_lock(&priv->mutex);
if (offset < TWL4030_GPIO_MAX)
ret = twl4030_set_gpio_direction(offset, 1);
else
ret = -EINVAL;
if (!ret)
priv->direction &= ~BIT(offset);
mutex_unlock(&priv->mutex);
return ret;
} }
static int twl_get(struct gpio_chip *chip, unsigned offset) static int twl_get(struct gpio_chip *chip, unsigned offset)
{ {
struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
int ret;
int status = 0; int status = 0;
if (offset < TWL4030_GPIO_MAX) mutex_lock(&priv->mutex);
status = twl4030_get_gpio_datain(offset); if (!(priv->usage_count & BIT(offset))) {
else if (offset == TWL4030_GPIO_MAX) ret = -EPERM;
status = cached_leden & LEDEN_LEDAON; goto out;
}
if (priv->direction & BIT(offset))
status = priv->out_state & BIT(offset);
else else
status = cached_leden & LEDEN_LEDBON; status = twl4030_get_gpio_datain(offset);
return (status < 0) ? 0 : status;
ret = (status <= 0) ? 0 : 1;
out:
mutex_unlock(&priv->mutex);
return ret;
} }
static int twl_direction_out(struct gpio_chip *chip, unsigned offset, int value) static void twl_set(struct gpio_chip *chip, unsigned offset, int value)
{ {
if (offset < TWL4030_GPIO_MAX) { struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
mutex_lock(&priv->mutex);
if (offset < TWL4030_GPIO_MAX)
twl4030_set_gpio_dataout(offset, value); twl4030_set_gpio_dataout(offset, value);
return twl4030_set_gpio_direction(offset, 0); else
} else {
twl4030_led_set_value(offset - TWL4030_GPIO_MAX, value); twl4030_led_set_value(offset - TWL4030_GPIO_MAX, value);
return 0;
} if (value)
priv->out_state |= BIT(offset);
else
priv->out_state &= ~BIT(offset);
mutex_unlock(&priv->mutex);
} }
static void twl_set(struct gpio_chip *chip, unsigned offset, int value) static int twl_direction_out(struct gpio_chip *chip, unsigned offset, int value)
{ {
struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
mutex_lock(&priv->mutex);
if (offset < TWL4030_GPIO_MAX) if (offset < TWL4030_GPIO_MAX)
twl4030_set_gpio_dataout(offset, value); twl4030_set_gpio_dataout(offset, value);
else
twl4030_led_set_value(offset - TWL4030_GPIO_MAX, value); priv->direction |= BIT(offset);
mutex_unlock(&priv->mutex);
twl_set(chip, offset, value);
return 0;
} }
static int twl_to_irq(struct gpio_chip *chip, unsigned offset) static int twl_to_irq(struct gpio_chip *chip, unsigned offset)
{ {
return (twl4030_gpio_irq_base && (offset < TWL4030_GPIO_MAX)) struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
? (twl4030_gpio_irq_base + offset)
return (priv->irq_base && (offset < TWL4030_GPIO_MAX))
? (priv->irq_base + offset)
: -EINVAL; : -EINVAL;
} }
static struct gpio_chip twl_gpiochip = { static struct gpio_chip template_chip = {
.label = "twl4030", .label = "twl4030",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.request = twl_request, .request = twl_request,
...@@ -424,8 +462,14 @@ static int gpio_twl4030_probe(struct platform_device *pdev) ...@@ -424,8 +462,14 @@ static int gpio_twl4030_probe(struct platform_device *pdev)
{ {
struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data; struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data;
struct device_node *node = pdev->dev.of_node; struct device_node *node = pdev->dev.of_node;
struct gpio_twl4030_priv *priv;
int ret, irq_base; int ret, irq_base;
priv = devm_kzalloc(&pdev->dev, sizeof(struct gpio_twl4030_priv),
GFP_KERNEL);
if (!priv)
return -ENOMEM;
/* maybe setup IRQs */ /* maybe setup IRQs */
if (is_module()) { if (is_module()) {
dev_err(&pdev->dev, "can't dispatch IRQs from modules\n"); dev_err(&pdev->dev, "can't dispatch IRQs from modules\n");
...@@ -445,12 +489,15 @@ static int gpio_twl4030_probe(struct platform_device *pdev) ...@@ -445,12 +489,15 @@ static int gpio_twl4030_probe(struct platform_device *pdev)
if (ret < 0) if (ret < 0)
return ret; return ret;
twl4030_gpio_irq_base = irq_base; priv->irq_base = irq_base;
no_irqs: no_irqs:
twl_gpiochip.base = -1; priv->gpio_chip = template_chip;
twl_gpiochip.ngpio = TWL4030_GPIO_MAX; priv->gpio_chip.base = -1;
twl_gpiochip.dev = &pdev->dev; priv->gpio_chip.ngpio = TWL4030_GPIO_MAX;
priv->gpio_chip.dev = &pdev->dev;
mutex_init(&priv->mutex);
if (node) if (node)
pdata = of_gpio_twl4030(&pdev->dev); pdata = of_gpio_twl4030(&pdev->dev);
...@@ -481,23 +528,23 @@ static int gpio_twl4030_probe(struct platform_device *pdev) ...@@ -481,23 +528,23 @@ static int gpio_twl4030_probe(struct platform_device *pdev)
* is (still) clear if use_leds is set. * is (still) clear if use_leds is set.
*/ */
if (pdata->use_leds) if (pdata->use_leds)
twl_gpiochip.ngpio += 2; priv->gpio_chip.ngpio += 2;
ret = gpiochip_add(&twl_gpiochip); ret = gpiochip_add(&priv->gpio_chip);
if (ret < 0) { if (ret < 0) {
dev_err(&pdev->dev, "could not register gpiochip, %d\n", ret); dev_err(&pdev->dev, "could not register gpiochip, %d\n", ret);
twl_gpiochip.ngpio = 0; priv->gpio_chip.ngpio = 0;
gpio_twl4030_remove(pdev); gpio_twl4030_remove(pdev);
goto out; goto out;
} }
twl4030_gpio_base = twl_gpiochip.base; platform_set_drvdata(pdev, priv);
if (pdata && pdata->setup) { if (pdata && pdata->setup) {
int status; int status;
status = pdata->setup(&pdev->dev, status = pdata->setup(&pdev->dev, priv->gpio_chip.base,
twl4030_gpio_base, TWL4030_GPIO_MAX); TWL4030_GPIO_MAX);
if (status) if (status)
dev_dbg(&pdev->dev, "setup --> %d\n", status); dev_dbg(&pdev->dev, "setup --> %d\n", status);
} }
...@@ -510,18 +557,19 @@ static int gpio_twl4030_probe(struct platform_device *pdev) ...@@ -510,18 +557,19 @@ static int gpio_twl4030_probe(struct platform_device *pdev)
static int gpio_twl4030_remove(struct platform_device *pdev) static int gpio_twl4030_remove(struct platform_device *pdev)
{ {
struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data; struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data;
struct gpio_twl4030_priv *priv = platform_get_drvdata(pdev);
int status; int status;
if (pdata && pdata->teardown) { if (pdata && pdata->teardown) {
status = pdata->teardown(&pdev->dev, status = pdata->teardown(&pdev->dev, priv->gpio_chip.base,
twl4030_gpio_base, TWL4030_GPIO_MAX); TWL4030_GPIO_MAX);
if (status) { if (status) {
dev_dbg(&pdev->dev, "teardown --> %d\n", status); dev_dbg(&pdev->dev, "teardown --> %d\n", status);
return status; return status;
} }
} }
status = gpiochip_remove(&twl_gpiochip); status = gpiochip_remove(&priv->gpio_chip);
if (status < 0) if (status < 0)
return status; return status;
......
...@@ -73,19 +73,20 @@ struct vt8500_gpio_data { ...@@ -73,19 +73,20 @@ struct vt8500_gpio_data {
static struct vt8500_gpio_data vt8500_data = { static struct vt8500_gpio_data vt8500_data = {
.num_banks = 7, .num_banks = 7,
.banks = { .banks = {
VT8500_BANK(NO_REG, 0x3C, 0x5C, 0x7C, 9),
VT8500_BANK(0x00, 0x20, 0x40, 0x60, 26), VT8500_BANK(0x00, 0x20, 0x40, 0x60, 26),
VT8500_BANK(0x04, 0x24, 0x44, 0x64, 28), VT8500_BANK(0x04, 0x24, 0x44, 0x64, 28),
VT8500_BANK(0x08, 0x28, 0x48, 0x68, 31), VT8500_BANK(0x08, 0x28, 0x48, 0x68, 31),
VT8500_BANK(0x0C, 0x2C, 0x4C, 0x6C, 19), VT8500_BANK(0x0C, 0x2C, 0x4C, 0x6C, 19),
VT8500_BANK(0x10, 0x30, 0x50, 0x70, 19), VT8500_BANK(0x10, 0x30, 0x50, 0x70, 19),
VT8500_BANK(0x14, 0x34, 0x54, 0x74, 23), VT8500_BANK(0x14, 0x34, 0x54, 0x74, 23),
VT8500_BANK(NO_REG, 0x3C, 0x5C, 0x7C, 9),
}, },
}; };
static struct vt8500_gpio_data wm8505_data = { static struct vt8500_gpio_data wm8505_data = {
.num_banks = 10, .num_banks = 10,
.banks = { .banks = {
VT8500_BANK(0x64, 0x8C, 0xB4, 0xDC, 22),
VT8500_BANK(0x40, 0x68, 0x90, 0xB8, 8), VT8500_BANK(0x40, 0x68, 0x90, 0xB8, 8),
VT8500_BANK(0x44, 0x6C, 0x94, 0xBC, 32), VT8500_BANK(0x44, 0x6C, 0x94, 0xBC, 32),
VT8500_BANK(0x48, 0x70, 0x98, 0xC0, 6), VT8500_BANK(0x48, 0x70, 0x98, 0xC0, 6),
...@@ -95,7 +96,6 @@ static struct vt8500_gpio_data wm8505_data = { ...@@ -95,7 +96,6 @@ static struct vt8500_gpio_data wm8505_data = {
VT8500_BANK(0x58, 0x80, 0xA8, 0xD0, 5), VT8500_BANK(0x58, 0x80, 0xA8, 0xD0, 5),
VT8500_BANK(0x5C, 0x84, 0xAC, 0xD4, 12), VT8500_BANK(0x5C, 0x84, 0xAC, 0xD4, 12),
VT8500_BANK(0x60, 0x88, 0xB0, 0xD8, 16), VT8500_BANK(0x60, 0x88, 0xB0, 0xD8, 16),
VT8500_BANK(0x64, 0x8C, 0xB4, 0xDC, 22),
VT8500_BANK(0x500, 0x504, 0x508, 0x50C, 6), VT8500_BANK(0x500, 0x504, 0x508, 0x50C, 6),
}, },
}; };
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/export.h> #include <linux/export.h>
#include <linux/acpi_gpio.h> #include <linux/acpi_gpio.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/interrupt.h>
static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
{ {
...@@ -52,3 +53,89 @@ int acpi_get_gpio(char *path, int pin) ...@@ -52,3 +53,89 @@ int acpi_get_gpio(char *path, int pin)
return chip->base + pin; return chip->base + pin;
} }
EXPORT_SYMBOL_GPL(acpi_get_gpio); EXPORT_SYMBOL_GPL(acpi_get_gpio);
static irqreturn_t acpi_gpio_irq_handler(int irq, void *data)
{
acpi_handle handle = data;
acpi_evaluate_object(handle, NULL, NULL, NULL);
return IRQ_HANDLED;
}
/**
* acpi_gpiochip_request_interrupts() - Register isr for gpio chip ACPI events
* @chip: gpio chip
*
* ACPI5 platforms can use GPIO signaled ACPI events. These GPIO interrupts are
* handled by ACPI event methods which need to be called from the GPIO
* chip's interrupt handler. acpi_gpiochip_request_interrupts finds out which
* gpio pins have acpi event methods and assigns interrupt handlers that calls
* the acpi event methods for those pins.
*
* Interrupts are automatically freed on driver detach
*/
void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)
{
struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL};
struct acpi_resource *res;
acpi_handle handle, ev_handle;
acpi_status status;
unsigned int pin;
int irq, ret;
char ev_name[5];
if (!chip->dev || !chip->to_irq)
return;
handle = ACPI_HANDLE(chip->dev);
if (!handle)
return;
status = acpi_get_event_resources(handle, &buf);
if (ACPI_FAILURE(status))
return;
/* If a gpio interrupt has an acpi event handler method, then
* set up an interrupt handler that calls the acpi event handler
*/
for (res = buf.pointer;
res && (res->type != ACPI_RESOURCE_TYPE_END_TAG);
res = ACPI_NEXT_RESOURCE(res)) {
if (res->type != ACPI_RESOURCE_TYPE_GPIO ||
res->data.gpio.connection_type !=
ACPI_RESOURCE_GPIO_TYPE_INT)
continue;
pin = res->data.gpio.pin_table[0];
if (pin > chip->ngpio)
continue;
sprintf(ev_name, "_%c%02X",
res->data.gpio.triggering ? 'E' : 'L', pin);
status = acpi_get_handle(handle, ev_name, &ev_handle);
if (ACPI_FAILURE(status))
continue;
irq = chip->to_irq(chip, pin);
if (irq < 0)
continue;
/* Assume BIOS sets the triggering, so no flags */
ret = devm_request_threaded_irq(chip->dev, irq, NULL,
acpi_gpio_irq_handler,
0,
"GPIO-signaled-ACPI-event",
ev_handle);
if (ret)
dev_err(chip->dev,
"Failed to request IRQ %d ACPI event handler\n",
irq);
}
}
EXPORT_SYMBOL(acpi_gpiochip_request_interrupts);
...@@ -52,14 +52,13 @@ struct gpio_desc { ...@@ -52,14 +52,13 @@ struct gpio_desc {
/* flag symbols are bit numbers */ /* flag symbols are bit numbers */
#define FLAG_REQUESTED 0 #define FLAG_REQUESTED 0
#define FLAG_IS_OUT 1 #define FLAG_IS_OUT 1
#define FLAG_RESERVED 2 #define FLAG_EXPORT 2 /* protected by sysfs_lock */
#define FLAG_EXPORT 3 /* protected by sysfs_lock */ #define FLAG_SYSFS 3 /* exported via /sys/class/gpio/control */
#define FLAG_SYSFS 4 /* exported via /sys/class/gpio/control */ #define FLAG_TRIG_FALL 4 /* trigger on falling edge */
#define FLAG_TRIG_FALL 5 /* trigger on falling edge */ #define FLAG_TRIG_RISE 5 /* trigger on rising edge */
#define FLAG_TRIG_RISE 6 /* trigger on rising edge */ #define FLAG_ACTIVE_LOW 6 /* sysfs value has active low */
#define FLAG_ACTIVE_LOW 7 /* sysfs value has active low */ #define FLAG_OPEN_DRAIN 7 /* Gpio is open drain type */
#define FLAG_OPEN_DRAIN 8 /* Gpio is open drain type */ #define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */
#define FLAG_OPEN_SOURCE 9 /* Gpio is open source type */
#define ID_SHIFT 16 /* add new flags before this one */ #define ID_SHIFT 16 /* add new flags before this one */
...@@ -132,7 +131,7 @@ static int gpiochip_find_base(int ngpio) ...@@ -132,7 +131,7 @@ static int gpiochip_find_base(int ngpio)
struct gpio_desc *desc = &gpio_desc[i]; struct gpio_desc *desc = &gpio_desc[i];
struct gpio_chip *chip = desc->chip; struct gpio_chip *chip = desc->chip;
if (!chip && !test_bit(FLAG_RESERVED, &desc->flags)) { if (!chip) {
spare++; spare++;
if (spare == ngpio) { if (spare == ngpio) {
base = i; base = i;
...@@ -150,47 +149,6 @@ static int gpiochip_find_base(int ngpio) ...@@ -150,47 +149,6 @@ static int gpiochip_find_base(int ngpio)
return base; return base;
} }
/**
* gpiochip_reserve() - reserve range of gpios to use with platform code only
* @start: starting gpio number
* @ngpio: number of gpios to reserve
* Context: platform init, potentially before irqs or kmalloc will work
*
* Returns a negative errno if any gpio within the range is already reserved
* or registered, else returns zero as a success code. Use this function
* to mark a range of gpios as unavailable for dynamic gpio number allocation,
* for example because its driver support is not yet loaded.
*/
int __init gpiochip_reserve(int start, int ngpio)
{
int ret = 0;
unsigned long flags;
int i;
if (!gpio_is_valid(start) || !gpio_is_valid(start + ngpio - 1))
return -EINVAL;
spin_lock_irqsave(&gpio_lock, flags);
for (i = start; i < start + ngpio; i++) {
struct gpio_desc *desc = &gpio_desc[i];
if (desc->chip || test_bit(FLAG_RESERVED, &desc->flags)) {
ret = -EBUSY;
goto err;
}
set_bit(FLAG_RESERVED, &desc->flags);
}
pr_debug("%s: reserved gpios from %d to %d\n",
__func__, start, start + ngpio - 1);
err:
spin_unlock_irqrestore(&gpio_lock, flags);
return ret;
}
/* caller ensures gpio is valid and requested, chip->get_direction may sleep */ /* caller ensures gpio is valid and requested, chip->get_direction may sleep */
static int gpio_get_direction(unsigned gpio) static int gpio_get_direction(unsigned gpio)
{ {
...@@ -254,13 +212,14 @@ static ssize_t gpio_direction_show(struct device *dev, ...@@ -254,13 +212,14 @@ static ssize_t gpio_direction_show(struct device *dev,
mutex_lock(&sysfs_lock); mutex_lock(&sysfs_lock);
if (!test_bit(FLAG_EXPORT, &desc->flags)) if (!test_bit(FLAG_EXPORT, &desc->flags)) {
status = -EIO; status = -EIO;
else } else {
gpio_get_direction(gpio); gpio_get_direction(gpio);
status = sprintf(buf, "%s\n", status = sprintf(buf, "%s\n",
test_bit(FLAG_IS_OUT, &desc->flags) test_bit(FLAG_IS_OUT, &desc->flags)
? "out" : "in"); ? "out" : "in");
}
mutex_unlock(&sysfs_lock); mutex_unlock(&sysfs_lock);
return status; return status;
......
...@@ -152,7 +152,6 @@ struct gpio_chip { ...@@ -152,7 +152,6 @@ struct gpio_chip {
extern const char *gpiochip_is_requested(struct gpio_chip *chip, extern const char *gpiochip_is_requested(struct gpio_chip *chip,
unsigned offset); unsigned offset);
extern struct gpio_chip *gpio_to_chip(unsigned gpio); extern struct gpio_chip *gpio_to_chip(unsigned gpio);
extern int __must_check gpiochip_reserve(int start, int ngpio);
/* add/remove chips */ /* add/remove chips */
extern int gpiochip_add(struct gpio_chip *chip); extern int gpiochip_add(struct gpio_chip *chip);
...@@ -192,12 +191,6 @@ extern int gpio_request_one(unsigned gpio, unsigned long flags, const char *labe ...@@ -192,12 +191,6 @@ extern int gpio_request_one(unsigned gpio, unsigned long flags, const char *labe
extern int gpio_request_array(const struct gpio *array, size_t num); extern int gpio_request_array(const struct gpio *array, size_t num);
extern void gpio_free_array(const struct gpio *array, size_t num); extern void gpio_free_array(const struct gpio *array, size_t num);
/* bindings for managed devices that want to request gpios */
int devm_gpio_request(struct device *dev, unsigned gpio, const char *label);
int devm_gpio_request_one(struct device *dev, unsigned gpio,
unsigned long flags, const char *label);
void devm_gpio_free(struct device *dev, unsigned int gpio);
#ifdef CONFIG_GPIO_SYSFS #ifdef CONFIG_GPIO_SYSFS
/* /*
...@@ -212,6 +205,43 @@ extern void gpio_unexport(unsigned gpio); ...@@ -212,6 +205,43 @@ extern void gpio_unexport(unsigned gpio);
#endif /* CONFIG_GPIO_SYSFS */ #endif /* CONFIG_GPIO_SYSFS */
#ifdef CONFIG_PINCTRL
/**
* struct gpio_pin_range - pin range controlled by a gpio chip
* @head: list for maintaining set of pin ranges, used internally
* @pctldev: pinctrl device which handles corresponding pins
* @range: actual range of pins controlled by a gpio controller
*/
struct gpio_pin_range {
struct list_head node;
struct pinctrl_dev *pctldev;
struct pinctrl_gpio_range range;
};
int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
unsigned int gpio_offset, unsigned int pin_offset,
unsigned int npins);
void gpiochip_remove_pin_ranges(struct gpio_chip *chip);
#else
static inline int
gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
unsigned int gpio_offset, unsigned int pin_offset,
unsigned int npins)
{
return 0;
}
static inline void
gpiochip_remove_pin_ranges(struct gpio_chip *chip)
{
}
#endif /* CONFIG_PINCTRL */
#else /* !CONFIG_GPIOLIB */ #else /* !CONFIG_GPIOLIB */
static inline bool gpio_is_valid(int number) static inline bool gpio_is_valid(int number)
...@@ -270,41 +300,4 @@ static inline void gpio_unexport(unsigned gpio) ...@@ -270,41 +300,4 @@ static inline void gpio_unexport(unsigned gpio)
} }
#endif /* CONFIG_GPIO_SYSFS */ #endif /* CONFIG_GPIO_SYSFS */
#ifdef CONFIG_PINCTRL
/**
* struct gpio_pin_range - pin range controlled by a gpio chip
* @head: list for maintaining set of pin ranges, used internally
* @pctldev: pinctrl device which handles corresponding pins
* @range: actual range of pins controlled by a gpio controller
*/
struct gpio_pin_range {
struct list_head node;
struct pinctrl_dev *pctldev;
struct pinctrl_gpio_range range;
};
int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
unsigned int gpio_offset, unsigned int pin_offset,
unsigned int npins);
void gpiochip_remove_pin_ranges(struct gpio_chip *chip);
#else
static inline int
gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
unsigned int gpio_offset, unsigned int pin_offset,
unsigned int npins)
{
return 0;
}
static inline void
gpiochip_remove_pin_ranges(struct gpio_chip *chip)
{
}
#endif /* CONFIG_PINCTRL */
#endif /* _ASM_GENERIC_GPIO_H */ #endif /* _ASM_GENERIC_GPIO_H */
...@@ -2,10 +2,12 @@ ...@@ -2,10 +2,12 @@
#define _LINUX_ACPI_GPIO_H_ #define _LINUX_ACPI_GPIO_H_
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/gpio.h>
#ifdef CONFIG_GPIO_ACPI #ifdef CONFIG_GPIO_ACPI
int acpi_get_gpio(char *path, int pin); int acpi_get_gpio(char *path, int pin);
void acpi_gpiochip_request_interrupts(struct gpio_chip *chip);
#else /* CONFIG_GPIO_ACPI */ #else /* CONFIG_GPIO_ACPI */
...@@ -14,6 +16,8 @@ static inline int acpi_get_gpio(char *path, int pin) ...@@ -14,6 +16,8 @@ static inline int acpi_get_gpio(char *path, int pin)
return -ENODEV; return -ENODEV;
} }
static inline void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) { }
#endif /* CONFIG_GPIO_ACPI */ #endif /* CONFIG_GPIO_ACPI */
#endif /* _LINUX_ACPI_GPIO_H_ */ #endif /* _LINUX_ACPI_GPIO_H_ */
...@@ -94,24 +94,12 @@ static inline int gpio_request(unsigned gpio, const char *label) ...@@ -94,24 +94,12 @@ static inline int gpio_request(unsigned gpio, const char *label)
return -ENOSYS; return -ENOSYS;
} }
static inline int devm_gpio_request(struct device *dev, unsigned gpio,
const char *label)
{
return -ENOSYS;
}
static inline int gpio_request_one(unsigned gpio, static inline int gpio_request_one(unsigned gpio,
unsigned long flags, const char *label) unsigned long flags, const char *label)
{ {
return -ENOSYS; return -ENOSYS;
} }
static inline int devm_gpio_request_one(struct device *dev, unsigned gpio,
unsigned long flags, const char *label)
{
return -ENOSYS;
}
static inline int gpio_request_array(const struct gpio *array, size_t num) static inline int gpio_request_array(const struct gpio *array, size_t num)
{ {
return -ENOSYS; return -ENOSYS;
...@@ -125,14 +113,6 @@ static inline void gpio_free(unsigned gpio) ...@@ -125,14 +113,6 @@ static inline void gpio_free(unsigned gpio)
WARN_ON(1); WARN_ON(1);
} }
static inline void devm_gpio_free(struct device *dev, unsigned gpio)
{
might_sleep();
/* GPIO can never have been requested */
WARN_ON(1);
}
static inline void gpio_free_array(const struct gpio *array, size_t num) static inline void gpio_free_array(const struct gpio *array, size_t num)
{ {
might_sleep(); might_sleep();
...@@ -248,4 +228,12 @@ gpiochip_remove_pin_ranges(struct gpio_chip *chip) ...@@ -248,4 +228,12 @@ gpiochip_remove_pin_ranges(struct gpio_chip *chip)
#endif /* ! CONFIG_GENERIC_GPIO */ #endif /* ! CONFIG_GENERIC_GPIO */
struct device;
/* bindings for managed devices that want to request gpios */
int devm_gpio_request(struct device *dev, unsigned gpio, const char *label);
int devm_gpio_request_one(struct device *dev, unsigned gpio,
unsigned long flags, const char *label);
void devm_gpio_free(struct device *dev, unsigned int gpio);
#endif /* __LINUX_GPIO_H */ #endif /* __LINUX_GPIO_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment