diff options
Diffstat (limited to 'drivers/iio/imu')
| -rw-r--r-- | drivers/iio/imu/Kconfig | 40 | ||||
| -rw-r--r-- | drivers/iio/imu/Makefile | 15 | ||||
| -rw-r--r-- | drivers/iio/imu/adis.c | 440 | ||||
| -rw-r--r-- | drivers/iio/imu/adis16400.h | 212 | ||||
| -rw-r--r-- | drivers/iio/imu/adis16400_buffer.c | 96 | ||||
| -rw-r--r-- | drivers/iio/imu/adis16400_core.c | 966 | ||||
| -rw-r--r-- | drivers/iio/imu/adis16480.c | 924 | ||||
| -rw-r--r-- | drivers/iio/imu/adis_buffer.c | 176 | ||||
| -rw-r--r-- | drivers/iio/imu/adis_trigger.c | 89 | ||||
| -rw-r--r-- | drivers/iio/imu/inv_mpu6050/Kconfig | 14 | ||||
| -rw-r--r-- | drivers/iio/imu/inv_mpu6050/Makefile | 6 | ||||
| -rw-r--r-- | drivers/iio/imu/inv_mpu6050/inv_mpu_core.c | 795 | ||||
| -rw-r--r-- | drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h | 246 | ||||
| -rw-r--r-- | drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c | 195 | ||||
| -rw-r--r-- | drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c | 155 |
15 files changed, 0 insertions, 4369 deletions
diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig deleted file mode 100644 index 4f40a10cb74..00000000000 --- a/drivers/iio/imu/Kconfig +++ /dev/null @@ -1,40 +0,0 @@ -# -# IIO imu drivers configuration -# -menu "Inertial measurement units" - -config ADIS16400 - tristate "Analog Devices ADIS16400 and similar IMU SPI driver" - depends on SPI - select IIO_ADIS_LIB - select IIO_ADIS_LIB_BUFFER if IIO_BUFFER - help - Say yes here to build support for Analog Devices adis16300, adis16344, - adis16350, adis16354, adis16355, adis16360, adis16362, adis16364, - adis16365, adis16400 and adis16405 triaxial inertial sensors - (adis16400 series also have magnetometers). - -config ADIS16480 - tristate "Analog Devices ADIS16480 and similar IMU driver" - depends on SPI - select IIO_ADIS_LIB - select IIO_ADIS_LIB_BUFFER if IIO_BUFFER - help - Say yes here to build support for Analog Devices ADIS16375, ADIS16480, - ADIS16485, ADIS16488 inertial sensors. - -endmenu - -config IIO_ADIS_LIB - tristate - help - A set of IO helper functions for the Analog Devices ADIS* device family. - -config IIO_ADIS_LIB_BUFFER - bool - select IIO_TRIGGERED_BUFFER - help - A set of buffer helper functions for the Analog Devices ADIS* device - family. - -source "drivers/iio/imu/inv_mpu6050/Kconfig" diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile deleted file mode 100644 index f2f56ceaed2..00000000000 --- a/drivers/iio/imu/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# -# Makefile for Inertial Measurement Units -# - -adis16400-y := adis16400_core.o -adis16400-$(CONFIG_IIO_BUFFER) += adis16400_buffer.o -obj-$(CONFIG_ADIS16400) += adis16400.o -obj-$(CONFIG_ADIS16480) += adis16480.o - -adis_lib-y += adis.o -adis_lib-$(CONFIG_IIO_ADIS_LIB_BUFFER) += adis_trigger.o -adis_lib-$(CONFIG_IIO_ADIS_LIB_BUFFER) += adis_buffer.o -obj-$(CONFIG_IIO_ADIS_LIB) += adis_lib.o - -obj-y += inv_mpu6050/ diff --git a/drivers/iio/imu/adis.c b/drivers/iio/imu/adis.c deleted file mode 100644 index 911255d41c1..00000000000 --- a/drivers/iio/imu/adis.c +++ /dev/null @@ -1,440 +0,0 @@ -/* - * Common library for ADIS16XXX devices - * - * Copyright 2012 Analog Devices Inc. - * Author: Lars-Peter Clausen <lars@metafoo.de> - * - * Licensed under the GPL-2 or later. - */ - -#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 <asm/unaligned.h> - -#include <linux/iio/iio.h> -#include <linux/iio/sysfs.h> -#include <linux/iio/buffer.h> -#include <linux/iio/imu/adis.h> - -#define ADIS_MSC_CTRL_DATA_RDY_EN BIT(2) -#define ADIS_MSC_CTRL_DATA_RDY_POL_HIGH BIT(1) -#define ADIS_MSC_CTRL_DATA_RDY_DIO2 BIT(0) -#define ADIS_GLOB_CMD_SW_RESET BIT(7) - -int adis_write_reg(struct adis *adis, unsigned int reg, - unsigned int value, unsigned int size) -{ - unsigned int page = reg / ADIS_PAGE_SIZE; - int ret, i; - struct spi_message msg; - struct spi_transfer xfers[] = { - { - .tx_buf = adis->tx, - .bits_per_word = 8, - .len = 2, - .cs_change = 1, - .delay_usecs = adis->data->write_delay, - }, { - .tx_buf = adis->tx + 2, - .bits_per_word = 8, - .len = 2, - .cs_change = 1, - .delay_usecs = adis->data->write_delay, - }, { - .tx_buf = adis->tx + 4, - .bits_per_word = 8, - .len = 2, - .cs_change = 1, - .delay_usecs = adis->data->write_delay, - }, { - .tx_buf = adis->tx + 6, - .bits_per_word = 8, - .len = 2, - .delay_usecs = adis->data->write_delay, - }, { - .tx_buf = adis->tx + 8, - .bits_per_word = 8, - .len = 2, - .delay_usecs = adis->data->write_delay, - }, - }; - - mutex_lock(&adis->txrx_lock); - - spi_message_init(&msg); - - if (adis->current_page != page) { - adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID); - adis->tx[1] = page; - spi_message_add_tail(&xfers[0], &msg); - } - - switch (size) { - case 4: - adis->tx[8] = ADIS_WRITE_REG(reg + 3); - adis->tx[9] = (value >> 24) & 0xff; - adis->tx[6] = ADIS_WRITE_REG(reg + 2); - adis->tx[7] = (value >> 16) & 0xff; - case 2: - adis->tx[4] = ADIS_WRITE_REG(reg + 1); - adis->tx[5] = (value >> 8) & 0xff; - case 1: - adis->tx[2] = ADIS_WRITE_REG(reg); - adis->tx[3] = value & 0xff; - break; - default: - ret = -EINVAL; - goto out_unlock; - } - - xfers[size].cs_change = 0; - - for (i = 1; i <= size; i++) - spi_message_add_tail(&xfers[i], &msg); - - ret = spi_sync(adis->spi, &msg); - if (ret) { - dev_err(&adis->spi->dev, "Failed to write register 0x%02X: %d\n", - reg, ret); - } else { - adis->current_page = page; - } - -out_unlock: - mutex_unlock(&adis->txrx_lock); - - return ret; -} -EXPORT_SYMBOL_GPL(adis_write_reg); - -/** - * adis_read_reg() - read 2 bytes from a 16-bit register - * @adis: The adis device - * @reg: The address of the lower of the two registers - * @val: The value read back from the device - */ -int adis_read_reg(struct adis *adis, unsigned int reg, - unsigned int *val, unsigned int size) -{ - unsigned int page = reg / ADIS_PAGE_SIZE; - struct spi_message msg; - int ret; - struct spi_transfer xfers[] = { - { - .tx_buf = adis->tx, - .bits_per_word = 8, - .len = 2, - .cs_change = 1, - .delay_usecs = adis->data->write_delay, - }, { - .tx_buf = adis->tx + 2, - .bits_per_word = 8, - .len = 2, - .cs_change = 1, - .delay_usecs = adis->data->read_delay, - }, { - .tx_buf = adis->tx + 4, - .rx_buf = adis->rx, - .bits_per_word = 8, - .len = 2, - .cs_change = 1, - .delay_usecs = adis->data->read_delay, - }, { - .rx_buf = adis->rx + 2, - .bits_per_word = 8, - .len = 2, - .delay_usecs = adis->data->read_delay, - }, - }; - - mutex_lock(&adis->txrx_lock); - spi_message_init(&msg); - - if (adis->current_page != page) { - adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID); - adis->tx[1] = page; - spi_message_add_tail(&xfers[0], &msg); - } - - switch (size) { - case 4: - adis->tx[2] = ADIS_READ_REG(reg + 2); - adis->tx[3] = 0; - spi_message_add_tail(&xfers[1], &msg); - case 2: - adis->tx[4] = ADIS_READ_REG(reg); - adis->tx[5] = 0; - spi_message_add_tail(&xfers[2], &msg); - spi_message_add_tail(&xfers[3], &msg); - break; - default: - ret = -EINVAL; - goto out_unlock; - } - - ret = spi_sync(adis->spi, &msg); - if (ret) { - dev_err(&adis->spi->dev, "Failed to read register 0x%02X: %d\n", - reg, ret); - goto out_unlock; - } else { - adis->current_page = page; - } - - switch (size) { - case 4: - *val = get_unaligned_be32(adis->rx); - break; - case 2: - *val = get_unaligned_be16(adis->rx + 2); - break; - } - -out_unlock: - mutex_unlock(&adis->txrx_lock); - - return ret; -} -EXPORT_SYMBOL_GPL(adis_read_reg); - -#ifdef CONFIG_DEBUG_FS - -int adis_debugfs_reg_access(struct iio_dev *indio_dev, - unsigned int reg, unsigned int writeval, unsigned int *readval) -{ - struct adis *adis = iio_device_get_drvdata(indio_dev); - - if (readval) { - uint16_t val16; - int ret; - - ret = adis_read_reg_16(adis, reg, &val16); - *readval = val16; - - return ret; - } else { - return adis_write_reg_16(adis, reg, writeval); - } -} -EXPORT_SYMBOL(adis_debugfs_reg_access); - -#endif - -/** - * adis_enable_irq() - Enable or disable data ready IRQ - * @adis: The adis device - * @enable: Whether to enable the IRQ - * - * Returns 0 on success, negative error code otherwise - */ -int adis_enable_irq(struct adis *adis, bool enable) -{ - int ret = 0; - uint16_t msc; - - if (adis->data->enable_irq) - return adis->data->enable_irq(adis, enable); - - ret = adis_read_reg_16(adis, adis->data->msc_ctrl_reg, &msc); - if (ret) - goto error_ret; - - msc |= ADIS_MSC_CTRL_DATA_RDY_POL_HIGH; - msc &= ~ADIS_MSC_CTRL_DATA_RDY_DIO2; - if (enable) - msc |= ADIS_MSC_CTRL_DATA_RDY_EN; - else - msc &= ~ADIS_MSC_CTRL_DATA_RDY_EN; - - ret = adis_write_reg_16(adis, adis->data->msc_ctrl_reg, msc); - -error_ret: - return ret; -} -EXPORT_SYMBOL(adis_enable_irq); - -/** - * adis_check_status() - Check the device for error conditions - * @adis: The adis device - * - * Returns 0 on success, a negative error code otherwise - */ -int adis_check_status(struct adis *adis) -{ - uint16_t status; - int ret; - int i; - - ret = adis_read_reg_16(adis, adis->data->diag_stat_reg, &status); - if (ret < 0) - return ret; - - status &= adis->data->status_error_mask; - - if (status == 0) - return 0; - - for (i = 0; i < 16; ++i) { - if (status & BIT(i)) { - dev_err(&adis->spi->dev, "%s.\n", - adis->data->status_error_msgs[i]); - } - } - - return -EIO; -} -EXPORT_SYMBOL_GPL(adis_check_status); - -/** - * adis_reset() - Reset the device - * @adis: The adis device - * - * Returns 0 on success, a negative error code otherwise - */ -int adis_reset(struct adis *adis) -{ - int ret; - - ret = adis_write_reg_8(adis, adis->data->glob_cmd_reg, - ADIS_GLOB_CMD_SW_RESET); - if (ret) - dev_err(&adis->spi->dev, "Failed to reset device: %d\n", ret); - - return ret; -} -EXPORT_SYMBOL_GPL(adis_reset); - -static int adis_self_test(struct adis *adis) -{ - int ret; - - ret = adis_write_reg_16(adis, adis->data->msc_ctrl_reg, - adis->data->self_test_mask); - if (ret) { - dev_err(&adis->spi->dev, "Failed to initiate self test: %d\n", - ret); - return ret; - } - - msleep(adis->data->startup_delay); - - return adis_check_status(adis); -} - -/** - * adis_inital_startup() - Performs device self-test - * @adis: The adis device - * - * Returns 0 if the device is operational, a negative error code otherwise. - * - * This function should be called early on in the device initialization sequence - * to ensure that the device is in a sane and known state and that it is usable. - */ -int adis_initial_startup(struct adis *adis) -{ - int ret; - - ret = adis_self_test(adis); - if (ret) { - dev_err(&adis->spi->dev, "Self-test failed, trying reset.\n"); - adis_reset(adis); - msleep(adis->data->startup_delay); - ret = adis_self_test(adis); - if (ret) { - dev_err(&adis->spi->dev, "Second self-test failed, giving up.\n"); - return ret; - } - } - - return 0; -} -EXPORT_SYMBOL_GPL(adis_initial_startup); - -/** - * adis_single_conversion() - Performs a single sample conversion - * @indio_dev: The IIO device - * @chan: The IIO channel - * @error_mask: Mask for the error bit - * @val: Result of the conversion - * - * Returns IIO_VAL_INT on success, a negative error code otherwise. - * - * The function performs a single conversion on a given channel and post - * processes the value accordingly to the channel spec. If a error_mask is given - * the function will check if the mask is set in the returned raw value. If it - * is set the function will perform a self-check. If the device does not report - * a error bit in the channels raw value set error_mask to 0. - */ -int adis_single_conversion(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, unsigned int error_mask, int *val) -{ - struct adis *adis = iio_device_get_drvdata(indio_dev); - unsigned int uval; - int ret; - - mutex_lock(&indio_dev->mlock); - - ret = adis_read_reg(adis, chan->address, &uval, - chan->scan_type.storagebits / 8); - if (ret) - goto err_unlock; - - if (uval & error_mask) { - ret = adis_check_status(adis); - if (ret) - goto err_unlock; - } - - if (chan->scan_type.sign == 's') - *val = sign_extend32(uval, chan->scan_type.realbits - 1); - else - *val = uval & ((1 << chan->scan_type.realbits) - 1); - - ret = IIO_VAL_INT; -err_unlock: - mutex_unlock(&indio_dev->mlock); - return ret; -} -EXPORT_SYMBOL_GPL(adis_single_conversion); - -/** - * adis_init() - Initialize adis device structure - * @adis: The adis device - * @indio_dev: The iio device - * @spi: The spi device - * @data: Chip specific data - * - * Returns 0 on success, a negative error code otherwise. - * - * This function must be called, before any other adis helper function may be - * called. - */ -int adis_init(struct adis *adis, struct iio_dev *indio_dev, - struct spi_device *spi, const struct adis_data *data) -{ - mutex_init(&adis->txrx_lock); - adis->spi = spi; - adis->data = data; - iio_device_set_drvdata(indio_dev, adis); - - if (data->has_paging) { - /* Need to set the page before first read/write */ - adis->current_page = -1; - } else { - /* Page will always be 0 */ - adis->current_page = 0; - } - - return adis_enable_irq(adis, false); -} -EXPORT_SYMBOL_GPL(adis_init); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); -MODULE_DESCRIPTION("Common library code for ADIS16XXX devices"); diff --git a/drivers/iio/imu/adis16400.h b/drivers/iio/imu/adis16400.h deleted file mode 100644 index 2f8f9d63238..00000000000 --- a/drivers/iio/imu/adis16400.h +++ /dev/null @@ -1,212 +0,0 @@ -/* - * adis16400.h support Analog Devices ADIS16400 - * 3d 18g accelerometers, - * 3d gyroscopes, - * 3d 2.5gauss magnetometers via SPI - * - * Copyright (c) 2009 Manuel Stahl <manuel.stahl@iis.fraunhofer.de> - * Copyright (c) 2007 Jonathan Cameron <jic23@kernel.org> - * - * Loosely based upon lis3l02dq.h - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef SPI_ADIS16400_H_ -#define SPI_ADIS16400_H_ - -#include <linux/iio/imu/adis.h> - -#define ADIS16400_STARTUP_DELAY 290 /* ms */ -#define ADIS16400_MTEST_DELAY 90 /* ms */ - -#define ADIS16400_FLASH_CNT 0x00 /* Flash memory write count */ -#define ADIS16400_SUPPLY_OUT 0x02 /* Power supply measurement */ -#define ADIS16400_XGYRO_OUT 0x04 /* X-axis gyroscope output */ -#define ADIS16400_YGYRO_OUT 0x06 /* Y-axis gyroscope output */ -#define ADIS16400_ZGYRO_OUT 0x08 /* Z-axis gyroscope output */ -#define ADIS16400_XACCL_OUT 0x0A /* X-axis accelerometer output */ -#define ADIS16400_YACCL_OUT 0x0C /* Y-axis accelerometer output */ -#define ADIS16400_ZACCL_OUT 0x0E /* Z-axis accelerometer output */ -#define ADIS16400_XMAGN_OUT 0x10 /* X-axis magnetometer measurement */ -#define ADIS16400_YMAGN_OUT 0x12 /* Y-axis magnetometer measurement */ -#define ADIS16400_ZMAGN_OUT 0x14 /* Z-axis magnetometer measurement */ -#define ADIS16400_TEMP_OUT 0x16 /* Temperature output */ -#define ADIS16400_AUX_ADC 0x18 /* Auxiliary ADC measurement */ - -#define ADIS16350_XTEMP_OUT 0x10 /* X-axis gyroscope temperature measurement */ -#define ADIS16350_YTEMP_OUT 0x12 /* Y-axis gyroscope temperature measurement */ -#define ADIS16350_ZTEMP_OUT 0x14 /* Z-axis gyroscope temperature measurement */ - -#define ADIS16300_PITCH_OUT 0x12 /* X axis inclinometer output measurement */ -#define ADIS16300_ROLL_OUT 0x14 /* Y axis inclinometer output measurement */ -#define ADIS16300_AUX_ADC 0x16 /* Auxiliary ADC measurement */ - -#define ADIS16448_BARO_OUT 0x16 /* Barometric pressure output */ -#define ADIS16448_TEMP_OUT 0x18 /* Temperature output */ - -/* Calibration parameters */ -#define ADIS16400_XGYRO_OFF 0x1A /* X-axis gyroscope bias offset factor */ -#define ADIS16400_YGYRO_OFF 0x1C /* Y-axis gyroscope bias offset factor */ -#define ADIS16400_ZGYRO_OFF 0x1E /* Z-axis gyroscope bias offset factor */ -#define ADIS16400_XACCL_OFF 0x20 /* X-axis acceleration bias offset factor */ -#define ADIS16400_YACCL_OFF 0x22 /* Y-axis acceleration bias offset factor */ -#define ADIS16400_ZACCL_OFF 0x24 /* Z-axis acceleration bias offset factor */ -#define ADIS16400_XMAGN_HIF 0x26 /* X-axis magnetometer, hard-iron factor */ -#define ADIS16400_YMAGN_HIF 0x28 /* Y-axis magnetometer, hard-iron factor */ -#define ADIS16400_ZMAGN_HIF 0x2A /* Z-axis magnetometer, hard-iron factor */ -#define ADIS16400_XMAGN_SIF 0x2C /* X-axis magnetometer, soft-iron factor */ -#define ADIS16400_YMAGN_SIF 0x2E /* Y-axis magnetometer, soft-iron factor */ -#define ADIS16400_ZMAGN_SIF 0x30 /* Z-axis magnetometer, soft-iron factor */ - -#define ADIS16400_GPIO_CTRL 0x32 /* Auxiliary digital input/output control */ -#define ADIS16400_MSC_CTRL 0x34 /* Miscellaneous control */ -#define ADIS16400_SMPL_PRD 0x36 /* Internal sample period (rate) control */ -#define ADIS16400_SENS_AVG 0x38 /* Dynamic range and digital filter control */ -#define ADIS16400_SLP_CNT 0x3A /* Sleep mode control */ -#define ADIS16400_DIAG_STAT 0x3C /* System status */ - -/* Alarm functions */ -#define ADIS16400_GLOB_CMD 0x3E /* System command */ -#define ADIS16400_ALM_MAG1 0x40 /* Alarm 1 amplitude threshold */ -#define ADIS16400_ALM_MAG2 0x42 /* Alarm 2 amplitude threshold */ -#define ADIS16400_ALM_SMPL1 0x44 /* Alarm 1 sample size */ -#define ADIS16400_ALM_SMPL2 0x46 /* Alarm 2 sample size */ -#define ADIS16400_ALM_CTRL 0x48 /* Alarm control */ -#define ADIS16400_AUX_DAC 0x4A /* Auxiliary DAC data */ - -#define ADIS16334_LOT_ID1 0x52 /* Lot identification code 1 */ -#define ADIS16334_LOT_ID2 0x54 /* Lot identification code 2 */ -#define ADIS16400_PRODUCT_ID 0x56 /* Product identifier */ -#define ADIS16334_SERIAL_NUMBER 0x58 /* Serial number, lot specific */ - -#define ADIS16400_ERROR_ACTIVE (1<<14) -#define ADIS16400_NEW_DATA (1<<14) - -/* MSC_CTRL */ -#define ADIS16400_MSC_CTRL_MEM_TEST (1<<11) -#define ADIS16400_MSC_CTRL_INT_SELF_TEST (1<<10) -#define ADIS16400_MSC_CTRL_NEG_SELF_TEST (1<<9) -#define ADIS16400_MSC_CTRL_POS_SELF_TEST (1<<8) -#define ADIS16400_MSC_CTRL_GYRO_BIAS (1<<7) -#define ADIS16400_MSC_CTRL_ACCL_ALIGN (1<<6) -#define ADIS16400_MSC_CTRL_DATA_RDY_EN (1<<2) -#define ADIS16400_MSC_CTRL_DATA_RDY_POL_HIGH (1<<1) -#define ADIS16400_MSC_CTRL_DATA_RDY_DIO2 (1<<0) - -/* SMPL_PRD */ -#define ADIS16400_SMPL_PRD_TIME_BASE (1<<7) -#define ADIS16400_SMPL_PRD_DIV_MASK 0x7F - -/* DIAG_STAT */ -#define ADIS16400_DIAG_STAT_ZACCL_FAIL 15 -#define ADIS16400_DIAG_STAT_YACCL_FAIL 14 -#define ADIS16400_DIAG_STAT_XACCL_FAIL 13 -#define ADIS16400_DIAG_STAT_XGYRO_FAIL 12 -#define ADIS16400_DIAG_STAT_YGYRO_FAIL 11 -#define ADIS16400_DIAG_STAT_ZGYRO_FAIL 10 -#define ADIS16400_DIAG_STAT_ALARM2 9 -#define ADIS16400_DIAG_STAT_ALARM1 8 -#define ADIS16400_DIAG_STAT_FLASH_CHK 6 -#define ADIS16400_DIAG_STAT_SELF_TEST 5 -#define ADIS16400_DIAG_STAT_OVERFLOW 4 -#define ADIS16400_DIAG_STAT_SPI_FAIL 3 -#define ADIS16400_DIAG_STAT_FLASH_UPT 2 -#define ADIS16400_DIAG_STAT_POWER_HIGH 1 -#define ADIS16400_DIAG_STAT_POWER_LOW 0 - -/* GLOB_CMD */ -#define ADIS16400_GLOB_CMD_SW_RESET (1<<7) -#define ADIS16400_GLOB_CMD_P_AUTO_NULL (1<<4) -#define ADIS16400_GLOB_CMD_FLASH_UPD (1<<3) -#define ADIS16400_GLOB_CMD_DAC_LATCH (1<<2) -#define ADIS16400_GLOB_CMD_FAC_CALIB (1<<1) -#define ADIS16400_GLOB_CMD_AUTO_NULL (1<<0) - -/* SLP_CNT */ -#define ADIS16400_SLP_CNT_POWER_OFF (1<<8) - -#define ADIS16334_RATE_DIV_SHIFT 8 -#define ADIS16334_RATE_INT_CLK BIT(0) - -#define ADIS16400_SPI_SLOW (u32)(300 * 1000) -#define ADIS16400_SPI_BURST (u32)(1000 * 1000) -#define ADIS16400_SPI_FAST (u32)(2000 * 1000) - -#define ADIS16400_HAS_PROD_ID BIT(0) -#define ADIS16400_NO_BURST BIT(1) -#define ADIS16400_HAS_SLOW_MODE BIT(2) -#define ADIS16400_HAS_SERIAL_NUMBER BIT(3) - -struct adis16400_state; - -struct adis16400_chip_info { - const struct iio_chan_spec *channels; - const int num_channels; - const long flags; - unsigned int gyro_scale_micro; - unsigned int accel_scale_micro; - int temp_scale_nano; - int temp_offset; - int (*set_freq)(struct adis16400_state *st, unsigned int freq); - int (*get_freq)(struct adis16400_state *st); -}; - -/** - * struct adis16400_state - device instance specific data - * @variant: chip variant info - * @filt_int: integer part of requested filter frequency - * @adis: adis device - **/ -struct adis16400_state { - struct adis16400_chip_info *variant; - int filt_int; - - struct adis adis; -}; - -/* At the moment triggers are only used for ring buffer - * filling. This may change! - */ - -enum { - ADIS16400_SCAN_SUPPLY, - ADIS16400_SCAN_GYRO_X, - ADIS16400_SCAN_GYRO_Y, - ADIS16400_SCAN_GYRO_Z, - ADIS16400_SCAN_ACC_X, - ADIS16400_SCAN_ACC_Y, - ADIS16400_SCAN_ACC_Z, - ADIS16400_SCAN_MAGN_X, - ADIS16400_SCAN_MAGN_Y, - ADIS16400_SCAN_MAGN_Z, - ADIS16400_SCAN_BARO, - ADIS16350_SCAN_TEMP_X, - ADIS16350_SCAN_TEMP_Y, - ADIS16350_SCAN_TEMP_Z, - ADIS16300_SCAN_INCLI_X, - ADIS16300_SCAN_INCLI_Y, - ADIS16400_SCAN_ADC, -}; - -#ifdef CONFIG_IIO_BUFFER - -ssize_t adis16400_read_data_from_ring(struct device *dev, - struct device_attribute *attr, - char *buf); - - -int adis16400_update_scan_mode(struct iio_dev *indio_dev, - const unsigned long *scan_mask); -irqreturn_t adis16400_trigger_handler(int irq, void *p); - -#else /* CONFIG_IIO_BUFFER */ - -#define adis16400_update_scan_mode NULL -#define adis16400_trigger_handler NULL - -#endif /* CONFIG_IIO_BUFFER */ - -#endif /* SPI_ADIS16400_H_ */ diff --git a/drivers/iio/imu/adis16400_buffer.c b/drivers/iio/imu/adis16400_buffer.c deleted file mode 100644 index 054c01d6e73..00000000000 --- a/drivers/iio/imu/adis16400_buffer.c +++ /dev/null @@ -1,96 +0,0 @@ -#include <linux/interrupt.h> -#include <linux/mutex.h> -#include <linux/kernel.h> -#include <linux/spi/spi.h> -#include <linux/slab.h> -#include <linux/bitops.h> -#include <linux/export.h> - -#include <linux/iio/iio.h> -#include <linux/iio/buffer.h> -#include <linux/iio/triggered_buffer.h> -#include <linux/iio/trigger_consumer.h> - -#include "adis16400.h" - -int adis16400_update_scan_mode(struct iio_dev *indio_dev, - const unsigned long *scan_mask) -{ - struct adis16400_state *st = iio_priv(indio_dev); - struct adis *adis = &st->adis; - uint16_t *tx, *rx; - - if (st->variant->flags & ADIS16400_NO_BURST) - return adis_update_scan_mode(indio_dev, scan_mask); - - kfree(adis->xfer); - kfree(adis->buffer); - - adis->xfer = kcalloc(2, sizeof(*adis->xfer), GFP_KERNEL); - if (!adis->xfer) - return -ENOMEM; - - adis->buffer = kzalloc(indio_dev->scan_bytes + sizeof(u16), - GFP_KERNEL); - if (!adis->buffer) - return -ENOMEM; - - rx = adis->buffer; - tx = adis->buffer + indio_dev->scan_bytes; - - tx[0] = ADIS_READ_REG(ADIS16400_GLOB_CMD); - tx[1] = 0; - - adis->xfer[0].tx_buf = tx; - adis->xfer[0].bits_per_word = 8; - adis->xfer[0].len = 2; - adis->xfer[1].tx_buf = tx; - adis->xfer[1].bits_per_word = 8; - adis->xfer[1].len = indio_dev->scan_bytes; - - spi_message_init(&adis->msg); - spi_message_add_tail(&adis->xfer[0], &adis->msg); - spi_message_add_tail(&adis->xfer[1], &adis->msg); - - return 0; -} - -irqreturn_t adis16400_trigger_handler(int irq, void *p) -{ - struct iio_poll_func *pf = p; - struct iio_dev *indio_dev = pf->indio_dev; - struct adis16400_state *st = iio_priv(indio_dev); - struct adis *adis = &st->adis; - u32 old_speed_hz = st->adis.spi->max_speed_hz; - int ret; - - if (!adis->buffer) - return -ENOMEM; - - if (!(st->variant->flags & ADIS16400_NO_BURST) && - st->adis.spi->max_speed_hz > ADIS16400_SPI_BURST) { - st->adis.spi->max_speed_hz = ADIS16400_SPI_BURST; - spi_setup(st->adis.spi); - } - - ret = spi_sync(adis->spi, &adis->msg); - if (ret) - dev_err(&adis->spi->dev, "Failed to read data: %d\n", ret); - - if (!(st->variant->flags & ADIS16400_NO_BURST)) { - st->adis.spi->max_speed_hz = old_speed_hz; - spi_setup(st->adis.spi); - } - - /* Guaranteed to be aligned with 8 byte boundary */ - if (indio_dev->scan_timestamp) { - void *b = adis->buffer + indio_dev->scan_bytes - sizeof(s64); - *(s64 *)b = pf->timestamp; - } - - iio_push_to_buffers(indio_dev, adis->buffer); - - iio_trigger_notify_done(indio_dev->trig); - - return IRQ_HANDLED; -} diff --git a/drivers/iio/imu/adis16400_core.c b/drivers/iio/imu/adis16400_core.c deleted file mode 100644 index f60591f0b92..00000000000 --- a/drivers/iio/imu/adis16400_core.c +++ /dev/null @@ -1,966 +0,0 @@ -/* - * adis16400.c support Analog Devices ADIS16400/5 - * 3d 2g Linear Accelerometers, - * 3d Gyroscopes, - * 3d Magnetometers via SPI - * - * Copyright (c) 2009 Manuel Stahl <manuel.stahl@iis.fraunhofer.de> - * Copyright (c) 2007 Jonathan Cameron <jic23@kernel.org> - * Copyright (c) 2011 Analog Devices Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ - -#include <linux/interrupt.h> -#include <linux/irq.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/list.h> -#include <linux/module.h> -#include <linux/debugfs.h> - -#include <linux/iio/iio.h> -#include <linux/iio/sysfs.h> -#include <linux/iio/buffer.h> - -#include "adis16400.h" - -#ifdef CONFIG_DEBUG_FS - -static ssize_t adis16400_show_serial_number(struct file *file, - char __user *userbuf, size_t count, loff_t *ppos) -{ - struct adis16400_state *st = file->private_data; - u16 lot1, lot2, serial_number; - char buf[16]; - size_t len; - int ret; - - ret = adis_read_reg_16(&st->adis, ADIS16334_LOT_ID1, &lot1); - if (ret < 0) - return ret; - - ret = adis_read_reg_16(&st->adis, ADIS16334_LOT_ID2, &lot2); - if (ret < 0) - return ret; - - ret = adis_read_reg_16(&st->adis, ADIS16334_SERIAL_NUMBER, - &serial_number); - if (ret < 0) - return ret; - - len = snprintf(buf, sizeof(buf), "%.4x-%.4x-%.4x\n", lot1, lot2, - serial_number); - - return simple_read_from_buffer(userbuf, count, ppos, buf, len); -} - -static const struct file_operations adis16400_serial_number_fops = { - .open = simple_open, - .read = adis16400_show_serial_number, - .llseek = default_llseek, - .owner = THIS_MODULE, -}; - -static int adis16400_show_product_id(void *arg, u64 *val) -{ - struct adis16400_state *st = arg; - uint16_t prod_id; - int ret; - - ret = adis_read_reg_16(&st->adis, ADIS16400_PRODUCT_ID, &prod_id); - if (ret < 0) - return ret; - - *val = prod_id; - - return 0; -} -DEFINE_SIMPLE_ATTRIBUTE(adis16400_product_id_fops, - adis16400_show_product_id, NULL, "%lld\n"); - -static int adis16400_show_flash_count(void *arg, u64 *val) -{ - struct adis16400_state *st = arg; - uint16_t flash_count; - int ret; - - ret = adis_read_reg_16(&st->adis, ADIS16400_FLASH_CNT, &flash_count); - if (ret < 0) - return ret; - - *val = flash_count; - - return 0; -} -DEFINE_SIMPLE_ATTRIBUTE(adis16400_flash_count_fops, - adis16400_show_flash_count, NULL, "%lld\n"); - -static int adis16400_debugfs_init(struct iio_dev *indio_dev) -{ - struct adis16400_state *st = iio_priv(indio_dev); - - if (st->variant->flags & ADIS16400_HAS_SERIAL_NUMBER) - debugfs_create_file("serial_number", 0400, - indio_dev->debugfs_dentry, st, - &adis16400_serial_number_fops); - if (st->variant->flags & ADIS16400_HAS_PROD_ID) - debugfs_create_file("product_id", 0400, - indio_dev->debugfs_dentry, st, - &adis16400_product_id_fops); - debugfs_create_file("flash_count", 0400, indio_dev->debugfs_dentry, - st, &adis16400_flash_count_fops); - - return 0; -} - -#else - -static int adis16400_debugfs_init(struct iio_dev *indio_dev) -{ - return 0; -} - -#endif - -enum adis16400_chip_variant { - ADIS16300, - ADIS16334, - ADIS16350, - ADIS16360, - ADIS16362, - ADIS16364, - ADIS16400, - ADIS16448, -}; - -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); - if (ret < 0) - return ret; - - t >>= ADIS16334_RATE_DIV_SHIFT; - - return 819200 >> t; -} - -static int adis16334_set_freq(struct adis16400_state *st, unsigned int freq) -{ - unsigned int t; - - if (freq < 819200) - t = ilog2(819200 / freq); - else - t = 0; - - if (t > 0x31) - t = 0x31; - - t <<= ADIS16334_RATE_DIV_SHIFT; - t |= ADIS16334_RATE_INT_CLK; - - return adis_write_reg_16(&st->adis, ADIS16400_SMPL_PRD, t); -} - -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); - if (ret < 0) - return ret; - - sps = (t & ADIS16400_SMPL_PRD_TIME_BASE) ? 52851 : 1638404; - sps /= (t & ADIS16400_SMPL_PRD_DIV_MASK) + 1; - - return sps; -} - -static int adis16400_set_freq(struct adis16400_state *st, unsigned int freq) -{ - unsigned int t; - uint8_t val = 0; - - t = 1638404 / freq; - if (t >= 128) { - val |= ADIS16400_SMPL_PRD_TIME_BASE; - t = 52851 / freq; - if (t >= 128) - t = 127; - } else if (t != 0) { - t--; - } - - val |= t; - - if (t >= 0x0A || (val & ADIS16400_SMPL_PRD_TIME_BASE)) - st->adis.spi->max_speed_hz = ADIS16400_SPI_SLOW; - else - st->adis.spi->max_speed_hz = ADIS16400_SPI_FAST; - - return adis_write_reg_8(&st->adis, ADIS16400_SMPL_PRD, val); -} - -static ssize_t adis16400_read_frequency(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct adis16400_state *st = iio_priv(indio_dev); - int ret; - - ret = st->variant->get_freq(st); - if (ret < 0) - return ret; - - return sprintf(buf, "%d.%.3d\n", ret / 1000, ret % 1000); -} - -static const unsigned adis16400_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 adis16400_set_filter(struct iio_dev *indio_dev, int sps, int val) -{ - struct adis16400_state *st = iio_priv(indio_dev); - uint16_t val16; - int i, ret; - - for (i = ARRAY_SIZE(adis16400_3db_divisors) - 1; i >= 1; i--) { - if (sps / adis16400_3db_divisors[i] >= val) - break; - } - - ret = adis_read_reg_16(&st->adis, ADIS16400_SENS_AVG, &val16); - if (ret < 0) - return ret; - - ret = adis_write_reg_16(&st->adis, ADIS16400_SENS_AVG, - (val16 & ~0x07) | i); - return ret; -} - -static ssize_t adis16400_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 adis16400_state *st = iio_priv(indio_dev); - int i, f, val; - int ret; - - ret = iio_str_to_fixpoint(buf, 100, &i, &f); - if (ret) - return ret; - - val = i * 1000 + f; - - if (val <= 0) - return -EINVAL; - - mutex_lock(&indio_dev->mlock); - st->variant->set_freq(st, val); - mutex_unlock(&indio_dev->mlock); - - return ret ? ret : len; -} - -/* Power down the device */ -static int adis16400_stop_device(struct iio_dev *indio_dev) -{ - struct adis16400_state *st = iio_priv(indio_dev); - int ret; - - ret = adis_write_reg_16(&st->adis, ADIS16400_SLP_CNT, - ADIS16400_SLP_CNT_POWER_OFF); - if (ret) - dev_err(&indio_dev->dev, - "problem with turning device off: SLP_CNT"); - - return ret; -} - -static int adis16400_initial_setup(struct iio_dev *indio_dev) -{ - struct adis16400_state *st = iio_priv(indio_dev); - uint16_t prod_id, smp_prd; - unsigned int device_id; - int ret; - - /* use low spi speed for init if the device has a slow mode */ - if (st->variant->flags & ADIS16400_HAS_SLOW_MODE) - st->adis.spi->max_speed_hz = ADIS16400_SPI_SLOW; - else - st->adis.spi->max_speed_hz = ADIS16400_SPI_FAST; - st->adis.spi->mode = SPI_MODE_3; - spi_setup(st->adis.spi); - - ret = adis_initial_startup(&st->adis); - if (ret) - return ret; - - if (st->variant->flags & ADIS16400_HAS_PROD_ID) { - ret = adis_read_reg_16(&st->adis, - ADIS16400_PRODUCT_ID, &prod_id); - if (ret) - goto err_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); - - dev_info(&indio_dev->dev, "%s: prod_id 0x%04x at CS%d (irq %d)\n", - indio_dev->name, prod_id, - st->adis.spi->chip_select, st->adis.spi->irq); - } - /* use high spi speed if possible */ - if (st->variant->flags & ADIS16400_HAS_SLOW_MODE) { - ret = adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &smp_prd); - if (ret) - goto err_ret; - - if ((smp_prd & ADIS16400_SMPL_PRD_DIV_MASK) < 0x0A) { - st->adis.spi->max_speed_hz = ADIS16400_SPI_FAST; - spi_setup(st->adis.spi); - } - } - -err_ret: - return ret; -} - -static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, - adis16400_read_frequency, - adis16400_write_frequency); - -static const uint8_t adis16400_addresses[] = { - [ADIS16400_SCAN_GYRO_X] = ADIS16400_XGYRO_OFF, - [ADIS16400_SCAN_GYRO_Y] = ADIS16400_YGYRO_OFF, - [ADIS16400_SCAN_GYRO_Z] = ADIS16400_ZGYRO_OFF, - [ADIS16400_SCAN_ACC_X] = ADIS16400_XACCL_OFF, - [ADIS16400_SCAN_ACC_Y] = ADIS16400_YACCL_OFF, - [ADIS16400_SCAN_ACC_Z] = ADIS16400_ZACCL_OFF, -}; - -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); - 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); - st->filt_int = val; - /* Work out update to current value */ - sps = st->variant->get_freq(st); - if (sps < 0) { - mutex_unlock(&indio_dev->mlock); - return sps; - } - - ret = adis16400_set_filter(indio_dev, sps, - val * 1000 + val2 / 1000); - mutex_unlock(&indio_dev->mlock); - return ret; - default: - return -EINVAL; - } -} - -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); - int16_t val16; - 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 = 0; - *val2 = st->variant->gyro_scale_micro; - return IIO_VAL_INT_PLUS_MICRO; - case IIO_VOLTAGE: - *val = 0; - if (chan->channel == 0) { - *val = 2; - *val2 = 418000; /* 2.418 mV */ - } else { - *val = 0; - *val2 = 805800; /* 805.8 uV */ - } - return IIO_VAL_INT_PLUS_MICRO; - case IIO_ACCEL: - *val = 0; - *val2 = st->variant->accel_scale_micro; - return IIO_VAL_INT_PLUS_MICRO; - case IIO_MAGN: - *val = 0; - *val2 = 500; /* 0.5 mgauss */ - return IIO_VAL_INT_PLUS_MICRO; - case IIO_TEMP: - *val = st->variant->temp_scale_nano / 1000000; - *val2 = (st->variant->temp_scale_nano % 1000000); - return IIO_VAL_INT_PLUS_MICRO; - default: - 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 = ((val16 & 0xFFF) << 4) >> 4; - *val = val16; - return IIO_VAL_INT; - case IIO_CHAN_INFO_OFFSET: - /* currently only temperature */ - *val = st->variant->temp_offset; - return IIO_VAL_INT; - case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: - mutex_lock(&indio_dev->mlock); - /* Need both the number of taps and the sampling frequency */ - ret = adis_read_reg_16(&st->adis, - ADIS16400_SENS_AVG, - &val16); - if (ret < 0) { - mutex_unlock(&indio_dev->mlock); - 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); - if (ret < 0) - return ret; - return IIO_VAL_INT_PLUS_MICRO; - default: - return -EINVAL; - } -} - -#define ADIS16400_VOLTAGE_CHAN(addr, bits, name, si) { \ - .type = IIO_VOLTAGE, \ - .indexed = 1, \ - .channel = 0, \ - .extend_name = name, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ - BIT(IIO_CHAN_INFO_SCALE), \ - .address = (addr), \ - .scan_index = (si), \ - .scan_type = { \ - .sign = 'u', \ - .realbits = (bits), \ - .storagebits = 16, \ - .shift = 0, \ - .endianness = IIO_BE, \ - }, \ -} - -#define ADIS16400_SUPPLY_CHAN(addr, bits) \ - ADIS16400_VOLTAGE_CHAN(addr, bits, "supply", ADIS16400_SCAN_SUPPLY) - -#define ADIS16400_AUX_ADC_CHAN(addr, bits) \ - ADIS16400_VOLTAGE_CHAN(addr, bits, NULL, ADIS16400_SCAN_ADC) - -#define ADIS16400_GYRO_CHAN(mod, addr, bits) { \ - .type = IIO_ANGL_VEL, \ - .modified = 1, \ - .channel2 = IIO_MOD_ ## mod, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ - BIT(IIO_CHAN_INFO_CALIBBIAS), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ - BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \ - .address = addr, \ - .scan_index = ADIS16400_SCAN_GYRO_ ## mod, \ - .scan_type = { \ - .sign = 's', \ - .realbits = (bits), \ - .storagebits = 16, \ - .shift = 0, \ - .endianness = IIO_BE, \ - }, \ -} - -#define ADIS16400_ACCEL_CHAN(mod, addr, bits) { \ - .type = IIO_ACCEL, \ - .modified = 1, \ - .channel2 = IIO_MOD_ ## mod, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ - BIT(IIO_CHAN_INFO_CALIBBIAS), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ - BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \ - .address = (addr), \ - .scan_index = ADIS16400_SCAN_ACC_ ## mod, \ - .scan_type = { \ - .sign = 's', \ - .realbits = (bits), \ - .storagebits = 16, \ - .shift = 0, \ - .endianness = IIO_BE, \ - }, \ -} - -#define ADIS16400_MAGN_CHAN(mod, addr, bits) { \ - .type = IIO_MAGN, \ - .modified = 1, \ - .channel2 = IIO_MOD_ ## mod, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ - BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \ - .address = (addr), \ - .scan_index = ADIS16400_SCAN_MAGN_ ## mod, \ - .scan_type = { \ - .sign = 's', \ - .realbits = (bits), \ - .storagebits = 16, \ - .shift = 0, \ - .endianness = IIO_BE, \ - }, \ -} - -#define ADIS16400_MOD_TEMP_NAME_X "x" -#define ADIS16400_MOD_TEMP_NAME_Y "y" -#define ADIS16400_MOD_TEMP_NAME_Z "z" - -#define ADIS16400_MOD_TEMP_CHAN(mod, addr, bits) { \ - .type = IIO_TEMP, \ - .indexed = 1, \ - .channel = 0, \ - .extend_name = ADIS16400_MOD_TEMP_NAME_ ## mod, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ - BIT(IIO_CHAN_INFO_OFFSET) | \ - BIT(IIO_CHAN_INFO_SCALE), \ - .info_mask_shared_by_type = \ - BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \ - .address = (addr), \ - .scan_index = ADIS16350_SCAN_TEMP_ ## mod, \ - .scan_type = { \ - .sign = 's', \ - .realbits = (bits), \ - .storagebits = 16, \ - .shift = 0, \ - .endianness = IIO_BE, \ - }, \ -} - -#define ADIS16400_TEMP_CHAN(addr, bits) { \ - .type = IIO_TEMP, \ - .indexed = 1, \ - .channel = 0, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ - BIT(IIO_CHAN_INFO_OFFSET) | \ - BIT(IIO_CHAN_INFO_SCALE), \ - .address = (addr), \ - .scan_index = ADIS16350_SCAN_TEMP_X, \ - .scan_type = { \ - .sign = 's', \ - .realbits = (bits), \ - .storagebits = 16, \ - .shift = 0, \ - .endianness = IIO_BE, \ - }, \ -} - -#define ADIS16400_INCLI_CHAN(mod, addr, bits) { \ - .type = IIO_INCLI, \ - .modified = 1, \ - .channel2 = IIO_MOD_ ## mod, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ - .address = (addr), \ - .scan_index = ADIS16300_SCAN_INCLI_ ## mod, \ - .scan_type = { \ - .sign = 's', \ - .realbits = (bits), \ - .storagebits = 16, \ - .shift = 0, \ - .endianness = IIO_BE, \ - }, \ -} - -static const struct iio_chan_spec adis16400_channels[] = { - ADIS16400_SUPPLY_CHAN(ADIS16400_SUPPLY_OUT, 14), - ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 14), - ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 14), - ADIS16400_GYRO_CHAN(Z, ADIS16400_ZGYRO_OUT, 14), - ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 14), - ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 14), - ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 14), - ADIS16400_MAGN_CHAN(X, ADIS16400_XMAGN_OUT, 14), - ADIS16400_MAGN_CHAN(Y, ADIS16400_YMAGN_OUT, 14), - ADIS16400_MAGN_CHAN(Z, ADIS16400_ZMAGN_OUT, 14), - ADIS16400_TEMP_CHAN(ADIS16400_TEMP_OUT, 12), - ADIS16400_AUX_ADC_CHAN(ADIS16400_AUX_ADC, 12), - IIO_CHAN_SOFT_TIMESTAMP(12) -}; - -static const struct iio_chan_spec adis16448_channels[] = { - ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 16), - ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 16), - ADIS16400_GYRO_CHAN(Z, ADIS16400_ZGYRO_OUT, 16), - ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 16), - ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 16), - ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 16), - ADIS16400_MAGN_CHAN(X, ADIS16400_XMAGN_OUT, 16), - ADIS16400_MAGN_CHAN(Y, ADIS16400_YMAGN_OUT, 16), - ADIS16400_MAGN_CHAN(Z, ADIS16400_ZMAGN_OUT, 16), - { - .type = IIO_PRESSURE, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), - .address = ADIS16448_BARO_OUT, - .scan_index = ADIS16400_SCAN_BARO, - .scan_type = IIO_ST('s', 16, 16, 0), - }, - ADIS16400_TEMP_CHAN(ADIS16448_TEMP_OUT, 12), - IIO_CHAN_SOFT_TIMESTAMP(11) -}; - -static const struct iio_chan_spec adis16350_channels[] = { - ADIS16400_SUPPLY_CHAN(ADIS16400_SUPPLY_OUT, 12), - ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 14), - ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 14), - ADIS16400_GYRO_CHAN(Z, ADIS16400_ZGYRO_OUT, 14), - ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 14), - ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 14), - ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 14), - ADIS16400_MAGN_CHAN(X, ADIS16400_XMAGN_OUT, 14), - ADIS16400_MAGN_CHAN(Y, ADIS16400_YMAGN_OUT, 14), - ADIS16400_MAGN_CHAN(Z, ADIS16400_ZMAGN_OUT, 14), - ADIS16400_AUX_ADC_CHAN(ADIS16300_AUX_ADC, 12), - ADIS16400_MOD_TEMP_CHAN(X, ADIS16350_XTEMP_OUT, 12), - ADIS16400_MOD_TEMP_CHAN(Y, ADIS16350_YTEMP_OUT, 12), - ADIS16400_MOD_TEMP_CHAN(Z, ADIS16350_ZTEMP_OUT, 12), - IIO_CHAN_SOFT_TIMESTAMP(11) -}; - -static const struct iio_chan_spec adis16300_channels[] = { - ADIS16400_SUPPLY_CHAN(ADIS16400_SUPPLY_OUT, 12), - ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 14), - ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 14), - ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 14), - ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 14), - ADIS16400_TEMP_CHAN(ADIS16350_XTEMP_OUT, 12), - ADIS16400_AUX_ADC_CHAN(ADIS16300_AUX_ADC, 12), - ADIS16400_INCLI_CHAN(X, ADIS16300_PITCH_OUT, 13), - ADIS16400_INCLI_CHAN(Y, ADIS16300_ROLL_OUT, 13), - IIO_CHAN_SOFT_TIMESTAMP(14) -}; - -static const struct iio_chan_spec adis16334_channels[] = { - ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 14), - ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 14), - ADIS16400_GYRO_CHAN(Z, ADIS16400_ZGYRO_OUT, 14), - ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 14), - ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 14), - ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 14), - ADIS16400_TEMP_CHAN(ADIS16350_XTEMP_OUT, 12), - IIO_CHAN_SOFT_TIMESTAMP(8) -}; - -static struct attribute *adis16400_attributes[] = { - &iio_dev_attr_sampling_frequency.dev_attr.attr, - NULL -}; - -static const struct attribute_group adis16400_attribute_group = { - .attrs = adis16400_attributes, -}; - -static struct adis16400_chip_info adis16400_chips[] = { - [ADIS16300] = { - .channels = adis16300_channels, - .num_channels = ARRAY_SIZE(adis16300_channels), - .flags = ADIS16400_HAS_SLOW_MODE, - .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ - .accel_scale_micro = 5884, - .temp_scale_nano = 140000000, /* 0.14 C */ - .temp_offset = 25000000 / 140000, /* 25 C = 0x00 */ - .set_freq = adis16400_set_freq, - .get_freq = adis16400_get_freq, - }, - [ADIS16334] = { - .channels = adis16334_channels, - .num_channels = ARRAY_SIZE(adis16334_channels), - .flags = ADIS16400_HAS_PROD_ID | ADIS16400_NO_BURST | - ADIS16400_HAS_SERIAL_NUMBER, - .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ - .accel_scale_micro = IIO_G_TO_M_S_2(1000), /* 1 mg */ - .temp_scale_nano = 67850000, /* 0.06785 C */ - .temp_offset = 25000000 / 67850, /* 25 C = 0x00 */ - .set_freq = adis16334_set_freq, - .get_freq = adis16334_get_freq, - }, - [ADIS16350] = { - .channels = adis16350_channels, - .num_channels = ARRAY_SIZE(adis16350_channels), - .gyro_scale_micro = IIO_DEGREE_TO_RAD(73260), /* 0.07326 deg/s */ - .accel_scale_micro = IIO_G_TO_M_S_2(2522), /* 0.002522 g */ - .temp_scale_nano = 145300000, /* 0.1453 C */ - .temp_offset = 25000000 / 145300, /* 25 C = 0x00 */ - .flags = ADIS16400_NO_BURST | ADIS16400_HAS_SLOW_MODE, - .set_freq = adis16400_set_freq, - .get_freq = adis16400_get_freq, - }, - [ADIS16360] = { - .channels = adis16350_channels, - .num_channels = ARRAY_SIZE(adis16350_channels), - .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE | - ADIS16400_HAS_SERIAL_NUMBER, - .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ - .accel_scale_micro = IIO_G_TO_M_S_2(3333), /* 3.333 mg */ - .temp_scale_nano = 136000000, /* 0.136 C */ - .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */ - .set_freq = adis16400_set_freq, - .get_freq = adis16400_get_freq, - }, - [ADIS16362] = { - .channels = adis16350_channels, - .num_channels = ARRAY_SIZE(adis16350_channels), - .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE | - ADIS16400_HAS_SERIAL_NUMBER, - .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ - .accel_scale_micro = IIO_G_TO_M_S_2(333), /* 0.333 mg */ - .temp_scale_nano = 136000000, /* 0.136 C */ - .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */ - .set_freq = adis16400_set_freq, - .get_freq = adis16400_get_freq, - }, - [ADIS16364] = { - .channels = adis16350_channels, - .num_channels = ARRAY_SIZE(adis16350_channels), - .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE | - ADIS16400_HAS_SERIAL_NUMBER, - .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ - .accel_scale_micro = IIO_G_TO_M_S_2(1000), /* 1 mg */ - .temp_scale_nano = 136000000, /* 0.136 C */ - .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */ - .set_freq = adis16400_set_freq, - .get_freq = adis16400_get_freq, - }, - [ADIS16400] = { - .channels = adis16400_channels, - .num_channels = ARRAY_SIZE(adis16400_channels), - .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE, - .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ - .accel_scale_micro = IIO_G_TO_M_S_2(3333), /* 3.333 mg */ - .temp_scale_nano = 140000000, /* 0.14 C */ - .temp_offset = 25000000 / 140000, /* 25 C = 0x00 */ - .set_freq = adis16400_set_freq, - .get_freq = adis16400_get_freq, - }, - [ADIS16448] = { - .channels = adis16448_channels, - .num_channels = ARRAY_SIZE(adis16448_channels), - .flags = ADIS16400_HAS_PROD_ID | - ADIS16400_HAS_SERIAL_NUMBER, - .gyro_scale_micro = IIO_DEGREE_TO_RAD(10000), /* 0.01 deg/s */ - .accel_scale_micro = IIO_G_TO_M_S_2(833), /* 1/1200 g */ - .temp_scale_nano = 73860000, /* 0.07386 C */ - .temp_offset = 31000000 / 73860, /* 31 C = 0x00 */ - .set_freq = adis16334_set_freq, - .get_freq = adis16334_get_freq, - } -}; - -static const struct iio_info adis16400_info = { - .driver_module = THIS_MODULE, - .read_raw = &adis16400_read_raw, - .write_raw = &adis16400_write_raw, - .attrs = &adis16400_attribute_group, - .update_scan_mode = adis16400_update_scan_mode, - .debugfs_reg_access = adis_debugfs_reg_access, -}; - -static const unsigned long adis16400_burst_scan_mask[] = { - ~0UL, - 0, -}; - -static const char * const adis16400_status_error_msgs[] = { - [ADIS16400_DIAG_STAT_ZACCL_FAIL] = "Z-axis accelerometer self-test failure", - [ADIS16400_DIAG_STAT_YACCL_FAIL] = "Y-axis accelerometer self-test failure", - [ADIS16400_DIAG_STAT_XACCL_FAIL] = "X-axis accelerometer self-test failure", - [ADIS16400_DIAG_STAT_XGYRO_FAIL] = "X-axis gyroscope self-test failure", - [ADIS16400_DIAG_STAT_YGYRO_FAIL] = "Y-axis gyroscope self-test failure", - [ADIS16400_DIAG_STAT_ZGYRO_FAIL] = "Z-axis gyroscope self-test failure", - [ADIS16400_DIAG_STAT_ALARM2] = "Alarm 2 active", - [ADIS16400_DIAG_STAT_ALARM1] = "Alarm 1 active", - [ADIS16400_DIAG_STAT_FLASH_CHK] = "Flash checksum error", - [ADIS16400_DIAG_STAT_SELF_TEST] = "Self test error", - [ADIS16400_DIAG_STAT_OVERFLOW] = "Sensor overrange", - [ADIS16400_DIAG_STAT_SPI_FAIL] = "SPI failure", - [ADIS16400_DIAG_STAT_FLASH_UPT] = "Flash update failed", - [ADIS16400_DIAG_STAT_POWER_HIGH] = "Power supply above 5.25V", - [ADIS16400_DIAG_STAT_POWER_LOW] = "Power supply below 4.75V", -}; - -static const struct adis_data adis16400_data = { - .msc_ctrl_reg = ADIS16400_MSC_CTRL, - .glob_cmd_reg = ADIS16400_GLOB_CMD, - .diag_stat_reg = ADIS16400_DIAG_STAT, - - .read_delay = 50, - .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) | - BIT(ADIS16400_DIAG_STAT_YACCL_FAIL) | - BIT(ADIS16400_DIAG_STAT_XACCL_FAIL) | - BIT(ADIS16400_DIAG_STAT_XGYRO_FAIL) | - BIT(ADIS16400_DIAG_STAT_YGYRO_FAIL) | - BIT(ADIS16400_DIAG_STAT_ZGYRO_FAIL) | - BIT(ADIS16400_DIAG_STAT_ALARM2) | - BIT(ADIS16400_DIAG_STAT_ALARM1) | - BIT(ADIS16400_DIAG_STAT_FLASH_CHK) | - BIT(ADIS16400_DIAG_STAT_SELF_TEST) | - BIT(ADIS16400_DIAG_STAT_OVERFLOW) | - BIT(ADIS16400_DIAG_STAT_SPI_FAIL) | - BIT(ADIS16400_DIAG_STAT_FLASH_UPT) | - BIT(ADIS16400_DIAG_STAT_POWER_HIGH) | - BIT(ADIS16400_DIAG_STAT_POWER_LOW), -}; - -static int adis16400_probe(struct spi_device *spi) -{ - struct adis16400_state *st; - struct iio_dev *indio_dev; - int ret; - - indio_dev = iio_device_alloc(sizeof(*st)); - if (indio_dev == NULL) - return -ENOMEM; - - st = iio_priv(indio_dev); - /* this is only used for removal purposes */ - spi_set_drvdata(spi, indio_dev); - - /* setup the industrialio driver allocated elements */ - st->variant = &adis16400_chips[spi_get_device_id(spi)->driver_data]; - indio_dev->dev.parent = &spi->dev; - indio_dev->name = spi_get_device_id(spi)->name; - indio_dev->channels = st->variant->channels; - indio_dev->num_channels = st->variant->num_channels; - indio_dev->info = &adis16400_info; - indio_dev->modes = INDIO_DIRECT_MODE; - - if (!(st->variant->flags & ADIS16400_NO_BURST)) - indio_dev->available_scan_masks = adis16400_burst_scan_mask; - - ret = adis_init(&st->adis, indio_dev, spi, &adis16400_data); - if (ret) - goto error_free_dev; - - ret = adis_setup_buffer_and_trigger(&st->adis, indio_dev, - adis16400_trigger_handler); - if (ret) - goto error_free_dev; - - /* Get the device into a sane initial state */ - ret = adis16400_initial_setup(indio_dev); - if (ret) - goto error_cleanup_buffer; - ret = iio_device_register(indio_dev); - if (ret) - goto error_cleanup_buffer; - - adis16400_debugfs_init(indio_dev); - return 0; - -error_cleanup_buffer: - adis_cleanup_buffer_and_trigger(&st->adis, indio_dev); -error_free_dev: - iio_device_free(indio_dev); - return ret; -} - -static int adis16400_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct adis16400_state *st = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - adis16400_stop_device(indio_dev); - - adis_cleanup_buffer_and_trigger(&st->adis, indio_dev); - - iio_device_free(indio_dev); - - return 0; -} - -static const struct spi_device_id adis16400_id[] = { - {"adis16300", ADIS16300}, - {"adis16334", ADIS16334}, - {"adis16350", ADIS16350}, - {"adis16354", ADIS16350}, - {"adis16355", ADIS16350}, - {"adis16360", ADIS16360}, - {"adis16362", ADIS16362}, - {"adis16364", ADIS16364}, - {"adis16365", ADIS16360}, - {"adis16400", ADIS16400}, - {"adis16405", ADIS16400}, - {"adis16448", ADIS16448}, - {} -}; -MODULE_DEVICE_TABLE(spi, adis16400_id); - -static struct spi_driver adis16400_driver = { - .driver = { - .name = "adis16400", - .owner = THIS_MODULE, - }, - .id_table = adis16400_id, - .probe = adis16400_probe, - .remove = adis16400_remove, -}; -module_spi_driver(adis16400_driver); - -MODULE_AUTHOR("Manuel Stahl <manuel.stahl@iis.fraunhofer.de>"); -MODULE_DESCRIPTION("Analog Devices ADIS16400/5 IMU SPI driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c deleted file mode 100644 index b7db3837629..00000000000 --- a/drivers/iio/imu/adis16480.c +++ /dev/null @@ -1,924 +0,0 @@ -/* - * ADIS16480 and similar IMUs driver - * - * Copyright 2012 Analog Devices Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ - -#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> - -#define ADIS16480_PAGE_SIZE 0x80 - -#define ADIS16480_REG(page, reg) ((page) * ADIS16480_PAGE_SIZE + (reg)) - -#define ADIS16480_REG_PAGE_ID 0x00 /* Same address on each page */ -#define ADIS16480_REG_SEQ_CNT ADIS16480_REG(0x00, 0x06) -#define ADIS16480_REG_SYS_E_FLA ADIS16480_REG(0x00, 0x08) -#define ADIS16480_REG_DIAG_STS ADIS16480_REG(0x00, 0x0A) -#define ADIS16480_REG_ALM_STS ADIS16480_REG(0x00, 0x0C) -#define ADIS16480_REG_TEMP_OUT ADIS16480_REG(0x00, 0x0E) -#define ADIS16480_REG_X_GYRO_OUT ADIS16480_REG(0x00, 0x10) -#define ADIS16480_REG_Y_GYRO_OUT ADIS16480_REG(0x00, 0x14) -#define ADIS16480_REG_Z_GYRO_OUT ADIS16480_REG(0x00, 0x18) -#define ADIS16480_REG_X_ACCEL_OUT ADIS16480_REG(0x00, 0x1C) -#define ADIS16480_REG_Y_ACCEL_OUT ADIS16480_REG(0x00, 0x20) -#define ADIS16480_REG_Z_ACCEL_OUT ADIS16480_REG(0x00, 0x24) -#define ADIS16480_REG_X_MAGN_OUT ADIS16480_REG(0x00, 0x28) -#define ADIS16480_REG_Y_MAGN_OUT ADIS16480_REG(0x00, 0x2A) -#define ADIS16480_REG_Z_MAGN_OUT ADIS16480_REG(0x00, 0x2C) -#define ADIS16480_REG_BAROM_OUT ADIS16480_REG(0x00, 0x2E) -#define ADIS16480_REG_X_DELTAANG_OUT ADIS16480_REG(0x00, 0x40) -#define ADIS16480_REG_Y_DELTAANG_OUT ADIS16480_REG(0x00, 0x44) -#define ADIS16480_REG_Z_DELTAANG_OUT ADIS16480_REG(0x00, 0x48) -#define ADIS16480_REG_X_DELTAVEL_OUT ADIS16480_REG(0x00, 0x4C) -#define ADIS16480_REG_Y_DELTAVEL_OUT ADIS16480_REG(0x00, 0x50) -#define ADIS16480_REG_Z_DELTAVEL_OUT ADIS16480_REG(0x00, 0x54) -#define ADIS16480_REG_PROD_ID ADIS16480_REG(0x00, 0x7E) - -#define ADIS16480_REG_X_GYRO_SCALE ADIS16480_REG(0x02, 0x04) -#define ADIS16480_REG_Y_GYRO_SCALE ADIS16480_REG(0x02, 0x06) -#define ADIS16480_REG_Z_GYRO_SCALE ADIS16480_REG(0x02, 0x08) -#define ADIS16480_REG_X_ACCEL_SCALE ADIS16480_REG(0x02, 0x0A) -#define ADIS16480_REG_Y_ACCEL_SCALE ADIS16480_REG(0x02, 0x0C) -#define ADIS16480_REG_Z_ACCEL_SCALE ADIS16480_REG(0x02, 0x0E) -#define ADIS16480_REG_X_GYRO_BIAS ADIS16480_REG(0x02, 0x10) -#define ADIS16480_REG_Y_GYRO_BIAS ADIS16480_REG(0x02, 0x14) -#define ADIS16480_REG_Z_GYRO_BIAS ADIS16480_REG(0x02, 0x18) -#define ADIS16480_REG_X_ACCEL_BIAS ADIS16480_REG(0x02, 0x1C) -#define ADIS16480_REG_Y_ACCEL_BIAS ADIS16480_REG(0x02, 0x20) -#define ADIS16480_REG_Z_ACCEL_BIAS ADIS16480_REG(0x02, 0x24) -#define ADIS16480_REG_X_HARD_IRON ADIS16480_REG(0x02, 0x28) -#define ADIS16480_REG_Y_HARD_IRON ADIS16480_REG(0x02, 0x2A) -#define ADIS16480_REG_Z_HARD_IRON ADIS16480_REG(0x02, 0x2C) -#define ADIS16480_REG_BAROM_BIAS ADIS16480_REG(0x02, 0x40) -#define ADIS16480_REG_FLASH_CNT ADIS16480_REG(0x02, 0x7C) - -#define ADIS16480_REG_GLOB_CMD ADIS16480_REG(0x03, 0x02) -#define ADIS16480_REG_FNCTIO_CTRL ADIS16480_REG(0x03, 0x06) -#define ADIS16480_REG_GPIO_CTRL ADIS16480_REG(0x03, 0x08) -#define ADIS16480_REG_CONFIG ADIS16480_REG(0x03, 0x0A) -#define ADIS16480_REG_DEC_RATE ADIS16480_REG(0x03, 0x0C) -#define ADIS16480_REG_SLP_CNT ADIS16480_REG(0x03, 0x10) -#define ADIS16480_REG_FILTER_BNK0 ADIS16480_REG(0x03, 0x16) -#define ADIS16480_REG_FILTER_BNK1 ADIS16480_REG(0x03, 0x18) -#define ADIS16480_REG_ALM_CNFG0 ADIS16480_REG(0x03, 0x20) -#define ADIS16480_REG_ALM_CNFG1 ADIS16480_REG(0x03, 0x22) -#define ADIS16480_REG_ALM_CNFG2 ADIS16480_REG(0x03, 0x24) -#define ADIS16480_REG_XG_ALM_MAGN ADIS16480_REG(0x03, 0x28) -#define ADIS16480_REG_YG_ALM_MAGN ADIS16480_REG(0x03, 0x2A) -#define ADIS16480_REG_ZG_ALM_MAGN ADIS16480_REG(0x03, 0x2C) -#define ADIS16480_REG_XA_ALM_MAGN ADIS16480_REG(0x03, 0x2E) -#define ADIS16480_REG_YA_ALM_MAGN ADIS16480_REG(0x03, 0x30) -#define ADIS16480_REG_ZA_ALM_MAGN ADIS16480_REG(0x03, 0x32) -#define ADIS16480_REG_XM_ALM_MAGN ADIS16480_REG(0x03, 0x34) -#define ADIS16480_REG_YM_ALM_MAGN ADIS16480_REG(0x03, 0x36) -#define ADIS16480_REG_ZM_ALM_MAGN ADIS16480_REG(0x03, 0x38) -#define ADIS16480_REG_BR_ALM_MAGN ADIS16480_REG(0x03, 0x3A) -#define ADIS16480_REG_FIRM_REV ADIS16480_REG(0x03, 0x78) -#define ADIS16480_REG_FIRM_DM ADIS16480_REG(0x03, 0x7A) -#define ADIS16480_REG_FIRM_Y ADIS16480_REG(0x03, 0x7C) - -#define ADIS16480_REG_SERIAL_NUM ADIS16480_REG(0x04, 0x20) - -/* Each filter coefficent bank spans two pages */ -#define ADIS16480_FIR_COEF(page) (x < 60 ? ADIS16480_REG(page, (x) + 8) : \ - ADIS16480_REG((page) + 1, (x) - 60 + 8)) -#define ADIS16480_FIR_COEF_A(x) ADIS16480_FIR_COEF(0x05, (x)) -#define ADIS16480_FIR_COEF_B(x) ADIS16480_FIR_COEF(0x07, (x)) -#define ADIS16480_FIR_COEF_C(x) ADIS16480_FIR_COEF(0x09, (x)) -#define ADIS16480_FIR_COEF_D(x) ADIS16480_FIR_COEF(0x0B, (x)) - -struct adis16480_chip_info { - unsigned int num_channels; - const struct iio_chan_spec *channels; -}; - -struct adis16480 { - const struct adis16480_chip_info *chip_info; - - struct adis adis; -}; - -#ifdef CONFIG_DEBUG_FS - -static ssize_t adis16480_show_firmware_revision(struct file *file, - char __user *userbuf, size_t count, loff_t *ppos) -{ - struct adis16480 *adis16480 = file->private_data; - char buf[7]; - size_t len; - u16 rev; - int ret; - - ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_FIRM_REV, &rev); - if (ret < 0) - return ret; - - len = scnprintf(buf, sizeof(buf), "%x.%x\n", rev >> 8, rev & 0xff); - - return simple_read_from_buffer(userbuf, count, ppos, buf, len); -} - -static const struct file_operations adis16480_firmware_revision_fops = { - .open = simple_open, - .read = adis16480_show_firmware_revision, - .llseek = default_llseek, - .owner = THIS_MODULE, -}; - -static ssize_t adis16480_show_firmware_date(struct file *file, - char __user *userbuf, size_t count, loff_t *ppos) -{ - struct adis16480 *adis16480 = file->private_data; - u16 md, year; - char buf[12]; - size_t len; - int ret; - - ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_FIRM_Y, &year); - if (ret < 0) - return ret; - - ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_FIRM_DM, &md); - if (ret < 0) - return ret; - - len = snprintf(buf, sizeof(buf), "%.2x-%.2x-%.4x\n", - md >> 8, md & 0xff, year); - - return simple_read_from_buffer(userbuf, count, ppos, buf, len); -} - -static const struct file_operations adis16480_firmware_date_fops = { - .open = simple_open, - .read = adis16480_show_firmware_date, - .llseek = default_llseek, - .owner = THIS_MODULE, -}; - -static int adis16480_show_serial_number(void *arg, u64 *val) -{ - struct adis16480 *adis16480 = arg; - u16 serial; - int ret; - - ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_SERIAL_NUM, - &serial); - if (ret < 0) - return ret; - - *val = serial; - - return 0; -} -DEFINE_SIMPLE_ATTRIBUTE(adis16480_serial_number_fops, - adis16480_show_serial_number, NULL, "0x%.4llx\n"); - -static int adis16480_show_product_id(void *arg, u64 *val) -{ - struct adis16480 *adis16480 = arg; - u16 prod_id; - int ret; - - ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_PROD_ID, - &prod_id); - if (ret < 0) - return ret; - - *val = prod_id; - - return 0; -} -DEFINE_SIMPLE_ATTRIBUTE(adis16480_product_id_fops, - adis16480_show_product_id, NULL, "%llu\n"); - -static int adis16480_show_flash_count(void *arg, u64 *val) -{ - struct adis16480 *adis16480 = arg; - u32 flash_count; - int ret; - - ret = adis_read_reg_32(&adis16480->adis, ADIS16480_REG_FLASH_CNT, - &flash_count); - if (ret < 0) - return ret; - - *val = flash_count; - - return 0; -} -DEFINE_SIMPLE_ATTRIBUTE(adis16480_flash_count_fops, - adis16480_show_flash_count, NULL, "%lld\n"); - -static int adis16480_debugfs_init(struct iio_dev *indio_dev) -{ - struct adis16480 *adis16480 = iio_priv(indio_dev); - - debugfs_create_file("firmware_revision", 0400, - indio_dev->debugfs_dentry, adis16480, - &adis16480_firmware_revision_fops); - debugfs_create_file("firmware_date", 0400, indio_dev->debugfs_dentry, - adis16480, &adis16480_firmware_date_fops); - debugfs_create_file("serial_number", 0400, indio_dev->debugfs_dentry, - adis16480, &adis16480_serial_number_fops); - debugfs_create_file("product_id", 0400, indio_dev->debugfs_dentry, - adis16480, &adis16480_product_id_fops); - debugfs_create_file("flash_count", 0400, indio_dev->debugfs_dentry, - adis16480, &adis16480_flash_count_fops); - - return 0; -} - -#else - -static int adis16480_debugfs_init(struct iio_dev *indio_dev) -{ - return 0; -} - -#endif - -static int adis16480_set_freq(struct adis16480 *st, unsigned int freq) -{ - unsigned int t; - - t = 2460000 / freq; - if (t > 2048) - t = 2048; - - if (t != 0) - t--; - - return adis_write_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, t); -} - -static int adis16480_get_freq(struct adis16480 *st, unsigned int *freq) -{ - uint16_t t; - int ret; - - ret = adis_read_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, &t); - if (ret < 0) - return ret; - - *freq = 2460000 / (t + 1); - - return 0; -} - -static ssize_t adis16480_read_frequency(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct adis16480 *st = iio_priv(indio_dev); - unsigned int freq; - int ret; - - ret = adis16480_get_freq(st, &freq); - if (ret < 0) - return ret; - - return sprintf(buf, "%d.%.3d\n", freq / 1000, freq % 1000); -} - -static ssize_t adis16480_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 adis16480 *st = iio_priv(indio_dev); - int freq_int, freq_fract; - long val; - int ret; - - ret = iio_str_to_fixpoint(buf, 100, &freq_int, &freq_fract); - if (ret) - return ret; - - val = freq_int * 1000 + freq_fract; - - if (val <= 0) - return -EINVAL; - - ret = adis16480_set_freq(st, val); - - return ret ? ret : len; -} - -static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, - adis16480_read_frequency, - adis16480_write_frequency); - -enum { - ADIS16480_SCAN_GYRO_X, - ADIS16480_SCAN_GYRO_Y, - ADIS16480_SCAN_GYRO_Z, - ADIS16480_SCAN_ACCEL_X, - ADIS16480_SCAN_ACCEL_Y, - ADIS16480_SCAN_ACCEL_Z, - ADIS16480_SCAN_MAGN_X, - ADIS16480_SCAN_MAGN_Y, - ADIS16480_SCAN_MAGN_Z, - ADIS16480_SCAN_BARO, - ADIS16480_SCAN_TEMP, -}; - -static const unsigned int adis16480_calibbias_regs[] = { - [ADIS16480_SCAN_GYRO_X] = ADIS16480_REG_X_GYRO_BIAS, - [ADIS16480_SCAN_GYRO_Y] = ADIS16480_REG_Y_GYRO_BIAS, - [ADIS16480_SCAN_GYRO_Z] = ADIS16480_REG_Z_GYRO_BIAS, - [ADIS16480_SCAN_ACCEL_X] = ADIS16480_REG_X_ACCEL_BIAS, - [ADIS16480_SCAN_ACCEL_Y] = ADIS16480_REG_Y_ACCEL_BIAS, - [ADIS16480_SCAN_ACCEL_Z] = ADIS16480_REG_Z_ACCEL_BIAS, - [ADIS16480_SCAN_MAGN_X] = ADIS16480_REG_X_HARD_IRON, - [ADIS16480_SCAN_MAGN_Y] = ADIS16480_REG_Y_HARD_IRON, - [ADIS16480_SCAN_MAGN_Z] = ADIS16480_REG_Z_HARD_IRON, - [ADIS16480_SCAN_BARO] = ADIS16480_REG_BAROM_BIAS, -}; - -static const unsigned int adis16480_calibscale_regs[] = { - [ADIS16480_SCAN_GYRO_X] = ADIS16480_REG_X_GYRO_SCALE, - [ADIS16480_SCAN_GYRO_Y] = ADIS16480_REG_Y_GYRO_SCALE, - [ADIS16480_SCAN_GYRO_Z] = ADIS16480_REG_Z_GYRO_SCALE, - [ADIS16480_SCAN_ACCEL_X] = ADIS16480_REG_X_ACCEL_SCALE, - [ADIS16480_SCAN_ACCEL_Y] = ADIS16480_REG_Y_ACCEL_SCALE, - [ADIS16480_SCAN_ACCEL_Z] = ADIS16480_REG_Z_ACCEL_SCALE, -}; - -static int adis16480_set_calibbias(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, int bias) -{ - unsigned int reg = adis16480_calibbias_regs[chan->scan_index]; - struct adis16480 *st = iio_priv(indio_dev); - - switch (chan->type) { - case IIO_MAGN: - case IIO_PRESSURE: - if (bias < -0x8000 || bias >= 0x8000) - return -EINVAL; - return adis_write_reg_16(&st->adis, reg, bias); - case IIO_ANGL_VEL: - case IIO_ACCEL: - return adis_write_reg_32(&st->adis, reg, bias); - default: - break; - } - - return -EINVAL; -} - -static int adis16480_get_calibbias(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, int *bias) -{ - unsigned int reg = adis16480_calibbias_regs[chan->scan_index]; - struct adis16480 *st = iio_priv(indio_dev); - uint16_t val16; - uint32_t val32; - int ret; - - switch (chan->type) { - case IIO_MAGN: - case IIO_PRESSURE: - ret = adis_read_reg_16(&st->adis, reg, &val16); - *bias = sign_extend32(val16, 15); - break; - case IIO_ANGL_VEL: - case IIO_ACCEL: - ret = adis_read_reg_32(&st->adis, reg, &val32); - *bias = sign_extend32(val32, 31); - break; - default: - ret = -EINVAL; - } - - if (ret < 0) - return ret; - - return IIO_VAL_INT; -} - -static int adis16480_set_calibscale(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, int scale) -{ - unsigned int reg = adis16480_calibscale_regs[chan->scan_index]; - struct adis16480 *st = iio_priv(indio_dev); - - if (scale < -0x8000 || scale >= 0x8000) - return -EINVAL; - - return adis_write_reg_16(&st->adis, reg, scale); -} - -static int adis16480_get_calibscale(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, int *scale) -{ - unsigned int reg = adis16480_calibscale_regs[chan->scan_index]; - struct adis16480 *st = iio_priv(indio_dev); - uint16_t val16; - int ret; - - ret = adis_read_reg_16(&st->adis, reg, &val16); - if (ret < 0) - return ret; - - *scale = sign_extend32(val16, 15); - return IIO_VAL_INT; -} - -static const unsigned int adis16480_def_filter_freqs[] = { - 310, - 55, - 275, - 63, -}; - -static const unsigned int ad16480_filter_data[][2] = { - [ADIS16480_SCAN_GYRO_X] = { ADIS16480_REG_FILTER_BNK0, 0 }, - [ADIS16480_SCAN_GYRO_Y] = { ADIS16480_REG_FILTER_BNK0, 3 }, - [ADIS16480_SCAN_GYRO_Z] = { ADIS16480_REG_FILTER_BNK0, 6 }, - [ADIS16480_SCAN_ACCEL_X] = { ADIS16480_REG_FILTER_BNK0, 9 }, - [ADIS16480_SCAN_ACCEL_Y] = { ADIS16480_REG_FILTER_BNK0, 12 }, - [ADIS16480_SCAN_ACCEL_Z] = { ADIS16480_REG_FILTER_BNK1, 0 }, - [ADIS16480_SCAN_MAGN_X] = { ADIS16480_REG_FILTER_BNK1, 3 }, - [ADIS16480_SCAN_MAGN_Y] = { ADIS16480_REG_FILTER_BNK1, 6 }, - [ADIS16480_SCAN_MAGN_Z] = { ADIS16480_REG_FILTER_BNK1, 9 }, -}; - -static int adis16480_get_filter_freq(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, int *freq) -{ - struct adis16480 *st = iio_priv(indio_dev); - unsigned int enable_mask, offset, reg; - uint16_t val; - int ret; - - reg = ad16480_filter_data[chan->scan_index][0]; - offset = ad16480_filter_data[chan->scan_index][1]; - enable_mask = BIT(offset + 2); - - ret = adis_read_reg_16(&st->adis, reg, &val); - if (ret < 0) - return ret; - - if (!(val & enable_mask)) - *freq = 0; - else - *freq = adis16480_def_filter_freqs[(val >> offset) & 0x3]; - - return IIO_VAL_INT; -} - -static int adis16480_set_filter_freq(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, unsigned int freq) -{ - struct adis16480 *st = iio_priv(indio_dev); - unsigned int enable_mask, offset, reg; - unsigned int diff, best_diff; - unsigned int i, best_freq; - uint16_t val; - int ret; - - reg = ad16480_filter_data[chan->scan_index][0]; - offset = ad16480_filter_data[chan->scan_index][1]; - enable_mask = BIT(offset + 2); - - ret = adis_read_reg_16(&st->adis, reg, &val); - if (ret < 0) - return ret; - - if (freq == 0) { - val &= ~enable_mask; - } else { - best_freq = 0; - best_diff = 310; - for (i = 0; i < ARRAY_SIZE(adis16480_def_filter_freqs); i++) { - if (adis16480_def_filter_freqs[i] >= freq) { - diff = adis16480_def_filter_freqs[i] - freq; - if (diff < best_diff) { - best_diff = diff; - best_freq = i; - } - } - } - - val &= ~(0x3 << offset); - val |= best_freq << offset; - val |= enable_mask; - } - - return adis_write_reg_16(&st->adis, reg, val); -} - -static int adis16480_read_raw(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, int *val, int *val2, long info) -{ - 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 = 0; - *val2 = IIO_DEGREE_TO_RAD(20000); /* 0.02 degree/sec */ - return IIO_VAL_INT_PLUS_MICRO; - case IIO_ACCEL: - *val = 0; - *val2 = IIO_G_TO_M_S_2(800); /* 0.8 mg */ - return IIO_VAL_INT_PLUS_MICRO; - case IIO_MAGN: - *val = 0; - *val2 = 100; /* 0.0001 gauss */ - return IIO_VAL_INT_PLUS_MICRO; - case IIO_TEMP: - *val = 5; - *val2 = 650000; /* 5.65 milli degree Celsius */ - return IIO_VAL_INT_PLUS_MICRO; - case IIO_PRESSURE: - *val = 0; - *val2 = 4000; /* 40ubar = 0.004 kPa */ - return IIO_VAL_INT_PLUS_MICRO; - default: - return -EINVAL; - } - case IIO_CHAN_INFO_OFFSET: - /* Only the temperature channel has a offset */ - *val = 4425; /* 25 degree Celsius = 0x0000 */ - return IIO_VAL_INT; - case IIO_CHAN_INFO_CALIBBIAS: - return adis16480_get_calibbias(indio_dev, chan, val); - case IIO_CHAN_INFO_CALIBSCALE: - return adis16480_get_calibscale(indio_dev, chan, val); - case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: - return adis16480_get_filter_freq(indio_dev, chan, val); - default: - return -EINVAL; - } -} - -static int adis16480_write_raw(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, int val, int val2, long info) -{ - switch (info) { - case IIO_CHAN_INFO_CALIBBIAS: - return adis16480_set_calibbias(indio_dev, chan, val); - case IIO_CHAN_INFO_CALIBSCALE: - return adis16480_set_calibscale(indio_dev, chan, val); - case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: - return adis16480_set_filter_freq(indio_dev, chan, val); - default: - return -EINVAL; - } -} - -#define ADIS16480_MOD_CHANNEL(_type, _mod, _address, _si, _info_sep, _bits) \ - { \ - .type = (_type), \ - .modified = 1, \ - .channel2 = (_mod), \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ - BIT(IIO_CHAN_INFO_CALIBBIAS) | \ - _info_sep, \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ - .address = (_address), \ - .scan_index = (_si), \ - .scan_type = { \ - .sign = 's', \ - .realbits = (_bits), \ - .storagebits = (_bits), \ - .endianness = IIO_BE, \ - }, \ - } - -#define ADIS16480_GYRO_CHANNEL(_mod) \ - ADIS16480_MOD_CHANNEL(IIO_ANGL_VEL, IIO_MOD_ ## _mod, \ - ADIS16480_REG_ ## _mod ## _GYRO_OUT, ADIS16480_SCAN_GYRO_ ## _mod, \ - BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \ - BIT(IIO_CHAN_INFO_CALIBSCALE), \ - 32) - -#define ADIS16480_ACCEL_CHANNEL(_mod) \ - ADIS16480_MOD_CHANNEL(IIO_ACCEL, IIO_MOD_ ## _mod, \ - ADIS16480_REG_ ## _mod ## _ACCEL_OUT, ADIS16480_SCAN_ACCEL_ ## _mod, \ - BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \ - BIT(IIO_CHAN_INFO_CALIBSCALE), \ - 32) - -#define ADIS16480_MAGN_CHANNEL(_mod) \ - ADIS16480_MOD_CHANNEL(IIO_MAGN, IIO_MOD_ ## _mod, \ - ADIS16480_REG_ ## _mod ## _MAGN_OUT, ADIS16480_SCAN_MAGN_ ## _mod, \ - BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \ - 16) - -#define ADIS16480_PRESSURE_CHANNEL() \ - { \ - .type = IIO_PRESSURE, \ - .indexed = 1, \ - .channel = 0, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ - BIT(IIO_CHAN_INFO_CALIBBIAS) | \ - BIT(IIO_CHAN_INFO_SCALE), \ - .address = ADIS16480_REG_BAROM_OUT, \ - .scan_index = ADIS16480_SCAN_BARO, \ - .scan_type = { \ - .sign = 's', \ - .realbits = 32, \ - .storagebits = 32, \ - .endianness = IIO_BE, \ - }, \ - } - -#define ADIS16480_TEMP_CHANNEL() { \ - .type = IIO_TEMP, \ - .indexed = 1, \ - .channel = 0, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ - BIT(IIO_CHAN_INFO_SCALE) | \ - BIT(IIO_CHAN_INFO_OFFSET), \ - .address = ADIS16480_REG_TEMP_OUT, \ - .scan_index = ADIS16480_SCAN_TEMP, \ - .scan_type = { \ - .sign = 's', \ - .realbits = 16, \ - .storagebits = 16, \ - .endianness = IIO_BE, \ - }, \ - } - -static const struct iio_chan_spec adis16480_channels[] = { - ADIS16480_GYRO_CHANNEL(X), - ADIS16480_GYRO_CHANNEL(Y), - ADIS16480_GYRO_CHANNEL(Z), - ADIS16480_ACCEL_CHANNEL(X), - ADIS16480_ACCEL_CHANNEL(Y), - ADIS16480_ACCEL_CHANNEL(Z), - ADIS16480_MAGN_CHANNEL(X), - ADIS16480_MAGN_CHANNEL(Y), - ADIS16480_MAGN_CHANNEL(Z), - ADIS16480_PRESSURE_CHANNEL(), - ADIS16480_TEMP_CHANNEL(), - IIO_CHAN_SOFT_TIMESTAMP(11) -}; - -static const struct iio_chan_spec adis16485_channels[] = { - ADIS16480_GYRO_CHANNEL(X), - ADIS16480_GYRO_CHANNEL(Y), - ADIS16480_GYRO_CHANNEL(Z), - ADIS16480_ACCEL_CHANNEL(X), - ADIS16480_ACCEL_CHANNEL(Y), - ADIS16480_ACCEL_CHANNEL(Z), - ADIS16480_TEMP_CHANNEL(), - IIO_CHAN_SOFT_TIMESTAMP(7) -}; - -enum adis16480_variant { - ADIS16375, - ADIS16480, - ADIS16485, - ADIS16488, -}; - -static const struct adis16480_chip_info adis16480_chip_info[] = { - [ADIS16375] = { - .channels = adis16485_channels, - .num_channels = ARRAY_SIZE(adis16485_channels), - }, - [ADIS16480] = { - .channels = adis16480_channels, - .num_channels = ARRAY_SIZE(adis16480_channels), - }, - [ADIS16485] = { - .channels = adis16485_channels, - .num_channels = ARRAY_SIZE(adis16485_channels), - }, - [ADIS16488] = { - .channels = adis16480_channels, - .num_channels = ARRAY_SIZE(adis16480_channels), - }, -}; - -static struct attribute *adis16480_attributes[] = { - &iio_dev_attr_sampling_frequency.dev_attr.attr, - NULL -}; - -static const struct attribute_group adis16480_attribute_group = { - .attrs = adis16480_attributes, -}; - -static const struct iio_info adis16480_info = { - .attrs = &adis16480_attribute_group, - .read_raw = &adis16480_read_raw, - .write_raw = &adis16480_write_raw, - .update_scan_mode = adis_update_scan_mode, - .driver_module = THIS_MODULE, -}; - -static int adis16480_stop_device(struct iio_dev *indio_dev) -{ - struct adis16480 *st = iio_priv(indio_dev); - int ret; - - ret = adis_write_reg_16(&st->adis, ADIS16480_REG_SLP_CNT, BIT(9)); - if (ret) - dev_err(&indio_dev->dev, - "Could not power down device: %d\n", ret); - - return ret; -} - -static int adis16480_enable_irq(struct adis *adis, bool enable) -{ - return adis_write_reg_16(adis, ADIS16480_REG_FNCTIO_CTRL, - enable ? BIT(3) : 0); -} - -static int adis16480_initial_setup(struct iio_dev *indio_dev) -{ - struct adis16480 *st = iio_priv(indio_dev); - uint16_t prod_id; - unsigned int device_id; - int ret; - - adis_reset(&st->adis); - msleep(70); - - ret = adis_write_reg_16(&st->adis, ADIS16480_REG_GLOB_CMD, BIT(1)); - if (ret) - return ret; - msleep(30); - - ret = adis_check_status(&st->adis); - if (ret) - return ret; - - ret = adis_read_reg_16(&st->adis, ADIS16480_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; -} - -#define ADIS16480_DIAG_STAT_XGYRO_FAIL 0 -#define ADIS16480_DIAG_STAT_YGYRO_FAIL 1 -#define ADIS16480_DIAG_STAT_ZGYRO_FAIL 2 -#define ADIS16480_DIAG_STAT_XACCL_FAIL 3 -#define ADIS16480_DIAG_STAT_YACCL_FAIL 4 -#define ADIS16480_DIAG_STAT_ZACCL_FAIL 5 -#define ADIS16480_DIAG_STAT_XMAGN_FAIL 8 -#define ADIS16480_DIAG_STAT_YMAGN_FAIL 9 -#define ADIS16480_DIAG_STAT_ZMAGN_FAIL 10 -#define ADIS16480_DIAG_STAT_BARO_FAIL 11 - -static const char * const adis16480_status_error_msgs[] = { - [ADIS16480_DIAG_STAT_XGYRO_FAIL] = "X-axis gyroscope self-test failure", - [ADIS16480_DIAG_STAT_YGYRO_FAIL] = "Y-axis gyroscope self-test failure", - [ADIS16480_DIAG_STAT_ZGYRO_FAIL] = "Z-axis gyroscope self-test failure", - [ADIS16480_DIAG_STAT_XACCL_FAIL] = "X-axis accelerometer self-test failure", - [ADIS16480_DIAG_STAT_YACCL_FAIL] = "Y-axis accelerometer self-test failure", - [ADIS16480_DIAG_STAT_ZACCL_FAIL] = "Z-axis accelerometer self-test failure", - [ADIS16480_DIAG_STAT_XMAGN_FAIL] = "X-axis magnetometer self-test failure", - [ADIS16480_DIAG_STAT_YMAGN_FAIL] = "Y-axis magnetometer self-test failure", - [ADIS16480_DIAG_STAT_ZMAGN_FAIL] = "Z-axis magnetometer self-test failure", - [ADIS16480_DIAG_STAT_BARO_FAIL] = "Barometer self-test failure", -}; - -static const struct adis_data adis16480_data = { - .diag_stat_reg = ADIS16480_REG_DIAG_STS, - .glob_cmd_reg = ADIS16480_REG_GLOB_CMD, - .has_paging = true, - - .read_delay = 5, - .write_delay = 5, - - .status_error_msgs = adis16480_status_error_msgs, - .status_error_mask = BIT(ADIS16480_DIAG_STAT_XGYRO_FAIL) | - BIT(ADIS16480_DIAG_STAT_YGYRO_FAIL) | - BIT(ADIS16480_DIAG_STAT_ZGYRO_FAIL) | - BIT(ADIS16480_DIAG_STAT_XACCL_FAIL) | - BIT(ADIS16480_DIAG_STAT_YACCL_FAIL) | - BIT(ADIS16480_DIAG_STAT_ZACCL_FAIL) | - BIT(ADIS16480_DIAG_STAT_XMAGN_FAIL) | - BIT(ADIS16480_DIAG_STAT_YMAGN_FAIL) | - BIT(ADIS16480_DIAG_STAT_ZMAGN_FAIL) | - BIT(ADIS16480_DIAG_STAT_BARO_FAIL), - - .enable_irq = adis16480_enable_irq, -}; - -static int adis16480_probe(struct spi_device *spi) -{ - const struct spi_device_id *id = spi_get_device_id(spi); - struct iio_dev *indio_dev; - struct adis16480 *st; - int ret; - - indio_dev = iio_device_alloc(sizeof(*st)); - if (indio_dev == NULL) - return -ENOMEM; - - spi_set_drvdata(spi, indio_dev); - - st = iio_priv(indio_dev); - - st->chip_info = &adis16480_chip_info[id->driver_data]; - indio_dev->dev.parent = &spi->dev; - indio_dev->name = spi_get_device_id(spi)->name; - indio_dev->channels = st->chip_info->channels; - indio_dev->num_channels = st->chip_info->num_channels; - indio_dev->info = &adis16480_info; - indio_dev->modes = INDIO_DIRECT_MODE; - - ret = adis_init(&st->adis, indio_dev, spi, &adis16480_data); - if (ret) - goto error_free_dev; - - ret = adis_setup_buffer_and_trigger(&st->adis, indio_dev, NULL); - if (ret) - goto error_free_dev; - - ret = adis16480_initial_setup(indio_dev); - if (ret) - goto error_cleanup_buffer; - - ret = iio_device_register(indio_dev); - if (ret) - goto error_stop_device; - - adis16480_debugfs_init(indio_dev); - - return 0; - -error_stop_device: - adis16480_stop_device(indio_dev); -error_cleanup_buffer: - adis_cleanup_buffer_and_trigger(&st->adis, indio_dev); -error_free_dev: - iio_device_free(indio_dev); - return ret; -} - -static int adis16480_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct adis16480 *st = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - adis16480_stop_device(indio_dev); - - adis_cleanup_buffer_and_trigger(&st->adis, indio_dev); - - iio_device_free(indio_dev); - - return 0; -} - -static const struct spi_device_id adis16480_ids[] = { - { "adis16375", ADIS16375 }, - { "adis16480", ADIS16480 }, - { "adis16485", ADIS16485 }, - { "adis16488", ADIS16488 }, - { } -}; -MODULE_DEVICE_TABLE(spi, adis16480_ids); - -static struct spi_driver adis16480_driver = { - .driver = { - .name = "adis16480", - .owner = THIS_MODULE, - }, - .id_table = adis16480_ids, - .probe = adis16480_probe, - .remove = adis16480_remove, -}; -module_spi_driver(adis16480_driver); - -MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); -MODULE_DESCRIPTION("Analog Devices ADIS16480 IMU driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/imu/adis_buffer.c b/drivers/iio/imu/adis_buffer.c deleted file mode 100644 index 99d8e0b0dd3..00000000000 --- a/drivers/iio/imu/adis_buffer.c +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Common library for ADIS16XXX devices - * - * Copyright 2012 Analog Devices Inc. - * Author: Lars-Peter Clausen <lars@metafoo.de> - * - * Licensed under the GPL-2 or later. - */ - -#include <linux/export.h> -#include <linux/interrupt.h> -#include <linux/mutex.h> -#include <linux/kernel.h> -#include <linux/spi/spi.h> -#include <linux/slab.h> - -#include <linux/iio/iio.h> -#include <linux/iio/buffer.h> -#include <linux/iio/trigger_consumer.h> -#include <linux/iio/triggered_buffer.h> -#include <linux/iio/imu/adis.h> - -int adis_update_scan_mode(struct iio_dev *indio_dev, - const unsigned long *scan_mask) -{ - struct adis *adis = iio_device_get_drvdata(indio_dev); - const struct iio_chan_spec *chan; - unsigned int scan_count; - unsigned int i, j; - __be16 *tx, *rx; - - kfree(adis->xfer); - kfree(adis->buffer); - - scan_count = indio_dev->scan_bytes / 2; - - adis->xfer = kcalloc(scan_count + 1, sizeof(*adis->xfer), GFP_KERNEL); - if (!adis->xfer) - return -ENOMEM; - - adis->buffer = kzalloc(indio_dev->scan_bytes * 2, GFP_KERNEL); - if (!adis->buffer) - return -ENOMEM; - - rx = adis->buffer; - tx = rx + indio_dev->scan_bytes; - - spi_message_init(&adis->msg); - - for (j = 0; j <= scan_count; j++) { - adis->xfer[j].bits_per_word = 8; - if (j != scan_count) - adis->xfer[j].cs_change = 1; - adis->xfer[j].len = 2; - adis->xfer[j].delay_usecs = adis->data->read_delay; - if (j < scan_count) - adis->xfer[j].tx_buf = &tx[j]; - if (j >= 1) - adis->xfer[j].rx_buf = &rx[j - 1]; - spi_message_add_tail(&adis->xfer[j], &adis->msg); - } - - chan = indio_dev->channels; - for (i = 0; i < indio_dev->num_channels; i++, chan++) { - if (!test_bit(chan->scan_index, scan_mask)) - continue; - if (chan->scan_type.storagebits == 32) - *tx++ = cpu_to_be16((chan->address + 2) << 8); - *tx++ = cpu_to_be16(chan->address << 8); - } - - return 0; -} -EXPORT_SYMBOL_GPL(adis_update_scan_mode); - -static irqreturn_t adis_trigger_handler(int irq, void *p) -{ - struct iio_poll_func *pf = p; - struct iio_dev *indio_dev = pf->indio_dev; - struct adis *adis = iio_device_get_drvdata(indio_dev); - int ret; - - if (!adis->buffer) - return -ENOMEM; - - if (adis->data->has_paging) { - mutex_lock(&adis->txrx_lock); - if (adis->current_page != 0) { - adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID); - adis->tx[1] = 0; - spi_write(adis->spi, adis->tx, 2); - } - } - - ret = spi_sync(adis->spi, &adis->msg); - if (ret) - dev_err(&adis->spi->dev, "Failed to read data: %d", ret); - - - if (adis->data->has_paging) { - adis->current_page = 0; - mutex_unlock(&adis->txrx_lock); - } - - /* Guaranteed to be aligned with 8 byte boundary */ - if (indio_dev->scan_timestamp) { - void *b = adis->buffer + indio_dev->scan_bytes - sizeof(s64); - *(s64 *)b = pf->timestamp; - } - - iio_push_to_buffers(indio_dev, adis->buffer); - - iio_trigger_notify_done(indio_dev->trig); - - return IRQ_HANDLED; -} - -/** - * adis_setup_buffer_and_trigger() - Sets up buffer and trigger for the adis device - * @adis: The adis device. - * @indio_dev: The IIO device. - * @trigger_handler: Optional trigger handler, may be NULL. - * - * Returns 0 on success, a negative error code otherwise. - * - * This function sets up the buffer and trigger for a adis devices. If - * 'trigger_handler' is NULL the default trigger handler will be used. The - * default trigger handler will simply read the registers assigned to the - * currently active channels. - * - * adis_cleanup_buffer_and_trigger() should be called to free the resources - * allocated by this function. - */ -int adis_setup_buffer_and_trigger(struct adis *adis, struct iio_dev *indio_dev, - irqreturn_t (*trigger_handler)(int, void *)) -{ - int ret; - - if (!trigger_handler) - trigger_handler = adis_trigger_handler; - - ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, - trigger_handler, NULL); - if (ret) - return ret; - - if (adis->spi->irq) { - ret = adis_probe_trigger(adis, indio_dev); - if (ret) - goto error_buffer_cleanup; - } - return 0; - -error_buffer_cleanup: - iio_triggered_buffer_cleanup(indio_dev); - return ret; -} -EXPORT_SYMBOL_GPL(adis_setup_buffer_and_trigger); - -/** - * adis_cleanup_buffer_and_trigger() - Free buffer and trigger resources - * @adis: The adis device. - * @indio_dev: The IIO device. - * - * Frees resources allocated by adis_setup_buffer_and_trigger() - */ -void adis_cleanup_buffer_and_trigger(struct adis *adis, - struct iio_dev *indio_dev) -{ - if (adis->spi->irq) - adis_remove_trigger(adis); - kfree(adis->buffer); - kfree(adis->xfer); - iio_triggered_buffer_cleanup(indio_dev); -} -EXPORT_SYMBOL_GPL(adis_cleanup_buffer_and_trigger); diff --git a/drivers/iio/imu/adis_trigger.c b/drivers/iio/imu/adis_trigger.c deleted file mode 100644 index e0017c22bb9..00000000000 --- a/drivers/iio/imu/adis_trigger.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Common library for ADIS16XXX devices - * - * Copyright 2012 Analog Devices Inc. - * Author: Lars-Peter Clausen <lars@metafoo.de> - * - * Licensed under the GPL-2 or later. - */ - -#include <linux/interrupt.h> -#include <linux/kernel.h> -#include <linux/spi/spi.h> -#include <linux/export.h> - -#include <linux/iio/iio.h> -#include <linux/iio/trigger.h> -#include <linux/iio/imu/adis.h> - -static int adis_data_rdy_trigger_set_state(struct iio_trigger *trig, - bool state) -{ - struct adis *adis = iio_trigger_get_drvdata(trig); - - return adis_enable_irq(adis, state); -} - -static const struct iio_trigger_ops adis_trigger_ops = { - .owner = THIS_MODULE, - .set_trigger_state = &adis_data_rdy_trigger_set_state, -}; - -/** - * adis_probe_trigger() - Sets up trigger for a adis device - * @adis: The adis device - * @indio_dev: The IIO device - * - * Returns 0 on success or a negative error code - * - * adis_remove_trigger() should be used to free the trigger. - */ -int adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev) -{ - int ret; - - adis->trig = iio_trigger_alloc("%s-dev%d", indio_dev->name, - indio_dev->id); - if (adis->trig == NULL) - return -ENOMEM; - - ret = request_irq(adis->spi->irq, - &iio_trigger_generic_data_rdy_poll, - IRQF_TRIGGER_RISING, - indio_dev->name, - adis->trig); - if (ret) - goto error_free_trig; - - adis->trig->dev.parent = &adis->spi->dev; - adis->trig->ops = &adis_trigger_ops; - iio_trigger_set_drvdata(adis->trig, adis); - ret = iio_trigger_register(adis->trig); - - indio_dev->trig = adis->trig; - if (ret) - goto error_free_irq; - - return 0; - -error_free_irq: - free_irq(adis->spi->irq, adis->trig); -error_free_trig: - iio_trigger_free(adis->trig); - return ret; -} -EXPORT_SYMBOL_GPL(adis_probe_trigger); - -/** - * adis_remove_trigger() - Remove trigger for a adis devices - * @adis: The adis device - * - * Removes the trigger previously registered with adis_probe_trigger(). - */ -void adis_remove_trigger(struct adis *adis) -{ - iio_trigger_unregister(adis->trig); - free_irq(adis->spi->irq, adis->trig); - iio_trigger_free(adis->trig); -} -EXPORT_SYMBOL_GPL(adis_remove_trigger); diff --git a/drivers/iio/imu/inv_mpu6050/Kconfig b/drivers/iio/imu/inv_mpu6050/Kconfig deleted file mode 100644 index 361b2328453..00000000000 --- a/drivers/iio/imu/inv_mpu6050/Kconfig +++ /dev/null @@ -1,14 +0,0 @@ -# -# inv-mpu6050 drivers for Invensense MPU devices and combos -# - -config INV_MPU6050_IIO - tristate "Invensense MPU6050 devices" - depends on I2C && SYSFS - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - This driver supports the Invensense MPU6050 devices. - It is a gyroscope/accelerometer combo device. - This driver can be built as a module. The module will be called - inv-mpu6050. diff --git a/drivers/iio/imu/inv_mpu6050/Makefile b/drivers/iio/imu/inv_mpu6050/Makefile deleted file mode 100644 index 3a677c778af..00000000000 --- a/drivers/iio/imu/inv_mpu6050/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# -# Makefile for Invensense MPU6050 device. -# - -obj-$(CONFIG_INV_MPU6050_IIO) += inv-mpu6050.o -inv-mpu6050-objs := inv_mpu_core.o inv_mpu_ring.o inv_mpu_trigger.o diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c deleted file mode 100644 index fe4c61e219f..00000000000 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ /dev/null @@ -1,795 +0,0 @@ -/* -* Copyright (C) 2012 Invensense, Inc. -* -* This software is licensed under the terms of the GNU General Public -* License version 2, as published by the Free Software Foundation, and -* may be copied, distributed, and modified under those terms. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -*/ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/i2c.h> -#include <linux/err.h> -#include <linux/delay.h> -#include <linux/sysfs.h> -#include <linux/jiffies.h> -#include <linux/irq.h> -#include <linux/interrupt.h> -#include <linux/kfifo.h> -#include <linux/spinlock.h> -#include "inv_mpu_iio.h" - -/* - * this is the gyro scale translated from dynamic range plus/minus - * {250, 500, 1000, 2000} to rad/s - */ -static const int gyro_scale_6050[] = {133090, 266181, 532362, 1064724}; - -/* - * this is the accel scale translated from dynamic range plus/minus - * {2, 4, 8, 16} to m/s^2 - */ -static const int accel_scale[] = {598, 1196, 2392, 4785}; - -static const struct inv_mpu6050_reg_map reg_set_6050 = { - .sample_rate_div = INV_MPU6050_REG_SAMPLE_RATE_DIV, - .lpf = INV_MPU6050_REG_CONFIG, - .user_ctrl = INV_MPU6050_REG_USER_CTRL, - .fifo_en = INV_MPU6050_REG_FIFO_EN, - .gyro_config = INV_MPU6050_REG_GYRO_CONFIG, - .accl_config = INV_MPU6050_REG_ACCEL_CONFIG, - .fifo_count_h = INV_MPU6050_REG_FIFO_COUNT_H, - .fifo_r_w = INV_MPU6050_REG_FIFO_R_W, - .raw_gyro = INV_MPU6050_REG_RAW_GYRO, - .raw_accl = INV_MPU6050_REG_RAW_ACCEL, - .temperature = INV_MPU6050_REG_TEMPERATURE, - .int_enable = INV_MPU6050_REG_INT_ENABLE, - .pwr_mgmt_1 = INV_MPU6050_REG_PWR_MGMT_1, - .pwr_mgmt_2 = INV_MPU6050_REG_PWR_MGMT_2, -}; - -static const struct inv_mpu6050_chip_config chip_config_6050 = { - .fsr = INV_MPU6050_FSR_2000DPS, - .lpf = INV_MPU6050_FILTER_20HZ, - .fifo_rate = INV_MPU6050_INIT_FIFO_RATE, - .gyro_fifo_enable = false, - .accl_fifo_enable = false, - .accl_fs = INV_MPU6050_FS_02G, -}; - -static const struct inv_mpu6050_hw hw_info[INV_NUM_PARTS] = { - { - .num_reg = 117, - .name = "MPU6050", - .reg = ®_set_6050, - .config = &chip_config_6050, - }, -}; - -int inv_mpu6050_write_reg(struct inv_mpu6050_state *st, int reg, u8 d) -{ - return i2c_smbus_write_i2c_block_data(st->client, reg, 1, &d); -} - -int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask) -{ - u8 d, mgmt_1; - int result; - - /* switch clock needs to be careful. Only when gyro is on, can - clock source be switched to gyro. Otherwise, it must be set to - internal clock */ - if (INV_MPU6050_BIT_PWR_GYRO_STBY == mask) { - result = i2c_smbus_read_i2c_block_data(st->client, - st->reg->pwr_mgmt_1, 1, &mgmt_1); - if (result != 1) - return result; - - mgmt_1 &= ~INV_MPU6050_BIT_CLK_MASK; - } - - if ((INV_MPU6050_BIT_PWR_GYRO_STBY == mask) && (!en)) { - /* turning off gyro requires switch to internal clock first. - Then turn off gyro engine */ - mgmt_1 |= INV_CLK_INTERNAL; - result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_1, mgmt_1); - if (result) - return result; - } - - result = i2c_smbus_read_i2c_block_data(st->client, - st->reg->pwr_mgmt_2, 1, &d); - if (result != 1) - return result; - if (en) - d &= ~mask; - else - d |= mask; - result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_2, d); - if (result) - return result; - - if (en) { - /* Wait for output stablize */ - msleep(INV_MPU6050_TEMP_UP_TIME); - if (INV_MPU6050_BIT_PWR_GYRO_STBY == mask) { - /* switch internal clock to PLL */ - mgmt_1 |= INV_CLK_PLL; - result = inv_mpu6050_write_reg(st, - st->reg->pwr_mgmt_1, mgmt_1); - if (result) - return result; - } - } - - return 0; -} - -int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on) -{ - int result; - - if (power_on) - result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_1, 0); - else - result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_1, - INV_MPU6050_BIT_SLEEP); - if (result) - return result; - - if (power_on) - msleep(INV_MPU6050_REG_UP_TIME); - - return 0; -} - -/** - * inv_mpu6050_init_config() - Initialize hardware, disable FIFO. - * - * Initial configuration: - * FSR: ± 2000DPS - * DLPF: 20Hz - * FIFO rate: 50Hz - * Clock source: Gyro PLL - */ -static int inv_mpu6050_init_config(struct iio_dev *indio_dev) -{ - int result; - u8 d; - struct inv_mpu6050_state *st = iio_priv(indio_dev); - - result = inv_mpu6050_set_power_itg(st, true); - if (result) - return result; - d = (INV_MPU6050_FSR_2000DPS << INV_MPU6050_GYRO_CONFIG_FSR_SHIFT); - result = inv_mpu6050_write_reg(st, st->reg->gyro_config, d); - if (result) - return result; - - d = INV_MPU6050_FILTER_20HZ; - result = inv_mpu6050_write_reg(st, st->reg->lpf, d); - if (result) - return result; - - d = INV_MPU6050_ONE_K_HZ / INV_MPU6050_INIT_FIFO_RATE - 1; - result = inv_mpu6050_write_reg(st, st->reg->sample_rate_div, d); - if (result) - return result; - - d = (INV_MPU6050_FS_02G << INV_MPU6050_ACCL_CONFIG_FSR_SHIFT); - result = inv_mpu6050_write_reg(st, st->reg->accl_config, d); - if (result) - return result; - - memcpy(&st->chip_config, hw_info[st->chip_type].config, - sizeof(struct inv_mpu6050_chip_config)); - result = inv_mpu6050_set_power_itg(st, false); - - return result; -} - -static int inv_mpu6050_sensor_show(struct inv_mpu6050_state *st, int reg, - int axis, int *val) -{ - int ind, result; - __be16 d; - - ind = (axis - IIO_MOD_X) * 2; - result = i2c_smbus_read_i2c_block_data(st->client, reg + ind, 2, - (u8 *)&d); - if (result != 2) - return -EINVAL; - *val = (short)be16_to_cpup(&d); - - return IIO_VAL_INT; -} - -static int inv_mpu6050_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, - int *val2, - long mask) { - struct inv_mpu6050_state *st = iio_priv(indio_dev); - - switch (mask) { - case IIO_CHAN_INFO_RAW: - { - int ret, result; - - ret = IIO_VAL_INT; - result = 0; - mutex_lock(&indio_dev->mlock); - if (!st->chip_config.enable) { - result = inv_mpu6050_set_power_itg(st, true); - if (result) - goto error_read_raw; - } - /* when enable is on, power is already on */ - switch (chan->type) { - case IIO_ANGL_VEL: - if (!st->chip_config.gyro_fifo_enable || - !st->chip_config.enable) { - result = inv_mpu6050_switch_engine(st, true, - INV_MPU6050_BIT_PWR_GYRO_STBY); - if (result) - goto error_read_raw; - } - ret = inv_mpu6050_sensor_show(st, st->reg->raw_gyro, - chan->channel2, val); - if (!st->chip_config.gyro_fifo_enable || - !st->chip_config.enable) { - result = inv_mpu6050_switch_engine(st, false, - INV_MPU6050_BIT_PWR_GYRO_STBY); - if (result) - goto error_read_raw; - } - break; - case IIO_ACCEL: - if (!st->chip_config.accl_fifo_enable || - !st->chip_config.enable) { - result = inv_mpu6050_switch_engine(st, true, - INV_MPU6050_BIT_PWR_ACCL_STBY); - if (result) - goto error_read_raw; - } - ret = inv_mpu6050_sensor_show(st, st->reg->raw_accl, - chan->channel2, val); - if (!st->chip_config.accl_fifo_enable || - !st->chip_config.enable) { - result = inv_mpu6050_switch_engine(st, false, - INV_MPU6050_BIT_PWR_ACCL_STBY); - if (result) - goto error_read_raw; - } - break; - case IIO_TEMP: - /* wait for stablization */ - msleep(INV_MPU6050_SENSOR_UP_TIME); - inv_mpu6050_sensor_show(st, st->reg->temperature, - IIO_MOD_X, val); - break; - default: - ret = -EINVAL; - break; - } -error_read_raw: - if (!st->chip_config.enable) - result |= inv_mpu6050_set_power_itg(st, false); - mutex_unlock(&indio_dev->mlock); - if (result) - return result; - - return ret; - } - case IIO_CHAN_INFO_SCALE: - switch (chan->type) { - case IIO_ANGL_VEL: - *val = 0; - *val2 = gyro_scale_6050[st->chip_config.fsr]; - - return IIO_VAL_INT_PLUS_NANO; - case IIO_ACCEL: - *val = 0; - *val2 = accel_scale[st->chip_config.accl_fs]; - - return IIO_VAL_INT_PLUS_MICRO; - case IIO_TEMP: - *val = 0; - *val2 = INV_MPU6050_TEMP_SCALE; - - return IIO_VAL_INT_PLUS_MICRO; - default: - return -EINVAL; - } - case IIO_CHAN_INFO_OFFSET: - switch (chan->type) { - case IIO_TEMP: - *val = INV_MPU6050_TEMP_OFFSET; - - return IIO_VAL_INT; - default: - return -EINVAL; - } - default: - return -EINVAL; - } -} - -static int inv_mpu6050_write_fsr(struct inv_mpu6050_state *st, int fsr) -{ - int result; - u8 d; - - if (fsr < 0 || fsr > INV_MPU6050_MAX_GYRO_FS_PARAM) - return -EINVAL; - if (fsr == st->chip_config.fsr) - return 0; - - d = (fsr << INV_MPU6050_GYRO_CONFIG_FSR_SHIFT); - result = inv_mpu6050_write_reg(st, st->reg->gyro_config, d); - if (result) - return result; - st->chip_config.fsr = fsr; - - return 0; -} - -static int inv_mpu6050_write_accel_fs(struct inv_mpu6050_state *st, int fs) -{ - int result; - u8 d; - - if (fs < 0 || fs > INV_MPU6050_MAX_ACCL_FS_PARAM) - return -EINVAL; - if (fs == st->chip_config.accl_fs) - return 0; - - d = (fs << INV_MPU6050_ACCL_CONFIG_FSR_SHIFT); - result = inv_mpu6050_write_reg(st, st->reg->accl_config, d); - if (result) - return result; - st->chip_config.accl_fs = fs; - - return 0; -} - -static int inv_mpu6050_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, - int val2, - long mask) { - struct inv_mpu6050_state *st = iio_priv(indio_dev); - int result; - - mutex_lock(&indio_dev->mlock); - /* we should only update scale when the chip is disabled, i.e., - not running */ - if (st->chip_config.enable) { - result = -EBUSY; - goto error_write_raw; - } - result = inv_mpu6050_set_power_itg(st, true); - if (result) - goto error_write_raw; - - switch (mask) { - case IIO_CHAN_INFO_SCALE: - switch (chan->type) { - case IIO_ANGL_VEL: - result = inv_mpu6050_write_fsr(st, val); - break; - case IIO_ACCEL: - result = inv_mpu6050_write_accel_fs(st, val); - break; - default: - result = -EINVAL; - break; - } - break; - default: - result = -EINVAL; - break; - } - -error_write_raw: - result |= inv_mpu6050_set_power_itg(st, false); - mutex_unlock(&indio_dev->mlock); - - return result; -} - -/** - * inv_mpu6050_set_lpf() - set low pass filer based on fifo rate. - * - * Based on the Nyquist principle, the sampling rate must - * exceed twice of the bandwidth of the signal, or there - * would be alising. This function basically search for the - * correct low pass parameters based on the fifo rate, e.g, - * sampling frequency. - */ -static int inv_mpu6050_set_lpf(struct inv_mpu6050_state *st, int rate) -{ - const int hz[] = {188, 98, 42, 20, 10, 5}; - const int d[] = {INV_MPU6050_FILTER_188HZ, INV_MPU6050_FILTER_98HZ, - INV_MPU6050_FILTER_42HZ, INV_MPU6050_FILTER_20HZ, - INV_MPU6050_FILTER_10HZ, INV_MPU6050_FILTER_5HZ}; - int i, h, result; - u8 data; - - h = (rate >> 1); - i = 0; - while ((h < hz[i]) && (i < ARRAY_SIZE(d) - 1)) - i++; - data = d[i]; - result = inv_mpu6050_write_reg(st, st->reg->lpf, data); - if (result) - return result; - st->chip_config.lpf = data; - - return 0; -} - -/** - * inv_mpu6050_fifo_rate_store() - Set fifo rate. - */ -static ssize_t inv_mpu6050_fifo_rate_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - s32 fifo_rate; - u8 d; - int result; - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct inv_mpu6050_state *st = iio_priv(indio_dev); - - if (kstrtoint(buf, 10, &fifo_rate)) - return -EINVAL; - if (fifo_rate < INV_MPU6050_MIN_FIFO_RATE || - fifo_rate > INV_MPU6050_MAX_FIFO_RATE) - return -EINVAL; - if (fifo_rate == st->chip_config.fifo_rate) - return count; - - mutex_lock(&indio_dev->mlock); - if (st->chip_config.enable) { - result = -EBUSY; - goto fifo_rate_fail; - } - result = inv_mpu6050_set_power_itg(st, true); - if (result) - goto fifo_rate_fail; - - d = INV_MPU6050_ONE_K_HZ / fifo_rate - 1; - result = inv_mpu6050_write_reg(st, st->reg->sample_rate_div, d); - if (result) - goto fifo_rate_fail; - st->chip_config.fifo_rate = fifo_rate; - - result = inv_mpu6050_set_lpf(st, fifo_rate); - if (result) - goto fifo_rate_fail; - -fifo_rate_fail: - result |= inv_mpu6050_set_power_itg(st, false); - mutex_unlock(&indio_dev->mlock); - if (result) - return result; - - return count; -} - -/** - * inv_fifo_rate_show() - Get the current sampling rate. - */ -static ssize_t inv_fifo_rate_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct inv_mpu6050_state *st = iio_priv(dev_to_iio_dev(dev)); - - return sprintf(buf, "%d\n", st->chip_config.fifo_rate); -} - -/** - * inv_attr_show() - calling this function will show current - * parameters. - */ -static ssize_t inv_attr_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct inv_mpu6050_state *st = iio_priv(dev_to_iio_dev(dev)); - struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - s8 *m; - - switch (this_attr->address) { - /* In MPU6050, the two matrix are the same because gyro and accel - are integrated in one chip */ - case ATTR_GYRO_MATRIX: - case ATTR_ACCL_MATRIX: - m = st->plat_data.orientation; - - return sprintf(buf, "%d, %d, %d; %d, %d, %d; %d, %d, %d\n", - m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8]); - default: - return -EINVAL; - } -} - -/** - * inv_mpu6050_validate_trigger() - validate_trigger callback for invensense - * MPU6050 device. - * @indio_dev: The IIO device - * @trig: The new trigger - * - * Returns: 0 if the 'trig' matches the trigger registered by the MPU6050 - * device, -EINVAL otherwise. - */ -static int inv_mpu6050_validate_trigger(struct iio_dev *indio_dev, - struct iio_trigger *trig) -{ - struct inv_mpu6050_state *st = iio_priv(indio_dev); - - if (st->trig != trig) - return -EINVAL; - - return 0; -} - -#define INV_MPU6050_CHAN(_type, _channel2, _index) \ - { \ - .type = _type, \ - .modified = 1, \ - .channel2 = _channel2, \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ - .scan_index = _index, \ - .scan_type = { \ - .sign = 's', \ - .realbits = 16, \ - .storagebits = 16, \ - .shift = 0 , \ - .endianness = IIO_BE, \ - }, \ - } - -static const struct iio_chan_spec inv_mpu_channels[] = { - IIO_CHAN_SOFT_TIMESTAMP(INV_MPU6050_SCAN_TIMESTAMP), - /* - * Note that temperature should only be via polled reading only, - * not the final scan elements output. - */ - { - .type = IIO_TEMP, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) - | BIT(IIO_CHAN_INFO_OFFSET) - | BIT(IIO_CHAN_INFO_SCALE), - .scan_index = -1, - }, - INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_X, INV_MPU6050_SCAN_GYRO_X), - INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Y, INV_MPU6050_SCAN_GYRO_Y), - INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Z, INV_MPU6050_SCAN_GYRO_Z), - - INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_X, INV_MPU6050_SCAN_ACCL_X), - INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Y, INV_MPU6050_SCAN_ACCL_Y), - INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Z, INV_MPU6050_SCAN_ACCL_Z), -}; - -/* constant IIO attribute */ -static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("10 20 50 100 200 500"); -static IIO_DEV_ATTR_SAMP_FREQ(S_IRUGO | S_IWUSR, inv_fifo_rate_show, - inv_mpu6050_fifo_rate_store); -static IIO_DEVICE_ATTR(in_gyro_matrix, S_IRUGO, inv_attr_show, NULL, - ATTR_GYRO_MATRIX); -static IIO_DEVICE_ATTR(in_accel_matrix, S_IRUGO, inv_attr_show, NULL, - ATTR_ACCL_MATRIX); - -static struct attribute *inv_attributes[] = { - &iio_dev_attr_in_gyro_matrix.dev_attr.attr, - &iio_dev_attr_in_accel_matrix.dev_attr.attr, - &iio_dev_attr_sampling_frequency.dev_attr.attr, - &iio_const_attr_sampling_frequency_available.dev_attr.attr, - NULL, -}; - -static const struct attribute_group inv_attribute_group = { - .attrs = inv_attributes -}; - -static const struct iio_info mpu_info = { - .driver_module = THIS_MODULE, - .read_raw = &inv_mpu6050_read_raw, - .write_raw = &inv_mpu6050_write_raw, - .attrs = &inv_attribute_group, - .validate_trigger = inv_mpu6050_validate_trigger, -}; - -/** - * inv_check_and_setup_chip() - check and setup chip. - */ -static int inv_check_and_setup_chip(struct inv_mpu6050_state *st, - const struct i2c_device_id *id) -{ - int result; - - st->chip_type = INV_MPU6050; - st->hw = &hw_info[st->chip_type]; - st->reg = hw_info[st->chip_type].reg; - - /* reset to make sure previous state are not there */ - result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_1, - INV_MPU6050_BIT_H_RESET); - if (result) - return result; - msleep(INV_MPU6050_POWER_UP_TIME); - /* toggle power state. After reset, the sleep bit could be on - or off depending on the OTP settings. Toggling power would - make it in a definite state as well as making the hardware - state align with the software state */ - result = inv_mpu6050_set_power_itg(st, false); - if (result) - return result; - result = inv_mpu6050_set_power_itg(st, true); - if (result) - return result; - - result = inv_mpu6050_switch_engine(st, false, - INV_MPU6050_BIT_PWR_ACCL_STBY); - if (result) - return result; - result = inv_mpu6050_switch_engine(st, false, - INV_MPU6050_BIT_PWR_GYRO_STBY); - if (result) - return result; - - return 0; -} - -/** - * inv_mpu_probe() - probe function. - * @client: i2c client. - * @id: i2c device id. - * - * Returns 0 on success, a negative error code otherwise. - */ -static int inv_mpu_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct inv_mpu6050_state *st; - struct iio_dev *indio_dev; - int result; - - if (!i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_READ_I2C_BLOCK | - I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) { - result = -ENOSYS; - goto out_no_free; - } - indio_dev = iio_device_alloc(sizeof(*st)); - if (indio_dev == NULL) { - result = -ENOMEM; - goto out_no_free; - } - st = iio_priv(indio_dev); - st->client = client; - st->plat_data = *(struct inv_mpu6050_platform_data - *)dev_get_platdata(&client->dev); - /* power is turned on inside check chip type*/ - result = inv_check_and_setup_chip(st, id); - if (result) - goto out_free; - - result = inv_mpu6050_init_config(indio_dev); - if (result) { - dev_err(&client->dev, - "Could not initialize device.\n"); - goto out_free; - } - - i2c_set_clientdata(client, indio_dev); - indio_dev->dev.parent = &client->dev; - indio_dev->name = id->name; - indio_dev->channels = inv_mpu_channels; - indio_dev->num_channels = ARRAY_SIZE(inv_mpu_channels); - - indio_dev->info = &mpu_info; - indio_dev->modes = INDIO_BUFFER_TRIGGERED; - - result = iio_triggered_buffer_setup(indio_dev, - inv_mpu6050_irq_handler, - inv_mpu6050_read_fifo, - NULL); - if (result) { - dev_err(&st->client->dev, "configure buffer fail %d\n", - result); - goto out_free; - } - result = inv_mpu6050_probe_trigger(indio_dev); - if (result) { - dev_err(&st->client->dev, "trigger probe fail %d\n", result); - goto out_unreg_ring; - } - - INIT_KFIFO(st->timestamps); - spin_lock_init(&st->time_stamp_lock); - result = iio_device_register(indio_dev); - if (result) { - dev_err(&st->client->dev, "IIO register fail %d\n", result); - goto out_remove_trigger; - } - - return 0; - -out_remove_trigger: - inv_mpu6050_remove_trigger(st); -out_unreg_ring: - iio_triggered_buffer_cleanup(indio_dev); -out_free: - iio_device_free(indio_dev); -out_no_free: - - return result; -} - -static int inv_mpu_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - struct inv_mpu6050_state *st = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - inv_mpu6050_remove_trigger(st); - iio_triggered_buffer_cleanup(indio_dev); - iio_device_free(indio_dev); - - return 0; -} -#ifdef CONFIG_PM_SLEEP - -static int inv_mpu_resume(struct device *dev) -{ - return inv_mpu6050_set_power_itg( - iio_priv(i2c_get_clientdata(to_i2c_client(dev))), true); -} - -static int inv_mpu_suspend(struct device *dev) -{ - return inv_mpu6050_set_power_itg( - iio_priv(i2c_get_clientdata(to_i2c_client(dev))), false); -} -static SIMPLE_DEV_PM_OPS(inv_mpu_pmops, inv_mpu_suspend, inv_mpu_resume); - -#define INV_MPU6050_PMOPS (&inv_mpu_pmops) -#else -#define INV_MPU6050_PMOPS NULL -#endif /* CONFIG_PM_SLEEP */ - -/* - * device id table is used to identify what device can be - * supported by this driver - */ -static const struct i2c_device_id inv_mpu_id[] = { - {"mpu6050", INV_MPU6050}, - {} -}; - -MODULE_DEVICE_TABLE(i2c, inv_mpu_id); - -static struct i2c_driver inv_mpu_driver = { - .probe = inv_mpu_probe, - .remove = inv_mpu_remove, - .id_table = inv_mpu_id, - .driver = { - .owner = THIS_MODULE, - .name = "inv-mpu6050", - .pm = INV_MPU6050_PMOPS, - }, -}; - -module_i2c_driver(inv_mpu_driver); - -MODULE_AUTHOR("Invensense Corporation"); -MODULE_DESCRIPTION("Invensense device MPU6050 driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h deleted file mode 100644 index f38395529a4..00000000000 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h +++ /dev/null @@ -1,246 +0,0 @@ -/* -* Copyright (C) 2012 Invensense, Inc. -* -* This software is licensed under the terms of the GNU General Public -* License version 2, as published by the Free Software Foundation, and -* may be copied, distributed, and modified under those terms. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -*/ -#include <linux/i2c.h> -#include <linux/kfifo.h> -#include <linux/spinlock.h> -#include <linux/iio/iio.h> -#include <linux/iio/buffer.h> -#include <linux/iio/sysfs.h> -#include <linux/iio/kfifo_buf.h> -#include <linux/iio/trigger.h> -#include <linux/iio/triggered_buffer.h> -#include <linux/iio/trigger_consumer.h> -#include <linux/platform_data/invensense_mpu6050.h> - -/** - * struct inv_mpu6050_reg_map - Notable registers. - * @sample_rate_div: Divider applied to gyro output rate. - * @lpf: Configures internal low pass filter. - * @user_ctrl: Enables/resets the FIFO. - * @fifo_en: Determines which data will appear in FIFO. - * @gyro_config: gyro config register. - * @accl_config: accel config register - * @fifo_count_h: Upper byte of FIFO count. - * @fifo_r_w: FIFO register. - * @raw_gyro: Address of first gyro register. - * @raw_accl: Address of first accel register. - * @temperature: temperature register - * @int_enable: Interrupt enable register. - * @pwr_mgmt_1: Controls chip's power state and clock source. - * @pwr_mgmt_2: Controls power state of individual sensors. - */ -struct inv_mpu6050_reg_map { - u8 sample_rate_div; - u8 lpf; - u8 user_ctrl; - u8 fifo_en; - u8 gyro_config; - u8 accl_config; - u8 fifo_count_h; - u8 fifo_r_w; - u8 raw_gyro; - u8 raw_accl; - u8 temperature; - u8 int_enable; - u8 pwr_mgmt_1; - u8 pwr_mgmt_2; -}; - -/*device enum */ -enum inv_devices { - INV_MPU6050, - INV_NUM_PARTS -}; - -/** - * struct inv_mpu6050_chip_config - Cached chip configuration data. - * @fsr: Full scale range. - * @lpf: Digital low pass filter frequency. - * @accl_fs: accel full scale range. - * @enable: master enable state. - * @accl_fifo_enable: enable accel data output - * @gyro_fifo_enable: enable gyro data output - * @fifo_rate: FIFO update rate. - */ -struct inv_mpu6050_chip_config { - unsigned int fsr:2; - unsigned int lpf:3; - unsigned int accl_fs:2; - unsigned int enable:1; - unsigned int accl_fifo_enable:1; - unsigned int gyro_fifo_enable:1; - u16 fifo_rate; -}; - -/** - * struct inv_mpu6050_hw - Other important hardware information. - * @num_reg: Number of registers on device. - * @name: name of the chip. - * @reg: register map of the chip. - * @config: configuration of the chip. - */ -struct inv_mpu6050_hw { - u8 num_reg; - u8 *name; - const struct inv_mpu6050_reg_map *reg; - const struct inv_mpu6050_chip_config *config; -}; - -/* - * struct inv_mpu6050_state - Driver state variables. - * @TIMESTAMP_FIFO_SIZE: fifo size for timestamp. - * @trig: IIO trigger. - * @chip_config: Cached attribute information. - * @reg: Map of important registers. - * @hw: Other hardware-specific information. - * @chip_type: chip type. - * @time_stamp_lock: spin lock to time stamp. - * @client: i2c client handle. - * @plat_data: platform data. - * @timestamps: kfifo queue to store time stamp. - */ -struct inv_mpu6050_state { -#define TIMESTAMP_FIFO_SIZE 16 - struct iio_trigger *trig; - struct inv_mpu6050_chip_config chip_config; - const struct inv_mpu6050_reg_map *reg; - const struct inv_mpu6050_hw *hw; - enum inv_devices chip_type; - spinlock_t time_stamp_lock; - struct i2c_client *client; - struct inv_mpu6050_platform_data plat_data; - DECLARE_KFIFO(timestamps, long long, TIMESTAMP_FIFO_SIZE); -}; - -/*register and associated bit definition*/ -#define INV_MPU6050_REG_SAMPLE_RATE_DIV 0x19 -#define INV_MPU6050_REG_CONFIG 0x1A -#define INV_MPU6050_REG_GYRO_CONFIG 0x1B -#define INV_MPU6050_REG_ACCEL_CONFIG 0x1C - -#define INV_MPU6050_REG_FIFO_EN 0x23 -#define INV_MPU6050_BIT_ACCEL_OUT 0x08 -#define INV_MPU6050_BITS_GYRO_OUT 0x70 - -#define INV_MPU6050_REG_INT_ENABLE 0x38 -#define INV_MPU6050_BIT_DATA_RDY_EN 0x01 -#define INV_MPU6050_BIT_DMP_INT_EN 0x02 - -#define INV_MPU6050_REG_RAW_ACCEL 0x3B -#define INV_MPU6050_REG_TEMPERATURE 0x41 -#define INV_MPU6050_REG_RAW_GYRO 0x43 - -#define INV_MPU6050_REG_USER_CTRL 0x6A -#define INV_MPU6050_BIT_FIFO_RST 0x04 -#define INV_MPU6050_BIT_DMP_RST 0x08 -#define INV_MPU6050_BIT_I2C_MST_EN 0x20 -#define INV_MPU6050_BIT_FIFO_EN 0x40 -#define INV_MPU6050_BIT_DMP_EN 0x80 - -#define INV_MPU6050_REG_PWR_MGMT_1 0x6B -#define INV_MPU6050_BIT_H_RESET 0x80 -#define INV_MPU6050_BIT_SLEEP 0x40 -#define INV_MPU6050_BIT_CLK_MASK 0x7 - -#define INV_MPU6050_REG_PWR_MGMT_2 0x6C -#define INV_MPU6050_BIT_PWR_ACCL_STBY 0x38 -#define INV_MPU6050_BIT_PWR_GYRO_STBY 0x07 - -#define INV_MPU6050_REG_FIFO_COUNT_H 0x72 -#define INV_MPU6050_REG_FIFO_R_W 0x74 - -#define INV_MPU6050_BYTES_PER_3AXIS_SENSOR 6 -#define INV_MPU6050_FIFO_COUNT_BYTE 2 -#define INV_MPU6050_FIFO_THRESHOLD 500 -#define INV_MPU6050_POWER_UP_TIME 100 -#define INV_MPU6050_TEMP_UP_TIME 100 -#define INV_MPU6050_SENSOR_UP_TIME 30 -#define INV_MPU6050_REG_UP_TIME 5 - -#define INV_MPU6050_TEMP_OFFSET 12421 -#define INV_MPU6050_TEMP_SCALE 2941 -#define INV_MPU6050_MAX_GYRO_FS_PARAM 3 -#define INV_MPU6050_MAX_ACCL_FS_PARAM 3 -#define INV_MPU6050_THREE_AXIS 3 -#define INV_MPU6050_GYRO_CONFIG_FSR_SHIFT 3 -#define INV_MPU6050_ACCL_CONFIG_FSR_SHIFT 3 - -/* 6 + 6 round up and plus 8 */ -#define INV_MPU6050_OUTPUT_DATA_SIZE 24 - -/* init parameters */ -#define INV_MPU6050_INIT_FIFO_RATE 50 -#define INV_MPU6050_TIME_STAMP_TOR 5 -#define INV_MPU6050_MAX_FIFO_RATE 1000 -#define INV_MPU6050_MIN_FIFO_RATE 4 -#define INV_MPU6050_ONE_K_HZ 1000 - -/* scan element definition */ -enum inv_mpu6050_scan { - INV_MPU6050_SCAN_ACCL_X, - INV_MPU6050_SCAN_ACCL_Y, - INV_MPU6050_SCAN_ACCL_Z, - INV_MPU6050_SCAN_GYRO_X, - INV_MPU6050_SCAN_GYRO_Y, - INV_MPU6050_SCAN_GYRO_Z, - INV_MPU6050_SCAN_TIMESTAMP, -}; - -enum inv_mpu6050_filter_e { - INV_MPU6050_FILTER_256HZ_NOLPF2 = 0, - INV_MPU6050_FILTER_188HZ, - INV_MPU6050_FILTER_98HZ, - INV_MPU6050_FILTER_42HZ, - INV_MPU6050_FILTER_20HZ, - INV_MPU6050_FILTER_10HZ, - INV_MPU6050_FILTER_5HZ, - INV_MPU6050_FILTER_2100HZ_NOLPF, - NUM_MPU6050_FILTER -}; - -/* IIO attribute address */ -enum INV_MPU6050_IIO_ATTR_ADDR { - ATTR_GYRO_MATRIX, - ATTR_ACCL_MATRIX, -}; - -enum inv_mpu6050_accl_fs_e { - INV_MPU6050_FS_02G = 0, - INV_MPU6050_FS_04G, - INV_MPU6050_FS_08G, - INV_MPU6050_FS_16G, - NUM_ACCL_FSR -}; - -enum inv_mpu6050_fsr_e { - INV_MPU6050_FSR_250DPS = 0, - INV_MPU6050_FSR_500DPS, - INV_MPU6050_FSR_1000DPS, - INV_MPU6050_FSR_2000DPS, - NUM_MPU6050_FSR -}; - -enum inv_mpu6050_clock_sel_e { - INV_CLK_INTERNAL = 0, - INV_CLK_PLL, - NUM_CLK -}; - -irqreturn_t inv_mpu6050_irq_handler(int irq, void *p); -irqreturn_t inv_mpu6050_read_fifo(int irq, void *p); -int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev); -void inv_mpu6050_remove_trigger(struct inv_mpu6050_state *st); -int inv_reset_fifo(struct iio_dev *indio_dev); -int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask); -int inv_mpu6050_write_reg(struct inv_mpu6050_state *st, int reg, u8 val); -int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on); diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c deleted file mode 100644 index 7da0832f187..00000000000 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c +++ /dev/null @@ -1,195 +0,0 @@ -/* -* Copyright (C) 2012 Invensense, Inc. -* -* This software is licensed under the terms of the GNU General Public -* License version 2, as published by the Free Software Foundation, and -* may be copied, distributed, and modified under those terms. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -*/ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/i2c.h> -#include <linux/err.h> -#include <linux/delay.h> -#include <linux/sysfs.h> -#include <linux/jiffies.h> -#include <linux/irq.h> -#include <linux/interrupt.h> -#include <linux/kfifo.h> -#include <linux/poll.h> -#include "inv_mpu_iio.h" - -int inv_reset_fifo(struct iio_dev *indio_dev) -{ - int result; - u8 d; - struct inv_mpu6050_state *st = iio_priv(indio_dev); - - /* disable interrupt */ - result = inv_mpu6050_write_reg(st, st->reg->int_enable, 0); - if (result) { - dev_err(&st->client->dev, "int_enable failed %d\n", result); - return result; - } - /* disable the sensor output to FIFO */ - result = inv_mpu6050_write_reg(st, st->reg->fifo_en, 0); - if (result) - goto reset_fifo_fail; - /* disable fifo reading */ - result = inv_mpu6050_write_reg(st, st->reg->user_ctrl, 0); - if (result) - goto reset_fifo_fail; - - /* reset FIFO*/ - result = inv_mpu6050_write_reg(st, st->reg->user_ctrl, - INV_MPU6050_BIT_FIFO_RST); - if (result) - goto reset_fifo_fail; - /* enable interrupt */ - if (st->chip_config.accl_fifo_enable || - st->chip_config.gyro_fifo_enable) { - result = inv_mpu6050_write_reg(st, st->reg->int_enable, - INV_MPU6050_BIT_DATA_RDY_EN); - if (result) - return result; - } - /* enable FIFO reading and I2C master interface*/ - result = inv_mpu6050_write_reg(st, st->reg->user_ctrl, - INV_MPU6050_BIT_FIFO_EN); - if (result) - goto reset_fifo_fail; - /* enable sensor output to FIFO */ - d = 0; - if (st->chip_config.gyro_fifo_enable) - d |= INV_MPU6050_BITS_GYRO_OUT; - if (st->chip_config.accl_fifo_enable) - d |= INV_MPU6050_BIT_ACCEL_OUT; - result = inv_mpu6050_write_reg(st, st->reg->fifo_en, d); - if (result) - goto reset_fifo_fail; - - return 0; - -reset_fifo_fail: - dev_err(&st->client->dev, "reset fifo failed %d\n", result); - result = inv_mpu6050_write_reg(st, st->reg->int_enable, - INV_MPU6050_BIT_DATA_RDY_EN); - - return result; -} - -static void inv_clear_kfifo(struct inv_mpu6050_state *st) -{ - unsigned long flags; - - /* take the spin lock sem to avoid interrupt kick in */ - spin_lock_irqsave(&st->time_stamp_lock, flags); - kfifo_reset(&st->timestamps); - spin_unlock_irqrestore(&st->time_stamp_lock, flags); -} - -/** - * inv_mpu6050_irq_handler() - Cache a timestamp at each data ready interrupt. - */ -irqreturn_t inv_mpu6050_irq_handler(int irq, void *p) -{ - struct iio_poll_func *pf = p; - struct iio_dev *indio_dev = pf->indio_dev; - struct inv_mpu6050_state *st = iio_priv(indio_dev); - s64 timestamp; - - timestamp = iio_get_time_ns(); - kfifo_in_spinlocked(&st->timestamps, ×tamp, 1, - &st->time_stamp_lock); - - return IRQ_WAKE_THREAD; -} - -/** - * inv_mpu6050_read_fifo() - Transfer data from hardware FIFO to KFIFO. - */ -irqreturn_t inv_mpu6050_read_fifo(int irq, void *p) -{ - struct iio_poll_func *pf = p; - struct iio_dev *indio_dev = pf->indio_dev; - struct inv_mpu6050_state *st = iio_priv(indio_dev); - size_t bytes_per_datum; - int result; - u8 data[INV_MPU6050_OUTPUT_DATA_SIZE]; - u16 fifo_count; - s64 timestamp; - u64 *tmp; - - mutex_lock(&indio_dev->mlock); - if (!(st->chip_config.accl_fifo_enable | - st->chip_config.gyro_fifo_enable)) - goto end_session; - bytes_per_datum = 0; - if (st->chip_config.accl_fifo_enable) - bytes_per_datum += INV_MPU6050_BYTES_PER_3AXIS_SENSOR; - - if (st->chip_config.gyro_fifo_enable) - bytes_per_datum += INV_MPU6050_BYTES_PER_3AXIS_SENSOR; - - /* - * read fifo_count register to know how many bytes inside FIFO - * right now - */ - result = i2c_smbus_read_i2c_block_data(st->client, - st->reg->fifo_count_h, - INV_MPU6050_FIFO_COUNT_BYTE, data); - if (result != INV_MPU6050_FIFO_COUNT_BYTE) - goto end_session; - fifo_count = be16_to_cpup((__be16 *)(&data[0])); - if (fifo_count < bytes_per_datum) - goto end_session; - /* fifo count can't be odd number, if it is odd, reset fifo*/ - if (fifo_count & 1) - goto flush_fifo; - if (fifo_count > INV_MPU6050_FIFO_THRESHOLD) - goto flush_fifo; - /* Timestamp mismatch. */ - if (kfifo_len(&st->timestamps) > - fifo_count / bytes_per_datum + INV_MPU6050_TIME_STAMP_TOR) - goto flush_fifo; - while (fifo_count >= bytes_per_datum) { - result = i2c_smbus_read_i2c_block_data(st->client, - st->reg->fifo_r_w, - bytes_per_datum, data); - if (result != bytes_per_datum) - goto flush_fifo; - - result = kfifo_out(&st->timestamps, ×tamp, 1); - /* when there is no timestamp, put timestamp as 0 */ - if (0 == result) - timestamp = 0; - - tmp = (u64 *)data; - tmp[DIV_ROUND_UP(bytes_per_datum, 8)] = timestamp; - result = iio_push_to_buffers(indio_dev, data); - if (result) - goto flush_fifo; - fifo_count -= bytes_per_datum; - } - -end_session: - mutex_unlock(&indio_dev->mlock); - iio_trigger_notify_done(indio_dev->trig); - - return IRQ_HANDLED; - -flush_fifo: - /* Flush HW and SW FIFOs. */ - inv_reset_fifo(indio_dev); - inv_clear_kfifo(st); - mutex_unlock(&indio_dev->mlock); - iio_trigger_notify_done(indio_dev->trig); - - return IRQ_HANDLED; -} diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c deleted file mode 100644 index 03b9372c121..00000000000 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c +++ /dev/null @@ -1,155 +0,0 @@ -/* -* Copyright (C) 2012 Invensense, Inc. -* -* This software is licensed under the terms of the GNU General Public -* License version 2, as published by the Free Software Foundation, and -* may be copied, distributed, and modified under those terms. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -*/ - -#include "inv_mpu_iio.h" - -static void inv_scan_query(struct iio_dev *indio_dev) -{ - struct inv_mpu6050_state *st = iio_priv(indio_dev); - - st->chip_config.gyro_fifo_enable = - test_bit(INV_MPU6050_SCAN_GYRO_X, - indio_dev->active_scan_mask) || - test_bit(INV_MPU6050_SCAN_GYRO_Y, - indio_dev->active_scan_mask) || - test_bit(INV_MPU6050_SCAN_GYRO_Z, - indio_dev->active_scan_mask); - - st->chip_config.accl_fifo_enable = - test_bit(INV_MPU6050_SCAN_ACCL_X, - indio_dev->active_scan_mask) || - test_bit(INV_MPU6050_SCAN_ACCL_Y, - indio_dev->active_scan_mask) || - test_bit(INV_MPU6050_SCAN_ACCL_Z, - indio_dev->active_scan_mask); -} - -/** - * inv_mpu6050_set_enable() - enable chip functions. - * @indio_dev: Device driver instance. - * @enable: enable/disable - */ -static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable) -{ - struct inv_mpu6050_state *st = iio_priv(indio_dev); - int result; - - if (enable) { - result = inv_mpu6050_set_power_itg(st, true); - if (result) - return result; - inv_scan_query(indio_dev); - if (st->chip_config.gyro_fifo_enable) { - result = inv_mpu6050_switch_engine(st, true, - INV_MPU6050_BIT_PWR_GYRO_STBY); - if (result) - return result; - } - if (st->chip_config.accl_fifo_enable) { - result = inv_mpu6050_switch_engine(st, true, - INV_MPU6050_BIT_PWR_ACCL_STBY); - if (result) - return result; - } - result = inv_reset_fifo(indio_dev); - if (result) - return result; - } else { - result = inv_mpu6050_write_reg(st, st->reg->fifo_en, 0); - if (result) - return result; - - result = inv_mpu6050_write_reg(st, st->reg->int_enable, 0); - if (result) - return result; - - result = inv_mpu6050_write_reg(st, st->reg->user_ctrl, 0); - if (result) - return result; - - result = inv_mpu6050_switch_engine(st, false, - INV_MPU6050_BIT_PWR_GYRO_STBY); - if (result) - return result; - - result = inv_mpu6050_switch_engine(st, false, - INV_MPU6050_BIT_PWR_ACCL_STBY); - if (result) - return result; - result = inv_mpu6050_set_power_itg(st, false); - if (result) - return result; - } - st->chip_config.enable = enable; - - return 0; -} - -/** - * inv_mpu_data_rdy_trigger_set_state() - set data ready interrupt state - * @trig: Trigger instance - * @state: Desired trigger state - */ -static int inv_mpu_data_rdy_trigger_set_state(struct iio_trigger *trig, - bool state) -{ - return inv_mpu6050_set_enable(iio_trigger_get_drvdata(trig), state); -} - -static const struct iio_trigger_ops inv_mpu_trigger_ops = { - .owner = THIS_MODULE, - .set_trigger_state = &inv_mpu_data_rdy_trigger_set_state, -}; - -int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev) -{ - int ret; - struct inv_mpu6050_state *st = iio_priv(indio_dev); - - st->trig = iio_trigger_alloc("%s-dev%d", - indio_dev->name, - indio_dev->id); - if (st->trig == NULL) { - ret = -ENOMEM; - goto error_ret; - } - ret = request_irq(st->client->irq, &iio_trigger_generic_data_rdy_poll, - IRQF_TRIGGER_RISING, - "inv_mpu", - st->trig); - if (ret) - goto error_free_trig; - st->trig->dev.parent = &st->client->dev; - st->trig->ops = &inv_mpu_trigger_ops; - iio_trigger_set_drvdata(st->trig, indio_dev); - ret = iio_trigger_register(st->trig); - if (ret) - goto error_free_irq; - indio_dev->trig = st->trig; - - return 0; - -error_free_irq: - free_irq(st->client->irq, st->trig); -error_free_trig: - iio_trigger_free(st->trig); -error_ret: - return ret; -} - -void inv_mpu6050_remove_trigger(struct inv_mpu6050_state *st) -{ - iio_trigger_unregister(st->trig); - free_irq(st->client->irq, st->trig); - iio_trigger_free(st->trig); -} |