aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sh/drivers')
-rw-r--r--arch/sh/drivers/heartbeat.c70
1 files changed, 51 insertions, 19 deletions
diff --git a/arch/sh/drivers/heartbeat.c b/arch/sh/drivers/heartbeat.c
index 10c1828c9ff5..b76a14f12ce2 100644
--- a/arch/sh/drivers/heartbeat.c
+++ b/arch/sh/drivers/heartbeat.c
@@ -24,24 +24,44 @@
24#include <linux/sched.h> 24#include <linux/sched.h>
25#include <linux/timer.h> 25#include <linux/timer.h>
26#include <linux/io.h> 26#include <linux/io.h>
27#include <asm/heartbeat.h>
27 28
28#define DRV_NAME "heartbeat" 29#define DRV_NAME "heartbeat"
29#define DRV_VERSION "0.1.0" 30#define DRV_VERSION "0.1.1"
30 31
31struct heartbeat_data { 32static unsigned char default_bit_pos[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
32 void __iomem *base; 33
33 unsigned char bit_pos[8]; 34static inline void heartbeat_toggle_bit(struct heartbeat_data *hd,
34 struct timer_list timer; 35 unsigned bit, unsigned int inverted)
35}; 36{
37 unsigned int new;
38
39 new = (1 << hd->bit_pos[bit]);
40 if (inverted)
41 new = ~new;
42
43 switch (hd->regsize) {
44 case 32:
45 iowrite32(new, hd->base);
46 break;
47 case 16:
48 iowrite16(new, hd->base);
49 break;
50 default:
51 iowrite8(new, hd->base);
52 break;
53 }
54}
36 55
37static void heartbeat_timer(unsigned long data) 56static void heartbeat_timer(unsigned long data)
38{ 57{
39 struct heartbeat_data *hd = (struct heartbeat_data *)data; 58 struct heartbeat_data *hd = (struct heartbeat_data *)data;
40 static unsigned bit = 0, up = 1; 59 static unsigned bit = 0, up = 1;
41 60
42 ctrl_outw(1 << hd->bit_pos[bit], (unsigned long)hd->base); 61 heartbeat_toggle_bit(hd, bit, hd->flags & HEARTBEAT_INVERTED);
62
43 bit += up; 63 bit += up;
44 if ((bit == 0) || (bit == ARRAY_SIZE(hd->bit_pos)-1)) 64 if ((bit == 0) || (bit == (hd->nr_bits)-1))
45 up = -up; 65 up = -up;
46 66
47 mod_timer(&hd->timer, jiffies + (110 - ((300 << FSHIFT) / 67 mod_timer(&hd->timer, jiffies + (110 - ((300 << FSHIFT) /
@@ -64,21 +84,31 @@ static int heartbeat_drv_probe(struct platform_device *pdev)
64 return -EINVAL; 84 return -EINVAL;
65 } 85 }
66 86
67 hd = kmalloc(sizeof(struct heartbeat_data), GFP_KERNEL);
68 if (unlikely(!hd))
69 return -ENOMEM;
70
71 if (pdev->dev.platform_data) { 87 if (pdev->dev.platform_data) {
72 memcpy(hd->bit_pos, pdev->dev.platform_data, 88 hd = pdev->dev.platform_data;
73 ARRAY_SIZE(hd->bit_pos));
74 } else { 89 } else {
75 int i; 90 hd = kzalloc(sizeof(struct heartbeat_data), GFP_KERNEL);
91 if (unlikely(!hd))
92 return -ENOMEM;
93 }
94
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");
98
99 if (!pdev->dev.platform_data)
100 kfree(hd);
101
102 return -ENXIO;
103 }
76 104
77 for (i = 0; i < ARRAY_SIZE(hd->bit_pos); i++) 105 if (!hd->nr_bits) {
78 hd->bit_pos[i] = i; 106 hd->bit_pos = default_bit_pos;
107 hd->nr_bits = ARRAY_SIZE(default_bit_pos);
79 } 108 }
80 109
81 hd->base = (void __iomem *)(unsigned long)res->start; 110 if (!hd->regsize)
111 hd->regsize = 8; /* default access size */
82 112
83 setup_timer(&hd->timer, heartbeat_timer, (unsigned long)hd); 113 setup_timer(&hd->timer, heartbeat_timer, (unsigned long)hd);
84 platform_set_drvdata(pdev, hd); 114 platform_set_drvdata(pdev, hd);
@@ -91,10 +121,12 @@ static int heartbeat_drv_remove(struct platform_device *pdev)
91 struct heartbeat_data *hd = platform_get_drvdata(pdev); 121 struct heartbeat_data *hd = platform_get_drvdata(pdev);
92 122
93 del_timer_sync(&hd->timer); 123 del_timer_sync(&hd->timer);
124 iounmap(hd->base);
94 125
95 platform_set_drvdata(pdev, NULL); 126 platform_set_drvdata(pdev, NULL);
96 127
97 kfree(hd); 128 if (!pdev->dev.platform_data)
129 kfree(hd);
98 130
99 return 0; 131 return 0;
100} 132}