IIC的框架結構和SPI是類似的,它們都擁有總線驅動層(IIC主控制器驅動層),核心層和從設備驅動層。本節主要介紹IIC主控制器的注冊以及從設備的注冊過程。首先要介紹描述IIC主控制器的結構struct i2c_adapter和描述IIC從設備的結構struct i2c_client
struct i2c_adapter的定義如下:
- struct i2c_adapter {
- struct module *owner; /*所屬模塊*/
- unsigned int id; /*algorithm的類型*/
- unsigned int class; /* classes to allow probing for */
- const struct i2c_algorithm *algo; /*總線通信方法*/
- void *algo_data; /*algorithm的數據*/
-
- /* --- administration stuff. */
- /*從設備注冊時調用*/
- int (*client_register)(struct i2c_client *) __deprecated;
- /*從設備注銷時調用*/
- int (*client_unregister)(struct i2c_client *) __deprecated;
-
- /* data fields that are valid for all devices */
- u8 level; /* nesting level for lockdep */
- struct mutex bus_lock;
- struct mutex clist_lock;
-
- int timeout; /* in jiffies */
- int retries; /*重試次數*/
- struct device dev;
-
- int nr; /*主控制器的編號*/
- struct list_head clients; /*用於鏈接從設備的鏈表頭*/
- char name[48]; /*控制器名*/
- struct completion dev_released;/*用於同步的完成量*/
- };
algo中定義了主控制器的的數據傳輸方式,client是一個鏈表頭,由於可能有多個從設備掛接在該總線上,因此client用於鏈接該控制器下的從設備
和SPI控制器一樣,IIC控制器也是平台資源,因此以platform的方式注冊進內核
- static int __init i2c_adap_s3c_init(void)
- {
- int ret;
-
- ret = platform_driver_register(&s3c2410_i2c_driver);
- if (ret == 0) {
- ret = platform_driver_register(&s3c2440_i2c_driver);
- if (ret)
- platform_driver_unregister(&s3c2410_i2c_driver);
- }
-
- return ret;
- }
s3c2410_i2c_driver和s3c2440_i2c_driver的定義除了name字段不一樣外,其他部分都一樣
- static struct platform_driver s3c2410_i2c_driver = {
- .probe = s3c24xx_i2c_probe,
- .remove = s3c24xx_i2c_remove,
- .suspend_late = s3c24xx_i2c_suspend_late,
- .resume = s3c24xx_i2c_resume,
- .driver = {
- .owner = THIS_MODULE,
- .name = "s3c2410-i2c",
- },
- };
-
- static struct platform_driver s3c2440_i2c_driver = {
- .probe = s3c24xx_i2c_probe,
- .remove = s3c24xx_i2c_remove,
- .suspend_late = s3c24xx_i2c_suspend_late,
- .resume = s3c24xx_i2c_resume,
- .driver = {
- .owner = THIS_MODULE,
- .name = "s3c2440-i2c",
- },
- };
當和platform_device匹配成功後,便調用s3c24xx_i2c_probe()函數
- static int s3c24xx_i2c_probe(struct platform_device *pdev)
- {
- struct s3c24xx_i2c *i2c;
- struct s3c2410_platform_i2c *pdata;
- struct resource *res;
- int ret;
-
- pdata = pdev->dev.platform_data;//獲取平台IIC數據
- if (!pdata) {
- dev_err(&pdev->dev, "no platform data\n");
- return -EINVAL;
- }
-
- /*創建一個struct s3c24xx_i2c*/
- i2c = kzalloc(sizeof(struct s3c24xx_i2c), GFP_KERNEL);
- if (!i2c) {
- dev_err(&pdev->dev, "no memory for state\n");
- return -ENOMEM;
- }
-
- /*設置IIC總線的相關項*/
- strlcpy(i2c->adap.name, "s3c2410-i2c", sizeof(i2c->adap.name));
- i2c->adap.owner = THIS_MODULE;
- i2c->adap.algo = &s3c24xx_i2c_algorithm;
- i2c->adap.retries = 2;
- i2c->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
- i2c->tx_setup = 50;
-
- spin_lock_init(&i2c->lock);
- init_waitqueue_head(&i2c->wait);//初始化等待隊列
-
- /* find the clock and enable it */
-
- i2c->dev = &pdev->dev;
- i2c->clk = clk_get(&pdev->dev, "i2c");
- if (IS_ERR(i2c->clk)) {
- dev_err(&pdev->dev, "cannot get clock\n");
- ret = -ENOENT;
- goto err_noclk;
- }
-
- dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk);
-
- clk_enable(i2c->clk);
-
- /* map the registers */
-
- /*獲取IIC的資源*/
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res == NULL) {
- dev_err(&pdev->dev, "cannot find IO resource\n");
- ret = -ENOENT;
- goto err_clk;
- }
-
- /*為IIC的寄存器申請內存空間*/
- i2c->ioarea = request_mem_region(res->start, (res->end-res->start)+1,
- pdev->name);
-
- if (i2c->ioarea == NULL) {
- dev_err(&pdev->dev, "cannot request IO\n");
- ret = -ENXIO;
- goto err_clk;
- }
-
- /*重映射IIC的寄存器*/
- i2c->regs = ioremap(res->start, (res->end-res->start)+1);
-
- if (i2c->regs == NULL) {
- dev_err(&pdev->dev, "cannot map IO\n");
- ret = -ENXIO;
- goto err_ioarea;
- }
-
- dev_dbg(&pdev->dev, "registers %p (%p, %p)\n",
- i2c->regs, i2c->ioarea, res);
-
- /* setup info block for the i2c core */
-
- i2c->adap.algo_data = i2c;
- i2c->adap.dev.parent = &pdev->dev;
-
- /* initialise the i2c controller */
-
- /*初始化s3c24xx的IIC控制器*/
- ret = s3c24xx_i2c_init(i2c);
- if (ret != 0)
- goto err_iomap;
-
- /* find the IRQ for this unit (note, this relies on the init call to
- * ensure no current IRQs pending
- */
-
- i2c->irq = ret = platform_get_irq(pdev, 0);
- if (ret <= 0) {
- dev_err(&pdev->dev, "cannot find IRQ\n");
- goto err_iomap;
- }
-
- /*注冊IIC中斷*/
- ret = request_irq(i2c->irq, s3c24xx_i2c_irq, IRQF_DISABLED,
- dev_name(&pdev->dev), i2c);
-
- if (ret != 0) {
- dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);
- goto err_iomap;
- }
-
- ret = s3c24xx_i2c_register_cpufreq(i2c);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to register cpufreq notifier\n");
- goto err_irq;
- }
-
- /* Note, previous versions of the driver used i2c_add_adapter()
- * to add the bus at any number. We now pass the bus number via
- * the platform data, so if unset it will now default to always
- * being bus 0.
- */
-
- i2c->adap.nr = pdata->bus_num;
-
- /*通過IIC 核心層函數注冊IIC控制器*/
- ret = i2c_add_numbered_adapter(&i2c->adap);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to add bus to i2c core\n");
- goto err_cpufreq;
- }
-
- platform_set_drvdata(pdev, i2c);
-
- dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev));
- return 0;
-
- err_cpufreq:
- s3c24xx_i2c_deregister_cpufreq(i2c);
-
- err_irq:
- free_irq(i2c->irq, i2c);
-
- err_iomap:
- iounmap(i2c->regs);
-
- err_ioarea:
- release_resource(i2c->ioarea);
- kfree(i2c->ioarea);
-
- err_clk:
- clk_disable(i2c->clk);
- clk_put(i2c->clk);
-
- err_noclk:
- kfree(i2c);
- return ret;
- }
i2c_add_numbered_adapter()會調用i2c_register_adapter()來完成實際的注冊工作
- static int i2c_register_adapter(struct i2c_adapter *adap)
- {
- int res = 0, dummy;
-
- /* Can't register until after driver model init */
- if (unlikely(WARN_ON(!i2c_bus_type.p)))
- return -EAGAIN;
-
- mutex_init(&adap->bus_lock);
- mutex_init(&adap->clist_lock);
- INIT_LIST_HEAD(&adap->clients);//初始化主控制器的從設備鏈表
-
- mutex_lock(&core_lock);
-
- /* Add the adapter to the driver core.
- * If the parent pointer is not set up,
- * we add this adapter to the host bus.
- */
- if (adap->dev.parent == NULL) {
- adap->dev.parent = &platform_bus;
- pr_debug("I2C adapter driver [%s] forgot to specify "
- "physical device\n", adap->name);
- }
-
- /* Set default timeout to 1 second if not already set */
- if (adap->timeout == 0)
- adap->timeout = HZ;
-
- dev_set_name(&adap->dev, "i2c-%d", adap->nr);
- adap->dev.release = &i2c_adapter_dev_release;
- adap->dev.class = &i2c_adapter_class;//所屬類為i2c_adaoter_class
- res = device_register(&adap->dev);//注冊設備
- if (res)
- goto out_list;
-
- dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
-
- /* create pre-declared device nodes for new-style drivers */
- /*浏覽板級信息注冊依附在該控制器下的從設備*/
- if (adap->nr < __i2c_first_dynamic_bus_num)
- i2c_scan_static_board_info(adap);
-
- /* Notify drivers */
- dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap,
- i2c_do_add_adapter);
-
- out_unlock:
- mutex_unlock(&core_lock);
- return res;
-
- out_list:
- idr_remove(&i2c_adapter_idr, adap->nr);
- goto out_unlock;
- }
- static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
- {
- struct i2c_devinfo *devinfo;
-
- mutex_lock(&__i2c_board_lock);
- /*遍歷IIC板級信息列表*/
- list_for_each_entry(devinfo, &__i2c_board_list, list) {
- /*如果從設備所屬的總線號等於IIC控制器的編號則創建新設備*/
- if (devinfo->busnum == adapter->nr
- && !i2c_new_device(adapter,
- &devinfo->board_info))
- dev_err(&adapter->dev,
- "Can't create device at 0x%02x\n",
- devinfo->board_info.addr);
- }
- mutex_unlock(&__i2c_board_lock);
- }
- struct i2c_client *
- i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
- {
- struct i2c_client *client;
- int status;
-
- client = kzalloc(sizeof *client, GFP_KERNEL);
- if (!client)
- return NULL;
-
- client->adapter = adap;//設定從設備所屬的IIC控制器
-
- client->dev.platform_data = info->platform_data;
-
- if (info->archdata)
- client->dev.archdata = *info->archdata;
-
- client->flags = info->flags;
- client->addr = info->addr;//從設備的地址
- client->irq = info->irq;
-
- strlcpy(client->name, info->type, sizeof(client->name));
-
- /* a new style driver may be bound to this device when we
- * return from this function, or any later moment (e.g. maybe
- * hotplugging will load the driver module). and the device
- * refcount model is the standard driver model one.
- */
- status = i2c_attach_client(client);
- if (status < 0) {
- kfree(client);
- client = NULL;
- }
- return client;
- }
- int i2c_attach_client(struct i2c_client *client)
- {
- struct i2c_adapter *adapter = client->adapter;
- int res;
-
- /* Check for address business */
- /*檢測該從設備的地址是否和已有從設備的地址相同*/
- res = i2c_check_addr(adapter, client->addr);
- if (res)
- return res;
-
- client->dev.parent = &client->adapter->dev;
- client->dev.bus = &i2c_bus_type;//設置從設備所屬的總線類型
-
- if (client->driver)
- client->dev.driver = &client->driver->driver;
-
- if (client->driver && !is_newstyle_driver(client->driver)) {
- client->dev.release = i2c_client_release;
- dev_set_uevent_suppress(&client->dev, 1);
- } else
- client->dev.release = i2c_client_dev_release;
-
- dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adapter),
- client->addr);//名字的構成為控制器號+地址
- res = device_register(&client->dev);//注冊設備
- if (res)
- goto out_err;
-
- mutex_lock(&adapter->clist_lock);
- list_add_tail(&client->list, &adapter->clients);//將從設備鏈入IIC控制器
- mutex_unlock(&adapter->clist_lock);
-
- dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n",
- client->name, dev_name(&client->dev));
-
- /*如果adapter中定義了從設備注冊函數,則進一步調用該函數進行注冊,s3c24xx中沒定義該函數*/
- if (adapter->client_register) {
- if (adapter->client_register(client)) {
- dev_dbg(&adapter->dev, "client_register "
- "failed for client [%s] at 0x%02x\n",
- client->name, client->addr);
- }
- }
-
- return 0;
-
- out_err:
- dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x "
- "(%d)\n", client->name, client->addr, res);
- return res;
- }