Example #1
0
static int
mxc_wdt_ioctl(struct inode *inode, struct file *file,
              unsigned int cmd, unsigned long arg)
{
    unsigned int new_margin;
    int boot_reason;

    static struct watchdog_info ident = {
        .identity = "MXC Watchdog",
        .options = WDIOF_SETTIMEOUT,
        .firmware_version = 0,
    };

    switch (cmd) {
    default:
        return -ENOIOCTLCMD;
    case WDIOC_GETSUPPORT:
        return copy_to_user((struct watchdog_info __user *)arg, &ident,
                            sizeof(ident));
    case WDIOC_GETSTATUS:
        return put_user(0, (int __user *)arg);

    case WDIOC_GETBOOTSTATUS:
        boot_reason = mxc_wdt_get_boot_reason();
        return put_user(boot_reason, (unsigned int __user *)arg);

    case WDIOC_KEEPALIVE:
        mxc_wdt_ping();
        return 0;

    case WDIOC_SETTIMEOUT:
        if (get_user(new_margin, (unsigned int __user *)arg))
            return -EFAULT;

        mxc_wdt_adjust_timeout(new_margin);
        mxc_wdt_disable();
        mxc_wdt_set_timeout();
        mxc_wdt_enable();
        mxc_wdt_ping();
        return 0;

    case WDIOC_GETTIMEOUT:
        mxc_wdt_ping();
        new_margin = mxc_wdt_get_timeout();
        return put_user(new_margin, (unsigned int __user *)arg);
    }
}

static struct file_operations mxc_wdt_fops = {
    .owner = THIS_MODULE,
    .write = mxc_wdt_write,
    .ioctl = mxc_wdt_ioctl,
    .open = mxc_wdt_open,
    .release = mxc_wdt_release,
};

static struct miscdevice mxc_wdt_miscdev = {
    .minor = WATCHDOG_MINOR,
    .name = "watchdog",
    .fops = &mxc_wdt_fops
};

static int __init mxc_wdt_probe(struct platform_device *pdev)
{
    int ret;

    mxc_wdt_disable();
    mxc_wdt_adjust_timeout(timer_margin);

    mxc_wdt_users = 0;

    mxc_wdt_miscdev.dev = &pdev->dev;

    mxc_wdt_clk = clk_get(NULL, "wdog_clk");
    clk_enable(mxc_wdt_clk);

    ret = misc_register(&mxc_wdt_miscdev);
    if (ret)
        goto fail;

    pr_info("MXC Watchdog Timer: initial timeout %d sec\n",
            timer_margin);

    return 0;

fail:
    pr_info("MXC Watchdog Probe failed\n");
    return ret;
}

static void mxc_wdt_shutdown(struct platform_device *pdev)
{
    mxc_wdt_disable();
    pr_info("MXC Watchdog shutdown\n");
}
static int
mxc_wdt_ioctl(struct inode *inode, struct file *file,
	      unsigned int cmd, unsigned long arg)
{
	int new_margin;
	int bootr;

	static struct watchdog_info ident = {
		.identity = "MXC Watchdog",
		.options = WDIOF_SETTIMEOUT,
		.firmware_version = 0,
	};

	switch (cmd) {
	default:
		return -ENOIOCTLCMD;
	case WDIOC_GETSUPPORT:
		return copy_to_user((struct watchdog_info __user *)arg, &ident,
				    sizeof(ident));
	case WDIOC_GETSTATUS:
		return put_user(0, (int __user *)arg);
	case WDIOC_GETBOOTSTATUS:
		bootr = mxc_wdt_get_bootreason(wdt_base_reg);
		return put_user(bootr, (int __user *)arg);
	case WDIOC_KEEPALIVE:
		mxc_wdt_ping(wdt_base_reg);
		return 0;
	case WDIOC_SETTIMEOUT:
		if (get_user(new_margin, (int __user *)arg))
			return -EFAULT;

		mxc_wdt_adjust_timeout(new_margin);
		mxc_wdt_disable(wdt_base_reg);
		mxc_wdt_set_timeout(wdt_base_reg);
		mxc_wdt_enable(wdt_base_reg);
		mxc_wdt_ping(wdt_base_reg);
		return 0;

	case WDIOC_GETTIMEOUT:
		mxc_wdt_ping(wdt_base_reg);
		new_margin = mxc_wdt_get_timeout(wdt_base_reg);
		return put_user(new_margin, (int __user *)arg);
	}
}

