diff options
author | Jinyoung Park <jinyoungp@nvidia.com> | 2013-06-21 16:24:00 +0900 |
---|---|---|
committer | Mrutyunjay Sawant <msawant@nvidia.com> | 2013-09-03 06:53:05 -0700 |
commit | 75d0eb7e29ef0aa54b1543a7413345339f4125c1 (patch) | |
tree | 180e0809a364cc97596afe2bc4b55819b26d2d13 | |
parent | 1dbccea32f0df915157c99f4f493625461bb8923 (diff) |
staging: iio: adc: palmas: Add ADC reading with dual-current source for CH3
Added ADC reading with dual-current source for Channel3 in order to do series
resistance cancellation for thermal diode.
Bug 1287901
Signed-off-by: Jinyoung Park <jinyoungp@nvidia.com>
Reviewed-on: http://git-master/r/241375
(cherry picked from commit 3c809efe7325c6c24f03cf61a590d672bd495ff3)
Change-Id: Ifaf6ae6e293d66955f5c55d9c739af94a692a30e
Signed-off-by: Jinyoung Park <jinyoungp@nvidia.com>
Reviewed-on: http://git-master/r/252883
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
-rw-r--r-- | drivers/staging/iio/adc/palmas_gpadc.c | 183 | ||||
-rw-r--r-- | include/linux/mfd/palmas.h | 21 |
2 files changed, 129 insertions, 75 deletions
diff --git a/drivers/staging/iio/adc/palmas_gpadc.c b/drivers/staging/iio/adc/palmas_gpadc.c index 87665e8ab7aa..3535c6e170c4 100644 --- a/drivers/staging/iio/adc/palmas_gpadc.c +++ b/drivers/staging/iio/adc/palmas_gpadc.c @@ -83,8 +83,9 @@ static struct palmas_gpadc_info palmas_gpadc_info[] = { struct palmas_gpadc { struct device *dev; struct palmas *palmas; - u8 ich0; - u8 ich3; + u8 ch0_current; + u8 ch3_current; + bool ch3_dual_current; bool extended_delay; int irq; struct palmas_gpadc_info *adc_info; @@ -173,8 +174,10 @@ static int palmas_gpadc_enable(struct palmas_gpadc *adc, int adc_chan, mask = PALMAS_GPADC_CTRL1_CURRENT_SRC_CH0_MASK | PALMAS_GPADC_CTRL1_CURRENT_SRC_CH3_MASK | PALMAS_GPADC_CTRL1_GPADC_FORCE; - val = (adc->ich0 << PALMAS_GPADC_CTRL1_CURRENT_SRC_CH0_SHIFT) | - (adc->ich3 << PALMAS_GPADC_CTRL1_CURRENT_SRC_CH3_SHIFT); + val = (adc->ch0_current + << PALMAS_GPADC_CTRL1_CURRENT_SRC_CH0_SHIFT); + val |= (adc->ch3_current + << PALMAS_GPADC_CTRL1_CURRENT_SRC_CH3_SHIFT); val |= PALMAS_GPADC_CTRL1_GPADC_FORCE; ret = palmas_update_bits(adc->palmas, PALMAS_GPADC_BASE, PALMAS_GPADC_CTRL1, mask, val); @@ -212,19 +215,30 @@ static int palmas_gpadc_enable(struct palmas_gpadc *adc, int adc_chan, return 0; } -static int palmas_gpadc_start_convertion(struct palmas_gpadc *adc, int adc_chan) +static int palmas_gpadc_set_current_src(struct palmas_gpadc *adc, + int ch0_current, int ch3_current) { - unsigned int adc_l; - unsigned int adc_h; + unsigned int val, mask; int ret; - ret = palmas_gpadc_enable(adc, adc_chan, true); - if (ret < 0) + mask = PALMAS_GPADC_CTRL1_CURRENT_SRC_CH0_MASK | + PALMAS_GPADC_CTRL1_CURRENT_SRC_CH3_MASK; + val = (ch0_current << PALMAS_GPADC_CTRL1_CURRENT_SRC_CH0_SHIFT) | + (ch3_current << PALMAS_GPADC_CTRL1_CURRENT_SRC_CH3_SHIFT); + ret = palmas_update_bits(adc->palmas, PALMAS_GPADC_BASE, + PALMAS_GPADC_CTRL1, mask, val); + if (ret < 0) { + dev_err(adc->dev, "CTRL1 update failed: %d\n", ret); return ret; + } - ret = palmas_gpadc_start_mask_interrupt(adc, 0); - if (ret < 0) - return ret; + return 0; +} + +static int palmas_gpadc_start_convertion(struct palmas_gpadc *adc, int adc_chan) +{ + unsigned int val; + int ret; INIT_COMPLETION(adc->conv_completion); ret = palmas_update_bits(adc->palmas, PALMAS_GPADC_BASE, @@ -233,7 +247,7 @@ static int palmas_gpadc_start_convertion(struct palmas_gpadc *adc, int adc_chan) PALMAS_GPADC_SW_SELECT_SW_START_CONV0); if (ret < 0) { dev_err(adc->dev, "ADC_SW_START write failed: %d\n", ret); - goto scrub; + return ret; } ret = wait_for_completion_timeout(&adc->conv_completion, @@ -241,44 +255,25 @@ static int palmas_gpadc_start_convertion(struct palmas_gpadc *adc, int adc_chan) if (ret == 0) { dev_err(adc->dev, "ADC conversion not completed\n"); ret = -ETIMEDOUT; - goto scrub; - } - - ret = palmas_read(adc->palmas, PALMAS_GPADC_BASE, - PALMAS_GPADC_SW_CONV0_LSB, &adc_l); - if (ret < 0) { - dev_err(adc->dev, "ADCDATAL read failed: %d\n", ret); - goto scrub; + return ret; } - ret = palmas_read(adc->palmas, PALMAS_GPADC_BASE, - PALMAS_GPADC_SW_CONV0_MSB, &adc_h); + ret = palmas_bulk_read(adc->palmas, PALMAS_GPADC_BASE, + PALMAS_GPADC_SW_CONV0_LSB, &val, 2); if (ret < 0) { - dev_err(adc->dev, "ADCDATAH read failed: %d\n", ret); - goto scrub; + dev_err(adc->dev, "ADCDATA read failed: %d\n", ret); + return ret; } - ret = ((adc_h & 0xF) << 8) | adc_l; - -scrub: - palmas_gpadc_enable(adc, adc_chan, false); - palmas_gpadc_start_mask_interrupt(adc, 1); + ret = (val & 0xFFF); return ret; } static int palmas_gpadc_get_calibrated_code(struct palmas_gpadc *adc, - int adc_chan) + int adc_chan, int val) { - int ret; - s64 code; + s64 code = val * PRECISION_MULTIPLIER; - ret = palmas_gpadc_start_convertion(adc, adc_chan); - if (ret < 0) { - dev_err(adc->dev, "ADC start coversion failed\n"); - return ret; - } - - code = ret * PRECISION_MULTIPLIER; if ((code - adc->adc_info[adc_chan].offset) < 0) { dev_err(adc->dev, "No Input Connected\n"); return 0; @@ -286,10 +281,10 @@ static int palmas_gpadc_get_calibrated_code(struct palmas_gpadc *adc, if (!(adc->adc_info[adc_chan].is_correct_code)) { code -= adc->adc_info[adc_chan].offset; - ret = div_s64(code, adc->adc_info[adc_chan].gain); + val = div_s64(code, adc->adc_info[adc_chan].gain); } - return ret; + return val; } static int palmas_gpadc_read_raw(struct iio_dev *indio_dev, @@ -299,37 +294,69 @@ static int palmas_gpadc_read_raw(struct iio_dev *indio_dev, int ret; int adc_chan = chan->channel; - if (chan->channel > PALMAS_ADC_CH_MAX) + if (adc_chan > PALMAS_ADC_CH_MAX) return -EINVAL; switch (mask) { case 0: + case IIO_CHAN_INFO_CALIBSCALE: mutex_lock(&indio_dev->mlock); + ret = palmas_gpadc_enable(adc, adc_chan, true); + if (ret < 0) + goto out_unlock; + + ret = palmas_gpadc_start_mask_interrupt(adc, 0); + if (ret < 0) + goto out_disable; + ret = palmas_gpadc_start_convertion(adc, adc_chan); if (ret < 0) { dev_err(adc->dev, "ADC start coversion failed\n"); - mutex_unlock(&indio_dev->mlock); - return ret; + goto out_mask_interrupt; } - *val = ret; - mutex_unlock(&indio_dev->mlock); - return IIO_VAL_INT; - case IIO_CHAN_INFO_CALIBSCALE: - mutex_lock(&indio_dev->mlock); - ret = palmas_gpadc_get_calibrated_code(adc, adc_chan); - if (ret < 0) { - dev_err(adc->dev, "get_corrected_code failed\n"); - mutex_unlock(&indio_dev->mlock); - return ret; + if (mask == IIO_CHAN_INFO_CALIBSCALE) + *val = palmas_gpadc_get_calibrated_code(adc, adc_chan, + ret); + else + *val = ret; + + if ((adc_chan == PALMAS_ADC_CH_IN3) && adc->ch3_dual_current + && val2) { + ret = palmas_gpadc_set_current_src(adc, + adc->ch0_current, adc->ch3_current + 1); + if (ret < 0) { + dev_err(adc->dev, "Current src set failed\n"); + goto out_mask_interrupt; + } + + ret = palmas_gpadc_start_convertion(adc, adc_chan); + if (ret < 0) { + dev_err(adc->dev, + "ADC start coversion failed\n"); + goto out_mask_interrupt; + } + + if (mask == IIO_CHAN_INFO_CALIBSCALE) + *val2 = palmas_gpadc_get_calibrated_code(adc, + adc_chan, ret); + else + *val2 = ret; } - *val = ret; - mutex_unlock(&indio_dev->mlock); - return IIO_VAL_INT; + ret = IIO_VAL_INT; + goto out_mask_interrupt; } return -EINVAL; + +out_mask_interrupt: + palmas_gpadc_start_mask_interrupt(adc, 1); +out_disable: + palmas_gpadc_enable(adc, adc_chan, false); +out_unlock: + mutex_unlock(&indio_dev->mlock); + return ret; } static const struct iio_info palmas_gpadc_iio_info = { @@ -413,23 +440,33 @@ static int __devinit palmas_gpadc_probe(struct platform_device *pdev) goto out_unregister_map; } - if (adc_pdata->channel0_current_uA == 0) - adc->ich0 = 0; - else if (adc_pdata->channel0_current_uA <= 5) - adc->ich0 = 1; - else if (adc_pdata->channel0_current_uA <= 15) - adc->ich0 = 2; + if (adc_pdata->ch0_current_uA == 0) + adc->ch0_current = PALMAS_ADC_CH0_CURRENT_SRC_0; + else if (adc_pdata->ch0_current_uA <= 5) + adc->ch0_current = PALMAS_ADC_CH0_CURRENT_SRC_5; + else if (adc_pdata->ch0_current_uA <= 15) + adc->ch0_current = PALMAS_ADC_CH0_CURRENT_SRC_15; else - adc->ich0 = 3; - - if (adc_pdata->channel3_current_uA == 0) - adc->ich3 = 0; - else if (adc_pdata->channel3_current_uA <= 10) - adc->ich3 = 1; - else if (adc_pdata->channel3_current_uA <= 400) - adc->ich3 = 2; + adc->ch0_current = PALMAS_ADC_CH0_CURRENT_SRC_20; + + if (adc_pdata->ch3_current_uA == 0) + adc->ch3_current = PALMAS_ADC_CH3_CURRENT_SRC_0; + else if (adc_pdata->ch3_current_uA <= 10) + adc->ch3_current = PALMAS_ADC_CH3_CURRENT_SRC_10; + else if (adc_pdata->ch3_current_uA <= 400) + adc->ch3_current = PALMAS_ADC_CH3_CURRENT_SRC_400; else - adc->ich3 = 3; + adc->ch3_current = PALMAS_ADC_CH3_CURRENT_SRC_800; + + /* If ch3_dual_current is true, it will measure ch3 input signal with + * ch3_current and the next current of ch3_current. */ + adc->ch3_dual_current = adc_pdata->ch3_dual_current; + if (adc->ch3_dual_current && + (adc->ch3_current == PALMAS_ADC_CH3_CURRENT_SRC_800)) { + dev_warn(adc->dev, + "Disable ch3_dual_current by wrong current setting\n"); + adc->ch3_dual_current = false; + } adc->extended_delay = adc_pdata->extended_delay; diff --git a/include/linux/mfd/palmas.h b/include/linux/mfd/palmas.h index 3d6837ce6bd8..d903336422ad 100644 --- a/include/linux/mfd/palmas.h +++ b/include/linux/mfd/palmas.h @@ -207,8 +207,9 @@ struct palmas_rtc_platform_data { }; struct palmas_gpadc_platform_data { - int channel0_current_uA; - int channel3_current_uA; + int ch0_current_uA; /* 0uA, 5uA, 15uA, 20uA */ + int ch3_current_uA; /* 0uA, 10uA, 400uA, 800uA */ + bool ch3_dual_current; bool extended_delay; struct iio_map *iio_maps; @@ -2807,6 +2808,22 @@ enum { PALMAS_ADC_CH_MAX, }; +/* Palma GPADC Channel0 Current Source */ +enum { + PALMAS_ADC_CH0_CURRENT_SRC_0, + PALMAS_ADC_CH0_CURRENT_SRC_5, + PALMAS_ADC_CH0_CURRENT_SRC_15, + PALMAS_ADC_CH0_CURRENT_SRC_20, +}; + +/* Palma GPADC Channel3 Current Source */ +enum { + PALMAS_ADC_CH3_CURRENT_SRC_0, + PALMAS_ADC_CH3_CURRENT_SRC_10, + PALMAS_ADC_CH3_CURRENT_SRC_400, + PALMAS_ADC_CH3_CURRENT_SRC_800, +}; + /* Palma Sleep requestor IDs IDs */ enum { PALMAS_SLEEP_REQSTR_ID_REGEN1, |