以s3c2440的I2C子系统为例, 分析其代码实现

来源:互联网 发布:不吃清真食品 知乎 编辑:程序博客网 时间:2024/05/21 07:02

本文以s3c2440的I2C子系统为例, 分析其代码实现

本人学习驱动不久, 如有瑕疵纰漏, 欢迎指教, 谢谢

从硬件的角度看, I2C子系统由总线适配器和挂在总线上的设备组成
因此, 很容易想到, Linux的I2C子系统至少要提供:
    总线上设备的支持, 以及其驱动
    总线适配器的支持, 以及其驱动

1. S3C2440的I2C总线作为一个平台设备, 来看下添加平台设备的代码: /arch/arm/mach-s3c2440/mach-smdk2440.c

[cpp] view plaincopy
  1. static struct platform_device *smdk2440_devices[] __initdata = {  
  2.     &s3c_device_usb,  
  3.     &s3c_device_lcd,  
  4.     &s3c_device_wdt,  
  5.     &s3c_device_i2c0,  
  6.     &s3c_device_iis,  
  7. };  
  8.   
  9. static void __init smdk2440_machine_init(void)  
  10. {  
  11.     s3c24xx_fb_set_platdata(&smdk2440_fb_info);  
  12.     s3c_i2c0_set_platdata(NULL);  
  13.   
  14.     platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));  
  15.     smdk_machine_init();  
  16. }  
其中, s3c_device_i2c0即为I2C的平台设备, 看下它是怎么定义的: /arch/arm/plat-s3c/dev-i2c0.c
[cpp] view plaincopy
  1. static struct resource s3c_i2c_resource[] = {  
  2.     [0] = {  
  3.         .start = S3C_PA_IIC,  
  4.         .end   = S3C_PA_IIC + SZ_4K - 1,  
  5.         .flags = IORESOURCE_MEM,  
  6.     },  
  7.     [1] = {  
  8.         .start = IRQ_IIC,  
  9.         .end   = IRQ_IIC,  
  10.         .flags = IORESOURCE_IRQ,  
  11.     },  
  12. };  
  13.   
  14. struct platform_device s3c_device_i2c0 = {  
  15.     .name         = "s3c2410-i2c",  
  16. #ifdef CONFIG_S3C_DEV_I2C1  
  17.     .id       = 0,  
  18. #else  
  19.     .id       = -1,  
  20. #endif  
  21.     .num_resources    = ARRAY_SIZE(s3c_i2c_resource),  
  22.     .resource     = s3c_i2c_resource,  
  23. };  
设备名称为s3c2410-i2c, 同时定义了两个资源, 一段IO内存, 一个中断号
在smdk2440_machine_init中, 即初始化过程中, 调用了s3c_i2c0_set_platdata(NULL)
[cpp] view plaincopy
  1. static struct s3c2410_platform_i2c default_i2c_data0 __initdata = {  
  2.     .flags      = 0,  
  3.     .slave_addr = 0x10,  
  4.     .bus_freq   = 100*1000,  
  5.     .max_freq   = 400*1000,  
  6.     .sda_delay  = S3C2410_IICLC_SDA_DELAY5 | S3C2410_IICLC_FILTER_ON,  
  7. };  
  8.   
  9. void __init s3c_i2c0_set_platdata(struct s3c2410_platform_i2c *pd)  
  10. {  
  11.     struct s3c2410_platform_i2c *npd;  
  12.   
  13.     if (!pd)  
  14.         pd = &default_i2c_data0;  
  15.   
  16.     npd = kmemdup(pd, sizeof(struct s3c2410_platform_i2c), GFP_KERNEL);  
  17.     if (!npd)  
  18.         printk(KERN_ERR "%s: no memory for platform data\n", __func__);  
  19.     else if (!npd->cfg_gpio)  
  20.         npd->cfg_gpio = s3c_i2c0_cfg_gpio;  
  21.   
  22.     s3c_device_i2c0.dev.platform_data = npd;  
  23. }  
阅读s3c_i2c0_set_platdata函数, 是对s3c_device_i2c0添加一些设备参数(default_i2c_data0)
简单的看下系统默认提供的这套参数, slave_addr应该是作为从机的地址, bus_freq应该是总线频率, 为100kHz, ...

所以, 设备结构体s3c_device_i2c0最后应该是这个样子:
[cpp] view plaincopy
  1. struct platform_device s3c_device_i2c0 = {  
  2.     .name         = "s3c2410-i2c",  
  3.     .id       = -1,  
  4.     .num_resources    = ARRAY_SIZE(s3c_i2c_resource),  
  5.     .resource     = s3c_i2c_resource,  
  6. };  
  7.   
  8. s3c_device_i2c0.dev.platform_data = {  
  9.     .flags      = 0,  
  10.     .slave_addr = 0x10,  
  11.     .bus_freq   = 100*1000,  
  12.     .max_freq   = 400*1000,  
  13.     .sda_delay  = S3C2410_IICLC_SDA_DELAY5 | S3C2410_IICLC_FILTER_ON,  
  14.     .cfg_gpio   = s3c_i2c0_cfg_gpio;  
  15. };  
