2010-11-22 16:35:32 +03:00
/*
* AD7887 SPI ADC driver
*
2011-05-18 17:41:50 +04:00
* Copyright 2010 - 2011 Analog Devices Inc .
2010-11-22 16:35:32 +03:00
*
2011-05-18 17:41:50 +04:00
* Licensed under the GPL - 2.
2010-11-22 16:35:32 +03:00
*/
# include <linux/device.h>
# include <linux/kernel.h>
# include <linux/slab.h>
# include <linux/sysfs.h>
# include <linux/spi/spi.h>
# include <linux/regulator/consumer.h>
# include <linux/err.h>
2011-07-03 23:49:50 +04:00
# include <linux/module.h>
2012-11-05 13:56:00 +04:00
# include <linux/interrupt.h>
2010-11-22 16:35:32 +03:00
2012-04-25 18:54:58 +04:00
# include <linux/iio/iio.h>
# include <linux/iio/sysfs.h>
# include <linux/iio/buffer.h>
2011-08-12 20:08:43 +04:00
2012-11-05 13:56:00 +04:00
# include <linux/iio/trigger_consumer.h>
# include <linux/iio/triggered_buffer.h>
2010-11-22 16:35:32 +03:00
2012-11-05 13:56:00 +04:00
# include <linux/platform_data/ad7887.h>
2010-11-22 16:35:32 +03:00
2012-11-05 13:56:00 +04:00
# define AD7887_REF_DIS (1 << 5) /* on-chip reference disable */
# define AD7887_DUAL (1 << 4) /* dual-channel mode */
# define AD7887_CH_AIN1 (1 << 3) /* convert on channel 1, DUAL=1 */
# define AD7887_CH_AIN0 (0 << 3) /* convert on channel 0, DUAL=0,1 */
# define AD7887_PM_MODE1 (0) /* CS based shutdown */
# define AD7887_PM_MODE2 (1) /* full on */
# define AD7887_PM_MODE3 (2) /* auto shutdown after conversion */
# define AD7887_PM_MODE4 (3) /* standby mode */
enum ad7887_channels {
AD7887_CH0 ,
AD7887_CH0_CH1 ,
AD7887_CH1 ,
} ;
# define RES_MASK(bits) ((1 << (bits)) - 1)
/**
* struct ad7887_chip_info - chip specifc information
* @ int_vref_mv : the internal reference voltage
* @ channel : channel specification
*/
struct ad7887_chip_info {
u16 int_vref_mv ;
struct iio_chan_spec channel [ 3 ] ;
} ;
struct ad7887_state {
struct spi_device * spi ;
const struct ad7887_chip_info * chip_info ;
struct regulator * reg ;
struct spi_transfer xfer [ 4 ] ;
struct spi_message msg [ 3 ] ;
struct spi_message * ring_msg ;
2012-11-05 13:56:00 +04:00
unsigned char tx_cmd_buf [ 4 ] ;
2012-11-05 13:56:00 +04:00
/*
* DMA ( thus cache coherency maintenance ) requires the
* transfer buffers to live in their own cache lines .
* Buffer needs to be large enough to hold two 16 bit samples and a
* 64 bit aligned 64 bit timestamp .
*/
unsigned char data [ ALIGN ( 4 , sizeof ( s64 ) ) + sizeof ( s64 ) ]
____cacheline_aligned ;
} ;
enum ad7887_supported_device_ids {
ID_AD7887
} ;
static int ad7887_ring_preenable ( struct iio_dev * indio_dev )
{
struct ad7887_state * st = iio_priv ( indio_dev ) ;
int ret ;
ret = iio_sw_buffer_preenable ( indio_dev ) ;
if ( ret < 0 )
return ret ;
/* We know this is a single long so can 'cheat' */
switch ( * indio_dev - > active_scan_mask ) {
case ( 1 < < 0 ) :
st - > ring_msg = & st - > msg [ AD7887_CH0 ] ;
break ;
case ( 1 < < 1 ) :
st - > ring_msg = & st - > msg [ AD7887_CH1 ] ;
/* Dummy read: push CH1 setting down to hardware */
spi_sync ( st - > spi , st - > ring_msg ) ;
break ;
case ( ( 1 < < 1 ) | ( 1 < < 0 ) ) :
st - > ring_msg = & st - > msg [ AD7887_CH0_CH1 ] ;
break ;
}
return 0 ;
}
static int ad7887_ring_postdisable ( struct iio_dev * indio_dev )
{
struct ad7887_state * st = iio_priv ( indio_dev ) ;
/* dummy read: restore default CH0 settin */
return spi_sync ( st - > spi , & st - > msg [ AD7887_CH0 ] ) ;
}
/**
* ad7887_trigger_handler ( ) bh of trigger launched polling to ring buffer
*
* Currently there is no option in this driver to disable the saving of
* timestamps within the ring .
* */
static irqreturn_t ad7887_trigger_handler ( int irq , void * p )
{
struct iio_poll_func * pf = p ;
struct iio_dev * indio_dev = pf - > indio_dev ;
struct ad7887_state * st = iio_priv ( indio_dev ) ;
s64 time_ns ;
int b_sent ;
b_sent = spi_sync ( st - > spi , st - > ring_msg ) ;
if ( b_sent )
goto done ;
time_ns = iio_get_time_ns ( ) ;
if ( indio_dev - > scan_timestamp )
memcpy ( st - > data + indio_dev - > scan_bytes - sizeof ( s64 ) ,
& time_ns , sizeof ( time_ns ) ) ;
2012-06-30 23:06:00 +04:00
iio_push_to_buffers ( indio_dev , st - > data ) ;
2012-11-05 13:56:00 +04:00
done :
iio_trigger_notify_done ( indio_dev - > trig ) ;
return IRQ_HANDLED ;
}
static const struct iio_buffer_setup_ops ad7887_ring_setup_ops = {
. preenable = & ad7887_ring_preenable ,
. postenable = & iio_triggered_buffer_postenable ,
. predisable = & iio_triggered_buffer_predisable ,
. postdisable = & ad7887_ring_postdisable ,
} ;
2010-11-22 16:35:32 +03:00
static int ad7887_scan_direct ( struct ad7887_state * st , unsigned ch )
{
int ret = spi_sync ( st - > spi , & st - > msg [ ch ] ) ;
if ( ret )
return ret ;
return ( st - > data [ ( ch * 2 ) ] < < 8 ) | st - > data [ ( ch * 2 ) + 1 ] ;
}
2011-10-06 20:14:37 +04:00
static int ad7887_read_raw ( struct iio_dev * indio_dev ,
2011-05-18 17:41:50 +04:00
struct iio_chan_spec const * chan ,
int * val ,
int * val2 ,
long m )
2010-11-22 16:35:32 +03:00
{
int ret ;
2011-10-06 20:14:37 +04:00
struct ad7887_state * st = iio_priv ( indio_dev ) ;
2010-11-22 16:35:32 +03:00
2011-05-18 17:41:50 +04:00
switch ( m ) {
2012-04-15 20:41:18 +04:00
case IIO_CHAN_INFO_RAW :
2011-10-06 20:14:37 +04:00
mutex_lock ( & indio_dev - > mlock ) ;
if ( iio_buffer_enabled ( indio_dev ) )
2011-12-06 02:18:23 +04:00
ret = - EBUSY ;
2011-05-18 17:41:50 +04:00
else
ret = ad7887_scan_direct ( st , chan - > address ) ;
2011-10-06 20:14:37 +04:00
mutex_unlock ( & indio_dev - > mlock ) ;
2011-05-18 17:41:50 +04:00
if ( ret < 0 )
return ret ;
2012-11-05 13:56:00 +04:00
* val = ret > > chan - > scan_type . shift ;
* val & = RES_MASK ( chan - > scan_type . realbits ) ;
2011-05-18 17:41:50 +04:00
return IIO_VAL_INT ;
2011-10-26 20:41:36 +04:00
case IIO_CHAN_INFO_SCALE :
2012-11-05 13:56:00 +04:00
if ( st - > reg ) {
* val = regulator_get_voltage ( st - > reg ) ;
if ( * val < 0 )
return * val ;
* val / = 1000 ;
} else {
* val = st - > chip_info - > int_vref_mv ;
}
2012-11-05 13:56:00 +04:00
* val2 = chan - > scan_type . realbits ;
2012-11-05 13:56:00 +04:00
return IIO_VAL_FRACTIONAL_LOG2 ;
2011-05-18 17:41:50 +04:00
}
return - EINVAL ;
2010-11-22 16:35:32 +03:00
}
static const struct ad7887_chip_info ad7887_chip_info_tbl [ ] = {
/*
* More devices added in future
*/
[ ID_AD7887 ] = {
2011-09-30 13:05:44 +04:00
. channel [ 0 ] = {
. type = IIO_VOLTAGE ,
. indexed = 1 ,
. channel = 1 ,
2012-04-15 20:41:18 +04:00
. info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT ,
2011-09-30 13:05:44 +04:00
. address = 1 ,
. scan_index = 1 ,
. scan_type = IIO_ST ( ' u ' , 12 , 16 , 0 ) ,
} ,
. channel [ 1 ] = {
. type = IIO_VOLTAGE ,
. indexed = 1 ,
. channel = 0 ,
2012-04-15 20:41:18 +04:00
. info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT ,
2011-09-30 13:05:44 +04:00
. address = 0 ,
. scan_index = 0 ,
. scan_type = IIO_ST ( ' u ' , 12 , 16 , 0 ) ,
} ,
2011-05-18 17:41:50 +04:00
. channel [ 2 ] = IIO_CHAN_SOFT_TIMESTAMP ( 2 ) ,
2010-11-22 16:35:32 +03:00
. int_vref_mv = 2500 ,
} ,
} ;
2011-05-18 17:42:37 +04:00
static const struct iio_info ad7887_info = {
. read_raw = & ad7887_read_raw ,
. driver_module = THIS_MODULE ,
} ;
2010-11-22 16:35:32 +03:00
static int __devinit ad7887_probe ( struct spi_device * spi )
{
struct ad7887_platform_data * pdata = spi - > dev . platform_data ;
struct ad7887_state * st ;
2012-04-26 15:35:01 +04:00
struct iio_dev * indio_dev = iio_device_alloc ( sizeof ( * st ) ) ;
2012-11-05 13:56:00 +04:00
uint8_t mode ;
2012-11-05 13:56:00 +04:00
int ret ;
2010-11-22 16:35:32 +03:00
2011-05-18 17:41:51 +04:00
if ( indio_dev = = NULL )
return - ENOMEM ;
st = iio_priv ( indio_dev ) ;
2010-11-22 16:35:32 +03:00
2012-11-05 13:56:00 +04:00
if ( ! pdata | | ! pdata - > use_onchip_ref ) {
st - > reg = regulator_get ( & spi - > dev , " vref " ) ;
if ( IS_ERR ( st - > reg ) ) {
ret = PTR_ERR ( st - > reg ) ;
goto error_free ;
}
2010-11-22 16:35:32 +03:00
ret = regulator_enable ( st - > reg ) ;
if ( ret )
goto error_put_reg ;
}
st - > chip_info =
& ad7887_chip_info_tbl [ spi_get_device_id ( spi ) - > driver_data ] ;
2011-05-18 17:41:51 +04:00
spi_set_drvdata ( spi , indio_dev ) ;
2010-11-22 16:35:32 +03:00
st - > spi = spi ;
/* Estabilish that the iio_dev is a child of the spi device */
2011-05-18 17:41:51 +04:00
indio_dev - > dev . parent = & spi - > dev ;
indio_dev - > name = spi_get_device_id ( spi ) - > name ;
2011-05-18 17:42:37 +04:00
indio_dev - > info = & ad7887_info ;
2011-05-18 17:41:51 +04:00
indio_dev - > modes = INDIO_DIRECT_MODE ;
2010-11-22 16:35:32 +03:00
/* Setup default message */
2012-11-05 13:56:00 +04:00
mode = AD7887_PM_MODE4 ;
if ( ! pdata | | ! pdata - > use_onchip_ref )
mode | = AD7887_REF_DIS ;
if ( pdata & & pdata - > en_dual )
mode | = AD7887_DUAL ;
st - > tx_cmd_buf [ 0 ] = AD7887_CH_AIN0 | mode ;
2010-11-22 16:35:32 +03:00
st - > xfer [ 0 ] . rx_buf = & st - > data [ 0 ] ;
st - > xfer [ 0 ] . tx_buf = & st - > tx_cmd_buf [ 0 ] ;
st - > xfer [ 0 ] . len = 2 ;
spi_message_init ( & st - > msg [ AD7887_CH0 ] ) ;
spi_message_add_tail ( & st - > xfer [ 0 ] , & st - > msg [ AD7887_CH0 ] ) ;
if ( pdata & & pdata - > en_dual ) {
2012-11-05 13:56:00 +04:00
st - > tx_cmd_buf [ 2 ] = AD7887_CH_AIN1 | mode ;
2010-11-22 16:35:32 +03:00
st - > xfer [ 1 ] . rx_buf = & st - > data [ 0 ] ;
st - > xfer [ 1 ] . tx_buf = & st - > tx_cmd_buf [ 2 ] ;
st - > xfer [ 1 ] . len = 2 ;
st - > xfer [ 2 ] . rx_buf = & st - > data [ 2 ] ;
2012-11-05 13:56:00 +04:00
st - > xfer [ 2 ] . tx_buf = & st - > tx_cmd_buf [ 0 ] ;
2010-11-22 16:35:32 +03:00
st - > xfer [ 2 ] . len = 2 ;
spi_message_init ( & st - > msg [ AD7887_CH0_CH1 ] ) ;
spi_message_add_tail ( & st - > xfer [ 1 ] , & st - > msg [ AD7887_CH0_CH1 ] ) ;
spi_message_add_tail ( & st - > xfer [ 2 ] , & st - > msg [ AD7887_CH0_CH1 ] ) ;
2012-11-05 13:56:00 +04:00
st - > xfer [ 3 ] . rx_buf = & st - > data [ 2 ] ;
st - > xfer [ 3 ] . tx_buf = & st - > tx_cmd_buf [ 2 ] ;
2010-11-22 16:35:32 +03:00
st - > xfer [ 3 ] . len = 2 ;
spi_message_init ( & st - > msg [ AD7887_CH1 ] ) ;
spi_message_add_tail ( & st - > xfer [ 3 ] , & st - > msg [ AD7887_CH1 ] ) ;
2011-05-18 17:41:51 +04:00
indio_dev - > channels = st - > chip_info - > channel ;
indio_dev - > num_channels = 3 ;
2010-11-22 16:35:32 +03:00
} else {
2011-05-18 17:41:51 +04:00
indio_dev - > channels = & st - > chip_info - > channel [ 1 ] ;
indio_dev - > num_channels = 2 ;
2011-05-18 17:41:50 +04:00
}
2010-11-22 16:35:32 +03:00
2012-11-05 13:56:00 +04:00
ret = iio_triggered_buffer_setup ( indio_dev , & iio_pollfunc_store_time ,
& ad7887_trigger_handler , & ad7887_ring_setup_ops ) ;
2010-11-22 16:35:32 +03:00
if ( ret )
2011-05-18 17:41:51 +04:00
goto error_disable_reg ;
2010-11-22 16:35:32 +03:00
2011-09-02 20:14:40 +04:00
ret = iio_device_register ( indio_dev ) ;
if ( ret )
goto error_unregister_ring ;
return 0 ;
error_unregister_ring :
2012-11-05 13:56:00 +04:00
iio_triggered_buffer_cleanup ( indio_dev ) ;
2010-11-22 16:35:32 +03:00
error_disable_reg :
2012-11-05 13:56:00 +04:00
if ( st - > reg )
2010-11-22 16:35:32 +03:00
regulator_disable ( st - > reg ) ;
error_put_reg :
2012-11-05 13:56:00 +04:00
if ( st - > reg )
2010-11-22 16:35:32 +03:00
regulator_put ( st - > reg ) ;
2012-11-05 13:56:00 +04:00
error_free :
2012-04-26 15:35:01 +04:00
iio_device_free ( indio_dev ) ;
2011-05-18 17:41:51 +04:00
2010-11-22 16:35:32 +03:00
return ret ;
}
2012-08-17 21:29:00 +04:00
static int __devexit ad7887_remove ( struct spi_device * spi )
2010-11-22 16:35:32 +03:00
{
2011-05-18 17:41:51 +04:00
struct iio_dev * indio_dev = spi_get_drvdata ( spi ) ;
struct ad7887_state * st = iio_priv ( indio_dev ) ;
2011-10-14 17:46:58 +04:00
iio_device_unregister ( indio_dev ) ;
2012-11-05 13:56:00 +04:00
iio_triggered_buffer_cleanup ( indio_dev ) ;
2012-11-05 13:56:00 +04:00
if ( st - > reg ) {
2010-11-22 16:35:32 +03:00
regulator_disable ( st - > reg ) ;
regulator_put ( st - > reg ) ;
}
2012-04-26 15:35:01 +04:00
iio_device_free ( indio_dev ) ;
2011-05-18 17:41:51 +04:00
2010-11-22 16:35:32 +03:00
return 0 ;
}
static const struct spi_device_id ad7887_id [ ] = {
{ " ad7887 " , ID_AD7887 } ,
{ }
} ;
2011-11-16 11:53:31 +04:00
MODULE_DEVICE_TABLE ( spi , ad7887_id ) ;
2010-11-22 16:35:32 +03:00
static struct spi_driver ad7887_driver = {
. driver = {
. name = " ad7887 " ,
. owner = THIS_MODULE ,
} ,
. probe = ad7887_probe ,
. remove = __devexit_p ( ad7887_remove ) ,
. id_table = ad7887_id ,
} ;
2011-11-16 13:13:39 +04:00
module_spi_driver ( ad7887_driver ) ;
2010-11-22 16:35:32 +03:00
MODULE_AUTHOR ( " Michael Hennerich <hennerich@blackfin.uclinux.org> " ) ;
MODULE_DESCRIPTION ( " Analog Devices AD7887 ADC " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;