diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2012-11-20 07:19:53 -0500 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2012-11-20 20:40:23 -0500 |
commit | d8d11ba566761625e2b5ab716dca920725f3dc0b (patch) | |
tree | 60c4fd1ee9970af93d077cba3834736c47178a23 /sound/soc/kirkwood/kirkwood-i2s.c | |
parent | dbc517bf32985f2438ff706204a6dd1476b3dc98 (diff) |
ASoC: kirkwood-i2s: better handling of play/record control registers
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/kirkwood/kirkwood-i2s.c')
-rw-r--r-- | sound/soc/kirkwood/kirkwood-i2s.c | 112 |
1 files changed, 72 insertions, 40 deletions
diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c index f059f401bdad..823ef1e71d19 100644 --- a/sound/soc/kirkwood/kirkwood-i2s.c +++ b/sound/soc/kirkwood/kirkwood-i2s.c | |||
@@ -113,15 +113,14 @@ static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream, | |||
113 | struct snd_soc_dai *dai) | 113 | struct snd_soc_dai *dai) |
114 | { | 114 | { |
115 | struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai); | 115 | struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai); |
116 | unsigned int i2s_reg, reg; | 116 | uint32_t ctl_play, ctl_rec; |
117 | unsigned long i2s_value, value; | 117 | unsigned int i2s_reg; |
118 | unsigned long i2s_value; | ||
118 | 119 | ||
119 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 120 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
120 | i2s_reg = KIRKWOOD_I2S_PLAYCTL; | 121 | i2s_reg = KIRKWOOD_I2S_PLAYCTL; |
121 | reg = KIRKWOOD_PLAYCTL; | ||
122 | } else { | 122 | } else { |
123 | i2s_reg = KIRKWOOD_I2S_RECCTL; | 123 | i2s_reg = KIRKWOOD_I2S_RECCTL; |
124 | reg = KIRKWOOD_RECCTL; | ||
125 | } | 124 | } |
126 | 125 | ||
127 | /* set dco conf */ | 126 | /* set dco conf */ |
@@ -130,9 +129,6 @@ static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream, | |||
130 | i2s_value = readl(priv->io+i2s_reg); | 129 | i2s_value = readl(priv->io+i2s_reg); |
131 | i2s_value &= ~KIRKWOOD_I2S_CTL_SIZE_MASK; | 130 | i2s_value &= ~KIRKWOOD_I2S_CTL_SIZE_MASK; |
132 | 131 | ||
133 | value = readl(priv->io+reg); | ||
134 | value &= ~KIRKWOOD_PLAYCTL_SIZE_MASK; | ||
135 | |||
136 | /* | 132 | /* |
137 | * Size settings in play/rec i2s control regs and play/rec control | 133 | * Size settings in play/rec i2s control regs and play/rec control |
138 | * regs must be the same. | 134 | * regs must be the same. |
@@ -140,38 +136,57 @@ static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream, | |||
140 | switch (params_format(params)) { | 136 | switch (params_format(params)) { |
141 | case SNDRV_PCM_FORMAT_S16_LE: | 137 | case SNDRV_PCM_FORMAT_S16_LE: |
142 | i2s_value |= KIRKWOOD_I2S_CTL_SIZE_16; | 138 | i2s_value |= KIRKWOOD_I2S_CTL_SIZE_16; |
143 | value |= KIRKWOOD_PLAYCTL_SIZE_16_C; | 139 | ctl_play = KIRKWOOD_PLAYCTL_SIZE_16_C | |
140 | KIRKWOOD_PLAYCTL_I2S_EN; | ||
141 | ctl_rec = KIRKWOOD_RECCTL_SIZE_16_C | | ||
142 | KIRKWOOD_RECCTL_I2S_EN; | ||
144 | break; | 143 | break; |
145 | /* | 144 | /* |
146 | * doesn't work... S20_3LE != kirkwood 20bit format ? | 145 | * doesn't work... S20_3LE != kirkwood 20bit format ? |
147 | * | 146 | * |
148 | case SNDRV_PCM_FORMAT_S20_3LE: | 147 | case SNDRV_PCM_FORMAT_S20_3LE: |
149 | i2s_value |= KIRKWOOD_I2S_CTL_SIZE_20; | 148 | i2s_value |= KIRKWOOD_I2S_CTL_SIZE_20; |
150 | value |= KIRKWOOD_PLAYCTL_SIZE_20; | 149 | ctl_play = KIRKWOOD_PLAYCTL_SIZE_20 | |
150 | KIRKWOOD_PLAYCTL_I2S_EN; | ||
151 | ctl_rec = KIRKWOOD_RECCTL_SIZE_20 | | ||
152 | KIRKWOOD_RECCTL_I2S_EN; | ||
151 | break; | 153 | break; |
152 | */ | 154 | */ |
153 | case SNDRV_PCM_FORMAT_S24_LE: | 155 | case SNDRV_PCM_FORMAT_S24_LE: |
154 | i2s_value |= KIRKWOOD_I2S_CTL_SIZE_24; | 156 | i2s_value |= KIRKWOOD_I2S_CTL_SIZE_24; |
155 | value |= KIRKWOOD_PLAYCTL_SIZE_24; | 157 | ctl_play = KIRKWOOD_PLAYCTL_SIZE_24 | |
158 | KIRKWOOD_PLAYCTL_I2S_EN; | ||
159 | ctl_rec = KIRKWOOD_RECCTL_SIZE_24 | | ||
160 | KIRKWOOD_RECCTL_I2S_EN; | ||
156 | break; | 161 | break; |
157 | case SNDRV_PCM_FORMAT_S32_LE: | 162 | case SNDRV_PCM_FORMAT_S32_LE: |
158 | i2s_value |= KIRKWOOD_I2S_CTL_SIZE_32; | 163 | i2s_value |= KIRKWOOD_I2S_CTL_SIZE_32; |
159 | value |= KIRKWOOD_PLAYCTL_SIZE_32; | 164 | ctl_play = KIRKWOOD_PLAYCTL_SIZE_32 | |
165 | KIRKWOOD_PLAYCTL_I2S_EN; | ||
166 | ctl_rec = KIRKWOOD_RECCTL_SIZE_32 | | ||
167 | KIRKWOOD_RECCTL_I2S_EN; | ||
160 | break; | 168 | break; |
161 | default: | 169 | default: |
162 | return -EINVAL; | 170 | return -EINVAL; |
163 | } | 171 | } |
164 | 172 | ||
165 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 173 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
166 | value &= ~KIRKWOOD_PLAYCTL_MONO_MASK; | ||
167 | if (params_channels(params) == 1) | 174 | if (params_channels(params) == 1) |
168 | value |= KIRKWOOD_PLAYCTL_MONO_BOTH; | 175 | ctl_play |= KIRKWOOD_PLAYCTL_MONO_BOTH; |
169 | else | 176 | else |
170 | value |= KIRKWOOD_PLAYCTL_MONO_OFF; | 177 | ctl_play |= KIRKWOOD_PLAYCTL_MONO_OFF; |
178 | |||
179 | priv->ctl_play &= ~(KIRKWOOD_PLAYCTL_MONO_MASK | | ||
180 | KIRKWOOD_PLAYCTL_I2S_EN | | ||
181 | KIRKWOOD_PLAYCTL_SPDIF_EN | | ||
182 | KIRKWOOD_PLAYCTL_SIZE_MASK); | ||
183 | priv->ctl_play |= ctl_play; | ||
184 | } else { | ||
185 | priv->ctl_rec &= ~KIRKWOOD_RECCTL_SIZE_MASK; | ||
186 | priv->ctl_rec |= ctl_rec; | ||
171 | } | 187 | } |
172 | 188 | ||
173 | writel(i2s_value, priv->io+i2s_reg); | 189 | writel(i2s_value, priv->io+i2s_reg); |
174 | writel(value, priv->io+reg); | ||
175 | 190 | ||
176 | return 0; | 191 | return 0; |
177 | } | 192 | } |
@@ -205,20 +220,18 @@ static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream, | |||
205 | 220 | ||
206 | switch (cmd) { | 221 | switch (cmd) { |
207 | case SNDRV_PCM_TRIGGER_START: | 222 | case SNDRV_PCM_TRIGGER_START: |
223 | /* configure */ | ||
224 | ctl = priv->ctl_play; | ||
225 | value = ctl & ~(KIRKWOOD_PLAYCTL_I2S_EN | | ||
226 | KIRKWOOD_PLAYCTL_SPDIF_EN); | ||
227 | writel(value, priv->io + KIRKWOOD_PLAYCTL); | ||
228 | |||
229 | /* enable interrupts */ | ||
208 | value = readl(priv->io + KIRKWOOD_INT_MASK); | 230 | value = readl(priv->io + KIRKWOOD_INT_MASK); |
209 | value |= KIRKWOOD_INT_CAUSE_PLAY_BYTES; | 231 | value |= KIRKWOOD_INT_CAUSE_PLAY_BYTES; |
210 | writel(value, priv->io + KIRKWOOD_INT_MASK); | 232 | writel(value, priv->io + KIRKWOOD_INT_MASK); |
211 | 233 | ||
212 | /* configure audio & enable i2s playback */ | 234 | /* enable playback */ |
213 | ctl &= ~KIRKWOOD_PLAYCTL_BURST_MASK; | ||
214 | ctl &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE | ||
215 | | KIRKWOOD_PLAYCTL_SPDIF_EN); | ||
216 | |||
217 | if (priv->burst == 32) | ||
218 | ctl |= KIRKWOOD_PLAYCTL_BURST_32; | ||
219 | else | ||
220 | ctl |= KIRKWOOD_PLAYCTL_BURST_128; | ||
221 | ctl |= KIRKWOOD_PLAYCTL_I2S_EN; | ||
222 | writel(ctl, priv->io + KIRKWOOD_PLAYCTL); | 235 | writel(ctl, priv->io + KIRKWOOD_PLAYCTL); |
223 | break; | 236 | break; |
224 | 237 | ||
@@ -259,30 +272,24 @@ static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream, | |||
259 | int cmd, struct snd_soc_dai *dai) | 272 | int cmd, struct snd_soc_dai *dai) |
260 | { | 273 | { |
261 | struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai); | 274 | struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai); |
262 | unsigned long value; | 275 | uint32_t ctl, value; |
263 | 276 | ||
264 | value = readl(priv->io + KIRKWOOD_RECCTL); | 277 | value = readl(priv->io + KIRKWOOD_RECCTL); |
265 | 278 | ||
266 | switch (cmd) { | 279 | switch (cmd) { |
267 | case SNDRV_PCM_TRIGGER_START: | 280 | case SNDRV_PCM_TRIGGER_START: |
281 | /* configure */ | ||
282 | ctl = priv->ctl_rec; | ||
283 | value = ctl & ~KIRKWOOD_RECCTL_I2S_EN; | ||
284 | writel(value, priv->io + KIRKWOOD_RECCTL); | ||
285 | |||
286 | /* enable interrupts */ | ||
268 | value = readl(priv->io + KIRKWOOD_INT_MASK); | 287 | value = readl(priv->io + KIRKWOOD_INT_MASK); |
269 | value |= KIRKWOOD_INT_CAUSE_REC_BYTES; | 288 | value |= KIRKWOOD_INT_CAUSE_REC_BYTES; |
270 | writel(value, priv->io + KIRKWOOD_INT_MASK); | 289 | writel(value, priv->io + KIRKWOOD_INT_MASK); |
271 | 290 | ||
272 | /* configure audio & enable i2s record */ | 291 | /* enable record */ |
273 | value = readl(priv->io + KIRKWOOD_RECCTL); | 292 | writel(ctl, priv->io + KIRKWOOD_RECCTL); |
274 | value &= ~KIRKWOOD_RECCTL_BURST_MASK; | ||
275 | value &= ~KIRKWOOD_RECCTL_MONO; | ||
276 | value &= ~(KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE | ||
277 | | KIRKWOOD_RECCTL_SPDIF_EN); | ||
278 | |||
279 | if (priv->burst == 32) | ||
280 | value |= KIRKWOOD_RECCTL_BURST_32; | ||
281 | else | ||
282 | value |= KIRKWOOD_RECCTL_BURST_128; | ||
283 | value |= KIRKWOOD_RECCTL_I2S_EN; | ||
284 | |||
285 | writel(value, priv->io + KIRKWOOD_RECCTL); | ||
286 | break; | 293 | break; |
287 | 294 | ||
288 | case SNDRV_PCM_TRIGGER_STOP: | 295 | case SNDRV_PCM_TRIGGER_STOP: |
@@ -448,6 +455,31 @@ static __devinit int kirkwood_i2s_dev_probe(struct platform_device *pdev) | |||
448 | if (err < 0) | 455 | if (err < 0) |
449 | return err; | 456 | return err; |
450 | 457 | ||
458 | priv->extclk = clk_get(&pdev->dev, "extclk"); | ||
459 | if (!IS_ERR(priv->extclk)) { | ||
460 | if (priv->extclk == priv->clk) { | ||
461 | clk_put(priv->extclk); | ||
462 | priv->extclk = ERR_PTR(-EINVAL); | ||
463 | } else { | ||
464 | dev_info(&pdev->dev, "found external clock\n"); | ||
465 | clk_prepare_enable(priv->extclk); | ||
466 | soc_dai = &kirkwood_i2s_dai_extclk; | ||
467 | } | ||
468 | } | ||
469 | |||
470 | /* Some sensible defaults - this reflects the powerup values */ | ||
471 | priv->ctl_play = KIRKWOOD_PLAYCTL_SIZE_24; | ||
472 | priv->ctl_rec = KIRKWOOD_RECCTL_SIZE_24; | ||
473 | |||
474 | /* Select the burst size */ | ||
475 | if (data->burst == 32) { | ||
476 | priv->ctl_play |= KIRKWOOD_PLAYCTL_BURST_32; | ||
477 | priv->ctl_rec |= KIRKWOOD_RECCTL_BURST_32; | ||
478 | } else { | ||
479 | priv->ctl_play |= KIRKWOOD_PLAYCTL_BURST_128; | ||
480 | priv->ctl_rec |= KIRKWOOD_RECCTL_BURST_128; | ||
481 | } | ||
482 | |||
451 | err = snd_soc_register_dai(&pdev->dev, &kirkwood_i2s_dai); | 483 | err = snd_soc_register_dai(&pdev->dev, &kirkwood_i2s_dai); |
452 | if (!err) | 484 | if (!err) |
453 | return 0; | 485 | return 0; |