Commit b12f79d0 authored by Philippe Gerum's avatar Philippe Gerum
Browse files

gpio: zynq: fixups for IRQ pipeline

parent 6ea4ff28
......@@ -14,6 +14,7 @@
#include <linux/gpio/driver.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/ipipe.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
......@@ -99,6 +100,7 @@ struct zynq_gpio {
static struct irq_chip zynq_gpio_level_irqchip;
static struct irq_chip zynq_gpio_edge_irqchip;
static IPIPE_DEFINE_RAW_SPINLOCK(zynq_gpio_lock);
/**
* zynq_gpio_get_bank_pin - Get the bank number and pin number within that bank
* for a given pin in the GPIO device
......@@ -221,6 +223,7 @@ static int zynq_gpio_dir_in(struct gpio_chip *chip, unsigned int pin)
u32 reg;
unsigned int bank_num, bank_pin_num;
struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip);
unsigned long flags;
zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num);
......@@ -228,10 +231,12 @@ static int zynq_gpio_dir_in(struct gpio_chip *chip, unsigned int pin)
if (bank_num == 0 && (bank_pin_num == 7 || bank_pin_num == 8))
return -EINVAL;
raw_spin_lock_irqsave(&zynq_gpio_lock, flags);
/* clear the bit in direction mode reg to set the pin as input */
reg = readl_relaxed(gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
reg &= ~BIT(bank_pin_num);
writel_relaxed(reg, gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
raw_spin_unlock_irqrestore(&zynq_gpio_lock, flags);
return 0;
}
......@@ -254,9 +259,11 @@ static int zynq_gpio_dir_out(struct gpio_chip *chip, unsigned int pin,
u32 reg;
unsigned int bank_num, bank_pin_num;
struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip);
unsigned long flags;
zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num);
raw_spin_lock_irqsave(&zynq_gpio_lock, flags);
/* set the GPIO pin as output */
reg = readl_relaxed(gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
reg |= BIT(bank_pin_num);
......@@ -266,6 +273,7 @@ static int zynq_gpio_dir_out(struct gpio_chip *chip, unsigned int pin,
reg = readl_relaxed(gpio->base_addr + ZYNQ_GPIO_OUTEN_OFFSET(bank_num));
reg |= BIT(bank_pin_num);
writel_relaxed(reg, gpio->base_addr + ZYNQ_GPIO_OUTEN_OFFSET(bank_num));
raw_spin_unlock_irqrestore(&zynq_gpio_lock, flags);
/* set the state of the pin */
zynq_gpio_set_value(chip, pin, state);
......@@ -284,11 +292,15 @@ static void zynq_gpio_irq_mask(struct irq_data *irq_data)
{
unsigned int device_pin_num, bank_num, bank_pin_num;
struct zynq_gpio *gpio = irq_data_get_irq_chip_data(irq_data);
unsigned long flags;
device_pin_num = irq_data->hwirq;
zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num);
raw_spin_lock_irqsave(&zynq_gpio_lock, flags);
ipipe_lock_irq(irq_data->irq);
writel_relaxed(BIT(bank_pin_num),
gpio->base_addr + ZYNQ_GPIO_INTDIS_OFFSET(bank_num));
raw_spin_unlock_irqrestore(&zynq_gpio_lock, flags);
}
/**
......@@ -304,11 +316,15 @@ static void zynq_gpio_irq_unmask(struct irq_data *irq_data)
{
unsigned int device_pin_num, bank_num, bank_pin_num;
struct zynq_gpio *gpio = irq_data_get_irq_chip_data(irq_data);
unsigned long flags;
device_pin_num = irq_data->hwirq;
zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num);
raw_spin_lock_irqsave(&zynq_gpio_lock, flags);
writel_relaxed(BIT(bank_pin_num),
gpio->base_addr + ZYNQ_GPIO_INTEN_OFFSET(bank_num));
ipipe_unlock_irq(irq_data->irq);
raw_spin_unlock_irqrestore(&zynq_gpio_lock, flags);
}
/**
......@@ -442,11 +458,43 @@ static int zynq_gpio_set_wake(struct irq_data *data, unsigned int on)
return 0;
}
#ifdef CONFIG_IPIPE
static void zynq_gpio_hold_irq(struct irq_data *irq_data)
{
unsigned int device_pin_num, bank_num, bank_pin_num;
struct zynq_gpio *gpio = irq_data_get_irq_chip_data(irq_data);
device_pin_num = irq_data->hwirq;
zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num, gpio);
writel_relaxed(BIT(bank_pin_num),
gpio->base_addr + ZYNQ_GPIO_INTDIS_OFFSET(bank_num));
writel_relaxed(BIT(bank_pin_num),
gpio->base_addr + ZYNQ_GPIO_INTSTS_OFFSET(bank_num));
}
static void zynq_gpio_release_irq(struct irq_data *irq_data)
{
unsigned int device_pin_num, bank_num, bank_pin_num;
struct zynq_gpio *gpio = irq_data_get_irq_chip_data(irq_data);
device_pin_num = irq_data->hwirq;
zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num, gpio);
writel_relaxed(BIT(bank_pin_num),
gpio->base_addr + ZYNQ_GPIO_INTEN_OFFSET(bank_num));
}
#endif /* CONFIG_IPIPE */
/* irq chip descriptor */
static struct irq_chip zynq_gpio_level_irqchip = {
.name = DRIVER_NAME,
.name = DRIVER_NAME "-level",
.irq_enable = zynq_gpio_irq_enable,
.irq_eoi = zynq_gpio_irq_ack,
#ifdef CONFIG_IPIPE
.irq_hold = zynq_gpio_hold_irq,
.irq_release = zynq_gpio_release_irq,
#endif
.irq_mask = zynq_gpio_irq_mask,
.irq_unmask = zynq_gpio_irq_unmask,
.irq_set_type = zynq_gpio_set_irq_type,
......@@ -456,9 +504,13 @@ static struct irq_chip zynq_gpio_level_irqchip = {
};
static struct irq_chip zynq_gpio_edge_irqchip = {
.name = DRIVER_NAME,
.name = DRIVER_NAME "-edge",
.irq_enable = zynq_gpio_irq_enable,
#ifdef CONFIG_IPIPE
.irq_mask_ack = zynq_gpio_hold_irq,
#else
.irq_ack = zynq_gpio_irq_ack,
#endif
.irq_mask = zynq_gpio_irq_mask,
.irq_unmask = zynq_gpio_irq_unmask,
.irq_set_type = zynq_gpio_set_irq_type,
......
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