2019-05-24 13:04:09 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2010-10-28 05:43:49 +04:00
/*
2016-11-21 00:11:24 +03:00
* ADIS16201 Dual - Axis Digital Inclinometer and Accelerometer
2010-10-28 05:43:49 +04:00
*
* Copyright 2010 Analog Devices Inc .
*/
# include <linux/device.h>
# include <linux/kernel.h>
2018-03-05 10:49:20 +03:00
# include <linux/module.h>
# include <linux/spi/spi.h>
2010-10-28 05:43:49 +04:00
2012-04-25 18:54:58 +04:00
# include <linux/iio/iio.h>
2012-11-13 17:28:00 +04:00
# include <linux/iio/imu/adis.h>
2011-05-18 17:41:46 +04:00
2018-03-16 23:06:21 +03:00
# define ADIS16201_STARTUP_DELAY_MS 220
# define ADIS16201_FLASH_CNT 0x00
/* Data Output Register Information */
# define ADIS16201_SUPPLY_OUT_REG 0x02
# define ADIS16201_XACCL_OUT_REG 0x04
# define ADIS16201_YACCL_OUT_REG 0x06
# define ADIS16201_AUX_ADC_REG 0x08
# define ADIS16201_TEMP_OUT_REG 0x0A
# define ADIS16201_XINCL_OUT_REG 0x0C
# define ADIS16201_YINCL_OUT_REG 0x0E
/* Calibration Register Definition */
# define ADIS16201_XACCL_OFFS_REG 0x10
# define ADIS16201_YACCL_OFFS_REG 0x12
# define ADIS16201_XACCL_SCALE_REG 0x14
# define ADIS16201_YACCL_SCALE_REG 0x16
# define ADIS16201_XINCL_OFFS_REG 0x18
# define ADIS16201_YINCL_OFFS_REG 0x1A
# define ADIS16201_XINCL_SCALE_REG 0x1C
# define ADIS16201_YINCL_SCALE_REG 0x1E
/* Alarm Register Definition */
# define ADIS16201_ALM_MAG1_REG 0x20
# define ADIS16201_ALM_MAG2_REG 0x22
# define ADIS16201_ALM_SMPL1_REG 0x24
# define ADIS16201_ALM_SMPL2_REG 0x26
# define ADIS16201_ALM_CTRL_REG 0x28
# define ADIS16201_AUX_DAC_REG 0x30
# define ADIS16201_GPIO_CTRL_REG 0x32
# define ADIS16201_SMPL_PRD_REG 0x36
2017-02-28 21:51:17 +03:00
/* Operation, filter configuration */
2018-03-16 23:06:21 +03:00
# define ADIS16201_AVG_CNT_REG 0x38
# define ADIS16201_SLP_CNT_REG 0x3A
2017-02-28 21:51:17 +03:00
2018-03-16 23:06:21 +03:00
/* Miscellaneous Control Register Definition */
# define ADIS16201_MSC_CTRL_REG 0x34
# define ADIS16201_MSC_CTRL_SELF_TEST_EN BIT(8)
2017-02-28 21:51:17 +03:00
/* Data-ready enable: 1 = enabled, 0 = disabled */
2018-03-16 23:06:21 +03:00
# define ADIS16201_MSC_CTRL_DATA_RDY_EN BIT(2)
2017-02-28 21:51:17 +03:00
/* Data-ready polarity: 1 = active high, 0 = active low */
2018-03-16 23:06:21 +03:00
# define ADIS16201_MSC_CTRL_ACTIVE_DATA_RDY_HIGH BIT(1)
2017-02-28 21:51:17 +03:00
/* Data-ready line selection: 1 = DIO1, 0 = DIO0 */
2018-03-16 23:06:21 +03:00
# define ADIS16201_MSC_CTRL_DATA_RDY_DIO1 BIT(0)
/* Diagnostics System Status Register Definition */
# define ADIS16201_DIAG_STAT_REG 0x3C
# define ADIS16201_DIAG_STAT_ALARM2 BIT(9)
# define ADIS16201_DIAG_STAT_ALARM1 BIT(8)
# define ADIS16201_DIAG_STAT_SPI_FAIL_BIT 3
# define ADIS16201_DIAG_STAT_FLASH_UPT_FAIL_BIT 2
2017-02-28 21:51:17 +03:00
/* Power supply above 3.625 V */
2018-03-16 23:06:21 +03:00
# define ADIS16201_DIAG_STAT_POWER_HIGH_BIT 1
2019-06-25 15:48:40 +03:00
/* Power supply below 2.975 V */
2018-03-16 23:06:21 +03:00
# define ADIS16201_DIAG_STAT_POWER_LOW_BIT 0
2017-02-28 21:51:17 +03:00
2018-03-16 23:06:21 +03:00
/* System Command Register Definition */
# define ADIS16201_GLOB_CMD_REG 0x3E
# define ADIS16201_GLOB_CMD_SW_RESET BIT(7)
# define ADIS16201_GLOB_CMD_FACTORY_RESET BIT(1)
2017-02-28 21:51:17 +03:00
2018-03-16 23:06:21 +03:00
# define ADIS16201_ERROR_ACTIVE BIT(14)
2017-02-28 21:51:17 +03:00
enum adis16201_scan {
ADIS16201_SCAN_ACC_X ,
ADIS16201_SCAN_ACC_Y ,
ADIS16201_SCAN_INCLI_X ,
ADIS16201_SCAN_INCLI_Y ,
ADIS16201_SCAN_SUPPLY ,
ADIS16201_SCAN_AUX_ADC ,
ADIS16201_SCAN_TEMP ,
} ;
2010-10-28 05:43:49 +04:00
2012-11-13 17:28:00 +04:00
static const u8 adis16201_addresses [ ] = {
2018-03-16 23:06:20 +03:00
[ ADIS16201_SCAN_ACC_X ] = ADIS16201_XACCL_OFFS_REG ,
[ ADIS16201_SCAN_ACC_Y ] = ADIS16201_YACCL_OFFS_REG ,
[ ADIS16201_SCAN_INCLI_X ] = ADIS16201_XINCL_OFFS_REG ,
[ ADIS16201_SCAN_INCLI_Y ] = ADIS16201_YINCL_OFFS_REG ,
2011-05-18 17:41:46 +04:00
} ;
static int adis16201_read_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
int * val , int * val2 ,
long mask )
{
2012-11-13 17:28:00 +04:00
struct adis * st = iio_priv ( indio_dev ) ;
2011-05-18 17:41:46 +04:00
int ret ;
int bits ;
u8 addr ;
s16 val16 ;
switch ( mask ) {
2012-04-15 20:41:17 +04:00
case IIO_CHAN_INFO_RAW :
2012-11-13 17:28:00 +04:00
return adis_single_conversion ( indio_dev , chan ,
2018-03-16 23:06:25 +03:00
ADIS16201_ERROR_ACTIVE , val ) ;
2011-10-26 20:41:36 +04:00
case IIO_CHAN_INFO_SCALE :
2011-05-18 17:41:46 +04:00
switch ( chan - > type ) {
2011-09-27 12:56:41 +04:00
case IIO_VOLTAGE :
2012-10-15 13:35:00 +04:00
if ( chan - > channel = = 0 ) {
2018-03-16 23:06:22 +03:00
/* Voltage base units are mV hence 1.22 mV */
2012-10-15 13:35:00 +04:00
* val = 1 ;
2018-03-16 23:06:22 +03:00
* val2 = 220000 ;
2012-10-15 13:35:00 +04:00
} else {
2018-03-16 23:06:22 +03:00
/* Voltage base units are mV hence 0.61 mV */
2012-10-15 13:35:00 +04:00
* val = 0 ;
2018-03-16 23:06:22 +03:00
* val2 = 610000 ;
2012-10-15 13:35:00 +04:00
}
2011-05-18 17:41:46 +04:00
return IIO_VAL_INT_PLUS_MICRO ;
case IIO_TEMP :
2018-03-16 23:06:22 +03:00
* val = - 470 ;
2012-10-15 13:35:00 +04:00
* val2 = 0 ;
2011-05-18 17:41:46 +04:00
return IIO_VAL_INT_PLUS_MICRO ;
case IIO_ACCEL :
2018-03-16 23:06:22 +03:00
/*
* IIO base unit for sensitivity of accelerometer
* is milli g .
* 1 LSB represents 0.244 mg .
*/
2011-05-18 17:41:46 +04:00
* val = 0 ;
2018-03-16 23:06:22 +03:00
* val2 = IIO_G_TO_M_S_2 ( 462400 ) ;
2012-10-15 13:35:00 +04:00
return IIO_VAL_INT_PLUS_NANO ;
2011-05-18 17:41:46 +04:00
case IIO_INCLI :
* val = 0 ;
2018-03-16 23:06:22 +03:00
* val2 = 100000 ;
2011-05-18 17:41:46 +04:00
return IIO_VAL_INT_PLUS_MICRO ;
default :
return - EINVAL ;
}
break ;
2011-10-26 20:41:36 +04:00
case IIO_CHAN_INFO_OFFSET :
2018-03-16 23:06:22 +03:00
/*
* The raw ADC value is 1278 when the temperature
* is 25 degrees and the scale factor per milli
* degree celcius is - 470.
*/
* val = 25000 / - 470 - 1278 ;
2011-05-18 17:41:46 +04:00
return IIO_VAL_INT ;
2011-10-26 20:41:36 +04:00
case IIO_CHAN_INFO_CALIBBIAS :
2011-05-18 17:41:46 +04:00
switch ( chan - > type ) {
case IIO_ACCEL :
bits = 12 ;
break ;
case IIO_INCLI :
bits = 9 ;
break ;
default :
return - EINVAL ;
2012-09-28 13:57:00 +04:00
}
2012-11-13 17:28:00 +04:00
addr = adis16201_addresses [ chan - > scan_index ] ;
ret = adis_read_reg_16 ( st , addr , & val16 ) ;
2017-03-18 00:43:56 +03:00
if ( ret )
2011-05-18 17:41:46 +04:00
return ret ;
2018-03-16 23:06:23 +03:00
* val = sign_extend32 ( val16 , bits - 1 ) ;
2011-05-18 17:41:46 +04:00
return IIO_VAL_INT ;
}
2018-03-05 10:49:21 +03:00
2011-05-18 17:41:46 +04:00
return - EINVAL ;
}
static int adis16201_write_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
int val ,
int val2 ,
long mask )
{
2012-11-13 17:28:00 +04:00
struct adis * st = iio_priv ( indio_dev ) ;
2018-03-22 22:12:43 +03:00
int m ;
2014-07-08 04:22:00 +04:00
2018-03-22 22:12:43 +03:00
if ( mask ! = IIO_CHAN_INFO_CALIBBIAS )
return - EINVAL ;
switch ( chan - > type ) {
case IIO_ACCEL :
m = GENMASK ( 11 , 0 ) ;
break ;
case IIO_INCLI :
m = GENMASK ( 8 , 0 ) ;
break ;
default :
return - EINVAL ;
2011-05-18 17:41:46 +04:00
}
2018-03-05 10:49:21 +03:00
2018-03-22 22:12:43 +03:00
return adis_write_reg_16 ( st , adis16201_addresses [ chan - > scan_index ] ,
val & m ) ;
2011-05-18 17:41:46 +04:00
}
2012-08-09 11:51:00 +04:00
static const struct iio_chan_spec adis16201_channels [ ] = {
2018-03-22 22:12:44 +03:00
ADIS_SUPPLY_CHAN ( ADIS16201_SUPPLY_OUT_REG , ADIS16201_SCAN_SUPPLY , 0 ,
12 ) ,
2018-03-16 23:06:20 +03:00
ADIS_TEMP_CHAN ( ADIS16201_TEMP_OUT_REG , ADIS16201_SCAN_TEMP , 0 , 12 ) ,
ADIS_ACCEL_CHAN ( X , ADIS16201_XACCL_OUT_REG , ADIS16201_SCAN_ACC_X ,
2015-03-25 10:51:55 +03:00
BIT ( IIO_CHAN_INFO_CALIBBIAS ) , 0 , 14 ) ,
2018-03-16 23:06:20 +03:00
ADIS_ACCEL_CHAN ( Y , ADIS16201_YACCL_OUT_REG , ADIS16201_SCAN_ACC_Y ,
2015-03-25 10:51:55 +03:00
BIT ( IIO_CHAN_INFO_CALIBBIAS ) , 0 , 14 ) ,
2018-03-16 23:06:20 +03:00
ADIS_AUX_ADC_CHAN ( ADIS16201_AUX_ADC_REG , ADIS16201_SCAN_AUX_ADC , 0 , 12 ) ,
ADIS_INCLI_CHAN ( X , ADIS16201_XINCL_OUT_REG , ADIS16201_SCAN_INCLI_X ,
2015-03-25 10:51:55 +03:00
BIT ( IIO_CHAN_INFO_CALIBBIAS ) , 0 , 14 ) ,
2021-03-21 21:29:56 +03:00
ADIS_INCLI_CHAN ( Y , ADIS16201_YINCL_OUT_REG , ADIS16201_SCAN_INCLI_Y ,
2015-03-25 10:51:55 +03:00
BIT ( IIO_CHAN_INFO_CALIBBIAS ) , 0 , 14 ) ,
2011-05-18 17:41:46 +04:00
IIO_CHAN_SOFT_TIMESTAMP ( 7 )
} ;
2010-10-28 05:43:49 +04:00
2011-05-18 17:42:37 +04:00
static const struct iio_info adis16201_info = {
2017-03-11 17:26:40 +03:00
. read_raw = adis16201_read_raw ,
. write_raw = adis16201_write_raw ,
2012-11-13 17:28:00 +04:00
. update_scan_mode = adis_update_scan_mode ,
2011-05-18 17:42:37 +04:00
} ;
2012-11-13 17:28:00 +04:00
static const char * const adis16201_status_error_msgs [ ] = {
[ ADIS16201_DIAG_STAT_SPI_FAIL_BIT ] = " SPI failure " ,
2018-03-16 23:06:18 +03:00
[ ADIS16201_DIAG_STAT_FLASH_UPT_FAIL_BIT ] = " Flash update failed " ,
2012-11-13 17:28:00 +04:00
[ ADIS16201_DIAG_STAT_POWER_HIGH_BIT ] = " Power supply above 3.625V " ,
2019-06-25 15:48:40 +03:00
[ ADIS16201_DIAG_STAT_POWER_LOW_BIT ] = " Power supply below 2.975V " ,
2012-11-13 17:28:00 +04:00
} ;
2020-01-07 14:17:04 +03:00
static const struct adis_timeout adis16201_timeouts = {
. reset_ms = ADIS16201_STARTUP_DELAY_MS ,
. sw_reset_ms = ADIS16201_STARTUP_DELAY_MS ,
. self_test_ms = ADIS16201_STARTUP_DELAY_MS ,
} ;
2012-11-13 17:28:00 +04:00
static const struct adis_data adis16201_data = {
. read_delay = 20 ,
2018-03-16 23:06:20 +03:00
. msc_ctrl_reg = ADIS16201_MSC_CTRL_REG ,
. glob_cmd_reg = ADIS16201_GLOB_CMD_REG ,
. diag_stat_reg = ADIS16201_DIAG_STAT_REG ,
2012-11-13 17:28:00 +04:00
. self_test_mask = ADIS16201_MSC_CTRL_SELF_TEST_EN ,
2020-02-10 16:26:02 +03:00
. self_test_reg = ADIS16201_MSC_CTRL_REG ,
2016-04-15 17:59:39 +03:00
. self_test_no_autoclear = true ,
2020-01-07 14:17:04 +03:00
. timeouts = & adis16201_timeouts ,
2012-11-13 17:28:00 +04:00
. status_error_msgs = adis16201_status_error_msgs ,
. status_error_mask = BIT ( ADIS16201_DIAG_STAT_SPI_FAIL_BIT ) |
2018-03-16 23:06:18 +03:00
BIT ( ADIS16201_DIAG_STAT_FLASH_UPT_FAIL_BIT ) |
2012-11-13 17:28:00 +04:00
BIT ( ADIS16201_DIAG_STAT_POWER_HIGH_BIT ) |
BIT ( ADIS16201_DIAG_STAT_POWER_LOW_BIT ) ,
} ;
2012-11-19 22:21:57 +04:00
static int adis16201_probe ( struct spi_device * spi )
2010-10-28 05:43:49 +04:00
{
2011-06-27 16:07:58 +04:00
struct iio_dev * indio_dev ;
2018-03-16 23:06:24 +03:00
struct adis * st ;
int ret ;
2011-06-27 16:07:58 +04:00
2013-08-24 22:48:00 +04:00
indio_dev = devm_iio_device_alloc ( & spi - > dev , sizeof ( * st ) ) ;
if ( ! indio_dev )
return - ENOMEM ;
2011-06-27 16:07:58 +04:00
st = iio_priv ( indio_dev ) ;
2010-10-28 05:43:49 +04:00
2011-06-27 16:07:58 +04:00
indio_dev - > name = spi - > dev . driver - > name ;
indio_dev - > info = & adis16201_info ;
2011-05-18 17:42:37 +04:00
2011-06-27 16:07:58 +04:00
indio_dev - > channels = adis16201_channels ;
indio_dev - > num_channels = ARRAY_SIZE ( adis16201_channels ) ;
indio_dev - > modes = INDIO_DIRECT_MODE ;
2010-10-28 05:43:49 +04:00
2012-11-13 17:28:00 +04:00
ret = adis_init ( st , indio_dev , spi , & adis16201_data ) ;
if ( ret )
2013-08-24 22:48:00 +04:00
return ret ;
2018-03-05 10:49:21 +03:00
2020-09-15 15:02:49 +03:00
ret = devm_adis_setup_buffer_and_trigger ( st , indio_dev , NULL ) ;
2010-10-28 05:43:49 +04:00
if ( ret )
2013-08-24 22:48:00 +04:00
return ret ;
2010-10-28 05:43:49 +04:00
2022-11-22 11:27:50 +03:00
ret = __adis_initial_startup ( st ) ;
2010-10-28 05:43:49 +04:00
if ( ret )
2020-09-15 15:02:49 +03:00
return ret ;
2010-10-28 05:43:49 +04:00
2020-09-15 15:02:49 +03:00
return devm_iio_device_register ( & spi - > dev , indio_dev ) ;
2010-10-28 05:43:49 +04:00
}
static struct spi_driver adis16201_driver = {
. driver = {
. name = " adis16201 " ,
} ,
. probe = adis16201_probe ,
} ;
2011-11-16 13:13:39 +04:00
module_spi_driver ( adis16201_driver ) ;
2010-10-28 05:43:49 +04:00
MODULE_AUTHOR ( " Barry Song <21cnbao@gmail.com> " ) ;
2016-11-21 00:11:24 +03:00
MODULE_DESCRIPTION ( " Analog Devices ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer " ) ;
2010-10-28 05:43:49 +04:00
MODULE_LICENSE ( " GPL v2 " ) ;
2011-11-16 11:53:31 +04:00
MODULE_ALIAS ( " spi:adis16201 " ) ;
2022-01-30 23:56:53 +03:00
MODULE_IMPORT_NS ( IIO_ADISLIB ) ;