Linux内核I2C子系统驱动

来源:互联网 发布:淘宝上架员招聘 编辑:程序博客网 时间:2024/05/15 10:01

一、I2C体系结构

      Linux的I2C体系结构分为3个组成部分:I2C核心、I2C总线驱动、I2C设备驱动,如下图所示。I2C核心提供总线驱动和设备驱动的注册、注销方法,algorithm;I2C总线驱动对硬件体系结构中适配器的实现,主要包括适配器i2c_adapter、适配器通信算法i2c_algorithm,如果CPU集成了I2C控制器并且linux内核支持这个CPU,那么总线驱动就不用管,比如S3C2440就属于这类情况,在后文中我们将分析它的总线驱动;I2C设备驱动是具体的一个设备(如AT24C02),挂接在CPU控制的I2C适配器的设备驱动,有了这部分驱动才能使用控制器操作该设备,设备驱动主要包括i2c_driver 和i2c_client数据结构。

      在linux-2.6.32.2的include/linux/i2c.h中定义了i2c_adapter、i2c_algorithm、i2c_driver、i2c_client数据结构如下所示,这4个结构体相互之间的关系。

[cpp] view plaincopy
  1. struct i2c_adapter {  
  2.     struct module *owner;  
  3.     unsigned int id;  
  4.     unsigned int class;       /* classes to allow probing for */  
  5.     const struct i2c_algorithm *algo; /* the algorithm to access the bus总线通信方法结构体指针 */  
  6.     void *algo_data;                  /* algorithm数据 */  
  7.   
  8.     /* data fields that are valid for all devices   */  
  9.     u8 level;           /* nesting level for lockdep */  
  10.     struct mutex bus_lock;  
  11.   
  12.     int timeout;            /* in jiffies */  
  13.     int retries;                    /* 重试次数 */  
  14.     struct device dev;      /* the adapter device */  
  15.   
  16.     int nr;  
  17.     char name[48];  
  18.     struct completion dev_released;  
  19. };  
  20. struct i2c_algorithm {  
  21.     int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,  
  22.                int num);               /*i2c传输函数指针*/  
  23.     int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,  
  24.                unsigned short flags, char read_write,  
  25.                u8 command, int size, union i2c_smbus_data *data);    /*smbus传输函数指针*/  
  26.   
  27.     /* To determine what the adapter supports */  
  28.     u32 (*functionality) (struct i2c_adapter *);            /*返回适配器支持的功能*/  
  29. };  
  30. struct i2c_driver {  
  31.     unsigned int class;  
  32.   
  33.     int (*attach_adapter)(struct i2c_adapter *);       /*依附i2c_adapter函数指针*/  
  34.     int (*detach_adapter)(struct i2c_adapter *);       /*脱离i2c_adapter函数指针*/  
  35.   
  36.     /* Standard driver model interfaces */  
  37.     int (*probe)(struct i2c_client *, const struct i2c_device_id *);  
  38.     int (*remove)(struct i2c_client *);  
  39.   
  40.     /* driver model interfaces that don't relate to enumeration  */  
  41.     void (*shutdown)(struct i2c_client *);  
  42.     int (*suspend)(struct i2c_client *, pm_message_t mesg);  
  43.     int (*resume)(struct i2c_client *);        /* probe,remove,suspend,resume驱动方法重要成员函数 */  
  44.   
  45.     /* a ioctl like command that can be used to perform specific functions 
  46.      * with the device. 
  47.      */  
  48.     int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);   /*类似ioctl*/  
  49.    
  50.     struct device_driver driver;  
  51.     const struct i2c_device_id *id_table;   /* 驱动支持多个设备,这里面就要包含这些设备的ID */  
  52.   
  53.     /* Device detection callback for automatic device creation */  
  54.     int (*detect)(struct i2c_client *, int kind, struct i2c_board_info *);   /*i2c client脱离函数指针*/  
  55.     const struct i2c_client_address_data *address_data;  
  56.     struct list_head clients;  
  57. };  
  58. struct i2c_client {  
  59.     unsigned short flags;       /* div., see below      */  
  60.     unsigned short addr;        /* chip address - NOTE: 7bit  芯片地址  */  
  61.                     /* addresses are stored in the  */  
  62.                     /* _LOWER_ 7 bits       */  
  63.     char name[I2C_NAME_SIZE];  
  64.     struct i2c_adapter *adapter;    /* the adapter we sit on  依附的i2c_adapter    */  
  65.     struct i2c_driver *driver;  /* and our access routines 依附的i2c_driver    */  
  66.     struct device dev;      /* the device structure     */  
  67.     int irq;            /* irq issued by device     */  
  68.     struct list_head detected;  
  69. };  

1、i2c_adapter 与i2c_algorithm,i2c_adapter 对应于物理上的一个适配器,而i2c_algorithm对应一套通信方法。一个I2C适配器需要i2c_algorithm中提供的通信函数来控制适配器上产生特定的访问周期。缺少i2c_algorithm 的i2c_adapter 什么也做不了,因此i2c_adapter 中包含其使用的i2c_algorithm的指针。i2c_algorithm 中的关键函数master_xfer()用于产生I2C 访问周期需要的信号,以i2c_msg(即I2C消息)为单位。i2c_msg结构体也非常关键。

struct i2c_msg {

       __u16 addr;    /* slave address                    */

       __u16 flags;

#define I2C_M_TEN            0x0010    /* this is a ten bit chip address */

#define I2C_M_RD              0x0001    /* read data, from slave to master */

#define I2C_M_NOSTART           0x4000    /* if I2C_FUNC_PROTOCOL_MANGLING */

#define I2C_M_REV_DIR_ADDR 0x2000    /* if I2C_FUNC_PROTOCOL_MANGLING */

#define I2C_M_IGNORE_NAK    0x1000    /* if I2C_FUNC_PROTOCOL_MANGLING */

#define I2C_M_NO_RD_ACK             0x0800    /* if I2C_FUNC_PROTOCOL_MANGLING */

#define I2C_M_RECV_LEN         0x0400    /* length will be first received byte */

       __u16 len;             /* msg length                       */

       __u8 *buf;             /* pointer to msg data                  */

};

2、i2c_driver 与i2c_client,i2c_driver 对应一套驱动方法,是纯粹的用于辅助作用的数据结构,它不对应于任何的物理实体。i2c_client对应于真实的物理设备,每个I2C设备都需要一个i2c_client来描述。i2c_client一般被包含在I2C字符设备的私有信息结构体中。

3、i2c_adpater 与i2c_client,i2c_adpater 与i2c_client 的关系与I2C 硬件体系中适配器和设备的关系一致,即i2c_client 依附于i2c_adpater。

二、I2C核心

    I2C核心是总线驱动和设备驱动的纽带,源码位于drivers/i2c/i2c-core.c,它并不依赖于硬件平台的接口函数,I2C核心中一些重要函数如下:

增加/删除i2c_adapter

int i2c_add_adapter(struct i2c_adapter *adapter)

int i2c_del_adapter(struct i2c_adapter *adapter)

增加/删除i2c_driver

int i2c_register_driver(struct module *owner, struct i2c_driver *driver)

int i2c_add_driver(struct i2c_driver *driver)         //调用i2c_register_driver

void i2c_del_driver(struct i2c_driver *driver)

增加/删除i2c_client

struct i2c_client *i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)

void i2c_unregister_device(struct i2c_client *client)

      注:在2.6.30版本之前使用的是i2c_attach_client()和i2c_detach_client()函数。之后attach被merge到了i2c_new_device中,而detach直接被unresister取代。实际上这两个函数内部都是调用了device_register()和device_unregister()

I2C传输、发送接收

int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)

int i2c_master_send(struct i2c_client *client,const char *buf ,int count)

int i2c_master_recv(struct i2c_client *client, char *buf ,int count)

      i2c_transfer()函数用于进行I2C 适配器和I2C 设备之间的一组消息交互,i2c_master_send()函数和i2c_master_recv()函数内部会调用i2c_transfer()函数分别完成一条写消息和一条读消息,i2c_transfer()本身不能喝硬件完成消息交互,它寻找i2c_adapter对应的i2c_algorithm,要实现数据传送就要实现i2c_algorithm的master_xfer(),在总线驱动中就是重点。



上一篇文章讲述了I2C子系统体系结构,总线驱动、设备驱动的知识点,下面就S3C2440 I2C总线驱动的实现详细讲解,它的源码位于drivers/i2c/busses/i2c-s3c2410.c

一、I2C平台设备资源

      IIC驱动中使用的平台设备与前面看门狗、rtc等方式原理相同,但定义路径有所不同,并且设置了额外一些参数。mach_smdk2440.c文件中smdk2440_machine_init函数初始化了平台设备,还对s3c_device_i2c0平台设备进行额外的设置(s3c_i2c0_set_platdata),s3c_device_i2c0平台设备定义在arch/arm/plat-s3c/dev-i2c0.c。

static void __init smdk2440_machine_init(void)

{

       s3c24xx_fb_set_platdata(&smdk2440_fb_info);

       s3c_i2c0_set_platdata(NULL);

 

       platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));

       smdk_machine_init();

}

下面是s3c_device_i2c0平台设备相关部分,s3c_i2c0_set_platdata初始化s3c_device_i2c0.dev.platform_data为default_i2c_data0

