diff options
author | Axel Lin <axel.lin@gmail.com> | 2012-03-15 23:53:53 -0400 |
---|---|---|
committer | Wim Van Sebroeck <wim@iguana.be> | 2012-03-27 14:16:07 -0400 |
commit | d6245842384c9289d4f778555fd8be729e0b0306 (patch) | |
tree | a51ecf0a2c130fb753a3ec9fbd852391aaf00f6e /drivers/watchdog/txx9wdt.c | |
parent | dddbc6a0513b25c80e73e14ee704186deedc0d00 (diff) |
watchdog: Convert txx9wdt driver to watchdog framework
This patch converts txx9wdt driver to watchdog framework.
Also use devm_* APIs to save a few error handling code.
Signed-off-by: Axel Lin <axel.lin@gmail.com>
Acked-by: Wolfram Sang <w.sang@pengutronix.de>
Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
Diffstat (limited to 'drivers/watchdog/txx9wdt.c')
-rw-r--r-- | drivers/watchdog/txx9wdt.c | 155 |
1 files changed, 37 insertions, 118 deletions
diff --git a/drivers/watchdog/txx9wdt.c b/drivers/watchdog/txx9wdt.c index d02804ccd280..53f1b17429c6 100644 --- a/drivers/watchdog/txx9wdt.c +++ b/drivers/watchdog/txx9wdt.c | |||
@@ -15,9 +15,7 @@ | |||
15 | #include <linux/types.h> | 15 | #include <linux/types.h> |
16 | #include <linux/miscdevice.h> | 16 | #include <linux/miscdevice.h> |
17 | #include <linux/watchdog.h> | 17 | #include <linux/watchdog.h> |
18 | #include <linux/fs.h> | ||
19 | #include <linux/init.h> | 18 | #include <linux/init.h> |
20 | #include <linux/uaccess.h> | ||
21 | #include <linux/platform_device.h> | 19 | #include <linux/platform_device.h> |
22 | #include <linux/clk.h> | 20 | #include <linux/clk.h> |
23 | #include <linux/err.h> | 21 | #include <linux/err.h> |
@@ -43,20 +41,19 @@ MODULE_PARM_DESC(nowayout, | |||
43 | #define WD_TIMER_CLK (clk_get_rate(txx9_imclk) / (2 << WD_TIMER_CCD)) | 41 | #define WD_TIMER_CLK (clk_get_rate(txx9_imclk) / (2 << WD_TIMER_CCD)) |
44 | #define WD_MAX_TIMEOUT ((0xffffffff >> (32 - TXX9_TIMER_BITS)) / WD_TIMER_CLK) | 42 | #define WD_MAX_TIMEOUT ((0xffffffff >> (32 - TXX9_TIMER_BITS)) / WD_TIMER_CLK) |
45 | 43 | ||
46 | static unsigned long txx9wdt_alive; | ||
47 | static int expect_close; | ||
48 | static struct txx9_tmr_reg __iomem *txx9wdt_reg; | 44 | static struct txx9_tmr_reg __iomem *txx9wdt_reg; |
49 | static struct clk *txx9_imclk; | 45 | static struct clk *txx9_imclk; |
50 | static DEFINE_SPINLOCK(txx9_lock); | 46 | static DEFINE_SPINLOCK(txx9_lock); |
51 | 47 | ||
52 | static void txx9wdt_ping(void) | 48 | static int txx9wdt_ping(struct watchdog_device *wdt_dev) |
53 | { | 49 | { |
54 | spin_lock(&txx9_lock); | 50 | spin_lock(&txx9_lock); |
55 | __raw_writel(TXx9_TMWTMR_TWIE | TXx9_TMWTMR_TWC, &txx9wdt_reg->wtmr); | 51 | __raw_writel(TXx9_TMWTMR_TWIE | TXx9_TMWTMR_TWC, &txx9wdt_reg->wtmr); |
56 | spin_unlock(&txx9_lock); | 52 | spin_unlock(&txx9_lock); |
53 | return 0; | ||
57 | } | 54 | } |
58 | 55 | ||
59 | static void txx9wdt_start(void) | 56 | static int txx9wdt_start(struct watchdog_device *wdt_dev) |
60 | { | 57 | { |
61 | spin_lock(&txx9_lock); | 58 | spin_lock(&txx9_lock); |
62 | __raw_writel(WD_TIMER_CLK * timeout, &txx9wdt_reg->cpra); | 59 | __raw_writel(WD_TIMER_CLK * timeout, &txx9wdt_reg->cpra); |
@@ -66,120 +63,44 @@ static void txx9wdt_start(void) | |||
66 | &txx9wdt_reg->tcr); | 63 | &txx9wdt_reg->tcr); |
67 | __raw_writel(TXx9_TMWTMR_TWIE | TXx9_TMWTMR_TWC, &txx9wdt_reg->wtmr); | 64 | __raw_writel(TXx9_TMWTMR_TWIE | TXx9_TMWTMR_TWC, &txx9wdt_reg->wtmr); |
68 | spin_unlock(&txx9_lock); | 65 | spin_unlock(&txx9_lock); |
66 | return 0; | ||
69 | } | 67 | } |
70 | 68 | ||
71 | static void txx9wdt_stop(void) | 69 | static int txx9wdt_stop(struct watchdog_device *wdt_dev) |
72 | { | 70 | { |
73 | spin_lock(&txx9_lock); | 71 | spin_lock(&txx9_lock); |
74 | __raw_writel(TXx9_TMWTMR_WDIS, &txx9wdt_reg->wtmr); | 72 | __raw_writel(TXx9_TMWTMR_WDIS, &txx9wdt_reg->wtmr); |
75 | __raw_writel(__raw_readl(&txx9wdt_reg->tcr) & ~TXx9_TMTCR_TCE, | 73 | __raw_writel(__raw_readl(&txx9wdt_reg->tcr) & ~TXx9_TMTCR_TCE, |
76 | &txx9wdt_reg->tcr); | 74 | &txx9wdt_reg->tcr); |
77 | spin_unlock(&txx9_lock); | 75 | spin_unlock(&txx9_lock); |
78 | } | ||
79 | |||
80 | static int txx9wdt_open(struct inode *inode, struct file *file) | ||
81 | { | ||
82 | if (test_and_set_bit(0, &txx9wdt_alive)) | ||
83 | return -EBUSY; | ||
84 | |||
85 | if (__raw_readl(&txx9wdt_reg->tcr) & TXx9_TMTCR_TCE) { | ||
86 | clear_bit(0, &txx9wdt_alive); | ||
87 | return -EBUSY; | ||
88 | } | ||
89 | |||
90 | if (nowayout) | ||
91 | __module_get(THIS_MODULE); | ||
92 | |||
93 | txx9wdt_start(); | ||
94 | return nonseekable_open(inode, file); | ||
95 | } | ||
96 | |||
97 | static int txx9wdt_release(struct inode *inode, struct file *file) | ||
98 | { | ||
99 | if (expect_close) | ||
100 | txx9wdt_stop(); | ||
101 | else { | ||
102 | pr_crit("Unexpected close, not stopping watchdog!\n"); | ||
103 | txx9wdt_ping(); | ||
104 | } | ||
105 | clear_bit(0, &txx9wdt_alive); | ||
106 | expect_close = 0; | ||
107 | return 0; | 76 | return 0; |
108 | } | 77 | } |
109 | 78 | ||
110 | static ssize_t txx9wdt_write(struct file *file, const char __user *data, | 79 | static int txx9wdt_set_timeout(struct watchdog_device *wdt_dev, |
111 | size_t len, loff_t *ppos) | 80 | unsigned int new_timeout) |
112 | { | 81 | { |
113 | if (len) { | 82 | timeout = new_timeout; |
114 | if (!nowayout) { | 83 | txx9wdt_stop(wdt_dev); |
115 | size_t i; | 84 | txx9wdt_start(wdt_dev); |
116 | 85 | return 0; | |
117 | expect_close = 0; | ||
118 | for (i = 0; i != len; i++) { | ||
119 | char c; | ||
120 | if (get_user(c, data + i)) | ||
121 | return -EFAULT; | ||
122 | if (c == 'V') | ||
123 | expect_close = 1; | ||
124 | } | ||
125 | } | ||
126 | txx9wdt_ping(); | ||
127 | } | ||
128 | return len; | ||
129 | } | 86 | } |
130 | 87 | ||
131 | static long txx9wdt_ioctl(struct file *file, unsigned int cmd, | 88 | static const struct watchdog_info txx9wdt_info = { |
132 | unsigned long arg) | 89 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, |
133 | { | 90 | .identity = "Hardware Watchdog for TXx9", |
134 | void __user *argp = (void __user *)arg; | 91 | }; |
135 | int __user *p = argp; | ||
136 | int new_timeout; | ||
137 | static const struct watchdog_info ident = { | ||
138 | .options = WDIOF_SETTIMEOUT | | ||
139 | WDIOF_KEEPALIVEPING | | ||
140 | WDIOF_MAGICCLOSE, | ||
141 | .firmware_version = 0, | ||
142 | .identity = "Hardware Watchdog for TXx9", | ||
143 | }; | ||
144 | |||
145 | switch (cmd) { | ||
146 | case WDIOC_GETSUPPORT: | ||
147 | return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; | ||
148 | case WDIOC_GETSTATUS: | ||
149 | case WDIOC_GETBOOTSTATUS: | ||
150 | return put_user(0, p); | ||
151 | case WDIOC_KEEPALIVE: | ||
152 | txx9wdt_ping(); | ||
153 | return 0; | ||
154 | case WDIOC_SETTIMEOUT: | ||
155 | if (get_user(new_timeout, p)) | ||
156 | return -EFAULT; | ||
157 | if (new_timeout < 1 || new_timeout > WD_MAX_TIMEOUT) | ||
158 | return -EINVAL; | ||
159 | timeout = new_timeout; | ||
160 | txx9wdt_stop(); | ||
161 | txx9wdt_start(); | ||
162 | /* Fall */ | ||
163 | case WDIOC_GETTIMEOUT: | ||
164 | return put_user(timeout, p); | ||
165 | default: | ||
166 | return -ENOTTY; | ||
167 | } | ||
168 | } | ||
169 | 92 | ||
170 | static const struct file_operations txx9wdt_fops = { | 93 | static const struct watchdog_ops txx9wdt_ops = { |
171 | .owner = THIS_MODULE, | 94 | .owner = THIS_MODULE, |
172 | .llseek = no_llseek, | 95 | .start = txx9wdt_start, |
173 | .write = txx9wdt_write, | 96 | .stop = txx9wdt_stop, |
174 | .unlocked_ioctl = txx9wdt_ioctl, | 97 | .ping = txx9wdt_ping, |
175 | .open = txx9wdt_open, | 98 | .set_timeout = txx9wdt_set_timeout, |
176 | .release = txx9wdt_release, | ||
177 | }; | 99 | }; |
178 | 100 | ||
179 | static struct miscdevice txx9wdt_miscdev = { | 101 | static struct watchdog_device txx9wdt = { |
180 | .minor = WATCHDOG_MINOR, | 102 | .info = &txx9wdt_info, |
181 | .name = "watchdog", | 103 | .ops = &txx9wdt_ops, |
182 | .fops = &txx9wdt_fops, | ||
183 | }; | 104 | }; |
184 | 105 | ||
185 | static int __init txx9wdt_probe(struct platform_device *dev) | 106 | static int __init txx9wdt_probe(struct platform_device *dev) |
@@ -201,26 +122,24 @@ static int __init txx9wdt_probe(struct platform_device *dev) | |||
201 | } | 122 | } |
202 | 123 | ||
203 | res = platform_get_resource(dev, IORESOURCE_MEM, 0); | 124 | res = platform_get_resource(dev, IORESOURCE_MEM, 0); |
204 | if (!res) | 125 | txx9wdt_reg = devm_request_and_ioremap(&dev->dev, res); |
205 | goto exit_busy; | 126 | if (!txx9wdt_reg) { |
206 | if (!devm_request_mem_region(&dev->dev, res->start, resource_size(res), | 127 | ret = -EBUSY; |
207 | "txx9wdt")) | ||
208 | goto exit_busy; | ||
209 | txx9wdt_reg = devm_ioremap(&dev->dev, res->start, resource_size(res)); | ||
210 | if (!txx9wdt_reg) | ||
211 | goto exit_busy; | ||
212 | |||
213 | ret = misc_register(&txx9wdt_miscdev); | ||
214 | if (ret) { | ||
215 | goto exit; | 128 | goto exit; |
216 | } | 129 | } |
217 | 130 | ||
131 | txx9wdt.min_timeout = 1; | ||
132 | txx9wdt.max_timeout = WD_MAX_TIMEOUT; | ||
133 | watchdog_set_nowayout(&txx9wdt, nowayout); | ||
134 | |||
135 | ret = watchdog_register_device(&txx9wdt); | ||
136 | if (ret) | ||
137 | goto exit; | ||
138 | |||
218 | pr_info("Hardware Watchdog Timer: timeout=%d sec (max %ld) (nowayout= %d)\n", | 139 | pr_info("Hardware Watchdog Timer: timeout=%d sec (max %ld) (nowayout= %d)\n", |
219 | timeout, WD_MAX_TIMEOUT, nowayout); | 140 | timeout, WD_MAX_TIMEOUT, nowayout); |
220 | 141 | ||
221 | return 0; | 142 | return 0; |
222 | exit_busy: | ||
223 | ret = -EBUSY; | ||
224 | exit: | 143 | exit: |
225 | if (txx9_imclk) { | 144 | if (txx9_imclk) { |
226 | clk_disable(txx9_imclk); | 145 | clk_disable(txx9_imclk); |
@@ -231,7 +150,7 @@ exit: | |||
231 | 150 | ||
232 | static int __exit txx9wdt_remove(struct platform_device *dev) | 151 | static int __exit txx9wdt_remove(struct platform_device *dev) |
233 | { | 152 | { |
234 | misc_deregister(&txx9wdt_miscdev); | 153 | watchdog_unregister_device(&txx9wdt); |
235 | clk_disable(txx9_imclk); | 154 | clk_disable(txx9_imclk); |
236 | clk_put(txx9_imclk); | 155 | clk_put(txx9_imclk); |
237 | return 0; | 156 | return 0; |
@@ -239,7 +158,7 @@ static int __exit txx9wdt_remove(struct platform_device *dev) | |||
239 | 158 | ||
240 | static void txx9wdt_shutdown(struct platform_device *dev) | 159 | static void txx9wdt_shutdown(struct platform_device *dev) |
241 | { | 160 | { |
242 | txx9wdt_stop(); | 161 | txx9wdt_stop(&txx9wdt); |
243 | } | 162 | } |
244 | 163 | ||
245 | static struct platform_driver txx9wdt_driver = { | 164 | static struct platform_driver txx9wdt_driver = { |