static struct file_operations mxc_wdt_fops = {
	.owner = THIS_MODULE,
	.write = mxc_wdt_write,
	.ioctl = mxc_wdt_ioctl,
	.open = mxc_wdt_open,
	.release = mxc_wdt_release,
};

static struct miscdevice mxc_wdt_miscdev = {
	.minor = WATCHDOG_MINOR,
	.name = "watchdog",
	.fops = &mxc_wdt_fops
};

static int __init mxc_wdt_probe(struct platform_device *pdev)
{
	struct resource *res, *mem;
	int ret;

	/* reserve static register mappings */
	res = platform_get_resource(pdev, IORESOURCE_MEM, dev_num);
	if (!res)
		return -ENOENT;

	mem = request_mem_region(res->start, res->end - res->start + 1,
				 pdev->name);
	if (mem == NULL)
		return -EBUSY;

	platform_set_drvdata(pdev, mem);

	wdt_base_reg = IO_ADDRESS(res->start);
	mxc_wdt_disable(wdt_base_reg);
	mxc_wdt_adjust_timeout(timer_margin);

	mxc_wdt_users = 0;

	mxc_wdt_miscdev.this_device = &pdev->dev;

	mxc_wdt_clk = clk_get(NULL, "wdog_clk");
	clk_enable(mxc_wdt_clk);

	ret = misc_register(&mxc_wdt_miscdev);
	if (ret)
		goto fail;

	pr_info("MXC Watchdog # %d Timer: initial timeout %d sec\n", dev_num,
		timer_margin);

	return 0;

      fail:
	release_resource(mem);
	pr_info("MXC Watchdog Probe failed\n");
	return ret;
}

static void mxc_wdt_shutdown(struct platform_device *pdev)
{
	struct resource *res = platform_get_drvdata(pdev);
	mxc_wdt_disable(wdt_base_reg);
	pr_info("MXC Watchdog # %d shutdown\n", dev_num);
}

static int __exit mxc_wdt_remove(struct platform_device *pdev)
{
	struct resource *mem = platform_get_drvdata(pdev);
	misc_deregister(&mxc_wdt_miscdev);
	release_resource(mem);
	pr_info("MXC Watchdog # %d removed\n", dev_num);
	return 0;
}

#ifdef	CONFIG_PM

/* REVISIT ... not clear this is the best way to handle system suspend; and
 * it's very inappropriate for selective device suspend (e.g. suspending this
 * through sysfs rather than by stopping the watchdog daemon).  Also, this
 * may not play well enough with NOWAYOUT...
 */

static int mxc_wdt_suspend(struct platform_device *pdev, pm_message_t state)
{
	struct resource *res = platform_get_drvdata(pdev);

	if (mxc_wdt_users) {
		mxc_wdt_disable(wdt_base_reg);
	}
	return 0;
}

static int mxc_wdt_resume(struct platform_device *pdev)
{
	struct resource *res = platform_get_drvdata(pdev);
	if (mxc_wdt_users) {
		mxc_wdt_enable(wdt_base_reg);
		mxc_wdt_ping(wdt_base_reg);
	}
	return 0;
}

#else
#define	mxc_wdt_suspend	NULL
#define	mxc_wdt_resume		NULL
#endif

static struct platform_driver mxc_wdt_driver = {
	.driver = {
		   .owner = THIS_MODULE,
		   .name = "mxc_wdt",
		   },
	.probe = mxc_wdt_probe,
	.shutdown = mxc_wdt_shutdown,
	.remove = __exit_p(mxc_wdt_remove),
	.suspend = mxc_wdt_suspend,
	.resume = mxc_wdt_resume,
};

