]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
stagging: iio: adc: add as3722 iio support
authorBibek Basu <bbasu@nvidia.com>
Tue, 24 Jun 2014 10:42:03 +0000 (16:12 +0530)
committerLaxman Dewangan <ldewangan@nvidia.com>
Wed, 23 Jul 2014 06:15:14 +0000 (23:15 -0700)
Add support for iio to  as3722 adc-extcon driver.
ADC0 will be used by any consumer of iiodev to
get the data via any of the 22 adc channel.

Change-Id: Idca9cc2368d9bd9464906cbafb483f5f7fe9c8cb
Signed-off-by: Bibek Basu <bbasu@nvidia.com>
Reviewed-on: http://git-master/r/428716
Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com>
Tested-by: Laxman Dewangan <ldewangan@nvidia.com>
arch/arm/boot/dts/tegra124-platforms/tegra124-ardbeg-pmic-e1733-1000-a00.dtsi
arch/arm/boot/dts/tegra124-platforms/tegra124-jetson_tk1-pmic-pm375-0000-c00-00.dtsi
arch/arm/boot/dts/tegra124-platforms/tegra124-norrin-pmic-pm374-0000-a00.dtsi
arch/arm/boot/dts/tegra124-platforms/tegra124-pm359-pmic.dtsi
arch/arm64/boot/dts/tegra132-bowmore-e1973-1000-a01-00.dts
arch/arm64/boot/dts/tegra132-norrin-pm374-0001-common.dtsi
drivers/staging/iio/adc/as3722-adc-extcon.c
include/linux/mfd/as3722-plat.h
include/linux/mfd/as3722.h

index b11be0d1e4a461937ad47981fde335416e8aed1e..bad095b8b105b85ad36f59b5af63f6deb5968df1 100644 (file)
                        ams,major-rev = <1>;
                        ams,minor-rev = <2>;
                        ams,system-power-controller;
-                       #extcon-cells = <1>;
-                       ams,enable-adc1-continuous-mode;
-                       ams,enable-low-voltage-range;
-                       ams,adc-channel = <12>;
-                       ams,hi-threshold = <0x100>;
-                       ams,low-threshold = <0x80>;
                        ams,enable-clock32k-out;
 
                        pinctrl-names = "default";
                                };
                        };
 
+                       adc_extcon: adc_extcon {
+                               compatible = "ams,as3722-adc-extcon";
+                               ams,extcon-name = "as3722-extcon";
+                               ams,enable-adc1-continuous-mode;
+                               ams,enable-low-voltage-range;
+                               ams,adc-channel = <12>;
+                               ams,hi-threshold = <0x100>;
+                               ams,low-threshold = <0x80>;
+                               #extcon-cells = <1>;
+                               #io-channel-cells = <1>;
+                       };
+
                        regulators {
                                compatible = "ams,as3722";
                                ldo0-in-supply = <&as3722_sd2>;
index 11c894adf2a8430c4b51cfaccd064198dd678a10..74c7708c3106c77ea7100e7f0361541a2b46713b 100644 (file)
                        ams,major-rev = <1>;
                        ams,minor-rev = <2>;
                        ams,system-power-controller;
-                       #extcon-cells = <1>;
-                       ams,enable-adc1-continuous-mode;
-                       ams,enable-low-voltage-range;
-                       ams,adc-channel = <12>;
-                       ams,hi-threshold = <256>;
-                       ams,low-threshold = <128>;
                        ams,enable-clock32k-out;
                        ams,backup-battery-chargable;
                        ams,battery-backup-charge-current = <AS3722_BBCCUR_400UA>;
                                };
                        };
 
+                       adc_extcon: adc_extcon {
+                               compatible = "ams,as3722-adc-extcon";
+                               ams,extcon-name = "as3722-extcon";
+                               ams,enable-adc1-continuous-mode;
+                               ams,enable-low-voltage-range;
+                               ams,adc-channel = <12>;
+                               ams,hi-threshold = <256>;
+                               ams,low-threshold = <128>;
+                               #extcon-cells = <1>;
+                               #io-channel-cells = <1>;
+                       };
+
                        regulators {
                             compatible = "ams,as3722";
                             ldo0-in-supply = <&as3722_sd2>;
index 5939ede6fc92db770e3563c1d7296b316c3e90ea..9ffee69166600db91008fe438fca449589984539 100644 (file)
                        ams,major-rev = <1>;
                        ams,minor-rev = <1>;
                        system-pmic-power-off;
-                       #extcon-cells = <1>;
-
-                       ams,enable-adc1-continuous-mode;
-                       ams,enable-low-voltage-range;
-                       ams,adc-channel = <12>;
-                       ams,hi-threshold = <256>;
-                       ams,low-threshold = <128>;
                        ams,enable-clock32k-out;
                        ams,oc-pg-mask = <AS3722_OC_PG_MASK_AC_OK>;
 
                                };
                        };
 
