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