2010-05-07 18:38:59 +04:00
/*
2016-11-21 00:11:24 +03:00
* ADIS16209 Dual - Axis Digital Inclinometer and Accelerometer
2010-05-07 18:38:59 +04:00
*
* Copyright 2010 Analog Devices Inc .
*
* Licensed under the GPL - 2 or later .
*/
# include <linux/device.h>
# include <linux/kernel.h>
2018-03-02 16:19:23 +03:00
# include <linux/list.h>
# include <linux/module.h>
2010-05-07 18:38:59 +04:00
# include <linux/spi/spi.h>
2010-05-23 11:10:35 +04:00
# include <linux/slab.h>
2010-05-07 18:38:59 +04:00
# include <linux/sysfs.h>
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>
2010-05-07 18:38:59 +04:00
2018-03-02 16:23:41 +03:00
# define ADIS16209_STARTUP_DELAY_MS 220
2018-03-02 16:25:56 +03:00
# define ADIS16209_FLASH_CNT_REG 0x00
2017-03-04 16:47:08 +03:00
2018-03-04 15:36:22 +03:00
/* Data Output Register Definitions */
2018-03-02 16:25:56 +03:00
# define ADIS16209_SUPPLY_OUT_REG 0x02
# define ADIS16209_XACCL_OUT_REG 0x04
# define ADIS16209_YACCL_OUT_REG 0x06
2017-03-04 16:47:08 +03:00
/* Output, auxiliary ADC input */
2018-03-02 16:25:56 +03:00
# define ADIS16209_AUX_ADC_REG 0x08
2017-03-04 16:47:08 +03:00
/* Output, temperature */
2018-03-02 16:25:56 +03:00
# define ADIS16209_TEMP_OUT_REG 0x0A
2018-03-04 15:36:22 +03:00
/* Output, +/- 90 degrees X-axis inclination */
2018-03-02 16:25:56 +03:00
# define ADIS16209_XINCL_OUT_REG 0x0C
# define ADIS16209_YINCL_OUT_REG 0x0E
2017-03-04 16:47:08 +03:00
/* Output, +/-180 vertical rotational position */
2018-03-02 16:25:56 +03:00
# define ADIS16209_ROT_OUT_REG 0x10
2017-03-04 16:47:08 +03:00
2018-03-04 15:36:22 +03:00
/*
* Calibration Register Definitions .
* Acceleration , inclination or rotation offset null .
*/
2018-03-02 16:25:56 +03:00
# 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 16:47:08 +03:00
2018-03-04 15:36:22 +03:00
/* Alarm Register Definitions */
2018-03-02 16:25:56 +03:00
# 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 16:47:08 +03:00
2018-03-02 16:25:56 +03:00
# 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 16:47:08 +03:00
2018-03-04 15:36:22 +03:00
# 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 16:47:08 +03:00
/* Data-ready polarity: 1 = active high, 0 = active low */
2018-03-04 15:36:22 +03:00
# define ADIS16209_MSC_CTRL_ACTIVE_HIGH BIT(1)
# define ADIS16209_MSC_CTRL_DATA_RDY_DIO2 BIT(0)
2017-03-04 16:47:08 +03:00
2018-03-04 15:41:17 +03:00
# define ADIS16209_STAT_REG 0x3C
# define ADIS16209_STAT_ALARM2 BIT(9)
# define ADIS16209_STAT_ALARM1 BIT(8)
2018-03-29 12:12:02 +03:00
# 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 16:47:08 +03:00
/* Power supply above 3.625 V */
2018-03-29 12:12:02 +03:00
# define ADIS16209_STAT_POWER_HIGH_BIT 1
2019-06-25 15:48:40 +03:00
/* Power supply below 2.975 V */
2018-03-29 12:12:02 +03:00
# define ADIS16209_STAT_POWER_LOW_BIT 0
2017-03-04 16:47:08 +03:00
2018-03-04 15:41:17 +03:00
# 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 16:47:08 +03:00
2018-03-04 15:36:22 +03:00
# define ADIS16209_ERROR_ACTIVE BIT(14)
2017-03-04 16:47:08 +03:00
2017-03-05 19:26:41 +03: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 17:28:00 +04:00
static const u8 adis16209_addresses [ 8 ] [ 1 ] = {
[ ADIS16209_SCAN_SUPPLY ] = { } ,
[ ADIS16209_SCAN_AUX_ADC ] = { } ,
2018-03-02 16:25:56 +03:00
[ 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 17:28:00 +04:00
[ ADIS16209_SCAN_ROT ] = { } ,
[ ADIS16209_SCAN_TEMP ] = { } ,
2011-05-18 17:41:49 +04: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 17:28:00 +04:00
struct adis * st = iio_priv ( indio_dev ) ;
2018-03-29 12:21:19 +03:00
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 17:41:49 +04:00
}
2018-03-29 12:21:19 +03:00
return adis_write_reg_16 ( st , adis16209_addresses [ chan - > scan_index ] [ 0 ] ,
val & m ) ;
2011-05-18 17:41:49 +04: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 17:28:00 +04:00
struct adis * st = iio_priv ( indio_dev ) ;
2011-05-18 17:41:49 +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 ,
ADIS16209_ERROR_ACTIVE , val ) ;
2011-10-26 20:41:36 +04:00
case IIO_CHAN_INFO_SCALE :
2011-05-18 17:41:49 +04:00
switch ( chan - > type ) {
2011-09-27 12:56:41 +04:00
case IIO_VOLTAGE :
2011-05-18 17:41:49 +04:00
* val = 0 ;
2018-03-04 15:43:12 +03:00
switch ( chan - > channel ) {
case 0 :
2012-10-15 13:35:00 +04:00
* val2 = 305180 ; /* 0.30518 mV */
2018-03-04 15:43:12 +03:00
break ;
case 1 :
2012-10-15 13:35:00 +04:00
* val2 = 610500 ; /* 0.6105 mV */
2018-03-04 15:43:12 +03:00
break ;
default :
return - EINVAL ;
}
2011-05-18 17:41:49 +04:00
return IIO_VAL_INT_PLUS_MICRO ;
case IIO_TEMP :
2018-03-04 15:36:22 +03:00
* val = - 470 ;
2012-10-15 13:35:00 +04:00
* val2 = 0 ;
2011-05-18 17:41:49 +04:00
return IIO_VAL_INT_PLUS_MICRO ;
case IIO_ACCEL :
2018-03-04 15:36:22 +03:00
/*
* IIO base unit for sensitivity of accelerometer
* is milli g .
* 1 LSB represents 0.244 mg .
*/
2011-05-18 17:41:49 +04:00
* val = 0 ;
2018-03-04 15:36:22 +03:00
* val2 = IIO_G_TO_M_S_2 ( 244140 ) ;
2012-10-15 13:35:00 +04:00
return IIO_VAL_INT_PLUS_NANO ;
2011-05-18 17:41:49 +04:00
case IIO_INCLI :
2012-10-15 13:35:00 +04:00
case IIO_ROT :
2018-03-04 15:36:22 +03:00
/*
* IIO base units for rotation are degrees .
* 1 LSB represents 0.025 milli degrees .
*/
2011-05-18 17:41:49 +04:00
* val = 0 ;
2018-03-04 15:36:22 +03:00
* val2 = 25000 ;
2011-05-18 17:41:49 +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-04 15:36:22 +03:00
/*
* The raw ADC value is 0x4FE when the temperature
2018-03-29 12:22:51 +03:00
* is 45 degrees and the scale factor per milli
2018-03-04 15:36:22 +03:00
* degree celcius is - 470.
*/
* val = 25000 / - 470 - 0x4FE ;
2011-05-18 17:41:49 +04:00
return IIO_VAL_INT ;
2011-10-26 20:41:36 +04:00
case IIO_CHAN_INFO_CALIBBIAS :
2011-05-18 17:41:49 +04:00
switch ( chan - > type ) {
case IIO_ACCEL :
bits = 14 ;
break ;
default :
return - EINVAL ;
2012-09-28 13:57:00 +04:00
}
2012-11-13 17:28:00 +04:00
addr = adis16209_addresses [ chan - > scan_index ] [ 0 ] ;
ret = adis_read_reg_16 ( st , addr , & val16 ) ;
2017-03-23 09:18:12 +03:00
if ( ret )
2011-05-18 17:41:49 +04:00
return ret ;
2018-03-04 15:45:06 +03:00
* val = sign_extend32 ( val16 , bits - 1 ) ;
2011-05-18 17:41:49 +04:00
return IIO_VAL_INT ;
}
return - EINVAL ;
}
2012-08-09 11:51:00 +04:00
static const struct iio_chan_spec adis16209_channels [ ] = {
2018-03-02 16:25:56 +03:00
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 16:25:56 +03:00
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 16:25:56 +03:00
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 16:25:56 +03:00
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 16:25:56 +03:00
ADIS_ROT_CHAN ( X , ADIS16209_ROT_OUT_REG , ADIS16209_SCAN_ROT , 0 , 0 , 14 ) ,
2011-05-18 17:41:49 +04:00
IIO_CHAN_SOFT_TIMESTAMP ( 8 )
} ;
2010-05-07 18:38:59 +04:00
2011-05-18 17:42:37 +04:00
static const struct iio_info adis16209_info = {
2017-03-11 17:26:41 +03:00
. read_raw = adis16209_read_raw ,
. write_raw = adis16209_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 adis16209_status_error_msgs [ ] = {
2018-03-04 15:41:17 +03:00
[ 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 17:28:00 +04:00
} ;
static const struct adis_data adis16209_data = {
. read_delay = 30 ,
2018-03-02 16:25:56 +03:00
. msc_ctrl_reg = ADIS16209_MSC_CTRL_REG ,
2018-03-04 15:41:17 +03:00
. glob_cmd_reg = ADIS16209_CMD_REG ,
. diag_stat_reg = ADIS16209_STAT_REG ,
2012-11-13 17:28:00 +04:00
. self_test_mask = ADIS16209_MSC_CTRL_SELF_TEST_EN ,
2016-04-15 17:59:41 +03:00
. self_test_no_autoclear = true ,
2018-03-02 16:23:41 +03:00
. startup_delay = ADIS16209_STARTUP_DELAY_MS ,
2012-11-13 17:28:00 +04:00
. status_error_msgs = adis16209_status_error_msgs ,
2018-03-04 15:41:17 +03:00
. 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 17:28:00 +04:00
} ;
2012-11-19 22:21:57 +04:00
static int adis16209_probe ( struct spi_device * spi )
2010-05-07 18:38:59 +04:00
{
2011-06-27 16:07:13 +04:00
struct iio_dev * indio_dev ;
2018-03-29 12:13:23 +03:00
struct adis * st ;
int ret ;
2010-05-07 18:38:59 +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 ;
2018-03-29 12:14:42 +03:00
2011-06-27 16:07:13 +04:00
st = iio_priv ( indio_dev ) ;
spi_set_drvdata ( spi , indio_dev ) ;
2010-05-07 18:38:59 +04:00
2011-06-27 16:07:13 +04:00
indio_dev - > name = spi - > dev . driver - > name ;
indio_dev - > dev . parent = & spi - > dev ;
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 18:38:59 +04:00
2012-11-13 17:28:00 +04:00
ret = adis_init ( st , indio_dev , spi , & adis16209_data ) ;
if ( ret )
2013-08-24 22:48:00 +04:00
return ret ;
2018-03-29 12:14:42 +03:00
2012-11-13 17:28:00 +04:00
ret = adis_setup_buffer_and_trigger ( st , indio_dev , NULL ) ;
2010-05-07 18:38:59 +04:00
if ( ret )
2013-08-24 22:48:00 +04:00
return ret ;
2010-05-07 18:38:59 +04:00
2012-11-13 17:28:00 +04:00
ret = adis_initial_startup ( st ) ;
2010-05-07 18:38:59 +04:00
if ( ret )
2012-11-13 17:28:00 +04:00
goto error_cleanup_buffer_trigger ;
2011-09-02 20:14:40 +04:00
ret = iio_device_register ( indio_dev ) ;
if ( ret )
2012-11-13 17:28:00 +04:00
goto error_cleanup_buffer_trigger ;
2011-09-02 20:14:40 +04:00
2010-05-07 18:38:59 +04:00
return 0 ;
2012-11-13 17:28:00 +04:00
error_cleanup_buffer_trigger :
adis_cleanup_buffer_and_trigger ( st , indio_dev ) ;
2010-05-07 18:38:59 +04:00
return ret ;
}
2012-11-19 22:26:37 +04:00
static int adis16209_remove ( struct spi_device * spi )
2010-05-07 18:38:59 +04:00
{
2011-06-27 16:07:13 +04:00
struct iio_dev * indio_dev = spi_get_drvdata ( spi ) ;
2012-11-13 17:28:00 +04:00
struct adis * st = iio_priv ( indio_dev ) ;
2010-05-07 18:38:59 +04:00
2011-10-14 17:46:58 +04:00
iio_device_unregister ( indio_dev ) ;
2012-11-13 17:28:00 +04:00
adis_cleanup_buffer_and_trigger ( st , indio_dev ) ;
2010-05-07 18:38:59 +04:00
return 0 ;
}
static struct spi_driver adis16209_driver = {
. driver = {
. name = " adis16209 " ,
} ,
. probe = adis16209_probe ,
2012-11-19 22:21:38 +04:00
. remove = adis16209_remove ,
2010-05-07 18:38:59 +04:00
} ;
2011-11-16 13:13:39 +04:00
module_spi_driver ( adis16209_driver ) ;
2010-05-07 18:38:59 +04:00
MODULE_AUTHOR ( " Barry Song <21cnbao@gmail.com> " ) ;
2016-11-21 00:11:24 +03:00
MODULE_DESCRIPTION ( " Analog Devices ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer " ) ;
2010-05-07 18:38:59 +04:00
MODULE_LICENSE ( " GPL v2 " ) ;
2011-11-16 11:53:31 +04:00
MODULE_ALIAS ( " spi:adis16209 " ) ;