unsigned char i2c_transmit(com_state_t type) { switch (type) { case START: status_reg = ADDR_MATCH; i2c_interrupt(); break; case DATA: case DATA_NACK: if (!dir_cpy) { if (gc) { status_reg = DATA_RXGC; i2c_interrupt(); } else { status_reg = DATA_RX; i2c_interrupt(); } } else { status_reg = DATA_TX; i2c_interrupt(); } break; case STOP: status_reg = STOP_CATCHED; i2c_interrupt(); return 0; } // TODO(NR) Timeout return (0); }
void intc_cpu_int_group_6(void) { /* Determine interrupt number. */ int intc_group_6 = intc_get_ec_int(); switch (intc_group_6) { #ifdef CONFIG_I2C case IT83XX_IRQ_SMB_A: i2c_interrupt(IT83XX_I2C_CH_A); break; case IT83XX_IRQ_SMB_B: i2c_interrupt(IT83XX_I2C_CH_B); break; case IT83XX_IRQ_SMB_C: i2c_interrupt(IT83XX_I2C_CH_C); break; case IT83XX_IRQ_SMB_D: i2c_interrupt(IT83XX_I2C_CH_D); break; case IT83XX_IRQ_SMB_E: i2c_interrupt(IT83XX_I2C_CH_E); break; case IT83XX_IRQ_SMB_F: i2c_interrupt(IT83XX_I2C_CH_F); break; #endif default: break; } }
void intc_cpu_int_group_6(void) { /* Determine interrupt number. */ int intc_group_6 = intc_get_ec_int(); switch (intc_group_6) { case IT83XX_IRQ_SMB_A: i2c_interrupt(0); break; case IT83XX_IRQ_SMB_B: i2c_interrupt(1); break; case IT83XX_IRQ_SMB_C: i2c_interrupt(2); break; default: break; } }
void interrupt_func(void) { // I2C interrupt handler i2c_interrupt(); if (INTCONbits.TMR0IF == 1) { TMR0 = T0CNT; INTCONbits.TMR0IF = 0; gcounter++; if (gcounter > 8000) { gcounter = 0; } } if (INTCONbits.RABIF == 1) { unsigned short now = TMR3; //TMR3 = 0; //PIR2bits.TMR3IF = 0; INTCONbits.RABIF = 0; debug_counter++; } }
int chip_i2c_xfer(int port, int slave_addr, const uint8_t *out, int out_size, uint8_t *in, int in_size, int flags) { int ctrl = i2c_port_to_controller(port); volatile struct i2c_status *p_status = i2c_stsobjs + ctrl; if (out_size == 0 && in_size == 0) return EC_SUCCESS; interrupt_disable(); /* make sure bus is not occupied by the other task */ if (p_status->task_waiting != TASK_ID_INVALID) { interrupt_enable(); return EC_ERROR_BUSY; } /* Assign current task ID */ p_status->task_waiting = task_get_current(); interrupt_enable(); /* Select port for multi-ports i2c controller */ i2c_select_port(port); /* Copy data to controller struct */ p_status->flags = flags; p_status->tx_buf = out; p_status->sz_txbuf = out_size; p_status->rx_buf = in; p_status->sz_rxbuf = in_size; #if I2C_7BITS_ADDR /* Set slave address from 7-bits to 8-bits */ p_status->slave_addr = (slave_addr<<1); #else /* Set slave address (8-bits) */ p_status->slave_addr = slave_addr; #endif /* Reset index & error */ p_status->idx_buf = 0; p_status->err_code = SMB_OK; /* Make sure we're in a good state to start */ if ((flags & I2C_XFER_START) && (i2c_bus_busy(ctrl) || (i2c_get_line_levels(port) != I2C_LINE_IDLE))) { /* Attempt to unwedge the controller. */ i2c_unwedge(ctrl); /* recovery i2c controller */ i2c_recovery(ctrl); /* Select port again for recovery */ i2c_select_port(port); } CPUTS("\n"); /* Start master transaction */ i2c_master_transaction(ctrl); /* Reset task ID */ p_status->task_waiting = TASK_ID_INVALID; /* Disable SMB interrupt and New Address Match interrupt source */ i2c_interrupt(ctrl, 0); CPRINTS("-Err:0x%02x\n", p_status->err_code); return (p_status->err_code == SMB_OK) ? EC_SUCCESS : EC_ERROR_UNKNOWN; }
inline void i2c_handle_sda_irq(int controller) { volatile struct i2c_status *p_status = i2c_stsobjs + controller; /* 1 Issue Start is successful ie. write address byte */ if (p_status->oper_state == SMB_MASTER_START || p_status->oper_state == SMB_REPEAT_START) { uint8_t addr = p_status->slave_addr; /* Prepare address byte */ if (p_status->sz_txbuf == 0) {/* Receive mode */ p_status->oper_state = SMB_READ_OPER; /* * Receiving one byte only - set nack just * before writing address byte */ if (p_status->sz_rxbuf == 1) I2C_NACK(controller); /* Write the address to the bus R bit*/ I2C_WRITE_BYTE(controller, (addr | 0x1)); CPRINTS("-ARR-0x%02x", addr); } else {/* Transmit mode */ p_status->oper_state = SMB_WRITE_OPER; /* Write the address to the bus W bit*/ I2C_WRITE_BYTE(controller, addr); CPRINTS("-ARW-0x%02x", addr); } /* Completed handling START condition */ return; } /* 2 Handle master write operation */ else if (p_status->oper_state == SMB_WRITE_OPER) { /* all bytes have been written, in a pure write operation */ if (p_status->idx_buf == p_status->sz_txbuf) { /* no more message */ if (p_status->sz_rxbuf == 0) { /* need to STOP or not */ if (p_status->flags & I2C_XFER_STOP) { /* Issue a STOP condition on the bus */ I2C_STOP(controller); CPUTS("-SP"); /* Clear SDAST by writing dummy byte */ I2C_WRITE_BYTE(controller, 0xFF); } /* Set error code */ p_status->err_code = SMB_OK; /* Set SMB status if we need stall bus */ p_status->oper_state = (p_status->flags & I2C_XFER_STOP) ? SMB_IDLE : SMB_WRITE_SUSPEND; /* * Disable interrupt for i2c master stall SCL * and forbid SDAST generate interrupt * until common layer start other transactions */ if (p_status->oper_state == SMB_WRITE_SUSPEND) i2c_interrupt(controller, 0); /* Notify upper layer */ task_set_event(p_status->task_waiting, TASK_EVENT_I2C_IDLE, 0); CPUTS("-END"); } /* need to restart & send slave address immediately */ else { uint8_t addr_byte = p_status->slave_addr; /* * Prepare address byte * and start to receive bytes */ p_status->oper_state = SMB_READ_OPER; /* Reset index of buffer */ p_status->idx_buf = 0; /* * Generate (Repeated) Start * upon next write to SDA */ I2C_START(controller); CPUTS("-RST"); /* * Receiving one byte only - set nack just * before writing address byte */ if (p_status->sz_rxbuf == 1) { I2C_NACK(controller); CPUTS("-GNA"); } /* Write the address to the bus R bit*/ I2C_WRITE_BYTE(controller, (addr_byte | 0x1)); CPUTS("-ARR"); } } /* write next byte (not last byte and not slave address */ else { I2C_WRITE_BYTE(controller, p_status->tx_buf[p_status->idx_buf++]); CPRINTS("-W(%02x)", p_status->tx_buf[p_status->idx_buf-1]); } } /* 3 Handle master read operation (read or after a write operation) */ else if (p_status->oper_state == SMB_READ_OPER) { uint8_t data; /* last byte is about to be read - end of transaction */ if (p_status->idx_buf == (p_status->sz_rxbuf - 1)) { /* need to STOP or not */ if (p_status->flags & I2C_XFER_STOP) { /* Stop should set before reading last byte */ I2C_STOP(controller); CPUTS("-SP"); } } /* Check if byte-before-last is about to be read */ else if (p_status->idx_buf == (p_status->sz_rxbuf - 2)) { /* * Set nack before reading byte-before-last, * so that nack will be generated after receive * of last byte */ if (p_status->flags & I2C_XFER_STOP) { I2C_NACK(controller); CPUTS("-GNA"); } } /* Read last byte but flag don't include I2C_XFER_STOP */ if (p_status->idx_buf == p_status->sz_rxbuf-1) { /* * Disable interrupt before i2c master read SDA reg * (stall SCL) and forbid SDAST generate interrupt * until common layer start other transactions */ if (!(p_status->flags & I2C_XFER_STOP)) i2c_interrupt(controller, 0); } /* Read data for SMBSDA */ I2C_READ_BYTE(controller, data); CPRINTS("-R(%02x)", data); /* Read to buffer */ p_status->rx_buf[p_status->idx_buf++] = data; /* last byte is read - end of transaction */ if (p_status->idx_buf == p_status->sz_rxbuf) { /* Set current status */ p_status->oper_state = (p_status->flags & I2C_XFER_STOP) ? SMB_IDLE : SMB_READ_SUSPEND; /* Set error code */ p_status->err_code = SMB_OK; /* Notify upper layer of missing data */ task_set_event(p_status->task_waiting, TASK_EVENT_I2C_IDLE, 0); CPUTS("-END"); } } }
enum smb_error i2c_master_transaction(int controller) { /* Set i2c mode to object */ int events = 0; volatile struct i2c_status *p_status = i2c_stsobjs + controller; /* Assign current SMB status of controller */ if (p_status->oper_state == SMB_IDLE) { /* New transaction */ p_status->oper_state = SMB_MASTER_START; } else if (p_status->oper_state == SMB_WRITE_SUSPEND) { if (p_status->sz_txbuf == 0) { /* Read bytes from next transaction */ p_status->oper_state = SMB_REPEAT_START; CPUTS("R"); } else { /* Continue to write the other bytes */ p_status->oper_state = SMB_WRITE_OPER; I2C_WRITE_BYTE(controller, p_status->tx_buf[p_status->idx_buf++]); CPRINTS("-W(%02x)", p_status->tx_buf[p_status->idx_buf-1]); } } else if (p_status->oper_state == SMB_READ_SUSPEND) { /* Need to read the other bytes from next transaction */ uint8_t data; uint8_t timeout = 10; /* unit: us */ p_status->oper_state = SMB_READ_OPER; /* wait for SDAST issue */ while (timeout > 0) { if (IS_BIT_SET(NPCX_SMBST(controller), NPCX_SMBST_SDAST)) break; if (--timeout > 0) usleep(10); } if (timeout == 0) return EC_ERROR_TIMEOUT; /* * Read first byte from SMBSDA in case SDAST interrupt occurs * immediately before task_wait_event_mask() func */ I2C_READ_BYTE(controller, data); CPRINTS("-R(%02x)", data); /* Read to buffer */ p_status->rx_buf[p_status->idx_buf++] = data; } /* Generate a START condition */ if (p_status->oper_state == SMB_MASTER_START || p_status->oper_state == SMB_REPEAT_START) { I2C_START(controller); CPUTS("ST"); } /* Enable SMB interrupt and New Address Match interrupt source */ i2c_interrupt(controller, 1); /* Wait for transfer complete or timeout */ events = task_wait_event_mask(TASK_EVENT_I2C_IDLE, p_status->timeout_us); /* Handle bus timeout */ if ((events & TASK_EVENT_I2C_IDLE) == 0) { /* Recovery I2C controller */ i2c_recovery(controller); p_status->err_code = SMB_TIMEOUT_ERROR; } /* * In slave write operation, NACK is OK, otherwise it is a problem */ else if (p_status->err_code == SMB_BUS_ERROR || p_status->err_code == SMB_MASTER_NO_ADDRESS_MATCH){ i2c_recovery(controller); } /* Wait till STOP condition is generated */ if (p_status->err_code == SMB_OK && i2c_wait_stop_completed(controller, I2C_MIN_TIMEOUT) != EC_SUCCESS) { cprints(CC_I2C, "STOP fail! scl %02x is held by slave device!", controller); p_status->err_code = SMB_TIMEOUT_ERROR; } return p_status->err_code; }