summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJinyoung Park <jinyoungp@nvidia.com>2013-06-21 16:24:00 +0900
committerMrutyunjay Sawant <msawant@nvidia.com>2013-09-03 06:53:05 -0700
commit75d0eb7e29ef0aa54b1543a7413345339f4125c1 (patch)
tree180e0809a364cc97596afe2bc4b55819b26d2d13
parent1dbccea32f0df915157c99f4f493625461bb8923 (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.c183
-rw-r--r--include/linux/mfd/palmas.h21
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,