/*
 * Copyright (c) 2021 ITE Corporation. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0
 */

#define DT_DRV_COMPAT ite_it8xxx2_watchdog

#include <drivers/watchdog.h>
#include <errno.h>
#include <soc.h>

#include <logging/log.h>
#define LOG_LEVEL CONFIG_WDT_LOG_LEVEL
LOG_MODULE_REGISTER(wdt_ite_it8xxx2);

#define IT8XXX2_WATCHDOG_MAGIC_BYTE			0x5c
#define WARNING_TIMER_PERIOD_MS_TO_1024HZ_COUNT(ms)	((ms) * 1024 / 1000)

/* enter critical period or not */
static int wdt_warning_fired;

/* device config */
struct wdt_it8xxx2_config {
	/* wdt register base address */
	struct wdt_it8xxx2_regs *base;
};

/* driver data */
struct wdt_it8xxx2_data {
	/* timeout callback used to handle watchdog event */
	wdt_callback_t callback;
	/* indicate whether a watchdog timeout is installed */
	bool timeout_installed;
	/* watchdog feed timeout in milliseconds */
	uint32_t timeout;
};

static int wdt_it8xxx2_install_timeout(const struct device *dev,
					  const struct wdt_timeout_cfg *config)
{
	const struct wdt_it8xxx2_config *const wdt_config = dev->config;
	struct wdt_it8xxx2_data *data = dev->data;
	struct wdt_it8xxx2_regs *const inst = wdt_config->base;

	/* if watchdog is already running */
	if ((inst->ETWCFG) & IT8XXX2_WDT_LEWDCNTL) {
		return -EBUSY;
	}

	/*
	 * Not support lower limit window timeouts (min value must be equal to
	 * 0). Upper limit window timeouts can't be 0 when we install timeout.
	 */
	if ((config->window.min != 0) || (config->window.max == 0)) {
		data->timeout_installed = false;
		return -EINVAL;
	}

	/* save watchdog timeout */
	data->timeout = config->window.max;

	/* install user timeout isr */
	data->callback = config->callback;

	/* mark installed */
	data->timeout_installed = true;

	return 0;
}

static int wdt_it8xxx2_setup(const struct device *dev, uint8_t options)
{
	const struct wdt_it8xxx2_config *const wdt_config = dev->config;
	struct wdt_it8xxx2_data *data = dev->data;
	struct wdt_it8xxx2_regs *const inst = wdt_config->base;
	uint16_t cnt0 = WARNING_TIMER_PERIOD_MS_TO_1024HZ_COUNT(data->timeout);
	uint16_t cnt1 = WARNING_TIMER_PERIOD_MS_TO_1024HZ_COUNT((data->timeout
			+ CONFIG_WDT_ITE_WARNING_LEADING_TIME_MS));

	/* disable pre-warning timer1 interrupt */
	irq_disable(DT_INST_IRQN(0));

	if (!data->timeout_installed) {
		LOG_ERR("No valid WDT timeout installed");
		return -EINVAL;
	}

	if ((inst->ETWCFG) & IT8XXX2_WDT_LEWDCNTL) {
		LOG_ERR("WDT is already running");
		return -EBUSY;
	}

	if ((options & WDT_OPT_PAUSE_IN_SLEEP) != 0) {
		LOG_ERR("WDT_OPT_PAUSE_IN_SLEEP is not supported");
		return -ENOTSUP;
	}

	/* pre-warning timer1 is 16-bit counter down timer */
	inst->ET1CNTLHR = (cnt0 >> 8) & 0xff;
	inst->ET1CNTLLR = cnt0 & 0xff;

	/* clear pre-warning timer1 interrupt status */
	ite_intc_isr_clear(DT_INST_IRQN(0));

	/* enable pre-warning timer1 interrupt */
	irq_enable(DT_INST_IRQN(0));

	/* don't stop watchdog timer counting */
	inst->ETWCTRL &= ~IT8XXX2_WDT_EWDSCEN;

	/* set watchdog timer count */
	inst->EWDCNTHR = (cnt1 >> 8) & 0xff;
	inst->EWDCNTLR = cnt1 & 0xff;

	/* allow to write timer1 count register */
	inst->ETWCFG &= ~IT8XXX2_WDT_LET1CNTL;

	/*
	 * bit5 = 1: enable key match function to touch watchdog
	 * bit4 = 1: select watchdog clock source from prescaler
	 * bit3 = 1: lock watchdog count register (also mark as watchdog running)
	 * bit1 = 1: lock timer1 prescaler register
	 */
	inst->ETWCFG = (IT8XXX2_WDT_EWDKEYEN |
			IT8XXX2_WDT_EWDSRC |
			IT8XXX2_WDT_LEWDCNTL |
			IT8XXX2_WDT_LET1PS);

	LOG_DBG("WDT Setup and enabled");

	return 0;
}

/*
 * reload the WDT and pre-warning timer1 counter
 *
 * @param dev Pointer to the device structure for the driver instance.
 * @param channel_id Index of the fed channel, and we only support
 *                   channel_id = 0 now.
 */
