audio: auge: fix audio locker, resample, tdm format, eq/drc, share buffer

PD#156734: audio: auge: fix audio locker, resample, tdm format, eq/drc, share buffer

Change-Id: I03750c34310bdbc32eddc51f64cf4b91a95325bc
Signed-off-by: Xing Wang <xing.wang@amlogic.com>
This commit is contained in:
Xing Wang
2018-02-06 17:21:00 +08:00
committed by Yixun Lan
parent 6ad73d85b6
commit af785cdbe3
25 changed files with 630 additions and 134 deletions

View File

@@ -14355,3 +14355,7 @@ AMLOGIC THERMAL DRIVER
M: Huan Biao <huan.biao@amlogic.com>
F: drivers/amlgoic/thermal/meson_tsensor.c
F: drivers/amlogic/thermal/meson_cooldev.c
AMLOGIC G12A Audio DRIVER
M: Xing Wang <xing.wang@amlogic.com>
F: sound/soc/amlogic/auge/*

View File

@@ -944,14 +944,35 @@
tdmout_index = <1>;
status = "okay";
};
audio_effect:eqdrc{
/*eq_enable = <1>;*/
/*drc_enable = <1>;*/
/*
* 0:tdmout_a
* 1:tdmout_b
* 2:tdmout_c
* 3:spdifout
* 4:spdifout_b
*/
eqdrc_module = <1>;
/* max 0xf, each bit for one lane, usually one lane */
lane_mask = <0x1>;
/* max 0xff, each bit for one channel */
channel_mask = <0x3>;
};
auge_sound {
compatible = "amlogic, g12a-sound-card";
aml-audio-card,name = "AML-AUGESOUND";
aml-audio-card,loopback = <&aml_loopback>;
aml-audio-card,aux-devs = <&amlogic_codec>;
/*avout mute gpio*/
avout_mute-gpios = <&gpio_ao GPIOAO_2 GPIO_ACTIVE_HIGH>;
/*for audio effect ,eqdrc */
aml-audio-card,effect = <&audio_effect>;
aml-audio-card,dai-link@0 {
format = "dsp_a";
mclk-fs = <512>;
@@ -976,38 +997,42 @@
};
aml-audio-card,dai-link@1 {
format = "i2s"; /*"dsp_a";*/
format = "i2s";// "dsp_a";
mclk-fs = <256>;
//continuous-clock;
//bitclock-inversion;
//frame-inversion;
bitclock-master = <&aml_tdmb>;
frame-master = <&aml_tdmb>;
//bitclock-master = <&tdmbcodec>;
//frame-master = <&tdmbcodec>;
cpu {
sound-dai = <&aml_tdmb>;
dai-tdm-slot-tx-mask = <1 1>;
dai-tdm-slot-rx-mask = <1 1>;
dai-tdm-slot-num = <2>;
/*
* dai-tdm-slot-tx-mask =
* <1 1 1 1 1 1 1 1>;
* dai-tdm-slot-rx-mask =
* <1 1 1 1 1 1 1 1>;
* dai-tdm-slot-num = <8>;
*/
/*
* dai-tdm-slot-tx-mask =
* <1 1 1 1 1 1 1 1>;
* dai-tdm-slot-rx-mask =
* <1 1 1 1 1 1 1 1>;
* dai-tdm-slot-num = <8>;
*/
dai-tdm-slot-width = <32>;
system-clock-frequency = <12288000>;
};
codec {
sound-dai = <&dummy_codec &amlogic_codec
/*&ad82584f_62*/>;
tdmbcodec: codec {
sound-dai = <&dummy_codec &dummy_codec
&amlogic_codec /*&ad82584f_62*/>;
};
};
aml-audio-card,dai-link@2 {
format = "i2s";
mclk-fs = <256>;
continuous-clock;
//continuous-clock;
//bitclock-inversion;
//frame-inversion;
bitclock-master = <&aml_tdmc>;
@@ -1070,7 +1095,7 @@
interrupt-names = "irq";
frequency = <49000000>; /* pll */
dividor = <49>; /* locker's parent */
status = "disabled";
status = "okay";
};
/* Audio Related end */
@@ -1336,8 +1361,8 @@
aml_tdma: tdma {
compatible = "amlogic, g12a-snd-tdma";
#sound-dai-cells = <0>;
dai-tdm-lane-slot-mask-in = <1 0>;
dai-tdm-lane-slot-mask-out = <0 1>;
dai-tdm-lane-slot-mask-in = <0 1>;
dai-tdm-oe-lane-slot-mask-out = <1 0>;
dai-tdm-clk-sel = <0>;
clocks = <&clkaudio CLKID_AUDIO_MCLK_A
&clkc CLKID_MPLL0>;
@@ -1357,6 +1382,14 @@
clock-names = "mclk", "clk_srcpll";
pinctrl-names = "tdm_pins";
pinctrl-0 = <&tdmb_mclk &tdmout_b &tdmin_b>;
/*
* 0: tdmout_a;
* 1: tdmout_b;
* 2: tdmout_c;
* 3: spdifout;
* 4: spdifout_b;
*/
samesource_sel = <4>;
};
aml_tdmc: tdmc {
@@ -1401,8 +1434,6 @@
&clkaudio CLKID_AUDIO_SPDIFOUTB_CTRL>;
clock-names = "sysclk",
"gate_spdifout", "clk_spdifout";
//pinctrl-names = "spdif_pins";
//pinctrl-0 = <&spdifout>;
status = "okay";
};
aml_pdm: pdm {
@@ -1423,6 +1454,59 @@
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 = <0x3f>;
/* 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";
};
audioresample: resample {
compatible = "amlogic, g12a-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, 0
* TDMIN_B, 1
* TDMIN_C, 2
* SPDIFIN, 3
* PDMIN, 4
* NONE,
* TDMIN_LB, 6
* LOOPBACK, 7
*/
resample_module = <4>;
status = "okay";
};
aml_pwrdet: pwrdet {
compatible = "amlogic, g12a-power-detect";
@@ -1444,7 +1528,7 @@
hi_th = <0x70000>;
lo_th = <0x16000>;
status = "disabled";
status = "okay";
};
}; /* end of audiobus */
@@ -1469,6 +1553,7 @@
mux {
groups = "mclk0_a";
function = "mclk0";
drive-strength = <2>;
};
};
tdmout_b: tdmout_b {
@@ -1477,13 +1562,16 @@
"tdmb_fs",
"tdmb_dout0";
function = "tdmb_out";
drive-strength = <2>;
};
};
tdmin_b:tdmin_b {
mux { /* GPIOA_4 */
groups = "tdmb_din1";
groups = "tdmb_din1"
/*,"tdmb_slv_sclk", "tdmb_slv_fs"*/;
function = "tdmb_in";
drive-strength = <2>;
};
};
@@ -1535,7 +1623,7 @@
groups = "pdm_din0_a",
/*"pdm_din1_a",*/
"pdm_din2_a",
"pdm_din3_a",
/*"pdm_din3_a",*/
"pdm_dclk_a";
function = "pdm";
};

