Linux I 2 Cコア

5083 ワード

I 2 Cコア(drivers/i 2 c/i 2 c-core.c)には、ハードウェアプラットフォームに依存しないインタフェース関数のセットが提供されています.このファイルは、一般的にエンジニアによって変更される必要はありませんが、I 2 Cバスドライバとデバイスドライバの間でI 2 Cコアに依存しているため、主な関数を理解することが重要です.I 2 Cコアにおける主な関数は以下の通りである.
(1)i 2 c_の追加/削除adapter.
int i2c_add_adapter(struct i2c_adapter *adap);
int i2c_del_adapter(struct i2c_adapter *adap);
(2)i 2 c_の追加/削除driver.
int i2c_register_driver(struct module *owner, struct *driver);
int i2c_del_driver(struct i2c_driver *driver);
inline int i2c_add_driver(struct i2c_driver *driver);
(3)i2c_Client依存/離脱.
int i2c_attach_client(struct i2c_client *client);
int i2c_detach_client(struct i2c_client *client);
特定のclientが検出され、関連付けられると、デバイスおよびsysfsファイルが登録される.逆に、clientが関連付けられていない場合、sysfsファイルとデバイスもログアウトされます.コードは次のようになります.
int i2c_attach_client(struct i2c_client *client)
{
	struct i2c_adapter *adapter = client->adapter;
	int res = 0;

	mutex_lock(&adapter->clist_lock);
	if (__i2c_check_addr(client->adapter, client->addr)) {
		res = -EBUSY;
		goto out_unlock;
	}
	list_add_tail(&client->list,&adapter->clients);

	client->usage_count = 0;

	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;
		client->dev.uevent_suppress = 1;
	} else
		client->dev.release = i2c_client_dev_release;

	snprintf(&client->dev.bus_id[0], sizeof(client->dev.bus_id),
		"%d-%04x", i2c_adapter_id(adapter), client->addr);
	dev_dbg(&adapter->dev, "client [%s] registered with bus id %s
", client->name, client->dev.bus_id); res = device_register(&client->dev); if (res) goto out_list; mutex_unlock(&adapter->clist_lock); if (adapter->client_register) { if (adapter->client_register(client)) { dev_dbg(&adapter->dev, "client_register " "failed for client [%s] at 0x%02x
", client->name, client->addr); } } return 0; out_list: list_del(&client->list); dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x " "(%d)
", client->name, client->addr, res); out_unlock: mutex_unlock(&adapter->clist_lock); return res; }
(4)I 2 C送信、送信、および受信.
int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num);
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);
i2c_Transfer()関数は、I 2 CアダプタとI 2 Cデバイスとの間のメッセージインタラクションのセットを行うために使用され、
i2c_master_send()関数とi 2 c_master_recv()関数の内部でi 2 c_が呼び出されます.Transfer()関数は、それぞれ1つの書き込みメッセージと1つの読み取りメッセージを完了します.
コードは次のとおりです.
i2c_master_send
int i2c_master_send(struct i2c_client *client,const char *buf ,int count)
{
	int ret;
	struct i2c_adapter *adap=client->adapter;
	struct i2c_msg msg;
        // 
	msg.addr = client->addr;
	msg.flags = client->flags & I2C_M_TEN;
	msg.len = count;
	msg.buf = (char *)buf;
        // 
	ret = i2c_transfer(adap, &msg, 1);

	/* If everything went ok (i.e. 1 msg transmitted), return #bytes
	   transmitted, else error code. */
	return (ret == 1) ? count : ret;
}
i2c_master_recv
int i2c_master_recv(struct i2c_client *client, char *buf ,int count)
{
	struct i2c_adapter *adap=client->adapter;
	struct i2c_msg msg;
	int ret;
        // 
	msg.addr = client->addr;
	msg.flags = client->flags & I2C_M_TEN;
	msg.flags |= I2C_M_RD;
	msg.len = count;
	msg.buf = buf;
        // 
	ret = i2c_transfer(adap, &msg, 1);

	/* If everything went ok (i.e. 1 msg transmitted), return #bytes
	   transmitted, else error code. */
	return (ret == 1) ? count : ret;
}

i2c_Transfer()関数自体は、i 2 c_を探しているだけで、アダプタの物理ハードウェアを駆動してメッセージインタラクションを完了する能力を備えていません.adapter対応i 2 c_Algorithm、i 2 c_を使用Algorithmのmaster_xfer()関数はハードウェアプロセスを本当に駆動します.
i2c_transfer
int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num)
{
	int ret;

	if (adap->algo->master_xfer) {
#ifdef DEBUG
		for (ret = 0; ret < num; ret++) {
			dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
				"len=%d%s
", ret, (msgs[ret].flags & I2C_M_RD) ? 'R' : 'W', msgs[ret].addr, msgs[ret].len, (msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : ""); } #endif mutex_lock_nested(&adap->bus_lock, adap->level); ret = adap->algo->master_xfer(adap,msgs,num);// algo master_xfer mutex_unlock(&adap->bus_lock); return ret; } else { dev_dbg(&adap->dev, "I2C level transfers not supported
"); return -ENOSYS; } }