Merge "power: qpnp-charger: add VCP workaround"
diff --git a/Documentation/devicetree/bindings/pil/pil-mba.txt b/Documentation/devicetree/bindings/pil/pil-mba.txt
index 9692059..ce6bb8f 100644
--- a/Documentation/devicetree/bindings/pil/pil-mba.txt
+++ b/Documentation/devicetree/bindings/pil/pil-mba.txt
@@ -12,6 +12,7 @@
the primary modem image metadata should be stored.
- reg-names: Names for the above base addresses. "rmb_base" and
"metadata_base" are expected.
+- interrupts: The modem watchdog interrupt
- qcom,firmware-name: Base name of the firmware image. Ex. "modem"
Optional properties:
@@ -24,6 +25,7 @@
reg = <0xfc820000 0x0020>,
<0x0d1f0000 0x4000>;
reg-names = "rmb_base", "metadata_base";
+ interrupts = <0 56 1>;
qcom,firmware-name = "modem";
qcom,depends-on = "mba";
diff --git a/Documentation/devicetree/bindings/pil/pil-pronto.txt b/Documentation/devicetree/bindings/pil/pil-pronto.txt
index e123bdb..e3108ac 100644
--- a/Documentation/devicetree/bindings/pil/pil-pronto.txt
+++ b/Documentation/devicetree/bindings/pil/pil-pronto.txt
@@ -10,6 +10,7 @@
- reg: offset and length of the register set for the device.
- reg-names: names of the bases for the above registers. "pmu_base", "clk_base",
and "halt_base" are expected.
+- interrupts: WCNSS to Apps watchdog bite interrupt
- vdd_pronto_pll-supply: regulator to supply pronto pll.
- qcom,firmware-name: Base name of the firmware image. Ex. "wcnss"
@@ -21,6 +22,7 @@
<0xfd485300 0xc>;
reg-names = "pmu_base", "clk_base", "halt_base";
vdd_pronto_pll-supply = <&pm8941_l12>;
+ interrupts = <0 231 1>;
qcom,firmware-name = "wcnss";
};
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
index d39c98c..ac9600d 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
@@ -11,6 +11,7 @@
memory mapped registers.
- reg-names: Names of the bases for the above registers. "qdsp6_base"
and "halt_base" are expected.
+- interrupts: The lpass watchdog interrupt
- qcom,firmware-name: Base name of the firmware image. Ex. "lpass"
Example:
@@ -19,6 +20,7 @@
reg = <0xfe200000 0x00100>,
<0xfd485100 0x00010>;
reg-names = "qdsp6_base", "halt_base";
+ interrupts = <0 194 1>;
qcom,firmware-name = "lpass";
};
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index cb2c1e1..5df0101 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -71,6 +71,7 @@
Value is from 16384 to 16393
BT SCO port ID value from 12288 to 12289
RT Proxy port ID values from 224 to 225 and 240 to 241
+ FM Rx and TX port ID values from 12292 to 12293
* msm-auxpcm
@@ -206,6 +207,16 @@
qcom,msm-dai-q6-dev-id = <12289>;
};
+ qcom,msm-dai-q6-int-fm-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <12292>;
+ };
+
+ qcom,msm-dai-q6-int-fm-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <12293>;
+ };
+
qcom,msm-dai-q6-be-afe-pcm-rx {
compatible = "qcom,msm-dai-q6-dev";
qcom,msm-dai-q6-dev-id = <224>;
diff --git a/arch/arm/boot/dts/msm8974-cdp.dts b/arch/arm/boot/dts/msm8974-cdp.dts
index 05fcc4f..0e0f6cf 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dts
+++ b/arch/arm/boot/dts/msm8974-cdp.dts
@@ -30,6 +30,10 @@
};
};
+ qcom,hdmi_tx@fd922100 {
+ status = "ok";
+ };
+
i2c@f9924000 {
atmel_mxt_ts@4a {
compatible = "atmel,mxt-ts";
diff --git a/arch/arm/boot/dts/msm8974-fluid.dts b/arch/arm/boot/dts/msm8974-fluid.dts
index b1d467e..3a7c19d 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dts
+++ b/arch/arm/boot/dts/msm8974-fluid.dts
@@ -30,6 +30,10 @@
};
};
+ qcom,hdmi_tx@fd922100 {
+ status = "ok";
+ };
+
i2c@f9924000 {
atmel_mxt_ts@4a {
compatible = "atmel,mxt-ts";
diff --git a/arch/arm/boot/dts/msm8974-liquid.dts b/arch/arm/boot/dts/msm8974-liquid.dts
index bf4adaf..bc682ea 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dts
+++ b/arch/arm/boot/dts/msm8974-liquid.dts
@@ -54,6 +54,10 @@
debounce-interval = <15>;
};
};
+
+ qcom,hdmi_tx@fd922100 {
+ status = "ok";
+ };
};
&pm8941_gpios {
diff --git a/arch/arm/boot/dts/msm8974-mtp.dts b/arch/arm/boot/dts/msm8974-mtp.dts
index e0d6ad3..ceb4f83 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dts
+++ b/arch/arm/boot/dts/msm8974-mtp.dts
@@ -30,6 +30,10 @@
};
};
+ qcom,hdmi_tx@fd922100 {
+ status = "disabled";
+ };
+
i2c@f9924000 {
atmel_mxt_ts@4a {
compatible = "atmel,mxt-ts";
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index a445a81..6a3add8 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -659,6 +659,7 @@
reg = <0xfe200000 0x00100>,
<0xfd485100 0x00010>;
reg-names = "qdsp6_base", "halt_base";
+ interrupts = <0 194 1>;
qcom,firmware-name = "adsp";
};
@@ -725,6 +726,16 @@
qcom,msm-dai-q6-dev-id = <12289>;
};
+ qcom,msm-dai-q6-int-fm-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <12292>;
+ };
+
+ qcom,msm-dai-q6-int-fm-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <12293>;
+ };
+
qcom,msm-dai-q6-be-afe-pcm-rx {
compatible = "qcom,msm-dai-q6-dev";
qcom,msm-dai-q6-dev-id = <224>;
@@ -804,6 +815,7 @@
reg = <0xfc820000 0x0020>,
<0x0d1fc000 0x4000>;
reg-names = "rmb_base", "metadata_base";
+ interrupts = <0 56 1>;
qcom,firmware-name = "modem";
qcom,depends-on = "mba";
@@ -815,6 +827,7 @@
<0xfc401700 0x4>,
<0xfd485300 0xc>;
reg-names = "pmu_base", "clk_base", "halt_base";
+ interrupts = <0 181 1>;
vdd_pronto_pll-supply = <&pm8941_l12>;
qcom,firmware-name = "wcnss";
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index cdc435c..7ee0eb2 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -1958,11 +1958,13 @@
If unsure, say N.
config MSM_PIL_LPASS_QDSP6V5
- tristate "LPASS QDSP6v5 (Hexagon) Boot Support"
- depends on MSM_PIL
- help
- Support for booting and shutting down QDSP6v5 (Hexagon) processors
- in low power audio subsystems.
+ tristate "LPASS QDSP6v5 (Hexagon) Boot Support"
+ depends on MSM_PIL && MSM_SUBSYSTEM_RESTART
+ help
+ Support for booting and shutting down QDSP6v5 (Hexagon) processors
+ in low power audio subsystems. This driver also monitors the ADSP
+ SMSM status bits and the ADSP's watchdog interrupt and restarts the
+ ADSP if the processor encounters a fatal error.
config MSM_PIL_MSS_QDSP6V5
tristate "MSS QDSP6v5 (Hexagon) Boot Support"
@@ -1973,7 +1975,7 @@
config MSM_PIL_MBA
tristate "Support for modem self-authentication"
- depends on MSM_PIL_MSS_QDSP6V5
+ depends on MSM_PIL_MSS_QDSP6V5 && MSM_SUBSYSTEM_RESTART
help
Support for booting self-authenticating modems using the Modem Boot
Authenticator.
@@ -1998,7 +2000,7 @@
config MSM_PIL_DSPS
tristate "DSPS Boot Support"
- depends on MSM_PIL
+ depends on MSM_PIL && MSM_SUBSYSTEM_RESTART
help
Support for booting and shutting down ARM7 DSPS processors.
@@ -2027,7 +2029,7 @@
config MSM_PIL_PRONTO
tristate "PRONTO (WCNSS) Boot Support"
- depends on MSM_PIL
+ depends on MSM_PIL && MSM_SUBSYSTEM_RESTART
help
Support for booting and shutting down the PRONTO processor (WCNSS).
PRONTO is the wireless subsystem processor used in bluetooth, wireless
@@ -2037,33 +2039,6 @@
bool "Secure Channel Manager (SCM) support"
default n
-config MSM_MODEM_SSR_8974
- bool "MSM 8974 Modem restart driver"
- depends on (ARCH_MSM8974)
- help
- This option enables the modem subsystem restart driver for the MSM8974.
- It monitors the modem SMSM status bits and the modem watchdog line and
- restarts the modem or the 8974 when the modem encounters a fatal error,
- depending on the restart level selected in the subsystem restart driver.
-
-config MSM_ADSP_SSR_8974
- bool "MSM 8974 adsp restart driver"
- depends on (ARCH_MSM8974)
- help
- This option enables the adsp restart driver for the MSM8974.
- It monitors the adsp SMSM status bits and the adsp watchdog line and
- restarts the adsp or the 8974 when the adsp encounters a fatal error,
- depending on the restart level selected in the subsystem restart driver.
-
-config MSM_WCNSS_SSR_8974
- tristate "MSM 8974 WCNSS restart module"
- depends on (ARCH_MSM8974)
- help
- This option enables the WCNSS restart module for MSM8974. It monitors
- WCNSS SMSM status bits and WCNSS hardware watchdog interrupt line; and
- depending on the restart level, it will restart WCNSS when a fatal error
- occurs at WCNSS.
-
config SCORPION_Uni_45nm_BUG
bool "Scorpion Uni 45nm(SC45U): Workaround for ICIMVAU and BPIMVA"
depends on ARCH_MSM7X30 || (ARCH_QSD8X50 && MSM_SOC_REV_A)
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 5f6d1d8..f073e70 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -24,6 +24,9 @@
obj-y += acpuclock.o
obj-$(CONFIG_ARCH_MSM_KRAIT) += acpuclock-krait.o
+ifdef CONFIG_ARCH_MSM_KRAIT
+obj-$(CONFIG_DEBUG_FS) += acpuclock-krait-debug.o
+endif
obj-$(CONFIG_ARCH_MSM7X27) += acpuclock-7627.o clock-pll.o
obj-$(CONFIG_ARCH_MSM_SCORPION) += pmu.o
obj-$(CONFIG_ARCH_MSM_SCORPIONMP) += perf_event_msm_l2.o
@@ -204,9 +207,6 @@
obj-y += ramdump.o
endif
obj-$(CONFIG_MSM_SYSMON_COMM) += sysmon.o
-obj-$(CONFIG_MSM_MODEM_SSR_8974) += modem-ssr-8974.o
-obj-$(CONFIG_MSM_ADSP_SSR_8974) += adsp-8974.o
-obj-$(CONFIG_MSM_WCNSS_SSR_8974) += wcnss-ssr-8974.o
ifdef CONFIG_CPU_IDLE
obj-$(CONFIG_ARCH_APQ8064) += cpuidle.o
diff --git a/arch/arm/mach-msm/acpuclock-krait-debug.c b/arch/arm/mach-msm/acpuclock-krait-debug.c
new file mode 100644
index 0000000..0ab70b4
--- /dev/null
+++ b/arch/arm/mach-msm/acpuclock-krait-debug.c
@@ -0,0 +1,335 @@
+/*
+ * Copyright (c) 2012, The Linux Foundation. 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.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/cpu.h>
+#include <linux/smp.h>
+
+#include <mach/msm_bus.h>
+#include <mach/msm-krait-l2-accessors.h>
+
+#include "acpuclock-krait.h"
+
+static struct drv_data *drv;
+static DEFINE_MUTEX(debug_lock);
+
+struct acg_action {
+ bool set;
+ bool enable;
+};
+static int l2_acg_en_val[MAX_SCALABLES];
+static struct dentry *base_dir;
+static struct dentry *sc_dir[MAX_SCALABLES];
+
+static void cpu_action(void *info)
+{
+ struct acg_action *action = info;
+
+ u32 val;
+ asm volatile ("mrc p15, 7, %[cpmr0], c15, c0, 5\n\t"
+ : [cpmr0]"=r" (val));
+ if (action->set) {
+ if (action->enable)
+ val &= ~BIT(0);
+ else
+ val |= BIT(0);
+ asm volatile ("mcr p15, 7, %[l2cpdr], c15, c0, 5\n\t"
+ : : [l2cpdr]"r" (val));
+ } else {
+ action->enable = !(val & BIT(0));
+ }
+}
+
+/* Disable auto clock-gating for a scalable. */
+static void disable_acg(int sc_id)
+{
+ u32 regval;
+
+ if (sc_id == L2) {
+ regval = get_l2_indirect_reg(drv->scalable[sc_id].l2cpmr_iaddr);
+ l2_acg_en_val[sc_id] = regval & (0x3 << 10);
+ regval |= (0x3 << 10);
+ set_l2_indirect_reg(drv->scalable[sc_id].l2cpmr_iaddr, regval);
+ } else {
+ struct acg_action action = { .set = true, .enable = false };
+ smp_call_function_single(sc_id, cpu_action, &action, 1);
+ }
+}
+
+/* Enable auto clock-gating for a scalable. */
+static void enable_acg(int sc_id)
+{
+ u32 regval;
+
+ if (sc_id == L2) {
+ regval = get_l2_indirect_reg(drv->scalable[sc_id].l2cpmr_iaddr);
+ regval &= ~(0x3 << 10);
+ regval |= l2_acg_en_val[sc_id];
+ set_l2_indirect_reg(drv->scalable[sc_id].l2cpmr_iaddr, regval);
+ } else {
+ struct acg_action action = { .set = true, .enable = true };
+ smp_call_function_single(sc_id, cpu_action, &action, 1);
+ }
+}
+
+/* Check if auto clock-gating for a scalable. */
+static bool acg_is_enabled(int sc_id)
+{
+ u32 regval;
+
+ if (sc_id == L2) {
+ regval = get_l2_indirect_reg(drv->scalable[sc_id].l2cpmr_iaddr);
+ return ((regval >> 10) & 0x3) != 0x3;
+ } else {
+ struct acg_action action = { .set = false };
+ smp_call_function_single(sc_id, cpu_action, &action, 1);
+ return action.enable;
+ }
+}
+
+/* Enable/Disable auto clock gating. */
+static int acg_set(void *data, u64 val)
+{
+ int ret = 0;
+ int sc_id = (int)data;
+
+ mutex_lock(&debug_lock);
+ get_online_cpus();
+ if (!sc_dir[sc_id]) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ if (val == 0 && acg_is_enabled(sc_id))
+ disable_acg(sc_id);
+ else if (val == 1)
+ enable_acg(sc_id);
+out:
+ put_online_cpus();
+ mutex_unlock(&debug_lock);
+
+ return ret;
+}
+
+/* Get auto clock-gating state. */
+static int acg_get(void *data, u64 *val)
+{
+ int ret = 0;
+ int sc_id = (int)data;
+
+ mutex_lock(&debug_lock);
+ get_online_cpus();
+ if (!sc_dir[sc_id]) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ *val = acg_is_enabled(sc_id);
+out:
+ put_online_cpus();
+ mutex_unlock(&debug_lock);
+
+ return ret;
+}
+DEFINE_SIMPLE_ATTRIBUTE(acgd_fops, acg_get, acg_set, "%lld\n");
+
+/* Get the rate */
+static int rate_get(void *data, u64 *val)
+{
+ int sc_id = (int)data;
+ *val = drv->scalable[sc_id].cur_speed->khz;
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(rate_fops, rate_get, NULL, "%lld\n");
+
+/* Get the HFPLL's L-value. */
+static int hfpll_l_get(void *data, u64 *val)
+{
+ int sc_id = (int)data;
+ *val = drv->scalable[sc_id].cur_speed->pll_l_val;
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(hfpll_l_fops, hfpll_l_get, NULL, "%lld\n");
+
+/* Get the L2 rate vote. */
+static int l2_vote_get(void *data, u64 *val)
+{
+ int level, sc_id = (int)data;
+
+ level = drv->scalable[sc_id].l2_vote;
+ *val = drv->l2_freq_tbl[level].speed.khz;
+
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(l2_vote_fops, l2_vote_get, NULL, "%lld\n");
+
+/* Get the bandwidth vote. */
+static int bw_vote_get(void *data, u64 *val)
+{
+ struct l2_level *l;
+
+ l = container_of(drv->scalable[L2].cur_speed,
+ struct l2_level, speed);
+ *val = drv->bus_scale->usecase[l->bw_level].vectors->ib;
+
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(bw_vote_fops, bw_vote_get, NULL, "%lld\n");
+
+/* Get the name of the currently-selected clock source. */
+static int src_name_show(struct seq_file *m, void *unused)
+{
+ const char *const src_names[NUM_SRC_ID] = {
+ [PLL_0] = "PLL0",
+ [HFPLL] = "HFPLL",
+ [PLL_8] = "PLL8",
+ };
+ int src, sc_id = (int)m->private;
+
+ src = drv->scalable[sc_id].cur_speed->src;
+ if (src > ARRAY_SIZE(src_names))
+ return -EINVAL;
+
+ seq_printf(m, "%s\n", src_names[src]);
+
+ return 0;
+}
+
+static int src_name_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, src_name_show, inode->i_private);
+}
+
+static const struct file_operations src_name_fops = {
+ .open = src_name_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+/* Get speed_bin ID */
+static int speed_bin_get(void *data, u64 *val)
+{
+ *val = drv->speed_bin;
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(speed_bin_fops, speed_bin_get, NULL, "%lld\n");
+
+/* Get pvs_bin ID */
+static int pvs_bin_get(void *data, u64 *val)
+{
+ *val = drv->pvs_bin;
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(pvs_bin_fops, pvs_bin_get, NULL, "%lld\n");
+
+/* Get boost_uv */
+static int boost_get(void *data, u64 *val)
+{
+ *val = drv->boost_uv;
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(boost_fops, boost_get, NULL, "%lld\n");
+
+static void __cpuinit add_scalable_dir(int sc_id)
+{
+ char sc_name[8];
+
+ if (sc_id == L2)
+ snprintf(sc_name, sizeof(sc_name), "l2");
+ else
+ snprintf(sc_name, sizeof(sc_name), "cpu%d", sc_id);
+
+ sc_dir[sc_id] = debugfs_create_dir(sc_name, base_dir);
+ if (!sc_dir[sc_id])
+ return;
+
+ debugfs_create_file("auto_gating", S_IRUGO | S_IWUSR,
+ sc_dir[sc_id], (void *)sc_id, &acgd_fops);
+
+ debugfs_create_file("rate", S_IRUGO,
+ sc_dir[sc_id], (void *)sc_id, &rate_fops);
+
+ debugfs_create_file("hfpll_l", S_IRUGO,
+ sc_dir[sc_id], (void *)sc_id, &hfpll_l_fops);
+
+ debugfs_create_file("src", S_IRUGO,
+ sc_dir[sc_id], (void *)sc_id, &src_name_fops);
+
+ if (sc_id == L2)
+ debugfs_create_file("bw_ib_vote", S_IRUGO,
+ sc_dir[sc_id], (void *)sc_id, &bw_vote_fops);
+ else
+ debugfs_create_file("l2_vote", S_IRUGO,
+ sc_dir[sc_id], (void *)sc_id, &l2_vote_fops);
+}
+
+static void __cpuinit remove_scalable_dir(int sc_id)
+{
+ debugfs_remove_recursive(sc_dir[sc_id]);
+ sc_dir[sc_id] = NULL;
+}
+
+static int __cpuinit debug_cpu_callback(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
+{
+ int cpu = (int)hcpu;
+
+ switch (action & ~CPU_TASKS_FROZEN) {
+ case CPU_DOWN_FAILED:
+ case CPU_UP_PREPARE:
+ add_scalable_dir(cpu);
+ break;
+ case CPU_UP_CANCELED:
+ case CPU_DOWN_PREPARE:
+ remove_scalable_dir(cpu);
+ break;
+ default:
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata debug_cpu_notifier = {
+ .notifier_call = debug_cpu_callback,
+};
+
+void __init acpuclk_krait_debug_init(struct drv_data *drv_data)
+{
+ int cpu;
+ drv = drv_data;
+
+ base_dir = debugfs_create_dir("acpuclk", NULL);
+ if (!base_dir)
+ return;
+
+ debugfs_create_file("speed_bin", S_IRUGO, base_dir, NULL,
+ &speed_bin_fops);
+ debugfs_create_file("pvs_bin", S_IRUGO, base_dir, NULL, &pvs_bin_fops);
+ debugfs_create_file("boost_uv", S_IRUGO, base_dir, NULL, &boost_fops);
+
+ for_each_online_cpu(cpu)
+ add_scalable_dir(cpu);
+ add_scalable_dir(L2);
+
+ register_hotcpu_notifier(&debug_cpu_notifier);
+}
diff --git a/arch/arm/mach-msm/acpuclock-krait.c b/arch/arm/mach-msm/acpuclock-krait.c
index 57c4411..d38396d 100644
--- a/arch/arm/mach-msm/acpuclock-krait.c
+++ b/arch/arm/mach-msm/acpuclock-krait.c
@@ -48,16 +48,7 @@
static DEFINE_MUTEX(driver_lock);
static DEFINE_SPINLOCK(l2_lock);
-static struct drv_data {
- struct acpu_level *acpu_freq_tbl;
- const struct l2_level *l2_freq_tbl;
- struct scalable *scalable;
- struct hfpll_data *hfpll_data;
- u32 bus_perf_client;
- struct msm_bus_scale_pdata *bus_scale;
- int boost_uv;
- struct device *dev;
-} drv;
+static struct drv_data drv;
static unsigned long acpuclk_krait_get_rate(int cpu)
{
@@ -986,7 +977,7 @@
struct pvs_table (*pvs_tables)[NUM_PVS])
{
void __iomem *pte_efuse;
- u32 pte_efuse_val, tbl_idx, bin_idx;
+ u32 pte_efuse_val;
pte_efuse = ioremap(pte_efuse_phys, 4);
if (!pte_efuse) {
@@ -998,10 +989,10 @@
iounmap(pte_efuse);
/* Select frequency tables. */
- bin_idx = get_speed_bin(pte_efuse_val);
- tbl_idx = get_pvs_bin(pte_efuse_val);
+ drv.speed_bin = get_speed_bin(pte_efuse_val);
+ drv.pvs_bin = get_pvs_bin(pte_efuse_val);
- return &pvs_tables[bin_idx][tbl_idx];
+ return &pvs_tables[drv.speed_bin][drv.pvs_bin];
}
static void __init drv_data_init(struct device *dev,
@@ -1091,5 +1082,7 @@
acpuclk_register(&acpuclk_krait_data);
register_hotcpu_notifier(&acpuclk_cpu_notifier);
+ acpuclk_krait_debug_init(&drv);
+
return 0;
}
diff --git a/arch/arm/mach-msm/acpuclock-krait.h b/arch/arm/mach-msm/acpuclock-krait.h
index 3fa10e3..245f276 100644
--- a/arch/arm/mach-msm/acpuclock-krait.h
+++ b/arch/arm/mach-msm/acpuclock-krait.h
@@ -39,6 +39,7 @@
PLL_0 = 0,
HFPLL,
PLL_8,
+ NUM_SRC_ID
};
/**
@@ -66,6 +67,7 @@
CPU2,
CPU3,
L2,
+ MAX_SCALABLES
};
@@ -261,6 +263,32 @@
};
/**
+ * struct drv_data - Driver state
+ * @acpu_freq_tbl: CPU frequency table.
+ * @l2_freq_tbl: L2 frequency table.
+ * @scalable: Array of scalables (CPUs and L2).
+ * @hfpll_data: High-frequency PLL data.
+ * @bus_perf_client: Bus driver client handle.
+ * @bus_scale: Bus driver scaling data.
+ * @boost_uv: Voltage boost amount
+ * @speed_bin: Speed bin ID.
+ * @pvs_bin: PVS bin ID.
+ * @dev: Device.
+ */
+struct drv_data {
+ struct acpu_level *acpu_freq_tbl;
+ const struct l2_level *l2_freq_tbl;
+ struct scalable *scalable;
+ struct hfpll_data *hfpll_data;
+ u32 bus_perf_client;
+ struct msm_bus_scale_pdata *bus_scale;
+ int boost_uv;
+ int speed_bin;
+ int pvs_bin;
+ struct device *dev;
+};
+
+/**
* struct acpuclk_platform_data - PMIC configuration data.
* @uses_pm8917: Boolean indicates presence of pm8917.
*/
@@ -273,4 +301,14 @@
*/
extern int acpuclk_krait_init(struct device *dev,
const struct acpuclk_krait_params *params);
+
+#ifdef CONFIG_DEBUG_FS
+/**
+ * acpuclk_krait_debug_init - Initialize debugfs interface.
+ */
+extern void __init acpuclk_krait_debug_init(struct drv_data *drv);
+#else
+static inline void acpuclk_krait_debug_init(void) { }
+#endif
+
#endif
diff --git a/arch/arm/mach-msm/adsp-8974.c b/arch/arm/mach-msm/adsp-8974.c
deleted file mode 100644
index fa7d9d4..0000000
--- a/arch/arm/mach-msm/adsp-8974.c
+++ /dev/null
@@ -1,301 +0,0 @@
-/* Copyright (c) 2011-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/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/reboot.h>
-#include <linux/workqueue.h>
-#include <linux/io.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/err.h>
-
-#include <mach/irqs.h>
-#include <mach/scm.h>
-#include <mach/peripheral-loader.h>
-#include <mach/subsystem_restart.h>
-#include <mach/subsystem_notif.h>
-
-#include "smd_private.h"
-#include "ramdump.h"
-#include "sysmon.h"
-
-#define SCM_Q6_NMI_CMD 0x1
-#define MODULE_NAME "adsp_8974"
-#define MAX_BUF_SIZE 0x51
-
-/* Interrupt line for WDOG bite*/
-#define ADSP_Q6SS_WDOG_EXPIRED 194
-
-/* Subsystem restart: QDSP6 data, functions */
-static void adsp_fatal_fn(struct work_struct *);
-static DECLARE_WORK(adsp_fatal_work, adsp_fatal_fn);
-
-struct adsp_ssr {
- void *adsp_ramdump_dev;
-} adsp_ssr;
-
-static struct adsp_ssr adsp_ssr_8974;
-static int q6_crash_shutdown;
-
-static int riva_notifier_cb(struct notifier_block *this, unsigned long code,
- void *ss_handle)
-{
- int ret;
- switch (code) {
- case SUBSYS_BEFORE_SHUTDOWN:
- pr_debug("%s: R-Notify: Shutdown started\n", __func__);
- ret = sysmon_send_event(SYSMON_SS_LPASS, "wcnss",
- SUBSYS_BEFORE_SHUTDOWN);
- if (ret < 0)
- pr_err("%s: sysmon_send_event error %d", __func__,
- ret);
- break;
- }
- return NOTIFY_DONE;
-}
-
-static void *ssr_notif_hdle;
-static struct notifier_block rnb = {
- .notifier_call = riva_notifier_cb,
-};
-
-static int modem_notifier_cb(struct notifier_block *this, unsigned long code,
- void *ss_handle)
-{
- int ret;
- switch (code) {
- case SUBSYS_BEFORE_SHUTDOWN:
- pr_debug("%s: M-Notify: Shutdown started\n", __func__);
- ret = sysmon_send_event(SYSMON_SS_LPASS, "modem",
- SUBSYS_BEFORE_SHUTDOWN);
- if (ret < 0)
- pr_err("%s: sysmon_send_event error %d", __func__,
- ret);
- break;
- }
- return NOTIFY_DONE;
-}
-
-static void *ssr_modem_notif_hdle;
-static struct notifier_block mnb = {
- .notifier_call = modem_notifier_cb,
-};
-
-static void adsp_log_failure_reason(void)
-{
- char *reason;
- char buffer[MAX_BUF_SIZE];
- unsigned size;
-
- reason = smem_get_entry(SMEM_SSR_REASON_LPASS0, &size);
-
- if (!reason) {
- pr_err("%s: subsystem failure reason: (unknown, smem_get_entry failed).",
- MODULE_NAME);
- return;
- }
-
- if (reason[0] == '\0') {
- pr_err("%s: subsystem failure reason: (unknown, init value found)",
- MODULE_NAME);
- return;
- }
-
- size = size < MAX_BUF_SIZE ? size : (MAX_BUF_SIZE-1);
- memcpy(buffer, reason, size);
- buffer[size] = '\0';
- pr_err("%s: subsystem failure reason: %s", MODULE_NAME, buffer);
- memset((void *)reason, 0x0, size);
- wmb();
-}
-
-static void restart_adsp(void)
-{
- adsp_log_failure_reason();
- subsystem_restart("adsp");
-}
-
-static void adsp_fatal_fn(struct work_struct *work)
-{
- pr_err("%s %s: Watchdog bite received from Q6!\n", MODULE_NAME,
- __func__);
- restart_adsp();
-}
-
-static void adsp_smsm_state_cb(void *data, uint32_t old_state,
- uint32_t new_state)
-{
- /* Ignore if we're the one that set SMSM_RESET */
- if (q6_crash_shutdown)
- return;
-
- if (new_state & SMSM_RESET) {
- pr_debug("%s: ADSP SMSM state changed to SMSM_RESET, new_state= 0x%x, old_state = 0x%x\n",
- __func__, new_state, old_state);
- restart_adsp();
- }
-}
-
-static void send_q6_nmi(void)
-{
- /* Send NMI to QDSP6 via an SCM call. */
- scm_call_atomic1(SCM_SVC_UTIL, SCM_Q6_NMI_CMD, 0x1);
- pr_debug("%s: Q6 NMI was sent.\n", __func__);
-}
-
-static int adsp_shutdown(const struct subsys_desc *subsys)
-{
- send_q6_nmi();
-
- /* The write needs to go through before the q6 is shutdown. */
- mb();
-
- pil_force_shutdown("adsp");
- disable_irq_nosync(ADSP_Q6SS_WDOG_EXPIRED);
-
- return 0;
-}
-
-static int adsp_powerup(const struct subsys_desc *subsys)
-{
- int ret;
-
- if (get_restart_level() == RESET_SUBSYS_INDEPENDENT) {
- pr_debug("%s: Wait for ADSP power up!", __func__);
- msleep(10000);
- }
-
- ret = pil_force_boot("adsp");
- enable_irq(ADSP_Q6SS_WDOG_EXPIRED);
- return ret;
-}
-/* RAM segments - address and size for 8974 */
-static struct ramdump_segment q6_segment = {0xdc00000, 0x1800000};
-
-static int adsp_ramdump(int enable, const struct subsys_desc *subsys)
-{
- pr_debug("%s: enable[%d]\n", __func__, enable);
- if (enable)
- return do_ramdump(adsp_ssr_8974.adsp_ramdump_dev,
- &q6_segment, 1);
- else
- return 0;
-}
-
-static void adsp_crash_shutdown(const struct subsys_desc *subsys)
-{
- q6_crash_shutdown = 1;
- send_q6_nmi();
-}
-
-static irqreturn_t adsp_wdog_bite_irq(int irq, void *dev_id)
-{
- int ret;
-
- pr_debug("%s: rxed irq[0x%x]", __func__, irq);
- disable_irq_nosync(ADSP_Q6SS_WDOG_EXPIRED);
- ret = schedule_work(&adsp_fatal_work);
-
- return IRQ_HANDLED;
-}
-
-static struct subsys_device *adsp_8974_dev;
-
-static struct subsys_desc adsp_8974 = {
- .name = "adsp",
- .shutdown = adsp_shutdown,
- .powerup = adsp_powerup,
- .ramdump = adsp_ramdump,
- .crash_shutdown = adsp_crash_shutdown
-};
-
-static int __init adsp_restart_init(void)
-{
- adsp_8974_dev = subsys_register(&adsp_8974);
- if (IS_ERR(adsp_8974_dev))
- return PTR_ERR(adsp_8974_dev);
- return 0;
-}
-
-static int __init adsp_fatal_init(void)
-{
- int ret;
-
- ret = smsm_state_cb_register(SMSM_Q6_STATE, SMSM_RESET,
- adsp_smsm_state_cb, 0);
-
- if (ret < 0)
- pr_err("%s: Unable to register SMSM callback! (%d)\n",
- __func__, ret);
-
- ret = request_irq(ADSP_Q6SS_WDOG_EXPIRED, adsp_wdog_bite_irq,
- IRQF_TRIGGER_RISING, "q6_wdog", NULL);
-
- if (ret < 0) {
- pr_err("%s: Unable to request ADSP_Q6SS_WDOG_EXPIRED irq.",
- __func__);
- goto out;
- }
- ret = adsp_restart_init();
- if (ret < 0) {
- pr_err("%s: Unable to reg with adsp ssr. (%d)\n",
- __func__, ret);
- goto out;
- }
-
- adsp_ssr_8974.adsp_ramdump_dev = create_ramdump_device("adsp");
-
- if (!adsp_ssr_8974.adsp_ramdump_dev) {
- pr_err("%s: Unable to create ramdump device.\n",
- __func__);
- ret = -ENOMEM;
- goto out;
- }
- ssr_notif_hdle = subsys_notif_register_notifier("riva",
- &rnb);
- if (IS_ERR(ssr_notif_hdle) < 0) {
- ret = PTR_ERR(ssr_notif_hdle);
- pr_err("%s: subsys_register_notifier for Riva: err = %d\n",
- __func__, ret);
- free_irq(ADSP_Q6SS_WDOG_EXPIRED, NULL);
- goto out;
- }
-
- ssr_modem_notif_hdle = subsys_notif_register_notifier("modem",
- &mnb);
- if (IS_ERR(ssr_modem_notif_hdle) < 0) {
- ret = PTR_ERR(ssr_modem_notif_hdle);
- pr_err("%s: subsys_register_notifier for Modem: err = %d\n",
- __func__, ret);
- subsys_notif_unregister_notifier(ssr_notif_hdle, &rnb);
- free_irq(ADSP_Q6SS_WDOG_EXPIRED, NULL);
- goto out;
- }
-
- pr_info("%s: adsp ssr driver init'ed.\n", __func__);
-out:
- return ret;
-}
-
-static void __exit adsp_fatal_exit(void)
-{
- subsys_notif_unregister_notifier(ssr_notif_hdle, &rnb);
- subsys_notif_unregister_notifier(ssr_modem_notif_hdle, &mnb);
- subsys_unregister(adsp_8974_dev);
- free_irq(ADSP_Q6SS_WDOG_EXPIRED, NULL);
-}
-
-module_init(adsp_fatal_init);
-module_exit(adsp_fatal_exit);
-
-MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/board-msm7627a-display.c b/arch/arm/mach-msm/board-msm7627a-display.c
index 8213000..2db074d 100644
--- a/arch/arm/mach-msm/board-msm7627a-display.c
+++ b/arch/arm/mach-msm/board-msm7627a-display.c
@@ -1124,10 +1124,12 @@
wmb();
lcdc_reset_cfg |= 1;
writel_relaxed(lcdc_reset_cfg, lcdc_reset_ptr);
+ msleep(20);
} else {
gpio_set_value_cansleep(GPIO_LCDC_BRDG_RESET_N, 0);
msleep(20);
gpio_set_value_cansleep(GPIO_LCDC_BRDG_RESET_N, 1);
+ msleep(20);
}
} else {
gpio_set_value_cansleep(GPIO_LCDC_BRDG_PD, 1);
diff --git a/arch/arm/mach-msm/board-msm7627a-wlan.c b/arch/arm/mach-msm/board-msm7627a-wlan.c
index 79f213e..75395b7 100644
--- a/arch/arm/mach-msm/board-msm7627a-wlan.c
+++ b/arch/arm/mach-msm/board-msm7627a-wlan.c
@@ -23,6 +23,7 @@
#define GPIO_WLAN_3V3_EN 119
static const char *id = "WLAN";
+static bool wlan_powered_up;
enum {
WLAN_VREG_S3 = 0,
@@ -199,6 +200,11 @@
int rc = 0;
static bool init_done;
+ if (wlan_powered_up) {
+ pr_info("WLAN already powered up\n");
+ return 0;
+ }
+
if (unlikely(!init_done)) {
gpio_wlan_config();
rc = qrf6285_init_regs();
@@ -279,13 +285,17 @@
}
pr_info("WLAN power-up success\n");
+ wlan_powered_up = true;
return 0;
set_clock_fail:
setup_wlan_clock(0);
set_gpio_fail:
setup_wlan_gpio(0);
gpio_fail:
- gpio_free(gpio_wlan_sys_rest_en);
+ if (!(machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb() ||
+ machine_is_msm8625_evb() || machine_is_msm8625_evt() ||
+ machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7()))
+ gpio_free(gpio_wlan_sys_rest_en);
qrd_gpio_fail:
/* GPIO_WLAN_3V3_EN is only required for the QRD7627a */
if (machine_is_msm7627a_qrd1())
@@ -294,6 +304,7 @@
wlan_switch_regulators(0);
out:
pr_info("WLAN power-up failed\n");
+ wlan_powered_up = false;
return rc;
}
@@ -301,6 +312,11 @@
{
int rc = 0;
+ if (!wlan_powered_up) {
+ pr_info("WLAN is not powered up, returning success\n");
+ return 0;
+ }
+
/* Disable the A0 clock */
rc = setup_wlan_clock(on);
if (rc) {
@@ -327,20 +343,12 @@
}
gpio_set_value(gpio_wlan_sys_rest_en, 0);
} else {
- rc = gpio_request(gpio_wlan_sys_rest_en, "WLAN_DEEP_SLEEP_N");
- if (!rc) {
- rc = setup_wlan_gpio(on);
- if (rc) {
- pr_err("%s: setup_wlan_gpio = %d\n",
- __func__, rc);
- goto set_gpio_fail;
- }
- gpio_free(gpio_wlan_sys_rest_en);
- } else {
- pr_err("%s: WLAN sys_rest_en GPIO %d request failed %d\n",
- __func__, gpio_wlan_sys_rest_en, rc);
- goto out;
+ rc = setup_wlan_gpio(on);
+ if (rc) {
+ pr_err("%s: setup_wlan_gpio = %d\n", __func__, rc);
+ goto set_gpio_fail;
}
+ gpio_free(gpio_wlan_sys_rest_en);
}
/* GPIO_WLAN_3V3_EN is only required for the QRD7627a */
@@ -362,7 +370,7 @@
__func__, rc);
goto reg_disable;
}
-
+ wlan_powered_up = false;
pr_info("WLAN power-down success\n");
return 0;
set_clock_fail:
@@ -370,14 +378,16 @@
set_gpio_fail:
setup_wlan_gpio(0);
gpio_fail:
- gpio_free(gpio_wlan_sys_rest_en);
+ if (!(machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb() ||
+ machine_is_msm8625_evb() || machine_is_msm8625_evt() ||
+ machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7()))
+ gpio_free(gpio_wlan_sys_rest_en);
qrd_gpio_fail:
/* GPIO_WLAN_3V3_EN is only required for the QRD7627a */
if (machine_is_msm7627a_qrd1())
gpio_free(GPIO_WLAN_3V3_EN);
reg_disable:
wlan_switch_regulators(0);
-out:
pr_info("WLAN power-down failed\n");
return rc;
}
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 4b03a7a..adf1733 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -6710,22 +6710,22 @@
struct clk *mmfpb_a_clk = clk_get_sys("clock-8960", "mmfpb_a_clk");
struct clk *cfpb_a_clk = clk_get_sys("clock-8960", "cfpb_a_clk");
- /* Vote for MMFPB to be at least 76.8MHz when an Apps CPU is active. */
+ /* Vote for MMFPB to be on when Apps is active. */
if (WARN(IS_ERR(mmfpb_a_clk), "mmfpb_a_clk not found (%ld)\n",
PTR_ERR(mmfpb_a_clk)))
return PTR_ERR(mmfpb_a_clk);
- rc = clk_set_rate(mmfpb_a_clk, 76800000);
+ rc = clk_set_rate(mmfpb_a_clk, 38400000);
if (WARN(rc, "mmfpb_a_clk rate was not set (%d)\n", rc))
return rc;
rc = clk_prepare_enable(mmfpb_a_clk);
if (WARN(rc, "mmfpb_a_clk not enabled (%d)\n", rc))
return rc;
- /* Vote for CFPB to be at least 64MHz when an Apps CPU is active. */
+ /* Vote for CFPB to be on when Apps is active. */
if (WARN(IS_ERR(cfpb_a_clk), "cfpb_a_clk not found (%ld)\n",
PTR_ERR(cfpb_a_clk)))
return PTR_ERR(cfpb_a_clk);
- rc = clk_set_rate(cfpb_a_clk, 64000000);
+ rc = clk_set_rate(cfpb_a_clk, 32000000);
if (WARN(rc, "cfpb_a_clk rate was not set (%d)\n", rc))
return rc;
rc = clk_prepare_enable(cfpb_a_clk);
diff --git a/arch/arm/mach-msm/clock-9625.c b/arch/arm/mach-msm/clock-9625.c
index 961d68b..02dd562 100644
--- a/arch/arm/mach-msm/clock-9625.c
+++ b/arch/arm/mach-msm/clock-9625.c
@@ -2011,9 +2011,6 @@
CLK_LOOKUP("core_clk", gcc_pdm2_clk.c, ""),
CLK_LOOKUP("iface_clk", gcc_pdm_ahb_clk.c, ""),
- CLK_LOOKUP("core_clk", gcc_qpic_clk.c, ""),
- CLK_LOOKUP("iface_clk", gcc_qpic_ahb_clk.c, ""),
-
CLK_LOOKUP("iface_clk", gcc_sdcc2_ahb_clk.c, "f98a4000.qcom,sdcc"),
CLK_LOOKUP("core_clk", gcc_sdcc2_apps_clk.c, "f98a4000.qcom,sdcc"),
CLK_LOOKUP("bus_clk", pnoc_sdcc2_clk.c, "f98a4000.qcom,sdcc"),
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index a49a145..d727c54 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -2404,19 +2404,6 @@
/* Sensors DSPS platform data */
-#define PPSS_DSPS_TCM_CODE_BASE 0x12000000
-#define PPSS_DSPS_TCM_CODE_SIZE 0x28000
-#define PPSS_DSPS_TCM_BUF_BASE 0x12040000
-#define PPSS_DSPS_TCM_BUF_SIZE 0x4000
-#define PPSS_DSPS_PIPE_BASE 0x12800000
-#define PPSS_DSPS_PIPE_SIZE 0x4000
-#define PPSS_DSPS_DDR_BASE 0x8fe00000
-#define PPSS_DSPS_DDR_SIZE 0x100000
-#define PPSS_SMEM_BASE 0x80000000
-#define PPSS_SMEM_SIZE 0x200000
-#define PPSS_REG_PHYS_BASE 0x12080000
-#define PPSS_WDOG_UNMASKED_INT_EN 0x1808
-
static struct dsps_clk_info dsps_clks[] = {};
static struct dsps_regulator_info dsps_regs[] = {};
@@ -2425,6 +2412,8 @@
* apq8064_init_dsps().
*/
+#define PPSS_REG_PHYS_BASE 0x12080000
+
struct msm_dsps_platform_data msm_dsps_pdata_8064 = {
.clks = dsps_clks,
.clks_num = ARRAY_SIZE(dsps_clks),
@@ -2433,17 +2422,6 @@
.regs = dsps_regs,
.regs_num = ARRAY_SIZE(dsps_regs),
.dsps_pwr_ctl_en = 1,
- .tcm_code_start = PPSS_DSPS_TCM_CODE_BASE,
- .tcm_code_size = PPSS_DSPS_TCM_CODE_SIZE,
- .tcm_buf_start = PPSS_DSPS_TCM_BUF_BASE,
- .tcm_buf_size = PPSS_DSPS_TCM_BUF_SIZE,
- .pipe_start = PPSS_DSPS_PIPE_BASE,
- .pipe_size = PPSS_DSPS_PIPE_SIZE,
- .ddr_start = PPSS_DSPS_DDR_BASE,
- .ddr_size = PPSS_DSPS_DDR_SIZE,
- .smem_start = PPSS_SMEM_BASE,
- .smem_size = PPSS_SMEM_SIZE,
- .ppss_wdog_unmasked_int_en_reg = PPSS_WDOG_UNMASKED_INT_EN,
.signature = DSPS_SIGNATURE,
};
@@ -2454,13 +2432,6 @@
.name = "ppss_reg",
.flags = IORESOURCE_MEM,
},
-
- {
- .start = PPSS_WDOG_TIMER_IRQ,
- .end = PPSS_WDOG_TIMER_IRQ,
- .name = "ppss_wdog",
- .flags = IORESOURCE_IRQ,
- },
};
struct platform_device msm_dsps_device_8064 = {
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 5b04fa7..0f71bc4 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -1462,9 +1462,24 @@
.id = -1,
};
+static struct resource msm_pil_dsps_resources[] = {
+ {
+ .start = PPSS_WDOG_TIMER_IRQ,
+ .end = PPSS_WDOG_TIMER_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = 0x12080000,
+ .end = 0x12080000 + SZ_8K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
struct platform_device msm_pil_dsps = {
- .name = "pil_dsps",
- .id = -1,
+ .name = "pil_dsps",
+ .id = -1,
+ .resource = msm_pil_dsps_resources,
+ .num_resources = ARRAY_SIZE(msm_pil_dsps_resources),
.dev.platform_data = "dsps",
};
@@ -3801,18 +3816,7 @@
/* Sensors DSPS platform data */
#ifdef CONFIG_MSM_DSPS
-#define PPSS_DSPS_TCM_CODE_BASE 0x12000000
-#define PPSS_DSPS_TCM_CODE_SIZE 0x28000
-#define PPSS_DSPS_TCM_BUF_BASE 0x12040000
-#define PPSS_DSPS_TCM_BUF_SIZE 0x4000
-#define PPSS_DSPS_PIPE_BASE 0x12800000
-#define PPSS_DSPS_PIPE_SIZE 0x4000
-#define PPSS_DSPS_DDR_BASE 0x8fe00000
-#define PPSS_DSPS_DDR_SIZE 0x100000
-#define PPSS_SMEM_BASE 0x80000000
-#define PPSS_SMEM_SIZE 0x200000
-#define PPSS_REG_PHYS_BASE 0x12080000
-#define PPSS_WDOG_UNMASKED_INT_EN 0x1808
+#define PPSS_REG_PHYS_BASE 0x12080000
static struct dsps_clk_info dsps_clks[] = {};
static struct dsps_regulator_info dsps_regs[] = {};
@@ -3830,17 +3834,6 @@
.regs = dsps_regs,
.regs_num = ARRAY_SIZE(dsps_regs),
.dsps_pwr_ctl_en = 1,
- .tcm_code_start = PPSS_DSPS_TCM_CODE_BASE,
- .tcm_code_size = PPSS_DSPS_TCM_CODE_SIZE,
- .tcm_buf_start = PPSS_DSPS_TCM_BUF_BASE,
- .tcm_buf_size = PPSS_DSPS_TCM_BUF_SIZE,
- .pipe_start = PPSS_DSPS_PIPE_BASE,
- .pipe_size = PPSS_DSPS_PIPE_SIZE,
- .ddr_start = PPSS_DSPS_DDR_BASE,
- .ddr_size = PPSS_DSPS_DDR_SIZE,
- .smem_start = PPSS_SMEM_BASE,
- .smem_size = PPSS_SMEM_SIZE,
- .ppss_wdog_unmasked_int_en_reg = PPSS_WDOG_UNMASKED_INT_EN,
.signature = DSPS_SIGNATURE,
};
@@ -3851,12 +3844,6 @@
.name = "ppss_reg",
.flags = IORESOURCE_MEM,
},
- {
- .start = PPSS_WDOG_TIMER_IRQ,
- .end = PPSS_WDOG_TIMER_IRQ,
- .name = "ppss_wdog",
- .flags = IORESOURCE_IRQ,
- },
};
struct platform_device msm_dsps_device = {
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index 37cdc98..5554eb8 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -1622,16 +1622,6 @@
/* Sensors DSPS platform data */
#ifdef CONFIG_MSM_DSPS
-#define PPSS_DSPS_TCM_CODE_BASE 0x12000000
-#define PPSS_DSPS_TCM_CODE_SIZE 0x28000
-#define PPSS_DSPS_TCM_BUF_BASE 0x12040000
-#define PPSS_DSPS_TCM_BUF_SIZE 0x4000
-#define PPSS_DSPS_PIPE_BASE 0x12800000
-#define PPSS_DSPS_PIPE_SIZE 0x0 /* 8660 V2 does not use PIPE memory */
-#define PPSS_DSPS_DDR_BASE 0x8fe00000
-#define PPSS_DSPS_DDR_SIZE 0x0 /* 8660 V2 does not use DDR memory */
-#define PPSS_SMEM_BASE 0x40000000
-#define PPSS_SMEM_SIZE 0x4000
#define PPSS_REG_PHYS_BASE 0x12080000
#define PPSS_PAUSE_REG 0x1804
@@ -1696,16 +1686,6 @@
.regs = dsps_regs,
.regs_num = ARRAY_SIZE(dsps_regs),
.init = dsps_init1,
- .tcm_code_start = PPSS_DSPS_TCM_CODE_BASE,
- .tcm_code_size = PPSS_DSPS_TCM_CODE_SIZE,
- .tcm_buf_start = PPSS_DSPS_TCM_BUF_BASE,
- .tcm_buf_size = PPSS_DSPS_TCM_BUF_SIZE,
- .pipe_start = PPSS_DSPS_PIPE_BASE,
- .pipe_size = PPSS_DSPS_PIPE_SIZE,
- .ddr_start = PPSS_DSPS_DDR_BASE,
- .ddr_size = PPSS_DSPS_DDR_SIZE,
- .smem_start = PPSS_SMEM_BASE,
- .smem_size = PPSS_SMEM_SIZE,
.ppss_pause_reg = PPSS_PAUSE_REG,
.signature = DSPS_SIGNATURE,
};
diff --git a/arch/arm/mach-msm/include/mach/msm_dsps.h b/arch/arm/mach-msm/include/mach/msm_dsps.h
index a876798..ac81616 100644
--- a/arch/arm/mach-msm/include/mach/msm_dsps.h
+++ b/arch/arm/mach-msm/include/mach/msm_dsps.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-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
@@ -75,16 +75,6 @@
* @regs_num - number of regulators.
* @dsps_pwr_ctl_en - to enable DSPS to do power control if set 1
* otherwise the apps will do power control
- * @tcm_code_start - start of the TCM code region as physical address
- * @tcm_code_size - size of the TCM code region in bytes
- * @tcm_buf_start - start of the TCM buf region as physical address
- * @tcm_buf_size - size of the TCM buf region in bytes
- * @pipe_start - start of the PIPE region as physical address
- * @pipe_size - size of the PIPE region in bytes
- * @ddr_start - start of the DDR region as physical address
- * @ddr_size - size of the DDR region in bytes
- * @smem_start - start of the smem region as physical address
- * @smem_size - size of the smem region in bytes
* @ppss_pause_reg - Offset to the PPSS_PAUSE register
* @ppss_wdog_unmasked_int_en_reg - Offset to PPSS_WDOG_UNMASKED_INT_EN register
* @signature - signature for validity check.
@@ -99,16 +89,6 @@
int regs_num;
int dsps_pwr_ctl_en;
void (*init)(struct msm_dsps_platform_data *data);
- int tcm_code_start;
- int tcm_code_size;
- int tcm_buf_start;
- int tcm_buf_size;
- int pipe_start;
- int pipe_size;
- int ddr_start;
- int ddr_size;
- int smem_start;
- int smem_size;
int ppss_pause_reg;
int ppss_wdog_unmasked_int_en_reg;
u32 signature;
diff --git a/arch/arm/mach-msm/lpm_resources.c b/arch/arm/mach-msm/lpm_resources.c
index 364f297..2db92f3 100644
--- a/arch/arm/mach-msm/lpm_resources.c
+++ b/arch/arm/mach-msm/lpm_resources.c
@@ -387,7 +387,7 @@
static bool msm_lpm_beyond_limits_l2(struct msm_rpmrs_limits *limits)
{
uint32_t l2;
- bool ret = true;
+ bool ret = false;
struct msm_lpm_resource *rs = &msm_lpm_l2;
if (rs->valid) {
@@ -669,7 +669,7 @@
msm_lpm_get_rpm_notif = false;
for (i = 0; i < ARRAY_SIZE(msm_lpm_resources); i++) {
rs = msm_lpm_resources[i];
- if (rs->flush)
+ if (rs->valid && rs->flush)
rs->flush(notify_rpm);
}
msm_lpm_get_rpm_notif = true;
diff --git a/arch/arm/mach-msm/modem-ssr-8974.c b/arch/arm/mach-msm/modem-ssr-8974.c
deleted file mode 100644
index 942eca5..0000000
--- a/arch/arm/mach-msm/modem-ssr-8974.c
+++ /dev/null
@@ -1,212 +0,0 @@
-/* Copyright (c) 2012, The Linux Foundation. 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/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/err.h>
-
-#include <mach/peripheral-loader.h>
-#include <mach/subsystem_restart.h>
-#include <mach/msm_smsm.h>
-
-#include "ramdump.h"
-
-static int crash_shutdown;
-static int modem_ssr_ignore_errors;
-static struct subsys_device *modem_ssr_dev;
-
-#define MAX_SSR_REASON_LEN 81U
-#define Q6SS_WDOG_ENABLE 0xFC802004
-#define MSS_Q6SS_WDOG_EXP_IRQ 56
-
-static void log_modem_sfr(void)
-{
- u32 size;
- char *smem_reason, reason[MAX_SSR_REASON_LEN];
-
- smem_reason = smem_get_entry(SMEM_SSR_REASON_MSS0, &size);
- if (!smem_reason || !size) {
- pr_err("modem subsystem failure reason: (unknown, smem_get_entry failed).\n");
- return;
- }
- if (!smem_reason[0]) {
- pr_err("modem subsystem failure reason: (unknown, empty string found).\n");
- return;
- }
-
- strlcpy(reason, smem_reason, min(size, sizeof(reason)));
- pr_err("modem subsystem failure reason: %s.\n", reason);
-
- smem_reason[0] = '\0';
- wmb();
-}
-
-static void restart_modem(void)
-{
- log_modem_sfr();
- modem_ssr_ignore_errors = 1;
- subsystem_restart("modem");
-}
-
-static void smsm_state_cb(void *data, uint32_t old_state, uint32_t new_state)
-{
- /* Ignore if we're the one that set SMSM_RESET */
- if (crash_shutdown)
- return;
-
- if (new_state & SMSM_RESET) {
- pr_err("Probable fatal error on the modem.\n");
- restart_modem();
- }
-}
-
-static int modem_shutdown(const struct subsys_desc *subsys)
-{
- pil_force_shutdown("modem");
- pil_force_shutdown("mba");
- return 0;
-}
-
-static int modem_powerup(const struct subsys_desc *subsys)
-{
- /*
- * At this time, the modem is shutdown. Therefore this function cannot
- * run concurrently with either the watchdog bite error handler or the
- * SMSM callback, making it safe to unset the flag below.
- */
- modem_ssr_ignore_errors = 0;
- pil_force_boot("mba");
- pil_force_boot("modem");
- return 0;
-}
-
-void modem_crash_shutdown(const struct subsys_desc *subsys)
-{
- crash_shutdown = 1;
- smsm_reset_modem(SMSM_RESET);
-}
-
-static struct ramdump_segment modem_segments[] = {
- {0x08400000, 0x0D100000 - 0x08400000},
-};
-
-static struct ramdump_segment smem_segments[] = {
- {0x0FA00000, 0x0FC00000 - 0x0FA00000},
-};
-
-static void *modem_ramdump_dev;
-static void *smem_ramdump_dev;
-
-static int modem_ramdump(int enable, const struct subsys_desc *crashed_subsys)
-{
- int ret = 0;
-
- if (!enable)
- return ret;
-
- pil_force_boot("mba");
-
- ret = do_ramdump(modem_ramdump_dev, modem_segments,
- ARRAY_SIZE(modem_segments));
-
- if (ret < 0) {
- pr_err("Unable to dump modem fw memory (rc = %d).\n",
- ret);
- goto out;
- }
-
- ret = do_ramdump(smem_ramdump_dev, smem_segments,
- ARRAY_SIZE(smem_segments));
-
- if (ret < 0) {
- pr_err("Unable to dump smem memory (rc = %d).\n", ret);
- goto out;
- }
-
-out:
- pil_force_shutdown("mba");
- return ret;
-}
-
-static irqreturn_t modem_wdog_bite_irq(int irq, void *dev_id)
-{
- if (modem_ssr_ignore_errors)
- return IRQ_HANDLED;
- pr_err("Watchdog bite received from the modem!\n");
- restart_modem();
- return IRQ_HANDLED;
-}
-
-static struct subsys_desc modem_8974 = {
- .name = "modem",
- .shutdown = modem_shutdown,
- .powerup = modem_powerup,
- .ramdump = modem_ramdump,
- .crash_shutdown = modem_crash_shutdown
-};
-
-static int __init modem_8974_init(void)
-{
- int ret;
-
- ret = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_RESET,
- smsm_state_cb, 0);
-
- if (ret < 0) {
- pr_err("%s: Unable to register SMSM callback! (%d)\n",
- __func__, ret);
- goto out;
- }
-
- ret = request_irq(MSS_Q6SS_WDOG_EXP_IRQ, modem_wdog_bite_irq,
- IRQF_TRIGGER_RISING, "modem_wdog_sw", NULL);
-
- if (ret < 0) {
- pr_err("%s: Unable to request q6sw watchdog IRQ. (%d)\n",
- __func__, ret);
- goto out;
- }
-
- modem_ssr_dev = subsys_register(&modem_8974);
-
- if (IS_ERR_OR_NULL(modem_ssr_dev)) {
- pr_err("%s: Unable to reg with subsystem restart. (%ld)\n",
- __func__, PTR_ERR(modem_ssr_dev));
- ret = PTR_ERR(modem_ssr_dev);
- goto out;
- }
-
- modem_ramdump_dev = create_ramdump_device("modem");
-
- if (!modem_ramdump_dev) {
- pr_err("%s: Unable to create a modem ramdump device.\n",
- __func__);
- ret = -ENOMEM;
- goto out;
- }
-
- smem_ramdump_dev = create_ramdump_device("smem-modem");
-
- if (!smem_ramdump_dev) {
- pr_err("%s: Unable to create an smem ramdump device.\n",
- __func__);
- ret = -ENOMEM;
- goto out;
- }
-
- pr_info("%s: modem subsystem restart driver init'ed.\n", __func__);
-out:
- return ret;
-}
-
-module_init(modem_8974_init);
diff --git a/arch/arm/mach-msm/msm_dsps.c b/arch/arm/mach-msm/msm_dsps.c
index c39829b..b85c812 100644
--- a/arch/arm/mach-msm/msm_dsps.c
+++ b/arch/arm/mach-msm/msm_dsps.c
@@ -15,8 +15,6 @@
*
*/
-#include <asm/atomic.h>
-
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/module.h>
@@ -39,7 +37,6 @@
#include <mach/msm_smsm.h>
#include <mach/msm_dsps.h>
#include <mach/subsystem_restart.h>
-#include <mach/subsystem_notif.h>
#include "ramdump.h"
#include "timer.h"
@@ -66,8 +63,6 @@
* @smem_ramdump_segments - Ramdump segment information for smem
* @is_on - DSPS is on.
* @ref_count - open/close reference count.
- * @wdog_irq - DSPS Watchdog IRQ
- * @crash_in_progress - 1 if crash recovery is in progress
* @ppss_base - ppss registers virtual base address.
*/
struct dsps_drv {
@@ -81,17 +76,9 @@
void *pil;
- void *dspsfw_ramdump_dev;
- struct ramdump_segment dspsfw_ramdump_segments[4];
-
- void *smem_ramdump_dev;
- struct ramdump_segment smem_ramdump_segments[1];
-
int is_on;
int ref_count;
- int wdog_irq;
- atomic_t crash_in_progress;
void __iomem *ppss_base;
};
@@ -101,13 +88,6 @@
static struct dsps_drv *drv;
/**
- * self-initiated shutdown flag
- */
-static int dsps_crash_shutdown_g;
-
-static void dsps_restart_handler(void);
-
-/**
* Load DSPS Firmware.
*/
static int dsps_load(const char *name)
@@ -382,41 +362,6 @@
}
/**
- *
- * Log subsystem restart failure reason
- */
-static void dsps_log_sfr(void)
-{
- const char dflt_reason[] = "Died too early due to unknown reason";
- char *smem_reset_reason;
- unsigned smem_reset_size;
-
- smem_reset_reason = smem_get_entry(SMEM_SSR_REASON_DSPS0,
- &smem_reset_size);
- if (smem_reset_reason != NULL && smem_reset_reason[0] != 0) {
- smem_reset_reason[smem_reset_size-1] = 0;
- pr_err("%s: DSPS failure: %s\nResetting DSPS\n",
- __func__, smem_reset_reason);
- memset(smem_reset_reason, 0, smem_reset_size);
- wmb();
- } else
- pr_err("%s: DSPS failure: %s\nResetting DSPS\n",
- __func__, dflt_reason);
-}
-
-/**
- * Watchdog interrupt handler
- *
- */
-static irqreturn_t dsps_wdog_bite_irq(int irq, void *dev_id)
-{
- pr_err("%s\n", __func__);
- dsps_log_sfr();
- dsps_restart_handler();
- return IRQ_HANDLED;
-}
-
-/**
* IO Control - handle commands from client.
*
*/
@@ -452,7 +397,7 @@
case DSPS_IOCTL_RESET:
pr_err("%s: User-initiated DSPS reset.\nResetting DSPS\n",
__func__);
- dsps_restart_handler();
+ subsystem_restart("dsps");
ret = 0;
break;
default:
@@ -471,7 +416,6 @@
{
int ret = -ENODEV;
struct resource *ppss_res;
- struct resource *ppss_wdog;
int i;
pr_debug("%s.\n", __func__);
@@ -541,58 +485,11 @@
drv->ppss_base = ioremap(ppss_res->start,
resource_size(ppss_res));
- ppss_wdog = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
- "ppss_wdog");
- if (ppss_wdog) {
- drv->wdog_irq = ppss_wdog->start;
- ret = request_irq(drv->wdog_irq, dsps_wdog_bite_irq,
- IRQF_TRIGGER_RISING, "dsps_wdog", NULL);
- if (ret) {
- pr_err("%s: request_irq fail %d\n", __func__, ret);
- goto request_irq_err;
- }
- } else {
- drv->wdog_irq = -1;
- pr_debug("%s: ppss_wdog not supported.\n", __func__);
- }
-
- drv->dspsfw_ramdump_segments[0].address = drv->pdata->tcm_code_start;
- drv->dspsfw_ramdump_segments[0].size = drv->pdata->tcm_code_size;
- drv->dspsfw_ramdump_segments[1].address = drv->pdata->tcm_buf_start;
- drv->dspsfw_ramdump_segments[1].size = drv->pdata->tcm_buf_size;
- drv->dspsfw_ramdump_segments[2].address = drv->pdata->pipe_start;
- drv->dspsfw_ramdump_segments[2].size = drv->pdata->pipe_size;
- drv->dspsfw_ramdump_segments[3].address = drv->pdata->ddr_start;
- drv->dspsfw_ramdump_segments[3].size = drv->pdata->ddr_size;
-
- drv->dspsfw_ramdump_dev = create_ramdump_device("dsps");
- if (!drv->dspsfw_ramdump_dev) {
- pr_err("%s: create_ramdump_device(\"dsps\") fail\n",
- __func__);
- goto create_ramdump_err;
- }
-
- drv->smem_ramdump_segments[0].address = drv->pdata->smem_start;
- drv->smem_ramdump_segments[0].size = drv->pdata->smem_size;
- drv->smem_ramdump_dev = create_ramdump_device("smem-dsps");
- if (!drv->smem_ramdump_dev) {
- pr_err("%s: create_ramdump_device(\"smem\") fail\n",
- __func__);
- goto create_ramdump_err;
- }
-
if (drv->pdata->init)
drv->pdata->init(drv->pdata);
return 0;
-create_ramdump_err:
- disable_irq_nosync(drv->wdog_irq);
- free_irq(drv->wdog_irq, NULL);
-
-request_irq_err:
- iounmap(drv->ppss_base);
-
reg_err:
for (i = 0; i < drv->pdata->regs_num; i++) {
if (drv->pdata->regs[i].reg) {
@@ -678,8 +575,6 @@
}
}
- free_irq(drv->wdog_irq, NULL);
-
iounmap(drv->ppss_base);
}
@@ -722,138 +617,6 @@
.unlocked_ioctl = dsps_ioctl,
};
-static struct subsys_device *dsps_dev;
-
-/**
- * Fatal error handler
- * Resets DSPS.
- */
-static void dsps_restart_handler(void)
-{
- pr_debug("%s: Restart lvl %d\n",
- __func__, get_restart_level());
-
- if (atomic_add_return(1, &drv->crash_in_progress) > 1) {
- pr_err("%s: DSPS already resetting. Count %d\n", __func__,
- atomic_read(&drv->crash_in_progress));
- } else {
- subsystem_restart_dev(dsps_dev);
- }
-}
-
-
-/**
- * SMSM state change callback
- *
- */
-static void dsps_smsm_state_cb(void *data, uint32_t old_state,
- uint32_t new_state)
-{
- pr_debug("%s\n", __func__);
- if (dsps_crash_shutdown_g == 1) {
- pr_debug("%s: SMSM_RESET state change ignored\n",
- __func__);
- dsps_crash_shutdown_g = 0;
- return;
- }
- if (new_state & SMSM_RESET) {
- dsps_log_sfr();
- dsps_restart_handler();
- }
-}
-
-/**
- * Shutdown function
- * called by the restart notifier
- *
- */
-static int dsps_shutdown(const struct subsys_desc *subsys)
-{
- pr_debug("%s\n", __func__);
- disable_irq_nosync(drv->wdog_irq);
- if (drv->pdata->ppss_wdog_unmasked_int_en_reg) {
- writel_relaxed(0, (drv->ppss_base+
- drv->pdata->ppss_wdog_unmasked_int_en_reg));
- mb(); /* Make sure wdog is disabled before shutting down */
- }
- pil_force_shutdown(drv->pdata->pil_name);
- dsps_power_off_handler();
- return 0;
-}
-
-/**
- * Powerup function
- * called by the restart notifier
- *
- */
-static int dsps_powerup(const struct subsys_desc *subsys)
-{
- pr_debug("%s\n", __func__);
- dsps_power_on_handler();
- pil_force_boot(drv->pdata->pil_name);
- atomic_set(&drv->crash_in_progress, 0);
- enable_irq(drv->wdog_irq);
- return 0;
-}
-
-/**
- * Crash shutdown function
- * called by the restart notifier
- *
- */
-static void dsps_crash_shutdown(const struct subsys_desc *subsys)
-{
- pr_debug("%s\n", __func__);
- disable_irq_nosync(drv->wdog_irq);
- dsps_crash_shutdown_g = 1;
- smsm_change_state(SMSM_DSPS_STATE, SMSM_RESET, SMSM_RESET);
-}
-
-/**
- * Ramdump function
- * called by the restart notifier
- *
- */
-static int dsps_ramdump(int enable, const struct subsys_desc *subsys)
-{
- int ret = 0;
- pr_debug("%s\n", __func__);
-
- if (enable) {
- if (drv->dspsfw_ramdump_dev != NULL) {
- ret = do_ramdump(drv->dspsfw_ramdump_dev,
- drv->dspsfw_ramdump_segments,
- ARRAY_SIZE(drv->dspsfw_ramdump_segments));
- if (ret < 0) {
- pr_err("%s: Unable to dump DSPS memory (rc = %d).\n",
- __func__, ret);
- goto dsps_ramdump_out;
- }
- }
- if (drv->smem_ramdump_dev != NULL) {
- ret = do_ramdump(drv->smem_ramdump_dev,
- drv->smem_ramdump_segments,
- ARRAY_SIZE(drv->smem_ramdump_segments));
- if (ret < 0) {
- pr_err("%s: Unable to dump smem memory (rc = %d).\n",
- __func__, ret);
- goto dsps_ramdump_out;
- }
- }
- }
-
-dsps_ramdump_out:
- return ret;
-}
-
-static struct subsys_desc dsps_ssrops = {
- .name = "dsps",
- .shutdown = dsps_shutdown,
- .powerup = dsps_powerup,
- .ramdump = dsps_ramdump,
- .crash_shutdown = dsps_crash_shutdown
-};
-
/**
* platform driver
*
@@ -874,8 +637,6 @@
pr_err("%s: kzalloc fail.\n", __func__);
goto alloc_err;
}
- atomic_set(&drv->crash_in_progress, 0);
-
drv->pdata = pdev->dev.platform_data;
drv->dev_class = class_create(THIS_MODULE, DRV_NAME);
@@ -918,31 +679,6 @@
goto cdev_add_err;
}
- ret =
- smsm_state_cb_register(SMSM_DSPS_STATE, SMSM_RESET,
- dsps_smsm_state_cb, 0);
- if (ret) {
- pr_err("%s: smsm_state_cb_register fail %d\n", __func__,
- ret);
- goto smsm_register_err;
- }
-
- dsps_dev = subsys_register(&dsps_ssrops);
- if (IS_ERR(dsps_dev)) {
- ret = PTR_ERR(dsps_dev);
- pr_err("%s: subsys_register fail %d\n", __func__,
- ret);
- goto ssr_register_err;
- }
-
- return 0;
-
-ssr_register_err:
- smsm_state_cb_deregister(SMSM_DSPS_STATE, SMSM_RESET,
- dsps_smsm_state_cb,
- 0);
-smsm_register_err:
- cdev_del(drv->cdev);
cdev_add_err:
kfree(drv->cdev);
cdev_alloc_err:
@@ -962,7 +698,6 @@
{
pr_debug("%s.\n", __func__);
- subsys_unregister(dsps_dev);
dsps_power_off_handler();
dsps_free_resources();
diff --git a/arch/arm/mach-msm/pil-dsps.c b/arch/arm/mach-msm/pil-dsps.c
index 81f5330..dc80a3a 100644
--- a/arch/arm/mach-msm/pil-dsps.c
+++ b/arch/arm/mach-msm/pil-dsps.c
@@ -17,11 +17,17 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/delay.h>
+#include <linux/atomic.h>
+#include <linux/interrupt.h>
#include <mach/msm_iomap.h>
+#include <mach/subsystem_restart.h>
+#include <mach/msm_smsm.h>
+#include <mach/peripheral-loader.h>
#include "peripheral-loader.h"
#include "scm-pas.h"
+#include "ramdump.h"
#define PPSS_RESET (MSM_CLK_CTL_BASE + 0x2594)
#define PPSS_RESET_PROC_RESET 0x2
@@ -31,6 +37,28 @@
#define PPSS_HCLK_CTL (MSM_CLK_CTL_BASE + 0x2580)
#define CLK_HALT_DFAB_STATE (MSM_CLK_CTL_BASE + 0x2FC8)
+#define PPSS_WDOG_UNMASKED_INT_EN 0x1808
+
+struct dsps_data {
+ struct pil_device *pil;
+ struct pil_desc desc;
+ struct subsys_device *subsys;
+ struct subsys_desc subsys_desc;
+ int crash;
+ int wdog_irq;
+ atomic_t wd_crash;
+ atomic_t crash_in_progress;
+ void __iomem *ppss_base;
+
+ void *ramdump_dev;
+ struct ramdump_segment fw_ramdump_segments[4];
+
+ void *smem_ramdump_dev;
+ struct ramdump_segment smem_ramdump_segments[1];
+};
+
+#define desc_to_drv(d) container_of(d, struct dsps_data, subsys_desc)
+
static int init_image_dsps(struct pil_desc *pil, const u8 *metadata,
size_t size)
{
@@ -88,15 +116,143 @@
.shutdown = shutdown_dsps_trusted,
};
+static void dsps_log_sfr(void)
+{
+ const char dflt_reason[] = "Died too early due to unknown reason";
+ char *smem_reset_reason;
+ unsigned smem_reset_size;
+
+ smem_reset_reason = smem_get_entry(SMEM_SSR_REASON_DSPS0,
+ &smem_reset_size);
+ if (smem_reset_reason != NULL && smem_reset_reason[0] != 0) {
+ smem_reset_reason[smem_reset_size-1] = 0;
+ pr_err("%s: DSPS failure: %s\nResetting DSPS\n",
+ __func__, smem_reset_reason);
+ memset(smem_reset_reason, 0, smem_reset_size);
+ wmb();
+ } else
+ pr_err("%s: DSPS failure: %s\nResetting DSPS\n",
+ __func__, dflt_reason);
+}
+
+
+static void dsps_restart_handler(struct dsps_data *drv)
+{
+ pr_debug("%s: Restart lvl %d\n",
+ __func__, get_restart_level());
+
+ if (atomic_add_return(1, &drv->crash_in_progress) > 1) {
+ pr_err("%s: DSPS already resetting. Count %d\n", __func__,
+ atomic_read(&drv->crash_in_progress));
+ } else {
+ subsystem_restart_dev(drv->subsys);
+ }
+}
+
+static void dsps_smsm_state_cb(void *data, uint32_t old_state,
+ uint32_t new_state)
+{
+ struct dsps_data *drv = data;
+
+ if (drv->crash == 1) {
+ pr_debug("SMSM_RESET state change ignored\n");
+ drv->crash = 0;
+ } else if (new_state & SMSM_RESET) {
+ dsps_log_sfr();
+ dsps_restart_handler(drv);
+ }
+}
+
+static int dsps_shutdown(const struct subsys_desc *desc)
+{
+ struct dsps_data *drv = desc_to_drv(desc);
+ disable_irq_nosync(drv->wdog_irq);
+ if (drv->ppss_base) {
+ writel_relaxed(0, drv->ppss_base + PPSS_WDOG_UNMASKED_INT_EN);
+ mb(); /* Make sure wdog is disabled before shutting down */
+ }
+ pil_force_shutdown(drv->desc.name);
+ return 0;
+}
+
+static int dsps_powerup(const struct subsys_desc *desc)
+{
+ struct dsps_data *drv = desc_to_drv(desc);
+
+ pil_force_boot(drv->desc.name);
+ atomic_set(&drv->crash_in_progress, 0);
+ enable_irq(drv->wdog_irq);
+
+ return 0;
+}
+
+static int dsps_ramdump(int enable, const struct subsys_desc *desc)
+{
+ int ret;
+ struct dsps_data *drv = desc_to_drv(desc);
+
+ if (!enable)
+ return 0;
+
+ ret = do_ramdump(drv->ramdump_dev,
+ drv->fw_ramdump_segments,
+ ARRAY_SIZE(drv->fw_ramdump_segments));
+ if (ret < 0) {
+ pr_err("%s: Unable to dump DSPS memory (rc = %d).\n",
+ __func__, ret);
+ return ret;
+ }
+ ret = do_ramdump(drv->smem_ramdump_dev,
+ drv->smem_ramdump_segments,
+ ARRAY_SIZE(drv->smem_ramdump_segments));
+ if (ret < 0) {
+ pr_err("%s: Unable to dump smem memory (rc = %d).\n",
+ __func__, ret);
+ return ret;
+ }
+ return 0;
+}
+
+static void dsps_crash_shutdown(const struct subsys_desc *desc)
+{
+ struct dsps_data *drv = desc_to_drv(desc);
+
+ disable_irq_nosync(drv->wdog_irq);
+ drv->crash = 1;
+ smsm_change_state(SMSM_DSPS_STATE, SMSM_RESET, SMSM_RESET);
+}
+
+static irqreturn_t dsps_wdog_bite_irq(int irq, void *dev_id)
+{
+ struct dsps_data *drv = dev_id;
+
+ atomic_set(&drv->wd_crash, 1);
+ dsps_log_sfr();
+ dsps_restart_handler(drv);
+ return IRQ_HANDLED;
+}
+
static int __devinit pil_dsps_driver_probe(struct platform_device *pdev)
{
+ struct dsps_data *drv;
struct pil_desc *desc;
- struct pil_device *pil;
+ int ret;
+ struct resource *res;
- desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
- if (!desc)
+ drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
+ if (!drv)
return -ENOMEM;
+ platform_set_drvdata(pdev, drv);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res) {
+ drv->ppss_base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!drv->ppss_base)
+ return -ENOMEM;
+ }
+
+ desc = &drv->desc;
desc->name = pdev->dev.platform_data;
desc->dev = &pdev->dev;
desc->owner = THIS_MODULE;
@@ -107,17 +263,85 @@
desc->ops = &pil_dsps_ops;
dev_info(&pdev->dev, "using non-secure boot\n");
}
- pil = msm_pil_register(desc);
- if (IS_ERR(pil))
- return PTR_ERR(pil);
- platform_set_drvdata(pdev, pil);
+ drv->pil = msm_pil_register(desc);
+ if (IS_ERR(drv->pil))
+ return PTR_ERR(drv->pil);
+
+ drv->fw_ramdump_segments[0].address = 0x12000000;
+ drv->fw_ramdump_segments[0].size = 0x28000;
+ drv->fw_ramdump_segments[1].address = 0x12040000;
+ drv->fw_ramdump_segments[1].size = 0x4000;
+ drv->fw_ramdump_segments[2].address = 0x12800000;
+ drv->fw_ramdump_segments[2].size = 0x4000;
+ drv->fw_ramdump_segments[3].address = 0x8fe00000;
+ drv->fw_ramdump_segments[3].size = 0x100000;
+ drv->ramdump_dev = create_ramdump_device("dsps");
+ if (!drv->ramdump_dev) {
+ ret = -ENOMEM;
+ goto err_ramdump;
+ }
+
+ drv->smem_ramdump_segments[0].address = PHYS_OFFSET - SZ_2M;
+ drv->smem_ramdump_segments[0].size = SZ_2M;
+ drv->smem_ramdump_dev = create_ramdump_device("smem-dsps");
+ if (!drv->smem_ramdump_dev) {
+ ret = -ENOMEM;
+ goto err_smem_ramdump;
+ }
+
+ drv->subsys_desc.name = "dsps";
+ drv->subsys_desc.shutdown = dsps_shutdown;
+ drv->subsys_desc.powerup = dsps_powerup;
+ drv->subsys_desc.ramdump = dsps_ramdump,
+ drv->subsys_desc.crash_shutdown = dsps_crash_shutdown;
+
+ drv->subsys = subsys_register(&drv->subsys_desc);
+ if (IS_ERR(drv->subsys)) {
+ ret = PTR_ERR(drv->subsys);
+ goto err_subsys;
+ }
+
+ ret = smsm_state_cb_register(SMSM_DSPS_STATE, SMSM_RESET,
+ dsps_smsm_state_cb, drv);
+ if (ret)
+ goto err_smsm;
+
+ drv->wdog_irq = platform_get_irq(pdev, 0);
+ if (drv->wdog_irq >= 0) {
+ ret = devm_request_irq(&pdev->dev, drv->wdog_irq,
+ dsps_wdog_bite_irq, IRQF_TRIGGER_RISING,
+ "dsps_wdog", drv);
+ if (ret) {
+ dev_err(&pdev->dev, "request_irq failed\n");
+ goto err_smsm;
+ }
+ } else {
+ drv->wdog_irq = -1;
+ dev_dbg(&pdev->dev, "ppss_wdog not supported\n");
+ }
+
return 0;
+
+err_smsm:
+ subsys_unregister(drv->subsys);
+err_subsys:
+ destroy_ramdump_device(drv->smem_ramdump_dev);
+err_smem_ramdump:
+ destroy_ramdump_device(drv->ramdump_dev);
+err_ramdump:
+ msm_pil_unregister(drv->pil);
+ return ret;
}
static int __devexit pil_dsps_driver_exit(struct platform_device *pdev)
{
- struct pil_device *pil = platform_get_drvdata(pdev);
- msm_pil_unregister(pil);
+ struct dsps_data *drv = platform_get_drvdata(pdev);
+ smsm_state_cb_deregister(SMSM_DSPS_STATE, SMSM_RESET,
+ dsps_smsm_state_cb, drv);
+ subsys_unregister(drv->subsys);
+ destroy_ramdump_device(drv->smem_ramdump_dev);
+ destroy_ramdump_device(drv->ramdump_dev);
+ msm_pil_unregister(drv->pil);
return 0;
}
diff --git a/arch/arm/mach-msm/pil-mba.c b/arch/arm/mach-msm/pil-mba.c
index 0207f0b..8432328 100644
--- a/arch/arm/mach-msm/pil-mba.c
+++ b/arch/arm/mach-msm/pil-mba.c
@@ -23,8 +23,14 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/of.h>
+#include <linux/interrupt.h>
+
+#include <mach/subsystem_restart.h>
+#include <mach/msm_smsm.h>
+#include <mach/peripheral-loader.h>
#include "peripheral-loader.h"
+#include "ramdump.h"
#define RMB_MBA_COMMAND 0x08
#define RMB_MBA_STATUS 0x0C
@@ -41,6 +47,8 @@
#define PROXY_TIMEOUT_MS 10000
#define POLL_INTERVAL_US 50
+#define MAX_SSR_REASON_LEN 81U
+
static int modem_auth_timeout_ms = 10000;
module_param(modem_auth_timeout_ms, int, S_IRUGO | S_IWUSR);
@@ -49,7 +57,13 @@
void __iomem *metadata_base;
unsigned long metadata_phys;
struct pil_device *pil;
+ struct subsys_device *subsys;
+ struct subsys_desc subsys_desc;
struct clk *xo;
+ void *ramdump_dev;
+ void *smem_ramdump_dev;
+ bool crash_shutdown;
+ bool ignore_errors;
u32 img_length;
};
@@ -160,18 +174,142 @@
.shutdown = pil_mba_shutdown,
};
+#define subsys_to_drv(d) container_of(d, struct mba_data, subsys_desc)
+
+static void log_modem_sfr(void)
+{
+ u32 size;
+ char *smem_reason, reason[MAX_SSR_REASON_LEN];
+
+ smem_reason = smem_get_entry(SMEM_SSR_REASON_MSS0, &size);
+ if (!smem_reason || !size) {
+ pr_err("modem subsystem failure reason: (unknown, smem_get_entry failed).\n");
+ return;
+ }
+ if (!smem_reason[0]) {
+ pr_err("modem subsystem failure reason: (unknown, empty string found).\n");
+ return;
+ }
+
+ strlcpy(reason, smem_reason, min(size, sizeof(reason)));
+ pr_err("modem subsystem failure reason: %s.\n", reason);
+
+ smem_reason[0] = '\0';
+ wmb();
+}
+
+static void restart_modem(struct mba_data *drv)
+{
+ log_modem_sfr();
+ drv->ignore_errors = true;
+ subsystem_restart_dev(drv->subsys);
+}
+
+static void smsm_state_cb(void *data, uint32_t old_state, uint32_t new_state)
+{
+ struct mba_data *drv = data;
+
+ /* Ignore if we're the one that set SMSM_RESET */
+ if (drv->crash_shutdown)
+ return;
+
+ if (new_state & SMSM_RESET) {
+ pr_err("Probable fatal error on the modem.\n");
+ restart_modem(drv);
+ }
+}
+
+static int modem_shutdown(const struct subsys_desc *subsys)
+{
+ pil_force_shutdown("modem");
+ pil_force_shutdown("mba");
+ return 0;
+}
+
+static int modem_powerup(const struct subsys_desc *subsys)
+{
+ struct mba_data *drv = subsys_to_drv(subsys);
+ /*
+ * At this time, the modem is shutdown. Therefore this function cannot
+ * run concurrently with either the watchdog bite error handler or the
+ * SMSM callback, making it safe to unset the flag below.
+ */
+ drv->ignore_errors = 0;
+ pil_force_boot("mba");
+ pil_force_boot("modem");
+ return 0;
+}
+
+static void modem_crash_shutdown(const struct subsys_desc *subsys)
+{
+ struct mba_data *drv = subsys_to_drv(subsys);
+ drv->crash_shutdown = true;
+ smsm_reset_modem(SMSM_RESET);
+}
+
+static struct ramdump_segment modem_segments[] = {
+ {0x08400000, 0x0D100000 - 0x08400000},
+};
+
+static struct ramdump_segment smem_segments[] = {
+ {0x0FA00000, 0x0FC00000 - 0x0FA00000},
+};
+
+static int modem_ramdump(int enable, const struct subsys_desc *subsys)
+{
+ struct mba_data *drv = subsys_to_drv(subsys);
+ int ret;
+
+ if (!enable)
+ return 0;
+
+ pil_force_boot("mba");
+
+ ret = do_ramdump(drv->ramdump_dev, modem_segments,
+ ARRAY_SIZE(modem_segments));
+ if (ret < 0) {
+ pr_err("Unable to dump modem fw memory (rc = %d).\n", ret);
+ goto out;
+ }
+
+ ret = do_ramdump(drv->smem_ramdump_dev, smem_segments,
+ ARRAY_SIZE(smem_segments));
+ if (ret < 0) {
+ pr_err("Unable to dump smem memory (rc = %d).\n", ret);
+ goto out;
+ }
+
+out:
+ pil_force_shutdown("mba");
+ return ret;
+}
+
+static irqreturn_t modem_wdog_bite_irq(int irq, void *dev_id)
+{
+ struct mba_data *drv = dev_id;
+ if (drv->ignore_errors)
+ return IRQ_HANDLED;
+ pr_err("Watchdog bite received from modem software!\n");
+ restart_modem(drv);
+ return IRQ_HANDLED;
+}
+
static int __devinit pil_mba_driver_probe(struct platform_device *pdev)
{
struct mba_data *drv;
struct resource *res;
struct pil_desc *desc;
- int ret;
+ int ret, irq;
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
if (!drv)
return -ENOMEM;
platform_set_drvdata(pdev, drv);
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rmb_base");
if (!res)
return -EINVAL;
@@ -215,12 +353,71 @@
if (IS_ERR(drv->pil))
return PTR_ERR(drv->pil);
+ drv->subsys_desc.name = desc->name;
+ drv->subsys_desc.dev = &pdev->dev;
+ drv->subsys_desc.owner = THIS_MODULE;
+ drv->subsys_desc.shutdown = modem_shutdown;
+ drv->subsys_desc.powerup = modem_powerup;
+ drv->subsys_desc.ramdump = modem_ramdump;
+ drv->subsys_desc.crash_shutdown = modem_crash_shutdown;
+
+ drv->ramdump_dev = create_ramdump_device("modem");
+ if (!drv->ramdump_dev) {
+ pr_err("%s: Unable to create a modem ramdump device.\n",
+ __func__);
+ ret = -ENOMEM;
+ goto err_ramdump;
+ }
+
+ drv->smem_ramdump_dev = create_ramdump_device("smem-modem");
+ if (!drv->smem_ramdump_dev) {
+ pr_err("%s: Unable to create an smem ramdump device.\n",
+ __func__);
+ ret = -ENOMEM;
+ goto err_ramdump_smem;
+ }
+
+ drv->subsys = subsys_register(&drv->subsys_desc);
+ if (IS_ERR(drv->subsys)) {
+ goto err_subsys;
+ ret = PTR_ERR(drv->subsys);
+ }
+
+ ret = devm_request_irq(&pdev->dev, irq, modem_wdog_bite_irq,
+ IRQF_TRIGGER_RISING, "modem_wdog", drv);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Unable to request watchdog IRQ.\n");
+ goto err_irq;
+ }
+
+ ret = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_RESET,
+ smsm_state_cb, drv);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Unable to register SMSM callback!\n");
+ goto err_irq;
+ }
+
return 0;
+
+err_irq:
+ subsys_unregister(drv->subsys);
+err_subsys:
+ destroy_ramdump_device(drv->smem_ramdump_dev);
+err_ramdump_smem:
+ destroy_ramdump_device(drv->ramdump_dev);
+err_ramdump:
+ msm_pil_unregister(drv->pil);
+ return ret;
}
static int __devexit pil_mba_driver_exit(struct platform_device *pdev)
{
struct mba_data *drv = platform_get_drvdata(pdev);
+ smsm_state_cb_deregister(SMSM_MODEM_STATE, SMSM_RESET,
+ smsm_state_cb, drv);
+ subsys_unregister(drv->subsys);
+ destroy_ramdump_device(drv->smem_ramdump_dev);
+ destroy_ramdump_device(drv->ramdump_dev);
msm_pil_unregister(drv->pil);
return 0;
}
diff --git a/arch/arm/mach-msm/pil-pronto.c b/arch/arm/mach-msm/pil-pronto.c
index 1e39043..5685787 100644
--- a/arch/arm/mach-msm/pil-pronto.c
+++ b/arch/arm/mach-msm/pil-pronto.c
@@ -22,6 +22,14 @@
#include <linux/iopoll.h>
#include <linux/of.h>
#include <linux/regulator/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/workqueue.h>
+#include <linux/wcnss_wlan.h>
+
+#include <mach/subsystem_restart.h>
+#include <mach/peripheral-loader.h>
+#include <mach/msm_smsm.h>
#include "peripheral-loader.h"
#include "scm-pas.h"
@@ -67,8 +75,14 @@
void __iomem *axi_halt_base;
unsigned long start_addr;
struct pil_device *pil;
+ struct subsys_device *subsys;
+ struct subsys_desc subsys_desc;
struct clk *cxo;
struct regulator *vreg;
+ bool restart_inprogress;
+ bool crash;
+ struct delayed_work cancel_vote_work;
+ int irq;
};
static int pil_pronto_make_proxy_vote(struct pil_desc *pil)
@@ -225,6 +239,129 @@
.proxy_unvote = pil_pronto_remove_proxy_vote,
};
+#define subsys_to_drv(d) container_of(d, struct pronto_data, subsys_desc)
+
+static void log_wcnss_sfr(void)
+{
+ char *smem_reset_reason;
+ unsigned smem_reset_size;
+
+ smem_reset_reason = smem_get_entry(SMEM_SSR_REASON_WCNSS0,
+ &smem_reset_size);
+
+ if (!smem_reset_reason || !smem_reset_size) {
+ pr_err("wcnss subsystem failure reason:\n"
+ "(unknown, smem_get_entry failed)");
+ } else if (!smem_reset_reason[0]) {
+ pr_err("wcnss subsystem failure reason:\n"
+ "(unknown, init string found)");
+ } else {
+ pr_err("wcnss subsystem failure reason: %.81s\n",
+ smem_reset_reason);
+ memset(smem_reset_reason, 0, smem_reset_size);
+ wmb();
+ }
+}
+
+static void restart_wcnss(struct pronto_data *drv)
+{
+ log_wcnss_sfr();
+ subsystem_restart_dev(drv->subsys);
+}
+
+static void smsm_state_cb_hdlr(void *data, uint32_t old_state,
+ uint32_t new_state)
+{
+ struct pronto_data *drv = data;
+
+ drv->crash = true;
+
+ pr_err("wcnss smsm state changed\n");
+
+ if (!(new_state & SMSM_RESET))
+ return;
+
+ if (drv->restart_inprogress) {
+ pr_err("wcnss: Ignoring smsm reset req, restart in progress\n");
+ return;
+ }
+
+ drv->restart_inprogress = true;
+ restart_wcnss(drv);
+}
+
+static irqreturn_t wcnss_wdog_bite_irq_hdlr(int irq, void *dev_id)
+{
+ struct pronto_data *drv = dev_id;
+
+ drv->crash = true;
+
+ if (drv->restart_inprogress) {
+ pr_err("Ignoring wcnss bite irq, restart in progress\n");
+ return IRQ_HANDLED;
+ }
+
+ drv->restart_inprogress = true;
+ restart_wcnss(drv);
+
+ return IRQ_HANDLED;
+}
+
+static void wcnss_post_bootup(struct work_struct *work)
+{
+ struct platform_device *pdev = wcnss_get_platform_device();
+ struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
+
+ wcnss_wlan_power(&pdev->dev, pwlanconfig, WCNSS_WLAN_SWITCH_OFF);
+}
+
+static int wcnss_shutdown(const struct subsys_desc *subsys)
+{
+ struct pronto_data *drv = subsys_to_drv(subsys);
+
+ pil_force_shutdown("wcnss");
+ flush_delayed_work(&drv->cancel_vote_work);
+ wcnss_flush_delayed_boot_votes();
+ disable_irq_nosync(drv->irq);
+
+ return 0;
+}
+
+static int wcnss_powerup(const struct subsys_desc *subsys)
+{
+ struct pronto_data *drv = subsys_to_drv(subsys);
+ struct platform_device *pdev = wcnss_get_platform_device();
+ struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
+ int ret = -1;
+
+ if (pdev && pwlanconfig)
+ ret = wcnss_wlan_power(&pdev->dev, pwlanconfig,
+ WCNSS_WLAN_SWITCH_ON);
+ if (!ret) {
+ msleep(1000);
+ pil_force_boot("wcnss");
+ }
+ drv->restart_inprogress = false;
+ enable_irq(drv->irq);
+ schedule_delayed_work(&drv->cancel_vote_work, msecs_to_jiffies(5000));
+
+ return 0;
+}
+
+static void crash_shutdown(const struct subsys_desc *subsys)
+{
+ struct pronto_data *drv = subsys_to_drv(subsys);
+
+ pr_err("wcnss crash shutdown %d\n", drv->crash);
+ if (!drv->crash)
+ smsm_change_state(SMSM_APPS_STATE, SMSM_RESET, SMSM_RESET);
+}
+
+static int wcnss_ramdump(int enable, const struct subsys_desc *crashed_subsys)
+{
+ return 0;
+}
+
static int __devinit pil_pronto_probe(struct platform_device *pdev)
{
struct pronto_data *drv;
@@ -242,6 +379,10 @@
return -ENOMEM;
platform_set_drvdata(pdev, drv);
+ drv->irq = platform_get_irq(pdev, 0);
+ if (drv->irq < 0)
+ return drv->irq;
+
drv->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
if (!drv->base)
return -ENOMEM;
@@ -303,6 +444,32 @@
if (IS_ERR(drv->pil))
return PTR_ERR(drv->pil);
+ ret = smsm_state_cb_register(SMSM_WCNSS_STATE, SMSM_RESET,
+ smsm_state_cb_hdlr, drv);
+ if (ret < 0)
+ goto err_smsm;
+
+ drv->subsys_desc.name = desc->name;
+ drv->subsys_desc.dev = &pdev->dev;
+ drv->subsys_desc.owner = THIS_MODULE;
+ drv->subsys_desc.shutdown = wcnss_shutdown;
+ drv->subsys_desc.powerup = wcnss_powerup;
+ drv->subsys_desc.ramdump = wcnss_ramdump;
+ drv->subsys_desc.crash_shutdown = crash_shutdown;
+
+ INIT_DELAYED_WORK(&drv->cancel_vote_work, wcnss_post_bootup);
+
+ drv->subsys = subsys_register(&drv->subsys_desc);
+ if (IS_ERR(drv->subsys)) {
+ ret = PTR_ERR(drv->subsys);
+ goto err_subsys;
+ }
+
+ ret = devm_request_irq(&pdev->dev, drv->irq, wcnss_wdog_bite_irq_hdlr,
+ IRQF_TRIGGER_HIGH, "wcnss_wdog", drv);
+ if (ret < 0)
+ goto err_irq;
+
/* Initialize common_ss GDSCR to wait 4 cycles between states */
regval = readl_relaxed(drv->base + PRONTO_PMU_COMMON_GDSCR)
& PRONTO_PMU_COMMON_GDSCR_SW_COLLAPSE;
@@ -311,11 +478,22 @@
writel_relaxed(regval, drv->base + PRONTO_PMU_COMMON_GDSCR);
return 0;
+err_irq:
+ subsys_unregister(drv->subsys);
+err_subsys:
+ smsm_state_cb_deregister(SMSM_WCNSS_STATE, SMSM_RESET,
+ smsm_state_cb_hdlr, drv);
+err_smsm:
+ msm_pil_unregister(drv->pil);
+ return ret;
}
static int __devexit pil_pronto_remove(struct platform_device *pdev)
{
struct pronto_data *drv = platform_get_drvdata(pdev);
+ subsys_unregister(drv->subsys);
+ smsm_state_cb_deregister(SMSM_WCNSS_STATE, SMSM_RESET,
+ smsm_state_cb_hdlr, drv);
msm_pil_unregister(drv->pil);
return 0;
}
diff --git a/arch/arm/mach-msm/pil-q6v5-lpass.c b/arch/arm/mach-msm/pil-q6v5-lpass.c
index ed072ea..c48ea02 100644
--- a/arch/arm/mach-msm/pil-q6v5-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v5-lpass.c
@@ -18,14 +18,39 @@
#include <linux/err.h>
#include <linux/of.h>
#include <linux/clk.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+
#include <mach/clk.h>
+#include <mach/subsystem_restart.h>
+#include <mach/subsystem_notif.h>
+#include <mach/scm.h>
+#include <mach/peripheral-loader.h>
+
#include "peripheral-loader.h"
#include "pil-q6v5.h"
#include "scm-pas.h"
+#include "ramdump.h"
+#include "sysmon.h"
#define QDSP6SS_RST_EVB 0x010
#define PROXY_TIMEOUT_MS 10000
+struct lpass_data {
+ struct q6v5_data *q6;
+ struct subsys_device *subsys;
+ struct subsys_desc subsys_desc;
+ void *ramdump_dev;
+ int wdog_irq;
+ struct work_struct work;
+ void *riva_notif_hdle;
+ void *modem_notif_hdle;
+ int crash_shutdown;
+};
+
+#define subsys_to_drv(d) container_of(d, struct lpass_data, subsys_desc)
+
static int pil_lpass_enable_clks(struct q6v5_data *drv)
{
int ret;
@@ -71,7 +96,7 @@
static int pil_lpass_shutdown(struct pil_desc *pil)
{
- struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+ struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
pil_q6v5_halt_axi_port(pil, drv->axi_halt_base);
@@ -93,7 +118,7 @@
static int pil_lpass_reset(struct pil_desc *pil)
{
- struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+ struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
int ret;
ret = pil_lpass_enable_clks(drv);
@@ -147,38 +172,211 @@
.shutdown = pil_lpass_shutdown_trusted,
};
+static int riva_notifier_cb(struct notifier_block *this, unsigned long code,
+ void *ss_handle)
+{
+ int ret;
+ switch (code) {
+ case SUBSYS_BEFORE_SHUTDOWN:
+ pr_debug("%s: R-Notify: Shutdown started\n", __func__);
+ ret = sysmon_send_event(SYSMON_SS_LPASS, "wcnss",
+ SUBSYS_BEFORE_SHUTDOWN);
+ if (ret < 0)
+ pr_err("%s: sysmon_send_event error %d", __func__, ret);
+ break;
+ }
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block rnb = {
+ .notifier_call = riva_notifier_cb,
+};
+
+static int modem_notifier_cb(struct notifier_block *this, unsigned long code,
+ void *ss_handle)
+{
+ int ret;
+ switch (code) {
+ case SUBSYS_BEFORE_SHUTDOWN:
+ pr_debug("%s: M-Notify: Shutdown started\n", __func__);
+ ret = sysmon_send_event(SYSMON_SS_LPASS, "modem",
+ SUBSYS_BEFORE_SHUTDOWN);
+ if (ret < 0)
+ pr_err("%s: sysmon_send_event error %d", __func__, ret);
+ break;
+ }
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block mnb = {
+ .notifier_call = modem_notifier_cb,
+};
+
+static void adsp_log_failure_reason(void)
+{
+ char *reason;
+ char buffer[81];
+ unsigned size;
+
+ reason = smem_get_entry(SMEM_SSR_REASON_LPASS0, &size);
+
+ if (!reason) {
+ pr_err("ADSP subsystem failure reason: (unknown, smem_get_entry failed).");
+ return;
+ }
+
+ if (reason[0] == '\0') {
+ pr_err("ADSP subsystem failure reason: (unknown, init value found)");
+ return;
+ }
+
+ size = min(size, sizeof(buffer) - 1);
+ memcpy(buffer, reason, size);
+ buffer[size] = '\0';
+ pr_err("ADSP subsystem failure reason: %s", buffer);
+ memset((void *)reason, 0x0, size);
+ wmb();
+}
+
+static void restart_adsp(struct lpass_data *drv)
+{
+ adsp_log_failure_reason();
+ subsystem_restart_dev(drv->subsys);
+}
+
+static void adsp_fatal_fn(struct work_struct *work)
+{
+ struct lpass_data *drv = container_of(work, struct lpass_data, work);
+
+ pr_err("Watchdog bite received from ADSP!\n");
+ restart_adsp(drv);
+}
+
+static void adsp_smsm_state_cb(void *data, uint32_t old_state,
+ uint32_t new_state)
+{
+ struct lpass_data *drv = data;
+
+ /* Ignore if we're the one that set SMSM_RESET */
+ if (drv->crash_shutdown)
+ return;
+
+ if (new_state & SMSM_RESET) {
+ pr_err("%s: ADSP SMSM state changed to SMSM_RESET, new_state = %#x, old_state = %#x\n",
+ __func__, new_state, old_state);
+ restart_adsp(drv);
+ }
+}
+
+#define SCM_Q6_NMI_CMD 0x1
+
+static void send_q6_nmi(void)
+{
+ /* Send NMI to QDSP6 via an SCM call. */
+ scm_call_atomic1(SCM_SVC_UTIL, SCM_Q6_NMI_CMD, 0x1);
+ pr_debug("%s: Q6 NMI was sent.\n", __func__);
+}
+
+#define subsys_to_lpass(d) container_of(d, struct lpass_data, subsys_desc)
+
+static int adsp_shutdown(const struct subsys_desc *subsys)
+{
+ struct lpass_data *drv = subsys_to_lpass(subsys);
+
+ send_q6_nmi();
+ /* The write needs to go through before the q6 is shutdown. */
+ mb();
+ pil_force_shutdown("adsp");
+ disable_irq_nosync(drv->wdog_irq);
+
+ return 0;
+}
+
+static int adsp_powerup(const struct subsys_desc *subsys)
+{
+ struct lpass_data *drv = subsys_to_lpass(subsys);
+ int ret = 0;
+
+ if (get_restart_level() == RESET_SUBSYS_INDEPENDENT) {
+ pr_debug("%s: Wait for ADSP power up!", __func__);
+ msleep(10000);
+ }
+
+ ret = pil_force_boot("adsp");
+ enable_irq(drv->wdog_irq);
+
+ return ret;
+}
+
+static struct ramdump_segment segments = { 0xdc00000, 0x1800000 };
+
+static int adsp_ramdump(int enable, const struct subsys_desc *subsys)
+{
+ struct lpass_data *drv = subsys_to_lpass(subsys);
+
+ if (!enable)
+ return 0;
+ return do_ramdump(drv->ramdump_dev, &segments, 1);
+}
+
+static void adsp_crash_shutdown(const struct subsys_desc *subsys)
+{
+ struct lpass_data *drv = subsys_to_lpass(subsys);
+
+ drv->crash_shutdown = 1;
+ send_q6_nmi();
+}
+
+static irqreturn_t adsp_wdog_bite_irq(int irq, void *dev_id)
+{
+ struct lpass_data *drv = dev_id;
+
+ disable_irq_nosync(drv->wdog_irq);
+ schedule_work(&drv->work);
+
+ return IRQ_HANDLED;
+}
+
static int __devinit pil_lpass_driver_probe(struct platform_device *pdev)
{
- struct q6v5_data *drv;
+ struct lpass_data *drv;
+ struct q6v5_data *q6;
struct pil_desc *desc;
+ int ret;
- desc = pil_q6v5_init(pdev);
- if (IS_ERR(desc))
- return PTR_ERR(desc);
+ drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
+ if (!drv)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, drv);
- drv = platform_get_drvdata(pdev);
- if (drv == NULL)
- return -ENODEV;
+ drv->wdog_irq = platform_get_irq(pdev, 0);
+ if (drv->wdog_irq < 0)
+ return drv->wdog_irq;
- desc->ops = &pil_lpass_ops;
+ q6 = pil_q6v5_init(pdev);
+ if (IS_ERR(q6))
+ return PTR_ERR(q6);
+ drv->q6 = q6;
+
+ desc = &q6->desc;
desc->owner = THIS_MODULE;
desc->proxy_timeout = PROXY_TIMEOUT_MS;
- drv->core_clk = devm_clk_get(&pdev->dev, "core_clk");
- if (IS_ERR(drv->core_clk))
- return PTR_ERR(drv->core_clk);
+ q6->core_clk = devm_clk_get(&pdev->dev, "core_clk");
+ if (IS_ERR(q6->core_clk))
+ return PTR_ERR(q6->core_clk);
- drv->ahb_clk = devm_clk_get(&pdev->dev, "iface_clk");
- if (IS_ERR(drv->ahb_clk))
- return PTR_ERR(drv->ahb_clk);
+ q6->ahb_clk = devm_clk_get(&pdev->dev, "iface_clk");
+ if (IS_ERR(q6->ahb_clk))
+ return PTR_ERR(q6->ahb_clk);
- drv->axi_clk = devm_clk_get(&pdev->dev, "bus_clk");
- if (IS_ERR(drv->axi_clk))
- return PTR_ERR(drv->axi_clk);
+ q6->axi_clk = devm_clk_get(&pdev->dev, "bus_clk");
+ if (IS_ERR(q6->axi_clk))
+ return PTR_ERR(q6->axi_clk);
- drv->reg_clk = devm_clk_get(&pdev->dev, "reg_clk");
- if (IS_ERR(drv->reg_clk))
- return PTR_ERR(drv->reg_clk);
+ q6->reg_clk = devm_clk_get(&pdev->dev, "reg_clk");
+ if (IS_ERR(q6->reg_clk))
+ return PTR_ERR(q6->reg_clk);
if (pas_supported(PAS_Q6) > 0) {
desc->ops = &pil_lpass_ops_trusted;
@@ -188,17 +386,79 @@
dev_info(&pdev->dev, "using non-secure boot\n");
}
- drv->pil = msm_pil_register(desc);
- if (IS_ERR(drv->pil))
- return PTR_ERR(drv->pil);
+ drv->q6->pil = msm_pil_register(desc);
+ if (IS_ERR(drv->q6->pil))
+ return PTR_ERR(drv->q6->pil);
+ drv->subsys_desc.name = desc->name;
+ drv->subsys_desc.owner = THIS_MODULE;
+ drv->subsys_desc.dev = &pdev->dev;
+ drv->subsys_desc.shutdown = adsp_shutdown;
+ drv->subsys_desc.powerup = adsp_powerup;
+ drv->subsys_desc.ramdump = adsp_ramdump;
+ drv->subsys_desc.crash_shutdown = adsp_crash_shutdown;
+
+ INIT_WORK(&drv->work, adsp_fatal_fn);
+
+ drv->ramdump_dev = create_ramdump_device("adsp");
+ if (!drv->ramdump_dev) {
+ ret = -ENOMEM;
+ goto err_ramdump;
+ }
+
+ drv->subsys = subsys_register(&drv->subsys_desc);
+ if (IS_ERR(drv->subsys)) {
+ ret = PTR_ERR(drv->subsys);
+ goto err_subsys;
+ }
+
+ ret = devm_request_irq(&pdev->dev, drv->wdog_irq, adsp_wdog_bite_irq,
+ IRQF_TRIGGER_RISING, dev_name(&pdev->dev), drv);
+ if (ret)
+ goto err_irq;
+
+ ret = smsm_state_cb_register(SMSM_Q6_STATE, SMSM_RESET,
+ adsp_smsm_state_cb, drv);
+ if (ret < 0)
+ goto err_smsm;
+
+ drv->riva_notif_hdle = subsys_notif_register_notifier("riva", &rnb);
+ if (IS_ERR(drv->riva_notif_hdle)) {
+ ret = PTR_ERR(drv->riva_notif_hdle);
+ goto err_notif_riva;
+ }
+
+ drv->modem_notif_hdle = subsys_notif_register_notifier("modem", &mnb);
+ if (IS_ERR(drv->modem_notif_hdle)) {
+ ret = PTR_ERR(drv->modem_notif_hdle);
+ goto err_notif_modem;
+ }
+ return 0;
+err_notif_modem:
+ subsys_notif_unregister_notifier(drv->riva_notif_hdle, &rnb);
+err_notif_riva:
+ smsm_state_cb_deregister(SMSM_Q6_STATE, SMSM_RESET,
+ adsp_smsm_state_cb, drv);
+err_smsm:
+err_irq:
+ subsys_unregister(drv->subsys);
+err_subsys:
+ destroy_ramdump_device(drv->ramdump_dev);
+err_ramdump:
+ msm_pil_unregister(drv->q6->pil);
return 0;
}
static int __devexit pil_lpass_driver_exit(struct platform_device *pdev)
{
- struct q6v5_data *drv = platform_get_drvdata(pdev);
- msm_pil_unregister(drv->pil);
+ struct lpass_data *drv = platform_get_drvdata(pdev);
+ subsys_notif_unregister_notifier(drv->riva_notif_hdle, &rnb);
+ subsys_notif_unregister_notifier(drv->modem_notif_hdle, &mnb);
+ smsm_state_cb_deregister(SMSM_Q6_STATE, SMSM_RESET,
+ adsp_smsm_state_cb, drv);
+ subsys_unregister(drv->subsys);
+ destroy_ramdump_device(drv->ramdump_dev);
+ msm_pil_unregister(drv->q6->pil);
return 0;
}
diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c
index 9ff1234..f3c731f 100644
--- a/arch/arm/mach-msm/pil-q6v5-mss.c
+++ b/arch/arm/mach-msm/pil-q6v5-mss.c
@@ -57,10 +57,10 @@
static int pbl_mba_boot_timeout_ms = 100;
module_param(pbl_mba_boot_timeout_ms, int, S_IRUGO | S_IWUSR);
-static int pil_mss_power_up(struct device *dev)
+static int pil_mss_power_up(struct q6v5_data *drv)
{
int ret;
- struct q6v5_data *drv = dev_get_drvdata(dev);
+ struct device *dev = drv->desc.dev;
ret = regulator_enable(drv->vreg);
if (ret)
@@ -69,10 +69,8 @@
return ret;
}
-static int pil_mss_power_down(struct device *dev)
+static int pil_mss_power_down(struct q6v5_data *drv)
{
- struct q6v5_data *drv = dev_get_drvdata(dev);
-
return regulator_disable(drv->vreg);
}
@@ -107,9 +105,9 @@
clk_disable_unprepare(drv->ahb_clk);
}
-static int wait_for_mba_ready(struct device *dev)
+static int wait_for_mba_ready(struct q6v5_data *drv)
{
- struct q6v5_data *drv = dev_get_drvdata(dev);
+ struct device *dev = drv->desc.dev;
int ret;
u32 status;
@@ -143,7 +141,7 @@
static int pil_mss_shutdown(struct pil_desc *pil)
{
- struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+ struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
pil_q6v5_halt_axi_port(pil, drv->axi_halt_base + MSS_Q6_HALT_BASE);
pil_q6v5_halt_axi_port(pil, drv->axi_halt_base + MSS_MODEM_HALT_BASE);
@@ -155,13 +153,13 @@
* writes performed during the shutdown succeed.
*/
if (drv->is_booted == false) {
- pil_mss_power_up(pil->dev);
+ pil_mss_power_up(drv);
pil_mss_enable_clks(drv);
}
pil_q6v5_shutdown(pil);
pil_mss_disable_clks(drv);
- pil_mss_power_down(pil->dev);
+ pil_mss_power_down(drv);
writel_relaxed(1, drv->restart_reg);
@@ -172,7 +170,7 @@
static int pil_mss_reset(struct pil_desc *pil)
{
- struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+ struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
int ret;
/* Deassert reset to subsystem and wait for propagation */
@@ -184,7 +182,7 @@
* Bring subsystem out of reset and enable required
* regulators and clocks.
*/
- ret = pil_mss_power_up(pil->dev);
+ ret = pil_mss_power_up(drv);
if (ret)
goto err_power;
@@ -211,7 +209,7 @@
/* Wait for MBA to start. Check for PBL and MBA errors while waiting. */
if (drv->self_auth) {
- ret = wait_for_mba_ready(pil->dev);
+ ret = wait_for_mba_ready(drv);
if (ret)
goto err_auth;
}
@@ -225,7 +223,7 @@
err_q6v5_reset:
pil_mss_disable_clks(drv);
err_clks:
- pil_mss_power_down(pil->dev);
+ pil_mss_power_down(drv);
err_power:
return ret;
}
@@ -245,13 +243,12 @@
struct resource *res;
int ret;
- desc = pil_q6v5_init(pdev);
- if (IS_ERR(desc))
- return PTR_ERR(desc);
- drv = platform_get_drvdata(pdev);
- if (drv == NULL)
- return -ENODEV;
+ drv = pil_q6v5_init(pdev);
+ if (IS_ERR(drv))
+ return PTR_ERR(drv);
+ platform_set_drvdata(pdev, drv);
+ desc = &drv->desc;
desc->ops = &pil_mss_ops;
desc->owner = THIS_MODULE;
desc->proxy_timeout = PROXY_TIMEOUT_MS;
diff --git a/arch/arm/mach-msm/pil-q6v5.c b/arch/arm/mach-msm/pil-q6v5.c
index f4e8844..70a12de 100644
--- a/arch/arm/mach-msm/pil-q6v5.c
+++ b/arch/arm/mach-msm/pil-q6v5.c
@@ -61,7 +61,7 @@
int pil_q6v5_make_proxy_votes(struct pil_desc *pil)
{
int ret;
- struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+ struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
ret = clk_prepare_enable(drv->xo);
if (ret) {
@@ -74,7 +74,7 @@
void pil_q6v5_remove_proxy_votes(struct pil_desc *pil)
{
- struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+ struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
clk_disable_unprepare(drv->xo);
}
EXPORT_SYMBOL(pil_q6v5_remove_proxy_votes);
@@ -104,7 +104,7 @@
size_t size)
{
const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
- struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+ struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
drv->start_addr = ehdr->e_entry;
return 0;
}
@@ -113,7 +113,7 @@
void pil_q6v5_shutdown(struct pil_desc *pil)
{
u32 val;
- struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+ struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
/* Turn off core clock */
val = readl_relaxed(drv->reg_base + QDSP6SS_GFMUX_CTL);
@@ -145,7 +145,7 @@
int pil_q6v5_reset(struct pil_desc *pil)
{
- struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+ struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
u32 val;
/* Assert resets, stop core */
@@ -193,7 +193,7 @@
}
EXPORT_SYMBOL(pil_q6v5_reset);
-struct pil_desc __devinit *pil_q6v5_init(struct platform_device *pdev)
+struct q6v5_data __devinit *pil_q6v5_init(struct platform_device *pdev)
{
struct q6v5_data *drv;
struct resource *res;
@@ -203,7 +203,6 @@
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
if (!drv)
return ERR_PTR(-ENOMEM);
- platform_set_drvdata(pdev, drv);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qdsp6_base");
if (!res)
@@ -218,10 +217,7 @@
if (!drv->axi_halt_base)
return ERR_PTR(-ENOMEM);
- desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
- if (!desc)
- return ERR_PTR(-ENOMEM);
-
+ desc = &drv->desc;
ret = of_property_read_string(pdev->dev.of_node, "qcom,firmware-name",
&desc->name);
if (ret)
@@ -233,6 +229,6 @@
desc->dev = &pdev->dev;
- return desc;
+ return drv;
}
EXPORT_SYMBOL(pil_q6v5_init);
diff --git a/arch/arm/mach-msm/pil-q6v5.h b/arch/arm/mach-msm/pil-q6v5.h
index 03f93fa..f176d2d 100644
--- a/arch/arm/mach-msm/pil-q6v5.h
+++ b/arch/arm/mach-msm/pil-q6v5.h
@@ -13,10 +13,11 @@
#ifndef __MSM_PIL_Q6V5_H
#define __MSM_PIL_Q6V5_H
+#include "peripheral-loader.h"
+
struct regulator;
struct clk;
struct pil_device;
-struct pil_desc;
struct platform_device;
struct q6v5_data {
@@ -36,6 +37,7 @@
bool is_booted;
int self_auth;
struct pil_device *pil;
+ struct pil_desc desc;
};
int pil_q6v5_make_proxy_votes(struct pil_desc *pil);
@@ -45,6 +47,6 @@
size_t size);
void pil_q6v5_shutdown(struct pil_desc *pil);
int pil_q6v5_reset(struct pil_desc *pil);
-struct pil_desc *pil_q6v5_init(struct platform_device *pdev);
+struct q6v5_data *pil_q6v5_init(struct platform_device *pdev);
#endif
diff --git a/arch/arm/mach-msm/wcnss-ssr-8974.c b/arch/arm/mach-msm/wcnss-ssr-8974.c
deleted file mode 100644
index 8841b52..0000000
--- a/arch/arm/mach-msm/wcnss-ssr-8974.c
+++ /dev/null
@@ -1,200 +0,0 @@
-/* Copyright (c) 2012, The Linux Foundation. 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/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/err.h>
-#include <linux/platform_device.h>
-#include <linux/workqueue.h>
-#include <linux/wcnss_wlan.h>
-#include <linux/delay.h>
-#include <mach/peripheral-loader.h>
-#include <mach/subsystem_restart.h>
-#include <mach/msm_smsm.h>
-
-#define MODULE_NAME "wcnss_8974"
-#define MAX_SSR_REASON_LEN 0x51
-
-static int ss_restart_inprogress;
-static int wcnss_crash;
-static struct subsys_device *wcnss_ssr_dev;
-static struct delayed_work cancel_vote_work;
-
-#define WCNSS_APSS_WDOG_BITE_RESET_RDY_IRQ 181
-
-static void log_wcnss_sfr(void)
-{
- char *smem_reset_reason;
- char buffer[MAX_SSR_REASON_LEN];
- unsigned smem_reset_size;
- unsigned size;
-
- smem_reset_reason = smem_get_entry(SMEM_SSR_REASON_WCNSS0,
- &smem_reset_size);
-
- if (!smem_reset_reason || !smem_reset_size) {
- pr_err("%s: wcnss subsystem failure reason: %s\n",
- __func__, "(unknown, smem_get_entry failed)");
- } else if (!smem_reset_reason[0]) {
- pr_err("%s: wcnss subsystem failure reason: %s\n",
- __func__, "(unknown, init string found)");
- } else {
- size = smem_reset_size < MAX_SSR_REASON_LEN ? smem_reset_size :
- (MAX_SSR_REASON_LEN - 1);
- memcpy(buffer, smem_reset_reason, size);
- buffer[size] = '\0';
- pr_err("%s: wcnss subsystem failure reason: %s\n",
- __func__, buffer);
- memset(smem_reset_reason, 0, smem_reset_size);
- wmb();
- }
-}
-
-static void restart_wcnss(void)
-{
- log_wcnss_sfr();
- subsystem_restart("wcnss");
-}
-
-static void smsm_state_cb_hdlr(void *data, uint32_t old_state,
- uint32_t new_state)
-{
- wcnss_crash = true;
-
- pr_err("%s: smsm state changed\n", MODULE_NAME);
-
- if (!(new_state & SMSM_RESET))
- return;
-
- if (ss_restart_inprogress) {
- pr_err("%s: Ignoring smsm reset req, restart in progress\n",
- MODULE_NAME);
- return;
- }
-
- ss_restart_inprogress = true;
- restart_wcnss();
-}
-
-
-static irqreturn_t wcnss_wdog_bite_irq_hdlr(int irq, void *dev_id)
-{
- wcnss_crash = true;
-
- if (ss_restart_inprogress) {
- pr_err("%s: Ignoring wcnss bite irq, restart in progress\n",
- MODULE_NAME);
- return IRQ_HANDLED;
- }
-
- ss_restart_inprogress = true;
- restart_wcnss();
-
- return IRQ_HANDLED;
-}
-
-static void wcnss_post_bootup(struct work_struct *work)
-{
- struct platform_device *pdev = wcnss_get_platform_device();
- struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
-
- pr_debug(MODULE_NAME ": Cancel APPS vote for Iris & Pronto\n");
-
- wcnss_wlan_power(&pdev->dev, pwlanconfig,
- WCNSS_WLAN_SWITCH_OFF);
-}
-
-static int wcnss_shutdown(const struct subsys_desc *subsys)
-{
- pil_force_shutdown("wcnss");
- flush_delayed_work(&cancel_vote_work);
- wcnss_flush_delayed_boot_votes();
- disable_irq_nosync(WCNSS_APSS_WDOG_BITE_RESET_RDY_IRQ);
-
- return 0;
-}
-
-static int wcnss_powerup(const struct subsys_desc *subsys)
-{
- struct platform_device *pdev = wcnss_get_platform_device();
- struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
- int ret = -1;
-
- if (pdev && pwlanconfig)
- ret = wcnss_wlan_power(&pdev->dev, pwlanconfig,
- WCNSS_WLAN_SWITCH_ON);
- if (!ret) {
- msleep(1000);
- pil_force_boot("wcnss");
- }
- ss_restart_inprogress = false;
- enable_irq(WCNSS_APSS_WDOG_BITE_RESET_RDY_IRQ);
- schedule_delayed_work(&cancel_vote_work, msecs_to_jiffies(5000));
-
- return 0;
-}
-
-/* wcnss crash handler */
-static void wcnss_crash_shutdown(const struct subsys_desc *subsys)
-{
- pr_err("%s: crash shutdown : %d\n", MODULE_NAME, wcnss_crash);
- if (wcnss_crash != true)
- smsm_change_state(SMSM_APPS_STATE, SMSM_RESET, SMSM_RESET);
-}
-
-static int wcnss_ramdump(int enable,
- const struct subsys_desc *crashed_subsys)
-{
- return 0;
-}
-
-static struct subsys_desc wcnss_ssr = {
- .name = "wcnss",
- .shutdown = wcnss_shutdown,
- .powerup = wcnss_powerup,
- .ramdump = wcnss_ramdump,
- .crash_shutdown = wcnss_crash_shutdown
-};
-
-static int __init wcnss_ssr_init(void)
-{
- int ret;
-
- ret = smsm_state_cb_register(SMSM_WCNSS_STATE, SMSM_RESET,
- smsm_state_cb_hdlr, 0);
- if (ret < 0) {
- pr_err("%s: Unable to register smsm callback for wcnss Reset! %d\n",
- MODULE_NAME, ret);
- goto out;
- }
- ret = request_irq(WCNSS_APSS_WDOG_BITE_RESET_RDY_IRQ,
- wcnss_wdog_bite_irq_hdlr, IRQF_TRIGGER_HIGH,
- "wcnss_wdog", NULL);
-
- if (ret < 0) {
- pr_err("%s: Unable to register for wcnss bite interrupt (%d)\n",
- MODULE_NAME, ret);
- goto out;
- }
- wcnss_ssr_dev = subsys_register(&wcnss_ssr);
- if (IS_ERR(wcnss_ssr_dev))
- return PTR_ERR(wcnss_ssr_dev);
-
- INIT_DELAYED_WORK(&cancel_vote_work, wcnss_post_bootup);
-
- pr_info("%s: module initialized\n", MODULE_NAME);
-out:
- return ret;
-}
-
-arch_initcall(wcnss_ssr_init);
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 4eca776..41fd7aa 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -2263,7 +2263,7 @@
static uint io_cnt;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
- struct adreno_context *adreno_ctx = context->devctxt;
+ struct adreno_context *adreno_ctx = context ? context->devctxt : NULL;
int retries = 0;
unsigned int ts_issued;
unsigned int context_id = _get_context_id(context);
@@ -2286,7 +2286,8 @@
* again after 'retry_ts_cmp_msecs' milliseconds.
*/
if (timestamp_cmp(timestamp, ts_issued) > 0) {
- if (!(adreno_ctx->flags & CTXT_FLAGS_USER_GENERATED_TS)) {
+ if (adreno_ctx == NULL ||
+ !(adreno_ctx->flags & CTXT_FLAGS_USER_GENERATED_TS)) {
KGSL_DRV_ERR(device,
"Cannot wait for invalid ts <%d:0x%x>, "
"last issued ts <%d:0x%x>\n",
diff --git a/drivers/iommu/msm_iommu.c b/drivers/iommu/msm_iommu.c
index df66a3a..63a027b 100644
--- a/drivers/iommu/msm_iommu.c
+++ b/drivers/iommu/msm_iommu.c
@@ -1122,7 +1122,12 @@
}
SET_FSR(base, num, fsr);
- SET_RESUME(base, num, 1);
+ /*
+ * Only resume fetches if the registered fault handler
+ * allows it
+ */
+ if (ret != -EBUSY)
+ SET_RESUME(base, num, 1);
ret = IRQ_HANDLED;
} else
diff --git a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
index fda03de..a608e1ab 100644
--- a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
@@ -486,7 +486,7 @@
|| CONTAINS(buff_off, size, temp->buff_off)
|| OVERLAPS(buff_off, size,
temp->buff_off, temp->size))) {
- dprintk(VIDC_WARN,
+ dprintk(VIDC_INFO,
"This memory region is already mapped\n");
ret = temp;
break;
@@ -509,7 +509,7 @@
if (!list_empty(list)) {
list_for_each_entry(temp, list, list) {
if (temp && temp->fd == fd) {
- dprintk(VIDC_ERR, "Found same fd buffer\n");
+ dprintk(VIDC_INFO, "Found same fd buffer\n");
ret = temp;
break;
}
@@ -709,7 +709,7 @@
b->m.planes[i].reserved[1],
b->m.planes[i].length);
if (binfo) {
- dprintk(VIDC_WARN,
+ dprintk(VIDC_INFO,
"This memory region has already been prepared\n");
rc = -EINVAL;
goto exit;
@@ -1153,7 +1153,7 @@
ocmem_notifier_register(OCMEM_VIDEO, &ocmem->vidc_ocmem_nb);
if (!ocmem->handle) {
dprintk(VIDC_WARN, "Failed to register OCMEM notifier.");
- dprintk(VIDC_WARN, " Performance will be impacted\n");
+ dprintk(VIDC_INFO, " Performance will be impacted\n");
}
return rc;
fail_register_domains:
diff --git a/drivers/media/video/msm_vidc/msm_vdec.c b/drivers/media/video/msm_vidc/msm_vdec.c
index e7b5caf..49b28ae 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.c
+++ b/drivers/media/video/msm_vidc/msm_vdec.c
@@ -344,7 +344,7 @@
0, 0);
if (!inst->extradata_handle) {
dprintk(VIDC_ERR,
- "Failed to allocate extradta memory\n");
+ "Failed to allocate extradata memory\n");
rc = -ENOMEM;
break;
}
@@ -436,7 +436,7 @@
rc = vb2_dqbuf(&q->vb2_bufq, b, true);
mutex_unlock(&q->lock);
if (rc)
- dprintk(VIDC_WARN, "Failed to dqbuf, %d\n", rc);
+ dprintk(VIDC_DBG, "Failed to dqbuf, %d\n", rc);
return rc;
}
@@ -622,7 +622,7 @@
sizeof(f->description));
f->pixelformat = fmt->fourcc;
} else {
- dprintk(VIDC_WARN, "No more formats found\n");
+ dprintk(VIDC_INFO, "No more formats found\n");
rc = -EINVAL;
}
return rc;
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index af9a5a2..d89ab9f 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -234,7 +234,7 @@
k++;
}
if (i == size) {
- dprintk(VIDC_WARN, "Format not found\n");
+ dprintk(VIDC_INFO, "Format not found\n");
return NULL;
}
return &fmt[i];
@@ -252,7 +252,7 @@
break;
}
if (i == size) {
- dprintk(VIDC_WARN, "Format not found\n");
+ dprintk(VIDC_INFO, "Format not found\n");
return NULL;
}
return &fmt[i];
@@ -1097,7 +1097,7 @@
}
if (msm_comm_scale_clocks(core, inst->session_type)) {
dprintk(VIDC_WARN, "Failed to scale clocks while closing\n");
- dprintk(VIDC_WARN, "Power might be impacted\n");
+ dprintk(VIDC_INFO, "Power might be impacted\n");
}
if (list_empty(&core->instances)) {
msm_comm_unset_ocmem(core);
@@ -1261,7 +1261,7 @@
rc = vidc_hal_session_start((void *) inst->session);
if (rc) {
dprintk(VIDC_ERR,
- "Failed to send load resources\n");
+ "Failed to send start\n");
goto exit;
}
change_inst_state(inst, MSM_VIDC_START);
@@ -1307,7 +1307,7 @@
rc = vidc_hal_session_release_res((void *) inst->session);
if (rc) {
dprintk(VIDC_ERR,
- "Failed to send load resources\n");
+ "Failed to send release resources\n");
goto exit;
}
change_inst_state(inst, MSM_VIDC_RELEASE_RESOURCES);
@@ -1331,7 +1331,7 @@
rc = vidc_hal_session_end((void *) inst->session);
if (rc) {
dprintk(VIDC_ERR,
- "Failed to send load resources\n");
+ "Failed to send close\n");
goto exit;
}
change_inst_state(inst, MSM_VIDC_OPEN);
diff --git a/drivers/media/video/msm_vidc/vidc_hal.c b/drivers/media/video/msm_vidc/vidc_hal.c
index 8ac35d9..aa30644 100644
--- a/drivers/media/video/msm_vidc/vidc_hal.c
+++ b/drivers/media/video/msm_vidc/vidc_hal.c
@@ -248,7 +248,7 @@
struct vidc_iface_q_info *qinfo;
if (!info || !packet || !pb_tx_req_is_set) {
- dprintk(VIDC_ERR, "Invalid Params in ");
+ dprintk(VIDC_ERR, "Invalid Params");
return -EINVAL;
}
@@ -311,11 +311,11 @@
int rc = 0;
if (!mem || !clnt || !size) {
- dprintk(VIDC_ERR, "Invalid Params in ");
+ dprintk(VIDC_ERR, "Invalid Params");
return -EINVAL;
}
vmem = (struct vidc_mem_addr *)mem;
- dprintk(VIDC_WARN, "start to alloc: size:%d, Flags: %d", size, flags);
+ dprintk(VIDC_INFO, "start to alloc: size:%d, Flags: %d", size, flags);
alloc = msm_smem_alloc(clnt, size, align, flags, domain, 1, 1);
dprintk(VIDC_DBG, "Alloc done");
@@ -390,7 +390,7 @@
int result = -EPERM;
if (!device || !pkt) {
- dprintk(VIDC_ERR, "Invalid Params in ");
+ dprintk(VIDC_ERR, "Invalid Params");
return -EINVAL;
}
@@ -422,7 +422,7 @@
struct vidc_iface_q_info *q_info;
if (!pkt) {
- dprintk(VIDC_ERR, "Invalid Params in ");
+ dprintk(VIDC_ERR, "Invalid Params");
return -EINVAL;
}
spin_lock(&device->read_lock);
@@ -456,7 +456,7 @@
struct vidc_iface_q_info *q_info;
if (!pkt) {
- dprintk(VIDC_ERR, "Invalid Params in ");
+ dprintk(VIDC_ERR, "Invalid Params");
return -EINVAL;
}
spin_lock(&device->read_lock);
@@ -760,7 +760,7 @@
"times: %d interrupt_status: %d",
(u32) device, ++device->reg_count, intr_status);
} else {
- dprintk(VIDC_WARN, "SPURIOUS_INTR for device: 0x%x: "
+ dprintk(VIDC_INFO, "SPURIOUS_INTR for device: 0x%x: "
"times: %d interrupt_status: %d",
(u32) device, ++device->spur_count, intr_status);
}
@@ -1625,7 +1625,7 @@
if (device) {
dev = device;
} else {
- dprintk(VIDC_ERR, ":invalid device");
+ dprintk(VIDC_ERR, "invalid device");
return NULL;
}
@@ -1658,7 +1658,7 @@
if (session_id) {
session = session_id;
} else {
- dprintk(VIDC_ERR, ":invalid session");
+ dprintk(VIDC_ERR, "invalid session");
return -ENODEV;
}
@@ -1694,7 +1694,7 @@
struct hal_session *session;
if (!sess || !buffer_info) {
- dprintk(VIDC_ERR, "Invalid Params in ");
+ dprintk(VIDC_ERR, "Invalid Params");
return -EINVAL;
} else {
session = sess;
@@ -1758,7 +1758,7 @@
struct hal_session *session;
if (!sess || !buffer_info) {
- dprintk(VIDC_ERR, "Invalid Params in ");
+ dprintk(VIDC_ERR, "Invalid Params");
return -EINVAL;
} else {
session = sess;
@@ -1850,7 +1850,7 @@
struct hal_session *session;
if (!sess || !input_frame) {
- dprintk(VIDC_ERR, "Invalid Params in ");
+ dprintk(VIDC_ERR, "Invalid Params");
return -EINVAL;
} else {
session = sess;
@@ -1908,7 +1908,7 @@
struct hal_session *session;
if (!sess || !output_frame) {
- dprintk(VIDC_ERR, "Invalid Params in ");
+ dprintk(VIDC_ERR, "Invalid Params");
return -EINVAL;
} else {
session = sess;
@@ -1940,7 +1940,7 @@
struct hal_session *session;
if (!sess || !seq_hdr) {
- dprintk(VIDC_ERR, "Invalid Params in ");
+ dprintk(VIDC_ERR, "Invalid Params");
return -EINVAL;
} else {
session = sess;
@@ -1967,7 +1967,7 @@
struct hal_session *session;
if (!sess || !seq_hdr) {
- dprintk(VIDC_ERR, "Invalid Params in ");
+ dprintk(VIDC_ERR, "Invalid Params");
return -EINVAL;
} else {
session = sess;
@@ -1994,7 +1994,7 @@
if (sess) {
session = sess;
} else {
- dprintk(VIDC_ERR, ":invalid session");
+ dprintk(VIDC_ERR, "invalid session");
return -ENODEV;
}
@@ -2017,7 +2017,7 @@
if (sess) {
session = sess;
} else {
- dprintk(VIDC_ERR, ":invalid session");
+ dprintk(VIDC_ERR, "invalid session");
return -ENODEV;
}
diff --git a/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c b/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
index 795024d..a0dd93c 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
+++ b/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
@@ -530,7 +530,7 @@
struct hal_session *session;
if (!msg_hdr) {
- dprintk(VIDC_ERR, "Invalid Params in ");
+ dprintk(VIDC_ERR, "Invalid Params");
return;
}
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index 65537e4..62f1a93 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -1205,9 +1205,6 @@
pr_err("%s: error, initializing device failed\n", __func__);
goto err_slim_add;
}
-
- wcd9xxx_init_slimslave(wcd9xxx, wcd9xxx_pgd_la);
-
#ifdef CONFIG_DEBUG_FS
debugCodec = wcd9xxx;
diff --git a/drivers/mfd/wcd9xxx-slimslave.c b/drivers/mfd/wcd9xxx-slimslave.c
index b4cf435..6e6de37 100644
--- a/drivers/mfd/wcd9xxx-slimslave.c
+++ b/drivers/mfd/wcd9xxx-slimslave.c
@@ -16,44 +16,20 @@
#define WCD9XXX_CHIP_ID_TAIKO 0x00000201
-struct wcd9xxx_slim_sch_rx {
- u32 sph;
- u32 ch_num;
- u16 ch_h;
- u16 grph;
-};
-
-struct wcd9xxx_slim_sch_tx {
- u32 sph;
- u32 ch_num;
- u16 ch_h;
- u16 grph;
-};
-
struct wcd9xxx_slim_sch {
- struct wcd9xxx_slim_sch_rx rx[SLIM_MAX_RX_PORTS];
- struct wcd9xxx_slim_sch_tx tx[SLIM_MAX_TX_PORTS];
-
- u16 rx_port_start_offset;
- u16 num_rx_slave_port;
- u16 port_ch_0_start_port_id;
- u16 port_ch_0_end_port_id;
- u16 pgd_tx_port_ch_1_end_port_id;
u16 rx_port_ch_reg_base;
u16 port_tx_cfg_reg_base;
u16 port_rx_cfg_reg_base;
- int number_of_tx_slave_dev_ports;
- int number_of_rx_slave_dev_ports;
};
static struct wcd9xxx_slim_sch sh_ch;
-static int wcd9xxx_alloc_slim_sh_ch_rx(struct wcd9xxx *wcd9xxx,
- u8 wcd9xxx_pgd_la);
-static int wcd9xxx_alloc_slim_sh_ch_tx(struct wcd9xxx *wcd9xxx,
- u8 wcd9xxx_pgd_la);
-static int wcd9xxx_dealloc_slim_sh_ch_rx(struct wcd9xxx *wcd9xxx);
-static int wcd9xxx_dealloc_slim_sh_ch_tx(struct wcd9xxx *wcd9xxx);
+static int wcd9xxx_alloc_slim_sh_ch(struct wcd9xxx *wcd9xxx,
+ u8 wcd9xxx_pgd_la, u32 cnt,
+ struct wcd9xxx_ch *channels, u32 path);
+
+static int wcd9xxx_dealloc_slim_sh_ch(struct slim_device *slim,
+ u32 cnt, struct wcd9xxx_ch *channels);
static int wcd9xxx_configure_ports(struct wcd9xxx *wcd9xxx)
{
@@ -65,55 +41,27 @@
id = cpu_to_be32(id);
pr_debug("%s: chip id 0x%08x\n", __func__, id);
if (id != WCD9XXX_CHIP_ID_TAIKO) {
- sh_ch.rx_port_start_offset =
- TABLA_SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS;
- sh_ch.num_rx_slave_port =
- TABLA_SB_PGD_MAX_NUMBER_OF_RX_SLAVE_DEV_PORTS;
- sh_ch.port_ch_0_start_port_id =
- TABLA_SB_PGD_RX_PORT_MULTI_CHANNEL_0_START_PORT_ID;
- sh_ch.port_ch_0_end_port_id =
- TABLA_SB_PGD_RX_PORT_MULTI_CHANNEL_0_END_PORT_ID;
- sh_ch.pgd_tx_port_ch_1_end_port_id =
- TABLA_SB_PGD_TX_PORT_MULTI_CHANNEL_1_END_PORT_ID;
-
- sh_ch.rx_port_ch_reg_base =
- 0x180 + (TABLA_SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS * 4);
- sh_ch.port_rx_cfg_reg_base =
- 0x040 + (TABLA_SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS);
- sh_ch.port_tx_cfg_reg_base = 0x040;
-
- sh_ch.number_of_tx_slave_dev_ports =
- TABLA_SB_PGD_MAX_NUMBER_OF_TX_SLAVE_DEV_PORTS;
- sh_ch.number_of_rx_slave_dev_ports =
- TABLA_SB_PGD_MAX_NUMBER_OF_RX_SLAVE_DEV_PORTS;
- } else {
- sh_ch.rx_port_start_offset =
- TAIKO_SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS;
- sh_ch.num_rx_slave_port =
- TAIKO_SB_PGD_MAX_NUMBER_OF_RX_SLAVE_DEV_PORTS;
- sh_ch.port_ch_0_start_port_id =
- TAIKO_SB_PGD_RX_PORT_MULTI_CHANNEL_0_START_PORT_ID;
- sh_ch.port_ch_0_end_port_id =
- TAIKO_SB_PGD_RX_PORT_MULTI_CHANNEL_0_END_PORT_ID;
- sh_ch.pgd_tx_port_ch_1_end_port_id =
- TAIKO_SB_PGD_TX_PORT_MULTI_CHANNEL_1_END_PORT_ID;
-
- sh_ch.rx_port_ch_reg_base = 0x180;
+ sh_ch.rx_port_ch_reg_base = 0x180 ;
sh_ch.port_rx_cfg_reg_base = 0x040;
+ sh_ch.port_tx_cfg_reg_base = 0x040;
+ } else {
+ sh_ch.rx_port_ch_reg_base =
+ 0x180 - (TAIKO_SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS * 4);
+ sh_ch.port_rx_cfg_reg_base =
+ 0x040 - TAIKO_SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS ;
sh_ch.port_tx_cfg_reg_base = 0x050;
-
- sh_ch.number_of_tx_slave_dev_ports =
- TAIKO_SB_PGD_MAX_NUMBER_OF_TX_SLAVE_DEV_PORTS;
- sh_ch.number_of_rx_slave_dev_ports =
- TAIKO_SB_PGD_MAX_NUMBER_OF_RX_SLAVE_DEV_PORTS;
}
return 0;
}
-int wcd9xxx_init_slimslave(struct wcd9xxx *wcd9xxx, u8 wcd9xxx_pgd_la)
+
+int wcd9xxx_init_slimslave(struct wcd9xxx *wcd9xxx, u8 wcd9xxx_pgd_la,
+ unsigned int tx_num, unsigned int *tx_slot,
+ unsigned int rx_num, unsigned int *rx_slot)
{
int ret = 0;
+ int i;
ret = wcd9xxx_configure_ports(wcd9xxx);
if (ret) {
@@ -122,125 +70,106 @@
goto err;
}
- ret = wcd9xxx_alloc_slim_sh_ch_rx(wcd9xxx, wcd9xxx_pgd_la);
- if (ret) {
- pr_err("%s: Failed to alloc rx slimbus shared channels\n",
- __func__);
- goto err;
+ if (wcd9xxx->rx_chs) {
+ wcd9xxx->num_rx_port = rx_num;
+ for (i = 0; i < rx_num; i++) {
+ wcd9xxx->rx_chs[i].ch_num = rx_slot[i];
+ INIT_LIST_HEAD(&wcd9xxx->rx_chs[i].list);
+ }
+ ret = wcd9xxx_alloc_slim_sh_ch(wcd9xxx, wcd9xxx_pgd_la,
+ wcd9xxx->num_rx_port,
+ wcd9xxx->rx_chs,
+ SLIM_SINK);
+ if (ret) {
+ pr_err("%s: Failed to alloc %d rx slimbus channels\n",
+ __func__, wcd9xxx->num_rx_port);
+ kfree(wcd9xxx->rx_chs);
+ wcd9xxx->rx_chs = NULL;
+ wcd9xxx->num_rx_port = 0;
+ }
+ } else {
+ pr_err("Not able to allocate memory for %d slimbus rx ports\n",
+ wcd9xxx->num_rx_port);
}
- ret = wcd9xxx_alloc_slim_sh_ch_tx(wcd9xxx, wcd9xxx_pgd_la);
- if (ret) {
- pr_err("%s: Failed to alloc tx slimbus shared channels\n",
- __func__);
- goto tx_err;
+
+ if (wcd9xxx->tx_chs) {
+ wcd9xxx->num_tx_port = tx_num;
+ for (i = 0; i < tx_num; i++) {
+ wcd9xxx->tx_chs[i].ch_num = tx_slot[i];
+ INIT_LIST_HEAD(&wcd9xxx->tx_chs[i].list);
+ }
+ ret = wcd9xxx_alloc_slim_sh_ch(wcd9xxx, wcd9xxx_pgd_la,
+ wcd9xxx->num_tx_port,
+ wcd9xxx->tx_chs,
+ SLIM_SRC);
+ if (ret) {
+ pr_err("%s: Failed to alloc %d tx slimbus channels\n",
+ __func__, wcd9xxx->num_tx_port);
+ kfree(wcd9xxx->tx_chs);
+ wcd9xxx->tx_chs = NULL;
+ wcd9xxx->num_tx_port = 0;
+ }
+ } else {
+ pr_err("Not able to allocate memory for %d slimbus tx ports\n",
+ wcd9xxx->num_tx_port);
}
+
return 0;
-tx_err:
- wcd9xxx_dealloc_slim_sh_ch_rx(wcd9xxx);
err:
return ret;
}
-
int wcd9xxx_deinit_slimslave(struct wcd9xxx *wcd9xxx)
{
- int ret = 0;
- ret = wcd9xxx_dealloc_slim_sh_ch_rx(wcd9xxx);
- if (ret < 0) {
- pr_err("%s: fail to dealloc rx slim ports\n", __func__);
- goto err;
+ if (wcd9xxx->num_rx_port) {
+ wcd9xxx_dealloc_slim_sh_ch(wcd9xxx->slim,
+ wcd9xxx->num_rx_port,
+ wcd9xxx->rx_chs);
+ wcd9xxx->num_rx_port = 0;
}
- ret = wcd9xxx_dealloc_slim_sh_ch_tx(wcd9xxx);
- if (ret < 0) {
- pr_err("%s: fail to dealloc tx slim ports\n", __func__);
- goto err;
+ if (wcd9xxx->num_tx_port) {
+ wcd9xxx_dealloc_slim_sh_ch(wcd9xxx->slim,
+ wcd9xxx->num_tx_port,
+ wcd9xxx->tx_chs);
+ wcd9xxx->num_tx_port = 0;
}
-err:
- return ret;
-}
-
-int wcd9xxx_get_channel(struct wcd9xxx *wcd9xxx, unsigned int *rx_ch,
- unsigned int *tx_ch)
-{
- int ch_idx = 0;
- struct wcd9xxx_slim_sch_rx *rx = sh_ch.rx;
- struct wcd9xxx_slim_sch_tx *tx = sh_ch.tx;
-
- for (ch_idx = 0; ch_idx < sh_ch.number_of_rx_slave_dev_ports; ch_idx++)
- rx_ch[ch_idx] = rx[ch_idx].ch_num;
- for (ch_idx = 0; ch_idx < sh_ch.number_of_tx_slave_dev_ports; ch_idx++)
- tx_ch[ch_idx] = tx[ch_idx].ch_num;
return 0;
}
-static int wcd9xxx_alloc_slim_sh_ch_rx(struct wcd9xxx *wcd9xxx,
- u8 wcd9xxx_pgd_la)
+
+static int wcd9xxx_alloc_slim_sh_ch(struct wcd9xxx *wcd9xxx,
+ u8 wcd9xxx_pgd_la, u32 cnt,
+ struct wcd9xxx_ch *channels, u32 path)
{
int ret = 0;
- u8 ch_idx ;
- u16 slave_port_id = 0;
- struct wcd9xxx_slim_sch_rx *rx = sh_ch.rx;
+ u32 ch_idx ;
- /*
- * DSP requires channel number to be between 128 and 255.
+ /* The slimbus channel allocation seem take longer time
+ * so do the allocation up front to avoid delay in start of
+ * playback
*/
pr_debug("%s: pgd_la[%d]\n", __func__, wcd9xxx_pgd_la);
- for (ch_idx = 0; ch_idx < sh_ch.number_of_rx_slave_dev_ports;
- ch_idx++) {
- slave_port_id = (ch_idx + sh_ch.rx_port_start_offset);
- rx[ch_idx].ch_num = slave_port_id + BASE_CH_NUM;
- ret = slim_get_slaveport(wcd9xxx_pgd_la, slave_port_id,
- &rx[ch_idx].sph, SLIM_SINK);
+ for (ch_idx = 0; ch_idx < cnt; ch_idx++) {
+ ret = slim_get_slaveport(wcd9xxx_pgd_la,
+ channels[ch_idx].port,
+ &channels[ch_idx].sph, path);
+ pr_debug("%s: pgd_la[%d] channels[%d].port[%d]\n"
+ "channels[%d].sph[%d] path[%d]\n",
+ __func__, wcd9xxx_pgd_la, ch_idx,
+ channels[ch_idx].port,
+ ch_idx, channels[ch_idx].sph, path);
if (ret < 0) {
pr_err("%s: slave port failure id[%d] ret[%d]\n",
- __func__, slave_port_id, ret);
+ __func__, channels[ch_idx].ch_num, ret);
goto err;
}
- ret = slim_query_ch(wcd9xxx->slim, rx[ch_idx].ch_num,
- &rx[ch_idx].ch_h);
+ ret = slim_query_ch(wcd9xxx->slim,
+ channels[ch_idx].ch_num,
+ &channels[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;
- }
- pr_debug("%s:ch_num=%d ch_h=%d sph=%d la=%d slave_port_id %d\n",
- __func__, rx[ch_idx].ch_num, rx[ch_idx].ch_h,
- rx[ch_idx].sph, wcd9xxx_pgd_la, slave_port_id);
- }
-err:
- return ret;
-}
-
-static int wcd9xxx_alloc_slim_sh_ch_tx(struct wcd9xxx *wcd9xxx,
- u8 wcd9xxx_pgd_la)
-{
- int ret = 0;
- u8 ch_idx;
- struct wcd9xxx_slim_sch_tx *tx = sh_ch.tx;
- u16 slave_port_id = 0;
-
- pr_debug("%s: pgd_la[%d]\n", __func__, wcd9xxx_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 < sh_ch.number_of_tx_slave_dev_ports;
- ch_idx++) {
- slave_port_id = ch_idx;
- tx[ch_idx].ch_num = slave_port_id + BASE_CH_NUM;
- ret = slim_get_slaveport(wcd9xxx_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(wcd9xxx->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);
+ __func__, channels[ch_idx].ch_num, ret);
goto err;
}
}
@@ -248,116 +177,46 @@
return ret;
}
-static int wcd9xxx_dealloc_slim_sh_ch_rx(struct wcd9xxx *wcd9xxx)
+static int wcd9xxx_dealloc_slim_sh_ch(struct slim_device *slim,
+ u32 cnt, struct wcd9xxx_ch *channels)
{
int idx = 0;
int ret = 0;
- struct wcd9xxx_slim_sch_rx *rx = sh_ch.rx;
/* slim_dealloc_ch */
- for (idx = 0; idx < sh_ch.number_of_rx_slave_dev_ports; idx++) {
- ret = slim_dealloc_ch(wcd9xxx->slim, rx[idx].ch_h);
+ for (idx = 0; idx < cnt; idx++) {
+ ret = slim_dealloc_ch(slim, channels[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);
+ __func__, ret, channels[idx].ch_h);
}
}
- memset(sh_ch.rx, 0, sizeof(sh_ch.rx));
- return ret;
-}
-
-static int wcd9xxx_dealloc_slim_sh_ch_tx(struct wcd9xxx *wcd9xxx)
-{
- int idx = 0;
- int ret = 0;
- struct wcd9xxx_slim_sch_tx *tx = sh_ch.tx;
- /* slim_dealloc_ch */
- for (idx = 0; idx < sh_ch.number_of_tx_slave_dev_ports; idx++) {
- ret = slim_dealloc_ch(wcd9xxx->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 wcd9xxx_cfg_slim_sch_rx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
- unsigned int ch_cnt, unsigned int rate)
+int wcd9xxx_cfg_slim_sch_rx(struct wcd9xxx *wcd9xxx,
+ struct list_head *wcd9xxx_ch_list,
+ unsigned int rate, unsigned int bit_width,
+ u16 *grph)
{
- u8 i;
- u16 grph;
- u32 sph[SLIM_MAX_RX_PORTS] = {0};
+ u8 ch_cnt = 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 wcd9xxx_slim_sch_rx *rx = sh_ch.rx;
+ u8 payload = 0;
+ u16 codec_port = 0;
+ int ret;
struct slim_ch prop;
+ struct wcd9xxx_ch *rx;
/* 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 - sh_ch.rx_port_start_offset);
- ch_h[i] = rx[idx].ch_h;
- sph[i] = rx[idx].sph;
- slave_port_id = idx;
- pr_debug("%s: idx %d, ch_h %d, sph %d\n",
- __func__, idx, ch_h[i], sph[i]);
- if ((slave_port_id > sh_ch.num_rx_slave_port)) {
- pr_err("Slimbus: invalid slave port id: %d",
- slave_port_id);
- ret = -EINVAL;
- goto err;
- }
- slave_port_id += sh_ch.rx_port_start_offset;
- pr_debug("%s: slave_port_id %d\n", __func__, slave_port_id);
- /* look for the valid port range and chose the
- * payload accordingly
- */
- if ((slave_port_id > sh_ch.pgd_tx_port_ch_1_end_port_id) &&
- (slave_port_id <= sh_ch.port_ch_0_end_port_id)) {
- payload_rx = payload_rx |
- (1 << (slave_port_id -
- sh_ch.port_ch_0_start_port_id));
- } else {
- ret = -EINVAL;
- goto err;
- }
-
- multi_chan_cfg_reg_addr =
- SB_PGD_RX_PORT_MULTI_CHANNEL_0(sh_ch.rx_port_ch_reg_base,
- idx);
- pr_debug("%s: multi_chan_cfg_reg_addr 0x%x\n", __func__,
- multi_chan_cfg_reg_addr);
-
- /* write to interface device */
- ret = wcd9xxx_interface_reg_write(wcd9xxx,
- 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 = wcd9xxx_interface_reg_write(
- wcd9xxx,
- SB_PGD_PORT_CFG_BYTE_ADDR(
- sh_ch.port_rx_cfg_reg_base, idx),
- wm_payload);
- if (ret < 0) {
- pr_err("%s:watermark set failure for port[%d] ret[%d]",
- __func__, slave_port_id, ret);
- }
+ list_for_each_entry(rx, wcd9xxx_ch_list, list) {
+ payload |= 1 << rx->shift;
+ ch_h[ch_cnt] = rx->ch_h;
+ ch_cnt++;
+ pr_debug("list ch->ch_h %d ch->sph %d\n", rx->ch_h, rx->sph);
}
-
+ pr_debug("%s: ch_cnt[%d] rate=%d WATER_MARK_VAL %d\n",
+ __func__, ch_cnt, rate, WATER_MARK_VAL);
/* slim_define_ch api */
prop.prot = SLIM_AUTO_ISO;
prop.baser = SLIM_RATE_4000HZ;
@@ -366,130 +225,97 @@
prop.ratem = (rate/4000);
prop.sampleszbits = 16;
- ret = slim_define_ch(wcd9xxx->slim, &prop, ch_h, ch_cnt, true, &grph);
+ pr_debug("Before slim_define_ch:\n"
+ "ch_cnt %d,ch_h[0] %d ch_h[1] %d, grph %d\n",
+ ch_cnt, ch_h[0], ch_h[1], *grph);
+ ret = slim_define_ch(wcd9xxx->slim, &prop, ch_h, ch_cnt,
+ true, grph);
if (ret < 0) {
pr_err("%s: slim_define_ch failed ret[%d]\n",
- __func__, ret);
+ __func__, ret);
goto err;
}
- for (i = 0; i < ch_cnt; i++) {
- ret = slim_connect_sink(wcd9xxx->slim, &sph[i], 1, ch_h[i]);
+
+ list_for_each_entry(rx, wcd9xxx_ch_list, list) {
+ codec_port = rx->port;
+ pr_debug("%s: codec_port %d rx 0x%x, payload %d\n"
+ "sh_ch.rx_port_ch_reg_base0 0x%x\n"
+ "sh_ch.port_rx_cfg_reg_base 0x%x\n",
+ __func__, codec_port, (u32)rx, payload,
+ sh_ch.rx_port_ch_reg_base,
+ sh_ch.port_rx_cfg_reg_base);
+
+ /* look for the valid port range and chose the
+ * payload accordingly
+ */
+ /* write to interface device */
+ ret = wcd9xxx_interface_reg_write(wcd9xxx,
+ SB_PGD_RX_PORT_MULTI_CHANNEL_0(
+ sh_ch.rx_port_ch_reg_base, codec_port),
+ payload);
+
+ if (ret < 0) {
+ pr_err("%s:Intf-dev fail reg[%d] payload[%d] ret[%d]\n",
+ __func__,
+ SB_PGD_RX_PORT_MULTI_CHANNEL_0(
+ sh_ch.rx_port_ch_reg_base, codec_port),
+ payload, ret);
+ goto err;
+ }
+ /* configure the slave port for water mark and enable*/
+ ret = wcd9xxx_interface_reg_write(wcd9xxx,
+ SB_PGD_PORT_CFG_BYTE_ADDR(
+ sh_ch.port_rx_cfg_reg_base, codec_port),
+ WATER_MARK_VAL);
+ if (ret < 0) {
+ pr_err("%s:watermark set failure for port[%d] ret[%d]",
+ __func__, codec_port, ret);
+ }
+
+ ret = slim_connect_sink(wcd9xxx->slim, &rx->sph, 1, rx->ch_h);
if (ret < 0) {
pr_err("%s: slim_connect_sink failed ret[%d]\n",
- __func__, ret);
+ __func__, ret);
goto err_close_slim_sch;
}
}
/* slim_control_ch */
- ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_ACTIVATE, true);
+ ret = slim_control_ch(wcd9xxx->slim, *grph, SLIM_CH_ACTIVATE,
+ true);
if (ret < 0) {
pr_err("%s: slim_control_ch failed ret[%d]\n",
- __func__, ret);
+ __func__, ret);
goto err_close_slim_sch;
}
- for (i = 0; i < ch_cnt; i++) {
- idx = (ch_num[i] - BASE_CH_NUM - sh_ch.rx_port_start_offset);
- rx[idx].grph = grph;
- }
return 0;
err_close_slim_sch:
/* release all acquired handles */
- wcd9xxx_close_slim_sch_rx(wcd9xxx, ch_num, ch_cnt);
+ wcd9xxx_close_slim_sch_rx(wcd9xxx, wcd9xxx_ch_list, *grph);
err:
return ret;
}
EXPORT_SYMBOL_GPL(wcd9xxx_cfg_slim_sch_rx);
/* Enable slimbus slave device for RX path */
-int wcd9xxx_cfg_slim_sch_tx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
- unsigned int ch_cnt, unsigned int rate)
+int wcd9xxx_cfg_slim_sch_tx(struct wcd9xxx *wcd9xxx,
+ struct list_head *wcd9xxx_ch_list,
+ unsigned int rate, unsigned int bit_width,
+ u16 *grph)
{
- 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_cnt = 0;
+ u16 payload = 0;
u16 ch_h[SLIM_MAX_TX_PORTS] = {0};
- u16 idx = 0, slave_port_id;
+ u16 codec_port;
int ret = 0;
- unsigned short multi_chan_cfg_reg_addr;
+ struct wcd9xxx_ch *tx;
- struct wcd9xxx_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;
- pr_debug("%s: idx %d, ch_h %d, sph %d, slave_port_id %d\n",
- __func__, idx, ch_h[i], sph[i], slave_port_id);
- if (slave_port_id > sh_ch.number_of_tx_slave_dev_ports) {
- 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 <=
- sh_ch.pgd_tx_port_ch_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 {
- pr_err("%s: slave port id %d error\n", __func__,
- slave_port_id);
- ret = -EINVAL;
- goto err;
- }
- multi_chan_cfg_reg_addr =
- SB_PGD_TX_PORT_MULTI_CHANNEL_0(slave_port_id);
- pr_debug("%s: multi_chan_cfg_reg_addr 0x%x\n", __func__,
- multi_chan_cfg_reg_addr);
- /* write to interface device */
- ret = wcd9xxx_interface_reg_write(wcd9xxx,
- 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 = wcd9xxx_interface_reg_write(wcd9xxx,
- 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;
- pr_debug("%s: tx_cfg_reg 0x%x wm 0x%x\n", __func__,
- SB_PGD_PORT_CFG_BYTE_ADDR(sh_ch.port_tx_cfg_reg_base,
- slave_port_id), wm_payload);
- ret = wcd9xxx_interface_reg_write(
- wcd9xxx,
- SB_PGD_PORT_CFG_BYTE_ADDR(
- sh_ch.port_tx_cfg_reg_base,
- slave_port_id),
- wm_payload);
- if (ret < 0) {
- pr_err("%s: watermark set failure for port[%d] ret[%d]",
- __func__, slave_port_id, ret);
- }
+ list_for_each_entry(tx, wcd9xxx_ch_list, list) {
+ payload |= 1 << tx->shift;
+ ch_h[ch_cnt] = tx->ch_h;
+ ch_cnt++;
}
/* slim_define_ch api */
@@ -499,13 +325,53 @@
prop.auxf = SLIM_CH_AUXF_NOT_APPLICABLE;
prop.ratem = (rate/4000);
prop.sampleszbits = 16;
- ret = slim_define_ch(wcd9xxx->slim, &prop, ch_h, ch_cnt, true, &grph);
+ ret = slim_define_ch(wcd9xxx->slim, &prop, ch_h, ch_cnt,
+ true, grph);
if (ret < 0) {
- pr_err("%s: slim_define_ch failed ret[%d]\n", __func__, ret);
+ 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(wcd9xxx->slim, sph[i], ch_h[i]);
+
+ pr_debug("%s: ch_cnt[%d] rate[%d]\n", __func__, ch_cnt, rate);
+ list_for_each_entry(tx, wcd9xxx_ch_list, list) {
+ codec_port = tx->port;
+ pr_debug("%s: codec_port %d rx 0x%x, payload 0x%x\n",
+ __func__, codec_port, (u32)tx, payload);
+ /* write to interface device */
+ ret = wcd9xxx_interface_reg_write(wcd9xxx,
+ SB_PGD_TX_PORT_MULTI_CHANNEL_0(codec_port),
+ payload & 0x00FF);
+ if (ret < 0) {
+ pr_err("%s:Intf-dev fail reg[%d] payload[%d] ret[%d]\n",
+ __func__,
+ SB_PGD_TX_PORT_MULTI_CHANNEL_0(codec_port),
+ payload, ret);
+ goto err;
+ }
+ /* ports 8,9 */
+ ret = wcd9xxx_interface_reg_write(wcd9xxx,
+ SB_PGD_TX_PORT_MULTI_CHANNEL_1(codec_port),
+ (payload & 0xFF00)>>8);
+ if (ret < 0) {
+ pr_err("%s:Intf-dev fail reg[%d] payload[%d] ret[%d]\n",
+ __func__,
+ SB_PGD_TX_PORT_MULTI_CHANNEL_1(codec_port),
+ payload, ret);
+ goto err;
+ }
+ /* configure the slave port for water mark and enable*/
+ ret = wcd9xxx_interface_reg_write(wcd9xxx,
+ SB_PGD_PORT_CFG_BYTE_ADDR(
+ sh_ch.port_tx_cfg_reg_base, codec_port),
+ WATER_MARK_VAL);
+ if (ret < 0) {
+ pr_err("%s:watermark set failure for port[%d] ret[%d]",
+ __func__, codec_port, ret);
+ }
+
+ ret = slim_connect_src(wcd9xxx->slim, tx->sph, tx->ch_h);
+
if (ret < 0) {
pr_err("%s: slim_connect_src failed ret[%d]\n",
__func__, ret);
@@ -513,91 +379,69 @@
}
}
/* slim_control_ch */
- ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_ACTIVATE, true);
+ ret = slim_control_ch(wcd9xxx->slim, *grph, SLIM_CH_ACTIVATE,
+ true);
if (ret < 0) {
pr_err("%s: slim_control_ch failed ret[%d]\n",
- __func__, ret);
+ __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 */
- wcd9xxx_close_slim_sch_tx(wcd9xxx, ch_num, ch_cnt);
+ wcd9xxx_close_slim_sch_tx(wcd9xxx, wcd9xxx_ch_list, *grph);
return ret;
}
EXPORT_SYMBOL_GPL(wcd9xxx_cfg_slim_sch_tx);
-int wcd9xxx_close_slim_sch_rx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
- unsigned int ch_cnt)
+int wcd9xxx_close_slim_sch_rx(struct wcd9xxx *wcd9xxx,
+ struct list_head *wcd9xxx_ch_list, u16 grph)
{
- u16 grph = 0;
- int i = 0 , idx = 0;
+ u32 sph[SLIM_MAX_RX_PORTS] = {0};
+ int ch_cnt = 0 ;
int ret = 0;
- struct wcd9xxx_slim_sch_rx *rx = sh_ch.rx;
+ struct wcd9xxx_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 - sh_ch.rx_port_start_offset);
- if (idx < 0) {
- pr_err("%s: Error:-Invalid index found = %d\n",
- __func__, idx);
- ret = -EINVAL;
- goto err;
- }
- grph = rx[idx].grph;
- pr_debug("%s: ch_num[%d] %d, idx %d, grph %x\n",
- __func__, i, ch_num[i], idx, grph);
- }
+ list_for_each_entry(rx, wcd9xxx_ch_list, list)
+ sph[ch_cnt++] = rx->sph;
+
+ pr_debug("%s ch_cht %d, sph[0] %d sph[1] %d\n", __func__, ch_cnt,
+ sph[0], sph[1]);
/* slim_control_ch (REMOVE) */
+ pr_debug("%s before slim_control_ch grph %d\n", __func__, grph);
ret = slim_control_ch(wcd9xxx->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 - sh_ch.rx_port_start_offset);
- rx[idx].grph = 0;
- }
err:
return ret;
}
EXPORT_SYMBOL_GPL(wcd9xxx_close_slim_sch_rx);
-int wcd9xxx_close_slim_sch_tx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
- unsigned int ch_cnt)
+int wcd9xxx_close_slim_sch_tx(struct wcd9xxx *wcd9xxx,
+ struct list_head *wcd9xxx_ch_list,
+ u16 grph)
{
- u16 grph = 0;
+ u32 sph[SLIM_MAX_TX_PORTS] = {0};
int ret = 0;
- int i = 0 , idx = 0;
- struct wcd9xxx_slim_sch_tx *tx = sh_ch.tx;
+ int ch_cnt = 0 ;
+ struct wcd9xxx_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);
- if (idx < 0) {
- pr_err("%s: Error:- Invalid index found = %d\n",
- __func__, idx);
- ret = -EINVAL;
- goto err;
- }
- grph = tx[idx].grph;
- }
+ pr_debug("%s\n", __func__);
+ list_for_each_entry(tx, wcd9xxx_ch_list, list)
+ sph[ch_cnt++] = tx->sph;
+
+ pr_debug("%s ch_cht %d, sph[0] %d sph[1] %d\n",
+ __func__, ch_cnt, sph[0], sph[1]);
/* slim_control_ch (REMOVE) */
ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_REMOVE, true);
if (ret < 0) {
pr_err("%s: slim_control_ch failed ret[%d]\n",
- __func__, ret);
+ __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;
}
@@ -607,8 +451,8 @@
{
int ret = 0;
- pr_debug("%s: ch_num[%d]\n", __func__, ch_num);
ret = (ch_num - BASE_CH_NUM);
+ pr_debug("%s: ch_num[%d] slave port[%d]\n", __func__, ch_num, ret);
if (ret < 0) {
pr_err("%s: Error:- Invalid slave port found = %d\n",
__func__, ret);
@@ -618,39 +462,16 @@
}
EXPORT_SYMBOL_GPL(wcd9xxx_get_slave_port);
-int wcd9xxx_disconnect_port(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
- unsigned int ch_cnt, unsigned int rx_tx)
+int wcd9xxx_disconnect_port(struct wcd9xxx *wcd9xxx,
+ struct list_head *wcd9xxx_ch_list, u16 grph)
{
- u32 sph[SLIM_MAX_TX_PORTS] = {0};
- int i = 0 , idx = 0;
+ u32 sph[SLIM_MAX_TX_PORTS + SLIM_MAX_RX_PORTS] = {0};
+ int ch_cnt = 0 ;
int ret = 0;
- struct wcd9xxx_slim_sch_rx *rx = sh_ch.rx;
- struct wcd9xxx_slim_sch_tx *tx = sh_ch.tx;
+ struct wcd9xxx_ch *slim_ch;
- pr_debug("%s: ch_cnt[%d], rx_tx flag = %d\n", __func__, ch_cnt, rx_tx);
- for (i = 0; i < ch_cnt; i++) {
- /* rx_tx will be 1 for rx, 0 for tx */
- if (rx_tx) {
- idx = (ch_num[i] - BASE_CH_NUM -
- sh_ch.rx_port_start_offset);
- if (idx < 0) {
- pr_err("%s: Invalid index found for RX = %d\n",
- __func__, idx);
- ret = -EINVAL;
- goto err;
- }
- sph[i] = rx[idx].sph;
- } else {
- idx = (ch_num[i] - BASE_CH_NUM);
- if (idx < 0) {
- pr_err("%s:Invalid index found for TX = %d\n",
- __func__, idx);
- ret = -EINVAL;
- goto err;
- }
- sph[i] = tx[idx].sph;
- }
- }
+ list_for_each_entry(slim_ch, wcd9xxx_ch_list, list)
+ sph[ch_cnt++] = slim_ch->sph;
/* slim_disconnect_port */
ret = slim_disconnect_ports(wcd9xxx->slim, sph, ch_cnt);
@@ -658,7 +479,6 @@
pr_err("%s: slim_disconnect_ports failed ret[%d]\n",
__func__, ret);
}
-err:
return ret;
}
EXPORT_SYMBOL_GPL(wcd9xxx_disconnect_port);
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 6de0a77..740c717 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -1168,6 +1168,7 @@
usb_anchor_urb(urb, &dev->deferred);
/* no use to process more packets */
netif_stop_queue(net);
+ usb_put_urb(urb);
spin_unlock_irqrestore(&dev->txq.lock, flags);
netdev_dbg(dev->net, "Delaying transmission for resumption\n");
goto deferred;
@@ -1317,6 +1318,8 @@
cancel_work_sync(&dev->kevent);
+ usb_scuttle_anchored_urbs(&dev->deferred);
+
if (dev->driver_info->unbind)
dev->driver_info->unbind (dev, intf);
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 0b1a16e..f596411 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -700,11 +700,19 @@
return mbim_bind_config(c, 0);
}
+static int mbim_function_ctrlrequest(struct android_usb_function *f,
+ struct usb_composite_dev *cdev,
+ const struct usb_ctrlrequest *c)
+{
+ return mbim_ctrlrequest(cdev, c);
+}
+
static struct android_usb_function mbim_function = {
.name = "usb_mbim",
.cleanup = mbim_function_cleanup,
.bind_config = mbim_function_bind_config,
.init = mbim_function_init,
+ .ctrlrequest = mbim_function_ctrlrequest,
};
#ifdef CONFIG_SND_PCM
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index b3cab7a..fa1bf43 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -2406,7 +2406,8 @@
* bits. This is a temporary workaround till
* HW designers come back on this.
*/
- if (retval == -EBUSY && req_dequeue && mEp->dir == 0) {
+ if (retval == -EBUSY && req_dequeue &&
+ (mEp->dir == 0 || mEp->num == 0)) {
req_dequeue = 0;
udc->dTD_update_fail_count++;
mEp->dTD_update_fail_count++;
diff --git a/drivers/usb/gadget/f_mbim.c b/drivers/usb/gadget/f_mbim.c
index 7a84ca3..681435a 100644
--- a/drivers/usb/gadget/f_mbim.c
+++ b/drivers/usb/gadget/f_mbim.c
@@ -19,7 +19,6 @@
#include <linux/usb/cdc.h>
#include <linux/usb/composite.h>
-#include <linux/usb/android_composite.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
@@ -41,6 +40,9 @@
#define NR_MBIM_PORTS 1
+/* ID for Microsoft OS String */
+#define MBIM_OS_STRING_ID 0xEE
+
struct ctrl_pkt {
void *buf;
int len;
@@ -356,6 +358,63 @@
NULL,
};
+/* Microsoft OS Descriptors */
+
+/*
+ * We specify our own bMS_VendorCode byte which Windows will use
+ * as the bRequest value in subsequent device get requests.
+ */
+#define MBIM_VENDOR_CODE 0xA5
+
+/* Microsoft OS String */
+static u8 mbim_os_string[] = {
+ 18, /* sizeof(mtp_os_string) */
+ USB_DT_STRING,
+ /* Signature field: "MSFT100" */
+ 'M', 0, 'S', 0, 'F', 0, 'T', 0, '1', 0, '0', 0, '0', 0,
+ /* vendor code */
+ MBIM_VENDOR_CODE,
+ /* padding */
+ 0
+};
+
+/* Microsoft Extended Configuration Descriptor Header Section */
+struct mbim_ext_config_desc_header {
+ __le32 dwLength;
+ __u16 bcdVersion;
+ __le16 wIndex;
+ __u8 bCount;
+ __u8 reserved[7];
+};
+
+/* Microsoft Extended Configuration Descriptor Function Section */
+struct mbim_ext_config_desc_function {
+ __u8 bFirstInterfaceNumber;
+ __u8 bInterfaceCount;
+ __u8 compatibleID[8];
+ __u8 subCompatibleID[8];
+ __u8 reserved[6];
+};
+
+/* Microsoft Extended Configuration Descriptor */
+static struct {
+ struct mbim_ext_config_desc_header header;
+ struct mbim_ext_config_desc_function function;
+} mbim_ext_config_desc = {
+ .header = {
+ .dwLength = __constant_cpu_to_le32(sizeof mbim_ext_config_desc),
+ .bcdVersion = __constant_cpu_to_le16(0x0100),
+ .wIndex = __constant_cpu_to_le16(4),
+ .bCount = 1,
+ },
+ .function = {
+ .bFirstInterfaceNumber = 0,
+ .bInterfaceCount = 1,
+ .compatibleID = { 'A', 'L', 'T', 'R', 'C', 'F', 'G' },
+ /* .subCompatibleID = DYNAMIC */
+ },
+};
+
/*
* Here are options for the Datagram Pointer table (NDP) parser.
* There are 2 different formats: NDP16 and NDP32 in the spec (ch. 3),
@@ -1108,6 +1167,63 @@
return value;
}
+/*
+ * This function handles the Microsoft-specific OS descriptor control
+ * requests that are issued by Windows host drivers to determine the
+ * configuration containing the MBIM function.
+ *
+ * Unlike mbim_setup() this function handles two specific device requests,
+ * and only when a configuration has not yet been selected.
+ */
+static int mbim_ctrlrequest(struct usb_composite_dev *cdev,
+ const struct usb_ctrlrequest *ctrl)
+{
+ int value = -EOPNOTSUPP;
+ u16 w_index = le16_to_cpu(ctrl->wIndex);
+ u16 w_value = le16_to_cpu(ctrl->wValue);
+ u16 w_length = le16_to_cpu(ctrl->wLength);
+
+ /* only respond to OS desciptors when no configuration selected */
+ if (cdev->config || !mbim_ext_config_desc.function.subCompatibleID[0])
+ return value;
+
+ pr_debug("%02x.%02x v%04x i%04x l%u",
+ ctrl->bRequestType, ctrl->bRequest,
+ w_value, w_index, w_length);
+
+ /* Handle MSFT OS string */
+ if (ctrl->bRequestType ==
+ (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE)
+ && ctrl->bRequest == USB_REQ_GET_DESCRIPTOR
+ && (w_value >> 8) == USB_DT_STRING
+ && (w_value & 0xFF) == MBIM_OS_STRING_ID) {
+
+ value = (w_length < sizeof(mbim_os_string) ?
+ w_length : sizeof(mbim_os_string));
+ memcpy(cdev->req->buf, mbim_os_string, value);
+
+ } else if (ctrl->bRequestType ==
+ (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
+ && ctrl->bRequest == MBIM_VENDOR_CODE && w_index == 4) {
+
+ /* Handle Extended OS descriptor */
+ value = (w_length < sizeof(mbim_ext_config_desc) ?
+ w_length : sizeof(mbim_ext_config_desc));
+ memcpy(cdev->req->buf, &mbim_ext_config_desc, value);
+ }
+
+ /* respond with data transfer or status phase? */
+ if (value >= 0) {
+ int rc;
+ cdev->req->zero = value < w_length;
+ cdev->req->length = value;
+ rc = usb_ep_queue(cdev->gadget->ep0, cdev->req, GFP_ATOMIC);
+ if (rc < 0)
+ pr_err("response queue error: %d", rc);
+ }
+ return value;
+}
+
static int mbim_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
{
struct f_mbim *mbim = func_to_mbim(f);
@@ -1371,6 +1487,17 @@
goto fail;
}
+ /*
+ * If MBIM is bound in a config other than the first, tell Windows
+ * about it by returning the num as a string in the OS descriptor's
+ * subCompatibleID field. Windows only supports up to config #4.
+ */
+ if (c->bConfigurationValue >= 2 && c->bConfigurationValue <= 4) {
+ pr_debug("MBIM in configuration %d", c->bConfigurationValue);
+ mbim_ext_config_desc.function.subCompatibleID[0] =
+ c->bConfigurationValue + '0';
+ }
+
pr_info("mbim(%d): %s speed IN/%s OUT/%s NOTIFY/%s\n",
mbim->port_num,
gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
@@ -1412,6 +1539,8 @@
kfree(mbim->not_port.notify_req->buf);
usb_ep_free_request(mbim->not_port.notify, mbim->not_port.notify_req);
+
+ mbim_ext_config_desc.function.subCompatibleID[0] = 0;
}
/**
diff --git a/drivers/usb/misc/ks_bridge.c b/drivers/usb/misc/ks_bridge.c
index 61e6891..410b5c4 100644
--- a/drivers/usb/misc/ks_bridge.c
+++ b/drivers/usb/misc/ks_bridge.c
@@ -287,6 +287,9 @@
unsigned long flags;
struct ks_bridge *ksb = fp->private_data;
+ if (!test_bit(USB_DEV_CONNECTED, &ksb->flags))
+ return -ENODEV;
+
pkt = ksb_alloc_data_pkt(count, GFP_KERNEL, ksb);
if (IS_ERR(pkt)) {
pr_err("unable to allocate data packet");
@@ -570,6 +573,8 @@
struct usb_endpoint_descriptor *ep_desc;
int i;
struct ks_bridge *ksb;
+ unsigned long flags;
+ struct data_pkt *pkt;
ifc_num = ifc->cur_altsetting->desc.bInterfaceNumber;
@@ -625,6 +630,23 @@
dbg_log_event(ksb, "PID-ATT", id->idProduct, 0);
+ /*free up stale buffers if any from previous disconnect*/
+ spin_lock_irqsave(&ksb->lock, flags);
+ while (!list_empty(&ksb->to_ks_list)) {
+ pkt = list_first_entry(&ksb->to_ks_list,
+ struct data_pkt, list);
+ list_del_init(&pkt->list);
+ ksb_free_data_pkt(pkt);
+ ksb->alloced_read_pkts--;
+ }
+ while (!list_empty(&ksb->to_mdm_list)) {
+ pkt = list_first_entry(&ksb->to_mdm_list,
+ struct data_pkt, list);
+ list_del_init(&pkt->list);
+ ksb_free_data_pkt(pkt);
+ }
+ spin_unlock_irqrestore(&ksb->lock, flags);
+
ksb->fs_dev = (struct miscdevice *)id->driver_info;
misc_register(ksb->fs_dev);
@@ -674,6 +696,8 @@
cancel_work_sync(&ksb->to_mdm_work);
cancel_work_sync(&ksb->start_rx_work);
+ misc_deregister(ksb->fs_dev);
+
usb_kill_anchored_urbs(&ksb->submitted);
wait_event_interruptible_timeout(
@@ -688,6 +712,7 @@
struct data_pkt, list);
list_del_init(&pkt->list);
ksb_free_data_pkt(pkt);
+ ksb->alloced_read_pkts--;
}
while (!list_empty(&ksb->to_mdm_list)) {
pkt = list_first_entry(&ksb->to_mdm_list,
@@ -697,7 +722,6 @@
}
spin_unlock_irqrestore(&ksb->lock, flags);
- misc_deregister(ksb->fs_dev);
ifc->needs_remote_wakeup = 0;
usb_put_dev(ksb->udev);
ksb->ifc = NULL;
diff --git a/include/linux/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h
index 421d758..cf57a64 100644
--- a/include/linux/mfd/wcd9xxx/core.h
+++ b/include/linux/mfd/wcd9xxx/core.h
@@ -13,6 +13,7 @@
#ifndef __MFD_TABLA_CORE_H__
#define __MFD_TABLA_CORE_H__
+#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/pm_qos.h>
#include <linux/platform_device.h>
@@ -88,6 +89,44 @@
WCD9XXX_PM_ASLEEP,
};
+/*
+ * data structure for Slimbus and I2S channel.
+ * Some of fields are only used in smilbus mode
+ */
+struct wcd9xxx_ch {
+ u32 sph; /* share channel handle - slimbus only */
+ u32 ch_num; /*
+ * vitrual channel number, such as 128 -144.
+ * apply for slimbus only
+ */
+ u16 ch_h; /* chanel handle - slimbus only */
+ u16 port; /*
+ * tabla port for RX and TX
+ * such as 0-9 for TX and 10 -16 for RX
+ * apply for both i2s and slimbus
+ */
+ u16 shift; /*
+ * shift bit for RX and TX
+ * apply for both i2s and slimbus
+ */
+ struct list_head list; /*
+ * channel link list
+ * apply for both i2s and slimbus
+ */
+};
+
+struct wcd9xxx_codec_dai_data {
+ u32 rate; /* sample rate */
+ u32 bit_width; /* sit width 16,24,32 */
+ struct list_head wcd9xxx_ch_list; /* channel list */
+ u16 grph; /* slimbus group handle */
+ u32 ch_mask;
+ wait_queue_head_t dai_wait;
+};
+
+#define WCD9XXX_CH(xport, xshift) \
+ {.port = xport, .shift = xshift}
+
struct wcd9xxx {
struct device *dev;
struct slim_device *slim;
@@ -102,7 +141,7 @@
int (*read_dev)(struct wcd9xxx *wcd9xxx, unsigned short reg,
int bytes, void *dest, bool interface_reg);
int (*write_dev)(struct wcd9xxx *wcd9xxx, unsigned short reg,
- int bytes, void *src, bool interface_reg);
+ int bytes, void *src, bool interface_reg);
u32 num_of_supplies;
struct regulator_bulk_data *supplies;
@@ -114,9 +153,6 @@
struct pm_qos_request pm_qos_req;
int wlock_holders;
- int num_rx_port;
- int num_tx_port;
-
u8 idbyte[4];
unsigned int irq_base;
@@ -125,6 +161,11 @@
u8 irq_masks_cache[WCD9XXX_NUM_IRQ_REGS];
bool irq_level_high[WCD9XXX_MAX_NUM_IRQS];
int num_irqs;
+ /* Slimbus or I2S port */
+ u32 num_rx_port;
+ u32 num_tx_port;
+ struct wcd9xxx_ch *rx_chs;
+ struct wcd9xxx_ch *tx_chs;
};
int wcd9xxx_reg_read(struct wcd9xxx *wcd9xxx, unsigned short reg);
diff --git a/include/linux/mfd/wcd9xxx/wcd9xxx-slimslave.h b/include/linux/mfd/wcd9xxx/wcd9xxx-slimslave.h
index 0d5d058..45abd92 100644
--- a/include/linux/mfd/wcd9xxx/wcd9xxx-slimslave.h
+++ b/include/linux/mfd/wcd9xxx/wcd9xxx-slimslave.h
@@ -16,27 +16,6 @@
#include <linux/slimbus/slimbus.h>
#include <linux/mfd/wcd9xxx/core.h>
-/* 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
@@ -92,30 +71,42 @@
/* 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_6BYTES 0
+#define SLAVE_PORT_WATER_MARK_9BYTES 1
+#define SLAVE_PORT_WATER_MARK_12BYTES 2
+#define SLAVE_PORT_WATER_MARK_15BYTES 3
#define SLAVE_PORT_WATER_MARK_SHIFT 1
#define SLAVE_PORT_ENABLE 1
#define SLAVE_PORT_DISABLE 0
-
+#define WATER_MARK_VAL \
+ ((SLAVE_PORT_WATER_MARK_12BYTES << SLAVE_PORT_WATER_MARK_SHIFT) | \
+ (SLAVE_PORT_ENABLE))
#define BASE_CH_NUM 128
-int wcd9xxx_init_slimslave(struct wcd9xxx *wcd9xxx, u8 wcd9xxx_pgd_la);
+int wcd9xxx_init_slimslave(struct wcd9xxx *wcd9xxx,
+ u8 wcd9xxx_pgd_la,
+ unsigned int tx_num, unsigned int *tx_slot,
+ unsigned int rx_num, unsigned int *rx_slot);
int wcd9xxx_deinit_slimslave(struct wcd9xxx *wcd9xxx);
-int wcd9xxx_cfg_slim_sch_rx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
- unsigned int tot_ch, unsigned int rate);
-int wcd9xxx_cfg_slim_sch_tx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
- unsigned int tot_ch, unsigned int rate);
-int wcd9xxx_close_slim_sch_rx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
- unsigned int tot_ch);
-int wcd9xxx_close_slim_sch_tx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
- unsigned int tot_ch);
+int wcd9xxx_cfg_slim_sch_rx(struct wcd9xxx *wcd9xxx,
+ struct list_head *wcd9xxx_ch_list,
+ unsigned int rate, unsigned int bit_width,
+ u16 *grph);
+int wcd9xxx_cfg_slim_sch_tx(struct wcd9xxx *wcd9xxx,
+ struct list_head *wcd9xxx_ch_list,
+ unsigned int rate, unsigned int bit_width,
+ u16 *grph);
+int wcd9xxx_close_slim_sch_rx(struct wcd9xxx *wcd9xxx,
+ struct list_head *wcd9xxx_ch_list, u16 grph);
+int wcd9xxx_close_slim_sch_tx(struct wcd9xxx *wcd9xxx,
+ struct list_head *wcd9xxx_ch_list, u16 grph);
int wcd9xxx_get_channel(struct wcd9xxx *wcd9xxx,
unsigned int *rx_ch,
unsigned int *tx_ch);
int wcd9xxx_get_slave_port(unsigned int ch_num);
-int wcd9xxx_disconnect_port(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
- unsigned int tot_ch, unsigned int rx_tx);
+int wcd9xxx_disconnect_port(struct wcd9xxx *wcd9xxx,
+ struct list_head *wcd9xxx_ch_list, u16 grph);
#endif /* __WCD9310_SLIMSLAVE_H_ */
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
index fa7abb1..9f02134 100644
--- a/sound/soc/codecs/wcd9304.c
+++ b/sound/soc/codecs/wcd9304.c
@@ -45,31 +45,42 @@
#define NUM_DECIMATORS 4
#define NUM_INTERPOLATORS 3
#define BITS_PER_REG 8
+
+enum {
+ AIF1_PB = 0,
+ AIF1_CAP,
+ NUM_CODEC_DAIS,
+};
+
+struct wcd9xxx_ch sitar_rx_chs[SITAR_RX_MAX] = {
+ WCD9XXX_CH(10, 0),
+ WCD9XXX_CH(11, 1),
+ WCD9XXX_CH(12, 2),
+ WCD9XXX_CH(13, 3),
+ WCD9XXX_CH(14, 4)
+};
+
+struct wcd9xxx_ch sitar_tx_chs[SITAR_TX_MAX] = {
+ WCD9XXX_CH(0, 0),
+ WCD9XXX_CH(1, 1),
+ WCD9XXX_CH(2, 2),
+ WCD9XXX_CH(3, 3),
+ WCD9XXX_CH(4, 4),
+};
+
#define SITAR_CFILT_FAST_MODE 0x00
#define SITAR_CFILT_SLOW_MODE 0x40
#define MBHC_FW_READ_ATTEMPTS 15
#define MBHC_FW_READ_TIMEOUT 2000000
+#define SLIM_CLOSE_TIMEOUT 1000
+
#define SITAR_JACK_MASK (SND_JACK_HEADSET | SND_JACK_OC_HPHL | SND_JACK_OC_HPHR)
#define SITAR_I2S_MASTER_MODE_MASK 0x08
#define SITAR_OCP_ATTEMPT 1
-#define AIF1_PB 1
-#define AIF1_CAP 2
-#define NUM_CODEC_DAIS 2
-#define SLIM_CLOSE_TIMEOUT 1000
-
-struct sitar_codec_dai_data {
- u32 rate;
- u32 *ch_num;
- u32 ch_act;
- u32 ch_tot;
- u32 ch_mask;
- wait_queue_head_t dai_wait;
-};
-
#define SITAR_MCLK_RATE_12288KHZ 12288000
#define SITAR_MCLK_RATE_9600KHZ 9600000
@@ -178,6 +189,11 @@
MBHC_STATE_RELEASE,
};
+static const u32 vport_check_table[NUM_CODEC_DAIS] = {
+ 0, /* AIF1_PB */
+ 0, /* AIF1_CAP */
+};
+
struct sitar_priv {
struct snd_soc_codec *codec;
u32 mclk_freq;
@@ -240,7 +256,7 @@
const struct firmware *mbhc_fw;
/* num of slim ports required */
- struct sitar_codec_dai_data dai[NUM_CODEC_DAIS];
+ struct wcd9xxx_codec_dai_data dai[NUM_CODEC_DAIS];
/* Currently, only used for mbhc purpose, to protect
* concurrent execution of mbhc threaded irq handlers and
@@ -935,6 +951,201 @@
SOC_DAPM_SINGLE("Switch", SITAR_A_RX_EAR_EN, 5, 1, 0),
};
+static int slim_tx_vport_validation(u32 dai_id, u32 port_id,
+ struct sitar_priv *sitar_p)
+{
+ struct wcd9xxx_ch *ch;
+ int ret = 0;
+ int index = 0;
+ u32 vtable = vport_check_table[dai_id];
+ pr_debug("%s: dai_id %u vtable 0x%x port_id %u\n", __func__,
+ dai_id, vtable, port_id);
+ while (vtable) {
+ if (vtable & 1) {
+ list_for_each_entry(ch,
+ &sitar_p->dai[index].wcd9xxx_ch_list,
+ list) {
+ pr_debug("%s: index %u ch->port%u vtable 0x%x\n",
+ __func__, index, ch->port, vtable);
+ if (ch->port == port_id) {
+ pr_err("%s: TX%u is used by AIF%u_CAP Mixer\n",
+ __func__, port_id + 1,
+ (index + 1)/2);
+ ret = -EINVAL;
+ break;
+ }
+ }
+ }
+ if (ret)
+ break;
+ index++;
+ vtable = vtable >> 1;
+ }
+ return ret;
+}
+
+static int slim_tx_mixer_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+
+ ucontrol->value.integer.value[0] = widget->value;
+ return 0;
+}
+
+static int slim_tx_mixer_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_codec *codec = widget->codec;
+ struct sitar_priv *sitar_p = snd_soc_codec_get_drvdata(codec);
+ struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
+ struct soc_multi_mixer_control *mixer =
+ ((struct soc_multi_mixer_control *)kcontrol->private_value);
+ u32 dai_id = widget->shift;
+ u32 port_id = mixer->shift;
+ u32 enable = ucontrol->value.integer.value[0];
+
+ mutex_lock(&codec->mutex);
+
+ if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+ if (dai_id != AIF1_CAP) {
+ dev_err(codec->dev, "%s: invalid AIF for I2C mode\n",
+ __func__);
+ mutex_unlock(&codec->mutex);
+ return -EINVAL;
+ }
+ }
+
+ switch (dai_id) {
+ case AIF1_CAP:
+ if (enable && !(widget->value & 1 << port_id)) {
+ if (slim_tx_vport_validation(dai_id,
+ port_id, sitar_p)) {
+ pr_info("%s: TX%u is used by other virtual port\n",
+ __func__, port_id + 1);
+ mutex_unlock(&codec->mutex);
+ return -EINVAL;
+ }
+ widget->value |= 1 << port_id;
+ list_add_tail(&core->tx_chs[port_id].list,
+ &sitar_p->dai[dai_id].wcd9xxx_ch_list);
+ } else if (!enable && (widget->value & 1 << port_id)) {
+ widget->value &= ~(1<<port_id);
+ list_del_init(&core->tx_chs[port_id].list);
+ } else {
+ if (enable)
+ pr_info("%s: TX%u port is used by this virtual port\n",
+ __func__, port_id + 1);
+ else
+ pr_info("%s: TX%u port is not used by this virtual port\n",
+ __func__, port_id + 1);
+ /* avoid update power function */
+ mutex_unlock(&codec->mutex);
+ return 0;
+ }
+ break;
+ default:
+ pr_err("Unknown AIF %d\n", dai_id);
+ mutex_unlock(&codec->mutex);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: name %s sname %s updated value %u shift %d\n", __func__,
+ widget->name, widget->sname, widget->value, widget->shift);
+ snd_soc_dapm_mixer_update_power(widget, kcontrol, enable);
+ mutex_unlock(&codec->mutex);
+ return 0;
+}
+
+static int slim_rx_mux_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+
+ ucontrol->value.enumerated.item[0] = widget->value;
+ return 0;
+}
+
+static const char * const slim_rx_mux_text[] = {
+ "ZERO", "AIF1_PB"
+};
+
+static int slim_rx_mux_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_codec *codec = widget->codec;
+ struct sitar_priv *sitar_p = snd_soc_codec_get_drvdata(codec);
+ struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ u32 port_id = widget->shift;
+
+ widget->value = ucontrol->value.enumerated.item[0];
+
+ mutex_lock(&codec->mutex);
+
+ if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+ if (widget->value > 1) {
+ dev_err(codec->dev, "%s: invalid AIF for I2C mode\n",
+ __func__);
+ mutex_unlock(&codec->mutex);
+ return -EINVAL;
+ }
+ }
+
+ switch (widget->value) {
+ case 0:
+ list_del_init(&core->rx_chs[port_id].list);
+ break;
+ case 1:
+ list_add_tail(&core->rx_chs[port_id].list,
+ &sitar_p->dai[AIF1_PB].wcd9xxx_ch_list);
+ break;
+ default:
+ pr_err("Unknown AIF %d\n", widget->value);
+ mutex_unlock(&codec->mutex);
+ return -EINVAL;
+ }
+ snd_soc_dapm_mux_update_power(widget, kcontrol, 1, widget->value, e);
+ mutex_unlock(&codec->mutex);
+ return 0;
+}
+
+static const struct soc_enum slim_rx_mux_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim_rx_mux_text), slim_rx_mux_text);
+
+static const struct snd_kcontrol_new sitar_aif_pb_mux[SITAR_RX_MAX] = {
+ SOC_DAPM_ENUM_EXT("SLIM RX1 MUX", slim_rx_mux_enum,
+ slim_rx_mux_get, slim_rx_mux_put),
+ SOC_DAPM_ENUM_EXT("SLIM RX2 MUX", slim_rx_mux_enum,
+ slim_rx_mux_get, slim_rx_mux_put),
+ SOC_DAPM_ENUM_EXT("SLIM RX3 MUX", slim_rx_mux_enum,
+ slim_rx_mux_get, slim_rx_mux_put),
+ SOC_DAPM_ENUM_EXT("SLIM RX4 MUX", slim_rx_mux_enum,
+ slim_rx_mux_get, slim_rx_mux_put),
+ SOC_DAPM_ENUM_EXT("SLIM RX5 MUX", slim_rx_mux_enum,
+ slim_rx_mux_get, slim_rx_mux_put)
+};
+
+static const struct snd_kcontrol_new sitar_aif_cap_mixer[SITAR_TX_MAX] = {
+ SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, SITAR_TX1, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, SITAR_TX2, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, SITAR_TX3, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, SITAR_TX4, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, SITAR_TX5, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+};
+
+
static void sitar_codec_enable_adc_block(struct snd_soc_codec *codec,
int enable)
{
@@ -1880,15 +2091,27 @@
SND_SOC_DAPM_MIXER("DAC1", SITAR_A_RX_EAR_EN, 6, 0, dac1_switch,
ARRAY_SIZE(dac1_switch)),
SND_SOC_DAPM_SUPPLY("EAR DRIVER", SITAR_A_RX_EAR_EN, 3, 0, NULL, 0),
- SND_SOC_DAPM_AIF_IN_E("SLIM RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
- 0, sitar_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, sitar_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),
- SND_SOC_DAPM_AIF_IN("SLIM RX5", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_AIF_IN_E("AIF1 PB", "AIF1 Playback", 0, SND_SOC_NOPM,
+ AIF1_PB, 0, sitar_codec_enable_slimrx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("SLIM RX1 MUX", SND_SOC_NOPM, SITAR_RX1, 0,
+ &sitar_aif_pb_mux[SITAR_RX1]),
+ SND_SOC_DAPM_MUX("SLIM RX2 MUX", SND_SOC_NOPM, SITAR_RX2, 0,
+ &sitar_aif_pb_mux[SITAR_RX2]),
+ SND_SOC_DAPM_MUX("SLIM RX3 MUX", SND_SOC_NOPM, SITAR_RX3, 0,
+ &sitar_aif_pb_mux[SITAR_RX3]),
+ SND_SOC_DAPM_MUX("SLIM RX4 MUX", SND_SOC_NOPM, SITAR_RX4, 0,
+ &sitar_aif_pb_mux[SITAR_RX4]),
+ SND_SOC_DAPM_MUX("SLIM RX5 MUX", SND_SOC_NOPM, SITAR_RX5, 0,
+ &sitar_aif_pb_mux[SITAR_RX5]),
+
+ SND_SOC_DAPM_MIXER("SLIM RX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM RX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM RX3", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM RX4", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM RX5", SND_SOC_NOPM, 0, 0, NULL, 0),
/* Headphone */
SND_SOC_DAPM_OUTPUT("HEADPHONE"),
@@ -2026,26 +2249,23 @@
SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
- SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, 0, 0, &sb_tx1_mux),
- SND_SOC_DAPM_MUX("SLIM TX2 MUX", SND_SOC_NOPM, 0, 0, &sb_tx2_mux),
- SND_SOC_DAPM_MUX("SLIM TX3 MUX", SND_SOC_NOPM, 0, 0, &sb_tx3_mux),
- SND_SOC_DAPM_MUX("SLIM TX4 MUX", SND_SOC_NOPM, 0, 0, &sb_tx4_mux),
- SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, 0, 0, &sb_tx5_mux),
-
- SND_SOC_DAPM_AIF_OUT_E("SLIM TX1", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
- 0, sitar_codec_enable_slimtx,
+ SND_SOC_DAPM_AIF_OUT_E("AIF1 CAP", "AIF1 Capture", 0, SND_SOC_NOPM,
+ AIF1_CAP, 0, sitar_codec_enable_slimtx,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_AIF_OUT_E("SLIM TX2", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
- 0, sitar_codec_enable_slimtx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER("AIF1_CAP Mixer", SND_SOC_NOPM, AIF1_CAP, 0,
+ sitar_aif_cap_mixer, ARRAY_SIZE(sitar_aif_cap_mixer)),
- SND_SOC_DAPM_AIF_OUT_E("SLIM TX3", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
- 0, sitar_codec_enable_slimtx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_AIF_OUT_E("SLIM TX4", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
- 0, sitar_codec_enable_slimtx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, SITAR_TX1, 0,
+ &sb_tx1_mux),
+ SND_SOC_DAPM_MUX("SLIM TX2 MUX", SND_SOC_NOPM, SITAR_TX2, 0,
+ &sb_tx2_mux),
+ SND_SOC_DAPM_MUX("SLIM TX3 MUX", SND_SOC_NOPM, SITAR_TX3, 0,
+ &sb_tx3_mux),
+ SND_SOC_DAPM_MUX("SLIM TX4 MUX", SND_SOC_NOPM, SITAR_TX3, 0,
+ &sb_tx4_mux),
+ SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, SITAR_TX3, 0,
+ &sb_tx5_mux),
SND_SOC_DAPM_AIF_OUT_E("SLIM TX5", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
0, sitar_codec_enable_slimtx,
@@ -2086,6 +2306,18 @@
{"SLIM TX3", NULL, "TX_I2S_CLK"},
{"SLIM TX4", NULL, "TX_I2S_CLK"},
};
+#define SLIM_MIXER(x) (\
+ {x, "SLIM TX1", "SLIM TX1 MUX"}, \
+ {x, "SLIM TX2", "SLIM TX2 MUX"}, \
+ {x, "SLIM TX3", "SLIM TX3 MUX"}, \
+ {x, "SLIM TX4", "SLIM TX4 MUX"})
+
+
+#define SLIM_MUX(x, y) (\
+ {"SLIM RX1 MUX", x, y}, \
+ {"SLIM RX2 MUX", x, y}, \
+ {"SLIM RX3 MUX", x, y}, \
+ {"SLIM RX4 MUX", x, y})
static const struct snd_soc_dapm_route audio_map[] = {
/* Earpiece (RX MIX1) */
@@ -2164,6 +2396,23 @@
{"RX3 MIX1", NULL, "ANC"},
/* SLIMBUS Connections */
+ {"AIF1 CAP", NULL, "AIF1_CAP Mixer"},
+
+ /* SLIM_MIXER("AIF1_CAP Mixer"),*/
+ {"AIF1_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
+ {"AIF1_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
+ {"AIF1_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
+ {"AIF1_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
+ /* SLIM_MUX("AIF1_PB", "AIF1 PB"), */
+ {"SLIM RX1 MUX", "AIF1_PB", "AIF1 PB"},
+ {"SLIM RX2 MUX", "AIF1_PB", "AIF1 PB"},
+ {"SLIM RX3 MUX", "AIF1_PB", "AIF1 PB"},
+ {"SLIM RX4 MUX", "AIF1_PB", "AIF1 PB"},
+
+ {"SLIM RX1", NULL, "SLIM RX1 MUX"},
+ {"SLIM RX2", NULL, "SLIM RX2 MUX"},
+ {"SLIM RX3", NULL, "SLIM RX3 MUX"},
+ {"SLIM RX4", NULL, "SLIM RX4 MUX"},
/* Slimbus port 5 is non functional in Sitar 1.0 */
{"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
@@ -2205,12 +2454,6 @@
/* TX */
- {"SLIM TX1", NULL, "SLIM TX1 MUX"},
- {"SLIM TX2", NULL, "SLIM TX2 MUX"},
- {"SLIM TX3", NULL, "SLIM TX3 MUX"},
- {"SLIM TX4", NULL, "SLIM TX4 MUX"},
- {"SLIM TX5", NULL, "SLIM TX5 MUX"},
-
{"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
{"SLIM TX2 MUX", "DEC2", "DEC2 MUX"},
{"SLIM TX3 MUX", "DEC3", "DEC3 MUX"},
@@ -2321,6 +2564,9 @@
{
int ret;
+ if (reg == SND_SOC_NOPM)
+ return 0;
+
BUG_ON(reg > SITAR_MAX_REGISTER);
if (!sitar_volatile(codec, reg)) {
@@ -2338,6 +2584,9 @@
unsigned int val;
int ret;
+ if (reg == SND_SOC_NOPM)
+ return 0;
+
BUG_ON(reg > SITAR_MAX_REGISTER);
if (!sitar_volatile(codec, reg) && sitar_readable(codec, reg) &&
@@ -2585,11 +2834,11 @@
return;
if (dai->id <= NUM_CODEC_DAIS) {
- if (sitar->dai[dai->id-1].ch_mask) {
+ if (sitar->dai[dai->id].ch_mask) {
active = 1;
pr_debug("%s(): Codec DAI: chmask[%d] = 0x%x\n",
- __func__, dai->id-1,
- sitar->dai[dai->id-1].ch_mask);
+ __func__, dai->id,
+ sitar->dai[dai->id].ch_mask);
}
}
@@ -2703,38 +2952,16 @@
{
struct sitar_priv *sitar = snd_soc_codec_get_drvdata(dai->codec);
- u32 i = 0;
+ struct wcd9xxx *core = dev_get_drvdata(dai->codec->dev->parent);
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++) {
- sitar->dai[dai->id - 1].ch_num[i] = rx_slot[i];
- sitar->dai[dai->id - 1].ch_act = 0;
- sitar->dai[dai->id - 1].ch_tot = rx_num;
- }
- } else if (dai->id == AIF1_CAP) {
- sitar->dai[dai->id - 1].ch_tot = tx_num;
- /* If all channels are already active,
- * Do not reset ch_act flag
- */
- if ((sitar->dai[dai->id - 1].ch_tot != 0)
- && (sitar->dai[dai->id - 1].ch_act ==
- sitar->dai[dai->id - 1].ch_tot)) {
- pr_info("%s: ch_act = %d, ch_tot = %d\n", __func__,
- sitar->dai[dai->id - 1].ch_act,
- sitar->dai[dai->id - 1].ch_tot);
-
- return 0;
- }
- sitar->dai[dai->id - 1].ch_act = 0;
-
- for (i = 0; i < tx_num; i++)
- sitar->dai[dai->id - 1].ch_num[i] = tx_slot[i];
- }
+ if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+ wcd9xxx_init_slimslave(core, core->slim->laddr,
+ tx_num, tx_slot, rx_num, rx_slot);
return 0;
}
@@ -2743,33 +2970,38 @@
unsigned int *rx_num, unsigned int *rx_slot)
{
- struct wcd9xxx *sitar = dev_get_drvdata(dai->codec->control_data);
+ struct sitar_priv *sitar_p = snd_soc_codec_get_drvdata(dai->codec);
+ u32 i = 0;
+ struct wcd9xxx_ch *ch;
- 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
- */
- wcd9xxx_get_channel(sitar, rx_ch, tx_ch);
- if (dai->id == AIF1_PB) {
- *rx_num = sitar_dai[dai->id - 1].playback.channels_max;
- while (cnt < *rx_num) {
- rx_slot[cnt] = rx_ch[cnt];
- cnt++;
+ switch (dai->id) {
+ case AIF1_PB:
+ if (!rx_slot || !rx_num) {
+ pr_err("%s: Invalid rx_slot 0x%x or rx_num 0x%x\n",
+ __func__, (u32) rx_slot, (u32) rx_num);
+ return -EINVAL;
}
- } else if (dai->id == AIF1_CAP) {
- *tx_num = sitar_dai[dai->id - 1].capture.channels_max;
- tx_slot[0] = tx_ch[cnt];
- tx_slot[1] = tx_ch[4 + cnt];
- tx_slot[2] = tx_ch[2 + cnt];
- tx_slot[3] = tx_ch[3 + cnt];
+ list_for_each_entry(ch, &sitar_p->dai[dai->id].wcd9xxx_ch_list,
+ list) {
+ rx_slot[i++] = ch->ch_num;
+ }
+ *rx_num = i;
+ break;
+ case AIF1_CAP:
+ if (!tx_slot || !tx_num) {
+ pr_err("%s: Invalid tx_slot 0x%x or tx_num 0x%x\n",
+ __func__, (u32) tx_slot, (u32) tx_num);
+ return -EINVAL;
+ }
+ list_for_each_entry(ch, &sitar_p->dai[dai->id].wcd9xxx_ch_list,
+ list) {
+ tx_slot[i++] = ch->ch_num;
+ }
+ *tx_num = i;
+ break;
+ default:
+ pr_err("%s: Invalid dai %d", __func__, dai->id);
+ return -EINVAL;
}
return 0;
}
@@ -2805,7 +3037,7 @@
break;
default:
pr_err("%s: Invalid sampling rate %d\n", __func__,
- params_rate(params));
+ params_rate(params));
return -EINVAL;
}
@@ -2842,13 +3074,14 @@
0x20, 0x00);
break;
default:
- pr_err("invalid format\n");
- break;
+ pr_err("%s: Unsupport format %d\n", __func__,
+ params_format(params));
+ return -EINVAL;
}
snd_soc_update_bits(codec, SITAR_A_CDC_CLK_TX_I2S_CTL,
0x03, tx_fs_rate);
} else {
- sitar->dai[dai->id - 1].rate = params_rate(params);
+ sitar->dai[dai->id].rate = params_rate(params);
}
}
@@ -2889,13 +3122,14 @@
0x20, 0x00);
break;
default:
- pr_err("invalid format\n");
+ pr_err("%s: Unsupport format %d\n", __func__,
+ params_format(params));
break;
}
snd_soc_update_bits(codec, SITAR_A_CDC_CLK_RX_I2S_CTL,
0x03, (rx_fs_rate >> 0x05));
} else {
- sitar->dai[dai->id - 1].rate = params_rate(params);
+ sitar->dai[dai->id].rate = params_rate(params);
}
}
@@ -2977,30 +3211,30 @@
static int sitar_codec_enable_chmask(struct sitar_priv *sitar,
int event, int index)
{
- int ret = 0;
- u32 k = 0;
+ int ret = 0;
+ struct wcd9xxx_ch *ch;
+
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- for (k = 0; k < sitar->dai[index].ch_tot; k++) {
- ret = wcd9xxx_get_slave_port(
- sitar->dai[index].ch_num[k]);
+ list_for_each_entry(ch,
+ &sitar->dai[index].wcd9xxx_ch_list, list) {
+ ret = wcd9xxx_get_slave_port(ch->ch_num);
if (ret < 0) {
- pr_err("%s: Invalid Slave port ID: %d\n",
- __func__, ret);
+ pr_err("%s: Invalid slave port ID: %d\n",
+ __func__, ret);
ret = -EINVAL;
break;
}
sitar->dai[index].ch_mask |= 1 << ret;
}
- ret = 0;
break;
case SND_SOC_DAPM_POST_PMD:
ret = wait_event_timeout(sitar->dai[index].dai_wait,
(sitar->dai[index].ch_mask == 0),
- msecs_to_jiffies(SLIM_CLOSE_TIMEOUT));
+ msecs_to_jiffies(SLIM_CLOSE_TIMEOUT));
if (!ret) {
- pr_err("%s: slim close tx/rx timeout\n",
- __func__);
+ pr_err("%s: Slim close tx/rx wait timeout\n",
+ __func__);
ret = -EINVAL;
} else {
ret = 0;
@@ -3013,70 +3247,46 @@
static int sitar_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct wcd9xxx *sitar;
+ struct wcd9xxx *core;
struct snd_soc_codec *codec = w->codec;
struct sitar_priv *sitar_p = snd_soc_codec_get_drvdata(codec);
- u32 j = 0;
- int ret = 0;
- codec->control_data = dev_get_drvdata(codec->dev->parent);
- sitar = codec->control_data;
+ int ret = 0;
+ struct wcd9xxx_codec_dai_data *dai;
+
+ core = dev_get_drvdata(codec->dev->parent);
/* Execute the callback only if interface type is slimbus */
if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
- if (event == SND_SOC_DAPM_POST_PMD && (sitar != NULL))
- sitar_codec_pm_runtime_put(sitar);
+ if (event == SND_SOC_DAPM_POST_PMD && (core != NULL))
+ sitar_codec_pm_runtime_put(core);
return 0;
}
+ dai = &sitar_p->dai[w->shift];
+
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- for (j = 0; j < ARRAY_SIZE(sitar_dai); j++) {
- if (sitar_dai[j].id == AIF1_CAP)
- continue;
- if (!strncmp(w->sname,
- sitar_dai[j].playback.stream_name, 13)) {
- ++sitar_p->dai[j].ch_act;
- break;
- }
- }
- if (sitar_p->dai[j].ch_act == sitar_p->dai[j].ch_tot) {
- ret = sitar_codec_enable_chmask(sitar_p, event, j);
- ret = wcd9xxx_cfg_slim_sch_rx(sitar,
- sitar_p->dai[j].ch_num,
- sitar_p->dai[j].ch_tot,
- sitar_p->dai[j].rate);
- }
+ ret = sitar_codec_enable_chmask(sitar_p, SND_SOC_DAPM_POST_PMU,
+ w->shift);
+ ret = wcd9xxx_cfg_slim_sch_rx(core, &dai->wcd9xxx_ch_list,
+ dai->rate, dai->bit_width,
+ &dai->grph);
break;
case SND_SOC_DAPM_POST_PMD:
- for (j = 0; j < ARRAY_SIZE(sitar_dai); j++) {
- if (sitar_dai[j].id == AIF1_CAP)
- continue;
- if (!strncmp(w->sname,
- sitar_dai[j].playback.stream_name, 13)) {
- --sitar_p->dai[j].ch_act;
- break;
- }
- }
- if (!sitar_p->dai[j].ch_act) {
- wcd9xxx_close_slim_sch_rx(sitar,
- sitar_p->dai[j].ch_num,
- sitar_p->dai[j].ch_tot);
- ret = sitar_codec_enable_chmask(sitar_p, event, j);
- if (ret < 0) {
- ret = wcd9xxx_disconnect_port(sitar,
- sitar_p->dai[j].ch_num,
- sitar_p->dai[j].ch_tot,
- 1);
+ ret = wcd9xxx_close_slim_sch_rx(core, &dai->wcd9xxx_ch_list,
+ dai->grph);
+ ret = sitar_codec_enable_chmask(sitar_p, SND_SOC_DAPM_POST_PMD,
+ w->shift);
+ if (ret < 0) {
+ ret = wcd9xxx_disconnect_port(core,
+ &dai->wcd9xxx_ch_list,
+ dai->grph);
pr_info("%s: Disconnect RX port ret = %d\n",
- __func__, ret);
- }
- sitar_p->dai[j].rate = 0;
- memset(sitar_p->dai[j].ch_num, 0, (sizeof(u32)*
- sitar_p->dai[j].ch_tot));
- sitar_p->dai[j].ch_tot = 0;
- if (sitar != NULL)
- sitar_codec_pm_runtime_put(sitar);
+ __func__, ret);
}
+ if (core != NULL)
+ sitar_codec_pm_runtime_put(core);
+ break;
}
return ret;
}
@@ -3084,72 +3294,45 @@
static int sitar_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct wcd9xxx *sitar;
+ struct wcd9xxx *core;
struct snd_soc_codec *codec = w->codec;
struct sitar_priv *sitar_p = snd_soc_codec_get_drvdata(codec);
- /* index to the DAI ID, for now hardcoding */
- u32 j = 0;
+ struct wcd9xxx_codec_dai_data *dai;
int ret = 0;
- codec->control_data = dev_get_drvdata(codec->dev->parent);
- sitar = codec->control_data;
+ core = dev_get_drvdata(codec->dev->parent);
/* Execute the callback only if interface type is slimbus */
if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
- if (event == SND_SOC_DAPM_POST_PMD && (sitar != NULL))
- sitar_codec_pm_runtime_put(sitar);
+ if (event == SND_SOC_DAPM_POST_PMD && (core != NULL))
+ sitar_codec_pm_runtime_put(core);
return 0;
}
+ dai = &sitar_p->dai[w->shift];
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- for (j = 0; j < ARRAY_SIZE(sitar_dai); j++) {
- if (sitar_dai[j].id == AIF1_PB)
- continue;
- if (!strncmp(w->sname,
- sitar_dai[j].capture.stream_name, 13)) {
- ++sitar_p->dai[j].ch_act;
- break;
- }
- }
- if (sitar_p->dai[j].ch_act == sitar_p->dai[j].ch_tot) {
- ret = sitar_codec_enable_chmask(sitar_p, event, j);
- ret = wcd9xxx_cfg_slim_sch_tx(sitar,
- sitar_p->dai[j].ch_num,
- sitar_p->dai[j].ch_tot,
- sitar_p->dai[j].rate);
- }
+ ret = sitar_codec_enable_chmask(sitar_p, SND_SOC_DAPM_POST_PMU,
+ w->shift);
+ ret = wcd9xxx_cfg_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
+ dai->rate, dai->bit_width,
+ &dai->grph);
break;
case SND_SOC_DAPM_POST_PMD:
- for (j = 0; j < ARRAY_SIZE(sitar_dai); j++) {
- if (sitar_dai[j].id == AIF1_PB)
- continue;
- if (!strncmp(w->sname,
- sitar_dai[j].capture.stream_name, 13)) {
- --sitar_p->dai[j].ch_act;
- break;
- }
+ ret = wcd9xxx_close_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
+ dai->grph);
+ ret = sitar_codec_enable_chmask(sitar_p, SND_SOC_DAPM_POST_PMD,
+ w->shift);
+ if (ret < 0) {
+ ret = wcd9xxx_disconnect_port(core,
+ &dai->wcd9xxx_ch_list,
+ dai->grph);
+ pr_info("%s: Disconnect RX port ret = %d\n",
+ __func__, ret);
}
- if (!sitar_p->dai[j].ch_act) {
- wcd9xxx_close_slim_sch_tx(sitar,
- sitar_p->dai[j].ch_num,
- sitar_p->dai[j].ch_tot);
- ret = sitar_codec_enable_chmask(sitar_p, event, j);
- if (ret < 0) {
- ret = wcd9xxx_disconnect_port(sitar,
- sitar_p->dai[j].ch_num,
- sitar_p->dai[j].ch_tot,
- 0);
- pr_info("%s: Disconnect TX port, ret = %d\n",
- __func__, ret);
- }
- sitar_p->dai[j].rate = 0;
- memset(sitar_p->dai[j].ch_num, 0, (sizeof(u32)*
- sitar_p->dai[j].ch_tot));
- sitar_p->dai[j].ch_tot = 0;
- if (sitar != NULL)
- sitar_codec_pm_runtime_put(sitar);
- }
+ if (core != NULL)
+ sitar_codec_pm_runtime_put(core);
+ break;
}
return ret;
}
@@ -5063,16 +5246,16 @@
static int sitar_codec_probe(struct snd_soc_codec *codec)
{
- struct sitar *control;
+ struct wcd9xxx *core;
struct sitar_priv *sitar;
struct snd_soc_dapm_context *dapm = &codec->dapm;
int ret = 0;
int i;
u8 sitar_version;
- int ch_cnt;
+ void *ptr = NULL;
codec->control_data = dev_get_drvdata(codec->dev->parent);
- control = codec->control_data;
+ core = codec->control_data;
sitar = kzalloc(sizeof(struct sitar_priv), GFP_KERNEL);
if (!sitar) {
@@ -5121,12 +5304,35 @@
ARRAY_SIZE(sitar_snd_controls));
snd_soc_dapm_new_controls(dapm, sitar_dapm_widgets,
ARRAY_SIZE(sitar_dapm_widgets));
+
+ ptr = kmalloc((sizeof(sitar_rx_chs) +
+ sizeof(sitar_tx_chs)), GFP_KERNEL);
+ if (!ptr) {
+ pr_err("%s: no mem for slim chan ctl data\n", __func__);
+ ret = -ENOMEM;
+ goto err_nomem_slimch;
+ }
if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
snd_soc_dapm_new_controls(dapm, sitar_dapm_i2s_widgets,
ARRAY_SIZE(sitar_dapm_i2s_widgets));
snd_soc_dapm_add_routes(dapm, audio_i2s_map,
ARRAY_SIZE(audio_i2s_map));
+ for (i = 0; i < ARRAY_SIZE(sitar_i2s_dai); i++)
+ INIT_LIST_HEAD(&sitar->dai[i].wcd9xxx_ch_list);
}
+ if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+ for (i = 0; i < NUM_CODEC_DAIS; i++) {
+ INIT_LIST_HEAD(&sitar->dai[i].wcd9xxx_ch_list);
+ init_waitqueue_head(&sitar->dai[i].dai_wait);
+ }
+ }
+ core->num_rx_port = SITAR_RX_MAX;
+ core->rx_chs = ptr;
+ memcpy(core->rx_chs, sitar_rx_chs, sizeof(sitar_rx_chs));
+ core->num_tx_port = SITAR_TX_MAX;
+ core->tx_chs = ptr + sizeof(sitar_rx_chs);
+ memcpy(core->tx_chs, sitar_tx_chs, sizeof(sitar_tx_chs));
+
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
sitar_version = snd_soc_read(codec, WCD9XXX_A_CHIP_VERSION);
@@ -5212,22 +5418,6 @@
}
wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
- for (i = 0; i < ARRAY_SIZE(sitar_dai); i++) {
- switch (sitar_dai[i].id) {
- case AIF1_PB:
- ch_cnt = sitar_dai[i].playback.channels_max;
- break;
- case AIF1_CAP:
- ch_cnt = sitar_dai[i].capture.channels_max;
- break;
- default:
- continue;
- }
- sitar->dai[i].ch_num = kzalloc((sizeof(unsigned int)*
- ch_cnt), GFP_KERNEL);
- init_waitqueue_head(&sitar->dai[i].dai_wait);
- }
-
codec->ignore_pmdown_time = 1;
#ifdef CONFIG_DEBUG_FS
@@ -5252,6 +5442,8 @@
wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION,
sitar);
err_insert_irq:
+ kfree(ptr);
+err_nomem_slimch:
err_pdata:
mutex_destroy(&sitar->codec_resource_lock);
kfree(sitar);
@@ -5259,7 +5451,6 @@
}
static int sitar_codec_remove(struct snd_soc_codec *codec)
{
- int i;
struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, sitar);
wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_RELEASE, sitar);
@@ -5274,8 +5465,6 @@
sitar_codec_enable_bandgap(codec, SITAR_BANDGAP_OFF);
if (sitar->mbhc_fw)
release_firmware(sitar->mbhc_fw);
- for (i = 0; i < ARRAY_SIZE(sitar_dai); i++)
- kfree(sitar->dai[i].ch_num);
mutex_destroy(&sitar->codec_resource_lock);
kfree(sitar);
return 0;
diff --git a/sound/soc/codecs/wcd9304.h b/sound/soc/codecs/wcd9304.h
index 70b3f0b..13336ef 100644
--- a/sound/soc/codecs/wcd9304.h
+++ b/sound/soc/codecs/wcd9304.h
@@ -191,6 +191,26 @@
extern int sitar_mclk_enable(struct snd_soc_codec *codec, int mclk_enable,
bool dapm);
+/* Number of input and output Slimbus ports
+ */
+enum {
+ SITAR_RX1 = 0,
+ SITAR_RX2,
+ SITAR_RX3,
+ SITAR_RX4,
+ SITAR_RX5,
+ SITAR_RX_MAX,
+};
+
+enum {
+ SITAR_TX1 = 0,
+ SITAR_TX2,
+ SITAR_TX3,
+ SITAR_TX4,
+ SITAR_TX5,
+ SITAR_TX_MAX,
+};
+
extern void *sitar_mbhc_cal_btn_det_mp(const struct sitar_mbhc_btn_detect_cfg
*btn_det,
const enum sitar_mbhc_btn_det_mem mem);
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index b64a6a7..564cad6 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -74,25 +74,33 @@
#define TABLA_OCP_ATTEMPT 1
-#define AIF1_PB 1
-#define AIF1_CAP 2
-#define AIF2_PB 3
-#define AIF2_CAP 4
-#define AIF3_CAP 5
-#define AIF3_PB 6
-
-#define NUM_CODEC_DAIS 6
-#define TABLA_COMP_DIGITAL_GAIN_OFFSET 3
-
-struct tabla_codec_dai_data {
- u32 rate;
- u32 *ch_num;
- u32 ch_act;
- u32 ch_tot;
- u32 ch_mask;
- wait_queue_head_t dai_wait;
+enum {
+ AIF1_PB = 0,
+ AIF1_CAP,
+ AIF2_PB,
+ AIF2_CAP,
+ AIF3_PB,
+ AIF3_CAP,
+ NUM_CODEC_DAIS,
};
+enum {
+ RX_MIX1_INP_SEL_ZERO = 0,
+ RX_MIX1_INP_SEL_SRC1,
+ RX_MIX1_INP_SEL_SRC2,
+ RX_MIX1_INP_SEL_IIR1,
+ RX_MIX1_INP_SEL_IIR2,
+ RX_MIX1_INP_SEL_RX1,
+ RX_MIX1_INP_SEL_RX2,
+ RX_MIX1_INP_SEL_RX3,
+ RX_MIX1_INP_SEL_RX4,
+ RX_MIX1_INP_SEL_RX5,
+ RX_MIX1_INP_SEL_RX6,
+ RX_MIX1_INP_SEL_RX7,
+};
+
+#define TABLA_COMP_DIGITAL_GAIN_OFFSET 3
+
#define TABLA_MCLK_RATE_12288KHZ 12288000
#define TABLA_MCLK_RATE_9600KHZ 9600000
@@ -255,6 +263,38 @@
static struct hpf_work tx_hpf_work[NUM_DECIMATORS];
+static const struct wcd9xxx_ch tabla_rx_chs[TABLA_RX_MAX] = {
+ WCD9XXX_CH(10, 0),
+ WCD9XXX_CH(11, 1),
+ WCD9XXX_CH(12, 2),
+ WCD9XXX_CH(13, 3),
+ WCD9XXX_CH(14, 4),
+ WCD9XXX_CH(15, 5),
+ WCD9XXX_CH(16, 6)
+};
+
+static const struct wcd9xxx_ch tabla_tx_chs[TABLA_TX_MAX] = {
+ WCD9XXX_CH(0, 0),
+ WCD9XXX_CH(1, 1),
+ WCD9XXX_CH(2, 2),
+ WCD9XXX_CH(3, 3),
+ WCD9XXX_CH(4, 4),
+ WCD9XXX_CH(5, 5),
+ WCD9XXX_CH(6, 6),
+ WCD9XXX_CH(7, 7),
+ WCD9XXX_CH(8, 8),
+ WCD9XXX_CH(9, 9)
+};
+
+static const u32 vport_check_table[NUM_CODEC_DAIS] = {
+ 0, /* AIF1_PB */
+ (1 << AIF2_CAP) | (1 << AIF3_CAP), /* AIF1_CAP */
+ 0, /* AIF2_PB */
+ (1 << AIF1_CAP) | (1 << AIF3_CAP), /* AIF2_CAP */
+ 0, /* AIF2_PB */
+ (1 << AIF1_CAP) | (1 << AIF2_CAP), /* AIF2_CAP */
+};
+
struct tabla_priv {
struct snd_soc_codec *codec;
struct tabla_reg_address reg_addr;
@@ -310,7 +350,7 @@
const struct firmware *mbhc_fw;
/* num of slim ports required */
- struct tabla_codec_dai_data dai[NUM_CODEC_DAIS];
+ struct wcd9xxx_codec_dai_data dai[NUM_CODEC_DAIS];
/*compander*/
int comp_enabled[COMPANDER_MAX];
@@ -1682,6 +1722,238 @@
static const struct snd_kcontrol_new lineout4_ground_switch =
SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_4_DAC_CTL, 6, 1, 0);
+static int slim_tx_vport_validation(u32 dai_id, u32 port_id,
+ struct tabla_priv *tabla_p)
+{
+ struct wcd9xxx_ch *ch;
+ int ret = 0;
+ int index = 0;
+ u32 vtable = vport_check_table[dai_id];
+ pr_debug("%s: dai_id %u vtable 0x%x port_id %u\n", __func__,
+ dai_id, vtable, port_id);
+ while (vtable) {
+ if (vtable & 1) {
+ list_for_each_entry(ch,
+ &tabla_p->dai[index].wcd9xxx_ch_list,
+ list) {
+ pr_debug("%s: index %u ch->port %u vtable 0x%x\n",
+ __func__, index, ch->port, vtable);
+ if (ch->port == port_id) {
+ pr_err("%s: TX%u is used by AIF%u_CAP Mixer\n",
+ __func__, port_id + 1,
+ (index + 1)/2);
+ ret = -EINVAL;
+ break;
+ }
+ }
+ }
+ if (ret)
+ break;
+ index++;
+ vtable = vtable >> 1;
+ }
+ return ret;
+}
+
+/* virtual port entries */
+static int slim_tx_mixer_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+
+ ucontrol->value.integer.value[0] = widget->value;
+ return 0;
+}
+
+static int slim_tx_mixer_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_codec *codec = widget->codec;
+ struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
+ struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
+ struct soc_multi_mixer_control *mixer =
+ ((struct soc_multi_mixer_control *)kcontrol->private_value);
+ u32 dai_id = widget->shift;
+ u32 port_id = mixer->shift;
+ u32 enable = ucontrol->value.integer.value[0];
+
+ pr_debug("%s: wname %s cname %s value %u shift %d item %ld\n", __func__,
+ widget->name, ucontrol->id.name, widget->value, widget->shift,
+ ucontrol->value.integer.value[0]);
+
+ mutex_lock(&codec->mutex);
+ if (tabla_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+ if (dai_id != AIF1_CAP) {
+ dev_err(codec->dev, "%s: invalid AIF for I2C mode\n",
+ __func__);
+ mutex_unlock(&codec->mutex);
+ return -EINVAL;
+ }
+ }
+ switch (dai_id) {
+ case AIF1_CAP:
+ case AIF2_CAP:
+ case AIF3_CAP:
+ /* only add to the list if value not set
+ */
+ if (enable && !(widget->value & 1 << port_id)) {
+ if (slim_tx_vport_validation(dai_id,
+ port_id, tabla_p)) {
+ pr_info("%s: TX%u is used by other virtual port\n",
+ __func__, port_id + 1);
+ mutex_unlock(&codec->mutex);
+ return -EINVAL;
+ }
+ widget->value |= 1 << port_id;
+ list_add_tail(&core->tx_chs[port_id].list,
+ &tabla_p->dai[dai_id].wcd9xxx_ch_list
+ );
+ } else if (!enable && (widget->value & 1 << port_id)) {
+ widget->value &= ~(1 << port_id);
+ list_del_init(&core->tx_chs[port_id].list);
+ } else {
+ if (enable)
+ pr_info("%s: TX%u port is used by this virtual port\n",
+ __func__, port_id + 1);
+ else
+ pr_info("%s: TX%u port is not used by this virtual port\n",
+ __func__, port_id + 1);
+ /* avoid update power function */
+ mutex_unlock(&codec->mutex);
+ return 0;
+ }
+ break;
+ default:
+ pr_err("Unknown AIF %d\n", dai_id);
+ mutex_unlock(&codec->mutex);
+ return -EINVAL;
+ }
+ pr_debug("%s: name %s sname %s updated value %u shift %d\n", __func__,
+ widget->name, widget->sname, widget->value, widget->shift);
+
+ snd_soc_dapm_mixer_update_power(widget, kcontrol, enable);
+
+ mutex_unlock(&codec->mutex);
+ return 0;
+}
+
+static int slim_rx_mux_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+
+ ucontrol->value.enumerated.item[0] = widget->value;
+ return 0;
+}
+
+static const char *const slim_rx_mux_text[] = {
+ "ZERO", "AIF1_PB", "AIF2_PB", "AIF3_PB"
+};
+
+static int slim_rx_mux_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_codec *codec = widget->codec;
+ struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
+ struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ u32 port_id = widget->shift;
+
+ pr_debug("%s: wname %s cname %s value %u shift %d item %u\n", __func__,
+ widget->name, ucontrol->id.name, widget->value, widget->shift,
+ ucontrol->value.enumerated.item[0]);
+
+ widget->value = ucontrol->value.enumerated.item[0];
+
+ mutex_lock(&codec->mutex);
+
+ if (tabla_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+ if (widget->value > 1) {
+ dev_err(codec->dev, "%s: invalid AIF for I2C mode\n",
+ __func__);
+ mutex_unlock(&codec->mutex);
+ return -EINVAL;
+ }
+ }
+ /* value need to match the Virtual port and AIF number
+ */
+ switch (widget->value) {
+ case 0:
+ list_del_init(&core->rx_chs[port_id].list);
+ break;
+ case 1:
+ list_add_tail(&core->rx_chs[port_id].list,
+ &tabla_p->dai[AIF1_PB].wcd9xxx_ch_list);
+ break;
+ case 2:
+ list_add_tail(&core->rx_chs[port_id].list,
+ &tabla_p->dai[AIF2_PB].wcd9xxx_ch_list);
+ break;
+ case 3:
+ list_add_tail(&core->rx_chs[port_id].list,
+ &tabla_p->dai[AIF3_PB].wcd9xxx_ch_list);
+ break;
+ default:
+ pr_err("Unknown AIF %d\n", widget->value);
+ mutex_unlock(&codec->mutex);
+ return -EINVAL;
+ }
+
+ snd_soc_dapm_mux_update_power(widget, kcontrol, 1, widget->value, e);
+
+ mutex_unlock(&codec->mutex);
+ return 0;
+}
+
+static const struct soc_enum slim_rx_mux_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim_rx_mux_text), slim_rx_mux_text);
+
+static const struct snd_kcontrol_new slim_rx_mux[TABLA_RX_MAX] = {
+ SOC_DAPM_ENUM_EXT("SLIM RX1 Mux", slim_rx_mux_enum,
+ slim_rx_mux_get, slim_rx_mux_put),
+ SOC_DAPM_ENUM_EXT("SLIM RX2 Mux", slim_rx_mux_enum,
+ slim_rx_mux_get, slim_rx_mux_put),
+ SOC_DAPM_ENUM_EXT("SLIM RX3 Mux", slim_rx_mux_enum,
+ slim_rx_mux_get, slim_rx_mux_put),
+ SOC_DAPM_ENUM_EXT("SLIM RX4 Mux", slim_rx_mux_enum,
+ slim_rx_mux_get, slim_rx_mux_put),
+ SOC_DAPM_ENUM_EXT("SLIM RX5 Mux", slim_rx_mux_enum,
+ slim_rx_mux_get, slim_rx_mux_put),
+ SOC_DAPM_ENUM_EXT("SLIM RX6 Mux", slim_rx_mux_enum,
+ slim_rx_mux_get, slim_rx_mux_put),
+ SOC_DAPM_ENUM_EXT("SLIM RX7 Mux", slim_rx_mux_enum,
+ slim_rx_mux_get, slim_rx_mux_put),
+};
+
+static const struct snd_kcontrol_new aif_cap_mixer[] = {
+ SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, TABLA_TX1, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, TABLA_TX2, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, TABLA_TX3, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, TABLA_TX4, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, TABLA_TX5, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX6", SND_SOC_NOPM, TABLA_TX6, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX7", SND_SOC_NOPM, TABLA_TX7, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX8", SND_SOC_NOPM, TABLA_TX8, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX9", SND_SOC_NOPM, TABLA_TX9, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX10", SND_SOC_NOPM, TABLA_TX10, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+};
+
static void tabla_codec_enable_adc_block(struct snd_soc_codec *codec,
int enable)
{
@@ -3122,13 +3394,47 @@
static const struct snd_soc_dapm_route audio_map[] = {
/* SLIMBUS Connections */
- {"SLIM TX1", NULL, "SLIM TX1 MUX"},
- {"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
+ {"AIF1 CAP", NULL, "AIF1_CAP Mixer"},
+ {"AIF2 CAP", NULL, "AIF2_CAP Mixer"},
+ {"AIF3 CAP", NULL, "AIF3_CAP Mixer"},
- {"SLIM TX2", NULL, "SLIM TX2 MUX"},
+ /* SLIM_MIXER("AIF1_CAP Mixer"),*/
+ {"AIF1_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
+ {"AIF1_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
+ {"AIF1_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
+ {"AIF1_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
+ {"AIF1_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
+ {"AIF1_CAP Mixer", "SLIM TX6", "SLIM TX6 MUX"},
+ {"AIF1_CAP Mixer", "SLIM TX7", "SLIM TX7 MUX"},
+ {"AIF1_CAP Mixer", "SLIM TX8", "SLIM TX8 MUX"},
+ {"AIF1_CAP Mixer", "SLIM TX9", "SLIM TX9 MUX"},
+ {"AIF1_CAP Mixer", "SLIM TX10", "SLIM TX10 MUX"},
+ /* SLIM_MIXER("AIF2_CAP Mixer"),*/
+ {"AIF2_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
+ {"AIF2_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
+ {"AIF2_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
+ {"AIF2_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
+ {"AIF2_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
+ {"AIF2_CAP Mixer", "SLIM TX6", "SLIM TX6 MUX"},
+ {"AIF2_CAP Mixer", "SLIM TX7", "SLIM TX7 MUX"},
+ {"AIF2_CAP Mixer", "SLIM TX8", "SLIM TX8 MUX"},
+ {"AIF2_CAP Mixer", "SLIM TX9", "SLIM TX9 MUX"},
+ {"AIF2_CAP Mixer", "SLIM TX10", "SLIM TX10 MUX"},
+ /* SLIM_MIXER("AIF3_CAP Mixer"),*/
+ {"AIF3_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
+ {"AIF3_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
+ {"AIF3_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
+ {"AIF3_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
+ {"AIF3_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
+ {"AIF3_CAP Mixer", "SLIM TX6", "SLIM TX6 MUX"},
+ {"AIF3_CAP Mixer", "SLIM TX7", "SLIM TX7 MUX"},
+ {"AIF3_CAP Mixer", "SLIM TX8", "SLIM TX8 MUX"},
+ {"AIF3_CAP Mixer", "SLIM TX9", "SLIM TX9 MUX"},
+ {"AIF3_CAP Mixer", "SLIM TX10", "SLIM TX10 MUX"},
+
+ {"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
{"SLIM TX2 MUX", "DEC2", "DEC2 MUX"},
- {"SLIM TX3", NULL, "SLIM TX3 MUX"},
{"SLIM TX3 MUX", "DEC3", "DEC3 MUX"},
{"SLIM TX3 MUX", "RMIX1", "RX1 MIX1"},
{"SLIM TX3 MUX", "RMIX2", "RX2 MIX1"},
@@ -3138,10 +3444,8 @@
{"SLIM TX3 MUX", "RMIX6", "RX6 MIX1"},
{"SLIM TX3 MUX", "RMIX7", "RX7 MIX1"},
- {"SLIM TX4", NULL, "SLIM TX4 MUX"},
{"SLIM TX4 MUX", "DEC4", "DEC4 MUX"},
- {"SLIM TX5", NULL, "SLIM TX5 MUX"},
{"SLIM TX5 MUX", "DEC5", "DEC5 MUX"},
{"SLIM TX5 MUX", "RMIX1", "RX1 MIX1"},
{"SLIM TX5 MUX", "RMIX2", "RX2 MIX1"},
@@ -3151,10 +3455,8 @@
{"SLIM TX5 MUX", "RMIX6", "RX6 MIX1"},
{"SLIM TX5 MUX", "RMIX7", "RX7 MIX1"},
- {"SLIM TX6", NULL, "SLIM TX6 MUX"},
{"SLIM TX6 MUX", "DEC6", "DEC6 MUX"},
- {"SLIM TX7", NULL, "SLIM TX7 MUX"},
{"SLIM TX7 MUX", "DEC1", "DEC1 MUX"},
{"SLIM TX7 MUX", "DEC2", "DEC2 MUX"},
{"SLIM TX7 MUX", "DEC3", "DEC3 MUX"},
@@ -3173,7 +3475,6 @@
{"SLIM TX7 MUX", "RMIX6", "RX6 MIX1"},
{"SLIM TX7 MUX", "RMIX7", "RX7 MIX1"},
- {"SLIM TX8", NULL, "SLIM TX8 MUX"},
{"SLIM TX8 MUX", "DEC1", "DEC1 MUX"},
{"SLIM TX8 MUX", "DEC2", "DEC2 MUX"},
{"SLIM TX8 MUX", "DEC3", "DEC3 MUX"},
@@ -3185,7 +3486,6 @@
{"SLIM TX8 MUX", "DEC9", "DEC9 MUX"},
{"SLIM TX8 MUX", "DEC10", "DEC10 MUX"},
- {"SLIM TX9", NULL, "SLIM TX9 MUX"},
{"SLIM TX9 MUX", "DEC1", "DEC1 MUX"},
{"SLIM TX9 MUX", "DEC2", "DEC2 MUX"},
{"SLIM TX9 MUX", "DEC3", "DEC3 MUX"},
@@ -3197,7 +3497,6 @@
{"SLIM TX9 MUX", "DEC9", "DEC9 MUX"},
{"SLIM TX9 MUX", "DEC10", "DEC10 MUX"},
- {"SLIM TX10", NULL, "SLIM TX10 MUX"},
{"SLIM TX10 MUX", "DEC1", "DEC1 MUX"},
{"SLIM TX10 MUX", "DEC2", "DEC2 MUX"},
{"SLIM TX10 MUX", "DEC3", "DEC3 MUX"},
@@ -3312,6 +3611,40 @@
{"RX3 MIX2", NULL, "RX3 MIX2 INP1"},
{"RX3 MIX2", NULL, "RX3 MIX2 INP2"},
+ /* SLIM_MUX("AIF1_PB", "AIF1 PB"),*/
+ {"SLIM RX1 MUX", "AIF1_PB", "AIF1 PB"},
+ {"SLIM RX2 MUX", "AIF1_PB", "AIF1 PB"},
+ {"SLIM RX3 MUX", "AIF1_PB", "AIF1 PB"},
+ {"SLIM RX4 MUX", "AIF1_PB", "AIF1 PB"},
+ {"SLIM RX5 MUX", "AIF1_PB", "AIF1 PB"},
+ {"SLIM RX6 MUX", "AIF1_PB", "AIF1 PB"},
+ {"SLIM RX7 MUX", "AIF1_PB", "AIF1 PB"},
+ /* SLIM_MUX("AIF2_PB", "AIF2 PB"),*/
+ {"SLIM RX1 MUX", "AIF2_PB", "AIF2 PB"},
+ {"SLIM RX2 MUX", "AIF2_PB", "AIF2 PB"},
+ {"SLIM RX3 MUX", "AIF2_PB", "AIF2 PB"},
+ {"SLIM RX4 MUX", "AIF2_PB", "AIF2 PB"},
+ {"SLIM RX5 MUX", "AIF2_PB", "AIF2 PB"},
+ {"SLIM RX6 MUX", "AIF2_PB", "AIF2 PB"},
+ {"SLIM RX7 MUX", "AIF2_PB", "AIF2 PB"},
+ /* SLIM_MUX("AIF3_PB", "AIF3 PB"),*/
+ {"SLIM RX1 MUX", "AIF3_PB", "AIF3 PB"},
+ {"SLIM RX2 MUX", "AIF3_PB", "AIF3 PB"},
+ {"SLIM RX3 MUX", "AIF3_PB", "AIF3 PB"},
+ {"SLIM RX4 MUX", "AIF3_PB", "AIF3 PB"},
+ {"SLIM RX5 MUX", "AIF3_PB", "AIF3 PB"},
+ {"SLIM RX6 MUX", "AIF3_PB", "AIF3 PB"},
+ {"SLIM RX7 MUX", "AIF3_PB", "AIF3 PB"},
+
+ {"SLIM RX1", NULL, "SLIM RX1 MUX"},
+ {"SLIM RX2", NULL, "SLIM RX2 MUX"},
+ {"SLIM RX3", NULL, "SLIM RX3 MUX"},
+ {"SLIM RX4", NULL, "SLIM RX4 MUX"},
+ {"SLIM RX5", NULL, "SLIM RX5 MUX"},
+ {"SLIM RX6", NULL, "SLIM RX6 MUX"},
+ {"SLIM RX7", NULL, "SLIM RX7 MUX"},
+
+ /* Mixer control for output path */
{"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
{"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
{"RX1 MIX1 INP1", "RX3", "SLIM RX3"},
@@ -3661,6 +3994,10 @@
unsigned int value)
{
int ret;
+
+ if (reg == SND_SOC_NOPM)
+ return 0;
+
BUG_ON(reg > TABLA_MAX_REGISTER);
if (!tabla_volatile(codec, reg)) {
@@ -3678,6 +4015,9 @@
unsigned int val;
int ret;
+ if (reg == SND_SOC_NOPM)
+ return 0;
+
BUG_ON(reg > TABLA_MAX_REGISTER);
if (!tabla_volatile(codec, reg) && tabla_readable(codec, reg) &&
@@ -3801,10 +4141,10 @@
return;
if (dai->id <= NUM_CODEC_DAIS) {
- if (tabla->dai[dai->id-1].ch_mask) {
+ if (tabla->dai[dai->id].ch_mask) {
active = 1;
pr_debug("%s(): Codec DAI: chmask[%d] = 0x%x\n",
- __func__, dai->id-1, tabla->dai[dai->id-1].ch_mask);
+ __func__, dai->id, tabla->dai[dai->id].ch_mask);
}
}
@@ -3925,39 +4265,20 @@
{
struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
- u32 i = 0;
+ struct wcd9xxx *core = dev_get_drvdata(dai->codec->dev->parent);
+
if (!tx_slot && !rx_slot) {
pr_err("%s: Invalid\n", __func__);
return -EINVAL;
}
- pr_debug("%s(): dai_name = %s DAI-ID %x tx_ch %d rx_ch %d\n",
- __func__, dai->name, dai->id, tx_num, rx_num);
+ pr_debug("%s(): dai_name = %s DAI-ID %x tx_ch %d rx_ch %d\n"
+ "tabla->intf_type %d\n",
+ __func__, dai->name, dai->id, tx_num, rx_num,
+ tabla->intf_type);
- if (dai->id == AIF1_PB || dai->id == AIF2_PB || dai->id == AIF3_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 || dai->id == AIF2_CAP ||
- dai->id == AIF3_CAP) {
- tabla->dai[dai->id - 1].ch_tot = tx_num;
- /* All channels are already active.
- * do not reset ch_act flag
- */
- if ((tabla->dai[dai->id - 1].ch_tot != 0)
- && (tabla->dai[dai->id - 1].ch_act ==
- tabla->dai[dai->id - 1].ch_tot)) {
- pr_info("%s: ch_act = %d, ch_tot = %d\n", __func__,
- tabla->dai[dai->id - 1].ch_act,
- tabla->dai[dai->id - 1].ch_tot);
- return 0;
- }
-
- tabla->dai[dai->id - 1].ch_act = 0;
- for (i = 0; i < tx_num; i++)
- tabla->dai[dai->id - 1].ch_num[i] = tx_slot[i];
- }
+ if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+ wcd9xxx_init_slimslave(core, core->slim->laddr,
+ tx_num, tx_slot, rx_num, rx_slot);
return 0;
}
@@ -3966,189 +4287,97 @@
unsigned int *rx_num, unsigned int *rx_slot)
{
- struct wcd9xxx *tabla = dev_get_drvdata(dai->codec->control_data);
+ struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(dai->codec);
+ u32 i = 0;
+ struct wcd9xxx_ch *ch;
- u32 cnt = 0;
- u32 tx_ch[SLIM_MAX_TX_PORTS];
- u32 rx_ch[SLIM_MAX_RX_PORTS];
+ switch (dai->id) {
+ case AIF1_PB:
+ case AIF2_PB:
+ case AIF3_PB:
+ if (!rx_slot || !rx_num) {
+ pr_err("%s: Invalid rx_slot %d or rx_num %d\n",
+ __func__, (u32) rx_slot, (u32) rx_num);
+ return -EINVAL;
+ }
+ list_for_each_entry(ch, &tabla_p->dai[dai->id].wcd9xxx_ch_list,
+ list) {
+ rx_slot[i++] = ch->ch_num;
+ }
+ *rx_num = i;
+ break;
+ case AIF1_CAP:
+ case AIF2_CAP:
+ case AIF3_CAP:
+ if (!tx_slot || !tx_num) {
+ pr_err("%s: Invalid tx_slot %d or tx_num %d\n",
+ __func__, (u32) tx_slot, (u32) tx_num);
+ return -EINVAL;
+ }
+ list_for_each_entry(ch, &tabla_p->dai[dai->id].wcd9xxx_ch_list,
+ list) {
+ tx_slot[i++] = ch->ch_num;
+ }
+ *tx_num = i;
+ break;
- if (!rx_slot && !tx_slot) {
- pr_err("%s: Invalid\n", __func__);
- return -EINVAL;
+ default:
+ pr_err("%s: Invalid DAI ID %x\n", __func__, dai->id);
+ break;
}
-
- /* for virtual port, codec driver needs to do
- * housekeeping, for now should be ok
- */
- wcd9xxx_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++;
- }
- } else if (dai->id == AIF2_PB) {
- *rx_num = tabla_dai[dai->id - 1].playback.channels_max;
- while (cnt < *rx_num) {
- rx_slot[cnt] = rx_ch[5 + cnt];
- cnt++;
- }
- } else if (dai->id == AIF2_CAP) {
- *tx_num = tabla_dai[dai->id - 1].capture.channels_max;
- tx_slot[0] = tx_ch[cnt];
- tx_slot[1] = tx_ch[1 + cnt];
- tx_slot[2] = tx_ch[5 + cnt];
- tx_slot[3] = tx_ch[3 + cnt];
-
- } else if (dai->id == AIF3_PB) {
- *rx_num = tabla_dai[dai->id - 1].playback.channels_max;
- rx_slot[0] = rx_ch[3];
- rx_slot[1] = rx_ch[4];
-
- } else if (dai->id == AIF3_CAP) {
- *tx_num = tabla_dai[dai->id - 1].capture.channels_max;
- tx_slot[cnt] = tx_ch[2 + cnt];
- tx_slot[cnt + 1] = tx_ch[4 + cnt];
- }
- pr_debug("%s(): dai_name = %s DAI-ID %x tx_ch %d rx_ch %d\n",
- __func__, dai->name, dai->id, *tx_num, *rx_num);
-
-
return 0;
}
-static struct snd_soc_dapm_widget tabla_dapm_aif_in_widgets[] = {
-
- SND_SOC_DAPM_AIF_IN_E("SLIM RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 1,
- 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, 2,
- 0, tabla_codec_enable_slimrx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_AIF_IN_E("SLIM RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 3,
- 0, tabla_codec_enable_slimrx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_AIF_IN_E("SLIM RX4", "AIF3 Playback", 0, SND_SOC_NOPM, 4,
- 0, tabla_codec_enable_slimrx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_AIF_IN_E("SLIM RX5", "AIF3 Playback", 0, SND_SOC_NOPM, 5,
- 0, tabla_codec_enable_slimrx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_AIF_IN_E("SLIM RX6", "AIF2 Playback", 0, SND_SOC_NOPM, 6,
- 0, tabla_codec_enable_slimrx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_AIF_IN_E("SLIM RX7", "AIF2 Playback", 0, SND_SOC_NOPM, 7,
- 0, tabla_codec_enable_slimrx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-};
-
-static struct snd_soc_dapm_widget tabla_dapm_aif_out_widgets[] = {
-
- SND_SOC_DAPM_AIF_OUT_E("SLIM TX1", "AIF2 Capture", 0, SND_SOC_NOPM, 1,
- 0, tabla_codec_enable_slimtx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_AIF_OUT_E("SLIM TX2", "AIF2 Capture", 0, SND_SOC_NOPM, 2,
- 0, tabla_codec_enable_slimtx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_AIF_OUT_E("SLIM TX3", "AIF3 Capture", 0, SND_SOC_NOPM, 3,
- 0, tabla_codec_enable_slimtx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_AIF_OUT_E("SLIM TX4", "AIF2 Capture", 0, SND_SOC_NOPM, 4,
- 0, tabla_codec_enable_slimtx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_AIF_OUT_E("SLIM TX5", "AIF3 Capture", 0, SND_SOC_NOPM, 5,
- 0, tabla_codec_enable_slimtx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_AIF_OUT_E("SLIM TX6", "AIF2 Capture", 0, SND_SOC_NOPM, 6,
- 0, tabla_codec_enable_slimtx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_AIF_OUT_E("SLIM TX7", "AIF1 Capture", 0, SND_SOC_NOPM, 7,
- 0, tabla_codec_enable_slimtx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_AIF_OUT_E("SLIM TX8", "AIF1 Capture", 0, SND_SOC_NOPM, 8,
- 0, tabla_codec_enable_slimtx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_AIF_OUT_E("SLIM TX9", "AIF1 Capture", 0, SND_SOC_NOPM, 9,
- 0, tabla_codec_enable_slimtx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_AIF_OUT_E("SLIM TX10", "AIF1 Capture", 0, SND_SOC_NOPM, 10,
- 0, tabla_codec_enable_slimtx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-};
-
static int tabla_set_interpolator_rate(struct snd_soc_dai *dai,
- u8 rx_fs_rate_reg_val, u32 compander_fs, u32 sample_rate)
+ u8 rx_fs_rate_reg_val,
+ u32 compander_fs,
+ u32 sample_rate)
{
- u32 i, j;
+ u32 j;
u8 rx_mix1_inp;
u16 rx_mix_1_reg_1, rx_mix_1_reg_2;
u16 rx_fs_reg;
u8 rx_mix_1_reg_1_val, rx_mix_1_reg_2_val;
struct snd_soc_codec *codec = dai->codec;
+ struct wcd9xxx_ch *ch;
struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
- struct snd_soc_dapm_widget *w = tabla_dapm_aif_in_widgets;
- for (i = 0; i < ARRAY_SIZE(tabla_dapm_aif_in_widgets); i++) {
+ list_for_each_entry(ch, &tabla->dai[dai->id].wcd9xxx_ch_list, list) {
- if (strncmp(dai->driver->playback.stream_name, w[i].sname, 13))
- continue;
+ rx_mix1_inp = ch->port - RX_MIX1_INP_SEL_RX1;
- rx_mix1_inp = w[i].shift + 4;
-
- if ((rx_mix1_inp < 0x5) || (rx_mix1_inp > 0xB)) {
-
- pr_err("%s: Invalid SLIM RX%u port. widget = %s\n",
- __func__, rx_mix1_inp - 4 , w[i].name);
+ if ((rx_mix1_inp < RX_MIX1_INP_SEL_RX1) ||
+ (rx_mix1_inp > RX_MIX1_INP_SEL_RX7)) {
+ pr_err("%s: Invalid TABLA_RX%u port. Dai ID is %d\n",
+ __func__, rx_mix1_inp - 5 , dai->id);
return -EINVAL;
}
rx_mix_1_reg_1 = TABLA_A_CDC_CONN_RX1_B1_CTL;
for (j = 0; j < NUM_INTERPOLATORS; j++) {
-
rx_mix_1_reg_2 = rx_mix_1_reg_1 + 1;
rx_mix_1_reg_1_val = snd_soc_read(codec,
- rx_mix_1_reg_1);
+ rx_mix_1_reg_1);
rx_mix_1_reg_2_val = snd_soc_read(codec,
- rx_mix_1_reg_2);
+ rx_mix_1_reg_2);
if (((rx_mix_1_reg_1_val & 0x0F) == rx_mix1_inp) ||
- (((rx_mix_1_reg_1_val >> 4) & 0x0F) == rx_mix1_inp)
- || ((rx_mix_1_reg_2_val & 0x0F) == rx_mix1_inp)) {
+ (((rx_mix_1_reg_1_val >> 4) & 0x0F) == rx_mix1_inp) ||
+ ((rx_mix_1_reg_2_val & 0x0F) == rx_mix1_inp)) {
rx_fs_reg = TABLA_A_CDC_RX1_B5_CTL + 8 * j;
- pr_debug("%s: %s connected to RX%u\n", __func__,
- w[i].name, j + 1);
+ pr_debug("%s: AIF_PB DAI(%d) connected to RX%u\n",
+ __func__, dai->id, j + 1);
pr_debug("%s: set RX%u sample rate to %u\n",
__func__, j + 1, sample_rate);
snd_soc_update_bits(codec, rx_fs_reg,
- 0xE0, rx_fs_rate_reg_val);
+ 0xE0, rx_fs_rate_reg_val);
if (comp_rx_path[j] < COMPANDER_MAX)
tabla->comp_fs[comp_rx_path[j]]
@@ -4164,26 +4393,26 @@
}
static int tabla_set_decimator_rate(struct snd_soc_dai *dai,
- u8 tx_fs_rate_reg_val, u32 sample_rate)
+ u8 tx_fs_rate_reg_val,
+ u32 sample_rate)
{
struct snd_soc_codec *codec = dai->codec;
- struct snd_soc_dapm_widget *w = tabla_dapm_aif_out_widgets;
-
- u32 i, tx_port;
+ struct wcd9xxx_ch *ch;
+ struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+ u32 tx_port;
u16 tx_port_reg, tx_fs_reg;
u8 tx_port_reg_val;
s8 decimator;
- for (i = 0; i < ARRAY_SIZE(tabla_dapm_aif_out_widgets); i++) {
+ list_for_each_entry(ch, &tabla->dai[dai->id].wcd9xxx_ch_list, list) {
- if (strncmp(dai->driver->capture.stream_name, w[i].sname, 12))
- continue;
-
- tx_port = w[i].shift;
+ tx_port = ch->port + 1;
+ pr_debug("%s: dai->id = %d, tx_port = %d",
+ __func__, dai->id, tx_port);
if ((tx_port < 1) || (tx_port > NUM_DECIMATORS)) {
- pr_err("%s: Invalid SLIM TX%u port. widget = %s\n",
- __func__, tx_port, w[i].name);
+ pr_err("%s: Invalid SLIM TX%u port. DAI ID is %d\n",
+ __func__, tx_port, dai->id);
return -EINVAL;
}
@@ -4212,38 +4441,38 @@
if (decimator) { /* SLIM_TX port has a DEC as input */
tx_fs_reg = TABLA_A_CDC_TX1_CLK_FS_CTL +
- 8 * (decimator - 1);
+ 8 * (decimator - 1);
pr_debug("%s: set DEC%u (-> SLIM_TX%u) rate to %u\n",
__func__, decimator, tx_port, sample_rate);
snd_soc_update_bits(codec, tx_fs_reg, 0x07,
- tx_fs_rate_reg_val);
+ tx_fs_rate_reg_val);
} else {
if ((tx_port_reg_val >= 0x1) &&
- (tx_port_reg_val <= 0x7)) {
+ (tx_port_reg_val <= 0x7)) {
pr_debug("%s: RMIX%u going to SLIM TX%u\n",
__func__, tx_port_reg_val, tx_port);
} else if ((tx_port_reg_val >= 0x8) &&
- (tx_port_reg_val <= 0x11)) {
+ (tx_port_reg_val <= 0x11)) {
pr_err("%s: ERROR: Should not be here\n",
- __func__);
- pr_err("%s: ERROR: DEC connected to SLIM TX%u\n"
- , __func__, tx_port);
+ __func__);
+ pr_err("%s: ERROR: DEC connected to SLIM TX%u\n",
+ __func__, tx_port);
return -EINVAL;
} else if (tx_port_reg_val == 0) {
pr_debug("%s: no signal to SLIM TX%u\n",
- __func__, tx_port);
+ __func__, tx_port);
} else {
- pr_err("%s: ERROR: wrong signal to SLIM TX%u\n"
- , __func__, tx_port);
- pr_err("%s: ERROR: wrong signal = %u\n"
- , __func__, tx_port_reg_val);
+ pr_err("%s: ERROR: wrong signal to SLIM TX%u\n",
+ __func__, tx_port);
+ pr_err("%s: ERROR: wrong signal = %u\n",
+ __func__, tx_port_reg_val);
return -EINVAL;
}
}
@@ -4252,8 +4481,8 @@
}
static int tabla_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
@@ -4262,8 +4491,8 @@
int ret;
pr_debug("%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n", __func__,
- dai->name, dai->id, params_rate(params),
- params_channels(params));
+ dai->name, dai->id, params_rate(params),
+ params_channels(params));
switch (params_rate(params)) {
case 8000:
@@ -4298,7 +4527,7 @@
break;
default:
pr_err("%s: Invalid sampling rate %d\n", __func__,
- params_rate(params));
+ params_rate(params));
return -EINVAL;
}
@@ -4306,10 +4535,10 @@
case SNDRV_PCM_STREAM_CAPTURE:
ret = tabla_set_decimator_rate(dai, tx_fs_rate_reg_val,
- params_rate(params));
+ params_rate(params));
if (ret < 0) {
pr_err("%s: set decimator rate failed %d\n", __func__,
- ret);
+ ret);
return ret;
}
@@ -4324,24 +4553,34 @@
TABLA_A_CDC_CLK_TX_I2S_CTL, 0x20, 0x00);
break;
default:
- pr_err("%s: invalid TX format %u\n", __func__,
- params_format(params));
+ pr_err("%s: Invalid format %d\n", __func__,
+ params_format(params));
return -EINVAL;
}
snd_soc_update_bits(codec, TABLA_A_CDC_CLK_TX_I2S_CTL,
- 0x07, tx_fs_rate_reg_val);
+ 0x07, tx_fs_rate_reg_val);
} else {
- tabla->dai[dai->id - 1].rate = params_rate(params);
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ tabla->dai[dai->id].bit_width = 16;
+ break;
+ default:
+ pr_err("%s: Invalid TX format %d\n", __func__,
+ params_format(params));
+ return -EINVAL;
+ }
+ tabla->dai[dai->id].rate = params_rate(params);
}
break;
case SNDRV_PCM_STREAM_PLAYBACK:
ret = tabla_set_interpolator_rate(dai, rx_fs_rate_reg_val,
- compander_fs, params_rate(params));
+ compander_fs,
+ params_rate(params));
if (ret < 0) {
pr_err("%s: set decimator rate failed %d\n", __func__,
- ret);
+ ret);
return ret;
}
@@ -4356,20 +4595,29 @@
TABLA_A_CDC_CLK_RX_I2S_CTL, 0x20, 0x00);
break;
default:
- pr_err("%s: invalid RX format %u\n", __func__,
- params_format(params));
+ pr_err("%s: Invalid RX format %d\n", __func__,
+ params_format(params));
return -EINVAL;
}
snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_I2S_CTL,
0x03, (rx_fs_rate_reg_val >> 0x05));
} else {
- tabla->dai[dai->id - 1].rate = params_rate(params);
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ tabla->dai[dai->id].bit_width = 16;
+ break;
+ default:
+ pr_err("%s: Invalid format %d\n", __func__,
+ params_format(params));
+ return -EINVAL;
+ }
+ tabla->dai[dai->id].rate = params_rate(params);
}
break;
default:
pr_err("%s: Invalid stream type %d\n", __func__,
- substream->stream);
+ substream->stream);
return -EINVAL;
}
return 0;
@@ -4475,7 +4723,7 @@
static struct snd_soc_dai_driver tabla_i2s_dai[] = {
{
.name = "tabla_i2s_rx1",
- .id = 1,
+ .id = AIF1_PB,
.playback = {
.stream_name = "AIF1 Playback",
.rates = WCD9310_RATES,
@@ -4489,7 +4737,7 @@
},
{
.name = "tabla_i2s_tx1",
- .id = 2,
+ .id = AIF1_CAP,
.capture = {
.stream_name = "AIF1 Capture",
.rates = WCD9310_RATES,
@@ -4504,15 +4752,16 @@
};
static int tabla_codec_enable_chmask(struct tabla_priv *tabla_p,
- int event, int index)
+ int event, int index)
{
int ret = 0;
- u32 k = 0;
+ struct wcd9xxx_ch *ch;
+
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- for (k = 0; k < tabla_p->dai[index].ch_tot; k++) {
- ret = wcd9xxx_get_slave_port(
- tabla_p->dai[index].ch_num[k]);
+ list_for_each_entry(ch,
+ &tabla_p->dai[index].wcd9xxx_ch_list, list) {
+ ret = wcd9xxx_get_slave_port(ch->ch_num);
if (ret < 0) {
pr_err("%s: Invalid slave port ID: %d\n",
__func__, ret);
@@ -4521,7 +4770,6 @@
}
tabla_p->dai[index].ch_mask |= 1 << ret;
}
- ret = 0;
break;
case SND_SOC_DAPM_POST_PMD:
ret = wait_event_timeout(tabla_p->dai[index].dai_wait,
@@ -4531,191 +4779,134 @@
pr_err("%s: Slim close tx/rx wait timeout\n",
__func__);
ret = -EINVAL;
- } else
- ret = 0;
+ }
break;
}
return ret;
}
static int tabla_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+ struct snd_kcontrol *kcontrol,
+ int event)
{
- struct wcd9xxx *tabla;
+ struct wcd9xxx *core;
struct snd_soc_codec *codec = w->codec;
struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
- u32 j = 0;
- int ret = 0;
- codec->control_data = dev_get_drvdata(codec->dev->parent);
- tabla = codec->control_data;
+ u32 ret = 0;
+ struct wcd9xxx_codec_dai_data *dai;
+
+ core = dev_get_drvdata(codec->dev->parent);
+
+ pr_debug("%s: event called! codec name %s num_dai %d\n"
+ "stream name %s event %d\n",
+ __func__, w->codec->name, w->codec->num_dai,
+ w->sname, event);
/* Execute the callback only if interface type is slimbus */
if (tabla_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
- if (event == SND_SOC_DAPM_POST_PMD && (tabla != NULL) &&
- (tabla->dev != NULL) &&
- (tabla->dev->parent != NULL)) {
- pm_runtime_mark_last_busy(tabla->dev->parent);
- pm_runtime_put(tabla->dev->parent);
+ if (event == SND_SOC_DAPM_POST_PMD && (core != NULL) &&
+ (core->dev != NULL) &&
+ (core->dev->parent != NULL)) {
+ pm_runtime_mark_last_busy(core->dev->parent);
+ pm_runtime_put(core->dev->parent);
}
return 0;
}
-
- pr_debug("%s: %s %d\n", __func__, w->name, event);
+ pr_debug("%s: w->name %s w->shift %d event %d\n",
+ __func__, w->name, w->shift, event);
+ dai = &tabla_p->dai[w->shift];
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
- if ((tabla_dai[j].id == AIF1_CAP) ||
- (tabla_dai[j].id == AIF2_CAP) ||
- (tabla_dai[j].id == AIF3_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_codec_enable_chmask(tabla_p,
- SND_SOC_DAPM_POST_PMU,
- j);
- ret = wcd9xxx_cfg_slim_sch_rx(tabla,
- tabla_p->dai[j].ch_num,
- tabla_p->dai[j].ch_tot,
- tabla_p->dai[j].rate);
- }
+ ret = tabla_codec_enable_chmask(tabla_p, SND_SOC_DAPM_POST_PMU,
+ w->shift);
+ ret = wcd9xxx_cfg_slim_sch_rx(core, &dai->wcd9xxx_ch_list,
+ dai->rate, dai->bit_width,
+ &dai->grph);
break;
case SND_SOC_DAPM_POST_PMD:
- for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
- if ((tabla_dai[j].id == AIF1_CAP) ||
- (tabla_dai[j].id == AIF2_CAP) ||
- (tabla_dai[j].id == AIF3_CAP))
- continue;
- if (!strncmp(w->sname,
- tabla_dai[j].playback.stream_name, 13)) {
- if (tabla_p->dai[j].ch_act)
- --tabla_p->dai[j].ch_act;
- break;
- }
+ ret = wcd9xxx_close_slim_sch_rx(core,
+ &dai->wcd9xxx_ch_list,
+ dai->grph);
+ ret = tabla_codec_enable_chmask(tabla_p, SND_SOC_DAPM_POST_PMD,
+ w->shift);
+ if (ret < 0) {
+ ret = wcd9xxx_disconnect_port(core,
+ &dai->wcd9xxx_ch_list,
+ dai->grph);
+ pr_info("%s: Disconnect RX port, ret = %d\n",
+ __func__, ret);
}
- if (!tabla_p->dai[j].ch_act) {
- ret = wcd9xxx_close_slim_sch_rx(tabla,
- tabla_p->dai[j].ch_num,
- tabla_p->dai[j].ch_tot);
- ret = tabla_codec_enable_chmask(tabla_p,
- SND_SOC_DAPM_POST_PMD,
- j);
- if (ret < 0) {
- ret = wcd9xxx_disconnect_port(tabla,
- tabla_p->dai[j].ch_num,
- tabla_p->dai[j].ch_tot,
- 1);
- pr_info("%s: Disconnect RX port ret = %d\n",
- __func__, ret);
- }
- 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;
-
- if ((tabla != NULL) &&
- (tabla->dev != NULL) &&
- (tabla->dev->parent != NULL)) {
- pm_runtime_mark_last_busy(tabla->dev->parent);
- pm_runtime_put(tabla->dev->parent);
- }
+ if ((core != NULL) &&
+ (core->dev != NULL) &&
+ (core->dev->parent != NULL)) {
+ pm_runtime_mark_last_busy(core->dev->parent);
+ pm_runtime_put(core->dev->parent);
}
+ break;
}
+
return ret;
}
static int tabla_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+ struct snd_kcontrol *kcontrol,
+ int event)
{
- struct wcd9xxx *tabla;
+ struct wcd9xxx *core;
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;
- int ret = 0;
+ u32 ret = 0;
+ struct wcd9xxx_codec_dai_data *dai;
- codec->control_data = dev_get_drvdata(codec->dev->parent);
- tabla = codec->control_data;
+ core = dev_get_drvdata(codec->dev->parent);
+
+ pr_debug("%s: event called! codec name %s num_dai %d\n"
+ "stream name %s\n", __func__, w->codec->name,
+ w->codec->num_dai, w->sname);
/* Execute the callback only if interface type is slimbus */
if (tabla_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
- if (event == SND_SOC_DAPM_POST_PMD && (tabla != NULL) &&
- (tabla->dev != NULL) &&
- (tabla->dev->parent != NULL)) {
- pm_runtime_mark_last_busy(tabla->dev->parent);
- pm_runtime_put(tabla->dev->parent);
+ if (event == SND_SOC_DAPM_POST_PMD && (core != NULL) &&
+ (core->dev != NULL) &&
+ (core->dev->parent != NULL)) {
+ pm_runtime_mark_last_busy(core->dev->parent);
+ pm_runtime_put(core->dev->parent);
}
return 0;
}
pr_debug("%s(): %s %d\n", __func__, w->name, event);
+ dai = &tabla_p->dai[w->shift];
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
- if (tabla_dai[j].id == AIF1_PB ||
- tabla_dai[j].id == AIF2_PB ||
- tabla_dai[j].id == AIF3_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_codec_enable_chmask(tabla_p,
- SND_SOC_DAPM_POST_PMU,
- j);
- ret = wcd9xxx_cfg_slim_sch_tx(tabla,
- tabla_p->dai[j].ch_num,
- tabla_p->dai[j].ch_tot,
- tabla_p->dai[j].rate);
- }
+ ret = tabla_codec_enable_chmask(tabla_p, SND_SOC_DAPM_POST_PMU,
+ w->shift);
+ ret = wcd9xxx_cfg_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
+ dai->rate,
+ dai->bit_width,
+ &dai->grph);
break;
case SND_SOC_DAPM_POST_PMD:
- for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
- if (tabla_dai[j].id == AIF1_PB ||
- tabla_dai[j].id == AIF2_PB ||
- tabla_dai[j].id == AIF3_PB)
- continue;
- if (!strncmp(w->sname,
- tabla_dai[j].capture.stream_name, 13)) {
- --tabla_p->dai[j].ch_act;
- break;
- }
+ ret = wcd9xxx_close_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
+ dai->grph);
+ ret = tabla_codec_enable_chmask(tabla_p, SND_SOC_DAPM_POST_PMD,
+ w->shift);
+ if (ret < 0) {
+ ret = wcd9xxx_disconnect_port(core,
+ &dai->wcd9xxx_ch_list,
+ dai->grph);
+ pr_info("%s: Disconnect TX port, ret = %d\n",
+ __func__, ret);
}
- if (!tabla_p->dai[j].ch_act) {
- ret = wcd9xxx_close_slim_sch_tx(tabla,
- tabla_p->dai[j].ch_num,
- tabla_p->dai[j].ch_tot);
- ret = tabla_codec_enable_chmask(tabla_p,
- SND_SOC_DAPM_POST_PMD,
- j);
- if (ret < 0) {
- ret = wcd9xxx_disconnect_port(tabla,
- tabla_p->dai[j].ch_num,
- tabla_p->dai[j].ch_tot, 0);
- pr_info("%s: Disconnect TX port, ret = %d\n",
- __func__, ret);
- }
-
- 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;
- if ((tabla != NULL) &&
- (tabla->dev != NULL) &&
- (tabla->dev->parent != NULL)) {
- pm_runtime_mark_last_busy(tabla->dev->parent);
- pm_runtime_put(tabla->dev->parent);
- }
+ if ((core != NULL) &&
+ (core->dev != NULL) &&
+ (core->dev->parent != NULL)) {
+ pm_runtime_mark_last_busy(core->dev->parent);
+ pm_runtime_put(core->dev->parent);
}
+ break;
}
return ret;
}
@@ -4734,6 +4925,38 @@
SND_SOC_DAPM_MIXER("DAC1", SND_SOC_NOPM, 0, 0, dac1_switch,
ARRAY_SIZE(dac1_switch)),
+ SND_SOC_DAPM_AIF_IN_E("AIF1 PB", "AIF1 Playback", 0, SND_SOC_NOPM,
+ AIF1_PB, 0, tabla_codec_enable_slimrx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_AIF_IN_E("AIF2 PB", "AIF2 Playback", 0, SND_SOC_NOPM,
+ AIF2_PB, 0, tabla_codec_enable_slimrx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_AIF_IN_E("AIF3 PB", "AIF3 Playback", 0, SND_SOC_NOPM,
+ AIF3_PB, 0, tabla_codec_enable_slimrx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("SLIM RX1 MUX", SND_SOC_NOPM, TABLA_RX1, 0,
+ &slim_rx_mux[TABLA_RX1]),
+ SND_SOC_DAPM_MUX("SLIM RX2 MUX", SND_SOC_NOPM, TABLA_RX2, 0,
+ &slim_rx_mux[TABLA_RX2]),
+ SND_SOC_DAPM_MUX("SLIM RX3 MUX", SND_SOC_NOPM, TABLA_RX3, 0,
+ &slim_rx_mux[TABLA_RX3]),
+ SND_SOC_DAPM_MUX("SLIM RX4 MUX", SND_SOC_NOPM, TABLA_RX4, 0,
+ &slim_rx_mux[TABLA_RX4]),
+ SND_SOC_DAPM_MUX("SLIM RX5 MUX", SND_SOC_NOPM, TABLA_RX5, 0,
+ &slim_rx_mux[TABLA_RX5]),
+ SND_SOC_DAPM_MUX("SLIM RX6 MUX", SND_SOC_NOPM, TABLA_RX6, 0,
+ &slim_rx_mux[TABLA_RX6]),
+ SND_SOC_DAPM_MUX("SLIM RX7 MUX", SND_SOC_NOPM, TABLA_RX7, 0,
+ &slim_rx_mux[TABLA_RX7]),
+
+ SND_SOC_DAPM_MIXER("SLIM RX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM RX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM RX3", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM RX4", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM RX5", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM RX6", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM RX7", SND_SOC_NOPM, 0, 0, NULL, 0),
/* Headphone */
SND_SOC_DAPM_OUTPUT("HEADPHONE"),
SND_SOC_DAPM_PGA_E("HPHL", TABLA_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
@@ -5013,16 +5236,47 @@
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_MUX("SLIM TX2 MUX", SND_SOC_NOPM, 0, 0, &sb_tx2_mux),
- SND_SOC_DAPM_MUX("SLIM TX3 MUX", SND_SOC_NOPM, 0, 0, &sb_tx3_mux),
- SND_SOC_DAPM_MUX("SLIM TX4 MUX", SND_SOC_NOPM, 0, 0, &sb_tx4_mux),
- SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, 0, 0, &sb_tx5_mux),
- SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, 0, 0, &sb_tx6_mux),
- SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, 0, 0, &sb_tx7_mux),
- SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, 0, 0, &sb_tx8_mux),
- SND_SOC_DAPM_MUX("SLIM TX9 MUX", SND_SOC_NOPM, 0, 0, &sb_tx9_mux),
- SND_SOC_DAPM_MUX("SLIM TX10 MUX", SND_SOC_NOPM, 0, 0, &sb_tx10_mux),
+ SND_SOC_DAPM_AIF_OUT_E("AIF1 CAP", "AIF1 Capture", 0, SND_SOC_NOPM,
+ AIF1_CAP, 0, tabla_codec_enable_slimtx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_AIF_OUT_E("AIF2 CAP", "AIF2 Capture", 0, SND_SOC_NOPM,
+ AIF2_CAP, 0, tabla_codec_enable_slimtx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_AIF_OUT_E("AIF3 CAP", "AIF3 Capture", 0, SND_SOC_NOPM,
+ AIF3_CAP, 0, tabla_codec_enable_slimtx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MIXER("AIF1_CAP Mixer", SND_SOC_NOPM, AIF1_CAP, 0,
+ aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
+
+ SND_SOC_DAPM_MIXER("AIF2_CAP Mixer", SND_SOC_NOPM, AIF2_CAP, 0,
+ aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
+
+ SND_SOC_DAPM_MIXER("AIF3_CAP Mixer", SND_SOC_NOPM, AIF3_CAP, 0,
+ aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
+
+ SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, TABLA_TX1, 0,
+ &sb_tx1_mux),
+ SND_SOC_DAPM_MUX("SLIM TX2 MUX", SND_SOC_NOPM, TABLA_TX2, 0,
+ &sb_tx2_mux),
+ SND_SOC_DAPM_MUX("SLIM TX3 MUX", SND_SOC_NOPM, TABLA_TX3, 0,
+ &sb_tx3_mux),
+ SND_SOC_DAPM_MUX("SLIM TX4 MUX", SND_SOC_NOPM, TABLA_TX4, 0,
+ &sb_tx4_mux),
+ SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, TABLA_TX5, 0,
+ &sb_tx5_mux),
+ SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, TABLA_TX6, 0,
+ &sb_tx6_mux),
+ SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, TABLA_TX7, 0,
+ &sb_tx7_mux),
+ SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, TABLA_TX8, 0,
+ &sb_tx8_mux),
+ SND_SOC_DAPM_MUX("SLIM TX9 MUX", SND_SOC_NOPM, TABLA_TX9, 0,
+ &sb_tx9_mux),
+ SND_SOC_DAPM_MUX("SLIM TX10 MUX", SND_SOC_NOPM, TABLA_TX10, 0,
+ &sb_tx10_mux),
/* Digital Mic Inputs */
SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
@@ -7608,7 +7862,6 @@
int i, j, port_id, k, ch_mask_temp;
unsigned long slimbus_value;
u8 val;
-
for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++) {
slimbus_value = wcd9xxx_interface_reg_read(codec->control_data,
TABLA_SLIM_PGD_PORT_INT_STATUS0 + i);
@@ -7622,17 +7875,18 @@
pr_err_ratelimited("underflow error on port %x,"
" value %x\n", i*8 + j, val);
if (val & 0x4) {
- pr_debug("%s: port %x disconnect value %x\n",
- __func__, i*8 + j, val);
port_id = i*8 + j;
for (k = 0; k < ARRAY_SIZE(tabla_dai); k++) {
ch_mask_temp = 1 << port_id;
+ pr_debug("%s: tabla_p->dai[%d].ch_mask = 0x%x\n",
+ __func__, k,
+ tabla_p->dai[k].ch_mask);
if (ch_mask_temp &
tabla_p->dai[k].ch_mask) {
tabla_p->dai[k].ch_mask &=
- ~ch_mask_temp;
+ ~ch_mask_temp;
if (!tabla_p->dai[k].ch_mask)
- wake_up(
+ wake_up(
&tabla_p->dai[k].dai_wait);
}
}
@@ -8114,7 +8368,7 @@
struct snd_soc_dapm_context *dapm = &codec->dapm;
int ret = 0;
int i;
- int ch_cnt;
+ void *ptr = NULL;
codec->control_data = dev_get_drvdata(codec->dev->parent);
control = codec->control_data;
@@ -8174,8 +8428,6 @@
goto err_pdata;
}
-// snd_soc_add_codec_controls(codec, tabla_snd_controls,
-// ARRAY_SIZE(tabla_snd_controls));
if (TABLA_IS_1_X(control->version))
snd_soc_add_codec_controls(codec, tabla_1_x_snd_controls,
ARRAY_SIZE(tabla_1_x_snd_controls));
@@ -8183,15 +8435,6 @@
snd_soc_add_codec_controls(codec, tabla_2_higher_snd_controls,
ARRAY_SIZE(tabla_2_higher_snd_controls));
-// snd_soc_dapm_new_controls(dapm, tabla_dapm_widgets,
-// ARRAY_SIZE(tabla_dapm_widgets));
-
- snd_soc_dapm_new_controls(dapm, tabla_dapm_aif_in_widgets,
- ARRAY_SIZE(tabla_dapm_aif_in_widgets));
-
- snd_soc_dapm_new_controls(dapm, tabla_dapm_aif_out_widgets,
- ARRAY_SIZE(tabla_dapm_aif_out_widgets));
-
if (TABLA_IS_1_X(control->version))
snd_soc_dapm_new_controls(dapm, tabla_1_x_dapm_widgets,
ARRAY_SIZE(tabla_1_x_dapm_widgets));
@@ -8199,13 +8442,35 @@
snd_soc_dapm_new_controls(dapm, tabla_2_higher_dapm_widgets,
ARRAY_SIZE(tabla_2_higher_dapm_widgets));
+
+ ptr = kmalloc((sizeof(tabla_rx_chs) +
+ sizeof(tabla_tx_chs)), GFP_KERNEL);
+ if (!ptr) {
+ pr_err("%s: no mem for slim chan ctl data\n", __func__);
+ ret = -ENOMEM;
+ goto err_nomem_slimch;
+ }
if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
snd_soc_dapm_new_controls(dapm, tabla_dapm_i2s_widgets,
ARRAY_SIZE(tabla_dapm_i2s_widgets));
snd_soc_dapm_add_routes(dapm, audio_i2s_map,
ARRAY_SIZE(audio_i2s_map));
+ for (i = 0; i < ARRAY_SIZE(tabla_i2s_dai); i++)
+ INIT_LIST_HEAD(&tabla->dai[i].wcd9xxx_ch_list);
+ } else if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+ for (i = 0; i < NUM_CODEC_DAIS; i++) {
+ INIT_LIST_HEAD(&tabla->dai[i].wcd9xxx_ch_list);
+ init_waitqueue_head(&tabla->dai[i].dai_wait);
+ }
}
-// snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
+
+ control->num_rx_port = TABLA_RX_MAX;
+ control->rx_chs = ptr;
+ memcpy(control->rx_chs, tabla_rx_chs, sizeof(tabla_rx_chs));
+ control->num_tx_port = TABLA_TX_MAX;
+ control->tx_chs = ptr + sizeof(tabla_rx_chs);
+ memcpy(control->tx_chs, tabla_tx_chs, sizeof(tabla_tx_chs));
+
if (TABLA_IS_1_X(control->version)) {
snd_soc_dapm_add_routes(dapm, tabla_1_x_lineout_2_to_4_map,
@@ -8302,33 +8567,6 @@
"tabla_gpio_irq_resend");
tabla->gpio_irq_resend = false;
- 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;
- case AIF2_PB:
- ch_cnt = tabla_dai[i].playback.channels_max;
- break;
- case AIF2_CAP:
- ch_cnt = tabla_dai[i].capture.channels_max;
- break;
- case AIF3_PB:
- ch_cnt = tabla_dai[i].playback.channels_max;
- break;
- case AIF3_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);
- init_waitqueue_head(&tabla->dai[i].dai_wait);
- }
#ifdef CONFIG_DEBUG_FS
if (ret == 0) {
@@ -8360,13 +8598,14 @@
tabla);
err_insert_irq:
err_pdata:
+ kfree(ptr);
+err_nomem_slimch:
mutex_destroy(&tabla->codec_resource_lock);
kfree(tabla);
return ret;
}
static int tabla_codec_remove(struct snd_soc_codec *codec)
{
- int i;
struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
wake_lock_destroy(&tabla->irq_resend_wlock);
@@ -8384,8 +8623,6 @@
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);
mutex_destroy(&tabla->codec_resource_lock);
#ifdef CONFIG_DEBUG_FS
debugfs_remove(tabla->debugfs_poke);
diff --git a/sound/soc/codecs/wcd9310.h b/sound/soc/codecs/wcd9310.h
index 4c9f8b4..98c1835 100644
--- a/sound/soc/codecs/wcd9310.h
+++ b/sound/soc/codecs/wcd9310.h
@@ -252,3 +252,29 @@
sizeof(cfg_ptr->_alpha[0]))))
+/* Number of input and output Slimbus port */
+enum {
+ TABLA_RX1 = 0,
+ TABLA_RX2,
+ TABLA_RX3,
+ TABLA_RX4,
+ TABLA_RX5,
+ TABLA_RX6,
+ TABLA_RX7,
+ TABLA_RX_MAX,
+};
+
+enum {
+ TABLA_TX1 = 0,
+ TABLA_TX2,
+ TABLA_TX3,
+ TABLA_TX4,
+ TABLA_TX5,
+ TABLA_TX6,
+ TABLA_TX7,
+ TABLA_TX8,
+ TABLA_TX9,
+ TABLA_TX10,
+ TABLA_TX_MAX,
+};
+
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index d187ea5..0c36c4a 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -46,6 +46,7 @@
#define TAIKO_CFILT_SLOW_MODE 0x40
#define MBHC_FW_READ_ATTEMPTS 15
#define MBHC_FW_READ_TIMEOUT 2000000
+#define TAIKO_TX_PORT_NUMBER 16
enum {
MBHC_USE_HPHL_TRIGGER = 1,
@@ -63,23 +64,34 @@
#define TAIKO_OCP_ATTEMPT 1
-#define AIF1_PB 1
-#define AIF1_CAP 2
-#define AIF2_PB 3
-#define AIF2_CAP 4
-#define AIF3_CAP 5
-#define AIF3_PB 6
-
-#define NUM_CODEC_DAIS 6
-#define TAIKO_COMP_DIGITAL_GAIN_OFFSET 3
-
-struct taiko_codec_dai_data {
- u32 rate;
- u32 *ch_num;
- u32 ch_act;
- u32 ch_tot;
+enum {
+ AIF1_PB = 0,
+ AIF1_CAP,
+ AIF2_PB,
+ AIF2_CAP,
+ AIF3_PB,
+ AIF3_CAP,
+ NUM_CODEC_DAIS,
};
+enum {
+ RX_MIX1_INP_SEL_ZERO = 0,
+ RX_MIX1_INP_SEL_SRC1,
+ RX_MIX1_INP_SEL_SRC2,
+ RX_MIX1_INP_SEL_IIR1,
+ RX_MIX1_INP_SEL_IIR2,
+ RX_MIX1_INP_SEL_RX1,
+ RX_MIX1_INP_SEL_RX2,
+ RX_MIX1_INP_SEL_RX3,
+ RX_MIX1_INP_SEL_RX4,
+ RX_MIX1_INP_SEL_RX5,
+ RX_MIX1_INP_SEL_RX6,
+ RX_MIX1_INP_SEL_RX7,
+ RX_MIX1_INP_SEL_AUXRX,
+};
+
+#define TAIKO_COMP_DIGITAL_GAIN_OFFSET 3
+
#define TAIKO_MCLK_RATE_12288KHZ 12288000
#define TAIKO_MCLK_RATE_9600KHZ 9600000
@@ -237,6 +249,50 @@
static struct hpf_work tx_hpf_work[NUM_DECIMATORS];
+static const struct wcd9xxx_ch taiko_rx_chs[TAIKO_RX_MAX] = {
+ WCD9XXX_CH(16, 0),
+ WCD9XXX_CH(17, 1),
+ WCD9XXX_CH(18, 2),
+ WCD9XXX_CH(19, 3),
+ WCD9XXX_CH(20, 4),
+ WCD9XXX_CH(21, 5),
+ WCD9XXX_CH(22, 6),
+ WCD9XXX_CH(23, 7),
+ WCD9XXX_CH(24, 8),
+ WCD9XXX_CH(25, 9),
+ WCD9XXX_CH(26, 10),
+ WCD9XXX_CH(27, 11),
+ WCD9XXX_CH(28, 12),
+};
+
+static const struct wcd9xxx_ch taiko_tx_chs[TAIKO_TX_MAX] = {
+ WCD9XXX_CH(0, 0),
+ WCD9XXX_CH(1, 1),
+ WCD9XXX_CH(2, 2),
+ WCD9XXX_CH(3, 3),
+ WCD9XXX_CH(4, 4),
+ WCD9XXX_CH(5, 5),
+ WCD9XXX_CH(6, 6),
+ WCD9XXX_CH(7, 7),
+ WCD9XXX_CH(8, 8),
+ WCD9XXX_CH(9, 9),
+ WCD9XXX_CH(10, 10),
+ WCD9XXX_CH(11, 11),
+ WCD9XXX_CH(12, 12),
+ WCD9XXX_CH(13, 13),
+ WCD9XXX_CH(14, 14),
+ WCD9XXX_CH(15, 15),
+};
+
+static const u32 vport_check_table[NUM_CODEC_DAIS] = {
+ 0, /* AIF1_PB */
+ (1 << AIF2_CAP) | (1 << AIF3_CAP), /* AIF1_CAP */
+ 0, /* AIF2_PB */
+ (1 << AIF1_CAP) | (1 << AIF3_CAP), /* AIF2_CAP */
+ 0, /* AIF2_PB */
+ (1 << AIF1_CAP) | (1 << AIF2_CAP), /* AIF2_CAP */
+};
+
struct taiko_priv {
struct snd_soc_codec *codec;
struct taiko_reg_address reg_addr;
@@ -292,7 +348,7 @@
const struct firmware *mbhc_fw;
/* num of slim ports required */
- struct taiko_codec_dai_data dai[NUM_CODEC_DAIS];
+ struct wcd9xxx_codec_dai_data dai[NUM_CODEC_DAIS];
/*compander*/
int comp_enabled[COMPANDER_MAX];
@@ -1604,6 +1660,240 @@
static const struct snd_kcontrol_new lineout4_ground_switch =
SOC_DAPM_SINGLE("Switch", TAIKO_A_RX_LINE_4_DAC_CTL, 6, 1, 0);
+static int slim_tx_vport_validation(u32 dai_id, u32 port_id,
+ struct taiko_priv *taiko_p)
+{
+ struct wcd9xxx_ch *ch;
+ int ret = 0;
+ int index = 0;
+ u32 vtable = vport_check_table[dai_id];
+ pr_debug("%s: dai_id %u vtable 0x%x port_id %u\n", __func__,
+ dai_id, vtable, port_id);
+ while (vtable) {
+ if (vtable & 1) {
+ list_for_each_entry(ch,
+ &taiko_p->dai[index].wcd9xxx_ch_list,
+ list) {
+ pr_debug("%s: index %u ch->port %u vtable 0x%x\n",
+ __func__, index, ch->port, vtable);
+ if (ch->port == port_id) {
+ pr_err("%s: TX%u is used by AIF%u_CAP Mixer\n",
+ __func__, port_id + 1,
+ (index + 1)/2);
+ ret = -EINVAL;
+ break;
+ }
+ }
+ }
+ if (ret)
+ break;
+ index++;
+ vtable = vtable >> 1;
+ }
+ return ret;
+}
+
+/* virtual port entries */
+static int slim_tx_mixer_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+
+ ucontrol->value.integer.value[0] = widget->value;
+ return 0;
+}
+
+static int slim_tx_mixer_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_codec *codec = widget->codec;
+ struct taiko_priv *taiko_p = snd_soc_codec_get_drvdata(codec);
+ struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
+ struct soc_multi_mixer_control *mixer =
+ ((struct soc_multi_mixer_control *)kcontrol->private_value);
+ u32 dai_id = widget->shift;
+ u32 port_id = mixer->shift;
+ u32 enable = ucontrol->value.integer.value[0];
+
+
+ pr_debug("%s: wname %s cname %s value %u shift %d item %ld\n", __func__,
+ widget->name, ucontrol->id.name, widget->value, widget->shift,
+ ucontrol->value.integer.value[0]);
+
+ mutex_lock(&codec->mutex);
+
+ if (taiko_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+ if (dai_id != AIF1_CAP) {
+ dev_err(codec->dev, "%s: invalid AIF for I2C mode\n",
+ __func__);
+ mutex_unlock(&codec->mutex);
+ return -EINVAL;
+ }
+ }
+ switch (dai_id) {
+ case AIF1_CAP:
+ case AIF2_CAP:
+ case AIF3_CAP:
+ /* only add to the list if value not set
+ */
+ if (enable && !(widget->value & 1 << port_id)) {
+ if (slim_tx_vport_validation(dai_id,
+ port_id, taiko_p)) {
+ pr_info("%s: TX%u is used by other virtual port\n",
+ __func__, port_id + 1);
+ mutex_unlock(&codec->mutex);
+ return -EINVAL;
+ }
+ widget->value |= 1 << port_id;
+ list_add_tail(&core->tx_chs[port_id].list,
+ &taiko_p->dai[dai_id].wcd9xxx_ch_list
+ );
+ } else if (!enable && (widget->value & 1 << port_id)) {
+ widget->value &= ~(1 << port_id);
+ list_del_init(&core->tx_chs[port_id].list);
+ } else {
+ if (enable)
+ pr_info("%s: TX%u port is used by this virtual port\n",
+ __func__, port_id + 1);
+ else
+ pr_info("%s: TX%u port is not used by this virtual port\n",
+ __func__, port_id + 1);
+ /* avoid update power function */
+ mutex_unlock(&codec->mutex);
+ return 0;
+ }
+ break;
+ default:
+ pr_err("Unknown AIF %d\n", dai_id);
+ mutex_unlock(&codec->mutex);
+ return -EINVAL;
+ }
+ pr_debug("%s: name %s sname %s updated value %u shift %d\n", __func__,
+ widget->name, widget->sname, widget->value, widget->shift);
+
+ snd_soc_dapm_mixer_update_power(widget, kcontrol, enable);
+
+ mutex_unlock(&codec->mutex);
+ return 0;
+}
+
+static int slim_rx_mux_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+
+ ucontrol->value.enumerated.item[0] = widget->value;
+ return 0;
+}
+
+static const char *const slim_rx_mux_text[] = {
+ "ZERO", "AIF1_PB", "AIF2_PB", "AIF3_PB"
+};
+
+static int slim_rx_mux_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_codec *codec = widget->codec;
+ struct taiko_priv *taiko_p = snd_soc_codec_get_drvdata(codec);
+ struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ u32 port_id = widget->shift;
+
+ pr_debug("%s: wname %s cname %s value %u shift %d item %ld\n", __func__,
+ widget->name, ucontrol->id.name, widget->value, widget->shift,
+ ucontrol->value.integer.value[0]);
+
+ widget->value = ucontrol->value.enumerated.item[0];
+
+ mutex_lock(&codec->mutex);
+
+ if (taiko_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+ if (widget->value > 1) {
+ dev_err(codec->dev, "%s: invalid AIF for I2C mode\n",
+ __func__);
+ mutex_unlock(&codec->mutex);
+ return -EINVAL;
+ }
+ }
+ /* value need to match the Virtual port and AIF number
+ */
+ switch (widget->value) {
+ case 0:
+ list_del_init(&core->rx_chs[port_id].list);
+ break;
+ case 1:
+ list_add_tail(&core->rx_chs[port_id].list,
+ &taiko_p->dai[AIF1_PB].wcd9xxx_ch_list);
+ break;
+ case 2:
+ list_add_tail(&core->rx_chs[port_id].list,
+ &taiko_p->dai[AIF2_PB].wcd9xxx_ch_list);
+ break;
+ case 3:
+ list_add_tail(&core->rx_chs[port_id].list,
+ &taiko_p->dai[AIF3_PB].wcd9xxx_ch_list);
+ break;
+ default:
+ pr_err("Unknown AIF %d\n", widget->value);
+ mutex_unlock(&codec->mutex);
+ return -EINVAL;
+ }
+
+ snd_soc_dapm_mux_update_power(widget, kcontrol, 1, widget->value, e);
+
+ mutex_unlock(&codec->mutex);
+ return 0;
+}
+
+static const struct soc_enum slim_rx_mux_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim_rx_mux_text), slim_rx_mux_text);
+
+static const struct snd_kcontrol_new slim_rx_mux[TAIKO_RX_MAX] = {
+ SOC_DAPM_ENUM_EXT("SLIM RX1 Mux", slim_rx_mux_enum,
+ slim_rx_mux_get, slim_rx_mux_put),
+ SOC_DAPM_ENUM_EXT("SLIM RX2 Mux", slim_rx_mux_enum,
+ slim_rx_mux_get, slim_rx_mux_put),
+ SOC_DAPM_ENUM_EXT("SLIM RX3 Mux", slim_rx_mux_enum,
+ slim_rx_mux_get, slim_rx_mux_put),
+ SOC_DAPM_ENUM_EXT("SLIM RX4 Mux", slim_rx_mux_enum,
+ slim_rx_mux_get, slim_rx_mux_put),
+ SOC_DAPM_ENUM_EXT("SLIM RX5 Mux", slim_rx_mux_enum,
+ slim_rx_mux_get, slim_rx_mux_put),
+ SOC_DAPM_ENUM_EXT("SLIM RX6 Mux", slim_rx_mux_enum,
+ slim_rx_mux_get, slim_rx_mux_put),
+ SOC_DAPM_ENUM_EXT("SLIM RX7 Mux", slim_rx_mux_enum,
+ slim_rx_mux_get, slim_rx_mux_put),
+};
+
+static const struct snd_kcontrol_new aif_cap_mixer[] = {
+ SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, TAIKO_TX1, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, TAIKO_TX2, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, TAIKO_TX3, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, TAIKO_TX4, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, TAIKO_TX5, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX6", SND_SOC_NOPM, TAIKO_TX6, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX7", SND_SOC_NOPM, TAIKO_TX7, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX8", SND_SOC_NOPM, TAIKO_TX8, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX9", SND_SOC_NOPM, TAIKO_TX9, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+ SOC_SINGLE_EXT("SLIM TX10", SND_SOC_NOPM, TAIKO_TX10, 1, 0,
+ slim_tx_mixer_get, slim_tx_mixer_put),
+};
+
static void taiko_codec_enable_adc_block(struct snd_soc_codec *codec,
int enable)
{
@@ -2965,14 +3255,48 @@
static const struct snd_soc_dapm_route audio_map[] = {
/* SLIMBUS Connections */
+ {"AIF1 CAP", NULL, "AIF1_CAP Mixer"},
+ {"AIF2 CAP", NULL, "AIF2_CAP Mixer"},
+ {"AIF3 CAP", NULL, "AIF3_CAP Mixer"},
- {"SLIM TX1", NULL, "SLIM TX1 MUX"},
+ /* SLIM_MIXER("AIF1_CAP Mixer"),*/
+ {"AIF1_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
+ {"AIF1_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
+ {"AIF1_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
+ {"AIF1_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
+ {"AIF1_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
+ {"AIF1_CAP Mixer", "SLIM TX6", "SLIM TX6 MUX"},
+ {"AIF1_CAP Mixer", "SLIM TX7", "SLIM TX7 MUX"},
+ {"AIF1_CAP Mixer", "SLIM TX8", "SLIM TX8 MUX"},
+ {"AIF1_CAP Mixer", "SLIM TX9", "SLIM TX9 MUX"},
+ {"AIF1_CAP Mixer", "SLIM TX10", "SLIM TX10 MUX"},
+ /* SLIM_MIXER("AIF2_CAP Mixer"),*/
+ {"AIF2_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
+ {"AIF2_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
+ {"AIF2_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
+ {"AIF2_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
+ {"AIF2_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
+ {"AIF2_CAP Mixer", "SLIM TX6", "SLIM TX6 MUX"},
+ {"AIF2_CAP Mixer", "SLIM TX7", "SLIM TX7 MUX"},
+ {"AIF2_CAP Mixer", "SLIM TX8", "SLIM TX8 MUX"},
+ {"AIF2_CAP Mixer", "SLIM TX9", "SLIM TX9 MUX"},
+ {"AIF2_CAP Mixer", "SLIM TX10", "SLIM TX10 MUX"},
+ /* SLIM_MIXER("AIF3_CAP Mixer"),*/
+ {"AIF3_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
+ {"AIF3_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
+ {"AIF3_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
+ {"AIF3_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
+ {"AIF3_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
+ {"AIF3_CAP Mixer", "SLIM TX6", "SLIM TX6 MUX"},
+ {"AIF3_CAP Mixer", "SLIM TX7", "SLIM TX7 MUX"},
+ {"AIF3_CAP Mixer", "SLIM TX8", "SLIM TX8 MUX"},
+ {"AIF3_CAP Mixer", "SLIM TX9", "SLIM TX9 MUX"},
+ {"AIF3_CAP Mixer", "SLIM TX10", "SLIM TX10 MUX"},
+
{"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
- {"SLIM TX2", NULL, "SLIM TX2 MUX"},
{"SLIM TX2 MUX", "DEC2", "DEC2 MUX"},
- {"SLIM TX3", NULL, "SLIM TX3 MUX"},
{"SLIM TX3 MUX", "DEC3", "DEC3 MUX"},
{"SLIM TX3 MUX", "RMIX1", "RX1 MIX1"},
{"SLIM TX3 MUX", "RMIX2", "RX2 MIX1"},
@@ -2982,10 +3306,8 @@
{"SLIM TX3 MUX", "RMIX6", "RX6 MIX1"},
{"SLIM TX3 MUX", "RMIX7", "RX7 MIX1"},
- {"SLIM TX4", NULL, "SLIM TX4 MUX"},
{"SLIM TX4 MUX", "DEC4", "DEC4 MUX"},
- {"SLIM TX5", NULL, "SLIM TX5 MUX"},
{"SLIM TX5 MUX", "DEC5", "DEC5 MUX"},
{"SLIM TX5 MUX", "RMIX1", "RX1 MIX1"},
{"SLIM TX5 MUX", "RMIX2", "RX2 MIX1"},
@@ -2995,10 +3317,8 @@
{"SLIM TX5 MUX", "RMIX6", "RX6 MIX1"},
{"SLIM TX5 MUX", "RMIX7", "RX7 MIX1"},
- {"SLIM TX6", NULL, "SLIM TX6 MUX"},
{"SLIM TX6 MUX", "DEC6", "DEC6 MUX"},
- {"SLIM TX7", NULL, "SLIM TX7 MUX"},
{"SLIM TX7 MUX", "DEC1", "DEC1 MUX"},
{"SLIM TX7 MUX", "DEC2", "DEC2 MUX"},
{"SLIM TX7 MUX", "DEC3", "DEC3 MUX"},
@@ -3017,7 +3337,6 @@
{"SLIM TX7 MUX", "RMIX6", "RX6 MIX1"},
{"SLIM TX7 MUX", "RMIX7", "RX7 MIX1"},
- {"SLIM TX8", NULL, "SLIM TX8 MUX"},
{"SLIM TX8 MUX", "DEC1", "DEC1 MUX"},
{"SLIM TX8 MUX", "DEC2", "DEC2 MUX"},
{"SLIM TX8 MUX", "DEC3", "DEC3 MUX"},
@@ -3029,7 +3348,6 @@
{"SLIM TX8 MUX", "DEC9", "DEC9 MUX"},
{"SLIM TX8 MUX", "DEC10", "DEC10 MUX"},
- {"SLIM TX9", NULL, "SLIM TX9 MUX"},
{"SLIM TX9 MUX", "DEC1", "DEC1 MUX"},
{"SLIM TX9 MUX", "DEC2", "DEC2 MUX"},
{"SLIM TX9 MUX", "DEC3", "DEC3 MUX"},
@@ -3041,7 +3359,6 @@
{"SLIM TX9 MUX", "DEC9", "DEC9 MUX"},
{"SLIM TX9 MUX", "DEC10", "DEC10 MUX"},
- {"SLIM TX10", NULL, "SLIM TX10 MUX"},
{"SLIM TX10 MUX", "DEC1", "DEC1 MUX"},
{"SLIM TX10 MUX", "DEC2", "DEC2 MUX"},
{"SLIM TX10 MUX", "DEC3", "DEC3 MUX"},
@@ -3172,6 +3489,39 @@
{"RX7 MIX2", NULL, "RX7 MIX2 INP1"},
{"RX7 MIX2", NULL, "RX7 MIX2 INP2"},
+ /* SLIM_MUX("AIF1_PB", "AIF1 PB"),*/
+ {"SLIM RX1 MUX", "AIF1_PB", "AIF1 PB"},
+ {"SLIM RX2 MUX", "AIF1_PB", "AIF1 PB"},
+ {"SLIM RX3 MUX", "AIF1_PB", "AIF1 PB"},
+ {"SLIM RX4 MUX", "AIF1_PB", "AIF1 PB"},
+ {"SLIM RX5 MUX", "AIF1_PB", "AIF1 PB"},
+ {"SLIM RX6 MUX", "AIF1_PB", "AIF1 PB"},
+ {"SLIM RX7 MUX", "AIF1_PB", "AIF1 PB"},
+ /* SLIM_MUX("AIF2_PB", "AIF2 PB"),*/
+ {"SLIM RX1 MUX", "AIF2_PB", "AIF2 PB"},
+ {"SLIM RX2 MUX", "AIF2_PB", "AIF2 PB"},
+ {"SLIM RX3 MUX", "AIF2_PB", "AIF2 PB"},
+ {"SLIM RX4 MUX", "AIF2_PB", "AIF2 PB"},
+ {"SLIM RX5 MUX", "AIF2_PB", "AIF2 PB"},
+ {"SLIM RX6 MUX", "AIF2_PB", "AIF2 PB"},
+ {"SLIM RX7 MUX", "AIF2_PB", "AIF2 PB"},
+ /* SLIM_MUX("AIF3_PB", "AIF3 PB"),*/
+ {"SLIM RX1 MUX", "AIF3_PB", "AIF3 PB"},
+ {"SLIM RX2 MUX", "AIF3_PB", "AIF3 PB"},
+ {"SLIM RX3 MUX", "AIF3_PB", "AIF3 PB"},
+ {"SLIM RX4 MUX", "AIF3_PB", "AIF3 PB"},
+ {"SLIM RX5 MUX", "AIF3_PB", "AIF3 PB"},
+ {"SLIM RX6 MUX", "AIF3_PB", "AIF3 PB"},
+ {"SLIM RX7 MUX", "AIF3_PB", "AIF3 PB"},
+
+ {"SLIM RX1", NULL, "SLIM RX1 MUX"},
+ {"SLIM RX2", NULL, "SLIM RX2 MUX"},
+ {"SLIM RX3", NULL, "SLIM RX3 MUX"},
+ {"SLIM RX4", NULL, "SLIM RX4 MUX"},
+ {"SLIM RX5", NULL, "SLIM RX5 MUX"},
+ {"SLIM RX6", NULL, "SLIM RX6 MUX"},
+ {"SLIM RX7", NULL, "SLIM RX7 MUX"},
+
{"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
{"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
{"RX1 MIX1 INP1", "RX3", "SLIM RX3"},
@@ -3448,6 +3798,10 @@
unsigned int value)
{
int ret;
+
+ if (reg == SND_SOC_NOPM)
+ return 0;
+
BUG_ON(reg > TAIKO_MAX_REGISTER);
if (!taiko_volatile(codec, reg)) {
@@ -3465,6 +3819,9 @@
unsigned int val;
int ret;
+ if (reg == SND_SOC_NOPM)
+ return 0;
+
BUG_ON(reg > TAIKO_MAX_REGISTER);
if (!taiko_volatile(codec, reg) && taiko_readable(codec, reg) &&
@@ -3690,90 +4047,221 @@
{
struct taiko_priv *taiko = snd_soc_codec_get_drvdata(dai->codec);
- u32 i = 0;
+ struct wcd9xxx *core = dev_get_drvdata(dai->codec->dev->parent);
if (!tx_slot && !rx_slot) {
pr_err("%s: Invalid\n", __func__);
return -EINVAL;
}
- pr_debug("%s(): dai_name = %s DAI-ID %x tx_ch %d rx_ch %d\n",
- __func__, dai->name, dai->id, tx_num, rx_num);
+ pr_debug("%s(): dai_name = %s DAI-ID %x tx_ch %d rx_ch %d\n"
+ "taiko->intf_type %d\n",
+ __func__, dai->name, dai->id, tx_num, rx_num,
+ taiko->intf_type);
- if (dai->id == AIF1_PB || dai->id == AIF2_PB || dai->id == AIF3_PB) {
- for (i = 0; i < rx_num; i++) {
- taiko->dai[dai->id - 1].ch_num[i] = rx_slot[i];
- taiko->dai[dai->id - 1].ch_act = 0;
- taiko->dai[dai->id - 1].ch_tot = rx_num;
+ if (taiko->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+ wcd9xxx_init_slimslave(core, core->slim->laddr,
+ tx_num, tx_slot, rx_num, rx_slot);
+ return 0;
+}
+
+static int taiko_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 taiko_priv *taiko_p = snd_soc_codec_get_drvdata(dai->codec);
+ u32 i = 0;
+ struct wcd9xxx_ch *ch;
+
+ switch (dai->id) {
+ case AIF1_PB:
+ case AIF2_PB:
+ case AIF3_PB:
+ if (!rx_slot || !rx_num) {
+ pr_err("%s: Invalid rx_slot %d or rx_num %d\n",
+ __func__, (u32) rx_slot, (u32) rx_num);
+ return -EINVAL;
}
- } else if (dai->id == AIF1_CAP || dai->id == AIF2_CAP ||
- dai->id == AIF3_CAP) {
- for (i = 0; i < tx_num; i++) {
- taiko->dai[dai->id - 1].ch_num[i] = tx_slot[i];
- taiko->dai[dai->id - 1].ch_act = 0;
- taiko->dai[dai->id - 1].ch_tot = tx_num;
+ list_for_each_entry(ch, &taiko_p->dai[dai->id].wcd9xxx_ch_list,
+ list) {
+ pr_debug("%s: tx_slot[%d] %d, ch->ch_num %d\n",
+ __func__, i, tx_slot[i], ch->ch_num);
+ rx_slot[i++] = ch->ch_num;
+ }
+ pr_debug("%s: rx_num %d\n", __func__, i);
+ *rx_num = i;
+ break;
+ case AIF1_CAP:
+ case AIF2_CAP:
+ case AIF3_CAP:
+ if (!tx_slot || !tx_num) {
+ pr_err("%s: Invalid tx_slot %d or tx_num %d\n",
+ __func__, (u32) tx_slot, (u32) tx_num);
+ return -EINVAL;
+ }
+ list_for_each_entry(ch, &taiko_p->dai[dai->id].wcd9xxx_ch_list,
+ list) {
+ pr_debug("%s: tx_slot[%d] %d, ch->ch_num %d\n",
+ __func__, i, tx_slot[i], ch->ch_num);
+ tx_slot[i++] = ch->ch_num;
+ }
+ pr_debug("%s: tx_num %d\n", __func__, i);
+ *tx_num = i;
+ break;
+
+ default:
+ pr_err("%s: Invalid DAI ID %x\n", __func__, dai->id);
+ break;
+ }
+
+ return 0;
+}
+
+static int taiko_set_interpolator_rate(struct snd_soc_dai *dai,
+ u8 rx_fs_rate_reg_val, u32 compander_fs, u32 sample_rate)
+{
+ u32 j;
+ u8 rx_mix1_inp;
+ u16 rx_mix_1_reg_1, rx_mix_1_reg_2;
+ u16 rx_fs_reg;
+ u8 rx_mix_1_reg_1_val, rx_mix_1_reg_2_val;
+ struct snd_soc_codec *codec = dai->codec;
+ struct wcd9xxx_ch *ch;
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+
+ list_for_each_entry(ch, &taiko->dai[dai->id].wcd9xxx_ch_list, list) {
+ /* for RX port starting from 16 instead of 10 like tabla */
+ rx_mix1_inp = ch->port + RX_MIX1_INP_SEL_RX1 -
+ TAIKO_TX_PORT_NUMBER;
+ if ((rx_mix1_inp < RX_MIX1_INP_SEL_RX1) ||
+ (rx_mix1_inp > RX_MIX1_INP_SEL_RX7)) {
+ pr_err("%s: Invalid TAIKO_RX%u port. Dai ID is %d\n",
+ __func__, rx_mix1_inp - 5 , dai->id);
+ return -EINVAL;
+ }
+
+ rx_mix_1_reg_1 = TAIKO_A_CDC_CONN_RX1_B1_CTL;
+
+ for (j = 0; j < NUM_INTERPOLATORS; j++) {
+ rx_mix_1_reg_2 = rx_mix_1_reg_1 + 1;
+
+ rx_mix_1_reg_1_val = snd_soc_read(codec,
+ rx_mix_1_reg_1);
+ rx_mix_1_reg_2_val = snd_soc_read(codec,
+ rx_mix_1_reg_2);
+
+ if (((rx_mix_1_reg_1_val & 0x0F) == rx_mix1_inp) ||
+ (((rx_mix_1_reg_1_val >> 4) & 0x0F)
+ == rx_mix1_inp) ||
+ ((rx_mix_1_reg_2_val & 0x0F) == rx_mix1_inp)) {
+
+ rx_fs_reg = TAIKO_A_CDC_RX1_B5_CTL + 8 * j;
+
+ pr_debug("%s: AIF_PB DAI(%d) connected to RX%u\n",
+ __func__, dai->id, j + 1);
+
+ pr_debug("%s: set RX%u sample rate to %u\n",
+ __func__, j + 1, sample_rate);
+
+ snd_soc_update_bits(codec, rx_fs_reg,
+ 0xE0, rx_fs_rate_reg_val);
+
+ if (comp_rx_path[j] < COMPANDER_MAX)
+ taiko->comp_fs[comp_rx_path[j]]
+ = compander_fs;
+ }
+ if (j <= 2)
+ rx_mix_1_reg_1 += 3;
+ else
+ rx_mix_1_reg_1 += 2;
}
}
return 0;
}
-static int taiko_get_channel_map(struct snd_soc_dai *dai,
- unsigned int *tx_num, unsigned int *tx_slot,
- unsigned int *rx_num, unsigned int *rx_slot)
-
+static int taiko_set_decimator_rate(struct snd_soc_dai *dai,
+ u8 tx_fs_rate_reg_val, u32 sample_rate)
{
- struct wcd9xxx *taiko = dev_get_drvdata(dai->codec->control_data);
+ struct snd_soc_codec *codec = dai->codec;
+ struct wcd9xxx_ch *ch;
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+ u32 tx_port;
+ u16 tx_port_reg, tx_fs_reg;
+ u8 tx_port_reg_val;
+ s8 decimator;
- u32 cnt = 0;
- u32 tx_ch[SLIM_MAX_TX_PORTS];
- u32 rx_ch[SLIM_MAX_RX_PORTS];
+ list_for_each_entry(ch, &taiko->dai[dai->id].wcd9xxx_ch_list, list) {
- if (!rx_slot && !tx_slot) {
- pr_err("%s: Invalid\n", __func__);
- return -EINVAL;
+ tx_port = ch->port + 1;
+ pr_debug("%s: dai->id = %d, tx_port = %d",
+ __func__, dai->id, tx_port);
+
+ if ((tx_port < 1) || (tx_port > NUM_DECIMATORS)) {
+ pr_err("%s: Invalid SLIM TX%u port. DAI ID is %d\n",
+ __func__, tx_port, dai->id);
+ return -EINVAL;
+ }
+
+ tx_port_reg = TAIKO_A_CDC_CONN_TX_SB_B1_CTL + (tx_port - 1);
+ tx_port_reg_val = snd_soc_read(codec, tx_port_reg);
+
+ decimator = 0;
+
+ if ((tx_port >= 1) && (tx_port <= 6)) {
+
+ tx_port_reg_val = tx_port_reg_val & 0x0F;
+ if (tx_port_reg_val == 0x8)
+ decimator = tx_port;
+
+ } else if ((tx_port >= 7) && (tx_port <= NUM_DECIMATORS)) {
+
+ tx_port_reg_val = tx_port_reg_val & 0x1F;
+
+ if ((tx_port_reg_val >= 0x8) &&
+ (tx_port_reg_val <= 0x11)) {
+
+ decimator = (tx_port_reg_val - 0x8) + 1;
+ }
+ }
+
+ if (decimator) { /* SLIM_TX port has a DEC as input */
+
+ tx_fs_reg = TAIKO_A_CDC_TX1_CLK_FS_CTL +
+ 8 * (decimator - 1);
+
+ pr_debug("%s: set DEC%u (-> SLIM_TX%u) rate to %u\n",
+ __func__, decimator, tx_port, sample_rate);
+
+ snd_soc_update_bits(codec, tx_fs_reg, 0x07,
+ tx_fs_rate_reg_val);
+
+ } else {
+ if ((tx_port_reg_val >= 0x1) &&
+ (tx_port_reg_val <= 0x7)) {
+
+ pr_debug("%s: RMIX%u going to SLIM TX%u\n",
+ __func__, tx_port_reg_val, tx_port);
+
+ } else if ((tx_port_reg_val >= 0x8) &&
+ (tx_port_reg_val <= 0x11)) {
+
+ pr_err("%s: ERROR: Should not be here\n",
+ __func__);
+ pr_err("%s: ERROR: DEC connected to SLIM TX%u\n",
+ __func__, tx_port);
+ return -EINVAL;
+
+ } else if (tx_port_reg_val == 0) {
+ pr_debug("%s: no signal to SLIM TX%u\n",
+ __func__, tx_port);
+ } else {
+ pr_err("%s: ERROR: wrong signal to SLIM TX%u\n",
+ __func__, tx_port);
+ pr_err("%s: ERROR: wrong signal = %u\n",
+ __func__, tx_port_reg_val);
+ return -EINVAL;
+ }
+ }
}
-
- /* for virtual port, codec driver needs to do
- * housekeeping, for now should be ok
- */
- wcd9xxx_get_channel(taiko, rx_ch, tx_ch);
- if (dai->id == AIF1_PB) {
- *rx_num = taiko_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 = taiko_dai[dai->id - 1].capture.channels_max;
- while (cnt < *tx_num) {
- tx_slot[cnt] = tx_ch[6 + cnt];
- cnt++;
- }
- } else if (dai->id == AIF2_PB) {
- *rx_num = taiko_dai[dai->id - 1].playback.channels_max;
- while (cnt < *rx_num) {
- rx_slot[cnt] = rx_ch[5 + cnt];
- cnt++;
- }
- } else if (dai->id == AIF2_CAP) {
- *tx_num = taiko_dai[dai->id - 1].capture.channels_max;
- tx_slot[0] = tx_ch[cnt];
- tx_slot[1] = tx_ch[1 + cnt];
- tx_slot[2] = tx_ch[5 + cnt];
- tx_slot[3] = tx_ch[3 + cnt];
-
- } else if (dai->id == AIF3_PB) {
- *rx_num = taiko_dai[dai->id - 1].playback.channels_max;
- rx_slot[0] = rx_ch[3];
- rx_slot[1] = rx_ch[4];
-
- } else if (dai->id == AIF3_CAP) {
- *tx_num = taiko_dai[dai->id - 1].capture.channels_max;
- tx_slot[cnt] = tx_ch[2 + cnt];
- tx_slot[cnt + 1] = tx_ch[4 + cnt];
- }
- pr_debug("%s(): dai_name = %s DAI-ID %x tx_ch %d rx_ch %d\n",
- __func__, dai->name, dai->id, *tx_num, *rx_num);
-
-
return 0;
}
@@ -3783,10 +4271,9 @@
{
struct snd_soc_codec *codec = dai->codec;
struct taiko_priv *taiko = snd_soc_codec_get_drvdata(dai->codec);
- u8 path, shift;
- u16 tx_fs_reg, rx_fs_reg;
- u8 tx_fs_rate, rx_fs_rate, rx_state, tx_state;
+ u8 tx_fs_rate, rx_fs_rate;
u32 compander_fs;
+ int ret;
pr_debug("%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n", __func__,
dai->name, dai->id, params_rate(params),
@@ -3825,37 +4312,20 @@
break;
default:
pr_err("%s: Invalid sampling rate %d\n", __func__,
- params_rate(params));
+ params_rate(params));
return -EINVAL;
}
-
- /**
- * If current dai is a tx dai, set sample rate to
- * all the txfe paths that are currently not active
- */
- if ((dai->id == AIF1_CAP) || (dai->id == AIF2_CAP) ||
- (dai->id == AIF3_CAP)) {
-
- tx_state = snd_soc_read(codec,
- TAIKO_A_CDC_CLK_TX_CLK_EN_B1_CTL);
-
- for (path = 1, shift = 0;
- path <= NUM_DECIMATORS; path++, shift++) {
-
- if (path == BITS_PER_REG + 1) {
- shift = 0;
- tx_state = snd_soc_read(codec,
- TAIKO_A_CDC_CLK_TX_CLK_EN_B2_CTL);
- }
-
- if (!(tx_state & (1 << shift))) {
- tx_fs_reg = TAIKO_A_CDC_TX1_CLK_FS_CTL
- + (BITS_PER_REG*(path-1));
- snd_soc_update_bits(codec, tx_fs_reg,
- 0x07, tx_fs_rate);
- }
+ switch (substream->stream) {
+ case SNDRV_PCM_STREAM_CAPTURE:
+ ret = taiko_set_decimator_rate(dai, tx_fs_rate,
+ params_rate(params));
+ if (ret < 0) {
+ pr_err("%s: set decimator rate failed %d\n", __func__,
+ ret);
+ return ret;
}
+
if (taiko->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
@@ -3873,37 +4343,20 @@
break;
}
snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_TX_I2S_CTL,
- 0x07, tx_fs_rate);
+ 0x07, tx_fs_rate);
} else {
- taiko->dai[dai->id - 1].rate = params_rate(params);
+ taiko->dai[dai->id].rate = params_rate(params);
}
- }
- /**
- * TODO: Need to handle case where same RX chain takes 2 or more inputs
- * with varying sample rates
- */
+ break;
- /**
- * If current dai is a rx dai, set sample rate to
- * all the rx paths that are currently not active
- */
- if (dai->id == AIF1_PB || dai->id == AIF2_PB || dai->id == AIF3_PB) {
-
- rx_state = snd_soc_read(codec,
- TAIKO_A_CDC_CLK_RX_B1_CTL);
-
- for (path = 1, shift = 0;
- path <= NUM_INTERPOLATORS; path++, shift++) {
-
- if (!(rx_state & (1 << shift))) {
- rx_fs_reg = TAIKO_A_CDC_RX1_B5_CTL
- + (BITS_PER_REG*(path-1));
- snd_soc_update_bits(codec, rx_fs_reg,
- 0xE0, rx_fs_rate);
- if (comp_rx_path[shift] < COMPANDER_MAX)
- taiko->comp_fs[comp_rx_path[shift]]
- = compander_fs;
- }
+ case SNDRV_PCM_STREAM_PLAYBACK:
+ ret = taiko_set_interpolator_rate(dai, rx_fs_rate,
+ compander_fs,
+ params_rate(params));
+ if (ret < 0) {
+ pr_err("%s: set decimator rate failed %d\n", __func__,
+ ret);
+ return ret;
}
if (taiko->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
switch (params_format(params)) {
@@ -3922,10 +4375,15 @@
break;
}
snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_RX_I2S_CTL,
- 0x03, (rx_fs_rate >> 0x05));
+ 0x03, (rx_fs_rate >> 0x05));
} else {
- taiko->dai[dai->id - 1].rate = params_rate(params);
+ taiko->dai[dai->id].rate = params_rate(params);
}
+ break;
+ default:
+ pr_err("%s: Invalid stream type %d\n", __func__,
+ substream->stream);
+ return -EINVAL;
}
return 0;
@@ -4031,7 +4489,7 @@
static struct snd_soc_dai_driver taiko_i2s_dai[] = {
{
.name = "taiko_i2s_rx1",
- .id = 1,
+ .id = AIF1_PB,
.playback = {
.stream_name = "AIF1 Playback",
.rates = WCD9320_RATES,
@@ -4045,7 +4503,7 @@
},
{
.name = "taiko_i2s_tx1",
- .id = 2,
+ .id = AIF1_CAP,
.capture = {
.stream_name = "AIF1 Capture",
.rates = WCD9320_RATES,
@@ -4060,125 +4518,77 @@
};
static int taiko_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+ struct snd_kcontrol *kcontrol,
+ int event)
{
- struct wcd9xxx *taiko;
+ struct wcd9xxx *core;
struct snd_soc_codec *codec = w->codec;
struct taiko_priv *taiko_p = snd_soc_codec_get_drvdata(codec);
- u32 j = 0;
u32 ret = 0;
- codec->control_data = dev_get_drvdata(codec->dev->parent);
- taiko = codec->control_data;
+ struct wcd9xxx_codec_dai_data *dai;
+
+ core = dev_get_drvdata(codec->dev->parent);
+
+ pr_debug("%s: event called! codec name %s num_dai %d\n"
+ "stream name %s event %d\n",
+ __func__, w->codec->name, w->codec->num_dai, w->sname, event);
+
/* Execute the callback only if interface type is slimbus */
if (taiko_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
return 0;
- pr_debug("%s: %s %d\n", __func__, w->name, event);
+ dai = &taiko_p->dai[w->shift];
+ pr_debug("%s: w->name %s w->shift %d event %d\n",
+ __func__, w->name, w->shift, event);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- for (j = 0; j < ARRAY_SIZE(taiko_dai); j++) {
- if ((taiko_dai[j].id == AIF1_CAP) ||
- (taiko_dai[j].id == AIF2_CAP) ||
- (taiko_dai[j].id == AIF3_CAP))
- continue;
- if (!strncmp(w->sname,
- taiko_dai[j].playback.stream_name, 13)) {
- ++taiko_p->dai[j].ch_act;
- break;
- }
- }
- if (taiko_p->dai[j].ch_act == taiko_p->dai[j].ch_tot)
- ret = wcd9xxx_cfg_slim_sch_rx(taiko,
- taiko_p->dai[j].ch_num,
- taiko_p->dai[j].ch_tot,
- taiko_p->dai[j].rate);
+ ret = wcd9xxx_cfg_slim_sch_rx(core, &dai->wcd9xxx_ch_list,
+ dai->rate, dai->bit_width,
+ &dai->grph);
break;
case SND_SOC_DAPM_POST_PMD:
- for (j = 0; j < ARRAY_SIZE(taiko_dai); j++) {
- if ((taiko_dai[j].id == AIF1_CAP) ||
- (taiko_dai[j].id == AIF2_CAP) ||
- (taiko_dai[j].id == AIF3_CAP))
- continue;
- if (!strncmp(w->sname,
- taiko_dai[j].playback.stream_name, 13)) {
- --taiko_p->dai[j].ch_act;
- break;
- }
- }
- if (!taiko_p->dai[j].ch_act) {
- ret = wcd9xxx_close_slim_sch_rx(taiko,
- taiko_p->dai[j].ch_num,
- taiko_p->dai[j].ch_tot);
- usleep_range(15000, 15000);
- taiko_p->dai[j].rate = 0;
- memset(taiko_p->dai[j].ch_num, 0, (sizeof(u32)*
- taiko_p->dai[j].ch_tot));
- taiko_p->dai[j].ch_tot = 0;
- }
+ ret = wcd9xxx_close_slim_sch_rx(core, &dai->wcd9xxx_ch_list,
+ dai->grph);
+ usleep_range(15000, 15000);
+ break;
}
return ret;
}
static int taiko_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+ struct snd_kcontrol *kcontrol,
+ int event)
{
- struct wcd9xxx *taiko;
+ struct wcd9xxx *core;
struct snd_soc_codec *codec = w->codec;
struct taiko_priv *taiko_p = snd_soc_codec_get_drvdata(codec);
- /* index to the DAI ID, for now hardcoding */
- u32 j = 0;
u32 ret = 0;
+ struct wcd9xxx_codec_dai_data *dai;
- codec->control_data = dev_get_drvdata(codec->dev->parent);
- taiko = codec->control_data;
+ core = dev_get_drvdata(codec->dev->parent);
+
+ pr_debug("%s: event called! codec name %s num_dai %d stream name %s\n",
+ __func__, w->codec->name, w->codec->num_dai, w->sname);
/* Execute the callback only if interface type is slimbus */
if (taiko_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
return 0;
- pr_debug("%s(): %s %d\n", __func__, w->name, event);
+ pr_debug("%s(): w->name %s event %d w->shift %d\n",
+ __func__, w->name, event, w->shift);
+ dai = &taiko_p->dai[w->shift];
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- for (j = 0; j < ARRAY_SIZE(taiko_dai); j++) {
- if (taiko_dai[j].id == AIF1_PB ||
- taiko_dai[j].id == AIF2_PB ||
- taiko_dai[j].id == AIF3_PB)
- continue;
- if (!strncmp(w->sname,
- taiko_dai[j].capture.stream_name, 13)) {
- ++taiko_p->dai[j].ch_act;
- break;
- }
- }
- if (taiko_p->dai[j].ch_act == taiko_p->dai[j].ch_tot)
- ret = wcd9xxx_cfg_slim_sch_tx(taiko,
- taiko_p->dai[j].ch_num,
- taiko_p->dai[j].ch_tot,
- taiko_p->dai[j].rate);
+ ret = wcd9xxx_cfg_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
+ dai->rate, dai->bit_width,
+ &dai->grph);
break;
case SND_SOC_DAPM_POST_PMD:
- for (j = 0; j < ARRAY_SIZE(taiko_dai); j++) {
- if (taiko_dai[j].id == AIF1_PB ||
- taiko_dai[j].id == AIF2_PB ||
- taiko_dai[j].id == AIF3_PB)
- continue;
- if (!strncmp(w->sname,
- taiko_dai[j].capture.stream_name, 13)) {
- --taiko_p->dai[j].ch_act;
- break;
- }
- }
- if (!taiko_p->dai[j].ch_act) {
- ret = wcd9xxx_close_slim_sch_tx(taiko,
- taiko_p->dai[j].ch_num,
- taiko_p->dai[j].ch_tot);
- taiko_p->dai[j].rate = 0;
- memset(taiko_p->dai[j].ch_num, 0, (sizeof(u32)*
- taiko_p->dai[j].ch_tot));
- taiko_p->dai[j].ch_tot = 0;
- }
+ ret = wcd9xxx_close_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
+ dai->grph);
+ break;
}
return ret;
}
@@ -4218,29 +4628,38 @@
SND_SOC_DAPM_MIXER("DAC1", TAIKO_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, taiko_codec_enable_slimrx,
+ SND_SOC_DAPM_AIF_IN_E("AIF1 PB", "AIF1 Playback", 0, SND_SOC_NOPM,
+ AIF1_PB, 0, taiko_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, taiko_codec_enable_slimrx,
+ SND_SOC_DAPM_AIF_IN_E("AIF2 PB", "AIF2 Playback", 0, SND_SOC_NOPM,
+ AIF2_PB, 0, taiko_codec_enable_slimrx,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_AIF_IN_E("SLIM RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
- 0, taiko_codec_enable_slimrx,
+ SND_SOC_DAPM_AIF_IN_E("AIF3 PB", "AIF3 Playback", 0, SND_SOC_NOPM,
+ AIF3_PB, 0, taiko_codec_enable_slimrx,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_AIF_IN_E("SLIM RX4", "AIF3 Playback", 0, SND_SOC_NOPM, 0,
- 0, taiko_codec_enable_slimrx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_AIF_IN_E("SLIM RX5", "AIF3 Playback", 0, SND_SOC_NOPM, 0,
- 0, taiko_codec_enable_slimrx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX("SLIM RX1 MUX", SND_SOC_NOPM, TAIKO_RX1, 0,
+ &slim_rx_mux[TAIKO_RX1]),
+ SND_SOC_DAPM_MUX("SLIM RX2 MUX", SND_SOC_NOPM, TAIKO_RX2, 0,
+ &slim_rx_mux[TAIKO_RX2]),
+ SND_SOC_DAPM_MUX("SLIM RX3 MUX", SND_SOC_NOPM, TAIKO_RX3, 0,
+ &slim_rx_mux[TAIKO_RX3]),
+ SND_SOC_DAPM_MUX("SLIM RX4 MUX", SND_SOC_NOPM, TAIKO_RX4, 0,
+ &slim_rx_mux[TAIKO_RX4]),
+ SND_SOC_DAPM_MUX("SLIM RX5 MUX", SND_SOC_NOPM, TAIKO_RX5, 0,
+ &slim_rx_mux[TAIKO_RX5]),
+ SND_SOC_DAPM_MUX("SLIM RX6 MUX", SND_SOC_NOPM, TAIKO_RX6, 0,
+ &slim_rx_mux[TAIKO_RX6]),
+ SND_SOC_DAPM_MUX("SLIM RX7 MUX", SND_SOC_NOPM, TAIKO_RX7, 0,
+ &slim_rx_mux[TAIKO_RX7]),
- SND_SOC_DAPM_AIF_IN_E("SLIM RX6", "AIF2 Playback", 0, SND_SOC_NOPM, 0,
- 0, taiko_codec_enable_slimrx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_AIF_IN_E("SLIM RX7", "AIF2 Playback", 0, SND_SOC_NOPM, 0,
- 0, taiko_codec_enable_slimrx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER("SLIM RX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM RX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM RX3", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM RX4", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM RX5", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM RX6", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM RX7", SND_SOC_NOPM, 0, 0, NULL, 0),
/* Headphone */
SND_SOC_DAPM_OUTPUT("HEADPHONE"),
@@ -4541,55 +4960,47 @@
taiko_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_E("SLIM TX1", "AIF2 Capture", 0, SND_SOC_NOPM, 0,
- 0, taiko_codec_enable_slimtx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_AIF_OUT_E("AIF1 CAP", "AIF1 Capture", 0, SND_SOC_NOPM,
+ AIF1_CAP, 0, taiko_codec_enable_slimtx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MUX("SLIM TX2 MUX", SND_SOC_NOPM, 0, 0, &sb_tx2_mux),
- SND_SOC_DAPM_AIF_OUT_E("SLIM TX2", "AIF2 Capture", 0, SND_SOC_NOPM, 0,
- 0, taiko_codec_enable_slimtx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_AIF_OUT_E("AIF2 CAP", "AIF2 Capture", 0, SND_SOC_NOPM,
+ AIF2_CAP, 0, taiko_codec_enable_slimtx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MUX("SLIM TX3 MUX", SND_SOC_NOPM, 0, 0, &sb_tx3_mux),
- SND_SOC_DAPM_AIF_OUT_E("SLIM TX3", "AIF3 Capture", 0, SND_SOC_NOPM, 0,
- 0, taiko_codec_enable_slimtx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_AIF_OUT_E("AIF3 CAP", "AIF3 Capture", 0, SND_SOC_NOPM,
+ AIF3_CAP, 0, taiko_codec_enable_slimtx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MUX("SLIM TX4 MUX", SND_SOC_NOPM, 0, 0, &sb_tx4_mux),
- SND_SOC_DAPM_AIF_OUT_E("SLIM TX4", "AIF2 Capture", 0, SND_SOC_NOPM, 0,
- 0, taiko_codec_enable_slimtx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER("AIF1_CAP Mixer", SND_SOC_NOPM, AIF1_CAP, 0,
+ aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
- SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, 0, 0, &sb_tx5_mux),
- SND_SOC_DAPM_AIF_OUT_E("SLIM TX5", "AIF3 Capture", 0, SND_SOC_NOPM, 0,
- 0, taiko_codec_enable_slimtx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER("AIF2_CAP Mixer", SND_SOC_NOPM, AIF2_CAP, 0,
+ aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
- SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, 0, 0, &sb_tx6_mux),
- SND_SOC_DAPM_AIF_OUT_E("SLIM TX6", "AIF2 Capture", 0, SND_SOC_NOPM, 0,
- 0, taiko_codec_enable_slimtx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER("AIF3_CAP Mixer", SND_SOC_NOPM, AIF3_CAP, 0,
+ aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
- 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, taiko_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, taiko_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, taiko_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, taiko_codec_enable_slimtx,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, TAIKO_TX1, 0,
+ &sb_tx1_mux),
+ SND_SOC_DAPM_MUX("SLIM TX2 MUX", SND_SOC_NOPM, TAIKO_TX2, 0,
+ &sb_tx2_mux),
+ SND_SOC_DAPM_MUX("SLIM TX3 MUX", SND_SOC_NOPM, TAIKO_TX3, 0,
+ &sb_tx3_mux),
+ SND_SOC_DAPM_MUX("SLIM TX4 MUX", SND_SOC_NOPM, TAIKO_TX4, 0,
+ &sb_tx4_mux),
+ SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, TAIKO_TX5, 0,
+ &sb_tx5_mux),
+ SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, TAIKO_TX6, 0,
+ &sb_tx6_mux),
+ SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, TAIKO_TX7, 0,
+ &sb_tx7_mux),
+ SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, TAIKO_TX8, 0,
+ &sb_tx8_mux),
+ SND_SOC_DAPM_MUX("SLIM TX9 MUX", SND_SOC_NOPM, TAIKO_TX9, 0,
+ &sb_tx9_mux),
+ SND_SOC_DAPM_MUX("SLIM TX10 MUX", SND_SOC_NOPM, TAIKO_TX10, 0,
+ &sb_tx10_mux),
/* Digital Mic Inputs */
SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
@@ -7488,7 +7899,7 @@
struct snd_soc_dapm_context *dapm = &codec->dapm;
int ret = 0;
int i;
- int ch_cnt;
+ void *ptr = NULL;
codec->control_data = dev_get_drvdata(codec->dev->parent);
control = codec->control_data;
@@ -7550,43 +7961,39 @@
goto err_pdata;
}
+ ptr = kmalloc((sizeof(taiko_rx_chs) +
+ sizeof(taiko_tx_chs)), GFP_KERNEL);
+ if (!ptr) {
+ pr_err("%s: no mem for slim chan ctl data\n", __func__);
+ ret = -ENOMEM;
+ goto err_nomem_slimch;
+ }
+
if (taiko->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
snd_soc_dapm_new_controls(dapm, taiko_dapm_i2s_widgets,
ARRAY_SIZE(taiko_dapm_i2s_widgets));
snd_soc_dapm_add_routes(dapm, audio_i2s_map,
ARRAY_SIZE(audio_i2s_map));
+ for (i = 0; i < ARRAY_SIZE(taiko_i2s_dai); i++)
+ INIT_LIST_HEAD(&taiko->dai[i].wcd9xxx_ch_list);
+ } else if (taiko->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+ for (i = 0; i < NUM_CODEC_DAIS; i++) {
+ INIT_LIST_HEAD(&taiko->dai[i].wcd9xxx_ch_list);
+ init_waitqueue_head(&taiko->dai[i].dai_wait);
+ }
}
+ control->num_rx_port = TAIKO_RX_MAX;
+ control->rx_chs = ptr;
+ memcpy(control->rx_chs, taiko_rx_chs, sizeof(taiko_rx_chs));
+ control->num_tx_port = TAIKO_TX_MAX;
+ control->tx_chs = ptr + sizeof(taiko_rx_chs);
+ memcpy(control->tx_chs, taiko_tx_chs, sizeof(taiko_tx_chs));
+
snd_soc_dapm_sync(dapm);
(void) taiko_setup_irqs(taiko);
- for (i = 0; i < ARRAY_SIZE(taiko_dai); i++) {
- switch (taiko_dai[i].id) {
- case AIF1_PB:
- ch_cnt = taiko_dai[i].playback.channels_max;
- break;
- case AIF1_CAP:
- ch_cnt = taiko_dai[i].capture.channels_max;
- break;
- case AIF2_PB:
- ch_cnt = taiko_dai[i].playback.channels_max;
- break;
- case AIF2_CAP:
- ch_cnt = taiko_dai[i].capture.channels_max;
- break;
- case AIF3_PB:
- ch_cnt = taiko_dai[i].playback.channels_max;
- break;
- case AIF3_CAP:
- ch_cnt = taiko_dai[i].capture.channels_max;
- break;
- default:
- continue;
- }
- taiko->dai[i].ch_num = kzalloc((sizeof(unsigned int)*
- ch_cnt), GFP_KERNEL);
- }
#ifdef CONFIG_DEBUG_FS
if (ret == 0) {
@@ -7602,13 +8009,14 @@
return ret;
err_pdata:
+ kfree(ptr);
+err_nomem_slimch:
mutex_destroy(&taiko->codec_resource_lock);
kfree(taiko);
return ret;
}
static int taiko_codec_remove(struct snd_soc_codec *codec)
{
- int i;
struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, taiko);
wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_RELEASE, taiko);
@@ -7623,8 +8031,6 @@
taiko_codec_enable_bandgap(codec, TAIKO_BANDGAP_OFF);
if (taiko->mbhc_fw)
release_firmware(taiko->mbhc_fw);
- for (i = 0; i < ARRAY_SIZE(taiko_dai); i++)
- kfree(taiko->dai[i].ch_num);
mutex_destroy(&taiko->codec_resource_lock);
#ifdef CONFIG_DEBUG_FS
debugfs_remove(taiko->debugfs_poke);
diff --git a/sound/soc/codecs/wcd9320.h b/sound/soc/codecs/wcd9320.h
index 7ca8ff0..6f4b0cf 100644
--- a/sound/soc/codecs/wcd9320.h
+++ b/sound/soc/codecs/wcd9320.h
@@ -78,6 +78,44 @@
TAIKO_BTN_DET_GAIN
};
+/* Number of input and output Slimbus port */
+enum {
+ TAIKO_RX1 = 0,
+ TAIKO_RX2,
+ TAIKO_RX3,
+ TAIKO_RX4,
+ TAIKO_RX5,
+ TAIKO_RX6,
+ TAIKO_RX7,
+ TAIKO_RX8,
+ TAIKO_RX9,
+ TAIKO_RX10,
+ TAIKO_RX11,
+ TAIKO_RX12,
+ TAIKO_RX13,
+ TAIKO_RX_MAX,
+};
+
+enum {
+ TAIKO_TX1 = 0,
+ TAIKO_TX2,
+ TAIKO_TX3,
+ TAIKO_TX4,
+ TAIKO_TX5,
+ TAIKO_TX6,
+ TAIKO_TX7,
+ TAIKO_TX8,
+ TAIKO_TX9,
+ TAIKO_TX10,
+ TAIKO_TX11,
+ TAIKO_TX12,
+ TAIKO_TX13,
+ TAIKO_TX14,
+ TAIKO_TX15,
+ TAIKO_TX16,
+ TAIKO_TX_MAX,
+};
+
struct taiko_mbhc_general_cfg {
u8 t_ldoh;
u8 t_bg_fast_settle;
diff --git a/sound/soc/msm/apq8064.c b/sound/soc/msm/apq8064.c
index 7894368..1316a0e 100644
--- a/sound/soc/msm/apq8064.c
+++ b/sound/soc/msm/apq8064.c
@@ -859,7 +859,6 @@
unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
unsigned int num_tx_ch = 0;
-
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
pr_debug("%s: rx_0_ch=%d\n", __func__, msm_slim_0_rx_ch);
@@ -877,25 +876,7 @@
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 {
-
- if (codec_dai->id == 2)
- num_tx_ch = msm_slim_0_tx_ch;
- else if (codec_dai->id == 5) {
- /* DAI 5 is used for external EC reference from codec.
- * Since Rx is fed as reference for EC, the config of
- * this DAI is based on that of the Rx path.
- */
- num_tx_ch = msm_slim_0_rx_ch;
- }
-
pr_debug("%s: %s_tx_dai_id_%d_ch=%d\n", __func__,
codec_dai->name, codec_dai->id, num_tx_ch);
@@ -905,6 +886,19 @@
pr_err("%s: failed to get codec chan map\n", __func__);
goto end;
}
+ /* For tabla_tx1 case */
+ if (codec_dai->id == 1)
+ num_tx_ch = msm_slim_0_tx_ch;
+ /* For tabla_tx3 case */
+ else if (codec_dai->id == 4) {
+ /* DAI 5 is used for external EC reference from codec.
+ * Since Rx is fed as reference for EC, the config of
+ * this DAI is based on that of the Rx path.
+ */
+ num_tx_ch = msm_slim_0_rx_ch;
+ } else {
+ num_tx_ch = tx_ch_cnt;
+ }
ret = snd_soc_dai_set_channel_map(cpu_dai,
num_tx_ch, tx_ch, 0 , 0);
@@ -912,15 +906,6 @@
pr_err("%s: failed to set cpu chan map\n", __func__);
goto end;
}
- ret = snd_soc_dai_set_channel_map(codec_dai,
- num_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;
@@ -965,13 +950,6 @@
pr_err("%s: failed to set cpu chan map\n", __func__);
goto end;
}
- ret = snd_soc_dai_set_channel_map(codec_dai, 0, 0,
- num_rx_ch, rx_ch);
- if (ret < 0) {
- pr_err("%s: failed to set codec channel map\n",
- __func__);
- goto end;
- }
} else {
num_tx_ch = params_channels(params);
@@ -992,13 +970,6 @@
pr_err("%s: failed to set cpu chan map\n", __func__);
goto end;
}
- ret = snd_soc_dai_set_channel_map(codec_dai,
- num_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;
@@ -1128,14 +1099,14 @@
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ unsigned int rx_ch[TABLA_RX_MAX] = {138, 139, 140, 141, 142, 143, 144};
+ unsigned int tx_ch[TABLA_TX_MAX] = {128, 129, 130, 131, 132, 133, 134,
+ 135, 136, 137};
+
pr_debug("%s(), dev_name%s\n", __func__, dev_name(cpu_dai->dev));
- /*if (machine_is_msm_liquid()) {
- top_spk_pamp_gpio = (PM8921_GPIO_PM_TO_SYS(19));
- bottom_spk_pamp_gpio = (PM8921_GPIO_PM_TO_SYS(18));
- }*/
-
snd_soc_dapm_new_controls(dapm, apq8064_dapm_widgets,
ARRAY_SIZE(apq8064_dapm_widgets));
@@ -1221,6 +1192,8 @@
mbhc_cfg.read_fw_bin = apq8064_hs_detect_use_firmware;
err = tabla_hs_detect(codec, &mbhc_cfg);
+ snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
+ tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
return err;
}
diff --git a/sound/soc/msm/mdm9615.c b/sound/soc/msm/mdm9615.c
index 57b846c..5a47efe 100644
--- a/sound/soc/msm/mdm9615.c
+++ b/sound/soc/msm/mdm9615.c
@@ -915,13 +915,6 @@
pr_err("%s: failed to set cpu chan map\n", __func__);
goto end;
}
- ret = snd_soc_dai_set_channel_map(codec_dai, 0, 0,
- mdm9615_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);
@@ -935,13 +928,6 @@
pr_err("%s: failed to set cpu chan map\n", __func__);
goto end;
}
- ret = snd_soc_dai_set_channel_map(codec_dai,
- mdm9615_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;
@@ -1588,6 +1574,15 @@
.vin_sel = 2,
.inv_int_pol = 0,
};
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+ /* Tabla SLIMBUS configuration
+ * RX1, RX2, RX3, RX4, RX5, RX6, RX7
+ * TX1, TX2, TX3, TX4, TX5, TX6, TX7, TX8, TX9, TX10
+ */
+ unsigned int rx_ch[TABLA_RX_MAX] = {138, 139, 140, 141, 142, 143, 144};
+ unsigned int tx_ch[TABLA_TX_MAX] = {128, 129, 130, 131, 132, 133, 134,
+ 135, 136, 137};
pr_debug("%s(), dev_name%s\n", __func__, dev_name(cpu_dai->dev));
@@ -1639,6 +1634,10 @@
err = tabla_hs_detect(codec, &mbhc_cfg);
+ snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
+ tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
+
+
return err;
}
diff --git a/sound/soc/msm/mpq8064.c b/sound/soc/msm/mpq8064.c
index 011b798..23703f2 100644
--- a/sound/soc/msm/mpq8064.c
+++ b/sound/soc/msm/mpq8064.c
@@ -724,13 +724,6 @@
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);
@@ -744,14 +737,6 @@
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:
@@ -764,6 +749,10 @@
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ unsigned int rx_ch[TABLA_RX_MAX] = {138, 139, 140, 141, 142, 143, 144};
+ unsigned int tx_ch[TABLA_TX_MAX] = {128, 129, 130, 131, 132, 133, 134,
+ 135, 136, 137};
pr_debug("%s(), dev_name%s\n", __func__, dev_name(cpu_dai->dev));
@@ -798,6 +787,8 @@
codec_clk = clk_get(cpu_dai->dev, "osr_clk");
err = tabla_hs_detect(codec, &mbhc_cfg);
+ snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
+ tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
return err;
}
diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c
index 4725e8e..76b7597 100644
--- a/sound/soc/msm/msm8930.c
+++ b/sound/soc/msm/msm8930.c
@@ -621,13 +621,6 @@
pr_err("%s: failed to set cpu chan map\n", __func__);
goto end;
}
- ret = snd_soc_dai_set_channel_map(codec_dai, 0, 0,
- msm8930_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);
@@ -641,14 +634,6 @@
pr_err("%s: failed to set cpu chan map\n", __func__);
goto end;
}
- ret = snd_soc_dai_set_channel_map(codec_dai,
- msm8930_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;
@@ -660,6 +645,14 @@
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+ /* Tabla SLIMBUS configuration
+ * RX1, RX2, RX3, RX4, RX5
+ * TX1, TX2, TX3, TX4, TX5
+ */
+ unsigned int rx_ch[SITAR_RX_MAX] = {138, 139, 140, 141, 142};
+ unsigned int tx_ch[SITAR_TX_MAX] = {128, 129, 130, 131, 132};
pr_debug("%s()\n", __func__);
@@ -690,6 +683,9 @@
}
codec_clk = clk_get(cpu_dai->dev, "osr_clk");
+ snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
+ tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
+
mbhc_cfg.gpio = 37;
mbhc_cfg.gpio_irq = gpio_to_irq(mbhc_cfg.gpio);
sitar_hs_detect(codec, &mbhc_cfg);
diff --git a/sound/soc/msm/msm8960.c b/sound/soc/msm/msm8960.c
index 6ec44bf..da7a129 100644
--- a/sound/soc/msm/msm8960.c
+++ b/sound/soc/msm/msm8960.c
@@ -777,13 +777,6 @@
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 {
pr_debug("%s: %s tx_dai_id = %d num_ch = %d\n", __func__,
@@ -801,13 +794,6 @@
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;
@@ -845,13 +831,6 @@
pr_err("%s: failed to set cpu chan map\n", __func__);
goto end;
}
- ret = snd_soc_dai_set_channel_map(codec_dai, 0, 0,
- num_rx_ch, rx_ch);
- if (ret < 0) {
- pr_err("%s: failed to set codec channel map\n",
- __func__);
- goto end;
- }
} else {
num_tx_ch = params_channels(params);
@@ -871,13 +850,6 @@
pr_err("%s: failed to set cpu chan map\n", __func__);
goto end;
}
- ret = snd_soc_dai_set_channel_map(codec_dai,
- num_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;
@@ -896,6 +868,15 @@
.vin_sel = 2,
.inv_int_pol = 0,
};
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+ /* Tabla SLIMBUS configuration
+ * RX1, RX2, RX3, RX4, RX5, RX6, RX7
+ * TX1, TX2, TX3, TX4, TX5, TX6, TX7, TX8
+ */
+ unsigned int rx_ch[TABLA_RX_MAX] = {138, 139, 140, 141, 142, 143, 144};
+ unsigned int tx_ch[TABLA_TX_MAX] = {128, 129, 130, 131, 132, 133, 134,
+ 135, 136, 137};
pr_debug("%s(), dev_name%s\n", __func__, dev_name(cpu_dai->dev));
@@ -958,6 +939,8 @@
mbhc_cfg.read_fw_bin = hs_detect_use_firmware;
err = tabla_hs_detect(codec, &mbhc_cfg);
+ snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
+ tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
return err;
}
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index f462299..57a7fa7 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -639,6 +639,18 @@
return 0;
}
+static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ pr_debug("%s()\n", __func__);
+ rate->min = rate->max = 48000;
+
+ return 0;
+}
+
static const struct soc_enum msm_snd_enum[] = {
SOC_ENUM_SINGLE_EXT(2, spk_function),
SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
@@ -660,6 +672,19 @@
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+ /* Taiko SLIMBUS configuration
+ * RX1, RX2, RX3, RX4, RX5, RX6, RX7, RX8, RX9, RX10, RX11, RX12, RX13
+ * TX1, TX2, TX3, TX4, TX5, TX6, TX7, TX8, TX9, TX10, TX11, TX12, TX13
+ * TX14, TX15, TX16
+ */
+ unsigned int rx_ch[TAIKO_RX_MAX] = {144, 145, 146, 147, 148, 149, 150,
+ 151, 152, 153, 154, 155, 156};
+ unsigned int tx_ch[TAIKO_TX_MAX] = {128, 129, 130, 131, 132, 133,
+ 134, 135, 136, 137, 138, 139,
+ 140, 141, 142, 143};
+
pr_info("%s(), dev_name%s\n", __func__, dev_name(cpu_dai->dev));
@@ -694,6 +719,9 @@
return err;
}
+ snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
+ tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
+
err = snd_soc_jack_new(codec, "Button Jack",
TAIKO_JACK_BUTTON_MASK, &button_jack);
if (err) {
@@ -737,20 +765,8 @@
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 {
- if (codec_dai->id == 2)
- user_set_tx_ch = msm_slim_0_tx_ch;
- else if (codec_dai->id == 4)
- user_set_tx_ch = params_channels(params);
-
pr_debug("%s: %s_tx_dai_id_%d_ch=%d\n", __func__,
codec_dai->name, codec_dai->id, user_set_tx_ch);
@@ -760,19 +776,24 @@
pr_err("%s: failed to get codec chan map\n", __func__);
goto end;
}
+ /* For tabla_tx1 case */
+ if (codec_dai->id == 1)
+ user_set_tx_ch = msm_slim_0_tx_ch;
+ /* For tabla_tx2 case */
+ else if (codec_dai->id == 3)
+ user_set_tx_ch = params_channels(params);
+ else
+ user_set_tx_ch = tx_ch_cnt;
+
+ pr_debug("%s: msm_slim_0_tx_ch(%d)user_set_tx_ch(%d)tx_ch_cnt(%d)\n",
+ __func__, msm_slim_0_tx_ch, user_set_tx_ch, tx_ch_cnt);
+
ret = snd_soc_dai_set_channel_map(cpu_dai,
user_set_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,
- user_set_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;
@@ -974,6 +995,30 @@
.be_id = MSM_BACKEND_DAI_INT_BT_SCO_TX,
.be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
},
+ {
+ .name = LPASS_BE_INT_FM_RX,
+ .stream_name = "Internal FM Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.12292",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INT_FM_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ },
+ {
+ .name = LPASS_BE_INT_FM_TX,
+ .stream_name = "Internal FM Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.12293",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INT_FM_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ },
/* Backend AFE DAI Links */
{
.name = LPASS_BE_AFE_PCM_RX,
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index dacd59c..354dece 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -899,6 +899,36 @@
.remove = msm_dai_q6_dai_remove,
};
+static struct snd_soc_dai_driver msm_dai_q6_fm_rx_dai = {
+ .playback = {
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 2,
+ .channels_max = 2,
+ .rate_max = 48000,
+ .rate_min = 8000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_fm_tx_dai = {
+ .capture = {
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 2,
+ .channels_max = 2,
+ .rate_max = 48000,
+ .rate_min = 8000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+};
+
static int __devinit msm_auxpcm_dev_probe(struct platform_device *pdev)
{
int id;
@@ -1158,6 +1188,12 @@
rc = snd_soc_register_dai(&pdev->dev,
&msm_dai_q6_bt_sco_tx_dai);
break;
+ case INT_FM_RX:
+ rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_fm_rx_dai);
+ break;
+ case INT_FM_TX:
+ rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_fm_tx_dai);
+ break;
case RT_PROXY_DAI_001_RX:
case RT_PROXY_DAI_002_RX:
rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_afe_rx_dai);
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index f0465a5..4819e0a 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -344,6 +344,8 @@
break;
case INT_BT_SCO_RX:
case INT_BT_SCO_TX:
+ case INT_FM_RX:
+ case INT_FM_TX:
cfg_type = AFE_PARAM_ID_INTERNAL_BT_FM_CONFIG;
break;
default: