/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
 */

#ifndef __QCOM_ADC_TM_H__
#define __QCOM_ADC_TM_H__

#include <linux/kernel.h>
#include <linux/thermal.h>
#include <linux/interrupt.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/iio/consumer.h>
#include <linux/qpnp/qpnp-revid.h>
#include <linux/adc-tm-clients.h>

#define ADC_TM_DECIMATION_DEFAULT	2
#define ADC_TM_DECIMATION_SAMPLES_MAX	3
#define ADC_TM_DEF_AVG_SAMPLES		0 /* 1 sample */
#define ADC_TM_DEF_HW_SETTLE_TIME	0 /* 15 us */
#define ADC_TM_HW_SETTLE_SAMPLES_MAX	16
#define ADC_TM_AVG_SAMPLES_MAX		16
#define ADC_TM_TIMER1			3 /* 3.9ms */
#define ADC_TM_TIMER2			10 /* 1 second */
#define ADC_TM_TIMER3			4 /* 4 second */
#define ADC_HC_VDD_REF			1875000
#define MAX_PROP_NAME_LEN		32
#define R_PU_100K			100000
#define RATIO_MAX_ADC7			0x4000
#define MAX_CODE_VOLT			0x70e4
#define ADC_CHANNEL_OFFSET		8
#define V_CHAN(x)		(((x).sid << ADC_CHANNEL_OFFSET) | (x).adc_ch)
#define ADC_CHANNEL_MASK		0xff

enum adc_cal_method {
	ADC_NO_CAL = 0,
	ADC_RATIO_CAL = 1,
	ADC_ABS_CAL = 2,
	ADC_CAL_SEL_NONE,
};

enum adc_cal_val {
	ADC_TIMER_CAL = 0,
	ADC_NEW_CAL,
	ADC_CAL_VAL_NONE,
};

enum adc_timer_select {
	ADC_TIMER_SEL_1 = 0,
	ADC_TIMER_SEL_2,
	ADC_TIMER_SEL_3,
	ADC_TIMER_SEL_NONE,
};

enum adc_time_select {
	MEAS_INT_50MS = 0,
	MEAS_INT_100MS,
	MEAS_INT_1S,
	MEAS_INT_SET,
	MEAS_INT_NONE,
};

/**
 * enum adc_tm_rscale_fn_type - Scaling function used to convert the
 *	channels input voltage/temperature to corresponding ADC code that is
 *	applied for thresholds. Check the corresponding channels scaling to
 *	determine the appropriate temperature/voltage units that are passed
 *	to the scaling function. Example battery follows the power supply
 *	framework that needs its units to be in decidegreesC so it passes
 *	deci-degreesC. PA_THERM clients pass the temperature in degrees.
 *	The order below should match the one in the driver for
 *	adc_tm_rscale_fn[].
 */
enum adc_tm_rscale_fn_type {
	SCALE_R_ABSOLUTE = 0,
	SCALE_RSCALE_NONE,
};

struct adc_tm_sensor {
	struct adc_tm_chip		*chip;
	struct thermal_zone_device	*tzd;
	enum adc_cal_val		cal_val;
	enum adc_cal_method		cal_sel;
	unsigned int			hw_settle_time;
	unsigned int			adc_ch;
	unsigned int			btm_ch;
	unsigned int			prescaling;
	unsigned int			timer_select;
	unsigned int			decimation;		/* PMIC7 */
	unsigned int			fast_avg_samples;	/* PMIC7 */
	unsigned int			sid;			/* PMIC7 */
	unsigned int			meas_time;		/* PMIC7 */
	int64_t				high_thr_voltage;	/* PMIC7 */
	int64_t				low_thr_voltage;	/* PMIC7 */
	enum adc_tm_rscale_fn_type	adc_rscale_fn;
	struct iio_channel		*adc;
	struct list_head		thr_list;
	bool				non_thermal;
	bool				high_thr_triggered;
	bool				low_thr_triggered;
	int				high_thr_en;		/* PMIC7 */
	int				low_thr_en;		/* PMIC7 */
	int				meas_en;		/* PMIC7 */
	struct workqueue_struct		*req_wq;
	struct work_struct		work;
};

