Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.12-rc5 423 lines 12 kB view raw
1/* 2 * coh901327_wdt.c 3 * 4 * Copyright (C) 2008-2009 ST-Ericsson AB 5 * License terms: GNU General Public License (GPL) version 2 6 * Watchdog driver for the ST-Ericsson AB COH 901 327 IP core 7 * Author: Linus Walleij <linus.walleij@stericsson.com> 8 */ 9#include <linux/module.h> 10#include <linux/types.h> 11#include <linux/watchdog.h> 12#include <linux/interrupt.h> 13#include <linux/pm.h> 14#include <linux/platform_device.h> 15#include <linux/io.h> 16#include <linux/bitops.h> 17#include <linux/clk.h> 18#include <linux/delay.h> 19#include <linux/err.h> 20 21#define DRV_NAME "WDOG COH 901 327" 22 23/* 24 * COH 901 327 register definitions 25 */ 26 27/* WDOG_FEED Register 32bit (-/W) */ 28#define U300_WDOG_FR 0x00 29#define U300_WDOG_FR_FEED_RESTART_TIMER 0xFEEDU 30/* WDOG_TIMEOUT Register 32bit (R/W) */ 31#define U300_WDOG_TR 0x04 32#define U300_WDOG_TR_TIMEOUT_MASK 0x7FFFU 33/* WDOG_DISABLE1 Register 32bit (-/W) */ 34#define U300_WDOG_D1R 0x08 35#define U300_WDOG_D1R_DISABLE1_DISABLE_TIMER 0x2BADU 36/* WDOG_DISABLE2 Register 32bit (R/W) */ 37#define U300_WDOG_D2R 0x0C 38#define U300_WDOG_D2R_DISABLE2_DISABLE_TIMER 0xCAFEU 39#define U300_WDOG_D2R_DISABLE_STATUS_DISABLED 0xDABEU 40#define U300_WDOG_D2R_DISABLE_STATUS_ENABLED 0x0000U 41/* WDOG_STATUS Register 32bit (R/W) */ 42#define U300_WDOG_SR 0x10 43#define U300_WDOG_SR_STATUS_TIMED_OUT 0xCFE8U 44#define U300_WDOG_SR_STATUS_NORMAL 0x0000U 45#define U300_WDOG_SR_RESET_STATUS_RESET 0xE8B4U 46/* WDOG_COUNT Register 32bit (R/-) */ 47#define U300_WDOG_CR 0x14 48#define U300_WDOG_CR_VALID_IND 0x8000U 49#define U300_WDOG_CR_VALID_STABLE 0x0000U 50#define U300_WDOG_CR_COUNT_VALUE_MASK 0x7FFFU 51/* WDOG_JTAGOVR Register 32bit (R/W) */ 52#define U300_WDOG_JOR 0x18 53#define U300_WDOG_JOR_JTAG_MODE_IND 0x0002U 54#define U300_WDOG_JOR_JTAG_WATCHDOG_ENABLE 0x0001U 55/* WDOG_RESTART Register 32bit (-/W) */ 56#define U300_WDOG_RR 0x1C 57#define U300_WDOG_RR_RESTART_VALUE_RESUME 0xACEDU 58/* WDOG_IRQ_EVENT Register 32bit (R/W) */ 59#define U300_WDOG_IER 0x20 60#define U300_WDOG_IER_WILL_BARK_IRQ_EVENT_IND 0x0001U 61#define U300_WDOG_IER_WILL_BARK_IRQ_ACK_ENABLE 0x0001U 62/* WDOG_IRQ_MASK Register 32bit (R/W) */ 63#define U300_WDOG_IMR 0x24 64#define U300_WDOG_IMR_WILL_BARK_IRQ_ENABLE 0x0001U 65/* WDOG_IRQ_FORCE Register 32bit (R/W) */ 66#define U300_WDOG_IFR 0x28 67#define U300_WDOG_IFR_WILL_BARK_IRQ_FORCE_ENABLE 0x0001U 68 69/* Default timeout in seconds = 1 minute */ 70static unsigned int margin = 60; 71static int irq; 72static void __iomem *virtbase; 73static struct device *parent; 74 75static struct clk *clk; 76 77/* 78 * Enabling and disabling functions. 79 */ 80static void coh901327_enable(u16 timeout) 81{ 82 u16 val; 83 unsigned long freq; 84 unsigned long delay_ns; 85 86 /* Restart timer if it is disabled */ 87 val = readw(virtbase + U300_WDOG_D2R); 88 if (val == U300_WDOG_D2R_DISABLE_STATUS_DISABLED) 89 writew(U300_WDOG_RR_RESTART_VALUE_RESUME, 90 virtbase + U300_WDOG_RR); 91 /* Acknowledge any pending interrupt so it doesn't just fire off */ 92 writew(U300_WDOG_IER_WILL_BARK_IRQ_ACK_ENABLE, 93 virtbase + U300_WDOG_IER); 94 /* 95 * The interrupt is cleared in the 32 kHz clock domain. 96 * Wait 3 32 kHz cycles for it to take effect 97 */ 98 freq = clk_get_rate(clk); 99 delay_ns = DIV_ROUND_UP(1000000000, freq); /* Freq to ns and round up */ 100 delay_ns = 3 * delay_ns; /* Wait 3 cycles */ 101 ndelay(delay_ns); 102 /* Enable the watchdog interrupt */ 103 writew(U300_WDOG_IMR_WILL_BARK_IRQ_ENABLE, virtbase + U300_WDOG_IMR); 104 /* Activate the watchdog timer */ 105 writew(timeout, virtbase + U300_WDOG_TR); 106 /* Start the watchdog timer */ 107 writew(U300_WDOG_FR_FEED_RESTART_TIMER, virtbase + U300_WDOG_FR); 108 /* 109 * Extra read so that this change propagate in the watchdog. 110 */ 111 (void) readw(virtbase + U300_WDOG_CR); 112 val = readw(virtbase + U300_WDOG_D2R); 113 if (val != U300_WDOG_D2R_DISABLE_STATUS_ENABLED) 114 dev_err(parent, 115 "%s(): watchdog not enabled! D2R value %04x\n", 116 __func__, val); 117} 118 119static void coh901327_disable(void) 120{ 121 u16 val; 122 123 /* Disable the watchdog interrupt if it is active */ 124 writew(0x0000U, virtbase + U300_WDOG_IMR); 125 /* If the watchdog is currently enabled, attempt to disable it */ 126 val = readw(virtbase + U300_WDOG_D2R); 127 if (val != U300_WDOG_D2R_DISABLE_STATUS_DISABLED) { 128 writew(U300_WDOG_D1R_DISABLE1_DISABLE_TIMER, 129 virtbase + U300_WDOG_D1R); 130 writew(U300_WDOG_D2R_DISABLE2_DISABLE_TIMER, 131 virtbase + U300_WDOG_D2R); 132 /* Write this twice (else problems occur) */ 133 writew(U300_WDOG_D2R_DISABLE2_DISABLE_TIMER, 134 virtbase + U300_WDOG_D2R); 135 } 136 val = readw(virtbase + U300_WDOG_D2R); 137 if (val != U300_WDOG_D2R_DISABLE_STATUS_DISABLED) 138 dev_err(parent, 139 "%s(): watchdog not disabled! D2R value %04x\n", 140 __func__, val); 141} 142 143static int coh901327_start(struct watchdog_device *wdt_dev) 144{ 145 coh901327_enable(wdt_dev->timeout * 100); 146 return 0; 147} 148 149static int coh901327_stop(struct watchdog_device *wdt_dev) 150{ 151 coh901327_disable(); 152 return 0; 153} 154 155static int coh901327_ping(struct watchdog_device *wdd) 156{ 157 /* Feed the watchdog */ 158 writew(U300_WDOG_FR_FEED_RESTART_TIMER, 159 virtbase + U300_WDOG_FR); 160 return 0; 161} 162 163static int coh901327_settimeout(struct watchdog_device *wdt_dev, 164 unsigned int time) 165{ 166 wdt_dev->timeout = time; 167 /* Set new timeout value */ 168 writew(time * 100, virtbase + U300_WDOG_TR); 169 /* Feed the dog */ 170 writew(U300_WDOG_FR_FEED_RESTART_TIMER, 171 virtbase + U300_WDOG_FR); 172 return 0; 173} 174 175static unsigned int coh901327_gettimeleft(struct watchdog_device *wdt_dev) 176{ 177 u16 val; 178 179 /* Read repeatedly until the value is stable! */ 180 val = readw(virtbase + U300_WDOG_CR); 181 while (val & U300_WDOG_CR_VALID_IND) 182 val = readw(virtbase + U300_WDOG_CR); 183 val &= U300_WDOG_CR_COUNT_VALUE_MASK; 184 if (val != 0) 185 val /= 100; 186 187 return val; 188} 189 190/* 191 * This interrupt occurs 10 ms before the watchdog WILL bark. 192 */ 193static irqreturn_t coh901327_interrupt(int irq, void *data) 194{ 195 u16 val; 196 197 /* 198 * Ack IRQ? If this occurs we're FUBAR anyway, so 199 * just acknowledge, disable the interrupt and await the imminent end. 200 * If you at some point need a host of callbacks to be called 201 * when the system is about to watchdog-reset, add them here! 202 * 203 * NOTE: on future versions of this IP-block, it will be possible 204 * to prevent a watchdog reset by feeding the watchdog at this 205 * point. 206 */ 207 val = readw(virtbase + U300_WDOG_IER); 208 if (val == U300_WDOG_IER_WILL_BARK_IRQ_EVENT_IND) 209 writew(U300_WDOG_IER_WILL_BARK_IRQ_ACK_ENABLE, 210 virtbase + U300_WDOG_IER); 211 writew(0x0000U, virtbase + U300_WDOG_IMR); 212 dev_crit(parent, "watchdog is barking!\n"); 213 return IRQ_HANDLED; 214} 215 216static const struct watchdog_info coh901327_ident = { 217 .options = WDIOF_CARDRESET | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, 218 .identity = DRV_NAME, 219}; 220 221static struct watchdog_ops coh901327_ops = { 222 .owner = THIS_MODULE, 223 .start = coh901327_start, 224 .stop = coh901327_stop, 225 .ping = coh901327_ping, 226 .set_timeout = coh901327_settimeout, 227 .get_timeleft = coh901327_gettimeleft, 228}; 229 230static struct watchdog_device coh901327_wdt = { 231 .info = &coh901327_ident, 232 .ops = &coh901327_ops, 233 /* 234 * Max timeout is 327 since the 10ms 235 * timeout register is max 236 * 0x7FFF = 327670ms ~= 327s. 237 */ 238 .min_timeout = 0, 239 .max_timeout = 327, 240}; 241 242static int __exit coh901327_remove(struct platform_device *pdev) 243{ 244 watchdog_unregister_device(&coh901327_wdt); 245 coh901327_disable(); 246 free_irq(irq, pdev); 247 clk_disable_unprepare(clk); 248 clk_put(clk); 249 return 0; 250} 251 252static int __init coh901327_probe(struct platform_device *pdev) 253{ 254 struct device *dev = &pdev->dev; 255 int ret; 256 u16 val; 257 struct resource *res; 258 259 parent = dev; 260 261 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 262 virtbase = devm_ioremap_resource(dev, res); 263 if (IS_ERR(virtbase)) 264 return PTR_ERR(virtbase); 265 266 clk = clk_get(dev, NULL); 267 if (IS_ERR(clk)) { 268 ret = PTR_ERR(clk); 269 dev_err(dev, "could not get clock\n"); 270 return ret; 271 } 272 ret = clk_prepare_enable(clk); 273 if (ret) { 274 dev_err(dev, "could not prepare and enable clock\n"); 275 goto out_no_clk_enable; 276 } 277 278 val = readw(virtbase + U300_WDOG_SR); 279 switch (val) { 280 case U300_WDOG_SR_STATUS_TIMED_OUT: 281 dev_info(dev, "watchdog timed out since last chip reset!\n"); 282 coh901327_wdt.bootstatus |= WDIOF_CARDRESET; 283 /* Status will be cleared below */ 284 break; 285 case U300_WDOG_SR_STATUS_NORMAL: 286 dev_info(dev, "in normal status, no timeouts have occurred.\n"); 287 break; 288 default: 289 dev_info(dev, "contains an illegal status code (%08x)\n", val); 290 break; 291 } 292 293 val = readw(virtbase + U300_WDOG_D2R); 294 switch (val) { 295 case U300_WDOG_D2R_DISABLE_STATUS_DISABLED: 296 dev_info(dev, "currently disabled.\n"); 297 break; 298 case U300_WDOG_D2R_DISABLE_STATUS_ENABLED: 299 dev_info(dev, "currently enabled! (disabling it now)\n"); 300 coh901327_disable(); 301 break; 302 default: 303 dev_err(dev, "contains an illegal enable/disable code (%08x)\n", 304 val); 305 break; 306 } 307 308 /* Reset the watchdog */ 309 writew(U300_WDOG_SR_RESET_STATUS_RESET, virtbase + U300_WDOG_SR); 310 311 irq = platform_get_irq(pdev, 0); 312 if (request_irq(irq, coh901327_interrupt, 0, 313 DRV_NAME " Bark", pdev)) { 314 ret = -EIO; 315 goto out_no_irq; 316 } 317 318 ret = watchdog_init_timeout(&coh901327_wdt, margin, dev); 319 if (ret < 0) 320 coh901327_wdt.timeout = 60; 321 322 coh901327_wdt.parent = dev; 323 ret = watchdog_register_device(&coh901327_wdt); 324 if (ret) 325 goto out_no_wdog; 326 327 dev_info(dev, "initialized. timer margin=%d sec\n", margin); 328 return 0; 329 330out_no_wdog: 331 free_irq(irq, pdev); 332out_no_irq: 333 clk_disable_unprepare(clk); 334out_no_clk_enable: 335 clk_put(clk); 336 return ret; 337} 338 339#ifdef CONFIG_PM 340 341static u16 wdogenablestore; 342static u16 irqmaskstore; 343 344static int coh901327_suspend(struct platform_device *pdev, pm_message_t state) 345{ 346 irqmaskstore = readw(virtbase + U300_WDOG_IMR) & 0x0001U; 347 wdogenablestore = readw(virtbase + U300_WDOG_D2R); 348 /* If watchdog is on, disable it here and now */ 349 if (wdogenablestore == U300_WDOG_D2R_DISABLE_STATUS_ENABLED) 350 coh901327_disable(); 351 return 0; 352} 353 354static int coh901327_resume(struct platform_device *pdev) 355{ 356 /* Restore the watchdog interrupt */ 357 writew(irqmaskstore, virtbase + U300_WDOG_IMR); 358 if (wdogenablestore == U300_WDOG_D2R_DISABLE_STATUS_ENABLED) { 359 /* Restart the watchdog timer */ 360 writew(U300_WDOG_RR_RESTART_VALUE_RESUME, 361 virtbase + U300_WDOG_RR); 362 writew(U300_WDOG_FR_FEED_RESTART_TIMER, 363 virtbase + U300_WDOG_FR); 364 } 365 return 0; 366} 367#else 368#define coh901327_suspend NULL 369#define coh901327_resume NULL 370#endif 371 372/* 373 * Mistreating the watchdog is the only way to perform a software reset of the 374 * system on EMP platforms. So we implement this and export a symbol for it. 375 */ 376void coh901327_watchdog_reset(void) 377{ 378 /* Enable even if on JTAG too */ 379 writew(U300_WDOG_JOR_JTAG_WATCHDOG_ENABLE, 380 virtbase + U300_WDOG_JOR); 381 /* 382 * Timeout = 5s, we have to wait for the watchdog reset to 383 * actually take place: the watchdog will be reloaded with the 384 * default value immediately, so we HAVE to reboot and get back 385 * into the kernel in 30s, or the device will reboot again! 386 * The boot loader will typically deactivate the watchdog, so we 387 * need time enough for the boot loader to get to the point of 388 * deactivating the watchdog before it is shut down by it. 389 * 390 * NOTE: on future versions of the watchdog, this restriction is 391 * gone: the watchdog will be reloaded with a default value (1 min) 392 * instead of last value, and you can conveniently set the watchdog 393 * timeout to 10ms (value = 1) without any problems. 394 */ 395 coh901327_enable(500); 396 /* Return and await doom */ 397} 398 399static const struct of_device_id coh901327_dt_match[] = { 400 { .compatible = "stericsson,coh901327" }, 401 {}, 402}; 403 404static struct platform_driver coh901327_driver = { 405 .driver = { 406 .name = "coh901327_wdog", 407 .of_match_table = coh901327_dt_match, 408 }, 409 .remove = __exit_p(coh901327_remove), 410 .suspend = coh901327_suspend, 411 .resume = coh901327_resume, 412}; 413 414module_platform_driver_probe(coh901327_driver, coh901327_probe); 415 416MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>"); 417MODULE_DESCRIPTION("COH 901 327 Watchdog"); 418 419module_param(margin, uint, 0); 420MODULE_PARM_DESC(margin, "Watchdog margin in seconds (default 60s)"); 421 422MODULE_LICENSE("GPL"); 423MODULE_ALIAS("platform:coh901327-watchdog");