一、关键源码文件:
1、GT911的器件驱动文件(基于该驱动修改成ILITEK驱动):
drivers/hdf_core/framework/model/input/driver/touchscreen/touch_gt911.c
2、HDF触摸屏平台驱动文件:
drivers/hdf_core/framework/model/input/driver/hdf_touch.c
二、驱动加载流程
首先加载平台驱动文件hdf_touch.c,下面是驱动入口。
struct HdfDriverEntry g_hdfTouchEntry = {
.moduleVersion = 1,
.moduleName = "HDF_TOUCH",
.Bind = HdfTouchDriverBind, //驱动对外提供的服务能力,将相关的务接口绑定到HDF框架
.Init = HdfTouchDriverProbe,
.Release = HdfTouchDriverRelease,
};
HDF_INIT(g_hdfTouchEntry);
执行函数HdfTouchDriverProbe:
static int32_t HdfTouchDriverProbe(struct HdfDeviceObject *device)
{
//************ 此处省略 ***************
//实现数据配置解析,解析触摸屏私有配置文件input_config.hcs下boardConfig下inputAttr、busConfig、pinConfig等各个子节点的属性
boardCfg = BoardConfigInstance(device);
//只是申请空间并初始化结构体
touchDriver = TouchDriverInstance();
//经上述函数,获取到节点信息,利用信息进行初始化,打开i2c设备节点。配置i2c 时钟线数据线的寄存器
ret = TouchDriverInit(touchDriver, boardCfg);
//************ 此处省略 ***************
}
下面开始实例化并加载器件驱动。
touch_gt911.c文件的重要结构体:
struct HdfDriverEntry g_touchGoodixChipEntry = {
.moduleVersion = 1,
.moduleName = "HDF_TOUCH_GT911",
.Init = HdfGoodixChipInit,
.Release = HdfGoodixChipRelease,
};
static struct TouchChipOps g_gt911ChipOps = {
.Init = ChipInit, //关键结构体的初始化
.Detect = ChipDetect, //获取触摸屏的信息,例如版本号
.Resume = ChipResume, //触摸屏唤醒
.Suspend = ChipSuspend, //触摸屏休眠
.DataHandle = ChipDataHandle, //中断处理
.UpdateFirmware = UpdateFirmware, //下发固件
.SetAbility = SetAbility, //设置按键值、坐标点信息等等
};
其中的moduleName 属性的值必须要跟平台下的device_info.hcs文件中同属性的值相同,不然驱动无法加载。
首先执行初始化函数HdfGoodixChipInit:
static int32_t HdfGoodixChipInit(struct HdfDeviceObject *device)
{
TouchChipCfg *chipCfg = NULL;
ChipDevice *chipDev = NULL;
//************************* 此处省略 ***********************
chipCfg = ChipConfigInstance(device); //实例化chipCfg 结构体,获取hcs节点信息,例如中断类型、总线类型、芯片版本等等信息
//************************* 此处省略 ***********************
chipDev = ChipDeviceInstance(); //实例化chipDev 结构体
//************************* 此处省略 ***********************
chipDev->chipCfg = chipCfg;
chipDev->ops = &g_gt911ChipOps;
chipDev->chipName = chipCfg->chipName;
chipDev->vendorName = chipCfg->vendorName;
if (RegisterChipDevice(chipDev) != HDF_SUCCESS) {
goto EXIT1;
}
}
再调用平台驱动函数RegisterChipDevice,一般来讲,触摸屏驱动一般是跑以下流程:
知道这个流程是怎么跑,我们就可以基于GT911的驱动,将ILITEK的驱动填充进去
三、基于GT911的原有驱动文件,转化为ILITEK驱动
调用完平台驱动函数RegisterChipDevice后,最后调用器件驱动函数ChipDetect,该函数主要完成触摸屏的上电、复位、申请中断,读取tp信息以及初始化ILITEK的协议。
ChipDetect函数代码如下:
void ilitek_set_pwr_on_xx(void)
{
GpioSetDir(94, 1); //HDF自带的GPIO操作函数
GpioWrite(94, 1);
}
void ilitek_reset_xx(void)
{
GpioSetDir(111, 1);
GpioWrite(111, 1);
OsalMSleep(10);
GpioWrite(111, 0);
OsalMSleep(10);
GpioWrite(111, 1);
OsalMSleep(1000);
}
void ilitek_request_irq_xx(void)
{
GpioSetDir(112,0);
}
/*
global value
*/
static InputI2cClient *g_i2cClient = NULL;
static int32_t ChipDetect(ChipDevice *device)
{
g_i2cClient = &device->driver->i2cClient; //全局变量
//******************************* 此处省略 *************************************
ilitek_request_irq_xx(); //申请中断
ilitek_set_pwr_on_xx(); //上电
ilitek_reset_xx(); //复位
//******************************* 此处省略 ********************************
ret = api_protocol_init_func(); //协议初始化
ret = ilitek_read_tp_info(true); //读取tp信息,例如固件版本、ic版本、坐标最大值、最小值等等
//******************************* 此处省略 **********************************
}
上述函数中,调用了ILITEK驱动中的API api_protocol_init_func用于协议初始化 以及 ilitek_read_tp_info用于读取tp信息,我们不用做太多修改,直接套用ILITEK驱动原生的。
值得注意的是,原生的i2c读写的函数中用到的i2c_client,在这里要替换成HDF i2c 适配层
的InputI2cClient结构体以及HDF特定的读写函数,要对ILITEK驱动中的读写函数做一下修改才能读写,如下:
int ilitek_i2c_write_and_read(uint8_t *cmd, int write_len, int delay, uint8_t *data, int read_len)
{
int ret = 0;
if(delay > 0)
{
ret = InputI2cWrite(g_i2cClient,cmd,write_len);
mdelay(delay);
ret = InputI2cRead(g_i2cClient,cmd,write_len, data,read_len);
}else if (delay == 0){
ret = InputI2cRead(g_i2cClient,cmd,write_len, data,read_len);
}
return ret;
}
ChipDetect函数执行完后,回到平台驱动的ChipDriverInit函数,然后申请中断:
static int32_t ChipDriverInit(ChipDevice *chipDev)
{
//********************** 此处省略***************************************
if ((chipDev->ops == NULL) || (chipDev->ops->Detect == NULL)) {
return HDF_FAILURE;
}
while (count --) {
OsalMSleep(100); // 100 : wait 100msthen try one time
ret = chipDev->ops->Detect(chipDev); //作上电、复位等初始化操作
if (ret == HDF_SUCCESS) {
break;
}
//********************** 此处省略***************************************
ret = SetupChipIrq(chipDev); //申请中断
CHECK_RETURN_VALUE(ret);
return HDF_SUCCESS;
}
SetupChipIrq函数如下:
static int32_t SetupChipIrq(ChipDevice *chipDev)
{
//************************* 此处省略 *********************************
uint16_t intGpioNum = chipDev->boardCfg->pins.intGpio; //中断引脚配置在gt911的私有配置文件
uint16_t irqFlag = chipDev->chipCfg->bus.chipI2c.irqFlag; //中断标志配置在gt911的私有配置文件
//************************* 此处省略 *********************************
irqFlag |= GPIO_IRQ_USING_THREAD;
ret = GpioSetIrq(intGpioNum, irqFlag, IrqHandle, chipDev->driver); //IrqHandle为中断处理函数
//************************* 此处省略 *********************************
ret = GpioEnableIrq(intGpioNum); //使能中断
}
中断处理函数最终调用GT911.C中的函数ChipDataHandle,如下图:
static int32_t ChipDataHandle(ChipDevice *device)
{
int ret;
ret = ilitek_read_data_and_report_3XX(device->driver);
if(ret == 0){
tp_log_err("------ liyj ----- ilitek_read_data_and_report_3XX success \n");
}else {
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
ChipDataHandle函数主要是处理坐标信息的设置和上报,直接将ILITEK驱动的上报函数ilitek_read_data_and_report_3XX搬过来即可。但要注意得是,要在原生的基础上作出以下修改:
1、传入参数TouchDriver *driver
2、原生的函数上报坐标信息使用的是struct input_dev结构体,这里要换成HDF 框架定义的 InputDevice 结构体
修改完如下:
int ilitek_read_data_and_report_3XX(TouchDriver *driver)
{
//**************************************** 此处省略***************************
//struct input_dev *input = ilitek_data->input_dev; 原生的写法,注释掉
input = driver->inputDev; //在外面定义了全局变量 InputDevice *input;
//**************************************** 此处省略***************************
}
再注释掉HDF 触摸驱动框架自带的坐标信息上报函数,如下:
static void EventHandle(TouchDriver *driver, ChipDevice *chipDev)
{
int32_t ret;
if ((chipDev->ops == NULL) || (chipDev->ops->DataHandle == NULL)) {
return;
}
ret = chipDev->ops->DataHandle(chipDev);
// if (ret == HDF_SUCCESS) {
// InputFrameReport(driver); //注释
// }
}
做完上述操作好,回到hdf_touch.c,执行器件驱动函数SetAbility进行按键事件、属性设置:
int32_t RegisterTouchChipDevice(ChipDevice *chipDev)
{
// ************************ 此处省略 ********************************
ret = DeviceBindDriver(chipDev);
ret = ChipDriverInit(chipDev);
inputDev = InputDeviceInstance(chipDev);
ret = RegisterInputDevice(inputDev);
// ************************ 此处省略 ********************************
chipDev->driver->inputDev = inputDev;
chipDev->ops->SetAbility(chipDev); //设置按键事件、属性
return HDF_SUCCESS;
}
SetAbility函数直接套用gt911.c原生的:
static void SetAbility(ChipDevice *device)
{
device->driver->inputDev->abilitySet.devProp[0] = SET_BIT(INPUT_PROP_DIRECT);
device->driver->inputDev->abilitySet.eventType[0] = SET_BIT(EV_SYN) |
SET_BIT(EV_KEY) | SET_BIT(EV_ABS);
device->driver->inputDev->abilitySet.absCode[0] = SET_BIT(ABS_X) | SET_BIT(ABS_Y);
device->driver->inputDev->abilitySet.absCode[1] = SET_BIT(ABS_MT_POSITION_X) |
SET_BIT(ABS_MT_POSITION_Y) | SET_BIT(ABS_MT_TRACKING_ID);
device->driver->inputDev->abilitySet.keyCode[KEY_CODE_4TH] = SET_BIT(KEY_UP) | SET_BIT(KEY_DOWN);
device->driver->inputDev->attrSet.axisInfo[ABS_X].min = 0;
device->driver->inputDev->attrSet.axisInfo[ABS_X].max = device->boardCfg->attr.resolutionX - 1;
//*************************************此处省略***********************
}
做到这一步,基本上已经移植完毕。接下来就是烧录验证。