static struct resource s3c_i2c_resource[] = {

       [0] = {

              .start = S3C_PA_IIC,

              .end   = S3C_PA_IIC + SZ_4K - 1,

              .flags = IORESOURCE_MEM,

       },

       [1] = {

              .start = IRQ_IIC,

              .end   = IRQ_IIC,

              .flags = IORESOURCE_IRQ,

       },

};

 

struct platform_device s3c_device_i2c0 = {

       .name               = "s3c2410-i2c",

#ifdef CONFIG_S3C_DEV_I2C1

       .id             = 0,

#else

       .id             = -1,

#endif

       .num_resources       = ARRAY_SIZE(s3c_i2c_resource),

       .resource   = s3c_i2c_resource,

};

 

static struct s3c2410_platform_i2c default_i2c_data0 __initdata = {

       .flags             = 0,

       .slave_addr     = 0x10,

       .frequency      = 100*1000,

       .sda_delay      = 100,

};

 

void __init s3c_i2c0_set_platdata(struct s3c2410_platform_i2c *pd)

{

       struct s3c2410_platform_i2c *npd;

 

       if (!pd)

              pd = &default_i2c_data0;

 

       npd = kmemdup(pd, sizeof(struct s3c2410_platform_i2c), GFP_KERNEL);

       if (!npd)

              printk(KERN_ERR "%s: no memory for platform data\n", __func__);

       else if (!npd->cfg_gpio)

              npd->cfg_gpio = s3c_i2c0_cfg_gpio;

       s3c_device_i2c0.dev.platform_data = npd;

}

void s3c_i2c0_cfg_gpio(struct platform_device *dev)

{         //  位于arch/arm/plat-s3c24xx/setup-i2c.c

       s3c2410_gpio_cfgpin(S3C2410_GPE(15), S3C2410_GPE15_IICSDA);

       s3c2410_gpio_cfgpin(S3C2410_GPE(14), S3C2410_GPE14_IICSCL);

}

二、总线驱动实现

1.I2C适配器驱动加载卸载

