2019-06-04 10:11:33 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2014-10-03 13:24:27 -07:00
/*
* Elan I2C / SMBus Touchpad driver - SMBus interface
*
* Copyright ( c ) 2013 ELAN Microelectronics Corp .
*
* Author : 林 政 維 ( Duson Lin ) < dusonlin @ emc . com . tw >
*
* Based on cyapa driver :
* copyright ( c ) 2011 - 2012 Cypress Semiconductor , Inc .
* copyright ( c ) 2011 - 2012 Google , Inc .
*
* Trademarks are the property of their respective owners .
*/
# include <linux/delay.h>
# include <linux/i2c.h>
# include <linux/init.h>
# include <linux/kernel.h>
# include "elan_i2c.h"
/* Elan SMbus commands */
# define ETP_SMBUS_IAP_CMD 0x00
# define ETP_SMBUS_ENABLE_TP 0x20
# define ETP_SMBUS_SLEEP_CMD 0x21
# define ETP_SMBUS_IAP_PASSWORD_WRITE 0x29
# define ETP_SMBUS_IAP_PASSWORD_READ 0x80
# define ETP_SMBUS_WRITE_FW_BLOCK 0x2A
# define ETP_SMBUS_IAP_RESET_CMD 0x2B
# define ETP_SMBUS_RANGE_CMD 0xA0
# define ETP_SMBUS_FW_VERSION_CMD 0xA1
# define ETP_SMBUS_XY_TRACENUM_CMD 0xA2
# define ETP_SMBUS_SM_VERSION_CMD 0xA3
# define ETP_SMBUS_UNIQUEID_CMD 0xA3
# define ETP_SMBUS_RESOLUTION_CMD 0xA4
# define ETP_SMBUS_HELLOPACKET_CMD 0xA7
# define ETP_SMBUS_PACKET_QUERY 0xA8
# define ETP_SMBUS_IAP_VERSION_CMD 0xAC
# define ETP_SMBUS_IAP_CTRL_CMD 0xAD
# define ETP_SMBUS_IAP_CHECKSUM_CMD 0xAE
# define ETP_SMBUS_FW_CHECKSUM_CMD 0xAF
# define ETP_SMBUS_MAX_BASELINE_CMD 0xC3
# define ETP_SMBUS_MIN_BASELINE_CMD 0xC4
# define ETP_SMBUS_CALIBRATE_QUERY 0xC5
# define ETP_SMBUS_REPORT_LEN 32
2020-12-10 23:40:09 -08:00
# define ETP_SMBUS_REPORT_LEN2 7
2014-10-03 13:24:27 -07:00
# define ETP_SMBUS_REPORT_OFFSET 2
# define ETP_SMBUS_HELLOPACKET_LEN 5
# define ETP_SMBUS_IAP_PASSWORD 0x1234
# define ETP_SMBUS_IAP_MODE_ON (1 << 6)
static int elan_smbus_initialize ( struct i2c_client * client )
{
u8 check [ ETP_SMBUS_HELLOPACKET_LEN ] = { 0x55 , 0x55 , 0x55 , 0x55 , 0x55 } ;
2018-06-19 11:17:32 -07:00
u8 values [ I2C_SMBUS_BLOCK_MAX ] = { 0 } ;
2014-10-03 13:24:27 -07:00
int len , error ;
/* Get hello packet */
len = i2c_smbus_read_block_data ( client ,
ETP_SMBUS_HELLOPACKET_CMD , values ) ;
if ( len ! = ETP_SMBUS_HELLOPACKET_LEN ) {
dev_err ( & client - > dev , " hello packet length fail: %d \n " , len ) ;
error = len < 0 ? len : - EIO ;
return error ;
}
/* compare hello packet */
if ( memcmp ( values , check , ETP_SMBUS_HELLOPACKET_LEN ) ) {
2015-02-06 08:39:20 -08:00
dev_err ( & client - > dev , " hello packet fail [%*ph] \n " ,
2014-10-03 13:24:27 -07:00
ETP_SMBUS_HELLOPACKET_LEN , values ) ;
return - ENXIO ;
}
/* enable tp */
error = i2c_smbus_write_byte ( client , ETP_SMBUS_ENABLE_TP ) ;
if ( error ) {
dev_err ( & client - > dev , " failed to enable touchpad: %d \n " , error ) ;
return error ;
}
return 0 ;
}
static int elan_smbus_set_mode ( struct i2c_client * client , u8 mode )
{
u8 cmd [ 4 ] = { 0x00 , 0x07 , 0x00 , mode } ;
return i2c_smbus_write_block_data ( client , ETP_SMBUS_IAP_CMD ,
sizeof ( cmd ) , cmd ) ;
}
static int elan_smbus_sleep_control ( struct i2c_client * client , bool sleep )
{
if ( sleep )
return i2c_smbus_write_byte ( client , ETP_SMBUS_SLEEP_CMD ) ;
else
return 0 ; /* XXX should we send ETP_SMBUS_ENABLE_TP here? */
}
static int elan_smbus_power_control ( struct i2c_client * client , bool enable )
{
return 0 ; /* A no-op */
}
static int elan_smbus_calibrate ( struct i2c_client * client )
{
u8 cmd [ 4 ] = { 0x00 , 0x08 , 0x00 , 0x01 } ;
return i2c_smbus_write_block_data ( client , ETP_SMBUS_IAP_CMD ,
sizeof ( cmd ) , cmd ) ;
}
static int elan_smbus_calibrate_result ( struct i2c_client * client , u8 * val )
{
int error ;
2018-06-19 11:17:32 -07:00
u8 buf [ I2C_SMBUS_BLOCK_MAX ] = { 0 } ;
BUILD_BUG_ON ( ETP_CALIBRATE_MAX_LEN > sizeof ( buf ) ) ;
2014-10-03 13:24:27 -07:00
error = i2c_smbus_read_block_data ( client ,
2018-06-19 11:17:32 -07:00
ETP_SMBUS_CALIBRATE_QUERY , buf ) ;
2014-10-03 13:24:27 -07:00
if ( error < 0 )
return error ;
2018-06-19 11:17:32 -07:00
memcpy ( val , buf , ETP_CALIBRATE_MAX_LEN ) ;
2014-10-03 13:24:27 -07:00
return 0 ;
}
static int elan_smbus_get_baseline_data ( struct i2c_client * client ,
bool max_baseline , u8 * value )
{
int error ;
2018-05-22 17:19:57 -07:00
u8 val [ I2C_SMBUS_BLOCK_MAX ] = { 0 } ;
2014-10-03 13:24:27 -07:00
error = i2c_smbus_read_block_data ( client ,
max_baseline ?
ETP_SMBUS_MAX_BASELINE_CMD :
ETP_SMBUS_MIN_BASELINE_CMD ,
val ) ;
if ( error < 0 )
return error ;
* value = be16_to_cpup ( ( __be16 * ) val ) ;
return 0 ;
}
static int elan_smbus_get_version ( struct i2c_client * client ,
2020-07-20 14:56:54 -07:00
u8 pattern , bool iap , u8 * version )
2014-10-03 13:24:27 -07:00
{
int error ;
2018-05-22 17:19:57 -07:00
u8 val [ I2C_SMBUS_BLOCK_MAX ] = { 0 } ;
2014-10-03 13:24:27 -07:00
error = i2c_smbus_read_block_data ( client ,
iap ? ETP_SMBUS_IAP_VERSION_CMD :
ETP_SMBUS_FW_VERSION_CMD ,
val ) ;
if ( error < 0 ) {
dev_err ( & client - > dev , " failed to get %s version: %d \n " ,
iap ? " IAP " : " FW " , error ) ;
return error ;
}
* version = val [ 2 ] ;
return 0 ;
}
2020-07-20 14:56:54 -07:00
static int elan_smbus_get_sm_version ( struct i2c_client * client , u8 pattern ,
u16 * ic_type , u8 * version , u8 * clickpad )
2014-10-03 13:24:27 -07:00
{
int error ;
2018-05-22 17:19:57 -07:00
u8 val [ I2C_SMBUS_BLOCK_MAX ] = { 0 } ;
2014-10-03 13:24:27 -07:00
error = i2c_smbus_read_block_data ( client ,
ETP_SMBUS_SM_VERSION_CMD , val ) ;
if ( error < 0 ) {
dev_err ( & client - > dev , " failed to get SM version: %d \n " , error ) ;
return error ;
}
2015-06-08 16:39:35 -07:00
* version = val [ 0 ] ;
* ic_type = val [ 1 ] ;
2017-08-18 16:49:53 -07:00
* clickpad = val [ 0 ] & 0x10 ;
2014-10-03 13:24:27 -07:00
return 0 ;
}
2015-09-21 09:26:46 -07:00
static int elan_smbus_get_product_id ( struct i2c_client * client , u16 * id )
2014-10-03 13:24:27 -07:00
{
int error ;
2018-05-22 17:19:57 -07:00
u8 val [ I2C_SMBUS_BLOCK_MAX ] = { 0 } ;
2014-10-03 13:24:27 -07:00
error = i2c_smbus_read_block_data ( client ,
ETP_SMBUS_UNIQUEID_CMD , val ) ;
if ( error < 0 ) {
dev_err ( & client - > dev , " failed to get product ID: %d \n " , error ) ;
return error ;
}
2015-09-21 09:26:46 -07:00
* id = be16_to_cpup ( ( __be16 * ) val ) ;
2014-10-03 13:24:27 -07:00
return 0 ;
}
static int elan_smbus_get_checksum ( struct i2c_client * client ,
bool iap , u16 * csum )
{
int error ;
2018-05-22 17:19:57 -07:00
u8 val [ I2C_SMBUS_BLOCK_MAX ] = { 0 } ;
2014-10-03 13:24:27 -07:00
error = i2c_smbus_read_block_data ( client ,
iap ? ETP_SMBUS_FW_CHECKSUM_CMD :
ETP_SMBUS_IAP_CHECKSUM_CMD ,
val ) ;
if ( error < 0 ) {
dev_err ( & client - > dev , " failed to get %s checksum: %d \n " ,
iap ? " IAP " : " FW " , error ) ;
return error ;
}
* csum = be16_to_cpup ( ( __be16 * ) val ) ;
return 0 ;
}
static int elan_smbus_get_max ( struct i2c_client * client ,
unsigned int * max_x , unsigned int * max_y )
{
2016-09-30 16:42:19 -07:00
int ret ;
2014-10-03 13:24:27 -07:00
int error ;
2018-05-22 17:19:57 -07:00
u8 val [ I2C_SMBUS_BLOCK_MAX ] = { 0 } ;
2014-10-03 13:24:27 -07:00
2016-09-30 16:42:19 -07:00
ret = i2c_smbus_read_block_data ( client , ETP_SMBUS_RANGE_CMD , val ) ;
if ( ret ! = 3 ) {
error = ret < 0 ? ret : - EIO ;
2014-10-03 13:24:27 -07:00
dev_err ( & client - > dev , " failed to get dimensions: %d \n " , error ) ;
return error ;
}
* max_x = ( 0x0f & val [ 0 ] ) < < 8 | val [ 1 ] ;
* max_y = ( 0xf0 & val [ 0 ] ) < < 4 | val [ 2 ] ;
return 0 ;
}
static int elan_smbus_get_resolution ( struct i2c_client * client ,
u8 * hw_res_x , u8 * hw_res_y )
{
2016-09-30 16:42:19 -07:00
int ret ;
2014-10-03 13:24:27 -07:00
int error ;
2018-05-22 17:19:57 -07:00
u8 val [ I2C_SMBUS_BLOCK_MAX ] = { 0 } ;
2014-10-03 13:24:27 -07:00
2016-09-30 16:42:19 -07:00
ret = i2c_smbus_read_block_data ( client , ETP_SMBUS_RESOLUTION_CMD , val ) ;
if ( ret ! = 3 ) {
error = ret < 0 ? ret : - EIO ;
2014-10-03 13:24:27 -07:00
dev_err ( & client - > dev , " failed to get resolution: %d \n " , error ) ;
return error ;
}
* hw_res_x = val [ 1 ] & 0x0F ;
* hw_res_y = ( val [ 1 ] & 0xF0 ) > > 4 ;
return 0 ;
}
static int elan_smbus_get_num_traces ( struct i2c_client * client ,
unsigned int * x_traces ,
unsigned int * y_traces )
{
2016-09-30 16:42:19 -07:00
int ret ;
2014-10-03 13:24:27 -07:00
int error ;
2018-05-22 17:19:57 -07:00
u8 val [ I2C_SMBUS_BLOCK_MAX ] = { 0 } ;
2014-10-03 13:24:27 -07:00
2016-09-30 16:42:19 -07:00
ret = i2c_smbus_read_block_data ( client , ETP_SMBUS_XY_TRACENUM_CMD , val ) ;
if ( ret ! = 3 ) {
error = ret < 0 ? ret : - EIO ;
2014-10-03 13:24:27 -07:00
dev_err ( & client - > dev , " failed to get trace info: %d \n " , error ) ;
return error ;
}
2015-04-20 10:19:24 -07:00
* x_traces = val [ 1 ] ;
* y_traces = val [ 2 ] ;
2014-10-03 13:24:27 -07:00
return 0 ;
}
2015-04-12 16:01:05 -07:00
static int elan_smbus_get_pressure_adjustment ( struct i2c_client * client ,
int * adjustment )
{
* adjustment = ETP_PRESSURE_OFFSET ;
return 0 ;
}
2014-10-03 13:24:27 -07:00
static int elan_smbus_iap_get_mode ( struct i2c_client * client ,
enum tp_mode * mode )
{
int error ;
u16 constant ;
2018-05-22 17:19:57 -07:00
u8 val [ I2C_SMBUS_BLOCK_MAX ] = { 0 } ;
2014-10-03 13:24:27 -07:00
error = i2c_smbus_read_block_data ( client , ETP_SMBUS_IAP_CTRL_CMD , val ) ;
if ( error < 0 ) {
dev_err ( & client - > dev , " failed to read iap ctrol register: %d \n " ,
error ) ;
return error ;
}
constant = be16_to_cpup ( ( __be16 * ) val ) ;
dev_dbg ( & client - > dev , " iap control reg: 0x%04x. \n " , constant ) ;
* mode = ( constant & ETP_SMBUS_IAP_MODE_ON ) ? IAP_MODE : MAIN_MODE ;
return 0 ;
}
static int elan_smbus_iap_reset ( struct i2c_client * client )
{
int error ;
error = i2c_smbus_write_byte ( client , ETP_SMBUS_IAP_RESET_CMD ) ;
if ( error ) {
dev_err ( & client - > dev , " cannot reset IC: %d \n " , error ) ;
return error ;
}
return 0 ;
}
static int elan_smbus_set_flash_key ( struct i2c_client * client )
{
int error ;
u8 cmd [ 4 ] = { 0x00 , 0x0B , 0x00 , 0x5A } ;
error = i2c_smbus_write_block_data ( client , ETP_SMBUS_IAP_CMD ,
sizeof ( cmd ) , cmd ) ;
if ( error ) {
dev_err ( & client - > dev , " cannot set flash key: %d \n " , error ) ;
return error ;
}
return 0 ;
}
2020-07-16 22:49:09 -07:00
static int elan_smbus_prepare_fw_update ( struct i2c_client * client , u16 ic_type ,
2020-11-11 20:06:24 -08:00
u8 iap_version , u16 fw_page_size )
2014-10-03 13:24:27 -07:00
{
struct device * dev = & client - > dev ;
int len ;
int error ;
enum tp_mode mode ;
2018-05-22 17:19:57 -07:00
u8 val [ I2C_SMBUS_BLOCK_MAX ] = { 0 } ;
2014-10-03 13:24:27 -07:00
u8 cmd [ 4 ] = { 0x0F , 0x78 , 0x00 , 0x06 } ;
u16 password ;
/* Get FW in which mode (IAP_MODE/MAIN_MODE) */
error = elan_smbus_iap_get_mode ( client , & mode ) ;
if ( error )
return error ;
if ( mode = = MAIN_MODE ) {
/* set flash key */
error = elan_smbus_set_flash_key ( client ) ;
if ( error )
return error ;
/* write iap password */
if ( i2c_smbus_write_byte ( client ,
ETP_SMBUS_IAP_PASSWORD_WRITE ) < 0 ) {
dev_err ( dev , " cannot write iap password \n " ) ;
return - EIO ;
}
error = i2c_smbus_write_block_data ( client , ETP_SMBUS_IAP_CMD ,
sizeof ( cmd ) , cmd ) ;
if ( error ) {
dev_err ( dev , " failed to write iap password: %d \n " ,
error ) ;
return error ;
}
/*
* Read back password to make sure we enabled flash
* successfully .
*/
len = i2c_smbus_read_block_data ( client ,
ETP_SMBUS_IAP_PASSWORD_READ ,
val ) ;
2018-08-01 15:57:43 -07:00
if ( len < ( int ) sizeof ( u16 ) ) {
2014-10-03 13:24:27 -07:00
error = len < 0 ? len : - EIO ;
dev_err ( dev , " failed to read iap password: %d \n " ,
error ) ;
return error ;
}
password = be16_to_cpup ( ( __be16 * ) val ) ;
if ( password ! = ETP_SMBUS_IAP_PASSWORD ) {
dev_err ( dev , " wrong iap password = 0x%X \n " , password ) ;
return - EIO ;
}
/* Wait 30ms for MAIN_MODE change to IAP_MODE */
msleep ( 30 ) ;
}
error = elan_smbus_set_flash_key ( client ) ;
if ( error )
return error ;
/* Reset IC */
error = elan_smbus_iap_reset ( client ) ;
if ( error )
return error ;
return 0 ;
}
2020-07-16 21:32:23 -07:00
static int elan_smbus_write_fw_block ( struct i2c_client * client , u16 fw_page_size ,
2014-10-03 13:24:27 -07:00
const u8 * page , u16 checksum , int idx )
{
struct device * dev = & client - > dev ;
int error ;
u16 result ;
2018-05-22 17:19:57 -07:00
u8 val [ I2C_SMBUS_BLOCK_MAX ] = { 0 } ;
2014-10-03 13:24:27 -07:00
/*
* Due to the limitation of smbus protocol limiting
* transfer to 32 bytes at a time , we must split block
* in 2 transfers .
*/
error = i2c_smbus_write_block_data ( client ,
ETP_SMBUS_WRITE_FW_BLOCK ,
2020-07-16 21:32:23 -07:00
fw_page_size / 2 ,
2014-10-03 13:24:27 -07:00
page ) ;
if ( error ) {
dev_err ( dev , " Failed to write page %d (part %d): %d \n " ,
idx , 1 , error ) ;
return error ;
}
error = i2c_smbus_write_block_data ( client ,
ETP_SMBUS_WRITE_FW_BLOCK ,
2020-07-16 21:32:23 -07:00
fw_page_size / 2 ,
page + fw_page_size / 2 ) ;
2014-10-03 13:24:27 -07:00
if ( error ) {
dev_err ( dev , " Failed to write page %d (part %d): %d \n " ,
idx , 2 , error ) ;
return error ;
}
/* Wait for F/W to update one page ROM data. */
usleep_range ( 8000 , 10000 ) ;
error = i2c_smbus_read_block_data ( client ,
ETP_SMBUS_IAP_CTRL_CMD , val ) ;
if ( error < 0 ) {
dev_err ( dev , " Failed to read IAP write result: %d \n " ,
error ) ;
return error ;
}
result = be16_to_cpup ( ( __be16 * ) val ) ;
if ( result & ( ETP_FW_IAP_PAGE_ERR | ETP_FW_IAP_INTF_ERR ) ) {
dev_err ( dev , " IAP reports failed write: %04hx \n " ,
result ) ;
return - EIO ;
}
return 0 ;
}
2020-07-20 12:46:10 -07:00
static int elan_smbus_get_report_features ( struct i2c_client * client , u8 pattern ,
unsigned int * features ,
unsigned int * report_len )
{
/*
* SMBus controllers with pattern 2 lack area info , as newer
* high - precision packets use that space for coordinates .
*/
* features = pattern < = 0x01 ? ETP_FEATURE_REPORT_MK : 0 ;
* report_len = ETP_SMBUS_REPORT_LEN ;
return 0 ;
}
static int elan_smbus_get_report ( struct i2c_client * client ,
u8 * report , unsigned int report_len )
2014-10-03 13:24:27 -07:00
{
int len ;
2018-06-19 11:17:32 -07:00
BUILD_BUG_ON ( I2C_SMBUS_BLOCK_MAX > ETP_SMBUS_REPORT_LEN ) ;
2014-10-03 13:24:27 -07:00
len = i2c_smbus_read_block_data ( client ,
ETP_SMBUS_PACKET_QUERY ,
& report [ ETP_SMBUS_REPORT_OFFSET ] ) ;
if ( len < 0 ) {
dev_err ( & client - > dev , " failed to read report data: %d \n " , len ) ;
return len ;
}
2020-12-10 23:40:09 -08:00
if ( report [ ETP_REPORT_ID_OFFSET ] = = ETP_TP_REPORT_ID2 )
report_len = ETP_SMBUS_REPORT_LEN2 ;
if ( len ! = report_len ) {
2014-10-03 13:24:27 -07:00
dev_err ( & client - > dev ,
" wrong report length (%d vs %d expected) \n " ,
2020-12-10 23:40:09 -08:00
len , report_len ) ;
2014-10-03 13:24:27 -07:00
return - EIO ;
}
return 0 ;
}
static int elan_smbus_finish_fw_update ( struct i2c_client * client ,
struct completion * fw_completion )
{
/* No special handling unlike I2C transport */
return 0 ;
}
2016-11-27 20:59:29 -08:00
static int elan_smbus_get_pattern ( struct i2c_client * client , u8 * pattern )
{
* pattern = 0 ;
return 0 ;
}
2014-10-03 13:24:27 -07:00
const struct elan_transport_ops elan_smbus_ops = {
. initialize = elan_smbus_initialize ,
. sleep_control = elan_smbus_sleep_control ,
. power_control = elan_smbus_power_control ,
. set_mode = elan_smbus_set_mode ,
. calibrate = elan_smbus_calibrate ,
. calibrate_result = elan_smbus_calibrate_result ,
. get_baseline_data = elan_smbus_get_baseline_data ,
. get_version = elan_smbus_get_version ,
. get_sm_version = elan_smbus_get_sm_version ,
. get_product_id = elan_smbus_get_product_id ,
. get_checksum = elan_smbus_get_checksum ,
2015-04-12 16:01:05 -07:00
. get_pressure_adjustment = elan_smbus_get_pressure_adjustment ,
2014-10-03 13:24:27 -07:00
. get_max = elan_smbus_get_max ,
. get_resolution = elan_smbus_get_resolution ,
. get_num_traces = elan_smbus_get_num_traces ,
. iap_get_mode = elan_smbus_iap_get_mode ,
. iap_reset = elan_smbus_iap_reset ,
. prepare_fw_update = elan_smbus_prepare_fw_update ,
. write_fw_block = elan_smbus_write_fw_block ,
. finish_fw_update = elan_smbus_finish_fw_update ,
2020-07-20 12:46:10 -07:00
. get_report_features = elan_smbus_get_report_features ,
2014-10-03 13:24:27 -07:00
. get_report = elan_smbus_get_report ,
2016-11-27 20:59:29 -08:00
. get_pattern = elan_smbus_get_pattern ,
2014-10-03 13:24:27 -07:00
} ;