Merge "soundwire: Vote for LPASS HW Core before soundwire register access"
diff --git a/asoc/codecs/bolero/Kbuild b/asoc/codecs/bolero/Kbuild
index f01f523..25d7881 100644
--- a/asoc/codecs/bolero/Kbuild
+++ b/asoc/codecs/bolero/Kbuild
@@ -70,6 +70,7 @@
BOLERO_OBJS += bolero-cdc-utils.o
BOLERO_OBJS += bolero-cdc-regmap.o
BOLERO_OBJS += bolero-cdc-tables.o
+ BOLERO_OBJS += bolero-clk-rsc.o
endif
ifdef CONFIG_WSA_MACRO
diff --git a/asoc/codecs/bolero/bolero-cdc.c b/asoc/codecs/bolero/bolero-cdc.c
index 217fa5f..d805126 100644
--- a/asoc/codecs/bolero/bolero-cdc.c
+++ b/asoc/codecs/bolero/bolero-cdc.c
@@ -16,6 +16,7 @@
#include <soc/swr-common.h>
#include "bolero-cdc.h"
#include "internal.h"
+#include "bolero-clk-rsc.h"
#define DRV_NAME "bolero_codec"
@@ -93,43 +94,44 @@
static int __bolero_reg_read(struct bolero_priv *priv,
u16 macro_id, u16 reg, u8 *val)
{
- int ret = -EINVAL;
- u16 current_mclk_mux_macro;
+ int ret = 0;
mutex_lock(&priv->clk_lock);
if (!priv->dev_up) {
dev_dbg_ratelimited(priv->dev,
"%s: SSR in progress, exit\n", __func__);
- goto err;
+ ret = -EINVAL;
+ goto ssr_err;
}
if (priv->macro_params[VA_MACRO].dev)
pm_runtime_get_sync(priv->macro_params[VA_MACRO].dev);
- current_mclk_mux_macro =
- priv->current_mclk_mux_macro[macro_id];
- if (!priv->macro_params[current_mclk_mux_macro].mclk_fn) {
- dev_dbg_ratelimited(priv->dev,
- "%s: mclk_fn not init for macro-id:%d, current_mclk_mux_macro:%d\n",
- __func__, macro_id, current_mclk_mux_macro);
+
+ /* Request Clk before register access */
+ ret = bolero_clk_rsc_request_clock(priv->macro_params[macro_id].dev,
+ priv->macro_params[macro_id].default_clk_id,
+ priv->macro_params[macro_id].clk_id_req,
+ true);
+ if (ret < 0) {
+ dev_err_ratelimited(priv->dev,
+ "%s: Failed to enable clock, ret:%d\n", __func__, ret);
goto err;
}
- ret = priv->macro_params[current_mclk_mux_macro].mclk_fn(
- priv->macro_params[current_mclk_mux_macro].dev, true);
- if (ret) {
- dev_dbg_ratelimited(priv->dev,
- "%s: clock enable failed for macro-id:%d, current_mclk_mux_macro:%d\n",
- __func__, macro_id, current_mclk_mux_macro);
- goto err;
- }
+
bolero_ahb_read_device(
priv->macro_params[macro_id].io_base, reg, val);
- priv->macro_params[current_mclk_mux_macro].mclk_fn(
- priv->macro_params[current_mclk_mux_macro].dev, false);
+
+ bolero_clk_rsc_request_clock(priv->macro_params[macro_id].dev,
+ priv->macro_params[macro_id].default_clk_id,
+ priv->macro_params[macro_id].clk_id_req,
+ false);
+
err:
if (priv->macro_params[VA_MACRO].dev) {
pm_runtime_mark_last_busy(priv->macro_params[VA_MACRO].dev);
pm_runtime_put_autosuspend(priv->macro_params[VA_MACRO].dev);
}
+ssr_err:
mutex_unlock(&priv->clk_lock);
return ret;
}
@@ -137,42 +139,43 @@
static int __bolero_reg_write(struct bolero_priv *priv,
u16 macro_id, u16 reg, u8 val)
{
- int ret = -EINVAL;
- u16 current_mclk_mux_macro;
+ int ret = 0;
mutex_lock(&priv->clk_lock);
if (!priv->dev_up) {
dev_dbg_ratelimited(priv->dev,
"%s: SSR in progress, exit\n", __func__);
- goto err;
+ ret = -EINVAL;
+ goto ssr_err;
}
if (priv->macro_params[VA_MACRO].dev)
- ret = pm_runtime_get_sync(priv->macro_params[VA_MACRO].dev);
- current_mclk_mux_macro =
- priv->current_mclk_mux_macro[macro_id];
- if (!priv->macro_params[current_mclk_mux_macro].mclk_fn) {
- dev_dbg_ratelimited(priv->dev,
- "%s: mclk_fn not init for macro-id:%d, current_mclk_mux_macro:%d\n",
- __func__, macro_id, current_mclk_mux_macro);
+ pm_runtime_get_sync(priv->macro_params[VA_MACRO].dev);
+
+ /* Request Clk before register access */
+ ret = bolero_clk_rsc_request_clock(priv->macro_params[macro_id].dev,
+ priv->macro_params[macro_id].default_clk_id,
+ priv->macro_params[macro_id].clk_id_req,
+ true);
+ if (ret < 0) {
+ dev_err_ratelimited(priv->dev,
+ "%s: Failed to enable clock, ret:%d\n", __func__, ret);
goto err;
}
- ret = priv->macro_params[current_mclk_mux_macro].mclk_fn(
- priv->macro_params[current_mclk_mux_macro].dev, true);
- if (ret) {
- dev_dbg_ratelimited(priv->dev,
- "%s: clock enable failed for macro-id:%d, current_mclk_mux_macro:%d\n",
- __func__, macro_id, current_mclk_mux_macro);
- goto err;
- }
+
bolero_ahb_write_device(
- priv->macro_params[macro_id].io_base, reg, val);
- priv->macro_params[current_mclk_mux_macro].mclk_fn(
- priv->macro_params[current_mclk_mux_macro].dev, false);
+ priv->macro_params[macro_id].io_base, reg, val);
+
+ bolero_clk_rsc_request_clock(priv->macro_params[macro_id].dev,
+ priv->macro_params[macro_id].default_clk_id,
+ priv->macro_params[macro_id].clk_id_req,
+ false);
+
err:
if (priv->macro_params[VA_MACRO].dev) {
pm_runtime_mark_last_busy(priv->macro_params[VA_MACRO].dev);
pm_runtime_put_autosuspend(priv->macro_params[VA_MACRO].dev);
}
+ssr_err:
mutex_unlock(&priv->clk_lock);
return ret;
}
@@ -239,7 +242,7 @@
data, (void *)priv->wcd_dev);
}
-static bool bolero_is_valid_macro_dev(struct device *dev)
+static bool bolero_is_valid_child_dev(struct device *dev)
{
if (of_device_is_compatible(dev->parent->of_node, "qcom,bolero-codec"))
return true;
@@ -326,6 +329,36 @@
}
EXPORT_SYMBOL(bolero_get_device_ptr);
+/**
+ * bolero_get_rsc_clk_device_ptr - Get rsc clk device ptr
+ *
+ * @dev: bolero device ptr.
+ *
+ * Returns dev ptr on success or NULL on error.
+ */
+struct device *bolero_get_rsc_clk_device_ptr(struct device *dev)
+{
+ struct bolero_priv *priv;
+
+ if (!dev) {
+ pr_err("%s: dev is null\n", __func__);
+ return NULL;
+ }
+
+ if (!bolero_is_valid_codec_dev(dev)) {
+ pr_err("%s: invalid codec\n", __func__);
+ return NULL;
+ }
+ priv = dev_get_drvdata(dev);
+ if (!priv) {
+ dev_err(dev, "%s: priv is null\n", __func__);
+ return NULL;
+ }
+
+ return priv->clk_dev;
+}
+EXPORT_SYMBOL(bolero_get_rsc_clk_device_ptr);
+
static int bolero_copy_dais_from_macro(struct bolero_priv *priv)
{
struct snd_soc_dai_driver *dai_ptr;
@@ -356,6 +389,69 @@
}
/**
+ * bolero_register_res_clk - Registers rsc clk driver to bolero
+ *
+ * @dev: rsc clk device ptr.
+ * @rsc_clk_cb: event handler callback for notifications like SSR
+ *
+ * Returns 0 on success or -EINVAL on error.
+ */
+int bolero_register_res_clk(struct device *dev, rsc_clk_cb_t rsc_clk_cb)
+{
+ struct bolero_priv *priv;
+
+ if (!dev || !rsc_clk_cb) {
+ pr_err("%s: dev or rsc_clk_cb is null\n", __func__);
+ return -EINVAL;
+ }
+ if (!bolero_is_valid_child_dev(dev)) {
+ dev_err(dev, "%s: child device :%pK not added yet\n",
+ __func__, dev);
+ return -EINVAL;
+ }
+ priv = dev_get_drvdata(dev->parent);
+ if (!priv) {
+ dev_err(dev, "%s: priv is null\n", __func__);
+ return -EINVAL;
+ }
+
+ priv->clk_dev = dev;
+ priv->rsc_clk_cb = rsc_clk_cb;
+
+ return 0;
+}
+EXPORT_SYMBOL(bolero_register_res_clk);
+
+/**
+ * bolero_unregister_res_clk - Unregisters rsc clk driver from bolero
+ *
+ * @dev: resource clk device ptr.
+ */
+void bolero_unregister_res_clk(struct device *dev)
+{
+ struct bolero_priv *priv;
+
+ if (!dev) {
+ pr_err("%s: dev is NULL\n", __func__);
+ return;
+ }
+ if (!bolero_is_valid_child_dev(dev)) {
+ dev_err(dev, "%s: child device :%pK not added\n",
+ __func__, dev);
+ return;
+ }
+ priv = dev_get_drvdata(dev->parent);
+ if (!priv) {
+ dev_err(dev, "%s: priv is null\n", __func__);
+ return;
+ }
+
+ priv->clk_dev = NULL;
+ priv->rsc_clk_cb = NULL;
+}
+EXPORT_SYMBOL(bolero_unregister_res_clk);
+
+/**
* bolero_register_macro - Registers macro to bolero
*
* @dev: macro device ptr.
@@ -374,7 +470,7 @@
pr_err("%s: dev or ops is null\n", __func__);
return -EINVAL;
}
- if (!bolero_is_valid_macro_dev(dev)) {
+ if (!bolero_is_valid_child_dev(dev)) {
dev_err(dev, "%s: child device for macro:%d not added yet\n",
__func__, macro_id);
return -EINVAL;
@@ -385,12 +481,13 @@
return -EINVAL;
}
+ priv->macro_params[macro_id].clk_id_req = ops->clk_id_req;
+ priv->macro_params[macro_id].default_clk_id = ops->default_clk_id;
priv->macro_params[macro_id].init = ops->init;
priv->macro_params[macro_id].exit = ops->exit;
priv->macro_params[macro_id].io_base = ops->io_base;
priv->macro_params[macro_id].num_dais = ops->num_dais;
priv->macro_params[macro_id].dai_ptr = ops->dai_ptr;
- priv->macro_params[macro_id].mclk_fn = ops->mclk_fn;
priv->macro_params[macro_id].event_handler = ops->event_handler;
priv->macro_params[macro_id].set_port_map = ops->set_port_map;
priv->macro_params[macro_id].dev = dev;
@@ -441,7 +538,7 @@
pr_err("%s: dev is null\n", __func__);
return;
}
- if (!bolero_is_valid_macro_dev(dev)) {
+ if (!bolero_is_valid_child_dev(dev)) {
dev_err(dev, "%s: macro:%d not in valid registered macro-list\n",
__func__, macro_id);
return;
@@ -455,7 +552,6 @@
priv->macro_params[macro_id].init = NULL;
priv->macro_params[macro_id].num_dais = 0;
priv->macro_params[macro_id].dai_ptr = NULL;
- priv->macro_params[macro_id].mclk_fn = NULL;
priv->macro_params[macro_id].event_handler = NULL;
priv->macro_params[macro_id].dev = NULL;
if (macro_id == TX_MACRO)
@@ -470,150 +566,6 @@
}
EXPORT_SYMBOL(bolero_unregister_macro);
-static void bolero_fs_gen_enable(struct bolero_priv *priv, bool enable)
-{
- if (enable) {
- if (++priv->clk_users == 1) {
- mutex_unlock(&priv->clk_lock);
- regmap_update_bits(priv->regmap,
- BOLERO_CDC_VA_CLK_RST_CTRL_MCLK_CONTROL,
- 0x01, 0x01);
- regmap_update_bits(priv->regmap,
- BOLERO_CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL,
- 0x01, 0x01);
- regmap_update_bits(priv->regmap,
- BOLERO_CDC_VA_TOP_CSR_TOP_CFG0,
- 0x02, 0x02);
- mutex_lock(&priv->clk_lock);
- }
- } else {
- if (priv->clk_users <= 0) {
- dev_err(priv->dev,
- "%s:clock already disabled\n",
- __func__);
- priv->clk_users = 0;
- return;
- }
- if (--priv->clk_users == 0) {
- mutex_unlock(&priv->clk_lock);
- regmap_update_bits(priv->regmap,
- BOLERO_CDC_VA_TOP_CSR_TOP_CFG0,
- 0x02, 0x00);
- regmap_update_bits(priv->regmap,
- BOLERO_CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL,
- 0x01, 0x00);
- regmap_update_bits(priv->regmap,
- BOLERO_CDC_VA_CLK_RST_CTRL_MCLK_CONTROL,
- 0x01, 0x00);
- mutex_lock(&priv->clk_lock);
- }
- }
-}
-
-/**
- * bolero_request_clock - request for clock enable/disable
- *
- * @dev: macro device ptr.
- * @macro_id: ID of macro calling this API.
- * @mclk_mux_id: MCLK_MUX ID.
- * @enable: enable or disable clock flag
- *
- * Returns 0 on success or -EINVAL on error.
- */
-int bolero_request_clock(struct device *dev, u16 macro_id,
- enum mclk_mux mclk_mux_id,
- bool enable)
-{
- struct bolero_priv *priv;
- u16 mclk_mux0_macro, mclk_mux1_macro;
- int ret = 0, ret1 = 0;
-
- if (!dev) {
- pr_err("%s: dev is null\n", __func__);
- return -EINVAL;
- }
- if (!bolero_is_valid_macro_dev(dev)) {
- dev_err(dev, "%s: macro:%d not in valid registered macro-list\n",
- __func__, macro_id);
- return -EINVAL;
- }
- priv = dev_get_drvdata(dev->parent);
- if (!priv || (macro_id >= MAX_MACRO)) {
- dev_err(dev, "%s: priv is null or invalid macro\n", __func__);
- return -EINVAL;
- }
- mclk_mux0_macro = bolero_mclk_mux_tbl[macro_id][MCLK_MUX0];
- mutex_lock(&priv->clk_lock);
- switch (mclk_mux_id) {
- case MCLK_MUX0:
- ret = priv->macro_params[mclk_mux0_macro].mclk_fn(
- priv->macro_params[mclk_mux0_macro].dev, enable);
- if (ret < 0) {
- dev_err(dev,
- "%s: MCLK_MUX0 %s failed for macro:%d, mclk_mux0_macro:%d\n",
- __func__,
- enable ? "enable" : "disable",
- macro_id, mclk_mux0_macro);
- goto err;
- }
- bolero_fs_gen_enable(priv, enable);
- break;
- case MCLK_MUX1:
- mclk_mux1_macro = bolero_mclk_mux_tbl[macro_id][MCLK_MUX1];
- ret = priv->macro_params[mclk_mux0_macro].mclk_fn(
- priv->macro_params[mclk_mux0_macro].dev,
- true);
- if (ret < 0) {
- dev_err(dev,
- "%s: MCLK_MUX0 en failed for macro:%d mclk_mux0_macro:%d\n",
- __func__, macro_id, mclk_mux0_macro);
- /*
- * for disable case, need to proceed still for mclk_mux1
- * counter to decrement
- */
- if (enable)
- goto err;
- }
- bolero_fs_gen_enable(priv, enable);
- /*
- * need different return value as ret variable
- * is used to track mclk_mux0 enable success or fail
- */
- ret1 = priv->macro_params[mclk_mux1_macro].mclk_fn(
- priv->macro_params[mclk_mux1_macro].dev, enable);
- if (ret1 < 0)
- dev_err(dev,
- "%s: MCLK_MUX1 %s failed for macro:%d, mclk_mux1_macro:%d\n",
- __func__,
- enable ? "enable" : "disable",
- macro_id, mclk_mux1_macro);
- /* disable mclk_mux0 only if ret is success(0) */
- if (!ret)
- priv->macro_params[mclk_mux0_macro].mclk_fn(
- priv->macro_params[mclk_mux0_macro].dev,
- false);
- if (enable && ret1)
- goto err;
- break;
- case MCLK_MUX_MAX:
- default:
- dev_err(dev, "%s: invalid mclk_mux_id: %d\n",
- __func__, mclk_mux_id);
- ret = -EINVAL;
- goto err;
- }
- if (enable)
- priv->current_mclk_mux_macro[macro_id] =
- bolero_mclk_mux_tbl[macro_id][mclk_mux_id];
- else
- priv->current_mclk_mux_macro[macro_id] =
- bolero_mclk_mux_tbl[macro_id][MCLK_MUX0];
-err:
- mutex_unlock(&priv->clk_lock);
- return ret;
-}
-EXPORT_SYMBOL(bolero_request_clock);
-
static ssize_t bolero_version_read(struct snd_info_entry *entry,
void *file_private_data,
struct file *file,
@@ -657,6 +609,9 @@
return 0;
}
+ if (priv->rsc_clk_cb)
+ priv->rsc_clk_cb(priv->clk_dev, BOLERO_MACRO_EVT_SSR_UP);
+
if (priv->macro_params[VA_MACRO].event_handler)
priv->macro_params[VA_MACRO].event_handler(
priv->component,
@@ -683,6 +638,9 @@
struct bolero_priv *priv = data;
int macro_idx;
+ if (priv->rsc_clk_cb)
+ priv->rsc_clk_cb(priv->clk_dev, BOLERO_MACRO_EVT_SSR_DOWN);
+
bolero_cdc_notifier_call(priv, BOLERO_WCD_EVT_PA_OFF_PRE_SSR);
regcache_cache_only(priv->regmap, true);
@@ -1074,7 +1032,30 @@
.remove = bolero_remove,
};
-module_platform_driver(bolero_drv);
+static int bolero_drv_init(void)
+{
+ return platform_driver_register(&bolero_drv);
+}
+
+static void bolero_drv_exit(void)
+{
+ platform_driver_unregister(&bolero_drv);
+}
+
+static int __init bolero_init(void)
+{
+ bolero_drv_init();
+ bolero_clk_rsc_mgr_init();
+ return 0;
+}
+module_init(bolero_init);
+
+static void __exit bolero_exit(void)
+{
+ bolero_clk_rsc_mgr_exit();
+ bolero_drv_exit();
+}
+module_exit(bolero_exit);
MODULE_DESCRIPTION("Bolero driver");
MODULE_LICENSE("GPL v2");
diff --git a/asoc/codecs/bolero/bolero-cdc.h b/asoc/codecs/bolero/bolero-cdc.h
index 524225e..e533eb8 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, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
*/
#ifndef BOLERO_CDC_H
@@ -54,16 +54,20 @@
int (*set_port_map)(struct snd_soc_component *component, u32 uc,
u32 size, void *data);
char __iomem *io_base;
+ u16 clk_id_req;
+ u16 default_clk_id;
};
+typedef int (*rsc_clk_cb_t)(struct device *dev, u16 event);
+
#if IS_ENABLED(CONFIG_SND_SOC_BOLERO)
+int bolero_register_res_clk(struct device *dev, rsc_clk_cb_t cb);
+void bolero_unregister_res_clk(struct device *dev);
int bolero_register_macro(struct device *dev, u16 macro_id,
struct macro_ops *ops);
void bolero_unregister_macro(struct device *dev, u16 macro_id);
struct device *bolero_get_device_ptr(struct device *dev, u16 macro_id);
-int bolero_request_clock(struct device *dev, u16 macro_id,
- enum mclk_mux mclk_mux_id,
- bool enable);
+struct device *bolero_get_rsc_clk_device_ptr(struct device *dev);
int bolero_info_create_codec_entry(
struct snd_info_entry *codec_root,
struct snd_soc_component *component);
@@ -73,6 +77,14 @@
int bolero_runtime_suspend(struct device *dev);
int bolero_set_port_map(struct snd_soc_component *component, u32 size, void *data);
#else
+static inline int bolero_register_res_clk(struct device *dev, rsc_clk_cb_t cb)
+{
+ return 0;
+}
+static inline void bolero_unregister_res_clk(struct device *dev)
+{
+}
+
static inline int bolero_register_macro(struct device *dev,
u16 macro_id,
struct macro_ops *ops)
@@ -90,13 +102,6 @@
return NULL;
}
-static inline int bolero_request_clock(struct device *dev, u16 macro_id,
- enum mclk_mux mclk_mux_id,
- bool enable)
-{
- return 0;
-}
-
static int bolero_info_create_codec_entry(
struct snd_info_entry *codec_root,
struct snd_soc_component *component)
diff --git a/asoc/codecs/bolero/bolero-clk-rsc.c b/asoc/codecs/bolero/bolero-clk-rsc.c
new file mode 100644
index 0000000..03befde
--- /dev/null
+++ b/asoc/codecs/bolero/bolero-clk-rsc.c
@@ -0,0 +1,613 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/of_platform.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include "bolero-cdc.h"
+#include "bolero-clk-rsc.h"
+
+#define DRV_NAME "bolero-clk-rsc"
+#define BOLERO_CLK_NAME_LENGTH 30
+#define NPL_CLK_OFFSET (TX_NPL_CLK - TX_CORE_CLK)
+
+static char clk_src_name[MAX_CLK][BOLERO_CLK_NAME_LENGTH] = {
+ "tx_core_clk",
+ "rx_core_clk",
+ "wsa_core_clk",
+ "va_core_clk",
+ "tx_npl_clk",
+ "rx_npl_clk",
+ "wsa_npl_clk",
+ "va_npl_clk",
+};
+
+struct bolero_clk_rsc {
+ struct device *dev;
+ struct mutex rsc_clk_lock;
+ struct clk *clk[MAX_CLK];
+ int clk_cnt[MAX_CLK];
+ int reg_seq_en_cnt;
+ int va_tx_clk_cnt;
+ bool dev_up;
+ u32 num_fs_reg;
+ u32 *fs_gen_seq;
+ int default_clk_id[MAX_CLK];
+ struct regmap *regmap;
+ char __iomem *rx_clk_muxsel;
+ char __iomem *wsa_clk_muxsel;
+ char __iomem *va_clk_muxsel;
+};
+
+static int bolero_clk_rsc_cb(struct device *dev, u16 event)
+{
+ struct bolero_clk_rsc *priv;
+
+ if (!dev) {
+ pr_err("%s: Invalid device pointer\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ priv = dev_get_drvdata(dev);
+ if (!priv) {
+ pr_err("%s: Invalid clk rsc priviate data\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&priv->rsc_clk_lock);
+ if (event == BOLERO_MACRO_EVT_SSR_UP)
+ priv->dev_up = true;
+ else if (event == BOLERO_MACRO_EVT_SSR_DOWN)
+ priv->dev_up = false;
+ mutex_unlock(&priv->rsc_clk_lock);
+
+ return 0;
+}
+
+static char __iomem *bolero_clk_rsc_get_clk_muxsel(struct bolero_clk_rsc *priv,
+ int clk_id)
+{
+ switch (clk_id) {
+ case RX_CORE_CLK:
+ return priv->rx_clk_muxsel;
+ case WSA_CORE_CLK:
+ return priv->wsa_clk_muxsel;
+ case VA_CORE_CLK:
+ return priv->va_clk_muxsel;
+ case TX_CORE_CLK:
+ default:
+ dev_err_ratelimited(priv->dev, "%s: Invalid case\n", __func__);
+ break;
+ }
+
+ return NULL;
+}
+
+static int bolero_clk_rsc_mux0_clk_request(struct bolero_clk_rsc *priv,
+ int clk_id,
+ bool enable)
+{
+ int ret = 0;
+
+ if (enable) {
+ /* Enable Requested Core clk */
+ if (priv->clk_cnt[clk_id] == 0) {
+ ret = clk_prepare_enable(priv->clk[clk_id]);
+ if (ret < 0) {
+ dev_err_ratelimited(priv->dev, "%s:clk_id %d enable failed\n",
+ __func__, clk_id);
+ goto done;
+ }
+ if (priv->clk[clk_id + NPL_CLK_OFFSET]) {
+ ret = clk_prepare_enable(
+ priv->clk[clk_id + NPL_CLK_OFFSET]);
+ if (ret < 0) {
+ dev_err_ratelimited(priv->dev, "%s:clk_id %d enable failed\n",
+ __func__,
+ clk_id + NPL_CLK_OFFSET);
+ goto err;
+ }
+ }
+ }
+ priv->clk_cnt[clk_id]++;
+ } else {
+ if (priv->clk_cnt[clk_id] <= 0) {
+ dev_err_ratelimited(priv->dev, "%s: clk_id: %d is already disabled\n",
+ __func__, clk_id);
+ priv->clk_cnt[clk_id] = 0;
+ goto done;
+ }
+ priv->clk_cnt[clk_id]--;
+ if (priv->clk_cnt[clk_id] == 0) {
+ if (priv->clk[clk_id + NPL_CLK_OFFSET])
+ clk_disable_unprepare(
+ priv->clk[clk_id + NPL_CLK_OFFSET]);
+ clk_disable_unprepare(priv->clk[clk_id]);
+ }
+ }
+ return ret;
+
+err:
+ clk_disable_unprepare(priv->clk[clk_id]);
+done:
+ return ret;
+}
+
+static int bolero_clk_rsc_mux1_clk_request(struct bolero_clk_rsc *priv,
+ int clk_id,
+ bool enable)
+{
+ char __iomem *clk_muxsel = NULL;
+ int ret = 0;
+ int default_clk_id = priv->default_clk_id[clk_id];
+
+ clk_muxsel = bolero_clk_rsc_get_clk_muxsel(priv, clk_id);
+ if (!clk_muxsel) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (enable) {
+ if (priv->clk_cnt[clk_id] == 0) {
+ ret = bolero_clk_rsc_mux0_clk_request(priv, default_clk_id,
+ true);
+ if (ret < 0)
+ goto done;
+
+ ret = clk_prepare_enable(priv->clk[clk_id]);
+ if (ret < 0) {
+ dev_err_ratelimited(priv->dev, "%s:clk_id %d enable failed\n",
+ __func__, clk_id);
+ goto err_clk;
+ }
+ if (priv->clk[clk_id + NPL_CLK_OFFSET]) {
+ ret = clk_prepare_enable(
+ priv->clk[clk_id + NPL_CLK_OFFSET]);
+ if (ret < 0) {
+ dev_err_ratelimited(priv->dev, "%s:clk_id %d enable failed\n",
+ __func__,
+ clk_id + NPL_CLK_OFFSET);
+ goto err_npl_clk;
+ }
+ }
+ iowrite32(0x1, clk_muxsel);
+ bolero_clk_rsc_mux0_clk_request(priv, default_clk_id,
+ false);
+ }
+ priv->clk_cnt[clk_id]++;
+ } else {
+ if (priv->clk_cnt[clk_id] <= 0) {
+ dev_err_ratelimited(priv->dev, "%s: clk_id: %d is already disabled\n",
+ __func__, clk_id);
+ priv->clk_cnt[clk_id] = 0;
+ goto done;
+ }
+ priv->clk_cnt[clk_id]--;
+ if (priv->clk_cnt[clk_id] == 0) {
+ bolero_clk_rsc_mux0_clk_request(priv, default_clk_id,
+ true);
+
+ iowrite32(0x0, clk_muxsel);
+ if (priv->clk[clk_id + NPL_CLK_OFFSET])
+ clk_disable_unprepare(
+ priv->clk[clk_id + NPL_CLK_OFFSET]);
+ clk_disable_unprepare(priv->clk[clk_id]);
+
+ bolero_clk_rsc_mux0_clk_request(priv, default_clk_id,
+ false);
+ }
+ }
+ return ret;
+
+err_npl_clk:
+ clk_disable_unprepare(priv->clk[clk_id]);
+
+err_clk:
+ bolero_clk_rsc_mux0_clk_request(priv, default_clk_id, false);
+done:
+ return ret;
+}
+
+static int bolero_clk_rsc_check_and_update_va_clk(struct bolero_clk_rsc *priv,
+ bool mux_switch,
+ int clk_id,
+ bool enable)
+{
+ int ret = 0;
+
+ if (enable) {
+ if (clk_id == VA_CORE_CLK && mux_switch) {
+ /*
+ * Handle the following usecase scenarios during enable
+ * 1. VA only, Active clk is VA_CORE_CLK
+ * 2. record -> record + VA, Active clk is TX_CORE_CLK
+ */
+ if (priv->clk_cnt[TX_CORE_CLK] == 0) {
+ ret = bolero_clk_rsc_mux1_clk_request(priv,
+ VA_CORE_CLK, enable);
+ if (ret < 0)
+ goto err;
+ } else {
+ ret = bolero_clk_rsc_mux0_clk_request(priv,
+ TX_CORE_CLK, enable);
+ if (ret < 0)
+ goto err;
+ priv->va_tx_clk_cnt++;
+ }
+ } else if ((priv->clk_cnt[TX_CORE_CLK] > 0) &&
+ (priv->clk_cnt[VA_CORE_CLK] > 0)) {
+ /*
+ * Handle following concurrency scenario during enable
+ * 1. VA-> Record+VA, Increment TX CLK and Disable VA
+ * 2. VA-> Playback+VA, Increment TX CLK and Disable VA
+ */
+ while (priv->clk_cnt[VA_CORE_CLK] > 0) {
+ ret = bolero_clk_rsc_mux0_clk_request(priv,
+ TX_CORE_CLK, true);
+ if (ret < 0)
+ goto err;
+
+ bolero_clk_rsc_mux1_clk_request(priv,
+ VA_CORE_CLK, false);
+ priv->va_tx_clk_cnt++;
+ }
+ }
+ } else {
+ if (clk_id == VA_CORE_CLK && mux_switch) {
+ /*
+ * Handle the following usecase scenarios during disable
+ * 1. VA only, disable VA_CORE_CLK
+ * 2. Record + VA -> Record, decrement TX CLK count
+ */
+ if (priv->clk_cnt[VA_CORE_CLK]) {
+ bolero_clk_rsc_mux1_clk_request(priv,
+ VA_CORE_CLK, enable);
+ } else if (priv->va_tx_clk_cnt) {
+ bolero_clk_rsc_mux0_clk_request(priv,
+ TX_CORE_CLK, enable);
+ priv->va_tx_clk_cnt--;
+ }
+ } else if (priv->va_tx_clk_cnt == priv->clk_cnt[TX_CORE_CLK]) {
+ /*
+ * Handle the following usecase scenarios during disable
+ * Record+VA-> VA: enable VA CLK, decrement TX CLK count
+ */
+ while (priv->va_tx_clk_cnt) {
+ ret = bolero_clk_rsc_mux1_clk_request(priv,
+ VA_CORE_CLK, true);
+ if (ret < 0)
+ goto err;
+
+ bolero_clk_rsc_mux0_clk_request(priv,
+ TX_CORE_CLK, false);
+ priv->va_tx_clk_cnt--;
+ }
+ }
+ }
+
+err:
+ return ret;
+}
+
+/**
+ * bolero_clk_rsc_fs_gen_request - request to enable/disable fs generation
+ * sequence
+ *
+ * @dev: Macro device pointer
+ * @enable: enable or disable flag
+ */
+void bolero_clk_rsc_fs_gen_request(struct device *dev, bool enable)
+{
+ int i;
+ struct regmap *regmap;
+ struct device *clk_dev = NULL;
+ struct bolero_clk_rsc *priv = NULL;
+
+ if (!dev) {
+ pr_err("%s: dev is null %d\n", __func__);
+ return;
+ }
+ clk_dev = bolero_get_rsc_clk_device_ptr(dev->parent);
+ if (!clk_dev) {
+ pr_err("%s: Invalid rsc clk device\n", __func__);
+ return;
+ }
+ priv = dev_get_drvdata(clk_dev);
+ if (!priv) {
+ pr_err("%s: Invalid rsc clk priviate data\n", __func__);
+ return;
+ }
+ regmap = dev_get_regmap(priv->dev->parent, NULL);
+ if (enable) {
+ if (priv->reg_seq_en_cnt++ == 0) {
+ for (i = 0; i < (priv->num_fs_reg * 2); i += 2) {
+ dev_dbg(priv->dev, "%s: Register: %d, value: %d\n",
+ __func__, priv->fs_gen_seq[i],
+ priv->fs_gen_seq[i + 1]);
+ regmap_update_bits(regmap,
+ priv->fs_gen_seq[i],
+ priv->fs_gen_seq[i + 1],
+ priv->fs_gen_seq[i + 1]);
+ }
+ }
+ } else {
+ if (priv->reg_seq_en_cnt <= 0) {
+ dev_err_ratelimited(priv->dev, "%s: req_seq_cnt: %d is already disabled\n",
+ __func__, priv->reg_seq_en_cnt);
+ priv->reg_seq_en_cnt = 0;
+ return;
+ }
+ if (--priv->reg_seq_en_cnt == 0) {
+ for (i = ((priv->num_fs_reg - 1) * 2); i >= 0; i -= 2) {
+ dev_dbg(priv->dev, "%s: Register: %d, value: %d\n",
+ __func__, priv->fs_gen_seq[i],
+ priv->fs_gen_seq[i + 1]);
+ regmap_update_bits(regmap, priv->fs_gen_seq[i],
+ priv->fs_gen_seq[i + 1], 0x0);
+ }
+ }
+ }
+}
+EXPORT_SYMBOL(bolero_clk_rsc_fs_gen_request);
+
+/**
+ * bolero_clk_rsc_request_clock - request for clock to
+ * enable/disable
+ *
+ * @dev: Macro device pointer.
+ * @default_clk_id: mux0 Core clock ID input.
+ * @clk_id_req: Core clock ID requested to enable/disable
+ * @enable: enable or disable clock flag
+ *
+ * Returns 0 on success or -EINVAL on error.
+ */
+int bolero_clk_rsc_request_clock(struct device *dev,
+ int default_clk_id,
+ int clk_id_req,
+ bool enable)
+{
+ int ret = 0;
+ struct device *clk_dev = NULL;
+ struct bolero_clk_rsc *priv = NULL;
+ bool mux_switch = false;
+
+ if (!dev) {
+ pr_err("%s: dev is null %d\n", __func__);
+ return -EINVAL;
+ }
+ if ((clk_id_req < 0 || clk_id_req >= MAX_CLK) &&
+ (default_clk_id < 0 || default_clk_id >= MAX_CLK)) {
+ pr_err("%s: Invalid clk_id_req: %d or default_clk_id: %d\n",
+ __func__, clk_id_req, default_clk_id);
+ return -EINVAL;
+ }
+ clk_dev = bolero_get_rsc_clk_device_ptr(dev->parent);
+ if (!clk_dev) {
+ pr_err("%s: Invalid rsc clk device\n", __func__);
+ return -EINVAL;
+ }
+ priv = dev_get_drvdata(clk_dev);
+ if (!priv) {
+ pr_err("%s: Invalid rsc clk priviate data\n", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&priv->rsc_clk_lock);
+ if (!priv->dev_up) {
+ dev_err_ratelimited(priv->dev, "%s: SSR is in progress..\n",
+ __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+ priv->default_clk_id[clk_id_req] = default_clk_id;
+ if (default_clk_id != clk_id_req)
+ mux_switch = true;
+
+ if (mux_switch) {
+ if (clk_id_req != VA_CORE_CLK) {
+ ret = bolero_clk_rsc_mux1_clk_request(priv, clk_id_req,
+ enable);
+ if (ret < 0)
+ goto err;
+ }
+ } else {
+ ret = bolero_clk_rsc_mux0_clk_request(priv, clk_id_req, enable);
+ if (ret < 0)
+ goto err;
+ }
+
+ ret = bolero_clk_rsc_check_and_update_va_clk(priv, mux_switch,
+ clk_id_req,
+ enable);
+ if (ret < 0)
+ goto err;
+
+ dev_dbg(priv->dev, "%s: clk_cnt: %d for requested clk: %d, enable: %d\n",
+ __func__, priv->clk_cnt[clk_id_req], clk_id_req,
+ enable);
+
+ mutex_unlock(&priv->rsc_clk_lock);
+
+ return 0;
+
+err:
+ mutex_unlock(&priv->rsc_clk_lock);
+ return ret;
+}
+EXPORT_SYMBOL(bolero_clk_rsc_request_clock);
+
+
+static int bolero_clk_rsc_probe(struct platform_device *pdev)
+{
+ int ret = 0, fs_gen_size, i, j;
+ const char **clk_name_array;
+ int clk_cnt;
+ struct clk *clk;
+ struct bolero_clk_rsc *priv = NULL;
+ u32 muxsel = 0;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(struct bolero_clk_rsc),
+ GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ /* Get clk fs gen sequence from device tree */
+ if (!of_find_property(pdev->dev.of_node, "qcom,fs-gen-sequence",
+ &fs_gen_size)) {
+ dev_err(&pdev->dev, "%s: unable to find qcom,fs-gen-sequence property\n",
+ __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+ priv->num_fs_reg = fs_gen_size/(2 * sizeof(u32));
+ priv->fs_gen_seq = devm_kzalloc(&pdev->dev, fs_gen_size, GFP_KERNEL);
+ if (!priv->fs_gen_seq) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ dev_dbg(&pdev->dev, "%s: num_fs_reg %d\n", __func__, priv->num_fs_reg);
+ /* Parse fs-gen-sequence */
+ ret = of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,fs-gen-sequence",
+ priv->fs_gen_seq,
+ priv->num_fs_reg * 2);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "%s: unable to parse fs-gen-sequence, ret = %d\n",
+ __func__, ret);
+ goto err;
+ }
+
+ /* Get clk details from device tree */
+ clk_cnt = of_property_count_strings(pdev->dev.of_node, "clock-names");
+ if (clk_cnt <= 0 || clk_cnt > MAX_CLK) {
+ dev_err(&pdev->dev, "%s: Invalid number of clocks %d",
+ __func__, clk_cnt);
+ ret = -EINVAL;
+ goto err;
+ }
+ clk_name_array = devm_kzalloc(&pdev->dev, clk_cnt * sizeof(char *),
+ GFP_KERNEL);
+
+ ret = of_property_read_string_array(pdev->dev.of_node, "clock-names",
+ clk_name_array, clk_cnt);
+
+ for (i = 0; i < MAX_CLK; i++) {
+ priv->clk[i] = NULL;
+ for (j = 0; j < clk_cnt; j++) {
+ if (!strcmp(clk_src_name[i], clk_name_array[j])) {
+ clk = devm_clk_get(&pdev->dev, clk_src_name[i]);
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+ dev_err(&pdev->dev, "%s: clk get failed for %s with ret %d\n",
+ __func__, clk_src_name[i], ret);
+ goto err;
+ }
+ priv->clk[i] = clk;
+ dev_dbg(&pdev->dev, "%s: clk get success for clk name %s\n",
+ __func__, clk_src_name[i]);
+ }
+ }
+ }
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "qcom,rx_mclk_mode_muxsel", &muxsel);
+ if (ret) {
+ dev_dbg(&pdev->dev, "%s: could not find qcom,rx_mclk_mode_muxsel entry in dt\n",
+ __func__);
+ } else {
+ priv->rx_clk_muxsel = devm_ioremap(&pdev->dev, muxsel, 0x4);
+ if (!priv->rx_clk_muxsel) {
+ dev_err(&pdev->dev, "%s: ioremap failed for rx muxsel\n",
+ __func__);
+ return -ENOMEM;
+ }
+ }
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "qcom,wsa_mclk_mode_muxsel", &muxsel);
+ if (ret) {
+ dev_dbg(&pdev->dev, "%s: could not find qcom,wsa_mclk_mode_muxsel entry in dt\n",
+ __func__);
+ } else {
+ priv->wsa_clk_muxsel = devm_ioremap(&pdev->dev, muxsel, 0x4);
+ if (!priv->wsa_clk_muxsel) {
+ dev_err(&pdev->dev, "%s: ioremap failed for wsa muxsel\n",
+ __func__);
+ return -ENOMEM;
+ }
+ }
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "qcom,va_mclk_mode_muxsel", &muxsel);
+ if (ret) {
+ dev_dbg(&pdev->dev, "%s: could not find qcom,va_mclk_mode_muxsel entry in dt\n",
+ __func__);
+ } else {
+ priv->va_clk_muxsel = devm_ioremap(&pdev->dev, muxsel, 0x4);
+ if (!priv->va_clk_muxsel) {
+ dev_err(&pdev->dev, "%s: ioremap failed for va muxsel\n",
+ __func__);
+ return -ENOMEM;
+ }
+ }
+
+ ret = bolero_register_res_clk(&pdev->dev, bolero_clk_rsc_cb);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "%s: Failed to register cb %d",
+ __func__, ret);
+ goto err;
+ }
+ priv->dev = &pdev->dev;
+ priv->dev_up = true;
+ mutex_init(&priv->rsc_clk_lock);
+ dev_set_drvdata(&pdev->dev, priv);
+
+err:
+ return ret;
+}
+
+static int bolero_clk_rsc_remove(struct platform_device *pdev)
+{
+ struct bolero_clk_rsc *priv = dev_get_drvdata(&pdev->dev);
+
+ bolero_unregister_res_clk(&pdev->dev);
+ of_platform_depopulate(&pdev->dev);
+ if (!priv)
+ return -EINVAL;
+ mutex_destroy(&priv->rsc_clk_lock);
+
+ return 0;
+}
+
+static const struct of_device_id bolero_clk_rsc_dt_match[] = {
+ {.compatible = "qcom,bolero-clk-rsc-mngr"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, bolero_clk_rsc_dt_match);
+
+static struct platform_driver bolero_clk_rsc_mgr = {
+ .driver = {
+ .name = "bolero-clk-rsc-mngr",
+ .owner = THIS_MODULE,
+ .of_match_table = bolero_clk_rsc_dt_match,
+ },
+ .probe = bolero_clk_rsc_probe,
+ .remove = bolero_clk_rsc_remove,
+};
+
+int bolero_clk_rsc_mgr_init(void)
+{
+ return platform_driver_register(&bolero_clk_rsc_mgr);
+}
+
+void bolero_clk_rsc_mgr_exit(void)
+{
+ platform_driver_unregister(&bolero_clk_rsc_mgr);
+}
+MODULE_DESCRIPTION("Bolero clock resource manager driver");
+MODULE_LICENSE("GPL v2");
diff --git a/asoc/codecs/bolero/bolero-clk-rsc.h b/asoc/codecs/bolero/bolero-clk-rsc.h
new file mode 100644
index 0000000..b378f73
--- /dev/null
+++ b/asoc/codecs/bolero/bolero-clk-rsc.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef BOLERO_CLK_RSC_H
+#define BOLERO_CLK_RSC_H
+
+#include <linux/regmap.h>
+#include <dt-bindings/sound/qcom,bolero-clk-rsc.h>
+
+#if IS_ENABLED(CONFIG_SND_SOC_BOLERO)
+int bolero_clk_rsc_mgr_init(void);
+void bolero_clk_rsc_mgr_exit(void);
+void bolero_clk_rsc_fs_gen_request(struct device *dev,
+ bool enable);
+int bolero_clk_rsc_request_clock(struct device *dev,
+ int default_clk_id,
+ int clk_id_req,
+ bool enable);
+#else
+static inline void bolero_clk_rsc_fs_gen_request(struct device *dev,
+ bool enable)
+{
+}
+static inline int bolero_clk_rsc_mgr_init(void)
+{
+ return 0;
+}
+static inline void bolero_clk_rsc_mgr_exit(void)
+{
+}
+static inline int bolero_clk_rsc_request_clock(struct device *dev,
+ int default_clk_id,
+ int clk_id_req,
+ bool enable)
+{
+ return 0;
+}
+
+#endif /* CONFIG_SND_SOC_BOLERO */
+#endif /* BOLERO_CLK_RSC_H */
diff --git a/asoc/codecs/bolero/internal.h b/asoc/codecs/bolero/internal.h
index 2749b0b..734afbc 100644
--- a/asoc/codecs/bolero/internal.h
+++ b/asoc/codecs/bolero/internal.h
@@ -7,7 +7,7 @@
#include "bolero-cdc-registers.h"
-#define BOLERO_CDC_CHILD_DEVICES_MAX 5
+#define BOLERO_CDC_CHILD_DEVICES_MAX 6
/* from bolero to WCD events */
enum {
@@ -73,7 +73,8 @@
struct wcd_ctrl_platform_data plat_data;
struct device *wcd_dev;
struct blocking_notifier_head notifier;
- int clk_users;
+ struct device *clk_dev;
+ rsc_clk_cb_t rsc_clk_cb;
};
struct regmap *bolero_regmap_init(struct device *dev,
diff --git a/asoc/codecs/bolero/rx-macro.c b/asoc/codecs/bolero/rx-macro.c
index 0352152..0fc13ee 100644
--- a/asoc/codecs/bolero/rx-macro.c
+++ b/asoc/codecs/bolero/rx-macro.c
@@ -18,6 +18,7 @@
#include <asoc/msm-cdc-pinctrl.h>
#include "bolero-cdc.h"
#include "bolero-cdc-registers.h"
+#include "bolero-clk-rsc.h"
#define RX_MACRO_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
@@ -331,8 +332,6 @@
* @swr_plat_data: Soundwire platform data
* @rx_macro_add_child_devices_work: work for adding child devices
* @rx_swr_gpio_p: used by pinctrl API
- * @rx_core_clk: MCLK for rx macro
- * @rx_npl_clk: NPL clock for RX soundwire
* @component: codec handle
*/
struct rx_macro_priv {
@@ -353,15 +352,12 @@
bool dev_up;
bool hph_pwr_mode;
bool hph_hd2_mode;
- u16 mclk_mux;
struct mutex mclk_lock;
struct mutex swr_clk_lock;
struct rx_swr_ctrl_data *swr_ctrl_data;
struct rx_swr_ctrl_platform_data swr_plat_data;
struct work_struct rx_macro_add_child_devices_work;
struct device_node *rx_swr_gpio_p;
- struct clk *rx_core_clk;
- struct clk *rx_npl_clk;
struct snd_soc_component *component;
unsigned long active_ch_mask[RX_MACRO_MAX_DAIS];
unsigned long active_ch_cnt[RX_MACRO_MAX_DAIS];
@@ -378,6 +374,8 @@
int is_softclip_on;
int softclip_clk_users;
struct rx_macro_bcl_pmic_params bcl_pmic_params;
+ u16 clk_id;
+ u16 default_clk_id;
};
static struct snd_soc_dai_driver rx_macro_dai[];
@@ -1059,7 +1057,7 @@
bool mclk_enable, bool dapm)
{
struct regmap *regmap = dev_get_regmap(rx_priv->dev->parent, NULL);
- int ret = 0, mclk_mux = MCLK_MUX0;
+ int ret = 0;
if (regmap == NULL) {
dev_err(rx_priv->dev, "%s: regmap is NULL\n", __func__);
@@ -1073,16 +1071,19 @@
if (mclk_enable) {
if (rx_priv->rx_mclk_users == 0) {
if (rx_priv->is_native_on)
- mclk_mux = MCLK_MUX1;
- ret = bolero_request_clock(rx_priv->dev,
- RX_MACRO, mclk_mux, true);
+ rx_priv->clk_id = RX_CORE_CLK;
+ ret = bolero_clk_rsc_request_clock(rx_priv->dev,
+ rx_priv->default_clk_id,
+ rx_priv->clk_id,
+ true);
if (ret < 0) {
dev_err(rx_priv->dev,
"%s: rx request clock enable failed\n",
__func__);
goto exit;
}
- rx_priv->mclk_mux = mclk_mux;
+ bolero_clk_rsc_fs_gen_request(rx_priv->dev,
+ true);
regcache_mark_dirty(regmap);
regcache_sync_region(regmap,
RX_START_OFFSET,
@@ -1113,10 +1114,13 @@
regmap_update_bits(regmap,
BOLERO_CDC_RX_CLK_RST_CTRL_MCLK_CONTROL,
0x01, 0x00);
- mclk_mux = rx_priv->mclk_mux;
- bolero_request_clock(rx_priv->dev,
- RX_MACRO, mclk_mux, false);
- rx_priv->mclk_mux = MCLK_MUX0;
+ bolero_clk_rsc_fs_gen_request(rx_priv->dev,
+ false);
+ bolero_clk_rsc_request_clock(rx_priv->dev,
+ rx_priv->default_clk_id,
+ rx_priv->clk_id,
+ false);
+ rx_priv->clk_id = rx_priv->default_clk_id;
}
}
exit:
@@ -1142,9 +1146,9 @@
case SND_SOC_DAPM_PRE_PMU:
/* if swr_clk_users > 0, call device down */
if (rx_priv->swr_clk_users > 0) {
- if ((rx_priv->mclk_mux == MCLK_MUX0 &&
+ if ((rx_priv->clk_id == rx_priv->default_clk_id &&
rx_priv->is_native_on) ||
- (rx_priv->mclk_mux == MCLK_MUX1 &&
+ (rx_priv->clk_id == RX_CORE_CLK &&
!rx_priv->is_native_on)) {
swrm_wcd_notify(
rx_priv->swr_ctrl_data[0].rx_swr_pdev,
@@ -1174,51 +1178,13 @@
return ret;
}
-static int rx_macro_mclk_ctrl(struct device *dev, bool enable)
-{
- struct rx_macro_priv *rx_priv = dev_get_drvdata(dev);
- int ret = 0;
-
- if (enable) {
- ret = clk_prepare_enable(rx_priv->rx_core_clk);
- if (ret < 0) {
- dev_err(dev, "%s:rx mclk enable failed\n", __func__);
- return ret;
- }
- ret = clk_prepare_enable(rx_priv->rx_npl_clk);
- if (ret < 0) {
- clk_disable_unprepare(rx_priv->rx_core_clk);
- dev_err(dev, "%s:rx npl_clk enable failed\n",
- __func__);
- return ret;
- }
- if (rx_priv->rx_mclk_cnt++ == 0) {
- if (rx_priv->dev_up)
- iowrite32(0x1, rx_priv->rx_mclk_mode_muxsel);
- }
- } else {
- if (rx_priv->rx_mclk_cnt <= 0) {
- dev_dbg(dev, "%s:rx mclk already disabled\n", __func__);
- rx_priv->rx_mclk_cnt = 0;
- return 0;
- }
- if (--rx_priv->rx_mclk_cnt == 0) {
- if (rx_priv->dev_up)
- iowrite32(0x0, rx_priv->rx_mclk_mode_muxsel);
- }
- clk_disable_unprepare(rx_priv->rx_npl_clk);
- clk_disable_unprepare(rx_priv->rx_core_clk);
- }
-
- return 0;
-}
-
static int rx_macro_event_handler(struct snd_soc_component *component,
u16 event, u32 data)
{
u16 reg = 0, reg_mix = 0, rx_idx = 0, mute = 0x0, val = 0;
struct device *rx_dev = NULL;
struct rx_macro_priv *rx_priv = NULL;
+ int ret = 0;
if (!rx_macro_get_data(component, &rx_dev, &rx_priv, __func__))
return -EINVAL;
@@ -1256,17 +1222,25 @@
rx_priv->dev_up = true;
/* reset swr after ssr/pdr */
rx_priv->reset_swr = true;
- /* enable&disable MCLK_MUX1 to reset GFMUX reg */
- bolero_request_clock(rx_priv->dev,
- RX_MACRO, MCLK_MUX1, true);
- bolero_request_clock(rx_priv->dev,
- RX_MACRO, MCLK_MUX1, false);
+ /* enable&disable RX_CORE_CLK to reset GFMUX reg */
+ ret = bolero_clk_rsc_request_clock(rx_priv->dev,
+ rx_priv->default_clk_id,
+ RX_CORE_CLK, true);
+ if (ret < 0)
+ dev_err_ratelimited(rx_priv->dev,
+ "%s, failed to enable clk, ret:%d\n",
+ __func__, ret);
+ else
+ bolero_clk_rsc_request_clock(rx_priv->dev,
+ rx_priv->default_clk_id,
+ RX_CORE_CLK, false);
+
swrm_wcd_notify(
rx_priv->swr_ctrl_data[0].rx_swr_pdev,
SWR_DEVICE_SSR_UP, NULL);
break;
}
- return 0;
+ return ret;
}
static int rx_macro_find_playback_dai_id_for_port(int port_id,
@@ -3573,7 +3547,6 @@
ops->io_base = rx_io_base;
ops->dai_ptr = rx_macro_dai;
ops->num_dais = ARRAY_SIZE(rx_macro_dai);
- ops->mclk_fn = rx_macro_mclk_ctrl;
ops->event_handler = rx_macro_event_handler;
ops->set_port_map = rx_macro_set_port_map;
}
@@ -3585,8 +3558,8 @@
u32 rx_base_addr = 0, muxsel = 0;
char __iomem *rx_io_base = NULL, *muxsel_io = NULL;
int ret = 0;
- struct clk *rx_core_clk = NULL, *rx_npl_clk = NULL;
u8 bcl_pmic_params[3];
+ u32 default_clk_id = 0;
rx_priv = devm_kzalloc(&pdev->dev, sizeof(struct rx_macro_priv),
GFP_KERNEL);
@@ -3608,6 +3581,13 @@
__func__, "reg");
return ret;
}
+ ret = of_property_read_u32(pdev->dev.of_node, "qcom,default-clk-id",
+ &default_clk_id);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: could not find %s entry in dt\n",
+ __func__, "qcom,default-clk-id");
+ default_clk_id = RX_CORE_CLK;
+ }
rx_priv->rx_swr_gpio_p = of_parse_phandle(pdev->dev.of_node,
"qcom,rx-swr-gpios", 0);
if (!rx_priv->rx_swr_gpio_p) {
@@ -3639,25 +3619,6 @@
rx_priv->swr_plat_data.clk = rx_swrm_clock;
rx_priv->swr_plat_data.handle_irq = NULL;
- /* Register MCLK for rx macro */
- rx_core_clk = devm_clk_get(&pdev->dev, "rx_core_clk");
- if (IS_ERR(rx_core_clk)) {
- ret = PTR_ERR(rx_core_clk);
- dev_err(&pdev->dev, "%s: clk get %s failed %d\n",
- __func__, "rx_core_clk", ret);
- return ret;
- }
- rx_priv->rx_core_clk = rx_core_clk;
- /* Register npl clk for soundwire */
- rx_npl_clk = devm_clk_get(&pdev->dev, "rx_npl_clk");
- if (IS_ERR(rx_npl_clk)) {
- ret = PTR_ERR(rx_npl_clk);
- dev_err(&pdev->dev, "%s: clk get %s failed %d\n",
- __func__, "rx_npl_clk", ret);
- return ret;
- }
- rx_priv->rx_npl_clk = rx_npl_clk;
-
ret = of_property_read_u8_array(pdev->dev.of_node,
"qcom,rx-bcl-pmic-params", bcl_pmic_params,
sizeof(bcl_pmic_params));
@@ -3669,6 +3630,10 @@
rx_priv->bcl_pmic_params.sid = bcl_pmic_params[1];
rx_priv->bcl_pmic_params.ppid = bcl_pmic_params[2];
}
+ rx_priv->clk_id = default_clk_id;
+ rx_priv->default_clk_id = default_clk_id;
+ ops.clk_id_req = rx_priv->clk_id;
+ ops.default_clk_id = default_clk_id;
dev_set_drvdata(&pdev->dev, rx_priv);
mutex_init(&rx_priv->mclk_lock);
diff --git a/asoc/codecs/bolero/tx-macro.c b/asoc/codecs/bolero/tx-macro.c
index 98ee1e7..b7d7d37 100644
--- a/asoc/codecs/bolero/tx-macro.c
+++ b/asoc/codecs/bolero/tx-macro.c
@@ -16,6 +16,7 @@
#include <asoc/msm-cdc-pinctrl.h>
#include "bolero-cdc.h"
#include "bolero-cdc-registers.h"
+#include "bolero-clk-rsc.h"
#define TX_MACRO_MAX_OFFSET 0x1000
@@ -129,8 +130,6 @@
int swr_clk_users;
bool dapm_mclk_enable;
bool reset_swr;
- struct clk *tx_core_clk;
- struct clk *tx_npl_clk;
struct mutex mclk_lock;
struct mutex swr_clk_lock;
struct snd_soc_component *component;
@@ -151,6 +150,8 @@
struct platform_device *pdev_child_devices
[TX_MACRO_CHILD_DEVICES_MAX];
int child_count;
+ int tx_swr_clk_cnt;
+ int va_swr_clk_cnt;
};
static bool tx_macro_get_data(struct snd_soc_component *component,
@@ -198,14 +199,18 @@
mutex_lock(&tx_priv->mclk_lock);
if (mclk_enable) {
if (tx_priv->tx_mclk_users == 0) {
- ret = bolero_request_clock(tx_priv->dev,
- TX_MACRO, MCLK_MUX0, true);
+ ret = bolero_clk_rsc_request_clock(tx_priv->dev,
+ TX_CORE_CLK,
+ TX_CORE_CLK,
+ true);
if (ret < 0) {
dev_err(tx_priv->dev,
"%s: request clock enable failed\n",
__func__);
goto exit;
}
+ bolero_clk_rsc_fs_gen_request(tx_priv->dev,
+ true);
regcache_mark_dirty(regmap);
regcache_sync_region(regmap,
TX_START_OFFSET,
@@ -236,8 +241,13 @@
regmap_update_bits(regmap,
BOLERO_CDC_TX_CLK_RST_CTRL_MCLK_CONTROL,
0x01, 0x00);
- bolero_request_clock(tx_priv->dev,
- TX_MACRO, MCLK_MUX0, false);
+ bolero_clk_rsc_fs_gen_request(tx_priv->dev,
+ false);
+
+ bolero_clk_rsc_request_clock(tx_priv->dev,
+ TX_CORE_CLK,
+ TX_CORE_CLK,
+ false);
}
}
exit:
@@ -245,6 +255,44 @@
return ret;
}
+static int tx_macro_va_swr_clk_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct device *tx_dev = NULL;
+ struct tx_macro_priv *tx_priv = NULL;
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+
+ if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__))
+ return -EINVAL;
+
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ ++tx_priv->va_swr_clk_cnt;
+ if (SND_SOC_DAPM_EVENT_OFF(event))
+ --tx_priv->va_swr_clk_cnt;
+
+ return 0;
+}
+
+static int tx_macro_tx_swr_clk_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct device *tx_dev = NULL;
+ struct tx_macro_priv *tx_priv = NULL;
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+
+ if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__))
+ return -EINVAL;
+
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ ++tx_priv->tx_swr_clk_cnt;
+ if (SND_SOC_DAPM_EVENT_OFF(event))
+ --tx_priv->tx_swr_clk_cnt;
+
+ return 0;
+}
+
static int tx_macro_mclk_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -278,33 +326,6 @@
return ret;
}
-static int tx_macro_mclk_ctrl(struct device *dev, bool enable)
-{
- struct tx_macro_priv *tx_priv = dev_get_drvdata(dev);
- int ret = 0;
-
- if (enable) {
- ret = clk_prepare_enable(tx_priv->tx_core_clk);
- if (ret < 0) {
- dev_err(dev, "%s:tx mclk enable failed\n", __func__);
- goto exit;
- }
- ret = clk_prepare_enable(tx_priv->tx_npl_clk);
- if (ret < 0) {
- dev_err(dev, "%s:tx npl_clk enable failed\n",
- __func__);
- clk_disable_unprepare(tx_priv->tx_core_clk);
- goto exit;
- }
- } else {
- clk_disable_unprepare(tx_priv->tx_npl_clk);
- clk_disable_unprepare(tx_priv->tx_core_clk);
- }
-
-exit:
- return ret;
-}
-
static int tx_macro_event_handler(struct snd_soc_component *component,
u16 event, u32 data)
{
@@ -1156,6 +1177,14 @@
SND_SOC_DAPM_SUPPLY_S("TX_MCLK", 0, SND_SOC_NOPM, 0, 0,
tx_macro_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY_S("TX_SWR_CLK", 0, SND_SOC_NOPM, 0, 0,
+ tx_macro_tx_swr_clk_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY_S("VA_SWR_CLK", 0, SND_SOC_NOPM, 0, 0,
+ tx_macro_va_swr_clk_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
};
static const struct snd_soc_dapm_route tx_audio_map[] = {
@@ -1203,6 +1232,7 @@
{"TX DMIC MUX0", "DMIC7", "TX DMIC7"},
{"TX DEC0 MUX", "SWR_MIC", "TX SMIC MUX0"},
+ {"TX SMIC MUX0", NULL, "TX_SWR_CLK"},
{"TX SMIC MUX0", "ADC0", "TX SWR_ADC0"},
{"TX SMIC MUX0", "ADC1", "TX SWR_ADC1"},
{"TX SMIC MUX0", "ADC2", "TX SWR_ADC2"},
@@ -1228,6 +1258,7 @@
{"TX DMIC MUX1", "DMIC7", "TX DMIC7"},
{"TX DEC1 MUX", "SWR_MIC", "TX SMIC MUX1"},
+ {"TX SMIC MUX1", NULL, "TX_SWR_CLK"},
{"TX SMIC MUX1", "ADC0", "TX SWR_ADC0"},
{"TX SMIC MUX1", "ADC1", "TX SWR_ADC1"},
{"TX SMIC MUX1", "ADC2", "TX SWR_ADC2"},
@@ -1253,6 +1284,7 @@
{"TX DMIC MUX2", "DMIC7", "TX DMIC7"},
{"TX DEC2 MUX", "SWR_MIC", "TX SMIC MUX2"},
+ {"TX SMIC MUX2", NULL, "TX_SWR_CLK"},
{"TX SMIC MUX2", "ADC0", "TX SWR_ADC0"},
{"TX SMIC MUX2", "ADC1", "TX SWR_ADC1"},
{"TX SMIC MUX2", "ADC2", "TX SWR_ADC2"},
@@ -1278,6 +1310,7 @@
{"TX DMIC MUX3", "DMIC7", "TX DMIC7"},
{"TX DEC3 MUX", "SWR_MIC", "TX SMIC MUX3"},
+ {"TX SMIC MUX3", NULL, "TX_SWR_CLK"},
{"TX SMIC MUX3", "ADC0", "TX SWR_ADC0"},
{"TX SMIC MUX3", "ADC1", "TX SWR_ADC1"},
{"TX SMIC MUX3", "ADC2", "TX SWR_ADC2"},
@@ -1303,6 +1336,7 @@
{"TX DMIC MUX4", "DMIC7", "TX DMIC7"},
{"TX DEC4 MUX", "SWR_MIC", "TX SMIC MUX4"},
+ {"TX SMIC MUX4", NULL, "TX_SWR_CLK"},
{"TX SMIC MUX4", "ADC0", "TX SWR_ADC0"},
{"TX SMIC MUX4", "ADC1", "TX SWR_ADC1"},
{"TX SMIC MUX4", "ADC2", "TX SWR_ADC2"},
@@ -1328,6 +1362,7 @@
{"TX DMIC MUX5", "DMIC7", "TX DMIC7"},
{"TX DEC5 MUX", "SWR_MIC", "TX SMIC MUX5"},
+ {"TX SMIC MUX5", NULL, "TX_SWR_CLK"},
{"TX SMIC MUX5", "ADC0", "TX SWR_ADC0"},
{"TX SMIC MUX5", "ADC1", "TX SWR_ADC1"},
{"TX SMIC MUX5", "ADC2", "TX SWR_ADC2"},
@@ -1353,6 +1388,7 @@
{"TX DMIC MUX6", "DMIC7", "TX DMIC7"},
{"TX DEC6 MUX", "SWR_MIC", "TX SMIC MUX6"},
+ {"TX SMIC MUX6", NULL, "TX_SWR_CLK"},
{"TX SMIC MUX6", "ADC0", "TX SWR_ADC0"},
{"TX SMIC MUX6", "ADC1", "TX SWR_ADC1"},
{"TX SMIC MUX6", "ADC2", "TX SWR_ADC2"},
@@ -1378,6 +1414,7 @@
{"TX DMIC MUX7", "DMIC7", "TX DMIC7"},
{"TX DEC7 MUX", "SWR_MIC", "TX SMIC MUX7"},
+ {"TX SMIC MUX7", NULL, "TX_SWR_CLK"},
{"TX SMIC MUX7", "ADC0", "TX SWR_ADC0"},
{"TX SMIC MUX7", "ADC1", "TX SWR_ADC1"},
{"TX SMIC MUX7", "ADC2", "TX SWR_ADC2"},
@@ -1769,7 +1806,6 @@
ops->io_base = tx_io_base;
ops->dai_ptr = tx_macro_dai;
ops->num_dais = ARRAY_SIZE(tx_macro_dai);
- ops->mclk_fn = tx_macro_mclk_ctrl;
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;
@@ -1781,7 +1817,6 @@
struct tx_macro_priv *tx_priv = NULL;
u32 tx_base_addr = 0, sample_rate = 0;
char __iomem *tx_io_base = NULL;
- struct clk *tx_core_clk = NULL, *tx_npl_clk = NULL;
int ret = 0;
const char *dmic_sample_rate = "qcom,tx-dmic-sample-rate";
@@ -1835,34 +1870,19 @@
tx_priv->swr_plat_data.bulk_write = NULL;
tx_priv->swr_plat_data.clk = tx_macro_swrm_clock;
tx_priv->swr_plat_data.handle_irq = NULL;
- /* Register MCLK for tx macro */
- tx_core_clk = devm_clk_get(&pdev->dev, "tx_core_clk");
- if (IS_ERR(tx_core_clk)) {
- ret = PTR_ERR(tx_core_clk);
- dev_err(&pdev->dev, "%s: clk get %s failed %d\n",
- __func__, "tx_core_clk", ret);
- return ret;
- }
- tx_priv->tx_core_clk = tx_core_clk;
- /* Register npl clk for soundwire */
- tx_npl_clk = devm_clk_get(&pdev->dev, "tx_npl_clk");
- if (IS_ERR(tx_npl_clk)) {
- ret = PTR_ERR(tx_npl_clk);
- dev_err(&pdev->dev, "%s: clk get %s failed %d\n",
- __func__, "tx_npl_clk", ret);
- return ret;
- }
- tx_priv->tx_npl_clk = tx_npl_clk;
mutex_init(&tx_priv->mclk_lock);
mutex_init(&tx_priv->swr_clk_lock);
tx_macro_init_ops(&ops, tx_io_base);
+ ops.clk_id_req = TX_CORE_CLK;
+ ops.default_clk_id = TX_CORE_CLK;
ret = bolero_register_macro(&pdev->dev, TX_MACRO, &ops);
if (ret) {
dev_err(&pdev->dev,
"%s: register macro failed\n", __func__);
goto err_reg_macro;
}
+
schedule_work(&tx_priv->tx_macro_add_child_devices_work);
return 0;
err_reg_macro:
diff --git a/asoc/codecs/bolero/va-macro.c b/asoc/codecs/bolero/va-macro.c
index 8789fce..a4f3c7d 100644
--- a/asoc/codecs/bolero/va-macro.c
+++ b/asoc/codecs/bolero/va-macro.c
@@ -15,6 +15,7 @@
#include <linux/pm_runtime.h>
#include "bolero-cdc.h"
#include "bolero-cdc-registers.h"
+#include "bolero-clk-rsc.h"
/* pm runtime auto suspend timer in msecs */
#define VA_AUTO_SUSPEND_DELAY 100 /* delay in msec */
@@ -94,7 +95,6 @@
struct device *dev;
bool dec_active[VA_MACRO_NUM_DECIMATORS];
bool va_without_decimation;
- struct clk *va_core_clk;
struct mutex mclk_lock;
struct snd_soc_component *component;
struct hpf_work va_hpf_work[VA_MACRO_NUM_DECIMATORS];
@@ -114,6 +114,8 @@
u32 micb_voltage;
u32 micb_current;
int micb_users;
+ u16 default_clk_id;
+ u16 clk_id;
};
static bool va_macro_get_data(struct snd_soc_component *component,
@@ -153,15 +155,18 @@
mutex_lock(&va_priv->mclk_lock);
if (mclk_enable) {
if (va_priv->va_mclk_users == 0) {
- ret = bolero_request_clock(va_priv->dev,
- VA_MACRO,
- va_priv->mclk_mux_sel, true);
+ ret = bolero_clk_rsc_request_clock(va_priv->dev,
+ va_priv->default_clk_id,
+ va_priv->clk_id,
+ true);
if (ret < 0) {
dev_err(va_priv->dev,
"%s: va request clock en failed\n",
__func__);
goto exit;
}
+ bolero_clk_rsc_fs_gen_request(va_priv->dev,
+ true);
regcache_mark_dirty(regmap);
regcache_sync_region(regmap,
VA_START_OFFSET,
@@ -177,9 +182,12 @@
}
va_priv->va_mclk_users--;
if (va_priv->va_mclk_users == 0) {
- bolero_request_clock(va_priv->dev,
- VA_MACRO,
- va_priv->mclk_mux_sel, false);
+ bolero_clk_rsc_fs_gen_request(va_priv->dev,
+ false);
+ bolero_clk_rsc_request_clock(va_priv->dev,
+ va_priv->default_clk_id,
+ va_priv->clk_id,
+ false);
}
}
exit:
@@ -240,6 +248,10 @@
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
ret = va_macro_mclk_enable(va_priv, 1, true);
+ ret = bolero_clk_rsc_request_clock(va_priv->dev,
+ va_priv->default_clk_id,
+ TX_CORE_CLK,
+ true);
break;
case SND_SOC_DAPM_POST_PMD:
va_macro_mclk_enable(va_priv, 0, true);
@@ -252,29 +264,6 @@
return ret;
}
-static int va_macro_mclk_ctrl(struct device *dev, bool enable)
-{
- struct va_macro_priv *va_priv = dev_get_drvdata(dev);
- int ret = 0;
-
- if (enable) {
- ret = clk_prepare_enable(va_priv->va_core_clk);
- if (ret < 0) {
- dev_err(dev, "%s:va mclk enable failed\n", __func__);
- goto exit;
- }
- if (va_priv->mclk_mux_sel == MCLK_MUX1)
- iowrite32(0x1, va_priv->va_island_mode_muxsel);
- } else {
- if (va_priv->mclk_mux_sel == MCLK_MUX1)
- iowrite32(0x0, va_priv->va_island_mode_muxsel);
- clk_disable_unprepare(va_priv->va_core_clk);
- }
-
-exit:
- return ret;
-}
-
static void va_macro_tx_hpf_corner_freq_callback(struct work_struct *work)
{
struct delayed_work *hpf_delayed_work;
@@ -599,6 +588,10 @@
/* apply gain after decimator is enabled */
snd_soc_component_write(component, tx_gain_ctl_reg,
snd_soc_component_read32(component, tx_gain_ctl_reg));
+ bolero_clk_rsc_request_clock(va_priv->dev,
+ va_priv->default_clk_id,
+ TX_CORE_CLK,
+ false);
break;
case SND_SOC_DAPM_PRE_PMD:
hpf_cut_off_freq =
@@ -1581,7 +1574,6 @@
ops->init = va_macro_init;
ops->exit = va_macro_deinit;
ops->io_base = va_io_base;
- ops->mclk_fn = va_macro_mclk_ctrl;
ops->event_handler = va_macro_event_handler;
}
@@ -1589,10 +1581,8 @@
{
struct macro_ops ops;
struct va_macro_priv *va_priv;
- u32 va_base_addr, sample_rate = 0, island_sel = 0;
+ u32 va_base_addr, sample_rate = 0;
char __iomem *va_io_base;
- char __iomem *va_muxsel_io = NULL;
- struct clk *va_core_clk;
bool va_without_decimation = false;
const char *micb_supply_str = "va-vdd-micb-supply";
const char *micb_supply_str1 = "va-vdd-micb";
@@ -1600,7 +1590,7 @@
const char *micb_current_str = "qcom,va-vdd-micb-current";
int ret = 0;
const char *dmic_sample_rate = "qcom,va-dmic-sample-rate";
- u16 mclk_mux_sel = MCLK_MUX0;
+ u32 default_clk_id = 0;
va_priv = devm_kzalloc(&pdev->dev, sizeof(struct va_macro_priv),
GFP_KERNEL);
@@ -1639,53 +1629,6 @@
}
va_priv->va_io_base = va_io_base;
- ret = of_property_read_u16(va_priv->dev->of_node,
- "qcom,va-clk-mux-select", &mclk_mux_sel);
- if (ret) {
- dev_dbg(&pdev->dev,
- "%s: could not find %s entry in dt, use default\n",
- __func__, "qcom,va-clk-mux-select");
- } else {
- if (mclk_mux_sel != MCLK_MUX0 && mclk_mux_sel != MCLK_MUX1) {
- dev_err(&pdev->dev,
- "%s: mclk_mux_sel: %d is invalid\n",
- __func__, mclk_mux_sel);
- return -EINVAL;
- }
- }
- va_priv->mclk_mux_sel = mclk_mux_sel;
-
- if (va_priv->mclk_mux_sel == MCLK_MUX1) {
- ret = of_property_read_u32(pdev->dev.of_node,
- "qcom,va-island-mode-muxsel",
- &island_sel);
- if (ret) {
- dev_err(&pdev->dev,
- "%s: could not find %s entry in dt\n",
- __func__, "qcom,va-island-mode-muxsel");
- return ret;
- } else {
- va_muxsel_io = devm_ioremap(&pdev->dev,
- island_sel, 0x4);
- if (!va_muxsel_io) {
- dev_err(&pdev->dev,
- "%s: ioremap failed for island_sel\n",
- __func__);
- return -ENOMEM;
- }
- }
- va_priv->va_island_mode_muxsel = va_muxsel_io;
- }
- /* Register MCLK for va macro */
- va_core_clk = devm_clk_get(&pdev->dev, "va_core_clk");
- if (IS_ERR(va_core_clk)) {
- ret = PTR_ERR(va_core_clk);
- dev_err(&pdev->dev, "%s: clk get %s failed\n",
- __func__, "va_core_clk");
- return ret;
- }
- va_priv->va_core_clk = va_core_clk;
-
if (of_parse_phandle(pdev->dev.of_node, micb_supply_str, 0)) {
va_priv->micb_supply = devm_regulator_get(&pdev->dev,
micb_supply_str1);
@@ -1717,10 +1660,21 @@
return ret;
}
}
+ ret = of_property_read_u32(pdev->dev.of_node, "qcom,default-clk-id",
+ &default_clk_id);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: could not find %s entry in dt\n",
+ __func__, "qcom,default-clk-id");
+ default_clk_id = VA_CORE_CLK;
+ }
+ va_priv->clk_id = VA_CORE_CLK;
+ va_priv->default_clk_id = default_clk_id;
mutex_init(&va_priv->mclk_lock);
dev_set_drvdata(&pdev->dev, va_priv);
va_macro_init_ops(&ops, va_io_base, va_without_decimation);
+ ops.clk_id_req = va_priv->default_clk_id;
+ ops.default_clk_id = va_priv->default_clk_id;
ret = bolero_register_macro(&pdev->dev, VA_MACRO, &ops);
if (ret < 0) {
dev_err(&pdev->dev, "%s: register macro failed\n", __func__);
diff --git a/asoc/codecs/bolero/wsa-macro.c b/asoc/codecs/bolero/wsa-macro.c
index b0a4b1e..dd3f4fe 100644
--- a/asoc/codecs/bolero/wsa-macro.c
+++ b/asoc/codecs/bolero/wsa-macro.c
@@ -17,6 +17,7 @@
#include "bolero-cdc.h"
#include "bolero-cdc-registers.h"
#include "wsa-macro.h"
+#include "bolero-clk-rsc.h"
#define WSA_MACRO_MAX_OFFSET 0x1000
@@ -175,8 +176,6 @@
* @swr_plat_data: Soundwire platform data
* @wsa_macro_add_child_devices_work: work for adding child devices
* @wsa_swr_gpio_p: used by pinctrl API
- * @wsa_core_clk: MCLK for wsa macro
- * @wsa_npl_clk: NPL clock for WSA soundwire
* @component: codec handle
* @rx_0_count: RX0 interpolation users
* @rx_1_count: RX1 interpolation users
@@ -201,8 +200,6 @@
struct wsa_macro_swr_ctrl_platform_data swr_plat_data;
struct work_struct wsa_macro_add_child_devices_work;
struct device_node *wsa_swr_gpio_p;
- struct clk *wsa_core_clk;
- struct clk *wsa_npl_clk;
struct snd_soc_component *component;
int rx_0_count;
int rx_1_count;
@@ -219,6 +216,8 @@
int is_softclip_on[WSA_MACRO_SOFTCLIP_MAX];
int softclip_clk_users[WSA_MACRO_SOFTCLIP_MAX];
struct wsa_macro_bcl_pmic_params bcl_pmic_params;
+ char __iomem *mclk_mode_muxsel;
+ u16 default_clk_id;
};
static int wsa_macro_config_ear_spkr_gain(struct snd_soc_component *component,
@@ -808,14 +807,18 @@
mutex_lock(&wsa_priv->mclk_lock);
if (mclk_enable) {
if (wsa_priv->wsa_mclk_users == 0) {
- ret = bolero_request_clock(wsa_priv->dev,
- WSA_MACRO, MCLK_MUX0, true);
+ ret = bolero_clk_rsc_request_clock(wsa_priv->dev,
+ wsa_priv->default_clk_id,
+ wsa_priv->default_clk_id,
+ true);
if (ret < 0) {
dev_err(wsa_priv->dev,
"%s: wsa request clock enable failed\n",
__func__);
goto exit;
}
+ bolero_clk_rsc_fs_gen_request(wsa_priv->dev,
+ true);
regcache_mark_dirty(regmap);
regcache_sync_region(regmap,
WSA_START_OFFSET,
@@ -846,8 +849,13 @@
regmap_update_bits(regmap,
BOLERO_CDC_WSA_CLK_RST_CTRL_MCLK_CONTROL,
0x01, 0x00);
- bolero_request_clock(wsa_priv->dev,
- WSA_MACRO, MCLK_MUX0, false);
+ bolero_clk_rsc_fs_gen_request(wsa_priv->dev,
+ false);
+
+ bolero_clk_rsc_request_clock(wsa_priv->dev,
+ wsa_priv->default_clk_id,
+ wsa_priv->default_clk_id,
+ false);
}
}
exit:
@@ -888,35 +896,6 @@
return ret;
}
-static int wsa_macro_mclk_ctrl(struct device *dev, bool enable)
-{
- struct wsa_macro_priv *wsa_priv = dev_get_drvdata(dev);
- int ret = 0;
-
- if (!wsa_priv)
- return -EINVAL;
-
- if (enable) {
- ret = clk_prepare_enable(wsa_priv->wsa_core_clk);
- if (ret < 0) {
- dev_err(dev, "%s:wsa mclk enable failed\n", __func__);
- goto exit;
- }
- ret = clk_prepare_enable(wsa_priv->wsa_npl_clk);
- if (ret < 0) {
- dev_err(dev, "%s:wsa npl_clk enable failed\n",
- __func__);
- clk_disable_unprepare(wsa_priv->wsa_core_clk);
- goto exit;
- }
- } else {
- clk_disable_unprepare(wsa_priv->wsa_npl_clk);
- clk_disable_unprepare(wsa_priv->wsa_core_clk);
- }
-exit:
- return ret;
-}
-
static int wsa_macro_event_handler(struct snd_soc_component *component,
u16 event, u32 data)
{
@@ -2809,7 +2788,6 @@
ops->io_base = wsa_io_base;
ops->dai_ptr = wsa_macro_dai;
ops->num_dais = ARRAY_SIZE(wsa_macro_dai);
- ops->mclk_fn = wsa_macro_mclk_ctrl;
ops->event_handler = wsa_macro_event_handler;
ops->set_port_map = wsa_macro_set_port_map;
}
@@ -2818,10 +2796,9 @@
{
struct macro_ops ops;
struct wsa_macro_priv *wsa_priv;
- u32 wsa_base_addr;
+ u32 wsa_base_addr, default_clk_id;
char __iomem *wsa_io_base;
int ret = 0;
- struct clk *wsa_core_clk, *wsa_npl_clk;
u8 bcl_pmic_params[3];
wsa_priv = devm_kzalloc(&pdev->dev, sizeof(struct wsa_macro_priv),
@@ -2861,24 +2838,13 @@
wsa_priv->swr_plat_data.clk = wsa_swrm_clock;
wsa_priv->swr_plat_data.handle_irq = NULL;
- /* Register MCLK for wsa macro */
- wsa_core_clk = devm_clk_get(&pdev->dev, "wsa_core_clk");
- if (IS_ERR(wsa_core_clk)) {
- ret = PTR_ERR(wsa_core_clk);
- dev_err(&pdev->dev, "%s: clk get %s failed\n",
- __func__, "wsa_core_clk");
- return ret;
+ ret = of_property_read_u32(pdev->dev.of_node, "qcom,default-clk-id",
+ &default_clk_id);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: could not find %s entry in dt\n",
+ __func__, "qcom,mux0-clk-id");
+ default_clk_id = WSA_CORE_CLK;
}
- wsa_priv->wsa_core_clk = wsa_core_clk;
- /* Register npl clk for soundwire */
- wsa_npl_clk = devm_clk_get(&pdev->dev, "wsa_npl_clk");
- if (IS_ERR(wsa_npl_clk)) {
- ret = PTR_ERR(wsa_npl_clk);
- dev_err(&pdev->dev, "%s: clk get %s failed\n",
- __func__, "wsa_npl_clk");
- return ret;
- }
- wsa_priv->wsa_npl_clk = wsa_npl_clk;
ret = of_property_read_u8_array(pdev->dev.of_node,
"qcom,wsa-bcl-pmic-params", bcl_pmic_params,
@@ -2891,11 +2857,14 @@
wsa_priv->bcl_pmic_params.sid = bcl_pmic_params[1];
wsa_priv->bcl_pmic_params.ppid = bcl_pmic_params[2];
}
+ wsa_priv->default_clk_id = default_clk_id;
dev_set_drvdata(&pdev->dev, wsa_priv);
mutex_init(&wsa_priv->mclk_lock);
mutex_init(&wsa_priv->swr_clk_lock);
wsa_macro_init_ops(&ops, wsa_io_base);
+ ops.clk_id_req = wsa_priv->default_clk_id;
+ ops.default_clk_id = wsa_priv->default_clk_id;
ret = bolero_register_macro(&pdev->dev, WSA_MACRO, &ops);
if (ret < 0) {
dev_err(&pdev->dev, "%s: register macro failed\n", __func__);
diff --git a/asoc/codecs/wcd-mbhc-v2.c b/asoc/codecs/wcd-mbhc-v2.c
index 1159b11..6a85c82 100644
--- a/asoc/codecs/wcd-mbhc-v2.c
+++ b/asoc/codecs/wcd-mbhc-v2.c
@@ -1358,9 +1358,6 @@
* by an external source
*/
if (mbhc->mbhc_cfg->enable_usbc_analog) {
- mbhc->hphl_swh = 0;
- mbhc->gnd_swh = 0;
-
if (mbhc->mbhc_cb->hph_pull_up_control_v2)
mbhc->mbhc_cb->hph_pull_up_control_v2(component,
HS_PULLUP_I_OFF);
diff --git a/asoc/codecs/wcd937x/internal.h b/asoc/codecs/wcd937x/internal.h
index 110425a..b7bdfa2 100644
--- a/asoc/codecs/wcd937x/internal.h
+++ b/asoc/codecs/wcd937x/internal.h
@@ -83,6 +83,8 @@
struct snd_info_entry *entry;
struct snd_info_entry *version_entry;
int ear_rx_path;
+ int ana_clk_count;
+ struct mutex ana_tx_clk_lock;
};
struct wcd937x_micbias_setting {
diff --git a/asoc/codecs/wcd937x/wcd937x.c b/asoc/codecs/wcd937x/wcd937x.c
index 0836bc0..5e9994f 100644
--- a/asoc/codecs/wcd937x/wcd937x.c
+++ b/asoc/codecs/wcd937x/wcd937x.c
@@ -1271,12 +1271,17 @@
struct snd_soc_component *component =
snd_soc_dapm_to_component(w->dapm);
+ struct wcd937x_priv *wcd937x =
+ snd_soc_component_get_drvdata(component);
dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__,
w->name, event);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
+ mutex_lock(&wcd937x->ana_tx_clk_lock);
+ wcd937x->ana_clk_count++;
+ mutex_unlock(&wcd937x->ana_tx_clk_lock);
snd_soc_component_update_bits(component,
WCD937X_DIGITAL_CDC_DIG_CLK_CTL, 0x80, 0x80);
snd_soc_component_update_bits(component,
@@ -1300,6 +1305,8 @@
{
struct snd_soc_component *component =
snd_soc_dapm_to_component(w->dapm);
+ struct wcd937x_priv *wcd937x =
+ snd_soc_component_get_drvdata(component);
dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__,
w->name, event);
@@ -1328,8 +1335,15 @@
WCD937X_ANA_TX_CH2, 0x80, 0x00);
snd_soc_component_update_bits(component,
WCD937X_DIGITAL_CDC_DIG_CLK_CTL, 0x10, 0x00);
- snd_soc_component_update_bits(component,
+ mutex_lock(&wcd937x->ana_tx_clk_lock);
+ wcd937x->ana_clk_count--;
+ if (wcd937x->ana_clk_count <= 0) {
+ snd_soc_component_update_bits(component,
WCD937X_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x00);
+ wcd937x->ana_clk_count = 0;
+ }
+
+ mutex_unlock(&wcd937x->ana_tx_clk_lock);
snd_soc_component_update_bits(component,
WCD937X_DIGITAL_CDC_DIG_CLK_CTL, 0x80, 0x00);
break;
@@ -1393,6 +1407,9 @@
break;
case MICB_ENABLE:
wcd937x->micb_ref[micb_index]++;
+ mutex_lock(&wcd937x->ana_tx_clk_lock);
+ wcd937x->ana_clk_count++;
+ mutex_unlock(&wcd937x->ana_tx_clk_lock);
if (wcd937x->micb_ref[micb_index] == 1) {
snd_soc_component_update_bits(component,
WCD937X_DIGITAL_CDC_DIG_CLK_CTL, 0xE0, 0xE0);
@@ -1417,6 +1434,9 @@
&wcd937x->mbhc->wcd_mbhc);
break;
case MICB_DISABLE:
+ mutex_lock(&wcd937x->ana_tx_clk_lock);
+ wcd937x->ana_clk_count--;
+ mutex_unlock(&wcd937x->ana_tx_clk_lock);
if (wcd937x->micb_ref[micb_index] > 0)
wcd937x->micb_ref[micb_index]--;
if ((wcd937x->micb_ref[micb_index] == 0) &&
@@ -1437,6 +1457,14 @@
post_off_event,
&wcd937x->mbhc->wcd_mbhc);
}
+ mutex_lock(&wcd937x->ana_tx_clk_lock);
+ if (wcd937x->ana_clk_count <= 0) {
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_ANA_CLK_CTL,
+ 0x10, 0x00);
+ wcd937x->ana_clk_count = 0;
+ }
+ mutex_unlock(&wcd937x->ana_tx_clk_lock);
if (is_dapm && post_dapm_off && wcd937x->mbhc)
blocking_notifier_call_chain(
&wcd937x->mbhc->notifier, post_dapm_off,
@@ -2761,6 +2789,7 @@
}
mutex_init(&wcd937x->micb_lock);
+ mutex_init(&wcd937x->ana_tx_clk_lock);
/* Request for watchdog interrupt */
wcd_request_irq(&wcd937x->irq_info, WCD937X_IRQ_HPHR_PDM_WD_INT,
"HPHR PDM WD INT", wcd937x_wd_handle_irq, NULL);
@@ -2797,6 +2826,7 @@
snd_soc_unregister_component(dev);
component_unbind_all(dev, wcd937x);
mutex_destroy(&wcd937x->micb_lock);
+ mutex_destroy(&wcd937x->ana_tx_clk_lock);
}
static const struct of_device_id wcd937x_dt_match[] = {
diff --git a/asoc/codecs/wcd938x/wcd938x-mbhc.c b/asoc/codecs/wcd938x/wcd938x-mbhc.c
index 6d9f500..2516943 100644
--- a/asoc/codecs/wcd938x/wcd938x-mbhc.c
+++ b/asoc/codecs/wcd938x/wcd938x-mbhc.c
@@ -1,6 +1,6 @@
// 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.
*/
#include <linux/module.h>
#include <linux/init.h>
@@ -957,6 +957,31 @@
EXPORT_SYMBOL(wcd938x_mbhc_hs_detect_exit);
/*
+ * wcd938x_mbhc_ssr_down: stop mbhc during
+ * wcd938x subsystem restart
+ * mbhc: pointer to wcd937x_mbhc structure
+ * component: handle to snd_soc_component *
+ */
+void wcd938x_mbhc_ssr_down(struct wcd938x_mbhc *mbhc,
+ struct snd_soc_component *component)
+{
+ struct wcd_mbhc *wcd_mbhc = NULL;
+
+ if (!mbhc || !component)
+ return;
+
+ wcd_mbhc = &mbhc->wcd_mbhc;
+ if (!wcd_mbhc) {
+ dev_err(component->dev, "%s: wcd_mbhc is NULL\n", __func__);
+ return;
+ }
+
+ wcd938x_mbhc_hs_detect_exit(component);
+ wcd_mbhc_deinit(wcd_mbhc);
+}
+EXPORT_SYMBOL(wcd938x_mbhc_ssr_down);
+
+/*
* wcd938x_mbhc_post_ssr_init: initialize mbhc for
* wcd938x post subsystem restart
* @mbhc: poniter to wcd938x_mbhc structure
@@ -979,7 +1004,6 @@
return -EINVAL;
}
- wcd_mbhc_deinit(wcd_mbhc);
ret = wcd_mbhc_init(wcd_mbhc, component, &mbhc_cb, &intr_ids,
wcd_mbhc_registers, WCD938X_ZDET_SUPPORTED);
if (ret) {
diff --git a/asoc/codecs/wcd938x/wcd938x-mbhc.h b/asoc/codecs/wcd938x/wcd938x-mbhc.h
index cf4c60e..e33a92c 100644
--- a/asoc/codecs/wcd938x/wcd938x-mbhc.h
+++ b/asoc/codecs/wcd938x/wcd938x-mbhc.h
@@ -1,6 +1,6 @@
/* 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 __WCD938X_MBHC_H__
#define __WCD938X_MBHC_H__
@@ -20,6 +20,8 @@
extern int wcd938x_mbhc_hs_detect(struct snd_soc_component *component,
struct wcd_mbhc_config *mbhc_cfg);
extern void wcd938x_mbhc_deinit(struct snd_soc_component *component);
+extern void wcd938x_mbhc_ssr_down(struct wcd938x_mbhc *mbhc,
+ struct snd_soc_component *component);
extern int wcd938x_mbhc_post_ssr_init(struct wcd938x_mbhc *mbhc,
struct snd_soc_component *component);
extern int wcd938x_mbhc_get_impedance(struct wcd938x_mbhc *wcd938x_mbhc,
@@ -43,6 +45,10 @@
static inline void wcd938x_mbhc_deinit(struct snd_soc_component *component)
{
}
+static inline void wcd938x_mbhc_ssr_down(struct wcd938x_mbhc *mbhc,
+ struct snd_soc_component *component)
+{
+}
static inline int wcd938x_mbhc_post_ssr_init(struct wcd938x_mbhc *mbhc,
struct snd_soc_component *component)
{
diff --git a/asoc/codecs/wcd938x/wcd938x.c b/asoc/codecs/wcd938x/wcd938x.c
index 8ab4a7c..96d9b98 100644
--- a/asoc/codecs/wcd938x/wcd938x.c
+++ b/asoc/codecs/wcd938x/wcd938x.c
@@ -1355,6 +1355,13 @@
__func__, micb_index);
return -EINVAL;
}
+
+ if (NULL == wcd938x) {
+ dev_err(component->dev,
+ "%s: wcd938x private data is NULL\n", __func__);
+ return -EINVAL;
+ }
+
switch (micb_num) {
case MIC_BIAS_1:
micb_reg = WCD938X_ANA_MICB1;
@@ -1524,6 +1531,8 @@
0x80, 0x00);
break;
case BOLERO_WCD_EVT_SSR_DOWN:
+ mbhc = &wcd938x->mbhc->wcd_mbhc;
+ wcd938x_mbhc_ssr_down(wcd938x->mbhc, component);
wcd938x_reset_low(wcd938x->dev);
break;
case BOLERO_WCD_EVT_SSR_UP:
diff --git a/asoc/kona.c b/asoc/kona.c
index 704951c..9508b95 100644
--- a/asoc/kona.c
+++ b/asoc/kona.c
@@ -140,6 +140,10 @@
SLIM_TX_MAX,
};
+enum {
+ AFE_LOOPBACK_TX_IDX = 0,
+ AFE_LOOPBACK_TX_IDX_MAX,
+};
struct msm_asoc_mach_data {
struct snd_info_entry *codec_root;
int usbc_en2_gpio; /* used by gpio driver API */
@@ -370,6 +374,10 @@
[VA_CDC_DMA_TX_2] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 8},
};
+static struct dev_config afe_loopback_tx_cfg[] = {
+ [AFE_LOOPBACK_TX_IDX] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+};
+
static char const *bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE",
"S32_LE"};
static char const *ch_text[] = {"Two", "Three", "Four", "Five",
@@ -420,6 +428,7 @@
static char const *bt_sample_rate_tx_text[] = {"KHZ_8", "KHZ_16",
"KHZ_44P1", "KHZ_48",
"KHZ_88P2", "KHZ_96"};
+static const char *const afe_loopback_tx_ch_text[] = {"One", "Two"};
static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_sample_rate, usb_sample_rate_text);
static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_sample_rate, usb_sample_rate_text);
@@ -526,6 +535,7 @@
static SOC_ENUM_SINGLE_EXT_DECL(bt_sample_rate, bt_sample_rate_text);
static SOC_ENUM_SINGLE_EXT_DECL(bt_sample_rate_rx, bt_sample_rate_rx_text);
static SOC_ENUM_SINGLE_EXT_DECL(bt_sample_rate_tx, bt_sample_rate_tx_text);
+static SOC_ENUM_SINGLE_EXT_DECL(afe_loopback_tx_chs, afe_loopback_tx_ch_text);
static bool is_initial_boot;
static bool codec_reg_done;
@@ -808,6 +818,27 @@
usb_tx_cfg.sample_rate);
return 0;
}
+static int afe_loopback_tx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: afe_loopback_tx_ch = %d\n", __func__,
+ afe_loopback_tx_cfg[0].channels);
+ ucontrol->value.enumerated.item[0] =
+ afe_loopback_tx_cfg[0].channels - 1;
+
+ return 0;
+}
+
+static int afe_loopback_tx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ afe_loopback_tx_cfg[0].channels =
+ ucontrol->value.enumerated.item[0] + 1;
+ pr_debug("%s: afe_loopback_tx_ch = %d\n", __func__,
+ afe_loopback_tx_cfg[0].channels);
+
+ return 1;
+}
static int usb_audio_rx_format_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -3299,6 +3330,8 @@
SOC_ENUM_EXT("BT SampleRate TX", bt_sample_rate_tx,
msm_bt_sample_rate_tx_get,
msm_bt_sample_rate_tx_put),
+ SOC_ENUM_EXT("AFE_LOOPBACK_TX Channels", afe_loopback_tx_chs,
+ afe_loopback_tx_ch_get, afe_loopback_tx_ch_put),
};
static const struct snd_kcontrol_new msm_snd_controls[] = {
@@ -3339,7 +3372,7 @@
SNDRV_PCM_HW_PARAM_RATE);
struct snd_interval *channels = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS);
- int idx, rc = 0;
+ int idx = 0, rc = 0;
pr_debug("%s: format = %d, rate = %d\n",
__func__, params_format(params), params_rate(params));
@@ -3578,6 +3611,14 @@
slim_tx_cfg[SLIM_TX_7].channels;
break;
+ case MSM_BACKEND_DAI_AFE_LOOPBACK_TX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ afe_loopback_tx_cfg[idx].bit_format);
+ rate->min = rate->max = afe_loopback_tx_cfg[idx].sample_rate;
+ channels->min = channels->max =
+ afe_loopback_tx_cfg[idx].channels;
+ break;
+
default:
rate->min = rate->max = SAMPLING_RATE_48KHZ;
break;
@@ -5475,6 +5516,23 @@
},
};
+static struct snd_soc_dai_link msm_afe_rxtx_lb_be_dai_link[] = {
+ {
+ .name = LPASS_BE_AFE_LOOPBACK_TX,
+ .stream_name = "AFE Loopback Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.24577",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .id = MSM_BACKEND_DAI_AFE_LOOPBACK_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+};
+
static struct snd_soc_dai_link msm_kona_dai_links[
ARRAY_SIZE(msm_common_dai_links) +
ARRAY_SIZE(msm_bolero_fe_dai_links) +
@@ -5486,7 +5544,8 @@
ARRAY_SIZE(msm_rx_tx_cdc_dma_be_dai_links) +
ARRAY_SIZE(msm_va_cdc_dma_be_dai_links) +
ARRAY_SIZE(ext_disp_be_dai_link) +
- ARRAY_SIZE(msm_wcn_be_dai_links)];
+ ARRAY_SIZE(msm_wcn_be_dai_links) +
+ ARRAY_SIZE(msm_afe_rxtx_lb_be_dai_link)];
static int msm_populate_dai_link_component_of_node(
struct snd_soc_card *card)
@@ -5792,6 +5851,15 @@
total_links += ARRAY_SIZE(msm_wcn_be_dai_links);
}
+ rc = of_property_read_u32(dev->of_node, "qcom,afe-rxtx-lb",
+ &val);
+ if (!rc && val) {
+ memcpy(msm_kona_dai_links + total_links,
+ msm_afe_rxtx_lb_be_dai_link,
+ sizeof(msm_afe_rxtx_lb_be_dai_link));
+ total_links +=
+ ARRAY_SIZE(msm_afe_rxtx_lb_be_dai_link);
+ }
dailink = msm_kona_dai_links;
} else if(!strcmp(match->data, "stub_codec")) {
card = &snd_soc_card_stub_msm;
diff --git a/dsp/q6adm.c b/dsp/q6adm.c
index f081065..8848b22 100644
--- a/dsp/q6adm.c
+++ b/dsp/q6adm.c
@@ -1510,7 +1510,7 @@
}
adm_callback_debug_print(data);
- if (data->payload_size) {
+ if (data->payload_size >= sizeof(uint32_t)) {
copp_idx = (data->token) & 0XFF;
port_idx = ((data->token) >> 16) & 0xFF;
client_id = ((data->token) >> 8) & 0xFF;
@@ -1530,13 +1530,20 @@
return 0;
}
if (data->opcode == APR_BASIC_RSP_RESULT) {
- if (data->payload_size < (2 * sizeof(uint32_t))) {
- pr_err("%s: Invalid payload size %d\n", __func__,
- data->payload_size);
- return 0;
- }
pr_debug("%s: APR_BASIC_RSP_RESULT id 0x%x\n",
__func__, payload[0]);
+
+ if (!((client_id != ADM_CLIENT_ID_SOURCE_TRACKING) &&
+ ((payload[0] == ADM_CMD_SET_PP_PARAMS_V5) ||
+ (payload[0] == ADM_CMD_SET_PP_PARAMS_V6)))) {
+ if (data->payload_size <
+ (2 * sizeof(uint32_t))) {
+ pr_err("%s: Invalid payload size %d\n",
+ __func__, data->payload_size);
+ return 0;
+ }
+ }
+
if (payload[1] != 0) {
pr_err("%s: cmd = 0x%x returned error = 0x%x\n",
__func__, payload[0], payload[1]);
@@ -1718,21 +1725,28 @@
case ADM_CMDRSP_GET_PP_TOPO_MODULE_LIST_V2:
pr_debug("%s: ADM_CMDRSP_GET_PP_TOPO_MODULE_LIST\n",
__func__);
- num_modules = payload[1];
- pr_debug("%s: Num modules %d\n", __func__, num_modules);
- if (payload[0]) {
- pr_err("%s: ADM_CMDRSP_GET_PP_TOPO_MODULE_LIST, error = %d\n",
- __func__, payload[0]);
- } else if (num_modules > MAX_MODULES_IN_TOPO) {
- pr_err("%s: ADM_CMDRSP_GET_PP_TOPO_MODULE_LIST invalid num modules received, num modules = %d\n",
- __func__, num_modules);
+ if (data->payload_size >= (2 * sizeof(uint32_t))) {
+ num_modules = payload[1];
+ pr_debug("%s: Num modules %d\n", __func__,
+ num_modules);
+ if (payload[0]) {
+ pr_err("%s: ADM_CMDRSP_GET_PP_TOPO_MODULE_LIST, error = %d\n",
+ __func__, payload[0]);
+ } else if (num_modules > MAX_MODULES_IN_TOPO) {
+ pr_err("%s: ADM_CMDRSP_GET_PP_TOPO_MODULE_LIST invalid num modules received, num modules = %d\n",
+ __func__, num_modules);
+ } else {
+ ret = adm_process_get_topo_list_response(
+ data->opcode, copp_idx,
+ num_modules, payload,
+ data->payload_size);
+ if (ret)
+ pr_err("%s: Failed to process get topo modules list response, error %d\n",
+ __func__, ret);
+ }
} else {
- ret = adm_process_get_topo_list_response(
- data->opcode, copp_idx, num_modules,
- payload, data->payload_size);
- if (ret)
- pr_err("%s: Failed to process get topo modules list response, error %d\n",
- __func__, ret);
+ pr_err("%s: Invalid payload size %d\n",
+ __func__, data->payload_size);
}
atomic_set(&this_adm.copp.stat[port_idx][copp_idx],
payload[0]);
diff --git a/dsp/q6afe.c b/dsp/q6afe.c
index fd66571..0002d82 100644
--- a/dsp/q6afe.c
+++ b/dsp/q6afe.c
@@ -400,6 +400,11 @@
/* 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;
@@ -408,7 +413,17 @@
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;
@@ -597,6 +612,7 @@
data->opcode == AFE_PORT_CMDRSP_GET_PARAM_V3) {
uint32_t *payload = data->payload;
uint32_t param_id;
+ uint32_t param_id_pos = 0;
if (!payload || (data->token >= AFE_MAX_PORTS)) {
pr_err("%s: Error: size %d payload %pK token %d\n",
@@ -605,9 +621,23 @@
return -EINVAL;
}
- param_id = (data->opcode == AFE_PORT_CMDRSP_GET_PARAM_V3) ?
- payload[3] :
- payload[2];
+ if (rtac_make_afe_callback(data->payload,
+ data->payload_size))
+ return 0;
+
+ if (data->opcode == AFE_PORT_CMDRSP_GET_PARAM_V3)
+ param_id_pos = 4;
+ else
+ param_id_pos = 3;
+
+ if (data->payload_size >= param_id_pos * sizeof(uint32_t))
+ param_id = payload[param_id_pos - 1];
+ else {
+ pr_err("%s: Error: size %d is less than expected\n",
+ __func__, data->payload_size);
+ return -EINVAL;
+ }
+
if (param_id == AUDPROC_PARAM_ID_FFV_DOA_TRACKING_MONITOR) {
doa_tracking_mon_afe_cb_handler(data->opcode,
data->payload, data->payload_size);
@@ -615,10 +645,6 @@
av_dev_drift_afe_cb_handler(data->opcode, data->payload,
data->payload_size);
} else {
- if (rtac_make_afe_callback(data->payload,
- data->payload_size))
- return 0;
-
if (sp_make_afe_callback(data->opcode, data->payload,
data->payload_size))
return -EINVAL;
@@ -645,6 +671,11 @@
payload = data->payload;
if (data->opcode == APR_BASIC_RSP_RESULT) {
+ if (data->payload_size < (2 * sizeof(uint32_t))) {
+ pr_err("%s: Error: size %d is less than expected\n",
+ __func__, data->payload_size);
+ return -EINVAL;
+ }
pr_debug("%s:opcode = 0x%x cmd = 0x%x status = 0x%x token=%d\n",
__func__, data->opcode,
payload[0], payload[1], data->token);
diff --git a/dsp/q6asm.c b/dsp/q6asm.c
index 6681dcb..b27163f 100644
--- a/dsp/q6asm.c
+++ b/dsp/q6asm.c
@@ -1952,8 +1952,8 @@
(data->opcode != ASM_DATA_EVENT_EOS) &&
(data->opcode != ASM_SESSION_EVENTX_OVERFLOW) &&
(data->opcode != ASM_SESSION_EVENT_RX_UNDERFLOW)) {
- if (payload == NULL || (data->payload_size < (2 * sizeof(uint32_t)))) {
- pr_err("%s: payload is null or invalid size[%d]\n", __func__, data->payload_size);
+ if (payload == NULL) {
+ pr_err("%s: payload is null\n", __func__);
spin_unlock_irqrestore(
&(session[session_id].session_lock), flags);
return -EINVAL;
diff --git a/dsp/q6core.c b/dsp/q6core.c
index 283f785..3f15f10 100644
--- a/dsp/q6core.c
+++ b/dsp/q6core.c
@@ -194,7 +194,7 @@
}
EXPORT_SYMBOL(q6core_send_uevent);
-static int parse_fwk_version_info(uint32_t *payload)
+static int parse_fwk_version_info(uint32_t *payload, uint16_t payload_size)
{
size_t ver_size;
int num_services;
@@ -207,6 +207,11 @@
* Based on this info, we copy the payload into core
* avcs version info structure.
*/
+ if (payload_size < 5 * sizeof(uint32_t)) {
+ pr_err("%s: payload has invalid size %d\n",
+ __func__, payload_size);
+ return -EINVAL;
+ }
num_services = payload[4];
if (num_services > VSS_MAX_AVCS_NUM_SERVICES) {
pr_err("%s: num_services: %d greater than max services: %d\n",
@@ -221,6 +226,12 @@
ver_size = sizeof(struct avcs_get_fwk_version) +
num_services * sizeof(struct avs_svc_api_info);
+ if (payload_size < ver_size) {
+ pr_err("%s: payload has invalid size %d, expected size %zu\n",
+ __func__, payload_size, ver_size);
+ return -EINVAL;
+ }
+
q6core_lcl.q6core_avcs_ver_info.ver_info =
kzalloc(ver_size, GFP_ATOMIC);
if (q6core_lcl.q6core_avcs_ver_info.ver_info == NULL)
@@ -257,6 +268,12 @@
payload1 = data->payload;
+ if (data->payload_size < 2 * sizeof(uint32_t)) {
+ pr_err("%s: payload has invalid size %d\n",
+ __func__, data->payload_size);
+ return -EINVAL;
+ }
+
switch (payload1[0]) {
case AVCS_CMD_SHARED_MEM_UNMAP_REGIONS:
@@ -347,6 +364,11 @@
break;
}
case AVCS_CMDRSP_SHARED_MEM_MAP_REGIONS:
+ if (data->payload_size < sizeof(uint32_t)) {
+ pr_err("%s: payload has invalid size %d\n",
+ __func__, data->payload_size);
+ return -EINVAL;
+ }
payload1 = data->payload;
pr_debug("%s: AVCS_CMDRSP_SHARED_MEM_MAP_REGIONS handle %d\n",
__func__, payload1[0]);
@@ -361,6 +383,11 @@
}
break;
case AVCS_CMDRSP_CREATE_LPASS_NPA_CLIENT:
+ if (data->payload_size < 2 * sizeof(uint32_t)) {
+ pr_err("%s: payload has invalid size %d\n",
+ __func__, data->payload_size);
+ return -EINVAL;
+ }
payload1 = data->payload;
pr_debug("%s: AVCS_CMDRSP_CREATE_LPASS_NPA_CLIENT handle %d\n",
__func__, payload1[1]);
@@ -370,6 +397,11 @@
wake_up(&q6core_lcl.lpass_npa_rsc_wait);
break;
case AVCS_CMDRSP_ADSP_EVENT_GET_STATE:
+ if (data->payload_size < sizeof(uint32_t)) {
+ pr_err("%s: payload has invalid size %d\n",
+ __func__, data->payload_size);
+ return -EINVAL;
+ }
payload1 = data->payload;
q6core_lcl.param = payload1[0];
pr_debug("%s: Received ADSP get state response 0x%x\n",
@@ -380,6 +412,11 @@
wake_up(&q6core_lcl.bus_bw_req_wait);
break;
case AVCS_CMDRSP_GET_LICENSE_VALIDATION_RESULT:
+ if (data->payload_size < sizeof(uint32_t)) {
+ pr_err("%s: payload has invalid size %d\n",
+ __func__, data->payload_size);
+ return -EINVAL;
+ }
payload1 = data->payload;
pr_debug("%s: cmd = LICENSE_VALIDATION_RESULT, result = 0x%x\n",
__func__, payload1[0]);
@@ -392,7 +429,7 @@
pr_debug("%s: Received AVCS_CMDRSP_GET_FWK_VERSION\n",
__func__);
payload1 = data->payload;
- ret = parse_fwk_version_info(payload1);
+ ret = parse_fwk_version_info(payload1, data->payload_size);
if (ret < 0) {
q6core_lcl.adsp_status = ret;
pr_err("%s: Failed to parse payload:%d\n",
diff --git a/dsp/voice_mhi.c b/dsp/voice_mhi.c
index 6c8a7fc..87572ef 100644
--- a/dsp/voice_mhi.c
+++ b/dsp/voice_mhi.c
@@ -426,7 +426,7 @@
static void voice_mhi_pcie_down_callback(struct mhi_device *voice_mhi_dev)
{
dma_addr_t iova;
- struct device *md;
+ struct device *md = NULL;
mutex_lock(&voice_mhi_lcl.mutex);
diff --git a/soc/swr-mstr-ctrl.c b/soc/swr-mstr-ctrl.c
index 26965a3..bddf30a 100644
--- a/soc/swr-mstr-ctrl.c
+++ b/soc/swr-mstr-ctrl.c
@@ -2060,6 +2060,7 @@
swrm->slave_status = 0;
swrm->num_rx_chs = 0;
swrm->clk_ref_count = 0;
+ swrm->swr_irq_wakeup_capable = 0;
swrm->mclk_freq = MCLK_FREQ;
swrm->dev_up = true;
swrm->state = SWR_MSTR_UP;
@@ -2112,7 +2113,15 @@
}
}
-
+ /* Make inband tx interrupts as wakeup capable for slave irq */
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "qcom,swr-mstr-irq-wakeup-capable",
+ &swrm->swr_irq_wakeup_capable);
+ if (ret)
+ dev_dbg(swrm->dev, "%s: swrm irq wakeup capable not defined\n",
+ __func__);
+ if (swrm->swr_irq_wakeup_capable)
+ irq_set_irq_wake(swrm->irq, 1);
ret = swr_register_master(&swrm->master);
if (ret) {
dev_err(&pdev->dev, "%s: error adding swr master\n", __func__);
@@ -2168,6 +2177,13 @@
(void *) "swrm_reg_dump",
&swrm_debug_ops);
}
+
+ ret = device_init_wakeup(swrm->dev, true);
+ if (ret) {
+ dev_err(swrm->dev, "Device wakeup init failed: %d\n", ret);
+ goto err_irq_wakeup_fail;
+ }
+
pm_runtime_set_autosuspend_delay(&pdev->dev, auto_suspend_timer);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_active(&pdev->dev);
@@ -2179,6 +2195,8 @@
msm_aud_evt_register_client(&swrm->event_notifier);
return 0;
+err_irq_wakeup_fail:
+ device_init_wakeup(swrm->dev, false);
err_mstr_fail:
if (swrm->reg_irq)
swrm->reg_irq(swrm->handle, swr_mstr_interrupt,
@@ -2210,11 +2228,14 @@
free_irq(swrm->irq, swrm);
else if (swrm->wake_irq > 0)
free_irq(swrm->wake_irq, swrm);
+ if (swrm->swr_irq_wakeup_capable)
+ irq_set_irq_wake(swrm->irq, 0);
cancel_work_sync(&swrm->wakeup_work);
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
swr_unregister_master(&swrm->master);
msm_aud_evt_unregister_client(&swrm->event_notifier);
+ device_init_wakeup(swrm->dev, false);
mutex_destroy(&swrm->mlock);
mutex_destroy(&swrm->reslock);
mutex_destroy(&swrm->iolock);
diff --git a/soc/swr-mstr-ctrl.h b/soc/swr-mstr-ctrl.h
index 96aa048..4a48571 100644
--- a/soc/swr-mstr-ctrl.h
+++ b/soc/swr-mstr-ctrl.h
@@ -1,6 +1,6 @@
/* 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.
*/
#ifndef _SWR_WCD_CTRL_H
@@ -156,6 +156,7 @@
struct port_params **port_param;
struct clk *lpass_core_hw_vote;
u8 num_usecase;
+ u32 swr_irq_wakeup_capable;
};
#endif /* _SWR_WCD_CTRL_H */