I2C驅動框架分析

1. I2C驅動框架

I2C設備驅動的層次分爲設備層、總線層。理解這兩個層次的重點是理解4個數據結構,分別爲i2c_driver,i2c_client、i2c_algorithm,i2c_adapter。

i2c_driver和i2c_client是設備層,i2c_algorithm和i2c_adapter是總線層。

  1. struct i2c_adapter {  
  2.     struct module *owner;  
  3.     unsigned int class;       /* classes to allow probing for */  
  4.     const struct i2c_algorithm *algo; /* the algorithm to access the bus */  
  5.     void *algo_data;  
  6.   
  7.     /* data fields that are valid for all devices   */  
  8.     struct rt_mutex bus_lock;  
  9.   
  10.     int timeout;            /* in jiffies */  
  11.     int retries;  
  12.     struct device dev;      /* the adapter device */    //內嵌的device結構  
  13.   
  14.     int nr;  
  15.     char name[48];  
  16.     struct completion dev_released;  
  17.   
  18.     struct mutex userspace_clients_lock;  
  19.     struct list_head userspace_clients;     //此總線上的設備鏈表  
  20. };  
  21. struct i2c_driver {  
  22.     unsigned int class;  
  23.   
  24.     /* Notifies the driver that a new bus has appeared or is about to be 
  25.      * removed. You should avoid using this, it will be removed in a 
  26.      * near future. 
  27.      */  
  28.     int (*attach_adapter)(struct i2c_adapter *) __deprecated;  
  29.     int (*detach_adapter)(struct i2c_adapter *) __deprecated;  
  30.   
  31.     /* Standard driver model interfaces */  
  32.     int (*probe)(struct i2c_client *, const struct i2c_device_id *);  
  33.     int (*remove)(struct i2c_client *);  
  34.   
  35.     /* driver model interfaces that don't relate to enumeration  */  
  36.     void (*shutdown)(struct i2c_client *);  
  37.     int (*suspend)(struct i2c_client *, pm_message_t mesg);  
  38.     int (*resume)(struct i2c_client *);  
  39.   
  40.     /* Alert callback, for example for the SMBus alert protocol. 
  41.      * The format and meaning of the data value depends on the protocol. 
  42.      * For the SMBus alert protocol, there is a single bit of data passed 
  43.      * as the alert response's low bit ("event flag"). 
  44.      */  
  45.     void (*alert)(struct i2c_client *, unsigned int data);  
  46.   
  47.     /* a ioctl like command that can be used to perform specific functions 
  48.      * with the device. 
  49.      */  
  50.     int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);  
  51.   
  52.     struct device_driver driver;  
  53.     const struct i2c_device_id *id_table;  
  54.   
  55.     /* Device detection callback for automatic device creation */  
  56.     int (*detect)(struct i2c_client *, struct i2c_board_info *);  
  57.     const unsigned short *address_list;  
  58.     struct list_head clients;  
  59. };  
  60. struct i2c_client {  
  61.     unsigned short flags;       /* div., see below      */  
  62.     unsigned short addr;        /* chip address - NOTE: 7bit    */  
  63.                     /* addresses are stored in the  */  
  64.                     /* _LOWER_ 7 bits       */  
  65.     char name[I2C_NAME_SIZE];  
  66.     struct i2c_adapter *adapter;    /* the adapter we sit on    */         //依附的適配器  
  67.     struct i2c_driver *driver;  /* and our access routines  */    //設備的驅動  
  68.     struct device dev;      /* the device structure     */<     //內嵌的device結構  
  69.     int irq;            /* irq issued by device     */  
  70.     struct list_head detected;                                                 //已經被發現的設備鏈表  
  71. };  
struct i2c_adapter {
	struct module *owner;
	unsigned int class;		  /* classes to allow probing for */
	const struct i2c_algorithm *algo; /* the algorithm to access the bus */
	void *algo_data;

	/* data fields that are valid for all devices	*/
	struct rt_mutex bus_lock;

	int timeout;			/* in jiffies */
	int retries;
	struct device dev;		/* the adapter device */	//內嵌的device結構

	int nr;
	char name[48];
	struct completion dev_released;

	struct mutex userspace_clients_lock;
	struct list_head userspace_clients;		//此總線上的設備鏈表
};
struct i2c_driver {
	unsigned int class;

