193 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			193 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  *
 | |
|  * FocalTech TouchScreen driver.
 | |
|  *
 | |
|  * Copyright (c) 2012-2019, FocalTech Systems, Ltd., all rights reserved.
 | |
|  *
 | |
|  * This software is licensed under the terms of the GNU General Public
 | |
|  * License version 2, as published by the Free Software Foundation, and
 | |
|  * may be copied, distributed, and modified under those terms.
 | |
|  *
 | |
|  * This program is distributed in the hope that it will be useful,
 | |
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|  * GNU General Public License for more details.
 | |
|  *
 | |
|  */
 | |
| 
 | |
| /************************************************************************
 | |
| *
 | |
| * File Name: focaltech_i2c.c
 | |
| *
 | |
| * Author: Focaltech Driver Team
 | |
| *
 | |
| * Created: 2016-08-04
 | |
| *
 | |
| * Abstract: i2c communication with TP
 | |
| *
 | |
| * Version: v1.0
 | |
| *
 | |
| * Revision History:
 | |
| *
 | |
| ************************************************************************/
 | |
| 
 | |
| /*****************************************************************************
 | |
| * Included header files
 | |
| *****************************************************************************/
 | |
| #include "focaltech_core.h"
 | |
| 
 | |
| /*****************************************************************************
 | |
| * Private constant and macro definitions using #define
 | |
| *****************************************************************************/
 | |
| #define I2C_RETRY_NUMBER                    3
 | |
| #define I2C_BUF_LENGTH                      256
 | |
| 
 | |
| /*****************************************************************************
 | |
| * Private enumerations, structures and unions using typedef
 | |
| *****************************************************************************/
 | |
| 
 | |
| /*****************************************************************************
 | |
| * Static variables
 | |
| *****************************************************************************/
 | |
| 
 | |
| /*****************************************************************************
 | |
| * Global variable or extern global variabls/functions
 | |
| *****************************************************************************/
 | |
| 
 | |
| /*****************************************************************************
 | |
| * Static function prototypes
 | |
| *****************************************************************************/
 | |
| 
 | |
| /*****************************************************************************
 | |
| * functions body
 | |
| *****************************************************************************/
 | |
| int fts_read(u8 *cmd, u32 cmdlen, u8 *data, u32 datalen)
 | |
