Merge tag 'iio-fixes-for-3.11a' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 17 Jul 2013 05:41:38 +0000 (22:41 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 17 Jul 2013 05:41:38 +0000 (22:41 -0700)
Jonathan writes:

The first round of IIO fixes for the 3.11 cycle.

This set is larger than I would like, partly due to my lack of review
time in the weeks before the merge window and partly because a
couple of large drivers and the subsystem as a whole seem to be
getting a lot more exposure and testing recently.

1) A long term bug in trigger handling gave a double free of the device.

2) Wrong return value handling means offsets are ignored in
   iio_convert_raw_to_processed_unlocked.

3) The iio_channel_has_info utility function was incorrectly updated
   during the recent info_mask split, this is now fixed.

4) mxs-lradc has a couple of little fixes.

5) A couple of missing .driver_module entries meant that drivers
   could be removed from underneath their users.

6) Error path fixes for ad7303 and lis3l02dq.

7) The scale value for presure in the lps331ap driver was out by
   a factor of 100.

1  2 
drivers/iio/adc/ti_am335x_adc.c

  #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)
@@@ -47,20 -42,10 +47,20 @@@ static void tiadc_writel(struct tiadc_d
        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
         */
  
        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)
@@@ -143,9 -108,7 +143,9 @@@ static int tiadc_read_raw(struct iio_de
  {
        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,
         * 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;
  }
  
  static const struct iio_info tiadc_info = {
        .read_raw = &tiadc_read_raw,
+       .driver_module = THIS_MODULE,
  };
  
  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;
        }
  
        }
        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);
@@@ -247,15 -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;
@@@ -266,10 -206,9 +267,10 @@@ static int tiadc_suspend(struct device 
  {
        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);
@@@ -305,22 -244,16 +306,22 @@@ static const struct dev_pm_ops tiadc_pm
  #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");