tl1,clocks.o \
sm1,clocks.o \
tm2,clocks.o \
- card.o \
card_utils.o \
tdm.o \
tdm_hw.o \
vad_hw.o \
vad_dev.o \
earc.o \
- earc_hw.o
+ earc_hw.o \
+ card.o
ret = aml_card_dai_link_of(np, priv,
i, false);
if (ret < 0) {
+ dev_err(dev, "parse dai_link-%d fail\n", i);
of_node_put(np);
goto card_parse_end;
}
unsigned int datalb_chnum;
unsigned int datalb_chmask;
unsigned int datalb_lane_mask; /* related with data lane */
-
+ unsigned int lb_format;
+ unsigned int lb_lane_chmask;
unsigned int sysclk_freq;
struct toddr *tddr;
/* datalb */
switch (p_loopback->datalb_src) {
- case TDMINLB_TDMOUTA ... TDMINLB_PAD_TDMINC:
+ case TDMINLB_TDMOUTA ... TDMINLB_PAD_TDMINC_D:
/*tdminlb_startup(p_loopback);*/
break;
case SPDIFINLB_SPDIFOUTA ... SPDIFINLB_SPDIFOUTB:
/* datalb */
switch (p_loopback->datalb_src) {
- case TDMINLB_TDMOUTA ... TDMINLB_PAD_TDMINC:
+ case TDMINLB_TDMOUTA ... TDMINLB_PAD_TDMINC_D:
/*tdminlb_shutdown(p_loopback);*/
break;
case SPDIFINLB_SPDIFOUTA ... SPDIFINLB_SPDIFOUTB:
}
switch (p_loopback->datalb_src) {
- case TDMINLB_TDMOUTA:
- case TDMINLB_TDMOUTB:
- case TDMINLB_TDMOUTC:
- case TDMINLB_PAD_TDMINA:
- case TDMINLB_PAD_TDMINB:
- case TDMINLB_PAD_TDMINC:
+ case TDMINLB_TDMOUTA ... TDMINLB_PAD_TDMINC_D:
if (bitwidth == 24) {
datalb_toddr_type = 4;
datalb_msb = 32 - 1;
lb_set_datain_cfg(p_loopback->id, &datain_cfg);
lb_set_datalb_cfg(p_loopback->id, &datalb_cfg);
- tdminlb_set_format(1); /* tdmin_lb i2s mode */
+ tdminlb_set_format(p_loopback->lb_format == SND_SOC_DAIFMT_I2S);
tdminlb_set_lanemask_and_chswap(0x76543210,
- p_loopback->datalb_lane_mask);
+ p_loopback->datalb_lane_mask,
+ p_loopback->lb_lane_chmask);
tdminlb_set_ctrl(p_loopback->datalb_src);
return 0;
case TDMINLB_PAD_TDMINB:
case TDMINLB_PAD_TDMINC:
break;
+ case TDMINLB_PAD_TDMINA_D:
+ case TDMINLB_PAD_TDMINB_D:
+ case TDMINLB_PAD_TDMINC_D:
+ break;
case SPDIFINLB_SPDIFOUTA:
case SPDIFINLB_SPDIFOUTB:
break;
/* datalb */
switch (p_loopback->datalb_src) {
- case TDMINLB_TDMOUTA ... TDMINLB_PAD_TDMINC:
+ case TDMINLB_TDMOUTA ... TDMINLB_PAD_TDMINC_D:
/*datalb_tdminlb_set_clk(p_loopback);*/
break;
case SPDIFINLB_SPDIFOUTA ... SPDIFINLB_SPDIFOUTB:
"TDMIN_A",
"TDMIN_B",
"TDMIN_C",
+ "TDMIN_A_D",
+ "TDMIN_B_D",
+ "TDMIN_C_D",
};
static const struct soc_enum datalb_tdminlb_enum =
return -EINVAL;
}
+static unsigned int loopback_parse_format(struct device_node *node)
+{
+ unsigned int format = 0;
+ int ret = 0;
+ const char *str;
+ struct {
+ char *name;
+ unsigned int val;
+ } fmt_table[] = {
+ {"i2s", SND_SOC_DAIFMT_I2S},
+ {"dsp_a", SND_SOC_DAIFMT_DSP_A},
+ {"dsp_b", SND_SOC_DAIFMT_DSP_B}
+ };
+
+ ret = of_property_read_string(node, "datalb-format", &str);
+ if (ret == 0) {
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(fmt_table); i++) {
+ if (strcmp(str, fmt_table[i].name) == 0) {
+ format |= fmt_table[i].val;
+ break;
+ }
+ }
+ }
+
+ /* default format is I2S */
+ if (format == 0)
+ format = SND_SOC_DAIFMT_I2S;
+
+ return format;
+}
+
static int loopback_parse_of(
struct device_node *node,
struct loopback *p_loopback)
goto fail;
}
+ p_loopback->lb_format = loopback_parse_format(node);
+ snd_soc_of_get_slot_mask
+ (node,
+ "datalb-channels-mask",
+ &p_loopback->lb_lane_chmask);
+ if (p_loopback->lb_lane_chmask == 0) {
+ /* default format is I2S and mask two channels */
+ p_loopback->lb_lane_chmask = 0x3;
+ }
pr_info("\tdatain_src:%d, datain_chnum:%d, datain_chumask:%x\n",
p_loopback->datain_src,
p_loopback->datain_chnum,
pr_info("\tdatain_lane_mask:0x%x, datalb_lane_mask:0x%x\n",
p_loopback->datain_lane_mask,
p_loopback->datalb_lane_mask);
+ pr_info("datalb_format: %d, chmask for lanes: %#x\n",
+ p_loopback->lb_format, p_loopback->lb_lane_chmask);
ret = datain_parse_of(node, p_loopback);
if (ret) {
TDMINLB_PAD_TDMINB,
TDMINLB_PAD_TDMINC,
+ TDMINLB_PAD_TDMINA_D,
+ TDMINLB_PAD_TDMINB_D,
+ TDMINLB_PAD_TDMINC_D,
+
SPDIFINLB_SPDIFOUTA,
SPDIFINLB_SPDIFOUTB,
};
#include "regs.h"
#include "iomap.h"
+static unsigned int
+get_tdmin_id_from_lb_src(enum datalb_src lb_src)
+{
+ return lb_src % TDMINLB_PAD_TDMINA;
+}
-void tdminlb_set_clk(int datatlb_src, int sclk_div, int ratio, bool enable)
+void tdminlb_set_clk(enum datalb_src lb_src,
+ int sclk_div, int ratio, bool enable)
{
unsigned int bclk_sel, fsclk_sel;
unsigned int tdmin_src;
/* config for external codec */
- if (datatlb_src >= 3) {
- unsigned int clk_id = datatlb_src - 3;
+ if (lb_src >= TDMINLB_PAD_TDMINA) {
+ unsigned int id = get_tdmin_id_from_lb_src(lb_src);
unsigned int offset, reg;
unsigned int fsclk_hi;
fsclk_hi = ratio / 2;
- bclk_sel = clk_id;
- fsclk_sel = clk_id;
+ bclk_sel = id;
+ fsclk_sel = id;
/*sclk, lrclk*/
offset = EE_AUDIO_MST_B_SCLK_CTRL0 - EE_AUDIO_MST_A_SCLK_CTRL0;
- reg = EE_AUDIO_MST_A_SCLK_CTRL0 + offset * clk_id;
+ reg = EE_AUDIO_MST_A_SCLK_CTRL0 + offset * id;
audiobus_update_bits(reg,
0x3 << 30 | 0x3ff << 20 | 0x3ff<<10 | 0x3ff,
(enable ? 0x3 : 0x0) << 30
| sclk_div << 20 | fsclk_hi << 10
| ratio);
-
- tdmin_src = datatlb_src - 3;
+ tdmin_src = id;
} else
- tdmin_src = datatlb_src;
+ tdmin_src = lb_src;
audiobus_update_bits(
EE_AUDIO_CLK_TDMIN_LB_CTRL,
{
audiobus_update_bits(EE_AUDIO_TDMIN_LB_CTRL,
0x1 << 30,
- i2s_fmt << 30 /* 0:tdm mode; 1: i2s mode; */
+ !!i2s_fmt << 30 /* 0:tdm mode; 1: i2s mode; */
);
}
-void tdminlb_set_ctrl(int src)
+void tdminlb_set_ctrl(enum datalb_src src)
{
audiobus_update_bits(
EE_AUDIO_TDMIN_LB_CTRL,
audiobus_write(EE_AUDIO_TDMIN_LB_MASK0 + lane, mask);
}
-void tdminlb_set_lanemask_and_chswap(int swap, int lane_mask)
+void tdminlb_set_lanemask_and_chswap(int swap, int lane_mask, unsigned int mask)
{
- unsigned int mask;
unsigned int i;
- pr_debug("tdmin_lb lane swap:0x%x mask:0x%x\n", swap, lane_mask);
-
- mask = 0x3; /* i2s format */
+ pr_debug
+ ("%s() lane swap:0x%x lane mask:0x%x, chmask:%#x\n",
+ __func__, swap, lane_mask, mask);
/* channel swap */
audiobus_write(EE_AUDIO_TDMIN_LB_SWAP0, swap);
#define __AML_LOOPBACK_HW_H__
#include <linux/types.h>
+#include "loopback.h"
struct data_cfg {
/*
bool ch_ctrl_switch;
};
-extern void tdminlb_set_clk(int datatlb_src,
- int sclk_div, int ratio, bool enable);
+void tdminlb_set_clk(enum datalb_src lb_src,
+ int sclk_div, int ratio, bool enable);
extern void tdminlb_set_format(int i2s_fmt);
-extern void tdminlb_set_ctrl(int src);
+void tdminlb_set_ctrl(enum datalb_src src);
extern void tdminlb_enable(int tdm_index, int in_enable);
extern void tdminlb_fifo_enable(int is_enable);
extern void tdminlb_set_format(int i2s_fmt);
-extern void tdminlb_set_lanemask_and_chswap(int swap, int lane_mask);
-
+void tdminlb_set_lanemask_and_chswap
+ (int swap, int lane_mask, unsigned int mask);
extern void tdminlb_set_src(int src);
extern void lb_set_datain_src(int id, int src);
#if 1
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
/* set lanes mask acordingly */
- if (p_tdm->chipinfo
- && p_tdm->chipinfo->oe_fn
- && p_tdm->setting.lane_oe_mask_out)
+ lane_mask = setting->lane_mask_out;
+ /* compatible using oe masks */
+ if (!lane_mask && setting->lane_oe_mask_out)
lane_mask = setting->lane_oe_mask_out;
- else
- lane_mask = setting->lane_mask_out;
+
for (i = 0; i < p_tdm->lane_cnt; i++) {
if (((1 << i) & lane_mask) && lanes) {
aml_tdm_set_channel_mask(p_tdm->actrl,
unsigned int lanes_oe_out_cnt = 0, lanes_oe_in_cnt = 0;
unsigned int force_oe = 0, oe_val = 0;
unsigned int lanes_lb_cnt = 0;
- int out_lanes, in_lanes;
+ int out_lanes = 0, in_lanes = 0;
int in_src = -1;
lanes_out_cnt = pop_count(p_tdm->setting.lane_mask_out);
lanes_in_cnt = pop_count(p_tdm->setting.lane_mask_in);
- lanes_oe_out_cnt = pop_count(p_tdm->setting.lane_oe_mask_out);
- lanes_oe_in_cnt = pop_count(p_tdm->setting.lane_oe_mask_in);
lanes_lb_cnt = pop_count(p_tdm->setting.lane_lb_mask_in);
pr_debug("%s(), txmask(%#x), rxmask(%#x)\n",
__func__, tx_mask, rx_mask);
pr_debug("\tlanes_out_cnt(%d), lanes_in_cnt(%d)\n",
lanes_out_cnt, lanes_in_cnt);
- pr_debug("\tlanes_oe_out_cnt(%d), lanes_oe_in_cnt(%d)\n",
- lanes_oe_out_cnt, lanes_oe_in_cnt);
pr_debug("\tlanes_lb_cnt(%d)\n",
lanes_lb_cnt);
pr_debug("\tslots(%d), slot_width(%d)\n",
p_tdm->setting.lane_lb_mask_in
& p_tdm->setting.lane_oe_mask_in);
+ lanes_oe_out_cnt = pop_count(p_tdm->setting.lane_oe_mask_out);
+ lanes_oe_in_cnt = pop_count(p_tdm->setting.lane_oe_mask_in);
+ pr_debug
+ ("\tlanes_oe_out_cnt(%d), lanes_oe_in_cnt(%d)\n",
+ lanes_oe_out_cnt, lanes_oe_in_cnt);
+
if (lanes_oe_out_cnt) {
- force_oe = p_tdm->setting.lane_oe_mask_out;
+ unsigned int oe_fn_version = p_tdm->chipinfo->oe_fn;
+
+ force_oe = (1 << p_tdm->chipinfo->lane_cnt) - 1;
oe_val = p_tdm->setting.lane_oe_mask_out;
+ if (oe_fn_version == OE_FUNCTION_V1) {
+ aml_tdm_set_oe_v1
+ (p_tdm->actrl, p_tdm->id,
+ force_oe, oe_val);
+ } else if (oe_fn_version == OE_FUNCTION_V2) {
+ aml_tdm_set_oe_v2
+ (p_tdm->actrl, p_tdm->id,
+ force_oe, oe_val);
+ } else {
+ pr_err
+ ("%s(), oe version(%d) not support\n",
+ __func__, oe_fn_version);
+ }
}
if (lanes_lb_cnt)
}
}
- out_lanes = lanes_out_cnt + lanes_oe_out_cnt;
+ out_lanes = lanes_out_cnt;
in_lanes = lanes_in_cnt + lanes_oe_in_cnt + lanes_lb_cnt;
if (p_tdm->chipinfo
if (out_lanes > 0 && out_lanes <= LANE_MAX3)
aml_tdm_set_slot_out(p_tdm->actrl,
- p_tdm->id, slots, slot_width,
- force_oe, oe_val);
+ p_tdm->id, slots, slot_width);
/* constrains hw channels_max by DTS configs */
drv->playback.channels_max = slots * out_lanes;
off_set = EE_AUDIO_TDMIN_B_CTRL - EE_AUDIO_TDMIN_A_CTRL;
reg_in = EE_AUDIO_TDMIN_A_CTRL + off_set * idx;
- aml_audiobus_update_bits(actrl, reg_in,
+ aml_audiobus_update_bits
+ (actrl, reg_in,
0x1 << 25, is_rev << 25);
}
-void aml_tdm_set_slot_out(
+void aml_tdm_set_oe_v1(
struct aml_audio_controller *actrl,
- int index, int slots, int slot_width,
- int force_oe, int oe_val)
+ int index, int force_oe, int oe_val)
{
unsigned int reg, offset;
offset = EE_AUDIO_TDMOUT_B_CTRL0 - EE_AUDIO_TDMOUT_A_CTRL0;
reg = EE_AUDIO_TDMOUT_A_CTRL0 + offset * index;
- aml_audiobus_update_bits(actrl, reg,
- 0x3ff, ((slots - 1) << 5) | (slot_width - 1));
if (force_oe) {
+ offset = EE_AUDIO_TDMOUT_B_CTRL2 - EE_AUDIO_TDMOUT_A_CTRL2;
+ reg = EE_AUDIO_TDMOUT_A_CTRL2 + offset * index;
+
aml_audiobus_update_bits(actrl, reg, 0xf << 24, force_oe << 24);
+ /* force oe val, in or out */
+ reg = EE_AUDIO_TDMOUT_A_CTRL1 + offset * index;
+ aml_audiobus_update_bits(actrl, reg, 0xf, oe_val);
+ }
+}
+
+void aml_tdm_set_oe_v2(
+ struct aml_audio_controller *actrl,
+ int index, int force_oe, int oe_val)
+{
+ unsigned int reg, offset;
+
+ if (force_oe) {
+ offset = EE_AUDIO_TDMOUT_B_CTRL2 - EE_AUDIO_TDMOUT_A_CTRL2;
+ reg = EE_AUDIO_TDMOUT_A_CTRL2 + offset * index;
+
+ aml_audiobus_update_bits(actrl, reg, 0xff << 8, force_oe << 8);
+
/* force oe val, in or out */
if (oe_val) {
- reg = EE_AUDIO_TDMOUT_A_CTRL1 + offset * index;
- aml_audiobus_update_bits(actrl, reg,
- 0xf << 0, oe_val << 0);
+ aml_audiobus_update_bits
+ (actrl, reg, 0xff << 16, oe_val << 16);
}
}
}
+void aml_tdm_set_slot_out(
+ struct aml_audio_controller *actrl,
+ int index, int slots, int slot_width)
+{
+ unsigned int reg, offset;
+
+ offset = EE_AUDIO_TDMOUT_B_CTRL0 - EE_AUDIO_TDMOUT_A_CTRL0;
+ reg = EE_AUDIO_TDMOUT_A_CTRL0 + offset * index;
+ aml_audiobus_update_bits
+ (actrl, reg, 0x3ff, ((slots - 1) << 5) | (slot_width - 1));
+}
+
void aml_tdm_set_slot_in(
struct aml_audio_controller *actrl,
int index, int in_src, int slot_width)
extern void aml_tdm_set_slot_out(
struct aml_audio_controller *actrl,
- int index, int slots, int slot_width,
- int force_oe, int oe_val);
+ int index, int slots, int slot_width);
extern void aml_tdm_set_slot_in(
struct aml_audio_controller *actrl,
bool mute,
int lane_cnt);
void aml_tdm_out_reset(unsigned int tdm_id, int offset);
+void aml_tdm_set_oe_v1(
+ struct aml_audio_controller *actrl,
+ int index, int force_oe, int oe_val);
+void aml_tdm_set_oe_v2(
+ struct aml_audio_controller *actrl,
+ int index, int force_oe, int oe_val);
+
#endif
*
*/
+/* For OE function V1:
+ * OE is set by EE_AUDIO_TDMOUT_A_CTRL0 & EE_AUDIO_TDMOUT_A_CTRL1
+ */
+#define OE_FUNCTION_V1 1
+/* For OE function V2:
+ * OE is set by EE_AUDIO_TDMOUT_A_CTRL2
+ */
+#define OE_FUNCTION_V2 2
+
struct tdm_chipinfo {
/* device id */
unsigned int id;
bool sclk_ws_inv;
/* output en (oe) for pinmux */
- bool oe_fn;
+ unsigned int oe_fn;
/* clk pad */
bool no_mclkpad_ctrl;
struct tdm_chipinfo g12a_tdmb_chipinfo = {
.id = TDM_B,
.sclk_ws_inv = true,
- .oe_fn = true,
+ .oe_fn = OE_FUNCTION_V1,
.same_src_fn = true,
.mclkpad_no_offset = true,
};
struct tdm_chipinfo g12a_tdmc_chipinfo = {
.id = TDM_C,
.sclk_ws_inv = true,
- .oe_fn = true,
+ .oe_fn = OE_FUNCTION_V1,
.same_src_fn = true,
.mclkpad_no_offset = true,
};
struct tdm_chipinfo g12a_tdminlb_chipinfo = {
.id = TDM_LB,
.sclk_ws_inv = true,
- .oe_fn = true,
+ .oe_fn = OE_FUNCTION_V1,
.same_src_fn = true,
.mclkpad_no_offset = true,
};
struct tdm_chipinfo tl1_tdma_chipinfo = {
.id = TDM_A,
.sclk_ws_inv = true,
- .oe_fn = true,
+ .oe_fn = OE_FUNCTION_V1,
.same_src_fn = true,
.adc_fn = true,
.reset_reg_offset = 1,
struct tdm_chipinfo tl1_tdmb_chipinfo = {
.id = TDM_B,
.sclk_ws_inv = true,
- .oe_fn = true,
+ .oe_fn = OE_FUNCTION_V1,
.same_src_fn = true,
.adc_fn = true,
.reset_reg_offset = 1,
struct tdm_chipinfo tl1_tdmc_chipinfo = {
.id = TDM_C,
.sclk_ws_inv = true,
- .oe_fn = true,
+ .oe_fn = OE_FUNCTION_V1,
.same_src_fn = true,
.adc_fn = true,
.reset_reg_offset = 1,
struct tdm_chipinfo tl1_tdminlb_chipinfo = {
.id = TDM_LB,
.sclk_ws_inv = true,
- .oe_fn = true,
+ .oe_fn = OE_FUNCTION_V1,
.same_src_fn = true,
.adc_fn = true,
.async_fifo = true,
struct tdm_chipinfo sm1_tdma_chipinfo = {
.id = TDM_A,
.sclk_ws_inv = true,
- .oe_fn = true,
+ .oe_fn = OE_FUNCTION_V2,
.same_src_fn = true,
.lane_cnt = LANE_MAX0,
.reset_reg_offset = 1,
struct tdm_chipinfo sm1_tdmb_chipinfo = {
.id = TDM_B,
.sclk_ws_inv = true,
- .oe_fn = true,
+ .oe_fn = OE_FUNCTION_V2,
.same_src_fn = true,
.lane_cnt = LANE_MAX3,
.reset_reg_offset = 1,
struct tdm_chipinfo sm1_tdmc_chipinfo = {
.id = TDM_C,
.sclk_ws_inv = true,
- .oe_fn = true,
+ .oe_fn = OE_FUNCTION_V2,
.same_src_fn = true,
.lane_cnt = LANE_MAX1,
.reset_reg_offset = 1,
struct tdm_chipinfo sm1_tdminlb_chipinfo = {
.id = TDM_LB,
.sclk_ws_inv = true,
- .oe_fn = true,
+ .oe_fn = OE_FUNCTION_V2,
.same_src_fn = true,
.lane_cnt = LANE_MAX3,
.async_fifo = true,
struct tdm_chipinfo tm2_tdma_chipinfo = {
.id = TDM_A,
.sclk_ws_inv = true,
- .oe_fn = true,
+ .oe_fn = OE_FUNCTION_V2,
.same_src_fn = true,
.adc_fn = true,
.lane_cnt = LANE_MAX3,
struct tdm_chipinfo tm2_tdmb_chipinfo = {
.id = TDM_B,
.sclk_ws_inv = true,
- .oe_fn = true,
+ .oe_fn = OE_FUNCTION_V2,
.same_src_fn = true,
.adc_fn = true,
.lane_cnt = LANE_MAX1,
struct tdm_chipinfo tm2_tdmc_chipinfo = {
.id = TDM_C,
.sclk_ws_inv = true,
- .oe_fn = true,
+ .oe_fn = OE_FUNCTION_V2,
.same_src_fn = true,
.adc_fn = true,
.lane_cnt = LANE_MAX1,
struct tdm_chipinfo tm2_tdminlb_chipinfo = {
.id = TDM_LB,
.sclk_ws_inv = true,
- .oe_fn = true,
+ .oe_fn = OE_FUNCTION_V2,
.same_src_fn = true,
.lane_cnt = LANE_MAX3,
.async_fifo = true,