static int rwdt_probe()

in renesas_wdt.c [212:293]


static int rwdt_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct rwdt_priv *priv;
	unsigned long clks_per_sec;
	int ret, i;
	u8 csra;

	if (rwdt_blacklisted(dev))
		return -ENODEV;

	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
	if (!priv)
		return -ENOMEM;

	priv->base = devm_platform_ioremap_resource(pdev, 0);
	if (IS_ERR(priv->base))
		return PTR_ERR(priv->base);

	priv->clk = devm_clk_get(dev, NULL);
	if (IS_ERR(priv->clk))
		return PTR_ERR(priv->clk);

	pm_runtime_enable(dev);
	pm_runtime_get_sync(dev);
	priv->clk_rate = clk_get_rate(priv->clk);
	csra = readb_relaxed(priv->base + RWTCSRA);
	priv->wdev.bootstatus = csra & RWTCSRA_WOVF ? WDIOF_CARDRESET : 0;
	pm_runtime_put(dev);

	if (!priv->clk_rate) {
		ret = -ENOENT;
		goto out_pm_disable;
	}

	for (i = ARRAY_SIZE(clk_divs) - 1; i >= 0; i--) {
		clks_per_sec = priv->clk_rate / clk_divs[i];
		if (clks_per_sec && clks_per_sec < 65536) {
			priv->cks = i;
			break;
		}
	}

	if (i < 0) {
		dev_err(dev, "Can't find suitable clock divider\n");
		ret = -ERANGE;
		goto out_pm_disable;
	}

	priv->wdev.info = &rwdt_ident;
	priv->wdev.ops = &rwdt_ops;
	priv->wdev.parent = dev;
	priv->wdev.min_timeout = 1;
	priv->wdev.max_timeout = DIV_BY_CLKS_PER_SEC(priv, 65536);
	priv->wdev.timeout = min(priv->wdev.max_timeout, RWDT_DEFAULT_TIMEOUT);

	platform_set_drvdata(pdev, priv);
	watchdog_set_drvdata(&priv->wdev, priv);
	watchdog_set_nowayout(&priv->wdev, nowayout);
	watchdog_set_restart_priority(&priv->wdev, 0);
	watchdog_stop_on_unregister(&priv->wdev);

	/* This overrides the default timeout only if DT configuration was found */
	watchdog_init_timeout(&priv->wdev, 0, dev);

	/* Check if FW enabled the watchdog */
	if (csra & RWTCSRA_TME) {
		/* Ensure properly initialized dividers */
		rwdt_start(&priv->wdev);
		set_bit(WDOG_HW_RUNNING, &priv->wdev.status);
	}

	ret = watchdog_register_device(&priv->wdev);
	if (ret < 0)
		goto out_pm_disable;

	return 0;

 out_pm_disable:
	pm_runtime_disable(dev);
	return ret;
}