ad芯片驱动编写 linux
2018-07-06 05:03:53 lailaiquququ11 阅读数 1185

本博客参考了https://blog.csdn.net/jklinux/article/details/74561352 ,在之前基础上扩展

现实中lcd的显示部分与触摸部分实际是分开的。

我们可以形象的理解为:电容屏的触摸相当于在lcd屏上覆盖一个透明的矩阵键盘, 当用户按下时,可以获取用按下的坐标位置.
通常情况不管是电阻还是电容屏,现都使用一个触控芯片,用于处理用户的操作坐标及实现与SOC的坐标数据的交互.

电阻的触控芯片有: tsc2046, 还有国内的: xx2046

电容的触控芯片有: ft5x06(9寸屏以下使用), gt9271(9寸屏以上用)

============

电容屏说明:主要围绕上面我们使用较多的芯片的来说

这里写图片描述
注意: 屏越大, tx/rx线就越多. tx线相当于矩阵键盘里的列线, rx线相当于矩阵键盘里的行线.

这里写图片描述
TP表示触摸屏上的触摸膜
Host表示我们的板
整个图的意思:表示ft5x06触控芯片, 会自动处理按下坐标的事件,会通过int脚(低电平工作)通知我们的SOC有坐标事件发生,然后我们通过i2c接口把坐标数据读取回去。也就是对我们来说, 触控芯片就是一个i2c设备.

i2c设备得有设备地址, 我用过的ft5306的地址有: 0x2b(这个在个人理解上,是很老的一批芯片使用的地址), 0x38(??), 设备地址可以用i2c_new_probed_device函数探测出来
==================
1>      ft5x06芯片内部也有很多寄存器, 寄存器上的值需要通过i2c按口来访问:
这里写图片描述

===========
2>       ft5x06的i2c读写时序:

这里写图片描述
其中Data Address表示芯片内部的寄存器地址
///////
这里写图片描述
从触控芯片读取寄存器的值的时序. 但这里没有指定从哪个寄存器开始读。有些ft5306默认是从地址为0的寄存器开始读, 有些必须用下面时序来指定要开始读寄存器的地址才可以

这里写图片描述

//  这个用于指定开始读数据的寄存器的地址

/linux-3.4.112/drivers/input/touchscreen  可以在内核源当中找到这几种常见的触摸芯片的驱动

//电容的触控芯片有: ft5x06(9寸屏以下使用), gt9271(9寸屏以上用) ,在编程上 两者的主要使用区别在于:后者需要每下一次操作之前把寄存器的值清0(后续补贴上gt9271代码及差异之处

====================

电阻屏的说明:

电阻的触控芯片有: tsc2046, 还有国内的: xx2046基本都是最后兼容到tsc2046芯片上。

当然还有很大一部分的芯片是自带有这部分的触摸功能的。如s3c2440 ,6818等

我们用一部分的hdmi的触摸屏都是使用的电阻屏,对应的触控芯片会有不一样(比如,树梅派的屏大致的原理是把24位色的转化成16位色,显示在屏幕上。)

使用的电阻屏,以四线电阻屏比较多。

.......

具体原理(待补上)

.......

我们能够知道,四线屏的原理是最后采集到的ADC值,最后我们需要使用移植tslib第三方库 来实现我们获得的电压值到坐标值的转换(这里的内容参考的s3c2440的lcd屏驱动的实现来描述的)。而电容屏是不需要这个步骤,直接能从触控芯片输出中得到坐标值。

====================

芯片的操作:

读取ft5306芯片内部地址为0xa3的寄存器的值:


#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>

int myprobe(struct i2c_client *cli, const struct i2c_device_id *id)
{
    struct i2c_msg msgs[2];
    char reg_addr = 0xa3; //读取ft5306芯片内部地址为xa3寄存器的值 
    char data;

    printk("in myprobe ...%s, %x\n", cli->name, cli->addr);
    // set data address
    msgs[0].addr = cli->addr;
    msgs[0].flags = 0; //write
    msgs[0].len = 1; //要发出的数据长度,多少字节
    msgs[0].buf = &reg_addr;    
    if (i2c_transfer(cli->adapter,  &msgs[0], 1) < 0)
    {
        printk("i2c_transfer0 failed ...\n");
        return -ENODEV;
    }
    // read reg_addr 0xa3
    msgs[1].addr = cli->addr;
    msgs[1].flags = I2C_M_RD;
    msgs[1].len = 1;
    msgs[1].buf = &data; 
    i2c_transfer(cli->adapter,  &msgs[1], 1);

    printk("data = %x\n", data);
    return 0;
}

