ASoC: xlnx: parse AES audio parameters

AES channel status carries various audio parameters. If channel status is
detected, current patch extracts sample rate and bit depth parameters of
the incoming stream during capture.

Signed-off-by: Maruthi Srinivas Bayyavarapu <maruthi.srinivas.bayyavarapu@xilinx.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Maruthi Srinivas Bayyavarapu 2019-01-10 18:44:43 +05:30 committed by Mark Brown
parent 5b86fa6d29
commit c284d4e31a
No known key found for this signature in database
GPG key ID: 24D68B725D5487D0

View file

@ -13,6 +13,7 @@
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/sizes.h> #include <linux/sizes.h>
#include <sound/asoundef.h>
#include <sound/soc.h> #include <sound/soc.h>
#include <sound/pcm_params.h> #include <sound/pcm_params.h>
@ -63,6 +64,7 @@
#define PERIODS_MAX 6 #define PERIODS_MAX 6
#define PERIOD_BYTES_MIN 192 #define PERIOD_BYTES_MIN 192
#define PERIOD_BYTES_MAX (50 * 1024) #define PERIOD_BYTES_MAX (50 * 1024)
#define XLNX_PARAM_UNKNOWN 0
enum bit_depth { enum bit_depth {
BIT_DEPTH_8, BIT_DEPTH_8,
@ -117,6 +119,129 @@ static const struct snd_pcm_hardware xlnx_pcm_hardware = {
.periods_max = PERIODS_MAX, .periods_max = PERIODS_MAX,
}; };
enum {
AES_TO_AES,
AES_TO_PCM,
PCM_TO_PCM,
PCM_TO_AES
};
static void xlnx_parse_aes_params(u32 chsts_reg1_val, u32 chsts_reg2_val,
struct device *dev)
{
u32 padded, srate, bit_depth, status[2];
if (chsts_reg1_val & IEC958_AES0_PROFESSIONAL) {
status[0] = chsts_reg1_val & 0xff;
status[1] = (chsts_reg1_val >> 16) & 0xff;
switch (status[0] & IEC958_AES0_PRO_FS) {
case IEC958_AES0_PRO_FS_44100:
srate = 44100;
break;
case IEC958_AES0_PRO_FS_48000:
srate = 48000;
break;
case IEC958_AES0_PRO_FS_32000:
srate = 32000;
break;
case IEC958_AES0_PRO_FS_NOTID:
default:
srate = XLNX_PARAM_UNKNOWN;
break;
}
switch (status[1] & IEC958_AES2_PRO_SBITS) {
case IEC958_AES2_PRO_WORDLEN_NOTID:
case IEC958_AES2_PRO_SBITS_20:
padded = 0;
break;
case IEC958_AES2_PRO_SBITS_24:
padded = 4;
break;
default:
bit_depth = XLNX_PARAM_UNKNOWN;
goto log_params;
}
switch (status[1] & IEC958_AES2_PRO_WORDLEN) {
case IEC958_AES2_PRO_WORDLEN_20_16:
bit_depth = 16 + padded;
break;
case IEC958_AES2_PRO_WORDLEN_22_18:
bit_depth = 18 + padded;
break;
case IEC958_AES2_PRO_WORDLEN_23_19:
bit_depth = 19 + padded;
break;
case IEC958_AES2_PRO_WORDLEN_24_20:
bit_depth = 20 + padded;
break;
case IEC958_AES2_PRO_WORDLEN_NOTID:
default:
bit_depth = XLNX_PARAM_UNKNOWN;
break;
}
} else {
status[0] = (chsts_reg1_val >> 24) & 0xff;
status[1] = chsts_reg2_val & 0xff;
switch (status[0] & IEC958_AES3_CON_FS) {
case IEC958_AES3_CON_FS_44100:
srate = 44100;
break;
case IEC958_AES3_CON_FS_48000:
srate = 48000;
break;
case IEC958_AES3_CON_FS_32000:
srate = 32000;
break;
default:
srate = XLNX_PARAM_UNKNOWN;
break;
}
if (status[1] & IEC958_AES4_CON_MAX_WORDLEN_24)
padded = 4;
else
padded = 0;
switch (status[1] & IEC958_AES4_CON_WORDLEN) {
case IEC958_AES4_CON_WORDLEN_20_16:
bit_depth = 16 + padded;
break;
case IEC958_AES4_CON_WORDLEN_22_18:
bit_depth = 18 + padded;
break;
case IEC958_AES4_CON_WORDLEN_23_19:
bit_depth = 19 + padded;
break;
case IEC958_AES4_CON_WORDLEN_24_20:
bit_depth = 20 + padded;
break;
case IEC958_AES4_CON_WORDLEN_21_17:
bit_depth = 17 + padded;
break;
case IEC958_AES4_CON_WORDLEN_NOTID:
default:
bit_depth = XLNX_PARAM_UNKNOWN;
break;
}
}
log_params:
if (srate != XLNX_PARAM_UNKNOWN)
dev_info(dev, "sample rate = %d\n", srate);
else
dev_info(dev, "sample rate = unknown\n");
if (bit_depth != XLNX_PARAM_UNKNOWN)
dev_info(dev, "bit_depth = %d\n", bit_depth);
else
dev_info(dev, "bit_depth = unknown\n");
}
static int xlnx_formatter_pcm_reset(void __iomem *mmio_base) static int xlnx_formatter_pcm_reset(void __iomem *mmio_base)
{ {
u32 val, retries = 0; u32 val, retries = 0;
@ -302,8 +427,12 @@ static int xlnx_formatter_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params) struct snd_pcm_hw_params *params)
{ {
u32 low, high, active_ch, val, bytes_per_ch, bits_per_sample; u32 low, high, active_ch, val, bytes_per_ch, bits_per_sample;
u32 aes_reg1_val, aes_reg2_val;
int status; int status;
u64 size; u64 size;
struct snd_soc_pcm_runtime *prtd = substream->private_data;
struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd,
DRV_NAME);
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
struct xlnx_pcm_stream_param *stream_data = runtime->private_data; struct xlnx_pcm_stream_param *stream_data = runtime->private_data;
@ -311,6 +440,20 @@ static int xlnx_formatter_pcm_hw_params(struct snd_pcm_substream *substream,
if (active_ch > stream_data->ch_limit) if (active_ch > stream_data->ch_limit)
return -EINVAL; return -EINVAL;
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
stream_data->xfer_mode == AES_TO_PCM) {
val = readl(stream_data->mmio + XLNX_AUD_STS);
if (val & AUD_STS_CH_STS_MASK) {
aes_reg1_val = readl(stream_data->mmio +
XLNX_AUD_CH_STS_START);
aes_reg2_val = readl(stream_data->mmio +
XLNX_AUD_CH_STS_START + 0x4);
xlnx_parse_aes_params(aes_reg1_val, aes_reg2_val,
component->dev);
}
}
size = params_buffer_bytes(params); size = params_buffer_bytes(params);
status = snd_pcm_lib_malloc_pages(substream, size); status = snd_pcm_lib_malloc_pages(substream, size);
if (status < 0) if (status < 0)