/*
 * Copyright (c) 2024 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <nrfx_comp.h>

#include <zephyr/drivers/comparator/nrf_comp.h>
#include <zephyr/kernel.h>
#include <zephyr/pm/device.h>

#define DT_DRV_COMPAT nordic_nrf_comp

#define SHIM_NRF_COMP_DT_INST_REFSEL(inst) \
	_CONCAT(COMP_NRF_COMP_REFSEL_, DT_INST_STRING_TOKEN(inst, refsel))

#define SHIM_NRF_COMP_DT_INST_REFSEL_IS_AREF(inst) \
	DT_INST_ENUM_HAS_VALUE(inst, refsel, AREF)

#define SHIM_NRF_COMP_DT_INST_EXTREFSEL(inst) \
	_CONCAT(COMP_NRF_COMP_EXTREFSEL_, DT_INST_STRING_TOKEN(inst, extrefsel))

#define SHIM_NRF_COMP_DT_INST_MAIN_MODE_IS_SE(inst) \
	DT_INST_ENUM_HAS_VALUE(inst, main_mode, SE)

#define SHIM_NRF_COMP_DT_INST_MAIN_MODE_IS_DIFF(inst) \
	DT_INST_ENUM_HAS_VALUE(inst, main_mode, DIFF)

#define SHIM_NRF_COMP_DT_INST_TH_DOWN(inst) \
	DT_INST_PROP(inst, th_down)

#define SHIM_NRF_COMP_DT_INST_TH_UP(inst) \
	DT_INST_PROP(inst, th_up)

#define SHIM_NRF_COMP_DT_INST_SP_MODE(inst) \
	_CONCAT(COMP_NRF_COMP_SP_MODE_, DT_INST_STRING_TOKEN(inst, sp_mode))

#define SHIM_NRF_COMP_DT_INST_ENABLE_HYST(inst) \
	DT_INST_PROP(inst, enable_hyst)

#define SHIM_NRF_COMP_DT_INST_ISOURCE(inst) \
	_CONCAT(COMP_NRF_COMP_ISOURCE_, DT_INST_STRING_TOKEN(inst, isource))

#define SHIM_NRF_COMP_DT_INST_PSEL(inst) \
	_CONCAT(COMP_NRF_COMP_PSEL_, DT_INST_STRING_TOKEN(inst, psel))

#if defined(COMP_HYST_HYST_Hyst40mV)
#define NRF_COMP_HYST_ENABLED NRF_COMP_HYST_40MV
#elif defined(COMP_HYST_HYST_Hyst50mV)
#define NRF_COMP_HYST_ENABLED NRF_COMP_HYST_50MV
#endif

#define NRF_COMP_HYST_DISABLED NRF_COMP_HYST_NO_HYST

#if defined(NRF_COMP_HYST_ENABLED)
#define NRF_COMP_HAS_HYST 1
#else
#define NRF_COMP_HAS_HYST 0
#endif

struct shim_nrf_comp_data {
	uint32_t event_mask;
	bool started;
	atomic_t triggered;
	comparator_callback_t callback;
	void *user_data;
};

#if (NRF_COMP_HAS_AIN_AS_PIN)
static const uint32_t shim_nrf_comp_ain_map[] = {
#if defined(CONFIG_SOC_NRF54H20) || defined(CONFIG_SOC_NRF9280)
	NRF_PIN_PORT_TO_PIN_NUMBER(0U, 1),
	NRF_PIN_PORT_TO_PIN_NUMBER(1U, 1),
	NRF_PIN_PORT_TO_PIN_NUMBER(2U, 1),
	NRF_PIN_PORT_TO_PIN_NUMBER(3U, 1),
	NRF_PIN_PORT_TO_PIN_NUMBER(4U, 1),
	NRF_PIN_PORT_TO_PIN_NUMBER(5U, 1),
	NRF_PIN_PORT_TO_PIN_NUMBER(6U, 1),
	NRF_PIN_PORT_TO_PIN_NUMBER(7U, 1),
#elif defined(CONFIG_SOC_NRF54L05) || defined(CONFIG_SOC_NRF54L10) || defined(CONFIG_SOC_NRF54L15)
	NRF_PIN_PORT_TO_PIN_NUMBER(4U, 1),
	NRF_PIN_PORT_TO_PIN_NUMBER(5U, 1),
	NRF_PIN_PORT_TO_PIN_NUMBER(6U, 1),
	NRF_PIN_PORT_TO_PIN_NUMBER(7U, 1),
	NRF_PIN_PORT_TO_PIN_NUMBER(11U, 1),
	NRF_PIN_PORT_TO_PIN_NUMBER(12U, 1),
	NRF_PIN_PORT_TO_PIN_NUMBER(13U, 1),
	NRF_PIN_PORT_TO_PIN_NUMBER(14U, 1),
#endif
};
#endif

#if SHIM_NRF_COMP_DT_INST_MAIN_MODE_IS_SE(0)
BUILD_ASSERT(SHIM_NRF_COMP_DT_INST_TH_DOWN(0) < 64);
BUILD_ASSERT(SHIM_NRF_COMP_DT_INST_TH_UP(0) < 64);
#endif

#if NRF_COMP_HAS_AIN_AS_PIN
BUILD_ASSERT((COMP_NRF_COMP_PSEL_AIN0 == 0));
BUILD_ASSERT((COMP_NRF_COMP_PSEL_AIN7 == 7));
BUILD_ASSERT((COMP_NRF_COMP_EXTREFSEL_AIN0 == 0));
BUILD_ASSERT((COMP_NRF_COMP_EXTREFSEL_AIN7 == 7));
#else
#ifndef COMP_PSEL_PSEL_AnalogInput4
BUILD_ASSERT(SHIM_NRF_COMP_DT_INST_PSEL(0) != COMP_NRF_COMP_PSEL_AIN4);
#endif

#ifndef COMP_PSEL_PSEL_AnalogInput5
BUILD_ASSERT(SHIM_NRF_COMP_DT_INST_PSEL(0) != COMP_NRF_COMP_PSEL_AIN5);
#endif

#ifndef COMP_PSEL_PSEL_AnalogInput6
BUILD_ASSERT(SHIM_NRF_COMP_DT_INST_PSEL(0) != COMP_NRF_COMP_PSEL_AIN6);
#endif

#ifndef COMP_PSEL_PSEL_AnalogInput7
BUILD_ASSERT(SHIM_NRF_COMP_DT_INST_PSEL(0) != COMP_NRF_COMP_PSEL_AIN7);
#endif
#endif

#ifndef COMP_PSEL_PSEL_VddDiv2
BUILD_ASSERT(SHIM_NRF_COMP_DT_INST_PSEL(0) != COMP_NRF_COMP_PSEL_VDD_DIV2);
#endif

#ifndef COMP_PSEL_PSEL_VddhDiv5
BUILD_ASSERT(SHIM_NRF_COMP_DT_INST_PSEL(0) != COMP_NRF_COMP_PSEL_VDDH_DIV5);
#endif

#ifndef COMP_MODE_SP_Normal
BUILD_ASSERT(SHIM_NRF_COMP_DT_INST_SP_MODE(0) != COMP_NRF_COMP_SP_MODE_NORMAL);
#endif

#if NRF_COMP_HAS_ISOURCE
#ifndef COMP_ISOURCE_ISOURCE_Ien2uA5
BUILD_ASSERT(SHIM_NRF_COMP_DT_INST_ISOURCE(0) != COMP_NRF_COMP_ISOURCE_2UA5);
#endif

#ifndef COMP_ISOURCE_ISOURCE_Ien5uA
BUILD_ASSERT(SHIM_NRF_COMP_DT_INST_ISOURCE(0) != COMP_NRF_COMP_ISOURCE_5UA);
#endif

#ifndef COMP_ISOURCE_ISOURCE_Ien10uA
BUILD_ASSERT(SHIM_NRF_COMP_DT_INST_ISOURCE(0) != COMP_NRF_COMP_ISOURCE_10UA);
#endif
#endif

#if SHIM_NRF_COMP_DT_INST_REFSEL_IS_AREF(0)
#ifndef COMP_EXTREFSEL_EXTREFSEL_AnalogReference4
BUILD_ASSERT(SHIM_NRF_COMP_DT_INST_EXTREFSEL(0) != COMP_NRF_COMP_EXTREFSEL_AIN4);
#endif

#ifndef COMP_EXTREFSEL_EXTREFSEL_AnalogReference5
BUILD_ASSERT(SHIM_NRF_COMP_DT_INST_EXTREFSEL(0) != COMP_NRF_COMP_EXTREFSEL_AIN5);
#endif

#ifndef COMP_EXTREFSEL_EXTREFSEL_AnalogReference6
BUILD_ASSERT(SHIM_NRF_COMP_DT_INST_EXTREFSEL(0) != COMP_NRF_COMP_EXTREFSEL_AIN6);
#endif

#ifndef COMP_EXTREFSEL_EXTREFSEL_AnalogReference7
BUILD_ASSERT(SHIM_NRF_COMP_DT_INST_EXTREFSEL(0) != COMP_NRF_COMP_EXTREFSEL_AIN7);
#endif
#endif

#if SHIM_NRF_COMP_DT_INST_MAIN_MODE_IS_SE(0)
#ifndef COMP_REFSEL_REFSEL_Int1V8
BUILD_ASSERT(SHIM_NRF_COMP_DT_INST_REFSEL(0) != COMP_NRF_COMP_REFSEL_INT_1V8);
#endif

#ifndef COMP_REFSEL_REFSEL_Int2V4
BUILD_ASSERT(SHIM_NRF_COMP_DT_INST_REFSEL(0) != COMP_NRF_COMP_REFSEL_INT_2V4);
#endif

#ifndef COMP_REFSEL_REFSEL_AVDDAO1V8
BUILD_ASSERT(SHIM_NRF_COMP_DT_INST_REFSEL(0) != COMP_NRF_COMP_REFSEL_AVDDAO1V8);
#endif

#ifndef COMP_REFSEL_REFSEL_VDD
BUILD_ASSERT(SHIM_NRF_COMP_DT_INST_REFSEL(0) != COMP_NRF_COMP_REFSEL_VDD);
#endif
#endif

#if SHIM_NRF_COMP_DT_INST_MAIN_MODE_IS_DIFF(0)
#if SHIM_NRF_COMP_DT_INST_ENABLE_HYST(0)
BUILD_ASSERT(NRF_COMP_HAS_HYST);
#endif
#endif

#if SHIM_NRF_COMP_DT_INST_MAIN_MODE_IS_SE(0)
static const struct comp_nrf_comp_se_config shim_nrf_comp_config0 = {
	.psel = SHIM_NRF_COMP_DT_INST_PSEL(0),
	.sp_mode = SHIM_NRF_COMP_DT_INST_SP_MODE(0),
	.isource = SHIM_NRF_COMP_DT_INST_ISOURCE(0),
#if SHIM_NRF_COMP_DT_INST_REFSEL_IS_AREF(0)
	.extrefsel = SHIM_NRF_COMP_DT_INST_EXTREFSEL(0),
#endif
	.refsel = SHIM_NRF_COMP_DT_INST_REFSEL(0),
	.th_down = SHIM_NRF_COMP_DT_INST_TH_DOWN(0),
	.th_up = SHIM_NRF_COMP_DT_INST_TH_UP(0),
};
#else
static const struct comp_nrf_comp_diff_config shim_nrf_comp_config0 = {
	.psel = SHIM_NRF_COMP_DT_INST_PSEL(0),
	.sp_mode = SHIM_NRF_COMP_DT_INST_SP_MODE(0),
	.isource = SHIM_NRF_COMP_DT_INST_ISOURCE(0),
	.extrefsel = SHIM_NRF_COMP_DT_INST_EXTREFSEL(0),
	.enable_hyst = SHIM_NRF_COMP_DT_INST_ENABLE_HYST(0),
};
#endif

static struct shim_nrf_comp_data shim_nrf_comp_data0;

#if CONFIG_PM_DEVICE
static bool shim_nrf_comp_is_resumed(void)
{
	enum pm_device_state state;

	(void)pm_device_state_get(DEVICE_DT_INST_GET(0), &state);
	return state == PM_DEVICE_STATE_ACTIVE;
}
#else
static bool shim_nrf_comp_is_resumed(void)
{
	return true;
}
#endif

static void shim_nrf_comp_start(void)
{
	if (shim_nrf_comp_data0.started) {
		return;
	}

	nrfx_comp_start(shim_nrf_comp_data0.event_mask, 0);
	shim_nrf_comp_data0.started = true;
}

static void shim_nrf_comp_stop(void)
{
	if (!shim_nrf_comp_data0.started) {
		return;
	}

	nrfx_comp_stop();
	shim_nrf_comp_data0.started = false;
}

static int shim_nrf_comp_pm_callback(const struct device *dev, enum pm_device_action action)
{
	ARG_UNUSED(dev);

	switch (action) {
	case PM_DEVICE_ACTION_RESUME:
		shim_nrf_comp_start();
		break;

#if CONFIG_PM_DEVICE
	case PM_DEVICE_ACTION_SUSPEND:
		shim_nrf_comp_stop();
		break;
#endif

	default:
		return -ENOTSUP;
	}

	return 0;
}

#if (NRF_COMP_HAS_AIN_AS_PIN)
static int shim_nrf_comp_psel_to_nrf(enum comp_nrf_comp_psel shim,
				     nrf_comp_input_t *nrf)
{
	if (shim >= ARRAY_SIZE(shim_nrf_comp_ain_map)) {
		return -EINVAL;
	}

	*nrf = shim_nrf_comp_ain_map[(uint32_t)shim];
	return 0;
}
#else
static int shim_nrf_comp_psel_to_nrf(enum comp_nrf_comp_psel shim,
				     nrf_comp_input_t *nrf)
{
	switch (shim) {
	case COMP_NRF_COMP_PSEL_AIN0:
		*nrf = NRF_COMP_INPUT_0;
		break;

	case COMP_NRF_COMP_PSEL_AIN1:
		*nrf = NRF_COMP_INPUT_1;
		break;

	case COMP_NRF_COMP_PSEL_AIN2:
		*nrf = NRF_COMP_INPUT_2;
		break;

	case COMP_NRF_COMP_PSEL_AIN3:
		*nrf = NRF_COMP_INPUT_3;
		break;

#if defined(COMP_PSEL_PSEL_AnalogInput4)
	case COMP_NRF_COMP_PSEL_AIN4:
		*nrf = NRF_COMP_INPUT_4;
		break;
#endif

#if defined(COMP_PSEL_PSEL_AnalogInput5)
	case COMP_NRF_COMP_PSEL_AIN5:
		*nrf = NRF_COMP_INPUT_5;
		break;
#endif

#if defined(COMP_PSEL_PSEL_AnalogInput6)
	case COMP_NRF_COMP_PSEL_AIN6:
		*nrf = NRF_COMP_INPUT_6;
		break;
#endif

#if defined(COMP_PSEL_PSEL_AnalogInput7)
	case COMP_NRF_COMP_PSEL_AIN7:
		*nrf = NRF_COMP_INPUT_7;
		break;
#endif

#if defined(COMP_PSEL_PSEL_VddDiv2)
	case COMP_NRF_COMP_PSEL_VDD_DIV2:
		*nrf = NRF_COMP_VDD_DIV2;
		break;
#endif

#if defined(COMP_PSEL_PSEL_VddhDiv5)
	case COMP_NRF_COMP_PSEL_VDDH_DIV5:
		*nrf = NRF_COMP_VDDH_DIV5;
		break;
#endif

	default:
		return -EINVAL;
	}

	return 0;
}
#endif

static int shim_nrf_comp_sp_mode_to_nrf(enum comp_nrf_comp_sp_mode shim,
					nrf_comp_sp_mode_t *nrf)
{
	switch (shim) {
	case COMP_NRF_COMP_SP_MODE_LOW:
		*nrf = NRF_COMP_SP_MODE_LOW;
		break;

#if defined(COMP_MODE_SP_Normal)
	case COMP_NRF_COMP_SP_MODE_NORMAL:
		*nrf = NRF_COMP_SP_MODE_NORMAL;
		break;
#endif

	case COMP_NRF_COMP_SP_MODE_HIGH:
		*nrf = NRF_COMP_SP_MODE_HIGH;
		break;

	default:
		return -EINVAL;
	}

	return 0;
}

#if NRF_COMP_HAS_ISOURCE
static int shim_nrf_comp_isource_to_nrf(enum comp_nrf_comp_isource shim,
					nrf_isource_t *nrf)
{
	switch (shim) {
	case COMP_NRF_COMP_ISOURCE_DISABLED:
		*nrf = NRF_COMP_ISOURCE_OFF;
		break;

#if defined(COMP_ISOURCE_ISOURCE_Ien2uA5)
	case COMP_NRF_COMP_ISOURCE_2UA5:
		*nrf = NRF_COMP_ISOURCE_IEN_2UA5;
		break;
#endif

#if defined(COMP_ISOURCE_ISOURCE_Ien5uA)
	case COMP_NRF_COMP_ISOURCE_5UA:
		*nrf = NRF_COMP_ISOURCE_IEN_5UA;
		break;
#endif

#if defined(COMP_ISOURCE_ISOURCE_Ien10uA)
	case COMP_NRF_COMP_ISOURCE_10UA:
		*nrf = NRF_COMP_ISOURCE_IEN_10UA;
		break;
#endif

	default:
		return -EINVAL;
	}

	return 0;
}
#endif

#if (NRF_COMP_HAS_AIN_AS_PIN)
static int shim_nrf_comp_extrefsel_to_nrf(enum comp_nrf_comp_extrefsel shim,
					  nrf_comp_ext_ref_t *nrf)
{
	if (shim >= ARRAY_SIZE(shim_nrf_comp_ain_map)) {
		return -EINVAL;
	}

	*nrf = shim_nrf_comp_ain_map[(uint32_t)shim];
	return 0;
}
#else
static int shim_nrf_comp_extrefsel_to_nrf(enum comp_nrf_comp_extrefsel shim,
					  nrf_comp_ext_ref_t *nrf)
{
	switch (shim) {
	case COMP_NRF_COMP_EXTREFSEL_AIN0:
		*nrf = NRF_COMP_EXT_REF_0;
		break;

	case COMP_NRF_COMP_EXTREFSEL_AIN1:
		*nrf = NRF_COMP_EXT_REF_1;
		break;

	case COMP_NRF_COMP_EXTREFSEL_AIN2:
		*nrf = NRF_COMP_EXT_REF_2;
		break;

	case COMP_NRF_COMP_EXTREFSEL_AIN3:
		*nrf = NRF_COMP_EXT_REF_3;
		break;

#if defined(COMP_EXTREFSEL_EXTREFSEL_AnalogReference4)
	case COMP_NRF_COMP_EXTREFSEL_AIN4:
		*nrf = NRF_COMP_EXT_REF_4;
		break;
#endif

#if defined(COMP_EXTREFSEL_EXTREFSEL_AnalogReference5)
	case COMP_NRF_COMP_EXTREFSEL_AIN5:
		*nrf = NRF_COMP_EXT_REF_5;
		break;
#endif

#if defined(COMP_EXTREFSEL_EXTREFSEL_AnalogReference6)
	case COMP_NRF_COMP_EXTREFSEL_AIN6:
		*nrf = NRF_COMP_EXT_REF_6;
		break;
#endif

#if defined(COMP_EXTREFSEL_EXTREFSEL_AnalogReference7)
	case COMP_NRF_COMP_EXTREFSEL_AIN7:
		*nrf = NRF_COMP_EXT_REF_7;
		break;
#endif

	default:
		return -EINVAL;
	}

	return 0;
}
#endif

static int shim_nrf_comp_refsel_to_nrf(enum comp_nrf_comp_refsel shim,
				       nrf_comp_ref_t *nrf)
{
	switch (shim) {
	case COMP_NRF_COMP_REFSEL_INT_1V2:
		*nrf = NRF_COMP_REF_INT_1V2;
		break;

#if defined(COMP_REFSEL_REFSEL_Int1V8)
	case COMP_NRF_COMP_REFSEL_INT_1V8:
		*nrf = NRF_COMP_REF_INT_1V8;
		break;
#endif

#if defined(COMP_REFSEL_REFSEL_Int2V4)
	case COMP_NRF_COMP_REFSEL_INT_2V4:
		*nrf = NRF_COMP_REF_INT_2V4;
		break;
#endif

#if defined(COMP_REFSEL_REFSEL_AVDDAO1V8)
	case COMP_NRF_COMP_REFSEL_AVDDAO1V8:
		*nrf = NRF_COMP_REF_AVDDAO1V8;
		break;
#endif

#if defined(COMP_REFSEL_REFSEL_VDD)
	case COMP_NRF_COMP_REFSEL_VDD:
		*nrf = NRF_COMP_REF_VDD;
		break;
#endif

	case COMP_NRF_COMP_REFSEL_AREF:
		*nrf = NRF_COMP_REF_AREF;
		break;

	default:
		return -EINVAL;
	}

	return 0;
}

static int shim_nrf_comp_se_config_to_nrf(const struct comp_nrf_comp_se_config *shim,
					  nrfx_comp_config_t *nrf)
{
	if (shim_nrf_comp_refsel_to_nrf(shim->refsel, &nrf->reference)) {
		return -EINVAL;
	}

	if (shim_nrf_comp_extrefsel_to_nrf(shim->extrefsel, &nrf->ext_ref)) {
		return -EINVAL;
	}

	nrf->main_mode = NRF_COMP_MAIN_MODE_SE;

	if (shim->th_down > 63 || shim->th_up > 63) {
		return -EINVAL;
	}

	nrf->threshold.th_down = shim->th_down;
	nrf->threshold.th_up = shim->th_up;

	if (shim_nrf_comp_sp_mode_to_nrf(shim->sp_mode, &nrf->speed_mode)) {
		return -EINVAL;
	}

	nrf->hyst = NRF_COMP_HYST_NO_HYST;

#if NRF_COMP_HAS_ISOURCE
	if (shim_nrf_comp_isource_to_nrf(shim->isource, &nrf->isource)) {
		return -EINVAL;
	}
#else
	if (shim->isource != COMP_NRF_COMP_ISOURCE_DISABLED) {
		return -EINVAL;
	}
#endif

	if (shim_nrf_comp_psel_to_nrf(shim->psel, &nrf->input)) {
		return -EINVAL;
	}

	nrf->interrupt_priority = 0;
	return 0;
}

static int shim_nrf_comp_diff_config_to_nrf(const struct comp_nrf_comp_diff_config *shim,
					    nrfx_comp_config_t *nrf)
{
	nrf->reference = NRF_COMP_REF_AREF;

	if (shim_nrf_comp_extrefsel_to_nrf(shim->extrefsel, &nrf->ext_ref)) {
		return -EINVAL;
	}

	nrf->main_mode = NRF_COMP_MAIN_MODE_DIFF;
	nrf->threshold.th_down = 0;
	nrf->threshold.th_up = 0;

	if (shim_nrf_comp_sp_mode_to_nrf(shim->sp_mode, &nrf->speed_mode)) {
		return -EINVAL;
	}

#if NRF_COMP_HAS_HYST
	if (shim->enable_hyst) {
		nrf->hyst = NRF_COMP_HYST_ENABLED;
	} else {
		nrf->hyst = NRF_COMP_HYST_DISABLED;
	}
#else
	if (shim->enable_hyst) {
		return -EINVAL;
	}
#endif

#if NRF_COMP_HAS_ISOURCE
	if (shim_nrf_comp_isource_to_nrf(shim->isource, &nrf->isource)) {
		return -EINVAL;
	}
#else
	if (shim->isource != COMP_NRF_COMP_ISOURCE_DISABLED) {
		return -EINVAL;
	}
#endif

	if (shim_nrf_comp_psel_to_nrf(shim->psel, &nrf->input)) {
		return -EINVAL;
	}

	nrf->interrupt_priority = 0;
	return 0;
}

static int shim_nrf_comp_get_output(const struct device *dev)
{
	ARG_UNUSED(dev);

	return nrfx_comp_sample();
}

static int shim_nrf_comp_set_trigger(const struct device *dev,
				     enum comparator_trigger trigger)
{
	shim_nrf_comp_stop();

	switch (trigger) {
	case COMPARATOR_TRIGGER_NONE:
		shim_nrf_comp_data0.event_mask = 0;
		break;

	case COMPARATOR_TRIGGER_RISING_EDGE:
		shim_nrf_comp_data0.event_mask = NRF_COMP_INT_UP_MASK;
		break;

	case COMPARATOR_TRIGGER_FALLING_EDGE:
		shim_nrf_comp_data0.event_mask = NRF_COMP_INT_DOWN_MASK;
		break;

	case COMPARATOR_TRIGGER_BOTH_EDGES:
		shim_nrf_comp_data0.event_mask = NRF_COMP_INT_CROSS_MASK;
		break;
	}

	if (shim_nrf_comp_is_resumed()) {
		shim_nrf_comp_start();
	}

	return 0;
}

static int shim_nrf_comp_set_trigger_callback(const struct device *dev,
					      comparator_callback_t callback,
					      void *user_data)
{
	shim_nrf_comp_stop();

	shim_nrf_comp_data0.callback = callback;
	shim_nrf_comp_data0.user_data = user_data;

	if (callback != NULL && atomic_test_and_clear_bit(&shim_nrf_comp_data0.triggered, 0)) {
		callback(dev, user_data);
	}

	if (shim_nrf_comp_is_resumed()) {
		shim_nrf_comp_start();
	}

	return 0;
}

static int shim_nrf_comp_trigger_is_pending(const struct device *dev)
{
	ARG_UNUSED(dev);

	return atomic_test_and_clear_bit(&shim_nrf_comp_data0.triggered, 0);
}

static DEVICE_API(comparator, shim_nrf_comp_api) = {
	.get_output = shim_nrf_comp_get_output,
	.set_trigger = shim_nrf_comp_set_trigger,
	.set_trigger_callback = shim_nrf_comp_set_trigger_callback,
	.trigger_is_pending = shim_nrf_comp_trigger_is_pending,
};

static int shim_nrf_comp_reconfigure(const nrfx_comp_config_t *nrf)
{
	shim_nrf_comp_stop();

	(void)nrfx_comp_reconfigure(nrf);

	if (shim_nrf_comp_is_resumed()) {
		shim_nrf_comp_start();
	}

	return 0;
}

int comp_nrf_comp_configure_se(const struct device *dev,
			       const struct comp_nrf_comp_se_config *config)
{
	nrfx_comp_config_t nrf = {};

	ARG_UNUSED(dev);

	if (shim_nrf_comp_se_config_to_nrf(config, &nrf)) {
		return -EINVAL;
	}

	return shim_nrf_comp_reconfigure(&nrf);
}

int comp_nrf_comp_configure_diff(const struct device *dev,
				 const struct comp_nrf_comp_diff_config *config)
{
	nrfx_comp_config_t nrf = {};

	ARG_UNUSED(dev);

	if (shim_nrf_comp_diff_config_to_nrf(config, &nrf)) {
		return -EINVAL;
	}

	return shim_nrf_comp_reconfigure(&nrf);
}

static void shim_nrf_comp_event_handler(nrf_comp_event_t event)
{
	ARG_UNUSED(event);

	if (shim_nrf_comp_data0.callback == NULL) {
		atomic_set_bit(&shim_nrf_comp_data0.triggered, 0);
		return;
	}

	shim_nrf_comp_data0.callback(DEVICE_DT_INST_GET(0), shim_nrf_comp_data0.user_data);
	atomic_clear_bit(&shim_nrf_comp_data0.triggered, 0);
}

static int shim_nrf_comp_init(const struct device *dev)
{
	nrfx_comp_config_t nrf = {};

	IRQ_CONNECT(DT_INST_IRQN(0),
		    DT_INST_IRQ(0, priority),
		    nrfx_isr,
		    nrfx_comp_irq_handler,
		    0);

	irq_enable(DT_INST_IRQN(0));

#if SHIM_NRF_COMP_DT_INST_MAIN_MODE_IS_SE(0)
	(void)shim_nrf_comp_se_config_to_nrf(&shim_nrf_comp_config0, &nrf);
#else
	(void)shim_nrf_comp_diff_config_to_nrf(&shim_nrf_comp_config0, &nrf);
#endif

	if (nrfx_comp_init(&nrf, shim_nrf_comp_event_handler) != NRFX_SUCCESS) {
		return -ENODEV;
	}

	return pm_device_driver_init(dev, shim_nrf_comp_pm_callback);
}

PM_DEVICE_DT_INST_DEFINE(0, shim_nrf_comp_pm_callback);

DEVICE_DT_INST_DEFINE(0,
		      shim_nrf_comp_init,
		      PM_DEVICE_DT_INST_GET(0),
		      NULL,
		      NULL,
		      POST_KERNEL,
		      CONFIG_COMPARATOR_INIT_PRIORITY,
		      &shim_nrf_comp_api);