	/* Notifies the driver that a new bus has appeared or is about to be
	 * removed. You should avoid using this, it will be removed in a
	 * near future.
	 */
	int (*attach_adapter)(struct i2c_adapter *) __deprecated;
	int (*detach_adapter)(struct i2c_adapter *) __deprecated;

	/* Standard driver model interfaces */
	int (*probe)(struct i2c_client *, const struct i2c_device_id *);
	int (*remove)(struct i2c_client *);

	/* driver model interfaces that don't relate to enumeration  */
	void (*shutdown)(struct i2c_client *);
	int (*suspend)(struct i2c_client *, pm_message_t mesg);
	int (*resume)(struct i2c_client *);

	/* Alert callback, for example for the SMBus alert protocol.
	 * The format and meaning of the data value depends on the protocol.
	 * For the SMBus alert protocol, there is a single bit of data passed
	 * as the alert response's low bit ("event flag").
	 */
	void (*alert)(struct i2c_client *, unsigned int data);

	/* a ioctl like command that can be used to perform specific functions
	 * with the device.
	 */
	int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);

	struct device_driver driver;
	const struct i2c_device_id *id_table;

	/* Device detection callback for automatic device creation */
	int (*detect)(struct i2c_client *, struct i2c_board_info *);
	const unsigned short *address_list;
	struct list_head clients;
};
struct i2c_client {
	unsigned short flags;		/* div., see below		*/
	unsigned short addr;		/* chip address - NOTE: 7bit	*/
					/* addresses are stored in the	*/
					/* _LOWER_ 7 bits		*/
	char name[I2C_NAME_SIZE];
	struct i2c_adapter *adapter;	/* the adapter we sit on	*/         //依附的適配器
	struct i2c_driver *driver;	/* and our access routines	*/	  //設備的驅動
	struct device dev;		/* the device structure		*/<	   //內嵌的device結構
	int irq;			/* irq issued by device		*/
	struct list_head detected;                                                 //已經被發現的設備鏈表
};


2. 設備側驅動的註冊

  1. int i2c_register_driver(struct module *owner, struct i2c_driver *driver)  
  2. {  
  3.     int res;  
  4.   
  5.     /* Can't register until after driver model init */  
  6.     if (unlikely(WARN_ON(!i2c_bus_type.p)))  
  7.         return -EAGAIN;  
  8.   
  9.     /* add the driver to the list of i2c drivers in the driver core */  
  10.     driver->driver.owner = owner;  
  11.     driver->driver.bus = &i2c_bus_type;    //i2c_driver的總線類型爲i2c  
  12.   
  13.     /* When registration returns, the driver core 
  14.      * will have called probe() for all matching-but-unbound devices. 
  15.      */  
  16.     res = driver_register(&driver->driver);      //註冊i2c_driver內嵌的driver  
  17.     if (res)  
  18.         return res;  
  19.   
  20.     /* Drivers should switch to dev_pm_ops instead. */  
  21.     if (driver->suspend)  
  22.         pr_warn("i2c-core: driver [%s] using legacy suspend method\n",  
  23.             driver->driver.name);  
  24.     if (driver->resume)  
  25.         pr_warn("i2c-core: driver [%s] using legacy resume method\n",  
  26.             driver->driver.name);  
  27.   
  28.     pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);  
  29.     INIT_LIST_HEAD(&driver->clients);  
  30.     /* Walk the adapters that are already present */  
  31.     res = i2c_for_each_dev(driver, __process_new_driver);   //掃描i2c總線掛載的i2c_client設備和i2c_adapte設備,不過只有adapter設備才能執行__process_new_driver  
