驱动专题:第四章 IIC驱动 4. IIC协议/裸驱/adapter驱动程序分析

开发板:mini2440

内核  :linux2.6.32.2

参考  :韦东山毕业班I2C视频教程


1、i2c协议简要分析

    i2c中线是一种由 PHILIPS 公司开发的串行总线,用于连接微控制器及其外围设备,它具有以下特点。
        1、只有两条总线线路:一条串行数据线SDA,一条串行时钟线SCL
        2、每个连接到总线的器件都可以使用软件根据它的唯一的地址来确定。
        3、传输数据的设备之间是简单的主从关系
        4、主机可以用作主机发送器或者主机接收器。
        5、它是一个真正的多主机总线,两个或多个主机同时发起数据传输时,可以通过冲突检测和仲裁来防止数据被破坏。
        6、串行的8位双向传输,位速在标准模式下可达 100kbit/s,在快速模式下可达400kbit/s,在高速模式下可待3.4Mbit/s。
        7、片上的滤波器可以增加抗干扰能力,保证数据的完整性。

        8、连接到同一总线上的IC数量只受到总线的最大电容400Pf的限制。


    如上图所示,启动一个传输时,主机先发送一个S信号,然后发送8位数据。这8位数据的前7位为从机地址第八位表示传输的方向(0表示写,1表示读),如果有数据则继续发送,最后发出P信号停止。


信号类型:

    注意:正常数据传输时,SDA 在 SCL 为低电平时改变,在 SCL 为高电平时保持稳定。
    开始信号 S 信号:
        SCL 为高电平时,SDA由高电平向低电平跳变,开始传送数据。
    结束信号 P 信号:
        SCL 为高电平时,SDA由低电平向高电平跳变,结束传送数据。
    响应信号 ACK:
        接收器在接收到8位数据后,在第9个时钟周期,拉低 SDA 电平
    注意:在第9个时钟周期,发送器保持SDA为高,如果有ACK,那么第9个时钟周期SDA为低电平,如果没有为高电平,发送器根据电平高低分辨是否有ACK信号。
          如果使能了IIC中断,发送完8bit数据后,主机自动进入中断处理函数,此时SCL被发送器拉低,让接收器被迫等待。恢复传输只需要清除中断挂起。



2、 s3c2440 读写流程


    1、设置传输模式 IICSTAT[7-6],我们做实验与AT24C08通信时,2440作为主机,因此只用到主机发模式和主机收模式。
    2、写入从机地址到 IICDS[7-1],此时IICDS[7-1]位表示从机地址,第0位不关心。如 AT24C08 为 0xA0(最低位写0了,发送到数据线上的7位地址的后边以为才表示收发,这里虽然写0但并不是根据这里的0来真正发送的)。
    3、写 0xF0(写) 或 0xB0(读)到 IICSTAT 寄存器, 高两位表示 传输模式前边设置过了,设置IICSTT[5-4] 为 11,使能传输,发送S信号。
    4、IIC控制器自动将第2步中设置的 IICDS[7-1] 再根据 传输模式 补充 IICDS[0]位,发送出去。
    5、进入第9个时钟周期,此时,从机决定是否发出ACK信号,主机进入中断,判断是否收到ACK信号,以及是否继续传输。
    继续发送:
        1、将数据写入 IICDS 
        2、清除中断挂起,SCL时钟恢复,IICDS的数据被自动发送到 SDA 线上,回到第5步。
    停止发送:
        1、写 0xD0(写) 和 0x90(读) 到 IICATAT ,IICATAT[7-6]还是表示的传输模式,IICATAT[5-4] == 0 1,发送停止信号
        2、清除中断挂起,SCL时钟恢复,发出停止信号
        3、延时,等待停止信号发出



3、 AT24C08 读写分析

    1、写过程


    写过程与2440芯片的里的写流程相一致,按照流程写就OK

    2、读过程


    读过程是由2440芯片里的一个写流程加一个读流程组合而成,其中写流程结束没有发出P信号,而是直接发出了S信号开始读流程,也就是我为什么加了一道红线的原因。

