aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/sh
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-03-01 11:58:44 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2010-03-01 11:58:44 -0500
commit524df55725217b13d5a232fb5badb5846418ea0e (patch)
treec041613577ac7e68737cfd8af16a37d1ed37e6af /sound/soc/sh
parent0f4533979473a456a8adb3869365e12c7a99cf65 (diff)
parent6679ee1870f7ccdd48e2e5c57919240b8f19a6dc (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6: (252 commits) ASoC: Check progress when reporting periods from i.MX FIQ handler ASoC: Remove a unused variables from i.MX FIQ runtime data ALSA: hda - Add/fix ALC269 FSC and Quanta models ALSA: hda - Add ALC670 codec support OMAP4: PMIC: Add support for twl6030 codec ALSA: hda - remove unnecessary msleep on power state transitions usb/gadget/{f_audio,gmidi}.c: follow recent changes in audio.h ASoC: fsi: Modify over/under run error settlement ASoC: OMAP4: Add McPDM platform driver ASoC: OMAP4: Add support for McPDM ASoC: OMAP: data_type and sync_mode configurable in audio dma ALSA: hda - Add missing description in HD-Audio-Models.txt ALSA: add support for Macbook Air 2,1 internal speaker ALSA: usbaudio: consolidate header files ALSA: usbmixer: bail out early when parsing audio class v2 descriptors ALSA: usbaudio: implement basic set of class v2.0 parser ALSA: usbaudio: introduce new types for audio class v2 ALSA: usbaudio: parse USB descriptors with structs ALSA: hda - enable snoop for Intel Cougar Point ALSA: hda - Remove identical definitions for macmini3 model ...
Diffstat (limited to 'sound/soc/sh')
-rw-r--r--sound/soc/sh/Kconfig23
-rw-r--r--sound/soc/sh/Makefile6
-rw-r--r--sound/soc/sh/fsi-da7210.c83
-rw-r--r--sound/soc/sh/fsi.c227
-rw-r--r--sound/soc/sh/migor.c218
-rw-r--r--sound/soc/sh/siu.h193
-rw-r--r--sound/soc/sh/siu_dai.c847
-rw-r--r--sound/soc/sh/siu_pcm.c616
8 files changed, 2130 insertions, 83 deletions
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig
index 9e6976586554..106674979b53 100644
--- a/sound/soc/sh/Kconfig
+++ b/sound/soc/sh/Kconfig
@@ -26,6 +26,13 @@ config SND_SOC_SH4_FSI
26 help 26 help
27 This option enables FSI sound support 27 This option enables FSI sound support
28 28
29config SND_SOC_SH4_SIU
30 tristate
31 depends on (SUPERH || ARCH_SHMOBILE) && HAVE_CLK
32 select DMA_ENGINE
33 select DMADEVICES
34 select SH_DMAE
35
29## 36##
30## Boards 37## Boards
31## 38##
@@ -47,4 +54,20 @@ config SND_FSI_AK4642
47 This option enables generic sound support for the 54 This option enables generic sound support for the
48 FSI - AK4642 unit 55 FSI - AK4642 unit
49 56
57config SND_FSI_DA7210
58 bool "FSI-DA7210 sound support"
59 depends on SND_SOC_SH4_FSI
60 select SND_SOC_DA7210
61 help
62 This option enables generic sound support for the
63 FSI - DA7210 unit
64
65config SND_SIU_MIGOR
66 tristate "SIU sound support on Migo-R"
67 depends on SH_MIGOR
68 select SND_SOC_SH4_SIU
69 select SND_SOC_WM8978
70 help
71 This option enables sound support for the SH7722 Migo-R board
72
50endmenu 73endmenu
diff --git a/sound/soc/sh/Makefile b/sound/soc/sh/Makefile
index a6997872f24e..8a5a19293bda 100644
--- a/sound/soc/sh/Makefile
+++ b/sound/soc/sh/Makefile
@@ -6,13 +6,19 @@ obj-$(CONFIG_SND_SOC_PCM_SH7760) += snd-soc-dma-sh7760.o
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 8snd-soc-fsi-objs := fsi.o
9snd-soc-siu-objs := siu_pcm.o siu_dai.o
9obj-$(CONFIG_SND_SOC_SH4_HAC) += snd-soc-hac.o 10obj-$(CONFIG_SND_SOC_SH4_HAC) += snd-soc-hac.o
10obj-$(CONFIG_SND_SOC_SH4_SSI) += snd-soc-ssi.o 11obj-$(CONFIG_SND_SOC_SH4_SSI) += snd-soc-ssi.o
11obj-$(CONFIG_SND_SOC_SH4_FSI) += snd-soc-fsi.o 12obj-$(CONFIG_SND_SOC_SH4_FSI) += snd-soc-fsi.o
13obj-$(CONFIG_SND_SOC_SH4_SIU) += snd-soc-siu.o
12 14
13## boards 15## boards
14snd-soc-sh7760-ac97-objs := sh7760-ac97.o 16snd-soc-sh7760-ac97-objs := sh7760-ac97.o
15snd-soc-fsi-ak4642-objs := fsi-ak4642.o 17snd-soc-fsi-ak4642-objs := fsi-ak4642.o
18snd-soc-fsi-da7210-objs := fsi-da7210.o
19snd-soc-migor-objs := migor.o
16 20
17obj-$(CONFIG_SND_SH7760_AC97) += snd-soc-sh7760-ac97.o 21obj-$(CONFIG_SND_SH7760_AC97) += snd-soc-sh7760-ac97.o
18obj-$(CONFIG_SND_FSI_AK4642) += snd-soc-fsi-ak4642.o 22obj-$(CONFIG_SND_FSI_AK4642) += snd-soc-fsi-ak4642.o
23obj-$(CONFIG_SND_FSI_DA7210) += snd-soc-fsi-da7210.o
24obj-$(CONFIG_SND_SIU_MIGOR) += snd-soc-migor.o
diff --git a/sound/soc/sh/fsi-da7210.c b/sound/soc/sh/fsi-da7210.c
new file mode 100644
index 000000000000..33b4d177f466
--- /dev/null
+++ b/sound/soc/sh/fsi-da7210.c
@@ -0,0 +1,83 @@
1/*
2 * fsi-da7210.c
3 *
4 * Copyright (C) 2009 Renesas Solutions Corp.
5 * Kuninori Morimoto <morimoto.kuninori@renesas.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 */
12
13#include <linux/interrupt.h>
14#include <linux/platform_device.h>
15#include <linux/io.h>
16#include <linux/i2c.h>
17#include <sound/core.h>
18#include <sound/pcm.h>
19#include <sound/pcm_params.h>
20#include <sound/soc.h>
21#include <sound/soc-dapm.h>
22
23#include <sound/sh_fsi.h>
24#include "../codecs/da7210.h"
25
26static int fsi_da7210_init(struct snd_soc_codec *codec)
27{
28 return snd_soc_dai_set_fmt(&da7210_dai,
29 SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
30 SND_SOC_DAIFMT_CBM_CFM);
31}
32
33static struct snd_soc_dai_link fsi_da7210_dai = {
34 .name = "DA7210",
35 .stream_name = "DA7210",
36 .cpu_dai = &fsi_soc_dai[1], /* FSI B */
37 .codec_dai = &da7210_dai,
38 .init = fsi_da7210_init,
39};
40
41static struct snd_soc_card fsi_soc_card = {
42 .name = "FSI",
43 .platform = &fsi_soc_platform,
44 .dai_link = &fsi_da7210_dai,
45 .num_links = 1,
46};
47
48static struct snd_soc_device fsi_da7210_snd_devdata = {
49 .card = &fsi_soc_card,
50 .codec_dev = &soc_codec_dev_da7210,
51};
52
53static struct platform_device *fsi_da7210_snd_device;
54
55static int __init fsi_da7210_sound_init(void)
56{
57 int ret;
58
59 fsi_da7210_snd_device = platform_device_alloc("soc-audio", -1);
60 if (!fsi_da7210_snd_device)
61 return -ENOMEM;
62
63 platform_set_drvdata(fsi_da7210_snd_device, &fsi_da7210_snd_devdata);
64 fsi_da7210_snd_devdata.dev = &fsi_da7210_snd_device->dev;
65 ret = platform_device_add(fsi_da7210_snd_device);
66 if (ret)
67 platform_device_put(fsi_da7210_snd_device);
68
69 return ret;
70}
71
72static void __exit fsi_da7210_sound_exit(void)
73{
74 platform_device_unregister(fsi_da7210_snd_device);
75}
76
77module_init(fsi_da7210_sound_init);
78module_exit(fsi_da7210_sound_exit);
79
80/* Module information */
81MODULE_DESCRIPTION("ALSA SoC FSI DA2710");
82MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>");
83MODULE_LICENSE("GPL");
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index 42813b808389..993abb730dfa 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -67,6 +67,7 @@
67/* DOFF_ST */ 67/* DOFF_ST */
68#define ERR_OVER 0x00000010 68#define ERR_OVER 0x00000010
69#define ERR_UNDER 0x00000001 69#define ERR_UNDER 0x00000001
70#define ST_ERR (ERR_OVER | ERR_UNDER)
70 71
71/* CLK_RST */ 72/* CLK_RST */
72#define B_CLK 0x00000010 73#define B_CLK 0x00000010
@@ -92,6 +93,7 @@
92struct fsi_priv { 93struct fsi_priv {
93 void __iomem *base; 94 void __iomem *base;
94 struct snd_pcm_substream *substream; 95 struct snd_pcm_substream *substream;
96 struct fsi_master *master;
95 97
96 int fifo_max; 98 int fifo_max;
97 int chan; 99 int chan;
@@ -108,10 +110,9 @@ struct fsi_master {
108 struct fsi_priv fsia; 110 struct fsi_priv fsia;
109 struct fsi_priv fsib; 111 struct fsi_priv fsib;
110 struct sh_fsi_platform_info *info; 112 struct sh_fsi_platform_info *info;
113 spinlock_t lock;
111}; 114};
112 115
113static struct fsi_master *master;
114
115/************************************************************************ 116/************************************************************************
116 117
117 118
@@ -119,35 +120,35 @@ static struct fsi_master *master;
119 120
120 121
121************************************************************************/ 122************************************************************************/
122static int __fsi_reg_write(u32 reg, u32 data) 123static void __fsi_reg_write(u32 reg, u32 data)
123{ 124{
124 /* valid data area is 24bit */ 125 /* valid data area is 24bit */
125 data &= 0x00ffffff; 126 data &= 0x00ffffff;
126 127
127 return ctrl_outl(data, reg); 128 __raw_writel(data, reg);
128} 129}
129 130
130static u32 __fsi_reg_read(u32 reg) 131static u32 __fsi_reg_read(u32 reg)
131{ 132{
132 return ctrl_inl(reg); 133 return __raw_readl(reg);
133} 134}
134 135
135static int __fsi_reg_mask_set(u32 reg, u32 mask, u32 data) 136static void __fsi_reg_mask_set(u32 reg, u32 mask, u32 data)
136{ 137{
137 u32 val = __fsi_reg_read(reg); 138 u32 val = __fsi_reg_read(reg);
138 139
139 val &= ~mask; 140 val &= ~mask;
140 val |= data & mask; 141 val |= data & mask;
141 142
142 return __fsi_reg_write(reg, val); 143 __fsi_reg_write(reg, val);
143} 144}
144 145
145static int fsi_reg_write(struct fsi_priv *fsi, u32 reg, u32 data) 146static void fsi_reg_write(struct fsi_priv *fsi, u32 reg, u32 data)
146{ 147{
147 if (reg > REG_END) 148 if (reg > REG_END)
148 return -1; 149 return;
149 150
150 return __fsi_reg_write((u32)(fsi->base + reg), data); 151 __fsi_reg_write((u32)(fsi->base + reg), data);
151} 152}
152 153
153static u32 fsi_reg_read(struct fsi_priv *fsi, u32 reg) 154static u32 fsi_reg_read(struct fsi_priv *fsi, u32 reg)
@@ -158,39 +159,55 @@ static u32 fsi_reg_read(struct fsi_priv *fsi, u32 reg)
158 return __fsi_reg_read((u32)(fsi->base + reg)); 159 return __fsi_reg_read((u32)(fsi->base + reg));
159} 160}
160 161
161static int fsi_reg_mask_set(struct fsi_priv *fsi, u32 reg, u32 mask, u32 data) 162static void fsi_reg_mask_set(struct fsi_priv *fsi, u32 reg, u32 mask, u32 data)
162{ 163{
163 if (reg > REG_END) 164 if (reg > REG_END)
164 return -1; 165 return;
165 166
166 return __fsi_reg_mask_set((u32)(fsi->base + reg), mask, data); 167 __fsi_reg_mask_set((u32)(fsi->base + reg), mask, data);
167} 168}
168 169
169static int fsi_master_write(u32 reg, u32 data) 170static void fsi_master_write(struct fsi_master *master, u32 reg, u32 data)
170{ 171{
172 unsigned long flags;
173
171 if ((reg < MREG_START) || 174 if ((reg < MREG_START) ||
172 (reg > MREG_END)) 175 (reg > MREG_END))
173 return -1; 176 return;
174 177
175 return __fsi_reg_write((u32)(master->base + reg), data); 178 spin_lock_irqsave(&master->lock, flags);
179 __fsi_reg_write((u32)(master->base + reg), data);
180 spin_unlock_irqrestore(&master->lock, flags);
176} 181}
177 182
178static u32 fsi_master_read(u32 reg) 183static u32 fsi_master_read(struct fsi_master *master, u32 reg)
179{ 184{
185 u32 ret;
186 unsigned long flags;
187
180 if ((reg < MREG_START) || 188 if ((reg < MREG_START) ||
181 (reg > MREG_END)) 189 (reg > MREG_END))
182 return 0; 190 return 0;
183 191
184 return __fsi_reg_read((u32)(master->base + reg)); 192 spin_lock_irqsave(&master->lock, flags);
193 ret = __fsi_reg_read((u32)(master->base + reg));
194 spin_unlock_irqrestore(&master->lock, flags);
195
196 return ret;
185} 197}
186 198
187static int fsi_master_mask_set(u32 reg, u32 mask, u32 data) 199static void fsi_master_mask_set(struct fsi_master *master,
200 u32 reg, u32 mask, u32 data)
188{ 201{
202 unsigned long flags;
203
189 if ((reg < MREG_START) || 204 if ((reg < MREG_START) ||
190 (reg > MREG_END)) 205 (reg > MREG_END))
191 return -1; 206 return;
192 207
193 return __fsi_reg_mask_set((u32)(master->base + reg), mask, data); 208 spin_lock_irqsave(&master->lock, flags);
209 __fsi_reg_mask_set((u32)(master->base + reg), mask, data);
210 spin_unlock_irqrestore(&master->lock, flags);
194} 211}
195 212
196/************************************************************************ 213/************************************************************************
@@ -200,43 +217,35 @@ static int fsi_master_mask_set(u32 reg, u32 mask, u32 data)
200 217
201 218
202************************************************************************/ 219************************************************************************/
203static struct fsi_priv *fsi_get(struct snd_pcm_substream *substream) 220static struct fsi_master *fsi_get_master(struct fsi_priv *fsi)
204{ 221{
205 struct snd_soc_pcm_runtime *rtd; 222 return fsi->master;
206 struct fsi_priv *fsi = NULL; 223}
207 224
208 if (!substream || !master) 225static int fsi_is_port_a(struct fsi_priv *fsi)
209 return NULL; 226{
227 return fsi->master->base == fsi->base;
228}
210 229
211 rtd = substream->private_data; 230static struct snd_soc_dai *fsi_get_dai(struct snd_pcm_substream *substream)
212 switch (rtd->dai->cpu_dai->id) { 231{
213 case 0: 232 struct snd_soc_pcm_runtime *rtd = substream->private_data;
214 fsi = &master->fsia; 233 struct snd_soc_dai_link *machine = rtd->dai;
215 break;
216 case 1:
217 fsi = &master->fsib;
218 break;
219 }
220 234
221 return fsi; 235 return machine->cpu_dai;
222} 236}
223 237
224static int fsi_is_port_a(struct fsi_priv *fsi) 238static struct fsi_priv *fsi_get_priv(struct snd_pcm_substream *substream)
225{ 239{
226 /* return 240 struct snd_soc_dai *dai = fsi_get_dai(substream);
227 * 1 : port a
228 * 0 : port b
229 */
230 241
231 if (fsi == &master->fsia) 242 return dai->private_data;
232 return 1;
233
234 return 0;
235} 243}
236 244
237static u32 fsi_get_info_flags(struct fsi_priv *fsi) 245static u32 fsi_get_info_flags(struct fsi_priv *fsi)
238{ 246{
239 int is_porta = fsi_is_port_a(fsi); 247 int is_porta = fsi_is_port_a(fsi);
248 struct fsi_master *master = fsi_get_master(fsi);
240 249
241 return is_porta ? master->info->porta_flags : 250 return is_porta ? master->info->porta_flags :
242 master->info->portb_flags; 251 master->info->portb_flags;
@@ -314,27 +323,30 @@ static int fsi_get_fifo_residue(struct fsi_priv *fsi, int is_play)
314static void fsi_irq_enable(struct fsi_priv *fsi, int is_play) 323static void fsi_irq_enable(struct fsi_priv *fsi, int is_play)
315{ 324{
316 u32 data = fsi_port_ab_io_bit(fsi, is_play); 325 u32 data = fsi_port_ab_io_bit(fsi, is_play);
326 struct fsi_master *master = fsi_get_master(fsi);
317 327
318 fsi_master_mask_set(IMSK, data, data); 328 fsi_master_mask_set(master, IMSK, data, data);
319 fsi_master_mask_set(IEMSK, data, data); 329 fsi_master_mask_set(master, IEMSK, data, data);
320} 330}
321 331
322static void fsi_irq_disable(struct fsi_priv *fsi, int is_play) 332static void fsi_irq_disable(struct fsi_priv *fsi, int is_play)
323{ 333{
324 u32 data = fsi_port_ab_io_bit(fsi, is_play); 334 u32 data = fsi_port_ab_io_bit(fsi, is_play);
335 struct fsi_master *master = fsi_get_master(fsi);
325 336
326 fsi_master_mask_set(IMSK, data, 0); 337 fsi_master_mask_set(master, IMSK, data, 0);
327 fsi_master_mask_set(IEMSK, data, 0); 338 fsi_master_mask_set(master, IEMSK, data, 0);
328} 339}
329 340
330static void fsi_clk_ctrl(struct fsi_priv *fsi, int enable) 341static void fsi_clk_ctrl(struct fsi_priv *fsi, int enable)
331{ 342{
332 u32 val = fsi_is_port_a(fsi) ? (1 << 0) : (1 << 4); 343 u32 val = fsi_is_port_a(fsi) ? (1 << 0) : (1 << 4);
344 struct fsi_master *master = fsi_get_master(fsi);
333 345
334 if (enable) 346 if (enable)
335 fsi_master_mask_set(CLK_RST, val, val); 347 fsi_master_mask_set(master, CLK_RST, val, val);
336 else 348 else
337 fsi_master_mask_set(CLK_RST, val, 0); 349 fsi_master_mask_set(master, CLK_RST, val, 0);
338} 350}
339 351
340static void fsi_irq_init(struct fsi_priv *fsi, int is_play) 352static void fsi_irq_init(struct fsi_priv *fsi, int is_play)
@@ -355,43 +367,46 @@ static void fsi_irq_init(struct fsi_priv *fsi, int is_play)
355 fsi_reg_mask_set(fsi, ctrl, FIFO_CLR, FIFO_CLR); 367 fsi_reg_mask_set(fsi, ctrl, FIFO_CLR, FIFO_CLR);
356 368
357 /* clear interrupt factor */ 369 /* clear interrupt factor */
358 fsi_master_mask_set(INT_ST, data, 0); 370 fsi_master_mask_set(fsi_get_master(fsi), INT_ST, data, 0);
359} 371}
360 372
361static void fsi_soft_all_reset(void) 373static void fsi_soft_all_reset(struct fsi_master *master)
362{ 374{
363 u32 status = fsi_master_read(SOFT_RST); 375 u32 status = fsi_master_read(master, SOFT_RST);
364 376
365 /* port AB reset */ 377 /* port AB reset */
366 status &= 0x000000ff; 378 status &= 0x000000ff;
367 fsi_master_write(SOFT_RST, status); 379 fsi_master_write(master, SOFT_RST, status);
368 mdelay(10); 380 mdelay(10);
369 381
370 /* soft reset */ 382 /* soft reset */
371 status &= 0x000000f0; 383 status &= 0x000000f0;
372 fsi_master_write(SOFT_RST, status); 384 fsi_master_write(master, SOFT_RST, status);
373 status |= 0x00000001; 385 status |= 0x00000001;
374 fsi_master_write(SOFT_RST, status); 386 fsi_master_write(master, SOFT_RST, status);
375 mdelay(10); 387 mdelay(10);
376} 388}
377 389
378/* playback interrupt */ 390/* playback interrupt */
379static int fsi_data_push(struct fsi_priv *fsi) 391static int fsi_data_push(struct fsi_priv *fsi, int startup)
380{ 392{
381 struct snd_pcm_runtime *runtime; 393 struct snd_pcm_runtime *runtime;
382 struct snd_pcm_substream *substream = NULL; 394 struct snd_pcm_substream *substream = NULL;
395 u32 status;
383 int send; 396 int send;
384 int fifo_free; 397 int fifo_free;
385 int width; 398 int width;
386 u8 *start; 399 u8 *start;
387 int i; 400 int i, over_period;
388 401
389 if (!fsi || 402 if (!fsi ||
390 !fsi->substream || 403 !fsi->substream ||
391 !fsi->substream->runtime) 404 !fsi->substream->runtime)
392 return -EINVAL; 405 return -EINVAL;
393 406
394 runtime = fsi->substream->runtime; 407 over_period = 0;
408 substream = fsi->substream;
409 runtime = substream->runtime;
395 410
396 /* FSI FIFO has limit. 411 /* FSI FIFO has limit.
397 * So, this driver can not send periods data at a time 412 * So, this driver can not send periods data at a time
@@ -399,7 +414,7 @@ static int fsi_data_push(struct fsi_priv *fsi)
399 if (fsi->byte_offset >= 414 if (fsi->byte_offset >=
400 fsi->period_len * (fsi->periods + 1)) { 415 fsi->period_len * (fsi->periods + 1)) {
401 416
402 substream = fsi->substream; 417 over_period = 1;
403 fsi->periods = (fsi->periods + 1) % runtime->periods; 418 fsi->periods = (fsi->periods + 1) % runtime->periods;
404 419
405 if (0 == fsi->periods) 420 if (0 == fsi->periods)
@@ -438,30 +453,44 @@ static int fsi_data_push(struct fsi_priv *fsi)
438 453
439 fsi->byte_offset += send * width; 454 fsi->byte_offset += send * width;
440 455
456 status = fsi_reg_read(fsi, DOFF_ST);
457 if (!startup) {
458 struct snd_soc_dai *dai = fsi_get_dai(substream);
459
460 if (status & ERR_OVER)
461 dev_err(dai->dev, "over run\n");
462 if (status & ERR_UNDER)
463 dev_err(dai->dev, "under run\n");
464 }
465 fsi_reg_write(fsi, DOFF_ST, 0);
466
441 fsi_irq_enable(fsi, 1); 467 fsi_irq_enable(fsi, 1);
442 468
443 if (substream) 469 if (over_period)
444 snd_pcm_period_elapsed(substream); 470 snd_pcm_period_elapsed(substream);
445 471
446 return 0; 472 return 0;
447} 473}
448 474
449static int fsi_data_pop(struct fsi_priv *fsi) 475static int fsi_data_pop(struct fsi_priv *fsi, int startup)
450{ 476{
451 struct snd_pcm_runtime *runtime; 477 struct snd_pcm_runtime *runtime;
452 struct snd_pcm_substream *substream = NULL; 478 struct snd_pcm_substream *substream = NULL;
479 u32 status;
453 int free; 480 int free;
454 int fifo_fill; 481 int fifo_fill;
455 int width; 482 int width;
456 u8 *start; 483 u8 *start;
457 int i; 484 int i, over_period;
458 485
459 if (!fsi || 486 if (!fsi ||
460 !fsi->substream || 487 !fsi->substream ||
461 !fsi->substream->runtime) 488 !fsi->substream->runtime)
462 return -EINVAL; 489 return -EINVAL;
463 490
464 runtime = fsi->substream->runtime; 491 over_period = 0;
492 substream = fsi->substream;
493 runtime = substream->runtime;
465 494
466 /* FSI FIFO has limit. 495 /* FSI FIFO has limit.
467 * So, this driver can not send periods data at a time 496 * So, this driver can not send periods data at a time
@@ -469,7 +498,7 @@ static int fsi_data_pop(struct fsi_priv *fsi)
469 if (fsi->byte_offset >= 498 if (fsi->byte_offset >=
470 fsi->period_len * (fsi->periods + 1)) { 499 fsi->period_len * (fsi->periods + 1)) {
471 500
472 substream = fsi->substream; 501 over_period = 1;
473 fsi->periods = (fsi->periods + 1) % runtime->periods; 502 fsi->periods = (fsi->periods + 1) % runtime->periods;
474 503
475 if (0 == fsi->periods) 504 if (0 == fsi->periods)
@@ -507,9 +536,20 @@ static int fsi_data_pop(struct fsi_priv *fsi)
507 536
508 fsi->byte_offset += fifo_fill * width; 537 fsi->byte_offset += fifo_fill * width;
509 538
539 status = fsi_reg_read(fsi, DIFF_ST);
540 if (!startup) {
541 struct snd_soc_dai *dai = fsi_get_dai(substream);
542
543 if (status & ERR_OVER)
544 dev_err(dai->dev, "over run\n");
545 if (status & ERR_UNDER)
546 dev_err(dai->dev, "under run\n");
547 }
548 fsi_reg_write(fsi, DIFF_ST, 0);
549
510 fsi_irq_enable(fsi, 0); 550 fsi_irq_enable(fsi, 0);
511 551
512 if (substream) 552 if (over_period)
513 snd_pcm_period_elapsed(substream); 553 snd_pcm_period_elapsed(substream);
514 554
515 return 0; 555 return 0;
@@ -517,23 +557,24 @@ static int fsi_data_pop(struct fsi_priv *fsi)
517 557
518static irqreturn_t fsi_interrupt(int irq, void *data) 558static irqreturn_t fsi_interrupt(int irq, void *data)
519{ 559{
520 u32 status = fsi_master_read(SOFT_RST) & ~0x00000010; 560 struct fsi_master *master = data;
521 u32 int_st = fsi_master_read(INT_ST); 561 u32 status = fsi_master_read(master, SOFT_RST) & ~0x00000010;
562 u32 int_st = fsi_master_read(master, INT_ST);
522 563
523 /* clear irq status */ 564 /* clear irq status */
524 fsi_master_write(SOFT_RST, status); 565 fsi_master_write(master, SOFT_RST, status);
525 fsi_master_write(SOFT_RST, status | 0x00000010); 566 fsi_master_write(master, SOFT_RST, status | 0x00000010);
526 567
527 if (int_st & INT_A_OUT) 568 if (int_st & INT_A_OUT)
528 fsi_data_push(&master->fsia); 569 fsi_data_push(&master->fsia, 0);
529 if (int_st & INT_B_OUT) 570 if (int_st & INT_B_OUT)
530 fsi_data_push(&master->fsib); 571 fsi_data_push(&master->fsib, 0);
531 if (int_st & INT_A_IN) 572 if (int_st & INT_A_IN)
532 fsi_data_pop(&master->fsia); 573 fsi_data_pop(&master->fsia, 0);
533 if (int_st & INT_B_IN) 574 if (int_st & INT_B_IN)
534 fsi_data_pop(&master->fsib); 575 fsi_data_pop(&master->fsib, 0);
535 576
536 fsi_master_write(INT_ST, 0x0000000); 577 fsi_master_write(master, INT_ST, 0x0000000);
537 578
538 return IRQ_HANDLED; 579 return IRQ_HANDLED;
539} 580}
@@ -548,7 +589,7 @@ static irqreturn_t fsi_interrupt(int irq, void *data)
548static int fsi_dai_startup(struct snd_pcm_substream *substream, 589static int fsi_dai_startup(struct snd_pcm_substream *substream,
549 struct snd_soc_dai *dai) 590 struct snd_soc_dai *dai)
550{ 591{
551 struct fsi_priv *fsi = fsi_get(substream); 592 struct fsi_priv *fsi = fsi_get_priv(substream);
552 const char *msg; 593 const char *msg;
553 u32 flags = fsi_get_info_flags(fsi); 594 u32 flags = fsi_get_info_flags(fsi);
554 u32 fmt; 595 u32 fmt;
@@ -667,7 +708,7 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream,
667static void fsi_dai_shutdown(struct snd_pcm_substream *substream, 708static void fsi_dai_shutdown(struct snd_pcm_substream *substream,
668 struct snd_soc_dai *dai) 709 struct snd_soc_dai *dai)
669{ 710{
670 struct fsi_priv *fsi = fsi_get(substream); 711 struct fsi_priv *fsi = fsi_get_priv(substream);
671 int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; 712 int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
672 713
673 fsi_irq_disable(fsi, is_play); 714 fsi_irq_disable(fsi, is_play);
@@ -679,7 +720,7 @@ static void fsi_dai_shutdown(struct snd_pcm_substream *substream,
679static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, 720static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
680 struct snd_soc_dai *dai) 721 struct snd_soc_dai *dai)
681{ 722{
682 struct fsi_priv *fsi = fsi_get(substream); 723 struct fsi_priv *fsi = fsi_get_priv(substream);
683 struct snd_pcm_runtime *runtime = substream->runtime; 724 struct snd_pcm_runtime *runtime = substream->runtime;
684 int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; 725 int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
685 int ret = 0; 726 int ret = 0;
@@ -689,7 +730,7 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
689 fsi_stream_push(fsi, substream, 730 fsi_stream_push(fsi, substream,
690 frames_to_bytes(runtime, runtime->buffer_size), 731 frames_to_bytes(runtime, runtime->buffer_size),
691 frames_to_bytes(runtime, runtime->period_size)); 732 frames_to_bytes(runtime, runtime->period_size));
692 ret = is_play ? fsi_data_push(fsi) : fsi_data_pop(fsi); 733 ret = is_play ? fsi_data_push(fsi, 1) : fsi_data_pop(fsi, 1);
693 break; 734 break;
694 case SNDRV_PCM_TRIGGER_STOP: 735 case SNDRV_PCM_TRIGGER_STOP:
695 fsi_irq_disable(fsi, is_play); 736 fsi_irq_disable(fsi, is_play);
@@ -760,7 +801,7 @@ static int fsi_hw_free(struct snd_pcm_substream *substream)
760static snd_pcm_uframes_t fsi_pointer(struct snd_pcm_substream *substream) 801static snd_pcm_uframes_t fsi_pointer(struct snd_pcm_substream *substream)
761{ 802{
762 struct snd_pcm_runtime *runtime = substream->runtime; 803 struct snd_pcm_runtime *runtime = substream->runtime;
763 struct fsi_priv *fsi = fsi_get(substream); 804 struct fsi_priv *fsi = fsi_get_priv(substream);
764 long location; 805 long location;
765 806
766 location = (fsi->byte_offset - 1); 807 location = (fsi->byte_offset - 1);
@@ -870,10 +911,16 @@ EXPORT_SYMBOL_GPL(fsi_soc_platform);
870************************************************************************/ 911************************************************************************/
871static int fsi_probe(struct platform_device *pdev) 912static int fsi_probe(struct platform_device *pdev)
872{ 913{
914 struct fsi_master *master;
873 struct resource *res; 915 struct resource *res;
874 unsigned int irq; 916 unsigned int irq;
875 int ret; 917 int ret;
876 918
919 if (0 != pdev->id) {
920 dev_err(&pdev->dev, "current fsi support id 0 only now\n");
921 return -ENODEV;
922 }
923
877 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 924 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
878 irq = platform_get_irq(pdev, 0); 925 irq = platform_get_irq(pdev, 0);
879 if (!res || (int)irq <= 0) { 926 if (!res || (int)irq <= 0) {
@@ -899,15 +946,20 @@ static int fsi_probe(struct platform_device *pdev)
899 master->irq = irq; 946 master->irq = irq;
900 master->info = pdev->dev.platform_data; 947 master->info = pdev->dev.platform_data;
901 master->fsia.base = master->base; 948 master->fsia.base = master->base;
949 master->fsia.master = master;
902 master->fsib.base = master->base + 0x40; 950 master->fsib.base = master->base + 0x40;
951 master->fsib.master = master;
952 spin_lock_init(&master->lock);
903 953
904 pm_runtime_enable(&pdev->dev); 954 pm_runtime_enable(&pdev->dev);
905 pm_runtime_resume(&pdev->dev); 955 pm_runtime_resume(&pdev->dev);
906 956
907 fsi_soc_dai[0].dev = &pdev->dev; 957 fsi_soc_dai[0].dev = &pdev->dev;
958 fsi_soc_dai[0].private_data = &master->fsia;
908 fsi_soc_dai[1].dev = &pdev->dev; 959 fsi_soc_dai[1].dev = &pdev->dev;
960 fsi_soc_dai[1].private_data = &master->fsib;
909 961
910 fsi_soft_all_reset(); 962 fsi_soft_all_reset(master);
911 963
912 ret = request_irq(irq, &fsi_interrupt, IRQF_DISABLED, "fsi", master); 964 ret = request_irq(irq, &fsi_interrupt, IRQF_DISABLED, "fsi", master);
913 if (ret) { 965 if (ret) {
@@ -937,6 +989,10 @@ exit:
937 989
938static int fsi_remove(struct platform_device *pdev) 990static int fsi_remove(struct platform_device *pdev)
939{ 991{
992 struct fsi_master *master;
993
994 master = fsi_get_master(fsi_soc_dai[0].private_data);
995
940 snd_soc_unregister_dais(fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai)); 996 snd_soc_unregister_dais(fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai));
941 snd_soc_unregister_platform(&fsi_soc_platform); 997 snd_soc_unregister_platform(&fsi_soc_platform);
942 998
@@ -946,7 +1002,12 @@ static int fsi_remove(struct platform_device *pdev)
946 1002
947 iounmap(master->base); 1003 iounmap(master->base);
948 kfree(master); 1004 kfree(master);
949 master = NULL; 1005
1006 fsi_soc_dai[0].dev = NULL;
1007 fsi_soc_dai[0].private_data = NULL;
1008 fsi_soc_dai[1].dev = NULL;
1009 fsi_soc_dai[1].private_data = NULL;
1010
950 return 0; 1011 return 0;
951} 1012}
952 1013
diff --git a/sound/soc/sh/migor.c b/sound/soc/sh/migor.c
new file mode 100644
index 000000000000..b823a5c9b9bc
--- /dev/null
+++ b/sound/soc/sh/migor.c
@@ -0,0 +1,218 @@
1/*
2 * ALSA SoC driver for Migo-R
3 *
4 * Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/device.h>
12#include <linux/firmware.h>
13#include <linux/module.h>
14
15#include <asm/clock.h>
16
17#include <cpu/sh7722.h>
18
19#include <sound/core.h>
20#include <sound/pcm.h>
21#include <sound/soc.h>
22#include <sound/soc-dapm.h>
23
24#include "../codecs/wm8978.h"
25#include "siu.h"
26
27/* Default 8000Hz sampling frequency */
28static unsigned long codec_freq = 8000 * 512;
29
30static unsigned int use_count;
31
32/* External clock, sourced from the codec at the SIUMCKB pin */
33static unsigned long siumckb_recalc(struct clk *clk)
34{
35 return codec_freq;
36}
37
38static struct clk_ops siumckb_clk_ops = {
39 .recalc = siumckb_recalc,
40};
41
42static struct clk siumckb_clk = {
43 .name = "siumckb_clk",
44 .id = -1,
45 .ops = &siumckb_clk_ops,
46 .rate = 0, /* initialised at run-time */
47};
48
49static int migor_hw_params(struct snd_pcm_substream *substream,
50 struct snd_pcm_hw_params *params)
51{
52 struct snd_soc_pcm_runtime *rtd = substream->private_data;
53 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
54 int ret;
55 unsigned int rate = params_rate(params);
56
57 ret = snd_soc_dai_set_sysclk(codec_dai, WM8978_PLL, 13000000,
58 SND_SOC_CLOCK_IN);
59 if (ret < 0)
60 return ret;
61
62 ret = snd_soc_dai_set_clkdiv(codec_dai, WM8978_OPCLKRATE, rate * 512);
63 if (ret < 0)
64 return ret;
65
66 ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_NB_IF |
67 SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS);
68 if (ret < 0)
69 return ret;
70
71 ret = snd_soc_dai_set_fmt(rtd->dai->cpu_dai, SND_SOC_DAIFMT_NB_IF |
72 SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS);
73 if (ret < 0)
74 return ret;
75
76 codec_freq = rate * 512;
77 /*
78 * This propagates the parent frequency change to children and
79 * recalculates the frequency table
80 */
81 clk_set_rate(&siumckb_clk, codec_freq);
82 dev_dbg(codec_dai->dev, "%s: configure %luHz\n", __func__, codec_freq);
83
84 ret = snd_soc_dai_set_sysclk(rtd->dai->cpu_dai, SIU_CLKB_EXT,
85 codec_freq / 2, SND_SOC_CLOCK_IN);
86
87 if (!ret)
88 use_count++;
89
90 return ret;
91}
92
93static int migor_hw_free(struct snd_pcm_substream *substream)
94{
95 struct snd_soc_pcm_runtime *rtd = substream->private_data;
96 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
97
98 if (use_count) {
99 use_count--;
100
101 if (!use_count)
102 snd_soc_dai_set_sysclk(codec_dai, WM8978_PLL, 0,
103 SND_SOC_CLOCK_IN);
104 } else {
105 dev_dbg(codec_dai->dev, "Unbalanced hw_free!\n");
106 }
107
108 return 0;
109}
110
111static struct snd_soc_ops migor_dai_ops = {
112 .hw_params = migor_hw_params,
113 .hw_free = migor_hw_free,
114};
115
116static const struct snd_soc_dapm_widget migor_dapm_widgets[] = {
117 SND_SOC_DAPM_HP("Headphone", NULL),
118 SND_SOC_DAPM_MIC("Onboard Microphone", NULL),
119 SND_SOC_DAPM_MIC("External Microphone", NULL),
120};
121
122static const struct snd_soc_dapm_route audio_map[] = {
123 /* Headphone output connected to LHP/RHP, enable OUT4 for VMID */
124 { "Headphone", NULL, "OUT4 VMID" },
125 { "OUT4 VMID", NULL, "LHP" },
126 { "OUT4 VMID", NULL, "RHP" },
127
128 /* On-board microphone */
129 { "RMICN", NULL, "Mic Bias" },
130 { "RMICP", NULL, "Mic Bias" },
131 { "Mic Bias", NULL, "Onboard Microphone" },
132
133 /* External microphone */
134 { "LMICN", NULL, "Mic Bias" },
135 { "LMICP", NULL, "Mic Bias" },
136 { "Mic Bias", NULL, "External Microphone" },
137};
138
139static int migor_dai_init(struct snd_soc_codec *codec)
140{
141 snd_soc_dapm_new_controls(codec, migor_dapm_widgets,
142 ARRAY_SIZE(migor_dapm_widgets));
143
144 snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
145
146 return 0;
147}
148
149/* migor digital audio interface glue - connects codec <--> CPU */
150static struct snd_soc_dai_link migor_dai = {
151 .name = "wm8978",
152 .stream_name = "WM8978",
153 .cpu_dai = &siu_i2s_dai,
154 .codec_dai = &wm8978_dai,
155 .ops = &migor_dai_ops,
156 .init = migor_dai_init,
157};
158
159/* migor audio machine driver */
160static struct snd_soc_card snd_soc_migor = {
161 .name = "Migo-R",
162 .platform = &siu_platform,
163 .dai_link = &migor_dai,
164 .num_links = 1,
165};
166
167/* migor audio subsystem */
168static struct snd_soc_device migor_snd_devdata = {
169 .card = &snd_soc_migor,
170 .codec_dev = &soc_codec_dev_wm8978,
171};
172
173static struct platform_device *migor_snd_device;
174
175static int __init migor_init(void)
176{
177 int ret;
178
179 ret = clk_register(&siumckb_clk);
180 if (ret < 0)
181 return ret;
182
183 /* Port number used on this machine: port B */
184 migor_snd_device = platform_device_alloc("soc-audio", 1);
185 if (!migor_snd_device) {
186 ret = -ENOMEM;
187 goto epdevalloc;
188 }
189
190 platform_set_drvdata(migor_snd_device, &migor_snd_devdata);
191
192 migor_snd_devdata.dev = &migor_snd_device->dev;
193
194 ret = platform_device_add(migor_snd_device);
195 if (ret)
196 goto epdevadd;
197
198 return 0;
199
200epdevadd:
201 platform_device_put(migor_snd_device);
202epdevalloc:
203 clk_unregister(&siumckb_clk);
204 return ret;
205}
206
207static void __exit migor_exit(void)
208{
209 clk_unregister(&siumckb_clk);
210 platform_device_unregister(migor_snd_device);
211}
212
213module_init(migor_init);
214module_exit(migor_exit);
215
216MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
217MODULE_DESCRIPTION("ALSA SoC Migor");
218MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/sh/siu.h b/sound/soc/sh/siu.h
new file mode 100644
index 000000000000..9cc04ab2bce7
--- /dev/null
+++ b/sound/soc/sh/siu.h
@@ -0,0 +1,193 @@
1/*
2 * siu.h - ALSA SoC driver for Renesas SH7343, SH7722 SIU peripheral.
3 *
4 * Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
5 * Copyright (C) 2006 Carlos Munoz <carlos@kenati.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#ifndef SIU_H
23#define SIU_H
24
25/* Common kernel and user-space firmware-building defines and types */
26
27#define YRAM0_SIZE (0x0040 / 4) /* 16 */
28#define YRAM1_SIZE (0x0080 / 4) /* 32 */
29#define YRAM2_SIZE (0x0040 / 4) /* 16 */
30#define YRAM3_SIZE (0x0080 / 4) /* 32 */
31#define YRAM4_SIZE (0x0080 / 4) /* 32 */
32#define YRAM_DEF_SIZE (YRAM0_SIZE + YRAM1_SIZE + YRAM2_SIZE + \
33 YRAM3_SIZE + YRAM4_SIZE)
34#define YRAM_FIR_SIZE (0x0400 / 4) /* 256 */
35#define YRAM_IIR_SIZE (0x0200 / 4) /* 128 */
36
37#define XRAM0_SIZE (0x0400 / 4) /* 256 */
38#define XRAM1_SIZE (0x0200 / 4) /* 128 */
39#define XRAM2_SIZE (0x0200 / 4) /* 128 */
40
41/* PRAM program array size */
42#define PRAM0_SIZE (0x0100 / 4) /* 64 */
43#define PRAM1_SIZE ((0x2000 - 0x0100) / 4) /* 1984 */
44
45#include <linux/types.h>
46
47struct siu_spb_param {
48 __u32 ab1a; /* input FIFO address */
49 __u32 ab0a; /* output FIFO address */
50 __u32 dir; /* 0=the ather except CPUOUTPUT, 1=CPUINPUT */
51 __u32 event; /* SPB program starting conditions */
52 __u32 stfifo; /* STFIFO register setting value */
53 __u32 trdat; /* TRDAT register setting value */
54};
55
56struct siu_firmware {
57 __u32 yram_fir_coeff[YRAM_FIR_SIZE];
58 __u32 pram0[PRAM0_SIZE];
59 __u32 pram1[PRAM1_SIZE];
60 __u32 yram0[YRAM0_SIZE];
61 __u32 yram1[YRAM1_SIZE];
62 __u32 yram2[YRAM2_SIZE];
63 __u32 yram3[YRAM3_SIZE];
64 __u32 yram4[YRAM4_SIZE];
65 __u32 spbpar_num;
66 struct siu_spb_param spbpar[32];
67};
68
69#ifdef __KERNEL__
70
71#include <linux/dmaengine.h>
72#include <linux/interrupt.h>
73#include <linux/io.h>
74
75#include <asm/dma-sh.h>
76
77#include <sound/core.h>
78#include <sound/pcm.h>
79#include <sound/soc-dai.h>
80
81#define SIU_PERIOD_BYTES_MAX 8192 /* DMA transfer/period size */
82#define SIU_PERIOD_BYTES_MIN 256 /* DMA transfer/period size */
83#define SIU_PERIODS_MAX 64 /* Max periods in buffer */
84#define SIU_PERIODS_MIN 4 /* Min periods in buffer */
85#define SIU_BUFFER_BYTES_MAX (SIU_PERIOD_BYTES_MAX * SIU_PERIODS_MAX)
86
87/* SIU ports: only one can be used at a time */
88enum {
89 SIU_PORT_A,
90 SIU_PORT_B,
91 SIU_PORT_NUM,
92};
93
94/* SIU clock configuration */
95enum {
96 SIU_CLKA_PLL,
97 SIU_CLKA_EXT,
98 SIU_CLKB_PLL,
99 SIU_CLKB_EXT
100};
101
102struct siu_info {
103 int port_id;
104 u32 __iomem *pram;
105 u32 __iomem *xram;
106 u32 __iomem *yram;
107 u32 __iomem *reg;
108 struct siu_firmware fw;
109};
110
111struct siu_stream {
112 struct tasklet_struct tasklet;
113 struct snd_pcm_substream *substream;
114 snd_pcm_format_t format;
115 size_t buf_bytes;
116 size_t period_bytes;
117 int cur_period; /* Period currently in dma */
118 u32 volume;
119 snd_pcm_sframes_t xfer_cnt; /* Number of frames */
120 u8 rw_flg; /* transfer status */
121 /* DMA status */
122 struct dma_chan *chan; /* DMA channel */
123 struct dma_async_tx_descriptor *tx_desc;
124 dma_cookie_t cookie;
125 struct sh_dmae_slave param;
126};
127
128struct siu_port {
129 unsigned long play_cap; /* Used to track full duplex */
130 struct snd_pcm *pcm;
131 struct siu_stream playback;
132 struct siu_stream capture;
133 u32 stfifo; /* STFIFO value from firmware */
134 u32 trdat; /* TRDAT value from firmware */
135};
136
137extern struct siu_port *siu_ports[SIU_PORT_NUM];
138
139static inline struct siu_port *siu_port_info(struct snd_pcm_substream *substream)
140{
141 struct platform_device *pdev =
142 to_platform_device(substream->pcm->card->dev);
143 return siu_ports[pdev->id];
144}
145
146/* Register access */
147static inline void siu_write32(u32 __iomem *addr, u32 val)
148{
149 __raw_writel(val, addr);
150}
151
152static inline u32 siu_read32(u32 __iomem *addr)
153{
154 return __raw_readl(addr);
155}
156
157/* SIU registers */
158#define SIU_IFCTL (0x000 / sizeof(u32))
159#define SIU_SRCTL (0x004 / sizeof(u32))
160#define SIU_SFORM (0x008 / sizeof(u32))
161#define SIU_CKCTL (0x00c / sizeof(u32))
162#define SIU_TRDAT (0x010 / sizeof(u32))
163#define SIU_STFIFO (0x014 / sizeof(u32))
164#define SIU_DPAK (0x01c / sizeof(u32))
165#define SIU_CKREV (0x020 / sizeof(u32))
166#define SIU_EVNTC (0x028 / sizeof(u32))
167#define SIU_SBCTL (0x040 / sizeof(u32))
168#define SIU_SBPSET (0x044 / sizeof(u32))
169#define SIU_SBFSTS (0x068 / sizeof(u32))
170#define SIU_SBDVCA (0x06c / sizeof(u32))
171#define SIU_SBDVCB (0x070 / sizeof(u32))
172#define SIU_SBACTIV (0x074 / sizeof(u32))
173#define SIU_DMAIA (0x090 / sizeof(u32))
174#define SIU_DMAIB (0x094 / sizeof(u32))
175#define SIU_DMAOA (0x098 / sizeof(u32))
176#define SIU_DMAOB (0x09c / sizeof(u32))
177#define SIU_DMAML (0x0a0 / sizeof(u32))
178#define SIU_SPSTS (0x0cc / sizeof(u32))
179#define SIU_SPCTL (0x0d0 / sizeof(u32))
180#define SIU_BRGASEL (0x100 / sizeof(u32))
181#define SIU_BRRA (0x104 / sizeof(u32))
182#define SIU_BRGBSEL (0x108 / sizeof(u32))
183#define SIU_BRRB (0x10c / sizeof(u32))
184
185extern struct snd_soc_platform siu_platform;
186extern struct snd_soc_dai siu_i2s_dai;
187
188int siu_init_port(int port, struct siu_port **port_info, struct snd_card *card);
189void siu_free_port(struct siu_port *port_info);
190
191#endif
192
193#endif /* SIU_H */
diff --git a/sound/soc/sh/siu_dai.c b/sound/soc/sh/siu_dai.c
new file mode 100644
index 000000000000..5452d19607e1
--- /dev/null
+++ b/sound/soc/sh/siu_dai.c
@@ -0,0 +1,847 @@
1/*
2 * siu_dai.c - ALSA SoC driver for Renesas SH7343, SH7722 SIU peripheral.
3 *
4 * Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
5 * Copyright (C) 2006 Carlos Munoz <carlos@kenati.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#include <linux/delay.h>
23#include <linux/firmware.h>
24#include <linux/pm_runtime.h>
25
26#include <asm/clock.h>
27#include <asm/siu.h>
28
29#include <sound/control.h>
30#include <sound/soc-dai.h>
31
32#include "siu.h"
33
34/* Board specifics */
35#if defined(CONFIG_CPU_SUBTYPE_SH7722)
36# define SIU_MAX_VOLUME 0x1000
37#else
38# define SIU_MAX_VOLUME 0x7fff
39#endif
40
41#define PRAM_SIZE 0x2000
42#define XRAM_SIZE 0x800
43#define YRAM_SIZE 0x800
44
45#define XRAM_OFFSET 0x4000
46#define YRAM_OFFSET 0x6000
47#define REG_OFFSET 0xc000
48
49#define PLAYBACK_ENABLED 1
50#define CAPTURE_ENABLED 2
51
52#define VOLUME_CAPTURE 0
53#define VOLUME_PLAYBACK 1
54#define DFLT_VOLUME_LEVEL 0x08000800
55
56/*
57 * SPDIF is only available on port A and on some SIU implementations it is only
58 * available for input. Due to the lack of hardware to test it, SPDIF is left
59 * disabled in this driver version
60 */
61struct format_flag {
62 u32 i2s;
63 u32 pcm;
64 u32 spdif;
65 u32 mask;
66};
67
68struct port_flag {
69 struct format_flag playback;
70 struct format_flag capture;
71};
72
73static struct port_flag siu_flags[SIU_PORT_NUM] = {
74 [SIU_PORT_A] = {
75 .playback = {
76 .i2s = 0x50000000,
77 .pcm = 0x40000000,
78 .spdif = 0x80000000, /* not on all SIU versions */
79 .mask = 0xd0000000,
80 },
81 .capture = {
82 .i2s = 0x05000000,
83 .pcm = 0x04000000,
84 .spdif = 0x08000000,
85 .mask = 0x0d000000,
86 },
87 },
88 [SIU_PORT_B] = {
89 .playback = {
90 .i2s = 0x00500000,
91 .pcm = 0x00400000,
92 .spdif = 0, /* impossible - turn off */
93 .mask = 0x00500000,
94 },
95 .capture = {
96 .i2s = 0x00050000,
97 .pcm = 0x00040000,
98 .spdif = 0, /* impossible - turn off */
99 .mask = 0x00050000,
100 },
101 },
102};
103
104static void siu_dai_start(struct siu_port *port_info)
105{
106 struct siu_info *info = siu_i2s_dai.private_data;
107 u32 __iomem *base = info->reg;
108
109 dev_dbg(port_info->pcm->card->dev, "%s\n", __func__);
110
111 /* Turn on SIU clock */
112 pm_runtime_get_sync(siu_i2s_dai.dev);
113
114 /* Issue software reset to siu */
115 siu_write32(base + SIU_SRCTL, 0);
116
117 /* Wait for the reset to take effect */
118 udelay(1);
119
120 port_info->stfifo = 0;
121 port_info->trdat = 0;
122
123 /* portA, portB, SIU operate */
124 siu_write32(base + SIU_SRCTL, 0x301);
125
126 /* portA=256fs, portB=256fs */
127 siu_write32(base + SIU_CKCTL, 0x40400000);
128
129 /* portA's BRG does not divide SIUCKA */
130 siu_write32(base + SIU_BRGASEL, 0);
131 siu_write32(base + SIU_BRRA, 0);
132
133 /* portB's BRG divides SIUCKB by half */
134 siu_write32(base + SIU_BRGBSEL, 1);
135 siu_write32(base + SIU_BRRB, 0);
136
137 siu_write32(base + SIU_IFCTL, 0x44440000);
138
139 /* portA: 32 bit/fs, master; portB: 32 bit/fs, master */
140 siu_write32(base + SIU_SFORM, 0x0c0c0000);
141
142 /*
143 * Volume levels: looks like the DSP firmware implements volume controls
144 * differently from what's described in the datasheet
145 */
146 siu_write32(base + SIU_SBDVCA, port_info->playback.volume);
147 siu_write32(base + SIU_SBDVCB, port_info->capture.volume);
148}
149
150static void siu_dai_stop(void)
151{
152 struct siu_info *info = siu_i2s_dai.private_data;
153 u32 __iomem *base = info->reg;
154
155 /* SIU software reset */
156 siu_write32(base + SIU_SRCTL, 0);
157
158 /* Turn off SIU clock */
159 pm_runtime_put_sync(siu_i2s_dai.dev);
160}
161
162static void siu_dai_spbAselect(struct siu_port *port_info)
163{
164 struct siu_info *info = siu_i2s_dai.private_data;
165 struct siu_firmware *fw = &info->fw;
166 u32 *ydef = fw->yram0;
167 u32 idx;
168
169 /* path A use */
170 if (!info->port_id)
171 idx = 1; /* portA */
172 else
173 idx = 2; /* portB */
174
175 ydef[0] = (fw->spbpar[idx].ab1a << 16) |
176 (fw->spbpar[idx].ab0a << 8) |
177 (fw->spbpar[idx].dir << 7) | 3;
178 ydef[1] = fw->yram0[1]; /* 0x03000300 */
179 ydef[2] = (16 / 2) << 24;
180 ydef[3] = fw->yram0[3]; /* 0 */
181 ydef[4] = fw->yram0[4]; /* 0 */
182 ydef[7] = fw->spbpar[idx].event;
183 port_info->stfifo |= fw->spbpar[idx].stfifo;
184 port_info->trdat |= fw->spbpar[idx].trdat;
185}
186
187static void siu_dai_spbBselect(struct siu_port *port_info)
188{
189 struct siu_info *info = siu_i2s_dai.private_data;
190 struct siu_firmware *fw = &info->fw;
191 u32 *ydef = fw->yram0;
192 u32 idx;
193
194 /* path B use */
195 if (!info->port_id)
196 idx = 7; /* portA */
197 else
198 idx = 8; /* portB */
199
200 ydef[5] = (fw->spbpar[idx].ab1a << 16) |
201 (fw->spbpar[idx].ab0a << 8) | 1;
202 ydef[6] = fw->spbpar[idx].event;
203 port_info->stfifo |= fw->spbpar[idx].stfifo;
204 port_info->trdat |= fw->spbpar[idx].trdat;
205}
206
207static void siu_dai_open(struct siu_stream *siu_stream)
208{
209 struct siu_info *info = siu_i2s_dai.private_data;
210 u32 __iomem *base = info->reg;
211 u32 srctl, ifctl;
212
213 srctl = siu_read32(base + SIU_SRCTL);
214 ifctl = siu_read32(base + SIU_IFCTL);
215
216 switch (info->port_id) {
217 case SIU_PORT_A:
218 /* portA operates */
219 srctl |= 0x200;
220 ifctl &= ~0xc2;
221 break;
222 case SIU_PORT_B:
223 /* portB operates */
224 srctl |= 0x100;
225 ifctl &= ~0x31;
226 break;
227 }
228
229 siu_write32(base + SIU_SRCTL, srctl);
230 /* Unmute and configure portA */
231 siu_write32(base + SIU_IFCTL, ifctl);
232}
233
234/*
235 * At the moment only fixed Left-upper, Left-lower, Right-upper, Right-lower
236 * packing is supported
237 */
238static void siu_dai_pcmdatapack(struct siu_stream *siu_stream)
239{
240 struct siu_info *info = siu_i2s_dai.private_data;
241 u32 __iomem *base = info->reg;
242 u32 dpak;
243
244 dpak = siu_read32(base + SIU_DPAK);
245
246 switch (info->port_id) {
247 case SIU_PORT_A:
248 dpak &= ~0xc0000000;
249 break;
250 case SIU_PORT_B:
251 dpak &= ~0x00c00000;
252 break;
253 }
254
255 siu_write32(base + SIU_DPAK, dpak);
256}
257
258static int siu_dai_spbstart(struct siu_port *port_info)
259{
260 struct siu_info *info = siu_i2s_dai.private_data;
261 u32 __iomem *base = info->reg;
262 struct siu_firmware *fw = &info->fw;
263 u32 *ydef = fw->yram0;
264 int cnt;
265 u32 __iomem *add;
266 u32 *ptr;
267
268 /* Load SPB Program in PRAM */
269 ptr = fw->pram0;
270 add = info->pram;
271 for (cnt = 0; cnt < PRAM0_SIZE; cnt++, add++, ptr++)
272 siu_write32(add, *ptr);
273
274 ptr = fw->pram1;
275 add = info->pram + (0x0100 / sizeof(u32));
276 for (cnt = 0; cnt < PRAM1_SIZE; cnt++, add++, ptr++)
277 siu_write32(add, *ptr);
278
279 /* XRAM initialization */
280 add = info->xram;
281 for (cnt = 0; cnt < XRAM0_SIZE + XRAM1_SIZE + XRAM2_SIZE; cnt++, add++)
282 siu_write32(add, 0);
283
284 /* YRAM variable area initialization */
285 add = info->yram;
286 for (cnt = 0; cnt < YRAM_DEF_SIZE; cnt++, add++)
287 siu_write32(add, ydef[cnt]);
288
289 /* YRAM FIR coefficient area initialization */
290 add = info->yram + (0x0200 / sizeof(u32));
291 for (cnt = 0; cnt < YRAM_FIR_SIZE; cnt++, add++)
292 siu_write32(add, fw->yram_fir_coeff[cnt]);
293
294 /* YRAM IIR coefficient area initialization */
295 add = info->yram + (0x0600 / sizeof(u32));
296 for (cnt = 0; cnt < YRAM_IIR_SIZE; cnt++, add++)
297 siu_write32(add, 0);
298
299 siu_write32(base + SIU_TRDAT, port_info->trdat);
300 port_info->trdat = 0x0;
301
302
303 /* SPB start condition: software */
304 siu_write32(base + SIU_SBACTIV, 0);
305 /* Start SPB */
306 siu_write32(base + SIU_SBCTL, 0xc0000000);
307 /* Wait for program to halt */
308 cnt = 0x10000;
309 while (--cnt && siu_read32(base + SIU_SBCTL) != 0x80000000)
310 cpu_relax();
311
312 if (!cnt)
313 return -EBUSY;
314
315 /* SPB program start address setting */
316 siu_write32(base + SIU_SBPSET, 0x00400000);
317 /* SPB hardware start(FIFOCTL source) */
318 siu_write32(base + SIU_SBACTIV, 0xc0000000);
319
320 return 0;
321}
322
323static void siu_dai_spbstop(struct siu_port *port_info)
324{
325 struct siu_info *info = siu_i2s_dai.private_data;
326 u32 __iomem *base = info->reg;
327
328 siu_write32(base + SIU_SBACTIV, 0);
329 /* SPB stop */
330 siu_write32(base + SIU_SBCTL, 0);
331
332 port_info->stfifo = 0;
333}
334
335/* API functions */
336
337/* Playback and capture hardware properties are identical */
338static struct snd_pcm_hardware siu_dai_pcm_hw = {
339 .info = SNDRV_PCM_INFO_INTERLEAVED,
340 .formats = SNDRV_PCM_FMTBIT_S16,
341 .rates = SNDRV_PCM_RATE_8000_48000,
342 .rate_min = 8000,
343 .rate_max = 48000,
344 .channels_min = 2,
345 .channels_max = 2,
346 .buffer_bytes_max = SIU_BUFFER_BYTES_MAX,
347 .period_bytes_min = SIU_PERIOD_BYTES_MIN,
348 .period_bytes_max = SIU_PERIOD_BYTES_MAX,
349 .periods_min = SIU_PERIODS_MIN,
350 .periods_max = SIU_PERIODS_MAX,
351};
352
353static int siu_dai_info_volume(struct snd_kcontrol *kctrl,
354 struct snd_ctl_elem_info *uinfo)
355{
356 struct siu_port *port_info = snd_kcontrol_chip(kctrl);
357
358 dev_dbg(port_info->pcm->card->dev, "%s\n", __func__);
359
360 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
361 uinfo->count = 2;
362 uinfo->value.integer.min = 0;
363 uinfo->value.integer.max = SIU_MAX_VOLUME;
364
365 return 0;
366}
367
368static int siu_dai_get_volume(struct snd_kcontrol *kctrl,
369 struct snd_ctl_elem_value *ucontrol)
370{
371 struct siu_port *port_info = snd_kcontrol_chip(kctrl);
372 struct device *dev = port_info->pcm->card->dev;
373 u32 vol;
374
375 dev_dbg(dev, "%s\n", __func__);
376
377 switch (kctrl->private_value) {
378 case VOLUME_PLAYBACK:
379 /* Playback is always on port 0 */
380 vol = port_info->playback.volume;
381 ucontrol->value.integer.value[0] = vol & 0xffff;
382 ucontrol->value.integer.value[1] = vol >> 16 & 0xffff;
383 break;
384 case VOLUME_CAPTURE:
385 /* Capture is always on port 1 */
386 vol = port_info->capture.volume;
387 ucontrol->value.integer.value[0] = vol & 0xffff;
388 ucontrol->value.integer.value[1] = vol >> 16 & 0xffff;
389 break;
390 default:
391 dev_err(dev, "%s() invalid private_value=%ld\n",
392 __func__, kctrl->private_value);
393 return -EINVAL;
394 }
395
396 return 0;
397}
398
399static int siu_dai_put_volume(struct snd_kcontrol *kctrl,
400 struct snd_ctl_elem_value *ucontrol)
401{
402 struct siu_port *port_info = snd_kcontrol_chip(kctrl);
403 struct device *dev = port_info->pcm->card->dev;
404 struct siu_info *info = siu_i2s_dai.private_data;
405 u32 __iomem *base = info->reg;
406 u32 new_vol;
407 u32 cur_vol;
408
409 dev_dbg(dev, "%s\n", __func__);
410
411 if (ucontrol->value.integer.value[0] < 0 ||
412 ucontrol->value.integer.value[0] > SIU_MAX_VOLUME ||
413 ucontrol->value.integer.value[1] < 0 ||
414 ucontrol->value.integer.value[1] > SIU_MAX_VOLUME)
415 return -EINVAL;
416
417 new_vol = ucontrol->value.integer.value[0] |
418 ucontrol->value.integer.value[1] << 16;
419
420 /* See comment above - DSP firmware implementation */
421 switch (kctrl->private_value) {
422 case VOLUME_PLAYBACK:
423 /* Playback is always on port 0 */
424 cur_vol = port_info->playback.volume;
425 siu_write32(base + SIU_SBDVCA, new_vol);
426 port_info->playback.volume = new_vol;
427 break;
428 case VOLUME_CAPTURE:
429 /* Capture is always on port 1 */
430 cur_vol = port_info->capture.volume;
431 siu_write32(base + SIU_SBDVCB, new_vol);
432 port_info->capture.volume = new_vol;
433 break;
434 default:
435 dev_err(dev, "%s() invalid private_value=%ld\n",
436 __func__, kctrl->private_value);
437 return -EINVAL;
438 }
439
440 if (cur_vol != new_vol)
441 return 1;
442
443 return 0;
444}
445
446static struct snd_kcontrol_new playback_controls = {
447 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
448 .name = "PCM Playback Volume",
449 .index = 0,
450 .info = siu_dai_info_volume,
451 .get = siu_dai_get_volume,
452 .put = siu_dai_put_volume,
453 .private_value = VOLUME_PLAYBACK,
454};
455
456static struct snd_kcontrol_new capture_controls = {
457 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
458 .name = "PCM Capture Volume",
459 .index = 0,
460 .info = siu_dai_info_volume,
461 .get = siu_dai_get_volume,
462 .put = siu_dai_put_volume,
463 .private_value = VOLUME_CAPTURE,
464};
465
466int siu_init_port(int port, struct siu_port **port_info, struct snd_card *card)
467{
468 struct device *dev = card->dev;
469 struct snd_kcontrol *kctrl;
470 int ret;
471
472 *port_info = kzalloc(sizeof(**port_info), GFP_KERNEL);
473 if (!*port_info)
474 return -ENOMEM;
475
476 dev_dbg(dev, "%s: port #%d@%p\n", __func__, port, *port_info);
477
478 (*port_info)->playback.volume = DFLT_VOLUME_LEVEL;
479 (*port_info)->capture.volume = DFLT_VOLUME_LEVEL;
480
481 /*
482 * Add mixer support. The SPB is used to change the volume. Both
483 * ports use the same SPB. Therefore, we only register one
484 * control instance since it will be used by both channels.
485 * In error case we continue without controls.
486 */
487 kctrl = snd_ctl_new1(&playback_controls, *port_info);
488 ret = snd_ctl_add(card, kctrl);
489 if (ret < 0)
490 dev_err(dev,
491 "failed to add playback controls %p port=%d err=%d\n",
492 kctrl, port, ret);
493
494 kctrl = snd_ctl_new1(&capture_controls, *port_info);
495 ret = snd_ctl_add(card, kctrl);
496 if (ret < 0)
497 dev_err(dev,
498 "failed to add capture controls %p port=%d err=%d\n",
499 kctrl, port, ret);
500
501 return 0;
502}
503
504void siu_free_port(struct siu_port *port_info)
505{
506 kfree(port_info);
507}
508
509static int siu_dai_startup(struct snd_pcm_substream *substream,
510 struct snd_soc_dai *dai)
511{
512 struct siu_info *info = siu_i2s_dai.private_data;
513 struct snd_pcm_runtime *rt = substream->runtime;
514 struct siu_port *port_info = siu_port_info(substream);
515 int ret;
516
517 dev_dbg(substream->pcm->card->dev, "%s: port=%d@%p\n", __func__,
518 info->port_id, port_info);
519
520 snd_soc_set_runtime_hwparams(substream, &siu_dai_pcm_hw);
521
522 ret = snd_pcm_hw_constraint_integer(rt, SNDRV_PCM_HW_PARAM_PERIODS);
523 if (unlikely(ret < 0))
524 return ret;
525
526 siu_dai_start(port_info);
527
528 return 0;
529}
530
531static void siu_dai_shutdown(struct snd_pcm_substream *substream,
532 struct snd_soc_dai *dai)
533{
534 struct siu_info *info = siu_i2s_dai.private_data;
535 struct siu_port *port_info = siu_port_info(substream);
536
537 dev_dbg(substream->pcm->card->dev, "%s: port=%d@%p\n", __func__,
538 info->port_id, port_info);
539
540 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
541 port_info->play_cap &= ~PLAYBACK_ENABLED;
542 else
543 port_info->play_cap &= ~CAPTURE_ENABLED;
544
545 /* Stop the siu if the other stream is not using it */
546 if (!port_info->play_cap) {
547 /* during stmread or stmwrite ? */
548 BUG_ON(port_info->playback.rw_flg || port_info->capture.rw_flg);
549 siu_dai_spbstop(port_info);
550 siu_dai_stop();
551 }
552}
553
554/* PCM part of siu_dai_playback_prepare() / siu_dai_capture_prepare() */
555static int siu_dai_prepare(struct snd_pcm_substream *substream,
556 struct snd_soc_dai *dai)
557{
558 struct siu_info *info = siu_i2s_dai.private_data;
559 struct snd_pcm_runtime *rt = substream->runtime;
560 struct siu_port *port_info = siu_port_info(substream);
561 struct siu_stream *siu_stream;
562 int self, ret;
563
564 dev_dbg(substream->pcm->card->dev,
565 "%s: port %d, active streams %lx, %d channels\n",
566 __func__, info->port_id, port_info->play_cap, rt->channels);
567
568 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
569 self = PLAYBACK_ENABLED;
570 siu_stream = &port_info->playback;
571 } else {
572 self = CAPTURE_ENABLED;
573 siu_stream = &port_info->capture;
574 }
575
576 /* Set up the siu if not already done */
577 if (!port_info->play_cap) {
578 siu_stream->rw_flg = 0; /* stream-data transfer flag */
579
580 siu_dai_spbAselect(port_info);
581 siu_dai_spbBselect(port_info);
582
583 siu_dai_open(siu_stream);
584
585 siu_dai_pcmdatapack(siu_stream);
586
587 ret = siu_dai_spbstart(port_info);
588 if (ret < 0)
589 goto fail;
590 }
591
592 port_info->play_cap |= self;
593
594fail:
595 return ret;
596}
597
598/*
599 * SIU can set bus format to I2S / PCM / SPDIF independently for playback and
600 * capture, however, the current API sets the bus format globally for a DAI.
601 */
602static int siu_dai_set_fmt(struct snd_soc_dai *dai,
603 unsigned int fmt)
604{
605 struct siu_info *info = siu_i2s_dai.private_data;
606 u32 __iomem *base = info->reg;
607 u32 ifctl;
608
609 dev_dbg(dai->dev, "%s: fmt 0x%x on port %d\n",
610 __func__, fmt, info->port_id);
611
612 if (info->port_id < 0)
613 return -ENODEV;
614
615 /* Here select between I2S / PCM / SPDIF */
616 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
617 case SND_SOC_DAIFMT_I2S:
618 ifctl = siu_flags[info->port_id].playback.i2s |
619 siu_flags[info->port_id].capture.i2s;
620 break;
621 case SND_SOC_DAIFMT_LEFT_J:
622 ifctl = siu_flags[info->port_id].playback.pcm |
623 siu_flags[info->port_id].capture.pcm;
624 break;
625 /* SPDIF disabled - see comment at the top */
626 default:
627 return -EINVAL;
628 }
629
630 ifctl |= ~(siu_flags[info->port_id].playback.mask |
631 siu_flags[info->port_id].capture.mask) &
632 siu_read32(base + SIU_IFCTL);
633 siu_write32(base + SIU_IFCTL, ifctl);
634
635 return 0;
636}
637
638static int siu_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
639 unsigned int freq, int dir)
640{
641 struct clk *siu_clk, *parent_clk;
642 char *siu_name, *parent_name;
643 int ret;
644
645 if (dir != SND_SOC_CLOCK_IN)
646 return -EINVAL;
647
648 dev_dbg(dai->dev, "%s: using clock %d\n", __func__, clk_id);
649
650 switch (clk_id) {
651 case SIU_CLKA_PLL:
652 siu_name = "siua_clk";
653 parent_name = "pll_clk";
654 break;
655 case SIU_CLKA_EXT:
656 siu_name = "siua_clk";
657 parent_name = "siumcka_clk";
658 break;
659 case SIU_CLKB_PLL:
660 siu_name = "siub_clk";
661 parent_name = "pll_clk";
662 break;
663 case SIU_CLKB_EXT:
664 siu_name = "siub_clk";
665 parent_name = "siumckb_clk";
666 break;
667 default:
668 return -EINVAL;
669 }
670
671 siu_clk = clk_get(siu_i2s_dai.dev, siu_name);
672 if (IS_ERR(siu_clk))
673 return PTR_ERR(siu_clk);
674
675 parent_clk = clk_get(siu_i2s_dai.dev, parent_name);
676 if (!IS_ERR(parent_clk)) {
677 ret = clk_set_parent(siu_clk, parent_clk);
678 if (!ret)
679 clk_set_rate(siu_clk, freq);
680 clk_put(parent_clk);
681 }
682
683 clk_put(siu_clk);
684
685 return 0;
686}
687
688static struct snd_soc_dai_ops siu_dai_ops = {
689 .startup = siu_dai_startup,
690 .shutdown = siu_dai_shutdown,
691 .prepare = siu_dai_prepare,
692 .set_sysclk = siu_dai_set_sysclk,
693 .set_fmt = siu_dai_set_fmt,
694};
695
696struct snd_soc_dai siu_i2s_dai = {
697 .name = "sh-siu",
698 .id = 0,
699 .playback = {
700 .channels_min = 2,
701 .channels_max = 2,
702 .formats = SNDRV_PCM_FMTBIT_S16,
703 .rates = SNDRV_PCM_RATE_8000_48000,
704 },
705 .capture = {
706 .channels_min = 2,
707 .channels_max = 2,
708 .formats = SNDRV_PCM_FMTBIT_S16,
709 .rates = SNDRV_PCM_RATE_8000_48000,
710 },
711 .ops = &siu_dai_ops,
712};
713EXPORT_SYMBOL_GPL(siu_i2s_dai);
714
715static int __devinit siu_probe(struct platform_device *pdev)
716{
717 const struct firmware *fw_entry;
718 struct resource *res, *region;
719 struct siu_info *info;
720 int ret;
721
722 info = kmalloc(sizeof(*info), GFP_KERNEL);
723 if (!info)
724 return -ENOMEM;
725
726 ret = request_firmware(&fw_entry, "siu_spb.bin", &pdev->dev);
727 if (ret)
728 goto ereqfw;
729
730 /*
731 * Loaded firmware is "const" - read only, but we have to modify it in
732 * snd_siu_sh7343_spbAselect() and snd_siu_sh7343_spbBselect()
733 */
734 memcpy(&info->fw, fw_entry->data, fw_entry->size);
735
736 release_firmware(fw_entry);
737
738 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
739 if (!res) {
740 ret = -ENODEV;
741 goto egetres;
742 }
743
744 region = request_mem_region(res->start, resource_size(res),
745 pdev->name);
746 if (!region) {
747 dev_err(&pdev->dev, "SIU region already claimed\n");
748 ret = -EBUSY;
749 goto ereqmemreg;
750 }
751
752 ret = -ENOMEM;
753 info->pram = ioremap(res->start, PRAM_SIZE);
754 if (!info->pram)
755 goto emappram;
756 info->xram = ioremap(res->start + XRAM_OFFSET, XRAM_SIZE);
757 if (!info->xram)
758 goto emapxram;
759 info->yram = ioremap(res->start + YRAM_OFFSET, YRAM_SIZE);
760 if (!info->yram)
761 goto emapyram;
762 info->reg = ioremap(res->start + REG_OFFSET, resource_size(res) -
763 REG_OFFSET);
764 if (!info->reg)
765 goto emapreg;
766
767 siu_i2s_dai.dev = &pdev->dev;
768 siu_i2s_dai.private_data = info;
769
770 ret = snd_soc_register_dais(&siu_i2s_dai, 1);
771 if (ret < 0)
772 goto edaiinit;
773
774 ret = snd_soc_register_platform(&siu_platform);
775 if (ret < 0)
776 goto esocregp;
777
778 pm_runtime_enable(&pdev->dev);
779
780 return ret;
781
782esocregp:
783 snd_soc_unregister_dais(&siu_i2s_dai, 1);
784edaiinit:
785 iounmap(info->reg);
786emapreg:
787 iounmap(info->yram);
788emapyram:
789 iounmap(info->xram);
790emapxram:
791 iounmap(info->pram);
792emappram:
793 release_mem_region(res->start, resource_size(res));
794ereqmemreg:
795egetres:
796ereqfw:
797 kfree(info);
798
799 return ret;
800}
801
802static int __devexit siu_remove(struct platform_device *pdev)
803{
804 struct siu_info *info = siu_i2s_dai.private_data;
805 struct resource *res;
806
807 pm_runtime_disable(&pdev->dev);
808
809 snd_soc_unregister_platform(&siu_platform);
810 snd_soc_unregister_dais(&siu_i2s_dai, 1);
811
812 iounmap(info->reg);
813 iounmap(info->yram);
814 iounmap(info->xram);
815 iounmap(info->pram);
816 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
817 if (res)
818 release_mem_region(res->start, resource_size(res));
819 kfree(info);
820
821 return 0;
822}
823
824static struct platform_driver siu_driver = {
825 .driver = {
826 .name = "sh_siu",
827 },
828 .probe = siu_probe,
829 .remove = __devexit_p(siu_remove),
830};
831
832static int __init siu_init(void)
833{
834 return platform_driver_register(&siu_driver);
835}
836
837static void __exit siu_exit(void)
838{
839 platform_driver_unregister(&siu_driver);
840}
841
842module_init(siu_init)
843module_exit(siu_exit)
844
845MODULE_AUTHOR("Carlos Munoz <carlos@kenati.com>");
846MODULE_DESCRIPTION("ALSA SoC SH7722 SIU driver");
847MODULE_LICENSE("GPL");
diff --git a/sound/soc/sh/siu_pcm.c b/sound/soc/sh/siu_pcm.c
new file mode 100644
index 000000000000..c5efc30f0136
--- /dev/null
+++ b/sound/soc/sh/siu_pcm.c
@@ -0,0 +1,616 @@
1/*
2 * siu_pcm.c - ALSA driver for Renesas SH7343, SH7722 SIU peripheral.
3 *
4 * Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
5 * Copyright (C) 2006 Carlos Munoz <carlos@kenati.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21#include <linux/delay.h>
22#include <linux/dma-mapping.h>
23#include <linux/dmaengine.h>
24#include <linux/interrupt.h>
25#include <linux/module.h>
26#include <linux/platform_device.h>
27#include <linux/slab.h>
28
29#include <sound/control.h>
30#include <sound/core.h>
31#include <sound/pcm.h>
32#include <sound/pcm_params.h>
33#include <sound/soc-dai.h>
34
35#include <asm/dma-sh.h>
36#include <asm/siu.h>
37
38#include "siu.h"
39
40#define GET_MAX_PERIODS(buf_bytes, period_bytes) \
41 ((buf_bytes) / (period_bytes))
42#define PERIOD_OFFSET(buf_addr, period_num, period_bytes) \
43 ((buf_addr) + ((period_num) * (period_bytes)))
44
45#define RWF_STM_RD 0x01 /* Read in progress */
46#define RWF_STM_WT 0x02 /* Write in progress */
47
48struct siu_port *siu_ports[SIU_PORT_NUM];
49
50/* transfersize is number of u32 dma transfers per period */
51static int siu_pcm_stmwrite_stop(struct siu_port *port_info)
52{
53 struct siu_info *info = siu_i2s_dai.private_data;
54 u32 __iomem *base = info->reg;
55 struct siu_stream *siu_stream = &port_info->playback;
56 u32 stfifo;
57
58 if (!siu_stream->rw_flg)
59 return -EPERM;
60
61 /* output FIFO disable */
62 stfifo = siu_read32(base + SIU_STFIFO);
63 siu_write32(base + SIU_STFIFO, stfifo & ~0x0c180c18);
64 pr_debug("%s: STFIFO %x -> %x\n", __func__,
65 stfifo, stfifo & ~0x0c180c18);
66
67 /* during stmwrite clear */
68 siu_stream->rw_flg = 0;
69
70 return 0;
71}
72
73static int siu_pcm_stmwrite_start(struct siu_port *port_info)
74{
75 struct siu_stream *siu_stream = &port_info->playback;
76
77 if (siu_stream->rw_flg)
78 return -EPERM;
79
80 /* Current period in buffer */
81 port_info->playback.cur_period = 0;
82
83 /* during stmwrite flag set */
84 siu_stream->rw_flg = RWF_STM_WT;
85
86 /* DMA transfer start */
87 tasklet_schedule(&siu_stream->tasklet);
88
89 return 0;
90}
91
92static void siu_dma_tx_complete(void *arg)
93{
94 struct siu_stream *siu_stream = arg;
95
96 if (!siu_stream->rw_flg)
97 return;
98
99 /* Update completed period count */
100 if (++siu_stream->cur_period >=
101 GET_MAX_PERIODS(siu_stream->buf_bytes,
102 siu_stream->period_bytes))
103 siu_stream->cur_period = 0;
104
105 pr_debug("%s: done period #%d (%u/%u bytes), cookie %d\n",
106 __func__, siu_stream->cur_period,
107 siu_stream->cur_period * siu_stream->period_bytes,
108 siu_stream->buf_bytes, siu_stream->cookie);
109
110 tasklet_schedule(&siu_stream->tasklet);
111
112 /* Notify alsa: a period is done */
113 snd_pcm_period_elapsed(siu_stream->substream);
114}
115
116static int siu_pcm_wr_set(struct siu_port *port_info,
117 dma_addr_t buff, u32 size)
118{
119 struct siu_info *info = siu_i2s_dai.private_data;
120 u32 __iomem *base = info->reg;
121 struct siu_stream *siu_stream = &port_info->playback;
122 struct snd_pcm_substream *substream = siu_stream->substream;
123 struct device *dev = substream->pcm->card->dev;
124 struct dma_async_tx_descriptor *desc;
125 dma_cookie_t cookie;
126 struct scatterlist sg;
127 u32 stfifo;
128
129 sg_init_table(&sg, 1);
130 sg_set_page(&sg, pfn_to_page(PFN_DOWN(buff)),
131 size, offset_in_page(buff));
132 sg_dma_address(&sg) = buff;
133
134 desc = siu_stream->chan->device->device_prep_slave_sg(siu_stream->chan,
135 &sg, 1, DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
136 if (!desc) {
137 dev_err(dev, "Failed to allocate a dma descriptor\n");
138 return -ENOMEM;
139 }
140
141 desc->callback = siu_dma_tx_complete;
142 desc->callback_param = siu_stream;
143 cookie = desc->tx_submit(desc);
144 if (cookie < 0) {
145 dev_err(dev, "Failed to submit a dma transfer\n");
146 return cookie;
147 }
148
149 siu_stream->tx_desc = desc;
150 siu_stream->cookie = cookie;
151
152 dma_async_issue_pending(siu_stream->chan);
153
154 /* only output FIFO enable */
155 stfifo = siu_read32(base + SIU_STFIFO);
156 siu_write32(base + SIU_STFIFO, stfifo | (port_info->stfifo & 0x0c180c18));
157 dev_dbg(dev, "%s: STFIFO %x -> %x\n", __func__,
158 stfifo, stfifo | (port_info->stfifo & 0x0c180c18));
159
160 return 0;
161}
162
163static int siu_pcm_rd_set(struct siu_port *port_info,
164 dma_addr_t buff, size_t size)
165{
166 struct siu_info *info = siu_i2s_dai.private_data;
167 u32 __iomem *base = info->reg;
168 struct siu_stream *siu_stream = &port_info->capture;
169 struct snd_pcm_substream *substream = siu_stream->substream;
170 struct device *dev = substream->pcm->card->dev;
171 struct dma_async_tx_descriptor *desc;
172 dma_cookie_t cookie;
173 struct scatterlist sg;
174 u32 stfifo;
175
176 dev_dbg(dev, "%s: %u@%llx\n", __func__, size, (unsigned long long)buff);
177
178 sg_init_table(&sg, 1);
179 sg_set_page(&sg, pfn_to_page(PFN_DOWN(buff)),
180 size, offset_in_page(buff));
181 sg_dma_address(&sg) = buff;
182
183 desc = siu_stream->chan->device->device_prep_slave_sg(siu_stream->chan,
184 &sg, 1, DMA_FROM_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
185 if (!desc) {
186 dev_err(dev, "Failed to allocate dma descriptor\n");
187 return -ENOMEM;
188 }
189
190 desc->callback = siu_dma_tx_complete;
191 desc->callback_param = siu_stream;
192 cookie = desc->tx_submit(desc);
193 if (cookie < 0) {
194 dev_err(dev, "Failed to submit dma descriptor\n");
195 return cookie;
196 }
197
198 siu_stream->tx_desc = desc;
199 siu_stream->cookie = cookie;
200
201 dma_async_issue_pending(siu_stream->chan);
202
203 /* only input FIFO enable */
204 stfifo = siu_read32(base + SIU_STFIFO);
205 siu_write32(base + SIU_STFIFO, siu_read32(base + SIU_STFIFO) |
206 (port_info->stfifo & 0x13071307));
207 dev_dbg(dev, "%s: STFIFO %x -> %x\n", __func__,
208 stfifo, stfifo | (port_info->stfifo & 0x13071307));
209
210 return 0;
211}
212
213static void siu_io_tasklet(unsigned long data)
214{
215 struct siu_stream *siu_stream = (struct siu_stream *)data;
216 struct snd_pcm_substream *substream = siu_stream->substream;
217 struct device *dev = substream->pcm->card->dev;
218 struct snd_pcm_runtime *rt = substream->runtime;
219 struct siu_port *port_info = siu_port_info(substream);
220
221 dev_dbg(dev, "%s: flags %x\n", __func__, siu_stream->rw_flg);
222
223 if (!siu_stream->rw_flg) {
224 dev_dbg(dev, "%s: stream inactive\n", __func__);
225 return;
226 }
227
228 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
229 dma_addr_t buff;
230 size_t count;
231 u8 *virt;
232
233 buff = (dma_addr_t)PERIOD_OFFSET(rt->dma_addr,
234 siu_stream->cur_period,
235 siu_stream->period_bytes);
236 virt = PERIOD_OFFSET(rt->dma_area,
237 siu_stream->cur_period,
238 siu_stream->period_bytes);
239 count = siu_stream->period_bytes;
240
241 /* DMA transfer start */
242 siu_pcm_rd_set(port_info, buff, count);
243 } else {
244 siu_pcm_wr_set(port_info,
245 (dma_addr_t)PERIOD_OFFSET(rt->dma_addr,
246 siu_stream->cur_period,
247 siu_stream->period_bytes),
248 siu_stream->period_bytes);
249 }
250}
251
252/* Capture */
253static int siu_pcm_stmread_start(struct siu_port *port_info)
254{
255 struct siu_stream *siu_stream = &port_info->capture;
256
257 if (siu_stream->xfer_cnt > 0x1000000)
258 return -EINVAL;
259 if (siu_stream->rw_flg)
260 return -EPERM;
261
262 /* Current period in buffer */
263 siu_stream->cur_period = 0;
264
265 /* during stmread flag set */
266 siu_stream->rw_flg = RWF_STM_RD;
267
268 tasklet_schedule(&siu_stream->tasklet);
269
270 return 0;
271}
272
273static int siu_pcm_stmread_stop(struct siu_port *port_info)
274{
275 struct siu_info *info = siu_i2s_dai.private_data;
276 u32 __iomem *base = info->reg;
277 struct siu_stream *siu_stream = &port_info->capture;
278 struct device *dev = siu_stream->substream->pcm->card->dev;
279 u32 stfifo;
280
281 if (!siu_stream->rw_flg)
282 return -EPERM;
283
284 /* input FIFO disable */
285 stfifo = siu_read32(base + SIU_STFIFO);
286 siu_write32(base + SIU_STFIFO, stfifo & ~0x13071307);
287 dev_dbg(dev, "%s: STFIFO %x -> %x\n", __func__,
288 stfifo, stfifo & ~0x13071307);
289
290 /* during stmread flag clear */
291 siu_stream->rw_flg = 0;
292
293 return 0;
294}
295
296static int siu_pcm_hw_params(struct snd_pcm_substream *ss,
297 struct snd_pcm_hw_params *hw_params)
298{
299 struct siu_info *info = siu_i2s_dai.private_data;
300 struct device *dev = ss->pcm->card->dev;
301 int ret;
302
303 dev_dbg(dev, "%s: port=%d\n", __func__, info->port_id);
304
305 ret = snd_pcm_lib_malloc_pages(ss, params_buffer_bytes(hw_params));
306 if (ret < 0)
307 dev_err(dev, "snd_pcm_lib_malloc_pages() failed\n");
308
309 return ret;
310}
311
312static int siu_pcm_hw_free(struct snd_pcm_substream *ss)
313{
314 struct siu_info *info = siu_i2s_dai.private_data;
315 struct siu_port *port_info = siu_port_info(ss);
316 struct device *dev = ss->pcm->card->dev;
317 struct siu_stream *siu_stream;
318
319 if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
320 siu_stream = &port_info->playback;
321 else
322 siu_stream = &port_info->capture;
323
324 dev_dbg(dev, "%s: port=%d\n", __func__, info->port_id);
325
326 return snd_pcm_lib_free_pages(ss);
327}
328
329static bool filter(struct dma_chan *chan, void *slave)
330{
331 struct sh_dmae_slave *param = slave;
332
333 pr_debug("%s: slave ID %d\n", __func__, param->slave_id);
334
335 if (unlikely(param->dma_dev != chan->device->dev))
336 return false;
337
338 chan->private = param;
339 return true;
340}
341
342static int siu_pcm_open(struct snd_pcm_substream *ss)
343{
344 /* Playback / Capture */
345 struct siu_info *info = siu_i2s_dai.private_data;
346 struct siu_port *port_info = siu_port_info(ss);
347 struct siu_stream *siu_stream;
348 u32 port = info->port_id;
349 struct siu_platform *pdata = siu_i2s_dai.dev->platform_data;
350 struct device *dev = ss->pcm->card->dev;
351 dma_cap_mask_t mask;
352 struct sh_dmae_slave *param;
353
354 dma_cap_zero(mask);
355 dma_cap_set(DMA_SLAVE, mask);
356
357 dev_dbg(dev, "%s, port=%d@%p\n", __func__, port, port_info);
358
359 if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) {
360 siu_stream = &port_info->playback;
361 param = &siu_stream->param;
362 param->slave_id = port ? SHDMA_SLAVE_SIUB_TX :
363 SHDMA_SLAVE_SIUA_TX;
364 } else {
365 siu_stream = &port_info->capture;
366 param = &siu_stream->param;
367 param->slave_id = port ? SHDMA_SLAVE_SIUB_RX :
368 SHDMA_SLAVE_SIUA_RX;
369 }
370
371 param->dma_dev = pdata->dma_dev;
372 /* Get DMA channel */
373 siu_stream->chan = dma_request_channel(mask, filter, param);
374 if (!siu_stream->chan) {
375 dev_err(dev, "DMA channel allocation failed!\n");
376 return -EBUSY;
377 }
378
379 siu_stream->substream = ss;
380
381 return 0;
382}
383
384static int siu_pcm_close(struct snd_pcm_substream *ss)
385{
386 struct siu_info *info = siu_i2s_dai.private_data;
387 struct device *dev = ss->pcm->card->dev;
388 struct siu_port *port_info = siu_port_info(ss);
389 struct siu_stream *siu_stream;
390
391 dev_dbg(dev, "%s: port=%d\n", __func__, info->port_id);
392
393 if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
394 siu_stream = &port_info->playback;
395 else
396 siu_stream = &port_info->capture;
397
398 dma_release_channel(siu_stream->chan);
399 siu_stream->chan = NULL;
400
401 siu_stream->substream = NULL;
402
403 return 0;
404}
405
406static int siu_pcm_prepare(struct snd_pcm_substream *ss)
407{
408 struct siu_info *info = siu_i2s_dai.private_data;
409 struct siu_port *port_info = siu_port_info(ss);
410 struct device *dev = ss->pcm->card->dev;
411 struct snd_pcm_runtime *rt = ss->runtime;
412 struct siu_stream *siu_stream;
413 snd_pcm_sframes_t xfer_cnt;
414
415 if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
416 siu_stream = &port_info->playback;
417 else
418 siu_stream = &port_info->capture;
419
420 rt = siu_stream->substream->runtime;
421
422 siu_stream->buf_bytes = snd_pcm_lib_buffer_bytes(ss);
423 siu_stream->period_bytes = snd_pcm_lib_period_bytes(ss);
424
425 dev_dbg(dev, "%s: port=%d, %d channels, period=%u bytes\n", __func__,
426 info->port_id, rt->channels, siu_stream->period_bytes);
427
428 /* We only support buffers that are multiples of the period */
429 if (siu_stream->buf_bytes % siu_stream->period_bytes) {
430 dev_err(dev, "%s() - buffer=%d not multiple of period=%d\n",
431 __func__, siu_stream->buf_bytes,
432 siu_stream->period_bytes);
433 return -EINVAL;
434 }
435
436 xfer_cnt = bytes_to_frames(rt, siu_stream->period_bytes);
437 if (!xfer_cnt || xfer_cnt > 0x1000000)
438 return -EINVAL;
439
440 siu_stream->format = rt->format;
441 siu_stream->xfer_cnt = xfer_cnt;
442
443 dev_dbg(dev, "port=%d buf=%lx buf_bytes=%d period_bytes=%d "
444 "format=%d channels=%d xfer_cnt=%d\n", info->port_id,
445 (unsigned long)rt->dma_addr, siu_stream->buf_bytes,
446 siu_stream->period_bytes,
447 siu_stream->format, rt->channels, (int)xfer_cnt);
448
449 return 0;
450}
451
452static int siu_pcm_trigger(struct snd_pcm_substream *ss, int cmd)
453{
454 struct siu_info *info = siu_i2s_dai.private_data;
455 struct device *dev = ss->pcm->card->dev;
456 struct siu_port *port_info = siu_port_info(ss);
457 int ret;
458
459 dev_dbg(dev, "%s: port=%d@%p, cmd=%d\n", __func__,
460 info->port_id, port_info, cmd);
461
462 switch (cmd) {
463 case SNDRV_PCM_TRIGGER_START:
464 if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
465 ret = siu_pcm_stmwrite_start(port_info);
466 else
467 ret = siu_pcm_stmread_start(port_info);
468
469 if (ret < 0)
470 dev_warn(dev, "%s: start failed on port=%d\n",
471 __func__, info->port_id);
472
473 break;
474 case SNDRV_PCM_TRIGGER_STOP:
475 if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
476 siu_pcm_stmwrite_stop(port_info);
477 else
478 siu_pcm_stmread_stop(port_info);
479 ret = 0;
480
481 break;
482 default:
483 dev_err(dev, "%s() unsupported cmd=%d\n", __func__, cmd);
484 ret = -EINVAL;
485 }
486
487 return ret;
488}
489
490/*
491 * So far only resolution of one period is supported, subject to extending the
492 * dmangine API
493 */
494static snd_pcm_uframes_t siu_pcm_pointer_dma(struct snd_pcm_substream *ss)
495{
496 struct device *dev = ss->pcm->card->dev;
497 struct siu_info *info = siu_i2s_dai.private_data;
498 u32 __iomem *base = info->reg;
499 struct siu_port *port_info = siu_port_info(ss);
500 struct snd_pcm_runtime *rt = ss->runtime;
501 size_t ptr;
502 struct siu_stream *siu_stream;
503
504 if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
505 siu_stream = &port_info->playback;
506 else
507 siu_stream = &port_info->capture;
508
509 /*
510 * ptr is the offset into the buffer where the dma is currently at. We
511 * check if the dma buffer has just wrapped.
512 */
513 ptr = PERIOD_OFFSET(rt->dma_addr,
514 siu_stream->cur_period,
515 siu_stream->period_bytes) - rt->dma_addr;
516
517 dev_dbg(dev,
518 "%s: port=%d, events %x, FSTS %x, xferred %u/%u, cookie %d\n",
519 __func__, info->port_id, siu_read32(base + SIU_EVNTC),
520 siu_read32(base + SIU_SBFSTS), ptr, siu_stream->buf_bytes,
521 siu_stream->cookie);
522
523 if (ptr >= siu_stream->buf_bytes)
524 ptr = 0;
525
526 return bytes_to_frames(ss->runtime, ptr);
527}
528
529static int siu_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
530 struct snd_pcm *pcm)
531{
532 /* card->dev == socdev->dev, see snd_soc_new_pcms() */
533 struct siu_info *info = siu_i2s_dai.private_data;
534 struct platform_device *pdev = to_platform_device(card->dev);
535 int ret;
536 int i;
537
538 /* pdev->id selects between SIUA and SIUB */
539 if (pdev->id < 0 || pdev->id >= SIU_PORT_NUM)
540 return -EINVAL;
541
542 info->port_id = pdev->id;
543
544 /*
545 * While the siu has 2 ports, only one port can be on at a time (only 1
546 * SPB). So far all the boards using the siu had only one of the ports
547 * wired to a codec. To simplify things, we only register one port with
548 * alsa. In case both ports are needed, it should be changed here
549 */
550 for (i = pdev->id; i < pdev->id + 1; i++) {
551 struct siu_port **port_info = &siu_ports[i];
552
553 ret = siu_init_port(i, port_info, card);
554 if (ret < 0)
555 return ret;
556
557 ret = snd_pcm_lib_preallocate_pages_for_all(pcm,
558 SNDRV_DMA_TYPE_DEV, NULL,
559 SIU_BUFFER_BYTES_MAX, SIU_BUFFER_BYTES_MAX);
560 if (ret < 0) {
561 dev_err(card->dev,
562 "snd_pcm_lib_preallocate_pages_for_all() err=%d",
563 ret);
564 goto fail;
565 }
566
567 (*port_info)->pcm = pcm;
568
569 /* IO tasklets */
570 tasklet_init(&(*port_info)->playback.tasklet, siu_io_tasklet,
571 (unsigned long)&(*port_info)->playback);
572 tasklet_init(&(*port_info)->capture.tasklet, siu_io_tasklet,
573 (unsigned long)&(*port_info)->capture);
574 }
575
576 dev_info(card->dev, "SuperH SIU driver initialized.\n");
577 return 0;
578
579fail:
580 siu_free_port(siu_ports[pdev->id]);
581 dev_err(card->dev, "SIU: failed to initialize.\n");
582 return ret;
583}
584
585static void siu_pcm_free(struct snd_pcm *pcm)
586{
587 struct platform_device *pdev = to_platform_device(pcm->card->dev);
588 struct siu_port *port_info = siu_ports[pdev->id];
589
590 tasklet_kill(&port_info->capture.tasklet);
591 tasklet_kill(&port_info->playback.tasklet);
592
593 siu_free_port(port_info);
594 snd_pcm_lib_preallocate_free_for_all(pcm);
595
596 dev_dbg(pcm->card->dev, "%s\n", __func__);
597}
598
599static struct snd_pcm_ops siu_pcm_ops = {
600 .open = siu_pcm_open,
601 .close = siu_pcm_close,
602 .ioctl = snd_pcm_lib_ioctl,
603 .hw_params = siu_pcm_hw_params,
604 .hw_free = siu_pcm_hw_free,
605 .prepare = siu_pcm_prepare,
606 .trigger = siu_pcm_trigger,
607 .pointer = siu_pcm_pointer_dma,
608};
609
610struct snd_soc_platform siu_platform = {
611 .name = "siu-audio",
612 .pcm_ops = &siu_pcm_ops,
613 .pcm_new = siu_pcm_new,
614 .pcm_free = siu_pcm_free,
615};
616EXPORT_SYMBOL_GPL(siu_platform);