核心中編寫i2c裝置驅動

2021-06-27 20:29:17 字數 4925 閱讀 6972

二、核心中編寫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...