/*
 * Copyright (c) 2023, Prevas A/S
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#define DT_DRV_COMPAT ti_tps382x

#include <errno.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/watchdog.h>
#include <zephyr/logging/log.h>

LOG_MODULE_REGISTER(wdt_ti_tps382x, CONFIG_WDT_LOG_LEVEL);

struct ti_tps382x_config {
	struct gpio_dt_spec wdi_gpio;
	int timeout;
};

static int ti_tps382x_init(const struct device *dev)
{
	const struct ti_tps382x_config *config = dev->config;

	if (!gpio_is_ready_dt(&config->wdi_gpio)) {
		LOG_ERR("WDI gpio not ready");
		return -ENODEV;
	}

	return 0;
}

static int ti_tps382x_setup(const struct device *dev, uint8_t options)
{
	const struct ti_tps382x_config *config = dev->config;

	return gpio_pin_configure_dt(&config->wdi_gpio, GPIO_OUTPUT);
}

static int ti_tps382x_disable(const struct device *dev)
{
	const struct ti_tps382x_config *config = dev->config;

	/* The watchdog timer can be disabled by disconnecting the WDI pin from
	 * the system. Do this by changing the gpio to an input (tri-state).
	 */
	return gpio_pin_configure_dt(&config->wdi_gpio, GPIO_INPUT);
}

static int ti_tps382x_install_timeout(const struct device *dev,
				      const struct wdt_timeout_cfg *cfg)
{
	const struct ti_tps382x_config *config = dev->config;

	if (cfg->window.max != config->timeout) {
		LOG_ERR("Upper limit of watchdog timeout must be %d not %u",
			config->timeout, cfg->window.max);
		return -EINVAL;
	} else if (cfg->window.min != 0) {
		LOG_ERR("Window timeouts not supported");
		return -EINVAL;
	} else if (cfg->callback != NULL) {
		LOG_ERR("Callbacks not supported");
		return -EINVAL;
	}

	return 0;
}

static int ti_tps382x_feed(const struct device *dev, int channel_id)
{
	const struct ti_tps382x_config *config = dev->config;

	return gpio_pin_toggle_dt(&config->wdi_gpio);
}

static const struct wdt_driver_api ti_tps382x_api = {
	.setup = ti_tps382x_setup,
	.disable = ti_tps382x_disable,
	.install_timeout = ti_tps382x_install_timeout,
	.feed = ti_tps382x_feed,
};

#define WDT_TI_TPS382X_INIT(n)                                                \
	static const struct ti_tps382x_config ti_tps382x_##n##config = {      \
		.wdi_gpio = GPIO_DT_SPEC_INST_GET(n, wdi_gpios),              \
		.timeout = DT_INST_PROP(n, timeout_period),                   \
	};                                                                    \
                                                                              \
	DEVICE_DT_INST_DEFINE(                                                \
		n, ti_tps382x_init, NULL, NULL, &ti_tps382x_##n##config,      \
		POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,              \
		&ti_tps382x_api                                               \
	);

DT_INST_FOREACH_STATUS_OKAY(WDT_TI_TPS382X_INIT);
