ssiu.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. /*
  2. * Renesas R-Car SSIU support
  3. *
  4. * Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
  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. #include "rsnd.h"
  11. #define SSIU_NAME "ssiu"
  12. struct rsnd_ssiu {
  13. struct rsnd_mod mod;
  14. };
  15. #define rsnd_ssiu_nr(priv) ((priv)->ssiu_nr)
  16. #define for_each_rsnd_ssiu(pos, priv, i) \
  17. for (i = 0; \
  18. (i < rsnd_ssiu_nr(priv)) && \
  19. ((pos) = ((struct rsnd_ssiu *)(priv)->ssiu + i)); \
  20. i++)
  21. static int rsnd_ssiu_init(struct rsnd_mod *mod,
  22. struct rsnd_dai_stream *io,
  23. struct rsnd_priv *priv)
  24. {
  25. struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
  26. u32 multi_ssi_slaves = rsnd_ssi_multi_slaves_runtime(io);
  27. int use_busif = rsnd_ssi_use_busif(io);
  28. int id = rsnd_mod_id(mod);
  29. u32 mask1, val1;
  30. u32 mask2, val2;
  31. /*
  32. * SSI_MODE0
  33. */
  34. rsnd_mod_bset(mod, SSI_MODE0, (1 << id), !use_busif << id);
  35. /*
  36. * SSI_MODE1
  37. */
  38. mask1 = (1 << 4) | (1 << 20); /* mask sync bit */
  39. mask2 = (1 << 4); /* mask sync bit */
  40. val1 = val2 = 0;
  41. if (rsnd_ssi_is_pin_sharing(io)) {
  42. int shift = -1;
  43. switch (id) {
  44. case 1:
  45. shift = 0;
  46. break;
  47. case 2:
  48. shift = 2;
  49. break;
  50. case 4:
  51. shift = 16;
  52. break;
  53. default:
  54. return -EINVAL;
  55. }
  56. mask1 |= 0x3 << shift;
  57. val1 = rsnd_rdai_is_clk_master(rdai) ?
  58. 0x2 << shift : 0x1 << shift;
  59. } else if (multi_ssi_slaves) {
  60. mask2 |= 0x00000007;
  61. mask1 |= 0x0000000f;
  62. switch (multi_ssi_slaves) {
  63. case 0x0206: /* SSI0/1/2/9 */
  64. val2 = (1 << 4) | /* SSI0129 sync */
  65. (rsnd_rdai_is_clk_master(rdai) ? 0x2 : 0x1);
  66. /* fall through */
  67. case 0x0006: /* SSI0/1/2 */
  68. val1 = rsnd_rdai_is_clk_master(rdai) ?
  69. 0xa : 0x5;
  70. if (!val2) /* SSI012 sync */
  71. val1 |= (1 << 4);
  72. }
  73. }
  74. rsnd_mod_bset(mod, SSI_MODE1, mask1, val1);
  75. rsnd_mod_bset(mod, SSI_MODE2, mask2, val2);
  76. return 0;
  77. }
  78. static struct rsnd_mod_ops rsnd_ssiu_ops_gen1 = {
  79. .name = SSIU_NAME,
  80. .init = rsnd_ssiu_init,
  81. };
  82. static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
  83. struct rsnd_dai_stream *io,
  84. struct rsnd_priv *priv)
  85. {
  86. int ret;
  87. ret = rsnd_ssiu_init(mod, io, priv);
  88. if (ret < 0)
  89. return ret;
  90. if (rsnd_runtime_is_ssi_tdm(io)) {
  91. /*
  92. * TDM Extend Mode
  93. * see
  94. * rsnd_ssi_config_init()
  95. */
  96. rsnd_mod_write(mod, SSI_MODE, 0x1);
  97. }
  98. if (rsnd_ssi_use_busif(io)) {
  99. rsnd_mod_write(mod, SSI_BUSIF_ADINR,
  100. rsnd_get_adinr_bit(mod, io) |
  101. (rsnd_io_is_play(io) ?
  102. rsnd_runtime_channel_after_ctu(io) :
  103. rsnd_runtime_channel_original(io)));
  104. rsnd_mod_write(mod, SSI_BUSIF_MODE, 1);
  105. rsnd_mod_write(mod, SSI_BUSIF_DALIGN,
  106. rsnd_get_dalign(mod, io));
  107. }
  108. return 0;
  109. }
  110. static int rsnd_ssiu_start_gen2(struct rsnd_mod *mod,
  111. struct rsnd_dai_stream *io,
  112. struct rsnd_priv *priv)
  113. {
  114. if (!rsnd_ssi_use_busif(io))
  115. return 0;
  116. rsnd_mod_write(mod, SSI_CTRL, 0x1);
  117. if (rsnd_ssi_multi_slaves_runtime(io))
  118. rsnd_mod_write(mod, SSI_CONTROL, 0x1);
  119. return 0;
  120. }
  121. static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod,
  122. struct rsnd_dai_stream *io,
  123. struct rsnd_priv *priv)
  124. {
  125. if (!rsnd_ssi_use_busif(io))
  126. return 0;
  127. rsnd_mod_write(mod, SSI_CTRL, 0);
  128. if (rsnd_ssi_multi_slaves_runtime(io))
  129. rsnd_mod_write(mod, SSI_CONTROL, 0);
  130. return 0;
  131. }
  132. static struct rsnd_mod_ops rsnd_ssiu_ops_gen2 = {
  133. .name = SSIU_NAME,
  134. .init = rsnd_ssiu_init_gen2,
  135. .start = rsnd_ssiu_start_gen2,
  136. .stop = rsnd_ssiu_stop_gen2,
  137. };
  138. static struct rsnd_mod *rsnd_ssiu_mod_get(struct rsnd_priv *priv, int id)
  139. {
  140. if (WARN_ON(id < 0 || id >= rsnd_ssiu_nr(priv)))
  141. id = 0;
  142. return rsnd_mod_get((struct rsnd_ssiu *)(priv->ssiu) + id);
  143. }
  144. int rsnd_ssiu_attach(struct rsnd_dai_stream *io,
  145. struct rsnd_mod *ssi_mod)
  146. {
  147. struct rsnd_priv *priv = rsnd_io_to_priv(io);
  148. struct rsnd_mod *mod = rsnd_ssiu_mod_get(priv, rsnd_mod_id(ssi_mod));
  149. rsnd_mod_confirm_ssi(ssi_mod);
  150. return rsnd_dai_connect(mod, io, mod->type);
  151. }
  152. int rsnd_ssiu_probe(struct rsnd_priv *priv)
  153. {
  154. struct device *dev = rsnd_priv_to_dev(priv);
  155. struct rsnd_ssiu *ssiu;
  156. static struct rsnd_mod_ops *ops;
  157. int i, nr, ret;
  158. /* same number to SSI */
  159. nr = priv->ssi_nr;
  160. ssiu = devm_kzalloc(dev, sizeof(*ssiu) * nr, GFP_KERNEL);
  161. if (!ssiu)
  162. return -ENOMEM;
  163. priv->ssiu = ssiu;
  164. priv->ssiu_nr = nr;
  165. if (rsnd_is_gen1(priv))
  166. ops = &rsnd_ssiu_ops_gen1;
  167. else
  168. ops = &rsnd_ssiu_ops_gen2;
  169. for_each_rsnd_ssiu(ssiu, priv, i) {
  170. ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu),
  171. ops, NULL, rsnd_mod_get_status,
  172. RSND_MOD_SSIU, i);
  173. if (ret)
  174. return ret;
  175. }
  176. return 0;
  177. }
  178. void rsnd_ssiu_remove(struct rsnd_priv *priv)
  179. {
  180. struct rsnd_ssiu *ssiu;
  181. int i;
  182. for_each_rsnd_ssiu(ssiu, priv, i) {
  183. rsnd_mod_quit(rsnd_mod_get(ssiu));
  184. }
  185. }