aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDongsheng.wang@freescale.com <Dongsheng.wang@freescale.com>2013-04-08 22:22:32 -0400
committerScott Wood <scottwood@freescale.com>2013-07-01 19:38:42 -0400
commita63b3bc7db32b63bfe5f48fa8582f931db81c86e (patch)
tree7e119f7c7129a103d5a4d70390888cbbf0e2824c
parent9e6f31a9dbc58f6a5661f8dc8c919441b8d3ced4 (diff)
powerpc/fsl: add MPIC timer wakeup support
The driver provides a way to wake up the system by the MPIC timer. For example, echo 5 > /sys/devices/system/mpic/timer_wakeup echo standby > /sys/power/state After 5 seconds the MPIC timer will generate an interrupt to wake up the system. Signed-off-by: Wang Dongsheng <dongsheng.wang@freescale.com> Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com> Signed-off-by: Li Yang <leoli@freescale.com>
-rw-r--r--arch/powerpc/platforms/Kconfig9
-rw-r--r--arch/powerpc/sysdev/Makefile1
-rw-r--r--arch/powerpc/sysdev/fsl_mpic_timer_wakeup.c161
3 files changed, 171 insertions, 0 deletions
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index 7d07d9e8e1dd..0847ee6cd616 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -98,6 +98,15 @@ config MPIC_TIMER
98 chip, but it can potentially support other global timers 98 chip, but it can potentially support other global timers
99 complying with the OpenPIC standard. 99 complying with the OpenPIC standard.
100 100
101config FSL_MPIC_TIMER_WAKEUP
102 tristate "Freescale MPIC global timer wakeup driver"
103 depends on FSL_SOC && MPIC_TIMER && PM
104 default n
105 help
106 The driver provides a way to wake up the system by MPIC
107 timer.
108 e.g. "echo 5 > /sys/devices/system/mpic/timer_wakeup"
109
101config PPC_EPAPR_HV_PIC 110config PPC_EPAPR_HV_PIC
102 bool 111 bool
103 default n 112 default n
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 2eb72c1a4291..f67ac900d870 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -5,6 +5,7 @@ ccflags-$(CONFIG_PPC64) := $(NO_MINIMAL_TOC)
5mpic-msi-obj-$(CONFIG_PCI_MSI) += mpic_msi.o mpic_u3msi.o mpic_pasemi_msi.o 5mpic-msi-obj-$(CONFIG_PCI_MSI) += mpic_msi.o mpic_u3msi.o mpic_pasemi_msi.o
6obj-$(CONFIG_MPIC) += mpic.o $(mpic-msi-obj-y) 6obj-$(CONFIG_MPIC) += mpic.o $(mpic-msi-obj-y)
7obj-$(CONFIG_MPIC_TIMER) += mpic_timer.o 7obj-$(CONFIG_MPIC_TIMER) += mpic_timer.o
8obj-$(CONFIG_FSL_MPIC_TIMER_WAKEUP) += fsl_mpic_timer_wakeup.o
8mpic-msgr-obj-$(CONFIG_MPIC_MSGR) += mpic_msgr.o 9mpic-msgr-obj-$(CONFIG_MPIC_MSGR) += mpic_msgr.o
9obj-$(CONFIG_MPIC) += mpic.o $(mpic-msi-obj-y) $(mpic-msgr-obj-y) 10obj-$(CONFIG_MPIC) += mpic.o $(mpic-msi-obj-y) $(mpic-msgr-obj-y)
10obj-$(CONFIG_PPC_EPAPR_HV_PIC) += ehv_pic.o 11obj-$(CONFIG_PPC_EPAPR_HV_PIC) += ehv_pic.o
diff --git a/arch/powerpc/sysdev/fsl_mpic_timer_wakeup.c b/arch/powerpc/sysdev/fsl_mpic_timer_wakeup.c
new file mode 100644
index 000000000000..1707bf04dec6
--- /dev/null
+++ b/arch/powerpc/sysdev/fsl_mpic_timer_wakeup.c
@@ -0,0 +1,161 @@
1/*
2 * MPIC timer wakeup driver
3 *
4 * Copyright 2013 Freescale Semiconductor, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version.
10 */
11
12#include <linux/kernel.h>
13#include <linux/slab.h>
14#include <linux/errno.h>
15#include <linux/module.h>
16#include <linux/interrupt.h>
17#include <linux/device.h>
18
19#include <asm/mpic_timer.h>
20#include <asm/mpic.h>
21
22struct fsl_mpic_timer_wakeup {
23 struct mpic_timer *timer;
24 struct work_struct free_work;
25};
26
27static struct fsl_mpic_timer_wakeup *fsl_wakeup;
28static DEFINE_MUTEX(sysfs_lock);
29
30static void fsl_free_resource(struct work_struct *ws)
31{
32 struct fsl_mpic_timer_wakeup *wakeup =
33 container_of(ws, struct fsl_mpic_timer_wakeup, free_work);
34
35 mutex_lock(&sysfs_lock);
36
37 if (wakeup->timer) {
38 disable_irq_wake(wakeup->timer->irq);
39 mpic_free_timer(wakeup->timer);
40 }
41
42 wakeup->timer = NULL;
43 mutex_unlock(&sysfs_lock);
44}
45
46static irqreturn_t fsl_mpic_timer_irq(int irq, void *dev_id)
47{
48 struct fsl_mpic_timer_wakeup *wakeup = dev_id;
49
50 schedule_work(&wakeup->free_work);
51
52 return wakeup->timer ? IRQ_HANDLED : IRQ_NONE;
53}
54
55static ssize_t fsl_timer_wakeup_show(struct device *dev,
56 struct device_attribute *attr,
57 char *buf)
58{
59 struct timeval interval;
60 int val = 0;
61
62 mutex_lock(&sysfs_lock);
63 if (fsl_wakeup->timer) {
64 mpic_get_remain_time(fsl_wakeup->timer, &interval);
65 val = interval.tv_sec + 1;
66 }
67 mutex_unlock(&sysfs_lock);
68
69 return sprintf(buf, "%d\n", val);
70}
71
72static ssize_t fsl_timer_wakeup_store(struct device *dev,
73 struct device_attribute *attr,
74 const char *buf,
75 size_t count)
76{
77 struct timeval interval;
78 int ret;
79
80 interval.tv_usec = 0;
81 if (kstrtol(buf, 0, &interval.tv_sec))
82 return -EINVAL;
83
84 mutex_lock(&sysfs_lock);
85
86 if (fsl_wakeup->timer) {
87 disable_irq_wake(fsl_wakeup->timer->irq);
88 mpic_free_timer(fsl_wakeup->timer);
89 fsl_wakeup->timer = NULL;
90 }
91
92 if (!interval.tv_sec) {
93 mutex_unlock(&sysfs_lock);
94 return count;
95 }
96
97 fsl_wakeup->timer = mpic_request_timer(fsl_mpic_timer_irq,
98 fsl_wakeup, &interval);
99 if (!fsl_wakeup->timer) {
100 mutex_unlock(&sysfs_lock);
101 return -EINVAL;
102 }
103
104 ret = enable_irq_wake(fsl_wakeup->timer->irq);
105 if (ret) {
106 mpic_free_timer(fsl_wakeup->timer);
107 fsl_wakeup->timer = NULL;
108 mutex_unlock(&sysfs_lock);
109
110 return ret;
111 }
112
113 mpic_start_timer(fsl_wakeup->timer);
114
115 mutex_unlock(&sysfs_lock);
116
117 return count;
118}
119
120static struct device_attribute mpic_attributes = __ATTR(timer_wakeup, 0644,
121 fsl_timer_wakeup_show, fsl_timer_wakeup_store);
122
123static int __init fsl_wakeup_sys_init(void)
124{
125 int ret;
126
127 fsl_wakeup = kzalloc(sizeof(struct fsl_mpic_timer_wakeup), GFP_KERNEL);
128 if (!fsl_wakeup)
129 return -ENOMEM;
130
131 INIT_WORK(&fsl_wakeup->free_work, fsl_free_resource);
132
133 ret = device_create_file(mpic_subsys.dev_root, &mpic_attributes);
134 if (ret)
135 kfree(fsl_wakeup);
136
137 return ret;
138}
139
140static void __exit fsl_wakeup_sys_exit(void)
141{
142 device_remove_file(mpic_subsys.dev_root, &mpic_attributes);
143
144 mutex_lock(&sysfs_lock);
145
146 if (fsl_wakeup->timer) {
147 disable_irq_wake(fsl_wakeup->timer->irq);
148 mpic_free_timer(fsl_wakeup->timer);
149 }
150
151 kfree(fsl_wakeup);
152
153 mutex_unlock(&sysfs_lock);
154}
155
156module_init(fsl_wakeup_sys_init);
157module_exit(fsl_wakeup_sys_exit);
158
159MODULE_DESCRIPTION("Freescale MPIC global timer wakeup driver");
160MODULE_LICENSE("GPL v2");
161MODULE_AUTHOR("Wang Dongsheng <dongsheng.wang@freescale.com>");