Merge "ASoC: msmcobalt: Add support for TDM"
This commit is contained in:
commit
b80c3a0a3a
1 changed files with 790 additions and 0 deletions
|
@ -71,6 +71,9 @@
|
||||||
#define WCN_CDC_SLIM_RX_CH_MAX 2
|
#define WCN_CDC_SLIM_RX_CH_MAX 2
|
||||||
#define WCN_CDC_SLIM_TX_CH_MAX 3
|
#define WCN_CDC_SLIM_TX_CH_MAX 3
|
||||||
|
|
||||||
|
#define TDM_CHANNEL_MAX 8
|
||||||
|
#define TDM_SLOT_OFFSET_MAX 8
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
SLIM_RX_0 = 0,
|
SLIM_RX_0 = 0,
|
||||||
SLIM_RX_1,
|
SLIM_RX_1,
|
||||||
|
@ -170,6 +173,131 @@ struct msm_asoc_wcd93xx_codec {
|
||||||
void (*mbhc_hs_detect_exit)(struct snd_soc_codec *codec);
|
void (*mbhc_hs_detect_exit)(struct snd_soc_codec *codec);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
TDM_0 = 0,
|
||||||
|
TDM_1,
|
||||||
|
TDM_2,
|
||||||
|
TDM_3,
|
||||||
|
TDM_4,
|
||||||
|
TDM_5,
|
||||||
|
TDM_6,
|
||||||
|
TDM_7,
|
||||||
|
TDM_PORT_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
TDM_PRI = 0,
|
||||||
|
TDM_SEC,
|
||||||
|
TDM_TERT,
|
||||||
|
TDM_QUAT,
|
||||||
|
TDM_INTERFACE_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tdm_port {
|
||||||
|
u32 mode;
|
||||||
|
u32 channel;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* TDM default config */
|
||||||
|
static struct dev_config tdm_rx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = {
|
||||||
|
{ /* PRI TDM */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_0 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */
|
||||||
|
},
|
||||||
|
{ /* SEC TDM */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_0 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */
|
||||||
|
},
|
||||||
|
{ /* TERT TDM */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_0 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */
|
||||||
|
},
|
||||||
|
{ /* QUAT TDM */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_0 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* TDM default config */
|
||||||
|
static struct dev_config tdm_tx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = {
|
||||||
|
{ /* PRI TDM */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_0 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_4 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_6 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */
|
||||||
|
},
|
||||||
|
{ /* SEC TDM */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_0 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_4 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_6 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */
|
||||||
|
},
|
||||||
|
{ /* TERT TDM */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_0 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_4 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_6 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */
|
||||||
|
},
|
||||||
|
{ /* QUAT TDM */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_0 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_4 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_6 */
|
||||||
|
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*TDM default offset currently only supporting TDM_RX_0 and TDM_TX_0 */
|
||||||
|
static unsigned int tdm_slot_offset[TDM_PORT_MAX][TDM_SLOT_OFFSET_MAX] = {
|
||||||
|
{0, 4, 8, 12, 16, 20, 24, 28},/* TX_0 | RX_0 */
|
||||||
|
{AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_1 | RX_1 */
|
||||||
|
{AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_2 | RX_2 */
|
||||||
|
{AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_3 | RX_3 */
|
||||||
|
{AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_4 | RX_4 */
|
||||||
|
{AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_5 | RX_5 */
|
||||||
|
{AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_6 | RX_6 */
|
||||||
|
{AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_7 | RX_7 */
|
||||||
|
};
|
||||||
|
|
||||||
/* Default configuration of slimbus channels */
|
/* Default configuration of slimbus channels */
|
||||||
static struct dev_config slim_rx_cfg[] = {
|
static struct dev_config slim_rx_cfg[] = {
|
||||||
[SLIM_RX_0] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
|
[SLIM_RX_0] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
|
||||||
|
@ -272,6 +400,12 @@ static char const *usb_sample_rate_text[] = {"KHZ_8", "KHZ_11P025",
|
||||||
"KHZ_96", "KHZ_192"};
|
"KHZ_96", "KHZ_192"};
|
||||||
static char const *ext_disp_sample_rate_text[] = {"KHZ_48", "KHZ_96",
|
static char const *ext_disp_sample_rate_text[] = {"KHZ_48", "KHZ_96",
|
||||||
"KHZ_192"};
|
"KHZ_192"};
|
||||||
|
static char const *tdm_ch_text[] = {"One", "Two", "Three", "Four",
|
||||||
|
"Five", "Six", "Seven", "Eight"};
|
||||||
|
static char const *tdm_bit_format_text[] = {"S16_LE", "S24_LE", "S32_LE"};
|
||||||
|
static char const *tdm_sample_rate_text[] = {"KHZ_8", "KHZ_16", "KHZ_32",
|
||||||
|
"KHZ_44P1", "KHZ_48", "KHZ_96",
|
||||||
|
"KHZ_192", "KHZ_352P8", "KHZ_384"};
|
||||||
static const char *const auxpcm_rate_text[] = {"KHZ_8", "KHZ_16"};
|
static const char *const auxpcm_rate_text[] = {"KHZ_8", "KHZ_16"};
|
||||||
static char const *mi2s_rate_text[] = {"KHZ_8", "KHZ_16",
|
static char const *mi2s_rate_text[] = {"KHZ_8", "KHZ_16",
|
||||||
"KHZ_32", "KHZ_44P1", "KHZ_48",
|
"KHZ_32", "KHZ_44P1", "KHZ_48",
|
||||||
|
@ -308,6 +442,12 @@ static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_sample_rate, usb_sample_rate_text);
|
||||||
static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_sample_rate, usb_sample_rate_text);
|
static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_sample_rate, usb_sample_rate_text);
|
||||||
static SOC_ENUM_SINGLE_EXT_DECL(ext_disp_rx_sample_rate,
|
static SOC_ENUM_SINGLE_EXT_DECL(ext_disp_rx_sample_rate,
|
||||||
ext_disp_sample_rate_text);
|
ext_disp_sample_rate_text);
|
||||||
|
static SOC_ENUM_SINGLE_EXT_DECL(tdm_tx_chs, tdm_ch_text);
|
||||||
|
static SOC_ENUM_SINGLE_EXT_DECL(tdm_tx_format, tdm_bit_format_text);
|
||||||
|
static SOC_ENUM_SINGLE_EXT_DECL(tdm_tx_sample_rate, tdm_sample_rate_text);
|
||||||
|
static SOC_ENUM_SINGLE_EXT_DECL(tdm_rx_chs, tdm_ch_text);
|
||||||
|
static SOC_ENUM_SINGLE_EXT_DECL(tdm_rx_format, tdm_bit_format_text);
|
||||||
|
static SOC_ENUM_SINGLE_EXT_DECL(tdm_rx_sample_rate, tdm_sample_rate_text);
|
||||||
static SOC_ENUM_SINGLE_EXT_DECL(prim_aux_pcm_rx_sample_rate, auxpcm_rate_text);
|
static SOC_ENUM_SINGLE_EXT_DECL(prim_aux_pcm_rx_sample_rate, auxpcm_rate_text);
|
||||||
static SOC_ENUM_SINGLE_EXT_DECL(sec_aux_pcm_rx_sample_rate, auxpcm_rate_text);
|
static SOC_ENUM_SINGLE_EXT_DECL(sec_aux_pcm_rx_sample_rate, auxpcm_rate_text);
|
||||||
static SOC_ENUM_SINGLE_EXT_DECL(tert_aux_pcm_rx_sample_rate, auxpcm_rate_text);
|
static SOC_ENUM_SINGLE_EXT_DECL(tert_aux_pcm_rx_sample_rate, auxpcm_rate_text);
|
||||||
|
@ -1328,6 +1468,45 @@ static int proxy_rx_ch_put(struct snd_kcontrol *kcontrol,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int tdm_get_sample_rate(int value)
|
||||||
|
{
|
||||||
|
int sample_rate = 0;
|
||||||
|
|
||||||
|
switch (value) {
|
||||||
|
case 0:
|
||||||
|
sample_rate = SAMPLING_RATE_8KHZ;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
sample_rate = SAMPLING_RATE_16KHZ;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
sample_rate = SAMPLING_RATE_32KHZ;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
sample_rate = SAMPLING_RATE_44P1KHZ;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
sample_rate = SAMPLING_RATE_48KHZ;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
sample_rate = SAMPLING_RATE_96KHZ;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
sample_rate = SAMPLING_RATE_192KHZ;
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
sample_rate = SAMPLING_RATE_352P8KHZ;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
sample_rate = SAMPLING_RATE_384KHZ;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sample_rate = SAMPLING_RATE_48KHZ;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return sample_rate;
|
||||||
|
}
|
||||||
|
|
||||||
static int aux_pcm_get_sample_rate(int value)
|
static int aux_pcm_get_sample_rate(int value)
|
||||||
{
|
{
|
||||||
int sample_rate;
|
int sample_rate;
|
||||||
|
@ -1344,6 +1523,45 @@ static int aux_pcm_get_sample_rate(int value)
|
||||||
return sample_rate;
|
return sample_rate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int tdm_get_sample_rate_val(int sample_rate)
|
||||||
|
{
|
||||||
|
int sample_rate_val = 0;
|
||||||
|
|
||||||
|
switch (sample_rate) {
|
||||||
|
case SAMPLING_RATE_8KHZ:
|
||||||
|
sample_rate_val = 0;
|
||||||
|
break;
|
||||||
|
case SAMPLING_RATE_16KHZ:
|
||||||
|
sample_rate_val = 1;
|
||||||
|
break;
|
||||||
|
case SAMPLING_RATE_32KHZ:
|
||||||
|
sample_rate_val = 2;
|
||||||
|
break;
|
||||||
|
case SAMPLING_RATE_44P1KHZ:
|
||||||
|
sample_rate_val = 3;
|
||||||
|
break;
|
||||||
|
case SAMPLING_RATE_48KHZ:
|
||||||
|
sample_rate_val = 4;
|
||||||
|
break;
|
||||||
|
case SAMPLING_RATE_96KHZ:
|
||||||
|
sample_rate_val = 5;
|
||||||
|
break;
|
||||||
|
case SAMPLING_RATE_192KHZ:
|
||||||
|
sample_rate_val = 6;
|
||||||
|
break;
|
||||||
|
case SAMPLING_RATE_352P8KHZ:
|
||||||
|
sample_rate_val = 7;
|
||||||
|
break;
|
||||||
|
case SAMPLING_RATE_384KHZ:
|
||||||
|
sample_rate_val = 8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sample_rate_val = 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return sample_rate_val;
|
||||||
|
}
|
||||||
|
|
||||||
static int aux_pcm_get_sample_rate_val(int sample_rate)
|
static int aux_pcm_get_sample_rate_val(int sample_rate)
|
||||||
{
|
{
|
||||||
int sample_rate_val;
|
int sample_rate_val;
|
||||||
|
@ -1360,6 +1578,361 @@ static int aux_pcm_get_sample_rate_val(int sample_rate)
|
||||||
return sample_rate_val;
|
return sample_rate_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int tdm_get_port_idx(struct snd_kcontrol *kcontrol,
|
||||||
|
struct tdm_port *port)
|
||||||
|
{
|
||||||
|
if (port) {
|
||||||
|
if (strnstr(kcontrol->id.name, "PRI",
|
||||||
|
sizeof(kcontrol->id.name))) {
|
||||||
|
port->mode = TDM_PRI;
|
||||||
|
} else if (strnstr(kcontrol->id.name, "SEC",
|
||||||
|
sizeof(kcontrol->id.name))) {
|
||||||
|
port->mode = TDM_SEC;
|
||||||
|
} else if (strnstr(kcontrol->id.name, "TERT",
|
||||||
|
sizeof(kcontrol->id.name))) {
|
||||||
|
port->mode = TDM_TERT;
|
||||||
|
} else if (strnstr(kcontrol->id.name, "QUAT",
|
||||||
|
sizeof(kcontrol->id.name))) {
|
||||||
|
port->mode = TDM_QUAT;
|
||||||
|
} else {
|
||||||
|
pr_err("%s: unsupported mode in: %s",
|
||||||
|
__func__, kcontrol->id.name);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strnstr(kcontrol->id.name, "RX_0",
|
||||||
|
sizeof(kcontrol->id.name)) ||
|
||||||
|
strnstr(kcontrol->id.name, "TX_0",
|
||||||
|
sizeof(kcontrol->id.name))) {
|
||||||
|
port->channel = TDM_0;
|
||||||
|
} else if (strnstr(kcontrol->id.name, "RX_1",
|
||||||
|
sizeof(kcontrol->id.name)) ||
|
||||||
|
strnstr(kcontrol->id.name, "TX_1",
|
||||||
|
sizeof(kcontrol->id.name))) {
|
||||||
|
port->channel = TDM_1;
|
||||||
|
} else if (strnstr(kcontrol->id.name, "RX_2",
|
||||||
|
sizeof(kcontrol->id.name)) ||
|
||||||
|
strnstr(kcontrol->id.name, "TX_2",
|
||||||
|
sizeof(kcontrol->id.name))) {
|
||||||
|
port->channel = TDM_2;
|
||||||
|
} else if (strnstr(kcontrol->id.name, "RX_3",
|
||||||
|
sizeof(kcontrol->id.name)) ||
|
||||||
|
strnstr(kcontrol->id.name, "TX_3",
|
||||||
|
sizeof(kcontrol->id.name))) {
|
||||||
|
port->channel = TDM_3;
|
||||||
|
} else if (strnstr(kcontrol->id.name, "RX_4",
|
||||||
|
sizeof(kcontrol->id.name)) ||
|
||||||
|
strnstr(kcontrol->id.name, "TX_4",
|
||||||
|
sizeof(kcontrol->id.name))) {
|
||||||
|
port->channel = TDM_4;
|
||||||
|
} else if (strnstr(kcontrol->id.name, "RX_5",
|
||||||
|
sizeof(kcontrol->id.name)) ||
|
||||||
|
strnstr(kcontrol->id.name, "TX_5",
|
||||||
|
sizeof(kcontrol->id.name))) {
|
||||||
|
port->channel = TDM_5;
|
||||||
|
} else if (strnstr(kcontrol->id.name, "RX_6",
|
||||||
|
sizeof(kcontrol->id.name)) ||
|
||||||
|
strnstr(kcontrol->id.name, "TX_6",
|
||||||
|
sizeof(kcontrol->id.name))) {
|
||||||
|
port->channel = TDM_6;
|
||||||
|
} else if (strnstr(kcontrol->id.name, "RX_7",
|
||||||
|
sizeof(kcontrol->id.name)) ||
|
||||||
|
strnstr(kcontrol->id.name, "TX_7",
|
||||||
|
sizeof(kcontrol->id.name))) {
|
||||||
|
port->channel = TDM_7;
|
||||||
|
} else {
|
||||||
|
pr_err("%s: unsupported channel in: %s",
|
||||||
|
__func__, kcontrol->id.name);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
return -EINVAL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tdm_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
|
||||||
|
struct snd_ctl_elem_value *ucontrol)
|
||||||
|
{
|
||||||
|
struct tdm_port port;
|
||||||
|
int ret = tdm_get_port_idx(kcontrol, &port);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
pr_err("%s: unsupported control: %s",
|
||||||
|
__func__, kcontrol->id.name);
|
||||||
|
} else {
|
||||||
|
ucontrol->value.enumerated.item[0] = tdm_get_sample_rate_val(
|
||||||
|
tdm_rx_cfg[port.mode][port.channel].sample_rate);
|
||||||
|
|
||||||
|
pr_debug("%s: tdm_rx_sample_rate = %d, item = %d\n", __func__,
|
||||||
|
tdm_rx_cfg[port.mode][port.channel].sample_rate,
|
||||||
|
ucontrol->value.enumerated.item[0]);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tdm_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
|
||||||
|
struct snd_ctl_elem_value *ucontrol)
|
||||||
|
{
|
||||||
|
struct tdm_port port;
|
||||||
|
int ret = tdm_get_port_idx(kcontrol, &port);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
pr_err("%s: unsupported control: %s",
|
||||||
|
__func__, kcontrol->id.name);
|
||||||
|
} else {
|
||||||
|
tdm_rx_cfg[port.mode][port.channel].sample_rate =
|
||||||
|
tdm_get_sample_rate(ucontrol->value.enumerated.item[0]);
|
||||||
|
|
||||||
|
pr_debug("%s: tdm_rx_sample_rate = %d, item = %d\n", __func__,
|
||||||
|
tdm_rx_cfg[port.mode][port.channel].sample_rate,
|
||||||
|
ucontrol->value.enumerated.item[0]);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tdm_tx_sample_rate_get(struct snd_kcontrol *kcontrol,
|
||||||
|
struct snd_ctl_elem_value *ucontrol)
|
||||||
|
{
|
||||||
|
struct tdm_port port;
|
||||||
|
int ret = tdm_get_port_idx(kcontrol, &port);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
pr_err("%s: unsupported control: %s",
|
||||||
|
__func__, kcontrol->id.name);
|
||||||
|
} else {
|
||||||
|
ucontrol->value.enumerated.item[0] = tdm_get_sample_rate_val(
|
||||||
|
tdm_tx_cfg[port.mode][port.channel].sample_rate);
|
||||||
|
|
||||||
|
pr_debug("%s: tdm_tx_sample_rate = %d, item = %d\n", __func__,
|
||||||
|
tdm_tx_cfg[port.mode][port.channel].sample_rate,
|
||||||
|
ucontrol->value.enumerated.item[0]);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tdm_tx_sample_rate_put(struct snd_kcontrol *kcontrol,
|
||||||
|
struct snd_ctl_elem_value *ucontrol)
|
||||||
|
{
|
||||||
|
struct tdm_port port;
|
||||||
|
int ret = tdm_get_port_idx(kcontrol, &port);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
pr_err("%s: unsupported control: %s",
|
||||||
|
__func__, kcontrol->id.name);
|
||||||
|
} else {
|
||||||
|
tdm_tx_cfg[port.mode][port.channel].sample_rate =
|
||||||
|
tdm_get_sample_rate(ucontrol->value.enumerated.item[0]);
|
||||||
|
|
||||||
|
pr_debug("%s: tdm_tx_sample_rate = %d, item = %d\n", __func__,
|
||||||
|
tdm_tx_cfg[port.mode][port.channel].sample_rate,
|
||||||
|
ucontrol->value.enumerated.item[0]);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tdm_get_format(int value)
|
||||||
|
{
|
||||||
|
int format = 0;
|
||||||
|
|
||||||
|
switch (value) {
|
||||||
|
case 0:
|
||||||
|
format = SNDRV_PCM_FORMAT_S16_LE;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
format = SNDRV_PCM_FORMAT_S24_LE;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
format = SNDRV_PCM_FORMAT_S32_LE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
format = SNDRV_PCM_FORMAT_S16_LE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tdm_get_format_val(int format)
|
||||||
|
{
|
||||||
|
int value = 0;
|
||||||
|
|
||||||
|
switch (format) {
|
||||||
|
case SNDRV_PCM_FORMAT_S16_LE:
|
||||||
|
value = 0;
|
||||||
|
break;
|
||||||
|
case SNDRV_PCM_FORMAT_S24_LE:
|
||||||
|
value = 1;
|
||||||
|
break;
|
||||||
|
case SNDRV_PCM_FORMAT_S32_LE:
|
||||||
|
value = 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
value = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tdm_rx_format_get(struct snd_kcontrol *kcontrol,
|
||||||
|
struct snd_ctl_elem_value *ucontrol)
|
||||||
|
{
|
||||||
|
struct tdm_port port;
|
||||||
|
int ret = tdm_get_port_idx(kcontrol, &port);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
pr_err("%s: unsupported control: %s",
|
||||||
|
__func__, kcontrol->id.name);
|
||||||
|
} else {
|
||||||
|
ucontrol->value.enumerated.item[0] = tdm_get_format_val(
|
||||||
|
tdm_rx_cfg[port.mode][port.channel].bit_format);
|
||||||
|
|
||||||
|
pr_debug("%s: tdm_rx_bit_format = %d, item = %d\n", __func__,
|
||||||
|
tdm_rx_cfg[port.mode][port.channel].bit_format,
|
||||||
|
ucontrol->value.enumerated.item[0]);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tdm_rx_format_put(struct snd_kcontrol *kcontrol,
|
||||||
|
struct snd_ctl_elem_value *ucontrol)
|
||||||
|
{
|
||||||
|
struct tdm_port port;
|
||||||
|
int ret = tdm_get_port_idx(kcontrol, &port);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
pr_err("%s: unsupported control: %s",
|
||||||
|
__func__, kcontrol->id.name);
|
||||||
|
} else {
|
||||||
|
tdm_rx_cfg[port.mode][port.channel].bit_format =
|
||||||
|
tdm_get_format(ucontrol->value.enumerated.item[0]);
|
||||||
|
|
||||||
|
pr_debug("%s: tdm_rx_bit_format = %d, item = %d\n", __func__,
|
||||||
|
tdm_rx_cfg[port.mode][port.channel].bit_format,
|
||||||
|
ucontrol->value.enumerated.item[0]);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tdm_tx_format_get(struct snd_kcontrol *kcontrol,
|
||||||
|
struct snd_ctl_elem_value *ucontrol)
|
||||||
|
{
|
||||||
|
struct tdm_port port;
|
||||||
|
int ret = tdm_get_port_idx(kcontrol, &port);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
pr_err("%s: unsupported control: %s",
|
||||||
|
__func__, kcontrol->id.name);
|
||||||
|
} else {
|
||||||
|
ucontrol->value.enumerated.item[0] = tdm_get_format_val(
|
||||||
|
tdm_tx_cfg[port.mode][port.channel].bit_format);
|
||||||
|
|
||||||
|
pr_debug("%s: tdm_tx_bit_format = %d, item = %d\n", __func__,
|
||||||
|
tdm_tx_cfg[port.mode][port.channel].bit_format,
|
||||||
|
ucontrol->value.enumerated.item[0]);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tdm_tx_format_put(struct snd_kcontrol *kcontrol,
|
||||||
|
struct snd_ctl_elem_value *ucontrol)
|
||||||
|
{
|
||||||
|
struct tdm_port port;
|
||||||
|
int ret = tdm_get_port_idx(kcontrol, &port);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
pr_err("%s: unsupported control: %s",
|
||||||
|
__func__, kcontrol->id.name);
|
||||||
|
} else {
|
||||||
|
tdm_tx_cfg[port.mode][port.channel].bit_format =
|
||||||
|
tdm_get_format(ucontrol->value.enumerated.item[0]);
|
||||||
|
|
||||||
|
pr_debug("%s: tdm_tx_bit_format = %d, item = %d\n", __func__,
|
||||||
|
tdm_tx_cfg[port.mode][port.channel].bit_format,
|
||||||
|
ucontrol->value.enumerated.item[0]);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tdm_rx_ch_get(struct snd_kcontrol *kcontrol,
|
||||||
|
struct snd_ctl_elem_value *ucontrol)
|
||||||
|
{
|
||||||
|
struct tdm_port port;
|
||||||
|
int ret = tdm_get_port_idx(kcontrol, &port);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
pr_err("%s: unsupported control: %s",
|
||||||
|
__func__, kcontrol->id.name);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
ucontrol->value.enumerated.item[0] =
|
||||||
|
tdm_rx_cfg[port.mode][port.channel].channels - 1;
|
||||||
|
|
||||||
|
pr_debug("%s: tdm_rx_ch = %d, item = %d\n", __func__,
|
||||||
|
tdm_rx_cfg[port.mode][port.channel].channels - 1,
|
||||||
|
ucontrol->value.enumerated.item[0]);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tdm_rx_ch_put(struct snd_kcontrol *kcontrol,
|
||||||
|
struct snd_ctl_elem_value *ucontrol)
|
||||||
|
{
|
||||||
|
struct tdm_port port;
|
||||||
|
int ret = tdm_get_port_idx(kcontrol, &port);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
pr_err("%s: unsupported control: %s",
|
||||||
|
__func__, kcontrol->id.name);
|
||||||
|
} else {
|
||||||
|
tdm_rx_cfg[port.mode][port.channel].channels =
|
||||||
|
ucontrol->value.enumerated.item[0] + 1;
|
||||||
|
|
||||||
|
pr_debug("%s: tdm_rx_ch = %d, item = %d\n", __func__,
|
||||||
|
tdm_rx_cfg[port.mode][port.channel].channels,
|
||||||
|
ucontrol->value.enumerated.item[0] + 1);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tdm_tx_ch_get(struct snd_kcontrol *kcontrol,
|
||||||
|
struct snd_ctl_elem_value *ucontrol)
|
||||||
|
{
|
||||||
|
struct tdm_port port;
|
||||||
|
int ret = tdm_get_port_idx(kcontrol, &port);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
pr_err("%s: unsupported control: %s",
|
||||||
|
__func__, kcontrol->id.name);
|
||||||
|
} else {
|
||||||
|
ucontrol->value.enumerated.item[0] =
|
||||||
|
tdm_tx_cfg[port.mode][port.channel].channels - 1;
|
||||||
|
|
||||||
|
pr_debug("%s: tdm_tx_ch = %d, item = %d\n", __func__,
|
||||||
|
tdm_tx_cfg[port.mode][port.channel].channels - 1,
|
||||||
|
ucontrol->value.enumerated.item[0]);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tdm_tx_ch_put(struct snd_kcontrol *kcontrol,
|
||||||
|
struct snd_ctl_elem_value *ucontrol)
|
||||||
|
{
|
||||||
|
struct tdm_port port;
|
||||||
|
int ret = tdm_get_port_idx(kcontrol, &port);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
pr_err("%s: unsupported control: %s",
|
||||||
|
__func__, kcontrol->id.name);
|
||||||
|
} else {
|
||||||
|
tdm_tx_cfg[port.mode][port.channel].channels =
|
||||||
|
ucontrol->value.enumerated.item[0] + 1;
|
||||||
|
|
||||||
|
pr_debug("%s: tdm_tx_ch = %d, item = %d\n", __func__,
|
||||||
|
tdm_tx_cfg[port.mode][port.channel].channels,
|
||||||
|
ucontrol->value.enumerated.item[0] + 1);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int aux_pcm_get_port_idx(struct snd_kcontrol *kcontrol)
|
static int aux_pcm_get_port_idx(struct snd_kcontrol *kcontrol)
|
||||||
{
|
{
|
||||||
int idx;
|
int idx;
|
||||||
|
@ -1758,6 +2331,24 @@ static const struct snd_kcontrol_new msm_snd_controls[] = {
|
||||||
SOC_ENUM_EXT("Display Port RX SampleRate", ext_disp_rx_sample_rate,
|
SOC_ENUM_EXT("Display Port RX SampleRate", ext_disp_rx_sample_rate,
|
||||||
ext_disp_rx_sample_rate_get,
|
ext_disp_rx_sample_rate_get,
|
||||||
ext_disp_rx_sample_rate_put),
|
ext_disp_rx_sample_rate_put),
|
||||||
|
SOC_ENUM_EXT("TERT_TDM_RX_0 SampleRate", tdm_rx_sample_rate,
|
||||||
|
tdm_rx_sample_rate_get,
|
||||||
|
tdm_rx_sample_rate_put),
|
||||||
|
SOC_ENUM_EXT("TERT_TDM_TX_0 SampleRate", tdm_tx_sample_rate,
|
||||||
|
tdm_tx_sample_rate_get,
|
||||||
|
tdm_tx_sample_rate_put),
|
||||||
|
SOC_ENUM_EXT("TERT_TDM_RX_0 Format", tdm_rx_format,
|
||||||
|
tdm_rx_format_get,
|
||||||
|
tdm_rx_format_put),
|
||||||
|
SOC_ENUM_EXT("TERT_TDM_TX_0 Format", tdm_tx_format,
|
||||||
|
tdm_tx_format_get,
|
||||||
|
tdm_tx_format_put),
|
||||||
|
SOC_ENUM_EXT("TERT_TDM_RX_0 Channels", tdm_rx_chs,
|
||||||
|
tdm_rx_ch_get,
|
||||||
|
tdm_rx_ch_put),
|
||||||
|
SOC_ENUM_EXT("TERT_TDM_TX_0 Channels", tdm_tx_chs,
|
||||||
|
tdm_tx_ch_get,
|
||||||
|
tdm_tx_ch_put),
|
||||||
SOC_ENUM_EXT("PRIM_AUX_PCM_RX SampleRate", prim_aux_pcm_rx_sample_rate,
|
SOC_ENUM_EXT("PRIM_AUX_PCM_RX SampleRate", prim_aux_pcm_rx_sample_rate,
|
||||||
aux_pcm_rx_sample_rate_get,
|
aux_pcm_rx_sample_rate_get,
|
||||||
aux_pcm_rx_sample_rate_put),
|
aux_pcm_rx_sample_rate_put),
|
||||||
|
@ -2095,6 +2686,22 @@ static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
|
||||||
rate->min = rate->max = SAMPLING_RATE_48KHZ;
|
rate->min = rate->max = SAMPLING_RATE_48KHZ;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case MSM_BACKEND_DAI_TERT_TDM_RX_0:
|
||||||
|
channels->min = channels->max =
|
||||||
|
tdm_rx_cfg[TDM_TERT][TDM_0].channels;
|
||||||
|
param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
|
||||||
|
tdm_rx_cfg[TDM_TERT][TDM_0].bit_format);
|
||||||
|
rate->min = rate->max = tdm_rx_cfg[TDM_TERT][TDM_0].sample_rate;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MSM_BACKEND_DAI_TERT_TDM_TX_0:
|
||||||
|
channels->min = channels->max =
|
||||||
|
tdm_tx_cfg[TDM_TERT][TDM_0].channels;
|
||||||
|
param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
|
||||||
|
tdm_tx_cfg[TDM_TERT][TDM_0].bit_format);
|
||||||
|
rate->min = rate->max = tdm_tx_cfg[TDM_TERT][TDM_0].sample_rate;
|
||||||
|
break;
|
||||||
|
|
||||||
case MSM_BACKEND_DAI_AUXPCM_RX:
|
case MSM_BACKEND_DAI_AUXPCM_RX:
|
||||||
rate->min = rate->max =
|
rate->min = rate->max =
|
||||||
aux_pcm_rx_cfg[PRIM_AUX_PCM].sample_rate;
|
aux_pcm_rx_cfg[PRIM_AUX_PCM].sample_rate;
|
||||||
|
@ -3176,6 +3783,157 @@ static struct snd_soc_ops msm_aux_pcm_be_ops = {
|
||||||
.shutdown = msm_aux_pcm_snd_shutdown,
|
.shutdown = msm_aux_pcm_snd_shutdown,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static unsigned int tdm_param_set_slot_mask(u16 port_id, int slot_width,
|
||||||
|
int slots)
|
||||||
|
{
|
||||||
|
unsigned int slot_mask = 0;
|
||||||
|
int i, j;
|
||||||
|
unsigned int *slot_offset;
|
||||||
|
|
||||||
|
for (i = TDM_0; i < TDM_PORT_MAX; i++) {
|
||||||
|
slot_offset = tdm_slot_offset[i];
|
||||||
|
|
||||||
|
for (j = 0; j < TDM_SLOT_OFFSET_MAX; j++) {
|
||||||
|
if (slot_offset[j] != AFE_SLOT_MAPPING_OFFSET_INVALID)
|
||||||
|
slot_mask |=
|
||||||
|
(1 << ((slot_offset[j] * 8) / slot_width));
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return slot_mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int msm_tdm_snd_hw_params(struct snd_pcm_substream *substream,
|
||||||
|
struct snd_pcm_hw_params *params)
|
||||||
|
{
|
||||||
|
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||||
|
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||||
|
int ret = 0;
|
||||||
|
int channels, slot_width, slots;
|
||||||
|
unsigned int slot_mask;
|
||||||
|
unsigned int *slot_offset;
|
||||||
|
int offset_channels = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
pr_debug("%s: dai id = 0x%x\n", __func__, cpu_dai->id);
|
||||||
|
|
||||||
|
channels = params_channels(params);
|
||||||
|
switch (channels) {
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
case 3:
|
||||||
|
case 4:
|
||||||
|
case 5:
|
||||||
|
case 6:
|
||||||
|
case 7:
|
||||||
|
case 8:
|
||||||
|
switch (params_format(params)) {
|
||||||
|
case SNDRV_PCM_FORMAT_S32_LE:
|
||||||
|
case SNDRV_PCM_FORMAT_S24_LE:
|
||||||
|
case SNDRV_PCM_FORMAT_S16_LE:
|
||||||
|
/*
|
||||||
|
* up to 8 channels HW config should
|
||||||
|
* use 32 bit slot width for max support of
|
||||||
|
* stream bit width. (slot_width > bit_width)
|
||||||
|
*/
|
||||||
|
slot_width = 32;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
pr_err("%s: invalid param format 0x%x\n",
|
||||||
|
__func__, params_format(params));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
slots = 8;
|
||||||
|
slot_mask = tdm_param_set_slot_mask(cpu_dai->id,
|
||||||
|
slot_width,
|
||||||
|
slots);
|
||||||
|
if (!slot_mask) {
|
||||||
|
pr_err("%s: invalid slot_mask 0x%x\n",
|
||||||
|
__func__, slot_mask);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
pr_err("%s: invalid param channels %d\n",
|
||||||
|
__func__, channels);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
/* currently only supporting TDM_RX_0 and TDM_TX_0 */
|
||||||
|
switch (cpu_dai->id) {
|
||||||
|
case AFE_PORT_ID_PRIMARY_TDM_RX:
|
||||||
|
case AFE_PORT_ID_SECONDARY_TDM_RX:
|
||||||
|
case AFE_PORT_ID_TERTIARY_TDM_RX:
|
||||||
|
case AFE_PORT_ID_QUATERNARY_TDM_RX:
|
||||||
|
case AFE_PORT_ID_PRIMARY_TDM_TX:
|
||||||
|
case AFE_PORT_ID_SECONDARY_TDM_TX:
|
||||||
|
case AFE_PORT_ID_TERTIARY_TDM_TX:
|
||||||
|
case AFE_PORT_ID_QUATERNARY_TDM_TX:
|
||||||
|
slot_offset = tdm_slot_offset[TDM_0];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
pr_err("%s: dai id 0x%x not supported\n",
|
||||||
|
__func__, cpu_dai->id);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < TDM_SLOT_OFFSET_MAX; i++) {
|
||||||
|
if (slot_offset[i] != AFE_SLOT_MAPPING_OFFSET_INVALID)
|
||||||
|
offset_channels++;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset_channels == 0) {
|
||||||
|
pr_err("%s: slot offset not supported, offset_channels %d\n",
|
||||||
|
__func__, offset_channels);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (channels > offset_channels) {
|
||||||
|
pr_err("%s: channels %d exceed offset_channels %d\n",
|
||||||
|
__func__, channels, offset_channels);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||||
|
ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0, slot_mask,
|
||||||
|
slots, slot_width);
|
||||||
|
if (ret < 0) {
|
||||||
|
pr_err("%s: failed to set tdm slot, err:%d\n",
|
||||||
|
__func__, ret);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = snd_soc_dai_set_channel_map(cpu_dai, 0, NULL,
|
||||||
|
channels, slot_offset);
|
||||||
|
if (ret < 0) {
|
||||||
|
pr_err("%s: failed to set channel map, err:%d\n",
|
||||||
|
__func__, ret);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret = snd_soc_dai_set_tdm_slot(cpu_dai, slot_mask, 0,
|
||||||
|
slots, slot_width);
|
||||||
|
if (ret < 0) {
|
||||||
|
pr_err("%s: failed to set tdm slot, err:%d\n",
|
||||||
|
__func__, ret);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = snd_soc_dai_set_channel_map(cpu_dai, channels,
|
||||||
|
slot_offset, 0, NULL);
|
||||||
|
if (ret < 0) {
|
||||||
|
pr_err("%s: failed to set channel map, err:%d\n",
|
||||||
|
__func__, ret);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static struct snd_soc_ops msm_be_ops = {
|
static struct snd_soc_ops msm_be_ops = {
|
||||||
.hw_params = msm_snd_hw_params,
|
.hw_params = msm_snd_hw_params,
|
||||||
};
|
};
|
||||||
|
@ -3192,6 +3950,10 @@ static struct snd_soc_ops msm_wcn_ops = {
|
||||||
.hw_params = msm_wcn_hw_params,
|
.hw_params = msm_wcn_hw_params,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct snd_soc_ops msm_tdm_be_ops = {
|
||||||
|
.hw_params = msm_tdm_snd_hw_params
|
||||||
|
};
|
||||||
|
|
||||||
/* Digital audio interface glue - connects codec <---> CPU */
|
/* Digital audio interface glue - connects codec <---> CPU */
|
||||||
static struct snd_soc_dai_link msm_common_dai_links[] = {
|
static struct snd_soc_dai_link msm_common_dai_links[] = {
|
||||||
/* FrontEnd DAI Links */
|
/* FrontEnd DAI Links */
|
||||||
|
@ -3992,6 +4754,34 @@ static struct snd_soc_dai_link msm_common_be_dai_links[] = {
|
||||||
.be_hw_params_fixup = msm_be_hw_params_fixup,
|
.be_hw_params_fixup = msm_be_hw_params_fixup,
|
||||||
.ignore_suspend = 1,
|
.ignore_suspend = 1,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = LPASS_BE_TERT_TDM_RX_0,
|
||||||
|
.stream_name = "Tertiary TDM0 Playback",
|
||||||
|
.cpu_dai_name = "msm-dai-q6-tdm.36896",
|
||||||
|
.platform_name = "msm-pcm-routing",
|
||||||
|
.codec_name = "msm-stub-codec.1",
|
||||||
|
.codec_dai_name = "msm-stub-rx",
|
||||||
|
.no_pcm = 1,
|
||||||
|
.dpcm_playback = 1,
|
||||||
|
.be_id = MSM_BACKEND_DAI_TERT_TDM_RX_0,
|
||||||
|
.be_hw_params_fixup = msm_be_hw_params_fixup,
|
||||||
|
.ops = &msm_tdm_be_ops,
|
||||||
|
.ignore_suspend = 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = LPASS_BE_TERT_TDM_TX_0,
|
||||||
|
.stream_name = "Tertiary TDM0 Capture",
|
||||||
|
.cpu_dai_name = "msm-dai-q6-tdm.36897",
|
||||||
|
.platform_name = "msm-pcm-routing",
|
||||||
|
.codec_name = "msm-stub-codec.1",
|
||||||
|
.codec_dai_name = "msm-stub-tx",
|
||||||
|
.no_pcm = 1,
|
||||||
|
.dpcm_capture = 1,
|
||||||
|
.be_id = MSM_BACKEND_DAI_TERT_TDM_TX_0,
|
||||||
|
.be_hw_params_fixup = msm_be_hw_params_fixup,
|
||||||
|
.ops = &msm_tdm_be_ops,
|
||||||
|
.ignore_suspend = 1,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct snd_soc_dai_link msm_tasha_be_dai_links[] = {
|
static struct snd_soc_dai_link msm_tasha_be_dai_links[] = {
|
||||||
|
|
Loading…
Add table
Reference in a new issue