2019-05-24 13:04:09 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2010-10-28 05:44:05 +04:00
/*
* ADIS16080 / 100 Yaw Rate Gyroscope with SPI driver
*
* Copyright 2010 Analog Devices Inc .
*/
# include <linux/delay.h>
# include <linux/mutex.h>
# include <linux/device.h>
# include <linux/kernel.h>
# include <linux/spi/spi.h>
# include <linux/slab.h>
# include <linux/sysfs.h>
2011-07-03 23:49:50 +04:00
# include <linux/module.h>
2010-10-28 05:44:05 +04:00
2012-04-25 18:54:58 +04:00
# include <linux/iio/iio.h>
# include <linux/iio/sysfs.h>
2010-10-28 05:44:05 +04:00
2011-02-25 19:09:07 +03:00
# define ADIS16080_DIN_GYRO (0 << 10) /* Gyroscope output */
# define ADIS16080_DIN_TEMP (1 << 10) /* Temperature output */
# define ADIS16080_DIN_AIN1 (2 << 10)
# define ADIS16080_DIN_AIN2 (3 << 10)
/*
* 1 : Write contents on DIN to control register .
* 0 : No changes to control register .
*/
# define ADIS16080_DIN_WRITE (1 << 15)
2013-01-09 18:01:00 +04:00
struct adis16080_chip_info {
int scale_val ;
int scale_val2 ;
} ;
2011-02-25 19:09:07 +03:00
/**
* struct adis16080_state - device instance specific data
* @ us : actual spi_device to write data
2013-01-09 18:01:00 +04:00
* @ info : chip specific parameters
2011-03-31 05:57:33 +04:00
* @ buf : transmit or receive buffer
2020-07-16 16:59:10 +03:00
* @ lock : lock to protect buffer during reads
2011-02-25 19:09:07 +03:00
* */
struct adis16080_state {
struct spi_device * us ;
2013-01-09 18:01:00 +04:00
const struct adis16080_chip_info * info ;
2019-09-19 16:23:03 +03:00
struct mutex lock ;
2011-02-25 19:09:07 +03:00
2013-01-09 18:01:00 +04:00
__be16 buf ____cacheline_aligned ;
2011-02-25 19:09:07 +03:00
} ;
2010-10-28 05:44:05 +04:00
2013-01-09 18:01:00 +04:00
static int adis16080_read_sample ( struct iio_dev * indio_dev ,
u16 addr , int * val )
2010-10-28 05:44:05 +04:00
{
2011-06-27 16:07:44 +04:00
struct adis16080_state * st = iio_priv ( indio_dev ) ;
2010-10-28 05:44:05 +04:00
int ret ;
2013-01-09 18:01:00 +04:00
struct spi_transfer t [ ] = {
{
. tx_buf = & st - > buf ,
. len = 2 ,
. cs_change = 1 ,
} , {
. rx_buf = & st - > buf ,
. len = 2 ,
} ,
} ;
2010-10-28 05:44:05 +04:00
2013-01-09 18:01:00 +04:00
st - > buf = cpu_to_be16 ( addr | ADIS16080_DIN_WRITE ) ;
2010-10-28 05:44:05 +04:00
2013-10-05 11:45:00 +04:00
ret = spi_sync_transfer ( st - > us , t , ARRAY_SIZE ( t ) ) ;
2010-10-28 05:44:05 +04:00
if ( ret = = 0 )
2013-01-09 18:01:00 +04:00
* val = sign_extend32 ( be16_to_cpu ( st - > buf ) , 11 ) ;
2010-10-28 05:44:05 +04:00
return ret ;
}
2011-08-12 20:47:57 +04:00
static int adis16080_read_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
int * val ,
int * val2 ,
long mask )
2010-10-28 05:44:05 +04:00
{
2013-01-09 18:01:00 +04:00
struct adis16080_state * st = iio_priv ( indio_dev ) ;
2013-01-09 18:01:00 +04:00
int ret ;
2011-08-12 20:47:57 +04:00
switch ( mask ) {
2012-04-15 20:41:20 +04:00
case IIO_CHAN_INFO_RAW :
2019-09-19 16:23:03 +03:00
mutex_lock ( & st - > lock ) ;
2013-01-09 18:01:00 +04:00
ret = adis16080_read_sample ( indio_dev , chan - > address , val ) ;
2019-09-19 16:23:03 +03:00
mutex_unlock ( & st - > lock ) ;
2013-01-09 18:01:00 +04:00
return ret ? ret : IIO_VAL_INT ;
2013-01-09 18:01:00 +04:00
case IIO_CHAN_INFO_SCALE :
switch ( chan - > type ) {
case IIO_ANGL_VEL :
* val = st - > info - > scale_val ;
* val2 = st - > info - > scale_val2 ;
return IIO_VAL_FRACTIONAL ;
case IIO_VOLTAGE :
/* VREF = 5V, 12 bits */
* val = 5000 ;
* val2 = 12 ;
return IIO_VAL_FRACTIONAL_LOG2 ;
case IIO_TEMP :
/* 85 C = 585, 25 C = 0 */
* val = 85000 - 25000 ;
* val2 = 585 ;
return IIO_VAL_FRACTIONAL ;
default :
return - EINVAL ;
}
case IIO_CHAN_INFO_OFFSET :
switch ( chan - > type ) {
case IIO_VOLTAGE :
/* 2.5 V = 0 */
* val = 2048 ;
return IIO_VAL_INT ;
case IIO_TEMP :
/* 85 C = 585, 25 C = 0 */
* val = DIV_ROUND_CLOSEST ( 25 * 585 , 85 - 25 ) ;
return IIO_VAL_INT ;
default :
return - EINVAL ;
}
default :
break ;
2011-08-12 20:47:57 +04:00
}
2010-10-28 05:44:05 +04:00
2013-01-09 18:01:00 +04:00
return - EINVAL ;
2010-10-28 05:44:05 +04:00
}
2011-08-12 20:47:57 +04:00
static const struct iio_chan_spec adis16080_channels [ ] = {
{
2011-10-05 18:27:59 +04:00
. type = IIO_ANGL_VEL ,
2011-08-12 20:47:57 +04:00
. modified = 1 ,
. channel2 = IIO_MOD_Z ,
2013-02-27 23:29:24 +04:00
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) |
BIT ( IIO_CHAN_INFO_SCALE ) ,
2011-08-12 20:47:57 +04:00
. address = ADIS16080_DIN_GYRO ,
} , {
2011-09-27 12:56:41 +04:00
. type = IIO_VOLTAGE ,
2011-08-12 20:47:57 +04:00
. indexed = 1 ,
. channel = 0 ,
2013-02-27 23:29:24 +04:00
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) |
BIT ( IIO_CHAN_INFO_SCALE ) |
BIT ( IIO_CHAN_INFO_OFFSET ) ,
2011-08-12 20:47:57 +04:00
. address = ADIS16080_DIN_AIN1 ,
} , {
2011-09-27 12:56:41 +04:00
. type = IIO_VOLTAGE ,
2011-08-12 20:47:57 +04:00
. indexed = 1 ,
. channel = 1 ,
2013-02-27 23:29:24 +04:00
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) |
BIT ( IIO_CHAN_INFO_SCALE ) |
BIT ( IIO_CHAN_INFO_OFFSET ) ,
2011-08-12 20:47:57 +04:00
. address = ADIS16080_DIN_AIN2 ,
} , {
. type = IIO_TEMP ,
. indexed = 1 ,
. channel = 0 ,
2013-02-27 23:29:24 +04:00
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) |
BIT ( IIO_CHAN_INFO_SCALE ) |
BIT ( IIO_CHAN_INFO_OFFSET ) ,
2011-08-12 20:47:57 +04:00
. address = ADIS16080_DIN_TEMP ,
}
2010-10-28 05:44:05 +04:00
} ;
2011-05-18 17:42:37 +04:00
static const struct iio_info adis16080_info = {
2011-08-12 20:47:57 +04:00
. read_raw = & adis16080_read_raw ,
2011-05-18 17:42:37 +04:00
} ;
2013-01-09 18:01:00 +04:00
enum {
ID_ADIS16080 ,
ID_ADIS16100 ,
} ;
static const struct adis16080_chip_info adis16080_chip_info [ ] = {
[ ID_ADIS16080 ] = {
/* 80 degree = 819, 819 rad = 46925 degree */
. scale_val = 80 ,
. scale_val2 = 46925 ,
} ,
[ ID_ADIS16100 ] = {
/* 300 degree = 1230, 1230 rad = 70474 degree */
. scale_val = 300 ,
. scale_val2 = 70474 ,
} ,
} ;
2012-11-19 22:21:57 +04:00
static int adis16080_probe ( struct spi_device * spi )
2010-10-28 05:44:05 +04:00
{
2013-01-09 18:01:00 +04:00
const struct spi_device_id * id = spi_get_device_id ( spi ) ;
2011-06-27 16:07:44 +04:00
struct adis16080_state * st ;
struct iio_dev * indio_dev ;
/* setup the industrialio driver allocated elements */
2013-08-13 10:34:00 +04:00
indio_dev = devm_iio_device_alloc ( & spi - > dev , sizeof ( * st ) ) ;
if ( ! indio_dev )
return - ENOMEM ;
2011-06-27 16:07:44 +04:00
st = iio_priv ( indio_dev ) ;
2010-10-28 05:44:05 +04:00
/* this is only used for removal purposes */
2011-06-27 16:07:44 +04:00
spi_set_drvdata ( spi , indio_dev ) ;
2010-10-28 05:44:05 +04:00
2019-09-19 16:23:03 +03:00
mutex_init ( & st - > lock ) ;
2010-10-28 05:44:05 +04:00
/* Allocate the comms buffers */
st - > us = spi ;
2013-01-09 18:01:00 +04:00
st - > info = & adis16080_chip_info [ id - > driver_data ] ;
2010-10-28 05:44:05 +04:00
2011-06-27 16:07:44 +04:00
indio_dev - > name = spi - > dev . driver - > name ;
2011-08-12 20:47:57 +04:00
indio_dev - > channels = adis16080_channels ;
indio_dev - > num_channels = ARRAY_SIZE ( adis16080_channels ) ;
2011-06-27 16:07:44 +04:00
indio_dev - > info = & adis16080_info ;
indio_dev - > modes = INDIO_DIRECT_MODE ;
2010-10-28 05:44:05 +04:00
2013-08-13 10:34:00 +04:00
return iio_device_register ( indio_dev ) ;
2010-10-28 05:44:05 +04:00
}
2012-11-19 22:26:37 +04:00
static int adis16080_remove ( struct spi_device * spi )
2010-10-28 05:44:05 +04:00
{
2011-06-27 16:07:44 +04:00
iio_device_unregister ( spi_get_drvdata ( spi ) ) ;
2010-10-28 05:44:05 +04:00
return 0 ;
}
2013-01-09 18:01:00 +04:00
static const struct spi_device_id adis16080_ids [ ] = {
2013-01-09 18:01:00 +04:00
{ " adis16080 " , ID_ADIS16080 } ,
{ " adis16100 " , ID_ADIS16100 } ,
2013-01-09 18:01:00 +04:00
{ } ,
} ;
MODULE_DEVICE_TABLE ( spi , adis16080_ids ) ;
2010-10-28 05:44:05 +04:00
static struct spi_driver adis16080_driver = {
. driver = {
. name = " adis16080 " ,
} ,
. probe = adis16080_probe ,
2012-11-19 22:21:38 +04:00
. remove = adis16080_remove ,
2013-01-09 18:01:00 +04:00
. id_table = adis16080_ids ,
2010-10-28 05:44:05 +04:00
} ;
2011-11-16 13:13:39 +04:00
module_spi_driver ( adis16080_driver ) ;
2010-10-28 05:44:05 +04:00
MODULE_AUTHOR ( " Barry Song <21cnbao@gmail.com> " ) ;
2011-02-11 17:20:01 +03:00
MODULE_DESCRIPTION ( " Analog Devices ADIS16080/100 Yaw Rate Gyroscope Driver " ) ;
2010-10-28 05:44:05 +04:00
MODULE_LICENSE ( " GPL v2 " ) ;