2 * Generic heartbeat driver for regular LED banks
4 * Copyright (C) 2007 Paul Mundt
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).
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
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
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>
27 #include <asm/heartbeat.h>
29 #define DRV_NAME "heartbeat"
30 #define DRV_VERSION "0.1.1"
32 static unsigned char default_bit_pos
[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
34 static inline void heartbeat_toggle_bit(struct heartbeat_data
*hd
,
35 unsigned bit
, unsigned int inverted
)
39 new = (1 << hd
->bit_pos
[bit
]);
43 switch (hd
->regsize
) {
45 iowrite32(new, hd
->base
);
48 iowrite16(new, hd
->base
);
51 iowrite8(new, hd
->base
);
56 static void heartbeat_timer(unsigned long data
)
58 struct heartbeat_data
*hd
= (struct heartbeat_data
*)data
;
59 static unsigned bit
= 0, up
= 1;
61 heartbeat_toggle_bit(hd
, bit
, hd
->flags
& HEARTBEAT_INVERTED
);
64 if ((bit
== 0) || (bit
== (hd
->nr_bits
)-1))
67 mod_timer(&hd
->timer
, jiffies
+ (110 - ((300 << FSHIFT
) /
68 ((avenrun
[0] / 5) + (3 << FSHIFT
)))));
71 static int heartbeat_drv_probe(struct platform_device
*pdev
)
74 struct heartbeat_data
*hd
;
76 if (unlikely(pdev
->num_resources
!= 1)) {
77 dev_err(&pdev
->dev
, "invalid number of resources\n");
81 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
82 if (unlikely(res
== NULL
)) {
83 dev_err(&pdev
->dev
, "invalid resource\n");
87 if (pdev
->dev
.platform_data
) {
88 hd
= pdev
->dev
.platform_data
;
90 hd
= kzalloc(sizeof(struct heartbeat_data
), GFP_KERNEL
);
95 hd
->base
= ioremap_nocache(res
->start
, res
->end
- res
->start
+ 1);
96 if (!unlikely(hd
->base
)) {
97 dev_err(&pdev
->dev
, "ioremap failed\n");
99 if (!pdev
->dev
.platform_data
)
106 hd
->bit_pos
= default_bit_pos
;
107 hd
->nr_bits
= ARRAY_SIZE(default_bit_pos
);
111 hd
->regsize
= 8; /* default access size */
113 setup_timer(&hd
->timer
, heartbeat_timer
, (unsigned long)hd
);
114 platform_set_drvdata(pdev
, hd
);
116 return mod_timer(&hd
->timer
, jiffies
+ 1);
119 static int heartbeat_drv_remove(struct platform_device
*pdev
)
121 struct heartbeat_data
*hd
= platform_get_drvdata(pdev
);
123 del_timer_sync(&hd
->timer
);
126 platform_set_drvdata(pdev
, NULL
);
128 if (!pdev
->dev
.platform_data
)
134 static struct platform_driver heartbeat_driver
= {
135 .probe
= heartbeat_drv_probe
,
136 .remove
= heartbeat_drv_remove
,
142 static int __init
heartbeat_init(void)
144 printk(KERN_NOTICE DRV_NAME
": version %s loaded\n", DRV_VERSION
);
145 return platform_driver_register(&heartbeat_driver
);
148 static void __exit
heartbeat_exit(void)
150 platform_driver_unregister(&heartbeat_driver
);
152 module_init(heartbeat_init
);
153 module_exit(heartbeat_exit
);
155 MODULE_VERSION(DRV_VERSION
);
156 MODULE_AUTHOR("Paul Mundt");
157 MODULE_LICENSE("GPLv2");