c,c++
分类: LINUX
2018-08-28 18:06:47
移植的目标平台为海思3531,移植驱动前,先找FAE索要linux平台的驱动源码。拿到源码后,在驱动模块入口函数ft5x0x_ts_init中通过i2c_new_device向i2c总线注册触摸屏设备,前提是触摸屏IC得支持使用I2C接口通信。简要记录一下碰到的问题及解决过程:
解决过程:
按照平台设备驱动的框架,首先定义一个i2c_board_info结构体,其中I2C_BOARD_INFO中的.name与i2c_driver结构体中的drvier->name一致。如下
static struct i2c_driver ft5x0x_ts_driver = {
.probe = ft5x0x_ts_probe,
.remove = __devexit_p(ft5x0x_ts_remove),
.id_table = ft5x0x_ts_id,
.driver = {
.name = "ft5x0x_ts",
.owner = THIS_MODULE,
},
};
static struct i2c_board_info __initdata fts_i2c_board_info[] = {
{
I2C_BOARD_INFO("ft5x0x_ts", 0x70),
.irq = IRQ_EINT(6),
},
};
此时,一般情况下,如果内核中的板级驱动初始化代码中如果使用了i2c_register_board_info来注册设备信息,则可以将上述I2C_BOARD_INFO("ft5x0x_ts", 0x70)信息扩充到板级驱动代码中的i2c_board_info结构体中,只需定义i2c_driver结构体然后在模块入口函数中调用i2c_add_driver,并传入i2c_driver结构体指针,如下:
i2c_add_driver(&ft5x0x_ts_driver);
然后平台驱动将会自动匹配并调用自定义的probe函数。如果板级驱动初始化代码中没有使用i2c_register_board_info注册设备信息,此时仍然可以通过以下方式注册i2c设备:
struct i2c_adapter *i2c_adap;
int busNum = 0 ;
i2c_adap = i2c_get_adapter(busNum);//这里要实验的触摸屏是挂接在第1条I2C-0总线上的,所以这里的参数是0
if (!i2c_adap) {
pr_err("failed to get adapter i2c%d\n", busNum);
return -ENODEV;
}
this_client = i2c_new_device(i2c_adap, fts_i2c_board_info);//设置和注册i2c_client结构体
ret = i2c_add_driver(&ft5x0x_ts_driver);
printk("ret=%d\n",ret);
i2c_put_adapter(i2c_adap);
通过调用i2c_new_device接口,设备将注册到内核并创建i2c_client结构体。然后调用 i2c_add_driver接口来与I2C总线驱动进行匹配,若名称一致,匹配成功后执行自定义的 probe函数。
解决过程:
NO1.
查询错误码,-1表示操作不允许.猜想是中断号不正确,查阅海思3531硬件手册,在request_irq中填入正确的中断号,错误依旧.后来发现更改中断触发方式,将flags设置为0后,中断可以申请成功了.对比了海思驱动代码中的用法,确实也将flags设置为0.由此,猜想中断触发方式无须内核处理,由驱动根据硬件平台设置即可.相反设置了标志位,但内核中并无实现,由此产生错误.
NO2.
至于中断申请成功后,点击触摸屏后不能进入中断处理函数的问题,首先按照硬件手册确认中断GPIO管脚配置情况,发现配置有问题,更改配置后,问题解决,点击触摸屏后便立即进入了中断处理函数.
NO3.
中断处理函数中,一般需要禁止中断,将disable_irq接口更改为disable_irq_nosync后,问题解决.
驱动源码中的数据读取函数为标准的i2c_transfer接口重新封装实现的,触摸屏数据有多个数据,采用一次性读取多个字节数据的方式.通常利用i2c_transfer按照I2c协议,首先向触摸屏IC写入1个字节的将要读取的寄存器序列的首地址,然后通过i2c_transfer接口接收N个字节的数据.如下:
int ret;
struct i2c_msg msgs[] = {
{
.addr = this_client->addr,
.flags = 0,
.len = 1,
.buf = rxdata,
},
{
.addr = this_client->addr,
.flags = I2C_M_RD,
.len = length,
.buf = rxdata,
},
};
//msleep(1);
ret = i2c_transfer(this_client->adapter, msgs, 2);
if (ret < 0)
pr_err("msg %s i2c read error: %d\n", __func__, ret);
return ret;
但在海思3531上采用此种办法时出现错误,似乎不支持i2c_transfer的1个字节的传输指令.重写多字节读取接口,采用每次读一个字节数据,连续读取N次的办法后,问题解决.
for(i = 0; i < length; i++)
{
int result = 0;
result = ft5x0x_read_reg(start_addr+i, rxdata+i);
if(result >= 0)
{
ret += result;
}
}
询问FAE得知可以通过升级触摸屏IC固件来解决.好比重新校准.
原因:触摸IC复位没有成功.
解决办法: 复位后,将复位管脚电平复原为高电平
RESET_PIN = 0; // 复位
mdelay(5);
RESET_PIN = 1; // 还原
mdelay(5);