audio: auge: fix spdif in & out work at the same time for ASRC

PD#163795: audio: auge: fix spdif in & out work at the same time for ASRC

1. fix spdifin toddr as right_j for asrc, not support asrc 32bit now
2. fix clk dir for set_sysclk
3. auto enable/disable asrc when switch raw data and pcm data source
4. fix lr channel swap when replug in
5. detect spdifin sample mode by max_width
6. force to clear spdif in sample rate irq bit for axg
7. enable spdif in for s420 boards

Change-Id: I83dc211815068b9d073fb20433c76ce9f129b40e
Signed-off-by: Xing Wang <xing.wang@amlogic.com>
This commit is contained in:
Xing Wang
2018-04-03 14:03:41 +08:00
committed by Jianxin Pan
parent 6affba0e44
commit bf64bfb4f2
20 changed files with 1321 additions and 293 deletions

View File

@@ -1158,6 +1158,20 @@
interrupt-names = "irq_spdifin";
pinctrl-names = "spdif_pins";
pinctrl-0 = <&spdifout &spdifin>;
/*
* whether do asrc for pcm.
* if raw data, asrc is disabled automatically
* 0: "Disable",
* 1: "Enable:32K",
* 2: "Enable:44K",
* 3: "Enable:48K",
* 4: "Enable:88K",
* 5: "Enable:96K",
* 6: "Enable:176K",
* 7: "Enable:192K",
*/
auto_asrc = <0>;
status = "okay";
};
aml_pdm: pdm {
@@ -1242,7 +1256,7 @@
* TDMIN_LB,
* LOOPBACK,
*/
resample_module = <4>;
resample_module = <3>;
status = "okay";
};
aml_pwrdet: pwrdet {
@@ -1266,7 +1280,7 @@
hi_th = <0x70000>;
lo_th = <0x16000>;
status = "okay";
status = "disabled";
};
}; /* end of audiobus */

View File

@@ -1139,6 +1139,20 @@
interrupt-names = "irq_spdifin";
pinctrl-names = "spdif_pins";
pinctrl-0 = <&spdifout &spdifin>;
/*
* whether do asrc for pcm.
* if raw data, asrc is disabled automatically
* 0: "Disable",
* 1: "Enable:32K",
* 2: "Enable:44K",
* 3: "Enable:48K",
* 4: "Enable:88K",
* 5: "Enable:96K",
* 6: "Enable:176K",
* 7: "Enable:192K",
*/
auto_asrc = <0>;
status = "okay";
};
aml_pdm: pdm {
@@ -1206,6 +1220,49 @@
status = "okay";
};
audioresample: resample {
compatible = "amlogic, axg-resample";
clocks = <&clkc CLKID_MPLL3
&clkaudio CLKID_AUDIO_MCLK_F
&clkaudio CLKID_AUDIO_RESAMPLE_CTRL>;
clock-names = "resample_pll", "resample_src", "resample_clk";
/*same with toddr_src
* TDMIN_A,
* TDMIN_B,
* TDMIN_C,
* SPDIFIN,
* PDMIN,
* NONE,
* TDMIN_LB,
* LOOPBACK,
*/
resample_module = <3>;
status = "okay";
};
aml_pwrdet: pwrdet {
compatible = "amlogic, axg-power-detect";
interrupts = <GIC_SPI 91 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "pwrdet_irq";
/* pwrdet source sel
* 7: loopback;
* 6: tdmin_lb;
* 5: reserved;
* 4: pdmin;
* 3: spdifin;
* 2: tdmin_c;
* 1: tdmin_b;
* 0: tdmin_a;
*/
pwrdet_src = <4>;
hi_th = <0x70000>;
lo_th = <0x16000>;
status = "disabled";
};
}; /* end of audiobus */
&pinctrl_periphs {

View File

@@ -1016,6 +1016,20 @@
interrupt-names = "irq_spdifin";
pinctrl-names = "spdif_pins";
pinctrl-0 = <&spdifout &spdifin>;
/*
* whether do asrc for pcm.
* if raw data, asrc is disabled automatically
* 0: "Disable",
* 1: "Enable:32K",
* 2: "Enable:44K",
* 3: "Enable:48K",
* 4: "Enable:88K",
* 5: "Enable:96K",
* 6: "Enable:176K",
* 7: "Enable:192K",
*/
auto_asrc = <0>;
status = "okay";
};
aml_pdm: pdm {
@@ -1080,6 +1094,49 @@
status = "okay";
};
audioresample: resample {
compatible = "amlogic, axg-resample";
clocks = <&clkc CLKID_MPLL3
&clkaudio CLKID_AUDIO_MCLK_F
&clkaudio CLKID_AUDIO_RESAMPLE_CTRL>;
clock-names = "resample_pll", "resample_src", "resample_clk";
/*same with toddr_src
* TDMIN_A,
* TDMIN_B,
* TDMIN_C,
* SPDIFIN,
* PDMIN,
* NONE,
* TDMIN_LB,
* LOOPBACK,
*/
resample_module = <3>;
status = "okay";
};
aml_pwrdet: pwrdet {
compatible = "amlogic, axg-power-detect";
interrupts = <GIC_SPI 91 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "pwrdet_irq";
/* pwrdet source sel
* 7: loopback;
* 6: tdmin_lb;
* 5: reserved;
* 4: pdmin;
* 3: spdifin;
* 2: tdmin_c;
* 1: tdmin_b;
* 0: tdmin_a;
*/
pwrdet_src = <4>;
hi_th = <0x70000>;
lo_th = <0x16000>;
status = "disabled";
};
}; /* end of audiobus */
&pinctrl_periphs {

View File

@@ -1060,6 +1060,20 @@
interrupt-names = "irq_spdifin";
pinctrl-names = "spdif_pins";
pinctrl-0 = <&spdifout &spdifin>;
/*
* whether do asrc for pcm.
* if raw data, asrc is disabled automatically
* 0: "Disable",
* 1: "Enable:32K",
* 2: "Enable:44K",
* 3: "Enable:48K",
* 4: "Enable:88K",
* 5: "Enable:96K",
* 6: "Enable:176K",
* 7: "Enable:192K",
*/
auto_asrc = <0>;
status = "okay";
};
aml_pdm: pdm {
@@ -1124,6 +1138,49 @@
status = "okay";
};
audioresample: resample {
compatible = "amlogic, axg-resample";
clocks = <&clkc CLKID_MPLL3
&clkaudio CLKID_AUDIO_MCLK_F
&clkaudio CLKID_AUDIO_RESAMPLE_CTRL>;
clock-names = "resample_pll", "resample_src", "resample_clk";
/*same with toddr_src
* TDMIN_A,
* TDMIN_B,
* TDMIN_C,
* SPDIFIN,
* PDMIN,
* NONE,
* TDMIN_LB,
* LOOPBACK,
*/
resample_module = <3>;
status = "okay";
};
aml_pwrdet: pwrdet {
compatible = "amlogic, axg-power-detect";
interrupts = <GIC_SPI 91 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "pwrdet_irq";
/* pwrdet source sel
* 7: loopback;
* 6: tdmin_lb;
* 5: reserved;
* 4: pdmin;
* 3: spdifin;
* 2: tdmin_c;
* 1: tdmin_b;
* 0: tdmin_a;
*/
pwrdet_src = <4>;
hi_th = <0x70000>;
lo_th = <0x16000>;
status = "disabled";
};
}; /* end of audiobus */
&pinctrl_periphs {

View File

@@ -1026,6 +1026,20 @@
interrupt-names = "irq_spdifin";
pinctrl-names = "spdif_pins";
pinctrl-0 = <&spdifout &spdifin>;
/*
* whether do asrc for pcm.
* if raw data, asrc is disabled automatically
* 0: "Disable",
* 1: "Enable:32K",
* 2: "Enable:44K",
* 3: "Enable:48K",
* 4: "Enable:88K",
* 5: "Enable:96K",
* 6: "Enable:176K",
* 7: "Enable:192K",
*/
auto_asrc = <0>;
status = "okay";
};
aml_pdm: pdm {
@@ -1090,6 +1104,49 @@
status = "okay";
};
audioresample: resample {
compatible = "amlogic, axg-resample";
clocks = <&clkc CLKID_MPLL3
&clkaudio CLKID_AUDIO_MCLK_F
&clkaudio CLKID_AUDIO_RESAMPLE_CTRL>;
clock-names = "resample_pll", "resample_src", "resample_clk";
/*same with toddr_src
* TDMIN_A,
* TDMIN_B,
* TDMIN_C,
* SPDIFIN,
* PDMIN,
* NONE,
* TDMIN_LB,
* LOOPBACK,
*/
resample_module = <3>;
status = "okay";
};
aml_pwrdet: pwrdet {
compatible = "amlogic, axg-power-detect";
interrupts = <GIC_SPI 91 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "pwrdet_irq";
/* pwrdet source sel
* 7: loopback;
* 6: tdmin_lb;
* 5: reserved;
* 4: pdmin;
* 3: spdifin;
* 2: tdmin_c;
* 1: tdmin_b;
* 0: tdmin_a;
*/
pwrdet_src = <4>;
hi_th = <0x70000>;
lo_th = <0x16000>;
status = "disabled";
};
}; /* end of audiobus */
&pinctrl_periphs {

View File

@@ -434,16 +434,15 @@
};
};
/*aml-audio-card,dai-link@4 {
* mclk-fs = <128>;
* cpu {
* sound-dai = <&aml_spdif>;
* };
* codec {
* sound-dai = <&dummy_codec>;
* };
*};
*/
aml-audio-card,dai-link@4 {
mclk-fs = <128>;
cpu {
sound-dai = <&aml_spdif>;
};
codec {
sound-dai = <&dummy_codec>;
};
};
};
bt-dev{
@@ -955,7 +954,21 @@
interrupt-names = "irq_spdifin";
pinctrl-names = "spdif_pins";
pinctrl-0 = <&spdifout &spdifin>;
status = "disabled";
/*
* whether do asrc for pcm.
* if raw data, asrc is disabled automatically
* 0: "Disable",
* 1: "Enable:32K",
* 2: "Enable:44K",
* 3: "Enable:48K",
* 4: "Enable:88K",
* 5: "Enable:96K",
* 6: "Enable:176K",
* 7: "Enable:192K",
*/
auto_asrc = <0>;
status = "okay";
};
aml_pdm: pdm {
@@ -1020,6 +1033,26 @@
status = "okay";
};
audioresample: resample {
compatible = "amlogic, axg-resample";
clocks = <&clkc CLKID_MPLL3
&clkaudio CLKID_AUDIO_MCLK_F
&clkaudio CLKID_AUDIO_RESAMPLE_CTRL>;
clock-names = "resample_pll", "resample_src", "resample_clk";
/*same with toddr_src
* TDMIN_A,
* TDMIN_B,
* TDMIN_C,
* SPDIFIN,
* PDMIN,
* NONE,
* TDMIN_LB,
* LOOPBACK,
*/
resample_module = <3>;
status = "okay";
};
}; /* end of audiobus */
&pinctrl_periphs {

View File

@@ -425,16 +425,15 @@
};
};
/*aml-audio-card,dai-link@4 {
* mclk-fs = <128>;
* cpu {
* sound-dai = <&aml_spdif>;
* };
* codec {
* sound-dai = <&dummy_codec>;
* };
*};
*/
aml-audio-card,dai-link@4 {
mclk-fs = <128>;
cpu {
sound-dai = <&aml_spdif>;
};
codec {
sound-dai = <&dummy_codec>;
};
};
};
bt-dev{
@@ -822,7 +821,21 @@
interrupt-names = "irq_spdifin";
pinctrl-names = "spdif_pins";
pinctrl-0 = <&spdifout &spdifin>;
status = "disabled";
/*
* whether do asrc for pcm.
* if raw data, asrc is disabled automatically
* 0: "Disable",
* 1: "Enable:32K",
* 2: "Enable:44K",
* 3: "Enable:48K",
* 4: "Enable:88K",
* 5: "Enable:96K",
* 6: "Enable:176K",
* 7: "Enable:192K",
*/
auto_asrc = <0>;
status = "okay";
};
aml_pdm: pdm {
@@ -886,6 +899,26 @@
status = "okay";
};
audioresample: resample {
compatible = "amlogic, axg-resample";
clocks = <&clkc CLKID_MPLL3
&clkaudio CLKID_AUDIO_MCLK_F
&clkaudio CLKID_AUDIO_RESAMPLE_CTRL>;
clock-names = "resample_pll", "resample_src", "resample_clk";
/*same with toddr_src
* TDMIN_A,
* TDMIN_B,
* TDMIN_C,
* SPDIFIN,
* PDMIN,
* NONE,
* TDMIN_LB,
* LOOPBACK,
*/
resample_module = <3>;
status = "okay";
};
}; /* end of audiobus */
&pinctrl_periphs {

View File

@@ -437,16 +437,15 @@
};
};
/*aml-audio-card,dai-link@4 {
* mclk-fs = <128>;
* cpu {
* sound-dai = <&aml_spdif>;
* };
* codec {
* sound-dai = <&dummy_codec>;
* };
*};
*/
aml-audio-card,dai-link@4 {
mclk-fs = <128>;
cpu {
sound-dai = <&aml_spdif>;
};
codec {
sound-dai = <&dummy_codec>;
};
};
};
bt-dev{
@@ -960,7 +959,21 @@
interrupt-names = "irq_spdifin";
pinctrl-names = "spdif_pins";
pinctrl-0 = <&spdifout &spdifin>;
status = "disabled";
/*
* whether do asrc for pcm.
* if raw data, asrc is disabled automatically
* 0: "Disable",
* 1: "Enable:32K",
* 2: "Enable:44K",
* 3: "Enable:48K",
* 4: "Enable:88K",
* 5: "Enable:96K",
* 6: "Enable:176K",
* 7: "Enable:192K",
*/
auto_asrc = <0>;
status = "okay";
};
aml_pdm: pdm {
@@ -1026,6 +1039,26 @@
status = "okay";
};
audioresample: resample {
compatible = "amlogic, axg-resample";
clocks = <&clkc CLKID_MPLL3
&clkaudio CLKID_AUDIO_MCLK_F
&clkaudio CLKID_AUDIO_RESAMPLE_CTRL>;
clock-names = "resample_pll", "resample_src", "resample_clk";
/*same with toddr_src
* TDMIN_A,
* TDMIN_B,
* TDMIN_C,
* SPDIFIN,
* PDMIN,
* NONE,
* TDMIN_LB,
* LOOPBACK,
*/
resample_module = <3>;
status = "okay";
};
}; /* end of audiobus */
&pinctrl_periphs {

View File

@@ -433,6 +433,12 @@ static int aml_card_hw_params(struct snd_pcm_substream *substream,
aml_priv_to_props(priv, rtd->num);
unsigned int mclk = 0, mclk_fs = 0;
int i = 0, ret = 0;
int clk_dir = 0;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
clk_dir = SND_SOC_CLOCK_OUT;
else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
clk_dir = SND_SOC_CLOCK_IN;
if (priv->mclk_fs)
mclk_fs = priv->mclk_fs;
@@ -444,16 +450,15 @@ static int aml_card_hw_params(struct snd_pcm_substream *substream,
for (i = 0; i < rtd->num_codecs; i++) {
codec_dai = rtd->codec_dais[i];
ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
SND_SOC_CLOCK_IN);
clk_dir);
if (ret && ret != -ENOTSUPP)
goto err;
}
ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
SND_SOC_CLOCK_OUT);
clk_dir);
if (ret && ret != -ENOTSUPP)
goto err;

