aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/char/watchdog/mv64x60_wdt.c38
1 files changed, 31 insertions, 7 deletions
diff --git a/drivers/char/watchdog/mv64x60_wdt.c b/drivers/char/watchdog/mv64x60_wdt.c
index 420c7b82f4ca..e990e3af8be4 100644
--- a/drivers/char/watchdog/mv64x60_wdt.c
+++ b/drivers/char/watchdog/mv64x60_wdt.c
@@ -43,6 +43,7 @@ static unsigned long wdt_flags;
43static int wdt_status; 43static int wdt_status;
44static void __iomem *mv64x60_wdt_regs; 44static void __iomem *mv64x60_wdt_regs;
45static int mv64x60_wdt_timeout; 45static int mv64x60_wdt_timeout;
46static unsigned int bus_clk;
46 47
47static void mv64x60_wdt_reg_write(u32 val) 48static void mv64x60_wdt_reg_write(u32 val)
48{ 49{
@@ -82,6 +83,18 @@ static void mv64x60_wdt_handler_enable(void)
82 } 83 }
83} 84}
84 85
86static void mv64x60_wdt_set_timeout(int timeout)
87{
88 /* maximum bus cycle count is 0xFFFFFFFF */
89 if (timeout > 0xFFFFFFFF / bus_clk)
90 timeout = 0xFFFFFFFF / bus_clk;
91
92 mv64x60_wdt_timeout = timeout;
93 writel((timeout * bus_clk) >> 8,
94 mv64x60_wdt_regs + MV64x60_WDT_WDC_OFFSET);
95 mv64x60_wdt_service();
96}
97
85static int mv64x60_wdt_open(struct inode *inode, struct file *file) 98static int mv64x60_wdt_open(struct inode *inode, struct file *file)
86{ 99{
87 if (test_and_set_bit(MV64x60_WDOG_FLAG_OPENED, &wdt_flags)) 100 if (test_and_set_bit(MV64x60_WDOG_FLAG_OPENED, &wdt_flags))
@@ -118,9 +131,11 @@ static ssize_t mv64x60_wdt_write(struct file *file, const char __user *data,
118static int mv64x60_wdt_ioctl(struct inode *inode, struct file *file, 131static int mv64x60_wdt_ioctl(struct inode *inode, struct file *file,
119 unsigned int cmd, unsigned long arg) 132 unsigned int cmd, unsigned long arg)
120{ 133{
134 int timeout;
121 void __user *argp = (void __user *)arg; 135 void __user *argp = (void __user *)arg;
122 static struct watchdog_info info = { 136 static struct watchdog_info info = {
123 .options = WDIOF_KEEPALIVEPING, 137 .options = WDIOF_SETTIMEOUT |
138 WDIOF_KEEPALIVEPING,
124 .firmware_version = 0, 139 .firmware_version = 0,
125 .identity = "MV64x60 watchdog", 140 .identity = "MV64x60 watchdog",
126 }; 141 };
@@ -150,7 +165,10 @@ static int mv64x60_wdt_ioctl(struct inode *inode, struct file *file,
150 break; 165 break;
151 166
152 case WDIOC_SETTIMEOUT: 167 case WDIOC_SETTIMEOUT:
153 return -EOPNOTSUPP; 168 if (get_user(timeout, (int __user *)argp))
169 return -EFAULT;
170 mv64x60_wdt_set_timeout(timeout);
171 /* Fall through */
154 172
155 case WDIOC_GETTIMEOUT: 173 case WDIOC_GETTIMEOUT:
156 if (put_user(mv64x60_wdt_timeout, (int __user *)argp)) 174 if (put_user(mv64x60_wdt_timeout, (int __user *)argp))
@@ -182,15 +200,22 @@ static struct miscdevice mv64x60_wdt_miscdev = {
182static int __devinit mv64x60_wdt_probe(struct platform_device *dev) 200static int __devinit mv64x60_wdt_probe(struct platform_device *dev)
183{ 201{
184 struct mv64x60_wdt_pdata *pdata = dev->dev.platform_data; 202 struct mv64x60_wdt_pdata *pdata = dev->dev.platform_data;
185 int bus_clk = 133;
186 struct resource *r; 203 struct resource *r;
204 int timeout = 10;
187 205
188 mv64x60_wdt_timeout = 10; 206 bus_clk = 133; /* in MHz */
189 if (pdata) { 207 if (pdata) {
190 mv64x60_wdt_timeout = pdata->timeout; 208 timeout = pdata->timeout;
191 bus_clk = pdata->bus_clk; 209 bus_clk = pdata->bus_clk;
192 } 210 }
193 211
212 /* Since bus_clk is truncated MHz, actual frequency could be
213 * up to 1MHz higher. Round up, since it's better to time out
214 * too late than too soon.
215 */
216 bus_clk++;
217 bus_clk *= 1000000; /* convert to Hz */
218
194 r = platform_get_resource(dev, IORESOURCE_MEM, 0); 219 r = platform_get_resource(dev, IORESOURCE_MEM, 0);
195 if (!r) 220 if (!r)
196 return -ENODEV; 221 return -ENODEV;
@@ -199,8 +224,7 @@ static int __devinit mv64x60_wdt_probe(struct platform_device *dev)
199 if (mv64x60_wdt_regs == NULL) 224 if (mv64x60_wdt_regs == NULL)
200 return -ENOMEM; 225 return -ENOMEM;
201 226
202 writel((mv64x60_wdt_timeout * (bus_clk * 1000000)) >> 8, 227 mv64x60_wdt_set_timeout(timeout);
203 mv64x60_wdt_regs + MV64x60_WDT_WDC_OFFSET);
204 228
205 return misc_register(&mv64x60_wdt_miscdev); 229 return misc_register(&mv64x60_wdt_miscdev);
206} 230}