static int wdt_it8xxx2_feed(const struct device *dev, int channel_id)
{
	const struct wdt_it8xxx2_config *const wdt_config = dev->config;
	struct wdt_it8xxx2_data *data = dev->data;
	struct wdt_it8xxx2_regs *const inst = wdt_config->base;
	uint16_t cnt0 = WARNING_TIMER_PERIOD_MS_TO_1024HZ_COUNT(data->timeout);

	ARG_UNUSED(channel_id);

	/* reset pre-warning timer1 */
	inst->ETWCTRL |= IT8XXX2_WDT_ET1RST;

	/* restart watchdog timer */
	inst->EWDKEYR = IT8XXX2_WATCHDOG_MAGIC_BYTE;

	/* reset pre-warning timer1 to default if time is touched */
	if (wdt_warning_fired) {
		wdt_warning_fired = 0;

		/* pre-warning timer1 is 16-bit counter down timer */
		inst->ET1CNTLHR = (cnt0 >> 8) & 0xff;
		inst->ET1CNTLLR = cnt0 & 0xff;

		/* clear timer1 interrupt status */
		ite_intc_isr_clear(DT_INST_IRQN(0));

		/* enable timer1 interrupt */
		irq_enable(DT_INST_IRQN(0));
	}

	LOG_DBG("WDT Kicking");

	return 0;
}

static int wdt_it8xxx2_disable(const struct device *dev)
{
	const struct wdt_it8xxx2_config *const wdt_config = dev->config;
	struct wdt_it8xxx2_data *data = dev->data;
	struct wdt_it8xxx2_regs *const inst = wdt_config->base;

	/* stop watchdog timer counting */
	inst->ETWCTRL |= IT8XXX2_WDT_EWDSCEN;

	/* unlock watchdog count register (also mark as watchdog not running) */
	inst->ETWCFG &= ~IT8XXX2_WDT_LEWDCNTL;

	/* disable pre-warning timer1 interrupt */
	irq_disable(DT_INST_IRQN(0));

	/* mark uninstalled */
	data->timeout_installed = false;

	LOG_DBG("WDT Disabled");

	return 0;
}

static void wdt_it8xxx2_isr(const struct device *dev)
{
	const struct wdt_it8xxx2_config *const wdt_config = dev->config;
	struct wdt_it8xxx2_data *data = dev->data;
	struct wdt_it8xxx2_regs *const inst = wdt_config->base;

	/* clear pre-warning timer1 interrupt status */
	ite_intc_isr_clear(DT_INST_IRQN(0));

	/* reset pre-warning timer1 */
	inst->ETWCTRL |= IT8XXX2_WDT_ET1RST;

	/* callback function, ex. print warning message */
	if (data->callback) {
		data->callback(dev, 0);
	}

#ifdef CONFIG_WDT_ITE_REDUCE_WARNING_LEADING_TIME
	/*
	 * Once warning timer triggered: if watchdog timer isn't reloaded,
	 * then we will reduce interval of warning timer to 30ms to print
	 * more warning messages before watchdog reset.
	 */
	if (!wdt_warning_fired) {
		uint16_t cnt0 = WARNING_TIMER_PERIOD_MS_TO_1024HZ_COUNT(30);

		/* pre-warning timer1 is 16-bit counter down timer */
		inst->ET1CNTLHR = (cnt0 >> 8) & 0xff;
		inst->ET1CNTLLR = cnt0 & 0xff;

		/* clear pre-warning timer1 interrupt status */
		ite_intc_isr_clear(DT_INST_IRQN(0));
	}
#endif
	wdt_warning_fired++;

	LOG_DBG("WDT ISR");
}

static const struct wdt_driver_api wdt_it8xxx2_api = {
	.setup = wdt_it8xxx2_setup,
	.disable = wdt_it8xxx2_disable,
	.install_timeout = wdt_it8xxx2_install_timeout,
	.feed = wdt_it8xxx2_feed,
};

static int wdt_it8xxx2_init(const struct device *dev)
{
	const struct wdt_it8xxx2_config *const wdt_config = dev->config;
	struct wdt_it8xxx2_regs *const inst = wdt_config->base;

	if (IS_ENABLED(CONFIG_WDT_DISABLE_AT_BOOT)) {
		wdt_it8xxx2_disable(dev);
	}

	/* unlock access to watchdog registers */
	inst->ETWCFG = 0x00;

	/* set WDT and timer1 to use 1.024kHz clock */
	inst->ET1PSR = IT8XXX2_WDT_ETPS_1P024_KHZ;

	/* set WDT key match enabled and WDT clock to use ET1PSR */
	inst->ETWCFG = (IT8XXX2_WDT_EWDKEYEN |
			IT8XXX2_WDT_EWDSRC);

	/*
	 * select the mode that watchdog can be stopped, this is needed for
	 * wdt_it8xxx2_disable() api and WDT_OPT_PAUSE_HALTED_BY_DBG flag
	 */
	inst->ETWCTRL |= IT8XXX2_WDT_EWDSCMS;

	IRQ_CONNECT(DT_INST_IRQN(0), 0, wdt_it8xxx2_isr,
		    DEVICE_DT_INST_GET(0), 0);
	return 0;
}

static const struct wdt_it8xxx2_config wdt_it8xxx2_cfg_0 = {
	.base = (struct wdt_it8xxx2_regs *)DT_INST_REG_ADDR(0),
};

static struct wdt_it8xxx2_data wdt_it8xxx2_dev_data;

DEVICE_DT_INST_DEFINE(0, wdt_it8xxx2_init, NULL,
			&wdt_it8xxx2_dev_data, &wdt_it8xxx2_cfg_0,
			PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
			&wdt_it8xxx2_api);
