利用Linux中IIC設(shè)備子系統(tǒng)移植IIC設(shè)備驅(qū)動

創(chuàng)新互聯(lián)專注于網(wǎng)站建設(shè)|網(wǎng)站維護(hù)|優(yōu)化|托管以及網(wǎng)絡(luò)推廣,積累了大量的網(wǎng)站設(shè)計(jì)與制作經(jīng)驗(yàn),為許多企業(yè)提供了網(wǎng)站定制設(shè)計(jì)服務(wù),案例作品覆蓋成都會所設(shè)計(jì)等行業(yè)。能根據(jù)企業(yè)所處的行業(yè)與銷售的產(chǎn)品,結(jié)合品牌形象的塑造,量身制作品質(zhì)網(wǎng)站。
背景描述
IIC總線在嵌入式系統(tǒng)中應(yīng)用十分廣泛,常見的有eeprom,rtc。一般的處理器會包含IIC的控制器,用來完成IIC時序的控制;另外一方面,由于IIC的時序簡單,使用GPIO口來模擬時序也是常見的做法。面對不同的IIC控制器,各種各樣的芯片以及l(fā)inux源碼,如何更快做好IIC設(shè)備驅(qū)動。
問題描述
在我們的方案中,我們會用到eeprom,rtc以及tw2865。由于Hi3520的IIC控制器設(shè)計(jì)有問題,無法正常使用。而IIC控制器的SDA和SCL管腳正好是和兩個GPIO管腳復(fù)用的。Hisi將控制gpio來實(shí)現(xiàn)IIC的時序,從而對IIC設(shè)備進(jìn)行操作。這種設(shè)計(jì)方式簡單明了,但使用IIC子系統(tǒng),可以更方便的移植和維護(hù)其他的設(shè)備驅(qū)動。
問題分析
Hisi對于gpio口,rtc芯片以及tw2865的處理方式如下:將gpio口做成一個模塊化的驅(qū)動,該驅(qū)動模擬IIC時序,并向外提供一些函數(shù)接口,比如:EXPORT_SYMBOL(gpio_i2c_read_tw2815);等。對于具體的rtc芯片,將其注冊為一個misc設(shè)備,并利用gpio模塊導(dǎo)出的函數(shù)進(jìn)行rtc芯片的配置操作。
其實(shí)對于linux-2.6.24\drivers\i2c目錄下代碼,我們可以加以利用。
Linux的IIC字結(jié)構(gòu)分為三個組成部分:
IIC核心
IIC核心提供了IIC總線驅(qū)動和設(shè)備驅(qū)動的注冊、注銷方法,IICalgorithm上層的、與具體適配器無關(guān)的代碼以及探測設(shè)備、檢測設(shè)備地址的上層代碼。
IIC總線驅(qū)動
IIC總線驅(qū)動是對IIC硬件體系結(jié)構(gòu)中適配器端的實(shí)現(xiàn)。
IIC設(shè)備驅(qū)動
IIC設(shè)備驅(qū)動是對IIC硬件體系總設(shè)備端的實(shí)現(xiàn)。
我們查看下該目錄下的makefile和kconfig:
obj-$(CONFIG_I2C_BOARDINFO) +=i2c-boardinfo.o
obj-$(CONFIG_I2C) += i2c-core.o
obj-$(CONFIG_I2C_CHARDEV) +=i2c-dev.o
obj-y +=busses/ chips/ algos/
i2c-core.c就是IIC核心,buses中的文件是主流處理器中IIC總線的總線驅(qū)動,而chips中的文件就是常用芯片的驅(qū)動,algos中的文件實(shí)現(xiàn)了一些總線適配器的algorithm,其中就包括我們要用到的i2c-algo-bit.c文件。
我們首先利用i2c-gpio.c和i2c-algo-bit.c做好總線驅(qū)動。
在i2c-gpio.c中,module_init?i2c_gpio_init?platform_driver_probe(i2c_gpio_driver,i2c_gpio_probe);
將其注冊為platform虛擬總線的驅(qū)動。
在staticint __init i2c_gpio_probe(struct platform_device *pdev)中,
定義了如下三個結(jié)構(gòu)體:
structi2c_gpio_platform_data *pdata;//平臺相關(guān)的gpio的設(shè)置
structi2c_algo_bit_data *bit_data;//包含algorithm的具體函數(shù),setor
get SDA和SCL
structi2c_adapter *adap;//適配器
i2c_gpio_probe主要做了下面幾件事:
填充bit_data結(jié)構(gòu)的各個函數(shù)指針,關(guān)聯(lián)到具體的操作SDA和SCl函數(shù)。
填充adap結(jié)構(gòu),adap-algo_data= bit_data;
pdata= pdev-dev.platform_data;
bit_data-data= pdata;
pdev-dev-driver_data= adap;
在i2c-core中注冊適配器類型。
inti2c_bit_add_numbered_bus(struct i2c_adapter *adap)
在staticint i2c_bit_prepare_bus(struct i2c_adapter *adap)中
adap-algo= i2c_bit_algo;
將i2c_bit_algo與adap關(guān)聯(lián)上。
static const structi2c_algorithm i2c_bit_algo = {
.master_xfer = bit_xfer,
.functionality = bit_func,
};
其中,master_xfer函數(shù)指針就是IIC傳輸函數(shù)指針。
I2c-algo-bit.c還實(shí)現(xiàn)了IIC開始條件,結(jié)束條件的模擬,發(fā)送字節(jié),接收字節(jié)以及應(yīng)答位的處理。
i2c-gpio.c中的i2c_gpio_setsda_val等函數(shù)是與具體平臺gpio相關(guān)的。
修改對應(yīng)arch-hi3520v100目錄下的gpio.h中的各個函數(shù),這些函數(shù)是通過操作寄存器來控制gpio的方向和值。
在對應(yīng)mach-hi3520v100中的platform-devices.c中添加如下:
static structi2c_gpio_platform_data pdata = {
.sda_pin = 10,
.sda_is_open_drain = 1,
.scl_pin = 11,
.scl_is_open_drain = 1,
.udelay = 4, /* ~100 kHz */
};
static struct platform_devicehisilicon_i2c_gpio_device = {
.name = "i2c-gpio",
.id = -1,
.dev.platform_data = pdata,
};
static struct platform_device*hisilicon_plat_devs[] __initdata = {
hisilicon_i2c_gpio_device,
};
int __inithisilicon_register_platform_devices(void)
{
platform_add_devices(hisilicon_plat_devs,ARRAY_SIZE (hisilicon_plat_devs));
return 0;
}
通過platform添加devices和driver,使得pdev-dev.platform_data=pdata
綜合上面的過程,我們完成了adapter的注冊,并將用gpio口模擬的algorithm與adapter完成了關(guān)聯(lián)。
這樣,在rtc-x1205.c中,x1205_attach函數(shù)利用i2c核心完成client和adap的關(guān)聯(lián)。
在x1205_probe函數(shù)中填充i2c_client結(jié)構(gòu)體,并調(diào)用i2c_attach_client通知iic核心。
接著注冊rtc驅(qū)動。
最后我們要讀取時間,就需要構(gòu)造i2c_msg結(jié)構(gòu)體,如下所示:
struct i2c_msg msgs[] = {
{ client-addr, 0, 2,dt_addr }, /* setup read ptr */
{ client-addr, I2C_M_RD,8, buf }, /* read date */
};
/* read date registers */
if((i2c_transfer(client-adapter, msgs[0], 2)) != 2) {
dev_err(client-dev,"%s: read error\n", __FUNCTION__);
return -EIO;
}
dt_addr是寄存器的地址,I2C_M_RD表示iicread。
最近我也遇到這個問題了,糾結(jié)了一天,在網(wǎng)友的支持下解決了,這個天嵌的版本中,i2c和他的攝像頭驅(qū)動(OV9650驅(qū)動)相沖突,你在編譯內(nèi)核之前,將攝像頭的驅(qū)動全部去掉,這樣子重新編譯之后,i2c就可以正常測試使用了。
假設(shè)手上有一塊從淘寶上買來的開發(fā)板,我要在開發(fā)板的I2C總線上增加一個從設(shè)備(如at24c08),那么我要怎樣寫這個“I2C設(shè)備驅(qū)動”,讓
應(yīng)用程序可以訪問at24c08呢?
先來看一個最簡單的i2c設(shè)備驅(qū)動:
static struct i2c_board_info at24cxx_info = { //所支持的i2c設(shè)備的列表
I2C_BOARD_INFO("at24c08", 0x50), //一項(xiàng)代表一個支持的設(shè)備,它的名字叫做“at24c08”,器件地址是0x50
};
static struct i2c_client *at24cxx_client;
static int at24cxx_dev_init(void)
{
struct i2c_adapter *i2c_adap; //分配一個適配器的指針
i2c_adap = i2c_get_adapter(0); //調(diào)用core層的函數(shù),獲得一個i2c總線。這里我們已經(jīng)知道新增的器件掛接在編號為0的i2c總線上
at24cxx_client = i2c_new_device(i2c_adap, at24cxx_info); // 把i2c適配器和新增的I2C器件關(guān)聯(lián)起來,這個用了i2c總線0,地址是0x50。這就組成了一個客戶端
at24cxx_client i2c_put_adapter(i2c_adap);
return 0;
}
static void at24cxx_dev_exit(void)
{
i2c_unregister_device(at24cxx_client);
}
module_init(at24cxx_dev_init);
module_exit(at24cxx_dev_exit);
當(dāng)前文章:linuxi2c的命令 linux讀i2c總線命令
本文URL:http://chinadenli.net/article8/hppoip.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供建站公司、電子商務(wù)、定制開發(fā)、小程序開發(fā)、商城網(wǎng)站、網(wǎng)站改版
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)