View File

@@ -74,8 +74,9 @@ struct toddr {
unsigned int msb_bit;
unsigned int lsb_bit;
unsigned int reg_base;
unsigned int channels;
unsigned int bitdepth;
unsigned int channels;
unsigned int rate;
enum toddr_src src;
unsigned int fifo_id;
@@ -129,14 +130,17 @@ static struct toddr toddrs[DDRMAX];
/* resample */
static struct toddr_attach attach_resample;
static void aml_check_resample(bool enable);
static bool aml_check_resample_module(int src);
/* power detect */
static struct toddr_attach attach_pwrdet;
static void aml_check_pwrdet(bool enable);
static bool aml_check_pwrdet_module(int src);
/* Audio EQ DRC */
static struct frddr_attach attach_aed;
static void aml_check_aed(bool enable, int dst);
static bool aml_check_aed_module(int dst);
/* to DDRS */
static struct toddr *register_toddr_l(struct device *dev,
@@ -341,10 +345,15 @@ void aml_toddr_enable(struct toddr *to, bool enable)
aml_audiobus_update_bits(actrl, reg, 1<<31, enable<<31);
/* check resample */
aml_check_resample(enable);
if (aml_check_resample_module(to->src))
aml_check_resample(enable);
/* check power detect */
aml_check_pwrdet(enable);
if (aml_check_pwrdet_module(to->src))
aml_check_pwrdet(enable);
if (!enable)
aml_audiobus_write(actrl, reg, 0x0);
}
void aml_toddr_select_src(struct toddr *to, enum toddr_src src)
@@ -377,84 +386,170 @@ void aml_toddr_set_fifos(struct toddr *to, unsigned int thresh)
aml_audiobus_write(actrl, reg, (thresh-1)<<16|2<<8);
}
void aml_toddr_set_format(struct toddr *to,
unsigned int type, unsigned int msb, unsigned int lsb,
int ch_num, int bit_depth)
void aml_toddr_set_format(struct toddr *to, struct toddr_fmt *fmt)
{
struct aml_audio_controller *actrl = to->actrl;
unsigned int reg_base = to->reg_base;
unsigned int reg;
to->channels = ch_num;
to->bitdepth = bit_depth;
to->bitdepth = fmt->bit_depth;
to->channels = fmt->ch_num;
to->rate = fmt->rate;
reg = calc_toddr_address(EE_AUDIO_TODDR_A_CTRL0, reg_base);
aml_audiobus_update_bits(actrl, reg, 0x1fff<<3,
type<<13|msb<<8|lsb<<3);
aml_audiobus_update_bits(actrl, reg,
0x7 << 24 | 0x1fff << 3,
fmt->endian << 24 | fmt->type << 13 |
fmt->msb << 8 | fmt->lsb << 3);
}
void aml_toddr_insert_chanum(struct toddr *to)
{
struct aml_audio_controller *actrl = to->actrl;
unsigned int reg_base = to->reg_base;
unsigned int reg;
reg = calc_toddr_address(EE_AUDIO_TODDR_A_CTRL1, reg_base);
aml_audiobus_update_bits(actrl, reg, 1 << 24, 1 << 24);
}
unsigned int aml_toddr_read(struct toddr *to)
{
struct aml_audio_controller *actrl = to->actrl;
unsigned int reg_base = to->reg_base;
unsigned int reg;
reg = calc_toddr_address(EE_AUDIO_TODDR_A_CTRL0, reg_base);
return aml_audiobus_read(actrl, reg);
}
void aml_toddr_write(struct toddr *to, unsigned int val)
{
struct aml_audio_controller *actrl = to->actrl;
unsigned int reg_base = to->reg_base;
unsigned int reg;
reg = calc_toddr_address(EE_AUDIO_TODDR_A_CTRL0, reg_base);
aml_audiobus_write(actrl, reg, val);
}
void aml_toddr_set_resample(struct toddr *to, bool enable)
{
struct aml_audio_controller *actrl = to->actrl;
unsigned int reg_base = to->reg_base;
unsigned int reg;
pr_info("toddr selects data to %s resample\n",
enable ? "enable" : "disable");
reg = calc_toddr_address(EE_AUDIO_TODDR_A_CTRL0, reg_base);
aml_audiobus_update_bits(actrl, reg, 1<<30, enable<<30);
}
static void aml_set_resample(struct toddr *to,
bool enable)
{
struct aml_audio_controller *actrl = to->actrl;
unsigned int reg_base = to->reg_base;
unsigned int reg;
if (enable) {
int bitwidth = to->bitdepth;
/* channels and bit depth for resample */
resample_format_set(to->channels, to->bitdepth);
if ((to->src == SPDIFIN) && (bitwidth == 32)) {
struct aml_audio_controller *actrl = to->actrl;
unsigned int reg_base = to->reg_base;
unsigned int reg;
unsigned int endian, toddr_type;
/* TODO: fixed me */
pr_info("Warning: Not support 32bit sample rate for axg chipset\n");
bitwidth = 24;
endian = 5;
toddr_type = 4;
/* FIX ME */
reg = calc_toddr_address(EE_AUDIO_TODDR_A_CTRL0,
reg_base);
aml_audiobus_update_bits(actrl, reg,
0x7 << 24 | 0x7 << 13,
endian << 24 | toddr_type << 13);
}
resample_format_set(to->channels, bitwidth);
/* toddr index for resample */
resample_src_select(to->fifo_id);
}
/* resample enable or not */
reg = calc_toddr_address(EE_AUDIO_TODDR_A_CTRL0, reg_base);
aml_audiobus_update_bits(actrl, reg, 0x1 << 30, enable << 30);
resample_enable(enable);
/* select reample data */
aml_toddr_set_resample(to, enable);
}
void aml_resample_enable(bool enable, int resample_module)
{
/* when try to enable resample, if toddr is not in used,
* set resample status as ready
*/
attach_resample.enable = enable;
attach_resample.attach_module = resample_module;
if (enable) {
if ((attach_resample.status == DISABLED)
|| (attach_resample.status == READY)) {
struct toddr *to = fetch_toddr_by_src(resample_module);
if (!to) {
attach_resample.status = READY;
pr_info("not in capture, resample is ready");
} else {
attach_resample.status = RUNNING;
aml_set_resample(to, enable);
}
}
} else {
if (attach_resample.status == RUNNING) {
struct toddr *to = fetch_toddr_by_src(resample_module);
aml_set_resample(to, enable);
}
attach_resample.status = DISABLED;
}
aml_check_resample(enable);
}
static bool aml_check_resample_module(int src)
{
bool is_module_resample = false;
if (attach_resample.enable
&& (src == attach_resample.attach_module))
is_module_resample = true;
return is_module_resample;
}
/*
* when try to enable resample, if toddr is not in used,
* set resample status as ready
*/
static void aml_check_resample(bool enable)
{
/* resample in enable */
if (attach_resample.enable) {
if (enable) {
/* check whether ready ? */
if (attach_resample.status == READY)
aml_resample_enable(true,
if ((attach_resample.status == DISABLED)
|| (attach_resample.status == READY)) {
struct toddr *to = fetch_toddr_by_src(
attach_resample.attach_module);
if (!to) {
attach_resample.status = READY;
pr_info("not in capture, Resample is ready\n");
} else {
attach_resample.status = RUNNING;
aml_set_resample(to, enable);
pr_info("Resample in running, module:%d, toddr:%d\n",
attach_resample.attach_module,
to->fifo_id);
}
}
} else {
if (attach_resample.status == RUNNING)
attach_resample.status = READY;
if (attach_resample.status == RUNNING) {
struct toddr *to = fetch_toddr_by_src(
attach_resample.attach_module);
aml_set_resample(to, enable);
attach_resample.status = DISABLED;
}
}
} else {
/* ensure resample is disabled */
struct toddr *to = fetch_toddr_by_src(
attach_resample.attach_module);
if (to) {
pr_info("Resample in running, disable it\n");
/* select reample data */
aml_toddr_set_resample(to, false);
/* update resample status */
attach_resample.status = DISABLED;
}
}
}
@@ -490,7 +585,7 @@ void aml_pwrdet_enable(bool enable, int pwrdet_module)
if (!to) {
attach_pwrdet.status = READY;
pr_info("not in capture, power detect is ready");
pr_info("not in capture, power detect is ready\n");
} else {
attach_pwrdet.status = RUNNING;
aml_set_pwrdet(to, enable);
@@ -506,6 +601,17 @@ void aml_pwrdet_enable(bool enable, int pwrdet_module)
}
}
static bool aml_check_pwrdet_module(int src)
{
bool is_module_pwrdet = false;
if (attach_pwrdet.enable
&& (src == attach_pwrdet.attach_module))
is_module_pwrdet = true;
return is_module_pwrdet;
}
static void aml_check_pwrdet(bool enable)
{
/* power detect in enable */
@@ -746,7 +852,8 @@ void aml_frddr_enable(struct frddr *fr, bool enable)
aml_audiobus_write(actrl, reg, 0x0);
/* check for Audio EQ/DRC */
aml_check_aed(enable, fr->dest);
if (aml_check_aed_module(fr->dest))
aml_check_aed(enable, fr->dest);
}
void aml_frddr_select_dst(struct frddr *fr, enum frddr_dest dst)
@@ -868,6 +975,17 @@ void aml_aed_enable(bool enable, int aed_module)
}
}
static bool aml_check_aed_module(int dst)
{
bool is_module_aed = false;
if (attach_aed.enable
&& (dst == attach_aed.attach_module))
is_module_aed = true;
return is_module_aed;
}
static void aml_check_aed(bool enable, int dst)
{
/* check effect module is sync with crruent frddr dst */

View File

@@ -55,6 +55,16 @@ enum frddr_dest {
SPDIFOUT_B,
};
struct toddr_fmt {
unsigned int type;
unsigned int msb;
unsigned int lsb;
unsigned int endian;
unsigned int bit_depth;
unsigned int ch_num;
unsigned int rate;
};
/* to ddrs */
int fetch_toddr_index_by_src(int toddr_src);
struct toddr *fetch_toddr_by_src(int toddr_src);
@@ -69,9 +79,10 @@ unsigned int aml_toddr_get_position(struct toddr *to);
void aml_toddr_select_src(struct toddr *to, enum toddr_src);
void aml_toddr_enable(struct toddr *to, bool enable);
void aml_toddr_set_fifos(struct toddr *to, unsigned int thresh);
void aml_toddr_set_format(struct toddr *to,
unsigned int type, unsigned int msb, unsigned int lsb,
int ch_num, int bit_depth);
void aml_toddr_set_format(struct toddr *to, struct toddr_fmt *fmt);
void aml_toddr_insert_chanum(struct toddr *to);
unsigned int aml_toddr_read(struct toddr *to);
void aml_toddr_write(struct toddr *to, unsigned int val);
/* resample */
void aml_resample_enable(bool enable, int resample_module);

View File

@@ -619,13 +619,19 @@ static int aml_pdm_dai_prepare(
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
struct toddr *to = p_pdm->tddr;
struct toddr_fmt fmt;
unsigned int osr = 192;
/* to ddr pdmin */
fmt.type = toddr_type;
fmt.msb = 31;
fmt.lsb = lsb;
fmt.endian = 0;
fmt.bit_depth = bitwidth;
fmt.ch_num = runtime->channels;
fmt.rate = runtime->rate;
aml_toddr_select_src(to, PDMIN);
aml_toddr_set_format(to, toddr_type, 31, lsb,
runtime->channels,
bitwidth);
aml_toddr_set_format(to, &fmt);
aml_toddr_set_fifos(to, 0x40);
aml_pdm_ctrl(p_pdm->actrl,

View File

@@ -20,15 +20,20 @@
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <sound/soc.h>
#include <sound/tlv.h>
#include "resample.h"
#include "resample_hw.h"
#include "ddr_mngr.h"
#include "regs.h"
#include "iomap.h"
#define DRV_NAME "audioresample"
#define CLK_RATIO 256
struct resample_chipinfo {
bool dividor_fn;
};
@@ -50,6 +55,9 @@ struct audioresample {
/* resample to the rate */
int out_rate;
/* sync with auge_resample_texts */
int asr_idx;
bool enable;
};
@@ -63,23 +71,30 @@ static int resample_clk_set(struct audioresample *p_resample)
if (p_resample->enable) {
ret = clk_prepare_enable(p_resample->clk);
if (ret) {
pr_err("Can't enable resample_clk clock: %d\n", ret);
pr_err("Can't enable resample_clk clock: %d\n",
ret);
return -EINVAL;
}
ret = clk_prepare_enable(p_resample->sclk);
if (ret) {
pr_err("Can't enable resample_src clock: %d\n", ret);
pr_err("Can't enable resample_src clock: %d\n",
ret);
return -EINVAL;
}
if (p_resample->out_rate) {
clk_set_rate(p_resample->pll,
p_resample->out_rate * CLK_RATIO * 2);
clk_set_rate(p_resample->sclk,
p_resample->out_rate * 256);
p_resample->out_rate * CLK_RATIO);
clk_set_rate(p_resample->clk,
p_resample->out_rate * 256);
p_resample->out_rate * CLK_RATIO);
} else {
/* defaule resample clk */
clk_set_rate(p_resample->sclk, 48000 * 256);
clk_set_rate(p_resample->clk, 48000 * 256);
clk_set_rate(p_resample->pll, 48000 * CLK_RATIO * 2);
clk_set_rate(p_resample->sclk, 48000 * CLK_RATIO);
clk_set_rate(p_resample->clk, 48000 * CLK_RATIO);
}
ret = clk_prepare_enable(p_resample->pll);
@@ -104,10 +119,10 @@ static int resample_clk_set(struct audioresample *p_resample)
static void audio_resample_init(struct audioresample *p_resample)
{
resample_clk_set(p_resample);
aml_resample_enable(p_resample->enable,
p_resample->resample_module);
resample_clk_set(p_resample);
}
static int audio_resample_set(int enable, int rate)
@@ -124,8 +139,6 @@ static int audio_resample_set(int enable, int rate)
return 0;
}
static int auge_resample;
static const char *const auge_resample_texts[] = {
"Disable",
"Enable:32K",
@@ -137,6 +150,30 @@ static const char *const auge_resample_texts[] = {
"Enable:192K",
};
static int resample_idx2rate(int index)
{
int rate = 0;
if (index == 0)
rate = 0;
else if (index == 1)
rate = 32000;
else if (index == 2)
rate = 44100;
else if (index == 3)
rate = 48000;
else if (index == 4)
rate = 88200;
else if (index == 5)
rate = 96000;
else if (index == 6)
rate = 176400;
else if (index == 7)
rate = 192000;
return rate;
}
static const struct soc_enum auge_resample_enum =
SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(auge_resample_texts),
auge_resample_texts);
@@ -145,7 +182,36 @@ static int resample_get_enum(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
ucontrol->value.enumerated.item[0] = auge_resample;
struct audioresample *p_resample = snd_kcontrol_chip(kcontrol);
ucontrol->value.enumerated.item[0] = p_resample->asr_idx;
return 0;
}
int resample_set(int index)
{
int resample_rate = resample_idx2rate(index);
if (index == s_resample->asr_idx)
return 0;
s_resample->asr_idx = index;
pr_info("%s %s\n",
__func__,
auge_resample_texts[index]);
if (audio_resample_set(index, resample_rate))
return 0;
if ((index == 0) || (resample_rate == 0))
resample_disable();
else {
resample_init(resample_rate);
resample_set_hw_param(index - 1);
}
return 0;
}
@@ -154,51 +220,9 @@ static int resample_set_enum(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
/* struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
* struct aml_audio_private_data *p_aml_audio =
* snd_soc_card_get_drvdata(card);
* struct aml_card_info *p_cardinfo = p_aml_audio->cardinfo;
*/
int index = ucontrol->value.enumerated.item[0];
int resample_rate = 0;
if (index == 0)
resample_rate = 0;
else if (index == 1)
resample_rate = 32000;
else if (index == 2)
resample_rate = 44100;
else if (index == 3)
resample_rate = 48000;
else if (index == 4)
resample_rate = 88200;
else if (index == 5)
resample_rate = 96000;
else if (index == 6)
resample_rate = 176400;
else if (index == 7)
resample_rate = 192000;
else
return 0;
auge_resample = index;
if (audio_resample_set(index, resample_rate))
return 0;
if (index == 0)
resample_disable();
else {
resample_enable(resample_rate);
// TODO: fixe me
resample_set_hw_param(index - 1);
}
/*
* if (index > 0
* && p_aml_audio
* && p_cardinfo)
* p_cardinfo->set_resample_param(index - 1);
*/
resample_set(index);
return 0;
}
@@ -246,9 +270,61 @@ static int mixer_audiobus_write(
return 0;
}
static const struct snd_kcontrol_new snd_resample_controls[] = {
/* resample module
* keep sync with enum toddr_src in ddr_mngr.h
*/
static const char *const auge_resample_module_texts[] = {
"TDMIN_A",
"TDMIN_B",
"TDMIN_C",
"SPDIFIN",
"PDMIN",
"NONE",
"TDMIN_LB",
"LOOPBACK",
};
/* resample */
static const struct soc_enum auge_resample_module_enum =
SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(auge_resample_module_texts),
auge_resample_module_texts);
static int resample_module_get_enum(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct audioresample *p_resample = snd_kcontrol_chip(kcontrol);
if (!p_resample) {
pr_err("audio resample is not init\n");
return -EINVAL;
}
ucontrol->value.enumerated.item[0] = p_resample->resample_module;
return 0;
}
static int resample_module_set_enum(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct audioresample *p_resample = snd_kcontrol_chip(kcontrol);
if (!p_resample) {
pr_err("audio resample is not init\n");
return -EINVAL;
}
p_resample->resample_module = ucontrol->value.enumerated.item[0];
/* update info to ddr */
aml_resample_enable(p_resample->enable,
p_resample->resample_module);
return 0;
}
static const struct snd_kcontrol_new snd_resample_controls[] = {
SOC_ENUM_EXT("Hardware resample enable",
auge_resample_enum,
resample_get_enum,
@@ -261,12 +337,26 @@ static const struct snd_kcontrol_new snd_resample_controls[] = {
EE_AUDIO_RESAMPLE_CTRL2, 0, 0xffffff, 0,
mixer_audiobus_read, mixer_audiobus_write,
NULL),
SOC_ENUM_EXT("Hardware resample module",
auge_resample_module_enum,
resample_module_get_enum,
resample_module_set_enum),
};
int card_add_resample_kcontrols(struct snd_soc_card *card)
{
return snd_soc_add_card_controls(card,
snd_resample_controls, ARRAY_SIZE(snd_resample_controls));
unsigned int idx;
int err;
for (idx = 0; idx < ARRAY_SIZE(snd_resample_controls); idx++) {
err = snd_ctl_add(card->snd_card,
snd_ctl_new1(&snd_resample_controls[idx],
s_resample));
if (err < 0)
return err;
}
return 0;
}
static struct resample_chipinfo g12a_resample_chipinfo = {

View File

@@ -19,4 +19,5 @@
extern int card_add_resample_kcontrols(struct snd_soc_card *card);
extern int resample_set(int index);
#endif

View File

@@ -14,8 +14,11 @@
* more details.
*
*/
#include <linux/clk.h>
#include "resample_hw.h"
#include "regs.h"
#include "iomap.h"
/*Cnt_ctrl = mclk/fs_out-1 ; fest 256fs */
#define RESAMPLE_CNT_CONTROL 255
@@ -37,22 +40,39 @@ static u32 resample_coef_parameters_table[7][5] = {
{0x00800000, 0x0, 0x0, 0x0, 0x0},
};
int resample_enable(int input_sr)
void resample_enable(bool enable)
{
audiobus_update_bits(EE_AUDIO_RESAMPLE_CTRL0,
0x1 << 31,
1 << 31);
audiobus_update_bits(EE_AUDIO_RESAMPLE_CTRL0,
0x1 << 31,
0 << 31);
audiobus_update_bits(EE_AUDIO_RESAMPLE_CTRL0,
0x1 << 28,
enable << 28);
}
int resample_init(int input_sr)
{
u16 Avg_cnt_init = 0;
unsigned int clk_rate = 167000000;//clk81;
Avg_cnt_init = (u16)(clk_rate * 4 / input_sr);
if (input_sr)
Avg_cnt_init = (u16)(clk_rate * 4 / input_sr);
else
pr_err("unsupport input sample rate:%d\n", input_sr);
pr_info("clk_rate = %u, input_sr = %d, Avg_cnt_init = %u\n",
clk_rate, input_sr, Avg_cnt_init);
audiobus_write(EE_AUDIO_RESAMPLE_CTRL0, (1 << 31));
audiobus_write(EE_AUDIO_RESAMPLE_CTRL0, 0);
audiobus_write(EE_AUDIO_RESAMPLE_CTRL0,
(1 << 28) /* enable */
| (0 << 26) /* method0 */
| (RESAMPLE_CNT_CONTROL << 16)
| Avg_cnt_init);
audiobus_update_bits(EE_AUDIO_RESAMPLE_CTRL0,
0x3 << 26 | 0x3ff << 16 | 0xffff << 0,
0x0 << 26 | /* method0 */
RESAMPLE_CNT_CONTROL << 16 |
Avg_cnt_init << 0);
return 0;
}
@@ -91,3 +111,13 @@ void resample_format_set(int ch_num, int bits)
audiobus_write(EE_AUDIO_RESAMPLE_CTRL3,
ch_num << 8 | (bits - 1) << 0);
}
int resample_ctrl_read(int idx)
{
return audiobus_read(EE_AUDIO_RESAMPLE_CTRL0);
}
void resample_ctrl_write(int idx, int value)
{
audiobus_write(EE_AUDIO_RESAMPLE_CTRL0, value);
}

View File

@@ -16,15 +16,15 @@
*/
#ifndef __AML_AUDIO_RESAMPLE_HW_H__
#define __AML_AUDIO_RESAMPLE_HW_H__
#include <linux/clk.h>
#include "regs.h"
#include "iomap.h"
extern int resample_enable(int input_sr);
extern void resample_enable(bool enable);
extern int resample_init(int input_sr);
extern int resample_disable(void);
extern int resample_set_hw_param(int index);
extern void resample_src_select(int src);
extern void resample_format_set(int ch_num, int bits);
extern int resample_ctrl_read(int idx);
extern void resample_ctrl_write(int idx, int value);
#endif

View File

@@ -37,6 +37,8 @@
#include "ddr_mngr.h"
#include "spdif_hw.h"
#include "audio_utils.h"
#include "resample.h"
#include "resample_hw.h"
#define DRV_NAME "aml_spdif"
@@ -46,15 +48,22 @@
/* Debug by PTM when bringup */
/* #define G12A_PTM */
/* for debug */
/*#define __SPDIFIN_INSERT_CHNUM__*/
struct spdif_chipinfo {
unsigned int id;
/* add ch_cnt to ch_num */
bool chnum_en;
/* Reg_clr_interrupt[7:0] for each bit of irq_status[7:0]; */
bool clr_irq_bits;
/* find PaPb */
bool irq_papb;
/*
* axg, clear all irq bits
* after axg, such as g12a, clear each bits
* Reg_clr_interrupt[7:0] for each bit of irq_status[7:0];
*/
bool clr_irq_all_bits;
/* no PaPb irq */
bool irq_no_papb;
/* reg_hold_start_en; 1: add delay to match TDM out when share buff; */
bool hold_start;
/* eq/drc */
@@ -83,6 +92,27 @@ struct aml_spdif {
unsigned int id;
struct spdif_chipinfo *chipinfo;
unsigned int clk_cont; /* CONTINUOUS CLOCK */
/* spdif in do asrc for pcm,
* if raw data, disable it automatically.
*/
unsigned int auto_asrc;
/* check spdifin channel status for pcm or nonpcm */
struct timer_list timer;
struct work_struct work;
/* spdif in reset for l/r channel swap when plug/unplug */
struct timer_list reset_timer;
/* timer is used */
int is_reset_timer_used;
/* reset timer counter */
int timer_counter;
/* 0: default, 1: spdif in firstly enable, 2: spdif in could be reset */
int sample_rate_detect_start;
/* is spdif in reset */
int is_reset;
int last_sample_rate_mode;
};
static const struct snd_pcm_hardware aml_spdif_hardware = {
@@ -102,7 +132,7 @@ static const struct snd_pcm_hardware aml_spdif_hardware = {
.buffer_bytes_max = 256 * 1024,
.rate_min = 8000,
.rate_max = 48000,
.rate_max = 192000,
.channels_min = 2,
.channels_max = 32,
};
@@ -114,24 +144,14 @@ static const unsigned int spdifin_extcon[] = {
};
/* current sample mode and its sample rate */
int sample_mode[] = {
24000,
32000,
44100,
46000,
48000,
96000,
192000,
};
static const char *const spdifin_samplerate[] = {
"N/A",
"24000",
"32000",
"44100",
"46000",
"48000",
"88200",
"96000",
"176400",
"192000"
};
@@ -187,18 +207,17 @@ static const struct sppdif_audio_info type_texts[] = {
{6, 0x003, "PAUSE"},
{6, 0x100, "PAUSE"},
};
static const struct soc_enum spdif_audio_type_enum =
SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(spdif_audio_type_texts),
spdif_audio_type_texts);
static int spdifin_audio_type_get_enum(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
static int spdifin_check_audio_type(void)
{
int audio_type = 0;
int i;
int total_num = sizeof(type_texts)/sizeof(struct sppdif_audio_info);
int pc = spdifin_get_audio_type();
int audio_type = 0;
int i;
for (i = 0; i < total_num; i++) {
if (pc == type_texts[i].pc) {
@@ -206,7 +225,18 @@ static int spdifin_audio_type_get_enum(
break;
}
}
ucontrol->value.enumerated.item[0] = audio_type;
pr_info("%s audio type:%d\n", __func__, audio_type);
return audio_type;
}
static int spdifin_audio_type_get_enum(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
ucontrol->value.enumerated.item[0] =
spdifin_check_audio_type();
return 0;
}
@@ -223,54 +253,271 @@ static const struct snd_kcontrol_new snd_spdif_controls[] = {
NULL),
};
static bool spdifin_check_audiotype_by_sw(struct aml_spdif *p_spdif)
{
if (p_spdif
&& p_spdif->chipinfo
&& p_spdif->chipinfo->irq_no_papb)
return true;
return false;
}
static void spdifin_audio_type_start_timer(
struct aml_spdif *p_spdif)
{
p_spdif->timer.expires = jiffies + 1;
add_timer(&p_spdif->timer);
}
static void spdifin_audio_type_stop_timer(
struct aml_spdif *p_spdif)
{
del_timer(&p_spdif->timer);
}
static void spdifin_audio_type_timer_func(unsigned long data)
{
struct aml_spdif *p_spdif = (struct aml_spdif *)data;
unsigned long delay = msecs_to_jiffies(1);
schedule_work(&p_spdif->work);
mod_timer(&p_spdif->timer, jiffies + delay);
}
static void spdifin_audio_type_work_func(struct work_struct *work)
{
struct aml_spdif *p_spdif = container_of(
work, struct aml_spdif, work);
int val = spdifin_get_ch_status0to31();
/* auto resample ? */
if (!p_spdif->auto_asrc)
return;
if (val & 0x2)
/* nonpcm, resample disable */
resample_set(0);
else
/* pcm, resample which rate ? */
resample_set(p_spdif->auto_asrc);
}
static void spdifin_audio_type_detect_init(struct aml_spdif *p_spdif)
{
init_timer(&p_spdif->timer);
p_spdif->timer.function = spdifin_audio_type_timer_func;
p_spdif->timer.data = (unsigned long)p_spdif;
INIT_WORK(&p_spdif->work, spdifin_audio_type_work_func);
}
static void spdifin_audio_type_detect_deinit(struct aml_spdif *p_spdif)
{
cancel_work_sync(&p_spdif->work);
}
static void spdifin_fast_reset(struct aml_spdif *p_spdif)
{
struct aml_audio_controller *actrl = p_spdif->actrl;
unsigned int tddr_val = aml_toddr_read(p_spdif->tddr);
unsigned int spdifin_ctrl_val = aml_spdif_ctrl_read(actrl,
SNDRV_PCM_STREAM_CAPTURE, p_spdif->id);
unsigned int asr_ctrl_val = 0;
pr_info("%s\n", __func__);
/* toddr disable */
tddr_val &= ~(1 << 31);
aml_toddr_write(p_spdif->tddr, tddr_val);
/* resample disable and reset */
if (p_spdif->auto_asrc) {
asr_ctrl_val = resample_ctrl_read(0);
asr_ctrl_val &= ~(1 << 28);
resample_ctrl_write(0, asr_ctrl_val);
asr_ctrl_val |= (1 << 31);
resample_ctrl_write(0, asr_ctrl_val);
asr_ctrl_val &= ~(1 << 31);
resample_ctrl_write(0, asr_ctrl_val);
}
/* spdif in disable and reset */
spdifin_ctrl_val &= ~(0x1 << 31);
aml_spdif_ctrl_write(actrl,
SNDRV_PCM_STREAM_CAPTURE, p_spdif->id, spdifin_ctrl_val);
spdifin_ctrl_val &= ~(0x3 << 28);
aml_spdif_ctrl_write(actrl,
SNDRV_PCM_STREAM_CAPTURE, p_spdif->id, spdifin_ctrl_val);
spdifin_ctrl_val |= (0x1 << 29);
aml_spdif_ctrl_write(actrl,
SNDRV_PCM_STREAM_CAPTURE, p_spdif->id, spdifin_ctrl_val);
spdifin_ctrl_val |= (0x1 << 28);
aml_spdif_ctrl_write(actrl,
SNDRV_PCM_STREAM_CAPTURE, p_spdif->id, spdifin_ctrl_val);
/* toddr enable */
tddr_val |= (1 << 31);
aml_toddr_write(p_spdif->tddr, tddr_val);
/* resample enable */
if (p_spdif->auto_asrc) {
asr_ctrl_val |= (1 << 28);
resample_ctrl_write(0, asr_ctrl_val);
}
/* spdif in enable */
spdifin_ctrl_val |= (0x1 << 31);
aml_spdif_ctrl_write(actrl,
SNDRV_PCM_STREAM_CAPTURE, p_spdif->id, spdifin_ctrl_val);
}
#define MAX_TIMER_COUNTER 30
#define FIRST_DELAY 20
static void spdifin_reset_timer(unsigned long data)
{
struct aml_spdif *p_spdif = (struct aml_spdif *)data;
unsigned long delay = msecs_to_jiffies(1);
int intrpt_status = aml_spdifin_status_check(p_spdif->actrl);
int mode = (intrpt_status >> 28) & 0x7;
if ((p_spdif->last_sample_rate_mode != mode) ||
(p_spdif->last_sample_rate_mode == 0x7)) {
p_spdif->last_sample_rate_mode = mode;
p_spdif->timer_counter = 0;
mod_timer(&p_spdif->reset_timer, jiffies + delay);
} else if ((p_spdif->last_sample_rate_mode == mode) &&
(mode != 0x7)) {
if (p_spdif->timer_counter > MAX_TIMER_COUNTER) {
p_spdif->timer_counter = 0;
if (p_spdif->is_reset ||
(p_spdif->sample_rate_detect_start == 1)) {
p_spdif->is_reset = 0;
p_spdif->sample_rate_detect_start = 2;
if (p_spdif->is_reset_timer_used) {
p_spdif->is_reset_timer_used = 0;
del_timer(&p_spdif->reset_timer);
}
pr_debug("%s,last sample mode:0x%x, stop timer\n",
__func__,
p_spdif->last_sample_rate_mode);
} else {
p_spdif->last_sample_rate_mode = 0;
p_spdif->is_reset = 1;
spdifin_fast_reset(p_spdif);
delay = msecs_to_jiffies(FIRST_DELAY);
mod_timer(&p_spdif->reset_timer,
jiffies + delay);
}
} else {
p_spdif->timer_counter++;
mod_timer(&p_spdif->reset_timer, jiffies + delay);
}
}
}
static void spdifin_status_event(struct aml_spdif *p_spdif)
{
int intrpt_status;
if (p_spdif == NULL)
if (!p_spdif)
return;
/*
* interrupt status, check and clear by reg_clk_interrupt;
*/
/* interrupt status, check and clear by reg_clk_interrupt */
intrpt_status = aml_spdifin_status_check(p_spdif->actrl);
/* clear irq bits immediametely */
if (p_spdif->chipinfo)
aml_spdifin_clr_irq(p_spdif->actrl,
p_spdif->chipinfo->clr_irq_all_bits,
intrpt_status & 0xff);
if (intrpt_status & 0x1)
pr_warn_once("over flow!!\n");
pr_info("over flow!!\n");
if (intrpt_status & 0x2)
pr_warn_once("parity error\n");
pr_info("parity error\n");
if (intrpt_status & 0x4) {
int mode = (intrpt_status >> 28) & 0x7;
pr_warn_once("sample mode changed\n");
if (mode == 0x7) {
pr_debug("Default value, not detect sample rate\n");
pr_debug("sample rate, mode:%x\n", mode);
if (/*(mode == 0x7) && */(!p_spdif->sample_rate_detect_start)) {
p_spdif->sample_rate_detect_start = 1;
pr_debug("spdif in sample rate started\n");
}
if (p_spdif->sample_rate_detect_start) {
p_spdif->last_sample_rate_mode = mode;
if (!p_spdif->is_reset_timer_used) {
unsigned long delay = msecs_to_jiffies(1);
if (p_spdif->sample_rate_detect_start == 1)
delay = msecs_to_jiffies(FIRST_DELAY);
setup_timer(&p_spdif->reset_timer,
spdifin_reset_timer,
(unsigned long)p_spdif);
mod_timer(&p_spdif->reset_timer,
jiffies + delay);
}
p_spdif->is_reset_timer_used++;
p_spdif->timer_counter = 0;
}
if ((mode == 0x7) ||
(((intrpt_status >> 18) & 0x3ff) == 0x3ff)) {
pr_info("Default value, not detect sample rate\n");
extcon_set_state(p_spdif->edev,
EXTCON_SPDIFIN_SAMPLERATE, 0);
} else if (mode >= 0) {
pr_debug("Event: EXTCON_SPDIFIN_SAMPLERATE, new sample rate:%d\n",
sample_mode[mode]);
if (p_spdif->last_sample_rate_mode != mode) {
pr_info("Event: EXTCON_SPDIFIN_SAMPLERATE, new sample rate:%s\n",
spdifin_samplerate[mode + 1]);
extcon_set_state(p_spdif->edev,
EXTCON_SPDIFIN_SAMPLERATE, 1);
/* resample enable, by hw */
if (!spdifin_check_audiotype_by_sw(p_spdif))
resample_set(p_spdif->auto_asrc);
extcon_set_state(p_spdif->edev,
EXTCON_SPDIFIN_SAMPLERATE, 1);
}
}
p_spdif->last_sample_rate_mode = mode;
}
if (intrpt_status & 0x8) {
pr_warn_once("Pc changed, try to read spdifin audio type\n");
pr_info("Pc changed, try to read spdifin audio type\n");
extcon_set_state(p_spdif->edev,
EXTCON_SPDIFIN_AUDIOTYPE, 1);
} else
/* resample disable, by hw */
if (!spdifin_check_audiotype_by_sw(p_spdif))
resample_set(0);
}
if (intrpt_status & 0x10)
pr_info("Pd changed\n");
if (intrpt_status & 0x20) {
pr_info("nonpcm to pcm\n");
extcon_set_state(p_spdif->edev,
EXTCON_SPDIFIN_AUDIOTYPE, 0);
if (intrpt_status & 0x10)
pr_warn_once("Pd changed\n");
if (intrpt_status & 0x20)
pr_warn_once("nonpcm to pcm\n");
/* resample to 48k, by hw */
if (!spdifin_check_audiotype_by_sw(p_spdif))
resample_set(p_spdif->auto_asrc);
}
if (intrpt_status & 0x40)
pr_warn_once("valid changed\n");
pr_info("valid changed\n");
}
static irqreturn_t aml_spdif_ddr_isr(int irq, void *devid)
@@ -291,8 +538,6 @@ static irqreturn_t aml_spdifin_status_isr(int irq, void *devid)
{
struct aml_spdif *p_spdif = (struct aml_spdif *)devid;
aml_spdifin_status_check(p_spdif->actrl);
spdifin_status_event(p_spdif);
return IRQ_HANDLED;
@@ -306,7 +551,7 @@ static int aml_spdif_open(struct snd_pcm_substream *substream)
struct aml_spdif *p_spdif;
int ret = 0;
pr_info("asoc debug: %s-%d\n", __func__, __LINE__);
pr_info("%s\n", __func__);
p_spdif = (struct aml_spdif *)dev_get_drvdata(dev);
@@ -337,6 +582,10 @@ static int aml_spdif_open(struct snd_pcm_substream *substream)
p_spdif->irq_spdifin);
return ret;
}
if (spdifin_check_audiotype_by_sw(p_spdif))
spdifin_audio_type_detect_init(p_spdif);
p_spdif->sample_rate_detect_start = 0;
}
runtime->private_data = p_spdif;
@@ -350,13 +599,30 @@ static int aml_spdif_close(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
struct aml_spdif *p_spdif = runtime->private_data;
pr_info("asoc debug: %s-%d\n", __func__, __LINE__);
pr_info("%s\n", __func__);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
aml_audio_unregister_frddr(p_spdif->dev, substream);
} else {
aml_audio_unregister_toddr(p_spdif->dev, substream);
free_irq(p_spdif->irq_spdifin, p_spdif);
if (spdifin_check_audiotype_by_sw(p_spdif))
spdifin_audio_type_detect_deinit(p_spdif);
if (p_spdif->is_reset_timer_used) {
p_spdif->is_reset_timer_used = 0;
del_timer(&p_spdif->reset_timer);
}
/* clear extcon status */
if (p_spdif->id == 0) {
extcon_set_state(p_spdif->edev,
EXTCON_SPDIFIN_SAMPLERATE, 0);
extcon_set_state(p_spdif->edev,
EXTCON_SPDIFIN_AUDIOTYPE, 0);
}
}
runtime->private_data = NULL;
@@ -381,7 +647,30 @@ static int aml_spdif_hw_free(struct snd_pcm_substream *substream)
static int aml_spdif_trigger(struct snd_pcm_substream *substream, int cmd)
{
return 0;
struct snd_pcm_runtime *runtime = substream->runtime;
struct aml_spdif *p_spdif = runtime->private_data;
int ret = 0;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
if ((spdifin_check_audiotype_by_sw(p_spdif))
&& (substream->stream == SNDRV_PCM_STREAM_CAPTURE))
spdifin_audio_type_start_timer(p_spdif);
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
case SNDRV_PCM_TRIGGER_STOP:
if ((spdifin_check_audiotype_by_sw(p_spdif))
&& (substream->stream == SNDRV_PCM_STREAM_CAPTURE))
spdifin_audio_type_stop_timer(p_spdif);
break;
default:
ret = -EINVAL;
}
return ret;
}
static int aml_spdif_prepare(struct snd_pcm_substream *substream)
@@ -475,6 +764,7 @@ static int aml_spdif_new(struct snd_soc_pcm_runtime *rtd)
__func__,
(p_spdif->id == 0) ? "a":"b",
p_spdif->clk_cont);
/* keep frddr when probe, after spdif_frddr_init done
* frddr can be released, and spdif outputs zero data
* without frddr used.
@@ -498,6 +788,8 @@ static int aml_dai_spdif_probe(struct snd_soc_dai *cpu_dai)
struct aml_spdif *p_spdif = snd_soc_dai_get_drvdata(cpu_dai);
int ret = 0;
pr_info("%s\n", __func__);
if (p_spdif->id == SPDIF_A) {
ret = snd_soc_add_dai_controls(cpu_dai, snd_spdif_controls,
ARRAY_SIZE(snd_spdif_controls));
@@ -505,14 +797,12 @@ static int aml_dai_spdif_probe(struct snd_soc_dai *cpu_dai)
pr_err("%s, failed add snd spdif controls\n", __func__);
}
pr_info("asoc debug: %s-%d\n", __func__, __LINE__);
return 0;
}
static int aml_dai_spdif_remove(struct snd_soc_dai *cpu_dai)
{
pr_info("asoc debug: %s-%d\n", __func__, __LINE__);
pr_info("%s\n", __func__);
return 0;
}
@@ -524,7 +814,9 @@ static int aml_dai_spdif_startup(
struct aml_spdif *p_spdif = snd_soc_dai_get_drvdata(cpu_dai);
int ret;
pr_info("asoc debug: %s-%d\n", __func__, __LINE__);
pr_info("%s stream:%d\n",
__func__,
substream->stream);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
@@ -579,6 +871,9 @@ static int aml_dai_spdif_startup(
pr_err("Can't enable pcm clk_spdifin clock: %d\n", ret);
goto err;
}
/* resample to 48k in default, by hw */
if (!spdifin_check_audiotype_by_sw(p_spdif))
resample_set(p_spdif->auto_asrc);
}
return 0;
@@ -593,6 +888,10 @@ static void aml_dai_spdif_shutdown(
{
struct aml_spdif *p_spdif = snd_soc_dai_get_drvdata(cpu_dai);
pr_info("%s, stream:%d\n",
__func__,
substream->stream);
/* disable clock and gate */
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
if (p_spdif->clk_cont) {
@@ -605,6 +904,10 @@ static void aml_dai_spdif_shutdown(
clk_disable_unprepare(p_spdif->sysclk);
clk_disable_unprepare(p_spdif->gate_spdifout);
} else {
/* resample disabled, by hw */
if (!spdifin_check_audiotype_by_sw(p_spdif))
resample_set(0);
clk_disable_unprepare(p_spdif->clk_spdifin);
clk_disable_unprepare(p_spdif->fixed_clk);
clk_disable_unprepare(p_spdif->gate_spdifin);
@@ -657,6 +960,7 @@ static int aml_dai_spdif_prepare(
} else {
struct toddr *to = p_spdif->tddr;
struct toddr_fmt fmt;
unsigned int msb, lsb, toddr_type;
if (loopback_is_enable()) {
@@ -704,16 +1008,30 @@ static int aml_dai_spdif_prepare(
}
// to ddr spdifin
fmt.type = toddr_type;
fmt.msb = msb;
fmt.lsb = lsb;
fmt.endian = 0;
fmt.bit_depth = bit_depth;
fmt.ch_num = runtime->channels;
fmt.rate = runtime->rate;
aml_toddr_select_src(to, SPDIFIN);
aml_toddr_set_format(to, toddr_type, msb, lsb,
runtime->channels,
bit_depth);
aml_toddr_set_format(to, &fmt);
aml_toddr_set_fifos(to, 0x40);
#ifdef __SPDIFIN_INSERT_CHNUM__
aml_toddr_insert_chanum(to);
#endif
}
aml_spdif_fifo_ctrl(p_spdif->actrl, bit_depth,
substream->stream, p_spdif->id, fifo_id);
#ifdef __SPDIFIN_INSERT_CHNUM__
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
aml_spdifin_chnum_en(p_spdif->actrl,
p_spdif->id, true);
#endif
return 0;
}
@@ -741,6 +1059,7 @@ static int aml_dai_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
aml_spdif_enable(p_spdif->actrl,
substream->stream, p_spdif->id, true);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
@@ -769,7 +1088,6 @@ static int aml_dai_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
return 0;
}
static int aml_dai_spdif_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *cpu_dai)
@@ -778,14 +1096,13 @@ static int aml_dai_spdif_hw_params(struct snd_pcm_substream *substream,
unsigned int rate = params_rate(params);
int ret = 0;
pr_info("%s\n", __func__);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
rate *= 128;
snd_soc_dai_set_sysclk(cpu_dai,
0, rate, SND_SOC_CLOCK_OUT);
} else {
clk_set_rate(p_spdif->clk_spdifin, 250000000);
clk_set_rate(p_spdif->clk_spdifin, 500000000);
}
return ret;
@@ -793,9 +1110,7 @@ static int aml_dai_spdif_hw_params(struct snd_pcm_substream *substream,
static int aml_dai_set_spdif_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
{
struct aml_spdif *p_spdif = snd_soc_dai_get_drvdata(cpu_dai);
pr_info("asoc aml_dai_set_spdif_fmt, %#x, %p\n", fmt, p_spdif);
pr_info("%s , fmt %#x\n", __func__, fmt);
return 0;
}
@@ -804,8 +1119,10 @@ static void aml_set_spdifclk(struct aml_spdif *p_spdif)
{
unsigned int mpll_freq = 0;
pr_info("asoc debug: %s-%d, sys freq:%d\n", __func__, __LINE__,
pr_info("%s, sys freq:%d\n",
__func__,
p_spdif->sysclk_freq);
if (p_spdif->sysclk_freq) {
unsigned int mul = 4;
int ret;
@@ -821,6 +1138,10 @@ static void aml_set_spdifclk(struct aml_spdif *p_spdif)
#ifdef G12A_PTM
mpll_freq = p_spdif->sysclk_freq * 57;
#endif
pr_info("\t finally sys freq:%d, mpll freq:%d\n",
p_spdif->sysclk_freq,
mpll_freq);
clk_set_rate(p_spdif->sysclk, mpll_freq);
clk_set_rate(p_spdif->clk_spdifout,
p_spdif->sysclk_freq);
@@ -841,13 +1162,18 @@ static void aml_set_spdifclk(struct aml_spdif *p_spdif)
static int aml_dai_set_spdif_sysclk(struct snd_soc_dai *cpu_dai,
int clk_id, unsigned int freq, int dir)
{
struct aml_spdif *p_spdif = snd_soc_dai_get_drvdata(cpu_dai);
pr_info("%s, clk_id:%d, freq:%d, dir:%d\n",
__func__,
clk_id,
freq,
dir);
p_spdif->sysclk_freq = freq;
pr_info("aml_dai_set_spdif_sysclk, %d, %d, %d\n",
clk_id, freq, dir);
if (dir == SND_SOC_CLOCK_OUT) {
struct aml_spdif *p_spdif = snd_soc_dai_get_drvdata(cpu_dai);
aml_set_spdifclk(p_spdif);
p_spdif->sysclk_freq = freq;
aml_set_spdifclk(p_spdif);
}
return 0;
}
@@ -970,6 +1296,14 @@ static int aml_spdif_parse_of(struct platform_device *pdev)
ret = extcon_dev_register(p_spdif->edev);
if (ret < 0)
pr_err("SPDIF IN extcon failed to register!!, ignore it\n");
ret = of_property_read_u32(pdev->dev.of_node,
"auto_asrc", &p_spdif->auto_asrc);
if (ret < 0)
p_spdif->auto_asrc = 0;
pr_info("SPDIF id %d auto_asrc:%d\n",
p_spdif->id,
p_spdif->auto_asrc);
}
/* clock for spdif out */
@@ -996,14 +1330,14 @@ static int aml_spdif_parse_of(struct platform_device *pdev)
}
struct spdif_chipinfo axg_spdif_chipinfo = {
.id = SPDIF_A,
.id = SPDIF_A,
.irq_no_papb = true,
.clr_irq_all_bits = true,
};
struct spdif_chipinfo g12a_spdif_a_chipinfo = {
.id = SPDIF_A,
.chnum_en = true,
.clr_irq_bits = true,
.irq_papb = true,
.hold_start = true,
.eq_drc_en = true,
};
@@ -1011,8 +1345,6 @@ struct spdif_chipinfo g12a_spdif_a_chipinfo = {
struct spdif_chipinfo g12a_spdif_b_chipinfo = {
.id = SPDIF_B,
.chnum_en = true,
.clr_irq_bits = true,
.irq_papb = true,
.hold_start = true,
.eq_drc_en = true,
};
@@ -1058,11 +1390,10 @@ static int aml_spdif_platform_probe(struct platform_device *pdev)
of_device_get_match_data(dev);
if (p_spdif_chipinfo) {
aml_spdif->id = p_spdif_chipinfo->id;
/* for spdif_b, clk be continuous,
/* for spdif output zero data, clk be continuous,
* and keep silence when no valid data
*/
/*if (aml_spdif->id == 1)*/
aml_spdif->clk_cont = 1;
aml_spdif->clk_cont = 1;
aml_spdif->chipinfo = p_spdif_chipinfo;
} else

View File

@@ -26,6 +26,49 @@
/*#define G12A_PTM*/
/*#define G12A_PTM_LB_INTERNAL*/
unsigned int aml_spdif_ctrl_read(struct aml_audio_controller *actrl,
int stream, int index)
{
unsigned int offset, reg;
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
offset = EE_AUDIO_SPDIFOUT_B_CTRL0 - EE_AUDIO_SPDIFOUT_CTRL0;
reg = EE_AUDIO_SPDIFOUT_CTRL0 + offset * index;
} else {
reg = EE_AUDIO_SPDIFIN_CTRL0;
}
return aml_audiobus_read(actrl, reg);
}
void aml_spdif_ctrl_write(struct aml_audio_controller *actrl,
int stream, int index, int val)
{
unsigned int offset, reg;
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
offset = EE_AUDIO_SPDIFOUT_B_CTRL0 - EE_AUDIO_SPDIFOUT_CTRL0;
reg = EE_AUDIO_SPDIFOUT_CTRL0 + offset * index;
} else {
reg = EE_AUDIO_SPDIFIN_CTRL0;
}
aml_audiobus_write(actrl, reg, val);
}
void aml_spdifin_chnum_en(struct aml_audio_controller *actrl,
int index, bool is_enable)
{
unsigned int reg;
reg = EE_AUDIO_SPDIFIN_CTRL0;
aml_audiobus_update_bits(actrl, reg, 1 << 26, is_enable << 26);
pr_info("%s spdifin ctrl0:0x%x\n",
__func__,
aml_audiobus_read(actrl, reg));
}
void aml_spdif_enable(
struct aml_audio_controller *actrl,
int stream,
@@ -84,23 +127,31 @@ int aml_spdifin_status_check(struct aml_audio_controller *actrl)
{
unsigned int val;
val = aml_audiobus_read(actrl,
EE_AUDIO_SPDIFIN_STAT0);
val = aml_audiobus_read(actrl, EE_AUDIO_SPDIFIN_STAT0);
/* pr_info("\t--- spdif handles status0 %#x\n", val); */
aml_audiobus_update_bits(actrl,
EE_AUDIO_SPDIFIN_CTRL0,
1<<26,
1<<26);
aml_audiobus_update_bits(actrl,
EE_AUDIO_SPDIFIN_CTRL0,
1<<26,
0);
return val;
}
void aml_spdifin_clr_irq(struct aml_audio_controller *actrl,
bool is_all_bits, int clr_bits_val)
{
if (is_all_bits) {
aml_audiobus_update_bits(actrl,
EE_AUDIO_SPDIFIN_CTRL0,
1 << 26,
1 << 26);
aml_audiobus_update_bits(actrl,
EE_AUDIO_SPDIFIN_CTRL0,
1 << 26,
0);
} else
aml_audiobus_update_bits(actrl,
EE_AUDIO_SPDIFIN_CTRL6,
0xff << 16,
clr_bits_val << 16);
}
void aml_spdif_fifo_reset(
struct aml_audio_controller *actrl,
int stream, int index)
@@ -161,7 +212,10 @@ void aml_spdif_fifo_ctrl(
}
pr_info("%s, bit depth:%d, frddr type:%d, toddr:type:%d\n",
__func__, bitwidth, frddr_type, toddr_type);
__func__,
bitwidth,
frddr_type,
toddr_type);
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
unsigned int offset, reg;
@@ -187,61 +241,65 @@ void aml_spdif_fifo_ctrl(
reg,
1<<4);
} else {
unsigned int lsb;
unsigned int spdifin_clk = 500000000;
if (bitwidth <= 24)
lsb = 28 - bitwidth;
else
lsb = 4;
/* sysclk/rate/32(bit)/2(ch)/2(bmc) */
unsigned int counter_32k = (spdifin_clk / (32000 * 64));
unsigned int counter_44k = (spdifin_clk / (44100 * 64));
unsigned int counter_48k = (spdifin_clk / (48000 * 64));
unsigned int counter_88k = (spdifin_clk / (88200 * 64));
unsigned int counter_96k = (spdifin_clk / (96000 * 64));
unsigned int counter_176k = (spdifin_clk / (176400 * 64));
unsigned int counter_192k = (spdifin_clk / (192000 * 64));
unsigned int mode0_th = 3 * (counter_32k + counter_44k) >> 1;
unsigned int mode1_th = 3 * (counter_44k + counter_48k) >> 1;
unsigned int mode2_th = 3 * (counter_48k + counter_88k) >> 1;
unsigned int mode3_th = 3 * (counter_88k + counter_96k) >> 1;
unsigned int mode4_th = 3 * (counter_96k + counter_176k) >> 1;
unsigned int mode5_th = 3 * (counter_176k + counter_192k) >> 1;
unsigned int mode0_timer = counter_32k >> 1;
unsigned int mode1_timer = counter_44k >> 1;
unsigned int mode2_timer = counter_48k >> 1;
unsigned int mode3_timer = counter_88k >> 1;
unsigned int mode4_timer = counter_96k >> 1;
unsigned int mode5_timer = (counter_176k >> 1);
unsigned int mode6_timer = (counter_192k >> 1);
// 250M
#ifdef G12A_PTM
aml_audiobus_write(actrl,
EE_AUDIO_SPDIFIN_CTRL1,
25000 << 0);
#else
aml_audiobus_write(actrl,
EE_AUDIO_SPDIFIN_CTRL1,
0xff << 20 | 25000 << 0);
#endif
0xff << 20 | (spdifin_clk / 10000) << 0);
aml_audiobus_write(actrl,
EE_AUDIO_SPDIFIN_CTRL2,
140 << 20 | 100 << 10 | 86 << 0);
mode0_th << 20 |
mode1_th << 10 |
mode2_th << 0);
aml_audiobus_write(actrl,
EE_AUDIO_SPDIFIN_CTRL3,
83 << 20 | 60 << 10 | 30 << 0);
mode3_th << 20 |
mode4_th << 10 |
mode5_th << 0);
aml_audiobus_write(actrl,
EE_AUDIO_SPDIFIN_CTRL4,
(81<<24) | /* reg_sample_mode0_timer */
(61<<16) | /* reg_sample_mode1_timer */
(44<<8) | /* reg_sample_mode2_timer*/
(42<<0)
(mode0_timer << 24) |
(mode1_timer << 16) |
(mode2_timer << 8) |
(mode3_timer << 0)
);
#ifdef G12A_PTM
aml_audiobus_write(actrl,
EE_AUDIO_SPDIFIN_CTRL5,
(40<<24) |
(20<<16) |
(10<<8) |
(0<<0)
(mode4_timer << 24) |
(mode5_timer << 16) |
(mode6_timer << 8)
);
#else
aml_audiobus_write(actrl,
EE_AUDIO_SPDIFIN_CTRL5,
(40<<24) | /* reg_sample_mode4_timer = 5[31:24]; */
(20<<16) | /* reg_sample_mode5_timer = 5[23:16]; */
(9<<8) | /* reg_sample_mode6_timer = 5[15:8]; */
(0<<0) /* reg_sample_mode7_timer = 5[7:0]; */
);
#endif
aml_audiobus_update_bits(actrl,
EE_AUDIO_SPDIFIN_CTRL0,
0x3<<24|1<<12,
3<<24|1<<12);
0x1 << 25 | 0x1 << 24 | 0xfff << 12,
0x1 << 25 | 0x0 << 24 | 0xff << 12);
}
}
@@ -432,17 +490,36 @@ int spdifin_get_sample_rate(void)
val = audiobus_read(EE_AUDIO_SPDIFIN_STAT0);
/* NA when check min width of two edges */
if (((val >> 18) & 0x3ff) == 0x3ff)
return 0x7;
return (val >> 28) & 0x7;
}
static int spdifin_get_channel_status(int sel)
{
unsigned int val;
/* set ch_status_sel to channel status */
audiobus_update_bits(EE_AUDIO_SPDIFIN_CTRL0, 0xf << 8, sel << 8);
val = audiobus_read(EE_AUDIO_SPDIFIN_STAT1);
return val;
}
int spdifin_get_ch_status0to31(void)
{
return spdifin_get_channel_status(0x0);
}
int spdifin_get_audio_type(void)
{
unsigned int val;
/* set ch_status_sel to read Pc*/
audiobus_update_bits(EE_AUDIO_SPDIFIN_CTRL0, 0xf << 8, 0x6 << 8);
val = audiobus_read(EE_AUDIO_SPDIFIN_STAT1);
/* set ch_status_sel to read Pc */
val = spdifin_get_channel_status(0x6);
return (val >> 16) & 0xff;
}
@@ -557,7 +634,9 @@ void spdifout_play_with_zerodata(unsigned int spdif_id)
void spdifout_play_with_zerodata_free(unsigned int spdif_id)
{
pr_info("%s, spdif id:%d\n", __func__, spdif_id);
pr_info("%s, spdif id:%d\n",
__func__,
spdif_id);
/* free frddr, then frddr in mngr */
frddr_deinit_without_mngr(spdif_id);

View File

@@ -22,6 +22,12 @@
#include <linux/amlogic/media/sound/spdif_info.h>
extern unsigned int aml_spdif_ctrl_read(struct aml_audio_controller *actrl,
int stream, int index);
extern void aml_spdif_ctrl_write(struct aml_audio_controller *actrl,
int stream, int index, int val);
extern void aml_spdifin_chnum_en(struct aml_audio_controller *actrl,
int index, bool is_enable);
extern void aml_spdif_enable(
struct aml_audio_controller *actrl,
int stream,
@@ -38,6 +44,8 @@ extern void aml_spdif_arb_config(struct aml_audio_controller *actrl);
extern int aml_spdifin_status_check(
struct aml_audio_controller *actrl);
extern void aml_spdifin_clr_irq(struct aml_audio_controller *actrl,
bool is_all_bits, int clr_bits_val);
extern void aml_spdif_fifo_reset(
struct aml_audio_controller *actrl,
@@ -69,6 +77,8 @@ extern void spdifout_enable(int spdif_id, bool is_enable);
extern int spdifin_get_sample_rate(void);
extern int spdifin_get_ch_status0to31(void);
extern int spdifin_get_audio_type(void);
extern void spdif_set_channel_status_info(

View File

@@ -451,6 +451,7 @@ static int aml_dai_tdm_prepare(struct snd_pcm_substream *substream,
enum toddr_src src;
unsigned int lsb = 32 - bit_depth;
unsigned int toddr_type;
struct toddr_fmt fmt;
switch (bit_depth) {
case 8:
@@ -484,10 +485,15 @@ static int aml_dai_tdm_prepare(struct snd_pcm_substream *substream,
return -EINVAL;
}
fmt.type = toddr_type;
fmt.msb = 31;
fmt.lsb = lsb;
fmt.endian = 0;
fmt.bit_depth = bit_depth;
fmt.ch_num = runtime->channels;
fmt.rate = runtime->rate;
aml_toddr_select_src(to, src);
aml_toddr_set_format(to, toddr_type, 31, lsb,
runtime->channels,
bit_depth);
aml_toddr_set_format(to, &fmt);
aml_toddr_set_fifos(to, 0x40);
}