diff options
| -rw-r--r-- | Documentation/devicetree/bindings/usb/msm-ssusb.txt | 2 | ||||
| -rw-r--r-- | arch/arm/boot/dts/qcom/msm8996-cdp.dtsi | 1 | ||||
| -rw-r--r-- | arch/arm/boot/dts/qcom/msm8996-mtp.dtsi | 1 | ||||
| -rw-r--r-- | drivers/char/diag/diagfwd.c | 10 | ||||
| -rw-r--r-- | drivers/net/wireless/cnss2/pci.c | 6 | ||||
| -rw-r--r-- | drivers/net/wireless/cnss2/usb.c | 6 | ||||
| -rw-r--r-- | drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c | 5 | ||||
| -rw-r--r-- | drivers/soc/qcom/hab/hab_msg.c | 1 | ||||
| -rw-r--r-- | drivers/usb/dwc3/dwc3-msm.c | 139 | ||||
| -rw-r--r-- | drivers/usb/phy/phy-msm-qusb.c | 332 | ||||
| -rw-r--r-- | include/linux/usb/phy.h | 12 | ||||
| -rw-r--r-- | sound/soc/msm/msm8998.c | 1774 | ||||
| -rw-r--r-- | sound/soc/msm/qdsp6v2/q6afe.c | 15 |
13 files changed, 2146 insertions, 158 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 26e4c5abef89..38f3715973cd 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/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/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 fe3edb5db9b2..d8e128eee8cc 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c @@ -824,10 +824,11 @@ int ipa3_qmi_ul_filter_request_send( 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) + QMI_IPA_IP_TYPE_V6_V01) { IPAWANERR("Invalid IP type %d\n", req->firewall_rules_list[i].ip_type); - return -EINVAL; + return -EINVAL; + } } req_desc.max_msg_len = diff --git a/drivers/soc/qcom/hab/hab_msg.c b/drivers/soc/qcom/hab/hab_msg.c index dabffa0e856a..9f92074665df 100644 --- a/drivers/soc/qcom/hab/hab_msg.c +++ b/drivers/soc/qcom/hab/hab_msg.c @@ -206,6 +206,7 @@ int hab_msg_recv(struct physical_channel *pchan, struct virtual_channel *vchan = NULL; struct export_desc *exp_desc = NULL, exp_ack = {0}; struct timeval tv = {0}; + unsigned long long rx_mpm_tv = 0; /* get the local virtual channel if it isn't an open message */ if (payload_type != HAB_PAYLOAD_TYPE_INIT && diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 1c7d7af6787a..0650f0b69de7 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.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 @@ -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); @@ -130,6 +133,34 @@ struct dwc3_msm_req_complete { struct usb_request *req); }; +enum dwc3_drd_state { + DRD_STATE_UNDEFINED = 0, + + DRD_STATE_IDLE, + DRD_STATE_PERIPHERAL, + DRD_STATE_PERIPHERAL_SUSPEND, + + DRD_STATE_HOST_IDLE, + DRD_STATE_HOST, +}; + +static const char *const state_names[] = { + [DRD_STATE_UNDEFINED] = "undefined", + [DRD_STATE_IDLE] = "idle", + [DRD_STATE_PERIPHERAL] = "peripheral", + [DRD_STATE_PERIPHERAL_SUSPEND] = "peripheral_suspend", + [DRD_STATE_HOST_IDLE] = "host_idle", + [DRD_STATE_HOST] = "host", +}; + +static const char *dwc3_drd_state_string(enum dwc3_drd_state state) +{ + if (state < 0 || state >= ARRAY_SIZE(state_names)) + return "UNKNOWN"; + + return state_names[state]; +} + enum dwc3_id_state { DWC3_ID_GROUND = 0, DWC3_ID_FLOAT, @@ -147,6 +178,7 @@ enum plug_orientation { #define ID 0 #define B_SESS_VLD 1 #define B_SUSPEND 2 +#define WAIT_FOR_LPM 3 #define PM_QOS_SAMPLE_SEC 2 #define PM_QOS_THRESHOLD 400 @@ -193,7 +225,7 @@ struct dwc3_msm { unsigned long inputs; unsigned max_power; bool charging_disabled; - enum usb_otg_state otg_state; + enum dwc3_drd_state drd_state; enum usb_chg_state chg_state; struct work_struct bus_vote_w; unsigned int bus_vote; @@ -220,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; @@ -1934,7 +1968,7 @@ static void dwc3_msm_power_collapse_por(struct dwc3_msm *mdwc) atomic_set(&mdwc->in_p3, val == DWC3_LINK_STATE_U3); dwc3_msm_write_reg_field(mdwc->base, PWR_EVNT_IRQ_MASK_REG, PWR_EVNT_POWERDOWN_IN_P3_MASK, 1); - if (mdwc->otg_state == OTG_STATE_A_HOST) { + if (mdwc->drd_state == DRD_STATE_HOST) { dev_dbg(mdwc->dev, "%s: set the core in host mode\n", __func__); dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); @@ -2056,7 +2090,7 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc, bool hibernation) } if (!mdwc->vbus_active && dwc->is_drd && - mdwc->otg_state == OTG_STATE_B_PERIPHERAL) { + mdwc->drd_state == DRD_STATE_PERIPHERAL) { /* * In some cases, the pm_runtime_suspend may be called by * usb_bam when there is pending lpm flag. However, if this is @@ -2078,7 +2112,7 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc, bool hibernation) * then check controller state of L2 and break * LPM sequence. Check this for device bus suspend case. */ - if ((dwc->is_drd && mdwc->otg_state == OTG_STATE_B_SUSPEND) && + if ((dwc->is_drd && mdwc->drd_state == DRD_STATE_PERIPHERAL_SUSPEND) && (dwc->gadget.state != USB_STATE_CONFIGURED)) { pr_err("%s(): Trying to go in LPM with state:%d\n", __func__, dwc->gadget.state); @@ -2192,7 +2226,13 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc, bool hibernation) dev_info(mdwc->dev, "DWC3 in low power mode\n"); dbg_event(0xFF, "Ctl Sus", atomic_read(&dwc->in_lpm)); + + /* kick_sm if it is waiting for lpm sequence to finish */ + if (test_and_clear_bit(WAIT_FOR_LPM, &mdwc->inputs)) + schedule_delayed_work(&mdwc->sm_work, 0); + mutex_unlock(&mdwc->suspend_resume_mutex); + return 0; } @@ -2724,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; @@ -3272,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; @@ -3702,6 +3745,9 @@ static int dwc3_otg_start_host(struct dwc3_msm *mdwc, int on) if (!mdwc->host_only_mode) dwc3_post_host_reset_core_init(dwc); + /* wait for LPM, to ensure h/w is reset after stop_host */ + set_bit(WAIT_FOR_LPM, &mdwc->inputs); + pm_runtime_mark_last_busy(mdwc->dev); pm_runtime_put_sync_autosuspend(mdwc->dev); dbg_event(0xFF, "StopHost psync", @@ -3784,6 +3830,9 @@ static int dwc3_otg_start_peripheral(struct dwc3_msm *mdwc, int on) usb_phy_notify_disconnect(mdwc->ss_phy, USB_SPEED_SUPER); dwc3_override_vbus_status(mdwc, false); dwc3_usb3_phy_suspend(dwc, false); + + /* wait for LPM, to ensure h/w is reset after stop_peripheral */ + set_bit(WAIT_FOR_LPM, &mdwc->inputs); } pm_runtime_put_sync(mdwc->dev); @@ -3820,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 @@ -3853,7 +3903,7 @@ set_prop: * * @w: Pointer to the dwc3 otg workqueue * - * NOTE: After any change in otg_state, we must reschdule the state machine. + * NOTE: After any change in drd_state, we must reschdule the state machine. */ static void dwc3_otg_sm_work(struct work_struct *w) { @@ -3872,13 +3922,13 @@ static void dwc3_otg_sm_work(struct work_struct *w) return; } - state = usb_otg_state_string(mdwc->otg_state); + state = dwc3_drd_state_string(mdwc->drd_state); dev_dbg(mdwc->dev, "%s state\n", state); dbg_event(0xFF, state, 0); /* Check OTG state */ - switch (mdwc->otg_state) { - case OTG_STATE_UNDEFINED: + switch (mdwc->drd_state) { + case DRD_STATE_UNDEFINED: /* put controller and phy in suspend if no cable connected */ if (test_bit(ID, &mdwc->inputs) && !test_bit(B_SESS_VLD, &mdwc->inputs)) { @@ -3890,36 +3940,57 @@ static void dwc3_otg_sm_work(struct work_struct *w) pm_runtime_put_sync(mdwc->dev); dbg_event(0xFF, "Undef NoUSB", atomic_read(&mdwc->dev->power.usage_count)); - mdwc->otg_state = OTG_STATE_B_IDLE; + mdwc->drd_state = DRD_STATE_IDLE; break; } dbg_event(0xFF, "Exit UNDEF", 0); - mdwc->otg_state = OTG_STATE_B_IDLE; + mdwc->drd_state = DRD_STATE_IDLE; pm_runtime_set_suspended(mdwc->dev); pm_runtime_enable(mdwc->dev); /* fall-through */ - case OTG_STATE_B_IDLE: + case DRD_STATE_IDLE: + if (test_bit(WAIT_FOR_LPM, &mdwc->inputs)) { + dev_dbg(mdwc->dev, "still not in lpm, wait.\n"); + break; + } + if (!test_bit(ID, &mdwc->inputs)) { dev_dbg(mdwc->dev, "!id\n"); - mdwc->otg_state = OTG_STATE_A_IDLE; + mdwc->drd_state = DRD_STATE_HOST_IDLE; 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, msecs_to_jiffies(SDP_CONNETION_CHECK_TIME)); /* * Increment pm usage count upon cable connect. Count - * is decremented in OTG_STATE_B_PERIPHERAL state on + * is decremented in DRD_STATE_PERIPHERAL state on * cable disconnect or in bus suspend. */ 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->otg_state = OTG_STATE_B_PERIPHERAL; + mdwc->drd_state = DRD_STATE_PERIPHERAL; work = 1; break; } else { @@ -3929,17 +4000,17 @@ static void dwc3_otg_sm_work(struct work_struct *w) } break; - case OTG_STATE_B_PERIPHERAL: + case DRD_STATE_PERIPHERAL: if (!test_bit(B_SESS_VLD, &mdwc->inputs) || !test_bit(ID, &mdwc->inputs)) { dev_dbg(mdwc->dev, "!id || !bsv\n"); - mdwc->otg_state = OTG_STATE_B_IDLE; + mdwc->drd_state = DRD_STATE_IDLE; cancel_delayed_work_sync(&mdwc->sdp_check); dwc3_otg_start_peripheral(mdwc, 0); /* * Decrement pm usage count upon cable disconnect * which was incremented upon cable connect in - * OTG_STATE_B_IDLE state + * DRD_STATE_IDLE state */ pm_runtime_put_sync(mdwc->dev); dbg_event(0xFF, "!BSV psync", @@ -3948,13 +4019,13 @@ static void dwc3_otg_sm_work(struct work_struct *w) } else if (test_bit(B_SUSPEND, &mdwc->inputs) && test_bit(B_SESS_VLD, &mdwc->inputs)) { dev_dbg(mdwc->dev, "BPER bsv && susp\n"); - mdwc->otg_state = OTG_STATE_B_SUSPEND; + mdwc->drd_state = DRD_STATE_PERIPHERAL_SUSPEND; /* * Decrement pm usage count upon bus suspend. * Count was incremented either upon cable - * connect in OTG_STATE_B_IDLE or host + * connect in DRD_STATE_IDLE or host * initiated resume after bus suspend in - * OTG_STATE_B_SUSPEND state + * DRD_STATE_PERIPHERAL_SUSPEND state */ pm_runtime_mark_last_busy(mdwc->dev); pm_runtime_put_autosuspend(mdwc->dev); @@ -3963,20 +4034,20 @@ static void dwc3_otg_sm_work(struct work_struct *w) } break; - case OTG_STATE_B_SUSPEND: + case DRD_STATE_PERIPHERAL_SUSPEND: if (!test_bit(B_SESS_VLD, &mdwc->inputs)) { dev_dbg(mdwc->dev, "BSUSP: !bsv\n"); - mdwc->otg_state = OTG_STATE_B_IDLE; + mdwc->drd_state = DRD_STATE_IDLE; cancel_delayed_work_sync(&mdwc->sdp_check); dwc3_otg_start_peripheral(mdwc, 0); } else if (!test_bit(B_SUSPEND, &mdwc->inputs)) { dev_dbg(mdwc->dev, "BSUSP !susp\n"); - mdwc->otg_state = OTG_STATE_B_PERIPHERAL; + mdwc->drd_state = DRD_STATE_PERIPHERAL; /* * Increment pm usage count upon host * initiated resume. Count was decremented * upon bus suspend in - * OTG_STATE_B_PERIPHERAL state. + * DRD_STATE_PERIPHERAL state. */ pm_runtime_get_sync(mdwc->dev); dbg_event(0xFF, "!SUSP gsync", @@ -3984,15 +4055,15 @@ static void dwc3_otg_sm_work(struct work_struct *w) } break; - case OTG_STATE_A_IDLE: + case DRD_STATE_HOST_IDLE: /* Switch to A-Device*/ if (test_bit(ID, &mdwc->inputs)) { dev_dbg(mdwc->dev, "id\n"); - mdwc->otg_state = OTG_STATE_B_IDLE; + mdwc->drd_state = DRD_STATE_IDLE; mdwc->vbus_retry_count = 0; work = 1; } else { - mdwc->otg_state = OTG_STATE_A_HOST; + mdwc->drd_state = DRD_STATE_HOST; ret = dwc3_otg_start_host(mdwc, 1); if ((ret == -EPROBE_DEFER) && mdwc->vbus_retry_count < 3) { @@ -4000,14 +4071,14 @@ static void dwc3_otg_sm_work(struct work_struct *w) * Get regulator failed as regulator driver is * not up yet. Will try to start host after 1sec */ - mdwc->otg_state = OTG_STATE_A_IDLE; + mdwc->drd_state = DRD_STATE_HOST_IDLE; dev_dbg(mdwc->dev, "Unable to get vbus regulator. Retrying...\n"); delay = VBUS_REG_CHECK_DELAY; work = 1; mdwc->vbus_retry_count++; } else if (ret) { dev_err(mdwc->dev, "unable to start host\n"); - mdwc->otg_state = OTG_STATE_A_IDLE; + mdwc->drd_state = DRD_STATE_HOST_IDLE; goto ret; } if (mdwc->no_wakeup_src_in_hostmode) { @@ -4017,12 +4088,12 @@ static void dwc3_otg_sm_work(struct work_struct *w) } break; - case OTG_STATE_A_HOST: + case DRD_STATE_HOST: if (test_bit(ID, &mdwc->inputs) || mdwc->hc_died) { dbg_event(0xFF, "id || hc_died", 0); dev_dbg(mdwc->dev, "%s state id || hc_died\n", state); dwc3_otg_start_host(mdwc, 0); - mdwc->otg_state = OTG_STATE_B_IDLE; + mdwc->drd_state = DRD_STATE_IDLE; mdwc->vbus_retry_count = 0; mdwc->hc_died = false; work = 1; @@ -4175,7 +4246,7 @@ static int dwc3_msm_pm_restore(struct device *dev) pm_runtime_enable(dev); /* Restore PHY flags if hibernated in host mode */ - if (mdwc->otg_state == OTG_STATE_A_HOST) { + if (mdwc->drd_state == DRD_STATE_HOST) { mdwc->hs_phy->flags |= PHY_HOST_MODE; if (mdwc->ss_phy) { mdwc->ss_phy->flags |= PHY_HOST_MODE; 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/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/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(¶m_hdr, &payload[1], sizeof(struct param_hdr_v3)); data_start = &payload[5]; break; |
