Skip to content

Commit

Permalink
iio: adc: aspeed: Support battery sensing.
Browse files Browse the repository at this point in the history
In ast2600, ADC integrate dividing circuit at last input channel for
battery sensing. This patch use the dts property "battery-sensing" to
enable this feature makes the last channel of each adc can tolerance
higher voltage than reference voltage. The offset interface of ch7 will
be separated when enabling the battery sensing mode.

Signed-off-by: Billy Tsai <billy_tsai@aspeedtech.com>
Link: https://lore.kernel.org/r/20210922081520.30580-11-billy_tsai@aspeedtech.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
  • Loading branch information
billy-tsai authored and jic23 committed Oct 19, 2021
1 parent f2836e8 commit df05f38
Showing 1 changed file with 78 additions and 3 deletions.
81 changes: 78 additions & 3 deletions drivers/iio/adc/aspeed_adc.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,16 @@ struct aspeed_adc_model_data {
unsigned int vref_fixed_mv;
bool wait_init_sequence;
bool need_prescaler;
bool bat_sense_sup;
u8 scaler_bit_width;
unsigned int num_channels;
};

struct adc_gain {
u8 mult;
u8 div;
};

struct aspeed_adc_data {
struct device *dev;
const struct aspeed_adc_model_data *model_data;
Expand All @@ -104,6 +110,8 @@ struct aspeed_adc_data {
int vref_mv;
u32 sample_period_ns;
int cv;
bool battery_sensing;
struct adc_gain battery_mode_gain;
};

#define ASPEED_CHAN(_idx, _data_reg_addr) { \
Expand Down Expand Up @@ -136,6 +144,27 @@ static const struct iio_chan_spec aspeed_adc_iio_channels[] = {
ASPEED_CHAN(15, 0x2E),
};

#define ASPEED_BAT_CHAN(_idx, _data_reg_addr) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = (_idx), \
.address = (_data_reg_addr), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_OFFSET), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
}
static const struct iio_chan_spec aspeed_adc_iio_bat_channels[] = {
ASPEED_CHAN(0, 0x10),
ASPEED_CHAN(1, 0x12),
ASPEED_CHAN(2, 0x14),
ASPEED_CHAN(3, 0x16),
ASPEED_CHAN(4, 0x18),
ASPEED_CHAN(5, 0x1A),
ASPEED_CHAN(6, 0x1C),
ASPEED_BAT_CHAN(7, 0x1E),
};

static int aspeed_adc_compensation(struct iio_dev *indio_dev)
{
struct aspeed_adc_data *data = iio_priv(indio_dev);
Expand Down Expand Up @@ -204,14 +233,39 @@ static int aspeed_adc_read_raw(struct iio_dev *indio_dev,
int *val, int *val2, long mask)
{
struct aspeed_adc_data *data = iio_priv(indio_dev);
u32 adc_engine_control_reg_val;

switch (mask) {
case IIO_CHAN_INFO_RAW:
*val = readw(data->base + chan->address);
if (data->battery_sensing && chan->channel == 7) {
adc_engine_control_reg_val =
readl(data->base + ASPEED_REG_ENGINE_CONTROL);
writel(adc_engine_control_reg_val |
FIELD_PREP(ASPEED_ADC_CH7_MODE,
ASPEED_ADC_CH7_BAT) |
ASPEED_ADC_BAT_SENSING_ENABLE,
data->base + ASPEED_REG_ENGINE_CONTROL);
/*
* After enable battery sensing mode need to wait some time for adc stable
* Experiment result is 1ms.
*/
mdelay(1);
*val = readw(data->base + chan->address);
*val = (*val * data->battery_mode_gain.mult) /
data->battery_mode_gain.div;
/* Restore control register value */
writel(adc_engine_control_reg_val,
data->base + ASPEED_REG_ENGINE_CONTROL);
} else
*val = readw(data->base + chan->address);
return IIO_VAL_INT;

case IIO_CHAN_INFO_OFFSET:
*val = data->cv;
if (data->battery_sensing && chan->channel == 7)
*val = (data->cv * data->battery_mode_gain.mult) /
data->battery_mode_gain.div;
else
*val = data->cv;
return IIO_VAL_INT;

case IIO_CHAN_INFO_SCALE:
Expand Down Expand Up @@ -459,6 +513,23 @@ static int aspeed_adc_probe(struct platform_device *pdev)
if (ret)
return ret;

if (of_find_property(data->dev->of_node, "aspeed,battery-sensing",
NULL)) {
if (data->model_data->bat_sense_sup) {
data->battery_sensing = 1;
if (readl(data->base + ASPEED_REG_ENGINE_CONTROL) &
ASPEED_ADC_BAT_SENSING_DIV) {
data->battery_mode_gain.mult = 3;
data->battery_mode_gain.div = 1;
} else {
data->battery_mode_gain.mult = 3;
data->battery_mode_gain.div = 2;
}
} else
dev_warn(&pdev->dev,
"Failed to enable battey-sensing mode\n");
}

ret = clk_prepare_enable(data->clk_scaler->clk);
if (ret)
return ret;
Expand Down Expand Up @@ -509,7 +580,9 @@ static int aspeed_adc_probe(struct platform_device *pdev)
indio_dev->name = data->model_data->model_name;
indio_dev->info = &aspeed_adc_iio_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = aspeed_adc_iio_channels;
indio_dev->channels = data->battery_sensing ?
aspeed_adc_iio_bat_channels :
aspeed_adc_iio_channels;
indio_dev->num_channels = data->model_data->num_channels;

ret = devm_iio_device_register(data->dev, indio_dev);
Expand Down Expand Up @@ -542,6 +615,7 @@ static const struct aspeed_adc_model_data ast2600_adc0_model_data = {
.min_sampling_rate = 10000,
.max_sampling_rate = 500000,
.wait_init_sequence = true,
.bat_sense_sup = true,
.scaler_bit_width = 16,
.num_channels = 8,
};
Expand All @@ -551,6 +625,7 @@ static const struct aspeed_adc_model_data ast2600_adc1_model_data = {
.min_sampling_rate = 10000,
.max_sampling_rate = 500000,
.wait_init_sequence = true,
.bat_sense_sup = true,
.scaler_bit_width = 16,
.num_channels = 8,
};
Expand Down

0 comments on commit df05f38

Please sign in to comment.