static u32 hsi_process_int_event(struct hsi_port *pport) { unsigned int port = pport->port_number; unsigned int irq = pport->n_irq; u32 status_reg; bool cawake_double_int = false; /* Clear CAWAKE backup interrupt */ hsi_driver_ack_interrupt(pport, HSI_CAWAKEDETECTED, true); /* Process events for channels 0..7 */ status_reg = hsi_driver_int_proc(pport, HSI_SYS_MPU_STATUS_REG(port, irq), HSI_SYS_MPU_ENABLE_REG(port, irq), 0, min(pport->max_ch, (u8) HSI_SSI_CHANNELS_MAX) - 1, cawake_double_int); /* If another CAWAKE interrupt occured while previous is still being * processed, mark it for extra processing */ if (hsi_driver_is_interrupt_pending(pport, HSI_CAWAKEDETECTED, true) && (status_reg & HSI_CAWAKEDETECTED)) { dev_warn(pport->hsi_controller->dev, "New CAWAKE interrupt " "detected during interrupt processing\n"); /* Force processing of backup CAWAKE interrupt */ cawake_double_int = true; } /* Process events for channels 8..15 or backup interrupt if needed */ if ((pport->max_ch > HSI_SSI_CHANNELS_MAX) || cawake_double_int) status_reg |= hsi_driver_int_proc(pport, HSI_SYS_MPU_U_STATUS_REG(port, irq), HSI_SYS_MPU_U_ENABLE_REG(port, irq), HSI_SSI_CHANNELS_MAX, pport->max_ch - 1, cawake_double_int); return status_reg; }
/** * hsi_do_cawake_process - CAWAKE line management * @pport - HSI port to process * * This function handles the CAWAKE L/H transitions and call the event callback * accordingly. * * Returns 0 if CAWAKE event process, -EAGAIN if CAWAKE event processing is * delayed due to a pending DMA interrupt. * If -EAGAIN is returned, pport->hsi_tasklet has to be re-scheduled once * DMA tasklet has be executed. This should be done automatically by driver. * */ int hsi_do_cawake_process(struct hsi_port *pport) { struct hsi_dev *hsi_ctrl = pport->hsi_controller; bool cawake_status = hsi_get_cawake(pport); if (pport->wake_rx_3_wires_mode) { dev_warn(hsi_ctrl->dev, "CAWAKE edge in RX 3 wires, exiting\n"); return 0; } /* Deal with init condition */ if (unlikely(pport->cawake_status < 0)) pport->cawake_status = !cawake_status; dev_dbg(hsi_ctrl->dev, "%s: Interrupts are not enabled but CAWAKE came." "hsi: port[%d] irq[%d] irq_en=0x%08x dma_irq_en=0x%08x\n", __func__, pport->port_number, pport->n_irq, hsi_inl(pport->hsi_controller->base, HSI_SYS_MPU_ENABLE_REG(pport->port_number, pport->n_irq)), hsi_inl(pport->hsi_controller->base, HSI_SYS_GDD_MPU_IRQ_ENABLE_REG)); /* Check CAWAKE line status */ if (cawake_status) { dev_dbg(hsi_ctrl->dev, "CAWAKE rising edge detected\n"); /* Check for possible mismatch (race condition) */ if (unlikely(pport->cawake_status)) { dev_warn(hsi_ctrl->dev, "Missed previous CAWAKE falling edge...\n"); spin_unlock(&hsi_ctrl->lock); hsi_port_event_handler(pport, HSI_EVENT_CAWAKE_DOWN, NULL); spin_lock(&hsi_ctrl->lock); /* In case another CAWAKE interrupt occured and caused * a race condition, clear CAWAKE backup interrupt to * avoid handling twice the race condition */ hsi_driver_ack_interrupt(pport, HSI_CAWAKEDETECTED, true); } pport->cawake_status = 1; spin_unlock(&hsi_ctrl->lock); hsi_port_event_handler(pport, HSI_EVENT_CAWAKE_UP, NULL); spin_lock(&hsi_ctrl->lock); /* * HSI - OMAP4430-2.2BUG00055: i702 * HSI: DSP Swakeup generated is the same than MPU Swakeup. * System cannot enter in off mode due to the DSP. */ if (is_hsi_errata(hsi_ctrl, HSI_ERRATUM_i702_PM_HSI_SWAKEUP)) omap_pm_clear_dsp_wake_up(); } else { dev_dbg(hsi_ctrl->dev, "CAWAKE falling edge detected\n"); /* Check for pending DMA interrupt */ if (hsi_is_dma_read_int_pending(hsi_ctrl)) { dev_dbg(hsi_ctrl->dev, "Pending DMA Read interrupt " "before CAWAKE->L, exiting " "Interrupt tasklet.\n"); return -EAGAIN; } if (unlikely(!pport->cawake_status)) { dev_warn(hsi_ctrl->dev, "Missed previous CAWAKE rising edge...\n"); spin_unlock(&hsi_ctrl->lock); hsi_port_event_handler(pport, HSI_EVENT_CAWAKE_UP, NULL); spin_lock(&hsi_ctrl->lock); /* In case another CAWAKE interrupt occured and caused * a race condition, clear CAWAKE backup interrupt to * avoid handling twice the race condition */ hsi_driver_ack_interrupt(pport, HSI_CAWAKEDETECTED, true); } pport->cawake_status = 0; spin_unlock(&hsi_ctrl->lock); hsi_port_event_handler(pport, HSI_EVENT_CAWAKE_DOWN, NULL); spin_lock(&hsi_ctrl->lock); } /* If another CAWAKE event occured while previous is still processed */ /* do not clear the status bit */ cawake_status = hsi_get_cawake(pport); if (cawake_status != pport->cawake_status) { dev_warn(hsi_ctrl->dev, "CAWAKE line changed to %d while CAWAKE" "event is still being processed\n", cawake_status); return -EAGAIN; } return 0; }
/** * hsi_do_cawake_process - CAWAKE line management * @pport - HSI port to process * * This function handles the CAWAKE L/H transitions and call the event callback * accordingly. * * Returns 0 if CAWAKE event process, -EAGAIN if CAWAKE event processing is * delayed due to a pending DMA interrupt. * If -EAGAIN is returned, pport->hsi_tasklet has to be re-scheduled once * DMA tasklet has be executed. This should be done automatically by driver. * */ int hsi_do_cawake_process(struct hsi_port *pport) { struct hsi_dev *hsi_ctrl = pport->hsi_controller; bool cawake_status = hsi_get_cawake(pport); if (pport->wake_rx_3_wires_mode) { dev_warn(hsi_ctrl->dev, "CAWAKE edge in RX 3 wires, exiting\n"); return 0; } /* Deal with init condition */ if (unlikely(pport->cawake_status < 0)) pport->cawake_status = !cawake_status; /* Check CAWAKE line status */ if (cawake_status) { dev_dbg(hsi_ctrl->dev, "CAWAKE rising edge detected\n"); /* Check for possible mismatch (race condition) */ if (unlikely(pport->cawake_status)) { dev_warn(hsi_ctrl->dev, "Missed previous CAWAKE falling edge...\n"); spin_unlock(&hsi_ctrl->lock); hsi_port_event_handler(pport, HSI_EVENT_CAWAKE_DOWN, NULL); spin_lock(&hsi_ctrl->lock); /* In case another CAWAKE interrupt occured and caused * a race condition, clear CAWAKE backup interrupt to * avoid handling twice the race condition */ hsi_driver_ack_interrupt(pport, HSI_CAWAKEDETECTED, true); } pport->cawake_status = 1; /* Allow data reception */ hsi_hsr_resume(hsi_ctrl); spin_unlock(&hsi_ctrl->lock); hsi_port_event_handler(pport, HSI_EVENT_CAWAKE_UP, NULL); spin_lock(&hsi_ctrl->lock); /* * HSI - OMAP4430-2.2BUG00055: i702 * HSI: DSP Swakeup generated is the same than MPU Swakeup. * System cannot enter in off mode due to the DSP. */ if (is_hsi_errata(hsi_ctrl, HSI_ERRATUM_i702_PM_HSI_SWAKEUP)) omap_pm_clear_dsp_wake_up(); } else { dev_dbg(hsi_ctrl->dev, "CAWAKE falling edge detected\n"); /* Check for pending DMA interrupt */ if (hsi_is_dma_read_int_pending(hsi_ctrl)) { dev_dbg(hsi_ctrl->dev, "Pending DMA Read interrupt " "before CAWAKE->L, exiting " "Interrupt tasklet.\n"); return -EAGAIN; } if (unlikely(!pport->cawake_status)) { dev_warn(hsi_ctrl->dev, "Missed previous CAWAKE rising edge...\n"); spin_unlock(&hsi_ctrl->lock); hsi_port_event_handler(pport, HSI_EVENT_CAWAKE_UP, NULL); spin_lock(&hsi_ctrl->lock); /* In case another CAWAKE interrupt occured and caused * a race condition, clear CAWAKE backup interrupt to * avoid handling twice the race condition */ hsi_driver_ack_interrupt(pport, HSI_CAWAKEDETECTED, true); } pport->cawake_status = 0; /* Forbid data reception */ hsi_hsr_suspend(hsi_ctrl); spin_unlock(&hsi_ctrl->lock); hsi_port_event_handler(pport, HSI_EVENT_CAWAKE_DOWN, NULL); spin_lock(&hsi_ctrl->lock); } return 0; }