int myremove(struct i2c_client *cli)
{
    printk("in myremove ...\n");
    return 0;
}


struct i2c_device_id ids[] = {
    {"ft5x0x_ts"},
    {},
};

struct i2c_driver mydrv = {
    .probe = myprobe,
    .remove = myremove,

    .id_table = ids,

    .driver = {
        .name = "myi2c",
    },  
};

module_i2c_driver(mydrv);
MODULE_LICENSE("GPL");

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60

///////////////////////////////////////////////////////////////////////////////////////////////////////////////
当触屏有按下或松手事件发生时, 触控芯片会通过int脚发出通知信号. 设备驱动里在中断处理函数里读取坐标数据,但调用i2c_transfer函数会堵塞而中断处函数里不可以堵塞的, 所以用工作队列作中断的底半部,在中断的底半部里读取坐标.

实现标准的输入设备驱动,还需要在驱动加入输入设备的驱动模型.
为了方便QT程序的应用,实现单点触摸输入设备:
主要驱动模型:

    input_dev初始化
mydev->name = "my ts";
mydev->evbit[0] = BIT_MASK(EV_KEY)|BIT_MASK(EV_ABS); //支持事件类型, 触摸屏的坐标是绝对坐标
mydev->keybit[BIT_WORD(BTN_TOUCH)] |= BIT_MASK(BTN_TOUCH);//触摸按键支持

    set_bit(ABS_X, mydev->absbit); // 设置此输入设备的绝对坐标数据里有x, y, pressure数据
    set_bit(ABS_Y, mydev->absbit);
    set_bit(ABS_PRESSURE, mydev->absbit);

input_set_abs_params(mydev, ABS_X, 最小值, 最大值, 物理误差, 误差); //x轴的最小/大值
input_set_abs_params(mydev, ABS_Y, 0, 0x3ff, 0, 0);
input_set_abs_params(mydev, ABS_PRESSURE, 0, 1, 0, 0);

    采到坐标数据后:
        input_report_abs(mydev, ABS_X, x); //汇报坐标值
        input_report_abs(mydev, ABS_Y, y);
        input_report_key(mydev, BTN_TOUCH, 1); //汇报按下
        input_report_abs(mydev, ABS_PRESSURE, 1);
        input_sync(mydev);
    注意汇报坐标值时得要汇报按下

    收到up的中断后
    input_report_key(mydev, BTN_TOUCH, 0); //汇报松手
    input_report_abs(mydev, ABS_PRESSURE, 0);
    input_sync(mydev);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

///////////////////////
test.c


#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#include <linux/slab.h>
#include <linux/input.h>

typedef struct {
    struct workqueue_struct *queue; //  工作队列,用于调度工作任务
    struct work_struct work; // 工作任务,用于中断底半部
    struct i2c_client *cli; // i2c设备
    struct input_dev *dev; //输入设备
}mywork_t;

irqreturn_t ts_irq(int irqno, void *arg)
{
    mywork_t *mywork = (mywork_t *)arg;

    disable_irq_nosync(irqno); //关闭中断,等中断底半部接收坐标后再重新打开中断
    queue_work(mywork->queue, &mywork->work); //底半部的工作安排
    return IRQ_HANDLED;
}

void ts_work(struct work_struct *work) //中断底半部处理函数
{
    mywork_t *mywork = container_of(work, mywork_t, work);
    struct i2c_msg msg;
    struct i2c_client *cli = mywork->cli;
    unsigned char data[32];
    int x, y;


    msg.addr = cli->addr;
    msg.flags = I2C_M_RD;
    msg.len = 32;  //从地址为0的寄存器,连续读32个寄存器的值
    msg.buf = data;

    if (i2c_transfer(cli->adapter, &msg, 1) < 0)
    {
        printk("i2c transfer failed ...\n");
        return;
    }

    if ((data[3]>>6) == 1) //up
    {
        input_report_abs(mywork->dev, ABS_PRESSURE, 0);
        input_report_key(mywork->dev, BTN_TOUCH, 0);
        input_sync(mywork->dev);
    }
    else  //按下
    {
        x = ((data[3]&0xf)<<8) | data[4];
        y = ((data[5]&0xf)<<8) | data[6];


        input_report_abs(mywork->dev, ABS_X, x);
        input_report_abs(mywork->dev, ABS_Y, y);
        input_report_abs(mywork->dev, ABS_PRESSURE, 1);
        input_report_key(mywork->dev, BTN_TOUCH, 1);
        input_sync(mywork->dev);
    }   
    enable_irq(cli->irq); //重新打开中断
}