其中有个函数指针cfg_gpio, 指向了s3c_i2c0_cfg_gpio, 作用是配置I2C相应IO接口:
[cpp] view plaincopy
  1. void s3c_i2c0_cfg_gpio(struct platform_device *dev)  
  2. {  
  3.     s3c2410_gpio_cfgpin(S3C2410_GPE15, S3C2410_GPE15_IICSDA);  
  4.     s3c2410_gpio_cfgpin(S3C2410_GPE14, S3C2410_GPE14_IICSCL);  
  5. }  

自此, I2C作为平台设备, 被添加到了平台总线上.

2. 设备添加完了, 就该驱动了, 来看下I2C设备驱动定义: /drivers/i2c/buses/i2c-s3c2410.c
[cpp] view plaincopy
  1. static struct platform_driver s3c2410_i2c_driver = {  
  2.     .probe      = s3c24xx_i2c_probe,  
  3.     .remove     = s3c24xx_i2c_remove,  
  4.     .suspend_late   = s3c24xx_i2c_suspend_late,  
  5.     .resume     = s3c24xx_i2c_resume,  
  6.     .driver     = {  
  7.         .owner  = THIS_MODULE,  
  8.         .name   = "s3c2410-i2c",  
  9.     },  
  10. };  
驱动名字为s3c2410-i2c, 和设备名字一样
然后将注册驱动, 将驱动添加到平台总线上:
[cpp] view plaincopy
  1. static int __init i2c_adap_s3c_init(void)  
  2. {  
  3.     int ret;  
  4.   
  5.     ret = platform_driver_register(&s3c2410_i2c_driver);  
  6.     if (ret == 0) {  
  7.         ret = platform_driver_register(&s3c2440_i2c_driver);  
  8.         if (ret)  
  9.             platform_driver_unregister(&s3c2410_i2c_driver);  
  10.     }  
  11.   
  12.     return ret;  
  13. }  

回想一下, 当添加一个平台设备或者平台驱动时, 都会调用总线的match函数来将设备和驱动配对
而平台总线的match是根据设备和驱动的名字, 当相同时, 即匹配成功, 并调用驱动的probe函数

那么, 接着来看下s3c24xx_i2c_probe函数, 为了看着清晰些, 我把错误检测和错误恢复的代码删了
[cpp] view plaincopy
  1. /* s3c24xx_i2c_probe 
  2.  * 
  3.  * called by the bus driver when a suitable device is found 
  4. */  
  5. static int s3c24xx_i2c_probe(struct platform_device *pdev)  
  6. {  
  7.     struct s3c24xx_i2c *i2c;  
  8.     struct s3c2410_platform_i2c *pdata;  
  9.     struct resource *res;  
  10.     int ret;  
  11.   
  12.     pdata = pdev->dev.platform_data;  
  13.   
  14.     i2c = kzalloc(sizeof(struct s3c24xx_i2c), GFP_KERNEL);  
  15.   
  16.     strlcpy(i2c->adap.name, "s3c2410-i2c"sizeof(i2c->adap.name));  
  17.     i2c->adap.owner   = THIS_MODULE;  
  18.     i2c->adap.algo    = &s3c24xx_i2c_algorithm;  
  19.     i2c->adap.retries = 2;  
  20.     i2c->adap.class   = I2C_CLASS_HWMON | I2C_CLASS_SPD;  
  21.     i2c->tx_setup     = 50;  
  22.   
  23.     spin_lock_init(&i2c->lock);  
  24.     init_waitqueue_head(&i2c->wait);  
  25.   
  26.     /* find the clock and enable it */  
  27.     i2c->dev = &pdev->dev;  
  28.     i2c->clk = clk_get(&pdev->dev, "i2c");  
  29.   
  30.     dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk);  
  31.   
  32.     clk_enable(i2c->clk);  
  33.   
  34.     /* map the registers */  
  35.     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  
  36.   
  37.     i2c->ioarea = request_mem_region(res->start, (res->end-res->start)+1,  
  38.                      pdev->name);  
  39.   
  40.     i2c->regs = ioremap(res->start, (res->end-res->start)+1);  
  41.   
  42.     dev_dbg(&pdev->dev, "registers %p (%p, %p)\n",  
  43.         i2c->regs, i2c->ioarea, res);  
  44.   
  45.     /* setup info block for the i2c core */  
  46.     i2c->adap.algo_data = i2c;  
  47.     i2c->adap.dev.parent = &pdev->dev;  
  48.   
  49.     /* initialise the i2c controller */  
  50.     ret = s3c24xx_i2c_init(i2c);  
  51.   
  52.     /* find the IRQ for this unit (note, this relies on the init call to 
  53.      * ensure no current IRQs pending 
  54.      */  
  55.     i2c->irq = ret = platform_get_irq(pdev, 0);  
  56.   
  57.     ret = request_irq(i2c->irq, s3c24xx_i2c_irq, IRQF_DISABLED,  
  58.               dev_name(&pdev->dev), i2c);  
  59.   
  60.     ret = s3c24xx_i2c_register_cpufreq(i2c);  
  61.   
  62.     /* Note, previous versions of the driver used i2c_add_adapter() 
  63.      * to add the bus at any number. We now pass the bus number via 
  64.      * the platform data, so if unset it will now default to always 
  65.      * being bus 0. 
  66.      */  
  67.     i2c->adap.nr = pdata->bus_num;  
  68.   
  69.     ret = i2c_add_numbered_adapter(&i2c->adap);  
  70.   
  71.     platform_set_drvdata(pdev, i2c);  
  72.   
  73.     dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev));  
  74.     return 0;  
  75. }  
