aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/soc/fsl/fsl_ssi.c122
1 files changed, 122 insertions, 0 deletions
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index d0b9fe31f49a..a85268bb4507 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -131,6 +131,18 @@ enum fsl_ssi_type {
131 FSL_SSI_MX51, 131 FSL_SSI_MX51,
132}; 132};
133 133
134struct fsl_ssi_reg_val {
135 u32 sier;
136 u32 srcr;
137 u32 stcr;
138 u32 scr;
139};
140
141struct fsl_ssi_rxtx_reg_val {
142 struct fsl_ssi_reg_val rx;
143 struct fsl_ssi_reg_val tx;
144};
145
134/** 146/**
135 * fsl_ssi_private: per-SSI private data 147 * fsl_ssi_private: per-SSI private data
136 * 148 *
@@ -169,6 +181,8 @@ struct fsl_ssi_private {
169 struct imx_dma_data filter_data_tx; 181 struct imx_dma_data filter_data_tx;
170 struct imx_dma_data filter_data_rx; 182 struct imx_dma_data filter_data_rx;
171 struct imx_pcm_fiq_params fiq_params; 183 struct imx_pcm_fiq_params fiq_params;
184 /* Register values for rx/tx configuration */
185 struct fsl_ssi_rxtx_reg_val rxtx_reg_val;
172 186
173 struct { 187 struct {
174 unsigned int rfrc; 188 unsigned int rfrc;
@@ -462,6 +476,114 @@ static void fsl_ssi_debugfs_remove(struct fsl_ssi_private *ssi_private)
462 476
463#endif /* IS_ENABLED(CONFIG_DEBUG_FS) */ 477#endif /* IS_ENABLED(CONFIG_DEBUG_FS) */
464 478
479/*
480 * Enable/Disable all rx/tx config flags at once.
481 */
482static void fsl_ssi_rxtx_config(struct fsl_ssi_private *ssi_private,
483 bool enable)
484{
485 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
486 struct fsl_ssi_rxtx_reg_val *vals = &ssi_private->rxtx_reg_val;
487
488 if (enable) {
489 write_ssi_mask(&ssi->sier, 0, vals->rx.sier | vals->tx.sier);
490 write_ssi_mask(&ssi->srcr, 0, vals->rx.srcr | vals->tx.srcr);
491 write_ssi_mask(&ssi->stcr, 0, vals->rx.stcr | vals->tx.stcr);
492 } else {
493 write_ssi_mask(&ssi->srcr, vals->rx.srcr | vals->tx.srcr, 0);
494 write_ssi_mask(&ssi->stcr, vals->rx.stcr | vals->tx.stcr, 0);
495 write_ssi_mask(&ssi->sier, vals->rx.sier | vals->tx.sier, 0);
496 }
497}
498
499/*
500 * Enable/Disable a ssi configuration. You have to pass either
501 * ssi_private->rxtx_reg_val.rx or tx as vals parameter.
502 */
503static void fsl_ssi_config(struct fsl_ssi_private *ssi_private, bool enable,
504 struct fsl_ssi_reg_val *vals)
505{
506 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
507 struct fsl_ssi_reg_val *avals;
508 u32 scr_val = read_ssi(&ssi->scr);
509 int nr_active_streams = !!(scr_val & CCSR_SSI_SCR_TE) +
510 !!(scr_val & CCSR_SSI_SCR_RE);
511
512 /* Find the other direction values rx or tx which we do not want to
513 * modify */
514 if (&ssi_private->rxtx_reg_val.rx == vals)
515 avals = &ssi_private->rxtx_reg_val.tx;
516 else
517 avals = &ssi_private->rxtx_reg_val.rx;
518
519 /* If vals should be disabled, start with disabling the unit */
520 if (!enable) {
521 u32 scr = vals->scr & (vals->scr ^ avals->scr);
522 write_ssi_mask(&ssi->scr, scr, 0);
523 }
524
525 /*
526 * We are running on a SoC which does not support online SSI
527 * reconfiguration, so we have to enable all necessary flags at once
528 * even if we do not use them later (capture and playback configuration)
529 */
530 if (ssi_private->offline_config) {
531 if ((enable && !nr_active_streams) ||
532 (!enable && nr_active_streams == 1))
533 fsl_ssi_rxtx_config(ssi_private, enable);
534
535 goto config_done;
536 }
537
538 /*
539 * Configure single direction units while the SSI unit is running
540 * (online configuration)
541 */
542 if (enable) {
543 write_ssi_mask(&ssi->sier, 0, vals->sier);
544 write_ssi_mask(&ssi->srcr, 0, vals->srcr);
545 write_ssi_mask(&ssi->stcr, 0, vals->stcr);
546 } else {
547 u32 sier;
548 u32 srcr;
549 u32 stcr;
550
551 /*
552 * Disabling the necessary flags for one of rx/tx while the
553 * other stream is active is a little bit more difficult. We
554 * have to disable only those flags that differ between both
555 * streams (rx XOR tx) and that are set in the stream that is
556 * disabled now. Otherwise we could alter flags of the other
557 * stream
558 */
559
560 /* These assignments are simply vals without bits set in avals*/
561 sier = vals->sier & (vals->sier ^ avals->sier);
562 srcr = vals->srcr & (vals->srcr ^ avals->srcr);
563 stcr = vals->stcr & (vals->stcr ^ avals->stcr);
564
565 write_ssi_mask(&ssi->srcr, srcr, 0);
566 write_ssi_mask(&ssi->stcr, stcr, 0);
567 write_ssi_mask(&ssi->sier, sier, 0);
568 }
569
570config_done:
571 /* Enabling of subunits is done after configuration */
572 if (enable)
573 write_ssi_mask(&ssi->scr, 0, vals->scr);
574}
575
576
577static void fsl_ssi_rx_config(struct fsl_ssi_private *ssi_private, bool enable)
578{
579 fsl_ssi_config(ssi_private, enable, &ssi_private->rxtx_reg_val.rx);
580}
581
582static void fsl_ssi_tx_config(struct fsl_ssi_private *ssi_private, bool enable)
583{
584 fsl_ssi_config(ssi_private, enable, &ssi_private->rxtx_reg_val.tx);
585}
586
465static void fsl_ssi_setup_ac97(struct fsl_ssi_private *ssi_private) 587static void fsl_ssi_setup_ac97(struct fsl_ssi_private *ssi_private)
466{ 588{
467 struct ccsr_ssi __iomem *ssi = ssi_private->ssi; 589 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;