Exemplo n.º 1
0
/**
 * IPC interrupts are recieved by the FW when a) Host SW rings doorbell and
 * b) when Host SW clears doorbell busy bit [31].
 *
 * Doorbell Register (DB) bits
 * ----+-------+--------+-----------+--------+------------+--------------------
 *  31 | 30 29 |  28-20 |19 18 17 16| 15 14  | 13 12 11 10| 9 8 7 6 5 4 3 2 1 0
 * ----+-------+--------+-----------+--------+------------+--------------------
 * Busy|Options|Reserved|  Command  |Reserved|   Protocol |    Message Length
 * ----+-------+--------+-----------+--------+------------+--------------------
 *
 * ISH Peripheral Interrupt Status Register:
 *  Bit 0 - If set, indicates interrupt was caused by setting Host2ISH DB
 *
 * ISH Peripheral Interrupt Mask Register
 *  Bit 0 - If set, mask interrupt caused by Host2ISH DB
 *
 * ISH Peripheral DB Clear Status Register
 *  Bit 0 - If set, indicates interrupt was caused by clearing Host2ISH DB
 */
static void ipc_interrupt_handler(void)
{
	uint32_t pisr = REG32(IPC_PISR);
	uint32_t pimr = REG32(IPC_PIMR);
	uint32_t busy_clear = REG32(IPC_BUSY_CLEAR);
	uint32_t drbl = REG32(IPC_ISH2HOST_MSG_REGS);
	uint8_t proto, cmd;

	if ((pisr & IPC_PISR_HOST2ISH_BIT)
	    && (pimr & IPC_PIMR_HOST2ISH_BIT)) {

		/* New message arrived */
		ipc_set_pimr(IPC_PEER_HOST_ID, UNSET_PIMR, PIMR_SIGNAL_IN);
		task_set_event(TASK_ID_IPC_COMM, EVENT_FLAG_BIT_READ_IPC, 0);
		proto = IPC_HEADER_GET_PROTOCOL(drbl);
		cmd = IPC_HEADER_GET_MNG_CMD(drbl);

		if ((proto == IPC_PROTOCOL_MNG) && (cmd == MNG_TIME_UPDATE))
			/* Ignoring time update from host */
			;
	}

	if ((busy_clear & IPC_INT_ISH2HOST_CLR_BIT)
	    && (pimr & IPC_PIMR_ISH2HOST_CLR_MASK_BIT)) {
		/* Written message cleared */
		REG32(IPC_BUSY_CLEAR) = IPC_ISH_FWSTS;
		task_set_event(TASK_ID_IPC_COMM, EVENT_FLAG_BIT_WRITE_IPC, 0);
	}
}
Exemplo n.º 2
0
static void chip_pd_irq(enum usbpd_port port)
{
	task_clear_pending_irq(usbpd_ctrl_regs[port].irq);

	/* check status */
	if (USBPD_IS_HARD_RESET_DETECT(port)) {
		/* clear interrupt */
		IT83XX_USBPD_ISR(port) = USBPD_REG_MASK_HARD_RESET_DETECT;
		task_set_event(PD_PORT_TO_TASK_ID(port),
			PD_EVENT_TCPC_RESET, 0);
	} else {
		if (USBPD_IS_RX_DONE(port)) {
			/* mask RX done interrupt */
			IT83XX_USBPD_IMR(port) |= USBPD_REG_MASK_MSG_RX_DONE;
			/* clear RX done interrupt */
			IT83XX_USBPD_ISR(port) = USBPD_REG_MASK_MSG_RX_DONE;
			task_set_event(PD_PORT_TO_TASK_ID(port),
				PD_EVENT_RX, 0);
		}
		if (USBPD_IS_TX_DONE(port)) {
			/* clear TX done interrupt */
			IT83XX_USBPD_ISR(port) = USBPD_REG_MASK_MSG_TX_DONE;
			task_set_event(PD_PORT_TO_TASK_ID(port),
				TASK_EVENT_PHY_TX_DONE, 0);
		}
	}
}
Exemplo n.º 3
0
void tcpci_tcpc_alert(int port)
{
	int status;

	/* Read the Alert register from the TCPC */
	tcpm_alert_status(port, &status);

	/*
	 * Clear alert status for everything except RX_STATUS, which shouldn't
	 * be cleared until we have successfully retrieved message.
	 */
	if (status & ~TCPC_REG_ALERT_RX_STATUS)
		tcpc_write16(port, TCPC_REG_ALERT,
			     status & ~TCPC_REG_ALERT_RX_STATUS);

	if (status & TCPC_REG_ALERT_CC_STATUS) {
		/* CC status changed, wake task */
		task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_CC, 0);
	}
	if (status & TCPC_REG_ALERT_POWER_STATUS) {
		int reg = 0;

		tcpc_read(port, TCPC_REG_POWER_STATUS_MASK, &reg);

		if (reg == TCPC_REG_POWER_STATUS_MASK_ALL) {
			/*
			 * If power status mask has been reset, then the TCPC
			 * has reset.
			 */
			task_set_event(PD_PORT_TO_TASK_ID(port),
				       PD_EVENT_TCPC_RESET, 0);
		} else {
			/* Read Power Status register */
			tcpci_tcpm_get_power_status(port, &reg);
			/* Update VBUS status */
			tcpc_vbus[port] = reg &
				TCPC_REG_POWER_STATUS_VBUS_PRES ? 1 : 0;
#if defined(CONFIG_USB_PD_VBUS_DETECT_TCPC) && defined(CONFIG_USB_CHARGER)
			/* Update charge manager with new VBUS state */
			usb_charger_vbus_change(port, tcpc_vbus[port]);
			task_wake(PD_PORT_TO_TASK_ID(port));
#endif /* CONFIG_USB_PD_VBUS_DETECT_TCPC && CONFIG_USB_CHARGER */
		}
	}
	if (status & TCPC_REG_ALERT_RX_STATUS) {
		/* message received */
		task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_RX, 0);
	}
	if (status & TCPC_REG_ALERT_RX_HARD_RST) {
		/* hard reset received */
		pd_execute_hard_reset(port);
		task_wake(PD_PORT_TO_TASK_ID(port));
	}
	if (status & TCPC_REG_ALERT_TX_COMPLETE) {
		/* transmit complete */
		pd_transmit_complete(port, status & TCPC_REG_ALERT_TX_SUCCESS ?
					   TCPC_TX_COMPLETE_SUCCESS :
					   TCPC_TX_COMPLETE_FAILED);
	}
}
Exemplo n.º 4
0
void tcpc_alert(int port)
{
	int status;

	/* Read the Alert register from the TCPC */
	tcpm_alert_status(port, &status);

	/*
	 * Clear alert status for everything except RX_STATUS, which shouldn't
	 * be cleared until we have successfully retrieved message.
	 */
	if (status & ~TCPC_REG_ALERT_RX_STATUS)
		i2c_write16(I2C_PORT_TCPC, I2C_ADDR_TCPC(port),
			    TCPC_REG_ALERT, status & ~TCPC_REG_ALERT_RX_STATUS);

	if (status & TCPC_REG_ALERT_CC_STATUS) {
		/* CC status changed, wake task */
		task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_CC, 0);
	}
	if (status & TCPC_REG_ALERT_RX_STATUS) {
		/* message received */
		task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_RX, 0);
	}
	if (status & TCPC_REG_ALERT_RX_HARD_RST) {
		/* hard reset received */
		pd_execute_hard_reset(port);
		task_wake(PD_PORT_TO_TASK_ID(port));
	}
	if (status & TCPC_REG_ALERT_TX_COMPLETE) {
		/* transmit complete */
		pd_transmit_complete(port, status & TCPC_REG_ALERT_TX_SUCCESS ?
					   TCPC_TX_COMPLETE_SUCCESS :
					   TCPC_TX_COMPLETE_FAILED);
	}
}
Exemplo n.º 5
0
void usb_charger_vbus_change(int port, int vbus_level)
{
	/* Update VBUS supplier and signal VBUS change to USB_CHG task */
	update_vbus_supplier(port, vbus_level);
#if CONFIG_USB_PD_PORT_COUNT == 2
	task_set_event(port ? TASK_ID_USB_CHG_P1 : TASK_ID_USB_CHG_P0,
		       USB_CHG_EVENT_VBUS, 0);
#else
	task_set_event(TASK_ID_USB_CHG_P0, USB_CHG_EVENT_VBUS, 0);
#endif
}
Exemplo n.º 6
0
void anx74xx_tcpc_alert(int port)
{
	int status;

	/* Check the alert status */
	if (anx74xx_alert_status(port, &status))
		status = 0;
	if (status) {

		if (status & ANX74XX_REG_ALERT_CC_CHANGE) {
			/* CC status changed, wake task */
			task_set_event(PD_PORT_TO_TASK_ID(port),
					PD_EVENT_CC, 0);
		}

		/* If alert is to receive a message */
		if (status & ANX74XX_REG_ALERT_MSG_RECV) {
			/* Set a PD_EVENT_RX */
			task_set_event(PD_PORT_TO_TASK_ID(port),
						PD_EVENT_RX, 0);
		}
		if (status & ANX74XX_REG_ALERT_TX_ACK_RECV) {
			/* Inform PD about this TX success */
			pd_transmit_complete(port,
						TCPC_TX_COMPLETE_SUCCESS);
		}
		if (status & ANX74XX_REG_ALERT_TX_MSG_ERROR) {
			/* let PD does not wait for this */
			pd_transmit_complete(port,
					      TCPC_TX_COMPLETE_FAILED);
		}
		if (status & ANX74XX_REG_ALERT_TX_CABLE_RESETOK) {
			/* ANX hardware clears the request bit */
			pd_transmit_complete(port,
					      TCPC_TX_COMPLETE_SUCCESS);
		}
		if (status & ANX74XX_REG_ALERT_TX_HARD_RESETOK) {
			/* ANX hardware clears the request bit */
			pd_transmit_complete(port,
					     TCPC_TX_COMPLETE_SUCCESS);
		}
		if (status & ANX74XX_REG_ALERT_HARD_RST_RECV) {
			/* hard reset received */
			pd_execute_hard_reset(port);
			task_wake(PD_PORT_TO_TASK_ID(port));
		}
	}
}
Exemplo n.º 7
0
static inline void _dma_wake_callback(void *cb_data)
{
	task_id_t id = (task_id_t)(int)cb_data;

	if (id != TASK_ID_INVALID)
		task_set_event(id, TASK_EVENT_DMA_TC, 0);
}
Exemplo n.º 8
0
void host_command_pd_send_status(enum pd_charge_state new_chg_state)
{
	/* Update PD MCU charge state if necessary */
	if (new_chg_state != PD_CHARGE_NO_CHANGE)
		charge_state = new_chg_state;
	/* Wake PD HC task to send status */
	task_set_event(TASK_ID_PDCMD, TASK_EVENT_EXCHANGE_PD_STATUS, 0);
}
Exemplo n.º 9
0
static void anx74xx_cable_det_handler(void)
{
	/* confirm if cable_det is asserted */
	if (!gpio_get_level(GPIO_USB_C0_CABLE_DET) ||
		gpio_get_level(GPIO_USB_C0_PD_RST_L))
		return;

	task_set_event(TASK_ID_PD_C0, PD_EVENT_TCPC_RESET, 0);
}
Exemplo n.º 10
0
/**
 * Handle an interrupt on the specified sample sequencer.
 */