[cpp] view plaincopy
  1. static int s3c24xx_i2c_calcdivisor(unsigned long clkin, unsigned int wanted,  
  2.                    unsigned int *div1, unsigned int *divs)  
  3. {  
  4.     unsigned int calc_divs = clkin / wanted;  
  5.     unsigned int calc_div1;  
  6.   
  7.     if (calc_divs > (16*16))  
  8.         calc_div1 = 512;  
  9.     else  
  10.         calc_div1 = 16;  
  11.   
  12.     calc_divs += calc_div1-1;  
  13.     calc_divs /= calc_div1;  
  14.   
  15.     if (calc_divs == 0)  
  16.         calc_divs = 1;  
  17.     if (calc_divs > 17)  
  18.         calc_divs = 17;  
  19.   
  20.     *divs = calc_divs;  
  21.     *div1 = calc_div1;  
  22.   
  23.     return clkin / (calc_divs * calc_div1);  
  24. }  
  25.   
  26. /* s3c24xx_i2c_clockrate 
  27.  * 
  28.  * work out a divisor for the user requested frequency setting, 
  29.  * either by the requested frequency, or scanning the acceptable 
  30.  * range of frequencies until something is found 
  31. */  
  32.   
  33. static int s3c24xx_i2c_clockrate(struct s3c24xx_i2c *i2c, unsigned int *got)  
  34. {  
  35.     struct s3c2410_platform_i2c *pdata = i2c->dev->platform_data;  
  36.     unsigned long clkin = clk_get_rate(i2c->clk);   /* PCLK */  
  37.     unsigned int divs, div1;  
  38.     unsigned long target_frequency;    /* 需要设置速率默认100khz */  
  39.     u32 iiccon;  
  40.     int freq;  
  41.   
  42.     i2c->clkrate = clkin;  
  43.     clkin /= 1000;      /* clkin now in KHz */  
  44.   
  45.     dev_dbg(i2c->dev, "pdata desired frequency %lu\n", pdata->frequency);  
  46.   
  47.     target_frequency = pdata->frequency ? pdata->frequency : 100000;  
  48.   
  49.     target_frequency /= 1000; /* Target frequency now in KHz */  
  50.   
  51.     freq = s3c24xx_i2c_calcdivisor(clkin, target_frequency, &div1, &divs);  /* 计算出IICCON中Tx clock source selection和Transmit clock value */  
  52.   
  53.     if (freq > target_frequency) {  
  54.         dev_err(i2c->dev,  
  55.             "Unable to achieve desired frequency %luKHz."   \  
  56.             " Lowest achievable %dKHz\n", target_frequency, freq);  
  57.         return -EINVAL;  
  58.     }  
  59.   
  60.     *got = freq;  
  61.   
  62.     iiccon = readl(i2c->regs + S3C2410_IICCON);  
  63.     iiccon &= ~(S3C2410_IICCON_SCALEMASK | S3C2410_IICCON_TXDIV_512);  
  64.     iiccon |= (divs-1);  
  65.   
  66.     if (div1 == 512)  
  67.         iiccon |= S3C2410_IICCON_TXDIV_512;  
  68.   
  69.     writel(iiccon, i2c->regs + S3C2410_IICCON);  
  70.   
  71.     if (s3c24xx_i2c_is2440(i2c)) {    /* 2440设置IICLC */  
  72.         unsigned long sda_delay;  
  73.   
  74.         if (pdata->sda_delay) {  
  75.             sda_delay = (freq / 1000) * pdata->sda_delay;  
  76.             sda_delay /= 1000000;  
  77.             sda_delay = DIV_ROUND_UP(sda_delay, 5);  
  78.             if (sda_delay > 3)  
  79.                 sda_delay = 3;  
  80.             sda_delay |= S3C2410_IICLC_FILTER_ON;  
  81.         } else  
  82.             sda_delay = 0;  
  83.   
  84.         dev_dbg(i2c->dev, "IICLC=%08lx\n", sda_delay);  
  85.         writel(sda_delay, i2c->regs + S3C2440_IICLC);  
  86.     }  
  87.   
  88.     return 0;  
  89. }  
  90.   
  91. #ifdef CONFIG_CPU_FREQ  
  92.   
  93. #define freq_to_i2c(_n) container_of(_n, struct s3c24xx_i2c, freq_transition)  
  94.   
  95. static int s3c24xx_i2c_cpufreq_transition(struct notifier_block *nb,  
  96.                       unsigned long val, void *data)  
  97. {  
  98.     struct s3c24xx_i2c *i2c = freq_to_i2c(nb);  
  99.     unsigned long flags;  
  100.     unsigned int got;  
  101.     int delta_f;  
  102.     int ret;  
  103.   
  104.     delta_f = clk_get_rate(i2c->clk) - i2c->clkrate;  
  105.   
  106.     /* if we're post-change and the input clock has slowed down 
  107.      * or at pre-change and the clock is about to speed up, then 
  108.      * adjust our clock rate. <0 is slow, >0 speedup. 
  109.      */  
  110.   
  111.     if ((val == CPUFREQ_POSTCHANGE && delta_f < 0) ||  
  112.         (val == CPUFREQ_PRECHANGE && delta_f > 0)) {  
  113.         spin_lock_irqsave(&i2c->lock, flags);  
  114.         ret = s3c24xx_i2c_clockrate(i2c, &got);  
  115.         spin_unlock_irqrestore(&i2c->lock, flags);  
  116.   
  117.         if (ret < 0)  
  118.             dev_err(i2c->dev, "cannot find frequency\n");  
  119.         else  
  120.             dev_info(i2c->dev, "setting freq %d\n", got);  
  121.     }  
  122.   
  123.     return 0;  
  124. }  
  125.   
  126. static inline int s3c24xx_i2c_register_cpufreq(struct s3c24xx_i2c *i2c)  
  127. {  
  128.     i2c->freq_transition.notifier_call = s3c24xx_i2c_cpufreq_transition;  
  129.   
  130.     return cpufreq_register_notifier(&i2c->freq_transition,  
  131.                      CPUFREQ_TRANSITION_NOTIFIER);  
  132. }  
  133.   
  134. static inline void s3c24xx_i2c_deregister_cpufreq(struct s3c24xx_i2c *i2c)  
  135. {  
  136.     cpufreq_unregister_notifier(&i2c->freq_transition,  
  137.                     CPUFREQ_TRANSITION_NOTIFIER);  
  138. }  
  139.   
  140. #else  
  141. static inline int s3c24xx_i2c_register_cpufreq(struct s3c24xx_i2c *i2c)  
  142. {  
  143.     return 0;  
  144. }  
  145.   
  146. static inline void s3c24xx_i2c_deregister_cpufreq(struct s3c24xx_i2c *i2c)  
  147. {  
  148. }  
  149. #endif  
  150.   
  151. /* s3c24xx_i2c_init 
  152.  * 
  153.  * initialise the controller, set the IO lines and frequency 
  154. */  
  155.   
  156. static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)  
  157. {  
  158.     unsigned long iicon = S3C2410_IICCON_IRQEN | S3C2410_IICCON_ACKEN;  
  159.     struct s3c2410_platform_i2c *pdata;  
  160.     unsigned int freq;  
  161.   
  162.     /* get the plafrom data */  
  163.   
  164.     pdata = i2c->dev->platform_data;    /* 获取platform_data */  
  165.   
  166.     /* inititalise the gpio */  
  167.   
  168.     if (pdata->cfg_gpio)  
  169.         pdata->cfg_gpio(to_platform_device(i2c->dev));  
  170.   
  171.     /* write slave address */  
  172.   
  173.     writeb(pdata->slave_addr, i2c->regs + S3C2410_IICADD);  
  174.   
  175.     dev_info(i2c->dev, "slave address 0x%02x\n", pdata->slave_addr);  
  176.   
  177.     writel(iicon, i2c->regs + S3C2410_IICCON);  
  178.   
  179.     /* we need to work out the divisors for the clock... */  
  180.   
  181.     if (s3c24xx_i2c_clockrate(i2c, &freq) != 0) {         /* 设置i2c速率 */  
  182.         writel(0, i2c->regs + S3C2410_IICCON);       
  183.         dev_err(i2c->dev, "cannot meet bus frequency required\n");  
  184.         return -EINVAL;  
  185.     }  
  186.   
  187.     /* todo - check that the i2c lines aren't being dragged anywhere */  
  188.   
  189.     dev_info(i2c->dev, "bus frequency set to %d KHz\n", freq);  
  190.     dev_dbg(i2c->dev, "S3C2410_IICCON=0x%02lx\n", iicon);  
  191.   
  192.     return 0;  
  193. }  
  194.   
  195. /* s3c24xx_i2c_probe 
  196.  * 
  197.  * called by the bus driver when a suitable device is found 
  198. */  
  199.   
  200. static int s3c24xx_i2c_probe(struct platform_device *pdev)  
  201. {  
  202.     struct s3c24xx_i2c *i2c;  
  203.     struct s3c2410_platform_i2c *pdata;  
  204.     struct resource *res;  
  205.     int ret;  
  206.   
  207.     pdata = pdev->dev.platform_data;    /* 在平台设备资源中初始化了platform_data,关于platform_data参考前一节 */  
  208.     if (!pdata) {  
  209.         dev_err(&pdev->dev, "no platform data\n");  
  210.         return -EINVAL;  
  211.     }  
  212.   
  213.     i2c = kzalloc(sizeof(struct s3c24xx_i2c), GFP_KERNEL); /* s3c24xx_i2c分配空间 */  
  214.     if (!i2c) {  
  215.         dev_err(&pdev->dev, "no memory for state\n");  
  216.         return -ENOMEM;  
  217.     }  
  218.   
  219.     strlcpy(i2c->adap.name, "s3c2410-i2c"sizeof(i2c->adap.name));   /* s3c24xx_i2c初始化 */  
  220.     i2c->adap.owner   = THIS_MODULE;  
  221.     i2c->adap.algo    = &s3c24xx_i2c_algorithm;   /* 通信方法,下一节重点介绍 */  
  222.     i2c->adap.retries = 2;  
  223.     i2c->adap.class   = I2C_CLASS_HWMON | I2C_CLASS_SPD;  
  224.     i2c->tx_setup     = 50;  
  225.   
  226.     spin_lock_init(&i2c->lock);  
  227.     init_waitqueue_head(&i2c->wait);  
  228.   
  229.     /* find the clock and enable it */  
  230.   
  231.     i2c->dev = &pdev->dev;  
  232.     i2c->clk = clk_get(&pdev->dev, "i2c");   /* 时钟 */  
  233.     if (IS_ERR(i2c->clk)) {  
  234.         dev_err(&pdev->dev, "cannot get clock\n");  
  235.         ret = -ENOENT;  
  236.         goto err_noclk;  
  237.     }  
  238.   
  239.     dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk);  
  240.   
  241.     clk_enable(i2c->clk);  
  242.   
  243.     /* map the registers */  
  244.   
  245.     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);    /* 寄存器映射 */  
  246.     if (res == NULL) {  
  247.         dev_err(&pdev->dev, "cannot find IO resource\n");  
  248.         ret = -ENOENT;  
  249.         goto err_clk;  
  250.     }  
  251.   
  252.     i2c->ioarea = request_mem_region(res->start, resource_size(res),  
  253.                      pdev->name);  
  254.   
  255.     if (i2c->ioarea == NULL) {  
  256.         dev_err(&pdev->dev, "cannot request IO\n");  
  257.         ret = -ENXIO;  
  258.         goto err_clk;  
  259.     }  
  260.   
  261.     i2c->regs = ioremap(res->start, resource_size(res));  
  262.   
  263.     if (i2c->regs == NULL) {  
  264.         dev_err(&pdev->dev, "cannot map IO\n");  
  265.         ret = -ENXIO;  
  266.         goto err_ioarea;  
  267.     }  
  268.   
  269.     dev_dbg(&pdev->dev, "registers %p (%p, %p)\n",  
  270.         i2c->regs, i2c->ioarea, res);  
  271.   
  272.     /* setup info block for the i2c core */  
  273.   
  274.     i2c->adap.algo_data = i2c;  
  275.     i2c->adap.dev.parent = &pdev->dev;  
  276.   
  277.     /* initialise the i2c controller */  
  278.   
  279.     ret = s3c24xx_i2c_init(i2c);     /* 初始化 */  
  280.     if (ret != 0)  
  281.         goto err_iomap;  
  282.   
  283.     /* find the IRQ for this unit (note, this relies on the init call to 
  284.      * ensure no current IRQs pending 
  285.      */  
  286.   
  287.     i2c->irq = ret = platform_get_irq(pdev, 0);     /* 中断申请 */  
  288.     if (ret <= 0) {  
  289.         dev_err(&pdev->dev, "cannot find IRQ\n");  
  290.         goto err_iomap;  
  291.     }  
  292.   
  293.     ret = request_irq(i2c->irq, s3c24xx_i2c_irq, IRQF_DISABLED,  
  294.               dev_name(&pdev->dev), i2c);  
  295.   
  296.     if (ret != 0) {  
  297.         dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);  
  298.         goto err_iomap;  
  299.     }  
  300.   
  301.     ret = s3c24xx_i2c_register_cpufreq(i2c);  /* 关于cpufreq没明白,有关cpufreq可以暂时不管 */  
  302.     if (ret < 0) {  
  303.         dev_err(&pdev->dev, "failed to register cpufreq notifier\n");  
  304.         goto err_irq;  
  305.     }  
  306.   
  307.     /* Note, previous versions of the driver used i2c_add_adapter() 
  308.      * to add the bus at any number. We now pass the bus number via 
  309.      * the platform data, so if unset it will now default to always 
  310.      * being bus 0. 
  311.      */  
  312.   
  313.     i2c->adap.nr = pdata->bus_num;            
  314.     /*调用了i2c-core中的i2c_add_adapter函数来添加一个i2c控制器,i2c_add_numbered_adapter和i2c_add_adapter的 
  315.      区别在于前者用来添加一个在CPU内部集成的适配器,而后者用来添加一个CPU外部的适配器。显然这里应该用前者 */  
  316.     ret = i2c_add_numbered_adapter(&i2c->adap);  
  317.     if (ret < 0) {  
  318.         dev_err(&pdev->dev, "failed to add bus to i2c core\n");  
  319.         goto err_cpufreq;  
  320.     }  
  321.   
  322.     platform_set_drvdata(pdev, i2c);  
  323.   
  324.     dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev));  
  325.     return 0;  
  326.   
  327.  err_cpufreq:  
  328.     s3c24xx_i2c_deregister_cpufreq(i2c);  
  329.   
  330.  err_irq:  
  331.     free_irq(i2c->irq, i2c);  
  332.   
  333.  err_iomap:  
  334.     iounmap(i2c->regs);  
  335.   
  336.  err_ioarea:  
  337.     release_resource(i2c->ioarea);  
  338.     kfree(i2c->ioarea);  
  339.   
  340.  err_clk:  
  341.     clk_disable(i2c->clk);  
  342.     clk_put(i2c->clk);  
  343.   
  344.  err_noclk:  
  345.     kfree(i2c);  
  346.     return ret;  
  347. }  
  348.   
  349. /* s3c24xx_i2c_remove 
  350.  * 
  351.  * called when device is removed from the bus 
  352. */  
  353.   
  354. static int s3c24xx_i2c_remove(struct platform_device *pdev)  
  355. {  
  356.     struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);  
  357.   
  358.     s3c24xx_i2c_deregister_cpufreq(i2c);  
  359.   
  360.     i2c_del_adapter(&i2c->adap);     /* 删除adapter*/  
  361.     free_irq(i2c->irq, i2c);  
  362.   
  363.     clk_disable(i2c->clk);  
  364.     clk_put(i2c->clk);  
  365.   
  366.     iounmap(i2c->regs);  
  367.   
  368.     release_resource(i2c->ioarea);  
  369.     kfree(i2c->ioarea);  
  370.     kfree(i2c);  
  371.   
  372.     return 0;  
  373. }  
  374.   
  375. #ifdef CONFIG_PM  
  376. static int s3c24xx_i2c_suspend_noirq(struct device *dev)  
  377. {  
  378.     struct platform_device *pdev = to_platform_device(dev);  
  379.     struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);  
  380.   
  381.     i2c->suspended = 1;  
  382.   
  383.     return 0;  
  384. }  
  385.   
  386. static int s3c24xx_i2c_resume(struct device *dev)  
  387. {  
  388.     struct platform_device *pdev = to_platform_device(dev);  
  389.     struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);  
  390.   
  391.     i2c->suspended = 0;  
  392.     s3c24xx_i2c_init(i2c);  
  393.   
  394.     return 0;  
  395. }  
  396.   
  397. static struct dev_pm_ops s3c24xx_i2c_dev_pm_ops = {  
  398.     .suspend_noirq = s3c24xx_i2c_suspend_noirq,  
  399.     .resume = s3c24xx_i2c_resume,  
  400. };  
  401.   
  402. #define S3C24XX_DEV_PM_OPS (&s3c24xx_i2c_dev_pm_ops)  
  403. #else  
  404. #define S3C24XX_DEV_PM_OPS NULL  
  405. #endif  
  406.   
  407. /* device driver for platform bus bits */  
  408.   
  409. static struct platform_device_id s3c24xx_driver_ids[] = {  
  410.     {  
  411.         .name       = "s3c2410-i2c",  
  412.         .driver_data    = TYPE_S3C2410,  
  413.     }, {  
  414.         .name       = "s3c2440-i2c",  
  415.         .driver_data    = TYPE_S3C2440,  
  416.     }, { },  
  417. };  
  418. MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids);  
  419.   
  420. static struct platform_driver s3c24xx_i2c_driver = {  
  421.     .probe      = s3c24xx_i2c_probe,  
  422.     .remove     = s3c24xx_i2c_remove,  
  423.     .id_table   = s3c24xx_driver_ids,   //解释参见代码后面说明  
  424.     .driver     = {  
  425.         .owner  = THIS_MODULE,  
  426.         .name   = "s3c-i2c",  
  427.         .pm = S3C24XX_DEV_PM_OPS,  
  428.     },  
  429. };  
  430.   
  431. static int __init i2c_adap_s3c_init(void)  
  432. {  
  433.     return platform_driver_register(&s3c24xx_i2c_driver);  
  434. }  
  435. subsys_initcall(i2c_adap_s3c_init);  
  436.   
  437. static void __exit i2c_adap_s3c_exit(void)  
  438. {  
  439.     platform_driver_unregister(&s3c24xx_i2c_driver);  
  440. }  
  441. module_exit(i2c_adap_s3c_exit);  
  442.   
  443. MODULE_DESCRIPTION("S3C24XX I2C Bus driver");  
  444. MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");  
  445. MODULE_LICENSE("GPL");  

      i2c_adap_s3c_init注册i2c平台驱动s3c24xx_i2c_driver,它是platform_driver结构体,不要误解为i2c_driver。同时还实现了probe、remove、id_table、driver,其中suspend、resume在driver中实现。i2c_adap_s3c_exit注销s3c24xx_i2c_driver。

      关于平台驱动s3c24xx_i2c_driver中名字为s3c_i2c与平台设备中名字s3c2410-i2c不一样,怎么匹配?这里主要在于id_table,s3c24xx_driver_ids包含了驱动所支持的设备ID表,判断这个表中的名字与平台设备中名字一致,则匹配成功。

