diff options
Diffstat (limited to 'arch/sh/drivers/heartbeat.c')
-rw-r--r-- | arch/sh/drivers/heartbeat.c | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/arch/sh/drivers/heartbeat.c b/arch/sh/drivers/heartbeat.c new file mode 100644 index 000000000000..bc59cb6cd78b --- /dev/null +++ b/arch/sh/drivers/heartbeat.c | |||
@@ -0,0 +1,132 @@ | |||
1 | /* | ||
2 | * Generic heartbeat driver for regular LED banks | ||
3 | * | ||
4 | * Copyright (C) 2007 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 | |||
28 | #define DRV_NAME "heartbeat" | ||
29 | #define DRV_VERSION "0.1.0" | ||
30 | |||
31 | struct heartbeat_data { | ||
32 | void __iomem *base; | ||
33 | unsigned char bit_pos[8]; | ||
34 | struct timer_list timer; | ||
35 | }; | ||
36 | |||
37 | static void heartbeat_timer(unsigned long data) | ||
38 | { | ||
39 | struct heartbeat_data *hd = (struct heartbeat_data *)data; | ||
40 | static unsigned bit = 0, up = 1; | ||
41 | |||
42 | ctrl_outw(1 << hd->bit_pos[bit], (unsigned long)hd->base); | ||
43 | if (up) | ||
44 | if (bit == (ARRAY_SIZE(hd->bit_pos) - 1)) { | ||
45 | bit--; | ||
46 | up = 0; | ||
47 | } else | ||
48 | bit++; | ||
49 | else if (bit == 0) | ||
50 | up = 1; | ||
51 | else | ||
52 | bit--; | ||
53 | |||
54 | mod_timer(&hd->timer, jiffies + (110 - ((300 << FSHIFT) / | ||
55 | ((avenrun[0] / 5) + (3 << FSHIFT))))); | ||
56 | } | ||
57 | |||
58 | static int heartbeat_drv_probe(struct platform_device *pdev) | ||
59 | { | ||
60 | struct resource *res; | ||
61 | struct heartbeat_data *hd; | ||
62 | |||
63 | if (unlikely(pdev->num_resources != 1)) { | ||
64 | dev_err(&pdev->dev, "invalid number of resources\n"); | ||
65 | return -EINVAL; | ||
66 | } | ||
67 | |||
68 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
69 | if (unlikely(res == NULL)) { | ||
70 | dev_err(&pdev->dev, "invalid resource\n"); | ||
71 | return -EINVAL; | ||
72 | } | ||
73 | |||
74 | hd = kmalloc(sizeof(struct heartbeat_data), GFP_KERNEL); | ||
75 | if (unlikely(!hd)) | ||
76 | return -ENOMEM; | ||
77 | |||
78 | if (pdev->dev.platform_data) { | ||
79 | memcpy(hd->bit_pos, pdev->dev.platform_data, | ||
80 | ARRAY_SIZE(hd->bit_pos)); | ||
81 | } else { | ||
82 | int i; | ||
83 | |||
84 | for (i = 0; i < ARRAY_SIZE(hd->bit_pos); i++) | ||
85 | hd->bit_pos[i] = i; | ||
86 | } | ||
87 | |||
88 | hd->base = (void __iomem *)res->start; | ||
89 | |||
90 | setup_timer(&hd->timer, heartbeat_timer, (unsigned long)hd); | ||
91 | platform_set_drvdata(pdev, hd); | ||
92 | |||
93 | return mod_timer(&hd->timer, jiffies + 1); | ||
94 | } | ||
95 | |||
96 | static int heartbeat_drv_remove(struct platform_device *pdev) | ||
97 | { | ||
98 | struct heartbeat_data *hd = platform_get_drvdata(pdev); | ||
99 | |||
100 | del_timer_sync(&hd->timer); | ||
101 | |||
102 | platform_set_drvdata(pdev, NULL); | ||
103 | |||
104 | kfree(hd); | ||
105 | |||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | static struct platform_driver heartbeat_driver = { | ||
110 | .probe = heartbeat_drv_probe, | ||
111 | .remove = heartbeat_drv_remove, | ||
112 | .driver = { | ||
113 | .name = DRV_NAME, | ||
114 | }, | ||
115 | }; | ||
116 | |||
117 | static int __init heartbeat_init(void) | ||
118 | { | ||
119 | printk(KERN_NOTICE DRV_NAME ": version %s loaded\n", DRV_VERSION); | ||
120 | return platform_driver_register(&heartbeat_driver); | ||
121 | } | ||
122 | |||
123 | static void __exit heartbeat_exit(void) | ||
124 | { | ||
125 | platform_driver_unregister(&heartbeat_driver); | ||
126 | } | ||
127 | module_init(heartbeat_init); | ||
128 | module_exit(heartbeat_exit); | ||
129 | |||
130 | MODULE_VERSION(DRV_VERSION); | ||
131 | MODULE_AUTHOR("Paul Mundt"); | ||
132 | MODULE_LICENSE("GPLv2"); | ||