/* Write */
static ssize_t intel_scu_write(struct file *file, char const *data, size_t len,
			      loff_t *ppos)
{
	pr_debug(PFX "watchdog %s\n", __func__);

	if (watchdog_device.shutdown_flag == true)
		/* do nothing if we are shutting down */
		return len;

	if (watchdog_device.started) {
		/* Watchdog already started, keep it alive */
		watchdog_keepalive();
		wake_unlock(&watchdog_wake_lock);
	} else {
		/* Start watchdog with timer value set by init */
		watchdog_config_and_start(timeout, pre_timeout);
	}

	return len;
}
/* ioctl */
static long intel_scu_ioctl(struct file *file, unsigned int cmd,
			    unsigned long arg)
{
	void __user *argp = (void __user *)arg;
	u32 __user *p = argp;
	u32 val;
	int options;

	static const struct watchdog_info ident = {
		.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
		/* @todo Get from SCU via ipc_get_scu_fw_version()? */
		.firmware_version = 0,
		/* len < 32 */
		.identity = "Intel_SCU IOH Watchdog"
	};

	switch (cmd) {
	case WDIOC_GETSUPPORT:
		return copy_to_user(argp, &ident,
				    sizeof(ident)) ? -EFAULT : 0;
	case WDIOC_GETSTATUS:
	case WDIOC_GETBOOTSTATUS:
		return put_user(0, p);
	case WDIOC_KEEPALIVE:
		pr_warn("%s: KeepAlive ioctl\n", __func__);
		if (!watchdog_device.started)
			return -EINVAL;

		watchdog_keepalive();
		return 0;
	case WDIOC_SETPRETIMEOUT:
		pr_warn("%s: SetPreTimeout ioctl\n", __func__);

		if (watchdog_device.started)
			return -EBUSY;

		/* Timeout to warn */
		if (get_user(val, p))
			return -EFAULT;

		pre_timeout = val;
		return 0;
	case WDIOC_SETTIMEOUT:
		pr_warn("%s: SetTimeout ioctl\n", __func__);

		if (watchdog_device.started)
			return -EBUSY;

		if (get_user(val, p))
			return -EFAULT;

		timeout = val;
		return 0;
	case WDIOC_GETTIMEOUT:
		return put_user(timeout, p);
	case WDIOC_SETOPTIONS:
		if (get_user(options, p))
			return -EFAULT;

		if (options & WDIOS_DISABLECARD) {
			pr_warn("%s: Stopping the watchdog\n", __func__);
			watchdog_stop();
			return 0;
		}

		if (options & WDIOS_ENABLECARD) {
			pr_warn("%s: Starting the watchdog\n", __func__);

			if (watchdog_device.started)
				return -EBUSY;

			if (check_timeouts(pre_timeout, timeout)) {
				pr_warn("%s: Invalid thresholds\n",
					__func__);
				return -EINVAL;
			}
			if (watchdog_config_and_start(timeout, pre_timeout))
				return -EINVAL;
			return 0;
		}
		return 0;
	default:
		return -ENOTTY;
	}
}

static int watchdog_set_reset_type(int reset_type)
{
	int ret;
	struct ipc_wd_on_timeout {
		u32 reset_type;
	} ipc_wd_on_timeout = { reset_type };

	ret = rpmsg_send_command(watchdog_instance, IPC_WATCHDOG,
				 SCU_WATCHDOG_SET_ACTION_ON_TIMEOUT,
				 (u8 *)&ipc_wd_on_timeout, NULL,
				 sizeof(ipc_wd_on_timeout), 0);
	if (ret) {
		pr_crit("Error setting watchdog action: %d\n", ret);
		return -EIO;
	}

	watchdog_device.normal_wd_action = reset_type;

	return 0;
}