Merge tag 'staging-5.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh...
[linux-2.6-microblaze.git] / drivers / iio / imu / adis16400.c
index 44e46dc..cfb1c19 100644 (file)
@@ -156,12 +156,14 @@ struct adis16400_state;
 
 struct adis16400_chip_info {
        const struct iio_chan_spec *channels;
+       const struct adis_timeout *timeouts;
        const int num_channels;
        const long flags;
        unsigned int gyro_scale_micro;
        unsigned int accel_scale_micro;
        int temp_scale_nano;
        int temp_offset;
+       /* set_freq() & get_freq() need to avoid using ADIS lib's state lock */
        int (*set_freq)(struct adis16400_state *st, unsigned int freq);
        int (*get_freq)(struct adis16400_state *st);
 };
@@ -326,7 +328,7 @@ static int adis16334_get_freq(struct adis16400_state *st)
        int ret;
        uint16_t t;
 
-       ret = adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &t);
+       ret = __adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &t);
        if (ret)
                return ret;
 
@@ -350,7 +352,7 @@ static int adis16334_set_freq(struct adis16400_state *st, unsigned int freq)
        t <<= ADIS16334_RATE_DIV_SHIFT;
        t |= ADIS16334_RATE_INT_CLK;
 
-       return adis_write_reg_16(&st->adis, ADIS16400_SMPL_PRD, t);
+       return __adis_write_reg_16(&st->adis, ADIS16400_SMPL_PRD, t);
 }
 
 static int adis16400_get_freq(struct adis16400_state *st)
@@ -358,7 +360,7 @@ static int adis16400_get_freq(struct adis16400_state *st)
        int sps, ret;
        uint16_t t;
 
-       ret = adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &t);
+       ret = __adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &t);
        if (ret)
                return ret;
 
@@ -390,7 +392,7 @@ static int adis16400_set_freq(struct adis16400_state *st, unsigned int freq)
        else
                st->adis.spi->max_speed_hz = ADIS16400_SPI_FAST;
 
