Freescale P4080 I2C 驱动分析

 Freescale P4080是一款8核心网络处理器,功能强大,外设齐全,基于powerpc e500 core。在嵌入式网络应用上被广泛使用。

今天只讨论P4080的I2C部分。

P4080片上集成了4个I2C 控制器,在我们的应用中,这4个I2C Controller 都是作为master来使用。

先来一张I2C 控制器的结构图

Freescale P4080 I2C 驱动分析_第1张图片

这张图描述了一I2C 控制器应该有的寄存器,描述了各寄存器应有的功能。

其实,实现I2C驱动的关键就在于按照文档进行配置这些寄存器。不单是I2C,大部分驱动程序都是这样,比如DDR,SPI,DMA等都是按照文档,

提供一个接口(函数)来访问硬件,这就是所谓的驱动啦。

来看一下p4080上是怎么规定这么资源(registers)的地址的

Freescale P4080 I2C 驱动分析_第2张图片

规定了各I2C控制器的基地址,以及各控制器中的寄存器偏移。我们要按照这个地址进行组织代码,写一个结构体进行

描述I2C控制器,下面的结构体来自freescale

typedef struct fsl_i2c {

    u8 adr;     /* I2C slave address */
    u8 res0[3];
#define I2C_ADR     0xFE
#define I2C_ADR_SHIFT   1
#define I2C_ADR_RES ~(I2C_ADR)

    u8 fdr;     /* I2C frequency divider register */
    u8 res1[3];
#define IC2_FDR     0x3F
#define IC2_FDR_SHIFT   0
#define IC2_FDR_RES ~(IC2_FDR)

    u8 cr;      /* I2C control redister */
    u8 res2[3];
#define I2C_CR_MEN  0x80
#define I2C_CR_MIEN 0x40
#define I2C_CR_MSTA 0x20
#define I2C_CR_MTX  0x10
#define I2C_CR_TXAK 0x08
#define I2C_CR_RSTA 0x04
#define I2C_CR_BCST 0x01

    u8 sr;      /* I2C status register */
    u8 res3[3];
#define I2C_SR_MCF  0x80
#define I2C_SR_MAAS 0x40
#define I2C_SR_MBB  0x20
#define I2C_SR_MAL  0x10
#define I2C_SR_BCSTM    0x08
#define I2C_SR_SRW  0x04
#define I2C_SR_MIF  0x02
#define I2C_SR_RXAK 0x01

    u8 dr;      /* I2C data register */
    u8 res4[3];
#define I2C_DR      0xFF
#define I2C_DR_SHIFT    0
#define I2C_DR_RES  ~(I2C_DR)

    u8 dfsrr;   /* I2C digital filter sampling rate register */
    u8 res5[3];
#define I2C_DFSRR   0x3F
#define I2C_DFSRR_SHIFT 0
#define I2C_DFSRR_RES   ~(I2C_DR)

    /* Fill out the reserved block */
    u8 res6[0xE8];
} fsl_i2c_t;


看到了吧,是不是严格按照上图的顺序来的。这样,在配置寄存器的时候就方便多了,只需要知道一个指向该控制器的结构体指针,

然后配置里面的各项,实际上正好是配置了各个寄存器,这也是在驱动中常用的方法。

四个寄存器的基地址也是定义好的

#define CONFIG_SYS_I2C_OFFSET       0x118000
#define CONFIG_SYS_I2C2_OFFSET      0x118100
第三,第四个控制器为0x119000, 0x119100
在加上系统的基地址(这个是所有控制器都要加上的,在这里,控制器的base address相当于在系统上的一个偏移,哈哈,类似分页了)
定义四个控制器结构体
66 #if defined CONFIG_SYS_NUM_OF_I2C
 67 static unsigned int i2c_bus_speed[CONFIG_SYS_NUM_OF_I2C] = {CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SPEED,CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SPEED };
 68 
 69  const struct fsl_i2c *i2c_dev[CONFIG_SYS_NUM_OF_I2C] = {
 70     (struct fsl_i2c *) (CONFIG_SYS_IMMR + CONFIG_SYS_I2C_OFFSET),
 71     (struct fsl_i2c *) (CONFIG_SYS_IMMR + CONFIG_SYS_I2C_OFFSET + 0x100),
 72 #if defined(CONFIG_PPC_P4080)                // (dual) i2c module #2
 73     (struct fsl_i2c *) (CONFIG_SYS_IMMR + CONFIG_SYS_I2C_OFFSET + 0x1000),
 74     (struct fsl_i2c *) (CONFIG_SYS_IMMR + CONFIG_SYS_I2C_OFFSET + 0x1000 + 0x100)
 75 #endif
 76 };

 