int myprobe(struct i2c_client *cli, const struct i2c_device_id *id)
{
    int ret;
    mywork_t *mywork;
    struct input_dev *dev;

    mywork = kzalloc(sizeof(*mywork), GFP_KERNEL); //准备i2c设备的数据

    mywork->cli = cli;
    mywork->queue = create_singlethread_workqueue("myts"); //创建工作队列
    INIT_WORK(&mywork->work, ts_work); //初始化工作任务

    dev = input_allocate_device(); //输入设备分配空间

    //初始化输入设备
    dev->name = "myts", 
    dev->evbit[0] = BIT_MASK(EV_KEY)|BIT_MASK(EV_ABS);
    dev->keybit[BIT_WORD(BTN_TOUCH)] |= BIT_MASK(BTN_TOUCH);

    input_set_abs_params(dev, ABS_X, 0, 800, 0, 0);         
    input_set_abs_params(dev, ABS_Y, 0, 480, 0, 0);     
    input_set_abs_params(dev, ABS_PRESSURE, 0, 1, 0, 0);

    dev->absbit[BIT_WORD(ABS_X)] |= BIT_MASK(ABS_X);
    dev->absbit[BIT_WORD(ABS_Y)] |= BIT_MASK(ABS_Y);
    dev->absbit[BIT_WORD(ABS_PRESSURE)] |= BIT_MASK(ABS_PRESSURE);

    mywork->dev = dev;

    input_register_device(dev); //注册输入设备
    dev_set_drvdata(&cli->dev, mywork);
    ret = request_irq(cli->irq, ts_irq, IRQF_TRIGGER_FALLING, "myts", mywork); //申请中断
    return ret;
}

int myremove(struct i2c_client *cli)
{
    mywork_t *mywork = dev_get_drvdata(&cli->dev);

    free_irq(cli->irq, mywork);
    cancel_work_sync(&mywork->work);
    destroy_workqueue(mywork->queue);
    input_unregister_device(mywork->dev);
    printk("in myremove ...\n");


    return 0;
}


struct i2c_device_id ids[] = {
    {"ft5x0x_ts"},
    {},
};

struct i2c_driver mydrv = {
    .probe = myprobe,
    .remove = myremove,

    .id_table = ids,

    .driver = {
        .name = "myi2c",
    },  
};

moudle_i2c_driver(mydrv);
MODULE_LICENSE("GPL");



2013-12-02 11:38:02 u013011925 阅读数 549

Linux加入到Windows域 收藏

--------------------------------------------------------------------------------

2009-12-07 09:52:56 标签:   [推送到技术圈]

一、实验环境:
AD server:windows server 2003
samba:redhat as5
AD server的hostname和IP地址:
turbomai-c89f91.test.com  192.168.0.122/24
AD samba的hostname和IP地址:
zhouhw       192.168.0.121/24
Domain name:turbomai-c89f91.test.com
DNS:192.168.151.122
安装NTP时间验证套件:
# mount /dev/cdrom /media
# rpm -ivh /cdrom/CentOS/RPMS/ntp-4.2.2p1-7.el5.i386.rpm
当然也可以用yum来安装
#yum -y install ntp (注意ntp要小写)
再来与AD server校准时间
# ntpdate 192.168.0.122
# hwclock -w
安装Samba服务器软件需求:
krb5-workstation-1.2.7-19
pam_krb5-1.70-1
krb5-devel-1.2.7-19
krb5-libs-1.2.7-19
samba-3.0.5-2
安装完后,如果你要确认samba安装成功没有可以用下述命令来检查samba包的基础库支持
# smbd -b | grep LDAP
HAVE_LDAP_H
HAVE_LDAP
HAVE_LDAP_DOMAIN2HOSTLIST
...
# smbd -b | grep KRB
HAVE_KRB5_H
HAVE_ADDRTYPE_IN_KRB5_ADDRESS
HAVE_KRB5
...
# smbd -b | grep ADS
WITH_ADS
WITH_ADS
# smbd -b | grep WINBIND
WITH_WINBIND
WITH_WINBIND
二、编辑设定档
1、krb5配置
#vi /etc/krb5.conf
[logging]
default = FILE:/var/log/krb5libs.log
kdc = FILE:/var/log/krb5kdc.log
admin_server = FILE:/var/log/kadmind.log
 
