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 time64_t interval
= 0;
61 mutex_lock(&sysfs_lock
);
62 if (fsl_wakeup
->timer
) {
63 mpic_get_remain_time(fsl_wakeup
->timer
, &interval
);
66 mutex_unlock(&sysfs_lock
);
68 return sprintf(buf
, "%lld\n", interval
);
71 static ssize_t
fsl_timer_wakeup_store(struct device
*dev
,
72 struct device_attribute
*attr
,
79 if (kstrtoll(buf
, 0, &interval
))
82 mutex_lock(&sysfs_lock
);
84 if (fsl_wakeup
->timer
) {
85 disable_irq_wake(fsl_wakeup
->timer
->irq
);
86 mpic_free_timer(fsl_wakeup
->timer
);
87 fsl_wakeup
->timer
= NULL
;
91 mutex_unlock(&sysfs_lock
);
95 fsl_wakeup
->timer
= mpic_request_timer(fsl_mpic_timer_irq
,
96 fsl_wakeup
, interval
);
97 if (!fsl_wakeup
->timer
) {
98 mutex_unlock(&sysfs_lock
);
102 ret
= enable_irq_wake(fsl_wakeup
->timer
->irq
);
104 mpic_free_timer(fsl_wakeup
->timer
);
105 fsl_wakeup
->timer
= NULL
;
106 mutex_unlock(&sysfs_lock
);
111 mpic_start_timer(fsl_wakeup
->timer
);
113 mutex_unlock(&sysfs_lock
);
118 static struct device_attribute mpic_attributes
= __ATTR(timer_wakeup
, 0644,
119 fsl_timer_wakeup_show
, fsl_timer_wakeup_store
);
121 static int __init
fsl_wakeup_sys_init(void)
125 fsl_wakeup
= kzalloc(sizeof(struct fsl_mpic_timer_wakeup
), GFP_KERNEL
);
129 INIT_WORK(&fsl_wakeup
->free_work
, fsl_free_resource
);
131 ret
= device_create_file(mpic_subsys
.dev_root
, &mpic_attributes
);
138 static void __exit
fsl_wakeup_sys_exit(void)
140 device_remove_file(mpic_subsys
.dev_root
, &mpic_attributes
);
142 mutex_lock(&sysfs_lock
);
144 if (fsl_wakeup
->timer
) {
145 disable_irq_wake(fsl_wakeup
->timer
->irq
);
146 mpic_free_timer(fsl_wakeup
->timer
);
151 mutex_unlock(&sysfs_lock
);
154 module_init(fsl_wakeup_sys_init
);
155 module_exit(fsl_wakeup_sys_exit
);
157 MODULE_DESCRIPTION("Freescale MPIC global timer wakeup driver");
158 MODULE_LICENSE("GPL v2");
159 MODULE_AUTHOR("Wang Dongsheng <dongsheng.wang@freescale.com>");