blob: e1a3d1a2b4c8832c794e75822e43e7f591e22d40 [file] [log] [blame]
Kuninori Morimotoa4d7d552009-08-20 21:01:05 +09001/*
2 * Fifo-attached Serial Interface (FSI) support for SH7724
3 *
4 * Copyright (C) 2009 Renesas Solutions Corp.
5 * Kuninori Morimoto <morimoto.kuninori@renesas.com>
6 *
7 * Based on ssi.c
8 * Copyright (c) 2007 Manuel Lauss <mano@roarinelk.homelinux.net>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14
15#include <linux/init.h>
16#include <linux/module.h>
17#include <linux/platform_device.h>
18#include <linux/delay.h>
19#include <linux/list.h>
20#include <linux/clk.h>
21#include <linux/io.h>
22#include <sound/core.h>
23#include <sound/pcm.h>
24#include <sound/initval.h>
25#include <sound/soc.h>
26#include <sound/pcm_params.h>
27#include <sound/sh_fsi.h>
28#include <asm/atomic.h>
Kuninori Morimotoa4d7d552009-08-20 21:01:05 +090029
30#define DO_FMT 0x0000
31#define DOFF_CTL 0x0004
32#define DOFF_ST 0x0008
33#define DI_FMT 0x000C
34#define DIFF_CTL 0x0010
35#define DIFF_ST 0x0014
36#define CKG1 0x0018
37#define CKG2 0x001C
38#define DIDT 0x0020
39#define DODT 0x0024
40#define MUTE_ST 0x0028
41#define REG_END MUTE_ST
42
43#define INT_ST 0x0200
44#define IEMSK 0x0204
45#define IMSK 0x0208
46#define MUTE 0x020C
47#define CLK_RST 0x0210
48#define SOFT_RST 0x0214
49#define MREG_START INT_ST
50#define MREG_END SOFT_RST
51
52/* DO_FMT */
53/* DI_FMT */
54#define CR_FMT(param) ((param) << 4)
55# define CR_MONO 0x0
56# define CR_MONO_D 0x1
57# define CR_PCM 0x2
58# define CR_I2S 0x3
59# define CR_TDM 0x4
60# define CR_TDM_D 0x5
61
62/* DOFF_CTL */
63/* DIFF_CTL */
64#define IRQ_HALF 0x00100000
65#define FIFO_CLR 0x00000001
66
67/* DOFF_ST */
68#define ERR_OVER 0x00000010
69#define ERR_UNDER 0x00000001
70
71/* CLK_RST */
72#define B_CLK 0x00000010
73#define A_CLK 0x00000001
74
75/* INT_ST */
76#define INT_B_IN (1 << 12)
77#define INT_B_OUT (1 << 8)
78#define INT_A_IN (1 << 4)
79#define INT_A_OUT (1 << 0)
80
81#define FSI_RATES SNDRV_PCM_RATE_8000_96000
82
83#define FSI_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE)
84
85/************************************************************************
86
87
88 struct
89
90
91************************************************************************/
92struct fsi_priv {
93 void __iomem *base;
94 struct snd_pcm_substream *substream;
95
96 int fifo_max;
97 int chan;
Kuninori Morimotoa4d7d552009-08-20 21:01:05 +090098
99 int byte_offset;
100 int period_len;
101 int buffer_len;
102 int periods;
103};
104
105struct fsi_master {
106 void __iomem *base;
107 int irq;
108 struct clk *clk;
109 struct fsi_priv fsia;
110 struct fsi_priv fsib;
111 struct sh_fsi_platform_info *info;
112};
113
114static struct fsi_master *master;
115
116/************************************************************************
117
118
119 basic read write function
120
121
122************************************************************************/
123static int __fsi_reg_write(u32 reg, u32 data)
124{
125 /* valid data area is 24bit */
126 data &= 0x00ffffff;
127
128 return ctrl_outl(data, reg);
129}
130
131static u32 __fsi_reg_read(u32 reg)
132{
133 return ctrl_inl(reg);
134}
135
136static int __fsi_reg_mask_set(u32 reg, u32 mask, u32 data)
137{
138 u32 val = __fsi_reg_read(reg);
139
140 val &= ~mask;
141 val |= data & mask;
142
143 return __fsi_reg_write(reg, val);
144}
145
146static int fsi_reg_write(struct fsi_priv *fsi, u32 reg, u32 data)
147{
148 if (reg > REG_END)
149 return -1;
150
151 return __fsi_reg_write((u32)(fsi->base + reg), data);
152}
153
154static u32 fsi_reg_read(struct fsi_priv *fsi, u32 reg)
155{
156 if (reg > REG_END)
157 return 0;
158
159 return __fsi_reg_read((u32)(fsi->base + reg));
160}
161
162static int fsi_reg_mask_set(struct fsi_priv *fsi, u32 reg, u32 mask, u32 data)
163{
164 if (reg > REG_END)
165 return -1;
166
167 return __fsi_reg_mask_set((u32)(fsi->base + reg), mask, data);
168}
169
170static int fsi_master_write(u32 reg, u32 data)
171{
172 if ((reg < MREG_START) ||
173 (reg > MREG_END))
174 return -1;
175
176 return __fsi_reg_write((u32)(master->base + reg), data);
177}
178
179static u32 fsi_master_read(u32 reg)
180{
181 if ((reg < MREG_START) ||
182 (reg > MREG_END))
183 return 0;
184
185 return __fsi_reg_read((u32)(master->base + reg));
186}
187
188static int fsi_master_mask_set(u32 reg, u32 mask, u32 data)
189{
190 if ((reg < MREG_START) ||
191 (reg > MREG_END))
192 return -1;
193
194 return __fsi_reg_mask_set((u32)(master->base + reg), mask, data);
195}
196
197/************************************************************************
198
199
200 basic function
201
202
203************************************************************************/
204static struct fsi_priv *fsi_get(struct snd_pcm_substream *substream)
205{
206 struct snd_soc_pcm_runtime *rtd;
207 struct fsi_priv *fsi = NULL;
208
209 if (!substream || !master)
210 return NULL;
211
212 rtd = substream->private_data;
213 switch (rtd->dai->cpu_dai->id) {
214 case 0:
215 fsi = &master->fsia;
216 break;
217 case 1:
218 fsi = &master->fsib;
219 break;
220 }
221
222 return fsi;
223}
224
225static int fsi_is_port_a(struct fsi_priv *fsi)
226{
227 /* return
228 * 1 : port a
229 * 0 : port b
230 */
231
232 if (fsi == &master->fsia)
233 return 1;
234
235 return 0;
236}
237
238static u32 fsi_get_info_flags(struct fsi_priv *fsi)
239{
240 int is_porta = fsi_is_port_a(fsi);
241
242 return is_porta ? master->info->porta_flags :
243 master->info->portb_flags;
244}
245
246static int fsi_is_master_mode(struct fsi_priv *fsi, int is_play)
247{
248 u32 mode;
249 u32 flags = fsi_get_info_flags(fsi);
250
251 mode = is_play ? SH_FSI_OUT_SLAVE_MODE : SH_FSI_IN_SLAVE_MODE;
252
253 /* return
254 * 1 : master mode
255 * 0 : slave mode
256 */
257
258 return (mode & flags) != mode;
259}
260
261static u32 fsi_port_ab_io_bit(struct fsi_priv *fsi, int is_play)
262{
263 int is_porta = fsi_is_port_a(fsi);
264 u32 data;
265
266 if (is_porta)
267 data = is_play ? (1 << 0) : (1 << 4);
268 else
269 data = is_play ? (1 << 8) : (1 << 12);
270
271 return data;
272}
273
274static void fsi_stream_push(struct fsi_priv *fsi,
275 struct snd_pcm_substream *substream,
276 u32 buffer_len,
277 u32 period_len)
278{
279 fsi->substream = substream;
280 fsi->buffer_len = buffer_len;
281 fsi->period_len = period_len;
282 fsi->byte_offset = 0;
283 fsi->periods = 0;
284}
285
286static void fsi_stream_pop(struct fsi_priv *fsi)
287{
288 fsi->substream = NULL;
289 fsi->buffer_len = 0;
290 fsi->period_len = 0;
291 fsi->byte_offset = 0;
292 fsi->periods = 0;
293}
294
295static int fsi_get_fifo_residue(struct fsi_priv *fsi, int is_play)
296{
297 u32 status;
298 u32 reg = is_play ? DOFF_ST : DIFF_ST;
299 int residue;
300
301 status = fsi_reg_read(fsi, reg);
302 residue = 0x1ff & (status >> 8);
303 residue *= fsi->chan;
304
305 return residue;
306}
307
Kuninori Morimotoa4d7d552009-08-20 21:01:05 +0900308/************************************************************************
309
310
311 ctrl function
312
313
314************************************************************************/
315static void fsi_irq_enable(struct fsi_priv *fsi, int is_play)
316{
317 u32 data = fsi_port_ab_io_bit(fsi, is_play);
318
319 fsi_master_mask_set(IMSK, data, data);
320 fsi_master_mask_set(IEMSK, data, data);
321}
322
323static void fsi_irq_disable(struct fsi_priv *fsi, int is_play)
324{
325 u32 data = fsi_port_ab_io_bit(fsi, is_play);
326
327 fsi_master_mask_set(IMSK, data, 0);
328 fsi_master_mask_set(IEMSK, data, 0);
329}
330
331static void fsi_clk_ctrl(struct fsi_priv *fsi, int enable)
332{
333 u32 val = fsi_is_port_a(fsi) ? (1 << 0) : (1 << 4);
334
335 if (enable)
336 fsi_master_mask_set(CLK_RST, val, val);
337 else
338 fsi_master_mask_set(CLK_RST, val, 0);
339}
340
341static void fsi_irq_init(struct fsi_priv *fsi, int is_play)
342{
343 u32 data;
344 u32 ctrl;
345
346 data = fsi_port_ab_io_bit(fsi, is_play);
347 ctrl = is_play ? DOFF_CTL : DIFF_CTL;
348
349 /* set IMSK */
350 fsi_irq_disable(fsi, is_play);
351
352 /* set interrupt generation factor */
353 fsi_reg_write(fsi, ctrl, IRQ_HALF);
354
355 /* clear FIFO */
356 fsi_reg_mask_set(fsi, ctrl, FIFO_CLR, FIFO_CLR);
357
358 /* clear interrupt factor */
359 fsi_master_mask_set(INT_ST, data, 0);
360}
361
362static void fsi_soft_all_reset(void)
363{
364 u32 status = fsi_master_read(SOFT_RST);
365
366 /* port AB reset */
367 status &= 0x000000ff;
368 fsi_master_write(SOFT_RST, status);
369 mdelay(10);
370
371 /* soft reset */
372 status &= 0x000000f0;
373 fsi_master_write(SOFT_RST, status);
374 status |= 0x00000001;
375 fsi_master_write(SOFT_RST, status);
376 mdelay(10);
377}
378
Kuninori Morimotoa4d7d552009-08-20 21:01:05 +0900379/* playback interrupt */
380static int fsi_data_push(struct fsi_priv *fsi)
381{
382 struct snd_pcm_runtime *runtime;
383 struct snd_pcm_substream *substream = NULL;
384 int send;
385 int fifo_free;
386 int width;
Kuninori Morimoto9ddc9aa2009-10-30 12:02:39 +0900387 u8 *start;
388 int i;
Kuninori Morimotoa4d7d552009-08-20 21:01:05 +0900389
390 if (!fsi ||
391 !fsi->substream ||
392 !fsi->substream->runtime)
393 return -EINVAL;
394
395 runtime = fsi->substream->runtime;
396
397 /* FSI FIFO has limit.
398 * So, this driver can not send periods data at a time
399 */
400 if (fsi->byte_offset >=
401 fsi->period_len * (fsi->periods + 1)) {
402
403 substream = fsi->substream;
404 fsi->periods = (fsi->periods + 1) % runtime->periods;
405
406 if (0 == fsi->periods)
407 fsi->byte_offset = 0;
408 }
409
410 /* get 1 channel data width */
411 width = frames_to_bytes(runtime, 1) / fsi->chan;
412
413 /* get send size for alsa */
414 send = (fsi->buffer_len - fsi->byte_offset) / width;
415
416 /* get FIFO free size */
417 fifo_free = (fsi->fifo_max * fsi->chan) - fsi_get_fifo_residue(fsi, 1);
418
419 /* size check */
420 if (fifo_free < send)
421 send = fifo_free;
422
Kuninori Morimoto9ddc9aa2009-10-30 12:02:39 +0900423 start = runtime->dma_area;
424 start += fsi->byte_offset;
425
426 switch (width) {
427 case 2:
428 for (i = 0; i < send; i++)
429 fsi_reg_write(fsi, DODT,
430 ((u32)*((u16 *)start + i) << 8));
431 break;
432 case 4:
433 for (i = 0; i < send; i++)
434 fsi_reg_write(fsi, DODT, *((u32 *)start + i));
435 break;
436 default:
Kuninori Morimotoa4d7d552009-08-20 21:01:05 +0900437 return -EINVAL;
Kuninori Morimoto9ddc9aa2009-10-30 12:02:39 +0900438 }
Kuninori Morimotoa4d7d552009-08-20 21:01:05 +0900439
440 fsi->byte_offset += send * width;
441
442 fsi_irq_enable(fsi, 1);
443
444 if (substream)
445 snd_pcm_period_elapsed(substream);
446
447 return 0;
448}
449
Kuninori Morimoto07102f32009-10-30 12:02:44 +0900450static int fsi_data_pop(struct fsi_priv *fsi)
451{
452 struct snd_pcm_runtime *runtime;
453 struct snd_pcm_substream *substream = NULL;
454 int free;
455 int fifo_fill;
456 int width;
457 u8 *start;
458 int i;
459
460 if (!fsi ||
461 !fsi->substream ||
462 !fsi->substream->runtime)
463 return -EINVAL;
464
465 runtime = fsi->substream->runtime;
466
467 /* FSI FIFO has limit.
468 * So, this driver can not send periods data at a time
469 */
470 if (fsi->byte_offset >=
471 fsi->period_len * (fsi->periods + 1)) {
472
473 substream = fsi->substream;
474 fsi->periods = (fsi->periods + 1) % runtime->periods;
475
476 if (0 == fsi->periods)
477 fsi->byte_offset = 0;
478 }
479
480 /* get 1 channel data width */
481 width = frames_to_bytes(runtime, 1) / fsi->chan;
482
483 /* get free space for alsa */
484 free = (fsi->buffer_len - fsi->byte_offset) / width;
485
486 /* get recv size */
487 fifo_fill = fsi_get_fifo_residue(fsi, 0);
488
489 if (free < fifo_fill)
490 fifo_fill = free;
491
492 start = runtime->dma_area;
493 start += fsi->byte_offset;
494
495 switch (width) {
496 case 2:
497 for (i = 0; i < fifo_fill; i++)
498 *((u16 *)start + i) =
499 (u16)(fsi_reg_read(fsi, DIDT) >> 8);
500 break;
501 case 4:
502 for (i = 0; i < fifo_fill; i++)
503 *((u32 *)start + i) = fsi_reg_read(fsi, DIDT);
504 break;
505 default:
506 return -EINVAL;
507 }
508
509 fsi->byte_offset += fifo_fill * width;
510
511 fsi_irq_enable(fsi, 0);
512
513 if (substream)
514 snd_pcm_period_elapsed(substream);
515
516 return 0;
517}
518
Kuninori Morimotoa4d7d552009-08-20 21:01:05 +0900519static irqreturn_t fsi_interrupt(int irq, void *data)
520{
521 u32 status = fsi_master_read(SOFT_RST) & ~0x00000010;
522 u32 int_st = fsi_master_read(INT_ST);
523
524 /* clear irq status */
525 fsi_master_write(SOFT_RST, status);
526 fsi_master_write(SOFT_RST, status | 0x00000010);
527
528 if (int_st & INT_A_OUT)
529 fsi_data_push(&master->fsia);
530 if (int_st & INT_B_OUT)
531 fsi_data_push(&master->fsib);
Kuninori Morimoto07102f32009-10-30 12:02:44 +0900532 if (int_st & INT_A_IN)
533 fsi_data_pop(&master->fsia);
534 if (int_st & INT_B_IN)
535 fsi_data_pop(&master->fsib);
Kuninori Morimotoa4d7d552009-08-20 21:01:05 +0900536
537 fsi_master_write(INT_ST, 0x0000000);
538
539 return IRQ_HANDLED;
540}
541
542/************************************************************************
543
544
545 dai ops
546
547
548************************************************************************/
549static int fsi_dai_startup(struct snd_pcm_substream *substream,
550 struct snd_soc_dai *dai)
551{
552 struct fsi_priv *fsi = fsi_get(substream);
553 const char *msg;
554 u32 flags = fsi_get_info_flags(fsi);
555 u32 fmt;
556 u32 reg;
557 u32 data;
558 int is_play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
559 int is_master;
560 int ret = 0;
561
562 clk_enable(master->clk);
563
564 /* CKG1 */
565 data = is_play ? (1 << 0) : (1 << 4);
566 is_master = fsi_is_master_mode(fsi, is_play);
567 if (is_master)
568 fsi_reg_mask_set(fsi, CKG1, data, data);
569 else
570 fsi_reg_mask_set(fsi, CKG1, data, 0);
571
572 /* clock inversion (CKG2) */
573 data = 0;
574 switch (SH_FSI_INVERSION_MASK & flags) {
575 case SH_FSI_LRM_INV:
576 data = 1 << 12;
577 break;
578 case SH_FSI_BRM_INV:
579 data = 1 << 8;
580 break;
581 case SH_FSI_LRS_INV:
582 data = 1 << 4;
583 break;
584 case SH_FSI_BRS_INV:
585 data = 1 << 0;
586 break;
587 }
588 fsi_reg_write(fsi, CKG2, data);
589
590 /* do fmt, di fmt */
591 data = 0;
592 reg = is_play ? DO_FMT : DI_FMT;
593 fmt = is_play ? SH_FSI_GET_OFMT(flags) : SH_FSI_GET_IFMT(flags);
594 switch (fmt) {
595 case SH_FSI_FMT_MONO:
596 msg = "MONO";
597 data = CR_FMT(CR_MONO);
598 fsi->chan = 1;
599 break;
600 case SH_FSI_FMT_MONO_DELAY:
601 msg = "MONO Delay";
602 data = CR_FMT(CR_MONO_D);
603 fsi->chan = 1;
604 break;
605 case SH_FSI_FMT_PCM:
606 msg = "PCM";
607 data = CR_FMT(CR_PCM);
608 fsi->chan = 2;
609 break;
610 case SH_FSI_FMT_I2S:
611 msg = "I2S";
612 data = CR_FMT(CR_I2S);
613 fsi->chan = 2;
614 break;
615 case SH_FSI_FMT_TDM:
616 msg = "TDM";
617 data = CR_FMT(CR_TDM) | (fsi->chan - 1);
618 fsi->chan = is_play ?
619 SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags);
620 break;
621 case SH_FSI_FMT_TDM_DELAY:
622 msg = "TDM Delay";
623 data = CR_FMT(CR_TDM_D) | (fsi->chan - 1);
624 fsi->chan = is_play ?
625 SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags);
626 break;
627 default:
628 dev_err(dai->dev, "unknown format.\n");
629 return -EINVAL;
630 }
631
632 switch (fsi->chan) {
633 case 1:
634 fsi->fifo_max = 256;
635 break;
636 case 2:
637 fsi->fifo_max = 128;
638 break;
639 case 3:
640 case 4:
641 fsi->fifo_max = 64;
642 break;
643 case 5:
644 case 6:
645 case 7:
646 case 8:
647 fsi->fifo_max = 32;
648 break;
649 default:
650 dev_err(dai->dev, "channel size error.\n");
651 return -EINVAL;
652 }
653
654 fsi_reg_write(fsi, reg, data);
Kuninori Morimotoa4d7d552009-08-20 21:01:05 +0900655
656 /*
657 * clear clk reset if master mode
658 */
659 if (is_master)
660 fsi_clk_ctrl(fsi, 1);
661
662 /* irq setting */
663 fsi_irq_init(fsi, is_play);
664
665 return ret;
666}
667
668static void fsi_dai_shutdown(struct snd_pcm_substream *substream,
669 struct snd_soc_dai *dai)
670{
671 struct fsi_priv *fsi = fsi_get(substream);
672 int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
673
674 fsi_irq_disable(fsi, is_play);
675 fsi_clk_ctrl(fsi, 0);
676
677 clk_disable(master->clk);
678}
679
680static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
681 struct snd_soc_dai *dai)
682{
683 struct fsi_priv *fsi = fsi_get(substream);
684 struct snd_pcm_runtime *runtime = substream->runtime;
685 int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
686 int ret = 0;
687
Kuninori Morimotoa4d7d552009-08-20 21:01:05 +0900688 switch (cmd) {
689 case SNDRV_PCM_TRIGGER_START:
690 fsi_stream_push(fsi, substream,
691 frames_to_bytes(runtime, runtime->buffer_size),
692 frames_to_bytes(runtime, runtime->period_size));
Kuninori Morimoto07102f32009-10-30 12:02:44 +0900693 ret = is_play ? fsi_data_push(fsi) : fsi_data_pop(fsi);
Kuninori Morimotoa4d7d552009-08-20 21:01:05 +0900694 break;
695 case SNDRV_PCM_TRIGGER_STOP:
696 fsi_irq_disable(fsi, is_play);
697 fsi_stream_pop(fsi);
698 break;
699 }
700
701 return ret;
702}
703
704static struct snd_soc_dai_ops fsi_dai_ops = {
705 .startup = fsi_dai_startup,
706 .shutdown = fsi_dai_shutdown,
707 .trigger = fsi_dai_trigger,
708};
709
710/************************************************************************
711
712
713 pcm ops
714
715
716************************************************************************/
717static struct snd_pcm_hardware fsi_pcm_hardware = {
718 .info = SNDRV_PCM_INFO_INTERLEAVED |
719 SNDRV_PCM_INFO_MMAP |
720 SNDRV_PCM_INFO_MMAP_VALID |
721 SNDRV_PCM_INFO_PAUSE,
722 .formats = FSI_FMTS,
723 .rates = FSI_RATES,
724 .rate_min = 8000,
725 .rate_max = 192000,
726 .channels_min = 1,
727 .channels_max = 2,
728 .buffer_bytes_max = 64 * 1024,
729 .period_bytes_min = 32,
730 .period_bytes_max = 8192,
731 .periods_min = 1,
732 .periods_max = 32,
733 .fifo_size = 256,
734};
735
736static int fsi_pcm_open(struct snd_pcm_substream *substream)
737{
738 struct snd_pcm_runtime *runtime = substream->runtime;
739 int ret = 0;
740
741 snd_soc_set_runtime_hwparams(substream, &fsi_pcm_hardware);
742
743 ret = snd_pcm_hw_constraint_integer(runtime,
744 SNDRV_PCM_HW_PARAM_PERIODS);
745
746 return ret;
747}
748
749static int fsi_hw_params(struct snd_pcm_substream *substream,
750 struct snd_pcm_hw_params *hw_params)
751{
752 return snd_pcm_lib_malloc_pages(substream,
753 params_buffer_bytes(hw_params));
754}
755
756static int fsi_hw_free(struct snd_pcm_substream *substream)
757{
758 return snd_pcm_lib_free_pages(substream);
759}
760
761static snd_pcm_uframes_t fsi_pointer(struct snd_pcm_substream *substream)
762{
763 struct snd_pcm_runtime *runtime = substream->runtime;
764 struct fsi_priv *fsi = fsi_get(substream);
Kuninori Morimotoa4d7d552009-08-20 21:01:05 +0900765 long location;
766
Kuninori Morimoto9ddc9aa2009-10-30 12:02:39 +0900767 location = (fsi->byte_offset - 1);
Kuninori Morimotoa4d7d552009-08-20 21:01:05 +0900768 if (location < 0)
769 location = 0;
770
771 return bytes_to_frames(runtime, location);
772}
773
774static struct snd_pcm_ops fsi_pcm_ops = {
775 .open = fsi_pcm_open,
776 .ioctl = snd_pcm_lib_ioctl,
777 .hw_params = fsi_hw_params,
778 .hw_free = fsi_hw_free,
779 .pointer = fsi_pointer,
780};
781
782/************************************************************************
783
784
785 snd_soc_platform
786
787
788************************************************************************/
789#define PREALLOC_BUFFER (32 * 1024)
790#define PREALLOC_BUFFER_MAX (32 * 1024)
791
792static void fsi_pcm_free(struct snd_pcm *pcm)
793{
794 snd_pcm_lib_preallocate_free_for_all(pcm);
795}
796
797static int fsi_pcm_new(struct snd_card *card,
798 struct snd_soc_dai *dai,
799 struct snd_pcm *pcm)
800{
801 /*
802 * dont use SNDRV_DMA_TYPE_DEV, since it will oops the SH kernel
803 * in MMAP mode (i.e. aplay -M)
804 */
805 return snd_pcm_lib_preallocate_pages_for_all(
806 pcm,
807 SNDRV_DMA_TYPE_CONTINUOUS,
808 snd_dma_continuous_data(GFP_KERNEL),
809 PREALLOC_BUFFER, PREALLOC_BUFFER_MAX);
810}
811
812/************************************************************************
813
814
815 alsa struct
816
817
818************************************************************************/
819struct snd_soc_dai fsi_soc_dai[] = {
820 {
821 .name = "FSIA",
822 .id = 0,
823 .playback = {
824 .rates = FSI_RATES,
825 .formats = FSI_FMTS,
826 .channels_min = 1,
827 .channels_max = 8,
828 },
Kuninori Morimoto07102f32009-10-30 12:02:44 +0900829 .capture = {
830 .rates = FSI_RATES,
831 .formats = FSI_FMTS,
832 .channels_min = 1,
833 .channels_max = 8,
834 },
Kuninori Morimotoa4d7d552009-08-20 21:01:05 +0900835 .ops = &fsi_dai_ops,
836 },
837 {
838 .name = "FSIB",
839 .id = 1,
840 .playback = {
841 .rates = FSI_RATES,
842 .formats = FSI_FMTS,
843 .channels_min = 1,
844 .channels_max = 8,
845 },
Kuninori Morimoto07102f32009-10-30 12:02:44 +0900846 .capture = {
847 .rates = FSI_RATES,
848 .formats = FSI_FMTS,
849 .channels_min = 1,
850 .channels_max = 8,
851 },
Kuninori Morimotoa4d7d552009-08-20 21:01:05 +0900852 .ops = &fsi_dai_ops,
853 },
854};
855EXPORT_SYMBOL_GPL(fsi_soc_dai);
856
857struct snd_soc_platform fsi_soc_platform = {
858 .name = "fsi-pcm",
859 .pcm_ops = &fsi_pcm_ops,
860 .pcm_new = fsi_pcm_new,
861 .pcm_free = fsi_pcm_free,
862};
863EXPORT_SYMBOL_GPL(fsi_soc_platform);
864
865/************************************************************************
866
867
868 platform function
869
870
871************************************************************************/
872static int fsi_probe(struct platform_device *pdev)
873{
874 struct resource *res;
875 char clk_name[8];
876 unsigned int irq;
877 int ret;
878
879 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
880 irq = platform_get_irq(pdev, 0);
881 if (!res || !irq) {
882 dev_err(&pdev->dev, "Not enough FSI platform resources.\n");
883 ret = -ENODEV;
884 goto exit;
885 }
886
887 master = kzalloc(sizeof(*master), GFP_KERNEL);
888 if (!master) {
889 dev_err(&pdev->dev, "Could not allocate master\n");
890 ret = -ENOMEM;
891 goto exit;
892 }
893
894 master->base = ioremap_nocache(res->start, resource_size(res));
895 if (!master->base) {
896 ret = -ENXIO;
897 dev_err(&pdev->dev, "Unable to ioremap FSI registers.\n");
898 goto exit_kfree;
899 }
900
901 master->irq = irq;
902 master->info = pdev->dev.platform_data;
903 master->fsia.base = master->base;
904 master->fsib.base = master->base + 0x40;
905
Kuninori Morimotoa4d7d552009-08-20 21:01:05 +0900906 /* FSI is based on SPU mstp */
907 snprintf(clk_name, sizeof(clk_name), "spu%d", pdev->id);
908 master->clk = clk_get(NULL, clk_name);
909 if (IS_ERR(master->clk)) {
910 dev_err(&pdev->dev, "cannot get %s mstp\n", clk_name);
911 ret = -EIO;
Kuninori Morimoto9ddc9aa2009-10-30 12:02:39 +0900912 goto exit_iounmap;
Kuninori Morimotoa4d7d552009-08-20 21:01:05 +0900913 }
914
915 fsi_soc_dai[0].dev = &pdev->dev;
916 fsi_soc_dai[1].dev = &pdev->dev;
917
918 fsi_soft_all_reset();
919
920 ret = request_irq(irq, &fsi_interrupt, IRQF_DISABLED, "fsi", master);
921 if (ret) {
922 dev_err(&pdev->dev, "irq request err\n");
Kuninori Morimoto9ddc9aa2009-10-30 12:02:39 +0900923 goto exit_iounmap;
Kuninori Morimotoa4d7d552009-08-20 21:01:05 +0900924 }
925
926 ret = snd_soc_register_platform(&fsi_soc_platform);
927 if (ret < 0) {
928 dev_err(&pdev->dev, "cannot snd soc register\n");
929 goto exit_free_irq;
930 }
931
932 return snd_soc_register_dais(fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai));
933
934exit_free_irq:
935 free_irq(irq, master);
Kuninori Morimotoa4d7d552009-08-20 21:01:05 +0900936exit_iounmap:
937 iounmap(master->base);
938exit_kfree:
939 kfree(master);
940 master = NULL;
941exit:
942 return ret;
943}
944
945static int fsi_remove(struct platform_device *pdev)
946{
947 snd_soc_unregister_dais(fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai));
948 snd_soc_unregister_platform(&fsi_soc_platform);
949
950 clk_put(master->clk);
951
Kuninori Morimotoa4d7d552009-08-20 21:01:05 +0900952 free_irq(master->irq, master);
953
954 iounmap(master->base);
955 kfree(master);
956 master = NULL;
957 return 0;
958}
959
960static struct platform_driver fsi_driver = {
961 .driver = {
962 .name = "sh_fsi",
963 },
964 .probe = fsi_probe,
965 .remove = fsi_remove,
966};
967
968static int __init fsi_mobile_init(void)
969{
970 return platform_driver_register(&fsi_driver);
971}
972
973static void __exit fsi_mobile_exit(void)
974{
975 platform_driver_unregister(&fsi_driver);
976}
977module_init(fsi_mobile_init);
978module_exit(fsi_mobile_exit);
979
980MODULE_LICENSE("GPL");
981MODULE_DESCRIPTION("SuperH onchip FSI audio driver");
982MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>");