xref: /openbmc/linux/drivers/thermal/qcom/qcom-spmi-adc-tm5.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1ca66dca5SDmitry Baryshkov // SPDX-License-Identifier: GPL-2.0-only
2ca66dca5SDmitry Baryshkov /*
3ca66dca5SDmitry Baryshkov  * Copyright (c) 2020 Linaro Limited
4ca66dca5SDmitry Baryshkov  *
5ca66dca5SDmitry Baryshkov  * Based on original driver:
6ca66dca5SDmitry Baryshkov  * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
796f6f333SJishnu Prakash  *
896f6f333SJishnu Prakash  * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
9ca66dca5SDmitry Baryshkov  */
1096f6f333SJishnu Prakash 
11ca66dca5SDmitry Baryshkov #include <linux/bitfield.h>
12ca66dca5SDmitry Baryshkov #include <linux/iio/adc/qcom-vadc-common.h>
13ca66dca5SDmitry Baryshkov #include <linux/iio/consumer.h>
14ca66dca5SDmitry Baryshkov #include <linux/interrupt.h>
15ca66dca5SDmitry Baryshkov #include <linux/module.h>
16ca66dca5SDmitry Baryshkov #include <linux/of.h>
17ca66dca5SDmitry Baryshkov #include <linux/platform_device.h>
18ca66dca5SDmitry Baryshkov #include <linux/regmap.h>
19ca66dca5SDmitry Baryshkov #include <linux/thermal.h>
205618f1beSAndy Shevchenko 
215618f1beSAndy Shevchenko #include <asm/unaligned.h>
22ca66dca5SDmitry Baryshkov 
23ee35f721SDmitry Baryshkov #include "../thermal_hwmon.h"
24ee35f721SDmitry Baryshkov 
25ca66dca5SDmitry Baryshkov /*
26ca66dca5SDmitry Baryshkov  * Thermal monitoring block consists of 8 (ADC_TM5_NUM_CHANNELS) channels. Each
27ca66dca5SDmitry Baryshkov  * channel is programmed to use one of ADC channels for voltage comparison.
28ca66dca5SDmitry Baryshkov  * Voltages are programmed using ADC codes, so we have to convert temp to
29ca66dca5SDmitry Baryshkov  * voltage and then to ADC code value.
30ca66dca5SDmitry Baryshkov  *
31ca66dca5SDmitry Baryshkov  * Configuration of TM channels must match configuration of corresponding ADC
32ca66dca5SDmitry Baryshkov  * channels.
33ca66dca5SDmitry Baryshkov  */
34ca66dca5SDmitry Baryshkov 
35ca66dca5SDmitry Baryshkov #define ADC5_MAX_CHANNEL                        0xc0
36ca66dca5SDmitry Baryshkov #define ADC_TM5_NUM_CHANNELS		8
37ca66dca5SDmitry Baryshkov 
38ca66dca5SDmitry Baryshkov #define ADC_TM5_STATUS_LOW			0x0a
39ca66dca5SDmitry Baryshkov 
40ca66dca5SDmitry Baryshkov #define ADC_TM5_STATUS_HIGH			0x0b
41ca66dca5SDmitry Baryshkov 
42ca66dca5SDmitry Baryshkov #define ADC_TM5_NUM_BTM				0x0f
43ca66dca5SDmitry Baryshkov 
44ca66dca5SDmitry Baryshkov #define ADC_TM5_ADC_DIG_PARAM			0x42
45ca66dca5SDmitry Baryshkov 
46ca66dca5SDmitry Baryshkov #define ADC_TM5_FAST_AVG_CTL			(ADC_TM5_ADC_DIG_PARAM + 1)
47ca66dca5SDmitry Baryshkov #define ADC_TM5_FAST_AVG_EN				BIT(7)
48ca66dca5SDmitry Baryshkov 
49ca66dca5SDmitry Baryshkov #define ADC_TM5_MEAS_INTERVAL_CTL		(ADC_TM5_ADC_DIG_PARAM + 2)
50ca66dca5SDmitry Baryshkov #define ADC_TM5_TIMER1					3 /* 3.9ms */
51ca66dca5SDmitry Baryshkov 
52ca66dca5SDmitry Baryshkov #define ADC_TM5_MEAS_INTERVAL_CTL2		(ADC_TM5_ADC_DIG_PARAM + 3)
53ca66dca5SDmitry Baryshkov #define ADC_TM5_MEAS_INTERVAL_CTL2_MASK			0xf0
54ca66dca5SDmitry Baryshkov #define ADC_TM5_TIMER2					10 /* 1 second */
55ca66dca5SDmitry Baryshkov #define ADC_TM5_MEAS_INTERVAL_CTL3_MASK			0xf
56ca66dca5SDmitry Baryshkov #define ADC_TM5_TIMER3					4 /* 4 second */
57ca66dca5SDmitry Baryshkov 
58ca66dca5SDmitry Baryshkov #define ADC_TM_EN_CTL1				0x46
59ca66dca5SDmitry Baryshkov #define ADC_TM_EN					BIT(7)
60ca66dca5SDmitry Baryshkov #define ADC_TM_CONV_REQ				0x47
61ca66dca5SDmitry Baryshkov #define ADC_TM_CONV_REQ_EN				BIT(7)
62ca66dca5SDmitry Baryshkov 
63ca66dca5SDmitry Baryshkov #define ADC_TM5_M_CHAN_BASE			0x60
64ca66dca5SDmitry Baryshkov 
65ca66dca5SDmitry Baryshkov #define ADC_TM5_M_ADC_CH_SEL_CTL(n)		(ADC_TM5_M_CHAN_BASE + ((n) * 8) + 0)
66ca66dca5SDmitry Baryshkov #define ADC_TM5_M_LOW_THR0(n)			(ADC_TM5_M_CHAN_BASE + ((n) * 8) + 1)
67ca66dca5SDmitry Baryshkov #define ADC_TM5_M_LOW_THR1(n)			(ADC_TM5_M_CHAN_BASE + ((n) * 8) + 2)
68ca66dca5SDmitry Baryshkov #define ADC_TM5_M_HIGH_THR0(n)			(ADC_TM5_M_CHAN_BASE + ((n) * 8) + 3)
69ca66dca5SDmitry Baryshkov #define ADC_TM5_M_HIGH_THR1(n)			(ADC_TM5_M_CHAN_BASE + ((n) * 8) + 4)
70ca66dca5SDmitry Baryshkov #define ADC_TM5_M_MEAS_INTERVAL_CTL(n)		(ADC_TM5_M_CHAN_BASE + ((n) * 8) + 5)
71ca66dca5SDmitry Baryshkov #define ADC_TM5_M_CTL(n)			(ADC_TM5_M_CHAN_BASE + ((n) * 8) + 6)
72ca66dca5SDmitry Baryshkov #define ADC_TM5_M_CTL_HW_SETTLE_DELAY_MASK		0xf
73ca66dca5SDmitry Baryshkov #define ADC_TM5_M_CTL_CAL_SEL_MASK			0x30
74ca66dca5SDmitry Baryshkov #define ADC_TM5_M_CTL_CAL_VAL				0x40
75ca66dca5SDmitry Baryshkov #define ADC_TM5_M_EN(n)				(ADC_TM5_M_CHAN_BASE + ((n) * 8) + 7)
76ca66dca5SDmitry Baryshkov #define ADC_TM5_M_MEAS_EN				BIT(7)
77ca66dca5SDmitry Baryshkov #define ADC_TM5_M_HIGH_THR_INT_EN			BIT(1)
78ca66dca5SDmitry Baryshkov #define ADC_TM5_M_LOW_THR_INT_EN			BIT(0)
79ca66dca5SDmitry Baryshkov 
8096f6f333SJishnu Prakash #define ADC_TM_GEN2_STATUS1			0x08
8196f6f333SJishnu Prakash #define ADC_TM_GEN2_STATUS_LOW_SET		0x09
8296f6f333SJishnu Prakash #define ADC_TM_GEN2_STATUS_LOW_CLR		0x0a
8396f6f333SJishnu Prakash #define ADC_TM_GEN2_STATUS_HIGH_SET		0x0b
8496f6f333SJishnu Prakash #define ADC_TM_GEN2_STATUS_HIGH_CLR		0x0c
8596f6f333SJishnu Prakash 
8696f6f333SJishnu Prakash #define ADC_TM_GEN2_CFG_HS_SET			0x0d
8796f6f333SJishnu Prakash #define ADC_TM_GEN2_CFG_HS_FLAG			BIT(0)
8896f6f333SJishnu Prakash #define ADC_TM_GEN2_CFG_HS_CLR			0x0e
8996f6f333SJishnu Prakash 
9096f6f333SJishnu Prakash #define ADC_TM_GEN2_SID				0x40
9196f6f333SJishnu Prakash 
9296f6f333SJishnu Prakash #define ADC_TM_GEN2_CH_CTL			0x41
9396f6f333SJishnu Prakash #define ADC_TM_GEN2_TM_CH_SEL			GENMASK(7, 5)
9496f6f333SJishnu Prakash #define ADC_TM_GEN2_MEAS_INT_SEL		GENMASK(3, 2)
9596f6f333SJishnu Prakash 
9696f6f333SJishnu Prakash #define ADC_TM_GEN2_ADC_DIG_PARAM		0x42
9796f6f333SJishnu Prakash #define ADC_TM_GEN2_CTL_CAL_SEL			GENMASK(5, 4)
9896f6f333SJishnu Prakash #define ADC_TM_GEN2_CTL_DEC_RATIO_MASK		GENMASK(3, 2)
9996f6f333SJishnu Prakash 
10096f6f333SJishnu Prakash #define ADC_TM_GEN2_FAST_AVG_CTL		0x43
10196f6f333SJishnu Prakash #define ADC_TM_GEN2_FAST_AVG_EN			BIT(7)
10296f6f333SJishnu Prakash 
10396f6f333SJishnu Prakash #define ADC_TM_GEN2_ADC_CH_SEL_CTL		0x44
10496f6f333SJishnu Prakash 
10596f6f333SJishnu Prakash #define ADC_TM_GEN2_DELAY_CTL			0x45
10696f6f333SJishnu Prakash #define ADC_TM_GEN2_HW_SETTLE_DELAY		GENMASK(3, 0)
10796f6f333SJishnu Prakash 
10896f6f333SJishnu Prakash #define ADC_TM_GEN2_EN_CTL1			0x46
10996f6f333SJishnu Prakash #define ADC_TM_GEN2_EN				BIT(7)
11096f6f333SJishnu Prakash 
11196f6f333SJishnu Prakash #define ADC_TM_GEN2_CONV_REQ			0x47
11296f6f333SJishnu Prakash #define ADC_TM_GEN2_CONV_REQ_EN			BIT(7)
11396f6f333SJishnu Prakash 
11496f6f333SJishnu Prakash #define ADC_TM_GEN2_LOW_THR0			0x49
11596f6f333SJishnu Prakash #define ADC_TM_GEN2_LOW_THR1			0x4a
11696f6f333SJishnu Prakash #define ADC_TM_GEN2_HIGH_THR0			0x4b
11796f6f333SJishnu Prakash #define ADC_TM_GEN2_HIGH_THR1			0x4c
11896f6f333SJishnu Prakash #define ADC_TM_GEN2_LOWER_MASK(n)		((n) & GENMASK(7, 0))
11996f6f333SJishnu Prakash #define ADC_TM_GEN2_UPPER_MASK(n)		(((n) & GENMASK(15, 8)) >> 8)
12096f6f333SJishnu Prakash 
12196f6f333SJishnu Prakash #define ADC_TM_GEN2_MEAS_IRQ_EN			0x4d
12296f6f333SJishnu Prakash #define ADC_TM_GEN2_MEAS_EN			BIT(7)
12396f6f333SJishnu Prakash #define ADC_TM5_GEN2_HIGH_THR_INT_EN		BIT(1)
12496f6f333SJishnu Prakash #define ADC_TM5_GEN2_LOW_THR_INT_EN		BIT(0)
12596f6f333SJishnu Prakash 
12696f6f333SJishnu Prakash #define ADC_TM_GEN2_MEAS_INT_LSB		0x50
12796f6f333SJishnu Prakash #define ADC_TM_GEN2_MEAS_INT_MSB		0x51
12896f6f333SJishnu Prakash #define ADC_TM_GEN2_MEAS_INT_MODE		0x52
12996f6f333SJishnu Prakash 
13096f6f333SJishnu Prakash #define ADC_TM_GEN2_Mn_DATA0(n)			((n * 2) + 0xa0)
13196f6f333SJishnu Prakash #define ADC_TM_GEN2_Mn_DATA1(n)			((n * 2) + 0xa1)
13296f6f333SJishnu Prakash #define ADC_TM_GEN2_DATA_SHIFT			8
13396f6f333SJishnu Prakash 
134ca66dca5SDmitry Baryshkov enum adc5_timer_select {
135ca66dca5SDmitry Baryshkov 	ADC5_TIMER_SEL_1 = 0,
136ca66dca5SDmitry Baryshkov 	ADC5_TIMER_SEL_2,
137ca66dca5SDmitry Baryshkov 	ADC5_TIMER_SEL_3,
138ca66dca5SDmitry Baryshkov 	ADC5_TIMER_SEL_NONE,
139ca66dca5SDmitry Baryshkov };
140ca66dca5SDmitry Baryshkov 
1417e70a89aSJishnu Prakash enum adc5_gen {
1427e70a89aSJishnu Prakash 	ADC_TM5,
1437e70a89aSJishnu Prakash 	ADC_TM_HC,
14496f6f333SJishnu Prakash 	ADC_TM5_GEN2,
1457e70a89aSJishnu Prakash 	ADC_TM5_MAX
146ca66dca5SDmitry Baryshkov };
147ca66dca5SDmitry Baryshkov 
148ca66dca5SDmitry Baryshkov enum adc_tm5_cal_method {
149ca66dca5SDmitry Baryshkov 	ADC_TM5_NO_CAL = 0,
150ca66dca5SDmitry Baryshkov 	ADC_TM5_RATIOMETRIC_CAL,
151ca66dca5SDmitry Baryshkov 	ADC_TM5_ABSOLUTE_CAL
152ca66dca5SDmitry Baryshkov };
153ca66dca5SDmitry Baryshkov 
15496f6f333SJishnu Prakash enum adc_tm_gen2_time_select {
15596f6f333SJishnu Prakash 	MEAS_INT_50MS = 0,
15696f6f333SJishnu Prakash 	MEAS_INT_100MS,
15796f6f333SJishnu Prakash 	MEAS_INT_1S,
15896f6f333SJishnu Prakash 	MEAS_INT_SET,
15996f6f333SJishnu Prakash 	MEAS_INT_NONE,
16096f6f333SJishnu Prakash };
16196f6f333SJishnu Prakash 
162ca66dca5SDmitry Baryshkov struct adc_tm5_chip;
1637e70a89aSJishnu Prakash struct adc_tm5_channel;
1647e70a89aSJishnu Prakash 
1657e70a89aSJishnu Prakash struct adc_tm5_data {
1667e70a89aSJishnu Prakash 	const u32 full_scale_code_volt;
1677e70a89aSJishnu Prakash 	unsigned int *decimation;
1687e70a89aSJishnu Prakash 	unsigned int *hw_settle;
1697e70a89aSJishnu Prakash 	int (*disable_channel)(struct adc_tm5_channel *channel);
1707e70a89aSJishnu Prakash 	int (*configure)(struct adc_tm5_channel *channel, int low, int high);
1717e70a89aSJishnu Prakash 	irqreturn_t (*isr)(int irq, void *data);
1727e70a89aSJishnu Prakash 	int (*init)(struct adc_tm5_chip *chip);
1737e70a89aSJishnu Prakash 	char *irq_name;
1747e70a89aSJishnu Prakash 	int gen;
1757e70a89aSJishnu Prakash };
176ca66dca5SDmitry Baryshkov 
177ca66dca5SDmitry Baryshkov /**
178ca66dca5SDmitry Baryshkov  * struct adc_tm5_channel - ADC Thermal Monitoring channel data.
179ca66dca5SDmitry Baryshkov  * @channel: channel number.
180ca66dca5SDmitry Baryshkov  * @adc_channel: corresponding ADC channel number.
181ca66dca5SDmitry Baryshkov  * @cal_method: calibration method.
182ca66dca5SDmitry Baryshkov  * @prescale: channel scaling performed on the input signal.
183ca66dca5SDmitry Baryshkov  * @hw_settle_time: the time between AMUX being configured and the
184ca66dca5SDmitry Baryshkov  *	start of conversion.
18596f6f333SJishnu Prakash  * @decimation: sampling rate supported for the channel.
18696f6f333SJishnu Prakash  * @avg_samples: ability to provide single result from the ADC
18796f6f333SJishnu Prakash  *	that is an average of multiple measurements.
18896f6f333SJishnu Prakash  * @high_thr_en: channel upper voltage threshold enable state.
18996f6f333SJishnu Prakash  * @low_thr_en: channel lower voltage threshold enable state.
19096f6f333SJishnu Prakash  * @meas_en: recurring measurement enable state
191ca66dca5SDmitry Baryshkov  * @iio: IIO channel instance used by this channel.
192ca66dca5SDmitry Baryshkov  * @chip: ADC TM chip instance.
193ca66dca5SDmitry Baryshkov  * @tzd: thermal zone device used by this channel.
194ca66dca5SDmitry Baryshkov  */
195ca66dca5SDmitry Baryshkov struct adc_tm5_channel {
196ca66dca5SDmitry Baryshkov 	unsigned int		channel;
197ca66dca5SDmitry Baryshkov 	unsigned int		adc_channel;
198ca66dca5SDmitry Baryshkov 	enum adc_tm5_cal_method	cal_method;
199ca66dca5SDmitry Baryshkov 	unsigned int		prescale;
200ca66dca5SDmitry Baryshkov 	unsigned int		hw_settle_time;
20196f6f333SJishnu Prakash 	unsigned int		decimation;	/* For Gen2 ADC_TM */
20296f6f333SJishnu Prakash 	unsigned int		avg_samples;	/* For Gen2 ADC_TM */
20396f6f333SJishnu Prakash 	bool			high_thr_en;	/* For Gen2 ADC_TM */
20496f6f333SJishnu Prakash 	bool			low_thr_en;	/* For Gen2 ADC_TM */
20596f6f333SJishnu Prakash 	bool			meas_en;	/* For Gen2 ADC_TM */
206ca66dca5SDmitry Baryshkov 	struct iio_channel	*iio;
207ca66dca5SDmitry Baryshkov 	struct adc_tm5_chip	*chip;
208ca66dca5SDmitry Baryshkov 	struct thermal_zone_device *tzd;
209ca66dca5SDmitry Baryshkov };
210ca66dca5SDmitry Baryshkov 
211ca66dca5SDmitry Baryshkov /**
212ca66dca5SDmitry Baryshkov  * struct adc_tm5_chip - ADC Thermal Monitoring properties
213ca66dca5SDmitry Baryshkov  * @regmap: SPMI ADC5 Thermal Monitoring  peripheral register map field.
214ca66dca5SDmitry Baryshkov  * @dev: SPMI ADC5 device.
215ca66dca5SDmitry Baryshkov  * @data: software configuration data.
216ca66dca5SDmitry Baryshkov  * @channels: array of ADC TM channel data.
217ca66dca5SDmitry Baryshkov  * @nchannels: amount of channels defined/allocated
218ca66dca5SDmitry Baryshkov  * @decimation: sampling rate supported for the channel.
21996f6f333SJishnu Prakash  *      Applies to all channels, used only on Gen1 ADC_TM.
220ca66dca5SDmitry Baryshkov  * @avg_samples: ability to provide single result from the ADC
22196f6f333SJishnu Prakash  *      that is an average of multiple measurements. Applies to all
22296f6f333SJishnu Prakash  *      channels, used only on Gen1 ADC_TM.
223ca66dca5SDmitry Baryshkov  * @base: base address of TM registers.
22496f6f333SJishnu Prakash  * @adc_mutex_lock: ADC_TM mutex lock, used only on Gen2 ADC_TM.
22596f6f333SJishnu Prakash  *      It is used to ensure only one ADC channel configuration
22696f6f333SJishnu Prakash  *      is done at a time using the shared set of configuration
22796f6f333SJishnu Prakash  *      registers.
228ca66dca5SDmitry Baryshkov  */
229ca66dca5SDmitry Baryshkov struct adc_tm5_chip {
230ca66dca5SDmitry Baryshkov 	struct regmap		*regmap;
231ca66dca5SDmitry Baryshkov 	struct device		*dev;
232ca66dca5SDmitry Baryshkov 	const struct adc_tm5_data	*data;
233ca66dca5SDmitry Baryshkov 	struct adc_tm5_channel	*channels;
234ca66dca5SDmitry Baryshkov 	unsigned int		nchannels;
235ca66dca5SDmitry Baryshkov 	unsigned int		decimation;
236ca66dca5SDmitry Baryshkov 	unsigned int		avg_samples;
237ca66dca5SDmitry Baryshkov 	u16			base;
23896f6f333SJishnu Prakash 	struct mutex		adc_mutex_lock;
239ca66dca5SDmitry Baryshkov };
240ca66dca5SDmitry Baryshkov 
adc_tm5_read(struct adc_tm5_chip * adc_tm,u16 offset,u8 * data,int len)241ca66dca5SDmitry Baryshkov static int adc_tm5_read(struct adc_tm5_chip *adc_tm, u16 offset, u8 *data, int len)
242ca66dca5SDmitry Baryshkov {
243ca66dca5SDmitry Baryshkov 	return regmap_bulk_read(adc_tm->regmap, adc_tm->base + offset, data, len);
244ca66dca5SDmitry Baryshkov }
245ca66dca5SDmitry Baryshkov 
adc_tm5_write(struct adc_tm5_chip * adc_tm,u16 offset,u8 * data,int len)246ca66dca5SDmitry Baryshkov static int adc_tm5_write(struct adc_tm5_chip *adc_tm, u16 offset, u8 *data, int len)
247ca66dca5SDmitry Baryshkov {
248ca66dca5SDmitry Baryshkov 	return regmap_bulk_write(adc_tm->regmap, adc_tm->base + offset, data, len);
249ca66dca5SDmitry Baryshkov }
250ca66dca5SDmitry Baryshkov 
adc_tm5_reg_update(struct adc_tm5_chip * adc_tm,u16 offset,u8 mask,u8 val)251ca66dca5SDmitry Baryshkov static int adc_tm5_reg_update(struct adc_tm5_chip *adc_tm, u16 offset, u8 mask, u8 val)
252ca66dca5SDmitry Baryshkov {
253ca66dca5SDmitry Baryshkov 	return regmap_write_bits(adc_tm->regmap, adc_tm->base + offset, mask, val);
254ca66dca5SDmitry Baryshkov }
255ca66dca5SDmitry Baryshkov 
adc_tm5_isr(int irq,void * data)256ca66dca5SDmitry Baryshkov static irqreturn_t adc_tm5_isr(int irq, void *data)
257ca66dca5SDmitry Baryshkov {
258ca66dca5SDmitry Baryshkov 	struct adc_tm5_chip *chip = data;
259ca66dca5SDmitry Baryshkov 	u8 status_low, status_high, ctl;
260ca66dca5SDmitry Baryshkov 	int ret, i;
261ca66dca5SDmitry Baryshkov 
262ca66dca5SDmitry Baryshkov 	ret = adc_tm5_read(chip, ADC_TM5_STATUS_LOW, &status_low, sizeof(status_low));
263ca66dca5SDmitry Baryshkov 	if (unlikely(ret)) {
264ca66dca5SDmitry Baryshkov 		dev_err(chip->dev, "read status low failed: %d\n", ret);
265ca66dca5SDmitry Baryshkov 		return IRQ_HANDLED;
266ca66dca5SDmitry Baryshkov 	}
267ca66dca5SDmitry Baryshkov 
268ca66dca5SDmitry Baryshkov 	ret = adc_tm5_read(chip, ADC_TM5_STATUS_HIGH, &status_high, sizeof(status_high));
269ca66dca5SDmitry Baryshkov 	if (unlikely(ret)) {
270ca66dca5SDmitry Baryshkov 		dev_err(chip->dev, "read status high failed: %d\n", ret);
271ca66dca5SDmitry Baryshkov 		return IRQ_HANDLED;
272ca66dca5SDmitry Baryshkov 	}
273ca66dca5SDmitry Baryshkov 
274ca66dca5SDmitry Baryshkov 	for (i = 0; i < chip->nchannels; i++) {
275ca66dca5SDmitry Baryshkov 		bool upper_set = false, lower_set = false;
276ca66dca5SDmitry Baryshkov 		unsigned int ch = chip->channels[i].channel;
277ca66dca5SDmitry Baryshkov 
278ca66dca5SDmitry Baryshkov 		/* No TZD, we warned at the boot time */
279ca66dca5SDmitry Baryshkov 		if (!chip->channels[i].tzd)
280ca66dca5SDmitry Baryshkov 			continue;
281ca66dca5SDmitry Baryshkov 
282ca66dca5SDmitry Baryshkov 		ret = adc_tm5_read(chip, ADC_TM5_M_EN(ch), &ctl, sizeof(ctl));
283ca66dca5SDmitry Baryshkov 		if (unlikely(ret)) {
284ca66dca5SDmitry Baryshkov 			dev_err(chip->dev, "ctl read failed: %d, channel %d\n", ret, i);
285ca66dca5SDmitry Baryshkov 			continue;
286ca66dca5SDmitry Baryshkov 		}
287ca66dca5SDmitry Baryshkov 
288ca66dca5SDmitry Baryshkov 		if (!(ctl & ADC_TM5_M_MEAS_EN))
289ca66dca5SDmitry Baryshkov 			continue;
290ca66dca5SDmitry Baryshkov 
291ca66dca5SDmitry Baryshkov 		lower_set = (status_low & BIT(ch)) &&
292ca66dca5SDmitry Baryshkov 			(ctl & ADC_TM5_M_LOW_THR_INT_EN);
293ca66dca5SDmitry Baryshkov 
294ca66dca5SDmitry Baryshkov 		upper_set = (status_high & BIT(ch)) &&
295ca66dca5SDmitry Baryshkov 			(ctl & ADC_TM5_M_HIGH_THR_INT_EN);
296ca66dca5SDmitry Baryshkov 
297ca66dca5SDmitry Baryshkov 		if (upper_set || lower_set)
298ca66dca5SDmitry Baryshkov 			thermal_zone_device_update(chip->channels[i].tzd,
299ca66dca5SDmitry Baryshkov 						   THERMAL_EVENT_UNSPECIFIED);
300ca66dca5SDmitry Baryshkov 	}
301ca66dca5SDmitry Baryshkov 
302ca66dca5SDmitry Baryshkov 	return IRQ_HANDLED;
303ca66dca5SDmitry Baryshkov }
304ca66dca5SDmitry Baryshkov 
adc_tm5_gen2_isr(int irq,void * data)30596f6f333SJishnu Prakash static irqreturn_t adc_tm5_gen2_isr(int irq, void *data)
30696f6f333SJishnu Prakash {
30796f6f333SJishnu Prakash 	struct adc_tm5_chip *chip = data;
30896f6f333SJishnu Prakash 	u8 status_low, status_high;
30996f6f333SJishnu Prakash 	int ret, i;
31096f6f333SJishnu Prakash 
31196f6f333SJishnu Prakash 	ret = adc_tm5_read(chip, ADC_TM_GEN2_STATUS_LOW_CLR, &status_low, sizeof(status_low));
31296f6f333SJishnu Prakash 	if (ret) {
31396f6f333SJishnu Prakash 		dev_err(chip->dev, "read status_low failed: %d\n", ret);
31496f6f333SJishnu Prakash 		return IRQ_HANDLED;
31596f6f333SJishnu Prakash 	}
31696f6f333SJishnu Prakash 
31796f6f333SJishnu Prakash 	ret = adc_tm5_read(chip, ADC_TM_GEN2_STATUS_HIGH_CLR, &status_high, sizeof(status_high));
31896f6f333SJishnu Prakash 	if (ret) {
31996f6f333SJishnu Prakash 		dev_err(chip->dev, "read status_high failed: %d\n", ret);
32096f6f333SJishnu Prakash 		return IRQ_HANDLED;
32196f6f333SJishnu Prakash 	}
32296f6f333SJishnu Prakash 
32396f6f333SJishnu Prakash 	ret = adc_tm5_write(chip, ADC_TM_GEN2_STATUS_LOW_CLR, &status_low, sizeof(status_low));
32496f6f333SJishnu Prakash 	if (ret < 0) {
32596f6f333SJishnu Prakash 		dev_err(chip->dev, "clear status low failed with %d\n", ret);
32696f6f333SJishnu Prakash 		return IRQ_HANDLED;
32796f6f333SJishnu Prakash 	}
32896f6f333SJishnu Prakash 
32996f6f333SJishnu Prakash 	ret = adc_tm5_write(chip, ADC_TM_GEN2_STATUS_HIGH_CLR, &status_high, sizeof(status_high));
33096f6f333SJishnu Prakash 	if (ret < 0) {
33196f6f333SJishnu Prakash 		dev_err(chip->dev, "clear status high failed with %d\n", ret);
33296f6f333SJishnu Prakash 		return IRQ_HANDLED;
33396f6f333SJishnu Prakash 	}
33496f6f333SJishnu Prakash 
33596f6f333SJishnu Prakash 	for (i = 0; i < chip->nchannels; i++) {
33696f6f333SJishnu Prakash 		bool upper_set = false, lower_set = false;
33796f6f333SJishnu Prakash 		unsigned int ch = chip->channels[i].channel;
33896f6f333SJishnu Prakash 
33996f6f333SJishnu Prakash 		/* No TZD, we warned at the boot time */
34096f6f333SJishnu Prakash 		if (!chip->channels[i].tzd)
34196f6f333SJishnu Prakash 			continue;
34296f6f333SJishnu Prakash 
34396f6f333SJishnu Prakash 		if (!chip->channels[i].meas_en)
34496f6f333SJishnu Prakash 			continue;
34596f6f333SJishnu Prakash 
34696f6f333SJishnu Prakash 		lower_set = (status_low & BIT(ch)) &&
34796f6f333SJishnu Prakash 			(chip->channels[i].low_thr_en);
34896f6f333SJishnu Prakash 
34996f6f333SJishnu Prakash 		upper_set = (status_high & BIT(ch)) &&
35096f6f333SJishnu Prakash 			(chip->channels[i].high_thr_en);
35196f6f333SJishnu Prakash 
35296f6f333SJishnu Prakash 		if (upper_set || lower_set)
35396f6f333SJishnu Prakash 			thermal_zone_device_update(chip->channels[i].tzd,
35496f6f333SJishnu Prakash 						   THERMAL_EVENT_UNSPECIFIED);
35596f6f333SJishnu Prakash 	}
35696f6f333SJishnu Prakash 
35796f6f333SJishnu Prakash 	return IRQ_HANDLED;
35896f6f333SJishnu Prakash }
35996f6f333SJishnu Prakash 
adc_tm5_get_temp(struct thermal_zone_device * tz,int * temp)360ca1b9a9eSDaniel Lezcano static int adc_tm5_get_temp(struct thermal_zone_device *tz, int *temp)
361ca66dca5SDmitry Baryshkov {
3625f68d078SDaniel Lezcano 	struct adc_tm5_channel *channel = thermal_zone_device_priv(tz);
363ca66dca5SDmitry Baryshkov 	int ret;
364ca66dca5SDmitry Baryshkov 
365ca66dca5SDmitry Baryshkov 	if (!channel || !channel->iio)
366ca66dca5SDmitry Baryshkov 		return -EINVAL;
367ca66dca5SDmitry Baryshkov 
368ca66dca5SDmitry Baryshkov 	ret = iio_read_channel_processed(channel->iio, temp);
369ca66dca5SDmitry Baryshkov 	if (ret < 0)
370ca66dca5SDmitry Baryshkov 		return ret;
371ca66dca5SDmitry Baryshkov 
372ca66dca5SDmitry Baryshkov 	if (ret != IIO_VAL_INT)
373ca66dca5SDmitry Baryshkov 		return -EINVAL;
374ca66dca5SDmitry Baryshkov 
375ca66dca5SDmitry Baryshkov 	return 0;
376ca66dca5SDmitry Baryshkov }
377ca66dca5SDmitry Baryshkov 
adc_tm5_disable_channel(struct adc_tm5_channel * channel)378ca66dca5SDmitry Baryshkov static int adc_tm5_disable_channel(struct adc_tm5_channel *channel)
379ca66dca5SDmitry Baryshkov {
380ca66dca5SDmitry Baryshkov 	struct adc_tm5_chip *chip = channel->chip;
381ca66dca5SDmitry Baryshkov 	unsigned int reg = ADC_TM5_M_EN(channel->channel);
382ca66dca5SDmitry Baryshkov 
383ca66dca5SDmitry Baryshkov 	return adc_tm5_reg_update(chip, reg,
384ca66dca5SDmitry Baryshkov 				  ADC_TM5_M_MEAS_EN |
385ca66dca5SDmitry Baryshkov 				  ADC_TM5_M_HIGH_THR_INT_EN |
386ca66dca5SDmitry Baryshkov 				  ADC_TM5_M_LOW_THR_INT_EN,
387ca66dca5SDmitry Baryshkov 				  0);
388ca66dca5SDmitry Baryshkov }
389ca66dca5SDmitry Baryshkov 
39096f6f333SJishnu Prakash #define ADC_TM_GEN2_POLL_DELAY_MIN_US		100
39196f6f333SJishnu Prakash #define ADC_TM_GEN2_POLL_DELAY_MAX_US		110
39296f6f333SJishnu Prakash #define ADC_TM_GEN2_POLL_RETRY_COUNT		3
39396f6f333SJishnu Prakash 
adc_tm5_gen2_conv_req(struct adc_tm5_chip * chip)39496f6f333SJishnu Prakash static int32_t adc_tm5_gen2_conv_req(struct adc_tm5_chip *chip)
39596f6f333SJishnu Prakash {
39696f6f333SJishnu Prakash 	int ret;
39796f6f333SJishnu Prakash 	u8 data;
39896f6f333SJishnu Prakash 	unsigned int count;
39996f6f333SJishnu Prakash 
40096f6f333SJishnu Prakash 	data = ADC_TM_GEN2_EN;
40196f6f333SJishnu Prakash 	ret = adc_tm5_write(chip, ADC_TM_GEN2_EN_CTL1, &data, 1);
40296f6f333SJishnu Prakash 	if (ret < 0) {
40396f6f333SJishnu Prakash 		dev_err(chip->dev, "adc-tm enable failed with %d\n", ret);
40496f6f333SJishnu Prakash 		return ret;
40596f6f333SJishnu Prakash 	}
40696f6f333SJishnu Prakash 
40796f6f333SJishnu Prakash 	data = ADC_TM_GEN2_CFG_HS_FLAG;
40896f6f333SJishnu Prakash 	ret = adc_tm5_write(chip, ADC_TM_GEN2_CFG_HS_SET, &data, 1);
40996f6f333SJishnu Prakash 	if (ret < 0) {
41096f6f333SJishnu Prakash 		dev_err(chip->dev, "adc-tm handshake failed with %d\n", ret);
41196f6f333SJishnu Prakash 		return ret;
41296f6f333SJishnu Prakash 	}
41396f6f333SJishnu Prakash 
41496f6f333SJishnu Prakash 	data = ADC_TM_GEN2_CONV_REQ_EN;
41596f6f333SJishnu Prakash 	ret = adc_tm5_write(chip, ADC_TM_GEN2_CONV_REQ, &data, 1);
41696f6f333SJishnu Prakash 	if (ret < 0) {
41796f6f333SJishnu Prakash 		dev_err(chip->dev, "adc-tm request conversion failed with %d\n", ret);
41896f6f333SJishnu Prakash 		return ret;
41996f6f333SJishnu Prakash 	}
42096f6f333SJishnu Prakash 
42196f6f333SJishnu Prakash 	/*
42296f6f333SJishnu Prakash 	 * SW sets a handshake bit and waits for PBS to clear it
42396f6f333SJishnu Prakash 	 * before the next conversion request can be queued.
42496f6f333SJishnu Prakash 	 */
42596f6f333SJishnu Prakash 
42696f6f333SJishnu Prakash 	for (count = 0; count < ADC_TM_GEN2_POLL_RETRY_COUNT; count++) {
42796f6f333SJishnu Prakash 		ret = adc_tm5_read(chip, ADC_TM_GEN2_CFG_HS_SET, &data, sizeof(data));
42896f6f333SJishnu Prakash 		if (ret < 0) {
42996f6f333SJishnu Prakash 			dev_err(chip->dev, "adc-tm read failed with %d\n", ret);
43096f6f333SJishnu Prakash 			return ret;
43196f6f333SJishnu Prakash 		}
43296f6f333SJishnu Prakash 
43396f6f333SJishnu Prakash 		if (!(data & ADC_TM_GEN2_CFG_HS_FLAG))
43496f6f333SJishnu Prakash 			return ret;
43596f6f333SJishnu Prakash 		usleep_range(ADC_TM_GEN2_POLL_DELAY_MIN_US,
43696f6f333SJishnu Prakash 			ADC_TM_GEN2_POLL_DELAY_MAX_US);
43796f6f333SJishnu Prakash 	}
43896f6f333SJishnu Prakash 
43996f6f333SJishnu Prakash 	dev_err(chip->dev, "adc-tm conversion request handshake timed out\n");
44096f6f333SJishnu Prakash 
44196f6f333SJishnu Prakash 	return -ETIMEDOUT;
44296f6f333SJishnu Prakash }
44396f6f333SJishnu Prakash 
adc_tm5_gen2_disable_channel(struct adc_tm5_channel * channel)44496f6f333SJishnu Prakash static int adc_tm5_gen2_disable_channel(struct adc_tm5_channel *channel)
44596f6f333SJishnu Prakash {
44696f6f333SJishnu Prakash 	struct adc_tm5_chip *chip = channel->chip;
44796f6f333SJishnu Prakash 	int ret;
44896f6f333SJishnu Prakash 	u8 val;
44996f6f333SJishnu Prakash 
45096f6f333SJishnu Prakash 	mutex_lock(&chip->adc_mutex_lock);
45196f6f333SJishnu Prakash 
45296f6f333SJishnu Prakash 	channel->meas_en = false;
45396f6f333SJishnu Prakash 	channel->high_thr_en = false;
45496f6f333SJishnu Prakash 	channel->low_thr_en = false;
45596f6f333SJishnu Prakash 
45696f6f333SJishnu Prakash 	ret = adc_tm5_read(chip, ADC_TM_GEN2_CH_CTL, &val, sizeof(val));
45796f6f333SJishnu Prakash 	if (ret < 0) {
45896f6f333SJishnu Prakash 		dev_err(chip->dev, "adc-tm block read failed with %d\n", ret);
45996f6f333SJishnu Prakash 		goto disable_fail;
46096f6f333SJishnu Prakash 	}
46196f6f333SJishnu Prakash 
46296f6f333SJishnu Prakash 	val &= ~ADC_TM_GEN2_TM_CH_SEL;
46396f6f333SJishnu Prakash 	val |= FIELD_PREP(ADC_TM_GEN2_TM_CH_SEL, channel->channel);
46496f6f333SJishnu Prakash 
46596f6f333SJishnu Prakash 	ret = adc_tm5_write(chip, ADC_TM_GEN2_CH_CTL, &val, 1);
46696f6f333SJishnu Prakash 	if (ret < 0) {
46796f6f333SJishnu Prakash 		dev_err(chip->dev, "adc-tm channel disable failed with %d\n", ret);
46896f6f333SJishnu Prakash 		goto disable_fail;
46996f6f333SJishnu Prakash 	}
47096f6f333SJishnu Prakash 
47196f6f333SJishnu Prakash 	val = 0;
47296f6f333SJishnu Prakash 	ret = adc_tm5_write(chip, ADC_TM_GEN2_MEAS_IRQ_EN, &val, 1);
47396f6f333SJishnu Prakash 	if (ret < 0) {
47496f6f333SJishnu Prakash 		dev_err(chip->dev, "adc-tm interrupt disable failed with %d\n", ret);
47596f6f333SJishnu Prakash 		goto disable_fail;
47696f6f333SJishnu Prakash 	}
47796f6f333SJishnu Prakash 
47896f6f333SJishnu Prakash 
47996f6f333SJishnu Prakash 	ret = adc_tm5_gen2_conv_req(channel->chip);
48096f6f333SJishnu Prakash 	if (ret < 0)
48196f6f333SJishnu Prakash 		dev_err(chip->dev, "adc-tm channel configure failed with %d\n", ret);
48296f6f333SJishnu Prakash 
48396f6f333SJishnu Prakash disable_fail:
48496f6f333SJishnu Prakash 	mutex_unlock(&chip->adc_mutex_lock);
48596f6f333SJishnu Prakash 	return ret;
48696f6f333SJishnu Prakash }
48796f6f333SJishnu Prakash 
adc_tm5_enable(struct adc_tm5_chip * chip)488ca66dca5SDmitry Baryshkov static int adc_tm5_enable(struct adc_tm5_chip *chip)
489ca66dca5SDmitry Baryshkov {
490ca66dca5SDmitry Baryshkov 	int ret;
491ca66dca5SDmitry Baryshkov 	u8 data;
492ca66dca5SDmitry Baryshkov 
493ca66dca5SDmitry Baryshkov 	data = ADC_TM_EN;
494ca66dca5SDmitry Baryshkov 	ret = adc_tm5_write(chip, ADC_TM_EN_CTL1, &data, sizeof(data));
495ca66dca5SDmitry Baryshkov 	if (ret < 0) {
496ca66dca5SDmitry Baryshkov 		dev_err(chip->dev, "adc-tm enable failed\n");
497ca66dca5SDmitry Baryshkov 		return ret;
498ca66dca5SDmitry Baryshkov 	}
499ca66dca5SDmitry Baryshkov 
500ca66dca5SDmitry Baryshkov 	data = ADC_TM_CONV_REQ_EN;
501ca66dca5SDmitry Baryshkov 	ret = adc_tm5_write(chip, ADC_TM_CONV_REQ, &data, sizeof(data));
502ca66dca5SDmitry Baryshkov 	if (ret < 0) {
503ca66dca5SDmitry Baryshkov 		dev_err(chip->dev, "adc-tm request conversion failed\n");
504ca66dca5SDmitry Baryshkov 		return ret;
505ca66dca5SDmitry Baryshkov 	}
506ca66dca5SDmitry Baryshkov 
507ca66dca5SDmitry Baryshkov 	return 0;
508ca66dca5SDmitry Baryshkov }
509ca66dca5SDmitry Baryshkov 
adc_tm5_configure(struct adc_tm5_channel * channel,int low,int high)510ca66dca5SDmitry Baryshkov static int adc_tm5_configure(struct adc_tm5_channel *channel, int low, int high)
511ca66dca5SDmitry Baryshkov {
512ca66dca5SDmitry Baryshkov 	struct adc_tm5_chip *chip = channel->chip;
513ca66dca5SDmitry Baryshkov 	u8 buf[8];
514ca66dca5SDmitry Baryshkov 	u16 reg = ADC_TM5_M_ADC_CH_SEL_CTL(channel->channel);
515ca66dca5SDmitry Baryshkov 	int ret;
516ca66dca5SDmitry Baryshkov 
517ca66dca5SDmitry Baryshkov 	ret = adc_tm5_read(chip, reg, buf, sizeof(buf));
518ca66dca5SDmitry Baryshkov 	if (ret) {
519ca66dca5SDmitry Baryshkov 		dev_err(chip->dev, "channel %d params read failed: %d\n", channel->channel, ret);
520ca66dca5SDmitry Baryshkov 		return ret;
521ca66dca5SDmitry Baryshkov 	}
522ca66dca5SDmitry Baryshkov 
523ca66dca5SDmitry Baryshkov 	buf[0] = channel->adc_channel;
524ca66dca5SDmitry Baryshkov 
525ca66dca5SDmitry Baryshkov 	/* High temperature corresponds to low voltage threshold */
526ca66dca5SDmitry Baryshkov 	if (high != INT_MAX) {
527ca66dca5SDmitry Baryshkov 		u16 adc_code = qcom_adc_tm5_temp_volt_scale(channel->prescale,
528ca66dca5SDmitry Baryshkov 				chip->data->full_scale_code_volt, high);
529ca66dca5SDmitry Baryshkov 
53096f6f333SJishnu Prakash 		put_unaligned_le16(adc_code, &buf[1]);
531ca66dca5SDmitry Baryshkov 		buf[7] |= ADC_TM5_M_LOW_THR_INT_EN;
532ca66dca5SDmitry Baryshkov 	} else {
533ca66dca5SDmitry Baryshkov 		buf[7] &= ~ADC_TM5_M_LOW_THR_INT_EN;
534ca66dca5SDmitry Baryshkov 	}
535ca66dca5SDmitry Baryshkov 
536ca66dca5SDmitry Baryshkov 	/* Low temperature corresponds to high voltage threshold */
537ca66dca5SDmitry Baryshkov 	if (low != -INT_MAX) {
538ca66dca5SDmitry Baryshkov 		u16 adc_code = qcom_adc_tm5_temp_volt_scale(channel->prescale,
539ca66dca5SDmitry Baryshkov 				chip->data->full_scale_code_volt, low);
540ca66dca5SDmitry Baryshkov 
54196f6f333SJishnu Prakash 		put_unaligned_le16(adc_code, &buf[3]);
542ca66dca5SDmitry Baryshkov 		buf[7] |= ADC_TM5_M_HIGH_THR_INT_EN;
543ca66dca5SDmitry Baryshkov 	} else {
544ca66dca5SDmitry Baryshkov 		buf[7] &= ~ADC_TM5_M_HIGH_THR_INT_EN;
545ca66dca5SDmitry Baryshkov 	}
546ca66dca5SDmitry Baryshkov 
547ca66dca5SDmitry Baryshkov 	buf[5] = ADC5_TIMER_SEL_2;
548ca66dca5SDmitry Baryshkov 
549ca66dca5SDmitry Baryshkov 	/* Set calibration select, hw_settle delay */
550ca66dca5SDmitry Baryshkov 	buf[6] &= ~ADC_TM5_M_CTL_HW_SETTLE_DELAY_MASK;
551ca66dca5SDmitry Baryshkov 	buf[6] |= FIELD_PREP(ADC_TM5_M_CTL_HW_SETTLE_DELAY_MASK, channel->hw_settle_time);
552ca66dca5SDmitry Baryshkov 	buf[6] &= ~ADC_TM5_M_CTL_CAL_SEL_MASK;
553ca66dca5SDmitry Baryshkov 	buf[6] |= FIELD_PREP(ADC_TM5_M_CTL_CAL_SEL_MASK, channel->cal_method);
554ca66dca5SDmitry Baryshkov 
555ca66dca5SDmitry Baryshkov 	buf[7] |= ADC_TM5_M_MEAS_EN;
556ca66dca5SDmitry Baryshkov 
557ca66dca5SDmitry Baryshkov 	ret = adc_tm5_write(chip, reg, buf, sizeof(buf));
558ca66dca5SDmitry Baryshkov 	if (ret) {
559ca66dca5SDmitry Baryshkov 		dev_err(chip->dev, "channel %d params write failed: %d\n", channel->channel, ret);
560ca66dca5SDmitry Baryshkov 		return ret;
561ca66dca5SDmitry Baryshkov 	}
562ca66dca5SDmitry Baryshkov 
563ca66dca5SDmitry Baryshkov 	return adc_tm5_enable(chip);
564ca66dca5SDmitry Baryshkov }
565ca66dca5SDmitry Baryshkov 
adc_tm5_gen2_configure(struct adc_tm5_channel * channel,int low,int high)56696f6f333SJishnu Prakash static int adc_tm5_gen2_configure(struct adc_tm5_channel *channel, int low, int high)
56796f6f333SJishnu Prakash {
56896f6f333SJishnu Prakash 	struct adc_tm5_chip *chip = channel->chip;
56996f6f333SJishnu Prakash 	int ret;
57096f6f333SJishnu Prakash 	u8 buf[14];
57196f6f333SJishnu Prakash 	u16 adc_code;
57296f6f333SJishnu Prakash 
57396f6f333SJishnu Prakash 	mutex_lock(&chip->adc_mutex_lock);
57496f6f333SJishnu Prakash 
57596f6f333SJishnu Prakash 	channel->meas_en = true;
57696f6f333SJishnu Prakash 
57796f6f333SJishnu Prakash 	ret = adc_tm5_read(chip, ADC_TM_GEN2_SID, buf, sizeof(buf));
57896f6f333SJishnu Prakash 	if (ret < 0) {
57996f6f333SJishnu Prakash 		dev_err(chip->dev, "adc-tm block read failed with %d\n", ret);
58096f6f333SJishnu Prakash 		goto config_fail;
58196f6f333SJishnu Prakash 	}
58296f6f333SJishnu Prakash 
58396f6f333SJishnu Prakash 	/* Set SID from virtual channel number */
58496f6f333SJishnu Prakash 	buf[0] = channel->adc_channel >> 8;
58596f6f333SJishnu Prakash 
58696f6f333SJishnu Prakash 	/* Set TM channel number used and measurement interval */
58796f6f333SJishnu Prakash 	buf[1] &= ~ADC_TM_GEN2_TM_CH_SEL;
58896f6f333SJishnu Prakash 	buf[1] |= FIELD_PREP(ADC_TM_GEN2_TM_CH_SEL, channel->channel);
58996f6f333SJishnu Prakash 	buf[1] &= ~ADC_TM_GEN2_MEAS_INT_SEL;
59096f6f333SJishnu Prakash 	buf[1] |= FIELD_PREP(ADC_TM_GEN2_MEAS_INT_SEL, MEAS_INT_1S);
59196f6f333SJishnu Prakash 
59296f6f333SJishnu Prakash 	buf[2] &= ~ADC_TM_GEN2_CTL_DEC_RATIO_MASK;
59396f6f333SJishnu Prakash 	buf[2] |= FIELD_PREP(ADC_TM_GEN2_CTL_DEC_RATIO_MASK, channel->decimation);
59496f6f333SJishnu Prakash 	buf[2] &= ~ADC_TM_GEN2_CTL_CAL_SEL;
59596f6f333SJishnu Prakash 	buf[2] |= FIELD_PREP(ADC_TM_GEN2_CTL_CAL_SEL, channel->cal_method);
59696f6f333SJishnu Prakash 
59796f6f333SJishnu Prakash 	buf[3] = channel->avg_samples | ADC_TM_GEN2_FAST_AVG_EN;
59896f6f333SJishnu Prakash 
59996f6f333SJishnu Prakash 	buf[4] = channel->adc_channel & 0xff;
60096f6f333SJishnu Prakash 
60196f6f333SJishnu Prakash 	buf[5] = channel->hw_settle_time & ADC_TM_GEN2_HW_SETTLE_DELAY;
60296f6f333SJishnu Prakash 
60396f6f333SJishnu Prakash 	/* High temperature corresponds to low voltage threshold */
60496f6f333SJishnu Prakash 	if (high != INT_MAX) {
60596f6f333SJishnu Prakash 		channel->low_thr_en = true;
60696f6f333SJishnu Prakash 		adc_code = qcom_adc_tm5_gen2_temp_res_scale(high);
60796f6f333SJishnu Prakash 		put_unaligned_le16(adc_code, &buf[9]);
60896f6f333SJishnu Prakash 	} else {
60996f6f333SJishnu Prakash 		channel->low_thr_en = false;
61096f6f333SJishnu Prakash 	}
61196f6f333SJishnu Prakash 
61296f6f333SJishnu Prakash 	/* Low temperature corresponds to high voltage threshold */
61396f6f333SJishnu Prakash 	if (low != -INT_MAX) {
61496f6f333SJishnu Prakash 		channel->high_thr_en = true;
61596f6f333SJishnu Prakash 		adc_code = qcom_adc_tm5_gen2_temp_res_scale(low);
61696f6f333SJishnu Prakash 		put_unaligned_le16(adc_code, &buf[11]);
61796f6f333SJishnu Prakash 	} else {
61896f6f333SJishnu Prakash 		channel->high_thr_en = false;
61996f6f333SJishnu Prakash 	}
62096f6f333SJishnu Prakash 
62196f6f333SJishnu Prakash 	buf[13] = ADC_TM_GEN2_MEAS_EN;
62296f6f333SJishnu Prakash 	if (channel->high_thr_en)
62396f6f333SJishnu Prakash 		buf[13] |= ADC_TM5_GEN2_HIGH_THR_INT_EN;
62496f6f333SJishnu Prakash 	if (channel->low_thr_en)
62596f6f333SJishnu Prakash 		buf[13] |= ADC_TM5_GEN2_LOW_THR_INT_EN;
62696f6f333SJishnu Prakash 
62796f6f333SJishnu Prakash 	ret = adc_tm5_write(chip, ADC_TM_GEN2_SID, buf, sizeof(buf));
62896f6f333SJishnu Prakash 	if (ret) {
62996f6f333SJishnu Prakash 		dev_err(chip->dev, "channel %d params write failed: %d\n", channel->channel, ret);
63096f6f333SJishnu Prakash 		goto config_fail;
63196f6f333SJishnu Prakash 	}
63296f6f333SJishnu Prakash 
63396f6f333SJishnu Prakash 	ret = adc_tm5_gen2_conv_req(channel->chip);
63496f6f333SJishnu Prakash 	if (ret < 0)
63596f6f333SJishnu Prakash 		dev_err(chip->dev, "adc-tm channel configure failed with %d\n", ret);
63696f6f333SJishnu Prakash 
63796f6f333SJishnu Prakash config_fail:
63896f6f333SJishnu Prakash 	mutex_unlock(&chip->adc_mutex_lock);
63996f6f333SJishnu Prakash 	return ret;
64096f6f333SJishnu Prakash }
64196f6f333SJishnu Prakash 
adc_tm5_set_trips(struct thermal_zone_device * tz,int low,int high)642ca1b9a9eSDaniel Lezcano static int adc_tm5_set_trips(struct thermal_zone_device *tz, int low, int high)
643ca66dca5SDmitry Baryshkov {
6445f68d078SDaniel Lezcano 	struct adc_tm5_channel *channel = thermal_zone_device_priv(tz);
645ca66dca5SDmitry Baryshkov 	struct adc_tm5_chip *chip;
646ca66dca5SDmitry Baryshkov 	int ret;
647ca66dca5SDmitry Baryshkov 
648ca66dca5SDmitry Baryshkov 	if (!channel)
649ca66dca5SDmitry Baryshkov 		return -EINVAL;
650ca66dca5SDmitry Baryshkov 
651ca66dca5SDmitry Baryshkov 	chip = channel->chip;
652ca66dca5SDmitry Baryshkov 	dev_dbg(chip->dev, "%d:low(mdegC):%d, high(mdegC):%d\n",
653ca66dca5SDmitry Baryshkov 		channel->channel, low, high);
654ca66dca5SDmitry Baryshkov 
655ca66dca5SDmitry Baryshkov 	if (high == INT_MAX && low <= -INT_MAX)
6567e70a89aSJishnu Prakash 		ret = chip->data->disable_channel(channel);
657ca66dca5SDmitry Baryshkov 	else
6587e70a89aSJishnu Prakash 		ret = chip->data->configure(channel, low, high);
659ca66dca5SDmitry Baryshkov 
660ca66dca5SDmitry Baryshkov 	return ret;
661ca66dca5SDmitry Baryshkov }
662ca66dca5SDmitry Baryshkov 
663ca1b9a9eSDaniel Lezcano static const struct thermal_zone_device_ops adc_tm5_thermal_ops = {
664ca66dca5SDmitry Baryshkov 	.get_temp = adc_tm5_get_temp,
665ca66dca5SDmitry Baryshkov 	.set_trips = adc_tm5_set_trips,
666ca66dca5SDmitry Baryshkov };
667ca66dca5SDmitry Baryshkov 
adc_tm5_register_tzd(struct adc_tm5_chip * adc_tm)668ca66dca5SDmitry Baryshkov static int adc_tm5_register_tzd(struct adc_tm5_chip *adc_tm)
669ca66dca5SDmitry Baryshkov {
670ca66dca5SDmitry Baryshkov 	unsigned int i;
671ca66dca5SDmitry Baryshkov 	struct thermal_zone_device *tzd;
672ca66dca5SDmitry Baryshkov 
673ca66dca5SDmitry Baryshkov 	for (i = 0; i < adc_tm->nchannels; i++) {
674ca66dca5SDmitry Baryshkov 		adc_tm->channels[i].chip = adc_tm;
675ca1b9a9eSDaniel Lezcano 		tzd = devm_thermal_of_zone_register(adc_tm->dev,
676ca66dca5SDmitry Baryshkov 						    adc_tm->channels[i].channel,
677ca66dca5SDmitry Baryshkov 						    &adc_tm->channels[i],
6787e70a89aSJishnu Prakash 						    &adc_tm5_thermal_ops);
679ca66dca5SDmitry Baryshkov 		if (IS_ERR(tzd)) {
68070ee251dSMatthias Kaehlcke 			if (PTR_ERR(tzd) == -ENODEV) {
6812baad249SManivannan Sadhasivam 				dev_dbg(adc_tm->dev, "thermal sensor on channel %d is not used\n",
68270ee251dSMatthias Kaehlcke 					 adc_tm->channels[i].channel);
68370ee251dSMatthias Kaehlcke 				continue;
68470ee251dSMatthias Kaehlcke 			}
68570ee251dSMatthias Kaehlcke 
686ca66dca5SDmitry Baryshkov 			dev_err(adc_tm->dev, "Error registering TZ zone for channel %d: %ld\n",
687ca66dca5SDmitry Baryshkov 				adc_tm->channels[i].channel, PTR_ERR(tzd));
688ca66dca5SDmitry Baryshkov 			return PTR_ERR(tzd);
689ca66dca5SDmitry Baryshkov 		}
690ca66dca5SDmitry Baryshkov 		adc_tm->channels[i].tzd = tzd;
691*7adbbb3bSYangtao Li 		devm_thermal_add_hwmon_sysfs(adc_tm->dev, tzd);
692ca66dca5SDmitry Baryshkov 	}
693ca66dca5SDmitry Baryshkov 
694ca66dca5SDmitry Baryshkov 	return 0;
695ca66dca5SDmitry Baryshkov }
696ca66dca5SDmitry Baryshkov 
adc_tm_hc_init(struct adc_tm5_chip * chip)697f6c83676SBjorn Andersson static int adc_tm_hc_init(struct adc_tm5_chip *chip)
698f6c83676SBjorn Andersson {
699f6c83676SBjorn Andersson 	unsigned int i;
700f6c83676SBjorn Andersson 	u8 buf[2];
701f6c83676SBjorn Andersson 	int ret;
702f6c83676SBjorn Andersson 
703f6c83676SBjorn Andersson 	for (i = 0; i < chip->nchannels; i++) {
704f6c83676SBjorn Andersson 		if (chip->channels[i].channel >= ADC_TM5_NUM_CHANNELS) {
705f6c83676SBjorn Andersson 			dev_err(chip->dev, "Invalid channel %d\n", chip->channels[i].channel);
706f6c83676SBjorn Andersson 			return -EINVAL;
707f6c83676SBjorn Andersson 		}
708f6c83676SBjorn Andersson 	}
709f6c83676SBjorn Andersson 
710f6c83676SBjorn Andersson 	buf[0] = chip->decimation;
711f6c83676SBjorn Andersson 	buf[1] = chip->avg_samples | ADC_TM5_FAST_AVG_EN;
712f6c83676SBjorn Andersson 
713f6c83676SBjorn Andersson 	ret = adc_tm5_write(chip, ADC_TM5_ADC_DIG_PARAM, buf, sizeof(buf));
714f6c83676SBjorn Andersson 	if (ret)
715f6c83676SBjorn Andersson 		dev_err(chip->dev, "block write failed: %d\n", ret);
716f6c83676SBjorn Andersson 
717f6c83676SBjorn Andersson 	return ret;
718f6c83676SBjorn Andersson }
719f6c83676SBjorn Andersson 
adc_tm5_init(struct adc_tm5_chip * chip)720ca66dca5SDmitry Baryshkov static int adc_tm5_init(struct adc_tm5_chip *chip)
721ca66dca5SDmitry Baryshkov {
722ca66dca5SDmitry Baryshkov 	u8 buf[4], channels_available;
723ca66dca5SDmitry Baryshkov 	int ret;
724ca66dca5SDmitry Baryshkov 	unsigned int i;
725ca66dca5SDmitry Baryshkov 
726ca66dca5SDmitry Baryshkov 	ret = adc_tm5_read(chip, ADC_TM5_NUM_BTM,
727ca66dca5SDmitry Baryshkov 			   &channels_available, sizeof(channels_available));
728ca66dca5SDmitry Baryshkov 	if (ret) {
729ca66dca5SDmitry Baryshkov 		dev_err(chip->dev, "read failed for BTM channels\n");
730ca66dca5SDmitry Baryshkov 		return ret;
731ca66dca5SDmitry Baryshkov 	}
732ca66dca5SDmitry Baryshkov 
73374369d04SColin Ian King 	for (i = 0; i < chip->nchannels; i++) {
73474369d04SColin Ian King 		if (chip->channels[i].channel >= channels_available) {
73574369d04SColin Ian King 			dev_err(chip->dev, "Invalid channel %d\n", chip->channels[i].channel);
73674369d04SColin Ian King 			return -EINVAL;
73774369d04SColin Ian King 		}
73874369d04SColin Ian King 	}
73974369d04SColin Ian King 
740ca66dca5SDmitry Baryshkov 	buf[0] = chip->decimation;
741ca66dca5SDmitry Baryshkov 	buf[1] = chip->avg_samples | ADC_TM5_FAST_AVG_EN;
742ca66dca5SDmitry Baryshkov 	buf[2] = ADC_TM5_TIMER1;
743ca66dca5SDmitry Baryshkov 	buf[3] = FIELD_PREP(ADC_TM5_MEAS_INTERVAL_CTL2_MASK, ADC_TM5_TIMER2) |
744ca66dca5SDmitry Baryshkov 		 FIELD_PREP(ADC_TM5_MEAS_INTERVAL_CTL3_MASK, ADC_TM5_TIMER3);
745ca66dca5SDmitry Baryshkov 
746ca66dca5SDmitry Baryshkov 	ret = adc_tm5_write(chip, ADC_TM5_ADC_DIG_PARAM, buf, sizeof(buf));
747ca66dca5SDmitry Baryshkov 	if (ret) {
748ca66dca5SDmitry Baryshkov 		dev_err(chip->dev, "block write failed: %d\n", ret);
749ca66dca5SDmitry Baryshkov 		return ret;
750ca66dca5SDmitry Baryshkov 	}
751ca66dca5SDmitry Baryshkov 
752ca66dca5SDmitry Baryshkov 	return ret;
753ca66dca5SDmitry Baryshkov }
754ca66dca5SDmitry Baryshkov 
adc_tm5_gen2_init(struct adc_tm5_chip * chip)75596f6f333SJishnu Prakash static int adc_tm5_gen2_init(struct adc_tm5_chip *chip)
75696f6f333SJishnu Prakash {
75796f6f333SJishnu Prakash 	u8 channels_available;
75896f6f333SJishnu Prakash 	int ret;
75996f6f333SJishnu Prakash 	unsigned int i;
76096f6f333SJishnu Prakash 
76196f6f333SJishnu Prakash 	ret = adc_tm5_read(chip, ADC_TM5_NUM_BTM,
76296f6f333SJishnu Prakash 			   &channels_available, sizeof(channels_available));
76396f6f333SJishnu Prakash 	if (ret) {
76496f6f333SJishnu Prakash 		dev_err(chip->dev, "read failed for BTM channels\n");
76596f6f333SJishnu Prakash 		return ret;
76696f6f333SJishnu Prakash 	}
76796f6f333SJishnu Prakash 
76896f6f333SJishnu Prakash 	for (i = 0; i < chip->nchannels; i++) {
76996f6f333SJishnu Prakash 		if (chip->channels[i].channel >= channels_available) {
77096f6f333SJishnu Prakash 			dev_err(chip->dev, "Invalid channel %d\n", chip->channels[i].channel);
77196f6f333SJishnu Prakash 			return -EINVAL;
77296f6f333SJishnu Prakash 		}
77396f6f333SJishnu Prakash 	}
77496f6f333SJishnu Prakash 
77596f6f333SJishnu Prakash 	mutex_init(&chip->adc_mutex_lock);
77696f6f333SJishnu Prakash 
77796f6f333SJishnu Prakash 	return ret;
77896f6f333SJishnu Prakash }
77996f6f333SJishnu Prakash 
adc_tm5_get_dt_channel_data(struct adc_tm5_chip * adc_tm,struct adc_tm5_channel * channel,struct device_node * node)780ca66dca5SDmitry Baryshkov static int adc_tm5_get_dt_channel_data(struct adc_tm5_chip *adc_tm,
781ca66dca5SDmitry Baryshkov 				       struct adc_tm5_channel *channel,
782ca66dca5SDmitry Baryshkov 				       struct device_node *node)
783ca66dca5SDmitry Baryshkov {
784ca66dca5SDmitry Baryshkov 	const char *name = node->name;
78596f6f333SJishnu Prakash 	u32 chan, value, adc_channel, varr[2];
786ca66dca5SDmitry Baryshkov 	int ret;
787ca66dca5SDmitry Baryshkov 	struct device *dev = adc_tm->dev;
788ca66dca5SDmitry Baryshkov 	struct of_phandle_args args;
789ca66dca5SDmitry Baryshkov 
790ca66dca5SDmitry Baryshkov 	ret = of_property_read_u32(node, "reg", &chan);
791ca66dca5SDmitry Baryshkov 	if (ret) {
792ca66dca5SDmitry Baryshkov 		dev_err(dev, "%s: invalid channel number %d\n", name, ret);
793ca66dca5SDmitry Baryshkov 		return ret;
794ca66dca5SDmitry Baryshkov 	}
795ca66dca5SDmitry Baryshkov 
796ca66dca5SDmitry Baryshkov 	if (chan >= ADC_TM5_NUM_CHANNELS) {
797ca66dca5SDmitry Baryshkov 		dev_err(dev, "%s: channel number too big: %d\n", name, chan);
798ca66dca5SDmitry Baryshkov 		return -EINVAL;
799ca66dca5SDmitry Baryshkov 	}
800ca66dca5SDmitry Baryshkov 
801ca66dca5SDmitry Baryshkov 	channel->channel = chan;
802ca66dca5SDmitry Baryshkov 
803ca66dca5SDmitry Baryshkov 	/*
804ca66dca5SDmitry Baryshkov 	 * We are tied to PMIC's ADC controller, which always use single
805ca66dca5SDmitry Baryshkov 	 * argument for channel number.  So don't bother parsing
806ca66dca5SDmitry Baryshkov 	 * #io-channel-cells, just enforce cell_count = 1.
807ca66dca5SDmitry Baryshkov 	 */
808ca66dca5SDmitry Baryshkov 	ret = of_parse_phandle_with_fixed_args(node, "io-channels", 1, 0, &args);
809ca66dca5SDmitry Baryshkov 	if (ret < 0) {
810ca66dca5SDmitry Baryshkov 		dev_err(dev, "%s: error parsing ADC channel number %d: %d\n", name, chan, ret);
811ca66dca5SDmitry Baryshkov 		return ret;
812ca66dca5SDmitry Baryshkov 	}
813ca66dca5SDmitry Baryshkov 	of_node_put(args.np);
814ca66dca5SDmitry Baryshkov 
81596f6f333SJishnu Prakash 	if (args.args_count != 1) {
81696f6f333SJishnu Prakash 		dev_err(dev, "%s: invalid args count for ADC channel %d\n", name, chan);
81796f6f333SJishnu Prakash 		return -EINVAL;
81896f6f333SJishnu Prakash 	}
81996f6f333SJishnu Prakash 
82096f6f333SJishnu Prakash 	adc_channel = args.args[0];
82196f6f333SJishnu Prakash 	if (adc_tm->data->gen == ADC_TM5_GEN2)
82296f6f333SJishnu Prakash 		adc_channel &= 0xff;
82396f6f333SJishnu Prakash 
82496f6f333SJishnu Prakash 	if (adc_channel >= ADC5_MAX_CHANNEL) {
825ca66dca5SDmitry Baryshkov 		dev_err(dev, "%s: invalid ADC channel number %d\n", name, chan);
8265d8db38aSYang Yingliang 		return -EINVAL;
827ca66dca5SDmitry Baryshkov 	}
828ca66dca5SDmitry Baryshkov 	channel->adc_channel = args.args[0];
829ca66dca5SDmitry Baryshkov 
83017fe12a2SNuno Sá 	channel->iio = devm_fwnode_iio_channel_get_by_name(adc_tm->dev,
83117fe12a2SNuno Sá 							   of_fwnode_handle(node), NULL);
832ca66dca5SDmitry Baryshkov 	if (IS_ERR(channel->iio)) {
833ca66dca5SDmitry Baryshkov 		ret = PTR_ERR(channel->iio);
834ca66dca5SDmitry Baryshkov 		if (ret != -EPROBE_DEFER)
835ca66dca5SDmitry Baryshkov 			dev_err(dev, "%s: error getting channel: %d\n", name, ret);
836ca66dca5SDmitry Baryshkov 		return ret;
837ca66dca5SDmitry Baryshkov 	}
838ca66dca5SDmitry Baryshkov 
839ca66dca5SDmitry Baryshkov 	ret = of_property_read_u32_array(node, "qcom,pre-scaling", varr, 2);
840ca66dca5SDmitry Baryshkov 	if (!ret) {
841ca66dca5SDmitry Baryshkov 		ret = qcom_adc5_prescaling_from_dt(varr[0], varr[1]);
842ca66dca5SDmitry Baryshkov 		if (ret < 0) {
843ca66dca5SDmitry Baryshkov 			dev_err(dev, "%s: invalid pre-scaling <%d %d>\n",
844ca66dca5SDmitry Baryshkov 				name, varr[0], varr[1]);
845ca66dca5SDmitry Baryshkov 			return ret;
846ca66dca5SDmitry Baryshkov 		}
847ca66dca5SDmitry Baryshkov 		channel->prescale = ret;
848ca66dca5SDmitry Baryshkov 	} else {
849ca66dca5SDmitry Baryshkov 		/* 1:1 prescale is index 0 */
850ca66dca5SDmitry Baryshkov 		channel->prescale = 0;
851ca66dca5SDmitry Baryshkov 	}
852ca66dca5SDmitry Baryshkov 
853ca66dca5SDmitry Baryshkov 	ret = of_property_read_u32(node, "qcom,hw-settle-time-us", &value);
854ca66dca5SDmitry Baryshkov 	if (!ret) {
855ca66dca5SDmitry Baryshkov 		ret = qcom_adc5_hw_settle_time_from_dt(value, adc_tm->data->hw_settle);
856ca66dca5SDmitry Baryshkov 		if (ret < 0) {
857ca66dca5SDmitry Baryshkov 			dev_err(dev, "%s invalid hw-settle-time-us %d us\n",
858ca66dca5SDmitry Baryshkov 				name, value);
859ca66dca5SDmitry Baryshkov 			return ret;
860ca66dca5SDmitry Baryshkov 		}
861ca66dca5SDmitry Baryshkov 		channel->hw_settle_time = ret;
862ca66dca5SDmitry Baryshkov 	} else {
863ca66dca5SDmitry Baryshkov 		channel->hw_settle_time = VADC_DEF_HW_SETTLE_TIME;
864ca66dca5SDmitry Baryshkov 	}
865ca66dca5SDmitry Baryshkov 
866ca66dca5SDmitry Baryshkov 	if (of_property_read_bool(node, "qcom,ratiometric"))
867ca66dca5SDmitry Baryshkov 		channel->cal_method = ADC_TM5_RATIOMETRIC_CAL;
868ca66dca5SDmitry Baryshkov 	else
869ca66dca5SDmitry Baryshkov 		channel->cal_method = ADC_TM5_ABSOLUTE_CAL;
870ca66dca5SDmitry Baryshkov 
87196f6f333SJishnu Prakash 	if (adc_tm->data->gen == ADC_TM5_GEN2) {
87296f6f333SJishnu Prakash 		ret = of_property_read_u32(node, "qcom,decimation", &value);
87396f6f333SJishnu Prakash 		if (!ret) {
87496f6f333SJishnu Prakash 			ret = qcom_adc5_decimation_from_dt(value, adc_tm->data->decimation);
87596f6f333SJishnu Prakash 			if (ret < 0) {
87696f6f333SJishnu Prakash 				dev_err(dev, "invalid decimation %d\n", value);
87796f6f333SJishnu Prakash 				return ret;
87896f6f333SJishnu Prakash 			}
87996f6f333SJishnu Prakash 			channel->decimation = ret;
88096f6f333SJishnu Prakash 		} else {
88196f6f333SJishnu Prakash 			channel->decimation = ADC5_DECIMATION_DEFAULT;
88296f6f333SJishnu Prakash 		}
88396f6f333SJishnu Prakash 
88496f6f333SJishnu Prakash 		ret = of_property_read_u32(node, "qcom,avg-samples", &value);
88596f6f333SJishnu Prakash 		if (!ret) {
88696f6f333SJishnu Prakash 			ret = qcom_adc5_avg_samples_from_dt(value);
88796f6f333SJishnu Prakash 			if (ret < 0) {
88896f6f333SJishnu Prakash 				dev_err(dev, "invalid avg-samples %d\n", value);
88996f6f333SJishnu Prakash 				return ret;
89096f6f333SJishnu Prakash 			}
89196f6f333SJishnu Prakash 			channel->avg_samples = ret;
89296f6f333SJishnu Prakash 		} else {
89396f6f333SJishnu Prakash 			channel->avg_samples = VADC_DEF_AVG_SAMPLES;
89496f6f333SJishnu Prakash 		}
89596f6f333SJishnu Prakash 	}
89696f6f333SJishnu Prakash 
897ca66dca5SDmitry Baryshkov 	return 0;
898ca66dca5SDmitry Baryshkov }
899ca66dca5SDmitry Baryshkov 
9007e70a89aSJishnu Prakash static const struct adc_tm5_data adc_tm5_data_pmic = {
9017e70a89aSJishnu Prakash 	.full_scale_code_volt = 0x70e4,
9027e70a89aSJishnu Prakash 	.decimation = (unsigned int []) { 250, 420, 840 },
9037e70a89aSJishnu Prakash 	.hw_settle = (unsigned int []) { 15, 100, 200, 300, 400, 500, 600, 700,
9047e70a89aSJishnu Prakash 					 1000, 2000, 4000, 8000, 16000, 32000,
9057e70a89aSJishnu Prakash 					 64000, 128000 },
9067e70a89aSJishnu Prakash 	.disable_channel = adc_tm5_disable_channel,
9077e70a89aSJishnu Prakash 	.configure = adc_tm5_configure,
9087e70a89aSJishnu Prakash 	.isr = adc_tm5_isr,
9097e70a89aSJishnu Prakash 	.init = adc_tm5_init,
9107e70a89aSJishnu Prakash 	.irq_name = "pm-adc-tm5",
9117e70a89aSJishnu Prakash 	.gen = ADC_TM5,
9127e70a89aSJishnu Prakash };
9137e70a89aSJishnu Prakash 
9147e70a89aSJishnu Prakash static const struct adc_tm5_data adc_tm_hc_data_pmic = {
9157e70a89aSJishnu Prakash 	.full_scale_code_volt = 0x70e4,
9167e70a89aSJishnu Prakash 	.decimation = (unsigned int []) { 256, 512, 1024 },
9177e70a89aSJishnu Prakash 	.hw_settle = (unsigned int []) { 0, 100, 200, 300, 400, 500, 600, 700,
9187e70a89aSJishnu Prakash 					 1000, 2000, 4000, 6000, 8000, 10000 },
9197e70a89aSJishnu Prakash 	.disable_channel = adc_tm5_disable_channel,
9207e70a89aSJishnu Prakash 	.configure = adc_tm5_configure,
9217e70a89aSJishnu Prakash 	.isr = adc_tm5_isr,
9227e70a89aSJishnu Prakash 	.init = adc_tm_hc_init,
9237e70a89aSJishnu Prakash 	.irq_name = "pm-adc-tm5",
9247e70a89aSJishnu Prakash 	.gen = ADC_TM_HC,
9257e70a89aSJishnu Prakash };
9267e70a89aSJishnu Prakash 
92796f6f333SJishnu Prakash static const struct adc_tm5_data adc_tm5_gen2_data_pmic = {
92896f6f333SJishnu Prakash 	.full_scale_code_volt = 0x70e4,
92996f6f333SJishnu Prakash 	.decimation = (unsigned int []) { 85, 340, 1360 },
93096f6f333SJishnu Prakash 	.hw_settle = (unsigned int []) { 15, 100, 200, 300, 400, 500, 600, 700,
93196f6f333SJishnu Prakash 					 1000, 2000, 4000, 8000, 16000, 32000,
93296f6f333SJishnu Prakash 					 64000, 128000 },
93396f6f333SJishnu Prakash 	.disable_channel = adc_tm5_gen2_disable_channel,
93496f6f333SJishnu Prakash 	.configure = adc_tm5_gen2_configure,
93596f6f333SJishnu Prakash 	.isr = adc_tm5_gen2_isr,
93696f6f333SJishnu Prakash 	.init = adc_tm5_gen2_init,
93796f6f333SJishnu Prakash 	.irq_name = "pm-adc-tm5-gen2",
93896f6f333SJishnu Prakash 	.gen = ADC_TM5_GEN2,
93996f6f333SJishnu Prakash };
94096f6f333SJishnu Prakash 
adc_tm5_get_dt_data(struct adc_tm5_chip * adc_tm,struct device_node * node)941ca66dca5SDmitry Baryshkov static int adc_tm5_get_dt_data(struct adc_tm5_chip *adc_tm, struct device_node *node)
942ca66dca5SDmitry Baryshkov {
943ca66dca5SDmitry Baryshkov 	struct adc_tm5_channel *channels;
944ca66dca5SDmitry Baryshkov 	struct device_node *child;
945ca66dca5SDmitry Baryshkov 	u32 value;
946ca66dca5SDmitry Baryshkov 	int ret;
947ca66dca5SDmitry Baryshkov 	struct device *dev = adc_tm->dev;
948ca66dca5SDmitry Baryshkov 
949ca66dca5SDmitry Baryshkov 	adc_tm->nchannels = of_get_available_child_count(node);
950ca66dca5SDmitry Baryshkov 	if (!adc_tm->nchannels)
951ca66dca5SDmitry Baryshkov 		return -EINVAL;
952ca66dca5SDmitry Baryshkov 
953ca66dca5SDmitry Baryshkov 	adc_tm->channels = devm_kcalloc(dev, adc_tm->nchannels,
954ca66dca5SDmitry Baryshkov 					sizeof(*adc_tm->channels), GFP_KERNEL);
955ca66dca5SDmitry Baryshkov 	if (!adc_tm->channels)
956ca66dca5SDmitry Baryshkov 		return -ENOMEM;
957ca66dca5SDmitry Baryshkov 
958ca66dca5SDmitry Baryshkov 	channels = adc_tm->channels;
959ca66dca5SDmitry Baryshkov 
960ca66dca5SDmitry Baryshkov 	adc_tm->data = of_device_get_match_data(dev);
961ca66dca5SDmitry Baryshkov 	if (!adc_tm->data)
962ca66dca5SDmitry Baryshkov 		adc_tm->data = &adc_tm5_data_pmic;
963ca66dca5SDmitry Baryshkov 
964ca66dca5SDmitry Baryshkov 	ret = of_property_read_u32(node, "qcom,decimation", &value);
965ca66dca5SDmitry Baryshkov 	if (!ret) {
966ca66dca5SDmitry Baryshkov 		ret = qcom_adc5_decimation_from_dt(value, adc_tm->data->decimation);
967ca66dca5SDmitry Baryshkov 		if (ret < 0) {
968ca66dca5SDmitry Baryshkov 			dev_err(dev, "invalid decimation %d\n", value);
969ca66dca5SDmitry Baryshkov 			return ret;
970ca66dca5SDmitry Baryshkov 		}
971ca66dca5SDmitry Baryshkov 		adc_tm->decimation = ret;
972ca66dca5SDmitry Baryshkov 	} else {
973ca66dca5SDmitry Baryshkov 		adc_tm->decimation = ADC5_DECIMATION_DEFAULT;
974ca66dca5SDmitry Baryshkov 	}
975ca66dca5SDmitry Baryshkov 
976ca66dca5SDmitry Baryshkov 	ret = of_property_read_u32(node, "qcom,avg-samples", &value);
977ca66dca5SDmitry Baryshkov 	if (!ret) {
978ca66dca5SDmitry Baryshkov 		ret = qcom_adc5_avg_samples_from_dt(value);
979ca66dca5SDmitry Baryshkov 		if (ret < 0) {
980ca66dca5SDmitry Baryshkov 			dev_err(dev, "invalid avg-samples %d\n", value);
981ca66dca5SDmitry Baryshkov 			return ret;
982ca66dca5SDmitry Baryshkov 		}
983ca66dca5SDmitry Baryshkov 		adc_tm->avg_samples = ret;
984ca66dca5SDmitry Baryshkov 	} else {
985ca66dca5SDmitry Baryshkov 		adc_tm->avg_samples = VADC_DEF_AVG_SAMPLES;
986ca66dca5SDmitry Baryshkov 	}
987ca66dca5SDmitry Baryshkov 
988ca66dca5SDmitry Baryshkov 	for_each_available_child_of_node(node, child) {
989ca66dca5SDmitry Baryshkov 		ret = adc_tm5_get_dt_channel_data(adc_tm, channels, child);
990ca66dca5SDmitry Baryshkov 		if (ret) {
991ca66dca5SDmitry Baryshkov 			of_node_put(child);
992ca66dca5SDmitry Baryshkov 			return ret;
993ca66dca5SDmitry Baryshkov 		}
994ca66dca5SDmitry Baryshkov 
995ca66dca5SDmitry Baryshkov 		channels++;
996ca66dca5SDmitry Baryshkov 	}
997ca66dca5SDmitry Baryshkov 
998ca66dca5SDmitry Baryshkov 	return 0;
999ca66dca5SDmitry Baryshkov }
1000ca66dca5SDmitry Baryshkov 
adc_tm5_probe(struct platform_device * pdev)1001ca66dca5SDmitry Baryshkov static int adc_tm5_probe(struct platform_device *pdev)
1002ca66dca5SDmitry Baryshkov {
1003ca66dca5SDmitry Baryshkov 	struct device_node *node = pdev->dev.of_node;
1004ca66dca5SDmitry Baryshkov 	struct device *dev = &pdev->dev;
1005ca66dca5SDmitry Baryshkov 	struct adc_tm5_chip *adc_tm;
1006ca66dca5SDmitry Baryshkov 	struct regmap *regmap;
1007ca66dca5SDmitry Baryshkov 	int ret, irq;
1008ca66dca5SDmitry Baryshkov 	u32 reg;
1009ca66dca5SDmitry Baryshkov 
1010ca66dca5SDmitry Baryshkov 	regmap = dev_get_regmap(dev->parent, NULL);
1011ca66dca5SDmitry Baryshkov 	if (!regmap)
1012ca66dca5SDmitry Baryshkov 		return -ENODEV;
1013ca66dca5SDmitry Baryshkov 
1014ca66dca5SDmitry Baryshkov 	ret = of_property_read_u32(node, "reg", &reg);
1015ca66dca5SDmitry Baryshkov 	if (ret)
1016ca66dca5SDmitry Baryshkov 		return ret;
1017ca66dca5SDmitry Baryshkov 
1018ca66dca5SDmitry Baryshkov 	adc_tm = devm_kzalloc(&pdev->dev, sizeof(*adc_tm), GFP_KERNEL);
1019ca66dca5SDmitry Baryshkov 	if (!adc_tm)
1020ca66dca5SDmitry Baryshkov 		return -ENOMEM;
1021ca66dca5SDmitry Baryshkov 
1022ca66dca5SDmitry Baryshkov 	adc_tm->regmap = regmap;
1023ca66dca5SDmitry Baryshkov 	adc_tm->dev = dev;
1024ca66dca5SDmitry Baryshkov 	adc_tm->base = reg;
1025ca66dca5SDmitry Baryshkov 
1026ca66dca5SDmitry Baryshkov 	irq = platform_get_irq(pdev, 0);
1027e9202098SJiapeng Chong 	if (irq < 0)
1028ca66dca5SDmitry Baryshkov 		return irq;
1029ca66dca5SDmitry Baryshkov 
1030ca66dca5SDmitry Baryshkov 	ret = adc_tm5_get_dt_data(adc_tm, node);
10316f894164SJohan Hovold 	if (ret)
10326f894164SJohan Hovold 		return dev_err_probe(dev, ret, "get dt data failed\n");
1033ca66dca5SDmitry Baryshkov 
10347e70a89aSJishnu Prakash 	ret = adc_tm->data->init(adc_tm);
1035ca66dca5SDmitry Baryshkov 	if (ret) {
1036ca66dca5SDmitry Baryshkov 		dev_err(dev, "adc-tm init failed\n");
1037ca66dca5SDmitry Baryshkov 		return ret;
1038ca66dca5SDmitry Baryshkov 	}
1039ca66dca5SDmitry Baryshkov 
1040ca66dca5SDmitry Baryshkov 	ret = adc_tm5_register_tzd(adc_tm);
1041ca66dca5SDmitry Baryshkov 	if (ret) {
1042ca66dca5SDmitry Baryshkov 		dev_err(dev, "tzd register failed\n");
1043ca66dca5SDmitry Baryshkov 		return ret;
1044ca66dca5SDmitry Baryshkov 	}
1045ca66dca5SDmitry Baryshkov 
10467e70a89aSJishnu Prakash 	return devm_request_threaded_irq(dev, irq, NULL, adc_tm->data->isr,
10477e70a89aSJishnu Prakash 			IRQF_ONESHOT, adc_tm->data->irq_name, adc_tm);
1048ca66dca5SDmitry Baryshkov }
1049ca66dca5SDmitry Baryshkov 
1050ca66dca5SDmitry Baryshkov static const struct of_device_id adc_tm5_match_table[] = {
1051ca66dca5SDmitry Baryshkov 	{
1052ca66dca5SDmitry Baryshkov 		.compatible = "qcom,spmi-adc-tm5",
1053ca66dca5SDmitry Baryshkov 		.data = &adc_tm5_data_pmic,
1054ca66dca5SDmitry Baryshkov 	},
1055f6c83676SBjorn Andersson 	{
1056f6c83676SBjorn Andersson 		.compatible = "qcom,spmi-adc-tm-hc",
1057f6c83676SBjorn Andersson 		.data = &adc_tm_hc_data_pmic,
1058f6c83676SBjorn Andersson 	},
105996f6f333SJishnu Prakash 	{
106096f6f333SJishnu Prakash 		.compatible = "qcom,spmi-adc-tm5-gen2",
106196f6f333SJishnu Prakash 		.data = &adc_tm5_gen2_data_pmic,
106296f6f333SJishnu Prakash 	},
1063ca66dca5SDmitry Baryshkov 	{ }
1064ca66dca5SDmitry Baryshkov };
1065ca66dca5SDmitry Baryshkov MODULE_DEVICE_TABLE(of, adc_tm5_match_table);
1066ca66dca5SDmitry Baryshkov 
1067ca66dca5SDmitry Baryshkov static struct platform_driver adc_tm5_driver = {
1068ca66dca5SDmitry Baryshkov 	.driver = {
1069ca66dca5SDmitry Baryshkov 		.name = "qcom-spmi-adc-tm5",
1070ca66dca5SDmitry Baryshkov 		.of_match_table = adc_tm5_match_table,
1071ca66dca5SDmitry Baryshkov 	},
1072ca66dca5SDmitry Baryshkov 	.probe = adc_tm5_probe,
1073ca66dca5SDmitry Baryshkov };
1074ca66dca5SDmitry Baryshkov module_platform_driver(adc_tm5_driver);
1075ca66dca5SDmitry Baryshkov 
1076ca66dca5SDmitry Baryshkov MODULE_DESCRIPTION("SPMI PMIC Thermal Monitor ADC driver");
1077ca66dca5SDmitry Baryshkov MODULE_LICENSE("GPL v2");
1078