From b603438690417c5e96ff477969a4dd62de04ce62 Mon Sep 17 00:00:00 2001 From: Meng Wang Date: Tue, 19 Nov 2019 09:16:55 +0800 Subject: [PATCH 1/3] dsp: afe: add new clk state and lock for codec clk cmds There's some race condition when sending afe cmds between USB playback and codec clk enablement. Add new clk_state, clk_status and clk lock to resolve the race condition. Change-Id: I2ccc77c20a274b797129b8b674c026ef003353d4 Signed-off-by: Meng Wang --- dsp/q6afe.c | 233 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 203 insertions(+), 30 deletions(-) diff --git a/dsp/q6afe.c b/dsp/q6afe.c index 80f6589eab9c..96c53c875bad 100644 --- a/dsp/q6afe.c +++ b/dsp/q6afe.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. */ #include #include @@ -23,6 +23,7 @@ #include "q6afecal-hwdep.h" #define WAKELOCK_TIMEOUT 5000 +#define AFE_CLK_TOKEN 1024 enum { AFE_COMMON_RX_CAL = 0, AFE_COMMON_TX_CAL, @@ -106,8 +107,11 @@ struct afe_ctl { void *apr; atomic_t state; atomic_t status; + atomic_t clk_state; + atomic_t clk_status; wait_queue_head_t wait[AFE_MAX_PORTS]; wait_queue_head_t wait_wakeup; + wait_queue_head_t clk_wait; struct task_struct *task; wait_queue_head_t lpass_core_hw_wait; uint32_t lpass_hw_core_client_hdl[AFE_LPASS_CORE_HW_VOTE_MAX]; @@ -154,6 +158,7 @@ struct afe_ctl { struct aanc_data aanc_info; struct mutex afe_cmd_lock; struct mutex afe_apr_lock; + struct mutex afe_clk_lock; int set_custom_topology; int dev_acdb_id[AFE_MAX_PORTS]; routing_cb rt_cb; @@ -680,8 +685,8 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv) if (data->token < AFE_LPASS_CORE_HW_VOTE_MAX) this_afe.lpass_hw_core_client_hdl[data->token] = payload[0]; - atomic_set(&this_afe.state, 0); - atomic_set(&this_afe.status, 0); + atomic_set(&this_afe.clk_state, 0); + atomic_set(&this_afe.clk_status, 0); wake_up(&this_afe.lpass_core_hw_wait); } else if (data->payload_size) { uint32_t *payload; @@ -699,7 +704,10 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv) payload[0], payload[1], data->token); /* payload[1] contains the error status for response */ if (payload[1] != 0) { - atomic_set(&this_afe.status, payload[1]); + if(data->token == AFE_CLK_TOKEN) + atomic_set(&this_afe.clk_status, payload[1]); + else + atomic_set(&this_afe.status, payload[1]); pr_err("%s: cmd = 0x%x returned error = 0x%x\n", __func__, payload[0], payload[1]); } @@ -720,11 +728,16 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv) case AFE_SVC_CMD_SET_PARAM: case AFE_SVC_CMD_SET_PARAM_V2: case AFE_PORT_CMD_MOD_EVENT_CFG: - atomic_set(&this_afe.state, 0); - if (afe_token_is_valid(data->token)) - wake_up(&this_afe.wait[data->token]); - else - return -EINVAL; + if(data->token == AFE_CLK_TOKEN) { + atomic_set(&this_afe.clk_state, 0); + wake_up(&this_afe.clk_wait); + } else { + atomic_set(&this_afe.state, 0); + if (afe_token_is_valid(data->token)) + wake_up(&this_afe.wait[data->token]); + else + return -EINVAL; + } break; case AFE_SERVICE_CMD_REGISTER_RT_PORT_DRIVER: break; @@ -770,7 +783,9 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv) break; case AFE_CMD_REMOTE_LPASS_CORE_HW_VOTE_REQUEST: case AFE_CMD_REMOTE_LPASS_CORE_HW_DEVOTE_REQUEST: - atomic_set(&this_afe.state, 0); + if (payload[1] != 0) + atomic_set(&this_afe.clk_state, + payload[1]); wake_up(&this_afe.lpass_core_hw_wait); break; case AFE_SVC_CMD_EVENT_CFG: @@ -1090,6 +1105,46 @@ static int afe_apr_send_pkt(void *data, wait_queue_head_t *wait) mutex_unlock(&this_afe.afe_apr_lock); return ret; } +/* + * afe_apr_send_clk_pkt : returns 0 on success, negative otherwise. + */ +static int afe_apr_send_clk_pkt(void *data, wait_queue_head_t *wait) +{ + int ret; + + if (wait) + atomic_set(&this_afe.clk_state, 1); + atomic_set(&this_afe.clk_status, 0); + ret = apr_send_pkt(this_afe.apr, data); + if (ret > 0) { + if (wait) { + ret = wait_event_timeout(*wait, + (atomic_read(&this_afe.clk_state) == 0), + msecs_to_jiffies(2 * TIMEOUT_MS)); + if (!ret) { + pr_err("%s: timeout\n", __func__); + ret = -ETIMEDOUT; + } else if (atomic_read(&this_afe.clk_status) > 0) { + pr_err("%s: DSP returned error[%s]\n", __func__, + adsp_err_get_err_str(atomic_read( + &this_afe.clk_status))); + ret = adsp_err_get_lnx_err_code( + atomic_read(&this_afe.clk_status)); + } else { + ret = 0; + } + } else { + ret = 0; + } + } else if (ret == 0) { + pr_err("%s: packet not transmitted\n", __func__); + /* apr_send_pkt can return 0 when nothing is transmitted */ + ret = -EINVAL; + } + + pr_debug("%s: leave %d\n", __func__, ret); + return ret; +} /* This function shouldn't be called directly. Instead call q6afe_set_params. */ static int q6afe_set_params_v2(u16 port_id, int index, @@ -1486,6 +1541,122 @@ done: return rc; } +/* + * This function shouldn't be called directly. Instead call + * q6afe_clk_set_params. + */ +static int q6afe_clk_set_params_v1(int index, struct mem_mapping_hdr *mem_hdr, + u8 *packed_param_data, u32 packed_data_size) +{ + struct afe_svc_cmd_set_param_v1 *svc_set_param = NULL; + uint32_t size = sizeof(struct afe_svc_cmd_set_param_v1); + int rc = 0; + + if (packed_param_data != NULL) + size += packed_data_size; + svc_set_param = kzalloc(size, GFP_KERNEL); + if (svc_set_param == NULL) + return -ENOMEM; + + svc_set_param->apr_hdr.hdr_field = + APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, APR_HDR_LEN(APR_HDR_SIZE), + APR_PKT_VER); + svc_set_param->apr_hdr.pkt_size = size; + svc_set_param->apr_hdr.src_port = 0; + svc_set_param->apr_hdr.dest_port = 0; + svc_set_param->apr_hdr.token = AFE_CLK_TOKEN; + svc_set_param->apr_hdr.opcode = AFE_SVC_CMD_SET_PARAM; + svc_set_param->payload_size = packed_data_size; + + if (mem_hdr != NULL) { + /* Out of band case. */ + svc_set_param->mem_hdr = *mem_hdr; + } else if (packed_param_data != NULL) { + /* In band case. */ + memcpy(&svc_set_param->param_data, packed_param_data, + packed_data_size); + } else { + pr_err("%s: Both memory header and param data are NULL\n", + __func__); + rc = -EINVAL; + goto done; + } + + rc = afe_apr_send_clk_pkt(svc_set_param, &this_afe.clk_wait); +done: + kfree(svc_set_param); + return rc; +} + +/* + * This function shouldn't be called directly. Instead call + * q6afe_clk_set_params. + */ +static int q6afe_clk_set_params_v2(int index, struct mem_mapping_hdr *mem_hdr, + u8 *packed_param_data, u32 packed_data_size) +{ + struct afe_svc_cmd_set_param_v2 *svc_set_param = NULL; + uint16_t size = sizeof(struct afe_svc_cmd_set_param_v2); + int rc = 0; + + if (packed_param_data != NULL) + size += packed_data_size; + svc_set_param = kzalloc(size, GFP_KERNEL); + if (svc_set_param == NULL) + return -ENOMEM; + + svc_set_param->apr_hdr.hdr_field = + APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, APR_HDR_LEN(APR_HDR_SIZE), + APR_PKT_VER); + svc_set_param->apr_hdr.pkt_size = size; + svc_set_param->apr_hdr.src_port = 0; + svc_set_param->apr_hdr.dest_port = 0; + svc_set_param->apr_hdr.token = AFE_CLK_TOKEN; + svc_set_param->apr_hdr.opcode = AFE_SVC_CMD_SET_PARAM_V2; + svc_set_param->payload_size = packed_data_size; + + if (mem_hdr != NULL) { + /* Out of band case. */ + svc_set_param->mem_hdr = *mem_hdr; + } else if (packed_param_data != NULL) { + /* In band case. */ + memcpy(&svc_set_param->param_data, packed_param_data, + packed_data_size); + } else { + pr_err("%s: Both memory header and param data are NULL\n", + __func__); + rc = -EINVAL; + goto done; + } + + rc = afe_apr_send_clk_pkt(svc_set_param, &this_afe.clk_wait); +done: + kfree(svc_set_param); + return rc; +} + +static int q6afe_clk_set_params(int index, struct mem_mapping_hdr *mem_hdr, + u8 *packed_param_data, u32 packed_data_size, + bool is_iid_supported) +{ + int ret; + + ret = afe_q6_interface_prepare(); + if (ret != 0) { + pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret); + return ret; + } + + if (is_iid_supported) + return q6afe_clk_set_params_v2(index, mem_hdr, + packed_param_data, + packed_data_size); + else + return q6afe_clk_set_params_v1(index, mem_hdr, + packed_param_data, + packed_data_size); +} + static int q6afe_svc_set_params(int index, struct mem_mapping_hdr *mem_hdr, u8 *packed_param_data, u32 packed_data_size, bool is_iid_supported) @@ -1530,9 +1701,12 @@ static int q6afe_svc_pack_and_set_param_in_band(int index, __func__, ret); goto done; } - - ret = q6afe_svc_set_params(index, NULL, packed_param_data, - packed_data_size, is_iid_supported); + if (param_hdr.module_id == AFE_MODULE_CLOCK_SET) + ret = q6afe_clk_set_params(index, NULL, packed_param_data, + packed_data_size, is_iid_supported); + else + ret = q6afe_svc_set_params(index, NULL, packed_param_data, + packed_data_size, is_iid_supported); done: kfree(packed_param_data); @@ -7630,13 +7804,7 @@ int afe_set_lpass_clk_cfg(int index, struct afe_clk_set *cfg) memset(¶m_hdr, 0, sizeof(param_hdr)); - ret = afe_q6_interface_prepare(); - if (ret != 0) { - pr_err_ratelimited("%s: Q6 interface prepare failed %d\n", __func__, ret); - return ret; - } - - mutex_lock(&this_afe.afe_cmd_lock); + mutex_lock(&this_afe.afe_clk_lock); param_hdr.module_id = AFE_MODULE_CLOCK_SET; param_hdr.instance_id = INSTANCE_ID_0; param_hdr.param_id = AFE_PARAM_ID_CLOCK_SET; @@ -7656,7 +7824,7 @@ int afe_set_lpass_clk_cfg(int index, struct afe_clk_set *cfg) pr_err_ratelimited("%s: AFE clk cfg failed with ret %d\n", __func__, ret); - mutex_unlock(&this_afe.afe_cmd_lock); + mutex_unlock(&this_afe.afe_clk_lock); return ret; } EXPORT_SYMBOL(afe_set_lpass_clk_cfg); @@ -9003,6 +9171,8 @@ int __init afe_init(void) atomic_set(&this_afe.state, 0); atomic_set(&this_afe.status, 0); + atomic_set(&this_afe.clk_state, 0); + atomic_set(&this_afe.clk_status, 0); atomic_set(&this_afe.mem_map_cal_index, -1); this_afe.apr = NULL; this_afe.dtmf_gen_rx_portid = -1; @@ -9016,6 +9186,7 @@ int __init afe_init(void) this_afe.ex_ftm_cfg.mode = MSM_SPKR_PROT_DISABLED; mutex_init(&this_afe.afe_cmd_lock); mutex_init(&this_afe.afe_apr_lock); + mutex_init(&this_afe.afe_clk_lock); for (i = 0; i < AFE_MAX_PORTS; i++) { this_afe.afe_cal_mode[i] = AFE_CAL_MODE_DEFAULT; this_afe.afe_sample_rates[i] = 0; @@ -9027,6 +9198,7 @@ int __init afe_init(void) } init_waitqueue_head(&this_afe.wait_wakeup); init_waitqueue_head(&this_afe.lpass_core_hw_wait); + init_waitqueue_head(&this_afe.clk_wait); wl.ws = wakeup_source_register(NULL, "spkr-prot"); if (!wl.ws) return -ENOMEM; @@ -9076,6 +9248,7 @@ void afe_exit(void) config_debug_fs_exit(); mutex_destroy(&this_afe.afe_cmd_lock); mutex_destroy(&this_afe.afe_apr_lock); + mutex_destroy(&this_afe.afe_clk_lock); wakeup_source_unregister(wl.ws); } @@ -9139,7 +9312,7 @@ int afe_vote_lpass_core_hw(uint32_t hw_block_id, char *client_name, return ret; } - mutex_lock(&this_afe.afe_cmd_lock); + mutex_lock(&this_afe.afe_clk_lock); memset(cmd_ptr, 0, sizeof(hw_vote_cfg)); @@ -9159,15 +9332,15 @@ int afe_vote_lpass_core_hw(uint32_t hw_block_id, char *client_name, __func__, cmd_ptr->hdr.opcode, cmd_ptr->hw_block_id); *client_handle = 0; - ret = afe_apr_send_pkt((uint32_t *) cmd_ptr, - &this_afe.lpass_core_hw_wait); + + ret = afe_apr_send_clk_pkt((uint32_t *)cmd_ptr, + &this_afe.lpass_core_hw_wait); if (ret == 0) { *client_handle = this_afe.lpass_hw_core_client_hdl[hw_block_id]; pr_debug("%s: lpass_hw_core_client_hdl %d\n", __func__, this_afe.lpass_hw_core_client_hdl[hw_block_id]); } - - mutex_unlock(&this_afe.afe_cmd_lock); + mutex_unlock(&this_afe.afe_clk_lock); return ret; } EXPORT_SYMBOL(afe_vote_lpass_core_hw); @@ -9193,7 +9366,7 @@ int afe_unvote_lpass_core_hw(uint32_t hw_block_id, uint32_t client_handle) return ret; } - mutex_lock(&this_afe.afe_cmd_lock); + mutex_lock(&this_afe.afe_clk_lock); if (!this_afe.lpass_hw_core_client_hdl[hw_block_id]) { pr_debug("%s: SSR in progress, return\n", __func__); @@ -9222,10 +9395,10 @@ int afe_unvote_lpass_core_hw(uint32_t hw_block_id, uint32_t client_handle) goto done; } - ret = afe_apr_send_pkt((uint32_t *) cmd_ptr, - &this_afe.lpass_core_hw_wait); + ret = afe_apr_send_clk_pkt((uint32_t *)cmd_ptr, + &this_afe.lpass_core_hw_wait); done: - mutex_unlock(&this_afe.afe_cmd_lock); + mutex_unlock(&this_afe.afe_clk_lock); return ret; } EXPORT_SYMBOL(afe_unvote_lpass_core_hw); From 0e19126c1fa63227196af797ed8b324e8a3eec5b Mon Sep 17 00:00:00 2001 From: Sudheer Papothi Date: Thu, 21 Nov 2019 07:24:42 +0530 Subject: [PATCH 2/3] ASoC: bolero: Add concurrency support on audio capture path During voice activation and audio capture concurrency usecase, there is no common reference count for DMIC clock enablement, results into mute when one usecase tears down. Change enables a common reference count in bolero codec driver between voice activation usecase and audio capture usecase to avoid mute during VA and audio capture concurrency. Change-Id: I424c941178d7e9ff91288a50ba27605b2b9d3abe Signed-off-by: Sudheer Papothi Signed-off-by: Akhil Karuturi --- asoc/codecs/bolero/bolero-cdc.c | 130 +++++++++++++++++++++++++++++++- asoc/codecs/bolero/bolero-cdc.h | 17 ++++- asoc/codecs/bolero/internal.h | 10 ++- asoc/codecs/bolero/tx-macro.c | 71 ++++------------- asoc/codecs/bolero/va-macro.c | 81 +++++--------------- 5 files changed, 190 insertions(+), 119 deletions(-) diff --git a/asoc/codecs/bolero/bolero-cdc.c b/asoc/codecs/bolero/bolero-cdc.c index 63d8d1013a86..066b72eb08ca 100644 --- a/asoc/codecs/bolero/bolero-cdc.c +++ b/asoc/codecs/bolero/bolero-cdc.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #include @@ -470,6 +470,129 @@ void bolero_unregister_res_clk(struct device *dev) } EXPORT_SYMBOL(bolero_unregister_res_clk); +static u8 bolero_dmic_clk_div_get(struct snd_soc_component *component, + int mode) +{ + struct bolero_priv* priv = snd_soc_component_get_drvdata(component); + int macro = (mode ? VA_MACRO : TX_MACRO); + int ret = 0; + + if (priv->macro_params[macro].clk_div_get) { + ret = priv->macro_params[macro].clk_div_get(component); + if (ret > 0) + return ret; + } + + return 1; +} + +int bolero_dmic_clk_enable(struct snd_soc_component *component, + u32 dmic, u32 tx_mode, bool enable) +{ + struct bolero_priv* priv = snd_soc_component_get_drvdata(component); + u8 dmic_clk_en = 0x01; + u16 dmic_clk_reg = 0; + s32 *dmic_clk_cnt = NULL; + u8 *dmic_clk_div = NULL; + u8 freq_change_mask = 0; + u8 clk_div = 0; + + dev_dbg(component->dev, "%s: enable: %d, tx_mode:%d, dmic: %d\n", + __func__, enable, tx_mode, dmic); + + switch (dmic) { + case 0: + case 1: + dmic_clk_cnt = &(priv->dmic_0_1_clk_cnt); + dmic_clk_div = &(priv->dmic_0_1_clk_div); + dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC0_CTL; + freq_change_mask = 0x01; + break; + case 2: + case 3: + dmic_clk_cnt = &(priv->dmic_2_3_clk_cnt); + dmic_clk_div = &(priv->dmic_2_3_clk_div); + dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC1_CTL; + freq_change_mask = 0x02; + break; + case 4: + case 5: + dmic_clk_cnt = &(priv->dmic_4_5_clk_cnt); + dmic_clk_div = &(priv->dmic_4_5_clk_div); + dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC2_CTL; + freq_change_mask = 0x04; + break; + case 6: + case 7: + dmic_clk_cnt = &(priv->dmic_6_7_clk_cnt); + dmic_clk_div = &(priv->dmic_6_7_clk_div); + dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC3_CTL; + freq_change_mask = 0x08; + break; + default: + dev_err(component->dev, "%s: Invalid DMIC Selection\n", + __func__); + return -EINVAL; + } + dev_dbg(component->dev, "%s: DMIC%d dmic_clk_cnt %d\n", + __func__, dmic, *dmic_clk_cnt); + if (enable) { + clk_div = bolero_dmic_clk_div_get(component, tx_mode); + (*dmic_clk_cnt)++; + if (*dmic_clk_cnt == 1) { + snd_soc_component_update_bits(component, + BOLERO_CDC_VA_TOP_CSR_DMIC_CFG, + 0x80, 0x00); + snd_soc_component_update_bits(component, dmic_clk_reg, + 0x0E, clk_div << 0x1); + snd_soc_component_update_bits(component, dmic_clk_reg, + dmic_clk_en, dmic_clk_en); + } else { + if (*dmic_clk_div > clk_div) { + snd_soc_component_update_bits(component, + BOLERO_CDC_VA_TOP_CSR_DMIC_CFG, + freq_change_mask, freq_change_mask); + snd_soc_component_update_bits(component, dmic_clk_reg, + 0x0E, clk_div << 0x1); + snd_soc_component_update_bits(component, + BOLERO_CDC_VA_TOP_CSR_DMIC_CFG, + freq_change_mask, 0x00); + } else { + clk_div = *dmic_clk_div; + } + } + *dmic_clk_div = clk_div; + } else { + (*dmic_clk_cnt)--; + if (*dmic_clk_cnt == 0) { + snd_soc_component_update_bits(component, dmic_clk_reg, + dmic_clk_en, 0); + clk_div = 0; + snd_soc_component_update_bits(component, dmic_clk_reg, + 0x0E, clk_div << 0x1); + } else { + clk_div = bolero_dmic_clk_div_get(component, tx_mode); + if (*dmic_clk_div > clk_div) { + clk_div = bolero_dmic_clk_div_get(component, !tx_mode); + snd_soc_component_update_bits(component, + BOLERO_CDC_VA_TOP_CSR_DMIC_CFG, + freq_change_mask, freq_change_mask); + snd_soc_component_update_bits(component, dmic_clk_reg, + 0x0E, clk_div << 0x1); + snd_soc_component_update_bits(component, + BOLERO_CDC_VA_TOP_CSR_DMIC_CFG, + freq_change_mask, 0x00); + } else { + clk_div = *dmic_clk_div; + } + } + *dmic_clk_div = clk_div; + } + + return 0; +} +EXPORT_SYMBOL(bolero_dmic_clk_enable); + /** * bolero_register_macro - Registers macro to bolero * @@ -518,6 +641,9 @@ int bolero_register_macro(struct device *dev, u16 macro_id, priv->macro_params[macro_id].reg_evt_listener = ops->reg_evt_listener; } + if (macro_id == TX_MACRO || macro_id == VA_MACRO) + priv->macro_params[macro_id].clk_div_get = ops->clk_div_get; + if (priv->version == BOLERO_VERSION_2_1) { if (macro_id == VA_MACRO) priv->macro_params[macro_id].reg_wake_irq = @@ -588,6 +714,8 @@ void bolero_unregister_macro(struct device *dev, u16 macro_id) priv->macro_params[macro_id].clk_switch = NULL; priv->macro_params[macro_id].reg_evt_listener = NULL; } + if (macro_id == TX_MACRO || macro_id == VA_MACRO) + priv->macro_params[macro_id].clk_div_get = NULL; priv->num_dais -= priv->macro_params[macro_id].num_dais; priv->num_macros_registered--; diff --git a/asoc/codecs/bolero/bolero-cdc.h b/asoc/codecs/bolero/bolero-cdc.h index 2ec4617447bd..dd58eed87c86 100644 --- a/asoc/codecs/bolero/bolero-cdc.h +++ b/asoc/codecs/bolero/bolero-cdc.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #ifndef BOLERO_CDC_H @@ -50,6 +50,12 @@ enum { BOLERO_MACRO_EVT_BCS_CLK_OFF }; +enum { + DMIC_TX = 0, + DMIC_VA = 1, + +}; + struct macro_ops { int (*init)(struct snd_soc_component *component); int (*exit)(struct snd_soc_component *component); @@ -63,6 +69,7 @@ struct macro_ops { int (*set_port_map)(struct snd_soc_component *component, u32 uc, u32 size, void *data); int (*clk_switch)(struct snd_soc_component *component); + int (*clk_div_get)(struct snd_soc_component *component); int (*reg_evt_listener)(struct snd_soc_component *component, bool en); char __iomem *io_base; u16 clk_id_req; @@ -93,6 +100,8 @@ int bolero_register_event_listener(struct snd_soc_component *component, void bolero_wsa_pa_on(struct device *dev); bool bolero_check_core_votes(struct device *dev); int bolero_get_version(struct device *dev); +int bolero_dmic_clk_enable(struct snd_soc_component *component, + u32 dmic, u32 tx_mode, bool enable); #else static inline int bolero_register_res_clk(struct device *dev, rsc_clk_cb_t cb) { @@ -177,5 +186,11 @@ static int bolero_get_version(struct device *dev) { return 0; } + +static int bolero_dmic_clk_enable(struct snd_soc_component *component, + u32 dmic, u32 tx_mode, bool enable) +{ + return 0; +} #endif /* CONFIG_SND_SOC_BOLERO */ #endif /* BOLERO_CDC_H */ diff --git a/asoc/codecs/bolero/internal.h b/asoc/codecs/bolero/internal.h index d18568b0eb16..503443158c4a 100644 --- a/asoc/codecs/bolero/internal.h +++ b/asoc/codecs/bolero/internal.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #ifndef _BOLERO_INTERNAL_H @@ -82,6 +82,14 @@ struct bolero_priv { struct blocking_notifier_head notifier; struct device *clk_dev; rsc_clk_cb_t rsc_clk_cb; + s32 dmic_0_1_clk_cnt; + s32 dmic_2_3_clk_cnt; + s32 dmic_4_5_clk_cnt; + s32 dmic_6_7_clk_cnt; + u8 dmic_0_1_clk_div; + u8 dmic_2_3_clk_div; + u8 dmic_4_5_clk_div; + u8 dmic_6_7_clk_div; }; struct regmap *bolero_regmap_init(struct device *dev, diff --git a/asoc/codecs/bolero/tx-macro.c b/asoc/codecs/bolero/tx-macro.c index 80a0ea84acb2..669f9f009ac9 100644 --- a/asoc/codecs/bolero/tx-macro.c +++ b/asoc/codecs/bolero/tx-macro.c @@ -158,10 +158,6 @@ struct tx_macro_priv { struct work_struct tx_macro_add_child_devices_work; struct hpf_work tx_hpf_work[NUM_DECIMATORS]; struct tx_mute_work tx_mute_dwork[NUM_DECIMATORS]; - s32 dmic_0_1_clk_cnt; - s32 dmic_2_3_clk_cnt; - s32 dmic_4_5_clk_cnt; - s32 dmic_6_7_clk_cnt; u16 dmic_clk_div; u32 version; u32 is_used_tx_swr_gpio; @@ -814,17 +810,9 @@ static int tx_macro_enable_dmic(struct snd_soc_dapm_widget *w, { struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); - u8 dmic_clk_en = 0x01; - u16 dmic_clk_reg = 0; - s32 *dmic_clk_cnt = NULL; unsigned int dmic = 0; int ret = 0; char *wname = NULL; - struct device *tx_dev = NULL; - struct tx_macro_priv *tx_priv = NULL; - - if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) - return -EINVAL; wname = strpbrk(w->name, "01234567"); if (!wname) { @@ -839,54 +827,15 @@ static int tx_macro_enable_dmic(struct snd_soc_dapm_widget *w, return -EINVAL; } - switch (dmic) { - case 0: - case 1: - dmic_clk_cnt = &(tx_priv->dmic_0_1_clk_cnt); - dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC0_CTL; - break; - case 2: - case 3: - dmic_clk_cnt = &(tx_priv->dmic_2_3_clk_cnt); - dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC1_CTL; - break; - case 4: - case 5: - dmic_clk_cnt = &(tx_priv->dmic_4_5_clk_cnt); - dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC2_CTL; - break; - case 6: - case 7: - dmic_clk_cnt = &(tx_priv->dmic_6_7_clk_cnt); - dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC3_CTL; - break; - default: - dev_err(component->dev, "%s: Invalid DMIC Selection\n", - __func__); - return -EINVAL; - } - dev_dbg(component->dev, "%s: event %d DMIC%d dmic_clk_cnt %d\n", - __func__, event, dmic, *dmic_clk_cnt); + dev_dbg(component->dev, "%s: event %d DMIC%d\n", + __func__, event, dmic); switch (event) { case SND_SOC_DAPM_PRE_PMU: - (*dmic_clk_cnt)++; - if (*dmic_clk_cnt == 1) { - snd_soc_component_update_bits(component, - BOLERO_CDC_VA_TOP_CSR_DMIC_CFG, - 0x80, 0x00); - - snd_soc_component_update_bits(component, dmic_clk_reg, - 0x0E, tx_priv->dmic_clk_div << 0x1); - snd_soc_component_update_bits(component, dmic_clk_reg, - dmic_clk_en, dmic_clk_en); - } + bolero_dmic_clk_enable(component, dmic, DMIC_TX, true); break; case SND_SOC_DAPM_POST_PMD: - (*dmic_clk_cnt)--; - if (*dmic_clk_cnt == 0) - snd_soc_component_update_bits(component, dmic_clk_reg, - dmic_clk_en, 0); + bolero_dmic_clk_enable(component, dmic, DMIC_TX, false); break; } @@ -2590,6 +2539,17 @@ exit: return ret; } +static int tx_macro_clk_div_get(struct snd_soc_component *component) +{ + struct device *tx_dev = NULL; + struct tx_macro_priv *tx_priv = NULL; + + if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + return tx_priv->dmic_clk_div; +} + static int tx_macro_clk_switch(struct snd_soc_component *component) { struct device *tx_dev = NULL; @@ -3093,6 +3053,7 @@ static void tx_macro_init_ops(struct macro_ops *ops, ops->event_handler = tx_macro_event_handler; ops->reg_wake_irq = tx_macro_reg_wake_irq; ops->set_port_map = tx_macro_set_port_map; + ops->clk_div_get = tx_macro_clk_div_get; ops->clk_switch = tx_macro_clk_switch; ops->reg_evt_listener = tx_macro_register_event_listener; } diff --git a/asoc/codecs/bolero/va-macro.c b/asoc/codecs/bolero/va-macro.c index 319fc63319e3..116a2dae30c6 100644 --- a/asoc/codecs/bolero/va-macro.c +++ b/asoc/codecs/bolero/va-macro.c @@ -142,10 +142,6 @@ struct va_macro_priv { struct va_mute_work va_mute_dwork[VA_MACRO_NUM_DECIMATORS]; unsigned long active_ch_mask[VA_MACRO_MAX_DAIS]; unsigned long active_ch_cnt[VA_MACRO_MAX_DAIS]; - s32 dmic_0_1_clk_cnt; - s32 dmic_2_3_clk_cnt; - s32 dmic_4_5_clk_cnt; - s32 dmic_6_7_clk_cnt; u16 dmic_clk_div; u16 va_mclk_users; int swr_clk_users; @@ -196,6 +192,17 @@ static bool va_macro_get_data(struct snd_soc_component *component, return true; } +static int va_macro_clk_div_get(struct snd_soc_component *component) +{ + struct device *va_dev = NULL; + struct va_macro_priv *va_priv = NULL; + + if (!va_macro_get_data(component, &va_dev, &va_priv, __func__)) + return -EINVAL; + + return va_priv->dmic_clk_div; +} + static int va_macro_mclk_enable(struct va_macro_priv *va_priv, bool mclk_enable, bool dapm) { @@ -978,81 +985,32 @@ static int va_macro_enable_dmic(struct snd_soc_dapm_widget *w, { struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); - u8 dmic_clk_en = 0x01; - u16 dmic_clk_reg; - s32 *dmic_clk_cnt; - unsigned int dmic; - int ret; + unsigned int dmic = 0; + int ret = 0; char *wname; - struct device *va_dev = NULL; - struct va_macro_priv *va_priv = NULL; - - if (!va_macro_get_data(component, &va_dev, &va_priv, __func__)) - return -EINVAL; wname = strpbrk(w->name, "01234567"); if (!wname) { - dev_err(va_dev, "%s: widget not found\n", __func__); + dev_err(component->dev, "%s: widget not found\n", __func__); return -EINVAL; } ret = kstrtouint(wname, 10, &dmic); if (ret < 0) { - dev_err(va_dev, "%s: Invalid DMIC line on the codec\n", + dev_err(component->dev, "%s: Invalid DMIC line on the codec\n", __func__); return -EINVAL; } - switch (dmic) { - case 0: - case 1: - dmic_clk_cnt = &(va_priv->dmic_0_1_clk_cnt); - dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC0_CTL; - break; - case 2: - case 3: - dmic_clk_cnt = &(va_priv->dmic_2_3_clk_cnt); - dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC1_CTL; - break; - case 4: - case 5: - dmic_clk_cnt = &(va_priv->dmic_4_5_clk_cnt); - dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC2_CTL; - break; - case 6: - case 7: - dmic_clk_cnt = &(va_priv->dmic_6_7_clk_cnt); - dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC3_CTL; - break; - default: - dev_err(va_dev, "%s: Invalid DMIC Selection\n", - __func__); - return -EINVAL; - } - dev_dbg(va_dev, "%s: event %d DMIC%d dmic_clk_cnt %d\n", - __func__, event, dmic, *dmic_clk_cnt); + dev_dbg(component->dev, "%s: event %d DMIC%d\n", + __func__, event, dmic); switch (event) { case SND_SOC_DAPM_PRE_PMU: - (*dmic_clk_cnt)++; - if (*dmic_clk_cnt == 1) { - snd_soc_component_update_bits(component, - BOLERO_CDC_VA_TOP_CSR_DMIC_CFG, - 0x80, 0x00); - snd_soc_component_update_bits(component, dmic_clk_reg, - VA_MACRO_TX_DMIC_CLK_DIV_MASK, - va_priv->dmic_clk_div << - VA_MACRO_TX_DMIC_CLK_DIV_SHFT); - snd_soc_component_update_bits(component, dmic_clk_reg, - dmic_clk_en, dmic_clk_en); - } + bolero_dmic_clk_enable(component, dmic, DMIC_VA, true); break; case SND_SOC_DAPM_POST_PMD: - (*dmic_clk_cnt)--; - if (*dmic_clk_cnt == 0) { - snd_soc_component_update_bits(component, dmic_clk_reg, - dmic_clk_en, 0); - } + bolero_dmic_clk_enable(component, dmic, DMIC_VA, false); break; } @@ -2795,6 +2753,7 @@ static void va_macro_init_ops(struct macro_ops *ops, ops->event_handler = va_macro_event_handler; ops->set_port_map = va_macro_set_port_map; ops->reg_wake_irq = va_macro_reg_wake_irq; + ops->clk_div_get = va_macro_clk_div_get; } static int va_macro_probe(struct platform_device *pdev) From 7fcb671a3db7d1d70594e7cd0799942772b63e54 Mon Sep 17 00:00:00 2001 From: Derek Chen Date: Wed, 11 Dec 2019 15:40:03 -0800 Subject: [PATCH 3/3] ASoC: msm: update QUAT/QUIN TDM slot mappings for A2B Update QUAT and QUIN TDM slot mappings for extended usecases over A2B codec. QUAT TDM RX 0 -> DAC1 (8 CH) QUAT TDM RX 1 -> DAC2 (8 CH) QUAT TDM TX 0 -> ADC1 and ADC2 (16 CH) QUIN TDM RX 0 -> DAC1 and DAC2 (16 CH) QUIN TDM TX 0 -> ADC1 and ADC2 (16 CH) Change-Id: I0d13ab3d44a05716a043189e6eb6c809dfff6d9d Signed-off-by: Derek Chen --- asoc/sa6155.c | 49 ++++++++++++++++++++----------------------------- asoc/sa8155.c | 38 ++++++++++++++++++++------------------ 2 files changed, 40 insertions(+), 47 deletions(-) diff --git a/asoc/sa6155.c b/asoc/sa6155.c index 7335d4fdd23d..3b88c96dd7b7 100644 --- a/asoc/sa6155.c +++ b/asoc/sa6155.c @@ -1,13 +1,4 @@ -/* Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. +/* Copyright (c) 2014-2020, The Linux Foundation. All rights reserved. */ /* * Copyright 2011, The Android Open Source Project @@ -213,7 +204,7 @@ static struct dev_config tdm_rx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = { }, { /* QUAT TDM */ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 8}, /* RX_0 */ - {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 8}, /* RX_1 */ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */ @@ -222,10 +213,10 @@ static struct dev_config tdm_rx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = { {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */ }, { /* QUIN TDM */ - {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* RX_0 */ - {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* RX_1 */ - {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* RX_2 */ - {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* RX_3 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 6}, /* RX_0 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */ @@ -276,9 +267,9 @@ static struct dev_config tdm_tx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = { {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */ }, { /* QUIN TDM */ - {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 6}, /* TX_0 */ - {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */ - {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 4}, /* TX_0 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* TX_1 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* TX_2 */ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_4 */ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */ @@ -415,20 +406,20 @@ static unsigned int tdm_rx_slot_offset {0xFFFF}, /* not used */ }, {/* QUAT TDM */ - {0, 4, 8, 12, 16, 20, 24, 28, 0xFFFF},/*AMP OUT*/ + {0, 8, 16, 24, 32, 40, 48, 56, 0xFFFF}, /*8 CH SPKR*/ + {4, 12, 20, 28, 36, 44, 52, 60, 0xFFFF}, /*8 CH SPKR*/ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ - {28,0xFFFF}, + {60,0xFFFF}, }, {/* QUIN TDM */ - {0, 4, 0xFFFF},/*STEREO SPKR1*/ - {8, 12, 0xFFFF},/*STEREO SPKR2*/ - {16, 20, 0xFFFF},/*STEREO SPKR3*/ - {24, 28, 0xFFFF},/*STEREO SPKR4*/ + {0, 4, 8, 12, 16, 20, 0xFFFF}, + {24, 0xFFFF}, + {28, 0xFFFF}, + {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ @@ -480,14 +471,14 @@ static unsigned int tdm_tx_slot_offset {60,0xFFFF}, }, {/* QUIN TDM */ - {0, 4, 8, 12, 16, 20, 0xFFFF},/*EC/ANC REF*/ + {0, 4, 8, 12, 0xFFFF}, + {16, 20, 0xFFFF}, + {24, 28, 0xFFFF}, {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ - {20, 0xFFFF}, + {28, 0xFFFF}, } }; diff --git a/asoc/sa8155.c b/asoc/sa8155.c index 695f122686bb..098c9c12ee8e 100644 --- a/asoc/sa8155.c +++ b/asoc/sa8155.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2020, The Linux Foundation. All rights reserved. */ /* * Copyright 2011, The Android Open Source Project @@ -205,7 +205,7 @@ static struct dev_config tdm_rx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = { }, { /* QUAT TDM */ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 8}, /* RX_0 */ - {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 8}, /* RX_1 */ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */ @@ -214,10 +214,10 @@ static struct dev_config tdm_rx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = { {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */ }, { /* QUIN TDM */ - {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* RX_0 */ - {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* RX_1 */ - {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* RX_2 */ - {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* RX_3 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 16}, /* RX_0 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */ @@ -268,7 +268,7 @@ static struct dev_config tdm_tx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = { {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */ }, { /* QUIN TDM */ - {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 6}, /* TX_0 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 16}, /* TX_0 */ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */ @@ -407,24 +407,25 @@ static unsigned int tdm_rx_slot_offset {0xFFFF}, /* not used */ }, {/* QUAT TDM */ - {0, 4, 8, 12, 16, 20, 24, 28, 0xFFFF},/*AMP OUT*/ + {0, 8, 16, 24, 32, 40, 48, 56, 0xFFFF}, /*8 CH SPKR*/ + {4, 12, 20, 28, 36, 44, 52, 60, 0xFFFF}, /*8 CH SPKR*/ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ - {0xFFFF}, /* not used */ - {28,0xFFFF}, + {60,0xFFFF}, }, {/* QUIN TDM */ - {0, 4, 0xFFFF},/*STEREO SPKR1*/ - {8, 12, 0xFFFF},/*STEREO SPKR2*/ - {16, 20, 0xFFFF},/*STEREO SPKR3*/ - {24, 28, 0xFFFF},/*STEREO SPKR4*/ + {0, 8, 16, 24, 32, 40, 48, 56, + 4, 12, 20, 28, 36, 44, 52, 60, 0xFFFF}, /*16 CH SPKR*/ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ - {28, 0xFFFF}, + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {60, 0xFFFF}, } }; @@ -462,7 +463,7 @@ static unsigned int tdm_tx_slot_offset }, {/* QUAT TDM */ {0, 4, 8, 12, 16, 20, 24, 28, - 32, 36, 40, 44, 48, 52, 56, 60, 0xFFFF},/*MIC ARR*/ + 32, 36, 40, 44, 48, 52, 56, 60, 0xFFFF},/*16 CH MIC ARR1*/ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ @@ -472,14 +473,15 @@ static unsigned int tdm_tx_slot_offset {60,0xFFFF}, }, {/* QUIN TDM */ - {0, 4, 8, 12, 16, 20, 0xFFFF},/*EC/ANC REF*/ + {0, 4, 8, 12, 16, 20, 24, 28, + 32, 36, 40, 44, 48, 52, 56, 60, 0xFFFF},/*16 CH MIC ARR2*/ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ {0xFFFF}, /* not used */ - {20, 0xFFFF}, + {60, 0xFFFF}, } };