0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #include <linux/bitops.h>
0016 #include <linux/clk.h>
0017 #include <linux/debugfs.h>
0018 #include <linux/delay.h>
0019 #include <linux/err.h>
0020 #include <linux/interrupt.h>
0021 #include <linux/io.h>
0022 #include <linux/kernel.h>
0023 #include <linux/limits.h>
0024 #include <linux/module.h>
0025 #include <linux/moduleparam.h>
0026 #include <linux/of.h>
0027 #include <linux/platform_device.h>
0028 #include <linux/pm.h>
0029 #include <linux/reset.h>
0030 #include <linux/watchdog.h>
0031
0032 #define WDOG_CONTROL_REG_OFFSET 0x00
0033 #define WDOG_CONTROL_REG_WDT_EN_MASK 0x01
0034 #define WDOG_CONTROL_REG_RESP_MODE_MASK 0x02
0035 #define WDOG_TIMEOUT_RANGE_REG_OFFSET 0x04
0036 #define WDOG_TIMEOUT_RANGE_TOPINIT_SHIFT 4
0037 #define WDOG_CURRENT_COUNT_REG_OFFSET 0x08
0038 #define WDOG_COUNTER_RESTART_REG_OFFSET 0x0c
0039 #define WDOG_COUNTER_RESTART_KICK_VALUE 0x76
0040 #define WDOG_INTERRUPT_STATUS_REG_OFFSET 0x10
0041 #define WDOG_INTERRUPT_CLEAR_REG_OFFSET 0x14
0042 #define WDOG_COMP_PARAMS_5_REG_OFFSET 0xe4
0043 #define WDOG_COMP_PARAMS_4_REG_OFFSET 0xe8
0044 #define WDOG_COMP_PARAMS_3_REG_OFFSET 0xec
0045 #define WDOG_COMP_PARAMS_2_REG_OFFSET 0xf0
0046 #define WDOG_COMP_PARAMS_1_REG_OFFSET 0xf4
0047 #define WDOG_COMP_PARAMS_1_USE_FIX_TOP BIT(6)
0048 #define WDOG_COMP_VERSION_REG_OFFSET 0xf8
0049 #define WDOG_COMP_TYPE_REG_OFFSET 0xfc
0050
0051
0052 #define DW_WDT_NUM_TOPS 16
0053 #define DW_WDT_FIX_TOP(_idx) (1U << (16 + _idx))
0054
0055 #define DW_WDT_DEFAULT_SECONDS 30
0056
0057 static const u32 dw_wdt_fix_tops[DW_WDT_NUM_TOPS] = {
0058 DW_WDT_FIX_TOP(0), DW_WDT_FIX_TOP(1), DW_WDT_FIX_TOP(2),
0059 DW_WDT_FIX_TOP(3), DW_WDT_FIX_TOP(4), DW_WDT_FIX_TOP(5),
0060 DW_WDT_FIX_TOP(6), DW_WDT_FIX_TOP(7), DW_WDT_FIX_TOP(8),
0061 DW_WDT_FIX_TOP(9), DW_WDT_FIX_TOP(10), DW_WDT_FIX_TOP(11),
0062 DW_WDT_FIX_TOP(12), DW_WDT_FIX_TOP(13), DW_WDT_FIX_TOP(14),
0063 DW_WDT_FIX_TOP(15)
0064 };
0065
0066 static bool nowayout = WATCHDOG_NOWAYOUT;
0067 module_param(nowayout, bool, 0);
0068 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
0069 "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
0070
0071 enum dw_wdt_rmod {
0072 DW_WDT_RMOD_RESET = 1,
0073 DW_WDT_RMOD_IRQ = 2
0074 };
0075
0076 struct dw_wdt_timeout {
0077 u32 top_val;
0078 unsigned int sec;
0079 unsigned int msec;
0080 };
0081
0082 struct dw_wdt {
0083 void __iomem *regs;
0084 struct clk *clk;
0085 struct clk *pclk;
0086 unsigned long rate;
0087 enum dw_wdt_rmod rmod;
0088 struct dw_wdt_timeout timeouts[DW_WDT_NUM_TOPS];
0089 struct watchdog_device wdd;
0090 struct reset_control *rst;
0091
0092 u32 control;
0093 u32 timeout;
0094
0095 #ifdef CONFIG_DEBUG_FS
0096 struct dentry *dbgfs_dir;
0097 #endif
0098 };
0099
0100 #define to_dw_wdt(wdd) container_of(wdd, struct dw_wdt, wdd)
0101
0102 static inline int dw_wdt_is_enabled(struct dw_wdt *dw_wdt)
0103 {
0104 return readl(dw_wdt->regs + WDOG_CONTROL_REG_OFFSET) &
0105 WDOG_CONTROL_REG_WDT_EN_MASK;
0106 }
0107
0108 static void dw_wdt_update_mode(struct dw_wdt *dw_wdt, enum dw_wdt_rmod rmod)
0109 {
0110 u32 val;
0111
0112 val = readl(dw_wdt->regs + WDOG_CONTROL_REG_OFFSET);
0113 if (rmod == DW_WDT_RMOD_IRQ)
0114 val |= WDOG_CONTROL_REG_RESP_MODE_MASK;
0115 else
0116 val &= ~WDOG_CONTROL_REG_RESP_MODE_MASK;
0117 writel(val, dw_wdt->regs + WDOG_CONTROL_REG_OFFSET);
0118
0119 dw_wdt->rmod = rmod;
0120 }
0121
0122 static unsigned int dw_wdt_find_best_top(struct dw_wdt *dw_wdt,
0123 unsigned int timeout, u32 *top_val)
0124 {
0125 int idx;
0126
0127
0128
0129
0130
0131
0132 for (idx = 0; idx < DW_WDT_NUM_TOPS; ++idx) {
0133 if (dw_wdt->timeouts[idx].sec >= timeout)
0134 break;
0135 }
0136
0137 if (idx == DW_WDT_NUM_TOPS)
0138 --idx;
0139
0140 *top_val = dw_wdt->timeouts[idx].top_val;
0141
0142 return dw_wdt->timeouts[idx].sec;
0143 }
0144
0145 static unsigned int dw_wdt_get_min_timeout(struct dw_wdt *dw_wdt)
0146 {
0147 int idx;
0148
0149
0150
0151
0152
0153 for (idx = 0; idx < DW_WDT_NUM_TOPS; ++idx) {
0154 if (dw_wdt->timeouts[idx].sec)
0155 break;
0156 }
0157
0158 return dw_wdt->timeouts[idx].sec;
0159 }
0160
0161 static unsigned int dw_wdt_get_max_timeout_ms(struct dw_wdt *dw_wdt)
0162 {
0163 struct dw_wdt_timeout *timeout = &dw_wdt->timeouts[DW_WDT_NUM_TOPS - 1];
0164 u64 msec;
0165
0166 msec = (u64)timeout->sec * MSEC_PER_SEC + timeout->msec;
0167
0168 return msec < UINT_MAX ? msec : UINT_MAX;
0169 }
0170
0171 static unsigned int dw_wdt_get_timeout(struct dw_wdt *dw_wdt)
0172 {
0173 int top_val = readl(dw_wdt->regs + WDOG_TIMEOUT_RANGE_REG_OFFSET) & 0xF;
0174 int idx;
0175
0176 for (idx = 0; idx < DW_WDT_NUM_TOPS; ++idx) {
0177 if (dw_wdt->timeouts[idx].top_val == top_val)
0178 break;
0179 }
0180
0181
0182
0183
0184
0185 return dw_wdt->timeouts[idx].sec * dw_wdt->rmod;
0186 }
0187
0188 static int dw_wdt_ping(struct watchdog_device *wdd)
0189 {
0190 struct dw_wdt *dw_wdt = to_dw_wdt(wdd);
0191
0192 writel(WDOG_COUNTER_RESTART_KICK_VALUE, dw_wdt->regs +
0193 WDOG_COUNTER_RESTART_REG_OFFSET);
0194
0195 return 0;
0196 }
0197
0198 static int dw_wdt_set_timeout(struct watchdog_device *wdd, unsigned int top_s)
0199 {
0200 struct dw_wdt *dw_wdt = to_dw_wdt(wdd);
0201 unsigned int timeout;
0202 u32 top_val;
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212 timeout = dw_wdt_find_best_top(dw_wdt, DIV_ROUND_UP(top_s, dw_wdt->rmod),
0213 &top_val);
0214 if (dw_wdt->rmod == DW_WDT_RMOD_IRQ)
0215 wdd->pretimeout = timeout;
0216 else
0217 wdd->pretimeout = 0;
0218
0219
0220
0221
0222
0223
0224
0225 writel(top_val | top_val << WDOG_TIMEOUT_RANGE_TOPINIT_SHIFT,
0226 dw_wdt->regs + WDOG_TIMEOUT_RANGE_REG_OFFSET);
0227
0228
0229 if (watchdog_active(wdd))
0230 dw_wdt_ping(wdd);
0231
0232
0233
0234
0235
0236
0237 if (top_s * 1000 <= wdd->max_hw_heartbeat_ms)
0238 wdd->timeout = timeout * dw_wdt->rmod;
0239 else
0240 wdd->timeout = top_s;
0241
0242 return 0;
0243 }
0244
0245 static int dw_wdt_set_pretimeout(struct watchdog_device *wdd, unsigned int req)
0246 {
0247 struct dw_wdt *dw_wdt = to_dw_wdt(wdd);
0248
0249
0250
0251
0252
0253
0254 dw_wdt_update_mode(dw_wdt, req ? DW_WDT_RMOD_IRQ : DW_WDT_RMOD_RESET);
0255 dw_wdt_set_timeout(wdd, wdd->timeout);
0256
0257 return 0;
0258 }
0259
0260 static void dw_wdt_arm_system_reset(struct dw_wdt *dw_wdt)
0261 {
0262 u32 val = readl(dw_wdt->regs + WDOG_CONTROL_REG_OFFSET);
0263
0264
0265 if (dw_wdt->rmod == DW_WDT_RMOD_IRQ)
0266 val |= WDOG_CONTROL_REG_RESP_MODE_MASK;
0267 else
0268 val &= ~WDOG_CONTROL_REG_RESP_MODE_MASK;
0269
0270 val |= WDOG_CONTROL_REG_WDT_EN_MASK;
0271 writel(val, dw_wdt->regs + WDOG_CONTROL_REG_OFFSET);
0272 }
0273
0274 static int dw_wdt_start(struct watchdog_device *wdd)
0275 {
0276 struct dw_wdt *dw_wdt = to_dw_wdt(wdd);
0277
0278 dw_wdt_set_timeout(wdd, wdd->timeout);
0279 dw_wdt_ping(&dw_wdt->wdd);
0280 dw_wdt_arm_system_reset(dw_wdt);
0281
0282 return 0;
0283 }
0284
0285 static int dw_wdt_stop(struct watchdog_device *wdd)
0286 {
0287 struct dw_wdt *dw_wdt = to_dw_wdt(wdd);
0288
0289 if (!dw_wdt->rst) {
0290 set_bit(WDOG_HW_RUNNING, &wdd->status);
0291 return 0;
0292 }
0293
0294 reset_control_assert(dw_wdt->rst);
0295 reset_control_deassert(dw_wdt->rst);
0296
0297 return 0;
0298 }
0299
0300 static int dw_wdt_restart(struct watchdog_device *wdd,
0301 unsigned long action, void *data)
0302 {
0303 struct dw_wdt *dw_wdt = to_dw_wdt(wdd);
0304
0305 writel(0, dw_wdt->regs + WDOG_TIMEOUT_RANGE_REG_OFFSET);
0306 dw_wdt_update_mode(dw_wdt, DW_WDT_RMOD_RESET);
0307 if (dw_wdt_is_enabled(dw_wdt))
0308 writel(WDOG_COUNTER_RESTART_KICK_VALUE,
0309 dw_wdt->regs + WDOG_COUNTER_RESTART_REG_OFFSET);
0310 else
0311 dw_wdt_arm_system_reset(dw_wdt);
0312
0313
0314 mdelay(500);
0315
0316 return 0;
0317 }
0318
0319 static unsigned int dw_wdt_get_timeleft(struct watchdog_device *wdd)
0320 {
0321 struct dw_wdt *dw_wdt = to_dw_wdt(wdd);
0322 unsigned int sec;
0323 u32 val;
0324
0325 val = readl(dw_wdt->regs + WDOG_CURRENT_COUNT_REG_OFFSET);
0326 sec = val / dw_wdt->rate;
0327
0328 if (dw_wdt->rmod == DW_WDT_RMOD_IRQ) {
0329 val = readl(dw_wdt->regs + WDOG_INTERRUPT_STATUS_REG_OFFSET);
0330 if (!val)
0331 sec += wdd->pretimeout;
0332 }
0333
0334 return sec;
0335 }
0336
0337 static const struct watchdog_info dw_wdt_ident = {
0338 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
0339 WDIOF_MAGICCLOSE,
0340 .identity = "Synopsys DesignWare Watchdog",
0341 };
0342
0343 static const struct watchdog_info dw_wdt_pt_ident = {
0344 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
0345 WDIOF_PRETIMEOUT | WDIOF_MAGICCLOSE,
0346 .identity = "Synopsys DesignWare Watchdog",
0347 };
0348
0349 static const struct watchdog_ops dw_wdt_ops = {
0350 .owner = THIS_MODULE,
0351 .start = dw_wdt_start,
0352 .stop = dw_wdt_stop,
0353 .ping = dw_wdt_ping,
0354 .set_timeout = dw_wdt_set_timeout,
0355 .set_pretimeout = dw_wdt_set_pretimeout,
0356 .get_timeleft = dw_wdt_get_timeleft,
0357 .restart = dw_wdt_restart,
0358 };
0359
0360 static irqreturn_t dw_wdt_irq(int irq, void *devid)
0361 {
0362 struct dw_wdt *dw_wdt = devid;
0363 u32 val;
0364
0365
0366
0367
0368
0369 val = readl(dw_wdt->regs + WDOG_INTERRUPT_STATUS_REG_OFFSET);
0370 if (!val)
0371 return IRQ_NONE;
0372
0373 watchdog_notify_pretimeout(&dw_wdt->wdd);
0374
0375 return IRQ_HANDLED;
0376 }
0377
0378 static int dw_wdt_suspend(struct device *dev)
0379 {
0380 struct dw_wdt *dw_wdt = dev_get_drvdata(dev);
0381
0382 dw_wdt->control = readl(dw_wdt->regs + WDOG_CONTROL_REG_OFFSET);
0383 dw_wdt->timeout = readl(dw_wdt->regs + WDOG_TIMEOUT_RANGE_REG_OFFSET);
0384
0385 clk_disable_unprepare(dw_wdt->pclk);
0386 clk_disable_unprepare(dw_wdt->clk);
0387
0388 return 0;
0389 }
0390
0391 static int dw_wdt_resume(struct device *dev)
0392 {
0393 struct dw_wdt *dw_wdt = dev_get_drvdata(dev);
0394 int err = clk_prepare_enable(dw_wdt->clk);
0395
0396 if (err)
0397 return err;
0398
0399 err = clk_prepare_enable(dw_wdt->pclk);
0400 if (err) {
0401 clk_disable_unprepare(dw_wdt->clk);
0402 return err;
0403 }
0404
0405 writel(dw_wdt->timeout, dw_wdt->regs + WDOG_TIMEOUT_RANGE_REG_OFFSET);
0406 writel(dw_wdt->control, dw_wdt->regs + WDOG_CONTROL_REG_OFFSET);
0407
0408 dw_wdt_ping(&dw_wdt->wdd);
0409
0410 return 0;
0411 }
0412
0413 static DEFINE_SIMPLE_DEV_PM_OPS(dw_wdt_pm_ops, dw_wdt_suspend, dw_wdt_resume);
0414
0415
0416
0417
0418
0419
0420
0421
0422
0423 static void dw_wdt_handle_tops(struct dw_wdt *dw_wdt, const u32 *tops)
0424 {
0425 struct dw_wdt_timeout tout, *dst;
0426 int val, tidx;
0427 u64 msec;
0428
0429
0430
0431
0432
0433
0434
0435 for (val = 0; val < DW_WDT_NUM_TOPS; ++val) {
0436 tout.top_val = val;
0437 tout.sec = tops[val] / dw_wdt->rate;
0438 msec = (u64)tops[val] * MSEC_PER_SEC;
0439 do_div(msec, dw_wdt->rate);
0440 tout.msec = msec - ((u64)tout.sec * MSEC_PER_SEC);
0441
0442
0443
0444
0445
0446 for (tidx = 0; tidx < val; ++tidx) {
0447 dst = &dw_wdt->timeouts[tidx];
0448 if (tout.sec > dst->sec || (tout.sec == dst->sec &&
0449 tout.msec >= dst->msec))
0450 continue;
0451 else
0452 swap(*dst, tout);
0453 }
0454
0455 dw_wdt->timeouts[val] = tout;
0456 }
0457 }
0458
0459 static int dw_wdt_init_timeouts(struct dw_wdt *dw_wdt, struct device *dev)
0460 {
0461 u32 data, of_tops[DW_WDT_NUM_TOPS];
0462 const u32 *tops;
0463 int ret;
0464
0465
0466
0467
0468
0469
0470 data = readl(dw_wdt->regs + WDOG_COMP_PARAMS_1_REG_OFFSET);
0471 if (data & WDOG_COMP_PARAMS_1_USE_FIX_TOP) {
0472 tops = dw_wdt_fix_tops;
0473 } else {
0474 ret = of_property_read_variable_u32_array(dev_of_node(dev),
0475 "snps,watchdog-tops", of_tops, DW_WDT_NUM_TOPS,
0476 DW_WDT_NUM_TOPS);
0477 if (ret < 0) {
0478 dev_warn(dev, "No valid TOPs array specified\n");
0479 tops = dw_wdt_fix_tops;
0480 } else {
0481 tops = of_tops;
0482 }
0483 }
0484
0485
0486 dw_wdt_handle_tops(dw_wdt, tops);
0487 if (!dw_wdt->timeouts[DW_WDT_NUM_TOPS - 1].sec) {
0488 dev_err(dev, "No any valid TOP detected\n");
0489 return -EINVAL;
0490 }
0491
0492 return 0;
0493 }
0494
0495 #ifdef CONFIG_DEBUG_FS
0496
0497 #define DW_WDT_DBGFS_REG(_name, _off) \
0498 { \
0499 .name = _name, \
0500 .offset = _off \
0501 }
0502
0503 static const struct debugfs_reg32 dw_wdt_dbgfs_regs[] = {
0504 DW_WDT_DBGFS_REG("cr", WDOG_CONTROL_REG_OFFSET),
0505 DW_WDT_DBGFS_REG("torr", WDOG_TIMEOUT_RANGE_REG_OFFSET),
0506 DW_WDT_DBGFS_REG("ccvr", WDOG_CURRENT_COUNT_REG_OFFSET),
0507 DW_WDT_DBGFS_REG("crr", WDOG_COUNTER_RESTART_REG_OFFSET),
0508 DW_WDT_DBGFS_REG("stat", WDOG_INTERRUPT_STATUS_REG_OFFSET),
0509 DW_WDT_DBGFS_REG("param5", WDOG_COMP_PARAMS_5_REG_OFFSET),
0510 DW_WDT_DBGFS_REG("param4", WDOG_COMP_PARAMS_4_REG_OFFSET),
0511 DW_WDT_DBGFS_REG("param3", WDOG_COMP_PARAMS_3_REG_OFFSET),
0512 DW_WDT_DBGFS_REG("param2", WDOG_COMP_PARAMS_2_REG_OFFSET),
0513 DW_WDT_DBGFS_REG("param1", WDOG_COMP_PARAMS_1_REG_OFFSET),
0514 DW_WDT_DBGFS_REG("version", WDOG_COMP_VERSION_REG_OFFSET),
0515 DW_WDT_DBGFS_REG("type", WDOG_COMP_TYPE_REG_OFFSET)
0516 };
0517
0518 static void dw_wdt_dbgfs_init(struct dw_wdt *dw_wdt)
0519 {
0520 struct device *dev = dw_wdt->wdd.parent;
0521 struct debugfs_regset32 *regset;
0522
0523 regset = devm_kzalloc(dev, sizeof(*regset), GFP_KERNEL);
0524 if (!regset)
0525 return;
0526
0527 regset->regs = dw_wdt_dbgfs_regs;
0528 regset->nregs = ARRAY_SIZE(dw_wdt_dbgfs_regs);
0529 regset->base = dw_wdt->regs;
0530
0531 dw_wdt->dbgfs_dir = debugfs_create_dir(dev_name(dev), NULL);
0532
0533 debugfs_create_regset32("registers", 0444, dw_wdt->dbgfs_dir, regset);
0534 }
0535
0536 static void dw_wdt_dbgfs_clear(struct dw_wdt *dw_wdt)
0537 {
0538 debugfs_remove_recursive(dw_wdt->dbgfs_dir);
0539 }
0540
0541 #else
0542
0543 static void dw_wdt_dbgfs_init(struct dw_wdt *dw_wdt) {}
0544 static void dw_wdt_dbgfs_clear(struct dw_wdt *dw_wdt) {}
0545
0546 #endif
0547
0548 static int dw_wdt_drv_probe(struct platform_device *pdev)
0549 {
0550 struct device *dev = &pdev->dev;
0551 struct watchdog_device *wdd;
0552 struct dw_wdt *dw_wdt;
0553 int ret;
0554
0555 dw_wdt = devm_kzalloc(dev, sizeof(*dw_wdt), GFP_KERNEL);
0556 if (!dw_wdt)
0557 return -ENOMEM;
0558
0559 dw_wdt->regs = devm_platform_ioremap_resource(pdev, 0);
0560 if (IS_ERR(dw_wdt->regs))
0561 return PTR_ERR(dw_wdt->regs);
0562
0563
0564
0565
0566
0567
0568
0569 dw_wdt->clk = devm_clk_get(dev, "tclk");
0570 if (IS_ERR(dw_wdt->clk)) {
0571 dw_wdt->clk = devm_clk_get(dev, NULL);
0572 if (IS_ERR(dw_wdt->clk))
0573 return PTR_ERR(dw_wdt->clk);
0574 }
0575
0576 ret = clk_prepare_enable(dw_wdt->clk);
0577 if (ret)
0578 return ret;
0579
0580 dw_wdt->rate = clk_get_rate(dw_wdt->clk);
0581 if (dw_wdt->rate == 0) {
0582 ret = -EINVAL;
0583 goto out_disable_clk;
0584 }
0585
0586
0587
0588
0589
0590
0591
0592
0593 dw_wdt->pclk = devm_clk_get_optional(dev, "pclk");
0594 if (IS_ERR(dw_wdt->pclk)) {
0595 ret = PTR_ERR(dw_wdt->pclk);
0596 goto out_disable_clk;
0597 }
0598
0599 ret = clk_prepare_enable(dw_wdt->pclk);
0600 if (ret)
0601 goto out_disable_clk;
0602
0603 dw_wdt->rst = devm_reset_control_get_optional_shared(&pdev->dev, NULL);
0604 if (IS_ERR(dw_wdt->rst)) {
0605 ret = PTR_ERR(dw_wdt->rst);
0606 goto out_disable_pclk;
0607 }
0608
0609
0610 dw_wdt_update_mode(dw_wdt, DW_WDT_RMOD_RESET);
0611
0612
0613
0614
0615
0616
0617
0618 ret = platform_get_irq_optional(pdev, 0);
0619 if (ret > 0) {
0620 ret = devm_request_irq(dev, ret, dw_wdt_irq,
0621 IRQF_SHARED | IRQF_TRIGGER_RISING,
0622 pdev->name, dw_wdt);
0623 if (ret)
0624 goto out_disable_pclk;
0625
0626 dw_wdt->wdd.info = &dw_wdt_pt_ident;
0627 } else {
0628 if (ret == -EPROBE_DEFER)
0629 goto out_disable_pclk;
0630
0631 dw_wdt->wdd.info = &dw_wdt_ident;
0632 }
0633
0634 reset_control_deassert(dw_wdt->rst);
0635
0636 ret = dw_wdt_init_timeouts(dw_wdt, dev);
0637 if (ret)
0638 goto out_disable_clk;
0639
0640 wdd = &dw_wdt->wdd;
0641 wdd->ops = &dw_wdt_ops;
0642 wdd->min_timeout = dw_wdt_get_min_timeout(dw_wdt);
0643 wdd->max_hw_heartbeat_ms = dw_wdt_get_max_timeout_ms(dw_wdt);
0644 wdd->parent = dev;
0645
0646 watchdog_set_drvdata(wdd, dw_wdt);
0647 watchdog_set_nowayout(wdd, nowayout);
0648 watchdog_init_timeout(wdd, 0, dev);
0649
0650
0651
0652
0653
0654
0655 if (dw_wdt_is_enabled(dw_wdt)) {
0656 wdd->timeout = dw_wdt_get_timeout(dw_wdt);
0657 set_bit(WDOG_HW_RUNNING, &wdd->status);
0658 } else {
0659 wdd->timeout = DW_WDT_DEFAULT_SECONDS;
0660 watchdog_init_timeout(wdd, 0, dev);
0661 }
0662
0663 platform_set_drvdata(pdev, dw_wdt);
0664
0665 watchdog_set_restart_priority(wdd, 128);
0666
0667 ret = watchdog_register_device(wdd);
0668 if (ret)
0669 goto out_disable_pclk;
0670
0671 dw_wdt_dbgfs_init(dw_wdt);
0672
0673 return 0;
0674
0675 out_disable_pclk:
0676 clk_disable_unprepare(dw_wdt->pclk);
0677
0678 out_disable_clk:
0679 clk_disable_unprepare(dw_wdt->clk);
0680 return ret;
0681 }
0682
0683 static int dw_wdt_drv_remove(struct platform_device *pdev)
0684 {
0685 struct dw_wdt *dw_wdt = platform_get_drvdata(pdev);
0686
0687 dw_wdt_dbgfs_clear(dw_wdt);
0688
0689 watchdog_unregister_device(&dw_wdt->wdd);
0690 reset_control_assert(dw_wdt->rst);
0691 clk_disable_unprepare(dw_wdt->pclk);
0692 clk_disable_unprepare(dw_wdt->clk);
0693
0694 return 0;
0695 }
0696
0697 #ifdef CONFIG_OF
0698 static const struct of_device_id dw_wdt_of_match[] = {
0699 { .compatible = "snps,dw-wdt", },
0700 { }
0701 };
0702 MODULE_DEVICE_TABLE(of, dw_wdt_of_match);
0703 #endif
0704
0705 static struct platform_driver dw_wdt_driver = {
0706 .probe = dw_wdt_drv_probe,
0707 .remove = dw_wdt_drv_remove,
0708 .driver = {
0709 .name = "dw_wdt",
0710 .of_match_table = of_match_ptr(dw_wdt_of_match),
0711 .pm = pm_sleep_ptr(&dw_wdt_pm_ops),
0712 },
0713 };
0714
0715 module_platform_driver(dw_wdt_driver);
0716
0717 MODULE_AUTHOR("Jamie Iles");
0718 MODULE_DESCRIPTION("Synopsys DesignWare Watchdog Driver");
0719 MODULE_LICENSE("GPL");