RK3288 android7.1 适配 ilitek i2c接口TP

一,Ilitek 触摸屏简介

  1. Ilitek 提供多种型号的触控屏控制器,如 ILI6480、ILI9341 等,采用 I2C 接口。

    这些控制器能够支持多点触控,并具有优秀的灵敏度和响应速度。

  2. Ilitek 的触摸屏控制器监测屏幕上的触摸事件。

    当触摸发生时,控制器将触摸坐标(通常是 x 和 y 坐标)通过 I2C 总线发送给主机。


二,DTS配置

bash 复制代码
&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

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)拷贝到下面的文件夹:

bash 复制代码
./kernel/drivers/input/touchscreen

b. 然后修改 touchscreen 目录下的 Makefile以及Kconfig。这个Makefile中定义的就是要编译哪个平台的触摸屏驱动的。

bash 复制代码
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. 内核中加载驱动:

bash 复制代码
kernel/arch/arm/configs/rockchip_defconfig中添加:
CONFIG_TOUCHSCREEN_ILITEK=y

四,调试

  1. 确认 /sys/bus/i2c/devices 下有裝置节点 (-0041);
  2. 报点问题:
    有触摸效果,只是坐标 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 设为正确值。

相关推荐
7yewh2 天前
嵌入式驱动RK3566 HDMI eDP MIPI 背光 屏幕选型与调试提升篇-eDP屏
linux·arm开发·驱动开发·嵌入式硬件·嵌入式linux·rk·edp
Y多了个想法1 个月前
RK3568 android11 适配敦泰触摸屏 FocalTech-ft5526
android·rk3568·触摸屏·tp·敦泰·focaltech·ft5526
小狗爱吃黄桃罐头2 个月前
江协科技STM32学习- P31 I2C通信协议
stm32·i2c·江科大
双翌视觉2 个月前
TP&LCM柔性屏自动化贴合应用
自动化·视觉检测·智能制造·机器视觉·lcm·tp·贴合机
打地基的小白3 个月前
软件I2C-基于江科大源码进行的原理解析和改造升级
stm32·单片机·嵌入式硬件·通信模式·i2c
oushaojun23 个月前
linux应用层读写i2c设备
linux·应用层·i2c
LeeYLong3 个月前
I2C/IIC学习笔记
笔记·学习·通信协议·i2c
钟剑锋-JeffChong4 个月前
stm32之硬件I2C读写MPU6050陀螺仪、加速度传感器应用案例
stm32·单片机·嵌入式硬件·嵌入式开发·i2c·mpu6050
蚂蚁小兵4 个月前
LIN诊断(3)—— 传输层诊断协议(LINTP)
canoe·lin·tp·iso-17987-2