diff options
| author | Markus Pargmann <mpa@pengutronix.de> | 2013-12-20 08:11:33 -0500 |
|---|---|---|
| committer | Mark Brown <broonie@linaro.org> | 2014-01-08 12:20:32 -0500 |
| commit | 4e6ec0d98c045cb2c0c6550c65c4afae208872e9 (patch) | |
| tree | 02c270d6090a20f6329aa8c8a8054c57ef811ecc | |
| parent | bd3ca7d1b8ee0dcd502c8c15d1cf741bc165722f (diff) | |
ASoC: fsl-ssi: Add configuration helper functions
This patch adds a struct 'fsl_ssi_rxtx_reg_val' which holds register
values necessary to enable rx/tx. Based on those preset register values,
the added configuration functions will cleanly enable/disable different
parts of the SSI IP while supporting online/offline configuration.
Different operating modes can be setup directly as different register
values in fsl_ssi_reg_val.
These functions and structs will help to cleanup and simplify the
trigger function to support many different IP versions (online/offline
configuration) and different operating modes.
Signed-off-by: Markus Pargmann <mpa@pengutronix.de>
Signed-off-by: Mark Brown <broonie@linaro.org>
| -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; |