2.I2C通信方法

[cpp] view plaincopy
  1. #include <linux/kernel.h>  
  2. #include <linux/module.h>  
  3.   
  4. #include <linux/i2c.h>  
  5. #include <linux/i2c-id.h>  
  6. #include <linux/init.h>  
  7. #include <linux/time.h>  
  8. #include <linux/interrupt.h>  
  9. #include <linux/delay.h>  
  10. #include <linux/errno.h>  
  11. #include <linux/err.h>  
  12. #include <linux/platform_device.h>  
  13. #include <linux/clk.h>  
  14. #include <linux/cpufreq.h>  
  15.   
  16. #include <asm/irq.h>  
  17. #include <asm/io.h>  
  18.   
  19. #include <plat/regs-iic.h>  
  20. #include <plat/iic.h>  
  21.   
  22. /* i2c controller state */  
  23.   
  24. enum s3c24xx_i2c_state {  
  25.     STATE_IDLE,  
  26.     STATE_START,  
  27.     STATE_READ,  
  28.     STATE_WRITE,  
  29.     STATE_STOP  
  30. };  
  31.   
  32. enum s3c24xx_i2c_type {  
  33.     TYPE_S3C2410,  
  34.     TYPE_S3C2440,  
  35. };  
  36.   
  37. struct s3c24xx_i2c {  
  38.     spinlock_t      lock;  
  39.     wait_queue_head_t   wait;  
  40.     unsigned int        suspended:1;  
  41.   
  42.     struct i2c_msg      *msg;  
  43.     unsigned int        msg_num;  
  44.     unsigned int        msg_idx;  
  45.     unsigned int        msg_ptr;  
  46.   
  47.     unsigned int        tx_setup;  
  48.     unsigned int        irq;  
  49.   
  50.     enum s3c24xx_i2c_state  state;  
  51.     unsigned long       clkrate;  
  52.   
  53.     void __iomem        *regs;  
  54.     struct clk      *clk;  
  55.     struct device       *dev;  
  56.     struct resource     *ioarea;  
  57.     struct i2c_adapter  adap;  
  58.   
  59. #ifdef CONFIG_CPU_FREQ  
  60.     struct notifier_block   freq_transition;  
  61. #endif  
  62. };  
  63.   
  64. /* default platform data removed, dev should always carry data. */  
  65.   
  66. /* s3c24xx_i2c_is2440() 
  67.  * 
  68.  * return true is this is an s3c2440 
  69. */  
  70.   
  71. static inline int s3c24xx_i2c_is2440(struct s3c24xx_i2c *i2c)  
  72. {  
  73.     struct platform_device *pdev = to_platform_device(i2c->dev);  
  74.     enum s3c24xx_i2c_type type;  
  75.   
  76.     type = platform_get_device_id(pdev)->driver_data;  
  77.     return type == TYPE_S3C2440;  
  78. }  
  79.   
  80. /* s3c24xx_i2c_master_complete 
  81.  * 
  82.  * complete the message and wake up the caller, using the given return code, 
  83.  * or zero to mean ok. 
  84. */  
  85.   
  86. static inline void s3c24xx_i2c_master_complete(struct s3c24xx_i2c *i2c, int ret)  
  87. {  
  88.     dev_dbg(i2c->dev, "master_complete %d\n", ret);  
  89.   
  90.     i2c->msg_ptr = 0;  
  91.     i2c->msg = NULL;  
  92.     i2c->msg_idx++;  
  93.     i2c->msg_num = 0;  
  94.     if (ret)  
  95.         i2c->msg_idx = ret;  
  96.   
  97.     wake_up(&i2c->wait);  
  98. }  
  99.   
  100. static inline void s3c24xx_i2c_disable_ack(struct s3c24xx_i2c *i2c)  
  101. {  
  102.     unsigned long tmp;  
  103.   
  104.     tmp = readl(i2c->regs + S3C2410_IICCON);  
  105.     writel(tmp & ~S3C2410_IICCON_ACKEN, i2c->regs + S3C2410_IICCON);  
  106. }  
  107.   
  108. static inline void s3c24xx_i2c_enable_ack(struct s3c24xx_i2c *i2c)  
  109. {  
  110.     unsigned long tmp;  
  111.   
  112.     tmp = readl(i2c->regs + S3C2410_IICCON);  
  113.     writel(tmp | S3C2410_IICCON_ACKEN, i2c->regs + S3C2410_IICCON);  
  114. }  
  115.   
  116. /* irq enable/disable functions */  
  117.   
  118. static inline void s3c24xx_i2c_disable_irq(struct s3c24xx_i2c *i2c)  
  119. {  
  120.     unsigned long tmp;  
  121.   
  122.     tmp = readl(i2c->regs + S3C2410_IICCON);  
  123.     writel(tmp & ~S3C2410_IICCON_IRQEN, i2c->regs + S3C2410_IICCON);  
  124. }  
  125.   
  126. static inline void s3c24xx_i2c_enable_irq(struct s3c24xx_i2c *i2c)  
  127. {  
  128.     unsigned long tmp;  
  129.   
  130.     tmp = readl(i2c->regs + S3C2410_IICCON);  
  131.     writel(tmp | S3C2410_IICCON_IRQEN, i2c->regs + S3C2410_IICCON);  
  132. }  
  133.   
  134.   
  135. /* s3c24xx_i2c_message_start 
  136.  * 
  137.  * put the start of a message onto the bus 
  138. */  
  139.   
  140. static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c,  
  141.                       struct i2c_msg *msg)  
  142. {  
  143.     unsigned int addr = (msg->addr & 0x7f) << 1;  
  144.     unsigned long stat;  
  145.     unsigned long iiccon;  
  146.   
  147.     stat = 0;  
  148.     stat |=  S3C2410_IICSTAT_TXRXEN;      /* 使能TXRX */  
  149.   
  150.     if (msg->flags & I2C_M_RD) {          /* 设备地址 */  
  151.         stat |= S3C2410_IICSTAT_MASTER_RX;  
  152.         addr |= 1;  
  153.     } else  
  154.         stat |= S3C2410_IICSTAT_MASTER_TX;  
  155.   
  156.     if (msg->flags & I2C_M_REV_DIR_ADDR)  
  157.         addr ^= 1;  
  158.   
  159.     /* todo - check for wether ack wanted or not */  
  160.     s3c24xx_i2c_enable_ack(i2c);          /* 使能ack */  
  161.   
  162.     iiccon = readl(i2c->regs + S3C2410_IICCON);  
  163.     writel(stat, i2c->regs + S3C2410_IICSTAT);  
  164.   
  165.     dev_dbg(i2c->dev, "START: %08lx to IICSTAT, %02x to DS\n", stat, addr);  
  166.     writeb(addr, i2c->regs + S3C2410_IICDS);    /* 写设备地址 */  
  167.   
  168.     /* delay here to ensure the data byte has gotten onto the bus 
  169.      * before the transaction is started */  
  170.   
  171.     ndelay(i2c->tx_setup);  
  172.   
  173.     dev_dbg(i2c->dev, "iiccon, %08lx\n", iiccon);  
  174.     writel(iiccon, i2c->regs + S3C2410_IICCON);  
  175.   
  176.     stat |= S3C2410_IICSTAT_START;             /* 启动i2c,当设备地址发送后就会进入中断,在中断中根据不同状态进行读写操作 */  
  177.     writel(stat, i2c->regs + S3C2410_IICSTAT);  
  178. }  
  179.   
  180. static inline void s3c24xx_i2c_stop(struct s3c24xx_i2c *i2c, int ret)  
  181. {  
  182.     unsigned long iicstat = readl(i2c->regs + S3C2410_IICSTAT);  
  183.   
  184.     dev_dbg(i2c->dev, "STOP\n");  
  185.   
  186.     /* stop the transfer */  
  187.     iicstat &= ~S3C2410_IICSTAT_START;  
  188.     writel(iicstat, i2c->regs + S3C2410_IICSTAT);  
  189.   
  190.     i2c->state = STATE_STOP;  
  191.   
  192.     s3c24xx_i2c_master_complete(i2c, ret);  
  193.     s3c24xx_i2c_disable_irq(i2c);  
  194. }  
  195.   
  196. /* helper functions to determine the current state in the set of 
  197.  * messages we are sending */  
  198.   
  199. /* 关于以下三个函数功能区别,后文详解 */  
  200. /* is_lastmsg() 
  201.  * 
  202.  * returns TRUE if the current message is the last in the set 
  203. */  
  204.   
  205. static inline int is_lastmsg(struct s3c24xx_i2c *i2c)  
  206. {  
  207.     return i2c->msg_idx >= (i2c->msg_num - 1);  
  208. }  
  209.   
  210. /* is_msglast 
  211.  * 
  212.  * returns TRUE if we this is the last byte in the current message 
  213. */  
  214.   
  215. static inline int is_msglast(struct s3c24xx_i2c *i2c)  
  216. {  
  217.     return i2c->msg_ptr == i2c->msg->len-1;  
  218. }  
  219.   
  220. /* is_msgend 
  221.  * 
  222.  * returns TRUE if we reached the end of the current message 
  223. */  
  224.   
  225. static inline int is_msgend(struct s3c24xx_i2c *i2c)  
  226. {  
  227.     return i2c->msg_ptr >= i2c->msg->len;  
  228. }  
  229.   
  230. /* i2s_s3c_irq_nextbyte 
  231.  * 
  232.  * process an interrupt and work out what to do 
  233.  */  
  234.   
  235. static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)  
  236. {   
  237.        /* 此函数比较复杂,在后文中将举一个具体例子来说明整个过程 */  
  238.     unsigned long tmp;  
  239.     unsigned char byte;  
  240.     int ret = 0;  
  241.   
  242.     switch (i2c->state) {  
  243.   
  244.     case STATE_IDLE:  
  245.         dev_err(i2c->dev, "%s: called in STATE_IDLE\n", __func__);  
  246.         goto out;  
  247.         break;  
  248.   
  249.     case STATE_STOP:  
  250.         dev_err(i2c->dev, "%s: called in STATE_STOP\n", __func__);  
  251.         s3c24xx_i2c_disable_irq(i2c);  
  252.         goto out_ack;  
  253.   
  254.     case STATE_START:  
  255.         /* last thing we did was send a start condition on the 
  256.          * bus, or started a new i2c message 
  257.          */  
  258.   
  259.         if (iicstat & S3C2410_IICSTAT_LASTBIT &&  
  260.             !(i2c->msg->flags & I2C_M_IGNORE_NAK)) {  
  261.             /* ack was not received... */  
  262.   
  263.             dev_dbg(i2c->dev, "ack was not received\n");  
  264.             s3c24xx_i2c_stop(i2c, -ENXIO);  
  265.             goto out_ack;  
  266.         }  
  267.   
  268.         if (i2c->msg->flags & I2C_M_RD)  
  269.             i2c->state = STATE_READ;  
  270.         else  
  271.             i2c->state = STATE_WRITE;  
  272.   
  273.         /* terminate the transfer if there is nothing to do 
  274.          * as this is used by the i2c probe to find devices. */  
  275.   
  276.         if (is_lastmsg(i2c) && i2c->msg->len == 0) {  
  277.             s3c24xx_i2c_stop(i2c, 0);  
  278.             goto out_ack;  
  279.         }  
  280.   
  281.         if (i2c->state == STATE_READ)  
  282.             goto prepare_read;  
  283.   
  284.         /* fall through to the write state, as we will need to 
  285.          * send a byte as well */  
  286.   
  287.     case STATE_WRITE:  
  288.         /* we are writing data to the device... check for the 
  289.          * end of the message, and if so, work out what to do 
  290.          */  
  291.   
  292.         if (!(i2c->msg->flags & I2C_M_IGNORE_NAK)) {  
  293.             if (iicstat & S3C2410_IICSTAT_LASTBIT) {  
  294.                 dev_dbg(i2c->dev, "WRITE: No Ack\n");  
  295.   
  296.                 s3c24xx_i2c_stop(i2c, -ECONNREFUSED);  
  297.                 goto out_ack;  
  298.             }  
  299.         }  
  300.   
  301.  retry_write:  
  302.   
  303.         if (!is_msgend(i2c)) {  
  304.             byte = i2c->msg->buf[i2c->msg_ptr++];  
  305.             writeb(byte, i2c->regs + S3C2410_IICDS);  
  306.   
  307.             /* delay after writing the byte to allow the 
  308.              * data setup time on the bus, as writing the 
  309.              * data to the register causes the first bit 
  310.              * to appear on SDA, and SCL will change as 
  311.              * soon as the interrupt is acknowledged */  
  312.   
  313.             ndelay(i2c->tx_setup);  
  314.   
  315.         } else if (!is_lastmsg(i2c)) {  
  316.             /* we need to go to the next i2c message */  
  317.   
  318.             dev_dbg(i2c->dev, "WRITE: Next Message\n");  
  319.   
  320.             i2c->msg_ptr = 0;  
  321.             i2c->msg_idx++;  
  322.             i2c->msg++;  
  323.   
  324.             /* check to see if we need to do another message */  
  325.             if (i2c->msg->flags & I2C_M_NOSTART) {  
  326.   
  327.                 if (i2c->msg->flags & I2C_M_RD) {  
  328.                     /* cannot do this, the controller 
  329.                      * forces us to send a new START 
  330.                      * when we change direction */  
  331.   
  332.                     s3c24xx_i2c_stop(i2c, -EINVAL);  
  333.                 }  
  334.   
  335.                 goto retry_write;  
  336.             } else {  
  337.                 /* send the new start */  
  338.                 s3c24xx_i2c_message_start(i2c, i2c->msg);  
  339.                 i2c->state = STATE_START;  
  340.             }  
  341.   
  342.         } else {  
  343.             /* send stop */  
  344.   
  345.             s3c24xx_i2c_stop(i2c, 0);  
  346.         }  
  347.         break;  
  348.   
  349.     case STATE_READ:  
  350.         /* we have a byte of data in the data register, do 
  351.          * something with it, and then work out wether we are 
  352.          * going to do any more read/write 
  353.          */  
  354.   
  355.         byte = readb(i2c->regs + S3C2410_IICDS);  
  356.         i2c->msg->buf[i2c->msg_ptr++] = byte;  
  357.   
  358.  prepare_read:  
  359.         if (is_msglast(i2c)) {  
  360.             /* last byte of buffer */  
  361.   
  362.             if (is_lastmsg(i2c))  
  363.                 s3c24xx_i2c_disable_ack(i2c);  
  364.   
  365.         } else if (is_msgend(i2c)) {  
  366.             /* ok, we've read the entire buffer, see if there 
  367.              * is anything else we need to do */  
  368.   
  369.             if (is_lastmsg(i2c)) {  
  370.                 /* last message, send stop and complete */  
  371.                 dev_dbg(i2c->dev, "READ: Send Stop\n");  
  372.   
  373.                 s3c24xx_i2c_stop(i2c, 0);  
  374.             } else {  
  375.                 /* go to the next transfer */  
  376.                 dev_dbg(i2c->dev, "READ: Next Transfer\n");  
  377.   
  378.                 i2c->msg_ptr = 0;  
  379.                 i2c->msg_idx++;  
  380.                 i2c->msg++;  
  381.             }  
  382.         }  
  383.   
  384.         break;  
  385.     }  
  386.   
  387.     /* acknowlegde the IRQ and get back on with the work */  
  388.   
  389.  out_ack:              /* 退出时请pend flag */  
  390.     tmp = readl(i2c->regs + S3C2410_IICCON);  
  391.     tmp &= ~S3C2410_IICCON_IRQPEND;  
  392.     writel(tmp, i2c->regs + S3C2410_IICCON);  
  393.  out:  
  394.     return ret;  
  395. }  
  396.   
  397. /* s3c24xx_i2c_irq 
  398.  * 
  399.  * top level IRQ servicing routine 
  400. */  
  401.   
  402. static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id)  
  403. {  
  404.     /* 中断第一次进入在调用s3c24xx_i2c_message_start写入设备地址后 */  
  405.     struct s3c24xx_i2c *i2c = dev_id;  
  406.     unsigned long status;  
  407.     unsigned long tmp;  
  408.   
  409.     status = readl(i2c->regs + S3C2410_IICSTAT);  
  410.   
  411.     if (status & S3C2410_IICSTAT_ARBITR) {  
  412.         /* deal with arbitration loss */  
  413.         dev_err(i2c->dev, "deal with arbitration loss\n");  
  414.     }  
  415.   
  416.     if (i2c->state == STATE_IDLE) {  
  417.         dev_dbg(i2c->dev, "IRQ: error i2c->state == IDLE\n");  
  418.   
  419.         tmp = readl(i2c->regs + S3C2410_IICCON);  
  420.         tmp &= ~S3C2410_IICCON_IRQPEND;  
  421.         writel(tmp, i2c->regs +  S3C2410_IICCON);  
  422.         goto out;  
  423.     }  
  424.   
  425.     /* pretty much this leaves us with the fact that we've 
  426.      * transmitted or received whatever byte we last sent */  
  427.   
  428.     i2s_s3c_irq_nextbyte(i2c, status);    /* 根据不同状态步步推进读写操作,i2s_s3c_irq_nextbyte难点 */  
  429.   
  430.  out:  
  431.     return IRQ_HANDLED;  
  432. }  
  433.   
  434.   
  435. /* s3c24xx_i2c_set_master 
  436.  * 
  437.  * get the i2c bus for a master transaction 
  438. */  
  439.   
  440. static int s3c24xx_i2c_set_master(struct s3c24xx_i2c *i2c)  
  441. {  
  442.     unsigned long iicstat;  
  443.     int timeout = 400;  
  444.   
  445.     while (timeout-- > 0) {  
  446.         iicstat = readl(i2c->regs + S3C2410_IICSTAT);  
  447.   
  448.         if (!(iicstat & S3C2410_IICSTAT_BUSBUSY))  
  449.             return 0;  
  450.   
  451.         msleep(1);  
  452.     }  
  453.   
  454.     return -ETIMEDOUT;  
  455. }  
  456.   
  457. /* s3c24xx_i2c_doxfer 
  458.  * 
  459.  * this starts an i2c transfer 
  460. */  
  461.   
  462. static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,  
  463.                   struct i2c_msg *msgs, int num)  
  464. {  
  465.     unsigned long timeout;  
  466.     int ret;  
  467.   
  468.     if (i2c->suspended)  
  469.         return -EIO;  
  470.   
  471.     ret = s3c24xx_i2c_set_master(i2c);       /* 检查i2c总线状态 */  
  472.     if (ret != 0) {  
  473.         dev_err(i2c->dev, "cannot get bus (error %d)\n", ret);  
  474.         ret = -EAGAIN;  
  475.         goto out;  
  476.     }  
  477.   
  478.     spin_lock_irq(&i2c->lock);  
  479.   
  480.     i2c->msg     = msgs;        /* 把消息写入i2c结构体 */    
  481.     i2c->msg_num = num;  
  482.     i2c->msg_ptr = 0;  
  483.     i2c->msg_idx = 0;  
  484.     i2c->state   = STATE_START;  
  485.   
  486.     s3c24xx_i2c_enable_irq(i2c);      /* 使能中断*/  
  487.     s3c24xx_i2c_message_start(i2c, msgs);   /* 写设备地址,启动i2c */  
  488.     spin_unlock_irq(&i2c->lock);  
  489.   
  490.     timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);  /* 等待消息传输完成,否则超时 */  
  491.   
  492.     ret = i2c->msg_idx;     /* 成功传输消息条数 */  
  493.   
  494.     /* having these next two as dev_err() makes life very 
  495.      * noisy when doing an i2cdetect */  
  496.   
  497.     if (timeout == 0)  
  498.         dev_dbg(i2c->dev, "timeout\n");  
  499.     else if (ret != num)              /* 如果ret不等于原有消息条数,传输失败 */  
  500.         dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret);  
  501.   
  502.     /* ensure the stop has been through the bus */  
  503.   
  504.     msleep(1);  
  505.   
  506.  out:  
  507.     return ret;  
  508. }  
  509.   
  510. /* s3c24xx_i2c_xfer 
  511.  * 
  512.  * first port of call from the i2c bus code when an message needs 
  513.  * transferring across the i2c bus. 
  514. */  
  515.   
  516. static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,  
  517.             struct i2c_msg *msgs, int num)  
  518. {  
  519.     struct s3c24xx_i2c *i2c = (struct s3c24xx_i2c *)adap->algo_data;  
  520.     int retry;  
  521.     int ret;  
  522.   
  523.     for (retry = 0; retry < adap->retries; retry++) {   /* 传输不成功重复次数 */  
  524.   
  525.         ret = s3c24xx_i2c_doxfer(i2c, msgs, num);   /* 重点在这里实现 */  
  526.   
  527.         if (ret != -EAGAIN)  
  528.             return ret;  
  529.   
  530.         dev_dbg(i2c->dev, "Retrying transmission (%d)\n", retry);  
  531.   
  532.         udelay(100);  
  533.     }  
  534.   
  535.     return -EREMOTEIO;  
  536. }  
  537.   
  538. /* declare our i2c functionality */  
  539. static u32 s3c24xx_i2c_func(struct i2c_adapter *adap)  
  540. {      /* 支持的功能,定义在i2c.h */  
  541.     return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING;  
  542. }  
  543.   
  544. /* i2c bus registration info */  
  545.   
  546. static const struct i2c_algorithm s3c24xx_i2c_algorithm = {  
  547.     .master_xfer        = s3c24xx_i2c_xfer,  
  548.     .functionality      = s3c24xx_i2c_func,  
  549. };  

      I2C适配器的通信方法整个驱动的重点,主要实现i2c_algorithm的master_xfer()和functionality()。s3c24xx_i2c_xfer中调用了s3c24xx_i2c_doxfer,然后启动i2c,并且通过中断s3c24xx_i2c_irq和i2s_s3c_irq_nextbyte来一步步推进传输工作。

      通信方法传输是以消息为单位的,所有先了解消息结构体。消息i2c_msg包括地址、标志、一条消息包含的数据及长度。

