2010-10-27 21:44:20 -04:00
/*
2011-10-05 15:28:02 +01:00
* ad2s1200 . c simple support for the ADI Resolver to Digital Converters :
* AD2S1200 / 1205
2010-10-27 21:44:20 -04:00
*
2018-05-18 20:23:25 +02:00
* Copyright ( c ) 2018 - 2018 David Veenstra < davidjulianveenstra @ gmail . com >
2010-10-27 21:44:20 -04:00
* Copyright ( c ) 2010 - 2010 Analog Devices Inc .
*
* 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 .
*/
2018-04-20 21:29:52 +02:00
2018-04-20 21:28:52 +02:00
# include <linux/bitops.h>
2010-10-27 21:44:20 -04:00
# include <linux/delay.h>
2018-04-20 21:28:52 +02:00
# include <linux/device.h>
2010-10-27 21:44:20 -04:00
# include <linux/gpio.h>
2018-05-18 20:21:56 +02:00
# include <linux/gpio/consumer.h>
2011-07-03 15:49:50 -04:00
# include <linux/module.h>
2018-04-20 21:28:52 +02:00
# include <linux/mutex.h>
# include <linux/spi/spi.h>
# include <linux/sysfs.h>
# include <linux/types.h>
2010-10-27 21:44:20 -04:00
2012-04-25 15:54:58 +01:00
# include <linux/iio/iio.h>
# include <linux/iio/sysfs.h>
2010-10-27 21:44:20 -04:00
2011-10-05 15:28:02 +01:00
# define DRV_NAME "ad2s1200"
2010-10-27 21:44:20 -04:00
/* input clock on serial interface */
2011-10-05 15:28:02 +01:00
# define AD2S1200_HZ 8192000
2010-10-27 21:44:20 -04:00
/* clock period in nano second */
2016-02-18 18:59:34 +08:00
# define AD2S1200_TSCLK (1000000000 / AD2S1200_HZ)
2010-10-27 21:44:20 -04:00
2018-05-18 20:21:34 +02:00
/**
* struct ad2s1200_state - driver instance specific data .
* @ lock : protects both the GPIO pins and the rx buffer .
* @ sdev : spi device .
* @ sample : GPIO pin SAMPLE .
* @ rdvel : GPIO pin RDVEL .
* @ rx : buffer for spi transfers .
*/
2011-10-05 15:28:02 +01:00
struct ad2s1200_state {
2010-10-27 21:44:20 -04:00
struct mutex lock ;
struct spi_device * sdev ;
2018-05-18 20:21:56 +02:00
struct gpio_desc * sample ;
struct gpio_desc * rdvel ;
2018-04-23 00:03:03 +02:00
__be16 rx ____cacheline_aligned ;
2010-10-27 21:44:20 -04:00
} ;
2011-10-05 15:28:01 +01:00
static int ad2s1200_read_raw ( struct iio_dev * indio_dev ,
2016-02-18 18:59:33 +08:00
struct iio_chan_spec const * chan ,
int * val ,
int * val2 ,
long m )
2010-10-27 21:44:20 -04:00
{
2018-04-20 21:29:08 +02:00
struct ad2s1200_state * st = iio_priv ( indio_dev ) ;
2018-05-18 20:21:23 +02:00
int ret ;
2010-10-27 21:44:20 -04:00
2018-05-18 20:23:01 +02:00
switch ( m ) {
case IIO_CHAN_INFO_SCALE :
switch ( chan - > type ) {
2018-05-18 20:23:14 +02:00
case IIO_ANGL :
/* 2 * Pi / (2^12 - 1) ~= 0.001534355 */
* val = 0 ;
* val2 = 1534355 ;
return IIO_VAL_INT_PLUS_NANO ;
2018-05-18 20:23:01 +02:00
case IIO_ANGL_VEL :
/* 2 * Pi ~= 6.283185 */
* val = 6 ;
* val2 = 283185 ;
return IIO_VAL_INT_PLUS_MICRO ;
default :
return - EINVAL ;
}
break ;
case IIO_CHAN_INFO_RAW :
mutex_lock ( & st - > lock ) ;
gpiod_set_value ( st - > sample , 0 ) ;
/* delay (6 * AD2S1200_TSCLK + 20) nano seconds */
udelay ( 1 ) ;
gpiod_set_value ( st - > sample , 1 ) ;
gpiod_set_value ( st - > rdvel , ! ! ( chan - > type = = IIO_ANGL ) ) ;
ret = spi_read ( st - > sdev , & st - > rx , 2 ) ;
if ( ret < 0 ) {
mutex_unlock ( & st - > lock ) ;
return ret ;
}
switch ( chan - > type ) {
case IIO_ANGL :
* val = be16_to_cpup ( & st - > rx ) > > 4 ;
break ;
case IIO_ANGL_VEL :
* val = sign_extend32 ( be16_to_cpup ( & st - > rx ) > > 4 , 11 ) ;
break ;
default :
mutex_unlock ( & st - > lock ) ;
return - EINVAL ;
}
/* delay (2 * AD2S1200_TSCLK + 20) ns for sample pulse */
udelay ( 1 ) ;
2011-10-05 15:28:01 +01:00
mutex_unlock ( & st - > lock ) ;
2018-05-18 20:23:01 +02:00
return IIO_VAL_INT ;
2011-10-05 15:28:01 +01:00
default :
2018-05-18 20:23:01 +02:00
break ;
2011-06-27 13:07:52 +01:00
}
2018-04-20 21:29:52 +02:00
2018-05-18 20:23:01 +02:00
return - EINVAL ;
2010-10-27 21:44:20 -04:00
}
2011-10-05 15:28:01 +01:00
static const struct iio_chan_spec ad2s1200_channels [ ] = {
{
. type = IIO_ANGL ,
. indexed = 1 ,
. channel = 0 ,
2013-02-27 19:41:20 +00:00
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) ,
2018-05-18 20:23:14 +02:00
. info_mask_shared_by_type = BIT ( IIO_CHAN_INFO_SCALE ) ,
2011-10-05 15:28:01 +01:00
} , {
. type = IIO_ANGL_VEL ,
. indexed = 1 ,
. channel = 0 ,
2013-02-27 19:41:20 +00:00
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) ,
2018-05-18 20:23:01 +02:00
. info_mask_shared_by_type = BIT ( IIO_CHAN_INFO_SCALE ) ,
2011-10-05 15:28:01 +01:00
}
2010-10-27 21:44:20 -04:00
} ;
2011-10-05 15:28:02 +01:00
static const struct iio_info ad2s1200_info = {
2017-03-11 19:56:43 +05:30
. read_raw = ad2s1200_read_raw ,
2011-05-18 14:42:37 +01:00
} ;
2012-11-19 13:21:57 -05:00
static int ad2s1200_probe ( struct spi_device * spi )
2010-10-27 21:44:20 -04:00
{
2011-10-05 15:28:02 +01:00
struct ad2s1200_state * st ;
2011-06-27 13:07:52 +01:00
struct iio_dev * indio_dev ;
2018-05-18 20:22:32 +02:00
int ret ;
2018-04-20 21:29:52 +02:00
2013-09-11 10:55:00 +01:00
indio_dev = devm_iio_device_alloc ( & spi - > dev , sizeof ( * st ) ) ;
if ( ! indio_dev )
return - ENOMEM ;
2018-04-20 21:29:52 +02:00
2011-06-27 13:07:52 +01:00
spi_set_drvdata ( spi , indio_dev ) ;
st = iio_priv ( indio_dev ) ;
2010-10-27 21:44:20 -04:00
mutex_init ( & st - > lock ) ;
st - > sdev = spi ;
2018-05-18 20:22:32 +02:00
st - > sample = devm_gpiod_get ( & spi - > dev , " adi,sample " , GPIOD_OUT_LOW ) ;
if ( IS_ERR ( st - > sample ) ) {
dev_err ( & spi - > dev , " Failed to claim SAMPLE gpio: err=%ld \n " ,
PTR_ERR ( st - > sample ) ) ;
return PTR_ERR ( st - > sample ) ;
}
st - > rdvel = devm_gpiod_get ( & spi - > dev , " adi,rdvel " , GPIOD_OUT_LOW ) ;
if ( IS_ERR ( st - > rdvel ) ) {
dev_err ( & spi - > dev , " Failed to claim RDVEL gpio: err=%ld \n " ,
PTR_ERR ( st - > rdvel ) ) ;
return PTR_ERR ( st - > rdvel ) ;
}
2010-10-27 21:44:20 -04:00
2011-06-27 13:07:52 +01:00
indio_dev - > dev . parent = & spi - > dev ;
2011-10-05 15:28:02 +01:00
indio_dev - > info = & ad2s1200_info ;
2011-06-27 13:07:52 +01:00
indio_dev - > modes = INDIO_DIRECT_MODE ;
2011-10-05 15:28:01 +01:00
indio_dev - > channels = ad2s1200_channels ;
indio_dev - > num_channels = ARRAY_SIZE ( ad2s1200_channels ) ;
2011-10-05 15:28:02 +01:00
indio_dev - > name = spi_get_device_id ( spi ) - > name ;
2010-10-27 21:44:20 -04:00
2011-10-05 15:28:02 +01:00
spi - > max_speed_hz = AD2S1200_HZ ;
2010-10-27 21:44:20 -04:00
spi - > mode = SPI_MODE_3 ;
2018-05-18 20:21:44 +02:00
ret = spi_setup ( spi ) ;
if ( ret < 0 ) {
dev_err ( & spi - > dev , " spi_setup failed! \n " ) ;
return ret ;
}
2010-10-27 21:44:20 -04:00
2018-05-18 20:21:44 +02:00
return devm_iio_device_register ( & spi - > dev , indio_dev ) ;
2010-10-27 21:44:20 -04:00
}
2018-05-18 20:22:41 +02:00
static const struct of_device_id ad2s1200_of_match [ ] = {
{ . compatible = " adi,ad2s1200 " , } ,
{ . compatible = " adi,ad2s1205 " , } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , ad2s1200_of_match ) ;
2011-10-05 15:28:02 +01:00
static const struct spi_device_id ad2s1200_id [ ] = {
{ " ad2s1200 " } ,
{ " ad2s1205 " } ,
{ }
} ;
2011-11-16 08:53:31 +01:00
MODULE_DEVICE_TABLE ( spi , ad2s1200_id ) ;
2011-10-05 15:28:02 +01:00
static struct spi_driver ad2s1200_driver = {
2010-10-27 21:44:20 -04:00
. driver = {
. name = DRV_NAME ,
2018-05-18 20:22:41 +02:00
. of_match_table = of_match_ptr ( ad2s1200_of_match ) ,
2010-10-27 21:44:20 -04:00
} ,
2011-10-05 15:28:02 +01:00
. probe = ad2s1200_probe ,
. id_table = ad2s1200_id ,
2010-10-27 21:44:20 -04:00
} ;
2011-11-16 10:13:39 +01:00
module_spi_driver ( ad2s1200_driver ) ;
2010-10-27 21:44:20 -04:00
2018-05-18 20:23:25 +02:00
MODULE_AUTHOR ( " David Veenstra <davidjulianveenstra@gmail.com> " ) ;
2010-10-27 21:44:20 -04:00
MODULE_AUTHOR ( " Graff Yang <graff.yang@gmail.com> " ) ;
MODULE_DESCRIPTION ( " Analog Devices AD2S1200/1205 Resolver to Digital SPI driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;