2021-10-15 10:14:27 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2012-10-16 12:55:43 +05:30
/*
* TI Touch Screen / ADC MFD driver
*
2020-07-22 21:24:54 +02:00
* Copyright ( C ) 2012 Texas Instruments Incorporated - https : //www.ti.com/
2012-10-16 12:55:43 +05:30
*/
# include <linux/module.h>
# include <linux/slab.h>
# include <linux/err.h>
# include <linux/io.h>
# include <linux/clk.h>
# include <linux/regmap.h>
# include <linux/mfd/core.h>
# include <linux/pm_runtime.h>
2013-01-24 03:45:09 +00:00
# include <linux/of.h>
# include <linux/of_device.h>
2013-12-19 16:28:31 +01:00
# include <linux/sched.h>
2012-10-16 12:55:43 +05:30
# include <linux/mfd/ti_am335x_tscadc.h>
static const struct regmap_config tscadc_regmap_config = {
. name = " ti_tscadc " ,
. reg_bits = 32 ,
. reg_stride = 4 ,
. val_bits = 32 ,
} ;
2016-06-08 10:54:34 -05:00
void am335x_tsc_se_set_cache ( struct ti_tscadc_dev * tscadc , u32 val )
2013-01-24 03:45:05 +00:00
{
2013-10-22 16:12:39 +02:00
unsigned long flags ;
2016-06-08 10:54:34 -05:00
spin_lock_irqsave ( & tscadc - > reg_lock , flags ) ;
tscadc - > reg_se_cache | = val ;
if ( tscadc - > adc_waiting )
wake_up ( & tscadc - > reg_se_wait ) ;
else if ( ! tscadc - > adc_in_use )
2016-06-08 10:54:35 -05:00
regmap_write ( tscadc - > regmap , REG_SE , tscadc - > reg_se_cache ) ;
2013-12-19 16:28:31 +01:00
2016-06-08 10:54:34 -05:00
spin_unlock_irqrestore ( & tscadc - > reg_lock , flags ) ;
2013-01-24 03:45:05 +00:00
}
2013-12-19 16:28:29 +01:00
EXPORT_SYMBOL_GPL ( am335x_tsc_se_set_cache ) ;
2016-06-08 10:54:34 -05:00
static void am335x_tscadc_need_adc ( struct ti_tscadc_dev * tscadc )
2013-12-19 16:28:31 +01:00
{
DEFINE_WAIT ( wait ) ;
u32 reg ;
2016-06-08 10:54:35 -05:00
regmap_read ( tscadc - > regmap , REG_ADCFSM , & reg ) ;
2013-12-19 16:28:31 +01:00
if ( reg & SEQ_STATUS ) {
2016-06-08 10:54:34 -05:00
tscadc - > adc_waiting = true ;
prepare_to_wait ( & tscadc - > reg_se_wait , & wait ,
2013-12-19 16:28:31 +01:00
TASK_UNINTERRUPTIBLE ) ;
2016-06-08 10:54:34 -05:00
spin_unlock_irq ( & tscadc - > reg_lock ) ;
2013-12-19 16:28:31 +01:00
schedule ( ) ;
2016-06-08 10:54:34 -05:00
spin_lock_irq ( & tscadc - > reg_lock ) ;
finish_wait ( & tscadc - > reg_se_wait , & wait ) ;
2013-12-19 16:28:31 +01:00
2015-01-07 11:19:36 +05:30
/*
* Sequencer should either be idle or
* busy applying the charge step .
*/
2016-06-08 10:54:35 -05:00
regmap_read ( tscadc - > regmap , REG_ADCFSM , & reg ) ;
2015-01-07 11:19:36 +05:30
WARN_ON ( ( reg & SEQ_STATUS ) & & ! ( reg & CHARGE_STEP ) ) ;
2016-06-08 10:54:34 -05:00
tscadc - > adc_waiting = false ;
2013-12-19 16:28:31 +01:00
}
2016-06-08 10:54:34 -05:00
tscadc - > adc_in_use = true ;
2013-12-19 16:28:31 +01:00
}
2016-06-08 10:54:34 -05:00
void am335x_tsc_se_set_once ( struct ti_tscadc_dev * tscadc , u32 val )
2013-12-19 16:28:31 +01:00
{
2016-06-08 10:54:34 -05:00
spin_lock_irq ( & tscadc - > reg_lock ) ;
am335x_tscadc_need_adc ( tscadc ) ;
2013-12-19 16:28:31 +01:00
2016-06-08 10:54:35 -05:00
regmap_write ( tscadc - > regmap , REG_SE , val ) ;
2016-06-08 10:54:34 -05:00
spin_unlock_irq ( & tscadc - > reg_lock ) ;
2013-12-19 16:28:31 +01:00
}
EXPORT_SYMBOL_GPL ( am335x_tsc_se_set_once ) ;
2016-06-08 10:54:34 -05:00
void am335x_tsc_se_adc_done ( struct ti_tscadc_dev * tscadc )
2013-12-19 16:28:29 +01:00
{
unsigned long flags ;
2016-06-08 10:54:34 -05:00
spin_lock_irqsave ( & tscadc - > reg_lock , flags ) ;
tscadc - > adc_in_use = false ;
2016-06-08 10:54:35 -05:00
regmap_write ( tscadc - > regmap , REG_SE , tscadc - > reg_se_cache ) ;
2016-06-08 10:54:34 -05:00
spin_unlock_irqrestore ( & tscadc - > reg_lock , flags ) ;
2013-12-19 16:28:29 +01:00
}
2013-12-19 16:28:31 +01:00
EXPORT_SYMBOL_GPL ( am335x_tsc_se_adc_done ) ;
2013-01-24 03:45:05 +00:00
2016-06-08 10:54:34 -05:00
void am335x_tsc_se_clr ( struct ti_tscadc_dev * tscadc , u32 val )
2013-01-24 03:45:05 +00:00
{
2013-10-22 16:12:39 +02:00
unsigned long flags ;
2016-06-08 10:54:34 -05:00
spin_lock_irqsave ( & tscadc - > reg_lock , flags ) ;
tscadc - > reg_se_cache & = ~ val ;
2016-06-08 10:54:35 -05:00
regmap_write ( tscadc - > regmap , REG_SE , tscadc - > reg_se_cache ) ;
2016-06-08 10:54:34 -05:00
spin_unlock_irqrestore ( & tscadc - > reg_lock , flags ) ;
2013-01-24 03:45:05 +00:00
}
EXPORT_SYMBOL_GPL ( am335x_tsc_se_clr ) ;
2016-06-08 10:54:34 -05:00
static void tscadc_idle_config ( struct ti_tscadc_dev * tscadc )
2012-10-16 12:55:43 +05:30
{
unsigned int idleconfig ;
2021-10-15 10:14:53 +02:00
idleconfig = STEPCONFIG_INM_ADCREFM | STEPCONFIG_INP_ADCREFM ;
if ( ti_adc_with_touchscreen ( tscadc ) )
idleconfig | = STEPCONFIG_YNN | STEPCONFIG_YPN ;
2012-10-16 12:55:43 +05:30
2016-06-08 10:54:35 -05:00
regmap_write ( tscadc - > regmap , REG_IDLECONFIG , idleconfig ) ;
2012-10-16 12:55:43 +05:30
}
2012-12-21 15:03:15 -08:00
static int ti_tscadc_probe ( struct platform_device * pdev )
2012-10-16 12:55:43 +05:30
{
2021-10-15 10:14:29 +02:00
struct ti_tscadc_dev * tscadc ;
struct resource * res ;
struct clk * clk ;
struct device_node * node ;
struct mfd_cell * cell ;
struct property * prop ;
const __be32 * cur ;
2021-10-15 10:14:54 +02:00
bool use_tsc = false , use_mag = false ;
2021-10-15 10:14:29 +02:00
u32 val ;
2021-10-15 10:14:40 +02:00
int err ;
2021-10-15 10:14:50 +02:00
int tscmag_wires = 0 , adc_channels = 0 , cell_idx = 0 , total_channels ;
2021-10-15 10:14:54 +02:00
int readouts = 0 , mag_tracks = 0 ;
2012-10-16 12:55:43 +05:30
2021-10-15 10:14:34 +02:00
/* Allocate memory for device */
tscadc = devm_kzalloc ( & pdev - > dev , sizeof ( * tscadc ) , GFP_KERNEL ) ;
if ( ! tscadc )
return - ENOMEM ;
tscadc - > dev = & pdev - > dev ;
2013-05-21 17:56:49 +02:00
if ( ! pdev - > dev . of_node ) {
dev_err ( & pdev - > dev , " Could not find valid DT data. \n " ) ;
2012-10-16 12:55:43 +05:30
return - EINVAL ;
}
2021-10-15 10:14:35 +02:00
tscadc - > data = of_device_get_match_data ( & pdev - > dev ) ;
2021-10-15 10:14:53 +02:00
if ( ti_adc_with_touchscreen ( tscadc ) ) {
node = of_get_child_by_name ( pdev - > dev . of_node , " tsc " ) ;
of_property_read_u32 ( node , " ti,wires " , & tscmag_wires ) ;
2021-10-15 10:14:55 +02:00
err = of_property_read_u32 ( node , " ti,coordinate-readouts " ,
& readouts ) ;
if ( err < 0 )
of_property_read_u32 ( node , " ti,coordiante-readouts " ,
& readouts ) ;
2021-10-15 10:14:53 +02:00
of_node_put ( node ) ;
2021-10-15 10:14:55 +02:00
2021-10-15 10:14:53 +02:00
if ( tscmag_wires )
use_tsc = true ;
2021-10-15 10:14:54 +02:00
} else {
/*
* When adding support for the magnetic stripe reader , here is
* the place to look for the number of tracks used from device
* tree . Let ' s default to 0 for now .
*/
mag_tracks = 0 ;
tscmag_wires = mag_tracks * 2 ;
if ( tscmag_wires )
use_mag = true ;
2021-10-15 10:14:53 +02:00
}
2013-01-24 03:45:09 +00:00
2013-05-21 17:56:49 +02:00
node = of_get_child_by_name ( pdev - > dev . of_node , " adc " ) ;
2013-05-29 17:39:02 +02:00
of_property_for_each_u32 ( node , " ti,adc-channels " , prop , cur , val ) {
adc_channels + + ;
if ( val > 7 ) {
dev_err ( & pdev - > dev , " PIN numbers are 0..7 (not %d) \n " ,
2021-10-15 10:14:28 +02:00
val ) ;
2021-10-15 10:14:26 +02:00
of_node_put ( node ) ;
2013-05-29 17:39:02 +02:00
return - EINVAL ;
}
}
2021-10-15 10:14:26 +02:00
of_node_put ( node ) ;
2021-10-15 10:14:50 +02:00
total_channels = tscmag_wires + adc_channels ;
2012-10-16 12:55:45 +05:30
if ( total_channels > 8 ) {
dev_err ( & pdev - > dev , " Number of i/p channels more than 8 \n " ) ;
return - EINVAL ;
}
2021-10-15 10:14:28 +02:00
2012-10-13 16:37:24 +03:00
if ( total_channels = = 0 ) {
2021-08-26 13:32:50 +01:00
dev_err ( & pdev - > dev , " Need at least one channel. \n " ) ;
2012-10-13 16:37:24 +03:00
return - EINVAL ;
}
2012-10-16 12:55:44 +05:30
2021-10-15 10:14:52 +02:00
if ( use_tsc & & ( readouts * 2 + 2 + adc_channels > 16 ) ) {
2013-05-29 17:39:02 +02:00
dev_err ( & pdev - > dev , " Too many step configurations requested \n " ) ;
return - EINVAL ;
}
2012-11-06 13:39:03 +05:30
err = platform_get_irq ( pdev , 0 ) ;
2021-08-11 20:19:34 +08:00
if ( err < 0 )
2021-10-15 10:14:30 +02:00
return err ;
2021-08-11 20:19:34 +08:00
else
2012-11-06 13:39:03 +05:30
tscadc - > irq = err ;
2012-10-16 12:55:43 +05:30
2014-02-12 14:31:49 +09:00
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
tscadc - > tscadc_base = devm_ioremap_resource ( & pdev - > dev , res ) ;
if ( IS_ERR ( tscadc - > tscadc_base ) )
return PTR_ERR ( tscadc - > tscadc_base ) ;
2012-10-16 12:55:43 +05:30
2019-11-09 10:36:18 +05:30
tscadc - > tscadc_phys_base = res - > start ;
2016-06-08 10:54:35 -05:00
tscadc - > regmap = devm_regmap_init_mmio ( & pdev - > dev ,
2021-10-15 10:14:28 +02:00
tscadc - > tscadc_base ,
& tscadc_regmap_config ) ;
2016-06-08 10:54:35 -05:00
if ( IS_ERR ( tscadc - > regmap ) ) {
2012-10-16 12:55:43 +05:30
dev_err ( & pdev - > dev , " regmap init failed \n " ) ;
2021-10-15 10:14:30 +02:00
return PTR_ERR ( tscadc - > regmap ) ;
2012-10-16 12:55:43 +05:30
}
2013-01-24 03:45:05 +00:00
spin_lock_init ( & tscadc - > reg_lock ) ;
2013-12-19 16:28:31 +01:00
init_waitqueue_head ( & tscadc - > reg_se_wait ) ;
2012-10-16 12:55:43 +05:30
pm_runtime_enable ( & pdev - > dev ) ;
pm_runtime_get_sync ( & pdev - > dev ) ;
/*
2021-10-15 10:14:31 +02:00
* The TSC_ADC_Subsystem has 2 clock domains : OCP_CLK and ADC_CLK .
* ADCs produce a 12 - bit sample every 15 ADC_CLK cycles .
* am33xx ADCs expect to capture 200 ksps .
2021-10-15 10:14:54 +02:00
* am47xx ADCs expect to capture 867 ksps .
* We need ADC clocks respectively running at 3 MHz and 13 MHz .
* These frequencies are valid since TSC_ADC_SS controller design
2021-10-15 10:14:31 +02:00
* assumes the OCP clock is at least 6 x faster than the ADC clock .
2012-10-16 12:55:43 +05:30
*/
2021-10-15 10:14:32 +02:00
clk = devm_clk_get ( & pdev - > dev , NULL ) ;
2012-10-16 12:55:43 +05:30
if ( IS_ERR ( clk ) ) {
2021-10-15 10:14:51 +02:00
dev_err ( & pdev - > dev , " failed to get fck \n " ) ;
2012-10-16 12:55:43 +05:30
err = PTR_ERR ( clk ) ;
goto err_disable_clk ;
}
2013-07-20 17:27:35 +01:00
2021-10-15 10:14:35 +02:00
tscadc - > clk_div = ( clk_get_rate ( clk ) / tscadc - > data - > target_clk_rate ) - 1 ;
2016-06-08 10:54:35 -05:00
regmap_write ( tscadc - > regmap , REG_CLKDIV , tscadc - > clk_div ) ;
2012-10-16 12:55:43 +05:30
2021-10-15 10:14:40 +02:00
/*
* Set the control register bits . tscadc - > ctrl stores the configuration
* of the CTRL register but not the subsystem enable bit which must be
* added manually when timely .
*/
2021-10-15 10:14:53 +02:00
tscadc - > ctrl = CNTRLREG_STEPID ;
if ( ti_adc_with_touchscreen ( tscadc ) ) {
tscadc - > ctrl | = CNTRLREG_TSC_STEPCONFIGWRT ;
if ( use_tsc ) {
tscadc - > ctrl | = CNTRLREG_TSC_ENB ;
if ( tscmag_wires = = 5 )
tscadc - > ctrl | = CNTRLREG_TSC_5WIRE ;
else
tscadc - > ctrl | = CNTRLREG_TSC_4WIRE ;
}
2021-10-15 10:14:54 +02:00
} else {
tscadc - > ctrl | = CNTRLREG_MAG_PREAMP_PWRDOWN |
CNTRLREG_MAG_PREAMP_BYPASS ;
2014-09-04 19:01:57 +02:00
}
2021-10-15 10:14:40 +02:00
regmap_write ( tscadc - > regmap , REG_CTRL , tscadc - > ctrl ) ;
2012-10-16 12:55:43 +05:30
2021-10-15 10:14:38 +02:00
tscadc_idle_config ( tscadc ) ;
2012-10-16 12:55:43 +05:30
/* Enable the TSC module enable bit */
2021-10-15 10:14:48 +02:00
regmap_write ( tscadc - > regmap , REG_CTRL , tscadc - > ctrl | CNTRLREG_SSENB ) ;
2012-10-16 12:55:43 +05:30
2021-10-15 10:14:54 +02:00
/* TSC or MAG Cell */
if ( use_tsc | | use_mag ) {
2021-10-15 10:14:37 +02:00
cell = & tscadc - > cells [ cell_idx + + ] ;
2021-10-15 10:14:35 +02:00
cell - > name = tscadc - > data - > secondary_feature_name ;
cell - > of_compatible = tscadc - > data - > secondary_feature_compatible ;
2012-10-13 16:37:24 +03:00
cell - > platform_data = & tscadc ;
cell - > pdata_size = sizeof ( tscadc ) ;
}
2012-10-16 12:55:44 +05:30
2012-10-16 12:55:45 +05:30
/* ADC Cell */
2012-10-13 16:37:24 +03:00
if ( adc_channels > 0 ) {
2021-10-15 10:14:37 +02:00
cell = & tscadc - > cells [ cell_idx + + ] ;
2021-10-15 10:14:35 +02:00
cell - > name = tscadc - > data - > adc_feature_name ;
cell - > of_compatible = tscadc - > data - > adc_feature_compatible ;
2012-10-13 16:37:24 +03:00
cell - > platform_data = & tscadc ;
cell - > pdata_size = sizeof ( tscadc ) ;
}
2012-10-16 12:55:45 +05:30
2018-12-03 13:31:17 +05:30
err = mfd_add_devices ( & pdev - > dev , PLATFORM_DEVID_AUTO ,
2021-10-15 10:14:37 +02:00
tscadc - > cells , cell_idx , NULL , 0 , NULL ) ;
2012-10-16 12:55:43 +05:30
if ( err < 0 )
goto err_disable_clk ;
platform_set_drvdata ( pdev , tscadc ) ;
return 0 ;
err_disable_clk :
pm_runtime_put_sync ( & pdev - > dev ) ;
pm_runtime_disable ( & pdev - > dev ) ;
2021-10-15 10:14:30 +02:00
2012-10-16 12:55:43 +05:30
return err ;
}
2012-12-21 15:03:15 -08:00
static int ti_tscadc_remove ( struct platform_device * pdev )
2012-10-16 12:55:43 +05:30
{
2021-10-15 10:14:29 +02:00
struct ti_tscadc_dev * tscadc = platform_get_drvdata ( pdev ) ;
2012-10-16 12:55:43 +05:30
2016-06-08 10:54:35 -05:00
regmap_write ( tscadc - > regmap , REG_SE , 0x00 ) ;
2012-10-16 12:55:43 +05:30
pm_runtime_put_sync ( & pdev - > dev ) ;
pm_runtime_disable ( & pdev - > dev ) ;
mfd_remove_devices ( tscadc - > dev ) ;
return 0 ;
}
2018-06-30 16:03:16 +05:30
static int __maybe_unused ti_tscadc_can_wakeup ( struct device * dev , void * data )
{
return device_may_wakeup ( dev ) ;
}
2016-06-08 10:54:32 -05:00
static int __maybe_unused tscadc_suspend ( struct device * dev )
2012-10-16 12:55:43 +05:30
{
2021-10-15 10:14:29 +02:00
struct ti_tscadc_dev * tscadc = dev_get_drvdata ( dev ) ;
2012-10-16 12:55:43 +05:30
2016-06-08 10:54:35 -05:00
regmap_write ( tscadc - > regmap , REG_SE , 0x00 ) ;
2018-06-30 16:03:16 +05:30
if ( device_for_each_child ( dev , NULL , ti_tscadc_can_wakeup ) ) {
u32 ctrl ;
regmap_read ( tscadc - > regmap , REG_CTRL , & ctrl ) ;
ctrl & = ~ ( CNTRLREG_POWERDOWN ) ;
2021-10-15 10:14:48 +02:00
ctrl | = CNTRLREG_SSENB ;
2018-06-30 16:03:16 +05:30
regmap_write ( tscadc - > regmap , REG_CTRL , ctrl ) ;
}
2012-10-16 12:55:43 +05:30
pm_runtime_put_sync ( dev ) ;
return 0 ;
}
2016-06-08 10:54:32 -05:00
static int __maybe_unused tscadc_resume ( struct device * dev )
2012-10-16 12:55:43 +05:30
{
2021-10-15 10:14:29 +02:00
struct ti_tscadc_dev * tscadc = dev_get_drvdata ( dev ) ;
2012-10-16 12:55:43 +05:30
pm_runtime_get_sync ( dev ) ;
2021-10-15 10:14:39 +02:00
regmap_write ( tscadc - > regmap , REG_CLKDIV , tscadc - > clk_div ) ;
2021-10-15 10:14:40 +02:00
regmap_write ( tscadc - > regmap , REG_CTRL , tscadc - > ctrl ) ;
2021-10-15 10:14:38 +02:00
tscadc_idle_config ( tscadc ) ;
2021-10-15 10:14:48 +02:00
regmap_write ( tscadc - > regmap , REG_CTRL , tscadc - > ctrl | CNTRLREG_SSENB ) ;
2012-10-16 12:55:43 +05:30
return 0 ;
}
2016-06-08 10:54:32 -05:00
static SIMPLE_DEV_PM_OPS ( tscadc_pm_ops , tscadc_suspend , tscadc_resume ) ;
2012-10-16 12:55:43 +05:30
2021-10-15 10:14:35 +02:00
static const struct ti_tscadc_data tscdata = {
. adc_feature_name = " TI-am335x-adc " ,
. adc_feature_compatible = " ti,am3359-adc " ,
. secondary_feature_name = " TI-am335x-tsc " ,
. secondary_feature_compatible = " ti,am3359-tsc " ,
2021-10-15 10:14:49 +02:00
. target_clk_rate = TSC_ADC_CLK ,
2021-10-15 10:14:35 +02:00
} ;
2021-10-15 10:14:54 +02:00
static const struct ti_tscadc_data magdata = {
. adc_feature_name = " TI-am43xx-adc " ,
. adc_feature_compatible = " ti,am4372-adc " ,
. secondary_feature_name = " TI-am43xx-mag " ,
. secondary_feature_compatible = " ti,am4372-mag " ,
. target_clk_rate = MAG_ADC_CLK ,
} ;
2013-01-24 03:45:09 +00:00
static const struct of_device_id ti_tscadc_dt_ids [ ] = {
2021-10-15 10:14:35 +02:00
{ . compatible = " ti,am3359-tscadc " , . data = & tscdata } ,
2021-10-15 10:14:54 +02:00
{ . compatible = " ti,am4372-magadc " , . data = & magdata } ,
2013-01-24 03:45:09 +00:00
{ }
} ;
MODULE_DEVICE_TABLE ( of , ti_tscadc_dt_ids ) ;
2012-10-16 12:55:43 +05:30
static struct platform_driver ti_tscadc_driver = {
. driver = {
2013-01-24 03:45:09 +00:00
. name = " ti_am3359-tscadc " ,
2016-06-08 10:54:32 -05:00
. pm = & tscadc_pm_ops ,
2013-10-15 09:18:49 +05:30
. of_match_table = ti_tscadc_dt_ids ,
2012-10-16 12:55:43 +05:30
} ,
. probe = ti_tscadc_probe ,
2012-12-21 15:03:15 -08:00
. remove = ti_tscadc_remove ,
2012-10-16 12:55:43 +05:30
} ;
module_platform_driver ( ti_tscadc_driver ) ;
2021-10-15 10:14:54 +02:00
MODULE_DESCRIPTION ( " TI touchscreen/magnetic stripe reader/ADC MFD controller driver " ) ;
2012-10-16 12:55:43 +05:30
MODULE_AUTHOR ( " Rachna Patil <rachna@ti.com> " ) ;
MODULE_LICENSE ( " GPL " ) ;