struct adc_tm_client_info {
	struct list_head			list;
	struct adc_tm_param			*param;
	int32_t						low_thr_requested;
	int32_t						high_thr_requested;
	bool						notify_low_thr;
	bool						notify_high_thr;
	bool						high_thr_set;
	bool						low_thr_set;
	enum adc_tm_state_request	state_request;
};

struct adc_tm_cmn_prop {
	unsigned int			decimation;
	unsigned int			fast_avg_samples;
	unsigned int			timer1;
	unsigned int			timer2;
	unsigned int			timer3;
};

struct adc_tm_ops {
	int (*get_temp)(struct adc_tm_sensor *sensor, int *temp);
	int (*init)(struct adc_tm_chip *chip, uint32_t dt_chans);
	int (*set_trips)(struct adc_tm_sensor *sensor, int low_temp,
							int high_temp);
	int32_t (*channel_measure)(struct adc_tm_chip *chip,
					struct adc_tm_param *param);
	int32_t (*disable_chan)(struct adc_tm_chip *chip,
					struct adc_tm_param *param);
	void (*notify)(struct adc_tm_sensor *adc_tm);
	int (*interrupts_reg)(struct adc_tm_chip *chip);
	int (*shutdown)(struct adc_tm_chip *chip);
};

struct adc_tm_chip {
	struct device			*dev;
	struct list_head		list;
	struct regmap			*regmap;
	u16				base;
	struct adc_tm_cmn_prop		prop;
	spinlock_t			adc_tm_lock;
	struct mutex		adc_mutex_lock;
	const struct adc_tm_ops		*ops;
	const struct adc_tm_data	*data;
	unsigned int			dt_channels;
	struct pmic_revid_data		*pmic_rev_id;
	struct adc_tm_sensor		sensor[0];
};

struct adc_tm_data {
	const struct adc_tm_ops *ops;
	const u32	full_scale_code_volt;
	unsigned int	*decimation;
	unsigned int	*hw_settle;
};

extern const struct adc_tm_data data_adc_tm5;
extern const struct adc_tm_data data_adc_tm7;
extern const struct adc_tm_data data_adc_tm_rev2;

/**
 * Channel index for the corresponding index to adc_tm_channel_select
 */
enum adc_tm_channel_num {
	ADC_TM_CHAN0 = 0,
	ADC_TM_CHAN1,
	ADC_TM_CHAN2,
	ADC_TM_CHAN3,
	ADC_TM_CHAN4,
	ADC_TM_CHAN5,
	ADC_TM_CHAN6,
	ADC_TM_CHAN7,
	ADC_TM_CHAN_NONE
};

/**
 * Channel selection registers for each of the configurable measurements
 * Channels allotment is set at device config for a channel.
 */
enum adc_tm_channel_sel	{
	ADC_TM_M0_ADC_CH_SEL_CTL = 0x60,
	ADC_TM_M1_ADC_CH_SEL_CTL = 0x68,
	ADC_TM_M2_ADC_CH_SEL_CTL = 0x70,
	ADC_TM_M3_ADC_CH_SEL_CTL = 0x78,
	ADC_TM_M4_ADC_CH_SEL_CTL = 0x80,
	ADC_TM_M5_ADC_CH_SEL_CTL = 0x88,
	ADC_TM_M6_ADC_CH_SEL_CTL = 0x90,
	ADC_TM_M7_ADC_CH_SEL_CTL = 0x98,
	ADC_TM_CH_SELECT_NONE
};

/**
 * enum adc_tm_fast_avg_ctl - Provides ability to obtain single result
 *		from the ADC that is an average of multiple measurement
 *		samples. Select number of samples for use in fast
 *		average mode (i.e. 2 ^ value).
 * %ADC_FAST_AVG_SAMPLE_1:   0x0 = 1
 * %ADC_FAST_AVG_SAMPLE_2:   0x1 = 2
 * %ADC_FAST_AVG_SAMPLE_4:   0x2 = 4
 * %ADC_FAST_AVG_SAMPLE_8:   0x3 = 8
 * %ADC_FAST_AVG_SAMPLE_16:  0x4 = 16
 */