struct i2c_msg {

       __u16 addr;    /* slave address                    */

       __u16 flags;

#define I2C_M_TEN            0x0010    /* this is a ten bit chip address */

#define I2C_M_RD              0x0001    /* read data, from slave to master */

#define I2C_M_NOSTART           0x4000    /* if I2C_FUNC_PROTOCOL_MANGLING */

#define I2C_M_REV_DIR_ADDR 0x2000    /* if I2C_FUNC_PROTOCOL_MANGLING */

#define I2C_M_IGNORE_NAK    0x1000    /* if I2C_FUNC_PROTOCOL_MANGLING */

#define I2C_M_NO_RD_ACK             0x0800    /* if I2C_FUNC_PROTOCOL_MANGLING */

#define I2C_M_RECV_LEN         0x0400    /* length will be first received byte */

       __u16 len;             /* msg length                       */

       __u8 *buf;             /* pointer to msg data                  */

};

      代码中提到的is_lastmsg、is_msglast、is_msgend到底判断是什么?在s3c24xx_i2c中定义的struct i2c_msg       *msg看出可以包含多条消息,而一条消息有可能包含多个数据,比如对于AT24c02页写就包含多个数据。is_lastmsg判断是否是消息中最后一条,使用了变量msg_idx;is_msglast判断是否一条消息中最后一个数据,is_msgend判断是否是一条消息全部完成,所以这两个函数使用变量时msg_ptr。

      下面就根据AT24C02具体的讲解s3c24xx_i2c_irq和i2s_s3c_irq_nextbyte如何实现传输。

      任意地址字节写时序如上所示,只需要一条消息即可。其中flag位为写,写0即可,消息包括两个数据目标地址、数据,消息如下所示。

