xref: /openbmc/linux/drivers/iio/adc/aspeed_adc.c (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
175a6faf6SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
257380323SRick Altherr /*
31b5ceb55SBilly Tsai  * Aspeed AST2400/2500/2600 ADC
457380323SRick Altherr  *
557380323SRick Altherr  * Copyright (C) 2017 Google, Inc.
626a9f730SBilly Tsai  * Copyright (C) 2021 Aspeed Technology Inc.
790f96477SBilly Tsai  *
890f96477SBilly Tsai  * ADC clock formula:
990f96477SBilly Tsai  * Ast2400/Ast2500:
1090f96477SBilly Tsai  * clock period = period of PCLK * 2 * (ADC0C[31:17] + 1) * (ADC0C[9:0] + 1)
1190f96477SBilly Tsai  * Ast2600:
1290f96477SBilly Tsai  * clock period = period of PCLK * 2 * (ADC0C[15:0] + 1)
1357380323SRick Altherr  */
1457380323SRick Altherr 
1557380323SRick Altherr #include <linux/clk.h>
1657380323SRick Altherr #include <linux/clk-provider.h>
1757380323SRick Altherr #include <linux/err.h>
1857380323SRick Altherr #include <linux/errno.h>
1957380323SRick Altherr #include <linux/io.h>
2057380323SRick Altherr #include <linux/module.h>
2157380323SRick Altherr #include <linux/of_platform.h>
2257380323SRick Altherr #include <linux/platform_device.h>
231b5ceb55SBilly Tsai #include <linux/regulator/consumer.h>
24edf7550aSJoel Stanley #include <linux/reset.h>
2557380323SRick Altherr #include <linux/spinlock.h>
2657380323SRick Altherr #include <linux/types.h>
2726a9f730SBilly Tsai #include <linux/bitfield.h>
28d0a4c17bSBilly Tsai #include <linux/regmap.h>
29d0a4c17bSBilly Tsai #include <linux/mfd/syscon.h>
3057380323SRick Altherr 
3157380323SRick Altherr #include <linux/iio/iio.h>
3257380323SRick Altherr #include <linux/iio/driver.h>
33737cc2a5SMykola Kostenok #include <linux/iopoll.h>
3457380323SRick Altherr 
3557380323SRick Altherr #define ASPEED_RESOLUTION_BITS		10
3657380323SRick Altherr #define ASPEED_CLOCKS_PER_SAMPLE	12
3757380323SRick Altherr 
3857380323SRick Altherr #define ASPEED_REG_ENGINE_CONTROL	0x00
3957380323SRick Altherr #define ASPEED_REG_INTERRUPT_CONTROL	0x04
4057380323SRick Altherr #define ASPEED_REG_VGA_DETECT_CONTROL	0x08
4157380323SRick Altherr #define ASPEED_REG_CLOCK_CONTROL	0x0C
4226a9f730SBilly Tsai #define ASPEED_REG_COMPENSATION_TRIM	0xC4
4326a9f730SBilly Tsai /*
4426a9f730SBilly Tsai  * The register offset between 0xC8~0xCC can be read and won't affect the
4526a9f730SBilly Tsai  * hardware logic in each version of ADC.
4626a9f730SBilly Tsai  */
4726a9f730SBilly Tsai #define ASPEED_REG_MAX			0xD0
4857380323SRick Altherr 
4926a9f730SBilly Tsai #define ASPEED_ADC_ENGINE_ENABLE		BIT(0)
5026a9f730SBilly Tsai #define ASPEED_ADC_OP_MODE			GENMASK(3, 1)
5126a9f730SBilly Tsai #define ASPEED_ADC_OP_MODE_PWR_DOWN		0
5226a9f730SBilly Tsai #define ASPEED_ADC_OP_MODE_STANDBY		1
5326a9f730SBilly Tsai #define ASPEED_ADC_OP_MODE_NORMAL		7
5426a9f730SBilly Tsai #define ASPEED_ADC_CTRL_COMPENSATION		BIT(4)
5526a9f730SBilly Tsai #define ASPEED_ADC_AUTO_COMPENSATION		BIT(5)
5626a9f730SBilly Tsai /*
5726a9f730SBilly Tsai  * Bit 6 determines not only the reference voltage range but also the dividing
5826a9f730SBilly Tsai  * circuit for battery sensing.
5926a9f730SBilly Tsai  */
6026a9f730SBilly Tsai #define ASPEED_ADC_REF_VOLTAGE			GENMASK(7, 6)
6126a9f730SBilly Tsai #define ASPEED_ADC_REF_VOLTAGE_2500mV		0
6226a9f730SBilly Tsai #define ASPEED_ADC_REF_VOLTAGE_1200mV		1
6326a9f730SBilly Tsai #define ASPEED_ADC_REF_VOLTAGE_EXT_HIGH		2
6426a9f730SBilly Tsai #define ASPEED_ADC_REF_VOLTAGE_EXT_LOW		3
6526a9f730SBilly Tsai #define ASPEED_ADC_BAT_SENSING_DIV		BIT(6)
6626a9f730SBilly Tsai #define ASPEED_ADC_BAT_SENSING_DIV_2_3		0
6726a9f730SBilly Tsai #define ASPEED_ADC_BAT_SENSING_DIV_1_3		1
68737cc2a5SMykola Kostenok #define ASPEED_ADC_CTRL_INIT_RDY		BIT(8)
6926a9f730SBilly Tsai #define ASPEED_ADC_CH7_MODE			BIT(12)
7026a9f730SBilly Tsai #define ASPEED_ADC_CH7_NORMAL			0
7126a9f730SBilly Tsai #define ASPEED_ADC_CH7_BAT			1
7226a9f730SBilly Tsai #define ASPEED_ADC_BAT_SENSING_ENABLE		BIT(13)
7326a9f730SBilly Tsai #define ASPEED_ADC_CTRL_CHANNEL			GENMASK(31, 16)
7426a9f730SBilly Tsai #define ASPEED_ADC_CTRL_CHANNEL_ENABLE(ch)	FIELD_PREP(ASPEED_ADC_CTRL_CHANNEL, BIT(ch))
75737cc2a5SMykola Kostenok 
76737cc2a5SMykola Kostenok #define ASPEED_ADC_INIT_POLLING_TIME	500
77737cc2a5SMykola Kostenok #define ASPEED_ADC_INIT_TIMEOUT		500000
7813d4f9dfSBilly Tsai /*
7913d4f9dfSBilly Tsai  * When the sampling rate is too high, the ADC may not have enough charging
8013d4f9dfSBilly Tsai  * time, resulting in a low voltage value. Thus, the default uses a slow
8113d4f9dfSBilly Tsai  * sampling rate for most use cases.
8213d4f9dfSBilly Tsai  */
8313d4f9dfSBilly Tsai #define ASPEED_ADC_DEF_SAMPLING_RATE	65000
84737cc2a5SMykola Kostenok 
85d0a4c17bSBilly Tsai struct aspeed_adc_trim_locate {
86d0a4c17bSBilly Tsai 	const unsigned int offset;
87d0a4c17bSBilly Tsai 	const unsigned int field;
88d0a4c17bSBilly Tsai };
8957380323SRick Altherr 
9057380323SRick Altherr struct aspeed_adc_model_data {
9157380323SRick Altherr 	const char *model_name;
9257380323SRick Altherr 	unsigned int min_sampling_rate;	// Hz
9357380323SRick Altherr 	unsigned int max_sampling_rate;	// Hz
94eaa74a8dSBilly Tsai 	unsigned int vref_fixed_mv;
95737cc2a5SMykola Kostenok 	bool wait_init_sequence;
96eaa74a8dSBilly Tsai 	bool need_prescaler;
97df05f384SBilly Tsai 	bool bat_sense_sup;
98eaa74a8dSBilly Tsai 	u8 scaler_bit_width;
99eaa74a8dSBilly Tsai 	unsigned int num_channels;
100d0a4c17bSBilly Tsai 	const struct aspeed_adc_trim_locate *trim_locate;
10157380323SRick Altherr };
10257380323SRick Altherr 
103df05f384SBilly Tsai struct adc_gain {
104df05f384SBilly Tsai 	u8 mult;
105df05f384SBilly Tsai 	u8 div;
10657380323SRick Altherr };
10757380323SRick Altherr 
10857380323SRick Altherr struct aspeed_adc_data {
10957380323SRick Altherr 	struct device		*dev;
11089c65417SBilly Tsai 	const struct aspeed_adc_model_data *model_data;
1111b5ceb55SBilly Tsai 	struct regulator	*regulator;
11257380323SRick Altherr 	void __iomem		*base;
11357380323SRick Altherr 	spinlock_t		clk_lock;
11490f96477SBilly Tsai 	struct clk_hw		*fixed_div_clk;
11557380323SRick Altherr 	struct clk_hw		*clk_prescaler;
11657380323SRick Altherr 	struct clk_hw		*clk_scaler;
117edf7550aSJoel Stanley 	struct reset_control	*rst;
118eaa74a8dSBilly Tsai 	int			vref_mv;
11913d4f9dfSBilly Tsai 	u32			sample_period_ns;
120f2836e8cSBilly Tsai 	int			cv;
121df05f384SBilly Tsai 	bool			battery_sensing;
122df05f384SBilly Tsai 	struct adc_gain		battery_mode_gain;
12357380323SRick Altherr };
12457380323SRick Altherr 
12557380323SRick Altherr #define ASPEED_CHAN(_idx, _data_reg_addr) {			\
12657380323SRick Altherr 	.type = IIO_VOLTAGE,					\
12757380323SRick Altherr 	.indexed = 1,						\
12857380323SRick Altherr 	.channel = (_idx),					\
12957380323SRick Altherr 	.address = (_data_reg_addr),				\
13057380323SRick Altherr 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
13157380323SRick Altherr 	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |	\
132f2836e8cSBilly Tsai 				BIT(IIO_CHAN_INFO_SAMP_FREQ) |	\
133f2836e8cSBilly Tsai 				BIT(IIO_CHAN_INFO_OFFSET),	\
13457380323SRick Altherr }
13557380323SRick Altherr 
13657380323SRick Altherr static const struct iio_chan_spec aspeed_adc_iio_channels[] = {
13757380323SRick Altherr 	ASPEED_CHAN(0, 0x10),
13857380323SRick Altherr 	ASPEED_CHAN(1, 0x12),
13957380323SRick Altherr 	ASPEED_CHAN(2, 0x14),
14057380323SRick Altherr 	ASPEED_CHAN(3, 0x16),
14157380323SRick Altherr 	ASPEED_CHAN(4, 0x18),
14257380323SRick Altherr 	ASPEED_CHAN(5, 0x1A),
14357380323SRick Altherr 	ASPEED_CHAN(6, 0x1C),
14457380323SRick Altherr 	ASPEED_CHAN(7, 0x1E),
14557380323SRick Altherr 	ASPEED_CHAN(8, 0x20),
14657380323SRick Altherr 	ASPEED_CHAN(9, 0x22),
14757380323SRick Altherr 	ASPEED_CHAN(10, 0x24),
14857380323SRick Altherr 	ASPEED_CHAN(11, 0x26),
14957380323SRick Altherr 	ASPEED_CHAN(12, 0x28),
15057380323SRick Altherr 	ASPEED_CHAN(13, 0x2A),
15157380323SRick Altherr 	ASPEED_CHAN(14, 0x2C),
15257380323SRick Altherr 	ASPEED_CHAN(15, 0x2E),
15357380323SRick Altherr };
15457380323SRick Altherr 
155df05f384SBilly Tsai #define ASPEED_BAT_CHAN(_idx, _data_reg_addr) {					\
156df05f384SBilly Tsai 		.type = IIO_VOLTAGE,						\
157df05f384SBilly Tsai 		.indexed = 1,							\
158df05f384SBilly Tsai 		.channel = (_idx),						\
159df05f384SBilly Tsai 		.address = (_data_reg_addr),					\
160df05f384SBilly Tsai 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |			\
161df05f384SBilly Tsai 				      BIT(IIO_CHAN_INFO_OFFSET),		\
162df05f384SBilly Tsai 		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |		\
163df05f384SBilly Tsai 					    BIT(IIO_CHAN_INFO_SAMP_FREQ),	\
164df05f384SBilly Tsai }
165df05f384SBilly Tsai static const struct iio_chan_spec aspeed_adc_iio_bat_channels[] = {
166df05f384SBilly Tsai 	ASPEED_CHAN(0, 0x10),
167df05f384SBilly Tsai 	ASPEED_CHAN(1, 0x12),
168df05f384SBilly Tsai 	ASPEED_CHAN(2, 0x14),
169df05f384SBilly Tsai 	ASPEED_CHAN(3, 0x16),
170df05f384SBilly Tsai 	ASPEED_CHAN(4, 0x18),
171df05f384SBilly Tsai 	ASPEED_CHAN(5, 0x1A),
172df05f384SBilly Tsai 	ASPEED_CHAN(6, 0x1C),
173df05f384SBilly Tsai 	ASPEED_BAT_CHAN(7, 0x1E),
174df05f384SBilly Tsai };
175df05f384SBilly Tsai 
aspeed_adc_set_trim_data(struct iio_dev * indio_dev)176d0a4c17bSBilly Tsai static int aspeed_adc_set_trim_data(struct iio_dev *indio_dev)
177d0a4c17bSBilly Tsai {
178d0a4c17bSBilly Tsai 	struct device_node *syscon;
179d0a4c17bSBilly Tsai 	struct regmap *scu;
180d0a4c17bSBilly Tsai 	u32 scu_otp, trimming_val;
181d0a4c17bSBilly Tsai 	struct aspeed_adc_data *data = iio_priv(indio_dev);
182d0a4c17bSBilly Tsai 
183d0a4c17bSBilly Tsai 	syscon = of_find_node_by_name(NULL, "syscon");
184d0a4c17bSBilly Tsai 	if (syscon == NULL) {
185d0a4c17bSBilly Tsai 		dev_warn(data->dev, "Couldn't find syscon node\n");
186d0a4c17bSBilly Tsai 		return -EOPNOTSUPP;
187d0a4c17bSBilly Tsai 	}
188d0a4c17bSBilly Tsai 	scu = syscon_node_to_regmap(syscon);
1898a2b6b56SMiaoqian Lin 	of_node_put(syscon);
190d0a4c17bSBilly Tsai 	if (IS_ERR(scu)) {
191d0a4c17bSBilly Tsai 		dev_warn(data->dev, "Failed to get syscon regmap\n");
192d0a4c17bSBilly Tsai 		return -EOPNOTSUPP;
193d0a4c17bSBilly Tsai 	}
194d0a4c17bSBilly Tsai 	if (data->model_data->trim_locate) {
195d0a4c17bSBilly Tsai 		if (regmap_read(scu, data->model_data->trim_locate->offset,
196d0a4c17bSBilly Tsai 				&scu_otp)) {
197d0a4c17bSBilly Tsai 			dev_warn(data->dev,
198d0a4c17bSBilly Tsai 				 "Failed to get adc trimming data\n");
199d0a4c17bSBilly Tsai 			trimming_val = 0x8;
200d0a4c17bSBilly Tsai 		} else {
201d0a4c17bSBilly Tsai 			trimming_val =
202d0a4c17bSBilly Tsai 				((scu_otp) &
203d0a4c17bSBilly Tsai 				 (data->model_data->trim_locate->field)) >>
204d0a4c17bSBilly Tsai 				__ffs(data->model_data->trim_locate->field);
205*fdd0d6b2SBilly Tsai 			if (!trimming_val)
206*fdd0d6b2SBilly Tsai 				trimming_val = 0x8;
207d0a4c17bSBilly Tsai 		}
208d0a4c17bSBilly Tsai 		dev_dbg(data->dev,
209d0a4c17bSBilly Tsai 			"trimming val = %d, offset = %08x, fields = %08x\n",
210d0a4c17bSBilly Tsai 			trimming_val, data->model_data->trim_locate->offset,
211d0a4c17bSBilly Tsai 			data->model_data->trim_locate->field);
212d0a4c17bSBilly Tsai 		writel(trimming_val, data->base + ASPEED_REG_COMPENSATION_TRIM);
213d0a4c17bSBilly Tsai 	}
214d0a4c17bSBilly Tsai 	return 0;
215d0a4c17bSBilly Tsai }
216d0a4c17bSBilly Tsai 
aspeed_adc_compensation(struct iio_dev * indio_dev)217f2836e8cSBilly Tsai static int aspeed_adc_compensation(struct iio_dev *indio_dev)
218f2836e8cSBilly Tsai {
219f2836e8cSBilly Tsai 	struct aspeed_adc_data *data = iio_priv(indio_dev);
220f2836e8cSBilly Tsai 	u32 index, adc_raw = 0;
221f2836e8cSBilly Tsai 	u32 adc_engine_control_reg_val;
222f2836e8cSBilly Tsai 
223f2836e8cSBilly Tsai 	adc_engine_control_reg_val =
224f2836e8cSBilly Tsai 		readl(data->base + ASPEED_REG_ENGINE_CONTROL);
225f2836e8cSBilly Tsai 	adc_engine_control_reg_val &= ~ASPEED_ADC_OP_MODE;
226f2836e8cSBilly Tsai 	adc_engine_control_reg_val |=
227f2836e8cSBilly Tsai 		(FIELD_PREP(ASPEED_ADC_OP_MODE, ASPEED_ADC_OP_MODE_NORMAL) |
228f2836e8cSBilly Tsai 		 ASPEED_ADC_ENGINE_ENABLE);
229f2836e8cSBilly Tsai 	/*
230f2836e8cSBilly Tsai 	 * Enable compensating sensing:
231f2836e8cSBilly Tsai 	 * After that, the input voltage of ADC will force to half of the reference
232f2836e8cSBilly Tsai 	 * voltage. So the expected reading raw data will become half of the max
233f2836e8cSBilly Tsai 	 * value. We can get compensating value = 0x200 - ADC read raw value.
234f2836e8cSBilly Tsai 	 * It is recommended to average at least 10 samples to get a final CV.
235f2836e8cSBilly Tsai 	 */
236f2836e8cSBilly Tsai 	writel(adc_engine_control_reg_val | ASPEED_ADC_CTRL_COMPENSATION |
237f2836e8cSBilly Tsai 		       ASPEED_ADC_CTRL_CHANNEL_ENABLE(0),
238f2836e8cSBilly Tsai 	       data->base + ASPEED_REG_ENGINE_CONTROL);
239f2836e8cSBilly Tsai 	/*
240f2836e8cSBilly Tsai 	 * After enable compensating sensing mode need to wait some time for ADC stable
241f2836e8cSBilly Tsai 	 * Experiment result is 1ms.
242f2836e8cSBilly Tsai 	 */
243f2836e8cSBilly Tsai 	mdelay(1);
244f2836e8cSBilly Tsai 
245f2836e8cSBilly Tsai 	for (index = 0; index < 16; index++) {
246f2836e8cSBilly Tsai 		/*
247f2836e8cSBilly Tsai 		 * Waiting for the sampling period ensures that the value acquired
248f2836e8cSBilly Tsai 		 * is fresh each time.
249f2836e8cSBilly Tsai 		 */
250f2836e8cSBilly Tsai 		ndelay(data->sample_period_ns);
251f2836e8cSBilly Tsai 		adc_raw += readw(data->base + aspeed_adc_iio_channels[0].address);
252f2836e8cSBilly Tsai 	}
253f2836e8cSBilly Tsai 	adc_raw >>= 4;
254f2836e8cSBilly Tsai 	data->cv = BIT(ASPEED_RESOLUTION_BITS - 1) - adc_raw;
255f2836e8cSBilly Tsai 	writel(adc_engine_control_reg_val,
256f2836e8cSBilly Tsai 	       data->base + ASPEED_REG_ENGINE_CONTROL);
257f2836e8cSBilly Tsai 	dev_dbg(data->dev, "Compensating value = %d\n", data->cv);
258f2836e8cSBilly Tsai 
259f2836e8cSBilly Tsai 	return 0;
260f2836e8cSBilly Tsai }
261f2836e8cSBilly Tsai 
aspeed_adc_set_sampling_rate(struct iio_dev * indio_dev,u32 rate)26213d4f9dfSBilly Tsai static int aspeed_adc_set_sampling_rate(struct iio_dev *indio_dev, u32 rate)
26313d4f9dfSBilly Tsai {
26413d4f9dfSBilly Tsai 	struct aspeed_adc_data *data = iio_priv(indio_dev);
26513d4f9dfSBilly Tsai 
26613d4f9dfSBilly Tsai 	if (rate < data->model_data->min_sampling_rate ||
26713d4f9dfSBilly Tsai 	    rate > data->model_data->max_sampling_rate)
26813d4f9dfSBilly Tsai 		return -EINVAL;
26913d4f9dfSBilly Tsai 	/* Each sampling needs 12 clocks to convert.*/
27013d4f9dfSBilly Tsai 	clk_set_rate(data->clk_scaler->clk, rate * ASPEED_CLOCKS_PER_SAMPLE);
27113d4f9dfSBilly Tsai 	rate = clk_get_rate(data->clk_scaler->clk);
27213d4f9dfSBilly Tsai 	data->sample_period_ns = DIV_ROUND_UP_ULL(
27313d4f9dfSBilly Tsai 		(u64)NSEC_PER_SEC * ASPEED_CLOCKS_PER_SAMPLE, rate);
27413d4f9dfSBilly Tsai 	dev_dbg(data->dev, "Adc clock = %d sample period = %d ns", rate,
27513d4f9dfSBilly Tsai 		data->sample_period_ns);
27613d4f9dfSBilly Tsai 
27713d4f9dfSBilly Tsai 	return 0;
27813d4f9dfSBilly Tsai }
27913d4f9dfSBilly Tsai 
aspeed_adc_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)28057380323SRick Altherr static int aspeed_adc_read_raw(struct iio_dev *indio_dev,
28157380323SRick Altherr 			       struct iio_chan_spec const *chan,
28257380323SRick Altherr 			       int *val, int *val2, long mask)
28357380323SRick Altherr {
28457380323SRick Altherr 	struct aspeed_adc_data *data = iio_priv(indio_dev);
285df05f384SBilly Tsai 	u32 adc_engine_control_reg_val;
28657380323SRick Altherr 
28757380323SRick Altherr 	switch (mask) {
28857380323SRick Altherr 	case IIO_CHAN_INFO_RAW:
289df05f384SBilly Tsai 		if (data->battery_sensing && chan->channel == 7) {
290df05f384SBilly Tsai 			adc_engine_control_reg_val =
291df05f384SBilly Tsai 				readl(data->base + ASPEED_REG_ENGINE_CONTROL);
292df05f384SBilly Tsai 			writel(adc_engine_control_reg_val |
293df05f384SBilly Tsai 				       FIELD_PREP(ASPEED_ADC_CH7_MODE,
294df05f384SBilly Tsai 						  ASPEED_ADC_CH7_BAT) |
295df05f384SBilly Tsai 				       ASPEED_ADC_BAT_SENSING_ENABLE,
296df05f384SBilly Tsai 			       data->base + ASPEED_REG_ENGINE_CONTROL);
297df05f384SBilly Tsai 			/*
298df05f384SBilly Tsai 			 * After enable battery sensing mode need to wait some time for adc stable
299df05f384SBilly Tsai 			 * Experiment result is 1ms.
300df05f384SBilly Tsai 			 */
301df05f384SBilly Tsai 			mdelay(1);
302df05f384SBilly Tsai 			*val = readw(data->base + chan->address);
303df05f384SBilly Tsai 			*val = (*val * data->battery_mode_gain.mult) /
304df05f384SBilly Tsai 			       data->battery_mode_gain.div;
305df05f384SBilly Tsai 			/* Restore control register value */
306df05f384SBilly Tsai 			writel(adc_engine_control_reg_val,
307df05f384SBilly Tsai 			       data->base + ASPEED_REG_ENGINE_CONTROL);
308df05f384SBilly Tsai 		} else
30957380323SRick Altherr 			*val = readw(data->base + chan->address);
31057380323SRick Altherr 		return IIO_VAL_INT;
31157380323SRick Altherr 
312f2836e8cSBilly Tsai 	case IIO_CHAN_INFO_OFFSET:
313df05f384SBilly Tsai 		if (data->battery_sensing && chan->channel == 7)
314df05f384SBilly Tsai 			*val = (data->cv * data->battery_mode_gain.mult) /
315df05f384SBilly Tsai 			       data->battery_mode_gain.div;
316df05f384SBilly Tsai 		else
317f2836e8cSBilly Tsai 			*val = data->cv;
318f2836e8cSBilly Tsai 		return IIO_VAL_INT;
319f2836e8cSBilly Tsai 
32057380323SRick Altherr 	case IIO_CHAN_INFO_SCALE:
3211de952a4SBilly Tsai 		*val = data->vref_mv;
32257380323SRick Altherr 		*val2 = ASPEED_RESOLUTION_BITS;
32357380323SRick Altherr 		return IIO_VAL_FRACTIONAL_LOG2;
32457380323SRick Altherr 
32557380323SRick Altherr 	case IIO_CHAN_INFO_SAMP_FREQ:
32657380323SRick Altherr 		*val = clk_get_rate(data->clk_scaler->clk) /
32757380323SRick Altherr 				ASPEED_CLOCKS_PER_SAMPLE;
32857380323SRick Altherr 		return IIO_VAL_INT;
32957380323SRick Altherr 
33057380323SRick Altherr 	default:
33157380323SRick Altherr 		return -EINVAL;
33257380323SRick Altherr 	}
33357380323SRick Altherr }
33457380323SRick Altherr 
aspeed_adc_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)33557380323SRick Altherr static int aspeed_adc_write_raw(struct iio_dev *indio_dev,
33657380323SRick Altherr 				struct iio_chan_spec const *chan,
33757380323SRick Altherr 				int val, int val2, long mask)
33857380323SRick Altherr {
33957380323SRick Altherr 	switch (mask) {
34057380323SRick Altherr 	case IIO_CHAN_INFO_SAMP_FREQ:
34113d4f9dfSBilly Tsai 		return aspeed_adc_set_sampling_rate(indio_dev, val);
34257380323SRick Altherr 
34357380323SRick Altherr 	case IIO_CHAN_INFO_SCALE:
34457380323SRick Altherr 	case IIO_CHAN_INFO_RAW:
34557380323SRick Altherr 		/*
34657380323SRick Altherr 		 * Technically, these could be written but the only reasons
34757380323SRick Altherr 		 * for doing so seem better handled in userspace.  EPERM is
34857380323SRick Altherr 		 * returned to signal this is a policy choice rather than a
34957380323SRick Altherr 		 * hardware limitation.
35057380323SRick Altherr 		 */
35157380323SRick Altherr 		return -EPERM;
35257380323SRick Altherr 
35357380323SRick Altherr 	default:
35457380323SRick Altherr 		return -EINVAL;
35557380323SRick Altherr 	}
35657380323SRick Altherr }
35757380323SRick Altherr 
aspeed_adc_reg_access(struct iio_dev * indio_dev,unsigned int reg,unsigned int writeval,unsigned int * readval)35857380323SRick Altherr static int aspeed_adc_reg_access(struct iio_dev *indio_dev,
35957380323SRick Altherr 				 unsigned int reg, unsigned int writeval,
36057380323SRick Altherr 				 unsigned int *readval)
36157380323SRick Altherr {
36257380323SRick Altherr 	struct aspeed_adc_data *data = iio_priv(indio_dev);
36357380323SRick Altherr 
36457380323SRick Altherr 	if (!readval || reg % 4 || reg > ASPEED_REG_MAX)
36557380323SRick Altherr 		return -EINVAL;
36657380323SRick Altherr 
36757380323SRick Altherr 	*readval = readl(data->base + reg);
36857380323SRick Altherr 
36957380323SRick Altherr 	return 0;
37057380323SRick Altherr }
37157380323SRick Altherr 
37257380323SRick Altherr static const struct iio_info aspeed_adc_iio_info = {
37357380323SRick Altherr 	.read_raw = aspeed_adc_read_raw,
37457380323SRick Altherr 	.write_raw = aspeed_adc_write_raw,
37557380323SRick Altherr 	.debugfs_reg_access = aspeed_adc_reg_access,
37657380323SRick Altherr };
37757380323SRick Altherr 
aspeed_adc_unregister_fixed_divider(void * data)37890f96477SBilly Tsai static void aspeed_adc_unregister_fixed_divider(void *data)
37990f96477SBilly Tsai {
38090f96477SBilly Tsai 	struct clk_hw *clk = data;
38190f96477SBilly Tsai 
38290f96477SBilly Tsai 	clk_hw_unregister_fixed_factor(clk);
38390f96477SBilly Tsai }
38490f96477SBilly Tsai 
aspeed_adc_reset_assert(void * data)3854c56572cSBilly Tsai static void aspeed_adc_reset_assert(void *data)
3864c56572cSBilly Tsai {
3874c56572cSBilly Tsai 	struct reset_control *rst = data;
3884c56572cSBilly Tsai 
3894c56572cSBilly Tsai 	reset_control_assert(rst);
3904c56572cSBilly Tsai }
3914c56572cSBilly Tsai 
aspeed_adc_clk_disable_unprepare(void * data)3924c56572cSBilly Tsai static void aspeed_adc_clk_disable_unprepare(void *data)
3934c56572cSBilly Tsai {
3944c56572cSBilly Tsai 	struct clk *clk = data;
3954c56572cSBilly Tsai 
3964c56572cSBilly Tsai 	clk_disable_unprepare(clk);
3974c56572cSBilly Tsai }
3984c56572cSBilly Tsai 
aspeed_adc_power_down(void * data)3994c56572cSBilly Tsai static void aspeed_adc_power_down(void *data)
4004c56572cSBilly Tsai {
4014c56572cSBilly Tsai 	struct aspeed_adc_data *priv_data = data;
4024c56572cSBilly Tsai 
4034c56572cSBilly Tsai 	writel(FIELD_PREP(ASPEED_ADC_OP_MODE, ASPEED_ADC_OP_MODE_PWR_DOWN),
4044c56572cSBilly Tsai 	       priv_data->base + ASPEED_REG_ENGINE_CONTROL);
4054c56572cSBilly Tsai }
4064c56572cSBilly Tsai 
aspeed_adc_reg_disable(void * data)4071b5ceb55SBilly Tsai static void aspeed_adc_reg_disable(void *data)
4081b5ceb55SBilly Tsai {
4091b5ceb55SBilly Tsai 	struct regulator *reg = data;
4101b5ceb55SBilly Tsai 
4111b5ceb55SBilly Tsai 	regulator_disable(reg);
4121b5ceb55SBilly Tsai }
4131b5ceb55SBilly Tsai 
aspeed_adc_vref_config(struct iio_dev * indio_dev)4141de952a4SBilly Tsai static int aspeed_adc_vref_config(struct iio_dev *indio_dev)
4151de952a4SBilly Tsai {
4161de952a4SBilly Tsai 	struct aspeed_adc_data *data = iio_priv(indio_dev);
4171b5ceb55SBilly Tsai 	int ret;
4181b5ceb55SBilly Tsai 	u32 adc_engine_control_reg_val;
4191de952a4SBilly Tsai 
4201de952a4SBilly Tsai 	if (data->model_data->vref_fixed_mv) {
4211de952a4SBilly Tsai 		data->vref_mv = data->model_data->vref_fixed_mv;
4221de952a4SBilly Tsai 		return 0;
4231de952a4SBilly Tsai 	}
4241b5ceb55SBilly Tsai 	adc_engine_control_reg_val =
4251b5ceb55SBilly Tsai 		readl(data->base + ASPEED_REG_ENGINE_CONTROL);
4261b5ceb55SBilly Tsai 	data->regulator = devm_regulator_get_optional(data->dev, "vref");
4271b5ceb55SBilly Tsai 	if (!IS_ERR(data->regulator)) {
4281b5ceb55SBilly Tsai 		ret = regulator_enable(data->regulator);
4291b5ceb55SBilly Tsai 		if (ret)
4301b5ceb55SBilly Tsai 			return ret;
4311b5ceb55SBilly Tsai 		ret = devm_add_action_or_reset(
4321b5ceb55SBilly Tsai 			data->dev, aspeed_adc_reg_disable, data->regulator);
4331b5ceb55SBilly Tsai 		if (ret)
4341b5ceb55SBilly Tsai 			return ret;
4351b5ceb55SBilly Tsai 		data->vref_mv = regulator_get_voltage(data->regulator);
4361b5ceb55SBilly Tsai 		/* Conversion from uV to mV */
4371b5ceb55SBilly Tsai 		data->vref_mv /= 1000;
4381b5ceb55SBilly Tsai 		if ((data->vref_mv >= 1550) && (data->vref_mv <= 2700))
4391b5ceb55SBilly Tsai 			writel(adc_engine_control_reg_val |
4401b5ceb55SBilly Tsai 				FIELD_PREP(
4411b5ceb55SBilly Tsai 					ASPEED_ADC_REF_VOLTAGE,
4421b5ceb55SBilly Tsai 					ASPEED_ADC_REF_VOLTAGE_EXT_HIGH),
4431b5ceb55SBilly Tsai 			data->base + ASPEED_REG_ENGINE_CONTROL);
4441b5ceb55SBilly Tsai 		else if ((data->vref_mv >= 900) && (data->vref_mv <= 1650))
4451b5ceb55SBilly Tsai 			writel(adc_engine_control_reg_val |
4461b5ceb55SBilly Tsai 				FIELD_PREP(
4471b5ceb55SBilly Tsai 					ASPEED_ADC_REF_VOLTAGE,
4481b5ceb55SBilly Tsai 					ASPEED_ADC_REF_VOLTAGE_EXT_LOW),
4491b5ceb55SBilly Tsai 			data->base + ASPEED_REG_ENGINE_CONTROL);
4501b5ceb55SBilly Tsai 		else {
4511b5ceb55SBilly Tsai 			dev_err(data->dev, "Regulator voltage %d not support",
4521b5ceb55SBilly Tsai 				data->vref_mv);
4531b5ceb55SBilly Tsai 			return -EOPNOTSUPP;
4541b5ceb55SBilly Tsai 		}
4551b5ceb55SBilly Tsai 	} else {
4561b5ceb55SBilly Tsai 		if (PTR_ERR(data->regulator) != -ENODEV)
4571b5ceb55SBilly Tsai 			return PTR_ERR(data->regulator);
4581b5ceb55SBilly Tsai 		data->vref_mv = 2500000;
4591b5ceb55SBilly Tsai 		of_property_read_u32(data->dev->of_node,
4601b5ceb55SBilly Tsai 				     "aspeed,int-vref-microvolt",
4611b5ceb55SBilly Tsai 				     &data->vref_mv);
4621b5ceb55SBilly Tsai 		/* Conversion from uV to mV */
4631b5ceb55SBilly Tsai 		data->vref_mv /= 1000;
4641b5ceb55SBilly Tsai 		if (data->vref_mv == 2500)
4651b5ceb55SBilly Tsai 			writel(adc_engine_control_reg_val |
4661b5ceb55SBilly Tsai 				FIELD_PREP(ASPEED_ADC_REF_VOLTAGE,
4671b5ceb55SBilly Tsai 						ASPEED_ADC_REF_VOLTAGE_2500mV),
4681b5ceb55SBilly Tsai 			data->base + ASPEED_REG_ENGINE_CONTROL);
4691b5ceb55SBilly Tsai 		else if (data->vref_mv == 1200)
4701b5ceb55SBilly Tsai 			writel(adc_engine_control_reg_val |
4711b5ceb55SBilly Tsai 				FIELD_PREP(ASPEED_ADC_REF_VOLTAGE,
4721b5ceb55SBilly Tsai 						ASPEED_ADC_REF_VOLTAGE_1200mV),
4731b5ceb55SBilly Tsai 			data->base + ASPEED_REG_ENGINE_CONTROL);
4741b5ceb55SBilly Tsai 		else {
4751b5ceb55SBilly Tsai 			dev_err(data->dev, "Voltage %d not support", data->vref_mv);
4761b5ceb55SBilly Tsai 			return -EOPNOTSUPP;
4771b5ceb55SBilly Tsai 		}
4781b5ceb55SBilly Tsai 	}
4791b5ceb55SBilly Tsai 
4801de952a4SBilly Tsai 	return 0;
4811de952a4SBilly Tsai }
4821de952a4SBilly Tsai 
aspeed_adc_probe(struct platform_device * pdev)48357380323SRick Altherr static int aspeed_adc_probe(struct platform_device *pdev)
48457380323SRick Altherr {
48557380323SRick Altherr 	struct iio_dev *indio_dev;
48657380323SRick Altherr 	struct aspeed_adc_data *data;
48757380323SRick Altherr 	int ret;
48857380323SRick Altherr 	u32 adc_engine_control_reg_val;
4899223bd04SBilly Tsai 	unsigned long scaler_flags = 0;
4909223bd04SBilly Tsai 	char clk_name[32], clk_parent_name[32];
49157380323SRick Altherr 
49257380323SRick Altherr 	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*data));
49357380323SRick Altherr 	if (!indio_dev)
49457380323SRick Altherr 		return -ENOMEM;
49557380323SRick Altherr 
49657380323SRick Altherr 	data = iio_priv(indio_dev);
49757380323SRick Altherr 	data->dev = &pdev->dev;
49889c65417SBilly Tsai 	data->model_data = of_device_get_match_data(&pdev->dev);
499eb795cd9SBilly Tsai 	platform_set_drvdata(pdev, indio_dev);
50057380323SRick Altherr 
501d19aeb29SJonathan Cameron 	data->base = devm_platform_ioremap_resource(pdev, 0);
50257380323SRick Altherr 	if (IS_ERR(data->base))
50357380323SRick Altherr 		return PTR_ERR(data->base);
50457380323SRick Altherr 
50557380323SRick Altherr 	/* Register ADC clock prescaler with source specified by device tree. */
50657380323SRick Altherr 	spin_lock_init(&data->clk_lock);
5079223bd04SBilly Tsai 	snprintf(clk_parent_name, ARRAY_SIZE(clk_parent_name), "%s",
5089223bd04SBilly Tsai 		 of_clk_get_parent_name(pdev->dev.of_node, 0));
50990f96477SBilly Tsai 	snprintf(clk_name, ARRAY_SIZE(clk_name), "%s-fixed-div",
51090f96477SBilly Tsai 		 data->model_data->model_name);
51190f96477SBilly Tsai 	data->fixed_div_clk = clk_hw_register_fixed_factor(
51290f96477SBilly Tsai 		&pdev->dev, clk_name, clk_parent_name, 0, 1, 2);
51390f96477SBilly Tsai 	if (IS_ERR(data->fixed_div_clk))
51490f96477SBilly Tsai 		return PTR_ERR(data->fixed_div_clk);
51557380323SRick Altherr 
51690f96477SBilly Tsai 	ret = devm_add_action_or_reset(data->dev,
51790f96477SBilly Tsai 				       aspeed_adc_unregister_fixed_divider,
51890f96477SBilly Tsai 				       data->fixed_div_clk);
51990f96477SBilly Tsai 	if (ret)
52090f96477SBilly Tsai 		return ret;
52190f96477SBilly Tsai 	snprintf(clk_parent_name, ARRAY_SIZE(clk_parent_name), clk_name);
52257380323SRick Altherr 
5239223bd04SBilly Tsai 	if (data->model_data->need_prescaler) {
5249223bd04SBilly Tsai 		snprintf(clk_name, ARRAY_SIZE(clk_name), "%s-prescaler",
5259223bd04SBilly Tsai 			 data->model_data->model_name);
5264c56572cSBilly Tsai 		data->clk_prescaler = devm_clk_hw_register_divider(
5279223bd04SBilly Tsai 			&pdev->dev, clk_name, clk_parent_name, 0,
5289223bd04SBilly Tsai 			data->base + ASPEED_REG_CLOCK_CONTROL, 17, 15, 0,
5299223bd04SBilly Tsai 			&data->clk_lock);
53057380323SRick Altherr 		if (IS_ERR(data->clk_prescaler))
53157380323SRick Altherr 			return PTR_ERR(data->clk_prescaler);
5329223bd04SBilly Tsai 		snprintf(clk_parent_name, ARRAY_SIZE(clk_parent_name),
5339223bd04SBilly Tsai 			 clk_name);
5349223bd04SBilly Tsai 		scaler_flags = CLK_SET_RATE_PARENT;
5359223bd04SBilly Tsai 	}
53657380323SRick Altherr 	/*
53757380323SRick Altherr 	 * Register ADC clock scaler downstream from the prescaler. Allow rate
53857380323SRick Altherr 	 * setting to adjust the prescaler as well.
53957380323SRick Altherr 	 */
5409223bd04SBilly Tsai 	snprintf(clk_name, ARRAY_SIZE(clk_name), "%s-scaler",
5419223bd04SBilly Tsai 		 data->model_data->model_name);
5424c56572cSBilly Tsai 	data->clk_scaler = devm_clk_hw_register_divider(
5439223bd04SBilly Tsai 		&pdev->dev, clk_name, clk_parent_name, scaler_flags,
5449223bd04SBilly Tsai 		data->base + ASPEED_REG_CLOCK_CONTROL, 0,
54557142663SBilly Tsai 		data->model_data->scaler_bit_width,
54657142663SBilly Tsai 		data->model_data->need_prescaler ? CLK_DIVIDER_ONE_BASED : 0,
54757142663SBilly Tsai 		&data->clk_lock);
5484c56572cSBilly Tsai 	if (IS_ERR(data->clk_scaler))
5494c56572cSBilly Tsai 		return PTR_ERR(data->clk_scaler);
55057380323SRick Altherr 
5511b5ceb55SBilly Tsai 	data->rst = devm_reset_control_get_shared(&pdev->dev, NULL);
552edf7550aSJoel Stanley 	if (IS_ERR(data->rst)) {
553edf7550aSJoel Stanley 		dev_err(&pdev->dev,
554edf7550aSJoel Stanley 			"invalid or missing reset controller device tree entry");
5554c56572cSBilly Tsai 		return PTR_ERR(data->rst);
556edf7550aSJoel Stanley 	}
557edf7550aSJoel Stanley 	reset_control_deassert(data->rst);
558edf7550aSJoel Stanley 
5594c56572cSBilly Tsai 	ret = devm_add_action_or_reset(data->dev, aspeed_adc_reset_assert,
5604c56572cSBilly Tsai 				       data->rst);
5614c56572cSBilly Tsai 	if (ret)
5624c56572cSBilly Tsai 		return ret;
563737cc2a5SMykola Kostenok 
5641de952a4SBilly Tsai 	ret = aspeed_adc_vref_config(indio_dev);
5651de952a4SBilly Tsai 	if (ret)
5664c56572cSBilly Tsai 		return ret;
5671de952a4SBilly Tsai 
568d0a4c17bSBilly Tsai 	ret = aspeed_adc_set_trim_data(indio_dev);
569d0a4c17bSBilly Tsai 	if (ret)
570d0a4c17bSBilly Tsai 		return ret;
571d0a4c17bSBilly Tsai 
572df05f384SBilly Tsai 	if (of_find_property(data->dev->of_node, "aspeed,battery-sensing",
573df05f384SBilly Tsai 			     NULL)) {
574df05f384SBilly Tsai 		if (data->model_data->bat_sense_sup) {
575df05f384SBilly Tsai 			data->battery_sensing = 1;
576df05f384SBilly Tsai 			if (readl(data->base + ASPEED_REG_ENGINE_CONTROL) &
577df05f384SBilly Tsai 			    ASPEED_ADC_BAT_SENSING_DIV) {
578df05f384SBilly Tsai 				data->battery_mode_gain.mult = 3;
579df05f384SBilly Tsai 				data->battery_mode_gain.div = 1;
580df05f384SBilly Tsai 			} else {
581df05f384SBilly Tsai 				data->battery_mode_gain.mult = 3;
582df05f384SBilly Tsai 				data->battery_mode_gain.div = 2;
583df05f384SBilly Tsai 			}
584df05f384SBilly Tsai 		} else
585df05f384SBilly Tsai 			dev_warn(&pdev->dev,
5860fc3c826SColin Ian King 				 "Failed to enable battery-sensing mode\n");
587df05f384SBilly Tsai 	}
588df05f384SBilly Tsai 
58913d4f9dfSBilly Tsai 	ret = clk_prepare_enable(data->clk_scaler->clk);
59013d4f9dfSBilly Tsai 	if (ret)
59113d4f9dfSBilly Tsai 		return ret;
59213d4f9dfSBilly Tsai 	ret = devm_add_action_or_reset(data->dev,
59313d4f9dfSBilly Tsai 				       aspeed_adc_clk_disable_unprepare,
59413d4f9dfSBilly Tsai 				       data->clk_scaler->clk);
59513d4f9dfSBilly Tsai 	if (ret)
59613d4f9dfSBilly Tsai 		return ret;
59713d4f9dfSBilly Tsai 	ret = aspeed_adc_set_sampling_rate(indio_dev,
59813d4f9dfSBilly Tsai 					   ASPEED_ADC_DEF_SAMPLING_RATE);
59913d4f9dfSBilly Tsai 	if (ret)
60013d4f9dfSBilly Tsai 		return ret;
60113d4f9dfSBilly Tsai 
6021b5ceb55SBilly Tsai 	adc_engine_control_reg_val =
6031b5ceb55SBilly Tsai 		readl(data->base + ASPEED_REG_ENGINE_CONTROL);
6041b5ceb55SBilly Tsai 	adc_engine_control_reg_val |=
6051b5ceb55SBilly Tsai 		FIELD_PREP(ASPEED_ADC_OP_MODE, ASPEED_ADC_OP_MODE_NORMAL) |
6061b5ceb55SBilly Tsai 		ASPEED_ADC_ENGINE_ENABLE;
607737cc2a5SMykola Kostenok 	/* Enable engine in normal mode. */
6081b5ceb55SBilly Tsai 	writel(adc_engine_control_reg_val,
609737cc2a5SMykola Kostenok 	       data->base + ASPEED_REG_ENGINE_CONTROL);
610737cc2a5SMykola Kostenok 
6114c56572cSBilly Tsai 	ret = devm_add_action_or_reset(data->dev, aspeed_adc_power_down,
6124c56572cSBilly Tsai 					data);
6134c56572cSBilly Tsai 	if (ret)
6144c56572cSBilly Tsai 		return ret;
6154c56572cSBilly Tsai 
6164c56572cSBilly Tsai 	if (data->model_data->wait_init_sequence) {
617737cc2a5SMykola Kostenok 		/* Wait for initial sequence complete. */
618737cc2a5SMykola Kostenok 		ret = readl_poll_timeout(data->base + ASPEED_REG_ENGINE_CONTROL,
619737cc2a5SMykola Kostenok 					 adc_engine_control_reg_val,
620737cc2a5SMykola Kostenok 					 adc_engine_control_reg_val &
621737cc2a5SMykola Kostenok 					 ASPEED_ADC_CTRL_INIT_RDY,
622737cc2a5SMykola Kostenok 					 ASPEED_ADC_INIT_POLLING_TIME,
623737cc2a5SMykola Kostenok 					 ASPEED_ADC_INIT_TIMEOUT);
624737cc2a5SMykola Kostenok 		if (ret)
62557380323SRick Altherr 			return ret;
62657380323SRick Altherr 	}
62757380323SRick Altherr 
628f2836e8cSBilly Tsai 	aspeed_adc_compensation(indio_dev);
6294c56572cSBilly Tsai 	/* Start all channels in normal mode. */
63026a9f730SBilly Tsai 	adc_engine_control_reg_val =
6314c56572cSBilly Tsai 		readl(data->base + ASPEED_REG_ENGINE_CONTROL);
6324c56572cSBilly Tsai 	adc_engine_control_reg_val |= ASPEED_ADC_CTRL_CHANNEL;
63357380323SRick Altherr 	writel(adc_engine_control_reg_val,
63457380323SRick Altherr 	       data->base + ASPEED_REG_ENGINE_CONTROL);
63557380323SRick Altherr 
63689c65417SBilly Tsai 	indio_dev->name = data->model_data->model_name;
63757380323SRick Altherr 	indio_dev->info = &aspeed_adc_iio_info;
63857380323SRick Altherr 	indio_dev->modes = INDIO_DIRECT_MODE;
639df05f384SBilly Tsai 	indio_dev->channels = data->battery_sensing ?
640df05f384SBilly Tsai 					    aspeed_adc_iio_bat_channels :
641df05f384SBilly Tsai 					    aspeed_adc_iio_channels;
642eaa74a8dSBilly Tsai 	indio_dev->num_channels = data->model_data->num_channels;
64357380323SRick Altherr 
6444c56572cSBilly Tsai 	ret = devm_iio_device_register(data->dev, indio_dev);
64557380323SRick Altherr 	return ret;
64657380323SRick Altherr }
64757380323SRick Altherr 
648d0a4c17bSBilly Tsai static const struct aspeed_adc_trim_locate ast2500_adc_trim = {
649d0a4c17bSBilly Tsai 	.offset = 0x154,
650d0a4c17bSBilly Tsai 	.field = GENMASK(31, 28),
651d0a4c17bSBilly Tsai };
652d0a4c17bSBilly Tsai 
653d0a4c17bSBilly Tsai static const struct aspeed_adc_trim_locate ast2600_adc0_trim = {
654d0a4c17bSBilly Tsai 	.offset = 0x5d0,
655d0a4c17bSBilly Tsai 	.field = GENMASK(3, 0),
656d0a4c17bSBilly Tsai };
657d0a4c17bSBilly Tsai 
658d0a4c17bSBilly Tsai static const struct aspeed_adc_trim_locate ast2600_adc1_trim = {
659d0a4c17bSBilly Tsai 	.offset = 0x5d0,
660d0a4c17bSBilly Tsai 	.field = GENMASK(7, 4),
661d0a4c17bSBilly Tsai };
662d0a4c17bSBilly Tsai 
66357380323SRick Altherr static const struct aspeed_adc_model_data ast2400_model_data = {
66457380323SRick Altherr 	.model_name = "ast2400-adc",
665eaa74a8dSBilly Tsai 	.vref_fixed_mv = 2500,
66657380323SRick Altherr 	.min_sampling_rate = 10000,
66757380323SRick Altherr 	.max_sampling_rate = 500000,
668eaa74a8dSBilly Tsai 	.need_prescaler = true,
669eaa74a8dSBilly Tsai 	.scaler_bit_width = 10,
670eaa74a8dSBilly Tsai 	.num_channels = 16,
67157380323SRick Altherr };
67257380323SRick Altherr 
67357380323SRick Altherr static const struct aspeed_adc_model_data ast2500_model_data = {
67457380323SRick Altherr 	.model_name = "ast2500-adc",
675eaa74a8dSBilly Tsai 	.vref_fixed_mv = 1800,
67657380323SRick Altherr 	.min_sampling_rate = 1,
67757380323SRick Altherr 	.max_sampling_rate = 1000000,
678737cc2a5SMykola Kostenok 	.wait_init_sequence = true,
679eaa74a8dSBilly Tsai 	.need_prescaler = true,
680eaa74a8dSBilly Tsai 	.scaler_bit_width = 10,
681eaa74a8dSBilly Tsai 	.num_channels = 16,
682d0a4c17bSBilly Tsai 	.trim_locate = &ast2500_adc_trim,
68357380323SRick Altherr };
68457380323SRick Altherr 
6851b5ceb55SBilly Tsai static const struct aspeed_adc_model_data ast2600_adc0_model_data = {
6861b5ceb55SBilly Tsai 	.model_name = "ast2600-adc0",
6871b5ceb55SBilly Tsai 	.min_sampling_rate = 10000,
6881b5ceb55SBilly Tsai 	.max_sampling_rate = 500000,
6891b5ceb55SBilly Tsai 	.wait_init_sequence = true,
690df05f384SBilly Tsai 	.bat_sense_sup = true,
6911b5ceb55SBilly Tsai 	.scaler_bit_width = 16,
6921b5ceb55SBilly Tsai 	.num_channels = 8,
693d0a4c17bSBilly Tsai 	.trim_locate = &ast2600_adc0_trim,
6941b5ceb55SBilly Tsai };
6951b5ceb55SBilly Tsai 
6961b5ceb55SBilly Tsai static const struct aspeed_adc_model_data ast2600_adc1_model_data = {
6971b5ceb55SBilly Tsai 	.model_name = "ast2600-adc1",
6981b5ceb55SBilly Tsai 	.min_sampling_rate = 10000,
6991b5ceb55SBilly Tsai 	.max_sampling_rate = 500000,
7001b5ceb55SBilly Tsai 	.wait_init_sequence = true,
701df05f384SBilly Tsai 	.bat_sense_sup = true,
7021b5ceb55SBilly Tsai 	.scaler_bit_width = 16,
7031b5ceb55SBilly Tsai 	.num_channels = 8,
704d0a4c17bSBilly Tsai 	.trim_locate = &ast2600_adc1_trim,
70557380323SRick Altherr };
70657380323SRick Altherr 
70757380323SRick Altherr static const struct of_device_id aspeed_adc_matches[] = {
70857380323SRick Altherr 	{ .compatible = "aspeed,ast2400-adc", .data = &ast2400_model_data },
70957380323SRick Altherr 	{ .compatible = "aspeed,ast2500-adc", .data = &ast2500_model_data },
7101b5ceb55SBilly Tsai 	{ .compatible = "aspeed,ast2600-adc0", .data = &ast2600_adc0_model_data },
7111b5ceb55SBilly Tsai 	{ .compatible = "aspeed,ast2600-adc1", .data = &ast2600_adc1_model_data },
71257380323SRick Altherr 	{},
71357380323SRick Altherr };
71457380323SRick Altherr MODULE_DEVICE_TABLE(of, aspeed_adc_matches);
71557380323SRick Altherr 
71657380323SRick Altherr static struct platform_driver aspeed_adc_driver = {
71757380323SRick Altherr 	.probe = aspeed_adc_probe,
71857380323SRick Altherr 	.driver = {
71957380323SRick Altherr 		.name = KBUILD_MODNAME,
72057380323SRick Altherr 		.of_match_table = aspeed_adc_matches,
72157380323SRick Altherr 	}
72257380323SRick Altherr };
72357380323SRick Altherr 
72457380323SRick Altherr module_platform_driver(aspeed_adc_driver);
72557380323SRick Altherr 
72657380323SRick Altherr MODULE_AUTHOR("Rick Altherr <raltherr@google.com>");
7271b5ceb55SBilly Tsai MODULE_DESCRIPTION("Aspeed AST2400/2500/2600 ADC Driver");
72857380323SRick Altherr MODULE_LICENSE("GPL");
729