On 11/20/2012 09:15 PM, Lars-Peter Clausen wrote: > On 11/20/2012 10:05 PM, Jonathan Cameron wrote: >> On 11/20/2012 01:36 PM, Lars-Peter Clausen wrote: >>> This patch adds support for the ADIS16133, ADIS16135, ADIS16136 single channel >>> gyroscopes. The main difference between them is the sensor precision. >>> >>> Signed-off-by: Lars-Peter Clausen <lars@xxxxxxxxxx> >> A nice driver. >> >> The only thing I could pick up on was the 'interesting' comments alongside >> the 3db divisors. >> >> Still I just wanted to comment on something really ;) >> >> added to togreg branch of iio.git >> > > just remembered that I wanted to remove the __devinit/__devexit annotations > before sending this patch out, but then forgot about it. Can you fix this up? > Otherwise I'll just sent a follow up patch. Same for the adis16480 driver. Will fixup. I clean forgot that was going on... > > Thanks, > - Lars > >>> --- >>> drivers/iio/gyro/Kconfig | 9 + >>> drivers/iio/gyro/Makefile | 1 + >>> drivers/iio/gyro/adis16136.c | 581 +++++++++++++++++++++++++++++++++++++++++++ >>> 3 files changed, 591 insertions(+) >>> create mode 100644 drivers/iio/gyro/adis16136.c >>> >>> diff --git a/drivers/iio/gyro/Kconfig b/drivers/iio/gyro/Kconfig >>> index 21e27e2..48ed148 100644 >>> --- a/drivers/iio/gyro/Kconfig >>> +++ b/drivers/iio/gyro/Kconfig >>> @@ -3,6 +3,15 @@ >>> # >>> menu "Digital gyroscope sensors" >>> >>> +config ADIS16136 >>> + tristate "Analog devices ADIS16136 and similar gyroscopes driver" >>> + depends on SPI_MASTER >>> + select IIO_ADIS_LIB >>> + select IIO_ADIS_LIB_BUFFER if IIO_BUFFER >>> + help >>> + Say yes here to build support for the Analog Devices ADIS16133, ADIS16135, >>> + ADIS16136 gyroscope devices. >>> + >>> config HID_SENSOR_GYRO_3D >>> depends on HID_SENSOR_HUB >>> select IIO_BUFFER >>> diff --git a/drivers/iio/gyro/Makefile b/drivers/iio/gyro/Makefile >>> index 8a895d9..702a058 100644 >>> --- a/drivers/iio/gyro/Makefile >>> +++ b/drivers/iio/gyro/Makefile >>> @@ -2,4 +2,5 @@ >>> # Makefile for industrial I/O gyroscope sensor drivers >>> # >>> >>> +obj-$(CONFIG_ADIS16136) += adis16136.o >>> obj-$(CONFIG_HID_SENSOR_GYRO_3D) += hid-sensor-gyro-3d.o >>> diff --git a/drivers/iio/gyro/adis16136.c b/drivers/iio/gyro/adis16136.c >>> new file mode 100644 >>> index 0000000..277aa74 >>> --- /dev/null >>> +++ b/drivers/iio/gyro/adis16136.c >>> @@ -0,0 +1,581 @@ >>> +/* >>> + * ADIS16133/ADIS16135/ADIS16136 gyroscope driver >>> + * >>> + * Copyright 2012 Analog Devices Inc. >>> + * Author: Lars-Peter Clausen <lars@xxxxxxxxxx> >>> + * >>> + * 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/iio/iio.h> >>> +#include <linux/debugfs.h> >>> + >>> +#define ADIS16136_REG_FLASH_CNT 0x00 >>> +#define ADIS16136_REG_TEMP_OUT 0x02 >>> +#define ADIS16136_REG_GYRO_OUT2 0x04 >>> +#define ADIS16136_REG_GYRO_OUT 0x06 >>> +#define ADIS16136_REG_GYRO_OFF2 0x08 >>> +#define ADIS16136_REG_GYRO_OFF 0x0A >>> +#define ADIS16136_REG_ALM_MAG1 0x10 >>> +#define ADIS16136_REG_ALM_MAG2 0x12 >>> +#define ADIS16136_REG_ALM_SAMPL1 0x14 >>> +#define ADIS16136_REG_ALM_SAMPL2 0x16 >>> +#define ADIS16136_REG_ALM_CTRL 0x18 >>> +#define ADIS16136_REG_GPIO_CTRL 0x1A >>> +#define ADIS16136_REG_MSC_CTRL 0x1C >>> +#define ADIS16136_REG_SMPL_PRD 0x1E >>> +#define ADIS16136_REG_AVG_CNT 0x20 >>> +#define ADIS16136_REG_DEC_RATE 0x22 >>> +#define ADIS16136_REG_SLP_CTRL 0x24 >>> +#define ADIS16136_REG_DIAG_STAT 0x26 >>> +#define ADIS16136_REG_GLOB_CMD 0x28 >>> +#define ADIS16136_REG_LOT1 0x32 >>> +#define ADIS16136_REG_LOT2 0x34 >>> +#define ADIS16136_REG_LOT3 0x36 >>> +#define ADIS16136_REG_PROD_ID 0x38 >>> +#define ADIS16136_REG_SERIAL_NUM 0x3A >>> + >>> +#define ADIS16136_DIAG_STAT_FLASH_UPDATE_FAIL 2 >>> +#define ADIS16136_DIAG_STAT_SPI_FAIL 3 >>> +#define ADIS16136_DIAG_STAT_SELF_TEST_FAIL 5 >>> +#define ADIS16136_DIAG_STAT_FLASH_CHKSUM_FAIL 6 >>> + >>> +#define ADIS16136_MSC_CTRL_MEMORY_TEST BIT(11) >>> +#define ADIS16136_MSC_CTRL_SELF_TEST BIT(10) >>> + >>> +struct adis16136_chip_info { >>> + unsigned int precision; >>> + unsigned int fullscale; >>> +}; >>> + >>> +struct adis16136 { >>> + const struct adis16136_chip_info *chip_info; >>> + >>> + struct adis adis; >>> +}; >>> + >>> +#ifdef CONFIG_DEBUG_FS >>> + >>> +static ssize_t adis16136_show_serial(struct file *file, >>> + char __user *userbuf, size_t count, loff_t *ppos) >>> +{ >>> + struct adis16136 *adis16136 = file->private_data; >>> + uint16_t lot1, lot2, lot3, serial; >>> + char buf[20]; >>> + size_t len; >>> + int ret; >>> + >>> + ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_SERIAL_NUM, >>> + &serial); >>> + if (ret < 0) >>> + return ret; >>> + >>> + ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT1, &lot1); >>> + if (ret < 0) >>> + return ret; >>> + >>> + ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT2, &lot2); >>> + if (ret < 0) >>> + return ret; >>> + >>> + ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT3, &lot3); >>> + if (ret < 0) >>> + return ret; >>> + >>> + len = snprintf(buf, sizeof(buf), "%.4x%.4x%.4x-%.4x\n", lot1, lot2, >>> + lot3, serial); >>> + >>> + return simple_read_from_buffer(userbuf, count, ppos, buf, len); >>> +} >>> + >>> +static const struct file_operations adis16136_serial_fops = { >>> + .open = simple_open, >>> + .read = adis16136_show_serial, >>> + .llseek = default_llseek, >>> + .owner = THIS_MODULE, >>> +}; >>> + >>> +static int adis16136_show_product_id(void *arg, u64 *val) >>> +{ >>> + struct adis16136 *adis16136 = arg; >>> + u16 prod_id; >>> + int ret; >>> + >>> + ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_PROD_ID, >>> + &prod_id); >>> + if (ret < 0) >>> + return ret; >>> + >>> + *val = prod_id; >>> + >>> + return 0; >>> +} >>> +DEFINE_SIMPLE_ATTRIBUTE(adis16136_product_id_fops, >>> + adis16136_show_product_id, NULL, "%llu\n"); >>> + >>> +static int adis16136_show_flash_count(void *arg, u64 *val) >>> +{ >>> + struct adis16136 *adis16136 = arg; >>> + uint16_t flash_count; >>> + int ret; >>> + >>> + ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_FLASH_CNT, >>> + &flash_count); >>> + if (ret < 0) >>> + return ret; >>> + >>> + *val = flash_count; >>> + >>> + return 0; >>> +} >>> +DEFINE_SIMPLE_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); >>> + >>> + 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); >>> + >>> + return 0; >>> +} >>> + >>> +#else >>> + >>> +static int adis16136_debugfs_init(struct iio_dev *indio_dev) >>> +{ >>> + return 0; >>> +} >>> + >>> +#endif >>> + >>> +static int adis16136_set_freq(struct adis16136 *adis16136, unsigned int freq) >>> +{ >>> + unsigned int t; >>> + >>> + t = 32768 / freq; >>> + if (t < 0xf) >>> + t = 0xf; >>> + else if (t > 0xffff) >>> + t = 0xffff; >>> + else >>> + t--; >>> + >>> + return adis_write_reg_16(&adis16136->adis, ADIS16136_REG_SMPL_PRD, t); >>> +} >>> + >>> +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) >>> + return ret; >>> + >>> + *freq = 32768 / (t + 1); >>> + >>> + return 0; >>> +} >>> + >>> +static ssize_t adis16136_write_frequency(struct device *dev, >>> + struct device_attribute *attr, const char *buf, size_t len) >>> +{ >>> + struct iio_dev *indio_dev = dev_to_iio_dev(dev); >>> + struct adis16136 *adis16136 = iio_priv(indio_dev); >>> + long val; >>> + int ret; >>> + >>> + ret = kstrtol(buf, 10, &val); >>> + if (ret) >>> + return ret; >>> + >>> + if (val == 0) >>> + return -EINVAL; >>> + >>> + ret = adis16136_set_freq(adis16136, val); >>> + >>> + return ret ? ret : len; >>> +} >>> + >>> +static ssize_t adis16136_read_frequency(struct device *dev, >>> + struct device_attribute *attr, char *buf) >>> +{ >>> + struct iio_dev *indio_dev = dev_to_iio_dev(dev); >>> + struct adis16136 *adis16136 = iio_priv(indio_dev); >>> + unsigned int freq; >>> + int ret; >>> + >>> + ret = adis16136_get_freq(adis16136, &freq); >>> + if (ret < 0) >>> + return ret; >>> + >>> + return sprintf(buf, "%d\n", freq); >>> +} >>> + >>> +static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, >>> + adis16136_read_frequency, >>> + adis16136_write_frequency); >>> + >> I love the comments. Useful sounding but I have no idea what >> they actually mean! >>> +static const unsigned adis16136_3db_divisors[] = { >>> + [0] = 2, /* Special case */ >>> + [1] = 6, >>> + [2] = 12, >>> + [3] = 25, >>> + [4] = 50, >>> + [5] = 100, >>> + [6] = 200, >>> + [7] = 200, /* Not a valid setting */ >>> +}; >>> + >>> +static int adis16136_set_filter(struct iio_dev *indio_dev, int val) >>> +{ >>> + struct adis16136 *adis16136 = iio_priv(indio_dev); >>> + unsigned int freq; >>> + int i, ret; >>> + >>> + ret = adis16136_get_freq(adis16136, &freq); >>> + if (ret < 0) >>> + return ret; >>> + >>> + for (i = ARRAY_SIZE(adis16136_3db_divisors) - 1; i >= 1; i--) { >>> + if (freq / adis16136_3db_divisors[i] >= val) >>> + break; >>> + } >>> + >>> + return adis_write_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, i); >>> +} >>> + >>> +static int adis16136_get_filter(struct iio_dev *indio_dev, int *val) >>> +{ >>> + struct adis16136 *adis16136 = iio_priv(indio_dev); >>> + unsigned int freq; >>> + uint16_t val16; >>> + int ret; >>> + >>> + mutex_lock(&indio_dev->mlock); >>> + >>> + ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, &val16); >>> + if (ret < 0) >>> + goto err_unlock; >>> + >>> + ret = adis16136_get_freq(adis16136, &freq); >>> + if (ret < 0) >>> + goto err_unlock; >>> + >>> + *val = freq / adis16136_3db_divisors[val16 & 0x07]; >>> + >>> +err_unlock: >>> + mutex_unlock(&indio_dev->mlock); >>> + >>> + return ret ? ret : IIO_VAL_INT; >>> +} >>> + >>> +static int adis16136_read_raw(struct iio_dev *indio_dev, >>> + const struct iio_chan_spec *chan, int *val, int *val2, long info) >>> +{ >>> + struct adis16136 *adis16136 = iio_priv(indio_dev); >>> + uint32_t val32; >>> + int ret; >>> + >>> + switch (info) { >>> + case IIO_CHAN_INFO_RAW: >>> + return adis_single_conversion(indio_dev, chan, 0, val); >>> + case IIO_CHAN_INFO_SCALE: >>> + switch (chan->type) { >>> + case IIO_ANGL_VEL: >>> + *val = adis16136->chip_info->precision; >>> + *val2 = (adis16136->chip_info->fullscale << 16); >>> + return IIO_VAL_FRACTIONAL; >>> + case IIO_TEMP: >>> + *val = 10; >>> + *val2 = 697000; /* 0.010697 degree Celsius */ >>> + return IIO_VAL_INT_PLUS_MICRO; >>> + default: >>> + return -EINVAL; >>> + } >>> + case IIO_CHAN_INFO_CALIBBIAS: >>> + ret = adis_read_reg_32(&adis16136->adis, >>> + ADIS16136_REG_GYRO_OFF2, &val32); >>> + if (ret < 0) >>> + return ret; >>> + >>> + *val = sign_extend32(val32, 31); >>> + >>> + return IIO_VAL_INT; >>> + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: >>> + return adis16136_get_filter(indio_dev, val); >>> + default: >>> + return -EINVAL; >>> + } >>> +} >>> + >>> +static int adis16136_write_raw(struct iio_dev *indio_dev, >>> + const struct iio_chan_spec *chan, int val, int val2, long info) >>> +{ >>> + struct adis16136 *adis16136 = iio_priv(indio_dev); >>> + >>> + switch (info) { >>> + case IIO_CHAN_INFO_CALIBBIAS: >>> + return adis_write_reg_32(&adis16136->adis, >>> + ADIS16136_REG_GYRO_OFF2, val); >>> + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: >>> + return adis16136_set_filter(indio_dev, val); >>> + default: >>> + break; >>> + } >>> + >>> + return -EINVAL; >>> +} >>> + >>> +enum { >>> + ADIS16136_SCAN_GYRO, >>> + ADIS16136_SCAN_TEMP, >>> +}; >>> + >>> +static const struct iio_chan_spec adis16136_channels[] = { >>> + { >>> + .type = IIO_ANGL_VEL, >>> + .modified = 1, >>> + .channel2 = IIO_MOD_X, >>> + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | >>> + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | >>> + IIO_CHAN_INFO_SCALE_SHARED_BIT | >>> + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SEPARATE_BIT, >>> + .address = ADIS16136_REG_GYRO_OUT2, >>> + .scan_index = ADIS16136_SCAN_GYRO, >>> + .scan_type = { >>> + .sign = 's', >>> + .realbits = 32, >>> + .storagebits = 32, >>> + .endianness = IIO_BE, >>> + }, >>> + }, { >>> + .type = IIO_TEMP, >>> + .indexed = 1, >>> + .channel = 0, >>> + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | >>> + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, >>> + .address = ADIS16136_REG_TEMP_OUT, >>> + .scan_index = ADIS16136_SCAN_TEMP, >>> + .scan_type = { >>> + .sign = 's', >>> + .realbits = 16, >>> + .storagebits = 16, >>> + .endianness = IIO_BE, >>> + }, >>> + }, >>> + IIO_CHAN_SOFT_TIMESTAMP(2), >>> +}; >>> + >>> +static struct attribute *adis16136_attributes[] = { >>> + &iio_dev_attr_sampling_frequency.dev_attr.attr, >>> + NULL >>> +}; >>> + >>> +static const struct attribute_group adis16136_attribute_group = { >>> + .attrs = adis16136_attributes, >>> +}; >>> + >>> +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, >>> + .update_scan_mode = adis_update_scan_mode, >>> + .debugfs_reg_access = adis_debugfs_reg_access, >>> +}; >>> + >>> +static int adis16136_stop_device(struct iio_dev *indio_dev) >>> +{ >>> + struct adis16136 *adis16136 = iio_priv(indio_dev); >>> + int ret; >>> + >>> + ret = adis_write_reg_16(&adis16136->adis, ADIS16136_REG_SLP_CTRL, 0xff); >>> + if (ret) >>> + dev_err(&indio_dev->dev, >>> + "Could not power down device: %d\n", ret); >>> + >>> + return ret; >>> +} >>> + >>> +static int adis16136_initial_setup(struct iio_dev *indio_dev) >>> +{ >>> + struct adis16136 *adis16136 = iio_priv(indio_dev); >>> + unsigned int device_id; >>> + uint16_t prod_id; >>> + int ret; >>> + >>> + ret = adis_initial_startup(&adis16136->adis); >>> + if (ret) >>> + return ret; >>> + >>> + ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_PROD_ID, >>> + &prod_id); >>> + if (ret) >>> + return ret; >>> + >>> + sscanf(indio_dev->name, "adis%u\n", &device_id); >>> + >>> + if (prod_id != device_id) >>> + dev_warn(&indio_dev->dev, "Device ID(%u) and product ID(%u) do not match.", >>> + device_id, prod_id); >>> + >>> + return 0; >>> +} >>> + >>> +static const char * const adis16136_status_error_msgs[] = { >>> + [ADIS16136_DIAG_STAT_FLASH_UPDATE_FAIL] = "Flash update failed", >>> + [ADIS16136_DIAG_STAT_SPI_FAIL] = "SPI failure", >>> + [ADIS16136_DIAG_STAT_SELF_TEST_FAIL] = "Self test error", >>> + [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), >>> +}; >>> + >>> +enum adis16136_id { >>> + ID_ADIS16133, >>> + ID_ADIS16135, >>> + ID_ADIS16136, >>> +}; >>> + >>> +static const struct adis16136_chip_info adis16136_chip_info[] = { >>> + [ID_ADIS16133] = { >>> + .precision = IIO_DEGREE_TO_RAD(1200), >>> + .fullscale = 24000, >>> + }, >>> + [ID_ADIS16135] = { >>> + .precision = IIO_DEGREE_TO_RAD(300), >>> + .fullscale = 24000, >>> + }, >>> + [ID_ADIS16136] = { >>> + .precision = IIO_DEGREE_TO_RAD(450), >>> + .fullscale = 24623, >>> + }, >>> +}; >>> + >>> +static int __devinit 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; >>> + int ret; >>> + >>> + indio_dev = iio_device_alloc(sizeof(*adis16136)); >>> + if (indio_dev == NULL) >>> + return -ENOMEM; >>> + >>> + spi_set_drvdata(spi, indio_dev); >>> + >>> + 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); >>> + if (ret) >>> + goto error_free_dev; >>> + >>> + ret = adis_setup_buffer_and_trigger(&adis16136->adis, indio_dev, NULL); >>> + if (ret) >>> + goto error_free_dev; >>> + >>> + ret = adis16136_initial_setup(indio_dev); >>> + if (ret) >>> + goto error_cleanup_buffer; >>> + >>> + ret = iio_device_register(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 __devexit 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); >>> + >>> + adis_cleanup_buffer_and_trigger(&adis16136->adis, indio_dev); >>> + >>> + iio_device_free(indio_dev); >>> + >>> + return 0; >>> +} >>> + >>> +static const struct spi_device_id adis16136_ids[] = { >>> + { "adis16133", ID_ADIS16133 }, >>> + { "adis16135", ID_ADIS16135 }, >>> + { "adis16136", ID_ADIS16136 }, >>> + { } >>> +}; >>> +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 = __devexit_p(adis16136_remove), >>> +}; >>> +module_spi_driver(adis16136_driver); >>> + >>> +MODULE_AUTHOR("Lars-Peter Clausen <lars@xxxxxxxxxx>"); >>> +MODULE_DESCRIPTION("Analog Devices ADIS16133/ADIS16135/ADIS16136 gyroscope driver"); >>> +MODULE_LICENSE("GPL v2"); >>> > -- To unsubscribe from this list: send the line "unsubscribe linux-iio" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html