int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
{
	int res;

	/* Can't register until after driver model init */
	if (unlikely(WARN_ON(!i2c_bus_type.p)))
		return -EAGAIN;

	/* add the driver to the list of i2c drivers in the driver core */
	driver->driver.owner = owner;
	driver->driver.bus = &i2c_bus_type;    //i2c_driver的總線類型爲i2c

	/* When registration returns, the driver core
	 * will have called probe() for all matching-but-unbound devices.
	 */
	res = driver_register(&driver->driver);		//註冊i2c_driver內嵌的driver
	if (res)
		return res;

	/* Drivers should switch to dev_pm_ops instead. */
	if (driver->suspend)
		pr_warn("i2c-core: driver [%s] using legacy suspend method\n",
			driver->driver.name);
	if (driver->resume)
		pr_warn("i2c-core: driver [%s] using legacy resume method\n",
			driver->driver.name);

	pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
	INIT_LIST_HEAD(&driver->clients);
	/* Walk the adapters that are already present */
	res = i2c_for_each_dev(driver, __process_new_driver);	//掃描i2c總線掛載的i2c_client設備和i2c_adapte設備,不過只有adapter設備才能執行__process_new_driver

下面先分析下driver_register的執行流程:

driver_register

driver_find

bus_add_driver

driver_attach

bus_for_each_dev(drv->bus, NULL, drv, __driver_attach)

__driver_attach

driver_match_device

drv->bus->match(dev, drv)

i2c_device_match

driver_probe_device

really_probe

dev->bus->probe(dev)

i2c_device_probe

driver->probe(client, i2c_match_id(driver->id_table, client))

再來分析下__process_new_driver

  1. static int __process_new_driver(struct device *dev, void *data)  
  2. {  
  3.     if (dev->type != &i2c_adapter_type)  
  4.     {  
  5.         //printk("-----dev type is not i2c adapter type\n");  
  6.         return 0;  
  7.     }  
  8.     //printk("-----i2c do add adapter\n");  
  9.     return i2c_do_add_adapter(data, to_i2c_adapter(dev));  
  10. }  
static int __process_new_driver(struct device *dev, void *data)
{
	if (dev->type != &i2c_adapter_type)
	{
		//printk("-----dev type is not i2c adapter type\n");
		return 0;
	}
	//printk("-----i2c do add adapter\n");
	return i2c_do_add_adapter(data, to_i2c_adapter(dev));
}
  1. static int i2c_do_add_adapter(struct i2c_driver *driver,  
  2.                   struct i2c_adapter *adap)  
  3. {  
  4.     /* Detect supported devices on that bus, and instantiate them */  
  5.     i2c_detect(adap, driver);   //if (!driver->detect || !address_list),如果detect函數和address_list沒有定義就直接返回。  
  6.   
  7.     /* Let legacy drivers scan this bus for matching devices */  
  8.     if (driver->attach_adapter) {                //如果沒定義就不執行  
  9.         dev_warn(&adap->dev, "%s: attach_adapter method is deprecated\n",  
  10.              driver->driver.name);  
  11.         dev_warn(&adap->dev, "Please use another way to instantiate "  
  12.              "your i2c_client\n");  
  13.         /* We ignore the return code; if it fails, too bad */  
  14.         driver->attach_adapter(adap);  
  15.     }  
  16.     return 0;  
  17. }  
static int i2c_do_add_adapter(struct i2c_driver *driver,
			      struct i2c_adapter *adap)
{
	/* Detect supported devices on that bus, and instantiate them */
	i2c_detect(adap, driver);	//if (!driver->detect || !address_list),如果detect函數和address_list沒有定義就直接返回。

	/* Let legacy drivers scan this bus for matching devices */
	if (driver->attach_adapter) {				//如果沒定義就不執行
		dev_warn(&adap->dev, "%s: attach_adapter method is deprecated\n",
			 driver->driver.name);
		dev_warn(&adap->dev, "Please use another way to instantiate "
			 "your i2c_client\n");
		/* We ignore the return code; if it fails, too bad */
		driver->attach_adapter(adap);
	}
	return 0;
}
3. 總線側驅動的註冊

  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.     if (!pdata) {  
  10.         dev_err(&pdev->dev, "no platform data\n");  
  11.         return -EINVAL;  
  12.     }  
  13.   
  14.     i2c = kzalloc(sizeof(struct s3c24xx_i2c), GFP_KERNEL);  
  15.     if (!i2c) {  
  16.         dev_err(&pdev->dev, "no memory for state\n");  
  17.         return -ENOMEM;  
  18.     }  
  19.   
  20.     strlcpy(i2c->adap.name, "s3c2410-i2c"sizeof(i2c->adap.name));  
  21.     i2c->adap.owner   = THIS_MODULE;  
  22.     i2c->adap.algo    = &s3c24xx_i2c_algorithm;  
  23.     i2c->adap.retries = 2;  
  24.     i2c->adap.class   = I2C_CLASS_HWMON | I2C_CLASS_SPD;  
  25.     i2c->tx_setup     = 50;  
  26.   
  27.     spin_lock_init(&i2c->lock);  
  28.     init_waitqueue_head(&i2c->wait);  
  29.   
  30.     /* find the clock and enable it */  
  31.   
  32.     i2c->dev = &pdev->dev;  
  33.     i2c->clk = clk_get(&pdev->dev, "i2c");  
  34.     if (IS_ERR(i2c->clk)) {  
  35.         dev_err(&pdev->dev, "cannot get clock\n");  
  36.         ret = -ENOENT;  
  37.         goto err_noclk;  
  38.     }  
  39.   
  40.     dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk);  
  41.   
  42.     clk_enable(i2c->clk);  
  43.   
  44.     /* map the registers */  
  45.   
  46.     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  
  47.     if (res == NULL) {  
  48.         dev_err(&pdev->dev, "cannot find IO resource\n");  
  49.         ret = -ENOENT;  
  50.         goto err_clk;  
  51.     }  
  52.   
  53.     i2c->ioarea = request_mem_region(res->start, resource_size(res),  
  54.                      pdev->name);  
  55.   
  56.     if (i2c->ioarea == NULL) {  
  57.         dev_err(&pdev->dev, "cannot request IO\n");  
  58.         ret = -ENXIO;  
  59.         goto err_clk;  
  60.     }  
  61.   
  62.     i2c->regs = ioremap(res->start, resource_size(res));  
  63.   
  64.     if (i2c->regs == NULL) {  
  65.         dev_err(&pdev->dev, "cannot map IO\n");  
  66.         ret = -ENXIO;  
  67.         goto err_ioarea;  
  68.     }  
  69.   
  70.     dev_dbg(&pdev->dev, "registers %p (%p, %p)\n",  
  71.         i2c->regs, i2c->ioarea, res);  
  72.   
  73.     /* setup info block for the i2c core */  
  74.   
  75.     i2c->adap.algo_data = i2c;  
  76.     i2c->adap.dev.parent = &pdev->dev;  
  77.   
  78.     /* initialise the i2c controller */  
  79.   
  80.     ret = s3c24xx_i2c_init(i2c);  
  81.     if (ret != 0)  
  82.         goto err_iomap;  
  83.   
  84.     /* find the IRQ for this unit (note, this relies on the init call to 
  85.      * ensure no current IRQs pending 
  86.      */  
  87.   
  88.     i2c->irq = ret = platform_get_irq(pdev, 0);  
  89.     if (ret <= 0) {  
  90.         dev_err(&pdev->dev, "cannot find IRQ\n");  
  91.         goto err_iomap;  
  92.     }  
  93.   
  94.     ret = request_irq(i2c->irq, s3c24xx_i2c_irq, IRQF_DISABLED,  
  95.               dev_name(&pdev->dev), i2c);  
  96.   
  97.     if (ret != 0) {  
  98.         dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);  
  99.         goto err_iomap;  
  100.     }  
  101.   
  102.     ret = s3c24xx_i2c_register_cpufreq(i2c);  
  103.     if (ret < 0) {  
  104.         dev_err(&pdev->dev, "failed to register cpufreq notifier\n");  
  105.         goto err_irq;  
  106.     }  
  107.   
  108.     /* Note, previous versions of the driver used i2c_add_adapter() 
  109.      * to add the bus at any number. We now pass the bus number via 
  110.      * the platform data, so if unset it will now default to always 
  111.      * being bus 0. 
  112.      */  
  113.   
  114.     i2c->adap.nr = pdata->bus_num;  
  115.   
  116.     ret = i2c_add_numbered_adapter(&i2c->adap);  
  117.     if (ret < 0) {  
  118.         dev_err(&pdev->dev, "failed to add bus to i2c core\n");  
  119.         goto err_cpufreq;  
  120.     }  
  121.   
  122.     platform_set_drvdata(pdev, i2c);  
  123.   
  124.     dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev));  
  125.     clk_disable(i2c->clk);  
  126.     return 0;  
  127.   
  128.  err_cpufreq:  
  129.     s3c24xx_i2c_deregister_cpufreq(i2c);  
  130.   
  131.  err_irq:  
  132.     free_irq(i2c->irq, i2c);  
  133.   
  134.  err_iomap:  
  135.     iounmap(i2c->regs);  
  136.   
  137.  err_ioarea:  
  138.     release_resource(i2c->ioarea);  
  139.     kfree(i2c->ioarea);  
  140.   
  141.  err_clk:  
  142.     clk_disable(i2c->clk);  
  143.     clk_put(i2c->clk);  
  144.   
  145.  err_noclk:  
  146.     kfree(i2c);  
  147.     return ret;  
  148. }  
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;
	if (!pdata) {
		dev_err(&pdev->dev, "no platform data\n");
		return -EINVAL;
	}

	i2c = kzalloc(sizeof(struct s3c24xx_i2c), GFP_KERNEL);
	if (!i2c) {
		dev_err(&pdev->dev, "no memory for state\n");
		return -ENOMEM;
	}

	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 */

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

	i2c->ioarea = request_mem_region(res->start, resource_size(res),
					 pdev->name);

	if (i2c->ioarea == NULL) {
		dev_err(&pdev->dev, "cannot request IO\n");
		ret = -ENXIO;
		goto err_clk;
	}

	i2c->regs = ioremap(res->start, resource_size(res));

	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 */

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

	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;

	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));
	clk_disable(i2c->clk);
	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_add_numbered_adapter

