2019-05-24 12:04:09 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2010-10-27 21:44:06 -04:00
/*
* ADIS16130 Digital Output , High Precision Angular Rate Sensor driver
*
* Copyright 2010 Analog Devices Inc .
*/
# include <linux/mutex.h>
# include <linux/kernel.h>
# include <linux/spi/spi.h>
2011-07-03 15:49:50 -04:00
# include <linux/module.h>
2010-10-27 21:44:06 -04:00
2012-04-25 15:54:58 +01:00
# include <linux/iio/iio.h>
2010-10-27 21:44:06 -04:00
2020-04-21 03:31:26 +03:00
# include <asm/unaligned.h>
2011-02-26 17:30:18 +00:00
# define ADIS16130_CON 0x0
# define ADIS16130_CON_RD (1 << 6)
# define ADIS16130_IOP 0x1
/* 1 = data-ready signal low when unread data on all channels; */
# define ADIS16130_IOP_ALL_RDY (1 << 3)
# define ADIS16130_IOP_SYNC (1 << 0) /* 1 = synchronization enabled */
# define ADIS16130_RATEDATA 0x8 /* Gyroscope output, rate of rotation */
# define ADIS16130_TEMPDATA 0xA /* Temperature output */
# define ADIS16130_RATECS 0x28 /* Gyroscope channel setup */
# define ADIS16130_RATECS_EN (1 << 3) /* 1 = channel enable; */
# define ADIS16130_TEMPCS 0x2A /* Temperature channel setup */
# define ADIS16130_TEMPCS_EN (1 << 3)
# define ADIS16130_RATECONV 0x30
# define ADIS16130_TEMPCONV 0x32
# define ADIS16130_MODE 0x38
# define ADIS16130_MODE_24BIT (1 << 1) /* 1 = 24-bit resolution; */
/**
* struct adis16130_state - device instance specific data
* @ us : actual spi_device to write data
* @ buf_lock : mutex to protect tx and rx
* @ buf : unified tx / rx buffer
* */
struct adis16130_state {
struct spi_device * us ;
struct mutex buf_lock ;
u8 buf [ 4 ] ____cacheline_aligned ;
} ;
2010-10-27 21:44:06 -04:00
2011-08-12 17:47:59 +01:00
static int adis16130_spi_read ( struct iio_dev * indio_dev , u8 reg_addr , u32 * val )
2010-10-27 21:44:06 -04:00
{
int ret ;
2011-06-27 13:07:45 +01:00
struct adis16130_state * st = iio_priv ( indio_dev ) ;
2011-08-12 16:55:28 +01:00
struct spi_transfer xfer = {
. tx_buf = st - > buf ,
. rx_buf = st - > buf ,
2011-08-12 17:08:41 +01:00
. len = 4 ,
2011-08-12 16:55:28 +01:00
} ;
2010-10-27 21:44:06 -04:00
mutex_lock ( & st - > buf_lock ) ;
2011-02-26 17:30:18 +00:00
st - > buf [ 0 ] = ADIS16130_CON_RD | reg_addr ;
2011-08-12 16:55:28 +01:00
st - > buf [ 1 ] = st - > buf [ 2 ] = st - > buf [ 3 ] = 0 ;
2013-10-05 08:45:00 +01:00
ret = spi_sync_transfer ( st - > us , & xfer , 1 ) ;
2011-08-12 17:08:41 +01:00
if ( ret = = 0 )
2020-04-21 03:31:26 +03:00
* val = get_unaligned_be24 ( & st - > buf [ 1 ] ) ;
2010-10-27 21:44:06 -04:00
mutex_unlock ( & st - > buf_lock ) ;
return ret ;
}
2011-08-12 17:47:59 +01:00
static int adis16130_read_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
int * val , int * val2 ,
long mask )
2010-10-27 21:44:06 -04:00
{
2011-08-12 17:47:59 +01:00
int ret ;
u32 temp ;
2010-10-27 21:44:06 -04:00
2013-06-10 15:00:00 +01:00
switch ( mask ) {
case IIO_CHAN_INFO_RAW :
/* Take the iio_dev status lock */
ret = adis16130_spi_read ( indio_dev , chan - > address , & temp ) ;
if ( ret )
return ret ;
* val = temp ;
return IIO_VAL_INT ;
case IIO_CHAN_INFO_SCALE :
switch ( chan - > type ) {
case IIO_ANGL_VEL :
/* 0 degree = 838860, 250 degree = 14260608 */
* val = 250 ;
* val2 = 336440817 ; /* RAD_TO_DEGREE(14260608 - 8388608) */
return IIO_VAL_FRACTIONAL ;
case IIO_TEMP :
/* 0C = 8036283, 105C = 9516048 */
* val = 105000 ;
* val2 = 9516048 - 8036283 ;
return IIO_VAL_FRACTIONAL ;
default :
return - EINVAL ;
}
case IIO_CHAN_INFO_OFFSET :
switch ( chan - > type ) {
case IIO_ANGL_VEL :
* val = - 8388608 ;
return IIO_VAL_INT ;
case IIO_TEMP :
* val = - 8036283 ;
return IIO_VAL_INT ;
default :
return - EINVAL ;
}
}
return - EINVAL ;
2010-10-27 21:44:06 -04:00
}
2011-08-12 17:47:59 +01:00
static const struct iio_chan_spec adis16130_channels [ ] = {
{
2011-10-05 15:27:59 +01:00
. type = IIO_ANGL_VEL ,
2011-08-12 17:47:59 +01:00
. modified = 1 ,
. channel2 = IIO_MOD_Z ,
2013-06-10 15:00:00 +01:00
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) |
BIT ( IIO_CHAN_INFO_SCALE ) |
BIT ( IIO_CHAN_INFO_OFFSET ) ,
2011-08-12 17:47:59 +01:00
. address = ADIS16130_RATEDATA ,
} , {
. type = IIO_TEMP ,
. indexed = 1 ,
. channel = 0 ,
2013-06-10 15:00:00 +01:00
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) |
BIT ( IIO_CHAN_INFO_SCALE ) |
BIT ( IIO_CHAN_INFO_OFFSET ) ,
2011-08-12 17:47:59 +01:00
. address = ADIS16130_TEMPDATA ,
}
2010-10-27 21:44:06 -04:00
} ;
2011-05-18 14:42:37 +01:00
static const struct iio_info adis16130_info = {
2011-08-12 17:47:59 +01:00
. read_raw = & adis16130_read_raw ,
2011-05-18 14:42:37 +01:00
} ;
2012-11-19 13:21:57 -05:00
static int adis16130_probe ( struct spi_device * spi )
2010-10-27 21:44:06 -04:00
{
2011-06-27 13:07:45 +01:00
struct adis16130_state * st ;
struct iio_dev * indio_dev ;
/* setup the industrialio driver allocated elements */
2013-08-13 07:34:00 +01:00
indio_dev = devm_iio_device_alloc ( & spi - > dev , sizeof ( * st ) ) ;
if ( ! indio_dev )
return - ENOMEM ;
2011-06-27 13:07:45 +01:00
st = iio_priv ( indio_dev ) ;
2010-10-27 21:44:06 -04:00
/* this is only used for removal purposes */
2011-06-27 13:07:45 +01:00
spi_set_drvdata ( spi , indio_dev ) ;
2010-10-27 21:44:06 -04:00
st - > us = spi ;
mutex_init ( & st - > buf_lock ) ;
2011-06-27 13:07:45 +01:00
indio_dev - > name = spi - > dev . driver - > name ;
2011-08-12 17:47:59 +01:00
indio_dev - > channels = adis16130_channels ;
indio_dev - > num_channels = ARRAY_SIZE ( adis16130_channels ) ;
2011-06-27 13:07:45 +01:00
indio_dev - > info = & adis16130_info ;
indio_dev - > modes = INDIO_DIRECT_MODE ;
2010-10-27 21:44:06 -04:00
2013-10-29 11:39:00 +00:00
return devm_iio_device_register ( & spi - > dev , indio_dev ) ;
2010-10-27 21:44:06 -04:00
}
static struct spi_driver adis16130_driver = {
. driver = {
. name = " adis16130 " ,
} ,
. probe = adis16130_probe ,
} ;
2011-11-16 10:13:39 +01:00
module_spi_driver ( adis16130_driver ) ;
2010-10-27 21:44:06 -04:00
MODULE_AUTHOR ( " Barry Song <21cnbao@gmail.com> " ) ;
2011-02-26 17:30:18 +00:00
MODULE_DESCRIPTION ( " Analog Devices ADIS16130 High Precision Angular Rate " ) ;
2010-10-27 21:44:06 -04:00
MODULE_LICENSE ( " GPL v2 " ) ;
2011-11-16 08:53:31 +01:00
MODULE_ALIAS ( " spi:adis16130 " ) ;