0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/module.h>
0013 #include <linux/moduleparam.h>
0014 #include <linux/mod_devicetable.h>
0015 #include <linux/types.h>
0016 #include <linux/kernel.h>
0017 #include <linux/watchdog.h>
0018 #include <linux/platform_device.h>
0019 #include <linux/io.h>
0020 #include <linux/device.h>
0021 #include <linux/clk.h>
0022 #include <linux/err.h>
0023
0024 #define MODULE_NAME "DAVINCI-WDT: "
0025
0026 #define DEFAULT_HEARTBEAT 60
0027 #define MAX_HEARTBEAT 600
0028
0029
0030 #define PID12 (0x0)
0031 #define EMUMGT (0x4)
0032 #define TIM12 (0x10)
0033 #define TIM34 (0x14)
0034 #define PRD12 (0x18)
0035 #define PRD34 (0x1C)
0036 #define TCR (0x20)
0037 #define TGCR (0x24)
0038 #define WDTCR (0x28)
0039
0040
0041 #define ENAMODE12_DISABLED (0 << 6)
0042 #define ENAMODE12_ONESHOT (1 << 6)
0043 #define ENAMODE12_PERIODIC (2 << 6)
0044
0045
0046 #define TIM12RS_UNRESET (1 << 0)
0047 #define TIM34RS_UNRESET (1 << 1)
0048 #define TIMMODE_64BIT_WDOG (2 << 2)
0049
0050
0051 #define WDEN (1 << 14)
0052 #define WDFLAG (1 << 15)
0053 #define WDKEY_SEQ0 (0xa5c6 << 16)
0054 #define WDKEY_SEQ1 (0xda7e << 16)
0055
0056 static int heartbeat;
0057
0058
0059
0060
0061
0062
0063
0064 struct davinci_wdt_device {
0065 void __iomem *base;
0066 struct clk *clk;
0067 struct watchdog_device wdd;
0068 };
0069
0070 static int davinci_wdt_start(struct watchdog_device *wdd)
0071 {
0072 u32 tgcr;
0073 u32 timer_margin;
0074 unsigned long wdt_freq;
0075 struct davinci_wdt_device *davinci_wdt = watchdog_get_drvdata(wdd);
0076
0077 wdt_freq = clk_get_rate(davinci_wdt->clk);
0078
0079
0080 iowrite32(0, davinci_wdt->base + TCR);
0081
0082 iowrite32(0, davinci_wdt->base + TGCR);
0083 tgcr = TIMMODE_64BIT_WDOG | TIM12RS_UNRESET | TIM34RS_UNRESET;
0084 iowrite32(tgcr, davinci_wdt->base + TGCR);
0085
0086 iowrite32(0, davinci_wdt->base + TIM12);
0087 iowrite32(0, davinci_wdt->base + TIM34);
0088
0089 timer_margin = (((u64)wdd->timeout * wdt_freq) & 0xffffffff);
0090 iowrite32(timer_margin, davinci_wdt->base + PRD12);
0091 timer_margin = (((u64)wdd->timeout * wdt_freq) >> 32);
0092 iowrite32(timer_margin, davinci_wdt->base + PRD34);
0093
0094 iowrite32(ENAMODE12_PERIODIC, davinci_wdt->base + TCR);
0095
0096
0097
0098
0099
0100 iowrite32(WDKEY_SEQ0 | WDEN, davinci_wdt->base + WDTCR);
0101
0102 iowrite32(WDKEY_SEQ1 | WDEN, davinci_wdt->base + WDTCR);
0103 return 0;
0104 }
0105
0106 static int davinci_wdt_ping(struct watchdog_device *wdd)
0107 {
0108 struct davinci_wdt_device *davinci_wdt = watchdog_get_drvdata(wdd);
0109
0110
0111 iowrite32(WDKEY_SEQ0, davinci_wdt->base + WDTCR);
0112
0113 iowrite32(WDKEY_SEQ1, davinci_wdt->base + WDTCR);
0114 return 0;
0115 }
0116
0117 static unsigned int davinci_wdt_get_timeleft(struct watchdog_device *wdd)
0118 {
0119 u64 timer_counter;
0120 unsigned long freq;
0121 u32 val;
0122 struct davinci_wdt_device *davinci_wdt = watchdog_get_drvdata(wdd);
0123
0124
0125 val = ioread32(davinci_wdt->base + WDTCR);
0126 if (val & WDFLAG)
0127 return 0;
0128
0129 freq = clk_get_rate(davinci_wdt->clk);
0130
0131 if (!freq)
0132 return 0;
0133
0134 timer_counter = ioread32(davinci_wdt->base + TIM12);
0135 timer_counter |= ((u64)ioread32(davinci_wdt->base + TIM34) << 32);
0136
0137 timer_counter = div64_ul(timer_counter, freq);
0138
0139 return wdd->timeout - timer_counter;
0140 }
0141
0142 static int davinci_wdt_restart(struct watchdog_device *wdd,
0143 unsigned long action, void *data)
0144 {
0145 struct davinci_wdt_device *davinci_wdt = watchdog_get_drvdata(wdd);
0146 u32 tgcr, wdtcr;
0147
0148
0149 iowrite32(0, davinci_wdt->base + TCR);
0150
0151
0152 tgcr = 0;
0153 iowrite32(tgcr, davinci_wdt->base + TGCR);
0154 tgcr = TIMMODE_64BIT_WDOG | TIM12RS_UNRESET | TIM34RS_UNRESET;
0155 iowrite32(tgcr, davinci_wdt->base + TGCR);
0156
0157
0158 iowrite32(0, davinci_wdt->base + TIM12);
0159 iowrite32(0, davinci_wdt->base + TIM34);
0160 iowrite32(0, davinci_wdt->base + PRD12);
0161 iowrite32(0, davinci_wdt->base + PRD34);
0162
0163
0164 wdtcr = WDKEY_SEQ0 | WDEN;
0165 iowrite32(wdtcr, davinci_wdt->base + WDTCR);
0166
0167
0168 wdtcr = WDKEY_SEQ1 | WDEN;
0169 iowrite32(wdtcr, davinci_wdt->base + WDTCR);
0170
0171
0172 wdtcr = 0x00004000;
0173 iowrite32(wdtcr, davinci_wdt->base + WDTCR);
0174
0175 return 0;
0176 }
0177
0178 static const struct watchdog_info davinci_wdt_info = {
0179 .options = WDIOF_KEEPALIVEPING,
0180 .identity = "DaVinci/Keystone Watchdog",
0181 };
0182
0183 static const struct watchdog_ops davinci_wdt_ops = {
0184 .owner = THIS_MODULE,
0185 .start = davinci_wdt_start,
0186 .stop = davinci_wdt_ping,
0187 .ping = davinci_wdt_ping,
0188 .get_timeleft = davinci_wdt_get_timeleft,
0189 .restart = davinci_wdt_restart,
0190 };
0191
0192 static void davinci_clk_disable_unprepare(void *data)
0193 {
0194 clk_disable_unprepare(data);
0195 }
0196
0197 static int davinci_wdt_probe(struct platform_device *pdev)
0198 {
0199 int ret = 0;
0200 struct device *dev = &pdev->dev;
0201 struct watchdog_device *wdd;
0202 struct davinci_wdt_device *davinci_wdt;
0203
0204 davinci_wdt = devm_kzalloc(dev, sizeof(*davinci_wdt), GFP_KERNEL);
0205 if (!davinci_wdt)
0206 return -ENOMEM;
0207
0208 davinci_wdt->clk = devm_clk_get(dev, NULL);
0209 if (IS_ERR(davinci_wdt->clk))
0210 return dev_err_probe(dev, PTR_ERR(davinci_wdt->clk),
0211 "failed to get clock node\n");
0212
0213 ret = clk_prepare_enable(davinci_wdt->clk);
0214 if (ret) {
0215 dev_err(dev, "failed to prepare clock\n");
0216 return ret;
0217 }
0218 ret = devm_add_action_or_reset(dev, davinci_clk_disable_unprepare,
0219 davinci_wdt->clk);
0220 if (ret)
0221 return ret;
0222
0223 platform_set_drvdata(pdev, davinci_wdt);
0224
0225 wdd = &davinci_wdt->wdd;
0226 wdd->info = &davinci_wdt_info;
0227 wdd->ops = &davinci_wdt_ops;
0228 wdd->min_timeout = 1;
0229 wdd->max_timeout = MAX_HEARTBEAT;
0230 wdd->timeout = DEFAULT_HEARTBEAT;
0231 wdd->parent = dev;
0232
0233 watchdog_init_timeout(wdd, heartbeat, dev);
0234
0235 dev_info(dev, "heartbeat %d sec\n", wdd->timeout);
0236
0237 watchdog_set_drvdata(wdd, davinci_wdt);
0238 watchdog_set_nowayout(wdd, 1);
0239 watchdog_set_restart_priority(wdd, 128);
0240
0241 davinci_wdt->base = devm_platform_ioremap_resource(pdev, 0);
0242 if (IS_ERR(davinci_wdt->base))
0243 return PTR_ERR(davinci_wdt->base);
0244
0245 return devm_watchdog_register_device(dev, wdd);
0246 }
0247
0248 static const struct of_device_id davinci_wdt_of_match[] = {
0249 { .compatible = "ti,davinci-wdt", },
0250 {},
0251 };
0252 MODULE_DEVICE_TABLE(of, davinci_wdt_of_match);
0253
0254 static struct platform_driver platform_wdt_driver = {
0255 .driver = {
0256 .name = "davinci-wdt",
0257 .of_match_table = davinci_wdt_of_match,
0258 },
0259 .probe = davinci_wdt_probe,
0260 };
0261
0262 module_platform_driver(platform_wdt_driver);
0263
0264 MODULE_AUTHOR("Texas Instruments");
0265 MODULE_DESCRIPTION("DaVinci Watchdog Driver");
0266
0267 module_param(heartbeat, int, 0);
0268 MODULE_PARM_DESC(heartbeat,
0269 "Watchdog heartbeat period in seconds from 1 to "
0270 __MODULE_STRING(MAX_HEARTBEAT) ", default "
0271 __MODULE_STRING(DEFAULT_HEARTBEAT));
0272
0273 MODULE_LICENSE("GPL");
0274 MODULE_ALIAS("platform:davinci-wdt");