|
@@ -88,6 +88,8 @@ struct gpio_bank {
|
|
|
#define BANK_USED(bank) (bank->mod_usage || bank->irq_usage)
|
|
|
#define LINE_USED(line, offset) (line & (BIT(offset)))
|
|
|
|
|
|
+static void omap_gpio_unmask_irq(struct irq_data *d);
|
|
|
+
|
|
|
static int omap_irq_to_gpio(struct gpio_bank *bank, unsigned int gpio_irq)
|
|
|
{
|
|
|
return bank->chip.base + gpio_irq;
|
|
@@ -477,6 +479,16 @@ static int omap_gpio_is_input(struct gpio_bank *bank, int mask)
|
|
|
return readl_relaxed(reg) & mask;
|
|
|
}
|
|
|
|
|
|
+static void omap_gpio_init_irq(struct gpio_bank *bank, unsigned gpio,
|
|
|
+ unsigned offset)
|
|
|
+{
|
|
|
+ if (!LINE_USED(bank->mod_usage, offset)) {
|
|
|
+ omap_enable_gpio_module(bank, offset);
|
|
|
+ omap_set_gpio_direction(bank, offset, 1);
|
|
|
+ }
|
|
|
+ bank->irq_usage |= BIT(GPIO_INDEX(bank, gpio));
|
|
|
+}
|
|
|
+
|
|
|
static int omap_gpio_irq_type(struct irq_data *d, unsigned type)
|
|
|
{
|
|
|
struct gpio_bank *bank = omap_irq_data_get_bank(d);
|
|
@@ -506,15 +518,11 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type)
|
|
|
spin_lock_irqsave(&bank->lock, flags);
|
|
|
offset = GPIO_INDEX(bank, gpio);
|
|
|
retval = omap_set_gpio_triggering(bank, offset, type);
|
|
|
- if (!LINE_USED(bank->mod_usage, offset)) {
|
|
|
- omap_enable_gpio_module(bank, offset);
|
|
|
- omap_set_gpio_direction(bank, offset, 1);
|
|
|
- } else if (!omap_gpio_is_input(bank, BIT(offset))) {
|
|
|
+ omap_gpio_init_irq(bank, gpio, offset);
|
|
|
+ if (!omap_gpio_is_input(bank, BIT(offset))) {
|
|
|
spin_unlock_irqrestore(&bank->lock, flags);
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
-
|
|
|
- bank->irq_usage |= BIT(GPIO_INDEX(bank, gpio));
|
|
|
spin_unlock_irqrestore(&bank->lock, flags);
|
|
|
|
|
|
if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
|
|
@@ -792,6 +800,24 @@ exit:
|
|
|
pm_runtime_put(bank->dev);
|
|
|
}
|
|
|
|
|
|
+static unsigned int omap_gpio_irq_startup(struct irq_data *d)
|
|
|
+{
|
|
|
+ struct gpio_bank *bank = omap_irq_data_get_bank(d);
|
|
|
+ unsigned int gpio = omap_irq_to_gpio(bank, d->hwirq);
|
|
|
+ unsigned long flags;
|
|
|
+ unsigned offset = GPIO_INDEX(bank, gpio);
|
|
|
+
|
|
|
+ if (!BANK_USED(bank))
|
|
|
+ pm_runtime_get_sync(bank->dev);
|
|
|
+
|
|
|
+ spin_lock_irqsave(&bank->lock, flags);
|
|
|
+ omap_gpio_init_irq(bank, gpio, offset);
|
|
|
+ spin_unlock_irqrestore(&bank->lock, flags);
|
|
|
+ omap_gpio_unmask_irq(d);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static void omap_gpio_irq_shutdown(struct irq_data *d)
|
|
|
{
|
|
|
struct gpio_bank *bank = omap_irq_data_get_bank(d);
|
|
@@ -1181,6 +1207,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
|
|
|
if (!irqc)
|
|
|
return -ENOMEM;
|
|
|
|
|
|
+ irqc->irq_startup = omap_gpio_irq_startup,
|
|
|
irqc->irq_shutdown = omap_gpio_irq_shutdown,
|
|
|
irqc->irq_ack = omap_gpio_ack_irq,
|
|
|
irqc->irq_mask = omap_gpio_mask_irq,
|