2010-05-04 17:43:15 +04:00
/*
* adis16400 . c support Analog Devices ADIS16400 / 5
* 3 d 2 g Linear Accelerometers ,
* 3 d Gyroscopes ,
* 3 d Magnetometers via SPI
*
* Copyright ( c ) 2009 Manuel Stahl < manuel . stahl @ iis . fraunhofer . de >
2012-09-03 00:34:59 +04:00
* Copyright ( c ) 2007 Jonathan Cameron < jic23 @ kernel . org >
2011-03-21 18:44:40 +03:00
* Copyright ( c ) 2011 Analog Devices Inc .
2010-05-04 17:43:15 +04:00
*
* 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>
2010-05-23 11:10:35 +04:00
# include <linux/slab.h>
2010-05-04 17:43:15 +04:00
# include <linux/sysfs.h>
# include <linux/list.h>
2011-07-03 23:49:50 +04:00
# include <linux/module.h>
2013-01-16 16:48:00 +04:00
# include <linux/debugfs.h>
2010-05-04 17:43:15 +04:00
2012-04-25 18:54:58 +04:00
# include <linux/iio/iio.h>
# include <linux/iio/sysfs.h>
# include <linux/iio/buffer.h>
2013-01-16 16:48:00 +04:00
2010-05-04 17:43:15 +04:00
# include "adis16400.h"
2013-01-16 16:48:00 +04:00
# 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
2011-05-18 17:41:28 +04:00
enum adis16400_chip_variant {
2011-05-18 17:41:30 +04:00
ADIS16300 ,
2011-09-30 13:05:45 +04:00
ADIS16334 ,
2011-05-18 17:41:28 +04:00
ADIS16350 ,
ADIS16360 ,
ADIS16362 ,
ADIS16364 ,
ADIS16400 ,
2013-01-16 16:48:00 +04:00
ADIS16448 ,
2011-05-18 17:41:28 +04:00
} ;
2013-01-16 16:48:00 +04:00
static int adis16334_get_freq ( struct adis16400_state * st )
2011-11-27 15:39:13 +04:00
{
2012-10-30 14:26:00 +04:00
int ret ;
2013-01-16 16:48:00 +04:00
uint16_t t ;
2012-10-30 14:26:00 +04:00
2013-01-16 16:48:00 +04:00
ret = adis_read_reg_16 ( & st - > adis , ADIS16400_SMPL_PRD , & t ) ;
2012-10-30 14:26:00 +04:00
if ( ret < 0 )
return ret ;
t > > = ADIS16334_RATE_DIV_SHIFT ;
2013-01-16 16:48:00 +04:00
return 819200 > > t ;
2012-10-30 14:26:00 +04:00
}
2013-01-16 16:48:00 +04:00
static int adis16334_set_freq ( struct adis16400_state * st , unsigned int freq )
2012-10-30 14:26:00 +04:00
{
unsigned int t ;
2013-01-16 16:48:00 +04:00
if ( freq < 819200 )
t = ilog2 ( 819200 / freq ) ;
2013-01-16 16:48:00 +04:00
else
t = 0 ;
2012-10-30 14:26:00 +04:00
if ( t > 0x31 )
t = 0x31 ;
t < < = ADIS16334_RATE_DIV_SHIFT ;
t | = ADIS16334_RATE_INT_CLK ;
2013-01-16 16:48:00 +04:00
return adis_write_reg_16 ( & st - > adis , ADIS16400_SMPL_PRD , t ) ;
2012-10-30 14:26:00 +04:00
}
2013-01-16 16:48:00 +04:00
static int adis16400_get_freq ( struct adis16400_state * st )
2012-10-30 14:26:00 +04:00
{
2011-11-27 15:39:13 +04:00
int sps , ret ;
2013-01-16 16:48:00 +04:00
uint16_t t ;
2011-11-27 15:39:13 +04:00
2013-01-16 16:48:00 +04:00
ret = adis_read_reg_16 ( & st - > adis , ADIS16400_SMPL_PRD , & t ) ;
2011-11-27 15:39:13 +04:00
if ( ret < 0 )
return ret ;
2013-01-16 16:48:00 +04:00
2013-01-16 16:48:00 +04:00
sps = ( t & ADIS16400_SMPL_PRD_TIME_BASE ) ? 52851 : 1638404 ;
2011-11-27 15:39:13 +04:00
sps / = ( t & ADIS16400_SMPL_PRD_DIV_MASK ) + 1 ;
return sps ;
}
2013-01-16 16:48:00 +04:00
static int adis16400_set_freq ( struct adis16400_state * st , unsigned int freq )
2012-10-30 14:26:00 +04:00
{
unsigned int t ;
2013-01-16 16:48:00 +04:00
uint8_t val = 0 ;
2012-10-30 14:26:00 +04:00
2013-01-16 16:48:00 +04:00
t = 1638404 / freq ;
2013-01-16 16:48:00 +04:00
if ( t > = 128 ) {
val | = ADIS16400_SMPL_PRD_TIME_BASE ;
t = 52851 / freq ;
if ( t > = 128 )
t = 127 ;
} else if ( t ! = 0 ) {
2012-10-30 14:26:00 +04:00
t - - ;
2013-01-16 16:48:00 +04:00
}
2013-01-16 16:48:00 +04:00
2013-01-16 16:48:00 +04:00
val | = t ;
if ( t > = 0x0A | | ( val & ADIS16400_SMPL_PRD_TIME_BASE ) )
2013-01-16 16:48:00 +04:00
st - > adis . spi - > max_speed_hz = ADIS16400_SPI_SLOW ;
2012-10-30 14:26:00 +04:00
else
2013-01-16 16:48:00 +04:00
st - > adis . spi - > max_speed_hz = ADIS16400_SPI_FAST ;
2012-10-30 14:26:00 +04:00
2013-01-16 16:48:00 +04:00
return adis_write_reg_8 ( & st - > adis , ADIS16400_SMPL_PRD , val ) ;
2012-10-30 14:26:00 +04:00
}
2010-05-04 17:43:15 +04:00
static ssize_t adis16400_read_frequency ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
2012-05-12 17:39:50 +04:00
struct iio_dev * indio_dev = dev_to_iio_dev ( dev ) ;
2012-10-30 14:26:00 +04:00
struct adis16400_state * st = iio_priv ( indio_dev ) ;
2013-01-16 16:48:00 +04:00
int ret ;
2012-10-30 14:26:00 +04:00
2013-01-16 16:48:00 +04:00
ret = st - > variant - > get_freq ( st ) ;
2011-11-27 15:39:13 +04:00
if ( ret < 0 )
2010-05-04 17:43:15 +04:00
return ret ;
2013-01-16 16:48:00 +04:00
2013-01-16 16:48:00 +04:00
return sprintf ( buf , " %d.%.3d \n " , ret / 1000 , ret % 1000 ) ;
2010-05-04 17:43:15 +04:00
}
2011-11-27 15:39:13 +04:00
static const unsigned adis16400_3db_divisors [ ] = {
[ 0 ] = 2 , /* Special case */
2013-01-16 16:48:00 +04:00
[ 1 ] = 6 ,
[ 2 ] = 12 ,
[ 3 ] = 25 ,
[ 4 ] = 50 ,
[ 5 ] = 100 ,
[ 6 ] = 200 ,
[ 7 ] = 200 , /* Not a valid setting */
2011-11-27 15:39:13 +04:00
} ;
static int adis16400_set_filter ( struct iio_dev * indio_dev , int sps , int val )
{
2013-01-16 16:48:00 +04:00
struct adis16400_state * st = iio_priv ( indio_dev ) ;
2013-01-16 16:48:00 +04:00
uint16_t val16 ;
2011-11-27 15:39:13 +04:00
int i , ret ;
2013-01-16 16:48:00 +04:00
for ( i = ARRAY_SIZE ( adis16400_3db_divisors ) - 1 ; i > = 1 ; i - - ) {
if ( sps / adis16400_3db_divisors [ i ] > = val )
2011-11-27 15:39:13 +04:00
break ;
2013-01-16 16:48:00 +04:00
}
2013-01-16 16:48:00 +04:00
ret = adis_read_reg_16 ( & st - > adis , ADIS16400_SENS_AVG , & val16 ) ;
2013-01-16 16:48:00 +04:00
if ( ret < 0 )
return ret ;
2011-11-27 15:39:13 +04:00
2013-01-16 16:48:00 +04:00
ret = adis_write_reg_16 ( & st - > adis , ADIS16400_SENS_AVG ,
2013-01-16 16:48:00 +04:00
( val16 & ~ 0x07 ) | i ) ;
2011-11-27 15:39:13 +04:00
return ret ;
}
2010-05-04 17:43:15 +04:00
static ssize_t adis16400_write_frequency ( struct device * dev ,
2013-01-16 16:48:00 +04:00
struct device_attribute * attr , const char * buf , size_t len )
2010-05-04 17:43:15 +04:00
{
2012-05-12 17:39:50 +04:00
struct iio_dev * indio_dev = dev_to_iio_dev ( dev ) ;
2011-05-18 17:42:23 +04:00
struct adis16400_state * st = iio_priv ( indio_dev ) ;
2013-01-16 16:48:00 +04:00
int i , f , val ;
2010-05-04 17:43:15 +04:00
int ret ;
2013-01-16 16:48:00 +04:00
ret = iio_str_to_fixpoint ( buf , 100 , & i , & f ) ;
2010-05-04 17:43:15 +04:00
if ( ret )
return ret ;
2013-01-16 16:48:00 +04:00
2013-01-16 16:48:00 +04:00
val = i * 1000 + f ;
if ( val < = 0 )
2012-08-18 12:48:00 +04:00
return - EINVAL ;
2010-05-04 17:43:15 +04:00
mutex_lock ( & indio_dev - > mlock ) ;
2013-01-16 16:48:00 +04:00
st - > variant - > set_freq ( st , val ) ;
2010-05-04 17:43:15 +04:00
mutex_unlock ( & indio_dev - > mlock ) ;
return ret ? ret : len ;
}
/* Power down the device */
2011-05-18 17:41:27 +04:00
static int adis16400_stop_device ( struct iio_dev * indio_dev )
2010-05-04 17:43:15 +04:00
{
2013-01-16 16:48:00 +04:00
struct adis16400_state * st = iio_priv ( indio_dev ) ;
2010-05-04 17:43:15 +04:00
int ret ;
2013-01-16 16:48:00 +04:00
ret = adis_write_reg_16 ( & st - > adis , ADIS16400_SLP_CNT ,
ADIS16400_SLP_CNT_POWER_OFF ) ;
2010-05-04 17:43:15 +04:00
if ( ret )
2011-05-18 17:41:27 +04:00
dev_err ( & indio_dev - > dev ,
" problem with turning device off: SLP_CNT " ) ;
2010-05-04 17:43:15 +04:00
return ret ;
}
2011-05-18 17:42:23 +04:00
static int adis16400_initial_setup ( struct iio_dev * indio_dev )
2010-05-04 17:43:15 +04:00
{
2011-05-18 17:42:23 +04:00
struct adis16400_state * st = iio_priv ( indio_dev ) ;
2013-01-16 16:48:00 +04:00
uint16_t prod_id , smp_prd ;
unsigned int device_id ;
int ret ;
2010-05-04 17:43:15 +04:00
2012-10-30 14:26:00 +04:00
/* use low spi speed for init if the device has a slow mode */
if ( st - > variant - > flags & ADIS16400_HAS_SLOW_MODE )
2013-01-16 16:48:00 +04:00
st - > adis . spi - > max_speed_hz = ADIS16400_SPI_SLOW ;
2012-10-30 14:26:00 +04:00
else
2013-01-16 16:48:00 +04:00
st - > adis . spi - > max_speed_hz = ADIS16400_SPI_FAST ;
st - > adis . spi - > mode = SPI_MODE_3 ;
spi_setup ( st - > adis . spi ) ;
2010-05-04 17:43:15 +04:00
2013-01-16 16:48:00 +04:00
ret = adis_initial_startup ( & st - > adis ) ;
if ( ret )
return ret ;
2010-05-04 17:43:15 +04:00
2011-05-18 17:41:28 +04:00
if ( st - > variant - > flags & ADIS16400_HAS_PROD_ID ) {
2013-01-16 16:48:00 +04:00
ret = adis_read_reg_16 ( & st - > adis ,
2011-05-18 17:41:28 +04:00
ADIS16400_PRODUCT_ID , & prod_id ) ;
if ( ret )
goto err_ret ;
2010-05-04 17:43:15 +04:00
2012-10-30 14:26:00 +04:00
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 ) ;
2010-05-04 17:43:15 +04:00
2011-09-02 20:25:34 +04:00
dev_info ( & indio_dev - > dev , " %s: prod_id 0x%04x at CS%d (irq %d) \n " ,
2013-01-16 16:48:00 +04:00
indio_dev - > name , prod_id ,
st - > adis . spi - > chip_select , st - > adis . spi - > irq ) ;
2011-05-18 17:41:28 +04:00
}
2010-05-04 17:43:15 +04:00
/* use high spi speed if possible */
2012-10-30 14:26:00 +04:00
if ( st - > variant - > flags & ADIS16400_HAS_SLOW_MODE ) {
2013-01-16 16:48:00 +04:00
ret = adis_read_reg_16 ( & st - > adis , ADIS16400_SMPL_PRD , & smp_prd ) ;
2012-10-30 14:26:00 +04:00
if ( ret )
goto err_ret ;
if ( ( smp_prd & ADIS16400_SMPL_PRD_DIV_MASK ) < 0x0A ) {
2013-01-16 16:48:00 +04:00
st - > adis . spi - > max_speed_hz = ADIS16400_SPI_FAST ;
spi_setup ( st - > adis . spi ) ;
2012-10-30 14:26:00 +04:00
}
2010-05-04 17:43:15 +04:00
}
err_ret :
return ret ;
}
static IIO_DEV_ATTR_SAMP_FREQ ( S_IWUSR | S_IRUGO ,
2011-09-02 20:25:33 +04:00
adis16400_read_frequency ,
adis16400_write_frequency ) ;
2010-05-04 17:43:15 +04:00
2013-01-16 16:48:00 +04:00
static const uint8_t adis16400_addresses [ ] = {
2013-01-16 16:48:00 +04:00
[ 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 ,
2011-05-18 17:41:27 +04:00
} ;
static int adis16400_write_raw ( struct iio_dev * indio_dev ,
2013-01-16 16:48:00 +04:00
struct iio_chan_spec const * chan , int val , int val2 , long info )
2011-05-18 17:41:27 +04:00
{
2011-11-27 15:39:13 +04:00
struct adis16400_state * st = iio_priv ( indio_dev ) ;
int ret , sps ;
2011-09-02 20:25:33 +04:00
2013-01-16 16:48:00 +04:00
switch ( info ) {
2011-10-26 20:41:36 +04:00
case IIO_CHAN_INFO_CALIBBIAS :
2011-05-18 17:41:27 +04:00
mutex_lock ( & indio_dev - > mlock ) ;
2013-01-16 16:48:00 +04:00
ret = adis_write_reg_16 ( & st - > adis ,
adis16400_addresses [ chan - > scan_index ] , val ) ;
2011-05-18 17:41:27 +04:00
mutex_unlock ( & indio_dev - > mlock ) ;
return ret ;
2011-11-27 15:39:13 +04:00
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY :
2013-01-16 16:48:00 +04:00
/*
* Need to cache values so we can update if the frequency
* changes .
*/
2011-11-27 15:39:13 +04:00
mutex_lock ( & indio_dev - > mlock ) ;
st - > filt_int = val ;
/* Work out update to current value */
2013-01-16 16:48:00 +04:00
sps = st - > variant - > get_freq ( st ) ;
2011-11-27 15:39:13 +04:00
if ( sps < 0 ) {
mutex_unlock ( & indio_dev - > mlock ) ;
return sps ;
}
2013-01-16 16:48:00 +04:00
ret = adis16400_set_filter ( indio_dev , sps ,
val * 1000 + val2 / 1000 ) ;
2011-11-27 15:39:13 +04:00
mutex_unlock ( & indio_dev - > mlock ) ;
return ret ;
2011-05-18 17:41:27 +04:00
default :
return - EINVAL ;
}
}
static int adis16400_read_raw ( struct iio_dev * indio_dev ,
2013-01-16 16:48:00 +04:00
struct iio_chan_spec const * chan , int * val , int * val2 , long info )
2011-05-18 17:41:27 +04:00
{
2011-05-18 17:42:23 +04:00
struct adis16400_state * st = iio_priv ( indio_dev ) ;
2013-01-16 16:48:00 +04:00
int16_t val16 ;
2013-01-16 16:48:00 +04:00
int ret ;
2011-05-18 17:41:27 +04:00
2013-01-16 16:48:00 +04:00
switch ( info ) {
2012-04-15 20:41:21 +04:00
case IIO_CHAN_INFO_RAW :
2013-01-16 16:48:00 +04:00
return adis_single_conversion ( indio_dev , chan , 0 , val ) ;
2011-10-26 20:41:36 +04:00
case IIO_CHAN_INFO_SCALE :
2011-05-18 17:41:27 +04:00
switch ( chan - > type ) {
2011-10-05 18:27:59 +04:00
case IIO_ANGL_VEL :
2011-05-18 17:41:27 +04:00
* val = 0 ;
2011-05-18 17:41:28 +04:00
* val2 = st - > variant - > gyro_scale_micro ;
2011-05-18 17:41:27 +04:00
return IIO_VAL_INT_PLUS_MICRO ;
2011-09-27 12:56:41 +04:00
case IIO_VOLTAGE :
2011-05-18 17:41:27 +04:00
* val = 0 ;
2012-10-15 13:35:00 +04:00
if ( chan - > channel = = 0 ) {
* val = 2 ;
* val2 = 418000 ; /* 2.418 mV */
} else {
* val = 0 ;
* val2 = 805800 ; /* 805.8 uV */
}
2011-05-18 17:41:27 +04:00
return IIO_VAL_INT_PLUS_MICRO ;
case IIO_ACCEL :
* val = 0 ;
2011-05-18 17:41:28 +04:00
* val2 = st - > variant - > accel_scale_micro ;
2011-05-18 17:41:27 +04:00
return IIO_VAL_INT_PLUS_MICRO ;
case IIO_MAGN :
* val = 0 ;
2012-10-15 13:35:00 +04:00
* val2 = 500 ; /* 0.5 mgauss */
2011-05-18 17:41:27 +04:00
return IIO_VAL_INT_PLUS_MICRO ;
case IIO_TEMP :
2012-10-15 13:35:00 +04:00
* val = st - > variant - > temp_scale_nano / 1000000 ;
* val2 = ( st - > variant - > temp_scale_nano % 1000000 ) ;
2011-05-18 17:41:27 +04:00
return IIO_VAL_INT_PLUS_MICRO ;
default :
return - EINVAL ;
}
2011-10-26 20:41:36 +04:00
case IIO_CHAN_INFO_CALIBBIAS :
2011-05-18 17:41:27 +04:00
mutex_lock ( & indio_dev - > mlock ) ;
2013-01-16 16:48:00 +04:00
ret = adis_read_reg_16 ( & st - > adis ,
adis16400_addresses [ chan - > scan_index ] , & val16 ) ;
2011-05-18 17:41:28 +04:00
mutex_unlock ( & indio_dev - > mlock ) ;
if ( ret )
2011-05-18 17:41:27 +04:00
return ret ;
val16 = ( ( val16 & 0xFFF ) < < 4 ) > > 4 ;
* val = val16 ;
return IIO_VAL_INT ;
2011-10-26 20:41:36 +04:00
case IIO_CHAN_INFO_OFFSET :
2011-05-18 17:41:27 +04:00
/* currently only temperature */
2012-10-15 13:35:00 +04:00
* val = st - > variant - > temp_offset ;
2012-10-15 13:35:00 +04:00
return IIO_VAL_INT ;
2011-11-27 15:39:13 +04:00
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY :
mutex_lock ( & indio_dev - > mlock ) ;
/* Need both the number of taps and the sampling frequency */
2013-01-16 16:48:00 +04:00
ret = adis_read_reg_16 ( & st - > adis ,
2011-11-27 15:39:13 +04:00
ADIS16400_SENS_AVG ,
& val16 ) ;
if ( ret < 0 ) {
mutex_unlock ( & indio_dev - > mlock ) ;
return ret ;
}
2013-01-16 16:48:00 +04:00
ret = st - > variant - > get_freq ( st ) ;
2013-01-16 16:48:00 +04:00
if ( ret > = 0 ) {
ret / = adis16400_3db_divisors [ val16 & 0x07 ] ;
* val = ret / 1000 ;
* val2 = ( ret % 1000 ) * 1000 ;
}
2011-11-27 15:39:13 +04:00
mutex_unlock ( & indio_dev - > mlock ) ;
if ( ret < 0 )
return ret ;
return IIO_VAL_INT_PLUS_MICRO ;
2011-05-18 17:41:27 +04:00
default :
return - EINVAL ;
}
}
2013-01-16 16:48:00 +04:00
# define ADIS16400_VOLTAGE_CHAN(addr, bits, name, si) { \
. type = IIO_VOLTAGE , \
. indexed = 1 , \
. channel = 0 , \
. extend_name = name , \
. info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
IIO_CHAN_INFO_SCALE_SEPARATE_BIT , \
. address = ( addr ) , \
. scan_index = ( si ) , \
2013-01-16 16:48:00 +04:00
. scan_type = { \
. sign = ' u ' , \
. realbits = ( bits ) , \
. storagebits = 16 , \
. shift = 0 , \
. endianness = IIO_BE , \
} , \
2013-01-16 16:48:00 +04:00
}
# 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 = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | \
IIO_CHAN_INFO_SCALE_SHARED_BIT | \
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT , \
. address = addr , \
. scan_index = ADIS16400_SCAN_GYRO_ # # mod , \
2013-01-16 16:48:00 +04:00
. scan_type = { \
. sign = ' s ' , \
. realbits = ( bits ) , \
. storagebits = 16 , \
. shift = 0 , \
. endianness = IIO_BE , \
} , \
2013-01-16 16:48:00 +04:00
}
# define ADIS16400_ACCEL_CHAN(mod, addr, bits) { \
. type = IIO_ACCEL , \
. modified = 1 , \
. channel2 = IIO_MOD_ # # mod , \
. info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | \
IIO_CHAN_INFO_SCALE_SHARED_BIT | \
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT , \
. address = ( addr ) , \
. scan_index = ADIS16400_SCAN_ACC_ # # mod , \
2013-01-16 16:48:00 +04:00
. scan_type = { \
. sign = ' s ' , \
. realbits = ( bits ) , \
. storagebits = 16 , \
. shift = 0 , \
. endianness = IIO_BE , \
} , \
2013-01-16 16:48:00 +04:00
}
# define ADIS16400_MAGN_CHAN(mod, addr, bits) { \
. type = IIO_MAGN , \
. modified = 1 , \
. channel2 = IIO_MOD_ # # mod , \
. info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
IIO_CHAN_INFO_SCALE_SHARED_BIT | \
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT , \
. address = ( addr ) , \
. scan_index = ADIS16400_SCAN_MAGN_ # # mod , \
2013-01-16 16:48:00 +04:00
. scan_type = { \
. sign = ' s ' , \
. realbits = ( bits ) , \
. storagebits = 16 , \
. shift = 0 , \
. endianness = IIO_BE , \
} , \
2013-01-16 16:48:00 +04:00
}
# 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 = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | \
IIO_CHAN_INFO_SCALE_SEPARATE_BIT | \
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT , \
. address = ( addr ) , \
. scan_index = ADIS16350_SCAN_TEMP_ # # mod , \
2013-01-16 16:48:00 +04:00
. scan_type = { \
. sign = ' s ' , \
. realbits = ( bits ) , \
. storagebits = 16 , \
. shift = 0 , \
. endianness = IIO_BE , \
} , \
2013-01-16 16:48:00 +04:00
}
# define ADIS16400_TEMP_CHAN(addr, bits) { \
. type = IIO_TEMP , \
. indexed = 1 , \
. channel = 0 , \
. info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | \
IIO_CHAN_INFO_SCALE_SEPARATE_BIT , \
. address = ( addr ) , \
. scan_index = ADIS16350_SCAN_TEMP_X , \
2013-01-16 16:48:00 +04:00
. scan_type = { \
. sign = ' s ' , \
. realbits = ( bits ) , \
. storagebits = 16 , \
. shift = 0 , \
. endianness = IIO_BE , \
} , \
2013-01-16 16:48:00 +04:00
}
# define ADIS16400_INCLI_CHAN(mod, addr, bits) { \
. type = IIO_INCLI , \
. modified = 1 , \
. channel2 = IIO_MOD_ # # mod , \
. info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
IIO_CHAN_INFO_SCALE_SHARED_BIT , \
. address = ( addr ) , \
. scan_index = ADIS16300_SCAN_INCLI_ # # mod , \
2013-01-16 16:48:00 +04:00
. scan_type = { \
. sign = ' s ' , \
. realbits = ( bits ) , \
. storagebits = 16 , \
. shift = 0 , \
. endianness = IIO_BE , \
} , \
2013-01-16 16:48:00 +04:00
}
2012-08-09 11:51:00 +04:00
static const struct iio_chan_spec adis16400_channels [ ] = {
2013-01-16 16:48:00 +04:00
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 ) ,
2011-05-18 17:41:27 +04:00
IIO_CHAN_SOFT_TIMESTAMP ( 12 )
} ;
2013-01-16 16:48:00 +04:00
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 = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT ,
. 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 )
} ;
2012-08-09 11:51:00 +04:00
static const struct iio_chan_spec adis16350_channels [ ] = {
2013-01-16 16:48:00 +04:00
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 ) ,
2011-05-18 17:41:28 +04:00
IIO_CHAN_SOFT_TIMESTAMP ( 11 )
} ;
2012-08-09 11:51:00 +04:00
static const struct iio_chan_spec adis16300_channels [ ] = {
2013-01-16 16:48:00 +04:00
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 ) ,
2011-05-18 17:41:30 +04:00
IIO_CHAN_SOFT_TIMESTAMP ( 14 )
} ;
2011-09-30 13:05:45 +04:00
static const struct iio_chan_spec adis16334_channels [ ] = {
2013-01-16 16:48:00 +04:00
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 )
2011-08-12 21:04:37 +04:00
} ;
2010-05-04 17:43:15 +04:00
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 ,
} ;
2011-05-18 17:41:28 +04:00
static struct adis16400_chip_info adis16400_chips [ ] = {
2011-05-18 17:41:30 +04:00
[ ADIS16300 ] = {
. channels = adis16300_channels ,
. num_channels = ARRAY_SIZE ( adis16300_channels ) ,
2012-10-30 14:26:00 +04:00
. flags = ADIS16400_HAS_SLOW_MODE ,
2012-10-15 13:35:00 +04:00
. gyro_scale_micro = IIO_DEGREE_TO_RAD ( 50000 ) , /* 0.05 deg/s */
2011-05-18 17:41:30 +04:00
. accel_scale_micro = 5884 ,
2012-10-15 13:35:00 +04:00
. temp_scale_nano = 140000000 , /* 0.14 C */
. temp_offset = 25000000 / 140000 , /* 25 C = 0x00 */
2012-10-30 14:26:00 +04:00
. set_freq = adis16400_set_freq ,
. get_freq = adis16400_get_freq ,
2011-05-18 17:41:30 +04:00
} ,
2011-09-30 13:05:45 +04:00
[ ADIS16334 ] = {
. channels = adis16334_channels ,
. num_channels = ARRAY_SIZE ( adis16334_channels ) ,
2013-01-16 16:48:00 +04:00
. flags = ADIS16400_HAS_PROD_ID | ADIS16400_NO_BURST |
ADIS16400_HAS_SERIAL_NUMBER ,
2012-10-15 13:35:00 +04:00
. gyro_scale_micro = IIO_DEGREE_TO_RAD ( 50000 ) , /* 0.05 deg/s */
. accel_scale_micro = IIO_G_TO_M_S_2 ( 1000 ) , /* 1 mg */
2012-10-15 13:35:00 +04:00
. temp_scale_nano = 67850000 , /* 0.06785 C */
. temp_offset = 25000000 / 67850 , /* 25 C = 0x00 */
2012-10-30 14:26:00 +04:00
. set_freq = adis16334_set_freq ,
. get_freq = adis16334_get_freq ,
2011-08-12 21:04:37 +04:00
} ,
2011-05-18 17:41:28 +04:00
[ ADIS16350 ] = {
. channels = adis16350_channels ,
. num_channels = ARRAY_SIZE ( adis16350_channels ) ,
2012-10-15 13:35:00 +04:00
. 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 */
2012-10-15 13:35:00 +04:00
. temp_scale_nano = 145300000 , /* 0.1453 C */
. temp_offset = 25000000 / 145300 , /* 25 C = 0x00 */
2012-10-30 14:26:00 +04:00
. flags = ADIS16400_NO_BURST | ADIS16400_HAS_SLOW_MODE ,
. set_freq = adis16400_set_freq ,
. get_freq = adis16400_get_freq ,
2011-05-18 17:41:28 +04:00
} ,
[ ADIS16360 ] = {
. channels = adis16350_channels ,
. num_channels = ARRAY_SIZE ( adis16350_channels ) ,
2013-01-16 16:48:00 +04:00
. flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE |
ADIS16400_HAS_SERIAL_NUMBER ,
2012-10-15 13:35:00 +04:00
. 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 */
2012-10-15 13:35:00 +04:00
. temp_scale_nano = 136000000 , /* 0.136 C */
. temp_offset = 25000000 / 136000 , /* 25 C = 0x00 */
2012-10-30 14:26:00 +04:00
. set_freq = adis16400_set_freq ,
. get_freq = adis16400_get_freq ,
2011-05-18 17:41:28 +04:00
} ,
[ ADIS16362 ] = {
. channels = adis16350_channels ,
. num_channels = ARRAY_SIZE ( adis16350_channels ) ,
2013-01-16 16:48:00 +04:00
. flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE |
ADIS16400_HAS_SERIAL_NUMBER ,
2012-10-15 13:35:00 +04:00
. 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 */
2012-10-15 13:35:00 +04:00
. temp_scale_nano = 136000000 , /* 0.136 C */
. temp_offset = 25000000 / 136000 , /* 25 C = 0x00 */
2012-10-30 14:26:00 +04:00
. set_freq = adis16400_set_freq ,
. get_freq = adis16400_get_freq ,
2011-05-18 17:41:28 +04:00
} ,
[ ADIS16364 ] = {
. channels = adis16350_channels ,
. num_channels = ARRAY_SIZE ( adis16350_channels ) ,
2013-01-16 16:48:00 +04:00
. flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE |
ADIS16400_HAS_SERIAL_NUMBER ,
2012-10-15 13:35:00 +04:00
. gyro_scale_micro = IIO_DEGREE_TO_RAD ( 50000 ) , /* 0.05 deg/s */
. accel_scale_micro = IIO_G_TO_M_S_2 ( 1000 ) , /* 1 mg */
2012-10-15 13:35:00 +04:00
. temp_scale_nano = 136000000 , /* 0.136 C */
. temp_offset = 25000000 / 136000 , /* 25 C = 0x00 */
2012-10-30 14:26:00 +04:00
. set_freq = adis16400_set_freq ,
. get_freq = adis16400_get_freq ,
2011-05-18 17:41:28 +04:00
} ,
[ ADIS16400 ] = {
. channels = adis16400_channels ,
. num_channels = ARRAY_SIZE ( adis16400_channels ) ,
2012-10-30 14:26:00 +04:00
. flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE ,
2012-10-15 13:35:00 +04:00
. 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 */
2012-10-15 13:35:00 +04:00
. temp_scale_nano = 140000000 , /* 0.14 C */
. temp_offset = 25000000 / 140000 , /* 25 C = 0x00 */
2012-10-30 14:26:00 +04:00
. set_freq = adis16400_set_freq ,
. get_freq = adis16400_get_freq ,
2013-01-16 16:48:00 +04:00
} ,
[ 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 ,
2011-05-18 17:41:28 +04:00
}
} ;
2011-05-18 17:42:37 +04:00
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 ,
2013-01-16 16:48:00 +04:00
. update_scan_mode = adis16400_update_scan_mode ,
2013-01-16 16:48:00 +04:00
. debugfs_reg_access = adis_debugfs_reg_access ,
2013-01-16 16:48:00 +04:00
} ;
static const unsigned long adis16400_burst_scan_mask [ ] = {
~ 0UL ,
0 ,
2011-05-18 17:42:37 +04:00
} ;
2011-05-18 17:41:28 +04:00
2013-01-16 16:48:00 +04:00
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 ) ,
} ;
2012-11-19 22:21:57 +04:00
static int adis16400_probe ( struct spi_device * spi )
2010-05-04 17:43:15 +04:00
{
2011-05-18 17:42:23 +04:00
struct adis16400_state * st ;
2013-01-16 16:48:00 +04:00
struct iio_dev * indio_dev ;
int ret ;
indio_dev = iio_device_alloc ( sizeof ( * st ) ) ;
if ( indio_dev = = NULL )
return - ENOMEM ;
2011-05-18 17:42:23 +04:00
st = iio_priv ( indio_dev ) ;
2010-05-04 17:43:15 +04:00
/* this is only used for removal purposes */
2011-05-18 17:42:23 +04:00
spi_set_drvdata ( spi , indio_dev ) ;
2010-05-04 17:43:15 +04:00
/* setup the industrialio driver allocated elements */
2011-05-18 17:41:28 +04:00
st - > variant = & adis16400_chips [ spi_get_device_id ( spi ) - > driver_data ] ;
2011-05-18 17:42:23 +04:00
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 ;
2011-05-18 17:42:37 +04:00
indio_dev - > info = & adis16400_info ;
2011-05-18 17:42:23 +04:00
indio_dev - > modes = INDIO_DIRECT_MODE ;
2013-01-16 16:48:00 +04:00
if ( ! ( st - > variant - > flags & ADIS16400_NO_BURST ) )
indio_dev - > available_scan_masks = adis16400_burst_scan_mask ;
2013-01-16 16:48:00 +04:00
ret = adis_init ( & st - > adis , indio_dev , spi , & adis16400_data ) ;
if ( ret )
goto error_free_dev ;
2013-01-16 16:48:00 +04:00
ret = adis_setup_buffer_and_trigger ( & st - > adis , indio_dev ,
adis16400_trigger_handler ) ;
2010-05-04 17:43:15 +04:00
if ( ret )
goto error_free_dev ;
/* Get the device into a sane initial state */
2011-05-18 17:42:23 +04:00
ret = adis16400_initial_setup ( indio_dev ) ;
2010-05-04 17:43:15 +04:00
if ( ret )
2013-01-16 16:48:00 +04:00
goto error_cleanup_buffer ;
2011-09-02 20:14:40 +04:00
ret = iio_device_register ( indio_dev ) ;
if ( ret )
2013-01-16 16:48:00 +04:00
goto error_cleanup_buffer ;
2011-09-02 20:14:40 +04:00
2013-01-16 16:48:00 +04:00
adis16400_debugfs_init ( indio_dev ) ;
2010-05-04 17:43:15 +04:00
return 0 ;
2013-01-16 16:48:00 +04:00
error_cleanup_buffer :
adis_cleanup_buffer_and_trigger ( & st - > adis , indio_dev ) ;
2010-05-04 17:43:15 +04:00
error_free_dev :
2012-04-26 15:35:01 +04:00
iio_device_free ( indio_dev ) ;
2010-05-04 17:43:15 +04:00
return ret ;
}
2012-11-19 22:26:37 +04:00
static int adis16400_remove ( struct spi_device * spi )
2010-05-04 17:43:15 +04:00
{
2013-01-16 16:48:00 +04:00
struct iio_dev * indio_dev = spi_get_drvdata ( spi ) ;
2013-01-16 16:48:00 +04:00
struct adis16400_state * st = iio_priv ( indio_dev ) ;
2010-05-04 17:43:15 +04:00
2011-10-14 17:46:58 +04:00
iio_device_unregister ( indio_dev ) ;
2012-09-22 12:56:00 +04:00
adis16400_stop_device ( indio_dev ) ;
2010-05-04 17:43:15 +04:00
2013-01-16 16:48:00 +04:00
adis_cleanup_buffer_and_trigger ( & st - > adis , indio_dev ) ;
2013-01-16 16:48:00 +04:00
2012-04-26 15:35:01 +04:00
iio_device_free ( indio_dev ) ;
2011-05-18 17:41:28 +04:00
2010-05-04 17:43:15 +04:00
return 0 ;
}
2011-05-18 17:41:28 +04:00
static const struct spi_device_id adis16400_id [ ] = {
2011-05-18 17:41:30 +04:00
{ " adis16300 " , ADIS16300 } ,
2011-09-30 13:05:45 +04:00
{ " adis16334 " , ADIS16334 } ,
2011-05-18 17:41:28 +04:00
{ " adis16350 " , ADIS16350 } ,
{ " adis16354 " , ADIS16350 } ,
{ " adis16355 " , ADIS16350 } ,
{ " adis16360 " , ADIS16360 } ,
{ " adis16362 " , ADIS16362 } ,
{ " adis16364 " , ADIS16364 } ,
2012-10-30 14:26:00 +04:00
{ " adis16365 " , ADIS16360 } ,
2011-05-18 17:41:28 +04:00
{ " adis16400 " , ADIS16400 } ,
{ " adis16405 " , ADIS16400 } ,
2013-01-16 16:48:00 +04:00
{ " adis16448 " , ADIS16448 } ,
2011-05-18 17:41:28 +04:00
{ }
} ;
2011-11-16 11:53:31 +04:00
MODULE_DEVICE_TABLE ( spi , adis16400_id ) ;
2011-05-18 17:41:28 +04:00
2010-05-04 17:43:15 +04:00
static struct spi_driver adis16400_driver = {
. driver = {
. name = " adis16400 " ,
. owner = THIS_MODULE ,
} ,
2011-05-18 17:41:28 +04:00
. id_table = adis16400_id ,
2010-05-04 17:43:15 +04:00
. probe = adis16400_probe ,
2012-11-19 22:21:38 +04:00
. remove = adis16400_remove ,
2010-05-04 17:43:15 +04:00
} ;
2011-11-16 13:13:39 +04:00
module_spi_driver ( adis16400_driver ) ;
2010-05-04 17:43:15 +04:00
MODULE_AUTHOR ( " Manuel Stahl <manuel.stahl@iis.fraunhofer.de> " ) ;
MODULE_DESCRIPTION ( " Analog Devices ADIS16400/5 IMU SPI driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;