i2c_register_adapter

device_register //註冊i2c_adapter內嵌的device

i2c_scan_static_board_info

list_for_each_entry(devinfo, &__i2c_board_list, list)

i2c_new_device

device_register //註冊i2c_device內嵌的device

bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter)

__process_new_adapter

i2c_do_add_adapter(to_i2c_driver(d), data)

所以i2c_add_numbered_adapter也走到了i2c_do_add_adapter。


初始化流程總結:

1. setup_arch時把靜態定義的struct i2c_board_info結構,使用i2c_register_board_info函數註冊到全局__i2c_board_list中。

2. 適配層 platform_driver的註冊,就是分配i2c_adapter結構,初始化,然後掃描__i2c_board_list中的鏈表,並且分配i2c_device結構。

3. 設備側i2c_driver的註冊,如果找到i2c總線上註冊的i2c_device結構,就觸發i2c_driver裏面的probe。

4. 不管是註冊i2c_adapter還是i2c_driver,最後都會觸發到i2c_do_add_adapter。

4. i2c-dev的分析

  1. static struct notifier_block i2cdev_notifier = {  
  2.     .notifier_call = i2cdev_notifier_call,  
  3. };  
  4. static int __init i2c_dev_init(void)  
  5. {  
  6.     int res;  
  7.   
  8.     printk(KERN_INFO "i2c /dev entries driver\n");  
  9.   
  10.     res = register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops);  
  11.     if (res)  
  12.         goto out;  
  13.   
  14.     i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");  
  15.     if (IS_ERR(i2c_dev_class)) {  
  16.         res = PTR_ERR(i2c_dev_class);  
  17.         goto out_unreg_chrdev;  
  18.     }  
  19.   
  20.     /* Keep track of adapters which will be added or removed later */  
  21.     res = bus_register_notifier(&i2c_bus_type, &i2cdev_notifier);  
  22.     if (res)  
  23.         goto out_unreg_class;  
  24.   
  25.     /* Bind to already existing adapters right away */  
  26.     i2c_for_each_dev(NULL, i2cdev_attach_adapter);  
  27.   
  28.     return 0;  
  29.   
  30. out_unreg_class:  
  31.     class_destroy(i2c_dev_class);  
  32. out_unreg_chrdev:  
  33.     unregister_chrdev(I2C_MAJOR, "i2c");  
  34. out:  
  35.     printk(KERN_ERR "%s: Driver Initialisation failed\n", __FILE__);  
  36.     return res;  
  37. }  
  38. int i2cdev_notifier_call(struct notifier_block *nb, unsigned long action,  
  39.              void *data)  
  40. {  
  41.     struct device *dev = data;  
  42.   
  43.     switch (action) {  
  44.     case BUS_NOTIFY_ADD_DEVICE:  
  45.         return i2cdev_attach_adapter(dev, NULL);  
  46.     case BUS_NOTIFY_DEL_DEVICE:  
  47.         return i2cdev_detach_adapter(dev, NULL);  
  48.     }  
  49.   
  50.     return 0;  
  51. }  
