Linux中對I2C的支持很是全面,既提供了內核態的訪問方式,也提供了用戶態的訪問方法。
linux
Linux中對I2C的支持能夠分爲兩個層面,一個是adapter和algorithm,對應的是i2c控制器;再一個是driver和client.Linux內核提供了豐富的接口來實添加i2c設備驅動。要添加一個i2c設備驅動,須要幾個固定的步驟。首先,須要往i2c設備列表裏添加一組設備ID foo_idtable:數據結構
static struct i2c_device_id foo_idtable[] = { ide
{ "foo", my_id_for_foo },函數
{ "bar", my_id_for_bar },spa
{ } code
};orm
MODULE_DEVICE_TABLE(i2c, foo_idtable);接口
而後填充i2c driver的數據結構:ip
static struct i2c_driver foo_driver = { rem
.driver = {
.name = "foo",
.pm = &foo_pm_ops, /* optional */
},
.id_table = foo_idtable,
.probe = foo_probe,
.remove = foo_remove,
/* if device autodetection is needed: */
.class = I2C_CLASS_SOMETHING,
.detect = foo_detect,
.address_list = normal_i2c,
.shutdown = foo_shutdown, /* optional */
.command = foo_command, /* optional, deprecated */
}
剩下的就是逐一初始化foo_probe()、foo_remove()、foo_detect()等函數。一旦準備好了相應的client結構,就能夠實現foo_read_valule()和foo_write_value()函數,固然這二者都是基於底層公共的i2c/smbus讀寫函數:i2c_smbus_read/write_byte_data/word()去實現。
若是確實有i2c設備掛載在某個i2c總線上,能夠經過填充i2c_board_info數據結構來構造這個設備的實例,而後調用i2c_new_device()來探測實際接入的i2c設備。固然也可能事先沒法確認系統上有什麼類型的i2c設備,這個時候須要定義一個call back函數,放在probe()後面,讓它去確認是否有指定類型的i2c設備掛在系統上。使用完設備後,能夠調用i2c_unregister_device()來註銷以前註冊的設備。固然執行這些全部操做的前提是設備對應的驅動已經被初始化好而且加載到內核,能夠參考下面的代碼來實現初始化和退出操做:
static int __init foo_init(void)
{
return i2c_add_driver(&foo_driver);
}
module_init(foo_init);
static void __exit foo_cleanup(void)
{
i2c_del_driver(&foo_driver);
}
module_exit(foo_cleanup);
The module_i2c_driver() macro can be used to reduce above code.
module_i2c_driver(foo_driver);
若是驅動中,須要向設備發送或者從設備接受數據,能夠調用:
int i2c_master_send(struct i2c_client *client, const char *buf, int count);
int i2c_master_recv(struct i2c_client *client, char *buf, int count);
這兩組函數來實現,更多的函數在linux/i2c.h中有說明。
固然linux內核中也提供了設備做爲從設備的驅動,這中狀況下的系統層次圖以下所示:
e.g. sysfs I2C slave events I/O registers
+-----------+ v +---------+ v +--------+ v +------------+
| Userspace +........+ Backend +-----------+ Driver +-----+ Controller |
+-----------+ +---------+ +--------+ +------------+
| |
----------------------------------------------------------------+-- I2C
--------------------------------------------------------------+---- Bus
不一樣於PCI/USB設備,I2C沒有提供硬件上自動枚舉的能力,所以在初始化i2c設備以前須要顯式地指定設備的地址。內核提供了多個顯式初始化一個i2c設備的方法:
1、經過bus number聲明一個i2c設備:
這種狀況尤爲適用於i2c做爲系統總線的嵌入式系統,以omp2 h4爲例,用戶須要註冊i2c board info:
Example (from omap2 h4):
static struct i2c_board_info h4_i2c_board_info[] __initdata = {
{
I2C_BOARD_INFO("isp1301_omap", 0x2d),
.irq = OMAP_GPIO_IRQ(125),
},
{ /* EEPROM on mainboard */
I2C_BOARD_INFO("24c01", 0x52),
.platform_data = &m24c01,
},
{ /* EEPROM on cpu card */
I2C_BOARD_INFO("24c01", 0x57),
.platform_data = &m24c01,
},
};
static void __init omap_h4_init(void)
{
(...)
i2c_register_board_info(1, h4_i2c_board_info,
ARRAY_SIZE(h4_i2c_board_info));
(...)
}
2、經過設備樹申明一個i2c設備:
這種方式須要把心建的設備節點掛在master conrollor對應的設備樹上,也就是說它必須是master controller的子節點,以下面的例子所示:
i2c1: i2c@400a0000 {
/* ... master properties skipped ... */
clock-frequency = <100000>;
flash@50 {
compatible = "atmel,24c256";
reg = <0x50>;
};
pca9532: gpio@60 {
compatible = "nxp,pca9532";
gpio-controller;
#gpio-cells = <2>;
reg = <0x60>;
};
};
3、經過ACPI申明一個I2C設備:
ACPI表裏可以申明I2C設備:Documentation/acpi/enumeration.txt。
4、顯式地實例化i2c設備:
這也是經過填充i2c_board_info數據結構,而後調用i2c_new_device()實現的,以下面的代碼所示:
static struct i2c_board_info sfe4001_hwmon_info = {
I2C_BOARD_INFO("max6647", 0x4e),
};
int sfe4001_init(struct efx_nic *efx)
{
(...)
efx->board_info.hwmon_client =
i2c_new_device(&efx->i2c_adap, &sfe4001_hwmon_info);
(...)
}
上面的代碼在i2c bus上實例化了一個i2c設備。
5、對一些特殊的設備進行自動探測
有的系統上並無提供足夠多的關於i2c設備和拓撲信息,這個時候就須要依賴i2c-core去探測設備,這就要求:
i2c設備驅動必須實現detect()函數;
只有掛載了這種設備的i2c總線可以且容許被探測。
6、利用/sysfs經過用戶態初始化i2c設備
好比咱們須要把位於i2c地址0x50的eerom添加到設備當中去,能夠直接操做sysfs實現:
echo eeprom 0x50 > /sys/bus/i2c/devices/i2c-3/new_device