linux下i2c与时钟芯片pcf8563的通信

本文介绍了如何在Linux系统下,特别是在搭载Cavium Networks OCTEON CN52XX处理器的硬件平台上,实现通过i2c总线与pcf8563时钟芯片进行通信。重点讨论了数据的包装和发送过程,模拟用户层的操作来实现这一功能。
摘要由CSDN通过智能技术生成

                    
linux下的i2c驱动以及与时钟芯片pcf8563通信过程             


为更深入的了解linux下的i2c总线驱动以及通信原理,可以用一个用户程序模拟,

这个程序,可以使用一个addr, 一个offset,对i2c的从设备地址为addr,寄存器地址为offset的寄存器读写操作。  

在我们的版卡上时钟芯片pcf8563的i2c地址为0x51  , pcf8563有00—0f个寄存器,通过读写秒,分钟,小时等的寄存器,可以验证我们的程序是否执行成功。

一,这个测试程序怎么写?

思路是:  hwclock -w /hwclock -s 这些命令都是对始终芯片pcf8563执行了读写的操作命令,那么我们的程序,就模仿hwclock -w 的执行过程,最后实现通过cpu(octeon) 与i2c从设备的数据通信。 这样就看到了i2c总线在处理器octeon的控制下的通信过程。

二,怎么观察hwclock -w 的执行过程?

hwclock -w 读写了时钟芯片pcf8563,那么从pcf8563的驱动程序入手,在pcf8563中的read,write 函数中进入i2c层。再有i2c层进入octeon。

即从rtc层进入i2c层, 再进入cpu层。 在这之间的执行函数分别加printk,在版卡上观察dmesg, 这样就可以找到执行的层层路径。

知道了数据的发送路径,再观察出hwclock -w 实现了哪些数据的包装和发送,那么我们的程序就可以在以用户层模仿这些操作。

注意:

我们版卡的cpuCaviumNetworks OCTEON CN52XX


****************************************************************************** *************************

by 韩大卫@吉林师范大学
		 
 															handawei@jusontech.com
 
 														转载务必表明出处!
                                                            

 
********************************************** *******************************

hwclock -w  命令需要使用到的rtc芯片pcf8563中的读写函数如下:


在driver/rtc/rtc-pcf8563.c 中

 static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm)
{
        struct pcf8563 *pcf8563 = i2c_get_clientdata(client);
        int i, err;
        unsigned char buf[9];

        printk(KERN_DEBUG "%s:  secs=%d, mins=%d, hours=%d,ecs=%d, mins=%d, hours=%d\n",
                                __func__,
                                tm->tm_sec, tm->tm_min, tm->tm_hour,
                                tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);


        /* hours, minutes and seconds */
        buf[PCF8563_REG_SC] = bin2bcd(tm->tm_sec);
        buf[PCF8563_REG_MN] = bin2bcd(tm->tm_min);
        buf[PCF8563_REG_HR] = bin2bcd(tm->tm_hour);

        buf[PCF8563_REG_DM] = bin2bcd(tm->tm_mday);

        /* month, 1 - 12 */
        buf[PCF8563_REG_MO] = bin2bcd(tm->tm_mon + 1);

        /* year and century */
        buf[PCF8563_REG_YR] = bin2bcd(tm->tm_year % 100);
        if (pcf8563->c_polarity ? (tm->tm_year >= 100) : (tm->tm_year < 100))
                buf[PCF8563_REG_MO] |= PCF8563_MO_C;

        buf[PCF8563_REG_DW] = tm->tm_wday & 0x07;

        /* write register's data */
        for (i = 0; i < 7; i++) {
                unsigned char data[2] = { PCF8563_REG_SC + i,
                                                buf[PCF8563_REG_SC + i] };

           
                err = i2c_master_send(client, data, sizeof(data));
                if (err != sizeof(data)) {
                        dev_err(&client->dev,
                                "%s: err=%d addr=%02x, data=%02x\n",
                                __func__, err, data[0], data[1]);
                        return -EIO;
                }   


在 driver/i2c/i2c-core.c 中:


int i2c_master_send(struct i2c_client *client,const char *buf ,int count)
{
        int ret;
        struct i2c_adapter *adap=client->adapter;
        struct i2c_msg msg;

        msg.addr = client->addr;
        msg.flags = client->flags & I2C_M_TEN;
        msg.len = count;
        msg.buf = (char *)buf;
    
       //added by handwei.2012.7.5
printk(KERN_DEBUG "%s: msg.addr = %x,msg.flags = %x,msg.len = %d,msg.buf[0] = %x,msg.buf[1] = %x\n",__func__,msg.addr,msg.flags,msg.len,msg.buf[0],msg.buf[1]);

        ret = i2c_transfer(adap, &msg, 1);

        /* If everything went ok (i.e. 1 msg transmitted), return #bytes
           transmitted, else error code. */
        return (ret == 1) ? count : ret;
}


注意: i2c_transfer(adap, &msg, 1);

中的 1 决定了 进入 octeon_i2c_xfer ()后,要进入 if(num==1)中。

下面是 octeon_i2c_xfer的代码:

static int octeon_i2c_xfer(struct i2c_adapter *adap,
                           struct i2c_msg *msgs,
                           int num)
{
        printk(KERN_DEBUG "here is octeon_i2c_xfer,num = %d\n",num);
        struct i2c_msg *pmsg;
        int i;
        int ret = 0;
        struct octeon_i2c *i2c = i2c_get_adapdata(adap);

        if (num == 1) {
                if (msgs[0].len > 0 && msgs[0].len <= 8) {
                        if (msgs[0].flags & I2C_M_RD)
                                ret = octeon_i2c_simple_read(i2c, msgs);
                        else
                                ret = octeon_i2c_simple_write(i2c, msgs);
                        goto out;
                }    
        } else if (num == 2) {
                if ((msgs[0].flags & I2C_M_RD) == 0 &&
                    msgs[0].len > 0 && msgs[0].len <= 2 &&
                    msgs[1].len > 0 && msgs[1].len <= 8 &&
                    msgs[0].addr == msgs[1].addr) {
                        if (msgs[1].flags & I2C_M_RD)
                                ret = octeon_i2c_ia_read(i2c, msgs);
                        else
                                ret = octeon_i2c_ia_write(i2c, msgs);
                        goto out;
                }    
        }    

        for (i = 0; ret == 0 && i < num; i++) {
                pmsg = &msgs[i];
                dev_dbg(i2c->dev,
                        "Doing %s %d byte(s) to/from 0x%02x - %d of %d messages\n",
                         pmsg->flags & I2C_M_RD ? "read" : "write",
                         pmsg->len, pmsg->addr, i + 1, num);
                if (pmsg->flags & I2C_M_RD)
                        ret = octeon_i2c_read(i2c, pmsg->addr, pmsg->buf,
                                              pmsg->len, i);
             else
                                ret = octeon_i2c_ia_write(i2c, msgs);
                                                                         }
        octeon_i2c_stop(i2c);
out:
        return (ret != 0) ? ret : num;
}



通过在 i2c-core.c: i2c_master_send()中添加printk,
 
        printk(KERN_DEBUG "%s: msg.addr = %x,msg.flags =
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值