audio: add loopback

PD#147538: audio: loopback for pdm/spdif/tdm

1. pdm/spdif/tdm as loopback datain soruce, tdmin_lb as datalb source
2. add mixer kcontrols for loopback

Change-Id: I579db913080b3bb02bc99885eb330e24af8a0edb
Signed-off-by: Xing Wang <xing.wang@amlogic.com>
This commit is contained in:
Xing Wang
2017-07-06 21:40:10 +08:00
committed by Jianxin Pan
parent 826fba96f2
commit 7f841659f4
17 changed files with 830 additions and 48 deletions

View File

@@ -13994,3 +13994,11 @@ F: driver/amlogic/ddr_window/Kconfig
AMLOGIC AUDIO INFO
M: wang xing <xing.wang@amlogic.com>
F: drivers/amlogic/audioinfo/
AMLOGIC AXG ADD LOOPBACK INTERFACE
M: wang xing <xing.wang@amlogic.com>
F: arch/arm64/boot/dts/amlogic/axg_s400.dts
F: sound/soc/amlogic/auge/*
F: sound/soc/codecs/amlogic/pdm_dummy.c
F: sound/soc/codecs/amlogic/tlv320adc3101.c

View File

@@ -446,6 +446,8 @@
aml-audio-card,name = "AML-AXGSOUND";
//aml-audio-card,mclk-fs = <256>;
aml-audio-card,loopback = <&aml_loopback>;
aml-audio-card,dai-link@0 {
format = "dsp_a";
mclk-fs = <512>;
@@ -984,6 +986,40 @@
filter_mode = <1>; /* mode 0~4, defalut:1 */
status = "okay";
};
aml_loopback: loopback {
compatible = "amlogic, snd-loopback";
/*
* 0: out rate = in data rate;
* 1: out rate = loopback data rate;
*/
lb_mode = <0>;
/* datain src
* 0: tdmin_a;
* 1: tdmin_b;
* 2: tdmin_c;
* 3: spdifin;
* 4: pdmin;
*/
datain_src = <4>;
datain_chnum = <8>;
datain_chmask = <0xfc>;
/* tdmin_lb src
* 0: tdmoutA
* 1: tdmoutB
* 2: tdmoutC
* 3: PAD_tdminA
* 4: PAD_tdminB
* 5: PAD_tdminC
*/
datalb_src = <2>;
datalb_chnum = <8>;
datalb_chmask = <0x3>;
status = "okay";
};
}; /* end of audiobus */
&pinctrl_periphs {

View File

@@ -11,4 +11,6 @@ obj-$(CONFIG_AMLOGIC_SND_SOC_AUGE) += audio_controller.o \
pdm_hw.o \
pdm_hw_coeff.o \
iomap.o \
ddr_mngr.o
ddr_mngr.o \
loopback_hw.o \
audio_utils.o

View File

@@ -0,0 +1,331 @@
/*
* sound/soc/amlogic/auge/audio_utils.c
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#include "audio_utils.h"
#include "regs.h"
#include "iomap.h"
#include "loopback_hw.h"
static unsigned int loopback_enable;
static const char *const loopback_enable_texts[] = {
"Disable",
"Enable",
};
static const struct soc_enum loopback_enable_enum =
SOC_ENUM_SINGLE(EE_AUDIO_LB_CTRL0,
31,
ARRAY_SIZE(loopback_enable_texts),
loopback_enable_texts);
static int loopback_enable_get_enum(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
ucontrol->value.enumerated.item[0] = loopback_enable;
return 0;
}
static int loopback_enable_set_enum(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
loopback_enable = ucontrol->value.enumerated.item[0];
return 0;
}
static unsigned int loopback_datain;
static const char *const loopback_datain_texts[] = {
"Tdmin A",
"Tdmin B",
"Tdmin C",
"Spdif In",
"Pdm In",
};
static const struct soc_enum loopback_datain_enum =
SOC_ENUM_SINGLE(EE_AUDIO_LB_CTRL0, 0, ARRAY_SIZE(loopback_datain_texts),
loopback_datain_texts);
static int loopback_datain_get_enum(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
ucontrol->value.enumerated.item[0] = loopback_datain;
return 0;
}
static int loopback_datain_set_enum(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
loopback_datain = ucontrol->value.enumerated.item[0];
audiobus_update_bits(EE_AUDIO_LB_CTRL0, 0, loopback_datain);
return 0;
}
static unsigned int loopback_tdminlb;
static const char *const loopback_tdminlb_texts[] = {
"tdmoutA",
"tdmoutB",
"tdmoutC",
"tdminA",
"tdminB",
"tdminC",
};
static const struct soc_enum loopback_tdminlb_enum =
SOC_ENUM_SINGLE(EE_AUDIO_TDMIN_LB_CTRL,
20,
ARRAY_SIZE(loopback_tdminlb_texts),
loopback_tdminlb_texts);
static int loopback_tdminlb_get_enum(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
ucontrol->value.enumerated.item[0] = loopback_tdminlb;
return 0;
}
static int loopback_tdminlb_set_enum(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
loopback_tdminlb = ucontrol->value.enumerated.item[0];
audiobus_update_bits(EE_AUDIO_TDMIN_LB_CTRL,
0xf << 20,
loopback_datain);
return 0;
}
static const struct snd_kcontrol_new snd_auge_controls[] = {
/* loopback enable */
SOC_ENUM_EXT("Loopback Enable",
loopback_enable_enum,
loopback_enable_get_enum,
loopback_enable_set_enum),
/* loopback data in source */
SOC_ENUM_EXT("Loopback datain source",
loopback_datain_enum,
loopback_datain_get_enum,
loopback_datain_set_enum),
/* loopback data tdmin lb */
SOC_ENUM_EXT("Loopback tmdin lb source",
loopback_tdminlb_enum,
loopback_tdminlb_get_enum,
loopback_tdminlb_set_enum),
};
int snd_card_add_kcontrols(struct snd_soc_card *card)
{
pr_info("%s card:%p\n", __func__, card);
return snd_soc_add_card_controls(card,
snd_auge_controls, ARRAY_SIZE(snd_auge_controls));
}
int loopback_parse_of(struct device_node *node,
struct loopback_cfg *lb_cfg)
{
int ret;
ret = of_property_read_u32(node, "lb_mode",
&lb_cfg->lb_mode);
if (ret) {
pr_err("failed to get lb_mode, set it default\n");
lb_cfg->lb_mode = 0;
ret = 0;
}
ret = of_property_read_u32(node, "datain_src",
&lb_cfg->datain_src);
if (ret) {
pr_err("failed to get datain_src\n");
ret = -EINVAL;
goto fail;
}
ret = of_property_read_u32(node, "datain_chnum",
&lb_cfg->datain_chnum);
if (ret) {
pr_err("failed to get datain_chnum\n");
ret = -EINVAL;
goto fail;
}
ret = of_property_read_u32(node, "datain_chmask",
&lb_cfg->datain_chmask);
if (ret) {
pr_err("failed to get datain_chmask\n");
ret = -EINVAL;
goto fail;
}
ret = of_property_read_u32(node, "datalb_src",
&lb_cfg->datalb_src);
if (ret) {
pr_err("failed to get datalb_src\n");
ret = -EINVAL;
goto fail;
}
ret = of_property_read_u32(node, "datalb_chnum",
&lb_cfg->datalb_chnum);
if (ret) {
pr_err("failed to get datalb_chnum\n");
ret = -EINVAL;
goto fail;
}
ret = of_property_read_u32(node, "datalb_chmask",
&lb_cfg->datalb_chmask);
if (ret) {
pr_err("failed to get datalb_chmask\n");
ret = -EINVAL;
goto fail;
}
loopback_datain = lb_cfg->datain_src;
loopback_tdminlb = lb_cfg->datalb_src;
pr_info("parse loopback:, \tlb mode:%d\n",
lb_cfg->lb_mode);
pr_info("\tdatain_src:%d, datain_chnum:%d, datain_chumask:%x\n",
lb_cfg->datain_src,
lb_cfg->datain_chnum,
lb_cfg->datain_chmask);
pr_info("\tdatalb_src:%d, datalb_chnum:%d, datalb_chumask:%x\n",
lb_cfg->datalb_src,
lb_cfg->datalb_chnum,
lb_cfg->datalb_chmask);
fail:
return ret;
}
int loopback_prepare(
struct snd_pcm_substream *substream,
struct loopback_cfg *lb_cfg)
{
struct snd_pcm_runtime *runtime = substream->runtime;
unsigned int bitwidth;
unsigned int datain_toddr_type, datalb_toddr_type;
unsigned int datain_msb, datain_lsb, datalb_msb, datalb_lsb;
struct lb_cfg datain_cfg;
struct lb_cfg datalb_cfg;
struct audio_data ddrdata;
struct data_in datain;
struct data_lb datalb;
if (!lb_cfg)
return -EINVAL;
bitwidth = snd_pcm_format_width(runtime->format);
switch (lb_cfg->datain_src) {
case DATAIN_TDMA:
case DATAIN_TDMB:
case DATAIN_TDMC:
case DATAIN_PDM:
datain_toddr_type = 0;
datain_msb = 32 - 1;
datain_lsb = 0;
break;
case DATAIN_SPDIF:
datain_toddr_type = 3;
datain_msb = 27;
datain_lsb = 4;
if (bitwidth <= 24)
datain_lsb = 28 - bitwidth;
else
datain_lsb = 4;
break;
default:
pr_err("unsupport data in source:%d\n",
lb_cfg->datain_src);
return -EINVAL;
}
switch (lb_cfg->datalb_src) {
case TDMINLB_TDMOUTA:
case TDMINLB_TDMOUTB:
case TDMINLB_TDMOUTC:
case TDMINLB_PAD_TDMINA:
case TDMINLB_PAD_TDMINB:
case TDMINLB_PAD_TDMINC:
if (bitwidth == 24) {
datalb_toddr_type = 4;
datalb_msb = 32 - 1;
datalb_lsb = 32 - bitwidth;
} else {
datalb_toddr_type = 0;
datalb_msb = 32 - 1;
datalb_lsb = 0;
}
break;
default:
pr_err("unsupport data lb source:%d\n",
lb_cfg->datalb_src);
return -EINVAL;
}
datain_cfg.ext_signed = 0;
datain_cfg.chnum = runtime->channels;
datain_cfg.chmask = lb_cfg->datain_chmask;
ddrdata.combined_type = datain_toddr_type;
ddrdata.msb = datain_msb;
ddrdata.lsb = datain_lsb;
ddrdata.src = lb_cfg->datain_src;
datain.config = &datain_cfg;
datain.ddrdata = &ddrdata;
datalb_cfg.ext_signed = 0;
datalb_cfg.chnum = lb_cfg->datalb_chnum;
datalb_cfg.chmask = lb_cfg->datalb_chmask;
datalb.config = &datalb_cfg;
datalb.ddr_type = datalb_toddr_type;
datalb.msb = datalb_msb;
datalb.lsb = datalb_lsb;
datain_config(&datain);
datalb_config(&datalb);
datalb_ctrl(lb_cfg->datalb_src, bitwidth);
lb_enable_ex(lb_cfg->lb_mode, true);
return 0;
}
int loopback_is_enable(void)
{
return (loopback_enable == 1);
}

