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>
This commit is contained in:
Markus Pargmann 2013-12-20 14:11:33 +01:00 committed by Mark Brown
parent bd3ca7d1b8
commit 4e6ec0d98c

View file

@ -131,6 +131,18 @@ enum fsl_ssi_type {
FSL_SSI_MX51,
};
struct fsl_ssi_reg_val {
u32 sier;
u32 srcr;
u32 stcr;
u32 scr;
};
struct fsl_ssi_rxtx_reg_val {
struct fsl_ssi_reg_val rx;
struct fsl_ssi_reg_val tx;
};
/**
* fsl_ssi_private: per-SSI private data
*
@ -169,6 +181,8 @@ struct fsl_ssi_private {
struct imx_dma_data filter_data_tx;
struct imx_dma_data filter_data_rx;
struct imx_pcm_fiq_params fiq_params;
/* Register values for rx/tx configuration */
struct fsl_ssi_rxtx_reg_val rxtx_reg_val;
struct {
unsigned int rfrc;
@ -462,6 +476,114 @@ static void fsl_ssi_debugfs_remove(struct fsl_ssi_private *ssi_private)
#endif /* IS_ENABLED(CONFIG_DEBUG_FS) */
/*
* Enable/Disable all rx/tx config flags at once.
*/
static void fsl_ssi_rxtx_config(struct fsl_ssi_private *ssi_private,
bool enable)
{
struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
struct fsl_ssi_rxtx_reg_val *vals = &ssi_private->rxtx_reg_val;
if (enable) {
write_ssi_mask(&ssi->sier, 0, vals->rx.sier | vals->tx.sier);
write_ssi_mask(&ssi->srcr, 0, vals->rx.srcr | vals->tx.srcr);
write_ssi_mask(&ssi->stcr, 0, vals->rx.stcr | vals->tx.stcr);
} else {
write_ssi_mask(&ssi->srcr, vals->rx.srcr | vals->tx.srcr, 0);
write_ssi_mask(&ssi->stcr, vals->rx.stcr | vals->tx.stcr, 0);
write_ssi_mask(&ssi->sier, vals->rx.sier | vals->tx.sier, 0);
}
}
/*
* Enable/Disable a ssi configuration. You have to pass either
* ssi_private->rxtx_reg_val.rx or tx as vals parameter.
*/
static void fsl_ssi_config(struct fsl_ssi_private *ssi_private, bool enable,
struct fsl_ssi_reg_val *vals)
{
struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
struct fsl_ssi_reg_val *avals;
u32 scr_val = read_ssi(&ssi->scr);
int nr_active_streams = !!(scr_val & CCSR_SSI_SCR_TE) +
!!(scr_val & CCSR_SSI_SCR_RE);
/* Find the other direction values rx or tx which we do not want to
* modify */
if (&ssi_private->rxtx_reg_val.rx == vals)
avals = &ssi_private->rxtx_reg_val.tx;
else
avals = &ssi_private->rxtx_reg_val.rx;
/* If vals should be disabled, start with disabling the unit */
if (!enable) {
u32 scr = vals->scr & (vals->scr ^ avals->scr);
write_ssi_mask(&ssi->scr, scr, 0);
}
/*
* We are running on a SoC which does not support online SSI
* reconfiguration, so we have to enable all necessary flags at once
* even if we do not use them later (capture and playback configuration)
*/
if (ssi_private->offline_config) {
if ((enable && !nr_active_streams) ||
(!enable && nr_active_streams == 1))
fsl_ssi_rxtx_config(ssi_private, enable);
goto config_done;
}
/*
* Configure single direction units while the SSI unit is running
* (online configuration)
*/
if (enable) {
write_ssi_mask(&ssi->sier, 0, vals->sier);
write_ssi_mask(&ssi->srcr, 0, vals->srcr);
write_ssi_mask(&ssi->stcr, 0, vals->stcr);
} else {
u32 sier;
u32 srcr;
u32 stcr;
/*
* Disabling the necessary flags for one of rx/tx while the
* other stream is active is a little bit more difficult. We
* have to disable only those flags that differ between both
* streams (rx XOR tx) and that are set in the stream that is
* disabled now. Otherwise we could alter flags of the other
* stream
*/
/* These assignments are simply vals without bits set in avals*/
sier = vals->sier & (vals->sier ^ avals->sier);
srcr = vals->srcr & (vals->srcr ^ avals->srcr);
stcr = vals->stcr & (vals->stcr ^ avals->stcr);
write_ssi_mask(&ssi->srcr, srcr, 0);
write_ssi_mask(&ssi->stcr, stcr, 0);
write_ssi_mask(&ssi->sier, sier, 0);
}
config_done:
/* Enabling of subunits is done after configuration */
if (enable)
write_ssi_mask(&ssi->scr, 0, vals->scr);
}
static void fsl_ssi_rx_config(struct fsl_ssi_private *ssi_private, bool enable)
{
fsl_ssi_config(ssi_private, enable, &ssi_private->rxtx_reg_val.rx);
}
static void fsl_ssi_tx_config(struct fsl_ssi_private *ssi_private, bool enable)
{
fsl_ssi_config(ssi_private, enable, &ssi_private->rxtx_reg_val.tx);
}
static void fsl_ssi_setup_ac97(struct fsl_ssi_private *ssi_private)
{
struct ccsr_ssi __iomem *ssi = ssi_private->ssi;