Zynq linux的I2C驱动学习笔记
?
最近在用米爾的Z-TURN BOARD單板做小項目。順便也加強學習I2C驅動,記一篇做記錄。?
I2C總線知識非常簡單,SDA,SCL,他們的時序規則是:I2C總線是由數據線SDA和時鐘SCL構成的串行總線,可發送和接收數據。在CPU與被控IC之間、IC與IC之間進行雙向傳送,最高傳送速率100kbps。各種被控制電路均并聯在這條總線上,但就像電話機一樣只有撥通各自的號碼才能工作,所以每個電路和模塊都有唯一的地址,在信息的傳輸過程中,I2C總線上并接的每一模塊電路既是主控器(或被控器),又是發送器(或接收器),這取決于它所要完成的功能。CPU發出的控制信號分為地址碼和控制量兩部分,地址碼用來選址,即接通需要控制的電路,確定控制的種類;控制量決定該調整的類別(如對比度、亮度等)及需要調整的量。這樣,各控制電路雖然掛在同一條總線上,卻彼此獨立,互不相關。?
I2C總線在傳送數據過程中共有三種類型信號, 它們分別是:開始信號、結束信號和應答信號。?
開始信號:SCL為高電平時,SDA由高電平向低電平跳變,開始傳送數據。?
結束信號:SCL為高電平時,SDA由低電平向高電平跳變,結束傳送數據。?
應答信號:接收數據的IC在接收到8bit數據后,向發送數據的IC發出特定的低電平脈沖,表示已收到數據。CPU向受控單元發出一個信號后,等待受控單元發出一個應答信號,CPU接收到應答信號后,根據實際情況作出是否繼續傳遞信號的判斷。若未收到應答信號,由判斷為受控單元出現故障。?
在LINUX系統初始化的過程中,通過?i2c_register_board_info,將所需要的I2C從設備加入一個名為_i2c_board_list雙向循環鏈表,系統在成功加載I2C主設備adapt后,就會對這張鏈表里所有I2C從設備逐一地完成?i2c_client的注冊。?
也就是說,i2c_client和i2c_adapter都是由i2c_core來維護的。?
在xilinx-linux中,i2c從設備是通過dts文件傳遞給內核的,內核通過zynq_init_machine函數注冊所有的i2c從設備,i2c_client.?
I2C的linux必須知道4個結構體:i2c_adapter,i2c_algorithm,i2c_client,i2c_driver?
struct i2c_adapter {?
struct module owner;?
unsigned int class; / classes to allow probing for /?
const struct i2c_algorithm algo; / the algorithm to access the bus /?
void *algo_data;?
/ data fields that are valid for all devices /?
struct rt_mutex bus_lock;?
int timeout; / in jIFfies /?
int retries;?
struct device dev; / the adapter device /?
int nr;?
char name[48];?
struct completion dev_released;?
struct mutex userspace_clients_lock;?
struct list_head userspace_clients;?
struct i2c_bus_recovery_info *bus_recovery_info;?
};?
i2c總線控制器數據依附于algo_data,比如xi2cps,s3c24xx_i2c。?
struct device dev;成員表明i2c_adapter是一個硬件,對應SoC上的I2C控制器。而i2c_algorithm則是這個I2C控制器的底層驅動程序。?
同理:?
struct i2c_client {?
unsigned short flags; / div., see below /?
unsigned short addr; / chip address - NOTE: 7bit /?
/ addresses are stored in the /?
/ LOWER 7 bits /?
char name[I2C_NAME_SIZE];?
struct i2c_adapter adapter; / the adapter we sit on /?
struct i2c_driver driver; / and our access routines /?
struct device dev; / the device structure /?
int irq; / irq issued by device /?
struct list_head detected;?
};?
struct i2c_client代表一個掛載到i2c總線上的i2c從設備,該設備所需要的數據結構,其中包括?
該i2c從設備所依附的i2c主設備?struct i2c_adapter adapter?
該i2c從設備的驅動程序struct i2c_driver driver?
作為i2c從設備所通用的成員變量,比如addr, name等?
該i2c從設備驅動所特有的數據,依附于dev->driver_data下,在i2c_driver中的probe函數中設置這個結構體成員。比如eeprom的eeprom_data。?
所有i2c從設備組成的雙向鏈表:detected?
struct device dev表明struct i2c_client代表的是一個硬件,比如eeprom芯片,或則rtc芯片,通過i2c總線連接到i2c_adapter硬件上。?
而i2c_driver則是這個i2c_client芯片硬件的驅動程序。?
我們一般會對每個I2C字符設備定義一個私有信息結構體,而i2c_client一般被包含在這個私有信息結構體中。看過LDR3源代碼的hacker應該比較清楚。?
i2c_client依附于i2c_adapter,也就是I2C設備和I2C總線控制器的對應關系,一個i2c_adapter可以掛接多個i2c_client,i2c_adapter的struct list_head userspace_clients;結構成員就是所有client的鏈表。?
linux的最新版本基本上支持目前所有的I2C適配器硬件和I2C從設備,但是對于工程師來說,可能要面臨各種情況:為i2c_adapter和i2c_client編寫驅動程序。?
二、I2C核心?
I2C核心是源碼位于drivers/i2c/i2c-core.c,它并不依賴于硬件平臺的接口函數,是I2C總線驅動和設備驅動的紐帶。?
增加/刪除i2c_adapter?
int i2c_add_adapter(struct i2c_adapter adapter) //調用i2c_register_adapter()?
int i2c_del_adapter(struct i2c_adapter adapter)?
增加/刪除i2c_driver?
int i2c_register_driver(struct module owner, struct i2c_driver driver)?
int i2c_add_driver(struct i2c_driver driver) //調用i2c_register_driver?
void i2c_del_driver(struct i2c_driver driver)?
增加/刪除i2c_client?
struct i2c_client i2c_new_device(struct i2c_adapter adap, struct i2c_board_info const info)?
void i2c_unregister_device(struct i2c_client client)?
注:在2.6.30版本之前使用的是i2c_attach_client()和i2c_detach_client()函數。之后attach被merge到了i2c_new_device中,而detach直接被unregister取代。實際上這兩個函數內部都是調用了device_register()和device_unregister()?
I2C傳輸、發送接收?
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()函數用于進行I2C?適配器和I2C?設備之間的一組消息交互,i2c_master_send()函數和i2c_master_recv()函數內部會調用i2c_transfer()函數分別完成一條寫消息和一條讀消息。?
i2c_transfer()本身不能和硬件完成消息交互,它尋找i2c_adapter對應的i2c_algorithm,要實現數據傳送就要實現i2c_algorithm的master_xfer(),這個函數與具體的硬件有關,大部分時間由廠商完成。?
i2c_transfer()通過調用__i2c_transfer()完成I2C通訊:?
int __i2c_transfer(struct i2c_adapter adap, struct i2c_msg msgs, int num)?
{?
unsigned long orig_jiffies;?
int ret, try;?
/ Retry automatically on arbitration loss /?
orig_jiffies = jiffies;?
for (ret = 0, try = 0; try <= adap->retries; try++) {?
ret = adap->algo->master_xfer(adap, msgs, num);?
if (ret != -EAGAIN)?
break;?
if (time_after(jiffies, orig_jiffies + adap->timeout))?
break;?
}?
return ret;?
}?
可見retries為重傳嘗試次數,timeout為超時時間。?
三、Linux I2C總線驅動?
1、I2C適配器的加載和卸除?
加載:申請硬件資源,比如IO地址,中斷號,調用i2c_add_adapter加載適配器?
i2c_add_adapter中會調用i2c_register_adapter函數?
static int i2c_register_adapter(struct i2c_adapter *adap)?
{?
device_register(&adap->dev); //完成I2C主設備adapter的注冊,即注冊object和發送uevent等?
i2c_scan_static_board_info(adap); //注冊i2c_clienlt?
}?
static void i2c_scan_static_board_info(struct i2c_adapter adapter)?
{?
struct i2c_devinfo devinfo;?
down_read(&__i2c_board_lock);?
list_for_each_entry(devinfo, &i2c_board_list, list) {?
if (devinfo->busnum == adapter->nr?
&& !i2c_new_device(adapter,?
&devinfo->board_info))?
dev_err(&adapter->dev,?
“Can’t create device at 0x%02x\n”,?
devinfo->board_info.addr);?
}?
up_read(&i2c_board_lock);?
}?
i2c_new_device調用device_register注冊i2c從設備。?
那么,這個I2C從設備組成的雙向循環鏈表,是什么時候通過什么方式建立起來的呢??
以?/arch/ARM/mach-pxa/saar.c?為例?
static void __init saar_init(void)?
{?
saar_init_i2c();?
}?
static void __init saar_init_i2c(void)?
{?
pxa_set_i2c_info(NULL);?
i2c_register_board_info(0, ARRAY_AND_SIZE(saar_i2c_info));?
}?
static struct i2c_board_info saar_i2c_info[] = {?
[0] = {?
.type = “da9034”,?
.addr = 0x34,?
.platform_data = &saar_da9034_info,?
.irq = PXA_GPIO_TO_IRQ(mfp_to_gpio(MFP_PIN_GPIO83)),?
},?
};?
/ drivers/i2c/i2c-boardinfo.c /?
int __init i2c_register_board_info(int busnum, structi2c_board_info const info, unsigned len)?
{?
struct i2c_devinfo devinfo;?
devinfo->board_info = *info;?
list_add_tail(&devinfo->list, &__i2c_board_list); //將I2C從設備加入該鏈表中
為滿足不同企業的網絡連接需求,海外專線服務提供多種帶寬速率選項,通過靈活、便捷的接入方式,直連運營商骨干互聯網,再透傳訪問全球互聯網內容,助力高質量、高安全的實現全球互聯互通。
總結
以上是生活随笔為你收集整理的Zynq linux的I2C驱动学习笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 部编五年级下册数学《长方体的体积》教学方
- 下一篇: 丝印AENA16SOT-23封装是什么芯