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不同,寄存器的配置也就不同。分析也没有什么意义,只要保证标准参数传进来之后我们能够正确解析对出正确的操作,回复给正确的状态就可以了。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-23 17:30:24

uboot移植i2c的相关文章

I.MX6Q(TQIMX6Q/TQE9)学习笔记——新版BSP之u-boot移植

前段时间就开始学习I.MX6Q了,但是最近工作实在是忙,间断了一些时间了.为了提高移植效率,还是考虑移植Freescale维护的3.10版本的内核. 源码获取 Freescale维护的3.10的内核是使用git管理的,但是直接使用git下载代码会比较慢,下面是我下载好的uboot和kernel: I.MX6Q BSP源码(Freescale官方维护) 代码下载好后,先将u-boot解压到工作目录,然后在终端下切换到uboot根目录.由于这个版本的bsp是使用git管理的,因此,需要切换到指定分支

PowerPC平台 u-boot 移植

PowerPC功能很强的通信处理器,支持1000M以太网接口,以Freescale的P1010处理器为开发平台,讲述移植linux的整个过程,与大家分享. 1.配置交叉编译链 网上下载交叉编译工具,配置环境变量 sudo gedit /etc/environment 在末尾添加交叉编译链路径 :/home/freescale/work/tools/freescale/bin log out(不需要重启),输入如下,验证交叉编译是否安装成功: [email protected]:~/work/u-

uboot移植总结

1.uboot的介绍及体系结构 1.1 uboot的介绍 Uboot是德国DENX小组的开发用于多种嵌入式CPU的bootloader程序, UBoot不仅仅支持嵌入式Linux系统的引导,当前,它还支持NetBSD, VxWorks, QNX, RTEMS, ARTOS, LynxOS嵌入式操作系统.UBoot除了支持PowerPC系列的处理器外,还能支持MIPS. x86.ARM.NIOS.XScale等诸多常用系列的处理器. 1.2 uboot的体系结构 目录树 |--board |--c

嵌入式linux开发uboot移植(三)——uboot启动过程源码分析

嵌入式linux开发uboot移植(三)--uboot启动过程源码分析 一.uboot启动流程简介 与大多数BootLoader一样,uboot的启动过程分为BL1和BL2两个阶段.BL1阶段通常是开发板的配置等设备初始化代码,需要依赖依赖于SoC体系结构,通常用汇编语言来实现:BL2阶段主要是对外部设备如网卡.Flash等的初始化以及uboot命令集等的自身实现,通常用C语言来实现. 1.BL1阶段 uboot的BL1阶段代码通常放在start.s文件中,用汇编语言实现,其主要代码功能如下:

uboot移植

Uboot移植 1.架构 board:与一些开发板相关的配置文件 common:uboot下使用能够使用的命令 CPU:与特定CPU架构相关的目录 disk:对磁盘的支持 doc:文档目录 drivers:uboot支持的设备驱动程序放置的地方,比如:网卡.Flash.串口和USB等. fs:支持的文件系统 include:uboot使用的头文件 lib_xxx:与架构有关的库文件 net:与网络协议栈有关的代码 tools:用于生成uboot的工具 2.启动 启动过程: 系统复位进入u-boo

嵌入式linux开发uboot移植(二)——uboot工程源码目录分析

嵌入式linux开发uboot移植(二)--uboot工程源码目录分析 本文分析的uboot为uboot_smdkv210,是三星官方发布的基于S5PV210评估开发板对应的uboot. 一.uboot源码目录结构解析 1.cpu 本文件夹下的子文件与处理器相关,每个文件夹代表一种CPU系列.每个子目录中都包括cpu.c.interrupts.c.start.S文件. cpu.c主要用于初始化CPU.设置指令Cache和数据Cache等 interrupt.c主要用于设置系统的各种中断和异常 s

U-Boot移植之前期分析(上)

老是看别人移植uboot,用别人移植好的uboot,今天终于下定决心自己移植一个uboot来玩玩,好歹我也是个软件开发人员啊. 第一步:去ftp://ftp.denx.de/pub/u-boot/网站下载个uboot工程源码,为了防止环境出问题,我决定用个老一点的,于是就下了:u-boot-1.1.6.tar.bz2. 第二步:解压源码:tar  jxvf  u-boot-1.1.6.tar.bz2. 第三步:建立source insight工程 好了完成以上三步之后,我们需要的前提条件都准备好

U-Boot移植之前期分析(下)

接U-Boot移植之前期分析(上): 2. 顶层目录下mkconfig的分析过程 在上面的分析中知道了语句:"@$(MKCONFIG) $(@:_config=) arm arm920t MY_JZ2440 sumsung s3c24x0"对应于执行顶层目录下的mkconfig文件并传递了六个参数 ($0-$6):100ask24x0 arm arm920t 100ask24x0 NULL s3c24x0.下面分析这句话的到底做了什么事情,具体可以阅读源码,由于比较简单这里直接列出具体

uboot移植——uboot源码目录分析

uboot移植(一)--uboot源码目录分析 本文分析的uboot是九鼎官方提供的,是对应s5pv210开发板x210bv3的uboot 一:uboot的概念及移植的原理. uboot就是在内核运行前的一段小程序,用来初始化硬件设备,建立内存空间映射图.从而将系统的软硬件带到合适的状态,主要功能就是为了启动内核,它将内核从flash中拷贝到ddr中,然后跳转到内核入口中,交由内核控制权,uboot严重依赖硬件,因此一个通用的uboot不太可能. 移植原理:uboot中有很多平行代码,各自属于各