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/device.h>
24 #include <linux/clk.h>
28 #include "nuc900-audio.h"
30 static DEFINE_MUTEX(ac97_mutex
);
31 struct nuc900_audio
*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 struct snd_ac97_bus_ops soc_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
,
207 EXPORT_SYMBOL_GPL(soc_ac97_ops
);
209 static int nuc900_ac97_trigger(struct snd_pcm_substream
*substream
,
210 int cmd
, struct snd_soc_dai
*dai
)
212 struct nuc900_audio
*nuc900_audio
= nuc900_ac97_data
;
214 unsigned long val
, tmp
;
219 case SNDRV_PCM_TRIGGER_START
:
220 case SNDRV_PCM_TRIGGER_RESUME
:
221 val
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_RESET
);
222 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
) {
223 tmp
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_ACOS0
);
224 tmp
|= (SLOT3_VALID
| SLOT4_VALID
| VALID_FRAME
);
225 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_ACOS0
, tmp
);
227 tmp
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_PSR
);
228 tmp
|= (P_DMA_END_IRQ
| P_DMA_MIDDLE_IRQ
);
229 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_PSR
, tmp
);
232 tmp
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_RSR
);
233 tmp
|= (R_DMA_END_IRQ
| R_DMA_MIDDLE_IRQ
);
235 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_RSR
, tmp
);
239 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_RESET
, val
);
242 case SNDRV_PCM_TRIGGER_STOP
:
243 case SNDRV_PCM_TRIGGER_SUSPEND
:
244 val
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_RESET
);
245 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
) {
246 tmp
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_ACOS0
);
247 tmp
&= ~(SLOT3_VALID
| SLOT4_VALID
);
248 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_ACOS0
, tmp
);
250 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_PSR
, RESET_PRSR
);
253 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_RSR
, RESET_PRSR
);
257 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_RESET
, val
);
267 static int nuc900_ac97_probe(struct platform_device
*pdev
,
268 struct snd_soc_dai
*dai
)
270 struct nuc900_audio
*nuc900_audio
= nuc900_ac97_data
;
273 mutex_lock(&ac97_mutex
);
275 /* enable unit clock */
276 clk_enable(nuc900_audio
->clk
);
278 /* enable audio controller and AC-link interface */
279 val
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_CON
);
280 val
|= (IIS_AC_PIN_SEL
| ACLINK_EN
);
281 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_CON
, val
);
283 mutex_unlock(&ac97_mutex
);
288 static void nuc900_ac97_remove(struct platform_device
*pdev
,
289 struct snd_soc_dai
*dai
)
291 struct nuc900_audio
*nuc900_audio
= nuc900_ac97_data
;
293 clk_disable(nuc900_audio
->clk
);
296 static struct snd_soc_dai_ops nuc900_ac97_dai_ops
= {
297 .trigger
= nuc900_ac97_trigger
,
300 static struct snd_soc_dai_driver nuc900_ac97_dai
= {
301 .probe
= nuc900_ac97_probe
,
302 .remove
= nuc900_ac97_remove
,
305 .rates
= SNDRV_PCM_RATE_8000_48000
,
306 .formats
= SNDRV_PCM_FMTBIT_S16_LE
,
311 .rates
= SNDRV_PCM_RATE_8000_48000
,
312 .formats
= SNDRV_PCM_FMTBIT_S16_LE
,
316 .ops
= &nuc900_ac97_dai_ops
,
319 static int __devinit
nuc900_ac97_drvprobe(struct platform_device
*pdev
)
321 struct nuc900_audio
*nuc900_audio
;
324 if (nuc900_ac97_data
)
327 nuc900_audio
= kzalloc(sizeof(struct nuc900_audio
), GFP_KERNEL
);
331 spin_lock_init(&nuc900_audio
->lock
);
333 nuc900_audio
->res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
334 if (!nuc900_audio
->res
) {
339 if (!request_mem_region(nuc900_audio
->res
->start
,
340 resource_size(nuc900_audio
->res
), pdev
->name
)) {
345 nuc900_audio
->mmio
= ioremap(nuc900_audio
->res
->start
,
346 resource_size(nuc900_audio
->res
));
347 if (!nuc900_audio
->mmio
) {
352 nuc900_audio
->clk
= clk_get(&pdev
->dev
, NULL
);
353 if (IS_ERR(nuc900_audio
->clk
)) {
354 ret
= PTR_ERR(nuc900_audio
->clk
);
358 nuc900_audio
->irq_num
= platform_get_irq(pdev
, 0);
359 if (!nuc900_audio
->irq_num
) {
364 nuc900_ac97_data
= nuc900_audio
;
366 ret
= snd_soc_register_dai(&pdev
->dev
, &nuc900_ac97_dai
);
370 mfp_set_groupg(nuc900_audio
->dev
); /* enbale ac97 multifunction pin*/
375 clk_put(nuc900_audio
->clk
);
377 iounmap(nuc900_audio
->mmio
);
379 release_mem_region(nuc900_audio
->res
->start
,
380 resource_size(nuc900_audio
->res
));
386 static int __devexit
nuc900_ac97_drvremove(struct platform_device
*pdev
)
389 snd_soc_unregister_dai(&pdev
->dev
);
391 clk_put(nuc900_ac97_data
->clk
);
392 iounmap(nuc900_ac97_data
->mmio
);
393 release_mem_region(nuc900_ac97_data
->res
->start
,
394 resource_size(nuc900_ac97_data
->res
));
396 nuc900_ac97_data
= NULL
;
401 static struct platform_driver nuc900_ac97_driver
= {
403 .name
= "nuc900-ac97",
404 .owner
= THIS_MODULE
,
406 .probe
= nuc900_ac97_drvprobe
,
407 .remove
= __devexit_p(nuc900_ac97_drvremove
),
410 static int __init
nuc900_ac97_init(void)
412 return platform_driver_register(&nuc900_ac97_driver
);
415 static void __exit
nuc900_ac97_exit(void)
417 platform_driver_unregister(&nuc900_ac97_driver
);
420 module_init(nuc900_ac97_init
);
421 module_exit(nuc900_ac97_exit
);
423 MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>");
424 MODULE_DESCRIPTION("NUC900 AC97 SoC driver!");
425 MODULE_LICENSE("GPL");
426 MODULE_ALIAS("platform:nuc900-ac97");