static int __init mxc_wdt_init(void)
{
	pr_info("MXC WatchDog Driver %s\n", DVR_VER);

	if ((timer_margin < TIMER_MARGIN_MIN) ||
	    (timer_margin > TIMER_MARGIN_MAX)) {
		pr_info("MXC watchdog error. wrong timer_margin %d\n",
			timer_margin);
		pr_info("    Range: %d to %d seconds\n", TIMER_MARGIN_MIN,
			TIMER_MARGIN_MAX);
		return -EINVAL;
	}

	return platform_driver_register(&mxc_wdt_driver);
}
Example #3
0
static int
mxc_wdt_ioctl(struct inode *inode, struct file *file,
	      unsigned int cmd, unsigned long arg)
{
	int new_margin;
	int bootr;

	static struct watchdog_info ident = {
		.identity = "MXC Watchdog",
		.options = WDIOF_SETTIMEOUT,
		.firmware_version = 0,
	};

	switch (cmd) {
	default:
		return -ENOIOCTLCMD;
	case WDIOC_GETSUPPORT:
		return copy_to_user((struct watchdog_info __user *)arg, &ident,
				    sizeof(ident));
	case WDIOC_GETSTATUS:
		return put_user(0, (int __user *)arg);
	case WDIOC_GETBOOTSTATUS:
		bootr = mxc_wdt_get_bootreason(wdt_base_reg);
		return put_user(bootr, (int __user *)arg);
	case WDIOC_KEEPALIVE:
		mxc_wdt_ping(wdt_base_reg);
#ifdef CONFIG_MACH_MX51_ERDOS
		mxc_wdt_staticstics [2]++;
#endif /* CONFIG_MACH_MX51_ERDOS */
			return 0;
	case WDIOC_SETTIMEOUT:
		if (get_user(new_margin, (int __user *)arg))
			return -EFAULT;

		mxc_wdt_adjust_timeout(new_margin);
		mxc_wdt_disable(wdt_base_reg);
		mxc_wdt_set_timeout(wdt_base_reg);
		mxc_wdt_enable(wdt_base_reg);
		mxc_wdt_ping(wdt_base_reg);
		return 0;

	case WDIOC_GETTIMEOUT:
		mxc_wdt_ping(wdt_base_reg);
		new_margin = mxc_wdt_get_timeout(wdt_base_reg);
		return put_user(new_margin, (int __user *)arg);
	}
}

static struct file_operations mxc_wdt_fops = {
	.owner = THIS_MODULE,
	.write = mxc_wdt_write,
	.ioctl = mxc_wdt_ioctl,
	.open = mxc_wdt_open,
	.release = mxc_wdt_release,
};

static struct miscdevice mxc_wdt_miscdev = {
	.minor = WATCHDOG_MINOR,
	.name = "watchdog",
	.fops = &mxc_wdt_fops
};

#ifdef CONFIG_MACH_MX51_ERDOS
/*
 * wdt_self_workqueue_handler 
 */
static void wdt_self_workqueue_handler (struct work_struct *work)
{
	mxc_wdt_staticstics [0]++;
	if (opened == 0) {
	/*
	 * WDT heartbeat
	 */
	mxc_wdt_staticstics [1]++;
	mxc_wdt_ping (wdt_base_reg);
	/*
	 * next interval
	 */
	schedule_delayed_work (&wdt_self_work, 60 * HZ);
	}
}

/*
 * wdt_self_start 
 */
static void wdt_self_start (void)
{
	/*
	 * delay work create
	 */
	INIT_DELAYED_WORK (&wdt_self_work, wdt_self_workqueue_handler);
	schedule_delayed_work (&wdt_self_work, HZ);
	mxc_wdt_config (wdt_base_reg);
	mxc_wdt_set_timeout (wdt_base_reg);
	mxc_wdt_enable (wdt_base_reg);
}