2 * MPIC timer wakeup driver
4 * Copyright 2013 Freescale Semiconductor, Inc.
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.
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>
19 #include <asm/mpic_timer.h>
22 struct fsl_mpic_timer_wakeup
{
23 struct mpic_timer
*timer
;
24 struct work_struct free_work
;
27 static struct fsl_mpic_timer_wakeup
*fsl_wakeup
;
28 static DEFINE_MUTEX(sysfs_lock
);
30 static void fsl_free_resource(struct work_struct
*ws
)
32 struct fsl_mpic_timer_wakeup
*wakeup
=
33 container_of(ws
, struct fsl_mpic_timer_wakeup
, free_work
);
35 mutex_lock(&sysfs_lock
);
38 disable_irq_wake(wakeup
->timer
->irq
);
39 mpic_free_timer(wakeup
->timer
);
43 mutex_unlock(&sysfs_lock
);
46 static irqreturn_t
fsl_mpic_timer_irq(int irq
, void *dev_id
)
48 struct fsl_mpic_timer_wakeup
*wakeup
= dev_id
;
50 schedule_work(&wakeup
->free_work
);
52 return wakeup
->timer
? IRQ_HANDLED
: IRQ_NONE
;
55 static ssize_t
fsl_timer_wakeup_show(struct device
*dev
,
56 struct device_attribute
*attr
,
59 struct timeval interval
;
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;
67 mutex_unlock(&sysfs_lock
);
69 return sprintf(buf
, "%d\n", val
);
72 static ssize_t
fsl_timer_wakeup_store(struct device
*dev
,
73 struct device_attribute
*attr
,
77 struct timeval interval
;
81 if (kstrtol(buf
, 0, &interval
.tv_sec
))
84 mutex_lock(&sysfs_lock
);
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
;
92 if (!interval
.tv_sec
) {
93 mutex_unlock(&sysfs_lock
);
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
);
104 ret
= enable_irq_wake(fsl_wakeup
->timer
->irq
);
106 mpic_free_timer(fsl_wakeup
->timer
);
107 fsl_wakeup
->timer
= NULL
;
108 mutex_unlock(&sysfs_lock
);
113 mpic_start_timer(fsl_wakeup
->timer
);
115 mutex_unlock(&sysfs_lock
);
120 static struct device_attribute mpic_attributes
= __ATTR(timer_wakeup
, 0644,
121 fsl_timer_wakeup_show
, fsl_timer_wakeup_store
);
123 static int __init
fsl_wakeup_sys_init(void)
127 fsl_wakeup
= kzalloc(sizeof(struct fsl_mpic_timer_wakeup
), GFP_KERNEL
);
131 INIT_WORK(&fsl_wakeup
->free_work
, fsl_free_resource
);
133 ret
= device_create_file(mpic_subsys
.dev_root
, &mpic_attributes
);
140 static void __exit
fsl_wakeup_sys_exit(void)
142 device_remove_file(mpic_subsys
.dev_root
, &mpic_attributes
);
144 mutex_lock(&sysfs_lock
);
146 if (fsl_wakeup
->timer
) {
147 disable_irq_wake(fsl_wakeup
->timer
->irq
);
148 mpic_free_timer(fsl_wakeup
->timer
);
153 mutex_unlock(&sysfs_lock
);
156 module_init(fsl_wakeup_sys_init
);
157 module_exit(fsl_wakeup_sys_exit
);
159 MODULE_DESCRIPTION("Freescale MPIC global timer wakeup driver");
160 MODULE_LICENSE("GPL v2");
161 MODULE_AUTHOR("Wang Dongsheng <dongsheng.wang@freescale.com>");