static void handle_interrupt(int ss)
{
	int id = task_waiting_on_ss[ss];

	/* Clear the interrupt status */
	LM4_ADC_ADCISC = (0x1 << ss);

	/* Wake up the task which was waiting on the interrupt, if any */
	if (id != TASK_ID_INVALID)
		task_set_event(id, TASK_EVENT_ADC_DONE, 0);
}
Exemplo n.º 11
0
void mutex_unlock(struct mutex *mtx)
{
	int v;
	mtx->lock = 0;

	for (v = 31; v >= 0; --v)
		if ((1ul << v) & mtx->waiters) {
			mtx->waiters &= ~(1ul << v);
			task_set_event(v, TASK_EVENT_MUTEX, 0);
			break;
		}
}
Exemplo n.º 12
0
void task_abc(void *data)
{
	int task_id = task_get_current();
	int id = task_id - TASK_ID_A;
	task_id_t next = task_id + 1;

	if (next > TASK_ID_C)
		next = TASK_ID_A;

	task_wait_event(-1);

	CPRINTS("%c Starting", 'A' + id);
	cflush();

	while (1) {
		wake_count[id]++;
		if (id == 2 && wake_count[id] == repeat_count)
			task_set_event(TASK_ID_CTS, TASK_EVENT_WAKE, 1);
		else
			task_set_event(next, TASK_EVENT_WAKE, 1);
	}
}
Exemplo n.º 13
0
void i2c_master_int_handler (int controller)
{
	volatile struct i2c_status *p_status = i2c_stsobjs + controller;
	/* Condition 1 : A Bus Error has been identified */
	if (IS_BIT_SET(NPCX_SMBST(controller), NPCX_SMBST_BER)) {
		/* Generate a STOP condition */
		I2C_STOP(controller);
		CPUTS("-SP");
		/* Clear BER Bit */
		SET_BIT(NPCX_SMBST(controller), NPCX_SMBST_BER);
		/* Set error code */
		p_status->err_code = SMB_BUS_ERROR;
		/* Notify upper layer */
		p_status->oper_state = SMB_IDLE;
		task_set_event(p_status->task_waiting, TASK_EVENT_I2C_IDLE, 0);
		CPUTS("-BER");
	}

	/* Condition 2: A negative acknowledge has occurred */
	if (IS_BIT_SET(NPCX_SMBST(controller), NPCX_SMBST_NEGACK)) {
		/* Generate a STOP condition */
		I2C_STOP(controller);
		CPUTS("-SP");
		/* Clear NEGACK Bit */
		SET_BIT(NPCX_SMBST(controller), NPCX_SMBST_NEGACK);
		/* Set error code */
		p_status->err_code = SMB_MASTER_NO_ADDRESS_MATCH;
		/* Notify upper layer */
		p_status->oper_state = SMB_IDLE;
		task_set_event(p_status->task_waiting, TASK_EVENT_I2C_IDLE, 0);
		CPUTS("-NA");
	}

	/* Condition 3: SDA status is set - transmit or receive */
	if (IS_BIT_SET(NPCX_SMBST(controller), NPCX_SMBST_SDAST))
		i2c_handle_sda_irq(controller);
}
Exemplo n.º 14
0
void host_command_received(struct host_cmd_handler_args *args)
{
	/*
	 * TODO(crosbug.com/p/23806): should warn if we already think we're in
	 * a command.
	 */

	/*
	 * If this is the reboot command, reboot immediately.  This gives the
	 * host processor a way to unwedge the EC even if it's busy with some
	 * other command.
	 */
	if (args->command == EC_CMD_REBOOT) {
		system_reset(SYSTEM_RESET_HARD);
		/* Reset should never return; if it does, post an error */
		args->result = EC_RES_ERROR;
	}

#ifdef CONFIG_AP_HANG_DETECT
	/* If hang detection is enabled, check stop on host command */
	hang_detect_stop_on_host_command();
#endif

	if (args->result) {
		; /* driver has signalled an error, respond now */
#ifdef CONFIG_HOST_COMMAND_STATUS
	} else if (args->command == EC_CMD_GET_COMMS_STATUS) {
		args->result = host_command_process(args);
#endif
	} else {
		/* Save the command */
		pending_args = args;

		/* Wake up the task to handle the command */
		task_set_event(TASK_ID_HOSTCMD, TASK_EVENT_CMD_PENDING, 0);
		return;
	}

	/*
	 * TODO (crosbug.com/p/29315): This is typically running in interrupt
	 * context, so it woud be better not to send the response here, and to
	 * let the host command task send the response.
	 */
	/* Send the response now */
	host_send_response(args);
}
Exemplo n.º 15
0
void i2c_interrupt(int port)
{
	int id = pdata[port].task_waiting;

	/* Clear the interrupt status */
	task_clear_pending_irq(i2c_ctrl_regs[port].irq);

	/* If no task is waiting, just return */
	if (id == TASK_ID_INVALID)
		return;

	/* If done doing work, wake up the task waiting for the transfer */
	if (!i2c_transaction(port)) {
		task_disable_irq(i2c_ctrl_regs[port].irq);
		task_set_event(id, TASK_EVENT_I2C_IDLE, 0);
	}
}
Exemplo n.º 16
0
Arquivo: i2c.c Projeto: thehobn/ec
static void handle_interrupt(int port)
{
	int id = task_waiting_on_port[port];

	/* Clear the interrupt status */
	MEC1322_I2C_COMPLETE(port) |= 1 << 29;

	/*
	 * Write to control register interferes with I2C transaction.
	 * Instead, let's disable IRQ from the core until the next time
	 * we want to wait for STS_PIN/STS_NBB.
	 */
	task_disable_irq(MEC1322_IRQ_I2C_0 + port);

	/* Wake up the task which was waiting on the I2C interrupt, if any. */
	if (id != TASK_ID_INVALID)
		task_set_event(id, TASK_EVENT_I2C_IDLE, 0);
}
Exemplo n.º 17
0
void usb_charger_vbus_change(int port, int vbus_level)
{
	/* If VBUS has transitioned low, notify PD module directly */
	if (!vbus_level)
		pd_vbus_low(port);

	/* Update VBUS supplier and signal VBUS change to USB_CHG task */
	update_vbus_supplier(port, vbus_level);

#ifdef HAS_TASK_USB_CHG_P0
	/* USB Charger task(s) */
	task_set_event(USB_CHG_PORT_TO_TASK_ID(port), USB_CHG_EVENT_VBUS, 0);
#endif

#ifdef CONFIG_USB_PD_VBUS_DETECT_CHARGER
	/* USB PD task */
	task_wake(PD_PORT_TO_TASK_ID(port));
#endif
}
Exemplo n.º 18
0
Arquivo: i2c.c Projeto: thehobn/ec
static int wait_byte_done(int port)
{
	uint8_t sts = MEC1322_I2C_STATUS(port);
	int rv;
	int event = 0;

	while (sts & STS_PIN) {
		rv = wait_for_interrupt(port, &event);
		if (rv)
			return rv;
		sts = MEC1322_I2C_STATUS(port);
	}
	/*
	 * Restore any events that we saw while waiting. TASK_EVENT_TIMER isn't
	 * one, because we've handled it above.
	 */
	task_set_event(task_get_current(), event, 0);

	return sts & STS_LRB;
}
Exemplo n.º 19
0
Arquivo: i2c.c Projeto: thehobn/ec
static int wait_for_interrupt(int port, int *event)
{
	task_waiting_on_port[port] = task_get_current();
	task_enable_irq(MEC1322_IRQ_I2C_0 + port);
	/*
	 * We want to wait here quietly until the I2C interrupt comes
	 * along, but we don't want to lose any pending events that
	 * will be needed by the task that started the I2C transaction
	 * in the first place. So we save them up and restore them when
	 * the I2C is either completed or timed out. Refer to the
	 * implementation of usleep() for a similar situation.
	 */
	*event |= (task_wait_event(SECOND) & ~TASK_EVENT_I2C_IDLE);
	task_waiting_on_port[port] = TASK_ID_INVALID;
	if (*event & TASK_EVENT_TIMER) {
		/* Restore any events that we saw while waiting */
		task_set_event(task_get_current(),
				(*event & ~TASK_EVENT_TIMER), 0);
		return EC_ERROR_TIMEOUT;
	}
	return EC_SUCCESS;
}
Exemplo n.º 20
0
Arquivo: i2c.c Projeto: thehobn/ec
static int wait_idle(int port)
{
	uint8_t sts = MEC1322_I2C_STATUS(port);
	int rv;
	int event = 0;

	while (!(sts & STS_NBB)) {
		rv = wait_for_interrupt(port, &event);
		if (rv)
			return rv;
		sts = MEC1322_I2C_STATUS(port);
	}
	/*
	 * Restore any events that we saw while waiting. TASK_EVENT_TIMER isn't
	 * one, because we've handled it above.
	 */
	task_set_event(task_get_current(), event, 0);

	if (sts & (STS_BER | STS_LAB))
		return EC_ERROR_UNKNOWN;
	return EC_SUCCESS;
}
Exemplo n.º 21
0
void tcpc_alert(int port)
{
	int status;

	/* Read the Alert register from the TCPC */
	tcpm_alert_status(port, &status);

	/*
	 * Clear alert status for everything except RX_STATUS, which shouldn't
	 * be cleared until we have successfully retrieved message.
	 */
	if (status & ~TCPC_REG_ALERT_RX_STATUS)
		tcpc_alert_status_clear(port,
					status & ~TCPC_REG_ALERT_RX_STATUS);

	if (status & TCPC_REG_ALERT_CC_STATUS) {
		/* CC status changed, wake task */
		task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_CC, 0);
	}
	if (status & TCPC_REG_ALERT_RX_STATUS) {
		/*
		 * message received. since TCPC is compiled in, we
		 * already received PD_EVENT_RX from phy layer in
		 * pd_rx_event(), so we don't need to set another
		 * event.
		 */
	}
	if (status & TCPC_REG_ALERT_RX_HARD_RST) {
		/* hard reset received */
		pd_execute_hard_reset(port);
		task_wake(PD_PORT_TO_TASK_ID(port));
	}
	if (status & TCPC_REG_ALERT_TX_COMPLETE) {
		/* transmit complete */
		pd_transmit_complete(port, status & TCPC_REG_ALERT_TX_SUCCESS ?
					   TCPC_TX_COMPLETE_SUCCESS :
					   TCPC_TX_COMPLETE_FAILED);
	}
}
Exemplo n.º 22
0
void board_set_charge_limit(int port, int supplier, int limit_ma, int max_ma)
{
	charge_limit_ma = limit_ma;
	if (charge_limit_ma > overcurrent_current_ma)
		task_set_event(TASK_ID_TEST_RUNNER, TASK_EVENT_OVERCURRENT, 0);
}
Exemplo n.º 23
0
static int host_cmd_motion_sense(struct host_cmd_handler_args *args)
{
	const struct ec_params_motion_sense *in = args->params;
	struct ec_response_motion_sense *out = args->response;
	struct motion_sensor_t *sensor;
	int i, ret = EC_RES_INVALID_PARAM, reported;

	switch (in->cmd) {
	case MOTIONSENSE_CMD_DUMP:
		out->dump.module_flags =
			(*(host_get_memmap(EC_MEMMAP_ACC_STATUS)) &
			 EC_MEMMAP_ACC_STATUS_PRESENCE_BIT) ?
			MOTIONSENSE_MODULE_FLAG_ACTIVE : 0;
		out->dump.sensor_count = motion_sensor_count;
		args->response_size = sizeof(out->dump);
		reported = MIN(motion_sensor_count, in->dump.max_sensor_count);
		mutex_lock(&g_sensor_mutex);
		for (i = 0; i < reported; i++) {
			sensor = &motion_sensors[i];
			out->dump.sensor[i].flags =
				MOTIONSENSE_SENSOR_FLAG_PRESENT;
			/* casting from int to s16 */
			out->dump.sensor[i].data[X] = sensor->xyz[X];
			out->dump.sensor[i].data[Y] = sensor->xyz[Y];
			out->dump.sensor[i].data[Z] = sensor->xyz[Z];
		}
		mutex_unlock(&g_sensor_mutex);
		args->response_size += reported *
			sizeof(struct ec_response_motion_sensor_data);
		break;

	case MOTIONSENSE_CMD_DATA:
		sensor = host_sensor_id_to_motion_sensor(
				in->sensor_odr.sensor_num);
		if (sensor == NULL)
			return EC_RES_INVALID_PARAM;

		out->data.flags = 0;

		mutex_lock(&g_sensor_mutex);
		out->data.data[X] = sensor->xyz[X];
		out->data.data[Y] = sensor->xyz[Y];
		out->data.data[Z] = sensor->xyz[Z];
		mutex_unlock(&g_sensor_mutex);
		args->response_size = sizeof(out->data);
		break;

	case MOTIONSENSE_CMD_INFO:
		sensor = host_sensor_id_to_motion_sensor(
				in->sensor_odr.sensor_num);
		if (sensor == NULL)
			return EC_RES_INVALID_PARAM;

		out->info.type = sensor->type;
		out->info.location = sensor->location;
		out->info.chip = sensor->chip;

		args->response_size = sizeof(out->info);
		break;

	case MOTIONSENSE_CMD_EC_RATE:
		sensor = host_sensor_id_to_motion_sensor(
				in->sensor_odr.sensor_num);
		if (sensor == NULL)
			return EC_RES_INVALID_PARAM;

		/*
		 * Set new sensor sampling rate when AP is on, if the data arg
		 * has a value.
		 */
		if (in->ec_rate.data != EC_MOTION_SENSE_NO_VALUE) {
			if (in->ec_rate.data == 0)
				sensor->config[SENSOR_CONFIG_AP].ec_rate = 0;
			else
				sensor->config[SENSOR_CONFIG_AP].ec_rate =
					MAX(in->ec_rate.data,
					    MIN_MOTION_SENSE_WAIT_TIME / MSEC);

			/* Bound the new sampling rate. */
			motion_sense_set_accel_interval();
		}

		out->ec_rate.ret = motion_sense_ec_rate(sensor) / MSEC;

		args->response_size = sizeof(out->ec_rate);
		break;

	case MOTIONSENSE_CMD_SENSOR_ODR:
		/* Verify sensor number is valid. */
		sensor = host_sensor_id_to_motion_sensor(
				in->sensor_odr.sensor_num);
		if (sensor == NULL)
			return EC_RES_INVALID_PARAM;

		/* Set new data rate if the data arg has a value. */
		if (in->sensor_odr.data != EC_MOTION_SENSE_NO_VALUE) {
			sensor->config[SENSOR_CONFIG_AP].odr =
				in->sensor_odr.data |
				(in->sensor_odr.roundup ? ROUND_UP_FLAG : 0);

			ret = motion_sense_set_data_rate(sensor);
			if (ret != EC_SUCCESS)
				return EC_RES_INVALID_PARAM;

			/*
			 * To be sure timestamps are calculated properly,
			 * Send an event to have a timestamp inserted in the
			 * FIFO.
			 */
			task_set_event(TASK_ID_MOTIONSENSE,
					TASK_EVENT_MOTION_ODR_CHANGE, 0);
			/*
			 * If the sensor was suspended before, or now
			 * suspended, we have to recalculate the EC sampling
			 * rate
			 */
			motion_sense_set_accel_interval();
		}

		out->sensor_odr.ret = sensor->drv->get_data_rate(sensor);

		args->response_size = sizeof(out->sensor_odr);

		break;

	case MOTIONSENSE_CMD_SENSOR_RANGE:
		/* Verify sensor number is valid. */
		sensor = host_sensor_id_to_motion_sensor(
				in->sensor_range.sensor_num);
		if (sensor == NULL)
			return EC_RES_INVALID_PARAM;

		/* Set new range if the data arg has a value. */
		if (in->sensor_range.data != EC_MOTION_SENSE_NO_VALUE) {
			if (sensor->drv->set_range(sensor,
						in->sensor_range.data,
						in->sensor_range.roundup)
					!= EC_SUCCESS) {
				return EC_RES_INVALID_PARAM;
			}
		}

		out->sensor_range.ret = sensor->drv->get_range(sensor);
		args->response_size = sizeof(out->sensor_range);
		break;

	case MOTIONSENSE_CMD_SENSOR_OFFSET:
		/* Verify sensor number is valid. */
		sensor = host_sensor_id_to_motion_sensor(
				in->sensor_offset.sensor_num);
		if (sensor == NULL)
			return EC_RES_INVALID_PARAM;

		/* Set new range if the data arg has a value. */
		if (in->sensor_offset.flags & MOTION_SENSE_SET_OFFSET) {
			ret = sensor->drv->set_offset(sensor,
						in->sensor_offset.offset,
						in->sensor_offset.temp);
			if (ret != EC_SUCCESS)
				return ret;
		}

		ret = sensor->drv->get_offset(sensor, out->sensor_offset.offset,
				&out->sensor_offset.temp);
		if (ret != EC_SUCCESS)
			return ret;
		args->response_size = sizeof(out->sensor_offset);
		break;

	case MOTIONSENSE_CMD_PERFORM_CALIB:
		/* Verify sensor number is valid. */
		sensor = host_sensor_id_to_motion_sensor(
				in->sensor_offset.sensor_num);
		if (sensor == NULL)
			return EC_RES_INVALID_PARAM;
		if (!sensor->drv->perform_calib)
			return EC_RES_INVALID_COMMAND;

		ret = sensor->drv->perform_calib(sensor);
		if (ret != EC_SUCCESS)
			return ret;
		ret = sensor->drv->get_offset(sensor, out->sensor_offset.offset,
				&out->sensor_offset.temp);
		if (ret != EC_SUCCESS)
			return ret;
		args->response_size = sizeof(out->sensor_offset);
		break;

#ifdef CONFIG_ACCEL_FIFO
	case MOTIONSENSE_CMD_FIFO_FLUSH:
		sensor = host_sensor_id_to_motion_sensor(
				in->sensor_odr.sensor_num);
		if (sensor == NULL)
			return EC_RES_INVALID_PARAM;

		atomic_add(&sensor->flush_pending, 1);

		task_set_event(TASK_ID_MOTIONSENSE,
			       TASK_EVENT_MOTION_FLUSH_PENDING, 0);
		/* passthrough */
	case MOTIONSENSE_CMD_FIFO_INFO:
		motion_sense_get_fifo_info(&out->fifo_info);
		for (i = 0; i < motion_sensor_count; i++) {
			out->fifo_info.lost[i] = motion_sensors[i].lost;
			motion_sensors[i].lost = 0;
		}
		motion_sense_fifo_lost = 0;
		args->response_size = sizeof(out->fifo_info) +
			sizeof(uint16_t) * motion_sensor_count;
		break;

	case MOTIONSENSE_CMD_FIFO_READ:
		mutex_lock(&g_sensor_mutex);
		reported = MIN((args->response_max - sizeof(out->fifo_read)) /
			       motion_sense_fifo.unit_bytes,
			       MIN(queue_count(&motion_sense_fifo),
				   in->fifo_read.max_data_vector));
		reported = queue_remove_units(&motion_sense_fifo,
				out->fifo_read.data, reported);
		mutex_unlock(&g_sensor_mutex);
		out->fifo_read.number_data = reported;
		args->response_size = sizeof(out->fifo_read) + reported *
			motion_sense_fifo.unit_bytes;
		break;
#else
	case MOTIONSENSE_CMD_FIFO_INFO:
		/* Only support the INFO command, to tell there is no FIFO. */
		memset(&out->fifo_info, 0, sizeof(out->fifo_info));
		args->response_size = sizeof(out->fifo_info);
		break;
#endif
	default:
		/* Call other users of the motion task */
#ifdef CONFIG_LID_ANGLE
		if (ret == EC_RES_INVALID_PARAM)
			ret = host_cmd_motion_lid(args);
#endif
		return ret;
	}

	return EC_RES_SUCCESS;
}
Exemplo n.º 24
0
void fusb302_tcpc_alert(int port)
{
	/* interrupt has been received */
	int interrupt;
	int interrupta;
	int interruptb;
	int reg;
	int toggle_answer;
	int head;
	uint32_t payload[7];

	/* reading interrupt registers clears them */

	tcpc_read(port, TCPC_REG_INTERRUPT, &interrupt);
	tcpc_read(port, TCPC_REG_INTERRUPTA, &interrupta);
	tcpc_read(port, TCPC_REG_INTERRUPTB, &interruptb);

	/*
	 * Ignore BC_LVL changes when transmitting / receiving PD,
	 * since CC level will constantly change.
	 */
	if (state[port].rx_enable)
		interrupt &= ~TCPC_REG_INTERRUPT_BC_LVL;

	if (interrupt & TCPC_REG_INTERRUPT_BC_LVL) {
		/* CC Status change */
		task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_CC, 0);
	}

	if (interrupt & TCPC_REG_INTERRUPT_COLLISION) {
		/* packet sending collided */
		state[port].tx_hard_reset_req = 0;
		pd_transmit_complete(port, TCPC_TX_COMPLETE_FAILED);
	}

	if (interrupta & TCPC_REG_INTERRUPTA_TX_SUCCESS) {
		/*
		 * Sent packet was acknowledged with a GoodCRC,
		 * so remove GoodCRC message from FIFO.
		 */
		tcpm_get_message(port, payload, &head);

		pd_transmit_complete(port, TCPC_TX_COMPLETE_SUCCESS);
	}

	if (interrupta & TCPC_REG_INTERRUPTA_TOGDONE) {
		/* Don't allow other tasks to change CC PUs */
		mutex_lock(&state[port].set_cc_lock);
		/* If our toggle request is obsolete then we're done */
		if (state[port].dfp_toggling_on) {
			/* read what 302 settled on for an answer...*/
			tcpc_read(port, TCPC_REG_STATUS1A, &reg);
			reg = reg >> TCPC_REG_STATUS1A_TOGSS_POS;
			reg = reg & TCPC_REG_STATUS1A_TOGSS_MASK;

			toggle_answer = reg;

			/* Turn off toggle so we can take over the switches */
			tcpc_read(port, TCPC_REG_CONTROL2, &reg);
			reg &= ~TCPC_REG_CONTROL2_TOGGLE;
			tcpc_write(port, TCPC_REG_CONTROL2, reg);

			switch (toggle_answer) {
			case TCPC_REG_STATUS1A_TOGSS_SRC1:
				state[port].togdone_pullup_cc1 = 1;
				state[port].togdone_pullup_cc2 = 0;
				break;
			case TCPC_REG_STATUS1A_TOGSS_SRC2:
				state[port].togdone_pullup_cc1 = 0;
				state[port].togdone_pullup_cc2 = 1;
				break;
			case TCPC_REG_STATUS1A_TOGSS_SNK1:
			case TCPC_REG_STATUS1A_TOGSS_SNK2:
			case TCPC_REG_STATUS1A_TOGSS_AA:
				state[port].togdone_pullup_cc1 = 0;
				state[port].togdone_pullup_cc2 = 0;
				break;
			default:
				/* TODO: should never get here, but? */
				ASSERT(0);
				break;
			}

			/* enable the pull-up we know to be necessary */
			tcpc_read(port, TCPC_REG_SWITCHES0, &reg);

			reg &= ~(TCPC_REG_SWITCHES0_CC2_PU_EN |
				 TCPC_REG_SWITCHES0_CC1_PU_EN |
				 TCPC_REG_SWITCHES0_CC1_PD_EN |
				 TCPC_REG_SWITCHES0_CC2_PD_EN |
				 TCPC_REG_SWITCHES0_VCONN_CC1 |
				 TCPC_REG_SWITCHES0_VCONN_CC2);

			reg |= TCPC_REG_SWITCHES0_CC1_PU_EN |
			       TCPC_REG_SWITCHES0_CC2_PU_EN;

			if (state[port].vconn_enabled)
				reg |= state[port].togdone_pullup_cc1 ?
				       TCPC_REG_SWITCHES0_VCONN_CC2 :
				       TCPC_REG_SWITCHES0_VCONN_CC1;

			tcpc_write(port, TCPC_REG_SWITCHES0, reg);
			/* toggle done */
			state[port].dfp_toggling_on = 0;
		}
Exemplo n.º 25
0
void usb0_evt(enum gpio_signal signal)
{
	task_set_event(TASK_ID_USB_CHG_P0, USB_CHG_EVENT_BC12, 0);
}
Exemplo n.º 26
0
void si114x_interrupt(enum gpio_signal signal)
{
	task_set_event(TASK_ID_MOTIONSENSE,
		       CONFIG_ALS_SI114X_INT_EVENT, 0);
}
Exemplo n.º 27
0
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");
		}
	}
}