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