2012-10-16 12:55:45 +05:30
/*
* TI ADC MFD driver
*
* Copyright ( C ) 2012 Texas Instruments Incorporated - http : //www.ti.com/
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
*
* This program is distributed " as is " WITHOUT ANY WARRANTY of any
* kind , whether express or implied ; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*/
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/err.h>
# include <linux/module.h>
# include <linux/slab.h>
# include <linux/interrupt.h>
# include <linux/platform_device.h>
# include <linux/io.h>
# include <linux/iio/iio.h>
2013-01-24 03:45:11 +00:00
# include <linux/of.h>
# include <linux/of_device.h>
2012-10-13 16:37:24 +03:00
# include <linux/iio/machine.h>
# include <linux/iio/driver.h>
2012-10-16 12:55:45 +05:30
# include <linux/mfd/ti_am335x_tscadc.h>
struct tiadc_device {
struct ti_tscadc_dev * mfd_tscadc ;
int channels ;
2013-05-29 17:39:02 +02:00
u8 channel_line [ 8 ] ;
u8 channel_step [ 8 ] ;
2012-10-16 12:55:45 +05:30
} ;
static unsigned int tiadc_readl ( struct tiadc_device * adc , unsigned int reg )
{
return readl ( adc - > mfd_tscadc - > tscadc_base + reg ) ;
}
static void tiadc_writel ( struct tiadc_device * adc , unsigned int reg ,
unsigned int val )
{
writel ( val , adc - > mfd_tscadc - > tscadc_base + reg ) ;
}
2013-01-24 03:45:05 +00:00
static u32 get_adc_step_mask ( struct tiadc_device * adc_dev )
{
u32 step_en ;
step_en = ( ( 1 < < adc_dev - > channels ) - 1 ) ;
step_en < < = TOTAL_STEPS - adc_dev - > channels + 1 ;
return step_en ;
}
2012-10-16 12:55:45 +05:30
static void tiadc_step_config ( struct tiadc_device * adc_dev )
{
unsigned int stepconfig ;
2013-05-29 17:39:02 +02:00
int i , steps ;
2012-10-16 12:55:45 +05:30
/*
* There are 16 configurable steps and 8 analog input
* lines available which are shared between Touchscreen and ADC .
*
* Steps backwards i . e . from 16 towards 0 are used by ADC
* depending on number of input lines needed .
* Channel would represent which analog input
* needs to be given to ADC to digitalize data .
*/
steps = TOTAL_STEPS - adc_dev - > channels ;
stepconfig = STEPCONFIG_AVG_16 | STEPCONFIG_FIFO1 ;
2013-05-29 17:39:02 +02:00
for ( i = 0 ; i < adc_dev - > channels ; i + + ) {
int chan ;
chan = adc_dev - > channel_line [ i ] ;
tiadc_writel ( adc_dev , REG_STEPCONFIG ( steps ) ,
stepconfig | STEPCONFIG_INP ( chan ) ) ;
tiadc_writel ( adc_dev , REG_STEPDELAY ( steps ) ,
2012-10-16 12:55:45 +05:30
STEPCONFIG_OPENDLY ) ;
2013-05-29 17:39:02 +02:00
adc_dev - > channel_step [ i ] = steps ;
steps + + ;
2012-10-16 12:55:45 +05:30
}
2013-07-20 17:27:00 +01:00
2012-10-16 12:55:45 +05:30
}
2012-10-13 16:37:24 +03:00
static const char * const chan_name_ain [ ] = {
" AIN0 " ,
" AIN1 " ,
" AIN2 " ,
" AIN3 " ,
" AIN4 " ,
" AIN5 " ,
" AIN6 " ,
" AIN7 " ,
} ;
2012-10-16 12:55:45 +05:30
static int tiadc_channel_init ( struct iio_dev * indio_dev , int channels )
{
2012-10-13 16:37:24 +03:00
struct tiadc_device * adc_dev = iio_priv ( indio_dev ) ;
2012-10-16 12:55:45 +05:30
struct iio_chan_spec * chan_array ;
2012-10-13 16:37:24 +03:00
struct iio_chan_spec * chan ;
2012-10-16 12:55:45 +05:30
int i ;
indio_dev - > num_channels = channels ;
2012-10-13 16:37:24 +03:00
chan_array = kcalloc ( channels ,
2012-10-16 12:55:45 +05:30
sizeof ( struct iio_chan_spec ) , GFP_KERNEL ) ;
if ( chan_array = = NULL )
return - ENOMEM ;
2012-10-13 16:37:24 +03:00
chan = chan_array ;
for ( i = 0 ; i < channels ; i + + , chan + + ) {
2012-10-16 12:55:45 +05:30
chan - > type = IIO_VOLTAGE ;
chan - > indexed = 1 ;
2013-05-29 17:39:02 +02:00
chan - > channel = adc_dev - > channel_line [ i ] ;
2013-02-27 19:07:18 +00:00
chan - > info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) ;
2013-05-29 17:39:02 +02:00
chan - > datasheet_name = chan_name_ain [ chan - > channel ] ;
2012-10-13 16:37:24 +03:00
chan - > scan_type . sign = ' u ' ;
chan - > scan_type . realbits = 12 ;
chan - > scan_type . storagebits = 32 ;
2012-10-16 12:55:45 +05:30
}
indio_dev - > channels = chan_array ;
2012-10-13 16:37:24 +03:00
return 0 ;
2012-10-16 12:55:45 +05:30
}
static void tiadc_channels_remove ( struct iio_dev * indio_dev )
{
kfree ( indio_dev - > channels ) ;
}
static int tiadc_read_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
int * val , int * val2 , long mask )
{
struct tiadc_device * adc_dev = iio_priv ( indio_dev ) ;
2013-07-20 17:27:00 +01:00
int i , map_val ;
unsigned int fifo1count , read , stepid ;
2013-05-29 17:39:02 +02:00
u32 step = UINT_MAX ;
2013-05-29 18:49:55 +02:00
bool found = false ;
2013-07-20 17:27:00 +01:00
u32 step_en ;
unsigned long timeout = jiffies + usecs_to_jiffies
( IDLE_TIMEOUT * adc_dev - > channels ) ;
step_en = get_adc_step_mask ( adc_dev ) ;
am335x_tsc_se_set ( adc_dev - > mfd_tscadc , step_en ) ;
/* Wait for ADC sequencer to complete sampling */
while ( tiadc_readl ( adc_dev , REG_ADCFSM ) & SEQ_STATUS ) {
if ( time_after ( jiffies , timeout ) )
return - EAGAIN ;
}
map_val = chan - > channel + TOTAL_CHANNELS ;
2012-10-16 12:55:45 +05:30
/*
* When the sub - system is first enabled ,
* the sequencer will always start with the
* lowest step ( 1 ) and continue until step ( 16 ) .
* For ex : If we have enabled 4 ADC channels and
* currently use only 1 out of them , the
* sequencer still configures all the 4 steps ,
* leading to 3 unwanted data .
* Hence we need to flush out this data .
*/
2013-05-29 17:39:02 +02:00
for ( i = 0 ; i < ARRAY_SIZE ( adc_dev - > channel_step ) ; i + + ) {
if ( chan - > channel = = adc_dev - > channel_line [ i ] ) {
step = adc_dev - > channel_step [ i ] ;
break ;
}
}
if ( WARN_ON_ONCE ( step = = UINT_MAX ) )
return - EINVAL ;
2012-10-16 12:55:45 +05:30
fifo1count = tiadc_readl ( adc_dev , REG_FIFO1CNT ) ;
for ( i = 0 ; i < fifo1count ; i + + ) {
2013-05-29 17:39:02 +02:00
read = tiadc_readl ( adc_dev , REG_FIFO1 ) ;
2013-07-20 17:27:00 +01:00
stepid = read & FIFOREAD_CHNLID_MASK ;
stepid = stepid > > 0x10 ;
if ( stepid = = map_val ) {
read = read & FIFOREAD_DATA_MASK ;
2013-05-29 18:49:55 +02:00
found = true ;
2013-07-20 17:27:00 +01:00
* val = read ;
2013-05-29 18:49:55 +02:00
}
2012-10-16 12:55:45 +05:30
}
2013-07-20 17:27:00 +01:00
2013-05-29 18:49:55 +02:00
if ( found = = false )
return - EBUSY ;
2012-10-16 12:55:45 +05:30
return IIO_VAL_INT ;
}
static const struct iio_info tiadc_info = {
. read_raw = & tiadc_read_raw ,
2013-07-06 05:20:00 +01:00
. driver_module = THIS_MODULE ,
2012-10-16 12:55:45 +05:30
} ;
2012-12-21 13:21:43 -08:00
static int tiadc_probe ( struct platform_device * pdev )
2012-10-16 12:55:45 +05:30
{
struct iio_dev * indio_dev ;
struct tiadc_device * adc_dev ;
2013-01-24 03:45:11 +00:00
struct device_node * node = pdev - > dev . of_node ;
2013-05-29 17:39:02 +02:00
struct property * prop ;
const __be32 * cur ;
2012-10-16 12:55:45 +05:30
int err ;
2013-05-29 17:39:02 +02:00
u32 val ;
int channels = 0 ;
2012-10-16 12:55:45 +05:30
2013-05-21 17:49:22 +02:00
if ( ! node ) {
dev_err ( & pdev - > dev , " Could not find valid DT data. \n " ) ;
2012-10-16 12:55:45 +05:30
return - EINVAL ;
}
2013-07-23 09:46:00 +01:00
indio_dev = devm_iio_device_alloc ( & pdev - > dev ,
sizeof ( struct tiadc_device ) ) ;
2012-10-16 12:55:45 +05:30
if ( indio_dev = = NULL ) {
dev_err ( & pdev - > dev , " failed to allocate iio device \n " ) ;
2013-07-23 09:46:00 +01:00
return - ENOMEM ;
2012-10-16 12:55:45 +05:30
}
adc_dev = iio_priv ( indio_dev ) ;
2013-01-24 03:45:11 +00:00
adc_dev - > mfd_tscadc = ti_tscadc_dev_get ( pdev ) ;
2013-05-29 17:39:02 +02:00
of_property_for_each_u32 ( node , " ti,adc-channels " , prop , cur , val ) {
adc_dev - > channel_line [ channels ] = val ;
channels + + ;
}
adc_dev - > channels = channels ;
2012-10-16 12:55:45 +05:30
indio_dev - > dev . parent = & pdev - > dev ;
indio_dev - > name = dev_name ( & pdev - > dev ) ;
indio_dev - > modes = INDIO_DIRECT_MODE ;
indio_dev - > info = & tiadc_info ;
tiadc_step_config ( adc_dev ) ;
err = tiadc_channel_init ( indio_dev , adc_dev - > channels ) ;
if ( err < 0 )
2013-07-23 09:46:00 +01:00
return err ;
2012-10-16 12:55:45 +05:30
err = iio_device_register ( indio_dev ) ;
if ( err )
goto err_free_channels ;
platform_set_drvdata ( pdev , indio_dev ) ;
return 0 ;
err_free_channels :
tiadc_channels_remove ( indio_dev ) ;
return err ;
}
2012-12-21 13:21:43 -08:00
static int tiadc_remove ( struct platform_device * pdev )
2012-10-16 12:55:45 +05:30
{
struct iio_dev * indio_dev = platform_get_drvdata ( pdev ) ;
2013-01-24 03:45:05 +00:00
struct tiadc_device * adc_dev = iio_priv ( indio_dev ) ;
u32 step_en ;
2012-10-16 12:55:45 +05:30
iio_device_unregister ( indio_dev ) ;
tiadc_channels_remove ( indio_dev ) ;
2013-01-24 03:45:05 +00:00
step_en = get_adc_step_mask ( adc_dev ) ;
am335x_tsc_se_clr ( adc_dev - > mfd_tscadc , step_en ) ;
2012-10-16 12:55:45 +05:30
return 0 ;
}
# ifdef CONFIG_PM
static int tiadc_suspend ( struct device * dev )
{
struct iio_dev * indio_dev = dev_get_drvdata ( dev ) ;
struct tiadc_device * adc_dev = iio_priv ( indio_dev ) ;
2013-06-05 16:13:47 +02:00
struct ti_tscadc_dev * tscadc_dev ;
2012-10-16 12:55:45 +05:30
unsigned int idle ;
2013-06-05 16:13:47 +02:00
tscadc_dev = ti_tscadc_dev_get ( to_platform_device ( dev ) ) ;
2012-10-16 12:55:45 +05:30
if ( ! device_may_wakeup ( tscadc_dev - > dev ) ) {
idle = tiadc_readl ( adc_dev , REG_CTRL ) ;
idle & = ~ ( CNTRLREG_TSCSSENB ) ;
tiadc_writel ( adc_dev , REG_CTRL , ( idle |
CNTRLREG_POWERDOWN ) ) ;
}
return 0 ;
}
static int tiadc_resume ( struct device * dev )
{
struct iio_dev * indio_dev = dev_get_drvdata ( dev ) ;
struct tiadc_device * adc_dev = iio_priv ( indio_dev ) ;
unsigned int restore ;
/* Make sure ADC is powered up */
restore = tiadc_readl ( adc_dev , REG_CTRL ) ;
restore & = ~ ( CNTRLREG_POWERDOWN ) ;
tiadc_writel ( adc_dev , REG_CTRL , restore ) ;
tiadc_step_config ( adc_dev ) ;
return 0 ;
}
static const struct dev_pm_ops tiadc_pm_ops = {
. suspend = tiadc_suspend ,
. resume = tiadc_resume ,
} ;
# define TIADC_PM_OPS (&tiadc_pm_ops)
# else
# define TIADC_PM_OPS NULL
# endif
2013-01-24 03:45:11 +00:00
static const struct of_device_id ti_adc_dt_ids [ ] = {
{ . compatible = " ti,am3359-adc " , } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , ti_adc_dt_ids ) ;
2012-10-16 12:55:45 +05:30
static struct platform_driver tiadc_driver = {
. driver = {
2013-05-27 17:12:52 +02:00
. name = " TI-am335x-adc " ,
2012-10-16 12:55:45 +05:30
. owner = THIS_MODULE ,
. pm = TIADC_PM_OPS ,
2013-01-24 03:45:11 +00:00
. of_match_table = of_match_ptr ( ti_adc_dt_ids ) ,
2012-10-16 12:55:45 +05:30
} ,
. probe = tiadc_probe ,
2012-12-21 13:21:43 -08:00
. remove = tiadc_remove ,
2012-10-16 12:55:45 +05:30
} ;
module_platform_driver ( tiadc_driver ) ;
MODULE_DESCRIPTION ( " TI ADC controller driver " ) ;
MODULE_AUTHOR ( " Rachna Patil <rachna@ti.com> " ) ;
MODULE_LICENSE ( " GPL " ) ;