MTK 平台tp相关,以联永的nt11004为例
一 硬件
tp硬件上主要有6根线:vdd,int,sda,scl,reset,gnd
vdd:电压值为2.8v
int:输入脚,低电平有效。int的触发电平需为电平触发
sda,scl为i2c脚
reset:低电平有效,tp正常工作模式此脚需为高电平。
gnd:地
tp里如有fireware,则无需初始化,只要vdd,reset,gnd接上后,触摸tp,int就有正常中断产生,如没请联系tp fae,此为判断tp是否有硬件问题。
二 软件
代码路径:
V:\mt6577\alps\mediatek\custom\common\kernel\touchpanel\nt11004\nt11004_driver.c
V:\mt6577\alps\mediatek\custom\basicom77_cu_ics2\kernel\touchpanel\nt11004\tpd_custom_nt11004.h
1 宏定义:
ProjectConfig.mk CUSTOM_KERNEL_TOUCHPANEL=nt11004
2 在dws中配置tp reset 和 int脚
3 跟相关tp原厂要份驱动代码,如果没有,就copy一份之前的,修改。
tp设备是通过module_init(tpd_driver_init)挂载到系统上的,tpd_driver_init中主要实现注册i2c设备和tp设备,具体挂载在哪一路i2c上需看原理图。
4 probe中申请int,创建tp时间处理线程,当有触摸时,tp产生中断,bb通过i2c总线读取相应的坐标,将坐标点传递给上层驱动。大致的流程图如下:
三 tp虚拟按键
目前智能机都采用全触控的方式实现手机的正常使用,故往往会用到tp做虚拟按键,下面也简单介绍下mtk tp虚拟按键的实现方式:
整个Android的Virtual key的整个的简单框图如下:
APP-------> Framework-------> Kernel-------> Hardware
struct tpd_driver_t { char *tpd_device_name; int (*tpd_local_init)(void); void (*suspend)(struct early_suspend *h); void (*resume)(struct early_suspend *h); int tpd_have_button; };
其中变量int tpd_have_button就是判断是否存在tp按键,如项目有使用tp虚拟按键,这在注册时须将此处的值设置为1,如:
static struct tpd_driver_t tpd_device_driver = { .tpd_device_name = NT11004_TS_NAME, .tpd_local_init = tpd_local_init, .suspend = tpd_suspend, .resume = tpd_resume, #ifdef TPD_HAVE_BUTTON .tpd_have_button = 1, #else .tpd_have_button = 0, #endif
}
tp 按键相关的驱动代码:
X:\MT6577\alps\mediatek\custom\common\kernel\touchpanel\src\tpd_button.c
//#ifdef TPD_HAVE_BUTTON //static int tpd_keys[TPD_KEY_COUNT] = TPD_KEYS; //static int tpd_keys_dim[TPD_KEY_COUNT][4] = TPD_KEYS_DIM; static unsigned int tpd_keycnt = 0; static int tpd_keys[TPD_VIRTUAL_KEY_MAX]={0}; static int tpd_keys_dim[TPD_VIRTUAL_KEY_MAX][4];// = {0}; static ssize_t mtk_virtual_keys_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { int i, j; for(i=0, j=0;i<tpd_keycnt;i++) j+=sprintf(buf, "%s%s:%d:%d:%d:%d:%d%s",buf, __stringify(EV_KEY),tpd_keys[i], tpd_keys_dim[i][0],tpd_keys_dim[i][1], tpd_keys_dim[i][2],tpd_keys_dim[i][3], (i==tpd_keycnt-1?"\n":":")); return j; static struct kobj_attribute mtk_virtual_keys_attr = { .attr = { .name = "virtualkeys.mtk-tpd", .mode = S_IRUGO, }, .show = &mtk_virtual_keys_show, }; static struct attribute *mtk_properties_attrs[] = { &mtk_virtual_keys_attr.attr, NULL }; static struct attribute_group mtk_properties_attr_group = { .attrs = mtk_properties_attrs, }; void tpd_button_init(void) { int ret = 0, i = 0; // if((tpd->kpd=input_allocate_device())==NULL) return -ENOMEM; tpd->kpd=input_allocate_device(); /* struct input_dev kpd initialization and registration */ tpd->kpd->name = TPD_DEVICE "-kpd"; set_bit(EV_KEY, tpd->kpd->evbit); //set_bit(EV_REL, tpd->kpd->evbit); //set_bit(EV_ABS, tpd->kpd->evbit); for(i=0;i<tpd_keycnt;i++) __set_bit(tpd_keys[i], tpd->kpd->keybit); tpd->kpd->id.bustype = BUS_HOST; tpd->kpd->id.vendor = 0x0001; tpd->kpd->id.product = 0x0001; tpd->kpd->id.version = 0x0100; if(input_register_device(tpd->kpd)) TPD_DMESG("input_register_device failed.(kpd)\n"); set_bit(EV_KEY, tpd->dev->evbit);
for(i=0;i<tpd_keycnt;i++) __set_bit(tpd_keys[i], tpd->dev->keybit); properties_kobj = kobject_create_and_add("board_properties", NULL); if(properties_kobj) ret = sysfs_create_group(properties_kobj,&mtk_properties_attr_group); if(!properties_kobj || ret) printk("failed to create board_properties\n"); }
在sys/board_properties/下创建一个叫virtualkeys.*节点;在frameworks/base/services/input下的文件EventHub.cpp中对这个节点进行访问;
如果采用以上方式注册tp虚拟按键,则需要在X:\MT6577\alps\mediatek\config\basicom_6462k有对应的mtk-kpd.kl中有对应虚拟按键的键值映射表。用adb shell 可以再/system/usr/keylayout目录下看到此文件。
EventHub.cpp中会检测是否有tp事件发生,如果tp坐标点值落在主次的虚拟按键virtualkeys.*中的话,则转成上次按键消息传递给上层。
四 tp接近的功能
此功能是在中断处理函数中通过调用ret = hwmsen_get_interrupt_data(ID_PROXIMITY, &sensor_data),更新psensor的数据,senosr处理模块polling时检测到有数据更新后将消息传递上hal层。代码请参考X:\MT6577\alps\kernel\mediatek\source\kernel\drivers\hwmon\hwmsen\hwmsen_dev.c
故此功能需保证驱动和hal都需要先注册上psensor相关的模块。
当一个模块需调用其他模块的函数或者变量时:可使用EXPORT_SYMBOL和EXPORT_SYMBOL_GPL来定义:
/proc/kallsyms”文件对应着内核符号表,记录了符号以及符号所在的内存地址。
模块可以使用如下宏导出符号到内核符号表:
1 EXPORT_SYMBOL(符号名);
2 EXPORT_SYMBOL_GPL(符号名)
导出的符号可以被其他模块使用,不过使用之前一定要声明一下。EXPORT_SYMBOL_GPL()只适用于包含GPL许可权的模块。
五 tp apk升级功能的实现方法
static int nvt_flash_init() { int ret=0; NVT_proc_entry = create_proc_entry(DEVICE_NAME, 0666, NULL); if(NVT_proc_entry == NULL) { TPD_DMESG("Couldn't create proc entry!\n"); ret = -ENOMEM; return ret ; } else { TPD_DMESG("Create proc entry success!\n"); NVT_proc_entry->proc_fops = &nvt_flash_fops; } flash_priv=kzalloc(sizeof(*flash_priv),GFP_KERNEL); TPD_DMESG("============================================================\n"); TPD_DMESG("NVT_flash driver loaded\n"); TPD_DMESG("============================================================\n"); return 0; error: if(ret != 0) { TPD_DMESG("flash_priv error!\n"); } return -1; }
通过create_proc_entry(DEVICE_NAME, 0666, NULL)创建一个虚拟的文件, 虚拟文件一方面可以向用户呈现内核中的一些信息,也可以用作一种从用户空间向内核发送信息的手段。故用户空间可直对该文件节点进行读写操作来控制内核驱动。我们可以通过
adbshell后再proc目录下看到我们创建的节点DEVICE_NAME。
struct file_operations nvt_flash_fops = { .owner = THIS_MODULE, .open = nvt_flash_open, .release = nvt_flash_close, .write = nvt_flash_write, .read = nvt_flash_read, };
当我们需要知道tp的一些信息,只需通过去读该虚拟文件,调用nvt_flash_read则可以知道,而tp升级是通过对虚拟文件进行写操作,调用nvt_flash_write将二进制文件fw通过i2c总线写到tp ic的rom中。
六 经常遇到一些问题
调试中遇到一些问题总结:
tp触摸按键没有功能
1 检查在sys/board_properties/是否有注册上相关节点
2 检查kl文件的键值映射表
tp触摸无效:
1 硬件量int是否有中断产生
2 tp address是否正确,i2c时候有ack
|