static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, int clk_id, unsigned int freq, int dir) { struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs; int err = 0; if (mcbsp->active) { if (freq == mcbsp->in_freq) return 0; else return -EBUSY; } mcbsp->in_freq = freq; regs->srgr2 &= ~CLKSM; regs->pcr0 &= ~SCLKME; switch (clk_id) { case OMAP_MCBSP_SYSCLK_CLK: regs->srgr2 |= CLKSM; break; case OMAP_MCBSP_SYSCLK_CLKS_FCLK: if (mcbsp_omap1()) { err = -EINVAL; break; } err = omap2_mcbsp_set_clks_src(mcbsp, MCBSP_CLKS_PRCM_SRC); break; case OMAP_MCBSP_SYSCLK_CLKS_EXT: if (mcbsp_omap1()) { err = 0; break; } err = omap2_mcbsp_set_clks_src(mcbsp, MCBSP_CLKS_PAD_SRC); break; case OMAP_MCBSP_SYSCLK_CLKX_EXT: regs->srgr2 |= CLKSM; case OMAP_MCBSP_SYSCLK_CLKR_EXT: regs->pcr0 |= SCLKME; break; default: err = -ENODEV; } return err; }
void omap_mcbsp_free(struct omap_mcbsp *mcbsp) { void *reg_cache; if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free) mcbsp->pdata->ops->free(mcbsp->id - 1); /* Disable wakeup behavior */ if (mcbsp->pdata->has_wakeup) MCBSP_WRITE(mcbsp, WAKEUPEN, 0); /* Disable interrupt requests */ if (mcbsp->irq) MCBSP_WRITE(mcbsp, IRQEN, 0); if (mcbsp->irq) { free_irq(mcbsp->irq, (void *)mcbsp); } else { free_irq(mcbsp->rx_irq, (void *)mcbsp); free_irq(mcbsp->tx_irq, (void *)mcbsp); } reg_cache = mcbsp->reg_cache; /* * Select CLKS source from internal source unconditionally before * marking the McBSP port as free. * If the external clock source via MCBSP_CLKS pin has been selected the * system will refuse to enter idle if the CLKS pin source is not reset * back to internal source. */ if (!mcbsp_omap1()) omap2_mcbsp_set_clks_src(mcbsp, MCBSP_CLKS_PRCM_SRC); spin_lock(&mcbsp->lock); if (mcbsp->free) dev_err(mcbsp->dev, "McBSP%d was not reserved\n", mcbsp->id); else mcbsp->free = true; mcbsp->reg_cache = NULL; spin_unlock(&mcbsp->lock); if (reg_cache) kfree(reg_cache); }
static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, int clk_id, unsigned int freq, int dir) { struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs; int err = 0; if (mcbsp->active) { if (freq == mcbsp->in_freq) return 0; else return -EBUSY; } mcbsp->in_freq = freq; regs->srgr2 &= ~CLKSM; regs->pcr0 &= ~SCLKME; switch (clk_id) { case OMAP_MCBSP_SYSCLK_CLK: regs->srgr2 |= CLKSM; break; case OMAP_MCBSP_SYSCLK_CLKS_FCLK: if (mcbsp_omap1()) { err = -EINVAL; break; } err = omap2_mcbsp_set_clks_src(mcbsp, MCBSP_CLKS_PRCM_SRC); break; case OMAP_MCBSP_SYSCLK_CLKS_EXT: if (mcbsp_omap1()) { err = 0; break; } err = omap2_mcbsp_set_clks_src(mcbsp, MCBSP_CLKS_PAD_SRC); break; case OMAP_MCBSP_SYSCLK_CLKX_EXT: regs->srgr2 |= CLKSM; regs->pcr0 |= SCLKME; /* * If McBSP is master but yet the CLKX/CLKR pin drives the SRG, * disable output on those pins. This enables to inject the * reference clock through CLKX/CLKR. For this to work * set_dai_sysclk() _needs_ to be called after set_dai_fmt(). */ regs->pcr0 &= ~CLKXM; break; case OMAP_MCBSP_SYSCLK_CLKR_EXT: regs->pcr0 |= SCLKME; /* Disable ouput on CLKR pin in master mode */ regs->pcr0 &= ~CLKRM; break; default: err = -ENODEV; } return err; }