Merge tag 'iio-fixes-for-3.11a' of git://git.kernel.org/pub/scm/linux/kernel/git...
[cascardo/linux.git] / drivers / iio / adc / ti_am335x_adc.c
index 985f588..0ad208a 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/iio/iio.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/iio/machine.h>
+#include <linux/iio/driver.h>
 
 #include <linux/mfd/ti_am335x_tscadc.h>
-#include <linux/platform_data/ti_am335x_adc.h>
 
 struct tiadc_device {
        struct ti_tscadc_dev *mfd_tscadc;
        int channels;
+       u8 channel_line[8];
+       u8 channel_step[8];
 };
 
 static unsigned int tiadc_readl(struct tiadc_device *adc, unsigned int reg)
@@ -42,10 +47,20 @@ static void tiadc_writel(struct tiadc_device *adc, unsigned int reg,
        writel(val, adc->mfd_tscadc->tscadc_base + reg);
 }
 
+static u32 get_adc_step_mask(struct tiadc_device *adc_dev)
+{
+       u32 step_en;
+
+       step_en = ((1 << adc_dev->channels) - 1);
+       step_en <<= TOTAL_STEPS - adc_dev->channels + 1;
+       return step_en;
+}
+
 static void tiadc_step_config(struct tiadc_device *adc_dev)
 {
        unsigned int stepconfig;
-       int i, channels = 0, steps;
+       int i, steps;
+       u32 step_en;
 
        /*
         * There are 16 configurable steps and 8 analog input
@@ -58,43 +73,63 @@ static void tiadc_step_config(struct tiadc_device *adc_dev)
         */
 
        steps = TOTAL_STEPS - adc_dev->channels;
-       channels = TOTAL_CHANNELS - adc_dev->channels;
-
        stepconfig = STEPCONFIG_AVG_16 | STEPCONFIG_FIFO1;
 
-       for (i = (steps + 1); i <= TOTAL_STEPS; i++) {
-               tiadc_writel(adc_dev, REG_STEPCONFIG(i),
-                               stepconfig | STEPCONFIG_INP(channels));
-               tiadc_writel(adc_dev, REG_STEPDELAY(i),
+       for (i = 0; i < adc_dev->channels; i++) {
+               int chan;
+
+               chan = adc_dev->channel_line[i];
+               tiadc_writel(adc_dev, REG_STEPCONFIG(steps),
+                               stepconfig | STEPCONFIG_INP(chan));
+               tiadc_writel(adc_dev, REG_STEPDELAY(steps),
                                STEPCONFIG_OPENDLY);
-               channels++;
+               adc_dev->channel_step[i] = steps;
+               steps++;
        }
-       tiadc_writel(adc_dev, REG_SE, STPENB_STEPENB);
+       step_en = get_adc_step_mask(adc_dev);
+       am335x_tsc_se_set(adc_dev->mfd_tscadc, step_en);
 }
 
+static const char * const chan_name_ain[] = {
+       "AIN0",
+       "AIN1",
+       "AIN2",
+       "AIN3",
+       "AIN4",
+       "AIN5",
+       "AIN6",
+       "AIN7",
+};
+
 static int tiadc_channel_init(struct iio_dev *indio_dev, int channels)
 {
+       struct tiadc_device *adc_dev = iio_priv(indio_dev);
        struct iio_chan_spec *chan_array;
+       struct iio_chan_spec *chan;
        int i;
 
        indio_dev->num_channels = channels;
-       chan_array = kcalloc(indio_dev->num_channels,
+       chan_array = kcalloc(channels,
                        sizeof(struct iio_chan_spec), GFP_KERNEL);
-
        if (chan_array == NULL)
                return -ENOMEM;
 
-       for (i = 0; i < (indio_dev->num_channels); i++) {
-               struct iio_chan_spec *chan = chan_array + i;
+       chan = chan_array;
+       for (i = 0; i < channels; i++, chan++) {
+
                chan->type = IIO_VOLTAGE;
                chan->indexed = 1;
-               chan->channel = i;
+               chan->channel = adc_dev->channel_line[i];
                chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
+               chan->datasheet_name = chan_name_ain[chan->channel];
+               chan->scan_type.sign = 'u';
+               chan->scan_type.realbits = 12;
+               chan->scan_type.storagebits = 32;
        }
 
        indio_dev->channels = chan_array;
 
-       return indio_dev->num_channels;
+       return 0;
 }
 
 static void tiadc_channels_remove(struct iio_dev *indio_dev)
@@ -108,7 +143,9 @@ static int tiadc_read_raw(struct iio_dev *indio_dev,
 {
        struct tiadc_device *adc_dev = iio_priv(indio_dev);
        int i;
-       unsigned int fifo1count, readx1;
+       unsigned int fifo1count, read;
+       u32 step = UINT_MAX;
+       bool found = false;
 
        /*
         * When the sub-system is first enabled,
@@ -121,14 +158,26 @@ static int tiadc_read_raw(struct iio_dev *indio_dev,
         * Hence we need to flush out this data.
         */
 
+       for (i = 0; i < ARRAY_SIZE(adc_dev->channel_step); i++) {
+               if (chan->channel == adc_dev->channel_line[i]) {
+                       step = adc_dev->channel_step[i];
+                       break;
+               }
+       }
+       if (WARN_ON_ONCE(step == UINT_MAX))
+               return -EINVAL;
+
        fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT);
        for (i = 0; i < fifo1count; i++) {
-               readx1 = tiadc_readl(adc_dev, REG_FIFO1);
-               if (i == chan->channel)
-                       *val = readx1 & 0xfff;
+               read = tiadc_readl(adc_dev, REG_FIFO1);
+               if (read >> 16 == step) {
+                       *val = read & 0xfff;
+                       found = true;
+               }
        }
-       tiadc_writel(adc_dev, REG_SE, STPENB_STEPENB);
-
+       am335x_tsc_se_update(adc_dev->mfd_tscadc);
+       if (found == false)
+               return -EBUSY;
        return IIO_VAL_INT;
 }
 
@@ -141,13 +190,15 @@ static int tiadc_probe(struct platform_device *pdev)
 {
        struct iio_dev          *indio_dev;
        struct tiadc_device     *adc_dev;
-       struct ti_tscadc_dev    *tscadc_dev = pdev->dev.platform_data;
-       struct mfd_tscadc_board *pdata;
+       struct device_node      *node = pdev->dev.of_node;
+       struct property         *prop;
+       const __be32            *cur;
        int                     err;
+       u32                     val;
+       int                     channels = 0;
 
-       pdata = tscadc_dev->dev->platform_data;
-       if (!pdata || !pdata->adc_init) {
-               dev_err(&pdev->dev, "Could not find platform data\n");
+       if (!node) {
+               dev_err(&pdev->dev, "Could not find valid DT data.\n");
                return -EINVAL;
        }
 
@@ -159,8 +210,13 @@ static int tiadc_probe(struct platform_device *pdev)
        }
        adc_dev = iio_priv(indio_dev);
 
-       adc_dev->mfd_tscadc = tscadc_dev;
-       adc_dev->channels = pdata->adc_init->adc_channels;
+       adc_dev->mfd_tscadc = ti_tscadc_dev_get(pdev);
+
+       of_property_for_each_u32(node, "ti,adc-channels", prop, cur, val) {
+               adc_dev->channel_line[channels] = val;
+               channels++;
+       }
+       adc_dev->channels = channels;
 
        indio_dev->dev.parent = &pdev->dev;
        indio_dev->name = dev_name(&pdev->dev);
@@ -192,10 +248,15 @@ err_ret:
 static int tiadc_remove(struct platform_device *pdev)
 {
        struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+       struct tiadc_device *adc_dev = iio_priv(indio_dev);
+       u32 step_en;
 
        iio_device_unregister(indio_dev);
        tiadc_channels_remove(indio_dev);
 
+       step_en = get_adc_step_mask(adc_dev);
+       am335x_tsc_se_clr(adc_dev->mfd_tscadc, step_en);
+
        iio_device_free(indio_dev);
 
        return 0;
@@ -206,9 +267,10 @@ static int tiadc_suspend(struct device *dev)
 {
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
        struct tiadc_device *adc_dev = iio_priv(indio_dev);
-       struct ti_tscadc_dev *tscadc_dev = dev->platform_data;
+       struct ti_tscadc_dev *tscadc_dev;
        unsigned int idle;
 
+       tscadc_dev = ti_tscadc_dev_get(to_platform_device(dev));
        if (!device_may_wakeup(tscadc_dev->dev)) {
                idle = tiadc_readl(adc_dev, REG_CTRL);
                idle &= ~(CNTRLREG_TSCSSENB);
@@ -244,16 +306,22 @@ static const struct dev_pm_ops tiadc_pm_ops = {
 #define TIADC_PM_OPS NULL
 #endif
 
+static const struct of_device_id ti_adc_dt_ids[] = {
+       { .compatible = "ti,am3359-adc", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, ti_adc_dt_ids);
+
 static struct platform_driver tiadc_driver = {
        .driver = {
-               .name   = "tiadc",
+               .name   = "TI-am335x-adc",
                .owner  = THIS_MODULE,
                .pm     = TIADC_PM_OPS,
+               .of_match_table = of_match_ptr(ti_adc_dt_ids),
        },
        .probe  = tiadc_probe,
        .remove = tiadc_remove,
 };
-
 module_platform_driver(tiadc_driver);
 
 MODULE_DESCRIPTION("TI ADC controller driver");