附上一份简单的裸机程序,仅供参考:基于MINI2440

  1. #include <stdio.h>
  2. #include "s3c2440.h"
  3. void Delay(int time);
  4. #define WRDATA (1)
  5. #define RDDATA (2)
  6. typedef struct tI2C {
  7. unsigned char *pData; /* 数据缓冲区 */
  8. volatile int DataCount; /* 等待传输的数据长度 */
  9. volatile int Status; /* 状态 */
  10. volatile int Mode; /* 模式:读/写 */
  11. volatile int Pt; /* pData中待传输数据的位置 */
  12. }tS3C24xx_I2C, *ptS3C24xx_I2C;
  13. static tS3C24xx_I2C g_tS3C24xx_I2C;
  14. /*
  15. * I2C初始化
  16. */
  17. void i2c_init(void)
  18. {
  19. GPEUP |= 0xc000; // 禁止内部上拉
  20. /*
  21. * AT24C08 两根线 I2CSCL I2CSDA 与 2440芯片相连
  22. * 配置2440 GPECON GPE15 GPE14引脚为I2C功能
  23. */
  24. GPECON |= 0xa0000000; // 选择引脚功能:GPE15:IICSDA, GPE14:IICSCL
  25. /* 开INT_IIC中断 */
  26. //INTMSK &= ~(BIT_IIC);
  27. /* bit[7] = 1, 使能ACK
  28. * bit[6] = 0, IICCLK = PCLK/16
  29. * bit[5] = 1, 使能中断
  30. * bit[3:0] = 0xf, Tx clock = IICCLK/16
  31. * PCLK = 50MHz, IICCLK = 3.125MHz, Tx Clock = 0.195MHz
  32. */
  33. IICCON = ( 1<< 7) | ( 0<< 6) | ( 1<< 5) | ( 0xf); // 0xaf
  34. //IICADD = 0x10; // S3C24xx slave address = [7:1]
  35. IICSTAT = 0x10; // I2C串行输出使能(Rx/Tx)
  36. }
  37. void I_Write(unsigned int slvaddr, unsigned char addr, unsigned char data)
  38. {
  39. unsigned int ack;
  40. // 写从地址
  41. IICSTAT |= 0x1<< 6; //主机写模式
  42. IICSTAT |= 0x1<< 7;
  43. IICDS = slvaddr; //0xa0; //write slave address to IICDS
  44. IICCON&=~ 0x10; //clear pending bit
  45. IICSTAT = 0xf0; //(M/T start)
  46. while((IICCON & 1<< 4) == 0); //udelay(10);//ack period and then interrupt is pending
  47. // 写寄存器地址
  48. IICDS = addr;
  49. IICCON&=~ 0x10; //clear pending bit
  50. while((IICCON & 1<< 4) == 0); //udelay(10);//ack period and then interrupt is pending
  51. // 写数据
  52. IICDS = data;
  53. IICCON&=~ 0x10; //clear pending bit
  54. while((IICCON & 1<< 4) == 0); //udelay(10);//ack period and then interrupt is pending
  55. // 发出停止信号
  56. IICSTAT = 0xD0; //write (M/T stop to IICSTAT)
  57. IICCON&=~ 0x10; //clear pending bit
  58. while((IICSTAT & 1<< 5) == 1);
  59. }
  60. unsigned char I_Read(unsigned int slvaddr, unsigned char addr)
  61. {
  62. unsigned char data = 1;
  63. int ack;
  64. // 写从地址
  65. IICSTAT |= 0x1<< 6; //主机写模式
  66. IICSTAT |= 0x1<< 7;
  67. slvaddr = 0xA0;
  68. IICDS = slvaddr; //0xa0; //write slave address to IICDS
  69. IICCON&=~ 0x10; //clear pending bit
  70. IICSTAT = 0xf0; //(M/T start)
  71. while((IICCON & 1<< 4) == 0); //udelay(10);//ack period and then interrupt is pending
  72. // 写寄存器地址
  73. IICDS = addr;
  74. IICCON&=~ 0x10; //clear pending bit
  75. while((IICCON & 1<< 4) == 0); //udelay(10);//ack period and then interrupt is pending
  76. // 写从地址(读模式)
  77. slvaddr = 0xA1;
  78. IICSTAT &= ~( 0x1<< 6); //主机接受模式
  79. IICSTAT |= 0x1<< 7;
  80. IICDS = slvaddr;
  81. IICCON&=~ 0x10; //clear pending bit
  82. IICSTAT = 0xb0; //(M/R Start)
  83. while((IICCON & 1<< 4) == 0); //udelay(10);//uart_SendByte('o');//ack period and then interrupt is pending::
  84. // 读数据
  85. data = IICDS;
  86. //IICCON&=~0x10; //clear pending bit
  87. IICCON = 0x2f; //清挂起状态,并设置无应答
  88. while((IICCON & 1<< 4) == 0); //udelay(10);//ack period and then interrupt is pending
  89. data = IICDS;
  90. //IICCON&=~0x10; //clear pending bit
  91. IICCON = 0x2f; //清挂起状态,并设置无应答
  92. while((IICCON & 1<< 4) == 0); //udelay(10);//ack period and then interrupt is pending
  93. IICSTAT = 0x90;
  94. IICCON = 0xaf;
  95. //IICCON &= ~0x10; //clear pending bit
  96. while((IICSTAT & 1<< 5) == 1);
  97. return data;
  98. }


