iio: adc: rradc: Update RRADC reads and scaling

A check is needed to ensure the LSB and MSB are coherent
when reading the result registers for the RRADC channels.
The driver performs another round of read request and
compares the result registers to ensure the data read
back is coherent.

Since there are no channel specific properties remove
the dependency to add the channel nodes in the device
tree and instead statically register the channels within
the driver.

Update the scaling functions to report in the units
desired for the final scaled value based on the channel.
The resistance channel reports the units for batt_id
in ohms, the voltage channels such as DCIN, USBIN report
the value in units of microvolts, the current channels
in units of microamps and the temperature channels
such as thermistors are reported in units of millidegC.

Change-Id: I56e6bff28be2cc23f00622d5c37e42564c51a72f
Signed-off-by: Siddartha Mohanadoss <smohanad@codeaurora.org>
This commit is contained in:
Siddartha Mohanadoss 2016-07-19 21:24:30 -07:00 committed by Nicholas Troast
parent 2a61ba9c0d
commit e64cce5256
2 changed files with 144 additions and 109 deletions

View file

@ -36,13 +36,10 @@ Main node properties:
Definition: Must be one. For details about IIO bindings see:
Documentation/devicetree/bindings/iio/iio-bindings.txt
Channel subnode properties:
- channel:
Usage: required
Value type: <u32>
Definition: ADC channel number.
See drivers/iio/adc/qcom-rradc.c for channels within rradc_channel_id
IIO client nodes need to specify the RRADC channel number while requesting ADC reads.
The channel list supported by the RRADC driver is available in the enum rradc_channel_id
located at at drivers/iio/adc/qcom-rradc.c. Clients can use this index from the enum
as the channel number while requesting ADC reads.
Example:
@ -53,11 +50,6 @@ Example:
#address-cells = <1>;
#size-cells = <0>;
#io-channel-cells = <1>;
/* Channel node */
batt_id {
channel = <0>;
};
};
/* IIO client node */

View file

