Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/powerpc/sysdev/fsl_mpic_timer_wakeup.c
26424 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* MPIC timer wakeup driver
4
*
5
* Copyright 2013 Freescale Semiconductor, Inc.
6
*/
7
8
#include <linux/kernel.h>
9
#include <linux/slab.h>
10
#include <linux/errno.h>
11
#include <linux/module.h>
12
#include <linux/interrupt.h>
13
#include <linux/device.h>
14
15
#include <asm/mpic_timer.h>
16
#include <asm/mpic.h>
17
18
struct fsl_mpic_timer_wakeup {
19
struct mpic_timer *timer;
20
struct work_struct free_work;
21
};
22
23
static struct fsl_mpic_timer_wakeup *fsl_wakeup;
24
static DEFINE_MUTEX(sysfs_lock);
25
26
static void fsl_free_resource(struct work_struct *ws)
27
{
28
struct fsl_mpic_timer_wakeup *wakeup =
29
container_of(ws, struct fsl_mpic_timer_wakeup, free_work);
30
31
mutex_lock(&sysfs_lock);
32
33
if (wakeup->timer) {
34
disable_irq_wake(wakeup->timer->irq);
35
mpic_free_timer(wakeup->timer);
36
}
37
38
wakeup->timer = NULL;
39
mutex_unlock(&sysfs_lock);
40
}
41
42
static irqreturn_t fsl_mpic_timer_irq(int irq, void *dev_id)
43
{
44
struct fsl_mpic_timer_wakeup *wakeup = dev_id;
45
46
schedule_work(&wakeup->free_work);
47
48
return wakeup->timer ? IRQ_HANDLED : IRQ_NONE;
49
}
50
51
static ssize_t fsl_timer_wakeup_show(struct device *dev,
52
struct device_attribute *attr,
53
char *buf)
54
{
55
time64_t interval = 0;
56
57
mutex_lock(&sysfs_lock);
58
if (fsl_wakeup->timer) {
59
mpic_get_remain_time(fsl_wakeup->timer, &interval);
60
interval++;
61
}
62
mutex_unlock(&sysfs_lock);
63
64
return sprintf(buf, "%lld\n", interval);
65
}
66
67
static ssize_t fsl_timer_wakeup_store(struct device *dev,
68
struct device_attribute *attr,
69
const char *buf,
70
size_t count)
71
{
72
time64_t interval;
73
int ret;
74
75
if (kstrtoll(buf, 0, &interval))
76
return -EINVAL;
77
78
guard(mutex)(&sysfs_lock);
79
80
if (fsl_wakeup->timer) {
81
disable_irq_wake(fsl_wakeup->timer->irq);
82
mpic_free_timer(fsl_wakeup->timer);
83
fsl_wakeup->timer = NULL;
84
}
85
86
if (!interval)
87
return count;
88
89
fsl_wakeup->timer = mpic_request_timer(fsl_mpic_timer_irq,
90
fsl_wakeup, interval);
91
if (!fsl_wakeup->timer)
92
return -EINVAL;
93
94
ret = enable_irq_wake(fsl_wakeup->timer->irq);
95
if (ret) {
96
mpic_free_timer(fsl_wakeup->timer);
97
fsl_wakeup->timer = NULL;
98
return ret;
99
}
100
101
mpic_start_timer(fsl_wakeup->timer);
102
103
return count;
104
}
105
106
static struct device_attribute mpic_attributes = __ATTR(timer_wakeup, 0644,
107
fsl_timer_wakeup_show, fsl_timer_wakeup_store);
108
109
static int __init fsl_wakeup_sys_init(void)
110
{
111
struct device *dev_root;
112
int ret = -EINVAL;
113
114
fsl_wakeup = kzalloc(sizeof(struct fsl_mpic_timer_wakeup), GFP_KERNEL);
115
if (!fsl_wakeup)
116
return -ENOMEM;
117
118
INIT_WORK(&fsl_wakeup->free_work, fsl_free_resource);
119
120
dev_root = bus_get_dev_root(&mpic_subsys);
121
if (dev_root) {
122
ret = device_create_file(dev_root, &mpic_attributes);
123
put_device(dev_root);
124
if (ret)
125
kfree(fsl_wakeup);
126
}
127
128
return ret;
129
}
130
131
static void __exit fsl_wakeup_sys_exit(void)
132
{
133
struct device *dev_root;
134
135
dev_root = bus_get_dev_root(&mpic_subsys);
136
if (dev_root) {
137
device_remove_file(dev_root, &mpic_attributes);
138
put_device(dev_root);
139
}
140
141
mutex_lock(&sysfs_lock);
142
143
if (fsl_wakeup->timer) {
144
disable_irq_wake(fsl_wakeup->timer->irq);
145
mpic_free_timer(fsl_wakeup->timer);
146
}
147
148
kfree(fsl_wakeup);
149
150
mutex_unlock(&sysfs_lock);
151
}
152
153
module_init(fsl_wakeup_sys_init);
154
module_exit(fsl_wakeup_sys_exit);
155
156
MODULE_DESCRIPTION("Freescale MPIC global timer wakeup driver");
157
MODULE_LICENSE("GPL v2");
158
MODULE_AUTHOR("Wang Dongsheng <[email protected]>");
159
160