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
]);
45 switch (hd
->regsize
) {
47 new |= ioread32(hd
->base
) & ~hd
->mask
;
48 iowrite32(new, hd
->base
);
51 new |= ioread16(hd
->base
) & ~hd
->mask
;
52 iowrite16(new, hd
->base
);
55 new |= ioread8(hd
->base
) & ~hd
->mask
;
56 iowrite8(new, hd
->base
);
61 static void heartbeat_timer(unsigned long data
)
63 struct heartbeat_data
*hd
= (struct heartbeat_data
*)data
;
64 static unsigned bit
= 0, up
= 1;
66 heartbeat_toggle_bit(hd
, bit
, hd
->flags
& HEARTBEAT_INVERTED
);
69 if ((bit
== 0) || (bit
== (hd
->nr_bits
)-1))
72 mod_timer(&hd
->timer
, jiffies
+ (110 - ((300 << FSHIFT
) /
73 ((avenrun
[0] / 5) + (3 << FSHIFT
)))));
76 static int heartbeat_drv_probe(struct platform_device
*pdev
)
79 struct heartbeat_data
*hd
;
82 if (unlikely(pdev
->num_resources
!= 1)) {
83 dev_err(&pdev
->dev
, "invalid number of resources\n");
87 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
88 if (unlikely(res
== NULL
)) {
89 dev_err(&pdev
->dev
, "invalid resource\n");
93 if (pdev
->dev
.platform_data
) {
94 hd
= pdev
->dev
.platform_data
;
96 hd
= kzalloc(sizeof(struct heartbeat_data
), GFP_KERNEL
);
101 hd
->base
= ioremap_nocache(res
->start
, res
->end
- res
->start
+ 1);
102 if (unlikely(!hd
->base
)) {
103 dev_err(&pdev
->dev
, "ioremap failed\n");
105 if (!pdev
->dev
.platform_data
)
112 hd
->bit_pos
= default_bit_pos
;
113 hd
->nr_bits
= ARRAY_SIZE(default_bit_pos
);
117 for (i
= 0; i
< hd
->nr_bits
; i
++)
118 hd
->mask
|= (1 << hd
->bit_pos
[i
]);
121 hd
->regsize
= 8; /* default access size */
123 setup_timer(&hd
->timer
, heartbeat_timer
, (unsigned long)hd
);
124 platform_set_drvdata(pdev
, hd
);
126 return mod_timer(&hd
->timer
, jiffies
+ 1);
129 static int heartbeat_drv_remove(struct platform_device
*pdev
)
131 struct heartbeat_data
*hd
= platform_get_drvdata(pdev
);
133 del_timer_sync(&hd
->timer
);
136 platform_set_drvdata(pdev
, NULL
);
138 if (!pdev
->dev
.platform_data
)
144 static struct platform_driver heartbeat_driver
= {
145 .probe
= heartbeat_drv_probe
,
146 .remove
= heartbeat_drv_remove
,
152 static int __init
heartbeat_init(void)
154 printk(KERN_NOTICE DRV_NAME
": version %s loaded\n", DRV_VERSION
);
155 return platform_driver_register(&heartbeat_driver
);
158 static void __exit
heartbeat_exit(void)
160 platform_driver_unregister(&heartbeat_driver
);
162 module_init(heartbeat_init
);
163 module_exit(heartbeat_exit
);
165 MODULE_VERSION(DRV_VERSION
);
166 MODULE_AUTHOR("Paul Mundt");
167 MODULE_LICENSE("GPL v2");