1 // SPDX-License-Identifier: BSD-3-Clause
2 //
3 // Copyright(c) 2016 Intel Corporation. All rights reserved.
4 //
5 // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
6 // Keyon Jie <yang.jie@linux.intel.com>
7 // Rander Wang <rander.wang@linux.intel.com>
8
9 #include <sof/audio/component.h>
10 #include <sof/common.h>
11 #include <sof/drivers/mn.h>
12 #include <sof/drivers/timestamp.h>
13 #include <sof/drivers/ssp.h>
14 #include <sof/lib/alloc.h>
15 #include <sof/lib/clk.h>
16 #include <sof/lib/dai.h>
17 #include <sof/lib/dma.h>
18 #include <sof/lib/memory.h>
19 #include <sof/lib/pm_runtime.h>
20 #include <sof/lib/uuid.h>
21 #include <sof/lib/wait.h>
22 #include <sof/platform.h>
23 #include <sof/spinlock.h>
24 #include <sof/trace/trace.h>
25 #include <ipc/dai.h>
26 #include <ipc/dai-intel.h>
27 #include <ipc/stream.h>
28 #include <ipc/topology.h>
29 #include <ipc4/ssp.h>
30 #include <user/trace.h>
31
32 #include <errno.h>
33 #include <stdbool.h>
34 #include <stdint.h>
35
36 /* 31458125-95c4-4085-8f3f-497434cb2daf */
37 DECLARE_SOF_UUID("ssp-dai", ssp_uuid, 0x31458125, 0x95c4, 0x4085,
38 0x8f, 0x3f, 0x49, 0x74, 0x34, 0xcb, 0x2d, 0xaf);
39
40 DECLARE_TR_CTX(ssp_tr, SOF_UUID(ssp_uuid), LOG_LEVEL_INFO);
41
42 /* empty SSP transmit FIFO */
ssp_empty_tx_fifo(struct dai * dai)43 static void ssp_empty_tx_fifo(struct dai *dai)
44 {
45 int ret;
46 uint32_t sssr;
47
48 /*
49 * SSSR_TNF is cleared when TX FIFO is empty or full,
50 * so wait for set TNF then for TFL zero - order matter.
51 */
52 ret = poll_for_register_delay(dai_base(dai) + SSSR, SSSR_TNF, SSSR_TNF,
53 SSP_MAX_SEND_TIME_PER_SAMPLE);
54 ret |= poll_for_register_delay(dai_base(dai) + SSCR3, SSCR3_TFL_MASK, 0,
55 SSP_MAX_SEND_TIME_PER_SAMPLE *
56 (SSP_FIFO_DEPTH - 1) / 2);
57
58 if (ret)
59 dai_warn(dai, "ssp_empty_tx_fifo() warning: timeout");
60
61 sssr = ssp_read(dai, SSSR);
62
63 /* clear interrupt */
64 if (sssr & SSSR_TUR)
65 ssp_write(dai, SSSR, sssr);
66 }
67
68 /* empty SSP receive FIFO */
ssp_empty_rx_fifo(struct dai * dai)69 static void ssp_empty_rx_fifo(struct dai *dai)
70 {
71 struct ssp_pdata *ssp = dai_get_drvdata(dai);
72 uint64_t sample_ticks = clock_ticks_per_sample(PLATFORM_DEFAULT_CLOCK,
73 ssp->params.fsync_rate);
74 uint32_t retry = SSP_RX_FLUSH_RETRY_MAX;
75 uint32_t entries;
76 uint32_t i;
77
78 /*
79 * To make sure all the RX FIFO entries are read out for the flushing,
80 * we need to wait a minimal SSP port delay after entries are all read,
81 * and then re-check to see if there is any subsequent entries written
82 * to the FIFO. This will help to make sure there is no sample mismatched
83 * issue for the next run with the SSP RX.
84 */
85 while ((ssp_read(dai, SSSR) & SSSR_RNE) && retry--) {
86 entries = SSCR3_RFL_VAL(ssp_read(dai, SSCR3));
87 dai_dbg(dai, "ssp_empty_rx_fifo(), before flushing, entries %d", entries);
88 for (i = 0; i < entries + 1; i++)
89 /* read to try empty fifo */
90 ssp_read(dai, SSDR);
91
92 /* wait to get valid fifo status and re-check */
93 wait_delay(sample_ticks);
94 entries = SSCR3_RFL_VAL(ssp_read(dai, SSCR3));
95 dai_dbg(dai, "ssp_empty_rx_fifo(), after flushing, entries %d", entries);
96 }
97
98 /* clear interrupt */
99 ssp_update_bits(dai, SSSR, SSSR_ROR, SSSR_ROR);
100 }
101
102 /* save SSP context prior to entering D3 */
ssp_context_store(struct dai * dai)103 static int ssp_context_store(struct dai *dai)
104 {
105 struct ssp_pdata *ssp = dai_get_drvdata(dai);
106
107 ssp->sscr0 = ssp_read(dai, SSCR0);
108 ssp->sscr1 = ssp_read(dai, SSCR1);
109
110 /* FIXME: need to store sscr2,3,4,5 */
111 ssp->psp = ssp_read(dai, SSPSP);
112
113 return 0;
114 }
115
116 /* restore SSP context after leaving D3 */
ssp_context_restore(struct dai * dai)117 static int ssp_context_restore(struct dai *dai)
118 {
119 struct ssp_pdata *ssp = dai_get_drvdata(dai);
120
121 ssp_write(dai, SSCR0, ssp->sscr0);
122 ssp_write(dai, SSCR1, ssp->sscr1);
123 /* FIXME: need to restore sscr2,3,4,5 */
124 ssp_write(dai, SSPSP, ssp->psp);
125
126 return 0;
127 }
128
ssp_mclk_prepare_enable(struct dai * dai)129 static int ssp_mclk_prepare_enable(struct dai *dai)
130 {
131 struct ssp_pdata *ssp = dai_get_drvdata(dai);
132 struct sof_ipc_dai_config *config = &ssp->config;
133 int ret;
134
135 if (ssp->clk_active & SSP_CLK_MCLK_ACTIVE)
136 return 0;
137
138 /* MCLK config */
139 ret = mn_set_mclk(config->ssp.mclk_id, config->ssp.mclk_rate);
140 if (ret < 0)
141 dai_err(dai, "ssp_mclk_prepare_enable(): invalid mclk_rate = %d for mclk_id = %d",
142 config->ssp.mclk_rate, config->ssp.mclk_id);
143 else
144 ssp->clk_active |= SSP_CLK_MCLK_ACTIVE;
145
146 return ret;
147 }
148
ssp_mclk_disable_unprepare(struct dai * dai)149 static void ssp_mclk_disable_unprepare(struct dai *dai)
150 {
151 struct ssp_pdata *ssp = dai_get_drvdata(dai);
152
153 if (!(ssp->clk_active & SSP_CLK_MCLK_ACTIVE))
154 return;
155
156 mn_release_mclk(ssp->config.ssp.mclk_id);
157
158 ssp->clk_active &= ~SSP_CLK_MCLK_ACTIVE;
159 }
160
ssp_bclk_prepare_enable(struct dai * dai)161 static int ssp_bclk_prepare_enable(struct dai *dai)
162 {
163 struct ssp_pdata *ssp = dai_get_drvdata(dai);
164 struct sof_ipc_dai_config *config = &ssp->config;
165 uint32_t sscr0;
166 uint32_t mdiv;
167 bool need_ecs = false;
168 int ret = 0;
169
170 if (ssp->clk_active & SSP_CLK_BCLK_ACTIVE)
171 return 0;
172
173 sscr0 = ssp_read(dai, SSCR0);
174
175 #if CONFIG_INTEL_MN
176 /* BCLK config */
177 ret = mn_set_bclk(config->dai_index, config->ssp.bclk_rate,
178 &mdiv, &need_ecs);
179 if (ret < 0) {
180 dai_err(dai, "ssp_bclk_prepare_enable(): invalid bclk_rate = %d for dai_index = %d",
181 config->ssp.bclk_rate, config->dai_index);
182 goto out;
183 }
184 #else
185 if (ssp_freq[SSP_DEFAULT_IDX].freq % config->ssp.bclk_rate != 0) {
186 dai_err(dai, "ssp_bclk_prepare_enable(): invalid bclk_rate = %d for dai_index = %d",
187 config->ssp.bclk_rate, config->dai_index);
188 ret = -EINVAL;
189 goto out;
190 }
191
192 mdiv = ssp_freq[SSP_DEFAULT_IDX].freq / config->ssp.bclk_rate;
193 #endif
194
195 if (need_ecs)
196 sscr0 |= SSCR0_ECS;
197
198 /* clock divisor is SCR + 1 */
199 mdiv -= 1;
200
201 /* divisor must be within SCR range */
202 if (mdiv > (SSCR0_SCR_MASK >> 8)) {
203 dai_err(dai, "ssp_bclk_prepare_enable(): divisor %d is not within SCR range",
204 mdiv);
205 ret = -EINVAL;
206 goto out;
207 }
208
209 /* set the SCR divisor */
210 sscr0 &= ~SSCR0_SCR_MASK;
211 sscr0 |= SSCR0_SCR(mdiv);
212
213 ssp_write(dai, SSCR0, sscr0);
214
215 dai_info(dai, "ssp_bclk_prepare_enable(): sscr0 = 0x%08x", sscr0);
216 out:
217 if (!ret)
218 ssp->clk_active |= SSP_CLK_BCLK_ACTIVE;
219
220 return ret;
221 }
222
ssp_bclk_disable_unprepare(struct dai * dai)223 static void ssp_bclk_disable_unprepare(struct dai *dai)
224 {
225 struct ssp_pdata *ssp = dai_get_drvdata(dai);
226
227 if (!(ssp->clk_active & SSP_CLK_BCLK_ACTIVE))
228 return;
229 #if CONFIG_INTEL_MN
230 mn_release_bclk(dai->index);
231 #endif
232 ssp->clk_active &= ~SSP_CLK_BCLK_ACTIVE;
233 }
234
235 /* Digital Audio interface formatting */
ssp_set_config_tplg(struct dai * dai,struct ipc_config_dai * common_config,void * spec_config)236 static int ssp_set_config_tplg(struct dai *dai, struct ipc_config_dai *common_config,
237 void *spec_config)
238 {
239 struct ssp_pdata *ssp = dai_get_drvdata(dai);
240 struct sof_ipc_dai_config *config = spec_config;
241 uint32_t sscr0;
242 uint32_t sscr1;
243 uint32_t sscr2;
244 uint32_t sscr3;
245 uint32_t sspsp;
246 uint32_t sspsp2;
247 uint32_t sstsa;
248 uint32_t ssrsa;
249 uint32_t ssto;
250 uint32_t ssioc;
251 uint32_t bdiv;
252 uint32_t data_size;
253 uint32_t frame_end_padding;
254 uint32_t slot_end_padding;
255 uint32_t frame_len = 0;
256 uint32_t bdiv_min;
257 uint32_t tft;
258 uint32_t rft;
259 uint32_t active_tx_slots = 2;
260 uint32_t active_rx_slots = 2;
261 uint32_t sample_width = 2;
262
263 bool inverted_bclk = false;
264 bool inverted_frame = false;
265 bool cfs = false;
266 bool start_delay = false;
267
268 int ret = 0;
269
270 spin_lock(&dai->lock);
271
272 /* ignore config if SSP is already configured */
273 if (ssp->state[DAI_DIR_PLAYBACK] > COMP_STATE_READY ||
274 ssp->state[DAI_DIR_CAPTURE] > COMP_STATE_READY) {
275 dai_info(dai, "ssp_set_config(): Already configured. Ignore config");
276 goto out;
277 }
278
279 dai_info(dai, "ssp_set_config(), config->format = 0x%4x",
280 common_config->format);
281
282 /* reset SSP settings */
283 /* sscr0 dynamic settings are DSS, EDSS, SCR, FRDC, ECS */
284 /*
285 * FIXME: MOD, ACS, NCS are not set,
286 * no support for network mode for now
287 */
288 sscr0 = SSCR0_PSP | SSCR0_RIM | SSCR0_TIM;
289
290 /* sscr1 dynamic settings are SFRMDIR, SCLKDIR, SCFR, RSRE, TSRE */
291 sscr1 = SSCR1_TTE | SSCR1_TTELP | SSCR1_TRAIL;
292
293 /* sscr2 dynamic setting is LJDFD */
294 sscr2 = SSCR2_SDFD | SSCR2_TURM1;
295
296 /* sscr3 dynamic settings are TFT, RFT */
297 sscr3 = 0;
298
299 /* sspsp dynamic settings are SCMODE, SFRMP, DMYSTRT, SFRMWDTH */
300 sspsp = 0;
301
302 ssp->config = *config;
303 ssp->params = config->ssp;
304
305 /* sspsp2 no dynamic setting */
306 sspsp2 = 0x0;
307
308 /* ssioc dynamic setting is SFCR */
309 ssioc = SSIOC_SCOE;
310
311 /* ssto no dynamic setting */
312 ssto = 0x0;
313
314 /* sstsa dynamic setting is TTSA, default 2 slots */
315 sstsa = SSTSA_SSTSA(config->ssp.tx_slots);
316
317 /* ssrsa dynamic setting is RTSA, default 2 slots */
318 ssrsa = SSRSA_SSRSA(config->ssp.rx_slots);
319
320 switch (config->format & SOF_DAI_FMT_CLOCK_PROVIDER_MASK) {
321 case SOF_DAI_FMT_CBP_CFP:
322 sscr1 |= SSCR1_SCLKDIR | SSCR1_SFRMDIR;
323 break;
324 case SOF_DAI_FMT_CBC_CFC:
325 sscr1 |= SSCR1_SCFR;
326 cfs = true;
327 break;
328 case SOF_DAI_FMT_CBP_CFC:
329 sscr1 |= SSCR1_SCLKDIR;
330 /* FIXME: this mode has not been tested */
331
332 cfs = true;
333 break;
334 case SOF_DAI_FMT_CBC_CFP:
335 sscr1 |= SSCR1_SCFR | SSCR1_SFRMDIR;
336 /* FIXME: this mode has not been tested */
337 break;
338 default:
339 dai_err(dai, "ssp_set_config(): format & PROVIDER_MASK EINVAL");
340 ret = -EINVAL;
341 goto out;
342 }
343
344 /* clock signal polarity */
345 switch (config->format & SOF_DAI_FMT_INV_MASK) {
346 case SOF_DAI_FMT_NB_NF:
347 break;
348 case SOF_DAI_FMT_NB_IF:
349 inverted_frame = true; /* handled later with format */
350 break;
351 case SOF_DAI_FMT_IB_IF:
352 inverted_bclk = true; /* handled later with bclk idle */
353 inverted_frame = true; /* handled later with format */
354 break;
355 case SOF_DAI_FMT_IB_NF:
356 inverted_bclk = true; /* handled later with bclk idle */
357 break;
358 default:
359 dai_err(dai, "ssp_set_config(): format & INV_MASK EINVAL");
360 ret = -EINVAL;
361 goto out;
362 }
363
364 /* supporting bclk idle state */
365 if (ssp->params.clks_control &
366 SOF_DAI_INTEL_SSP_CLKCTRL_BCLK_IDLE_HIGH) {
367 /* bclk idle state high */
368 sspsp |= SSPSP_SCMODE((inverted_bclk ^ 0x3) & 0x3);
369 } else {
370 /* bclk idle state low */
371 sspsp |= SSPSP_SCMODE(inverted_bclk);
372 }
373
374 sscr0 |= SSCR0_MOD | SSCR0_ACS;
375
376 /* Additional hardware settings */
377
378 /* Receiver Time-out Interrupt Disabled/Enabled */
379 sscr1 |= (ssp->params.quirks & SOF_DAI_INTEL_SSP_QUIRK_TINTE) ?
380 SSCR1_TINTE : 0;
381
382 /* Peripheral Trailing Byte Interrupts Disable/Enable */
383 sscr1 |= (ssp->params.quirks & SOF_DAI_INTEL_SSP_QUIRK_PINTE) ?
384 SSCR1_PINTE : 0;
385
386 /* Enable/disable internal loopback. Output of transmit serial
387 * shifter connected to input of receive serial shifter, internally.
388 */
389 sscr1 |= (ssp->params.quirks & SOF_DAI_INTEL_SSP_QUIRK_LBM) ?
390 SSCR1_LBM : 0;
391
392 /* Transmit data are driven at the same/opposite clock edge specified
393 * in SSPSP.SCMODE[1:0]
394 */
395 sscr2 |= (ssp->params.quirks & SOF_DAI_INTEL_SSP_QUIRK_SMTATF) ?
396 SSCR2_SMTATF : 0;
397
398 /* Receive data are sampled at the same/opposite clock edge specified
399 * in SSPSP.SCMODE[1:0]
400 */
401 sscr2 |= (ssp->params.quirks & SOF_DAI_INTEL_SSP_QUIRK_MMRATF) ?
402 SSCR2_MMRATF : 0;
403
404 /* Enable/disable the fix for PSP consumer mode TXD wait for frame
405 * de-assertion before starting the second channel
406 */
407 sscr2 |= (ssp->params.quirks & SOF_DAI_INTEL_SSP_QUIRK_PSPSTWFDFD) ?
408 SSCR2_PSPSTWFDFD : 0;
409
410 /* Enable/disable the fix for PSP provider mode FSRT with dummy stop &
411 * frame end padding capability
412 */
413 sscr2 |= (ssp->params.quirks & SOF_DAI_INTEL_SSP_QUIRK_PSPSRWFDFD) ?
414 SSCR2_PSPSRWFDFD : 0;
415
416 if (!config->ssp.mclk_rate ||
417 config->ssp.mclk_rate > ssp_freq[MAX_SSP_FREQ_INDEX].freq) {
418 dai_err(dai, "ssp_set_config(): invalid MCLK = %d Hz (valid < %d)",
419 config->ssp.mclk_rate,
420 ssp_freq[MAX_SSP_FREQ_INDEX].freq);
421 ret = -EINVAL;
422 goto out;
423 }
424
425 if (!config->ssp.bclk_rate ||
426 config->ssp.bclk_rate > config->ssp.mclk_rate) {
427 dai_err(dai, "ssp_set_config(): BCLK %d Hz = 0 or > MCLK %d Hz",
428 config->ssp.bclk_rate, config->ssp.mclk_rate);
429 ret = -EINVAL;
430 goto out;
431 }
432
433 /* calc frame width based on BCLK and rate - must be divisable */
434 if (config->ssp.bclk_rate % config->ssp.fsync_rate) {
435 dai_err(dai, "ssp_set_config(): BCLK %d is not divisable by rate %d",
436 config->ssp.bclk_rate, config->ssp.fsync_rate);
437 ret = -EINVAL;
438 goto out;
439 }
440
441 /* must be enough BCLKs for data */
442 bdiv = config->ssp.bclk_rate / config->ssp.fsync_rate;
443 if (bdiv < config->ssp.tdm_slot_width * config->ssp.tdm_slots) {
444 dai_err(dai, "ssp_set_config(): not enough BCLKs need %d",
445 config->ssp.tdm_slot_width *
446 config->ssp.tdm_slots);
447 ret = -EINVAL;
448 goto out;
449 }
450
451 /* tdm_slot_width must be <= 38 for SSP */
452 if (config->ssp.tdm_slot_width > 38) {
453 dai_err(dai, "ssp_set_config(): tdm_slot_width %d > 38",
454 config->ssp.tdm_slot_width);
455 ret = -EINVAL;
456 goto out;
457 }
458
459 bdiv_min = config->ssp.tdm_slots *
460 (config->ssp.tdm_per_slot_padding_flag ?
461 config->ssp.tdm_slot_width : config->ssp.sample_valid_bits);
462 if (bdiv < bdiv_min) {
463 dai_err(dai, "ssp_set_config(): bdiv(%d) < bdiv_min(%d)",
464 bdiv, bdiv_min);
465 ret = -EINVAL;
466 goto out;
467 }
468
469 frame_end_padding = bdiv - bdiv_min;
470 if (frame_end_padding > SSPSP2_FEP_MASK) {
471 dai_err(dai, "ssp_set_config(): frame_end_padding too big: %u",
472 frame_end_padding);
473 ret = -EINVAL;
474 goto out;
475 }
476
477 /* format */
478 switch (config->format & SOF_DAI_FMT_FORMAT_MASK) {
479 case SOF_DAI_FMT_I2S:
480
481 start_delay = true;
482
483 sscr0 |= SSCR0_FRDC(config->ssp.tdm_slots);
484
485 if (bdiv % 2) {
486 dai_err(dai, "ssp_set_config(): bdiv %d is not divisible by 2",
487 bdiv);
488 ret = -EINVAL;
489 goto out;
490 }
491
492 /* set asserted frame length to half frame length */
493 frame_len = bdiv / 2;
494
495 /*
496 * handle frame polarity, I2S default is falling/active low,
497 * non-inverted(inverted_frame=0) -- active low(SFRMP=0),
498 * inverted(inverted_frame=1) -- rising/active high(SFRMP=1),
499 * so, we should set SFRMP to inverted_frame.
500 */
501 sspsp |= SSPSP_SFRMP(inverted_frame);
502
503 /*
504 * for I2S/LEFT_J, the padding has to happen at the end
505 * of each slot
506 */
507 if (frame_end_padding % 2) {
508 dai_err(dai, "ssp_set_config(): frame_end_padding %d is not divisible by 2",
509 frame_end_padding);
510 ret = -EINVAL;
511 goto out;
512 }
513
514 slot_end_padding = frame_end_padding / 2;
515
516 if (slot_end_padding > SOF_DAI_INTEL_SSP_SLOT_PADDING_MAX) {
517 /* too big padding */
518 dai_err(dai, "ssp_set_config(): slot_end_padding > %d",
519 SOF_DAI_INTEL_SSP_SLOT_PADDING_MAX);
520 ret = -EINVAL;
521 goto out;
522 }
523
524 sspsp |= SSPSP_DMYSTOP(slot_end_padding);
525 slot_end_padding >>= SSPSP_DMYSTOP_BITS;
526 sspsp |= SSPSP_EDMYSTOP(slot_end_padding);
527
528 break;
529
530 case SOF_DAI_FMT_LEFT_J:
531
532 /* default start_delay value is set to false */
533
534 sscr0 |= SSCR0_FRDC(config->ssp.tdm_slots);
535
536 /* LJDFD enable */
537 sscr2 &= ~SSCR2_LJDFD;
538
539 if (bdiv % 2) {
540 dai_err(dai, "ssp_set_config(): bdiv %d is not divisible by 2",
541 bdiv);
542 ret = -EINVAL;
543 goto out;
544 }
545
546 /* set asserted frame length to half frame length */
547 frame_len = bdiv / 2;
548
549 /*
550 * handle frame polarity, LEFT_J default is rising/active high,
551 * non-inverted(inverted_frame=0) -- active high(SFRMP=1),
552 * inverted(inverted_frame=1) -- falling/active low(SFRMP=0),
553 * so, we should set SFRMP to !inverted_frame.
554 */
555 sspsp |= SSPSP_SFRMP(!inverted_frame);
556
557 /*
558 * for I2S/LEFT_J, the padding has to happen at the end
559 * of each slot
560 */
561 if (frame_end_padding % 2) {
562 dai_err(dai, "ssp_set_config(): frame_end_padding %d is not divisible by 2",
563 frame_end_padding);
564 ret = -EINVAL;
565 goto out;
566 }
567
568 slot_end_padding = frame_end_padding / 2;
569
570 if (slot_end_padding > 15) {
571 /* can't handle padding over 15 bits */
572 dai_err(dai, "ssp_set_config(): slot_end_padding %d > 15 bits",
573 slot_end_padding);
574 ret = -EINVAL;
575 goto out;
576 }
577
578 sspsp |= SSPSP_DMYSTOP(slot_end_padding);
579 slot_end_padding >>= SSPSP_DMYSTOP_BITS;
580 sspsp |= SSPSP_EDMYSTOP(slot_end_padding);
581
582 break;
583 case SOF_DAI_FMT_DSP_A:
584
585 start_delay = true;
586
587 /* fallthrough */
588
589 case SOF_DAI_FMT_DSP_B:
590
591 /* default start_delay value is set to false */
592
593 sscr0 |= SSCR0_MOD | SSCR0_FRDC(config->ssp.tdm_slots);
594
595 /* set asserted frame length */
596 frame_len = 1; /* default */
597
598 if (cfs && ssp->params.frame_pulse_width > 0 &&
599 ssp->params.frame_pulse_width <=
600 SOF_DAI_INTEL_SSP_FRAME_PULSE_WIDTH_MAX) {
601 frame_len = ssp->params.frame_pulse_width;
602 }
603
604 /* frame_pulse_width must less or equal 38 */
605 if (ssp->params.frame_pulse_width >
606 SOF_DAI_INTEL_SSP_FRAME_PULSE_WIDTH_MAX) {
607 dai_err(dai, "ssp_set_config(): frame_pulse_width > %d",
608 SOF_DAI_INTEL_SSP_FRAME_PULSE_WIDTH_MAX);
609 ret = -EINVAL;
610 goto out;
611 }
612 /*
613 * handle frame polarity, DSP_B default is rising/active high,
614 * non-inverted(inverted_frame=0) -- active high(SFRMP=1),
615 * inverted(inverted_frame=1) -- falling/active low(SFRMP=0),
616 * so, we should set SFRMP to !inverted_frame.
617 */
618 sspsp |= SSPSP_SFRMP(!inverted_frame);
619
620 active_tx_slots = popcount(config->ssp.tx_slots);
621 active_rx_slots = popcount(config->ssp.rx_slots);
622
623 /*
624 * handle TDM mode, TDM mode has padding at the end of
625 * each slot. The amount of padding is equal to result of
626 * subtracting slot width and valid bits per slot.
627 */
628 if (ssp->params.tdm_per_slot_padding_flag) {
629 frame_end_padding = bdiv - config->ssp.tdm_slots *
630 config->ssp.tdm_slot_width;
631
632 slot_end_padding = config->ssp.tdm_slot_width -
633 config->ssp.sample_valid_bits;
634
635 if (slot_end_padding >
636 SOF_DAI_INTEL_SSP_SLOT_PADDING_MAX) {
637 dai_err(dai, "ssp_set_config(): slot_end_padding > %d",
638 SOF_DAI_INTEL_SSP_SLOT_PADDING_MAX);
639 ret = -EINVAL;
640 goto out;
641 }
642
643 sspsp |= SSPSP_DMYSTOP(slot_end_padding);
644 slot_end_padding >>= SSPSP_DMYSTOP_BITS;
645 sspsp |= SSPSP_EDMYSTOP(slot_end_padding);
646 }
647
648 sspsp2 |= (frame_end_padding & SSPSP2_FEP_MASK);
649
650 break;
651 default:
652 dai_err(dai, "ssp_set_config(): invalid format 0x%04x",
653 config->format);
654 ret = -EINVAL;
655 goto out;
656 }
657
658 if (start_delay)
659 sspsp |= SSPSP_FSRT;
660
661 sspsp |= SSPSP_SFRMWDTH(frame_len);
662
663 data_size = config->ssp.sample_valid_bits;
664
665 if (data_size > 16)
666 sscr0 |= (SSCR0_EDSS | SSCR0_DSIZE(data_size - 16));
667 else
668 sscr0 |= SSCR0_DSIZE(data_size);
669
670 /* setting TFT and RFT */
671 switch (config->ssp.sample_valid_bits) {
672 case 16:
673 /* use 2 bytes for each slot */
674 sample_width = 2;
675 break;
676 case 24:
677 case 32:
678 /* use 4 bytes for each slot */
679 sample_width = 4;
680 break;
681 default:
682 dai_err(dai, "ssp_set_config(): sample_valid_bits %d",
683 config->ssp.sample_valid_bits);
684 ret = -EINVAL;
685 goto out;
686 }
687
688 tft = MIN(SSP_FIFO_DEPTH - SSP_FIFO_WATERMARK,
689 sample_width * active_tx_slots);
690 rft = MIN(SSP_FIFO_DEPTH - SSP_FIFO_WATERMARK,
691 sample_width * active_rx_slots);
692
693 sscr3 |= SSCR3_TX(tft) | SSCR3_RX(rft);
694
695 ssp_write(dai, SSCR0, sscr0);
696 ssp_write(dai, SSCR1, sscr1);
697 ssp_write(dai, SSCR2, sscr2);
698 ssp_write(dai, SSCR3, sscr3);
699 ssp_write(dai, SSPSP, sspsp);
700 ssp_write(dai, SSPSP2, sspsp2);
701 ssp_write(dai, SSIOC, ssioc);
702 ssp_write(dai, SSTO, ssto);
703 ssp_write(dai, SSTSA, sstsa);
704 ssp_write(dai, SSRSA, ssrsa);
705
706 dai_info(dai, "ssp_set_config(), sscr0 = 0x%08x, sscr1 = 0x%08x, ssto = 0x%08x, sspsp = 0x%0x",
707 sscr0, sscr1, ssto, sspsp);
708 dai_info(dai, "ssp_set_config(), sscr2 = 0x%08x, sspsp2 = 0x%08x, sscr3 = 0x%08x, ssioc = 0x%08x",
709 sscr2, sspsp2, sscr3, ssioc);
710 dai_info(dai, "ssp_set_config(), ssrsa = 0x%08x, sstsa = 0x%08x",
711 ssrsa, sstsa);
712
713 ssp->state[DAI_DIR_PLAYBACK] = COMP_STATE_PREPARE;
714 ssp->state[DAI_DIR_CAPTURE] = COMP_STATE_PREPARE;
715
716 switch (config->flags & SOF_DAI_CONFIG_FLAGS_MASK) {
717 case SOF_DAI_CONFIG_FLAGS_HW_PARAMS:
718 if (ssp->params.clks_control & SOF_DAI_INTEL_SSP_CLKCTRL_MCLK_ES) {
719 ret = ssp_mclk_prepare_enable(dai);
720 if (ret < 0)
721 goto out;
722
723 ssp->clk_active |= SSP_CLK_MCLK_ES_REQ;
724
725 dai_info(dai, "ssp_set_config(): hw_params stage: enabled MCLK clocks for SSP%d...",
726 dai->index);
727 }
728
729 if (ssp->params.clks_control & SOF_DAI_INTEL_SSP_CLKCTRL_BCLK_ES) {
730 bool enable_sse = false;
731
732 if (!(ssp->clk_active & SSP_CLK_BCLK_ACTIVE))
733 enable_sse = true;
734
735 ret = ssp_bclk_prepare_enable(dai);
736 if (ret < 0)
737 goto out;
738
739 ssp->clk_active |= SSP_CLK_BCLK_ES_REQ;
740
741 if (enable_sse) {
742
743 /* enable TRSE/RSRE before SSE */
744 ssp_update_bits(dai, SSCR1,
745 SSCR1_TSRE | SSCR1_RSRE,
746 SSCR1_TSRE | SSCR1_RSRE);
747
748 /* enable port */
749 ssp_update_bits(dai, SSCR0, SSCR0_SSE, SSCR0_SSE);
750
751 dai_info(dai, "ssp_set_config(): SSE set for SSP%d", dai->index);
752 }
753
754 dai_info(dai, "ssp_set_config(): hw_params stage: enabled BCLK clocks for SSP%d...",
755 dai->index);
756 }
757 break;
758 case SOF_DAI_CONFIG_FLAGS_HW_FREE:
759 if (ssp->params.clks_control & SOF_DAI_INTEL_SSP_CLKCTRL_BCLK_ES) {
760 dai_info(dai, "ssp_set_config(): hw_free stage: releasing BCLK clocks for SSP%d...",
761 dai->index);
762 if (ssp->clk_active & SSP_CLK_BCLK_ACTIVE) {
763 /* clear TRSE/RSRE before SSE */
764 ssp_update_bits(dai, SSCR1,
765 SSCR1_TSRE | SSCR1_RSRE,
766 0);
767
768 ssp_update_bits(dai, SSCR0, SSCR0_SSE, 0);
769 dai_info(dai, "ssp_set_config(): SSE clear for SSP%d", dai->index);
770 }
771 ssp_bclk_disable_unprepare(dai);
772 ssp->clk_active &= ~SSP_CLK_BCLK_ES_REQ;
773 }
774 if (ssp->params.clks_control & SOF_DAI_INTEL_SSP_CLKCTRL_MCLK_ES) {
775 dai_info(dai, "ssp_set_config: hw_free stage: releasing MCLK clocks for SSP%d...",
776 dai->index);
777 ssp_mclk_disable_unprepare(dai);
778 ssp->clk_active &= ~SSP_CLK_MCLK_ES_REQ;
779 }
780 break;
781 default:
782 break;
783 }
784 out:
785
786 spin_unlock(&dai->lock);
787
788 return ret;
789 }
790
ssp_set_config_blob(struct dai * dai,struct ipc_config_dai * common_config,void * spec_config)791 static int ssp_set_config_blob(struct dai *dai, struct ipc_config_dai *common_config,
792 void *spec_config)
793 {
794 struct ipc4_ssp_configuration_blob *blob = spec_config;
795 struct ssp_pdata *ssp = dai_get_drvdata(dai);
796 uint32_t ssc0, sstsa, ssrsa;
797
798 /* set config only once for playback or capture */
799 if (dai->sref > 1)
800 return 0;
801
802 ssc0 = blob->i2s_driver_config.i2s_config.ssc0;
803 sstsa = blob->i2s_driver_config.i2s_config.sstsa;
804 ssrsa = blob->i2s_driver_config.i2s_config.ssrsa;
805
806 ssp_write(dai, SSCR0, ssc0);
807 ssp_write(dai, SSCR1, blob->i2s_driver_config.i2s_config.ssc1);
808 ssp_write(dai, SSCR2, blob->i2s_driver_config.i2s_config.ssc2);
809 ssp_write(dai, SSCR3, blob->i2s_driver_config.i2s_config.ssc3);
810 ssp_write(dai, SSPSP, blob->i2s_driver_config.i2s_config.sspsp);
811 ssp_write(dai, SSPSP2, blob->i2s_driver_config.i2s_config.sspsp2);
812 ssp_write(dai, SSIOC, blob->i2s_driver_config.i2s_config.ssioc);
813 ssp_write(dai, SSTO, blob->i2s_driver_config.i2s_config.sscto);
814 ssp_write(dai, SSTSA, sstsa);
815 ssp_write(dai, SSRSA, ssrsa);
816
817 dai_info(dai, "ssp_set_config(), sscr0 = 0x%08x, sscr1 = 0x%08x, ssto = 0x%08x, sspsp = 0x%0x",
818 ssc0, blob->i2s_driver_config.i2s_config.ssc1,
819 blob->i2s_driver_config.i2s_config.sscto,
820 blob->i2s_driver_config.i2s_config.sspsp);
821 dai_info(dai, "ssp_set_config(), sscr2 = 0x%08x, sspsp2 = 0x%08x, sscr3 = 0x%08x",
822 blob->i2s_driver_config.i2s_config.ssc2, blob->i2s_driver_config.i2s_config.sspsp2,
823 blob->i2s_driver_config.i2s_config.ssc3);
824 dai_err(dai, "ssp_set_config(), ssioc = 0x%08x, ssrsa = 0x%08x, sstsa = 0x%08x",
825 blob->i2s_driver_config.i2s_config.ssioc, ssrsa, sstsa);
826
827 ssp->config.ssp.sample_valid_bits = SSCR0_DSIZE_GET(ssc0);
828 if (ssc0 & SSCR0_EDSS)
829 ssp->config.ssp.sample_valid_bits += 16;
830
831 ssp->config.ssp.tdm_slots = SSCR0_FRDC_GET(ssc0);
832 ssp->config.ssp.tx_slots = SSTSA_GET(sstsa);
833 ssp->config.ssp.rx_slots = SSRSA_GET(ssrsa);
834 ssp->config.ssp.fsync_rate = 48000;
835 ssp->params = ssp->config.ssp;
836
837 ssp->state[DAI_DIR_PLAYBACK] = COMP_STATE_PREPARE;
838 ssp->state[DAI_DIR_CAPTURE] = COMP_STATE_PREPARE;
839
840 /* ssp blob is set by pcm_hw_params for ipc4 stream, so enable
841 * mclk and bclk at this time.
842 */
843 mn_set_mclk_blob(blob->i2s_driver_config.mclk_config.mdivc,
844 blob->i2s_driver_config.mclk_config.mdivr);
845 ssp->clk_active |= SSP_CLK_MCLK_ES_REQ;
846
847 /* enable TRSE/RSRE before SSE */
848 ssp_update_bits(dai, SSCR1, SSCR1_TSRE | SSCR1_RSRE, SSCR1_TSRE | SSCR1_RSRE);
849
850 /* enable port */
851 ssp_update_bits(dai, SSCR0, SSCR0_SSE, SSCR0_SSE);
852 ssp->clk_active |= SSP_CLK_BCLK_ES_REQ;
853
854 return 0;
855 }
856
ssp_set_config(struct dai * dai,struct ipc_config_dai * common_config,void * spec_config)857 static int ssp_set_config(struct dai *dai, struct ipc_config_dai *common_config,
858 void *spec_config)
859 {
860 if (!common_config->is_config_blob)
861 return ssp_set_config_tplg(dai, common_config, spec_config);
862 else
863 return ssp_set_config_blob(dai, common_config, spec_config);
864 }
865
866 /*
867 * Portion of the SSP configuration should be applied just before the
868 * SSP dai is activated, for either power saving or params runtime
869 * configurable flexibility.
870 */
ssp_pre_start(struct dai * dai)871 static int ssp_pre_start(struct dai *dai)
872 {
873 struct ssp_pdata *ssp = dai_get_drvdata(dai);
874 int ret = 0;
875
876 dai_info(dai, "ssp_pre_start()");
877
878 /*
879 * We will test if mclk/bclk is configured in
880 * ssp_mclk/bclk_prepare_enable/disable functions
881 */
882 if (!(ssp->clk_active & SSP_CLK_MCLK_ES_REQ)) {
883 /* MCLK config */
884 ret = ssp_mclk_prepare_enable(dai);
885 if (ret < 0)
886 return ret;
887 }
888
889 if (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ))
890 ret = ssp_bclk_prepare_enable(dai);
891
892 return ret;
893 }
894
895 /*
896 * For power saving, we should do kinds of power release when the SSP
897 * dai is changed to inactive, though the runtime param configuration
898 * don't have to be reset.
899 */
ssp_post_stop(struct dai * dai)900 static void ssp_post_stop(struct dai *dai)
901 {
902 struct ssp_pdata *ssp = dai_get_drvdata(dai);
903
904 /* release clocks if SSP is inactive */
905 if (ssp->state[SOF_IPC_STREAM_PLAYBACK] != COMP_STATE_ACTIVE &&
906 ssp->state[SOF_IPC_STREAM_CAPTURE] != COMP_STATE_ACTIVE) {
907 if (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ)) {
908 dai_info(dai, "ssp_post_stop releasing BCLK clocks for SSP%d...",
909 dai->index);
910 ssp_bclk_disable_unprepare(dai);
911 }
912 if (!(ssp->clk_active & SSP_CLK_MCLK_ES_REQ)) {
913 dai_info(dai, "ssp_post_stop releasing MCLK clocks for SSP%d...",
914 dai->index);
915 ssp_mclk_disable_unprepare(dai);
916 }
917 }
918 }
919
920 /* get SSP hw params */
ssp_get_hw_params(struct dai * dai,struct sof_ipc_stream_params * params,int dir)921 static int ssp_get_hw_params(struct dai *dai,
922 struct sof_ipc_stream_params *params, int dir)
923 {
924 struct ssp_pdata *ssp = dai_get_drvdata(dai);
925
926 params->rate = ssp->params.fsync_rate;
927 params->buffer_fmt = 0;
928
929 if (dir == SOF_IPC_STREAM_PLAYBACK)
930 params->channels = popcount(ssp->params.tx_slots);
931 else
932 params->channels = popcount(ssp->params.rx_slots);
933
934 switch (ssp->params.sample_valid_bits) {
935 case 16:
936 params->frame_fmt = SOF_IPC_FRAME_S16_LE;
937 break;
938 case 24:
939 params->frame_fmt = SOF_IPC_FRAME_S24_4LE;
940 break;
941 case 32:
942 params->frame_fmt = SOF_IPC_FRAME_S32_LE;
943 break;
944 default:
945 dai_err(dai, "ssp_get_hw_params(): not supported format");
946 return -EINVAL;
947 }
948
949 return 0;
950 }
951
952 /* start the SSP for either playback or capture */
ssp_start(struct dai * dai,int direction)953 static void ssp_start(struct dai *dai, int direction)
954 {
955 struct ssp_pdata *ssp = dai_get_drvdata(dai);
956
957 spin_lock(&dai->lock);
958
959 /* request mclk/bclk */
960 ssp_pre_start(dai);
961
962 if (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ)) {
963 /* enable TRSE/RSRE before SSE */
964 ssp_update_bits(dai, SSCR1,
965 SSCR1_TSRE | SSCR1_RSRE,
966 SSCR1_TSRE | SSCR1_RSRE);
967
968 /* enable port */
969 ssp_update_bits(dai, SSCR0, SSCR0_SSE, SSCR0_SSE);
970 dai_info(dai, "ssp_start(): SSE set for SSP%d", dai->index);
971 }
972 ssp->state[direction] = COMP_STATE_ACTIVE;
973
974 dai_info(dai, "ssp_start()");
975
976 if (ssp->params.bclk_delay) {
977 /* drive BCLK early for guaranteed time,
978 * before first FSYNC, it is required by some codecs
979 */
980 wait_delay(clock_ms_to_ticks(PLATFORM_DEFAULT_CLOCK,
981 ssp->params.bclk_delay));
982 }
983
984 /* enable DMA */
985 if (direction == DAI_DIR_PLAYBACK)
986 ssp_update_bits(dai, SSTSA, SSTSA_TXEN, SSTSA_TXEN);
987 else
988 ssp_update_bits(dai, SSRSA, SSRSA_RXEN, SSRSA_RXEN);
989
990 /*
991 * Wait to get valid fifo status in clock consumer mode. TODO it's
992 * uncertain which SSP clock consumer modes need the delay atm, but
993 * these can be added here when confirmed.
994 */
995 switch (ssp->config.format & SOF_DAI_FMT_CLOCK_PROVIDER_MASK) {
996 case SOF_DAI_FMT_CBC_CFC:
997 break;
998 default:
999 /* delay for all SSP consumed clocks atm - see above */
1000 wait_delay(PLATFORM_SSP_DELAY);
1001 break;
1002 }
1003
1004 spin_unlock(&dai->lock);
1005 }
1006
1007 /* stop the SSP for either playback or capture */
ssp_stop(struct dai * dai,int direction)1008 static void ssp_stop(struct dai *dai, int direction)
1009 {
1010 struct ssp_pdata *ssp = dai_get_drvdata(dai);
1011
1012 spin_lock(&dai->lock);
1013
1014 /*
1015 * Wait to get valid fifo status in clock consumer mode. TODO it's
1016 * uncertain which SSP clock consumer modes need the delay atm, but
1017 * these can be added here when confirmed.
1018 */
1019 switch (ssp->config.format & SOF_DAI_FMT_CLOCK_PROVIDER_MASK) {
1020 case SOF_DAI_FMT_CBC_CFC:
1021 break;
1022 default:
1023 /* delay for all SSP consumed clocks atm - see above */
1024 wait_delay(PLATFORM_SSP_DELAY);
1025 break;
1026 }
1027
1028 /* stop Rx if neeed */
1029 if (direction == DAI_DIR_CAPTURE &&
1030 ssp->state[SOF_IPC_STREAM_CAPTURE] != COMP_STATE_PREPARE) {
1031 ssp_update_bits(dai, SSRSA, SSRSA_RXEN, 0);
1032 ssp_empty_rx_fifo(dai);
1033 ssp->state[SOF_IPC_STREAM_CAPTURE] = COMP_STATE_PREPARE;
1034 dai_info(dai, "ssp_stop(), RX stop");
1035 }
1036
1037 /* stop Tx if needed */
1038 if (direction == DAI_DIR_PLAYBACK &&
1039 ssp->state[SOF_IPC_STREAM_PLAYBACK] != COMP_STATE_PREPARE) {
1040 ssp_empty_tx_fifo(dai);
1041 ssp_update_bits(dai, SSTSA, SSTSA_TXEN, 0);
1042 ssp->state[SOF_IPC_STREAM_PLAYBACK] = COMP_STATE_PREPARE;
1043 dai_info(dai, "ssp_stop(), TX stop");
1044 }
1045
1046 /* disable SSP port if no users */
1047 if (ssp->state[SOF_IPC_STREAM_CAPTURE] == COMP_STATE_PREPARE &&
1048 ssp->state[SOF_IPC_STREAM_PLAYBACK] == COMP_STATE_PREPARE) {
1049 if (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ)) {
1050 /* clear TRSE/RSRE before SSE */
1051 ssp_update_bits(dai, SSCR1,
1052 SSCR1_TSRE | SSCR1_RSRE,
1053 0);
1054
1055 ssp_update_bits(dai, SSCR0, SSCR0_SSE, 0);
1056 dai_info(dai, "ssp_stop(): SSE clear SSP%d", dai->index);
1057 }
1058 }
1059
1060 ssp_post_stop(dai);
1061
1062 spin_unlock(&dai->lock);
1063 }
1064
ssp_pause(struct dai * dai,int direction)1065 static void ssp_pause(struct dai *dai, int direction)
1066 {
1067 struct ssp_pdata *ssp = dai_get_drvdata(dai);
1068
1069 if (direction == SOF_IPC_STREAM_CAPTURE)
1070 dai_info(dai, "ssp_pause(), RX");
1071 else
1072 dai_info(dai, "ssp_pause(), TX");
1073
1074 ssp->state[direction] = COMP_STATE_PAUSED;
1075 }
1076
ssp_trigger(struct dai * dai,int cmd,int direction)1077 static int ssp_trigger(struct dai *dai, int cmd, int direction)
1078 {
1079 struct ssp_pdata *ssp = dai_get_drvdata(dai);
1080
1081 dai_info(dai, "ssp_trigger() cmd %d", cmd);
1082
1083 switch (cmd) {
1084 case COMP_TRIGGER_START:
1085 if (ssp->state[direction] == COMP_STATE_PREPARE ||
1086 ssp->state[direction] == COMP_STATE_PAUSED)
1087 ssp_start(dai, direction);
1088 break;
1089 case COMP_TRIGGER_RELEASE:
1090 if (ssp->state[direction] == COMP_STATE_PAUSED ||
1091 ssp->state[direction] == COMP_STATE_PREPARE)
1092 ssp_start(dai, direction);
1093 break;
1094 case COMP_TRIGGER_STOP:
1095 ssp_stop(dai, direction);
1096 break;
1097 case COMP_TRIGGER_PAUSE:
1098 ssp_pause(dai, direction);
1099 break;
1100 case COMP_TRIGGER_RESUME:
1101 ssp_context_restore(dai);
1102 break;
1103 case COMP_TRIGGER_SUSPEND:
1104 ssp_context_store(dai);
1105 break;
1106 default:
1107 break;
1108 }
1109
1110 return 0;
1111 }
1112
ssp_probe(struct dai * dai)1113 static int ssp_probe(struct dai *dai)
1114 {
1115 struct ssp_pdata *ssp;
1116
1117 if (dai_get_drvdata(dai))
1118 return -EEXIST; /* already created */
1119
1120 /* allocate private data */
1121 ssp = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*ssp));
1122 if (!ssp) {
1123 dai_err(dai, "ssp_probe(): alloc failed");
1124 return -ENOMEM;
1125 }
1126 dai_set_drvdata(dai, ssp);
1127
1128 ssp->state[DAI_DIR_PLAYBACK] = COMP_STATE_READY;
1129 ssp->state[DAI_DIR_CAPTURE] = COMP_STATE_READY;
1130
1131 #if CONFIG_INTEL_MN
1132 /* Reset M/N, power-gating functions need it */
1133 mn_reset_bclk_divider(dai->index);
1134 #endif
1135
1136 /* Enable SSP power */
1137 pm_runtime_get_sync(SSP_POW, dai->index);
1138
1139 /* Disable dynamic clock gating before touching any register */
1140 pm_runtime_get_sync(SSP_CLK, dai->index);
1141
1142 ssp_empty_rx_fifo(dai);
1143
1144 return 0;
1145 }
1146
ssp_remove(struct dai * dai)1147 static int ssp_remove(struct dai *dai)
1148 {
1149 pm_runtime_put_sync(SSP_CLK, dai->index);
1150
1151 ssp_mclk_disable_unprepare(dai);
1152 ssp_bclk_disable_unprepare(dai);
1153
1154 /* Disable SSP power */
1155 pm_runtime_put_sync(SSP_POW, dai->index);
1156
1157 rfree(dai_get_drvdata(dai));
1158 dai_set_drvdata(dai, NULL);
1159
1160 return 0;
1161 }
1162
ssp_get_handshake(struct dai * dai,int direction,int stream_id)1163 static int ssp_get_handshake(struct dai *dai, int direction, int stream_id)
1164 {
1165 return dai->plat_data.fifo[direction].handshake;
1166 }
1167
ssp_get_fifo(struct dai * dai,int direction,int stream_id)1168 static int ssp_get_fifo(struct dai *dai, int direction, int stream_id)
1169 {
1170 return dai->plat_data.fifo[direction].offset;
1171 }
1172
1173 const struct dai_driver ssp_driver = {
1174 .type = SOF_DAI_INTEL_SSP,
1175 .uid = SOF_UUID(ssp_uuid),
1176 .tctx = &ssp_tr,
1177 .dma_caps = DMA_CAP_GP_LP | DMA_CAP_GP_HP,
1178 .dma_dev = DMA_DEV_SSP,
1179 .ops = {
1180 .trigger = ssp_trigger,
1181 .set_config = ssp_set_config,
1182 .pm_context_store = ssp_context_store,
1183 .pm_context_restore = ssp_context_restore,
1184 .get_hw_params = ssp_get_hw_params,
1185 .get_handshake = ssp_get_handshake,
1186 .get_fifo = ssp_get_fifo,
1187 .probe = ssp_probe,
1188 .remove = ssp_remove,
1189 },
1190 .ts_ops = {
1191 .ts_config = timestamp_ssp_config,
1192 .ts_start = timestamp_ssp_start,
1193 .ts_get = timestamp_ssp_get,
1194 .ts_stop = timestamp_ssp_stop,
1195 },
1196 };
1197