View File

@@ -0,0 +1,137 @@
/*
* sound/soc/amlogic/auge/audio_utils.h
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#ifndef __AML_AUDIO_UTILS_H__
#define __AML_AUDIO_UTILS_H__
#include <linux/types.h>
#include <sound/soc.h>
/* datain src
* [4]: pdmin;
* [3]: spdifin;
* [2]: tdmin_c;
* [1]: tdmin_b;
* [0]: tdmin_a;
*/
enum datain_src {
DATAIN_TDMA = 0,
DATAIN_TDMB,
DATAIN_TDMC,
DATAIN_SPDIF,
DATAIN_PDM,
};
/* datalb src/tdmlb src
* [0]: tdmoutA
* [1]: tdmoutB
* [2]: tdmoutC
* [3]: PAD_tdminA
* [4]: PAD_tdminB
* [5]: PAD_tdminC
*/
enum tdmin_lb_src {
TDMINLB_TDMOUTA = 0,
TDMINLB_TDMOUTB,
TDMINLB_TDMOUTC,
TDMINLB_PAD_TDMINA,
TDMINLB_PAD_TDMINB,
TDMINLB_PAD_TDMINC,
};
/* toddr_src_sel
* [7]: loopback;
* [6]: tdmin_lb;
* [5]: reserved;
* [4]: pdmin;
* [3]: spdifin;
* [2]: tdmin_c;
* [1]: tdmin_b;
* [0]: tdmin_a;
*/
enum fifoin_src {
FIFOIN_TDMINA = 0,
FIFOIN_TDMINB = 1,
FIFOIN_TDMINC = 2,
FIFOIN_SPDIF = 3,
FIFOIN_PDM = 4,
FIFOIN_TDMINLB = 6,
FIFOIN_LOOPBACK = 7
};
/* audio data selected to ddr */
struct audio_data {
unsigned int resample;
/* reg_dat_sel
* 0: combined data[m:n] without gap;
* like S0[m:n],S1[m:n],S2[m:n],
* 1: combined data[m:n] as 16bits;
* like {S0[11:0],4'd0},{S1[11:0],4'd0}
* 2: combined data[m:n] as 16bits;
* like {4'd0,S0[11:0]},{4'd0,{S1[11:0]}
* 3: combined data[m:n] as 32bits;
* like {S0[27:4],8'd0},{S1[27:4],8'd0}
* 4: combined data[m:n] as 32bits;
* like {8'd0,S0[27:4]},{8'd0,{S1[27:4]}
*/
unsigned int combined_type;
/* the msb positioin in data */
unsigned int msb;
/* the lsb position in data */
unsigned int lsb;
/* toddr_src_sel
* [7]: loopback;
* [6]: tdmin_lb;
* [5]: reserved;
* [4]: pdmin;
* [3]: spdifin;
* [2]: tdmin_c;
* [1]: tdmin_b;
* [0]: tdmin_a;
*/
unsigned int src;
};
/**/
struct loopback_cfg {
/* lb_mode
* 0: out rate = in data rate;
* 1: out rate = loopback data rate;
*/
unsigned int lb_mode;
enum datain_src datain_src;
unsigned int datain_chnum;
unsigned int datain_chmask;
enum tdmin_lb_src datalb_src;
unsigned int datalb_chnum;
unsigned int datalb_chmask;
};
extern int loopback_is_enable(void);
extern int snd_card_add_kcontrols(struct snd_soc_card *card);
extern int loopback_parse_of(struct device_node *node,
struct loopback_cfg *lb_cfg);
extern int loopback_prepare(
struct snd_pcm_substream *substream,
struct loopback_cfg *lb_cfg);
#endif

