I2C

时间:2023-03-08 23:45:08
I2C

1.I2C协议
个。

I2C

2.1 I2CADR 地址寄存器

CPU也可以是I2C的Slave,CPU的I2C地址有 I2CADR指定
I2C
 

2.2 I2CFDR 频率设置寄存器
I2C
The serial bit clock frequency of SCL is equal to the CCB clock divided by the divider.
用来设置I2C总线频率

2.3 I2CCR 控制寄存器

I2C

MEN: Module Enable.    置1时,I2C模块使能
MIEN:Module Interrupt Enable. 置1时,I2C中断使能。
MSTA:Master/slave mode. 1 Master mode,0 Slave mode.
        当1->0时,CPU发起STOP信号
        当0->1时,CPU发起START信号
MTX:Transmit/receive mode select.0 Receive mode,1 Transmit mode
TXAK:Transfer acknowledge. 置1时,CPU在9th clock发送ACK拉低SDA
RSTA:Repeat START. 置1时,CPU发送REPEAT START
BCST:置1,CPU接收广播信息(信息的slave addr为7个0)

2.4 I2CSR 状态寄存器

I2C

MCF:0  Byte transfer is in process
     1  Byte transfer is completed

MAAS:当CPU作为Slave时,若I2CDR与会话中Slaveaddr匹配,此bit被置1

MBB:0 I2C bus idle  
     1 I2C bus busy

MAL:若置1,表示仲裁失败
BCSTM:若置1,表示接收到广播信息

SRW:When MAAS is set, SRW indicates the value of the R/W command bit of the calling address, which is sent from the master.
   0 Slave receive, master writing to slave
   1 Slave transmit, master reading from slave

MIF:Module interrupt. The MIF bit is set when an interrupt is pending, causing a processor interrupt request(provided I2CCR[MIEN] is set)

RXAK:若置1,表示收到了ACK

2.5 I2CDR 数据寄存器

I2C

这个寄存器储存CPU将要传输的数据。

