342 lines
10 KiB
C
342 lines
10 KiB
C
/*
|
|
* ESWIN EPH861X series Touchscreen driver
|
|
*
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the
|
|
* Free Software Foundation; either version 2 of the License, or (at your
|
|
* option) any later version.
|
|
*
|
|
*/
|
|
|
|
// uncomment to enable the dev_dbg prints to dmesg
|
|
#define DEBUG
|
|
// uncomment to test with input forced open
|
|
//#define INPUT_DEVICE_ALWAYS_OPEN
|
|
#include <linux/types.h>
|
|
|
|
|
|
|
|
#include <uapi/asm-generic/errno-base.h>
|
|
#include <linux/kernel.h>
|
|
#include <uapi/linux/input-event-codes.h>
|
|
|
|
#include <linux/sysfs.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/gfp.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/dmapool.h>
|
|
#include <linux/dma-mapping.h>
|
|
|
|
#include "eswin_eph861x_tlv.h"
|
|
#include "eswin_eph861x_types.h"
|
|
#include "eswin_eph861x_project_config.h"
|
|
#include "eswin_eph861x_comms.h"
|
|
|
|
struct dma_pool *pool_rx;
|
|
struct dma_pool *pool_tx;
|
|
|
|
|
|
struct tlv_header eph_get_tl_header_info(struct eph_data *ephdata, u8 *message)
|
|
{
|
|
struct tlv_header tlvheader;
|
|
|
|
tlvheader.type = message[TLV_TYPE_FIELD];
|
|
tlvheader.length = (u16)min((int)((int)(message[TLV_LENGTH_FIELD] | ((u16)message[(TLV_LENGTH_FIELD+1)] << 8u)) + TLV_HEADER_SIZE), 0xFFFF); // little endian 16
|
|
|
|
return tlvheader;
|
|
}
|
|
|
|
|
|
int eph_comms_two_stage_read(struct eph_data *ephdata, u8 *buf)
|
|
{
|
|
int ret_val = 0;
|
|
struct tlv_header tlvheader = {0};
|
|
u16 length;
|
|
|
|
/* River will do TL then TLV so header length - Decode length etc */
|
|
/* offset not used for header */
|
|
// note: SPI has difference with i2c, SPI read success return 0,but i2c retutn read count // add by hh
|
|
ret_val = eph_comms_read(ephdata, sizeof(struct tlv_header),(u8*)&tlvheader);
|
|
#if 0
|
|
dev_dbg(&ephdata->commsdevice->dev,
|
|
"ESWIN - eph_comms_two_stage_read first stage type: %d, length: %d, ret_val %d ",
|
|
tlvheader.type, tlvheader.length, ret_val);
|
|
#endif
|
|
if (!ret_val)
|
|
{
|
|
/* saturate to 16 bit type */
|
|
/* if device isnt connected then this can overflow without the saturation */
|
|
length = (u16)min((int)((int)le16_to_cpu(tlvheader.length) + TLV_HEADER_SIZE), 0xFFFF);
|
|
|
|
/* wait a delay for TIC to be ready */
|
|
udelay(50);
|
|
#if 0
|
|
dev_info(&ephdata->commsdevice->dev,
|
|
"eph_comms_two_stage_read: type: %u length: %u ",
|
|
tlvheader.type, length);
|
|
#endif
|
|
/* do a read */
|
|
/* Read control configuration response */
|
|
ret_val = eph_comms_read(ephdata, length, buf);
|
|
#if 0
|
|
dev_dbg(&ephdata->commsdevice->dev,
|
|
"eph_comms_two_stage_read: ESWIN - eph_comms_two_stage_read second stage ret_val %d, Type 0x%x, length_LSB 0x%x, length_MSB 0x%x, buff[3] 0x%x, buff[4] 0x%x, buff[5] 0x%x, buff[6] 0x%x, buff[7] 0x%x, buff[8] 0x%x, buff[9] 0x%x, buff[10] 0x%x, buff[11] 0x%x",
|
|
ret_val, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]);
|
|
#endif
|
|
if (ret_val)
|
|
{
|
|
dev_err(&ephdata->commsdevice->dev, "eph_comms_two_stage_read: Failed to read payload: (%d)", ret_val);
|
|
} else {
|
|
// bugfix: spi clk low when start to transfer data
|
|
if ((buf[0] == buf[0+TLV_HEADER_SIZE]) && (buf[1] == buf[1+TLV_HEADER_SIZE]) && (buf[2] == buf[2+TLV_HEADER_SIZE])) {
|
|
uint16_t data_length = buf[TLV_LENGTH_FIELD] | ((uint16_t)buf[TLV_LENGTH_FIELD+1] << 8);
|
|
for (int i = 0; i < data_length; i++) {
|
|
buf[i] = buf[i+TLV_HEADER_SIZE];
|
|
}
|
|
ret_val = eph_comms_read(ephdata, TLV_HEADER_SIZE, &buf[data_length]);
|
|
//dev_info(&ephdata->commsdevice->dev, "glued the data %d %d %d", buf[0], buf[1], buf[2]);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dev_err(&ephdata->commsdevice->dev, "eph_comms_two_stage_read: Failed to read header: (%d)", ret_val);
|
|
}
|
|
|
|
return ret_val;
|
|
}
|
|
|
|
|
|
|
|
int eph_read_report(struct eph_data *ephdata, u8 *buf)
|
|
{
|
|
int ret_val = 0;
|
|
|
|
/* Part of interrupt handling - No error handling. If message cant be decoded then it will be discsarded */
|
|
/* no read offset required ----- always part of the command aspect */
|
|
ret_val = eph_comms_two_stage_read(ephdata, buf);
|
|
|
|
|
|
return ret_val;
|
|
|
|
}
|
|
|
|
|
|
u8 eph_read_chg(struct eph_data *ephdata)
|
|
{
|
|
u8 ret_val = (u8)gpio_get_value(ephdata->ephplatform->gpio_chg_irq);
|
|
return ret_val;
|
|
}
|
|
|
|
int eph_wait_for_chg(struct eph_data *ephdata)
|
|
{
|
|
int timeout_counter = 25000; // 500 msec
|
|
|
|
while (0 != eph_read_chg(ephdata) && timeout_counter > 0)
|
|
{
|
|
timeout_counter--;
|
|
udelay(20);
|
|
}
|
|
|
|
return timeout_counter > 0 ? 0 : -1;
|
|
}
|
|
|
|
u32 ctl_data[2] = { 200, 0 };
|
|
|
|
int eph_comms_specific_checks(struct comms_device *commsdevice)
|
|
{
|
|
int ret_val;
|
|
#if (ESWIN_EPH861X_SPI)
|
|
#if 0//KERNEL_VERSION(5, 15, 0) >= LINUX_VERSION_CODE
|
|
struct spi_delay d;
|
|
d.value = 100;
|
|
d.unit = SPI_DELAY_UNIT_USECS;
|
|
commsdevice->cs_setup = d;
|
|
pr_err("eph_comms_specific_checks----11a----\n");
|
|
#else
|
|
//pr_err("eph_add 100us delay----\n");
|
|
commsdevice->controller_data = ctl_data;
|
|
#endif
|
|
commsdevice->mode = 3;
|
|
//commsdevice->chip_select = 0;
|
|
ret_val = eph_comms_specific_checks_spi(commsdevice);
|
|
#endif
|
|
#if (ESWIN_EPH861X_I2C)
|
|
ret_val = eph_comms_specific_checks_i2c(commsdevice);
|
|
#endif
|
|
#if ((ESWIN_EPH861X_SPI) && (ESWIN_EPH861X_I2C))
|
|
#error " Must select only SPI or I2C "
|
|
#endif
|
|
#if (!((ESWIN_EPH861X_SPI) || (ESWIN_EPH861X_I2C)))
|
|
#error " Must select SPI or I2C "
|
|
#endif
|
|
|
|
return ret_val;
|
|
}
|
|
|
|
void eph_comms_driver_data_set(struct comms_device *commsdevice, struct eph_data *ephdata)
|
|
{
|
|
|
|
#if (ESWIN_EPH861X_SPI)
|
|
eph_comms_driver_data_set_spi(commsdevice, ephdata);
|
|
#endif
|
|
#if (ESWIN_EPH861X_I2C)
|
|
eph_comms_driver_data_set_i2c(commsdevice, ephdata);
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
struct eph_data* eph_comms_driver_data_get(struct comms_device *commsdevice)
|
|
{
|
|
|
|
#if (ESWIN_EPH861X_SPI)
|
|
struct eph_data* ephdata = eph_comms_driver_data_get_spi(commsdevice);
|
|
#endif
|
|
#if (ESWIN_EPH861X_I2C)
|
|
struct eph_data* ephdata = eph_comms_driver_data_get_i2c(commsdevice);
|
|
#endif
|
|
|
|
return ephdata;
|
|
}
|
|
|
|
|
|
struct comms_device* eph_comms_device_get(struct device *dev)
|
|
{
|
|
|
|
#if (ESWIN_EPH861X_SPI)
|
|
struct comms_device *commsdevice = eph_comms_device_get_spi(dev);
|
|
#endif
|
|
#if (ESWIN_EPH861X_I2C)
|
|
struct comms_device *commsdevice = eph_comms_device_get_i2c(dev);
|
|
#endif
|
|
|
|
return commsdevice;
|
|
}
|
|
|
|
char* eph_comms_devicename_get(struct eph_data *ephdata)
|
|
{
|
|
char * commsdevice_name;
|
|
|
|
#if (ESWIN_EPH861X_SPI)
|
|
commsdevice_name = ephdata->commsdevice->modalias;
|
|
#endif
|
|
#if (ESWIN_EPH861X_I2C)
|
|
commsdevice_name = ephdata->commsdevice->name;
|
|
#endif
|
|
|
|
return commsdevice_name;
|
|
}
|
|
|
|
int eph_comms_specific_bootloader_checks(struct eph_data *ephdata)
|
|
{
|
|
|
|
#if (ESWIN_EPH861X_SPI)
|
|
int ret_val = eph_comms_specific_bootloader_checks_spi(ephdata);
|
|
#endif
|
|
#if (ESWIN_EPH861X_I2C)
|
|
int ret_val = eph_comms_specific_bootloader_checks_i2c(ephdata);
|
|
#endif
|
|
|
|
return ret_val;
|
|
}
|
|
|
|
|
|
u8 eph_get_data_crc(uint8_t* p_msg, size_t size)
|
|
{
|
|
u8 calc_crc = 0;
|
|
int i;
|
|
for (i = 0; i < size; i++)
|
|
{
|
|
calc_crc = get_crc8_iter(calc_crc, p_msg[i]);
|
|
}
|
|
return calc_crc;
|
|
}
|
|
|
|
|
|
u8 get_crc8_iter(u8 crc, u8 data)
|
|
{
|
|
static const u8 crcpoly = 0x8c;
|
|
u8 index = 8;
|
|
u8 fb;
|
|
do
|
|
{
|
|
fb = (crc ^ data) & 0x01;
|
|
data >>= 1;
|
|
crc >>= 1;
|
|
if (fb)
|
|
{
|
|
crc ^= crcpoly;
|
|
}
|
|
} while (--index);
|
|
return crc;
|
|
}
|
|
|
|
int eph_allocate_comms_memory(struct comms_device *commsdevice, struct eph_data *ephdata)
|
|
{
|
|
int ret_val = 0;
|
|
|
|
ephdata->comms_send_crc_buf = (u8*)kcalloc(COMMS_BUF_WRITE_SIZE, sizeof(ephdata->comms_send_crc_buf), GFP_KERNEL);
|
|
if (NULL == ephdata->comms_send_crc_buf)
|
|
{
|
|
return -ENOMEM;
|
|
}
|
|
|
|
ephdata->report_buf = (u8*)kcalloc(COMMS_BUF_SIZE, sizeof(ephdata->report_buf), GFP_KERNEL);
|
|
if (NULL == ephdata->report_buf)
|
|
{
|
|
return -ENOMEM;
|
|
}
|
|
|
|
#if (ESWIN_EPH861X_SPI && ESWIN_EPH861X_SPI_USE_DMA)
|
|
//TODO configuration for DMA should not be needed in generic driver and the following can be consolodated into single pool
|
|
/* Configure DMA for SPI */
|
|
arch_setup_dma_ops(&commsdevice->dev, 0, U64_MAX, NULL, true);
|
|
|
|
ret_val = dma_coerce_mask_and_coherent(&commsdevice->dev,
|
|
DMA_BIT_MASK(32));
|
|
if (ret_val)
|
|
{
|
|
dev_err(&commsdevice->dev, "%s. dma_coerce_mask_and_coherent failed\n", __func__);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
/* Create memory pool */
|
|
pool_rx = dma_pool_create("create_comms_receive_buf", &ephdata->commsdevice->dev, COMMS_BUF_SIZE,
|
|
0 /* byte alignment */,
|
|
0 /* no page-crossing issues */);
|
|
|
|
/* Allocate memory from pool */
|
|
ephdata->comms_receive_buf = (u8*)dma_pool_alloc(pool_rx, GFP_KERNEL, &ephdata->comms_dma_handle_rx);
|
|
if (NULL == ephdata->comms_receive_buf)
|
|
{
|
|
dev_err(&commsdevice->dev, "%s comms_receive_buf memory allocation failed \n", __func__);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
/* Create memory pool */
|
|
pool_tx = dma_pool_create("create_comms_send_buf", &ephdata->commsdevice->dev, COMMS_BUF_WRITE_SIZE,
|
|
0 /* byte alignment */,
|
|
0 /* no page-crossing issues */);
|
|
|
|
/* Allocate memory from pool */
|
|
ephdata->comms_send_buf = (u8*)dma_pool_alloc(pool_tx, GFP_KERNEL, &ephdata->comms_dma_handle_tx);
|
|
if (NULL == ephdata->comms_send_buf)
|
|
{
|
|
dev_err(&commsdevice->dev, "%s comms_send_buf memory allocation failed \n", __func__);
|
|
return -ENOMEM;
|
|
}
|
|
#elif (ESWIN_EPH861X_SPI)
|
|
// only use spi not use dma
|
|
ephdata->comms_receive_buf = (u8*)kcalloc(COMMS_BUF_SIZE, sizeof(ephdata->comms_receive_buf), GFP_KERNEL);
|
|
ephdata->comms_send_buf = (u8*)kcalloc(COMMS_BUF_WRITE_SIZE, sizeof(ephdata->comms_receive_buf), GFP_KERNEL);
|
|
#endif
|
|
|
|
#if (ESWIN_EPH861X_I2C) // modified by hh just define spi here
|
|
ephdata->comms_receive_buf = (u8*)kcalloc(COMMS_BUF_SIZE, sizeof(ephdata->comms_receive_buf), GFP_KERNEL);
|
|
#endif
|
|
return ret_val;
|
|
|
|
}
|