diff options
Diffstat (limited to 'arch/sh/drivers/heartbeat.c')
-rw-r--r-- | arch/sh/drivers/heartbeat.c | 70 |
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 | ||
31 | struct heartbeat_data { | 32 | static unsigned char default_bit_pos[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; |
32 | void __iomem *base; | 33 | |
33 | unsigned char bit_pos[8]; | 34 | static 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 | ||
37 | static void heartbeat_timer(unsigned long data) | 56 | static 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 | } |