Merge "arm/dt: Add MSM8226 Device tree support for LPM drivers"
diff --git a/arch/arm/boot/dts/msm8974-rumi.dtsi b/arch/arm/boot/dts/msm8974-rumi.dtsi
index 4919391..38e552e 100644
--- a/arch/arm/boot/dts/msm8974-rumi.dtsi
+++ b/arch/arm/boot/dts/msm8974-rumi.dtsi
@@ -75,7 +75,7 @@
interrupts = <0 105 0>;
interrupt-names = "qup_err_intr";
qcom,i2c-bus-freq = <100000>;
- qcom,i2c-src-freq = <24000000>;
+ qcom,i2c-src-freq = <19200000>;
gpios = <&msmgpio 83 0>, /* DAT */
<&msmgpio 84 0>; /* CLK */
};
diff --git a/arch/arm/boot/dts/msm8974-smp2p.dtsi b/arch/arm/boot/dts/msm8974-smp2p.dtsi
new file mode 100644
index 0000000..511f91f
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-smp2p.dtsi
@@ -0,0 +1,171 @@
+/* Copyright (c) 2013, 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.
+ */
+/ {
+ qcom,smp2p-modem {
+ compatible = "qcom,smp2p";
+ reg = <0xfa006000 0x1000>, <0x8 0x0>;
+ reg-names = "irq-reg-base", "irq-reg-offset";
+ qcom,remote-pid = <1>;
+ qcom,irq-bitmask = <0x4000>;
+ interrupts = <0 27 1>;
+ };
+
+ qcom,smp2p-adsp {
+ compatible = "qcom,smp2p";
+ reg = <0xfa006000 0x1000>, <0x8 0x0>;
+ reg-names = "irq-reg-base", "irq-reg-offset";
+ qcom,remote-pid = <2>;
+ qcom,irq-bitmask = <0x400>;
+ interrupts = <0 158 1>;
+ };
+
+ qcom,smp2p-wcnss {
+ compatible = "qcom,smp2p";
+ reg = <0xfa006000 0x1000>, <0x8 0x0>;
+ reg-names = "irq-reg-base", "irq-reg-offset";
+ qcom,remote-pid = <4>;
+ qcom,irq-bitmask = <0x40000>;
+ interrupts = <0 143 1>;
+ };
+
+ /* SMP2P Test Driver for inbound entries */
+ smp2pgpio_smp2p_7_in: qcom,smp2pgpio-smp2p-7-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <7>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_7_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_7_in";
+ gpios = <&smp2pgpio_smp2p_7_in 0 0>;
+ };
+
+ /* SMP2P Test Driver for outbound entries */
+ smp2pgpio_smp2p_7_out: qcom,smp2pgpio-smp2p-7-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <7>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_7_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_7_out";
+ gpios = <&smp2pgpio_smp2p_7_out 0 0>;
+ };
+
+ /* SMP2P Test Driver for modem inbound */
+ smp2pgpio_smp2p_1_in: qcom,smp2pgpio-smp2p-1-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <1>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_1_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_1_in";
+ gpios = <&smp2pgpio_smp2p_1_in 0 0>;
+ };
+
+ /* SMP2P Test Driver for modem output */
+ smp2pgpio_smp2p_1_out: qcom,smp2pgpio-smp2p-1-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_1_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_1_out";
+ gpios = <&smp2pgpio_smp2p_1_out 0 0>;
+ };
+
+ /* SMP2P Test Driver for adsp inbound */
+ smp2pgpio_smp2p_2_in: qcom,smp2pgpio-smp2p-2-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <2>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_2_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_2_in";
+ gpios = <&smp2pgpio_smp2p_2_in 0 0>;
+ };
+
+ /* SMP2P Test Driver for adsp output */
+ smp2pgpio_smp2p_2_out: qcom,smp2pgpio-smp2p-2-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <2>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_2_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_2_out";
+ gpios = <&smp2pgpio_smp2p_2_out 0 0>;
+ };
+
+ /* SMP2P Test Driver for wcnss inbound */
+ smp2pgpio_smp2p_4_in: qcom,smp2pgpio-smp2p-4-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <4>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_4_in {
+ compatible = "qcom,smp2pgpio_test_smp2p_4_in";
+ gpios = <&smp2pgpio_smp2p_4_in 0 0>;
+ };
+
+ /* SMP2P Test Driver for wcnss output */
+ smp2pgpio_smp2p_4_out: qcom,smp2pgpio-smp2p-4-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "smp2p";
+ qcom,remote-pid = <4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ qcom,smp2pgpio_test_smp2p_4_out {
+ compatible = "qcom,smp2pgpio_test_smp2p_4_out";
+ gpios = <&smp2pgpio_smp2p_4_out 0 0>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index c7505cb..eb1a108 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -19,6 +19,7 @@
/include/ "msm8974-ion.dtsi"
/include/ "msm8974-gpu.dtsi"
/include/ "msm8974-mdss.dtsi"
+/include/ "msm8974-smp2p.dtsi"
/ {
model = "Qualcomm MSM 8974";
@@ -595,7 +596,7 @@
interrupts = <0 105 0>;
interrupt-names = "qup_err_intr";
qcom,i2c-bus-freq = <100000>;
- qcom,i2c-src-freq = <24000000>;
+ qcom,i2c-src-freq = <19200000>;
};
i2c@f9924000 {
@@ -608,7 +609,7 @@
interrupts = <0 96 0>;
interrupt-names = "qup_err_intr";
qcom,i2c-bus-freq = <100000>;
- qcom,i2c-src-freq = <24000000>;
+ qcom,i2c-src-freq = <19200000>;
};
spi@f9923000 {
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index d374b59..7e32126 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -81,7 +81,7 @@
vbus_otg-supply = <&usb_vbus>;
qcom,hsusb-otg-phy-type = <2>;
- qcom,hsusb-otg-mode = <3>;
+ qcom,hsusb-otg-mode = <1>;
qcom,hsusb-otg-otg-control = <1>;
qcom,hsusb-otg-disable-reset;
};
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 04b18d7..463ce85 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -179,3 +179,9 @@
# CONFIG_CRYPTO_HW is not set
CONFIG_CRC_CCITT=y
CONFIG_LIBCRC32C=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_VIDEOBUF2_MSM_MEM=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_OCMEM=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index a5a9620..ba0036b 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -45,6 +45,8 @@
CONFIG_MSM_SMD=y
CONFIG_MSM_SMD_PKG4=y
CONFIG_MSM_BAM_DMUX=y
+CONFIG_MSM_SMP2P=y
+CONFIG_MSM_SMP2P_TEST=y
CONFIG_MSM_IPC_LOGGING=y
CONFIG_MSM_IPC_ROUTER=y
CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
@@ -76,6 +78,7 @@
CONFIG_MSM_L1_ERR_LOG=y
CONFIG_MSM_L2_ERP_2BIT_PANIC=y
CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
+CONFIG_MSM_UARTDM_Core_v14=y
CONFIG_STRICT_MEMORY_RWX=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
@@ -260,6 +263,7 @@
CONFIG_TOUCHSCREEN_ATMEL_MXT=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_UINPUT=y
+CONFIG_SERIAL_MSM_HS=y
CONFIG_SERIAL_MSM_HSL=y
CONFIG_SERIAL_MSM_HSL_CONSOLE=y
CONFIG_DIAG_CHAR=y
@@ -337,6 +341,7 @@
CONFIG_SND_USB_AUDIO=y
CONFIG_SND_SOC=y
CONFIG_SND_SOC_MSM8974=y
+CONFIG_USB_SUSPEND=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_ROOT_HUB_TT=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index ef61e66..99e4e6e 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -44,6 +44,8 @@
CONFIG_MSM_SMD=y
CONFIG_MSM_SMD_PKG4=y
CONFIG_MSM_BAM_DMUX=y
+CONFIG_MSM_SMP2P=y
+CONFIG_MSM_SMP2P_TEST=y
CONFIG_MSM_IPC_LOGGING=y
CONFIG_MSM_IPC_ROUTER=y
CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
@@ -80,6 +82,7 @@
CONFIG_MSM_CACHE_DUMP=y
CONFIG_MSM_CACHE_DUMP_ON_PANIC=y
CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
+CONFIG_MSM_UARTDM_Core_v14=y
CONFIG_STRICT_MEMORY_RWX=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
@@ -264,6 +267,7 @@
CONFIG_TOUCHSCREEN_ATMEL_MXT=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_UINPUT=y
+CONFIG_SERIAL_MSM_HS=y
CONFIG_SERIAL_MSM_HSL=y
CONFIG_SERIAL_MSM_HSL_CONSOLE=y
CONFIG_DIAG_CHAR=y
@@ -340,6 +344,7 @@
CONFIG_SND_USB_AUDIO=y
CONFIG_SND_SOC=y
CONFIG_SND_SOC_MSM8974=y
+CONFIG_USB_SUSPEND=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_ROOT_HUB_TT=y
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 0cf684d..15c9adb 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -529,7 +529,7 @@
config MSM_LPM_TEST
bool "Low Power Mode test framework"
- depends on MSM_RPM
+ depends on MSM_RPM || MSM_RPM_SMD
depends on MSM_PM8X60
help
LPM_TEST is a test framework that assists in exercising the low
diff --git a/arch/arm/mach-msm/lpm_levels.c b/arch/arm/mach-msm/lpm_levels.c
index 61c2aa8..b84d345 100644
--- a/arch/arm/mach-msm/lpm_levels.c
+++ b/arch/arm/mach-msm/lpm_levels.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, 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
@@ -37,6 +37,10 @@
static struct msm_rpmrs_level *msm_lpm_levels;
static int msm_lpm_level_count;
+static DEFINE_PER_CPU(uint32_t , msm_lpm_sleep_time);
+static DEFINE_PER_CPU(int , lpm_permitted_level);
+static DEFINE_PER_CPU(struct atomic_notifier_head, lpm_notify_head);
+
static void msm_lpm_level_update(void)
{
unsigned int lpm_level;
@@ -55,6 +59,12 @@
int ret = 0;
int debug_mask;
struct msm_rpmrs_limits *l = (struct msm_rpmrs_limits *)limits;
+ struct msm_lpm_sleep_data sleep_data;
+
+ sleep_data.limits = limits;
+ sleep_data.kernel_sleep = __get_cpu_var(msm_lpm_sleep_time);
+ atomic_notifier_call_chain(&__get_cpu_var(lpm_notify_head),
+ MSM_LPM_STATE_ENTER, &sleep_data);
ret = msm_rpm_enter_sleep();
if (ret) {
@@ -88,6 +98,8 @@
msm_rpm_exit_sleep();
msm_lpmrs_exit_sleep((struct msm_rpmrs_limits *)limits,
from_idle, notify_rpm, collapsed);
+ atomic_notifier_call_chain(&__get_cpu_var(lpm_notify_head),
+ MSM_LPM_STATE_EXIT, NULL);
}
void msm_lpm_show_resources(void)
@@ -96,6 +108,48 @@
return;
}
+uint32_t msm_pm_get_pxo(struct msm_rpmrs_limits *limits)
+{
+ return limits->pxo;
+}
+
+uint32_t msm_pm_get_l2_cache(struct msm_rpmrs_limits *limits)
+{
+ return limits->l2_cache;
+}
+
+uint32_t msm_pm_get_vdd_mem(struct msm_rpmrs_limits *limits)
+{
+ return limits->vdd_mem_upper_bound;
+}
+
+uint32_t msm_pm_get_vdd_dig(struct msm_rpmrs_limits *limits)
+{
+ return limits->vdd_dig_upper_bound;
+}
+
+static bool lpm_level_permitted(int cur_level_count)
+{
+ if (__get_cpu_var(lpm_permitted_level) == msm_lpm_level_count + 1)
+ return true;
+ return (__get_cpu_var(lpm_permitted_level) == cur_level_count);
+}
+
+int msm_lpm_register_notifier(int cpu, int level_iter,
+ struct notifier_block *nb, bool is_latency_measure)
+{
+ per_cpu(lpm_permitted_level, cpu) = level_iter;
+ return atomic_notifier_chain_register(&per_cpu(lpm_notify_head,
+ cpu), nb);
+}
+
+int msm_lpm_unregister_notifier(int cpu, struct notifier_block *nb)
+{
+ per_cpu(lpm_permitted_level, cpu) = msm_lpm_level_count + 1;
+ return atomic_notifier_chain_unregister(&per_cpu(lpm_notify_head, cpu),
+ nb);
+}
+
s32 msm_cpuidle_get_deep_idle_latency(void)
{
int i;
@@ -127,7 +181,7 @@
struct msm_rpmrs_level *best_level = NULL;
uint32_t pwr;
int i;
-
+ int best_level_iter = msm_lpm_level_count + 1;
if (!msm_lpm_levels)
return NULL;
@@ -170,14 +224,31 @@
level->rs_limits.latency_us[cpu] = level->latency_us;
level->rs_limits.power[cpu] = pwr;
best_level = level;
-
+ best_level_iter = i;
if (power)
*power = pwr;
}
}
+ if (best_level && !lpm_level_permitted(best_level_iter))
+ best_level = NULL;
+ else
+ per_cpu(msm_lpm_sleep_time, cpu) =
+ time_param->modified_time_us ?
+ time_param->modified_time_us : time_param->sleep_us;
return best_level ? &best_level->rs_limits : NULL;
}
+
+static struct lpm_test_platform_data lpm_test_pdata;
+
+static struct platform_device msm_lpm_test_device = {
+ .name = "lpm_test",
+ .id = -1,
+ .dev = {
+ .platform_data = &lpm_test_pdata,
+ },
+};
+
static struct msm_pm_sleep_ops msm_lpm_ops = {
.lowest_limits = msm_lpm_lowest_limits,
.enter_sleep = msm_lpm_enter_sleep,
@@ -194,6 +265,7 @@
int ret = 0;
uint32_t num_levels = 0;
int idx = 0;
+ unsigned int m_cpu = 0;
for_each_child_of_node(pdev->dev.of_node, node)
num_levels++;
@@ -279,6 +351,14 @@
msm_lpm_levels = levels;
msm_lpm_level_count = idx;
+ lpm_test_pdata.msm_lpm_test_levels = msm_lpm_levels;
+ lpm_test_pdata.msm_lpm_test_level_count = msm_lpm_level_count;
+
+ for_each_possible_cpu(m_cpu)
+ per_cpu(lpm_permitted_level, m_cpu) =
+ msm_lpm_level_count + 1;
+
+ platform_device_register(&msm_lpm_test_device);
msm_pm_set_sleep_ops(&msm_lpm_ops);
return 0;
diff --git a/arch/arm/mach-msm/lpm_resources.h b/arch/arm/mach-msm/lpm_resources.h
index 120832f..42e43c2 100644
--- a/arch/arm/mach-msm/lpm_resources.h
+++ b/arch/arm/mach-msm/lpm_resources.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, 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
@@ -15,6 +15,7 @@
#define __ARCH_ARM_MACH_MSM_LPM_RESOURCES_H
#include "pm.h"
+#include "test-lpm.h"
enum {
MSM_LPM_PXO_OFF = 0,
@@ -50,6 +51,93 @@
uint32_t time_overhead_us;
};
+enum {
+ MSM_LPM_STATE_ENTER = 0,
+ MSM_LPM_STATE_EXIT = 1,
+};
+
+#define MSM_PM(field) MSM_LPM_##field
+
+/**
+ * msm_pm_get_pxo() - get the limits for pxo
+ * @limits: pointer to the msm_rpmrs_limits structure
+ *
+ * This function gets the limits to the resource pxo on
+ * 8974
+ */
+
+uint32_t msm_pm_get_pxo(struct msm_rpmrs_limits *limits);
+
+/**
+ * msm_pm_get_l2_cache() - get the limits for l2 cache
+ * @limits: pointer to the msm_rpmrs_limits structure
+ *
+ * This function gets the limits to the resource l2 cache
+ * on 8974
+ */
+
+uint32_t msm_pm_get_l2_cache(struct msm_rpmrs_limits *limits);
+
+/**
+ * msm_pm_get_vdd_mem() - get the limits for pxo
+ * @limits: pointer to the msm_rpmrs_limits structure
+ *
+ * This function gets the limits to the resource vdd mem
+ * on 8974
+ */
+
+uint32_t msm_pm_get_vdd_mem(struct msm_rpmrs_limits *limits);
+
+/**
+ * msm_pm_get_vdd_dig() - get the limits for vdd dig
+ * @limits: pointer to the msm_rpmrs_limits structure
+ *
+ * This function gets the limits to the resource on 8974
+ */
+
+uint32_t msm_pm_get_vdd_dig(struct msm_rpmrs_limits *limits);
+
+/**
+ * struct msm_lpm_sleep_data - abstraction to get sleep data
+ * @limits: pointer to the msm_rpmrs_limits structure
+ * @kernel_sleep: kernel sleep time as decided by the power calculation
+ * algorithm
+ *
+ * This structure is an abstraction to get the limits and kernel sleep time
+ * during enter sleep.
+ */
+
+struct msm_lpm_sleep_data {
+ struct msm_rpmrs_limits *limits;
+ uint32_t kernel_sleep;
+};
+
+/**
+ * msm_lpm_register_notifier() - register for notifications
+ * @cpu: cpu to debug
+ * @level_iter: low power level index to debug
+ * @nb: notifier block to callback on notifications
+ * @is_latency_measure: is it latency measure
+ *
+ * This function sets the permitted level to the index of the
+ * level under test and registers notifier for callback.
+ */
+
+int msm_lpm_register_notifier(int cpu, int level_iter,
+ struct notifier_block *nb, bool is_latency_measure);
+
+/**
+ * msm_lpm_unregister_notifier() - unregister from notifications
+ * @cpu: cpu to debug
+ * @nb: notifier block to callback on notifications
+ *
+ * This function sets the permitted level to a value one more than
+ * available levels count which indicates that all levels are
+ * permitted and it also unregisters notifier for callback.
+ */
+
+int msm_lpm_unregister_notifier(int cpu, struct notifier_block *nb);
+
#ifdef CONFIG_MSM_RPM_SMD
/**
diff --git a/arch/arm/mach-msm/no-pm.c b/arch/arm/mach-msm/no-pm.c
index d460c70..0db6e68 100644
--- a/arch/arm/mach-msm/no-pm.c
+++ b/arch/arm/mach-msm/no-pm.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2011, 2013 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
@@ -48,3 +48,4 @@
return -ENOSYS;
}
+void msm_pm_enable_retention(bool enable) {}
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index e35d843..261d433 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, 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
@@ -118,6 +118,7 @@
static struct msm_pm_init_data_type msm_pm_init_data;
static struct hrtimer pm_hrtimer;
static struct msm_pm_sleep_ops pm_sleep_ops;
+static bool msm_pm_ldo_retention_enabled = true;
/*
* Write out the attribute.
*/
@@ -820,6 +821,14 @@
}
/* fall through */
case MSM_PM_SLEEP_MODE_RETENTION:
+ /*
+ * The Krait BHS regulator doesn't have enough head
+ * room to drive the retention voltage on LDO and so
+ * has disabled retention
+ */
+ if (!msm_pm_ldo_retention_enabled)
+ break;
+
if (!allow)
break;
@@ -995,6 +1004,34 @@
msm_pm_swfi();
}
+static void msm_pm_ack_retention_disable(void *data)
+{
+ /*
+ * This is a NULL function to ensure that the core has woken up
+ * and is safe to disable retention.
+ */
+}
+/**
+ * msm_pm_enable_retention() - Disable/Enable retention on all cores
+ * @enable: Enable/Disable retention
+ *
+ */
+void msm_pm_enable_retention(bool enable)
+{
+ msm_pm_ldo_retention_enabled = enable;
+ /*
+ * If retention is being disabled, wakeup all online core to ensure
+ * that it isn't executing retention. Offlined cores need not be woken
+ * up as they enter the deepest sleep mode, namely RPM assited power
+ * collapse
+ */
+ if (!enable)
+ smp_call_function_many(cpu_online_mask,
+ msm_pm_ack_retention_disable,
+ NULL, true);
+}
+EXPORT_SYMBOL(msm_pm_enable_retention);
+
static int msm_pm_enter(suspend_state_t state)
{
bool allow[MSM_PM_SLEEP_MODE_NR];
diff --git a/arch/arm/mach-msm/pm-data.c b/arch/arm/mach-msm/pm-data.c
index 6f4743f..08cdf5d 100644
--- a/arch/arm/mach-msm/pm-data.c
+++ b/arch/arm/mach-msm/pm-data.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, 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
@@ -30,7 +30,7 @@
[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_RETENTION)] = {
.idle_supported = 1,
- .suspend_supported = 1,
+ .suspend_supported = 0,
.idle_enabled = 0,
.suspend_enabled = 0,
},
diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h
index 86d8f98..399194a 100644
--- a/arch/arm/mach-msm/pm.h
+++ b/arch/arm/mach-msm/pm.h
@@ -1,7 +1,7 @@
/* arch/arm/mach-msm/pm.h
*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
* Author: San Mehat <san@android.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -114,6 +114,7 @@
int msm_pm_idle_enter(enum msm_pm_sleep_mode sleep_mode);
void msm_pm_cpu_enter_lowpower(unsigned int cpu);
void __init msm_pm_set_tz_retention_flag(unsigned int flag);
+void msm_pm_enable_retention(bool enable);
#ifdef CONFIG_MSM_PM8X60
void msm_pm_set_rpm_wakeup_irq(unsigned int irq);
diff --git a/arch/arm/mach-msm/test-lpm.c b/arch/arm/mach-msm/test-lpm.c
index dbc8100..031b2dc 100644
--- a/arch/arm/mach-msm/test-lpm.c
+++ b/arch/arm/mach-msm/test-lpm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, 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
@@ -26,6 +26,9 @@
#if defined(CONFIG_MSM_RPM)
#include "rpm_resources.h"
#endif
+#if defined(CONFIG_MSM_RPM_SMD)
+#include "lpm_resources.h"
+#endif
#include "timer.h"
#include "test-lpm.h"
diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h
index 042ba37..844c65f 100644
--- a/drivers/media/dvb/dvb-core/demux.h
+++ b/drivers/media/dvb/dvb-core/demux.h
@@ -7,7 +7,7 @@
* Copyright (c) 2000 Nokia Research Center
* Tampere, FINLAND
*
- * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2012-2013, 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 Lesser General Public License
@@ -100,6 +100,9 @@
int disc_indicator_set;
int pes_length_mismatch;
u64 stc;
+ u32 tei_counter;
+ u32 cont_err_counter;
+ u32 ts_packets_num;
} pes_end;
struct {
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index f5a505c..bddbb5f 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -1861,6 +1861,9 @@
event.params.pes.flags = 0;
event.params.pes.stc = 0;
+ event.params.pes.transport_error_indicator_counter = 0;
+ event.params.pes.continuity_error_counter = 0;
+ event.params.pes.ts_packets_num = 0;
dvb_dmxdev_add_event(events, &event);
events->current_event_data_size = 0;
@@ -2109,6 +2112,13 @@
DMX_FILTER_PES_LENGTH_ERROR;
event.params.pes.stc = dmx_data_ready->pes_end.stc;
+ event.params.pes.transport_error_indicator_counter =
+ dmx_data_ready->pes_end.tei_counter;
+ event.params.pes.continuity_error_counter =
+ dmx_data_ready->pes_end.cont_err_counter;
+ event.params.pes.ts_packets_num =
+ dmx_data_ready->pes_end.ts_packets_num;
+
dvb_dmxdev_add_event(events, &event);
events->current_event_data_size = 0;
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index eea83c2..488f42c 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -5,7 +5,7 @@
* & Marcus Metzler <marcus@convergence.de>
* for convergence integrated media GmbH
*
- * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2012-2013, 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 Lesser General Public License
@@ -127,15 +127,15 @@
{
int count = payload(buf);
int p;
- //int ccok;
- //u8 cc;
+ int ccok;
+ u8 cc;
+ struct dmx_data_ready data;
if (count == 0)
return -1;
p = 188 - count;
- /*
cc = buf[3] & 0x0f;
if (feed->first_cc)
ccok = 1;
@@ -144,26 +144,41 @@
feed->first_cc = 0;
feed->cc = cc;
- if (!ccok)
- printk("missed packet!\n");
- */
/* PUSI ? */
if (buf[1] & 0x40) {
- if (feed->pusi_seen)
+ if (feed->pusi_seen) {
/* We had seen PUSI before, this means
* that previous PES can be closed now.
*/
- feed->cb.ts(NULL, 0, NULL, 0,
- &feed->feed.ts, DMX_OK_PES_END);
+ data.status = DMX_OK_PES_END;
+ data.data_length = 0;
+ data.pes_end.start_gap = 0;
+ data.pes_end.actual_length = feed->peslen;
+ data.pes_end.disc_indicator_set = 0;
+ data.pes_end.pes_length_mismatch = 0;
+ data.pes_end.stc = 0;
+ data.pes_end.tei_counter = feed->pes_tei_counter;
+ data.pes_end.cont_err_counter =
+ feed->pes_cont_err_counter;
+ data.pes_end.ts_packets_num = feed->pes_ts_packets_num;
+ feed->data_ready_cb.ts(&feed->feed.ts, &data);
+ }
feed->pusi_seen = 1;
feed->peslen = 0;
+ feed->pes_tei_counter = 0;
+ feed->pes_ts_packets_num = 0;
+ feed->pes_cont_err_counter = 0;
}
if (feed->pusi_seen == 0)
return 0;
+ feed->pes_ts_packets_num++;
+ feed->pes_cont_err_counter += !ccok;
+ feed->pes_tei_counter += (buf[1] & 0x80) ? 1 : 0;
+
feed->peslen += count;
return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts, DMX_OK);
@@ -1243,6 +1258,9 @@
feed->demux = demux;
feed->pid = 0xffff;
feed->peslen = 0;
+ feed->pes_tei_counter = 0;
+ feed->pes_ts_packets_num = 0;
+ feed->pes_cont_err_counter = 0;
feed->buffer = NULL;
feed->tsp_out_format = DMX_TSP_FORMAT_188;
memset(&feed->indexing_params, 0,
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h
index 2e4a468..5e98ea1 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.h
+++ b/drivers/media/dvb/dvb-core/dvb_demux.h
@@ -4,7 +4,7 @@
* Copyright (C) 2000-2001 Marcus Metzler & Ralph Metzler
* for convergence integrated media GmbH
*
- * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2012-2013, 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 Lesser General Public License
@@ -105,6 +105,9 @@
int pusi_seen; /* prevents feeding of garbage from previous section */
u32 peslen;
+ u32 pes_tei_counter;
+ u32 pes_cont_err_counter;
+ u32 pes_ts_packets_num;
struct list_head list_head;
unsigned int index; /* a unique index for each feed (can be used as hardware pid filter index) */
diff --git a/drivers/media/video/msmb/sensor/msm_sensor.c b/drivers/media/video/msmb/sensor/msm_sensor.c
index 1f54951..78c3207 100644
--- a/drivers/media/video/msmb/sensor/msm_sensor.c
+++ b/drivers/media/video/msmb/sensor/msm_sensor.c
@@ -783,7 +783,7 @@
int32_t msm_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl)
{
- int32_t rc = 0, index = 0, clk_index = 0;
+ int32_t rc = 0, index = 0;
struct msm_sensor_power_setting_array *power_setting_array = NULL;
struct msm_sensor_power_setting *power_setting = NULL;
struct msm_camera_sensor_board_info *data = s_ctrl->sensordata;
@@ -900,17 +900,22 @@
return 0;
power_up_failed:
pr_err("%s:%d failed\n", __func__, __LINE__);
+ if (s_ctrl->sensor_device_type == MSM_SENSOR_PLATFORM_DEVICE) {
+ s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_util(
+ s_ctrl->sensor_i2c_client, MSM_CCI_RELEASE);
+ }
+
for (index--; index >= 0; index--) {
CDBG("%s index %d\n", __func__, index);
power_setting = &power_setting_array->power_setting[index];
CDBG("%s type %d\n", __func__, power_setting->seq_type);
switch (power_setting->seq_type) {
case SENSOR_CLK:
- for (clk_index--; clk_index >= 0; clk_index--)
- msm_cam_clk_enable(s_ctrl->dev,
- &s_ctrl->clk_info[clk_index],
- (struct clk **)&power_setting->data[0],
- 1, 0);
+ msm_cam_clk_enable(s_ctrl->dev,
+ &s_ctrl->clk_info[0],
+ (struct clk **)&power_setting->data[0],
+ s_ctrl->clk_info_size,
+ 0);
break;
case SENSOR_GPIO:
gpio_set_value_cansleep(
diff --git a/drivers/net/ethernet/msm/msm_rmnet_bam.c b/drivers/net/ethernet/msm/msm_rmnet_bam.c
index 295c55c..83f486c 100644
--- a/drivers/net/ethernet/msm/msm_rmnet_bam.c
+++ b/drivers/net/ethernet/msm/msm_rmnet_bam.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2013, 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
@@ -746,6 +746,112 @@
return 0;
}
+/* support for 9 new rmnet ports */
+#define RMNET_REV_DEVICE_COUNT (9)
+static struct net_device *netdevs_rev[RMNET_REV_DEVICE_COUNT];
+static struct platform_driver bam_rmnet_rev_drivers[RMNET_REV_DEVICE_COUNT];
+
+static int bam_rmnet_rev_probe(struct platform_device *pdev)
+{
+ int i;
+ char name[BAM_DMUX_CH_NAME_MAX_LEN];
+ struct rmnet_private *p;
+
+ for (i = 0; i < RMNET_REV_DEVICE_COUNT; ++i) {
+ scnprintf(name, BAM_DMUX_CH_NAME_MAX_LEN, "bam_dmux_ch_%d",
+ (i+BAM_DMUX_DATA_REV_RMNET_0));
+ if (!strncmp(pdev->name, name, BAM_DMUX_CH_NAME_MAX_LEN))
+ break;
+ }
+
+ if (i >= RMNET_REV_DEVICE_COUNT) {
+ pr_err("%s: wrong netdev %s\n", __func__, pdev->name);
+ return 0;
+ }
+
+ p = netdev_priv(netdevs_rev[i]);
+ if (p->in_reset) {
+ p->in_reset = 0;
+ msm_bam_dmux_open(p->ch_id, netdevs_rev[i], bam_notify);
+ netif_carrier_on(netdevs_rev[i]);
+ netif_start_queue(netdevs_rev[i]);
+ }
+
+ return 0;
+}
+
+static int bam_rmnet_rev_remove(struct platform_device *pdev)
+{
+ int i;
+ char name[BAM_DMUX_CH_NAME_MAX_LEN];
+ struct rmnet_private *p;
+
+ for (i = 0; i < RMNET_REV_DEVICE_COUNT; ++i) {
+ scnprintf(name, BAM_DMUX_CH_NAME_MAX_LEN, "bam_dmux_ch_%d",
+ (i+BAM_DMUX_DATA_REV_RMNET_0));
+ if (!strncmp(pdev->name, name, BAM_DMUX_CH_NAME_MAX_LEN))
+ break;
+ }
+
+ if (i >= RMNET_REV_DEVICE_COUNT) {
+ pr_err("%s: wrong netdev %s\n", __func__, pdev->name);
+ return 0;
+ }
+
+ p = netdev_priv(netdevs_rev[i]);
+ p->in_reset = 1;
+ if (p->waiting_for_ul_skb != NULL) {
+ dev_kfree_skb_any(p->waiting_for_ul_skb);
+ p->waiting_for_ul_skb = NULL;
+ }
+ msm_bam_dmux_close(p->ch_id);
+ netif_carrier_off(netdevs_rev[i]);
+ netif_stop_queue(netdevs_rev[i]);
+ return 0;
+}
+
+#ifdef CONFIG_MSM_RMNET_DEBUG
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static int rmnet_debug_init_timeout_suspend(struct net_device *dev)
+{
+ struct device *d;
+ d = &(dev->dev);
+ return device_create_file(d, &dev_attr_timeout_suspend);
+}
+#else
+static int rmnet_debug_init_timeout_suspend(struct net_device *dev)
+{
+ return 0;
+}
+#endif
+static int rmnet_debug_init(struct net_device *dev)
+{
+
+ struct device *d;
+ struct rmnet_private *p;
+ int err = 0;
+ d = &(dev->dev);
+ p = netdev_priv(dev);
+ p->timeout_us = 0;
+ p->wakeups_xmit = p->wakeups_rcv = 0;
+ err = device_create_file(d, &dev_attr_timeout);
+ if (err)
+ return err;
+ err = device_create_file(d, &dev_attr_wakeups_xmit);
+ if (err)
+ return err;
+ err = device_create_file(d, &dev_attr_wakeups_rcv);
+ if (err)
+ return err;
+ err = rmnet_debug_init_timeout_suspend(dev);
+ return err;
+}
+#else
+static int rmnet_debug_init(struct net_device *dev)
+{
+ return 0;
+}
+#endif
static int __init rmnet_init(void)
{
int ret;
@@ -828,6 +934,53 @@
return ret;
}
}
+ /*Support for new rmnet ports */
+ for (n = 0; n < RMNET_REV_DEVICE_COUNT; n++) {
+ dev = alloc_netdev(sizeof(struct rmnet_private),
+ "rev_rmnet%d", rmnet_setup);
+
+ if (!dev) {
+ pr_err("%s: no memory for rev netdev %d\n",
+ __func__, n);
+ return -ENOMEM;
+ }
+
+ netdevs_rev[n] = dev;
+ d = &(dev->dev);
+ p = netdev_priv(dev);
+ /* Initial config uses Ethernet */
+ p->operation_mode = RMNET_MODE_LLP_ETH;
+ p->ch_id = n+BAM_DMUX_DATA_REV_RMNET_0;
+ p->waiting_for_ul_skb = NULL;
+ p->in_reset = 0;
+ spin_lock_init(&p->lock);
+ spin_lock_init(&p->tx_queue_lock);
+
+ ret = register_netdev(dev);
+ if (ret) {
+ pr_err("%s: unable to register rev netdev %d rc=%d\n",
+ __func__, n, ret);
+ free_netdev(dev);
+ return ret;
+ }
+ if (rmnet_debug_init(dev))
+ continue;
+ bam_rmnet_rev_drivers[n].probe = bam_rmnet_rev_probe;
+ bam_rmnet_rev_drivers[n].remove = bam_rmnet_rev_remove;
+ tempname = kmalloc(BAM_DMUX_CH_NAME_MAX_LEN, GFP_KERNEL);
+ if (tempname == NULL)
+ return -ENOMEM;
+ scnprintf(tempname, BAM_DMUX_CH_NAME_MAX_LEN, "bam_dmux_ch_%d",
+ (n+BAM_DMUX_DATA_REV_RMNET_0));
+ bam_rmnet_rev_drivers[n].driver.name = tempname;
+ bam_rmnet_rev_drivers[n].driver.owner = THIS_MODULE;
+ ret = platform_driver_register(&bam_rmnet_rev_drivers[n]);
+ if (ret) {
+ pr_err("%s: new rev driver registration failed n=%d rc=%d\n",
+ __func__, n, ret);
+ return ret;
+ }
+ }
return 0;
}
diff --git a/include/linux/dvb/dmx.h b/include/linux/dvb/dmx.h
index 460cba3..53bbd5e 100644
--- a/include/linux/dvb/dmx.h
+++ b/include/linux/dvb/dmx.h
@@ -5,7 +5,7 @@
* & Ralph Metzler <ralph@convergence.de>
* for convergence integrated media GmbH
*
- * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2012-2013, 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 Lesser General Public License
@@ -250,6 +250,18 @@
/* Flags passed in filter events */
__u32 flags;
+
+ /*
+ * Number of TS packets with Transport Error Indicator (TEI)
+ * found while constructing the PES.
+ */
+ __u32 transport_error_indicator_counter;
+
+ /* Number of continuity errors found while constructing the PES */
+ __u32 continuity_error_counter;
+
+ /* Total number of TS packets holding the PES */
+ __u32 ts_packets_num;
};
/* Section info associated with DMX_EVENT_NEW_SECTION event */
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index d7521f8..6f81063 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -339,7 +339,7 @@
struct wcd9xxx_pdata *pdata;
u32 anc_slot;
-
+ bool anc_func;
bool no_mic_headset_override;
/* Delayed work to report long button press */
struct delayed_work mbhc_btn_dwork;
@@ -539,6 +539,48 @@
return 0;
}
+static int tabla_get_anc_func(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+ ucontrol->value.integer.value[0] = (tabla->anc_func == true ? 1 : 0);
+ return 0;
+}
+
+static int tabla_put_anc_func(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+ mutex_lock(&dapm->codec->mutex);
+
+ tabla->anc_func = (!ucontrol->value.integer.value[0] ? false : true);
+
+ dev_dbg(codec->dev, "%s: anc_func %x", __func__, tabla->anc_func);
+
+ if (tabla->anc_func == true) {
+ snd_soc_dapm_enable_pin(dapm, "ANC HPHR");
+ snd_soc_dapm_enable_pin(dapm, "ANC HPHL");
+ snd_soc_dapm_enable_pin(dapm, "ANC HEADPHONE");
+ snd_soc_dapm_disable_pin(dapm, "HPHR");
+ snd_soc_dapm_disable_pin(dapm, "HPHL");
+ snd_soc_dapm_disable_pin(dapm, "HEADPHONE");
+ } else {
+ snd_soc_dapm_disable_pin(dapm, "ANC HPHR");
+ snd_soc_dapm_disable_pin(dapm, "ANC HPHL");
+ snd_soc_dapm_disable_pin(dapm, "ANC HEADPHONE");
+ snd_soc_dapm_enable_pin(dapm, "HPHR");
+ snd_soc_dapm_enable_pin(dapm, "HPHL");
+ snd_soc_dapm_enable_pin(dapm, "HEADPHONE");
+ }
+ snd_soc_dapm_sync(dapm);
+ mutex_unlock(&dapm->codec->mutex);
+ return 0;
+}
+
static int tabla_pa_gain_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -987,6 +1029,10 @@
return 0;
}
+static const char *const tabla_anc_func_text[] = {"OFF", "ON"};
+static const struct soc_enum tabla_anc_func_enum =
+ SOC_ENUM_SINGLE_EXT(2, tabla_anc_func_text);
+
static const char *tabla_ear_pa_gain_text[] = {"POS_6_DB", "POS_2_DB"};
static const struct soc_enum tabla_ear_pa_gain_enum[] = {
SOC_ENUM_SINGLE_EXT(2, tabla_ear_pa_gain_text),
@@ -1130,6 +1176,8 @@
SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 0, 100, tabla_get_anc_slot,
tabla_put_anc_slot),
+ SOC_ENUM_EXT("ANC Function", tabla_anc_func_enum, tabla_get_anc_func,
+ tabla_put_anc_func),
SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
SOC_ENUM("TX3 HPF cut off", cf_dec3_enum),
@@ -2476,111 +2524,6 @@
return 0;
}
-static int tabla_codec_enable_anc(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- struct snd_soc_codec *codec = w->codec;
- const char *filename;
- const struct firmware *fw;
- int i;
- int ret;
- int num_anc_slots;
- struct anc_header *anc_head;
- struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
- u32 anc_writes_size = 0;
- int anc_size_remaining;
- u32 *anc_ptr;
- u16 reg;
- u8 mask, val, old_val;
-
- pr_debug("%s %d\n", __func__, event);
- switch (event) {
- case SND_SOC_DAPM_PRE_PMU:
-
- filename = "wcd9310/wcd9310_anc.bin";
-
- ret = request_firmware(&fw, filename, codec->dev);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
- ret);
- return -ENODEV;
- }
-
- if (fw->size < sizeof(struct anc_header)) {
- dev_err(codec->dev, "Not enough data\n");
- release_firmware(fw);
- return -ENOMEM;
- }
-
- /* First number is the number of register writes */
- anc_head = (struct anc_header *)(fw->data);
- anc_ptr = (u32 *)((u32)fw->data + sizeof(struct anc_header));
- anc_size_remaining = fw->size - sizeof(struct anc_header);
- num_anc_slots = anc_head->num_anc_slots;
-
- if (tabla->anc_slot >= num_anc_slots) {
- dev_err(codec->dev, "Invalid ANC slot selected\n");
- release_firmware(fw);
- return -EINVAL;
- }
-
- for (i = 0; i < num_anc_slots; i++) {
-
- if (anc_size_remaining < TABLA_PACKED_REG_SIZE) {
- dev_err(codec->dev, "Invalid register format\n");
- release_firmware(fw);
- return -EINVAL;
- }
- anc_writes_size = (u32)(*anc_ptr);
- anc_size_remaining -= sizeof(u32);
- anc_ptr += 1;
-
- if (anc_writes_size * TABLA_PACKED_REG_SIZE
- > anc_size_remaining) {
- dev_err(codec->dev, "Invalid register format\n");
- release_firmware(fw);
- return -ENOMEM;
- }
-
- if (tabla->anc_slot == i)
- break;
-
- anc_size_remaining -= (anc_writes_size *
- TABLA_PACKED_REG_SIZE);
- anc_ptr += anc_writes_size;
- }
- if (i == num_anc_slots) {
- dev_err(codec->dev, "Selected ANC slot not present\n");
- release_firmware(fw);
- return -ENOMEM;
- }
-
- for (i = 0; i < anc_writes_size; i++) {
- TABLA_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
- mask, val);
- old_val = snd_soc_read(codec, reg);
- snd_soc_write(codec, reg, (old_val & ~mask) |
- (val & mask));
- }
- release_firmware(fw);
-
- TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
- /* if MBHC polling is active, set TX7_MBHC_EN bit 7 */
- if (tabla->mbhc_polling_active)
- snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80,
- 0x80);
- TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
- break;
- case SND_SOC_DAPM_POST_PMD:
- /* unset TX7_MBHC_EN bit 7 */
- snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x00);
-
- snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
- snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_CLK_EN_CTL, 0);
- break;
- }
- return 0;
-}
/* called under codec_resource_lock acquisition */
static void tabla_codec_start_hs_polling(struct snd_soc_codec *codec)
@@ -3283,6 +3226,160 @@
WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
}
+static int tabla_codec_enable_anc(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ const char *filename;
+ const struct firmware *fw;
+ int i;
+ int ret;
+ int num_anc_slots;
+ struct anc_header *anc_head;
+ struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+ u32 anc_writes_size = 0;
+ int anc_size_remaining;
+ u32 *anc_ptr;
+ u16 reg;
+ u8 mask, val, old_val;
+ u8 mbhc_micb_ctl_val;
+
+ pr_debug("%s: DAPM Event %d ANC func is %d\n",
+ __func__, event, tabla->anc_func);
+
+ if (tabla->anc_func == 0)
+ return 0;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ mbhc_micb_ctl_val = snd_soc_read(codec,
+ tabla->mbhc_bias_regs.ctl_reg);
+
+ if (!(mbhc_micb_ctl_val & 0x80)) {
+ TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
+ tabla_codec_switch_micbias(codec, 1);
+ TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
+ }
+
+ filename = "wcd9310/wcd9310_anc.bin";
+
+ ret = request_firmware(&fw, filename, codec->dev);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
+ ret);
+ return -ENODEV;
+ }
+
+ if (fw->size < sizeof(struct anc_header)) {
+ dev_err(codec->dev, "Not enough data\n");
+ release_firmware(fw);
+ return -ENOMEM;
+ }
+
+ /* First number is the number of register writes */
+ anc_head = (struct anc_header *)(fw->data);
+ anc_ptr = (u32 *)((u32)fw->data + sizeof(struct anc_header));
+ anc_size_remaining = fw->size - sizeof(struct anc_header);
+ num_anc_slots = anc_head->num_anc_slots;
+
+ if (tabla->anc_slot >= num_anc_slots) {
+ dev_err(codec->dev, "Invalid ANC slot selected\n");
+ release_firmware(fw);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < num_anc_slots; i++) {
+
+ if (anc_size_remaining < TABLA_PACKED_REG_SIZE) {
+ dev_err(codec->dev, "Invalid register format\n");
+ release_firmware(fw);
+ return -EINVAL;
+ }
+ anc_writes_size = (u32)(*anc_ptr);
+ anc_size_remaining -= sizeof(u32);
+ anc_ptr += 1;
+
+ if (anc_writes_size * TABLA_PACKED_REG_SIZE
+ > anc_size_remaining) {
+ dev_err(codec->dev, "Invalid register format\n");
+ release_firmware(fw);
+ return -ENOMEM;
+ }
+
+ if (tabla->anc_slot == i)
+ break;
+
+ anc_size_remaining -= (anc_writes_size *
+ TABLA_PACKED_REG_SIZE);
+ anc_ptr += anc_writes_size;
+ }
+ if (i == num_anc_slots) {
+ dev_err(codec->dev, "Selected ANC slot not present\n");
+ release_firmware(fw);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < anc_writes_size; i++) {
+ TABLA_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
+ mask, val);
+ old_val = snd_soc_read(codec, reg);
+ snd_soc_write(codec, reg, (old_val & ~mask) |
+ (val & mask));
+ }
+ usleep_range(10000, 10000);
+ snd_soc_update_bits(codec, TABLA_A_RX_HPH_CNP_EN, 0x30, 0x30);
+ msleep(30);
+ release_firmware(fw);
+ TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
+ /* if MBHC polling is active, set TX7_MBHC_EN bit 7 */
+ if (tabla->mbhc_polling_active)
+ snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80,
+ 0x80);
+ TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* schedule work is required because at the time HPH PA DAPM
+ * event callback is called by DAPM framework, CODEC dapm mutex
+ * would have been locked while snd_soc_jack_report also
+ * attempts to acquire same lock.
+ */
+ if (w->shift == 5) {
+ clear_bit(TABLA_HPHL_PA_OFF_ACK,
+ &tabla->hph_pa_dac_state);
+ clear_bit(TABLA_HPHL_DAC_OFF_ACK,
+ &tabla->hph_pa_dac_state);
+ if (tabla->hph_status & SND_JACK_OC_HPHL)
+ schedule_work(&tabla->hphlocp_work);
+ } else if (w->shift == 4) {
+ clear_bit(TABLA_HPHR_PA_OFF_ACK,
+ &tabla->hph_pa_dac_state);
+ clear_bit(TABLA_HPHR_DAC_OFF_ACK,
+ &tabla->hph_pa_dac_state);
+ if (tabla->hph_status & SND_JACK_OC_HPHR)
+ schedule_work(&tabla->hphrocp_work);
+ }
+
+ TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
+ tabla_codec_switch_micbias(codec, 0);
+ TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
+
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ snd_soc_update_bits(codec, TABLA_A_RX_HPH_CNP_EN, 0x30, 0x00);
+ msleep(40);
+ /* unset TX7_MBHC_EN bit 7 */
+ snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x00);
+ snd_soc_update_bits(codec, TABLA_A_CDC_ANC1_CTL, 0x01, 0x00);
+ snd_soc_update_bits(codec, TABLA_A_CDC_ANC2_CTL, 0x01, 0x00);
+ msleep(20);
+ snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_RESET_CTL, 0x0F);
+ snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_CLK_EN_CTL, 0);
+ snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
+ break;
+ }
+ return 0;
+}
+
static int tabla_hph_pa_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -3592,7 +3689,6 @@
{"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX2"},
{"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX2"},
- {"ANC", NULL, "ANC1 FB MUX"},
/* Headset (RX MIX1 and RX MIX2) */
{"HEADPHONE", NULL, "HPHL"},
@@ -3607,19 +3703,26 @@
{"HPHL DAC", NULL, "CP"},
{"HPHR DAC", NULL, "CP"},
- {"ANC", NULL, "ANC1 MUX"},
- {"ANC", NULL, "ANC2 MUX"},
+ {"ANC HEADPHONE", NULL, "ANC HPHL"},
+ {"ANC HEADPHONE", NULL, "ANC HPHR"},
+
+ {"ANC HPHL", NULL, "HPHL_PA_MIXER"},
+ {"ANC HPHR", NULL, "HPHR_PA_MIXER"},
+
{"ANC1 MUX", "ADC1", "ADC1"},
{"ANC1 MUX", "ADC2", "ADC2"},
{"ANC1 MUX", "ADC3", "ADC3"},
{"ANC1 MUX", "ADC4", "ADC4"},
+ {"ANC1 MUX", "DMIC1", "DMIC1"},
+ {"ANC1 MUX", "DMIC2", "DMIC2"},
+ {"ANC1 MUX", "DMIC3", "DMIC3"},
+ {"ANC1 MUX", "DMIC4", "DMIC4"},
{"ANC2 MUX", "ADC1", "ADC1"},
{"ANC2 MUX", "ADC2", "ADC2"},
{"ANC2 MUX", "ADC3", "ADC3"},
{"ANC2 MUX", "ADC4", "ADC4"},
- {"ANC", NULL, "CDC_CONN"},
-
+ {"ANC HPHR", NULL, "CDC_CONN"},
{"DAC1", "Switch", "RX1 CHAIN"},
{"HPHL DAC", "Switch", "RX1 CHAIN"},
{"HPHR DAC", NULL, "RX2 CHAIN"},
@@ -3646,8 +3749,8 @@
{"RX1 CHAIN", NULL, "RX1 MIX2"},
{"RX2 CHAIN", NULL, "RX2 MIX2"},
- {"RX1 CHAIN", NULL, "ANC"},
- {"RX2 CHAIN", NULL, "ANC"},
+ {"RX1 MIX2", NULL, "ANC1 MUX"},
+ {"RX2 MIX2", NULL, "ANC2 MUX"},
{"CP", NULL, "RX_BIAS"},
{"LINEOUT1 DAC", NULL, "RX_BIAS"},
@@ -4052,6 +4155,14 @@
(reg <= TABLA_A_CDC_IIR2_COEF_B5_CTL))
return 1;
+ /* ANC filter registers are not cacheable */
+ if ((reg >= TABLA_A_CDC_ANC1_FILT1_B1_CTL) &&
+ (reg <= TABLA_A_CDC_ANC1_FILT2_B3_CTL))
+ return 1;
+ if ((reg >= TABLA_A_CDC_ANC2_FILT1_B1_CTL) &&
+ (reg <= TABLA_A_CDC_ANC2_FILT2_B3_CTL))
+ return 1;
+
/* Digital gain register is not cacheable so we have to write
* the setting even it is the same
*/
@@ -5284,9 +5395,13 @@
SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
- SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
- tabla_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_OUTPUT("ANC HEADPHONE"),
+ SND_SOC_DAPM_PGA_E("ANC HPHL", SND_SOC_NOPM, 0, 0, NULL, 0,
+ tabla_codec_enable_anc,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("ANC HPHR", SND_SOC_NOPM, 0, 0, NULL, 0,
+ tabla_codec_enable_anc, SND_SOC_DAPM_PRE_PMU),
+
SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
@@ -8650,6 +8765,12 @@
"tabla_gpio_irq_resend");
tabla->gpio_irq_resend = false;
+ mutex_lock(&dapm->codec->mutex);
+ snd_soc_dapm_disable_pin(dapm, "ANC HPHL");
+ snd_soc_dapm_disable_pin(dapm, "ANC HPHR");
+ snd_soc_dapm_disable_pin(dapm, "ANC HEADPHONE");
+ snd_soc_dapm_sync(dapm);
+ mutex_unlock(&dapm->codec->mutex);
#ifdef CONFIG_DEBUG_FS
if (ret == 0) {
diff --git a/sound/soc/msm/qdsp6v2/audio_ocmem.c b/sound/soc/msm/qdsp6v2/audio_ocmem.c
index f151e51..145f095 100644
--- a/sound/soc/msm/qdsp6v2/audio_ocmem.c
+++ b/sound/soc/msm/qdsp6v2/audio_ocmem.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, 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
@@ -590,7 +590,7 @@
pr_debug("%s\n", __func__);
audio_ocmem_lcl.audio_ocmem_workqueue =
alloc_workqueue("ocmem_audio_client_driver_audio",
- WQ_NON_REENTRANT, 0);
+ WQ_NON_REENTRANT | WQ_UNBOUND, 0);
if (!audio_ocmem_lcl.audio_ocmem_workqueue) {
pr_err("%s: Failed to create ocmem audio work queue\n",
__func__);
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 5ac643416..99047178 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -78,7 +78,7 @@
[snd_soc_dapm_pre] = 0,
[snd_soc_dapm_aif_in] = 1,
[snd_soc_dapm_aif_out] = 1,
- [snd_soc_dapm_adc] = 1,
+ [snd_soc_dapm_adc] = 5,
[snd_soc_dapm_hp] = 2,
[snd_soc_dapm_spk] = 2,
[snd_soc_dapm_out_drv] = 2,