in rti_wdt.c [193:303]
static int rti_wdt_probe(struct platform_device *pdev)
{
int ret = 0;
struct device *dev = &pdev->dev;
struct watchdog_device *wdd;
struct rti_wdt_device *wdt;
struct clk *clk;
u32 last_ping = 0;
wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
if (!wdt)
return -ENOMEM;
clk = clk_get(dev, NULL);
if (IS_ERR(clk))
return dev_err_probe(dev, PTR_ERR(clk), "failed to get clock\n");
wdt->freq = clk_get_rate(clk);
clk_put(clk);
if (!wdt->freq) {
dev_err(dev, "Failed to get fck rate.\n");
return -EINVAL;
}
/*
* If watchdog is running at 32k clock, it is not accurate.
* Adjust frequency down in this case so that we don't pet
* the watchdog too often.
*/
if (wdt->freq < 32768)
wdt->freq = wdt->freq * 9 / 10;
pm_runtime_enable(dev);
ret = pm_runtime_get_sync(dev);
if (ret) {
pm_runtime_put_noidle(dev);
return dev_err_probe(dev, ret, "runtime pm failed\n");
}
platform_set_drvdata(pdev, wdt);
wdd = &wdt->wdd;
wdd->info = &rti_wdt_info;
wdd->ops = &rti_wdt_ops;
wdd->min_timeout = 1;
wdd->max_hw_heartbeat_ms = (WDT_PRELOAD_MAX << WDT_PRELOAD_SHIFT) /
wdt->freq * 1000;
wdd->parent = dev;
watchdog_set_drvdata(wdd, wdt);
watchdog_set_nowayout(wdd, 1);
watchdog_set_restart_priority(wdd, 128);
wdt->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(wdt->base)) {
ret = PTR_ERR(wdt->base);
goto err_iomap;
}
if (readl(wdt->base + RTIDWDCTRL) == WDENABLE_KEY) {
u32 time_left_ms;
u64 heartbeat_ms;
u32 wsize;
set_bit(WDOG_HW_RUNNING, &wdd->status);
time_left_ms = rti_wdt_get_timeleft_ms(wdd);
heartbeat_ms = readl(wdt->base + RTIDWDPRLD);
heartbeat_ms <<= WDT_PRELOAD_SHIFT;
heartbeat_ms *= 1000;
do_div(heartbeat_ms, wdt->freq);
if (heartbeat_ms != heartbeat * 1000)
dev_warn(dev, "watchdog already running, ignoring heartbeat config!\n");
heartbeat = heartbeat_ms;
heartbeat /= 1000;
wsize = readl(wdt->base + RTIWWDSIZECTRL);
ret = rti_wdt_setup_hw_hb(wdd, wsize);
if (ret) {
dev_err(dev, "bad window size.\n");
goto err_iomap;
}
last_ping = heartbeat_ms - time_left_ms;
if (time_left_ms > heartbeat_ms) {
dev_warn(dev, "time_left > heartbeat? Assuming last ping just before now.\n");
last_ping = 0;
}
}
watchdog_init_timeout(wdd, heartbeat, dev);
ret = watchdog_register_device(wdd);
if (ret) {
dev_err(dev, "cannot register watchdog device\n");
goto err_iomap;
}
if (last_ping)
watchdog_set_last_hw_keepalive(wdd, last_ping);
return 0;
err_iomap:
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
return ret;
}