2019-05-24 13:04:09 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2016-09-23 18:19:44 +03:00
/*
* AD7766 / AD7767 SPI ADC driver
*
* Copyright 2016 Analog Devices Inc .
*/
# include <linux/clk.h>
# include <linux/delay.h>
# include <linux/device.h>
# include <linux/err.h>
# include <linux/gpio/consumer.h>
# include <linux/module.h>
# include <linux/regulator/consumer.h>
# include <linux/slab.h>
# include <linux/spi/spi.h>
# include <linux/iio/iio.h>
# include <linux/iio/buffer.h>
# include <linux/iio/trigger.h>
# include <linux/iio/trigger_consumer.h>
# include <linux/iio/triggered_buffer.h>
struct ad7766_chip_info {
unsigned int decimation_factor ;
} ;
enum {
AD7766_SUPPLY_AVDD = 0 ,
AD7766_SUPPLY_DVDD = 1 ,
AD7766_SUPPLY_VREF = 2 ,
AD7766_NUM_SUPPLIES = 3
} ;
struct ad7766 {
const struct ad7766_chip_info * chip_info ;
struct spi_device * spi ;
struct clk * mclk ;
struct gpio_desc * pd_gpio ;
struct regulator_bulk_data reg [ AD7766_NUM_SUPPLIES ] ;
struct iio_trigger * trig ;
struct spi_transfer xfer ;
struct spi_message msg ;
/*
2022-05-08 20:55:55 +03:00
* DMA ( thus cache coherency maintenance ) may require the
2016-09-23 18:19:44 +03:00
* transfer buffers to live in their own cache lines .
* Make the buffer large enough for one 24 bit sample and one 64 bit
* aligned 64 bit timestamp .
*/
2022-05-08 20:55:55 +03:00
unsigned char data [ ALIGN ( 3 , sizeof ( s64 ) ) + sizeof ( s64 ) ] __aligned ( IIO_DMA_MINALIGN ) ;
2016-09-23 18:19:44 +03:00
} ;
/*
* AD7766 and AD7767 variations are interface compatible , the main difference is
* analog performance . Both parts will use the same ID .
*/
enum ad7766_device_ids {
ID_AD7766 ,
ID_AD7766_1 ,
ID_AD7766_2 ,
} ;
static irqreturn_t ad7766_trigger_handler ( int irq , void * p )
{
struct iio_poll_func * pf = p ;
struct iio_dev * indio_dev = pf - > indio_dev ;
struct ad7766 * ad7766 = iio_priv ( indio_dev ) ;
int ret ;
ret = spi_sync ( ad7766 - > spi , & ad7766 - > msg ) ;
if ( ret < 0 )
goto done ;
iio_push_to_buffers_with_timestamp ( indio_dev , ad7766 - > data ,
pf - > timestamp ) ;
done :
iio_trigger_notify_done ( indio_dev - > trig ) ;
return IRQ_HANDLED ;
}
static int ad7766_preenable ( struct iio_dev * indio_dev )
{
struct ad7766 * ad7766 = iio_priv ( indio_dev ) ;
int ret ;
ret = regulator_bulk_enable ( ARRAY_SIZE ( ad7766 - > reg ) , ad7766 - > reg ) ;
if ( ret < 0 ) {
dev_err ( & ad7766 - > spi - > dev , " Failed to enable supplies: %d \n " ,
ret ) ;
return ret ;
}
ret = clk_prepare_enable ( ad7766 - > mclk ) ;
if ( ret < 0 ) {
dev_err ( & ad7766 - > spi - > dev , " Failed to enable MCLK: %d \n " , ret ) ;
regulator_bulk_disable ( ARRAY_SIZE ( ad7766 - > reg ) , ad7766 - > reg ) ;
return ret ;
}
2017-07-17 00:26:03 +03:00
gpiod_set_value ( ad7766 - > pd_gpio , 0 ) ;
2016-09-23 18:19:44 +03:00
return 0 ;
}
static int ad7766_postdisable ( struct iio_dev * indio_dev )
{
struct ad7766 * ad7766 = iio_priv ( indio_dev ) ;
2017-07-17 00:26:03 +03:00
gpiod_set_value ( ad7766 - > pd_gpio , 1 ) ;
2016-09-23 18:19:44 +03:00
/*
* The PD pin is synchronous to the clock , so give it some time to
* notice the change before we disable the clock .
*/
msleep ( 20 ) ;
clk_disable_unprepare ( ad7766 - > mclk ) ;
regulator_bulk_disable ( ARRAY_SIZE ( ad7766 - > reg ) , ad7766 - > reg ) ;
return 0 ;
}
static int ad7766_read_raw ( struct iio_dev * indio_dev ,
const struct iio_chan_spec * chan , int * val , int * val2 , long info )
{
struct ad7766 * ad7766 = iio_priv ( indio_dev ) ;
struct regulator * vref = ad7766 - > reg [ AD7766_SUPPLY_VREF ] . consumer ;
int scale_uv ;
switch ( info ) {
case IIO_CHAN_INFO_SCALE :
scale_uv = regulator_get_voltage ( vref ) ;
if ( scale_uv < 0 )
return scale_uv ;
* val = scale_uv / 1000 ;
* val2 = chan - > scan_type . realbits ;
return IIO_VAL_FRACTIONAL_LOG2 ;
case IIO_CHAN_INFO_SAMP_FREQ :
* val = clk_get_rate ( ad7766 - > mclk ) /
ad7766 - > chip_info - > decimation_factor ;
return IIO_VAL_INT ;
}
return - EINVAL ;
}
static const struct iio_chan_spec ad7766_channels [ ] = {
{
. type = IIO_VOLTAGE ,
. indexed = 1 ,
. info_mask_shared_by_type = BIT ( IIO_CHAN_INFO_SCALE ) ,
. info_mask_shared_by_all = BIT ( IIO_CHAN_INFO_SAMP_FREQ ) ,
. scan_type = {
. sign = ' s ' ,
. realbits = 24 ,
. storagebits = 32 ,
. endianness = IIO_BE ,
} ,
} ,
IIO_CHAN_SOFT_TIMESTAMP ( 1 ) ,
} ;
static const struct ad7766_chip_info ad7766_chip_info [ ] = {
[ ID_AD7766 ] = {
. decimation_factor = 8 ,
} ,
[ ID_AD7766_1 ] = {
. decimation_factor = 16 ,
} ,
[ ID_AD7766_2 ] = {
. decimation_factor = 32 ,
} ,
} ;
static const struct iio_buffer_setup_ops ad7766_buffer_setup_ops = {
. preenable = & ad7766_preenable ,
. postdisable = & ad7766_postdisable ,
} ;
static const struct iio_info ad7766_info = {
. read_raw = & ad7766_read_raw ,
} ;
static irqreturn_t ad7766_irq ( int irq , void * private )
{
iio_trigger_poll ( private ) ;
return IRQ_HANDLED ;
}
static int ad7766_set_trigger_state ( struct iio_trigger * trig , bool enable )
{
struct ad7766 * ad7766 = iio_trigger_get_drvdata ( trig ) ;
if ( enable )
enable_irq ( ad7766 - > spi - > irq ) ;
else
disable_irq ( ad7766 - > spi - > irq ) ;
return 0 ;
}
static const struct iio_trigger_ops ad7766_trigger_ops = {
. set_trigger_state = ad7766_set_trigger_state ,
. validate_device = iio_trigger_validate_own_device ,
} ;
static int ad7766_probe ( struct spi_device * spi )
{
const struct spi_device_id * id = spi_get_device_id ( spi ) ;
struct iio_dev * indio_dev ;
struct ad7766 * ad7766 ;
int ret ;
indio_dev = devm_iio_device_alloc ( & spi - > dev , sizeof ( * ad7766 ) ) ;
if ( ! indio_dev )
return - ENOMEM ;
ad7766 = iio_priv ( indio_dev ) ;
ad7766 - > chip_info = & ad7766_chip_info [ id - > driver_data ] ;
ad7766 - > mclk = devm_clk_get ( & spi - > dev , " mclk " ) ;
if ( IS_ERR ( ad7766 - > mclk ) )
return PTR_ERR ( ad7766 - > mclk ) ;
ad7766 - > reg [ AD7766_SUPPLY_AVDD ] . supply = " avdd " ;
ad7766 - > reg [ AD7766_SUPPLY_DVDD ] . supply = " dvdd " ;
ad7766 - > reg [ AD7766_SUPPLY_VREF ] . supply = " vref " ;
ret = devm_regulator_bulk_get ( & spi - > dev , ARRAY_SIZE ( ad7766 - > reg ) ,
ad7766 - > reg ) ;
2016-11-10 22:30:18 +03:00
if ( ret )
return ret ;
2016-09-23 18:19:44 +03:00
ad7766 - > pd_gpio = devm_gpiod_get_optional ( & spi - > dev , " powerdown " ,
GPIOD_OUT_HIGH ) ;
if ( IS_ERR ( ad7766 - > pd_gpio ) )
return PTR_ERR ( ad7766 - > pd_gpio ) ;
indio_dev - > name = spi_get_device_id ( spi ) - > name ;
indio_dev - > modes = INDIO_DIRECT_MODE ;
indio_dev - > channels = ad7766_channels ;
indio_dev - > num_channels = ARRAY_SIZE ( ad7766_channels ) ;
indio_dev - > info = & ad7766_info ;
if ( spi - > irq > 0 ) {
ad7766 - > trig = devm_iio_trigger_alloc ( & spi - > dev , " %s-dev%d " ,
2021-04-26 20:49:03 +03:00
indio_dev - > name ,
iio_device_id ( indio_dev ) ) ;
2016-09-23 18:19:44 +03:00
if ( ! ad7766 - > trig )
return - ENOMEM ;
ad7766 - > trig - > ops = & ad7766_trigger_ops ;
iio_trigger_set_drvdata ( ad7766 - > trig , ad7766 ) ;
/*
* The device generates interrupts as long as it is powered up .
* Some platforms might not allow the option to power it down so
2021-04-02 21:45:38 +03:00
* don ' t enable the interrupt to avoid extra load on the system
2016-09-23 18:19:44 +03:00
*/
2021-04-02 21:45:38 +03:00
ret = devm_request_irq ( & spi - > dev , spi - > irq , ad7766_irq ,
IRQF_TRIGGER_FALLING | IRQF_NO_AUTOEN ,
dev_name ( & spi - > dev ) ,
ad7766 - > trig ) ;
if ( ret < 0 )
return ret ;
2016-09-23 18:19:44 +03:00
ret = devm_iio_trigger_register ( & spi - > dev , ad7766 - > trig ) ;
if ( ret )
return ret ;
}
ad7766 - > spi = spi ;
/* First byte always 0 */
ad7766 - > xfer . rx_buf = & ad7766 - > data [ 1 ] ;
ad7766 - > xfer . len = 3 ;
spi_message_init ( & ad7766 - > msg ) ;
spi_message_add_tail ( & ad7766 - > xfer , & ad7766 - > msg ) ;
ret = devm_iio_triggered_buffer_setup ( & spi - > dev , indio_dev ,
& iio_pollfunc_store_time , & ad7766_trigger_handler ,
& ad7766_buffer_setup_ops ) ;
if ( ret )
return ret ;
2021-05-11 16:47:39 +03:00
return devm_iio_device_register ( & spi - > dev , indio_dev ) ;
2016-09-23 18:19:44 +03:00
}
static const struct spi_device_id ad7766_id [ ] = {
{ " ad7766 " , ID_AD7766 } ,
{ " ad7766-1 " , ID_AD7766_1 } ,
{ " ad7766-2 " , ID_AD7766_2 } ,
{ " ad7767 " , ID_AD7766 } ,
{ " ad7767-1 " , ID_AD7766_1 } ,
{ " ad7767-2 " , ID_AD7766_2 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( spi , ad7766_id ) ;
static struct spi_driver ad7766_driver = {
. driver = {
. name = " ad7766 " ,
} ,
. probe = ad7766_probe ,
. id_table = ad7766_id ,
} ;
module_spi_driver ( ad7766_driver ) ;
MODULE_AUTHOR ( " Lars-Peter Clausen <lars@metafoo.de> " ) ;
MODULE_DESCRIPTION ( " Analog Devices AD7766 and AD7767 ADCs driver support " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;