/*
 * Copyright (c) 2023 PHYTEC Messtechnik GmbH
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <zephyr/drivers/gpio.h>

#ifndef ZEPHYR_DRIVERS_SENSOR_TMD2620_TMD2620_H_
#define ZEPHYR_DRIVERS_SENSOR_TMD2620_TMD2620_H_

#define TMD2620_CHIP_ID (0b110101 << 2)

#define TMD2620_ENABLE_REG 0x80
#define TMD2620_ENABLE_WEN BIT(3)
#define TMD2620_ENABLE_PEN BIT(2)
#define TMD2620_ENABLE_PON BIT(0)

/* PRATE register defines the time between proximity measurements
 * while averaging is turned on.
 * Formular: time between measurements = REG_VALUE * 88µs
 */
#define TMD2620_PRATE_REG 0x82

/*
 * WTIME Register defines the wait time between measurements.
 * Formular: Wait time = (REG_VALUE + 1) * 2.81ms
 * If the WLONG bit is set:
 * Formular: Wait time = (REG_VALUE + 1) * 33.8ms
 */
#define TMD2620_WTIME_REG 0x83

/*
 * PILT Register defines the low interrupt threshold.
 * If the value generated by the proximity channel is below the
 * threshold, PPERS value is reached and PIEN is enabled, the INT pin will be asserted
 */
#define TMD2620_PILT_REG 0x88

/*
 * PILT Register defines the high interrupt threshold.
 * If the value generated by the proximity channel is above the
 * threshold, PPERS value is reached and PIEN is enabled, the INT pin will be asserted
 */
#define TMD2620_PIHT_REG 0x8A

/*
 * PERS register controls the interrupt filtering capabilities.
 * With the PPERS bits its possible to configure how many values out of
 * the threshold have to be generated until a interrupt is generated.
 * 0: every read cycle
 * 1: any proximiy value outside of range
 * 2: 2 consecutive values outside of range
 * ...
 */
#define TMD2620_PERS_REG   0x8C
#define TMD2620_PERS_PPERS (BIT(4) | BIT(5) | BIT(6) | BIT(7))

#define TMD2620_CFG0_REG   0x8D
#define TMD2620_CFG0_WLONG BIT(2)

#define TMD2620_PCFG0_REG	      0x8E
/* pulse length */
#define TMD2620_PCFG0_PPULSE_LEN_4US  0
#define TMD2620_PCFG0_PPULSE_LEN_8US  BIT(6)
#define TMD2620_PCFG0_PPULSE_LEN_16US BIT(7)
#define TMD2620_PCFG0_PPULSE_LEN_32US (BIT(6) | BIT(7))
#define TMD2620_PCFG0_PPULSE_LEN_MASK TMD2620_PCFG0_PPULSE_LEN_32US
/* maximum number of pulses */
#define TMD2620_PCFG0_PPULSE	      (BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5))

#define TMD2620_PCFG1_REG      0x8F
/* proximity gain control */
#define TMD2620_PCFG1_PGAIN_X1 0
#define TMD2620_PCFG1_PGAIN_X2 BIT(6)
#define TMD2620_PCFG1_PGAIN_X4 BIT(7)
#define TMD2620_PCFG1_PGAIN_X8 (BIT(6) | BIT(7))
#define TMD2620_PCFG1_PLDRIVE  (BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4))

#define TMD2620_REVID_REG 0x91

#define TMD2620_ID_REG 0x92

#define TMD2620_STATUS_REG	       0x93
#define TMD2620_STATUS_PSAT	       BIT(6)
#define TMD2620_STATUS_PINT	       BIT(5)
#define TMD2620_STATUS_CINT	       BIT(3)
#define TMD2620_STATUS_ZINT	       BIT(2)
#define TMD2620_STATUS_PSAT_REFLECTIVE BIT(1)
#define TMD2620_STATUS_PSAT_AMBIENT    BIT(0)

