static int bcm1161_i2c_inb(void *base, int no_ack, struct bcm1161_i2c *i2c) { u8 cs = REG_I2C_CS(base); u8 data; I2C_DEBUG(DBG_TRACE, "%d\n", no_ack); /* Wait for controller to be done with last command */ if (bcm1161_check_cmdbusy(base) < 0) { I2C_DEBUG(DBG_ERROR, "cmdbusy always high\n"); return -EIO; } /* Initiate data read with ACK low */ REG_I2C_CS(base) = REG_I2C_CS_SDA | REG_I2C_CS_SCL | REG_I2C_CS_CMDREAD | REG_I2C_CS_EN | (no_ack ? REG_I2C_CS_ACK : 0); /* Wait for command to be done */ if (bcm1161_wait_sesdone(base, 1, i2c) < 0) { I2C_DEBUG(DBG_ERROR, "sesdone timed out, cs = 0x%02x\n", cs); return -ETIMEDOUT; } /* Read data */ data = REG_I2C_DAT(base); udelay(5); return (int)data; }
bool I2C_MultipleWrite(alt_u32 clk_base, alt_u32 data_base, alt_8 DeviceAddr, alt_u8 ControlAddr, alt_u8 *pData, alt_u16 len){ bool bSuccess = TRUE; int i; i2c_start(clk_base, data_base); if (!i2c_write(clk_base, data_base, DeviceAddr)){ // send ID bSuccess = FALSE; I2C_DEBUG(("I2C HMB_E2 Fail: Address NACK!\n")); } if (bSuccess && !i2c_write(clk_base, data_base, ControlAddr)){ // send sub-address bSuccess = FALSE; I2C_DEBUG(("I2C HMB_E2 Fail: SubAddress NACK!\n")); } if (bSuccess){ for(i=0;i<len && bSuccess;i++){ bSuccess = i2c_write(clk_base, data_base, *pData); pData++; } if (!bSuccess) I2C_DEBUG(("I2C HMB_E2 Fail: write NACK!\n")); } i2c_stop(clk_base, data_base); usleep(7*1000); // delay to wait EE2 ready (at least 5 ms delay is required) return bSuccess; }
/* returns: * 1 if the device acknowledged * 0 if the device did not ack * -ETIMEDOUT if an error occurred (while raising the scl line) */ static int bcm1161_i2c_outb(void *base, char c, struct bcm1161_i2c *i2c) { int ack; I2C_DEBUG(DBG_TRACE, "0x%2x\n", c); udelay(5); /* Wait for controller to be done with last command */ if (bcm1161_check_cmdbusy(base) < 0) { I2C_DEBUG(DBG_ERROR, "cmdbusy always high\n"); return -EIO; } /* Send data */ REG_I2C_CS(base) = REG_I2C_CS_SDA | REG_I2C_CS_SCL | REG_I2C_CS_EN; REG_I2C_DAT(base) = (u8) c; /* Wait for command to be done */ ack = bcm1161_wait_sesdone(base, 0, i2c); if (ack < 0) { I2C_DEBUG(DBG_ERROR, "sesdone timed out\n"); return -ETIMEDOUT; } return ack; }
bool I2C_Write(alt_u32 clk_base, alt_u32 data_base, alt_8 DeviceAddr, alt_u8 ControlAddr, alt_u8 ControlData){ bool bSuccess = TRUE; //alt_u8 DeviceAddr; // device id //DeviceAddr = HMB_E2_I2C_ID; i2c_start(clk_base, data_base); if (!i2c_write(clk_base, data_base, DeviceAddr)){ // send ID bSuccess = FALSE; I2C_DEBUG(("I2C HMB_E2 Fail: Address NACK!\n")); } if (bSuccess && !i2c_write(clk_base, data_base, ControlAddr)){ // send sub-address bSuccess = FALSE; I2C_DEBUG(("I2C HMB_E2 Fail: SubAddress NACK!\n")); } if (bSuccess && !i2c_write(clk_base, data_base, ControlData)){ bSuccess = FALSE; I2C_DEBUG(("I2C HMB_E2 Fail: write NACK!\n")); } i2c_stop(clk_base, data_base); usleep(7*1000); // delay to wait EE2 ready (at least 5 ms delay is required) return bSuccess; }
bool I2C_Read(alt_u32 clk_base, alt_u32 data_base, alt_8 DeviceAddr, alt_u8 ControlAddr, alt_u8 *pControlData){ bool bSuccess = TRUE; //alt_u8 DeviceAddr; // device id //DeviceAddr = HMB_E2_I2C_ID; i2c_start(clk_base, data_base); if (!i2c_write(clk_base, data_base, DeviceAddr)){ // send ID bSuccess = FALSE; I2C_DEBUG(("I2C HMB_E2 Fail: Address NACK!\n")); } if (bSuccess && !i2c_write(clk_base, data_base, ControlAddr)){ // send sub-address bSuccess = FALSE; I2C_DEBUG(("I2C HMB_E2 Fail: SubAddress NACK!\n")); } i2c_start(clk_base, data_base); // restart DeviceAddr |= 1; // Read if (bSuccess && !i2c_write(clk_base, data_base, DeviceAddr)){ // send id bSuccess = FALSE; I2C_DEBUG(("I2C HMB_E2 Fail: Address+1 NACK!\n")); } if (bSuccess){ i2c_read(clk_base, data_base, pControlData, FALSE); // read } i2c_stop(clk_base, data_base); return bSuccess; }
static int bcm1161_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg, struct bcm1161_i2c *i2c) { int inval; int rdcount = 0; /* counts bytes read */ char *temp = msg->buf; int count = msg->len; while (count > 0) { inval = bcm1161_i2c_inb(i2c_adap->algo_data, (msg->flags & I2C_M_NO_RD_ACK) || (count == 1), i2c); if (inval >= 0) { I2C_DEBUG(DBG_TRACE2, "reading %2.2X\n", inval & 0xff); *temp = inval; rdcount++; } else { /* read timed out */ i2c_errors++; I2C_DEBUG(DBG_ERROR, "timed out.\n"); break; } temp++; count--; } return rdcount; }
static int bcm1161_sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg, struct bcm1161_i2c *i2c) { char c; const char *temp = msg->buf; int count = msg->len; unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK; int retval; int wrcount = 0; while (count > 0) { c = *temp; I2C_DEBUG(DBG_TRACE2, "writing %2.2X\n", c & 0xff); retval = bcm1161_i2c_outb(i2c_adap->algo_data, c, i2c); if ((retval > 0) || (nak_ok && (retval == 0))) { /* ok or ignored NAK */ count--; temp++; wrcount++; } else { /* arbitration or no acknowledge */ I2C_DEBUG(DBG_ERROR, "error %d/%d.\n", wrcount, msg->len); i2c_errors++; bcm1161_i2c_stop(i2c_adap->algo_data, i2c); return (retval < 0) ? retval : -EFAULT; /* got a better one ?? */ } } return wrcount; }
static int iicbb_stop(device_t dev) { struct iicbb_softc *sc = device_get_softc(dev); I2C_SET(sc,dev,0,0); I2C_SET(sc,dev,1,0); I2C_SET(sc,dev,1,1); I2C_DEBUG(printf(">")); I2C_DEBUG(printf("\n")); return (0); }
/* doAddress initiates the transfer by generating the start condition (in * try_address) and transmits the address in the necessary format to handle * reads, writes as well as 10bit-addresses. * returns: * 0 everything went okay, the chip ack'ed, or IGNORE_NAK flag was set * -x an error occurred (like: -EREMOTEIO if the device did not answer, or * -ETIMEDOUT, for example if the lines are stuck...) */ static int bcm1161_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg, struct bcm1161_i2c *i2c) { unsigned short flags = msg->flags; unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK; unsigned char addr; int ret, retries; retries = nak_ok ? 0 : i2c_adap->retries; if ((flags & I2C_M_TEN)) { /* a ten bit address */ addr = 0xf0 | ((msg->addr >> 7) & 0x03); I2C_DEBUG(DBG_TRACE2, "addr: %d\n", addr); /* try extended address code... */ ret = bcm1161_try_address(i2c_adap, addr, retries, i2c); if ((ret != 1) && !nak_ok) { I2C_DEBUG(DBG_ERROR, "died at extended address code.\n"); return -EREMOTEIO; } /* the remaining 8 bit address */ ret = bcm1161_i2c_outb(i2c_adap->algo_data, msg->addr & 0x7f, i2c); if ((ret != 1) && !nak_ok) { /* the chip did not ack / xmission error occurred */ I2C_DEBUG(DBG_ERROR, "died at 2nd address code.\n"); return -EREMOTEIO; } if (flags & I2C_M_RD) { ret = bcm1161_i2c_repstart(i2c_adap->algo_data, i2c); if (ret < 0) return -EIO; /* okay, now switch into reading mode */ addr |= 0x01; ret = bcm1161_try_address(i2c_adap, addr, retries, i2c); if ((ret != 1) && !nak_ok) { I2C_DEBUG(DBG_ERROR, "died at extended address code.\n"); return -EREMOTEIO; } } } else { /* normal 7bit address */
static int bcm1161_wait_sesdone(int *base, int clear_cmd, struct bcm1161_i2c *i2c) { int ret; u8 isr; u8 cs = REG_I2C_CS(base); #if !I2C_POLL_COMMAND_DONE ret = bcm1161_wait_interrupt(i2c); #else ret = bcm1161_wait_interrupt(base, i2c); #endif if (ret < 0) { I2C_DEBUG(DBG_ERROR, "wait interrupt timed out %d cs = 0x%02X\n", ret, cs); i2c_errors++; bcm1161_i2c_reset_controller(base); return ret; } /* Get status from interrupt status register */ isr = ret; /* Clear command */ cs = REG_I2C_CS(base); if (clear_cmd) { REG_I2C_CS(base) = (cs & ~REG_I2C_CS_CMDMASK); } if (isr & REG_I2C_ISR_I2CERR) { I2C_DEBUG(DBG_ERROR, "bus error detected, slave addr = 0x%04X\n", i2c->addr); i2c_errors++; return -EIO; } if (isr & REG_I2C_ISR_NOACK) { I2C_DEBUG(DBG_ERROR, "no ack, slave addr = 0x%04X\n", i2c->addr); i2c_errors++; } if (!(isr & REG_I2C_ISR_SES_DONE)) { I2C_DEBUG(DBG_ERROR, "ses done timedout\n"); i2c_errors++; return -EIO; } return (cs & REG_I2C_CS_ACK) ? 0 : 1; }
void i2c_stop(struct i2c_bus *bus) { I2C_SET(bus,0,0); I2C_SET(bus,1,0); I2C_SET(bus,1,1); I2C_DEBUG(printk(">\n")); }
/* try_address tries to contact a chip for a number of * times before it gives up. * return values: * 1 chip answered * 0 chip did not answer * -x transmission error */ static int bcm1161_try_address(struct i2c_adapter *i2c_adap, unsigned char addr, int retries, struct bcm1161_i2c *i2c) { int i, ret = -1; I2C_DEBUG(DBG_TRACE, "0x%02x, %d\n", addr, retries); for (i = 0; i <= retries; i++) { ret = bcm1161_i2c_outb(i2c_adap->algo_data, addr, i2c); if (ret == 1) break; /* success! */ bcm1161_i2c_stop(i2c_adap->algo_data, i2c); udelay(5); if (i == retries) /* no success */ break; bcm1161_i2c_start(i2c_adap->algo_data, i2c); udelay(100); } udelay(5); if (i) { I2C_DEBUG(DBG_INFO, "Used %d tries to %s client at 0x%02x : %s\n", i + 1, addr & 1 ? "read" : "write", addr >> 1, ret == 1 ? "success" : ret == 0 ? "no ack" : "failed, timeout?"); } return ret; }
static int bcm1161_wait_interrupt(void *base, struct bcm1161 *i2c) { /* wait for I2C Controller Interrupt */ unsigned int i = 0; #if defined (CONFIG_ARCH_BCM116X) timer_tick_count_t clk; timer_tick_count_t clk2; #endif int isr; #if defined (CONFIG_ARCH_BCM116X) clk = timer_get_tick_count(); #endif while ((REG_I2C_ISR(base) & I2C_ISR_MASK_ALL) == 0) { i++; if (i == (unsigned int)(-1)) { I2C_DEBUG(DBG_ERROR, "wait timed out, %d\n", clk); return -ETIMEDOUT; } } #if defined (CONFIG_ARCH_BCM116X) clk2 = timer_get_tick_count(); clk = clk2 - clk; if (clk > i2c_max_irq_wait) { i2c_max_irq_wait = clk; } #endif isr = REG_I2C_ISR(base); REG_I2C_ISR(base) = isr; return isr; }
static int iicbb_start(device_t dev, u_char slave, int timeout) { int error; I2C_DEBUG(printf("<")); I2C_SET(dev,1,1); I2C_SET(dev,1,0); I2C_SET(dev,0,0); /* send address */ iicbb_sendbyte(dev, slave, timeout); /* check for ack */ if (iicbb_ack(dev, timeout)) { error = IIC_ENOACK; goto error; } return(0); error: iicbb_stop(dev); return (error); }
void i2c_start(struct i2c_bus *bus) { I2C_SET(bus,0,1); I2C_SET(bus,1,1); I2C_SET(bus,1,0); I2C_SET(bus,0,0); I2C_DEBUG(printk("%s: < ",bus->name)); }
static int iicbb_stop(device_t dev) { I2C_SET(dev,0,0); I2C_SET(dev,1,0); I2C_SET(dev,1,1); I2C_DEBUG(printf(">")); return (0); }
static int bcm1161_i2c_start(void *base, struct bcm1161_i2c *i2c) { u8 cs; int i = 0; I2C_DEBUG(DBG_TRACE, "\n"); #if ADD_TURNAROUND_DELAY udelay(TURN_AROUND_DELAY); #endif while (((cs = REG_I2C_CS(base)) & (REG_I2C_CS_SDA | REG_I2C_CS_SCL)) != (REG_I2C_CS_SDA | REG_I2C_CS_SCL)) { if ((i % 100) == 0) { i2c_errors++; I2C_DEBUG(DBG_ERROR, "waiting for cs = 0x%2x [i = %d] base = 0x%p\n", cs, i, (unsigned int)base); bcm1161_i2c_reset_controller(base); } i++; } /* Wait for controller to be done with last command */ if (bcm1161_check_cmdbusy(base) < 0) { I2C_DEBUG(DBG_ERROR, "cmdbusy always high\n"); return -EIO; } /* Send normal start condition */ REG_I2C_CS(base) = REG_I2C_CS_SDA | REG_I2C_CS_SCL | REG_I2C_CS_CMDSTART | REG_I2C_CS_EN; /* Wait for command to be done */ if (bcm1161_wait_sesdone(base, 1, i2c) < 0) { I2C_DEBUG(DBG_ERROR, "sesdone timed out\n"); return -ETIMEDOUT; } return 0; }
static int bcm1161_i2c_repstart(void *base, struct bcm1161_i2c *i2c) { I2C_DEBUG(DBG_TRACE, "\n"); /* Wait for controller to be done with last command */ if (bcm1161_check_cmdbusy(base) < 0) { I2C_DEBUG(DBG_ERROR, "cmdbusy always high\n"); return -EIO; } /* Send repeated start condition */ REG_I2C_CS(base) = REG_I2C_CS_SDA | REG_I2C_CS_SCL | REG_I2C_CS_CMDRESTART | REG_I2C_CS_EN; /* Wait for command to be done */ if (bcm1161_wait_sesdone(base, 1, i2c) < 0) { I2C_DEBUG(DBG_ERROR, "sesdone timed out\n"); return -ETIMEDOUT; } return 0; }
int i2c_sendbyte(struct i2c_bus *bus,unsigned char data,int wait_for_ack) { int i, ack; I2C_SET(bus,0,0); for (i=7; i>=0; i--) (data&(1<<i)) ? i2c_one(bus) : i2c_zero(bus); if (wait_for_ack) udelay(wait_for_ack); ack=i2c_ack(bus); I2C_DEBUG(printk("%02x%c ",(int)data,ack?'-':'+')); return ack; }
bool I2C_MultipleRead(alt_u32 clk_base, alt_u32 data_base, alt_8 DeviceAddr, alt_u8 szData[], alt_u16 len){ int i; bool bSuccess = TRUE; //alt_u8 DeviceAddr, alt_u8 ControlAddr = 0; // device id //DeviceAddr = HMB_E2_I2C_ID; i2c_start(clk_base, data_base); if (!i2c_write(clk_base, data_base, DeviceAddr)){ // send ID bSuccess = FALSE; I2C_DEBUG(("I2C HMB_E2 Fail: Address NACK!\n")); } if (bSuccess && !i2c_write(clk_base, data_base, ControlAddr)){ // send sub-address bSuccess = FALSE; I2C_DEBUG(("I2C HMB_E2 Fail: SubAddress NACK!\n")); } if (bSuccess) i2c_start(clk_base, data_base); // restart DeviceAddr |= 1; // Read if (bSuccess && !i2c_write(clk_base, data_base, DeviceAddr)){ // send id bSuccess = FALSE; I2C_DEBUG(("I2C HMB_E2 Fail: Address+1 NACK!\n")); } if (bSuccess){ for(i=0;i<len && bSuccess;i++){ i2c_read(clk_base, data_base, &szData[i], (i==(len-1))?FALSE:TRUE); // read } } i2c_stop(clk_base, data_base); return bSuccess; }
static void iicbb_sendbyte(device_t dev, u_char data, int timeout) { int i; for (i=7; i>=0; i--) { if (data&(1<<i)) { iicbb_one(dev, timeout); } else { iicbb_zero(dev, timeout); } } I2C_DEBUG(printf("w%02x",(int)data)); return; }
static int bcm1161_i2c_stop(void *base, struct bcm1161_i2c *i2c) { u8 cs = REG_I2C_CS(base); I2C_DEBUG(DBG_TRACE, "\n"); /* Wait for controller to be done with last command */ if (bcm1161_check_cmdbusy(base) < 0) { I2C_DEBUG(DBG_ERROR, "cmdbusy always high\n"); return -EIO; } /* Send stop condition */ REG_I2C_CS(base) = REG_I2C_CS_SDA | REG_I2C_CS_SCL | REG_I2C_CS_CMDSTOP | REG_I2C_CS_EN; /* Wait for command to be done */ if (bcm1161_wait_sesdone(base, 1, i2c) < 0) { I2C_DEBUG(DBG_ERROR, "sesdone timed out, cs = 0x%02x\n", cs); return -ETIMEDOUT; } return 0; }
/* compute the clock period required for the delay between i2c transactions */ static unsigned long bcm1161_i2c_bus_clk_period(struct bcm1161_i2c *i2c) { u8 tim, div, p; tim = REG_I2C_TIM(i2c->adapter.algo_data); div = tim & REG_I2C_TIM_DIVMSK; p = (tim & REG_I2C_TIM_PMSK) >> BSC_TIM_P_VAL_BIT_SHIFT; I2C_DEBUG(DBG_INFO, " tim[%d]\t div[%d]\t p[%d]\n", tim, div, p); div = 1 << (4 - div); p = 2 * (p + 1) + 1 + 2 * (p + 1) + 2; return (div * p * 1000000 + (clk_get_rate(i2c->clk) >> 1) - 1) / BSC_MASTER_CLK_FREQ; }
unsigned char i2c_readbyte(struct i2c_bus *bus,int last) { int i; unsigned char data=0; I2C_SET(bus,0,1); for (i=7; i>=0; i--) { I2C_SET(bus,1,1); if (I2C_GET(bus)) data |= (1<<i); I2C_SET(bus,0,1); } last ? i2c_one(bus) : i2c_zero(bus); I2C_DEBUG(printk("=%02x%c ",(int)data,last?'-':'+')); return data; }
/* * Waiting for ACKNOWLEDGE. * * When a chip is being addressed or has received data it will issue an * ACKNOWLEDGE pulse. Therefore the MASTER must release the DATA line * (set it to high level) and then release the CLOCK line. * Now it must wait for the SLAVE to pull the DATA line low. * Actually on the bus this looks like a START condition so nothing happens * because of the fact that the IC's that have not been addressed are doing * nothing. * * When the SLAVE has pulled this line low the MASTER will take the CLOCK * line low and then the SLAVE will release the SDA (data) line. */ static int iicbb_ack(device_t dev, int timeout) { int noack; int k = 0; I2C_SET(dev,0,1); I2C_SET(dev,1,1); do { noack = I2C_GETSDA(dev); if (!noack) break; DELAY(10); k += 10; } while (k < timeout); I2C_SET(dev,0,1); I2C_DEBUG(printf("%c ",noack?'-':'+')); return (noack); }
static u_char iicbb_readbyte(device_t dev, int last, int timeout) { int i; unsigned char data=0; I2C_SET(dev,0,1); for (i=7; i>=0; i--) { I2C_SET(dev,1,1); if (I2C_GETSDA(dev)) data |= (1<<i); I2C_SET(dev,0,1); } if (last) { iicbb_one(dev, timeout); } else { iicbb_zero(dev, timeout); } I2C_DEBUG(printf("r%02x%c ",(int)data,last?'-':'+')); return data; }
/* * Waiting for ACKNOWLEDGE. * * When a chip is being addressed or has received data it will issue an * ACKNOWLEDGE pulse. Therefore the MASTER must release the DATA line * (set it to high level) and then release the CLOCK line. * Now it must wait for the SLAVE to pull the DATA line low. * Actually on the bus this looks like a START condition so nothing happens * because of the fact that the IC's that have not been addressed are doing * nothing. * * When the SLAVE has pulled this line low the MASTER will take the CLOCK * line low and then the SLAVE will release the SDA (data) line. */ static int iicbb_ack(device_t dev, int timeout) { struct iicbb_softc *sc = device_get_softc(dev); int noack; int k = 0; I2C_SET(sc,dev,0,1); I2C_SET(sc,dev,1,1); do { noack = I2C_GETSDA(dev); if (!noack) break; DELAY(1); k++; } while (k < timeout); I2C_SET(sc,dev,0,1); I2C_DEBUG(printf("%c ",noack?'-':'+')); return (noack); }