blob: b616aff934fc93f2ce64ba36213ad19cfa20bc34 [file] [log] [blame]
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2012-2019, 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;
/**
* 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__ */