kernel_samsung_a34x-permissive/drivers/input/touchscreen/FT3518/focaltech_i2c.c
2024-04-28 15:51:13 +02:00

288 lines
7.3 KiB
C

/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2016 MediaTek Inc.
*/
/************************************************************************
*
* 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 DMA_BUFFER_LENGTH 256
#define I2C_RETRY_NUMBER 3
/*****************************************************************************
* Private enumerations, structures and unions using typedef
*****************************************************************************/
/*****************************************************************************
* Static variables
*****************************************************************************/
#ifdef CONFIG_MTK_I2C_EXTENSION
u8 *g_dma_buff_va;
dma_addr_t g_dma_buff_pa;
#endif
/*****************************************************************************
* Global variable or extern global variabls/functions
*****************************************************************************/
/*****************************************************************************
* Static function prototypes
*****************************************************************************/
/*****************************************************************************
* functions body
*****************************************************************************/
#ifdef CONFIG_MTK_I2C_EXTENSION
int fts_read(u8 *cmd, u32 cmdlen, u8 *data, u32 datalen)
{
int ret = 0;
int i = 0;
struct i2c_client *client = NULL;
/* must have data when read */
if (!fts_data || !fts_data->client || !data || !datalen) {
FTS_ERROR("fts_data/client/data/datalen(%d) is invalid",
datalen);
return -EINVAL;
}
client = fts_data->client;
mutex_lock(&fts_data->bus_lock);
if ((writelen > 0) && (writelen <= DMA_BUFFER_LENGTH)) {
memcpy(g_dma_buff_va, cmd, cmdlen);
client->addr = ((client->addr & I2C_MASK_FLAG) | I2C_DMA_FLAG);
for (i = 0; i < I2C_RETRY_NUMBER; i++) {
ret = i2c_master_send(client,
(unsigned char *)g_dma_buff_pa,
writelen);
if (ret != writelen) {
FTS_ERROR(
"[IIC]: i2c_master_send failed, ret=%d!!",
ret);
} else
break;
}
client->addr = client->addr & I2C_MASK_FLAG & (~I2C_DMA_FLAG);
}
if ((readlen > 0) && (readlen <= DMA_BUFFER_LENGTH)) {
client->addr = ((client->addr & I2C_MASK_FLAG) | I2C_DMA_FLAG);
for (i = 0; i < I2C_RETRY_NUMBER; i++) {
ret = i2c_master_recv(client,
(unsigned char *)g_dma_buff_pa,
datalen);
if (ret != readlen)
FTS_ERROR("i2c_master_recv failed,ret=%d", ret);
else
break;
}
memcpy(data, g_dma_buff_va, readlen);
client->addr = client->addr & I2C_MASK_FLAG & (~I2C_DMA_FLAG);
} else
FTS_ERROR("i2c read len(%d) fail", readlen);
mutex_unlock(&fts_data->bus_lock);
return ret;
}
int fts_i2c_write(u8 *writebuf, int writelen)
{
int ret = 0;
int i = 0;
struct i2c_client *client = NULL;
if (!fts_data || !fts_data->client || !writebuf || !writelen) {
FTS_ERROR("fts_data/client/data/datalen(%d) is invalid",
writelen);
return -EINVAL;
}
client = fts_data->client;
mutex_lock(&fts_data->bus_lock);
if ((writelen > 0) && (writelen <= DMA_BUFFER_LENGTH)) {
memcpy(g_dma_buff_va, writebuf, writelen);
client->addr = ((client->addr & I2C_MASK_FLAG) | I2C_DMA_FLAG);
for (i = 0; i < I2C_RETRY_NUMBER; i++) {
ret = i2c_master_send(client,
(unsigned char *)g_dma_buff_pa,
writelen);
if (ret != writelen)
FTS_ERROR("i2c_master_send failed,ret=%d", ret);
else
break;
}
client->addr = client->addr & I2C_MASK_FLAG & (~I2C_DMA_FLAG);
} else
FTS_ERROR("i2c write len(%d) fail", writelen);
mutex_unlock(&fts_data->bus_lock);
return ret;
}
static void fts_i2c_msg_dma_alloct(void)
{
FTS_FUNC_ENTER();
if (g_dma_buff_va == NULL) {
fts_data->input_dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
g_dma_buff_va = (u8 *)dma_alloc_coherent(
&fts_data->input_dev->dev, DMA_BUFFER_LENGTH,
&g_dma_buff_pa, GFP_KERNEL);
if (!g_dma_buff_va)
FTS_ERROR("Allocate DMA I2C Buffer failed");
}
FTS_FUNC_EXIT();
}
static void fts_i2c_msg_dma_release(void)
{
FTS_FUNC_ENTER();
if (g_dma_buff_va) {
dma_free_coherent(NULL, DMA_BUFFER_LENGTH, g_dma_buff_va,
g_dma_buff_pa);
g_dma_buff_va = NULL;
g_dma_buff_pa = 0;
FTS_ERROR("[IIC]: Allocated DMA I2C Buffer release!!");
}
FTS_FUNC_EXIT();
}
#else
int fts_read(u8 *cmd, u32 cmdlen, u8 *data, u32 datalen)
{
int ret = 0;
int i = 0;
struct i2c_client *client = NULL;
struct i2c_msg msg_list[2];
struct i2c_msg *msg = NULL;
int msg_num = 0;
/* must have data when read */
if (!fts_data || !fts_data->client || !data || !datalen) {
FTS_ERROR("fts_data/client/data/datalen(%d) is invalid",
datalen);
return -EINVAL;
}
client = fts_data->client;
mutex_lock(&fts_data->bus_lock);
memset(&msg_list[0], 0, sizeof(struct i2c_msg));
memset(&msg_list[1], 0, sizeof(struct i2c_msg));
msg_list[0].addr = client->addr;
msg_list[0].flags = 0;
msg_list[0].len = cmdlen;
msg_list[0].buf = cmd;
msg_list[1].addr = client->addr;
msg_list[1].flags = I2C_M_RD;
msg_list[1].len = datalen;
msg_list[1].buf = data;
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(client->adapter, msg, msg_num);
if (ret < 0)
FTS_ERROR("i2c_transfer(read) fail,ret:%d", ret);
else
break;
}
mutex_unlock(&fts_data->bus_lock);
return ret;
}
int fts_write(u8 *writebuf, u32 writelen)
{
int ret = 0;
int i = 0;
struct i2c_client *client = NULL;
struct i2c_msg msgs;
if (!fts_data || !fts_data->client || !writebuf || !writelen) {
FTS_ERROR("fts_data/client/data/datalen(%d) is invalid",
writelen);
return -EINVAL;
}
client = fts_data->client;
mutex_lock(&fts_data->bus_lock);
memset(&msgs, 0, sizeof(struct i2c_msg));
msgs.addr = client->addr;
msgs.flags = 0;
msgs.len = writelen;
msgs.buf = writebuf;
for (i = 0; i < I2C_RETRY_NUMBER; i++) {
ret = i2c_transfer(client->adapter, &msgs, 1);
if (ret < 0)
FTS_ERROR("i2c_transfer(write) fail,reg:%d", ret);
else
break;
}
mutex_unlock(&fts_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));
}
#endif
int fts_bus_init(struct fts_ts_data *ts_data)
{
FTS_FUNC_ENTER();
#ifdef CONFIG_MTK_I2C_EXTENSION
fts_i2c_msg_dma_alloct();
#endif
ts_data->bus_buf = NULL;
FTS_FUNC_EXIT();
return 0;
}
int fts_bus_exit(struct fts_ts_data *ts_data)
{
FTS_FUNC_ENTER();
#ifdef CONFIG_MTK_I2C_EXTENSION
fts_i2c_msg_dma_release();
#endif
FTS_FUNC_EXIT();
return 0;
}