diff options
-rw-r--r-- | sound/soc/fsl/fsl_ssi.c | 122 |
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 | ||
134 | struct fsl_ssi_reg_val { | ||
135 | u32 sier; | ||
136 | u32 srcr; | ||
137 | u32 stcr; | ||
138 | u32 scr; | ||
139 | }; | ||
140 | |||
141 | struct 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 | */ | ||
482 | static 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 | */ | ||
503 | static 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 | |||
570 | config_done: | ||
571 | /* Enabling of subunits is done after configuration */ | ||
572 | if (enable) | ||
573 | write_ssi_mask(&ssi->scr, 0, vals->scr); | ||
574 | } | ||
575 | |||
576 | |||
577 | static 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 | |||
582 | static 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 | |||
465 | static void fsl_ssi_setup_ac97(struct fsl_ssi_private *ssi_private) | 587 | static 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; |