blob: 9742a280ba158b204ba8e4df1a0174b4f23c8d60 [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
450static irqreturn_t fsi_interrupt(int irq, void *data)
451{
452 u32 status = fsi_master_read(SOFT_RST) & ~0x00000010;
453 u32 int_st = fsi_master_read(INT_ST);
454
455 /* clear irq status */
456 fsi_master_write(SOFT_RST, status);
457 fsi_master_write(SOFT_RST, status | 0x00000010);
458
459 if (int_st & INT_A_OUT)
460 fsi_data_push(&master->fsia);
461 if (int_st & INT_B_OUT)
462 fsi_data_push(&master->fsib);
463
464 fsi_master_write(INT_ST, 0x0000000);
465
466 return IRQ_HANDLED;
467}
468
469/************************************************************************
470
471
472 dai ops
473
474
475************************************************************************/
476static int fsi_dai_startup(struct snd_pcm_substream *substream,
477 struct snd_soc_dai *dai)
478{
479 struct fsi_priv *fsi = fsi_get(substream);
480 const char *msg;
481 u32 flags = fsi_get_info_flags(fsi);
482 u32 fmt;
483 u32 reg;
484 u32 data;
485 int is_play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
486 int is_master;
487 int ret = 0;
488
489 clk_enable(master->clk);
490
491 /* CKG1 */
492 data = is_play ? (1 << 0) : (1 << 4);
493 is_master = fsi_is_master_mode(fsi, is_play);
494 if (is_master)
495 fsi_reg_mask_set(fsi, CKG1, data, data);
496 else
497 fsi_reg_mask_set(fsi, CKG1, data, 0);
498
499 /* clock inversion (CKG2) */
500 data = 0;
501 switch (SH_FSI_INVERSION_MASK & flags) {
502 case SH_FSI_LRM_INV:
503 data = 1 << 12;
504 break;
505 case SH_FSI_BRM_INV:
506 data = 1 << 8;
507 break;
508 case SH_FSI_LRS_INV:
509 data = 1 << 4;
510 break;
511 case SH_FSI_BRS_INV:
512 data = 1 << 0;
513 break;
514 }
515 fsi_reg_write(fsi, CKG2, data);
516
517 /* do fmt, di fmt */
518 data = 0;
519 reg = is_play ? DO_FMT : DI_FMT;
520 fmt = is_play ? SH_FSI_GET_OFMT(flags) : SH_FSI_GET_IFMT(flags);
521 switch (fmt) {
522 case SH_FSI_FMT_MONO:
523 msg = "MONO";
524 data = CR_FMT(CR_MONO);
525 fsi->chan = 1;
526 break;
527 case SH_FSI_FMT_MONO_DELAY:
528 msg = "MONO Delay";
529 data = CR_FMT(CR_MONO_D);
530 fsi->chan = 1;
531 break;
532 case SH_FSI_FMT_PCM:
533 msg = "PCM";
534 data = CR_FMT(CR_PCM);
535 fsi->chan = 2;
536 break;
537 case SH_FSI_FMT_I2S:
538 msg = "I2S";
539 data = CR_FMT(CR_I2S);
540 fsi->chan = 2;
541 break;
542 case SH_FSI_FMT_TDM:
543 msg = "TDM";
544 data = CR_FMT(CR_TDM) | (fsi->chan - 1);
545 fsi->chan = is_play ?
546 SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags);
547 break;
548 case SH_FSI_FMT_TDM_DELAY:
549 msg = "TDM Delay";
550 data = CR_FMT(CR_TDM_D) | (fsi->chan - 1);
551 fsi->chan = is_play ?
552 SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags);
553 break;
554 default:
555 dev_err(dai->dev, "unknown format.\n");
556 return -EINVAL;
557 }
558
559 switch (fsi->chan) {
560 case 1:
561 fsi->fifo_max = 256;
562 break;
563 case 2:
564 fsi->fifo_max = 128;
565 break;
566 case 3:
567 case 4:
568 fsi->fifo_max = 64;
569 break;
570 case 5:
571 case 6:
572 case 7:
573 case 8:
574 fsi->fifo_max = 32;
575 break;
576 default:
577 dev_err(dai->dev, "channel size error.\n");
578 return -EINVAL;
579 }
580
581 fsi_reg_write(fsi, reg, data);
Kuninori Morimotoa4d7d552009-08-20 21:01:05 +0900582
583 /*
584 * clear clk reset if master mode
585 */
586 if (is_master)
587 fsi_clk_ctrl(fsi, 1);
588
589 /* irq setting */
590 fsi_irq_init(fsi, is_play);
591
592 return ret;
593}
594
595static void fsi_dai_shutdown(struct snd_pcm_substream *substream,
596 struct snd_soc_dai *dai)
597{
598 struct fsi_priv *fsi = fsi_get(substream);
599 int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
600
601 fsi_irq_disable(fsi, is_play);
602 fsi_clk_ctrl(fsi, 0);
603
604 clk_disable(master->clk);
605}
606
607static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
608 struct snd_soc_dai *dai)
609{
610 struct fsi_priv *fsi = fsi_get(substream);
611 struct snd_pcm_runtime *runtime = substream->runtime;
612 int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
613 int ret = 0;
614
615 /* capture not supported */
616 if (!is_play)
617 return -ENODEV;
618
619 switch (cmd) {
620 case SNDRV_PCM_TRIGGER_START:
621 fsi_stream_push(fsi, substream,
622 frames_to_bytes(runtime, runtime->buffer_size),
623 frames_to_bytes(runtime, runtime->period_size));
624 ret = fsi_data_push(fsi);
625 break;
626 case SNDRV_PCM_TRIGGER_STOP:
627 fsi_irq_disable(fsi, is_play);
628 fsi_stream_pop(fsi);
629 break;
630 }
631
632 return ret;
633}
634
635static struct snd_soc_dai_ops fsi_dai_ops = {
636 .startup = fsi_dai_startup,
637 .shutdown = fsi_dai_shutdown,
638 .trigger = fsi_dai_trigger,
639};
640
641/************************************************************************
642
643
644 pcm ops
645
646
647************************************************************************/
648static struct snd_pcm_hardware fsi_pcm_hardware = {
649 .info = SNDRV_PCM_INFO_INTERLEAVED |
650 SNDRV_PCM_INFO_MMAP |
651 SNDRV_PCM_INFO_MMAP_VALID |
652 SNDRV_PCM_INFO_PAUSE,
653 .formats = FSI_FMTS,
654 .rates = FSI_RATES,
655 .rate_min = 8000,
656 .rate_max = 192000,
657 .channels_min = 1,
658 .channels_max = 2,
659 .buffer_bytes_max = 64 * 1024,
660 .period_bytes_min = 32,
661 .period_bytes_max = 8192,
662 .periods_min = 1,
663 .periods_max = 32,
664 .fifo_size = 256,
665};
666
667static int fsi_pcm_open(struct snd_pcm_substream *substream)
668{
669 struct snd_pcm_runtime *runtime = substream->runtime;
670 int ret = 0;
671
672 snd_soc_set_runtime_hwparams(substream, &fsi_pcm_hardware);
673
674 ret = snd_pcm_hw_constraint_integer(runtime,
675 SNDRV_PCM_HW_PARAM_PERIODS);
676
677 return ret;
678}
679
680static int fsi_hw_params(struct snd_pcm_substream *substream,
681 struct snd_pcm_hw_params *hw_params)
682{
683 return snd_pcm_lib_malloc_pages(substream,
684 params_buffer_bytes(hw_params));
685}
686
687static int fsi_hw_free(struct snd_pcm_substream *substream)
688{
689 return snd_pcm_lib_free_pages(substream);
690}
691
692static snd_pcm_uframes_t fsi_pointer(struct snd_pcm_substream *substream)
693{
694 struct snd_pcm_runtime *runtime = substream->runtime;
695 struct fsi_priv *fsi = fsi_get(substream);
Kuninori Morimotoa4d7d552009-08-20 21:01:05 +0900696 long location;
697
Kuninori Morimoto9ddc9aa2009-10-30 12:02:39 +0900698 location = (fsi->byte_offset - 1);
Kuninori Morimotoa4d7d552009-08-20 21:01:05 +0900699 if (location < 0)
700 location = 0;
701
702 return bytes_to_frames(runtime, location);
703}
704
705static struct snd_pcm_ops fsi_pcm_ops = {
706 .open = fsi_pcm_open,
707 .ioctl = snd_pcm_lib_ioctl,
708 .hw_params = fsi_hw_params,
709 .hw_free = fsi_hw_free,
710 .pointer = fsi_pointer,
711};
712
713/************************************************************************
714
715
716 snd_soc_platform
717
718
719************************************************************************/
720#define PREALLOC_BUFFER (32 * 1024)
721#define PREALLOC_BUFFER_MAX (32 * 1024)
722
723static void fsi_pcm_free(struct snd_pcm *pcm)
724{
725 snd_pcm_lib_preallocate_free_for_all(pcm);
726}
727
728static int fsi_pcm_new(struct snd_card *card,
729 struct snd_soc_dai *dai,
730 struct snd_pcm *pcm)
731{
732 /*
733 * dont use SNDRV_DMA_TYPE_DEV, since it will oops the SH kernel
734 * in MMAP mode (i.e. aplay -M)
735 */
736 return snd_pcm_lib_preallocate_pages_for_all(
737 pcm,
738 SNDRV_DMA_TYPE_CONTINUOUS,
739 snd_dma_continuous_data(GFP_KERNEL),
740 PREALLOC_BUFFER, PREALLOC_BUFFER_MAX);
741}
742
743/************************************************************************
744
745
746 alsa struct
747
748
749************************************************************************/
750struct snd_soc_dai fsi_soc_dai[] = {
751 {
752 .name = "FSIA",
753 .id = 0,
754 .playback = {
755 .rates = FSI_RATES,
756 .formats = FSI_FMTS,
757 .channels_min = 1,
758 .channels_max = 8,
759 },
760 /* capture not supported */
761 .ops = &fsi_dai_ops,
762 },
763 {
764 .name = "FSIB",
765 .id = 1,
766 .playback = {
767 .rates = FSI_RATES,
768 .formats = FSI_FMTS,
769 .channels_min = 1,
770 .channels_max = 8,
771 },
772 /* capture not supported */
773 .ops = &fsi_dai_ops,
774 },
775};
776EXPORT_SYMBOL_GPL(fsi_soc_dai);
777
778struct snd_soc_platform fsi_soc_platform = {
779 .name = "fsi-pcm",
780 .pcm_ops = &fsi_pcm_ops,
781 .pcm_new = fsi_pcm_new,
782 .pcm_free = fsi_pcm_free,
783};
784EXPORT_SYMBOL_GPL(fsi_soc_platform);
785
786/************************************************************************
787
788
789 platform function
790
791
792************************************************************************/
793static int fsi_probe(struct platform_device *pdev)
794{
795 struct resource *res;
796 char clk_name[8];
797 unsigned int irq;
798 int ret;
799
800 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
801 irq = platform_get_irq(pdev, 0);
802 if (!res || !irq) {
803 dev_err(&pdev->dev, "Not enough FSI platform resources.\n");
804 ret = -ENODEV;
805 goto exit;
806 }
807
808 master = kzalloc(sizeof(*master), GFP_KERNEL);
809 if (!master) {
810 dev_err(&pdev->dev, "Could not allocate master\n");
811 ret = -ENOMEM;
812 goto exit;
813 }
814
815 master->base = ioremap_nocache(res->start, resource_size(res));
816 if (!master->base) {
817 ret = -ENXIO;
818 dev_err(&pdev->dev, "Unable to ioremap FSI registers.\n");
819 goto exit_kfree;
820 }
821
822 master->irq = irq;
823 master->info = pdev->dev.platform_data;
824 master->fsia.base = master->base;
825 master->fsib.base = master->base + 0x40;
826
Kuninori Morimotoa4d7d552009-08-20 21:01:05 +0900827 /* FSI is based on SPU mstp */
828 snprintf(clk_name, sizeof(clk_name), "spu%d", pdev->id);
829 master->clk = clk_get(NULL, clk_name);
830 if (IS_ERR(master->clk)) {
831 dev_err(&pdev->dev, "cannot get %s mstp\n", clk_name);
832 ret = -EIO;
Kuninori Morimoto9ddc9aa2009-10-30 12:02:39 +0900833 goto exit_iounmap;
Kuninori Morimotoa4d7d552009-08-20 21:01:05 +0900834 }
835
836 fsi_soc_dai[0].dev = &pdev->dev;
837 fsi_soc_dai[1].dev = &pdev->dev;
838
839 fsi_soft_all_reset();
840
841 ret = request_irq(irq, &fsi_interrupt, IRQF_DISABLED, "fsi", master);
842 if (ret) {
843 dev_err(&pdev->dev, "irq request err\n");
Kuninori Morimoto9ddc9aa2009-10-30 12:02:39 +0900844 goto exit_iounmap;
Kuninori Morimotoa4d7d552009-08-20 21:01:05 +0900845 }
846
847 ret = snd_soc_register_platform(&fsi_soc_platform);
848 if (ret < 0) {
849 dev_err(&pdev->dev, "cannot snd soc register\n");
850 goto exit_free_irq;
851 }
852
853 return snd_soc_register_dais(fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai));
854
855exit_free_irq:
856 free_irq(irq, master);
Kuninori Morimotoa4d7d552009-08-20 21:01:05 +0900857exit_iounmap:
858 iounmap(master->base);
859exit_kfree:
860 kfree(master);
861 master = NULL;
862exit:
863 return ret;
864}
865
866static int fsi_remove(struct platform_device *pdev)
867{
868 snd_soc_unregister_dais(fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai));
869 snd_soc_unregister_platform(&fsi_soc_platform);
870
871 clk_put(master->clk);
872
Kuninori Morimotoa4d7d552009-08-20 21:01:05 +0900873 free_irq(master->irq, master);
874
875 iounmap(master->base);
876 kfree(master);
877 master = NULL;
878 return 0;
879}
880
881static struct platform_driver fsi_driver = {
882 .driver = {
883 .name = "sh_fsi",
884 },
885 .probe = fsi_probe,
886 .remove = fsi_remove,
887};
888
889static int __init fsi_mobile_init(void)
890{
891 return platform_driver_register(&fsi_driver);
892}
893
894static void __exit fsi_mobile_exit(void)
895{
896 platform_driver_unregister(&fsi_driver);
897}
898module_init(fsi_mobile_init);
899module_exit(fsi_mobile_exit);
900
901MODULE_LICENSE("GPL");
902MODULE_DESCRIPTION("SuperH onchip FSI audio driver");
903MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>");