GT2933触摸驱动分析 - 初始化(续)

goodix_later_init_thread线程

Platform驱动的第一阶段执行完毕后,会通过kthread_run函数注册goodix_later_init_thread线程,该线程会执行第二阶段的任务。

1. 读取版本信息,写入fw_version;
c 复制代码
ret = hw_ops->read_version(cd, &cd->fw_version);
	if (ret < 0) {
		ts_err(dev, "failed to get version info, try to upgrade");
		update_flag |= UPDATE_MODE_FORCE;
	}

读取的起始地址为0x10014,大小为sizeof(struct goodix_fw_version)等于28字节。

2. 读取芯片IC的信息,写入ic_info;
c 复制代码
ret = hw_ops->get_ic_info(cd, &cd->ic_info);
	if (ret < 0) {
		ts_err(dev, "failed to get ic info, try to upgrade");
		update_flag |= UPDATE_MODE_FORCE;
	}

地址为0x10070,大小为256字节。读取解析后写入ic_info变量中。

3. 更新固件

调用 goodix_do_fw_update(cd, update_flag)做固件更新,通过创建内核线程goodix_fw_update_thread完成。在update_thread中函数会调用API接口request_firmware去文件系统中查找名为goodix_cfg_group.bin的升级固件,找到后会将固件的内容拷贝至cfg_bin变量后进行解析,如果三次都没有找到该固件,则直接返回。同样的方法会找goodix_firmware.bin文件,找到后会更新,否则直接返回。

更新goodix_cfg_group.bin
c 复制代码
goodix_fw_update_thread   
|--->start = ktime_get()  //获取的CLOCK_MONOTONIC时间
|--->goodix_get_config_proc(cd)   
	|--->goodix_read_cfg_bin(cd, cfg_name, &cfg_bin)  //cfg_name: goodix_cfg_group.bin
		|--->ret = request_firmware(&firmware, cfg_name, &cd->pdev->dev)  //调用fimware子系统接口
	 //如果获取成功
	|--->goodix_parse_cfg_bin(cd, &cfg_bin) 
	|--->goodix_get_reg_and_cfg(cd, sensor_id, &cfg_bin) 

第一步是从文件系统中获取goodix_cfg_group.bin文件,第二步是解析该文件,最后是依据解析后的文件更新GT2933中的配置寄存器等。

更新goodix_firmware.bin
c 复制代码
|--->goodix_request_firmware(&fwu_ctrl->fw_data,fwu_ctrl->fw_name)     //goodix_firmware.bin 
	|--->r = request_firmware(&fw_data->firmware, name, device)
|--->goodix_fw_update_proc(fwu_ctrl)
	|--->ret = goodix_parse_firmware(fwu_ctrl->core_data, &fwu_ctrl->fw_data);
	|--->goodix_update_prepare(fwu_ctrl);
		|--->hw_ops->reset(cd, 5) //control reset_gpio
		|--->Hold cpu, enable misctl clock,disable watch dog
		|--->goodix_load_isp(cd, &fwu_ctrl->fw_data)
	|--->goodix_flash_firmware(fwu_ctrl);
		|--->goodix_flash_subsystem(fw_ctrl->core_data, fw_x)
			|--->goodix_flash_package(cd, subsys->type, fw_packet,subsys_base_addr + offset,data_size +4);
				|--->goodix_send_flash_cmd(cd, &flash_cmd); 

第一步是从文件系统中获取goodix_firmware.bin ,如果获取成功,则进行第二步,对文件进行解析,解析之后加载isp,准备对固件进行更新,具体的更新操作可以理解为向GT2933中flash寄存器中写入解析后的数据。

goodix_firmware.bin固件可以理解为GT2933的固件,烧写在flash中,而goodix_cfg_group.bin可以理解为GT2933配置寄存器的数值。

firmware接口
c 复制代码
int request_firmware(const struct firmware **fw, const char *name, struct device *device);

request_firmware为内核下固件更新子系统的调用接口,fw为用于保存申请到的固件,name为固件名,device为申请固件的设备结构体。如果申请成功,则返回0,失败会返回一个负值。该固件子系统将固件以二进制文件形式存储于文件系统之中,在内核启动后再从用户空间将固件传递至内核空间,解析固件获得参数,最后加载至硬件设备。那么升级的固件要存放在哪个目录下呢?内核下规定了以下目录为firmware子系统查找的路径。

4. 打印ic_info信息

调用print_ic_info(cd, &cd->ic_info)函数打印ic-information信息;

5. 调用goodix_send_ic_config(cd, CONFIG_TYPE_NORMAL)函数;
6. 调用goodix_ts_stage2_init(cd)函数进行第二阶段的其他部分初始化
6.1 向input子系统注册touch设备

alloc/config/register input device和input子系统打交道;

goodix_ts_input_dev_config(cd)显示申请一个新的input设备,然后配置该设备,将触摸版的panel_max_w/x/y信息写入输入设备的参数中,最后调用input_register_device接口向input子系统中注册该设备;

6.2 向input子系统注册pen设备

goodix_ts_pen_dev_config(cd) 向系统中申请/配置/注册pen设备,需要在board_data->pen_enable写1后才会执行。在配置中使用了panel_max_p/x/y参数。

6.3 申请中断
c 复制代码
ret = devm_request_threaded_irq(&core_data->pdev->dev,
                      core_data->irq, NULL,
                      goodix_ts_threadirq_func,
					  ts_bdata->irq_flags | IRQF_ONESHOT | IRQF_TRIGGER_FALLING,
					  GOODIX_CORE_DRIVER_NAME,
                      core_data);