@ -162,6 +162,9 @@
#define FG_ADC_KELVINMIL_CELSIUSMIL 273150
#define FG_ADC_RR_GPIO_FS_RANGE 5000
#define FG_RR_ADC_COHERENT_CHECK_RETRY 5
#define FG_RR_ADC_MAX_CONTINUOUS_BUFFER_LEN 16
#define FG_RR_ADC_STS_CHANNEL_READING_MASK 0x3
/*
* The channel number is not a physical index in hardware,
@ -171,21 +174,16 @@
* the RR ADC before RR_ADC_MAX.
*/
enum rradc_channel_id {
RR_ADC_BATT_ID_5 = 0,
RR_ADC_BATT_ID_15,
RR_ADC_BATT_ID_150,
RR_ADC_BATT_ID,
RR_ADC_BATT_ID = 0,
RR_ADC_BATT_THERM,
RR_ADC_SKIN_TEMP,
RR_ADC_USBIN_V,
RR_ADC_USBIN_I,
RR_ADC_DCIN_V,
RR_ADC_USBIN_V,
RR_ADC_DCIN_I,
RR_ADC_DCIN_V,
RR_ADC_DIE_TEMP,
RR_ADC_CHG_TEMP,
RR_ADC_GPIO,
RR_ADC_ATEST,
RR_ADC_TM_ADC,
RR_ADC_MAX
};
@ -205,51 +203,75 @@ struct rradc_channels {
long info_mask;
u8 lsb;
u8 msb;
u8 sts;
int (*scale)(struct rradc_chip *chip, struct rradc_chan_prop *prop,
u16 adc_code, int *result);
};
struct rradc_chan_prop {
enum rradc_channel_id channel;
uint32_t channel_data;
int (*scale)(struct rradc_chip *chip, struct rradc_chan_prop *prop,
u16 adc_code, int *result);
};
static int rradc_read(struct rradc_chip *rr_adc, u16 offset, u8 *data, int len)
{
int rc = 0;
int rc = 0, retry_cnt = 0, i = 0;
u8 data_check[FG_RR_ADC_MAX_CONTINUOUS_BUFFER_LEN];
bool coherent_err = false;
rc = regmap_bulk_read(rr_adc->regmap, rr_adc->base + offset, data, len);
if (rc < 0)
pr_err("rr adc read reg %d failed with %d\n", offset, rc);
if (len > FG_RR_ADC_MAX_CONTINUOUS_BUFFER_LEN) {
pr_err("Increase the buffer length\n");
return -EINVAL;
}
while (retry_cnt < FG_RR_ADC_COHERENT_CHECK_RETRY) {
rc = regmap_bulk_read(rr_adc->regmap, rr_adc->base + offset,
data, len);
if (rc < 0) {
pr_err("rr_adc reg 0x%x failed :%d\n", offset, rc);
return rc;
}
rc = regmap_bulk_read(rr_adc->regmap, rr_adc->base + offset,
data_check, len);
if (rc < 0) {
pr_err("rr_adc reg 0x%x failed :%d\n", offset, rc);
return rc;
}
for (i = 0; i < len; i++) {
if (data[i] != data_check[i])
coherent_err = true;
}
if (coherent_err) {
retry_cnt++;
coherent_err = false;
pr_debug("retry_cnt:%d\n", retry_cnt);
} else {
break;
}
}
if (retry_cnt == FG_RR_ADC_COHERENT_CHECK_RETRY)
pr_err("Retry exceeded for coherrency check\n");
return rc;
}
static int rradc_post_process_batt_id(struct rradc_chip *chip,
struct rradc_chan_prop *prop, u16 adc_code,
int *result_mohms)
int *result_ohms)
{
uint32_t current_value;
int64_t r_id;
switch (prop->channel) {
case RR_ADC_BATT_ID_5:
current_value = FG_ADC_RR_BATT_ID_5_MA;
break;
case RR_ADC_BATT_ID_15:
current_value = FG_ADC_RR_BATT_ID_15_MA;
break;
case RR_ADC_BATT_ID_150:
current_value = FG_ADC_RR_BATT_ID_150_MA;
break;
default:
return -EINVAL;
}
current_value = prop->channel_data;
r_id = ((int64_t)adc_code * FG_ADC_RR_FS_VOLTAGE_MV);
r_id = div64_s64(r_id, (FG_MAX_ADC_READINGS * current_value));
*result_mohms = (r_id * FG_ADC_SCALE_MILLI_FACTOR);
*result_ohms = (r_id * FG_ADC_SCALE_MILLI_FACTOR);
return 0;
}
@ -270,30 +292,30 @@ static int rradc_post_process_therm(struct rradc_chip *chip,
static int rradc_post_process_volt(struct rradc_chip *chip,
struct rradc_chan_prop *prop, u16 adc_code,
int *result_mv)
int *result_uv)
{
int64_t mv = 0;
int64_t uv = 0;
/* 8x input attenuation; 2.5V ADC full scale */
mv = ((int64_t)adc_code * FG_ADC_RR_VOLT_INPUT_FACTOR);
mv *= FG_ADC_RR_FS_VOLTAGE_MV;
mv = div64_s64(mv, FG_MAX_ADC_READINGS);
*result_mv = mv;
uv = ((int64_t)adc_code * FG_ADC_RR_VOLT_INPUT_FACTOR);
uv *= (FG_ADC_RR_FS_VOLTAGE_MV * FG_ADC_SCALE_MILLI_FACTOR);
uv = div64_s64(uv, FG_MAX_ADC_READINGS);
*result_uv = uv;
return 0;
}
static int rradc_post_process_curr(struct rradc_chip *chip,
struct rradc_chan_prop *prop, u16 adc_code,
int *result_ma)
int *result_ua)
{
int64_t ma = 0;
int64_t ua = 0;
/* 0.5 V/A; 2.5V ADC full scale */
ma = ((int64_t)adc_code * FG_ADC_RR_CURR_INPUT_FACTOR);
ma *= FG_ADC_RR_FS_VOLTAGE_MV;
ma = div64_s64(ma, FG_MAX_ADC_READINGS);
*result_ma = ma;
ua = ((int64_t)adc_code * FG_ADC_RR_CURR_INPUT_FACTOR);
ua *= (FG_ADC_RR_FS_VOLTAGE_MV * FG_ADC_SCALE_MILLI_FACTOR);
ua = div64_s64(ua, FG_MAX_ADC_READINGS);
*result_ua = ua;
return 0;
}
@ -346,63 +368,68 @@ static int rradc_post_process_gpio(struct rradc_chip *chip,
return 0;
}
#define RR_ADC_CHAN(_dname, _type, _mask, _scale, _lsb, _msb) \
#define RR_ADC_CHAN(_dname, _type, _mask, _scale, _lsb, _msb, _sts) \
{ \
.datasheet_name = __stringify(_dname), \
.datasheet_name = (_dname), \
.type = _type, \
.info_mask = _mask, \
.scale = _scale, \
.lsb = _lsb, \
.msb = _msb, \
.sts = _sts, \
}, \
#define RR_ADC_CHAN_TEMP(_dname, _scale, _lsb, _msb) \
#define RR_ADC_CHAN_TEMP(_dname, _scale, _lsb, _msb, _sts) \
RR_ADC_CHAN(_dname, IIO_TEMP, \
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_PROCESSED), \
_scale, _lsb, _msb) \
_scale, _lsb, _msb, _sts) \
#define RR_ADC_CHAN_VOLT(_dname, _scale, _lsb, _msb) \
#define RR_ADC_CHAN_VOLT(_dname, _scale, _lsb, _msb, _sts) \
RR_ADC_CHAN(_dname, IIO_VOLTAGE, \
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_PROCESSED),\
_scale, _lsb, _msb) \
_scale, _lsb, _msb, _sts) \
#define RR_ADC_CHAN_CURRENT(_dname, _scale, _lsb, _msb) \
#define RR_ADC_CHAN_CURRENT(_dname, _scale, _lsb, _msb, _sts) \
RR_ADC_CHAN(_dname, IIO_CURRENT, \
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_PROCESSED),\
_scale, _lsb, _msb) \
_scale, _lsb, _msb, _sts) \
#define RR_ADC_CHAN_RESISTANCE(_dname, _scale, _lsb, _msb) \
#define RR_ADC_CHAN_RESISTANCE(_dname, _scale, _lsb, _msb, _sts) \
RR_ADC_CHAN(_dname, IIO_RESISTANCE, \
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_PROCESSED),\
_scale, _lsb, _msb) \
_scale, _lsb, _msb, _sts) \
static const struct rradc_channels rradc_chans[] = {
RR_ADC_CHAN_RESISTANCE("batt_id_5", rradc_post_process_batt_id,
FG_ADC_RR_BATT_ID_5_LSB, FG_ADC_RR_BATT_ID_5_MSB)
RR_ADC_CHAN_RESISTANCE("batt_id_15", rradc_post_process_batt_id,
FG_ADC_RR_BATT_ID_15_LSB, FG_ADC_RR_BATT_ID_15_MSB)
RR_ADC_CHAN_RESISTANCE("batt_id_150", rradc_post_process_batt_id,
FG_ADC_RR_BATT_ID_150_LSB, FG_ADC_RR_BATT_ID_150_MSB)
RR_ADC_CHAN_RESISTANCE("batt_id", rradc_post_process_batt_id,
FG_ADC_RR_BATT_ID_5_LSB, FG_ADC_RR_BATT_ID_5_MSB)
FG_ADC_RR_BATT_ID_5_LSB, FG_ADC_RR_BATT_ID_5_MSB,
FG_ADC_RR_BATT_ID_STS)
RR_ADC_CHAN_TEMP("batt_therm", &rradc_post_process_therm,
FG_ADC_RR_BATT_THERM_LSB, FG_ADC_RR_BATT_THERM_MSB)
FG_ADC_RR_BATT_THERM_LSB, FG_ADC_RR_BATT_THERM_MSB,
FG_ADC_RR_BATT_THERM_STS)
RR_ADC_CHAN_TEMP("skin_temp", &rradc_post_process_therm,
FG_ADC_RR_SKIN_TEMP_LSB, FG_ADC_RR_SKIN_TEMP_MSB)
FG_ADC_RR_SKIN_TEMP_LSB, FG_ADC_RR_SKIN_TEMP_MSB,
FG_ADC_RR_AUX_THERM_STS)
RR_ADC_CHAN_CURRENT("usbin_i", &rradc_post_process_curr,
FG_ADC_RR_USB_IN_V_LSB, FG_ADC_RR_USB_IN_V_MSB)
FG_ADC_RR_USB_IN_I_LSB, FG_ADC_RR_USB_IN_I_MSB,
FG_ADC_RR_USB_IN_I_STS)
RR_ADC_CHAN_VOLT("usbin_v", &rradc_post_process_volt,
FG_ADC_RR_USB_IN_I_LSB, FG_ADC_RR_USB_IN_I_MSB)
FG_ADC_RR_USB_IN_V_LSB, FG_ADC_RR_USB_IN_V_MSB,
FG_ADC_RR_USB_IN_V_STS)
RR_ADC_CHAN_CURRENT("dcin_i", &rradc_post_process_curr,
FG_ADC_RR_DC_IN_V_LSB, FG_ADC_RR_DC_IN_V_MSB)
FG_ADC_RR_DC_IN_I_LSB, FG_ADC_RR_DC_IN_I_MSB,
FG_ADC_RR_DC_IN_I_STS)
RR_ADC_CHAN_VOLT("dcin_v", &rradc_post_process_volt,
FG_ADC_RR_DC_IN_I_LSB, FG_ADC_RR_DC_IN_I_MSB)
FG_ADC_RR_DC_IN_V_LSB, FG_ADC_RR_DC_IN_V_MSB,
FG_ADC_RR_DC_IN_V_STS)
RR_ADC_CHAN_TEMP("die_temp", &rradc_post_process_die_temp,
FG_ADC_RR_PMI_DIE_TEMP_LSB, FG_ADC_RR_PMI_DIE_TEMP_MSB)
FG_ADC_RR_PMI_DIE_TEMP_LSB, FG_ADC_RR_PMI_DIE_TEMP_MSB,
FG_ADC_RR_PMI_DIE_TEMP_STS)
RR_ADC_CHAN_TEMP("chg_temp", &rradc_post_process_chg_temp,
FG_ADC_RR_CHARGER_TEMP_LSB, FG_ADC_RR_CHARGER_TEMP_MSB)
FG_ADC_RR_CHARGER_TEMP_LSB, FG_ADC_RR_CHARGER_TEMP_MSB,
FG_ADC_RR_CHARGER_TEMP_STS)
RR_ADC_CHAN_VOLT("gpio", &rradc_post_process_gpio,
FG_ADC_RR_GPIO_LSB, FG_ADC_RR_GPIO_MSB)
FG_ADC_RR_GPIO_LSB, FG_ADC_RR_GPIO_MSB,
FG_ADC_RR_GPIO_STS)
};
static int rradc_do_conversion(struct rradc_chip *chip,
@ -411,15 +438,35 @@ static int rradc_do_conversion(struct rradc_chip *chip,
int rc = 0, bytes_to_read = 0;
u8 buf[6];
u16 offset = 0, batt_id_5 = 0, batt_id_15 = 0, batt_id_150 = 0;
u16 status = 0;
mutex_lock(&chip->lock);
if (prop->channel != RR_ADC_BATT_ID) {
/* BATT_ID STS bit does not get set initially */
status = rradc_chans[prop->channel].sts;
rc = rradc_read(chip, status, buf, 1);
if (rc < 0) {
pr_err("status read failed:%d\n", rc);
goto fail;
}
buf[0] &= FG_RR_ADC_STS_CHANNEL_READING_MASK;
if (buf[0] != FG_RR_ADC_STS_CHANNEL_READING_MASK) {
pr_warn("%s is not ready; nothing to read\n",
rradc_chans[prop->channel].datasheet_name);
rc = -ENODATA;
goto fail;
}
}
offset = rradc_chans[prop->channel].lsb;
if (prop->channel == RR_ADC_BATT_ID)
bytes_to_read = 6;
else
bytes_to_read = 2;
buf[0] = 0;
rc = rradc_read(chip, offset, buf, bytes_to_read);
if (rc) {
pr_err("read data failed\n");
@ -427,18 +474,27 @@ static int rradc_do_conversion(struct rradc_chip *chip,
}
if (prop->channel == RR_ADC_BATT_ID) {
batt_id_150 = (buf[4] << 8) | buf[5];
batt_id_15 = (buf[2] << 8) | buf[3];
batt_id_5 = (buf[0] << 8) | buf[1];
batt_id_150 = (buf[5] << 8) | buf[4];
batt_id_15 = (buf[3] << 8) | buf[2];
batt_id_5 = (buf[1] << 8) | buf[0];
if ((!batt_id_150) && (!batt_id_15) && (!batt_id_5)) {
pr_err("Invalid batt_id values with all zeros\n");
rc = -EINVAL;
goto fail;
}
if (batt_id_150 <= FG_ADC_RR_BATT_ID_RANGE) {
pr_debug("Batt_id_150 is chosen\n");
*data = batt_id_150;
prop->channel_data = FG_ADC_RR_BATT_ID_150_MA;
} else if (batt_id_15 <= FG_ADC_RR_BATT_ID_RANGE) {
pr_debug("Batt_id_15 is chosen\n");
*data = batt_id_15;
prop->channel_data = FG_ADC_RR_BATT_ID_15_MA;
} else {
pr_debug("Batt_id_5 is chosen\n");
*data = batt_id_5;
prop->channel_data = FG_ADC_RR_BATT_ID_5_MA;
}
} else {
*data = (buf[1] << 8) | buf[0];
@ -458,6 +514,11 @@ static int rradc_read_raw(struct iio_dev *indio_dev,
u16 adc_code;
int rc = 0;
if (chan->address >= RR_ADC_MAX) {
pr_err("Invalid channel index:%ld\n", chan->address);
return -EINVAL;
}
switch (mask) {
case IIO_CHAN_INFO_PROCESSED:
prop = &chip->chan_props[chan->address];
@ -477,10 +538,6 @@ static int rradc_read_raw(struct iio_dev *indio_dev,
*val = (int) adc_code;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = 0;
*val2 = 1000;
return IIO_VAL_INT_PLUS_MICRO;
default:
rc = -EINVAL;
break;
@ -498,15 +555,11 @@ static int rradc_get_dt_data(struct rradc_chip *chip, struct device_node *node)
{
const struct rradc_channels *rradc_chan;
struct iio_chan_spec *iio_chan;
struct device_node *child;
unsigned int index = 0, chan, base;
unsigned int i = 0, base;
int rc = 0;
struct rradc_chan_prop prop;
chip->nchannels = of_get_available_child_count(node);
if (!chip->nchannels || (chip->nchannels >= RR_ADC_MAX))
return -EINVAL;
chip->nchannels = RR_ADC_MAX;
chip->iio_chans = devm_kcalloc(chip->dev, chip->nchannels,
sizeof(*chip->iio_chans), GFP_KERNEL);
if (!chip->iio_chans)
@ -529,31 +582,21 @@ static int rradc_get_dt_data(struct rradc_chip *chip, struct device_node *node)
chip->base = base;
iio_chan = chip->iio_chans;
for_each_available_child_of_node(node, child) {
rc = of_property_read_u32(child, "channel", &chan);
if (rc) {
dev_err(chip->dev, "invalid channel number %d\n", chan);
return rc;
}
for (i = 0; i < RR_ADC_MAX; i++) {
prop.channel = i;
prop.scale = rradc_chans[i].scale;
/* Private channel data used for selecting batt_id */
prop.channel_data = 0;
chip->chan_props[i] = prop;
if (chan > RR_ADC_MAX || chan < RR_ADC_BATT_ID_5) {
dev_err(chip->dev, "invalid channel number %d\n", chan);
return -EINVAL;
}
prop.channel = chan;
prop.scale = rradc_chans[chan].scale;
chip->chan_props[index] = prop;
rradc_chan = &rradc_chans[chan];
rradc_chan = &rradc_chans[i];
iio_chan->channel = prop.channel;
iio_chan->datasheet_name = rradc_chan->datasheet_name;
iio_chan->extend_name = rradc_chan->datasheet_name;
iio_chan->info_mask_separate = rradc_chan->info_mask;
iio_chan->type = rradc_chan->type;
iio_chan->indexed = 1;
iio_chan->address = index++;
iio_chan->address = i;
iio_chan++;
}