static struct notifier_block i2cdev_notifier = {
	.notifier_call = i2cdev_notifier_call,
};
static int __init i2c_dev_init(void)
{
	int res;

	printk(KERN_INFO "i2c /dev entries driver\n");

	res = register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops);
	if (res)
		goto out;

	i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");
	if (IS_ERR(i2c_dev_class)) {
		res = PTR_ERR(i2c_dev_class);
		goto out_unreg_chrdev;
	}

	/* Keep track of adapters which will be added or removed later */
	res = bus_register_notifier(&i2c_bus_type, &i2cdev_notifier);
	if (res)
		goto out_unreg_class;

	/* Bind to already existing adapters right away */
	i2c_for_each_dev(NULL, i2cdev_attach_adapter);

	return 0;

out_unreg_class:
	class_destroy(i2c_dev_class);
out_unreg_chrdev:
	unregister_chrdev(I2C_MAJOR, "i2c");
out:
	printk(KERN_ERR "%s: Driver Initialisation failed\n", __FILE__);
	return res;
}
int i2cdev_notifier_call(struct notifier_block *nb, unsigned long action,
			 void *data)
{
	struct device *dev = data;

	switch (action) {
	case BUS_NOTIFY_ADD_DEVICE:
		return i2cdev_attach_adapter(dev, NULL);
	case BUS_NOTIFY_DEL_DEVICE:
		return i2cdev_detach_adapter(dev, NULL);
	}

	return 0;
}
所以每當有i2c_adapter要註冊時,都會觸發i2cdev_attach_adapter函數。

  1. static int i2cdev_attach_adapter(struct device *dev, void *dummy)  
  2. {  
  3.     struct i2c_adapter *adap;  
  4.     struct i2c_dev *i2c_dev;  
  5.     int res;  
  6.   
  7.     if (dev->type != &i2c_adapter_type)  
  8.         return 0;  
  9.     adap = to_i2c_adapter(dev);  
  10.   
  11.     i2c_dev = get_free_i2c_dev(adap);  
  12.     if (IS_ERR(i2c_dev))  
  13.         return PTR_ERR(i2c_dev);  
  14.   
  15.     /* register this i2c device with the driver core */  
  16.     i2c_dev->dev = device_create(i2c_dev_class, &adap->dev,  
  17.                      MKDEV(I2C_MAJOR, adap->nr), NULL,  
  18.                      "i2c-%d", adap->nr);  
  19.     if (IS_ERR(i2c_dev->dev)) {  
  20.         res = PTR_ERR(i2c_dev->dev);  
  21.         goto error;  
  22.     }  
  23.     res = device_create_file(i2c_dev->dev, &dev_attr_name);  
  24.     if (res)  
  25.         goto error_destroy;  
  26.   
  27.     pr_debug("i2c-dev: adapter [%s] registered as minor %d\n",  
  28.          adap->name, adap->nr);  
  29.     //printk("-------i2c-dev: adapter [%s] registered as minor %d\n",  
  30.          //adap->name, adap->nr);  
  31.     return 0;  
  32. error_destroy:  
  33.     device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));  
  34. error:  
  35.     return_i2c_dev(i2c_dev);  
  36.     return res;  
  37. }  