View File

@@ -18,6 +18,24 @@
#ifndef _AML_NOTIFY_H
#define _AML_NOTIFY_H
#include <linux/notifier.h>
/* HDMI audio stream type ID */
#define AOUT_EVENT_IEC_60958_PCM 0x1
#define AOUT_EVENT_RAWDATA_AC_3 0x2
#define AOUT_EVENT_RAWDATA_MPEG1 0x3
#define AOUT_EVENT_RAWDATA_MP3 0x4
#define AOUT_EVENT_RAWDATA_MPEG2 0x5
#define AOUT_EVENT_RAWDATA_AAC 0x6
#define AOUT_EVENT_RAWDATA_DTS 0x7
#define AOUT_EVENT_RAWDATA_ATRAC 0x8
#define AOUT_EVENT_RAWDATA_ONE_BIT_AUDIO 0x9
#define AOUT_EVENT_RAWDATA_DOBLY_DIGITAL_PLUS 0xA
#define AOUT_EVENT_RAWDATA_DTS_HD 0xB
#define AOUT_EVENT_RAWDATA_MAT_MLP 0xC
#define AOUT_EVENT_RAWDATA_DST 0xD
#define AOUT_EVENT_RAWDATA_WMA_PRO 0xE
#define AOUT_EVENT_RAWDATA_DTS_HD_MA (AOUT_EVENT_RAWDATA_DTS_HD|(1<<8))
int aout_notifier_call_chain(unsigned long val, void *v);
int aout_unregister_client(struct notifier_block *p);
int aout_register_client(struct notifier_block *p);

View File

@@ -23,4 +23,5 @@ obj-$(CONFIG_AMLOGIC_SND_SOC_AUGE) += audio_controller.o \
effects.o \
effects_hw.o \
pwrdet.o \
pwrdet_hw.o
pwrdet_hw.o \
sharebuffer.o

View File

@@ -959,7 +959,7 @@ static int aml_card_probe(struct platform_device *pdev)
if (priv->chipinfo && priv->chipinfo->eqdrc_fn) {
pr_info("eq/drc function enable\n");
ret = card_add_eqdrc_kcontrols(&priv->snd_card);
ret = card_add_effects_init(&priv->snd_card);
if (ret < 0)
pr_warn_once("Failed to add audio effects controls\n");
} else

View File

