uboot移植i2c
uboot作為kernel啟動的服務程式,內部支援很多的元件。部分需求會想讓uboot支援eeprom儲存或者rtc的功能支援,這樣就需要uboot支援i2c的驅動。下下來的uboot裡面就是有i2c的驅動例子的,這裡就分析一下供移植模仿。
在uboot/drivers/i2c 下面就是幾個i2c驅動的例子。
這裡我們選擇davinci_i2c.c來分析。這個是寫的比較清楚和簡單的。第一步我們需要先定義編譯的條件,在uboot/include/configs/davinci_dm355evm.h 這個板級的配置檔案裡面定義i2c的配置:
/* I2C */
define CONFIG_HARD_I2C
define CONFIG_DRIVER_DAVINCI_I2C
define CONFIG_SYS_I2C_SPEED 400000
define CONFIG_SYS_I2C_SLAVE 0x10 /*
第二步:makefile 裡新增編譯
在uboot/drivers/i2c Makefile裡新增
COBJS-$(CONFIG_DRIVER_DAVINCI_I2C) += davinci_i2c.o
比對第一步就可以知道這個功能就可以保證davinc_i2c.c可以被編譯了。
第三步:完成兩個必須的函式。這裡要看一個關鍵的檔案。因為uboot是沒有i2c的框架的。裡面只是用uboot/include/i2c.h 定義了操作函式,如果想用i2c只要include這個檔案。就可以通過定義的/*
* Probe the given I2C chip address. Returns 0 if a chip responded,
* not 0 on failure.
*/
int i2c_probe(uchar chip);
/*
* Read/Write interface:
* chip: I2C chip address, range 0..127
* addr: Memory (register) address within the chip
* alen: Number of bytes to use for addr (typically 1, 2 for larger
* memories, 0 for register type devices with only one
* register)
* buffer: Where to read/write the data
* len: How many bytes to read/write
*
* Returns: 0 on success, not 0 on failure
*/
int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len);
int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len);
這樣三個函式完成操作了。我們的任務就是實現這三個函式。轉過來看看davinci_i2c.c的原始碼
int i2c_probe(u_int8_t chip)
{
int rc = 1;
if (chip == REG(I2C_OA)) {
return(rc);
}
REG(I2C_CON) = 0;
if (wait_for_bus()) {return(1);}
/* try to read one byte from current (or only) address */
REG(I2C_CNT) = 1;
REG(I2C_SA) = chip;
REG(I2C_CON) = (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP);
udelay (50000);
if (!(REG(I2C_STAT) & I2C_STAT_NACK)) {
rc = 0;
flush_rx();
REG(I2C_STAT) = 0xffff;
} else {
REG(I2C_STAT) = 0xffff;
REG(I2C_CON) |= I2C_CON_STP;
udelay(20000);
if (wait_for_bus()) {return(1);}
}
flush_rx();
REG(I2C_STAT) = 0xffff;
REG(I2C_CNT) = 0;
return(rc);
}
int i2c_read(u_int8_t chip, u_int32_t addr, int alen, u_int8_t *buf, int len)
{
u_int32_t tmp;
int i;
if ((alen < 0) || (alen > 2)) {
printf("%s(): bogus address length %x\n", __FUNCTION__, alen);
return(1);
}
if (wait_for_bus()) {return(1);}
if (alen != 0) {
/* Start address phase */
tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX;
REG(I2C_CNT) = alen;
REG(I2C_SA) = chip;
REG(I2C_CON) = tmp;
tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK);
CHECK_NACK();
switch (alen) {
case 2:
/* Send address MSByte */
if (tmp & I2C_STAT_XRDY) {
REG(I2C_DXR) = (addr >> 8) & 0xff;
} else {
REG(I2C_CON) = 0;
return(1);
}
tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK);
CHECK_NACK();
/* No break, fall through */
case 1:
/* Send address LSByte */
if (tmp & I2C_STAT_XRDY) {
REG(I2C_DXR) = addr & 0xff;
} else {
REG(I2C_CON) = 0;
return(1);
}
tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK | I2C_STAT_ARDY);
CHECK_NACK();
if (!(tmp & I2C_STAT_ARDY)) {
REG(I2C_CON) = 0;
return(1);
}
}
}
/* Address phase is over, now read 'len' bytes and stop */
tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP;
REG(I2C_CNT) = len & 0xffff;
REG(I2C_SA) = chip;
REG(I2C_CON) = tmp;
for (i = 0; i < len; i++) {
tmp = poll_i2c_irq(I2C_STAT_RRDY | I2C_STAT_NACK | I2C_STAT_ROVR);
CHECK_NACK();
if (tmp & I2C_STAT_RRDY) {
buf[i] = REG(I2C_DRR);
} else {
REG(I2C_CON) = 0;
return(1);
}
}
tmp = poll_i2c_irq(I2C_STAT_SCD | I2C_STAT_NACK);
CHECK_NACK();
if (!(tmp & I2C_STAT_SCD)) {
REG(I2C_CON) = 0;
return(1);
}
flush_rx();
REG(I2C_STAT) = 0xffff;
REG(I2C_CNT) = 0;
REG(I2C_CON) = 0;
return(0);
}
int i2c_write(u_int8_t chip, u_int32_t addr, int alen, u_int8_t *buf, int len)
{
u_int32_t tmp;
int i;
if ((alen < 0) || (alen > 2)) {
printf("%s(): bogus address length %x\n", __FUNCTION__, alen);
return(1);
}
if (len < 0) {
printf("%s(): bogus length %x\n", __FUNCTION__, len);
return(1);
}
if (wait_for_bus()) {return(1);}
/* Start address phase */
tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX | I2C_CON_STP;
REG(I2C_CNT) = (alen == 0) ? len & 0xffff : (len & 0xffff) + alen;
REG(I2C_SA) = chip;
REG(I2C_CON) = tmp;
switch (alen) {
case 2:
/* Send address MSByte */
tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK);
CHECK_NACK();
if (tmp & I2C_STAT_XRDY) {
REG(I2C_DXR) = (addr >> 8) & 0xff;
} else {
REG(I2C_CON) = 0;
return(1);
}
/* No break, fall through */
case 1:
/* Send address LSByte */
tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK);
CHECK_NACK();
if (tmp & I2C_STAT_XRDY) {
REG(I2C_DXR) = addr & 0xff;
} else {
REG(I2C_CON) = 0;
return(1);
}
}
for (i = 0; i < len; i++) {
tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK);
CHECK_NACK();
if (tmp & I2C_STAT_XRDY) {
REG(I2C_DXR) = buf[i];
} else {
return(1);
}
}
tmp = poll_i2c_irq(I2C_STAT_SCD | I2C_STAT_NACK);
CHECK_NACK();
if (!(tmp & I2C_STAT_SCD)) {
REG(I2C_CON) = 0;
return(1);
}
flush_rx();
REG(I2C_STAT) = 0xffff;
REG(I2C_CNT) = 0;
REG(I2C_CON) = 0;
return(0);
}
是不是也正好有這三個檔案,並且函式型別和引數都是一樣的呢。檔案中的其他函式都只是這三個核心函式呼叫的。我們做移植的時候也只要實現對應這個標準介面的讀寫註冊函式就可以了。
函式裡面的內容因為沒見soc廠商所用的ip不同,暫存器的配置也就不同。分析也沒有什麼意義,只要保證標準引數傳進來之後我們能夠正確解析對出正確的操作,回覆給正確的狀態就可以了。
相關文章
- uboot移植rtcboot
- 2.12.uboot的移植2-從uboot官方標準uboot開始移植boot
- uboot i2c 操作函式記錄boot函式
- 系統移植——uboot常用命令boot
- uboot1: 啟動流程和移植框架boot框架
- 移植uboot-2015-10(一)boot
- uboot和系統移植擴充套件--主Makefile分析boot套件
- uboot-2012.04.01移植編譯前準備boot編譯
- Uboot功能boot
- uboot-uboot介紹-學習筆記boot筆記
- uboot 新增命令boot
- U8g2圖形庫與STM32移植(I2C,軟體與硬體)
- I2C
- uboot 解壓縮boot
- uboot 命令總結boot
- uboot 結構分析boot
- Uboot基本知識boot
- uboot如何啟動核心boot
- uboot開機logobootGo
- 為什麼要有ubootboot
- I2C協議協議
- uboot-cmd按鍵退出boot
- uboot中rtc頂層分析boot
- uboot-學習筆記boot筆記
- rockchip uboot 應用dts overlaysboot
- hi3531 SDK 編譯 uboot, 改動PHY地址, 改動 uboot 引數 .編譯boot
- I2C 匯流排
- uboot顯示logo的方式bootGo
- uboot常用命令及其使用boot
- Linux:uboot啟動流程分析Linuxboot
- uboot中MAC網路(待續)bootMac
- i2c除錯工具分享除錯
- I2C系統框架(1)框架
- ncurses庫移植
- uboot中start.s原始碼指令boot原始碼
- uboot環境變數實現分析boot變數
- 【esp32 專案】使用I2C第一篇——I2C的科普
- UART,I2C,SPI 介面總結