ssiu.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  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. /* clear status */
  32. switch (id) {
  33. case 0:
  34. case 1:
  35. case 2:
  36. case 3:
  37. case 4:
  38. rsnd_mod_write(mod, SSI_SYS_STATUS0, 0xf << (id * 4));
  39. rsnd_mod_write(mod, SSI_SYS_STATUS2, 0xf << (id * 4));
  40. rsnd_mod_write(mod, SSI_SYS_STATUS4, 0xf << (id * 4));
  41. rsnd_mod_write(mod, SSI_SYS_STATUS6, 0xf << (id * 4));
  42. break;
  43. case 9:
  44. rsnd_mod_write(mod, SSI_SYS_STATUS1, 0xf << 4);
  45. rsnd_mod_write(mod, SSI_SYS_STATUS3, 0xf << 4);
  46. rsnd_mod_write(mod, SSI_SYS_STATUS5, 0xf << 4);
  47. rsnd_mod_write(mod, SSI_SYS_STATUS7, 0xf << 4);
  48. break;
  49. }
  50. /*
  51. * SSI_MODE0
  52. */
  53. rsnd_mod_bset(mod, SSI_MODE0, (1 << id), !use_busif << id);
  54. /*
  55. * SSI_MODE1
  56. */
  57. mask1 = (1 << 4) | (1 << 20); /* mask sync bit */
  58. mask2 = (1 << 4); /* mask sync bit */
  59. val1 = val2 = 0;
  60. if (rsnd_ssi_is_pin_sharing(io)) {
  61. int shift = -1;
  62. switch (id) {
  63. case 1:
  64. shift = 0;
  65. break;
  66. case 2:
  67. shift = 2;
  68. break;
  69. case 4:
  70. shift = 16;
  71. break;
  72. default:
  73. return -EINVAL;
  74. }
  75. mask1 |= 0x3 << shift;
  76. val1 = rsnd_rdai_is_clk_master(rdai) ?
  77. 0x2 << shift : 0x1 << shift;
  78. } else if (multi_ssi_slaves) {
  79. mask2 |= 0x00000007;
  80. mask1 |= 0x0000000f;
  81. switch (multi_ssi_slaves) {
  82. case 0x0206: /* SSI0/1/2/9 */
  83. val2 = (1 << 4) | /* SSI0129 sync */
  84. (rsnd_rdai_is_clk_master(rdai) ? 0x2 : 0x1);
  85. /* fall through */
  86. case 0x0006: /* SSI0/1/2 */
  87. val1 = rsnd_rdai_is_clk_master(rdai) ?
  88. 0xa : 0x5;
  89. if (!val2) /* SSI012 sync */
  90. val1 |= (1 << 4);
  91. }
  92. }
  93. rsnd_mod_bset(mod, SSI_MODE1, mask1, val1);
  94. rsnd_mod_bset(mod, SSI_MODE2, mask2, val2);
  95. return 0;
  96. }
  97. static struct rsnd_mod_ops rsnd_ssiu_ops_gen1 = {
  98. .name = SSIU_NAME,
  99. .init = rsnd_ssiu_init,
  100. };
  101. static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
  102. struct rsnd_dai_stream *io,
  103. struct rsnd_priv *priv)
  104. {
  105. int ret;
  106. ret = rsnd_ssiu_init(mod, io, priv);
  107. if (ret < 0)
  108. return ret;
  109. if (rsnd_runtime_is_ssi_tdm(io)) {
  110. /*
  111. * TDM Extend Mode
  112. * see
  113. * rsnd_ssi_config_init()
  114. */
  115. rsnd_mod_write(mod, SSI_MODE, 0x1);
  116. }
  117. if (rsnd_ssi_use_busif(io)) {
  118. rsnd_mod_write(mod, SSI_BUSIF_ADINR,
  119. rsnd_get_adinr_bit(mod, io) |
  120. (rsnd_io_is_play(io) ?
  121. rsnd_runtime_channel_after_ctu(io) :
  122. rsnd_runtime_channel_original(io)));
  123. rsnd_mod_write(mod, SSI_BUSIF_MODE, 1);
  124. rsnd_mod_write(mod, SSI_BUSIF_DALIGN,
  125. rsnd_get_dalign(mod, io));
  126. }
  127. return 0;
  128. }
  129. static int rsnd_ssiu_start_gen2(struct rsnd_mod *mod,
  130. struct rsnd_dai_stream *io,
  131. struct rsnd_priv *priv)
  132. {
  133. if (!rsnd_ssi_use_busif(io))
  134. return 0;
  135. rsnd_mod_write(mod, SSI_CTRL, 0x1);
  136. if (rsnd_ssi_multi_slaves_runtime(io))
  137. rsnd_mod_write(mod, SSI_CONTROL, 0x1);
  138. return 0;
  139. }
  140. static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod,
  141. struct rsnd_dai_stream *io,
  142. struct rsnd_priv *priv)
  143. {
  144. if (!rsnd_ssi_use_busif(io))
  145. return 0;
  146. rsnd_mod_write(mod, SSI_CTRL, 0);
  147. if (rsnd_ssi_multi_slaves_runtime(io))
  148. rsnd_mod_write(mod, SSI_CONTROL, 0);
  149. return 0;
  150. }
  151. static struct rsnd_mod_ops rsnd_ssiu_ops_gen2 = {
  152. .name = SSIU_NAME,
  153. .init = rsnd_ssiu_init_gen2,
  154. .start = rsnd_ssiu_start_gen2,
  155. .stop = rsnd_ssiu_stop_gen2,
  156. };
  157. static struct rsnd_mod *rsnd_ssiu_mod_get(struct rsnd_priv *priv, int id)
  158. {
  159. if (WARN_ON(id < 0 || id >= rsnd_ssiu_nr(priv)))
  160. id = 0;
  161. return rsnd_mod_get((struct rsnd_ssiu *)(priv->ssiu) + id);
  162. }
  163. int rsnd_ssiu_attach(struct rsnd_dai_stream *io,
  164. struct rsnd_mod *ssi_mod)
  165. {
  166. struct rsnd_priv *priv = rsnd_io_to_priv(io);
  167. struct rsnd_mod *mod = rsnd_ssiu_mod_get(priv, rsnd_mod_id(ssi_mod));
  168. rsnd_mod_confirm_ssi(ssi_mod);
  169. return rsnd_dai_connect(mod, io, mod->type);
  170. }
  171. int rsnd_ssiu_probe(struct rsnd_priv *priv)
  172. {
  173. struct device *dev = rsnd_priv_to_dev(priv);
  174. struct rsnd_ssiu *ssiu;
  175. static struct rsnd_mod_ops *ops;
  176. int i, nr, ret;
  177. /* same number to SSI */
  178. nr = priv->ssi_nr;
  179. ssiu = devm_kzalloc(dev, sizeof(*ssiu) * nr, GFP_KERNEL);
  180. if (!ssiu)
  181. return -ENOMEM;
  182. priv->ssiu = ssiu;
  183. priv->ssiu_nr = nr;
  184. if (rsnd_is_gen1(priv))
  185. ops = &rsnd_ssiu_ops_gen1;
  186. else
  187. ops = &rsnd_ssiu_ops_gen2;
  188. for_each_rsnd_ssiu(ssiu, priv, i) {
  189. ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu),
  190. ops, NULL, rsnd_mod_get_status,
  191. RSND_MOD_SSIU, i);
  192. if (ret)
  193. return ret;
  194. }
  195. return 0;
  196. }
  197. void rsnd_ssiu_remove(struct rsnd_priv *priv)
  198. {
  199. struct rsnd_ssiu *ssiu;
  200. int i;
  201. for_each_rsnd_ssiu(ssiu, priv, i) {
  202. rsnd_mod_quit(rsnd_mod_get(ssiu));
  203. }
  204. }