4、adapter驱动程序
    这里,我们主要分析驱动里的发送核心算法,至于注册中断,IO内存映射,设置寄存器不在讨论。
    static int xxx_i2c_xfer(struct i2c_adapter *adpap, struct i2c_msg *msg,int num)
    这个算法函数的作用就是将上层封装好的一些i2c_msg 进行解析,将数据写入寄存器,发送出去。在设备驱动层,我们使用了类似i2c_smbus_write_byte 等函数,类似的函数有很多,它们的作用就是封装i2c_msg 结构(比如读和写的 msg 肯定不一样,读一个字节和读多个字节也不一样),然后调用 i2c_smbus_xfer_emulated->i2c_transfer,最终调用到我们的xxx_i2c_xfer函数进行传输。通过分析i2c_smbus_xfer_emulated函数,我们可以了解i2c_msg是如何封装的。下面,我们简单分析一下,知道最上层想干什么,我们才能知道实现哪些底层的功能不是。
  1. struct i2c_msg {
  2. __u16 addr; //从机地址
  3. __u16 flags;
  4. __u16 len; // buf 里 有多少个字节
  5. __u8 *buf; // 本 msg 含有的数据,可能是1个字节,可有可能是多个字节
  6. };

    此函数,省略了很多内容,举例分析而已~,细节请看源码

  1. static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
  2. unsigned short flags,
  3. char read_write, u8 command, int size,
  4. union i2c_smbus_data * data)
  5. {
  6. unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX+ 3];
  7. unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX+ 2];
  8. int num = read_write == I2C_SMBUS_READ? 2: 1; // 写操作两个Msg 读操作一个msg 这和我们前面分析AT24c08是一致的
  9. struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 },
  10. { addr, flags | I2C_M_RD, 0, msgbuf1 }
  11. };
  12. msgbuf0[ 0] = command; // 从机地址右移1位得到的,比如AT24C08 为 0x50
  13. switch(size) {
  14. case I2C_SMBUS_BYTE_DATA: // 单字节读写
  15. if (read_write == I2C_SMBUS_READ)
  16. msg[ 1].len = 1;
  17. /*
  18. * 读:
  19. * msgbuf0[0] = command
  20. * msg[1].len = 1 ,数据会读到 msgbuf0[1] 里
  21. */
  22. else {
  23. msg[ 0].len = 2;
  24. msgbuf0[ 1] = data->byte;
  25. /*
  26. * 写:
  27. * msgbuf0[0] = command
  28. * msgbuf0[1] = data->byte
  29. */
  30. }
  31. break;
  32. }
  33. status = i2c_transfer(adapter, msg, num);
  34. }
    上面代码跟我们分析AT24C08的时候如出一辙,对于一个写操作,我们只需要一个2440的写流程对应于这里的一个Msg,然而对于读操作,我们需要2440的两个流程,对应于这里的两个Msg。那么,我们底层控制器驱动需要做的工作就是,取出所有的Msg,将每一个Msg里buf里的数据发送出去,如果有下一个Msg, 那么再将下一个Msg里的buf发送完毕,最后发出P停止信号。还有一点,每发送一个Msg都要先发出S开始信号。

    在看adapter程序之前,我们先来简单思考一下,发出S开始信号之后,可能有以下3中情况:
        1、当前msg.len == 0 ,如果有ACK直接发出stop信号。这种情况出现在,控制器枚举设备的时候,因为它只发送S信号以及设备地址,不发送数据。
        2、根据msg->flags 为 I2C_M_RD 等信息判断读写,msg->flags 最低位为1表示读,最低位为0表示写。
            #define I2C_M_TEN0x0010          /* this is a ten bit chip address */
            #define I2C_M_RD0x0001           /* read data, from slave to master */
            #define I2C_M_NOSTART0x4000      /* if I2C_FUNC_PROTOCOL_MANGLING */
            #define I2C_M_REV_DIR_ADDR0x2000 /* if I2C_FUNC_PROTOCOL_MANGLING */
            #define I2C_M_IGNORE_NAK0x1000   /* if I2C_FUNC_PROTOCOL_MANGLING */
            #define I2C_M_NO_RD_ACK0x0800    /* if I2C_FUNC_PROTOCOL_MANGLING */
            #define I2C_M_RECV_LEN0x0400     /* length will be first received byte */
        2.1 如果是读
            恢复 IIC 传输,开始读就行了,在下一个中断里将寄存器数据取出,如果是最后一个要读取的数据,不能发送ACK(禁用ACK)。
        2.2 如果是写
         将数据写入 IICDS 寄存器,恢复 IIC 传输。


