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 static struct snd_ac97_bus_ops nuc900_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
,
207 static int nuc900_ac97_trigger(struct snd_pcm_substream
*substream
,
208 int cmd
, struct snd_soc_dai
*dai
)
210 struct nuc900_audio
*nuc900_audio
= nuc900_ac97_data
;
212 unsigned long val
, tmp
;
217 case SNDRV_PCM_TRIGGER_START
:
218 case SNDRV_PCM_TRIGGER_RESUME
:
219 val
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_RESET
);
220 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
) {
221 tmp
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_ACOS0
);
222 tmp
|= (SLOT3_VALID
| SLOT4_VALID
| VALID_FRAME
);
223 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_ACOS0
, tmp
);
225 tmp
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_PSR
);
226 tmp
|= (P_DMA_END_IRQ
| P_DMA_MIDDLE_IRQ
);
227 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_PSR
, tmp
);
230 tmp
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_RSR
);
231 tmp
|= (R_DMA_END_IRQ
| R_DMA_MIDDLE_IRQ
);
233 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_RSR
, tmp
);
237 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_RESET
, val
);
240 case SNDRV_PCM_TRIGGER_STOP
:
241 case SNDRV_PCM_TRIGGER_SUSPEND
:
242 val
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_RESET
);
243 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
) {
244 tmp
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_ACOS0
);
245 tmp
&= ~(SLOT3_VALID
| SLOT4_VALID
);
246 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_ACOS0
, tmp
);
248 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_PSR
, RESET_PRSR
);
251 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_RSR
, RESET_PRSR
);
255 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_RESET
, val
);
265 static int nuc900_ac97_probe(struct snd_soc_dai
*dai
)
267 struct nuc900_audio
*nuc900_audio
= nuc900_ac97_data
;
270 mutex_lock(&ac97_mutex
);
272 /* enable unit clock */
273 clk_enable(nuc900_audio
->clk
);
275 /* enable audio controller and AC-link interface */
276 val
= AUDIO_READ(nuc900_audio
->mmio
+ ACTL_CON
);
277 val
|= (IIS_AC_PIN_SEL
| ACLINK_EN
);
278 AUDIO_WRITE(nuc900_audio
->mmio
+ ACTL_CON
, val
);
280 mutex_unlock(&ac97_mutex
);
285 static int nuc900_ac97_remove(struct snd_soc_dai
*dai
)
287 struct nuc900_audio
*nuc900_audio
= nuc900_ac97_data
;
289 clk_disable(nuc900_audio
->clk
);
293 static const struct snd_soc_dai_ops nuc900_ac97_dai_ops
= {
294 .trigger
= nuc900_ac97_trigger
,
297 static struct snd_soc_dai_driver nuc900_ac97_dai
= {
298 .probe
= nuc900_ac97_probe
,
299 .remove
= nuc900_ac97_remove
,
302 .rates
= SNDRV_PCM_RATE_8000_48000
,
303 .formats
= SNDRV_PCM_FMTBIT_S16_LE
,
308 .rates
= SNDRV_PCM_RATE_8000_48000
,
309 .formats
= SNDRV_PCM_FMTBIT_S16_LE
,
313 .ops
= &nuc900_ac97_dai_ops
,
316 static const struct snd_soc_component_driver nuc900_ac97_component
= {
317 .name
= "nuc900-ac97",
320 static int nuc900_ac97_drvprobe(struct platform_device
*pdev
)
322 struct nuc900_audio
*nuc900_audio
;
325 if (nuc900_ac97_data
)
328 nuc900_audio
= devm_kzalloc(&pdev
->dev
, sizeof(struct nuc900_audio
),
333 spin_lock_init(&nuc900_audio
->lock
);
335 nuc900_audio
->res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
336 nuc900_audio
->mmio
= devm_ioremap_resource(&pdev
->dev
,
338 if (IS_ERR(nuc900_audio
->mmio
))
339 return PTR_ERR(nuc900_audio
->mmio
);
341 nuc900_audio
->clk
= devm_clk_get(&pdev
->dev
, NULL
);
342 if (IS_ERR(nuc900_audio
->clk
)) {
343 ret
= PTR_ERR(nuc900_audio
->clk
);
347 nuc900_audio
->irq_num
= platform_get_irq(pdev
, 0);
348 if (!nuc900_audio
->irq_num
) {
353 nuc900_ac97_data
= nuc900_audio
;
355 ret
= snd_soc_set_ac97_ops(&nuc900_ac97_ops
);
359 ret
= snd_soc_register_component(&pdev
->dev
, &nuc900_ac97_component
,
360 &nuc900_ac97_dai
, 1);
364 /* enbale ac97 multifunction pin */
365 mfp_set_groupg(nuc900_audio
->dev
, NULL
);
370 snd_soc_set_ac97_ops(NULL
);
374 static int nuc900_ac97_drvremove(struct platform_device
*pdev
)
376 snd_soc_unregister_component(&pdev
->dev
);
378 nuc900_ac97_data
= NULL
;
379 snd_soc_set_ac97_ops(NULL
);
384 static struct platform_driver nuc900_ac97_driver
= {
386 .name
= "nuc900-ac97",
387 .owner
= THIS_MODULE
,
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");