in controllers/omap_ssi_port.c [519:583]
static int ssi_flush(struct hsi_client *cl)
{
struct hsi_port *port = hsi_get_port(cl);
struct omap_ssi_port *omap_port = hsi_port_drvdata(port);
struct hsi_controller *ssi = to_hsi_controller(port->device.parent);
struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
struct hsi_msg *msg;
void __iomem *sst = omap_port->sst_base;
void __iomem *ssr = omap_port->ssr_base;
unsigned int i;
u32 err;
pm_runtime_get_sync(omap_port->pdev);
spin_lock_bh(&omap_port->lock);
/* stop all ssi communication */
pinctrl_pm_select_idle_state(omap_port->pdev);
udelay(1); /* wait for racing frames */
/* Stop all DMA transfers */
for (i = 0; i < SSI_MAX_GDD_LCH; i++) {
msg = omap_ssi->gdd_trn[i].msg;
if (!msg || (port != hsi_get_port(msg->cl)))
continue;
writew_relaxed(0, omap_ssi->gdd + SSI_GDD_CCR_REG(i));
if (msg->ttype == HSI_MSG_READ)
pm_runtime_put_autosuspend(omap_port->pdev);
omap_ssi->gdd_trn[i].msg = NULL;
}
/* Flush all SST buffers */
writel_relaxed(0, sst + SSI_SST_BUFSTATE_REG);
writel_relaxed(0, sst + SSI_SST_TXSTATE_REG);
/* Flush all SSR buffers */
writel_relaxed(0, ssr + SSI_SSR_RXSTATE_REG);
writel_relaxed(0, ssr + SSI_SSR_BUFSTATE_REG);
/* Flush all errors */
err = readl(ssr + SSI_SSR_ERROR_REG);
writel_relaxed(err, ssr + SSI_SSR_ERRORACK_REG);
/* Flush break */
writel_relaxed(0, ssr + SSI_SSR_BREAK_REG);
/* Clear interrupts */
writel_relaxed(0, omap_ssi->sys + SSI_MPU_ENABLE_REG(port->num, 0));
writel_relaxed(0xffffff00,
omap_ssi->sys + SSI_MPU_STATUS_REG(port->num, 0));
writel_relaxed(0, omap_ssi->sys + SSI_GDD_MPU_IRQ_ENABLE_REG);
writel(0xff, omap_ssi->sys + SSI_GDD_MPU_IRQ_STATUS_REG);
/* Dequeue all pending requests */
for (i = 0; i < omap_port->channels; i++) {
/* Release write clocks */
if (!list_empty(&omap_port->txqueue[i]))
pm_runtime_put_autosuspend(omap_port->pdev);
ssi_flush_queue(&omap_port->txqueue[i], NULL);
ssi_flush_queue(&omap_port->rxqueue[i], NULL);
}
ssi_flush_queue(&omap_port->brkqueue, NULL);
/* Resume SSI communication */
pinctrl_pm_select_default_state(omap_port->pdev);
spin_unlock_bh(&omap_port->lock);
pm_runtime_mark_last_busy(omap_port->pdev);
pm_runtime_put_autosuspend(omap_port->pdev);
return 0;
}