至此,I2C Controller在内存中的表示就已经完成了,剩下的就是如何配置按照文档进行配置它们,使之能正常工作。


 

需要配置的是速度,这个在文档中也是有规定的,只需要按照方法一步步来就可以了。

然后实现reset函数,就是像寄存器cr中写固定的值,这些都是硬件决定的,没什么好讲,其实驱动就是这个样子,你可能在上层实现的优雅一点,但是

对于最底层,谁也无能为力,比如实现reset的函数

239 void i2c_soft_reset(const struct fsl_i2c *dev )
240 {
241     volatile u8 cTmp;
242 
243         debug("\t@%08x:  I2CCSR:%02x I2CCCR:%02x  ", (int) dev, readb(&dev->sr), readb(&dev->cr));
244 
245         /* per 11.5.6 of 8548 UM */
246         writeb(0x20, &dev->cr); //这里都是硬件规定,不要问为啥是0x20, 00100000这个值中已经申明了某一位置位
247         udelay(1000);
248         writeb(0xA0, &dev->cr);          /* start condition */
249         udelay(1000);
250 
251         cTmp =  readb(&dev->dr);         /* kick off the read 8 data + ack */
252         debug("I2CCDR:%02x %s \n", cTmp, __FUNCTION__);
253 
254         writeb(0x0, &dev->cr);             /* disable and leave it alone */
255         udelay(1000);
256 
257 }
硬件给提供的接口就是你配置寄存器(或寄存器的某一位,某几位)就能实现神马功能,就是这样!
有了上述两操作,可以提供init函数了,就是设置速度,然后reset。
 
接着,终于步入最关键的, 实现读写啊!
 
无论是读还是写之前,先要看看总线是否空闲
353 static int
354 i2c_wait4bus(void)
355 {
356     unsigned long long timeval = get_ticks();
357     const unsigned long long timeout = usec2ticks(CONFIG_I2C_MBB_TIMEOUT);
358 
359     while (readb(&i2c_dev[i2c_bus_num]->sr) & I2C_SR_MBB) {
360         if ((get_ticks() - timeval) > timeout)
361             return -1;
362     }
363 
364     return 0;
365 }
 
接着,就要跟I2C协议扯上关系了,比如一个读的过程,一写的过程,具体有哪几步,哈,还是看协议吧,我是看了就忘
406 static int i2c_write_addr (u8 dev, u8 dir, int rsta)
407 {
408     writeb(I2C_CR_MEN | I2C_CR_MSTA | I2C_CR_MTX
409            | (rsta ? I2C_CR_RSTA : 0),
410            &i2c_dev[i2c_bus_num]->cr);
411 
412     writeb((dev << 1) | dir, &i2c_dev[i2c_bus_num]->dr);
413 
414     if (i2c_wait(I2C_WRITE_BIT) < 0)
415         return 0;
416 
417     return 1;
418 }
419 
420 // static __inline__ int
421 static int __i2c_write(u8 *data, int length)
422 {
423     int i;
424 
425     for (i = 0; i < length; i++) {
426         writeb(data[i], &i2c_dev[i2c_bus_num]->dr);
427 
428         if (i2c_wait(I2C_WRITE_BIT) < 0)
429             break;
430     }
431 
432     return i;
433 }
上面两个函数就是,一个发地址,一个发数据
492 int
493 i2c_write(u8 dev, uint addr, int alen, u8 *data, int length)
494 {
495     int i = -1; /* signal error */
496     u8 *a = (u8*)&addr;
497 
498     if (i2c_wait4bus() >= 0
499         && i2c_write_addr(dev, I2C_WRITE_BIT, 0) != 0
500         && __i2c_write(&a[4 - alen], alen) == alen) {
501         i = __i2c_write(data, length);
502     }
503 
504     writeb(I2C_CR_MEN, &i2c_dev[i2c_bus_num]->cr);
505     if (i2c_wait4bus()) /* Wait until STOP */
506         debug("i2c_write: wait4bus timed out\n");
507 
508     if (i == length)
509         return 0;
510 
511     return -1;
512 }
这个接口就可以提供给上层使用啦。dev是slave的地址哦

你可能感兴趣的:(c,struct,filter,网络应用,文档,Signal)