MTK平台 CTP流程解析

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         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         __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         __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

你可能感兴趣的:(驱动)