uint8_t smbus_read_byte(i2c_bus *bus, int addr, uint8_t command) { uint8_t data; i2c_start_transfer(bus, addr, 0); i2c_send(bus, command); i2c_start_transfer(bus, addr, 1); data = i2c_recv(bus); i2c_nack(bus); i2c_end_transfer(bus); return data; }
uint16_t smbus_read_word(i2c_bus *bus, uint8_t addr, uint8_t command) { uint16_t data; i2c_start_transfer(bus, addr, 0); i2c_send(bus, command); i2c_start_transfer(bus, addr, 1); data = i2c_recv(bus); data |= i2c_recv(bus) << 8; i2c_nack(bus); i2c_end_transfer(bus); return data; }
void smbus_write_byte(i2c_bus *bus, int addr, uint8_t command, uint8_t data) { i2c_start_transfer(bus, addr, 0); i2c_send(bus, command); i2c_send(bus, data); i2c_end_transfer(bus); }
void i2c_common(mal_i2c_s *handle) { // Check if transmission is complete if (I2C_GetITStatus(handle->stm_handle, I2C_IT_TC) == SET) { // Transmit complete, stop transfer, clear interrupt with stop I2C_GenerateSTOP(handle->stm_handle, ENABLE); // Make sure it was expected if (I2C_STATE_WAITING_TRANSFER_COMPLETE != handle->state) { // We are in error handle->state = (volatile mal_hspec_stm32f0_i2c_states_e)I2C_STATE_ERROR; } else { // Next state handle->state = (volatile mal_hspec_stm32f0_i2c_states_e)I2C_STATE_WAIT_STOP; } } // Check for stop if (I2C_GetITStatus(handle->stm_handle, I2C_IT_STOPF) == SET) { // Clear interrupt I2C_ClearITPendingBit(handle->stm_handle, I2C_IT_STOPF); // Notify mal_i2c_result_e i2c_result = MAL_I2C_SUCCESS; if (I2C_STATE_WAIT_STOP != handle->state) { i2c_result = MAL_I2C_BUS_ERROR; } handle->msg->callback(handle->msg->handle, &handle->msg->packet, i2c_result, &handle->msg); // Check if a new message can be started if (handle->msg != NULL) { i2c_start_transfer(handle); } else { handle->is_active = false; } } }
static int pca954x_decode_address(I2CSlave *i2c, uint8_t address) { PCA954XState *s = PCA954X(i2c); int i; uint8_t channel_status = 0; s->control_decoded = address == (PCA954X_CONTROL_ADDR | (s->chip_enable & 0x7)); if (s->control_decoded) { return 0; } for (i = 0; i < s->lanes; ++i) { if (s->active_lanes & (1 << i)) { DB_PRINT("starting active bus %d addr:%02x rnw:%d\n", i, address, s->event == I2C_START_RECV); channel_status |= (i2c_start_transfer(s->busses[i], address, s->event == I2C_START_RECV)) << i; } } if (s->active_lanes == channel_status) { return 1; } return 0; }
/* * The state machine needs some refinement. It is only used to track * invalid STOP commands for the moment. */ static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value) { bus->cmd &= ~0xFFFF; bus->cmd |= value & 0xFFFF; if (bus->cmd & I2CD_M_START_CMD) { uint8_t state = aspeed_i2c_get_state(bus) & I2CD_MACTIVE ? I2CD_MSTARTR : I2CD_MSTART; aspeed_i2c_set_state(bus, state); if (i2c_start_transfer(bus->bus, extract32(bus->buf, 1, 7), extract32(bus->buf, 0, 1))) { bus->intr_status |= I2CD_INTR_TX_NAK; } else { bus->intr_status |= I2CD_INTR_TX_ACK; } /* START command is also a TX command, as the slave address is * sent on the bus */ bus->cmd &= ~(I2CD_M_START_CMD | I2CD_M_TX_CMD); /* No slave found */ if (!i2c_bus_busy(bus->bus)) { return; } aspeed_i2c_set_state(bus, I2CD_MACTIVE); } if (bus->cmd & I2CD_M_TX_CMD) { aspeed_i2c_set_state(bus, I2CD_MTXD); if (i2c_send(bus->bus, bus->buf)) { bus->intr_status |= (I2CD_INTR_TX_NAK); i2c_end_transfer(bus->bus); } else { bus->intr_status |= I2CD_INTR_TX_ACK; } bus->cmd &= ~I2CD_M_TX_CMD; aspeed_i2c_set_state(bus, I2CD_MACTIVE); } if ((bus->cmd & (I2CD_M_RX_CMD | I2CD_M_S_RX_CMD_LAST)) && !(bus->intr_status & I2CD_INTR_RX_DONE)) { aspeed_i2c_handle_rx_cmd(bus); } if (bus->cmd & I2CD_M_STOP_CMD) { if (!(aspeed_i2c_get_state(bus) & I2CD_MACTIVE)) { qemu_log_mask(LOG_GUEST_ERROR, "%s: abnormal stop\n", __func__); bus->intr_status |= I2CD_INTR_ABNORMAL; } else { aspeed_i2c_set_state(bus, I2CD_MSTOP); i2c_end_transfer(bus->bus); bus->intr_status |= I2CD_INTR_NORMAL_STOP; } bus->cmd &= ~I2CD_M_STOP_CMD; aspeed_i2c_set_state(bus, I2CD_IDLE); } }
int smbus_read_block(i2c_bus *bus, int addr, uint8_t command, uint8_t *data) { int len; int i; i2c_start_transfer(bus, addr, 0); i2c_send(bus, command); i2c_start_transfer(bus, addr, 1); len = i2c_recv(bus); if (len > 32) len = 0; for (i = 0; i < len; i++) data[i] = i2c_recv(bus); i2c_nack(bus); i2c_end_transfer(bus); return len; }
void smbus_write_word(i2c_bus *bus, int addr, uint8_t command, uint16_t data) { i2c_start_transfer(bus, addr, 0); i2c_send(bus, command); i2c_send(bus, data & 0xff); i2c_send(bus, data >> 8); i2c_end_transfer(bus); }
uint8_t smbus_receive_byte(i2c_bus *bus, int addr) { uint8_t data; i2c_start_transfer(bus, addr, 1); data = i2c_recv(bus); i2c_nack(bus); i2c_end_transfer(bus); return data; }
mal_error_e mal_i2c_transfer(mal_i2c_s *handle, mal_i2c_msg_s *msg) { // Make sure I2C is free if (handle->is_active) { return MAL_ERROR_HARDWARE_UNAVAILABLE; } handle->is_active = true; // Save msg handle->msg = msg; i2c_start_transfer(handle); return MAL_ERROR_OK; }
void smbus_write_block(i2c_bus *bus, int addr, uint8_t command, uint8_t *data, int len) { int i; if (len > 32) len = 32; i2c_start_transfer(bus, addr, 0); i2c_send(bus, command); i2c_send(bus, len); for (i = 0; i < len; i++) i2c_send(bus, data[i]); i2c_end_transfer(bus); }
void smbus_send_byte(i2c_bus *bus, int addr, uint8_t data) { i2c_start_transfer(bus, addr, 0); i2c_send(bus, data); i2c_end_transfer(bus); }
/* Master device commands. */ void smbus_quick_command(I2CBus *bus, uint8_t addr, int read) { i2c_start_transfer(bus, addr, read); i2c_end_transfer(bus); }
static void i2c_state_update(i2c_interface *i2c, int data, int clock) { if (!i2c) return; switch (i2c->state) { case STOPPED: if (data == 0 && i2c->last_data == 1 && clock == 1) i2c->state = INITIALIZING; break; case INITIALIZING: if (clock == 0 && i2c->last_clock == 1 && data == 0) i2c->state = SENDING_BIT7; else i2c_enter_stop(i2c); break; case SENDING_BIT7 ... SENDING_BIT0: if (clock == 0 && i2c->last_clock == 1) { i2c->buffer = (i2c->buffer << 1) | data; i2c->state++; /* will end up in WAITING_FOR_ACK */ } else if (data == 1 && i2c->last_data == 0 && clock == 1) i2c_enter_stop(i2c); break; case WAITING_FOR_ACK: if (clock == 0 && i2c->last_clock == 1) { if (i2c->current_addr < 0) { i2c->current_addr = i2c->buffer; i2c_start_transfer(i2c->bus, i2c->current_addr & 0xfe, i2c->buffer & 1); } else i2c_send(i2c->bus, i2c->buffer); if (i2c->current_addr & 1) { i2c->state = RECEIVING_BIT7; i2c->buffer = i2c_recv(i2c->bus); } else i2c->state = SENDING_BIT7; } else if (data == 1 && i2c->last_data == 0 && clock == 1) i2c_enter_stop(i2c); break; case RECEIVING_BIT7 ... RECEIVING_BIT0: if (clock == 0 && i2c->last_clock == 1) { i2c->state++; /* will end up in SENDING_ACK */ i2c->buffer <<= 1; } else if (data == 1 && i2c->last_data == 0 && clock == 1) i2c_enter_stop(i2c); break; case SENDING_ACK: if (clock == 0 && i2c->last_clock == 1) { i2c->state = RECEIVING_BIT7; if (data == 0) i2c->buffer = i2c_recv(i2c->bus); else i2c_nack(i2c->bus); } else if (data == 1 && i2c->last_data == 0 && clock == 1) i2c_enter_stop(i2c); break; } i2c->last_data = data; i2c->last_clock = clock; }
static void imx_i2c_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { IMXI2CState *s = IMX_I2C(opaque); DPRINTF("write %s [0x%" HWADDR_PRIx "] <- 0x%02x\n", imx_i2c_get_regname(offset), offset, (int)value); value &= 0xff; switch (offset) { case IADR_ADDR: s->iadr = value & IADR_MASK; /* i2c_set_slave_address(s->bus, (uint8_t)s->iadr); */ break; case IFDR_ADDR: s->ifdr = value & IFDR_MASK; break; case I2CR_ADDR: if (imx_i2c_is_enabled(s) && ((value & I2CR_IEN) == 0)) { /* This is a soft reset. IADR is preserved during soft resets */ uint16_t iadr = s->iadr; imx_i2c_reset(DEVICE(s)); s->iadr = iadr; } else { /* normal write */ s->i2cr = value & I2CR_MASK; if (imx_i2c_is_master(s)) { /* set the bus to busy */ s->i2sr |= I2SR_IBB; } else { /* slave mode */ /* bus is not busy anymore */ s->i2sr &= ~I2SR_IBB; /* * if we unset the master mode then it ends the ongoing * transfer if any */ if (s->address != ADDR_RESET) { i2c_end_transfer(s->bus); s->address = ADDR_RESET; } } if (s->i2cr & I2CR_RSTA) { /* Restart */ /* if this is a restart then it ends the ongoing transfer */ if (s->address != ADDR_RESET) { i2c_end_transfer(s->bus); s->address = ADDR_RESET; s->i2cr &= ~I2CR_RSTA; } } } break; case I2SR_ADDR: /* * if the user writes 0 to IIF then lower the interrupt and * reset the bit */ if ((s->i2sr & I2SR_IIF) && !(value & I2SR_IIF)) { s->i2sr &= ~I2SR_IIF; qemu_irq_lower(s->irq); } /* * if the user writes 0 to IAL, reset the bit */ if ((s->i2sr & I2SR_IAL) && !(value & I2SR_IAL)) { s->i2sr &= ~I2SR_IAL; } break; case I2DR_ADDR: /* if the device is not enabled, nothing to do */ if (!imx_i2c_is_enabled(s)) { break; } s->i2dr_write = value & I2DR_MASK; if (imx_i2c_is_master(s)) { /* If this is the first write cycle then it is the slave addr */ if (s->address == ADDR_RESET) { if (i2c_start_transfer(s->bus, extract32(s->i2dr_write, 1, 7), extract32(s->i2dr_write, 0, 1))) { /* if non zero is returned, the adress is not valid */ s->i2sr |= I2SR_RXAK; } else { s->address = s->i2dr_write; s->i2sr &= ~I2SR_RXAK; imx_i2c_raise_interrupt(s); } } else { /* This is a normal data write */ if (i2c_send(s->bus, s->i2dr_write)) { /* if the target return non zero then end the transfer */ s->i2sr |= I2SR_RXAK; s->address = ADDR_RESET; i2c_end_transfer(s->bus); } else { s->i2sr &= ~I2SR_RXAK; imx_i2c_raise_interrupt(s); } } } else { qemu_log_mask(LOG_UNIMP, "[%s]%s: slave mode not implemented\n", TYPE_IMX_I2C, __func__); } break; default: qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad address at offset 0x%" HWADDR_PRIx "\n", TYPE_IMX_I2C, __func__, offset); break; } }
AUXReply aux_request(AUXBus *bus, AUXCommand cmd, uint32_t address, uint8_t len, uint8_t *data) { AUXReply ret = AUX_NACK; I2CBus *i2c_bus = aux_get_i2c_bus(bus); size_t i; bool is_write = false; DPRINTF("request at address 0x%" PRIX32 ", command %u, len %u\n", address, cmd, len); switch (cmd) { /* * Forward the request on the AUX bus.. */ case WRITE_AUX: case READ_AUX: is_write = cmd == READ_AUX ? false : true; for (i = 0; i < len; i++) { if (!address_space_rw(&bus->aux_addr_space, address++, MEMTXATTRS_UNSPECIFIED, data++, 1, is_write)) { ret = AUX_I2C_ACK; } else { ret = AUX_NACK; break; } } break; /* * Classic I2C transactions.. */ case READ_I2C: case WRITE_I2C: is_write = cmd == READ_I2C ? false : true; if (i2c_bus_busy(i2c_bus)) { i2c_end_transfer(i2c_bus); } if (i2c_start_transfer(i2c_bus, address, is_write)) { ret = AUX_I2C_NACK; break; } ret = AUX_I2C_ACK; while (len > 0) { if (i2c_send_recv(i2c_bus, data++, is_write) < 0) { ret = AUX_I2C_NACK; break; } len--; } i2c_end_transfer(i2c_bus); break; /* * I2C MOT transactions. * * Here we send a start when: * - We didn't start transaction yet. * - We had a READ and we do a WRITE. * - We changed the address. */ case WRITE_I2C_MOT: case READ_I2C_MOT: is_write = cmd == READ_I2C_MOT ? false : true; ret = AUX_I2C_NACK; if (!i2c_bus_busy(i2c_bus)) { /* * No transactions started.. */ if (i2c_start_transfer(i2c_bus, address, is_write)) { break; } } else if ((address != bus->last_i2c_address) || (bus->last_transaction != cmd)) { /* * Transaction started but we need to restart.. */ i2c_end_transfer(i2c_bus); if (i2c_start_transfer(i2c_bus, address, is_write)) { break; } } bus->last_transaction = cmd; bus->last_i2c_address = address; while (len > 0) { if (i2c_send_recv(i2c_bus, data++, is_write) < 0) { i2c_end_transfer(i2c_bus); break; } len--; } if (len == 0) { ret = AUX_I2C_ACK; } break; default: DPRINTF("Not implemented!\n"); return AUX_NACK; } DPRINTF("reply: %u\n", ret); return ret; }
/* Master device commands. */ void smbus_quick_command(i2c_bus *bus, int addr, int read) { i2c_start_transfer(bus, addr, read); i2c_end_transfer(bus); }