Skip to content

Commit

Permalink
ASoC: kirkwood-i2s: better handling of play/record control registers
Browse files Browse the repository at this point in the history
Signed-off-by: Russell King <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
  • Loading branch information
Russell King authored and broonie committed Nov 21, 2012
1 parent dbc517b commit d8d11ba
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 40 deletions.
112 changes: 72 additions & 40 deletions sound/soc/kirkwood/kirkwood-i2s.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,15 +113,14 @@ static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
unsigned int i2s_reg, reg;
unsigned long i2s_value, value;
uint32_t ctl_play, ctl_rec;
unsigned int i2s_reg;
unsigned long i2s_value;

if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
i2s_reg = KIRKWOOD_I2S_PLAYCTL;
reg = KIRKWOOD_PLAYCTL;
} else {
i2s_reg = KIRKWOOD_I2S_RECCTL;
reg = KIRKWOOD_RECCTL;
}

/* set dco conf */
Expand All @@ -130,48 +129,64 @@ static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream,
i2s_value = readl(priv->io+i2s_reg);
i2s_value &= ~KIRKWOOD_I2S_CTL_SIZE_MASK;

value = readl(priv->io+reg);
value &= ~KIRKWOOD_PLAYCTL_SIZE_MASK;

/*
* Size settings in play/rec i2s control regs and play/rec control
* regs must be the same.
*/
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
i2s_value |= KIRKWOOD_I2S_CTL_SIZE_16;
value |= KIRKWOOD_PLAYCTL_SIZE_16_C;
ctl_play = KIRKWOOD_PLAYCTL_SIZE_16_C |
KIRKWOOD_PLAYCTL_I2S_EN;
ctl_rec = KIRKWOOD_RECCTL_SIZE_16_C |
KIRKWOOD_RECCTL_I2S_EN;
break;
/*
* doesn't work... S20_3LE != kirkwood 20bit format ?
*
case SNDRV_PCM_FORMAT_S20_3LE:
i2s_value |= KIRKWOOD_I2S_CTL_SIZE_20;
value |= KIRKWOOD_PLAYCTL_SIZE_20;
ctl_play = KIRKWOOD_PLAYCTL_SIZE_20 |
KIRKWOOD_PLAYCTL_I2S_EN;
ctl_rec = KIRKWOOD_RECCTL_SIZE_20 |
KIRKWOOD_RECCTL_I2S_EN;
break;
*/
case SNDRV_PCM_FORMAT_S24_LE:
i2s_value |= KIRKWOOD_I2S_CTL_SIZE_24;
value |= KIRKWOOD_PLAYCTL_SIZE_24;
ctl_play = KIRKWOOD_PLAYCTL_SIZE_24 |
KIRKWOOD_PLAYCTL_I2S_EN;
ctl_rec = KIRKWOOD_RECCTL_SIZE_24 |
KIRKWOOD_RECCTL_I2S_EN;
break;
case SNDRV_PCM_FORMAT_S32_LE:
i2s_value |= KIRKWOOD_I2S_CTL_SIZE_32;
value |= KIRKWOOD_PLAYCTL_SIZE_32;
ctl_play = KIRKWOOD_PLAYCTL_SIZE_32 |
KIRKWOOD_PLAYCTL_I2S_EN;
ctl_rec = KIRKWOOD_RECCTL_SIZE_32 |
KIRKWOOD_RECCTL_I2S_EN;
break;
default:
return -EINVAL;
}

if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
value &= ~KIRKWOOD_PLAYCTL_MONO_MASK;
if (params_channels(params) == 1)
value |= KIRKWOOD_PLAYCTL_MONO_BOTH;
ctl_play |= KIRKWOOD_PLAYCTL_MONO_BOTH;
else
value |= KIRKWOOD_PLAYCTL_MONO_OFF;
ctl_play |= KIRKWOOD_PLAYCTL_MONO_OFF;

priv->ctl_play &= ~(KIRKWOOD_PLAYCTL_MONO_MASK |
KIRKWOOD_PLAYCTL_I2S_EN |
KIRKWOOD_PLAYCTL_SPDIF_EN |
KIRKWOOD_PLAYCTL_SIZE_MASK);
priv->ctl_play |= ctl_play;
} else {
priv->ctl_rec &= ~KIRKWOOD_RECCTL_SIZE_MASK;
priv->ctl_rec |= ctl_rec;
}