| {
 | |
|     int ret = 0;
 | |
|     int i = 0;
 | |
|     struct fts_ts_data *ts_data = fts_data;
 | |
|     struct i2c_msg msg_list[2];
 | |
|     struct i2c_msg *msg = NULL;
 | |
|     int msg_num = 0;
 | |
| 
 | |
|     /* must have data when read */
 | |
|     if (!ts_data || !ts_data->client || !data || !datalen
 | |
|         || (datalen >= I2C_BUF_LENGTH) || (cmdlen >= I2C_BUF_LENGTH)) {
 | |
|         FTS_ERROR("fts_data/client/cmdlen(%d)/data/datalen(%d) is invalid",
 | |
|                   cmdlen, datalen);
 | |
|         return -EINVAL;
 | |
|     }
 | |
| 
 | |
|     mutex_lock(&ts_data->bus_lock);
 | |
|     memset(&msg_list[0], 0, sizeof(struct i2c_msg));
 | |
|     memset(&msg_list[1], 0, sizeof(struct i2c_msg));
 | |
|     memcpy(ts_data->bus_tx_buf, cmd, cmdlen);
 | |
|     msg_list[0].addr = ts_data->client->addr;
 | |
|     msg_list[0].flags = 0;
 | |
|     msg_list[0].len = cmdlen;
 | |
|     msg_list[0].buf = ts_data->bus_tx_buf;
 | |
|     msg_list[1].addr = ts_data->client->addr;
 | |
|     msg_list[1].flags = I2C_M_RD;
 | |
|     msg_list[1].len = datalen;
 | |
|     msg_list[1].buf = ts_data->bus_rx_buf;
 | |
|     if (cmd && cmdlen) {
 | |
|         msg = &msg_list[0];
 | |
|         msg_num = 2;
 | |
|     } else {
 | |
|         msg = &msg_list[1];
 | |
|         msg_num = 1;
 | |
|     }
 | |
| 
 | |
|     for (i = 0; i < I2C_RETRY_NUMBER; i++) {
 | |
|         ret = i2c_transfer(ts_data->client->adapter, msg, msg_num);
 | |
|         if (ret < 0) {
 | |
|             FTS_ERROR("i2c_transfer(read) fail,ret:%d", ret);
 | |
|         } else {
 | |
|             memcpy(data, ts_data->bus_rx_buf, datalen);
 | |
|             break;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     mutex_unlock(&ts_data->bus_lock);
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| int fts_write(u8 *writebuf, u32 writelen)
 | |
| {
 | |
|     int ret = 0;
 | |
|     int i = 0;
 | |
|     struct fts_ts_data *ts_data = fts_data;
 | |
|     struct i2c_msg msgs;
 | |
| 
 | |
|     if (!ts_data || !ts_data->client || !writebuf || !writelen
 | |
|         || (writelen >= I2C_BUF_LENGTH)) {
 | |
|         FTS_ERROR("fts_data/client/data/datalen(%d) is invalid", writelen);
 | |
|         return -EINVAL;
 | |
|     }
 | |
| 
 | |
|     mutex_lock(&ts_data->bus_lock);
 | |
|     memset(&msgs, 0, sizeof(struct i2c_msg));
 | |
|     memcpy(ts_data->bus_tx_buf, writebuf, writelen);
 | |
|     msgs.addr = ts_data->client->addr;
 | |
|     msgs.flags = 0;
 | |
|     msgs.len = writelen;
 | |
|     msgs.buf = ts_data->bus_tx_buf;
 | |
|     for (i = 0; i < I2C_RETRY_NUMBER; i++) {
 | |
|         ret = i2c_transfer(ts_data->client->adapter, &msgs, 1);
 | |
|         if (ret < 0) {
 | |
|             FTS_ERROR("i2c_transfer(write) fail,ret:%d", ret);
 | |
|         } else {
 | |
|             break;
 | |
|         }
 | |
|     }
 | |
|     mutex_unlock(&ts_data->bus_lock);
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| int fts_read_reg(u8 addr, u8 *value)
 | |
| {
 | |
|     return fts_read(&addr, 1, value, 1);
 | |
| }
 | |
| 
 | |
| int fts_write_reg(u8 addr, u8 value)
 | |
| {
 | |
|     u8 buf[2] = { 0 };
 | |
| 
 | |
|     buf[0] = addr;
 | |
|     buf[1] = value;
 | |
|     return fts_write(buf, sizeof(buf));
 | |
| }
 | |
| 
 | |
| int fts_bus_init(struct fts_ts_data *ts_data)
 | |
| {
 | |
|     FTS_FUNC_ENTER();
 | |
|     ts_data->bus_tx_buf = kzalloc(I2C_BUF_LENGTH, GFP_KERNEL);
 | |
|     if (NULL == ts_data->bus_tx_buf) {
 | |
|         FTS_ERROR("failed to allocate memory for bus_tx_buf");
 | |
|         return -ENOMEM;
 | |
|     }
 | |
| 
 | |
|     ts_data->bus_rx_buf = kzalloc(I2C_BUF_LENGTH, GFP_KERNEL);
 | |
|     if (NULL == ts_data->bus_rx_buf) {
 | |
|         FTS_ERROR("failed to allocate memory for bus_rx_buf");
 | |
|         return -ENOMEM;
 | |
|     }
 | |
|     FTS_FUNC_EXIT();
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| int fts_bus_exit(struct fts_ts_data *ts_data)
 | |
| {
 | |
|     FTS_FUNC_ENTER();
 | |
|     if (ts_data && ts_data->bus_tx_buf) {
 | |
|         kfree(ts_data->bus_tx_buf);
 | |
|         ts_data->bus_tx_buf = NULL;
 | |
|     }
 | |
| 
 | |
|     if (ts_data && ts_data->bus_rx_buf) {
 | |
|         kfree(ts_data->bus_rx_buf);
 | |
|         ts_data->bus_rx_buf = NULL;
 | |
|     }
 | |
|     FTS_FUNC_EXIT();
 | |
|     return 0;
 | |
| } |