aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Brown <broonie@linaro.org>2013-08-22 09:28:47 -0400
committerMark Brown <broonie@linaro.org>2013-08-22 09:28:47 -0400
commitb008387ab5f5369f925649d0201ace5055008530 (patch)
treeabc9571bb77201fe97088d9f6cb24659b4e6d439
parent5388d48047def3c30e42c7ba86c3c9ff0d2bd40c (diff)
parent2460719c79854a3bebe569cbfbfa0b1caa1dc434 (diff)
Merge remote-tracking branch 'asoc/topic/rcar' into asoc-next
-rw-r--r--include/sound/rcar_snd.h84
-rw-r--r--sound/soc/sh/Kconfig7
-rw-r--r--sound/soc/sh/Makefile3
-rw-r--r--sound/soc/sh/rcar/Makefile2
-rw-r--r--sound/soc/sh/rcar/adg.c234
-rw-r--r--sound/soc/sh/rcar/core.c861
-rw-r--r--sound/soc/sh/rcar/gen.c280
-rw-r--r--sound/soc/sh/rcar/rsnd.h302
-rw-r--r--sound/soc/sh/rcar/scu.c236
-rw-r--r--sound/soc/sh/rcar/ssi.c728
10 files changed, 2737 insertions, 0 deletions
diff --git a/include/sound/rcar_snd.h b/include/sound/rcar_snd.h
new file mode 100644
index 000000000000..d35412ae03b3
--- /dev/null
+++ b/include/sound/rcar_snd.h
@@ -0,0 +1,84 @@
1/*
2 * Renesas R-Car SRU/SCU/SSIU/SSI support
3 *
4 * Copyright (C) 2013 Renesas Solutions Corp.
5 * Kuninori Morimoto <kuninori.morimoto.gx@renesas.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 version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#ifndef RCAR_SND_H
13#define RCAR_SND_H
14
15#include <linux/sh_clk.h>
16
17#define RSND_GEN1_SRU 0
18#define RSND_GEN1_ADG 1
19#define RSND_GEN1_SSI 2
20
21#define RSND_GEN2_SRU 0
22#define RSND_GEN2_ADG 1
23#define RSND_GEN2_SSIU 2
24#define RSND_GEN2_SSI 3
25
26#define RSND_BASE_MAX 4
27
28/*
29 * flags
30 *
31 * 0xAB000000
32 *
33 * A : clock sharing settings
34 * B : SSI direction
35 */
36#define RSND_SSI_CLK_PIN_SHARE (1 << 31)
37#define RSND_SSI_CLK_FROM_ADG (1 << 30) /* clock parent is master */
38#define RSND_SSI_SYNC (1 << 29) /* SSI34_sync etc */
39#define RSND_SSI_DEPENDENT (1 << 28) /* SSI needs SRU/SCU */
40
41#define RSND_SSI_PLAY (1 << 24)
42
43#define RSND_SSI_SET(_dai_id, _dma_id, _pio_irq, _flags) \
44{ .dai_id = _dai_id, .dma_id = _dma_id, .pio_irq = _pio_irq, .flags = _flags }
45#define RSND_SSI_UNUSED \
46{ .dai_id = -1, .dma_id = -1, .pio_irq = -1, .flags = 0 }
47
48struct rsnd_ssi_platform_info {
49 int dai_id;
50 int dma_id;
51 int pio_irq;
52 u32 flags;
53};
54
55/*
56 * flags
57 */
58#define RSND_SCU_USB_HPBIF (1 << 31) /* it needs RSND_SSI_DEPENDENT */
59
60struct rsnd_scu_platform_info {
61 u32 flags;
62};
63
64/*
65 * flags
66 *
67 * 0x0000000A
68 *
69 * A : generation
70 */
71#define RSND_GEN1 (1 << 0) /* fixme */
72#define RSND_GEN2 (2 << 0) /* fixme */
73
74struct rcar_snd_info {
75 u32 flags;
76 struct rsnd_ssi_platform_info *ssi_info;
77 int ssi_info_nr;
78 struct rsnd_scu_platform_info *scu_info;
79 int scu_info_nr;
80 int (*start)(int id);
81 int (*stop)(int id);
82};
83
84#endif
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig
index 6bcb1164d599..56d8ff6a402d 100644
--- a/sound/soc/sh/Kconfig
+++ b/sound/soc/sh/Kconfig
@@ -34,6 +34,13 @@ config SND_SOC_SH4_SIU
34 select SH_DMAE 34 select SH_DMAE
35 select FW_LOADER 35 select FW_LOADER
36 36
37config SND_SOC_RCAR
38 tristate "R-Car series SRU/SCU/SSIU/SSI support"
39 select SND_SIMPLE_CARD
40 select RCAR_CLK_ADG
41 help
42 This option enables R-Car SUR/SCU/SSIU/SSI sound support
43
37## 44##
38## Boards 45## Boards
39## 46##
diff --git a/sound/soc/sh/Makefile b/sound/soc/sh/Makefile
index 849b387d17d9..aaf3dcd1ee2a 100644
--- a/sound/soc/sh/Makefile
+++ b/sound/soc/sh/Makefile
@@ -12,6 +12,9 @@ obj-$(CONFIG_SND_SOC_SH4_SSI) += snd-soc-ssi.o
12obj-$(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 13obj-$(CONFIG_SND_SOC_SH4_SIU) += snd-soc-siu.o
14 14
15## audio units for R-Car
16obj-$(CONFIG_SND_SOC_RCAR) += rcar/
17
15## boards 18## boards
16snd-soc-sh7760-ac97-objs := sh7760-ac97.o 19snd-soc-sh7760-ac97-objs := sh7760-ac97.o
17snd-soc-migor-objs := migor.o 20snd-soc-migor-objs := migor.o
diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/sh/rcar/Makefile
new file mode 100644
index 000000000000..0ff492df7929
--- /dev/null
+++ b/sound/soc/sh/rcar/Makefile
@@ -0,0 +1,2 @@
1snd-soc-rcar-objs := core.o gen.o scu.o adg.o ssi.o
2obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o \ No newline at end of file
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c
new file mode 100644
index 000000000000..d80deb7ccf13
--- /dev/null
+++ b/sound/soc/sh/rcar/adg.c
@@ -0,0 +1,234 @@
1/*
2 * Helper routines for R-Car sound ADG.
3 *
4 * Copyright (C) 2013 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10#include <linux/sh_clk.h>
11#include <mach/clock.h>
12#include "rsnd.h"
13
14#define CLKA 0
15#define CLKB 1
16#define CLKC 2
17#define CLKI 3
18#define CLKMAX 4
19
20struct rsnd_adg {
21 struct clk *clk[CLKMAX];
22
23 int rate_of_441khz_div_6;
24 int rate_of_48khz_div_6;
25};
26
27#define for_each_rsnd_clk(pos, adg, i) \
28 for (i = 0, (pos) = adg->clk[i]; \
29 i < CLKMAX; \
30 i++, (pos) = adg->clk[i])
31#define rsnd_priv_to_adg(priv) ((struct rsnd_adg *)(priv)->adg)
32
33static enum rsnd_reg rsnd_adg_ssi_reg_get(int id)
34{
35 enum rsnd_reg reg;
36
37 /*
38 * SSI 8 is not connected to ADG.
39 * it works with SSI 7
40 */
41 if (id == 8)
42 return RSND_REG_MAX;
43
44 if (0 <= id && id <= 3)
45 reg = RSND_REG_AUDIO_CLK_SEL0;
46 else if (4 <= id && id <= 7)
47 reg = RSND_REG_AUDIO_CLK_SEL1;
48 else
49 reg = RSND_REG_AUDIO_CLK_SEL2;
50
51 return reg;
52}
53
54int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod)
55{
56 struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
57 enum rsnd_reg reg;
58 int id;
59
60 /*
61 * "mod" = "ssi" here.
62 * we can get "ssi id" from mod
63 */
64 id = rsnd_mod_id(mod);
65 reg = rsnd_adg_ssi_reg_get(id);
66
67 rsnd_write(priv, mod, reg, 0);
68
69 return 0;
70}
71
72int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate)
73{
74 struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
75 struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
76 struct device *dev = rsnd_priv_to_dev(priv);
77 struct clk *clk;
78 enum rsnd_reg reg;
79 int id, shift, i;
80 u32 data;
81 int sel_table[] = {
82 [CLKA] = 0x1,
83 [CLKB] = 0x2,
84 [CLKC] = 0x3,
85 [CLKI] = 0x0,
86 };
87
88 dev_dbg(dev, "request clock = %d\n", rate);
89
90 /*
91 * find suitable clock from
92 * AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC/AUDIO_CLKI.
93 */
94 data = 0;
95 for_each_rsnd_clk(clk, adg, i) {
96 if (rate == clk_get_rate(clk)) {
97 data = sel_table[i];
98 goto found_clock;
99 }
100 }
101
102 /*
103 * find 1/6 clock from BRGA/BRGB
104 */
105 if (rate == adg->rate_of_441khz_div_6) {
106 data = 0x10;
107 goto found_clock;
108 }
109
110 if (rate == adg->rate_of_48khz_div_6) {
111 data = 0x20;
112 goto found_clock;
113 }
114
115 return -EIO;
116
117found_clock:
118
119 /*
120 * This "mod" = "ssi" here.
121 * we can get "ssi id" from mod
122 */
123 id = rsnd_mod_id(mod);
124 reg = rsnd_adg_ssi_reg_get(id);
125
126 dev_dbg(dev, "ADG: ssi%d selects clk%d = %d", id, i, rate);
127
128 /*
129 * Enable SSIx clock
130 */
131 shift = (id % 4) * 8;
132
133 rsnd_bset(priv, mod, reg,
134 0xFF << shift,
135 data << shift);
136
137 return 0;
138}
139
140static void rsnd_adg_ssi_clk_init(struct rsnd_priv *priv, struct rsnd_adg *adg)
141{
142 struct clk *clk;
143 unsigned long rate;
144 u32 ckr;
145 int i;
146 int brg_table[] = {
147 [CLKA] = 0x0,
148 [CLKB] = 0x1,
149 [CLKC] = 0x4,
150 [CLKI] = 0x2,
151 };
152
153 /*
154 * This driver is assuming that AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC
155 * have 44.1kHz or 48kHz base clocks for now.
156 *
157 * SSI itself can divide parent clock by 1/1 - 1/16
158 * So, BRGA outputs 44.1kHz base parent clock 1/32,
159 * and, BRGB outputs 48.0kHz base parent clock 1/32 here.
160 * see
161 * rsnd_adg_ssi_clk_try_start()
162 */
163 ckr = 0;
164 adg->rate_of_441khz_div_6 = 0;
165 adg->rate_of_48khz_div_6 = 0;
166 for_each_rsnd_clk(clk, adg, i) {
167 rate = clk_get_rate(clk);
168
169 if (0 == rate) /* not used */
170 continue;
171
172 /* RBGA */
173 if (!adg->rate_of_441khz_div_6 && (0 == rate % 44100)) {
174 adg->rate_of_441khz_div_6 = rate / 6;
175 ckr |= brg_table[i] << 20;
176 }
177
178 /* RBGB */
179 if (!adg->rate_of_48khz_div_6 && (0 == rate % 48000)) {
180 adg->rate_of_48khz_div_6 = rate / 6;
181 ckr |= brg_table[i] << 16;
182 }
183 }
184
185 rsnd_priv_bset(priv, SSICKR, 0x00FF0000, ckr);
186 rsnd_priv_write(priv, BRRA, 0x00000002); /* 1/6 */
187 rsnd_priv_write(priv, BRRB, 0x00000002); /* 1/6 */
188}
189
190int rsnd_adg_probe(struct platform_device *pdev,
191 struct rcar_snd_info *info,
192 struct rsnd_priv *priv)
193{
194 struct rsnd_adg *adg;
195 struct device *dev = rsnd_priv_to_dev(priv);
196 struct clk *clk;
197 int i;
198
199 adg = devm_kzalloc(dev, sizeof(*adg), GFP_KERNEL);
200 if (!adg) {
201 dev_err(dev, "ADG allocate failed\n");
202 return -ENOMEM;
203 }
204
205 adg->clk[CLKA] = clk_get(NULL, "audio_clk_a");
206 adg->clk[CLKB] = clk_get(NULL, "audio_clk_b");
207 adg->clk[CLKC] = clk_get(NULL, "audio_clk_c");
208 adg->clk[CLKI] = clk_get(NULL, "audio_clk_internal");
209 for_each_rsnd_clk(clk, adg, i) {
210 if (IS_ERR(clk)) {
211 dev_err(dev, "Audio clock failed\n");
212 return -EIO;
213 }
214 }
215
216 rsnd_adg_ssi_clk_init(priv, adg);
217
218 priv->adg = adg;
219
220 dev_dbg(dev, "adg probed\n");
221
222 return 0;
223}
224
225void rsnd_adg_remove(struct platform_device *pdev,
226 struct rsnd_priv *priv)
227{
228 struct rsnd_adg *adg = priv->adg;
229 struct clk *clk;
230 int i;
231
232 for_each_rsnd_clk(clk, adg, i)
233 clk_put(clk);
234}
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
new file mode 100644
index 000000000000..a35706028514
--- /dev/null
+++ b/sound/soc/sh/rcar/core.c
@@ -0,0 +1,861 @@
1/*
2 * Renesas R-Car SRU/SCU/SSIU/SSI support
3 *
4 * Copyright (C) 2013 Renesas Solutions Corp.
5 * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
6 *
7 * Based on fsi.c
8 * Kuninori Morimoto <morimoto.kuninori@renesas.com>
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/*
16 * Renesas R-Car sound device structure
17 *
18 * Gen1
19 *
20 * SRU : Sound Routing Unit
21 * - SRC : Sampling Rate Converter
22 * - CMD
23 * - CTU : Channel Count Conversion Unit
24 * - MIX : Mixer
25 * - DVC : Digital Volume and Mute Function
26 * - SSI : Serial Sound Interface
27 *
28 * Gen2
29 *
30 * SCU : Sampling Rate Converter Unit
31 * - SRC : Sampling Rate Converter
32 * - CMD
33 * - CTU : Channel Count Conversion Unit
34 * - MIX : Mixer
35 * - DVC : Digital Volume and Mute Function
36 * SSIU : Serial Sound Interface Unit
37 * - SSI : Serial Sound Interface
38 */
39
40/*
41 * driver data Image
42 *
43 * rsnd_priv
44 * |
45 * | ** this depends on Gen1/Gen2
46 * |
47 * +- gen
48 * |
49 * | ** these depend on data path
50 * | ** gen and platform data control it
51 * |
52 * +- rdai[0]
53 * | | sru ssiu ssi
54 * | +- playback -> [mod] -> [mod] -> [mod] -> ...
55 * | |
56 * | | sru ssiu ssi
57 * | +- capture -> [mod] -> [mod] -> [mod] -> ...
58 * |
59 * +- rdai[1]
60 * | | sru ssiu ssi
61 * | +- playback -> [mod] -> [mod] -> [mod] -> ...
62 * | |
63 * | | sru ssiu ssi
64 * | +- capture -> [mod] -> [mod] -> [mod] -> ...
65 * ...
66 * |
67 * | ** these control ssi
68 * |
69 * +- ssi
70 * | |
71 * | +- ssi[0]
72 * | +- ssi[1]
73 * | +- ssi[2]
74 * | ...
75 * |
76 * | ** these control scu
77 * |
78 * +- scu
79 * |
80 * +- scu[0]
81 * +- scu[1]
82 * +- scu[2]
83 * ...
84 *
85 *
86 * for_each_rsnd_dai(xx, priv, xx)
87 * rdai[0] => rdai[1] => rdai[2] => ...
88 *
89 * for_each_rsnd_mod(xx, rdai, xx)
90 * [mod] => [mod] => [mod] => ...
91 *
92 * rsnd_dai_call(xxx, fn )
93 * [mod]->fn() -> [mod]->fn() -> [mod]->fn()...
94 *
95 */
96#include <linux/pm_runtime.h>
97#include "rsnd.h"
98
99#define RSND_RATES SNDRV_PCM_RATE_8000_96000
100#define RSND_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE)
101
102/*
103 * rsnd_platform functions
104 */
105#define rsnd_platform_call(priv, dai, func, param...) \
106 (!(priv->info->func) ? -ENODEV : \
107 priv->info->func(param))
108
109
110/*
111 * basic function
112 */
113u32 rsnd_read(struct rsnd_priv *priv,
114 struct rsnd_mod *mod, enum rsnd_reg reg)
115{
116 void __iomem *base = rsnd_gen_reg_get(priv, mod, reg);
117
118 BUG_ON(!base);
119
120 return ioread32(base);
121}
122
123void rsnd_write(struct rsnd_priv *priv,
124 struct rsnd_mod *mod,
125 enum rsnd_reg reg, u32 data)
126{
127 void __iomem *base = rsnd_gen_reg_get(priv, mod, reg);
128 struct device *dev = rsnd_priv_to_dev(priv);
129
130 BUG_ON(!base);
131
132 dev_dbg(dev, "w %p : %08x\n", base, data);
133
134 iowrite32(data, base);
135}
136
137void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod,
138 enum rsnd_reg reg, u32 mask, u32 data)
139{
140 void __iomem *base = rsnd_gen_reg_get(priv, mod, reg);
141 struct device *dev = rsnd_priv_to_dev(priv);
142 u32 val;
143
144 BUG_ON(!base);
145
146 val = ioread32(base);
147 val &= ~mask;
148 val |= data & mask;
149 iowrite32(val, base);
150
151 dev_dbg(dev, "s %p : %08x\n", base, val);
152}
153
154/*
155 * rsnd_mod functions
156 */
157char *rsnd_mod_name(struct rsnd_mod *mod)
158{
159 if (!mod || !mod->ops)
160 return "unknown";
161
162 return mod->ops->name;
163}
164
165void rsnd_mod_init(struct rsnd_priv *priv,
166 struct rsnd_mod *mod,
167 struct rsnd_mod_ops *ops,
168 int id)
169{
170 mod->priv = priv;
171 mod->id = id;
172 mod->ops = ops;
173 INIT_LIST_HEAD(&mod->list);
174}
175
176/*
177 * rsnd_dma functions
178 */
179static void rsnd_dma_continue(struct rsnd_dma *dma)
180{
181 /* push next A or B plane */
182 dma->submit_loop = 1;
183 schedule_work(&dma->work);
184}
185
186void rsnd_dma_start(struct rsnd_dma *dma)
187{
188 /* push both A and B plane*/
189 dma->submit_loop = 2;
190 schedule_work(&dma->work);
191}
192
193void rsnd_dma_stop(struct rsnd_dma *dma)
194{
195 dma->submit_loop = 0;
196 cancel_work_sync(&dma->work);
197 dmaengine_terminate_all(dma->chan);
198}
199
200static void rsnd_dma_complete(void *data)
201{
202 struct rsnd_dma *dma = (struct rsnd_dma *)data;
203 struct rsnd_priv *priv = dma->priv;
204 unsigned long flags;
205
206 rsnd_lock(priv, flags);
207
208 dma->complete(dma);
209
210 if (dma->submit_loop)
211 rsnd_dma_continue(dma);
212
213 rsnd_unlock(priv, flags);
214}
215
216static void rsnd_dma_do_work(struct work_struct *work)
217{
218 struct rsnd_dma *dma = container_of(work, struct rsnd_dma, work);
219 struct rsnd_priv *priv = dma->priv;
220 struct device *dev = rsnd_priv_to_dev(priv);
221 struct dma_async_tx_descriptor *desc;
222 dma_addr_t buf;
223 size_t len;
224 int i;
225
226 for (i = 0; i < dma->submit_loop; i++) {
227
228 if (dma->inquiry(dma, &buf, &len) < 0)
229 return;
230
231 desc = dmaengine_prep_slave_single(
232 dma->chan, buf, len, dma->dir,
233 DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
234 if (!desc) {
235 dev_err(dev, "dmaengine_prep_slave_sg() fail\n");
236 return;
237 }
238
239 desc->callback = rsnd_dma_complete;
240 desc->callback_param = dma;
241
242 if (dmaengine_submit(desc) < 0) {
243 dev_err(dev, "dmaengine_submit() fail\n");
244 return;
245 }
246
247 }
248
249 dma_async_issue_pending(dma->chan);
250}
251
252int rsnd_dma_available(struct rsnd_dma *dma)
253{
254 return !!dma->chan;
255}
256
257static bool rsnd_dma_filter(struct dma_chan *chan, void *param)
258{
259 chan->private = param;
260
261 return true;
262}
263
264int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
265 int is_play, int id,
266 int (*inquiry)(struct rsnd_dma *dma,
267 dma_addr_t *buf, int *len),
268 int (*complete)(struct rsnd_dma *dma))
269{
270 struct device *dev = rsnd_priv_to_dev(priv);
271 dma_cap_mask_t mask;
272
273 if (dma->chan) {
274 dev_err(dev, "it already has dma channel\n");
275 return -EIO;
276 }
277
278 dma_cap_zero(mask);
279 dma_cap_set(DMA_SLAVE, mask);
280
281 dma->slave.shdma_slave.slave_id = id;
282
283 dma->chan = dma_request_channel(mask, rsnd_dma_filter,
284 &dma->slave.shdma_slave);
285 if (!dma->chan) {
286 dev_err(dev, "can't get dma channel\n");
287 return -EIO;
288 }
289
290 dma->dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
291 dma->priv = priv;
292 dma->inquiry = inquiry;
293 dma->complete = complete;
294 INIT_WORK(&dma->work, rsnd_dma_do_work);
295
296 return 0;
297}
298
299void rsnd_dma_quit(struct rsnd_priv *priv,
300 struct rsnd_dma *dma)
301{
302 if (dma->chan)
303 dma_release_channel(dma->chan);
304
305 dma->chan = NULL;
306}
307
308/*
309 * rsnd_dai functions
310 */
311#define rsnd_dai_call(rdai, io, fn) \
312({ \
313 struct rsnd_mod *mod, *n; \
314 int ret = 0; \
315 for_each_rsnd_mod(mod, n, io) { \
316 ret = rsnd_mod_call(mod, fn, rdai, io); \
317 if (ret < 0) \
318 break; \
319 } \
320 ret; \
321})
322
323int rsnd_dai_connect(struct rsnd_dai *rdai,
324 struct rsnd_mod *mod,
325 struct rsnd_dai_stream *io)
326{
327 struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
328 struct device *dev = rsnd_priv_to_dev(priv);
329
330 if (!mod) {
331 dev_err(dev, "NULL mod\n");
332 return -EIO;
333 }
334
335 if (!list_empty(&mod->list)) {
336 dev_err(dev, "%s%d is not empty\n",
337 rsnd_mod_name(mod),
338 rsnd_mod_id(mod));
339 return -EIO;
340 }
341
342 list_add_tail(&mod->list, &io->head);
343
344 return 0;
345}
346
347int rsnd_dai_disconnect(struct rsnd_mod *mod)
348{
349 list_del_init(&mod->list);
350
351 return 0;
352}
353
354int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai)
355{
356 int id = rdai - priv->rdai;
357
358 if ((id < 0) || (id >= rsnd_dai_nr(priv)))
359 return -EINVAL;
360
361 return id;
362}
363
364struct rsnd_dai *rsnd_dai_get(struct rsnd_priv *priv, int id)
365{
366 return priv->rdai + id;
367}
368
369static struct rsnd_dai *rsnd_dai_to_rdai(struct snd_soc_dai *dai)
370{
371 struct rsnd_priv *priv = snd_soc_dai_get_drvdata(dai);
372
373 return rsnd_dai_get(priv, dai->id);
374}
375
376int rsnd_dai_is_play(struct rsnd_dai *rdai, struct rsnd_dai_stream *io)
377{
378 return &rdai->playback == io;
379}
380
381/*
382 * rsnd_soc_dai functions
383 */
384int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional)
385{
386 struct snd_pcm_substream *substream = io->substream;
387 struct snd_pcm_runtime *runtime = substream->runtime;
388 int pos = io->byte_pos + additional;
389
390 pos %= (runtime->periods * io->byte_per_period);
391
392 return pos;
393}
394
395void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int byte)
396{
397 io->byte_pos += byte;
398
399 if (io->byte_pos >= io->next_period_byte) {
400 struct snd_pcm_substream *substream = io->substream;
401 struct snd_pcm_runtime *runtime = substream->runtime;
402
403 io->period_pos++;
404 io->next_period_byte += io->byte_per_period;
405
406 if (io->period_pos >= runtime->periods) {
407 io->byte_pos = 0;
408 io->period_pos = 0;
409 io->next_period_byte = io->byte_per_period;
410 }
411
412 snd_pcm_period_elapsed(substream);
413 }
414}
415
416static int rsnd_dai_stream_init(struct rsnd_dai_stream *io,
417 struct snd_pcm_substream *substream)
418{
419 struct snd_pcm_runtime *runtime = substream->runtime;
420
421 if (!list_empty(&io->head))
422 return -EIO;
423
424 INIT_LIST_HEAD(&io->head);
425 io->substream = substream;
426 io->byte_pos = 0;
427 io->period_pos = 0;
428 io->byte_per_period = runtime->period_size *
429 runtime->channels *
430 samples_to_bytes(runtime, 1);
431 io->next_period_byte = io->byte_per_period;
432
433 return 0;
434}
435
436static
437struct snd_soc_dai *rsnd_substream_to_dai(struct snd_pcm_substream *substream)
438{
439 struct snd_soc_pcm_runtime *rtd = substream->private_data;
440
441 return rtd->cpu_dai;
442}
443
444static
445struct rsnd_dai_stream *rsnd_rdai_to_io(struct rsnd_dai *rdai,
446 struct snd_pcm_substream *substream)
447{
448 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
449 return &rdai->playback;
450 else
451 return &rdai->capture;
452}
453
454static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
455 struct snd_soc_dai *dai)
456{
457 struct rsnd_priv *priv = snd_soc_dai_get_drvdata(dai);
458 struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
459 struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
460 struct rsnd_mod *mod = rsnd_ssi_mod_get_frm_dai(priv,
461 rsnd_dai_id(priv, rdai),
462 rsnd_dai_is_play(rdai, io));
463 int ssi_id = rsnd_mod_id(mod);
464 int ret;
465 unsigned long flags;
466
467 rsnd_lock(priv, flags);
468
469 switch (cmd) {
470 case SNDRV_PCM_TRIGGER_START:
471 ret = rsnd_dai_stream_init(io, substream);
472 if (ret < 0)
473 goto dai_trigger_end;
474
475 ret = rsnd_platform_call(priv, dai, start, ssi_id);
476 if (ret < 0)
477 goto dai_trigger_end;
478
479 ret = rsnd_gen_path_init(priv, rdai, io);
480 if (ret < 0)
481 goto dai_trigger_end;
482
483 ret = rsnd_dai_call(rdai, io, init);
484 if (ret < 0)
485 goto dai_trigger_end;
486
487 ret = rsnd_dai_call(rdai, io, start);
488 if (ret < 0)
489 goto dai_trigger_end;
490 break;
491 case SNDRV_PCM_TRIGGER_STOP:
492 ret = rsnd_dai_call(rdai, io, stop);
493 if (ret < 0)
494 goto dai_trigger_end;
495
496 ret = rsnd_dai_call(rdai, io, quit);
497 if (ret < 0)
498 goto dai_trigger_end;
499
500 ret = rsnd_gen_path_exit(priv, rdai, io);
501 if (ret < 0)
502 goto dai_trigger_end;
503
504 ret = rsnd_platform_call(priv, dai, stop, ssi_id);
505 if (ret < 0)
506 goto dai_trigger_end;
507 break;
508 default:
509 ret = -EINVAL;
510 }
511
512dai_trigger_end:
513 rsnd_unlock(priv, flags);
514
515 return ret;
516}
517
518static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
519{
520 struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
521
522 /* set master/slave audio interface */
523 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
524 case SND_SOC_DAIFMT_CBM_CFM:
525 rdai->clk_master = 1;
526 break;
527 case SND_SOC_DAIFMT_CBS_CFS:
528 rdai->clk_master = 0;
529 break;
530 default:
531 return -EINVAL;
532 }
533
534 /* set clock inversion */
535 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
536 case SND_SOC_DAIFMT_NB_IF:
537 rdai->bit_clk_inv = 0;
538 rdai->frm_clk_inv = 1;
539 break;
540 case SND_SOC_DAIFMT_IB_NF:
541 rdai->bit_clk_inv = 1;
542 rdai->frm_clk_inv = 0;
543 break;
544 case SND_SOC_DAIFMT_IB_IF:
545 rdai->bit_clk_inv = 1;
546 rdai->frm_clk_inv = 1;
547 break;
548 case SND_SOC_DAIFMT_NB_NF:
549 default:
550 rdai->bit_clk_inv = 0;
551 rdai->frm_clk_inv = 0;
552 break;
553 }
554
555 /* set format */
556 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
557 case SND_SOC_DAIFMT_I2S:
558 rdai->sys_delay = 0;
559 rdai->data_alignment = 0;
560 break;
561 case SND_SOC_DAIFMT_LEFT_J:
562 rdai->sys_delay = 1;
563 rdai->data_alignment = 0;
564 break;
565 case SND_SOC_DAIFMT_RIGHT_J:
566 rdai->sys_delay = 1;
567 rdai->data_alignment = 1;
568 break;
569 }
570
571 return 0;
572}
573
574static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
575 .trigger = rsnd_soc_dai_trigger,
576 .set_fmt = rsnd_soc_dai_set_fmt,
577};
578
579static int rsnd_dai_probe(struct platform_device *pdev,
580 struct rcar_snd_info *info,
581 struct rsnd_priv *priv)
582{
583 struct snd_soc_dai_driver *drv;
584 struct rsnd_dai *rdai;
585 struct rsnd_mod *pmod, *cmod;
586 struct device *dev = rsnd_priv_to_dev(priv);
587 int dai_nr;
588 int i;
589
590 /* get max dai nr */
591 for (dai_nr = 0; dai_nr < 32; dai_nr++) {
592 pmod = rsnd_ssi_mod_get_frm_dai(priv, dai_nr, 1);
593 cmod = rsnd_ssi_mod_get_frm_dai(priv, dai_nr, 0);
594
595 if (!pmod && !cmod)
596 break;
597 }
598
599 if (!dai_nr) {
600 dev_err(dev, "no dai\n");
601 return -EIO;
602 }
603
604 drv = devm_kzalloc(dev, sizeof(*drv) * dai_nr, GFP_KERNEL);
605 rdai = devm_kzalloc(dev, sizeof(*rdai) * dai_nr, GFP_KERNEL);
606 if (!drv || !rdai) {
607 dev_err(dev, "dai allocate failed\n");
608 return -ENOMEM;
609 }
610
611 for (i = 0; i < dai_nr; i++) {
612
613 pmod = rsnd_ssi_mod_get_frm_dai(priv, i, 1);
614 cmod = rsnd_ssi_mod_get_frm_dai(priv, i, 0);
615
616 /*
617 * init rsnd_dai
618 */
619 INIT_LIST_HEAD(&rdai[i].playback.head);
620 INIT_LIST_HEAD(&rdai[i].capture.head);
621
622 snprintf(rdai[i].name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", i);
623
624 /*
625 * init snd_soc_dai_driver
626 */
627 drv[i].name = rdai[i].name;
628 drv[i].ops = &rsnd_soc_dai_ops;
629 if (pmod) {
630 drv[i].playback.rates = RSND_RATES;
631 drv[i].playback.formats = RSND_FMTS;
632 drv[i].playback.channels_min = 2;
633 drv[i].playback.channels_max = 2;
634 }
635 if (cmod) {
636 drv[i].capture.rates = RSND_RATES;
637 drv[i].capture.formats = RSND_FMTS;
638 drv[i].capture.channels_min = 2;
639 drv[i].capture.channels_max = 2;
640 }
641
642 dev_dbg(dev, "%s (%s/%s)\n", rdai[i].name,
643 pmod ? "play" : " -- ",
644 cmod ? "capture" : " -- ");
645 }
646
647 priv->dai_nr = dai_nr;
648 priv->daidrv = drv;
649 priv->rdai = rdai;
650
651 return 0;
652}
653
654static void rsnd_dai_remove(struct platform_device *pdev,
655 struct rsnd_priv *priv)
656{
657}
658
659/*
660 * pcm ops
661 */
662static struct snd_pcm_hardware rsnd_pcm_hardware = {
663 .info = SNDRV_PCM_INFO_INTERLEAVED |
664 SNDRV_PCM_INFO_MMAP |
665 SNDRV_PCM_INFO_MMAP_VALID |
666 SNDRV_PCM_INFO_PAUSE,
667 .formats = RSND_FMTS,
668 .rates = RSND_RATES,
669 .rate_min = 8000,
670 .rate_max = 192000,
671 .channels_min = 2,
672 .channels_max = 2,
673 .buffer_bytes_max = 64 * 1024,
674 .period_bytes_min = 32,
675 .period_bytes_max = 8192,
676 .periods_min = 1,
677 .periods_max = 32,
678 .fifo_size = 256,
679};
680
681static int rsnd_pcm_open(struct snd_pcm_substream *substream)
682{
683 struct snd_pcm_runtime *runtime = substream->runtime;
684 int ret = 0;
685
686 snd_soc_set_runtime_hwparams(substream, &rsnd_pcm_hardware);
687
688 ret = snd_pcm_hw_constraint_integer(runtime,
689 SNDRV_PCM_HW_PARAM_PERIODS);
690
691 return ret;
692}
693
694static int rsnd_hw_params(struct snd_pcm_substream *substream,
695 struct snd_pcm_hw_params *hw_params)
696{
697 return snd_pcm_lib_malloc_pages(substream,
698 params_buffer_bytes(hw_params));
699}
700
701static snd_pcm_uframes_t rsnd_pointer(struct snd_pcm_substream *substream)
702{
703 struct snd_pcm_runtime *runtime = substream->runtime;
704 struct snd_soc_dai *dai = rsnd_substream_to_dai(substream);
705 struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
706 struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
707
708 return bytes_to_frames(runtime, io->byte_pos);
709}
710
711static struct snd_pcm_ops rsnd_pcm_ops = {
712 .open = rsnd_pcm_open,
713 .ioctl = snd_pcm_lib_ioctl,
714 .hw_params = rsnd_hw_params,
715 .hw_free = snd_pcm_lib_free_pages,
716 .pointer = rsnd_pointer,
717};
718
719/*
720 * snd_soc_platform
721 */
722
723#define PREALLOC_BUFFER (32 * 1024)
724#define PREALLOC_BUFFER_MAX (32 * 1024)
725
726static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd)
727{
728 return snd_pcm_lib_preallocate_pages_for_all(
729 rtd->pcm,
730 SNDRV_DMA_TYPE_DEV,
731 rtd->card->snd_card->dev,
732 PREALLOC_BUFFER, PREALLOC_BUFFER_MAX);
733}
734
735static void rsnd_pcm_free(struct snd_pcm *pcm)
736{
737 snd_pcm_lib_preallocate_free_for_all(pcm);
738}
739
740static struct snd_soc_platform_driver rsnd_soc_platform = {
741 .ops = &rsnd_pcm_ops,
742 .pcm_new = rsnd_pcm_new,
743 .pcm_free = rsnd_pcm_free,
744};
745
746static const struct snd_soc_component_driver rsnd_soc_component = {
747 .name = "rsnd",
748};
749
750/*
751 * rsnd probe
752 */
753static int rsnd_probe(struct platform_device *pdev)
754{
755 struct rcar_snd_info *info;
756 struct rsnd_priv *priv;
757 struct device *dev = &pdev->dev;
758 int ret;
759
760 info = pdev->dev.platform_data;
761 if (!info) {
762 dev_err(dev, "driver needs R-Car sound information\n");
763 return -ENODEV;
764 }
765
766 /*
767 * init priv data
768 */
769 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
770 if (!priv) {
771 dev_err(dev, "priv allocate failed\n");
772 return -ENODEV;
773 }
774
775 priv->dev = dev;
776 priv->info = info;
777 spin_lock_init(&priv->lock);
778
779 /*
780 * init each module
781 */
782 ret = rsnd_gen_probe(pdev, info, priv);
783 if (ret < 0)
784 return ret;
785
786 ret = rsnd_scu_probe(pdev, info, priv);
787 if (ret < 0)
788 return ret;
789
790 ret = rsnd_adg_probe(pdev, info, priv);
791 if (ret < 0)
792 return ret;
793
794 ret = rsnd_ssi_probe(pdev, info, priv);
795 if (ret < 0)
796 return ret;
797
798 ret = rsnd_dai_probe(pdev, info, priv);
799 if (ret < 0)
800 return ret;
801
802 /*
803 * asoc register
804 */
805 ret = snd_soc_register_platform(dev, &rsnd_soc_platform);
806 if (ret < 0) {
807 dev_err(dev, "cannot snd soc register\n");
808 return ret;
809 }
810
811 ret = snd_soc_register_component(dev, &rsnd_soc_component,
812 priv->daidrv, rsnd_dai_nr(priv));
813 if (ret < 0) {
814 dev_err(dev, "cannot snd dai register\n");
815 goto exit_snd_soc;
816 }
817
818 dev_set_drvdata(dev, priv);
819
820 pm_runtime_enable(dev);
821
822 dev_info(dev, "probed\n");
823 return ret;
824
825exit_snd_soc:
826 snd_soc_unregister_platform(dev);
827
828 return ret;
829}
830
831static int rsnd_remove(struct platform_device *pdev)
832{
833 struct rsnd_priv *priv = dev_get_drvdata(&pdev->dev);
834
835 pm_runtime_disable(&pdev->dev);
836
837 /*
838 * remove each module
839 */
840 rsnd_ssi_remove(pdev, priv);
841 rsnd_adg_remove(pdev, priv);
842 rsnd_scu_remove(pdev, priv);
843 rsnd_dai_remove(pdev, priv);
844 rsnd_gen_remove(pdev, priv);
845
846 return 0;
847}
848
849static struct platform_driver rsnd_driver = {
850 .driver = {
851 .name = "rcar_sound",
852 },
853 .probe = rsnd_probe,
854 .remove = rsnd_remove,
855};
856module_platform_driver(rsnd_driver);
857
858MODULE_LICENSE("GPL");
859MODULE_DESCRIPTION("Renesas R-Car audio driver");
860MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
861MODULE_ALIAS("platform:rcar-pcm-audio");
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c
new file mode 100644
index 000000000000..babb203b43b7
--- /dev/null
+++ b/sound/soc/sh/rcar/gen.c
@@ -0,0 +1,280 @@
1/*
2 * Renesas R-Car Gen1 SRU/SSI support
3 *
4 * Copyright (C) 2013 Renesas Solutions Corp.
5 * Kuninori Morimoto <kuninori.morimoto.gx@renesas.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 version 2 as
9 * published by the Free Software Foundation.
10 */
11#include "rsnd.h"
12
13struct rsnd_gen_ops {
14 int (*path_init)(struct rsnd_priv *priv,
15 struct rsnd_dai *rdai,
16 struct rsnd_dai_stream *io);
17 int (*path_exit)(struct rsnd_priv *priv,
18 struct rsnd_dai *rdai,
19 struct rsnd_dai_stream *io);
20};
21
22struct rsnd_gen_reg_map {
23 int index; /* -1 : not supported */
24 u32 offset_id; /* offset of ssi0, ssi1, ssi2... */
25 u32 offset_adr; /* offset of SSICR, SSISR, ... */
26};
27
28struct rsnd_gen {
29 void __iomem *base[RSND_BASE_MAX];
30
31 struct rsnd_gen_reg_map reg_map[RSND_REG_MAX];
32 struct rsnd_gen_ops *ops;
33};
34
35#define rsnd_priv_to_gen(p) ((struct rsnd_gen *)(p)->gen)
36
37/*
38 * Gen2
39 * will be filled in the future
40 */
41
42/*
43 * Gen1
44 */
45static int rsnd_gen1_path_init(struct rsnd_priv *priv,
46 struct rsnd_dai *rdai,
47 struct rsnd_dai_stream *io)
48{
49 struct rsnd_mod *mod;
50 int ret;
51 int id;
52
53 /*
54 * Gen1 is created by SRU/SSI, and this SRU is base module of
55 * Gen2's SCU/SSIU/SSI. (Gen2 SCU/SSIU came from SRU)
56 *
57 * Easy image is..
58 * Gen1 SRU = Gen2 SCU + SSIU + etc
59 *
60 * Gen2 SCU path is very flexible, but, Gen1 SRU (SCU parts) is
61 * using fixed path.
62 *
63 * Then, SSI id = SCU id here
64 */
65
66 /* get SSI's ID */
67 mod = rsnd_ssi_mod_get_frm_dai(priv,
68 rsnd_dai_id(priv, rdai),
69 rsnd_dai_is_play(rdai, io));
70 id = rsnd_mod_id(mod);
71
72 /* SSI */
73 mod = rsnd_ssi_mod_get(priv, id);
74 ret = rsnd_dai_connect(rdai, mod, io);
75 if (ret < 0)
76 return ret;
77
78 /* SCU */
79 mod = rsnd_scu_mod_get(priv, id);
80 ret = rsnd_dai_connect(rdai, mod, io);
81
82 return ret;
83}
84
85static int rsnd_gen1_path_exit(struct rsnd_priv *priv,
86 struct rsnd_dai *rdai,
87 struct rsnd_dai_stream *io)
88{
89 struct rsnd_mod *mod, *n;
90 int ret = 0;
91
92 /*
93 * remove all mod from rdai
94 */
95 for_each_rsnd_mod(mod, n, io)
96 ret |= rsnd_dai_disconnect(mod);
97
98 return ret;
99}
100
101static struct rsnd_gen_ops rsnd_gen1_ops = {
102 .path_init = rsnd_gen1_path_init,
103 .path_exit = rsnd_gen1_path_exit,
104};
105
106#define RSND_GEN1_REG_MAP(g, s, i, oi, oa) \
107 do { \
108 (g)->reg_map[RSND_REG_##i].index = RSND_GEN1_##s; \
109 (g)->reg_map[RSND_REG_##i].offset_id = oi; \
110 (g)->reg_map[RSND_REG_##i].offset_adr = oa; \
111 } while (0)
112
113static void rsnd_gen1_reg_map_init(struct rsnd_gen *gen)
114{
115 RSND_GEN1_REG_MAP(gen, SRU, SRC_ROUTE_SEL, 0x0, 0x00);
116 RSND_GEN1_REG_MAP(gen, SRU, SRC_TMG_SEL0, 0x0, 0x08);
117 RSND_GEN1_REG_MAP(gen, SRU, SRC_TMG_SEL1, 0x0, 0x0c);
118 RSND_GEN1_REG_MAP(gen, SRU, SRC_TMG_SEL2, 0x0, 0x10);
119 RSND_GEN1_REG_MAP(gen, SRU, SRC_CTRL, 0x0, 0xc0);
120 RSND_GEN1_REG_MAP(gen, SRU, SSI_MODE0, 0x0, 0xD0);
121 RSND_GEN1_REG_MAP(gen, SRU, SSI_MODE1, 0x0, 0xD4);
122 RSND_GEN1_REG_MAP(gen, SRU, BUSIF_MODE, 0x4, 0x20);
123 RSND_GEN1_REG_MAP(gen, SRU, BUSIF_ADINR, 0x40, 0x214);
124
125 RSND_GEN1_REG_MAP(gen, ADG, BRRA, 0x0, 0x00);
126 RSND_GEN1_REG_MAP(gen, ADG, BRRB, 0x0, 0x04);
127 RSND_GEN1_REG_MAP(gen, ADG, SSICKR, 0x0, 0x08);
128 RSND_GEN1_REG_MAP(gen, ADG, AUDIO_CLK_SEL0, 0x0, 0x0c);
129 RSND_GEN1_REG_MAP(gen, ADG, AUDIO_CLK_SEL1, 0x0, 0x10);
130 RSND_GEN1_REG_MAP(gen, ADG, AUDIO_CLK_SEL3, 0x0, 0x18);
131 RSND_GEN1_REG_MAP(gen, ADG, AUDIO_CLK_SEL4, 0x0, 0x1c);
132 RSND_GEN1_REG_MAP(gen, ADG, AUDIO_CLK_SEL5, 0x0, 0x20);
133
134 RSND_GEN1_REG_MAP(gen, SSI, SSICR, 0x40, 0x00);
135 RSND_GEN1_REG_MAP(gen, SSI, SSISR, 0x40, 0x04);
136 RSND_GEN1_REG_MAP(gen, SSI, SSITDR, 0x40, 0x08);
137 RSND_GEN1_REG_MAP(gen, SSI, SSIRDR, 0x40, 0x0c);
138 RSND_GEN1_REG_MAP(gen, SSI, SSIWSR, 0x40, 0x20);
139}
140
141static int rsnd_gen1_probe(struct platform_device *pdev,
142 struct rcar_snd_info *info,
143 struct rsnd_priv *priv)
144{
145 struct device *dev = rsnd_priv_to_dev(priv);
146 struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
147 struct resource *sru_res;
148 struct resource *adg_res;
149 struct resource *ssi_res;
150
151 /*
152 * map address
153 */
154 sru_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_SRU);
155 adg_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_ADG);
156 ssi_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_SSI);
157
158 gen->base[RSND_GEN1_SRU] = devm_ioremap_resource(dev, sru_res);
159 gen->base[RSND_GEN1_ADG] = devm_ioremap_resource(dev, adg_res);
160 gen->base[RSND_GEN1_SSI] = devm_ioremap_resource(dev, ssi_res);
161 if (IS_ERR(gen->base[RSND_GEN1_SRU]) ||
162 IS_ERR(gen->base[RSND_GEN1_ADG]) ||
163 IS_ERR(gen->base[RSND_GEN1_SSI]))
164 return -ENODEV;
165
166 gen->ops = &rsnd_gen1_ops;
167 rsnd_gen1_reg_map_init(gen);
168
169 dev_dbg(dev, "Gen1 device probed\n");
170 dev_dbg(dev, "SRU : %08x => %p\n", sru_res->start,
171 gen->base[RSND_GEN1_SRU]);
172 dev_dbg(dev, "ADG : %08x => %p\n", adg_res->start,
173 gen->base[RSND_GEN1_ADG]);
174 dev_dbg(dev, "SSI : %08x => %p\n", ssi_res->start,
175 gen->base[RSND_GEN1_SSI]);
176
177 return 0;
178
179}
180
181static void rsnd_gen1_remove(struct platform_device *pdev,
182 struct rsnd_priv *priv)
183{
184}
185
186/*
187 * Gen
188 */
189int rsnd_gen_path_init(struct rsnd_priv *priv,
190 struct rsnd_dai *rdai,
191 struct rsnd_dai_stream *io)
192{
193 struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
194
195 return gen->ops->path_init(priv, rdai, io);
196}
197
198int rsnd_gen_path_exit(struct rsnd_priv *priv,
199 struct rsnd_dai *rdai,
200 struct rsnd_dai_stream *io)
201{
202 struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
203
204 return gen->ops->path_exit(priv, rdai, io);
205}
206
207void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
208 struct rsnd_mod *mod,
209 enum rsnd_reg reg)
210{
211 struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
212 struct device *dev = rsnd_priv_to_dev(priv);
213 int index;
214 u32 offset_id, offset_adr;
215
216 if (reg >= RSND_REG_MAX) {
217 dev_err(dev, "rsnd_reg reg error\n");
218 return NULL;
219 }
220
221 index = gen->reg_map[reg].index;
222 offset_id = gen->reg_map[reg].offset_id;
223 offset_adr = gen->reg_map[reg].offset_adr;
224
225 if (index < 0) {
226 dev_err(dev, "unsupported reg access %d\n", reg);
227 return NULL;
228 }
229
230 if (offset_id && mod)
231 offset_id *= rsnd_mod_id(mod);
232
233 /*
234 * index/offset were set on gen1/gen2
235 */
236
237 return gen->base[index] + offset_id + offset_adr;
238}
239
240int rsnd_gen_probe(struct platform_device *pdev,
241 struct rcar_snd_info *info,
242 struct rsnd_priv *priv)
243{
244 struct device *dev = rsnd_priv_to_dev(priv);
245 struct rsnd_gen *gen;
246 int i;
247
248 gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL);
249 if (!gen) {
250 dev_err(dev, "GEN allocate failed\n");
251 return -ENOMEM;
252 }
253
254 priv->gen = gen;
255
256 /*
257 * see
258 * rsnd_reg_get()
259 * rsnd_gen_probe()
260 */
261 for (i = 0; i < RSND_REG_MAX; i++)
262 gen->reg_map[i].index = -1;
263
264 /*
265 * init each module
266 */
267 if (rsnd_is_gen1(priv))
268 return rsnd_gen1_probe(pdev, info, priv);
269
270 dev_err(dev, "unknown generation R-Car sound device\n");
271
272 return -ENODEV;
273}
274
275void rsnd_gen_remove(struct platform_device *pdev,
276 struct rsnd_priv *priv)
277{
278 if (rsnd_is_gen1(priv))
279 rsnd_gen1_remove(pdev, priv);
280}
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
new file mode 100644
index 000000000000..9cc6986a8cfb
--- /dev/null
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -0,0 +1,302 @@
1/*
2 * Renesas R-Car
3 *
4 * Copyright (C) 2013 Renesas Solutions Corp.
5 * Kuninori Morimoto <kuninori.morimoto.gx@renesas.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 version 2 as
9 * published by the Free Software Foundation.
10 */
11#ifndef RSND_H
12#define RSND_H
13
14#include <linux/clk.h>
15#include <linux/device.h>
16#include <linux/dma-mapping.h>
17#include <linux/io.h>
18#include <linux/list.h>
19#include <linux/module.h>
20#include <linux/sh_dma.h>
21#include <linux/workqueue.h>
22#include <sound/rcar_snd.h>
23#include <sound/soc.h>
24#include <sound/pcm_params.h>
25
26/*
27 * pseudo register
28 *
29 * The register address offsets SRU/SCU/SSIU on Gen1/Gen2 are very different.
30 * This driver uses pseudo register in order to hide it.
31 * see gen1/gen2 for detail
32 */
33enum rsnd_reg {
34 /* SRU/SCU */
35 RSND_REG_SRC_ROUTE_SEL,
36 RSND_REG_SRC_TMG_SEL0,
37 RSND_REG_SRC_TMG_SEL1,
38 RSND_REG_SRC_TMG_SEL2,
39 RSND_REG_SRC_CTRL,
40 RSND_REG_SSI_MODE0,
41 RSND_REG_SSI_MODE1,
42 RSND_REG_BUSIF_MODE,
43 RSND_REG_BUSIF_ADINR,
44
45 /* ADG */
46 RSND_REG_BRRA,
47 RSND_REG_BRRB,
48 RSND_REG_SSICKR,
49 RSND_REG_AUDIO_CLK_SEL0,
50 RSND_REG_AUDIO_CLK_SEL1,
51 RSND_REG_AUDIO_CLK_SEL2,
52 RSND_REG_AUDIO_CLK_SEL3,
53 RSND_REG_AUDIO_CLK_SEL4,
54 RSND_REG_AUDIO_CLK_SEL5,
55
56 /* SSI */
57 RSND_REG_SSICR,
58 RSND_REG_SSISR,
59 RSND_REG_SSITDR,
60 RSND_REG_SSIRDR,
61 RSND_REG_SSIWSR,
62
63 RSND_REG_MAX,
64};
65
66struct rsnd_priv;
67struct rsnd_mod;
68struct rsnd_dai;
69struct rsnd_dai_stream;
70
71/*
72 * R-Car basic functions
73 */
74#define rsnd_mod_read(m, r) \
75 rsnd_read(rsnd_mod_to_priv(m), m, RSND_REG_##r)
76#define rsnd_mod_write(m, r, d) \
77 rsnd_write(rsnd_mod_to_priv(m), m, RSND_REG_##r, d)
78#define rsnd_mod_bset(m, r, s, d) \
79 rsnd_bset(rsnd_mod_to_priv(m), m, RSND_REG_##r, s, d)
80
81#define rsnd_priv_read(p, r) rsnd_read(p, NULL, RSND_REG_##r)
82#define rsnd_priv_write(p, r, d) rsnd_write(p, NULL, RSND_REG_##r, d)
83#define rsnd_priv_bset(p, r, s, d) rsnd_bset(p, NULL, RSND_REG_##r, s, d)
84
85u32 rsnd_read(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg);
86void rsnd_write(struct rsnd_priv *priv, struct rsnd_mod *mod,
87 enum rsnd_reg reg, u32 data);
88void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg,
89 u32 mask, u32 data);
90
91/*
92 * R-Car DMA
93 */
94struct rsnd_dma {
95 struct rsnd_priv *priv;
96 struct sh_dmae_slave slave;
97 struct work_struct work;
98 struct dma_chan *chan;
99 enum dma_data_direction dir;
100 int (*inquiry)(struct rsnd_dma *dma, dma_addr_t *buf, int *len);
101 int (*complete)(struct rsnd_dma *dma);
102
103 int submit_loop;
104};
105
106void rsnd_dma_start(struct rsnd_dma *dma);
107void rsnd_dma_stop(struct rsnd_dma *dma);
108int rsnd_dma_available(struct rsnd_dma *dma);
109int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
110 int is_play, int id,
111 int (*inquiry)(struct rsnd_dma *dma, dma_addr_t *buf, int *len),
112 int (*complete)(struct rsnd_dma *dma));
113void rsnd_dma_quit(struct rsnd_priv *priv,
114 struct rsnd_dma *dma);
115
116
117/*
118 * R-Car sound mod
119 */
120
121struct rsnd_mod_ops {
122 char *name;
123 int (*init)(struct rsnd_mod *mod,
124 struct rsnd_dai *rdai,
125 struct rsnd_dai_stream *io);
126 int (*quit)(struct rsnd_mod *mod,
127 struct rsnd_dai *rdai,
128 struct rsnd_dai_stream *io);
129 int (*start)(struct rsnd_mod *mod,
130 struct rsnd_dai *rdai,
131 struct rsnd_dai_stream *io);
132 int (*stop)(struct rsnd_mod *mod,
133 struct rsnd_dai *rdai,
134 struct rsnd_dai_stream *io);
135};
136
137struct rsnd_mod {
138 int id;
139 struct rsnd_priv *priv;
140 struct rsnd_mod_ops *ops;
141 struct list_head list; /* connect to rsnd_dai playback/capture */
142 struct rsnd_dma dma;
143};
144
145#define rsnd_mod_to_priv(mod) ((mod)->priv)
146#define rsnd_mod_to_dma(mod) (&(mod)->dma)
147#define rsnd_dma_to_mod(_dma) container_of((_dma), struct rsnd_mod, dma)
148#define rsnd_mod_id(mod) ((mod)->id)
149#define for_each_rsnd_mod(pos, n, io) \
150 list_for_each_entry_safe(pos, n, &(io)->head, list)
151#define rsnd_mod_call(mod, func, rdai, io) \
152 (!(mod) ? -ENODEV : \
153 !((mod)->ops->func) ? 0 : \
154 (mod)->ops->func(mod, rdai, io))
155
156void rsnd_mod_init(struct rsnd_priv *priv,
157 struct rsnd_mod *mod,
158 struct rsnd_mod_ops *ops,
159 int id);
160char *rsnd_mod_name(struct rsnd_mod *mod);
161
162/*
163 * R-Car sound DAI
164 */
165#define RSND_DAI_NAME_SIZE 16
166struct rsnd_dai_stream {
167 struct list_head head; /* head of rsnd_mod list */
168 struct snd_pcm_substream *substream;
169 int byte_pos;
170 int period_pos;
171 int byte_per_period;
172 int next_period_byte;
173};
174
175struct rsnd_dai {
176 char name[RSND_DAI_NAME_SIZE];
177 struct rsnd_dai_platform_info *info; /* rcar_snd.h */
178 struct rsnd_dai_stream playback;
179 struct rsnd_dai_stream capture;
180
181 int clk_master:1;
182 int bit_clk_inv:1;
183 int frm_clk_inv:1;
184 int sys_delay:1;
185 int data_alignment:1;
186};
187
188#define rsnd_dai_nr(priv) ((priv)->dai_nr)
189#define for_each_rsnd_dai(rdai, priv, i) \
190 for (i = 0, (rdai) = rsnd_dai_get(priv, i); \
191 i < rsnd_dai_nr(priv); \
192 i++, (rdai) = rsnd_dai_get(priv, i))
193
194struct rsnd_dai *rsnd_dai_get(struct rsnd_priv *priv, int id);
195int rsnd_dai_disconnect(struct rsnd_mod *mod);
196int rsnd_dai_connect(struct rsnd_dai *rdai, struct rsnd_mod *mod,
197 struct rsnd_dai_stream *io);
198int rsnd_dai_is_play(struct rsnd_dai *rdai, struct rsnd_dai_stream *io);
199int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai);
200#define rsnd_dai_get_platform_info(rdai) ((rdai)->info)
201#define rsnd_io_to_runtime(io) ((io)->substream->runtime)
202
203void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt);
204int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional);
205
206/*
207 * R-Car Gen1/Gen2
208 */
209int rsnd_gen_probe(struct platform_device *pdev,
210 struct rcar_snd_info *info,
211 struct rsnd_priv *priv);
212void rsnd_gen_remove(struct platform_device *pdev,
213 struct rsnd_priv *priv);
214int rsnd_gen_path_init(struct rsnd_priv *priv,
215 struct rsnd_dai *rdai,
216 struct rsnd_dai_stream *io);
217int rsnd_gen_path_exit(struct rsnd_priv *priv,
218 struct rsnd_dai *rdai,
219 struct rsnd_dai_stream *io);
220void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
221 struct rsnd_mod *mod,
222 enum rsnd_reg reg);
223#define rsnd_is_gen1(s) ((s)->info->flags & RSND_GEN1)
224#define rsnd_is_gen2(s) ((s)->info->flags & RSND_GEN2)
225
226/*
227 * R-Car ADG
228 */
229int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod);
230int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate);
231int rsnd_adg_probe(struct platform_device *pdev,
232 struct rcar_snd_info *info,
233 struct rsnd_priv *priv);
234void rsnd_adg_remove(struct platform_device *pdev,
235 struct rsnd_priv *priv);
236
237/*
238 * R-Car sound priv
239 */
240struct rsnd_priv {
241
242 struct device *dev;
243 struct rcar_snd_info *info;
244 spinlock_t lock;
245
246 /*
247 * below value will be filled on rsnd_gen_probe()
248 */
249 void *gen;
250
251 /*
252 * below value will be filled on rsnd_scu_probe()
253 */
254 void *scu;
255 int scu_nr;
256
257 /*
258 * below value will be filled on rsnd_adg_probe()
259 */
260 void *adg;
261
262 /*
263 * below value will be filled on rsnd_ssi_probe()
264 */
265 void *ssiu;
266
267 /*
268 * below value will be filled on rsnd_dai_probe()
269 */
270 struct snd_soc_dai_driver *daidrv;
271 struct rsnd_dai *rdai;
272 int dai_nr;
273};
274
275#define rsnd_priv_to_dev(priv) ((priv)->dev)
276#define rsnd_lock(priv, flags) spin_lock_irqsave(&priv->lock, flags)
277#define rsnd_unlock(priv, flags) spin_unlock_irqrestore(&priv->lock, flags)
278
279/*
280 * R-Car SCU
281 */
282int rsnd_scu_probe(struct platform_device *pdev,
283 struct rcar_snd_info *info,
284 struct rsnd_priv *priv);
285void rsnd_scu_remove(struct platform_device *pdev,
286 struct rsnd_priv *priv);
287struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id);
288#define rsnd_scu_nr(priv) ((priv)->scu_nr)
289
290/*
291 * R-Car SSI
292 */
293int rsnd_ssi_probe(struct platform_device *pdev,
294 struct rcar_snd_info *info,
295 struct rsnd_priv *priv);
296void rsnd_ssi_remove(struct platform_device *pdev,
297 struct rsnd_priv *priv);
298struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id);
299struct rsnd_mod *rsnd_ssi_mod_get_frm_dai(struct rsnd_priv *priv,
300 int dai_id, int is_play);
301
302#endif
diff --git a/sound/soc/sh/rcar/scu.c b/sound/soc/sh/rcar/scu.c
new file mode 100644
index 000000000000..184d9008cecd
--- /dev/null
+++ b/sound/soc/sh/rcar/scu.c
@@ -0,0 +1,236 @@
1/*
2 * Renesas R-Car SCU support
3 *
4 * Copyright (C) 2013 Renesas Solutions Corp.
5 * Kuninori Morimoto <kuninori.morimoto.gx@renesas.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 version 2 as
9 * published by the Free Software Foundation.
10 */
11#include "rsnd.h"
12
13struct rsnd_scu {
14 struct rsnd_scu_platform_info *info; /* rcar_snd.h */
15 struct rsnd_mod mod;
16};
17
18#define rsnd_scu_mode_flags(p) ((p)->info->flags)
19
20/*
21 * ADINR
22 */
23#define OTBL_24 (0 << 16)
24#define OTBL_22 (2 << 16)
25#define OTBL_20 (4 << 16)
26#define OTBL_18 (6 << 16)
27#define OTBL_16 (8 << 16)
28
29
30#define rsnd_mod_to_scu(_mod) \
31 container_of((_mod), struct rsnd_scu, mod)
32
33#define for_each_rsnd_scu(pos, priv, i) \
34 for ((i) = 0; \
35 ((i) < rsnd_scu_nr(priv)) && \
36 ((pos) = (struct rsnd_scu *)(priv)->scu + i); \
37 i++)
38
39static int rsnd_scu_set_route(struct rsnd_priv *priv,
40 struct rsnd_mod *mod,
41 struct rsnd_dai *rdai,
42 struct rsnd_dai_stream *io)
43{
44 struct scu_route_config {
45 u32 mask;
46 int shift;
47 } routes[] = {
48 { 0xF, 0, }, /* 0 */
49 { 0xF, 4, }, /* 1 */
50 { 0xF, 8, }, /* 2 */
51 { 0x7, 12, }, /* 3 */
52 { 0x7, 16, }, /* 4 */
53 { 0x7, 20, }, /* 5 */
54 { 0x7, 24, }, /* 6 */
55 { 0x3, 28, }, /* 7 */
56 { 0x3, 30, }, /* 8 */
57 };
58
59 u32 mask;
60 u32 val;
61 int shift;
62 int id;
63
64 /*
65 * Gen1 only
66 */
67 if (!rsnd_is_gen1(priv))
68 return 0;
69
70 id = rsnd_mod_id(mod);
71 if (id < 0 || id > ARRAY_SIZE(routes))
72 return -EIO;
73
74 /*
75 * SRC_ROUTE_SELECT
76 */
77 val = rsnd_dai_is_play(rdai, io) ? 0x1 : 0x2;
78 val = val << routes[id].shift;
79 mask = routes[id].mask << routes[id].shift;
80
81 rsnd_mod_bset(mod, SRC_ROUTE_SEL, mask, val);
82
83 /*
84 * SRC_TIMING_SELECT
85 */
86 shift = (id % 4) * 8;
87 mask = 0x1F << shift;
88 if (8 == id) /* SRU8 is very special */
89 val = id << shift;
90 else
91 val = (id + 1) << shift;
92
93 switch (id / 4) {
94 case 0:
95 rsnd_mod_bset(mod, SRC_TMG_SEL0, mask, val);
96 break;
97 case 1:
98 rsnd_mod_bset(mod, SRC_TMG_SEL1, mask, val);
99 break;
100 case 2:
101 rsnd_mod_bset(mod, SRC_TMG_SEL2, mask, val);
102 break;
103 }
104
105 return 0;
106}
107
108static int rsnd_scu_set_mode(struct rsnd_priv *priv,
109 struct rsnd_mod *mod,
110 struct rsnd_dai *rdai,
111 struct rsnd_dai_stream *io)
112{
113 int id = rsnd_mod_id(mod);
114 u32 val;
115
116 if (rsnd_is_gen1(priv)) {
117 val = (1 << id);
118 rsnd_mod_bset(mod, SRC_CTRL, val, val);
119 }
120
121 return 0;
122}
123
124static int rsnd_scu_set_hpbif(struct rsnd_priv *priv,
125 struct rsnd_mod *mod,
126 struct rsnd_dai *rdai,
127 struct rsnd_dai_stream *io)
128{
129 struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
130 u32 adinr = runtime->channels;
131
132 switch (runtime->sample_bits) {
133 case 16:
134 adinr |= OTBL_16;
135 break;
136 case 32:
137 adinr |= OTBL_24;
138 break;
139 default:
140 return -EIO;
141 }
142
143 rsnd_mod_write(mod, BUSIF_MODE, 1);
144 rsnd_mod_write(mod, BUSIF_ADINR, adinr);
145
146 return 0;
147}
148
149static int rsnd_scu_start(struct rsnd_mod *mod,
150 struct rsnd_dai *rdai,
151 struct rsnd_dai_stream *io)
152{
153 struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
154 struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
155 struct device *dev = rsnd_priv_to_dev(priv);
156 u32 flags = rsnd_scu_mode_flags(scu);
157 int ret;
158
159 /*
160 * SCU will be used if it has RSND_SCU_USB_HPBIF flags
161 */
162 if (!(flags & RSND_SCU_USB_HPBIF)) {
163 /* it use PIO transter */
164 dev_dbg(dev, "%s%d is not used\n",
165 rsnd_mod_name(mod), rsnd_mod_id(mod));
166
167 return 0;
168 }
169
170 /* it use DMA transter */
171 ret = rsnd_scu_set_route(priv, mod, rdai, io);
172 if (ret < 0)
173 return ret;
174
175 ret = rsnd_scu_set_mode(priv, mod, rdai, io);
176 if (ret < 0)
177 return ret;
178
179 ret = rsnd_scu_set_hpbif(priv, mod, rdai, io);
180 if (ret < 0)
181 return ret;
182
183 dev_dbg(dev, "%s%d start\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
184
185 return 0;
186}
187
188static struct rsnd_mod_ops rsnd_scu_ops = {
189 .name = "scu",
190 .start = rsnd_scu_start,
191};
192
193struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id)
194{
195 BUG_ON(id < 0 || id >= rsnd_scu_nr(priv));
196
197 return &((struct rsnd_scu *)(priv->scu) + id)->mod;
198}
199
200int rsnd_scu_probe(struct platform_device *pdev,
201 struct rcar_snd_info *info,
202 struct rsnd_priv *priv)
203{
204 struct device *dev = rsnd_priv_to_dev(priv);
205 struct rsnd_scu *scu;
206 int i, nr;
207
208 /*
209 * init SCU
210 */
211 nr = info->scu_info_nr;
212 scu = devm_kzalloc(dev, sizeof(*scu) * nr, GFP_KERNEL);
213 if (!scu) {
214 dev_err(dev, "SCU allocate failed\n");
215 return -ENOMEM;
216 }
217
218 priv->scu_nr = nr;
219 priv->scu = scu;
220
221 for_each_rsnd_scu(scu, priv, i) {
222 rsnd_mod_init(priv, &scu->mod,
223 &rsnd_scu_ops, i);
224 scu->info = &info->scu_info[i];
225
226 dev_dbg(dev, "SCU%d probed\n", i);
227 }
228 dev_dbg(dev, "scu probed\n");
229
230 return 0;
231}
232
233void rsnd_scu_remove(struct platform_device *pdev,
234 struct rsnd_priv *priv)
235{
236}
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
new file mode 100644
index 000000000000..fae26d3f79d2
--- /dev/null
+++ b/sound/soc/sh/rcar/ssi.c
@@ -0,0 +1,728 @@
1/*
2 * Renesas R-Car SSIU/SSI support
3 *
4 * Copyright (C) 2013 Renesas Solutions Corp.
5 * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
6 *
7 * Based on fsi.c
8 * Kuninori Morimoto <morimoto.kuninori@renesas.com>
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#include <linux/delay.h>
15#include "rsnd.h"
16#define RSND_SSI_NAME_SIZE 16
17
18/*
19 * SSICR
20 */
21#define FORCE (1 << 31) /* Fixed */
22#define DMEN (1 << 28) /* DMA Enable */
23#define UIEN (1 << 27) /* Underflow Interrupt Enable */
24#define OIEN (1 << 26) /* Overflow Interrupt Enable */
25#define IIEN (1 << 25) /* Idle Mode Interrupt Enable */
26#define DIEN (1 << 24) /* Data Interrupt Enable */
27
28#define DWL_8 (0 << 19) /* Data Word Length */
29#define DWL_16 (1 << 19) /* Data Word Length */
30#define DWL_18 (2 << 19) /* Data Word Length */
31#define DWL_20 (3 << 19) /* Data Word Length */
32#define DWL_22 (4 << 19) /* Data Word Length */
33#define DWL_24 (5 << 19) /* Data Word Length */
34#define DWL_32 (6 << 19) /* Data Word Length */
35
36#define SWL_32 (3 << 16) /* R/W System Word Length */
37#define SCKD (1 << 15) /* Serial Bit Clock Direction */
38#define SWSD (1 << 14) /* Serial WS Direction */
39#define SCKP (1 << 13) /* Serial Bit Clock Polarity */
40#define SWSP (1 << 12) /* Serial WS Polarity */
41#define SDTA (1 << 10) /* Serial Data Alignment */
42#define DEL (1 << 8) /* Serial Data Delay */
43#define CKDV(v) (v << 4) /* Serial Clock Division Ratio */
44#define TRMD (1 << 1) /* Transmit/Receive Mode Select */
45#define EN (1 << 0) /* SSI Module Enable */
46
47/*
48 * SSISR
49 */
50#define UIRQ (1 << 27) /* Underflow Error Interrupt Status */
51#define OIRQ (1 << 26) /* Overflow Error Interrupt Status */
52#define IIRQ (1 << 25) /* Idle Mode Interrupt Status */
53#define DIRQ (1 << 24) /* Data Interrupt Status Flag */
54
55/*
56 * SSIWSR
57 */
58#define CONT (1 << 8) /* WS Continue Function */
59
60struct rsnd_ssi {
61 struct clk *clk;
62 struct rsnd_ssi_platform_info *info; /* rcar_snd.h */
63 struct rsnd_ssi *parent;
64 struct rsnd_mod mod;
65
66 struct rsnd_dai *rdai;
67 struct rsnd_dai_stream *io;
68 u32 cr_own;
69 u32 cr_clk;
70 u32 cr_etc;
71 int err;
72 int dma_offset;
73 unsigned int usrcnt;
74 unsigned int rate;
75};
76
77struct rsnd_ssiu {
78 u32 ssi_mode0;
79 u32 ssi_mode1;
80
81 int ssi_nr;
82 struct rsnd_ssi *ssi;
83};
84
85#define for_each_rsnd_ssi(pos, priv, i) \
86 for (i = 0; \
87 (i < rsnd_ssi_nr(priv)) && \
88 ((pos) = ((struct rsnd_ssiu *)((priv)->ssiu))->ssi + i); \
89 i++)
90
91#define rsnd_ssi_nr(priv) (((struct rsnd_ssiu *)((priv)->ssiu))->ssi_nr)
92#define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod)
93#define rsnd_dma_to_ssi(dma) rsnd_mod_to_ssi(rsnd_dma_to_mod(dma))
94#define rsnd_ssi_pio_available(ssi) ((ssi)->info->pio_irq > 0)
95#define rsnd_ssi_dma_available(ssi) \
96 rsnd_dma_available(rsnd_mod_to_dma(&(ssi)->mod))
97#define rsnd_ssi_clk_from_parent(ssi) ((ssi)->parent)
98#define rsnd_rdai_is_clk_master(rdai) ((rdai)->clk_master)
99#define rsnd_ssi_mode_flags(p) ((p)->info->flags)
100#define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id)
101#define rsnd_ssi_to_ssiu(ssi)\
102 (((struct rsnd_ssiu *)((ssi) - rsnd_mod_id(&(ssi)->mod))) - 1)
103
104static void rsnd_ssi_mode_init(struct rsnd_priv *priv,
105 struct rsnd_ssiu *ssiu)
106{
107 struct device *dev = rsnd_priv_to_dev(priv);
108 struct rsnd_ssi *ssi;
109 u32 flags;
110 u32 val;
111 int i;
112
113 /*
114 * SSI_MODE0
115 */
116 ssiu->ssi_mode0 = 0;
117 for_each_rsnd_ssi(ssi, priv, i) {
118 flags = rsnd_ssi_mode_flags(ssi);
119
120 /* see also BUSIF_MODE */
121 if (!(flags & RSND_SSI_DEPENDENT)) {
122 ssiu->ssi_mode0 |= (1 << i);
123 dev_dbg(dev, "SSI%d uses INDEPENDENT mode\n", i);
124 } else {
125 dev_dbg(dev, "SSI%d uses DEPENDENT mode\n", i);
126 }
127 }
128
129 /*
130 * SSI_MODE1
131 */
132#define ssi_parent_set(p, sync, adg, ext) \
133 do { \
134 ssi->parent = ssiu->ssi + p; \
135 if (flags & RSND_SSI_CLK_FROM_ADG) \
136 val = adg; \
137 else \
138 val = ext; \
139 if (flags & RSND_SSI_SYNC) \
140 val |= sync; \
141 } while (0)
142
143 ssiu->ssi_mode1 = 0;
144 for_each_rsnd_ssi(ssi, priv, i) {
145 flags = rsnd_ssi_mode_flags(ssi);
146
147 if (!(flags & RSND_SSI_CLK_PIN_SHARE))
148 continue;
149
150 val = 0;
151 switch (i) {
152 case 1:
153 ssi_parent_set(0, (1 << 4), (0x2 << 0), (0x1 << 0));
154 break;
155 case 2:
156 ssi_parent_set(0, (1 << 4), (0x2 << 2), (0x1 << 2));
157 break;
158 case 4:
159 ssi_parent_set(3, (1 << 20), (0x2 << 16), (0x1 << 16));
160 break;
161 case 8:
162 ssi_parent_set(7, 0, 0, 0);
163 break;
164 }
165
166 ssiu->ssi_mode1 |= val;
167 }
168}
169
170static void rsnd_ssi_mode_set(struct rsnd_ssi *ssi)
171{
172 struct rsnd_ssiu *ssiu = rsnd_ssi_to_ssiu(ssi);
173
174 rsnd_mod_write(&ssi->mod, SSI_MODE0, ssiu->ssi_mode0);
175 rsnd_mod_write(&ssi->mod, SSI_MODE1, ssiu->ssi_mode1);
176}
177
178static void rsnd_ssi_status_check(struct rsnd_mod *mod,
179 u32 bit)
180{
181 struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
182 struct device *dev = rsnd_priv_to_dev(priv);
183 u32 status;
184 int i;
185
186 for (i = 0; i < 1024; i++) {
187 status = rsnd_mod_read(mod, SSISR);
188 if (status & bit)
189 return;
190
191 udelay(50);
192 }
193
194 dev_warn(dev, "status check failed\n");
195}
196
197static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
198 unsigned int rate)
199{
200 struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod);
201 struct device *dev = rsnd_priv_to_dev(priv);
202 int i, j, ret;
203 int adg_clk_div_table[] = {
204 1, 6, /* see adg.c */
205 };
206 int ssi_clk_mul_table[] = {
207 1, 2, 4, 8, 16, 6, 12,
208 };
209 unsigned int main_rate;
210
211 /*
212 * Find best clock, and try to start ADG
213 */
214 for (i = 0; i < ARRAY_SIZE(adg_clk_div_table); i++) {
215 for (j = 0; j < ARRAY_SIZE(ssi_clk_mul_table); j++) {
216
217 /*
218 * this driver is assuming that
219 * system word is 64fs (= 2 x 32bit)
220 * see rsnd_ssi_start()
221 */
222 main_rate = rate / adg_clk_div_table[i]
223 * 32 * 2 * ssi_clk_mul_table[j];
224
225 ret = rsnd_adg_ssi_clk_try_start(&ssi->mod, main_rate);
226 if (0 == ret) {
227 ssi->rate = rate;
228 ssi->cr_clk = FORCE | SWL_32 |
229 SCKD | SWSD | CKDV(j);
230
231 dev_dbg(dev, "ssi%d outputs %u Hz\n",
232 rsnd_mod_id(&ssi->mod), rate);
233
234 return 0;
235 }
236 }
237 }
238
239 dev_err(dev, "unsupported clock rate\n");
240 return -EIO;
241}
242
243static void rsnd_ssi_master_clk_stop(struct rsnd_ssi *ssi)
244{
245 ssi->rate = 0;
246 ssi->cr_clk = 0;
247 rsnd_adg_ssi_clk_stop(&ssi->mod);
248}
249
250static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi,
251 struct rsnd_dai *rdai,
252 struct rsnd_dai_stream *io)
253{
254 struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod);
255 struct device *dev = rsnd_priv_to_dev(priv);
256 u32 cr;
257
258 if (0 == ssi->usrcnt) {
259 clk_enable(ssi->clk);
260
261 if (rsnd_rdai_is_clk_master(rdai)) {
262 struct snd_pcm_runtime *runtime;
263
264 runtime = rsnd_io_to_runtime(io);
265
266 if (rsnd_ssi_clk_from_parent(ssi))
267 rsnd_ssi_hw_start(ssi->parent, rdai, io);
268 else
269 rsnd_ssi_master_clk_start(ssi, runtime->rate);
270 }
271 }
272
273 cr = ssi->cr_own |
274 ssi->cr_clk |
275 ssi->cr_etc |
276 EN;
277
278 rsnd_mod_write(&ssi->mod, SSICR, cr);
279
280 ssi->usrcnt++;
281
282 dev_dbg(dev, "ssi%d hw started\n", rsnd_mod_id(&ssi->mod));
283}
284
285static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi,
286 struct rsnd_dai *rdai)
287{
288 struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod);
289 struct device *dev = rsnd_priv_to_dev(priv);
290 u32 cr;
291
292 if (0 == ssi->usrcnt) /* stop might be called without start */
293 return;
294
295 ssi->usrcnt--;
296
297 if (0 == ssi->usrcnt) {
298 /*
299 * disable all IRQ,
300 * and, wait all data was sent
301 */
302 cr = ssi->cr_own |
303 ssi->cr_clk;
304
305 rsnd_mod_write(&ssi->mod, SSICR, cr | EN);
306 rsnd_ssi_status_check(&ssi->mod, DIRQ);
307
308 /*
309 * disable SSI,
310 * and, wait idle state
311 */
312 rsnd_mod_write(&ssi->mod, SSICR, cr); /* disabled all */
313 rsnd_ssi_status_check(&ssi->mod, IIRQ);
314
315 if (rsnd_rdai_is_clk_master(rdai)) {
316 if (rsnd_ssi_clk_from_parent(ssi))
317 rsnd_ssi_hw_stop(ssi->parent, rdai);
318 else
319 rsnd_ssi_master_clk_stop(ssi);
320 }
321
322 clk_disable(ssi->clk);
323 }
324
325 dev_dbg(dev, "ssi%d hw stopped\n", rsnd_mod_id(&ssi->mod));
326}
327
328/*
329 * SSI mod common functions
330 */
331static int rsnd_ssi_init(struct rsnd_mod *mod,
332 struct rsnd_dai *rdai,
333 struct rsnd_dai_stream *io)
334{
335 struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
336 struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
337 struct device *dev = rsnd_priv_to_dev(priv);
338 struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
339 u32 cr;
340
341 cr = FORCE;
342
343 /*
344 * always use 32bit system word for easy clock calculation.
345 * see also rsnd_ssi_master_clk_enable()
346 */
347 cr |= SWL_32;
348
349 /*
350 * init clock settings for SSICR
351 */
352 switch (runtime->sample_bits) {
353 case 16:
354 cr |= DWL_16;
355 break;
356 case 32:
357 cr |= DWL_24;
358 break;
359 default:
360 return -EIO;
361 }
362
363 if (rdai->bit_clk_inv)
364 cr |= SCKP;
365 if (rdai->frm_clk_inv)
366 cr |= SWSP;
367 if (rdai->data_alignment)
368 cr |= SDTA;
369 if (rdai->sys_delay)
370 cr |= DEL;
371 if (rsnd_dai_is_play(rdai, io))
372 cr |= TRMD;
373
374 /*
375 * set ssi parameter
376 */
377 ssi->rdai = rdai;
378 ssi->io = io;
379 ssi->cr_own = cr;
380 ssi->err = -1; /* ignore 1st error */
381
382 rsnd_ssi_mode_set(ssi);
383
384 dev_dbg(dev, "%s.%d init\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
385
386 return 0;
387}
388
389static int rsnd_ssi_quit(struct rsnd_mod *mod,
390 struct rsnd_dai *rdai,
391 struct rsnd_dai_stream *io)
392{
393 struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
394 struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
395 struct device *dev = rsnd_priv_to_dev(priv);
396
397 dev_dbg(dev, "%s.%d quit\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
398
399 if (ssi->err > 0)
400 dev_warn(dev, "ssi under/over flow err = %d\n", ssi->err);
401
402 ssi->rdai = NULL;
403 ssi->io = NULL;
404 ssi->cr_own = 0;
405 ssi->err = 0;
406
407 return 0;
408}
409
410static void rsnd_ssi_record_error(struct rsnd_ssi *ssi, u32 status)
411{
412 /* under/over flow error */
413 if (status & (UIRQ | OIRQ)) {
414 ssi->err++;
415
416 /* clear error status */
417 rsnd_mod_write(&ssi->mod, SSISR, 0);
418 }
419}
420
421/*
422 * SSI PIO
423 */
424static irqreturn_t rsnd_ssi_pio_interrupt(int irq, void *data)
425{
426 struct rsnd_ssi *ssi = data;
427 struct rsnd_dai_stream *io = ssi->io;
428 u32 status = rsnd_mod_read(&ssi->mod, SSISR);
429 irqreturn_t ret = IRQ_NONE;
430
431 if (io && (status & DIRQ)) {
432 struct rsnd_dai *rdai = ssi->rdai;
433 struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
434 u32 *buf = (u32 *)(runtime->dma_area +
435 rsnd_dai_pointer_offset(io, 0));
436
437 rsnd_ssi_record_error(ssi, status);
438
439 /*
440 * 8/16/32 data can be assesse to TDR/RDR register
441 * directly as 32bit data
442 * see rsnd_ssi_init()
443 */
444 if (rsnd_dai_is_play(rdai, io))
445 rsnd_mod_write(&ssi->mod, SSITDR, *buf);
446 else
447 *buf = rsnd_mod_read(&ssi->mod, SSIRDR);
448
449 rsnd_dai_pointer_update(io, sizeof(*buf));
450
451 ret = IRQ_HANDLED;
452 }
453
454 return ret;
455}
456
457static int rsnd_ssi_pio_start(struct rsnd_mod *mod,
458 struct rsnd_dai *rdai,
459 struct rsnd_dai_stream *io)
460{
461 struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
462 struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
463 struct device *dev = rsnd_priv_to_dev(priv);
464
465 /* enable PIO IRQ */
466 ssi->cr_etc = UIEN | OIEN | DIEN;
467
468 rsnd_ssi_hw_start(ssi, rdai, io);
469
470 dev_dbg(dev, "%s.%d start\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
471
472 return 0;
473}
474
475static int rsnd_ssi_pio_stop(struct rsnd_mod *mod,
476 struct rsnd_dai *rdai,
477 struct rsnd_dai_stream *io)
478{
479 struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
480 struct device *dev = rsnd_priv_to_dev(priv);
481 struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
482
483 dev_dbg(dev, "%s.%d stop\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
484
485 ssi->cr_etc = 0;
486
487 rsnd_ssi_hw_stop(ssi, rdai);
488
489 return 0;
490}
491
492static struct rsnd_mod_ops rsnd_ssi_pio_ops = {
493 .name = "ssi (pio)",
494 .init = rsnd_ssi_init,
495 .quit = rsnd_ssi_quit,
496 .start = rsnd_ssi_pio_start,
497 .stop = rsnd_ssi_pio_stop,
498};
499
500static int rsnd_ssi_dma_inquiry(struct rsnd_dma *dma, dma_addr_t *buf, int *len)
501{
502 struct rsnd_ssi *ssi = rsnd_dma_to_ssi(dma);
503 struct rsnd_dai_stream *io = ssi->io;
504 struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
505
506 *len = io->byte_per_period;
507 *buf = runtime->dma_addr +
508 rsnd_dai_pointer_offset(io, ssi->dma_offset + *len);
509 ssi->dma_offset = *len; /* it cares A/B plane */
510
511 return 0;
512}
513
514static int rsnd_ssi_dma_complete(struct rsnd_dma *dma)
515{
516 struct rsnd_ssi *ssi = rsnd_dma_to_ssi(dma);
517 struct rsnd_dai_stream *io = ssi->io;
518 u32 status = rsnd_mod_read(&ssi->mod, SSISR);
519
520 rsnd_ssi_record_error(ssi, status);
521
522 rsnd_dai_pointer_update(ssi->io, io->byte_per_period);
523
524 return 0;
525}
526
527static int rsnd_ssi_dma_start(struct rsnd_mod *mod,
528 struct rsnd_dai *rdai,
529 struct rsnd_dai_stream *io)
530{
531 struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
532 struct rsnd_dma *dma = rsnd_mod_to_dma(&ssi->mod);
533
534 /* enable DMA transfer */
535 ssi->cr_etc = DMEN;
536 ssi->dma_offset = 0;
537
538 rsnd_dma_start(dma);
539
540 rsnd_ssi_hw_start(ssi, ssi->rdai, io);
541
542 /* enable WS continue */
543 if (rsnd_rdai_is_clk_master(rdai))
544 rsnd_mod_write(&ssi->mod, SSIWSR, CONT);
545
546 return 0;
547}
548
549static int rsnd_ssi_dma_stop(struct rsnd_mod *mod,
550 struct rsnd_dai *rdai,
551 struct rsnd_dai_stream *io)
552{
553 struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
554 struct rsnd_dma *dma = rsnd_mod_to_dma(&ssi->mod);
555
556 ssi->cr_etc = 0;
557
558 rsnd_ssi_hw_stop(ssi, rdai);
559
560 rsnd_dma_stop(dma);
561
562 return 0;
563}
564
565static struct rsnd_mod_ops rsnd_ssi_dma_ops = {
566 .name = "ssi (dma)",
567 .init = rsnd_ssi_init,
568 .quit = rsnd_ssi_quit,
569 .start = rsnd_ssi_dma_start,
570 .stop = rsnd_ssi_dma_stop,
571};
572
573/*
574 * Non SSI
575 */
576static int rsnd_ssi_non(struct rsnd_mod *mod,
577 struct rsnd_dai *rdai,
578 struct rsnd_dai_stream *io)
579{
580 struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
581 struct device *dev = rsnd_priv_to_dev(priv);
582
583 dev_dbg(dev, "%s\n", __func__);
584
585 return 0;
586}
587
588static struct rsnd_mod_ops rsnd_ssi_non_ops = {
589 .name = "ssi (non)",
590 .init = rsnd_ssi_non,
591 .quit = rsnd_ssi_non,
592 .start = rsnd_ssi_non,
593 .stop = rsnd_ssi_non,
594};
595
596/*
597 * ssi mod function
598 */
599struct rsnd_mod *rsnd_ssi_mod_get_frm_dai(struct rsnd_priv *priv,
600 int dai_id, int is_play)
601{
602 struct rsnd_ssi *ssi;
603 int i, has_play;
604
605 is_play = !!is_play;
606
607 for_each_rsnd_ssi(ssi, priv, i) {
608 if (rsnd_ssi_dai_id(ssi) != dai_id)
609 continue;
610
611 has_play = !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_PLAY);
612
613 if (is_play == has_play)
614 return &ssi->mod;
615 }
616
617 return NULL;
618}
619
620struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id)
621{
622 BUG_ON(id < 0 || id >= rsnd_ssi_nr(priv));
623
624 return &(((struct rsnd_ssiu *)(priv->ssiu))->ssi + id)->mod;
625}
626
627int rsnd_ssi_probe(struct platform_device *pdev,
628 struct rcar_snd_info *info,
629 struct rsnd_priv *priv)
630{
631 struct rsnd_ssi_platform_info *pinfo;
632 struct device *dev = rsnd_priv_to_dev(priv);
633 struct rsnd_mod_ops *ops;
634 struct clk *clk;
635 struct rsnd_ssiu *ssiu;
636 struct rsnd_ssi *ssi;
637 char name[RSND_SSI_NAME_SIZE];
638 int i, nr, ret;
639
640 /*
641 * init SSI
642 */
643 nr = info->ssi_info_nr;
644 ssiu = devm_kzalloc(dev, sizeof(*ssiu) + (sizeof(*ssi) * nr),
645 GFP_KERNEL);
646 if (!ssiu) {
647 dev_err(dev, "SSI allocate failed\n");
648 return -ENOMEM;
649 }
650
651 priv->ssiu = ssiu;
652 ssiu->ssi = (struct rsnd_ssi *)(ssiu + 1);
653 ssiu->ssi_nr = nr;
654
655 for_each_rsnd_ssi(ssi, priv, i) {
656 pinfo = &info->ssi_info[i];
657
658 snprintf(name, RSND_SSI_NAME_SIZE, "ssi.%d", i);
659
660 clk = clk_get(dev, name);
661 if (IS_ERR(clk))
662 return PTR_ERR(clk);
663
664 ssi->info = pinfo;
665 ssi->clk = clk;
666
667 ops = &rsnd_ssi_non_ops;
668
669 /*
670 * SSI DMA case
671 */
672 if (pinfo->dma_id > 0) {
673 ret = rsnd_dma_init(
674 priv, rsnd_mod_to_dma(&ssi->mod),
675 (rsnd_ssi_mode_flags(ssi) & RSND_SSI_PLAY),
676 pinfo->dma_id,
677 rsnd_ssi_dma_inquiry,
678 rsnd_ssi_dma_complete);
679 if (ret < 0)
680 dev_info(dev, "SSI DMA failed. try PIO transter\n");
681 else
682 ops = &rsnd_ssi_dma_ops;
683
684 dev_dbg(dev, "SSI%d use DMA transfer\n", i);
685 }
686
687 /*
688 * SSI PIO case
689 */
690 if (!rsnd_ssi_dma_available(ssi) &&
691 rsnd_ssi_pio_available(ssi)) {
692 ret = devm_request_irq(dev, pinfo->pio_irq,
693 &rsnd_ssi_pio_interrupt,
694 IRQF_SHARED,
695 dev_name(dev), ssi);
696 if (ret) {
697 dev_err(dev, "SSI request interrupt failed\n");
698 return ret;
699 }
700
701 ops = &rsnd_ssi_pio_ops;
702
703 dev_dbg(dev, "SSI%d use PIO transfer\n", i);
704 }
705
706 rsnd_mod_init(priv, &ssi->mod, ops, i);
707 }
708
709 rsnd_ssi_mode_init(priv, ssiu);
710
711 dev_dbg(dev, "ssi probed\n");
712
713 return 0;
714}
715
716void rsnd_ssi_remove(struct platform_device *pdev,
717 struct rsnd_priv *priv)
718{
719 struct rsnd_ssi *ssi;
720 int i;
721
722 for_each_rsnd_ssi(ssi, priv, i) {
723 clk_put(ssi->clk);
724 if (rsnd_ssi_dma_available(ssi))
725 rsnd_dma_quit(priv, rsnd_mod_to_dma(&ssi->mod));
726 }
727
728}