writel(i2s_value, priv->io+i2s_reg);
writel(value, priv->io+reg);

return 0;
}
Expand Down Expand Up @@ -205,20 +220,18 @@ static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream,

switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
/* configure */
ctl = priv->ctl_play;
value = ctl & ~(KIRKWOOD_PLAYCTL_I2S_EN |
KIRKWOOD_PLAYCTL_SPDIF_EN);
writel(value, priv->io + KIRKWOOD_PLAYCTL);

/* enable interrupts */
value = readl(priv->io + KIRKWOOD_INT_MASK);
value |= KIRKWOOD_INT_CAUSE_PLAY_BYTES;
writel(value, priv->io + KIRKWOOD_INT_MASK);

/* configure audio & enable i2s playback */
ctl &= ~KIRKWOOD_PLAYCTL_BURST_MASK;
ctl &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE
| KIRKWOOD_PLAYCTL_SPDIF_EN);

if (priv->burst == 32)
ctl |= KIRKWOOD_PLAYCTL_BURST_32;
else
ctl |= KIRKWOOD_PLAYCTL_BURST_128;
ctl |= KIRKWOOD_PLAYCTL_I2S_EN;
/* enable playback */
writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
break;

Expand Down Expand Up @@ -259,30 +272,24 @@ static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
unsigned long value;
uint32_t ctl, value;

value = readl(priv->io + KIRKWOOD_RECCTL);

switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
/* configure */
ctl = priv->ctl_rec;
value = ctl & ~KIRKWOOD_RECCTL_I2S_EN;
writel(value, priv->io + KIRKWOOD_RECCTL);

/* enable interrupts */
value = readl(priv->io + KIRKWOOD_INT_MASK);
value |= KIRKWOOD_INT_CAUSE_REC_BYTES;
writel(value, priv->io + KIRKWOOD_INT_MASK);

/* configure audio & enable i2s record */
value = readl(priv->io + KIRKWOOD_RECCTL);
value &= ~KIRKWOOD_RECCTL_BURST_MASK;
value &= ~KIRKWOOD_RECCTL_MONO;
value &= ~(KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE
| KIRKWOOD_RECCTL_SPDIF_EN);

if (priv->burst == 32)
value |= KIRKWOOD_RECCTL_BURST_32;
else
value |= KIRKWOOD_RECCTL_BURST_128;
value |= KIRKWOOD_RECCTL_I2S_EN;

writel(value, priv->io + KIRKWOOD_RECCTL);
/* enable record */
writel(ctl, priv->io + KIRKWOOD_RECCTL);
break;

case SNDRV_PCM_TRIGGER_STOP:
Expand Down Expand Up @@ -448,6 +455,31 @@ static __devinit int kirkwood_i2s_dev_probe(struct platform_device *pdev)
if (err < 0)
return err;

priv->extclk = clk_get(&pdev->dev, "extclk");
if (!IS_ERR(priv->extclk)) {
if (priv->extclk == priv->clk) {
clk_put(priv->extclk);
priv->extclk = ERR_PTR(-EINVAL);
} else {
dev_info(&pdev->dev, "found external clock\n");
clk_prepare_enable(priv->extclk);
soc_dai = &kirkwood_i2s_dai_extclk;
}
}

/* Some sensible defaults - this reflects the powerup values */
priv->ctl_play = KIRKWOOD_PLAYCTL_SIZE_24;
priv->ctl_rec = KIRKWOOD_RECCTL_SIZE_24;

/* Select the burst size */
if (data->burst == 32) {
priv->ctl_play |= KIRKWOOD_PLAYCTL_BURST_32;
priv->ctl_rec |= KIRKWOOD_RECCTL_BURST_32;
} else {
priv->ctl_play |= KIRKWOOD_PLAYCTL_BURST_128;
priv->ctl_rec |= KIRKWOOD_RECCTL_BURST_128;
}

err = snd_soc_register_dai(&pdev->dev, &kirkwood_i2s_dai);
if (!err)
return 0;
Expand Down
2 changes: 2 additions & 0 deletions sound/soc/kirkwood/kirkwood.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@

struct kirkwood_dma_data {
void __iomem *io;
uint32_t ctl_play;
uint32_t ctl_rec;
int irq;
int burst;
struct clk *clk;
Expand Down

0 comments on commit d8d11ba

Please sign in to comment.