2 * Generic heartbeat driver for regular LED banks
4 * Copyright (C) 2007 - 2010 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/platform_device.h>
23 #include <linux/sched.h>
24 #include <linux/sched/loadavg.h>
25 #include <linux/timer.h>
27 #include <linux/slab.h>
28 #include <asm/heartbeat.h>
30 #define DRV_NAME "heartbeat"
31 #define DRV_VERSION "0.1.2"
33 static unsigned char default_bit_pos
[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
35 static inline void heartbeat_toggle_bit(struct heartbeat_data
*hd
,
36 unsigned bit
, unsigned int inverted
)
40 new = (1 << hd
->bit_pos
[bit
]);
46 switch (hd
->regsize
) {
48 new |= ioread32(hd
->base
) & ~hd
->mask
;
49 iowrite32(new, hd
->base
);
52 new |= ioread16(hd
->base
) & ~hd
->mask
;
53 iowrite16(new, hd
->base
);
56 new |= ioread8(hd
->base
) & ~hd
->mask
;
57 iowrite8(new, hd
->base
);
62 static void heartbeat_timer(struct timer_list
*t
)
64 struct heartbeat_data
*hd
= from_timer(hd
, t
, timer
);
65 static unsigned bit
= 0, up
= 1;
67 heartbeat_toggle_bit(hd
, bit
, hd
->flags
& HEARTBEAT_INVERTED
);
70 if ((bit
== 0) || (bit
== (hd
->nr_bits
)-1))
73 mod_timer(&hd
->timer
, jiffies
+ (110 - ((300 << FSHIFT
) /
74 ((avenrun
[0] / 5) + (3 << FSHIFT
)))));
77 static int heartbeat_drv_probe(struct platform_device
*pdev
)
80 struct heartbeat_data
*hd
;
83 if (unlikely(pdev
->num_resources
!= 1)) {
84 dev_err(&pdev
->dev
, "invalid number of resources\n");
88 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
89 if (unlikely(res
== NULL
)) {
90 dev_err(&pdev
->dev
, "invalid resource\n");
94 if (pdev
->dev
.platform_data
) {
95 hd
= pdev
->dev
.platform_data
;
97 hd
= kzalloc(sizeof(struct heartbeat_data
), GFP_KERNEL
);
102 hd
->base
= ioremap_nocache(res
->start
, resource_size(res
));
103 if (unlikely(!hd
->base
)) {
104 dev_err(&pdev
->dev
, "ioremap failed\n");
106 if (!pdev
->dev
.platform_data
)
113 hd
->bit_pos
= default_bit_pos
;
114 hd
->nr_bits
= ARRAY_SIZE(default_bit_pos
);
118 for (i
= 0; i
< hd
->nr_bits
; i
++)
119 hd
->mask
|= (1 << hd
->bit_pos
[i
]);
122 switch (res
->flags
& IORESOURCE_MEM_TYPE_MASK
) {
123 case IORESOURCE_MEM_32BIT
:
126 case IORESOURCE_MEM_16BIT
:
129 case IORESOURCE_MEM_8BIT
:
136 timer_setup(&hd
->timer
, heartbeat_timer
, 0);
137 platform_set_drvdata(pdev
, hd
);
139 return mod_timer(&hd
->timer
, jiffies
+ 1);
142 static struct platform_driver heartbeat_driver
= {
143 .probe
= heartbeat_drv_probe
,
146 .suppress_bind_attrs
= true,
150 static int __init
heartbeat_init(void)
152 printk(KERN_NOTICE DRV_NAME
": version %s loaded\n", DRV_VERSION
);
153 return platform_driver_register(&heartbeat_driver
);
155 device_initcall(heartbeat_init
);