summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/usb/msm-ssusb.txt2
-rw-r--r--arch/arm/boot/dts/qcom/msm8996-cdp.dtsi1
-rw-r--r--arch/arm/boot/dts/qcom/msm8996-mtp.dtsi1
-rw-r--r--arch/arm/boot/dts/qcom/msm8996.dtsi1
-rw-r--r--drivers/char/diag/diagfwd.c10
-rw-r--r--drivers/i2c/busses/Kconfig6
-rw-r--r--drivers/i2c/busses/Makefile1
-rw-r--r--drivers/i2c/busses/virtio-i2c.c356
-rw-r--r--drivers/net/wireless/cnss2/pci.c6
-rw-r--r--drivers/net/wireless/cnss2/usb.c6
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c36
-rw-r--r--drivers/soc/qcom/hab/ghs_comm.c33
-rw-r--r--drivers/soc/qcom/hab/hab.c213
-rw-r--r--drivers/soc/qcom/hab/hab.h21
-rw-r--r--drivers/soc/qcom/hab/hab_ghs.c4
-rw-r--r--drivers/soc/qcom/hab/hab_mem_linux.c3
-rw-r--r--drivers/soc/qcom/hab/hab_mimex.c77
-rw-r--r--drivers/soc/qcom/hab/hab_msg.c44
-rw-r--r--drivers/soc/qcom/hab/hab_open.c50
-rw-r--r--drivers/soc/qcom/hab/hab_parser.c7
-rw-r--r--drivers/soc/qcom/hab/hab_pchan.c9
-rw-r--r--drivers/soc/qcom/hab/hab_stat.c57
-rw-r--r--drivers/soc/qcom/hab/hab_vchan.c30
-rw-r--r--drivers/soc/qcom/hab/khab.c4
-rw-r--r--drivers/usb/dwc3/dwc3-msm.c27
-rw-r--r--drivers/usb/phy/phy-msm-qusb.c332
-rw-r--r--include/linux/usb/phy.h12
-rw-r--r--include/uapi/linux/virtio_ids.h2
-rw-r--r--net/core/sockev_nlmcast.c10
-rw-r--r--sound/soc/msm/msm8998.c1774
-rw-r--r--sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c184
-rw-r--r--sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c14
-rw-r--r--sound/soc/msm/qdsp6v2/q6afe.c15
33 files changed, 2927 insertions, 421 deletions
diff --git a/Documentation/devicetree/bindings/usb/msm-ssusb.txt b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
index 54792335e67e..a8229051cbd8 100644
--- a/Documentation/devicetree/bindings/usb/msm-ssusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
@@ -66,6 +66,8 @@ Optional properties :
which is used as a vote by driver to get max performance in perf mode.
- qcom,no-wakeup-src-in-hostmode: If present then driver doesn't use wakeup_source APIs
in host mode. This allows PM suspend to happen irrespective of runtimePM state of host.
+- qcom,check-for-float: If present, the driver will always check for possible
+ float connection irrespective of the charger type.
Sub nodes:
- Sub node for "DWC3- USB3 controller".
diff --git a/arch/arm/boot/dts/qcom/msm8996-cdp.dtsi b/arch/arm/boot/dts/qcom/msm8996-cdp.dtsi
index 9f480a4f5388..3988953f6963 100644
--- a/arch/arm/boot/dts/qcom/msm8996-cdp.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8996-cdp.dtsi
@@ -787,6 +787,7 @@
&usb3 {
extcon = <&pmi8994_charger>;
+ qcom,check-for-float;
};
&usb2s {
diff --git a/arch/arm/boot/dts/qcom/msm8996-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8996-mtp.dtsi
index 45d0233f8ce7..d3350deba5d2 100644
--- a/arch/arm/boot/dts/qcom/msm8996-mtp.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8996-mtp.dtsi
@@ -511,6 +511,7 @@
&usb3 {
extcon = <&pmi8994_charger>;
+ qcom,check-for-float;
};
&i2c_7 {
diff --git a/arch/arm/boot/dts/qcom/msm8996.dtsi b/arch/arm/boot/dts/qcom/msm8996.dtsi
index 62abceb7b5b1..fd49714e2a5c 100644
--- a/arch/arm/boot/dts/qcom/msm8996.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8996.dtsi
@@ -2177,6 +2177,7 @@
phy_type= "utmi";
qcom,phy-clk-scheme = "cmos";
qcom,major-rev = <1>;
+ qcom,enable-dpdm-pulsing;
clocks = <&clock_gcc clk_gcc_usb_phy_cfg_ahb2phy_clk>,
<&clock_gcc clk_ln_bb_clk>;
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 75c68c903371..711da56468df 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -1648,7 +1648,7 @@ void diag_process_non_hdlc_pkt(unsigned char *buf, int len, int pid)
if (*(uint8_t *)(data_ptr + actual_pkt->length) !=
CONTROL_CHAR) {
mutex_unlock(&driver->hdlc_recovery_mutex);
- diag_hdlc_start_recovery(buf, len, pid);
+ diag_hdlc_start_recovery(buf, (len - read_bytes), pid);
mutex_lock(&driver->hdlc_recovery_mutex);
}
err = diag_process_apps_pkt(data_ptr,
@@ -1674,8 +1674,8 @@ start:
pkt_len = actual_pkt->length;
if (actual_pkt->start != CONTROL_CHAR) {
- diag_hdlc_start_recovery(buf, len, pid);
- diag_send_error_rsp(buf, len, pid);
+ diag_hdlc_start_recovery(buf, (len - read_bytes), pid);
+ diag_send_error_rsp(buf, (len - read_bytes), pid);
goto end;
}
mutex_lock(&driver->hdlc_recovery_mutex);
@@ -1683,7 +1683,7 @@ start:
pr_err("diag: In %s, incoming data is too large for the request buffer %d\n",
__func__, pkt_len);
mutex_unlock(&driver->hdlc_recovery_mutex);
- diag_hdlc_start_recovery(buf, len, pid);
+ diag_hdlc_start_recovery(buf, (len - read_bytes), pid);
break;
}
if ((pkt_len + header_len) > (len - read_bytes)) {
@@ -1700,7 +1700,7 @@ start:
if (*(uint8_t *)(data_ptr + actual_pkt->length) !=
CONTROL_CHAR) {
mutex_unlock(&driver->hdlc_recovery_mutex);
- diag_hdlc_start_recovery(buf, len, pid);
+ diag_hdlc_start_recovery(buf, (len - read_bytes), pid);
mutex_lock(&driver->hdlc_recovery_mutex);
}
else
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 5b57c7edbc72..151e9c039957 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -1209,5 +1209,11 @@ config I2C_MSM_V2
This driver can also be built as a module. If so, the module
will be called i2c-msm-v2.
+config VIRTIO_I2C
+ tristate "VIRTIO_I2C"
+ depends on VIRTIO
+ help
+ If you say yes to this option, the virtio i2c will be
+ supported.
endmenu
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 0c9891812aa8..47e5ed02ea7f 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -97,6 +97,7 @@ obj-$(CONFIG_I2C_XLR) += i2c-xlr.o
obj-$(CONFIG_I2C_XLP9XX) += i2c-xlp9xx.o
obj-$(CONFIG_I2C_RCAR) += i2c-rcar.o
obj-$(CONFIG_I2C_MSM_V2) += i2c-msm-v2.o
+obj-$(CONFIG_VIRTIO_I2C) += virtio-i2c.o
# External I2C/SMBus adapter drivers
obj-$(CONFIG_I2C_DIOLAN_U2C) += i2c-diolan-u2c.o
diff --git a/drivers/i2c/busses/virtio-i2c.c b/drivers/i2c/busses/virtio-i2c.c
new file mode 100644
index 000000000000..95c35541c295
--- /dev/null
+++ b/drivers/i2c/busses/virtio-i2c.c
@@ -0,0 +1,356 @@
+/* Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/idr.h>
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/spinlock.h>
+#include <linux/virtio.h>
+#include <uapi/linux/virtio_ids.h>
+#include <linux/virtio_config.h>
+#include <linux/i2c.h>
+
+#define I2C_ADAPTER_NR 0x00
+
+#define I2C_VIRTIO_RD 0x01
+#define I2C_VIRTIO_WR 0x02
+#define I2C_VIRTIO_RDWR 0x03
+
+/**
+ * struct virtio_i2c - virtio i2c device
+ * @adapter: i2c adapter
+ * @vdev: the virtio device
+ * @vq: i2c virtqueue
+ */
+struct virtio_i2c {
+ struct i2c_adapter adapter;
+ struct virtio_device *vdev;
+ struct virtqueue *vq;
+ wait_queue_head_t inq;
+};
+
+struct i2c_transfer_head {
+ u32 type; /* read or write from or to slave */
+ u32 addr; /* slave addr */
+ u32 length; /* buffer length */
+ u32 total_length; /* merge write and read will use this segment */
+};
+
+struct i2c_transfer_end {
+ u32 result; /* return value from backend */
+};
+
+struct virtio_i2c_req {
+ struct i2c_transfer_head head;
+ char *buf;
+ struct i2c_transfer_end end;
+};
+
+static int virti2c_transfer(struct virtio_i2c *vi2c,
+ struct virtio_i2c_req *i2c_req)
+{
+ struct virtqueue *vq = vi2c->vq;
+ struct scatterlist outhdr, bufhdr, inhdr, *sgs[3];
+ unsigned int num_out = 0, num_in = 0, err, len;
+ struct virtio_i2c_req *req_handled = NULL;
+
+ /* send the head queue to the backend */
+ sg_init_one(&outhdr, &i2c_req->head, sizeof(i2c_req->head));
+ sgs[num_out++] = &outhdr;
+
+ /* send the buffer queue to the backend */
+ sg_init_one(&bufhdr, i2c_req->buf,
+ (i2c_req->head.type == I2C_VIRTIO_RDWR) ?
+ i2c_req->head.total_length : i2c_req->head.length);
+ if (i2c_req->head.type & I2C_VIRTIO_WR)
+ sgs[num_out++] = &bufhdr;
+ else
+ sgs[num_out + num_in++] = &bufhdr;
+
+ /* send the result queue to the backend */
+ sg_init_one(&inhdr, &i2c_req->end, sizeof(i2c_req->end));
+ sgs[num_out + num_in++] = &inhdr;
+
+ /* call the virtqueue function */
+ err = virtqueue_add_sgs(vq, sgs, num_out, num_in, i2c_req, GFP_KERNEL);
+ if (err)
+ goto req_exit;
+
+ /* Tell Host to go! */
+ err = virtqueue_kick(vq);
+
+ wait_event(vi2c->inq,
+ (req_handled = virtqueue_get_buf(vq, &len)));
+
+ if (i2c_req->head.type == I2C_VIRTIO_RDWR) {
+ if (i2c_req->end.result ==
+ i2c_req->head.total_length - i2c_req->head.length)
+ err = 0;
+ else
+ err = -EINVAL;
+ } else {
+ if (i2c_req->end.result == i2c_req->head.length)
+ err = 0;
+ else
+ err = -EINVAL;
+ }
+req_exit:
+ return err;
+}
+
+/* prepare the transfer req */
+static struct virtio_i2c_req *virti2c_transfer_prepare(struct i2c_msg *msg_1,
+ struct i2c_msg *msg_2)
+{
+ char *ptr = NULL;
+ int merge = 0;
+ struct virtio_i2c_req *i2c_req;
+
+ if (msg_1 == NULL)
+ return NULL;
+
+ if (msg_2)
+ merge = 1;
+
+ i2c_req = kzalloc(sizeof(struct virtio_i2c_req), GFP_KERNEL);
+ if (i2c_req == NULL)
+ return NULL;
+
+ if (merge)
+ ptr = kzalloc((msg_1->len + msg_2->len), GFP_KERNEL);
+ else
+ ptr = msg_1->buf;
+ if (ptr == NULL)
+ goto err_mem;
+
+ /* prepare the head */
+ i2c_req->head.type = merge ?
+ I2C_VIRTIO_RDWR : ((msg_1->flags & I2C_M_RD) ?
+ I2C_VIRTIO_RD : I2C_VIRTIO_WR);
+ i2c_req->head.addr = msg_1->addr;
+ i2c_req->head.length = msg_1->len;
+ if (merge)
+ i2c_req->head.total_length = msg_1->len + msg_2->len;
+
+ /* prepare the buf */
+ if (merge)
+ memcpy(ptr, msg_1->buf, msg_1->len);
+ i2c_req->buf = ptr;
+
+ return i2c_req;
+err_mem:
+ kfree(i2c_req);
+ i2c_req = NULL;
+ return NULL;
+}
+
+static void virti2c_transfer_end(struct virtio_i2c_req *req,
+ struct i2c_msg *msg)
+{
+ if (req->head.type == I2C_VIRTIO_RDWR) {
+ memcpy(msg->buf, req->buf + req->head.length, msg->len);
+ kfree(req->buf);
+ req->buf = NULL;
+ }
+
+ kfree(req);
+ req = NULL;
+}
+
+static int virtio_i2c_master_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs, int num)
+{
+ int i, ret;
+ struct virtio_i2c_req *i2c_req;
+ struct virtio_i2c *vi2c = i2c_get_adapdata(adap);
+
+ if (num < 1) {
+ dev_err(&vi2c->vdev->dev,
+ "error on number of msgs(%d) received\n", num);
+ return -EINVAL;
+ }
+
+ if (IS_ERR_OR_NULL(msgs)) {
+ dev_err(&vi2c->vdev->dev, " error no msgs Accessing invalid pointer location\n");
+ return PTR_ERR(msgs);
+ }
+
+ for (i = 0; i < num; i++) {
+
+ if (msgs[i].flags & I2C_M_RD) {
+ /* read the data from slave to master*/
+ i2c_req = virti2c_transfer_prepare(&msgs[i], NULL);
+
+ } else if ((i + 1 < num) && (msgs[i + 1].flags & I2C_M_RD) &&
+ (msgs[i].addr == msgs[i + 1].addr)) {
+ /* write then read from same address*/
+ i2c_req = virti2c_transfer_prepare(&msgs[i],
+ &msgs[i+1]);
+ i += 1;
+
+ } else {
+ /* write the data to slave */
+ i2c_req = virti2c_transfer_prepare(&msgs[i], NULL);
+ }
+
+ if (i2c_req == NULL) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ ret = virti2c_transfer(vi2c, i2c_req);
+ virti2c_transfer_end(i2c_req, &msgs[i]);
+ if (ret)
+ goto err;
+ }
+ return num;
+err:
+ return ret;
+}
+
+static u32 virtio_i2c_functionality(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm virtio_i2c_algorithm = {
+ .master_xfer = virtio_i2c_master_xfer,
+ .functionality = virtio_i2c_functionality,
+};
+
+/* virtqueue incoming data interrupt IRQ */
+static void virti2c_vq_isr(struct virtqueue *vq)
+{
+ struct virtio_i2c *vi2c = vq->vdev->priv;
+
+ wake_up(&vi2c->inq);
+}
+
+static int virti2c_init_vqs(struct virtio_i2c *vi2c)
+{
+ struct virtqueue *vqs[1];
+ vq_callback_t *cbs[] = { virti2c_vq_isr };
+ static const char * const names[] = { "virti2c_vq_isr" };
+ int err;
+
+ err = vi2c->vdev->config->find_vqs(vi2c->vdev, 1, vqs, cbs, names);
+ if (err)
+ return err;
+ vi2c->vq = vqs[0];
+
+ return 0;
+}
+
+static void virti2c_del_vqs(struct virtio_i2c *vi2c)
+{
+ vi2c->vdev->config->del_vqs(vi2c->vdev);
+}
+
+static int virti2c_init_hw(struct virtio_device *vdev,
+ struct virtio_i2c *vi2c)
+{
+ int err;
+
+ i2c_set_adapdata(&vi2c->adapter, vi2c);
+ vi2c->adapter.algo = &virtio_i2c_algorithm;
+
+ vi2c->adapter.owner = THIS_MODULE;
+ vi2c->adapter.dev.parent = &vdev->dev;
+ vi2c->adapter.dev.of_node = vdev->dev.parent->of_node;
+
+ /* read virtio i2c config info */
+ vi2c->adapter.nr = virtio_cread32(vdev, I2C_ADAPTER_NR);
+ snprintf(vi2c->adapter.name, sizeof(vi2c->adapter.name),
+ "virtio_i2c_%d", vi2c->adapter.nr);
+
+ err = i2c_add_numbered_adapter(&vi2c->adapter);
+ if (err)
+ return err;
+ return 0;
+}
+
+static int virti2c_probe(struct virtio_device *vdev)
+{
+ struct virtio_i2c *vi2c;
+ int err = 0;
+
+ if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1))
+ return -ENODEV;
+
+ vi2c = kzalloc(sizeof(*vi2c), GFP_KERNEL);
+ if (!vi2c)
+ return -ENOMEM;
+
+ vi2c->vdev = vdev;
+ vdev->priv = vi2c;
+ init_waitqueue_head(&vi2c->inq);
+
+ err = virti2c_init_vqs(vi2c);
+ if (err)
+ goto err_init_vq;
+
+ err = virti2c_init_hw(vdev, vi2c);
+ if (err)
+ goto err_init_hw;
+
+ virtio_device_ready(vdev);
+
+ virtqueue_enable_cb(vi2c->vq);
+ return 0;
+
+err_init_hw:
+ virti2c_del_vqs(vi2c);
+err_init_vq:
+ kfree(vi2c);
+ return err;
+}
+static void virti2c_remove(struct virtio_device *vdev)
+{
+ struct virtio_i2c *vi2c = vdev->priv;
+
+ i2c_del_adapter(&vi2c->adapter);
+ vdev->config->reset(vdev);
+ virti2c_del_vqs(vi2c);
+ kfree(vi2c);
+}
+
+static unsigned int features[] = {
+ /* none */
+};
+static struct virtio_device_id id_table[] = {
+ { VIRTIO_ID_I2C, VIRTIO_DEV_ANY_ID },
+ { 0 },
+};
+
+static struct virtio_driver virtio_i2c_driver = {
+ .driver.name = KBUILD_MODNAME,
+ .driver.owner = THIS_MODULE,
+ .feature_table = features,
+ .feature_table_size = ARRAY_SIZE(features),
+ .id_table = id_table,
+ .probe = virti2c_probe,
+ .remove = virti2c_remove,
+};
+
+module_virtio_driver(virtio_i2c_driver);
+MODULE_DEVICE_TABLE(virtio, id_table);
+
+MODULE_DESCRIPTION("Virtio i2c frontend driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c
index 3926023a1493..7dc419753a80 100644
--- a/drivers/net/wireless/cnss2/pci.c
+++ b/drivers/net/wireless/cnss2/pci.c
@@ -749,6 +749,12 @@ int cnss_wlan_register_driver(struct cnss_wlan_driver *driver_ops)
return -ENODEV;
}
+ if (plat_priv->bus_type != CNSS_BUS_PCI) {
+ cnss_pr_err("Wrong bus type. Expected bus_type %d\n",
+ plat_priv->bus_type);
+ return -EFAULT;
+ }
+
pci_priv = plat_priv->bus_priv;
if (!pci_priv) {
cnss_pr_err("pci_priv is NULL\n");
diff --git a/drivers/net/wireless/cnss2/usb.c b/drivers/net/wireless/cnss2/usb.c
index a15f967f986d..3d3932371b26 100644
--- a/drivers/net/wireless/cnss2/usb.c
+++ b/drivers/net/wireless/cnss2/usb.c
@@ -73,6 +73,12 @@ int cnss_usb_wlan_register_driver(struct cnss_usb_wlan_driver *driver_ops)
return -ENODEV;
}
+ if (plat_priv->bus_type != CNSS_BUS_USB) {
+ cnss_pr_err("Wrong bus type. Expected bus_type %d\n",
+ plat_priv->bus_type);
+ return -EFAULT;
+ }
+
usb_priv = plat_priv->bus_priv;
usb_priv->plat_priv = plat_priv;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c
index 6b90abf787b9..d8e128eee8cc 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2019, 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
@@ -779,7 +779,7 @@ int ipa3_qmi_ul_filter_request_send(
{
struct ipa_configure_ul_firewall_rules_resp_msg_v01 resp;
struct msg_desc req_desc, resp_desc;
- int rc;
+ int rc, i;
IPAWANDBG("IPACM pass %u rules to Q6\n",
req->firewall_rules_list_len);
@@ -799,6 +799,38 @@ int ipa3_qmi_ul_filter_request_send(
}
mutex_unlock(&ipa3_qmi_lock);
+ /* check if modem is up */
+ if (!ipa3_qmi_indication_fin ||
+ !ipa3_qmi_modem_init_fin ||
+ !ipa_q6_clnt) {
+ IPAWANDBG("modem QMI service is not up yet\n");
+ return -EINVAL;
+ }
+
+ /* Passing 0 rules means that firewall is disabled */
+ if (req->firewall_rules_list_len == 0)
+ IPAWANDBG("IPACM passed 0 rules to Q6\n");
+
+ if (req->firewall_rules_list_len >= QMI_IPA_MAX_UL_FIREWALL_RULES_V01) {
+ IPAWANERR(
+ "Number of rules passed by IPACM, %d, exceed limit %d\n",
+ req->firewall_rules_list_len,
+ QMI_IPA_MAX_UL_FIREWALL_RULES_V01);
+ return -EINVAL;
+ }
+
+ /* Check for valid IP type */
+ for (i = 0; i < req->firewall_rules_list_len; i++) {
+ if (req->firewall_rules_list[i].ip_type !=
+ QMI_IPA_IP_TYPE_V4_V01 &&
+ req->firewall_rules_list[i].ip_type !=
+ QMI_IPA_IP_TYPE_V6_V01) {
+ IPAWANERR("Invalid IP type %d\n",
+ req->firewall_rules_list[i].ip_type);
+ return -EINVAL;
+ }
+ }
+
req_desc.max_msg_len =
QMI_IPA_INSTALL_UL_FIREWALL_RULES_REQ_MAX_MSG_LEN_V01;
req_desc.msg_id = QMI_IPA_INSTALL_UL_FIREWALL_RULES_REQ_V01;
diff --git a/drivers/soc/qcom/hab/ghs_comm.c b/drivers/soc/qcom/hab/ghs_comm.c
index 1fdb1668295c..fbd579793879 100644
--- a/drivers/soc/qcom/hab/ghs_comm.c
+++ b/drivers/soc/qcom/hab/ghs_comm.c
@@ -20,19 +20,28 @@ int physical_channel_read(struct physical_channel *pchan,
{
struct ghs_vdev *dev = (struct ghs_vdev *)pchan->hyp_data;
+ if (!payload || !dev->read_data) {
+ pr_err("invalid parameters %pK %pK offset %d read %zd\n",
+ payload, dev->read_data, dev->read_offset, read_size);
+ return 0;
+ }
+
/* size in header is only for payload excluding the header itself */
- if (dev->read_size < read_size + sizeof(struct hab_header)) {
- pr_warn("read %zd is less than requested %zd plus header %zd\n",
- dev->read_size, read_size, sizeof(struct hab_header));
- read_size = dev->read_size;
+ if (dev->read_size < read_size + sizeof(struct hab_header) +
+ dev->read_offset) {
+ pr_warn("read %zd is less than requested %zd header %zd offset %d\n",
+ dev->read_size, read_size,
+ sizeof(struct hab_header), dev->read_offset);
+ read_size = dev->read_size - dev->read_offset -
+ sizeof(struct hab_header);
}
/* always skip the header */
memcpy(payload, (unsigned char *)dev->read_data +
sizeof(struct hab_header) + dev->read_offset, read_size);
- dev->read_offset += read_size;
+ dev->read_offset += (int)read_size;
- return read_size;
+ return (int)read_size;
}
int physical_channel_send(struct physical_channel *pchan,
@@ -41,8 +50,8 @@ int physical_channel_send(struct physical_channel *pchan,
{
size_t sizebytes = HAB_HEADER_GET_SIZE(*header);
struct ghs_vdev *dev = (struct ghs_vdev *)pchan->hyp_data;
- GIPC_Result result;
- uint8_t *msg;
+ GIPC_Result result = GIPC_Success;
+ uint8_t *msg = NULL;
spin_lock_bh(&dev->io_lock);
@@ -61,7 +70,7 @@ int physical_channel_send(struct physical_channel *pchan,
}
if (HAB_HEADER_GET_TYPE(*header) == HAB_PAYLOAD_TYPE_PROFILE) {
- struct timeval tv;
+ struct timeval tv = {0};
struct habmm_xing_vm_stat *pstat =
(struct habmm_xing_vm_stat *)payload;
@@ -90,11 +99,11 @@ int physical_channel_send(struct physical_channel *pchan,
void physical_channel_rx_dispatch(unsigned long physical_channel)
{
- struct hab_header header;
+ struct hab_header header = {0};
struct physical_channel *pchan =
(struct physical_channel *)physical_channel;
struct ghs_vdev *dev = (struct ghs_vdev *)pchan->hyp_data;
- GIPC_Result result;
+ GIPC_Result result = GIPC_Success;
uint32_t events;
unsigned long flags;
@@ -119,7 +128,7 @@ void physical_channel_rx_dispatch(unsigned long physical_channel)
dev->read_data,
GIPC_RECV_BUFF_SIZE_BYTES,
&dev->read_size,
- &header.id_type_size);
+ (uint32_t *)&header.id_type_size);
if (result == GIPC_Success || dev->read_size > 0) {
/* handle corrupted msg? */
diff --git a/drivers/soc/qcom/hab/hab.c b/drivers/soc/qcom/hab/hab.c
index b6dfe2d9ae22..f4fef27aeee1 100644
--- a/drivers/soc/qcom/hab/hab.c
+++ b/drivers/soc/qcom/hab/hab.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2019, 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
@@ -21,7 +21,7 @@
.openlock = __SPIN_LOCK_UNLOCKED(&hab_devices[__num__].openlock)\
}
-static const char hab_info_str[] = "Change: 17280941 Revision: #81";
+static const char hab_info_str[] = "Change: 19231400 Revision: #95";
/*
* The following has to match habmm definitions, order does not matter if
@@ -60,7 +60,7 @@ struct hab_driver hab_driver = {
struct uhab_context *hab_ctx_alloc(int kernel)
{
- struct uhab_context *ctx;
+ struct uhab_context *ctx = NULL;
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx)
@@ -79,6 +79,9 @@ struct uhab_context *hab_ctx_alloc(int kernel)
rwlock_init(&ctx->exp_lock);
rwlock_init(&ctx->ctx_lock);
+ INIT_LIST_HEAD(&ctx->forbidden_chans);
+ spin_lock_init(&ctx->forbidden_lock);
+
INIT_LIST_HEAD(&ctx->pending_open);
kref_init(&ctx->refcount);
ctx->import_ctx = habmem_imp_hyp_open();
@@ -106,18 +109,29 @@ void hab_ctx_free(struct kref *ref)
{
struct uhab_context *ctx =
container_of(ref, struct uhab_context, refcount);
- struct hab_export_ack_recvd *ack_recvd, *tmp;
- struct virtual_channel *vchan;
- struct physical_channel *pchan;
- int i;
- struct uhab_context *ctxdel, *ctxtmp;
- struct hab_open_node *node;
- struct export_desc *exp, *exp_tmp;
+ struct hab_export_ack_recvd *ack_recvd = NULL, *tmp = NULL;
+ struct virtual_channel *vchan = NULL;
+ struct physical_channel *pchan = NULL;
+ int i = 0;
+ struct uhab_context *ctxdel = NULL, *ctxtmp = NULL;
+ struct hab_open_node *node = NULL;
+ struct export_desc *exp = NULL, *exp_tmp = NULL;
+ struct hab_forbidden_node *forbidden = NULL, *forbidden_tmp = NULL;
+
+ spin_lock_bh(&ctx->forbidden_lock);
+ list_for_each_entry_safe(forbidden, forbidden_tmp,
+ &ctx->forbidden_chans, node) {
+ list_del(&forbidden->node);
+ pr_debug("Remove mmid 0x%x from forbidden list, ctx %p\n",
+ forbidden->mmid, ctx);
+ kfree(forbidden);
+ }
+ spin_unlock_bh(&ctx->forbidden_lock);
/* garbage-collect exp/imp buffers */
write_lock_bh(&ctx->exp_lock);
list_for_each_entry_safe(exp, exp_tmp, &ctx->exp_whse, node) {
- list_del(&exp->node);
+ list_del((struct list_head *)&exp->node);
pr_debug("potential leak exp %d vcid %X recovered\n",
exp->export_id, exp->vcid_local);
habmem_hyp_revoke(exp->payload, exp->payload_count);
@@ -127,7 +141,7 @@ void hab_ctx_free(struct kref *ref)
spin_lock_bh(&ctx->imp_lock);
list_for_each_entry_safe(exp, exp_tmp, &ctx->imp_whse, node) {
- list_del(&exp->node);
+ list_del((struct list_head *)&exp->node);
ctx->import_total--;
pr_debug("leaked imp %d vcid %X for ctx is collected total %d\n",
exp->export_id, exp->vcid_local,
@@ -211,7 +225,7 @@ void hab_ctx_free(struct kref *ref)
struct virtual_channel *hab_get_vchan_fromvcid(int32_t vcid,
struct uhab_context *ctx, int ignore_remote)
{
- struct virtual_channel *vchan;
+ struct virtual_channel *vchan = NULL;
read_lock(&ctx->ctx_lock);
list_for_each_entry(vchan, &ctx->vchannels, node) {
@@ -236,7 +250,7 @@ struct virtual_channel *hab_get_vchan_fromvcid(int32_t vcid,
struct hab_device *find_hab_device(unsigned int mm_id)
{
- int i;
+ int i = 0;
for (i = 0; i < hab_driver.ndevices; i++) {
if (hab_driver.devp[i].id == HAB_MMID_GET_MAJOR(mm_id))
@@ -259,13 +273,13 @@ struct virtual_channel *frontend_open(struct uhab_context *ctx,
unsigned int mm_id,
int dom_id)
{
- int ret, ret2, open_id = 0;
+ int ret = 0, ret2 = 0, open_id = 0;
struct physical_channel *pchan = NULL;
- struct hab_device *dev;
+ struct hab_device *dev = NULL;
struct virtual_channel *vchan = NULL;
static atomic_t open_id_counter = ATOMIC_INIT(0);
- struct hab_open_request request;
- struct hab_open_request *recv_request;
+ struct hab_open_request request = {0};
+ struct hab_open_request *recv_request = NULL;
int sub_id = HAB_MMID_GET_MINOR(mm_id);
struct hab_open_node pending_open = { { 0 } };
@@ -284,7 +298,7 @@ struct virtual_channel *frontend_open(struct uhab_context *ctx,
goto err;
}
- open_id = atomic_inc_return(&open_id_counter);
+ open_id = (int)atomic_inc_return(&open_id_counter);
vchan = hab_vchan_alloc(ctx, pchan, open_id);
if (!vchan) {
pr_err("vchan alloc failed\n");
@@ -336,7 +350,7 @@ struct virtual_channel *frontend_open(struct uhab_context *ctx,
vchan->id);
hab_open_pending_exit(ctx, pchan, &pending_open);
- if (ret != -EINTR)
+ if (ret != -EINTR && ret != -ENXIO)
ret = -EINVAL;
goto err;
}
@@ -377,15 +391,15 @@ err:
struct virtual_channel *backend_listen(struct uhab_context *ctx,
unsigned int mm_id, int timeout)
{
- int ret, ret2;
- int open_id, ver_fe;
+ int ret = 0, ret2 = 0;
+ int open_id = 0, ver_fe = 0;
int sub_id = HAB_MMID_GET_MINOR(mm_id);
struct physical_channel *pchan = NULL;
- struct hab_device *dev;
+ struct hab_device *dev = NULL;
struct virtual_channel *vchan = NULL;
- struct hab_open_request request;
- struct hab_open_request *recv_request;
- uint32_t otherend_vchan_id;
+ struct hab_open_request request = {0};
+ struct hab_open_request *recv_request = NULL;
+ uint32_t otherend_vchan_id = 0;
struct hab_open_node pending_open = { { 0 } };
dev = find_hab_device(mm_id);
@@ -407,6 +421,8 @@ struct virtual_channel *backend_listen(struct uhab_context *ctx,
ret = -EINVAL;
if (-EAGAIN == ret) {
ret = -ETIMEDOUT;
+ } else if (-ENXIO == ret) {
+ pr_warn("open request canceling\n");
} else {
/* device is closed */
pr_err("open request wait failed ctx closing %d\n",
@@ -416,7 +432,7 @@ struct virtual_channel *backend_listen(struct uhab_context *ctx,
} else if (!ret && recv_request &&
((recv_request->xdata.ver_fe & 0xFFFF0000) !=
(HAB_API_VER & 0xFFFF0000))) {
- int ret2;
+ int ret2 = 0;
/* version check */
pr_err("version mismatch fe %X be %X on mmid %d\n",
recv_request->xdata.ver_fe, HAB_API_VER, mm_id);
@@ -467,11 +483,11 @@ struct virtual_channel *backend_listen(struct uhab_context *ctx,
hab_open_request_init(&request, HAB_PAYLOAD_TYPE_INIT_DONE,
pchan, 0, sub_id, open_id);
ret = hab_open_listen(ctx, dev, &request, &recv_request,
- HAB_HS_TIMEOUT);
+ HAB_HS_INIT_DONE_TIMEOUT);
hab_open_pending_exit(ctx, pchan, &pending_open);
- if (ret && recv_request &&
+ if (!ret && recv_request &&
recv_request->type == HAB_PAYLOAD_TYPE_INIT_CANCEL) {
- pr_err("listen cancelled vcid %x subid %d openid %d ret %d\n",
+ pr_warn("open rmt cancelled vcid %x subid %d openid %d ret %d\n",
request.xdata.vchan_id, request.xdata.sub_id,
request.xdata.open_id, ret);
@@ -487,9 +503,12 @@ struct virtual_channel *backend_listen(struct uhab_context *ctx,
ret2, vchan->id);
hab_open_pending_exit(ctx, pchan, &pending_open);
- ret = -ENODEV; /* open request cancelled remotely */
+ ret = -ENODEV; /* open request FE cancelled remotely */
break;
- } else if (ret != -EAGAIN) {
+ } else if (-ENXIO == ret) {
+ pr_warn("backend mmid %d listen canceling\n", mm_id);
+ goto err;
+ } else if (ret != -EAGAIN && ret != -EINTR) {
hab_open_pending_exit(ctx, pchan, &pending_open);
break; /* received something. good case! */
}
@@ -540,8 +559,8 @@ long hab_vchan_send(struct uhab_context *ctx,
void *data,
unsigned int flags)
{
- struct virtual_channel *vchan;
- int ret;
+ struct virtual_channel *vchan = NULL;
+ int ret = 0;
struct hab_header header = HAB_HEADER_INITIALIZER;
int nonblocking_flag = flags & HABMM_SOCKET_SEND_FLAGS_NON_BLOCKING;
@@ -557,7 +576,7 @@ long hab_vchan_send(struct uhab_context *ctx,
goto err;
}
- HAB_HEADER_SET_SIZE(header, sizebytes);
+ HAB_HEADER_SET_SIZE(header, (uint32_t)sizebytes);
if (flags & HABMM_SOCKET_SEND_FLAGS_XING_VM_STAT) {
HAB_HEADER_SET_TYPE(header, HAB_PAYLOAD_TYPE_PROFILE);
if (sizebytes < sizeof(struct habmm_xing_vm_stat)) {
@@ -602,11 +621,11 @@ int hab_vchan_recv(struct uhab_context *ctx,
int *rsize,
unsigned int flags)
{
- struct virtual_channel *vchan;
+ struct virtual_channel *vchan = NULL;
int ret = 0;
int nonblocking_flag = flags & HABMM_SOCKET_RECV_FLAGS_NON_BLOCKING;
- vchan = hab_get_vchan_fromvcid(vcid, ctx, 1);
+ vchan = hab_get_vchan_fromvcid(vcid, ctx, 1); /* to drain local q */
if (!vchan) {
pr_err("vcid %X vchan 0x%pK ctx %pK\n", vcid, vchan, ctx);
return -ENODEV;
@@ -640,6 +659,68 @@ bool hab_is_loopback(void)
return hab_driver.b_loopback;
}
+static int hab_stop(struct uhab_context *ctx, unsigned int mmid)
+{
+ struct hab_forbidden_node *node = NULL, *tmp = NULL;
+ struct hab_device *dev = NULL;
+
+ dev = find_hab_device(mmid);
+ if (dev == NULL) {
+ pr_err("failed to find dev based on id 0x%x\n", mmid);
+ return -EINVAL;
+ }
+
+ spin_lock_bh(&ctx->forbidden_lock);
+
+ list_for_each_entry_safe(node, tmp, &ctx->forbidden_chans, node) {
+ if (node->mmid == mmid) {
+ pr_info("mmid 0x%x has been in forbidden list, ctx %p\n",
+ mmid, ctx);
+ spin_unlock_bh(&ctx->forbidden_lock);
+ return 0;
+ }
+ }
+
+ pr_info("Add mmid 0x%x into forbidden list, ctx %p\n",
+ mmid, ctx);
+
+ node = kzalloc(sizeof(*node), GFP_ATOMIC);
+ if (!node) {
+ spin_unlock_bh(&ctx->forbidden_lock);
+ return -ENOMEM;
+ }
+ node->mmid = mmid;
+ list_add_tail(&node->node, &ctx->forbidden_chans);
+
+ spin_unlock_bh(&ctx->forbidden_lock);
+
+ wake_up_interruptible(&dev->openq);
+
+ return 0;
+}
+
+int hab_is_forbidden(struct uhab_context *ctx,
+ struct hab_device *dev,
+ uint32_t sub_id)
+{
+ struct hab_forbidden_node *node = NULL, *tmp = NULL;
+
+ if (!dev)
+ return 0;
+
+ spin_lock_bh(&ctx->forbidden_lock);
+ list_for_each_entry_safe(node, tmp, &ctx->forbidden_chans, node) {
+ if ((HAB_MMID_GET_MAJOR(node->mmid) == dev->id) &&
+ (HAB_MMID_GET_MINOR(node->mmid) == sub_id)) {
+ spin_unlock_bh(&ctx->forbidden_lock);
+ return 1;
+ }
+ }
+ spin_unlock_bh(&ctx->forbidden_lock);
+
+ return 0;
+}
+
int hab_vchan_open(struct uhab_context *ctx,
unsigned int mmid,
int32_t *vcid,
@@ -647,8 +728,9 @@ int hab_vchan_open(struct uhab_context *ctx,
uint32_t flags)
{
struct virtual_channel *vchan = NULL;
- struct hab_device *dev;
+ struct hab_device *dev = NULL;
+ (void)flags;
pr_debug("Open mmid=%d, loopback mode=%d, loopback be ctx %d\n",
mmid, hab_driver.b_loopback, ctx->lb_be);
@@ -664,6 +746,13 @@ int hab_vchan_open(struct uhab_context *ctx,
} else {
dev = find_hab_device(mmid);
+ if (hab_is_forbidden(ctx,
+ dev, HAB_MMID_GET_MINOR(mmid))) {
+ pr_err("mmid 0x%x has been forbidden",
+ mmid);
+ return -ENXIO;
+ }
+
if (dev) {
struct physical_channel *pchan =
hab_pchan_find_domid(dev,
@@ -689,7 +778,7 @@ int hab_vchan_open(struct uhab_context *ctx,
if (IS_ERR(vchan)) {
if (-ETIMEDOUT != PTR_ERR(vchan) && -EAGAIN != PTR_ERR(vchan))
pr_err("vchan open failed mmid=%d\n", mmid);
- return PTR_ERR(vchan);
+ return (int)PTR_ERR(vchan);
}
pr_debug("vchan id %x remote id %x session %d\n", vchan->id,
@@ -720,7 +809,8 @@ void hab_send_close_msg(struct virtual_channel *vchan)
void hab_vchan_close(struct uhab_context *ctx, int32_t vcid)
{
- struct virtual_channel *vchan, *tmp;
+ struct virtual_channel *vchan = NULL, *tmp = NULL;
+ int vchan_found = 0;
if (!ctx)
return;
@@ -744,10 +834,14 @@ void hab_vchan_close(struct uhab_context *ctx, int32_t vcid)
hab_vchan_stop_notify(vchan);
hab_vchan_put(vchan); /* there is a lock inside */
write_lock(&ctx->ctx_lock);
+ vchan_found = 1;
break;
}
}
write_unlock(&ctx->ctx_lock);
+
+ if (!vchan_found)
+ hab_stop(ctx, vcid);
}
/*
@@ -760,9 +854,9 @@ void hab_vchan_close(struct uhab_context *ctx, int32_t vcid)
static int hab_initialize_pchan_entry(struct hab_device *mmid_device,
int vmid_local, int vmid_remote, int is_be)
{
- char pchan_name[MAX_VMID_NAME_SIZE];
+ char pchan_name[MAX_VMID_NAME_SIZE] = {0};
struct physical_channel *pchan = NULL;
- int ret;
+ int ret = 0;
int vmid = is_be ? vmid_remote : vmid_local; /* used for naming only */
if (!mmid_device) {
@@ -799,7 +893,7 @@ static int hab_initialize_pchan_entry(struct hab_device *mmid_device,
*/
static int hab_generate_pchan(struct local_vmid *settings, int i, int j)
{
- int k, ret = 0;
+ int k = 0, ret = 0;
pr_debug("%d as mmid %d in vmid %d\n",
HABCFG_GET_MMID(settings, i, j), j, i);
@@ -922,13 +1016,13 @@ static int hab_generate_pchan(struct local_vmid *settings, int i, int j)
*/
static int hab_generate_pchan_list(struct local_vmid *settings)
{
- int i, j, ret = 0;
+ int i = 0, j = 0, ret = 0;
/* scan by valid VMs, then mmid */
pr_debug("self vmid is %d\n", settings->self);
for (i = 0; i < HABCFG_VMID_MAX; i++) {
- if (HABCFG_GET_VMID(settings, i) != HABCFG_VMID_INVALID &&
- HABCFG_GET_VMID(settings, i) != settings->self) {
+ if (HABCFG_GET_VMID(settings, i) != HABCFG_VMID_INVALID
+ && HABCFG_GET_VMID(settings, i) != settings->self) {
pr_debug("create pchans for vm %d\n", i);
for (j = 1; j <= HABCFG_MMID_AREA_MAX; j++) {
@@ -954,9 +1048,9 @@ static int hab_generate_pchan_list(struct local_vmid *settings)
int do_hab_parse(void)
{
- int result;
- int i;
- struct hab_device *device;
+ int result = 0;
+ int i = 0;
+ struct hab_device *device = NULL;
/* single GVM is 2, multigvm is 2 or 3. GHS LV-GVM 2, LA-GVM 3 */
int default_gvmid = DEFAULT_GVMID;
@@ -966,7 +1060,8 @@ int do_hab_parse(void)
/* first check if hypervisor plug-in is ready */
result = hab_hypervisor_register();
if (result) {
- pr_err("register HYP plug-in failed, ret %d\n", result);
+ pr_err("register HYP plug-in failed, ret %d driver version %s\n",
+ result, hab_info_str);
return result;
}
@@ -1014,13 +1109,13 @@ int get_refcnt(struct kref ref)
void hab_hypervisor_unregister_common(void)
{
- int status, i;
- struct uhab_context *ctx;
- struct virtual_channel *vchan;
+ int status = 0, i = 0;
+ struct uhab_context *ctx = NULL;
+ struct virtual_channel *vchan = NULL;
for (i = 0; i < hab_driver.ndevices; i++) {
struct hab_device *habdev = &hab_driver.devp[i];
- struct physical_channel *pchan, *pchan_tmp;
+ struct physical_channel *pchan = NULL, *pchan_tmp = NULL;
list_for_each_entry_safe(pchan, pchan_tmp,
&habdev->pchannels, node) {
@@ -1194,13 +1289,11 @@ static long hab_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
recv_param->sizebytes = 0;
ret = -EFAULT;
}
- } else if (ret && msg) {
- pr_warn("vcid %X recv failed %d and msg is still of %zd bytes\n",
- recv_param->vcid, (int)ret, msg->sizebytes);
- }
-
- if (msg)
hab_msg_free(msg);
+ } else
+ pr_warn("vcid %X recv failed %d buf size %d\n",
+ recv_param->vcid, (int)ret,
+ recv_param->sizebytes);
break;
case IOCTL_HAB_VC_EXPORT:
ret = hab_mem_export(ctx, (struct hab_export *)data, 0);
diff --git a/drivers/soc/qcom/hab/hab.h b/drivers/soc/qcom/hab/hab.h
index 7d0c5f2673a2..cb7ed52050b2 100644
--- a/drivers/soc/qcom/hab/hab.h
+++ b/drivers/soc/qcom/hab/hab.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2019, 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
@@ -46,6 +46,7 @@
#include <linux/kobject.h>
#include <linux/sysfs.h>
#include <linux/delay.h>
+#include <linux/version.h>
#include <soc/qcom/boot_stats.h>
enum hab_payload_type {
@@ -161,13 +162,13 @@ struct hab_header {
#define HAB_HEADER_SET_SIZE(header, size) \
((header).id_type_size = ((header).id_type_size & \
- (~HAB_HEADER_SIZE_MASK)) | \
+ (uint32_t)(~HAB_HEADER_SIZE_MASK)) | \
(((size) << HAB_HEADER_SIZE_SHIFT) & \
HAB_HEADER_SIZE_MASK))
#define HAB_HEADER_SET_TYPE(header, type) \
((header).id_type_size = ((header).id_type_size & \
- (~HAB_HEADER_TYPE_MASK)) | \
+ (uint32_t)(~HAB_HEADER_TYPE_MASK)) | \
(((type) << HAB_HEADER_TYPE_SHIFT) & \
HAB_HEADER_TYPE_MASK))
@@ -192,6 +193,7 @@ struct hab_header {
#define HAB_HEADER_GET_SESSION_ID(header) ((header).session_id)
#define HAB_HS_TIMEOUT (10*1000*1000)
+#define HAB_HS_INIT_DONE_TIMEOUT (3*1000)
struct physical_channel {
struct list_head node;
@@ -265,6 +267,11 @@ struct hab_message {
uint32_t data[];
};
+struct hab_forbidden_node {
+ struct list_head node;
+ uint32_t mmid;
+};
+
/* for all the pchans of same kind */
struct hab_device {
char name[MAX_VMID_NAME_SIZE];
@@ -302,6 +309,9 @@ struct uhab_context {
struct list_head pending_open; /* sent to remote */
int pending_cnt;
+ struct list_head forbidden_chans;
+ spinlock_t forbidden_lock;
+
rwlock_t ctx_lock;
int closing;
int kernel;
@@ -403,6 +413,9 @@ struct export_desc {
unsigned char payload[1];
} __packed;
+int hab_is_forbidden(struct uhab_context *ctx,
+ struct hab_device *dev,
+ uint32_t sub_id);
int hab_vchan_open(struct uhab_context *ctx,
unsigned int mmid, int32_t *vcid,
int32_t timeout, uint32_t flags);
@@ -521,7 +534,7 @@ static inline void hab_ctx_get(struct uhab_context *ctx)
static inline void hab_ctx_put(struct uhab_context *ctx)
{
if (ctx)
- kref_put(&ctx->refcount, hab_ctx_free);
+ kref_put(&ctx->refcount, &hab_ctx_free);
}
void hab_send_close_msg(struct virtual_channel *vchan);
diff --git a/drivers/soc/qcom/hab/hab_ghs.c b/drivers/soc/qcom/hab/hab_ghs.c
index a445aa1a6707..01f42b5f67ac 100644
--- a/drivers/soc/qcom/hab/hab_ghs.c
+++ b/drivers/soc/qcom/hab/hab_ghs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018-2019, 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
@@ -93,7 +93,7 @@ static int get_dt_name_idx(int vmid_base, int mmid,
struct ghs_vmm_plugin_info_s *plugin_info)
{
int idx = -1;
- int i;
+ int i = 0;
if (vmid_base < 0 || vmid_base > plugin_info->probe_cnt /
GIPC_VM_SET_CNT) {
diff --git a/drivers/soc/qcom/hab/hab_mem_linux.c b/drivers/soc/qcom/hab/hab_mem_linux.c
index 13bfab41f75d..6c61fbd00ded 100644
--- a/drivers/soc/qcom/hab/hab_mem_linux.c
+++ b/drivers/soc/qcom/hab/hab_mem_linux.c
@@ -598,6 +598,9 @@ static int hab_mem_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
vma->vm_private_data = pglist;
vma->vm_flags |= VM_MIXEDMAP;
+ if (!(pglist->userflags & HABMM_IMPORT_FLAGS_CACHED))
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
return 0;
}
diff --git a/drivers/soc/qcom/hab/hab_mimex.c b/drivers/soc/qcom/hab/hab_mimex.c
index b03739974390..c761099186d4 100644
--- a/drivers/soc/qcom/hab/hab_mimex.c
+++ b/drivers/soc/qcom/hab/hab_mimex.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2019, 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
@@ -31,15 +31,14 @@ static int hab_export_ack_find(struct uhab_context *ctx,
struct hab_export_ack *expect_ack, struct virtual_channel *vchan)
{
int ret = 0;
- struct hab_export_ack_recvd *ack_recvd, *tmp;
+ struct hab_export_ack_recvd *ack_recvd = NULL, *tmp = NULL;
spin_lock_bh(&ctx->expq_lock);
list_for_each_entry_safe(ack_recvd, tmp, &ctx->exp_rxq, node) {
- if ((ack_recvd->ack.export_id == expect_ack->export_id &&
+ if (ack_recvd->ack.export_id == expect_ack->export_id &&
ack_recvd->ack.vcid_local == expect_ack->vcid_local &&
- ack_recvd->ack.vcid_remote == expect_ack->vcid_remote)
- || vchan->otherend_closed) {
+ ack_recvd->ack.vcid_remote == expect_ack->vcid_remote) {
list_del(&ack_recvd->node);
kfree(ack_recvd);
ret = 1;
@@ -52,6 +51,12 @@ static int hab_export_ack_find(struct uhab_context *ctx,
}
}
+ if (!ret && vchan->otherend_closed) {
+ pr_info("no expected ack, but vchan %x is remotely closed\n",
+ vchan->id);
+ ret = 1;
+ }
+
spin_unlock_bh(&ctx->expq_lock);
return ret;
@@ -60,7 +65,7 @@ static int hab_export_ack_find(struct uhab_context *ctx,
static int hab_export_ack_wait(struct uhab_context *ctx,
struct hab_export_ack *expect_ack, struct virtual_channel *vchan)
{
- int ret;
+ int ret = 0;
ret = wait_event_interruptible_timeout(ctx->exp_wq,
hab_export_ack_find(ctx, expect_ack, vchan),
@@ -83,8 +88,8 @@ static struct export_desc *habmem_add_export(struct virtual_channel *vchan,
int sizebytes,
uint32_t flags)
{
- struct uhab_context *ctx;
- struct export_desc *exp;
+ struct uhab_context *ctx = NULL;
+ struct export_desc *exp = NULL;
if (!vchan || !sizebytes)
return NULL;
@@ -112,7 +117,7 @@ static struct export_desc *habmem_add_export(struct virtual_channel *vchan,
ctx = vchan->ctx;
write_lock(&ctx->exp_lock);
ctx->export_total++;
- list_add_tail(&exp->node, &ctx->exp_whse);
+ list_add_tail((struct list_head *)&exp->node, &ctx->exp_whse);
write_unlock(&ctx->exp_lock);
return exp;
@@ -120,8 +125,8 @@ static struct export_desc *habmem_add_export(struct virtual_channel *vchan,
void habmem_remove_export(struct export_desc *exp)
{
- struct physical_channel *pchan;
- struct uhab_context *ctx;
+ struct physical_channel *pchan = NULL;
+ struct uhab_context *ctx = NULL;
if (!exp || !exp->ctx || !exp->pchan) {
if (exp)
@@ -146,7 +151,7 @@ void habmem_remove_export(struct export_desc *exp)
static int compress_pfns(void **pfns, int npages, unsigned int *data_size)
{
- int i, j = 0;
+ int i = 0, j = 0;
struct grantable *item = (struct grantable *)*pfns;
int region_size = 1;
struct compressed_pfns *new_table =
@@ -162,8 +167,8 @@ static int compress_pfns(void **pfns, int npages, unsigned int *data_size)
region_size++; /* continuous pfn */
} else {
new_table->region[j].size = region_size;
- new_table->region[j].space = item[i].pfn -
- item[i-1].pfn - 1;
+ new_table->region[j].space = (int)(item[i].pfn -
+ item[i-1].pfn - 1);
j++;
region_size = 1;
}
@@ -173,8 +178,8 @@ static int compress_pfns(void **pfns, int npages, unsigned int *data_size)
new_table->nregions = j+1;
vfree(*pfns);
- *data_size = sizeof(struct compressed_pfns) +
- sizeof(struct region)*new_table->nregions;
+ *data_size = (int)(sizeof(struct compressed_pfns) +
+ sizeof(struct region)*new_table->nregions);
*pfns = new_table;
return 0;
}
@@ -191,9 +196,9 @@ static int habmem_export_vchan(struct uhab_context *ctx,
int nunits,
uint32_t flags,
uint32_t *export_id) {
- int ret;
- struct export_desc *exp;
- uint32_t sizebytes = sizeof(*exp) + payload_size;
+ int ret = 0;
+ struct export_desc *exp = NULL;
+ uint32_t sizebytes = (uint32_t)(sizeof(*exp) + payload_size);
struct hab_export_ack expected_ack = {0};
struct hab_header header = HAB_HEADER_INITIALIZER;
@@ -239,8 +244,8 @@ int hab_mem_export(struct uhab_context *ctx,
void *pdata_exp = NULL;
unsigned int pdata_size = 0;
uint32_t export_id = 0;
- struct virtual_channel *vchan;
- int page_count;
+ struct virtual_channel *vchan = NULL;
+ int page_count = 0;
int compressed = 0;
if (!ctx || !param || !param->buffer)
@@ -266,7 +271,7 @@ int hab_mem_export(struct uhab_context *ctx,
vchan->pchan->dom_id,
pdata_exp,
&compressed,
- &pdata_size);
+ (int *)&pdata_size);
} else {
ret = habmem_hyp_grant_user((unsigned long)param->buffer,
page_count,
@@ -274,7 +279,7 @@ int hab_mem_export(struct uhab_context *ctx,
vchan->pchan->dom_id,
pdata_exp,
&compressed,
- &pdata_size);
+ (int *)&pdata_size);
}
if (ret < 0) {
pr_err("habmem_hyp_grant vc %x failed size=%d ret=%d\n",
@@ -306,9 +311,10 @@ int hab_mem_unexport(struct uhab_context *ctx,
int kernel)
{
int ret = 0, found = 0;
- struct export_desc *exp, *tmp;
- struct virtual_channel *vchan;
+ struct export_desc *exp = NULL, *tmp = NULL;
+ struct virtual_channel *vchan = NULL;
+ (void)kernel;
if (!ctx || !param)
return -EINVAL;
@@ -322,8 +328,9 @@ int hab_mem_unexport(struct uhab_context *ctx,
write_lock(&ctx->exp_lock);
list_for_each_entry_safe(exp, tmp, &ctx->exp_whse, node) {
if (param->exportid == exp->export_id &&
- vchan->pchan == exp->pchan) {
- list_del(&exp->node);
+ vchan->pchan == exp->pchan &&
+ param->vcid == exp->vcid_local) {
+ list_del((struct list_head *)&exp->node);
found = 1;
break;
}
@@ -355,7 +362,7 @@ int hab_mem_import(struct uhab_context *ctx,
{
int ret = 0, found = 0;
struct export_desc *exp = NULL;
- struct virtual_channel *vchan;
+ struct virtual_channel *vchan = NULL;
if (!ctx || !param)
return -EINVAL;
@@ -368,8 +375,9 @@ int hab_mem_import(struct uhab_context *ctx,
spin_lock_bh(&ctx->imp_lock);
list_for_each_entry(exp, &ctx->imp_whse, node) {
- if ((exp->export_id == param->exportid) &&
- (exp->pchan == vchan->pchan)) {
+ if (exp->export_id == param->exportid &&
+ exp->pchan == vchan->pchan &&
+ param->vcid == exp->vcid_local) {
found = 1;
break;
}
@@ -414,8 +422,8 @@ int hab_mem_unimport(struct uhab_context *ctx,
int kernel)
{
int ret = 0, found = 0;
- struct export_desc *exp = NULL, *exp_tmp;
- struct virtual_channel *vchan;
+ struct export_desc *exp = NULL, *exp_tmp = NULL;
+ struct virtual_channel *vchan = NULL;
if (!ctx || !param)
return -EINVAL;
@@ -430,9 +438,10 @@ int hab_mem_unimport(struct uhab_context *ctx,
spin_lock_bh(&ctx->imp_lock);
list_for_each_entry_safe(exp, exp_tmp, &ctx->imp_whse, node) {
if (exp->export_id == param->exportid &&
- exp->pchan == vchan->pchan) {
+ exp->pchan == vchan->pchan &&
+ param->vcid == exp->vcid_local) {
/* same pchan is expected here */
- list_del(&exp->node);
+ list_del((struct list_head *)&exp->node);
ctx->import_total--;
found = 1;
break;
diff --git a/drivers/soc/qcom/hab/hab_msg.c b/drivers/soc/qcom/hab/hab_msg.c
index e0f4970ce14e..dabffa0e856a 100644
--- a/drivers/soc/qcom/hab/hab_msg.c
+++ b/drivers/soc/qcom/hab/hab_msg.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2019, 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
@@ -14,7 +14,7 @@
static int hab_rx_queue_empty(struct virtual_channel *vchan)
{
- int ret;
+ int ret = 0;
spin_lock_bh(&vchan->rx_lock);
ret = list_empty(&vchan->rx_list);
@@ -25,11 +25,11 @@ static int hab_rx_queue_empty(struct virtual_channel *vchan)
static struct hab_message*
hab_msg_alloc(struct physical_channel *pchan, size_t sizebytes)
{
- struct hab_message *message;
+ struct hab_message *message = NULL;
if (sizebytes > HAB_HEADER_SIZE_MASK) {
- pr_err("pchan %s send size too large %zd\n",
- pchan->name, sizebytes);
+ pr_err("pchan %s send size too large %zd header %zd\n",
+ pchan->name, sizebytes, sizeof(*message));
return NULL;
}
@@ -81,16 +81,16 @@ hab_msg_dequeue(struct virtual_channel *vchan, struct hab_message **msg,
message = list_first_entry(&vchan->rx_list,
struct hab_message, node);
if (message) {
- if (*rsize >= message->sizebytes) {
+ if (*rsize >= (int)message->sizebytes) {
/* msg can be safely retrieved in full */
list_del(&message->node);
ret = 0;
- *rsize = message->sizebytes;
+ *rsize = (int)message->sizebytes;
} else {
pr_err("vcid %x rcv buf too small %d < %zd\n",
vchan->id, *rsize,
message->sizebytes);
- *rsize = message->sizebytes;
+ *rsize = (int)message->sizebytes;
message = NULL;
ret = -EOVERFLOW; /* come back again */
}
@@ -121,7 +121,7 @@ static int hab_export_enqueue(struct virtual_channel *vchan,
struct uhab_context *ctx = vchan->ctx;
spin_lock_bh(&ctx->imp_lock);
- list_add_tail(&exp->node, &ctx->imp_whse);
+ list_add_tail((struct list_head *)&exp->node, &ctx->imp_whse);
ctx->import_total++;
spin_unlock_bh(&ctx->imp_lock);
@@ -139,7 +139,7 @@ static int hab_send_export_ack(struct virtual_channel *vchan,
};
struct hab_header header = HAB_HEADER_INITIALIZER;
- HAB_HEADER_SET_SIZE(header, sizeof(exp_ack));
+ HAB_HEADER_SET_SIZE(header, (uint32_t)sizeof(exp_ack));
HAB_HEADER_SET_TYPE(header, HAB_PAYLOAD_TYPE_EXPORT_ACK);
HAB_HEADER_SET_ID(header, exp->vcid_local);
HAB_HEADER_SET_SESSION_ID(header, vchan->session_id);
@@ -159,9 +159,9 @@ static int hab_receive_create_export_ack(struct physical_channel *pchan,
pr_err("exp ack size %zu is not as arrived %zu\n",
sizeof(ack_recvd->ack), sizebytes);
- if (sizebytes > HAB_HEADER_SIZE_MASK) {
- pr_err("pchan %s read size too large %zd\n",
- pchan->name, sizebytes);
+ if (sizebytes > sizeof(ack_recvd->ack)) {
+ pr_err("pchan %s read size too large %zd %zd\n",
+ pchan->name, sizebytes, sizeof(ack_recvd->ack));
return -EINVAL;
}
@@ -197,16 +197,15 @@ int hab_msg_recv(struct physical_channel *pchan,
struct hab_header *header)
{
int ret = 0;
- struct hab_message *message;
+ struct hab_message *message = NULL;
struct hab_device *dev = pchan->habdev;
size_t sizebytes = HAB_HEADER_GET_SIZE(*header);
uint32_t payload_type = HAB_HEADER_GET_TYPE(*header);
uint32_t vchan_id = HAB_HEADER_GET_ID(*header);
uint32_t session_id = HAB_HEADER_GET_SESSION_ID(*header);
struct virtual_channel *vchan = NULL;
- struct export_desc *exp_desc;
- struct timeval tv;
- unsigned long long rx_mpm_tv;
+ struct export_desc *exp_desc = NULL, exp_ack = {0};
+ struct timeval tv = {0};
/* get the local virtual channel if it isn't an open message */
if (payload_type != HAB_PAYLOAD_TYPE_INIT &&
@@ -296,8 +295,8 @@ int hab_msg_recv(struct physical_channel *pchan,
case HAB_PAYLOAD_TYPE_EXPORT:
if (sizebytes > HAB_HEADER_SIZE_MASK) {
- pr_err("%s exp size too large %zd\n",
- pchan->name, sizebytes);
+ pr_err("%s exp size too large %zd header %zd\n",
+ pchan->name, sizebytes, sizeof(*exp_desc));
break;
}
@@ -322,9 +321,12 @@ int hab_msg_recv(struct physical_channel *pchan,
exp_desc->domid_remote = pchan->vmid_remote;
exp_desc->domid_local = pchan->vmid_local;
exp_desc->pchan = pchan;
+ exp_ack = *exp_desc; /* preserve exporter's info for ack */
+ exp_desc->vcid_remote = exp_desc->vcid_local;
+ exp_desc->vcid_local = vchan->id;
- hab_export_enqueue(vchan, exp_desc);
- hab_send_export_ack(vchan, pchan, exp_desc);
+ hab_export_enqueue(vchan, exp_desc); /* for local use */
+ hab_send_export_ack(vchan, pchan, &exp_ack); /* ack exporter */
break;
case HAB_PAYLOAD_TYPE_EXPORT_ACK:
diff --git a/drivers/soc/qcom/hab/hab_open.c b/drivers/soc/qcom/hab/hab_open.c
index bc2b774883f4..72dc9a54d20e 100644
--- a/drivers/soc/qcom/hab/hab_open.c
+++ b/drivers/soc/qcom/hab/hab_open.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2019, 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
@@ -32,7 +32,8 @@ int hab_open_request_send(struct hab_open_request *request)
{
struct hab_header header = HAB_HEADER_INITIALIZER;
- HAB_HEADER_SET_SIZE(header, sizeof(struct hab_open_send_data));
+ HAB_HEADER_SET_SIZE(header,
+ (uint32_t)sizeof(struct hab_open_send_data));
HAB_HEADER_SET_TYPE(header, request->type);
return physical_channel_send(request->pchan, &header, &request->xdata);
@@ -42,12 +43,12 @@ int hab_open_request_send(struct hab_open_request *request)
int hab_open_request_add(struct physical_channel *pchan,
size_t sizebytes, int request_type)
{
- struct hab_open_node *node;
+ struct hab_open_node *node = NULL;
struct hab_device *dev = pchan->habdev;
- struct hab_open_request *request;
- struct timeval tv;
+ struct hab_open_request *request = NULL;
+ struct timeval tv = {0};
- if (sizebytes > HAB_HEADER_SIZE_MASK) {
+ if (sizebytes > sizeof(request->xdata)) {
pr_err("pchan %s request size too large %zd\n",
pchan->name, sizebytes);
return -EINVAL;
@@ -83,9 +84,9 @@ static int hab_open_request_find(struct uhab_context *ctx,
struct hab_open_request *listen,
struct hab_open_request **recv_request)
{
- struct hab_open_node *node, *tmp;
- struct hab_open_request *request;
- struct timeval tv;
+ struct hab_open_node *node = NULL, *tmp = NULL;
+ struct hab_open_request *request = NULL;
+ struct timeval tv = {0};
int ret = 0;
if (ctx->closing ||
@@ -126,6 +127,10 @@ static int hab_open_request_find(struct uhab_context *ctx,
done:
spin_unlock_bh(&dev->openlock);
+
+ if (hab_is_forbidden(ctx, dev, listen->xdata.sub_id))
+ ret = 1;
+
return ret;
}
@@ -165,6 +170,9 @@ int hab_open_listen(struct uhab_context *ctx,
pr_warn("something failed in open listen ret %d\n",
ret);
ret = -EINTR; /* condition not met */
+ } else if (hab_is_forbidden(ctx, dev, listen->xdata.sub_id)) {
+ pr_warn("local open cancelled ret %d\n", ret);
+ ret = -ENXIO;
} else if (ret > 0)
ret = 0; /* condition met */
} else { /* fe case */
@@ -176,6 +184,9 @@ int hab_open_listen(struct uhab_context *ctx,
} else if (-ERESTARTSYS == ret) {
pr_warn("local interrupted ret %d\n", ret);
ret = -EINTR;
+ } else if (hab_is_forbidden(ctx, dev, listen->xdata.sub_id)) {
+ pr_warn("local open cancelled ret %d\n", ret);
+ ret = -ENXIO;
}
}
@@ -187,15 +198,15 @@ int hab_open_receive_cancel(struct physical_channel *pchan,
size_t sizebytes)
{
struct hab_device *dev = pchan->habdev;
- struct hab_open_send_data data;
- struct hab_open_request *request;
- struct hab_open_node *node, *tmp;
+ struct hab_open_send_data data = {0};
+ struct hab_open_request *request = NULL;
+ struct hab_open_node *node = NULL, *tmp = NULL;
int bfound = 0;
- struct timeval tv;
+ struct timeval tv = {0};
- if (sizebytes > HAB_HEADER_SIZE_MASK) {
- pr_err("pchan %s cancel size too large %zd\n",
- pchan->name, sizebytes);
+ if (sizebytes > sizeof(data)) {
+ pr_err("pchan %s cancel size too large %zd header %zd\n",
+ pchan->name, sizebytes, sizeof(data));
return -EINVAL;
}
@@ -260,7 +271,8 @@ int hab_open_cancel_notify(struct hab_open_request *request)
{
struct hab_header header = HAB_HEADER_INITIALIZER;
- HAB_HEADER_SET_SIZE(header, sizeof(struct hab_open_send_data));
+ HAB_HEADER_SET_SIZE(header,
+ (uint32_t)sizeof(struct hab_open_send_data));
HAB_HEADER_SET_TYPE(header, HAB_PAYLOAD_TYPE_INIT_CANCEL);
return physical_channel_send(request->pchan, &header, &request->xdata);
@@ -270,6 +282,7 @@ int hab_open_pending_enter(struct uhab_context *ctx,
struct physical_channel *pchan,
struct hab_open_node *pending)
{
+ (void)pchan;
write_lock(&ctx->ctx_lock);
list_add_tail(&pending->node, &ctx->pending_open);
ctx->pending_cnt++;
@@ -282,9 +295,10 @@ int hab_open_pending_exit(struct uhab_context *ctx,
struct physical_channel *pchan,
struct hab_open_node *pending)
{
- struct hab_open_node *node, *tmp;
+ struct hab_open_node *node = NULL, *tmp = NULL;
int ret = -ENOENT;
+ (void)pchan;
write_lock(&ctx->ctx_lock);
list_for_each_entry_safe(node, tmp, &ctx->pending_open, node) {
if ((node->request.type == pending->request.type) &&
diff --git a/drivers/soc/qcom/hab/hab_parser.c b/drivers/soc/qcom/hab/hab_parser.c
index c332587e2b47..1c53877005a0 100644
--- a/drivers/soc/qcom/hab/hab_parser.c
+++ b/drivers/soc/qcom/hab/hab_parser.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, 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
@@ -23,7 +23,7 @@ static int fill_vmid_mmid_tbl(struct vmid_mmid_desc *tbl, int32_t vm_start,
int32_t mmid_range, int32_t be)
{
int ret = 0;
- int i, j;
+ int i = 0, j = 0;
for (i = vm_start; i < vm_start+vm_range; i++) {
tbl[i].vmid = i; /* set valid vmid value to make it usable */
@@ -43,6 +43,7 @@ static int fill_vmid_mmid_tbl(struct vmid_mmid_desc *tbl, int32_t vm_start,
void dump_settings(struct local_vmid *settings)
{
+ (void)settings;
pr_debug("self vmid is %d\n", settings->self);
}
@@ -152,7 +153,7 @@ static int hab_parse_dt(struct local_vmid *settings)
*/
int hab_parse(struct local_vmid *settings)
{
- int ret;
+ int ret = 0;
ret = hab_parse_dt(settings);
diff --git a/drivers/soc/qcom/hab/hab_pchan.c b/drivers/soc/qcom/hab/hab_pchan.c
index 8a9a6dfd1e0c..d82321a2b9cf 100644
--- a/drivers/soc/qcom/hab/hab_pchan.c
+++ b/drivers/soc/qcom/hab/hab_pchan.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2019, 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 @@ static void hab_pchan_free(struct kref *ref)
{
struct physical_channel *pchan =
container_of(ref, struct physical_channel, refcount);
- struct virtual_channel *vchan;
+ struct virtual_channel *vchan = NULL;
pr_debug("pchan %s refcnt %d\n", pchan->name,
get_refcnt(pchan->refcount));
@@ -67,14 +67,13 @@ static void hab_pchan_free(struct kref *ref)
}
read_unlock(&pchan->vchans_lock);
- kfree(pchan->hyp_data);
kfree(pchan);
}
struct physical_channel *
hab_pchan_find_domid(struct hab_device *dev, int dom_id)
{
- struct physical_channel *pchan;
+ struct physical_channel *pchan = NULL;
spin_lock_bh(&dev->pchan_lock);
list_for_each_entry(pchan, &dev->pchannels, node)
@@ -104,5 +103,5 @@ void hab_pchan_get(struct physical_channel *pchan)
void hab_pchan_put(struct physical_channel *pchan)
{
if (pchan)
- kref_put(&pchan->refcount, hab_pchan_free);
+ kref_put(&pchan->refcount, &hab_pchan_free);
}
diff --git a/drivers/soc/qcom/hab/hab_stat.c b/drivers/soc/qcom/hab/hab_stat.c
index b78e5e7e9867..b72528cc4d5f 100644
--- a/drivers/soc/qcom/hab/hab_stat.c
+++ b/drivers/soc/qcom/hab/hab_stat.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018-2019, 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
@@ -32,28 +32,28 @@ int hab_stat_deinit(struct hab_driver *driver)
static int hab_stat_buffer_print(char *dest,
int dest_size, const char *fmt, ...)
{
- va_list args;
- char line[MAX_LINE_SIZE];
- int ret;
+ va_list args = {0};
+ char line[MAX_LINE_SIZE] = {0};
+ int ret = 0;
va_start(args, fmt);
ret = vsnprintf(line, sizeof(line), fmt, args);
va_end(args);
if (ret > 0)
- ret = strlcat(dest, line, dest_size);
+ ret = (int)strlcat(dest, line, dest_size);
return ret;
}
int hab_stat_show_vchan(struct hab_driver *driver,
char *buf, int size)
{
- int i, ret = 0;
+ int i = 0, ret = 0;
- ret = strlcpy(buf, "", size);
+ ret = (int)strlcpy(buf, "", size);
for (i = 0; i < driver->ndevices; i++) {
struct hab_device *dev = &driver->devp[i];
- struct physical_channel *pchan;
- struct virtual_channel *vc;
+ struct physical_channel *pchan = NULL;
+ struct virtual_channel *vc = NULL;
spin_lock_bh(&dev->pchan_lock);
list_for_each_entry(pchan, &dev->pchannels, node) {
@@ -86,9 +86,9 @@ int hab_stat_show_ctx(struct hab_driver *driver,
char *buf, int size)
{
int ret = 0;
- struct uhab_context *ctx;
+ struct uhab_context *ctx = NULL;
- ret = strlcpy(buf, "", size);
+ ret = (int)strlcpy(buf, "", size);
spin_lock_bh(&hab_driver.drvlock);
ret = hab_stat_buffer_print(buf, size,
@@ -96,10 +96,11 @@ int hab_stat_show_ctx(struct hab_driver *driver,
driver->ctx_cnt);
list_for_each_entry(ctx, &hab_driver.uctx_list, node) {
ret = hab_stat_buffer_print(buf, size,
- "ctx %d K %d close %d vc %d exp %d imp %d open %d\n",
+ "ctx %d K %d close %d vc %d exp %d imp %d open %d ref %d\n",
ctx->owner, ctx->kernel, ctx->closing,
ctx->vcnt, ctx->export_total,
- ctx->import_total, ctx->pending_cnt);
+ ctx->import_total, ctx->pending_cnt,
+ get_refcnt(ctx->refcount));
}
spin_unlock_bh(&hab_driver.drvlock);
@@ -108,7 +109,7 @@ int hab_stat_show_ctx(struct hab_driver *driver,
static int get_pft_tbl_total_size(struct compressed_pfns *pfn_table)
{
- int i, total_size = 0;
+ int i = 0, total_size = 0;
for (i = 0; i < pfn_table->nregions; i++)
total_size += pfn_table->region[i].size * PAGE_SIZE;
@@ -119,27 +120,40 @@ static int get_pft_tbl_total_size(struct compressed_pfns *pfn_table)
static int print_ctx_total_expimp(struct uhab_context *ctx,
char *buf, int size)
{
- struct compressed_pfns *pfn_table;
+ struct compressed_pfns *pfn_table = NULL;
int exp_total = 0, imp_total = 0;
int exp_cnt = 0, imp_cnt = 0;
- struct export_desc *exp;
+ struct export_desc *exp = NULL;
+ int exim_size = 0;
read_lock(&ctx->exp_lock);
+ hab_stat_buffer_print(buf, size, "export[expid:vcid:size]: ");
list_for_each_entry(exp, &ctx->exp_whse, node) {
pfn_table = (struct compressed_pfns *)exp->payload;
- exp_total += get_pft_tbl_total_size(pfn_table);
+ exim_size = get_pft_tbl_total_size(pfn_table);
+ exp_total += exim_size;
exp_cnt++;
+ hab_stat_buffer_print(buf, size,
+ "[%d:%x:%d] ", exp->export_id,
+ exp->vcid_local, exim_size);
}
+ hab_stat_buffer_print(buf, size, "\n");
read_unlock(&ctx->exp_lock);
spin_lock_bh(&ctx->imp_lock);
+ hab_stat_buffer_print(buf, size, "import[expid:vcid:size]: ");
list_for_each_entry(exp, &ctx->imp_whse, node) {
if (habmm_imp_hyp_map_check(ctx->import_ctx, exp)) {
pfn_table = (struct compressed_pfns *)exp->payload;
- imp_total += get_pft_tbl_total_size(pfn_table);
+ exim_size = get_pft_tbl_total_size(pfn_table);
+ imp_total += exim_size;
imp_cnt++;
+ hab_stat_buffer_print(buf, size,
+ "[%d:%x:%d] ", exp->export_id,
+ exp->vcid_local, exim_size);
}
}
+ hab_stat_buffer_print(buf, size, "\n");
spin_unlock_bh(&ctx->imp_lock);
if (exp_cnt || exp_total || imp_cnt || imp_total)
@@ -154,10 +168,11 @@ static int print_ctx_total_expimp(struct uhab_context *ctx,
int hab_stat_show_expimp(struct hab_driver *driver,
int pid, char *buf, int size)
{
- struct uhab_context *ctx;
- int ret;
+ struct uhab_context *ctx = NULL;
+ int ret = 0;
- ret = strlcpy(buf, "", size);
+ (void)driver;
+ ret = (int)strlcpy(buf, "", size);
spin_lock_bh(&hab_driver.drvlock);
list_for_each_entry(ctx, &hab_driver.uctx_list, node) {
diff --git a/drivers/soc/qcom/hab/hab_vchan.c b/drivers/soc/qcom/hab/hab_vchan.c
index a95d6c7451c9..a6ee00211347 100644
--- a/drivers/soc/qcom/hab/hab_vchan.c
+++ b/drivers/soc/qcom/hab/hab_vchan.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2019, 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
@@ -16,8 +16,8 @@ struct virtual_channel *
hab_vchan_alloc(struct uhab_context *ctx, struct physical_channel *pchan,
int openid)
{
- int id;
- struct virtual_channel *vchan;
+ int id = 0;
+ struct virtual_channel *vchan = NULL;
if (!pchan || !ctx)
return NULL;
@@ -73,10 +73,10 @@ hab_vchan_free(struct kref *ref)
{
struct virtual_channel *vchan =
container_of(ref, struct virtual_channel, refcount);
- struct hab_message *message, *msg_tmp;
+ struct hab_message *message = NULL, *msg_tmp = NULL;
struct physical_channel *pchan = vchan->pchan;
struct uhab_context *ctx = vchan->ctx;
- struct virtual_channel *vc, *vc_tmp;
+ struct virtual_channel *vc = NULL, *vc_tmp = NULL;
spin_lock_bh(&vchan->rx_lock);
list_for_each_entry_safe(message, msg_tmp, &vchan->rx_list, node) {
@@ -117,7 +117,7 @@ hab_vchan_free(struct kref *ref)
struct virtual_channel*
hab_vchan_get(struct physical_channel *pchan, struct hab_header *header)
{
- struct virtual_channel *vchan;
+ struct virtual_channel *vchan = NULL;
uint32_t vchan_id = HAB_HEADER_GET_ID(*header);
uint32_t session_id = HAB_HEADER_GET_SESSION_ID(*header);
size_t sizebytes = HAB_HEADER_GET_SIZE(*header);
@@ -182,7 +182,7 @@ void hab_vchan_stop(struct virtual_channel *vchan)
void hab_vchans_stop(struct physical_channel *pchan)
{
- struct virtual_channel *vchan, *tmp;
+ struct virtual_channel *vchan = NULL, *tmp = NULL;
read_lock(&pchan->vchans_lock);
list_for_each_entry_safe(vchan, tmp, &pchan->vchannels, pnode) {
@@ -200,12 +200,12 @@ void hab_vchan_stop_notify(struct virtual_channel *vchan)
static int hab_vchans_per_pchan_empty(struct physical_channel *pchan)
{
- int empty;
+ int empty = 0;
read_lock(&pchan->vchans_lock);
empty = list_empty(&pchan->vchannels);
if (!empty) {
- struct virtual_channel *vchan;
+ struct virtual_channel *vchan = NULL;
int vcnt = pchan->vcnt;
list_for_each_entry(vchan, &pchan->vchannels, pnode) {
@@ -230,9 +230,9 @@ static int hab_vchans_per_pchan_empty(struct physical_channel *pchan)
static int hab_vchans_empty(int vmid)
{
- int i, empty = 1;
- struct physical_channel *pchan;
- struct hab_device *hab_dev;
+ int i = 0, empty = 1;
+ struct physical_channel *pchan = NULL;
+ struct hab_device *hab_dev = NULL;
for (i = 0; i < hab_driver.ndevices; i++) {
hab_dev = &hab_driver.devp[i];
@@ -277,13 +277,15 @@ int hab_vchan_find_domid(struct virtual_channel *vchan)
void hab_vchan_put(struct virtual_channel *vchan)
{
if (vchan)
- kref_put(&vchan->refcount, hab_vchan_free);
+ kref_put(&vchan->refcount, &hab_vchan_free);
}
int hab_vchan_query(struct uhab_context *ctx, int32_t vcid, uint64_t *ids,
char *names, size_t name_size, uint32_t flags)
{
- struct virtual_channel *vchan;
+ struct virtual_channel *vchan = NULL;
+
+ (void)flags;
vchan = hab_get_vchan_fromvcid(vcid, ctx, 1);
if (!vchan)
diff --git a/drivers/soc/qcom/hab/khab.c b/drivers/soc/qcom/hab/khab.c
index c4acf12fd553..b9b508e8e72d 100644
--- a/drivers/soc/qcom/hab/khab.c
+++ b/drivers/soc/qcom/hab/khab.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2019, 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 @@ int32_t habmm_socket_recv(int32_t handle, void *dst_buff, uint32_t *size_bytes,
uint32_t timeout, uint32_t flags)
{
int ret = 0;
- struct hab_message *msg;
+ struct hab_message *msg = NULL;
if (!size_bytes || !dst_buff)
return -EINVAL;
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 0f4fb9012171..0650f0b69de7 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -66,6 +66,9 @@
/* AHB2PHY read/write waite value */
#define ONE_READ_WRITE_WAIT 0x11
+/* DP_DM linestate float */
+#define DP_DM_STATE_FLOAT 0x02
+
/* cpu to fix usb interrupt */
static int cpu_to_affin;
module_param(cpu_to_affin, int, S_IRUGO|S_IWUSR);
@@ -249,6 +252,8 @@ struct dwc3_msm {
bool hc_died;
bool xhci_ss_compliance_enable;
bool no_wakeup_src_in_hostmode;
+ bool check_for_float;
+ bool float_detected;
struct extcon_dev *extcon_vbus;
struct extcon_dev *extcon_id;
@@ -2759,6 +2764,7 @@ static int dwc3_msm_vbus_notifier(struct notifier_block *nb,
if (mdwc->vbus_active == event)
return NOTIFY_DONE;
+ mdwc->float_detected = false;
cc_state = extcon_get_cable_state_(edev, EXTCON_USB_CC);
if (cc_state < 0)
mdwc->typec_orientation = ORIENTATION_NONE;
@@ -3307,6 +3313,8 @@ static int dwc3_msm_probe(struct platform_device *pdev)
if (of_property_read_bool(node, "qcom,disable-dev-mode-pm"))
pm_runtime_get_noresume(mdwc->dev);
+ mdwc->check_for_float = of_property_read_bool(node,
+ "qcom,check-for-float");
ret = dwc3_msm_extcon_register(mdwc);
if (ret)
goto put_dwc3;
@@ -3861,7 +3869,8 @@ static int dwc3_msm_gadget_vbus_draw(struct dwc3_msm *mdwc, unsigned mA)
int ret, psy_type;
psy_type = get_psy_type(mdwc);
- if (psy_type == POWER_SUPPLY_TYPE_USB_FLOAT) {
+ if (psy_type == POWER_SUPPLY_TYPE_USB_FLOAT
+ || (mdwc->check_for_float && mdwc->float_detected)) {
if (!mA)
pval.intval = -ETIMEDOUT;
else
@@ -3952,6 +3961,7 @@ static void dwc3_otg_sm_work(struct work_struct *w)
work = 1;
} else if (test_bit(B_SESS_VLD, &mdwc->inputs)) {
dev_dbg(mdwc->dev, "b_sess_vld\n");
+ mdwc->float_detected = false;
if (get_psy_type(mdwc) == POWER_SUPPLY_TYPE_USB_FLOAT)
queue_delayed_work(mdwc->dwc3_wq,
&mdwc->sdp_check,
@@ -3964,6 +3974,21 @@ static void dwc3_otg_sm_work(struct work_struct *w)
pm_runtime_get_sync(mdwc->dev);
dbg_event(0xFF, "BIDLE gsync",
atomic_read(&mdwc->dev->power.usage_count));
+ if (mdwc->check_for_float) {
+ /*
+ * If DP_DM are found to be floating, do not
+ * start the peripheral mode.
+ */
+ if (usb_phy_dpdm_with_idp_src(mdwc->hs_phy) ==
+ DP_DM_STATE_FLOAT) {
+ mdwc->float_detected = true;
+ dwc3_msm_gadget_vbus_draw(mdwc, 0);
+ pm_runtime_put_sync(mdwc->dev);
+ dbg_event(0xFF, "FLT sync", atomic_read(
+ &mdwc->dev->power.usage_count));
+ break;
+ }
+ }
dwc3_otg_start_peripheral(mdwc, 1);
mdwc->drd_state = DRD_STATE_PERIPHERAL;
work = 1;
diff --git a/drivers/usb/phy/phy-msm-qusb.c b/drivers/usb/phy/phy-msm-qusb.c
index be63c6c0a86a..ae72ec6b3d19 100644
--- a/drivers/usb/phy/phy-msm-qusb.c
+++ b/drivers/usb/phy/phy-msm-qusb.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2017,2019 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
@@ -29,11 +29,23 @@
#include <linux/usb/msm_hsusb.h>
#include <linux/reset.h>
+#define QUSB2PHY_PLL_PWR_CTL 0x18
+#define REF_BUF_EN BIT(0)
+#define REXT_EN BIT(1)
+#define PLL_BYPASSNL BIT(2)
+#define REXT_TRIM_0 BIT(4)
+
+#define QUSB2PHY_PLL_AUTOPGM_CTL1 0x1C
+#define PLL_RESET_N_CNT_5 0x5
+#define PLL_RESET_N BIT(4)
+#define PLL_AUTOPGM_EN BIT(7)
+
#define QUSB2PHY_PLL_STATUS 0x38
#define QUSB2PHY_PLL_LOCK BIT(5)
#define QUSB2PHY_PORT_QC1 0x70
#define VDM_SRC_EN BIT(4)
+#define IDP_SRC_EN BIT(3)
#define VDP_SRC_EN BIT(2)
#define QUSB2PHY_PORT_QC2 0x74
@@ -57,6 +69,7 @@
#define CORE_READY_STATUS BIT(0)
#define QUSB2PHY_PORT_UTMI_CTRL1 0xC0
+#define SUSPEND_N BIT(5)
#define TERM_SELECT BIT(4)
#define XCVR_SELECT_FS BIT(2)
#define OP_MODE_NON_DRIVE BIT(0)
@@ -84,6 +97,7 @@
#define DPSE_INTR_HIGH_SEL BIT(1)
#define DPSE_INTR_EN BIT(0)
+#define QUSB2PHY_PORT_INT_STATUS 0xF0
#define QUSB2PHY_PORT_UTMI_STATUS 0xF4
#define LINESTATE_DP BIT(0)
#define LINESTATE_DM BIT(1)
@@ -156,6 +170,10 @@ struct qusb_phy {
struct regulator_desc dpdm_rdesc;
struct regulator_dev *dpdm_rdev;
+ bool dpdm_pulsing_enabled;
+ struct power_supply *dpdm_psy;
+ struct power_supply_desc dpdm_psy_desc;
+
/* emulation targets specific */
void __iomem *emu_phy_base;
bool emulation;
@@ -167,6 +185,11 @@ struct qusb_phy {
int emu_dcm_reset_seq_len;
bool put_into_high_z_state;
struct mutex phy_lock;
+ spinlock_t pulse_lock;
+};
+
+static enum power_supply_property dpdm_props[] = {
+ POWER_SUPPLY_PROP_DP_DM,
};
static void qusb_phy_enable_clocks(struct qusb_phy *qphy, bool on)
@@ -331,10 +354,13 @@ err_vdd:
return ret;
}
+#define PHY_PULSE_TIME_USEC 250
static int qusb_phy_update_dpdm(struct usb_phy *phy, int value)
{
struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy);
int ret = 0;
+ unsigned long flags;
+ u32 reg;
dev_dbg(phy->dev, "%s value:%d rm_pulldown:%d\n",
__func__, value, qphy->rm_pulldown);
@@ -393,6 +419,21 @@ static int qusb_phy_update_dpdm(struct usb_phy *phy, int value)
qusb_phy_enable_clocks(qphy, false);
}
}
+
+ /* Clear QC1 and QC2 registers when rm_pulldown = 1 */
+ if (qphy->dpdm_pulsing_enabled && qphy->rm_pulldown) {
+ dev_dbg(phy->dev, "clearing qc1 and qc2 registers.\n");
+ ret = clk_prepare_enable(qphy->cfg_ahb_clk);
+ if (ret)
+ goto clk_error;
+
+ /* Clear qc1 and qc2 registers */
+ writel_relaxed(0x00, qphy->base + QUSB2PHY_PORT_QC1);
+ writel_relaxed(0x00, qphy->base + QUSB2PHY_PORT_QC2);
+ /* to make sure above write goes through */
+ mb();
+ clk_disable_unprepare(qphy->cfg_ahb_clk);
+ }
mutex_unlock(&qphy->phy_lock);
break;
@@ -401,6 +442,22 @@ static int qusb_phy_update_dpdm(struct usb_phy *phy, int value)
dev_dbg(phy->dev, "POWER_SUPPLY_DP_DM_DPR_DMR\n");
mutex_lock(&qphy->phy_lock);
if (qphy->rm_pulldown) {
+ dev_dbg(phy->dev, "clearing qc1 and qc2 registers.\n");
+ if (qphy->dpdm_pulsing_enabled) {
+ ret = clk_prepare_enable(qphy->cfg_ahb_clk);
+ if (ret)
+ goto clk_error;
+
+ /* Clear qc1 and qc2 registers */
+ writel_relaxed(0x00,
+ qphy->base + QUSB2PHY_PORT_QC1);
+ writel_relaxed(0x00,
+ qphy->base + QUSB2PHY_PORT_QC2);
+ /* to make sure above write goes through */
+ mb();
+ clk_disable_unprepare(qphy->cfg_ahb_clk);
+ }
+
if (!qphy->cable_connected) {
if (qphy->tcsr_clamp_dig_n)
writel_relaxed(0x0,
@@ -417,15 +474,172 @@ static int qusb_phy_update_dpdm(struct usb_phy *phy, int value)
mutex_unlock(&qphy->phy_lock);
break;
+ case POWER_SUPPLY_DP_DM_DP0P6_DMF:
+ if (!qphy->dpdm_pulsing_enabled)
+ break;
+
+ dev_dbg(phy->dev, "POWER_SUPPLY_DP_DM_DP0P6_DMF\n");
+ ret = clk_prepare_enable(qphy->cfg_ahb_clk);
+ if (ret)
+ goto clk_error;
+
+ /* Set DP to 0.6v and DM to High Z state */
+ writel_relaxed(VDP_SRC_EN, qphy->base + QUSB2PHY_PORT_QC1);
+ /* complete above write */
+ mb();
+ clk_disable_unprepare(qphy->cfg_ahb_clk);
+ break;
+
+ case POWER_SUPPLY_DP_DM_DP0P6_DM3P3:
+ if (!qphy->dpdm_pulsing_enabled)
+ break;
+
+ dev_dbg(phy->dev, "POWER_SUPPLY_DP_DM_DP0PHVDCP_36_DM3P3\n");
+ ret = clk_prepare_enable(qphy->cfg_ahb_clk);
+ if (ret)
+ goto clk_error;
+
+ /* Set DP to 0.6v */
+ writel_relaxed(VDP_SRC_EN, qphy->base + QUSB2PHY_PORT_QC1);
+ /* Set DM to 3.075v */
+ writel_relaxed(RPUM_LOW_EN | RDM_UP_EN,
+ qphy->base + QUSB2PHY_PORT_QC2);
+ /* complete above write */
+ mb();
+ clk_disable_unprepare(qphy->cfg_ahb_clk);
+ break;
+
+ case POWER_SUPPLY_DP_DM_DP_PULSE:
+ if (!qphy->dpdm_pulsing_enabled)
+ break;
+
+ dev_dbg(phy->dev, "POWER_SUPPLY_DP_DM_DP_PULSE\n");
+ ret = clk_prepare_enable(qphy->cfg_ahb_clk);
+ if (ret)
+ goto clk_error;
+
+ spin_lock_irqsave(&qphy->pulse_lock, flags);
+ /*Set DP to 3.075v, sleep for .25 ms */
+ reg = readl_relaxed(qphy->base + QUSB2PHY_PORT_QC2);
+ reg |= (RDP_UP_EN | RPUP_LOW_EN);
+ writel_relaxed(reg, qphy->base + QUSB2PHY_PORT_QC2);
+
+ /* complete above write */
+ mb();
+
+ /*
+ * It is recommended to wait here to get voltage change on
+ * DP/DM line.
+ */
+ udelay(PHY_PULSE_TIME_USEC);
+
+ /* Set DP to 0.6v, sleep 2-3ms */
+ reg = readl_relaxed(qphy->base + QUSB2PHY_PORT_QC1);
+ reg |= VDP_SRC_EN;
+ writel_relaxed(reg, qphy->base + QUSB2PHY_PORT_QC1);
+
+ reg = readl_relaxed(qphy->base + QUSB2PHY_PORT_QC2);
+ reg &= ~(RDP_UP_EN | RPUP_LOW_EN);
+ writel_relaxed(reg, qphy->base + QUSB2PHY_PORT_QC2);
+ /* complete above write */
+ mb();
+ spin_unlock_irqrestore(&qphy->pulse_lock, flags);
+ /*
+ * It is recommended to wait here to get voltage change on
+ * DP/DM line.
+ */
+ usleep_range(2000, 3000);
+ clk_disable_unprepare(qphy->cfg_ahb_clk);
+ break;
+
+ case POWER_SUPPLY_DP_DM_DM_PULSE:
+ if (!qphy->dpdm_pulsing_enabled)
+ break;
+
+ dev_dbg(phy->dev, "POWER_SUPPLY_DP_DM_DM_PULSE\n");
+ ret = clk_prepare_enable(qphy->cfg_ahb_clk);
+ if (ret)
+ goto clk_error;
+
+ spin_lock_irqsave(&qphy->pulse_lock, flags);
+ /* Set DM to 0.6v, sleep .25 ms */
+ reg = readl_relaxed(qphy->base + QUSB2PHY_PORT_QC1);
+ reg |= VDM_SRC_EN;
+ writel_relaxed(reg, qphy->base + QUSB2PHY_PORT_QC1);
+
+ reg = readl_relaxed(qphy->base + QUSB2PHY_PORT_QC2);
+ reg &= ~(RDM_UP_EN | RPUM_LOW_EN);
+ writel_relaxed(reg, qphy->base + QUSB2PHY_PORT_QC2);
+
+ /* complete above write */
+ mb();
+
+ /*
+ * It is recommended to wait here to get voltage change on
+ * DP/DM line.
+ */
+ udelay(PHY_PULSE_TIME_USEC);
+
+ /* DM to 3.075v, sleep 2-3ms */
+ reg = readl_relaxed(qphy->base + QUSB2PHY_PORT_QC2);
+ reg |= (RPUM_LOW_EN | RDM_UP_EN);
+ writel_relaxed(reg, qphy->base + QUSB2PHY_PORT_QC2);
+
+ reg = readl_relaxed(qphy->base + QUSB2PHY_PORT_QC1);
+ reg &= ~VDM_SRC_EN;
+ writel_relaxed(reg, qphy->base + QUSB2PHY_PORT_QC1);
+
+ /* complete above write */
+ mb();
+ spin_unlock_irqrestore(&qphy->pulse_lock, flags);
+
+ /*
+ * It is recommended to wait here to get voltage change on
+ * DP/DM line.
+ */
+ usleep_range(2000, 3000);
+ clk_disable_unprepare(qphy->cfg_ahb_clk);
+ break;
default:
ret = -EINVAL;
dev_err(phy->dev, "Invalid power supply property(%d)\n", value);
break;
}
+clk_error:
return ret;
}
+static int qusb_phy_get_property_usb(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ return -EINVAL;
+}
+
+static int qusb_phy_set_property_usb(struct power_supply *psy,
+ enum power_supply_property prop,
+ const union power_supply_propval *val)
+{
+ struct qusb_phy *qphy = power_supply_get_drvdata(psy);
+ int ret = 0;
+
+ switch (prop) {
+ case POWER_SUPPLY_PROP_DP_DM:
+ ret = qusb_phy_update_dpdm(&qphy->phy, val->intval);
+ if (ret) {
+ dev_dbg(qphy->phy.dev, "error in dpdm update: %d\n",
+ ret);
+ return ret;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static void qusb_phy_get_tune2_param(struct qusb_phy *qphy)
{
u8 num_of_bits;
@@ -692,6 +906,83 @@ static void qusb_phy_shutdown(struct usb_phy *phy)
qusb_phy_enable_clocks(qphy, false);
}
+
+/**
+ * Returns DP/DM linestate with Idp_src enabled to detect if lines are floating
+ *
+ * @uphy - usb phy pointer.
+ *
+ */
+static int qusb_phy_linestate_with_idp_src(struct usb_phy *phy)
+{
+ struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy);
+ u8 int_status, ret;
+
+ /* Disable/powerdown the PHY */
+ writel_relaxed(CLAMP_N_EN | FREEZIO_N | POWER_DOWN,
+ qphy->base + QUSB2PHY_PORT_POWERDOWN);
+
+ /* Put PHY in non-driving mode */
+ writel_relaxed(TERM_SELECT | XCVR_SELECT_FS | OP_MODE_NON_DRIVE |
+ SUSPEND_N, qphy->base + QUSB2PHY_PORT_UTMI_CTRL1);
+
+ /* Switch PHY to utmi register mode */
+ writel_relaxed(UTMI_ULPI_SEL | UTMI_TEST_MUX_SEL,
+ qphy->base + QUSB2PHY_PORT_UTMI_CTRL2);
+
+ writel_relaxed(PLL_RESET_N_CNT_5,
+ qphy->base + QUSB2PHY_PLL_AUTOPGM_CTL1);
+
+ /* Enable PHY */
+ writel_relaxed(CLAMP_N_EN | FREEZIO_N,
+ qphy->base + QUSB2PHY_PORT_POWERDOWN);
+
+ writel_relaxed(REF_BUF_EN | REXT_EN | PLL_BYPASSNL | REXT_TRIM_0,
+ qphy->base + QUSB2PHY_PLL_PWR_CTL);
+
+ usleep_range(5, 1000);
+
+ writel_relaxed(PLL_RESET_N | PLL_RESET_N_CNT_5,
+ qphy->base + QUSB2PHY_PLL_AUTOPGM_CTL1);
+ usleep_range(50, 1000);
+
+ writel_relaxed(0x00, qphy->base + QUSB2PHY_PORT_QC1);
+ writel_relaxed(0x00, qphy->base + QUSB2PHY_PORT_QC2);
+
+ /* Enable all chg_det events from PHY */
+ writel_relaxed(0x1F, qphy->base + QUSB2PHY_PORT_INTR_CTRL);
+ /* Enable Idp_src */
+ writel_relaxed(IDP_SRC_EN, qphy->base + QUSB2PHY_PORT_QC1);
+
+ usleep_range(1000, 2000);
+ int_status = readl_relaxed(qphy->base + QUSB2PHY_PORT_INT_STATUS);
+
+ /* Exit chg_det mode, set PHY regs to default values */
+ writel_relaxed(CLAMP_N_EN | FREEZIO_N | POWER_DOWN,
+ qphy->base + QUSB2PHY_PORT_POWERDOWN); /* 23 */
+
+ writel_relaxed(PLL_AUTOPGM_EN | PLL_RESET_N | PLL_RESET_N_CNT_5,
+ qphy->base + QUSB2PHY_PLL_AUTOPGM_CTL1);
+
+ writel_relaxed(UTMI_ULPI_SEL, qphy->base + QUSB2PHY_PORT_UTMI_CTRL2);
+
+ writel_relaxed(TERM_SELECT, qphy->base + QUSB2PHY_PORT_UTMI_CTRL1);
+
+ writel_relaxed(CLAMP_N_EN | FREEZIO_N,
+ qphy->base + QUSB2PHY_PORT_POWERDOWN);
+
+ int_status = int_status & 0x5;
+
+ /*
+ * int_status's Bit(0) is DP and Bit(2) is DM.
+ * Caller expects bit(1) as DP and bit(0) DM i.e. usual linestate format
+ */
+ ret = (int_status >> 2) | ((int_status & 0x1) << 1);
+ pr_debug("%s: int_status:%x, dpdm:%x\n", __func__, int_status, ret);
+
+ return ret;
+}
+
/**
* Performs QUSB2 PHY suspend/resume functionality.
*
@@ -902,6 +1193,7 @@ static int qusb_phy_probe(struct platform_device *pdev)
int ret = 0, size = 0;
const char *phy_type;
bool hold_phy_reset;
+ struct power_supply_config dpdm_cfg = {};
qphy = devm_kzalloc(dev, sizeof(*qphy), GFP_KERNEL);
if (!qphy)
@@ -1141,6 +1433,7 @@ static int qusb_phy_probe(struct platform_device *pdev)
}
mutex_init(&qphy->phy_lock);
+ spin_lock_init(&qphy->pulse_lock);
platform_set_drvdata(pdev, qphy);
qphy->phy.label = "msm-qusb-phy";
@@ -1150,6 +1443,7 @@ static int qusb_phy_probe(struct platform_device *pdev)
qphy->phy.type = USB_PHY_TYPE_USB2;
qphy->phy.notify_connect = qusb_phy_notify_connect;
qphy->phy.notify_disconnect = qusb_phy_notify_disconnect;
+ qphy->phy.dpdm_with_idp_src = qusb_phy_linestate_with_idp_src;
/*
* On some platforms multiple QUSB PHYs are available. If QUSB PHY is
@@ -1162,25 +1456,57 @@ static int qusb_phy_probe(struct platform_device *pdev)
dev_err(dev, "%s:phy_reset assert failed\n", __func__);
}
+ qphy->dpdm_pulsing_enabled = of_property_read_bool(dev->of_node,
+ "qcom,enable-dpdm-pulsing");
+
+ if (qphy->dpdm_pulsing_enabled) {
+ qphy->dpdm_psy_desc.name = "dpdm";
+ qphy->dpdm_psy_desc.type = POWER_SUPPLY_TYPE_USB;
+ qphy->dpdm_psy_desc.properties = dpdm_props;
+ qphy->dpdm_psy_desc.num_properties = ARRAY_SIZE(dpdm_props);
+ qphy->dpdm_psy_desc.set_property = qusb_phy_set_property_usb;
+ qphy->dpdm_psy_desc.get_property = qusb_phy_get_property_usb;
+
+ dpdm_cfg.drv_data = qphy;
+ dpdm_cfg.of_node = dev->of_node;
+ qphy->dpdm_psy = power_supply_register(&pdev->dev,
+ &qphy->dpdm_psy_desc, &dpdm_cfg);
+ if (IS_ERR(qphy->dpdm_psy)) {
+ dev_err(&pdev->dev, "%s:dpdm power_supply_register failed\n",
+ __func__);
+ return PTR_ERR(qphy->dpdm_psy);
+ }
+ }
+
ret = usb_add_phy_dev(&qphy->phy);
if (ret)
- return ret;
+ goto unregister_psy;
ret = qusb_phy_regulator_init(qphy);
if (ret)
- usb_remove_phy(&qphy->phy);
+ goto remove_phy;
/* de-assert clamp dig n to reduce leakage on 1p8 upon boot up */
if (qphy->tcsr_clamp_dig_n)
writel_relaxed(0x0, qphy->tcsr_clamp_dig_n);
return ret;
+
+remove_phy:
+ usb_remove_phy(&qphy->phy);
+unregister_psy:
+ if (qphy->dpdm_psy)
+ power_supply_unregister(qphy->dpdm_psy);
+
+ return ret;
}
static int qusb_phy_remove(struct platform_device *pdev)
{
struct qusb_phy *qphy = platform_get_drvdata(pdev);
+ if (qphy->dpdm_psy)
+ power_supply_unregister(qphy->dpdm_psy);
usb_remove_phy(&qphy->phy);
if (qphy->clocks_enabled) {
diff --git a/include/linux/usb/phy.h b/include/linux/usb/phy.h
index d25125402fda..f066d65ac3dd 100644
--- a/include/linux/usb/phy.h
+++ b/include/linux/usb/phy.h
@@ -126,6 +126,9 @@ struct usb_phy {
/* reset the PHY clocks */
int (*reset)(struct usb_phy *x);
+
+ /* return linestate with Idp_src (used for DCD with USB2 PHY) */
+ int (*dpdm_with_idp_src)(struct usb_phy *x);
};
/**
@@ -209,6 +212,15 @@ usb_phy_reset(struct usb_phy *x)
return 0;
}
+static inline int
+usb_phy_dpdm_with_idp_src(struct usb_phy *x)
+{
+ if (x && x->dpdm_with_idp_src)
+ return x->dpdm_with_idp_src(x);
+
+ return 0;
+}
+
/* for usb host and peripheral controller drivers */
#if IS_ENABLED(CONFIG_USB_PHY)
extern struct usb_phy *usb_get_phy(enum usb_phy_type type);
diff --git a/include/uapi/linux/virtio_ids.h b/include/uapi/linux/virtio_ids.h
index 3228d582234a..4914c3037a03 100644
--- a/include/uapi/linux/virtio_ids.h
+++ b/include/uapi/linux/virtio_ids.h
@@ -43,4 +43,6 @@
#define VIRTIO_ID_INPUT 18 /* virtio input */
#define VIRTIO_ID_VSOCK 19 /* virtio vsock transport */
+#define VIRTIO_ID_I2C 32 /* virtio i2c */
+
#endif /* _LINUX_VIRTIO_IDS_H */
diff --git a/net/core/sockev_nlmcast.c b/net/core/sockev_nlmcast.c
index 1e92c5632b97..0a8b0ed99356 100644
--- a/net/core/sockev_nlmcast.c
+++ b/net/core/sockev_nlmcast.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2015, 2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2015, 2018-2019 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
@@ -73,11 +73,13 @@ static int sockev_client_cb(struct notifier_block *nb,
sock = (struct socket *)data;
if (!socknlmsgsk || !sock)
- goto done;
+ goto sk_null;
sk = sock->sk;
if (!sk)
- goto done;
+ goto sk_null;
+
+ sock_hold(sk);
if (sk->sk_family != AF_INET && sk->sk_family != AF_INET6)
goto done;
@@ -108,6 +110,8 @@ static int sockev_client_cb(struct notifier_block *nb,
smsg->skflags = sk->sk_flags;
nlmsg_notify(socknlmsgsk, skb, 0, SKNLGRP_SOCKEV, 0, GFP_KERNEL);
done:
+ sock_put(sk);
+sk_null:
return 0;
}
diff --git a/sound/soc/msm/msm8998.c b/sound/soc/msm/msm8998.c
index 1e97a0cd76ac..1c1f65fb3f5c 100644
--- a/sound/soc/msm/msm8998.c
+++ b/sound/soc/msm/msm8998.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2019, 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
@@ -72,8 +72,8 @@
#define WCN_CDC_SLIM_RX_CH_MAX 2
#define WCN_CDC_SLIM_TX_CH_MAX 3
-#define TDM_CHANNEL_MAX 8
-#define TDM_SLOT_OFFSET_MAX 8
+#define TDM_CHANNEL_MAX 16
+#define TDM_SLOT_OFFSET_MAX 32
#define MSM_HIFI_ON 1
@@ -396,6 +396,117 @@ static struct dev_config aux_pcm_tx_cfg[] = {
[QUAT_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
};
+/* TDM default slot config */
+struct tdm_slot_cfg {
+ u32 width;
+ u32 num;
+};
+
+static struct tdm_slot_cfg tdm_slot[TDM_INTERFACE_MAX] = {
+ /* PRI TDM */
+ {32, 8},
+ /* SEC TDM */
+ {32, 8},
+ /* TERT TDM */
+ {32, 8},
+ /* QUAT TDM */
+ {32, 8}
+};
+
+static unsigned int tdm_rx_slot_offset
+ [TDM_INTERFACE_MAX][TDM_PORT_MAX][TDM_SLOT_OFFSET_MAX] = {
+ {/* PRI TDM */
+ {0, 4, 8, 12, 16, 20, 24, 28,
+ 32, 36, 40, 44, 48, 52, 56, 60, 0xFFFF},
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ },
+ {/* SEC TDM */
+ {0, 4, 8, 12, 16, 20, 24, 28,
+ 32, 36, 40, 44, 48, 52, 56, 60, 0xFFFF},
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ },
+ {/* TERT TDM */
+ {0, 4, 8, 12, 16, 20, 24, 28,
+ 32, 36, 40, 44, 48, 52, 56, 60, 0xFFFF},
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ },
+ {/* QUAT TDM */
+ {0, 4, 8, 12, 16, 20, 24, 28,
+ 32, 36, 40, 44, 48, 52, 56, 60, 0xFFFF},
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ }
+};
+
+static unsigned int tdm_tx_slot_offset
+ [TDM_INTERFACE_MAX][TDM_PORT_MAX][TDM_SLOT_OFFSET_MAX] = {
+ {/* PRI TDM */
+ {0, 4, 8, 12, 16, 20, 24, 28,
+ 32, 36, 40, 44, 48, 52, 56, 60, 0xFFFF},
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ },
+ {/* SEC TDM */
+ {0, 4, 8, 12, 16, 20, 24, 28,
+ 32, 36, 40, 44, 48, 52, 56, 60, 0xFFFF},
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ },
+ {/* TERT TDM */
+ {0, 4, 8, 12, 16, 20, 24, 28,
+ 32, 36, 40, 44, 48, 52, 56, 60, 0xFFFF},
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ },
+ {/* QUAT TDM */
+ {0, 4, 8, 12, 16, 20, 24, 28,
+ 32, 36, 40, 44, 48, 52, 56, 60, 0xFFFF},/*MIC ARR*/
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ }
+};
static int msm_vi_feed_tx_ch = 2;
static const char *const slim_rx_ch_text[] = {"One", "Two", "Three", "Four",
"Five", "Six", "Seven",
@@ -428,11 +539,17 @@ static char const *ext_disp_sample_rate_text[] = {"KHZ_48", "KHZ_96",
"KHZ_192", "KHZ_32", "KHZ_44P1",
"KHZ_88P2", "KHZ_176P4"};
static char const *tdm_ch_text[] = {"One", "Two", "Three", "Four",
- "Five", "Six", "Seven", "Eight"};
+ "Five", "Six", "Seven", "Eight",
+ "Nine", "Ten", "Eleven", "Twelve",
+ "Thirteen", "Fourteen", "Fifteen",
+ "Sixteen"};
static char const *tdm_bit_format_text[] = {"S16_LE", "S24_LE", "S32_LE"};
static char const *tdm_sample_rate_text[] = {"KHZ_8", "KHZ_16", "KHZ_32",
"KHZ_44P1", "KHZ_48", "KHZ_96",
"KHZ_192", "KHZ_352P8", "KHZ_384"};
+static const char *const tdm_slot_num_text[] = {"One", "Two", "Four",
+ "Eight", "Sixteen", "ThirtyTwo"};
+static const char *const tdm_slot_width_text[] = {"16", "24", "32"};
static const char *const auxpcm_rate_text[] = {"KHZ_8", "KHZ_16"};
static char const *mi2s_rate_text[] = {"KHZ_8", "KHZ_16",
"KHZ_32", "KHZ_44P1", "KHZ_48",
@@ -479,6 +596,8 @@ static SOC_ENUM_SINGLE_EXT_DECL(tdm_tx_sample_rate, tdm_sample_rate_text);
static SOC_ENUM_SINGLE_EXT_DECL(tdm_rx_chs, tdm_ch_text);
static SOC_ENUM_SINGLE_EXT_DECL(tdm_rx_format, tdm_bit_format_text);
static SOC_ENUM_SINGLE_EXT_DECL(tdm_rx_sample_rate, tdm_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tdm_slot_num, tdm_slot_num_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tdm_slot_width, tdm_slot_width_text);
static SOC_ENUM_SINGLE_EXT_DECL(prim_aux_pcm_rx_sample_rate, auxpcm_rate_text);
static SOC_ENUM_SINGLE_EXT_DECL(sec_aux_pcm_rx_sample_rate, auxpcm_rate_text);
static SOC_ENUM_SINGLE_EXT_DECL(tert_aux_pcm_rx_sample_rate, auxpcm_rate_text);
@@ -1812,73 +1931,95 @@ static int aux_pcm_get_sample_rate_val(int sample_rate)
return sample_rate_val;
}
+static int tdm_get_mode(struct snd_kcontrol *kcontrol)
+{
+ int mode;
+
+ if (strnstr(kcontrol->id.name, "PRI",
+ sizeof(kcontrol->id.name))) {
+ mode = TDM_PRI;
+ } else if (strnstr(kcontrol->id.name, "SEC",
+ sizeof(kcontrol->id.name))) {
+ mode = TDM_SEC;
+ } else if (strnstr(kcontrol->id.name, "TERT",
+ sizeof(kcontrol->id.name))) {
+ mode = TDM_TERT;
+ } else if (strnstr(kcontrol->id.name, "QUAT",
+ sizeof(kcontrol->id.name))) {
+ mode = TDM_QUAT;
+ } else {
+ pr_err("%s: unsupported mode in: %s",
+ __func__, kcontrol->id.name);
+ mode = -EINVAL;
+ }
+
+ return mode;
+}
+
+static int tdm_get_channel(struct snd_kcontrol *kcontrol)
+{
+ int channel;
+
+ if (strnstr(kcontrol->id.name, "RX_0",
+ sizeof(kcontrol->id.name)) ||
+ strnstr(kcontrol->id.name, "TX_0",
+ sizeof(kcontrol->id.name))) {
+ channel = TDM_0;
+ } else if (strnstr(kcontrol->id.name, "RX_1",
+ sizeof(kcontrol->id.name)) ||
+ strnstr(kcontrol->id.name, "TX_1",
+ sizeof(kcontrol->id.name))) {
+ channel = TDM_1;
+ } else if (strnstr(kcontrol->id.name, "RX_2",
+ sizeof(kcontrol->id.name)) ||
+ strnstr(kcontrol->id.name, "TX_2",
+ sizeof(kcontrol->id.name))) {
+ channel = TDM_2;
+ } else if (strnstr(kcontrol->id.name, "RX_3",
+ sizeof(kcontrol->id.name)) ||
+ strnstr(kcontrol->id.name, "TX_3",
+ sizeof(kcontrol->id.name))) {
+ channel = TDM_3;
+ } else if (strnstr(kcontrol->id.name, "RX_4",
+ sizeof(kcontrol->id.name)) ||
+ strnstr(kcontrol->id.name, "TX_4",
+ sizeof(kcontrol->id.name))) {
+ channel = TDM_4;
+ } else if (strnstr(kcontrol->id.name, "RX_5",
+ sizeof(kcontrol->id.name)) ||
+ strnstr(kcontrol->id.name, "TX_5",
+ sizeof(kcontrol->id.name))) {
+ channel = TDM_5;
+ } else if (strnstr(kcontrol->id.name, "RX_6",
+ sizeof(kcontrol->id.name)) ||
+ strnstr(kcontrol->id.name, "TX_6",
+ sizeof(kcontrol->id.name))) {
+ channel = TDM_6;
+ } else if (strnstr(kcontrol->id.name, "RX_7",
+ sizeof(kcontrol->id.name)) ||
+ strnstr(kcontrol->id.name, "TX_7",
+ sizeof(kcontrol->id.name))) {
+ channel = TDM_7;
+ } else {
+ pr_err("%s: unsupported channel in: %s",
+ __func__, kcontrol->id.name);
+ channel = -EINVAL;
+ }
+
+ return channel;
+}
+
static int tdm_get_port_idx(struct snd_kcontrol *kcontrol,
struct tdm_port *port)
{
if (port) {
- if (strnstr(kcontrol->id.name, "PRI",
- sizeof(kcontrol->id.name))) {
- port->mode = TDM_PRI;
- } else if (strnstr(kcontrol->id.name, "SEC",
- sizeof(kcontrol->id.name))) {
- port->mode = TDM_SEC;
- } else if (strnstr(kcontrol->id.name, "TERT",
- sizeof(kcontrol->id.name))) {
- port->mode = TDM_TERT;
- } else if (strnstr(kcontrol->id.name, "QUAT",
- sizeof(kcontrol->id.name))) {
- port->mode = TDM_QUAT;
- } else {
- pr_err("%s: unsupported mode in: %s",
- __func__, kcontrol->id.name);
- return -EINVAL;
- }
+ port->mode = tdm_get_mode(kcontrol);
+ if (port->mode < 0)
+ return port->mode;
- if (strnstr(kcontrol->id.name, "RX_0",
- sizeof(kcontrol->id.name)) ||
- strnstr(kcontrol->id.name, "TX_0",
- sizeof(kcontrol->id.name))) {
- port->channel = TDM_0;
- } else if (strnstr(kcontrol->id.name, "RX_1",
- sizeof(kcontrol->id.name)) ||
- strnstr(kcontrol->id.name, "TX_1",
- sizeof(kcontrol->id.name))) {
- port->channel = TDM_1;
- } else if (strnstr(kcontrol->id.name, "RX_2",
- sizeof(kcontrol->id.name)) ||
- strnstr(kcontrol->id.name, "TX_2",
- sizeof(kcontrol->id.name))) {
- port->channel = TDM_2;
- } else if (strnstr(kcontrol->id.name, "RX_3",
- sizeof(kcontrol->id.name)) ||
- strnstr(kcontrol->id.name, "TX_3",
- sizeof(kcontrol->id.name))) {
- port->channel = TDM_3;
- } else if (strnstr(kcontrol->id.name, "RX_4",
- sizeof(kcontrol->id.name)) ||
- strnstr(kcontrol->id.name, "TX_4",
- sizeof(kcontrol->id.name))) {
- port->channel = TDM_4;
- } else if (strnstr(kcontrol->id.name, "RX_5",
- sizeof(kcontrol->id.name)) ||
- strnstr(kcontrol->id.name, "TX_5",
- sizeof(kcontrol->id.name))) {
- port->channel = TDM_5;
- } else if (strnstr(kcontrol->id.name, "RX_6",
- sizeof(kcontrol->id.name)) ||
- strnstr(kcontrol->id.name, "TX_6",
- sizeof(kcontrol->id.name))) {
- port->channel = TDM_6;
- } else if (strnstr(kcontrol->id.name, "RX_7",
- sizeof(kcontrol->id.name)) ||
- strnstr(kcontrol->id.name, "TX_7",
- sizeof(kcontrol->id.name))) {
- port->channel = TDM_7;
- } else {
- pr_err("%s: unsupported channel in: %s",
- __func__, kcontrol->id.name);
- return -EINVAL;
- }
+ port->channel = tdm_get_channel(kcontrol);
+ if (port->channel < 0)
+ return port->channel;
} else
return -EINVAL;
return 0;
@@ -2167,6 +2308,316 @@ static int tdm_tx_ch_put(struct snd_kcontrol *kcontrol,
return ret;
}
+static int tdm_get_slot_num_val(int slot_num)
+{
+ int slot_num_val;
+
+ switch (slot_num) {
+ case 1:
+ slot_num_val = 0;
+ break;
+ case 2:
+ slot_num_val = 1;
+ break;
+ case 4:
+ slot_num_val = 2;
+ break;
+ case 8:
+ slot_num_val = 3;
+ break;
+ case 16:
+ slot_num_val = 4;
+ break;
+ case 32:
+ slot_num_val = 5;
+ break;
+ default:
+ slot_num_val = 5;
+ break;
+ }
+ return slot_num_val;
+}
+
+static int tdm_slot_num_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int mode = tdm_get_mode(kcontrol);
+
+ if (mode < 0) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ return mode;
+ }
+
+ ucontrol->value.enumerated.item[0] =
+ tdm_get_slot_num_val(tdm_slot[mode].num);
+
+ pr_debug("%s: mode = %d, tdm_slot_num = %d, item = %d\n", __func__,
+ mode, tdm_slot[mode].num,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int tdm_get_slot_num(int value)
+{
+ int slot_num;
+
+ switch (value) {
+ case 0:
+ slot_num = 1;
+ break;
+ case 1:
+ slot_num = 2;
+ break;
+ case 2:
+ slot_num = 4;
+ break;
+ case 3:
+ slot_num = 8;
+ break;
+ case 4:
+ slot_num = 16;
+ break;
+ case 5:
+ slot_num = 32;
+ break;
+ default:
+ slot_num = 8;
+ break;
+ }
+ return slot_num;
+}
+
+static int tdm_slot_num_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int mode = tdm_get_mode(kcontrol);
+
+ if (mode < 0) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ return mode;
+ }
+
+ tdm_slot[mode].num =
+ tdm_get_slot_num(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: mode = %d, tdm_slot_num = %d, item = %d\n", __func__,
+ mode, tdm_slot[mode].num,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int tdm_get_slot_width_val(int slot_width)
+{
+ int slot_width_val;
+
+ switch (slot_width) {
+ case 16:
+ slot_width_val = 0;
+ break;
+ case 24:
+ slot_width_val = 1;
+ break;
+ case 32:
+ slot_width_val = 2;
+ break;
+ default:
+ slot_width_val = 2;
+ break;
+ }
+ return slot_width_val;
+}
+
+static int tdm_slot_width_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int mode = tdm_get_mode(kcontrol);
+
+ if (mode < 0) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ return mode;
+ }
+
+ ucontrol->value.enumerated.item[0] =
+ tdm_get_slot_width_val(tdm_slot[mode].width);
+
+ pr_debug("%s: mode = %d, tdm_slot_width = %d, item = %d\n", __func__,
+ mode, tdm_slot[mode].width,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int tdm_get_slot_width(int value)
+{
+ int slot_width;
+
+ switch (value) {
+ case 0:
+ slot_width = 16;
+ break;
+ case 1:
+ slot_width = 24;
+ break;
+ case 2:
+ slot_width = 32;
+ break;
+ default:
+ slot_width = 32;
+ break;
+ }
+ return slot_width;
+}
+
+static int tdm_slot_width_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int mode = tdm_get_mode(kcontrol);
+
+ if (mode < 0) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ return mode;
+ }
+
+ tdm_slot[mode].width =
+ tdm_get_slot_width(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: mode = %d, tdm_slot_width = %d, item = %d\n", __func__,
+ mode, tdm_slot[mode].width,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int tdm_rx_slot_mapping_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ unsigned int *slot_offset;
+ int i;
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ } else {
+ if (port.mode < TDM_INTERFACE_MAX &&
+ port.channel < TDM_PORT_MAX) {
+ slot_offset =
+ tdm_rx_slot_offset[port.mode][port.channel];
+ pr_debug("%s: mode = %d, channel = %d\n",
+ __func__, port.mode, port.channel);
+ for (i = 0; i < TDM_SLOT_OFFSET_MAX; i++) {
+ ucontrol->value.integer.value[i] =
+ slot_offset[i];
+ pr_debug("%s: offset %d, value %d\n",
+ __func__, i, slot_offset[i]);
+ }
+ } else {
+ pr_err("%s: unsupported mode/channel", __func__);
+ }
+ }
+ return ret;
+}
+
+static int tdm_rx_slot_mapping_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ unsigned int *slot_offset;
+ int i;
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ } else {
+ if (port.mode < TDM_INTERFACE_MAX &&
+ port.channel < TDM_PORT_MAX) {
+ slot_offset =
+ tdm_rx_slot_offset[port.mode][port.channel];
+ pr_debug("%s: mode = %d, channel = %d\n",
+ __func__, port.mode, port.channel);
+ for (i = 0; i < TDM_SLOT_OFFSET_MAX; i++) {
+ slot_offset[i] =
+ ucontrol->value.integer.value[i];
+ pr_debug("%s: offset %d, value %d\n",
+ __func__, i, slot_offset[i]);
+ }
+ } else {
+ pr_err("%s: unsupported mode/channel", __func__);
+ }
+ }
+ return ret;
+}
+
+static int tdm_tx_slot_mapping_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ unsigned int *slot_offset;
+ int i;
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ } else {
+ if (port.mode < TDM_INTERFACE_MAX &&
+ port.channel < TDM_PORT_MAX) {
+ slot_offset =
+ tdm_tx_slot_offset[port.mode][port.channel];
+ pr_debug("%s: mode = %d, channel = %d\n",
+ __func__, port.mode, port.channel);
+ for (i = 0; i < TDM_SLOT_OFFSET_MAX; i++) {
+ ucontrol->value.integer.value[i] =
+ slot_offset[i];
+ pr_debug("%s: offset %d, value %d\n",
+ __func__, i, slot_offset[i]);
+ }
+ } else {
+ pr_err("%s: unsupported mode/channel", __func__);
+ }
+ }
+ return ret;
+}
+
+static int tdm_tx_slot_mapping_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ unsigned int *slot_offset;
+ int i;
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s",
+ __func__, kcontrol->id.name);
+ } else {
+ if (port.mode < TDM_INTERFACE_MAX &&
+ port.channel < TDM_PORT_MAX) {
+ slot_offset =
+ tdm_tx_slot_offset[port.mode][port.channel];
+ pr_debug("%s: mode = %d, channel = %d\n",
+ __func__, port.mode, port.channel);
+ for (i = 0; i < TDM_SLOT_OFFSET_MAX; i++) {
+ slot_offset[i] =
+ ucontrol->value.integer.value[i];
+ pr_debug("%s: offset %d, value %d\n",
+ __func__, i, slot_offset[i]);
+ }
+ } else {
+ pr_err("%s: unsupported mode/channel", __func__);
+ }
+ }
+ return ret;
+}
+
static int aux_pcm_get_port_idx(struct snd_kcontrol *kcontrol)
{
int idx;
@@ -2825,6 +3276,214 @@ static const struct snd_kcontrol_new msm_snd_controls[] = {
SOC_ENUM_EXT("QUAT_TDM_TX_0 Channels", tdm_tx_chs,
tdm_tx_ch_get,
tdm_tx_ch_put),
+ SOC_ENUM_EXT("PRI_TDM SlotNumber", tdm_slot_num,
+ tdm_slot_num_get, tdm_slot_num_put),
+ SOC_ENUM_EXT("PRI_TDM SlotWidth", tdm_slot_width,
+ tdm_slot_width_get, tdm_slot_width_put),
+ SOC_ENUM_EXT("SEC_TDM SlotNumber", tdm_slot_num,
+ tdm_slot_num_get, tdm_slot_num_put),
+ SOC_ENUM_EXT("SEC_TDM SlotWidth", tdm_slot_width,
+ tdm_slot_width_get, tdm_slot_width_put),
+ SOC_ENUM_EXT("TERT_TDM SlotNumber", tdm_slot_num,
+ tdm_slot_num_get, tdm_slot_num_put),
+ SOC_ENUM_EXT("TERT_TDM SlotWidth", tdm_slot_width,
+ tdm_slot_width_get, tdm_slot_width_put),
+ SOC_ENUM_EXT("QUAT_TDM SlotNumber", tdm_slot_num,
+ tdm_slot_num_get, tdm_slot_num_put),
+ SOC_ENUM_EXT("QUAT_TDM SlotWidth", tdm_slot_width,
+ tdm_slot_width_get, tdm_slot_width_put),
+ SOC_SINGLE_MULTI_EXT("PRI_TDM_RX_0 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_rx_slot_mapping_get, tdm_rx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("PRI_TDM_RX_1 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_rx_slot_mapping_get, tdm_rx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("PRI_TDM_RX_2 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_rx_slot_mapping_get, tdm_rx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("PRI_TDM_RX_3 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_rx_slot_mapping_get, tdm_rx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("PRI_TDM_RX_4 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_rx_slot_mapping_get, tdm_rx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("PRI_TDM_RX_5 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_rx_slot_mapping_get, tdm_rx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("PRI_TDM_RX_6 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_rx_slot_mapping_get, tdm_rx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("PRI_TDM_RX_7 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_rx_slot_mapping_get, tdm_rx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("PRI_TDM_TX_0 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_tx_slot_mapping_get, tdm_tx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("PRI_TDM_TX_1 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_tx_slot_mapping_get, tdm_tx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("PRI_TDM_TX_2 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_tx_slot_mapping_get, tdm_tx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("PRI_TDM_TX_3 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_tx_slot_mapping_get, tdm_tx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("PRI_TDM_TX_4 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_tx_slot_mapping_get, tdm_tx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("PRI_TDM_TX_5 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_tx_slot_mapping_get, tdm_tx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("PRI_TDM_TX_6 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_tx_slot_mapping_get, tdm_tx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("PRI_TDM_TX_7 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_tx_slot_mapping_get, tdm_tx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("SEC_TDM_RX_0 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_rx_slot_mapping_get, tdm_rx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("SEC_TDM_RX_1 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_rx_slot_mapping_get, tdm_rx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("SEC_TDM_RX_2 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_rx_slot_mapping_get, tdm_rx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("SEC_TDM_RX_3 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_rx_slot_mapping_get, tdm_rx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("SEC_TDM_RX_4 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_rx_slot_mapping_get, tdm_rx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("SEC_TDM_RX_5 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_rx_slot_mapping_get, tdm_rx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("SEC_TDM_RX_6 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_rx_slot_mapping_get, tdm_rx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("SEC_TDM_RX_7 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_rx_slot_mapping_get, tdm_rx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("SEC_TDM_TX_0 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_tx_slot_mapping_get, tdm_tx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("SEC_TDM_TX_1 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_tx_slot_mapping_get, tdm_tx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("SEC_TDM_TX_2 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_tx_slot_mapping_get, tdm_tx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("SEC_TDM_TX_3 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_tx_slot_mapping_get, tdm_tx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("SEC_TDM_TX_4 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_tx_slot_mapping_get, tdm_tx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("SEC_TDM_TX_5 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_tx_slot_mapping_get, tdm_tx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("SEC_TDM_TX_6 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_tx_slot_mapping_get, tdm_tx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("SEC_TDM_TX_7 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_tx_slot_mapping_get, tdm_tx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("TERT_TDM_RX_0 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_rx_slot_mapping_get, tdm_rx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("TERT_TDM_RX_1 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_rx_slot_mapping_get, tdm_rx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("TERT_TDM_RX_2 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_rx_slot_mapping_get, tdm_rx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("TERT_TDM_RX_3 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_rx_slot_mapping_get, tdm_rx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("TERT_TDM_RX_4 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_rx_slot_mapping_get, tdm_rx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("TERT_TDM_RX_5 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_rx_slot_mapping_get, tdm_rx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("TERT_TDM_RX_6 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_rx_slot_mapping_get, tdm_rx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("TERT_TDM_RX_7 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_rx_slot_mapping_get, tdm_rx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("TERT_TDM_TX_0 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_tx_slot_mapping_get, tdm_tx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("TERT_TDM_TX_1 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_tx_slot_mapping_get, tdm_tx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("TERT_TDM_TX_2 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_tx_slot_mapping_get, tdm_tx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("TERT_TDM_TX_3 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_tx_slot_mapping_get, tdm_tx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("TERT_TDM_TX_4 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_tx_slot_mapping_get, tdm_tx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("TERT_TDM_TX_5 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_tx_slot_mapping_get, tdm_tx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("TERT_TDM_TX_6 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_tx_slot_mapping_get, tdm_tx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("TERT_TDM_TX_7 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_tx_slot_mapping_get, tdm_tx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("QUAT_TDM_RX_0 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_rx_slot_mapping_get, tdm_rx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("QUAT_TDM_RX_1 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_rx_slot_mapping_get, tdm_rx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("QUAT_TDM_RX_2 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_rx_slot_mapping_get, tdm_rx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("QUAT_TDM_RX_3 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_rx_slot_mapping_get, tdm_rx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("QUAT_TDM_RX_4 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_rx_slot_mapping_get, tdm_rx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("QUAT_TDM_RX_5 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_rx_slot_mapping_get, tdm_rx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("QUAT_TDM_RX_6 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_rx_slot_mapping_get, tdm_rx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("QUAT_TDM_RX_7 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_rx_slot_mapping_get, tdm_rx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("QUAT_TDM_TX_0 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_tx_slot_mapping_get, tdm_tx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("QUAT_TDM_TX_1 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_tx_slot_mapping_get, tdm_tx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("QUAT_TDM_TX_2 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_tx_slot_mapping_get, tdm_tx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("QUAT_TDM_TX_3 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_tx_slot_mapping_get, tdm_tx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("QUAT_TDM_TX_4 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_tx_slot_mapping_get, tdm_tx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("QUAT_TDM_TX_5 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_tx_slot_mapping_get, tdm_tx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("QUAT_TDM_TX_6 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_tx_slot_mapping_get, tdm_tx_slot_mapping_put),
+ SOC_SINGLE_MULTI_EXT("QUAT_TDM_TX_7 SlotMapping",
+ SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
+ tdm_tx_slot_mapping_get, tdm_tx_slot_mapping_put),
SOC_ENUM_EXT("PRIM_AUX_PCM_RX SampleRate", prim_aux_pcm_rx_sample_rate,
aux_pcm_rx_sample_rate_get,
aux_pcm_rx_sample_rate_put),
@@ -4478,21 +5137,520 @@ static int msm_tdm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
SNDRV_PCM_HW_PARAM_RATE);
struct snd_interval *channels = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS);
-
- if (cpu_dai->id == AFE_PORT_ID_QUATERNARY_TDM_RX) {
+ switch (cpu_dai->id) {
+ case AFE_PORT_ID_PRIMARY_TDM_RX:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_PRI][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_PRI][TDM_0].bit_format);
+ rate->min = rate->max =
+ tdm_rx_cfg[TDM_PRI][TDM_0].sample_rate;
+ break;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_1:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_PRI][TDM_1].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_PRI][TDM_1].bit_format);
+ rate->min = rate->max =
+ tdm_rx_cfg[TDM_PRI][TDM_1].sample_rate;
+ break;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_2:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_PRI][TDM_2].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_PRI][TDM_2].bit_format);
+ rate->min = rate->max =
+ tdm_rx_cfg[TDM_PRI][TDM_2].sample_rate;
+ break;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_3:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_PRI][TDM_3].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_PRI][TDM_3].bit_format);
+ rate->min = rate->max =
+ tdm_rx_cfg[TDM_PRI][TDM_3].sample_rate;
+ break;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_4:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_PRI][TDM_4].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_PRI][TDM_4].bit_format);
+ rate->min = rate->max =
+ tdm_rx_cfg[TDM_PRI][TDM_4].sample_rate;
+ break;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_5:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_PRI][TDM_5].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_PRI][TDM_5].bit_format);
+ rate->min = rate->max =
+ tdm_rx_cfg[TDM_PRI][TDM_5].sample_rate;
+ break;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_6:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_PRI][TDM_6].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_PRI][TDM_6].bit_format);
+ rate->min = rate->max =
+ tdm_rx_cfg[TDM_PRI][TDM_6].sample_rate;
+ break;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_7:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_PRI][TDM_7].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_PRI][TDM_7].bit_format);
+ rate->min = rate->max =
+ tdm_rx_cfg[TDM_PRI][TDM_7].sample_rate;
+ break;
+ case AFE_PORT_ID_PRIMARY_TDM_TX:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_PRI][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_PRI][TDM_0].bit_format);
+ rate->min = rate->max =
+ tdm_tx_cfg[TDM_PRI][TDM_0].sample_rate;
+ break;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_1:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_PRI][TDM_1].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_PRI][TDM_1].bit_format);
+ rate->min = rate->max =
+ tdm_tx_cfg[TDM_PRI][TDM_1].sample_rate;
+ break;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_2:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_PRI][TDM_2].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_PRI][TDM_2].bit_format);
+ rate->min = rate->max =
+ tdm_tx_cfg[TDM_PRI][TDM_2].sample_rate;
+ break;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_3:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_PRI][TDM_3].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_PRI][TDM_3].bit_format);
+ rate->min = rate->max =
+ tdm_tx_cfg[TDM_PRI][TDM_3].sample_rate;
+ break;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_4:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_PRI][TDM_4].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_PRI][TDM_4].bit_format);
+ rate->min = rate->max =
+ tdm_tx_cfg[TDM_PRI][TDM_4].sample_rate;
+ break;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_5:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_PRI][TDM_5].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_PRI][TDM_5].bit_format);
+ rate->min = rate->max =
+ tdm_tx_cfg[TDM_PRI][TDM_5].sample_rate;
+ break;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_6:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_PRI][TDM_6].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_PRI][TDM_6].bit_format);
+ rate->min = rate->max =
+ tdm_tx_cfg[TDM_PRI][TDM_6].sample_rate;
+ break;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_7:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_PRI][TDM_7].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_PRI][TDM_7].bit_format);
+ rate->min = rate->max =
+ tdm_tx_cfg[TDM_PRI][TDM_7].sample_rate;
+ break;
+ case AFE_PORT_ID_SECONDARY_TDM_RX:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_SEC][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_SEC][TDM_0].bit_format);
+ rate->min = rate->max =
+ tdm_rx_cfg[TDM_SEC][TDM_0].sample_rate;
+ break;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_1:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_SEC][TDM_1].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_SEC][TDM_1].bit_format);
+ rate->min = rate->max =
+ tdm_rx_cfg[TDM_SEC][TDM_1].sample_rate;
+ break;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_2:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_SEC][TDM_2].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_SEC][TDM_2].bit_format);
+ rate->min = rate->max =
+ tdm_rx_cfg[TDM_SEC][TDM_2].sample_rate;
+ break;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_3:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_SEC][TDM_3].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_SEC][TDM_3].bit_format);
+ rate->min = rate->max =
+ tdm_rx_cfg[TDM_SEC][TDM_3].sample_rate;
+ break;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_4:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_SEC][TDM_4].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_SEC][TDM_4].bit_format);
+ rate->min = rate->max =
+ tdm_rx_cfg[TDM_SEC][TDM_4].sample_rate;
+ break;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_5:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_SEC][TDM_5].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_SEC][TDM_5].bit_format);
+ rate->min = rate->max =
+ tdm_rx_cfg[TDM_SEC][TDM_5].sample_rate;
+ break;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_6:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_SEC][TDM_6].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_SEC][TDM_6].bit_format);
+ rate->min = rate->max =
+ tdm_rx_cfg[TDM_SEC][TDM_6].sample_rate;
+ break;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_7:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_SEC][TDM_7].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_SEC][TDM_7].bit_format);
+ rate->min = rate->max =
+ tdm_rx_cfg[TDM_SEC][TDM_7].sample_rate;
+ break;
+ case AFE_PORT_ID_SECONDARY_TDM_TX:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_SEC][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_SEC][TDM_0].bit_format);
+ rate->min = rate->max =
+ tdm_tx_cfg[TDM_SEC][TDM_0].sample_rate;
+ break;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_1:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_SEC][TDM_1].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_SEC][TDM_1].bit_format);
+ rate->min = rate->max =
+ tdm_tx_cfg[TDM_SEC][TDM_1].sample_rate;
+ break;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_2:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_SEC][TDM_2].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_SEC][TDM_2].bit_format);
+ rate->min = rate->max =
+ tdm_tx_cfg[TDM_SEC][TDM_2].sample_rate;
+ break;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_3:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_SEC][TDM_3].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_SEC][TDM_3].bit_format);
+ rate->min = rate->max =
+ tdm_tx_cfg[TDM_SEC][TDM_3].sample_rate;
+ break;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_4:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_SEC][TDM_4].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_SEC][TDM_4].bit_format);
+ rate->min = rate->max =
+ tdm_tx_cfg[TDM_SEC][TDM_4].sample_rate;
+ break;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_5:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_SEC][TDM_5].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_SEC][TDM_5].bit_format);
+ rate->min = rate->max =
+ tdm_tx_cfg[TDM_SEC][TDM_5].sample_rate;
+ break;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_6:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_SEC][TDM_6].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_SEC][TDM_6].bit_format);
+ rate->min = rate->max =
+ tdm_tx_cfg[TDM_SEC][TDM_6].sample_rate;
+ break;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_7:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_SEC][TDM_7].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_SEC][TDM_7].bit_format);
+ rate->min = rate->max =
+ tdm_tx_cfg[TDM_SEC][TDM_7].sample_rate;
+ break;
+ case AFE_PORT_ID_TERTIARY_TDM_RX:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_TERT][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_TERT][TDM_0].bit_format);
+ rate->min = rate->max =
+ tdm_rx_cfg[TDM_TERT][TDM_0].sample_rate;
+ break;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_1:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_TERT][TDM_1].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_TERT][TDM_1].bit_format);
+ rate->min = rate->max =
+ tdm_rx_cfg[TDM_TERT][TDM_1].sample_rate;
+ break;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_2:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_TERT][TDM_2].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_TERT][TDM_2].bit_format);
+ rate->min = rate->max =
+ tdm_rx_cfg[TDM_TERT][TDM_2].sample_rate;
+ break;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_3:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_TERT][TDM_3].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_TERT][TDM_3].bit_format);
+ rate->min = rate->max =
+ tdm_rx_cfg[TDM_TERT][TDM_3].sample_rate;
+ break;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_4:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_TERT][TDM_4].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_TERT][TDM_4].bit_format);
+ rate->min = rate->max =
+ tdm_rx_cfg[TDM_TERT][TDM_4].sample_rate;
+ break;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_5:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_TERT][TDM_5].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_TERT][TDM_5].bit_format);
+ rate->min = rate->max =
+ tdm_rx_cfg[TDM_TERT][TDM_5].sample_rate;
+ break;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_6:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_TERT][TDM_6].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_TERT][TDM_6].bit_format);
+ rate->min = rate->max =
+ tdm_rx_cfg[TDM_TERT][TDM_6].sample_rate;
+ break;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_7:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_TERT][TDM_7].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_TERT][TDM_7].bit_format);
+ rate->min = rate->max =
+ tdm_rx_cfg[TDM_TERT][TDM_7].sample_rate;
+ break;
+ case AFE_PORT_ID_TERTIARY_TDM_TX:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_TERT][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_TERT][TDM_0].bit_format);
+ rate->min = rate->max =
+ tdm_tx_cfg[TDM_TERT][TDM_0].sample_rate;
+ break;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_1:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_TERT][TDM_1].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_TERT][TDM_1].bit_format);
+ rate->min = rate->max =
+ tdm_tx_cfg[TDM_TERT][TDM_1].sample_rate;
+ break;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_2:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_TERT][TDM_2].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_TERT][TDM_2].bit_format);
+ rate->min = rate->max =
+ tdm_tx_cfg[TDM_TERT][TDM_2].sample_rate;
+ break;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_3:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_TERT][TDM_3].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_TERT][TDM_3].bit_format);
+ rate->min = rate->max =
+ tdm_tx_cfg[TDM_TERT][TDM_3].sample_rate;
+ break;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_4:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_TERT][TDM_4].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_TERT][TDM_4].bit_format);
+ rate->min = rate->max =
+ tdm_tx_cfg[TDM_TERT][TDM_4].sample_rate;
+ break;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_5:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_TERT][TDM_5].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_TERT][TDM_5].bit_format);
+ rate->min = rate->max =
+ tdm_tx_cfg[TDM_TERT][TDM_5].sample_rate;
+ break;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_6:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_TERT][TDM_6].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_TERT][TDM_6].bit_format);
+ rate->min = rate->max =
+ tdm_tx_cfg[TDM_TERT][TDM_6].sample_rate;
+ break;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_7:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_TERT][TDM_7].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_TERT][TDM_7].bit_format);
+ rate->min = rate->max =
+ tdm_tx_cfg[TDM_TERT][TDM_7].sample_rate;
+ break;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX:
channels->min = channels->max =
tdm_rx_cfg[TDM_QUAT][TDM_0].channels;
param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
tdm_rx_cfg[TDM_QUAT][TDM_0].bit_format);
rate->min = rate->max =
tdm_rx_cfg[TDM_QUAT][TDM_0].sample_rate;
- } else if (cpu_dai->id == AFE_PORT_ID_SECONDARY_TDM_RX) {
+ break;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_1:
channels->min = channels->max =
- tdm_rx_cfg[TDM_SEC][TDM_0].channels;
+ tdm_rx_cfg[TDM_QUAT][TDM_1].channels;
param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
- tdm_rx_cfg[TDM_SEC][TDM_0].bit_format);
- rate->min = rate->max = tdm_rx_cfg[TDM_SEC][TDM_0].sample_rate;
- } else {
+ tdm_rx_cfg[TDM_QUAT][TDM_1].bit_format);
+ rate->min = rate->max =
+ tdm_rx_cfg[TDM_QUAT][TDM_1].sample_rate;
+ break;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_2:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_QUAT][TDM_2].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_QUAT][TDM_2].bit_format);
+ rate->min = rate->max =
+ tdm_rx_cfg[TDM_QUAT][TDM_2].sample_rate;
+ break;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_3:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_QUAT][TDM_3].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_QUAT][TDM_3].bit_format);
+ rate->min = rate->max =
+ tdm_rx_cfg[TDM_QUAT][TDM_3].sample_rate;
+ break;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_4:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_QUAT][TDM_4].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_QUAT][TDM_4].bit_format);
+ rate->min = rate->max =
+ tdm_rx_cfg[TDM_QUAT][TDM_4].sample_rate;
+ break;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_5:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_QUAT][TDM_5].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_QUAT][TDM_5].bit_format);
+ rate->min = rate->max =
+ tdm_rx_cfg[TDM_QUAT][TDM_5].sample_rate;
+ break;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_6:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_QUAT][TDM_6].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_QUAT][TDM_6].bit_format);
+ rate->min = rate->max =
+ tdm_rx_cfg[TDM_QUAT][TDM_6].sample_rate;
+ break;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_7:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_QUAT][TDM_7].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_QUAT][TDM_7].bit_format);
+ rate->min = rate->max =
+ tdm_rx_cfg[TDM_QUAT][TDM_7].sample_rate;
+ break;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_QUAT][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_QUAT][TDM_0].bit_format);
+ rate->min = rate->max =
+ tdm_tx_cfg[TDM_QUAT][TDM_0].sample_rate;
+ break;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_1:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_QUAT][TDM_1].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_QUAT][TDM_1].bit_format);
+ rate->min = rate->max =
+ tdm_tx_cfg[TDM_QUAT][TDM_1].sample_rate;
+ break;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_2:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_QUAT][TDM_2].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_QUAT][TDM_2].bit_format);
+ rate->min = rate->max =
+ tdm_tx_cfg[TDM_QUAT][TDM_2].sample_rate;
+ break;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_3:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_QUAT][TDM_3].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_QUAT][TDM_3].bit_format);
+ rate->min = rate->max =
+ tdm_tx_cfg[TDM_QUAT][TDM_3].sample_rate;
+ break;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_4:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_QUAT][TDM_4].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_QUAT][TDM_4].bit_format);
+ rate->min = rate->max =
+ tdm_tx_cfg[TDM_QUAT][TDM_4].sample_rate;
+ break;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_5:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_QUAT][TDM_5].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_QUAT][TDM_5].bit_format);
+ rate->min = rate->max =
+ tdm_tx_cfg[TDM_QUAT][TDM_5].sample_rate;
+ break;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_6:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_QUAT][TDM_6].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_QUAT][TDM_6].bit_format);
+ rate->min = rate->max =
+ tdm_tx_cfg[TDM_QUAT][TDM_6].sample_rate;
+ break;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_7:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_QUAT][TDM_7].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_QUAT][TDM_7].bit_format);
+ rate->min = rate->max =
+ tdm_tx_cfg[TDM_QUAT][TDM_7].sample_rate;
+ break;
+ default:
pr_err("%s: dai id 0x%x not supported\n",
__func__, cpu_dai->id);
return -EINVAL;
@@ -4505,25 +5663,411 @@ static int msm_tdm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
return 0;
}
+static unsigned int tdm_param_set_slot_mask(int slots)
+{
+ unsigned int slot_mask = 0;
+ int i = 0;
+
+ if ((slots <= 0) || (slots > 32)) {
+ pr_err("%s: invalid slot number %d\n", __func__, slots);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < slots ; i++)
+ slot_mask |= 1 << i;
+
+ return slot_mask;
+}
+
static int msm8998_tdm_snd_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret = 0;
- int channels, slot_width, slots;
+ int channels, slot_width, slots, rate, format;
unsigned int slot_mask;
- unsigned int slot_offset[8] = {0, 4, 8, 12, 16, 20, 24, 28};
+ unsigned int *slot_offset;
+ int offset_channels = 0;
+ int i;
+ int clk_freq;
pr_debug("%s: dai id = 0x%x\n", __func__, cpu_dai->id);
- slots = tdm_rx_cfg[TDM_QUAT][TDM_0].channels;
- /*2 slot config - bits 0 and 1 set for the first two slots */
- slot_mask = 0x0000FFFF >> (16-slots);
- slot_width = 32;
- channels = slots;
+ channels = params_channels(params);
+ if (channels < 1 || channels > 32) {
+ pr_err("%s: invalid param channels %d\n",
+ __func__, channels);
+ return -EINVAL;
+ }
+
+ format = params_format(params);
+ if (format != SNDRV_PCM_FORMAT_S32_LE &&
+ format != SNDRV_PCM_FORMAT_S24_LE &&
+ format != SNDRV_PCM_FORMAT_S16_LE) {
+ /*
+ * Up to 8 channel HW configuration should
+ * use 32 bit slot width for max support of
+ * stream bit width. (slot_width > bit_width)
+ */
+ pr_err("%s: invalid param format 0x%x\n",
+ __func__, format);
+ return -EINVAL;
+ }
+
+ switch (cpu_dai->id) {
+ case AFE_PORT_ID_PRIMARY_TDM_RX:
+ slots = tdm_slot[TDM_PRI].num;
+ slot_width = tdm_slot[TDM_PRI].width;
+ slot_offset = tdm_rx_slot_offset[TDM_PRI][TDM_0];
+ break;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_1:
+ slots = tdm_slot[TDM_PRI].num;
+ slot_width = tdm_slot[TDM_PRI].width;
+ slot_offset = tdm_rx_slot_offset[TDM_PRI][TDM_1];
+ break;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_2:
+ slots = tdm_slot[TDM_PRI].num;
+ slot_width = tdm_slot[TDM_PRI].width;
+ slot_offset = tdm_rx_slot_offset[TDM_PRI][TDM_2];
+ break;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_3:
+ slots = tdm_slot[TDM_PRI].num;
+ slot_width = tdm_slot[TDM_PRI].width;
+ slot_offset = tdm_rx_slot_offset[TDM_PRI][TDM_3];
+ break;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_4:
+ slots = tdm_slot[TDM_PRI].num;
+ slot_width = tdm_slot[TDM_PRI].width;
+ slot_offset = tdm_rx_slot_offset[TDM_PRI][TDM_4];
+ break;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_5:
+ slots = tdm_slot[TDM_PRI].num;
+ slot_width = tdm_slot[TDM_PRI].width;
+ slot_offset = tdm_rx_slot_offset[TDM_PRI][TDM_5];
+ break;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_6:
+ slots = tdm_slot[TDM_PRI].num;
+ slot_width = tdm_slot[TDM_PRI].width;
+ slot_offset = tdm_rx_slot_offset[TDM_PRI][TDM_6];
+ break;
+ case AFE_PORT_ID_PRIMARY_TDM_RX_7:
+ slots = tdm_slot[TDM_PRI].num;
+ slot_width = tdm_slot[TDM_PRI].width;
+ slot_offset = tdm_rx_slot_offset[TDM_PRI][TDM_7];
+ break;
+ case AFE_PORT_ID_PRIMARY_TDM_TX:
+ slots = tdm_slot[TDM_PRI].num;
+ slot_width = tdm_slot[TDM_PRI].width;
+ slot_offset = tdm_tx_slot_offset[TDM_PRI][TDM_0];
+ break;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_1:
+ slots = tdm_slot[TDM_PRI].num;
+ slot_width = tdm_slot[TDM_PRI].width;
+ slot_offset = tdm_tx_slot_offset[TDM_PRI][TDM_1];
+ break;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_2:
+ slots = tdm_slot[TDM_PRI].num;
+ slot_width = tdm_slot[TDM_PRI].width;
+ slot_offset = tdm_tx_slot_offset[TDM_PRI][TDM_2];
+ break;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_3:
+ slots = tdm_slot[TDM_PRI].num;
+ slot_width = tdm_slot[TDM_PRI].width;
+ slot_offset = tdm_tx_slot_offset[TDM_PRI][TDM_3];
+ break;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_4:
+ slots = tdm_slot[TDM_PRI].num;
+ slot_width = tdm_slot[TDM_PRI].width;
+ slot_offset = tdm_tx_slot_offset[TDM_PRI][TDM_4];
+ break;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_5:
+ slots = tdm_slot[TDM_PRI].num;
+ slot_width = tdm_slot[TDM_PRI].width;
+ slot_offset = tdm_tx_slot_offset[TDM_PRI][TDM_5];
+ break;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_6:
+ slots = tdm_slot[TDM_PRI].num;
+ slot_width = tdm_slot[TDM_PRI].width;
+ slot_offset = tdm_tx_slot_offset[TDM_PRI][TDM_6];
+ break;
+ case AFE_PORT_ID_PRIMARY_TDM_TX_7:
+ slots = tdm_slot[TDM_PRI].num;
+ slot_width = tdm_slot[TDM_PRI].width;
+ slot_offset = tdm_tx_slot_offset[TDM_PRI][TDM_7];
+ break;
+ case AFE_PORT_ID_SECONDARY_TDM_RX:
+ slots = tdm_slot[TDM_SEC].num;
+ slot_width = tdm_slot[TDM_SEC].width;
+ slot_offset = tdm_rx_slot_offset[TDM_SEC][TDM_0];
+ break;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_1:
+ slots = tdm_slot[TDM_SEC].num;
+ slot_width = tdm_slot[TDM_SEC].width;
+ slot_offset = tdm_rx_slot_offset[TDM_SEC][TDM_1];
+ break;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_2:
+ slots = tdm_slot[TDM_SEC].num;
+ slot_width = tdm_slot[TDM_SEC].width;
+ slot_offset = tdm_rx_slot_offset[TDM_SEC][TDM_2];
+ break;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_3:
+ slots = tdm_slot[TDM_SEC].num;
+ slot_width = tdm_slot[TDM_SEC].width;
+ slot_offset = tdm_rx_slot_offset[TDM_SEC][TDM_3];
+ break;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_4:
+ slots = tdm_slot[TDM_SEC].num;
+ slot_width = tdm_slot[TDM_SEC].width;
+ slot_offset = tdm_rx_slot_offset[TDM_SEC][TDM_4];
+ break;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_5:
+ slots = tdm_slot[TDM_SEC].num;
+ slot_width = tdm_slot[TDM_SEC].width;
+ slot_offset = tdm_rx_slot_offset[TDM_SEC][TDM_5];
+ break;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_6:
+ slots = tdm_slot[TDM_SEC].num;
+ slot_width = tdm_slot[TDM_SEC].width;
+ slot_offset = tdm_rx_slot_offset[TDM_SEC][TDM_6];
+ break;
+ case AFE_PORT_ID_SECONDARY_TDM_RX_7:
+ slots = tdm_slot[TDM_SEC].num;
+ slot_width = tdm_slot[TDM_SEC].width;
+ slot_offset = tdm_rx_slot_offset[TDM_SEC][TDM_7];
+ break;
+ case AFE_PORT_ID_SECONDARY_TDM_TX:
+ slots = tdm_slot[TDM_SEC].num;
+ slot_width = tdm_slot[TDM_SEC].width;
+ slot_offset = tdm_tx_slot_offset[TDM_SEC][TDM_0];
+ break;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_1:
+ slots = tdm_slot[TDM_SEC].num;
+ slot_width = tdm_slot[TDM_SEC].width;
+ slot_offset = tdm_tx_slot_offset[TDM_SEC][TDM_1];
+ break;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_2:
+ slots = tdm_slot[TDM_SEC].num;
+ slot_width = tdm_slot[TDM_SEC].width;
+ slot_offset = tdm_tx_slot_offset[TDM_SEC][TDM_2];
+ break;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_3:
+ slots = tdm_slot[TDM_SEC].num;
+ slot_width = tdm_slot[TDM_SEC].width;
+ slot_offset = tdm_tx_slot_offset[TDM_SEC][TDM_3];
+ break;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_4:
+ slots = tdm_slot[TDM_SEC].num;
+ slot_width = tdm_slot[TDM_SEC].width;
+ slot_offset = tdm_tx_slot_offset[TDM_SEC][TDM_4];
+ break;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_5:
+ slots = tdm_slot[TDM_SEC].num;
+ slot_width = tdm_slot[TDM_SEC].width;
+ slot_offset = tdm_tx_slot_offset[TDM_SEC][TDM_5];
+ break;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_6:
+ slots = tdm_slot[TDM_SEC].num;
+ slot_width = tdm_slot[TDM_SEC].width;
+ slot_offset = tdm_tx_slot_offset[TDM_SEC][TDM_6];
+ break;
+ case AFE_PORT_ID_SECONDARY_TDM_TX_7:
+ slots = tdm_slot[TDM_SEC].num;
+ slot_width = tdm_slot[TDM_SEC].width;
+ slot_offset = tdm_tx_slot_offset[TDM_SEC][TDM_7];
+ break;
+ case AFE_PORT_ID_TERTIARY_TDM_RX:
+ slots = tdm_slot[TDM_TERT].num;
+ slot_width = tdm_slot[TDM_TERT].width;
+ slot_offset = tdm_rx_slot_offset[TDM_TERT][TDM_0];
+ break;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_1:
+ slots = tdm_slot[TDM_TERT].num;
+ slot_width = tdm_slot[TDM_TERT].width;
+ slot_offset = tdm_rx_slot_offset[TDM_TERT][TDM_1];
+ break;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_2:
+ slots = tdm_slot[TDM_TERT].num;
+ slot_width = tdm_slot[TDM_TERT].width;
+ slot_offset = tdm_rx_slot_offset[TDM_TERT][TDM_2];
+ break;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_3:
+ slots = tdm_slot[TDM_TERT].num;
+ slot_width = tdm_slot[TDM_TERT].width;
+ slot_offset = tdm_rx_slot_offset[TDM_TERT][TDM_3];
+ break;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_4:
+ slots = tdm_slot[TDM_TERT].num;
+ slot_width = tdm_slot[TDM_TERT].width;
+ slot_offset = tdm_rx_slot_offset[TDM_TERT][TDM_4];
+ break;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_5:
+ slots = tdm_slot[TDM_TERT].num;
+ slot_width = tdm_slot[TDM_TERT].width;
+ slot_offset = tdm_rx_slot_offset[TDM_TERT][TDM_5];
+ break;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_6:
+ slots = tdm_slot[TDM_TERT].num;
+ slot_width = tdm_slot[TDM_TERT].width;
+ slot_offset = tdm_rx_slot_offset[TDM_TERT][TDM_6];
+ break;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_7:
+ slots = tdm_slot[TDM_TERT].num;
+ slot_width = tdm_slot[TDM_TERT].width;
+ slot_offset = tdm_rx_slot_offset[TDM_TERT][TDM_7];
+ break;
+ case AFE_PORT_ID_TERTIARY_TDM_TX:
+ slots = tdm_slot[TDM_TERT].num;
+ slot_width = tdm_slot[TDM_TERT].width;
+ slot_offset = tdm_tx_slot_offset[TDM_TERT][TDM_0];
+ break;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_1:
+ slots = tdm_slot[TDM_TERT].num;
+ slot_width = tdm_slot[TDM_TERT].width;
+ slot_offset = tdm_tx_slot_offset[TDM_TERT][TDM_1];
+ break;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_2:
+ slots = tdm_slot[TDM_TERT].num;
+ slot_width = tdm_slot[TDM_TERT].width;
+ slot_offset = tdm_tx_slot_offset[TDM_TERT][TDM_2];
+ break;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_3:
+ slots = tdm_slot[TDM_TERT].num;
+ slot_width = tdm_slot[TDM_TERT].width;
+ slot_offset = tdm_tx_slot_offset[TDM_TERT][TDM_3];
+ break;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_4:
+ slots = tdm_slot[TDM_TERT].num;
+ slot_width = tdm_slot[TDM_TERT].width;
+ slot_offset = tdm_tx_slot_offset[TDM_TERT][TDM_4];
+ break;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_5:
+ slots = tdm_slot[TDM_TERT].num;
+ slot_width = tdm_slot[TDM_TERT].width;
+ slot_offset = tdm_tx_slot_offset[TDM_TERT][TDM_5];
+ break;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_6:
+ slots = tdm_slot[TDM_TERT].num;
+ slot_width = tdm_slot[TDM_TERT].width;
+ slot_offset = tdm_tx_slot_offset[TDM_TERT][TDM_6];
+ break;
+ case AFE_PORT_ID_TERTIARY_TDM_TX_7:
+ slots = tdm_slot[TDM_TERT].num;
+ slot_width = tdm_slot[TDM_TERT].width;
+ slot_offset = tdm_tx_slot_offset[TDM_TERT][TDM_7];
+ break;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX:
+ slots = tdm_slot[TDM_QUAT].num;
+ slot_width = tdm_slot[TDM_QUAT].width;
+ slot_offset = tdm_rx_slot_offset[TDM_QUAT][TDM_0];
+ break;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_1:
+ slots = tdm_slot[TDM_QUAT].num;
+ slot_width = tdm_slot[TDM_QUAT].width;
+ slot_offset = tdm_rx_slot_offset[TDM_QUAT][TDM_1];
+ break;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_2:
+ slots = tdm_slot[TDM_QUAT].num;
+ slot_width = tdm_slot[TDM_QUAT].width;
+ slot_offset = tdm_rx_slot_offset[TDM_QUAT][TDM_2];
+ break;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_3:
+ slots = tdm_slot[TDM_QUAT].num;
+ slot_width = tdm_slot[TDM_QUAT].width;
+ slot_offset = tdm_rx_slot_offset[TDM_QUAT][TDM_3];
+ break;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_4:
+ slots = tdm_slot[TDM_QUAT].num;
+ slot_width = tdm_slot[TDM_QUAT].width;
+ slot_offset = tdm_rx_slot_offset[TDM_QUAT][TDM_4];
+ break;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_5:
+ slots = tdm_slot[TDM_QUAT].num;
+ slot_width = tdm_slot[TDM_QUAT].width;
+ slot_offset = tdm_rx_slot_offset[TDM_QUAT][TDM_5];
+ break;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_6:
+ slots = tdm_slot[TDM_QUAT].num;
+ slot_width = tdm_slot[TDM_QUAT].width;
+ slot_offset = tdm_rx_slot_offset[TDM_QUAT][TDM_6];
+ break;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX_7:
+ slots = tdm_slot[TDM_QUAT].num;
+ slot_width = tdm_slot[TDM_QUAT].width;
+ slot_offset = tdm_rx_slot_offset[TDM_QUAT][TDM_7];
+ break;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX:
+ slots = tdm_slot[TDM_QUAT].num;
+ slot_width = tdm_slot[TDM_QUAT].width;
+ slot_offset = tdm_tx_slot_offset[TDM_QUAT][TDM_0];
+ break;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_1:
+ slots = tdm_slot[TDM_QUAT].num;
+ slot_width = tdm_slot[TDM_QUAT].width;
+ slot_offset = tdm_tx_slot_offset[TDM_QUAT][TDM_1];
+ break;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_2:
+ slots = tdm_slot[TDM_QUAT].num;
+ slot_width = tdm_slot[TDM_QUAT].width;
+ slot_offset = tdm_tx_slot_offset[TDM_QUAT][TDM_2];
+ break;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_3:
+ slots = tdm_slot[TDM_QUAT].num;
+ slot_width = tdm_slot[TDM_QUAT].width;
+ slot_offset = tdm_tx_slot_offset[TDM_QUAT][TDM_3];
+ break;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_4:
+ slots = tdm_slot[TDM_QUAT].num;
+ slot_width = tdm_slot[TDM_QUAT].width;
+ slot_offset = tdm_tx_slot_offset[TDM_QUAT][TDM_4];
+ break;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_5:
+ slots = tdm_slot[TDM_QUAT].num;
+ slot_width = tdm_slot[TDM_QUAT].width;
+ slot_offset = tdm_tx_slot_offset[TDM_QUAT][TDM_5];
+ break;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_6:
+ slots = tdm_slot[TDM_QUAT].num;
+ slot_width = tdm_slot[TDM_QUAT].width;
+ slot_offset = tdm_tx_slot_offset[TDM_QUAT][TDM_6];
+ break;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX_7:
+ slots = tdm_slot[TDM_QUAT].num;
+ slot_width = tdm_slot[TDM_QUAT].width;
+ slot_offset = tdm_tx_slot_offset[TDM_QUAT][TDM_7];
+ break;
+ default:
+ pr_err("%s: dai id 0x%x not supported\n",
+ __func__, cpu_dai->id);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < TDM_SLOT_OFFSET_MAX; i++) {
+ if (slot_offset[i] != AFE_SLOT_MAPPING_OFFSET_INVALID)
+ offset_channels++;
+ else
+ break;
+ }
+
+ if (offset_channels == 0) {
+ pr_err("%s: invalid offset_channels %d\n",
+ __func__, offset_channels);
+ return -EINVAL;
+ }
+
+ if (channels > offset_channels) {
+ pr_err("%s: channels %d exceed offset_channels %d\n",
+ __func__, channels, offset_channels);
+ return -EINVAL;
+ }
+
+ slot_mask = tdm_param_set_slot_mask(slots);
+ if (!slot_mask) {
+ pr_err("%s: invalid slot_mask 0x%x\n",
+ __func__, slot_mask);
+ return -EINVAL;
+ }
- pr_debug("%s: slot_width %d slots %d\n", __func__, slot_width, slots);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
pr_debug("%s: slot_width %d\n", __func__, slot_width);
ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0, slot_mask,
@@ -4541,9 +6085,35 @@ static int msm8998_tdm_snd_hw_params(struct snd_pcm_substream *substream,
__func__, ret);
goto end;
}
+ } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, slot_mask, 0,
+ slots, slot_width);
+ if (ret < 0) {
+ pr_err("%s: failed to set tdm slot, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai,
+ channels, slot_offset, 0, NULL);
+ if (ret < 0) {
+ pr_err("%s: failed to set channel map, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
} else {
+ ret = -EINVAL;
pr_err("%s: invalid use case, err:%d\n",
__func__, ret);
+ goto end;
+ }
+
+ rate = params_rate(params);
+ clk_freq = rate * slot_width * slots;
+ ret = snd_soc_dai_set_sysclk(cpu_dai, 0, clk_freq, SND_SOC_CLOCK_OUT);
+ if (ret < 0) {
+ pr_err("%s: failed to set tdm clk, err:%d\n",
+ __func__, ret);
}
end:
@@ -4560,7 +6130,7 @@ static int msm8998_tdm_snd_startup(struct snd_pcm_substream *substream)
ret = msm_set_pinctrl(pinctrl_info, STATE_TDM_ACTIVE);
if (ret)
- pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
+ pr_err("%s: TDM TLMM pinctrl set failed with %d\n",
__func__, ret);
return ret;
@@ -4576,7 +6146,7 @@ static void msm8998_tdm_snd_shutdown(struct snd_pcm_substream *substream)
ret = msm_set_pinctrl(pinctrl_info, STATE_DISABLE);
if (ret)
- pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
+ pr_err("%s: TDM TLMM pinctrl set failed with %d\n",
__func__, ret);
}
@@ -4712,28 +6282,6 @@ static struct snd_soc_ops msm_aux_pcm_be_ops = {
.shutdown = msm_aux_pcm_snd_shutdown,
};
-static unsigned int tdm_param_set_slot_mask(u16 port_id, int slot_width,
- int slots)
-{
- unsigned int slot_mask = 0;
- int i, j;
- unsigned int *slot_offset;
-
- for (i = TDM_0; i < TDM_PORT_MAX; i++) {
- slot_offset = tdm_slot_offset[i];
-
- for (j = 0; j < TDM_SLOT_OFFSET_MAX; j++) {
- if (slot_offset[j] != AFE_SLOT_MAPPING_OFFSET_INVALID)
- slot_mask |=
- (1 << ((slot_offset[j] * 8) / slot_width));
- else
- break;
- }
- }
-
- return slot_mask;
-}
-
static int msm_tdm_snd_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -4775,9 +6323,7 @@ static int msm_tdm_snd_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
slots = 8;
- slot_mask = tdm_param_set_slot_mask(cpu_dai->id,
- slot_width,
- slots);
+ slot_mask = tdm_param_set_slot_mask(slots);
if (!slot_mask) {
pr_err("%s: invalid slot_mask 0x%x\n",
__func__, slot_mask);
@@ -5859,8 +7405,8 @@ static struct snd_soc_dai_link msm_common_be_dai_links[] = {
.no_pcm = 1,
.dpcm_playback = 1,
.be_id = MSM_BACKEND_DAI_PRI_TDM_RX_0,
- .be_hw_params_fixup = msm_be_hw_params_fixup,
- .ops = &msm_tdm_be_ops,
+ .be_hw_params_fixup = msm_tdm_be_hw_params_fixup,
+ .ops = &msm8998_tdm_be_ops,
.ignore_suspend = 1,
},
{
@@ -5873,8 +7419,8 @@ static struct snd_soc_dai_link msm_common_be_dai_links[] = {
.no_pcm = 1,
.dpcm_capture = 1,
.be_id = MSM_BACKEND_DAI_PRI_TDM_TX_0,
- .be_hw_params_fixup = msm_be_hw_params_fixup,
- .ops = &msm_tdm_be_ops,
+ .be_hw_params_fixup = msm_tdm_be_hw_params_fixup,
+ .ops = &msm8998_tdm_be_ops,
.ignore_suspend = 1,
},
{
@@ -5957,8 +7503,8 @@ static struct snd_soc_dai_link msm_common_be_dai_links[] = {
.no_pcm = 1,
.dpcm_capture = 1,
.be_id = MSM_BACKEND_DAI_QUAT_TDM_TX_0,
- .be_hw_params_fixup = msm_be_hw_params_fixup,
- .ops = &msm_tdm_be_ops,
+ .be_hw_params_fixup = msm_tdm_be_hw_params_fixup,
+ .ops = &msm8998_tdm_be_ops,
.ignore_suspend = 1,
},
};
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index 0c23e1eef483..39abecb64f0e 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2019, 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
@@ -1510,12 +1510,18 @@ static int msm_dai_q6_prepare(struct snd_pcm_substream *substream,
if (dai_data->enc_config.format != ENC_FMT_NONE) {
int bitwidth = 0;
- if (dai_data->afe_in_bitformat ==
- SNDRV_PCM_FORMAT_S24_LE)
+ switch (dai_data->afe_in_bitformat) {
+ case SNDRV_PCM_FORMAT_S32_LE:
+ bitwidth = 32;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
bitwidth = 24;
- else if (dai_data->afe_in_bitformat ==
- SNDRV_PCM_FORMAT_S16_LE)
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
bitwidth = 16;
+ break;
+ }
pr_debug("%s: calling AFE_PORT_START_V2 with enc_format: %d\n",
__func__, dai_data->enc_config.format);
rc = afe_port_start_v2(dai->id, &dai_data->port_config,
@@ -2337,6 +2343,9 @@ static int msm_dai_q6_afe_input_bit_format_get(
}
switch (dai_data->afe_in_bitformat) {
+ case SNDRV_PCM_FORMAT_S32_LE:
+ ucontrol->value.integer.value[0] = 2;
+ break;
case SNDRV_PCM_FORMAT_S24_LE:
ucontrol->value.integer.value[0] = 1;
break;
@@ -2362,6 +2371,9 @@ static int msm_dai_q6_afe_input_bit_format_put(
return -EINVAL;
}
switch (ucontrol->value.integer.value[0]) {
+ case 2:
+ dai_data->afe_in_bitformat = SNDRV_PCM_FORMAT_S32_LE;
+ break;
case 1:
dai_data->afe_in_bitformat = SNDRV_PCM_FORMAT_S24_LE;
break;
@@ -7424,11 +7436,17 @@ static int msm_dai_q6_tdm_set_tdm_slot(struct snd_soc_dai *dai,
return -EINVAL;
}
- /* HW only supports 16 and 8 slots configuration */
+ /* HW supports 1-32 slots configuration. Typical: 1, 2, 4, 8, 16, 32 */
switch (slots) {
+ case 1:
+ cap_mask = 0x01;
+ break;
case 2:
cap_mask = 0x03;
break;
+ case 4:
+ cap_mask = 0x0F;
+ break;
case 8:
cap_mask = 0xFF;
break;
@@ -7532,27 +7550,13 @@ static int msm_dai_q6_tdm_set_sysclk(struct snd_soc_dai *dai,
struct msm_dai_q6_tdm_dai_data *dai_data =
dev_get_drvdata(dai->dev);
- switch (dai->id) {
- case AFE_PORT_ID_PRIMARY_TDM_RX:
- case AFE_PORT_ID_PRIMARY_TDM_RX_1:
- case AFE_PORT_ID_PRIMARY_TDM_RX_2:
- case AFE_PORT_ID_PRIMARY_TDM_RX_3:
- case AFE_PORT_ID_PRIMARY_TDM_RX_4:
- case AFE_PORT_ID_PRIMARY_TDM_RX_5:
- case AFE_PORT_ID_PRIMARY_TDM_RX_6:
- case AFE_PORT_ID_PRIMARY_TDM_RX_7:
- case AFE_PORT_ID_PRIMARY_TDM_TX:
- case AFE_PORT_ID_PRIMARY_TDM_TX_1:
- case AFE_PORT_ID_PRIMARY_TDM_TX_2:
- case AFE_PORT_ID_PRIMARY_TDM_TX_3:
- case AFE_PORT_ID_PRIMARY_TDM_TX_4:
- case AFE_PORT_ID_PRIMARY_TDM_TX_5:
- case AFE_PORT_ID_PRIMARY_TDM_TX_6:
- case AFE_PORT_ID_PRIMARY_TDM_TX_7:
+ if ((dai->id >= AFE_PORT_ID_PRIMARY_TDM_RX) &&
+ (dai->id <= AFE_PORT_ID_QUATERNARY_TDM_TX_7)) {
dai_data->clk_set.clk_freq_in_hz = freq;
- break;
- default:
- return 0;
+ } else {
+ dev_err(dai->dev, "%s: invalid dai id 0x%x\n",
+ __func__, dai->id);
+ return -EINVAL;
}
dev_dbg(dai->dev, "%s: dai id = 0x%x group clk_freq %d\n",
@@ -8116,7 +8120,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8136,7 +8140,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8156,7 +8160,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8176,7 +8180,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8196,7 +8200,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8216,7 +8220,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8236,7 +8240,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8256,7 +8260,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8276,7 +8280,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8296,7 +8300,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8316,7 +8320,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8336,7 +8340,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8356,7 +8360,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8376,7 +8380,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8396,7 +8400,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8416,7 +8420,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8436,7 +8440,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8456,7 +8460,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8476,7 +8480,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8496,7 +8500,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8516,7 +8520,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8536,7 +8540,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8556,7 +8560,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8576,7 +8580,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8596,7 +8600,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8616,7 +8620,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8636,7 +8640,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8656,7 +8660,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8676,7 +8680,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8696,7 +8700,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8716,7 +8720,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8736,7 +8740,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8756,7 +8760,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8776,7 +8780,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8796,7 +8800,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8816,7 +8820,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8836,7 +8840,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8856,7 +8860,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8876,7 +8880,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8896,7 +8900,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8916,7 +8920,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8936,7 +8940,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8956,7 +8960,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8976,7 +8980,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -8996,7 +9000,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -9016,7 +9020,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -9036,7 +9040,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -9056,7 +9060,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -9076,7 +9080,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -9096,7 +9100,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -9116,7 +9120,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -9136,7 +9140,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -9156,7 +9160,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -9176,7 +9180,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -9196,7 +9200,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -9216,7 +9220,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -9236,7 +9240,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -9256,7 +9260,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -9276,7 +9280,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -9296,7 +9300,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -9316,7 +9320,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -9336,7 +9340,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -9356,7 +9360,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
@@ -9376,7 +9380,7 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = 16,
.rate_min = 8000,
.rate_max = 352800,
},
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index 0b55f71c23f6..ad921f778b12 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -1550,7 +1550,7 @@ static int msm_pcm_chmap_ctl_put(struct snd_kcontrol *kcontrol,
prtd = substream->runtime->private_data;
if (prtd) {
prtd->set_channel_map = true;
- for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+ for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V2; i++)
prtd->channel_map[i] =
(char)(ucontrol->value.integer.value[i]);
}
@@ -1578,11 +1578,11 @@ static int msm_pcm_chmap_ctl_get(struct snd_kcontrol *kcontrol,
prtd = substream->runtime->private_data;
if (prtd && prtd->set_channel_map == true) {
- for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+ for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V2; i++)
ucontrol->value.integer.value[i] =
(int)prtd->channel_map[i];
} else {
- for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+ for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V2; i++)
ucontrol->value.integer.value[i] = 0;
}
@@ -1600,7 +1600,7 @@ static int msm_pcm_add_chmap_controls(struct snd_soc_pcm_runtime *rtd)
pr_debug("%s, Channel map cntrl add\n", __func__);
ret = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
snd_pcm_std_chmaps,
- PCM_FORMAT_MAX_NUM_CHANNEL, 0,
+ PCM_FORMAT_MAX_NUM_CHANNEL_V2, 0,
&chmap_info);
if (ret < 0) {
pr_err("%s, channel map cntrl add failed\n", __func__);
@@ -2465,7 +2465,7 @@ static int msm_pcm_channel_mixer_output_map_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 32;
+ uinfo->count = PCM_FORMAT_MAX_NUM_CHANNEL_V2;
uinfo->value.integer.min = 1;
uinfo->value.integer.max = 64;
return 0;
@@ -2567,7 +2567,7 @@ static int msm_pcm_channel_mixer_input_map_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 32;
+ uinfo->count = PCM_FORMAT_MAX_NUM_CHANNEL_V2;
uinfo->value.integer.min = 1;
uinfo->value.integer.max = 64;
return 0;
@@ -2782,7 +2782,7 @@ static int msm_pcm_channel_mixer_weight_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 32;
+ uinfo->count = PCM_FORMAT_MAX_NUM_CHANNEL_V2;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 0x4000;
return 0;
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 4e1965302ba1..c8a2cc37363c 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -332,6 +332,11 @@ static int32_t sp_make_afe_callback(uint32_t opcode, uint32_t *payload,
/* Set command specific details */
switch (opcode) {
case AFE_PORT_CMDRSP_GET_PARAM_V2:
+ if (payload_size < (5 * sizeof(uint32_t))) {
+ pr_err("%s: Error: size %d is less than expected\n",
+ __func__, payload_size);
+ return -EINVAL;
+ }
expected_size += sizeof(struct param_hdr_v1);
param_hdr.module_id = payload[1];
param_hdr.instance_id = INSTANCE_ID_0;
@@ -340,7 +345,17 @@ static int32_t sp_make_afe_callback(uint32_t opcode, uint32_t *payload,
data_start = &payload[4];
break;
case AFE_PORT_CMDRSP_GET_PARAM_V3:
+ if (payload_size < (6 * sizeof(uint32_t))) {
+ pr_err("%s: Error: size %d is less than expected\n",
+ __func__, payload_size);
+ return -EINVAL;
+ }
expected_size += sizeof(struct param_hdr_v3);
+ if (payload_size < expected_size) {
+ pr_err("%s: Error: size %d is less than expected\n",
+ __func__, payload_size);
+ return -EINVAL;
+ }
memcpy(&param_hdr, &payload[1], sizeof(struct param_hdr_v3));
data_start = &payload[5];
break;