[libdefaults]
default_realm = TEST.COM # 大写域名
dns_lookup_realm = false
dns_lookup_kdc = false
ticket_lifetime = 24h
forwardable = yes
[realms]
TEST.COM = { # 大写域名
kdc = 192.168.0.122:88 # 域伺服器IP
admin_server = 192.168.0.122:749 # 域伺服器IP
default_domain = test.com # 这里就不用大写了
}
[domain_realm]
.ttest.com = TEST.COM # 域验证范围
test.com =TEST.COM
[kdc]
profile = /var/kerberos/krb5kdc/kdc.conf
[appdefaults]
pam = {
debug = false
ticket_lifetime = 36000
renew_lifetime = 36000
forwardable = true
krb4_convert = false
}
连接AD server
kinit administrator@TT.COM
Kerberos 的 kinit 命令将测试服务器间的通信,后面的域名TT.COM 是你的活动目录的域名,必须大写,否则会收到错误信息:
kinit(v5): Cannot find KDC for requested realm while getting initial credentials.
如果通信正常,你会提示输入口令,口令正确的话,就返回 bash 提示符,如果错误则报告:
kinit(v5): Preauthentication failed while getting initial credentials.
這一步代表了已经可以和AD server做沟通了,但并不代表Samba Server已经加入域了。
2、smb.conf配置
#vi /etc/samba/smb.conf
[global]
        workgroup = TEST # 一定要填自己的domain名稱
        netbios name = zhouhw #你的linux主机名
        idmap uid    = 15000-20000
        idmap gid    = 15000-20000
        winbind enum groups = yes
        winbind enum users  = yes
        winbind separator   = /
;       winbind use default domain = yes
        template homedir = /home/%D/%U
        template shell   = /bin/bash
 
        security = domain
 
        encrypt passwords = yes
        password server = 192.168.0.122
[homes]
   path = /home/%D/%U
   browseable = no
   writable = yes
   valid users = TESTcom/%U
   create mode = 0777
   directory mode = 0777
3、配置nsswitch.conf
#vi /etc/nsswitch.conf
修改以下位置
passwd:     files winbind
shadow:     files winbind
group:      files winbind
4、启用samba和winbind服务
service smb start
service winbind start
5、加入AD域
[root@zhouhw ~]# net rpc join -S turbomai-c89f91.test.com -U administrator
Password:
Joined domain TEST.
6、验证加入是否成功
[root@zhouhw ~]# net rpc testjoin
Join to 'TEST' is OK
7、做完这些,就可以到AD server上的活动目录中看到该机器了

2011-07-12 09:15:29 zhandoushi1982 阅读数 3056

        在驱动开发过程中,我们有时会碰到这种应用:比如说某款芯片的固件不是固定的,是可以后期升级的。那么在每次系统开机时,需要做个检测,如果检测到提供了新的固件,那么在第一次开机时就升级固件。之后由于保存了新的固件版本号可供检测,就不用再开机升级了。

        以一款I2C的触摸屏芯片为例,假设供应商提供的新固件文件名是Us3x06eb_use.it,将该文件放在触摸屏驱动.c的同目录下,那么需要做的就是在触摸屏的Probe函数里面加入对应的版本号检测处理,并决定是否升级。如果需要升级,将目标固件通过I2C写入即可。

typedef enum
{
       ERR_OK,
       ERR_MODE,
       ERR_READID,
       ERR_ERASE,
       ERR_STATUS,
       ERR_ECC,
       ERR_DL_ERASE_FAIL,
       ERR_DL_PROGRAM_FAIL,
       ERR_DL_VERIFY_FAIL
}E_UPGRADE_ERR_TYPE;

