aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorJarkko Nikula <jarkko.nikula@jollamobile.com>2012-09-11 02:01:10 -0400
committerWim Van Sebroeck <wim@iguana.be>2012-12-19 16:24:40 -0500
commitb2c4e4b2696287671723ef986f0db23cf4f52f15 (patch)
treef5c949159ada0b4ad75aebd16c05104b13975f30 /drivers
parent5235f57a6f460d5620acfcf236ca29ecca993325 (diff)
watchdog: Convert twl4030_wdt to watchdog core
Convert the twl4030_wdt watchdog driver to watchdog core. While at there use devm_kzalloc and set the default timeout in order to be able test this driver with a simple shell script. Signed-off-by: Jarkko Nikula <jarkko.nikula@jollamobile.com> Tested-by: Aaro Koskinen <aaro.koskinen@iki.fi> Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/watchdog/Kconfig1
-rw-r--r--drivers/watchdog/twl4030_wdt.c183
2 files changed, 35 insertions, 149 deletions
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index ad1bb9382a96..ae5af82ac31a 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -300,6 +300,7 @@ config COH901327_WATCHDOG
300config TWL4030_WATCHDOG 300config TWL4030_WATCHDOG
301 tristate "TWL4030 Watchdog" 301 tristate "TWL4030 Watchdog"
302 depends on TWL4030_CORE 302 depends on TWL4030_CORE
303 select WATCHDOG_CORE
303 help 304 help
304 Support for TI TWL4030 watchdog. Say 'Y' here to enable the 305 Support for TI TWL4030 watchdog. Say 'Y' here to enable the
305 watchdog timer support for TWL4030 chips. 306 watchdog timer support for TWL4030 chips.
diff --git a/drivers/watchdog/twl4030_wdt.c b/drivers/watchdog/twl4030_wdt.c
index 9f54b1da7185..01d63674c94f 100644
--- a/drivers/watchdog/twl4030_wdt.c
+++ b/drivers/watchdog/twl4030_wdt.c
@@ -22,26 +22,12 @@
22#include <linux/types.h> 22#include <linux/types.h>
23#include <linux/slab.h> 23#include <linux/slab.h>
24#include <linux/kernel.h> 24#include <linux/kernel.h>
25#include <linux/fs.h>
26#include <linux/watchdog.h> 25#include <linux/watchdog.h>
27#include <linux/platform_device.h> 26#include <linux/platform_device.h>
28#include <linux/miscdevice.h>
29#include <linux/uaccess.h>
30#include <linux/i2c/twl.h> 27#include <linux/i2c/twl.h>
31 28
32#define TWL4030_WATCHDOG_CFG_REG_OFFS 0x3 29#define TWL4030_WATCHDOG_CFG_REG_OFFS 0x3
33 30
34#define TWL4030_WDT_STATE_OPEN 0x1
35#define TWL4030_WDT_STATE_ACTIVE 0x8
36
37static struct platform_device *twl4030_wdt_dev;
38
39struct twl4030_wdt {
40 struct miscdevice miscdev;
41 int timer_margin;
42 unsigned long state;
43};
44
45static bool nowayout = WATCHDOG_NOWAYOUT; 31static bool nowayout = WATCHDOG_NOWAYOUT;
46module_param(nowayout, bool, 0); 32module_param(nowayout, bool, 0);
47MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started " 33MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
@@ -53,171 +39,71 @@ static int twl4030_wdt_write(unsigned char val)
53 TWL4030_WATCHDOG_CFG_REG_OFFS); 39 TWL4030_WATCHDOG_CFG_REG_OFFS);
54} 40}
55 41
56static int twl4030_wdt_enable(struct twl4030_wdt *wdt) 42static int twl4030_wdt_start(struct watchdog_device *wdt)
57{ 43{
58 return twl4030_wdt_write(wdt->timer_margin + 1); 44 return twl4030_wdt_write(wdt->timeout + 1);
59} 45}
60 46
61static int twl4030_wdt_disable(struct twl4030_wdt *wdt) 47static int twl4030_wdt_stop(struct watchdog_device *wdt)
62{ 48{
63 return twl4030_wdt_write(0); 49 return twl4030_wdt_write(0);
64} 50}
65 51
66static int twl4030_wdt_set_timeout(struct twl4030_wdt *wdt, int timeout) 52static int twl4030_wdt_set_timeout(struct watchdog_device *wdt,
67{ 53 unsigned int timeout)
68 if (timeout < 0 || timeout > 30) {
69 dev_warn(wdt->miscdev.parent,
70 "Timeout can only be in the range [0-30] seconds");
71 return -EINVAL;
72 }
73 wdt->timer_margin = timeout;
74 return twl4030_wdt_enable(wdt);
75}
76
77static ssize_t twl4030_wdt_write_fop(struct file *file,
78 const char __user *data, size_t len, loff_t *ppos)
79{ 54{
80 struct twl4030_wdt *wdt = file->private_data; 55 wdt->timeout = timeout;
81
82 if (len)
83 twl4030_wdt_enable(wdt);
84
85 return len;
86}
87
88static long twl4030_wdt_ioctl(struct file *file,
89 unsigned int cmd, unsigned long arg)
90{
91 void __user *argp = (void __user *)arg;
92 int __user *p = argp;
93 int new_margin;
94 struct twl4030_wdt *wdt = file->private_data;
95
96 static const struct watchdog_info twl4030_wd_ident = {
97 .identity = "TWL4030 Watchdog",
98 .options = WDIOF_SETTIMEOUT,
99 .firmware_version = 0,
100 };
101
102 switch (cmd) {
103 case WDIOC_GETSUPPORT:
104 return copy_to_user(argp, &twl4030_wd_ident,
105 sizeof(twl4030_wd_ident)) ? -EFAULT : 0;
106
107 case WDIOC_GETSTATUS:
108 case WDIOC_GETBOOTSTATUS:
109 return put_user(0, p);
110
111 case WDIOC_KEEPALIVE:
112 twl4030_wdt_enable(wdt);
113 break;
114
115 case WDIOC_SETTIMEOUT:
116 if (get_user(new_margin, p))
117 return -EFAULT;
118 if (twl4030_wdt_set_timeout(wdt, new_margin))
119 return -EINVAL;
120 return put_user(wdt->timer_margin, p);
121
122 case WDIOC_GETTIMEOUT:
123 return put_user(wdt->timer_margin, p);
124
125 default:
126 return -ENOTTY;
127 }
128
129 return 0; 56 return 0;
130} 57}
131 58
132static int twl4030_wdt_open(struct inode *inode, struct file *file) 59static const struct watchdog_info twl4030_wdt_info = {
133{ 60 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
134 struct twl4030_wdt *wdt = platform_get_drvdata(twl4030_wdt_dev); 61 .identity = "TWL4030 Watchdog",
135 62};
136 /* /dev/watchdog can only be opened once */
137 if (test_and_set_bit(0, &wdt->state))
138 return -EBUSY;
139
140 wdt->state |= TWL4030_WDT_STATE_ACTIVE;
141 file->private_data = (void *) wdt;
142
143 twl4030_wdt_enable(wdt);
144 return nonseekable_open(inode, file);
145}
146
147static int twl4030_wdt_release(struct inode *inode, struct file *file)
148{
149 struct twl4030_wdt *wdt = file->private_data;
150 if (nowayout) {
151 dev_alert(wdt->miscdev.parent,
152 "Unexpected close, watchdog still running!\n");
153 twl4030_wdt_enable(wdt);
154 } else {
155 if (twl4030_wdt_disable(wdt))
156 return -EFAULT;
157 wdt->state &= ~TWL4030_WDT_STATE_ACTIVE;
158 }
159
160 clear_bit(0, &wdt->state);
161 return 0;
162}
163 63
164static const struct file_operations twl4030_wdt_fops = { 64static const struct watchdog_ops twl4030_wdt_ops = {
165 .owner = THIS_MODULE, 65 .owner = THIS_MODULE,
166 .llseek = no_llseek, 66 .start = twl4030_wdt_start,
167 .open = twl4030_wdt_open, 67 .stop = twl4030_wdt_stop,
168 .release = twl4030_wdt_release, 68 .set_timeout = twl4030_wdt_set_timeout,
169 .unlocked_ioctl = twl4030_wdt_ioctl,
170 .write = twl4030_wdt_write_fop,
171}; 69};
172 70
173static int twl4030_wdt_probe(struct platform_device *pdev) 71static int twl4030_wdt_probe(struct platform_device *pdev)
174{ 72{
175 int ret = 0; 73 int ret = 0;
176 struct twl4030_wdt *wdt; 74 struct watchdog_device *wdt;
177 75
178 wdt = kzalloc(sizeof(struct twl4030_wdt), GFP_KERNEL); 76 wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
179 if (!wdt) 77 if (!wdt)
180 return -ENOMEM; 78 return -ENOMEM;
181 79
182 wdt->state = 0; 80 wdt->info = &twl4030_wdt_info;
183 wdt->timer_margin = 30; 81 wdt->ops = &twl4030_wdt_ops;
184 wdt->miscdev.parent = &pdev->dev; 82 wdt->status = 0;
185 wdt->miscdev.fops = &twl4030_wdt_fops; 83 wdt->timeout = 30;
186 wdt->miscdev.minor = WATCHDOG_MINOR; 84 wdt->min_timeout = 1;
187 wdt->miscdev.name = "watchdog"; 85 wdt->max_timeout = 30;
188 86
87 watchdog_set_nowayout(wdt, nowayout);
189 platform_set_drvdata(pdev, wdt); 88 platform_set_drvdata(pdev, wdt);
190 89
191 twl4030_wdt_dev = pdev; 90 twl4030_wdt_stop(wdt);
192 91
193 twl4030_wdt_disable(wdt); 92 ret = watchdog_register_device(wdt);
194
195 ret = misc_register(&wdt->miscdev);
196 if (ret) { 93 if (ret) {
197 dev_err(wdt->miscdev.parent,
198 "Failed to register misc device\n");
199 platform_set_drvdata(pdev, NULL); 94 platform_set_drvdata(pdev, NULL);
200 kfree(wdt);
201 twl4030_wdt_dev = NULL;
202 return ret; 95 return ret;
203 } 96 }
97
204 return 0; 98 return 0;
205} 99}
206 100
207static int twl4030_wdt_remove(struct platform_device *pdev) 101static int twl4030_wdt_remove(struct platform_device *pdev)
208{ 102{
209 struct twl4030_wdt *wdt = platform_get_drvdata(pdev); 103 struct watchdog_device *wdt = platform_get_drvdata(pdev);
210
211 if (wdt->state & TWL4030_WDT_STATE_ACTIVE)
212 if (twl4030_wdt_disable(wdt))
213 return -EFAULT;
214
215 wdt->state &= ~TWL4030_WDT_STATE_ACTIVE;
216 misc_deregister(&wdt->miscdev);
217 104
105 watchdog_unregister_device(wdt);
218 platform_set_drvdata(pdev, NULL); 106 platform_set_drvdata(pdev, NULL);
219 kfree(wdt);
220 twl4030_wdt_dev = NULL;
221 107
222 return 0; 108 return 0;
223} 109}
@@ -225,18 +111,18 @@ static int twl4030_wdt_remove(struct platform_device *pdev)
225#ifdef CONFIG_PM 111#ifdef CONFIG_PM
226static int twl4030_wdt_suspend(struct platform_device *pdev, pm_message_t state) 112static int twl4030_wdt_suspend(struct platform_device *pdev, pm_message_t state)
227{ 113{
228 struct twl4030_wdt *wdt = platform_get_drvdata(pdev); 114 struct watchdog_device *wdt = platform_get_drvdata(pdev);
229 if (wdt->state & TWL4030_WDT_STATE_ACTIVE) 115 if (watchdog_active(wdt))
230 return twl4030_wdt_disable(wdt); 116 return twl4030_wdt_stop(wdt);
231 117
232 return 0; 118 return 0;
233} 119}
234 120
235static int twl4030_wdt_resume(struct platform_device *pdev) 121static int twl4030_wdt_resume(struct platform_device *pdev)
236{ 122{
237 struct twl4030_wdt *wdt = platform_get_drvdata(pdev); 123 struct watchdog_device *wdt = platform_get_drvdata(pdev);
238 if (wdt->state & TWL4030_WDT_STATE_ACTIVE) 124 if (watchdog_active(wdt))
239 return twl4030_wdt_enable(wdt); 125 return twl4030_wdt_start(wdt);
240 126
241 return 0; 127 return 0;
242} 128}
@@ -260,6 +146,5 @@ module_platform_driver(twl4030_wdt_driver);
260 146
261MODULE_AUTHOR("Nokia Corporation"); 147MODULE_AUTHOR("Nokia Corporation");
262MODULE_LICENSE("GPL"); 148MODULE_LICENSE("GPL");
263MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
264MODULE_ALIAS("platform:twl4030_wdt"); 149MODULE_ALIAS("platform:twl4030_wdt");
265 150