cmd.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. // SPDX-License-Identifier: GPL-2.0
  2. //
  3. // Renesas R-Car CMD support
  4. //
  5. // Copyright (C) 2015 Renesas Solutions Corp.
  6. // Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
  7. #include "rsnd.h"
  8. struct rsnd_cmd {
  9. struct rsnd_mod mod;
  10. };
  11. #define CMD_NAME "cmd"
  12. #define rsnd_cmd_nr(priv) ((priv)->cmd_nr)
  13. #define for_each_rsnd_cmd(pos, priv, i) \
  14. for ((i) = 0; \
  15. ((i) < rsnd_cmd_nr(priv)) && \
  16. ((pos) = (struct rsnd_cmd *)(priv)->cmd + i); \
  17. i++)
  18. static int rsnd_cmd_init(struct rsnd_mod *mod,
  19. struct rsnd_dai_stream *io,
  20. struct rsnd_priv *priv)
  21. {
  22. struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
  23. struct rsnd_mod *mix = rsnd_io_to_mod_mix(io);
  24. struct device *dev = rsnd_priv_to_dev(priv);
  25. u32 data;
  26. static const u32 path[] = {
  27. [1] = 1 << 0,
  28. [5] = 1 << 8,
  29. [6] = 1 << 12,
  30. [9] = 1 << 15,
  31. };
  32. if (!mix && !dvc)
  33. return 0;
  34. if (ARRAY_SIZE(path) < rsnd_mod_id(mod) + 1)
  35. return -ENXIO;
  36. if (mix) {
  37. struct rsnd_dai *rdai;
  38. struct rsnd_mod *src;
  39. struct rsnd_dai_stream *tio;
  40. int i;
  41. /*
  42. * it is assuming that integrater is well understanding about
  43. * data path. Here doesn't check impossible connection,
  44. * like src2 + src5
  45. */
  46. data = 0;
  47. for_each_rsnd_dai(rdai, priv, i) {
  48. tio = &rdai->playback;
  49. src = rsnd_io_to_mod_src(tio);
  50. if (mix == rsnd_io_to_mod_mix(tio))
  51. data |= path[rsnd_mod_id(src)];
  52. tio = &rdai->capture;
  53. src = rsnd_io_to_mod_src(tio);
  54. if (mix == rsnd_io_to_mod_mix(tio))
  55. data |= path[rsnd_mod_id(src)];
  56. }
  57. } else {
  58. struct rsnd_mod *src = rsnd_io_to_mod_src(io);
  59. static const u8 cmd_case[] = {
  60. [0] = 0x3,
  61. [1] = 0x3,
  62. [2] = 0x4,
  63. [3] = 0x1,
  64. [4] = 0x2,
  65. [5] = 0x4,
  66. [6] = 0x1,
  67. [9] = 0x2,
  68. };
  69. if (unlikely(!src))
  70. return -EIO;
  71. data = path[rsnd_mod_id(src)] |
  72. cmd_case[rsnd_mod_id(src)] << 16;
  73. }
  74. dev_dbg(dev, "ctu/mix path = 0x%08x\n", data);
  75. rsnd_mod_write(mod, CMD_ROUTE_SLCT, data);
  76. rsnd_mod_write(mod, CMD_BUSIF_MODE, rsnd_get_busif_shift(io, mod) | 1);
  77. rsnd_mod_write(mod, CMD_BUSIF_DALIGN, rsnd_get_dalign(mod, io));
  78. rsnd_adg_set_cmd_timsel_gen2(mod, io);
  79. return 0;
  80. }
  81. static int rsnd_cmd_start(struct rsnd_mod *mod,
  82. struct rsnd_dai_stream *io,
  83. struct rsnd_priv *priv)
  84. {
  85. rsnd_mod_write(mod, CMD_CTRL, 0x10);
  86. return 0;
  87. }
  88. static int rsnd_cmd_stop(struct rsnd_mod *mod,
  89. struct rsnd_dai_stream *io,
  90. struct rsnd_priv *priv)
  91. {
  92. rsnd_mod_write(mod, CMD_CTRL, 0);
  93. return 0;
  94. }
  95. static struct rsnd_mod_ops rsnd_cmd_ops = {
  96. .name = CMD_NAME,
  97. .init = rsnd_cmd_init,
  98. .start = rsnd_cmd_start,
  99. .stop = rsnd_cmd_stop,
  100. };
  101. static struct rsnd_mod *rsnd_cmd_mod_get(struct rsnd_priv *priv, int id)
  102. {
  103. if (WARN_ON(id < 0 || id >= rsnd_cmd_nr(priv)))
  104. id = 0;
  105. return rsnd_mod_get((struct rsnd_cmd *)(priv->cmd) + id);
  106. }
  107. int rsnd_cmd_attach(struct rsnd_dai_stream *io, int id)
  108. {
  109. struct rsnd_priv *priv = rsnd_io_to_priv(io);
  110. struct rsnd_mod *mod = rsnd_cmd_mod_get(priv, id);
  111. return rsnd_dai_connect(mod, io, mod->type);
  112. }
  113. int rsnd_cmd_probe(struct rsnd_priv *priv)
  114. {
  115. struct device *dev = rsnd_priv_to_dev(priv);
  116. struct rsnd_cmd *cmd;
  117. int i, nr, ret;
  118. /* This driver doesn't support Gen1 at this point */
  119. if (rsnd_is_gen1(priv))
  120. return 0;
  121. /* same number as DVC */
  122. nr = priv->dvc_nr;
  123. if (!nr)
  124. return 0;
  125. cmd = devm_kcalloc(dev, nr, sizeof(*cmd), GFP_KERNEL);
  126. if (!cmd)
  127. return -ENOMEM;
  128. priv->cmd_nr = nr;
  129. priv->cmd = cmd;
  130. for_each_rsnd_cmd(cmd, priv, i) {
  131. ret = rsnd_mod_init(priv, rsnd_mod_get(cmd),
  132. &rsnd_cmd_ops, NULL,
  133. rsnd_mod_get_status, RSND_MOD_CMD, i);
  134. if (ret)
  135. return ret;
  136. }
  137. return 0;
  138. }
  139. void rsnd_cmd_remove(struct rsnd_priv *priv)
  140. {
  141. struct rsnd_cmd *cmd;
  142. int i;
  143. for_each_rsnd_cmd(cmd, priv, i) {
  144. rsnd_mod_quit(rsnd_mod_get(cmd));
  145. }
  146. }