#define    FTS_PACKET_LENGTH        2    //一次写两个字节,作为一个PACKET

static unsigned char CTPM_FW[] =            //载入目标固件
{
      #include "Us3x06eb_use.it"
};

static int fts_i2c_txdata(u8 *txdata, int length)   //一次通过I2C传输多字节数据
{
       int ret;
       struct i2c_msg msg;
       msg.addr = i2c_client->addr;
       msg.flags = 0;
       msg.len = length;
       msg.buf = txdata;
       ret = i2c_transfer(i2c_client->adapter, &msg, 1);

       if(ret < 0)
       {
             pr_err("%s i2c write error: %d\n", __func__, ret);
       }

       return ret;
}

static bool i2c_write_interface(u8 *pbt_buf, int dw_lenth)    //通过I2C写多个数据
{
       int ret;
       ret = i2c_master_send(i2c_client, pbt_buf, dw_lenth);
       if(ret <= 0)
       {
             printk("[TSP]i2c_write_interface error line = %d, ret = %d\n", __LINE__, ret);
             return FTS_FALSE;
       }

       return FTS_TRUE;
}

static bool i2c_read_interface(u8 *pbt_buf, int dw_lenth)   //通过I2C读多个数据
{
       int ret;
       ret = i2c_master_recv(i2c_client, pbt_buf, dw_lenth);
       if(ret <= 0)
       {
              printk("[TSP]i2c_read_interface error\n");
              return FTS_FALSE;
       }

       return FTS_TRUE;
}

static bool fts_register_write(u8 reg_name, u8 *tx_buf)     //往寄存器写单字节数据
{
       u8 write_cmd[2] = {0};
       write_cmd[0] = reg_name;
       write_cmd[1] = *tx_buf;
       return i2c_write_interface(write_cmd, 2);
}

static bool fts_register_read(u8 reg_name, u8 *rx_buf, int rx_length)    //从寄存器读多个数据
{
       u8 read_cmd[2] = {0};
       u8 cmd_len  = 0;
       read_cmd[0] = reg_name;
       cmd_len = 1;

       /*send register addr*/
       if(!i2c_write_interface(&read_cmd[0], cmd_len))
       {
              return FTS_FALSE;
       }

       if(!i2c_read_interface(rx_buf, rx_length))
       {
              return FTS_FALSE;
       }

       return FTS_TRUE;
}


      E_UPGRADE_ERR_TYPE  fts_ctpm_fw_upgrade(u8 *pbt_buf, int dw_lenth)   //编程烧录细节不阐述,实例会在本博客的续篇中列出

{

       //将数据划分成相应的PACKET,一次通过I2C写入芯片中。有几个问题需要注意:(1)要注意分包的衔接,数据长度未必恰好能划分成整数个包,那么最后一个包要单独

       //处理;(2)数据校验,比如说芯片带自动异或校验的话,一方面我们在发送的过程中要及时进行数据校验运算,另一方面在数据发送完毕后,可以把这个校验值跟校验

       //寄存器的值进行比较,从而判断当前传输是否有效。

}

int fts_ctpm_fw_upgrade_with_i_file(void)
{
       u8     *pbt_buf = 0x0;
       int ret;
       pbt_buf = CTPM_FW;
       ret =  fts_ctpm_fw_upgrade(pbt_buf, sizeof(CTPM_FW));     //升级特定文件
       return ret;
}

static int __devinit tpd_probe(struct i2c_client *client, const struct i2c_device_id *id) //TP的probe函数

{

        .............

        { 
               u8 reg_val=0;
               mdelay(50);
               fts_register_read(0xA6,®_val,1);     //读出当前版本号
                 if(reg_val<TP_LIB_VERSION)    //如果当前版本号小于待升级版本号,进行升级
                {
                       printk("TP firmware version OK, start upgrade\n"); 
                       fts_ctpm_fw_upgrade_with_i_file();   
              }
       }

        .............

}