static int i2cdev_attach_adapter(struct device *dev, void *dummy)
{
	struct i2c_adapter *adap;
	struct i2c_dev *i2c_dev;
	int res;

	if (dev->type != &i2c_adapter_type)
		return 0;
	adap = to_i2c_adapter(dev);

	i2c_dev = get_free_i2c_dev(adap);
	if (IS_ERR(i2c_dev))
		return PTR_ERR(i2c_dev);

	/* register this i2c device with the driver core */
	i2c_dev->dev = device_create(i2c_dev_class, &adap->dev,
				     MKDEV(I2C_MAJOR, adap->nr), NULL,
				     "i2c-%d", adap->nr);
	if (IS_ERR(i2c_dev->dev)) {
		res = PTR_ERR(i2c_dev->dev);
		goto error;
	}
	res = device_create_file(i2c_dev->dev, &dev_attr_name);
	if (res)
		goto error_destroy;

	pr_debug("i2c-dev: adapter [%s] registered as minor %d\n",
		 adap->name, adap->nr);
	//printk("-------i2c-dev: adapter [%s] registered as minor %d\n",
		 //adap->name, adap->nr);
	return 0;
error_destroy:
	device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));
error:
	return_i2c_dev(i2c_dev);
	return res;
}

總結:i2c驅動框架目前只是分析了初始化過程,i2c_client,i2c_driver,i2c_adapter的創建過程,它們之間的關係。具體的通信過程有時間再分析。


發佈了3 篇原創文章 · 獲贊 6 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章