summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sound/soc/msm/msmfalcon-common.c1146
-rw-r--r--sound/soc/msm/msmfalcon-common.h36
-rw-r--r--sound/soc/msm/msmfalcon-ext-dai-links.c452
-rw-r--r--sound/soc/msm/msmfalcon-external.c83
-rw-r--r--sound/soc/msm/msmfalcon-external.h8
-rw-r--r--sound/soc/msm/msmfalcon-internal.c521
6 files changed, 2173 insertions, 73 deletions
diff --git a/sound/soc/msm/msmfalcon-common.c b/sound/soc/msm/msmfalcon-common.c
index 6c96a0778b52..c82319539f39 100644
--- a/sound/soc/msm/msmfalcon-common.c
+++ b/sound/soc/msm/msmfalcon-common.c
@@ -28,6 +28,112 @@
#define DEV_NAME_STR_LEN 32
#define DEFAULT_MCLK_RATE 9600000
+struct dev_config {
+ u32 sample_rate;
+ u32 bit_format;
+ u32 channels;
+};
+
+/* 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 */
+ }
+};
+
+static struct dev_config usb_rx_cfg = {
+ .sample_rate = SAMPLING_RATE_48KHZ,
+ .bit_format = SNDRV_PCM_FORMAT_S16_LE,
+ .channels = 2,
+};
+
+static struct dev_config usb_tx_cfg = {
+ .sample_rate = SAMPLING_RATE_48KHZ,
+ .bit_format = SNDRV_PCM_FORMAT_S16_LE,
+ .channels = 1,
+};
+
enum {
PRIM_MI2S = 0,
SEC_MI2S,
@@ -68,12 +174,6 @@ struct auxpcm_conf {
u32 ref_cnt;
};
-struct dev_config {
- u32 sample_rate;
- u32 bit_format;
- u32 channels;
-};
-
struct msm_wsa881x_dev_info {
struct device_node *of_node;
u32 index;
@@ -111,12 +211,6 @@ static struct dev_config proxy_rx_cfg = {
.channels = 2,
};
-static struct dev_config btsco_cfg = {
- .sample_rate = SAMPLING_RATE_8KHZ,
- .bit_format = SNDRV_PCM_FORMAT_S16_LE,
- .channels = 1,
-};
-
/* Default configuration of MI2S channels */
static struct dev_config mi2s_rx_cfg[] = {
[PRIM_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
@@ -155,8 +249,22 @@ static char const *mi2s_rate_text[] = {"KHZ_8", "KHZ_16",
static const char *const mi2s_ch_text[] = {"One", "Two", "Three", "Four",
"Five", "Six", "Seven",
"Eight"};
+static char const *bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE",
+ "S32_LE"};
+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 usb_ch_text[] = {"One", "Two", "Three", "Four",
+ "Five", "Six", "Seven",
+ "Eight"};
+static char const *usb_sample_rate_text[] = {"KHZ_8", "KHZ_11P025",
+ "KHZ_16", "KHZ_22P05",
+ "KHZ_32", "KHZ_44P1", "KHZ_48",
+ "KHZ_96", "KHZ_192", "KHZ_384"};
-static SOC_ENUM_SINGLE_EXT_DECL(btsco_sample_rate, auxpcm_rate_text);
static SOC_ENUM_SINGLE_EXT_DECL(proxy_rx_chs, ch_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);
@@ -182,6 +290,18 @@ static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_rx_chs, mi2s_ch_text);
static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_tx_chs, mi2s_ch_text);
static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_rx_chs, mi2s_ch_text);
static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_tx_chs, mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_chs, usb_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_chs, usb_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_format, bit_format_text);
+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(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 struct afe_clk_set mi2s_clk[MI2S_MAX] = {
{
@@ -242,6 +362,439 @@ static int proxy_rx_ch_put(struct snd_kcontrol *kcontrol,
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 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 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_sample_rate(int value)
{
int sample_rate;
@@ -299,32 +852,6 @@ static int aux_pcm_get_port_idx(struct snd_kcontrol *kcontrol)
return idx;
}
-static int btsco_sample_rate_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- btsco_cfg.sample_rate =
- aux_pcm_get_sample_rate(ucontrol->value.enumerated.item[0]);
-
- pr_debug("%s: btsco_sample_rate = %d, item = %d\n", __func__,
- btsco_cfg.sample_rate,
- ucontrol->value.enumerated.item[0]);
-
- return 0;
-}
-
-static int btsco_sample_rate_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.enumerated.item[0] =
- aux_pcm_get_sample_rate_val(btsco_cfg.sample_rate);
-
- pr_debug("%s: btsco_sample_rate = %d, item = %d\n", __func__,
- btsco_cfg.sample_rate,
- ucontrol->value.enumerated.item[0]);
-
- return 0;
-}
-
static int aux_pcm_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -632,12 +1159,331 @@ static int msm_mi2s_tx_ch_put(struct snd_kcontrol *kcontrol,
return 1;
}
+static int usb_audio_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: usb_audio_rx_ch = %d\n", __func__,
+ usb_rx_cfg.channels);
+ ucontrol->value.integer.value[0] = usb_rx_cfg.channels - 1;
+ return 0;
+}
+
+static int usb_audio_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ usb_rx_cfg.channels = ucontrol->value.integer.value[0] + 1;
+
+ pr_debug("%s: usb_audio_rx_ch = %d\n", __func__, usb_rx_cfg.channels);
+ return 1;
+}
+
+static int usb_audio_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int sample_rate_val;
+
+ switch (usb_rx_cfg.sample_rate) {
+ case SAMPLING_RATE_384KHZ:
+ sample_rate_val = 9;
+ break;
+ case SAMPLING_RATE_192KHZ:
+ sample_rate_val = 8;
+ break;
+ case SAMPLING_RATE_96KHZ:
+ sample_rate_val = 7;
+ break;
+ case SAMPLING_RATE_48KHZ:
+ sample_rate_val = 6;
+ break;
+ case SAMPLING_RATE_44P1KHZ:
+ sample_rate_val = 5;
+ break;
+ case SAMPLING_RATE_32KHZ:
+ sample_rate_val = 4;
+ break;
+ case SAMPLING_RATE_22P05KHZ:
+ sample_rate_val = 3;
+ break;
+ case SAMPLING_RATE_16KHZ:
+ sample_rate_val = 2;
+ break;
+ case SAMPLING_RATE_11P025KHZ:
+ sample_rate_val = 1;
+ break;
+ case SAMPLING_RATE_8KHZ:
+ default:
+ sample_rate_val = 0;
+ break;
+ }
+
+ ucontrol->value.integer.value[0] = sample_rate_val;
+ pr_debug("%s: usb_audio_rx_sample_rate = %d\n", __func__,
+ usb_rx_cfg.sample_rate);
+ return 0;
+}
+
+static int usb_audio_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 9:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_384KHZ;
+ break;
+ case 8:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_192KHZ;
+ break;
+ case 7:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_96KHZ;
+ break;
+ case 6:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ case 5:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_44P1KHZ;
+ break;
+ case 4:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_32KHZ;
+ break;
+ case 3:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_22P05KHZ;
+ break;
+ case 2:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_16KHZ;
+ break;
+ case 1:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_11P025KHZ;
+ break;
+ case 0:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_8KHZ;
+ break;
+ default:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ }
+
+ pr_debug("%s: control value = %ld, usb_audio_rx_sample_rate = %d\n",
+ __func__, ucontrol->value.integer.value[0],
+ usb_rx_cfg.sample_rate);
+ return 0;
+}
+
+static int usb_audio_rx_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (usb_rx_cfg.bit_format) {
+ case SNDRV_PCM_FORMAT_S32_LE:
+ ucontrol->value.integer.value[0] = 3;
+ break;
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ ucontrol->value.integer.value[0] = 2;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ ucontrol->value.integer.value[0] = 1;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ ucontrol->value.integer.value[0] = 0;
+ break;
+ }
+
+ pr_debug("%s: usb_audio_rx_format = %d, ucontrol value = %ld\n",
+ __func__, usb_rx_cfg.bit_format,
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int usb_audio_rx_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int rc = 0;
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 3:
+ usb_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S32_LE;
+ break;
+ case 2:
+ usb_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_3LE;
+ break;
+ case 1:
+ usb_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 0:
+ default:
+ usb_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ }
+ pr_debug("%s: usb_audio_rx_format = %d, ucontrol value = %ld\n",
+ __func__, usb_rx_cfg.bit_format,
+ ucontrol->value.integer.value[0]);
+
+ return rc;
+}
+
+static int usb_audio_tx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: usb_audio_tx_ch = %d\n", __func__,
+ usb_tx_cfg.channels);
+ ucontrol->value.integer.value[0] = usb_tx_cfg.channels - 1;
+ return 0;
+}
+
+static int usb_audio_tx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ usb_tx_cfg.channels = ucontrol->value.integer.value[0] + 1;
+
+ pr_debug("%s: usb_audio_tx_ch = %d\n", __func__, usb_tx_cfg.channels);
+ return 1;
+}
+
+static int usb_audio_tx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int sample_rate_val;
+
+ switch (usb_tx_cfg.sample_rate) {
+ case SAMPLING_RATE_384KHZ:
+ sample_rate_val = 9;
+ break;
+ case SAMPLING_RATE_192KHZ:
+ sample_rate_val = 8;
+ break;
+ case SAMPLING_RATE_96KHZ:
+ sample_rate_val = 7;
+ break;
+ case SAMPLING_RATE_48KHZ:
+ sample_rate_val = 6;
+ break;
+ case SAMPLING_RATE_44P1KHZ:
+ sample_rate_val = 5;
+ break;
+ case SAMPLING_RATE_32KHZ:
+ sample_rate_val = 4;
+ break;
+ case SAMPLING_RATE_22P05KHZ:
+ sample_rate_val = 3;
+ break;
+ case SAMPLING_RATE_16KHZ:
+ sample_rate_val = 2;
+ break;
+ case SAMPLING_RATE_11P025KHZ:
+ sample_rate_val = 1;
+ break;
+ case SAMPLING_RATE_8KHZ:
+ sample_rate_val = 0;
+ break;
+ default:
+ sample_rate_val = 6;
+ break;
+ }
+
+ ucontrol->value.integer.value[0] = sample_rate_val;
+ pr_debug("%s: usb_audio_tx_sample_rate = %d\n", __func__,
+ usb_tx_cfg.sample_rate);
+ return 0;
+}
+
+static int usb_audio_tx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 9:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_384KHZ;
+ break;
+ case 8:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_192KHZ;
+ break;
+ case 7:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_96KHZ;
+ break;
+ case 6:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ case 5:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_44P1KHZ;
+ break;
+ case 4:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_32KHZ;
+ break;
+ case 3:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_22P05KHZ;
+ break;
+ case 2:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_16KHZ;
+ break;
+ case 1:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_11P025KHZ;
+ break;
+ case 0:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_8KHZ;
+ break;
+ default:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ }
+
+ pr_debug("%s: control value = %ld, usb_audio_tx_sample_rate = %d\n",
+ __func__, ucontrol->value.integer.value[0],
+ usb_tx_cfg.sample_rate);
+ return 0;
+}
+
+static int usb_audio_tx_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (usb_tx_cfg.bit_format) {
+ case SNDRV_PCM_FORMAT_S32_LE:
+ ucontrol->value.integer.value[0] = 3;
+ break;
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ ucontrol->value.integer.value[0] = 2;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ ucontrol->value.integer.value[0] = 1;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ ucontrol->value.integer.value[0] = 0;
+ break;
+ }
+
+ pr_debug("%s: usb_audio_tx_format = %d, ucontrol value = %ld\n",
+ __func__, usb_tx_cfg.bit_format,
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int usb_audio_tx_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int rc = 0;
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 3:
+ usb_tx_cfg.bit_format = SNDRV_PCM_FORMAT_S32_LE;
+ break;
+ case 2:
+ usb_tx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_3LE;
+ break;
+ case 1:
+ usb_tx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 0:
+ default:
+ usb_tx_cfg.bit_format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ }
+ pr_debug("%s: usb_audio_tx_format = %d, ucontrol value = %ld\n",
+ __func__, usb_tx_cfg.bit_format,
+ ucontrol->value.integer.value[0]);
+
+ return rc;
+}
+
const struct snd_kcontrol_new msm_common_snd_controls[] = {
SOC_ENUM_EXT("PROXY_RX Channels", proxy_rx_chs,
proxy_rx_ch_get, proxy_rx_ch_put),
- SOC_ENUM_EXT("BTSCO SampleRate", btsco_sample_rate,
- btsco_sample_rate_get,
- btsco_sample_rate_put),
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_put),
@@ -702,8 +1548,119 @@ const struct snd_kcontrol_new msm_common_snd_controls[] = {
msm_mi2s_rx_ch_get, msm_mi2s_rx_ch_put),
SOC_ENUM_EXT("QUAT_MI2S_TX Channels", quat_mi2s_tx_chs,
msm_mi2s_tx_ch_get, msm_mi2s_tx_ch_put),
+ SOC_ENUM_EXT("USB_AUDIO_RX Channels", usb_rx_chs,
+ usb_audio_rx_ch_get, usb_audio_rx_ch_put),
+ SOC_ENUM_EXT("USB_AUDIO_TX Channels", usb_tx_chs,
+ usb_audio_tx_ch_get, usb_audio_tx_ch_put),
+ SOC_ENUM_EXT("USB_AUDIO_RX Format", usb_rx_format,
+ usb_audio_rx_format_get, usb_audio_rx_format_put),
+ SOC_ENUM_EXT("USB_AUDIO_TX Format", usb_tx_format,
+ usb_audio_tx_format_get, usb_audio_tx_format_put),
+ SOC_ENUM_EXT("USB_AUDIO_RX SampleRate", usb_rx_sample_rate,
+ usb_audio_rx_sample_rate_get,
+ usb_audio_rx_sample_rate_put),
+ SOC_ENUM_EXT("USB_AUDIO_TX SampleRate", usb_tx_sample_rate,
+ usb_audio_tx_sample_rate_get,
+ usb_audio_tx_sample_rate_put),
+ SOC_ENUM_EXT("PRI_TDM_RX_0 SampleRate", tdm_rx_sample_rate,
+ tdm_rx_sample_rate_get,
+ tdm_rx_sample_rate_put),
+ SOC_ENUM_EXT("PRI_TDM_TX_0 SampleRate", tdm_tx_sample_rate,
+ tdm_tx_sample_rate_get,
+ tdm_tx_sample_rate_put),
+ SOC_ENUM_EXT("PRI_TDM_RX_0 Format", tdm_rx_format,
+ tdm_rx_format_get,
+ tdm_rx_format_put),
+ SOC_ENUM_EXT("PRI_TDM_TX_0 Format", tdm_tx_format,
+ tdm_tx_format_get,
+ tdm_tx_format_put),
+ SOC_ENUM_EXT("PRI_TDM_RX_0 Channels", tdm_rx_chs,
+ tdm_rx_ch_get,
+ tdm_rx_ch_put),
+ SOC_ENUM_EXT("PRI_TDM_TX_0 Channels", tdm_tx_chs,
+ tdm_tx_ch_get,
+ tdm_tx_ch_put),
+ SOC_ENUM_EXT("SEC_TDM_RX_0 SampleRate", tdm_rx_sample_rate,
+ tdm_rx_sample_rate_get,
+ tdm_rx_sample_rate_put),
+ SOC_ENUM_EXT("SEC_TDM_TX_0 SampleRate", tdm_tx_sample_rate,
+ tdm_tx_sample_rate_get,
+ tdm_tx_sample_rate_put),
+ SOC_ENUM_EXT("SEC_TDM_RX_0 Format", tdm_rx_format,
+ tdm_rx_format_get,
+ tdm_rx_format_put),
+ SOC_ENUM_EXT("SEC_TDM_TX_0 Format", tdm_tx_format,
+ tdm_tx_format_get,
+ tdm_tx_format_put),
+ SOC_ENUM_EXT("SEC_TDM_RX_0 Channels", tdm_rx_chs,
+ tdm_rx_ch_get,
+ tdm_rx_ch_put),
+ SOC_ENUM_EXT("SEC_TDM_TX_0 Channels", tdm_tx_chs,
+ tdm_tx_ch_get,
+ tdm_tx_ch_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("QUAT_TDM_RX_0 SampleRate", tdm_rx_sample_rate,
+ tdm_rx_sample_rate_get,
+ tdm_rx_sample_rate_put),
+ SOC_ENUM_EXT("QUAT_TDM_TX_0 SampleRate", tdm_tx_sample_rate,
+ tdm_tx_sample_rate_get,
+ tdm_tx_sample_rate_put),
+ SOC_ENUM_EXT("QUAT_TDM_RX_0 Format", tdm_rx_format,
+ tdm_rx_format_get,
+ tdm_rx_format_put),
+ SOC_ENUM_EXT("QUAT_TDM_TX_0 Format", tdm_tx_format,
+ tdm_tx_format_get,
+ tdm_tx_format_put),
+ SOC_ENUM_EXT("QUAT_TDM_RX_0 Channels", tdm_rx_chs,
+ tdm_rx_ch_get,
+ tdm_rx_ch_put),
+ SOC_ENUM_EXT("QUAT_TDM_TX_0 Channels", tdm_tx_chs,
+ tdm_tx_ch_get,
+ tdm_tx_ch_put),
};
+static inline int param_is_mask(int p)
+{
+ return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) &&
+ (p <= SNDRV_PCM_HW_PARAM_LAST_MASK);
+}
+
+static inline struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p,
+ int n)
+{
+ return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]);
+}
+
+static void param_set_mask(struct snd_pcm_hw_params *p, int n, unsigned bit)
+{
+ if (bit >= SNDRV_MASK_MAX)
+ return;
+ if (param_is_mask(n)) {
+ struct snd_mask *m = param_to_mask(p, n);
+
+ m->bits[0] = 0;
+ m->bits[1] = 0;
+ m->bits[bit >> 5] |= (1 << (bit & 31));
+ }
+}
+
/**
* msm_common_be_hw_params_fixup - updates settings of ALSA BE hw params.
*
@@ -726,10 +1683,18 @@ int msm_common_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
__func__, params_format(params), params_rate(params));
switch (dai_link->be_id) {
- case MSM_BACKEND_DAI_INT_BT_SCO_RX:
- case MSM_BACKEND_DAI_INT_BT_SCO_TX:
- channels->min = channels->max = btsco_cfg.channels;
- rate->min = rate->max = 1;
+ case MSM_BACKEND_DAI_USB_RX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ usb_rx_cfg.bit_format);
+ rate->min = rate->max = usb_rx_cfg.sample_rate;
+ channels->min = channels->max = usb_rx_cfg.channels;
+ break;
+
+ case MSM_BACKEND_DAI_USB_TX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ usb_tx_cfg.bit_format);
+ rate->min = rate->max = usb_tx_cfg.sample_rate;
+ channels->min = channels->max = usb_tx_cfg.channels;
break;
case MSM_BACKEND_DAI_AFE_PCM_RX:
@@ -737,6 +1702,70 @@ int msm_common_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
rate->min = rate->max = SAMPLING_RATE_48KHZ;
break;
+ case MSM_BACKEND_DAI_PRI_TDM_RX_0:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_PRI][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_PRI][TDM_0].bit_format);
+ rate->min = rate->max = tdm_rx_cfg[TDM_PRI][TDM_0].sample_rate;
+ break;
+
+ case MSM_BACKEND_DAI_PRI_TDM_TX_0:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_PRI][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_PRI][TDM_0].bit_format);
+ rate->min = rate->max = tdm_tx_cfg[TDM_PRI][TDM_0].sample_rate;
+ break;
+
+ case MSM_BACKEND_DAI_SEC_TDM_RX_0:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_SEC][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_SEC][TDM_0].bit_format);
+ rate->min = rate->max = tdm_rx_cfg[TDM_SEC][TDM_0].sample_rate;
+ break;
+
+ case MSM_BACKEND_DAI_SEC_TDM_TX_0:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_SEC][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_SEC][TDM_0].bit_format);
+ rate->min = rate->max = tdm_tx_cfg[TDM_SEC][TDM_0].sample_rate;
+ 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_QUAT_TDM_RX_0:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_QUAT][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_QUAT][TDM_0].bit_format);
+ rate->min = rate->max = tdm_rx_cfg[TDM_QUAT][TDM_0].sample_rate;
+ break;
+
+ case MSM_BACKEND_DAI_QUAT_TDM_TX_0:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_QUAT][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_QUAT][TDM_0].bit_format);
+ rate->min = rate->max = tdm_tx_cfg[TDM_QUAT][TDM_0].sample_rate;
+ break;
+
case MSM_BACKEND_DAI_AUXPCM_RX:
rate->min = rate->max =
aux_pcm_rx_cfg[PRIM_AUX_PCM].sample_rate;
@@ -1640,11 +2669,15 @@ static int msm_asoc_machine_probe(struct platform_device *pdev)
if (!strcmp(match->data, "tasha_codec") ||
!strcmp(match->data, "tavil_codec")) {
+ if (!strcmp(match->data, "tasha_codec"))
+ pdata->snd_card_val = EXT_SND_CARD_TASHA;
+ else
+ pdata->snd_card_val = EXT_SND_CARD_TAVIL;
ret = msm_ext_cdc_init(pdev, pdata, &card, &mbhc_cfg);
if (ret)
goto err;
} else if (!strcmp(match->data, "internal_codec")) {
- pdata->int_codec = 1;
+ pdata->snd_card_val = INT_SND_CARD;
ret = msm_int_cdc_init(pdev, pdata, &card, &mbhc_cfg);
if (ret)
goto err;
@@ -1656,12 +2689,15 @@ static int msm_asoc_machine_probe(struct platform_device *pdev)
if (!card)
goto err;
- /*reading the gpio configurations from dtsi file*/
- ret = msm_gpioset_initialize(CLIENT_WCD, &pdev->dev);
- if (ret < 0) {
- dev_err(&pdev->dev,
- "%s: error reading dtsi files%d\n", __func__, ret);
- goto err;
+ if (pdata->snd_card_val == INT_SND_CARD) {
+ /*reading the gpio configurations from dtsi file*/
+ ret = msm_gpioset_initialize(CLIENT_WCD, &pdev->dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "%s: error reading dtsi files%d\n",
+ __func__, ret);
+ goto err;
+ }
}
/*
@@ -1710,6 +2746,8 @@ static int msm_asoc_machine_probe(struct platform_device *pdev)
ret);
goto err;
}
+ if (pdata->snd_card_val != INT_SND_CARD)
+ msm_ext_register_audio_notifier();
return 0;
err:
if (pdata->us_euro_gpio > 0) {
@@ -1738,7 +2776,7 @@ static int msm_asoc_machine_remove(struct platform_device *pdev)
struct snd_soc_card *card = platform_get_drvdata(pdev);
struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
- if (pdata->int_codec)
+ if (pdata->snd_card_val == INT_SND_CARD)
mutex_destroy(&pdata->cdc_int_mclk0_mutex);
msm_free_auxdev_mem(pdev);
diff --git a/sound/soc/msm/msmfalcon-common.h b/sound/soc/msm/msmfalcon-common.h
index ff8232d6fcbb..5f6b8592acec 100644
--- a/sound/soc/msm/msmfalcon-common.h
+++ b/sound/soc/msm/msmfalcon-common.h
@@ -31,12 +31,46 @@
#define SAMPLING_RATE_352P8KHZ 352800
#define SAMPLING_RATE_384KHZ 384000
+#define TDM_CHANNEL_MAX 8
+#define TDM_SLOT_OFFSET_MAX 8
+
+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;
+};
+
extern const struct snd_kcontrol_new msm_common_snd_controls[];
struct msmfalcon_codec {
void* (*get_afe_config_fn)(struct snd_soc_codec *codec,
enum afe_config_type config_type);
};
+enum {
+ INT_SND_CARD,
+ EXT_SND_CARD_TASHA,
+ EXT_SND_CARD_TAVIL,
+};
+
struct msm_asoc_mach_data {
int us_euro_gpio; /* used by gpio driver API */
int hph_en1_gpio;
@@ -50,6 +84,7 @@ struct msm_asoc_mach_data {
int spk_ext_pa_gpio;
int mclk_freq;
int lb_mode;
+ int snd_card_val;
u8 micbias1_cap_mode;
u8 micbias2_cap_mode;
atomic_t int_mclk0_rsc_ref;
@@ -57,7 +92,6 @@ struct msm_asoc_mach_data {
struct mutex cdc_int_mclk0_mutex;
struct delayed_work disable_int_mclk0_work;
struct afe_clk_set digital_cdc_core_clk;
- bool int_codec;
};
int msm_common_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
diff --git a/sound/soc/msm/msmfalcon-ext-dai-links.c b/sound/soc/msm/msmfalcon-ext-dai-links.c
index 4dca7908c108..6f066c5945a9 100644
--- a/sound/soc/msm/msmfalcon-ext-dai-links.c
+++ b/sound/soc/msm/msmfalcon-ext-dai-links.c
@@ -16,6 +16,7 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/pcm.h>
+#include <sound/pcm_params.h>
#include "qdsp6v2/msm-pcm-routing-v2.h"
#include "../codecs/wcd9335.h"
#include "msmfalcon-common.h"
@@ -25,7 +26,11 @@
#define __CHIPSET__ "MSMFALCON "
#define MSM_DAILINK_NAME(name) (__CHIPSET__#name)
-static struct snd_soc_card snd_soc_card_msm_card;
+#define WCN_CDC_SLIM_RX_CH_MAX 2
+#define WCN_CDC_SLIM_TX_CH_MAX 3
+
+static struct snd_soc_card snd_soc_card_msm_card_tavil;
+static struct snd_soc_card snd_soc_card_msm_card_tasha;
static struct snd_soc_ops msm_ext_slimbus_be_ops = {
.hw_params = msm_snd_hw_params,
@@ -49,6 +54,222 @@ static struct snd_soc_ops msm_aux_pcm_be_ops = {
.shutdown = msm_aux_pcm_snd_shutdown,
};
+static int msm_wcn_init(struct snd_soc_pcm_runtime *rtd)
+{
+ unsigned int rx_ch[WCN_CDC_SLIM_RX_CH_MAX] = {157, 158};
+ unsigned int tx_ch[WCN_CDC_SLIM_TX_CH_MAX] = {159, 160, 161};
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+ return snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
+ tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
+}
+
+static int msm_wcn_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 *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
+ u32 rx_ch[WCN_CDC_SLIM_RX_CH_MAX], tx_ch[WCN_CDC_SLIM_TX_CH_MAX];
+ u32 rx_ch_cnt = 0, tx_ch_cnt = 0;
+ int ret;
+
+ dev_dbg(rtd->dev, "%s: %s_tx_dai_id_%d\n", __func__,
+ codec_dai->name, codec_dai->id);
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
+ if (ret) {
+ dev_err(rtd->dev,
+ "%s: failed to get BTFM codec chan map\n, err:%d\n",
+ __func__, ret);
+ goto exit;
+ }
+
+ dev_dbg(rtd->dev, "%s: tx_ch_cnt(%d) be_id %d\n",
+ __func__, tx_ch_cnt, dai_link->be_id);
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai,
+ tx_ch_cnt, tx_ch, rx_ch_cnt, rx_ch);
+ if (ret)
+ dev_err(rtd->dev, "%s: failed to set cpu chan map, err:%d\n",
+ __func__, ret);
+
+exit:
+ return ret;
+}
+
+static struct snd_soc_ops msm_wcn_ops = {
+ .hw_params = msm_wcn_hw_params,
+};
+
+/*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 */
+};
+
+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_tdm_be_ops = {
+ .hw_params = msm_tdm_snd_hw_params
+};
+
static struct snd_soc_dai_link msm_ext_tasha_fe_dai[] = {
/* tasha_vifeedback for speaker protection */
{
@@ -1167,6 +1388,145 @@ static struct snd_soc_dai_link msm_ext_common_be_dai[] = {
.be_hw_params_fixup = msm_ext_be_hw_params_fixup,
.ignore_suspend = 1,
},
+ {
+ .name = LPASS_BE_USB_AUDIO_RX,
+ .stream_name = "USB Audio Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.28672",
+ .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_USB_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_USB_AUDIO_TX,
+ .stream_name = "USB Audio Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.28673",
+ .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_USB_TX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_PRI_TDM_RX_0,
+ .stream_name = "Primary TDM0 Playback",
+ .cpu_dai_name = "msm-dai-q6-tdm.36864",
+ .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_PRI_TDM_RX_0,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_PRI_TDM_TX_0,
+ .stream_name = "Primary TDM0 Capture",
+ .cpu_dai_name = "msm-dai-q6-tdm.36865",
+ .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_PRI_TDM_TX_0,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SEC_TDM_RX_0,
+ .stream_name = "Secondary TDM0 Playback",
+ .cpu_dai_name = "msm-dai-q6-tdm.36880",
+ .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_SEC_TDM_RX_0,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SEC_TDM_TX_0,
+ .stream_name = "Secondary TDM0 Capture",
+ .cpu_dai_name = "msm-dai-q6-tdm.36881",
+ .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_SEC_TDM_TX_0,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .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_common_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_common_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_QUAT_TDM_RX_0,
+ .stream_name = "Quaternary TDM0 Playback",
+ .cpu_dai_name = "msm-dai-q6-tdm.36912",
+ .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_QUAT_TDM_RX_0,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_QUAT_TDM_TX_0,
+ .stream_name = "Quaternary TDM0 Capture",
+ .cpu_dai_name = "msm-dai-q6-tdm.36913",
+ .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_QUAT_TDM_TX_0,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
};
static struct snd_soc_dai_link msm_mi2s_be_dai_links[] = {
@@ -1415,13 +1775,66 @@ static struct snd_soc_dai_link msm_auxpcm_be_dai_links[] = {
},
};
+static struct snd_soc_dai_link msm_wcn_be_dai_links[] = {
+ {
+ .name = LPASS_BE_SLIMBUS_7_RX,
+ .stream_name = "Slimbus7 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16398",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "btfmslim_slave",
+ /* BT codec driver determines capabilities based on
+ * dai name, bt codecdai name should always contains
+ * supported usecase information
+ */
+ .codec_dai_name = "btfm_bt_sco_a2dp_slim_rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_7_RX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_wcn_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_7_TX,
+ .stream_name = "Slimbus7 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16399",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "btfmslim_slave",
+ .codec_dai_name = "btfm_bt_sco_slim_tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_7_TX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_wcn_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_8_TX,
+ .stream_name = "Slimbus8 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16401",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "btfmslim_slave",
+ .codec_dai_name = "btfm_fm_slim_tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_8_TX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .init = &msm_wcn_init,
+ .ops = &msm_wcn_ops,
+ .ignore_suspend = 1,
+ },
+};
+
static struct snd_soc_dai_link msm_ext_tasha_dai_links[
ARRAY_SIZE(msm_ext_common_fe_dai) +
ARRAY_SIZE(msm_ext_tasha_fe_dai) +
ARRAY_SIZE(msm_ext_common_be_dai) +
ARRAY_SIZE(msm_ext_tasha_be_dai) +
ARRAY_SIZE(msm_mi2s_be_dai_links) +
-ARRAY_SIZE(msm_auxpcm_be_dai_links)];
+ARRAY_SIZE(msm_auxpcm_be_dai_links) +
+ARRAY_SIZE(msm_wcn_be_dai_links)];
static struct snd_soc_dai_link msm_ext_tavil_dai_links[
ARRAY_SIZE(msm_ext_common_fe_dai) +
@@ -1429,7 +1842,8 @@ ARRAY_SIZE(msm_ext_tavil_fe_dai) +
ARRAY_SIZE(msm_ext_common_be_dai) +
ARRAY_SIZE(msm_ext_tavil_be_dai) +
ARRAY_SIZE(msm_mi2s_be_dai_links) +
-ARRAY_SIZE(msm_auxpcm_be_dai_links)];
+ARRAY_SIZE(msm_auxpcm_be_dai_links) +
+ARRAY_SIZE(msm_wcn_be_dai_links)];
/**
* populate_snd_card_dailinks - prepares dailink array and initializes card.
@@ -1438,13 +1852,24 @@ ARRAY_SIZE(msm_auxpcm_be_dai_links)];
*
* Returns card on success or NULL on failure.
*/
-struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
+struct snd_soc_card *populate_snd_card_dailinks(struct device *dev,
+ int snd_card_val)
{
- struct snd_soc_card *card = &snd_soc_card_msm_card;
+ struct snd_soc_card *card;
struct snd_soc_dai_link *msm_ext_dai_links = NULL;
int ret, len1, len2, len3, len4;
enum codec_variant codec_ver = 0;
+ if (snd_card_val == EXT_SND_CARD_TASHA) {
+ card = &snd_soc_card_msm_card_tasha;
+ } else if (snd_card_val == EXT_SND_CARD_TAVIL) {
+ card = &snd_soc_card_msm_card_tavil;
+ } else {
+ dev_err(dev, "%s: failing as no matching card name\n",
+ __func__);
+ return NULL;
+ }
+
card->dev = dev;
ret = snd_soc_of_parse_card_name(card, "qcom,model");
if (ret) {
@@ -1484,6 +1909,14 @@ struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
sizeof(msm_auxpcm_be_dai_links));
len4 += ARRAY_SIZE(msm_auxpcm_be_dai_links);
}
+ if (of_property_read_bool(dev->of_node, "qcom,wcn-btfm")) {
+ dev_dbg(dev, "%s(): WCN BTFM support present\n",
+ __func__);
+ memcpy(msm_ext_tasha_dai_links + len4,
+ msm_wcn_be_dai_links,
+ sizeof(msm_wcn_be_dai_links));
+ len4 += ARRAY_SIZE(msm_wcn_be_dai_links);
+ }
msm_ext_dai_links = msm_ext_tasha_dai_links;
} else if (strnstr(card->name, "tavil", strlen(card->name))) {
len1 = ARRAY_SIZE(msm_ext_common_fe_dai);
@@ -1512,6 +1945,14 @@ struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
sizeof(msm_auxpcm_be_dai_links));
len4 += ARRAY_SIZE(msm_auxpcm_be_dai_links);
}
+ if (of_property_read_bool(dev->of_node, "qcom,wcn-btfm")) {
+ dev_dbg(dev, "%s(): WCN BTFM support present\n",
+ __func__);
+ memcpy(msm_ext_tavil_dai_links + len4,
+ msm_wcn_be_dai_links,
+ sizeof(msm_wcn_be_dai_links));
+ len4 += ARRAY_SIZE(msm_wcn_be_dai_links);
+ }
msm_ext_dai_links = msm_ext_tavil_dai_links;
} else {
dev_err(dev, "%s: failing as no matching card name\n",
@@ -1520,7 +1961,6 @@ struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
}
card->dai_link = msm_ext_dai_links;
card->num_links = len4;
- card->dev = dev;
return card;
}
diff --git a/sound/soc/msm/msmfalcon-external.c b/sound/soc/msm/msmfalcon-external.c
index 046c63bb73cf..3934c50c48a9 100644
--- a/sound/soc/msm/msmfalcon-external.c
+++ b/sound/soc/msm/msmfalcon-external.c
@@ -122,6 +122,7 @@ static char const *slim_sample_rate_text[] = {"KHZ_8", "KHZ_16",
"KHZ_88P2", "KHZ_96", "KHZ_176P4",
"KHZ_192", "KHZ_352P8", "KHZ_384"};
static const char *const spk_function_text[] = {"Off", "On"};
+static char const *bt_sample_rate_text[] = {"KHZ_8", "KHZ_16", "KHZ_48"};
static SOC_ENUM_SINGLE_EXT_DECL(spk_func_en, spk_function_text);
static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_chs, slim_rx_ch_text);
@@ -140,6 +141,7 @@ static SOC_ENUM_SINGLE_EXT_DECL(slim_2_rx_sample_rate, slim_sample_rate_text);
static SOC_ENUM_SINGLE_EXT_DECL(slim_0_tx_sample_rate, slim_sample_rate_text);
static SOC_ENUM_SINGLE_EXT_DECL(slim_5_rx_sample_rate, slim_sample_rate_text);
static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_sample_rate, slim_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(bt_sample_rate, bt_sample_rate_text);
static int slim_get_sample_rate_val(int sample_rate)
{
@@ -302,6 +304,59 @@ static int slim_get_port_idx(struct snd_kcontrol *kcontrol)
return port_id;
}
+static int msm_bt_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ /*
+ * Slimbus_7_Rx/Tx sample rate values should always be in sync (same)
+ * when used for BT_SCO use case. Return either Rx or Tx sample rate
+ * value.
+ */
+ switch (slim_rx_cfg[SLIM_RX_7].sample_rate) {
+ case SAMPLING_RATE_48KHZ:
+ ucontrol->value.integer.value[0] = 2;
+ break;
+ case SAMPLING_RATE_16KHZ:
+ ucontrol->value.integer.value[0] = 1;
+ break;
+ case SAMPLING_RATE_8KHZ:
+ default:
+ ucontrol->value.integer.value[0] = 0;
+ break;
+ }
+ pr_debug("%s: sample rate = %d", __func__,
+ slim_rx_cfg[SLIM_RX_7].sample_rate);
+
+ return 0;
+}
+
+static int msm_bt_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 1:
+ slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_16KHZ;
+ slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_16KHZ;
+ break;
+ case 2:
+ slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_48KHZ;
+ slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ case 0:
+ default:
+ slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_8KHZ;
+ slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_8KHZ;
+ break;
+ }
+ pr_debug("%s: sample rates: slim7_rx = %d, slim7_tx = %d, value = %d\n",
+ __func__,
+ slim_rx_cfg[SLIM_RX_7].sample_rate,
+ slim_tx_cfg[SLIM_TX_7].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
static int slim_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -670,6 +725,9 @@ static const struct snd_kcontrol_new msm_snd_controls[] = {
slim_rx_sample_rate_get, slim_rx_sample_rate_put),
SOC_ENUM_EXT("SLIM_6_RX SampleRate", slim_6_rx_sample_rate,
slim_rx_sample_rate_get, slim_rx_sample_rate_put),
+ SOC_ENUM_EXT("BT SampleRate", bt_sample_rate,
+ msm_bt_sample_rate_get,
+ msm_bt_sample_rate_put),
};
static int msm_slim_get_ch_from_beid(int32_t be_id)
@@ -1627,6 +1685,21 @@ err_mbhc_cal:
EXPORT_SYMBOL(msm_audrx_init);
/**
+ * msm_ext_register_audio_notifier - register SSR notifier.
+ */
+void msm_ext_register_audio_notifier(void)
+{
+ int ret;
+
+ ret = audio_notifier_register("msmfalcon", AUDIO_NOTIFIER_ADSP_DOMAIN,
+ &service_nb);
+ if (ret < 0)
+ pr_err("%s: Audio notifier register failed ret = %d\n",
+ __func__, ret);
+}
+EXPORT_SYMBOL(msm_ext_register_audio_notifier);
+
+/**
* msm_ext_cdc_init - external codec machine specific init.
*
* @pdev: platform device handle
@@ -1650,24 +1723,16 @@ int msm_ext_cdc_init(struct platform_device *pdev,
wcd_mbhc_cfg_ptr->anc_micbias = MIC_BIAS_2;
wcd_mbhc_cfg_ptr->enable_anc_mic_detect = false;
- *card = populate_snd_card_dailinks(&pdev->dev);
+ *card = populate_snd_card_dailinks(&pdev->dev, pdata->snd_card_val);
if (!(*card)) {
dev_err(&pdev->dev, "%s: Card uninitialized\n", __func__);
ret = -EPROBE_DEFER;
goto err;
}
- (*card)->dev = &pdev->dev;
spdev = pdev;
platform_set_drvdata(pdev, *card);
snd_soc_card_set_drvdata(*card, pdata);
is_initial_boot = true;
- ret = audio_notifier_register("msmfalcon", AUDIO_NOTIFIER_ADSP_DOMAIN,
- &service_nb);
- if (ret < 0) {
- pr_err("%s: Audio notifier register failed ret = %d\n",
- __func__, ret);
- goto err;
- }
pdata->hph_en1_gpio = of_get_named_gpio(pdev->dev.of_node,
"qcom,hph-en1-gpio", 0);
if (!gpio_is_valid(pdata->hph_en1_gpio))
diff --git a/sound/soc/msm/msmfalcon-external.h b/sound/soc/msm/msmfalcon-external.h
index 24aa7ea53a09..654cb70b9c84 100644
--- a/sound/soc/msm/msmfalcon-external.h
+++ b/sound/soc/msm/msmfalcon-external.h
@@ -26,12 +26,14 @@ int msm_proxy_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
int msm_audrx_init(struct snd_soc_pcm_runtime *rtd);
int msm_snd_cpe_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params);
-struct snd_soc_card *populate_snd_card_dailinks(struct device *dev);
+struct snd_soc_card *populate_snd_card_dailinks(struct device *dev,
+ int snd_card_val);
int msm_ext_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params);
#ifdef CONFIG_SND_SOC_EXT_CODEC
int msm_ext_cdc_init(struct platform_device *, struct msm_asoc_mach_data *,
struct snd_soc_card **, struct wcd_mbhc_config *);
+void msm_ext_register_audio_notifier(void);
#else
inline int msm_ext_cdc_init(struct platform_device *pdev,
struct msm_asoc_mach_data *pdata,
@@ -40,5 +42,9 @@ inline int msm_ext_cdc_init(struct platform_device *pdev,
{
return 0;
}
+
+inline void msm_ext_register_audio_notifier(void)
+{
+}
#endif
#endif
diff --git a/sound/soc/msm/msmfalcon-internal.c b/sound/soc/msm/msmfalcon-internal.c
index 3a8b88cdfb64..180ff492e9e9 100644
--- a/sound/soc/msm/msmfalcon-internal.c
+++ b/sound/soc/msm/msmfalcon-internal.c
@@ -27,6 +27,9 @@
#define WCD_MBHC_DEF_RLOADS 5
+#define WCN_CDC_SLIM_RX_CH_MAX 2
+#define WCN_CDC_SLIM_TX_CH_MAX 3
+
enum {
INT0_MI2S = 0,
INT1_MI2S,
@@ -38,6 +41,24 @@ enum {
INT_MI2S_MAX,
};
+enum {
+ BT_SLIM7,
+ FM_SLIM8,
+ SLIM_MAX,
+};
+
+/*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 */
+};
+
static struct afe_clk_set int_mi2s_clk[INT_MI2S_MAX] = {
{
AFE_API_VERSION_I2S_CONFIG,
@@ -114,6 +135,11 @@ static struct dev_config int_mi2s_cfg[] = {
[INT6_MI2S] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
};
+static struct dev_config bt_fm_cfg[] = {
+ [BT_SLIM7] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [FM_SLIM8] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+};
+
static char const *int_mi2s_rate_text[] = {"KHZ_8", "KHZ_16",
"KHZ_32", "KHZ_44P1", "KHZ_48",
"KHZ_96", "KHZ_192"};
@@ -122,6 +148,7 @@ static const char *const int_mi2s_tx_ch_text[] = {"One", "Two",
"Three", "Four"};
static char const *bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE"};
static const char *const loopback_mclk_text[] = {"DISABLE", "ENABLE"};
+static char const *bt_sample_rate_text[] = {"KHZ_8", "KHZ_16", "KHZ_48"};
static SOC_ENUM_SINGLE_EXT_DECL(int0_mi2s_rx_sample_rate, int_mi2s_rate_text);
static SOC_ENUM_SINGLE_EXT_DECL(int0_mi2s_rx_chs, int_mi2s_ch_text);
@@ -137,6 +164,7 @@ static SOC_ENUM_SINGLE_EXT_DECL(int4_mi2s_rx_chs, int_mi2s_ch_text);
static SOC_ENUM_SINGLE_EXT_DECL(int4_mi2s_rx_format, bit_format_text);
static SOC_ENUM_SINGLE_EXT_DECL(int5_mi2s_tx_chs, int_mi2s_ch_text);
static SOC_ENUM_SINGLE_EXT_DECL(loopback_mclk_en, loopback_mclk_text);
+static SOC_ENUM_SINGLE_EXT_DECL(bt_sample_rate, bt_sample_rate_text);
static int msm_dmic_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event);
@@ -544,7 +572,7 @@ static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
return 0;
}
-int int_mi2s_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+static int int_mi2s_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
struct snd_soc_dai_link *dai_link = rtd->dai_link;
@@ -577,6 +605,38 @@ int int_mi2s_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
return 0;
}
+static int msm_btfm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ switch (dai_link->be_id) {
+ case MSM_BACKEND_DAI_SLIMBUS_7_RX:
+ case MSM_BACKEND_DAI_SLIMBUS_7_TX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ bt_fm_cfg[BT_SLIM7].bit_format);
+ rate->min = rate->max = bt_fm_cfg[BT_SLIM7].sample_rate;
+ channels->min = channels->max =
+ bt_fm_cfg[BT_SLIM7].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SLIMBUS_8_TX:
+ rate->min = rate->max = bt_fm_cfg[FM_SLIM8].sample_rate;
+ channels->min = channels->max =
+ bt_fm_cfg[FM_SLIM8].channels;
+ break;
+
+ default:
+ rate->min = rate->max = SAMPLING_RATE_48KHZ;
+ break;
+ }
+ return 0;
+}
+
static int msm_vi_feed_tx_ch_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -746,6 +806,55 @@ static int loopback_mclk_put(struct snd_kcontrol *kcontrol,
return ret;
}
+static int msm_bt_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ /*
+ * Slimbus_7_Rx/Tx sample rate values should always be in sync (same)
+ * when used for BT_SCO use case. Return either Rx or Tx sample rate
+ * value.
+ */
+ switch (bt_fm_cfg[BT_SLIM7].sample_rate) {
+ case SAMPLING_RATE_48KHZ:
+ ucontrol->value.integer.value[0] = 2;
+ break;
+ case SAMPLING_RATE_16KHZ:
+ ucontrol->value.integer.value[0] = 1;
+ break;
+ case SAMPLING_RATE_8KHZ:
+ default:
+ ucontrol->value.integer.value[0] = 0;
+ break;
+ }
+ pr_debug("%s: sample rate = %d", __func__,
+ bt_fm_cfg[BT_SLIM7].sample_rate);
+
+ return 0;
+}
+
+static int msm_bt_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 1:
+ bt_fm_cfg[BT_SLIM7].sample_rate = SAMPLING_RATE_16KHZ;
+ break;
+ case 2:
+ bt_fm_cfg[BT_SLIM7].sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ case 0:
+ default:
+ bt_fm_cfg[BT_SLIM7].sample_rate = SAMPLING_RATE_8KHZ;
+ break;
+ }
+ pr_debug("%s: sample rates: slim7_rx = %d, value = %d\n",
+ __func__,
+ bt_fm_cfg[BT_SLIM7].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
static const struct snd_kcontrol_new msm_snd_controls[] = {
SOC_ENUM_EXT("INT0_MI2S_RX Format", int0_mi2s_rx_format,
int_mi2s_bit_format_get, int_mi2s_bit_format_put),
@@ -779,6 +888,9 @@ static const struct snd_kcontrol_new msm_snd_controls[] = {
int_mi2s_ch_get, int_mi2s_ch_put),
SOC_ENUM_EXT("Loopback MCLK", loopback_mclk_en,
loopback_mclk_get, loopback_mclk_put),
+ SOC_ENUM_EXT("BT SampleRate", bt_sample_rate,
+ msm_bt_sample_rate_get,
+ msm_bt_sample_rate_put),
};
static const struct snd_kcontrol_new msm_swr_controls[] = {
@@ -1209,6 +1321,210 @@ static int msm_swr_audrx_init(struct snd_soc_pcm_runtime *rtd)
return 0;
}
+static int msm_wcn_init(struct snd_soc_pcm_runtime *rtd)
+{
+ unsigned int rx_ch[WCN_CDC_SLIM_RX_CH_MAX] = {157, 158};
+ unsigned int tx_ch[WCN_CDC_SLIM_TX_CH_MAX] = {159, 160, 161};
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+ return snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
+ tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
+}
+
+static int msm_wcn_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 *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
+ u32 rx_ch[WCN_CDC_SLIM_RX_CH_MAX], tx_ch[WCN_CDC_SLIM_TX_CH_MAX];
+ u32 rx_ch_cnt = 0, tx_ch_cnt = 0;
+ int ret;
+
+ dev_dbg(rtd->dev, "%s: %s_tx_dai_id_%d\n", __func__,
+ codec_dai->name, codec_dai->id);
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
+ if (ret) {
+ dev_err(rtd->dev,
+ "%s: failed to get BTFM codec chan map\n, err:%d\n",
+ __func__, ret);
+ goto exit;
+ }
+
+ dev_dbg(rtd->dev, "%s: tx_ch_cnt(%d) be_id %d\n",
+ __func__, tx_ch_cnt, dai_link->be_id);
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai,
+ tx_ch_cnt, tx_ch, rx_ch_cnt, rx_ch);
+ if (ret)
+ dev_err(rtd->dev, "%s: failed to set cpu chan map, err:%d\n",
+ __func__, ret);
+
+exit:
+ return ret;
+}
+
+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_tdm_be_ops = {
+ .hw_params = msm_tdm_snd_hw_params
+};
+
+static struct snd_soc_ops msm_wcn_ops = {
+ .hw_params = msm_wcn_hw_params,
+};
+
static struct snd_soc_ops msm_mi2s_be_ops = {
.startup = msm_mi2s_snd_startup,
.shutdown = msm_mi2s_snd_shutdown,
@@ -2029,6 +2345,145 @@ static struct snd_soc_dai_link msm_int_dai[] = {
.be_hw_params_fixup = msm_be_hw_params_fixup,
.ignore_suspend = 1,
},
+ {
+ .name = LPASS_BE_USB_AUDIO_RX,
+ .stream_name = "USB Audio Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.28672",
+ .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_USB_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_USB_AUDIO_TX,
+ .stream_name = "USB Audio Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.28673",
+ .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_USB_TX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_PRI_TDM_RX_0,
+ .stream_name = "Primary TDM0 Playback",
+ .cpu_dai_name = "msm-dai-q6-tdm.36864",
+ .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_PRI_TDM_RX_0,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_PRI_TDM_TX_0,
+ .stream_name = "Primary TDM0 Capture",
+ .cpu_dai_name = "msm-dai-q6-tdm.36865",
+ .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_PRI_TDM_TX_0,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SEC_TDM_RX_0,
+ .stream_name = "Secondary TDM0 Playback",
+ .cpu_dai_name = "msm-dai-q6-tdm.36880",
+ .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_SEC_TDM_RX_0,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SEC_TDM_TX_0,
+ .stream_name = "Secondary TDM0 Capture",
+ .cpu_dai_name = "msm-dai-q6-tdm.36881",
+ .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_SEC_TDM_TX_0,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .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_common_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_common_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_QUAT_TDM_RX_0,
+ .stream_name = "Quaternary TDM0 Playback",
+ .cpu_dai_name = "msm-dai-q6-tdm.36912",
+ .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_QUAT_TDM_RX_0,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_QUAT_TDM_TX_0,
+ .stream_name = "Quaternary TDM0 Capture",
+ .cpu_dai_name = "msm-dai-q6-tdm.36913",
+ .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_QUAT_TDM_TX_0,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
};
static struct snd_soc_dai_link msm_mi2s_be_dai_links[] = {
@@ -2277,10 +2732,64 @@ static struct snd_soc_dai_link msm_auxpcm_be_dai_links[] = {
},
};
+
+static struct snd_soc_dai_link msm_wcn_be_dai_links[] = {
+ {
+ .name = LPASS_BE_SLIMBUS_7_RX,
+ .stream_name = "Slimbus7 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16398",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "btfmslim_slave",
+ /* BT codec driver determines capabilities based on
+ * dai name, bt codecdai name should always contains
+ * supported usecase information
+ */
+ .codec_dai_name = "btfm_bt_sco_a2dp_slim_rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_7_RX,
+ .be_hw_params_fixup = msm_btfm_be_hw_params_fixup,
+ .ops = &msm_wcn_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_7_TX,
+ .stream_name = "Slimbus7 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16399",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "btfmslim_slave",
+ .codec_dai_name = "btfm_bt_sco_slim_tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_7_TX,
+ .be_hw_params_fixup = msm_btfm_be_hw_params_fixup,
+ .ops = &msm_wcn_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_8_TX,
+ .stream_name = "Slimbus8 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16401",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "btfmslim_slave",
+ .codec_dai_name = "btfm_fm_slim_tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_8_TX,
+ .be_hw_params_fixup = msm_btfm_be_hw_params_fixup,
+ .init = &msm_wcn_init,
+ .ops = &msm_wcn_ops,
+ .ignore_suspend = 1,
+ },
+};
+
static struct snd_soc_dai_link msm_int_dai_links[
ARRAY_SIZE(msm_int_dai) +
ARRAY_SIZE(msm_mi2s_be_dai_links) +
-ARRAY_SIZE(msm_auxpcm_be_dai_links)];
+ARRAY_SIZE(msm_auxpcm_be_dai_links)+
+ARRAY_SIZE(msm_wcn_be_dai_links)];
static struct snd_soc_card msmfalcon_card = {
/* snd_soc_card_msmfalcon */
@@ -2357,6 +2866,14 @@ static struct snd_soc_card *msm_int_populate_sndcard_dailinks(
sizeof(msm_auxpcm_be_dai_links));
len1 += ARRAY_SIZE(msm_auxpcm_be_dai_links);
}
+ if (of_property_read_bool(dev->of_node, "qcom,wcn-btfm")) {
+ dev_dbg(dev, "%s(): WCN BTFM support present\n",
+ __func__);
+ memcpy(dailink + len1,
+ msm_wcn_be_dai_links,
+ sizeof(msm_wcn_be_dai_links));
+ len1 += ARRAY_SIZE(msm_wcn_be_dai_links);
+ }
card->dai_link = dailink;
card->num_links = len1;
return card;