Beispiel #1
0
/* Task that listens for incomming IPC messages from Host and initiate host
 * command processing.
 */
void ipc_comm_task(void)
{
	int ret = 0;
	uint32_t out_drbl, pkt_len;

	for (;;) {

		ret = task_wait_event_mask(EVENT_FLAG_BIT_READ_IPC
					   | EVENT_FLAG_BIT_WRITE_IPC, -1);

		if ((ret & EVENT_FLAG_BIT_WRITE_IPC))
			continue;
		else if (!(ret & EVENT_FLAG_BIT_READ_IPC))
			continue;

		/* Read the command byte.  This clears the FRMH bit in
		 * the status byte.
		 */
		out_drbl = REG32(IPC_HOST2ISH_DOORBELL);
		pkt_len = out_drbl & IPC_HEADER_LENGTH_MASK;

		ret = ipc_read(IPC_PEER_HOST_ID, ipc_host_args, pkt_len);
		host_cmd_args.command = EC_COMMAND_PROTOCOL_3;

		host_cmd_args.result = EC_RES_SUCCESS;
		host_cmd_flags = ipc_host_args->flags;

		/* We only support new style command (v3) now */
		if (host_cmd_args.command == EC_COMMAND_PROTOCOL_3) {
			ipc_packet.send_response = ipc_send_response_packet;

			ipc_packet.request =
			    (const void *)ipc_get_hostcmd_data_range();
			ipc_packet.request_temp = params_copy;
			ipc_packet.request_max = sizeof(params_copy);
			/* Don't know the request size so pass in
			 * the entire buffer
			 */
			ipc_packet.request_size = EC_LPC_HOST_PACKET_SIZE;

			ipc_packet.response =
			    (void *)ipc_get_hostcmd_data_range();
			ipc_packet.response_max = EC_LPC_HOST_PACKET_SIZE;
			ipc_packet.response_size = 0;

			ipc_packet.driver_result = EC_RES_SUCCESS;
			host_packet_receive(&ipc_packet);
			usleep(10);	/* To force yield */

			continue;
		} else {
			/* Old style command unsupported */
			host_cmd_args.result = EC_RES_INVALID_COMMAND;
		}

		/* Hand off to host command handler */
		host_command_received(&host_cmd_args);
	}
}
Beispiel #2
0
/**
 * Flush an ADC sequencer and initiate a read.
 *
 * @param seq		Sequencer to read
 * @return Raw ADC value.
 */
