summaryrefslogtreecommitdiff
path: root/drivers/iio/gyro/adis16136.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iio/gyro/adis16136.c')
-rw-r--r--drivers/iio/gyro/adis16136.c197
1 files changed, 101 insertions, 96 deletions
diff --git a/drivers/iio/gyro/adis16136.c b/drivers/iio/gyro/adis16136.c
index 058e6d5c955f..369c7428e1ef 100644
--- a/drivers/iio/gyro/adis16136.c
+++ b/drivers/iio/gyro/adis16136.c
@@ -1,25 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ADIS16133/ADIS16135/ADIS16136 gyroscope driver
*
* Copyright 2012 Analog Devices Inc.
* Author: Lars-Peter Clausen <lars@metafoo.de>
- *
- * Licensed under the GPL-2.
*/
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/mutex.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
-#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
-#include <linux/iio/buffer.h>
#include <linux/iio/imu/adis.h>
#include <linux/debugfs.h>
@@ -60,6 +54,7 @@
struct adis16136_chip_info {
unsigned int precision;
unsigned int fullscale;
+ const struct adis_data adis_data;
};
struct adis16136 {
@@ -81,19 +76,19 @@ static ssize_t adis16136_show_serial(struct file *file,
ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_SERIAL_NUM,
&serial);
- if (ret < 0)
+ if (ret)
return ret;
ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT1, &lot1);
- if (ret < 0)
+ if (ret)
return ret;
ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT2, &lot2);
- if (ret < 0)
+ if (ret)
return ret;
ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT3, &lot3);
- if (ret < 0)
+ if (ret)
return ret;
len = snprintf(buf, sizeof(buf), "%.4x%.4x%.4x-%.4x\n", lot1, lot2,
@@ -117,14 +112,14 @@ static int adis16136_show_product_id(void *arg, u64 *val)
ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_PROD_ID,
&prod_id);
- if (ret < 0)
+ if (ret)
return ret;
*val = prod_id;
return 0;
}
-DEFINE_SIMPLE_ATTRIBUTE(adis16136_product_id_fops,
+DEFINE_DEBUGFS_ATTRIBUTE(adis16136_product_id_fops,
adis16136_show_product_id, NULL, "%llu\n");
static int adis16136_show_flash_count(void *arg, u64 *val)
@@ -135,26 +130,27 @@ static int adis16136_show_flash_count(void *arg, u64 *val)
ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_FLASH_CNT,
&flash_count);
- if (ret < 0)
+ if (ret)
return ret;
*val = flash_count;
return 0;
}
-DEFINE_SIMPLE_ATTRIBUTE(adis16136_flash_count_fops,
+DEFINE_DEBUGFS_ATTRIBUTE(adis16136_flash_count_fops,
adis16136_show_flash_count, NULL, "%lld\n");
static int adis16136_debugfs_init(struct iio_dev *indio_dev)
{
struct adis16136 *adis16136 = iio_priv(indio_dev);
+ struct dentry *d = iio_get_debugfs_dentry(indio_dev);
- debugfs_create_file("serial_number", 0400, indio_dev->debugfs_dentry,
- adis16136, &adis16136_serial_fops);
- debugfs_create_file("product_id", 0400, indio_dev->debugfs_dentry,
- adis16136, &adis16136_product_id_fops);
- debugfs_create_file("flash_count", 0400, indio_dev->debugfs_dentry,
- adis16136, &adis16136_flash_count_fops);
+ debugfs_create_file_unsafe("serial_number", 0400,
+ d, adis16136, &adis16136_serial_fops);
+ debugfs_create_file_unsafe("product_id", 0400,
+ d, adis16136, &adis16136_product_id_fops);
+ debugfs_create_file_unsafe("flash_count", 0400,
+ d, adis16136, &adis16136_flash_count_fops);
return 0;
}
@@ -183,13 +179,13 @@ static int adis16136_set_freq(struct adis16136 *adis16136, unsigned int freq)
return adis_write_reg_16(&adis16136->adis, ADIS16136_REG_SMPL_PRD, t);
}
-static int adis16136_get_freq(struct adis16136 *adis16136, unsigned int *freq)
+static int __adis16136_get_freq(struct adis16136 *adis16136, unsigned int *freq)
{
uint16_t t;
int ret;
- ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_SMPL_PRD, &t);
- if (ret < 0)
+ ret = __adis_read_reg_16(&adis16136->adis, ADIS16136_REG_SMPL_PRD, &t);
+ if (ret)
return ret;
*freq = 32768 / (t + 1);
@@ -225,11 +221,12 @@ static ssize_t adis16136_read_frequency(struct device *dev,
unsigned int freq;
int ret;
- ret = adis16136_get_freq(adis16136, &freq);
- if (ret < 0)
+ adis_dev_auto_lock(&adis16136->adis);
+ ret = __adis16136_get_freq(adis16136, &freq);
+ if (ret)
return ret;
- return sprintf(buf, "%d\n", freq);
+ return sysfs_emit(buf, "%d\n", freq);
}
static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
@@ -253,8 +250,9 @@ static int adis16136_set_filter(struct iio_dev *indio_dev, int val)
unsigned int freq;
int i, ret;
- ret = adis16136_get_freq(adis16136, &freq);
- if (ret < 0)
+ adis_dev_auto_lock(&adis16136->adis);
+ ret = __adis16136_get_freq(adis16136, &freq);
+ if (ret)
return ret;
for (i = ARRAY_SIZE(adis16136_3db_divisors) - 1; i >= 1; i--) {
@@ -262,7 +260,7 @@ static int adis16136_set_filter(struct iio_dev *indio_dev, int val)
break;
}
- return adis_write_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, i);
+ return __adis_write_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, i);
}
static int adis16136_get_filter(struct iio_dev *indio_dev, int *val)
@@ -272,22 +270,20 @@ static int adis16136_get_filter(struct iio_dev *indio_dev, int *val)
uint16_t val16;
int ret;
- mutex_lock(&indio_dev->mlock);
+ adis_dev_auto_lock(&adis16136->adis);
- ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, &val16);
- if (ret < 0)
- goto err_unlock;
+ ret = __adis_read_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT,
+ &val16);
+ if (ret)
+ return ret;
- ret = adis16136_get_freq(adis16136, &freq);
- if (ret < 0)
- goto err_unlock;
+ ret = __adis16136_get_freq(adis16136, &freq);
+ if (ret)
+ return ret;
*val = freq / adis16136_3db_divisors[val16 & 0x07];
-err_unlock:
- mutex_unlock(&indio_dev->mlock);
-
- return ret ? ret : IIO_VAL_INT;
+ return IIO_VAL_INT;
}
static int adis16136_read_raw(struct iio_dev *indio_dev,
@@ -316,7 +312,7 @@ static int adis16136_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_CALIBBIAS:
ret = adis_read_reg_32(&adis16136->adis,
ADIS16136_REG_GYRO_OFF2, &val32);
- if (ret < 0)
+ if (ret)
return ret;
*val = sign_extend32(val32, 31);
@@ -398,7 +394,6 @@ static const struct attribute_group adis16136_attribute_group = {
};
static const struct iio_info adis16136_info = {
- .driver_module = THIS_MODULE,
.attrs = &adis16136_attribute_group,
.read_raw = &adis16136_read_raw,
.write_raw = &adis16136_write_raw,
@@ -426,7 +421,7 @@ static int adis16136_initial_setup(struct iio_dev *indio_dev)
uint16_t prod_id;
int ret;
- ret = adis_initial_startup(&adis16136->adis);
+ ret = __adis_initial_startup(&adis16136->adis);
if (ret)
return ret;
@@ -435,7 +430,9 @@ static int adis16136_initial_setup(struct iio_dev *indio_dev)
if (ret)
return ret;
- sscanf(indio_dev->name, "adis%u\n", &device_id);
+ ret = sscanf(indio_dev->name, "adis%u\n", &device_id);
+ if (ret != 1)
+ return -EINVAL;
if (prod_id != device_id)
dev_warn(&indio_dev->dev, "Device ID(%u) and product ID(%u) do not match.",
@@ -451,53 +448,79 @@ static const char * const adis16136_status_error_msgs[] = {
[ADIS16136_DIAG_STAT_FLASH_CHKSUM_FAIL] = "Flash checksum error",
};
-static const struct adis_data adis16136_data = {
- .diag_stat_reg = ADIS16136_REG_DIAG_STAT,
- .glob_cmd_reg = ADIS16136_REG_GLOB_CMD,
- .msc_ctrl_reg = ADIS16136_REG_MSC_CTRL,
-
- .self_test_mask = ADIS16136_MSC_CTRL_SELF_TEST,
- .startup_delay = 80,
-
- .read_delay = 10,
- .write_delay = 10,
-
- .status_error_msgs = adis16136_status_error_msgs,
- .status_error_mask = BIT(ADIS16136_DIAG_STAT_FLASH_UPDATE_FAIL) |
- BIT(ADIS16136_DIAG_STAT_SPI_FAIL) |
- BIT(ADIS16136_DIAG_STAT_SELF_TEST_FAIL) |
- BIT(ADIS16136_DIAG_STAT_FLASH_CHKSUM_FAIL),
-};
+#define ADIS16136_DATA(_timeouts) \
+{ \
+ .diag_stat_reg = ADIS16136_REG_DIAG_STAT, \
+ .glob_cmd_reg = ADIS16136_REG_GLOB_CMD, \
+ .msc_ctrl_reg = ADIS16136_REG_MSC_CTRL, \
+ .self_test_reg = ADIS16136_REG_MSC_CTRL, \
+ .self_test_mask = ADIS16136_MSC_CTRL_SELF_TEST, \
+ .read_delay = 10, \
+ .write_delay = 10, \
+ .status_error_msgs = adis16136_status_error_msgs, \
+ .status_error_mask = BIT(ADIS16136_DIAG_STAT_FLASH_UPDATE_FAIL) | \
+ BIT(ADIS16136_DIAG_STAT_SPI_FAIL) | \
+ BIT(ADIS16136_DIAG_STAT_SELF_TEST_FAIL) | \
+ BIT(ADIS16136_DIAG_STAT_FLASH_CHKSUM_FAIL), \
+ .timeouts = (_timeouts), \
+}
enum adis16136_id {
ID_ADIS16133,
ID_ADIS16135,
ID_ADIS16136,
+ ID_ADIS16137,
+};
+
+static const struct adis_timeout adis16133_timeouts = {
+ .reset_ms = 75,
+ .sw_reset_ms = 75,
+ .self_test_ms = 50,
+};
+
+static const struct adis_timeout adis16136_timeouts = {
+ .reset_ms = 128,
+ .sw_reset_ms = 75,
+ .self_test_ms = 245,
};
static const struct adis16136_chip_info adis16136_chip_info[] = {
[ID_ADIS16133] = {
.precision = IIO_DEGREE_TO_RAD(1200),
.fullscale = 24000,
+ .adis_data = ADIS16136_DATA(&adis16133_timeouts),
},
[ID_ADIS16135] = {
.precision = IIO_DEGREE_TO_RAD(300),
.fullscale = 24000,
+ .adis_data = ADIS16136_DATA(&adis16133_timeouts),
},
[ID_ADIS16136] = {
.precision = IIO_DEGREE_TO_RAD(450),
.fullscale = 24623,
+ .adis_data = ADIS16136_DATA(&adis16136_timeouts),
+ },
+ [ID_ADIS16137] = {
+ .precision = IIO_DEGREE_TO_RAD(1000),
+ .fullscale = 24609,
+ .adis_data = ADIS16136_DATA(&adis16136_timeouts),
},
};
+static void adis16136_stop(void *data)
+{
+ adis16136_stop_device(data);
+}
+
static int adis16136_probe(struct spi_device *spi)
{
const struct spi_device_id *id = spi_get_device_id(spi);
struct adis16136 *adis16136;
struct iio_dev *indio_dev;
+ const struct adis_data *adis16136_data;
int ret;
- indio_dev = iio_device_alloc(sizeof(*adis16136));
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adis16136));
if (indio_dev == NULL)
return -ENOMEM;
@@ -506,53 +529,35 @@ static int adis16136_probe(struct spi_device *spi)
adis16136 = iio_priv(indio_dev);
adis16136->chip_info = &adis16136_chip_info[id->driver_data];
- indio_dev->dev.parent = &spi->dev;
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->channels = adis16136_channels;
indio_dev->num_channels = ARRAY_SIZE(adis16136_channels);
indio_dev->info = &adis16136_info;
indio_dev->modes = INDIO_DIRECT_MODE;
- ret = adis_init(&adis16136->adis, indio_dev, spi, &adis16136_data);
+ adis16136_data = &adis16136->chip_info->adis_data;
+
+ ret = adis_init(&adis16136->adis, indio_dev, spi, adis16136_data);
if (ret)
- goto error_free_dev;
+ return ret;
- ret = adis_setup_buffer_and_trigger(&adis16136->adis, indio_dev, NULL);
+ ret = devm_adis_setup_buffer_and_trigger(&adis16136->adis, indio_dev, NULL);
if (ret)
- goto error_free_dev;
+ return ret;
ret = adis16136_initial_setup(indio_dev);
if (ret)
- goto error_cleanup_buffer;
+ return ret;
- ret = iio_device_register(indio_dev);
+ ret = devm_add_action_or_reset(&spi->dev, adis16136_stop, indio_dev);
if (ret)
- goto error_stop_device;
-
- adis16136_debugfs_init(indio_dev);
-
- return 0;
-
-error_stop_device:
- adis16136_stop_device(indio_dev);
-error_cleanup_buffer:
- adis_cleanup_buffer_and_trigger(&adis16136->adis, indio_dev);
-error_free_dev:
- iio_device_free(indio_dev);
- return ret;
-}
-
-static int adis16136_remove(struct spi_device *spi)
-{
- struct iio_dev *indio_dev = spi_get_drvdata(spi);
- struct adis16136 *adis16136 = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
- adis16136_stop_device(indio_dev);
+ return ret;
- adis_cleanup_buffer_and_trigger(&adis16136->adis, indio_dev);
+ ret = devm_iio_device_register(&spi->dev, indio_dev);
+ if (ret)
+ return ret;
- iio_device_free(indio_dev);
+ adis16136_debugfs_init(indio_dev);
return 0;
}
@@ -561,6 +566,7 @@ static const struct spi_device_id adis16136_ids[] = {
{ "adis16133", ID_ADIS16133 },
{ "adis16135", ID_ADIS16135 },
{ "adis16136", ID_ADIS16136 },
+ { "adis16137", ID_ADIS16137 },
{ }
};
MODULE_DEVICE_TABLE(spi, adis16136_ids);
@@ -568,14 +574,13 @@ MODULE_DEVICE_TABLE(spi, adis16136_ids);
static struct spi_driver adis16136_driver = {
.driver = {
.name = "adis16136",
- .owner = THIS_MODULE,
},
.id_table = adis16136_ids,
.probe = adis16136_probe,
- .remove = adis16136_remove,
};
module_spi_driver(adis16136_driver);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("Analog Devices ADIS16133/ADIS16135/ADIS16136 gyroscope driver");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS("IIO_ADISLIB");