比较常规的probe, 使能时钟, 申请IO内存, 映射IO内存, 申请中断就不说了, 删去, 得到以下:
[cpp] view plaincopy
  1. static int s3c24xx_i2c_probe(struct platform_device *pdev)  
  2. {  
  3.     struct s3c24xx_i2c *i2c;  
  4.     struct s3c2410_platform_i2c *pdata;  
  5.     struct resource *res;  
  6.     int ret;  
  7.   
  8.     pdata = pdev->dev.platform_data;  
  9.   
  10.     i2c = kzalloc(sizeof(struct s3c24xx_i2c), GFP_KERNEL);  
  11.   
  12.     strlcpy(i2c->adap.name, "s3c2410-i2c"sizeof(i2c->adap.name));  
  13.     i2c->adap.owner   = THIS_MODULE;  
  14.     i2c->adap.algo    = &s3c24xx_i2c_algorithm;  
  15.     i2c->adap.retries = 2;  
  16.     i2c->adap.class   = I2C_CLASS_HWMON | I2C_CLASS_SPD;  
  17.     i2c->tx_setup     = 50;  
  18.   
  19.     /* setup info block for the i2c core */  
  20.     i2c->adap.algo_data = i2c;  
  21.     i2c->adap.dev.parent = &pdev->dev;  
  22.   
  23.     /* initialise the i2c controller */  
  24.     ret = s3c24xx_i2c_init(i2c);  
  25.     ret = s3c24xx_i2c_register_cpufreq(i2c);  
  26.   
  27.     /* Note, previous versions of the driver used i2c_add_adapter() 
  28.      * to add the bus at any number. We now pass the bus number via 
  29.      * the platform data, so if unset it will now default to always 
  30.      * being bus 0. 
  31.      */  
  32.     i2c->adap.nr = pdata->bus_num;  
  33.     ret = i2c_add_numbered_adapter(&i2c->adap);  
  34.   
  35.     platform_set_drvdata(pdev, i2c);  
  36.   
  37.     return 0;  
  38. }  
是不是清爽多了
函数定义了一个struct s3c24xx_i2c *i2c, 然后对其初始化
而且可以看出, 主要是对i2c->adap进行初始化
i2c->adap指向一个struct i2c_adapter结构体, 可以翻译为i2c适配器, 来看下
[cpp] view plaincopy
  1. /* 
  2.  * i2c_adapter is the structure used to identify a physical i2c bus along 
  3.  * with the access algorithms necessary to access it. 
  4.  */  
  5. struct i2c_adapter {  
  6.     struct module *owner;  
  7.     unsigned int id;  
  8.     unsigned int class;       /* classes to allow probing for */  
  9.     const struct i2c_algorithm *algo; /* the algorithm to access the bus */  
  10.     void *algo_data;  
  11.   
  12.     /* --- administration stuff. */  
  13.     int (*client_register)(struct i2c_client *);  
  14.     int (*client_unregister)(struct i2c_client *);  
  15.   
  16.     /* data fields that are valid for all devices   */  
  17.     u8 level;           /* nesting level for lockdep */  
  18.     struct mutex bus_lock;  
  19.     struct mutex clist_lock;  
  20.   
  21.     int timeout;            /* in jiffies */  
  22.     int retries;  
  23.     struct device dev;      /* the adapter device */  
  24.   
  25.     int nr;  
  26.     struct list_head clients;   /* DEPRECATED */  
  27.     char name[48];  
  28.     struct completion dev_released;  
  29. };  

