#define MCASP_MAX_AFIFO_DEPTH 64
+static u32 context_regs[] = {
+ DAVINCI_MCASP_TXFMCTL_REG,
+ DAVINCI_MCASP_RXFMCTL_REG,
+ DAVINCI_MCASP_TXFMT_REG,
+ DAVINCI_MCASP_RXFMT_REG,
+ DAVINCI_MCASP_ACLKXCTL_REG,
+ DAVINCI_MCASP_ACLKRCTL_REG,
+ DAVINCI_MCASP_AHCLKXCTL_REG,
+ DAVINCI_MCASP_AHCLKRCTL_REG,
+ DAVINCI_MCASP_PDIR_REG,
+ DAVINCI_MCASP_RXMASK_REG,
+ DAVINCI_MCASP_TXMASK_REG,
+ DAVINCI_MCASP_RXTDM_REG,
+ DAVINCI_MCASP_TXTDM_REG,
+};
+
struct davinci_mcasp_context {
- u32 txfmtctl;
- u32 rxfmtctl;
- u32 txfmt;
- u32 rxfmt;
- u32 aclkxctl;
- u32 aclkrctl;
- u32 pdir;
+ u32 config_regs[ARRAY_SIZE(context_regs)];
+ u32 afifo_regs[2]; /* for read/write fifo control registers */
+ u32 *xrsr_regs; /* for serializer configuration */
};
struct davinci_mcasp {
static void mcasp_start_rx(struct davinci_mcasp *mcasp)
{
+ /* Start clocks */
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXHCLKRST);
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXCLKRST);
-
/*
* When ASYNC == 0 the transmit and receive sections operate
* synchronously from the transmit clock and frame sync. We need to make
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST);
}
+ /* Activate serializer(s) */
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSERCLR);
- mcasp_set_reg(mcasp, DAVINCI_MCASP_RXBUF_REG, 0);
-
- mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSMRST);
- mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXFSRST);
- mcasp_set_reg(mcasp, DAVINCI_MCASP_RXBUF_REG, 0);
-
+ /* Release RX state machine */
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSMRST);
+ /* Release Frame Sync generator */
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXFSRST);
-
if (mcasp_is_synchronous(mcasp))
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST);
}
static void mcasp_start_tx(struct davinci_mcasp *mcasp)
{
- u8 offset = 0, i;
u32 cnt;
+ /* Start clocks */
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST);
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST);
+ /* Activate serializer(s) */
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSERCLR);
- mcasp_set_reg(mcasp, DAVINCI_MCASP_TXBUF_REG, 0);
- mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSMRST);
- mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST);
- mcasp_set_reg(mcasp, DAVINCI_MCASP_TXBUF_REG, 0);
- for (i = 0; i < mcasp->num_serializer; i++) {
- if (mcasp->serial_dir[i] == TX_MODE) {
- offset = i;
- break;
- }
- }
-
- /* wait for TX ready */
+ /* wait for XDATA to be cleared */
cnt = 0;
- while (!(mcasp_get_reg(mcasp, DAVINCI_MCASP_XRSRCTL_REG(offset)) &
- TXSTATE) && (cnt < 100000))
+ while (!(mcasp_get_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG) &
+ ~XRDATA) && (cnt < 100000))
cnt++;
- mcasp_set_reg(mcasp, DAVINCI_MCASP_TXBUF_REG, 0);
+ /* Release TX state machine */
+ mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSMRST);
+ /* Release Frame Sync generator */
+ mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST);
}
static void davinci_mcasp_start(struct davinci_mcasp *mcasp, int stream)
mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, 0);
mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF);
+
+ if (mcasp->rxnumevt) { /* disable FIFO */
+ u32 reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
+
+ mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
+ }
}
static void mcasp_stop_tx(struct davinci_mcasp *mcasp)
mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, val);
mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
+
+ if (mcasp->txnumevt) { /* disable FIFO */
+ u32 reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
+
+ mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
+ }
}
static void davinci_mcasp_stop(struct davinci_mcasp *mcasp, int stream)
{
- u32 reg;
-
mcasp->streams--;
- if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
- if (mcasp->txnumevt) { /* disable FIFO */
- reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
- mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
- }
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
mcasp_stop_tx(mcasp);
- } else {
- if (mcasp->rxnumevt) { /* disable FIFO */
- reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
- mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
- }
+ else
mcasp_stop_rx(mcasp);
- }
}
static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
{
struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
struct davinci_mcasp_context *context = &mcasp->context;
+ u32 reg;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(context_regs); i++)
+ context->config_regs[i] = mcasp_get_reg(mcasp, context_regs[i]);
+
+ if (mcasp->txnumevt) {
+ reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
+ context->afifo_regs[0] = mcasp_get_reg(mcasp, reg);
+ }
+ if (mcasp->rxnumevt) {
+ reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
+ context->afifo_regs[1] = mcasp_get_reg(mcasp, reg);
+ }
- context->txfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG);
- context->rxfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG);
- context->txfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMT_REG);
- context->rxfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMT_REG);
- context->aclkxctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG);
- context->aclkrctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG);
- context->pdir = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDIR_REG);
+ for (i = 0; i < mcasp->num_serializer; i++)
+ context->xrsr_regs[i] = mcasp_get_reg(mcasp,
+ DAVINCI_MCASP_XRSRCTL_REG(i));
return 0;
}
{
struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
struct davinci_mcasp_context *context = &mcasp->context;
+ u32 reg;
+ int i;
- mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG, context->txfmtctl);
- mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG, context->rxfmtctl);
- mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMT_REG, context->txfmt);
- mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMT_REG, context->rxfmt);
- mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, context->aclkxctl);
- mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, context->aclkrctl);
- mcasp_set_reg(mcasp, DAVINCI_MCASP_PDIR_REG, context->pdir);
+ for (i = 0; i < ARRAY_SIZE(context_regs); i++)
+ mcasp_set_reg(mcasp, context_regs[i], context->config_regs[i]);
+
+ if (mcasp->txnumevt) {
+ reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
+ mcasp_set_reg(mcasp, reg, context->afifo_regs[0]);
+ }
+ if (mcasp->rxnumevt) {
+ reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
+ mcasp_set_reg(mcasp, reg, context->afifo_regs[1]);
+ }
+
+ for (i = 0; i < mcasp->num_serializer; i++)
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
+ context->xrsr_regs[i]);
return 0;
}
mcasp->op_mode = pdata->op_mode;
mcasp->tdm_slots = pdata->tdm_slots;
mcasp->num_serializer = pdata->num_serializer;
+#ifdef CONFIG_PM_SLEEP
+ mcasp->context.xrsr_regs = devm_kzalloc(&pdev->dev,
+ sizeof(u32) * mcasp->num_serializer,
+ GFP_KERNEL);
+#endif
mcasp->serial_dir = pdata->serial_dir;
mcasp->version = pdata->version;
mcasp->txnumevt = pdata->txnumevt;