linux內核學習-驅動-I2C

先來看看linux內核的I2C驅動的文件在/drivers/i2c目錄下。
在這裏插入圖片描述

一、先看看Makefile文件

#
# Makefile for the i2c core.
#

obj-$(CONFIG_I2C_BOARDINFO)	+= i2c-boardinfo.o
obj-$(CONFIG_I2C)		+= i2c-core.o
obj-$(CONFIG_I2C_SMBUS)		+= i2c-smbus.o
obj-$(CONFIG_I2C_CHARDEV)	+= i2c-dev.o
obj-y				+= algos/ busses/

ifeq ($(CONFIG_I2C_DEBUG_CORE),y)
EXTRA_CFLAGS += -DDEBUG
endif

還是比較簡單的。

二、再來看看I2C子系統的啓動順序

根據上面的分析我們可以知道在linux系統中iic子系統的初始化順序爲:

  1. /driver/i2c/i2c-core.c postcore_initcall(i2c_init);
  2. /arch/arm/mach-s3c2440 MACHINE_START(S3C2440, “SMDK2440”)
  3. /drivers/i2c/busses/i2c-s3c2410.c subsys_initcall(i2c_adap_s3c_init);
  4. /driver/i2c/i2c-dev.c module_init(i2c_dev_init);

三、補充知識:Linux驅動模型

1.最開始寫硬件驅動,直接寫,然後創建一個節點給應用調用就行。
2.後來發現太混亂,引入了“驅動-總線-設備”的模型。這樣就對相似的設備做了分類。將底層代碼和設備代碼分離。思路清晰了。
3.在2.6版本內核以後,發現在內核代碼中有很多關於“board”、“platform”的冗餘代碼(比方說不同的開發板會有很多相似的硬件,那麼代碼就是一樣的。)。爲了解決這種辣雞代碼太多的問題,引進了“設備樹”的概念。將某IC的驅動都放入drivers目錄下,不同的

四、I2C bus總線

在I2C Bus用來掛載後面將會使用到的I2C 適配器(adapter)和I2C設備(client)。I2C bus是一個虛擬的設備。
注意這裏的i2c bus與platform bus不是屬於同一個類型的總線,platform bus用來管理platform driver 和platform device。.在整個linux 系統中只有一條platform bus,它在內核啓動時初始化:

start_kernel(/init/main.c) ->
rest_init (/init/main.c)->
kernel_thread(創建系統進程/arch/arm/kernel/process.c) ->
kernel_init(/init/main.c) -> do_basic_setup(/init/main.c) ->
driver_init(/drivers/base/init.c) -> platform_bus_init(/drivers/base/platform.c) ->
device_register(&platform_bus)
以上內容包括了函數所在位置(括號裏的就是位置。)

五、platform_bus註冊過程

源碼如下

struct device platform_bus = {
	.init_name	= "platform",
};

int __init platform_bus_init(void)
{
	int error;

	early_platform_cleanup();

	error = device_register(&platform_bus);
	if (error)
		return error;
	error =  bus_register(&platform_bus_type);
	if (error)
		device_unregister(&platform_bus);
	return error;
}

關鍵函數是device_register

error = device_register(&platform_bus);
error = bus_register(&platform_bus_type);
這兩句,就實現了bus的註冊。

六、i2c_bus註冊過程

上面準備好了platform_bus的總線,下一步就是i2c_bus的註冊。
首先初始化的是i2c_init() 函數,IIC Bus 就是在該函數中初始化的。
/dricer/i2c/i2c-core.c
在這裏插入圖片描述

(1.0)通過bus_register()函數註冊IIC總線。我們看參數i2c_bus_type,它被定義爲:

struct bus_type i2c_bus_type = {
	.name		= "i2c",
	.match		= i2c_device_match,1.1.probe		= i2c_device_probe,1.2.remove		= i2c_device_remove,
	.shutdown	= i2c_device_shutdown,
	.suspend	= i2c_device_suspend,
	.resume		= i2c_device_resume,
};

(1.1)總線提供的match方法:match方法用來進行 device 和driver 的匹配,在向總線註冊設備或是驅動的的時候會調用此方法。其函數定義爲:

static int i2c_device_match(struct device *dev, struct device_driver *drv)
{
	struct i2c_client	*client = i2c_verify_client(dev);1.1.0struct i2c_driver	*driver;
 
	if (!client)
		return 0;                                                    
 
	driver = to_i2c_driver(drv);1.1.1/* match on an id table if there is one */
	if (driver->id_table)
		return i2c_match_id(driver->id_table, client) != NULL;1.1.2return 0;
}

(1.1.0)用struct i2c_client 來描述一個具體的IIC設備,這裏指的是client device 。
(1.1.1)獲取driver
(1.1.2)如果IIC驅動的id_table 存在的話,使用i2c_match_id 進行函數進行匹配。匹配的方法是拿id_table 中的每一項與client 的name 進行匹配,如果名字相同則匹配成功。從這裏我們可以看出IIC總線的匹配方式與platform 總線的匹配方式是不同的:

  • IIC總線根據設備名字和驅動中的id_table進行匹配
  • platform總線根據設備名字和設備驅動名字進行匹配

driver是一張表(id_table),device有一個名字。

(1.2)總線提供的probe方法:probe方法在完成設備和驅動的配對之後調用執行。在裏面可以做一些更進一步的初始化工作

static int i2c_device_probe(struct device *dev)
{
	struct i2c_client	*client = i2c_verify_client(dev);
	struct i2c_driver	*driver;
	int status;
 
	if (!client)
		return 0;
 
	driver = to_i2c_driver(dev->driver);
	if (!driver->probe || !driver->id_table)
		return -ENODEV;
	client->driver = driver;
	if (!device_can_wakeup(&client->dev))1.2.0device_init_wakeup(&client->dev,
					client->flags & I2C_CLIENT_WAKE);
	dev_dbg(dev, "probe\n");
 
	status = driver->probe(client, i2c_match_id(driver->id_table, client));1.2.1if (status)
		client->driver = NULL;
	return status;
}

(1.2.0)IIC的電源管理
(1.2.1)調用IIC設備驅動中的Probe 函數

七、I2C platform device 初始化

上面的繼續梳理下:

  1. I2c bus的啓動過程,
  2. i2c bus如何註冊總線
  3. i2c bus如何match 驅動和設備
  4. i2c bus調用設備的probe方法。

OK,有了 總線,那麼就需要device和driver。不過內核爲了更進一步的抽象,把device和driver抽象成platform device和platform_driver。

I2C的platform device 初始化在mach-smdk2440.c文件中進行

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章