From 4990d4fe327b9d9a7a3be7103a82699406fdde69 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 18 May 2015 15:40:29 -0700 Subject: PM / Wakeirq: Add automated device wake IRQ handling Turns out we can automate the handling for the device_may_wakeup() quite a bit by using the kernel wakeup source list as suggested by Rafael J. Wysocki . And as some hardware has separate dedicated wake-up interrupt in addition to the IO interrupt, we can automate the handling by adding a generic threaded interrupt handler that just calls the device PM runtime to wake up the device. This allows dropping code from device drivers as we currently are doing it in multiple ways, and often wrong. For most drivers, we should be able to drop the following boilerplate code from runtime_suspend and runtime_resume functions: ... device_init_wakeup(dev, true); ... if (device_may_wakeup(dev)) enable_irq_wake(irq); ... if (device_may_wakeup(dev)) disable_irq_wake(irq); ... device_init_wakeup(dev, false); ... We can replace it with just the following init and exit time code: ... device_init_wakeup(dev, true); dev_pm_set_wake_irq(dev, irq); ... dev_pm_clear_wake_irq(dev); device_init_wakeup(dev, false); ... And for hardware with dedicated wake-up interrupts: ... device_init_wakeup(dev, true); dev_pm_set_dedicated_wake_irq(dev, irq); ... dev_pm_clear_wake_irq(dev); device_init_wakeup(dev, false); ... Signed-off-by: Tony Lindgren Signed-off-by: Rafael J. Wysocki --- include/linux/pm.h | 2 ++ include/linux/pm_wakeirq.h | 52 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/pm_wakeup.h | 9 ++++++++ 3 files changed, 63 insertions(+) create mode 100644 include/linux/pm_wakeirq.h (limited to 'include/linux') diff --git a/include/linux/pm.h b/include/linux/pm.h index 2d29c64f8fb1..1c4ed0cb7907 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -529,6 +529,7 @@ enum rpm_request { }; struct wakeup_source; +struct wake_irq; struct pm_domain_data; struct pm_subsys_data { @@ -568,6 +569,7 @@ struct dev_pm_info { unsigned long timer_expires; struct work_struct work; wait_queue_head_t wait_queue; + struct wake_irq *wakeirq; atomic_t usage_count; atomic_t child_count; unsigned int disable_depth:3; diff --git a/include/linux/pm_wakeirq.h b/include/linux/pm_wakeirq.h new file mode 100644 index 000000000000..4046fa1b7d25 --- /dev/null +++ b/include/linux/pm_wakeirq.h @@ -0,0 +1,52 @@ +/* + * pm_wakeirq.h - Device wakeirq helper functions + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _LINUX_PM_WAKEIRQ_H +#define _LINUX_PM_WAKEIRQ_H + +#ifdef CONFIG_PM + +extern int dev_pm_set_wake_irq(struct device *dev, int irq); +extern int dev_pm_set_dedicated_wake_irq(struct device *dev, + int irq); +extern void dev_pm_clear_wake_irq(struct device *dev); +extern void dev_pm_enable_wake_irq(struct device *dev); +extern void dev_pm_disable_wake_irq(struct device *dev); + +#else /* !CONFIG_PM */ + +static inline int dev_pm_set_wake_irq(struct device *dev, int irq) +{ + return 0; +} + +static inline int dev_pm_set_dedicated__wake_irq(struct device *dev, + int irq) +{ + return 0; +} + +static inline void dev_pm_clear_wake_irq(struct device *dev) +{ +} + +static inline void dev_pm_enable_wake_irq(struct device *dev) +{ +} + +static inline void dev_pm_disable_wake_irq(struct device *dev) +{ +} + +#endif /* CONFIG_PM */ +#endif /* _LINUX_PM_WAKEIRQ_H */ diff --git a/include/linux/pm_wakeup.h b/include/linux/pm_wakeup.h index a0f70808d7f4..a3447932df1f 100644 --- a/include/linux/pm_wakeup.h +++ b/include/linux/pm_wakeup.h @@ -28,9 +28,17 @@ #include +struct wake_irq; + /** * struct wakeup_source - Representation of wakeup sources * + * @name: Name of the wakeup source + * @entry: Wakeup source list entry + * @lock: Wakeup source lock + * @wakeirq: Optional device specific wakeirq + * @timer: Wakeup timer list + * @timer_expires: Wakeup timer expiration * @total_time: Total time this wakeup source has been active. * @max_time: Maximum time this wakeup source has been continuously active. * @last_time: Monotonic clock when the wakeup source's was touched last time. @@ -47,6 +55,7 @@ struct wakeup_source { const char *name; struct list_head entry; spinlock_t lock; + struct wake_irq *wakeirq; struct timer_list timer; unsigned long timer_expires; ktime_t total_time; -- cgit v1.2.3 From db874c7e10557f8f1af9a6fb1ec6589ae06f349c Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Fri, 29 May 2015 09:54:02 -0700 Subject: PM / wakeirq: Fix typo in prototype for dev_pm_set_dedicated_wake_irq Looks like I only built test the dev_pm_set_wake_irq and not the dev_pm_set_dedicated_wake_irq case on x86. Turns out there's a typo for the dev_pm_set_dedicated_wake_irq prototype that causes a build error if CONFIG_COMPILE_TEST and CONFIG_MMC_OMAP_HS are selected. Reported-by: Jim Davis Signed-off-by: Tony Lindgren Reviewed-by: Felipe Balbi Signed-off-by: Rafael J. Wysocki --- include/linux/pm_wakeirq.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/pm_wakeirq.h b/include/linux/pm_wakeirq.h index 4046fa1b7d25..cd5b62db9084 100644 --- a/include/linux/pm_wakeirq.h +++ b/include/linux/pm_wakeirq.h @@ -30,8 +30,7 @@ static inline int dev_pm_set_wake_irq(struct device *dev, int irq) return 0; } -static inline int dev_pm_set_dedicated__wake_irq(struct device *dev, - int irq) +static inline int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq) { return 0; } -- cgit v1.2.3