附上韦东山老师的程序:

    看程序之前,看一个大致的流程图,对于理解程序有帮助


  1. #include <linux/kernel.h>
  2. #include <linux/module.h>
  3. #include <linux/i2c.h>
  4. #include <linux/init.h>
  5. #include <linux/time.h>
  6. #include <linux/interrupt.h>
  7. #include <linux/delay.h>
  8. #include <linux/errno.h>
  9. #include <linux/err.h>
  10. #include <linux/platform_device.h>
  11. #include <linux/pm_runtime.h>
  12. #include <linux/clk.h>
  13. #include <linux/cpufreq.h>
  14. #include <linux/slab.h>
  15. #include <linux/io.h>
  16. #include <linux/of_i2c.h>
  17. #include <linux/of_gpio.h>
  18. #include <plat/gpio-cfg.h>
  19. #include <mach/regs-gpio.h>
  20. #include <asm/irq.h>
  21. #include <plat/regs-iic.h>
  22. #include <plat/iic.h>
  23. //#define PRINTK printk
  24. #define PRINTK(...)
  25. enum s3c24xx_i2c_state {
  26. STATE_IDLE,
  27. STATE_START,
  28. STATE_READ,
  29. STATE_WRITE,
  30. STATE_STOP
  31. };
  32. struct s3c2440_i2c_regs {
  33. unsigned int iiccon;
  34. unsigned int iicstat;
  35. unsigned int iicadd;
  36. unsigned int iicds;
  37. unsigned int iiclc;
  38. };
  39. struct s3c2440_i2c_xfer_data {
  40. struct i2c_msg *msgs;
  41. int msn_num;
  42. int cur_msg;
  43. int cur_ptr;
  44. int state;
  45. int err;
  46. wait_queue_head_t wait;
  47. };
  48. static struct s3c2440_i2c_xfer_data s3c2440_i2c_xfer_data;
  49. static struct s3c2440_i2c_regs *s3c2440_i2c_regs;
  50. static void s3c2440_i2c_start(void)
  51. {
  52. s3c2440_i2c_xfer_data.state = STATE_START;
  53. if (s3c2440_i2c_xfer_data.msgs->flags & I2C_M_RD) /* 读 */
  54. {
  55. s3c2440_i2c_regs->iicds = s3c2440_i2c_xfer_data.msgs->addr << 1;
  56. s3c2440_i2c_regs->iicstat = 0xb0; // 主机接收,启动
  57. }
  58. else /* 写 */
  59. {
  60. s3c2440_i2c_regs->iicds = s3c2440_i2c_xfer_data.msgs->addr << 1;
  61. s3c2440_i2c_regs->iicstat = 0xf0; // 主机发送,启动
  62. }
  63. }
  64. static void s3c2440_i2c_stop(int err)
  65. {
  66. s3c2440_i2c_xfer_data.state = STATE_STOP;
  67. s3c2440_i2c_xfer_data.err = err;
  68. PRINTK( "STATE_STOP, err = %d\n", err);
  69. if (s3c2440_i2c_xfer_data.msgs->flags & I2C_M_RD) /* 读 */
  70. {
  71. // 下面两行恢复I2C操作,发出P信号
  72. s3c2440_i2c_regs->iicstat = 0x90;
  73. s3c2440_i2c_regs->iiccon = 0xaf;
  74. ndelay( 50); // 等待一段时间以便P信号已经发出
  75. }
  76. else /* 写 */
  77. {
  78. // 下面两行用来恢复I2C操作,发出P信号
  79. s3c2440_i2c_regs->iicstat = 0xd0;
  80. s3c2440_i2c_regs->iiccon = 0xaf;
  81. ndelay( 50); // 等待一段时间以便P信号已经发出
  82. }
  83. /* 唤醒 */
  84. wake_up(&s3c2440_i2c_xfer_data.wait);
  85. }
  86. static int s3c2440_i2c_xfer(struct i2c_adapter *adap,
  87. struct i2c_msg *msgs, int num)
  88. {
  89. unsigned long timeout;
  90. /* 把num个msg的I2C数据发送出去/读进来 */
  91. s3c2440_i2c_xfer_data.msgs = msgs;
  92. s3c2440_i2c_xfer_data.msn_num = num;
  93. s3c2440_i2c_xfer_data.cur_msg = 0;
  94. s3c2440_i2c_xfer_data.cur_ptr = 0;
  95. s3c2440_i2c_xfer_data.err = -ENODEV;
  96. s3c2440_i2c_start();
  97. /* 休眠 */
  98. timeout = wait_event_timeout(s3c2440_i2c_xfer_data.wait, (s3c2440_i2c_xfer_data.state == STATE_STOP), HZ * 5);
  99. if ( 0 == timeout)
  100. {
  101. printk( "s3c2440_i2c_xfer time out\n");
  102. return -ETIMEDOUT;
  103. }
  104. else
  105. {
  106. return s3c2440_i2c_xfer_data.err;
  107. }
  108. }
  109. static u32 s3c2440_i2c_func(struct i2c_adapter *adap)
  110. {
  111. return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING;
  112. }
  113. static const struct i2c_algorithm s3c2440_i2c_algo = {
  114. // .smbus_xfer = ,
  115. .master_xfer = s3c2440_i2c_xfer,
  116. .functionality = s3c2440_i2c_func,
  117. };
  118. /* 1. 分配/设置i2c_adapter
  119. */
  120. static struct i2c_adapter s3c2440_i2c_adapter = {
  121. .name = "s3c2440_100ask",
  122. .algo = &s3c2440_i2c_algo,
  123. .owner = THIS_MODULE,
  124. };
  125. static int isLastMsg(void)
  126. {
  127. return (s3c2440_i2c_xfer_data.cur_msg == s3c2440_i2c_xfer_data.msn_num - 1);
  128. }
  129. static int isEndData(void)
  130. {
  131. return (s3c2440_i2c_xfer_data.cur_ptr >= s3c2440_i2c_xfer_data.msgs->len);
  132. }
  133. static int isLastData(void)
  134. {
  135. return (s3c2440_i2c_xfer_data.cur_ptr == s3c2440_i2c_xfer_data.msgs->len - 1);
  136. }
  137. static irqreturn_t s3c2440_i2c_xfer_irq(int irq, void *dev_id)
  138. {
  139. unsigned int iicSt;
  140. iicSt = s3c2440_i2c_regs->iicstat;
  141. if(iicSt & 0x8){ printk( "Bus arbitration failed\n\r"); }
  142. switch (s3c2440_i2c_xfer_data.state)
  143. {
  144. case STATE_START : /* 发出S和设备地址后,产生中断 */
  145. {
  146. PRINTK( "Start\n");
  147. /* 如果没有ACK, 返回错误 */
  148. if (iicSt & S3C2410_IICSTAT_LASTBIT)
  149. {
  150. s3c2440_i2c_stop(-ENODEV);
  151. break;
  152. }
  153. if (isLastMsg() && isEndData())
  154. {
  155. s3c2440_i2c_stop( 0);
  156. break;
  157. }
  158. /* 进入下一个状态 */
  159. if (s3c2440_i2c_xfer_data.msgs->flags & I2C_M_RD) /* 读 */
  160. {
  161. s3c2440_i2c_xfer_data.state = STATE_READ;
  162. goto next_read;
  163. }
  164. else
  165. {
  166. s3c2440_i2c_xfer_data.state = STATE_WRITE;
  167. }
  168. }
  169. case STATE_WRITE:
  170. {
  171. PRINTK( "STATE_WRITE\n");
  172. /* 如果没有ACK, 返回错误 */
  173. if (iicSt & S3C2410_IICSTAT_LASTBIT)
  174. {
  175. s3c2440_i2c_stop(-ENODEV);
  176. break;
  177. }
  178. if (!isEndData()) /* 如果当前msg还有数据要发送 */
  179. {
  180. s3c2440_i2c_regs->iicds = s3c2440_i2c_xfer_data.msgs->buf[s3c2440_i2c_xfer_data.cur_ptr];
  181. s3c2440_i2c_xfer_data.cur_ptr++;
  182. // 将数据写入IICDS后,需要一段时间才能出现在SDA线上
  183. ndelay( 50);
  184. s3c2440_i2c_regs->iiccon = 0xaf; // 恢复I2C传输
  185. break;
  186. }
  187. else if (!isLastMsg())
  188. {
  189. /* 开始处理下一个消息 */
  190. s3c2440_i2c_xfer_data.msgs++;
  191. s3c2440_i2c_xfer_data.cur_msg++;
  192. s3c2440_i2c_xfer_data.cur_ptr = 0;
  193. s3c2440_i2c_xfer_data.state = STATE_START;
  194. /* 发出START信号和发出设备地址 */
  195. s3c2440_i2c_start();
  196. break;
  197. }
  198. else
  199. {
  200. /* 是最后一个消息的最后一个数据 */
  201. s3c2440_i2c_stop( 0);
  202. break;
  203. }
  204. break;
  205. }
  206. case STATE_READ:
  207. {
  208. PRINTK( "STATE_READ\n");
  209. /* 读出数据 */
  210. s3c2440_i2c_xfer_data.msgs->buf[s3c2440_i2c_xfer_data.cur_ptr] = s3c2440_i2c_regs->iicds;
  211. s3c2440_i2c_xfer_data.cur_ptr++;
  212. next_read:
  213. if (!isEndData()) /* 如果数据没读写, 继续发起读操作 */
  214. {
  215. if (isLastData()) /* 如果即将读的数据是最后一个, 不发ack */
  216. {
  217. s3c2440_i2c_regs->iiccon = 0x2f; // 恢复I2C传输,接收到下一数据时无ACK
  218. }
  219. else
  220. {
  221. s3c2440_i2c_regs->iiccon = 0xaf; // 恢复I2C传输,接收到下一数据时发出ACK
  222. }
  223. break;
  224. }
  225. else if (!isLastMsg())
  226. {
  227. /* 开始处理下一个消息 */
  228. s3c2440_i2c_xfer_data.msgs++;
  229. s3c2440_i2c_xfer_data.cur_msg++;
  230. s3c2440_i2c_xfer_data.cur_ptr = 0;
  231. s3c2440_i2c_xfer_data.state = STATE_START;
  232. /* 发出START信号和发出设备地址 */
  233. s3c2440_i2c_start();
  234. break;
  235. }
  236. else
  237. {
  238. /* 是最后一个消息的最后一个数据 */
  239. s3c2440_i2c_stop( 0);
  240. break;
  241. }
  242. break;
  243. }
  244. default: break;
  245. }
  246. /* 清中断 */
  247. s3c2440_i2c_regs->iiccon &= ~(S3C2410_IICCON_IRQPEND);
  248. return IRQ_HANDLED;
  249. }
  250. /*
  251. * I2C初始化
  252. */
  253. static void s3c2440_i2c_init(void)
  254. {
  255. struct clk *clk;
  256. clk = clk_get( NULL, "i2c");
  257. clk_enable(clk);
  258. // 选择引脚功能:GPE15:IICSDA, GPE14:IICSCL
  259. s3c_gpio_cfgpin(S3C2410_GPE( 14), S3C2410_GPE14_IICSCL);
  260. s3c_gpio_cfgpin(S3C2410_GPE( 15), S3C2410_GPE15_IICSDA);
  261. /* bit[7] = 1, 使能ACK
  262. * bit[6] = 0, IICCLK = PCLK/16
  263. * bit[5] = 1, 使能中断
  264. * bit[3:0] = 0xf, Tx clock = IICCLK/16
  265. * PCLK = 50MHz, IICCLK = 3.125MHz, Tx Clock = 0.195MHz
  266. */
  267. s3c2440_i2c_regs->iiccon = ( 1<< 7) | ( 0<< 6) | ( 1<< 5) | ( 0xf); // 0xaf
  268. s3c2440_i2c_regs->iicadd = 0x10; // S3C24xx slave address = [7:1]
  269. s3c2440_i2c_regs->iicstat = 0x10; // I2C串行输出使能(Rx/Tx)
  270. }
  271. static int i2c_bus_s3c2440_init(void)
  272. {
  273. /* 2. 硬件相关的设置 */
  274. s3c2440_i2c_regs = ioremap( 0x54000000, sizeof(struct s3c2440_i2c_regs));
  275. s3c2440_i2c_init();
  276. request_irq(IRQ_IIC, s3c2440_i2c_xfer_irq, 0, "s3c2440-i2c", NULL);
  277. init_waitqueue_head(&s3c2440_i2c_xfer_data.wait);
  278. /* 3. 注册i2c_adapter */
  279. i2c_add_adapter(&s3c2440_i2c_adapter);
  280. return 0;
  281. }
  282. static void i2c_bus_s3c2440_exit(void)
  283. {
  284. i2c_del_adapter(&s3c2440_i2c_adapter);
  285. free_irq(IRQ_IIC, NULL);
  286. iounmap(s3c2440_i2c_regs);
  287. }
  288. module_init(i2c_bus_s3c2440_init);
  289. module_exit(i2c_bus_s3c2440_exit);
  290. MODULE_LICENSE( "GPL");
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值