Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/sh/drivers/heartbeat.c
10817 views
1
/*
2
* Generic heartbeat driver for regular LED banks
3
*
4
* Copyright (C) 2007 - 2010 Paul Mundt
5
*
6
* Most SH reference boards include a number of individual LEDs that can
7
* be independently controlled (either via a pre-defined hardware
8
* function or via the LED class, if desired -- the hardware tends to
9
* encapsulate some of the same "triggers" that the LED class supports,
10
* so there's not too much value in it).
11
*
12
* Additionally, most of these boards also have a LED bank that we've
13
* traditionally used for strobing the load average. This use case is
14
* handled by this driver, rather than giving each LED bit position its
15
* own struct device.
16
*
17
* This file is subject to the terms and conditions of the GNU General Public
18
* License. See the file "COPYING" in the main directory of this archive
19
* for more details.
20
*/
21
#include <linux/init.h>
22
#include <linux/module.h>
23
#include <linux/platform_device.h>
24
#include <linux/sched.h>
25
#include <linux/timer.h>
26
#include <linux/io.h>
27
#include <linux/slab.h>
28
#include <asm/heartbeat.h>
29
30
#define DRV_NAME "heartbeat"
31
#define DRV_VERSION "0.1.2"
32
33
static unsigned char default_bit_pos[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
34
35
static inline void heartbeat_toggle_bit(struct heartbeat_data *hd,
36
unsigned bit, unsigned int inverted)
37
{
38
unsigned int new;
39
40
new = (1 << hd->bit_pos[bit]);
41
if (inverted)
42
new = ~new;
43
44
new &= hd->mask;
45
46
switch (hd->regsize) {
47
case 32:
48
new |= ioread32(hd->base) & ~hd->mask;
49
iowrite32(new, hd->base);
50
break;
51
case 16:
52
new |= ioread16(hd->base) & ~hd->mask;
53
iowrite16(new, hd->base);
54
break;
55
default:
56
new |= ioread8(hd->base) & ~hd->mask;
57
iowrite8(new, hd->base);
58
break;
59
}
60
}
61
62
static void heartbeat_timer(unsigned long data)
63
{
64
struct heartbeat_data *hd = (struct heartbeat_data *)data;
65
static unsigned bit = 0, up = 1;
66
67
heartbeat_toggle_bit(hd, bit, hd->flags & HEARTBEAT_INVERTED);
68
69
bit += up;
70
if ((bit == 0) || (bit == (hd->nr_bits)-1))
71
up = -up;
72
73
mod_timer(&hd->timer, jiffies + (110 - ((300 << FSHIFT) /
74
((avenrun[0] / 5) + (3 << FSHIFT)))));
75
}
76
77
static int heartbeat_drv_probe(struct platform_device *pdev)
78
{
79
struct resource *res;
80
struct heartbeat_data *hd;
81
int i;
82
83
if (unlikely(pdev->num_resources != 1)) {
84
dev_err(&pdev->dev, "invalid number of resources\n");
85
return -EINVAL;
86
}
87
88
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
89
if (unlikely(res == NULL)) {
90
dev_err(&pdev->dev, "invalid resource\n");
91
return -EINVAL;
92
}
93
94
if (pdev->dev.platform_data) {
95
hd = pdev->dev.platform_data;
96
} else {
97
hd = kzalloc(sizeof(struct heartbeat_data), GFP_KERNEL);
98
if (unlikely(!hd))
99
return -ENOMEM;
100
}
101
102
hd->base = ioremap_nocache(res->start, resource_size(res));
103
if (unlikely(!hd->base)) {
104
dev_err(&pdev->dev, "ioremap failed\n");
105
106
if (!pdev->dev.platform_data)
107
kfree(hd);
108
109
return -ENXIO;
110
}
111
112
if (!hd->nr_bits) {
113
hd->bit_pos = default_bit_pos;
114
hd->nr_bits = ARRAY_SIZE(default_bit_pos);
115
}
116
117
hd->mask = 0;
118
for (i = 0; i < hd->nr_bits; i++)
119
hd->mask |= (1 << hd->bit_pos[i]);
120
121
if (!hd->regsize) {
122
switch (res->flags & IORESOURCE_MEM_TYPE_MASK) {
123
case IORESOURCE_MEM_32BIT:
124
hd->regsize = 32;
125
break;
126
case IORESOURCE_MEM_16BIT:
127
hd->regsize = 16;
128
break;
129
case IORESOURCE_MEM_8BIT:
130
default:
131
hd->regsize = 8;
132
break;
133
}
134
}
135
136
setup_timer(&hd->timer, heartbeat_timer, (unsigned long)hd);
137
platform_set_drvdata(pdev, hd);
138
139
return mod_timer(&hd->timer, jiffies + 1);
140
}
141
142
static int heartbeat_drv_remove(struct platform_device *pdev)
143
{
144
struct heartbeat_data *hd = platform_get_drvdata(pdev);
145
146
del_timer_sync(&hd->timer);
147
iounmap(hd->base);
148
149
platform_set_drvdata(pdev, NULL);
150
151
if (!pdev->dev.platform_data)
152
kfree(hd);
153
154
return 0;
155
}
156
157
static struct platform_driver heartbeat_driver = {
158
.probe = heartbeat_drv_probe,
159
.remove = heartbeat_drv_remove,
160
.driver = {
161
.name = DRV_NAME,
162
},
163
};
164
165
static int __init heartbeat_init(void)
166
{
167
printk(KERN_NOTICE DRV_NAME ": version %s loaded\n", DRV_VERSION);
168
return platform_driver_register(&heartbeat_driver);
169
}
170
171
static void __exit heartbeat_exit(void)
172
{
173
platform_driver_unregister(&heartbeat_driver);
174
}
175
module_init(heartbeat_init);
176
module_exit(heartbeat_exit);
177
178
MODULE_VERSION(DRV_VERSION);
179
MODULE_AUTHOR("Paul Mundt");
180
MODULE_LICENSE("GPL v2");
181
182