static int rti_wdt_probe()

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;
}