/** * 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); } }
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); } } }
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, ®); 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, ®); /* 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); } }
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); } }
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 }
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)); } } }
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); }
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); }
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); }
/** * 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); }
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; } }
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); } }
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); }
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); }
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); } }
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); }
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 }
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; }
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; }
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; }
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); } }
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); }
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; }
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 >> 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 &= ~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 &= ~(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; }
void usb0_evt(enum gpio_signal signal) { task_set_event(TASK_ID_USB_CHG_P0, USB_CHG_EVENT_BC12, 0); }
void si114x_interrupt(enum gpio_signal signal) { task_set_event(TASK_ID_MOTIONSENSE, CONFIG_ALS_SI114X_INT_EVENT, 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"); } } }