2009-03-08 16:56:00 telnetor 阅读数 451
2013-02-01 09:56:16 sir_zeng 阅读数 558
在驱动开发过程中,我们有时会碰到这种应用:比如说某款芯片的固件不是固定的,是可以后期升级的。那么在每次系统开机时,需要做个检测,如果检测到提供了新的固件,那么在第一次开机时就升级固件。之后由于保存了新的固件版本号可供检测,就不用再开机升级了。

        以一款I2C的触摸屏芯片为例,假设供应商提供的新固件文件名是Us3x06eb_use.it,将该文件放在触摸屏驱动.c的同目录下,那么需要做的就是在触摸屏的Probe函数里面加入对应的版本号检测处理,并决定是否升级。如果需要升级,将目标固件通过I2C写入即可。

  1. typedef enum 
  2.        ERR_OK, 
  3.        ERR_MODE, 
  4.        ERR_READID, 
  5.        ERR_ERASE, 
  6.        ERR_STATUS, 
  7.        ERR_ECC, 
  8.        ERR_DL_ERASE_FAIL, 
  9.        ERR_DL_PROGRAM_FAIL, 
  10.        ERR_DL_VERIFY_FAIL 
  11. }E_UPGRADE_ERR_TYPE; 
  12.  
  13. #define    FTS_PACKET_LENGTH        2    //一次写两个字节,作为一个PACKET 
  14.  
  15. static unsigned char CTPM_FW[] =            //载入目标固件 
  16.       #include "Us3x06eb_use.it" 
  17. }; 
  18.  
  19. static int fts_i2c_txdata(u8 *txdata, int length)   //一次通过I2C传输多字节数据 
  20.        int ret; 
  21.        struct i2c_msg msg; 
  22.        msg.addr = i2c_client->addr; 
  23.        msg.flags = 0; 
  24.        msg.len = length; 
  25.        msg.buf = txdata; 
  26.        ret = i2c_transfer(i2c_client->adapter, &msg, 1); 
  27.  
  28.        if(ret < 0) 
  29.        { 
  30.              pr_err("%s i2c write error: %d\n", __func__, ret); 
  31.        } 
  32.  
  33.        return ret; 
  34.  
  35. static bool i2c_write_interface(u8 *pbt_buf, int dw_lenth)    //通过I2C写多个数据 
  36.        int ret; 
  37.        ret = i2c_master_send(i2c_client, pbt_buf, dw_lenth); 
  38.        if(ret <= 0) 
  39.        { 
  40.              printk("[TSP]i2c_write_interface error line = %d, ret = %d\n", __LINE__, ret); 
  41.              return FTS_FALSE; 
  42.        } 
  43.  
  44.        return FTS_TRUE; 
  45.  
  46. static bool i2c_read_interface(u8 *pbt_buf, int dw_lenth)   //通过I2C读多个数据 
  47.        int ret; 
  48.        ret = i2c_master_recv(i2c_client, pbt_buf, dw_lenth); 
  49.        if(ret <= 0) 
  50.        { 
  51.               printk("[TSP]i2c_read_interface error\n"); 
  52.               return FTS_FALSE; 
  53.        } 
  54.  
  55.        return FTS_TRUE; 
  56.  
  57. static bool fts_register_write(u8 reg_name, u8 *tx_buf)     //往寄存器写单字节数据 
  58.        u8 write_cmd[2] = {0}; 
  59.        write_cmd[0] = reg_name; 
  60.        write_cmd[1] = *tx_buf; 
  61.        return i2c_write_interface(write_cmd, 2); 
  62.  
  63. static bool fts_register_read(u8 reg_name, u8 *rx_buf, int rx_length)    //从寄存器读多个数据 
  64.        u8 read_cmd[2] = {0}; 
  65.        u8 cmd_len  = 0; 
  66.        read_cmd[0] = reg_name; 
  67.        cmd_len = 1; 
  68.  
  69.        /*send register addr*/ 
  70.        if(!i2c_write_interface(&read_cmd[0], cmd_len)) 
  71.        { 
  72.               return FTS_FALSE; 
  73.        } 
  74.  
  75.        if(!i2c_read_interface(rx_buf, rx_length)) 
  76.        { 
  77.               return FTS_FALSE; 
  78.        } 
  79.  
  80.        return FTS_TRUE; 


      E_UPGRADE_ERR_TYPE  fts_ctpm_fw_upgrade(u8 *pbt_buf, int dw_lenth)   //编程烧录细节不阐述,实例会在本博客的续篇中列出

