|
@@ -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.
|
|
@@ -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 */
|
|
@@ -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);
|
|
|
}
|
|
|
|
|
@@ -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;
|
|
@@ -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);
|