struct i2c_msg *msg;

msg=malloc(sizeof(struct i2c_msg));

msg.len=2;    // 1个目标地址和1个数据

msg.addr=0x50; // 设备地址

msg.flags=0;  // write

msg.buf=(unsigned char*)malloc(2);

msg.buf[0]=0x10;// 目标地址

msg.buf[1]=0x58;// the data to write

      s3c24xx_i2c_xfer中调用了s3c24xx_i2c_doxfer,在s3c24xx_i2c_doxfer中把消息传入i2c->msg,使能中断,置i2c->state 为STATE_START,调用s3c24xx_i2c_message_start启动i2c发送设备地址,就等待中断来做后续工作。当设备地址发送后就会进入中断,继续进入i2s_s3c_irq_nextbyte的STATE_START,判断消息为写,置i2c->state 为STATE_WRITE,跳入STATE_WRITE,在retry_write这一段中,if先判断是否一条消息所有数据发送完,没发送完,则每次发送一条等待下次中断进入,每发送一个数据都要清pend位;发送完else if判断是否最后一条消息,如果不是则要指针指向下一条消息继续if的步骤;最后else为发送完成,停止i2c。针对任意字节写只有一条消息,if中发送两次就完成本条消息传输。

      任意地址字节读时序如上所示,需两条消息。第一条,写目标地址,flag位为写;第二条,读取数据,flag位为读,第一条与第二条消息之间要发送START。