3. PPC-Linux中I2C的实现
 
  内核代码(linux-2.6.24)中,通过I2C总线存取寄存器的函数都在文件drivers/i2c/busses/i2c-mpc.c中
  最重要的函数是mpc_xfer.
  

  1. static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
  2. {
  3. struct i2c_msg *pmsg;
  4. int i;
  5. int ret = 0;
  6. unsigned long orig_jiffies = jiffies;
  7. struct mpc_i2c *i2c = i2c_get_adapdata(adap);
  8. mpc_i2c_start(i2c);    // 设置I2CCR[MEN], 使能I2C module
  9. /* Allow bus up to 1s to become not busy */
  10. //一直读I2CSR[MBB],等待I2C总线空闲下来
  11. while (readb(i2c->base + MPC_I2C_SR) & CSR_MBB) {
  12. if (signal_pending(current)) {
  13. pr_debug("I2C: Interrupted\n");
  14. writeccr(i2c, 0);
  15. return -EINTR;
  16. }
  17. if (time_after(jiffies, orig_jiffies + HZ)) {
  18. pr_debug("I2C: timeout\n");
  19. if (readb(i2c->base + MPC_I2C_SR) ==
  20. (CSR_MCF | CSR_MBB | CSR_RXAK))
  21. mpc_i2c_fixup(i2c);
  22. return -EIO;
  23. }
  24. schedule();
  25. }
  26. for (i = 0; ret >= 0 && i < num; i++) {
  27. pmsg = &msgs[i];
  28. pr_debug("Doing %s %d bytes to 0x%02x - %d of %d messages\n",
  29. pmsg->flags & I2C_M_RD ? "read" : "write",
  30. pmsg->len, pmsg->addr, i + 1, num);
  31. //根据消息里的flag进行读操作或写操作
  32. if (pmsg->flags & I2C_M_RD)
  33. ret = mpc_read(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);
  34. else
  35. ret = mpc_write(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);
  36. }
  37. mpc_i2c_stop(i2c);    //保证为I2CCSR[MSTA]为0,保证能触发STOP
  38. return (ret < 0) ? ret : num;
  39. }

  1. static int mpc_write(struct mpc_i2c *i2c, int target,
  2. const u8 * data, int length, int restart)
  3. {
  4. int i;
  5. unsigned timeout = i2c->adap.timeout;
  6. u32 flags = restart ? CCR_RSTA : 0;
  7. /* Start with MEN */    //以防万一,保证I2C模块使能起来
  8. if (!restart)
  9. writeccr(i2c, CCR_MEN);
  10. /* Start as master */       //写了I2CCR[CCR_MSTA],触发CPU发起START信号
  11. writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags);
  12. /* Write target byte */     //CPU发送一个字节,slave I2C addr和0 (写操作bit)
  13. writeb((target << 1), i2c->base + MPC_I2C_DR);
  14. if (i2c_wait(i2c, timeout, 1) < 0)    //等待slave 发ACK
  15. return -1;
  16. for (i = 0; i < length; i++) {
  17. /* Write data byte */
  18. writeb(data[i], i2c->base + MPC_I2C_DR); //CPU接着发数据,包括reg addr和data
  19. if (i2c_wait(i2c, timeout, 1) < 0)       //等待slave 发ACK
  20. return -1;
  21. }
  22. return 0;
  23. }

  1. static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
  2. {
  3. unsigned long orig_jiffies = jiffies;
  4. u32 x;
  5. int result = 0;
  6. if (i2c->irq == 0)
  7. {    //循环读I2CSR,直到I2CSR[MIF]置1
  8. while (!(readb(i2c->base + MPC_I2C_SR) & CSR_MIF)) {
  9. schedule();
  10. if (time_after(jiffies, orig_jiffies + timeout)) {
  11. pr_debug("I2C: timeout\n");
  12. writeccr(i2c, 0);
  13. result = -EIO;
  14. break;
  15. }
  16. }
  17. x = readb(i2c->base + MPC_I2C_SR);
  18. writeb(0, i2c->base + MPC_I2C_SR);
  19. } else {
  20. /* Interrupt mode */
  21. result = wait_event_interruptible_timeout(i2c->queue,
  22. (i2c->interrupt & CSR_MIF), timeout * HZ);
  23. if (unlikely(result < 0)) {
  24. pr_debug("I2C: wait interrupted\n");
  25. writeccr(i2c, 0);
  26. } else if (unlikely(!(i2c->interrupt & CSR_MIF))) {
  27. pr_debug("I2C: wait timeout\n");
  28. writeccr(i2c, 0);
  29. result = -ETIMEDOUT;
  30. }
  31. x = i2c->interrupt;
  32. i2c->interrupt = 0;
  33. }
  34. if (result < 0)
  35. return result;
  36. if (!(x & CSR_MCF)) {
  37. pr_debug("I2C: unfinished\n");
  38. return -EIO;
  39. }
  40. if (x & CSR_MAL) {    //仲裁失败
  41. pr_debug("I2C: MAL\n");
  42. return -EIO;
  43. }
  44. if (writing && (x & CSR_RXAK)) {//写后没收到ACK
  45. pr_debug("I2C: No RXAK\n");
  46. /* generate stop */
  47. writeccr(i2c, CCR_MEN);
  48. return -EIO;
  49. }
  50. return 0;
  51. }

  1. static int mpc_read(struct mpc_i2c *i2c, int target,
  2. u8 * data, int length, int restart)
  3. {
  4. unsigned timeout = i2c->adap.timeout;
  5. int i;
  6. u32 flags = restart ? CCR_RSTA : 0;
  7. /* Start with MEN */    //以防万一,保证I2C模块使能
  8. if (!restart)
  9. writeccr(i2c, CCR_MEN);
  10. /* Switch to read - restart */
  11. //注意这里,再次把CCR_MSTA置1,再触发 START
  12. writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags);
  13. /* Write target address byte - this time with the read flag set */
  14. //CPU发送slave I2C addr和读操作1
  15. writeb((target << 1) | 1, i2c->base + MPC_I2C_DR);

//等待Slave发ACK

  1. if (i2c_wait(i2c, timeout, 1) < 0)
  2. return -1;
  3. if (length) {
  4. if (length == 1)
  5. writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK);
  6. else //为什么不置 TXAK
  7. writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA);
  8. /* Dummy read */
  9. readb(i2c->base + MPC_I2C_DR);
  10. }
  11. for (i = 0; i < length; i++) {
  12. if (i2c_wait(i2c, timeout, 0) < 0)
  13. return -1;
  14. /* Generate txack on next to last byte */
  15. //注意这里TXAK置1,表示CPU每收到1byte数据后,会发送ACK
  16. if (i == length - 2)
  17. writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK);
  18. /* Generate stop on last byte */
  19. //注意这里CCR_MSTA [1->0] CPU会触发STOP
  20. if (i == length - 1)
  21. writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_TXAK);
  22. data[i] = readb(i2c->base + MPC_I2C_DR);
  23. }
  24. return length;
  25. }