中断设置为下降沿触发,对应的中断服务函数为goodix_ts_threadirq_func。

6.4 文件系统接口初始化

在文件系统中创建文件节点,对应的结点属性如下,如果cat driver_infor,则会执行driver_infor_show函数,其他类似。

c 复制代码
static DEVICE_ATTR(driver_info, 0440, driver_info_show, NULL);
static DEVICE_ATTR(chip_info, 0440, chip_info_show, NULL);
static DEVICE_ATTR(reset, 0220, NULL, goodix_ts_reset_store);
static DEVICE_ATTR(send_cfg, 0220, NULL, goodix_ts_send_cfg_store);
static DEVICE_ATTR(read_cfg, 0440, read_cfg_show, NULL);
static DEVICE_ATTR(reg_rw, 0664, goodix_ts_reg_rw_show, goodix_ts_reg_rw_store);
static DEVICE_ATTR(irq_info, 0664, goodix_ts_irq_info_show,
		   goodix_ts_irq_info_store);
static DEVICE_ATTR(esd_info, 0664, goodix_ts_esd_info_show,
		   goodix_ts_esd_info_store);
static DEVICE_ATTR(debug_log, 0664, goodix_ts_debug_log_show,
		   goodix_ts_debug_log_store);
static DEVICE_ATTR(die_info, 0440, die_info_show, NULL);
6.5 proc目录节点初始化

在proc文件目录下创建goodix_ts节点,并添加tp_raw和tp_diff属性,对应的操作函数分别为:

c 复制代码
static const struct file_operations raw_proc_fops = {
	.open = tp_rawdata_open,
	.read = tp_data_read,
	.release = tp_data_release,
};

static const struct file_operations diff_proc_fops = {
	.open = tp_diffdata_open,
	.read = tp_data_read,
	.release = tp_data_release,
};
6.6 esd初始化

调用goodix_ts_esd_init(cd)函数,INIT_DELAYED_WORK(&ts_esd->esd_work, goodix_ts_esd_work)首先会定义一个延时工作队列,队列函数为goodix_ts_esd_work,然后开启esd功能,最后调用schedule_delayed_work(&ts_esd->esd_work, 2 * HZ)函数启动该工作队列;

c 复制代码
void goodix_ts_esd_on(struct goodix_ts_core *cd)
{
	struct device *dev = cd->bus->dev;
	struct goodix_ic_info_misc *misc = &cd->ic_info.misc;
	struct goodix_ts_esd *ts_esd = &cd->ts_esd;

	if (!misc->esd_addr)
		return;

	if (atomic_read(&ts_esd->esd_on))
		return;

	atomic_set(&ts_esd->esd_on, 1);
	if (!schedule_delayed_work(&ts_esd->esd_work, 2 * HZ))
		ts_info(dev, "esd work already in workqueue");

	ts_info(dev, "esd on");
}
6.7 gesture_module初始化

调用gesture_module_init(cd)函数,申请gesture_kobj,调用sysfs_create_group函数向gesture添加属性;

c 复制代码
static struct kobj_attribute double_type = __ATTR_RW(double_type);
static struct kobj_attribute single_type = __ATTR_RW(single_type);
static struct kobj_attribute fod_type = __ATTR_RW(fod_type);
static struct kobj_attribute slide_type = __ATTR_RW(slide_type);

static struct attribute *gesture_attrs[] = {
	&double_type.attr,
	&single_type.attr,
	&fod_type.attr,
	&slide_type.attr,
	NULL,
};
6.8 调用inspect_module_init(cd)函数

向内核proc目录创建auto_test结点,对应的操作函数为auto_test_ops。

c 复制代码
int inspect_module_init(struct goodix_ts_core *cd)
{
	struct proc_dir_entry *proc_entry;
	struct device *dev = cd->bus->dev;

	proc_entry = proc_create_data("auto_test", 0660,
				      cd->proc_dir_entry, &auto_test_ops,
				      cd);
	if (!proc_entry) {
		ts_err(dev, "failed to create proc entry");
		return -ENODEV;
	}

	ts_info(dev, "inspect module init success");
	return 0;
}
6.9 初始化两个工作队列
c 复制代码
INIT_WORK(&cd->resume_work, goodix_ts_resume_work)
INIT_WORK(&cd->self_check_work, goodix_self_check)
schedule_work(&cd->self_check_work)

至此,驱动初始化部分结束,接下来是中断的处理,触摸芯片通过中断的方式去响应触摸动作,读取坐标信息。初始化后整个驱动中的数据结构如下。

相关推荐
DevGu2 小时前
Linux 子账户显示bash-4.25,不显示用户名
linux·运维·bash
A13247053122 小时前
curl命令入门:命令行测试接口
linux·运维·服务器·网络·编辑器·github·vim
hetao17338372 小时前
2025-12-25~26 hetao1733837的刷题记录
c++·笔记·算法
客梦2 小时前
数据结构--栈
数据结构·笔记
晚风吹人醒.2 小时前
Awk文本处理工具:命令模式,脚本模式的介绍及正则表达式应用举例
linux·运维·服务器·awk
Li.CQ2 小时前
正则学习笔记
笔记·学习
lbt_dvshare2 小时前
vim 常用技巧和实例
linux·编辑器·vim
阿拉伯柠檬2 小时前
传输层与传输层协议UDP
linux·网络·网络协议·面试·udp
你好helloworld2 小时前
linux离线安装nvidia-docker
linux·运维·服务器