RK3288 android7.1 适配 ilitek i2c接口TP
一,Ilitek 触摸屏简介
-
Ilitek 提供多种型号的触控屏控制器,如 ILI6480、ILI9341 等,采用 I2C 接口。
这些控制器能够支持多点触控,并具有优秀的灵敏度和响应速度。 -
Ilitek 的触摸屏控制器监测屏幕上的触摸事件。
当触摸发生时,控制器将触摸坐标(通常是 x 和 y 坐标)通过 I2C 总线发送给主机。
二,DTS配置
&i2c1 {
status = "okay";
ilitek@41 {
compatible = "tchip,ilitek";
reg = <0x41>;
ilitek,irq-gpio = <&gpio7 6 GPIO_ACTIVE_HIGH>;
ilitek,reset-gpio = <&gpio7 15 GPIO_ACTIVE_HIGH>; //修改相对应的gpio参数
pinctrl-names = "default";
pinctrl-0 = <&ilitek_gpio_e>;
status = "okay";
};
};
&pinctrl {
touchscreen {
ilitek_gpio_e: ilitek-gpio-e {
rockchip,pins =
<7 6 RK_FUNC_GPIO &pcfg_pull_up>,
<7 15 RK_FUNC_GPIO &pcfg_pull_up>;
};
};
};
注:一定要对应的I2C bus节点(硬件原理图上会有标注)。
三,驱动文件配置
1. ilitek_lim.c
static int ilitek_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret = 0;
int revert_x=0;
int revert_y=0;
int revert_x_y=0;
struct device_node *param_node;
#ifdef ILI_UPDATE_FW
#ifdef UPDATE_THREADE
struct task_struct *thread_update = NULL;
#endif
#endif
#ifdef RECOGNITION_LONGTIME_BUTTON
struct task_struct *thread_longtime_button = NULL;
#endif
#ifdef WRITE_2210_CFG
struct task_struct *thread_write_cfg = NULL;
#endif
#if IC2120
int i = 0;
#endif
//int i = 0;
//uint8_t buf[8] = {0};
#ifdef DEBUG_NETLINK
struct netlink_kernel_cfg cfg = {
.groups = 0,
.input = udp_receive,
};
#endif
tp_log_info("Enter ilitek_i2c_probe +++++++++ client->addr = 0x%x++++++\n", client->addr);
if(!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)){
tp_log_err("%s, I2C_FUNC_I2C not support\n", __func__);
return -1;
}
// initialize global variable
#ifdef TOOL
memset(&dev_ilitek, 0, sizeof(struct dev_data));
#endif
memset(&i2c, 0, sizeof(struct i2c_data));
// initialize mutex object
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37)
init_MUTEX(&i2c.wr_sem);
#else
sema_init(&i2c.wr_sem,1);
#endif
i2c.wr_sem.count = 1;
mutex_init(&(i2c.irq_mutex));
i2c.report_status = 1;
i2c.client = client;
#ifdef CONFIG_ENABLE_REGULATOR_POWER_ON
ret = ilitek_get_regulator();
if (ret) {
tp_log_err("%s, ilitek_get_regulator failed\n", __func__);
return ret;
}
ret = ilitek_power_on(true);
if (ret) {
tp_log_err("%s, power on failed\n", __func__);
return ret;
}
#endif
//
ret = ilitek_request_io_port(client);
if (ret != 0)
{
tp_log_err("%s, io error", __func__);
return ret;
}
param_node = of_find_node_by_path("/smdt_param");
if (!param_node){
printk("gt9xx wxl error smdt_param not node!!!\n");
}
of_property_read_u32(param_node, "ctp_revert_x_flag", &revert_x);
of_property_read_u32(param_node, "ctp_revert_y_flag", &revert_y);
of_property_read_u32(param_node, "ctp_exchange_x_y_flag", &revert_x_y);
if(revert_x == 1 )
REVERT_X = 1;
else
REVERT_X = 0;
if(revert_y == 1 )
REVERT_Y = 1;
else
REVERT_Y = 0;
if(revert_x_y == 1 )
EXCHANG_XY = 1;
else
EXCHANG_XY = 0;
i2c.client->irq = gpio_to_irq(i2c.irq_gpio);
tp_log_info("ilitek i2c.irq_gpio = %d, i2c.client->irq = %d\n", i2c.irq_gpio, i2c.client->irq);
i2c.valid_i2c_register = 1;
#if 1
ilitek_reset(i2c.reset_gpio);
#endif
#if !IC2120
mdelay(200);
#else
for (i = 0; i < 30; i++ ) {
ret = ilitek_poll_int();
tp_log_info("ilitek int status = %d\n", ret);
if (ret == 0) {
break;
}
else {
mdelay(5);
}
}
if (i >= 30) {
#ifdef ILI_UPDATE_FW
tp_log_info("ilitek reset but int not pull low so driver_upgrade_flag = true\n");
driver_upgrade_flag = true;
#endif
}
else
#endif
{
#if 0
msleep(2000);
for (i = 0; i < 127; i++) {
//buf[0] = 0x10;
client->addr = i;
ret = ilitek_i2c_write_and_read(i2c.client, buf, 0, 10, buf, 4);
tp_log_info("ilitek %s, write 0x10 read buf = %X, %X, %X\n", __func__, buf[0], buf[1], buf[2]);
if (ret < 0) {
mdelay(5);
}
else {
tp_log_info("ilitek %s, client->addr = 0x%X, read buf = %X, %X, %X\n", __func__, client->addr, buf[0], buf[1], buf[2]);
tp_log_info("ilitek %s, client->addr = 0x%X, read buf = %X, %X, %X\n", __func__, client->addr, buf[0], buf[1], buf[2]);
tp_log_info("ilitek %s, client->addr = 0x%X, read buf = %X, %X, %X\n", __func__, client->addr, buf[0], buf[1], buf[2]);
tp_log_info("ilitek %s, client->addr = 0x%X, read buf = %X, %X, %X\n", __func__, client->addr, buf[0], buf[1], buf[2]);
tp_log_info("ilitek %s, client->addr = 0x%X, read buf = %X, %X, %X\n", __func__, client->addr, buf[0], buf[1], buf[2]);
break;
}
}
#endif
// read touch parameter
ret = ilitek_i2c_read_tp_info();
if(ret < 0){
tp_log_err("ilitek read tp info fail free gpio\n");
if (gpio_is_valid(i2c.irq_gpio)) {
gpio_free(i2c.irq_gpio);
}
if (gpio_is_valid(i2c.reset_gpio)) {
gpio_free(i2c.reset_gpio);
}
return ret;
}
}
#ifdef CLOCK_INTERRUPT
#ifdef REPORT_THREAD
i2c.thread = kthread_run(ilitek_i2c_touchevent_thread, NULL, "ilitek_i2c_thread");
if(i2c.thread == (struct task_struct*)ERR_PTR){
i2c.thread = NULL;
tp_log_err("%s, kthread create, error\n", __func__);
}
#endif
#endif
ilitek_handle_irqorpolling();
i2c.input_dev = input_allocate_device();
if(i2c.input_dev == NULL){
tp_log_err("%s, allocate input device, error\n", __func__);
return -1;
}
ilitek_set_input_param(i2c.input_dev, i2c.max_tp, i2c.max_x, i2c.max_y);
ret = input_register_device(i2c.input_dev);
if(ret){
tp_log_err("%s, register input device, error\n", __func__);
return ret;
}
i2c.valid_input_register = 1;
tp_log_info("%s, register input device, success\n", __func__);
#ifdef ILI_UPDATE_FW
#ifndef UPDATE_THREADE
{
update_wait_flag = 1;
ret = ilitek_upgrade_firmware();
if(ret == ILITEK_UPDATE_OK) {
tp_log_info("update end\n");
}
else if(ret == ILITEK_I2C_TRANSFER_ERR) {
tp_log_info("i2c communication error\n");
}
if(i2c.reset_request_success){
ilitek_reset(i2c.reset_gpio);
}
// read touch parameter
ret=ilitek_i2c_read_tp_info();
if(ret < 0)
{
tp_log_err("ilitek_i2c_read_tp_info err\n");
return ret;
}
update_wait_flag = 0;
#if 1
input_unregister_device(i2c.input_dev);
#if 1
i2c.input_dev = input_allocate_device();
if(i2c.input_dev == NULL){
tp_log_err("%s, allocate input device, error\n", __func__);
return -1;
}
#endif
// register input device
//memset(i2c.input_dev, 0, sizeof(struct input_dev));
// register input device
ilitek_set_input_param(i2c.input_dev, i2c.max_tp, i2c.max_x, i2c.max_y);
ret = input_register_device(i2c.input_dev);
if(ret){
tp_log_err("%s, register input device, error\n", __func__);
return ret;
}
tp_log_info("%s, register input device, success\n", __func__);
#endif
}
#else
{
thread_update= kthread_run(ilitek_i2c_update_thread, NULL, "ilitek_i2c_updatethread");
if(thread_update == (struct task_struct*)ERR_PTR){
thread_update = NULL;
tp_log_err("%s,thread_update kthread create, error\n", __func__);
}
}
#endif
#endif
#ifdef WRITE_2210_CFG
thread_write_cfg = kthread_run(ilitek_i2c_write_cfg_thread, NULL, "ilitek_i2c_write_cfg_thread");
if(thread_write_cfg == (struct task_struct*)ERR_PTR){
thread_write_cfg = NULL;
tp_log_err("%s,thread_write_cfg kthread create, error\n", __func__);
}
#endif
#ifdef RECOGNITION_LONGTIME_BUTTON
thread_longtime_button = kthread_run(ilitek_i2c_check_longtime_button_thread, NULL, "ilitek_i2c_check_longtime_button_thread");
if(thread_longtime_button == (struct task_struct*)ERR_PTR){
thread_longtime_button = NULL;
tp_log_err("%s,thread_longtime_button kthread create, error\n", __func__);
}
#endif
#ifdef GESTURE
ilitek_system_resume = 1;
input_set_capability(i2c.input_dev, EV_KEY, KEY_POWER);
input_set_capability(i2c.input_dev, EV_KEY, KEY_W);
input_set_capability(i2c.input_dev, EV_KEY, KEY_LEFT);
input_set_capability(i2c.input_dev, EV_KEY, KEY_RIGHT);
input_set_capability(i2c.input_dev, EV_KEY, KEY_UP);
input_set_capability(i2c.input_dev, EV_KEY, KEY_DOWN);
input_set_capability(i2c.input_dev, EV_KEY, KEY_O);
input_set_capability(i2c.input_dev, EV_KEY, KEY_C);
input_set_capability(i2c.input_dev, EV_KEY, KEY_E);
input_set_capability(i2c.input_dev, EV_KEY, KEY_M);
#endif
#ifdef TOOL
ret = create_tool_node();
#endif
#ifdef SENSOR_TEST
#ifdef SYS_ATTR_FILE
ilitek_sensor_test_init();
#endif
#endif
#ifdef HALL_CHECK
#if HALL_CHECK == HALL_CHECK_OTHER
ilitek_hall_check_init();
#elif HALL_CHECK == HALL_CHECK_HW
ilitek_hall_check_hw_init();
#endif //end of HALL_CHECK
#endif
Report_Flag=0;
#ifdef PLAT_ROCKCHIP
i2c.tp.tp_resume = ilitek_i2c_late_resume;
i2c.tp.tp_suspend = ilitek_i2c_early_suspend;
tp_register_fb(&i2c.tp);
#endif
#ifdef ILITEK_ESD_CHECK
INIT_DELAYED_WORK(&esd_work, ilitek_touch_esd_func);
esd_wq = create_singlethread_workqueue("esd_wq");
if (!esd_wq) {
return -ENOMEM;
}
queue_delayed_work(esd_wq, &esd_work, delay);
#endif
#ifdef WRITE_2210_CFG
ret = sysfs_create_group(&client->dev.kobj, &ilitek_test_attribute_group);
if (ret) {
dev_err(&client->dev, "failed to create sysfs attributes: %d\n",
ret);
return ret;
}
#endif
#ifdef DEBUG_NETLINK
//netlink_sock = netlink_kernel_create(&init_net, 21, 0,udp_receive, NULL, THIS_MODULE);
netlink_sock = netlink_kernel_create(&init_net, 21, &cfg);
#endif
device_init_wakeup(&client->dev, 1);
return 0;
}
ilitek_i2c_probe 函数是 I2C 设备的初始化函数,在设备被识别和加载驱动时调用。它的主要职责包括:
- 初始化设备:根据 I2C 客户端信息和设备 ID 来配置和初始化设备。
- 分配所需资源:如内存、GPIO 等。
- 设置中断处理程序(如适用):为设备配置中断。
- 注册输入设备:根据设备类型设置输入设备的相关参数。
2. ilitek_ts.h
ilitek_ts.h用于定义驱动相关的数据结构、常量、函数原型以及其他必要的包含。该头文件的内容用于抽象和管理与 Ilitek 触摸屏控制器之间的接口。
3. ILI25110CN080O0003_CRC.ili
ILI25110CN080O0003_CRC.ili 可能是与 Ilitek 触摸屏控制器 ILI2511 系列相关的文件。
4. 驱动移植
a.将原厂提供的的驱动(ilitek)拷贝到下面的文件夹:
./kernel/drivers/input/touchscreen
b. 然后修改 touchscreen 目录下的 Makefile以及Kconfig。这个Makefile中定义的就是要编译哪个平台的触摸屏驱动的。
kernel/drivers/input/touchscreen/Makefile中添加:
obj-$(CONFIG_TOUCHSCREEN_ILITEK) += ilitek/
--------------------------------------------------------
kernel/drivers/input/touchscreen/Kconfig中添加:
config TOUCHSCREEN_ILITEK
tristate "ILITEK touchscreens matched with screen support for rockchip platform"
depends on I2C && ARCH_ROCKCHIP
help
Say Y here if you have a touchscreen interface using the ILITEK
touchscreen chip on Rockchip platform, and your board-specific
initialization code includes that in its table of IIC devices.
If unsure, say N.
c. 内核中加载驱动:
kernel/arch/arm/configs/rockchip_defconfig中添加:
CONFIG_TOUCHSCREEN_ILITEK=y
四,调试
- 确认 /sys/bus/i2c/devices 下有裝置节点 (-0041);
- 报点问题:
有触摸效果,只是坐标 mapping 问题。
X、Y 需要交換。
將 ILITEK_ROTATE_FLAG 设定值由 0 改为 1 或由 1 改为 0。
X、Y 值要做鏡像变化。
將 ILITEK_REVERT_X 或 ILITEK_REVERT_Y 的设定值由 0 改为 1 或由 1 改为 0。
若需要指定显示屏的解析度。
则开放 ILITEK_USE_LCM_RESOLUTION 宏,同时將TOUCH_SCREEN_X_MAX 和 TOUCH_SCREEN_Y_MAX 设为正确值。