예제 #1
0
static int s3c2410wdt_resume(struct platform_device *pdev)
{
	struct s3c_watchdog_platdata *pdata;

	clk_enable(wdt_clock);
	pdata = dev_get_platdata(&pdev->dev);
	/* Stop and clear watchdog interrupt */
	s3c2410wdt_stop(&s3c2410_wdd);
	s3c2410wdt_int_clear(&s3c2410_wdd);

	/* Enable pmu watchdog reset control */
	if (pdata != NULL && pdata->pmu_wdt_control != NULL)
		pdata->pmu_wdt_control(1, pdata->pmu_wdt_reset_type);

	/* Restore watchdog state. */

	writel(wtdat_save, S3C2410_WTDAT);
	writel(wtdat_save, S3C2410_WTCNT); /* Reset count */
	writel(wtcon_save, S3C2410_WTCON);

	pr_debug("watchdog %sabled\n",
		(wtcon_save & S3C2410_WTCON_ENABLE) ? "en" : "dis");
//	atomic_set(&wdt_suspended, 0);

	return 0;
}
예제 #2
0
static irqreturn_t s3c2410wdt_irq(int irqno, void *param)
{
	dev_info(wdt_dev, "watchdog timer expired (irq)\n");
	s3c2410wdt_keepalive(&s3c2410_wdd);

	/* Clear the interrupt */
	s3c2410wdt_int_clear(&s3c2410_wdd);

	/* Print backtrace of all cpus. */
	handle_sysrq('l');

	/* Restart for availability */
	pr_info("%s: emergency reboot\n", __func__);
	emergency_restart();

	return IRQ_HANDLED;
}
static int s3c2410wdt_probe(struct platform_device *pdev)
{
	struct device *dev;
	unsigned int wtcon;
	int started = 0;
	int ret;
	struct s3c_watchdog_platdata *pdata;

	DBG("%s: probe=%p\n", __func__, pdev);

	dev = &pdev->dev;
	wdt_dev = &pdev->dev;

	if (s3c2410wdt_get_platdata(pdev)) {
		dev_err(dev, "failed to get platdata\n");
		return -EINVAL;
	}
	pdata = dev_get_platdata(&pdev->dev);

	wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (wdt_mem == NULL) {
		dev_err(dev, "no memory resource specified\n");
		return -ENOENT;
	}

	wdt_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
	if (wdt_irq == NULL) {
		dev_err(dev, "no irq resource specified\n");
		ret = -ENOENT;
		goto err;
	}

	/* get the memory region for the watchdog timer */
	wdt_base = devm_ioremap_resource(dev, wdt_mem);
	if (IS_ERR(wdt_base)) {
		ret = PTR_ERR(wdt_base);
		goto err;
	}

	DBG("probe: mapped wdt_base=%p\n", wdt_base);

	rate_wdt_clock = devm_clk_get(dev, "rate_watchdog");
	if (IS_ERR(rate_wdt_clock)) {
		dev_err(dev, "failed to find watchdog rate clock source\n");
		ret = PTR_ERR(rate_wdt_clock);
		goto err;
	}

	wdt_clock = devm_clk_get(dev, "gate_watchdog");
	if (IS_ERR(wdt_clock)) {
		dev_err(dev, "failed to find watchdog clock source\n");
		ret = PTR_ERR(wdt_clock);
		goto err;
	}

	clk_prepare_enable(wdt_clock);

	/* Enable pmu watchdog reset control */
	if (pdata != NULL && pdata->pmu_wdt_control != NULL) {
		s3c2410wdt_int_clear(&s3c2410_wdd);
		pdata->pmu_wdt_control(1, pdata->pmu_wdt_reset_type);
	}

	/* see if we can actually set the requested timer margin, and if
	 * not, try the default value */

	ret = s3c2410wdt_set_min_max_timeout(&s3c2410_wdd);
	if (ret != 0) {
		dev_err(dev, "clock rate is 0\n");
		goto err_clk;
	}

	watchdog_init_timeout(&s3c2410_wdd, tmr_margin,  &pdev->dev);
	if (s3c2410wdt_set_heartbeat(&s3c2410_wdd, s3c2410_wdd.timeout)) {
		started = s3c2410wdt_set_heartbeat(&s3c2410_wdd,
					CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME);

		if (started == 0)
			dev_info(dev,
			   "tmr_margin value out of range, default %d used\n",
			       CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME);
		else
			dev_info(dev, "default timer value is out of range, "
							"cannot start\n");
	}

	ret = devm_request_irq(dev, wdt_irq->start, s3c2410wdt_irq, 0,
				pdev->name, pdev);
	if (ret != 0) {
		dev_err(dev, "failed to install irq (%d)\n", ret);
		goto err_clk;
	}

	watchdog_set_nowayout(&s3c2410_wdd, nowayout);

	ret = watchdog_register_device(&s3c2410_wdd);
	if (ret) {
		dev_err(dev, "cannot register watchdog (%d)\n", ret);
		goto err_clk;
	}

	if (tmr_atboot && started == 0) {
		dev_info(dev, "starting watchdog timer\n");
		s3c2410wdt_start(&s3c2410_wdd);
	} else if (!tmr_atboot) {
		/* if we're not enabling the watchdog, then ensure it is
		 * disabled if it has been left running from the bootloader
		 * or other source */

		s3c2410wdt_stop(&s3c2410_wdd);
	}

	/* print out a statement of readiness */

	wtcon = readl(wdt_base + S3C2410_WTCON);

	dev_info(dev, "watchdog %sactive, reset %sabled, irq %sabled\n",
		 (wtcon & S3C2410_WTCON_ENABLE) ?  "" : "in",
		 (wtcon & S3C2410_WTCON_RSTEN) ? "en" : "dis",
		 (wtcon & S3C2410_WTCON_INTEN) ? "en" : "dis");

	return 0;

 err_clk:
	clk_disable_unprepare(wdt_clock);
	wdt_clock = NULL;
	rate_wdt_clock = NULL;

 err:
	wdt_irq = NULL;
	wdt_mem = NULL;
	return ret;
}