@ -43,18 +43,36 @@
# define KXSD9_STATE_RX_SIZE 2
# define KXSD9_STATE_TX_SIZE 2
struct kxsd9_transport ;
/**
* struct kxsd9_transport - transport adapter for SPI or I2C
* @ trdev : transport device such as SPI or I2C
* @ write1 ( ) : function to write a byte to the device
* @ write2 ( ) : function to write two consecutive bytes to the device
* @ readval ( ) : function to read a 16 bit value from the device
* @ rx : cache aligned read buffer
* @ tx : cache aligned write buffer
*/
struct kxsd9_transport {
void * trdev ;
int ( * write1 ) ( struct kxsd9_transport * tr , u8 byte ) ;
int ( * write2 ) ( struct kxsd9_transport * tr , u8 b1 , u8 b2 ) ;
int ( * readval ) ( struct kxsd9_transport * tr , u8 address ) ;
u8 rx [ KXSD9_STATE_RX_SIZE ] ____cacheline_aligned ;
u8 tx [ KXSD9_STATE_TX_SIZE ] ;
} ;
/**
* struct kxsd9_state - device related storage
* @ transport : transport for the KXSD9
* @ buf_lock : protect the rx and tx buffers .
* @ us : spi device
* @ rx : single rx buffer storage
* @ tx : single tx buffer storage
* */
struct kxsd9_state {
struct kxsd9_transport * transport ;
struct mutex buf_lock ;
struct spi_device * us ;
u8 rx [ KXSD9_STATE_RX_SIZE ] ____cacheline_aligned ;
u8 tx [ KXSD9_STATE_TX_SIZE ] ;
} ;
# define KXSD9_SCALE_2G "0.011978"
@ -80,13 +98,12 @@ static int kxsd9_write_scale(struct iio_dev *indio_dev, int micro)
return - EINVAL ;
mutex_lock ( & st - > buf_lock ) ;
ret = spi_w8r8 ( st - > us , KXSD9_READ ( KXSD9_REG_CTRL_C ) ) ;
if ( ret < 0 )
ret = st - > transport - > write1 ( st - > transport , KXSD9_READ ( KXSD9_REG_CTRL_C ) ) ;
if ( ret )
goto error_ret ;
st - > tx [ 0 ] = KXSD9_WRITE ( KXSD9_REG_CTRL_C ) ;
st - > tx [ 1 ] = ( ret & ~ KXSD9_FS_MASK ) | i ;
ret = spi_write ( st - > us , st - > tx , 2 ) ;
ret = st - > transport - > write2 ( st - > transport ,
KXSD9_WRITE ( KXSD9_REG_CTRL_C ) ,
( ret & ~ KXSD9_FS_MASK ) | i ) ;
error_ret :
mutex_unlock ( & st - > buf_lock ) ;
return ret ;
@ -96,24 +113,9 @@ static int kxsd9_read(struct iio_dev *indio_dev, u8 address)
{
int ret ;
struct kxsd9_state * st = iio_priv ( indio_dev ) ;
struct spi_transfer xfers [ ] = {
{
. bits_per_word = 8 ,
. len = 1 ,
. delay_usecs = 200 ,
. tx_buf = st - > tx ,
} , {
. bits_per_word = 8 ,
. len = 2 ,
. rx_buf = st - > rx ,
} ,
} ;
mutex_lock ( & st - > buf_lock ) ;
st - > tx [ 0 ] = KXSD9_READ ( address ) ;
ret = spi_sync_transfer ( st - > us , xfers , ARRAY_SIZE ( xfers ) ) ;
if ( ! ret )
ret = ( ( ( u16 ) ( st - > rx [ 0 ] ) ) < < 8 ) | ( st - > rx [ 1 ] & 0xF0 ) ;
ret = st - > transport - > readval ( st - > transport , KXSD9_READ ( address ) ) ;
mutex_unlock ( & st - > buf_lock ) ;
return ret ;
}
@ -163,8 +165,8 @@ static int kxsd9_read_raw(struct iio_dev *indio_dev,
ret = IIO_VAL_INT ;
break ;
case IIO_CHAN_INFO_SCALE :
ret = spi_w8r8 ( st - > us , KXSD9_READ ( KXSD9_REG_CTRL_C ) ) ;
if ( ret < 0 )
ret = st - > transport - > write1 ( st - > transport , KXSD9_READ ( KXSD9_REG_CTRL_C ) ) ;
if ( ret )
goto error_ret ;
* val = 0 ;
* val2 = kxsd9_micro_scales [ ret & KXSD9_FS_MASK ] ;
@ -203,15 +205,10 @@ static int kxsd9_power_up(struct kxsd9_state *st)
{
int ret ;
st - > tx [ 0 ] = 0x0d ;
st - > tx [ 1 ] = 0x40 ;
ret = spi_write ( st - > us , st - > tx , 2 ) ;
ret = st - > transport - > write2 ( st - > transport , 0x0d , 0x40 ) ;
if ( ret )
return ret ;
st - > tx [ 0 ] = 0x0c ;
st - > tx [ 1 ] = 0x9b ;
return spi_write ( st - > us , st - > tx , 2 ) ;
return st - > transport - > write2 ( st - > transport , 0x0c , 0x9b ) ;
} ;
static const struct iio_info kxsd9_info = {
@ -221,56 +218,130 @@ static const struct iio_info kxsd9_info = {
. driver_module = THIS_MODULE ,
} ;
static int kxsd9_probe ( struct spi_device * spi )
static int kxsd9_common_probe ( struct device * parent ,
struct kxsd9_transport * transport ,
const char * name ,
struct iio_dev * * retdev )
{
struct iio_dev * indio_dev ;
struct kxsd9_state * st ;
int ret ;
indio_dev = devm_iio_device_alloc ( & spi - > dev , sizeof ( * st ) ) ;
indio_dev = devm_iio_device_alloc ( parent , sizeof ( * st ) ) ;
if ( ! indio_dev )
return - ENOMEM ;
st = iio_priv ( indio_dev ) ;
spi_set_drvdata ( spi , indio_dev ) ;
st - > transport = transport ;
st - > us = spi ;
mutex_init ( & st - > buf_lock ) ;
indio_dev - > channels = kxsd9_channels ;
indio_dev - > num_channels = ARRAY_SIZE ( kxsd9_channels ) ;
indio_dev - > name = spi_get_device_id ( spi ) - > name ;
indio_dev - > dev . parent = & spi - > dev ;
indio_dev - > name = name ;
indio_dev - > dev . parent = parent ;
indio_dev - > info = & kxsd9_info ;
indio_dev - > modes = INDIO_DIRECT_MODE ;
kxsd9_power_up ( st ) ;
ret = iio_device_register ( indio_dev ) ;
if ( ret )
return ret ;
* retdev = indio_dev ;
return 0 ;
}
static int kxsd9_spi_write1 ( struct kxsd9_transport * tr , u8 byte )
{
struct spi_device * spi = tr - > trdev ;
return spi_w8r8 ( spi , byte ) ;
}
static int kxsd9_spi_write2 ( struct kxsd9_transport * tr , u8 b1 , u8 b2 )
{
struct spi_device * spi = tr - > trdev ;
tr - > tx [ 0 ] = b1 ;
tr - > tx [ 1 ] = b2 ;
return spi_write ( spi , tr - > tx , 2 ) ;
}
static int kxsd9_spi_readval ( struct kxsd9_transport * tr , u8 address )
{
struct spi_device * spi = tr - > trdev ;
struct spi_transfer xfers [ ] = {
{
. bits_per_word = 8 ,
. len = 1 ,
. delay_usecs = 200 ,
. tx_buf = tr - > tx ,
} , {
. bits_per_word = 8 ,
. len = 2 ,
. rx_buf = tr - > rx ,
} ,
} ;
int ret ;
tr - > tx [ 0 ] = address ;
ret = spi_sync_transfer ( spi , xfers , ARRAY_SIZE ( xfers ) ) ;
if ( ! ret )
ret = ( ( ( u16 ) ( tr - > rx [ 0 ] ) ) < < 8 ) | ( tr - > rx [ 1 ] & 0xF0 ) ;
return ret ;
}
static int kxsd9_spi_probe ( struct spi_device * spi )
{
struct kxsd9_transport * transport ;
struct iio_dev * indio_dev ;
int ret ;
transport = devm_kzalloc ( & spi - > dev , sizeof ( * transport ) , GFP_KERNEL ) ;
if ( ! transport )
return - ENOMEM ;
transport - > trdev = spi ;
transport - > write1 = kxsd9_spi_write1 ;
transport - > write2 = kxsd9_spi_write2 ;
transport - > readval = kxsd9_spi_readval ;
spi - > mode = SPI_MODE_0 ;
spi_setup ( spi ) ;
kxsd9_power_up ( st ) ;
return iio_device_register ( indio_dev ) ;
ret = kxsd9_common_probe ( & spi - > dev ,
transport ,
spi_get_device_id ( spi ) - > name ,
& indio_dev ) ;
if ( ret )
return ret ;
spi_set_drvdata ( spi , indio_dev ) ;
return 0 ;
}
static int kxsd9_remove ( struct spi_device * spi )
static int kxsd9_spi_ remove ( struct spi_device * spi )
{
iio_device_unregister ( spi_get_drvdata ( spi ) ) ;
return 0 ;
}
static const struct spi_device_id kxsd9_id [ ] = {
static const struct spi_device_id kxsd9_spi_ id [ ] = {
{ " kxsd9 " , 0 } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( spi , kxsd9_id ) ;
MODULE_DEVICE_TABLE ( spi , kxsd9_spi_ id ) ;
static struct spi_driver kxsd9_driver = {
static struct spi_driver kxsd9_spi_ driver = {
. driver = {
. name = " kxsd9 " ,
} ,
. probe = kxsd9_probe ,
. remove = kxsd9_remove ,
. id_table = kxsd9_id ,
. probe = kxsd9_spi_ probe ,
. remove = kxsd9_spi_ remove ,
. id_table = kxsd9_spi_ id ,
} ;
module_spi_driver ( kxsd9_driver ) ;
module_spi_driver ( kxsd9_spi_ driver ) ;
MODULE_AUTHOR ( " Jonathan Cameron <jic23@kernel.org> " ) ;
MODULE_DESCRIPTION ( " Kionix KXSD9 SPI driver " ) ;