2019-05-29 17:17:58 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2012-01-31 12:18:00 +04:00
/*
* Source for :
* Cypress TrueTouch ( TM ) Standard Product ( TTSP ) SPI touchscreen driver .
* For use with Cypress Txx3xx parts .
* Supported parts include :
* CY8CTST341
* CY8CTMA340
*
* Copyright ( C ) 2009 , 2010 , 2011 Cypress Semiconductor , Inc .
* Copyright ( C ) 2012 Javier Martinez Canillas < javier @ dowhile0 . org >
2013-07-01 05:46:56 +04:00
* Copyright ( C ) 2013 Cypress Semiconductor
2012-01-31 12:18:00 +04:00
*
2013-07-01 05:46:56 +04:00
* Contact Cypress Semiconductor at www . cypress . com < ttdrivers @ cypress . com >
2012-01-31 12:18:00 +04:00
*/
# include "cyttsp_core.h"
# include <linux/delay.h>
# include <linux/input.h>
# include <linux/spi/spi.h>
# define CY_SPI_WR_OP 0x00 /* r/~w */
# define CY_SPI_RD_OP 0x01
# define CY_SPI_CMD_BYTES 4
# define CY_SPI_SYNC_BYTE 2
# define CY_SPI_SYNC_ACK1 0x62 /* from protocol v.2 */
# define CY_SPI_SYNC_ACK2 0x9D /* from protocol v.2 */
# define CY_SPI_DATA_SIZE 128
# define CY_SPI_DATA_BUF_SIZE (CY_SPI_CMD_BYTES + CY_SPI_DATA_SIZE)
# define CY_SPI_BITS_PER_WORD 8
2013-07-01 05:46:56 +04:00
static int cyttsp_spi_xfer ( struct device * dev , u8 * xfer_buf ,
2013-07-05 01:02:57 +04:00
u8 op , u16 reg , u8 * buf , int length )
2012-01-31 12:18:00 +04:00
{
2013-07-01 05:46:56 +04:00
struct spi_device * spi = to_spi_device ( dev ) ;
2012-01-31 12:18:00 +04:00
struct spi_message msg ;
struct spi_transfer xfer [ 2 ] ;
2013-07-01 05:46:56 +04:00
u8 * wr_buf = & xfer_buf [ 0 ] ;
u8 * rd_buf = & xfer_buf [ CY_SPI_DATA_BUF_SIZE ] ;
2012-01-31 12:18:00 +04:00
int retval ;
int i ;
if ( length > CY_SPI_DATA_SIZE ) {
2013-07-01 05:46:56 +04:00
dev_err ( dev , " %s: length %d is too big. \n " ,
2012-01-31 12:18:00 +04:00
__func__ , length ) ;
return - EINVAL ;
}
memset ( wr_buf , 0 , CY_SPI_DATA_BUF_SIZE ) ;
memset ( rd_buf , 0 , CY_SPI_DATA_BUF_SIZE ) ;
wr_buf [ 0 ] = 0x00 ; /* header byte 0 */
wr_buf [ 1 ] = 0xFF ; /* header byte 1 */
wr_buf [ 2 ] = reg ; /* reg index */
wr_buf [ 3 ] = op ; /* r/~w */
if ( op = = CY_SPI_WR_OP )
memcpy ( wr_buf + CY_SPI_CMD_BYTES , buf , length ) ;
memset ( xfer , 0 , sizeof ( xfer ) ) ;
spi_message_init ( & msg ) ;
/*
We set both TX and RX buffers because Cypress TTSP
requires full duplex operation .
*/
xfer [ 0 ] . tx_buf = wr_buf ;
xfer [ 0 ] . rx_buf = rd_buf ;
switch ( op ) {
case CY_SPI_WR_OP :
xfer [ 0 ] . len = length + CY_SPI_CMD_BYTES ;
spi_message_add_tail ( & xfer [ 0 ] , & msg ) ;
break ;
case CY_SPI_RD_OP :
xfer [ 0 ] . len = CY_SPI_CMD_BYTES ;
spi_message_add_tail ( & xfer [ 0 ] , & msg ) ;
xfer [ 1 ] . rx_buf = buf ;
xfer [ 1 ] . len = length ;
spi_message_add_tail ( & xfer [ 1 ] , & msg ) ;
break ;
default :
2013-07-01 05:46:56 +04:00
dev_err ( dev , " %s: bad operation code=%d \n " , __func__ , op ) ;
2012-01-31 12:18:00 +04:00
return - EINVAL ;
}
retval = spi_sync ( spi , & msg ) ;
if ( retval < 0 ) {
2013-07-01 05:46:56 +04:00
dev_dbg ( dev , " %s: spi_sync() error %d, len=%d, op=%d \n " ,
2012-01-31 12:18:00 +04:00
__func__ , retval , xfer [ 1 ] . len , op ) ;
/*
* do not return here since was a bad ACK sequence
* let the following ACK check handle any errors and
* allow silent retries
*/
}
if ( rd_buf [ CY_SPI_SYNC_BYTE ] ! = CY_SPI_SYNC_ACK1 | |
rd_buf [ CY_SPI_SYNC_BYTE + 1 ] ! = CY_SPI_SYNC_ACK2 ) {
2013-07-01 05:46:56 +04:00
dev_dbg ( dev , " %s: operation %d failed \n " , __func__ , op ) ;
2012-01-31 12:18:00 +04:00
for ( i = 0 ; i < CY_SPI_CMD_BYTES ; i + + )
2013-07-01 05:46:56 +04:00
dev_dbg ( dev , " %s: test rd_buf[%d]:0x%02x \n " ,
2012-01-31 12:18:00 +04:00
__func__ , i , rd_buf [ i ] ) ;
for ( i = 0 ; i < length ; i + + )
2013-07-01 05:46:56 +04:00
dev_dbg ( dev , " %s: test buf[%d]:0x%02x \n " ,
2012-01-31 12:18:00 +04:00
__func__ , i , buf [ i ] ) ;
return - EIO ;
}
return 0 ;
}
2013-07-01 05:46:56 +04:00
static int cyttsp_spi_read_block_data ( struct device * dev , u8 * xfer_buf ,
2013-07-05 01:02:57 +04:00
u16 addr , u8 length , void * data )
2012-01-31 12:18:00 +04:00
{
2013-07-01 05:46:56 +04:00
return cyttsp_spi_xfer ( dev , xfer_buf , CY_SPI_RD_OP , addr , data ,
length ) ;
2012-01-31 12:18:00 +04:00
}
2013-07-01 05:46:56 +04:00
static int cyttsp_spi_write_block_data ( struct device * dev , u8 * xfer_buf ,
2013-07-05 01:02:57 +04:00
u16 addr , u8 length , const void * data )
2012-01-31 12:18:00 +04:00
{
2013-07-01 05:46:56 +04:00
return cyttsp_spi_xfer ( dev , xfer_buf , CY_SPI_WR_OP , addr , ( void * ) data ,
length ) ;
2012-01-31 12:18:00 +04:00
}
static const struct cyttsp_bus_ops cyttsp_spi_bus_ops = {
. bustype = BUS_SPI ,
. write = cyttsp_spi_write_block_data ,
. read = cyttsp_spi_read_block_data ,
} ;
2012-11-24 09:38:25 +04:00
static int cyttsp_spi_probe ( struct spi_device * spi )
2012-01-31 12:18:00 +04:00
{
struct cyttsp * ts ;
int error ;
/* Set up SPI*/
spi - > bits_per_word = CY_SPI_BITS_PER_WORD ;
spi - > mode = SPI_MODE_0 ;
error = spi_setup ( spi ) ;
if ( error < 0 ) {
dev_err ( & spi - > dev , " %s: SPI setup error %d \n " ,
__func__ , error ) ;
return error ;
}
ts = cyttsp_probe ( & cyttsp_spi_bus_ops , & spi - > dev , spi - > irq ,
CY_SPI_DATA_BUF_SIZE * 2 ) ;
if ( IS_ERR ( ts ) )
return PTR_ERR ( ts ) ;
spi_set_drvdata ( spi , ts ) ;
return 0 ;
}
static struct spi_driver cyttsp_spi_driver = {
. driver = {
. name = CY_SPI_NAME ,
. pm = & cyttsp_pm_ops ,
} ,
. probe = cyttsp_spi_probe ,
} ;
2012-03-17 10:05:26 +04:00
module_spi_driver ( cyttsp_spi_driver ) ;
2012-01-31 12:18:00 +04:00
MODULE_LICENSE ( " GPL " ) ;
MODULE_DESCRIPTION ( " Cypress TrueTouch(R) Standard Product (TTSP) SPI driver " ) ;
MODULE_AUTHOR ( " Cypress " ) ;
MODULE_ALIAS ( " spi:cyttsp " ) ;