Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5d45f4c8 authored by Vidyakumar Athota's avatar Vidyakumar Athota Committed by Gerrit - the friendly Code Review server
Browse files

asoc: codecs: bolero: add clk resource manager driver



Add Bolero clock resource manager driver to handle/manage
bolero clocks for all the concurrency usecases like record
+ voice activation.

Change-Id: I970a05d96fc9060b44bfe670d465f0b9d72cc53b
Signed-off-by: default avatarVidyakumar Athota <vathota@codeaurora.org>
parent b4c9798b
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -70,6 +70,7 @@ ifdef CONFIG_SND_SOC_BOLERO
	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
+171 −190
Original line number Diff line number Diff line
@@ -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 void bolero_ahb_read_device(char __iomem *io_base,
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);
		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);

	/* 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;
	}

	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_read(struct bolero_priv *priv,
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);
		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);
		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;
	}

	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);

	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 @@ static void bolero_cdc_notifier_call(struct bolero_priv *priv,
				     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 @@ struct device *bolero_get_device_ptr(struct device *dev, u16 macro_id)
}
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;
@@ -355,6 +388,69 @@ static int bolero_copy_dais_from_macro(struct bolero_priv *priv)
	return 0;
}

/**
 * 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
 *
@@ -374,7 +470,7 @@ int bolero_register_macro(struct device *dev, u16 macro_id,
		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 @@ int bolero_register_macro(struct device *dev, u16 macro_id,
		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 @@ void bolero_unregister_macro(struct device *dev, u16 macro_id)
		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 @@ void bolero_unregister_macro(struct device *dev, u16 macro_id)
	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 @@ void bolero_unregister_macro(struct device *dev, u16 macro_id)
}
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 @@ static int bolero_ssr_enable(struct device *dev, void *data)
		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 @@ static void bolero_ssr_disable(struct device *dev, void *data)
	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 @@ static struct platform_driver bolero_drv = {
	.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");
+16 −11
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_CDC_H
@@ -54,16 +54,20 @@ struct macro_ops {
	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_resume(struct device *dev);
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 @@ static inline struct device *bolero_get_device_ptr(struct device *dev,
	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)
+613 −0

File added.

Preview size limit exceeded, changes collapsed.

+42 −0
Original line number Diff line number Diff line
/* 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 */
Loading