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);

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

}

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);

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87

}

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);

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73


是不是也正好有这三个文件,并且函数类型和参数都是一样的呢。文件中的其他函数都只是这三个核心函数调用的。我们做移植的时候也只要实现对应这个标准接口的读写注册函数就可以了。

函数里面的内容因为没见soc厂商所用的ip不同,寄存器的配置也就不同。分析也没有什么意义,只要保证标准参数传进来之后我们能够正确解析对出正确的操作,回复给正确的状态就可以了。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值