예제 #1
0
파일: smbus.c 프로젝트: AmesianX/winkvm
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;
}
예제 #2
0
파일: smbus.c 프로젝트: Blopeur/qemu-heca
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;
}
예제 #3
0
파일: smbus.c 프로젝트: AmesianX/winkvm
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);
}
예제 #4
0
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;
		}
	}
}
예제 #5
0
파일: pca954x.c 프로젝트: Xilinx/qemu
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;
}
예제 #6
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);
    }
}
예제 #7
0
파일: smbus.c 프로젝트: AmesianX/winkvm
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;
}
예제 #8
0
파일: smbus.c 프로젝트: AmesianX/winkvm
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);
}
예제 #9
0
파일: smbus.c 프로젝트: AmesianX/winkvm
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;
}
예제 #10
0
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;
}
예제 #11
0
파일: smbus.c 프로젝트: AmesianX/winkvm
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);
}
예제 #12
0
파일: smbus.c 프로젝트: AmesianX/winkvm
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);
}
예제 #13
0
/* Master device commands.  */
void smbus_quick_command(I2CBus *bus, uint8_t addr, int read)
{
    i2c_start_transfer(bus, addr, read);
    i2c_end_transfer(bus);
}
예제 #14
0
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;
}
예제 #15
0
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;
    }
}
예제 #16
0
파일: auxbus.c 프로젝트: 8tab/qemu
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;
}
예제 #17
0
파일: smbus.c 프로젝트: AmesianX/winkvm
/* Master device commands.  */
void smbus_quick_command(i2c_bus *bus, int addr, int read)
{
    i2c_start_transfer(bus, addr, read);
    i2c_end_transfer(bus);
}