162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Aspeed AST2400/2500/2600 ADC 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2017 Google, Inc. 662306a36Sopenharmony_ci * Copyright (C) 2021 Aspeed Technology Inc. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * ADC clock formula: 962306a36Sopenharmony_ci * Ast2400/Ast2500: 1062306a36Sopenharmony_ci * clock period = period of PCLK * 2 * (ADC0C[31:17] + 1) * (ADC0C[9:0] + 1) 1162306a36Sopenharmony_ci * Ast2600: 1262306a36Sopenharmony_ci * clock period = period of PCLK * 2 * (ADC0C[15:0] + 1) 1362306a36Sopenharmony_ci */ 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <linux/clk.h> 1662306a36Sopenharmony_ci#include <linux/clk-provider.h> 1762306a36Sopenharmony_ci#include <linux/err.h> 1862306a36Sopenharmony_ci#include <linux/errno.h> 1962306a36Sopenharmony_ci#include <linux/io.h> 2062306a36Sopenharmony_ci#include <linux/module.h> 2162306a36Sopenharmony_ci#include <linux/of_platform.h> 2262306a36Sopenharmony_ci#include <linux/platform_device.h> 2362306a36Sopenharmony_ci#include <linux/regulator/consumer.h> 2462306a36Sopenharmony_ci#include <linux/reset.h> 2562306a36Sopenharmony_ci#include <linux/spinlock.h> 2662306a36Sopenharmony_ci#include <linux/types.h> 2762306a36Sopenharmony_ci#include <linux/bitfield.h> 2862306a36Sopenharmony_ci#include <linux/regmap.h> 2962306a36Sopenharmony_ci#include <linux/mfd/syscon.h> 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#include <linux/iio/iio.h> 3262306a36Sopenharmony_ci#include <linux/iio/driver.h> 3362306a36Sopenharmony_ci#include <linux/iopoll.h> 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#define ASPEED_RESOLUTION_BITS 10 3662306a36Sopenharmony_ci#define ASPEED_CLOCKS_PER_SAMPLE 12 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#define ASPEED_REG_ENGINE_CONTROL 0x00 3962306a36Sopenharmony_ci#define ASPEED_REG_INTERRUPT_CONTROL 0x04 4062306a36Sopenharmony_ci#define ASPEED_REG_VGA_DETECT_CONTROL 0x08 4162306a36Sopenharmony_ci#define ASPEED_REG_CLOCK_CONTROL 0x0C 4262306a36Sopenharmony_ci#define ASPEED_REG_COMPENSATION_TRIM 0xC4 4362306a36Sopenharmony_ci/* 4462306a36Sopenharmony_ci * The register offset between 0xC8~0xCC can be read and won't affect the 4562306a36Sopenharmony_ci * hardware logic in each version of ADC. 4662306a36Sopenharmony_ci */ 4762306a36Sopenharmony_ci#define ASPEED_REG_MAX 0xD0 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#define ASPEED_ADC_ENGINE_ENABLE BIT(0) 5062306a36Sopenharmony_ci#define ASPEED_ADC_OP_MODE GENMASK(3, 1) 5162306a36Sopenharmony_ci#define ASPEED_ADC_OP_MODE_PWR_DOWN 0 5262306a36Sopenharmony_ci#define ASPEED_ADC_OP_MODE_STANDBY 1 5362306a36Sopenharmony_ci#define ASPEED_ADC_OP_MODE_NORMAL 7 5462306a36Sopenharmony_ci#define ASPEED_ADC_CTRL_COMPENSATION BIT(4) 5562306a36Sopenharmony_ci#define ASPEED_ADC_AUTO_COMPENSATION BIT(5) 5662306a36Sopenharmony_ci/* 5762306a36Sopenharmony_ci * Bit 6 determines not only the reference voltage range but also the dividing 5862306a36Sopenharmony_ci * circuit for battery sensing. 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_ci#define ASPEED_ADC_REF_VOLTAGE GENMASK(7, 6) 6162306a36Sopenharmony_ci#define ASPEED_ADC_REF_VOLTAGE_2500mV 0 6262306a36Sopenharmony_ci#define ASPEED_ADC_REF_VOLTAGE_1200mV 1 6362306a36Sopenharmony_ci#define ASPEED_ADC_REF_VOLTAGE_EXT_HIGH 2 6462306a36Sopenharmony_ci#define ASPEED_ADC_REF_VOLTAGE_EXT_LOW 3 6562306a36Sopenharmony_ci#define ASPEED_ADC_BAT_SENSING_DIV BIT(6) 6662306a36Sopenharmony_ci#define ASPEED_ADC_BAT_SENSING_DIV_2_3 0 6762306a36Sopenharmony_ci#define ASPEED_ADC_BAT_SENSING_DIV_1_3 1 6862306a36Sopenharmony_ci#define ASPEED_ADC_CTRL_INIT_RDY BIT(8) 6962306a36Sopenharmony_ci#define ASPEED_ADC_CH7_MODE BIT(12) 7062306a36Sopenharmony_ci#define ASPEED_ADC_CH7_NORMAL 0 7162306a36Sopenharmony_ci#define ASPEED_ADC_CH7_BAT 1 7262306a36Sopenharmony_ci#define ASPEED_ADC_BAT_SENSING_ENABLE BIT(13) 7362306a36Sopenharmony_ci#define ASPEED_ADC_CTRL_CHANNEL GENMASK(31, 16) 7462306a36Sopenharmony_ci#define ASPEED_ADC_CTRL_CHANNEL_ENABLE(ch) FIELD_PREP(ASPEED_ADC_CTRL_CHANNEL, BIT(ch)) 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci#define ASPEED_ADC_INIT_POLLING_TIME 500 7762306a36Sopenharmony_ci#define ASPEED_ADC_INIT_TIMEOUT 500000 7862306a36Sopenharmony_ci/* 7962306a36Sopenharmony_ci * When the sampling rate is too high, the ADC may not have enough charging 8062306a36Sopenharmony_ci * time, resulting in a low voltage value. Thus, the default uses a slow 8162306a36Sopenharmony_ci * sampling rate for most use cases. 8262306a36Sopenharmony_ci */ 8362306a36Sopenharmony_ci#define ASPEED_ADC_DEF_SAMPLING_RATE 65000 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistruct aspeed_adc_trim_locate { 8662306a36Sopenharmony_ci const unsigned int offset; 8762306a36Sopenharmony_ci const unsigned int field; 8862306a36Sopenharmony_ci}; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistruct aspeed_adc_model_data { 9162306a36Sopenharmony_ci const char *model_name; 9262306a36Sopenharmony_ci unsigned int min_sampling_rate; // Hz 9362306a36Sopenharmony_ci unsigned int max_sampling_rate; // Hz 9462306a36Sopenharmony_ci unsigned int vref_fixed_mv; 9562306a36Sopenharmony_ci bool wait_init_sequence; 9662306a36Sopenharmony_ci bool need_prescaler; 9762306a36Sopenharmony_ci bool bat_sense_sup; 9862306a36Sopenharmony_ci u8 scaler_bit_width; 9962306a36Sopenharmony_ci unsigned int num_channels; 10062306a36Sopenharmony_ci const struct aspeed_adc_trim_locate *trim_locate; 10162306a36Sopenharmony_ci}; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistruct adc_gain { 10462306a36Sopenharmony_ci u8 mult; 10562306a36Sopenharmony_ci u8 div; 10662306a36Sopenharmony_ci}; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistruct aspeed_adc_data { 10962306a36Sopenharmony_ci struct device *dev; 11062306a36Sopenharmony_ci const struct aspeed_adc_model_data *model_data; 11162306a36Sopenharmony_ci struct regulator *regulator; 11262306a36Sopenharmony_ci void __iomem *base; 11362306a36Sopenharmony_ci spinlock_t clk_lock; 11462306a36Sopenharmony_ci struct clk_hw *fixed_div_clk; 11562306a36Sopenharmony_ci struct clk_hw *clk_prescaler; 11662306a36Sopenharmony_ci struct clk_hw *clk_scaler; 11762306a36Sopenharmony_ci struct reset_control *rst; 11862306a36Sopenharmony_ci int vref_mv; 11962306a36Sopenharmony_ci u32 sample_period_ns; 12062306a36Sopenharmony_ci int cv; 12162306a36Sopenharmony_ci bool battery_sensing; 12262306a36Sopenharmony_ci struct adc_gain battery_mode_gain; 12362306a36Sopenharmony_ci}; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci#define ASPEED_CHAN(_idx, _data_reg_addr) { \ 12662306a36Sopenharmony_ci .type = IIO_VOLTAGE, \ 12762306a36Sopenharmony_ci .indexed = 1, \ 12862306a36Sopenharmony_ci .channel = (_idx), \ 12962306a36Sopenharmony_ci .address = (_data_reg_addr), \ 13062306a36Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 13162306a36Sopenharmony_ci .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ 13262306a36Sopenharmony_ci BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ 13362306a36Sopenharmony_ci BIT(IIO_CHAN_INFO_OFFSET), \ 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic const struct iio_chan_spec aspeed_adc_iio_channels[] = { 13762306a36Sopenharmony_ci ASPEED_CHAN(0, 0x10), 13862306a36Sopenharmony_ci ASPEED_CHAN(1, 0x12), 13962306a36Sopenharmony_ci ASPEED_CHAN(2, 0x14), 14062306a36Sopenharmony_ci ASPEED_CHAN(3, 0x16), 14162306a36Sopenharmony_ci ASPEED_CHAN(4, 0x18), 14262306a36Sopenharmony_ci ASPEED_CHAN(5, 0x1A), 14362306a36Sopenharmony_ci ASPEED_CHAN(6, 0x1C), 14462306a36Sopenharmony_ci ASPEED_CHAN(7, 0x1E), 14562306a36Sopenharmony_ci ASPEED_CHAN(8, 0x20), 14662306a36Sopenharmony_ci ASPEED_CHAN(9, 0x22), 14762306a36Sopenharmony_ci ASPEED_CHAN(10, 0x24), 14862306a36Sopenharmony_ci ASPEED_CHAN(11, 0x26), 14962306a36Sopenharmony_ci ASPEED_CHAN(12, 0x28), 15062306a36Sopenharmony_ci ASPEED_CHAN(13, 0x2A), 15162306a36Sopenharmony_ci ASPEED_CHAN(14, 0x2C), 15262306a36Sopenharmony_ci ASPEED_CHAN(15, 0x2E), 15362306a36Sopenharmony_ci}; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci#define ASPEED_BAT_CHAN(_idx, _data_reg_addr) { \ 15662306a36Sopenharmony_ci .type = IIO_VOLTAGE, \ 15762306a36Sopenharmony_ci .indexed = 1, \ 15862306a36Sopenharmony_ci .channel = (_idx), \ 15962306a36Sopenharmony_ci .address = (_data_reg_addr), \ 16062306a36Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ 16162306a36Sopenharmony_ci BIT(IIO_CHAN_INFO_OFFSET), \ 16262306a36Sopenharmony_ci .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ 16362306a36Sopenharmony_ci BIT(IIO_CHAN_INFO_SAMP_FREQ), \ 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_cistatic const struct iio_chan_spec aspeed_adc_iio_bat_channels[] = { 16662306a36Sopenharmony_ci ASPEED_CHAN(0, 0x10), 16762306a36Sopenharmony_ci ASPEED_CHAN(1, 0x12), 16862306a36Sopenharmony_ci ASPEED_CHAN(2, 0x14), 16962306a36Sopenharmony_ci ASPEED_CHAN(3, 0x16), 17062306a36Sopenharmony_ci ASPEED_CHAN(4, 0x18), 17162306a36Sopenharmony_ci ASPEED_CHAN(5, 0x1A), 17262306a36Sopenharmony_ci ASPEED_CHAN(6, 0x1C), 17362306a36Sopenharmony_ci ASPEED_BAT_CHAN(7, 0x1E), 17462306a36Sopenharmony_ci}; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cistatic int aspeed_adc_set_trim_data(struct iio_dev *indio_dev) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci struct device_node *syscon; 17962306a36Sopenharmony_ci struct regmap *scu; 18062306a36Sopenharmony_ci u32 scu_otp, trimming_val; 18162306a36Sopenharmony_ci struct aspeed_adc_data *data = iio_priv(indio_dev); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci syscon = of_find_node_by_name(NULL, "syscon"); 18462306a36Sopenharmony_ci if (syscon == NULL) { 18562306a36Sopenharmony_ci dev_warn(data->dev, "Couldn't find syscon node\n"); 18662306a36Sopenharmony_ci return -EOPNOTSUPP; 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci scu = syscon_node_to_regmap(syscon); 18962306a36Sopenharmony_ci of_node_put(syscon); 19062306a36Sopenharmony_ci if (IS_ERR(scu)) { 19162306a36Sopenharmony_ci dev_warn(data->dev, "Failed to get syscon regmap\n"); 19262306a36Sopenharmony_ci return -EOPNOTSUPP; 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci if (data->model_data->trim_locate) { 19562306a36Sopenharmony_ci if (regmap_read(scu, data->model_data->trim_locate->offset, 19662306a36Sopenharmony_ci &scu_otp)) { 19762306a36Sopenharmony_ci dev_warn(data->dev, 19862306a36Sopenharmony_ci "Failed to get adc trimming data\n"); 19962306a36Sopenharmony_ci trimming_val = 0x8; 20062306a36Sopenharmony_ci } else { 20162306a36Sopenharmony_ci trimming_val = 20262306a36Sopenharmony_ci ((scu_otp) & 20362306a36Sopenharmony_ci (data->model_data->trim_locate->field)) >> 20462306a36Sopenharmony_ci __ffs(data->model_data->trim_locate->field); 20562306a36Sopenharmony_ci if (!trimming_val) 20662306a36Sopenharmony_ci trimming_val = 0x8; 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci dev_dbg(data->dev, 20962306a36Sopenharmony_ci "trimming val = %d, offset = %08x, fields = %08x\n", 21062306a36Sopenharmony_ci trimming_val, data->model_data->trim_locate->offset, 21162306a36Sopenharmony_ci data->model_data->trim_locate->field); 21262306a36Sopenharmony_ci writel(trimming_val, data->base + ASPEED_REG_COMPENSATION_TRIM); 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci return 0; 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_cistatic int aspeed_adc_compensation(struct iio_dev *indio_dev) 21862306a36Sopenharmony_ci{ 21962306a36Sopenharmony_ci struct aspeed_adc_data *data = iio_priv(indio_dev); 22062306a36Sopenharmony_ci u32 index, adc_raw = 0; 22162306a36Sopenharmony_ci u32 adc_engine_control_reg_val; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci adc_engine_control_reg_val = 22462306a36Sopenharmony_ci readl(data->base + ASPEED_REG_ENGINE_CONTROL); 22562306a36Sopenharmony_ci adc_engine_control_reg_val &= ~ASPEED_ADC_OP_MODE; 22662306a36Sopenharmony_ci adc_engine_control_reg_val |= 22762306a36Sopenharmony_ci (FIELD_PREP(ASPEED_ADC_OP_MODE, ASPEED_ADC_OP_MODE_NORMAL) | 22862306a36Sopenharmony_ci ASPEED_ADC_ENGINE_ENABLE); 22962306a36Sopenharmony_ci /* 23062306a36Sopenharmony_ci * Enable compensating sensing: 23162306a36Sopenharmony_ci * After that, the input voltage of ADC will force to half of the reference 23262306a36Sopenharmony_ci * voltage. So the expected reading raw data will become half of the max 23362306a36Sopenharmony_ci * value. We can get compensating value = 0x200 - ADC read raw value. 23462306a36Sopenharmony_ci * It is recommended to average at least 10 samples to get a final CV. 23562306a36Sopenharmony_ci */ 23662306a36Sopenharmony_ci writel(adc_engine_control_reg_val | ASPEED_ADC_CTRL_COMPENSATION | 23762306a36Sopenharmony_ci ASPEED_ADC_CTRL_CHANNEL_ENABLE(0), 23862306a36Sopenharmony_ci data->base + ASPEED_REG_ENGINE_CONTROL); 23962306a36Sopenharmony_ci /* 24062306a36Sopenharmony_ci * After enable compensating sensing mode need to wait some time for ADC stable 24162306a36Sopenharmony_ci * Experiment result is 1ms. 24262306a36Sopenharmony_ci */ 24362306a36Sopenharmony_ci mdelay(1); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci for (index = 0; index < 16; index++) { 24662306a36Sopenharmony_ci /* 24762306a36Sopenharmony_ci * Waiting for the sampling period ensures that the value acquired 24862306a36Sopenharmony_ci * is fresh each time. 24962306a36Sopenharmony_ci */ 25062306a36Sopenharmony_ci ndelay(data->sample_period_ns); 25162306a36Sopenharmony_ci adc_raw += readw(data->base + aspeed_adc_iio_channels[0].address); 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci adc_raw >>= 4; 25462306a36Sopenharmony_ci data->cv = BIT(ASPEED_RESOLUTION_BITS - 1) - adc_raw; 25562306a36Sopenharmony_ci writel(adc_engine_control_reg_val, 25662306a36Sopenharmony_ci data->base + ASPEED_REG_ENGINE_CONTROL); 25762306a36Sopenharmony_ci dev_dbg(data->dev, "Compensating value = %d\n", data->cv); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci return 0; 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic int aspeed_adc_set_sampling_rate(struct iio_dev *indio_dev, u32 rate) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci struct aspeed_adc_data *data = iio_priv(indio_dev); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci if (rate < data->model_data->min_sampling_rate || 26762306a36Sopenharmony_ci rate > data->model_data->max_sampling_rate) 26862306a36Sopenharmony_ci return -EINVAL; 26962306a36Sopenharmony_ci /* Each sampling needs 12 clocks to convert.*/ 27062306a36Sopenharmony_ci clk_set_rate(data->clk_scaler->clk, rate * ASPEED_CLOCKS_PER_SAMPLE); 27162306a36Sopenharmony_ci rate = clk_get_rate(data->clk_scaler->clk); 27262306a36Sopenharmony_ci data->sample_period_ns = DIV_ROUND_UP_ULL( 27362306a36Sopenharmony_ci (u64)NSEC_PER_SEC * ASPEED_CLOCKS_PER_SAMPLE, rate); 27462306a36Sopenharmony_ci dev_dbg(data->dev, "Adc clock = %d sample period = %d ns", rate, 27562306a36Sopenharmony_ci data->sample_period_ns); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci return 0; 27862306a36Sopenharmony_ci} 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_cistatic int aspeed_adc_read_raw(struct iio_dev *indio_dev, 28162306a36Sopenharmony_ci struct iio_chan_spec const *chan, 28262306a36Sopenharmony_ci int *val, int *val2, long mask) 28362306a36Sopenharmony_ci{ 28462306a36Sopenharmony_ci struct aspeed_adc_data *data = iio_priv(indio_dev); 28562306a36Sopenharmony_ci u32 adc_engine_control_reg_val; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci switch (mask) { 28862306a36Sopenharmony_ci case IIO_CHAN_INFO_RAW: 28962306a36Sopenharmony_ci if (data->battery_sensing && chan->channel == 7) { 29062306a36Sopenharmony_ci adc_engine_control_reg_val = 29162306a36Sopenharmony_ci readl(data->base + ASPEED_REG_ENGINE_CONTROL); 29262306a36Sopenharmony_ci writel(adc_engine_control_reg_val | 29362306a36Sopenharmony_ci FIELD_PREP(ASPEED_ADC_CH7_MODE, 29462306a36Sopenharmony_ci ASPEED_ADC_CH7_BAT) | 29562306a36Sopenharmony_ci ASPEED_ADC_BAT_SENSING_ENABLE, 29662306a36Sopenharmony_ci data->base + ASPEED_REG_ENGINE_CONTROL); 29762306a36Sopenharmony_ci /* 29862306a36Sopenharmony_ci * After enable battery sensing mode need to wait some time for adc stable 29962306a36Sopenharmony_ci * Experiment result is 1ms. 30062306a36Sopenharmony_ci */ 30162306a36Sopenharmony_ci mdelay(1); 30262306a36Sopenharmony_ci *val = readw(data->base + chan->address); 30362306a36Sopenharmony_ci *val = (*val * data->battery_mode_gain.mult) / 30462306a36Sopenharmony_ci data->battery_mode_gain.div; 30562306a36Sopenharmony_ci /* Restore control register value */ 30662306a36Sopenharmony_ci writel(adc_engine_control_reg_val, 30762306a36Sopenharmony_ci data->base + ASPEED_REG_ENGINE_CONTROL); 30862306a36Sopenharmony_ci } else 30962306a36Sopenharmony_ci *val = readw(data->base + chan->address); 31062306a36Sopenharmony_ci return IIO_VAL_INT; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci case IIO_CHAN_INFO_OFFSET: 31362306a36Sopenharmony_ci if (data->battery_sensing && chan->channel == 7) 31462306a36Sopenharmony_ci *val = (data->cv * data->battery_mode_gain.mult) / 31562306a36Sopenharmony_ci data->battery_mode_gain.div; 31662306a36Sopenharmony_ci else 31762306a36Sopenharmony_ci *val = data->cv; 31862306a36Sopenharmony_ci return IIO_VAL_INT; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 32162306a36Sopenharmony_ci *val = data->vref_mv; 32262306a36Sopenharmony_ci *val2 = ASPEED_RESOLUTION_BITS; 32362306a36Sopenharmony_ci return IIO_VAL_FRACTIONAL_LOG2; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci case IIO_CHAN_INFO_SAMP_FREQ: 32662306a36Sopenharmony_ci *val = clk_get_rate(data->clk_scaler->clk) / 32762306a36Sopenharmony_ci ASPEED_CLOCKS_PER_SAMPLE; 32862306a36Sopenharmony_ci return IIO_VAL_INT; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci default: 33162306a36Sopenharmony_ci return -EINVAL; 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci} 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cistatic int aspeed_adc_write_raw(struct iio_dev *indio_dev, 33662306a36Sopenharmony_ci struct iio_chan_spec const *chan, 33762306a36Sopenharmony_ci int val, int val2, long mask) 33862306a36Sopenharmony_ci{ 33962306a36Sopenharmony_ci switch (mask) { 34062306a36Sopenharmony_ci case IIO_CHAN_INFO_SAMP_FREQ: 34162306a36Sopenharmony_ci return aspeed_adc_set_sampling_rate(indio_dev, val); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 34462306a36Sopenharmony_ci case IIO_CHAN_INFO_RAW: 34562306a36Sopenharmony_ci /* 34662306a36Sopenharmony_ci * Technically, these could be written but the only reasons 34762306a36Sopenharmony_ci * for doing so seem better handled in userspace. EPERM is 34862306a36Sopenharmony_ci * returned to signal this is a policy choice rather than a 34962306a36Sopenharmony_ci * hardware limitation. 35062306a36Sopenharmony_ci */ 35162306a36Sopenharmony_ci return -EPERM; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci default: 35462306a36Sopenharmony_ci return -EINVAL; 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistatic int aspeed_adc_reg_access(struct iio_dev *indio_dev, 35962306a36Sopenharmony_ci unsigned int reg, unsigned int writeval, 36062306a36Sopenharmony_ci unsigned int *readval) 36162306a36Sopenharmony_ci{ 36262306a36Sopenharmony_ci struct aspeed_adc_data *data = iio_priv(indio_dev); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci if (!readval || reg % 4 || reg > ASPEED_REG_MAX) 36562306a36Sopenharmony_ci return -EINVAL; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci *readval = readl(data->base + reg); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci return 0; 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_cistatic const struct iio_info aspeed_adc_iio_info = { 37362306a36Sopenharmony_ci .read_raw = aspeed_adc_read_raw, 37462306a36Sopenharmony_ci .write_raw = aspeed_adc_write_raw, 37562306a36Sopenharmony_ci .debugfs_reg_access = aspeed_adc_reg_access, 37662306a36Sopenharmony_ci}; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_cistatic void aspeed_adc_unregister_fixed_divider(void *data) 37962306a36Sopenharmony_ci{ 38062306a36Sopenharmony_ci struct clk_hw *clk = data; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci clk_hw_unregister_fixed_factor(clk); 38362306a36Sopenharmony_ci} 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_cistatic void aspeed_adc_reset_assert(void *data) 38662306a36Sopenharmony_ci{ 38762306a36Sopenharmony_ci struct reset_control *rst = data; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci reset_control_assert(rst); 39062306a36Sopenharmony_ci} 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_cistatic void aspeed_adc_clk_disable_unprepare(void *data) 39362306a36Sopenharmony_ci{ 39462306a36Sopenharmony_ci struct clk *clk = data; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci clk_disable_unprepare(clk); 39762306a36Sopenharmony_ci} 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_cistatic void aspeed_adc_power_down(void *data) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci struct aspeed_adc_data *priv_data = data; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci writel(FIELD_PREP(ASPEED_ADC_OP_MODE, ASPEED_ADC_OP_MODE_PWR_DOWN), 40462306a36Sopenharmony_ci priv_data->base + ASPEED_REG_ENGINE_CONTROL); 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_cistatic void aspeed_adc_reg_disable(void *data) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci struct regulator *reg = data; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci regulator_disable(reg); 41262306a36Sopenharmony_ci} 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_cistatic int aspeed_adc_vref_config(struct iio_dev *indio_dev) 41562306a36Sopenharmony_ci{ 41662306a36Sopenharmony_ci struct aspeed_adc_data *data = iio_priv(indio_dev); 41762306a36Sopenharmony_ci int ret; 41862306a36Sopenharmony_ci u32 adc_engine_control_reg_val; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci if (data->model_data->vref_fixed_mv) { 42162306a36Sopenharmony_ci data->vref_mv = data->model_data->vref_fixed_mv; 42262306a36Sopenharmony_ci return 0; 42362306a36Sopenharmony_ci } 42462306a36Sopenharmony_ci adc_engine_control_reg_val = 42562306a36Sopenharmony_ci readl(data->base + ASPEED_REG_ENGINE_CONTROL); 42662306a36Sopenharmony_ci data->regulator = devm_regulator_get_optional(data->dev, "vref"); 42762306a36Sopenharmony_ci if (!IS_ERR(data->regulator)) { 42862306a36Sopenharmony_ci ret = regulator_enable(data->regulator); 42962306a36Sopenharmony_ci if (ret) 43062306a36Sopenharmony_ci return ret; 43162306a36Sopenharmony_ci ret = devm_add_action_or_reset( 43262306a36Sopenharmony_ci data->dev, aspeed_adc_reg_disable, data->regulator); 43362306a36Sopenharmony_ci if (ret) 43462306a36Sopenharmony_ci return ret; 43562306a36Sopenharmony_ci data->vref_mv = regulator_get_voltage(data->regulator); 43662306a36Sopenharmony_ci /* Conversion from uV to mV */ 43762306a36Sopenharmony_ci data->vref_mv /= 1000; 43862306a36Sopenharmony_ci if ((data->vref_mv >= 1550) && (data->vref_mv <= 2700)) 43962306a36Sopenharmony_ci writel(adc_engine_control_reg_val | 44062306a36Sopenharmony_ci FIELD_PREP( 44162306a36Sopenharmony_ci ASPEED_ADC_REF_VOLTAGE, 44262306a36Sopenharmony_ci ASPEED_ADC_REF_VOLTAGE_EXT_HIGH), 44362306a36Sopenharmony_ci data->base + ASPEED_REG_ENGINE_CONTROL); 44462306a36Sopenharmony_ci else if ((data->vref_mv >= 900) && (data->vref_mv <= 1650)) 44562306a36Sopenharmony_ci writel(adc_engine_control_reg_val | 44662306a36Sopenharmony_ci FIELD_PREP( 44762306a36Sopenharmony_ci ASPEED_ADC_REF_VOLTAGE, 44862306a36Sopenharmony_ci ASPEED_ADC_REF_VOLTAGE_EXT_LOW), 44962306a36Sopenharmony_ci data->base + ASPEED_REG_ENGINE_CONTROL); 45062306a36Sopenharmony_ci else { 45162306a36Sopenharmony_ci dev_err(data->dev, "Regulator voltage %d not support", 45262306a36Sopenharmony_ci data->vref_mv); 45362306a36Sopenharmony_ci return -EOPNOTSUPP; 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci } else { 45662306a36Sopenharmony_ci if (PTR_ERR(data->regulator) != -ENODEV) 45762306a36Sopenharmony_ci return PTR_ERR(data->regulator); 45862306a36Sopenharmony_ci data->vref_mv = 2500000; 45962306a36Sopenharmony_ci of_property_read_u32(data->dev->of_node, 46062306a36Sopenharmony_ci "aspeed,int-vref-microvolt", 46162306a36Sopenharmony_ci &data->vref_mv); 46262306a36Sopenharmony_ci /* Conversion from uV to mV */ 46362306a36Sopenharmony_ci data->vref_mv /= 1000; 46462306a36Sopenharmony_ci if (data->vref_mv == 2500) 46562306a36Sopenharmony_ci writel(adc_engine_control_reg_val | 46662306a36Sopenharmony_ci FIELD_PREP(ASPEED_ADC_REF_VOLTAGE, 46762306a36Sopenharmony_ci ASPEED_ADC_REF_VOLTAGE_2500mV), 46862306a36Sopenharmony_ci data->base + ASPEED_REG_ENGINE_CONTROL); 46962306a36Sopenharmony_ci else if (data->vref_mv == 1200) 47062306a36Sopenharmony_ci writel(adc_engine_control_reg_val | 47162306a36Sopenharmony_ci FIELD_PREP(ASPEED_ADC_REF_VOLTAGE, 47262306a36Sopenharmony_ci ASPEED_ADC_REF_VOLTAGE_1200mV), 47362306a36Sopenharmony_ci data->base + ASPEED_REG_ENGINE_CONTROL); 47462306a36Sopenharmony_ci else { 47562306a36Sopenharmony_ci dev_err(data->dev, "Voltage %d not support", data->vref_mv); 47662306a36Sopenharmony_ci return -EOPNOTSUPP; 47762306a36Sopenharmony_ci } 47862306a36Sopenharmony_ci } 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci return 0; 48162306a36Sopenharmony_ci} 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_cistatic int aspeed_adc_probe(struct platform_device *pdev) 48462306a36Sopenharmony_ci{ 48562306a36Sopenharmony_ci struct iio_dev *indio_dev; 48662306a36Sopenharmony_ci struct aspeed_adc_data *data; 48762306a36Sopenharmony_ci int ret; 48862306a36Sopenharmony_ci u32 adc_engine_control_reg_val; 48962306a36Sopenharmony_ci unsigned long scaler_flags = 0; 49062306a36Sopenharmony_ci char clk_name[32], clk_parent_name[32]; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*data)); 49362306a36Sopenharmony_ci if (!indio_dev) 49462306a36Sopenharmony_ci return -ENOMEM; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci data = iio_priv(indio_dev); 49762306a36Sopenharmony_ci data->dev = &pdev->dev; 49862306a36Sopenharmony_ci data->model_data = of_device_get_match_data(&pdev->dev); 49962306a36Sopenharmony_ci platform_set_drvdata(pdev, indio_dev); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci data->base = devm_platform_ioremap_resource(pdev, 0); 50262306a36Sopenharmony_ci if (IS_ERR(data->base)) 50362306a36Sopenharmony_ci return PTR_ERR(data->base); 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci /* Register ADC clock prescaler with source specified by device tree. */ 50662306a36Sopenharmony_ci spin_lock_init(&data->clk_lock); 50762306a36Sopenharmony_ci snprintf(clk_parent_name, ARRAY_SIZE(clk_parent_name), "%s", 50862306a36Sopenharmony_ci of_clk_get_parent_name(pdev->dev.of_node, 0)); 50962306a36Sopenharmony_ci snprintf(clk_name, ARRAY_SIZE(clk_name), "%s-fixed-div", 51062306a36Sopenharmony_ci data->model_data->model_name); 51162306a36Sopenharmony_ci data->fixed_div_clk = clk_hw_register_fixed_factor( 51262306a36Sopenharmony_ci &pdev->dev, clk_name, clk_parent_name, 0, 1, 2); 51362306a36Sopenharmony_ci if (IS_ERR(data->fixed_div_clk)) 51462306a36Sopenharmony_ci return PTR_ERR(data->fixed_div_clk); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci ret = devm_add_action_or_reset(data->dev, 51762306a36Sopenharmony_ci aspeed_adc_unregister_fixed_divider, 51862306a36Sopenharmony_ci data->fixed_div_clk); 51962306a36Sopenharmony_ci if (ret) 52062306a36Sopenharmony_ci return ret; 52162306a36Sopenharmony_ci snprintf(clk_parent_name, ARRAY_SIZE(clk_parent_name), clk_name); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci if (data->model_data->need_prescaler) { 52462306a36Sopenharmony_ci snprintf(clk_name, ARRAY_SIZE(clk_name), "%s-prescaler", 52562306a36Sopenharmony_ci data->model_data->model_name); 52662306a36Sopenharmony_ci data->clk_prescaler = devm_clk_hw_register_divider( 52762306a36Sopenharmony_ci &pdev->dev, clk_name, clk_parent_name, 0, 52862306a36Sopenharmony_ci data->base + ASPEED_REG_CLOCK_CONTROL, 17, 15, 0, 52962306a36Sopenharmony_ci &data->clk_lock); 53062306a36Sopenharmony_ci if (IS_ERR(data->clk_prescaler)) 53162306a36Sopenharmony_ci return PTR_ERR(data->clk_prescaler); 53262306a36Sopenharmony_ci snprintf(clk_parent_name, ARRAY_SIZE(clk_parent_name), 53362306a36Sopenharmony_ci clk_name); 53462306a36Sopenharmony_ci scaler_flags = CLK_SET_RATE_PARENT; 53562306a36Sopenharmony_ci } 53662306a36Sopenharmony_ci /* 53762306a36Sopenharmony_ci * Register ADC clock scaler downstream from the prescaler. Allow rate 53862306a36Sopenharmony_ci * setting to adjust the prescaler as well. 53962306a36Sopenharmony_ci */ 54062306a36Sopenharmony_ci snprintf(clk_name, ARRAY_SIZE(clk_name), "%s-scaler", 54162306a36Sopenharmony_ci data->model_data->model_name); 54262306a36Sopenharmony_ci data->clk_scaler = devm_clk_hw_register_divider( 54362306a36Sopenharmony_ci &pdev->dev, clk_name, clk_parent_name, scaler_flags, 54462306a36Sopenharmony_ci data->base + ASPEED_REG_CLOCK_CONTROL, 0, 54562306a36Sopenharmony_ci data->model_data->scaler_bit_width, 54662306a36Sopenharmony_ci data->model_data->need_prescaler ? CLK_DIVIDER_ONE_BASED : 0, 54762306a36Sopenharmony_ci &data->clk_lock); 54862306a36Sopenharmony_ci if (IS_ERR(data->clk_scaler)) 54962306a36Sopenharmony_ci return PTR_ERR(data->clk_scaler); 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci data->rst = devm_reset_control_get_shared(&pdev->dev, NULL); 55262306a36Sopenharmony_ci if (IS_ERR(data->rst)) { 55362306a36Sopenharmony_ci dev_err(&pdev->dev, 55462306a36Sopenharmony_ci "invalid or missing reset controller device tree entry"); 55562306a36Sopenharmony_ci return PTR_ERR(data->rst); 55662306a36Sopenharmony_ci } 55762306a36Sopenharmony_ci reset_control_deassert(data->rst); 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci ret = devm_add_action_or_reset(data->dev, aspeed_adc_reset_assert, 56062306a36Sopenharmony_ci data->rst); 56162306a36Sopenharmony_ci if (ret) 56262306a36Sopenharmony_ci return ret; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci ret = aspeed_adc_vref_config(indio_dev); 56562306a36Sopenharmony_ci if (ret) 56662306a36Sopenharmony_ci return ret; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci ret = aspeed_adc_set_trim_data(indio_dev); 56962306a36Sopenharmony_ci if (ret) 57062306a36Sopenharmony_ci return ret; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci if (of_find_property(data->dev->of_node, "aspeed,battery-sensing", 57362306a36Sopenharmony_ci NULL)) { 57462306a36Sopenharmony_ci if (data->model_data->bat_sense_sup) { 57562306a36Sopenharmony_ci data->battery_sensing = 1; 57662306a36Sopenharmony_ci if (readl(data->base + ASPEED_REG_ENGINE_CONTROL) & 57762306a36Sopenharmony_ci ASPEED_ADC_BAT_SENSING_DIV) { 57862306a36Sopenharmony_ci data->battery_mode_gain.mult = 3; 57962306a36Sopenharmony_ci data->battery_mode_gain.div = 1; 58062306a36Sopenharmony_ci } else { 58162306a36Sopenharmony_ci data->battery_mode_gain.mult = 3; 58262306a36Sopenharmony_ci data->battery_mode_gain.div = 2; 58362306a36Sopenharmony_ci } 58462306a36Sopenharmony_ci } else 58562306a36Sopenharmony_ci dev_warn(&pdev->dev, 58662306a36Sopenharmony_ci "Failed to enable battery-sensing mode\n"); 58762306a36Sopenharmony_ci } 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci ret = clk_prepare_enable(data->clk_scaler->clk); 59062306a36Sopenharmony_ci if (ret) 59162306a36Sopenharmony_ci return ret; 59262306a36Sopenharmony_ci ret = devm_add_action_or_reset(data->dev, 59362306a36Sopenharmony_ci aspeed_adc_clk_disable_unprepare, 59462306a36Sopenharmony_ci data->clk_scaler->clk); 59562306a36Sopenharmony_ci if (ret) 59662306a36Sopenharmony_ci return ret; 59762306a36Sopenharmony_ci ret = aspeed_adc_set_sampling_rate(indio_dev, 59862306a36Sopenharmony_ci ASPEED_ADC_DEF_SAMPLING_RATE); 59962306a36Sopenharmony_ci if (ret) 60062306a36Sopenharmony_ci return ret; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci adc_engine_control_reg_val = 60362306a36Sopenharmony_ci readl(data->base + ASPEED_REG_ENGINE_CONTROL); 60462306a36Sopenharmony_ci adc_engine_control_reg_val |= 60562306a36Sopenharmony_ci FIELD_PREP(ASPEED_ADC_OP_MODE, ASPEED_ADC_OP_MODE_NORMAL) | 60662306a36Sopenharmony_ci ASPEED_ADC_ENGINE_ENABLE; 60762306a36Sopenharmony_ci /* Enable engine in normal mode. */ 60862306a36Sopenharmony_ci writel(adc_engine_control_reg_val, 60962306a36Sopenharmony_ci data->base + ASPEED_REG_ENGINE_CONTROL); 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci ret = devm_add_action_or_reset(data->dev, aspeed_adc_power_down, 61262306a36Sopenharmony_ci data); 61362306a36Sopenharmony_ci if (ret) 61462306a36Sopenharmony_ci return ret; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci if (data->model_data->wait_init_sequence) { 61762306a36Sopenharmony_ci /* Wait for initial sequence complete. */ 61862306a36Sopenharmony_ci ret = readl_poll_timeout(data->base + ASPEED_REG_ENGINE_CONTROL, 61962306a36Sopenharmony_ci adc_engine_control_reg_val, 62062306a36Sopenharmony_ci adc_engine_control_reg_val & 62162306a36Sopenharmony_ci ASPEED_ADC_CTRL_INIT_RDY, 62262306a36Sopenharmony_ci ASPEED_ADC_INIT_POLLING_TIME, 62362306a36Sopenharmony_ci ASPEED_ADC_INIT_TIMEOUT); 62462306a36Sopenharmony_ci if (ret) 62562306a36Sopenharmony_ci return ret; 62662306a36Sopenharmony_ci } 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci aspeed_adc_compensation(indio_dev); 62962306a36Sopenharmony_ci /* Start all channels in normal mode. */ 63062306a36Sopenharmony_ci adc_engine_control_reg_val = 63162306a36Sopenharmony_ci readl(data->base + ASPEED_REG_ENGINE_CONTROL); 63262306a36Sopenharmony_ci adc_engine_control_reg_val |= ASPEED_ADC_CTRL_CHANNEL; 63362306a36Sopenharmony_ci writel(adc_engine_control_reg_val, 63462306a36Sopenharmony_ci data->base + ASPEED_REG_ENGINE_CONTROL); 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci indio_dev->name = data->model_data->model_name; 63762306a36Sopenharmony_ci indio_dev->info = &aspeed_adc_iio_info; 63862306a36Sopenharmony_ci indio_dev->modes = INDIO_DIRECT_MODE; 63962306a36Sopenharmony_ci indio_dev->channels = data->battery_sensing ? 64062306a36Sopenharmony_ci aspeed_adc_iio_bat_channels : 64162306a36Sopenharmony_ci aspeed_adc_iio_channels; 64262306a36Sopenharmony_ci indio_dev->num_channels = data->model_data->num_channels; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci ret = devm_iio_device_register(data->dev, indio_dev); 64562306a36Sopenharmony_ci return ret; 64662306a36Sopenharmony_ci} 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_cistatic const struct aspeed_adc_trim_locate ast2500_adc_trim = { 64962306a36Sopenharmony_ci .offset = 0x154, 65062306a36Sopenharmony_ci .field = GENMASK(31, 28), 65162306a36Sopenharmony_ci}; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_cistatic const struct aspeed_adc_trim_locate ast2600_adc0_trim = { 65462306a36Sopenharmony_ci .offset = 0x5d0, 65562306a36Sopenharmony_ci .field = GENMASK(3, 0), 65662306a36Sopenharmony_ci}; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_cistatic const struct aspeed_adc_trim_locate ast2600_adc1_trim = { 65962306a36Sopenharmony_ci .offset = 0x5d0, 66062306a36Sopenharmony_ci .field = GENMASK(7, 4), 66162306a36Sopenharmony_ci}; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_cistatic const struct aspeed_adc_model_data ast2400_model_data = { 66462306a36Sopenharmony_ci .model_name = "ast2400-adc", 66562306a36Sopenharmony_ci .vref_fixed_mv = 2500, 66662306a36Sopenharmony_ci .min_sampling_rate = 10000, 66762306a36Sopenharmony_ci .max_sampling_rate = 500000, 66862306a36Sopenharmony_ci .need_prescaler = true, 66962306a36Sopenharmony_ci .scaler_bit_width = 10, 67062306a36Sopenharmony_ci .num_channels = 16, 67162306a36Sopenharmony_ci}; 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_cistatic const struct aspeed_adc_model_data ast2500_model_data = { 67462306a36Sopenharmony_ci .model_name = "ast2500-adc", 67562306a36Sopenharmony_ci .vref_fixed_mv = 1800, 67662306a36Sopenharmony_ci .min_sampling_rate = 1, 67762306a36Sopenharmony_ci .max_sampling_rate = 1000000, 67862306a36Sopenharmony_ci .wait_init_sequence = true, 67962306a36Sopenharmony_ci .need_prescaler = true, 68062306a36Sopenharmony_ci .scaler_bit_width = 10, 68162306a36Sopenharmony_ci .num_channels = 16, 68262306a36Sopenharmony_ci .trim_locate = &ast2500_adc_trim, 68362306a36Sopenharmony_ci}; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_cistatic const struct aspeed_adc_model_data ast2600_adc0_model_data = { 68662306a36Sopenharmony_ci .model_name = "ast2600-adc0", 68762306a36Sopenharmony_ci .min_sampling_rate = 10000, 68862306a36Sopenharmony_ci .max_sampling_rate = 500000, 68962306a36Sopenharmony_ci .wait_init_sequence = true, 69062306a36Sopenharmony_ci .bat_sense_sup = true, 69162306a36Sopenharmony_ci .scaler_bit_width = 16, 69262306a36Sopenharmony_ci .num_channels = 8, 69362306a36Sopenharmony_ci .trim_locate = &ast2600_adc0_trim, 69462306a36Sopenharmony_ci}; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_cistatic const struct aspeed_adc_model_data ast2600_adc1_model_data = { 69762306a36Sopenharmony_ci .model_name = "ast2600-adc1", 69862306a36Sopenharmony_ci .min_sampling_rate = 10000, 69962306a36Sopenharmony_ci .max_sampling_rate = 500000, 70062306a36Sopenharmony_ci .wait_init_sequence = true, 70162306a36Sopenharmony_ci .bat_sense_sup = true, 70262306a36Sopenharmony_ci .scaler_bit_width = 16, 70362306a36Sopenharmony_ci .num_channels = 8, 70462306a36Sopenharmony_ci .trim_locate = &ast2600_adc1_trim, 70562306a36Sopenharmony_ci}; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_cistatic const struct of_device_id aspeed_adc_matches[] = { 70862306a36Sopenharmony_ci { .compatible = "aspeed,ast2400-adc", .data = &ast2400_model_data }, 70962306a36Sopenharmony_ci { .compatible = "aspeed,ast2500-adc", .data = &ast2500_model_data }, 71062306a36Sopenharmony_ci { .compatible = "aspeed,ast2600-adc0", .data = &ast2600_adc0_model_data }, 71162306a36Sopenharmony_ci { .compatible = "aspeed,ast2600-adc1", .data = &ast2600_adc1_model_data }, 71262306a36Sopenharmony_ci {}, 71362306a36Sopenharmony_ci}; 71462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, aspeed_adc_matches); 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_cistatic struct platform_driver aspeed_adc_driver = { 71762306a36Sopenharmony_ci .probe = aspeed_adc_probe, 71862306a36Sopenharmony_ci .driver = { 71962306a36Sopenharmony_ci .name = KBUILD_MODNAME, 72062306a36Sopenharmony_ci .of_match_table = aspeed_adc_matches, 72162306a36Sopenharmony_ci } 72262306a36Sopenharmony_ci}; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_cimodule_platform_driver(aspeed_adc_driver); 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ciMODULE_AUTHOR("Rick Altherr <raltherr@google.com>"); 72762306a36Sopenharmony_ciMODULE_DESCRIPTION("Aspeed AST2400/2500/2600 ADC Driver"); 72862306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 729