diff options
Diffstat (limited to 'drivers/gpio/gpio-omap.c')
-rw-r--r-- | drivers/gpio/gpio-omap.c | 83 |
1 files changed, 59 insertions, 24 deletions
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index b232397ad7ec..b0c57d505be7 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -488,9 +488,6 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type) unsigned long flags; unsigned offset = d->hwirq; - if (!BANK_USED(bank)) - pm_runtime_get_sync(bank->dev); - if (type & ~IRQ_TYPE_SENSE_MASK) return -EINVAL; @@ -498,12 +495,18 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type) (type & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH))) return -EINVAL; + if (!BANK_USED(bank)) + pm_runtime_get_sync(bank->dev); + spin_lock_irqsave(&bank->lock, flags); retval = omap_set_gpio_triggering(bank, offset, type); + if (retval) + goto error; omap_gpio_init_irq(bank, offset); if (!omap_gpio_is_input(bank, offset)) { spin_unlock_irqrestore(&bank->lock, flags); - return -EINVAL; + retval = -EINVAL; + goto error; } spin_unlock_irqrestore(&bank->lock, flags); @@ -512,6 +515,11 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type) else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) __irq_set_handler_locked(d->irq, handle_edge_irq); + return 0; + +error: + if (!BANK_USED(bank)) + pm_runtime_put(bank->dev); return retval; } @@ -638,15 +646,6 @@ static int omap_set_gpio_wakeup(struct gpio_bank *bank, unsigned offset, return 0; } -static void omap_reset_gpio(struct gpio_bank *bank, unsigned offset) -{ - omap_set_gpio_direction(bank, offset, 1); - omap_set_gpio_irqenable(bank, offset, 0); - omap_clear_gpio_irqstatus(bank, offset); - omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE); - omap_clear_gpio_debounce(bank, offset); -} - /* Use disable_irq_wake() and enable_irq_wake() functions from drivers */ static int omap_gpio_wake_enable(struct irq_data *d, unsigned int enable) { @@ -669,14 +668,7 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset) pm_runtime_get_sync(bank->dev); spin_lock_irqsave(&bank->lock, flags); - /* Set trigger to none. You need to enable the desired trigger with - * request_irq() or set_irq_type(). Only do this if the IRQ line has - * not already been requested. - */ - if (!LINE_USED(bank->irq_usage, offset)) { - omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE); - omap_enable_gpio_module(bank, offset); - } + omap_enable_gpio_module(bank, offset); bank->mod_usage |= BIT(offset); spin_unlock_irqrestore(&bank->lock, flags); @@ -690,8 +682,11 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset) spin_lock_irqsave(&bank->lock, flags); bank->mod_usage &= ~(BIT(offset)); + if (!LINE_USED(bank->irq_usage, offset)) { + omap_set_gpio_direction(bank, offset, 1); + omap_clear_gpio_debounce(bank, offset); + } omap_disable_gpio_module(bank, offset); - omap_reset_gpio(bank, offset); spin_unlock_irqrestore(&bank->lock, flags); /* @@ -795,11 +790,23 @@ static unsigned int omap_gpio_irq_startup(struct irq_data *d) pm_runtime_get_sync(bank->dev); spin_lock_irqsave(&bank->lock, flags); - omap_gpio_init_irq(bank, offset); + + if (!LINE_USED(bank->mod_usage, offset)) + omap_set_gpio_direction(bank, offset, 1); + else if (!omap_gpio_is_input(bank, offset)) + goto err; + omap_enable_gpio_module(bank, offset); + bank->irq_usage |= BIT(offset); + spin_unlock_irqrestore(&bank->lock, flags); omap_gpio_unmask_irq(d); return 0; +err: + spin_unlock_irqrestore(&bank->lock, flags); + if (!BANK_USED(bank)) + pm_runtime_put(bank->dev); + return -EINVAL; } static void omap_gpio_irq_shutdown(struct irq_data *d) @@ -810,8 +817,12 @@ static void omap_gpio_irq_shutdown(struct irq_data *d) spin_lock_irqsave(&bank->lock, flags); bank->irq_usage &= ~(BIT(offset)); + omap_set_gpio_irqenable(bank, offset, 0); + omap_clear_gpio_irqstatus(bank, offset); + omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE); + if (!LINE_USED(bank->mod_usage, offset)) + omap_clear_gpio_debounce(bank, offset); omap_disable_gpio_module(bank, offset); - omap_reset_gpio(bank, offset); spin_unlock_irqrestore(&bank->lock, flags); /* @@ -1233,6 +1244,17 @@ static int omap_gpio_probe(struct platform_device *pdev) return 0; } +static int omap_gpio_remove(struct platform_device *pdev) +{ + struct gpio_bank *bank = platform_get_drvdata(pdev); + + list_del(&bank->node); + gpiochip_remove(&bank->chip); + pm_runtime_disable(bank->dev); + + return 0; +} + #ifdef CONFIG_ARCH_OMAP2PLUS #if defined(CONFIG_PM) @@ -1418,6 +1440,7 @@ static int omap_gpio_runtime_resume(struct device *dev) } #endif /* CONFIG_PM */ +#if IS_BUILTIN(CONFIG_GPIO_OMAP) void omap2_gpio_prepare_for_idle(int pwr_mode) { struct gpio_bank *bank; @@ -1443,6 +1466,7 @@ void omap2_gpio_resume_after_idle(void) pm_runtime_get_sync(bank->dev); } } +#endif #if defined(CONFIG_PM) static void omap_gpio_init_context(struct gpio_bank *p) @@ -1598,6 +1622,7 @@ MODULE_DEVICE_TABLE(of, omap_gpio_match); static struct platform_driver omap_gpio_driver = { .probe = omap_gpio_probe, + .remove = omap_gpio_remove, .driver = { .name = "omap_gpio", .pm = &gpio_pm_ops, @@ -1615,3 +1640,13 @@ static int __init omap_gpio_drv_reg(void) return platform_driver_register(&omap_gpio_driver); } postcore_initcall(omap_gpio_drv_reg); + +static void __exit omap_gpio_exit(void) +{ + platform_driver_unregister(&omap_gpio_driver); +} +module_exit(omap_gpio_exit); + +MODULE_DESCRIPTION("omap gpio driver"); +MODULE_ALIAS("platform:gpio-omap"); +MODULE_LICENSE("GPL v2"); |