diff options
Diffstat (limited to 'sound/soc/sh/rcar/core.c')
-rw-r--r-- | sound/soc/sh/rcar/core.c | 160 |
1 files changed, 119 insertions, 41 deletions
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 02b4b085b8d7..3351a701c60e 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c | |||
@@ -138,12 +138,22 @@ struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io, | |||
138 | return mod->ops->dma_req(io, mod); | 138 | return mod->ops->dma_req(io, mod); |
139 | } | 139 | } |
140 | 140 | ||
141 | u32 *rsnd_mod_get_status(struct rsnd_dai_stream *io, | ||
142 | struct rsnd_mod *mod, | ||
143 | enum rsnd_mod_type type) | ||
144 | { | ||
145 | return &mod->status; | ||
146 | } | ||
147 | |||
141 | int rsnd_mod_init(struct rsnd_priv *priv, | 148 | int rsnd_mod_init(struct rsnd_priv *priv, |
142 | struct rsnd_mod *mod, | 149 | struct rsnd_mod *mod, |
143 | struct rsnd_mod_ops *ops, | 150 | struct rsnd_mod_ops *ops, |
144 | struct clk *clk, | 151 | struct clk *clk, |
145 | enum rsnd_mod_type type, | 152 | u32* (*get_status)(struct rsnd_dai_stream *io, |
146 | int id) | 153 | struct rsnd_mod *mod, |
154 | enum rsnd_mod_type type), | ||
155 | enum rsnd_mod_type type, | ||
156 | int id) | ||
147 | { | 157 | { |
148 | int ret = clk_prepare(clk); | 158 | int ret = clk_prepare(clk); |
149 | 159 | ||
@@ -155,6 +165,7 @@ int rsnd_mod_init(struct rsnd_priv *priv, | |||
155 | mod->type = type; | 165 | mod->type = type; |
156 | mod->clk = clk; | 166 | mod->clk = clk; |
157 | mod->priv = priv; | 167 | mod->priv = priv; |
168 | mod->get_status = get_status; | ||
158 | 169 | ||
159 | return ret; | 170 | return ret; |
160 | } | 171 | } |
@@ -163,6 +174,7 @@ void rsnd_mod_quit(struct rsnd_mod *mod) | |||
163 | { | 174 | { |
164 | if (mod->clk) | 175 | if (mod->clk) |
165 | clk_unprepare(mod->clk); | 176 | clk_unprepare(mod->clk); |
177 | mod->clk = NULL; | ||
166 | } | 178 | } |
167 | 179 | ||
168 | void rsnd_mod_interrupt(struct rsnd_mod *mod, | 180 | void rsnd_mod_interrupt(struct rsnd_mod *mod, |
@@ -212,13 +224,36 @@ int rsnd_get_slot_num(struct rsnd_dai_stream *io) | |||
212 | return rdai->slots_num; | 224 | return rdai->slots_num; |
213 | } | 225 | } |
214 | 226 | ||
215 | int rsnd_get_slot_width(struct rsnd_dai_stream *io) | 227 | int rsnd_runtime_channel_original(struct rsnd_dai_stream *io) |
216 | { | 228 | { |
217 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | 229 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); |
218 | int chan = runtime->channels; | ||
219 | 230 | ||
220 | /* Multi channel Mode */ | 231 | return runtime->channels; |
221 | if (rsnd_ssi_multi_slaves(io)) | 232 | } |
233 | |||
234 | int rsnd_runtime_channel_after_ctu(struct rsnd_dai_stream *io) | ||
235 | { | ||
236 | int chan = rsnd_runtime_channel_original(io); | ||
237 | struct rsnd_mod *ctu_mod = rsnd_io_to_mod_ctu(io); | ||
238 | |||
239 | if (ctu_mod) { | ||
240 | u32 converted_chan = rsnd_ctu_converted_channel(ctu_mod); | ||
241 | |||
242 | if (converted_chan) | ||
243 | return converted_chan; | ||
244 | } | ||
245 | |||
246 | return chan; | ||
247 | } | ||
248 | |||
249 | int rsnd_runtime_channel_for_ssi(struct rsnd_dai_stream *io) | ||
250 | { | ||
251 | int chan = rsnd_io_is_play(io) ? | ||
252 | rsnd_runtime_channel_after_ctu(io) : | ||
253 | rsnd_runtime_channel_original(io); | ||
254 | |||
255 | /* Use Multi SSI */ | ||
256 | if (rsnd_runtime_is_ssi_multi(io)) | ||
222 | chan /= rsnd_get_slot_num(io); | 257 | chan /= rsnd_get_slot_num(io); |
223 | 258 | ||
224 | /* TDM Extend Mode needs 8ch */ | 259 | /* TDM Extend Mode needs 8ch */ |
@@ -228,6 +263,21 @@ int rsnd_get_slot_width(struct rsnd_dai_stream *io) | |||
228 | return chan; | 263 | return chan; |
229 | } | 264 | } |
230 | 265 | ||
266 | int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io) | ||
267 | { | ||
268 | int slots = rsnd_get_slot_num(io); | ||
269 | int chan = rsnd_io_is_play(io) ? | ||
270 | rsnd_runtime_channel_after_ctu(io) : | ||
271 | rsnd_runtime_channel_original(io); | ||
272 | |||
273 | return (chan >= 6) && (slots > 1); | ||
274 | } | ||
275 | |||
276 | int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io) | ||
277 | { | ||
278 | return rsnd_runtime_channel_for_ssi(io) >= 6; | ||
279 | } | ||
280 | |||
231 | /* | 281 | /* |
232 | * ADINR function | 282 | * ADINR function |
233 | */ | 283 | */ |
@@ -249,29 +299,6 @@ u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io) | |||
249 | return 0; | 299 | return 0; |
250 | } | 300 | } |
251 | 301 | ||
252 | u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io) | ||
253 | { | ||
254 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
255 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | ||
256 | struct device *dev = rsnd_priv_to_dev(priv); | ||
257 | u32 chan = runtime->channels; | ||
258 | |||
259 | switch (chan) { | ||
260 | case 1: | ||
261 | case 2: | ||
262 | case 4: | ||
263 | case 6: | ||
264 | case 8: | ||
265 | break; | ||
266 | default: | ||
267 | dev_warn(dev, "not supported channel\n"); | ||
268 | chan = 0; | ||
269 | break; | ||
270 | } | ||
271 | |||
272 | return chan; | ||
273 | } | ||
274 | |||
275 | /* | 302 | /* |
276 | * DALIGN function | 303 | * DALIGN function |
277 | */ | 304 | */ |
@@ -324,31 +351,73 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) | |||
324 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); \ | 351 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); \ |
325 | struct rsnd_mod *mod = (io)->mod[idx]; \ | 352 | struct rsnd_mod *mod = (io)->mod[idx]; \ |
326 | struct device *dev = rsnd_priv_to_dev(priv); \ | 353 | struct device *dev = rsnd_priv_to_dev(priv); \ |
327 | u32 *status = (io)->mod_status + idx; \ | 354 | u32 *status = mod->get_status(io, mod, idx); \ |
328 | u32 mask = 0xF << __rsnd_mod_shift_##func; \ | 355 | u32 mask = 0xF << __rsnd_mod_shift_##func; \ |
329 | u8 val = (*status >> __rsnd_mod_shift_##func) & 0xF; \ | 356 | u8 val = (*status >> __rsnd_mod_shift_##func) & 0xF; \ |
330 | u8 add = ((val + __rsnd_mod_add_##func) & 0xF); \ | 357 | u8 add = ((val + __rsnd_mod_add_##func) & 0xF); \ |
331 | int ret = 0; \ | 358 | int ret = 0; \ |
332 | int call = (val == __rsnd_mod_call_##func) && (mod)->ops->func; \ | 359 | int call = (val == __rsnd_mod_call_##func) && (mod)->ops->func; \ |
333 | *status = (*status & ~mask) + \ | 360 | if (add == 0xF) \ |
334 | (add << __rsnd_mod_shift_##func); \ | 361 | call = 0; \ |
362 | else \ | ||
363 | *status = (*status & ~mask) + \ | ||
364 | (add << __rsnd_mod_shift_##func); \ | ||
335 | dev_dbg(dev, "%s[%d]\t0x%08x %s\n", \ | 365 | dev_dbg(dev, "%s[%d]\t0x%08x %s\n", \ |
336 | rsnd_mod_name(mod), rsnd_mod_id(mod), \ | 366 | rsnd_mod_name(mod), rsnd_mod_id(mod), \ |
337 | *status, call ? #func : ""); \ | 367 | *status, call ? #func : ""); \ |
338 | if (call) \ | 368 | if (call) \ |
339 | ret = (mod)->ops->func(mod, io, param); \ | 369 | ret = (mod)->ops->func(mod, io, param); \ |
370 | if (ret) \ | ||
371 | dev_dbg(dev, "%s[%d] : rsnd_mod_call error %d\n", \ | ||
372 | rsnd_mod_name(mod), rsnd_mod_id(mod), ret); \ | ||
340 | ret; \ | 373 | ret; \ |
341 | }) | 374 | }) |
342 | 375 | ||
376 | static enum rsnd_mod_type rsnd_mod_sequence[][RSND_MOD_MAX] = { | ||
377 | { | ||
378 | /* CAPTURE */ | ||
379 | RSND_MOD_AUDMAPP, | ||
380 | RSND_MOD_AUDMA, | ||
381 | RSND_MOD_DVC, | ||
382 | RSND_MOD_MIX, | ||
383 | RSND_MOD_CTU, | ||
384 | RSND_MOD_CMD, | ||
385 | RSND_MOD_SRC, | ||
386 | RSND_MOD_SSIU, | ||
387 | RSND_MOD_SSIM3, | ||
388 | RSND_MOD_SSIM2, | ||
389 | RSND_MOD_SSIM1, | ||
390 | RSND_MOD_SSIP, | ||
391 | RSND_MOD_SSI, | ||
392 | }, { | ||
393 | /* PLAYBACK */ | ||
394 | RSND_MOD_AUDMAPP, | ||
395 | RSND_MOD_AUDMA, | ||
396 | RSND_MOD_SSIM3, | ||
397 | RSND_MOD_SSIM2, | ||
398 | RSND_MOD_SSIM1, | ||
399 | RSND_MOD_SSIP, | ||
400 | RSND_MOD_SSI, | ||
401 | RSND_MOD_SSIU, | ||
402 | RSND_MOD_DVC, | ||
403 | RSND_MOD_MIX, | ||
404 | RSND_MOD_CTU, | ||
405 | RSND_MOD_CMD, | ||
406 | RSND_MOD_SRC, | ||
407 | }, | ||
408 | }; | ||
409 | |||
343 | #define rsnd_dai_call(fn, io, param...) \ | 410 | #define rsnd_dai_call(fn, io, param...) \ |
344 | ({ \ | 411 | ({ \ |
345 | struct rsnd_mod *mod; \ | 412 | struct rsnd_mod *mod; \ |
413 | int type, is_play = rsnd_io_is_play(io); \ | ||
346 | int ret = 0, i; \ | 414 | int ret = 0, i; \ |
347 | for (i = 0; i < RSND_MOD_MAX; i++) { \ | 415 | for (i = 0; i < RSND_MOD_MAX; i++) { \ |
348 | mod = (io)->mod[i]; \ | 416 | type = rsnd_mod_sequence[is_play][i]; \ |
417 | mod = (io)->mod[type]; \ | ||
349 | if (!mod) \ | 418 | if (!mod) \ |
350 | continue; \ | 419 | continue; \ |
351 | ret |= rsnd_mod_call(i, io, fn, param); \ | 420 | ret |= rsnd_mod_call(type, io, fn, param); \ |
352 | } \ | 421 | } \ |
353 | ret; \ | 422 | ret; \ |
354 | }) | 423 | }) |
@@ -363,6 +432,9 @@ int rsnd_dai_connect(struct rsnd_mod *mod, | |||
363 | if (!mod) | 432 | if (!mod) |
364 | return -EIO; | 433 | return -EIO; |
365 | 434 | ||
435 | if (io->mod[type] == mod) | ||
436 | return 0; | ||
437 | |||
366 | if (io->mod[type]) | 438 | if (io->mod[type]) |
367 | return -EINVAL; | 439 | return -EINVAL; |
368 | 440 | ||
@@ -511,9 +583,16 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, | |||
511 | ret = rsnd_dai_call(start, io, priv); | 583 | ret = rsnd_dai_call(start, io, priv); |
512 | if (ret < 0) | 584 | if (ret < 0) |
513 | goto dai_trigger_end; | 585 | goto dai_trigger_end; |
586 | |||
587 | ret = rsnd_dai_call(irq, io, priv, 1); | ||
588 | if (ret < 0) | ||
589 | goto dai_trigger_end; | ||
590 | |||
514 | break; | 591 | break; |
515 | case SNDRV_PCM_TRIGGER_STOP: | 592 | case SNDRV_PCM_TRIGGER_STOP: |
516 | ret = rsnd_dai_call(stop, io, priv); | 593 | ret = rsnd_dai_call(irq, io, priv, 0); |
594 | |||
595 | ret |= rsnd_dai_call(stop, io, priv); | ||
517 | 596 | ||
518 | ret |= rsnd_dai_call(quit, io, priv); | 597 | ret |= rsnd_dai_call(quit, io, priv); |
519 | 598 | ||
@@ -863,7 +942,7 @@ static int rsnd_kctrl_put(struct snd_kcontrol *kctrl, | |||
863 | } | 942 | } |
864 | } | 943 | } |
865 | 944 | ||
866 | if (change) | 945 | if (change && cfg->update) |
867 | cfg->update(cfg->io, mod); | 946 | cfg->update(cfg->io, mod); |
868 | 947 | ||
869 | return change; | 948 | return change; |
@@ -923,7 +1002,7 @@ int rsnd_kctrl_new_m(struct rsnd_mod *mod, | |||
923 | int ch_size, | 1002 | int ch_size, |
924 | u32 max) | 1003 | u32 max) |
925 | { | 1004 | { |
926 | if (ch_size > RSND_DVC_CHANNELS) | 1005 | if (ch_size > RSND_MAX_CHANNELS) |
927 | return -EINVAL; | 1006 | return -EINVAL; |
928 | 1007 | ||
929 | _cfg->cfg.max = max; | 1008 | _cfg->cfg.max = max; |
@@ -1055,7 +1134,6 @@ static int rsnd_probe(struct platform_device *pdev) | |||
1055 | struct rsnd_priv *priv; | 1134 | struct rsnd_priv *priv; |
1056 | struct device *dev = &pdev->dev; | 1135 | struct device *dev = &pdev->dev; |
1057 | struct rsnd_dai *rdai; | 1136 | struct rsnd_dai *rdai; |
1058 | const struct of_device_id *of_id = of_match_device(rsnd_of_match, dev); | ||
1059 | int (*probe_func[])(struct rsnd_priv *priv) = { | 1137 | int (*probe_func[])(struct rsnd_priv *priv) = { |
1060 | rsnd_gen_probe, | 1138 | rsnd_gen_probe, |
1061 | rsnd_dma_probe, | 1139 | rsnd_dma_probe, |
@@ -1081,7 +1159,7 @@ static int rsnd_probe(struct platform_device *pdev) | |||
1081 | } | 1159 | } |
1082 | 1160 | ||
1083 | priv->pdev = pdev; | 1161 | priv->pdev = pdev; |
1084 | priv->flags = (unsigned long)of_id->data; | 1162 | priv->flags = (unsigned long)of_device_get_match_data(dev); |
1085 | spin_lock_init(&priv->lock); | 1163 | spin_lock_init(&priv->lock); |
1086 | 1164 | ||
1087 | /* | 1165 | /* |