+                       adc_extcon: adc_extcon {
+                               compatible = "ams,as3722-adc-extcon";
+                               ams,extcon-name = "as3722-extcon";
+                               ams,enable-adc1-continuous-mode;
+                               ams,enable-low-voltage-range;
+                               ams,adc-channel = <12>;
+                               ams,hi-threshold = <256>;
+                               ams,low-threshold = <128>;
+                               #extcon-cells = <1>;
+                               #io-channel-cells = <1>;
+                       };
+
                        regulators {
                                compatible = "ams,as3722";
                                ldo0-in-supply = <&as3722_sd2>;
index 3a5d5ae4148e76391f465b4c75cba04c82b8299c..7758e378f22136bfcca76c008bbe2ded19957d0f 100644 (file)
                        ams,major-rev = <1>;
                        ams,minor-rev = <2>;
                        ams,system-power-controller;
-                       #extcon-cells = <1>;
-
-                       ams,enable-adc1-continuous-mode;
-                       ams,enable-low-voltage-range;
-                       ams,adc-channel = <12>;
-                       ams,hi-threshold = <256>;
-                       ams,low-threshold = <128>;
                        ams,enable-clock32k-out;
 
                        pinctrl-names = "default";
                                };
                        };
 
+                       adc_extcon: adc_extcon {
+                               compatible = "ams,as3722-adc-extcon";
+                               ams,extcon-name = "as3722-extcon";
+                               ams,enable-adc1-continuous-mode;
+                               ams,enable-low-voltage-range;
+                               ams,adc-channel = <12>;
+                               ams,hi-threshold = <256>;
+                               ams,low-threshold = <128>;
+                               #extcon-cells = <1>;
+                               #io-channel-cells = <1>;
+                       };
+
                        regulators {
                             compatible = "ams,as3722";
                             ldo0-in-supply = <&as3722_sd2>;
index 93fd6f9c646b12de3b0b0a06ad0e8c483213494c..5b65d60053064a95b3633db305360214a19dac07 100644 (file)
 
        otg@7d000000 {
                nvidia,id-detection-type = <1>;
-               extcon-cables = <&as3722 0>;
+               extcon-cables = <&adc_extcon 0>;
                extcon-cable-names = "id";
                #extcon-cells = <1>;
                usb_vbus = <&usb0_vbus>;
index 2545e3ed31304b82063c4f59d27254b968fd4a87..b79266d9db8ec2a19cca6739376a87f7c3c1af2d 100644 (file)
 
        otg@7d000000 {
                nvidia,id-detection-type = <1>;
-               extcon-cables = <&as3722 0>;
+               extcon-cables = <&adc_extcon 0>;
                extcon-cable-names = "id";
                #extcon-cells = <1>;
                usb_vbus-supply = <&usb0_vbus>;
index 5a2207fbbc7c4e85cb94cf37d4406d1bfac57149..9626f82c93ebfa806f544a62f7533e4f3c66953d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * as3722-adc-extcon.c -- AMS AS3722 ADC EXTCON.
  *
- * Copyright (c) 2013, NVIDIA Corporation. All rights reserved.
+ * Copyright (c) 2013-2014, NVIDIA Corporation. All rights reserved.
  *
  * Author: Mallikarjun Kasoju<mkasoju@nvidia.com>
  * Author: Laxman Dewangan <ldewangan@nvidia.com>
 #include <linux/err.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
 #include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
 #include <linux/delay.h>
+#include <linux/i2c.h>
 #include <linux/pm.h>
 #include <linux/extcon.h>
 #include <linux/mfd/as3722.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/machine.h>
+#include <linux/iio/driver.h>
+
+#define AS3722_ADC_CHAN_IIO(chan)                                      \
+{                                                                      \
+       .datasheet_name = AS3722_DATASHEET_NAME(chan),                  \
+       .type = IIO_VOLTAGE,                                            \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),                   \
+       .indexed = 1,                                                   \
+       .channel = AS3722_ADC_CH_##chan,                                \
+}
+
+static const struct iio_chan_spec as3722_gpadc_iio_channel[] = {
+       AS3722_ADC_CHAN_IIO(SD0),
+       AS3722_ADC_CHAN_IIO(SD1),
+       AS3722_ADC_CHAN_IIO(SD6),
+       AS3722_ADC_CHAN_IIO(DTEMP),
+       AS3722_ADC_CHAN_IIO(VSUP),
+       AS3722_ADC_CHAN_IIO(GPIO1),
+       AS3722_ADC_CHAN_IIO(GPIO2),
+       AS3722_ADC_CHAN_IIO(GPIO3),
+       AS3722_ADC_CHAN_IIO(GPIO4),
+       AS3722_ADC_CHAN_IIO(GPIO6),
+       AS3722_ADC_CHAN_IIO(GPIO7),
+       AS3722_ADC_CHAN_IIO(VBAT),
+       AS3722_ADC_CHAN_IIO(ADC1),
+       AS3722_ADC_CHAN_IIO(ADC2),
+       AS3722_ADC_CHAN_IIO(TBD1),
+       AS3722_ADC_CHAN_IIO(TBD2),
+       AS3722_ADC_CHAN_IIO(T1SD0),
+       AS3722_ADC_CHAN_IIO(T2SD0),
+       AS3722_ADC_CHAN_IIO(T3SD0),
+       AS3722_ADC_CHAN_IIO(T4SD0),
+       AS3722_ADC_CHAN_IIO(TSD1),
+       AS3722_ADC_CHAN_IIO(T1SD6),
+       AS3722_ADC_CHAN_IIO(T2SD6),
+};
 
 struct as3722_adc {
-       struct device           *dev;
-       struct as3722           *as3722;
-       struct extcon_dev       edev;
-       int                     irq;
-       int                     hi_threshold;
-       int                     low_threshold;
+       struct device                           *dev;
+       struct as3722                           *as3722;
+       struct extcon_dev                       edev;
+       struct iio_map                          *iio_maps;
+       struct as3722_adc_auto_conv_property    auto_conv1_data;
+       int                                     irq;
 };
 
 const char *as3722_adc_excon_cable[] = {
@@ -46,12 +87,103 @@ const char *as3722_adc_excon_cable[] = {
        NULL,
 };
 
-static int as3722_read_adc1_cable_update(struct as3722_adc *adc)
+static int as3722_adc_start_conversion(struct as3722_adc *adc, int chan)
 {
        struct as3722 *as3722 = adc->as3722;
+       unsigned int val;
+       int ret;
+       int timeout = 10;
+
+       /* configure ADC0 */
+       ret = as3722_update_bits(as3722, AS3722_ADC0_CONTROL_REG,
+                       AS3722_ADC_MASK_SOURCE_SELECT,
+                       chan);
+       if (ret < 0) {
+               dev_err(adc->dev, "ADC0_CONTROL source select fail %d\n", ret);
+               return ret;
+       }
+       /* Start ADC */
+       ret = as3722_update_bits(as3722, AS3722_ADC0_CONTROL_REG,
+                               AS3722_ADC_MASK_CONV_START,
+                               AS3722_ADC_MASK_CONV_START);
+       if (ret < 0) {
+               dev_err(adc->dev, "ADC0_CONTROL write failed %d\n", ret);
+               return ret;
+       }
+
+       /* Wait for conversion */
+       do {
+               ret = as3722_read(as3722, AS3722_ADC0_MSB_RESULT_REG,
+                               &val);
+               if (ret < 0) {
+                       dev_err(adc->dev,
+                                       "Reg 0x%02x read failed: %d\n",
+                                       AS3722_ADC0_MSB_RESULT_REG, ret);
+                       return ret;
+               }
+               if (!(val & AS3722_ADC_MASK_CONV_NOTREADY))
+                       return 0;  /* result available */
+               udelay(100);
+       } while (--timeout > 0);
+
+       return -ETIMEDOUT;
+}
+
+
+static int as3722_adc_extcon_read_raw(struct iio_dev *iodev,
+       struct iio_chan_spec const *chan, int *val, int *val2, long mask)
+{
+       struct as3722_adc *adc = iio_priv(iodev);
+       struct as3722 *as3722 = adc->as3722;
+       int adc_chan = chan->channel;
        int result;
+       int ret = 0;
+
+       if (adc_chan > AS3722_ADC_CH_MAX)
+               return -EINVAL;
+
+       mutex_lock(&iodev->mlock);
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               ret = as3722_adc_start_conversion(adc, adc_chan);
+               if (ret < 0) {
+                       dev_err(adc->dev,
+                               "failed to start conversion %d\n", ret);
+                       break;
+               }
+               ret = as3722_read(as3722, AS3722_ADC0_MSB_RESULT_REG , &result);
+               if (ret < 0) {
+                       dev_err(adc->dev,
+                               "ADC1_MSB_RESULT read failed %d\n", ret);
+                       break;
+               }
+               *val = ((result & AS3722_ADC_MASK_MSB_VAL) << 3);
+               ret = as3722_read(as3722, AS3722_ADC0_LSB_RESULT_REG, &result);
+               if (ret < 0) {
+                       dev_err(adc->dev,
+                               "ADC1_LSB_RESULT read failed %d\n", ret);
+                       break;
+               }
+               *val |= result & AS3722_ADC_MASK_LSB_VAL;
+               ret = IIO_VAL_INT;
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+       mutex_unlock(&iodev->mlock);
+       return ret;
+}
+
+
+static int as3722_read_adc1_cable_update(struct as3722_adc *adc)
+{
+       struct as3722_adc_auto_conv_property *conv_prop =
+                                       &adc->auto_conv1_data;
+       struct as3722 *as3722 = adc->as3722;
+       int result, val;
        int ret;
-       u32 val;
 
        ret = as3722_read(as3722, AS3722_ADC1_MSB_RESULT_REG , &val);
        if (ret < 0) {
@@ -66,11 +198,10 @@ static int as3722_read_adc1_cable_update(struct as3722_adc *adc)
                return ret;
        }
        result |= val & AS3722_ADC_MASK_LSB_VAL;
-
-       if (result >= adc->hi_threshold) {
+       if (result >= conv_prop->hi_threshold) {
                extcon_set_cable_state(&adc->edev, "USB-Host", false);
                dev_info(adc->dev, "USB-Host is disconnected\n");
-       } else if (result <= adc->low_threshold) {
+       } else if (result <= conv_prop->low_threshold) {
                extcon_set_cable_state(&adc->edev, "USB-Host", true);
                dev_info(adc->dev, "USB-Host is connected\n");
        }
@@ -79,67 +210,21 @@ static int as3722_read_adc1_cable_update(struct as3722_adc *adc)
 
 static irqreturn_t as3722_adc_extcon_irq(int irq, void *data)
 {
-       struct as3722_adc *adc = data;
-
-       as3722_read_adc1_cable_update(adc);
+       as3722_read_adc1_cable_update(data);
        return IRQ_HANDLED;
 }
 
-static int as3722_adc_extcon_probe(struct platform_device *pdev)
+static int as3722_gpadc_configure(struct as3722_adc *adc)
 {
-       struct as3722 *as3722 = dev_get_drvdata(pdev->dev.parent);
-       struct as3722_platform_data *pdata = dev_get_platdata(pdev->dev.parent);
-       struct device_node *node = pdev->dev.parent->of_node;
-       struct as3722_adc_extcon_platform_data *extcon_pdata;
-       struct as3722_adc *adc;
-       int ret = 0;
-       unsigned int try_counter = 0;
-       u32 val;
-
-       if (node && !pdata) {
-               extcon_pdata = devm_kzalloc(&pdev->dev,
-                               sizeof(struct as3722_adc_extcon_platform_data),
-                                       GFP_KERNEL);
-               of_property_read_string(node, "ams,extcon-name",
-                                &extcon_pdata->connection_name);
-               extcon_pdata->enable_adc1_continuous_mode =
-                       of_property_read_bool(node,
-                                       "ams,enable-adc1-continuous-mode");
-               extcon_pdata->enable_low_voltage_range =
-                       of_property_read_bool(node,
-                                       "ams,enable-low-voltage-range");
-               of_property_read_u32(node, "ams,adc-channel",
-                               &extcon_pdata->adc_channel);
-               of_property_read_u32(node, "ams,hi-threshold",
-                               &extcon_pdata->hi_threshold);
-               of_property_read_u32(node, "ams,low-threshold",
-                               &extcon_pdata->low_threshold);
-       } else if (pdata && pdata->extcon_pdata)
-               extcon_pdata = pdata->extcon_pdata;
-       else {
-               dev_err(&pdev->dev, "no platform data available\n");
-               return -ENODEV;
-       }
-
-       adc = devm_kzalloc(&pdev->dev, sizeof(*adc), GFP_KERNEL);
-       if (!adc) {
-               dev_err(&pdev->dev, "Malloc adc failed\n");
-               return -ENOMEM;
-       }
-
-       adc->dev = &pdev->dev;
-       adc->as3722 = as3722;
-       dev_set_drvdata(&pdev->dev, adc);
-       adc->irq = platform_get_irq(pdev, 0);
-       adc->hi_threshold = extcon_pdata->hi_threshold;
-       adc->low_threshold = extcon_pdata->low_threshold;
-
-       if (!extcon_pdata->enable_adc1_continuous_mode)
-               goto skip_adc_config;
+       struct as3722_adc_auto_conv_property *conv_prop =
+                                       &adc->auto_conv1_data;
+       struct as3722 *as3722 = adc->as3722;
+       int ret;
+       int val;
 
        /* Set ADC threshold values */
        ret = as3722_write(as3722, AS3722_ADC1_THRESHOLD_HI_MSB_REG,
-                               (extcon_pdata->hi_threshold >> 3) & 0x7F);
+                               (conv_prop->hi_threshold >> 3) & 0x7F);
        if (ret < 0) {
                dev_err(adc->dev, "ADC1_THRESHOLD_HI_MSB write failed %d\n",
                                ret);
@@ -147,7 +232,7 @@ static int as3722_adc_extcon_probe(struct platform_device *pdev)
        }
 
        ret = as3722_write(as3722, AS3722_ADC1_THRESHOLD_HI_LSB_REG,
-                               (extcon_pdata->hi_threshold) & 0x7);
+                               (conv_prop->hi_threshold) & 0x7);
        if (ret < 0) {
                dev_err(adc->dev, "ADC1_THRESHOLD_HI_LSB write failed %d\n",
                                ret);
@@ -155,7 +240,7 @@ static int as3722_adc_extcon_probe(struct platform_device *pdev)
        }
 
        ret = as3722_write(as3722, AS3722_ADC1_THRESHOLD_LO_MSB_REG,
-                               (extcon_pdata->low_threshold >> 3) & 0x7F);
+                               (conv_prop->low_threshold >> 3) & 0x7F);
        if (ret < 0) {
                dev_err(adc->dev, "ADC1_THRESHOLD_LO_MSB write failed %d\n",
                                ret);
@@ -163,7 +248,7 @@ static int as3722_adc_extcon_probe(struct platform_device *pdev)
        }
 
        ret = as3722_write(as3722, AS3722_ADC1_THRESHOLD_LO_LSB_REG,
-                               (extcon_pdata->low_threshold) & 0x7);
+                               (conv_prop->low_threshold) & 0x7);
        if (ret < 0) {
                dev_err(adc->dev, "ADC1_THRESHOLD_LO_LSB write failed %d\n",
                                ret);
@@ -171,25 +256,111 @@ static int as3722_adc_extcon_probe(struct platform_device *pdev)
        }
 
        /* Configure adc1 */
-       val = (extcon_pdata->adc_channel & 0x1F) |
-                       AS3722_ADC1_INTEVAL_SCAN_MASK;
-       if (extcon_pdata->enable_low_voltage_range)
-               val |= AS3722_ADC1_LOW_VOLTAGE_RANGE_MASK;
+       val = (conv_prop->adc_channel & AS3722_ADC_MASK_SOURCE_SELECT) |
+                       AS3722_ADC1_MASK_INTEVAL_SCAN;
+       if (conv_prop->enable_low_voltage_range)
+               val |= AS3722_ADC_MASK_LOW_VOLTAGE_RANGE;
        ret = as3722_write(as3722, AS3722_ADC1_CONTROL_REG, val);
        if (ret < 0) {
                dev_err(adc->dev, "ADC1_CONTROL write failed %d\n", ret);
                return ret;
        }
+       return 0;
+
+}
+
+static int as3722_gpadc_get_adc_dt_data(struct platform_device *pdev,
+       struct as3722_adc *adc)
+{
+       struct device_node *node;
+       struct as3722_adc_auto_conv_property *conv_prop = &adc->auto_conv1_data;
+
+       node = of_get_child_by_name(pdev->dev.parent->of_node, "adc_extcon");
+       if (!node) {
+               dev_err(&pdev->dev, "Device is not having adc_extcon node\n");
+               return -ENODEV;
+       }
+       pdev->dev.of_node = node;
+       of_property_read_string(node, "ams,extcon-name",
+                       &conv_prop->connection_name);
+       conv_prop->enable_adc1_continuous_mode =
+               of_property_read_bool(node,
+                               "ams,enable-adc1-continuous-mode");
+       conv_prop->enable_low_voltage_range =
+               of_property_read_bool(node,
+                               "ams,enable-low-voltage-range");
+       of_property_read_u32(node, "ams,adc-channel",
+                       &conv_prop->adc_channel);
+       of_property_read_u32(node, "ams,hi-threshold",
+                       &conv_prop->hi_threshold);
+       of_property_read_u32(node, "ams,low-threshold",
+                       &conv_prop->low_threshold);
+
+       return 0;
+}
+
+static const struct iio_info as3722_gpadc_iio_info = {
+       .read_raw = as3722_adc_extcon_read_raw,
+       .driver_module = THIS_MODULE,
+};
+
+static int as3722_adc_extcon_probe(struct platform_device *pdev)
+{
+       struct as3722 *as3722 = dev_get_drvdata(pdev->dev.parent);
+       struct as3722_platform_data *pdata = dev_get_platdata(pdev->dev.parent);
+       struct as3722_adc *adc;
+       struct iio_dev *iodev;
+       unsigned int try_counter = 0;
+       int val;
+       int ret = 0;
+
+       iodev = iio_device_alloc(sizeof(*adc));
+       if (!iodev) {
+               dev_err(&pdev->dev, "iio_device_alloc failed\n");
+               return -ENOMEM;
+       }
+       adc = iio_priv(iodev);
+       ret = as3722_gpadc_get_adc_dt_data(pdev, adc);
+       if (ret  < 0) {
+               if (pdata && pdata->extcon_pdata)
+                       adc->auto_conv1_data =
+                               pdata->extcon_pdata->adc1_auto_conv_data;
+               else {
+                       dev_err(&pdev->dev, "no platform data available\n");
+                       return -ENODEV;
+               }
+       }
+
+       adc->dev = &pdev->dev;
+       adc->as3722 = as3722;
+       dev_set_drvdata(&pdev->dev, iodev);
+       adc->irq = platform_get_irq(pdev, 0);
+       if (adc->iio_maps) {
+               ret = iio_map_array_register(iodev, adc->iio_maps);
+               if (ret < 0) {
+                       dev_err(&pdev->dev, "iio_map_array_register failed\n");
+                       goto out;
+               }
+       }
+
+       if (!adc->auto_conv1_data.enable_adc1_continuous_mode)
+               goto skip_adc_config;
+
+       ret = as3722_gpadc_configure(adc);
+       if (ret < 0) {
+               dev_err(&pdev->dev,
+                       "adc1 extcon property setting failed %d\n", ret);
+               goto out;
+       }
 
        /* Start ADC */
        ret = as3722_update_bits(as3722, AS3722_ADC1_CONTROL_REG,
-                               AS3722_ADC1_CONVERSION_START_MASK,
-                               AS3722_ADC1_CONVERSION_START_MASK);
+                                       AS3722_ADC_MASK_CONV_START,
+                                       AS3722_ADC_MASK_CONV_START);
        if (ret < 0) {
                dev_err(adc->dev, "ADC1_CONTROL write failed %d\n", ret);
                return ret;
        }
-
        /* Wait for 1 conversion */
        do {
                ret = as3722_read(as3722, AS3722_ADC1_MSB_RESULT_REG ,
@@ -199,20 +370,19 @@ static int as3722_adc_extcon_probe(struct platform_device *pdev)
                                ret);
                        return ret;
                }
-               if (!(val & AS3722_ADC1_MASK_CONV_NOTREADY))
+               if (!(val & AS3722_ADC_MASK_CONV_NOTREADY))
                        break;
                udelay(500);
        } while (try_counter++ < 10);
