summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJinyoung Park <jinyoungp@nvidia.com>2013-11-29 15:15:32 +0900
committerHarry Hong <hhong@nvidia.com>2013-12-01 22:13:14 -0800
commit6eda6ac9291fad2c5c11340f06263cc99411c670 (patch)
treee5ac85ca9cdf08fe2bf62191e34e2e63ab69009e
parentcd6f59a1958fda8475b8e4beaf6b845df4658249 (diff)
iio: staging: adc: palmas: Support for auto conversion shutdown
Support for auto conversion shutdown when auto conversion result is crossed threshold. Bug 1366274 Change-Id: Ib0037e4a6faedbe820c70c6155a35f2e6943caae Signed-off-by: Jinyoung Park <jinyoungp@nvidia.com> Reviewed-on: http://git-master/r/336848 Reviewed-by: Harry Hong <hhong@nvidia.com> Tested-by: Harry Hong <hhong@nvidia.com>
-rw-r--r--drivers/staging/iio/adc/palmas_gpadc.c284
-rw-r--r--include/linux/mfd/palmas.h2
2 files changed, 157 insertions, 129 deletions
diff --git a/drivers/staging/iio/adc/palmas_gpadc.c b/drivers/staging/iio/adc/palmas_gpadc.c
index 8a0c7bd6c5e6..47395a4f844a 100644
--- a/drivers/staging/iio/adc/palmas_gpadc.c
+++ b/drivers/staging/iio/adc/palmas_gpadc.c
@@ -174,6 +174,149 @@ static irqreturn_t palmas_gpadc_irq_auto(int irq, void *data)
return IRQ_HANDLED;
}
+static int palmas_gpadc_auto_conv_configure(struct palmas_gpadc *adc)
+{
+ int adc_period, conv;
+ int i;
+ int ch0 = 0, ch1 = 0;
+ int thres;
+ int ret;
+
+ adc_period = adc->auto_conversion_period;
+ for (i = 0; i < 16; ++i) {
+ if (((1000 * (1 << i))/32) > adc_period)
+ break;
+ }
+ if (i > 0)
+ i--;
+ adc_period = i;
+ ret = palmas_update_bits(adc->palmas, PALMAS_GPADC_BASE,
+ PALMAS_GPADC_AUTO_CTRL,
+ PALMAS_GPADC_AUTO_CTRL_COUNTER_CONV_MASK,
+ adc_period);
+ if (ret < 0) {
+ dev_err(adc->dev, "AUTO_CTRL write failed: %d\n", ret);
+ return ret;
+ }
+
+ conv = 0;
+ if (adc->auto_conv1_enable) {
+ int is_high;
+
+ ch0 = adc->auto_conv1_data.adc_channel_number;
+ conv |= PALMAS_GPADC_AUTO_CTRL_AUTO_CONV0_EN;
+ conv |= (adc->auto_conv1_data.adc_shutdown ?
+ PALMAS_GPADC_AUTO_CTRL_SHUTDOWN_CONV0 : 0);
+ if (adc->auto_conv1_data.adc_high_threshold > 0) {
+ thres = adc->auto_conv1_data.adc_high_threshold;
+ is_high = 0;
+ } else {
+ thres = adc->auto_conv1_data.adc_low_threshold;
+ is_high = BIT(7);
+ }
+
+ ret = palmas_write(adc->palmas, PALMAS_GPADC_BASE,
+ PALMAS_GPADC_THRES_CONV0_LSB, thres & 0xFF);
+ if (ret < 0) {
+ dev_err(adc->dev,
+ "THRES_CONV0_LSB write failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = palmas_write(adc->palmas, PALMAS_GPADC_BASE,
+ PALMAS_GPADC_THRES_CONV0_MSB,
+ ((thres >> 8) & 0xF) | is_high);
+ if (ret < 0) {
+ dev_err(adc->dev,
+ "THRES_CONV0_MSB write failed: %d\n", ret);
+ return ret;
+ }
+ }
+
+ if (adc->auto_conv2_enable) {
+ int is_high;
+
+ ch1 = adc->auto_conv2_data.adc_channel_number;
+ conv |= PALMAS_GPADC_AUTO_CTRL_AUTO_CONV1_EN;
+ conv |= (adc->auto_conv2_data.adc_shutdown ?
+ PALMAS_GPADC_AUTO_CTRL_SHUTDOWN_CONV1 : 0);
+ if (adc->auto_conv2_data.adc_high_threshold > 0) {
+ thres = adc->auto_conv2_data.adc_high_threshold;
+ is_high = 0;
+ } else {
+ thres = adc->auto_conv2_data.adc_low_threshold;
+ is_high = BIT(7);
+ }
+
+ ret = palmas_write(adc->palmas, PALMAS_GPADC_BASE,
+ PALMAS_GPADC_THRES_CONV1_LSB, thres & 0xFF);
+ if (ret < 0) {
+ dev_err(adc->dev,
+ "THRES_CONV1_LSB write failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = palmas_write(adc->palmas, PALMAS_GPADC_BASE,
+ PALMAS_GPADC_THRES_CONV1_MSB,
+ ((thres >> 8) & 0xF) | is_high);
+ if (ret < 0) {
+ dev_err(adc->dev,
+ "THRES_CONV1_MSB write failed: %d\n", ret);
+ return ret;
+ }
+ }
+
+ ret = palmas_write(adc->palmas, PALMAS_GPADC_BASE,
+ PALMAS_GPADC_AUTO_SELECT, (ch1 << 4) | ch0);
+ if (ret < 0) {
+ dev_err(adc->dev, "AUTO_SELECT write failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = palmas_update_bits(adc->palmas, PALMAS_GPADC_BASE,
+ PALMAS_GPADC_AUTO_CTRL,
+ PALMAS_GPADC_AUTO_CTRL_SHUTDOWN_CONV1 |
+ PALMAS_GPADC_AUTO_CTRL_SHUTDOWN_CONV0 |
+ PALMAS_GPADC_AUTO_CTRL_AUTO_CONV1_EN |
+ PALMAS_GPADC_AUTO_CTRL_AUTO_CONV0_EN, conv);
+ if (ret < 0) {
+ dev_err(adc->dev, "AUTO_CTRL write failed: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int palmas_gpadc_auto_conv_reset(struct palmas_gpadc *adc)
+{
+ int ret;
+
+ ret = palmas_write(adc->palmas, PALMAS_GPADC_BASE,
+ PALMAS_GPADC_AUTO_SELECT, 0);
+ if (ret < 0) {
+ dev_err(adc->dev, "AUTO_SELECT write failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = palmas_disable_auto_conversion(adc);
+ if (ret < 0) {
+ dev_err(adc->dev, "Disable auto conversion failed: %d\n", ret);
+ return ret;
+ }
+
+ if (adc->auto_conv1_data.adc_shutdown ||
+ adc->auto_conv2_data.adc_shutdown) {
+ ret = palmas_gpadc_auto_conv_configure(adc);
+ if (ret < 0) {
+ dev_err(adc->dev,
+ "auto conversion configure failed: %d\n", ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
static int palmas_gpadc_start_mask_interrupt(struct palmas_gpadc *adc, int mask)
{
int ret;
@@ -608,6 +751,16 @@ static int __devinit palmas_gpadc_probe(struct platform_device *pdev)
if (adc->auto_conv1_enable || adc->auto_conv2_enable)
device_wakeup_enable(&pdev->dev);
+ if (adc->auto_conv1_data.adc_shutdown ||
+ adc->auto_conv2_data.adc_shutdown) {
+ ret = palmas_gpadc_auto_conv_configure(adc);
+ if (ret < 0) {
+ dev_err(adc->dev,
+ "auto conversion configure failed: %d\n", ret);
+ goto out_irq_auto1_free;
+ }
+ }
+
return 0;
out_irq_auto1_free:
@@ -645,133 +798,6 @@ static int __devexit palmas_gpadc_remove(struct platform_device *pdev)
}
#ifdef CONFIG_PM_SLEEP
-static int palmas_adc_auto_conv_configure(struct palmas_gpadc *adc)
-{
- int adc_period, conv;
- int i;
- int ch0 = 0, ch1 = 0;
- int thres;
- int ret;
-
- adc_period = adc->auto_conversion_period;
- for (i = 0; i < 16; ++i) {
- if (((1000 * (1 << i))/32) > adc_period)
- break;
- }
- if (i > 0)
- i--;
- adc_period = i;
- ret = palmas_update_bits(adc->palmas, PALMAS_GPADC_BASE,
- PALMAS_GPADC_AUTO_CTRL,
- PALMAS_GPADC_AUTO_CTRL_COUNTER_CONV_MASK,
- adc_period);
- if (ret < 0) {
- dev_err(adc->dev, "AUTO_CTRL write failed: %d\n", ret);
- return ret;
- }
-
- conv = 0;
- if (adc->auto_conv1_enable) {
- int is_high;
-
- ch0 = adc->auto_conv1_data.adc_channel_number;
- conv |= PALMAS_GPADC_AUTO_CTRL_AUTO_CONV0_EN;
- if (adc->auto_conv1_data.adc_high_threshold > 0) {
- thres = adc->auto_conv1_data.adc_high_threshold;
- is_high = 0;
- } else {
- thres = adc->auto_conv1_data.adc_low_threshold;
- is_high = BIT(7);
- }
-
- ret = palmas_write(adc->palmas, PALMAS_GPADC_BASE,
- PALMAS_GPADC_THRES_CONV0_LSB, thres & 0xFF);
- if (ret < 0) {
- dev_err(adc->dev,
- "THRES_CONV0_LSB write failed: %d\n", ret);
- return ret;
- }
-
- ret = palmas_write(adc->palmas, PALMAS_GPADC_BASE,
- PALMAS_GPADC_THRES_CONV0_MSB,
- ((thres >> 8) & 0xF) | is_high);
- if (ret < 0) {
- dev_err(adc->dev,
- "THRES_CONV0_MSB write failed: %d\n", ret);
- return ret;
- }
- }
-
- if (adc->auto_conv2_enable) {
- int is_high;
-
- ch1 = adc->auto_conv2_data.adc_channel_number;
- conv |= PALMAS_GPADC_AUTO_CTRL_AUTO_CONV1_EN;
- if (adc->auto_conv2_data.adc_high_threshold > 0) {
- thres = adc->auto_conv2_data.adc_high_threshold;
- is_high = 0;
- } else {
- thres = adc->auto_conv2_data.adc_low_threshold;
- is_high = BIT(7);
- }
-
- ret = palmas_write(adc->palmas, PALMAS_GPADC_BASE,
- PALMAS_GPADC_THRES_CONV1_LSB, thres & 0xFF);
- if (ret < 0) {
- dev_err(adc->dev,
- "THRES_CONV1_LSB write failed: %d\n", ret);
- return ret;
- }
-
- ret = palmas_write(adc->palmas, PALMAS_GPADC_BASE,
- PALMAS_GPADC_THRES_CONV1_MSB,
- ((thres >> 8) & 0xF) | is_high);
- if (ret < 0) {
- dev_err(adc->dev,
- "THRES_CONV1_MSB write failed: %d\n", ret);
- return ret;
- }
- }
-
- ret = palmas_write(adc->palmas, PALMAS_GPADC_BASE,
- PALMAS_GPADC_AUTO_SELECT, (ch1 << 4) | ch0);
- if (ret < 0) {
- dev_err(adc->dev, "AUTO_SELECT write failed: %d\n", ret);
- return ret;
- }
-
- ret = palmas_update_bits(adc->palmas, PALMAS_GPADC_BASE,
- PALMAS_GPADC_AUTO_CTRL,
- PALMAS_GPADC_AUTO_CTRL_AUTO_CONV1_EN |
- PALMAS_GPADC_AUTO_CTRL_AUTO_CONV0_EN, conv);
- if (ret < 0) {
- dev_err(adc->dev, "AUTO_CTRL write failed: %d\n", ret);
- return ret;
- }
-
- return 0;
-}
-
-static int palmas_adc_auto_conv_reset(struct palmas_gpadc *adc)
-{
- int ret;
-
- ret = palmas_write(adc->palmas, PALMAS_GPADC_BASE,
- PALMAS_GPADC_AUTO_SELECT, 0);
- if (ret < 0) {
- dev_err(adc->dev, "AUTO_SELECT write failed: %d\n", ret);
- return ret;
- }
-
- ret = palmas_disable_auto_conversion(adc);
- if (ret < 0) {
- dev_err(adc->dev, "Disable auto conversion failed: %d\n", ret);
- return ret;
- }
-
- return 0;
-}
-
static int palmas_gpadc_suspend(struct device *dev)
{
struct iio_dev *iodev = dev_get_drvdata(dev);
@@ -782,7 +808,7 @@ static int palmas_gpadc_suspend(struct device *dev)
if (!device_may_wakeup(dev) || !wakeup)
return 0;
- ret = palmas_adc_auto_conv_configure(adc);
+ ret = palmas_gpadc_auto_conv_configure(adc);
if (ret < 0)
return ret;
@@ -805,7 +831,7 @@ static int palmas_gpadc_resume(struct device *dev)
if (!device_may_wakeup(dev) || !wakeup)
return 0;
- ret = palmas_adc_auto_conv_reset(adc);
+ ret = palmas_gpadc_auto_conv_reset(adc);
if (ret < 0)
return ret;
diff --git a/include/linux/mfd/palmas.h b/include/linux/mfd/palmas.h
index 973bdb58462d..bf9b56a6db0b 100644
--- a/include/linux/mfd/palmas.h
+++ b/include/linux/mfd/palmas.h
@@ -212,11 +212,13 @@ struct palmas_rtc_platform_data {
* @adc_channel_number: ADC channel number for monitoring.
* @adc_high_threshold: ADC High raw data for upper threshold to generate int.
* @adc_low_threshold: ADC low raw data for lower threshold to generate int.
+ * @adc_shutdown: Shutdown when interrupt generated.
*/
struct palmas_adc_auto_conv_property {
int adc_channel_number;
int adc_high_threshold;
int adc_low_threshold;
+ bool adc_shutdown;
};
struct palmas_gpadc_platform_data {