2019-05-28 19:57:06 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2011-04-04 17:39:15 +04:00
/*
* AD5504 , AD5501 High Voltage Digital to Analog Converter
*
* Copyright 2011 Analog Devices Inc .
*/
# include <linux/interrupt.h>
# include <linux/fs.h>
# include <linux/device.h>
# include <linux/kernel.h>
# include <linux/spi/spi.h>
# include <linux/slab.h>
# include <linux/sysfs.h>
# include <linux/regulator/consumer.h>
2011-07-03 23:49:50 +04:00
# include <linux/module.h>
2014-12-06 09:00:00 +03:00
# include <linux/bitops.h>
2011-04-04 17:39:15 +04:00
2012-04-25 18:54:58 +04:00
# include <linux/iio/iio.h>
# include <linux/iio/sysfs.h>
# include <linux/iio/events.h>
2012-06-04 13:36:28 +04:00
# include <linux/iio/dac/ad5504.h>
2011-04-04 17:39:15 +04:00
2014-12-06 09:00:00 +03:00
# define AD5504_RES_MASK GENMASK(11, 0)
# define AD5504_CMD_READ BIT(15)
# define AD5504_CMD_WRITE 0
2012-06-04 13:36:26 +04:00
# define AD5504_ADDR(addr) ((addr) << 12)
/* Registers */
# define AD5504_ADDR_NOOP 0
# define AD5504_ADDR_DAC(x) ((x) + 1)
# define AD5504_ADDR_ALL_DAC 5
# define AD5504_ADDR_CTRL 7
/* Control Register */
# define AD5504_DAC_PWR(ch) ((ch) << 2)
# define AD5504_DAC_PWRDWN_MODE(mode) ((mode) << 6)
# define AD5504_DAC_PWRDN_20K 0
# define AD5504_DAC_PWRDN_3STATE 1
/**
* struct ad5446_state - driver instance specific data
2014-12-06 09:00:00 +03:00
* @ spi : spi_device
2012-06-04 13:36:26 +04:00
* @ reg : supply regulator
* @ vref_mv : actual reference voltage used
2020-07-17 19:55:20 +03:00
* @ pwr_down_mask : power down mask
* @ pwr_down_mode : current power down mode
2013-11-25 16:41:00 +04:00
* @ data : transfer buffer
2012-06-04 13:36:26 +04:00
*/
struct ad5504_state {
struct spi_device * spi ;
struct regulator * reg ;
unsigned short vref_mv ;
unsigned pwr_down_mask ;
unsigned pwr_down_mode ;
2013-11-25 16:41:00 +04:00
__be16 data [ 2 ] ____cacheline_aligned ;
2012-06-04 13:36:26 +04:00
} ;
2020-07-17 19:55:20 +03:00
/*
2012-06-04 13:36:26 +04:00
* ad5504_supported_device_ids :
*/
enum ad5504_supported_device_ids {
ID_AD5504 ,
ID_AD5501 ,
} ;
2013-11-25 16:41:00 +04:00
static int ad5504_spi_write ( struct ad5504_state * st , u8 addr , u16 val )
2011-04-04 17:39:15 +04:00
{
2013-11-25 16:41:00 +04:00
st - > data [ 0 ] = cpu_to_be16 ( AD5504_CMD_WRITE | AD5504_ADDR ( addr ) |
2011-04-04 17:39:15 +04:00
( val & AD5504_RES_MASK ) ) ;
2013-11-25 16:41:00 +04:00
return spi_write ( st - > spi , & st - > data [ 0 ] , 2 ) ;
2011-04-04 17:39:15 +04:00
}
2013-11-25 16:41:00 +04:00
static int ad5504_spi_read ( struct ad5504_state * st , u8 addr )
2011-04-04 17:39:15 +04:00
{
int ret ;
2013-11-25 16:41:00 +04:00
struct spi_transfer t = {
. tx_buf = & st - > data [ 0 ] ,
. rx_buf = & st - > data [ 1 ] ,
. len = 2 ,
} ;
st - > data [ 0 ] = cpu_to_be16 ( AD5504_CMD_READ | AD5504_ADDR ( addr ) ) ;
ret = spi_sync_transfer ( st - > spi , & t , 1 ) ;
2011-11-15 19:31:23 +04:00
if ( ret < 0 )
return ret ;
2011-04-04 17:39:15 +04:00
2013-11-25 16:41:00 +04:00
return be16_to_cpu ( st - > data [ 1 ] ) & AD5504_RES_MASK ;
2011-04-04 17:39:15 +04:00
}
2011-11-15 19:31:23 +04:00
static int ad5504_read_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
int * val ,
int * val2 ,
long m )
2011-04-04 17:39:15 +04:00
{
2011-06-27 16:07:32 +04:00
struct ad5504_state * st = iio_priv ( indio_dev ) ;
2011-04-04 17:39:15 +04:00
int ret ;
2011-11-15 19:31:23 +04:00
switch ( m ) {
2012-04-15 20:41:19 +04:00
case IIO_CHAN_INFO_RAW :
2013-11-25 16:41:00 +04:00
ret = ad5504_spi_read ( st , chan - > address ) ;
2011-11-15 19:31:23 +04:00
if ( ret < 0 )
return ret ;
2011-04-04 17:39:15 +04:00
2011-11-15 19:31:23 +04:00
* val = ret ;
return IIO_VAL_INT ;
case IIO_CHAN_INFO_SCALE :
2013-09-28 13:31:00 +04:00
* val = st - > vref_mv ;
* val2 = chan - > scan_type . realbits ;
return IIO_VAL_FRACTIONAL_LOG2 ;
2011-11-15 19:31:23 +04:00
}
return - EINVAL ;
2011-04-04 17:39:15 +04:00
}
2011-11-15 19:31:23 +04:00
static int ad5504_write_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
int val ,
int val2 ,
long mask )
2011-04-04 17:39:15 +04:00
{
2011-06-27 16:07:32 +04:00
struct ad5504_state * st = iio_priv ( indio_dev ) ;
2011-04-04 17:39:15 +04:00
2011-11-15 19:31:23 +04:00
switch ( mask ) {
2012-04-15 20:41:19 +04:00
case IIO_CHAN_INFO_RAW :
2011-11-15 19:31:23 +04:00
if ( val > = ( 1 < < chan - > scan_type . realbits ) | | val < 0 )
return - EINVAL ;
2011-04-04 17:39:15 +04:00
2013-11-25 16:41:00 +04:00
return ad5504_spi_write ( st , chan - > address , val ) ;
2011-11-15 19:31:23 +04:00
default :
2014-03-07 11:38:00 +04:00
return - EINVAL ;
2011-11-15 19:31:23 +04:00
}
2011-04-04 17:39:15 +04:00
}
2012-06-04 13:36:15 +04:00
static const char * const ad5504_powerdown_modes [ ] = {
" 20kohm_to_gnd " ,
" three_state " ,
} ;
static int ad5504_get_powerdown_mode ( struct iio_dev * indio_dev ,
const struct iio_chan_spec * chan )
2011-04-04 17:39:15 +04:00
{
2011-06-27 16:07:32 +04:00
struct ad5504_state * st = iio_priv ( indio_dev ) ;
2011-04-04 17:39:15 +04:00
2012-06-04 13:36:15 +04:00
return st - > pwr_down_mode ;
2011-04-04 17:39:15 +04:00
}
2012-06-04 13:36:15 +04:00
static int ad5504_set_powerdown_mode ( struct iio_dev * indio_dev ,
const struct iio_chan_spec * chan , unsigned int mode )
2011-04-04 17:39:15 +04:00
{
2011-06-27 16:07:32 +04:00
struct ad5504_state * st = iio_priv ( indio_dev ) ;
2011-04-04 17:39:15 +04:00
2012-06-04 13:36:15 +04:00
st - > pwr_down_mode = mode ;
2011-04-04 17:39:15 +04:00
2012-06-04 13:36:15 +04:00
return 0 ;
2011-04-04 17:39:15 +04:00
}
2012-06-04 13:36:15 +04:00
static const struct iio_enum ad5504_powerdown_mode_enum = {
. items = ad5504_powerdown_modes ,
. num_items = ARRAY_SIZE ( ad5504_powerdown_modes ) ,
. get = ad5504_get_powerdown_mode ,
. set = ad5504_set_powerdown_mode ,
} ;
static ssize_t ad5504_read_dac_powerdown ( struct iio_dev * indio_dev ,
uintptr_t private , const struct iio_chan_spec * chan , char * buf )
2011-04-04 17:39:15 +04:00
{
2011-06-27 16:07:32 +04:00
struct ad5504_state * st = iio_priv ( indio_dev ) ;
2011-04-04 17:39:15 +04:00
return sprintf ( buf , " %d \n " ,
2012-06-04 13:36:15 +04:00
! ( st - > pwr_down_mask & ( 1 < < chan - > channel ) ) ) ;
2011-04-04 17:39:15 +04:00
}
2012-06-04 13:36:15 +04:00
static ssize_t ad5504_write_dac_powerdown ( struct iio_dev * indio_dev ,
uintptr_t private , const struct iio_chan_spec * chan , const char * buf ,
size_t len )
2011-04-04 17:39:15 +04:00
{
2012-06-04 13:36:22 +04:00
bool pwr_down ;
2011-04-04 17:39:15 +04:00
int ret ;
2011-06-27 16:07:32 +04:00
struct ad5504_state * st = iio_priv ( indio_dev ) ;
2011-04-04 17:39:15 +04:00
2012-06-04 13:36:22 +04:00
ret = strtobool ( buf , & pwr_down ) ;
2011-04-04 17:39:15 +04:00
if ( ret )
return ret ;
2012-06-04 13:36:22 +04:00
if ( pwr_down )
2012-06-04 13:36:15 +04:00
st - > pwr_down_mask | = ( 1 < < chan - > channel ) ;
2011-04-04 17:39:15 +04:00
else
2012-06-04 13:36:22 +04:00
st - > pwr_down_mask & = ~ ( 1 < < chan - > channel ) ;
2011-04-04 17:39:15 +04:00
2013-11-25 16:41:00 +04:00
ret = ad5504_spi_write ( st , AD5504_ADDR_CTRL ,
2011-04-04 17:39:15 +04:00
AD5504_DAC_PWRDWN_MODE ( st - > pwr_down_mode ) |
AD5504_DAC_PWR ( st - > pwr_down_mask ) ) ;
/* writes to the CTRL register must be followed by a NOOP */
2013-11-25 16:41:00 +04:00
ad5504_spi_write ( st , AD5504_ADDR_NOOP , 0 ) ;
2011-04-04 17:39:15 +04:00
return ret ? ret : len ;
}
static IIO_CONST_ATTR ( temp0_thresh_rising_value , " 110000 " ) ;
static IIO_CONST_ATTR ( temp0_thresh_rising_en , " 1 " ) ;
static struct attribute * ad5504_ev_attributes [ ] = {
& iio_const_attr_temp0_thresh_rising_value . dev_attr . attr ,
& iio_const_attr_temp0_thresh_rising_en . dev_attr . attr ,
NULL ,
} ;
2017-03-28 23:21:48 +03:00
static const struct attribute_group ad5504_ev_attribute_group = {
2011-04-04 17:39:15 +04:00
. attrs = ad5504_ev_attributes ,
} ;
2011-05-18 17:41:04 +04:00
static irqreturn_t ad5504_event_handler ( int irq , void * private )
2011-04-04 17:39:15 +04:00
{
2011-08-30 15:41:06 +04:00
iio_push_event ( private ,
2011-08-12 20:56:04 +04:00
IIO_UNMOD_EVENT_CODE ( IIO_TEMP ,
2011-05-18 17:41:04 +04:00
0 ,
IIO_EV_TYPE_THRESH ,
IIO_EV_DIR_RISING ) ,
2017-04-01 17:11:53 +03:00
iio_get_time_ns ( private ) ) ;
2011-05-18 17:41:04 +04:00
return IRQ_HANDLED ;
2011-04-04 17:39:15 +04:00
}
2011-05-18 17:42:37 +04:00
static const struct iio_info ad5504_info = {
2011-11-15 19:31:23 +04:00
. write_raw = ad5504_write_raw ,
. read_raw = ad5504_read_raw ,
2011-05-18 17:42:37 +04:00
. event_attrs = & ad5504_ev_attribute_group ,
} ;
2012-06-04 13:36:15 +04:00
static const struct iio_chan_spec_ext_info ad5504_ext_info [ ] = {
{
. name = " powerdown " ,
. read = ad5504_read_dac_powerdown ,
. write = ad5504_write_dac_powerdown ,
2013-09-08 17:57:00 +04:00
. shared = IIO_SEPARATE ,
2012-06-04 13:36:15 +04:00
} ,
2013-09-08 17:57:00 +04:00
IIO_ENUM ( " powerdown_mode " , IIO_SHARED_BY_TYPE ,
& ad5504_powerdown_mode_enum ) ,
2012-06-04 13:36:15 +04:00
IIO_ENUM_AVAILABLE ( " powerdown_mode " , & ad5504_powerdown_mode_enum ) ,
{ } ,
} ;
# define AD5504_CHANNEL(_chan) { \
. type = IIO_VOLTAGE , \
. indexed = 1 , \
. output = 1 , \
. channel = ( _chan ) , \
2013-02-27 23:11:04 +04:00
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) , \
. info_mask_shared_by_type = BIT ( IIO_CHAN_INFO_SCALE ) , \
2012-06-04 13:36:15 +04:00
. address = AD5504_ADDR_DAC ( _chan ) , \
2013-12-11 22:45:00 +04:00
. scan_type = { \
. sign = ' u ' , \
. realbits = 12 , \
. storagebits = 16 , \
} , \
2012-06-04 13:36:15 +04:00
. ext_info = ad5504_ext_info , \
}
static const struct iio_chan_spec ad5504_channels [ ] = {
AD5504_CHANNEL ( 0 ) ,
AD5504_CHANNEL ( 1 ) ,
AD5504_CHANNEL ( 2 ) ,
AD5504_CHANNEL ( 3 ) ,
2011-05-18 17:42:37 +04:00
} ;
2012-12-22 01:21:43 +04:00
static int ad5504_probe ( struct spi_device * spi )
2011-04-04 17:39:15 +04:00
{
struct ad5504_platform_data * pdata = spi - > dev . platform_data ;
2011-06-27 16:07:32 +04:00
struct iio_dev * indio_dev ;
2011-04-04 17:39:15 +04:00
struct ad5504_state * st ;
2011-06-27 16:07:32 +04:00
struct regulator * reg ;
2011-04-04 17:39:15 +04:00
int ret , voltage_uv = 0 ;
2013-08-19 15:38:00 +04:00
indio_dev = devm_iio_device_alloc ( & spi - > dev , sizeof ( * st ) ) ;
if ( ! indio_dev )
return - ENOMEM ;
reg = devm_regulator_get ( & spi - > dev , " vcc " ) ;
2011-06-27 16:07:32 +04:00
if ( ! IS_ERR ( reg ) ) {
ret = regulator_enable ( reg ) ;
2011-04-04 17:39:15 +04:00
if ( ret )
2013-08-19 15:38:00 +04:00
return ret ;
2011-04-04 17:39:15 +04:00
2012-12-14 16:06:00 +04:00
ret = regulator_get_voltage ( reg ) ;
if ( ret < 0 )
goto error_disable_reg ;
voltage_uv = ret ;
2011-04-04 17:39:15 +04:00
}
2011-06-27 16:07:32 +04:00
spi_set_drvdata ( spi , indio_dev ) ;
st = iio_priv ( indio_dev ) ;
2011-04-04 17:39:15 +04:00
if ( voltage_uv )
st - > vref_mv = voltage_uv / 1000 ;
else if ( pdata )
st - > vref_mv = pdata - > vref_mv ;
else
dev_warn ( & spi - > dev , " reference voltage unspecified \n " ) ;
2011-06-27 16:07:32 +04:00
st - > reg = reg ;
2011-04-04 17:39:15 +04:00
st - > spi = spi ;
2011-06-27 16:07:32 +04:00
indio_dev - > name = spi_get_device_id ( st - > spi ) - > name ;
2012-06-04 13:36:15 +04:00
indio_dev - > info = & ad5504_info ;
if ( spi_get_device_id ( st - > spi ) - > driver_data = = ID_AD5501 )
2011-11-15 19:31:23 +04:00
indio_dev - > num_channels = 1 ;
2012-06-04 13:36:15 +04:00
else
2011-11-15 19:31:23 +04:00
indio_dev - > num_channels = 4 ;
indio_dev - > channels = ad5504_channels ;
2011-06-27 16:07:32 +04:00
indio_dev - > modes = INDIO_DIRECT_MODE ;
2011-04-04 17:39:15 +04:00
if ( spi - > irq ) {
2013-08-19 15:38:00 +04:00
ret = devm_request_threaded_irq ( & spi - > dev , spi - > irq ,
2011-05-18 17:41:04 +04:00
NULL ,
& ad5504_event_handler ,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT ,
spi_get_device_id ( st - > spi ) - > name ,
2011-06-27 16:07:32 +04:00
indio_dev ) ;
2011-04-04 17:39:15 +04:00
if ( ret )
2011-09-02 20:14:40 +04:00
goto error_disable_reg ;
2011-04-04 17:39:15 +04:00
}
2011-09-02 20:14:40 +04:00
ret = iio_device_register ( indio_dev ) ;
if ( ret )
2013-08-19 15:38:00 +04:00
goto error_disable_reg ;
2011-09-02 20:14:40 +04:00
2011-04-04 17:39:15 +04:00
return 0 ;
error_disable_reg :
2011-06-27 16:07:32 +04:00
if ( ! IS_ERR ( reg ) )
2011-08-12 19:55:33 +04:00
regulator_disable ( reg ) ;
2011-04-04 17:39:15 +04:00
return ret ;
}
2012-12-22 01:21:43 +04:00
static int ad5504_remove ( struct spi_device * spi )
2011-04-04 17:39:15 +04:00
{
2011-06-27 16:07:32 +04:00
struct iio_dev * indio_dev = spi_get_drvdata ( spi ) ;
struct ad5504_state * st = iio_priv ( indio_dev ) ;
2011-09-02 20:14:40 +04:00
2011-10-14 17:46:58 +04:00
iio_device_unregister ( indio_dev ) ;
2011-04-04 17:39:15 +04:00
2013-08-19 15:38:00 +04:00
if ( ! IS_ERR ( st - > reg ) )
2011-09-02 20:14:40 +04:00
regulator_disable ( st - > reg ) ;
2011-04-04 17:39:15 +04:00
return 0 ;
}
static const struct spi_device_id ad5504_id [ ] = {
{ " ad5504 " , ID_AD5504 } ,
{ " ad5501 " , ID_AD5501 } ,
{ }
} ;
2011-11-16 11:53:31 +04:00
MODULE_DEVICE_TABLE ( spi , ad5504_id ) ;
2011-04-04 17:39:15 +04:00
static struct spi_driver ad5504_driver = {
. driver = {
. name = " ad5504 " ,
} ,
. probe = ad5504_probe ,
2012-12-22 01:21:43 +04:00
. remove = ad5504_remove ,
2011-04-04 17:39:15 +04:00
. id_table = ad5504_id ,
} ;
2011-11-16 13:13:39 +04:00
module_spi_driver ( ad5504_driver ) ;
2011-04-04 17:39:15 +04:00
2018-08-14 14:23:17 +03:00
MODULE_AUTHOR ( " Michael Hennerich <michael.hennerich@analog.com> " ) ;
2011-04-04 17:39:15 +04:00
MODULE_DESCRIPTION ( " Analog Devices AD5501/AD5501 DAC " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;