Skip to content

Commit

Permalink
ASoC: fsl-ssi: Fix register values when disabling
Browse files Browse the repository at this point in the history
The bits we have to clear when disabling are different when the other
stream is still active.

This patch fixes the calculation of new register values after disabling
one stream. It also adds a more detailed description of the new register
value calculation.

Signed-off-by: Markus Pargmann <mpa@pengutronix.de>
Tested-By: Michael Grzeschik <mgr@pengutronix.de>
Signed-off-by: Mark Brown <broonie@linaro.org>
  • Loading branch information
Markus Pargmann authored and Mark Brown committed May 20, 2014
1 parent 07a28db commit 65c961c
Showing 1 changed file with 35 additions and 5 deletions.
40 changes: 35 additions & 5 deletions sound/soc/fsl/fsl_ssi.c
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,26 @@ static void fsl_ssi_rxtx_config(struct fsl_ssi_private *ssi_private,
}
}

/*
* Calculate the bits that have to be disabled for the current stream that is
* getting disabled. This keeps the bits enabled that are necessary for the
* second stream to work if 'stream_active' is true.
*
* Detailed calculation:
* These are the values that need to be active after disabling. For non-active
* second stream, this is 0:
* vals_stream * !!stream_active
*
* The following computes the overall differences between the setup for the
* to-disable stream and the active stream, a simple XOR:
* vals_disable ^ (vals_stream * !!(stream_active))
*
* The full expression adds a mask on all values we care about
*/
#define fsl_ssi_disable_val(vals_disable, vals_stream, stream_active) \
((vals_disable) & \
((vals_disable) ^ ((vals_stream) * (u32)!!(stream_active))))

/*
* Enable/Disable a ssi configuration. You have to pass either
* ssi_private->rxtx_reg_val.rx or tx as vals parameter.
Expand All @@ -501,6 +521,12 @@ static void fsl_ssi_config(struct fsl_ssi_private *ssi_private, bool enable,
u32 scr_val = read_ssi(&ssi->scr);
int nr_active_streams = !!(scr_val & CCSR_SSI_SCR_TE) +
!!(scr_val & CCSR_SSI_SCR_RE);
int keep_active;

if (nr_active_streams - 1 > 0)
keep_active = 1;
else
keep_active = 0;

/* Find the other direction values rx or tx which we do not want to
* modify */
Expand All @@ -511,7 +537,8 @@ static void fsl_ssi_config(struct fsl_ssi_private *ssi_private, bool enable,

/* If vals should be disabled, start with disabling the unit */
if (!enable) {
u32 scr = vals->scr & (vals->scr ^ avals->scr);
u32 scr = fsl_ssi_disable_val(vals->scr, avals->scr,
keep_active);
write_ssi_mask(&ssi->scr, scr, 0);
}

Expand All @@ -522,7 +549,7 @@ static void fsl_ssi_config(struct fsl_ssi_private *ssi_private, bool enable,
*/
if (ssi_private->offline_config) {
if ((enable && !nr_active_streams) ||
(!enable && nr_active_streams == 1))
(!enable && !keep_active))
fsl_ssi_rxtx_config(ssi_private, enable);

goto config_done;
Expand Down Expand Up @@ -551,9 +578,12 @@ static void fsl_ssi_config(struct fsl_ssi_private *ssi_private, bool enable,
*/

/* 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);
sier = fsl_ssi_disable_val(vals->sier, avals->sier,
keep_active);
srcr = fsl_ssi_disable_val(vals->srcr, avals->srcr,
keep_active);
stcr = fsl_ssi_disable_val(vals->stcr, avals->stcr,
keep_active);

write_ssi_mask(&ssi->srcr, srcr, 0);
write_ssi_mask(&ssi->stcr, stcr, 0);
Expand Down

0 comments on commit 65c961c

Please sign in to comment.