struct i2c_adapter中还有个const struct i2c_algorithm *algo
将i2c_adapter简称为adp, i2c_algorithm简称为algo
具体讲一下这两个数据结构有什么用:
I2C子系统主要有三部分组成: core, adap, algo
core是i2c子系统的核心层, 将与具体硬件相关的代码交给adap
而adap含有一个algo, algo定义了与具体硬件通讯的代码所以
如果有一个应用程序希望与i2c设备通讯, 将依次通过core, adap, algo, 最终将数据发到总线上

继续看probe初始化过程, ret = s3c24xx_i2c_init(i2c);
[cpp] view plaincopy
  1. static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)  
  2. {  
  3.     unsigned long iicon = S3C2410_IICCON_IRQEN | S3C2410_IICCON_ACKEN;  
  4.     struct s3c2410_platform_i2c *pdata;  
  5.     unsigned int freq;  
  6.   
  7.     /* get the plafrom data */  
  8.     pdata = i2c->dev->platform_data;  
  9.   
  10.     /* inititalise the gpio */  
  11.     if (pdata->cfg_gpio)  
  12.         pdata->cfg_gpio(to_platform_device(i2c->dev));  
  13.   
  14.     /* write slave address */  
  15.     writeb(pdata->slave_addr, i2c->regs + S3C2410_IICADD);  
  16.   
  17.     dev_info(i2c->dev, "slave address 0x%02x\n", pdata->slave_addr);  
  18.   
  19.     writel(iicon, i2c->regs + S3C2410_IICCON);  
  20.   
  21.     /* we need to work out the divisors for the clock... */  
  22.     if (s3c24xx_i2c_clockrate(i2c, &freq) != 0) {  
  23.         writel(0, i2c->regs + S3C2410_IICCON);  
  24.         dev_err(i2c->dev, "cannot meet bus frequency required\n");  
  25.         return -EINVAL;  
  26.     }  
  27.   
  28.     /* todo - check that the i2c lines aren't being dragged anywhere */  
  29.     dev_info(i2c->dev, "bus frequency set to %d KHz\n", freq);  
  30.     dev_dbg(i2c->dev, "S3C2410_IICCON=0x%02lx\n", iicon);  
  31.   
  32.     /* check for s3c2440 i2c controller  */  
  33.     if (s3c24xx_i2c_is2440(i2c)) {  
  34.         dev_dbg(i2c->dev, "S3C2440_IICLC=%08x\n", pdata->sda_delay);  
  35.   
  36.         writel(pdata->sda_delay, i2c->regs + S3C2440_IICLC);  
  37.     }  
  38.   
  39.     return 0;  
  40. }  
主要是初始化硬件寄存器, 没什么好说的, 参考s3c2440手册

继续看probe初始化过程
i2c->adap.nr = pdata->bus_num;
ret = i2c_add_numbered_adapter(&i2c->adap);
[cpp] view plaincopy
  1. int i2c_add_numbered_adapter(struct i2c_adapter *adap)  
  2. {  
  3.     int id;  
  4.     int status;  
  5.   
  6.     if (adap->nr & ~MAX_ID_MASK)  
  7.         return -EINVAL;  
  8.   
  9. retry:  
  10.     if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)  
  11.         return -ENOMEM;  
  12.   
  13.     mutex_lock(&core_lock);  
  14.     /* "above" here means "above or equal to", sigh; 
  15.      * we need the "equal to" result to force the result 
  16.      */  
  17.     status = idr_get_new_above(&i2c_adapter_idr, adap, adap->nr, &id);  
  18.     if (status == 0 && id != adap->nr) {  
  19.         status = -EBUSY;  
  20.         idr_remove(&i2c_adapter_idr, id);  
  21.     }  
  22.     mutex_unlock(&core_lock);  
  23.     if (status == -EAGAIN)  
  24.         goto retry;  
  25.   
  26.     if (status == 0)  
  27.         status = i2c_register_adapter(adap);  
  28.     return status;  
  29. }  
调用了i2c_register_adapter(adap)
[cpp] view plaincopy
  1. static int i2c_register_adapter(struct i2c_adapter *adap)  
  2. {  
  3.     int res = 0, dummy;  
  4.   
  5.     /* Can't register until after driver model init */  
  6.     if (unlikely(WARN_ON(!i2c_bus_type.p)))  
  7.         return -EAGAIN;  
  8.   
  9.     mutex_init(&adap->bus_lock);  
  10.     mutex_init(&adap->clist_lock);  
  11.     INIT_LIST_HEAD(&adap->clients);  
  12.   
  13.     mutex_lock(&core_lock);  
  14.   
  15.     /* Add the adapter to the driver core. 
  16.      * If the parent pointer is not set up, 
  17.      * we add this adapter to the host bus. 
  18.      */  
  19.     if (adap->dev.parent == NULL) {  
  20.         adap->dev.parent = &platform_bus;  
  21.         pr_debug("I2C adapter driver [%s] forgot to specify "  
  22.              "physical device\n", adap->name);  
  23.     }  
  24.     dev_set_name(&adap->dev, "i2c-%d", adap->nr);  
  25.     adap->dev.release = &i2c_adapter_dev_release;  
  26.     adap->dev.class = &i2c_adapter_class;  
  27.     res = device_register(&adap->dev);  
  28.     if (res)  
  29.         goto out_list;  
  30.   
  31.     dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);  
  32.   
  33.     /* create pre-declared device nodes for new-style drivers */  
  34.     if (adap->nr < __i2c_first_dynamic_bus_num)  
  35.         i2c_scan_static_board_info(adap);  
  36.   
  37.     /* Notify drivers */  
  38.     dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap,  
  39.                  i2c_do_add_adapter);  
  40.   
  41. out_unlock:  
  42.     mutex_unlock(&core_lock);  
  43.     return res;  
  44.   
  45. out_list:  
  46.     idr_remove(&i2c_adapter_idr, adap->nr);  
  47.     goto out_unlock;  
  48. }  
