2 * Copyright (c) 2009-2010 Nuvoton technology corporation.
4 * Wan ZongShun <mcuos.com@gmail.com>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation;version 2 of the License.
12 #include <linux/init.h>
13 #include <linux/module.h>
14 #include <linux/slab.h>
15 #include <linux/device.h>
16 #include <linux/delay.h>
17 #include <linux/mutex.h>
18 #include <linux/suspend.h>
19 #include <sound/core.h>
20 #include <sound/pcm.h>
21 #include <sound/initval.h>
22 #include <sound/soc.h>
23 #include <linux/clk.h>
27 #include "nuc900-audio.h"
29 static DEFINE_MUTEX(ac97_mutex
);
30 struct nuc900_audio
*nuc900_ac97_data
;
31 EXPORT_SYMBOL_GPL(nuc900_ac97_data
);
33 static int nuc900_checkready(void)
35 struct nuc900_audio
*nuc900_audio
= nuc900_ac97_data
;
37 if (!(AUDIO_READ(nuc900_audio
->mmio
+ ACTL_ACIS0
) & CODEC_READY
))
43 /* AC97 controller reads codec register */
44 static unsigned short nuc900_ac97_read(struct snd_ac97
*ac97
,
47 struct nuc900_audio
*nuc900_audio
= nuc900_ac97_data
;
48 unsigned long timeout
= 0x10000, val
;
50 mutex_lock(&ac97_mutex
);
52 val
= nuc900_checkready();
54 dev_err(nuc900_audio
->dev
, "AC97 codec is not ready\n");
58 /* set the R_WB bit and write register index */
59 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_ACOS1
, R_WB
| reg
);
61 /* set the valid frame bit and valid slots */
62 val
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_ACOS0
);
63 val
|= (VALID_FRAME
| SLOT1_VALID
);
64 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_ACOS0
, val
);
68 /* polling the AC_R_FINISH */
69 while (!(AUDIO_READ(nuc900_audio
->mmio
+ ACTL_ACCON
) & AC_R_FINISH
)
74 dev_err(nuc900_audio
->dev
, "AC97 read register time out !\n");
79 val
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_ACOS0
) ;
81 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_ACOS0
, val
);
83 if (AUDIO_READ(nuc900_audio
->mmio
+ ACTL_ACIS1
) >> 2 != reg
) {
84 dev_err(nuc900_audio
->dev
,
85 "R_INDEX of REG_ACTL_ACIS1 not match!\n");
89 val
= (AUDIO_READ(nuc900_audio
->mmio
+ ACTL_ACIS2
) & 0xFFFF);
92 mutex_unlock(&ac97_mutex
);
96 /* AC97 controller writes to codec register */
97 static void nuc900_ac97_write(struct snd_ac97
*ac97
, unsigned short reg
,
100 struct nuc900_audio
*nuc900_audio
= nuc900_ac97_data
;
101 unsigned long tmp
, timeout
= 0x10000;
103 mutex_lock(&ac97_mutex
);
105 tmp
= nuc900_checkready();
107 dev_err(nuc900_audio
->dev
, "AC97 codec is not ready\n");
109 /* clear the R_WB bit and write register index */
110 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_ACOS1
, reg
);
112 /* write register value */
113 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_ACOS2
, val
);
115 /* set the valid frame bit and valid slots */
116 tmp
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_ACOS0
);
117 tmp
|= SLOT1_VALID
| SLOT2_VALID
| VALID_FRAME
;
118 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_ACOS0
, tmp
);
122 /* polling the AC_W_FINISH */
123 while ((AUDIO_READ(nuc900_audio
->mmio
+ ACTL_ACCON
) & AC_W_FINISH
)
128 dev_err(nuc900_audio
->dev
, "AC97 write register time out !\n");
130 tmp
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_ACOS0
);
131 tmp
&= ~(SLOT1_VALID
| SLOT2_VALID
);
132 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_ACOS0
, tmp
);
134 mutex_unlock(&ac97_mutex
);
138 static void nuc900_ac97_warm_reset(struct snd_ac97
*ac97
)
140 struct nuc900_audio
*nuc900_audio
= nuc900_ac97_data
;
143 mutex_lock(&ac97_mutex
);
145 /* warm reset AC 97 */
146 val
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_ACCON
);
148 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_ACCON
, val
);
152 val
= nuc900_checkready();
154 dev_err(nuc900_audio
->dev
, "AC97 codec is not ready\n");
156 mutex_unlock(&ac97_mutex
);
159 static void nuc900_ac97_cold_reset(struct snd_ac97
*ac97
)
161 struct nuc900_audio
*nuc900_audio
= nuc900_ac97_data
;
164 mutex_lock(&ac97_mutex
);
166 /* reset Audio Controller */
167 val
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_RESET
);
168 val
|= ACTL_RESET_BIT
;
169 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_RESET
, val
);
171 val
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_RESET
);
172 val
&= (~ACTL_RESET_BIT
);
173 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_RESET
, val
);
175 /* reset AC-link interface */
177 val
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_RESET
);
179 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_RESET
, val
);
181 val
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_RESET
);
183 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_RESET
, val
);
185 /* cold reset AC 97 */
186 val
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_ACCON
);
188 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_ACCON
, val
);
190 val
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_ACCON
);
192 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_ACCON
, val
);
196 mutex_unlock(&ac97_mutex
);
200 /* AC97 controller operations */
201 static struct snd_ac97_bus_ops nuc900_ac97_ops
= {
202 .read
= nuc900_ac97_read
,
203 .write
= nuc900_ac97_write
,
204 .reset
= nuc900_ac97_cold_reset
,
205 .warm_reset
= nuc900_ac97_warm_reset
,
208 static int nuc900_ac97_trigger(struct snd_pcm_substream
*substream
,
209 int cmd
, struct snd_soc_dai
*dai
)
211 struct nuc900_audio
*nuc900_audio
= nuc900_ac97_data
;
213 unsigned long val
, tmp
;
218 case SNDRV_PCM_TRIGGER_START
:
219 case SNDRV_PCM_TRIGGER_RESUME
:
220 val
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_RESET
);
221 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
) {
222 tmp
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_ACOS0
);
223 tmp
|= (SLOT3_VALID
| SLOT4_VALID
| VALID_FRAME
);
224 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_ACOS0
, tmp
);
226 tmp
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_PSR
);
227 tmp
|= (P_DMA_END_IRQ
| P_DMA_MIDDLE_IRQ
);
228 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_PSR
, tmp
);
231 tmp
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_RSR
);
232 tmp
|= (R_DMA_END_IRQ
| R_DMA_MIDDLE_IRQ
);
234 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_RSR
, tmp
);
238 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_RESET
, val
);
241 case SNDRV_PCM_TRIGGER_STOP
:
242 case SNDRV_PCM_TRIGGER_SUSPEND
:
243 val
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_RESET
);
244 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
) {
245 tmp
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_ACOS0
);
246 tmp
&= ~(SLOT3_VALID
| SLOT4_VALID
);
247 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_ACOS0
, tmp
);
249 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_PSR
, RESET_PRSR
);
252 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_RSR
, RESET_PRSR
);
256 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_RESET
, val
);
266 static int nuc900_ac97_probe(struct snd_soc_dai
*dai
)
268 struct nuc900_audio
*nuc900_audio
= nuc900_ac97_data
;
271 mutex_lock(&ac97_mutex
);
273 /* enable unit clock */
274 clk_enable(nuc900_audio
->clk
);
276 /* enable audio controller and AC-link interface */
277 val
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_CON
);
278 val
|= (IIS_AC_PIN_SEL
| ACLINK_EN
);
279 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_CON
, val
);
281 mutex_unlock(&ac97_mutex
);
286 static int nuc900_ac97_remove(struct snd_soc_dai
*dai
)
288 struct nuc900_audio
*nuc900_audio
= nuc900_ac97_data
;
290 clk_disable(nuc900_audio
->clk
);
294 static const struct snd_soc_dai_ops nuc900_ac97_dai_ops
= {
295 .trigger
= nuc900_ac97_trigger
,
298 static struct snd_soc_dai_driver nuc900_ac97_dai
= {
299 .probe
= nuc900_ac97_probe
,
300 .remove
= nuc900_ac97_remove
,
303 .rates
= SNDRV_PCM_RATE_8000_48000
,
304 .formats
= SNDRV_PCM_FMTBIT_S16_LE
,
309 .rates
= SNDRV_PCM_RATE_8000_48000
,
310 .formats
= SNDRV_PCM_FMTBIT_S16_LE
,
314 .ops
= &nuc900_ac97_dai_ops
,
317 static const struct snd_soc_component_driver nuc900_ac97_component
= {
318 .name
= "nuc900-ac97",
321 static int nuc900_ac97_drvprobe(struct platform_device
*pdev
)
323 struct nuc900_audio
*nuc900_audio
;
326 if (nuc900_ac97_data
)
329 nuc900_audio
= devm_kzalloc(&pdev
->dev
, sizeof(struct nuc900_audio
),
334 spin_lock_init(&nuc900_audio
->lock
);
336 nuc900_audio
->res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
337 nuc900_audio
->mmio
= devm_ioremap_resource(&pdev
->dev
,
339 if (IS_ERR(nuc900_audio
->mmio
))
340 return PTR_ERR(nuc900_audio
->mmio
);
342 nuc900_audio
->clk
= devm_clk_get(&pdev
->dev
, NULL
);
343 if (IS_ERR(nuc900_audio
->clk
)) {
344 ret
= PTR_ERR(nuc900_audio
->clk
);
348 nuc900_audio
->irq_num
= platform_get_irq(pdev
, 0);
349 if (!nuc900_audio
->irq_num
) {
354 nuc900_ac97_data
= nuc900_audio
;
356 ret
= snd_soc_set_ac97_ops(&nuc900_ac97_ops
);
360 ret
= snd_soc_register_component(&pdev
->dev
, &nuc900_ac97_component
,
361 &nuc900_ac97_dai
, 1);
365 /* enbale ac97 multifunction pin */
366 mfp_set_groupg(nuc900_audio
->dev
, NULL
);
371 snd_soc_set_ac97_ops(NULL
);
375 static int nuc900_ac97_drvremove(struct platform_device
*pdev
)
377 snd_soc_unregister_component(&pdev
->dev
);
379 nuc900_ac97_data
= NULL
;
380 snd_soc_set_ac97_ops(NULL
);
385 static struct platform_driver nuc900_ac97_driver
= {
387 .name
= "nuc900-ac97",
389 .probe
= nuc900_ac97_drvprobe
,
390 .remove
= nuc900_ac97_drvremove
,
393 module_platform_driver(nuc900_ac97_driver
);
395 MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>");
396 MODULE_DESCRIPTION("NUC900 AC97 SoC driver!");
397 MODULE_LICENSE("GPL");
398 MODULE_ALIAS("platform:nuc900-ac97");