struct i2c_msg *msgs;

msgs=malloc(2*sizeof(struct i2c_msg));

msgs[0].len=1; // 目标地址

msgs[0].addr=0x50; // 设备地址

msgs[0].flags=0; // write

msgs[0].buf=(unsigned char*)malloc(1);

msgs[0].buf[0]=0x10; // 目标地址

msgs[1].len=1; // 读出的数据

msgs[1].addr=0x50; // 设备地址

msgs[1].flags=I2C_M_RD; // read

msgs[1].buf=(unsigned char*)malloc(1);

msgs[1].buf[0]=0;// 初始化读缓冲

      直接从中断开始讲,发送设备地址后,进入STATE_START,判断第一条消息为写,置i2c->state 为STATE_WRITE,跳入STATE_WRITE,第一条消息有一个数据,发送完成后,在else if中判断不是此条消息不是最后一条,就会执行else if中指向下一条消息,s3c24xx_i2c_message_start重新发送START,置i2c->state 为STATE_START。下次进入中跳到STATE_START,判断第二条消息为读,置i2c->state 为STATE_READ跳入STATE_READ,第二条消息只有一个数据,关闭ack,接收一个字节,停止i2c。看完这两个例子,再看



当适配器加载到内核后,就针对具体设备编写I2C设备驱动。编写设备驱动有两种方法,一种是利用系统提供的i2c-dev.c实现,另一种为i2c编写一个独立的设备驱动。

一、i2c-dev.c控制i2c设备

      i2c-dev.c没有针对具体设备来设计,提供了通用i2cdev_read()、i2cdev_write()函数来对应用户空间要使用的read()和write()文件操作接口,这两个函数分别调用I2C 核心的i2c_master_recv()和i2c_master_send()函数来构造一条I2C 消息并引发适配器algorithm 通信函数的调用,完成消息的传输。但是i2c_read()、i2c_write()对于一些复杂消息(eeprom字节读ReStart模式)并不太适用,针对以上情况,可以使用i2cdev_ioctl()实现消息组的传输,通过I2C_RDWR IOCTL命令实现。

      常用的IOCTL包括包括I2C_SLAVE(设置从设备地址)、I2C_RETRIES(没有收到设备ACK 情况下的重试次数,默认为1)、I2C_TIMEOUT(超时)以及I2C_RDWR等。应用程序通过i2c_rdwr_ioctl_data结构体来给内核传递消息,结构体定义如下

struct i2c_rdwr_ioctl_data {

       struct i2c_msg __user *msgs; /* pointers to i2c_msgs */

       __u32 nmsgs; /* number of i2c_msgs */

};

      下面是利用i2c_dev.c操作i2c设备AT24C02具体的代码,这种方法是从应用层完成i2c设备驱动,代码摘自http://blog.csdn.net/hongtao_liu/article/details/4964244

 

[cpp] view plaincopy
  1. #include <stdio.h>  
  2. #include <linux/types.h>  
  3. #include <stdlib.h>  
  4. #include <fcntl.h>  
  5. #include <unistd.h>  
  6. #include <sys/types.h>  
  7. #include <sys/ioctl.h>  
  8. #include <errno.h>  
  9. #define I2C_RETRIES 0x0701  
  10. #define I2C_TIMEOUT 0x0702  
  11. #define I2C_RDWR 0x0707   
  12. /*********参数定义与内核一致,路径include/linux/i2c-dev.h*******/  
  13.   
  14. struct i2c_msg  
  15. {  
  16.     unsigned short addr;  
  17.     nsigned short flags;  
  18. #define I2C_M_TEN 0x0010  
  19. #define I2C_M_RD 0x0001  
  20.     unsigned short len;  
  21.     unsigned char *buf;  
  22. };  
  23.   
  24. struct i2c_rdwr_ioctl_data  
  25. {  
  26.     struct i2c_msg *msgs;  
  27.     int nmsgs;   
  28.         /* nmsgs这个数量决定了有多少开始信号,对于“单开始时序”,取1*/  
  29. };  
  30.   
  31. int main()  
  32. {  
  33.     int fd,ret;  
  34.     struct i2c_rdwr_ioctl_data e2prom_data;  
  35.     fd=open("/dev/i2c-0",O_RDWR);  
  36.         /* 
  37.         */dev/i2c-0是在注册i2c-dev.c后产生的,代表一个可操作的适配器。如果不使用i2c-dev.c  
  38.         *的方式,就没有,也不需要这个节点。  
  39.         */  
  40.     if(fd<0)  
  41.     {  
  42.         perror("open error");  
  43.     }  
  44.     e2prom_data.nmsgs=2;   
  45.         /* 
  46.         *因为操作时序中,最多是用到2个开始信号(字节读操作中),所以此将 
  47.         *e2prom_data.nmsgs配置为2 
  48.         */  
  49.     e2prom_data.msgs=(struct i2c_msg*)malloc(e2prom_data.nmsgs*sizeof(struct i2c_msg));  
  50.     if(!e2prom_data.msgs)  
  51.     {  
  52.         perror("malloc error");  
  53.         exit(1);  
  54.     }  
  55.     ioctl(fd,I2C_TIMEOUT,1);/*超时时间*/  
  56.     ioctl(fd,I2C_RETRIES,2);/*重复次数*/  
  57.   
  58.     /***write data to e2prom**/  
  59.     e2prom_data.nmsgs=1;  
  60.     (e2prom_data.msgs[0]).len=2; //1个 e2prom 写入目标的地址和1个数据   
  61.     (e2prom_data.msgs[0]).addr=0x50;//e2prom 设备地址  
  62.     (e2prom_data.msgs[0]).flags=0; //write  
  63.     (e2prom_data.msgs[0]).buf=(unsigned char*)malloc(2);  
  64.     (e2prom_data.msgs[0]).buf[0]=0x10;// e2prom 写入目标的地址  
  65.     (e2prom_data.msgs[0]).buf[1]=0x58;//the data to write   
  66.   
  67.         ret=ioctl(fd,I2C_RDWR,(unsigned long)&e2prom_data);  
  68.     if(ret<0)  
  69.     {  
  70.         perror("ioctl error1");  
  71.     }  
  72.     sleep(1);  
  73.   
  74.         /******read data from e2prom*******/  
  75.     e2prom_data.nmsgs=2;  
  76.     (e2prom_data.msgs[0]).len=1; //e2prom 目标数据的地址  
  77.     (e2prom_data.msgs[0]).addr=0x50; // e2prom 设备地址  
  78.     (e2prom_data.msgs[0]).flags=0;//write  
  79.     (e2prom_data.msgs[0]).buf[0]=0x10;//e2prom数据地址  
  80.     (e2prom_data.msgs[1]).len=1;//读出的数据  
  81.     (e2prom_data.msgs[1]).addr=0x50;// e2prom 设备地址   
  82.     (e2prom_data.msgs[1]).flags=I2C_M_RD;//read  
  83.     (e2prom_data.msgs[1]).buf=(unsigned char*)malloc(1);//存放返回值的地址。  
  84.     (e2prom_data.msgs[1]).buf[0]=0;//初始化读缓冲  
  85.   
  86.         ret=ioctl(fd,I2C_RDWR,(unsigned long)&e2prom_data);  
  87.     if(ret<0)  
  88.     {  
  89.         perror("ioctl error2");  
  90.     }  
  91.     printf("buff[0]=%x/n",(e2prom_data.msgs[1]).buf[0]);  
  92.         /***打印读出的值,没错的话,就应该是前面写的0x58了***/  
  93.     close(fd);  
  94.     return 0;  
  95. }  

二、内核中编写i2c设备驱动

      内核编写i2c设备驱动支持两种方式:Adapter方式(LEGACY)和Probe方式(new style)。

1.legacy方式

       此方法驱动需要自己创建i2c_client,并且要知道芯片的地址,在内核目录documentation/i2c/upgrading-clients中有一个例程。

i2c_driver构建

static struct i2c_driver at24c02_driver = {

       .driver = {

              .name      = "at24c02",

       },

       .id           = I2C_DRIVERID_EEPROM,

       .attach_adapter       = at24c02_attach_adapter,

       .detach_client  = at24c02_detach_client,

};

I2C设备驱动的加载与卸载函数模板

static int __init at24c02_init(void)

{

       return i2c_add_driver(&at24c02_driver);

}

      i2c_add_driver的执行回引发i2c_driver结构体at24c02_attach_adapter的执行,若内核中注册了i2c适配器,就顺序调用这些适配器来连接i2c设备,at24c02_attach_adapter调用i2c核心i2c_probe探测设备

static int at24c02_attach_adapter(struct i2c_adapter *adapter)

{

       return i2c_probe(adapter, &addr_data, at24c02_detect);

}

static unsigned short normal_i2c[] = { 0x50, 0x51, 0x52, 0x53, 0x54,

                                   0x55, 0x56, 0x57, I2C_CLIENT_END };

