in controllers/omap_ssi_port.c [454:517]
static int ssi_setup(struct hsi_client *cl)
{
struct hsi_port *port = to_hsi_port(cl->device.parent);
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);
void __iomem *sst = omap_port->sst_base;
void __iomem *ssr = omap_port->ssr_base;
u32 div;
u32 val;
int err = 0;
pm_runtime_get_sync(omap_port->pdev);
spin_lock_bh(&omap_port->lock);
if (cl->tx_cfg.speed)
omap_ssi->max_speed = cl->tx_cfg.speed;
div = ssi_calculate_div(ssi);
if (div > SSI_MAX_DIVISOR) {
dev_err(&cl->device, "Invalid TX speed %d Mb/s (div %d)\n",
cl->tx_cfg.speed, div);
err = -EINVAL;
goto out;
}
/* Set TX/RX module to sleep to stop TX/RX during cfg update */
writel_relaxed(SSI_MODE_SLEEP, sst + SSI_SST_MODE_REG);
writel_relaxed(SSI_MODE_SLEEP, ssr + SSI_SSR_MODE_REG);
/* Flush posted write */
val = readl(ssr + SSI_SSR_MODE_REG);
/* TX */
writel_relaxed(31, sst + SSI_SST_FRAMESIZE_REG);
writel_relaxed(div, sst + SSI_SST_DIVISOR_REG);
writel_relaxed(cl->tx_cfg.num_hw_channels, sst + SSI_SST_CHANNELS_REG);
writel_relaxed(cl->tx_cfg.arb_mode, sst + SSI_SST_ARBMODE_REG);
writel_relaxed(cl->tx_cfg.mode, sst + SSI_SST_MODE_REG);
/* RX */
writel_relaxed(31, ssr + SSI_SSR_FRAMESIZE_REG);
writel_relaxed(cl->rx_cfg.num_hw_channels, ssr + SSI_SSR_CHANNELS_REG);
writel_relaxed(0, ssr + SSI_SSR_TIMEOUT_REG);
/* Cleanup the break queue if we leave FRAME mode */
if ((omap_port->ssr.mode == SSI_MODE_FRAME) &&
(cl->rx_cfg.mode != SSI_MODE_FRAME))
ssi_flush_queue(&omap_port->brkqueue, cl);
writel_relaxed(cl->rx_cfg.mode, ssr + SSI_SSR_MODE_REG);
omap_port->channels = max(cl->rx_cfg.num_hw_channels,
cl->tx_cfg.num_hw_channels);
/* Shadow registering for OFF mode */
/* SST */
omap_port->sst.divisor = div;
omap_port->sst.frame_size = 31;
omap_port->sst.channels = cl->tx_cfg.num_hw_channels;
omap_port->sst.arb_mode = cl->tx_cfg.arb_mode;
omap_port->sst.mode = cl->tx_cfg.mode;
/* SSR */
omap_port->ssr.frame_size = 31;
omap_port->ssr.timeout = 0;
omap_port->ssr.channels = cl->rx_cfg.num_hw_channels;
omap_port->ssr.mode = cl->rx_cfg.mode;
out:
spin_unlock_bh(&omap_port->lock);
pm_runtime_mark_last_busy(omap_port->pdev);
pm_runtime_put_autosuspend(omap_port->pdev);
return err;
}