-       return adis_write_reg_8(&st->adis, ADIS16400_SMPL_PRD, val);
+       return __adis_write_reg_8(&st->adis, ADIS16400_SMPL_PRD, val);
 }
 
 static const unsigned int adis16400_3db_divisors[] = {
@@ -404,7 +406,7 @@ static const unsigned int adis16400_3db_divisors[] = {
        [7] = 200, /* Not a valid setting */
 };
 
-static int adis16400_set_filter(struct iio_dev *indio_dev, int sps, int val)
+static int __adis16400_set_filter(struct iio_dev *indio_dev, int sps, int val)
 {
        struct adis16400_state *st = iio_priv(indio_dev);
        uint16_t val16;
@@ -415,11 +417,11 @@ static int adis16400_set_filter(struct iio_dev *indio_dev, int sps, int val)
                        break;
        }
 
-       ret = adis_read_reg_16(&st->adis, ADIS16400_SENS_AVG, &val16);
+       ret = __adis_read_reg_16(&st->adis, ADIS16400_SENS_AVG, &val16);
        if (ret)
                return ret;
 
-       ret = adis_write_reg_16(&st->adis, ADIS16400_SENS_AVG,
+       ret = __adis_write_reg_16(&st->adis, ADIS16400_SENS_AVG,
                                         (val16 & ~0x07) | i);
        return ret;
 }
@@ -507,32 +509,31 @@ static int adis16400_write_raw(struct iio_dev *indio_dev,
        struct iio_chan_spec const *chan, int val, int val2, long info)
 {
        struct adis16400_state *st = iio_priv(indio_dev);
+       struct mutex *slock = &st->adis.state_lock;
        int ret, sps;
 
        switch (info) {
        case IIO_CHAN_INFO_CALIBBIAS:
-               mutex_lock(&indio_dev->mlock);
                ret = adis_write_reg_16(&st->adis,
                                adis16400_addresses[chan->scan_index], val);
-               mutex_unlock(&indio_dev->mlock);
                return ret;
        case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
                /*
                 * Need to cache values so we can update if the frequency
                 * changes.
                 */
-               mutex_lock(&indio_dev->mlock);
+               mutex_lock(slock);
                st->filt_int = val;
                /* Work out update to current value */
                sps = st->variant->get_freq(st);
                if (sps < 0) {
-                       mutex_unlock(&indio_dev->mlock);
+                       mutex_unlock(slock);
                        return sps;
                }
 
-               ret = adis16400_set_filter(indio_dev, sps,
+               ret = __adis16400_set_filter(indio_dev, sps,
                        val * 1000 + val2 / 1000);
-               mutex_unlock(&indio_dev->mlock);
+               mutex_unlock(slock);
                return ret;
        case IIO_CHAN_INFO_SAMP_FREQ:
                sps = val * 1000 + val2 / 1000;
@@ -540,9 +541,9 @@ static int adis16400_write_raw(struct iio_dev *indio_dev,
                if (sps <= 0)
                        return -EINVAL;
 
-               mutex_lock(&indio_dev->mlock);
+               mutex_lock(slock);
                ret = st->variant->set_freq(st, sps);
-               mutex_unlock(&indio_dev->mlock);
+               mutex_unlock(slock);
                return ret;
        default:
                return -EINVAL;
@@ -553,6 +554,7 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
        struct iio_chan_spec const *chan, int *val, int *val2, long info)
 {
        struct adis16400_state *st = iio_priv(indio_dev);
+       struct mutex *slock = &st->adis.state_lock;
        int16_t val16;
        int ret;
 
@@ -596,10 +598,8 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
                        return -EINVAL;
                }
        case IIO_CHAN_INFO_CALIBBIAS:
-               mutex_lock(&indio_dev->mlock);
                ret = adis_read_reg_16(&st->adis,
                                adis16400_addresses[chan->scan_index], &val16);
-               mutex_unlock(&indio_dev->mlock);
                if (ret)
                        return ret;
                val16 = sign_extend32(val16, 11);
@@ -610,27 +610,27 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
                *val = st->variant->temp_offset;
                return IIO_VAL_INT;
        case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
-               mutex_lock(&indio_dev->mlock);
+               mutex_lock(slock);
                /* Need both the number of taps and the sampling frequency */
-               ret = adis_read_reg_16(&st->adis,
+               ret = __adis_read_reg_16(&st->adis,
                                                ADIS16400_SENS_AVG,
                                                &val16);
                if (ret) {
-                       mutex_unlock(&indio_dev->mlock);
+                       mutex_unlock(slock);
                        return ret;
                }
                ret = st->variant->get_freq(st);
-               if (ret >= 0) {
-                       ret /= adis16400_3db_divisors[val16 & 0x07];
-                       *val = ret / 1000;
-                       *val2 = (ret % 1000) * 1000;
-               }
-               mutex_unlock(&indio_dev->mlock);
+               mutex_unlock(slock);
                if (ret)
                        return ret;
+               ret /= adis16400_3db_divisors[val16 & 0x07];
+               *val = ret / 1000;
+               *val2 = (ret % 1000) * 1000;
                return IIO_VAL_INT_PLUS_MICRO;
        case IIO_CHAN_INFO_SAMP_FREQ:
+               mutex_lock(slock);
                ret = st->variant->get_freq(st);
+               mutex_unlock(slock);
                if (ret)
                        return ret;
                *val = ret / 1000;
@@ -930,6 +930,36 @@ static const struct iio_chan_spec adis16334_channels[] = {
        IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP),
 };
 
+static const struct adis_timeout adis16300_timeouts = {
+       .reset_ms = ADIS16400_STARTUP_DELAY,
+       .sw_reset_ms = ADIS16400_STARTUP_DELAY,
+       .self_test_ms = ADIS16400_STARTUP_DELAY,
+};
+
+static const struct adis_timeout adis16362_timeouts = {
+       .reset_ms = 130,
+       .sw_reset_ms = 130,
+       .self_test_ms = 12,
+};
+
+static const struct adis_timeout adis16400_timeouts = {
+       .reset_ms = 170,
+       .sw_reset_ms = 170,
+       .self_test_ms = 12,
+};
+
+static const struct adis_timeout adis16445_timeouts = {
+       .reset_ms = 55,
+       .sw_reset_ms = 55,
+       .self_test_ms = 16,
+};
+
+static const struct adis_timeout adis16448_timeouts = {
+       .reset_ms = 90,
+       .sw_reset_ms = 90,
+       .self_test_ms = 45,
+};
+
 static struct adis16400_chip_info adis16400_chips[] = {
        [ADIS16300] = {
                .channels = adis16300_channels,
@@ -942,6 +972,7 @@ static struct adis16400_chip_info adis16400_chips[] = {
                .temp_offset = 25000000 / 140000, /* 25 C = 0x00 */
                .set_freq = adis16400_set_freq,
                .get_freq = adis16400_get_freq,
+               .timeouts = &adis16300_timeouts,
        },
        [ADIS16334] = {
                .channels = adis16334_channels,
@@ -965,6 +996,7 @@ static struct adis16400_chip_info adis16400_chips[] = {
                .flags = ADIS16400_NO_BURST | ADIS16400_HAS_SLOW_MODE,
                .set_freq = adis16400_set_freq,
                .get_freq = adis16400_get_freq,
+               .timeouts = &adis16300_timeouts,
        },
        [ADIS16360] = {
                .channels = adis16350_channels,
@@ -977,6 +1009,7 @@ static struct adis16400_chip_info adis16400_chips[] = {
                .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */
                .set_freq = adis16400_set_freq,
                .get_freq = adis16400_get_freq,
+               .timeouts = &adis16300_timeouts,
        },
        [ADIS16362] = {
                .channels = adis16350_channels,
@@ -989,6 +1022,7 @@ static struct adis16400_chip_info adis16400_chips[] = {
                .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */
                .set_freq = adis16400_set_freq,
                .get_freq = adis16400_get_freq,
+               .timeouts = &adis16362_timeouts,
        },
        [ADIS16364] = {
                .channels = adis16350_channels,
@@ -1001,6 +1035,7 @@ static struct adis16400_chip_info adis16400_chips[] = {
                .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */
                .set_freq = adis16400_set_freq,
                .get_freq = adis16400_get_freq,
+               .timeouts = &adis16362_timeouts,
        },
        [ADIS16367] = {
                .channels = adis16350_channels,
@@ -1013,6 +1048,7 @@ static struct adis16400_chip_info adis16400_chips[] = {
                .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */
                .set_freq = adis16400_set_freq,
                .get_freq = adis16400_get_freq,
+               .timeouts = &adis16300_timeouts,
        },
        [ADIS16400] = {
                .channels = adis16400_channels,
@@ -1024,6 +1060,7 @@ static struct adis16400_chip_info adis16400_chips[] = {
                .temp_offset = 25000000 / 140000, /* 25 C = 0x00 */
                .set_freq = adis16400_set_freq,
                .get_freq = adis16400_get_freq,
+               .timeouts = &adis16400_timeouts,
        },
        [ADIS16445] = {
                .channels = adis16445_channels,
@@ -1037,6 +1074,7 @@ static struct adis16400_chip_info adis16400_chips[] = {
                .temp_offset = 31000000 / 73860, /* 31 C = 0x00 */
                .set_freq = adis16334_set_freq,
                .get_freq = adis16334_get_freq,
+               .timeouts = &adis16445_timeouts,
        },
        [ADIS16448] = {
                .channels = adis16448_channels,
@@ -1050,6 +1088,7 @@ static struct adis16400_chip_info adis16400_chips[] = {
                .temp_offset = 31000000 / 73860, /* 31 C = 0x00 */
                .set_freq = adis16334_set_freq,
                .get_freq = adis16334_get_freq,
+               .timeouts = &adis16448_timeouts,
        }
 };
 
@@ -1087,7 +1126,6 @@ static const struct adis_data adis16400_data = {
        .write_delay = 50,
 
        .self_test_mask = ADIS16400_MSC_CTRL_MEM_TEST,
-       .startup_delay = ADIS16400_STARTUP_DELAY,
 
        .status_error_msgs = adis16400_status_error_msgs,
        .status_error_mask = BIT(ADIS16400_DIAG_STAT_ZACCL_FAIL) |
@@ -1121,11 +1159,28 @@ static void adis16400_setup_chan_mask(struct adis16400_state *st)
        }
 }
 
+static struct adis_data *adis16400_adis_data_alloc(struct adis16400_state *st,
+                                                  struct device *dev)
+{
+       struct adis_data *data;
+
+       data = devm_kmalloc(dev, sizeof(struct adis_data), GFP_KERNEL);
+       if (!data)
+               return ERR_PTR(-ENOMEM);
+
+       memcpy(data, &adis16400_data, sizeof(*data));
+
+       data->timeouts = st->variant->timeouts;
+
+       return data;
+}
+
 static int adis16400_probe(struct spi_device *spi)
 {
        struct adis16400_state *st;
        struct iio_dev *indio_dev;
        int ret;
+       const struct adis_data *adis16400_data;
 
        indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
        if (indio_dev == NULL)
@@ -1152,7 +1207,11 @@ static int adis16400_probe(struct spi_device *spi)
                        st->adis.burst->extra_len = sizeof(u16);
        }
 
-       ret = adis_init(&st->adis, indio_dev, spi, &adis16400_data);
+       adis16400_data = adis16400_adis_data_alloc(st, &spi->dev);
+       if (IS_ERR(adis16400_data))
+               return PTR_ERR(adis16400_data);
+
+       ret = adis_init(&st->adis, indio_dev, spi, adis16400_data);
        if (ret)
                return ret;