From cac089f9026e9ddb3481daf08f0fc4e5949fa1af Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 23 Apr 2015 16:56:22 -0700 Subject: gpio: omap: Allow building as a loadable module We currently get all kinds of errors building the omap gpio driver as a module starting with: undefined reference to `omap2_gpio_resume_after_idle' undefined reference to `omap2_gpio_prepare_for_idle' ... Let's fix the issue by adding inline functions to the header. Note that we can now also remove the two unused functions for omap_set_gpio_debounce and omap_set_gpio_debounce_time. Then doing rmmod on the module produces further warnings because of missing exit related functions. Let's add those. And finally, we can make the Kconfig entry just a tristate option that's selected for omaps. Cc: Javier Martinez Canillas Cc: Kevin Hilman Cc: Nishanth Menon Signed-off-by: Tony Lindgren Reviewed-by: Grygorii Strashko Acked-by: Santosh Shilimkar Reviewed-by: Felipe Balbi Signed-off-by: Linus Walleij --- drivers/gpio/gpio-omap.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers/gpio/gpio-omap.c') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index cd1d5bf48f36..38c268fb7ba8 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1263,6 +1263,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) @@ -1448,6 +1459,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; @@ -1473,6 +1485,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) @@ -1628,6 +1641,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, @@ -1645,3 +1659,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"); -- cgit v1.2.3 From 5f982c70a7c3382d3532ac6d13fdea48ab38b934 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Fri, 22 May 2015 17:35:48 +0300 Subject: gpio: omap: fix omap_gpio_free to not clean up irq configuration This patch fixes following issue: - GPIOn is used as IRQ by some dev, for example PCF8575.INT -> gpio6.11 - PCFx driver knows nothing about type of IRQ line (GPIO or not) so it doesn't request gpio and just do request_irq() - If gpio6.11 will be exported through the sysfs and then un-xeported then IRQs from PCFx will not be received any more, because IRQ configuration for gpio6.11 will be cleaned up unconditionally in omap_gpio_free. Fix this by removing all GPIO IRQ specific code from omap_gpio_free() and also do GPIO clean up (change direction to 'in' and disable debounce) only if corresponding GPIO is not used as IRQ too. GPIO IRQ will be properly cleaned up by GPIO irqchip code. Signed-off-by: Grygorii Strashko Tested-by: Tony Lindgren Signed-off-by: Linus Walleij --- drivers/gpio/gpio-omap.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/gpio/gpio-omap.c') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 6efee35f0ad4..505266153b4c 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -690,8 +690,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); /* -- cgit v1.2.3 From 1562e4618ded89b07d145d6985f469fe8be04830 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Fri, 22 May 2015 17:35:49 +0300 Subject: gpio: omap: fix error handling in omap_gpio_irq_type The GPIO bank will be kept powered in case if input parameters are invalid or error occurred in omap_gpio_irq_type. Hence, fix it by ensuring that GPIO bank will be unpowered in case of errors and add additional check of value returned from omap_set_gpio_triggering(). Signed-off-by: Grygorii Strashko Tested-by: Tony Lindgren Signed-off-by: Linus Walleij --- drivers/gpio/gpio-omap.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers/gpio/gpio-omap.c') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 505266153b4c..81e229f5ade3 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; } -- cgit v1.2.3 From 6e96c1b5e54889cd11ce29723a5c38ba284c1d91 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Fri, 22 May 2015 17:35:50 +0300 Subject: gpio: omap: rework omap_x_irq_shutdown to touch only irqs specific registers The GPIO Chip and GPIO IRQ Chip functionality are essentially orthogonal, so GPIO IRQ Chip implementation shouldn't touch GPIO specific registers and vise versa. Hence, rework omap_gpio_irq_shutdown and try to touch only irqs specific registers: - don't configure GPIO as input (it, actually, should be already configured as input). - don't clear debounce configuration if GPIO is still used as GPIO. We need to take in to account here commit c9c55d921115 ("gpio/omap: fix off-mode bug: clear debounce settings on free/reset"). Also remove omap_reset_gpio() function as it is not used any more. Signed-off-by: Grygorii Strashko Tested-by: Tony Lindgren Signed-off-by: Linus Walleij --- drivers/gpio/gpio-omap.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'drivers/gpio/gpio-omap.c') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 81e229f5ade3..b2fcdf4f8bd7 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -646,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) { @@ -821,8 +812,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); /* -- cgit v1.2.3 From c3518172129a60a1f3071e61a8a4ffc50c7b2a68 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Fri, 22 May 2015 17:35:51 +0300 Subject: gpio: omap: rework omap_gpio_request to touch only gpio specific registers The GPIO Chip and GPIO IRQ Chip functionality are essentially orthogonal, so GPIO Chip implementation shouldn't touch GPIO IRQ specific registers and vise versa. Hence, rework omap_gpio_request: - don't reset GPIO IRQ triggering type to IRQ_TYPE_NONE, because GPIO irqchip should be responsible for that; - call directly omap_enable_gpio_module as all needed checks are already present inside it. Signed-off-by: Grygorii Strashko Tested-by: Tony Lindgren Signed-off-by: Linus Walleij --- drivers/gpio/gpio-omap.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'drivers/gpio/gpio-omap.c') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index b2fcdf4f8bd7..606b401d2017 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -668,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); -- cgit v1.2.3 From 121dcb760426ca67ee90a8b2db6a75eee010f8e3 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Fri, 22 May 2015 17:35:52 +0300 Subject: gpio: omap: rework omap_gpio_irq_startup to handle current pin state properly The omap_gpio_irq_startup() can be called at time when: - corresponding GPIO has been requested already and in this case it has to be configured as input already. If not - return with -EINVAL and do not try to re-configure it as it could be unsafe. - corresponding GPIO is free: reconfigure GPIO as input. In addition, call omap_enable_gpio_module directly as all needed checks are already present inside it. Signed-off-by: Grygorii Strashko Tested-by: Tony Lindgren Signed-off-by: Linus Walleij --- drivers/gpio/gpio-omap.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers/gpio/gpio-omap.c') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 606b401d2017..b0c57d505be7 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -790,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) -- cgit v1.2.3