View File

@@ -47,6 +47,7 @@ struct aml_card_data {
struct snd_soc_dai_link *dai_link;
int spk_mute_gpio;
bool spk_mute_active_low;
struct loopback_cfg lb_cfg;
};
#define aml_priv_to_dev(priv) ((priv)->snd_card.dev)
@@ -217,10 +218,21 @@ err:
return ret;
}
int aml_card_prepare(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct aml_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
loopback_prepare(substream, &priv->lb_cfg);
return 0;
}
static struct snd_soc_ops aml_card_ops = {
.startup = aml_card_startup,
.shutdown = aml_card_shutdown,
.hw_params = aml_card_hw_params,
.startup = aml_card_startup,
.shutdown = aml_card_shutdown,
.hw_params = aml_card_hw_params,
.prepare = aml_card_prepare,
};
static int aml_card_dai_init(struct snd_soc_pcm_runtime *rtd)
@@ -466,6 +478,7 @@ static int aml_card_parse_of(struct device_node *node,
{
struct device *dev = aml_priv_to_dev(priv);
struct device_node *dai_link;
struct device_node *lb_link;
int ret;
if (!node)
@@ -492,6 +505,14 @@ static int aml_card_parse_of(struct device_node *node,
/* Factor to mclk, used in hw_params() */
of_property_read_u32(node, PREFIX "mclk-fs", &priv->mclk_fs);
/* Loopback */
lb_link = of_parse_phandle(node, PREFIX "loopback", 0);
if (lb_link) {
ret = loopback_parse_of(lb_link, &priv->lb_cfg);
if (ret < 0)
pr_err("failed parse loopback, ignore it\n");
}
/* Single/Muti DAI link(s) & New style of DT node */
if (dai_link) {
struct device_node *np = NULL;
@@ -522,6 +543,7 @@ static int aml_card_parse_of(struct device_node *node,
card_parse_end:
of_node_put(dai_link);
of_node_put(lb_link);
return ret;
}
@@ -608,6 +630,14 @@ static int aml_card_probe(struct platform_device *pdev)
ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card);
if (ret < 0) {
dev_err(dev, "failed to register sound card\n");
goto err;
}
/* Add controls */
ret = aml_card_add_controls(&priv->snd_card);
if (ret < 0) {
dev_err(dev, "failed to register mixer kcontrols\n");
goto err;
}

View File

@@ -18,6 +18,8 @@
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/kernel.h>
#include "card_utils.h"
int aml_card_parse_daifmt(struct device *dev,
@@ -288,3 +290,16 @@ int aml_card_clean_reference(struct snd_soc_card *card)
return 0;
}
int aml_card_add_controls(struct snd_soc_card *card)
{
int ret;
ret = snd_card_add_kcontrols(card);
if (ret < 0) {
pr_info("failed register kcontrols\n");
return ret;
}
return 0;
}

View File

@@ -19,6 +19,7 @@
#define __AML_CARD_CORE_H
#include <sound/soc.h>
#include "audio_utils.h"
struct aml_dai {
const char *name;
@@ -78,4 +79,6 @@ void aml_card_canonicalize_cpu(struct snd_soc_dai_link *dai_link,
int aml_card_clean_reference(struct snd_soc_card *card);
extern int aml_card_add_controls(struct snd_soc_card *card);
#endif /* __AML_CARD_CORE_H */

View File

@@ -19,6 +19,7 @@
#include <linux/slab.h>
#include "regs.h"
#include "ddr_mngr.h"
#include "audio_utils.h"
static DEFINE_MUTEX(ddr_mutex);
@@ -218,6 +219,10 @@ void aml_toddr_select_src(struct toddr *to, enum toddr_src src)
unsigned int reg_base = to->reg_base;
unsigned int reg;
/* check whether loopback enable */
if (loopback_is_enable())
src = LOOPBACK;
reg = calc_toddr_address(EE_AUDIO_TODDR_A_CTRL0, reg_base);
aml_audiobus_update_bits(actrl, reg, 0x7, src & 0x7);
}

View File

@@ -0,0 +1,125 @@
/*
* sound/soc/amlogic/auge/loopback_hw.c
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#include <sound/soc.h>
#include "regs.h"
#include "loopback_hw.h"
#include "iomap.h"
void datain_config(struct data_in *datain)
{
audiobus_write(
EE_AUDIO_LB_CTRL0,
datain->config->ext_signed << 29 |
(datain->config->chnum - 1) << 24 |
datain->config->chmask << 16 |
datain->ddrdata->combined_type << 13 |
datain->ddrdata->msb << 8 |
datain->ddrdata->lsb << 3 |
datain->ddrdata->src << 0
);
}
void datalb_config(struct data_lb *datalb)
{
audiobus_write(
EE_AUDIO_LB_CTRL1,
datalb->config->ext_signed << 29 |
(datalb->config->chnum - 1) << 24 |
datalb->config->chmask << 16 |
datalb->ddr_type << 13 |
datalb->msb << 8 |
datalb->lsb << 3
);
}
void datalb_ctrl(int lb_src, int bitdepth)
{
//tdmin lb, same as tdm out
audiobus_update_bits(
EE_AUDIO_CLK_TDMIN_LB_CTRL,
0x3 << 30 | 0 << 29 | 0xf << 24 | 0xf << 20,
0x3 << 30 | 0 << 29 | 2 << 24 | 2 << 20
);
//tdmin ctrl, from tdmout
//reset
audiobus_update_bits(EE_AUDIO_TDMIN_LB_CTRL, 3<<28, 0);
audiobus_update_bits(EE_AUDIO_TDMIN_LB_CTRL, 1<<29, 1<<29);
audiobus_update_bits(EE_AUDIO_TDMIN_LB_CTRL, 1<<28, 1<<28);
audiobus_write(
EE_AUDIO_TDMIN_LB_CTRL,
1 << 31 |
0 << 30 | /*0:tdm mode; 1: i2s mode;*/
1 << 29 |
1 << 28 |
lb_src << 20|
4 << 16|
(bitdepth - 1) << 0
);
audiobus_write(
EE_AUDIO_TDMIN_LB_MASK0,
0xff);
}
void lb_enable_ex(int mode, bool is_enable)
{
audiobus_update_bits(
EE_AUDIO_LB_CTRL0,
0x3 << 30,
is_enable << 31 |
mode << 30
);
}
void lb_set_datain_src(int src)
{
}
void lb_set_tdminlb_src(int src)
{
}
void lb_set_tdminlb_enable(bool is_enable)
{
}
void lb_enable(bool is_enable)
{
if (is_enable)
audiobus_update_bits(
EE_AUDIO_LB_CTRL0,
0x1 << 31,
is_enable << 31
);
else
audiobus_write(
EE_AUDIO_LB_CTRL0,
0);
}
void lb_set_mode(int mode)
{
audiobus_update_bits(
EE_AUDIO_LB_CTRL0,
0x1 << 30,
mode << 30
);
}

View File

@@ -0,0 +1,64 @@
/*
* sound/soc/amlogic/auge/loopback_hw.h
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#ifndef __AML_LOOPBACK_HW_H__
#define __AML_LOOPBACK_HW_H__
#include "audio_utils.h"
struct lb_cfg {
/*
* 0: extend bits as "0"
* 1: extend bits as "msb"
*/
unsigned int ext_signed;
/* total channel number */
unsigned int chnum;
/* which channel is selected for loopback */
unsigned int chmask;
};
struct data_in {
struct lb_cfg *config;
struct audio_data *ddrdata;
};
struct data_lb {
struct lb_cfg *config;
unsigned int ddr_type;
unsigned int msb;
unsigned int lsb;
};
struct loopback {
struct device *dev;
unsigned int lb_mode;
struct data_in *datain;
struct data_lb *datalb;
};
extern void datain_config(struct data_in *datain);
extern void datalb_config(struct data_lb *datalb);
extern void datalb_ctrl(int lb_src, int bitdepth);
extern void lb_enable_ex(int mode, bool is_enable);
#endif

View File

@@ -47,11 +47,11 @@ static struct snd_pcm_hardware aml_pdm_hardware = {
SNDRV_PCM_FMTBIT_S24 |
SNDRV_PCM_FMTBIT_S32,
.rate_min = 8000,
.rate_max = 48000,
.rate_min = 8000,
.rate_max = 48000,
.channels_min = 1,
.channels_max = 8,
.channels_min = PDM_CHANNELS_MIN,
.channels_max = PDM_CHANNELS_MAX,
.buffer_bytes_max = 32 * 1024,
.period_bytes_max = 16 * 1024,
@@ -473,10 +473,10 @@ static int aml_pdm_dai_prepare(
switch (bitwidth) {
case 16:
toddr_type = 2;
case 32:
toddr_type = 0;
break;
case 24:
case 32:
toddr_type = 4;
break;
default:

View File

@@ -27,9 +27,13 @@
#define DEFAULT_FS_RATIO 256
#define PDM_CHANNELS_MIN 1
#define PDM_CHANNELS_MAX 8
#define PDM_CHANNELS_MAX (8 + 8) /* 8ch pdm in, 8 ch tdmin_lb */
#define PDM_RATES (SNDRV_PCM_RATE_48000 |\
SNDRV_PCM_RATE_32000 |\
SNDRV_PCM_RATE_16000 |\
SNDRV_PCM_RATE_8000)
#define PDM_RATES SNDRV_PCM_RATE_8000_48000
#define PDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
SNDRV_PCM_FMTBIT_S24_LE |\
SNDRV_PCM_FMTBIT_S32_LE)

View File

@@ -34,7 +34,7 @@
#include "ddr_mngr.h"
#include "spdif_hw.h"
#include "audio_utils.h"
#define DRV_NAME "aml_spdif"
@@ -412,36 +412,55 @@ static int aml_dai_spdif_prepare(
aml_frddr_set_fifos(fr, 0x40, 0x20);
} else {
struct toddr *to = p_spdif->tddr;
unsigned int lsb, toddr_type;
unsigned int msb, lsb, toddr_type;
switch (bit_depth) {
case 8:
toddr_type = 0;
break;
case 16:
toddr_type = 1;
break;
case 24:
toddr_type = 4;
break;
case 32:
toddr_type = 3;
break;
default:
dev_err(p_spdif->dev,
"runtime format invalid bit_depth: %d\n",
bit_depth);
return -EINVAL;
if (loopback_is_enable()) {
switch (bit_depth) {
case 8:
case 16:
case 32:
toddr_type = 0;
break;
case 24:
toddr_type = 4;
break;
default:
pr_err(
"runtime format invalid bit_depth: %d\n",
bit_depth);
return -EINVAL;
}
msb = 32 - 1;
lsb = 32 - bit_depth;
} else {
switch (bit_depth) {
case 8:
case 16:
toddr_type = 0;
break;
case 24:
toddr_type = 4;
break;
case 32:
toddr_type = 3;
break;
default:
dev_err(p_spdif->dev,
"runtime format invalid bit_depth: %d\n",
bit_depth);
return -EINVAL;
}
msb = 28 - 1;
if (bit_depth <= 24)
lsb = 28 - bit_depth;
else
lsb = 4;
}
if (bit_depth <= 24)
lsb = 28 - bit_depth;
else
lsb = 4;
// to ddr spdifin
aml_toddr_select_src(to, SPDIFIN);
aml_toddr_set_format(to, toddr_type, 27, lsb);
aml_toddr_set_format(to, toddr_type, msb, lsb);
aml_toddr_set_fifos(to, 0x40);
}
@@ -576,7 +595,8 @@ static struct snd_soc_dai_driver aml_spdif_dai = {
},
.capture = {
.channels_min = 1,
.channels_max = 2,
/* spdif 2ch + tdmin_lb 8ch(fake for loopback) */
.channels_max = 10,
.rates = AML_DAI_SPDIF_RATES,
.formats = AML_DAI_SPDIF_FORMATS,
},

View File

@@ -403,13 +403,11 @@ static int aml_dai_tdm_prepare(struct snd_pcm_substream *substream,
switch (bit_depth) {
case 8:
case 16:
case 32:
toddr_type = 0;
break;
case 16:
toddr_type = 2;
break;
case 24:
case 32:
toddr_type = 4;
break;
default:
@@ -816,7 +814,7 @@ static struct snd_soc_dai_driver aml_tdm_dai[] = {
},
.capture = {
.channels_min = 1,
.channels_max = 8,
.channels_max = 32,
.rates = AML_DAI_TDM_RATES,
.formats = AML_DAI_TDM_FORMATS,
},
@@ -836,7 +834,7 @@ static struct snd_soc_dai_driver aml_tdm_dai[] = {
},
.capture = {
.channels_min = 1,
.channels_max = 8,
.channels_max = 32,
.rates = AML_DAI_TDM_RATES,
.formats = AML_DAI_TDM_FORMATS,
},

View File

@@ -20,7 +20,11 @@
#include <linux/of.h>
#include <sound/soc.h>
#define DUMMY_RATES SNDRV_PCM_RATE_8000_48000
#define DUMMY_RATES (SNDRV_PCM_RATE_48000 |\
SNDRV_PCM_RATE_32000 |\
SNDRV_PCM_RATE_16000 |\
SNDRV_PCM_RATE_8000)
#define DUMMY_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
SNDRV_PCM_FMTBIT_S24_LE |\
SNDRV_PCM_FMTBIT_S32_LE)
@@ -59,7 +63,7 @@ struct snd_soc_dai_driver pdm_dummy_dai = {
.capture = {
.stream_name = "PDM Capture",
.channels_min = 1,
.channels_max = 8,
.channels_max = 16,
.rates = DUMMY_RATES,
.formats = DUMMY_FORMATS,
},

View File

@@ -565,7 +565,7 @@ static int adc3101_mute(struct snd_soc_dai *dai, int mute)
static int adc3101_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
pr_info("%s ..\n", __func__);
pr_debug("%s ..\n", __func__);
switch (level) {
case SND_SOC_BIAS_ON:
/* Switch on PLL */