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