Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3167911
  • 博文数量: 685
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 5303
  • 用 户 组: 普通用户
  • 注册时间: 2014-04-19 14:17
个人简介

文章分类

全部博文(685)

文章存档

2015年(116)

2014年(569)

分类: LINUX

2014-07-25 05:12:19

原文地址:http://blog.csdn.net/liaozc/article/details/6655030

I2C子系统驱动(二)

      上一篇文章讲述了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适配器驱动加载卸载

  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, ");  
  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通信方法

  1. #include   
  2. #include   
  3.   
  4. #include   
  5. #include   
  6. #include   
  7. #include   
  8. #include   
  9. #include   
  10. #include   
  11. #include   
  12. #include   
  13. #include   
  14. #include   
  15.   
  16. #include   
  17. #include   
  18.   
  19. #include   
  20. #include   
  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。看完这两个例子,再看i2s_s3c_irq_nextbyte就容易理解。



阅读(1349) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~