其中, 最关键的是i2c_scan_static_board_info(adap);
[cpp] view plaincopy
  1. static void i2c_scan_static_board_info(struct i2c_adapter *adapter)  
  2. {  
  3.     struct i2c_devinfo  *devinfo;  
  4.   
  5.     mutex_lock(&__i2c_board_lock);  
  6.     list_for_each_entry(devinfo, &__i2c_board_list, list) {  
  7.         if (devinfo->busnum == adapter->nr  
  8.                 && !i2c_new_device(adapter,  
  9.                         &devinfo->board_info))  
  10.             printk(KERN_ERR "i2c-core: can't create i2c%d-%04x\n",  
  11.                 i2c_adapter_id(adapter),  
  12.                 devinfo->board_info.addr);  
  13.     }  
  14.     mutex_unlock(&__i2c_board_lock);  
  15. }  
此函数扫描所有预先定义好的设备(挂在总线上的设备), 然后添加设备(i2c_new_device)

来看下i2c的从机设备是如何添加的:
[cpp] view plaincopy
  1. struct i2c_client *  
  2. i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)  
  3. {  
  4.     struct i2c_client   *client;  
  5.     int         status;  
  6.   
  7.     client = kzalloc(sizeof *client, GFP_KERNEL);  
  8.     if (!client)  
  9.         return NULL;  
  10.   
  11.     client->adapter = adap;  
  12.   
  13.     client->dev.platform_data = info->platform_data;  
  14.   
  15.     if (info->archdata)  
  16.         client->dev.archdata = *info->archdata;  
  17.   
  18.     client->flags = info->flags;  
  19.     client->addr = info->addr;  
  20.     client->irq = info->irq;  
  21.   
  22.     strlcpy(client->name, info->type, sizeof(client->name));  
  23.   
  24.     /* a new style driver may be bound to this device when we 
  25.      * return from this function, or any later moment (e.g. maybe 
  26.      * hotplugging will load the driver module).  and the device 
  27.      * refcount model is the standard driver model one. 
  28.      */  
  29.     status = i2c_attach_client(client);  
  30.     if (status < 0) {  
  31.         kfree(client);  
  32.         client = NULL;  
  33.     }  
  34.     return client;  
  35. }  
可以看出, i2c的从机设备被定义为一个i2c_client结构, addr为从机地址, irq为中断号
接着调用i2c_attach_client
[cpp] view plaincopy
  1. int i2c_attach_client(struct i2c_client *client)  
  2. {  
  3.     struct i2c_adapter *adapter = client->adapter;  
  4.     int res;  
  5.   
  6.     /* Check for address business */  
  7.     res = i2c_check_addr(adapter, client->addr);  
  8.     if (res)  
  9.         return res;  
  10.   
  11.     client->dev.parent = &client->adapter->dev;  
  12.     client->dev.bus = &i2c_bus_type;  
  13.   
  14.     if (client->driver)  
  15.         client->dev.driver = &client->driver->driver;  
  16.   
  17.     if (client->driver && !is_newstyle_driver(client->driver)) {  
  18.         client->dev.release = i2c_client_release;  
  19.         client->dev.uevent_suppress = 1;  
  20.     } else  
  21.         client->dev.release = i2c_client_dev_release;  
  22.   
  23.     dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adapter),  
  24.              client->addr);  
  25.     res = device_register(&client->dev);  
  26.     if (res)  
  27.         goto out_err;  
  28.   
  29.     mutex_lock(&adapter->clist_lock);  
  30.     list_add_tail(&client->list, &adapter->clients);  
  31.     mutex_unlock(&adapter->clist_lock);  
  32.   
  33.     dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n",  
  34.         client->name, dev_name(&client->dev));  
  35.   
  36.     if (adapter->client_register)  {  
  37.         if (adapter->client_register(client)) {  
  38.             dev_dbg(&adapter->dev, "client_register "  
  39.                 "failed for client [%s] at 0x%02x\n",  
  40.                 client->name, client->addr);  
  41.         }  
  42.     }  
  43.   
  44.     return 0;  
  45.   
  46. out_err:  
  47.     dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x "  
  48.         "(%d)\n", client->name, client->addr, res);  
  49.     return res;  
  50. }  
