summaryrefslogtreecommitdiffstats
path: root/sound/soc
diff options
context:
space:
mode:
authorMaruthi Srinivas Bayyavarapu <maruthi.srinivas.bayyavarapu@xilinx.com>2019-01-10 18:44:43 +0530
committerMark Brown <broonie@kernel.org>2019-01-14 22:16:10 +0000
commitc284d4e31a0b66e6fe3734b36080afd237ff9fb0 (patch)
tree659fe685b10db0269cc29595381e732522fcc1a0 /sound/soc
parent5b86fa6d2903c41c3c3dbff4def76a5b8bbe0660 (diff)
downloadlinux-c284d4e31a0b66e6fe3734b36080afd237ff9fb0.tar.bz2
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>
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/xilinx/xlnx_formatter_pcm.c143
1 files changed, 143 insertions, 0 deletions
diff --git a/sound/soc/xilinx/xlnx_formatter_pcm.c b/sound/soc/xilinx/xlnx_formatter_pcm.c
index d2194da928e7..97177d35652e 100644
--- a/sound/soc/xilinx/xlnx_formatter_pcm.c
+++ b/sound/soc/xilinx/xlnx_formatter_pcm.c
@@ -13,6 +13,7 @@
#include <linux/of_irq.h>
#include <linux/sizes.h>
+#include <sound/asoundef.h>
#include <sound/soc.h>
#include <sound/pcm_params.h>
@@ -63,6 +64,7 @@
#define PERIODS_MAX 6
#define PERIOD_BYTES_MIN 192
#define PERIOD_BYTES_MAX (50 * 1024)
+#define XLNX_PARAM_UNKNOWN 0
enum bit_depth {
BIT_DEPTH_8,
@@ -117,6 +119,129 @@ static const struct snd_pcm_hardware xlnx_pcm_hardware = {
.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)
{
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)
{
u32 low, high, active_ch, val, bytes_per_ch, bits_per_sample;
+ u32 aes_reg1_val, aes_reg2_val;
int status;
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 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)
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);
status = snd_pcm_lib_malloc_pages(substream, size);
if (status < 0)