diff options
-rw-r--r-- | drivers/char/watchdog/mv64x60_wdt.c | 38 |
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; | |||
43 | static int wdt_status; | 43 | static int wdt_status; |
44 | static void __iomem *mv64x60_wdt_regs; | 44 | static void __iomem *mv64x60_wdt_regs; |
45 | static int mv64x60_wdt_timeout; | 45 | static int mv64x60_wdt_timeout; |
46 | static unsigned int bus_clk; | ||
46 | 47 | ||
47 | static void mv64x60_wdt_reg_write(u32 val) | 48 | static 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 | ||
86 | static 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 | |||
85 | static int mv64x60_wdt_open(struct inode *inode, struct file *file) | 98 | static 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, | |||
118 | static int mv64x60_wdt_ioctl(struct inode *inode, struct file *file, | 131 | static 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 = { | |||
182 | static int __devinit mv64x60_wdt_probe(struct platform_device *dev) | 200 | static 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 | } |