微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 手机设计讨论 > MTK手机平台交流 > MTK平台 CTP流程解析

MTK平台 CTP流程解析

时间:10-02 整理:3721RD 点击:

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------->
          php?mod=tag&id=6090" target="_blank" class="relatedlink">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,
           tpd_keys_dim[0],tpd_keys_dim[1],
           tpd_keys_dim[2],tpd_keys_dim[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, 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, 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

博主,我目前也在调试这块IC,有些问题一直搞不明白,小编能留个联系方式吗

我在网上看了一份代码,在tpd_custom_nt11004.h中有三个地址一直不是很清楚,看datesheet也没搞明白,我只知道其中一个是I2C地址,另外两个不太清楚是什么?博主能给解释一下吗?谢谢了
#ifndef TOUCHPANEL_H__
#define TOUCHPANEL_H__
#define NT11004_TS_ADDR                                    (0x34)
#define NT11004_HW_ADDR                                    (0x7F)
#define NT11004_FW_ADDR                                    (0x01)

写得很好,明白了一些东西

这个要看对应的DATASHEET呢。

学习                                

嗯,是这样的,我和厂商联系过,他们说TP的I2C地址就是0x01,在这个函数中static struct i2c_board_info __initdata i2c_tpd={ I2C_BOARD_INFO(NT11004_TS_NAME, 0X01)}初始化过了,但我不知道在下边这个函数中为什么还会有三个地址的选择,不知道他们分别代表什么,DATESHEET里说的也不是很清楚,博主能给解释一下吗?谢谢了
int nvt_flash_write(struct file *file, const char __user *buff, size_t count, loff_t *offp)
{
        struct i2c_msg msgs[2];       
        char *str;
        int ret = -1;
        int retries = 0;
        unsigned char tmpaddr;
        TPD_DMESG("nvt_flash_write\n");
       
        file->private_data = (uint8_t *)kmalloc(64, GFP_KERNEL);
        str = file->private_data;
        ret = copy_from_user(str, buff, count);
        TPD_DMESG("str[0]=%x, str[1]=%x, str[2]=%x, str[3]=%x\n", str[0], str[1], str[2], str[3]);
       
        tmpaddr = i2c_client->addr;
        if((str[0] == 0x7F)||(str[0] == (0x7F<<1)))
        {
                i2c_client->addr = NT11004_HW_ADDR;
        }
        else if((str[0] == 0x01)||(str[0] == (0x01<<1)))
        {
                i2c_client->addr = NT11004_FW_ADDR;
        }
        else
        {
                i2c_client->addr = NT11004_TS_ADDR;
        }
       
        i2c_smbus_write_i2c_block_data(i2c_client, str[2], str[1]-1, &str[3]);
        i2c_client->addr = tmpaddr;
        return ret;
}

写的很好很详细!支持支持

支持支持!支持免费

学习!

学习了~

感谢,感谢,非常感谢!

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top