Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ASoC: atmel_ssc_dai: enable fslen extension feature

When SSC work as master, it will generate the frame sync signal.
On old SoCs, it only supports frame sync length less or equal to
16bits, on newer SoCs, it supports frame sync length extension,
which can support frame size larger than 16 bits.
So, add this to make it supports playback 24/32 bits audio clips.

Signed-off-by: Bo Shen <voice.shen@atmel.com>
Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Signed-off-by: Mark Brown <broonie@linaro.org>

authored by

Bo Shen and committed by
Mark Brown
dfaf5356 c4027faf

+30 -16
+12
include/linux/atmel-ssc.h
··· 72 72 #define SSC_RFMR_DATNB_OFFSET 8 73 73 #define SSC_RFMR_FSEDGE_SIZE 1 74 74 #define SSC_RFMR_FSEDGE_OFFSET 24 75 + /* 76 + * The FSLEN_EXT exist on at91sam9rl, at91sam9g10, 77 + * at91sam9g20, and at91sam9g45 and newer SoCs 78 + */ 79 + #define SSC_RFMR_FSLEN_EXT_SIZE 4 80 + #define SSC_RFMR_FSLEN_EXT_OFFSET 28 75 81 #define SSC_RFMR_FSLEN_SIZE 4 76 82 #define SSC_RFMR_FSLEN_OFFSET 16 77 83 #define SSC_RFMR_FSOS_SIZE 4 ··· 116 110 #define SSC_TFMR_FSDEN_OFFSET 23 117 111 #define SSC_TFMR_FSEDGE_SIZE 1 118 112 #define SSC_TFMR_FSEDGE_OFFSET 24 113 + /* 114 + * The FSLEN_EXT exist on at91sam9rl, at91sam9g10, 115 + * at91sam9g20, and at91sam9g45 and newer SoCs 116 + */ 117 + #define SSC_TFMR_FSLEN_EXT_SIZE 4 118 + #define SSC_TFMR_FSLEN_EXT_OFFSET 28 119 119 #define SSC_TFMR_FSLEN_SIZE 4 120 120 #define SSC_TFMR_FSLEN_OFFSET 16 121 121 #define SSC_TFMR_FSOS_SIZE 3
+18 -16
sound/soc/atmel/atmel_ssc_dai.c
··· 347 347 u32 tfmr, rfmr, tcmr, rcmr; 348 348 int start_event; 349 349 int ret; 350 + int fslen, fslen_ext; 350 351 351 352 /* 352 353 * Currently, there is only one set of dma params for ··· 389 388 } 390 389 391 390 /* 392 - * The SSC only supports up to 16-bit samples in I2S format, due 393 - * to the size of the Frame Mode Register FSLEN field. 394 - */ 395 - if ((ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S 396 - && bits > 16) { 397 - printk(KERN_WARNING 398 - "atmel_ssc_dai: sample size %d " 399 - "is too large for I2S\n", bits); 400 - return -EINVAL; 401 - } 402 - 403 - /* 404 391 * Compute SSC register settings. 405 392 */ 406 393 switch (ssc_p->daifmt ··· 402 413 * from the MCK divider, and the BCLK signal 403 414 * is output on the SSC TK line. 404 415 */ 416 + 417 + if (bits > 16 && !ssc->pdata->has_fslen_ext) { 418 + dev_err(dai->dev, 419 + "sample size %d is too large for SSC device\n", 420 + bits); 421 + return -EINVAL; 422 + } 423 + 424 + fslen_ext = (bits - 1) / 16; 425 + fslen = (bits - 1) % 16; 426 + 405 427 rcmr = SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) 406 428 | SSC_BF(RCMR_STTDLY, START_DELAY) 407 429 | SSC_BF(RCMR_START, SSC_START_FALLING_RF) ··· 420 420 | SSC_BF(RCMR_CKO, SSC_CKO_NONE) 421 421 | SSC_BF(RCMR_CKS, SSC_CKS_DIV); 422 422 423 - rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) 423 + rfmr = SSC_BF(RFMR_FSLEN_EXT, fslen_ext) 424 + | SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) 424 425 | SSC_BF(RFMR_FSOS, SSC_FSOS_NEGATIVE) 425 - | SSC_BF(RFMR_FSLEN, (bits - 1)) 426 + | SSC_BF(RFMR_FSLEN, fslen) 426 427 | SSC_BF(RFMR_DATNB, (channels - 1)) 427 428 | SSC_BIT(RFMR_MSBF) 428 429 | SSC_BF(RFMR_LOOP, 0) ··· 436 435 | SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) 437 436 | SSC_BF(TCMR_CKS, SSC_CKS_DIV); 438 437 439 - tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) 438 + tfmr = SSC_BF(TFMR_FSLEN_EXT, fslen_ext) 439 + | SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) 440 440 | SSC_BF(TFMR_FSDEN, 0) 441 441 | SSC_BF(TFMR_FSOS, SSC_FSOS_NEGATIVE) 442 - | SSC_BF(TFMR_FSLEN, (bits - 1)) 442 + | SSC_BF(TFMR_FSLEN, fslen) 443 443 | SSC_BF(TFMR_DATNB, (channels - 1)) 444 444 | SSC_BIT(TFMR_MSBF) 445 445 | SSC_BF(TFMR_DATDEF, 0)