--- c/src/lib/libbsp/arm/beagle/i2c/bbb-i2c.c | 684 ++++++++++++++++++++++++++++-- c/src/lib/libbsp/arm/beagle/include/i2c.h | 18 +- cpukit/dev/i2c/eeprom.c | 24 +- testsuites/samples/i2c0/init.c | 98 ++++- 4 files changed, 777 insertions(+), 47 deletions(-)
diff --git a/c/src/lib/libbsp/arm/beagle/i2c/bbb-i2c.c b/c/src/lib/libbsp/arm/beagle/i2c/bbb-i2c.c index 6b790e5..6a22125 100644 --- a/c/src/lib/libbsp/arm/beagle/i2c/bbb-i2c.c +++ b/c/src/lib/libbsp/arm/beagle/i2c/bbb-i2c.c @@ -21,11 +21,23 @@ #include <bsp/bbb-gpio.h> #include <rtems/score/assert.h> +#define u16 unsigned int + +static int am335x_i2c_set_clock(i2c_bus *base, unsigned long clock); +static void omap24_i2c_init(i2c_bus *base); +static void flush_fifo(i2c_bus *base); +static int wait_for_bb(i2c_bus *base); +static int omap24_i2c_probe(i2c_bus *base); +static u16 wait_for_event(i2c_bus *base); +static int am335x_i2c_read(i2c_bus *base, unsigned char chip, uint addr, int alen, unsigned char *buffer, + int len); +static int read_eeprom(i2c_bus *base,struct am335x_baseboard_id *header); +static int am335x_i2c_write(i2c_bus *base, unsigned char chip, uint addr,int alen, unsigned char *buffer, + int len); /* static bool am335x_i2c_pinmux(bbb_i2c_bus *bus) { bool status =true; - // We will check i2c_bus_id in am335x_i2c_bus_register // Apart from mode and pull_up register what about SCREWCTRL & RXACTIVE ?? if (bus->i2c_bus_id == I2C1) { @@ -48,9 +60,7 @@ static bool am335x_i2c_pinmux(bbb_i2c_bus *bus) /* ref. Table 21-4 I2C Clock Signals */ /* For I2C1/2 - Interface clock - 100MHz - CORE_LKOUTM4 / 2 - pd_per_l4ls_gclk - Functional clock - 48MHz - PER_CLKOUTM2 / 4 - pd_per_ic2_fclk */ @@ -74,7 +84,6 @@ state. Functional clocks are guarantied to stay present. As long as in this configuration, power domain sleep transition cannot happen.*/ /* REG(AM335X_CM_PER_ADDR + AM335X_CM_PER_L4LS_CLKCTRL) |= AM335X_CM_PER_L4LS_CLKCTRL_MODULEMODE_ENABLE; - while((REG(AM335X_CM_PER_ADDR + AM335X_CM_PER_L4LS_CLKCTRL) & AM335X_CM_PER_L4LS_CLKCTRL_MODULEMODE) != AM335X_CM_PER_L4LS_CLKCTRL_MODULEMODE_ENABLE); */ @@ -86,30 +95,29 @@ this configuration, power domain sleep transition cannot happen.*/ if (bus->i2c_bus_id == I2C1) { REG(AM335X_CM_PER_ADDR + AM335X_CM_PER_I2C1_CLKCTRL) |= AM335X_CM_PER_I2C1_CLKCTRL_MODULEMODE_ENABLE; - while(REG((AM335X_CM_PER_ADDR + AM335X_CM_PER_I2C1_CLKCTRL) & AM335X_CM_PER_I2C1_CLKCTRL_MODULEMODE) != AM335X_CM_PER_I2C1_CLKCTRL_MODULEMODE_ENABLE); } else if (bus->i2c_bus_id == I2C2) { REG(AM335X_CM_PER_ADDR + AM335X_CM_PER_I2C2_CLKCTRL) |= AM335X_CM_PER_I2C2_CLKCTRL_MODULEMODE_ENABLE; - while(REG((AM335X_CM_PER_ADDR + AM335X_CM_PER_I2C2_CLKCTRL) & AM335X_CM_PER_I2C2_CLKCTRL_MODULEMODE) != AM335X_CM_PER_I2C2_CLKCTRL_MODULEMODE_ENABLE); - while(!(REG(AM335X_CM_PER_ADDR + AM335X_CM_PER_L4LS_CLKSTCTRL) & (AM335X_CM_PER_L4LS_CLKSTCTRL_CLKACTIVITY_L4LS_GCLK | AM335X_CM_PER_L4LS_CLKSTCTRL_CLKACTIVITY_I2C_FCLK))); - } } */ static void am335x_i2c0_pinmux(bbb_i2c_bus *bus) { - REG(bus->regs + AM335X_CONF_I2C0_SDA) = + printf("0x44e10000 + AM335X_CONF_I2C0_SDA:%x\n",0x44e10000 + AM335X_CONF_I2C0_SDA); + printf("bus->regs:%x\n", bus->regs); + + REG(0x44e10000 + AM335X_CONF_I2C0_SDA) = (BBB_RXACTIVE | BBB_SLEWCTRL | BBB_PU_EN); - REG(bus->regs + AM335X_CONF_I2C0_SCL) = + REG(0x44e10000 + AM335X_CONF_I2C0_SCL) = (BBB_RXACTIVE | BBB_SLEWCTRL | BBB_PU_EN); } @@ -314,14 +322,29 @@ void am335x_i2c_init(bbb_i2c_bus *bus, uint32_t input_clock) static bool am335x_i2c_busbusy(volatile bbb_i2c_regs *regs) { bool status; - - if (REG(®s->BBB_I2C_IRQSTATUS_RAW) & AM335X_I2C_IRQSTATUS_RAW_BB) + unsigned short stat; + int timeout = I2C_TIMEOUT; + + REG(®s->BBB_I2C_IRQSTATUS)=0xffff; + printf("REG(®s->BBB_I2C_IRQSTATUS_RAW):%x\n",REG(®s->BBB_I2C_IRQSTATUS_RAW) ); + // printf("%x\n",0x1400 & 0x1000 ); + printf("REG(®s->BBB_I2C_IRQSTATUS_RAW) & AM335X_I2C_IRQSTATUS_RAW_BB:%x\n",(REG(®s->BBB_I2C_IRQSTATUS_RAW) & AM335X_I2C_IRQSTATUS_RAW_BB)); +while(stat =( REG(®s->BBB_I2C_IRQSTATUS_RAW) & AM335X_I2C_IRQSTATUS_RAW_BB) && timeout--) { - status = true; - } else { - status = false; + +REG(®s->BBB_I2C_IRQSTATUS)=stat; + udelay(20); + + } + + if (timeout <= 0) { + printf("Timed out in wait_for_bb: status=%04x\n", + stat); + return 1; } - return status; + REG(®s->BBB_I2C_IRQSTATUS)=0xffff; /* clear delayed stuff*/ + return 0; + } static void am335x_i2c_reset(bbb_i2c_bus *bus) @@ -330,9 +353,27 @@ static void am335x_i2c_reset(bbb_i2c_bus *bus) printk("reset bus->reg is %x \n",bus->regs); /* Disable I2C module at the time of initialization*/ /*Should I use write32 ?? I guess mmio_clear is correct choice here*/ + REG(®s->BBB_I2C_CON)=0x00; printk("inside BBB_I2C_CON value is %x \n",®s->BBB_I2C_CON); - mmio_clear((®s->BBB_I2C_CON),AM335X_I2C_CON_I2C_EN); - mmio_clear((®s->BBB_I2C_SYSC),AM335X_I2C_SYSC_AUTOIDLE); + REG(®s->BBB_I2C_SYSC)= 0x2; +// mmio_clear((®s->BBB_I2C_CON),AM335X_I2C_CON_I2C_EN); + + REG(®s->BBB_I2C_CON)= AM335X_I2C_CON_I2C_EN; + + while((REG(®s->BBB_I2C_SYSS) &I2C_SYSS_RDONE)==0) //wait reset done + { + udelay(100); + + } + + REG(®s->BBB_I2C_CON)=0x00; + + am335x_i2c_set_clock(&bus->base, I2C_BUS_CLOCK_DEFAULT); + + REG(®s->BBB_I2C_CON)= AM335X_I2C_CON_MST | AM335X_I2C_CON_I2C_EN; + +// mmio_clear((®s->BBB_I2C_SYSC),AM335X_I2C_SYSC_AUTOIDLE); + //REG(bus->regs + AM335X_I2C_CON) &= ~(AM335X_I2C_CON_I2C_EN); //REG(bus->regs + AM335X_I2C_SYSC) &= ~(AM335X_I2C_SYSC_AUTOIDLE); @@ -385,6 +426,7 @@ static unsigned int am335x_i2c_intrawstatus(volatile bbb_i2c_regs *regs) static void am335x_i2c_masterint_enable(volatile bbb_i2c_regs *regs, unsigned int flag) { + printf("am335x_i2c_masterint_enable func\n"); REG(®s->BBB_I2C_IRQENABLE_SET) |= flag; } @@ -401,6 +443,7 @@ static void am335x_int_clear(volatile bbb_i2c_regs *regs, unsigned int flag) static void am335x_clean_interrupts(volatile bbb_i2c_regs *regs) { + printf("am335x_clean_interrupts func\n"); am335x_i2c_masterint_enable(regs,0x7FFF); am335x_int_clear(regs,0x7FFF); am335x_i2c_masterint_disable(regs,0x7FFF); @@ -412,30 +455,69 @@ static void am335x_i2c_setup_read_transfer(bbb_i2c_bus *bus, volatile bbb_i2c_re volatile unsigned int no_bytes; //am335x_i2c_masterint_enable(regs, AM335X_I2C_INT_RECV_READY); // No of data to be transmitted at a time + + +//bbb_i2c_bus *bus = (bbb_i2c_bus *) base; +// volatile bbb_i2c_regs *regs = bus->regs; + struct am335x_baseboard_id header; + + omap24_i2c_probe(&bus->base); + read_eeprom(&bus->base,&header); + +/* REG(®s->BBB_I2C_CNT) = 0x02; no_bytes = REG(®s->BBB_I2C_CNT); + // Set Slave address & Master enable, bring out of reset + REG(®s->BBB_I2C_SA) = msgs->addr; + printf("slave address : %x\n",REG(®s->BBB_I2C_SA)); + + // I2C Controller in Master Mode - REG(®s->BBB_I2C_CON) = AM335X_I2C_CFG_MST_TX | AM335X_I2C_CON_I2C_EN | AM335X_I2C_CON_START | AM335X_I2C_CON_MST; + REG(®s->BBB_I2C_CON) = AM335X_I2C_CFG_MST_TX | AM335X_I2C_CON_MST | AM335X_I2C_CON_START | AM335X_I2C_CON_I2C_EN | AM335X_I2C_CON_STOP; printk("set master in transmission mode %x \n",REG(®s->BBB_I2C_CON)); - // Set Slave address & Master enable, bring out of reset - REG(®s->BBB_I2C_SA) = msgs->addr; - printf("slave address : %x\n",REG(®s->BBB_I2C_SA)); +while(am335x_i2c_busbusy(regs) != 0); + printk("bus is free \n"); + + + // clear status of all interrupts am335x_clean_interrupts(regs); printk("\n set memory address to read\n"); // transmit interrupt is enabled + am335x_i2c_masterint_enable(regs,AM335X_I2C_IRQSTATUS_XRDY); printk("Enable transmit interrupt \n"); + + + //start condition - REG(®s->BBB_I2C_CON) |= AM335X_I2C_CON_START; + REG(®s->BBB_I2C_CON) |= AM335X_I2C_CON_START | AM335X_I2C_CON_I2C_EN; printk("start transmission \n"); - while(am335x_i2c_busbusy(regs) == 0); - printk("bus is free \n"); + printk("CNT : %x\n", no_bytes); + printf("BBB_I2C_DATA:%x\n", readb(®s->BBB_I2C_DATA)); + +writeb(0x5,®s->BBB_I2C_DATA); +printf("(0x50 >> 8)& 0xff:%x\n",(0x50 >> 8)& 0xff); +printf("REG(®s->BBB_I2C_DATA):%x\n",readb(®s->BBB_I2C_DATA) ); +printf("®s->BBB_I2C_DATA:%x\n",®s->BBB_I2C_DATA); +//REG(®s->BBB_I2C_IRQSTATUS)=AM335X_I2C_IRQSTATUS_XRDY; + +udelay(10); + +writeb(0x0,®s->BBB_I2C_DATA); +//REG(®s->BBB_I2C_DATA)= ( (0x50 >> 0)& 0xff); +printf("(0x50 >> 0)& 0xff:%x\n",(0x50 >> 0)& 0xff); +printf("REG(®s->BBB_I2C_DATA):%x\n",readb(®s->BBB_I2C_DATA) ); + +REG(®s->BBB_I2C_IRQSTATUS)=AM335X_I2C_IRQSTATUS_XRDY; + + + // no_bytes = REG(®s->BBB_I2C_CNT); while(0 != no_bytes); printk("total msg count for tranmission is zero \n"); while( !(am335x_i2c_intrawstatus(regs) & (AM335X_I2C_IRQSTATUS_ARDY))); @@ -464,6 +546,7 @@ static void am335x_i2c_setup_read_transfer(bbb_i2c_bus *bus, volatile bbb_i2c_re REG(®s->BBB_I2C_CON) |= AM335X_I2C_CON_START; } while(am335x_i2c_busbusy(regs) == 0); + */ printk("Exit read transfer\n"); } @@ -570,11 +653,16 @@ static void am335x_i2c_setup_transfer(bbb_i2c_bus *bus, volatile bbb_i2c_regs *r } regs = bus->regs; - - REG(&bus->regs->BBB_I2C_BUF) |= AM335X_I2C_BUF_TXFIFO_CLR; - REG(&bus->regs->BBB_I2C_BUF) |= AM335X_I2C_BUF_RXFIFO_CLR; - am335x_i2c_set_address_size(msgs,regs); - bus->read = ((bus->read == true) ? 0:1); + printf("REG(®s->BBB_I2C_DATA):%x\n",REG(®s->BBB_I2C_DATA) ); + // REG(&bus->regs->BBB_I2C_BUF) |= AM335X_I2C_BUF_TXFIFO_CLR; + // REG(&bus->regs->BBB_I2C_BUF) |= AM335X_I2C_BUF_RXFIFO_CLR; +printf("REG(®s->BBB_I2C_DATA):%x\n",REG(®s->BBB_I2C_DATA) ); + + // am335x_i2c_set_address_size(msgs,regs); +bus->read = (msgs->flags & I2C_M_RD) != 0; + +printf("bus->read:%d\n",bus->read ); + //bus->read = ((bus->read == true) ? 0:1); bus->already_transferred = (bus->read == true) ? 0 : 1; if (bus->read) { @@ -652,7 +740,7 @@ static int am335x_i2c_transfer(i2c_bus *base, i2c_msg *msgs, uint32_t msg_count) bbb_i2c_bus *bus = (bbb_i2c_bus *)base; volatile bbb_i2c_regs *regs; uint32_t i; - printk("\n enter transfer "); + printk("\n enter transfer\n "); rtems_task_wake_after(1); @@ -665,20 +753,23 @@ static int am335x_i2c_transfer(i2c_bus *base, i2c_msg *msgs, uint32_t msg_count) return -EINVAL; } } - + printf("bus->regs:%x\n",bus->regs ); bus->msgs = &msgs[0]; bus->msg_todo = msg_count; printk("total msg = msg_count : %x \n",bus->msg_todo); bus->current_msg_todo = msgs[0].len;// current data size - bus->current_msg_byte = msgs[0].buf;// current data + //bus->current_msg_byte = msgs[0].buf;// current data printk("\n current_msg_todo %x \n ",msgs[0].len); printk("\n current_msg_byte %x \n ",msgs[0].buf); + //printf("8011A5CC:%x\n", *(unsigned int *)(0x8011A5CC) ); bus->task_id = rtems_task_self(); regs = bus->regs; - am335x_i2c_setup_transfer(bus,regs); - REG(®s->BBB_I2C_IRQENABLE_SET) = BBB_I2C_IRQ_USED; + // REG(®s->BBB_I2C_IRQENABLE_SET) = BBB_I2C_IRQ_USED; + am335x_i2c_setup_transfer(bus,regs); + +/* sc = rtems_event_transient_receive(RTEMS_WAIT, bus->base.timeout); // If timeout then return timeout error if (sc != RTEMS_SUCCESSFUL) { @@ -688,7 +779,9 @@ static int am335x_i2c_transfer(i2c_bus *base, i2c_msg *msgs, uint32_t msg_count) return -ETIMEDOUT; } + */ printk("exit transfer\n"); + // return bus->regs->BBB_I2C_IRQSTATUS == 0 ? 0 : -EIO; return 0; } @@ -700,19 +793,28 @@ static int am335x_i2c_set_clock(i2c_bus *base, unsigned long clock) uint32_t prescaler,divider; printk("set clock start\n"); + REG(®s->BBB_I2C_CON)=0; + prescaler = (BBB_I2C_SYSCLK / BBB_I2C_INTERNAL_CLK) -1; + printf("prescaler:%d\n",prescaler ); printk("PSC offset %x \n ",®s->BBB_I2C_PSC); printk("PSC offset %x \n", &bus->regs->BBB_I2C_PSC); //mmio_write((®s->BBB_I2C_PSC), prescaler); REG(&bus->regs->BBB_I2C_PSC) = prescaler; divider = BBB_I2C_INTERNAL_CLK/(2*clock); + printf("divider:%d\n", divider); printk("SCLL offset %x \n",&bus->regs->BBB_I2C_SCLL); //mmio_write((®s->BBB_I2C_SCLL), (divider - 7)); REG(&bus->regs->BBB_I2C_SCLL) = (divider - 7); //mmio_write((®s->BBB_I2C_SCLH), (divider - 5)); printk("SCHL offset %x\n",&bus->regs->BBB_I2C_SCLH); REG(&bus->regs->BBB_I2C_SCLH) = (divider - 5); + + REG(®s->BBB_I2C_CON)=I2C_CON_EN; + +writew(0xFFFF, &bus->regs->BBB_I2C_IRQSTATUS); /* clear all pending status */ + printk("set clock end \n"); return 0; } @@ -729,6 +831,8 @@ static void am335x_i2c_destroy(i2c_bus *base) i2c_bus_destroy_and_free(&bus->base); } + + int am335x_i2c_bus_register( const char *bus_path, uintptr_t register_base, @@ -751,14 +855,15 @@ int am335x_i2c_bus_register( bus->regs = (volatile bbb_i2c_regs *) register_base; // 1. Enable clock for I2CX - I2C0ModuleClkConfig(); + I2C0ModuleClkConfig(); // 2. pinmux setup am335x_i2c0_pinmux(bus); // 3. RESET : Disable Master, autoideal - am335x_i2c_reset(bus); + // am335x_i2c_reset(bus); // 4. configure bus speed bus->input_clock = input_clock; // By default 100KHz. Normally pass 100KHz as argument +/* printk("Before set clock \n"); err = am335x_i2c_set_clock(&bus->base, I2C_BUS_CLOCK_DEFAULT); @@ -768,12 +873,16 @@ int am335x_i2c_bus_register( rtems_set_errno_and_return_minus_one(-err); } bus->irq = irq; - + */ +omap24_i2c_init(&bus->base); + //bring I2C out of reset - REG(&bus->regs->BBB_I2C_CON) |= AM335X_I2C_CON_I2C_EN; +//printf("REG(®s->BBB_I2C_IRQSTATUS):%x\n",REG(&bus->regs->BBB_I2C_IRQSTATUS)); + // REG(&bus->regs->BBB_I2C_CON) |= AM335X_I2C_CON_I2C_EN; // 5. Start interrupt service routine & one interrupt at a time +/* sc = rtems_interrupt_handler_install( irq, "BBB I2C", @@ -787,6 +896,7 @@ int am335x_i2c_bus_register( rtems_set_errno_and_return_minus_one(EIO); } + */ // 6. start transfer for reading and writing bus->base.transfer = am335x_i2c_transfer; bus->base.set_clock = am335x_i2c_set_clock; @@ -794,3 +904,499 @@ int am335x_i2c_bus_register( printk("exit register\n"); return i2c_bus_register(&bus->base,bus_path); } + + + + + + +static void omap24_i2c_init(i2c_bus *base) +{ + bbb_i2c_bus *bus = (bbb_i2c_bus *) base; + volatile bbb_i2c_regs *regs = bus->regs; + + struct am335x_baseboard_id header; + + int timeout = I2C_TIMEOUT; + int deblock = 1; +printf("omap24_i2c_init func!!!!!!\n"); +retry: + if (readw(&bus->regs->BBB_I2C_CON) & I2C_CON_EN) { + writew(0, &bus->regs->BBB_I2C_CON); + udelay(50000); + } + + writew(0x2, &bus->regs->BBB_I2C_SYSC); /* for ES2 after soft reset */ + udelay(1000); + + writew(I2C_CON_EN, &bus->regs->BBB_I2C_CON); + while (!(readw(&bus->regs->BBB_I2C_SYSS) & I2C_SYSS_RDONE) && timeout--) { + if (timeout <= 0) { + puts("ERROR: Timeout in soft-reset\n"); + return; + } + udelay(1000); + } + +am335x_i2c_set_clock(&bus->base, I2C_BUS_CLOCK_DEFAULT); + + /* own address */ + writew(1, &bus->regs->BBB_I2C_OA); + +//#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) + /* + * Have to enable interrupts for OMAP2/3, these IPs don't have + * an 'irqstatus_raw' register and we shall have to poll 'stat' + */ + // writew(I2C_IE_XRDY_IE | I2C_IE_RRDY_IE | I2C_IE_ARDY_IE | I2C_IE_NACK_IE | I2C_IE_AL_IE, &i2c_base->ie); +//#endif + udelay(1000); + flush_fifo(&bus->base); + writew(0xFFFF, &bus->regs->BBB_I2C_IRQSTATUS); + + /* Handle possible failed I2C state */ + if (wait_for_bb(&bus->base)) + if (deblock == 1) { + + //omap24_i2c_deblock(&bus->base); + printf("deblock\n"); + deblock = 0; + goto retry; + } + + + // omap24_i2c_probe(&bus->base); + // read_eeprom(&bus->base,&header); + +} + + +static void flush_fifo(i2c_bus *base) +{ + bbb_i2c_bus *bus = (bbb_i2c_bus *) base; + volatile bbb_i2c_regs *regs = bus->regs; + + + u16 stat; +printf("flush_fifo\n"); + /* + * note: if you try and read data when its not there or ready + * you get a bus error + */ + while (1) { + stat = readw(&bus->regs->BBB_I2C_IRQSTATUS); + if (stat == I2C_STAT_RRDY) { + readb(&bus->regs->BBB_I2C_DATA); + writew(I2C_STAT_RRDY, &bus->regs->BBB_I2C_IRQSTATUS); + udelay(1000); + } else + break; + } +} + + +static int wait_for_bb(i2c_bus *base) +{ + bbb_i2c_bus *bus = (bbb_i2c_bus *) base; + volatile bbb_i2c_regs *regs = bus->regs; + + + int timeout = I2C_TIMEOUT; + u16 stat; +printf("wait_for_bb\n"); + writew(0xFFFF, &bus->regs->BBB_I2C_IRQSTATUS); /* clear current interrupts...*/ +//printf("test1\n"); + /* Read RAW status */ +//printf("%x\n", readw(&bus->regs->BBB_I2C_IRQSTATUS_RAW) & I2C_STAT_BB); + while ((stat = readw(&bus->regs->BBB_I2C_IRQSTATUS_RAW) & + I2C_STAT_BB) && timeout--) { + + writew(stat, &bus->regs->BBB_I2C_IRQSTATUS); + udelay(200); + } + + if (timeout <= 0) { + printf("Timed out in wait_for_bb: status=%04x\n", + stat); + return 1; + } + writew(0xFFFF, &bus->regs->BBB_I2C_IRQSTATUS); /* clear delayed stuff*/ + return 0; +} + + +static int omap24_i2c_probe(i2c_bus *base) +{ + bbb_i2c_bus *bus = (bbb_i2c_bus *) base; + volatile bbb_i2c_regs *regs = bus->regs; + + unsigned char chip = 0x50; + u16 status; + int res = 1; /* default = fail */ + +printf("omap24_i2c_probe\n"); + if (chip == readw(&bus->regs->BBB_I2C_OA)) + return res; + + /* Wait until bus is free */ + if (wait_for_bb(&bus->base)) + return res; + + /* No data transfer, slave addr only */ + writew(chip, &bus->regs->BBB_I2C_SA); + /* Stop bit needed here */ + writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX | + I2C_CON_STP, &bus->regs->BBB_I2C_CON); + + status = wait_for_event(&bus->base); + + if ((status & ~I2C_STAT_XRDY) == 0 || (status & I2C_STAT_AL)) { + /* + * With current high-level command implementation, notifying + * the user shall flood the console with 127 messages. If + * silent exit is desired upon unconfigured bus, remove the + * following 'if' section: + */ + if (status == I2C_STAT_XRDY) + printf("i2c_probe: pads on bus probably not configured (status=0x%x)\n",status); + + goto pr_exit; + } + + /* Check for ACK (!NAK) */ + if (!(status & I2C_STAT_NACK)) { + printf("Device found\n"); + res = 0; /* Device found */ + udelay(200);/* Required by AM335X in SPL */ + /* Abort transfer (force idle state) */ + writew(I2C_CON_MST | I2C_CON_TRX, &bus->regs->BBB_I2C_CON); /* Reset */ + udelay(1000); + writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_TRX | + I2C_CON_STP, &bus->regs->BBB_I2C_CON); /* STP */ + } +pr_exit: + flush_fifo(&bus->base); + writew(0xFFFF, &bus->regs->BBB_I2C_IRQSTATUS); + return res; +} + + +static u16 wait_for_event(i2c_bus *base) +{ + bbb_i2c_bus *bus = (bbb_i2c_bus *) base; + volatile bbb_i2c_regs *regs = bus->regs; + + + u16 status; + int timeout = I2C_TIMEOUT; +//printf("wait_for_event \n"); + do { + udelay(200); + + /* Read RAW status */ + status = readw(&bus->regs->BBB_I2C_IRQSTATUS_RAW); + + } while (!(status & + (I2C_STAT_ROVR | I2C_STAT_XUDF | I2C_STAT_XRDY | + I2C_STAT_RRDY | I2C_STAT_ARDY | I2C_STAT_NACK | + I2C_STAT_AL)) && timeout--); + + if (timeout <= 0) { + printf("Timed out in wait_for_event: status=%04x\n", + status); + /* + * If status is still 0 here, probably the bus pads have + * not been configured for I2C, and/or pull-ups are missing. + */ + printf("Check if pads/pull-ups of bus are properly configured\n"); + writew(0xFFFF, &bus->regs->BBB_I2C_IRQSTATUS); + status = 0; + } + + return status; +} + + + + +static int am335x_i2c_read(i2c_bus *base, unsigned char chip, uint addr, int alen, unsigned char *buffer, + int len) +{ + + bbb_i2c_bus *bus = (bbb_i2c_bus *) base; + volatile bbb_i2c_regs *regs = bus->regs; + + int i2c_error = 0; + int i=0; + u16 status; +printf("am335x_i2c_read\n"); + if (alen < 0) { + puts("I2C read: addr len < 0\n"); + return 1; + } + if (len < 0) { + puts("I2C read: data len < 0\n"); + return 1; + } + if (buffer == NULL) { + puts("I2C read: NULL pointer passed\n"); + return 1; + } + + if (alen > 2) { + printf("I2C read: addr len %d not supported\n", alen); + return 1; + } + + if (addr + len > (1 << 16)) { + puts("I2C read: address out of range\n"); + return 1; + } + + /* Wait until bus not busy */ + if (wait_for_bb(&bus->base)) + return 1; +//printf("test2\n"); + /* Zero, one or two bytes reg address (offset) */ + writew(alen, &bus->regs->BBB_I2C_CNT); + /* Set slave address */ + writew(chip, &bus->regs->BBB_I2C_SA); +//printf("test3\n"); + if (alen) { + /* Must write reg offset first */ + + /* Stop - Start (P-S) */ + writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP | + I2C_CON_TRX, &bus->regs->BBB_I2C_CON); + + /* Send register offset */ + while (1) { + status = wait_for_event(&bus->base); + printf("status:%x\n",status ); + /* Try to identify bus that is not padconf'd for I2C */ + if (status == I2C_STAT_XRDY) { + i2c_error = 2; + printf("i2c_read (addr phase): pads on bus probably not configured (status=0x%x)\n", + status); + goto rd_exit; + } + if (status == 0 || (status & I2C_STAT_NACK)) { + i2c_error = 1; + printf("i2c_read: error waiting for addr ACK (status=0x%x)\n", + status); + goto rd_exit; + } + if (alen) { + if (status & I2C_STAT_XRDY) { + // printf("alen:%d\n",alen ); + alen--; + // printf("alen:%d\n",alen ); + // printf("addr:%x\n",addr ); + // printf("(addr >> (8 * alen)) & 0xff:%x\n",(addr >> (8 * alen)) & 0xff ); + /* Do we have to use byte access? */ + writeb((addr >> (8 * alen)) & 0xff, + &bus->regs->BBB_I2C_DATA); + writew(I2C_STAT_XRDY, &bus->regs->BBB_I2C_IRQSTATUS); + } + } + if (status & I2C_STAT_ARDY) { + writew(I2C_STAT_ARDY, &bus->regs->BBB_I2C_IRQSTATUS); + break; + } + } + } + /* Set slave address */ + writew(chip, &bus->regs->BBB_I2C_SA); + /* Read len bytes from slave */ + writew(len, &bus->regs->BBB_I2C_CNT); + /* Need stop bit here */ + writew(I2C_CON_EN | I2C_CON_MST | + I2C_CON_STT | I2C_CON_STP, + &bus->regs->BBB_I2C_CON); +//printf("test4\n"); + + + /* Receive data */ + while (1) { + status = wait_for_event(&bus->base); + // printf("test 5\n"); + /* + * Try to identify bus that is not padconf'd for I2C. This + * state could be left over from previous transactions if + * the address phase is skipped due to alen=0. + */ + if (status == I2C_STAT_XRDY) { + i2c_error = 2; + printf("i2c_read (data phase): pads on bus probably not configured (status=0x%x)\n", + status); + goto rd_exit; + } + if (status == 0 || (status & I2C_STAT_NACK)) { + // printf("i2c_error = 1\n"); + i2c_error = 1; + goto rd_exit; + } + if (status & I2C_STAT_RRDY) { + char temp; + temp=readb(&bus->regs->BBB_I2C_DATA); + *buffer++ =temp; + + *bus->msgs[0].buf++=temp; + // (*(uint8_t *) bus->current_msg_byte[0]) = readb(&bus->regs->BBB_I2C_DATA) & 0xFF; + i++; + writew(I2C_STAT_RRDY, &bus->regs->BBB_I2C_IRQSTATUS); + } + if (status & I2C_STAT_ARDY) { + writew(I2C_STAT_ARDY, &bus->regs->BBB_I2C_IRQSTATUS); + break; + } + } + +rd_exit: +//printf("rd_exit\n"); +//printf("i2c_error:%d\n",i2c_error); + flush_fifo(&bus->base); + writew(0xFFFF, &bus->regs->BBB_I2C_IRQSTATUS); + return i2c_error; +} + + + +static int read_eeprom(i2c_bus *base,struct am335x_baseboard_id *header) +{ + +bbb_i2c_bus *bus = (bbb_i2c_bus *) base; + volatile bbb_i2c_regs *regs = bus->regs; + +printf("sizeof(struct am335x_baseboard_id):%d\n",sizeof(struct am335x_baseboard_id) ); +//printf("sizeof(struct am335x_baseboard_id):%d\n",sizeof(unsigned int) ); +//printf("sizeof(struct am335x_baseboard_id):%d\n",sizeof(unsigned int) ); + am335x_i2c_read(&bus->base,0x50,0,2,(unsigned char *)header,sizeof(struct am335x_baseboard_id)); +/* +printf("am335x_i2c_read end\n"); + printf("header->magic:%x\n", header->magic); + printf("header->name[0]:%x\n", header->name[0]); + printf("header->name[1]:%x\n", header->name[1]); + printf("header->name[2]:%x\n", header->name[2]); + printf("header->name[3]:%x\n", header->name[3]); + printf("header->name[4]:%x\n", header->name[4]); + printf("header->name[5]:%x\n", header->name[5]); + printf("header->name[6]:%x\n", header->name[6]); + printf("header->name[7]:%x\n", header->name[7]); + */ +} + + + +static int am335x_i2c_write(i2c_bus *base, unsigned char chip, uint addr,int alen, unsigned char *buffer, + int len) +{ + + bbb_i2c_bus *bus = (bbb_i2c_bus *) base; + volatile bbb_i2c_regs *regs = bus->regs; + + int i; + u16 status; + int i2c_error = 0; + int timeout = I2C_TIMEOUT; + + if (alen < 0) { + puts("I2C write: addr len < 0\n"); + return 1; + } + + if (len < 0) { + puts("I2C write: data len < 0\n"); + return 1; + } + + if (buffer == NULL) { + puts("I2C write: NULL pointer passed\n"); + return 1; + } + + if (alen > 2) { + printf("I2C write: addr len %d not supported\n", alen); + return 1; + } + + if (addr + len > (1 << 16)) { + printf("I2C write: address 0x%x + 0x%x out of range\n", + addr, len); + return 1; + } + + /* Wait until bus not busy */ + if (wait_for_bb(&bus->base)) + return 1; + + /* Start address phase - will write regoffset + len bytes data */ + writew(alen + len, &bus->regs->BBB_I2C_CNT); + /* Set slave address */ + writew(chip,&bus->regs->BBB_I2C_SA); + /* Stop bit needed here */ + writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX | + I2C_CON_STP,&bus->regs->BBB_I2C_CON); + + while (alen) { + /* Must write reg offset (one or two bytes) */ + status = wait_for_event(&bus->base); + /* Try to identify bus that is not padconf'd for I2C */ + if (status == I2C_STAT_XRDY) { + i2c_error = 2; + printf("i2c_write: pads on bus probably not configured (status=0x%x)\n",status); + goto wr_exit; + } + if (status == 0 || (status & I2C_STAT_NACK)) { + i2c_error = 1; + printf("i2c_write: error waiting for addr ACK (status=0x%x)\n", + status); + goto wr_exit; + } + if (status & I2C_STAT_XRDY) { + alen--; + writeb((addr >> (8 * alen)) & 0xff, &bus->regs->BBB_I2C_DATA); + writew(I2C_STAT_XRDY, &bus->regs->BBB_I2C_IRQSTATUS); + } else { + i2c_error = 1; + printf("i2c_write: bus not ready for addr Tx (status=0x%x)\n", + status); + goto wr_exit; + } + } + /* Address phase is over, now write data */ + for (i = 0; i < len; i++) { + status = wait_for_event(&bus->base); + if (status == 0 || (status & I2C_STAT_NACK)) { + i2c_error = 1; + printf("i2c_write: error waiting for data ACK (status=0x%x)\n", + status); + goto wr_exit; + } + if (status & I2C_STAT_XRDY) { + writeb(buffer[i], &bus->regs->BBB_I2C_DATA); + writew(I2C_STAT_XRDY, &bus->regs->BBB_I2C_IRQSTATUS); + } else { + i2c_error = 1; + printf("i2c_write: bus not ready for data Tx (i=%d)\n", + i); + goto wr_exit; + } + } + /* + * poll ARDY bit for making sure that last byte really has been + * transferred on the bus. + */ + do { + status = wait_for_event(&bus->base); + } while (!(status & I2C_STAT_ARDY) && timeout--); + if (timeout <= 0) + printf("i2c_write: timed out writig last byte!\n"); + +wr_exit: + flush_fifo(&bus->base); + writew(0xFFFF, &bus->regs->BBB_I2C_IRQSTATUS); + return i2c_error; +} + + diff --git a/c/src/lib/libbsp/arm/beagle/include/i2c.h b/c/src/lib/libbsp/arm/beagle/include/i2c.h index d4a9e32..6c924ee 100644 --- a/c/src/lib/libbsp/arm/beagle/include/i2c.h +++ b/c/src/lib/libbsp/arm/beagle/include/i2c.h @@ -132,11 +132,11 @@ extern "C" { #define DISP_LINE_LEN 128 -#define I2C_TIMEOUT 1000 +#define I2C_TIMEOUT 1001 #define I2C_BUS_MAX 3 -#define I2C_BASE1 (OMAP34XX_CORE_L4_IO_BASE + 0x070000) +#define I2C_BASE1 (OMAP34XX_CORE_L4_IO_BASE + 0x070000) //0x48000000+0x070000 #define I2C_DEFAULT_BASE I2C_BASE1 @@ -356,7 +356,7 @@ static inline rtems_status_code beagle_i2c_read( | AM335X_I2C_IRQSTATUS_ARDY \ | AM335X_I2C_IRQSTATUS_RRDY \ | AM335X_I2C_IRQSTATUS_XRDY \ - | AM335X_I2C_IRQSTATUS_XUDF) + | AM335X_I2C_IRQSTATUS_XUDF ) #define BBB_I2C_IRQ_USED \ ( BBB_I2C_IRQ_ERROR \ @@ -478,6 +478,18 @@ static inline int bbb_register_i2c_2(void) } +struct am335x_baseboard_id { + unsigned int magic; + char name[8]; + char version[4]; + char serial[12]; + char config[32]; + char mac_addr[3][6]; +}; + + + + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/cpukit/dev/i2c/eeprom.c b/cpukit/dev/i2c/eeprom.c index 39cff95..15040af 100644 --- a/cpukit/dev/i2c/eeprom.c +++ b/cpukit/dev/i2c/eeprom.c @@ -55,6 +55,7 @@ static ssize_t eeprom_read( off_t offset ) { + eeprom *dev = (eeprom *) base; off_t avail = dev->size - offset; uint32_t off = (uint32_t) offset; @@ -86,6 +87,17 @@ static ssize_t eeprom_read( (uint8_t) (off >> 16), (uint8_t) (off >> 24) }; + + i2c_msg msgs[1] = { + { + .addr = i2c_addr, + .flags = I2C_M_RD, + .buf = in, + .len = cur + } + }; + + /* i2c_msg msgs[2] = { { .addr = i2c_addr, @@ -99,14 +111,22 @@ static ssize_t eeprom_read( .len = cur } }; + + + */ int err; + + err = i2c_bus_transfer(dev->base.bus, &msgs[0], RTEMS_ARRAY_SIZE(msgs)); + + if (err != 0) { return err; } - + todo -= cur; + off += cur; in += cur; } @@ -236,7 +256,7 @@ int i2c_dev_register_eeprom( } if (program_timeout_in_ms == 0) { - program_timeout_in_ms = 1000; + program_timeout_in_ms = 5000; } dev = (eeprom *) diff --git a/testsuites/samples/i2c0/init.c b/testsuites/samples/i2c0/init.c index b428216..70bbe12 100644 --- a/testsuites/samples/i2c0/init.c +++ b/testsuites/samples/i2c0/init.c @@ -23,10 +23,62 @@ #include <rtems/score/assert.h> #include <dev/i2c/eeprom.h> +#include <rtems/shell.h> +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <rtems/userenv.h> + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER +#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER +#define CONFIGURE_APPLICATION_NEEDS_STUB_DRIVER +#define CONFIGURE_APPLICATION_NEEDS_ZERO_DRIVER +#define CONFIGURE_APPLICATION_NEEDS_LIBBLOCK + +#define CONFIGURE_USE_IMFS_AS_BASE_FILESYSTEM + +#define CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS 32 + +#define CONFIGURE_MAXIMUM_USER_EXTENSIONS 1 + +#define CONFIGURE_UNLIMITED_ALLOCATION_SIZE 32 +#define CONFIGURE_UNLIMITED_OBJECTS +#define CONFIGURE_UNIFIED_WORK_AREAS + +#define CONFIGURE_STACK_CHECKER_ENABLED + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES +#define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_FLOATING_POINT + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> + + +#define CONFIGURE_SHELL_COMMAND_CP +#define CONFIGURE_SHELL_COMMAND_PWD +#define CONFIGURE_SHELL_COMMAND_LS +#define CONFIGURE_SHELL_COMMAND_LN +#define CONFIGURE_SHELL_COMMAND_LSOF +#define CONFIGURE_SHELL_COMMAND_CHDIR +#define CONFIGURE_SHELL_COMMAND_CD +#define CONFIGURE_SHELL_COMMAND_MKDIR +#define CONFIGURE_SHELL_COMMAND_RMDIR +#define CONFIGURE_SHELL_COMMAND_CAT +#define CONFIGURE_SHELL_COMMAND_MV +#define CONFIGURE_SHELL_COMMAND_RM +#define CONFIGURE_SHELL_COMMAND_MALLOC_INFO +#include <rtems/shellconfig.h> + + /* I2C address of CAT24C256 eeprom EEPROM SIZE 32 KB Ref: BBB SRM */ #define I2C_SLAVE_ADDR (0x50) -#define EEPROM_SIZE 256 +#define EEPROM_SIZE 78 #define EEPROM_PATH "/dev/i2c-0.eeprom" /* forward declarations to avoid warnings */ @@ -35,16 +87,23 @@ rtems_task Init(rtems_task_argument argument); const char rtems_test_name[] = "GSOC 2016 I2C TESTING"; rtems_printer rtems_test_printer; + rtems_task Init( rtems_task_argument ignored ) { + rtems_test_begin(); int i; int rv,fd_bus,fd_in_dev; uint8_t in[EEPROM_SIZE]; struct stat st; off_t off; + ssize_t n; + + rtems_shell_env_t env; + + /*bus registration */ rv = bbb_register_i2c_0(); @@ -64,23 +123,56 @@ rtems_task Init( 256, // size_in_bytes 0 // program time out in ms ); + + + + _Assert(rv == 0); +// exit( 0 ); printf("register EEPROM \n"); fd_in_dev = open(EEPROM_PATH, O_RDWR); + printf("fd_in_dev:%d\n", fd_in_dev); _Assert(fd_in_dev >=0); + + printf("open eeprom \n"); rv = fstat(fd_in_dev, &st); _Assert(rv == 0); _Assert(st.st_blksize == 8); _Assert(st.st_size == sizeof(in)); +printf("read func\n"); + + n = read(fd_in_dev, &in[0], sizeof(in)); + printf("n:%d\n",n ); + printf("0:%x, ",in[0]); + printf("1:%x, ",in[1]); + + for(i=0;i<sizeof(in);++i) + { +printf("%x\n",in[i]); + + } + + + + printf("sizeof(in):%d\n", sizeof(in)); + + + + // _Assert(n == -1); +/* +printf("test\n"); for ( i = 0; i < sizeof(in); ++i) { + printf("i:%d\n",i); off = lseek(fd_in_dev, 0, SEEK_SET); + printf("lseek func done!\n"); rv = read(fd_in_dev,&in[0], sizeof(in)); - printf("\n %s \n ",in[i]); + // printf("\n %s \n ",in[i]); } + */ printf("EXIT from test case"); close(fd_bus); - unlink(BBB_I2C_2_BUS_PATH); + unlink(BBB_I2C_2_BUS_PATH); rtems_test_end(); } -- 2.7.4 _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel