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.
i2c_master_send()関数とi 2 c_master_recv()関数の内部でi 2 c_が呼び出されます.Transfer()関数は、それぞれ1つの書き込みメッセージと1つの読み取りメッセージを完了します.
コードは次のとおりです.
i2c_master_send
i2c_Transfer()関数自体は、i 2 c_を探しているだけで、アダプタの物理ハードウェアを駆動してメッセージインタラクションを完了する能力を備えていません.adapter対応i 2 c_Algorithm、i 2 c_を使用Algorithmのmaster_xfer()関数はハードウェアプロセスを本当に駆動します.
i2c_transfer
(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;
}
}