/* PDATA contains the 1-byte proximity data */
#define TMD2620_PDATA_REG 0x9C

#define TMD2620_REVID2_REG    0x9E
#define TMD2620_REVID2_AUX_ID (BIT(0) | BIT(1) | BIT(2) | BIT(3))

#define TMD2620_CFG3_REG	    0xAB
#define TMD2620_CFG3_INT_READ_CLEAR BIT(7)
#define TMD2620_CFG3_SAI	    BIT(4)

#define TMD2620_POFFSET_L_REG 0xC0

#define TMD2620_POFFSET_H_REG 0xC1

#define TMD2620_CALIB_REG		 0xD7
#define TMD2620_CALIB_ELECTRICAL	 BIT(5)
#define TMD2620_CALIB_START_OFFSET_CALIB BIT(0)

#define TMD2620_CALIBCFG_REG			 0xD9
#define TMD2620_CALIBCFG_BINSRCH_TARGET		 (BIT(5) | BIT(6) | BIT(7))
#define TMD2620_CALIBCFG_PROX_AUTO_OFFSET_ADJUST BIT(3)
#define TMD2620_CALIBCFG_PRX_DATA_AVG		 (BIT(0) | BIT(1) | BIT(2))

#define TMD2620_CALIBSTAT_REG		  0xDC
#define TMD2620_CALIBSTAT_OFFSET_ADJUSTED BIT(2)
#define TMD2620_CALIBSTAT_CALIB_FINISHED  BIT(0)

#define TMD2620_INTENAB_REG   0xDD
#define TMD2620_INTENAB_PSIEN BIT(6)
#define TMD2620_INTENAB_PIEN  BIT(5)
#define TMD2620_INTENAB_CIEN  BIT(3)
#define TMD2620_INTENAB_ZIEN  BIT(2)

#define TMD2620_PGAIN_DEFAULT	   TMD2620_PCFG1_PGAIN_X4
#define TMD2620_PLDRIVE_DEFAULT	   7
#define TMD2620_PPULSE_DEFAULT	   15
#define TMD2620_PPULSE_LEN_DEFAULT TMD2620_PCFG0_PPULSE_LEN_16US

struct tmd2620_config {
	struct i2c_dt_spec i2c;
	struct gpio_dt_spec int_gpio;
	uint8_t inst;
	uint8_t proximity_gain;
	uint8_t proximity_pulse_length;
	uint8_t proximity_pulse_count;
	uint8_t proximity_high_threshold;
	uint8_t proximity_low_threshold;
	uint8_t proximity_led_drive_strength;
	uint8_t proximity_interrupt_filter;
	uint8_t enable_wait_mode;
	uint8_t wait_time_factor;
	uint8_t wait_long;
};

struct tmd2620_data {
	struct gpio_callback gpio_cb;
	const struct device *dev;
	uint8_t pdata;

#ifdef CONFIG_TMD2620_TRIGGER
	sensor_trigger_handler_t p_th_handler;
	const struct sensor_trigger *p_th_trigger;
	struct k_work work;
#else
	struct k_sem data_sem;
#endif
};

static void tmd2620_setup_int(const struct tmd2620_config *config, bool enable)
{
	unsigned int flags = enable ? GPIO_INT_EDGE_TO_ACTIVE : GPIO_INT_DISABLE;

	gpio_pin_interrupt_configure_dt(&config->int_gpio, flags);
}

#ifdef CONFIG_TMD2620_TRIGGER
void tmd2620_work_cb(struct k_work *work);

int tmd2620_attr_set(const struct device *dev, enum sensor_channel chan, enum sensor_attribute attr,
		     const struct sensor_value *val);

int tmd2620_trigger_set(const struct device *dev, const struct sensor_trigger *trigg,
			sensor_trigger_handler_t handler);
#endif

#endif /* ZEPHYR_DRIVERS_SENSOR_TMD2620_TMD2620_H_ */
