如何實(shí)例化i2c設(shè)備?4種方式如下:
- 方法1:靜態(tài)聲明I2C設(shè)備
- 通過devicetree聲明I2C設(shè)備
- 在板級(jí)文件中聲明I2C設(shè)備
- 方法2:顯式實(shí)例化設(shè)備
- 方法3:對(duì)某些設(shè)備的I2C總線進(jìn)行探測(cè)
- 方法4:從用戶空間實(shí)例化
在本篇中,主要看一下方法1,3和方法4。對(duì)于方法2,在下一篇的一個(gè)I2C ADC/DAC的misc設(shè)備驅(qū)動(dòng)實(shí)例中再加以詳述。
通過devicetree聲明I2C設(shè)備
/dts-v1/;
/plugin/;
/ {
compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
fragment@0 {
target = < &i2c1 >;
__overlay__ {
#address-cells = < 1 >;
#size-cells = < 0 >;
rtc@68 {
compatible = "maxim,ds3231";
reg = < 0x68 >;
#address-cells = < 2 >;
#size-cells = < 1 >;
};
};
};
};
首先,寫一個(gè)dts。
編譯,并將生成的.dtbo到/boot/overlays
重啟后,查看/dev可以看到rtc
通過板級(jí)文件中聲明I2C設(shè)備
在架構(gòu)板級(jí)文件中添加i2c設(shè)備信息,并注冊(cè)到特定位置。看一個(gè)nxp imx開發(fā)板的電源芯片的實(shí)例,arch/arm/mach-imx/mach-mx35_3ds.c
static struct mc13xxx_platform_data mx35_3ds_mc13892_data = {
.flags = MC13XXX_USE_RTC | MC13XXX_USE_TOUCHSCREEN,
.regulators = {
.num_regulators = ARRAY_SIZE(mx35_3ds_regulators),
.regulators = mx35_3ds_regulators,
},
};
#define GPIO_PMIC_INT IMX_GPIO_NR(2, 0)
static struct i2c_board_info mx35_3ds_i2c_mc13892 = {
I2C_BOARD_INFO("mc13892", 0x08),
.platform_data = &mx35_3ds_mc13892_data,
/* irq number is run-time assigned */
};
static void __init imx35_3ds_init_mc13892(void)
{
int ret = gpio_request_one(GPIO_PMIC_INT, GPIOF_DIR_IN, "pmic irq");
if (ret) {
pr_err("failed to get pmic irq: %dn", ret);
return;
}
mx35_3ds_i2c_mc13892.irq = gpio_to_irq(GPIO_PMIC_INT);
i2c_register_board_info(0, &mx35_3ds_i2c_mc13892, 1);
}
MC13892是面向i.MX51、i.MX37、i.MX3和i.MX27應(yīng)用處理器的PMIC。在板級(jí)文件中定義了一個(gè) i2c_board_info 結(jié)構(gòu)體,使用i2c_register_board_info函數(shù)將i2c設(shè)備信息添加到特定鏈表。
i2c_register_board_info在/drivers/i2c/i2c-boardinfo.c中:
/**
* i2c_register_board_info - statically declare I2C devices
* @busnum: identifies the bus to which these devices belong
* @info: vector of i2c device descriptors
* @len: how many descriptors in the vector; may be zero to reserve
* the specified bus number.
*
* Systems using the Linux I2C driver stack can declare tables of board info
* while they initialize. This should be done in board-specific init code
* near arch_initcall() time, or equivalent, before any I2C adapter driver is
* registered. For example, mainboard init code could define several devices,
* as could the init code for each daughtercard in a board stack.
*
* The I2C devices will be created later, after the adapter for the relevant
* bus has been registered. After that moment, standard driver model tools
* are used to bind "new style" I2C drivers to the devices. The bus number
* for any device declared using this routine is not available for dynamic
* allocation.
*
* The board info passed can safely be __initdata, but be careful of embedded
* pointers (for platform_data, functions, etc) since that won't be copied.
* Device properties are deep-copied though.
*/
int i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len)
對(duì)某些設(shè)備的I2C總線進(jìn)行探測(cè)
有時(shí)沒有關(guān)于I2C設(shè)備的足夠信息,甚至無法調(diào)用i2c_new_scanned_device()。典型的例子是PC主板上的硬件監(jiān)控芯片。有幾十個(gè)模型,可能被分配在25個(gè)不同的地址。考慮到主板的龐大數(shù)量,幾乎不可能建立一個(gè)正在使用的硬件監(jiān)控芯片的詳盡列表。幸運(yùn)的是,大多數(shù)這些芯片都有制造商和設(shè)備ID寄存器,因此可以通過探測(cè)來識(shí)別它們。
在這種情況下,I2C設(shè)備既沒有顯式聲明也沒有實(shí)例化。相反,一旦這些設(shè)備的驅(qū)動(dòng)程序被加載,I2C -core就會(huì)探測(cè)它們,如果找到了,就會(huì)自動(dòng)實(shí)例化一個(gè)I2C設(shè)備。為了防止此機(jī)制的任何不當(dāng)行為,適用以下限制:
- I2C設(shè)備驅(qū)動(dòng)程序必須實(shí)現(xiàn)detect()方法,該方法通過從任意寄存器讀取來識(shí)別受支持的設(shè)備。
- 只有那些可能有支持設(shè)備并同意被探測(cè)的總線才會(huì)被探測(cè)。例如,這避免了探測(cè)電視適配器上的硬件監(jiān)控芯片。
detect何時(shí)調(diào)用?
i2c_driver注冊(cè)的時(shí)候,i2c_core會(huì)在所有已經(jīng)注冊(cè)的i2c_adapter上探測(cè)address_list中的所有地址,硬件探測(cè)成功之后后調(diào)用i2c_driver的detect成員,然后根據(jù)detect填充的info建立一個(gè)i2c_client。
例如,MAX1668溫度傳感器的驅(qū)動(dòng)實(shí)現(xiàn),/drivers/hwmon/max1668.c
static struct i2c_driver max1668_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "max1668",
},
.probe = max1668_probe,
.id_table = max1668_id,
.detect = max1668_detect,
.address_list = max1668_addr_list,
};
module_i2c_driver(max1668_driver);
其中,detect函數(shù)
/* Return 0 if detection is successful, -ENODEV otherwise */
static int max1668_detect(struct i2c_client *client,
struct i2c_board_info *info)
{
struct i2c_adapter *adapter = client- >adapter;
const char *type_name;
int man_id, dev_id;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
/* Check for unsupported part */
man_id = i2c_smbus_read_byte_data(client, MAX1668_REG_MAN_ID);
if (man_id != MAN_ID_MAXIM)
return -ENODEV;
dev_id = i2c_smbus_read_byte_data(client, MAX1668_REG_DEV_ID);
if (dev_id < 0)
return -ENODEV;
type_name = NULL;
if (dev_id == DEV_ID_MAX1668)
type_name = "max1668";
else if (dev_id == DEV_ID_MAX1805)
type_name = "max1805";
else if (dev_id == DEV_ID_MAX1989)
type_name = "max1989";
if (!type_name)
return -ENODEV;
strlcpy(info- >type, type_name, I2C_NAME_SIZE);
return 0;
}
以樹莓派為例,i2c_add_adapter會(huì)在bcm2835_i2c_probe調(diào)用
static int bcm2835_i2c_probe(struct platform_device *pdev)
在i2c_register_adapter 中會(huì)調(diào)用,bus_for_each_drv 來來通知所有總線類型是i2c_bus_type的driver。
/* Notify drivers */
mutex_lock(&core_lock);
bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);
mutex_unlock(&core_lock);
static int __process_new_adapter(struct device_driver *d, void *data)
{
return i2c_do_add_adapter(to_i2c_driver(d), data);
}
在i2c_do_add_adapter->i2c_detect->i2c_detect_address 中有一段關(guān)鍵code
err = driver- >detect(temp_client, &info);
if (err) {
/* -ENODEV is returned if the detection fails. We catch it
here as this isn't an error. */
return err == -ENODEV ? 0 : err;
}
從用戶空間實(shí)例化
用戶空間通過兩個(gè)sysfs屬性文件來建立和刪除i2c_client:new_device和delete_device。
- new_device有兩個(gè)參數(shù):i2c設(shè)備的名字(字符串)和地址(以0x開頭的16進(jìn)制數(shù))。
- delete_device只有一個(gè)參數(shù):設(shè)備的地址。
pi@raspberrypi:/sys/class/i2c-adapter/i2c-1 $ ls
delete_device device i2c-dev name new_device of_node power subsystem uevent
添加rtc設(shè)備
pi@raspberrypi:/sys/class/i2c-adapter/i2c-1 $ echo ds3231 0x68 | sudo tee new_device
ds3231 0x68
方法2:顯式實(shí)例化設(shè)備,在下一篇"在Linux系統(tǒng)里如何編寫一個(gè)PCF8591的驅(qū)動(dòng),完成ADC數(shù)據(jù)采集,DAC數(shù)據(jù)輸出"中再詳述。
PCF8591 是一個(gè)單片集成、單獨(dú)供電、低功耗、8-bit CMOS數(shù)據(jù)獲取器件。PCF8591 具有 4 個(gè)模擬輸入、1 個(gè)模擬輸出和 1個(gè)串行 I2C 總線接口。
PCF8591 的 3 個(gè)地址引腳 A0, A1 和 A2 可用于硬件地址編程,允許在同個(gè) I2C 總線上接入 8 個(gè) PCF8591 器件,而無需額外的硬件。在 PCF8591 器件上輸入輸出的地址、控制和數(shù)據(jù)信號(hào)都是通過雙線雙向 I2C 總線以串行的方式進(jìn)行傳輸。
-
處理器
+關(guān)注
關(guān)注
68文章
19404瀏覽量
230807 -
驅(qū)動(dòng)器
+關(guān)注
關(guān)注
53文章
8271瀏覽量
146857 -
寄存器
+關(guān)注
關(guān)注
31文章
5363瀏覽量
120952 -
I2C總線
+關(guān)注
關(guān)注
8文章
406瀏覽量
61106 -
電源芯片
+關(guān)注
關(guān)注
43文章
1100瀏覽量
77203
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論