801-audio-0037-MLK-16224-4-ASoC-fsl_sai-support-multi-fifo-and-DSD.patch 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. From 87f734fa8214b4ddbfdac9b7ac5dc75a3d86badb Mon Sep 17 00:00:00 2001
  2. From: Shengjiu Wang <[email protected]>
  3. Date: Tue, 23 Jan 2018 13:26:37 +0800
  4. Subject: [PATCH] MLK-16224-4: ASoC: fsl_sai: support multi fifo and DSD
  5. The codec always mux the LRCLK pin to DSD data line, so when
  6. we want to support DSD, the pinmux is different. For two channel
  7. DSD, the DSDL is mapped to TX0, but the DSDR is mapped to TX4,
  8. there is address offset for the fifo address of TX0 and TX4, TX4's
  9. fifo is not adjacent to TX0's.
  10. Usually, if mapping is TX0 and TX1, that will be easy for SAI
  11. and SDMA to handle, that SAI can use the FIFO combine mode, SDMA
  12. can use the normal script.
  13. so for DSD:
  14. 1. The SDMA should use the multi-fifo script, and SAI can't
  15. use the FIFO combine mode.
  16. 2. driver should to check the dts configuration(fsl,dataline) for
  17. which dataline is used corrently
  18. 3. maxburst is the multiply of datalines
  19. 4. each channel of DSD occupy one data lane
  20. 5. according to data lane, set TRCE bits
  21. Signed-off-by: Shengjiu Wang <[email protected]>
  22. Reviewed-by: Viorel Suman <[email protected]>
  23. ---
  24. sound/soc/fsl/fsl_sai.c | 162 +++++++++++++++++++++++++++++++++++++++++++++---
  25. sound/soc/fsl/fsl_sai.h | 12 +++-
  26. 2 files changed, 164 insertions(+), 10 deletions(-)
  27. --- a/sound/soc/fsl/fsl_sai.c
  28. +++ b/sound/soc/fsl/fsl_sai.c
  29. @@ -267,6 +267,7 @@ static int fsl_sai_set_dai_fmt_tr(struct
  30. if (!sai->is_lsb_first)
  31. val_cr4 |= FSL_SAI_CR4_MF;
  32. + sai->is_dsp_mode = false;
  33. /* DAI mode */
  34. switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
  35. case SND_SOC_DAIFMT_I2S:
  36. @@ -305,6 +306,11 @@ static int fsl_sai_set_dai_fmt_tr(struct
  37. val_cr2 |= FSL_SAI_CR2_BCP;
  38. sai->is_dsp_mode = true;
  39. break;
  40. + case SND_SOC_DAIFMT_PDM:
  41. + val_cr2 |= FSL_SAI_CR2_BCP;
  42. + val_cr4 &= ~FSL_SAI_CR4_MF;
  43. + sai->is_dsp_mode = true;
  44. + break;
  45. case SND_SOC_DAIFMT_RIGHT_J:
  46. /* To be done */
  47. default:
  48. @@ -492,12 +498,38 @@ static int fsl_sai_hw_params(struct snd_
  49. u32 slot_width = word_width;
  50. u32 pins;
  51. int ret;
  52. + int i;
  53. + int trce_mask = 0;
  54. + snd_pcm_format_t format = params_format(params);
  55. if (sai->slots)
  56. slots = sai->slots;
  57. pins = DIV_ROUND_UP(channels, slots);
  58. + if (format == SNDRV_PCM_FORMAT_DSD_U8 ||
  59. + format == SNDRV_PCM_FORMAT_DSD_U16_LE ||
  60. + format == SNDRV_PCM_FORMAT_DSD_U16_BE ||
  61. + format == SNDRV_PCM_FORMAT_DSD_U32_LE ||
  62. + format == SNDRV_PCM_FORMAT_DSD_U32_BE) {
  63. + sai->is_dsd = true;
  64. +
  65. + if (!IS_ERR_OR_NULL(sai->pins_dsd)) {
  66. + ret = pinctrl_select_state(sai->pinctrl, sai->pins_dsd);
  67. + if (ret) {
  68. + dev_err(cpu_dai->dev,
  69. + "failed to set proper pins state: %d\n", ret);
  70. + return ret;
  71. + }
  72. + }
  73. + } else {
  74. + pinctrl_pm_select_default_state(cpu_dai->dev);
  75. + sai->is_dsd = false;
  76. + }
  77. +
  78. + if (sai->is_dsd)
  79. + pins = channels;
  80. +
  81. if (sai->slot_width)
  82. slot_width = sai->slot_width;
  83. @@ -527,7 +559,7 @@ static int fsl_sai_hw_params(struct snd_
  84. val_cr5 |= FSL_SAI_CR5_WNW(slot_width);
  85. val_cr5 |= FSL_SAI_CR5_W0W(slot_width);
  86. - if (sai->is_lsb_first)
  87. + if (sai->is_lsb_first || sai->is_dsd)
  88. val_cr5 |= FSL_SAI_CR5_FBT(0);
  89. else
  90. val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1);
  91. @@ -560,17 +592,71 @@ static int fsl_sai_hw_params(struct snd_
  92. }
  93. if (sai->soc->dataline != 0x1) {
  94. - if (sai->dataline[tx] <= 1)
  95. +
  96. + if (sai->dataline[tx] <= 1 || sai->is_multi_lane)
  97. regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, offset),
  98. FSL_SAI_CR4_FCOMB_MASK, 0);
  99. else
  100. regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, offset),
  101. FSL_SAI_CR4_FCOMB_MASK, FSL_SAI_CR4_FCOMB_SOFT);
  102. +
  103. + if (sai->is_multi_lane) {
  104. + if (tx) {
  105. + sai->dma_params_tx.maxburst =
  106. + FSL_SAI_MAXBURST_TX * pins;
  107. + if (sai->is_dsd)
  108. + sai->dma_params_tx.fifo_num = pins +
  109. + (sai->dataline_off_dsd[tx] << 8);
  110. + else
  111. + sai->dma_params_tx.fifo_num = pins +
  112. + (sai->dataline_off[tx] << 8);
  113. + } else {
  114. + sai->dma_params_rx.maxburst =
  115. + FSL_SAI_MAXBURST_RX * pins;
  116. + if (sai->is_dsd)
  117. + sai->dma_params_rx.fifo_num = pins +
  118. + (sai->dataline_off_dsd[tx] << 8);
  119. + else
  120. + sai->dma_params_rx.fifo_num = pins +
  121. + (sai->dataline_off[tx] << 8);
  122. + }
  123. + }
  124. +
  125. + snd_soc_dai_init_dma_data(cpu_dai, &sai->dma_params_tx,
  126. + &sai->dma_params_rx);
  127. }
  128. - regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, offset),
  129. + if (sai->is_dsd) {
  130. + if (__sw_hweight8(sai->dataline_dsd[tx] & 0xFF) < pins) {
  131. + dev_err(cpu_dai->dev, "channel not supported\n");
  132. + return -EINVAL;
  133. + }
  134. + /*find a proper tcre setting*/
  135. + for (i = 0; i < 8; i++) {
  136. + trce_mask = (1 << (i + 1)) - 1;
  137. + if (__sw_hweight8(sai->dataline_dsd[tx] & trce_mask) == pins)
  138. + break;
  139. + }
  140. +
  141. + regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, offset),
  142. FSL_SAI_CR3_TRCE_MASK,
  143. - FSL_SAI_CR3_TRCE((sai->dataline[tx] & ((1 << pins) - 1))));
  144. + FSL_SAI_CR3_TRCE((sai->dataline_dsd[tx] & trce_mask)));
  145. + } else {
  146. + if (__sw_hweight8(sai->dataline[tx] & 0xFF) < pins) {
  147. + dev_err(cpu_dai->dev, "channel not supported\n");
  148. + return -EINVAL;
  149. + }
  150. + /*find a proper tcre setting*/
  151. + for (i = 0; i < 8; i++) {
  152. + trce_mask = (1 << (i + 1)) - 1;
  153. + if (__sw_hweight8(sai->dataline[tx] & trce_mask) == pins)
  154. + break;
  155. + }
  156. +
  157. + regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, offset),
  158. + FSL_SAI_CR3_TRCE_MASK,
  159. + FSL_SAI_CR3_TRCE((sai->dataline[tx] & trce_mask)));
  160. + }
  161. regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, offset),
  162. FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
  163. @@ -610,9 +696,18 @@ static int fsl_sai_trigger(struct snd_pc
  164. unsigned char offset = sai->soc->reg_offset;
  165. bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
  166. u8 channels = substream->runtime->channels;
  167. + u32 slots = (channels == 1) ? 2 : channels;
  168. u32 xcsr, count = 100;
  169. - int i;
  170. + u32 pins;
  171. + int i = 0, j = 0, k = 0;
  172. +
  173. + if (sai->slots)
  174. + slots = sai->slots;
  175. +
  176. + pins = DIV_ROUND_UP(channels, slots);
  177. + if (sai->is_dsd)
  178. + pins = channels;
  179. /*
  180. * Asynchronous mode: Clear SYNC for both Tx and Rx.
  181. * Rx sync with Tx clocks: Clear SYNC for Tx, set it for Rx.
  182. @@ -631,10 +726,19 @@ static int fsl_sai_trigger(struct snd_pc
  183. case SNDRV_PCM_TRIGGER_START:
  184. case SNDRV_PCM_TRIGGER_RESUME:
  185. case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
  186. - for (i = 0; tx && i < channels; i++)
  187. - regmap_write(sai->regmap, FSL_SAI_TDR0, 0x0);
  188. - if (tx)
  189. - udelay(10);
  190. +
  191. + for (i = 0; tx && i < channels; i++) {
  192. + while (tx && i < channels)
  193. + if (sai->dataline[tx] & (1 << j)) {
  194. + regmap_write(sai->regmap, FSL_SAI_TDR0 + j * 0x4, 0x0);
  195. + i++;
  196. + k++;
  197. + }
  198. + j++;
  199. +
  200. + if (k%pins == 0)
  201. + j = 0;
  202. + }
  203. regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, offset),
  204. FSL_SAI_CSR_FRDE, FSL_SAI_CSR_FRDE);
  205. @@ -994,6 +1098,7 @@ static int fsl_sai_probe(struct platform
  206. char tmp[8];
  207. int irq, ret, i;
  208. int index;
  209. + int firstbitidx, nextbitidx;
  210. struct regmap_config fsl_sai_regmap_config = fsl_sai_v2_regmap_config;
  211. unsigned long irqflags = 0;
  212. @@ -1048,6 +1153,9 @@ static int fsl_sai_probe(struct platform
  213. }
  214. }
  215. + if (of_find_property(np, "fsl,sai-multi-lane", NULL))
  216. + sai->is_multi_lane = true;
  217. +
  218. /*dataline mask for rx and tx*/
  219. ret = of_property_read_u32_index(np, "fsl,dataline", 0, &sai->dataline[0]);
  220. if (ret)
  221. @@ -1062,6 +1170,37 @@ static int fsl_sai_probe(struct platform
  222. return -EINVAL;
  223. }
  224. + for (i = 0; i < 2; i++) {
  225. + firstbitidx = find_first_bit((const unsigned long *)&sai->dataline[i], 8);
  226. + nextbitidx = find_next_bit((const unsigned long *)&sai->dataline[i], 8, firstbitidx+1);
  227. + sai->dataline_off[i] = nextbitidx - firstbitidx - 1;
  228. +
  229. + if (sai->dataline_off[i] < 0 || sai->dataline_off[i] >= 7)
  230. + sai->dataline_off[i] = 0;
  231. + }
  232. +
  233. + ret = of_property_read_u32_index(np, "fsl,dataline,dsd", 0, &sai->dataline_dsd[0]);
  234. + if (ret)
  235. + sai->dataline_dsd[0] = 1;
  236. +
  237. + ret = of_property_read_u32_index(np, "fsl,dataline,dsd", 1, &sai->dataline_dsd[1]);
  238. + if (ret)
  239. + sai->dataline_dsd[1] = 1;
  240. +
  241. + if ((sai->dataline_dsd[0] & (~sai->soc->dataline)) || sai->dataline_dsd[1] & (~sai->soc->dataline)) {
  242. + dev_err(&pdev->dev, "dataline setting error, Mask is 0x%x\n", sai->soc->dataline);
  243. + return -EINVAL;
  244. + }
  245. +
  246. + for (i = 0; i < 2; i++) {
  247. + firstbitidx = find_first_bit((const unsigned long *)&sai->dataline_dsd[i], 8);
  248. + nextbitidx = find_next_bit((const unsigned long *)&sai->dataline_dsd[i], 8, firstbitidx+1);
  249. + sai->dataline_off_dsd[i] = nextbitidx - firstbitidx - 1;
  250. +
  251. + if (sai->dataline_off_dsd[i] < 0 || sai->dataline_off_dsd[i] >= 7)
  252. + sai->dataline_off_dsd[i] = 0;
  253. + }
  254. +
  255. if ((of_find_property(np, "fsl,i2s-xtor", NULL) != NULL) ||
  256. (of_find_property(np, "fsl,txm-rxs", NULL) != NULL))
  257. {
  258. @@ -1144,6 +1283,11 @@ static int fsl_sai_probe(struct platform
  259. sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX;
  260. sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX;
  261. + sai->pinctrl = devm_pinctrl_get(&pdev->dev);
  262. +
  263. + if (!IS_ERR_OR_NULL(sai->pinctrl))
  264. + sai->pins_dsd = pinctrl_lookup_state(sai->pinctrl, "dsd");
  265. +
  266. platform_set_drvdata(pdev, sai);
  267. pm_runtime_enable(&pdev->dev);
  268. --- a/sound/soc/fsl/fsl_sai.h
  269. +++ b/sound/soc/fsl/fsl_sai.h
  270. @@ -11,7 +11,10 @@
  271. #define FSL_SAI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
  272. SNDRV_PCM_FMTBIT_S24_LE |\
  273. - SNDRV_PCM_FMTBIT_S32_LE)
  274. + SNDRV_PCM_FMTBIT_S32_LE |\
  275. + SNDRV_PCM_FMTBIT_DSD_U8 |\
  276. + SNDRV_PCM_FMTBIT_DSD_U16_LE |\
  277. + SNDRV_PCM_FMTBIT_DSD_U32_LE)
  278. /* SAI Register Map Register */
  279. #define FSL_SAI_TCSR(offset) (0x00 + offset) /* SAI Transmit Control */
  280. @@ -172,9 +175,14 @@ struct fsl_sai {
  281. bool slave_mode[2];
  282. bool is_lsb_first;
  283. bool is_dsp_mode;
  284. + bool is_multi_lane;
  285. bool synchronous[2];
  286. bool is_stream_opened[2];
  287. + bool is_dsd;
  288. unsigned int dataline[2];
  289. + unsigned int dataline_dsd[2];
  290. + unsigned int dataline_off[2];
  291. + unsigned int dataline_off_dsd[2];
  292. unsigned int masterflag[2];
  293. unsigned int mclk_id[2];
  294. @@ -188,6 +196,8 @@ struct fsl_sai {
  295. struct snd_dmaengine_dai_dma_data dma_params_tx;
  296. const struct fsl_sai_soc_data *soc;
  297. struct pm_qos_request pm_qos_req;
  298. + struct pinctrl *pinctrl;
  299. + struct pinctrl_state *pins_dsd;
  300. };
  301. #define TX 1