2012-04-12 13:05:35 +04:00
/*
* ST SPEAr ADC driver
*
* Copyright 2012 Stefan Roese < sr @ denx . de >
*
* Licensed under the GPL - 2.
*/
# include <linux/module.h>
# include <linux/platform_device.h>
# include <linux/interrupt.h>
# include <linux/device.h>
# include <linux/kernel.h>
# include <linux/slab.h>
# include <linux/io.h>
# include <linux/clk.h>
# include <linux/err.h>
# include <linux/completion.h>
# include <linux/of.h>
# include <linux/of_address.h>
2012-04-25 18:54:58 +04:00
# include <linux/iio/iio.h>
# include <linux/iio/sysfs.h>
2012-04-12 13:05:35 +04:00
2014-05-04 20:45:00 +04:00
/* SPEAR registers definitions */
# define SPEAR600_ADC_SCAN_RATE_LO(x) ((x) & 0xFFFF)
# define SPEAR600_ADC_SCAN_RATE_HI(x) (((x) >> 0x10) & 0xFFFF)
# define SPEAR_ADC_CLK_LOW(x) (((x) & 0xf) << 0)
# define SPEAR_ADC_CLK_HIGH(x) (((x) & 0xf) << 4)
2012-04-12 13:05:35 +04:00
/* Bit definitions for SPEAR_ADC_STATUS */
2015-03-26 02:23:29 +03:00
# define SPEAR_ADC_STATUS_START_CONVERSION BIT(0)
2014-05-04 20:45:00 +04:00
# define SPEAR_ADC_STATUS_CHANNEL_NUM(x) ((x) << 1)
2015-03-26 02:23:29 +03:00
# define SPEAR_ADC_STATUS_ADC_ENABLE BIT(4)
2014-05-04 20:45:00 +04:00
# define SPEAR_ADC_STATUS_AVG_SAMPLE(x) ((x) << 5)
2015-03-26 02:23:29 +03:00
# define SPEAR_ADC_STATUS_VREF_INTERNAL BIT(9)
2012-04-12 13:05:35 +04:00
2014-05-04 20:45:00 +04:00
# define SPEAR_ADC_DATA_MASK 0x03ff
# define SPEAR_ADC_DATA_BITS 10
2012-04-12 13:05:35 +04:00
2014-05-04 20:45:00 +04:00
# define SPEAR_ADC_MOD_NAME "spear-adc"
2012-04-12 13:05:35 +04:00
2014-05-04 20:45:00 +04:00
# define SPEAR_ADC_CHANNEL_NUM 8
2012-04-12 13:05:35 +04:00
2014-05-04 20:45:00 +04:00
# define SPEAR_ADC_CLK_MIN 2500000
# define SPEAR_ADC_CLK_MAX 20000000
2012-04-12 13:05:35 +04:00
struct adc_regs_spear3xx {
u32 status ;
u32 average ;
u32 scan_rate ;
u32 clk ; /* Not avail for 1340 & 1310 */
2014-05-04 20:45:00 +04:00
u32 ch_ctrl [ SPEAR_ADC_CHANNEL_NUM ] ;
u32 ch_data [ SPEAR_ADC_CHANNEL_NUM ] ;
2012-04-12 13:05:35 +04:00
} ;
struct chan_data {
u32 lsb ;
u32 msb ;
} ;
struct adc_regs_spear6xx {
u32 status ;
u32 pad [ 2 ] ;
u32 clk ;
2014-05-04 20:45:00 +04:00
u32 ch_ctrl [ SPEAR_ADC_CHANNEL_NUM ] ;
struct chan_data ch_data [ SPEAR_ADC_CHANNEL_NUM ] ;
2012-04-12 13:05:35 +04:00
u32 scan_rate_lo ;
u32 scan_rate_hi ;
struct chan_data average ;
} ;
2014-05-04 20:45:00 +04:00
struct spear_adc_state {
2012-04-12 13:05:35 +04:00
struct device_node * np ;
struct adc_regs_spear3xx __iomem * adc_base_spear3xx ;
struct adc_regs_spear6xx __iomem * adc_base_spear6xx ;
struct clk * clk ;
struct completion completion ;
u32 current_clk ;
u32 sampling_freq ;
u32 avg_samples ;
u32 vref_external ;
u32 value ;
} ;
/*
* Functions to access some SPEAr ADC register . Abstracted into
* static inline functions , because of different register offsets
* on different SoC variants ( SPEAr300 vs SPEAr600 etc ) .
*/
2014-05-04 20:45:00 +04:00
static void spear_adc_set_status ( struct spear_adc_state * st , u32 val )
2012-04-12 13:05:35 +04:00
{
2014-05-04 20:45:00 +04:00
__raw_writel ( val , & st - > adc_base_spear6xx - > status ) ;
2012-04-12 13:05:35 +04:00
}
2014-05-04 20:45:00 +04:00
static void spear_adc_set_clk ( struct spear_adc_state * st , u32 val )
2012-04-12 13:05:35 +04:00
{
u32 clk_high , clk_low , count ;
2014-05-04 20:45:00 +04:00
u32 apb_clk = clk_get_rate ( st - > clk ) ;
2012-04-12 13:05:35 +04:00
2014-10-08 21:26:15 +04:00
count = DIV_ROUND_UP ( apb_clk , val ) ;
2012-04-12 13:05:35 +04:00
clk_low = count / 2 ;
clk_high = count - clk_low ;
2014-05-04 20:45:00 +04:00
st - > current_clk = apb_clk / count ;
2012-04-12 13:05:35 +04:00
2014-05-04 20:45:00 +04:00
__raw_writel ( SPEAR_ADC_CLK_LOW ( clk_low ) | SPEAR_ADC_CLK_HIGH ( clk_high ) ,
2014-05-04 20:45:00 +04:00
& st - > adc_base_spear6xx - > clk ) ;
2012-04-12 13:05:35 +04:00
}
2014-05-04 20:45:00 +04:00
static void spear_adc_set_ctrl ( struct spear_adc_state * st , int n ,
2012-04-12 13:05:35 +04:00
u32 val )
{
2014-05-04 20:45:00 +04:00
__raw_writel ( val , & st - > adc_base_spear6xx - > ch_ctrl [ n ] ) ;
2012-04-12 13:05:35 +04:00
}
2014-05-04 20:45:00 +04:00
static u32 spear_adc_get_average ( struct spear_adc_state * st )
2012-04-12 13:05:35 +04:00
{
2014-05-04 20:45:00 +04:00
if ( of_device_is_compatible ( st - > np , " st,spear600-adc " ) ) {
return __raw_readl ( & st - > adc_base_spear6xx - > average . msb ) &
2014-05-04 20:45:00 +04:00
SPEAR_ADC_DATA_MASK ;
2012-04-12 13:05:35 +04:00
} else {
2014-05-04 20:45:00 +04:00
return __raw_readl ( & st - > adc_base_spear3xx - > average ) &
2014-05-04 20:45:00 +04:00
SPEAR_ADC_DATA_MASK ;
2012-04-12 13:05:35 +04:00
}
}
2014-05-04 20:45:00 +04:00
static void spear_adc_set_scanrate ( struct spear_adc_state * st , u32 rate )
2012-04-12 13:05:35 +04:00
{
2014-05-04 20:45:00 +04:00
if ( of_device_is_compatible ( st - > np , " st,spear600-adc " ) ) {
2014-05-04 20:45:00 +04:00
__raw_writel ( SPEAR600_ADC_SCAN_RATE_LO ( rate ) ,
2014-05-04 20:45:00 +04:00
& st - > adc_base_spear6xx - > scan_rate_lo ) ;
2014-05-04 20:45:00 +04:00
__raw_writel ( SPEAR600_ADC_SCAN_RATE_HI ( rate ) ,
2014-05-04 20:45:00 +04:00
& st - > adc_base_spear6xx - > scan_rate_hi ) ;
2012-04-12 13:05:35 +04:00
} else {
2014-05-04 20:45:00 +04:00
__raw_writel ( rate , & st - > adc_base_spear3xx - > scan_rate ) ;
2012-04-12 13:05:35 +04:00
}
}
2014-05-04 20:45:00 +04:00
static int spear_adc_read_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
int * val ,
int * val2 ,
long mask )
2012-04-12 13:05:35 +04:00
{
2014-05-04 20:45:00 +04:00
struct spear_adc_state * st = iio_priv ( indio_dev ) ;
2012-04-12 13:05:35 +04:00
u32 status ;
switch ( mask ) {
2012-04-15 20:41:18 +04:00
case IIO_CHAN_INFO_RAW :
2012-04-12 13:05:35 +04:00
mutex_lock ( & indio_dev - > mlock ) ;
2014-05-04 20:45:00 +04:00
status = SPEAR_ADC_STATUS_CHANNEL_NUM ( chan - > channel ) |
2014-05-04 20:45:00 +04:00
SPEAR_ADC_STATUS_AVG_SAMPLE ( st - > avg_samples ) |
2014-05-04 20:45:00 +04:00
SPEAR_ADC_STATUS_START_CONVERSION |
SPEAR_ADC_STATUS_ADC_ENABLE ;
2014-05-04 20:45:00 +04:00
if ( st - > vref_external = = 0 )
2014-05-04 20:45:00 +04:00
status | = SPEAR_ADC_STATUS_VREF_INTERNAL ;
2012-04-12 13:05:35 +04:00
2014-05-04 20:45:00 +04:00
spear_adc_set_status ( st , status ) ;
wait_for_completion ( & st - > completion ) ; /* set by ISR */
* val = st - > value ;
2012-04-12 13:05:35 +04:00
mutex_unlock ( & indio_dev - > mlock ) ;
return IIO_VAL_INT ;
case IIO_CHAN_INFO_SCALE :
2014-05-04 20:45:00 +04:00
* val = st - > vref_external ;
2014-05-04 20:45:00 +04:00
* val2 = SPEAR_ADC_DATA_BITS ;
2013-09-28 13:31:00 +04:00
return IIO_VAL_FRACTIONAL_LOG2 ;
2014-05-04 20:45:00 +04:00
case IIO_CHAN_INFO_SAMP_FREQ :
2014-05-04 20:45:00 +04:00
* val = st - > current_clk ;
2014-05-04 20:45:00 +04:00
return IIO_VAL_INT ;
2012-04-12 13:05:35 +04:00
}
return - EINVAL ;
}
2014-05-04 20:45:00 +04:00
static int spear_adc_write_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
int val ,
int val2 ,
long mask )
{
2014-05-04 20:45:00 +04:00
struct spear_adc_state * st = iio_priv ( indio_dev ) ;
2014-05-04 20:45:00 +04:00
int ret = 0 ;
if ( mask ! = IIO_CHAN_INFO_SAMP_FREQ )
return - EINVAL ;
mutex_lock ( & indio_dev - > mlock ) ;
if ( ( val < SPEAR_ADC_CLK_MIN ) | |
2015-10-14 21:14:13 +03:00
( val > SPEAR_ADC_CLK_MAX ) | |
( val2 ! = 0 ) ) {
2014-05-04 20:45:00 +04:00
ret = - EINVAL ;
goto out ;
}
2014-05-04 20:45:00 +04:00
spear_adc_set_clk ( st , val ) ;
2014-05-04 20:45:00 +04:00
out :
mutex_unlock ( & indio_dev - > mlock ) ;
return ret ;
}
2012-04-12 13:05:35 +04:00
# define SPEAR_ADC_CHAN(idx) { \
. type = IIO_VOLTAGE , \
. indexed = 1 , \
2013-03-05 01:06:04 +04:00
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) , \
. info_mask_shared_by_type = BIT ( IIO_CHAN_INFO_SCALE ) , \
2014-05-04 20:45:00 +04:00
. info_mask_shared_by_all = BIT ( IIO_CHAN_INFO_SAMP_FREQ ) , \
2012-04-12 13:05:35 +04:00
. channel = idx , \
}
2012-08-09 11:51:00 +04:00
static const struct iio_chan_spec spear_adc_iio_channels [ ] = {
2012-04-12 13:05:35 +04:00
SPEAR_ADC_CHAN ( 0 ) ,
SPEAR_ADC_CHAN ( 1 ) ,
SPEAR_ADC_CHAN ( 2 ) ,
SPEAR_ADC_CHAN ( 3 ) ,
SPEAR_ADC_CHAN ( 4 ) ,
SPEAR_ADC_CHAN ( 5 ) ,
SPEAR_ADC_CHAN ( 6 ) ,
SPEAR_ADC_CHAN ( 7 ) ,
} ;
static irqreturn_t spear_adc_isr ( int irq , void * dev_id )
{
2014-10-30 14:32:25 +03:00
struct spear_adc_state * st = dev_id ;
2012-04-12 13:05:35 +04:00
/* Read value to clear IRQ */
2014-05-04 20:45:00 +04:00
st - > value = spear_adc_get_average ( st ) ;
complete ( & st - > completion ) ;
2012-04-12 13:05:35 +04:00
return IRQ_HANDLED ;
}
2014-05-04 20:45:00 +04:00
static int spear_adc_configure ( struct spear_adc_state * st )
2012-04-12 13:05:35 +04:00
{
int i ;
/* Reset ADC core */
2014-05-04 20:45:00 +04:00
spear_adc_set_status ( st , 0 ) ;
__raw_writel ( 0 , & st - > adc_base_spear6xx - > clk ) ;
2012-04-12 13:05:35 +04:00
for ( i = 0 ; i < 8 ; i + + )
2014-05-04 20:45:00 +04:00
spear_adc_set_ctrl ( st , i , 0 ) ;
spear_adc_set_scanrate ( st , 0 ) ;
2012-04-12 13:05:35 +04:00
2014-05-04 20:45:00 +04:00
spear_adc_set_clk ( st , st - > sampling_freq ) ;
2012-04-12 13:05:35 +04:00
return 0 ;
}
2014-05-04 20:45:00 +04:00
static const struct iio_info spear_adc_info = {
2014-05-04 20:45:00 +04:00
. read_raw = & spear_adc_read_raw ,
2014-05-04 20:45:00 +04:00
. write_raw = & spear_adc_write_raw ,
2012-04-12 13:05:35 +04:00
. driver_module = THIS_MODULE ,
} ;
2012-11-19 22:21:57 +04:00
static int spear_adc_probe ( struct platform_device * pdev )
2012-04-12 13:05:35 +04:00
{
struct device_node * np = pdev - > dev . of_node ;
struct device * dev = & pdev - > dev ;
2014-05-04 20:45:00 +04:00
struct spear_adc_state * st ;
2016-02-29 10:33:46 +03:00
struct resource * res ;
2014-05-04 20:45:00 +04:00
struct iio_dev * indio_dev = NULL ;
2012-04-12 13:05:35 +04:00
int ret = - ENODEV ;
int irq ;
2014-05-04 20:45:00 +04:00
indio_dev = devm_iio_device_alloc ( dev , sizeof ( struct spear_adc_state ) ) ;
if ( ! indio_dev ) {
2012-04-12 13:05:35 +04:00
dev_err ( dev , " failed allocating iio device \n " ) ;
2013-07-22 15:02:00 +04:00
return - ENOMEM ;
2012-04-12 13:05:35 +04:00
}
2014-05-04 20:45:00 +04:00
st = iio_priv ( indio_dev ) ;
2014-05-04 20:45:00 +04:00
st - > np = np ;
2012-04-12 13:05:35 +04:00
/*
* SPEAr600 has a different register layout than other SPEAr SoC ' s
* ( e . g . SPEAr3xx ) . Let ' s provide two register base addresses
* to support multi - arch kernels .
*/
2016-02-29 10:33:46 +03:00
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
st - > adc_base_spear6xx = devm_ioremap_resource ( & pdev - > dev , res ) ;
if ( IS_ERR ( st - > adc_base_spear6xx ) )
return PTR_ERR ( st - > adc_base_spear6xx ) ;
2014-05-04 20:45:00 +04:00
st - > adc_base_spear3xx =
( struct adc_regs_spear3xx __iomem * ) st - > adc_base_spear6xx ;
2012-04-12 13:05:35 +04:00
2016-02-02 15:56:32 +03:00
st - > clk = devm_clk_get ( dev , NULL ) ;
2014-05-04 20:45:00 +04:00
if ( IS_ERR ( st - > clk ) ) {
2012-04-12 13:05:35 +04:00
dev_err ( dev , " failed getting clock \n " ) ;
2016-02-29 10:33:46 +03:00
return PTR_ERR ( st - > clk ) ;
2012-04-12 13:05:35 +04:00
}
2014-05-04 20:45:00 +04:00
ret = clk_prepare_enable ( st - > clk ) ;
2012-04-12 13:05:35 +04:00
if ( ret ) {
dev_err ( dev , " failed enabling clock \n " ) ;
2016-02-29 10:33:46 +03:00
return ret ;
2012-04-12 13:05:35 +04:00
}
irq = platform_get_irq ( pdev , 0 ) ;
2013-10-17 00:45:00 +04:00
if ( irq < = 0 ) {
2012-04-12 13:05:35 +04:00
dev_err ( dev , " failed getting interrupt resource \n " ) ;
ret = - EINVAL ;
2016-02-02 15:56:32 +03:00
goto errout2 ;
2012-04-12 13:05:35 +04:00
}
2014-05-04 20:45:00 +04:00
ret = devm_request_irq ( dev , irq , spear_adc_isr , 0 , SPEAR_ADC_MOD_NAME ,
2014-05-04 20:45:00 +04:00
st ) ;
2012-04-12 13:05:35 +04:00
if ( ret < 0 ) {
dev_err ( dev , " failed requesting interrupt \n " ) ;
2016-02-02 15:56:32 +03:00
goto errout2 ;
2012-04-12 13:05:35 +04:00
}
if ( of_property_read_u32 ( np , " sampling-frequency " ,
2014-05-04 20:45:00 +04:00
& st - > sampling_freq ) ) {
2012-04-12 13:05:35 +04:00
dev_err ( dev , " sampling-frequency missing in DT \n " ) ;
ret = - EINVAL ;
2016-02-02 15:56:32 +03:00
goto errout2 ;
2012-04-12 13:05:35 +04:00
}
/*
* Optional avg_samples defaults to 0 , resulting in single data
* conversion
*/
2014-05-04 20:45:00 +04:00
of_property_read_u32 ( np , " average-samples " , & st - > avg_samples ) ;
2012-04-12 13:05:35 +04:00
/*
* Optional vref_external defaults to 0 , resulting in internal vref
* selection
*/
2014-05-04 20:45:00 +04:00
of_property_read_u32 ( np , " vref-external " , & st - > vref_external ) ;
2012-04-12 13:05:35 +04:00
2014-05-04 20:45:00 +04:00
spear_adc_configure ( st ) ;
2012-04-12 13:05:35 +04:00
2014-05-04 20:45:00 +04:00
platform_set_drvdata ( pdev , indio_dev ) ;
2012-04-12 13:05:35 +04:00
2014-05-04 20:45:00 +04:00
init_completion ( & st - > completion ) ;
2012-04-12 13:05:35 +04:00
2014-05-04 20:45:00 +04:00
indio_dev - > name = SPEAR_ADC_MOD_NAME ;
indio_dev - > dev . parent = dev ;
indio_dev - > info = & spear_adc_info ;
indio_dev - > modes = INDIO_DIRECT_MODE ;
indio_dev - > channels = spear_adc_iio_channels ;
indio_dev - > num_channels = ARRAY_SIZE ( spear_adc_iio_channels ) ;
2012-04-12 13:05:35 +04:00
2014-05-04 20:45:00 +04:00
ret = iio_device_register ( indio_dev ) ;
2012-04-12 13:05:35 +04:00
if ( ret )
2016-02-02 15:56:32 +03:00
goto errout2 ;
2012-04-12 13:05:35 +04:00
dev_info ( dev , " SPEAR ADC driver loaded, IRQ %d \n " , irq ) ;
return 0 ;
errout2 :
2016-02-02 15:56:32 +03:00
clk_disable_unprepare ( st - > clk ) ;
2012-04-12 13:05:35 +04:00
return ret ;
}
2012-11-19 22:26:37 +04:00
static int spear_adc_remove ( struct platform_device * pdev )
2012-04-12 13:05:35 +04:00
{
2014-05-04 20:45:00 +04:00
struct iio_dev * indio_dev = platform_get_drvdata ( pdev ) ;
struct spear_adc_state * st = iio_priv ( indio_dev ) ;
2012-04-12 13:05:35 +04:00
2014-05-04 20:45:00 +04:00
iio_device_unregister ( indio_dev ) ;
2014-05-04 20:45:00 +04:00
clk_disable_unprepare ( st - > clk ) ;
2012-04-12 13:05:35 +04:00
return 0 ;
}
2013-06-07 15:06:00 +04:00
# ifdef CONFIG_OF
2012-04-12 13:05:35 +04:00
static const struct of_device_id spear_adc_dt_ids [ ] = {
{ . compatible = " st,spear600-adc " , } ,
{ /* sentinel */ }
} ;
MODULE_DEVICE_TABLE ( of , spear_adc_dt_ids ) ;
2013-06-07 15:06:00 +04:00
# endif
2012-04-12 13:05:35 +04:00
static struct platform_driver spear_adc_driver = {
. probe = spear_adc_probe ,
2012-11-19 22:21:38 +04:00
. remove = spear_adc_remove ,
2012-04-12 13:05:35 +04:00
. driver = {
2014-05-04 20:45:00 +04:00
. name = SPEAR_ADC_MOD_NAME ,
2012-04-12 13:05:35 +04:00
. of_match_table = of_match_ptr ( spear_adc_dt_ids ) ,
} ,
} ;
module_platform_driver ( spear_adc_driver ) ;
MODULE_AUTHOR ( " Stefan Roese <sr@denx.de> " ) ;
MODULE_DESCRIPTION ( " SPEAr ADC driver " ) ;
MODULE_LICENSE ( " GPL " ) ;