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
;
32 static int nuc900_checkready(void)
34 struct nuc900_audio
*nuc900_audio
= nuc900_ac97_data
;
36 if (!(AUDIO_READ(nuc900_audio
->mmio
+ ACTL_ACIS0
) & CODEC_READY
))
42 /* AC97 controller reads codec register */
43 static unsigned short nuc900_ac97_read(struct snd_ac97
*ac97
,
46 struct nuc900_audio
*nuc900_audio
= nuc900_ac97_data
;
47 unsigned long timeout
= 0x10000, val
;
49 mutex_lock(&ac97_mutex
);
51 val
= nuc900_checkready();
53 dev_err(nuc900_audio
->dev
, "AC97 codec is not ready\n");
57 /* set the R_WB bit and write register index */
58 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_ACOS1
, R_WB
| reg
);
60 /* set the valid frame bit and valid slots */
61 val
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_ACOS0
);
62 val
|= (VALID_FRAME
| SLOT1_VALID
);
63 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_ACOS0
, val
);
67 /* polling the AC_R_FINISH */
68 while (!(AUDIO_READ(nuc900_audio
->mmio
+ ACTL_ACCON
) & AC_R_FINISH
)
73 dev_err(nuc900_audio
->dev
, "AC97 read register time out !\n");
78 val
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_ACOS0
) ;
80 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_ACOS0
, val
);
82 if (AUDIO_READ(nuc900_audio
->mmio
+ ACTL_ACIS1
) >> 2 != reg
) {
83 dev_err(nuc900_audio
->dev
,
84 "R_INDEX of REG_ACTL_ACIS1 not match!\n");
88 val
= (AUDIO_READ(nuc900_audio
->mmio
+ ACTL_ACIS2
) & 0xFFFF);
91 mutex_unlock(&ac97_mutex
);
95 /* AC97 controller writes to codec register */
96 static void nuc900_ac97_write(struct snd_ac97
*ac97
, unsigned short reg
,
99 struct nuc900_audio
*nuc900_audio
= nuc900_ac97_data
;
100 unsigned long tmp
, timeout
= 0x10000;
102 mutex_lock(&ac97_mutex
);
104 tmp
= nuc900_checkready();
106 dev_err(nuc900_audio
->dev
, "AC97 codec is not ready\n");
108 /* clear the R_WB bit and write register index */
109 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_ACOS1
, reg
);
111 /* write register value */
112 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_ACOS2
, val
);
114 /* set the valid frame bit and valid slots */
115 tmp
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_ACOS0
);
116 tmp
|= SLOT1_VALID
| SLOT2_VALID
| VALID_FRAME
;
117 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_ACOS0
, tmp
);
121 /* polling the AC_W_FINISH */
122 while ((AUDIO_READ(nuc900_audio
->mmio
+ ACTL_ACCON
) & AC_W_FINISH
)
127 dev_err(nuc900_audio
->dev
, "AC97 write register time out !\n");
129 tmp
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_ACOS0
);
130 tmp
&= ~(SLOT1_VALID
| SLOT2_VALID
);
131 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_ACOS0
, tmp
);
133 mutex_unlock(&ac97_mutex
);
137 static void nuc900_ac97_warm_reset(struct snd_ac97
*ac97
)
139 struct nuc900_audio
*nuc900_audio
= nuc900_ac97_data
;
142 mutex_lock(&ac97_mutex
);
144 /* warm reset AC 97 */
145 val
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_ACCON
);
147 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_ACCON
, val
);
151 val
= nuc900_checkready();
153 dev_err(nuc900_audio
->dev
, "AC97 codec is not ready\n");
155 mutex_unlock(&ac97_mutex
);
158 static void nuc900_ac97_cold_reset(struct snd_ac97
*ac97
)
160 struct nuc900_audio
*nuc900_audio
= nuc900_ac97_data
;
163 mutex_lock(&ac97_mutex
);
165 /* reset Audio Controller */
166 val
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_RESET
);
167 val
|= ACTL_RESET_BIT
;
168 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_RESET
, val
);
170 val
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_RESET
);
171 val
&= (~ACTL_RESET_BIT
);
172 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_RESET
, val
);
174 /* reset AC-link interface */
176 val
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_RESET
);
178 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_RESET
, val
);
180 val
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_RESET
);
182 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_RESET
, val
);
184 /* cold reset AC 97 */
185 val
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_ACCON
);
187 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_ACCON
, val
);
189 val
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_ACCON
);
191 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_ACCON
, val
);
195 mutex_unlock(&ac97_mutex
);
199 /* AC97 controller operations */
200 struct snd_ac97_bus_ops soc_ac97_ops
= {
201 .read
= nuc900_ac97_read
,
202 .write
= nuc900_ac97_write
,
203 .reset
= nuc900_ac97_cold_reset
,
204 .warm_reset
= nuc900_ac97_warm_reset
,
206 EXPORT_SYMBOL_GPL(soc_ac97_ops
);
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 int __devinit
nuc900_ac97_drvprobe(struct platform_device
*pdev
)
319 struct nuc900_audio
*nuc900_audio
;
322 if (nuc900_ac97_data
)
325 nuc900_audio
= kzalloc(sizeof(struct nuc900_audio
), GFP_KERNEL
);
329 spin_lock_init(&nuc900_audio
->lock
);
331 nuc900_audio
->res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
332 if (!nuc900_audio
->res
) {
337 if (!request_mem_region(nuc900_audio
->res
->start
,
338 resource_size(nuc900_audio
->res
), pdev
->name
)) {
343 nuc900_audio
->mmio
= ioremap(nuc900_audio
->res
->start
,
344 resource_size(nuc900_audio
->res
));
345 if (!nuc900_audio
->mmio
) {
350 nuc900_audio
->clk
= clk_get(&pdev
->dev
, NULL
);
351 if (IS_ERR(nuc900_audio
->clk
)) {
352 ret
= PTR_ERR(nuc900_audio
->clk
);
356 nuc900_audio
->irq_num
= platform_get_irq(pdev
, 0);
357 if (!nuc900_audio
->irq_num
) {
362 nuc900_ac97_data
= nuc900_audio
;
364 ret
= snd_soc_register_dai(&pdev
->dev
, &nuc900_ac97_dai
);
368 /* enbale ac97 multifunction pin */
369 mfp_set_groupg(nuc900_audio
->dev
, NULL
);
374 clk_put(nuc900_audio
->clk
);
376 iounmap(nuc900_audio
->mmio
);
378 release_mem_region(nuc900_audio
->res
->start
,
379 resource_size(nuc900_audio
->res
));
385 static int __devexit
nuc900_ac97_drvremove(struct platform_device
*pdev
)
387 snd_soc_unregister_dai(&pdev
->dev
);
389 clk_put(nuc900_ac97_data
->clk
);
390 iounmap(nuc900_ac97_data
->mmio
);
391 release_mem_region(nuc900_ac97_data
->res
->start
,
392 resource_size(nuc900_ac97_data
->res
));
394 kfree(nuc900_ac97_data
);
395 nuc900_ac97_data
= NULL
;
400 static struct platform_driver nuc900_ac97_driver
= {
402 .name
= "nuc900-ac97",
403 .owner
= THIS_MODULE
,
405 .probe
= nuc900_ac97_drvprobe
,
406 .remove
= __devexit_p(nuc900_ac97_drvremove
),
409 module_platform_driver(nuc900_ac97_driver
);
411 MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>");
412 MODULE_DESCRIPTION("NUC900 AC97 SoC driver!");
413 MODULE_LICENSE("GPL");
414 MODULE_ALIAS("platform:nuc900-ac97");