static void i2c_wait_for_bb(int bus) { I2C_REG(bus, I2C_STAT) = 0xffff; // clear whatever is pending while (I2C_REG(bus, I2C_STAT) & (1<<12)) { I2C_REG(bus, I2C_STAT) = 0xffff; // clear whatever is pending } I2C_REG(bus, I2C_STAT) = 0xffff; // clear whatever is pending }
status_t i2c_transmit(int bus, uint8_t address, const void *buf, size_t count) { status_t err; LTRACEF("bus %d, address 0x%hhx, buf %p, count %zd\n", bus, address, buf, count); i2c_wait_for_bb(bus); I2C_REG(bus, I2C_SA) = address; I2C_REG(bus, I2C_CNT) = count; I2C_REG(bus, I2C_CON) = (1<<15)|(1<<10)|(1<<9)|(1<<1)|(1<<0); // enable, master, transmit, STP, STT lk_time_t t = current_time(); const uint8_t *ptr = (const uint8_t *)buf; for (;;) { uint16_t stat = I2C_REG(bus, I2C_STAT); if (stat & (1<<1)) { // NACK // printf("NACK\n"); err = ERR_GENERIC; goto out; } if (stat & (1<<0)) { // AL (arbitration lost) // printf("arbitration lost!\n"); err = ERR_GENERIC; goto out; } if (stat & (1<<2)) { // ARDY // printf("ARDY, completed\n"); break; } if (stat & (1<<4)) { // RRDY // printf("XRDY\n"); // transmit a byte *REG8(I2C_REG_ADDR(bus, I2C_DATA)) = *ptr; ptr++; } I2C_REG(bus, I2C_STAT) = stat; if (current_time() - t > I2C_TIMEOUT) { // printf("i2c timeout\n"); err = ERR_TIMED_OUT; goto out; } } err = NO_ERROR; out: I2C_REG(bus, I2C_STAT) = 0xffff; I2C_REG(bus, I2C_CNT) = 0; return err; }
int i2c_receive(int bus, uint8_t address, void *buf, size_t count) { int err; LTRACEF("bus %d, address 0x%hhx, buf %p, count %zd\n", bus, address, buf, count); i2c_wait_for_bb(bus); I2C_REG(bus, I2C_SA) = address; I2C_REG(bus, I2C_CNT) = count; I2C_REG(bus, I2C_CON) = (1<<15)|(1<<10)|(1<<1)|(1<<0); // enable, master, STP, STT lk_time_t t = current_time(); uint8_t *ptr = (uint8_t *)buf; for(;;) { uint16_t stat = I2C_REG(bus, I2C_STAT); if (stat & (1<<1)) { // NACK // printf("NACK\n"); err = -1; goto out; } if (stat & (1<<0)) { // AL (arbitration lost) // printf("arbitration lost!\n"); err = -1; goto out; } if (stat & (1<<2)) { // ARDY // printf("ARDY, completed\n"); break; } if (stat & (1<<3)) { // RRDY // printf("RRDY\n"); // read a byte, since our fifo threshold is set to 1 byte *ptr = *REG8(I2C_REG_ADDR(bus, I2C_DATA)); ptr++; } I2C_REG(bus, I2C_STAT) = stat; if (current_time() - t > I2C_TIMEOUT) { // printf("i2c timeout\n"); err = ERR_TIMED_OUT; goto out; } } err = 0; out: I2C_REG(bus, I2C_STAT) = 0xffff; I2C_REG(bus, I2C_CNT) = 0; return err; }
void i2c_init(int speed, int slaveadd) { /* scl_out = clk_func_ref / 3, clk_func_ref = master_clock_freq / (divisor_2 + 1) master_clock_freq = ext_clock_freq / divisor_1 */ /* clk_func_ref = scl_out * 3, divisor_2 = (master_clock_freq / clk_func_ref) - 1 divisor_1 = ext_clock_freq / master_clock_freq */ /* for a target freq of 200kHz: ext_clock_freq = 13MHz clk_func_ref = 3 * 300kHZ = 600kHz divisor_1 = 1 => master_clock_freq = ext_clock_freq = 13MHz divisor_2 = 21 => clk_func_ref = 13MHz / (21+2) = 590.91 kHz scl_out = clk_func_ref / 3 = 509.91 kHz / 3 = 196.97kHz */ writeb(I2C_CMD_SOFT_RESET, I2C_REG(CMD_REG)); writeb(0x00, I2C_REG(CONF_CLK_REG)); writeb(21, I2C_REG(CONF_CLK_FUNC_REF)); writeb(I2C_CMD_EN_CLK, I2C_REG(CMD_REG)); }
int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u8 mask) { u8 busy; int i; int ret; for (i = 0; i < M5MOLS_I2C_CHECK_RETRY; i++) { ret = m5mols_read_u8(sd, I2C_REG(category, cmd, 1), &busy); if (ret < 0) return ret; if ((busy & mask) == mask) return 0; } return -EBUSY; }
int i2c_write(uint8_t chip, uint32_t addr, int alen, const uint8_t *buffer, int len) { uint8_t cmd; /* Calypso I2C controller doesn't support fancy addressing */ if (alen > 1) return -1; /* FIXME: implement writes longer than fifo size */ if (len > 16) return -1; printd("i2c_write(chip=0x%02u, addr=0x%02u): ", chip, addr) writeb(chip & 0x3f, I2C_REG(DEVICE_REG)); writeb(addr & 0xff, I2C_REG(ADDRESS_REG)); /* we have to tell the controller how many bits we'll put into the fifo ?!? */ writeb(len-1, I2C_REG(CONF_FIFO_REG)); /* fill the FIFO */ while (len--) { uint8_t byte = *buffer++; writeb(byte, I2C_REG(DATA_WR_REG)); printd("%02X ", byte); } dputchar('\n'); /* start the transfer */ cmd = readb(I2C_REG(CMD_REG)); cmd |= I2C_CMD_START; writeb(cmd, I2C_REG(CMD_REG)); /* wait until transfer completes */ while (1) { uint8_t reg = readb(I2C_REG(STATUS_ACTIVITY_REG)); printd("I2C Status: 0x%02x\n", rerg & 0xf); if (!(reg & I2C_STATUS_IDLE)) // 0: idle 1: not idle break; } dputs("I2C transfer completed\n"); return 0; }
static void i2c_reset_bus(int bus) { I2C_REG(bus, I2C_CON) &= ~(1<<15); // make sure the bus is disabled /* reset the bus */ I2C_REG(bus, I2C_SYSC) = (1<<1); I2C_REG(bus, I2C_CON) = (1<<15); // enable the bus while ((I2C_REG(bus, I2C_SYSS) & 1) == 0) ; /* disable the bus again and set up some internals */ I2C_REG(bus, I2C_CON) &= ~(1<<15); // make sure the bus is disabled /* set up the clock */ I2C_REG(bus, I2C_PSC) = 23; // 96Mhz / 23 == 4Mhz I2C_REG(bus, I2C_SCLL) = 13; I2C_REG(bus, I2C_SCLH) = 15; // 4Mhz / combined divider of 40 (13+7 + 15+5) == 100khz /* slave address */ I2C_REG(bus, I2C_OA0) = 1; // XXX made this up /* fifo is set to 1 byte trigger */ I2C_REG(bus, I2C_BUF) = 0; /* disable all interrupts */ I2C_REG(bus, I2C_IE) = 0; /* enable the bus */ I2C_REG(bus, I2C_CON) = (1<<15)|(1<<10)|(1<<9); // enable, master, transmitter mode }