@@ -136,7 +136,7 @@ static void aml_check_pwrdet(bool enable);
/* Audio EQ DRC */
static struct frddr_attach attach_aed;
static void aml_check_aed(bool enable);
static void aml_check_aed(bool enable, int dst);
/* to DDRS */
static struct toddr *register_toddr_l(struct device *dev,
@@ -716,7 +716,7 @@ void aml_frddr_enable(struct frddr *fr, bool enable)
aml_audiobus_update_bits(actrl, reg, 1<<31, enable<<31);
/* check for Audio EQ/DRC */
aml_check_aed(enable);
aml_check_aed(enable, fr->dest);
}
void aml_frddr_select_dst(struct frddr *fr, enum frddr_dest dst)
@@ -737,6 +737,42 @@ void aml_frddr_select_dst(struct frddr *fr, enum frddr_dest dst)
}
}
/* select dst for same source
* sel: share buffer req_sel 1~2
* sel 0 is aleardy used for reg_frddr_src_sel1
* sel 1 is for reg_frddr_src_sel2
* sel 2 is for reg_frddr_src_sel3
*/
void aml_frddr_select_dst_ss(struct frddr *fr, enum frddr_dest dst, int sel)
{
struct aml_audio_controller *actrl = fr->actrl;
unsigned int reg_base = fr->reg_base;
unsigned int reg;
if (dst == fr->dest) {
pr_warn_once("same source sel is same with frddr->dest\r");
return;
}
reg = calc_frddr_address(EE_AUDIO_FRDDR_A_CTRL0, reg_base);
/* same source en */
if (fr->chipinfo
&& fr->chipinfo->same_src_fn) {
if (sel == 1)
aml_audiobus_update_bits(actrl, reg,
0xf << 4,
dst << 4 | 1 << 7);
else if (sel == 2)
aml_audiobus_update_bits(actrl, reg,
0xf << 8,
dst << 8 | 1 << 11);
else
pr_warn_once("sel :%d is not supported for same source\n",
sel);
}
}
void aml_frddr_set_fifos(struct frddr *fr,
unsigned int depth, unsigned int thresh)
{
@@ -795,8 +831,12 @@ void aml_aed_enable(bool enable, int aed_module)
}
}
static void aml_check_aed(bool enable)
static void aml_check_aed(bool enable, int dst)
{
/* check effect module is sync with crruent frddr dst */
if (attach_aed.attach_module != dst)
return;
/* AED in enable */
if (attach_aed.enable) {
if (enable) {

View File

@@ -92,6 +92,8 @@ int aml_frddr_set_intrpt(struct frddr *fr, unsigned int intrpt);
unsigned int aml_frddr_get_position(struct frddr *fr);
void aml_frddr_enable(struct frddr *fr, bool enable);
void aml_frddr_select_dst(struct frddr *fr, enum frddr_dest);
extern void aml_frddr_select_dst_ss(struct frddr *fr,
enum frddr_dest dst, int sel);
void aml_frddr_set_fifos(struct frddr *fr,
unsigned int depth, unsigned int thresh);
unsigned int aml_frddr_get_fifo_id(struct frddr *fr);

View File

@@ -131,7 +131,7 @@ static int mixer_set_AED_req_ctrl(struct snd_kcontrol *kcontrol,
pr_info("AED req_sel0 module:%s\n", aed_req_module_texts[value]);
/* REQ_SEL0 */
aed_req_sel(0, value);
aed_req_sel(false, 0, value);
return 0;
}
@@ -140,9 +140,13 @@ static int mixer_set_EQ(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
unsigned int value = ucontrol->value.integer.value[0];
int eqdrc_module;
aed_set_eq(value, aml_EQ_param_length, &aml_EQ_param[0]);
eqdrc_module = aed_get_req_sel(0);
aml_aed_enable(value, eqdrc_module);
return 0;
}
@@ -150,10 +154,14 @@ static int mixer_set_DRC_params(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
unsigned int value = ucontrol->value.integer.value[0];
int eqdrc_module;
aed_set_drc(value, aml_DRC_param_length, &aml_drc_table[0],
aml_DRC_param_length, &aml_drc_tko_table[0]);
eqdrc_module = aed_get_req_sel(0);
aml_aed_enable(value, eqdrc_module);
return 0;
}
@@ -185,59 +193,99 @@ static const struct snd_kcontrol_new snd_eqdrc_controls[] = {
mixer_eqdrc_read, mixer_eqdrc_write,
chvol_tlv),
SOC_SINGLE_EXT_TLV("EQ master volume mute",
SOC_SINGLE_EXT("EQ master volume mute",
AED_MUTE, 31, 0x1, 0,
mixer_eqdrc_read, mixer_eqdrc_write,
NULL),
mixer_eqdrc_read, mixer_eqdrc_write),
SOC_SINGLE_EXT_TLV("EQ/DRC Channel Mask",
SOC_SINGLE_EXT("EQ/DRC Channel Mask",
AED_TOP_CTL, 18, 0xff, 0,
mixer_eqdrc_read, mixer_eqdrc_write,
NULL),
mixer_eqdrc_read, mixer_eqdrc_write),
SOC_SINGLE_EXT_TLV("EQ/DRC Lane Mask",
SOC_SINGLE_EXT("EQ/DRC Lane Mask",
AED_TOP_CTL, 14, 0xf, 0,
mixer_eqdrc_read, mixer_eqdrc_write,
NULL),
mixer_eqdrc_read, mixer_eqdrc_write),
SOC_SINGLE_EXT_TLV("EQ/DRC Req Module",
SOC_SINGLE_EXT("EQ/DRC Req Module",
AED_TOP_REQ_CTL, 0, 0x7, 0,
mixer_eqdrc_read, mixer_set_AED_req_ctrl,
NULL),
mixer_eqdrc_read, mixer_set_AED_req_ctrl),
SOC_SINGLE_EXT_TLV("EQ enable",
SOC_SINGLE_EXT("EQ enable",
AED_EQ_EN, 0, 0x1, 0,
mixer_eqdrc_read, mixer_set_EQ,
NULL),
mixer_eqdrc_read, mixer_set_EQ),
SOC_SINGLE_EXT_TLV("DRC enable",
SOC_SINGLE_EXT("DRC enable",
AED_DRC_EN, 0, 0x1, 0,
mixer_eqdrc_read, mixer_set_DRC_params,
NULL),
mixer_eqdrc_read, mixer_set_DRC_params),
SOC_SINGLE_EXT_TLV("NG enable",
SOC_SINGLE_EXT("NG enable",
AED_NG_CTL, 0, 0x1, 0,
mixer_eqdrc_read, mixer_eqdrc_write,
NULL),
mixer_eqdrc_read, mixer_eqdrc_write),
SOC_SINGLE_EXT_TLV("NG noise thd",
SOC_SINGLE_EXT("NG noise thd",
AED_NG_THD0, 8, 0x7FFF, 0,
mixer_eqdrc_read, mixer_eqdrc_write,
NULL),
mixer_eqdrc_read, mixer_eqdrc_write),
SOC_SINGLE_EXT_TLV("NG signal thd",
SOC_SINGLE_EXT("NG signal thd",
AED_NG_THD1, 8, 0x7FFF, 0,
mixer_eqdrc_read, mixer_eqdrc_write,
NULL),
mixer_eqdrc_read, mixer_eqdrc_write),
SOC_SINGLE_EXT_TLV("NG counter thd",
SOC_SINGLE_EXT("NG counter thd",
AED_NG_CNT_THD, 0, 0xFFFF, 0,
mixer_eqdrc_read, mixer_eqdrc_write,
NULL),
mixer_eqdrc_read, mixer_eqdrc_write),
};
int card_add_eqdrc_kcontrols(struct snd_soc_card *card)
int card_add_effects_init(struct snd_soc_card *card)
{
struct device_node *audio_effect_np;
int eq_enable = -1, drc_enable = -1, eqdrc_module = -1;
int lane_mask = -1, channel_mask = -1;
audio_effect_np = of_parse_phandle(card->dev->of_node,
"aml-audio-card,effect", 0);
if (audio_effect_np == NULL) {
pr_err("error: failed to find node %s for eq/drc info!\n",
"audio_effect");
return -EINVAL;
}
of_property_read_u32(audio_effect_np,
"eq_enable",
&eq_enable);
of_property_read_u32(audio_effect_np,
"drc_enable",
&drc_enable);
of_property_read_u32(audio_effect_np,
"eqdrc_module",
&eqdrc_module);
of_property_read_u32(audio_effect_np,
"lane_mask",
&lane_mask);
of_property_read_u32(audio_effect_np,
"channel_mask",
&channel_mask);
init_EQ_DRC_module();
if (eq_enable >= 0)
aed_set_eq(1, aml_EQ_param_length, &aml_EQ_param[0]);
if (drc_enable >= 0)
aed_set_drc(1, aml_DRC_param_length, &aml_drc_table[0],
aml_DRC_param_length, &aml_drc_tko_table[0]);
/* sel 0 in default */
if (eqdrc_module >= 0)
aed_req_sel(false, 0, eqdrc_module);
if (lane_mask >= 0)
aed_set_lane(lane_mask);
if (channel_mask >= 0)
aed_set_channel(channel_mask);
/* init eq/drc in defalut */
set_internal_EQ_volume(0xc0, 0x30, 0x30);
/* eq/drc mixer controls */
return snd_soc_add_card_controls(card,
snd_eqdrc_controls, ARRAY_SIZE(snd_eqdrc_controls));
}

View File

@@ -17,6 +17,6 @@
#ifndef __AML_AUDIO_EFFECTS_H__
#define __AML_AUDIO_EFFECTS_H__
extern int card_add_eqdrc_kcontrols(struct snd_soc_card *card);
extern int card_add_effects_init(struct snd_soc_card *card);
#endif

View File

@@ -35,12 +35,10 @@ int DRC0_enable(int enable, int thd0, int k0)
int init_EQ_DRC_module(void)
{
eqdrc_write(AED_TOP_CTL, (1 << 31)); /* fifo init */
eqdrc_write(AED_ED_CTL, 1); /* soft reset*/
msleep(20);
eqdrc_write(AED_ED_CTL, 0); /* soft reset*/
eqdrc_write(AED_TOP_CTL, (0 << 1) /*i2s in sel*/
| (1 << 0)); /*module enable*/
eqdrc_write(AED_NG_CTL, (3 << 30)); /* disable noise gate*/
return 0;
@@ -62,22 +60,22 @@ int set_internal_EQ_volume(
return 0;
}
void aed_req_sel(int sel, int req_module)
void aed_req_sel(bool enable, int sel, int req_module)
{
int mask_offset, val_offset;
switch (sel) {
case 0: /* REQ_SEL0 */
mask_offset = 0x1 << 3 | 0x7 << 0;
val_offset = 0x1 << 3 | req_module << 0;
val_offset = enable << 3 | req_module << 0;
break;
case 1: /* REQ_SEL1 */
mask_offset = 0x1 << 7 | 0x7 << 4;
val_offset = 0x1 << 7 | req_module << 4;
val_offset = enable << 7 | req_module << 4;
break;
case 2: /* REQ_SEL0 */
case 2: /* REQ_SEL2 */
mask_offset = 0x1 << 11 | 0x7 << 8;
val_offset = 0x1 << 11 | req_module << 8;
val_offset = enable << 11 | req_module << 8;
break;
default:
pr_err("unknown AED req_sel:%d\n", sel);
@@ -87,6 +85,30 @@ void aed_req_sel(int sel, int req_module)
eqdrc_update_bits(AED_TOP_REQ_CTL, mask_offset, val_offset);
}
/* get eq/drc module */
int aed_get_req_sel(int sel)
{
int val = eqdrc_read(AED_TOP_REQ_CTL);
int mask_off;
switch (sel) {
case 0: /* REQ_SEL0 */
mask_off = 0;
break;
case 1: /* REQ_SEL1 */
mask_off = 4;
break;
case 2: /* REQ_SEL2 */
mask_off = 8;
break;
default:
pr_err("unknown AED req_sel:%d\n", sel);
return -EINVAL;
}
return (val >> mask_off) & 0x7;
}
void aed_set_eq(int enable, int params_len, unsigned int *params)
{
if (enable) {
@@ -156,17 +178,31 @@ int aml_aed_format_set(int frddr_dst)
void aed_src_select(bool enable, int frddr_dst, int fifo_id)
{
if (enable) {
if (frddr_dst >= 3) {
/* SPDIFOUT A/B */
aml_spdifout_select_aed(enable, frddr_dst - 3);
} else if (frddr_dst < 3 && frddr_dst >= 0) {
/* TDMOUT A/B/C */
aml_tdmout_select_aed(enable, frddr_dst);
} else
pr_err("unknown function for AED\n");
}
/* Effect Module */
if (frddr_dst >= 3) {
/* SPDIFOUT A/B */
aml_spdifout_select_aed(enable, frddr_dst - 3);
} else if (frddr_dst < 3 && frddr_dst >= 0) {
/* TDMOUT A/B/C */
aml_tdmout_select_aed(enable, frddr_dst);
} else
pr_err("unknown function for AED\n");
/* AED module, req */
aed_req_sel(enable, 0, frddr_dst);
/* AED module, sel & enable */
eqdrc_update_bits(AED_TOP_CTL,
0x3 << 4 | 0x1 << 0,
fifo_id << 4 | enable << 0);
}
void aed_set_lane(int lane_mask)
{
eqdrc_update_bits(AED_TOP_CTL, 0xf << 14, lane_mask << 14);
}
void aed_set_channel(int channel_mask)
{
eqdrc_update_bits(AED_TOP_CTL, 0xff << 18, channel_mask << 18);
}

View File

@@ -29,11 +29,14 @@ extern int set_internal_EQ_volume(
unsigned int channel_1_volume,
unsigned int channel_2_volume);
extern void aed_req_sel(int sel, int req_module);
extern void aed_req_sel(bool enable, int sel, int req_module);
extern int aed_get_req_sel(int sel);
extern void aed_set_eq(int enable, int params_len, unsigned int *params);
extern void aed_set_drc(int enable,
int drc_len, unsigned int *drc_params,
int drc_tko_len, unsigned int *drc_tko_params);
extern int aml_aed_format_set(int frddr_dst);
extern void aed_src_select(bool enable, int frddr_dst, int fifo_id);
extern void aed_set_lane(int lane_mask);
extern void aed_set_channel(int channel_mask);
#endif

View File

@@ -182,9 +182,9 @@ CLOCK_COM_MUX(locker_in, AUD_ADDR_OFFSET(EE_AUDIO_CLK_LOCKER_CTRL), 0xf, 8);
CLOCK_COM_DIV(locker_in, AUD_ADDR_OFFSET(EE_AUDIO_CLK_LOCKER_CTRL), 0, 8);
CLOCK_COM_GATE(locker_in, AUD_ADDR_OFFSET(EE_AUDIO_CLK_LOCKER_CTRL), 15);
/* audio resample */
CLOCK_COM_MUX(resample, AUD_ADDR_OFFSET(EE_AUDIO_CLK_LOCKER_CTRL), 0xf, 24);
CLOCK_COM_DIV(resample, AUD_ADDR_OFFSET(EE_AUDIO_CLK_LOCKER_CTRL), 0, 0xff);
CLOCK_COM_GATE(resample, AUD_ADDR_OFFSET(EE_AUDIO_CLK_LOCKER_CTRL), 31);
CLOCK_COM_MUX(resample, AUD_ADDR_OFFSET(EE_AUDIO_CLK_RESAMPLE_CTRL), 0xf, 24);
CLOCK_COM_DIV(resample, AUD_ADDR_OFFSET(EE_AUDIO_CLK_RESAMPLE_CTRL), 0, 8);
CLOCK_COM_GATE(resample, AUD_ADDR_OFFSET(EE_AUDIO_CLK_RESAMPLE_CTRL), 31);
static int g12a_clks_init(struct clk **clks, void __iomem *iobase)
{
@@ -233,7 +233,7 @@ static int g12a_clks_init(struct clk **clks, void __iomem *iobase)
WARN_ON(IS_ERR_OR_NULL(clks[CLKID_AUDIO_SPDIFOUTB_CTRL]));
IOMAP_COM_CLK(locker_out, iobase);
clks[CLKID_AUDIO_LOCKER_OUT] = REGISTER_CLK_COM(locker_out);
clks[CLKID_AUDIO_LOCKER_OUT] = REGISTER_AUDIOCLK_COM(locker_out);
WARN_ON(IS_ERR_OR_NULL(clks[CLKID_AUDIO_LOCKER_OUT]));
IOMAP_COM_CLK(locker_in, iobase);

View File

@@ -55,16 +55,16 @@ void audiolocker_update_clks(struct clk *clk_calc, struct clk *clk_ref)
in_count = audiolocker_read(RO_REF2IMCLK_CNT_L);
out_count = audiolocker_read(RO_REF2OMCLK_CNT_L);
/*pr_info("\tin count:%d, out count:%d\n", in_count, out_count);*/
pr_info("\tin count:%d, out count:%d\n", in_count, out_count);
if (in_count < out_count) {
add_cnt++;
mpll1_rate = clk_get_rate(clk_calc);
mpll2_rate = clk_get_rate(clk_ref);
/* if ( !(add_cnt % 1000))
* pr_info("\t add cnt:%d, mpll1_rate:%d mpll2 rate:%d\n",
* add_cnt,mpll1_rate, mpll2_rate);
*/
pr_info("\t add cnt:%d, mpll1_rate:%d mpll2 rate:%d\n",
add_cnt, mpll1_rate, mpll2_rate);
clk_set_rate(clk_ref, mpll2_rate + 600);
/*udelay(1);*/
audiolocker_reset();
@@ -72,10 +72,10 @@ void audiolocker_update_clks(struct clk *clk_calc, struct clk *clk_ref)
reduce_cnt++;
mpll1_rate = clk_get_rate(clk_calc);
mpll2_rate = clk_get_rate(clk_ref);
/* if (!(reduce_cnt % 1000))
* pr_info("\t reduce cnt:%d, mpll1_rate:%d, mpll2 rate:%d\n",
* reduce_cnt,mpll1_rate, mpll2_rate);
*/
pr_info("\t reduce cnt:%d, mpll1_rate:%d, mpll2 rate:%d\n",
reduce_cnt, mpll1_rate, mpll2_rate);
clk_set_rate(clk_ref, mpll2_rate - 600);
/*udelay(1);*/
audiolocker_reset();

View File

@@ -71,11 +71,16 @@ static int resample_clk_set(struct audioresample *p_resample)
pr_err("Can't enable resample_src clock: %d\n", ret);
return -EINVAL;
}
if (p_resample->out_rate)
if (p_resample->out_rate) {
clk_set_rate(p_resample->sclk,
p_resample->out_rate * 256);
else
clk_set_rate(p_resample->clk,
p_resample->out_rate * 256);
} else {
/* defaule resample clk */
clk_set_rate(p_resample->sclk, 48000 * 256);
clk_set_rate(p_resample->clk, 48000 * 256);
}
ret = clk_prepare_enable(p_resample->pll);
if (ret) {

View File

@@ -0,0 +1,100 @@
/*
* sound/soc/amlogic/auge/sharebuffer.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/pcm.h>
#include <linux/amlogic/media/sound/aout_notify.h>
#include "sharebuffer.h"
#include "ddr_mngr.h"
#include "spdif_hw.h"
int sharebuffer_spdifout_prepare(struct snd_pcm_substream *substream,
struct frddr *fr, int spdif_id)
{
struct snd_pcm_runtime *runtime = substream->runtime;
int bit_depth;
bit_depth = snd_pcm_format_width(runtime->format);
spdifout_samesource_set(spdif_id,
aml_frddr_get_fifo_id(fr),
bit_depth, true);
/* spdif b, notify hdmitx audio */
if (spdif_id == 1) {
spdifoutb_to_hdmitx_ctrl();
aout_notifier_call_chain(0x1, substream);
}
return 0;
}
void sharebuffer_enable(int sel, bool enable)
{
if (sel < 0) {
pr_err("Not support same source\n");
return;
} else if (sel < 3) {
// TODO: same with tdm
} else if (sel < 5) {
/* same source with spdif a/b */
spdifout_enable(sel - 3, enable);
}
}
int sharebuffer_prepare(struct snd_pcm_substream *substream,
void *pfrddr, int samesource_sel)
{
struct frddr *fr = (struct frddr *)pfrddr;
/* each module prepare, clocks and controls */
if (samesource_sel < 0) {
pr_err("Not support same source\n");
return -EINVAL;
} else if (samesource_sel < 3) {
// TODO: same with tdm
} else if (samesource_sel < 5) {
/* same source with spdif a/b */
sharebuffer_spdifout_prepare(substream, fr, samesource_sel - 3);
}
/* frddr, share buffer, src_sel1 */
aml_frddr_select_dst_ss(fr, samesource_sel, 1);
return 0;
}
int sharebuffer_trigger(int cmd, int samesource_sel)
{
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
sharebuffer_enable(samesource_sel, true);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
sharebuffer_enable(samesource_sel, false);
break;
default:
return -EINVAL;
}
return 0;
}

View File

@@ -0,0 +1,24 @@
/*
* sound/soc/amlogic/auge/sharebuffer.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_SHAREBUFFER_H__
#define __AML_AUDIO_SHAREBUFFER_H__
extern int sharebuffer_prepare(struct snd_pcm_substream *substream,
void *pfrddr, int samesource_sel);
extern int sharebuffer_trigger(int cmd, int samesource_sel);
#endif

View File

@@ -416,11 +416,8 @@ static int aml_dai_spdif_prepare(
aml_frddr_select_dst(fr, dst);
aml_frddr_set_fifos(fr, 0x40, 0x20);
// TODO: TOHDMITX_CTRL0
/* TOHDMITX_CTRL0 */
if (p_spdif->id == 1) {
/* HDMI audio stream type ID */
#define AOUT_EVENT_IEC_60958_PCM 0x1
spdifoutb_to_hdmitx_ctrl();
aout_notifier_call_chain(AOUT_EVENT_IEC_60958_PCM,
substream);

View File

@@ -280,3 +280,90 @@ void spdifoutb_to_hdmitx_ctrl(void)
| 1 << 0 /* spdif_clk_b */
);
}
void spdifout_clk_ctrl(int spdif_id, bool is_enable)
{
unsigned int offset, reg;
offset = EE_AUDIO_CLK_SPDIFOUT_B_CTRL - EE_AUDIO_CLK_SPDIFOUT_CTRL;
reg = EE_AUDIO_CLK_SPDIFOUT_CTRL + offset * spdif_id;
/* select : mpll 0, 24m, so spdif clk:6m */
audiobus_write(reg, is_enable << 31 | 0x0 << 24 | 0x3 << 0);
}
void spdifout_fifo_ctrl(int spdif_id, int fifo_id, int bitwidth)
{
unsigned int frddr_type;
unsigned int offset, reg;
switch (bitwidth) {
case 8:
frddr_type = 0;
break;
case 16:
frddr_type = 1;
break;
case 24:
frddr_type = 4;
break;
case 32:
frddr_type = 3;
break;
default:
pr_err("runtime format invalid bitwidth: %d\n",
bitwidth);
return;
}
pr_info("%s, bit depth:%d, frddr type:%d\n",
__func__, bitwidth, frddr_type);
/* mask lane 0 L/R channels */
offset = EE_AUDIO_SPDIFOUT_B_CTRL0 - EE_AUDIO_SPDIFOUT_CTRL0;
reg = EE_AUDIO_SPDIFOUT_CTRL0 + offset * spdif_id;
audiobus_update_bits(reg,
0x1<<29|0x1<<28|0x1<<20|0x1<<19|0xff<<4,
1<<29|1<<28|0<<20|0<<19|0x3<<4);
offset = EE_AUDIO_SPDIFOUT_B_CTRL1 - EE_AUDIO_SPDIFOUT_CTRL1;
reg = EE_AUDIO_SPDIFOUT_CTRL1 + offset * spdif_id;
audiobus_update_bits(reg,
0x3 << 24 | 0x1f << 8 | 0x7 << 4,
fifo_id << 24 | (bitwidth - 1) << 8 | frddr_type<<4);
offset = EE_AUDIO_SPDIFOUT_B_SWAP - EE_AUDIO_SPDIFOUT_SWAP;
reg = EE_AUDIO_SPDIFOUT_SWAP + offset * spdif_id;
audiobus_write(reg, 1<<4);
/* reset afifo */
offset = EE_AUDIO_SPDIFOUT_B_CTRL0 - EE_AUDIO_SPDIFOUT_CTRL0;
reg = EE_AUDIO_SPDIFOUT_CTRL0 + offset * spdif_id;
audiobus_update_bits(reg, 3<<28, 0);
audiobus_update_bits(reg, 1<<29, 1<<29);
audiobus_update_bits(reg, 1<<28, 1<<28);
}
void spdifout_enable(int spdif_id, bool is_enable)
{
unsigned int offset, reg;
offset = EE_AUDIO_SPDIFOUT_B_CTRL0 - EE_AUDIO_SPDIFOUT_CTRL0;
reg = EE_AUDIO_SPDIFOUT_CTRL0 + offset * spdif_id;
audiobus_update_bits(reg, 1<<31, is_enable<<31);
}
void spdifout_samesource_set(int spdif_index, int fifo_id,
int bitwidth, bool is_enable)
{
int spdif_id;
if (spdif_index == 1)
spdif_id = 1;
else
spdif_id = 0;
spdifout_clk_ctrl(spdif_id, true);
spdifout_fifo_ctrl(spdif_id, fifo_id, bitwidth);
}

View File

@@ -54,4 +54,8 @@ extern void aml_spdifout_get_aed_info(int spdifout_id,
int *bitwidth, int *frddrtype);
extern void spdifoutb_to_hdmitx_ctrl(void);
extern void spdifout_samesource_set(int spdif_index, int fifo_id,
int bitwidth, bool is_enable);
extern void spdifout_enable(int spdif_id, bool is_enable);
#endif

View File

@@ -37,6 +37,10 @@
#include "ddr_mngr.h"
#include "tdm_hw.h"
/*#define G12A_PTM*/
#include "sharebuffer.h"
#define DRV_NAME "aml_tdm"
#define TDM_A 0
@@ -79,6 +83,9 @@ struct tdm_chipinfo {
/* clk pad */
bool clk_pad_ctl;
/* same source */
bool same_src_fn;
};
struct aml_tdm {
@@ -97,6 +104,8 @@ struct aml_tdm {
struct frddr *fddr;
struct tdm_chipinfo *chipinfo;
/* share buffer with module */
int samesource_sel;
};
static const struct snd_pcm_hardware aml_tdm_hardware = {
@@ -116,7 +125,7 @@ static const struct snd_pcm_hardware aml_tdm_hardware = {
.buffer_bytes_max = 512 * 1024,
.rate_min = 8000,
.rate_max = 48000,
.rate_max = 192000,
.channels_min = 1,
.channels_max = 32,
};
@@ -383,6 +392,14 @@ static int aml_dai_tdm_prepare(struct snd_pcm_substream *substream,
enum frddr_dest dst;
unsigned int fifo_id;
/* share buffer prepare */
if (p_tdm->chipinfo &&
p_tdm->chipinfo->same_src_fn) {
if (p_tdm->samesource_sel >= 0)
sharebuffer_prepare(substream,
fr, p_tdm->samesource_sel);
}
fifo_id = aml_frddr_get_fifo_id(fr);
aml_tdm_fifo_ctrl(p_tdm->actrl,
bit_depth,
@@ -460,6 +477,13 @@ static int aml_dai_tdm_trigger(struct snd_pcm_substream *substream, int cmd,
{
struct aml_tdm *p_tdm = snd_soc_dai_get_drvdata(cpu_dai);
/* share buffer trigger */
if (p_tdm->chipinfo &&
p_tdm->chipinfo->same_src_fn) {
if (p_tdm->samesource_sel >= 0)
sharebuffer_trigger(cmd, p_tdm->samesource_sel);
}
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
@@ -476,7 +500,6 @@ static int aml_dai_tdm_trigger(struct snd_pcm_substream *substream, int cmd,
dev_info(substream->pcm->card->dev, "tdm capture enable\n");
aml_toddr_enable(p_tdm->tddr, 1);
}
aml_tdm_enable(p_tdm->actrl,
substream->stream, p_tdm->id, true);
@@ -486,6 +509,7 @@ static int aml_dai_tdm_trigger(struct snd_pcm_substream *substream, int cmd,
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
aml_tdm_enable(p_tdm->actrl,
substream->stream, p_tdm->id, false);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
dev_info(substream->pcm->card->dev, "tdm playback stop\n");
aml_frddr_enable(p_tdm->fddr, 0);
@@ -697,8 +721,6 @@ static unsigned int aml_mpll_mclk_ratio(unsigned int freq)
return ratio;
}
/*#define G12A_PTM*/
static int aml_dai_set_tdm_sysclk(struct snd_soc_dai *cpu_dai,
int clk_id, unsigned int freq, int dir)
{
@@ -983,6 +1005,7 @@ struct tdm_chipinfo g12a_tdma_chipinfo = {
.sclk_ws_inv = true,
.oe_fn = true,
.clk_pad_ctl = true,
.same_src_fn = true,
};
struct tdm_chipinfo g12a_tdmb_chipinfo = {
@@ -990,6 +1013,7 @@ struct tdm_chipinfo g12a_tdmb_chipinfo = {
.sclk_ws_inv = true,
.oe_fn = true,
.clk_pad_ctl = true,
.same_src_fn = true,
};
struct tdm_chipinfo g12a_tdmc_chipinfo = {
@@ -997,6 +1021,7 @@ struct tdm_chipinfo g12a_tdmc_chipinfo = {
.sclk_ws_inv = true,
.oe_fn = true,
.clk_pad_ctl = true,
.same_src_fn = true,
};
static const struct of_device_id aml_tdm_device_id[] = {
@@ -1072,6 +1097,19 @@ static int aml_tdm_platform_probe(struct platform_device *pdev)
return -ENXIO;
}
/* default no same source */
if (p_tdm->chipinfo &&
p_tdm->chipinfo->same_src_fn) {
ret = of_property_read_u32(node, "samesource_sel",
&p_tdm->samesource_sel);
if (ret < 0)
p_tdm->samesource_sel = -1;
pr_info("TDM id %d samesource_sel:%d\n",
p_tdm->id,
p_tdm->samesource_sel);
}
/* get tdm lanes info. if not, set to default 1 */
ret = of_parse_tdm_lane_slot_in(node,
&p_tdm->setting.lane_mask_in);

View File

@@ -237,9 +237,12 @@ void aml_tdm_set_format(
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
if (p_config->sclk_ws_inv)
bclkout_skew = 2;
else
if (p_config->sclk_ws_inv) {
if (master_mode)
bclkout_skew = 2;
else
bclkout_skew = 3;
} else
bclkout_skew = 1;
bclkin_skew = 3;
@@ -264,9 +267,12 @@ void aml_tdm_set_format(
* that is, together with the last bit of the previous
* data word.
*/
if (p_config->sclk_ws_inv)
bclkout_skew = 2;
else
if (p_config->sclk_ws_inv) {
if (master_mode)
bclkout_skew = 2;
else
bclkout_skew = 3;
} else
bclkout_skew = 1;
bclkin_skew = 3;
@@ -279,7 +285,13 @@ void aml_tdm_set_format(
* Frame high, one bit for frame sync,
* frame sync asserts with the first bit of the frame.
*/
bclkout_skew = 2;
if (p_config->sclk_ws_inv) {
if (master_mode)
bclkout_skew = 3;
else
bclkout_skew = 4;
} else
bclkout_skew = 2;
bclkin_skew = 2;
if (capture_active)
@@ -343,7 +355,7 @@ void aml_tdm_set_format(
aml_audiobus_update_bits(actrl, reg_out,
0x3<<30, 0x3<<30);
if (p_config->sclk_ws_inv)
if (p_config->sclk_ws_inv && master_mode)
aml_audiobus_update_bits(actrl, reg_out,
0x1 << 28,
0x1 << 28);

View File

@@ -49,8 +49,6 @@
#include "spdif_dai.h"
#include "dmic.h"
#define AOUT_EVENT_IEC_60958_PCM 0x1
/* extern int set_i2s_iec958_samesource(int enable);
*
* the I2S hw and IEC958 PCM output initiation,958 initiation here,

View File

@@ -18,22 +18,6 @@
#ifndef _AML_SPDIF_DAI_H
#define _AML_SPDIF_DAI_H
/* HDMI audio stream type ID */
#define AOUT_EVENT_IEC_60958_PCM 0x1
#define AOUT_EVENT_RAWDATA_AC_3 0x2
#define AOUT_EVENT_RAWDATA_MPEG1 0x3
#define AOUT_EVENT_RAWDATA_MP3 0x4
#define AOUT_EVENT_RAWDATA_MPEG2 0x5
#define AOUT_EVENT_RAWDATA_AAC 0x6
#define AOUT_EVENT_RAWDATA_DTS 0x7
#define AOUT_EVENT_RAWDATA_ATRAC 0x8
#define AOUT_EVENT_RAWDATA_ONE_BIT_AUDIO 0x9
#define AOUT_EVENT_RAWDATA_DOBLY_DIGITAL_PLUS 0xA
#define AOUT_EVENT_RAWDATA_DTS_HD 0xB
#define AOUT_EVENT_RAWDATA_MAT_MLP 0xC
#define AOUT_EVENT_RAWDATA_DST 0xD
#define AOUT_EVENT_RAWDATA_WMA_PRO 0xE
#define AOUT_EVENT_RAWDATA_DTS_HD_MA (AOUT_EVENT_RAWDATA_DTS_HD|(1<<8))
extern unsigned int IEC958_mode_codec;
/*

View File

@@ -255,20 +255,23 @@ static const struct snd_soc_dapm_route T9015_audio_dapm_routes[] = {
static int aml_T9015_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct snd_soc_codec *codec = dai->codec;
u32 val = snd_soc_read(codec, AUDIO_CONFIG_BLOCK_ENABLE);
pr_debug("%s, format:%x, codec = %p\n", __func__, fmt, codec);
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
snd_soc_update_bits(codec, AUDIO_CONFIG_BLOCK_ENABLE,
I2S_MODE, 1);
val |= (0x1 << I2S_MODE);
break;
case SND_SOC_DAIFMT_CBS_CFS:
snd_soc_update_bits(codec, AUDIO_CONFIG_BLOCK_ENABLE,
I2S_MODE, 0);
val &= ~(0x1 << I2S_MODE);
break;
default:
return -EINVAL;
}
snd_soc_write(codec, AUDIO_CONFIG_BLOCK_ENABLE, val);
return 0;
}

View File

@@ -328,19 +328,23 @@ static const struct snd_soc_dapm_route T9015S_audio_dapm_routes[] = {
static int aml_T9015S_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct snd_soc_codec *codec = dai->codec;
u32 val = snd_soc_read(codec, AUDIO_CONFIG_BLOCK_ENABLE);
pr_debug("%s, format:%x, codec = %p\n", __func__, fmt, codec);
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
snd_soc_update_bits(codec, AUDIO_CONFIG_BLOCK_ENABLE,
I2S_MODE, 1);
val |= (0x1 << I2S_MODE);
break;
case SND_SOC_DAIFMT_CBS_CFS:
snd_soc_update_bits(codec, AUDIO_CONFIG_BLOCK_ENABLE,
I2S_MODE, 0);
val &= ~(0x1 << I2S_MODE);
break;
default:
return -EINVAL;
}
snd_soc_write(codec, AUDIO_CONFIG_BLOCK_ENABLE, val);
return 0;
}