/* Insmod parameters */

I2C_CLIENT_INSMOD_1(at24c02);

       其中第二个参数add_data是i2c_client_address_data类型的变量,由normal_i2c[]通过宏I2C_CLIENT_INSMOD_1构建而成,具体方法参考i2c.h文件。normal_i2c是i2c芯片的地址,如果地址与芯片对应不上,无法探测到设备,当探测到目标设备后,调用at24c02_detect,把探测到得地址address作为参数传入。

#define AT24C02_MAJOR 250

static int at24c02_major = AT24C02_MAJOR;

struct at24c02_data {

       struct cdev cdev;

       struct i2c_client client;

       struct mutex update_lock;

       u8 data[EEPROM_SIZE];             /* Register values */

};

static int at24c02_detect(struct i2c_adapter *adapter, int address, int kind)

{

       struct i2c_client *new_client;

       struct at24c02_data *data;

       int err = 0,result;

       dev_t at24c02_dev=MKDEV(at24c02_major,0);

 

       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA

                                       | I2C_FUNC_SMBUS_BYTE)) //判断适配器功能

              goto exit;

 

       if (!(data = kzalloc(sizeof(struct at24c02_data), GFP_KERNEL))) {

              err = -ENOMEM;

              goto exit;

       } 

       new_client = &data->client;

       memset(data->data, 0xff, EEPROM_SIZE);

       i2c_set_clientdata(new_client, data);

       new_client->addr = address;

       new_client->adapter = adapter;

       new_client->driver = &at24c02_driver;

       new_client->flags = 0;

 

       /* Fill in the remaining client fields */

       strlcpy(new_client->name, "at24c02", I2C_NAME_SIZE);

       mutex_init(&data->update_lock);

 

       /* Tell the I2C layer a new client has arrived */

       if ((err = i2c_attach_client(new_client)))

              goto exit_kfree;

 

       if(at24c02_major)

       {

              result=register_chrdev_region(at24c02_dev,1,”at24c02”);

       }

       else

      {

              result=alloc_chrdev_region(&at24c02_dev,0,1,”at24c02”);

              at24c02_major=MAJOR(at24c02_dev);

       }

       if(result<0)

       {

              printk(KERN_NOTICE “Unable to get region %d/n”,result);

              err=result;

              goto exit_detach;

       }

       at24c02_setup_cdev(data,0);    //注册字符设备at24c02_fops

       return 0;

 

exit_detach:

       i2c_detach_client(new_client);

exit_kfree:

       kfree(data);

exit:

       return err;

}

static void at24c02_setup_cdev(struct at24c02_data *dev,int index)

{

       int err,at24c02_dev=MKDEV(at24c02_major,index);

       cdev_init(&dev->cdev,&at24c02_fops);

       dev_cdev.owner=THIS_MODULE;

       err=cdev_add(&dev->cdev,at24c02_dev,1);

       if(err)

              printk(KERN_NOTICE "error %d adding at24c02 %d/n",err,index);

}

        i2c设备驱动卸载函数进行i2c_del_driver调用后,顺序调用内核中注册的适配器断开注册过的i2c设备,此过程是调用at24c02_detach_client实现的。

static void __exit at24c02_exit(void)

{

       i2c_del_driver(&at24c02_driver);

}

static int at24c02_detach_client(struct i2c_client *client)

{

       int err;

       struct at24c02_data *data;

 

       data=i2c_get_client(client);

       cdev_del(&(data->cdev));

       unregister_chrdev_region(MKDEV(at24c02_major, 0), 1);

       err = i2c_detach_client(client);

       if (err)

              return err;

       kfree(data);

 

       return 0;

}

字符驱动的实现

struct file_operations at24c02_fops = {

                .owner = THIS_MODULE,

                .read= at24c02 _read,

                .write= at24c02 _write,

                .open= at24c02 _open,

                .release = at24c02_release,

        };

      字符设备驱动不在详述,主要说明如何调用适配器完成数据传输。首先构造消息,通过i2c_transfer来传递,i2c_transfer找到对应适配器algorithm通信方法master_xfer最终完成i2c消息处理。下面是一个关于设备驱动的读函数,其他类似。

static int at24c02_open(struct inode *inode, struct file *file)

{

       struct at24c02_data *data;

       data=container_of(inode->i_cdev,struct at24c02_data,cdev);

       file->private_data = data;

       return 0;

}

static int at24c02_read(struct file *filp, char __user *buff,size_t count, loff_t *offp)

{

       int ret;

       struct i2c_msg msg[2];

       char addr = 0;

       struct at24c02_data *data=file->private_data;

   

       if (count > 1024)

       {

              return -EINVAL;

       }

 

       msg[0].addr  = data->client->addr;

       msg[0].flags = 0;       /* write */

       msg[0].len   = 1;       /* 1个地址 */

       msg[0].buf   = &addr;

       msg[1].addr  = data->client->addr;

       msg[1].flags = I2C_M_RD;       /* read */

       msg[1].len   = count;          /* 要读的数据个数 */

       msg[1].buf   = data->data;  

 

       ret = i2c_transfer(at24c02_client->adapter, msg, 2);

       if (ret == 2)

       {

              copy_to_user(buff, data->data, count);

              return count;

       }

       else

              return -EIO;

}

      目前适配器主要支持的传输方法有两种:master_xfer和smbus_xfer,从i2c_algorithm结构体可看出。一般来说,若适配器支持master_xfer那么它可以模拟支持smbus,但只实现smbus_xfer,则不支持master_xfer传输。当然,上面的驱动也可以采用smbus方式完成传输。采用LEGACY方式在2.6.32.2内核下编译不过去,主要是i2c核心中有些函数不存在,所以,设备驱动发展方向是new style方式。

2.new style方式

构建i2c_driver

static struct i2c_driver at24c02_driver = {

       .driver = {

              .name = "at24c02",

              .owner = THIS_MODULE,

       },

       .probe = at24c02_probe,

       .remove = __devexit_p(at24c02_remove),

       .id_table = at24c02_id,

};

加载与注销

static int __init at24c02_init(void)

{

       return i2c_add_driver(&at24c02_driver);

}

module_init(at24c02_init);

        i2c_add_driver会将驱动注册到总线上,探测到i2c设备就会调用at24c02_probe,探测主要是用i2c_match_id函数比较client的名字和id_table中名字,如果相等,则探测到i2c设备,本驱动中id_table如下:

static const struct i2c_device_id at24c02_id[] = {

       { "at24c02", 0 },

       { }

};

MODULE_DEVICE_TABLE(i2c, at24c02_id);

       MODULE_DEVICE_TABLE宏是用来生成i2c_device_id。在legacy方式中i2c_client是自己创建的,而此处的i2c_client如何得到?实际上是在i2c_register_board_info函数注册i2c_board_info过程中构建的,所以arch/arm/mach-s3c2440/mach-smdk2440.c中添加注册信息。

static struct i2c_board_info i2c_devices[] __initdata = {

       { I2C_BOARD_INFO("at24c02", 0x50), },

};

static void __init smdk2440_machine_init(void)

{

       i2c_register_board_info(0,i2c_devices,ARRAY_SIZE(i2c_devices));

       s3c24xx_fb_set_platdata(&smdk2440_fb_info);

       s3c_i2c0_set_platdata(NULL);

 

       platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));

       smdk_machine_init();

}

       如果没有注册i2c信息,就探测不到i2c设备。探测到at24c02设备后就会调用at24c02_probe函数。

static int __devinit at24c08b_probe(struct i2c_client *client,const struct i2c_device_id *id)

{

       struct at24c02_data *data;

       int err = 0,result;

       dev_t at24c02_dev=MKDEV(at24c02_major,0);

 

       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA

                                       | I2C_FUNC_SMBUS_BYTE)) //判断适配器功能

              goto exit;

 

       if (!(data = kzalloc(sizeof(struct at24c02_data), GFP_KERNEL))) {

              err = -ENOMEM;

              goto exit;

       }

 

       memset(data, 0, sizeof(struct at24c02_data));

       data->client=client;

       i2c_set_clientdata(client, data);

 

       if(at24c02_major)

       {

              result=register_chrdev_region(at24c02_dev,1,”at24c02”);

       }

       else

       {

              result=alloc_chrdev_region(&at24c02_dev,0,1,”at24c02”);

              at24c02_major=MAJOR(at24c02_dev);

       }

       if(result<0)

       {

              printk(KERN_NOTICE “Unable to get region %d/n”,result);

              err=result;

              goto exit_kfree;

       }

       at24c02_setup_cdev(data,0);    //注册字符设备at24c02_fops

       return 0;

 

exit_kfree:

       kfree(data);

exit:

       return err;

}

       probe函数主要注册了字符设备,通过data->client=client获得的相关信息。关于at24c02_fops结构体的完善,由于与前面一种方法类似,这里就不详述。最后就是驱动的注销。

static void __exit at24c02_exit(void)

{

       i2c_del_driver(&at24c02_driver);

}

module_exit(at24c02_exit);

static int __devexit at24c02_remove(struct i2c_client *client)

{

       int err;

       struct at24c02_data *data;

       data=i2c_get_client(client);

       cdev_del(&(data->cdev));

       unregister_chrdev_region(MKDEV(at24c02_major, 0), 1);

       kfree(data);

       return 0;

}







原创粉丝点击