i2c_attach_client做了添加设备(device_register)和将此client加入到其所在adp的clients链表中

自此, 总线驱动就添加完了, 总结一下, 具体经过以下步骤:
添加总线驱动 -> probe -> 创建适配器结构 -> 初始化适配器硬件 -> 扫描从机设备并添加

再来看下algo
在probe中, 有i2c->adap.algo = &s3c24xx_i2c_algorithm;
[cpp] view plaincopy
  1. static const struct i2c_algorithm s3c24xx_i2c_algorithm = {  
  2.     .master_xfer        = s3c24xx_i2c_xfer,  
  3.     .functionality      = s3c24xx_i2c_func,  
  4. };  
其中, master_xfer即为与具体硬件通讯的收发数据函数
[cpp] view plaincopy
  1. static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,  
  2.             struct i2c_msg *msgs, int num)  
  3. {  
  4.     struct s3c24xx_i2c *i2c = (struct s3c24xx_i2c *)adap->algo_data;  
  5.     int retry;  
  6.     int ret;  
  7.   
  8.     for (retry = 0; retry < adap->retries; retry++) {  
  9.   
  10.         ret = s3c24xx_i2c_doxfer(i2c, msgs, num);  
  11.   
  12.         if (ret != -EAGAIN)  
  13.             return ret;  
  14.   
  15.         dev_dbg(i2c->dev, "Retrying transmission (%d)\n", retry);  
  16.   
  17.         udelay(100);  
  18.     }  
  19.   
  20.     return -EREMOTEIO;  
  21. }  
参数i2c_msg封装了buf以及flags, 用以指定读或者写或者其他操作:
[cpp] view plaincopy
  1. struct i2c_msg {  
  2.     __u16 addr; /* slave address            */  
  3.     __u16 flags;  
  4. #define I2C_M_TEN       0x0010  /* this is a ten bit chip address */  
  5. #define I2C_M_RD        0x0001  /* read data, from slave to master */  
  6. #define I2C_M_NOSTART       0x4000  /* if I2C_FUNC_PROTOCOL_MANGLING */  
  7. #define I2C_M_REV_DIR_ADDR  0x2000  /* if I2C_FUNC_PROTOCOL_MANGLING */  
  8. #define I2C_M_IGNORE_NAK    0x1000  /* if I2C_FUNC_PROTOCOL_MANGLING */  
  9. #define I2C_M_NO_RD_ACK     0x0800  /* if I2C_FUNC_PROTOCOL_MANGLING */  
  10. #define I2C_M_RECV_LEN      0x0400  /* length will be first received byte */  
  11.     __u16 len;      /* msg length               */  
  12.     __u8 *buf;      /* pointer to msg data          */  
  13. };  

3. 从机设备
来看下如何静态添加一个设备
在arch/arm/mach-s3c2440/mach-anubis.c中, 可以看到一个例子:

[cpp] view plaincopy
  1. /* I2C devices. */  
  2. static struct i2c_board_info anubis_i2c_devs[] __initdata = {  
  3.     {  
  4.         I2C_BOARD_INFO("tps65011", 0x48),  
  5.         .irq    = IRQ_EINT20,  
  6.     }  
  7. };  
tps65011是设备名称, 0x48为从机地址
还有个中断, 连接在2440的EINT20上
可以查一下这个芯片, 是个锂电的电源管理芯片
那个中断用于当电量少于10%时报警

4. 从机设备驱动

来看一个I2C EEPROM设备驱动: /drivers/i2c/chips/ ds1682.c

[cpp] view plaincopy
  1. static struct i2c_driver ds1682_driver = {  
  2.     .driver = {  
  3.         .name = "ds1682",  
  4.     },  
  5.     .probe = ds1682_probe,  
  6.     .remove = ds1682_remove,  
  7.     .id_table = ds1682_id,  
  8. };  
  9.   
  10. static int __init ds1682_init(void)  
  11. {  
  12.     return i2c_add_driver(&ds1682_driver);  
  13. }  