-
-       adc->edev.name = (extcon_pdata->connection_name) ?
-                               extcon_pdata->connection_name : pdev->name;
+       adc->edev.name = (adc->auto_conv1_data.connection_name) ?
+                       adc->auto_conv1_data.connection_name : pdev->name;
        adc->edev.dev.parent = &pdev->dev;
        adc->edev.supported_cable = as3722_adc_excon_cable;
-       adc->edev.node = node;
+       adc->edev.node = pdev->dev.of_node;
        ret = extcon_dev_register(&adc->edev);
        if (ret < 0) {
                dev_err(&pdev->dev, "extcon dev register failed %d\n", ret);
-               return ret;
+               goto out;
        }
 
        /* Read ADC result */
@@ -223,12 +393,24 @@ static int as3722_adc_extcon_probe(struct platform_device *pdev)
        }
 
        ret = as3722_update_bits(as3722, AS3722_ADC1_CONTROL_REG,
-               AS3722_ADC1_INTEVAL_SCAN_MASK, AS3722_ADC1_INTEVAL_SCAN_MASK);
+               AS3722_ADC1_MASK_INTEVAL_SCAN, AS3722_ADC1_MASK_INTEVAL_SCAN);
        if (ret < 0) {
                dev_err(adc->dev, "ADC1 INTEVAL_SCAN set failed: %d\n", ret);
                goto scrub_edev;
        }
 
