Freescale P4080 I2C 驱动分析
来源:互联网 发布:卡盟外包系统源码 编辑:程序博客网 时间:2024/06/11 09:14
Freescale P4080是一款8核心网络处理器,功能强大,外设齐全,基于powerpc e500 core。在嵌入式网络应用上被广泛使用。
今天只讨论P4080的I2C部分。
P4080片上集成了4个I2C 控制器,在我们的应用中,这4个I2C Controller 都是作为master来使用。
先来一张I2C 控制器的结构图
这张图描述了一I2C 控制器应该有的寄存器,描述了各寄存器应有的功能。
其实,实现I2C驱动的关键就在于按照文档进行配置这些寄存器。不单是I2C,大部分驱动程序都是这样,比如DDR,SPI,DMA等都是按照文档,
提供一个接口(函数)来访问硬件,这就是所谓的驱动啦。
来看一下p4080上是怎么规定这么资源(registers)的地址的
规定了各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 int354 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_MTX409 | (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__ int421 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 int493 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() >= 0499 && i2c_write_addr(dev, I2C_WRITE_BIT, 0) != 0500 && __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的地址哦
- Freescale P4080 I2C 驱动分析
- linux I2C驱动分析
- linux I2C驱动分析
- Linux I2C 驱动分析
- I2C驱动分析
- Linux驱动I2C分析
- linux i2c 驱动分析
- I2C驱动分析
- I2C驱动分析
- Linux--I2C驱动分析
- linux i2c驱动分析
- i2c驱动分析
- linux i2c驱动分析
- i2c驱动分析
- Linux I2C 驱动分析
- i2c内核驱动分析
- Linux I2C驱动分析
- Freescale imx6 linux platform 驱动模型分析
- dtree+右键菜单 完美结合
- MuPDF在iOS平台的编译
- 在手机应用研发方面,IT专业人士对Android的兴趣远超iOS
- ImagePreview 图片预览 IE6下错误的问题
- Google adwords的优化
- Freescale P4080 I2C 驱动分析
- JQuery知识
- 火狐插件 YSlow插件帮助测试网站的加载速度
- Maven pom文件常用配置小结
- 自己DIY脱机下载- 硬件篇
- 用java编写生产者消费者程序
- 4.1.3,int *p = NULL 和*p = NULL 有什么区别?
- WIN API-VFP取得任务栏的尺寸(宽度和高度)及位置
- Android 使用Matrix实例