2021-04-28 10:32:08 +03:00
// SPDX-License-Identifier: GPL-2.0
/*
* Texas Instruments TSC2046 SPI ADC driver
*
* Copyright ( c ) 2021 Oleksij Rempel < kernel @ pengutronix . de > , Pengutronix
*/
# include <linux/bitfield.h>
# include <linux/delay.h>
# include <linux/module.h>
# include <linux/spi/spi.h>
# include <asm/unaligned.h>
# include <linux/iio/buffer.h>
# include <linux/iio/trigger_consumer.h>
# include <linux/iio/triggered_buffer.h>
# include <linux/iio/trigger.h>
/*
* The PENIRQ of TSC2046 controller is implemented as level shifter attached to
* the X + line . If voltage of the X + line reaches a specific level the IRQ will
* be activated or deactivated .
* To make this kind of IRQ reusable as trigger following additions were
* implemented :
* - rate limiting :
* For typical touchscreen use case , we need to trigger about each 10 ms .
* - hrtimer :
* Continue triggering at least once after the IRQ was deactivated . Then
* deactivate this trigger to stop sampling in order to reduce power
* consumption .
*/
# define TI_TSC2046_NAME "tsc2046"
/* This driver doesn't aim at the peak continuous sample rate */
# define TI_TSC2046_MAX_SAMPLE_RATE 125000
# define TI_TSC2046_SAMPLE_BITS \
BITS_PER_TYPE ( struct tsc2046_adc_atom )
# define TI_TSC2046_MAX_CLK_FREQ \
( TI_TSC2046_MAX_SAMPLE_RATE * TI_TSC2046_SAMPLE_BITS )
# define TI_TSC2046_SAMPLE_INTERVAL_US 10000
# define TI_TSC2046_START BIT(7)
# define TI_TSC2046_ADDR GENMASK(6, 4)
# define TI_TSC2046_ADDR_TEMP1 7
# define TI_TSC2046_ADDR_AUX 6
# define TI_TSC2046_ADDR_X 5
# define TI_TSC2046_ADDR_Z2 4
# define TI_TSC2046_ADDR_Z1 3
# define TI_TSC2046_ADDR_VBAT 2
# define TI_TSC2046_ADDR_Y 1
# define TI_TSC2046_ADDR_TEMP0 0
/*
* The mode bit sets the resolution of the ADC . With this bit low , the next
* conversion has 12 - bit resolution , whereas with this bit high , the next
* conversion has 8 - bit resolution . This driver is optimized for 12 - bit mode .
* So , for this driver , this bit should stay zero .
*/
# define TI_TSC2046_8BIT_MODE BIT(3)
/*
* SER / DFR - The SER / DFR bit controls the reference mode , either single - ended
* ( high ) or differential ( low ) .
*/
# define TI_TSC2046_SER BIT(2)
/*
* If VREF_ON and ADC_ON are both zero , then the chip operates in
* auto - wake / suspend mode . In most case this bits should stay zero .
*/
# define TI_TSC2046_PD1_VREF_ON BIT(1)
# define TI_TSC2046_PD0_ADC_ON BIT(0)
/*
* All supported devices can do 8 or 12 bit resolution . This driver
* supports only 12 bit mode , here we have a 16 bit data transfer , where
* the MSB and the 3 LSB are 0.
*/
# define TI_TSC2046_DATA_12BIT GENMASK(14, 3)
# define TI_TSC2046_MAX_CHAN 8
2022-01-11 16:04:02 +03:00
# define TI_TSC2046_MIN_POLL_CNT 3
# define TI_TSC2046_EXT_POLL_CNT 3
# define TI_TSC2046_POLL_CNT \
( TI_TSC2046_MIN_POLL_CNT + TI_TSC2046_EXT_POLL_CNT )
2022-01-17 11:28:51 +03:00
# define TI_TSC2046_INT_VREF 2500
2021-04-28 10:32:08 +03:00
/* Represents a HW sample */
struct tsc2046_adc_atom {
/*
* Command transmitted to the controller . This field is empty on the RX
* buffer .
*/
u8 cmd ;
/*
* Data received from the controller . This field is empty for the TX
* buffer
*/
__be16 data ;
} __packed ;
/* Layout of atomic buffers within big buffer */
struct tsc2046_adc_group_layout {
/* Group offset within the SPI RX buffer */
unsigned int offset ;
/*
* Amount of tsc2046_adc_atom structs within the same command gathered
* within same group .
*/
unsigned int count ;
/*
* Settling samples ( tsc2046_adc_atom structs ) which should be skipped
* before good samples will start .
*/
unsigned int skip ;
} ;
struct tsc2046_adc_dcfg {
const struct iio_chan_spec * channels ;
unsigned int num_channels ;
} ;
struct tsc2046_adc_ch_cfg {
unsigned int settling_time_us ;
unsigned int oversampling_ratio ;
} ;
2022-01-11 16:04:02 +03:00
enum tsc2046_state {
TSC2046_STATE_SHUTDOWN ,
TSC2046_STATE_STANDBY ,
TSC2046_STATE_POLL ,
TSC2046_STATE_POLL_IRQ_DISABLE ,
TSC2046_STATE_ENABLE_IRQ ,
} ;
2021-04-28 10:32:08 +03:00
struct tsc2046_adc_priv {
struct spi_device * spi ;
const struct tsc2046_adc_dcfg * dcfg ;
struct iio_trigger * trig ;
struct hrtimer trig_timer ;
2022-01-11 16:04:02 +03:00
enum tsc2046_state state ;
int poll_cnt ;
spinlock_t state_lock ;
2021-04-28 10:32:08 +03:00
struct spi_transfer xfer ;
struct spi_message msg ;
struct {
/* Scan data for each channel */
u16 data [ TI_TSC2046_MAX_CHAN ] ;
/* Timestamp */
s64 ts __aligned ( 8 ) ;
} scan_buf ;
/*
* Lock to protect the layout and the SPI transfer buffer .
* tsc2046_adc_group_layout can be changed within update_scan_mode ( ) ,
* in this case the l [ ] and tx / rx buffer will be out of sync to each
* other .
*/
struct mutex slock ;
struct tsc2046_adc_group_layout l [ TI_TSC2046_MAX_CHAN ] ;
struct tsc2046_adc_atom * rx ;
struct tsc2046_adc_atom * tx ;
unsigned int count ;
unsigned int groups ;
u32 effective_speed_hz ;
u32 scan_interval_us ;
u32 time_per_scan_us ;
u32 time_per_bit_ns ;
struct tsc2046_adc_ch_cfg ch_cfg [ TI_TSC2046_MAX_CHAN ] ;
} ;
# define TI_TSC2046_V_CHAN(index, bits, name) \
{ \
. type = IIO_VOLTAGE , \
. indexed = 1 , \
. channel = index , \
2022-01-17 11:28:51 +03:00
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) , \
. info_mask_shared_by_type = BIT ( IIO_CHAN_INFO_SCALE ) , \
2021-04-28 10:32:08 +03:00
. datasheet_name = " #name " , \
. scan_index = index , \
. scan_type = { \
. sign = ' u ' , \
. realbits = bits , \
. storagebits = 16 , \
. endianness = IIO_CPU , \
} , \
}
# define DECLARE_TI_TSC2046_8_CHANNELS(name, bits) \
const struct iio_chan_spec name # # _channels [ ] = { \
TI_TSC2046_V_CHAN ( 0 , bits , TEMP0 ) , \
TI_TSC2046_V_CHAN ( 1 , bits , Y ) , \
TI_TSC2046_V_CHAN ( 2 , bits , VBAT ) , \
TI_TSC2046_V_CHAN ( 3 , bits , Z1 ) , \
TI_TSC2046_V_CHAN ( 4 , bits , Z2 ) , \
TI_TSC2046_V_CHAN ( 5 , bits , X ) , \
TI_TSC2046_V_CHAN ( 6 , bits , AUX ) , \
TI_TSC2046_V_CHAN ( 7 , bits , TEMP1 ) , \
IIO_CHAN_SOFT_TIMESTAMP ( 8 ) , \
}
static DECLARE_TI_TSC2046_8_CHANNELS ( tsc2046_adc , 12 ) ;
static const struct tsc2046_adc_dcfg tsc2046_adc_dcfg_tsc2046e = {
. channels = tsc2046_adc_channels ,
. num_channels = ARRAY_SIZE ( tsc2046_adc_channels ) ,
} ;
/*
* Convert time to a number of samples which can be transferred within this
* time .
*/
static unsigned int tsc2046_adc_time_to_count ( struct tsc2046_adc_priv * priv ,
unsigned long time )
{
unsigned int bit_count , sample_count ;
bit_count = DIV_ROUND_UP ( time * NSEC_PER_USEC , priv - > time_per_bit_ns ) ;
sample_count = DIV_ROUND_UP ( bit_count , TI_TSC2046_SAMPLE_BITS ) ;
dev_dbg ( & priv - > spi - > dev , " Effective speed %u, time per bit: %u, count bits: %u, count samples: %u \n " ,
priv - > effective_speed_hz , priv - > time_per_bit_ns ,
bit_count , sample_count ) ;
return sample_count ;
}
static u8 tsc2046_adc_get_cmd ( struct tsc2046_adc_priv * priv , int ch_idx ,
bool keep_power )
{
u32 pd ;
/*
* if PD bits are 0 , controller will automatically disable ADC , VREF and
* enable IRQ .
*/
if ( keep_power )
pd = TI_TSC2046_PD0_ADC_ON ;
else
pd = 0 ;
2022-01-17 11:28:51 +03:00
switch ( ch_idx ) {
case TI_TSC2046_ADDR_TEMP1 :
case TI_TSC2046_ADDR_AUX :
case TI_TSC2046_ADDR_VBAT :
case TI_TSC2046_ADDR_TEMP0 :
pd | = TI_TSC2046_SER | TI_TSC2046_PD1_VREF_ON ;
}
2021-04-28 10:32:08 +03:00
return TI_TSC2046_START | FIELD_PREP ( TI_TSC2046_ADDR , ch_idx ) | pd ;
}
static u16 tsc2046_adc_get_value ( struct tsc2046_adc_atom * buf )
{
return FIELD_GET ( TI_TSC2046_DATA_12BIT , get_unaligned_be16 ( & buf - > data ) ) ;
}
static int tsc2046_adc_read_one ( struct tsc2046_adc_priv * priv , int ch_idx ,
u32 * effective_speed_hz )
{
2022-01-17 11:28:51 +03:00
struct tsc2046_adc_ch_cfg * ch = & priv - > ch_cfg [ ch_idx ] ;
struct tsc2046_adc_atom * rx_buf , * tx_buf ;
unsigned int val , val_normalized = 0 ;
int ret , i , count_skip = 0 , max_count ;
2021-04-28 10:32:08 +03:00
struct spi_transfer xfer ;
struct spi_message msg ;
2022-01-17 11:28:51 +03:00
u8 cmd ;
if ( ! effective_speed_hz ) {
count_skip = tsc2046_adc_time_to_count ( priv , ch - > settling_time_us ) ;
max_count = count_skip + ch - > oversampling_ratio ;
} else {
max_count = 1 ;
}
if ( sizeof ( * tx_buf ) * max_count > PAGE_SIZE )
return - ENOSPC ;
tx_buf = kcalloc ( max_count , sizeof ( * tx_buf ) , GFP_KERNEL ) ;
if ( ! tx_buf )
return - ENOMEM ;
rx_buf = kcalloc ( max_count , sizeof ( * rx_buf ) , GFP_KERNEL ) ;
if ( ! rx_buf ) {
ret = - ENOMEM ;
goto free_tx ;
}
/*
* Do not enable automatic power down on working samples . Otherwise the
* plates will never be completely charged .
*/
cmd = tsc2046_adc_get_cmd ( priv , ch_idx , true ) ;
for ( i = 0 ; i < max_count - 1 ; i + + )
tx_buf [ i ] . cmd = cmd ;
/* automatically power down on last sample */
tx_buf [ i ] . cmd = tsc2046_adc_get_cmd ( priv , ch_idx , false ) ;
2021-04-28 10:32:08 +03:00
memset ( & xfer , 0 , sizeof ( xfer ) ) ;
2022-01-17 11:28:51 +03:00
xfer . tx_buf = tx_buf ;
xfer . rx_buf = rx_buf ;
xfer . len = sizeof ( * tx_buf ) * max_count ;
2021-04-28 10:32:08 +03:00
spi_message_init_with_transfers ( & msg , & xfer , 1 ) ;
/*
* We aren ' t using spi_write_then_read ( ) because we need to be able
* to get hold of the effective_speed_hz from the xfer
*/
ret = spi_sync ( priv - > spi , & msg ) ;
if ( ret ) {
dev_err_ratelimited ( & priv - > spi - > dev , " SPI transfer failed %pe \n " ,
ERR_PTR ( ret ) ) ;
2022-01-17 11:28:51 +03:00
goto free_bufs ;
2021-04-28 10:32:08 +03:00
}
if ( effective_speed_hz )
* effective_speed_hz = xfer . effective_speed_hz ;
2022-01-17 11:28:51 +03:00
for ( i = 0 ; i < max_count - count_skip ; i + + ) {
val = tsc2046_adc_get_value ( & rx_buf [ count_skip + i ] ) ;
val_normalized + = val ;
}
ret = DIV_ROUND_UP ( val_normalized , max_count - count_skip ) ;
free_bufs :
kfree ( rx_buf ) ;
free_tx :
kfree ( tx_buf ) ;
return ret ;
2021-04-28 10:32:08 +03:00
}
static size_t tsc2046_adc_group_set_layout ( struct tsc2046_adc_priv * priv ,
unsigned int group ,
unsigned int ch_idx )
{
struct tsc2046_adc_ch_cfg * ch = & priv - > ch_cfg [ ch_idx ] ;
struct tsc2046_adc_group_layout * cur ;
unsigned int max_count , count_skip ;
unsigned int offset = 0 ;
if ( group )
offset = priv - > l [ group - 1 ] . offset + priv - > l [ group - 1 ] . count ;
count_skip = tsc2046_adc_time_to_count ( priv , ch - > settling_time_us ) ;
max_count = count_skip + ch - > oversampling_ratio ;
cur = & priv - > l [ group ] ;
cur - > offset = offset ;
cur - > count = max_count ;
cur - > skip = count_skip ;
return sizeof ( * priv - > tx ) * max_count ;
}
static void tsc2046_adc_group_set_cmd ( struct tsc2046_adc_priv * priv ,
unsigned int group , int ch_idx )
{
struct tsc2046_adc_group_layout * l = & priv - > l [ group ] ;
unsigned int i ;
u8 cmd ;
/*
* Do not enable automatic power down on working samples . Otherwise the
* plates will never be completely charged .
*/
cmd = tsc2046_adc_get_cmd ( priv , ch_idx , true ) ;
for ( i = 0 ; i < l - > count - 1 ; i + + )
priv - > tx [ l - > offset + i ] . cmd = cmd ;
/* automatically power down on last sample */
priv - > tx [ l - > offset + i ] . cmd = tsc2046_adc_get_cmd ( priv , ch_idx , false ) ;
}
static u16 tsc2046_adc_get_val ( struct tsc2046_adc_priv * priv , int group )
{
struct tsc2046_adc_group_layout * l ;
unsigned int val , val_normalized = 0 ;
int valid_count , i ;
l = & priv - > l [ group ] ;
valid_count = l - > count - l - > skip ;
for ( i = 0 ; i < valid_count ; i + + ) {
val = tsc2046_adc_get_value ( & priv - > rx [ l - > offset + l - > skip + i ] ) ;
val_normalized + = val ;
}
return DIV_ROUND_UP ( val_normalized , valid_count ) ;
}
static int tsc2046_adc_scan ( struct iio_dev * indio_dev )
{
struct tsc2046_adc_priv * priv = iio_priv ( indio_dev ) ;
struct device * dev = & priv - > spi - > dev ;
int group ;
int ret ;
ret = spi_sync ( priv - > spi , & priv - > msg ) ;
if ( ret < 0 ) {
dev_err_ratelimited ( dev , " SPI transfer failed: %pe \n " , ERR_PTR ( ret ) ) ;
return ret ;
}
for ( group = 0 ; group < priv - > groups ; group + + )
priv - > scan_buf . data [ group ] = tsc2046_adc_get_val ( priv , group ) ;
ret = iio_push_to_buffers_with_timestamp ( indio_dev , & priv - > scan_buf ,
iio_get_time_ns ( indio_dev ) ) ;
/* If the consumer is kfifo, we may get a EBUSY here - ignore it. */
if ( ret < 0 & & ret ! = - EBUSY ) {
dev_err_ratelimited ( dev , " Failed to push scan buffer %pe \n " ,
ERR_PTR ( ret ) ) ;
return ret ;
}
return 0 ;
}
static irqreturn_t tsc2046_adc_trigger_handler ( int irq , void * p )
{
struct iio_poll_func * pf = p ;
struct iio_dev * indio_dev = pf - > indio_dev ;
struct tsc2046_adc_priv * priv = iio_priv ( indio_dev ) ;
mutex_lock ( & priv - > slock ) ;
tsc2046_adc_scan ( indio_dev ) ;
mutex_unlock ( & priv - > slock ) ;
iio_trigger_notify_done ( indio_dev - > trig ) ;
return IRQ_HANDLED ;
}
2022-01-17 11:28:51 +03:00
static int tsc2046_adc_read_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
int * val , int * val2 , long m )
{
struct tsc2046_adc_priv * priv = iio_priv ( indio_dev ) ;
int ret ;
switch ( m ) {
case IIO_CHAN_INFO_RAW :
ret = tsc2046_adc_read_one ( priv , chan - > channel , NULL ) ;
if ( ret < 0 )
return ret ;
* val = ret ;
return IIO_VAL_INT ;
case IIO_CHAN_INFO_SCALE :
/*
* Note : the TSC2046 has internal voltage divider on the VBAT
* line . This divider can be influenced by external divider .
* So , it is better to use external voltage - divider driver
* instead , which is calculating complete chain .
*/
* val = TI_TSC2046_INT_VREF ;
* val2 = chan - > scan_type . realbits ;
return IIO_VAL_FRACTIONAL_LOG2 ;
}
return - EINVAL ;
}
2021-04-28 10:32:08 +03:00
static int tsc2046_adc_update_scan_mode ( struct iio_dev * indio_dev ,
const unsigned long * active_scan_mask )
{
struct tsc2046_adc_priv * priv = iio_priv ( indio_dev ) ;
unsigned int ch_idx , group = 0 ;
size_t size ;
mutex_lock ( & priv - > slock ) ;
size = 0 ;
2022-01-07 11:14:01 +03:00
for_each_set_bit ( ch_idx , active_scan_mask , ARRAY_SIZE ( priv - > l ) ) {
2021-04-28 10:32:08 +03:00
size + = tsc2046_adc_group_set_layout ( priv , group , ch_idx ) ;
tsc2046_adc_group_set_cmd ( priv , group , ch_idx ) ;
group + + ;
}
priv - > groups = group ;
priv - > xfer . len = size ;
priv - > time_per_scan_us = size * 8 * priv - > time_per_bit_ns / NSEC_PER_USEC ;
2021-10-07 12:30:06 +03:00
if ( priv - > scan_interval_us < priv - > time_per_scan_us )
2021-04-28 10:32:08 +03:00
dev_warn ( & priv - > spi - > dev , " The scan interval (%d) is less then calculated scan time (%d) \n " ,
priv - > scan_interval_us , priv - > time_per_scan_us ) ;
mutex_unlock ( & priv - > slock ) ;
return 0 ;
}
static const struct iio_info tsc2046_adc_info = {
2022-01-17 11:28:51 +03:00
. read_raw = tsc2046_adc_read_raw ,
2021-04-28 10:32:08 +03:00
. update_scan_mode = tsc2046_adc_update_scan_mode ,
} ;
2022-01-11 16:04:02 +03:00
static enum hrtimer_restart tsc2046_adc_timer ( struct hrtimer * hrtimer )
2021-04-28 10:32:08 +03:00
{
struct tsc2046_adc_priv * priv = container_of ( hrtimer ,
struct tsc2046_adc_priv ,
trig_timer ) ;
unsigned long flags ;
2022-01-11 16:04:02 +03:00
/*
* This state machine should address following challenges :
* - the interrupt source is based on level shifter attached to the X
* channel of ADC . It will change the state every time we switch
* between channels . So , we need to disable IRQ if we do
* iio_trigger_poll ( ) .
* - we should do iio_trigger_poll ( ) at some reduced sample rate
* - we should still trigger for some amount of time after last
* interrupt with enabled IRQ was processed .
*/
2021-04-28 10:32:08 +03:00
2022-01-11 16:04:02 +03:00
spin_lock_irqsave ( & priv - > state_lock , flags ) ;
switch ( priv - > state ) {
case TSC2046_STATE_ENABLE_IRQ :
if ( priv - > poll_cnt < TI_TSC2046_POLL_CNT ) {
priv - > poll_cnt + + ;
hrtimer_start ( & priv - > trig_timer ,
ns_to_ktime ( priv - > scan_interval_us *
NSEC_PER_USEC ) ,
HRTIMER_MODE_REL_SOFT ) ;
if ( priv - > poll_cnt > = TI_TSC2046_MIN_POLL_CNT ) {
priv - > state = TSC2046_STATE_POLL_IRQ_DISABLE ;
enable_irq ( priv - > spi - > irq ) ;
} else {
priv - > state = TSC2046_STATE_POLL ;
}
} else {
priv - > state = TSC2046_STATE_STANDBY ;
enable_irq ( priv - > spi - > irq ) ;
}
break ;
case TSC2046_STATE_POLL_IRQ_DISABLE :
disable_irq_nosync ( priv - > spi - > irq ) ;
fallthrough ;
case TSC2046_STATE_POLL :
priv - > state = TSC2046_STATE_ENABLE_IRQ ;
/* iio_trigger_poll() starts hrtimer */
iio_trigger_poll ( priv - > trig ) ;
break ;
case TSC2046_STATE_SHUTDOWN :
break ;
case TSC2046_STATE_STANDBY :
fallthrough ;
default :
dev_warn ( & priv - > spi - > dev , " Got unexpected state: %i \n " ,
priv - > state ) ;
break ;
}
spin_unlock_irqrestore ( & priv - > state_lock , flags ) ;
2021-04-28 10:32:08 +03:00
return HRTIMER_NORESTART ;
}
static irqreturn_t tsc2046_adc_irq ( int irq , void * dev_id )
{
struct iio_dev * indio_dev = dev_id ;
struct tsc2046_adc_priv * priv = iio_priv ( indio_dev ) ;
2022-01-11 16:04:02 +03:00
unsigned long flags ;
2021-04-28 10:32:08 +03:00
hrtimer_try_to_cancel ( & priv - > trig_timer ) ;
2022-01-11 16:04:02 +03:00
spin_lock_irqsave ( & priv - > state_lock , flags ) ;
if ( priv - > state ! = TSC2046_STATE_SHUTDOWN ) {
priv - > state = TSC2046_STATE_ENABLE_IRQ ;
priv - > poll_cnt = 0 ;
2021-04-28 10:32:08 +03:00
2022-01-11 16:04:02 +03:00
/* iio_trigger_poll() starts hrtimer */
disable_irq_nosync ( priv - > spi - > irq ) ;
iio_trigger_poll ( priv - > trig ) ;
}
spin_unlock_irqrestore ( & priv - > state_lock , flags ) ;
2021-04-28 10:32:08 +03:00
return IRQ_HANDLED ;
}
static void tsc2046_adc_reenable_trigger ( struct iio_trigger * trig )
{
struct iio_dev * indio_dev = iio_trigger_get_drvdata ( trig ) ;
struct tsc2046_adc_priv * priv = iio_priv ( indio_dev ) ;
2022-01-11 16:04:02 +03:00
ktime_t tim ;
2021-04-28 10:32:08 +03:00
/*
* We can sample it as fast as we can , but usually we do not need so
* many samples . Reduce the sample rate for default ( touchscreen ) use
* case .
*/
2022-01-11 16:04:02 +03:00
tim = ns_to_ktime ( ( priv - > scan_interval_us - priv - > time_per_scan_us ) *
NSEC_PER_USEC ) ;
hrtimer_start ( & priv - > trig_timer , tim , HRTIMER_MODE_REL_SOFT ) ;
2021-04-28 10:32:08 +03:00
}
static int tsc2046_adc_set_trigger_state ( struct iio_trigger * trig , bool enable )
{
struct iio_dev * indio_dev = iio_trigger_get_drvdata ( trig ) ;
struct tsc2046_adc_priv * priv = iio_priv ( indio_dev ) ;
2022-01-11 16:04:02 +03:00
unsigned long flags ;
2021-04-28 10:32:08 +03:00
if ( enable ) {
2022-01-11 16:04:02 +03:00
spin_lock_irqsave ( & priv - > state_lock , flags ) ;
if ( priv - > state = = TSC2046_STATE_SHUTDOWN ) {
priv - > state = TSC2046_STATE_STANDBY ;
enable_irq ( priv - > spi - > irq ) ;
}
spin_unlock_irqrestore ( & priv - > state_lock , flags ) ;
2021-04-28 10:32:08 +03:00
} else {
2022-01-11 16:04:02 +03:00
spin_lock_irqsave ( & priv - > state_lock , flags ) ;
if ( priv - > state = = TSC2046_STATE_STANDBY | |
priv - > state = = TSC2046_STATE_POLL_IRQ_DISABLE )
disable_irq_nosync ( priv - > spi - > irq ) ;
priv - > state = TSC2046_STATE_SHUTDOWN ;
spin_unlock_irqrestore ( & priv - > state_lock , flags ) ;
hrtimer_cancel ( & priv - > trig_timer ) ;
2021-04-28 10:32:08 +03:00
}
return 0 ;
}
static const struct iio_trigger_ops tsc2046_adc_trigger_ops = {
. set_trigger_state = tsc2046_adc_set_trigger_state ,
. reenable = tsc2046_adc_reenable_trigger ,
} ;
static int tsc2046_adc_setup_spi_msg ( struct tsc2046_adc_priv * priv )
{
unsigned int ch_idx ;
size_t size ;
int ret ;
/*
* Make dummy read to set initial power state and get real SPI clock
* freq . It seems to be not important which channel is used for this
* case .
*/
ret = tsc2046_adc_read_one ( priv , TI_TSC2046_ADDR_TEMP0 ,
& priv - > effective_speed_hz ) ;
if ( ret < 0 )
return ret ;
/*
* In case SPI controller do not report effective_speed_hz , use
* configure value and hope it will match .
*/
if ( ! priv - > effective_speed_hz )
priv - > effective_speed_hz = priv - > spi - > max_speed_hz ;
priv - > scan_interval_us = TI_TSC2046_SAMPLE_INTERVAL_US ;
priv - > time_per_bit_ns = DIV_ROUND_UP ( NSEC_PER_SEC ,
priv - > effective_speed_hz ) ;
/*
* Calculate and allocate maximal size buffer if all channels are
* enabled .
*/
size = 0 ;
2022-01-07 11:14:01 +03:00
for ( ch_idx = 0 ; ch_idx < ARRAY_SIZE ( priv - > l ) ; ch_idx + + )
2021-04-28 10:32:08 +03:00
size + = tsc2046_adc_group_set_layout ( priv , ch_idx , ch_idx ) ;
2022-01-17 11:28:52 +03:00
if ( size > PAGE_SIZE ) {
dev_err ( & priv - > spi - > dev ,
" Calculated scan buffer is too big. Try to reduce spi-max-frequency, settling-time-us or oversampling-ratio \n " ) ;
return - ENOSPC ;
}
2021-04-28 10:32:08 +03:00
priv - > tx = devm_kzalloc ( & priv - > spi - > dev , size , GFP_KERNEL ) ;
if ( ! priv - > tx )
return - ENOMEM ;
priv - > rx = devm_kzalloc ( & priv - > spi - > dev , size , GFP_KERNEL ) ;
if ( ! priv - > rx )
return - ENOMEM ;
priv - > xfer . tx_buf = priv - > tx ;
priv - > xfer . rx_buf = priv - > rx ;
priv - > xfer . len = size ;
spi_message_init_with_transfers ( & priv - > msg , & priv - > xfer , 1 ) ;
return 0 ;
}
static void tsc2046_adc_parse_fwnode ( struct tsc2046_adc_priv * priv )
{
struct fwnode_handle * child ;
struct device * dev = & priv - > spi - > dev ;
unsigned int i ;
for ( i = 0 ; i < ARRAY_SIZE ( priv - > ch_cfg ) ; i + + ) {
priv - > ch_cfg [ i ] . settling_time_us = 1 ;
priv - > ch_cfg [ i ] . oversampling_ratio = 1 ;
}
device_for_each_child_node ( dev , child ) {
u32 stl , overs , reg ;
int ret ;
ret = fwnode_property_read_u32 ( child , " reg " , & reg ) ;
if ( ret ) {
dev_err ( dev , " invalid reg on %pfw, err: %pe \n " , child ,
ERR_PTR ( ret ) ) ;
continue ;
}
if ( reg > = ARRAY_SIZE ( priv - > ch_cfg ) ) {
dev_err ( dev , " %pfw: Unsupported reg value: %i, max supported is: %zu. \n " ,
child , reg , ARRAY_SIZE ( priv - > ch_cfg ) ) ;
continue ;
}
ret = fwnode_property_read_u32 ( child , " settling-time-us " , & stl ) ;
if ( ! ret )
priv - > ch_cfg [ reg ] . settling_time_us = stl ;
ret = fwnode_property_read_u32 ( child , " oversampling-ratio " ,
& overs ) ;
if ( ! ret )
priv - > ch_cfg [ reg ] . oversampling_ratio = overs ;
}
}
static int tsc2046_adc_probe ( struct spi_device * spi )
{
const struct tsc2046_adc_dcfg * dcfg ;
struct device * dev = & spi - > dev ;
struct tsc2046_adc_priv * priv ;
struct iio_dev * indio_dev ;
struct iio_trigger * trig ;
int ret ;
if ( spi - > max_speed_hz > TI_TSC2046_MAX_CLK_FREQ ) {
dev_err ( dev , " SPI max_speed_hz is too high: %d Hz. Max supported freq is %zu Hz \n " ,
spi - > max_speed_hz , TI_TSC2046_MAX_CLK_FREQ ) ;
return - EINVAL ;
}
dcfg = device_get_match_data ( dev ) ;
if ( ! dcfg )
return - EINVAL ;
spi - > bits_per_word = 8 ;
spi - > mode & = ~ SPI_MODE_X_MASK ;
spi - > mode | = SPI_MODE_0 ;
ret = spi_setup ( spi ) ;
if ( ret < 0 )
return dev_err_probe ( dev , ret , " Error in SPI setup \n " ) ;
indio_dev = devm_iio_device_alloc ( dev , sizeof ( * priv ) ) ;
if ( ! indio_dev )
return - ENOMEM ;
priv = iio_priv ( indio_dev ) ;
priv - > dcfg = dcfg ;
priv - > spi = spi ;
indio_dev - > name = TI_TSC2046_NAME ;
2022-06-29 23:39:10 +03:00
indio_dev - > modes = INDIO_DIRECT_MODE ;
2021-04-28 10:32:08 +03:00
indio_dev - > channels = dcfg - > channels ;
indio_dev - > num_channels = dcfg - > num_channels ;
indio_dev - > info = & tsc2046_adc_info ;
tsc2046_adc_parse_fwnode ( priv ) ;
ret = tsc2046_adc_setup_spi_msg ( priv ) ;
if ( ret )
return ret ;
mutex_init ( & priv - > slock ) ;
ret = devm_request_irq ( dev , spi - > irq , & tsc2046_adc_irq ,
IRQF_NO_AUTOEN , indio_dev - > name , indio_dev ) ;
if ( ret )
return ret ;
trig = devm_iio_trigger_alloc ( dev , " touchscreen-%s " , indio_dev - > name ) ;
if ( ! trig )
return - ENOMEM ;
priv - > trig = trig ;
iio_trigger_set_drvdata ( trig , indio_dev ) ;
trig - > ops = & tsc2046_adc_trigger_ops ;
2022-01-11 16:04:02 +03:00
spin_lock_init ( & priv - > state_lock ) ;
priv - > state = TSC2046_STATE_SHUTDOWN ;
2021-04-28 10:32:08 +03:00
hrtimer_init ( & priv - > trig_timer , CLOCK_MONOTONIC ,
HRTIMER_MODE_REL_SOFT ) ;
2022-01-11 16:04:02 +03:00
priv - > trig_timer . function = tsc2046_adc_timer ;
2021-04-28 10:32:08 +03:00
ret = devm_iio_trigger_register ( dev , trig ) ;
if ( ret ) {
dev_err ( dev , " failed to register trigger \n " ) ;
return ret ;
}
ret = devm_iio_triggered_buffer_setup ( dev , indio_dev , NULL ,
& tsc2046_adc_trigger_handler , NULL ) ;
if ( ret ) {
dev_err ( dev , " Failed to setup triggered buffer \n " ) ;
return ret ;
}
/* set default trigger */
indio_dev - > trig = iio_trigger_get ( priv - > trig ) ;
return devm_iio_device_register ( dev , indio_dev ) ;
}
static const struct of_device_id ads7950_of_table [ ] = {
{ . compatible = " ti,tsc2046e-adc " , . data = & tsc2046_adc_dcfg_tsc2046e } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , ads7950_of_table ) ;
static struct spi_driver tsc2046_adc_driver = {
. driver = {
. name = " tsc2046 " ,
. of_match_table = ads7950_of_table ,
} ,
. probe = tsc2046_adc_probe ,
} ;
module_spi_driver ( tsc2046_adc_driver ) ;
MODULE_AUTHOR ( " Oleksij Rempel <kernel@pengutronix.de> " ) ;
MODULE_DESCRIPTION ( " TI TSC2046 ADC " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;