二、核心中編寫i2c裝置驅動
核心編寫i2c裝置驅動支援兩種方式:adapter方式(legacy)和probe方式(new style)。
1.legacy方式
此方法驅動需要自己建立i2c_client,並且要知道晶元的位址,在核心目錄documentation/i2c/upgrading-clients中有乙個例程。
i2c_driver構建
static struct i2c_driver at24c02_driver = ,
.id = i2c_driverid_eeprom,
.attach_adapter = at24c02_attach_adapter,
.detach_client = at24c02_detach_client,
};i2c裝置驅動的載入與解除安裝函式模板
static int __init at24c02_init(void)
i2c_add_driver的執行回引發i2c_driver結構體at24c02_attach_adapter的執行,若核心中註冊了i2c介面卡,就順序呼叫這些介面卡來連線i2c裝置,at24c02_attach_adapter呼叫i2c核心i2c_probe探測裝置
static int at24c02_attach_adapter(struct i2c_adapter *adapter)
static unsigned short normal_i2c = ;
/* insmod parameters */
i2c_client_insmod_1(at24c02);
其中第二個引數add_data是i2c_client_address_data型別的變數,由normal_i2c通過巨集i2c_client_insmod_1構建而成,具體方法參考i2c.h檔案。normal_i2c是i2c晶元的位址,如果位址與晶元對應不上,無法探測到裝置,當探測到目標裝置後,呼叫at24c02_detect,把探測到得位址address作為引數傳入。
#define at24c02_major 250
static int at24c02_major = at24c02_major;
struct at24c02_data ;
static int at24c02_detect(struct i2c_adapter *adapter, int address, int kind)
new_client = &data->client;
memset(data->data, 0xff, eeprom_size);
i2c_set_clientdata(new_client, data);
new_client->addr = address;
new_client->adapter = adapter;
new_client->driver = &at24c02_driver;
new_client->flags = 0;
/* fill in the remaining client fields */
strlcpy(new_client->name, "at24c02", i2c_name_size);
mutex_init(&data->update_lock);
/* tell the i2c layer a new client has arrived */
if ((err = i2c_attach_client(new_client)))
goto exit_kfree;
if(at24c02_major)
else
if(result<0)
at24c02_setup_cdev(data,0); //註冊字元裝置at24c02_fops
return 0;
exit_detach:
i2c_detach_client(new_client);
exit_kfree:
kfree(data);
exit:
return err;
}static void at24c02_setup_cdev(struct at24c02_data *dev,int index)
i2c裝置驅動解除安裝函式進行i2c_del_driver呼叫後,順序呼叫核心中註冊的介面卡斷開註冊過的i2c裝置,此過程是呼叫at24c02_detach_client實現的。
static void __exit at24c02_exit(void)
static int at24c02_detach_client(struct i2c_client *client)
字元驅動的實現
struct file_operations at24c02_fops = ;
字元裝置驅動不在詳述,主要說明如何呼叫介面卡完成資料傳輸。首先構造訊息,通過i2c_transfer來傳遞,i2c_transfer找到對應介面卡algorithm通訊方法master_xfer最終完成i2c訊息處理。下面是乙個關於裝置驅動的讀函式,其他類似。
static int at24c02_open(struct inode *inode, struct file *file)
static int at24c02_read(struct file *filp, char __user *buff,size_t count, loff_t *offp)
msg[0].addr = data->client->addr;
msg[0].flags = 0; /* write */
msg[0].len = 1; /* 1個位址 */
msg[0].buf = &addr;
msg[1].addr = data->client->addr;
msg[1].flags = i2c_m_rd; /* read */
msg[1].len = count; /* 要讀的資料個數 */
msg[1].buf = data->data;
ret = i2c_transfer(at24c02_client->adapter, msg, 2);
if (ret == 2)
else
return -eio;
}目前介面卡主要支援的傳輸方法有兩種:master_xfer和smbus_xfer,從i2c_algorithm結構體可看出。一般來說,若介面卡支援master_xfer那麼它可以模擬支援smbus,但只實現smbus_xfer,則不支援master_xfer傳輸。當然,上面的驅動也可以採用smbus方式完成傳輸。採用legacy方式在2.6.32.2核心下編譯不過去,主要是i2c核心中有些函式不存在,所以,裝置驅動發展方向是new style方式。
2.new style方式
構建i2c_driver
static struct i2c_driver at24c02_driver = ,
.probe = at24c02_probe,
.remove = __devexit_p(at24c02_remove),
.id_table = at24c02_id,
};載入與登出
static int __init at24c02_init(void)
module_init(at24c02_init);
i2c_add_driver會將驅動註冊到匯流排上,探測到i2c裝置就會呼叫at24c02_probe,探測主要是用i2c_match_id函式比較client的名字和id_table中名字,如果相等,則探測到i2c裝置,本驅動中id_table如下:
static const struct i2c_device_id at24c02_id = ,
};module_device_table(i2c, at24c02_id);
module_device_table巨集是用來生成i2c_device_id。在legacy方式中i2c_client是自己建立的,而此處的i2c_client如何得到?實際上是在i2c_register_board_info函式註冊i2c_board_info過程中構建的,所以arch/arm/mach-s3c2440/mach-smdk2440.c中新增註冊資訊。
static struct i2c_board_info i2c_devices __initdata = , };
static void __init smdk2440_machine_init(void)
如果沒有註冊i2c資訊,就探測不到i2c裝置。探測到at24c02裝置後就會呼叫at24c02_probe函式。
static int __devinit at24c08b_probe(struct i2c_client *client,const struct i2c_device_id *id)
memset(data, 0, sizeof(struct at24c02_data));
data->client=client;
i2c_set_clientdata(client, data);
if(at24c02_major)
else
if(result<0)
at24c02_setup_cdev(data,0); //註冊字元裝置at24c02_fops
return 0;
exit_kfree:
kfree(data);
exit:
return err;
}probe函式主要註冊了字元裝置,通過data->client=client獲得的相關資訊。關於at24c02_fops結構體的完善,由於與前面一種方法類似,這裡就不詳述。最後就是驅動的登出。
static void __exit at24c02_exit(void)
module_exit(at24c02_exit);
static int __devexit at24c02_remove(struct i2c_client *client)
I2C裝置驅動的編寫
前面我們說了如何i2c使用者模式驅動,這種驅動基於i2c子系統,但是他對於應用程式開發人員的要求較高,需要應用程式開發人員了解硬體的一些東西,比如時序,位址等等,而多數時候應用程式開發人員是按照操作檔案的方法操作裝置,所以我們更希望用一些更簡單的介面去訪問。也就是我們今天的內容 基於i2c子系統的字...
I2C裝置驅動的編寫 二
前面我們說了如何i2c使用者模式驅動,這種驅動基於i2c子系統,但是他對於應用程式開發人員的要求較高,需要應用程式開發人員了解硬體的一些東西,比如時序,位址等等,而多數時候應用程式開發人員是按照操作檔案的方法操作裝置,所以我們更希望用一些更簡單的介面去訪問。也就是我們今天的內容 基於i2c子系統的字...
i2c裝置驅動
1,i2c 裝置註冊 static struct i2c board info i2c2 devices i2c裝置一般在板級 中註冊 static void msm8916 add i2c deivces void 2,i2c驅動註冊 include static const struct i2c...