blob: 3446a113f482eb0b061d2b6b5ec226bc38378aa6 [file] [log] [blame]
Thomas Gleixner2874c5f2019-05-27 08:55:01 +02001// SPDX-License-Identifier: GPL-2.0-or-later
apatard@mandriva.comf9b95982010-05-31 13:49:14 +02002/*
3 * kirkwood-i2s.c
4 *
5 * (c) 2010 Arnaud Patard <apatard@mandriva.com>
Arnaud Patard (Rtp)69737892010-09-09 14:10:33 +02006 * (c) 2010 Arnaud Patard <arnaud.patard@rtp-net.org>
apatard@mandriva.comf9b95982010-05-31 13:49:14 +02007 */
8
9#include <linux/init.h>
10#include <linux/module.h>
11#include <linux/platform_device.h>
12#include <linux/io.h>
13#include <linux/slab.h>
14#include <linux/mbus.h>
15#include <linux/delay.h>
Andrew Lunne919c712012-03-09 09:56:41 +010016#include <linux/clk.h>
apatard@mandriva.comf9b95982010-05-31 13:49:14 +020017#include <sound/pcm.h>
18#include <sound/pcm_params.h>
19#include <sound/soc.h>
Arnd Bergmannc02cecb2012-08-24 15:21:54 +020020#include <linux/platform_data/asoc-kirkwood.h>
Jean-Francois Moineeb632312013-08-14 12:27:33 +020021#include <linux/of.h>
22
apatard@mandriva.comf9b95982010-05-31 13:49:14 +020023#include "kirkwood.h"
24
apatard@mandriva.comf9b95982010-05-31 13:49:14 +020025#define KIRKWOOD_I2S_FORMATS \
26 (SNDRV_PCM_FMTBIT_S16_LE | \
27 SNDRV_PCM_FMTBIT_S24_LE | \
28 SNDRV_PCM_FMTBIT_S32_LE)
29
Jean-Francois Moine1c195dd2013-11-26 10:41:40 +010030#define KIRKWOOD_SPDIF_FORMATS \
31 (SNDRV_PCM_FMTBIT_S16_LE | \
32 SNDRV_PCM_FMTBIT_S24_LE)
33
apatard@mandriva.comf9b95982010-05-31 13:49:14 +020034static int kirkwood_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
35 unsigned int fmt)
36{
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +000037 struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(cpu_dai);
apatard@mandriva.comf9b95982010-05-31 13:49:14 +020038 unsigned long mask;
39 unsigned long value;
40
41 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
42 case SND_SOC_DAIFMT_RIGHT_J:
43 mask = KIRKWOOD_I2S_CTL_RJ;
44 break;
45 case SND_SOC_DAIFMT_LEFT_J:
46 mask = KIRKWOOD_I2S_CTL_LJ;
47 break;
48 case SND_SOC_DAIFMT_I2S:
49 mask = KIRKWOOD_I2S_CTL_I2S;
50 break;
51 default:
52 return -EINVAL;
53 }
54
55 /*
56 * Set same format for playback and record
57 * This avoids some troubles.
58 */
59 value = readl(priv->io+KIRKWOOD_I2S_PLAYCTL);
60 value &= ~KIRKWOOD_I2S_CTL_JUST_MASK;
61 value |= mask;
62 writel(value, priv->io+KIRKWOOD_I2S_PLAYCTL);
63
64 value = readl(priv->io+KIRKWOOD_I2S_RECCTL);
65 value &= ~KIRKWOOD_I2S_CTL_JUST_MASK;
66 value |= mask;
67 writel(value, priv->io+KIRKWOOD_I2S_RECCTL);
68
69 return 0;
70}
71
72static inline void kirkwood_set_dco(void __iomem *io, unsigned long rate)
73{
74 unsigned long value;
75
76 value = KIRKWOOD_DCO_CTL_OFFSET_0;
77 switch (rate) {
78 default:
79 case 44100:
80 value |= KIRKWOOD_DCO_CTL_FREQ_11;
81 break;
82 case 48000:
83 value |= KIRKWOOD_DCO_CTL_FREQ_12;
84 break;
85 case 96000:
86 value |= KIRKWOOD_DCO_CTL_FREQ_24;
87 break;
88 }
89 writel(value, io + KIRKWOOD_DCO_CTL);
90
91 /* wait for dco locked */
92 do {
93 cpu_relax();
94 value = readl(io + KIRKWOOD_DCO_SPCR_STATUS);
Russell King2424d452012-11-20 12:18:32 +000095 value &= KIRKWOOD_DCO_SPCR_STATUS_DCO_LOCK;
apatard@mandriva.comf9b95982010-05-31 13:49:14 +020096 } while (value == 0);
97}
98
Russell King363589b2012-11-20 12:20:34 +000099static void kirkwood_set_rate(struct snd_soc_dai *dai,
100 struct kirkwood_dma_data *priv, unsigned long rate)
101{
102 uint32_t clks_ctrl;
103
Jean-Francois Moine1f1b6572013-10-18 20:34:52 +0200104 if (IS_ERR(priv->extclk)) {
Jean-Francois Moine8a537f82013-07-16 08:47:47 +0200105 /* use internal dco for the supported rates
106 * defined in kirkwood_i2s_dai */
Russell King363589b2012-11-20 12:20:34 +0000107 dev_dbg(dai->dev, "%s: dco set rate = %lu\n",
108 __func__, rate);
109 kirkwood_set_dco(priv->io, rate);
110
111 clks_ctrl = KIRKWOOD_MCLK_SOURCE_DCO;
Jean-Francois Moine8a537f82013-07-16 08:47:47 +0200112 } else {
113 /* use the external clock for the other rates
114 * defined in kirkwood_i2s_dai_extclk */
Russell King363589b2012-11-20 12:20:34 +0000115 dev_dbg(dai->dev, "%s: extclk set rate = %lu -> %lu\n",
116 __func__, rate, 256 * rate);
117 clk_set_rate(priv->extclk, 256 * rate);
118
119 clks_ctrl = KIRKWOOD_MCLK_SOURCE_EXTCLK;
120 }
121 writel(clks_ctrl, priv->io + KIRKWOOD_CLOCKS_CTRL);
122}
123
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000124static int kirkwood_i2s_startup(struct snd_pcm_substream *substream,
125 struct snd_soc_dai *dai)
126{
127 struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
128
129 snd_soc_dai_set_dma_data(dai, substream, priv);
130 return 0;
131}
132
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200133static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream,
134 struct snd_pcm_hw_params *params,
135 struct snd_soc_dai *dai)
136{
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000137 struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
Russell Kingd8d11ba2012-11-20 12:19:53 +0000138 uint32_t ctl_play, ctl_rec;
139 unsigned int i2s_reg;
140 unsigned long i2s_value;
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200141
142 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
143 i2s_reg = KIRKWOOD_I2S_PLAYCTL;
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200144 } else {
145 i2s_reg = KIRKWOOD_I2S_RECCTL;
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200146 }
147
Russell King363589b2012-11-20 12:20:34 +0000148 kirkwood_set_rate(dai, priv, params_rate(params));
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200149
150 i2s_value = readl(priv->io+i2s_reg);
151 i2s_value &= ~KIRKWOOD_I2S_CTL_SIZE_MASK;
152
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200153 /*
154 * Size settings in play/rec i2s control regs and play/rec control
155 * regs must be the same.
156 */
157 switch (params_format(params)) {
158 case SNDRV_PCM_FORMAT_S16_LE:
159 i2s_value |= KIRKWOOD_I2S_CTL_SIZE_16;
Russell Kingd8d11ba2012-11-20 12:19:53 +0000160 ctl_play = KIRKWOOD_PLAYCTL_SIZE_16_C |
Jean-Francois Moine75b9b652013-10-21 10:50:49 +0200161 KIRKWOOD_PLAYCTL_I2S_EN |
162 KIRKWOOD_PLAYCTL_SPDIF_EN;
Russell Kingd8d11ba2012-11-20 12:19:53 +0000163 ctl_rec = KIRKWOOD_RECCTL_SIZE_16_C |
Jean-Francois Moine75b9b652013-10-21 10:50:49 +0200164 KIRKWOOD_RECCTL_I2S_EN |
165 KIRKWOOD_RECCTL_SPDIF_EN;
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200166 break;
167 /*
168 * doesn't work... S20_3LE != kirkwood 20bit format ?
169 *
170 case SNDRV_PCM_FORMAT_S20_3LE:
171 i2s_value |= KIRKWOOD_I2S_CTL_SIZE_20;
Russell Kingd8d11ba2012-11-20 12:19:53 +0000172 ctl_play = KIRKWOOD_PLAYCTL_SIZE_20 |
173 KIRKWOOD_PLAYCTL_I2S_EN;
174 ctl_rec = KIRKWOOD_RECCTL_SIZE_20 |
175 KIRKWOOD_RECCTL_I2S_EN;
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200176 break;
177 */
178 case SNDRV_PCM_FORMAT_S24_LE:
179 i2s_value |= KIRKWOOD_I2S_CTL_SIZE_24;
Russell Kingd8d11ba2012-11-20 12:19:53 +0000180 ctl_play = KIRKWOOD_PLAYCTL_SIZE_24 |
Jean-Francois Moine75b9b652013-10-21 10:50:49 +0200181 KIRKWOOD_PLAYCTL_I2S_EN |
182 KIRKWOOD_PLAYCTL_SPDIF_EN;
Russell Kingd8d11ba2012-11-20 12:19:53 +0000183 ctl_rec = KIRKWOOD_RECCTL_SIZE_24 |
Jean-Francois Moine75b9b652013-10-21 10:50:49 +0200184 KIRKWOOD_RECCTL_I2S_EN |
185 KIRKWOOD_RECCTL_SPDIF_EN;
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200186 break;
187 case SNDRV_PCM_FORMAT_S32_LE:
188 i2s_value |= KIRKWOOD_I2S_CTL_SIZE_32;
Russell Kingd8d11ba2012-11-20 12:19:53 +0000189 ctl_play = KIRKWOOD_PLAYCTL_SIZE_32 |
190 KIRKWOOD_PLAYCTL_I2S_EN;
191 ctl_rec = KIRKWOOD_RECCTL_SIZE_32 |
192 KIRKWOOD_RECCTL_I2S_EN;
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200193 break;
194 default:
195 return -EINVAL;
196 }
arnaud.patard@rtp-net.orgdfe4c932010-07-11 23:28:31 +0200197
198 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
arnaud.patard@rtp-net.orgdfe4c932010-07-11 23:28:31 +0200199 if (params_channels(params) == 1)
Russell Kingd8d11ba2012-11-20 12:19:53 +0000200 ctl_play |= KIRKWOOD_PLAYCTL_MONO_BOTH;
arnaud.patard@rtp-net.orgdfe4c932010-07-11 23:28:31 +0200201 else
Russell Kingd8d11ba2012-11-20 12:19:53 +0000202 ctl_play |= KIRKWOOD_PLAYCTL_MONO_OFF;
203
204 priv->ctl_play &= ~(KIRKWOOD_PLAYCTL_MONO_MASK |
Russell Kingdb43b162013-08-04 20:26:03 +0100205 KIRKWOOD_PLAYCTL_ENABLE_MASK |
Russell Kingd8d11ba2012-11-20 12:19:53 +0000206 KIRKWOOD_PLAYCTL_SIZE_MASK);
207 priv->ctl_play |= ctl_play;
208 } else {
Russell King67721902014-06-26 15:23:00 +0100209 priv->ctl_rec &= ~(KIRKWOOD_RECCTL_ENABLE_MASK |
210 KIRKWOOD_RECCTL_SIZE_MASK);
Russell Kingd8d11ba2012-11-20 12:19:53 +0000211 priv->ctl_rec |= ctl_rec;
arnaud.patard@rtp-net.orgdfe4c932010-07-11 23:28:31 +0200212 }
213
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200214 writel(i2s_value, priv->io+i2s_reg);
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200215
216 return 0;
217}
218
Russell King2fbc3822014-06-26 15:23:05 +0100219static unsigned kirkwood_i2s_play_mute(unsigned ctl)
220{
221 if (!(ctl & KIRKWOOD_PLAYCTL_I2S_EN))
222 ctl |= KIRKWOOD_PLAYCTL_I2S_MUTE;
223 if (!(ctl & KIRKWOOD_PLAYCTL_SPDIF_EN))
224 ctl |= KIRKWOOD_PLAYCTL_SPDIF_MUTE;
225 return ctl;
226}
227
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200228static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream,
229 int cmd, struct snd_soc_dai *dai)
230{
Russell King920ec4e2014-06-26 15:23:20 +0100231 struct snd_pcm_runtime *runtime = substream->runtime;
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000232 struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
Russell King982b6042012-11-20 12:18:52 +0000233 uint32_t ctl, value;
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200234
Russell King982b6042012-11-20 12:18:52 +0000235 ctl = readl(priv->io + KIRKWOOD_PLAYCTL);
Russell King4d2097e2014-06-26 15:23:10 +0100236 if ((ctl & KIRKWOOD_PLAYCTL_ENABLE_MASK) == 0) {
Russell King982b6042012-11-20 12:18:52 +0000237 unsigned timeout = 5000;
238 /*
239 * The Armada510 spec says that if we enter pause mode, the
240 * busy bit must be read back as clear _twice_. Make sure
241 * we respect that otherwise we get DMA underruns.
242 */
243 do {
244 value = ctl;
245 ctl = readl(priv->io + KIRKWOOD_PLAYCTL);
246 if (!((ctl | value) & KIRKWOOD_PLAYCTL_PLAY_BUSY))
247 break;
248 udelay(1);
249 } while (timeout--);
250
251 if ((ctl | value) & KIRKWOOD_PLAYCTL_PLAY_BUSY)
252 dev_notice(dai->dev, "timed out waiting for busy to deassert: %08x\n",
253 ctl);
254 }
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200255
256 switch (cmd) {
257 case SNDRV_PCM_TRIGGER_START:
Russell Kingd8d11ba2012-11-20 12:19:53 +0000258 /* configure */
259 ctl = priv->ctl_play;
Jean-Francois Moine4f6f1472013-11-25 20:19:05 +0100260 if (dai->id == 0)
261 ctl &= ~KIRKWOOD_PLAYCTL_SPDIF_EN; /* i2s */
262 else
263 ctl &= ~KIRKWOOD_PLAYCTL_I2S_EN; /* spdif */
Russell King2fbc3822014-06-26 15:23:05 +0100264 ctl = kirkwood_i2s_play_mute(ctl);
Russell Kingdb43b162013-08-04 20:26:03 +0100265 value = ctl & ~KIRKWOOD_PLAYCTL_ENABLE_MASK;
Russell Kingd8d11ba2012-11-20 12:19:53 +0000266 writel(value, priv->io + KIRKWOOD_PLAYCTL);
267
268 /* enable interrupts */
Russell King920ec4e2014-06-26 15:23:20 +0100269 if (!runtime->no_period_wakeup) {
270 value = readl(priv->io + KIRKWOOD_INT_MASK);
271 value |= KIRKWOOD_INT_CAUSE_PLAY_BYTES;
272 writel(value, priv->io + KIRKWOOD_INT_MASK);
273 }
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200274
Russell Kingd8d11ba2012-11-20 12:19:53 +0000275 /* enable playback */
Russell King982b6042012-11-20 12:18:52 +0000276 writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200277 break;
278
279 case SNDRV_PCM_TRIGGER_STOP:
280 /* stop audio, disable interrupts */
Jean-Francois Moine75b9b652013-10-21 10:50:49 +0200281 ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE |
282 KIRKWOOD_PLAYCTL_SPDIF_MUTE;
Russell King982b6042012-11-20 12:18:52 +0000283 writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200284
285 value = readl(priv->io + KIRKWOOD_INT_MASK);
286 value &= ~KIRKWOOD_INT_CAUSE_PLAY_BYTES;
287 writel(value, priv->io + KIRKWOOD_INT_MASK);
288
289 /* disable all playbacks */
Russell Kingdb43b162013-08-04 20:26:03 +0100290 ctl &= ~KIRKWOOD_PLAYCTL_ENABLE_MASK;
Russell King982b6042012-11-20 12:18:52 +0000291 writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200292 break;
293
294 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
295 case SNDRV_PCM_TRIGGER_SUSPEND:
Jean-Francois Moine75b9b652013-10-21 10:50:49 +0200296 ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE |
297 KIRKWOOD_PLAYCTL_SPDIF_MUTE;
Russell King982b6042012-11-20 12:18:52 +0000298 writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200299 break;
300
301 case SNDRV_PCM_TRIGGER_RESUME:
302 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
Jean-Francois Moine75b9b652013-10-21 10:50:49 +0200303 ctl &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE |
304 KIRKWOOD_PLAYCTL_SPDIF_MUTE);
Russell King2fbc3822014-06-26 15:23:05 +0100305 ctl = kirkwood_i2s_play_mute(ctl);
Russell King982b6042012-11-20 12:18:52 +0000306 writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200307 break;
308
309 default:
310 return -EINVAL;
311 }
312
313 return 0;
314}
315
316static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream,
317 int cmd, struct snd_soc_dai *dai)
318{
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000319 struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
Russell Kingd8d11ba2012-11-20 12:19:53 +0000320 uint32_t ctl, value;
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200321
322 value = readl(priv->io + KIRKWOOD_RECCTL);
323
324 switch (cmd) {
325 case SNDRV_PCM_TRIGGER_START:
Russell Kingd8d11ba2012-11-20 12:19:53 +0000326 /* configure */
327 ctl = priv->ctl_rec;
Jean-Francois Moine75b9b652013-10-21 10:50:49 +0200328 if (dai->id == 0)
329 ctl &= ~KIRKWOOD_RECCTL_SPDIF_EN; /* i2s */
330 else
331 ctl &= ~KIRKWOOD_RECCTL_I2S_EN; /* spdif */
332
Russell King52b896c2014-06-26 15:22:55 +0100333 value = ctl & ~KIRKWOOD_RECCTL_ENABLE_MASK;
Russell Kingd8d11ba2012-11-20 12:19:53 +0000334 writel(value, priv->io + KIRKWOOD_RECCTL);
335
336 /* enable interrupts */
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200337 value = readl(priv->io + KIRKWOOD_INT_MASK);
338 value |= KIRKWOOD_INT_CAUSE_REC_BYTES;
339 writel(value, priv->io + KIRKWOOD_INT_MASK);
340
Russell Kingd8d11ba2012-11-20 12:19:53 +0000341 /* enable record */
342 writel(ctl, priv->io + KIRKWOOD_RECCTL);
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200343 break;
344
345 case SNDRV_PCM_TRIGGER_STOP:
346 /* stop audio, disable interrupts */
347 value = readl(priv->io + KIRKWOOD_RECCTL);
arnaud.patard@rtp-net.orgb424ec92010-07-11 23:28:32 +0200348 value |= KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE;
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200349 writel(value, priv->io + KIRKWOOD_RECCTL);
350
351 value = readl(priv->io + KIRKWOOD_INT_MASK);
352 value &= ~KIRKWOOD_INT_CAUSE_REC_BYTES;
353 writel(value, priv->io + KIRKWOOD_INT_MASK);
354
355 /* disable all records */
356 value = readl(priv->io + KIRKWOOD_RECCTL);
Russell King52b896c2014-06-26 15:22:55 +0100357 value &= ~KIRKWOOD_RECCTL_ENABLE_MASK;
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200358 writel(value, priv->io + KIRKWOOD_RECCTL);
359 break;
360
361 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
362 case SNDRV_PCM_TRIGGER_SUSPEND:
363 value = readl(priv->io + KIRKWOOD_RECCTL);
arnaud.patard@rtp-net.orgb424ec92010-07-11 23:28:32 +0200364 value |= KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE;
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200365 writel(value, priv->io + KIRKWOOD_RECCTL);
366 break;
367
368 case SNDRV_PCM_TRIGGER_RESUME:
369 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
370 value = readl(priv->io + KIRKWOOD_RECCTL);
arnaud.patard@rtp-net.orgb424ec92010-07-11 23:28:32 +0200371 value &= ~(KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE);
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200372 writel(value, priv->io + KIRKWOOD_RECCTL);
373 break;
374
375 default:
376 return -EINVAL;
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200377 }
378
379 return 0;
380}
381
382static int kirkwood_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
383 struct snd_soc_dai *dai)
384{
385 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
386 return kirkwood_i2s_play_trigger(substream, cmd, dai);
387 else
388 return kirkwood_i2s_rec_trigger(substream, cmd, dai);
389
390 return 0;
391}
392
Jean-Francois Moine75b9b652013-10-21 10:50:49 +0200393static int kirkwood_i2s_init(struct kirkwood_dma_data *priv)
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200394{
395 unsigned long value;
396 unsigned int reg_data;
397
398 /* put system in a "safe" state : */
399 /* disable audio interrupts */
400 writel(0xffffffff, priv->io + KIRKWOOD_INT_CAUSE);
401 writel(0, priv->io + KIRKWOOD_INT_MASK);
402
403 reg_data = readl(priv->io + 0x1200);
404 reg_data &= (~(0x333FF8));
405 reg_data |= 0x111D18;
406 writel(reg_data, priv->io + 0x1200);
407
408 msleep(500);
409
410 reg_data = readl(priv->io + 0x1200);
411 reg_data &= (~(0x333FF8));
412 reg_data |= 0x111D18;
413 writel(reg_data, priv->io + 0x1200);
414
415 /* disable playback/record */
416 value = readl(priv->io + KIRKWOOD_PLAYCTL);
Russell Kingdb43b162013-08-04 20:26:03 +0100417 value &= ~KIRKWOOD_PLAYCTL_ENABLE_MASK;
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200418 writel(value, priv->io + KIRKWOOD_PLAYCTL);
419
420 value = readl(priv->io + KIRKWOOD_RECCTL);
Russell King52b896c2014-06-26 15:22:55 +0100421 value &= ~KIRKWOOD_RECCTL_ENABLE_MASK;
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200422 writel(value, priv->io + KIRKWOOD_RECCTL);
423
424 return 0;
425
426}
427
Lars-Peter Clausen85e76522011-11-23 11:40:40 +0100428static const struct snd_soc_dai_ops kirkwood_i2s_dai_ops = {
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000429 .startup = kirkwood_i2s_startup,
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200430 .trigger = kirkwood_i2s_trigger,
431 .hw_params = kirkwood_i2s_hw_params,
432 .set_fmt = kirkwood_i2s_set_fmt,
433};
434
Jean-Francois Moine75b9b652013-10-21 10:50:49 +0200435static struct snd_soc_dai_driver kirkwood_i2s_dai[2] = {
436 {
437 .name = "i2s",
438 .id = 0,
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200439 .playback = {
440 .channels_min = 1,
441 .channels_max = 2,
Mark Brown9e12cbd2013-07-16 10:47:10 +0100442 .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
443 SNDRV_PCM_RATE_96000,
Russell King363589b2012-11-20 12:20:34 +0000444 .formats = KIRKWOOD_I2S_FORMATS,
445 },
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200446 .capture = {
447 .channels_min = 1,
448 .channels_max = 2,
Mark Brown9e12cbd2013-07-16 10:47:10 +0100449 .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
450 SNDRV_PCM_RATE_96000,
Russell King363589b2012-11-20 12:20:34 +0000451 .formats = KIRKWOOD_I2S_FORMATS,
452 },
453 .ops = &kirkwood_i2s_dai_ops,
Jean-Francois Moine75b9b652013-10-21 10:50:49 +0200454 },
455 {
456 .name = "spdif",
457 .id = 1,
458 .playback = {
459 .channels_min = 1,
460 .channels_max = 2,
461 .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
462 SNDRV_PCM_RATE_96000,
Jean-Francois Moine1c195dd2013-11-26 10:41:40 +0100463 .formats = KIRKWOOD_SPDIF_FORMATS,
Jean-Francois Moine75b9b652013-10-21 10:50:49 +0200464 },
465 .capture = {
466 .channels_min = 1,
467 .channels_max = 2,
468 .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
469 SNDRV_PCM_RATE_96000,
Jean-Francois Moine1c195dd2013-11-26 10:41:40 +0100470 .formats = KIRKWOOD_SPDIF_FORMATS,
Jean-Francois Moine75b9b652013-10-21 10:50:49 +0200471 },
472 .ops = &kirkwood_i2s_dai_ops,
473 },
Russell King363589b2012-11-20 12:20:34 +0000474};
475
Jean-Francois Moine75b9b652013-10-21 10:50:49 +0200476static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk[2] = {
477 {
478 .name = "i2s",
479 .id = 0,
Russell King363589b2012-11-20 12:20:34 +0000480 .playback = {
481 .channels_min = 1,
482 .channels_max = 2,
Jean-Francois Moine02fc17c2013-11-27 21:10:24 +0100483 .rates = SNDRV_PCM_RATE_CONTINUOUS,
484 .rate_min = 5512,
485 .rate_max = 192000,
Russell King363589b2012-11-20 12:20:34 +0000486 .formats = KIRKWOOD_I2S_FORMATS,
487 },
488 .capture = {
489 .channels_min = 1,
490 .channels_max = 2,
Jean-Francois Moine02fc17c2013-11-27 21:10:24 +0100491 .rates = SNDRV_PCM_RATE_CONTINUOUS,
492 .rate_min = 5512,
493 .rate_max = 192000,
Russell King363589b2012-11-20 12:20:34 +0000494 .formats = KIRKWOOD_I2S_FORMATS,
495 },
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200496 .ops = &kirkwood_i2s_dai_ops,
Jean-Francois Moine75b9b652013-10-21 10:50:49 +0200497 },
498 {
499 .name = "spdif",
500 .id = 1,
501 .playback = {
502 .channels_min = 1,
503 .channels_max = 2,
Jean-Francois Moine02fc17c2013-11-27 21:10:24 +0100504 .rates = SNDRV_PCM_RATE_CONTINUOUS,
505 .rate_min = 5512,
506 .rate_max = 192000,
Jean-Francois Moine1c195dd2013-11-26 10:41:40 +0100507 .formats = KIRKWOOD_SPDIF_FORMATS,
Jean-Francois Moine75b9b652013-10-21 10:50:49 +0200508 },
509 .capture = {
510 .channels_min = 1,
511 .channels_max = 2,
Jean-Francois Moine02fc17c2013-11-27 21:10:24 +0100512 .rates = SNDRV_PCM_RATE_CONTINUOUS,
513 .rate_min = 5512,
514 .rate_max = 192000,
Jean-Francois Moine1c195dd2013-11-26 10:41:40 +0100515 .formats = KIRKWOOD_SPDIF_FORMATS,
Jean-Francois Moine75b9b652013-10-21 10:50:49 +0200516 },
517 .ops = &kirkwood_i2s_dai_ops,
518 },
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200519};
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200520
Bill Pemberton34e15fb2012-12-07 09:26:26 -0500521static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200522{
Russell King363589b2012-11-20 12:20:34 +0000523 struct kirkwood_asoc_platform_data *data = pdev->dev.platform_data;
Jean-Francois Moine75b9b652013-10-21 10:50:49 +0200524 struct snd_soc_dai_driver *soc_dai = kirkwood_i2s_dai;
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000525 struct kirkwood_dma_data *priv;
Russell King363589b2012-11-20 12:20:34 +0000526 struct resource *mem;
Jean-Francois Moineeb632312013-08-14 12:27:33 +0200527 struct device_node *np = pdev->dev.of_node;
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200528 int err;
529
Russell Kingdbc517b2012-11-20 12:19:33 +0000530 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
Markus Elfringc7591ed2017-08-11 09:35:33 +0200531 if (!priv)
Russell Kingdbc517b2012-11-20 12:19:33 +0000532 return -ENOMEM;
Markus Elfringc7591ed2017-08-11 09:35:33 +0200533
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000534 dev_set_drvdata(&pdev->dev, priv);
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200535
536 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Thierry Redingb25b5aa2013-01-21 11:09:26 +0100537 priv->io = devm_ioremap_resource(&pdev->dev, mem);
538 if (IS_ERR(priv->io))
539 return PTR_ERR(priv->io);
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200540
541 priv->irq = platform_get_irq(pdev, 0);
Gustavo A. R. Silvae7b2e302017-06-30 16:46:33 -0500542 if (priv->irq < 0) {
543 dev_err(&pdev->dev, "platform_get_irq failed: %d\n", priv->irq);
544 return priv->irq;
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200545 }
546
Jean-Francois Moineeb632312013-08-14 12:27:33 +0200547 if (np) {
548 priv->burst = 128; /* might be 32 or 128 */
549 } else if (data) {
550 priv->burst = data->burst;
551 } else {
552 dev_err(&pdev->dev, "no DT nor platform data ?!\n");
Russell Kingdbc517b2012-11-20 12:19:33 +0000553 return -EINVAL;
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200554 }
555
Jean-Francois Moineeb632312013-08-14 12:27:33 +0200556 priv->clk = devm_clk_get(&pdev->dev, np ? "internal" : NULL);
Andrew Lunne919c712012-03-09 09:56:41 +0100557 if (IS_ERR(priv->clk)) {
558 dev_err(&pdev->dev, "no clock\n");
Russell Kingdbc517b2012-11-20 12:19:33 +0000559 return PTR_ERR(priv->clk);
Andrew Lunne919c712012-03-09 09:56:41 +0100560 }
Russell Kingdbc517b2012-11-20 12:19:33 +0000561
562 err = clk_prepare_enable(priv->clk);
563 if (err < 0)
564 return err;
Andrew Lunne919c712012-03-09 09:56:41 +0100565
Mark Brown4734dc92013-07-15 16:41:14 +0100566 priv->extclk = devm_clk_get(&pdev->dev, "extclk");
Jean-Francois Moine84aac6c2013-09-21 12:00:36 +0200567 if (IS_ERR(priv->extclk)) {
568 if (PTR_ERR(priv->extclk) == -EPROBE_DEFER)
569 return -EPROBE_DEFER;
570 } else {
Shawn Guoaaa6d062015-02-25 22:53:38 +0800571 if (clk_is_match(priv->extclk, priv->clk)) {
Russell Kingaf64d732013-08-04 20:23:03 +0100572 devm_clk_put(&pdev->dev, priv->extclk);
Russell Kingd8d11ba2012-11-20 12:19:53 +0000573 priv->extclk = ERR_PTR(-EINVAL);
574 } else {
575 dev_info(&pdev->dev, "found external clock\n");
576 clk_prepare_enable(priv->extclk);
Jean-Francois Moine99d8d3b2013-10-24 17:55:18 +0200577 soc_dai = kirkwood_i2s_dai_extclk;
Russell Kingd8d11ba2012-11-20 12:19:53 +0000578 }
579 }
580
581 /* Some sensible defaults - this reflects the powerup values */
582 priv->ctl_play = KIRKWOOD_PLAYCTL_SIZE_24;
583 priv->ctl_rec = KIRKWOOD_RECCTL_SIZE_24;
584
585 /* Select the burst size */
Jean-Francois Moineeb632312013-08-14 12:27:33 +0200586 if (priv->burst == 32) {
Russell Kingd8d11ba2012-11-20 12:19:53 +0000587 priv->ctl_play |= KIRKWOOD_PLAYCTL_BURST_32;
588 priv->ctl_rec |= KIRKWOOD_RECCTL_BURST_32;
589 } else {
590 priv->ctl_play |= KIRKWOOD_PLAYCTL_BURST_128;
591 priv->ctl_rec |= KIRKWOOD_RECCTL_BURST_128;
592 }
593
Kuninori Morimotof98fc0f2018-01-29 02:48:03 +0000594 err = devm_snd_soc_register_component(&pdev->dev, &kirkwood_soc_component,
Jean-Francois Moine75b9b652013-10-21 10:50:49 +0200595 soc_dai, 2);
Russell King64ddf1f2013-08-04 20:27:03 +0100596 if (err) {
597 dev_err(&pdev->dev, "snd_soc_register_component failed\n");
598 goto err_component;
599 }
Simon Baatzbaffab22012-07-19 00:04:09 +0200600
Jean-Francois Moine75b9b652013-10-21 10:50:49 +0200601 kirkwood_i2s_init(priv);
602
Russell King64ddf1f2013-08-04 20:27:03 +0100603 return 0;
Kuninori Morimotof98fc0f2018-01-29 02:48:03 +0000604
Russell King64ddf1f2013-08-04 20:27:03 +0100605 err_component:
Mark Brown4734dc92013-07-15 16:41:14 +0100606 if (!IS_ERR(priv->extclk))
Russell King363589b2012-11-20 12:20:34 +0000607 clk_disable_unprepare(priv->extclk);
Simon Baatzbaffab22012-07-19 00:04:09 +0200608 clk_disable_unprepare(priv->clk);
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200609
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200610 return err;
611}
612
Bill Pemberton34e15fb2012-12-07 09:26:26 -0500613static int kirkwood_i2s_dev_remove(struct platform_device *pdev)
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200614{
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000615 struct kirkwood_dma_data *priv = dev_get_drvdata(&pdev->dev);
616
Mark Brown4734dc92013-07-15 16:41:14 +0100617 if (!IS_ERR(priv->extclk))
Russell King363589b2012-11-20 12:20:34 +0000618 clk_disable_unprepare(priv->extclk);
Andrew Lunne919c712012-03-09 09:56:41 +0100619 clk_disable_unprepare(priv->clk);
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000620
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200621 return 0;
622}
623
Jean-Francois Moineeb632312013-08-14 12:27:33 +0200624#ifdef CONFIG_OF
Fabian Frederick7f2c52a2015-03-18 17:48:58 +0100625static const struct of_device_id mvebu_audio_of_match[] = {
Thomas Petazzonid098b2f2013-09-05 14:56:31 +0200626 { .compatible = "marvell,kirkwood-audio" },
627 { .compatible = "marvell,dove-audio" },
Thomas Petazzoni9a0d5112014-01-30 18:14:06 +0100628 { .compatible = "marvell,armada370-audio" },
Jean-Francois Moineeb632312013-08-14 12:27:33 +0200629 { }
630};
631MODULE_DEVICE_TABLE(of, mvebu_audio_of_match);
632#endif
633
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200634static struct platform_driver kirkwood_i2s_driver = {
635 .probe = kirkwood_i2s_dev_probe,
Bill Pemberton34e15fb2012-12-07 09:26:26 -0500636 .remove = kirkwood_i2s_dev_remove,
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200637 .driver = {
638 .name = DRV_NAME,
Jean-Francois Moineeb632312013-08-14 12:27:33 +0200639 .of_match_table = of_match_ptr(mvebu_audio_of_match),
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200640 },
641};
642
Axel Lin41b10222011-11-24 11:43:09 +0800643module_platform_driver(kirkwood_i2s_driver);
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200644
645/* Module information */
Arnaud Patard (Rtp)69737892010-09-09 14:10:33 +0200646MODULE_AUTHOR("Arnaud Patard, <arnaud.patard@rtp-net.org>");
apatard@mandriva.comf9b95982010-05-31 13:49:14 +0200647MODULE_DESCRIPTION("Kirkwood I2S SoC Interface");
648MODULE_LICENSE("GPL");
Russell King64ddf1f2013-08-04 20:27:03 +0100649MODULE_ALIAS("platform:mvebu-audio");