apl-ssp: fix capture double speed issue

Previously TFT and RFT are set to 0s which means we are using
threshold level 1, where interrupt asserts for every valid bits
of each slot(e.g. for s16_le capture, interrupts assert for
each 16 bits), but DMAC will treat it as notification of one
full sample(e.g. 32 bits for s16_le stereo) and read those all
bits, this will lead to capture with double speed at format
s16_le stereo.

Here add handle for FIFO trigger Threshold level, set them to
bytes for each full sample(active_slots * valid_bits / 8), and
the issue is fixed.

Signed-off-by: Keyon Jie <yang.jie@linux.intel.com>
This commit is contained in:
Keyon Jie 2018-03-15 20:01:09 +08:00 committed by Liam Girdwood
parent ced518efdb
commit cc54f1313d
1 changed files with 45 additions and 0 deletions

View File

@ -43,6 +43,19 @@
#define trace_ssp_error(__e) trace_error(TRACE_CLASS_SSP, __e)
#define tracev_ssp(__e) tracev_event(TRACE_CLASS_SSP, __e)
/* FIXME: move this to a helper and optimize */
static int hweight_32(uint32_t mask)
{
int i;
int count = 0;
for (i = 0; i < 32; i++) {
count += mask & 1;
mask >>= 1;
}
return count;
}
/* save SSP context prior to entering D3 */
static int ssp_context_store(struct dai *dai)
{
@ -96,6 +109,11 @@ static inline int ssp_set_config(struct dai *dai,
uint32_t dummy_stop;
uint32_t frame_len = 0;
uint32_t bdiv_min;
uint32_t tft;
uint32_t rft;
uint32_t active_tx_slots = 2;
uint32_t active_rx_slots = 2;
bool inverted_frame = false;
int ret = 0;
@ -353,6 +371,9 @@ static inline int ssp_set_config(struct dai *dai,
sspsp |= SSPSP_SFRMP(!inverted_frame);
sspsp |= SSPSP_FSRT;
active_tx_slots = hweight_32(config->tx_slot_mask);
active_rx_slots = hweight_32(config->rx_slot_mask);
break;
case SOF_DAI_FMT_DSP_B:
@ -371,6 +392,9 @@ static inline int ssp_set_config(struct dai *dai,
*/
sspsp |= SSPSP_SFRMP(!inverted_frame);
active_tx_slots = hweight_32(config->tx_slot_mask);
active_rx_slots = hweight_32(config->rx_slot_mask);
break;
default:
trace_ssp_error("eca");
@ -408,6 +432,27 @@ static inline int ssp_set_config(struct dai *dai,
/* bypass divider for MCLK */
mdivr = 0x00000fff;
/* setting TFT and RFT */
switch (config->sample_valid_bits) {
case 16:
/* use 2 bytes for each slot */
tft = active_tx_slots * 2;
rft = active_rx_slots * 2;
break;
case 24:
case 32:
/* use 4 bytes for each slot */
tft = active_tx_slots * 4;
rft = active_rx_slots * 4;
break;
default:
trace_ssp_error("ecd");
ret = -EINVAL;
goto out;
}
sscr3 |= SSCR3_TX(tft) | SSCR3_RX(rft);
trace_ssp("coe");
ssp_write(dai, SSCR0, sscr0);
ssp_write(dai, SSCR1, sscr1);