2019-05-24 12:04:09 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2010-05-07 15:38:59 +01:00
/*
2016-11-20 22:11:24 +01:00
* ADIS16209 Dual - Axis Digital Inclinometer and Accelerometer
2010-05-07 15:38:59 +01:00
*
* Copyright 2010 Analog Devices Inc .
*/
# include <linux/device.h>
# include <linux/kernel.h>
2018-03-02 18:49:23 +05:30
# include <linux/module.h>
2010-05-07 15:38:59 +01:00
# include <linux/spi/spi.h>
2012-04-25 15:54:58 +01:00
# include <linux/iio/iio.h>
2012-11-13 13:28:00 +00:00
# include <linux/iio/imu/adis.h>
2010-05-07 15:38:59 +01:00
2018-03-02 18:53:41 +05:30
# define ADIS16209_STARTUP_DELAY_MS 220
2018-03-02 18:55:56 +05:30
# define ADIS16209_FLASH_CNT_REG 0x00
2017-03-04 15:47:08 +02:00
2018-03-04 18:06:22 +05:30
/* Data Output Register Definitions */
2018-03-02 18:55:56 +05:30
# define ADIS16209_SUPPLY_OUT_REG 0x02
# define ADIS16209_XACCL_OUT_REG 0x04
# define ADIS16209_YACCL_OUT_REG 0x06
2017-03-04 15:47:08 +02:00
/* Output, auxiliary ADC input */
2018-03-02 18:55:56 +05:30
# define ADIS16209_AUX_ADC_REG 0x08
2017-03-04 15:47:08 +02:00
/* Output, temperature */
2018-03-02 18:55:56 +05:30
# define ADIS16209_TEMP_OUT_REG 0x0A
2018-03-04 18:06:22 +05:30
/* Output, +/- 90 degrees X-axis inclination */
2018-03-02 18:55:56 +05:30
# define ADIS16209_XINCL_OUT_REG 0x0C
# define ADIS16209_YINCL_OUT_REG 0x0E
2017-03-04 15:47:08 +02:00
/* Output, +/-180 vertical rotational position */
2018-03-02 18:55:56 +05:30
# define ADIS16209_ROT_OUT_REG 0x10
2017-03-04 15:47:08 +02:00
2018-03-04 18:06:22 +05:30
/*
* Calibration Register Definitions .
* Acceleration , inclination or rotation offset null .
*/
2018-03-02 18:55:56 +05:30
# define ADIS16209_XACCL_NULL_REG 0x12
# define ADIS16209_YACCL_NULL_REG 0x14
# define ADIS16209_XINCL_NULL_REG 0x16
# define ADIS16209_YINCL_NULL_REG 0x18
# define ADIS16209_ROT_NULL_REG 0x1A
2017-03-04 15:47:08 +02:00
2018-03-04 18:06:22 +05:30
/* Alarm Register Definitions */
2018-03-02 18:55:56 +05:30
# define ADIS16209_ALM_MAG1_REG 0x20
# define ADIS16209_ALM_MAG2_REG 0x22
# define ADIS16209_ALM_SMPL1_REG 0x24
# define ADIS16209_ALM_SMPL2_REG 0x26
# define ADIS16209_ALM_CTRL_REG 0x28
2017-03-04 15:47:08 +02:00
2018-03-02 18:55:56 +05:30
# define ADIS16209_AUX_DAC_REG 0x30
# define ADIS16209_GPIO_CTRL_REG 0x32
# define ADIS16209_SMPL_PRD_REG 0x36
# define ADIS16209_AVG_CNT_REG 0x38
# define ADIS16209_SLP_CNT_REG 0x3A
2017-03-04 15:47:08 +02:00
2018-03-04 18:06:22 +05:30
# define ADIS16209_MSC_CTRL_REG 0x34
# define ADIS16209_MSC_CTRL_PWRUP_SELF_TEST BIT(10)
# define ADIS16209_MSC_CTRL_SELF_TEST_EN BIT(8)
# define ADIS16209_MSC_CTRL_DATA_RDY_EN BIT(2)
2017-03-04 15:47:08 +02:00
/* Data-ready polarity: 1 = active high, 0 = active low */
2018-03-04 18:06:22 +05:30
# define ADIS16209_MSC_CTRL_ACTIVE_HIGH BIT(1)
# define ADIS16209_MSC_CTRL_DATA_RDY_DIO2 BIT(0)
2017-03-04 15:47:08 +02:00
2018-03-04 18:11:17 +05:30
# define ADIS16209_STAT_REG 0x3C
# define ADIS16209_STAT_ALARM2 BIT(9)
# define ADIS16209_STAT_ALARM1 BIT(8)
2018-03-29 14:42:02 +05:30
# define ADIS16209_STAT_SELFTEST_FAIL_BIT 5
# define ADIS16209_STAT_SPI_FAIL_BIT 3
# define ADIS16209_STAT_FLASH_UPT_FAIL_BIT 2
2017-03-04 15:47:08 +02:00
/* Power supply above 3.625 V */
2018-03-29 14:42:02 +05:30
# define ADIS16209_STAT_POWER_HIGH_BIT 1
2019-06-25 15:48:40 +03:00
/* Power supply below 2.975 V */
2018-03-29 14:42:02 +05:30
# define ADIS16209_STAT_POWER_LOW_BIT 0
2017-03-04 15:47:08 +02:00
2018-03-04 18:11:17 +05:30
# define ADIS16209_CMD_REG 0x3E
# define ADIS16209_CMD_SW_RESET BIT(7)
# define ADIS16209_CMD_CLEAR_STAT BIT(4)
# define ADIS16209_CMD_FACTORY_CAL BIT(1)
2017-03-04 15:47:08 +02:00
2018-03-04 18:06:22 +05:30
# define ADIS16209_ERROR_ACTIVE BIT(14)
2017-03-04 15:47:08 +02:00
2017-03-05 18:26:41 +02:00
enum adis16209_scan {
ADIS16209_SCAN_SUPPLY ,
ADIS16209_SCAN_ACC_X ,
ADIS16209_SCAN_ACC_Y ,
ADIS16209_SCAN_AUX_ADC ,
ADIS16209_SCAN_TEMP ,
ADIS16209_SCAN_INCLI_X ,
ADIS16209_SCAN_INCLI_Y ,
ADIS16209_SCAN_ROT ,
} ;
2012-11-13 13:28:00 +00:00
static const u8 adis16209_addresses [ 8 ] [ 1 ] = {
[ ADIS16209_SCAN_SUPPLY ] = { } ,
[ ADIS16209_SCAN_AUX_ADC ] = { } ,
2018-03-02 18:55:56 +05:30
[ ADIS16209_SCAN_ACC_X ] = { ADIS16209_XACCL_NULL_REG } ,
[ ADIS16209_SCAN_ACC_Y ] = { ADIS16209_YACCL_NULL_REG } ,
[ ADIS16209_SCAN_INCLI_X ] = { ADIS16209_XINCL_NULL_REG } ,
[ ADIS16209_SCAN_INCLI_Y ] = { ADIS16209_YINCL_NULL_REG } ,
2012-11-13 13:28:00 +00:00
[ ADIS16209_SCAN_ROT ] = { } ,
[ ADIS16209_SCAN_TEMP ] = { } ,
2011-05-18 14:41:49 +01:00
} ;
static int adis16209_write_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
int val ,
int val2 ,
long mask )
{
2012-11-13 13:28:00 +00:00
struct adis * st = iio_priv ( indio_dev ) ;
2018-03-29 14:51:19 +05:30
int m ;
if ( mask ! = IIO_CHAN_INFO_CALIBBIAS )
return - EINVAL ;
switch ( chan - > type ) {
case IIO_ACCEL :
case IIO_INCLI :
m = GENMASK ( 13 , 0 ) ;
break ;
default :
return - EINVAL ;
2011-05-18 14:41:49 +01:00
}
2018-03-29 14:51:19 +05:30
return adis_write_reg_16 ( st , adis16209_addresses [ chan - > scan_index ] [ 0 ] ,
val & m ) ;
2011-05-18 14:41:49 +01:00
}
static int adis16209_read_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
int * val , int * val2 ,
long mask )
{
2012-11-13 13:28:00 +00:00
struct adis * st = iio_priv ( indio_dev ) ;
2011-05-18 14:41:49 +01:00
int ret ;
int bits ;
u8 addr ;
s16 val16 ;
switch ( mask ) {
2012-04-15 17:41:17 +01:00
case IIO_CHAN_INFO_RAW :
2012-11-13 13:28:00 +00:00
return adis_single_conversion ( indio_dev , chan ,
ADIS16209_ERROR_ACTIVE , val ) ;
2011-10-26 17:41:36 +01:00
case IIO_CHAN_INFO_SCALE :
2011-05-18 14:41:49 +01:00
switch ( chan - > type ) {
2011-09-27 09:56:41 +01:00
case IIO_VOLTAGE :
2011-05-18 14:41:49 +01:00
* val = 0 ;
2018-03-04 18:13:12 +05:30
switch ( chan - > channel ) {
case 0 :
2012-10-15 10:35:00 +01:00
* val2 = 305180 ; /* 0.30518 mV */
2018-03-04 18:13:12 +05:30
break ;
case 1 :
2012-10-15 10:35:00 +01:00
* val2 = 610500 ; /* 0.6105 mV */
2018-03-04 18:13:12 +05:30
break ;
default :
return - EINVAL ;
}
2011-05-18 14:41:49 +01:00
return IIO_VAL_INT_PLUS_MICRO ;
case IIO_TEMP :
2018-03-04 18:06:22 +05:30
* val = - 470 ;
2012-10-15 10:35:00 +01:00
* val2 = 0 ;
2011-05-18 14:41:49 +01:00
return IIO_VAL_INT_PLUS_MICRO ;
case IIO_ACCEL :
2018-03-04 18:06:22 +05:30
/*
* IIO base unit for sensitivity of accelerometer
* is milli g .
* 1 LSB represents 0.244 mg .
*/
2011-05-18 14:41:49 +01:00
* val = 0 ;
2018-03-04 18:06:22 +05:30
* val2 = IIO_G_TO_M_S_2 ( 244140 ) ;
2012-10-15 10:35:00 +01:00
return IIO_VAL_INT_PLUS_NANO ;
2011-05-18 14:41:49 +01:00
case IIO_INCLI :
2012-10-15 10:35:00 +01:00
case IIO_ROT :
2018-03-04 18:06:22 +05:30
/*
* IIO base units for rotation are degrees .
* 1 LSB represents 0.025 milli degrees .
*/
2011-05-18 14:41:49 +01:00
* val = 0 ;
2018-03-04 18:06:22 +05:30
* val2 = 25000 ;
2011-05-18 14:41:49 +01:00
return IIO_VAL_INT_PLUS_MICRO ;
default :
return - EINVAL ;
}
break ;
2011-10-26 17:41:36 +01:00
case IIO_CHAN_INFO_OFFSET :
2018-03-04 18:06:22 +05:30
/*
* The raw ADC value is 0x4FE when the temperature
2018-03-29 14:52:51 +05:30
* is 45 degrees and the scale factor per milli
2018-03-04 18:06:22 +05:30
* degree celcius is - 470.
*/
* val = 25000 / - 470 - 0x4FE ;
2011-05-18 14:41:49 +01:00
return IIO_VAL_INT ;
2011-10-26 17:41:36 +01:00
case IIO_CHAN_INFO_CALIBBIAS :
2011-05-18 14:41:49 +01:00
switch ( chan - > type ) {
case IIO_ACCEL :
bits = 14 ;
break ;
default :
return - EINVAL ;
2012-09-28 10:57:00 +01:00
}
2012-11-13 13:28:00 +00:00
addr = adis16209_addresses [ chan - > scan_index ] [ 0 ] ;
ret = adis_read_reg_16 ( st , addr , & val16 ) ;
2017-03-23 02:18:12 -04:00
if ( ret )
2011-05-18 14:41:49 +01:00
return ret ;
2018-03-04 18:15:06 +05:30
* val = sign_extend32 ( val16 , bits - 1 ) ;
2011-05-18 14:41:49 +01:00
return IIO_VAL_INT ;
}
return - EINVAL ;
}
2012-08-09 08:51:00 +01:00
static const struct iio_chan_spec adis16209_channels [ ] = {
2018-03-02 18:55:56 +05:30
ADIS_SUPPLY_CHAN ( ADIS16209_SUPPLY_OUT_REG , ADIS16209_SCAN_SUPPLY ,
0 , 14 ) ,
ADIS_TEMP_CHAN ( ADIS16209_TEMP_OUT_REG , ADIS16209_SCAN_TEMP , 0 , 12 ) ,
ADIS_ACCEL_CHAN ( X , ADIS16209_XACCL_OUT_REG , ADIS16209_SCAN_ACC_X ,
2015-03-25 10:51:55 +03:00
BIT ( IIO_CHAN_INFO_CALIBBIAS ) , 0 , 14 ) ,
2018-03-02 18:55:56 +05:30
ADIS_ACCEL_CHAN ( Y , ADIS16209_YACCL_OUT_REG , ADIS16209_SCAN_ACC_Y ,
2015-03-25 10:51:55 +03:00
BIT ( IIO_CHAN_INFO_CALIBBIAS ) , 0 , 14 ) ,
2018-03-02 18:55:56 +05:30
ADIS_AUX_ADC_CHAN ( ADIS16209_AUX_ADC_REG , ADIS16209_SCAN_AUX_ADC , 0 , 12 ) ,
ADIS_INCLI_CHAN ( X , ADIS16209_XINCL_OUT_REG , ADIS16209_SCAN_INCLI_X ,
2015-03-25 10:51:55 +03:00
0 , 0 , 14 ) ,
2018-03-02 18:55:56 +05:30
ADIS_INCLI_CHAN ( Y , ADIS16209_YINCL_OUT_REG , ADIS16209_SCAN_INCLI_Y ,
2015-03-25 10:51:55 +03:00
0 , 0 , 14 ) ,
2018-03-02 18:55:56 +05:30
ADIS_ROT_CHAN ( X , ADIS16209_ROT_OUT_REG , ADIS16209_SCAN_ROT , 0 , 0 , 14 ) ,
2011-05-18 14:41:49 +01:00
IIO_CHAN_SOFT_TIMESTAMP ( 8 )
} ;
2010-05-07 15:38:59 +01:00
2011-05-18 14:42:37 +01:00
static const struct iio_info adis16209_info = {
2017-03-11 19:56:41 +05:30
. read_raw = adis16209_read_raw ,
. write_raw = adis16209_write_raw ,
2012-11-13 13:28:00 +00:00
. update_scan_mode = adis_update_scan_mode ,
2011-05-18 14:42:37 +01:00
} ;
2012-11-13 13:28:00 +00:00
static const char * const adis16209_status_error_msgs [ ] = {
2018-03-04 18:11:17 +05:30
[ ADIS16209_STAT_SELFTEST_FAIL_BIT ] = " Self test failure " ,
[ ADIS16209_STAT_SPI_FAIL_BIT ] = " SPI failure " ,
[ ADIS16209_STAT_FLASH_UPT_FAIL_BIT ] = " Flash update failed " ,
[ ADIS16209_STAT_POWER_HIGH_BIT ] = " Power supply above 3.625V " ,
2019-06-25 15:48:40 +03:00
[ ADIS16209_STAT_POWER_LOW_BIT ] = " Power supply below 2.975V " ,
2012-11-13 13:28:00 +00:00
} ;
2020-01-07 13:17:04 +02:00
static const struct adis_timeout adis16209_timeouts = {
. reset_ms = ADIS16209_STARTUP_DELAY_MS ,
. self_test_ms = ADIS16209_STARTUP_DELAY_MS ,
. sw_reset_ms = ADIS16209_STARTUP_DELAY_MS ,
} ;
2012-11-13 13:28:00 +00:00
static const struct adis_data adis16209_data = {
. read_delay = 30 ,
2018-03-02 18:55:56 +05:30
. msc_ctrl_reg = ADIS16209_MSC_CTRL_REG ,
2018-03-04 18:11:17 +05:30
. glob_cmd_reg = ADIS16209_CMD_REG ,
. diag_stat_reg = ADIS16209_STAT_REG ,
2012-11-13 13:28:00 +00:00
. self_test_mask = ADIS16209_MSC_CTRL_SELF_TEST_EN ,
2020-02-10 15:26:02 +02:00
. self_test_reg = ADIS16209_MSC_CTRL_REG ,
2016-04-15 16:59:41 +02:00
. self_test_no_autoclear = true ,
2020-01-07 13:17:04 +02:00
. timeouts = & adis16209_timeouts ,
2012-11-13 13:28:00 +00:00
. status_error_msgs = adis16209_status_error_msgs ,
2018-03-04 18:11:17 +05:30
. status_error_mask = BIT ( ADIS16209_STAT_SELFTEST_FAIL_BIT ) |
BIT ( ADIS16209_STAT_SPI_FAIL_BIT ) |
BIT ( ADIS16209_STAT_FLASH_UPT_FAIL_BIT ) |
BIT ( ADIS16209_STAT_POWER_HIGH_BIT ) |
BIT ( ADIS16209_STAT_POWER_LOW_BIT ) ,
2012-11-13 13:28:00 +00:00
} ;
2012-11-19 13:21:57 -05:00
static int adis16209_probe ( struct spi_device * spi )
2010-05-07 15:38:59 +01:00
{
2011-06-27 13:07:13 +01:00
struct iio_dev * indio_dev ;
2018-03-29 14:43:23 +05:30
struct adis * st ;
int ret ;
2010-05-07 15:38:59 +01:00
2013-08-24 19:48:00 +01:00
indio_dev = devm_iio_device_alloc ( & spi - > dev , sizeof ( * st ) ) ;
if ( ! indio_dev )
return - ENOMEM ;
2018-03-29 14:44:42 +05:30
2011-06-27 13:07:13 +01:00
st = iio_priv ( indio_dev ) ;
2010-05-07 15:38:59 +01:00
2011-06-27 13:07:13 +01:00
indio_dev - > name = spi - > dev . driver - > name ;
indio_dev - > info = & adis16209_info ;
indio_dev - > channels = adis16209_channels ;
indio_dev - > num_channels = ARRAY_SIZE ( adis16209_channels ) ;
indio_dev - > modes = INDIO_DIRECT_MODE ;
2010-05-07 15:38:59 +01:00
2012-11-13 13:28:00 +00:00
ret = adis_init ( st , indio_dev , spi , & adis16209_data ) ;
if ( ret )
2013-08-24 19:48:00 +01:00
return ret ;
2018-03-29 14:44:42 +05:30
2020-09-15 14:02:50 +02:00
ret = devm_adis_setup_buffer_and_trigger ( st , indio_dev , NULL ) ;
2010-05-07 15:38:59 +01:00
if ( ret )
2013-08-24 19:48:00 +01:00
return ret ;
2010-05-07 15:38:59 +01:00
2022-11-22 10:27:51 +02:00
ret = __adis_initial_startup ( st ) ;
2010-05-07 15:38:59 +01:00
if ( ret )
2020-09-15 14:02:50 +02:00
return ret ;
2010-05-07 15:38:59 +01:00
2020-09-15 14:02:50 +02:00
return devm_iio_device_register ( & spi - > dev , indio_dev ) ;
2010-05-07 15:38:59 +01:00
}
static struct spi_driver adis16209_driver = {
. driver = {
. name = " adis16209 " ,
} ,
. probe = adis16209_probe ,
} ;
2011-11-16 10:13:39 +01:00
module_spi_driver ( adis16209_driver ) ;
2010-05-07 15:38:59 +01:00
MODULE_AUTHOR ( " Barry Song <21cnbao@gmail.com> " ) ;
2016-11-20 22:11:24 +01:00
MODULE_DESCRIPTION ( " Analog Devices ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer " ) ;
2010-05-07 15:38:59 +01:00
MODULE_LICENSE ( " GPL v2 " ) ;
2011-11-16 08:53:31 +01:00
MODULE_ALIAS ( " spi:adis16209 " ) ;
2022-01-30 20:56:53 +00:00
MODULE_IMPORT_NS ( IIO_ADISLIB ) ;