1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Au12x0/Au1550 PSC ALSA ASoC audio support. |
4 | * |
5 | * (c) 2007-2009 MSC Vertriebsges.m.b.H., |
6 | * Manuel Lauss <manuel.lauss@gmail.com> |
7 | * |
8 | * Au1xxx-PSC AC97 glue. |
9 | */ |
10 | |
11 | #include <linux/init.h> |
12 | #include <linux/module.h> |
13 | #include <linux/slab.h> |
14 | #include <linux/device.h> |
15 | #include <linux/delay.h> |
16 | #include <linux/mutex.h> |
17 | #include <linux/suspend.h> |
18 | #include <sound/core.h> |
19 | #include <sound/pcm.h> |
20 | #include <sound/initval.h> |
21 | #include <sound/soc.h> |
22 | #include <asm/mach-au1x00/au1000.h> |
23 | #include <asm/mach-au1x00/au1xxx_psc.h> |
24 | |
25 | #include "psc.h" |
26 | |
27 | /* how often to retry failed codec register reads/writes */ |
28 | #define AC97_RW_RETRIES 5 |
29 | |
30 | #define AC97_DIR \ |
31 | (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE) |
32 | |
33 | #define AC97_RATES \ |
34 | SNDRV_PCM_RATE_8000_48000 |
35 | |
36 | #define AC97_FMTS \ |
37 | (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3BE) |
38 | |
39 | #define AC97PCR_START(stype) \ |
40 | ((stype) == SNDRV_PCM_STREAM_PLAYBACK ? PSC_AC97PCR_TS : PSC_AC97PCR_RS) |
41 | #define AC97PCR_STOP(stype) \ |
42 | ((stype) == SNDRV_PCM_STREAM_PLAYBACK ? PSC_AC97PCR_TP : PSC_AC97PCR_RP) |
43 | #define AC97PCR_CLRFIFO(stype) \ |
44 | ((stype) == SNDRV_PCM_STREAM_PLAYBACK ? PSC_AC97PCR_TC : PSC_AC97PCR_RC) |
45 | |
46 | #define AC97STAT_BUSY(stype) \ |
47 | ((stype) == SNDRV_PCM_STREAM_PLAYBACK ? PSC_AC97STAT_TB : PSC_AC97STAT_RB) |
48 | |
49 | /* instance data. There can be only one, MacLeod!!!! */ |
50 | static struct au1xpsc_audio_data *au1xpsc_ac97_workdata; |
51 | |
52 | #if 0 |
53 | |
54 | /* this could theoretically work, but ac97->bus->card->private_data can be NULL |
55 | * when snd_ac97_mixer() is called; I don't know if the rest further down the |
56 | * chain are always valid either. |
57 | */ |
58 | static inline struct au1xpsc_audio_data *ac97_to_pscdata(struct snd_ac97 *x) |
59 | { |
60 | struct snd_soc_card *c = x->bus->card->private_data; |
61 | return snd_soc_dai_get_drvdata(c->snd_soc_rtd_to_cpu(rtd, 0)); |
62 | } |
63 | |
64 | #else |
65 | |
66 | #define ac97_to_pscdata(x) au1xpsc_ac97_workdata |
67 | |
68 | #endif |
69 | |
70 | /* AC97 controller reads codec register */ |
71 | static unsigned short au1xpsc_ac97_read(struct snd_ac97 *ac97, |
72 | unsigned short reg) |
73 | { |
74 | struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97); |
75 | unsigned short retry, tmo; |
76 | unsigned long data; |
77 | |
78 | __raw_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata)); |
79 | wmb(); /* drain writebuffer */ |
80 | |
81 | retry = AC97_RW_RETRIES; |
82 | do { |
83 | mutex_lock(&pscdata->lock); |
84 | |
85 | __raw_writel(PSC_AC97CDC_RD | PSC_AC97CDC_INDX(reg), |
86 | AC97_CDC(pscdata)); |
87 | wmb(); /* drain writebuffer */ |
88 | |
89 | tmo = 20; |
90 | do { |
91 | udelay(21); |
92 | if (__raw_readl(AC97_EVNT(pscdata)) & PSC_AC97EVNT_CD) |
93 | break; |
94 | } while (--tmo); |
95 | |
96 | data = __raw_readl(AC97_CDC(pscdata)); |
97 | |
98 | __raw_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata)); |
99 | wmb(); /* drain writebuffer */ |
100 | |
101 | mutex_unlock(lock: &pscdata->lock); |
102 | |
103 | if (reg != ((data >> 16) & 0x7f)) |
104 | tmo = 1; /* wrong register, try again */ |
105 | |
106 | } while (--retry && !tmo); |
107 | |
108 | return retry ? data & 0xffff : 0xffff; |
109 | } |
110 | |
111 | /* AC97 controller writes to codec register */ |
112 | static void au1xpsc_ac97_write(struct snd_ac97 *ac97, unsigned short reg, |
113 | unsigned short val) |
114 | { |
115 | struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97); |
116 | unsigned int tmo, retry; |
117 | |
118 | __raw_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata)); |
119 | wmb(); /* drain writebuffer */ |
120 | |
121 | retry = AC97_RW_RETRIES; |
122 | do { |
123 | mutex_lock(&pscdata->lock); |
124 | |
125 | __raw_writel(PSC_AC97CDC_INDX(reg) | (val & 0xffff), |
126 | AC97_CDC(pscdata)); |
127 | wmb(); /* drain writebuffer */ |
128 | |
129 | tmo = 20; |
130 | do { |
131 | udelay(21); |
132 | if (__raw_readl(AC97_EVNT(pscdata)) & PSC_AC97EVNT_CD) |
133 | break; |
134 | } while (--tmo); |
135 | |
136 | __raw_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata)); |
137 | wmb(); /* drain writebuffer */ |
138 | |
139 | mutex_unlock(lock: &pscdata->lock); |
140 | } while (--retry && !tmo); |
141 | } |
142 | |
143 | /* AC97 controller asserts a warm reset */ |
144 | static void au1xpsc_ac97_warm_reset(struct snd_ac97 *ac97) |
145 | { |
146 | struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97); |
147 | |
148 | __raw_writel(PSC_AC97RST_SNC, AC97_RST(pscdata)); |
149 | wmb(); /* drain writebuffer */ |
150 | msleep(msecs: 10); |
151 | __raw_writel(0, AC97_RST(pscdata)); |
152 | wmb(); /* drain writebuffer */ |
153 | } |
154 | |
155 | static void au1xpsc_ac97_cold_reset(struct snd_ac97 *ac97) |
156 | { |
157 | struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97); |
158 | int i; |
159 | |
160 | /* disable PSC during cold reset */ |
161 | __raw_writel(0, AC97_CFG(au1xpsc_ac97_workdata)); |
162 | wmb(); /* drain writebuffer */ |
163 | __raw_writel(PSC_CTRL_DISABLE, PSC_CTRL(pscdata)); |
164 | wmb(); /* drain writebuffer */ |
165 | |
166 | /* issue cold reset */ |
167 | __raw_writel(PSC_AC97RST_RST, AC97_RST(pscdata)); |
168 | wmb(); /* drain writebuffer */ |
169 | msleep(msecs: 500); |
170 | __raw_writel(0, AC97_RST(pscdata)); |
171 | wmb(); /* drain writebuffer */ |
172 | |
173 | /* enable PSC */ |
174 | __raw_writel(PSC_CTRL_ENABLE, PSC_CTRL(pscdata)); |
175 | wmb(); /* drain writebuffer */ |
176 | |
177 | /* wait for PSC to indicate it's ready */ |
178 | i = 1000; |
179 | while (!((__raw_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_SR)) && (--i)) |
180 | msleep(msecs: 1); |
181 | |
182 | if (i == 0) { |
183 | printk(KERN_ERR "au1xpsc-ac97: PSC not ready!\n" ); |
184 | return; |
185 | } |
186 | |
187 | /* enable the ac97 function */ |
188 | __raw_writel(pscdata->cfg | PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata)); |
189 | wmb(); /* drain writebuffer */ |
190 | |
191 | /* wait for AC97 core to become ready */ |
192 | i = 1000; |
193 | while (!((__raw_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_DR)) && (--i)) |
194 | msleep(msecs: 1); |
195 | if (i == 0) |
196 | printk(KERN_ERR "au1xpsc-ac97: AC97 ctrl not ready\n" ); |
197 | } |
198 | |
199 | /* AC97 controller operations */ |
200 | static struct snd_ac97_bus_ops psc_ac97_ops = { |
201 | .read = au1xpsc_ac97_read, |
202 | .write = au1xpsc_ac97_write, |
203 | .reset = au1xpsc_ac97_cold_reset, |
204 | .warm_reset = au1xpsc_ac97_warm_reset, |
205 | }; |
206 | |
207 | static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream, |
208 | struct snd_pcm_hw_params *params, |
209 | struct snd_soc_dai *dai) |
210 | { |
211 | struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai); |
212 | unsigned long r, ro, stat; |
213 | int chans, t, stype = substream->stream; |
214 | |
215 | chans = params_channels(p: params); |
216 | |
217 | r = ro = __raw_readl(AC97_CFG(pscdata)); |
218 | stat = __raw_readl(AC97_STAT(pscdata)); |
219 | |
220 | /* already active? */ |
221 | if (stat & (PSC_AC97STAT_TB | PSC_AC97STAT_RB)) { |
222 | /* reject parameters not currently set up */ |
223 | if ((PSC_AC97CFG_GET_LEN(r) != params->msbits) || |
224 | (pscdata->rate != params_rate(p: params))) |
225 | return -EINVAL; |
226 | } else { |
227 | |
228 | /* set sample bitdepth: REG[24:21]=(BITS-2)/2 */ |
229 | r &= ~PSC_AC97CFG_LEN_MASK; |
230 | r |= PSC_AC97CFG_SET_LEN(params->msbits); |
231 | |
232 | /* channels: enable slots for front L/R channel */ |
233 | if (stype == SNDRV_PCM_STREAM_PLAYBACK) { |
234 | r &= ~PSC_AC97CFG_TXSLOT_MASK; |
235 | r |= PSC_AC97CFG_TXSLOT_ENA(3); |
236 | r |= PSC_AC97CFG_TXSLOT_ENA(4); |
237 | } else { |
238 | r &= ~PSC_AC97CFG_RXSLOT_MASK; |
239 | r |= PSC_AC97CFG_RXSLOT_ENA(3); |
240 | r |= PSC_AC97CFG_RXSLOT_ENA(4); |
241 | } |
242 | |
243 | /* do we need to poke the hardware? */ |
244 | if (!(r ^ ro)) |
245 | goto out; |
246 | |
247 | /* ac97 engine is about to be disabled */ |
248 | mutex_lock(&pscdata->lock); |
249 | |
250 | /* disable AC97 device controller first... */ |
251 | __raw_writel(r & ~PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata)); |
252 | wmb(); /* drain writebuffer */ |
253 | |
254 | /* ...wait for it... */ |
255 | t = 100; |
256 | while ((__raw_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_DR) && --t) |
257 | msleep(msecs: 1); |
258 | |
259 | if (!t) |
260 | printk(KERN_ERR "PSC-AC97: can't disable!\n" ); |
261 | |
262 | /* ...write config... */ |
263 | __raw_writel(r, AC97_CFG(pscdata)); |
264 | wmb(); /* drain writebuffer */ |
265 | |
266 | /* ...enable the AC97 controller again... */ |
267 | __raw_writel(r | PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata)); |
268 | wmb(); /* drain writebuffer */ |
269 | |
270 | /* ...and wait for ready bit */ |
271 | t = 100; |
272 | while ((!(__raw_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_DR)) && --t) |
273 | msleep(msecs: 1); |
274 | |
275 | if (!t) |
276 | printk(KERN_ERR "PSC-AC97: can't enable!\n" ); |
277 | |
278 | mutex_unlock(lock: &pscdata->lock); |
279 | |
280 | pscdata->cfg = r; |
281 | pscdata->rate = params_rate(p: params); |
282 | } |
283 | |
284 | out: |
285 | return 0; |
286 | } |
287 | |
288 | static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream, |
289 | int cmd, struct snd_soc_dai *dai) |
290 | { |
291 | struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai); |
292 | int ret, stype = substream->stream; |
293 | |
294 | ret = 0; |
295 | |
296 | switch (cmd) { |
297 | case SNDRV_PCM_TRIGGER_START: |
298 | case SNDRV_PCM_TRIGGER_RESUME: |
299 | __raw_writel(AC97PCR_CLRFIFO(stype), AC97_PCR(pscdata)); |
300 | wmb(); /* drain writebuffer */ |
301 | __raw_writel(AC97PCR_START(stype), AC97_PCR(pscdata)); |
302 | wmb(); /* drain writebuffer */ |
303 | break; |
304 | case SNDRV_PCM_TRIGGER_STOP: |
305 | case SNDRV_PCM_TRIGGER_SUSPEND: |
306 | __raw_writel(AC97PCR_STOP(stype), AC97_PCR(pscdata)); |
307 | wmb(); /* drain writebuffer */ |
308 | |
309 | while (__raw_readl(AC97_STAT(pscdata)) & AC97STAT_BUSY(stype)) |
310 | asm volatile ("nop" ); |
311 | |
312 | __raw_writel(AC97PCR_CLRFIFO(stype), AC97_PCR(pscdata)); |
313 | wmb(); /* drain writebuffer */ |
314 | |
315 | break; |
316 | default: |
317 | ret = -EINVAL; |
318 | } |
319 | return ret; |
320 | } |
321 | |
322 | static int au1xpsc_ac97_startup(struct snd_pcm_substream *substream, |
323 | struct snd_soc_dai *dai) |
324 | { |
325 | struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai); |
326 | snd_soc_dai_set_dma_data(dai, substream, &pscdata->dmaids[0]); |
327 | return 0; |
328 | } |
329 | |
330 | static int au1xpsc_ac97_probe(struct snd_soc_dai *dai) |
331 | { |
332 | return au1xpsc_ac97_workdata ? 0 : -ENODEV; |
333 | } |
334 | |
335 | static const struct snd_soc_dai_ops au1xpsc_ac97_dai_ops = { |
336 | .probe = au1xpsc_ac97_probe, |
337 | .startup = au1xpsc_ac97_startup, |
338 | .trigger = au1xpsc_ac97_trigger, |
339 | .hw_params = au1xpsc_ac97_hw_params, |
340 | }; |
341 | |
342 | static const struct snd_soc_dai_driver au1xpsc_ac97_dai_template = { |
343 | .playback = { |
344 | .rates = AC97_RATES, |
345 | .formats = AC97_FMTS, |
346 | .channels_min = 2, |
347 | .channels_max = 2, |
348 | }, |
349 | .capture = { |
350 | .rates = AC97_RATES, |
351 | .formats = AC97_FMTS, |
352 | .channels_min = 2, |
353 | .channels_max = 2, |
354 | }, |
355 | .ops = &au1xpsc_ac97_dai_ops, |
356 | }; |
357 | |
358 | static const struct snd_soc_component_driver au1xpsc_ac97_component = { |
359 | .name = "au1xpsc-ac97" , |
360 | .legacy_dai_naming = 1, |
361 | }; |
362 | |
363 | static int au1xpsc_ac97_drvprobe(struct platform_device *pdev) |
364 | { |
365 | int ret; |
366 | struct resource *dmares; |
367 | unsigned long sel; |
368 | struct au1xpsc_audio_data *wd; |
369 | |
370 | wd = devm_kzalloc(dev: &pdev->dev, size: sizeof(struct au1xpsc_audio_data), |
371 | GFP_KERNEL); |
372 | if (!wd) |
373 | return -ENOMEM; |
374 | |
375 | mutex_init(&wd->lock); |
376 | |
377 | wd->mmio = devm_platform_ioremap_resource(pdev, index: 0); |
378 | if (IS_ERR(ptr: wd->mmio)) |
379 | return PTR_ERR(ptr: wd->mmio); |
380 | |
381 | dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0); |
382 | if (!dmares) |
383 | return -EBUSY; |
384 | wd->dmaids[SNDRV_PCM_STREAM_PLAYBACK] = dmares->start; |
385 | |
386 | dmares = platform_get_resource(pdev, IORESOURCE_DMA, 1); |
387 | if (!dmares) |
388 | return -EBUSY; |
389 | wd->dmaids[SNDRV_PCM_STREAM_CAPTURE] = dmares->start; |
390 | |
391 | /* configuration: max dma trigger threshold, enable ac97 */ |
392 | wd->cfg = PSC_AC97CFG_RT_FIFO8 | PSC_AC97CFG_TT_FIFO8 | |
393 | PSC_AC97CFG_DE_ENABLE; |
394 | |
395 | /* preserve PSC clock source set up by platform */ |
396 | sel = __raw_readl(PSC_SEL(wd)) & PSC_SEL_CLK_MASK; |
397 | __raw_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd)); |
398 | wmb(); /* drain writebuffer */ |
399 | __raw_writel(0, PSC_SEL(wd)); |
400 | wmb(); /* drain writebuffer */ |
401 | __raw_writel(PSC_SEL_PS_AC97MODE | sel, PSC_SEL(wd)); |
402 | wmb(); /* drain writebuffer */ |
403 | |
404 | /* name the DAI like this device instance ("au1xpsc-ac97.PSCINDEX") */ |
405 | memcpy(&wd->dai_drv, &au1xpsc_ac97_dai_template, |
406 | sizeof(struct snd_soc_dai_driver)); |
407 | wd->dai_drv.name = dev_name(dev: &pdev->dev); |
408 | |
409 | platform_set_drvdata(pdev, data: wd); |
410 | |
411 | ret = snd_soc_set_ac97_ops(ops: &psc_ac97_ops); |
412 | if (ret) |
413 | return ret; |
414 | |
415 | ret = snd_soc_register_component(dev: &pdev->dev, component_driver: &au1xpsc_ac97_component, |
416 | dai_drv: &wd->dai_drv, num_dai: 1); |
417 | if (ret) |
418 | return ret; |
419 | |
420 | au1xpsc_ac97_workdata = wd; |
421 | return 0; |
422 | } |
423 | |
424 | static void au1xpsc_ac97_drvremove(struct platform_device *pdev) |
425 | { |
426 | struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev); |
427 | |
428 | snd_soc_unregister_component(dev: &pdev->dev); |
429 | |
430 | /* disable PSC completely */ |
431 | __raw_writel(0, AC97_CFG(wd)); |
432 | wmb(); /* drain writebuffer */ |
433 | __raw_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd)); |
434 | wmb(); /* drain writebuffer */ |
435 | |
436 | au1xpsc_ac97_workdata = NULL; /* MDEV */ |
437 | } |
438 | |
439 | #ifdef CONFIG_PM |
440 | static int au1xpsc_ac97_drvsuspend(struct device *dev) |
441 | { |
442 | struct au1xpsc_audio_data *wd = dev_get_drvdata(dev); |
443 | |
444 | /* save interesting registers and disable PSC */ |
445 | wd->pm[0] = __raw_readl(PSC_SEL(wd)); |
446 | |
447 | __raw_writel(0, AC97_CFG(wd)); |
448 | wmb(); /* drain writebuffer */ |
449 | __raw_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd)); |
450 | wmb(); /* drain writebuffer */ |
451 | |
452 | return 0; |
453 | } |
454 | |
455 | static int au1xpsc_ac97_drvresume(struct device *dev) |
456 | { |
457 | struct au1xpsc_audio_data *wd = dev_get_drvdata(dev); |
458 | |
459 | /* restore PSC clock config */ |
460 | __raw_writel(wd->pm[0] | PSC_SEL_PS_AC97MODE, PSC_SEL(wd)); |
461 | wmb(); /* drain writebuffer */ |
462 | |
463 | /* after this point the ac97 core will cold-reset the codec. |
464 | * During cold-reset the PSC is reinitialized and the last |
465 | * configuration set up in hw_params() is restored. |
466 | */ |
467 | return 0; |
468 | } |
469 | |
470 | static const struct dev_pm_ops au1xpscac97_pmops = { |
471 | .suspend = au1xpsc_ac97_drvsuspend, |
472 | .resume = au1xpsc_ac97_drvresume, |
473 | }; |
474 | |
475 | #define AU1XPSCAC97_PMOPS &au1xpscac97_pmops |
476 | |
477 | #else |
478 | |
479 | #define AU1XPSCAC97_PMOPS NULL |
480 | |
481 | #endif |
482 | |
483 | static struct platform_driver au1xpsc_ac97_driver = { |
484 | .driver = { |
485 | .name = "au1xpsc_ac97" , |
486 | .pm = AU1XPSCAC97_PMOPS, |
487 | }, |
488 | .probe = au1xpsc_ac97_drvprobe, |
489 | .remove_new = au1xpsc_ac97_drvremove, |
490 | }; |
491 | |
492 | module_platform_driver(au1xpsc_ac97_driver); |
493 | |
494 | MODULE_LICENSE("GPL" ); |
495 | MODULE_DESCRIPTION("Au12x0/Au1550 PSC AC97 ALSA ASoC audio driver" ); |
496 | MODULE_AUTHOR("Manuel Lauss" ); |
497 | |
498 | |