*
* @dbg_stats: Debugging statistics
*
- * @soc: SoC specifc data
+ * @soc: SoC specific data
*/
struct fsl_ssi_private {
struct regmap *regs;
static bool fsl_ssi_is_ac97(struct fsl_ssi_private *ssi_private)
{
- return !!(ssi_private->dai_fmt & SND_SOC_DAIFMT_AC97);
+ return (ssi_private->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) ==
+ SND_SOC_DAIFMT_AC97;
}
static bool fsl_ssi_is_i2s_master(struct fsl_ssi_private *ssi_private)
scr &= ~CCSR_SSI_SCR_SYS_CLK_EN;
break;
default:
- return -EINVAL;
+ if (!fsl_ssi_is_ac97(ssi_private))
+ return -EINVAL;
}
stcr |= strcr;
srcr |= strcr;
- if (ssi_private->cpu_dai_drv.symmetric_rates) {
- /* Need to clear RXDIR when using SYNC mode */
+ if (ssi_private->cpu_dai_drv.symmetric_rates
+ || fsl_ssi_is_ac97(ssi_private)) {
+ /* Need to clear RXDIR when using SYNC or AC97 mode */
srcr &= ~CCSR_SSI_SRCR_RXDIR;
scr |= CCSR_SSI_SCR_SYN;
}
CCSR_SSI_SCR_TCH_EN);
}
- if (fmt & SND_SOC_DAIFMT_AC97)
+ if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_AC97)
fsl_ssi_setup_ac97(ssi_private);
return 0;
static struct snd_soc_dai_driver fsl_ssi_ac97_dai = {
.bus_control = true,
+ .probe = fsl_ssi_dai_probe,
.playback = {
.stream_name = "AC97 Playback",
.channels_min = 2,
struct regmap *regs = fsl_ac97_data->regs;
unsigned int lreg;
unsigned int lval;
+ int ret;
if (reg > 0x7f)
return;
+ ret = clk_prepare_enable(fsl_ac97_data->clk);
+ if (ret) {
+ pr_err("ac97 write clk_prepare_enable failed: %d\n",
+ ret);
+ return;
+ }
lreg = reg << 12;
regmap_write(regs, CCSR_SSI_SACADD, lreg);
regmap_update_bits(regs, CCSR_SSI_SACNT, CCSR_SSI_SACNT_RDWR_MASK,
CCSR_SSI_SACNT_WR);
udelay(100);
+
+ clk_disable_unprepare(fsl_ac97_data->clk);
}
static unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97,
unsigned short val = -1;
u32 reg_val;
unsigned int lreg;
+ int ret;
+
+ ret = clk_prepare_enable(fsl_ac97_data->clk);
+ if (ret) {
+ pr_err("ac97 read clk_prepare_enable failed: %d\n",
+ ret);
+ return -1;
+ }
lreg = (reg & 0x7f) << 12;
regmap_write(regs, CCSR_SSI_SACADD, lreg);
regmap_read(regs, CCSR_SSI_SACDAT, ®_val);
val = (reg_val >> 4) & 0xffff;
+ clk_disable_unprepare(fsl_ac97_data->clk);
+
return val;
}
}
}
- /* For those SLAVE implementations, we ingore non-baudclk cases
+ /* For those SLAVE implementations, we ignore non-baudclk cases
* and, instead, abandon MASTER mode that needs baud clock.
*/
ssi_private->baudclk = devm_clk_get(&pdev->dev, "baud");
if (ret)
goto error_pcm;
} else {
- ret = imx_pcm_dma_init(pdev);
+ ret = imx_pcm_dma_init(pdev, IMX_SSI_DMABUF_SIZE);
if (ret)
goto error_pcm;
}
fsl_ac97_data = ssi_private;
- snd_soc_set_ac97_ops_of_reset(&fsl_ssi_ac97_ops, pdev);
+ ret = snd_soc_set_ac97_ops_of_reset(&fsl_ssi_ac97_ops, pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "could not set AC'97 ops\n");
+ return ret;
+ }
} else {
/* Initialize this copy of the CPU DAI driver structure */
memcpy(&ssi_private->cpu_dai_drv, &fsl_ssi_dai_template,
/* Are the RX and the TX clocks locked? */
if (!of_find_property(np, "fsl,ssi-asynchronous", NULL)) {
- ssi_private->cpu_dai_drv.symmetric_rates = 1;
+ if (!fsl_ssi_is_ac97(ssi_private))
+ ssi_private->cpu_dai_drv.symmetric_rates = 1;
+
ssi_private->cpu_dai_drv.symmetric_channels = 1;
ssi_private->cpu_dai_drv.symmetric_samplebits = 1;
}
_fsl_ssi_set_dai_fmt(&pdev->dev, ssi_private,
ssi_private->dai_fmt);
+ if (fsl_ssi_is_ac97(ssi_private)) {
+ u32 ssi_idx;
+
+ ret = of_property_read_u32(np, "cell-index", &ssi_idx);
+ if (ret) {
+ dev_err(&pdev->dev, "cannot get SSI index property\n");
+ goto error_sound_card;
+ }
+
+ ssi_private->pdev =
+ platform_device_register_data(NULL,
+ "ac97-codec", ssi_idx, NULL, 0);
+ if (IS_ERR(ssi_private->pdev)) {
+ ret = PTR_ERR(ssi_private->pdev);
+ dev_err(&pdev->dev,
+ "failed to register AC97 codec platform: %d\n",
+ ret);
+ goto error_sound_card;
+ }
+ }
+
return 0;
error_sound_card:
if (ssi_private->soc->imx)
fsl_ssi_imx_clean(pdev, ssi_private);
+ if (fsl_ssi_is_ac97(ssi_private))
+ snd_soc_set_ac97_ops(NULL);
+
return 0;
}