uboot移植i2c

来源:互联网 发布:股票实时数据api 编辑:程序博客网 时间:2024/06/07 22:09

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

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 四年级解方程应用题 二年级上数学应用题 二年级乘除法应用题 2年级下册数学应用题 七年级上数学应用题 三年级上册数学应用题 二年级下册数学应用题 四年级上册数学应用题 四年级上册数学应用题100道 五年级上册数学应用题 小学二年级数学应用题 二年级数学下册应用题大全 三年级下册数学应用题 小学六年级数学应用题 六年级下册数学应用题 七年级上册数学应用题 四年级鸡兔同笼应用题 五年级小数除法应用题 五年级下册数学应用题 三年级上期数学应用题 小学三年级时间应用题 小学二年级数学应用题大全 小学三年级数学应用题上册 六年级工程问题应用题 六年级数学比例应用题 六年级数学工程应用题 五年级鸡兔同笼应用题 10以内的加减法应用题 五年级上册小数除法应用题 小学二年级数学应用题上册 小学三年级上册数学应用题 二年级数学除法应用题 小学二年级除法应用题 二年级下册奥数应用题 七年级数学方程应用题 五年级数学方程应用题 小学数学四年级应用题 小学四年级上册数学应用题 六年级数学方程应用题 二年级上学期数学应用题 小学五年级上册应用题