Loading asoc/codecs/audio-ext-clk-up.c +25 −56 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. /* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. */ #include <linux/kernel.h> Loading @@ -14,7 +14,6 @@ #include <linux/platform_device.h> #include <dt-bindings/clock/qcom,audio-ext-clk.h> #include <dsp/q6afe-v2.h> #include <dsp/q6core.h> #include "audio-ext-clk-up.h" enum { Loading @@ -27,7 +26,7 @@ enum { AUDIO_EXT_CLK_LPASS5, AUDIO_EXT_CLK_LPASS6, AUDIO_EXT_CLK_LPASS7, AUDIO_EXT_CLK_LPASS_NPA_RSC_ISLAND, AUDIO_EXT_CLK_LPASS_CORE_HW_VOTE, AUDIO_EXT_CLK_LPASS_MAX, AUDIO_EXT_CLK_EXTERNAL_PLL = AUDIO_EXT_CLK_LPASS_MAX, AUDIO_EXT_CLK_MAX, Loading @@ -51,7 +50,7 @@ struct audio_ext_clk_priv { struct afe_clk_set clk_cfg; struct audio_ext_clk audio_clk; const char *clk_name; uint32_t npa_rsc_client_handle; uint32_t lpass_core_hwvote_client_handle; }; static inline struct audio_ext_clk_priv *to_audio_clk(struct clk_hw *hw) Loading Loading @@ -138,46 +137,40 @@ static u8 audio_ext_clk_get_parent(struct clk_hw *hw) return 0; } static int lpass_npa_rsc_prepare(struct clk_hw *hw) static int lpass_hw_vote_prepare(struct clk_hw *hw) { struct audio_ext_clk_priv *clk_priv = to_audio_clk(hw); int ret; if ((clk_priv->clk_src >= AUDIO_EXT_CLK_LPASS_NPA_RSC_ISLAND) && (clk_priv->clk_src < AUDIO_EXT_CLK_LPASS_MAX)) { if (q6core_get_avcs_api_version_per_service( APRV2_IDS_SERVICE_ID_ADSP_CORE_V) >= AVCS_API_VERSION_V4) { ret = q6core_request_island_transition( clk_priv->npa_rsc_client_handle, false); if (clk_priv->clk_src == AUDIO_EXT_CLK_LPASS_CORE_HW_VOTE) { ret = afe_vote_lpass_core_hw(AFE_LPASS_CORE_HW_MACRO_BLOCK, "LPASS_HW_MACRO", &clk_priv->lpass_core_hwvote_client_handle); if (ret < 0) { pr_err("%s q6core_request_island_transition failed %d\n", pr_err("%s lpass core hw vote failed %d\n", __func__, ret); return ret; } } } return 0; } static void lpass_npa_rsc_unprepare(struct clk_hw *hw) static void lpass_hw_vote_unprepare(struct clk_hw *hw) { struct audio_ext_clk_priv *clk_priv = to_audio_clk(hw); int ret = 0; if ((clk_priv->clk_src >= AUDIO_EXT_CLK_LPASS_NPA_RSC_ISLAND) && (clk_priv->clk_src < AUDIO_EXT_CLK_LPASS_MAX)) { if (q6core_get_avcs_api_version_per_service( APRV2_IDS_SERVICE_ID_ADSP_CORE_V) >= AVCS_API_VERSION_V4) { ret = q6core_request_island_transition( clk_priv->npa_rsc_client_handle, true); if (clk_priv->clk_src == AUDIO_EXT_CLK_LPASS_CORE_HW_VOTE) { ret = afe_unvote_lpass_core_hw( AFE_LPASS_CORE_HW_MACRO_BLOCK, clk_priv->lpass_core_hwvote_client_handle); if (ret < 0) { pr_err("%s q6core_request_island_transition failed %d\n", pr_err("%s lpass core hw vote failed %d\n", __func__, ret); } } } } static const struct clk_ops audio_ext_clk_ops = { .prepare = audio_ext_clk_prepare, Loading @@ -185,9 +178,9 @@ static const struct clk_ops audio_ext_clk_ops = { .get_parent = audio_ext_clk_get_parent, }; static const struct clk_ops lpass_npa_rsc_ops = { .prepare = lpass_npa_rsc_prepare, .unprepare = lpass_npa_rsc_unprepare, static const struct clk_ops lpass_hw_vote_ops = { .prepare = lpass_hw_vote_prepare, .unprepare = lpass_hw_vote_unprepare, }; static const char * const audio_ext_pmi_div_clk[] = { Loading Loading @@ -322,8 +315,8 @@ static struct audio_ext_clk audio_clk_array[] = { .pnctrl_info = {NULL}, .fact = { .hw.init = &(struct clk_init_data){ .name = "lpass_npa_rsc_island_clk", .ops = &lpass_npa_rsc_ops, .name = "lpass_hw_vote_clk", .ops = &lpass_hw_vote_ops, }, }, }, Loading Loading @@ -539,35 +532,11 @@ static int audio_ref_clk_probe(struct platform_device *pdev) audio_put_pinctrl(pdev); return ret; } if (clk_priv->clk_src == AUDIO_EXT_CLK_LPASS_NPA_RSC_ISLAND) { if (q6core_get_avcs_api_version_per_service( APRV2_IDS_SERVICE_ID_ADSP_CORE_V) >= AVCS_API_VERSION_V4) { ret = q6core_create_lpass_npa_client( AVCS_SLEEP_NODE_ISLAND_TRANSITION_RESOURCE_ID, "lpass_npa_rsc_mgr", &clk_priv->npa_rsc_client_handle); if (ret) { dev_err(&pdev->dev, "%s: q6core_create_lpass_npa_client is failed %d\n", __func__, ret); audio_put_pinctrl(pdev); return ret; } } } return 0; } static int audio_ref_clk_remove(struct platform_device *pdev) { struct audio_ext_clk_priv *clk_priv = platform_get_drvdata(pdev); if (clk_priv->clk_src == AUDIO_EXT_CLK_LPASS_NPA_RSC_ISLAND) { if (q6core_get_avcs_api_version_per_service( APRV2_IDS_SERVICE_ID_ADSP_CORE_V) >= AVCS_API_VERSION_V4) q6core_destroy_lpass_npa_client( clk_priv->npa_rsc_client_handle); } audio_put_pinctrl(pdev); return 0; Loading asoc/codecs/bolero/bolero-cdc.c +15 −15 Original line number Diff line number Diff line Loading @@ -949,7 +949,7 @@ static int bolero_probe(struct platform_device *pdev) struct bolero_priv *priv; u32 num_macros = 0; int ret; struct clk *lpass_npa_rsc_island = NULL; struct clk *lpass_core_hw_vote = NULL; priv = devm_kzalloc(&pdev->dev, sizeof(struct bolero_priv), GFP_KERNEL); Loading Loading @@ -998,16 +998,16 @@ static int bolero_probe(struct platform_device *pdev) bolero_add_child_devices); schedule_work(&priv->bolero_add_child_devices_work); /* Register LPASS NPA resource */ lpass_npa_rsc_island = devm_clk_get(&pdev->dev, "island_lpass_npa_rsc"); if (IS_ERR(lpass_npa_rsc_island)) { ret = PTR_ERR(lpass_npa_rsc_island); /* Register LPASS core hw vote */ lpass_core_hw_vote = devm_clk_get(&pdev->dev, "lpass_core_hw_vote"); if (IS_ERR(lpass_core_hw_vote)) { ret = PTR_ERR(lpass_core_hw_vote); dev_dbg(&pdev->dev, "%s: clk get %s failed %d\n", __func__, "island_lpass_npa_rsc", ret); lpass_npa_rsc_island = NULL; __func__, "lpass_core_hw_vote", ret); lpass_core_hw_vote = NULL; ret = 0; } priv->lpass_npa_rsc_island = lpass_npa_rsc_island; priv->lpass_core_hw_vote = lpass_core_hw_vote; return 0; } Loading @@ -1030,14 +1030,14 @@ int bolero_runtime_resume(struct device *dev) struct bolero_priv *priv = dev_get_drvdata(dev->parent); int ret = 0; if (priv->lpass_npa_rsc_island == NULL) { dev_dbg(dev, "%s: Invalid lpass npa rsc node\n", __func__); if (priv->lpass_core_hw_vote == NULL) { dev_dbg(dev, "%s: Invalid lpass core hw node\n", __func__); return 0; } ret = clk_prepare_enable(priv->lpass_npa_rsc_island); ret = clk_prepare_enable(priv->lpass_core_hw_vote); if (ret < 0) dev_err(dev, "%s:lpass npa rsc island enable failed\n", dev_err(dev, "%s:lpass core hw enable failed\n", __func__); pm_runtime_set_autosuspend_delay(priv->dev, BOLERO_AUTO_SUSPEND_DELAY); Loading @@ -1050,10 +1050,10 @@ int bolero_runtime_suspend(struct device *dev) struct bolero_priv *priv = dev_get_drvdata(dev->parent); mutex_lock(&priv->clk_lock); if (priv->lpass_npa_rsc_island != NULL) clk_disable_unprepare(priv->lpass_npa_rsc_island); if (priv->lpass_core_hw_vote != NULL) clk_disable_unprepare(priv->lpass_core_hw_vote); else dev_dbg(dev, "%s: Invalid lpass npa rsc node\n", dev_dbg(dev, "%s: Invalid lpass core hw node\n", __func__); mutex_unlock(&priv->clk_lock); return 0; Loading asoc/codecs/bolero/internal.h +2 −2 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* Copyright (c) 2018, The Linux Foundation. All rights reserved. /* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. */ #ifndef _BOLERO_INTERNAL_H Loading Loading @@ -57,7 +57,7 @@ struct bolero_priv { u16 current_mclk_mux_macro[MAX_MACRO]; struct work_struct bolero_add_child_devices_work; u32 version; struct clk *lpass_npa_rsc_island; struct clk *lpass_core_hw_vote; /* Entry for version info */ struct snd_info_entry *entry; Loading dsp/q6afe.c +177 −0 Original line number Diff line number Diff line Loading @@ -92,6 +92,9 @@ struct afe_ctl { atomic_t status; wait_queue_head_t wait[AFE_MAX_PORTS]; wait_queue_head_t wait_wakeup; struct task_struct *task; wait_queue_head_t lpass_core_hw_wait; uint32_t lpass_hw_core_client_hdl; void (*tx_cb)(uint32_t opcode, uint32_t token, uint32_t *payload, void *priv); void (*rx_cb)(uint32_t opcode, Loading Loading @@ -555,6 +558,16 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv) return -EINVAL; } else if (data->opcode == AFE_EVENT_MBHC_DETECTION_SW_WA) { msm_aud_evt_notifier_call_chain(SWR_WAKE_IRQ_EVENT, NULL); } else if (data->opcode == AFE_CMD_RSP_REMOTE_LPASS_CORE_HW_VOTE_REQUEST) { uint32_t *payload = data->payload; pr_debug("%s: AFE_CMD_RSP_REMOTE_LPASS_CORE_HW_VOTE_REQUEST handle %d\n", __func__, payload[0]); this_afe.lpass_hw_core_client_hdl = payload[0]; atomic_set(&this_afe.state, 0); atomic_set(&this_afe.status, 0); wake_up(&this_afe.lpass_core_hw_wait); } else if (data->payload_size) { uint32_t *payload; uint16_t port_id = 0; Loading Loading @@ -635,6 +648,11 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv) else return -EINVAL; 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); wake_up(&this_afe.lpass_core_hw_wait); break; case AFE_SVC_CMD_EVENT_CFG: atomic_set(&this_afe.state, payload[1]); wake_up(&this_afe.wait_wakeup); Loading Loading @@ -8427,6 +8445,7 @@ int __init afe_init(void) init_waitqueue_head(&this_afe.wait[i]); } init_waitqueue_head(&this_afe.wait_wakeup); init_waitqueue_head(&this_afe.lpass_core_hw_wait); wakeup_source_init(&wl.ws, "spkr-prot"); ret = afe_init_cal_data(); if (ret) Loading Loading @@ -8498,3 +8517,161 @@ int afe_cal_init_hwdep(void *card) return ret; } EXPORT_SYMBOL(afe_cal_init_hwdep); /* * afe_vote_lpass_core_hw - * Voting for lpass core hardware * * @hw_block_id: id of the hardware block * @client_name: client name * @client_handle: client handle * */ int afe_vote_lpass_core_hw(uint32_t hw_block_id, char *client_name, uint32_t *client_handle) { struct afe_cmd_remote_lpass_core_hw_vote_request hw_vote_cfg; struct afe_cmd_remote_lpass_core_hw_vote_request *cmd_ptr = &hw_vote_cfg; int ret = 0; if (!client_handle) { pr_err("%s: Invalid client_handle\n", __func__); return -EINVAL; } if (!client_name) { pr_err("%s: Invalid client_name\n", __func__); *client_handle = 0; return -EINVAL; } mutex_lock(&this_afe.afe_cmd_lock); memset(cmd_ptr, 0, sizeof(hw_vote_cfg)); cmd_ptr->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER); cmd_ptr->hdr.pkt_size = sizeof(hw_vote_cfg); cmd_ptr->hdr.src_port = 0; cmd_ptr->hdr.dest_port = 0; cmd_ptr->hdr.token = 0; cmd_ptr->hdr.opcode = AFE_CMD_REMOTE_LPASS_CORE_HW_VOTE_REQUEST; cmd_ptr->hw_block_id = hw_block_id; strlcpy(cmd_ptr->client_name, client_name, sizeof(cmd_ptr->client_name)); pr_debug("%s: lpass core hw vote opcode[0x%x] hw id[0x%x]\n", __func__, cmd_ptr->hdr.opcode, cmd_ptr->hw_block_id); *client_handle = 0; atomic_set(&this_afe.status, 0); atomic_set(&this_afe.state, 1); ret = apr_send_pkt(this_afe.apr, (uint32_t *) cmd_ptr); if (ret < 0) { pr_err("%s: lpass core hw vote failed %d\n", __func__, ret); goto done; } ret = wait_event_timeout(this_afe.lpass_core_hw_wait, (atomic_read(&this_afe.state) == 0), msecs_to_jiffies(TIMEOUT_MS)); if (!ret) { pr_err("%s: timeout. waited for lpass core hw vote\n", __func__); ret = -ETIMEDOUT; goto done; } else { /* set ret to 0 as no timeout happened */ ret = 0; } if (atomic_read(&this_afe.status) > 0) { pr_err("%s: lpass core hw vote cmd failed [%s]\n", __func__, adsp_err_get_err_str( atomic_read(&this_afe.status))); ret = adsp_err_get_lnx_err_code( atomic_read(&this_afe.status)); goto done; } *client_handle = this_afe.lpass_hw_core_client_hdl; pr_debug("%s: lpass_hw_core_client_hdl %d\n", __func__, this_afe.lpass_hw_core_client_hdl); done: mutex_unlock(&this_afe.afe_cmd_lock); return ret; } EXPORT_SYMBOL(afe_vote_lpass_core_hw); /* * afe_unvote_lpass_core_hw - * unvoting for lpass core hardware * * @hw_block_id: id of the hardware block * @client_handle: client handle * */ int afe_unvote_lpass_core_hw(uint32_t hw_block_id, uint32_t client_handle) { struct afe_cmd_remote_lpass_core_hw_devote_request hw_vote_cfg; struct afe_cmd_remote_lpass_core_hw_devote_request *cmd_ptr = &hw_vote_cfg; int ret = 0; mutex_lock(&this_afe.afe_cmd_lock); memset(cmd_ptr, 0, sizeof(hw_vote_cfg)); cmd_ptr->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER); cmd_ptr->hdr.pkt_size = sizeof(hw_vote_cfg); cmd_ptr->hdr.src_port = 0; cmd_ptr->hdr.dest_port = 0; cmd_ptr->hdr.token = 0; cmd_ptr->hdr.opcode = AFE_CMD_REMOTE_LPASS_CORE_HW_DEVOTE_REQUEST; cmd_ptr->hw_block_id = hw_block_id; cmd_ptr->client_handle = client_handle; pr_debug("%s: lpass core hw unvote opcode[0x%x] hw id[0x%x]\n", __func__, cmd_ptr->hdr.opcode, cmd_ptr->hw_block_id); atomic_set(&this_afe.status, 0); atomic_set(&this_afe.state, 1); ret = apr_send_pkt(this_afe.apr, (uint32_t *) cmd_ptr); if (ret < 0) { pr_err("%s: lpass core hw devote failed %d\n", __func__, ret); goto done; } ret = wait_event_timeout(this_afe.lpass_core_hw_wait, (atomic_read(&this_afe.state) == 0), msecs_to_jiffies(TIMEOUT_MS)); if (!ret) { pr_err("%s: timeout. waited for lpass core hw devote\n", __func__); ret = -ETIMEDOUT; goto done; } else { /* set ret to 0 as no timeout happened */ ret = 0; } if (atomic_read(&this_afe.status) > 0) { pr_err("%s: lpass core hw devote cmd failed [%s]\n", __func__, adsp_err_get_err_str( atomic_read(&this_afe.status))); ret = adsp_err_get_lnx_err_code( atomic_read(&this_afe.status)); } done: mutex_unlock(&this_afe.afe_cmd_lock); return ret; } EXPORT_SYMBOL(afe_unvote_lpass_core_hw); include/dsp/q6afe-v2.h +38 −0 Original line number Diff line number Diff line Loading @@ -453,4 +453,42 @@ void afe_register_wakeup_irq_callback( void (*afe_cb_wakeup_irq)(void *handle)); int afe_get_doa_tracking_mon(u16 port_id, struct doa_tracking_mon_param *doa_tracking_data); #define AFE_LPASS_CORE_HW_BLOCK_ID_NONE 0 #define AFE_LPASS_CORE_HW_BLOCK_ID_AVTIMER 2 #define AFE_LPASS_CORE_HW_MACRO_BLOCK 3 /* Handles audio-video timer (avtimer) and BTSC vote requests from clients. */ #define AFE_CMD_REMOTE_LPASS_CORE_HW_VOTE_REQUEST 0x000100f4 struct afe_cmd_remote_lpass_core_hw_vote_request { struct apr_hdr hdr; uint32_t hw_block_id; /* ID of the hardware block. */ char client_name[8]; /* Name of the client. */ } __packed; #define AFE_CMD_RSP_REMOTE_LPASS_CORE_HW_VOTE_REQUEST 0x000100f5 struct afe_cmd_rsp_remote_lpass_core_hw_vote_request { uint32_t client_handle; /**< Handle of the client. */ } __packed; #define AFE_CMD_REMOTE_LPASS_CORE_HW_DEVOTE_REQUEST 0x000100f6 struct afe_cmd_remote_lpass_core_hw_devote_request { struct apr_hdr hdr; uint32_t hw_block_id; /**< ID of the hardware block.*/ uint32_t client_handle; /**< Handle of the client.*/ } __packed; int afe_vote_lpass_core_hw(uint32_t hw_block_id, char *client_name, uint32_t *client_handle); int afe_unvote_lpass_core_hw(uint32_t hw_block_id, uint32_t client_handle); #endif /* __Q6AFE_V2_H__ */ Loading
asoc/codecs/audio-ext-clk-up.c +25 −56 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. /* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. */ #include <linux/kernel.h> Loading @@ -14,7 +14,6 @@ #include <linux/platform_device.h> #include <dt-bindings/clock/qcom,audio-ext-clk.h> #include <dsp/q6afe-v2.h> #include <dsp/q6core.h> #include "audio-ext-clk-up.h" enum { Loading @@ -27,7 +26,7 @@ enum { AUDIO_EXT_CLK_LPASS5, AUDIO_EXT_CLK_LPASS6, AUDIO_EXT_CLK_LPASS7, AUDIO_EXT_CLK_LPASS_NPA_RSC_ISLAND, AUDIO_EXT_CLK_LPASS_CORE_HW_VOTE, AUDIO_EXT_CLK_LPASS_MAX, AUDIO_EXT_CLK_EXTERNAL_PLL = AUDIO_EXT_CLK_LPASS_MAX, AUDIO_EXT_CLK_MAX, Loading @@ -51,7 +50,7 @@ struct audio_ext_clk_priv { struct afe_clk_set clk_cfg; struct audio_ext_clk audio_clk; const char *clk_name; uint32_t npa_rsc_client_handle; uint32_t lpass_core_hwvote_client_handle; }; static inline struct audio_ext_clk_priv *to_audio_clk(struct clk_hw *hw) Loading Loading @@ -138,46 +137,40 @@ static u8 audio_ext_clk_get_parent(struct clk_hw *hw) return 0; } static int lpass_npa_rsc_prepare(struct clk_hw *hw) static int lpass_hw_vote_prepare(struct clk_hw *hw) { struct audio_ext_clk_priv *clk_priv = to_audio_clk(hw); int ret; if ((clk_priv->clk_src >= AUDIO_EXT_CLK_LPASS_NPA_RSC_ISLAND) && (clk_priv->clk_src < AUDIO_EXT_CLK_LPASS_MAX)) { if (q6core_get_avcs_api_version_per_service( APRV2_IDS_SERVICE_ID_ADSP_CORE_V) >= AVCS_API_VERSION_V4) { ret = q6core_request_island_transition( clk_priv->npa_rsc_client_handle, false); if (clk_priv->clk_src == AUDIO_EXT_CLK_LPASS_CORE_HW_VOTE) { ret = afe_vote_lpass_core_hw(AFE_LPASS_CORE_HW_MACRO_BLOCK, "LPASS_HW_MACRO", &clk_priv->lpass_core_hwvote_client_handle); if (ret < 0) { pr_err("%s q6core_request_island_transition failed %d\n", pr_err("%s lpass core hw vote failed %d\n", __func__, ret); return ret; } } } return 0; } static void lpass_npa_rsc_unprepare(struct clk_hw *hw) static void lpass_hw_vote_unprepare(struct clk_hw *hw) { struct audio_ext_clk_priv *clk_priv = to_audio_clk(hw); int ret = 0; if ((clk_priv->clk_src >= AUDIO_EXT_CLK_LPASS_NPA_RSC_ISLAND) && (clk_priv->clk_src < AUDIO_EXT_CLK_LPASS_MAX)) { if (q6core_get_avcs_api_version_per_service( APRV2_IDS_SERVICE_ID_ADSP_CORE_V) >= AVCS_API_VERSION_V4) { ret = q6core_request_island_transition( clk_priv->npa_rsc_client_handle, true); if (clk_priv->clk_src == AUDIO_EXT_CLK_LPASS_CORE_HW_VOTE) { ret = afe_unvote_lpass_core_hw( AFE_LPASS_CORE_HW_MACRO_BLOCK, clk_priv->lpass_core_hwvote_client_handle); if (ret < 0) { pr_err("%s q6core_request_island_transition failed %d\n", pr_err("%s lpass core hw vote failed %d\n", __func__, ret); } } } } static const struct clk_ops audio_ext_clk_ops = { .prepare = audio_ext_clk_prepare, Loading @@ -185,9 +178,9 @@ static const struct clk_ops audio_ext_clk_ops = { .get_parent = audio_ext_clk_get_parent, }; static const struct clk_ops lpass_npa_rsc_ops = { .prepare = lpass_npa_rsc_prepare, .unprepare = lpass_npa_rsc_unprepare, static const struct clk_ops lpass_hw_vote_ops = { .prepare = lpass_hw_vote_prepare, .unprepare = lpass_hw_vote_unprepare, }; static const char * const audio_ext_pmi_div_clk[] = { Loading Loading @@ -322,8 +315,8 @@ static struct audio_ext_clk audio_clk_array[] = { .pnctrl_info = {NULL}, .fact = { .hw.init = &(struct clk_init_data){ .name = "lpass_npa_rsc_island_clk", .ops = &lpass_npa_rsc_ops, .name = "lpass_hw_vote_clk", .ops = &lpass_hw_vote_ops, }, }, }, Loading Loading @@ -539,35 +532,11 @@ static int audio_ref_clk_probe(struct platform_device *pdev) audio_put_pinctrl(pdev); return ret; } if (clk_priv->clk_src == AUDIO_EXT_CLK_LPASS_NPA_RSC_ISLAND) { if (q6core_get_avcs_api_version_per_service( APRV2_IDS_SERVICE_ID_ADSP_CORE_V) >= AVCS_API_VERSION_V4) { ret = q6core_create_lpass_npa_client( AVCS_SLEEP_NODE_ISLAND_TRANSITION_RESOURCE_ID, "lpass_npa_rsc_mgr", &clk_priv->npa_rsc_client_handle); if (ret) { dev_err(&pdev->dev, "%s: q6core_create_lpass_npa_client is failed %d\n", __func__, ret); audio_put_pinctrl(pdev); return ret; } } } return 0; } static int audio_ref_clk_remove(struct platform_device *pdev) { struct audio_ext_clk_priv *clk_priv = platform_get_drvdata(pdev); if (clk_priv->clk_src == AUDIO_EXT_CLK_LPASS_NPA_RSC_ISLAND) { if (q6core_get_avcs_api_version_per_service( APRV2_IDS_SERVICE_ID_ADSP_CORE_V) >= AVCS_API_VERSION_V4) q6core_destroy_lpass_npa_client( clk_priv->npa_rsc_client_handle); } audio_put_pinctrl(pdev); return 0; Loading
asoc/codecs/bolero/bolero-cdc.c +15 −15 Original line number Diff line number Diff line Loading @@ -949,7 +949,7 @@ static int bolero_probe(struct platform_device *pdev) struct bolero_priv *priv; u32 num_macros = 0; int ret; struct clk *lpass_npa_rsc_island = NULL; struct clk *lpass_core_hw_vote = NULL; priv = devm_kzalloc(&pdev->dev, sizeof(struct bolero_priv), GFP_KERNEL); Loading Loading @@ -998,16 +998,16 @@ static int bolero_probe(struct platform_device *pdev) bolero_add_child_devices); schedule_work(&priv->bolero_add_child_devices_work); /* Register LPASS NPA resource */ lpass_npa_rsc_island = devm_clk_get(&pdev->dev, "island_lpass_npa_rsc"); if (IS_ERR(lpass_npa_rsc_island)) { ret = PTR_ERR(lpass_npa_rsc_island); /* Register LPASS core hw vote */ lpass_core_hw_vote = devm_clk_get(&pdev->dev, "lpass_core_hw_vote"); if (IS_ERR(lpass_core_hw_vote)) { ret = PTR_ERR(lpass_core_hw_vote); dev_dbg(&pdev->dev, "%s: clk get %s failed %d\n", __func__, "island_lpass_npa_rsc", ret); lpass_npa_rsc_island = NULL; __func__, "lpass_core_hw_vote", ret); lpass_core_hw_vote = NULL; ret = 0; } priv->lpass_npa_rsc_island = lpass_npa_rsc_island; priv->lpass_core_hw_vote = lpass_core_hw_vote; return 0; } Loading @@ -1030,14 +1030,14 @@ int bolero_runtime_resume(struct device *dev) struct bolero_priv *priv = dev_get_drvdata(dev->parent); int ret = 0; if (priv->lpass_npa_rsc_island == NULL) { dev_dbg(dev, "%s: Invalid lpass npa rsc node\n", __func__); if (priv->lpass_core_hw_vote == NULL) { dev_dbg(dev, "%s: Invalid lpass core hw node\n", __func__); return 0; } ret = clk_prepare_enable(priv->lpass_npa_rsc_island); ret = clk_prepare_enable(priv->lpass_core_hw_vote); if (ret < 0) dev_err(dev, "%s:lpass npa rsc island enable failed\n", dev_err(dev, "%s:lpass core hw enable failed\n", __func__); pm_runtime_set_autosuspend_delay(priv->dev, BOLERO_AUTO_SUSPEND_DELAY); Loading @@ -1050,10 +1050,10 @@ int bolero_runtime_suspend(struct device *dev) struct bolero_priv *priv = dev_get_drvdata(dev->parent); mutex_lock(&priv->clk_lock); if (priv->lpass_npa_rsc_island != NULL) clk_disable_unprepare(priv->lpass_npa_rsc_island); if (priv->lpass_core_hw_vote != NULL) clk_disable_unprepare(priv->lpass_core_hw_vote); else dev_dbg(dev, "%s: Invalid lpass npa rsc node\n", dev_dbg(dev, "%s: Invalid lpass core hw node\n", __func__); mutex_unlock(&priv->clk_lock); return 0; Loading
asoc/codecs/bolero/internal.h +2 −2 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* Copyright (c) 2018, The Linux Foundation. All rights reserved. /* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. */ #ifndef _BOLERO_INTERNAL_H Loading Loading @@ -57,7 +57,7 @@ struct bolero_priv { u16 current_mclk_mux_macro[MAX_MACRO]; struct work_struct bolero_add_child_devices_work; u32 version; struct clk *lpass_npa_rsc_island; struct clk *lpass_core_hw_vote; /* Entry for version info */ struct snd_info_entry *entry; Loading
dsp/q6afe.c +177 −0 Original line number Diff line number Diff line Loading @@ -92,6 +92,9 @@ struct afe_ctl { atomic_t status; wait_queue_head_t wait[AFE_MAX_PORTS]; wait_queue_head_t wait_wakeup; struct task_struct *task; wait_queue_head_t lpass_core_hw_wait; uint32_t lpass_hw_core_client_hdl; void (*tx_cb)(uint32_t opcode, uint32_t token, uint32_t *payload, void *priv); void (*rx_cb)(uint32_t opcode, Loading Loading @@ -555,6 +558,16 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv) return -EINVAL; } else if (data->opcode == AFE_EVENT_MBHC_DETECTION_SW_WA) { msm_aud_evt_notifier_call_chain(SWR_WAKE_IRQ_EVENT, NULL); } else if (data->opcode == AFE_CMD_RSP_REMOTE_LPASS_CORE_HW_VOTE_REQUEST) { uint32_t *payload = data->payload; pr_debug("%s: AFE_CMD_RSP_REMOTE_LPASS_CORE_HW_VOTE_REQUEST handle %d\n", __func__, payload[0]); this_afe.lpass_hw_core_client_hdl = payload[0]; atomic_set(&this_afe.state, 0); atomic_set(&this_afe.status, 0); wake_up(&this_afe.lpass_core_hw_wait); } else if (data->payload_size) { uint32_t *payload; uint16_t port_id = 0; Loading Loading @@ -635,6 +648,11 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv) else return -EINVAL; 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); wake_up(&this_afe.lpass_core_hw_wait); break; case AFE_SVC_CMD_EVENT_CFG: atomic_set(&this_afe.state, payload[1]); wake_up(&this_afe.wait_wakeup); Loading Loading @@ -8427,6 +8445,7 @@ int __init afe_init(void) init_waitqueue_head(&this_afe.wait[i]); } init_waitqueue_head(&this_afe.wait_wakeup); init_waitqueue_head(&this_afe.lpass_core_hw_wait); wakeup_source_init(&wl.ws, "spkr-prot"); ret = afe_init_cal_data(); if (ret) Loading Loading @@ -8498,3 +8517,161 @@ int afe_cal_init_hwdep(void *card) return ret; } EXPORT_SYMBOL(afe_cal_init_hwdep); /* * afe_vote_lpass_core_hw - * Voting for lpass core hardware * * @hw_block_id: id of the hardware block * @client_name: client name * @client_handle: client handle * */ int afe_vote_lpass_core_hw(uint32_t hw_block_id, char *client_name, uint32_t *client_handle) { struct afe_cmd_remote_lpass_core_hw_vote_request hw_vote_cfg; struct afe_cmd_remote_lpass_core_hw_vote_request *cmd_ptr = &hw_vote_cfg; int ret = 0; if (!client_handle) { pr_err("%s: Invalid client_handle\n", __func__); return -EINVAL; } if (!client_name) { pr_err("%s: Invalid client_name\n", __func__); *client_handle = 0; return -EINVAL; } mutex_lock(&this_afe.afe_cmd_lock); memset(cmd_ptr, 0, sizeof(hw_vote_cfg)); cmd_ptr->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER); cmd_ptr->hdr.pkt_size = sizeof(hw_vote_cfg); cmd_ptr->hdr.src_port = 0; cmd_ptr->hdr.dest_port = 0; cmd_ptr->hdr.token = 0; cmd_ptr->hdr.opcode = AFE_CMD_REMOTE_LPASS_CORE_HW_VOTE_REQUEST; cmd_ptr->hw_block_id = hw_block_id; strlcpy(cmd_ptr->client_name, client_name, sizeof(cmd_ptr->client_name)); pr_debug("%s: lpass core hw vote opcode[0x%x] hw id[0x%x]\n", __func__, cmd_ptr->hdr.opcode, cmd_ptr->hw_block_id); *client_handle = 0; atomic_set(&this_afe.status, 0); atomic_set(&this_afe.state, 1); ret = apr_send_pkt(this_afe.apr, (uint32_t *) cmd_ptr); if (ret < 0) { pr_err("%s: lpass core hw vote failed %d\n", __func__, ret); goto done; } ret = wait_event_timeout(this_afe.lpass_core_hw_wait, (atomic_read(&this_afe.state) == 0), msecs_to_jiffies(TIMEOUT_MS)); if (!ret) { pr_err("%s: timeout. waited for lpass core hw vote\n", __func__); ret = -ETIMEDOUT; goto done; } else { /* set ret to 0 as no timeout happened */ ret = 0; } if (atomic_read(&this_afe.status) > 0) { pr_err("%s: lpass core hw vote cmd failed [%s]\n", __func__, adsp_err_get_err_str( atomic_read(&this_afe.status))); ret = adsp_err_get_lnx_err_code( atomic_read(&this_afe.status)); goto done; } *client_handle = this_afe.lpass_hw_core_client_hdl; pr_debug("%s: lpass_hw_core_client_hdl %d\n", __func__, this_afe.lpass_hw_core_client_hdl); done: mutex_unlock(&this_afe.afe_cmd_lock); return ret; } EXPORT_SYMBOL(afe_vote_lpass_core_hw); /* * afe_unvote_lpass_core_hw - * unvoting for lpass core hardware * * @hw_block_id: id of the hardware block * @client_handle: client handle * */ int afe_unvote_lpass_core_hw(uint32_t hw_block_id, uint32_t client_handle) { struct afe_cmd_remote_lpass_core_hw_devote_request hw_vote_cfg; struct afe_cmd_remote_lpass_core_hw_devote_request *cmd_ptr = &hw_vote_cfg; int ret = 0; mutex_lock(&this_afe.afe_cmd_lock); memset(cmd_ptr, 0, sizeof(hw_vote_cfg)); cmd_ptr->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER); cmd_ptr->hdr.pkt_size = sizeof(hw_vote_cfg); cmd_ptr->hdr.src_port = 0; cmd_ptr->hdr.dest_port = 0; cmd_ptr->hdr.token = 0; cmd_ptr->hdr.opcode = AFE_CMD_REMOTE_LPASS_CORE_HW_DEVOTE_REQUEST; cmd_ptr->hw_block_id = hw_block_id; cmd_ptr->client_handle = client_handle; pr_debug("%s: lpass core hw unvote opcode[0x%x] hw id[0x%x]\n", __func__, cmd_ptr->hdr.opcode, cmd_ptr->hw_block_id); atomic_set(&this_afe.status, 0); atomic_set(&this_afe.state, 1); ret = apr_send_pkt(this_afe.apr, (uint32_t *) cmd_ptr); if (ret < 0) { pr_err("%s: lpass core hw devote failed %d\n", __func__, ret); goto done; } ret = wait_event_timeout(this_afe.lpass_core_hw_wait, (atomic_read(&this_afe.state) == 0), msecs_to_jiffies(TIMEOUT_MS)); if (!ret) { pr_err("%s: timeout. waited for lpass core hw devote\n", __func__); ret = -ETIMEDOUT; goto done; } else { /* set ret to 0 as no timeout happened */ ret = 0; } if (atomic_read(&this_afe.status) > 0) { pr_err("%s: lpass core hw devote cmd failed [%s]\n", __func__, adsp_err_get_err_str( atomic_read(&this_afe.status))); ret = adsp_err_get_lnx_err_code( atomic_read(&this_afe.status)); } done: mutex_unlock(&this_afe.afe_cmd_lock); return ret; } EXPORT_SYMBOL(afe_unvote_lpass_core_hw);
include/dsp/q6afe-v2.h +38 −0 Original line number Diff line number Diff line Loading @@ -453,4 +453,42 @@ void afe_register_wakeup_irq_callback( void (*afe_cb_wakeup_irq)(void *handle)); int afe_get_doa_tracking_mon(u16 port_id, struct doa_tracking_mon_param *doa_tracking_data); #define AFE_LPASS_CORE_HW_BLOCK_ID_NONE 0 #define AFE_LPASS_CORE_HW_BLOCK_ID_AVTIMER 2 #define AFE_LPASS_CORE_HW_MACRO_BLOCK 3 /* Handles audio-video timer (avtimer) and BTSC vote requests from clients. */ #define AFE_CMD_REMOTE_LPASS_CORE_HW_VOTE_REQUEST 0x000100f4 struct afe_cmd_remote_lpass_core_hw_vote_request { struct apr_hdr hdr; uint32_t hw_block_id; /* ID of the hardware block. */ char client_name[8]; /* Name of the client. */ } __packed; #define AFE_CMD_RSP_REMOTE_LPASS_CORE_HW_VOTE_REQUEST 0x000100f5 struct afe_cmd_rsp_remote_lpass_core_hw_vote_request { uint32_t client_handle; /**< Handle of the client. */ } __packed; #define AFE_CMD_REMOTE_LPASS_CORE_HW_DEVOTE_REQUEST 0x000100f6 struct afe_cmd_remote_lpass_core_hw_devote_request { struct apr_hdr hdr; uint32_t hw_block_id; /**< ID of the hardware block.*/ uint32_t client_handle; /**< Handle of the client.*/ } __packed; int afe_vote_lpass_core_hw(uint32_t hw_block_id, char *client_name, uint32_t *client_handle); int afe_unvote_lpass_core_hw(uint32_t hw_block_id, uint32_t client_handle); #endif /* __Q6AFE_V2_H__ */