{

       //将数据划分成相应的PACKET,一次通过I2C写入芯片中。有几个问题需要注意:(1)要注意分包的衔接,数据长度未必恰好能划分成整数个包,那么最后一个包要单独

       //处理;(2)数据校验,比如说芯片带自动异或校验的话,一方面我们在发送的过程中要及时进行数据校验运算,另一方面在数据发送完毕后,可以把这个校验值跟校验

       //寄存器的值进行比较,从而判断当前传输是否有效。

}

  1. int fts_ctpm_fw_upgrade_with_i_file(void
  2.        u8     *pbt_buf = 0x0; 
  3.        int ret; 
  4.        pbt_buf = CTPM_FW; 
  5.        ret =  fts_ctpm_fw_upgrade(pbt_buf, sizeof(CTPM_FW));     //升级特定文件 
  6.        return ret; 
  7.  
  8. static int __devinit tpd_probe(struct i2c_client *client, const struct i2c_device_id *id) //TP的probe函数 
  9.  
  10.  
  11.         ............. 
  12.  
  13.         {  
  14.                u8 reg_val=0; 
  15.                mdelay(50); 
  16.                fts_register_read(0xA6,®_val,1);     //读出当前版本号 
  17.                  if(reg_val<TP_LIB_VERSION)    //如果当前版本号小于待升级版本号,进行升级 
  18.                 { 
  19.                        printk("TP firmware version OK, start upgrade\n");  
  20.                        fts_ctpm_fw_upgrade_with_i_file();    
  21.               } 
  22.        } 
  23.  
  24.         ............. 
  25.  

69 linux i2c设备驱动之ft5306电容触控芯片驱动

阅读数 782

lcd的显示部分与触摸部分实际是分开的。电容屏的触摸相当于在lcd屏上覆盖一个透明的矩阵键盘, 当用户按下时,可以获取用按下的坐标位置.通常情况不管是电阻还是电容屏,现都使用一个触控芯片,用于处理用户的操作坐标及实现与SOC的坐标数据的交互.电阻的触控芯片有:tsc2046,还有国内的:xx2046电容的触控芯片有:ft5x06(9寸屏以下使用),gt9271(9寸屏以上用)注

博文 来自: jklinux

Linux的芯片驱动firmware自动升级之二:MELFAS的TP升级实例

阅读数 595

以MELFAS的MS6000芯片固件升级实例,说明一般的数组格式的IMAGE文件烧录的过程。该芯片需要PIN脚组合完成一定的时序并实现一组命令码进入烧录模式,并且在烧录模式下的I2C地址是0XFA(跟芯片正常工作时的地址0X40不同),在烧录完毕后进行复位并开始相应正常的TP操作。芯片大致的烧录了流程图如下:         实现代码如下:(1)基础宏定义[cpp]

博文 来自: sir_zeng

Linux的芯片驱动firmware自动升级之二:MELFAS的TP升级实例

阅读数 3207

以MELFAS的MS6000芯片固件升级实例,说明一般的数组格式的IMAGE文件烧录的过程。该芯片需要PIN脚组合完成一定的时序并实现一组命令码进入烧录模式,并且在烧录模式下的I2C地址是0XFA(跟芯片正常工作时的地址0X40不同),在烧录完毕后进行复位并开始相应正常的TP操作。芯片大致的烧录了流程图如下:         实现代码如下:(1)基础宏定义#defineFIAM

博文 来自: zhandoushi1982

How to add Linux Samba to AD

阅读数 3

SetupsambaonlinuxserverLinuxmustbeconfiguredinordertobelongtoaWindowsdomain.ThisisdonebyusingtheSambafileserverwhichoffersseveralinterestingtools.Thegoali...

博文 来自: weixin_34259559

AD管理linux客户端

阅读数 6

https://www.jianshu.com/p/ecfc5a8c4237AD1.xxx.corp:是贵司WindowsAD上xxx.corp这个域的全局主域控制器LoginNO:是贵司AD域xxx.corp中一个组admin.win:是贵司AD域xxx.corp中的一个具有管理员权限的用户Daha.Ma:是贵司AD域xxx.corp...

博文 来自: weixin_33812433
没有更多推荐了,返回首页