ASoc: msm: Add support for slimbus shared channel.
Previously, DSP used to setup the data path towards the
codec via slimbus. Now, the data path setup is broken into
two parts - one half of the path setup between apps to slimbus
and the other half from DSP. This configuration mode is
required to reduce overflow or underflow errors. Also this is
required to handle a configuration where mdm can talk
directly to codec.
Change-Id: Ic9f20b8a2f8a8eb355c07565ec80ec947a7a7337
Signed-off-by: Bharath Ramachandramurthy <bramacha@codeaurora.org>
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 30192d9..c8fcf5f 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -69,7 +69,7 @@
obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o
obj-$(CONFIG_MCP_UCB1200_TS) += ucb1x00-ts.o
-obj-$(CONFIG_WCD9310_CODEC) += wcd9310-core.o wcd9310-irq.o
+obj-$(CONFIG_WCD9310_CODEC) += wcd9310-core.o wcd9310-irq.o wcd9310-slimslave.o
ifeq ($(CONFIG_SA1100_ASSABET),y)
obj-$(CONFIG_MCP_UCB1200) += ucb1x00-assabet.o
diff --git a/drivers/mfd/wcd9310-core.c b/drivers/mfd/wcd9310-core.c
index 588f950..87abcda 100644
--- a/drivers/mfd/wcd9310-core.c
+++ b/drivers/mfd/wcd9310-core.c
@@ -14,8 +14,8 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/mfd/core.h>
+#include <linux/mfd/wcd9310/wcd9310-slimslave.h>
#include <linux/mfd/pm8xxx/pm8921.h>
-#include <linux/mfd/wcd9310/core.h>
#include <linux/mfd/wcd9310/pdata.h>
#include <linux/mfd/wcd9310/registers.h>
#include <linux/delay.h>
@@ -921,7 +921,7 @@
pr_err("%s: error, initializing device failed\n", __func__);
goto err_slim_add;
}
-
+ tabla_init_slimslave(tabla, tabla_pgd_la);
#ifdef CONFIG_DEBUG_FS
debugTabla = tabla;
@@ -963,6 +963,7 @@
#endif
tabla = slim_get_devicedata(pdev);
+ tabla_deinit_slimslave(tabla);
tabla_device_exit(tabla);
tabla_disable_supplies(tabla);
slim_remove_device(tabla->slim_slave);
diff --git a/drivers/mfd/wcd9310-slimslave.c b/drivers/mfd/wcd9310-slimslave.c
new file mode 100644
index 0000000..dd586fa
--- /dev/null
+++ b/drivers/mfd/wcd9310-slimslave.c
@@ -0,0 +1,522 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/mfd/wcd9310/wcd9310-slimslave.h>
+
+struct tabla_slim_sch_rx {
+ u32 sph;
+ u32 ch_num;
+ u16 ch_h;
+ u16 grph;
+};
+
+struct tabla_slim_sch_tx {
+ u32 sph;
+ u32 ch_num;
+ u16 ch_h;
+ u16 grph;
+};
+
+struct tabla_slim_sch {
+ struct tabla_slim_sch_rx rx[SLIM_MAX_RX_PORTS];
+ struct tabla_slim_sch_tx tx[SLIM_MAX_TX_PORTS];
+};
+
+static struct tabla_slim_sch sh_ch;
+
+static int tabla_alloc_slim_sh_ch_rx(struct tabla *tabla, u8 tabla_pgd_la);
+static int tabla_alloc_slim_sh_ch_tx(struct tabla *tabla, u8 tabla_pgd_la);
+static int tabla_dealloc_slim_sh_ch_rx(struct tabla *tab);
+static int tabla_dealloc_slim_sh_ch_tx(struct tabla *tab);
+
+int tabla_init_slimslave(struct tabla *tabla, u8 tabla_pgd_la)
+{
+ int ret = 0;
+
+ ret = tabla_alloc_slim_sh_ch_rx(tabla, tabla_pgd_la);
+ if (ret) {
+ pr_err("%s: Failed to alloc rx slimbus shared channels\n",
+ __func__);
+ goto rx_err;
+ }
+ ret = tabla_alloc_slim_sh_ch_tx(tabla, tabla_pgd_la);
+ if (ret) {
+ pr_err("%s: Failed to alloc tx slimbus shared channels\n",
+ __func__);
+ goto tx_err;
+ }
+ return 0;
+tx_err:
+ tabla_dealloc_slim_sh_ch_rx(tabla);
+rx_err:
+ return ret;
+}
+
+
+int tabla_deinit_slimslave(struct tabla *tabla)
+{
+ int ret = 0;
+ ret = tabla_dealloc_slim_sh_ch_rx(tabla);
+ if (ret < 0) {
+ pr_err("%s: fail to dealloc rx slim ports\n", __func__);
+ goto err;
+ }
+ ret = tabla_dealloc_slim_sh_ch_tx(tabla);
+ if (ret < 0) {
+ pr_err("%s: fail to dealloc tx slim ports\n", __func__);
+ goto err;
+ }
+err:
+ return ret;
+}
+
+int tabla_get_channel(struct tabla *tabla,
+ unsigned int *rx_ch,
+ unsigned int *tx_ch)
+{
+ int ch_idx = 0;
+ struct tabla_slim_sch_rx *rx = sh_ch.rx;
+ struct tabla_slim_sch_tx *tx = sh_ch.tx;
+
+ for (ch_idx = 0; ch_idx < SLIM_MAX_RX_PORTS; ch_idx++)
+ rx_ch[ch_idx] = rx[ch_idx].ch_num;
+ for (ch_idx = 0; ch_idx < SLIM_MAX_TX_PORTS; ch_idx++)
+ tx_ch[ch_idx] = tx[ch_idx].ch_num;
+ return 0;
+}
+
+static int tabla_alloc_slim_sh_ch_rx(struct tabla *tabla, u8 tabla_pgd_la)
+{
+ int ret = 0;
+ u8 ch_idx ;
+ u16 slave_port_id = 0;
+ struct tabla_slim_sch_rx *rx = sh_ch.rx;
+
+ /* DSP requires channel number to be between 128 and 255. For RX port
+ * use channel numbers from 138 to 144, for TX port
+ * use channel numbers from 128 to 137
+ */
+ pr_debug("%s: pgd_la[%d]\n", __func__, tabla_pgd_la);
+ for (ch_idx = 0; ch_idx < SLIM_MAX_RX_PORTS; ch_idx++) {
+ slave_port_id = (ch_idx + 1 +
+ SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS);
+ rx[ch_idx].ch_num = slave_port_id + BASE_CH_NUM;
+ ret = slim_get_slaveport(tabla_pgd_la, slave_port_id,
+ &rx[ch_idx].sph, SLIM_SINK);
+ if (ret < 0) {
+ pr_err("%s: slave port failure id[%d] ret[%d]\n",
+ __func__, slave_port_id, ret);
+ goto err;
+ }
+
+ ret = slim_query_ch(tabla->slim, rx[ch_idx].ch_num,
+ &rx[ch_idx].ch_h);
+ if (ret < 0) {
+ pr_err("%s: slim_query_ch failed ch-num[%d] ret[%d]\n",
+ __func__, rx[ch_idx].ch_num, ret);
+ goto err;
+ }
+ }
+err:
+ return ret;
+}
+
+static int tabla_alloc_slim_sh_ch_tx(struct tabla *tabla, u8 tabla_pgd_la)
+{
+ int ret = 0;
+ u8 ch_idx ;
+ struct tabla_slim_sch_tx *tx = sh_ch.tx;
+ u16 slave_port_id = 0;
+
+ pr_debug("%s: pgd_la[%d]\n", __func__, tabla_pgd_la);
+ /* DSP requires channel number to be between 128 and 255. For RX port
+ * use channel numbers from 138 to 144, for TX port
+ * use channel numbers from 128 to 137
+ */
+ for (ch_idx = 0; ch_idx < SLIM_MAX_TX_PORTS; ch_idx++) {
+ slave_port_id = ch_idx;
+ tx[ch_idx].ch_num = slave_port_id + BASE_CH_NUM;
+ ret = slim_get_slaveport(tabla_pgd_la, slave_port_id,
+ &tx[ch_idx].sph, SLIM_SRC);
+ if (ret < 0) {
+ pr_err("%s: slave port failure id[%d] ret[%d]\n",
+ __func__, slave_port_id, ret);
+ goto err;
+ }
+ ret = slim_query_ch(tabla->slim, tx[ch_idx].ch_num,
+ &tx[ch_idx].ch_h);
+ if (ret < 0) {
+ pr_err("%s: slim_query_ch failed ch-num[%d] ret[%d]\n",
+ __func__, tx[ch_idx].ch_num, ret);
+ goto err;
+ }
+ }
+err:
+ return ret;
+}
+
+static int tabla_dealloc_slim_sh_ch_rx(struct tabla *tab)
+{
+ int idx = 0;
+ int ret = 0;
+ struct tabla_slim_sch_rx *rx = sh_ch.rx;
+ /* slim_dealloc_ch */
+ for (idx = 0; idx < SLIM_MAX_RX_PORTS; idx++) {
+ ret = slim_dealloc_ch(tab->slim, rx[idx].ch_h);
+ if (ret < 0) {
+ pr_err("%s: slim_dealloc_ch fail ret[%d] ch_h[%d]\n",
+ __func__, ret, rx[idx].ch_h);
+ }
+ }
+ memset(sh_ch.rx, 0, sizeof(sh_ch.rx));
+ return ret;
+}
+
+static int tabla_dealloc_slim_sh_ch_tx(struct tabla *tab)
+{
+ int idx = 0;
+ int ret = 0;
+ struct tabla_slim_sch_tx *tx = sh_ch.tx;
+ /* slim_dealloc_ch */
+ for (idx = 0; idx < SLIM_MAX_TX_PORTS; idx++) {
+ ret = slim_dealloc_ch(tab->slim, tx[idx].ch_h);
+ if (ret < 0) {
+ pr_err("%s: slim_dealloc_ch fail ret[%d] ch_h[%d]\n",
+ __func__, ret, tx[idx].ch_h);
+ }
+ }
+ memset(sh_ch.tx, 0, sizeof(sh_ch.tx));
+ return ret;
+}
+
+/* Enable slimbus slave device for RX path */
+int tabla_cfg_slim_sch_rx(struct tabla *tab, unsigned int *ch_num,
+ unsigned int ch_cnt, unsigned int rate)
+{
+ u8 i = 0;
+ u16 grph;
+ u32 sph[SLIM_MAX_RX_PORTS] = {0};
+ u16 ch_h[SLIM_MAX_RX_PORTS] = {0};
+ u16 slave_port_id;
+ u8 payload_rx = 0, wm_payload = 0;
+ int ret, idx = 0;
+ unsigned short multi_chan_cfg_reg_addr;
+ struct tabla_slim_sch_rx *rx = sh_ch.rx;
+ struct slim_ch prop;
+
+ /* Configure slave interface device */
+ pr_debug("%s: ch_cnt[%d] rate=%d\n", __func__, ch_cnt, rate);
+
+ for (i = 0; i < ch_cnt; i++) {
+ idx = (ch_num[i] - BASE_CH_NUM -
+ SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS - 1);
+ ch_h[i] = rx[idx].ch_h;
+ sph[i] = rx[idx].sph;
+ slave_port_id = idx + 1;
+ if ((slave_port_id > SB_PGD_MAX_NUMBER_OF_RX_SLAVE_DEV_PORTS) ||
+ (slave_port_id == 0)) {
+ pr_err("Slimbus: invalid slave port id: %d",
+ slave_port_id);
+ ret = -EINVAL;
+ goto err;
+ }
+ slave_port_id += SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS;
+ /* look for the valid port range and chose the
+ * payload accordingly
+ */
+ if ((slave_port_id >
+ SB_PGD_TX_PORT_MULTI_CHANNEL_1_END_PORT_ID) &&
+ (slave_port_id <
+ SB_PGD_RX_PORT_MULTI_CHANNEL_0_END_PORT_ID)) {
+ payload_rx = payload_rx |
+ (1 <<
+ (slave_port_id -
+ SB_PGD_RX_PORT_MULTI_CHANNEL_0_START_PORT_ID));
+ } else {
+ ret = -EINVAL;
+ goto err;
+ }
+ multi_chan_cfg_reg_addr =
+ SB_PGD_RX_PORT_MULTI_CHANNEL_0(slave_port_id);
+ /* write to interface device */
+ ret = tabla_interface_reg_write(tab, multi_chan_cfg_reg_addr,
+ payload_rx);
+ if (ret < 0) {
+ pr_err("%s:Intf-dev fail reg[%d] payload[%d] ret[%d]\n",
+ __func__,
+ multi_chan_cfg_reg_addr,
+ payload_rx, ret);
+ goto err;
+ }
+ /* configure the slave port for water mark and enable*/
+ wm_payload = (SLAVE_PORT_WATER_MARK_VALUE <<
+ SLAVE_PORT_WATER_MARK_SHIFT) +
+ SLAVE_PORT_ENABLE;
+ ret = tabla_interface_reg_write(tab,
+ SB_PGD_PORT_CFG_BYTE_ADDR(slave_port_id),
+ wm_payload);
+ if (ret < 0) {
+ pr_err("%s:watermark set failure for port[%d] ret[%d]",
+ __func__, slave_port_id, ret);
+ }
+ }
+
+ /* slim_define_ch api */
+ prop.prot = SLIM_AUTO_ISO;
+ prop.baser = SLIM_RATE_4000HZ;
+ prop.dataf = SLIM_CH_DATAF_NOT_DEFINED;
+ prop.auxf = SLIM_CH_AUXF_NOT_APPLICABLE;
+ prop.ratem = (rate/4000);
+ prop.sampleszbits = 16;
+
+ ret = slim_define_ch(tab->slim, &prop, ch_h, ch_cnt,
+ true, &grph);
+ if (ret < 0) {
+ pr_err("%s: slim_define_ch failed ret[%d]\n",
+ __func__, ret);
+ goto err;
+ }
+ for (i = 0; i < ch_cnt; i++) {
+ ret = slim_connect_sink(tab->slim, &sph[i],
+ 1, ch_h[i]);
+ if (ret < 0) {
+ pr_err("%s: slim_connect_sink failed ret[%d]\n",
+ __func__, ret);
+ goto err_close_slim_sch;
+ }
+ }
+ /* slim_control_ch */
+ ret = slim_control_ch(tab->slim, grph, SLIM_CH_ACTIVATE,
+ true);
+ if (ret < 0) {
+ pr_err("%s: slim_control_ch failed ret[%d]\n",
+ __func__, ret);
+ goto err_close_slim_sch;
+ }
+ for (i = 0; i < ch_cnt; i++) {
+ idx = (ch_num[i] - BASE_CH_NUM -
+ SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS - 1);
+ rx[idx].grph = grph;
+ }
+ return 0;
+
+err_close_slim_sch:
+ /* release all acquired handles */
+ tabla_close_slim_sch_rx(tab, ch_num, ch_cnt);
+err:
+ return ret;
+}
+EXPORT_SYMBOL_GPL(tabla_cfg_slim_sch_rx);
+
+/* Enable slimbus slave device for RX path */
+int tabla_cfg_slim_sch_tx(struct tabla *tab, unsigned int *ch_num,
+ unsigned int ch_cnt, unsigned int rate)
+{
+ u8 i = 0;
+ u8 payload_tx_0 = 0, payload_tx_1 = 0, wm_payload = 0;
+ u16 grph;
+ u32 sph[SLIM_MAX_TX_PORTS] = {0};
+ u16 ch_h[SLIM_MAX_TX_PORTS] = {0};
+ u16 idx = 0, slave_port_id;
+ int ret = 0;
+ unsigned short multi_chan_cfg_reg_addr;
+
+ struct tabla_slim_sch_tx *tx = sh_ch.tx;
+ struct slim_ch prop;
+
+ pr_debug("%s: ch_cnt[%d] rate[%d]\n", __func__, ch_cnt, rate);
+ for (i = 0; i < ch_cnt; i++) {
+ idx = (ch_num[i] - BASE_CH_NUM);
+ ch_h[i] = tx[idx].ch_h;
+ sph[i] = tx[idx].sph;
+ slave_port_id = idx ;
+ if ((slave_port_id > SB_PGD_MAX_NUMBER_OF_TX_SLAVE_DEV_PORTS) ||
+ (slave_port_id == 0)) {
+ pr_err("SLIMbus: invalid slave port id: %d",
+ slave_port_id);
+ ret = -EINVAL;
+ goto err;
+ }
+ /* look for the valid port range and chose the
+ * payload accordingly
+ */
+ if (slave_port_id <=
+ SB_PGD_TX_PORT_MULTI_CHANNEL_0_END_PORT_ID) {
+ payload_tx_0 = payload_tx_0 | (1 << slave_port_id);
+ } else if (slave_port_id <
+ SB_PGD_TX_PORT_MULTI_CHANNEL_1_END_PORT_ID) {
+ payload_tx_1 = payload_tx_1 |
+ (1 <<
+ (slave_port_id -
+ SB_PGD_TX_PORT_MULTI_CHANNEL_1_START_PORT_ID));
+ } else {
+ ret = -EINVAL;
+ goto err;
+ }
+ multi_chan_cfg_reg_addr =
+ SB_PGD_TX_PORT_MULTI_CHANNEL_0(slave_port_id);
+ /* write to interface device */
+ ret = tabla_interface_reg_write(tab, multi_chan_cfg_reg_addr,
+ payload_tx_0);
+ if (ret < 0) {
+ pr_err("%s:Intf-dev fail reg[%d] payload[%d] ret[%d]\n",
+ __func__,
+ multi_chan_cfg_reg_addr,
+ payload_tx_0, ret);
+ goto err;
+ }
+ multi_chan_cfg_reg_addr =
+ SB_PGD_TX_PORT_MULTI_CHANNEL_1(slave_port_id);
+ /* ports 8,9 */
+ ret = tabla_interface_reg_write(tab, multi_chan_cfg_reg_addr,
+ payload_tx_1);
+ if (ret < 0) {
+ pr_err("%s:Intf-dev fail reg[%d] payload[%d] ret[%d]\n",
+ __func__,
+ multi_chan_cfg_reg_addr,
+ payload_tx_1, ret);
+ goto err;
+ }
+ /* configure the slave port for water mark and enable*/
+ wm_payload = (SLAVE_PORT_WATER_MARK_VALUE <<
+ SLAVE_PORT_WATER_MARK_SHIFT) +
+ SLAVE_PORT_ENABLE;
+ ret = tabla_interface_reg_write(tab,
+ SB_PGD_PORT_CFG_BYTE_ADDR(slave_port_id),
+ wm_payload);
+ if (ret < 0) {
+ pr_err("%s:watermark set failure for port[%d] ret[%d]",
+ __func__,
+ slave_port_id, ret);
+ }
+ }
+
+ /* slim_define_ch api */
+ prop.prot = SLIM_AUTO_ISO;
+ prop.baser = SLIM_RATE_4000HZ;
+ prop.dataf = SLIM_CH_DATAF_NOT_DEFINED;
+ prop.auxf = SLIM_CH_AUXF_NOT_APPLICABLE;
+ prop.ratem = (rate/4000);
+ prop.sampleszbits = 16;
+ ret = slim_define_ch(tab->slim, &prop, ch_h, ch_cnt,
+ true, &grph);
+ if (ret < 0) {
+ pr_err("%s: slim_define_ch failed ret[%d]\n",
+ __func__, ret);
+ goto err;
+ }
+ for (i = 0; i < ch_cnt; i++) {
+ ret = slim_connect_src(tab->slim, sph[i],
+ ch_h[i]);
+ if (ret < 0) {
+ pr_err("%s: slim_connect_src failed ret[%d]\n",
+ __func__, ret);
+ goto err;
+ }
+ }
+ /* slim_control_ch */
+ ret = slim_control_ch(tab->slim, grph, SLIM_CH_ACTIVATE,
+ true);
+ if (ret < 0) {
+ pr_err("%s: slim_control_ch failed ret[%d]\n",
+ __func__, ret);
+ goto err;
+ }
+ for (i = 0; i < ch_cnt; i++) {
+ idx = (ch_num[i] - BASE_CH_NUM);
+ tx[idx].grph = grph;
+ }
+ return 0;
+err:
+ /* release all acquired handles */
+ tabla_close_slim_sch_tx(tab, ch_num, ch_cnt);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(tabla_cfg_slim_sch_tx);
+
+int tabla_close_slim_sch_rx(struct tabla *tab, unsigned int *ch_num,
+ unsigned int ch_cnt)
+{
+ u16 grph = 0;
+ u32 sph[SLIM_MAX_RX_PORTS] = {0};
+ int i = 0 , idx = 0;
+ int ret = 0;
+ struct tabla_slim_sch_rx *rx = sh_ch.rx;
+
+ pr_debug("%s: ch_cnt[%d]\n", __func__, ch_cnt);
+ for (i = 0; i < ch_cnt; i++) {
+ idx = (ch_num[i] - BASE_CH_NUM -
+ SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS - 1);
+ sph[i] = rx[idx].sph;
+ grph = rx[idx].grph;
+ }
+
+ /* slim_disconnect_port */
+ ret = slim_disconnect_ports(tab->slim, sph, ch_cnt);
+ if (ret < 0) {
+ pr_err("%s: slim_disconnect_ports failed ret[%d]\n",
+ __func__, ret);
+ }
+ /* slim_control_ch (REMOVE) */
+ ret = slim_control_ch(tab->slim, grph, SLIM_CH_REMOVE, true);
+ if (ret < 0) {
+ pr_err("%s: slim_control_ch failed ret[%d]\n",
+ __func__, ret);
+ goto err;
+ }
+ for (i = 0; i < ch_cnt; i++) {
+ idx = (ch_num[i] - BASE_CH_NUM -
+ SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS - 1);
+ rx[idx].grph = 0;
+ }
+err:
+ return ret;
+}
+EXPORT_SYMBOL_GPL(tabla_close_slim_sch_rx);
+
+int tabla_close_slim_sch_tx(struct tabla *tab, unsigned int *ch_num,
+ unsigned int ch_cnt)
+{
+ u16 grph = 0;
+ u32 sph[SLIM_MAX_TX_PORTS] = {0};
+ int ret = 0;
+ int i = 0 , idx = 0;
+ struct tabla_slim_sch_tx *tx = sh_ch.tx;
+
+ pr_debug("%s: ch_cnt[%d]\n", __func__, ch_cnt);
+ for (i = 0; i < ch_cnt; i++) {
+ idx = (ch_num[i] - BASE_CH_NUM);
+ sph[i] = tx[idx].sph;
+ grph = tx[idx].grph;
+ }
+ /* slim_disconnect_port */
+ ret = slim_disconnect_ports(tab->slim, sph, ch_cnt);
+ if (ret < 0) {
+ pr_err("%s: slim_disconnect_ports failed ret[%d]\n",
+ __func__, ret);
+ }
+ /* slim_control_ch (REMOVE) */
+ ret = slim_control_ch(tab->slim, grph, SLIM_CH_REMOVE, true);
+ if (ret < 0) {
+ pr_err("%s: slim_control_ch failed ret[%d]\n",
+ __func__, ret);
+ goto err;
+ }
+ for (i = 0; i < ch_cnt; i++) {
+ idx = (ch_num[i] - BASE_CH_NUM);
+ tx[idx].grph = 0;
+ }
+err:
+ return ret;
+}
+EXPORT_SYMBOL_GPL(tabla_close_slim_sch_tx);
diff --git a/include/linux/mfd/wcd9310/wcd9310-slimslave.h b/include/linux/mfd/wcd9310/wcd9310-slimslave.h
new file mode 100644
index 0000000..0bbf96f
--- /dev/null
+++ b/include/linux/mfd/wcd9310/wcd9310-slimslave.h
@@ -0,0 +1,102 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __WCD9310_SLIMSLAVE_H_
+#define __WCD9310_SLIMSLAVE_H_
+
+#include <linux/slimbus/slimbus.h>
+#include <linux/mfd/wcd9310/core.h>
+
+/* Local to the core only */
+#define SLIM_MAX_RX_PORTS 7
+#define SLIM_MAX_TX_PORTS 10
+
+/* Channel numbers to be used for each port */
+enum {
+ SLIM_TX_1 = 128,
+ SLIM_TX_2 = 129,
+ SLIM_TX_3 = 130,
+ SLIM_TX_4 = 131,
+ SLIM_TX_5 = 132,
+ SLIM_TX_6 = 133,
+ SLIM_TX_7 = 134,
+ SLIM_TX_8 = 135,
+ SLIM_TX_9 = 136,
+ SLIM_TX_10 = 137,
+ SLIM_RX_1 = 138,
+ SLIM_RX_2 = 139,
+ SLIM_RX_3 = 140,
+ SLIM_RX_4 = 141,
+ SLIM_RX_5 = 142,
+ SLIM_RX_6 = 143,
+ SLIM_RX_7 = 144,
+ SLIM_MAX = 145
+};
+
+/*
+ * client is expected to give port ids in the range of 1-10 for Tx ports and
+ * 1-7 for Rx ports, we need to add offset for getting the absolute slave
+ * port id before configuring the HW
+ */
+#define SB_PGD_MAX_NUMBER_OF_TX_SLAVE_DEV_PORTS 10
+#define SB_PGD_OFFSET_OF_TX_SLAVE_DEV_PORTS -1
+#define SB_PGD_MAX_NUMBER_OF_RX_SLAVE_DEV_PORTS 7
+#define SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS 9
+
+/* below details are taken from SLIMBUS slave SWI */
+#define SB_PGD_PORT_BASE 0x000
+
+#define SB_PGD_PORT_CFG_BYTE_ADDR(port_num) \
+ (SB_PGD_PORT_BASE + 0x040 + 1*port_num)
+
+#define SB_PGD_TX_PORT_MULTI_CHANNEL_0(port_num) \
+ (SB_PGD_PORT_BASE + 0x100 + 4*port_num)
+#define SB_PGD_TX_PORT_MULTI_CHANNEL_0_START_PORT_ID 0
+#define SB_PGD_TX_PORT_MULTI_CHANNEL_0_END_PORT_ID 7
+
+#define SB_PGD_TX_PORT_MULTI_CHANNEL_1(port_num) \
+ (SB_PGD_PORT_BASE + 0x101 + 4*port_num)
+#define SB_PGD_TX_PORT_MULTI_CHANNEL_1_START_PORT_ID 8
+#define SB_PGD_TX_PORT_MULTI_CHANNEL_1_END_PORT_ID 9
+
+#define SB_PGD_RX_PORT_MULTI_CHANNEL_0(port_num) \
+ (SB_PGD_PORT_BASE + 0x180 + 4*port_num)
+#define SB_PGD_RX_PORT_MULTI_CHANNEL_0_START_PORT_ID 10
+#define SB_PGD_RX_PORT_MULTI_CHANNEL_0_END_PORT_ID 16
+
+/* slave port water mark level
+ * (0: 6bytes, 1: 9bytes, 2: 12 bytes, 3: 15 bytes)
+ */
+#define SLAVE_PORT_WATER_MARK_VALUE 2
+#define SLAVE_PORT_WATER_MARK_SHIFT 1
+#define SLAVE_PORT_ENABLE 1
+#define SLAVE_PORT_DISABLE 0
+
+#define BASE_CH_NUM 128
+
+
+int tabla_init_slimslave(struct tabla *tabla, u8 tabla_pgd_la);
+
+int tabla_deinit_slimslave(struct tabla *tabla);
+
+int tabla_cfg_slim_sch_rx(struct tabla *tabla, unsigned int *ch_num,
+ unsigned int tot_ch, unsigned int rate);
+int tabla_cfg_slim_sch_tx(struct tabla *tabla, unsigned int *ch_num,
+ unsigned int tot_ch, unsigned int rate);
+int tabla_close_slim_sch_rx(struct tabla *tabla, unsigned int *ch_num,
+ unsigned int tot_ch);
+int tabla_close_slim_sch_tx(struct tabla *tabla, unsigned int *ch_num,
+ unsigned int tot_ch);
+int tabla_get_channel(struct tabla *tabla,
+ unsigned int *rx_ch,
+ unsigned int *tx_ch);
+#endif /* __WCD9310_SLIMSLAVE_H_ */
diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h
index 87bafed..097ba39 100644
--- a/include/sound/apr_audio.h
+++ b/include/sound/apr_audio.h
@@ -272,6 +272,16 @@
u16 reserved;
} __packed;
+struct afe_port_slimbus_sch_cfg {
+ u16 slimbus_dev_id; /* SLIMBUS Device id.*/
+ u16 bit_width; /** bit width of the samples, 16, 24.*/
+ u16 data_format; /** data format.*/
+ u16 num_channels; /** Number of channels.*/
+ u16 reserved;
+ /** Slave channel mapping for respective channels.*/
+ u8 slave_ch_mapping[8];
+} __packed;
+
struct afe_port_rtproxy_cfg {
u16 bitwidth; /* 16,24,32 */
u16 interleaved; /* interleaved = 1 */
@@ -284,16 +294,18 @@
int num_ch; /* 1 to 8 */
} __packed;
-#define AFE_PORT_AUDIO_IF_CONFIG 0x000100d3
+#define AFE_PORT_AUDIO_IF_CONFIG 0x000100d3
+#define AFE_PORT_AUDIO_SLIM_SCH_CONFIG 0x000100e4
#define AFE_PORT_MULTI_CHAN_HDMI_AUDIO_IF_CONFIG 0x000100D9
union afe_port_config {
- struct afe_port_pcm_cfg pcm;
- struct afe_port_mi2s_cfg mi2s;
- struct afe_port_hdmi_cfg hdmi;
- struct afe_port_hdmi_multi_ch_cfg hdmi_multi_ch;
- struct afe_port_slimbus_cfg slimbus;
- struct afe_port_rtproxy_cfg rtproxy;
+ struct afe_port_pcm_cfg pcm;
+ struct afe_port_mi2s_cfg mi2s;
+ struct afe_port_hdmi_cfg hdmi;
+ struct afe_port_hdmi_multi_ch_cfg hdmi_multi_ch;
+ struct afe_port_slimbus_cfg slimbus;
+ struct afe_port_slimbus_sch_cfg slim_sch;
+ struct afe_port_rtproxy_cfg rtproxy;
} __attribute__((packed));
struct afe_audioif_config_command {
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index bda171e..f1ce01f 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -2,6 +2,7 @@
* linux/sound/soc-dai.h -- ALSA SoC Layer
*
* Copyright: 2005-2008 Wolfson Microelectronics. PLC.
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -121,6 +122,10 @@
unsigned int tx_num, unsigned int *tx_slot,
unsigned int rx_num, unsigned int *rx_slot);
+int snd_soc_dai_get_channel_map(struct snd_soc_dai *dai,
+ unsigned int *tx_num, unsigned int *tx_slot,
+ unsigned int *rx_num, unsigned int *rx_slot);
+
int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate);
/* Digital Audio Interface mute */
@@ -150,6 +155,9 @@
unsigned int rx_num, unsigned int *rx_slot);
int (*set_tristate)(struct snd_soc_dai *dai, int tristate);
+ int (*get_channel_map)(struct snd_soc_dai *dai,
+ unsigned int *tx_num, unsigned int *tx_slot,
+ unsigned int *rx_num, unsigned int *rx_slot);
/*
* DAI digital mute - optional.
* Called by soc-core to minimise any pops.
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 7c2073d..deb13dc 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -36,8 +36,6 @@
#define NUM_DECIMATORS 10
#define NUM_INTERPOLATORS 7
#define BITS_PER_REG 8
-#define TABLA_RX_DAI_ID 1
-#define TABLA_TX_DAI_ID 2
#define TABLA_CFILT_FAST_MODE 0x00
#define TABLA_CFILT_SLOW_MODE 0x40
#define MBHC_FW_READ_ATTEMPTS 15
@@ -49,6 +47,17 @@
#define TABLA_OCP_ATTEMPT 1
+#define AIF1_PB 1
+#define AIF1_CAP 2
+#define NUM_CODEC_DAIS 2
+
+struct tabla_codec_dai_data {
+ u32 rate;
+ u32 *ch_num;
+ u32 ch_act;
+ u32 ch_tot;
+};
+
#define TABLA_MCLK_RATE_12288KHZ 12288000
#define TABLA_MCLK_RATE_9600KHZ 9600000
@@ -58,6 +67,7 @@
static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
+static struct snd_soc_dai_driver tabla_dai[];
enum tabla_bandgap_type {
TABLA_BANDGAP_OFF = 0,
@@ -194,6 +204,9 @@
/* Work to perform MBHC Firmware Read */
struct delayed_work mbhc_firmware_dwork;
const struct firmware *mbhc_fw;
+
+ /* num of slim ports required */
+ struct tabla_codec_dai_data dai[NUM_CODEC_DAIS];
};
#ifdef CONFIG_DEBUG_FS
@@ -1907,306 +1920,6 @@
return 0;
}
-static const struct snd_soc_dapm_widget tabla_dapm_widgets[] = {
- /*RX stuff */
- SND_SOC_DAPM_OUTPUT("EAR"),
-
- SND_SOC_DAPM_PGA("EAR PA", TABLA_A_RX_EAR_EN, 4, 0, NULL, 0),
-
- SND_SOC_DAPM_MIXER("DAC1", TABLA_A_RX_EAR_EN, 6, 0, dac1_switch,
- ARRAY_SIZE(dac1_switch)),
-
- SND_SOC_DAPM_AIF_IN("SLIM RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
- SND_SOC_DAPM_AIF_IN("SLIM RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
- SND_SOC_DAPM_AIF_IN("SLIM RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
- SND_SOC_DAPM_AIF_IN("SLIM RX4", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
-
- /* Headphone */
- SND_SOC_DAPM_OUTPUT("HEADPHONE"),
- SND_SOC_DAPM_PGA_E("HPHL", TABLA_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
- tabla_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MIXER("HPHL DAC", TABLA_A_RX_HPH_L_DAC_CTL, 7, 0,
- hphl_switch, ARRAY_SIZE(hphl_switch)),
-
- SND_SOC_DAPM_PGA_E("HPHR", TABLA_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
- tabla_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, TABLA_A_RX_HPH_R_DAC_CTL, 7, 0,
- tabla_hphr_dac_event,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-
- /* Speaker */
- SND_SOC_DAPM_OUTPUT("LINEOUT1"),
- SND_SOC_DAPM_OUTPUT("LINEOUT2"),
- SND_SOC_DAPM_OUTPUT("LINEOUT3"),
- SND_SOC_DAPM_OUTPUT("LINEOUT4"),
- SND_SOC_DAPM_OUTPUT("LINEOUT5"),
-
- SND_SOC_DAPM_PGA_E("LINEOUT1 PA", TABLA_A_RX_LINE_CNP_EN, 0, 0, NULL,
- 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_PGA_E("LINEOUT2 PA", TABLA_A_RX_LINE_CNP_EN, 1, 0, NULL,
- 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_PGA_E("LINEOUT3 PA", TABLA_A_RX_LINE_CNP_EN, 2, 0, NULL,
- 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_PGA_E("LINEOUT4 PA", TABLA_A_RX_LINE_CNP_EN, 3, 0, NULL,
- 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_PGA_E("LINEOUT5 PA", TABLA_A_RX_LINE_CNP_EN, 4, 0, NULL, 0,
- tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL, TABLA_A_RX_LINE_1_DAC_CTL, 7, 0
- , tabla_lineout_dac_event,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_DAC_E("LINEOUT2 DAC", NULL, TABLA_A_RX_LINE_2_DAC_CTL, 7, 0
- , tabla_lineout_dac_event,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_DAC_E("LINEOUT3 DAC", NULL, TABLA_A_RX_LINE_3_DAC_CTL, 7, 0
- , tabla_lineout_dac_event,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_SWITCH("LINEOUT3 DAC GROUND", SND_SOC_NOPM, 0, 0,
- &lineout3_ground_switch),
- SND_SOC_DAPM_DAC_E("LINEOUT4 DAC", NULL, TABLA_A_RX_LINE_4_DAC_CTL, 7, 0
- , tabla_lineout_dac_event,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_SWITCH("LINEOUT4 DAC GROUND", SND_SOC_NOPM, 0, 0,
- &lineout4_ground_switch),
- SND_SOC_DAPM_DAC_E("LINEOUT5 DAC", NULL, TABLA_A_RX_LINE_5_DAC_CTL, 7, 0
- , tabla_lineout_dac_event,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_MIXER_E("RX1 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
- 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
- SND_SOC_DAPM_MIXER_E("RX2 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
- 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
- SND_SOC_DAPM_MIXER_E("RX3 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
- 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
- SND_SOC_DAPM_MIXER_E("RX4 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
- 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
- SND_SOC_DAPM_MIXER_E("RX5 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 4, 0, NULL,
- 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
- SND_SOC_DAPM_MIXER_E("RX6 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0, NULL,
- 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
- SND_SOC_DAPM_MIXER_E("RX7 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 6, 0, NULL,
- 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
-
-
- SND_SOC_DAPM_MUX_E("RX4 DSM MUX", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0,
- &rx4_dsm_mux, tabla_codec_reset_interpolator,
- SND_SOC_DAPM_PRE_PMU),
-
- SND_SOC_DAPM_MUX_E("RX6 DSM MUX", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0,
- &rx6_dsm_mux, tabla_codec_reset_interpolator,
- SND_SOC_DAPM_PRE_PMU),
-
- SND_SOC_DAPM_MIXER("RX1 CHAIN", TABLA_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
- SND_SOC_DAPM_MIXER("RX2 CHAIN", TABLA_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
-
- SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
- &rx_mix1_inp1_mux),
- SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
- &rx_mix1_inp2_mux),
- SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
- &rx2_mix1_inp1_mux),
- SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
- &rx2_mix1_inp2_mux),
- SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
- &rx3_mix1_inp1_mux),
- SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
- &rx3_mix1_inp2_mux),
- SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
- &rx4_mix1_inp1_mux),
- SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
- &rx4_mix1_inp2_mux),
- SND_SOC_DAPM_MUX("RX5 MIX1 INP1", SND_SOC_NOPM, 0, 0,
- &rx5_mix1_inp1_mux),
- SND_SOC_DAPM_MUX("RX5 MIX1 INP2", SND_SOC_NOPM, 0, 0,
- &rx5_mix1_inp2_mux),
- SND_SOC_DAPM_MUX("RX6 MIX1 INP1", SND_SOC_NOPM, 0, 0,
- &rx6_mix1_inp1_mux),
- SND_SOC_DAPM_MUX("RX6 MIX1 INP2", SND_SOC_NOPM, 0, 0,
- &rx6_mix1_inp2_mux),
- SND_SOC_DAPM_MUX("RX7 MIX1 INP1", SND_SOC_NOPM, 0, 0,
- &rx7_mix1_inp1_mux),
- SND_SOC_DAPM_MUX("RX7 MIX1 INP2", SND_SOC_NOPM, 0, 0,
- &rx7_mix1_inp2_mux),
-
- SND_SOC_DAPM_SUPPLY("CP", TABLA_A_CP_EN, 0, 0,
- tabla_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
- SND_SOC_DAPM_PRE_PMD),
-
- SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
- tabla_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMD),
-
- /* TX */
-
- SND_SOC_DAPM_SUPPLY("CDC_CONN", TABLA_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
- 0),
-
- SND_SOC_DAPM_SUPPLY("LDO_H", TABLA_A_LDO_H_MODE_1, 7, 0,
- tabla_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
-
- SND_SOC_DAPM_INPUT("AMIC1"),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TABLA_A_MICB_1_CTL, 7, 0,
- tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", TABLA_A_MICB_1_CTL, 7, 0,
- tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", TABLA_A_MICB_1_CTL, 7, 0,
- tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_ADC_E("ADC1", NULL, TABLA_A_TX_1_2_EN, 7, 0,
- tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_INPUT("AMIC3"),
- SND_SOC_DAPM_ADC_E("ADC3", NULL, TABLA_A_TX_3_4_EN, 7, 0,
- tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_INPUT("AMIC4"),
- SND_SOC_DAPM_ADC_E("ADC4", NULL, TABLA_A_TX_3_4_EN, 3, 0,
- tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_INPUT("AMIC5"),
- SND_SOC_DAPM_ADC_E("ADC5", NULL, TABLA_A_TX_5_6_EN, 7, 0,
- tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
-
- SND_SOC_DAPM_INPUT("AMIC6"),
- SND_SOC_DAPM_ADC_E("ADC6", NULL, TABLA_A_TX_5_6_EN, 3, 0,
- tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
-
- SND_SOC_DAPM_MUX_E("DEC1 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
- &dec1_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
-
- SND_SOC_DAPM_MUX_E("DEC2 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0,
- &dec2_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
-
- SND_SOC_DAPM_MUX_E("DEC3 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 2, 0,
- &dec3_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
-
- SND_SOC_DAPM_MUX_E("DEC4 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 3, 0,
- &dec4_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
-
- SND_SOC_DAPM_MUX_E("DEC5 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 4, 0,
- &dec5_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
-
- SND_SOC_DAPM_MUX_E("DEC6 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 5, 0,
- &dec6_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
-
- SND_SOC_DAPM_MUX_E("DEC7 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 6, 0,
- &dec7_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
-
- SND_SOC_DAPM_MUX_E("DEC8 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 7, 0,
- &dec8_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
-
- SND_SOC_DAPM_MUX_E("DEC9 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL, 0, 0,
- &dec9_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
-
- SND_SOC_DAPM_MUX_E("DEC10 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL, 1, 0,
- &dec10_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
-
- SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
- SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
-
- SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
- tabla_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
-
- SND_SOC_DAPM_INPUT("AMIC2"),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TABLA_A_MICB_2_CTL, 7, 0,
- tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", TABLA_A_MICB_2_CTL, 7, 0,
- tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", TABLA_A_MICB_2_CTL, 7, 0,
- tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", TABLA_A_MICB_2_CTL, 7, 0,
- tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TABLA_A_MICB_3_CTL, 7, 0,
- tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", TABLA_A_MICB_3_CTL, 7, 0,
- tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", TABLA_A_MICB_3_CTL, 7, 0,
- tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_ADC_E("ADC2", NULL, TABLA_A_TX_1_2_EN, 3, 0,
- tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, 0, 0, &sb_tx1_mux),
- SND_SOC_DAPM_AIF_OUT("SLIM TX1", "AIF1 Capture", NULL, SND_SOC_NOPM,
- 0, 0),
-
- SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, 0, 0, &sb_tx5_mux),
- SND_SOC_DAPM_AIF_OUT("SLIM TX5", "AIF1 Capture", NULL, SND_SOC_NOPM,
- 4, 0),
-
- SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, 0, 0, &sb_tx6_mux),
- SND_SOC_DAPM_AIF_OUT("SLIM TX6", "AIF1 Capture", NULL, SND_SOC_NOPM,
- 5, 0),
-
- SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, 0, 0, &sb_tx7_mux),
- SND_SOC_DAPM_AIF_OUT("SLIM TX7", "AIF1 Capture", NULL, SND_SOC_NOPM,
- 0, 0),
-
- SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, 0, 0, &sb_tx8_mux),
- SND_SOC_DAPM_AIF_OUT("SLIM TX8", "AIF1 Capture", NULL, SND_SOC_NOPM,
- 0, 0),
-
- SND_SOC_DAPM_MUX("SLIM TX9 MUX", SND_SOC_NOPM, 0, 0, &sb_tx9_mux),
- SND_SOC_DAPM_AIF_OUT("SLIM TX9", "AIF1 Capture", NULL, SND_SOC_NOPM,
- 0, 0),
-
- SND_SOC_DAPM_MUX("SLIM TX10 MUX", SND_SOC_NOPM, 0, 0, &sb_tx10_mux),
- SND_SOC_DAPM_AIF_OUT("SLIM TX10", "AIF1 Capture", NULL, SND_SOC_NOPM,
- 0, 0),
-
- /* Digital Mic Inputs */
- SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
- tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
- tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
- tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
- tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 0, 0,
- tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_ADC_E("DMIC6", NULL, SND_SOC_NOPM, 0, 0,
- tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMD),
-
- /* Sidetone */
- SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
- SND_SOC_DAPM_PGA("IIR1", TABLA_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
-};
-
static const struct snd_soc_dapm_widget tabla_1_x_dapm_widgets[] = {
SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_1_A_MICB_4_CTL, 7,
0, tabla_codec_enable_micbias,
@@ -2675,7 +2388,6 @@
{
struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
- pr_debug("%s: enable = %d\n", __func__, enable);
if (enable) {
snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x10, 0);
snd_soc_write(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x17);
@@ -2880,11 +2592,11 @@
case SND_SOC_DAIFMT_CBS_CFS:
/* CPU is master */
if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
- if (dai->id == TABLA_TX_DAI_ID)
+ if (dai->id == AIF1_CAP)
snd_soc_update_bits(dai->codec,
TABLA_A_CDC_CLK_TX_I2S_CTL,
TABLA_I2S_MASTER_MODE_MASK, 0);
- else if (dai->id == TABLA_RX_DAI_ID)
+ else if (dai->id == AIF1_PB)
snd_soc_update_bits(dai->codec,
TABLA_A_CDC_CLK_RX_I2S_CTL,
TABLA_I2S_MASTER_MODE_MASK, 0);
@@ -2894,10 +2606,10 @@
/* CPU is slave */
if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
val = TABLA_I2S_MASTER_MODE_MASK;
- if (dai->id == TABLA_TX_DAI_ID)
+ if (dai->id == AIF1_CAP)
snd_soc_update_bits(dai->codec,
TABLA_A_CDC_CLK_TX_I2S_CTL, val, val);
- else if (dai->id == TABLA_RX_DAI_ID)
+ else if (dai->id == AIF1_PB)
snd_soc_update_bits(dai->codec,
TABLA_A_CDC_CLK_RX_I2S_CTL, val, val);
}
@@ -2908,6 +2620,71 @@
return 0;
}
+static int tabla_set_channel_map(struct snd_soc_dai *dai,
+ unsigned int tx_num, unsigned int *tx_slot,
+ unsigned int rx_num, unsigned int *rx_slot)
+
+{
+ struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
+ u32 i = 0;
+ if (!tx_slot && !rx_slot) {
+ pr_err("%s: Invalid\n", __func__);
+ return -EINVAL;
+ }
+ pr_debug("%s: DAI-ID %x %d %d\n", __func__, dai->id, tx_num, rx_num);
+
+ if (dai->id == AIF1_PB) {
+ for (i = 0; i < rx_num; i++) {
+ tabla->dai[dai->id - 1].ch_num[i] = rx_slot[i];
+ tabla->dai[dai->id - 1].ch_act = 0;
+ tabla->dai[dai->id - 1].ch_tot = rx_num;
+ }
+ } else if (dai->id == AIF1_CAP) {
+ for (i = 0; i < tx_num; i++) {
+ tabla->dai[dai->id - 1].ch_num[i] = tx_slot[i];
+ tabla->dai[dai->id - 1].ch_act = 0;
+ tabla->dai[dai->id - 1].ch_tot = tx_num;
+ }
+ }
+ return 0;
+}
+
+static int tabla_get_channel_map(struct snd_soc_dai *dai,
+ unsigned int *tx_num, unsigned int *tx_slot,
+ unsigned int *rx_num, unsigned int *rx_slot)
+
+{
+ struct tabla *tabla = dev_get_drvdata(dai->codec->control_data);
+
+ u32 cnt = 0;
+ u32 tx_ch[SLIM_MAX_TX_PORTS];
+ u32 rx_ch[SLIM_MAX_RX_PORTS];
+
+ if (!rx_slot && !tx_slot) {
+ pr_err("%s: Invalid\n", __func__);
+ return -EINVAL;
+ }
+ pr_debug("%s: DAI-ID %x\n", __func__, dai->id);
+ /* for virtual port, codec driver needs to do
+ * housekeeping, for now should be ok
+ */
+ tabla_get_channel(tabla, rx_ch, tx_ch);
+ if (dai->id == AIF1_PB) {
+ *rx_num = tabla_dai[dai->id - 1].playback.channels_max;
+ while (cnt < *rx_num) {
+ rx_slot[cnt] = rx_ch[cnt];
+ cnt++;
+ }
+ } else if (dai->id == AIF1_CAP) {
+ *tx_num = tabla_dai[dai->id - 1].capture.channels_max;
+ while (cnt < *tx_num) {
+ tx_slot[cnt] = tx_ch[6 + cnt];
+ cnt++;
+ }
+ }
+ return 0;
+}
+
static int tabla_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
@@ -2918,7 +2695,8 @@
u16 tx_fs_reg, rx_fs_reg;
u8 tx_fs_rate, rx_fs_rate, rx_state, tx_state;
- pr_debug("%s: DAI-ID %x\n", __func__, dai->id);
+ pr_debug("%s: DAI-ID %x rate %d\n", __func__, dai->id,
+ params_rate(params));
switch (params_rate(params)) {
case 8000:
@@ -2948,7 +2726,7 @@
* If current dai is a tx dai, set sample rate to
* all the txfe paths that are currently not active
*/
- if (dai->id == TABLA_TX_DAI_ID) {
+ if (dai->id == AIF1_CAP) {
tx_state = snd_soc_read(codec,
TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL);
@@ -2987,9 +2765,10 @@
}
snd_soc_update_bits(codec, TABLA_A_CDC_CLK_TX_I2S_CTL,
0x03, tx_fs_rate);
+ } else {
+ tabla->dai[dai->id - 1].rate = params_rate(params);
}
}
-
/**
* TODO: Need to handle case where same RX chain takes 2 or more inputs
* with varying sample rates
@@ -2999,7 +2778,7 @@
* If current dai is a rx dai, set sample rate to
* all the rx paths that are currently not active
*/
- if (dai->id == TABLA_RX_DAI_ID) {
+ if (dai->id == AIF1_PB) {
rx_state = snd_soc_read(codec,
TABLA_A_CDC_CLK_RX_B1_CTL);
@@ -3032,6 +2811,8 @@
}
snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_I2S_CTL,
0x03, (rx_fs_rate >> 0x05));
+ } else {
+ tabla->dai[dai->id - 1].rate = params_rate(params);
}
}
@@ -3044,12 +2825,14 @@
.hw_params = tabla_hw_params,
.set_sysclk = tabla_set_dai_sysclk,
.set_fmt = tabla_set_dai_fmt,
+ .set_channel_map = tabla_set_channel_map,
+ .get_channel_map = tabla_get_channel_map,
};
static struct snd_soc_dai_driver tabla_dai[] = {
{
.name = "tabla_rx1",
- .id = 1,
+ .id = AIF1_PB,
.playback = {
.stream_name = "AIF1 Playback",
.rates = WCD9310_RATES,
@@ -3057,13 +2840,13 @@
.rate_max = 48000,
.rate_min = 8000,
.channels_min = 1,
- .channels_max = 4,
+ .channels_max = 2,
},
.ops = &tabla_dai_ops,
},
{
.name = "tabla_tx1",
- .id = 2,
+ .id = AIF1_CAP,
.capture = {
.stream_name = "AIF1 Capture",
.rates = WCD9310_RATES,
@@ -3071,7 +2854,7 @@
.rate_max = 48000,
.rate_min = 8000,
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 4,
},
.ops = &tabla_dai_ops,
},
@@ -3107,6 +2890,426 @@
.ops = &tabla_dai_ops,
},
};
+
+static int tabla_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct tabla *tabla;
+ struct snd_soc_codec *codec = w->codec;
+ struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
+ u32 j = 0;
+ u32 ret = 0;
+ codec->control_data = dev_get_drvdata(codec->dev->parent);
+ tabla = codec->control_data;
+ /* Execute the callback only if interface type is slimbus */
+ if (tabla_p->intf_type != TABLA_INTERFACE_TYPE_SLIMBUS)
+ return 0;
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
+ if (tabla_dai[j].id == AIF1_CAP)
+ continue;
+ if (!strncmp(w->sname,
+ tabla_dai[j].playback.stream_name, 13)) {
+ ++tabla_p->dai[j].ch_act;
+ break;
+ }
+ }
+ if (tabla_p->dai[j].ch_act == tabla_p->dai[j].ch_tot)
+ ret = tabla_cfg_slim_sch_rx(tabla,
+ tabla_p->dai[j].ch_num,
+ tabla_p->dai[j].ch_tot,
+ tabla_p->dai[j].rate);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
+ if (tabla_dai[j].id == AIF1_CAP)
+ continue;
+ if (!strncmp(w->sname,
+ tabla_dai[j].playback.stream_name, 13)) {
+ --tabla_p->dai[j].ch_act;
+ break;
+ }
+ }
+ if (!tabla_p->dai[j].ch_act) {
+ ret = tabla_close_slim_sch_rx(tabla,
+ tabla_p->dai[j].ch_num,
+ tabla_p->dai[j].ch_tot);
+ tabla_p->dai[j].rate = 0;
+ memset(tabla_p->dai[j].ch_num, 0, (sizeof(u32)*
+ tabla_p->dai[j].ch_tot));
+ tabla_p->dai[j].ch_tot = 0;
+ }
+ }
+ return ret;
+}
+
+static int tabla_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct tabla *tabla;
+ struct snd_soc_codec *codec = w->codec;
+ struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
+ /* index to the DAI ID, for now hardcoding */
+ u32 j = 0;
+ u32 ret = 0;
+
+ codec->control_data = dev_get_drvdata(codec->dev->parent);
+ tabla = codec->control_data;
+
+ /* Execute the callback only if interface type is slimbus */
+ if (tabla_p->intf_type != TABLA_INTERFACE_TYPE_SLIMBUS)
+ return 0;
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
+ if (tabla_dai[j].id == AIF1_PB)
+ continue;
+ if (!strncmp(w->sname,
+ tabla_dai[j].capture.stream_name, 13)) {
+ ++tabla_p->dai[j].ch_act;
+ break;
+ }
+ }
+ if (tabla_p->dai[j].ch_act == tabla_p->dai[j].ch_tot)
+ ret = tabla_cfg_slim_sch_tx(tabla,
+ tabla_p->dai[j].ch_num,
+ tabla_p->dai[j].ch_tot,
+ tabla_p->dai[j].rate);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
+ if (tabla_dai[j].id == AIF1_PB)
+ continue;
+ if (!strncmp(w->sname,
+ tabla_dai[j].capture.stream_name, 13)) {
+ --tabla_p->dai[j].ch_act;
+ break;
+ }
+ }
+ if (!tabla_p->dai[j].ch_act) {
+ ret = tabla_close_slim_sch_tx(tabla,
+ tabla_p->dai[j].ch_num,
+ tabla_p->dai[j].ch_tot);
+ tabla_p->dai[j].rate = 0;
+ memset(tabla_p->dai[j].ch_num, 0, (sizeof(u32)*
+ tabla_p->dai[j].ch_tot));
+ tabla_p->dai[j].ch_tot = 0;
+ }
+ }
+ return ret;
+}
+
+/* Todo: Have seperate dapm widgets for I2S and Slimbus.
+ * Might Need to have callbacks registered only for slimbus
+ */
+static const struct snd_soc_dapm_widget tabla_dapm_widgets[] = {
+ /*RX stuff */
+ SND_SOC_DAPM_OUTPUT("EAR"),
+
+ SND_SOC_DAPM_PGA("EAR PA", TABLA_A_RX_EAR_EN, 4, 0, NULL, 0),
+
+ SND_SOC_DAPM_MIXER("DAC1", TABLA_A_RX_EAR_EN, 6, 0, dac1_switch,
+ ARRAY_SIZE(dac1_switch)),
+
+ SND_SOC_DAPM_AIF_IN_E("SLIM RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
+ 0, tabla_codec_enable_slimrx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_AIF_IN_E("SLIM RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
+ 0, tabla_codec_enable_slimrx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_AIF_IN("SLIM RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SLIM RX4", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+
+ /* Headphone */
+ SND_SOC_DAPM_OUTPUT("HEADPHONE"),
+ SND_SOC_DAPM_PGA_E("HPHL", TABLA_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
+ tabla_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER("HPHL DAC", TABLA_A_RX_HPH_L_DAC_CTL, 7, 0,
+ hphl_switch, ARRAY_SIZE(hphl_switch)),
+
+ SND_SOC_DAPM_PGA_E("HPHR", TABLA_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
+ tabla_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, TABLA_A_RX_HPH_R_DAC_CTL, 7, 0,
+ tabla_hphr_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ /* Speaker */
+ SND_SOC_DAPM_OUTPUT("LINEOUT1"),
+ SND_SOC_DAPM_OUTPUT("LINEOUT2"),
+ SND_SOC_DAPM_OUTPUT("LINEOUT3"),
+ SND_SOC_DAPM_OUTPUT("LINEOUT4"),
+ SND_SOC_DAPM_OUTPUT("LINEOUT5"),
+
+ SND_SOC_DAPM_PGA_E("LINEOUT1 PA", TABLA_A_RX_LINE_CNP_EN, 0, 0, NULL,
+ 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("LINEOUT2 PA", TABLA_A_RX_LINE_CNP_EN, 1, 0, NULL,
+ 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("LINEOUT3 PA", TABLA_A_RX_LINE_CNP_EN, 2, 0, NULL,
+ 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("LINEOUT4 PA", TABLA_A_RX_LINE_CNP_EN, 3, 0, NULL,
+ 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("LINEOUT5 PA", TABLA_A_RX_LINE_CNP_EN, 4, 0, NULL, 0,
+ tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL, TABLA_A_RX_LINE_1_DAC_CTL, 7, 0
+ , tabla_lineout_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_DAC_E("LINEOUT2 DAC", NULL, TABLA_A_RX_LINE_2_DAC_CTL, 7, 0
+ , tabla_lineout_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_DAC_E("LINEOUT3 DAC", NULL, TABLA_A_RX_LINE_3_DAC_CTL, 7, 0
+ , tabla_lineout_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SWITCH("LINEOUT3 DAC GROUND", SND_SOC_NOPM, 0, 0,
+ &lineout3_ground_switch),
+ SND_SOC_DAPM_DAC_E("LINEOUT4 DAC", NULL, TABLA_A_RX_LINE_4_DAC_CTL, 7, 0
+ , tabla_lineout_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SWITCH("LINEOUT4 DAC GROUND", SND_SOC_NOPM, 0, 0,
+ &lineout4_ground_switch),
+ SND_SOC_DAPM_DAC_E("LINEOUT5 DAC", NULL, TABLA_A_RX_LINE_5_DAC_CTL, 7, 0
+ , tabla_lineout_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MIXER_E("RX1 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
+ 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_MIXER_E("RX2 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
+ 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_MIXER_E("RX3 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
+ 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_MIXER_E("RX4 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
+ 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_MIXER_E("RX5 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 4, 0, NULL,
+ 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_MIXER_E("RX6 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0, NULL,
+ 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_MIXER_E("RX7 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 6, 0, NULL,
+ 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
+
+ SND_SOC_DAPM_MUX_E("RX4 DSM MUX", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0,
+ &rx4_dsm_mux, tabla_codec_reset_interpolator,
+ SND_SOC_DAPM_PRE_PMU),
+
+ SND_SOC_DAPM_MUX_E("RX6 DSM MUX", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0,
+ &rx6_dsm_mux, tabla_codec_reset_interpolator,
+ SND_SOC_DAPM_PRE_PMU),
+
+ SND_SOC_DAPM_MIXER("RX1 CHAIN", TABLA_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX2 CHAIN", TABLA_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
+
+ SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx_mix1_inp1_mux),
+ SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx_mix1_inp2_mux),
+ SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx2_mix1_inp1_mux),
+ SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx2_mix1_inp2_mux),
+ SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx3_mix1_inp1_mux),
+ SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx3_mix1_inp2_mux),
+ SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx4_mix1_inp1_mux),
+ SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx4_mix1_inp2_mux),
+ SND_SOC_DAPM_MUX("RX5 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx5_mix1_inp1_mux),
+ SND_SOC_DAPM_MUX("RX5 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx5_mix1_inp2_mux),
+ SND_SOC_DAPM_MUX("RX6 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx6_mix1_inp1_mux),
+ SND_SOC_DAPM_MUX("RX6 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx6_mix1_inp2_mux),
+ SND_SOC_DAPM_MUX("RX7 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx7_mix1_inp1_mux),
+ SND_SOC_DAPM_MUX("RX7 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx7_mix1_inp2_mux),
+
+ SND_SOC_DAPM_SUPPLY("CP", TABLA_A_CP_EN, 0, 0,
+ tabla_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
+ tabla_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ /* TX */
+
+ SND_SOC_DAPM_SUPPLY("CDC_CONN", TABLA_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
+ 0),
+
+ SND_SOC_DAPM_SUPPLY("LDO_H", TABLA_A_LDO_H_MODE_1, 7, 0,
+ tabla_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
+
+ SND_SOC_DAPM_INPUT("AMIC1"),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TABLA_A_MICB_1_CTL, 7, 0,
+ tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", TABLA_A_MICB_1_CTL, 7, 0,
+ tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", TABLA_A_MICB_1_CTL, 7, 0,
+ tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("ADC1", NULL, TABLA_A_TX_1_2_EN, 7, 0,
+ tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_INPUT("AMIC3"),
+ SND_SOC_DAPM_ADC_E("ADC3", NULL, TABLA_A_TX_3_4_EN, 7, 0,
+ tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_INPUT("AMIC4"),
+ SND_SOC_DAPM_ADC_E("ADC4", NULL, TABLA_A_TX_3_4_EN, 3, 0,
+ tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_INPUT("AMIC5"),
+ SND_SOC_DAPM_ADC_E("ADC5", NULL, TABLA_A_TX_5_6_EN, 7, 0,
+ tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
+
+ SND_SOC_DAPM_INPUT("AMIC6"),
+ SND_SOC_DAPM_ADC_E("ADC6", NULL, TABLA_A_TX_5_6_EN, 3, 0,
+ tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
+
+ SND_SOC_DAPM_MUX_E("DEC1 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
+ &dec1_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+
+ SND_SOC_DAPM_MUX_E("DEC2 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0,
+ &dec2_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+
+ SND_SOC_DAPM_MUX_E("DEC3 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 2, 0,
+ &dec3_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+
+ SND_SOC_DAPM_MUX_E("DEC4 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 3, 0,
+ &dec4_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+
+ SND_SOC_DAPM_MUX_E("DEC5 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 4, 0,
+ &dec5_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+
+ SND_SOC_DAPM_MUX_E("DEC6 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 5, 0,
+ &dec6_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+
+ SND_SOC_DAPM_MUX_E("DEC7 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 6, 0,
+ &dec7_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+
+ SND_SOC_DAPM_MUX_E("DEC8 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 7, 0,
+ &dec8_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+
+ SND_SOC_DAPM_MUX_E("DEC9 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL, 0, 0,
+ &dec9_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+
+ SND_SOC_DAPM_MUX_E("DEC10 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL, 1, 0,
+ &dec10_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+
+ SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
+ SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
+
+ SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
+ tabla_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
+
+ SND_SOC_DAPM_INPUT("AMIC2"),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TABLA_A_MICB_2_CTL, 7, 0,
+ tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", TABLA_A_MICB_2_CTL, 7, 0,
+ tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", TABLA_A_MICB_2_CTL, 7, 0,
+ tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", TABLA_A_MICB_2_CTL, 7, 0,
+ tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TABLA_A_MICB_3_CTL, 7, 0,
+ tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", TABLA_A_MICB_3_CTL, 7, 0,
+ tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", TABLA_A_MICB_3_CTL, 7, 0,
+ tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("ADC2", NULL, TABLA_A_TX_1_2_EN, 3, 0,
+ tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, 0, 0, &sb_tx1_mux),
+ SND_SOC_DAPM_AIF_OUT("SLIM TX1", "AIF1 Capture", NULL, SND_SOC_NOPM,
+ 0, 0),
+
+ SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, 0, 0, &sb_tx5_mux),
+ SND_SOC_DAPM_AIF_OUT("SLIM TX5", "AIF1 Capture", NULL, SND_SOC_NOPM,
+ 4, 0),
+
+ SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, 0, 0, &sb_tx6_mux),
+ SND_SOC_DAPM_AIF_OUT("SLIM TX6", "AIF1 Capture", NULL, SND_SOC_NOPM,
+ 5, 0),
+
+ SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, 0, 0, &sb_tx7_mux),
+ SND_SOC_DAPM_AIF_OUT_E("SLIM TX7", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
+ 0, tabla_codec_enable_slimtx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, 0, 0, &sb_tx8_mux),
+ SND_SOC_DAPM_AIF_OUT_E("SLIM TX8", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
+ 0, tabla_codec_enable_slimtx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("SLIM TX9 MUX", SND_SOC_NOPM, 0, 0, &sb_tx9_mux),
+ SND_SOC_DAPM_AIF_OUT_E("SLIM TX9", "AIF1 Capture", NULL, SND_SOC_NOPM,
+ 0, 0, tabla_codec_enable_slimtx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("SLIM TX10 MUX", SND_SOC_NOPM, 0, 0, &sb_tx10_mux),
+ SND_SOC_DAPM_AIF_OUT_E("SLIM TX10", "AIF1 Capture", NULL, SND_SOC_NOPM,
+ 0, 0, tabla_codec_enable_slimtx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ /* Digital Mic Inputs */
+ SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
+ tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
+ tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
+ tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
+ tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 0, 0,
+ tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("DMIC6", NULL, SND_SOC_NOPM, 0, 0,
+ tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ /* Sidetone */
+ SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
+ SND_SOC_DAPM_PGA("IIR1", TABLA_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
+};
+
static short tabla_codec_read_sta_result(struct snd_soc_codec *codec)
{
u8 bias_msb, bias_lsb;
@@ -4680,6 +4883,7 @@
struct snd_soc_dapm_context *dapm = &codec->dapm;
int ret = 0;
int i;
+ int ch_cnt;
codec->control_data = dev_get_drvdata(codec->dev->parent);
control = codec->control_data;
@@ -4831,6 +5035,20 @@
goto err_hphr_ocp_irq;
}
tabla_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPR_FAULT);
+ for (i = 0; i < ARRAY_SIZE(tabla_dai); i++) {
+ switch (tabla_dai[i].id) {
+ case AIF1_PB:
+ ch_cnt = tabla_dai[i].playback.channels_max;
+ break;
+ case AIF1_CAP:
+ ch_cnt = tabla_dai[i].capture.channels_max;
+ break;
+ default:
+ continue;
+ }
+ tabla->dai[i].ch_num = kzalloc((sizeof(unsigned int)*
+ ch_cnt), GFP_KERNEL);
+ }
#ifdef CONFIG_DEBUG_FS
debug_tabla_priv = tabla;
@@ -4857,6 +5075,7 @@
}
static int tabla_codec_remove(struct snd_soc_codec *codec)
{
+ int i;
struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
tabla_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
@@ -4867,6 +5086,8 @@
tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
if (tabla->mbhc_fw)
release_firmware(tabla->mbhc_fw);
+ for (i = 0; i < ARRAY_SIZE(tabla_dai); i++)
+ kfree(tabla->dai[i].ch_num);
kfree(tabla);
return 0;
}
diff --git a/sound/soc/codecs/wcd9310.h b/sound/soc/codecs/wcd9310.h
index 6ddc471..9c430b9 100644
--- a/sound/soc/codecs/wcd9310.h
+++ b/sound/soc/codecs/wcd9310.h
@@ -11,6 +11,7 @@
*/
#include <sound/soc.h>
#include <sound/jack.h>
+#include <linux/mfd/wcd9310/wcd9310-slimslave.h>
#define TABLA_NUM_REGISTERS 0x400
#define TABLA_MAX_REGISTER (TABLA_NUM_REGISTERS-1)
diff --git a/sound/soc/msm/apq8064.c b/sound/soc/msm/apq8064.c
index bd41e0b..b515090 100644
--- a/sound/soc/msm/apq8064.c
+++ b/sound/soc/msm/apq8064.c
@@ -671,6 +671,66 @@
return tabla_cal;
}
+static int msm_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;
+ int ret = 0;
+ unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
+ unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
+
+ pr_debug("%s: ch=%d\n", __func__,
+ msm_slim_0_rx_ch);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map\n", __func__);
+ goto end;
+ }
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
+ msm_slim_0_rx_ch, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map\n", __func__);
+ goto end;
+ }
+ ret = snd_soc_dai_set_channel_map(codec_dai, 0, 0,
+ msm_slim_0_rx_ch, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to set codec channel map\n",
+ __func__);
+ goto end;
+ }
+ } else {
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map\n", __func__);
+ goto end;
+ }
+ ret = snd_soc_dai_set_channel_map(cpu_dai,
+ msm_slim_0_tx_ch, tx_ch, 0 , 0);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map\n", __func__);
+ goto end;
+ }
+ ret = snd_soc_dai_set_channel_map(codec_dai,
+ msm_slim_0_tx_ch, tx_ch, 0, 0);
+ if (ret < 0) {
+ pr_err("%s: failed to set codec channel map\n",
+ __func__);
+ goto end;
+ }
+
+
+ }
+end:
+ return ret;
+}
+
static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
{
int err;
@@ -924,6 +984,7 @@
static struct snd_soc_ops msm_be_ops = {
.startup = msm_startup,
+ .hw_params = msm_hw_params,
.shutdown = msm_shutdown,
};
diff --git a/sound/soc/msm/msm-dai-q6.c b/sound/soc/msm/msm-dai-q6.c
index 0951795..aff87ae 100644
--- a/sound/soc/msm/msm-dai-q6.c
+++ b/sound/soc/msm/msm-dai-q6.c
@@ -211,81 +211,28 @@
struct snd_soc_dai *dai, int stream)
{
struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
- u8 pgd_la, inf_la;
- u16 *slave_port_mapping;
-
- memset(dai_data->port_config.slimbus.slave_port_mapping, 0,
- sizeof(dai_data->port_config.slimbus.slave_port_mapping));
dai_data->channels = params_channels(params);
-
- slave_port_mapping = dai_data->port_config.slimbus.slave_port_mapping;
-
- switch (dai_data->channels) {
- case 4:
- if (dai->id == SLIMBUS_0_TX) {
- slave_port_mapping[0] = 7;
- slave_port_mapping[1] = 8;
- slave_port_mapping[2] = 9;
- slave_port_mapping[3] = 10;
- } else {
- return -EINVAL;
- }
- break;
- case 3:
- if (dai->id == SLIMBUS_0_TX) {
- slave_port_mapping[0] = 7;
- slave_port_mapping[1] = 8;
- slave_port_mapping[2] = 9;
- } else {
- return -EINVAL;
- }
- break;
- case 2:
- if (dai->id == SLIMBUS_0_RX) {
- slave_port_mapping[0] = 1;
- slave_port_mapping[1] = 2;
- } else {
- slave_port_mapping[0] = 7;
- slave_port_mapping[1] = 8;
- }
- break;
- case 1:
- if (dai->id == SLIMBUS_0_RX)
- slave_port_mapping[0] = 1;
- else
- slave_port_mapping[0] = 7;
- break;
- default:
- return -EINVAL;
- break;
- }
dai_data->rate = params_rate(params);
- tabla_get_logical_addresses(&pgd_la, &inf_la);
dai_data->port_config.slimbus.slimbus_dev_id = AFE_SLIMBUS_DEVICE_1;
- dai_data->port_config.slimbus.slave_dev_pgd_la = pgd_la;
- dai_data->port_config.slimbus.slave_dev_intfdev_la = inf_la;
/* Q6 only supports 16 as now */
- dai_data->port_config.slimbus.bit_width = 16;
- dai_data->port_config.slimbus.data_format = 0;
- dai_data->port_config.slimbus.num_channels = dai_data->channels;
- dai_data->port_config.slimbus.reserved = 0;
+ dai_data->port_config.slim_sch.bit_width = 16;
+ dai_data->port_config.slim_sch.data_format = 0;
+ dai_data->port_config.slim_sch.num_channels = dai_data->channels;
+ dai_data->port_config.slim_sch.reserved = 0;
- dev_dbg(dai->dev, "slimbus_dev_id %hu slave_dev_pgd_la 0x%hx\n"
- "slave_dev_intfdev_la 0x%hx bit_width %hu data_format %hu\n"
- "num_channel %hu slave_port_mapping[0] %hu\n"
+ dev_dbg(dai->dev, "%s:slimbus_dev_id[%hu] bit_wd[%hu] format[%hu]\n"
+ "num_channel %hu slave_ch_mapping[0] %hu\n"
"slave_port_mapping[1] %hu slave_port_mapping[2] %hu\n"
- "sample_rate %d\n",
- dai_data->port_config.slimbus.slimbus_dev_id,
- dai_data->port_config.slimbus.slave_dev_pgd_la,
- dai_data->port_config.slimbus.slave_dev_intfdev_la,
- dai_data->port_config.slimbus.bit_width,
- dai_data->port_config.slimbus.data_format,
- dai_data->port_config.slimbus.num_channels,
- dai_data->port_config.slimbus.slave_port_mapping[0],
- dai_data->port_config.slimbus.slave_port_mapping[1],
- dai_data->port_config.slimbus.slave_port_mapping[2],
+ "sample_rate %d\n", __func__,
+ dai_data->port_config.slim_sch.slimbus_dev_id,
+ dai_data->port_config.slim_sch.bit_width,
+ dai_data->port_config.slim_sch.data_format,
+ dai_data->port_config.slim_sch.num_channels,
+ dai_data->port_config.slim_sch.slave_ch_mapping[0],
+ dai_data->port_config.slim_sch.slave_ch_mapping[1],
+ dai_data->port_config.slim_sch.slave_ch_mapping[2],
dai_data->rate);
return 0;
@@ -784,7 +731,8 @@
{
int rc = 0;
- dev_dbg(dai->dev, "enter %s, id = %d\n", __func__, dai->id);
+ dev_dbg(dai->dev, "enter %s, id = %d fmt[%d]\n", __func__,
+ dai->id, fmt);
switch (dai->id) {
case PRIMARY_I2S_TX:
case PRIMARY_I2S_RX:
@@ -801,12 +749,69 @@
return rc;
}
+static int msm_dai_q6_set_channel_map(struct snd_soc_dai *dai,
+ unsigned int tx_num, unsigned int *tx_slot,
+ unsigned int rx_num, unsigned int *rx_slot)
+
+{
+ int rc = 0;
+ struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+ unsigned int i = 0;
+
+ dev_dbg(dai->dev, "enter %s, id = %d\n", __func__,
+ dai->id);
+ if (!tx_slot && !rx_slot)
+ return -EINVAL;
+ switch (dai->id) {
+ case SLIMBUS_0_RX:
+ /* channel number to be between 128 and 255. For RX port
+ * use channel numbers from 138 to 144, for TX port
+ * use channel numbers from 128 to 137
+ */
+ for (i = 0; i < rx_num; i++) {
+ dai_data->port_config.slim_sch.slave_ch_mapping[i] =
+ rx_slot[i];
+ pr_debug("%s: find number of channels[%d] ch[%d]\n",
+ __func__, i,
+ rx_slot[i]);
+ }
+ dai_data->port_config.slim_sch.num_channels = rx_num;
+ pr_debug("%s:SLIMBUS_0_RX cnt[%d] ch[%d %d]\n", __func__,
+ rx_num, dai_data->port_config.slim_sch.slave_ch_mapping[0],
+ dai_data->port_config.slim_sch.slave_ch_mapping[1]);
+
+ break;
+ case SLIMBUS_0_TX:
+ /* channel number to be between 128 and 255. For RX port
+ * use channel numbers from 138 to 144, for TX port
+ * use channel numbers from 128 to 137
+ */
+ for (i = 0; i < tx_num; i++) {
+ dai_data->port_config.slim_sch.slave_ch_mapping[i] =
+ tx_slot[i];
+ pr_debug("%s: find number of channels[%d] ch[%d]\n",
+ __func__, i, tx_slot[i]);
+ }
+ dai_data->port_config.slim_sch.num_channels = tx_num;
+ pr_debug("%s:SLIMBUS_0_TX cnt[%d] ch[%d %d]\n", __func__,
+ tx_num, dai_data->port_config.slim_sch.slave_ch_mapping[0],
+ dai_data->port_config.slim_sch.slave_ch_mapping[1]);
+ break;
+ default:
+ dev_err(dai->dev, "invalid cpu_dai set_fmt\n");
+ rc = -EINVAL;
+ break;
+ }
+ return rc;
+}
+
static struct snd_soc_dai_ops msm_dai_q6_ops = {
.prepare = msm_dai_q6_prepare,
.trigger = msm_dai_q6_trigger,
.hw_params = msm_dai_q6_hw_params,
.shutdown = msm_dai_q6_shutdown,
.set_fmt = msm_dai_q6_set_fmt,
+ .set_channel_map = msm_dai_q6_set_channel_map,
};
static struct snd_soc_dai_ops msm_dai_q6_auxpcm_ops = {
diff --git a/sound/soc/msm/msm8960.c b/sound/soc/msm/msm8960.c
index 1ed73e2..bedfd68 100644
--- a/sound/soc/msm/msm8960.c
+++ b/sound/soc/msm/msm8960.c
@@ -643,6 +643,66 @@
return tabla_cal;
}
+static int msm8960_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;
+ int ret = 0;
+ unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
+ unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
+
+ pr_debug("%s: ch=%d\n", __func__,
+ msm8960_slim_0_rx_ch);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map\n", __func__);
+ goto end;
+ }
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
+ msm8960_slim_0_rx_ch, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map\n", __func__);
+ goto end;
+ }
+ ret = snd_soc_dai_set_channel_map(codec_dai, 0, 0,
+ msm8960_slim_0_rx_ch, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to set codec channel map\n",
+ __func__);
+ goto end;
+ }
+ } else {
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map\n", __func__);
+ goto end;
+ }
+ ret = snd_soc_dai_set_channel_map(cpu_dai,
+ msm8960_slim_0_tx_ch, tx_ch, 0 , 0);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map\n", __func__);
+ goto end;
+ }
+ ret = snd_soc_dai_set_channel_map(codec_dai,
+ msm8960_slim_0_tx_ch, tx_ch, 0, 0);
+ if (ret < 0) {
+ pr_err("%s: failed to set codec channel map\n",
+ __func__);
+ goto end;
+ }
+
+
+ }
+end:
+ return ret;
+}
+
static int msm8960_audrx_init(struct snd_soc_pcm_runtime *rtd)
{
int err;
@@ -914,6 +974,7 @@
static struct snd_soc_ops msm8960_be_ops = {
.startup = msm8960_startup,
+ .hw_params = msm8960_hw_params,
.shutdown = msm8960_shutdown,
};
diff --git a/sound/soc/msm/qdsp6/q6afe.c b/sound/soc/msm/qdsp6/q6afe.c
index ef01fb3..59506f1 100644
--- a/sound/soc/msm/qdsp6/q6afe.c
+++ b/sound/soc/msm/qdsp6/q6afe.c
@@ -78,6 +78,7 @@
switch (payload[0]) {
case AFE_PORT_AUDIO_IF_CONFIG:
case AFE_PORT_MULTI_CHAN_HDMI_AUDIO_IF_CONFIG:
+ case AFE_PORT_AUDIO_SLIM_SCH_CONFIG:
case AFE_PORT_CMD_STOP:
case AFE_PORT_CMD_START:
case AFE_PORT_CMD_LOOPBACK:
@@ -285,7 +286,7 @@
break;
case SLIMBUS_0_RX:
case SLIMBUS_0_TX:
- ret_size = SIZEOF_CFG_CMD(afe_port_slimbus_cfg);
+ ret_size = SIZEOF_CFG_CMD(afe_port_slimbus_sch_cfg);
break;
case RT_PROXY_PORT_001_RX:
case RT_PROXY_PORT_001_TX:
@@ -418,7 +419,23 @@
config.hdr.src_port = 0;
config.hdr.dest_port = 0;
config.hdr.token = 0;
- config.hdr.opcode = AFE_PORT_AUDIO_IF_CONFIG;
+ switch (port_id) {
+ case SLIMBUS_0_RX:
+ case SLIMBUS_0_TX:
+ case SLIMBUS_1_RX:
+ case SLIMBUS_1_TX:
+ case SLIMBUS_2_RX:
+ case SLIMBUS_2_TX:
+ case SLIMBUS_3_RX:
+ case SLIMBUS_3_TX:
+ case SLIMBUS_4_RX:
+ case SLIMBUS_4_TX:
+ config.hdr.opcode = AFE_PORT_AUDIO_SLIM_SCH_CONFIG;
+ break;
+ default:
+ config.hdr.opcode = AFE_PORT_AUDIO_IF_CONFIG;
+ break;
+ }
}
if (afe_validate_port(port_id) < 0) {
@@ -485,7 +502,7 @@
return ret;
}
- pr_info("%s: %d %d\n", __func__, port_id, rate);
+ pr_debug("%s: %d %d\n", __func__, port_id, rate);
if ((port_id == RT_PROXY_DAI_001_RX) ||
(port_id == RT_PROXY_DAI_002_TX))
@@ -793,7 +810,7 @@
int ret = 0;
struct afe_pseudoport_start_command start;
- pr_info("%s: port_id=%d\n", __func__, port_id);
+ pr_debug("%s: port_id=%d\n", __func__, port_id);
ret = afe_q6_interface_prepare();
if (ret != 0)
@@ -866,7 +883,7 @@
int ret = 0;
struct afe_pseudoport_stop_command stop;
- pr_info("%s: port_id=%d\n", __func__, port_id);
+ pr_debug("%s: port_id=%d\n", __func__, port_id);
if (this_afe.apr == NULL) {
pr_err("%s: AFE is already closed\n", __func__);
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 219ae10..d528f4b 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -3673,6 +3673,29 @@
EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map);
/**
+ * snd_soc_dai_get_channel_map - configure DAI audio channel map
+ * @dai: DAI
+ * @tx_num: how many TX channels
+ * @tx_slot: pointer to an array which imply the TX slot number channel
+ * 0~num-1 uses
+ * @rx_num: how many RX channels
+ * @rx_slot: pointer to an array which imply the RX slot number channel
+ * 0~num-1 uses
+ *
+ * configure the relationship between channel number and TDM slot number.
+ */
+int snd_soc_dai_get_channel_map(struct snd_soc_dai *dai,
+ unsigned int *tx_num, unsigned int *tx_slot,
+ unsigned int *rx_num, unsigned int *rx_slot)
+{
+ if (dai->driver && dai->driver->ops->get_channel_map)
+ return dai->driver->ops->get_channel_map(dai, tx_num, tx_slot,
+ rx_num, rx_slot);
+ else
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_get_channel_map);
+/**
* snd_soc_dai_set_tristate - configure DAI system or master clock.
* @dai: DAI
* @tristate: tristate enable
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index b462639..c03f7ca7 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -2,6 +2,7 @@
* soc-dapm.c -- ALSA SoC Dynamic Audio Power Management
*
* Copyright 2005 Wolfson Microelectronics PLC.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* Author: Liam Girdwood <lrg@slimlogic.co.uk>
*
@@ -59,8 +60,6 @@
[snd_soc_dapm_pre] = 0,
[snd_soc_dapm_supply] = 1,
[snd_soc_dapm_micbias] = 2,
- [snd_soc_dapm_aif_in] = 3,
- [snd_soc_dapm_aif_out] = 3,
[snd_soc_dapm_mic] = 4,
[snd_soc_dapm_mux] = 5,
[snd_soc_dapm_virt_mux] = 5,
@@ -69,6 +68,8 @@
[snd_soc_dapm_mixer] = 7,
[snd_soc_dapm_mixer_named_ctl] = 7,
[snd_soc_dapm_pga] = 8,
+ [snd_soc_dapm_aif_in] = 8,
+ [snd_soc_dapm_aif_out] = 8,
[snd_soc_dapm_adc] = 9,
[snd_soc_dapm_out_drv] = 10,
[snd_soc_dapm_hp] = 10,
@@ -78,6 +79,8 @@
static int dapm_down_seq[] = {
[snd_soc_dapm_pre] = 0,
+ [snd_soc_dapm_aif_in] = 1,
+ [snd_soc_dapm_aif_out] = 1,
[snd_soc_dapm_adc] = 1,
[snd_soc_dapm_hp] = 2,
[snd_soc_dapm_spk] = 2,
@@ -91,8 +94,6 @@
[snd_soc_dapm_mux] = 9,
[snd_soc_dapm_virt_mux] = 9,
[snd_soc_dapm_value_mux] = 9,
- [snd_soc_dapm_aif_in] = 10,
- [snd_soc_dapm_aif_out] = 10,
[snd_soc_dapm_supply] = 11,
[snd_soc_dapm_post] = 12,
};