2015-05-18 12:19:18 +03:00
/*
* Marvell Berlin2 ADC driver
*
* Copyright ( C ) 2015 Marvell Technology Group Ltd .
*
* Antoine Tenart < antoine . tenart @ free - electrons . com >
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed " as is " without any
* warranty of any kind , whether express or implied .
*/
# include <linux/iio/iio.h>
# include <linux/iio/driver.h>
# include <linux/iio/machine.h>
# include <linux/interrupt.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/platform_device.h>
# include <linux/slab.h>
# include <linux/mfd/syscon.h>
# include <linux/regmap.h>
# include <linux/sched.h>
# include <linux/wait.h>
# define BERLIN2_SM_CTRL 0x14
# define BERLIN2_SM_CTRL_SM_SOC_INT BIT(1)
# define BERLIN2_SM_CTRL_SOC_SM_INT BIT(2)
2015-07-28 01:38:57 +03:00
# define BERLIN2_SM_CTRL_ADC_SEL(x) ((x) << 5) /* 0-15 */
2015-07-28 01:38:59 +03:00
# define BERLIN2_SM_CTRL_ADC_SEL_MASK GENMASK(8, 5)
2015-05-18 12:19:18 +03:00
# define BERLIN2_SM_CTRL_ADC_POWER BIT(9)
# define BERLIN2_SM_CTRL_ADC_CLKSEL_DIV2 (0x0 << 10)
# define BERLIN2_SM_CTRL_ADC_CLKSEL_DIV3 (0x1 << 10)
# define BERLIN2_SM_CTRL_ADC_CLKSEL_DIV4 (0x2 << 10)
# define BERLIN2_SM_CTRL_ADC_CLKSEL_DIV8 (0x3 << 10)
2015-07-28 01:38:59 +03:00
# define BERLIN2_SM_CTRL_ADC_CLKSEL_MASK GENMASK(11, 10)
2015-05-18 12:19:18 +03:00
# define BERLIN2_SM_CTRL_ADC_START BIT(12)
# define BERLIN2_SM_CTRL_ADC_RESET BIT(13)
# define BERLIN2_SM_CTRL_ADC_BANDGAP_RDY BIT(14)
# define BERLIN2_SM_CTRL_ADC_CONT_SINGLE (0x0 << 15)
# define BERLIN2_SM_CTRL_ADC_CONT_CONTINUOUS (0x1 << 15)
# define BERLIN2_SM_CTRL_ADC_BUFFER_EN BIT(16)
# define BERLIN2_SM_CTRL_ADC_VREF_EXT (0x0 << 17)
# define BERLIN2_SM_CTRL_ADC_VREF_INT (0x1 << 17)
# define BERLIN2_SM_CTRL_ADC_ROTATE BIT(19)
# define BERLIN2_SM_CTRL_TSEN_EN BIT(20)
# define BERLIN2_SM_CTRL_TSEN_CLK_SEL_125 (0x0 << 21) /* 1.25 MHz */
# define BERLIN2_SM_CTRL_TSEN_CLK_SEL_250 (0x1 << 21) /* 2.5 MHz */
# define BERLIN2_SM_CTRL_TSEN_MODE_0_125 (0x0 << 22) /* 0-125 C */
# define BERLIN2_SM_CTRL_TSEN_MODE_10_50 (0x1 << 22) /* 10-50 C */
# define BERLIN2_SM_CTRL_TSEN_RESET BIT(29)
# define BERLIN2_SM_ADC_DATA 0x20
2015-07-28 01:38:59 +03:00
# define BERLIN2_SM_ADC_MASK GENMASK(9, 0)
2015-05-18 12:19:18 +03:00
# define BERLIN2_SM_ADC_STATUS 0x1c
# define BERLIN2_SM_ADC_STATUS_DATA_RDY(x) BIT(x) /* 0-15 */
2015-07-28 01:38:57 +03:00
# define BERLIN2_SM_ADC_STATUS_DATA_RDY_MASK GENMASK(15, 0)
2015-05-18 12:19:18 +03:00
# define BERLIN2_SM_ADC_STATUS_INT_EN(x) (BIT(x) << 16) /* 0-15 */
2015-07-28 01:38:57 +03:00
# define BERLIN2_SM_ADC_STATUS_INT_EN_MASK GENMASK(31, 16)
2015-05-18 12:19:18 +03:00
# define BERLIN2_SM_TSEN_STATUS 0x24
# define BERLIN2_SM_TSEN_STATUS_DATA_RDY BIT(0)
# define BERLIN2_SM_TSEN_STATUS_INT_EN BIT(1)
# define BERLIN2_SM_TSEN_DATA 0x28
2015-07-28 01:38:57 +03:00
# define BERLIN2_SM_TSEN_MASK GENMASK(9, 0)
2015-05-18 12:19:18 +03:00
# define BERLIN2_SM_TSEN_CTRL 0x74
# define BERLIN2_SM_TSEN_CTRL_START BIT(8)
# define BERLIN2_SM_TSEN_CTRL_SETTLING_4 (0x0 << 21) /* 4 us */
# define BERLIN2_SM_TSEN_CTRL_SETTLING_12 (0x1 << 21) /* 12 us */
2015-07-28 01:38:59 +03:00
# define BERLIN2_SM_TSEN_CTRL_SETTLING_MASK BIT(21)
2015-05-18 12:19:18 +03:00
# define BERLIN2_SM_TSEN_CTRL_TRIM(x) ((x) << 22)
2015-07-28 01:38:59 +03:00
# define BERLIN2_SM_TSEN_CTRL_TRIM_MASK GENMASK(25, 22)
2015-05-18 12:19:18 +03:00
struct berlin2_adc_priv {
struct regmap * regmap ;
struct mutex lock ;
wait_queue_head_t wq ;
bool data_available ;
int data ;
} ;
# define BERLIN2_ADC_CHANNEL(n, t) \
2015-07-28 01:39:04 +03:00
{ \
. channel = n , \
. datasheet_name = " channel " # n , \
. type = t , \
. indexed = 1 , \
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) , \
}
2015-05-18 12:19:18 +03:00
2015-07-28 01:39:00 +03:00
static const struct iio_chan_spec berlin2_adc_channels [ ] = {
2015-05-18 12:19:18 +03:00
BERLIN2_ADC_CHANNEL ( 0 , IIO_VOLTAGE ) , /* external input */
BERLIN2_ADC_CHANNEL ( 1 , IIO_VOLTAGE ) , /* external input */
BERLIN2_ADC_CHANNEL ( 2 , IIO_VOLTAGE ) , /* external input */
BERLIN2_ADC_CHANNEL ( 3 , IIO_VOLTAGE ) , /* external input */
BERLIN2_ADC_CHANNEL ( 4 , IIO_VOLTAGE ) , /* reserved */
BERLIN2_ADC_CHANNEL ( 5 , IIO_VOLTAGE ) , /* reserved */
{ /* temperature sensor */
. channel = 6 ,
. datasheet_name = " channel6 " ,
. type = IIO_TEMP ,
. indexed = 0 ,
. info_mask_separate = BIT ( IIO_CHAN_INFO_PROCESSED ) ,
} ,
BERLIN2_ADC_CHANNEL ( 7 , IIO_VOLTAGE ) , /* reserved */
IIO_CHAN_SOFT_TIMESTAMP ( 8 ) , /* timestamp */
} ;
static int berlin2_adc_read ( struct iio_dev * indio_dev , int channel )
{
struct berlin2_adc_priv * priv = iio_priv ( indio_dev ) ;
int data , ret ;
mutex_lock ( & priv - > lock ) ;
2015-07-28 01:39:03 +03:00
/* Enable the interrupts */
regmap_write ( priv - > regmap , BERLIN2_SM_ADC_STATUS ,
BERLIN2_SM_ADC_STATUS_INT_EN ( channel ) ) ;
2015-05-18 12:19:18 +03:00
/* Configure the ADC */
regmap_update_bits ( priv - > regmap , BERLIN2_SM_CTRL ,
2015-07-28 01:39:04 +03:00
BERLIN2_SM_CTRL_ADC_RESET |
BERLIN2_SM_CTRL_ADC_SEL_MASK |
BERLIN2_SM_CTRL_ADC_START ,
BERLIN2_SM_CTRL_ADC_SEL ( channel ) |
BERLIN2_SM_CTRL_ADC_START ) ;
2015-05-18 12:19:18 +03:00
ret = wait_event_interruptible_timeout ( priv - > wq , priv - > data_available ,
2015-07-28 01:39:04 +03:00
msecs_to_jiffies ( 1000 ) ) ;
2015-05-18 12:19:18 +03:00
/* Disable the interrupts */
regmap_update_bits ( priv - > regmap , BERLIN2_SM_ADC_STATUS ,
2015-07-28 01:39:04 +03:00
BERLIN2_SM_ADC_STATUS_INT_EN ( channel ) , 0 ) ;
2015-05-18 12:19:18 +03:00
if ( ret = = 0 )
ret = - ETIMEDOUT ;
if ( ret < 0 ) {
mutex_unlock ( & priv - > lock ) ;
return ret ;
}
regmap_update_bits ( priv - > regmap , BERLIN2_SM_CTRL ,
2015-07-28 01:39:04 +03:00
BERLIN2_SM_CTRL_ADC_START , 0 ) ;
2015-05-18 12:19:18 +03:00
data = priv - > data ;
priv - > data_available = false ;
mutex_unlock ( & priv - > lock ) ;
return data ;
}
static int berlin2_adc_tsen_read ( struct iio_dev * indio_dev )
{
struct berlin2_adc_priv * priv = iio_priv ( indio_dev ) ;
int data , ret ;
mutex_lock ( & priv - > lock ) ;
2015-07-28 01:39:03 +03:00
/* Enable interrupts */
regmap_write ( priv - > regmap , BERLIN2_SM_TSEN_STATUS ,
BERLIN2_SM_TSEN_STATUS_INT_EN ) ;
2015-05-18 12:19:18 +03:00
/* Configure the ADC */
regmap_update_bits ( priv - > regmap , BERLIN2_SM_CTRL ,
2015-07-28 01:39:04 +03:00
BERLIN2_SM_CTRL_TSEN_RESET |
BERLIN2_SM_CTRL_ADC_ROTATE ,
BERLIN2_SM_CTRL_ADC_ROTATE ) ;
2015-05-18 12:19:18 +03:00
/* Configure the temperature sensor */
regmap_update_bits ( priv - > regmap , BERLIN2_SM_TSEN_CTRL ,
2015-07-28 01:39:04 +03:00
BERLIN2_SM_TSEN_CTRL_TRIM_MASK |
BERLIN2_SM_TSEN_CTRL_SETTLING_MASK |
BERLIN2_SM_TSEN_CTRL_START ,
BERLIN2_SM_TSEN_CTRL_TRIM ( 3 ) |
BERLIN2_SM_TSEN_CTRL_SETTLING_12 |
BERLIN2_SM_TSEN_CTRL_START ) ;
2015-05-18 12:19:18 +03:00
ret = wait_event_interruptible_timeout ( priv - > wq , priv - > data_available ,
2015-07-28 01:39:04 +03:00
msecs_to_jiffies ( 1000 ) ) ;
2015-05-18 12:19:18 +03:00
/* Disable interrupts */
regmap_update_bits ( priv - > regmap , BERLIN2_SM_TSEN_STATUS ,
2015-07-28 01:39:04 +03:00
BERLIN2_SM_TSEN_STATUS_INT_EN , 0 ) ;
2015-05-18 12:19:18 +03:00
if ( ret = = 0 )
ret = - ETIMEDOUT ;
if ( ret < 0 ) {
mutex_unlock ( & priv - > lock ) ;
return ret ;
}
regmap_update_bits ( priv - > regmap , BERLIN2_SM_TSEN_CTRL ,
2015-07-28 01:39:04 +03:00
BERLIN2_SM_TSEN_CTRL_START , 0 ) ;
2015-05-18 12:19:18 +03:00
data = priv - > data ;
priv - > data_available = false ;
mutex_unlock ( & priv - > lock ) ;
return data ;
}
static int berlin2_adc_read_raw ( struct iio_dev * indio_dev ,
2015-07-28 01:39:04 +03:00
struct iio_chan_spec const * chan , int * val ,
int * val2 , long mask )
2015-05-18 12:19:18 +03:00
{
int temp ;
switch ( mask ) {
case IIO_CHAN_INFO_RAW :
if ( chan - > type ! = IIO_VOLTAGE )
return - EINVAL ;
* val = berlin2_adc_read ( indio_dev , chan - > channel ) ;
if ( * val < 0 )
return * val ;
return IIO_VAL_INT ;
case IIO_CHAN_INFO_PROCESSED :
if ( chan - > type ! = IIO_TEMP )
return - EINVAL ;
temp = berlin2_adc_tsen_read ( indio_dev ) ;
if ( temp < 0 )
return temp ;
if ( temp > 2047 )
2015-07-28 01:39:01 +03:00
temp - = 4096 ;
2015-05-18 12:19:18 +03:00
/* Convert to milli Celsius */
* val = ( ( temp * 100000 ) / 264 - 270000 ) ;
return IIO_VAL_INT ;
default :
break ;
}
return - EINVAL ;
}
static irqreturn_t berlin2_adc_irq ( int irq , void * private )
{
struct berlin2_adc_priv * priv = iio_priv ( private ) ;
unsigned val ;
regmap_read ( priv - > regmap , BERLIN2_SM_ADC_STATUS , & val ) ;
if ( val & BERLIN2_SM_ADC_STATUS_DATA_RDY_MASK ) {
regmap_read ( priv - > regmap , BERLIN2_SM_ADC_DATA , & priv - > data ) ;
priv - > data & = BERLIN2_SM_ADC_MASK ;
val & = ~ BERLIN2_SM_ADC_STATUS_DATA_RDY_MASK ;
regmap_write ( priv - > regmap , BERLIN2_SM_ADC_STATUS , val ) ;
priv - > data_available = true ;
wake_up_interruptible ( & priv - > wq ) ;
}
return IRQ_HANDLED ;
}
static irqreturn_t berlin2_adc_tsen_irq ( int irq , void * private )
{
struct berlin2_adc_priv * priv = iio_priv ( private ) ;
unsigned val ;
regmap_read ( priv - > regmap , BERLIN2_SM_TSEN_STATUS , & val ) ;
if ( val & BERLIN2_SM_TSEN_STATUS_DATA_RDY ) {
regmap_read ( priv - > regmap , BERLIN2_SM_TSEN_DATA , & priv - > data ) ;
priv - > data & = BERLIN2_SM_TSEN_MASK ;
val & = ~ BERLIN2_SM_TSEN_STATUS_DATA_RDY ;
regmap_write ( priv - > regmap , BERLIN2_SM_TSEN_STATUS , val ) ;
priv - > data_available = true ;
wake_up_interruptible ( & priv - > wq ) ;
}
return IRQ_HANDLED ;
}
static const struct iio_info berlin2_adc_info = {
. read_raw = berlin2_adc_read_raw ,
} ;
static int berlin2_adc_probe ( struct platform_device * pdev )
{
struct iio_dev * indio_dev ;
struct berlin2_adc_priv * priv ;
struct device_node * parent_np = of_get_parent ( pdev - > dev . of_node ) ;
int irq , tsen_irq ;
int ret ;
2015-07-28 01:39:01 +03:00
indio_dev = devm_iio_device_alloc ( & pdev - > dev , sizeof ( * priv ) ) ;
2015-05-18 12:19:18 +03:00
if ( ! indio_dev )
return - ENOMEM ;
priv = iio_priv ( indio_dev ) ;
platform_set_drvdata ( pdev , indio_dev ) ;
priv - > regmap = syscon_node_to_regmap ( parent_np ) ;
of_node_put ( parent_np ) ;
if ( IS_ERR ( priv - > regmap ) )
return PTR_ERR ( priv - > regmap ) ;
irq = platform_get_irq_byname ( pdev , " adc " ) ;
if ( irq < 0 )
2015-07-28 01:38:58 +03:00
return irq ;
2015-05-18 12:19:18 +03:00
tsen_irq = platform_get_irq_byname ( pdev , " tsen " ) ;
if ( tsen_irq < 0 )
2015-07-28 01:38:58 +03:00
return tsen_irq ;
2015-05-18 12:19:18 +03:00
ret = devm_request_irq ( & pdev - > dev , irq , berlin2_adc_irq , 0 ,
2015-07-28 01:39:04 +03:00
pdev - > dev . driver - > name , indio_dev ) ;
2015-05-18 12:19:18 +03:00
if ( ret )
return ret ;
ret = devm_request_irq ( & pdev - > dev , tsen_irq , berlin2_adc_tsen_irq ,
2015-07-28 01:39:04 +03:00
0 , pdev - > dev . driver - > name , indio_dev ) ;
2015-05-18 12:19:18 +03:00
if ( ret )
return ret ;
init_waitqueue_head ( & priv - > wq ) ;
mutex_init ( & priv - > lock ) ;
indio_dev - > name = dev_name ( & pdev - > dev ) ;
indio_dev - > modes = INDIO_DIRECT_MODE ;
indio_dev - > info = & berlin2_adc_info ;
indio_dev - > channels = berlin2_adc_channels ;
2015-07-28 01:39:02 +03:00
indio_dev - > num_channels = ARRAY_SIZE ( berlin2_adc_channels ) ;
2015-05-18 12:19:18 +03:00
/* Power up the ADC */
regmap_update_bits ( priv - > regmap , BERLIN2_SM_CTRL ,
2015-07-28 01:39:04 +03:00
BERLIN2_SM_CTRL_ADC_POWER ,
BERLIN2_SM_CTRL_ADC_POWER ) ;
2015-05-18 12:19:18 +03:00
ret = iio_device_register ( indio_dev ) ;
if ( ret ) {
/* Power down the ADC */
regmap_update_bits ( priv - > regmap , BERLIN2_SM_CTRL ,
2015-07-28 01:39:04 +03:00
BERLIN2_SM_CTRL_ADC_POWER , 0 ) ;
2015-05-18 12:19:18 +03:00
return ret ;
}
return 0 ;
}
static int berlin2_adc_remove ( struct platform_device * pdev )
{
struct iio_dev * indio_dev = platform_get_drvdata ( pdev ) ;
struct berlin2_adc_priv * priv = iio_priv ( indio_dev ) ;
iio_device_unregister ( indio_dev ) ;
/* Power down the ADC */
regmap_update_bits ( priv - > regmap , BERLIN2_SM_CTRL ,
2015-07-28 01:39:04 +03:00
BERLIN2_SM_CTRL_ADC_POWER , 0 ) ;
2015-05-18 12:19:18 +03:00
return 0 ;
}
static const struct of_device_id berlin2_adc_match [ ] = {
{ . compatible = " marvell,berlin2-adc " , } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , berlin2_adc_match ) ;
static struct platform_driver berlin2_adc_driver = {
. driver = {
. name = " berlin2-adc " ,
. of_match_table = berlin2_adc_match ,
} ,
. probe = berlin2_adc_probe ,
. remove = berlin2_adc_remove ,
} ;
module_platform_driver ( berlin2_adc_driver ) ;
MODULE_AUTHOR ( " Antoine Tenart <antoine.tenart@free-electrons.com> " ) ;
MODULE_DESCRIPTION ( " Marvell Berlin2 ADC driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;