static int flush_and_read(enum lm4_adc_sequencer seq)
{
	/*
	 * This is currently simple because we can dedicate a sequencer to each
	 * ADC channel.  If we have enough channels that's no longer possible,
	 * this code will need to become more complex.  For example, we could:
	 *
	 * 1) Read them all using a timer interrupt, and then return the most
	 * recent value?  This is lowest-latency for the caller, but won't
	 * return accurate data if read frequently.
	 *
	 * 2) Reserve SS3 for reading a single value, and configure it on each
	 * read?  Needs mutex if we could have multiple callers; doesn't matter
	 * if just used for debugging.
	 *
	 * 3) Both?
	 */
	volatile uint32_t scratch  __attribute__((unused));
	int event;

	/* Empty the FIFO of any previous results */
	while (!(LM4_ADC_SSFSTAT(seq) & 0x100))
		scratch = LM4_ADC_SSFIFO(seq);

	/*
	 * This assumes we don't have multiple tasks accessing the same
	 * sequencer. Add mutex lock if needed.
	 */
	task_waiting_on_ss[seq] = task_get_current();

	/* Clear the interrupt status */
	LM4_ADC_ADCISC |= 0x01 << seq;

	/* Enable interrupt */
	LM4_ADC_ADCIM |= 0x01 << seq;

	/* Initiate sample sequence */
	LM4_ADC_ADCPSSI |= 0x01 << seq;

	/* Wait for interrupt */
	event = task_wait_event_mask(TASK_EVENT_ADC_DONE, ADC_TIMEOUT_US);

	/* Disable interrupt */
	LM4_ADC_ADCIM &= ~(0x01 << seq);

	task_waiting_on_ss[seq] = TASK_ID_INVALID;

	if (!(event & TASK_EVENT_ADC_DONE))
		return ADC_READ_ERROR;

	/* Read the FIFO and convert to temperature */
	return LM4_ADC_SSFIFO(seq);
}
Beispiel #3
0
static int ipc_wait_until_msg_consumed(struct ipc_if_ctx *ctx, int timeout)
{
	int wait_sts = 0;
	uint32_t drbl;

	drbl = REG32(ctx->out_drbl_reg);
	if (!(drbl & IPC_DRBL_BUSY_BIT)) {
		/* doorbell is already cleared. we can continue */
		return 0;
	}

	while (1) {
		wait_sts = task_wait_event_mask(EVENT_FLAG_BIT_WRITE_IPC,
						timeout);
		drbl = REG32(ctx->out_drbl_reg);

		if (!(drbl & IPC_DRBL_BUSY_BIT)) {
			return 0;
		} else if (wait_sts != 0) {
			/* timeout */
			return wait_sts;
		}
	}
}
Beispiel #4
0
int chip_i2c_xfer(int port, int slave_addr, const uint8_t *out, int out_size,
	     uint8_t *in, int in_size, int flags)
{
	struct i2c_port_data *pd = pdata + port;
	uint32_t events = 0;

	if (out_size == 0 && in_size == 0)
		return EC_SUCCESS;

	if (pd->i2ccs) {
		if ((flags & I2C_XFER_SINGLE) == I2C_XFER_SINGLE)
			flags &= ~I2C_XFER_START;
	}

	/* Copy data to port struct */
	pd->out = out;
	pd->out_size = out_size;
	pd->in = in;
	pd->in_size = in_size;
	pd->flags = flags;
	pd->widx = 0;
	pd->ridx = 0;
	pd->err = 0;
	pd->addr = slave_addr;

	if (port < I2C_STANDARD_PORT_COUNT) {
		/* Make sure we're in a good state to start */
		if ((flags & I2C_XFER_START) && (i2c_is_busy(port)
			|| (IT83XX_SMB_HOSTA(port) & HOSTA_ALL_WC_BIT)
			|| (i2c_get_line_levels(port) != I2C_LINE_IDLE))) {

			/* Attempt to unwedge the port. */
			i2c_unwedge(port);
			/* reset i2c port */
			i2c_reset(port, I2C_RC_NO_IDLE_FOR_START);
		}
	} else {
		/* Make sure we're in a good state to start */
		if ((flags & I2C_XFER_START) && (i2c_is_busy(port)
			|| (i2c_get_line_levels(port) != I2C_LINE_IDLE))) {
			/* Attempt to unwedge the port. */
			i2c_unwedge(port);
			/* reset i2c port */
			i2c_reset(port, I2C_RC_NO_IDLE_FOR_START);
		}
	}

	pd->task_waiting = task_get_current();
	if (pd->flags & I2C_XFER_START) {
		pd->i2ccs = I2C_CH_NORMAL;
		/* enable i2c interrupt */
		task_clear_pending_irq(i2c_ctrl_regs[port].irq);
		task_enable_irq(i2c_ctrl_regs[port].irq);
	}
	/* Start transaction */
	i2c_transaction(port);
	/* Wait for transfer complete or timeout */
	events = task_wait_event_mask(TASK_EVENT_I2C_IDLE, pd->timeout_us);
	/* disable i2c interrupt */
	task_disable_irq(i2c_ctrl_regs[port].irq);
	pd->task_waiting = TASK_ID_INVALID;

	/* Handle timeout */
	if (!(events & TASK_EVENT_I2C_IDLE)) {
		pd->err = EC_ERROR_TIMEOUT;
		/* reset i2c port */
		i2c_reset(port, I2C_RC_TIMEOUT);
	}

	/* reset i2c channel status */
	if (pd->err)
		pd->i2ccs = I2C_CH_NORMAL;

	return pd->err;
}
Beispiel #5
0
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;
}