enum qpnp_adc_fast_avg_ctl {
	ADC_FAST_AVG_SAMPLE_1 = 0,
	ADC_FAST_AVG_SAMPLE_2,
	ADC_FAST_AVG_SAMPLE_4,
	ADC_FAST_AVG_SAMPLE_8,
	ADC_FAST_AVG_SAMPLE_16,
	ADC_FAST_AVG_SAMPLE_NONE,
};

struct adc_tm_trip_reg_type {
	enum adc_tm_channel_sel		btm_amux_ch;
	uint16_t			low_thr_lsb_addr;
	uint16_t			low_thr_msb_addr;
	uint16_t			high_thr_lsb_addr;
	uint16_t			high_thr_msb_addr;
	u8				multi_meas_en;
	u8				low_thr_int_chan_en;
	u8				high_thr_int_chan_en;
	u8				meas_interval_ctl;
};

/**
 * struct adc_tm_config - Represent ADC Thermal Monitor configuration.
 * @channel: ADC channel for which thermal monitoring is requested.
 * @adc_code: The pre-calibrated digital output of a given ADC releative to the
 *		ADC reference.
 * @high_thr_temp: Temperature at which high threshold notification is required.
 * @low_thr_temp: Temperature at which low threshold notification is required.
 * @low_thr_voltage : Low threshold voltage ADC code used for reverse
 *			calibration.
 * @high_thr_voltage: High threshold voltage ADC code used for reverse
 *			calibration.
 */
struct adc_tm_config {
	int	channel;
	int	adc_code;
	int	prescal;
	int	high_thr_temp;
	int	low_thr_temp;
	int64_t	high_thr_voltage;
	int64_t	low_thr_voltage;
};

/**
 * struct adc_tm_reverse_scale_fn - Reverse scaling prototype
 * @chan: Function pointer to one of the scaling functions
 *	which takes the adc properties and returns the physical result
 */
struct adc_tm_reverse_scale_fn {
	int32_t (*chan)(const struct adc_tm_data *data,
		struct adc_tm_config *tm_config);
};

struct adc_tm_reverse_scale_fn_adc7 {
	int32_t (*chan)(struct adc_tm_config *tm_config);
};

/**
 * struct adc_map_pt - Map the graph representation for ADC channel
 * @x: Represent the ADC digitized code.
 * @y: Represent the physical data which can be temperature, voltage,
 *     resistance.
 */
struct adc_tm_map_pt {
	int32_t x;
	int32_t y;
};

/**
 * struct adc_linear_graph - Represent ADC characteristics.
 * @dy: numerator slope to calculate the gain.
 * @dx: denominator slope to calculate the gain.
 * @gnd: A/D word of the ground reference used for the channel.
 *
 * Each ADC device has different offset and gain parameters which are
 * computed to calibrate the device.
 */
struct adc_tm_linear_graph {
	s32 dy;
	s32 dx;
	s32 gnd;
};

int therm_fwd_scale(int64_t code, uint32_t adc_hc_vdd_ref_mv,
				const struct adc_tm_data *data);

void adc_tm_scale_therm_voltage_100k(struct adc_tm_config *param,
				const struct adc_tm_data *data);

int32_t adc_tm_absolute_rthr(const struct adc_tm_data *data,
			struct adc_tm_config *tm_config);

int therm_fwd_scale_adc7(int64_t code);

void adc_tm_scale_therm_voltage_100k_adc7(struct adc_tm_config *param);

int32_t adc_tm_absolute_rthr_adc7(struct adc_tm_config *tm_config);

int adc_tm_is_valid(struct adc_tm_chip *chip);

#endif /* __QCOM_ADC_TM_H__ */