+       iodev->name = "as3722-adc-extcon";
+       iodev->dev.parent = &pdev->dev;
+       iodev->info = &as3722_gpadc_iio_info;
+       iodev->modes = INDIO_DIRECT_MODE;
+       iodev->channels = as3722_gpadc_iio_channel;
+       iodev->num_channels = ARRAY_SIZE(as3722_gpadc_iio_channel);
+
+       ret = iio_device_register(iodev);
+       if (ret < 0) {
+               dev_err(adc->dev, "iio_device_register() failed: %d\n", ret);
+               goto scrub_edev;
+       }
        ret = request_threaded_irq(adc->irq, NULL, as3722_adc_extcon_irq,
                IRQF_ONESHOT | IRQF_EARLY_RESUME, dev_name(adc->dev),
                adc);
@@ -243,29 +425,38 @@ skip_adc_config:
 
 stop_adc1:
        as3722_update_bits(as3722, AS3722_ADC1_CONTROL_REG,
-                       AS3722_ADC1_CONVERSION_START_MASK, 0);
+                       AS3722_ADC_MASK_CONV_START, 0);
+       iio_device_unregister(iodev);
 scrub_edev:
        extcon_dev_unregister(&adc->edev);
 
+out:
+       iio_device_free(iodev);
        return ret;
 }
 
 static int as3722_adc_extcon_remove(struct platform_device *pdev)
 {
-       struct as3722_adc *adc = dev_get_drvdata(&pdev->dev);
+       struct iio_dev *iodev = dev_get_drvdata(&pdev->dev);
+       struct as3722_adc *adc = iio_priv(iodev);
        struct as3722 *as3722 = adc->as3722;
 
        as3722_update_bits(as3722, AS3722_ADC1_CONTROL_REG,
-                       AS3722_ADC1_CONVERSION_START_MASK, 0);
+                       AS3722_ADC_MASK_CONV_START, 0);
        extcon_dev_unregister(&adc->edev);
