Merge "leds: leds-qpnp: avoid calling pwm_disable when scaling leds' brightness"
diff --git a/Documentation/devicetree/bindings/sound/voice-svc.txt b/Documentation/devicetree/bindings/sound/voice-svc.txt
new file mode 100644
index 0000000..deca7f5
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/voice-svc.txt
@@ -0,0 +1,11 @@
+* Voice Service binding
+
+Required properties:
+- compatible : "qcom,msm-voice-svc"
+
+Example:
+
+ qcom,msm-voice-svc {
+ compatible = "qcom,msm-voice-svc";
+ };
+
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index cf8e3b3..4117d9d 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -499,6 +499,10 @@
compatible = "qti,msm-pcm-loopback";
};
+ qcom,msm-voice-svc {
+ compatible = "qcom,msm-voice-svc";
+ };
+
qcom,msm-dai-q6 {
compatible = "qcom,msm-dai-q6";
qcom,msm-dai-q6-sb-0-rx {
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 23ddc8c..da5474d 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -1520,7 +1520,9 @@
compatible = "qcom,cpubw";
qcom,cpu-mem-ports = <1 512>, <2 512>;
qcom,bw-tbl =
+ < 381 /* 50 MHz */ >,
< 572 /* 75 MHz */ >,
+ < 762 /* 100 MHz */ >,
< 1144 /* 150 MHz */ >,
< 1525 /* 200 MHz */ >,
< 2342 /* 307 MHz */ >,
diff --git a/arch/arm/mach-msm/include/mach/ocmem_priv.h b/arch/arm/mach-msm/include/mach/ocmem_priv.h
index 32d58d4..00aedb6 100644
--- a/arch/arm/mach-msm/include/mach/ocmem_priv.h
+++ b/arch/arm/mach-msm/include/mach/ocmem_priv.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 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
@@ -226,7 +226,6 @@
int process_dump(int, struct ocmem_handle *, unsigned long);
int ocmem_rdm_transfer(int, struct ocmem_map_list *,
unsigned long, int);
-int ocmem_clear(unsigned long, unsigned long);
unsigned long process_quota(int);
int ocmem_memory_off(int, unsigned long, unsigned long);
int ocmem_memory_on(int, unsigned long, unsigned long);
diff --git a/arch/arm/mach-msm/include/mach/subsystem_notif.h b/arch/arm/mach-msm/include/mach/subsystem_notif.h
index 5865eff..59e212f 100644
--- a/arch/arm/mach-msm/include/mach/subsystem_notif.h
+++ b/arch/arm/mach-msm/include/mach/subsystem_notif.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011, 2013-2014, 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
@@ -25,6 +25,7 @@
SUBSYS_BEFORE_POWERUP,
SUBSYS_AFTER_POWERUP,
SUBSYS_RAMDUMP_NOTIFICATION,
+ SUBSYS_POWERUP_FAILURE,
SUBSYS_NOTIF_TYPE_COUNT
};
diff --git a/arch/arm/mach-msm/lpm_levels.c b/arch/arm/mach-msm/lpm_levels.c
index 7128017..9857162 100644
--- a/arch/arm/mach-msm/lpm_levels.c
+++ b/arch/arm/mach-msm/lpm_levels.c
@@ -526,7 +526,7 @@
if (latency_us < pwr->latency_us)
continue;
- if (next_event_us)
+ if (next_event_us) {
if (next_event_us < pwr->latency_us)
continue;
@@ -535,6 +535,7 @@
next_wakeup_us = next_event_us
- pwr->latency_us;
}
+ }
if (next_wakeup_us <= pwr->time_overhead_us)
continue;
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
index 626c5e8..0ffc194 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
@@ -364,7 +364,7 @@
{
struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);
void *sel_cdata;
- long rounded_rate;
+ long rounded_rate, cur_rate;
sel_cdata = fabric->cdata[ctx];
@@ -379,16 +379,20 @@
}
/* Enable clocks before accessing QoS registers */
- if (fabric->info.nodeclk[DUAL_CTX].clk)
+ if (fabric->info.nodeclk[DUAL_CTX].clk) {
if (fabric->info.nodeclk[DUAL_CTX].rate == 0) {
- rounded_rate = clk_round_rate(fabric->
- info.nodeclk[DUAL_CTX].clk, 1);
+ cur_rate = clk_get_rate(
+ fabric->info.nodeclk[DUAL_CTX].clk);
+ rounded_rate = clk_round_rate(
+ fabric->info.nodeclk[DUAL_CTX].clk,
+ cur_rate ? cur_rate : 1);
if (clk_set_rate(fabric->info.nodeclk[DUAL_CTX].clk,
rounded_rate))
MSM_BUS_ERR("Error: clk: en: Node: %d rate: %ld",
fabric->fabdev.id, rounded_rate);
clk_prepare_enable(fabric->info.nodeclk[DUAL_CTX].clk);
+ }
}
if (info->iface_clk.clk)
@@ -514,22 +518,26 @@
struct msm_bus_inode_info *info, uint64_t req_clk, uint64_t req_bw)
{
struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);
- long rounded_rate;
+ long rounded_rate, cur_rate;
if (fabdev->hw_algo.config_master == NULL)
return;
/* Enable clocks before accessing QoS registers */
- if (fabric->info.nodeclk[DUAL_CTX].clk)
+ if (fabric->info.nodeclk[DUAL_CTX].clk) {
if (fabric->info.nodeclk[DUAL_CTX].rate == 0) {
- rounded_rate = clk_round_rate(fabric->
- info.nodeclk[DUAL_CTX].clk, 1);
+ cur_rate = clk_get_rate(
+ fabric->info.nodeclk[DUAL_CTX].clk);
+ rounded_rate = clk_round_rate(
+ fabric->info.nodeclk[DUAL_CTX].clk,
+ cur_rate ? cur_rate : 1);
if (clk_set_rate(fabric->info.nodeclk[DUAL_CTX].clk,
rounded_rate))
MSM_BUS_ERR("Error: clk: en: Node: %d rate: %ld",
fabric->fabdev.id, rounded_rate);
clk_prepare_enable(fabric->info.nodeclk[DUAL_CTX].clk);
+ }
}
if (info->iface_clk.clk)
diff --git a/arch/arm/mach-msm/ocmem_core.c b/arch/arm/mach-msm/ocmem_core.c
index c186a5e..f753391 100644
--- a/arch/arm/mach-msm/ocmem_core.c
+++ b/arch/arm/mach-msm/ocmem_core.c
@@ -51,6 +51,7 @@
static struct ocmem_hw_region *region_ctrl;
static struct mutex region_ctrl_lock;
static void *ocmem_base;
+static void *ocmem_vbase;
#define OCMEM_V1_MACROS 8
#define OCMEM_V1_MACRO_SZ (SZ_64K)
@@ -562,6 +563,13 @@
ocmem_write(0x0, ocmem_base + OC_GFX_MPU_END);
}
+int ocmem_clear(unsigned long start, unsigned long size)
+{
+ memset((ocmem_vbase + start), 0x4D4D434F, size);
+ mb();
+ return 0;
+}
+
static int do_lock(enum ocmem_client id, unsigned long offset,
unsigned long len, enum region_mode mode)
{
@@ -1144,6 +1152,7 @@
pdata = platform_get_drvdata(pdev);
ocmem_base = pdata->reg_base;
+ ocmem_vbase = pdata->vbase;
rc = ocmem_enable_core_clock();
diff --git a/arch/arm/mach-msm/ocmem_rdm.c b/arch/arm/mach-msm/ocmem_rdm.c
index 4ff7212..9eac050 100644
--- a/arch/arm/mach-msm/ocmem_rdm.c
+++ b/arch/arm/mach-msm/ocmem_rdm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 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
@@ -149,38 +149,6 @@
return IRQ_HANDLED;
}
-#ifdef CONFIG_MSM_OCMEM_NONSECURE
-int ocmem_clear(unsigned long start, unsigned long size)
-{
- INIT_COMPLETION(dm_clear_event);
- /* Clear DM Mask */
- ocmem_write(DM_MASK_RESET, dm_base + DM_INTR_MASK);
- /* Clear DM Interrupts */
- ocmem_write(DM_INTR_RESET, dm_base + DM_INTR_CLR);
- /* DM CLR offset */
- ocmem_write(start, dm_base + DM_CLR_OFFSET);
- /* DM CLR size */
- ocmem_write(size, dm_base + DM_CLR_SIZE);
- /* Wipe out memory as "OCMM" */
- ocmem_write(0x4D4D434F, dm_base + DM_CLR_PATTERN);
- /* The offset, size and pattern for clearing must be set
- * before triggering the clearing engine
- */
- mb();
- /* Trigger Data Clear */
- ocmem_write(DM_CLR_ENABLE, dm_base + DM_CLR_TRIGGER);
-
- wait_for_completion(&dm_clear_event);
-
- return 0;
-}
-#else
-int ocmem_clear(unsigned long start, unsigned long size)
-{
- return 0;
-}
-#endif
-
/* Lock during transfers */
int ocmem_rdm_transfer(int id, struct ocmem_map_list *clist,
unsigned long start, int direction)
diff --git a/arch/arm/mach-msm/qdsp6v2/Makefile b/arch/arm/mach-msm/qdsp6v2/Makefile
index 6bd3efb..3d7638d 100644
--- a/arch/arm/mach-msm/qdsp6v2/Makefile
+++ b/arch/arm/mach-msm/qdsp6v2/Makefile
@@ -12,7 +12,7 @@
obj-$(CONFIG_FB_MSM_HDMI_MSM_PANEL) += lpa_if_hdmi.o
endif
obj-$(CONFIG_MSM_QDSP6_APR) += apr.o apr_v1.o apr_tal.o q6core.o dsp_debug.o
-obj-$(CONFIG_MSM_QDSP6_APRV2) += apr.o apr_v2.o apr_tal.o dsp_debug.o
+obj-$(CONFIG_MSM_QDSP6_APRV2) += apr.o apr_v2.o apr_tal.o dsp_debug.o voice_svc.o
ifdef CONFIG_ARCH_MSM9615
obj-y += audio_acdb.o
obj-y += rtac.o
diff --git a/arch/arm/mach-msm/qdsp6v2/apr.c b/arch/arm/mach-msm/qdsp6v2/apr.c
index 8d9ad29..937eeda 100644
--- a/arch/arm/mach-msm/qdsp6v2/apr.c
+++ b/arch/arm/mach-msm/qdsp6v2/apr.c
@@ -436,7 +436,7 @@
if (data.payload_size > 0)
data.payload = (char *)hdr + hdr_size;
- temp_port = ((data.src_port >> 8) * 8) + (data.src_port & 0xFF);
+ temp_port = ((data.dest_port >> 8) * 8) + (data.dest_port & 0xFF);
pr_debug("port = %d t_port = %d\n", data.src_port, temp_port);
if (c_svc->port_cnt && c_svc->port_fn[temp_port])
c_svc->port_fn[temp_port](&data, c_svc->port_priv[temp_port]);
diff --git a/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c b/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c
index 399e073..df7760a 100644
--- a/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c
+++ b/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c
@@ -344,7 +344,7 @@
pr_err("%s: ion import dma buffer failed\n",
__func__);
rc = -EINVAL;
- goto err_destroy_client;
+ goto err;
}
if (ionflag != NULL) {
@@ -380,10 +380,6 @@
err_ion_handle:
ion_free(client, *handle);
-err_destroy_client:
- msm_audio_ion_client_destroy(client);
- client = NULL;
- *handle = NULL;
err:
return rc;
}
diff --git a/arch/arm/mach-msm/qdsp6v2/voice_svc.c b/arch/arm/mach-msm/qdsp6v2/voice_svc.c
new file mode 100644
index 0000000..92b3003
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/voice_svc.c
@@ -0,0 +1,593 @@
+/* Copyright (c) 2014, 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/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/cdev.h>
+#include <sound/voice_svc.h>
+#include <mach/qdsp6v2/apr_tal.h>
+#include <mach/qdsp6v2/apr.h>
+
+#define DRIVER_NAME "voice_svc"
+#define MINOR_NUMBER 1
+#define APR_MAX_RESPONSE 10
+
+#define MAX(a, b) ((a) >= (b) ? (a) : (b))
+
+struct voice_svc_device {
+ struct cdev *cdev;
+ struct device *dev;
+ int major;
+};
+
+struct voice_svc_prvt {
+ void* apr_q6_mvm;
+ void* apr_q6_cvs;
+ uint16_t response_count;
+ struct list_head response_queue;
+ wait_queue_head_t response_wait;
+ spinlock_t response_lock;
+};
+
+struct apr_data {
+ struct apr_hdr hdr;
+ __u8 payload[0];
+} __packed;
+
+struct apr_response_list {
+ struct list_head list;
+ struct voice_svc_cmd_response resp;
+};
+
+static struct voice_svc_device *voice_svc_dev;
+static struct class *voice_svc_class;
+dev_t device_num;
+
+static int32_t qdsp_apr_callback(struct apr_client_data *data, void *priv)
+{
+ struct voice_svc_prvt *prtd;
+ struct apr_response_list *response_list;
+ unsigned long spin_flags;
+
+ if ((data == NULL) || (priv == NULL)) {
+ pr_err("%s: data or priv is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ prtd = (struct voice_svc_prvt*)priv;
+
+ pr_debug("%s: data->opcode %x\n", __func__,
+ data->opcode);
+
+ if (data->opcode == RESET_EVENTS) {
+ if (data->reset_proc == APR_DEST_QDSP6) {
+ pr_debug("%s: Received reset event\n", __func__);
+
+ if (prtd->apr_q6_mvm != NULL) {
+ apr_reset(prtd->apr_q6_mvm);
+ prtd->apr_q6_mvm = NULL;
+ }
+
+ if (prtd->apr_q6_cvs != NULL) {
+ apr_reset(prtd->apr_q6_cvs);
+ prtd->apr_q6_cvs = NULL;
+ }
+ } else if (data->reset_proc ==APR_DEST_MODEM) {
+ pr_debug("%s: Received Modem reset event\n", __func__);
+ }
+ }
+
+ spin_lock_irqsave(&prtd->response_lock, spin_flags);
+
+ if (prtd->response_count < APR_MAX_RESPONSE) {
+ response_list = (struct apr_response_list *)kmalloc(
+ sizeof(struct apr_response_list) + data->payload_size,
+ GFP_ATOMIC);
+ if (response_list == NULL) {
+ pr_err("%s: kmalloc failed\n", __func__);
+
+ return -ENOMEM;
+ }
+
+ response_list->resp.src_port = data->src_port;
+ response_list->resp.dest_port = ((data->dest_port) >> 8);
+ response_list->resp.token = data->token;
+ response_list->resp.opcode = data->opcode;
+ response_list->resp.payload_size = data->payload_size;
+ if (data->payload != NULL && data->payload_size > 0) {
+ memcpy(response_list->resp.payload, data->payload,
+ data->payload_size);
+ }
+
+ list_add_tail(&response_list->list, &prtd->response_queue);
+ prtd->response_count++;
+
+ wake_up(&prtd->response_wait);
+ } else {
+ pr_err("%s: Response dropped since the queue is full\n", __func__);
+ }
+
+ spin_unlock_irqrestore(&prtd->response_lock, spin_flags);
+
+ return 0;
+}
+
+static void voice_svc_update_hdr(struct voice_svc_cmd_request* apr_req_data,
+ struct apr_data *aprdata,
+ struct voice_svc_prvt *prtd)
+{
+
+ aprdata->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, \
+ APR_HDR_LEN(sizeof(struct apr_hdr)),\
+ APR_PKT_VER);
+ aprdata->hdr.src_port = ((apr_req_data->src_port) << 8 | 0x0001);
+ aprdata->hdr.dest_port = apr_req_data->dest_port;
+ aprdata->hdr.token = apr_req_data->token;
+ aprdata->hdr.opcode = apr_req_data->opcode;
+ aprdata->hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ apr_req_data->payload_size);
+ memcpy(aprdata->payload, apr_req_data->payload,
+ apr_req_data->payload_size);
+}
+
+static int voice_svc_send_req(struct voice_svc_cmd_request *apr_request,
+ struct voice_svc_prvt *prtd)
+{
+ int ret = 0;
+ void *apr_handle = NULL;
+ struct apr_data *aprdata = NULL;
+ uint32_t user_payload_size = 0;
+
+ if (apr_request == NULL) {
+ pr_err("%s: apr_request is NULL\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ user_payload_size = apr_request->payload_size;
+
+ aprdata = kmalloc(sizeof(struct apr_data) + user_payload_size,
+ GFP_KERNEL);
+
+ if (aprdata == NULL) {
+ pr_err("%s: aprdata kmalloc failed.", __func__);
+
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ voice_svc_update_hdr(apr_request, aprdata, prtd);
+
+ if (!strncmp(apr_request->svc_name, VOICE_SVC_CVS_STR,
+ MAX(sizeof(apr_request->svc_name), sizeof(VOICE_SVC_CVS_STR)))) {
+ apr_handle = prtd->apr_q6_cvs;
+ } else if (!strncmp(apr_request->svc_name, VOICE_SVC_MVM_STR,
+ MAX(sizeof(apr_request->svc_name), sizeof(VOICE_SVC_MVM_STR)))) {
+ apr_handle = prtd->apr_q6_mvm;
+ } else {
+ pr_err("%s: Invalid service %s\n", __func__,
+ apr_request->svc_name);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = apr_send_pkt(apr_handle, (uint32_t *)aprdata);
+
+ if (ret < 0) {
+ pr_err("%s: Fail in sending SNDRV_VOICE_SVC_REQUEST\n",
+ __func__);
+ ret = -EINVAL;
+ } else {
+ pr_debug("%s: apr packet sent successfully %d\n",
+ __func__, ret);
+ ret = 0;
+ }
+
+done:
+ if (aprdata != NULL)
+ kfree(aprdata);
+
+ return ret;
+}
+static int voice_svc_reg(char *svc, uint32_t src_port,
+ struct voice_svc_prvt *prtd, void **handle)
+{
+ int ret = 0;
+
+ if (handle == NULL) {
+ pr_err("%s: handle is NULL\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (*handle != NULL) {
+ pr_err("%s: svc handle not NULL\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ *handle = apr_register("ADSP",
+ svc, qdsp_apr_callback,
+ ((src_port) << 8 | 0x0001),
+ prtd);
+
+ if (*handle == NULL) {
+ pr_err("%s: Unable to register %s\n",
+ __func__, svc);
+
+ ret = -EFAULT;
+ goto done;
+ }
+ pr_debug("%s: register %s successful\n",
+ __func__, svc);
+done:
+ return ret;
+}
+
+static int voice_svc_dereg(char *svc, void **handle)
+{
+ int ret = 0;
+ if (handle == NULL) {
+ pr_err("%s: handle is NULL\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ apr_deregister(*handle);
+ *handle = NULL;
+ pr_debug("%s: deregister %s successful\n",
+ __func__, svc);
+
+done:
+ return 0;
+}
+
+static int process_reg_cmd(struct voice_svc_register apr_reg_svc,
+ struct voice_svc_prvt *prtd)
+{
+ int ret = 0;
+ char *svc = NULL;
+ void **handle = NULL;
+
+ if (!strncmp(apr_reg_svc.svc_name, VOICE_SVC_MVM_STR,
+ MAX(sizeof(apr_reg_svc.svc_name), sizeof(VOICE_SVC_MVM_STR)))) {
+ svc = VOICE_SVC_MVM_STR;
+ handle = &prtd->apr_q6_mvm;
+ } else if (!strncmp(apr_reg_svc.svc_name, VOICE_SVC_CVS_STR,
+ MAX(sizeof(apr_reg_svc.svc_name), sizeof(VOICE_SVC_CVS_STR)))) {
+ svc = VOICE_SVC_CVS_STR;
+ handle = &prtd->apr_q6_cvs;
+ } else {
+ pr_err("%s: Invalid Service: %s\n", __func__,
+ apr_reg_svc.svc_name);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (*handle == NULL &&
+ apr_reg_svc.reg_flag) {
+ ret = voice_svc_reg(svc, apr_reg_svc.src_port, prtd,
+ handle);
+ } else if (handle != NULL &&
+ !apr_reg_svc.reg_flag) {
+ ret = voice_svc_dereg(svc, handle);
+ }
+
+done:
+ return ret;
+}
+
+static long voice_svc_ioctl(struct file *file, unsigned int cmd,
+ unsigned long u_arg)
+{
+ int ret = 0;
+ struct voice_svc_prvt *prtd;
+ struct voice_svc_register apr_reg_svc;
+ struct voice_svc_cmd_request *apr_request = NULL;
+ struct voice_svc_cmd_response *apr_response = NULL;
+ struct apr_response_list *resp;
+ void __user *arg = (void __user *)u_arg;
+ uint32_t user_payload_size = 0;
+ unsigned long spin_flags;
+
+ pr_debug("%s: cmd: %u\n", __func__, cmd);
+
+ prtd = (struct voice_svc_prvt*)file->private_data;
+
+ switch (cmd) {
+ case SNDRV_VOICE_SVC_REGISTER_SVC:
+ pr_debug("%s: size of struct: %d\n", __func__,
+ sizeof(apr_reg_svc));
+ if (copy_from_user(&apr_reg_svc, arg, sizeof(apr_reg_svc))) {
+ pr_err("%s: copy_from_user failed\n", __func__);
+
+ ret = -EFAULT;
+ goto done;
+ }
+
+ ret = process_reg_cmd(apr_reg_svc, prtd);
+
+ break;
+ case SNDRV_VOICE_SVC_CMD_REQUEST:
+ if (!access_ok(VERIFY_READ, arg,
+ sizeof(struct voice_svc_cmd_request))) {
+ pr_err("%s: Unable to read user data", __func__);
+
+ ret = -EFAULT;
+ goto done;
+ }
+
+ user_payload_size =
+ ((struct voice_svc_cmd_request*)arg)->payload_size;
+
+ apr_request = kmalloc(sizeof(struct voice_svc_cmd_request) +
+ user_payload_size, GFP_KERNEL);
+
+ if (apr_request == NULL) {
+ pr_err("%s: apr_request kmalloc failed.", __func__);
+
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ if (copy_from_user(apr_request, arg,
+ sizeof(struct voice_svc_cmd_request) +
+ user_payload_size)) {
+ pr_err("%s: copy from user failed, size %d\n", __func__,
+ sizeof(struct voice_svc_cmd_request) +
+ user_payload_size);
+
+ ret = -EFAULT;
+ goto done;
+ }
+
+ ret = voice_svc_send_req(apr_request, prtd);
+
+ break;
+
+ case SNDRV_VOICE_SVC_CMD_RESPONSE:
+ do {
+ if (!access_ok(VERIFY_READ, arg,
+ sizeof(struct voice_svc_cmd_response))) {
+ pr_err("%s: Unable to read user data",
+ __func__);
+
+ ret = -EFAULT;
+ goto done;
+ }
+
+ user_payload_size =
+ ((struct voice_svc_cmd_response*)arg)->payload_size;
+ pr_debug("%s: RESPONSE: user payload size %d",
+ __func__, user_payload_size);
+
+ spin_lock_irqsave(&prtd->response_lock, spin_flags);
+ if (!list_empty(&prtd->response_queue)) {
+ resp = list_first_entry(&prtd->response_queue,
+ struct apr_response_list, list);
+
+ if (user_payload_size <
+ resp->resp.payload_size) {
+ pr_err("%s: Invalid payload size %d,%d",
+ __func__, user_payload_size,
+ resp->resp.payload_size);
+ ret = -ENOMEM;
+ spin_unlock_irqrestore(
+ &prtd->response_lock,
+ spin_flags);
+ goto done;
+ }
+
+ if (!access_ok(VERIFY_WRITE, arg,
+ sizeof(struct voice_svc_cmd_response) +
+ resp->resp.payload_size)) {
+ ret = -EFAULT;
+ spin_unlock_irqrestore(
+ &prtd->response_lock,
+ spin_flags);
+ goto done;
+ }
+
+ if (copy_to_user(arg, &resp->resp,
+ sizeof(struct voice_svc_cmd_response) +
+ resp->resp.payload_size)) {
+ pr_err("%s: copy to user failed, size \
+ %d\n", __func__,
+ sizeof(struct voice_svc_cmd_response) +
+ resp->resp.payload_size);
+
+ ret = -EFAULT;
+ spin_unlock_irqrestore(
+ &prtd->response_lock,
+ spin_flags);
+ goto done;
+ }
+
+ prtd->response_count--;
+
+ list_del(&resp->list);
+ kfree(resp);
+ spin_unlock_irqrestore(&prtd->response_lock,
+ spin_flags);
+ goto done;
+ } else {
+ spin_unlock_irqrestore(&prtd->response_lock,
+ spin_flags);
+ wait_event_interruptible(prtd->response_wait,
+ !list_empty(&prtd->response_queue));
+ pr_debug("%s: Interupt recieved for response",
+ __func__);
+ }
+ } while(!apr_response);
+ break;
+ default:
+ pr_debug("%s: cmd: %u\n", __func__, cmd);
+ ret = -EINVAL;
+ }
+
+done:
+ if (apr_request != NULL)
+ kfree(apr_request);
+
+ return ret;
+}
+
+static int voice_svc_open(struct inode *inode, struct file *file)
+{
+ struct voice_svc_prvt *prtd = NULL;
+
+ prtd = kmalloc(sizeof(struct voice_svc_prvt), GFP_KERNEL);
+
+ if (prtd == NULL) {
+ pr_err("%s: kmalloc failed", __func__);
+
+ return -ENOMEM;
+ }
+
+ memset(prtd, 0, sizeof(struct voice_svc_prvt));
+ prtd->apr_q6_cvs = NULL;
+ prtd->apr_q6_mvm = NULL;
+ prtd->response_count = 0;
+
+ INIT_LIST_HEAD(&prtd->response_queue);
+ init_waitqueue_head(&prtd->response_wait);
+ spin_lock_init(&prtd->response_lock);
+
+ file->private_data = (void*)prtd;
+
+ return 0;
+}
+
+static int voice_svc_release(struct inode *inode, struct file *file)
+{
+ kfree(file->private_data);
+ return 0;
+}
+
+static const struct file_operations voice_svc_fops = {
+ .owner = THIS_MODULE,
+ .open = voice_svc_open,
+ .unlocked_ioctl = voice_svc_ioctl,
+ .release = voice_svc_release,
+};
+
+
+static int voice_svc_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+
+ voice_svc_dev = devm_kzalloc(&pdev->dev, sizeof(struct voice_svc_device),
+ GFP_KERNEL);
+ if (!voice_svc_dev) {
+ pr_err("%s: kzalloc failed\n", __func__);
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ ret = alloc_chrdev_region(&device_num, 0, MINOR_NUMBER, DRIVER_NAME);
+ if (ret) {
+ pr_err("%s: Failed to alloc chrdev\n", __func__);
+ ret = -ENODEV;
+ goto done;
+ }
+
+ voice_svc_dev->major = MAJOR(device_num);
+ voice_svc_class = class_create(THIS_MODULE, DRIVER_NAME);
+ if (IS_ERR(voice_svc_class)) {
+ ret = PTR_ERR(voice_svc_class);
+ pr_err("%s: Failed to create class; err = %d\n", __func__,
+ ret);
+ goto class_err;
+ }
+
+ voice_svc_dev->dev = device_create(voice_svc_class, NULL, device_num,
+ NULL, DRIVER_NAME);
+ if (IS_ERR(voice_svc_dev->dev)) {
+ ret = PTR_ERR(voice_svc_dev->dev);
+ pr_err("%s: Failed to create device; err = %d\n", __func__,
+ ret);
+ goto dev_err;
+ }
+
+ voice_svc_dev->cdev = cdev_alloc();
+ cdev_init(voice_svc_dev->cdev, &voice_svc_fops);
+ ret = cdev_add(voice_svc_dev->cdev, device_num, MINOR_NUMBER);
+ if (ret) {
+ pr_err("%s: Failed to register chrdev; err = %d\n", __func__,
+ ret);
+ goto add_err;
+ }
+ pr_debug("%s: Device created\n", __func__);
+ goto done;
+
+add_err:
+ cdev_del(voice_svc_dev->cdev);
+ device_destroy(voice_svc_class, device_num);
+dev_err:
+ class_destroy(voice_svc_class);
+class_err:
+ unregister_chrdev_region(0, MINOR_NUMBER);
+done:
+ return ret;
+}
+
+static int voice_svc_remove(struct platform_device *pdev)
+{
+ cdev_del(voice_svc_dev->cdev);
+ kfree(voice_svc_dev->cdev);
+ device_destroy(voice_svc_class, device_num);
+ class_destroy(voice_svc_class);
+ unregister_chrdev_region(0, MINOR_NUMBER);
+ kfree(voice_svc_dev);
+
+ return 0;
+}
+
+static struct of_device_id voice_svc_of_match[] = {
+ {.compatible = "qcom,msm-voice-svc"},
+ { }
+};
+MODULE_DEVICE_TABLE(of, voice_svc_of_match);
+
+static struct platform_driver voice_svc_driver = {
+ .probe = voice_svc_probe,
+ .remove = voice_svc_remove,
+ .driver = {
+ .name = "msm-voice-svc",
+ .owner = THIS_MODULE,
+ .of_match_table = voice_svc_of_match,
+ },
+};
+
+static int __init voice_svc_init(void)
+{
+ return platform_driver_register(&voice_svc_driver);
+}
+
+static void __exit voice_svc_exit(void)
+{
+ platform_driver_unregister(&voice_svc_driver);
+}
+
+module_init(voice_svc_init);
+module_exit(voice_svc_exit);
+
+MODULE_DESCRIPTION("Soc QDSP6v2 Audio APR driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/smd_tty.c b/arch/arm/mach-msm/smd_tty.c
index 428d5b0..9cb26e1 100644
--- a/arch/arm/mach-msm/smd_tty.c
+++ b/arch/arm/mach-msm/smd_tty.c
@@ -551,7 +551,7 @@
static void smd_tty_close(struct tty_struct *tty, struct file *f)
{
- struct smd_tty_info *info = tty->driver_data;
+ struct smd_tty_info *info = smd_tty + tty->index;
tty_port_close(&info->port, tty, f);
}
diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
index 01e0985..bc4eb76 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2014, 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
@@ -466,13 +466,20 @@
pr_info("[%p]: Powering up %s\n", current, name);
init_completion(&dev->err_ready);
- if (dev->desc->powerup(dev->desc) < 0)
+
+ if (dev->desc->powerup(dev->desc) < 0) {
+ notify_each_subsys_device(&dev, 1, SUBSYS_POWERUP_FAILURE,
+ NULL);
panic("[%p]: Powerup error: %s!", current, name);
+ }
ret = wait_for_err_ready(dev);
- if (ret)
+ if (ret) {
+ notify_each_subsys_device(&dev, 1, SUBSYS_POWERUP_FAILURE,
+ NULL);
panic("[%p]: Timed out waiting for error ready: %s!",
current, name);
+ }
subsys_set_state(dev, SUBSYS_ONLINE);
}
@@ -500,8 +507,11 @@
init_completion(&subsys->err_ready);
ret = subsys->desc->start(subsys->desc);
- if (ret)
+ if (ret){
+ notify_each_subsys_device(&subsys, 1, SUBSYS_POWERUP_FAILURE,
+ NULL);
return ret;
+ }
if (subsys->desc->is_not_loadable) {
subsys_set_state(subsys, SUBSYS_ONLINE);
@@ -509,12 +519,14 @@
}
ret = wait_for_err_ready(subsys);
- if (ret)
+ if (ret) {
/* pil-boot succeeded but we need to shutdown
* the device because error ready timed out.
*/
+ notify_each_subsys_device(&subsys, 1, SUBSYS_POWERUP_FAILURE,
+ NULL);
subsys->desc->stop(subsys->desc);
- else
+ } else
subsys_set_state(subsys, SUBSYS_ONLINE);
return ret;
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 606953d..99647a7 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -107,6 +107,10 @@
#define DIAG_STM_WCNSS 0x04
#define DIAG_STM_APPS 0x08
+#define DIAG_DIAG_STM 0x214
+
+#define BAD_PARAM_RESPONSE_MESSAGE 20
+
/*
* The status bit masks when received in a signal handler are to be
* used in conjunction with the peripheral list bit mask to determine the
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 8cc7515..0bbb012 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -56,6 +56,8 @@
#define STM_RSP_SMD_COMPLY_INDEX 9
#define STM_RSP_NUM_BYTES 10
+#define STM_COMMAND_VALID 1
+
#define SMD_DRAIN_BUF_SIZE 4096
int diag_debug_buf_idx;
@@ -1136,20 +1138,44 @@
}
}
-int diag_process_stm_cmd(unsigned char *buf)
+int diag_process_stm_cmd(unsigned char *buf, unsigned char *dest_buf)
{
- uint8_t version = *(buf+STM_CMD_VERSION_OFFSET);
- uint8_t mask = *(buf+STM_CMD_MASK_OFFSET);
- uint8_t cmd = *(buf+STM_CMD_DATA_OFFSET);
+ uint8_t version, mask, cmd;
uint8_t rsp_supported = 0;
uint8_t rsp_smd_comply = 0;
- int valid_command = 1;
int i;
- /* Check if command is valid */
- if ((version != 1) || (mask == 0) || (0 != (mask >> 4)) ||
- (cmd != ENABLE_STM && cmd != DISABLE_STM)) {
- valid_command = 0;
+ if (!buf || !dest_buf) {
+ pr_err("diag: Invalid pointers buf: %p, dest_buf %p in %s\n",
+ buf, dest_buf, __func__);
+ return -EIO;
+ }
+
+ version = *(buf + STM_CMD_VERSION_OFFSET);
+ mask = *(buf + STM_CMD_MASK_OFFSET);
+ cmd = *(buf + STM_CMD_DATA_OFFSET);
+
+ /*
+ * Check if command is valid. If the command is asking for
+ * status, then the processor mask field is to be ignored.
+ */
+ if ((version != 1) || (cmd > STATUS_STM) ||
+ ((cmd != STATUS_STM) && ((mask == 0) || (0 != (mask >> 4))))) {
+ /* Command is invalid. Send bad param message response */
+ dest_buf[0] = BAD_PARAM_RESPONSE_MESSAGE;
+ for (i = 0; i < STM_CMD_NUM_BYTES; i++)
+ dest_buf[i+1] = *(buf + i);
+ return STM_CMD_NUM_BYTES+1;
+ } else if (cmd == STATUS_STM) {
+ /*
+ * Only the status is being queried, so fill in whether diag
+ * over stm is supported or not
+ */
+ for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++)
+ if (driver->peripheral_supports_stm[i])
+ rsp_supported |= 1 << i;
+
+ rsp_supported |= DIAG_STM_APPS;
} else {
if (mask & DIAG_STM_MODEM)
diag_process_stm_mask(cmd, DIAG_STM_MODEM, MODEM_DATA,
@@ -1169,15 +1195,13 @@
}
for (i = 0; i < STM_CMD_NUM_BYTES; i++)
- driver->apps_rsp_buf[i] = *(buf+i);
+ dest_buf[i] = *(buf + i);
- driver->apps_rsp_buf[STM_RSP_VALID_INDEX] = valid_command;
- driver->apps_rsp_buf[STM_RSP_SUPPORTED_INDEX] = rsp_supported;
- driver->apps_rsp_buf[STM_RSP_SMD_COMPLY_INDEX] = rsp_smd_comply;
+ dest_buf[STM_RSP_VALID_INDEX] = STM_COMMAND_VALID;
+ dest_buf[STM_RSP_SUPPORTED_INDEX] = rsp_supported;
+ dest_buf[STM_RSP_SMD_COMPLY_INDEX] = rsp_smd_comply;
- encode_rsp_and_send(STM_RSP_NUM_BYTES-1);
-
- return 0;
+ return STM_RSP_NUM_BYTES;
}
int diag_apps_responds()
@@ -1273,8 +1297,13 @@
encode_rsp_and_send(7);
return 0;
} else if ((*buf == 0x4b) && (*(buf+1) == 0x12) &&
- (*(uint16_t *)(buf+2) == 0x020E)) {
- return diag_process_stm_cmd(buf);
+ (*(uint16_t *)(buf+2) == DIAG_DIAG_STM)) {
+ len = diag_process_stm_cmd(buf, driver->apps_rsp_buf);
+ if (len > 0) {
+ encode_rsp_and_send(len - 1);
+ return 0;
+ }
+ return len;
}
/* Check for Apps Only & get event mask request */
else if (diag_apps_responds() && *buf == 0x81) {
diff --git a/drivers/char/diag/diagfwd_cntl.h b/drivers/char/diag/diagfwd_cntl.h
index d79195c..7f5ea03 100644
--- a/drivers/char/diag/diagfwd_cntl.h
+++ b/drivers/char/diag/diagfwd_cntl.h
@@ -54,8 +54,9 @@
#define ENABLE_SEPARATE_CMDRSP 1
#define DISABLE_SEPARATE_CMDRSP 0
-#define ENABLE_STM 1
#define DISABLE_STM 0
+#define ENABLE_STM 1
+#define STATUS_STM 2
#define UPDATE_PERIPHERAL_STM_STATE 1
#define CLEAR_PERIPHERAL_STM_STATE 2
diff --git a/drivers/input/misc/mma8x5x.c b/drivers/input/misc/mma8x5x.c
index 29e2d41..a605720 100644
--- a/drivers/input/misc/mma8x5x.c
+++ b/drivers/input/misc/mma8x5x.c
@@ -79,6 +79,7 @@
#define MMA_INT_ROUTING_CFG 0x01
#define MMA_POWER_CFG_MASK 0xFE
+#define MMA_ODR_MASK 0x38
struct sensor_regulator {
struct regulator *vreg;
@@ -405,7 +406,7 @@
if (result < 0)
goto out;
- val = (u8)result | val;
+ val = ((u8)result & ~MMA_ODR_MASK) | val;
result = i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG1,
(val & MMA_POWER_CFG_MASK));
if (result < 0)
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index ea7d670..66d6878 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -693,11 +693,20 @@
int rc = 0;
int i;
struct hal_buffer_requirements *buff_req_buffer;
+
if (!inst || !f || !inst->core || !inst->core->device) {
dprintk(VIDC_ERR,
"Invalid input, inst = %p, format = %p\n", inst, f);
return -EINVAL;
}
+
+ rc = msm_comm_try_get_bufreqs(inst);
+ if (rc) {
+ dprintk(VIDC_ERR, "Getting buffer requirements failed: %d\n",
+ rc);
+ return rc;
+ }
+
hdev = inst->core->device;
if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
fmt = inst->fmts[CAPTURE_PORT];
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index d8b608437..18432dd 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -116,6 +116,7 @@
"Extradata input crop",
"Extradata digital zoom",
"Extradata aspect ratio",
+ "Extradata LTR",
"Extradata macroblock metadata",
};
@@ -2614,6 +2615,14 @@
"Invalid input, inst = %p, format = %p\n", inst, f);
return -EINVAL;
}
+
+ rc = msm_comm_try_get_bufreqs(inst);
+ if (rc) {
+ dprintk(VIDC_WARN, "Getting new buffer requirements failed: %d\n",
+ rc);
+ return rc;
+ }
+
if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
fmt = inst->fmts[CAPTURE_PORT];
height = inst->prop.height[CAPTURE_PORT];
@@ -2643,8 +2652,16 @@
buff_req_buffer->buffer_size : 0;
}
for (i = 0; i < fmt->num_planes; ++i) {
- inst->bufq[CAPTURE_PORT].vb2_bufq.plane_sizes[i] =
- f->fmt.pix_mp.plane_fmt[i].sizeimage;
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ inst->bufq[OUTPUT_PORT].vb2_bufq.
+ plane_sizes[i] =
+ f->fmt.pix_mp.plane_fmt[i].sizeimage;
+ } else if (f->type ==
+ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ inst->bufq[CAPTURE_PORT].vb2_bufq.
+ plane_sizes[i] =
+ f->fmt.pix_mp.plane_fmt[i].sizeimage;
+ }
}
} else {
dprintk(VIDC_ERR,
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index f0721c3..9dbecfb 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -1343,7 +1343,6 @@
mutex_lock(&inst->lock);
}
mutex_unlock(&inst->lock);
- msm_smem_delete_client(inst->mem_client);
debugfs_remove_recursive(inst->debugfs_root);
}
}
@@ -1401,7 +1400,9 @@
for (i = 0; i < MAX_PORT_NUM; i++)
vb2_queue_release(&inst->bufq[i].vb2_bufq);
+ msm_smem_delete_client(inst->mem_client);
pr_info(VIDC_DBG_TAG "Closed video instance: %p\n", VIDC_INFO, inst);
kfree(inst);
+
return 0;
}
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 4fcd20e..eaa5beb 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -527,6 +527,25 @@
return rc;
}
+static void venus_hfi_set_registers(struct venus_hfi_device *device)
+{
+ struct reg_set *reg_set;
+ int i;
+
+ if (!device->res) {
+ dprintk(VIDC_ERR,
+ "device resources null, cannot set registers\n");
+ return;
+ }
+
+ reg_set = &device->res->reg_set;
+ for (i = 0; i < reg_set->count; i++) {
+ venus_hfi_write_register(device,
+ reg_set->reg_tbl[i].reg,
+ reg_set->reg_tbl[i].value, 0);
+ }
+}
+
static int venus_hfi_core_start_cpu(struct venus_hfi_device *device)
{
u32 ctrl_status = 0, count = 0, rc = 0;
@@ -962,6 +981,7 @@
device->power_enabled = 0;
--device->pwr_cnt;
+ dprintk(VIDC_INFO, "entering power collapse\n");
already_disabled:
return rc;
}
@@ -1001,18 +1021,45 @@
goto err_enable_clk;
}
+
+ /*
+ * Re-program all of the registers that get reset as a result of
+ * regulator_disable() and _enable()
+ */
+ venus_hfi_set_registers(device);
+
+ venus_hfi_write_register(device, VIDC_UC_REGION_ADDR,
+ (u32)device->iface_q_table.align_device_addr, 0);
+ venus_hfi_write_register(device,
+ VIDC_UC_REGION_SIZE, SHARED_QSIZE, 0);
+ venus_hfi_write_register(device, VIDC_CPU_CS_SCIACMDARG2,
+ (u32)device->iface_q_table.align_device_addr,
+ device->iface_q_table.align_virtual_addr);
+
+ if (!IS_ERR_OR_NULL(device->sfr.align_device_addr))
+ venus_hfi_write_register(device, VIDC_SFR_ADDR,
+ (u32)device->sfr.align_device_addr, 0);
+ if (!IS_ERR_OR_NULL(device->qdss.align_device_addr))
+ venus_hfi_write_register(device, VIDC_MMAP_ADDR,
+ (u32)device->qdss.align_device_addr, 0);
+
+ /* Reboot the firmware */
rc = venus_hfi_tzbsp_set_video_state(TZBSP_VIDEO_STATE_RESUME);
if (rc) {
dprintk(VIDC_ERR, "Failed to resume video core %d\n", rc);
goto err_set_video_state;
}
+
+ /* Wait for boot completion */
rc = venus_hfi_reset_core(device);
if (rc) {
dprintk(VIDC_ERR, "Failed to reset venus core");
goto err_reset_core;
}
+
device->power_enabled = 1;
++device->pwr_cnt;
+ dprintk(VIDC_INFO, "resuming from power collapse\n");
return rc;
err_reset_core:
venus_hfi_tzbsp_set_video_state(TZBSP_VIDEO_STATE_SUSPEND);
@@ -1497,25 +1544,6 @@
return -ENOMEM;
}
-static void venus_hfi_set_registers(struct venus_hfi_device *device)
-{
- struct reg_set *reg_set;
- int i;
-
- if (!device->res) {
- dprintk(VIDC_ERR,
- "device resources null, cannot set registers\n");
- return;
- }
-
- reg_set = &device->res->reg_set;
- for (i = 0; i < reg_set->count; i++) {
- venus_hfi_write_register(device,
- reg_set->reg_tbl[i].reg,
- reg_set->reg_tbl[i].value, 0);
- }
-}
-
static int venus_hfi_sys_set_debug(struct venus_hfi_device *device, int debug)
{
u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE];
@@ -1561,9 +1589,6 @@
dev->intr_status = 0;
INIT_LIST_HEAD(&dev->sess_head);
- mutex_init(&dev->read_lock);
- mutex_init(&dev->write_lock);
- mutex_init(&dev->session_lock);
venus_hfi_set_registers(dev);
if (!dev->hal_client) {
@@ -3301,7 +3326,6 @@
__func__, device);
return -EINVAL;
}
- mutex_init(&device->clk_pwr_lock);
device->clk_gating_level = VCODEC_CLK;
rc = venus_hfi_iommu_attach(device);
if (rc) {
@@ -3574,6 +3598,11 @@
goto error_createq_pm;
}
+ mutex_init(&hdevice->read_lock);
+ mutex_init(&hdevice->write_lock);
+ mutex_init(&hdevice->session_lock);
+ mutex_init(&hdevice->clk_pwr_lock);
+
if (hal_ctxt.dev_count == 0)
INIT_LIST_HEAD(&hal_ctxt.dev_head);
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 32f5220..822548e 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1503,7 +1503,8 @@
mrq->cmd->error = -EIO;
if (mrq->data)
mrq->data->error = -EIO;
- tasklet_schedule(&host->finish_tasklet);
+ mmc_request_done(host->mmc, mrq);
+ sdhci_runtime_pm_put(host);
return;
}
diff --git a/drivers/net/usb/rmnet_usb_data.c b/drivers/net/usb/rmnet_usb_data.c
index b0db01e..84b3324 100644
--- a/drivers/net/usb/rmnet_usb_data.c
+++ b/drivers/net/usb/rmnet_usb_data.c
@@ -550,8 +550,7 @@
break;
default:
- dev_err(&unet->intf->dev, "[%s] error: "
- "rmnet_ioct called for unsupported cmd[%d]",
+ dev_dbg(&unet->intf->dev, "[%s] error: rmnet_ioctl called for unsupported cmd[0x%x]\n",
dev->name, cmd);
return -EINVAL;
}
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 66875f7..a3e88b4 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -40,6 +40,7 @@
#include <mach/msm_smd.h>
#include <mach/msm_iomap.h>
#include <mach/subsystem_restart.h>
+#include <mach/subsystem_notif.h>
#ifdef CONFIG_WCNSS_MEM_PRE_ALLOC
#include "wcnss_prealloc.h"
@@ -145,6 +146,20 @@
#define MSM_PRONTO_PLL_BASE 0xfb21b1c0
#define PRONTO_PLL_STATUS_OFFSET 0x1c
+#define MSM_PRONTO_MCU_BASE 0xfb080c00
+#define MCU_CBR_CCAHB_ERR_OFFSET 0x380
+#define MCU_CBR_CAHB_ERR_OFFSET 0x384
+#define MCU_CBR_CCAHB_TIMEOUT_OFFSET 0x388
+#define MCU_CBR_CAHB_TIMEOUT_OFFSET 0x38c
+#define MCU_DBR_CDAHB_ERR_OFFSET 0x390
+#define MCU_DBR_DAHB_ERR_OFFSET 0x394
+#define MCU_DBR_CDAHB_TIMEOUT_OFFSET 0x398
+#define MCU_DBR_DAHB_TIMEOUT_OFFSET 0x39c
+#define MCU_FDBR_CDAHB_ERR_OFFSET 0x3a0
+#define MCU_FDBR_FDAHB_ERR_OFFSET 0x3a4
+#define MCU_FDBR_CDAHB_TIMEOUT_OFFSET 0x3a8
+#define MCU_FDBR_FDAHB_TIMEOUT_OFFSET 0x3ac
+
#define MSM_PRONTO_TXP_STATUS 0xfb08040c
#define MSM_PRONTO_TXP_PHY_ABORT 0xfb080488
#define MSM_PRONTO_BRDG_ERR_SRC 0xfb080fb0
@@ -189,6 +204,7 @@
/* max 20mhz channel count */
#define WCNSS_MAX_CH_NUM 45
+#define WCNSS_MAX_PIL_RETRY 3
#define VALID_VERSION(version) \
((strncmp(version, "INVALID", WCNSS_VERSION_LEN)) ? 1 : 0)
@@ -361,6 +377,7 @@
void __iomem *pronto_ccpu_base;
void __iomem *pronto_saw2_base;
void __iomem *pronto_pll_base;
+ void __iomem *pronto_mcu_base;
void __iomem *wlan_tx_status;
void __iomem *wlan_tx_phy_aborts;
void __iomem *wlan_brdg_err_source;
@@ -390,6 +407,7 @@
struct mutex vbat_monitor_mutex;
u16 unsafe_ch_count;
u16 unsafe_ch_list[WCNSS_MAX_CH_NUM];
+ void *wcnss_notif_hdle;
} *penv = NULL;
static ssize_t wcnss_wlan_macaddr_store(struct device *dev,
@@ -562,45 +580,47 @@
reg_addr = penv->msm_wcnss_base + PRONTO_PMU_SPARE_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_info_ratelimited("%s: PRONTO_PMU_SPARE %08x\n", __func__, reg);
+ pr_err("PRONTO_PMU_SPARE %08x\n", reg);
reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_CPU_CBCR_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_info_ratelimited("%s: PRONTO_PMU_COM_CPU_CBCR %08x\n",
- __func__, reg);
+ pr_err("PRONTO_PMU_COM_CPU_CBCR %08x\n", reg);
reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_AHB_CBCR_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_info_ratelimited("%s: PRONTO_PMU_COM_AHB_CBCR %08x\n",
- __func__, reg);
+ pr_err("PRONTO_PMU_COM_AHB_CBCR %08x\n", reg);
reg_addr = penv->msm_wcnss_base + PRONTO_PMU_CFG_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_info_ratelimited("%s: PRONTO_PMU_CFG %08x\n", __func__, reg);
+ pr_err("PRONTO_PMU_CFG %08x\n", reg);
reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_CSR_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_info_ratelimited("%s: PRONTO_PMU_COM_CSR %08x\n",
- __func__, reg);
+ pr_err("PRONTO_PMU_COM_CSR %08x\n", reg);
reg_addr = penv->msm_wcnss_base + PRONTO_PMU_SOFT_RESET_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_info_ratelimited("%s: PRONTO_PMU_SOFT_RESET %08x\n",
- __func__, reg);
+ pr_err("PRONTO_PMU_SOFT_RESET %08x\n", reg);
reg_addr = penv->pronto_saw2_base + PRONTO_SAW2_SPM_STS_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_info_ratelimited("%s: PRONTO_SAW2_SPM_STS %08x\n", __func__, reg);
+ pr_err("PRONTO_SAW2_SPM_STS %08x\n", reg);
+
+ reg_addr = penv->pronto_pll_base + PRONTO_PLL_STATUS_OFFSET;
+ reg = readl_relaxed(reg_addr);
+ pr_err("PRONTO_PLL_STATUS %08x\n", reg);
+
+ reg_addr = penv->msm_wcnss_base + PRONTO_PMU_CPU_AHB_CMD_RCGR_OFFSET;
+ reg4 = readl_relaxed(reg_addr);
+ pr_err("PMU_CPU_CMD_RCGR %08x\n", reg4);
reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_GDSCR_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_info_ratelimited("%s: PRONTO_PMU_COM_GDSCR %08x\n",
- __func__, reg);
+ pr_err("PRONTO_PMU_COM_GDSCR %08x\n", reg);
reg >>= 31;
if (!reg) {
- pr_info_ratelimited("%s: Cannot log, Pronto common SS is power collapsed\n",
- __func__);
+ pr_err("Cannot log, Pronto common SS is power collapsed\n");
return;
}
reg &= ~(PRONTO_PMU_COM_GDSCR_SW_COLLAPSE
@@ -614,35 +634,31 @@
reg_addr = penv->pronto_a2xb_base + A2XB_CFG_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_info_ratelimited("%s: A2XB_CFG_OFFSET %08x\n", __func__, reg);
+ pr_err("A2XB_CFG_OFFSET %08x\n", reg);
reg_addr = penv->pronto_a2xb_base + A2XB_INT_SRC_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_info_ratelimited("%s: A2XB_INT_SRC_OFFSET %08x\n", __func__, reg);
+ pr_err("A2XB_INT_SRC_OFFSET %08x\n", reg);
reg_addr = penv->pronto_a2xb_base + A2XB_ERR_INFO_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_info_ratelimited("%s: A2XB_ERR_INFO_OFFSET %08x\n", __func__, reg);
+ pr_err("A2XB_ERR_INFO_OFFSET %08x\n", reg);
reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_INVALID_ADDR_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_info_ratelimited("%s: CCU_CCPU_INVALID_ADDR %08x\n", __func__, reg);
+ pr_err("CCU_CCPU_INVALID_ADDR %08x\n", reg);
reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_LAST_ADDR0_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR0 %08x\n", __func__, reg);
+ pr_err("CCU_CCPU_LAST_ADDR0 %08x\n", reg);
reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_LAST_ADDR1_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR1 %08x\n", __func__, reg);
+ pr_err("CCU_CCPU_LAST_ADDR1 %08x\n", reg);
reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_LAST_ADDR2_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR2 %08x\n", __func__, reg);
-
- reg_addr = penv->pronto_pll_base + PRONTO_PLL_STATUS_OFFSET;
- reg = readl_relaxed(reg_addr);
- pr_info_ratelimited("%s: PRONTO_PLL_STATUS %08x\n", __func__, reg);
+ pr_err("CCU_CCPU_LAST_ADDR2 %08x\n", reg);
tst_addr = penv->pronto_a2xb_base + A2XB_TSTBUS_OFFSET;
tst_ctrl_addr = penv->pronto_a2xb_base + A2XB_TSTBUS_CTRL_OFFSET;
@@ -652,24 +668,21 @@
reg = reg | WCNSS_TSTBUS_CTRL_EN | WCNSS_TSTBUS_CTRL_RDFIFO;
writel_relaxed(reg, tst_ctrl_addr);
reg = readl_relaxed(tst_addr);
- pr_info_ratelimited("%s: Read data FIFO testbus %08x\n",
- __func__, reg);
+ pr_err("Read data FIFO testbus %08x\n", reg);
/* command FIFO */
reg = 0;
reg = reg | WCNSS_TSTBUS_CTRL_EN | WCNSS_TSTBUS_CTRL_CMDFIFO;
writel_relaxed(reg, tst_ctrl_addr);
reg = readl_relaxed(tst_addr);
- pr_info_ratelimited("%s: Command FIFO testbus %08x\n",
- __func__, reg);
+ pr_err("Command FIFO testbus %08x\n", reg);
/* write data FIFO */
reg = 0;
reg = reg | WCNSS_TSTBUS_CTRL_EN | WCNSS_TSTBUS_CTRL_WRFIFO;
writel_relaxed(reg, tst_ctrl_addr);
reg = readl_relaxed(tst_addr);
- pr_info_ratelimited("%s: Rrite data FIFO testbus %08x\n",
- __func__, reg);
+ pr_err("Rrite data FIFO testbus %08x\n", reg);
/* AXIM SEL CFG0 */
reg = 0;
@@ -677,8 +690,7 @@
WCNSS_TSTBUS_CTRL_AXIM_CFG0;
writel_relaxed(reg, tst_ctrl_addr);
reg = readl_relaxed(tst_addr);
- pr_info_ratelimited("%s: AXIM SEL CFG0 testbus %08x\n",
- __func__, reg);
+ pr_err("AXIM SEL CFG0 testbus %08x\n", reg);
/* AXIM SEL CFG1 */
reg = 0;
@@ -686,8 +698,7 @@
WCNSS_TSTBUS_CTRL_AXIM_CFG1;
writel_relaxed(reg, tst_ctrl_addr);
reg = readl_relaxed(tst_addr);
- pr_info_ratelimited("%s: AXIM SEL CFG1 testbus %08x\n",
- __func__, reg);
+ pr_err("AXIM SEL CFG1 testbus %08x\n", reg);
/* CTRL SEL CFG0 */
reg = 0;
@@ -695,8 +706,7 @@
WCNSS_TSTBUS_CTRL_CTRL_CFG0;
writel_relaxed(reg, tst_ctrl_addr);
reg = readl_relaxed(tst_addr);
- pr_info_ratelimited("%s: CTRL SEL CFG0 testbus %08x\n",
- __func__, reg);
+ pr_err("CTRL SEL CFG0 testbus %08x\n", reg);
/* CTRL SEL CFG1 */
reg = 0;
@@ -704,7 +714,7 @@
WCNSS_TSTBUS_CTRL_CTRL_CFG1;
writel_relaxed(reg, tst_ctrl_addr);
reg = readl_relaxed(tst_addr);
- pr_info_ratelimited("%s: CTRL SEL CFG1 testbus %08x\n", __func__, reg);
+ pr_err("CTRL SEL CFG1 testbus %08x\n", reg);
reg_addr = penv->msm_wcnss_base + PRONTO_PMU_WLAN_BCR_OFFSET;
@@ -715,30 +725,75 @@
reg_addr = penv->msm_wcnss_base + PRONTO_PMU_WLAN_AHB_CBCR_OFFSET;
reg3 = readl_relaxed(reg_addr);
- pr_info_ratelimited("%s: PMU_WLAN_AHB_CBCR %08x\n", __func__, reg3);
-
- reg_addr = penv->msm_wcnss_base + PRONTO_PMU_CPU_AHB_CMD_RCGR_OFFSET;
- reg4 = readl_relaxed(reg_addr);
- pr_info_ratelimited("%s: PMU_CPU_CMD_RCGR %08x\n", __func__, reg4);
+ pr_err("PMU_WLAN_AHB_CBCR %08x\n", reg3);
if ((reg & PRONTO_PMU_WLAN_BCR_BLK_ARES) ||
(reg2 & PRONTO_PMU_WLAN_GDSCR_SW_COLLAPSE) ||
(!(reg4 & PRONTO_PMU_CPU_AHB_CMD_RCGR_ROOT_EN)) ||
(reg3 & PRONTO_PMU_WLAN_AHB_CBCR_CLK_OFF) ||
(!(reg3 & PRONTO_PMU_WLAN_AHB_CBCR_CLK_EN))) {
- pr_info_ratelimited("%s: Cannot log, wlan domain is power collapsed\n",
- __func__);
+ pr_err("Cannot log, wlan domain is power collapsed\n");
return;
}
+ msleep(50);
+
reg = readl_relaxed(penv->wlan_tx_phy_aborts);
- pr_info_ratelimited("%s: WLAN_TX_PHY_ABORTS %08x\n", __func__, reg);
+ pr_err("WLAN_TX_PHY_ABORTS %08x\n", reg);
+
+ reg_addr = penv->pronto_mcu_base + MCU_CBR_CCAHB_ERR_OFFSET;
+ reg = readl_relaxed(reg_addr);
+ pr_err("MCU_CBR_CCAHB_ERR %08x\n", reg);
+
+ reg_addr = penv->pronto_mcu_base + MCU_CBR_CAHB_ERR_OFFSET;
+ reg = readl_relaxed(reg_addr);
+ pr_err("MCU_CBR_CAHB_ERR %08x\n", reg);
+
+ reg_addr = penv->pronto_mcu_base + MCU_CBR_CCAHB_TIMEOUT_OFFSET;
+ reg = readl_relaxed(reg_addr);
+ pr_err("MCU_CBR_CCAHB_TIMEOUT %08x\n", reg);
+
+ reg_addr = penv->pronto_mcu_base + MCU_CBR_CAHB_TIMEOUT_OFFSET;
+ reg = readl_relaxed(reg_addr);
+ pr_err("MCU_CBR_CAHB_TIMEOUT %08x\n", reg);
+
+ reg_addr = penv->pronto_mcu_base + MCU_DBR_CDAHB_ERR_OFFSET;
+ reg = readl_relaxed(reg_addr);
+ pr_err("MCU_DBR_CDAHB_ERR %08x\n", reg);
+
+ reg_addr = penv->pronto_mcu_base + MCU_DBR_DAHB_ERR_OFFSET;
+ reg = readl_relaxed(reg_addr);
+ pr_err("MCU_DBR_DAHB_ERR %08x\n", reg);
+
+ reg_addr = penv->pronto_mcu_base + MCU_DBR_CDAHB_TIMEOUT_OFFSET;
+ reg = readl_relaxed(reg_addr);
+ pr_err("MCU_DBR_CDAHB_TIMEOUT %08x\n", reg);
+
+ reg_addr = penv->pronto_mcu_base + MCU_DBR_DAHB_TIMEOUT_OFFSET;
+ reg = readl_relaxed(reg_addr);
+ pr_err("MCU_DBR_DAHB_TIMEOUT %08x\n", reg);
+
+ reg_addr = penv->pronto_mcu_base + MCU_FDBR_CDAHB_ERR_OFFSET;
+ reg = readl_relaxed(reg_addr);
+ pr_err("MCU_FDBR_CDAHB_ERR %08x\n", reg);
+
+ reg_addr = penv->pronto_mcu_base + MCU_FDBR_FDAHB_ERR_OFFSET;
+ reg = readl_relaxed(reg_addr);
+ pr_err("MCU_FDBR_FDAHB_ERR %08x\n", reg);
+
+ reg_addr = penv->pronto_mcu_base + MCU_FDBR_CDAHB_TIMEOUT_OFFSET;
+ reg = readl_relaxed(reg_addr);
+ pr_err("MCU_FDBR_CDAHB_TIMEOUT %08x\n", reg);
+
+ reg_addr = penv->pronto_mcu_base + MCU_FDBR_FDAHB_TIMEOUT_OFFSET;
+ reg = readl_relaxed(reg_addr);
+ pr_err("MCU_FDBR_FDAHB_TIMEOUT %08x\n", reg);
reg = readl_relaxed(penv->wlan_brdg_err_source);
- pr_info_ratelimited("%s: WLAN_BRDG_ERR_SOURCE %08x\n", __func__, reg);
+ pr_err("WLAN_BRDG_ERR_SOURCE %08x\n", reg);
reg = readl_relaxed(penv->wlan_tx_status);
- pr_info_ratelimited("%s: WLAN_TX_STATUS %08x\n", __func__, reg);
+ pr_err("WLAN_TXP_STATUS %08x\n", reg);
reg = readl_relaxed(penv->alarms_txctl);
pr_err("ALARMS_TXCTL %08x\n", reg);
@@ -2068,6 +2123,7 @@
unsigned long wcnss_phys_addr;
int size = 0;
struct resource *res;
+ int pil_retry = 0;
int has_pronto_hw = of_property_read_bool(pdev->dev.of_node,
"qcom,has-pronto-hw");
@@ -2249,6 +2305,13 @@
pr_err("%s: ioremap alarms TACTL failed\n", __func__);
goto fail_ioremap11;
}
+ penv->pronto_mcu_base = ioremap(MSM_PRONTO_MCU_BASE, SZ_1K);
+ if (!penv->pronto_mcu_base) {
+ ret = -ENOMEM;
+ pr_err("%s: ioremap wcnss physical(mcu) failed\n",
+ __func__);
+ goto fail_ioremap12;
+ }
}
penv->adc_tm_dev = qpnp_get_adc_tm(&penv->pdev->dev, "wcnss");
if (IS_ERR(penv->adc_tm_dev)) {
@@ -2259,12 +2322,17 @@
penv->fw_vbatt_state = WCNSS_CONFIG_UNSPECIFIED;
}
- /* trigger initialization of the WCNSS */
- penv->pil = subsystem_get(WCNSS_PIL_DEVICE);
- if (IS_ERR(penv->pil)) {
- dev_err(&pdev->dev, "Peripheral Loader failed on WCNSS.\n");
- ret = PTR_ERR(penv->pil);
- wcnss_pronto_log_debug_regs();
+ do {
+ /* trigger initialization of the WCNSS */
+ penv->pil = subsystem_get(WCNSS_PIL_DEVICE);
+ if (IS_ERR(penv->pil)) {
+ dev_err(&pdev->dev, "Peripheral Loader failed on WCNSS.\n");
+ ret = PTR_ERR(penv->pil);
+ wcnss_pronto_log_debug_regs();
+ }
+ } while (pil_retry++ < WCNSS_MAX_PIL_RETRY && IS_ERR(penv->pil));
+
+ if (pil_retry >= WCNSS_MAX_PIL_RETRY) {
penv->pil = NULL;
goto fail_pil;
}
@@ -2274,6 +2342,9 @@
fail_pil:
if (penv->riva_ccu_base)
iounmap(penv->riva_ccu_base);
+ if (penv->pronto_mcu_base)
+ iounmap(penv->pronto_mcu_base);
+fail_ioremap12:
if (penv->alarms_tactl)
iounmap(penv->alarms_tactl);
fail_ioremap11:
@@ -2440,6 +2511,22 @@
}
+static int wcnss_notif_cb(struct notifier_block *this, unsigned long code,
+ void *ss_handle)
+{
+ pr_debug("%s: wcnss notification event: %lu\n", __func__, code);
+
+ if (SUBSYS_POWERUP_FAILURE == code)
+ wcnss_pronto_log_debug_regs();
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block wnb = {
+ .notifier_call = wcnss_notif_cb,
+};
+
+
static const struct file_operations wcnss_node_fops = {
.owner = THIS_MODULE,
.open = wcnss_node_open,
@@ -2479,6 +2566,13 @@
return -ENOENT;
}
+ /* register wcnss event notification */
+ penv->wcnss_notif_hdle = subsys_notif_register_notifier("wcnss", &wnb);
+ if (IS_ERR(penv->wcnss_notif_hdle)) {
+ pr_err("wcnss: register event notification failed!\n");
+ return PTR_ERR(penv->wcnss_notif_hdle);
+ }
+
mutex_init(&penv->dev_lock);
mutex_init(&penv->ctrl_lock);
mutex_init(&penv->vbat_monitor_mutex);
@@ -2503,6 +2597,8 @@
static int __devexit
wcnss_wlan_remove(struct platform_device *pdev)
{
+ if (penv->wcnss_notif_hdle)
+ subsys_notif_unregister_notifier(penv->wcnss_notif_hdle, &wnb);
wcnss_remove_sysfs(&pdev->dev);
penv = NULL;
return 0;
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index a0d9a24..2003b69 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -2205,7 +2205,7 @@
pr_err("adc vbat failed err = %d\n", rc);
return soc;
}
- if (soc == 0 && vbat_uv > chip->v_cutoff_uv) {
+ if (soc <= 0 && vbat_uv > chip->v_cutoff_uv) {
pr_debug("clamping soc to 1, vbat (%d) > cutoff (%d)\n",
vbat_uv, chip->v_cutoff_uv);
return 1;
diff --git a/drivers/rtc/alarm.c b/drivers/rtc/alarm.c
index 51e176f..06749b9 100644
--- a/drivers/rtc/alarm.c
+++ b/drivers/rtc/alarm.c
@@ -520,8 +520,11 @@
spin_lock_irqsave(&alarm_slock, flags);
- if (!power_on_alarm)
+ if (!power_on_alarm) {
+ spin_unlock_irqrestore(&alarm_slock, flags);
goto disable_alarm;
+ }
+ spin_unlock_irqrestore(&alarm_slock, flags);
rtc_read_time(alarm_rtc_dev, &rtc_time);
getnstimeofday(&wall_time);
@@ -549,11 +552,9 @@
pr_alarm(FLOW, "Power-on alarm set to %lu\n",
alarm_time);
- spin_unlock_irqrestore(&alarm_slock, flags);
return;
disable_alarm:
- spin_unlock_irqrestore(&alarm_slock, flags);
rtc_alarm_irq_enable(alarm_rtc_dev, 0);
}
diff --git a/drivers/usb/gadget/f_rmnet.c b/drivers/usb/gadget/f_rmnet.c
index 2fa8c63..ebcec96 100644
--- a/drivers/usb/gadget/f_rmnet.c
+++ b/drivers/usb/gadget/f_rmnet.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2014, 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
@@ -47,7 +47,7 @@
/* control info */
struct list_head cpkt_resp_q;
- atomic_t notify_count;
+ unsigned long notify_count;
unsigned long cpkts_len;
};
@@ -605,7 +605,7 @@
list_del(&cpkt->list);
rmnet_free_ctrl_pkt(cpkt);
}
- atomic_set(&dev->notify_count, 0);
+ dev->notify_count = 0;
spin_unlock_irqrestore(&dev->lock, flags);
}
@@ -619,6 +619,7 @@
__func__, xport_to_str(dxport),
dev, dev->port_num);
+ usb_ep_fifo_flush(dev->notify);
frmnet_purge_responses(dev);
port_num = rmnet_ports[dev->port_num].data_xport_num;
@@ -754,7 +755,7 @@
return;
}
- if (atomic_inc_return(&dev->notify_count) != 1) {
+ if (++dev->notify_count != 1) {
spin_unlock_irqrestore(&dev->lock, flags);
return;
}
@@ -772,7 +773,14 @@
if (ret) {
spin_lock_irqsave(&dev->lock, flags);
if (!list_empty(&dev->cpkt_resp_q)) {
- atomic_dec(&dev->notify_count);
+ if (dev->notify_count > 0)
+ dev->notify_count--;
+ else {
+ pr_debug("%s: Invalid notify_count=%lu to decrement\n",
+ __func__, dev->notify_count);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return;
+ }
cpkt = list_first_entry(&dev->cpkt_resp_q,
struct rmnet_ctrl_pkt, list);
list_del(&cpkt->list);
@@ -911,7 +919,9 @@
case -ECONNRESET:
case -ESHUTDOWN:
/* connection gone */
- atomic_set(&dev->notify_count, 0);
+ spin_lock_irqsave(&dev->lock, flags);
+ dev->notify_count = 0;
+ spin_unlock_irqrestore(&dev->lock, flags);
break;
default:
pr_err("rmnet notify ep error %d\n", status);
@@ -920,14 +930,34 @@
if (!atomic_read(&dev->ctrl_online))
break;
- if (atomic_dec_and_test(&dev->notify_count))
+ spin_lock_irqsave(&dev->lock, flags);
+ if (dev->notify_count > 0) {
+ dev->notify_count--;
+ if (dev->notify_count == 0) {
+ spin_unlock_irqrestore(&dev->lock, flags);
+ break;
+ }
+ } else {
+ pr_debug("%s: Invalid notify_count=%lu to decrement\n",
+ __func__, dev->notify_count);
+ spin_unlock_irqrestore(&dev->lock, flags);
break;
+ }
+ spin_unlock_irqrestore(&dev->lock, flags);
status = usb_ep_queue(dev->notify, req, GFP_ATOMIC);
if (status) {
spin_lock_irqsave(&dev->lock, flags);
if (!list_empty(&dev->cpkt_resp_q)) {
- atomic_dec(&dev->notify_count);
+ if (dev->notify_count > 0)
+ dev->notify_count--;
+ else {
+ pr_err("%s: Invalid notify_count=%lu to decrement\n",
+ __func__, dev->notify_count);
+ spin_unlock_irqrestore(&dev->lock,
+ flags);
+ break;
+ }
cpkt = list_first_entry(&dev->cpkt_resp_q,
struct rmnet_ctrl_pkt, list);
list_del(&cpkt->list);
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index b324130..1111aeb 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -798,7 +798,7 @@
rc = mdp3_dma->stop(mdp3_dma, mdp3_session->intf);
if (rc) {
- pr_err("fail to stop the MDP3 dma\n");
+ pr_err("fail to stop the MDP3 dma %d\n", rc);
goto reset_error;
}
@@ -1011,7 +1011,11 @@
panel = mdp3_session->panel;
if (!mdp3_iommu_is_attached(MDP3_CLIENT_DMA_P)) {
pr_debug("continuous splash screen, IOMMU not attached\n");
- mdp3_ctrl_reset(mfd);
+ rc = mdp3_ctrl_reset(mfd);
+ if (rc) {
+ pr_err("fail to reset display\n");
+ return -EINVAL;
+ }
reset_done = true;
}
@@ -1092,7 +1096,11 @@
if (!mdp3_iommu_is_attached(MDP3_CLIENT_DMA_P)) {
pr_debug("continuous splash screen, IOMMU not attached\n");
- mdp3_ctrl_reset(mfd);
+ rc = mdp3_ctrl_reset(mfd);
+ if (rc) {
+ pr_err("fail to reset display\n");
+ return;
+ }
}
mutex_lock(&mdp3_session->lock);
diff --git a/drivers/video/msm/mdss/mdp3_dma.c b/drivers/video/msm/mdss/mdp3_dma.c
index 800c4b3..993a36f 100644
--- a/drivers/video/msm/mdss/mdp3_dma.c
+++ b/drivers/video/msm/mdss/mdp3_dma.c
@@ -18,7 +18,7 @@
#include "mdp3_hwio.h"
#define DMA_STOP_POLL_SLEEP_US 1000
-#define DMA_STOP_POLL_TIMEOUT_US 32000
+#define DMA_STOP_POLL_TIMEOUT_US 200000
#define DMA_HISTO_RESET_TIMEOUT_MS 40
#define DMA_LUT_CONFIG_MASK 0xfffffbe8
#define DMA_CCS_CONFIG_MASK 0xfffffc17
diff --git a/drivers/video/msm/mdss/mdss_hdmi_hdcp.c b/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
index e56e9fa..2240941 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
@@ -1050,7 +1050,10 @@
}
if (++hdcp_ctrl->auth_retries == AUTH_RETRIES_TIME) {
- hdmi_hdcp_off(hdcp_ctrl);
+ mutex_lock(hdcp_ctrl->init_data.mutex);
+ hdcp_ctrl->hdcp_state = HDCP_STATE_INACTIVE;
+ mutex_unlock(hdcp_ctrl->init_data.mutex);
+
hdcp_ctrl->auth_retries = 0;
ret = -ERANGE;
}
@@ -1077,13 +1080,6 @@
return 0;
}
- ret = hdmi_msm_if_abort_reauth(hdcp_ctrl);
-
- if (ret) {
- DEV_ERR("%s: abort reauthentication!\n", __func__);
- return ret;
- }
-
/*
* Disable HPD circuitry.
* This is needed to reset the HDCP cipher engine so that when we
@@ -1109,6 +1105,13 @@
DSS_REG_R(hdcp_ctrl->init_data.core_io,
HDMI_HPD_CTRL) | BIT(28));
+ ret = hdmi_msm_if_abort_reauth(hdcp_ctrl);
+
+ if (ret) {
+ DEV_ERR("%s: abort reauthentication!\n", __func__);
+ return ret;
+ }
+
/* Restart authentication attempt */
DEV_DBG("%s: %s: Scheduling work to start HDCP authentication",
__func__, HDCP_STATE_NAME);
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index cd2f8e4..cdf9d73 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -1143,6 +1143,13 @@
hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0, false);
hdmi_tx_wait_for_audio_engine(hdmi_ctrl);
+ if (!hdmi_ctrl->panel_power_on) {
+ if (hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_DDC_PM,
+ false))
+ DEV_WARN("%s: Failed to disable ddc power\n",
+ __func__);
+ }
+
hdmi_tx_send_cable_notification(hdmi_ctrl, 0);
DEV_INFO("%s: sense cable DISCONNECTED: state switch to %d\n",
__func__, hdmi_ctrl->sdev.state);
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 5c9ad9c..54ec6f8 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -1625,7 +1625,7 @@
*/
int mdss_mdp_pp_resume(struct mdss_mdp_ctl *ctl, u32 dspp_num)
{
- u32 flags = 0, disp_num, bl;
+ u32 flags = 0, disp_num, bl, ret = 0;
struct pp_sts_type pp_sts;
struct mdss_ad_info *ad;
struct mdss_data_type *mdata = ctl->mdata;
@@ -1636,7 +1636,9 @@
disp_num = ctl->mfd->index;
if (dspp_num < mdata->nad_cfgs) {
- ad = &mdata->ad_cfgs[dspp_num];
+ ret = mdss_mdp_get_ad(ctl->mfd, &ad);
+ if (ret)
+ return ret;
if (PP_AD_STATE_CFG & ad->state)
pp_ad_cfg_write(&mdata->ad_off[dspp_num], ad);
diff --git a/include/sound/Kbuild b/include/sound/Kbuild
index 60847b0..aeccfed 100644
--- a/include/sound/Kbuild
+++ b/include/sound/Kbuild
@@ -13,3 +13,4 @@
header-y += compress_offload.h
header-y += lsm_params.h
header-y += voice_params.h
+header-y += voice_svc.h
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 69944a6..1c6ea04 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 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
@@ -579,6 +579,15 @@
/* Clients must set this field to zero.*/
} __packed;
+#define ASM_PARAM_ID_AAC_STEREO_MIX_COEFF_SELECTION_FLAG_V2 (0x00010DD8)
+
+struct asm_aac_stereo_mix_coeff_selection_param_v2 {
+ struct apr_hdr hdr;
+ u32 param_id;
+ u32 param_size;
+ u32 aac_stereo_mix_coeff_flag;
+} __packed;
+
/* Allows a client to connect the desired stream to
* the desired AFE port through the stream router
*
diff --git a/include/sound/voice_svc.h b/include/sound/voice_svc.h
new file mode 100644
index 0000000..7045018
--- /dev/null
+++ b/include/sound/voice_svc.h
@@ -0,0 +1,46 @@
+#ifndef __VOICE_SVC_H__
+#define __VOICE_SVC_H__
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#define VOICE_SVC_DRIVER_NAME "voice_svc"
+
+#define VOICE_SVC_MVM_STR "MVM"
+#define VOICE_SVC_CVS_STR "CVS"
+#define MAX_APR_SERVICE_NAME_LEN 64
+
+struct voice_svc_register {
+ char svc_name[MAX_APR_SERVICE_NAME_LEN];
+ __u32 src_port;
+ __u8 reg_flag;
+};
+
+struct voice_svc_cmd_response {
+ __u32 src_port;
+ __u32 dest_port;
+ __u32 token;
+ __u32 opcode;
+ __u32 payload_size;
+ __u8 payload[0];
+};
+
+struct voice_svc_cmd_request {
+ char svc_name[MAX_APR_SERVICE_NAME_LEN];
+ __u32 src_port;
+ __u32 dest_port;
+ __u32 token;
+ __u32 opcode;
+ __u32 payload_size;
+ __u8 payload[0];
+};
+
+#define VOICE_SVC_MAGIC 'N'
+
+#define SNDRV_VOICE_SVC_REGISTER_SVC _IOWR(VOICE_SVC_MAGIC, \
+ 0x01, struct voice_svc_register)
+#define SNDRV_VOICE_SVC_CMD_RESPONSE _IOWR(VOICE_SVC_MAGIC, \
+ 0x02, struct voice_svc_cmd_response)
+#define SNDRV_VOICE_SVC_CMD_REQUEST _IOWR(VOICE_SVC_MAGIC, \
+ 0x03, struct voice_svc_cmd_request)
+#endif
diff --git a/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index 452bbab..c73b2c8 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -1200,6 +1200,13 @@
MSM8X10_WCD_A_CDC_TX2_VOL_CTL_GAIN,
-84, 40, digital_gain),
+ SOC_SINGLE_TLV("ADC1 Volume", MSM8X10_WCD_A_TX_1_EN, 2,
+ 19, 0, analog_gain),
+ SOC_SINGLE_TLV("ADC2 Volume", MSM8X10_WCD_A_TX_2_EN, 2,
+ 19, 0, analog_gain),
+ SOC_SINGLE_TLV("ADC3 Volume", MSM8X10_WCD_A_TX_3_EN, 2,
+ 19, 0, analog_gain),
+
SOC_SINGLE_S8_TLV("IIR1 INP1 Volume",
MSM8X10_WCD_A_CDC_IIR1_GAIN_B1_CTL,
-84, 40, digital_gain),
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index d84ba90..95f2041 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -43,6 +43,8 @@
#define TAPAN_HPH_PA_SETTLE_COMP_OFF 13000
#define DAPM_MICBIAS2_EXTERNAL_STANDALONE "MIC BIAS2 External Standalone"
+#define TAPAN_VALIDATE_RX_SBPORT_RANGE(port) ((port >= 16) && (port <= 20))
+#define TAPAN_CONVERT_RX_SBPORT_ID(port) (port - 16) /* RX1 port ID = 0 */
#define TAPAN_VDD_CX_OPTIMAL_UA 10000
#define TAPAN_VDD_CX_SLEEP_UA 2000
@@ -3236,6 +3238,8 @@
}
#define TAPAN_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
+#define TAPAN_FORMATS_S16_S24_LE (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FORMAT_S24_LE)
static int tapan_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
@@ -3643,6 +3647,68 @@
return 0;
}
+static void tapan_set_rxsb_port_format(struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
+ struct wcd9xxx_codec_dai_data *cdc_dai;
+ struct wcd9xxx_ch *ch;
+ int port;
+ u8 bit_sel;
+ u16 sb_ctl_reg, field_shift;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ bit_sel = 0x2;
+ tapan_p->dai[dai->id].bit_width = 16;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ bit_sel = 0x0;
+ tapan_p->dai[dai->id].bit_width = 24;
+ break;
+ default:
+ dev_err(codec->dev, "Invalid format %x\n",
+ params_format(params));
+ return;
+ }
+
+ cdc_dai = &tapan_p->dai[dai->id];
+
+ list_for_each_entry(ch, &cdc_dai->wcd9xxx_ch_list, list) {
+ port = wcd9xxx_get_slave_port(ch->ch_num);
+
+ if (IS_ERR_VALUE(port) ||
+ !TAPAN_VALIDATE_RX_SBPORT_RANGE(port)) {
+ dev_warn(codec->dev,
+ "%s: invalid port ID %d returned for RX DAI\n",
+ __func__, port);
+ return;
+ }
+
+ port = TAPAN_CONVERT_RX_SBPORT_ID(port);
+
+ if (port <= 3) {
+ sb_ctl_reg = TAPAN_A_CDC_CONN_RX_SB_B1_CTL;
+ field_shift = port << 1;
+ } else if (port <= 4) {
+ sb_ctl_reg = TAPAN_A_CDC_CONN_RX_SB_B2_CTL;
+ field_shift = (port - 4) << 1;
+ } else { /* should not happen */
+ dev_warn(codec->dev,
+ "%s: bad port ID %d\n", __func__, port);
+ return;
+ }
+
+ dev_dbg(codec->dev, "%s: sb_ctl_reg %x field_shift %x\n"
+ "bit_sel %x\n", __func__, sb_ctl_reg, field_shift,
+ bit_sel);
+ snd_soc_update_bits(codec, sb_ctl_reg, 0x3 << field_shift,
+ bit_sel << field_shift);
+ }
+}
+
+
static int tapan_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
@@ -3755,29 +3821,7 @@
snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_I2S_CTL,
0x03, (rx_fs_rate >> 0x05));
} else {
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S16_LE:
- snd_soc_update_bits(codec,
- TAPAN_A_CDC_CONN_RX_SB_B1_CTL,
- 0xFF, 0xAA);
- snd_soc_update_bits(codec,
- TAPAN_A_CDC_CONN_RX_SB_B2_CTL,
- 0xFF, 0x2A);
- tapan->dai[dai->id].bit_width = 16;
- break;
- case SNDRV_PCM_FORMAT_S24_LE:
- snd_soc_update_bits(codec,
- TAPAN_A_CDC_CONN_RX_SB_B1_CTL,
- 0xFF, 0x00);
- snd_soc_update_bits(codec,
- TAPAN_A_CDC_CONN_RX_SB_B2_CTL,
- 0xFF, 0x00);
- tapan->dai[dai->id].bit_width = 24;
- break;
- default:
- dev_err(codec->dev, "Invalid format\n");
- break;
- }
+ tapan_set_rxsb_port_format(params, dai);
tapan->dai[dai->id].rate = params_rate(params);
}
break;
@@ -3894,7 +3938,7 @@
.playback = {
.stream_name = "AIF1 Playback",
.rates = WCD9306_RATES,
- .formats = TAPAN_FORMATS,
+ .formats = TAPAN_FORMATS_S16_S24_LE,
.rate_max = 192000,
.rate_min = 8000,
.channels_min = 1,
@@ -3922,7 +3966,7 @@
.playback = {
.stream_name = "AIF2 Playback",
.rates = WCD9306_RATES,
- .formats = TAPAN_FORMATS,
+ .formats = TAPAN_FORMATS_S16_S24_LE,
.rate_min = 8000,
.rate_max = 192000,
.channels_min = 1,
@@ -3964,7 +4008,7 @@
.playback = {
.stream_name = "AIF3 Playback",
.rates = WCD9306_RATES,
- .formats = TAPAN_FORMATS,
+ .formats = TAPAN_FORMATS_S16_S24_LE,
.rate_min = 8000,
.rate_max = 192000,
.channels_min = 1,
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 2b43ab6..045a6d0 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -899,6 +899,30 @@
.ops = &msm_fe_dai_ops,
.name = "LSM8",
},
+ {
+ .playback = {
+ .stream_name = "VoWLAN Playback",
+ .aif_name = "VoWLAN_DL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .capture = {
+ .stream_name = "VoWLAN Capture",
+ .aif_name = "VoWLAN_UL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "VoWLAN",
+ },
};
static __devinit int msm_fe_dai_dev_probe(struct platform_device *pdev)
diff --git a/sound/soc/msm/msm8226.c b/sound/soc/msm/msm8226.c
index 17e99dd..cc27fc0 100644
--- a/sound/soc/msm/msm8226.c
+++ b/sound/soc/msm/msm8226.c
@@ -1607,7 +1607,7 @@
.codec_name = "snd-soc-dummy",
.be_id = MSM_FRONTEND_DAI_LSM8,
},
- {
+ {/* hw:x,28 */
.name = "INT_HFP_BT Hostless",
.stream_name = "INT_HFP_BT Hostless",
.cpu_dai_name = "INT_HFP_BT_HOSTLESS",
@@ -1622,7 +1622,7 @@
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
},
- {
+ {/* hw:x,29 */
.name = "MSM8226 HFP TX",
.stream_name = "MultiMedia6",
.cpu_dai_name = "MultiMedia6",
@@ -1638,6 +1638,21 @@
.ignore_pmdown_time = 1,
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA6,
},
+ {/* hw:x,30 */
+ .name = "VoWLAN",
+ .stream_name = "VoWLAN",
+ .cpu_dai_name = "VoWLAN",
+ .platform_name = "msm-pcm-voice",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_VOWLAN,
+ },
/* Backend BT/FM DAI Links */
{
.name = LPASS_BE_INT_BT_SCO_RX,
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index 1434970..8b2c443 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -57,6 +57,7 @@
struct msm_dai_q6_dai_data {
DECLARE_BITMAP(status_mask, STATUS_MAX);
+ DECLARE_BITMAP(hwfree_status, STATUS_MAX);
u32 rate;
u32 channels;
u32 bitwidth;
@@ -1510,6 +1511,11 @@
set_bit(STATUS_PORT_STARTED,
dai_data->status_mask);
}
+ if (!test_bit(STATUS_PORT_STARTED, dai_data->hwfree_status)) {
+ set_bit(STATUS_PORT_STARTED, dai_data->hwfree_status);
+ dev_dbg(dai->dev, "%s: set hwfree_status to started\n",
+ __func__);
+ }
return rc;
}
@@ -1525,7 +1531,6 @@
struct msm_dai_q6_dai_data *dai_data = &mi2s_dai_config->mi2s_dai_data;
struct afe_param_id_i2s_cfg *i2s = &dai_data->port_config.i2s;
-
dai_data->channels = params_channels(params);
switch (dai_data->channels) {
case 8:
@@ -1602,10 +1607,14 @@
dai_data->port_config.i2s.i2s_cfg_minor_version =
AFE_API_VERSION_I2S_CONFIG;
dai_data->port_config.i2s.sample_rate = dai_data->rate;
- if (test_bit(STATUS_PORT_STARTED,
- mi2s_dai_data->rx_dai.mi2s_dai_data.status_mask) ||
+ if ((test_bit(STATUS_PORT_STARTED,
+ mi2s_dai_data->rx_dai.mi2s_dai_data.status_mask) &&
test_bit(STATUS_PORT_STARTED,
- mi2s_dai_data->tx_dai.mi2s_dai_data.status_mask)) {
+ mi2s_dai_data->rx_dai.mi2s_dai_data.hwfree_status)) ||
+ (test_bit(STATUS_PORT_STARTED,
+ mi2s_dai_data->tx_dai.mi2s_dai_data.status_mask) &&
+ test_bit(STATUS_PORT_STARTED,
+ mi2s_dai_data->tx_dai.mi2s_dai_data.hwfree_status))) {
if ((mi2s_dai_data->tx_dai.mi2s_dai_data.rate !=
mi2s_dai_data->rx_dai.mi2s_dai_data.rate) ||
(mi2s_dai_data->rx_dai.mi2s_dai_data.bitwidth !=
@@ -1669,6 +1678,23 @@
return 0;
}
+static int msm_dai_q6_mi2s_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
+ dev_get_drvdata(dai->dev);
+ struct msm_dai_q6_dai_data *dai_data =
+ (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ &mi2s_dai_data->rx_dai.mi2s_dai_data :
+ &mi2s_dai_data->tx_dai.mi2s_dai_data);
+
+ if (test_bit(STATUS_PORT_STARTED, dai_data->hwfree_status)) {
+ clear_bit(STATUS_PORT_STARTED, dai_data->hwfree_status);
+ dev_dbg(dai->dev, "%s: clear hwfree_status\n", __func__);
+ }
+ return 0;
+}
+
static void msm_dai_q6_mi2s_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
@@ -1696,12 +1722,15 @@
dev_err(dai->dev, "fail to close AFE port\n");
clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
}
+ if (test_bit(STATUS_PORT_STARTED, dai_data->hwfree_status))
+ clear_bit(STATUS_PORT_STARTED, dai_data->hwfree_status);
}
static struct snd_soc_dai_ops msm_dai_q6_mi2s_ops = {
.startup = msm_dai_q6_mi2s_startup,
.prepare = msm_dai_q6_mi2s_prepare,
.hw_params = msm_dai_q6_mi2s_hw_params,
+ .hw_free = msm_dai_q6_mi2s_hw_free,
.set_fmt = msm_dai_q6_mi2s_set_fmt,
.shutdown = msm_dai_q6_mi2s_shutdown,
};
diff --git a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
index 63ac5d3..161904c 100644
--- a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
+++ b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
@@ -211,6 +211,14 @@
DOLBY_ENDDEP_PARAM_VMB_OFFSET},
{-320, -320, 144}
},
+ {PROXY, 6, DOLBY_ENDP_EXT_SPEAKERS,
+ {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+ {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+ DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+ {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+ DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+ {-320, -320, 144}
+ },
{FM, 2, DOLBY_ENDP_HDMI,
{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
@@ -409,7 +417,8 @@
for (idx = 0; idx < NUM_DOLBY_ENDP_DEVICE; idx++) {
if (dolby_dap_endp_params[idx].device ==
dolby_dap_params_states.device) {
- if (dolby_dap_params_states.device == AUX_DIGITAL) {
+ if (dolby_dap_params_states.device == AUX_DIGITAL ||
+ dolby_dap_params_states.device == PROXY) {
if (dolby_dap_endp_params[idx].device_ch_caps ==
device_channels)
break;
diff --git a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.h b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.h
index 4544fea..14586f4 100644
--- a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.h
+++ b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.h
@@ -249,7 +249,7 @@
#define DOLBY_AUTO_ENDDEP_IDX (MAX_DOLBY_PARAMS+4)
#define TOTAL_LENGTH_DOLBY_PARAM 745
-#define NUM_DOLBY_ENDP_DEVICE 23
+#define NUM_DOLBY_ENDP_DEVICE 24
#define DOLBY_VIS_PARAM_HEADER_SIZE 25
#define DOLBY_INVALID_PORT_ID -1
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 4aa1bce..8e69a2b 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -688,6 +688,8 @@
session_id = voc_get_session_id(VOICE_SESSION_NAME);
else if (val == MSM_FRONTEND_DAI_VOLTE)
session_id = voc_get_session_id(VOLTE_SESSION_NAME);
+ else if (val == MSM_FRONTEND_DAI_VOWLAN)
+ session_id = voc_get_session_id(VOWLAN_SESSION_NAME);
else if (val == MSM_FRONTEND_DAI_VOICE2)
session_id = voc_get_session_id(VOICE2_SESSION_NAME);
else if (val == MSM_FRONTEND_DAI_QCHAT)
@@ -2110,6 +2112,9 @@
SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_PRI_I2S_RX,
MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_PRI_I2S_RX,
MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
@@ -2131,6 +2136,9 @@
SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_SEC_I2S_RX,
MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SEC_I2S_RX,
MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
@@ -2152,6 +2160,9 @@
SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
@@ -2176,6 +2187,9 @@
SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_SLIMBUS_0_RX ,
MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_SLIMBUS_0_RX ,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SLIMBUS_0_RX ,
MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
@@ -2200,6 +2214,9 @@
SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_INT_BT_SCO_RX ,
MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_INT_BT_SCO_RX ,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_INT_BT_SCO_RX ,
MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
@@ -2224,6 +2241,9 @@
SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_MI2S_RX,
MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_MI2S_RX,
MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
@@ -2248,6 +2268,9 @@
SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_AFE_PCM_RX,
MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_AFE_PCM_RX,
MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
@@ -2272,6 +2295,9 @@
SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_AUXPCM_RX,
MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_AUXPCM_RX,
MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
@@ -2293,6 +2319,9 @@
SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
@@ -2314,6 +2343,9 @@
SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_HDMI_RX,
MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_HDMI_RX,
MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
msm_routing_put_voice_stub_mixer),
@@ -2418,6 +2450,33 @@
msm_routing_put_voice_mixer),
};
+static const struct snd_kcontrol_new tx_vowlan_mixer_controls[] = {
+ SOC_SINGLE_EXT("PRI_TX_VoWLAN", MSM_BACKEND_DAI_PRI_I2S_TX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SLIM_0_TX_VoWLAN", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX_VoWLAN",
+ MSM_BACKEND_DAI_INT_BT_SCO_TX, MSM_FRONTEND_DAI_VOWLAN, 1, 0,
+ msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX_VoWLAN", MSM_BACKEND_DAI_AFE_PCM_TX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_TX_VoWLAN", MSM_BACKEND_DAI_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_TX_VoWLAN", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("MI2S_TX_VoWLAN", MSM_BACKEND_DAI_MI2S_TX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX_VoWLAN", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
static const struct snd_kcontrol_new tx_voip_mixer_controls[] = {
SOC_SINGLE_EXT("PRI_TX_Voip", MSM_BACKEND_DAI_PRI_I2S_TX,
MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
@@ -3156,6 +3215,8 @@
SND_SOC_DAPM_AIF_OUT("VOICE2_UL", "Voice2 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("VoLTE_DL", "VoLTE Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("VoLTE_UL", "VoLTE Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("VoWLAN_DL", "VoWLAN Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("VoWLAN_UL", "VoWLAN Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("VOIP_UL", "VoIP Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("SLIM0_DL_HL", "SLIMBUS0_HOSTLESS Playback",
0, 0, 0, 0),
@@ -3425,6 +3486,9 @@
SND_SOC_DAPM_MIXER("VoLTE_Tx Mixer",
SND_SOC_NOPM, 0, 0, tx_volte_mixer_controls,
ARRAY_SIZE(tx_volte_mixer_controls)),
+ SND_SOC_DAPM_MIXER("VoWLAN_Tx Mixer",
+ SND_SOC_NOPM, 0, 0, tx_vowlan_mixer_controls,
+ ARRAY_SIZE(tx_vowlan_mixer_controls)),
SND_SOC_DAPM_MIXER("INTERNAL_BT_SCO_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
int_bt_sco_rx_mixer_controls, ARRAY_SIZE(int_bt_sco_rx_mixer_controls)),
SND_SOC_DAPM_MIXER("INTERNAL_FM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
@@ -3706,6 +3770,7 @@
{"PRI_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"PRI_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
{"PRI_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"PRI_RX_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
{"PRI_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"PRI_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"PRI_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
@@ -3714,6 +3779,7 @@
{"SEC_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"SEC_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
{"SEC_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"SEC_RX_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
{"SEC_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"SEC_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"SEC_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
@@ -3722,6 +3788,7 @@
{"SEC_MI2S_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"SEC_MI2S_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
{"SEC_MI2S_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"SEC_MI2S_RX_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
{"SEC_MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"SEC_MI2S_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"SEC_MI2S_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
@@ -3730,6 +3797,7 @@
{"SLIM_0_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"SLIM_0_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
{"SLIM_0_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"SLIM_0_RX_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
{"SLIM_0_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"SLIM_0_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"SLIM_0_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
@@ -3739,6 +3807,7 @@
{"INTERNAL_BT_SCO_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"INTERNAL_BT_SCO_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
{"INTERNAL_BT_SCO_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"INTERNAL_BT_SCO_RX_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
{"INTERNAL_BT_SCO_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"INTERNAL_BT_SCO_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"INTERNAL_BT_SCO_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
@@ -3747,6 +3816,7 @@
{"AFE_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"AFE_PCM_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
{"AFE_PCM_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"AFE_PCM_RX_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
{"AFE_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"AFE_PCM_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"AFE_PCM_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
@@ -3755,6 +3825,7 @@
{"AUX_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"AUX_PCM_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
{"AUX_PCM_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"AUX_PCM_RX_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
{"AUX_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"AUX_PCM_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"AUX_PCM_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
@@ -3763,6 +3834,7 @@
{"SEC_AUX_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"SEC_AUX_PCM_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"SEC_AUX_PCM_RX_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
{"SEC_AUX_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"SEC_AUX_PCM_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"SEC_AUX_PCM_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
@@ -3772,6 +3844,7 @@
{"HDMI_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"HDMI_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
{"HDMI_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"HDMI_RX_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
{"HDMI_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"HDMI_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"HDMI_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
@@ -3782,6 +3855,7 @@
{"MI2S_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
{"MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"MI2S_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"MI2S_RX_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
{"MI2S_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
{"MI2S_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
{"MI2S_RX", NULL, "MI2S_RX_Voice Mixer"},
@@ -3819,6 +3893,16 @@
{"VoLTE_Tx Mixer", "SEC_AUX_PCM_TX_VoLTE", "SEC_AUX_PCM_TX"},
{"VoLTE_Tx Mixer", "MI2S_TX_VoLTE", "MI2S_TX"},
{"VoLTE_UL", NULL, "VoLTE_Tx Mixer"},
+
+ {"VoWLAN_Tx Mixer", "PRI_TX_VoWLAN", "PRI_I2S_TX"},
+ {"VoWLAN_Tx Mixer", "SLIM_0_TX_VoWLAN", "SLIMBUS_0_TX"},
+ {"VoWLAN_Tx Mixer", "INTERNAL_BT_SCO_TX_VoWLAN", "INT_BT_SCO_TX"},
+ {"VoWLAN_Tx Mixer", "AFE_PCM_TX_VoWLAN", "PCM_TX"},
+ {"VoWLAN_Tx Mixer", "AUX_PCM_TX_VoWLAN", "AUX_PCM_TX"},
+ {"VoWLAN_Tx Mixer", "SEC_AUX_PCM_TX_VoWLAN", "SEC_AUX_PCM_TX"},
+ {"VoWLAN_Tx Mixer", "MI2S_TX_VoWLAN", "MI2S_TX"},
+ {"VoWLAN_UL", NULL, "VoWLAN_Tx Mixer"},
+
{"Voip_Tx Mixer", "PRI_TX_Voip", "PRI_I2S_TX"},
{"Voip_Tx Mixer", "MI2S_TX_Voip", "MI2S_TX"},
{"Voip_Tx Mixer", "SLIM_0_TX_Voip", "SLIMBUS_0_TX"},
@@ -4183,7 +4267,7 @@
path_type,
bedai->sample_rate,
channels,
- topology, false,
+ topology, fe_dai_perf_mode[i][session_type],
bits_per_sample);
}
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
index f2b0436..87e44b2 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
@@ -89,6 +89,7 @@
MSM_FRONTEND_DAI_LSM6,
MSM_FRONTEND_DAI_LSM7,
MSM_FRONTEND_DAI_LSM8,
+ MSM_FRONTEND_DAI_VOWLAN,
MSM_FRONTEND_DAI_MAX,
};
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
index 1074d76..fac5845 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
@@ -75,6 +75,14 @@
return false;
}
+static bool is_vowlan(struct msm_voice *pvowlan)
+{
+ if (pvowlan == &voice_info[VOWLAN_SESSION_INDEX])
+ return true;
+ else
+ return false;
+}
+
static uint32_t get_session_id(struct msm_voice *pvoc)
{
uint32_t session_id = 0;
@@ -85,6 +93,8 @@
session_id = voc_get_session_id(VOICE2_SESSION_NAME);
else if (is_qchat(pvoc))
session_id = voc_get_session_id(QCHAT_SESSION_NAME);
+ else if (is_vowlan(pvoc))
+ session_id = voc_get_session_id(VOWLAN_SESSION_NAME);
else
session_id = voc_get_session_id(VOICE_SESSION_NAME);
@@ -134,6 +144,10 @@
voice = &voice_info[QCHAT_SESSION_INDEX];
pr_debug("%s: Open QCHAT Substream Id=%s\n",
__func__, substream->pcm->id);
+ } else if (!strncmp("VoWLAN", substream->pcm->id, 6)) {
+ voice = &voice_info[VOWLAN_SESSION_INDEX];
+ pr_debug("%s: Open VoWLAN Substream Id=%s\n",
+ __func__, substream->pcm->id);
} else {
voice = &voice_info[VOICE_SESSION_INDEX];
pr_debug("%s: Open VOICE Substream Id=%s\n",
@@ -448,6 +462,7 @@
voc_set_tty_mode(voc_get_session_id(VOICE_SESSION_NAME), tty_mode);
voc_set_tty_mode(voc_get_session_id(VOICE2_SESSION_NAME), tty_mode);
voc_set_tty_mode(voc_get_session_id(VOLTE_SESSION_NAME), tty_mode);
+ voc_set_tty_mode(voc_get_session_id(VOWLAN_SESSION_NAME), tty_mode);
return 0;
}
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h
index f199be6..62c5732 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 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
@@ -18,6 +18,7 @@
VOLTE_SESSION_INDEX,
VOICE2_SESSION_INDEX,
QCHAT_SESSION_INDEX,
+ VOWLAN_SESSION_INDEX,
VOICE_SESSION_INDEX_MAX,
};
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 74b79dd..c36b53a 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -2505,8 +2505,35 @@
/* Support for selecting stereo mixing coefficients for B family not done */
int q6asm_cfg_aac_sel_mix_coef(struct audio_client *ac, uint32_t mix_coeff)
{
- /* To Be Done */
+ struct asm_aac_stereo_mix_coeff_selection_param_v2 aac_mix_coeff;
+ int rc = 0;
+
+ q6asm_add_hdr(ac, &aac_mix_coeff.hdr, sizeof(aac_mix_coeff), TRUE);
+ aac_mix_coeff.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+ aac_mix_coeff.param_id =
+ ASM_PARAM_ID_AAC_STEREO_MIX_COEFF_SELECTION_FLAG_V2;
+ aac_mix_coeff.param_size =
+ sizeof(struct asm_aac_stereo_mix_coeff_selection_param_v2);
+ aac_mix_coeff.aac_stereo_mix_coeff_flag = mix_coeff;
+ pr_debug("%s, mix_coeff = %u", __func__, mix_coeff);
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &aac_mix_coeff);
+ if (rc < 0) {
+ pr_err("%s:Command opcode[0x%x]paramid[0x%x] failed\n",
+ __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM,
+ ASM_PARAM_ID_AAC_STEREO_MIX_COEFF_SELECTION_FLAG_V2);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s:timeout opcode[0x%x]\n",
+ __func__, aac_mix_coeff.hdr.opcode);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
return 0;
+fail_cmd:
+ return rc;
}
int q6asm_enc_cfg_blk_qcelp(struct audio_client *ac, uint32_t frames_per_buf,
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index 61a262f..ac8b018 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -141,6 +141,7 @@
case VOLTE_SESSION_VSID:
case VOIP_SESSION_VSID:
case QCHAT_SESSION_VSID:
+ case VOWLAN_SESSION_VSID:
case ALL_SESSION_VSID:
ret = true;
break;
@@ -234,6 +235,9 @@
} else if (session_id ==
common.voice[VOC_PATH_QCHAT_PASSIVE].session_id) {
session_name = QCHAT_SESSION_NAME;
+ } else if (session_id ==
+ common.voice[VOC_PATH_VOWLAN_PASSIVE].session_id) {
+ session_name = VOWLAN_SESSION_NAME;
} else if (session_id == common.voice[VOC_PATH_FULL].session_id) {
session_name = VOIP_SESSION_NAME;
}
@@ -256,6 +260,9 @@
else if (!strncmp(name, "QCHAT session", 13))
session_id =
common.voice[VOC_PATH_QCHAT_PASSIVE].session_id;
+ else if (!strncmp(name, "VoWLAN session", 14))
+ session_id =
+ common.voice[VOC_PATH_VOWLAN_PASSIVE].session_id;
else
session_id = common.voice[VOC_PATH_FULL].session_id;
@@ -291,6 +298,10 @@
v = &common.voice[VOC_PATH_QCHAT_PASSIVE];
break;
+ case VOWLAN_SESSION_VSID:
+ v = &common.voice[VOC_PATH_VOWLAN_PASSIVE];
+ break;
+
case ALL_SESSION_VSID:
break;
@@ -331,6 +342,10 @@
idx = VOC_PATH_QCHAT_PASSIVE;
break;
+ case VOWLAN_SESSION_VSID:
+ idx = VOC_PATH_VOWLAN_PASSIVE;
+ break;
+
case ALL_SESSION_VSID:
idx = MAX_VOC_SESSIONS - 1;
break;
@@ -375,6 +390,11 @@
return (session_id == common.voice[VOC_PATH_QCHAT_PASSIVE].session_id);
}
+static bool is_vowlan_session(u32 session_id)
+{
+ return (session_id == common.voice[VOC_PATH_VOWLAN_PASSIVE].session_id);
+}
+
static bool is_voc_state_active(int voc_state)
{
if ((voc_state == VOC_RUN) ||
@@ -433,6 +453,7 @@
common.voice[VOC_PATH_VOICE2_PASSIVE].session_id = VOICE2_SESSION_VSID;
common.voice[VOC_PATH_FULL].session_id = VOIP_SESSION_VSID;
common.voice[VOC_PATH_QCHAT_PASSIVE].session_id = QCHAT_SESSION_VSID;
+ common.voice[VOC_PATH_VOWLAN_PASSIVE].session_id = VOWLAN_SESSION_VSID;
}
static int voice_apr_register(void)
@@ -661,6 +682,10 @@
strlcpy(mvm_session_cmd.mvm_session.name,
QCHAT_SESSION_VSID_STR,
sizeof(mvm_session_cmd.mvm_session.name));
+ } else if (is_vowlan_session(v->session_id)) {
+ strlcpy(mvm_session_cmd.mvm_session.name,
+ VOWLAN_SESSION_VSID_STR,
+ sizeof(mvm_session_cmd.mvm_session.name));
} else {
strlcpy(mvm_session_cmd.mvm_session.name,
"default modem voice",
@@ -753,6 +778,10 @@
strlcpy(cvs_session_cmd.cvs_session.name,
QCHAT_SESSION_VSID_STR,
sizeof(cvs_session_cmd.cvs_session.name));
+ } else if (is_vowlan_session(v->session_id)) {
+ strlcpy(cvs_session_cmd.cvs_session.name,
+ VOWLAN_SESSION_VSID_STR,
+ sizeof(cvs_session_cmd.cvs_session.name));
} else {
strlcpy(cvs_session_cmd.cvs_session.name,
"default modem voice",
diff --git a/sound/soc/msm/qdsp6v2/q6voice.h b/sound/soc/msm/qdsp6v2/q6voice.h
index 9efc9fc..59c86cd 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.h
+++ b/sound/soc/msm/qdsp6v2/q6voice.h
@@ -1319,7 +1319,7 @@
void *buf;
};
-#define MAX_VOC_SESSIONS 5
+#define MAX_VOC_SESSIONS 6
struct common_data {
/* these default values are for all devices */
@@ -1393,21 +1393,25 @@
#define VOC_PATH_VOLTE_PASSIVE 2
#define VOC_PATH_VOICE2_PASSIVE 3
#define VOC_PATH_QCHAT_PASSIVE 4
+#define VOC_PATH_VOWLAN_PASSIVE 5
#define MAX_SESSION_NAME_LEN 32
-#define VOICE_SESSION_NAME "Voice session"
-#define VOIP_SESSION_NAME "VoIP session"
-#define VOLTE_SESSION_NAME "VoLTE session"
-#define VOICE2_SESSION_NAME "Voice2 session"
-#define QCHAT_SESSION_NAME "QCHAT session"
+#define VOICE_SESSION_NAME "Voice session"
+#define VOIP_SESSION_NAME "VoIP session"
+#define VOLTE_SESSION_NAME "VoLTE session"
+#define VOICE2_SESSION_NAME "Voice2 session"
+#define QCHAT_SESSION_NAME "QCHAT session"
+#define VOWLAN_SESSION_NAME "VoWLAN session"
#define VOICE2_SESSION_VSID_STR "10DC1000"
#define QCHAT_SESSION_VSID_STR "10803000"
+#define VOWLAN_SESSION_VSID_STR "10002000"
#define VOICE_SESSION_VSID 0x10C01000
#define VOICE2_SESSION_VSID 0x10DC1000
#define VOLTE_SESSION_VSID 0x10C02000
#define VOIP_SESSION_VSID 0x10004000
#define QCHAT_SESSION_VSID 0x10803000
+#define VOWLAN_SESSION_VSID 0x10002000
#define ALL_SESSION_VSID 0xFFFFFFFF
#define VSID_MAX ALL_SESSION_VSID