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>
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/*
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>;
};
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>;
interrupt-names = "irq";
frequency = <49000000>; /* pll */
dividor = <49>; /* locker's parent */
- status = "disabled";
+ status = "okay";
};
/* Audio Related end */
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>;
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 {
&clkaudio CLKID_AUDIO_SPDIFOUTB_CTRL>;
clock-names = "sysclk",
"gate_spdifout", "clk_spdifout";
- //pinctrl-names = "spdif_pins";
- //pinctrl-0 = <&spdifout>;
status = "okay";
};
aml_pdm: pdm {
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";
hi_th = <0x70000>;
lo_th = <0x16000>;
- status = "disabled";
+ status = "okay";
};
}; /* end of audiobus */
mux {
groups = "mclk0_a";
function = "mclk0";
+ drive-strength = <2>;
};
};
tdmout_b: tdmout_b {
"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>;
};
};
groups = "pdm_din0_a",
/*"pdm_din1_a",*/
"pdm_din2_a",
- "pdm_din3_a",
+ /*"pdm_din3_a",*/
"pdm_dclk_a";
function = "pdm";
};
#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);
effects.o \
effects_hw.o \
pwrdet.o \
- pwrdet_hw.o
+ pwrdet_hw.o \
+ sharebuffer.o
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
/* 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,
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)
}
}
+/* 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)
{
}
}
-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) {
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);
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;
}
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;
}
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;
}
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));
}
#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
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;
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);
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) {
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);
+}
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
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)
{
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);
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();
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();
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) {
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
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);
| 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);
+}
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
#include "ddr_mngr.h"
#include "tdm_hw.h"
+/*#define G12A_PTM*/
+
+#include "sharebuffer.h"
+
#define DRV_NAME "aml_tdm"
#define TDM_A 0
/* clk pad */
bool clk_pad_ctl;
+
+ /* same source */
+ bool same_src_fn;
};
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 = {
.buffer_bytes_max = 512 * 1024,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 192000,
.channels_min = 1,
.channels_max = 32,
};
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,
{
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:
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);
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);
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)
{
.sclk_ws_inv = true,
.oe_fn = true,
.clk_pad_ctl = true,
+ .same_src_fn = true,
};
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 = {
.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[] = {
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);
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;
* 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;
* 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)
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);
#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,
#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;
/*
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;
}
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;
}