+       if (adc->iio_maps)
+               iio_map_array_unregister(iodev);
+       iio_device_unregister(iodev);
        free_irq(adc->irq, adc);
+       iio_device_free(iodev);
        return 0;
 }
 
 #ifdef CONFIG_PM_SLEEP
 static int as3722_adc_extcon_suspend(struct device *dev)
 {
-       struct as3722_adc *adc = dev_get_drvdata(dev);
+       struct iio_dev *iodev = dev_get_drvdata(dev);
+       struct as3722_adc *adc = iio_priv(iodev);
 
        if (device_may_wakeup(dev))
                enable_irq_wake(adc->irq);
@@ -275,7 +466,8 @@ static int as3722_adc_extcon_suspend(struct device *dev)
 
 static int as3722_adc_extcon_resume(struct device *dev)
 {
-       struct as3722_adc *adc = dev_get_drvdata(dev);
+       struct iio_dev *iodev = dev_get_drvdata(dev);
+       struct as3722_adc *adc = iio_priv(iodev);
 
        if (device_may_wakeup(dev))
                disable_irq_wake(adc->irq);
@@ -315,5 +507,6 @@ module_exit(as3722_adc_extcon_exit);
 MODULE_DESCRIPTION("as3722 ADC extcon driver");
 MODULE_AUTHOR("Mallikarjun Kasoju <mkasoju@nvidia.com>");
 MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
+MODULE_AUTHOR("Bibek Basu <bbasu@nvidia.com>");
 MODULE_ALIAS("platform:as3722-adc-extcon");
 MODULE_LICENSE("GPL v2");
index 701757898a6f7905449d0274d627f8a81e0eaf34..8263b2f50db342ff40c71a5732d39a49fc607de4 100644 (file)
@@ -139,16 +139,28 @@ struct as3722_regulator_platform_data {
 };
 
 /*
- * as3722_adc_extcon_platform_data: ADC platform data.
- * @connection_name: Extcon connection name.
+ * ADC auto conv property: Generate auto conv interrupt when threshold crossed.
+ * @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 as3722_adc_extcon_platform_data {
-       const char *connection_name;
-       bool enable_adc1_continuous_mode;
-       bool enable_low_voltage_range;
+struct as3722_adc_auto_conv_property {
        int adc_channel;
        int hi_threshold;
        int low_threshold;
+       int auto_conversion_period_ms;
+       const char *connection_name;
+       bool enable_adc1_continuous_mode;
+       bool enable_low_voltage_range;
+};
+
+/*
+ * as3722_adc_extcon_platform_data: ADC platform data.
+ * @auto conv property: Generate auto conv interrupt when threshold crossed.
+ */
+struct as3722_adc_extcon_platform_data {
+       struct as3722_adc_auto_conv_property adc1_auto_conv_data;
 };
 
 struct as3722_platform_data {
index a37e57412da808144fd9a5a8154bcb2501f29b22..76295aa8bc2e2e05514a06ee5b5bffe9d36f7161 100644 (file)
 #define AS3722_INTERRUPT_MASK4_OCCUR_ALARM_SD6         BIT(6)
 #define AS3722_INTERRUPT_MASK4_ADC                     BIT(7)
 
-#define AS3722_ADC1_INTERVAL_TIME                      BIT(0)
-#define AS3722_ADC1_INT_MODE_ON                                BIT(1)
-#define AS3722_ADC_BUF_ON                              BIT(2)
-#define AS3722_ADC1_LOW_VOLTAGE_RANGE                  BIT(5)
-#define AS3722_ADC1_INTEVAL_SCAN                       BIT(6)
-#define AS3722_ADC1_INT_MASK                           BIT(7)
-
-#define AS3722_ADC_MSB_VAL_MASK                                0x7F
-#define AS3722_ADC_LSB_VAL_MASK                                0x07
-
-#define AS3722_ADC0_CONV_START                         BIT(7)
-#define AS3722_ADC0_CONV_NOTREADY                      BIT(7)
-#define AS3722_ADC0_SOURCE_SELECT_MASK                 0x1F
-
-#define AS3722_ADC1_CONV_START                         BIT(7)
-#define AS3722_ADC1_CONV_NOTREADY                      BIT(7)
-#define AS3722_ADC1_SOURCE_SELECT_MASK                 0x1F
+#define AS3722_ADC1_MASK_INTERVAL_TIME                 BIT(0)
+#define AS3722_ADC1_MASK_INT_MODE_ON                   BIT(1)
+#define AS3722_ADC_MASK_BUF_ON                         BIT(2)
+#define AS3722_ADC_MASK_LOW_VOLTAGE_RANGE              BIT(5)
+#define AS3722_ADC1_MASK_INTEVAL_SCAN                  BIT(6)
+#define AS3722_ADC_MASK_CONV_START                     BIT(7)
+#define AS3722_ADC_MASK_CONV_NOTREADY                  BIT(7)
+#define AS3722_ADC_MASK_SOURCE_SELECT                  0x1F
+#define AS3722_ADC_MASK_MSB_VAL                                0x7F
+#define AS3722_ADC_MASK_LSB_VAL                                0x07
 
 /* GPIO modes */
 #define AS3722_GPIO_MODE_MASK                          0x07
 #define AS3722_EXT_CONTROL_ENABLE2                     0x2
 #define AS3722_EXT_CONTROL_ENABLE3                     0x3
 
-#define AS3722_ADC1_MASK_CONV_START                    BIT(7)
-#define AS3722_ADC1_BIT_CONV_START                     BIT(7)
-#define AS3722_ADC1_MASK_CONV_NOTREADY                 BIT(7)
-#define AS3722_ADC1_BIT_CONV_NOTREADY                  BIT(7)
-#define AS3722_ADC1_MASK_SOURCE_SELECT                 0x1F
-
-#define AS3722_ADC_MASK_MSB_VAL                                0x7F
-#define AS3722_ADC_MASK_LSB_VAL                                0x07
-
-#define AS3722_ADC1_LOW_VOLTAGE_RANGE_MASK             BIT(5)
-#define AS3722_ADC1_INTEVAL_SCAN_MASK                  BIT(6)
-#define AS3722_ADC1_CONVERSION_START_MASK              BIT(7)
-
 #define AS3722_CTRL_SEQ1_AC_OK_PWR_ON                  BIT(0)
 
 #define AS3722_BBCCUR_MASK                             0x18
@@ -521,4 +501,41 @@ static inline bool as3722_device_rev_eq_later(struct as3722 *as3722,
 
        return true;
 }
+
+/* as3722 adc channel */
+enum {
+       AS3722_ADC_CH_SD0,
+       AS3722_ADC_CH_SD1,
+       AS3722_ADC_CH_SD6,
+       AS3722_ADC_CH_DTEMP,
+       AS3722_ADC_CH_VSUP,
+       AS3722_ADC_CH_GPIO1,
+       AS3722_ADC_CH_GPIO2,
+       AS3722_ADC_CH_GPIO3,
+       AS3722_ADC_CH_GPIO4,
+       AS3722_ADC_CH_GPIO6,
+       AS3722_ADC_CH_GPIO7,
+       AS3722_ADC_CH_VBAT,
+       AS3722_ADC_CH_ADC1,
+       AS3722_ADC_CH_ADC2,
+       AS3722_ADC_CH_TBD1,
+       AS3722_ADC_CH_TBD2,
+       AS3722_ADC_CH_T1SD0,
+       AS3722_ADC_CH_T2SD0,
+       AS3722_ADC_CH_T3SD0,
+       AS3722_ADC_CH_T4SD0,
+       AS3722_ADC_CH_TSD1,
+       AS3722_ADC_CH_T1SD6,
+       AS3722_ADC_CH_T2SD6,
+       AS3722_ADC_CH_MAX,
+};
+
+#define AS3722_DATASHEET_NAME(_name)   "as3722-gpadc-chan-"#_name
+
+#define AS3722_GPADC_IIO_MAP(chan, _consumer, _comsumer_channel_name)  \
+{                                                                      \
+       .adc_channel_label = AS3722_DATASHEET_NAME(chan),               \
+       .consumer_dev_name = _consumer,                                 \
+       .consumer_channel = _comsumer_channel_name,                     \
+}
 #endif