mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-16 08:44:21 +08:00
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: Grant Likely <grant.likely@secretlab.ca>
This commit is contained in:
commit
0fa2fd9a0d
@ -927,8 +927,6 @@ static void tosa_restart(char mode, const char *cmd)
|
||||
|
||||
static void __init tosa_init(void)
|
||||
{
|
||||
int dummy;
|
||||
|
||||
pxa2xx_mfp_config(ARRAY_AND_SIZE(tosa_pin_config));
|
||||
|
||||
pxa_set_ffuart_info(NULL);
|
||||
@ -947,10 +945,6 @@ static void __init tosa_init(void)
|
||||
/* enable batt_fault */
|
||||
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_ficp_info(&tosa_ficp_platform_data);
|
||||
pxa_set_i2c_info(NULL);
|
||||
|
@ -30,6 +30,9 @@ config ARCH_REQUIRE_GPIOLIB
|
||||
Selecting this from the architecture code will cause the gpiolib
|
||||
code to always get built in.
|
||||
|
||||
config GPIO_DEVRES
|
||||
def_bool y
|
||||
depends on HAS_IOMEM
|
||||
|
||||
|
||||
menuconfig GPIOLIB
|
||||
|
@ -2,7 +2,8 @@
|
||||
|
||||
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_GPIO_ACPI) += gpiolib-acpi.o
|
||||
|
||||
|
@ -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_and_handler(virq, &mpc8xxx_irq_chip, handle_level_irq);
|
||||
irq_set_irq_type(virq, IRQ_TYPE_NONE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -65,6 +65,7 @@ struct mxs_gpio_port {
|
||||
struct irq_domain *domain;
|
||||
struct bgpio_chip bgc;
|
||||
enum mxs_gpio_id devid;
|
||||
u32 both_edges;
|
||||
};
|
||||
|
||||
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)
|
||||
|
||||
static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type)
|
||||
{
|
||||
u32 val;
|
||||
u32 pin_mask = 1 << d->hwirq;
|
||||
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
|
||||
struct mxs_gpio_port *port = gc->private;
|
||||
void __iomem *pin_addr;
|
||||
int edge;
|
||||
|
||||
port->both_edges &= ~pin_mask;
|
||||
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:
|
||||
edge = GPIO_INT_RISE_EDGE;
|
||||
break;
|
||||
@ -124,6 +135,23 @@ static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type)
|
||||
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 */
|
||||
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) {
|
||||
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));
|
||||
irq_stat &= ~(1 << irqoffset);
|
||||
}
|
||||
|
@ -46,6 +46,7 @@
|
||||
#define PCA957X_TYPE 0x2000
|
||||
|
||||
static const struct i2c_device_id pca953x_id[] = {
|
||||
{ "pca9505", 40 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "pca9534", 8 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "pca9535", 16 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "pca9536", 4 | PCA953X_TYPE, },
|
||||
@ -71,19 +72,23 @@ static const struct i2c_device_id 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 {
|
||||
unsigned gpio_start;
|
||||
u32 reg_output;
|
||||
u32 reg_direction;
|
||||
u8 reg_output[MAX_BANK];
|
||||
u8 reg_direction[MAX_BANK];
|
||||
struct mutex i2c_lock;
|
||||
|
||||
#ifdef CONFIG_GPIO_PCA953X_IRQ
|
||||
struct mutex irq_lock;
|
||||
u32 irq_mask;
|
||||
u32 irq_stat;
|
||||
u32 irq_trig_raise;
|
||||
u32 irq_trig_fall;
|
||||
int irq_base;
|
||||
u8 irq_mask[MAX_BANK];
|
||||
u8 irq_stat[MAX_BANK];
|
||||
u8 irq_trig_raise[MAX_BANK];
|
||||
u8 irq_trig_fall[MAX_BANK];
|
||||
struct irq_domain *domain;
|
||||
#endif
|
||||
|
||||
@ -93,33 +98,69 @@ struct pca953x_chip {
|
||||
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;
|
||||
|
||||
if (chip->gpio_chip.ngpio <= 8)
|
||||
ret = i2c_smbus_write_byte_data(chip->client, reg, val);
|
||||
else if (chip->gpio_chip.ngpio == 24) {
|
||||
cpu_to_le32s(&val);
|
||||
ret = i2c_smbus_write_byte_data(chip->client, reg, *val);
|
||||
else if (chip->gpio_chip.ngpio >= 24) {
|
||||
int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
|
||||
ret = i2c_smbus_write_i2c_block_data(chip->client,
|
||||
(reg << 2) | REG_ADDR_AI,
|
||||
3,
|
||||
(u8 *) &val);
|
||||
(reg << bank_shift) | REG_ADDR_AI,
|
||||
NBANK(chip), val);
|
||||
}
|
||||
else {
|
||||
switch (chip->chip_type) {
|
||||
case PCA953X_TYPE:
|
||||
ret = i2c_smbus_write_word_data(chip->client,
|
||||
reg << 1, val);
|
||||
reg << 1, (u16) *val);
|
||||
break;
|
||||
case PCA957X_TYPE:
|
||||
ret = i2c_smbus_write_byte_data(chip->client, reg << 1,
|
||||
val & 0xff);
|
||||
val[0]);
|
||||
if (ret < 0)
|
||||
break;
|
||||
ret = i2c_smbus_write_byte_data(chip->client,
|
||||
(reg << 1) + 1,
|
||||
(val & 0xff00) >> 8);
|
||||
val[1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -132,26 +173,24 @@ static int pca953x_write_reg(struct pca953x_chip *chip, int reg, u32 val)
|
||||
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;
|
||||
|
||||
if (chip->gpio_chip.ngpio <= 8) {
|
||||
ret = i2c_smbus_read_byte_data(chip->client, reg);
|
||||
*val = ret;
|
||||
}
|
||||
else if (chip->gpio_chip.ngpio == 24) {
|
||||
*val = 0;
|
||||
} else if (chip->gpio_chip.ngpio >= 24) {
|
||||
int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
|
||||
|
||||
ret = i2c_smbus_read_i2c_block_data(chip->client,
|
||||
(reg << 2) | REG_ADDR_AI,
|
||||
3,
|
||||
(u8 *) val);
|
||||
le32_to_cpus(val);
|
||||
(reg << bank_shift) | REG_ADDR_AI,
|
||||
NBANK(chip), val);
|
||||
} else {
|
||||
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) {
|
||||
dev_err(&chip->client->dev, "failed reading register\n");
|
||||
return ret;
|
||||
@ -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)
|
||||
{
|
||||
struct pca953x_chip *chip;
|
||||
uint reg_val;
|
||||
u8 reg_val;
|
||||
int ret, offset = 0;
|
||||
|
||||
chip = container_of(gc, struct pca953x_chip, gpio_chip);
|
||||
|
||||
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) {
|
||||
case PCA953X_TYPE:
|
||||
@ -179,11 +218,11 @@ static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
|
||||
offset = PCA957X_CFG;
|
||||
break;
|
||||
}
|
||||
ret = pca953x_write_reg(chip, offset, reg_val);
|
||||
ret = pca953x_write_single(chip, offset, reg_val, off);
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
chip->reg_direction = reg_val;
|
||||
chip->reg_direction[off / BANK_SZ] = reg_val;
|
||||
ret = 0;
|
||||
exit:
|
||||
mutex_unlock(&chip->i2c_lock);
|
||||
@ -194,7 +233,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
|
||||
unsigned off, int val)
|
||||
{
|
||||
struct pca953x_chip *chip;
|
||||
uint reg_val;
|
||||
u8 reg_val;
|
||||
int ret, offset = 0;
|
||||
|
||||
chip = container_of(gc, struct pca953x_chip, gpio_chip);
|
||||
@ -202,9 +241,11 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
|
||||
mutex_lock(&chip->i2c_lock);
|
||||
/* set output level */
|
||||
if (val)
|
||||
reg_val = chip->reg_output | (1u << off);
|
||||
reg_val = chip->reg_output[off / BANK_SZ]
|
||||
| (1u << (off % BANK_SZ));
|
||||
else
|
||||
reg_val = chip->reg_output & ~(1u << off);
|
||||
reg_val = chip->reg_output[off / BANK_SZ]
|
||||
& ~(1u << (off % BANK_SZ));
|
||||
|
||||
switch (chip->chip_type) {
|
||||
case PCA953X_TYPE:
|
||||
@ -214,14 +255,14 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
|
||||
offset = PCA957X_OUT;
|
||||
break;
|
||||
}
|
||||
ret = pca953x_write_reg(chip, offset, reg_val);
|
||||
ret = pca953x_write_single(chip, offset, reg_val, off);
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
chip->reg_output = reg_val;
|
||||
chip->reg_output[off / BANK_SZ] = reg_val;
|
||||
|
||||
/* 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) {
|
||||
case PCA953X_TYPE:
|
||||
offset = PCA953X_DIRECTION;
|
||||
@ -230,11 +271,11 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
|
||||
offset = PCA957X_CFG;
|
||||
break;
|
||||
}
|
||||
ret = pca953x_write_reg(chip, offset, reg_val);
|
||||
ret = pca953x_write_single(chip, offset, reg_val, off);
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
chip->reg_direction = reg_val;
|
||||
chip->reg_direction[off / BANK_SZ] = reg_val;
|
||||
ret = 0;
|
||||
exit:
|
||||
mutex_unlock(&chip->i2c_lock);
|
||||
@ -258,7 +299,7 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
|
||||
offset = PCA957X_IN;
|
||||
break;
|
||||
}
|
||||
ret = pca953x_read_reg(chip, offset, ®_val);
|
||||
ret = pca953x_read_single(chip, offset, ®_val, off);
|
||||
mutex_unlock(&chip->i2c_lock);
|
||||
if (ret < 0) {
|
||||
/* 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)
|
||||
static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
|
||||
{
|
||||
struct pca953x_chip *chip;
|
||||
u32 reg_val;
|
||||
u8 reg_val;
|
||||
int ret, offset = 0;
|
||||
|
||||
chip = container_of(gc, struct pca953x_chip, gpio_chip);
|
||||
|
||||
mutex_lock(&chip->i2c_lock);
|
||||
if (val)
|
||||
reg_val = chip->reg_output | (1u << off);
|
||||
reg_val = chip->reg_output[off / BANK_SZ]
|
||||
| (1u << (off % BANK_SZ));
|
||||
else
|
||||
reg_val = chip->reg_output & ~(1u << off);
|
||||
reg_val = chip->reg_output[off / BANK_SZ]
|
||||
& ~(1u << (off % BANK_SZ));
|
||||
|
||||
switch (chip->chip_type) {
|
||||
case PCA953X_TYPE:
|
||||
@ -293,11 +336,11 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
|
||||
offset = PCA957X_OUT;
|
||||
break;
|
||||
}
|
||||
ret = pca953x_write_reg(chip, offset, reg_val);
|
||||
ret = pca953x_write_single(chip, offset, reg_val, off);
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
chip->reg_output = reg_val;
|
||||
chip->reg_output[off / BANK_SZ] = reg_val;
|
||||
exit:
|
||||
mutex_unlock(&chip->i2c_lock);
|
||||
}
|
||||
@ -328,21 +371,21 @@ static int pca953x_gpio_to_irq(struct gpio_chip *gc, unsigned off)
|
||||
struct pca953x_chip *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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
@ -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)
|
||||
{
|
||||
struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
|
||||
u32 new_irqs;
|
||||
u32 level;
|
||||
u8 new_irqs;
|
||||
int level, i;
|
||||
|
||||
/* Look for any newly setup interrupt */
|
||||
new_irqs = chip->irq_trig_fall | chip->irq_trig_raise;
|
||||
new_irqs &= ~chip->reg_direction;
|
||||
for (i = 0; i < NBANK(chip); i++) {
|
||||
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);
|
||||
pca953x_gpio_direction_input(&chip->gpio_chip, level);
|
||||
new_irqs &= ~(1 << level);
|
||||
while (new_irqs) {
|
||||
level = __ffs(new_irqs);
|
||||
pca953x_gpio_direction_input(&chip->gpio_chip,
|
||||
level + (BANK_SZ * i));
|
||||
new_irqs &= ~(1 << level);
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&chip->irq_lock);
|
||||
@ -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)
|
||||
{
|
||||
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)) {
|
||||
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)
|
||||
}
|
||||
|
||||
if (type & IRQ_TYPE_EDGE_FALLING)
|
||||
chip->irq_trig_fall |= mask;
|
||||
chip->irq_trig_fall[bank_nb] |= mask;
|
||||
else
|
||||
chip->irq_trig_fall &= ~mask;
|
||||
chip->irq_trig_fall[bank_nb] &= ~mask;
|
||||
|
||||
if (type & IRQ_TYPE_EDGE_RISING)
|
||||
chip->irq_trig_raise |= mask;
|
||||
chip->irq_trig_raise[bank_nb] |= mask;
|
||||
else
|
||||
chip->irq_trig_raise &= ~mask;
|
||||
chip->irq_trig_raise[bank_nb] &= ~mask;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -404,13 +451,13 @@ static struct irq_chip pca953x_irq_chip = {
|
||||
.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;
|
||||
u32 old_stat;
|
||||
u32 pending;
|
||||
u32 trigger;
|
||||
int ret, offset = 0;
|
||||
u8 cur_stat[MAX_BANK];
|
||||
u8 old_stat[MAX_BANK];
|
||||
u8 pendings = 0;
|
||||
u8 trigger[MAX_BANK], triggers = 0;
|
||||
int ret, i, offset = 0;
|
||||
|
||||
switch (chip->chip_type) {
|
||||
case PCA953X_TYPE:
|
||||
@ -420,60 +467,88 @@ static u32 pca953x_irq_pending(struct pca953x_chip *chip)
|
||||
offset = PCA957X_IN;
|
||||
break;
|
||||
}
|
||||
ret = pca953x_read_reg(chip, offset, &cur_stat);
|
||||
ret = pca953x_read_regs(chip, offset, cur_stat);
|
||||
if (ret)
|
||||
return 0;
|
||||
|
||||
/* 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];
|
||||
|
||||
old_stat = chip->irq_stat;
|
||||
trigger = (cur_stat ^ old_stat) & chip->irq_mask;
|
||||
memcpy(old_stat, chip->irq_stat, NBANK(chip));
|
||||
|
||||
if (!trigger)
|
||||
for (i = 0; i < NBANK(chip); i++) {
|
||||
trigger[i] = (cur_stat[i] ^ old_stat[i]) & chip->irq_mask[i];
|
||||
triggers += trigger[i];
|
||||
}
|
||||
|
||||
if (!triggers)
|
||||
return 0;
|
||||
|
||||
chip->irq_stat = cur_stat;
|
||||
memcpy(chip->irq_stat, cur_stat, NBANK(chip));
|
||||
|
||||
pending = (old_stat & chip->irq_trig_fall) |
|
||||
(cur_stat & chip->irq_trig_raise);
|
||||
pending &= trigger;
|
||||
for (i = 0; i < NBANK(chip); i++) {
|
||||
pending[i] = (old_stat[i] & chip->irq_trig_fall[i]) |
|
||||
(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)
|
||||
{
|
||||
struct pca953x_chip *chip = devid;
|
||||
u32 pending;
|
||||
u32 level;
|
||||
u8 pending[MAX_BANK];
|
||||
u8 level;
|
||||
int i;
|
||||
|
||||
pending = pca953x_irq_pending(chip);
|
||||
|
||||
if (!pending)
|
||||
if (!pca953x_irq_pending(chip, pending))
|
||||
return IRQ_HANDLED;
|
||||
|
||||
do {
|
||||
level = __ffs(pending);
|
||||
handle_nested_irq(irq_find_mapping(chip->domain, level));
|
||||
|
||||
pending &= ~(1 << level);
|
||||
} while (pending);
|
||||
for (i = 0; i < NBANK(chip); i++) {
|
||||
while (pending[i]) {
|
||||
level = __ffs(pending[i]);
|
||||
handle_nested_irq(irq_find_mapping(chip->domain,
|
||||
level + (BANK_SZ * i)));
|
||||
pending[i] &= ~(1 << level);
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
const struct i2c_device_id *id,
|
||||
int irq_base)
|
||||
{
|
||||
struct i2c_client *client = chip->client;
|
||||
int ret, offset = 0;
|
||||
u32 temporary;
|
||||
int ret, i, offset = 0;
|
||||
|
||||
if (irq_base != -1
|
||||
&& (id->driver_data & PCA_INT)) {
|
||||
int lvl;
|
||||
|
||||
switch (chip->chip_type) {
|
||||
case PCA953X_TYPE:
|
||||
@ -483,49 +558,29 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
|
||||
offset = PCA957X_IN;
|
||||
break;
|
||||
}
|
||||
ret = pca953x_read_reg(chip, offset, &temporary);
|
||||
chip->irq_stat = temporary;
|
||||
ret = pca953x_read_regs(chip, offset, chip->irq_stat);
|
||||
if (ret)
|
||||
goto out_failed;
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* There is no way to know which GPIO line generated the
|
||||
* interrupt. We have to rely on the previous read for
|
||||
* 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);
|
||||
|
||||
chip->irq_base = irq_alloc_descs(-1, irq_base, chip->gpio_chip.ngpio, -1);
|
||||
if (chip->irq_base < 0)
|
||||
goto out_failed;
|
||||
|
||||
chip->domain = irq_domain_add_legacy(client->dev.of_node,
|
||||
chip->domain = irq_domain_add_simple(client->dev.of_node,
|
||||
chip->gpio_chip.ngpio,
|
||||
chip->irq_base,
|
||||
0,
|
||||
&irq_domain_simple_ops,
|
||||
irq_base,
|
||||
&pca953x_irq_simple_ops,
|
||||
NULL);
|
||||
if (!chip->domain) {
|
||||
ret = -ENODEV;
|
||||
goto out_irqdesc_free;
|
||||
}
|
||||
if (!chip->domain)
|
||||
return -ENODEV;
|
||||
|
||||
for (lvl = 0; lvl < chip->gpio_chip.ngpio; lvl++) {
|
||||
int irq = lvl + chip->irq_base;
|
||||
|
||||
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,
|
||||
ret = devm_request_threaded_irq(&client->dev,
|
||||
client->irq,
|
||||
NULL,
|
||||
pca953x_irq_handler,
|
||||
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
|
||||
@ -533,28 +588,15 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "failed to request irq %d\n",
|
||||
client->irq);
|
||||
goto out_irqdesc_free;
|
||||
return ret;
|
||||
}
|
||||
|
||||
chip->gpio_chip.to_irq = pca953x_gpio_to_irq;
|
||||
}
|
||||
|
||||
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 */
|
||||
static int pca953x_irq_setup(struct pca953x_chip *chip,
|
||||
const struct i2c_device_id *id,
|
||||
@ -567,10 +609,6 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pca953x_irq_teardown(struct pca953x_chip *chip)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -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)
|
||||
{
|
||||
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)
|
||||
goto out;
|
||||
|
||||
ret = pca953x_read_reg(chip, PCA953X_DIRECTION,
|
||||
&chip->reg_direction);
|
||||
ret = pca953x_read_regs(chip, PCA953X_DIRECTION,
|
||||
chip->reg_direction);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/* 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:
|
||||
return ret;
|
||||
}
|
||||
@ -638,28 +682,36 @@ out:
|
||||
static int device_pca957x_init(struct pca953x_chip *chip, u32 invert)
|
||||
{
|
||||
int ret;
|
||||
u32 val = 0;
|
||||
u8 val[MAX_BANK];
|
||||
|
||||
/* Let every port in proper state, that could save power */
|
||||
pca953x_write_reg(chip, PCA957X_PUPD, 0x0);
|
||||
pca953x_write_reg(chip, PCA957X_CFG, 0xffff);
|
||||
pca953x_write_reg(chip, PCA957X_OUT, 0x0);
|
||||
memset(val, 0, NBANK(chip));
|
||||
pca953x_write_regs(chip, PCA957X_PUPD, val);
|
||||
memset(val, 0xFF, NBANK(chip));
|
||||
pca953x_write_regs(chip, PCA957X_CFG, val);
|
||||
memset(val, 0, NBANK(chip));
|
||||
pca953x_write_regs(chip, PCA957X_OUT, val);
|
||||
|
||||
ret = pca953x_read_reg(chip, PCA957X_IN, &val);
|
||||
ret = pca953x_read_regs(chip, PCA957X_IN, val);
|
||||
if (ret)
|
||||
goto out;
|
||||
ret = pca953x_read_reg(chip, PCA957X_OUT, &chip->reg_output);
|
||||
ret = pca953x_read_regs(chip, PCA957X_OUT, chip->reg_output);
|
||||
if (ret)
|
||||
goto out;
|
||||
ret = pca953x_read_reg(chip, PCA957X_CFG, &chip->reg_direction);
|
||||
ret = pca953x_read_regs(chip, PCA957X_CFG, chip->reg_direction);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/* 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 */
|
||||
pca953x_write_reg(chip, PCA957X_BKEN, 0x202);
|
||||
memset(val, 0x02, NBANK(chip));
|
||||
pca953x_write_regs(chip, PCA957X_BKEN, val);
|
||||
|
||||
return 0;
|
||||
out:
|
||||
@ -675,7 +727,8 @@ static int pca953x_probe(struct i2c_client *client,
|
||||
int ret;
|
||||
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)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -710,15 +763,15 @@ static int pca953x_probe(struct i2c_client *client,
|
||||
else
|
||||
ret = device_pca957x_init(chip, invert);
|
||||
if (ret)
|
||||
goto out_failed;
|
||||
return ret;
|
||||
|
||||
ret = pca953x_irq_setup(chip, id, irq_base);
|
||||
if (ret)
|
||||
goto out_failed;
|
||||
return ret;
|
||||
|
||||
ret = gpiochip_add(&chip->gpio_chip);
|
||||
if (ret)
|
||||
goto out_failed_irq;
|
||||
return ret;
|
||||
|
||||
if (pdata && pdata->setup) {
|
||||
ret = pdata->setup(client, chip->gpio_chip.base,
|
||||
@ -729,12 +782,6 @@ static int pca953x_probe(struct i2c_client *client,
|
||||
|
||||
i2c_set_clientdata(client, chip);
|
||||
return 0;
|
||||
|
||||
out_failed_irq:
|
||||
pca953x_irq_teardown(chip);
|
||||
out_failed:
|
||||
kfree(chip);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pca953x_remove(struct i2c_client *client)
|
||||
@ -760,12 +807,11 @@ static int pca953x_remove(struct i2c_client *client)
|
||||
return ret;
|
||||
}
|
||||
|
||||
pca953x_irq_teardown(chip);
|
||||
kfree(chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id pca953x_dt_ids[] = {
|
||||
{ .compatible = "nxp,pca9505", },
|
||||
{ .compatible = "nxp,pca9534", },
|
||||
{ .compatible = "nxp,pca9535", },
|
||||
{ .compatible = "nxp,pca9536", },
|
||||
|
@ -365,7 +365,7 @@ static int __init pl061_gpio_init(void)
|
||||
{
|
||||
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_DESCRIPTION("PL061 GPIO driver");
|
||||
|
@ -642,12 +642,7 @@ static struct platform_driver pxa_gpio_driver = {
|
||||
.of_match_table = of_match_ptr(pxa_gpio_dt_ids),
|
||||
},
|
||||
};
|
||||
|
||||
static int __init pxa_gpio_init(void)
|
||||
{
|
||||
return platform_driver_register(&pxa_gpio_driver);
|
||||
}
|
||||
postcore_initcall(pxa_gpio_init);
|
||||
module_platform_driver(pxa_gpio_driver);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int pxa_gpio_suspend(void)
|
||||
|
@ -37,7 +37,6 @@
|
||||
|
||||
#include <linux/i2c/twl.h>
|
||||
|
||||
|
||||
/*
|
||||
* The GPIO "subchip" supports 18 GPIOs which can be configured as
|
||||
* inputs or outputs, with pullups or pulldowns on each pin. Each
|
||||
@ -49,11 +48,6 @@
|
||||
* 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 */
|
||||
#ifdef MODULE
|
||||
#define is_module() true
|
||||
@ -69,14 +63,24 @@ static int twl4030_gpio_irq_base;
|
||||
/* Mask for GPIO registers when aggregated into a 32-bit integer */
|
||||
#define GPIO_32_MASK 0x0003ffff
|
||||
|
||||
/* Data structures */
|
||||
static DEFINE_MUTEX(gpio_lock);
|
||||
struct gpio_twl4030_priv {
|
||||
struct gpio_chip gpio_chip;
|
||||
struct mutex mutex;
|
||||
int irq_base;
|
||||
|
||||
/* store usage of each GPIO. - each bit represents one GPIO */
|
||||
static unsigned int gpio_usage_count;
|
||||
/* Bitfields for state caching */
|
||||
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
|
||||
*/
|
||||
@ -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
|
||||
* 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)
|
||||
if (led)
|
||||
mask <<= 1;
|
||||
|
||||
mutex_lock(&gpio_lock);
|
||||
if (value)
|
||||
cached_leden &= ~mask;
|
||||
else
|
||||
cached_leden |= mask;
|
||||
status = twl_i2c_write_u8(TWL4030_MODULE_LED, cached_leden,
|
||||
TWL4030_LED_LEDEN_REG);
|
||||
mutex_unlock(&gpio_lock);
|
||||
}
|
||||
|
||||
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;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&gpio_lock);
|
||||
ret = gpio_twl4030_read(base);
|
||||
if (ret >= 0) {
|
||||
if (is_input)
|
||||
@ -168,7 +169,6 @@ static int twl4030_set_gpio_direction(int gpio, int is_input)
|
||||
|
||||
ret = gpio_twl4030_write(base, reg);
|
||||
}
|
||||
mutex_unlock(&gpio_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -193,10 +193,6 @@ static int twl4030_get_gpio_datain(int gpio)
|
||||
u8 base = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (unlikely((gpio >= TWL4030_GPIO_MAX)
|
||||
|| !(gpio_usage_count & BIT(gpio))))
|
||||
return -EPERM;
|
||||
|
||||
base = REG_GPIODATAIN1 + d_bnk;
|
||||
ret = gpio_twl4030_read(base);
|
||||
if (ret > 0)
|
||||
@ -209,9 +205,10 @@ static int twl4030_get_gpio_datain(int gpio)
|
||||
|
||||
static int twl_request(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
|
||||
int status = 0;
|
||||
|
||||
mutex_lock(&gpio_lock);
|
||||
mutex_lock(&priv->mutex);
|
||||
|
||||
/* Support the two LED outputs as output-only GPIOs. */
|
||||
if (offset >= TWL4030_GPIO_MAX) {
|
||||
@ -252,7 +249,7 @@ static int twl_request(struct gpio_chip *chip, unsigned offset)
|
||||
}
|
||||
|
||||
/* on first use, turn GPIO module "on" */
|
||||
if (!gpio_usage_count) {
|
||||
if (!priv->usage_count) {
|
||||
struct twl4030_gpio_platform_data *pdata;
|
||||
u8 value = MASK_GPIO_CTRL_GPIO_ON;
|
||||
|
||||
@ -266,79 +263,120 @@ static int twl_request(struct gpio_chip *chip, unsigned offset)
|
||||
status = gpio_twl4030_write(REG_GPIO_CTRL, value);
|
||||
}
|
||||
|
||||
if (!status)
|
||||
gpio_usage_count |= (0x1 << offset);
|
||||
|
||||
done:
|
||||
mutex_unlock(&gpio_lock);
|
||||
if (!status)
|
||||
priv->usage_count |= BIT(offset);
|
||||
|
||||
mutex_unlock(&priv->mutex);
|
||||
return status;
|
||||
}
|
||||
|
||||
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) {
|
||||
twl4030_led_set_value(offset - TWL4030_GPIO_MAX, 1);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
mutex_lock(&gpio_lock);
|
||||
|
||||
gpio_usage_count &= ~BIT(offset);
|
||||
priv->usage_count &= ~BIT(offset);
|
||||
|
||||
/* on last use, switch off GPIO module */
|
||||
if (!gpio_usage_count)
|
||||
if (!priv->usage_count)
|
||||
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)
|
||||
{
|
||||
return (offset < TWL4030_GPIO_MAX)
|
||||
? twl4030_set_gpio_direction(offset, 1)
|
||||
: -EINVAL;
|
||||
struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
|
||||
int ret;
|
||||
|
||||
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)
|
||||
{
|
||||
struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
|
||||
int ret;
|
||||
int status = 0;
|
||||
|
||||
if (offset < TWL4030_GPIO_MAX)
|
||||
status = twl4030_get_gpio_datain(offset);
|
||||
else if (offset == TWL4030_GPIO_MAX)
|
||||
status = cached_leden & LEDEN_LEDAON;
|
||||
else
|
||||
status = cached_leden & LEDEN_LEDBON;
|
||||
return (status < 0) ? 0 : status;
|
||||
}
|
||||
|
||||
static int twl_direction_out(struct gpio_chip *chip, unsigned offset, int value)
|
||||
{
|
||||
if (offset < TWL4030_GPIO_MAX) {
|
||||
twl4030_set_gpio_dataout(offset, value);
|
||||
return twl4030_set_gpio_direction(offset, 0);
|
||||
} else {
|
||||
twl4030_led_set_value(offset - TWL4030_GPIO_MAX, value);
|
||||
return 0;
|
||||
mutex_lock(&priv->mutex);
|
||||
if (!(priv->usage_count & BIT(offset))) {
|
||||
ret = -EPERM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (priv->direction & BIT(offset))
|
||||
status = priv->out_state & BIT(offset);
|
||||
else
|
||||
status = twl4030_get_gpio_datain(offset);
|
||||
|
||||
ret = (status <= 0) ? 0 : 1;
|
||||
out:
|
||||
mutex_unlock(&priv->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void twl_set(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)
|
||||
twl4030_set_gpio_dataout(offset, value);
|
||||
else
|
||||
twl4030_led_set_value(offset - TWL4030_GPIO_MAX, value);
|
||||
|
||||
if (value)
|
||||
priv->out_state |= BIT(offset);
|
||||
else
|
||||
priv->out_state &= ~BIT(offset);
|
||||
|
||||
mutex_unlock(&priv->mutex);
|
||||
}
|
||||
|
||||
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)
|
||||
twl4030_set_gpio_dataout(offset, 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)
|
||||
{
|
||||
return (twl4030_gpio_irq_base && (offset < TWL4030_GPIO_MAX))
|
||||
? (twl4030_gpio_irq_base + offset)
|
||||
struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
|
||||
|
||||
return (priv->irq_base && (offset < TWL4030_GPIO_MAX))
|
||||
? (priv->irq_base + offset)
|
||||
: -EINVAL;
|
||||
}
|
||||
|
||||
static struct gpio_chip twl_gpiochip = {
|
||||
static struct gpio_chip template_chip = {
|
||||
.label = "twl4030",
|
||||
.owner = THIS_MODULE,
|
||||
.request = twl_request,
|
||||
@ -424,8 +462,14 @@ static int gpio_twl4030_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
struct gpio_twl4030_priv *priv;
|
||||
int ret, irq_base;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(struct gpio_twl4030_priv),
|
||||
GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
/* maybe setup IRQs */
|
||||
if (is_module()) {
|
||||
dev_err(&pdev->dev, "can't dispatch IRQs from modules\n");
|
||||
@ -445,12 +489,15 @@ static int gpio_twl4030_probe(struct platform_device *pdev)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
twl4030_gpio_irq_base = irq_base;
|
||||
priv->irq_base = irq_base;
|
||||
|
||||
no_irqs:
|
||||
twl_gpiochip.base = -1;
|
||||
twl_gpiochip.ngpio = TWL4030_GPIO_MAX;
|
||||
twl_gpiochip.dev = &pdev->dev;
|
||||
priv->gpio_chip = template_chip;
|
||||
priv->gpio_chip.base = -1;
|
||||
priv->gpio_chip.ngpio = TWL4030_GPIO_MAX;
|
||||
priv->gpio_chip.dev = &pdev->dev;
|
||||
|
||||
mutex_init(&priv->mutex);
|
||||
|
||||
if (node)
|
||||
pdata = of_gpio_twl4030(&pdev->dev);
|
||||
@ -481,23 +528,23 @@ no_irqs:
|
||||
* is (still) clear if use_leds is set.
|
||||
*/
|
||||
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) {
|
||||
dev_err(&pdev->dev, "could not register gpiochip, %d\n", ret);
|
||||
twl_gpiochip.ngpio = 0;
|
||||
priv->gpio_chip.ngpio = 0;
|
||||
gpio_twl4030_remove(pdev);
|
||||
goto out;
|
||||
}
|
||||
|
||||
twl4030_gpio_base = twl_gpiochip.base;
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
if (pdata && pdata->setup) {
|
||||
int status;
|
||||
|
||||
status = pdata->setup(&pdev->dev,
|
||||
twl4030_gpio_base, TWL4030_GPIO_MAX);
|
||||
status = pdata->setup(&pdev->dev, priv->gpio_chip.base,
|
||||
TWL4030_GPIO_MAX);
|
||||
if (status)
|
||||
dev_dbg(&pdev->dev, "setup --> %d\n", status);
|
||||
}
|
||||
@ -510,18 +557,19 @@ out:
|
||||
static int gpio_twl4030_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct gpio_twl4030_priv *priv = platform_get_drvdata(pdev);
|
||||
int status;
|
||||
|
||||
if (pdata && pdata->teardown) {
|
||||
status = pdata->teardown(&pdev->dev,
|
||||
twl4030_gpio_base, TWL4030_GPIO_MAX);
|
||||
status = pdata->teardown(&pdev->dev, priv->gpio_chip.base,
|
||||
TWL4030_GPIO_MAX);
|
||||
if (status) {
|
||||
dev_dbg(&pdev->dev, "teardown --> %d\n", status);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
status = gpiochip_remove(&twl_gpiochip);
|
||||
status = gpiochip_remove(&priv->gpio_chip);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
|
@ -73,19 +73,20 @@ struct vt8500_gpio_data {
|
||||
static struct vt8500_gpio_data vt8500_data = {
|
||||
.num_banks = 7,
|
||||
.banks = {
|
||||
VT8500_BANK(NO_REG, 0x3C, 0x5C, 0x7C, 9),
|
||||
VT8500_BANK(0x00, 0x20, 0x40, 0x60, 26),
|
||||
VT8500_BANK(0x04, 0x24, 0x44, 0x64, 28),
|
||||
VT8500_BANK(0x08, 0x28, 0x48, 0x68, 31),
|
||||
VT8500_BANK(0x0C, 0x2C, 0x4C, 0x6C, 19),
|
||||
VT8500_BANK(0x10, 0x30, 0x50, 0x70, 19),
|
||||
VT8500_BANK(0x14, 0x34, 0x54, 0x74, 23),
|
||||
VT8500_BANK(NO_REG, 0x3C, 0x5C, 0x7C, 9),
|
||||
},
|
||||
};
|
||||
|
||||
static struct vt8500_gpio_data wm8505_data = {
|
||||
.num_banks = 10,
|
||||
.banks = {
|
||||
VT8500_BANK(0x64, 0x8C, 0xB4, 0xDC, 22),
|
||||
VT8500_BANK(0x40, 0x68, 0x90, 0xB8, 8),
|
||||
VT8500_BANK(0x44, 0x6C, 0x94, 0xBC, 32),
|
||||
VT8500_BANK(0x48, 0x70, 0x98, 0xC0, 6),
|
||||
@ -95,7 +96,6 @@ static struct vt8500_gpio_data wm8505_data = {
|
||||
VT8500_BANK(0x58, 0x80, 0xA8, 0xD0, 5),
|
||||
VT8500_BANK(0x5C, 0x84, 0xAC, 0xD4, 12),
|
||||
VT8500_BANK(0x60, 0x88, 0xB0, 0xD8, 16),
|
||||
VT8500_BANK(0x64, 0x8C, 0xB4, 0xDC, 22),
|
||||
VT8500_BANK(0x500, 0x504, 0x508, 0x50C, 6),
|
||||
},
|
||||
};
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <linux/export.h>
|
||||
#include <linux/acpi_gpio.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
|
||||
{
|
||||
@ -52,3 +53,89 @@ int acpi_get_gpio(char *path, int pin)
|
||||
return chip->base + pin;
|
||||
}
|
||||
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 {
|
||||
/* flag symbols are bit numbers */
|
||||
#define FLAG_REQUESTED 0
|
||||
#define FLAG_IS_OUT 1
|
||||
#define FLAG_RESERVED 2
|
||||
#define FLAG_EXPORT 3 /* protected by sysfs_lock */
|
||||
#define FLAG_SYSFS 4 /* exported via /sys/class/gpio/control */
|
||||
#define FLAG_TRIG_FALL 5 /* trigger on falling edge */
|
||||
#define FLAG_TRIG_RISE 6 /* trigger on rising edge */
|
||||
#define FLAG_ACTIVE_LOW 7 /* sysfs value has active low */
|
||||
#define FLAG_OPEN_DRAIN 8 /* Gpio is open drain type */
|
||||
#define FLAG_OPEN_SOURCE 9 /* Gpio is open source type */
|
||||
#define FLAG_EXPORT 2 /* protected by sysfs_lock */
|
||||
#define FLAG_SYSFS 3 /* exported via /sys/class/gpio/control */
|
||||
#define FLAG_TRIG_FALL 4 /* trigger on falling edge */
|
||||
#define FLAG_TRIG_RISE 5 /* trigger on rising edge */
|
||||
#define FLAG_ACTIVE_LOW 6 /* sysfs value has active low */
|
||||
#define FLAG_OPEN_DRAIN 7 /* Gpio is open drain type */
|
||||
#define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */
|
||||
|
||||
#define ID_SHIFT 16 /* add new flags before this one */
|
||||
|
||||
@ -132,7 +131,7 @@ static int gpiochip_find_base(int ngpio)
|
||||
struct gpio_desc *desc = &gpio_desc[i];
|
||||
struct gpio_chip *chip = desc->chip;
|
||||
|
||||
if (!chip && !test_bit(FLAG_RESERVED, &desc->flags)) {
|
||||
if (!chip) {
|
||||
spare++;
|
||||
if (spare == ngpio) {
|
||||
base = i;
|
||||
@ -150,47 +149,6 @@ static int gpiochip_find_base(int ngpio)
|
||||
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 */
|
||||
static int gpio_get_direction(unsigned gpio)
|
||||
{
|
||||
@ -254,13 +212,14 @@ static ssize_t gpio_direction_show(struct device *dev,
|
||||
|
||||
mutex_lock(&sysfs_lock);
|
||||
|
||||
if (!test_bit(FLAG_EXPORT, &desc->flags))
|
||||
if (!test_bit(FLAG_EXPORT, &desc->flags)) {
|
||||
status = -EIO;
|
||||
else
|
||||
} else {
|
||||
gpio_get_direction(gpio);
|
||||
status = sprintf(buf, "%s\n",
|
||||
test_bit(FLAG_IS_OUT, &desc->flags)
|
||||
? "out" : "in");
|
||||
}
|
||||
|
||||
mutex_unlock(&sysfs_lock);
|
||||
return status;
|
||||
|
@ -152,7 +152,6 @@ struct gpio_chip {
|
||||
extern const char *gpiochip_is_requested(struct gpio_chip *chip,
|
||||
unsigned offset);
|
||||
extern struct gpio_chip *gpio_to_chip(unsigned gpio);
|
||||
extern int __must_check gpiochip_reserve(int start, int ngpio);
|
||||
|
||||
/* add/remove chips */
|
||||
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
|
||||
extern int gpio_request_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
|
||||
|
||||
/*
|
||||
@ -212,6 +205,43 @@ extern void gpio_unexport(unsigned gpio);
|
||||
|
||||
#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 */
|
||||
|
||||
static inline bool gpio_is_valid(int number)
|
||||
@ -270,41 +300,4 @@ static inline void gpio_unexport(unsigned gpio)
|
||||
}
|
||||
#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 */
|
||||
|
@ -2,10 +2,12 @@
|
||||
#define _LINUX_ACPI_GPIO_H_
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#ifdef CONFIG_GPIO_ACPI
|
||||
|
||||
int acpi_get_gpio(char *path, int pin);
|
||||
void acpi_gpiochip_request_interrupts(struct gpio_chip *chip);
|
||||
|
||||
#else /* CONFIG_GPIO_ACPI */
|
||||
|
||||
@ -14,6 +16,8 @@ static inline int acpi_get_gpio(char *path, int pin)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) { }
|
||||
|
||||
#endif /* CONFIG_GPIO_ACPI */
|
||||
|
||||
#endif /* _LINUX_ACPI_GPIO_H_ */
|
||||
|
@ -94,24 +94,12 @@ static inline int gpio_request(unsigned gpio, const char *label)
|
||||
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,
|
||||
unsigned long flags, const char *label)
|
||||
{
|
||||
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)
|
||||
{
|
||||
return -ENOSYS;
|
||||
@ -125,14 +113,6 @@ static inline void gpio_free(unsigned gpio)
|
||||
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)
|
||||
{
|
||||
might_sleep();
|
||||
@ -248,4 +228,12 @@ gpiochip_remove_pin_ranges(struct gpio_chip *chip)
|
||||
|
||||
#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 */
|
||||
|
Loading…
Reference in New Issue
Block a user