1 /* 2 * drivers/char/watchdog/davinci_wdt.c 3 * 4 * Watchdog driver for DaVinci DM644x/DM646x processors 5 * 6 * Copyright (C) 2006-2013 Texas Instruments. 7 * 8 * 2007 (c) MontaVista Software, Inc. This file is licensed under 9 * the terms of the GNU General Public License version 2. This program 10 * is licensed "as is" without any warranty of any kind, whether express 11 * or implied. 12 */ 13 14 #include <linux/module.h> 15 #include <linux/moduleparam.h> 16 #include <linux/types.h> 17 #include <linux/kernel.h> 18 #include <linux/watchdog.h> 19 #include <linux/init.h> 20 #include <linux/platform_device.h> 21 #include <linux/io.h> 22 #include <linux/device.h> 23 #include <linux/clk.h> 24 #include <linux/err.h> 25 26 #define MODULE_NAME "DAVINCI-WDT: " 27 28 #define DEFAULT_HEARTBEAT 60 29 #define MAX_HEARTBEAT 600 /* really the max margin is 264/27MHz*/ 30 31 /* Timer register set definition */ 32 #define PID12 (0x0) 33 #define EMUMGT (0x4) 34 #define TIM12 (0x10) 35 #define TIM34 (0x14) 36 #define PRD12 (0x18) 37 #define PRD34 (0x1C) 38 #define TCR (0x20) 39 #define TGCR (0x24) 40 #define WDTCR (0x28) 41 42 /* TCR bit definitions */ 43 #define ENAMODE12_DISABLED (0 << 6) 44 #define ENAMODE12_ONESHOT (1 << 6) 45 #define ENAMODE12_PERIODIC (2 << 6) 46 47 /* TGCR bit definitions */ 48 #define TIM12RS_UNRESET (1 << 0) 49 #define TIM34RS_UNRESET (1 << 1) 50 #define TIMMODE_64BIT_WDOG (2 << 2) 51 52 /* WDTCR bit definitions */ 53 #define WDEN (1 << 14) 54 #define WDFLAG (1 << 15) 55 #define WDKEY_SEQ0 (0xa5c6 << 16) 56 #define WDKEY_SEQ1 (0xda7e << 16) 57 58 static int heartbeat; 59 60 /* 61 * struct to hold data for each WDT device 62 * @base - base io address of WD device 63 * @clk - source clock of WDT 64 * @wdd - hold watchdog device as is in WDT core 65 */ 66 struct davinci_wdt_device { 67 void __iomem *base; 68 struct clk *clk; 69 struct watchdog_device wdd; 70 }; 71 72 static int davinci_wdt_start(struct watchdog_device *wdd) 73 { 74 u32 tgcr; 75 u32 timer_margin; 76 unsigned long wdt_freq; 77 struct davinci_wdt_device *davinci_wdt = watchdog_get_drvdata(wdd); 78 79 wdt_freq = clk_get_rate(davinci_wdt->clk); 80 81 /* disable, internal clock source */ 82 iowrite32(0, davinci_wdt->base + TCR); 83 /* reset timer, set mode to 64-bit watchdog, and unreset */ 84 iowrite32(0, davinci_wdt->base + TGCR); 85 tgcr = TIMMODE_64BIT_WDOG | TIM12RS_UNRESET | TIM34RS_UNRESET; 86 iowrite32(tgcr, davinci_wdt->base + TGCR); 87 /* clear counter regs */ 88 iowrite32(0, davinci_wdt->base + TIM12); 89 iowrite32(0, davinci_wdt->base + TIM34); 90 /* set timeout period */ 91 timer_margin = (((u64)wdd->timeout * wdt_freq) & 0xffffffff); 92 iowrite32(timer_margin, davinci_wdt->base + PRD12); 93 timer_margin = (((u64)wdd->timeout * wdt_freq) >> 32); 94 iowrite32(timer_margin, davinci_wdt->base + PRD34); 95 /* enable run continuously */ 96 iowrite32(ENAMODE12_PERIODIC, davinci_wdt->base + TCR); 97 /* Once the WDT is in pre-active state write to 98 * TIM12, TIM34, PRD12, PRD34, TCR, TGCR, WDTCR are 99 * write protected (except for the WDKEY field) 100 */ 101 /* put watchdog in pre-active state */ 102 iowrite32(WDKEY_SEQ0 | WDEN, davinci_wdt->base + WDTCR); 103 /* put watchdog in active state */ 104 iowrite32(WDKEY_SEQ1 | WDEN, davinci_wdt->base + WDTCR); 105 return 0; 106 } 107 108 static int davinci_wdt_ping(struct watchdog_device *wdd) 109 { 110 struct davinci_wdt_device *davinci_wdt = watchdog_get_drvdata(wdd); 111 112 /* put watchdog in service state */ 113 iowrite32(WDKEY_SEQ0, davinci_wdt->base + WDTCR); 114 /* put watchdog in active state */ 115 iowrite32(WDKEY_SEQ1, davinci_wdt->base + WDTCR); 116 return 0; 117 } 118 119 static unsigned int davinci_wdt_get_timeleft(struct watchdog_device *wdd) 120 { 121 u64 timer_counter; 122 unsigned long freq; 123 u32 val; 124 struct davinci_wdt_device *davinci_wdt = watchdog_get_drvdata(wdd); 125 126 /* if timeout has occured then return 0 */ 127 val = ioread32(davinci_wdt->base + WDTCR); 128 if (val & WDFLAG) 129 return 0; 130 131 freq = clk_get_rate(davinci_wdt->clk); 132 133 if (!freq) 134 return 0; 135 136 timer_counter = ioread32(davinci_wdt->base + TIM12); 137 timer_counter |= ((u64)ioread32(davinci_wdt->base + TIM34) << 32); 138 139 do_div(timer_counter, freq); 140 141 return wdd->timeout - timer_counter; 142 } 143 144 static const struct watchdog_info davinci_wdt_info = { 145 .options = WDIOF_KEEPALIVEPING, 146 .identity = "DaVinci/Keystone Watchdog", 147 }; 148 149 static const struct watchdog_ops davinci_wdt_ops = { 150 .owner = THIS_MODULE, 151 .start = davinci_wdt_start, 152 .stop = davinci_wdt_ping, 153 .ping = davinci_wdt_ping, 154 .get_timeleft = davinci_wdt_get_timeleft, 155 }; 156 157 static int davinci_wdt_probe(struct platform_device *pdev) 158 { 159 int ret = 0; 160 struct device *dev = &pdev->dev; 161 struct resource *wdt_mem; 162 struct watchdog_device *wdd; 163 struct davinci_wdt_device *davinci_wdt; 164 165 davinci_wdt = devm_kzalloc(dev, sizeof(*davinci_wdt), GFP_KERNEL); 166 if (!davinci_wdt) 167 return -ENOMEM; 168 169 davinci_wdt->clk = devm_clk_get(dev, NULL); 170 if (WARN_ON(IS_ERR(davinci_wdt->clk))) 171 return PTR_ERR(davinci_wdt->clk); 172 173 clk_prepare_enable(davinci_wdt->clk); 174 175 platform_set_drvdata(pdev, davinci_wdt); 176 177 wdd = &davinci_wdt->wdd; 178 wdd->info = &davinci_wdt_info; 179 wdd->ops = &davinci_wdt_ops; 180 wdd->min_timeout = 1; 181 wdd->max_timeout = MAX_HEARTBEAT; 182 wdd->timeout = DEFAULT_HEARTBEAT; 183 184 watchdog_init_timeout(wdd, heartbeat, dev); 185 186 dev_info(dev, "heartbeat %d sec\n", wdd->timeout); 187 188 watchdog_set_drvdata(wdd, davinci_wdt); 189 watchdog_set_nowayout(wdd, 1); 190 191 wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 192 davinci_wdt->base = devm_ioremap_resource(dev, wdt_mem); 193 if (IS_ERR(davinci_wdt->base)) 194 return PTR_ERR(davinci_wdt->base); 195 196 ret = watchdog_register_device(wdd); 197 if (ret < 0) 198 dev_err(dev, "cannot register watchdog device\n"); 199 200 return ret; 201 } 202 203 static int davinci_wdt_remove(struct platform_device *pdev) 204 { 205 struct davinci_wdt_device *davinci_wdt = platform_get_drvdata(pdev); 206 207 watchdog_unregister_device(&davinci_wdt->wdd); 208 clk_disable_unprepare(davinci_wdt->clk); 209 210 return 0; 211 } 212 213 static const struct of_device_id davinci_wdt_of_match[] = { 214 { .compatible = "ti,davinci-wdt", }, 215 {}, 216 }; 217 MODULE_DEVICE_TABLE(of, davinci_wdt_of_match); 218 219 static struct platform_driver platform_wdt_driver = { 220 .driver = { 221 .name = "davinci-wdt", 222 .owner = THIS_MODULE, 223 .of_match_table = davinci_wdt_of_match, 224 }, 225 .probe = davinci_wdt_probe, 226 .remove = davinci_wdt_remove, 227 }; 228 229 module_platform_driver(platform_wdt_driver); 230 231 MODULE_AUTHOR("Texas Instruments"); 232 MODULE_DESCRIPTION("DaVinci Watchdog Driver"); 233 234 module_param(heartbeat, int, 0); 235 MODULE_PARM_DESC(heartbeat, 236 "Watchdog heartbeat period in seconds from 1 to " 237 __MODULE_STRING(MAX_HEARTBEAT) ", default " 238 __MODULE_STRING(DEFAULT_HEARTBEAT)); 239 240 MODULE_LICENSE("GPL"); 241 MODULE_ALIAS("platform:davinci-wdt"); 242