1
0
mirror of git://projects.qi-hardware.com/openwrt-xburst.git synced 2024-11-28 16:54:03 +02:00

jz4740: gpio: Emulate EDGE_BOTH irq type.

The jz4740 only supports EDGE_RISING or EDGE_FALLING. Some drivers need
EDGE_BOTH so we try to emulate it.
This commit is contained in:
Lars-Peter Clausen 2009-11-16 01:34:50 +01:00
parent 2982c214f6
commit 733ee36727

View File

@ -59,9 +59,9 @@
#define CHIP_TO_DATA_SELECT_REG(chip) CHIP_TO_REG(chip, 0x50)
#define CHIP_TO_DATA_SELECT_SET_REG(chip) CHIP_TO_REG(chip, 0x54)
#define CHIP_TO_DATA_SELECT_CLEAR_REG(chip) CHIP_TO_REG(chip, 0x58)
#define CHIP_TO_DATA_DIRECION_REG(chip) CHIP_TO_REG(chip, 0x60)
#define CHIP_TO_DATA_DIRECTION_SET_REG(chip) CHIP_TO_REG(chip, 0x64)
#define CHIP_TO_DATA_DIRECTION_CLEAR_REG(chip) CHIP_TO_REG(chip, 0x68)
#define CHIP_TO_DIRECION_REG(chip) CHIP_TO_REG(chip, 0x60)
#define CHIP_TO_DIRECTION_SET_REG(chip) CHIP_TO_REG(chip, 0x64)
#define CHIP_TO_DIRECTION_CLEAR_REG(chip) CHIP_TO_REG(chip, 0x68)
#define GPIO_TO_BIT(gpio) BIT(gpio & 0x1f)
@ -94,6 +94,7 @@ struct jz_gpio_chip {
uint32_t saved[4];
struct gpio_chip gpio_chip;
struct irq_chip irq_chip;
uint32_t edge_trigger_both;
};
static struct jz_gpio_chip *jz_irq_to_chip(unsigned int irq)
@ -186,7 +187,7 @@ static void jz_gpio_set_value(struct gpio_chip *chip, unsigned gpio, int value)
static int jz_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int value)
{
writel(BIT(gpio), CHIP_TO_DATA_DIRECTION_SET_REG(chip));
writel(BIT(gpio), CHIP_TO_DIRECTION_SET_REG(chip));
jz_gpio_set_value(chip, gpio, value);
return 0;
@ -194,7 +195,7 @@ static int jz_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int v
static int jz_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
{
writel(BIT(gpio), CHIP_TO_DATA_DIRECTION_CLEAR_REG(chip));
writel(BIT(gpio), CHIP_TO_DIRECTION_CLEAR_REG(chip));
return 0;
}
@ -205,6 +206,7 @@ static int jz_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
#define IRQ_TO_REG(irq, reg) GPIO_TO_REG(IRQ_TO_GPIO(irq), reg)
#define IRQ_TO_PIN_REG(irq) IRQ_TO_REG(irq, 0x00)
#define IRQ_TO_MASK_REG(irq) IRQ_TO_REG(irq, 0x20)
#define IRQ_TO_MASK_SET_REG(irq) IRQ_TO_REG(irq, 0x24)
#define IRQ_TO_MASK_CLEAR_REG(irq) IRQ_TO_REG(irq, 0x28)
@ -226,14 +228,28 @@ static void jz_gpio_irq_demux_handler(unsigned int irq, struct irq_desc *desc)
uint32_t flag;
unsigned int gpio_irq;
unsigned int gpio_bank;
struct jz_gpio_chip *chip = get_irq_desc_data(desc);
gpio_bank = JZ_IRQ_GPIO0 - irq;
flag = readl(jz_gpio_base + (gpio_bank << 8) + 0x80);
gpio_irq = ffs(flag);
gpio_irq = ffs(flag) - 1;
if (chip->edge_trigger_both & BIT(gpio_irq)) {
uint32_t value = readl(CHIP_TO_PIN_REG(&chip->gpio_chip));
if (value & BIT(gpio_irq)) {
writel(BIT(gpio_irq),
CHIP_TO_DIRECTION_CLEAR_REG(&chip->gpio_chip));
} else {
writel(BIT(gpio_irq),
CHIP_TO_DIRECTION_SET_REG(&chip->gpio_chip));
}
}
gpio_irq += (gpio_bank << 5) + JZ_IRQ_GPIO(0);
gpio_irq += (gpio_bank << 5) + JZ_IRQ_GPIO(0) - 1;
generic_handle_irq(gpio_irq);
};
@ -276,11 +292,22 @@ static void jz_gpio_irq_ack(unsigned int irq)
static int jz_gpio_irq_set_type(unsigned int irq, unsigned int flow_type)
{
uint32_t mask;
struct jz_gpio_chip *chip = jz_irq_to_chip(irq);
spin_lock(&jz_gpio_lock);
mask = readl(IRQ_TO_MASK_REG(irq));
writel(IRQ_TO_BIT(irq), IRQ_TO_MASK_CLEAR_REG(irq));
if (flow_type == IRQ_TYPE_EDGE_BOTH) {
uint32_t value = readl(IRQ_TO_PIN_REG(irq));
if (value & IRQ_TO_BIT(irq))
flow_type = IRQ_TYPE_EDGE_FALLING;
else
flow_type = IRQ_TYPE_EDGE_RISING;
chip->edge_trigger_both |= IRQ_TO_BIT(irq);
} else {
chip->edge_trigger_both &= ~IRQ_TO_BIT(irq);
}
switch(flow_type) {
case IRQ_TYPE_EDGE_RISING:
@ -288,7 +315,6 @@ static int jz_gpio_irq_set_type(unsigned int irq, unsigned int flow_type)
writel(IRQ_TO_BIT(irq), IRQ_TO_TRIGGER_SET_REG(irq));
break;
case IRQ_TYPE_EDGE_FALLING:
case IRQ_TYPE_EDGE_BOTH:
writel(IRQ_TO_BIT(irq), IRQ_TO_DIRECTION_CLEAR_REG(irq));
writel(IRQ_TO_BIT(irq), IRQ_TO_TRIGGER_SET_REG(irq));
break;
@ -376,6 +402,7 @@ int __init jz_gpiolib_init(void)
for (i = 0; i < ARRAY_SIZE(jz_gpio_chips); ++i, ++chip) {
gpiochip_add(&chip->gpio_chip);
chip->irq = JZ_IRQ_INTC_GPIO(i);
set_irq_data(chip->irq, chip);
set_irq_chained_handler(chip->irq, jz_gpio_irq_demux_handler);
for (irq = chip->irq_base; irq < chip->irq_base + chip->gpio_chip.ngpio;
++irq) {