[cpp] view plaincopy
  1. i2c_add_driver会遍历I2C总线上的设备, 匹配设备与驱动, 并调用probe  
  2. <pre name="code" class="cpp">/* 
  3.  * Called when a ds1682 device is matched with this driver 
  4.  */  
  5. static int ds1682_probe(struct i2c_client *client,  
  6.             const struct i2c_device_id *id)  
  7. {  
  8.     int rc;  
  9.   
  10.     if (!i2c_check_functionality(client->adapter,  
  11.                      I2C_FUNC_SMBUS_I2C_BLOCK)) {  
  12.         dev_err(&client->dev, "i2c bus does not support the ds1682\n");  
  13.         rc = -ENODEV;  
  14.         goto exit;  
  15.     }  
  16.   
  17.     rc = sysfs_create_group(&client->dev.kobj, &ds1682_group);  
  18.     if (rc)  
  19.         goto exit;  
  20.   
  21.     rc = sysfs_create_bin_file(&client->dev.kobj, &ds1682_eeprom_attr);  
  22.     if (rc)  
  23.         goto exit_bin_attr;  
  24.   
  25.     return 0;  
  26.   
  27.  exit_bin_attr:  
  28.     sysfs_remove_group(&client->dev.kobj, &ds1682_group);  
  29.  exit:  
  30.     return rc;  
  31. }</pre>由于EEPROM比较简单, 不需要什么硬件初始化所以我们看到, 这个probe没有做硬件初始化probe创建了在sysfs中的自己的设备目录下创建了一些属性: ds1682_group和ds1682_eeprom_attr<br>  
  32. <pre name="code" class="cpp">static SENSOR_DEVICE_ATTR_2(elapsed_time, S_IRUGO | S_IWUSR, ds1682_show,  
  33.                 ds1682_store, 4, DS1682_REG_ELAPSED);  
  34. static SENSOR_DEVICE_ATTR_2(alarm_time, S_IRUGO | S_IWUSR, ds1682_show,  
  35.                 ds1682_store, 4, DS1682_REG_ALARM);  
  36. static SENSOR_DEVICE_ATTR_2(event_count, S_IRUGO | S_IWUSR, ds1682_show,  
  37.                 ds1682_store, 2, DS1682_REG_EVT_CNTR);  
  38.   
  39. static const struct attribute_group ds1682_group = {  
  40.     .attrs = (struct attribute *[]) {  
  41.         &sensor_dev_attr_elapsed_time.dev_attr.attr,  
  42.         &sensor_dev_attr_alarm_time.dev_attr.attr,  
  43.         &sensor_dev_attr_event_count.dev_attr.attr,  
  44.         NULL,  
  45.     },  
  46. };  
  47.   
  48. static struct bin_attribute ds1682_eeprom_attr = {  
  49.     .attr = {  
  50.         .name = "eeprom",  
  51.         .mode = S_IRUGO | S_IWUSR,  
  52.     },  
  53.     .size = DS1682_EEPROM_SIZE,  
  54.     .read = ds1682_eeprom_read,  
  55.     .write = ds1682_eeprom_write,  
  56. };</pre>根据这些属性的定义, 程序在ds1682的设备目录下建立了以下文件:<p></p>  
  57. <pre></pre>  
  58. <p></p>  
  59. <blockquote style="margin:0 0 0 40px; border:none; padding:0px">  
  60. <p></p><pre name="code" class="cpp" style="background-color: rgb(255, 255, 255); "><pre name="code" class="cpp" style="background-color: rgb(255, 255, 255); ">elapsed_time, alarm_time, event_count, eeprom  
  61. </pre><p></p>  
  62. <pre></pre>  
  63. <p></p>  
  64. </pre></blockquote>  
  65. 其中eeprom文件为一个二进制文件, 直接将整片存储空间映射到该文件, 方便用户空间对其读写<br>  
  66. <p><br>  
  67. 再来看下前三个属性的读写方法: ds1682_show, ds1682_store<br>  
  68. </p><pre name="code" class="cpp">/* 
  69.  * Generic counter attributes 
  70.  */  
  71. static ssize_t ds1682_show(struct device *dev, struct device_attribute *attr,  
  72.                char *buf)  
  73. {  
  74.     struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);  
  75.     struct i2c_client *client = to_i2c_client(dev);  
  76.     __le32 val = 0;  
  77.     int rc;  
  78.   
  79.     dev_dbg(dev, "ds1682_show() called on %s\n", attr->attr.name);  
  80.   
  81.     /* Read the register */  
  82.     rc = i2c_smbus_read_i2c_block_data(client, sattr->index, sattr->nr,  
  83.                        (u8 *) & val);  
  84.     if (rc < 0)  
  85.         return -EIO;  
  86.   
  87.     /* Special case: the 32 bit regs are time values with 1/4s 
  88.      * resolution, scale them up to milliseconds */  
  89.     if (sattr->nr == 4)  
  90.         return sprintf(buf, "%llu\n",  
  91.             ((unsigned long long)le32_to_cpu(val)) * 250);  
  92.   
  93.     /* Format the output string and return # of bytes */  
  94.     return sprintf(buf, "%li\n", (long)le32_to_cpu(val));  
  95. }  
  96.   
  97. static ssize_t ds1682_store(struct device *dev, struct device_attribute *attr,  
  98.                 const char *buf, size_t count)  
  99. {  
  100.     struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);  
  101.     struct i2c_client *client = to_i2c_client(dev);  
  102.     char *endp;  
  103.     u64 val;  
  104.     __le32 val_le;  
  105.     int rc;  
  106.   
  107.     dev_dbg(dev, "ds1682_store() called on %s\n", attr->attr.name);  
  108.   
  109.     /* Decode input */  
  110.     val = simple_strtoull(buf, &endp, 0);  
  111.     if (buf == endp) {  
  112.         dev_dbg(dev, "input string not a number\n");  
  113.         return -EINVAL;  
  114.     }  
  115.   
  116.     /* Special case: the 32 bit regs are time values with 1/4s 
  117.      * resolution, scale input down to quarter-seconds */  
  118.     if (sattr->nr == 4)  
  119.         do_div(val, 250);  
  120.   
  121.     /* write out the value */  
  122.     val_le = cpu_to_le32(val);  
  123.     rc = i2c_smbus_write_i2c_block_data(client, sattr->index, sattr->nr,  
  124.                         (u8 *) & val_le);  
  125.     if (rc < 0) {  
  126.         dev_err(dev, "register write failed; reg=0x%x, size=%i\n",  
  127.             sattr->index, sattr->nr);  
  128.         return -EIO;  
  129.     }  
  130.   
  131.     return count;  
  132. }</pre>show函数中根据属性的编号, 读取ds1682的寄存器, 获取其相应属性:<br>  
  133. <p></p>  
  134. <blockquote style="margin:0 0 0 40px; border:none; padding:0px">  
  135. <p>rc = i2c_smbus_read_i2c_block_data(client, sattr->index, sattr->nr, (u8 *) & val);</p>  
  136. </blockquote>  
  137. <p>读写是不很方便呢, 这里show只调用了i2c_smbus_read_i2c_block_data, 并告诉它地址和长度即可<br>  
  138. 而i2c_smbus_read_i2c_block_data是i2c_core提供的功能<br>  
  139. 这里可以看到这样抽象的好处了, 编写i2c设备驱动的人, 不需要关心适配器是什么或者怎么实现的<br>  
  140. <br>  
  141. store函数也类似<br>  
  142. <br>  
  143. 再来看下eeprom属性的读写方法:<br>  
  144. </p><pre name="code" class="cpp">/* 
  145.  * User data attribute 
  146.  */  
  147. static ssize_t ds1682_eeprom_read(struct kobject *kobj, struct bin_attribute *attr,  
  148.                   char *buf, loff_t off, size_t count)  
  149. {  
  150.     struct i2c_client *client = kobj_to_i2c_client(kobj);  
  151.     int rc;  
  152.   
  153.     dev_dbg(&client->dev, "ds1682_eeprom_read(p=%p, off=%lli, c=%zi)\n",  
  154.         buf, off, count);  
  155.   
  156.     if (off >= DS1682_EEPROM_SIZE)  
  157.         return 0;  
  158.   
  159.     if (off + count > DS1682_EEPROM_SIZE)  
  160.         count = DS1682_EEPROM_SIZE - off;  
  161.   
  162.     rc = i2c_smbus_read_i2c_block_data(client, DS1682_REG_EEPROM + off,  
  163.                        count, buf);  
  164.     if (rc < 0)  
  165.         return -EIO;  
  166.   
  167.     return count;  
  168. }  
  169.   
  170. static ssize_t ds1682_eeprom_write(struct kobject *kobj, struct bin_attribute *attr,  
  171.                    char *buf, loff_t off, size_t count)  
  172. {  
  173.     struct i2c_client *client = kobj_to_i2c_client(kobj);  
  174.   
  175.     dev_dbg(&client->dev, "ds1682_eeprom_write(p=%p, off=%lli, c=%zi)\n",  
  176.         buf, off, count);  
  177.   
  178.     if (off >= DS1682_EEPROM_SIZE)  
  179.         return -ENOSPC;  
  180.   
  181.     if (off + count > DS1682_EEPROM_SIZE)  
  182.         count = DS1682_EEPROM_SIZE - off;  
  183.   
  184.     /* Write out to the device */  
  185.     if (i2c_smbus_write_i2c_block_data(client, DS1682_REG_EEPROM + off,  
  186.                        count, buf) < 0)  
  187.         return -EIO;  
  188.   
  189.     return count;  
  190. }</pre>这个就更简单了, 像不像普通字符设备的read和write<br>  
  191. <br>  
  192. 自此, 除了I2C Core的代码没有分析, 其他的都分析完了<br>  
  193. <p></p>  
  194.       
  195.         <div style="padding-top:20px">           
  196.             <p style="font-size:12px;">版权声明:本文为博主原创文章,未经博主允许不得转载。</p>  
  197.         </div>  
0 0
原创粉丝点击