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; }