ASoC: Staticise workqueue function for GPIO jack detection
[deliverable/linux.git] / sound / soc / s3c24xx / s3c-i2s-v2.c
CommitLineData
dc85447b
BD
1/* sound/soc/s3c24xx/s3c-i2c-v2.c
2 *
3 * ALSA Soc Audio Layer - I2S core for newer Samsung SoCs.
4 *
5 * Copyright (c) 2006 Wolfson Microelectronics PLC.
6 * Graeme Gregory graeme.gregory@wolfsonmicro.com
7 * linux@wolfsonmicro.com
8 *
9 * Copyright (c) 2008, 2007, 2004-2005 Simtec Electronics
10 * http://armlinux.simtec.co.uk/
11 * Ben Dooks <ben@simtec.co.uk>
12 *
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2 of the License, or (at your
16 * option) any later version.
17 */
18
19#include <linux/init.h>
20#include <linux/module.h>
21#include <linux/device.h>
22#include <linux/delay.h>
23#include <linux/clk.h>
24#include <linux/kernel.h>
25#include <linux/io.h>
26
27#include <sound/core.h>
28#include <sound/pcm.h>
29#include <sound/pcm_params.h>
30#include <sound/initval.h>
31#include <sound/soc.h>
32
33#include <plat/regs-s3c2412-iis.h>
34
35#include <plat/audio.h>
36#include <mach/dma.h>
37
38#include "s3c-i2s-v2.h"
39
40#define S3C2412_I2S_DEBUG_CON 0
41#define S3C2412_I2S_DEBUG 0
42
43#if S3C2412_I2S_DEBUG
44#define DBG(x...) printk(KERN_INFO x)
45#else
46#define DBG(x...) do { } while (0)
47#endif
48
49static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
50{
51 return cpu_dai->private_data;
52}
53
54#define bit_set(v, b) (((v) & (b)) ? 1 : 0)
55
56#if S3C2412_I2S_DEBUG_CON
57static void dbg_showcon(const char *fn, u32 con)
58{
59 printk(KERN_DEBUG "%s: LRI=%d, TXFEMPT=%d, RXFEMPT=%d, TXFFULL=%d, RXFFULL=%d\n", fn,
60 bit_set(con, S3C2412_IISCON_LRINDEX),
61 bit_set(con, S3C2412_IISCON_TXFIFO_EMPTY),
62 bit_set(con, S3C2412_IISCON_RXFIFO_EMPTY),
63 bit_set(con, S3C2412_IISCON_TXFIFO_FULL),
64 bit_set(con, S3C2412_IISCON_RXFIFO_FULL));
65
66 printk(KERN_DEBUG "%s: PAUSE: TXDMA=%d, RXDMA=%d, TXCH=%d, RXCH=%d\n",
67 fn,
68 bit_set(con, S3C2412_IISCON_TXDMA_PAUSE),
69 bit_set(con, S3C2412_IISCON_RXDMA_PAUSE),
70 bit_set(con, S3C2412_IISCON_TXCH_PAUSE),
71 bit_set(con, S3C2412_IISCON_RXCH_PAUSE));
72 printk(KERN_DEBUG "%s: ACTIVE: TXDMA=%d, RXDMA=%d, IIS=%d\n", fn,
73 bit_set(con, S3C2412_IISCON_TXDMA_ACTIVE),
74 bit_set(con, S3C2412_IISCON_RXDMA_ACTIVE),
75 bit_set(con, S3C2412_IISCON_IIS_ACTIVE));
76}
77#else
78static inline void dbg_showcon(const char *fn, u32 con)
79{
80}
81#endif
82
83
84/* Turn on or off the transmission path. */
85void s3c2412_snd_txctrl(struct s3c_i2sv2_info *i2s, int on)
86{
87 void __iomem *regs = i2s->regs;
88 u32 fic, con, mod;
89
90 DBG("%s(%d)\n", __func__, on);
91
92 fic = readl(regs + S3C2412_IISFIC);
93 con = readl(regs + S3C2412_IISCON);
94 mod = readl(regs + S3C2412_IISMOD);
95
96 DBG("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
97
98 if (on) {
99 con |= S3C2412_IISCON_TXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE;
100 con &= ~S3C2412_IISCON_TXDMA_PAUSE;
101 con &= ~S3C2412_IISCON_TXCH_PAUSE;
102
103 switch (mod & S3C2412_IISMOD_MODE_MASK) {
104 case S3C2412_IISMOD_MODE_TXONLY:
105 case S3C2412_IISMOD_MODE_TXRX:
106 /* do nothing, we are in the right mode */
107 break;
108
109 case S3C2412_IISMOD_MODE_RXONLY:
110 mod &= ~S3C2412_IISMOD_MODE_MASK;
111 mod |= S3C2412_IISMOD_MODE_TXRX;
112 break;
113
114 default:
115 dev_err(i2s->dev, "TXEN: Invalid MODE in IISMOD\n");
116 }
117
118 writel(con, regs + S3C2412_IISCON);
119 writel(mod, regs + S3C2412_IISMOD);
120 } else {
121 /* Note, we do not have any indication that the FIFO problems
122 * tha the S3C2410/2440 had apply here, so we should be able
123 * to disable the DMA and TX without resetting the FIFOS.
124 */
125
126 con |= S3C2412_IISCON_TXDMA_PAUSE;
127 con |= S3C2412_IISCON_TXCH_PAUSE;
128 con &= ~S3C2412_IISCON_TXDMA_ACTIVE;
129
130 switch (mod & S3C2412_IISMOD_MODE_MASK) {
131 case S3C2412_IISMOD_MODE_TXRX:
132 mod &= ~S3C2412_IISMOD_MODE_MASK;
133 mod |= S3C2412_IISMOD_MODE_RXONLY;
134 break;
135
136 case S3C2412_IISMOD_MODE_TXONLY:
137 mod &= ~S3C2412_IISMOD_MODE_MASK;
138 con &= ~S3C2412_IISCON_IIS_ACTIVE;
139 break;
140
141 default:
142 dev_err(i2s->dev, "TXDIS: Invalid MODE in IISMOD\n");
143 }
144
145 writel(mod, regs + S3C2412_IISMOD);
146 writel(con, regs + S3C2412_IISCON);
147 }
148
149 fic = readl(regs + S3C2412_IISFIC);
150 dbg_showcon(__func__, con);
151 DBG("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
152}
153EXPORT_SYMBOL_GPL(s3c2412_snd_txctrl);
154
155void s3c2412_snd_rxctrl(struct s3c_i2sv2_info *i2s, int on)
156{
157 void __iomem *regs = i2s->regs;
158 u32 fic, con, mod;
159
160 DBG("%s(%d)\n", __func__, on);
161
162 fic = readl(regs + S3C2412_IISFIC);
163 con = readl(regs + S3C2412_IISCON);
164 mod = readl(regs + S3C2412_IISMOD);
165
166 DBG("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
167
168 if (on) {
169 con |= S3C2412_IISCON_RXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE;
170 con &= ~S3C2412_IISCON_RXDMA_PAUSE;
171 con &= ~S3C2412_IISCON_RXCH_PAUSE;
172
173 switch (mod & S3C2412_IISMOD_MODE_MASK) {
174 case S3C2412_IISMOD_MODE_TXRX:
175 case S3C2412_IISMOD_MODE_RXONLY:
176 /* do nothing, we are in the right mode */
177 break;
178
179 case S3C2412_IISMOD_MODE_TXONLY:
180 mod &= ~S3C2412_IISMOD_MODE_MASK;
181 mod |= S3C2412_IISMOD_MODE_TXRX;
182 break;
183
184 default:
185 dev_err(i2s->dev, "RXEN: Invalid MODE in IISMOD\n");
186 }
187
188 writel(mod, regs + S3C2412_IISMOD);
189 writel(con, regs + S3C2412_IISCON);
190 } else {
191 /* See txctrl notes on FIFOs. */
192
193 con &= ~S3C2412_IISCON_RXDMA_ACTIVE;
194 con |= S3C2412_IISCON_RXDMA_PAUSE;
195 con |= S3C2412_IISCON_RXCH_PAUSE;
196
197 switch (mod & S3C2412_IISMOD_MODE_MASK) {
198 case S3C2412_IISMOD_MODE_RXONLY:
199 con &= ~S3C2412_IISCON_IIS_ACTIVE;
200 mod &= ~S3C2412_IISMOD_MODE_MASK;
201 break;
202
203 case S3C2412_IISMOD_MODE_TXRX:
204 mod &= ~S3C2412_IISMOD_MODE_MASK;
205 mod |= S3C2412_IISMOD_MODE_TXONLY;
206 break;
207
208 default:
209 dev_err(i2s->dev, "RXEN: Invalid MODE in IISMOD\n");
210 }
211
212 writel(con, regs + S3C2412_IISCON);
213 writel(mod, regs + S3C2412_IISMOD);
214 }
215
216 fic = readl(regs + S3C2412_IISFIC);
217 DBG("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
218}
219EXPORT_SYMBOL_GPL(s3c2412_snd_rxctrl);
220
221/*
222 * Wait for the LR signal to allow synchronisation to the L/R clock
223 * from the codec. May only be needed for slave mode.
224 */
225static int s3c2412_snd_lrsync(struct s3c_i2sv2_info *i2s)
226{
227 u32 iiscon;
228 unsigned long timeout = jiffies + msecs_to_jiffies(5);
229
230 DBG("Entered %s\n", __func__);
231
232 while (1) {
233 iiscon = readl(i2s->regs + S3C2412_IISCON);
234 if (iiscon & S3C2412_IISCON_LRINDEX)
235 break;
236
237 if (timeout < jiffies) {
238 printk(KERN_ERR "%s: timeout\n", __func__);
239 return -ETIMEDOUT;
240 }
241 }
242
243 return 0;
244}
245
246/*
247 * Set S3C2412 I2S DAI format
248 */
249static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
250 unsigned int fmt)
251{
252 struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
253 u32 iismod;
254
255 DBG("Entered %s\n", __func__);
256
257 iismod = readl(i2s->regs + S3C2412_IISMOD);
258 DBG("hw_params r: IISMOD: %x \n", iismod);
259
260#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413)
261#define IISMOD_MASTER_MASK S3C2412_IISMOD_MASTER_MASK
262#define IISMOD_SLAVE S3C2412_IISMOD_SLAVE
263#define IISMOD_MASTER S3C2412_IISMOD_MASTER_INTERNAL
264#endif
265
266#if defined(CONFIG_PLAT_S3C64XX)
267/* From Rev1.1 datasheet, we have two master and two slave modes:
268 * IMS[11:10]:
269 * 00 = master mode, fed from PCLK
270 * 01 = master mode, fed from CLKAUDIO
271 * 10 = slave mode, using PCLK
272 * 11 = slave mode, using I2SCLK
273 */
274#define IISMOD_MASTER_MASK (1 << 11)
275#define IISMOD_SLAVE (1 << 11)
276#define IISMOD_MASTER (0x0)
277#endif
278
279 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
280 case SND_SOC_DAIFMT_CBM_CFM:
281 i2s->master = 0;
282 iismod &= ~IISMOD_MASTER_MASK;
283 iismod |= IISMOD_SLAVE;
284 break;
285 case SND_SOC_DAIFMT_CBS_CFS:
286 i2s->master = 1;
287 iismod &= ~IISMOD_MASTER_MASK;
288 iismod |= IISMOD_MASTER;
289 break;
290 default:
291 DBG("unknwon master/slave format\n");
292 return -EINVAL;
293 }
294
295 iismod &= ~S3C2412_IISMOD_SDF_MASK;
296
297 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
298 case SND_SOC_DAIFMT_RIGHT_J:
299 iismod |= S3C2412_IISMOD_SDF_MSB;
300 break;
301 case SND_SOC_DAIFMT_LEFT_J:
302 iismod |= S3C2412_IISMOD_SDF_LSB;
303 break;
304 case SND_SOC_DAIFMT_I2S:
305 iismod |= S3C2412_IISMOD_SDF_IIS;
306 break;
307 default:
308 DBG("Unknown data format\n");
309 return -EINVAL;
310 }
311
312 writel(iismod, i2s->regs + S3C2412_IISMOD);
313 DBG("hw_params w: IISMOD: %x \n", iismod);
314 return 0;
315}
316
317static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream,
318 struct snd_pcm_hw_params *params,
319 struct snd_soc_dai *socdai)
320{
321 struct snd_soc_pcm_runtime *rtd = substream->private_data;
322 struct snd_soc_dai_link *dai = rtd->dai;
323 struct s3c_i2sv2_info *i2s = to_info(dai->cpu_dai);
324 u32 iismod;
325
326 DBG("Entered %s\n", __func__);
327
328 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
329 dai->cpu_dai->dma_data = i2s->dma_playback;
330 else
331 dai->cpu_dai->dma_data = i2s->dma_capture;
332
333 /* Working copies of register */
334 iismod = readl(i2s->regs + S3C2412_IISMOD);
335 DBG("%s: r: IISMOD: %x\n", __func__, iismod);
336
337 switch (params_format(params)) {
338 case SNDRV_PCM_FORMAT_S8:
339 iismod |= S3C2412_IISMOD_8BIT;
340 break;
341 case SNDRV_PCM_FORMAT_S16_LE:
342 iismod &= ~S3C2412_IISMOD_8BIT;
343 break;
344 }
345
346 writel(iismod, i2s->regs + S3C2412_IISMOD);
347 DBG("%s: w: IISMOD: %x\n", __func__, iismod);
348 return 0;
349}
350
351static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
352 struct snd_soc_dai *dai)
353{
354 struct snd_soc_pcm_runtime *rtd = substream->private_data;
355 struct s3c_i2sv2_info *i2s = to_info(rtd->dai->cpu_dai);
356 int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
357 unsigned long irqs;
358 int ret = 0;
359
360 DBG("Entered %s\n", __func__);
361
362 switch (cmd) {
363 case SNDRV_PCM_TRIGGER_START:
364 /* On start, ensure that the FIFOs are cleared and reset. */
365
366 writel(capture ? S3C2412_IISFIC_RXFLUSH : S3C2412_IISFIC_TXFLUSH,
367 i2s->regs + S3C2412_IISFIC);
368
369 /* clear again, just in case */
370 writel(0x0, i2s->regs + S3C2412_IISFIC);
371
372 case SNDRV_PCM_TRIGGER_RESUME:
373 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
374 if (!i2s->master) {
375 ret = s3c2412_snd_lrsync(i2s);
376 if (ret)
377 goto exit_err;
378 }
379
380 local_irq_save(irqs);
381
382 if (capture)
383 s3c2412_snd_rxctrl(i2s, 1);
384 else
385 s3c2412_snd_txctrl(i2s, 1);
386
387 local_irq_restore(irqs);
388 break;
389
390 case SNDRV_PCM_TRIGGER_STOP:
391 case SNDRV_PCM_TRIGGER_SUSPEND:
392 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
393 local_irq_save(irqs);
394
395 if (capture)
396 s3c2412_snd_rxctrl(i2s, 0);
397 else
398 s3c2412_snd_txctrl(i2s, 0);
399
400 local_irq_restore(irqs);
401 break;
402 default:
403 ret = -EINVAL;
404 break;
405 }
406
407exit_err:
408 return ret;
409}
410
411/*
412 * Set S3C2412 Clock dividers
413 */
414static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
415 int div_id, int div)
416{
417 struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
418 u32 reg;
419
420 DBG("%s(%p, %d, %d)\n", __func__, cpu_dai, div_id, div);
421
422 switch (div_id) {
423 case S3C_I2SV2_DIV_BCLK:
424 reg = readl(i2s->regs + S3C2412_IISMOD);
425 reg &= ~S3C2412_IISMOD_BCLK_MASK;
426 writel(reg | div, i2s->regs + S3C2412_IISMOD);
427
428 DBG("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD));
429 break;
430
431 case S3C_I2SV2_DIV_RCLK:
432 if (div > 3) {
433 /* convert value to bit field */
434
435 switch (div) {
436 case 256:
437 div = S3C2412_IISMOD_RCLK_256FS;
438 break;
439
440 case 384:
441 div = S3C2412_IISMOD_RCLK_384FS;
442 break;
443
444 case 512:
445 div = S3C2412_IISMOD_RCLK_512FS;
446 break;
447
448 case 768:
449 div = S3C2412_IISMOD_RCLK_768FS;
450 break;
451
452 default:
453 return -EINVAL;
454 }
455 }
456
457 reg = readl(i2s->regs + S3C2412_IISMOD);
458 reg &= ~S3C2412_IISMOD_RCLK_MASK;
459 writel(reg | div, i2s->regs + S3C2412_IISMOD);
460 DBG("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD));
461 break;
462
463 case S3C_I2SV2_DIV_PRESCALER:
464 if (div >= 0) {
465 writel((div << 8) | S3C2412_IISPSR_PSREN,
466 i2s->regs + S3C2412_IISPSR);
467 } else {
468 writel(0x0, i2s->regs + S3C2412_IISPSR);
469 }
470 DBG("%s: PSR=%08x\n", __func__, readl(i2s->regs + S3C2412_IISPSR));
471 break;
472
473 default:
474 return -EINVAL;
475 }
476
477 return 0;
478}
479
480/* default table of all avaialable root fs divisors */
481static unsigned int iis_fs_tab[] = { 256, 512, 384, 768 };
482
483int s3c2412_iis_calc_rate(struct s3c_i2sv2_rate_calc *info,
484 unsigned int *fstab,
485 unsigned int rate, struct clk *clk)
486{
487 unsigned long clkrate = clk_get_rate(clk);
488 unsigned int div;
489 unsigned int fsclk;
490 unsigned int actual;
491 unsigned int fs;
492 unsigned int fsdiv;
493 signed int deviation = 0;
494 unsigned int best_fs = 0;
495 unsigned int best_div = 0;
496 unsigned int best_rate = 0;
497 unsigned int best_deviation = INT_MAX;
498
499 if (fstab == NULL)
500 fstab = iis_fs_tab;
501
502 for (fs = 0; fs < ARRAY_SIZE(iis_fs_tab); fs++) {
503 fsdiv = iis_fs_tab[fs];
504
505 fsclk = clkrate / fsdiv;
506 div = fsclk / rate;
507
508 if ((fsclk % rate) > (rate / 2))
509 div++;
510
511 if (div <= 1)
512 continue;
513
514 actual = clkrate / (fsdiv * div);
515 deviation = actual - rate;
516
517 printk(KERN_DEBUG "%dfs: div %d => result %d, deviation %d\n",
518 fsdiv, div, actual, deviation);
519
520 deviation = abs(deviation);
521
522 if (deviation < best_deviation) {
523 best_fs = fsdiv;
524 best_div = div;
525 best_rate = actual;
526 best_deviation = deviation;
527 }
528
529 if (deviation == 0)
530 break;
531 }
532
533 printk(KERN_DEBUG "best: fs=%d, div=%d, rate=%d\n",
534 best_fs, best_div, best_rate);
535
536 info->fs_div = best_fs;
537 info->clk_div = best_div;
538
539 return 0;
540}
541EXPORT_SYMBOL_GPL(s3c2412_iis_calc_rate);
542
543int s3c_i2sv2_probe(struct platform_device *pdev,
544 struct snd_soc_dai *dai,
545 struct s3c_i2sv2_info *i2s,
546 unsigned long base)
547{
548 struct device *dev = &pdev->dev;
549
550 i2s->dev = dev;
551
552 /* record our i2s structure for later use in the callbacks */
553 dai->private_data = i2s;
554
555 i2s->regs = ioremap(base, 0x100);
556 if (i2s->regs == NULL) {
557 dev_err(dev, "cannot ioremap registers\n");
558 return -ENXIO;
559 }
560
561 i2s->iis_pclk = clk_get(dev, "iis");
562 if (i2s->iis_pclk == NULL) {
563 DBG("failed to get iis_clock\n");
564 iounmap(i2s->regs);
565 return -ENOENT;
566 }
567
568 clk_enable(i2s->iis_pclk);
569
570 s3c2412_snd_txctrl(i2s, 0);
571 s3c2412_snd_rxctrl(i2s, 0);
572
573 return 0;
574}
575
576EXPORT_SYMBOL_GPL(s3c_i2sv2_probe);
577
578#ifdef CONFIG_PM
579static int s3c2412_i2s_suspend(struct snd_soc_dai *dai)
580{
581 struct s3c_i2sv2_info *i2s = to_info(dai);
582 u32 iismod;
583
584 if (dai->active) {
585 i2s->suspend_iismod = readl(i2s->regs + S3C2412_IISMOD);
586 i2s->suspend_iiscon = readl(i2s->regs + S3C2412_IISCON);
587 i2s->suspend_iispsr = readl(i2s->regs + S3C2412_IISPSR);
588
589 /* some basic suspend checks */
590
591 iismod = readl(i2s->regs + S3C2412_IISMOD);
592
593 if (iismod & S3C2412_IISCON_RXDMA_ACTIVE)
594 pr_warning("%s: RXDMA active?\n", __func__);
595
596 if (iismod & S3C2412_IISCON_TXDMA_ACTIVE)
597 pr_warning("%s: TXDMA active?\n", __func__);
598
599 if (iismod & S3C2412_IISCON_IIS_ACTIVE)
600 pr_warning("%s: IIS active\n", __func__);
601 }
602
603 return 0;
604}
605
606static int s3c2412_i2s_resume(struct snd_soc_dai *dai)
607{
608 struct s3c_i2sv2_info *i2s = to_info(dai);
609
610 pr_info("dai_active %d, IISMOD %08x, IISCON %08x\n",
611 dai->active, i2s->suspend_iismod, i2s->suspend_iiscon);
612
613 if (dai->active) {
614 writel(i2s->suspend_iiscon, i2s->regs + S3C2412_IISCON);
615 writel(i2s->suspend_iismod, i2s->regs + S3C2412_IISMOD);
616 writel(i2s->suspend_iispsr, i2s->regs + S3C2412_IISPSR);
617
618 writel(S3C2412_IISFIC_RXFLUSH | S3C2412_IISFIC_TXFLUSH,
619 i2s->regs + S3C2412_IISFIC);
620
621 ndelay(250);
622 writel(0x0, i2s->regs + S3C2412_IISFIC);
623 }
624
625 return 0;
626}
627#else
628#define s3c2412_i2s_suspend NULL
629#define s3c2412_i2s_resume NULL
630#endif
631
632int s3c_i2sv2_register_dai(struct snd_soc_dai *dai)
633{
634 dai->ops.trigger = s3c2412_i2s_trigger;
635 dai->ops.hw_params = s3c2412_i2s_hw_params;
636 dai->ops.set_fmt = s3c2412_i2s_set_fmt;
637 dai->ops.set_clkdiv = s3c2412_i2s_set_clkdiv;
638
639 dai->suspend = s3c2412_i2s_suspend;
640 dai->resume = s3c2412_i2s_resume;
641
642 return snd_soc_register_dai(dai);
643}
644
645EXPORT_SYMBOL_GPL(s3c_i2sv2_register_dai);
This page took 0.049338 seconds and 5 git commands to generate.