Add 'qcom/opensource/audio-kernel/' from commit '0ee387dfadf349618494d6f82ec8cec796ebef70'
git-subtree-dir: qcom/opensource/audio-kernel git-subtree-mainline:99ab089c55
git-subtree-split:0ee387dfad
Change-Id: repo: https://git.codelinaro.org/clo/la/platform/vendor/qcom/opensource/audio-kernel-ar tag: AUDIO.LA.9.0.r1-07400-lanai.0
This commit is contained in:
183
qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/Kbuild
Normal file
183
qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/Kbuild
Normal file
@@ -0,0 +1,183 @@
|
||||
# We can build either as part of a standalone Kernel build or as
|
||||
# an external module. Determine which mechanism is being used
|
||||
ifeq ($(MODNAME),)
|
||||
KERNEL_BUILD := 1
|
||||
else
|
||||
KERNEL_BUILD := 0
|
||||
endif
|
||||
|
||||
|
||||
|
||||
ifeq ($(KERNEL_BUILD), 1)
|
||||
# These are configurable via Kconfig for kernel-based builds
|
||||
# Need to explicitly configure for Android-based builds
|
||||
AUDIO_BLD_DIR := $(shell pwd)/kernel/msm-5.4
|
||||
AUDIO_ROOT := $(AUDIO_BLD_DIR)/techpack/audio
|
||||
endif
|
||||
|
||||
ifeq ($(KERNEL_BUILD), 0)
|
||||
ifeq ($(CONFIG_ARCH_SM6150), y)
|
||||
include $(AUDIO_ROOT)/config/sm6150auto.conf
|
||||
export
|
||||
INCS += -include $(AUDIO_ROOT)/config/sm6150autoconf.h
|
||||
endif
|
||||
ifeq ($(CONFIG_ARCH_TRINKET), y)
|
||||
include $(AUDIO_ROOT)/config/sm6150auto.conf
|
||||
export
|
||||
INCS += -include $(AUDIO_ROOT)/config/sm6150autoconf.h
|
||||
endif
|
||||
ifeq ($(CONFIG_ARCH_KONA), y)
|
||||
include $(AUDIO_ROOT)/config/konaauto.conf
|
||||
INCS += -include $(AUDIO_ROOT)/config/konaautoconf.h
|
||||
endif
|
||||
ifeq ($(CONFIG_ARCH_WAIPIO), y)
|
||||
include $(AUDIO_ROOT)/config/waipioauto.conf
|
||||
INCS += -include $(AUDIO_ROOT)/config/waipioautoconf.h
|
||||
endif
|
||||
ifeq ($(CONFIG_ARCH_KALAMA), y)
|
||||
include $(AUDIO_ROOT)/config/kalamaauto.conf
|
||||
INCS += -include $(AUDIO_ROOT)/config/kalamaautoconf.h
|
||||
endif
|
||||
ifeq ($(CONFIG_ARCH_PINEAPPLE), y)
|
||||
include $(AUDIO_ROOT)/config/pineappleauto.conf
|
||||
INCS += -include $(AUDIO_ROOT)/config/pineappleautoconf.h
|
||||
endif
|
||||
ifeq ($(CONFIG_ARCH_PITTI), y)
|
||||
include $(AUDIO_ROOT)/config/pittiauto.conf
|
||||
INCS += -include $(AUDIO_ROOT)/config/pittiautoconf.h
|
||||
endif
|
||||
ifeq ($(CONFIG_ARCH_LITO), y)
|
||||
include $(AUDIO_ROOT)/config/litoauto.conf
|
||||
export
|
||||
INCS += -include $(AUDIO_ROOT)/config/litoautoconf.h
|
||||
endif
|
||||
ifeq ($(CONFIG_ARCH_BENGAL), y)
|
||||
include $(AUDIO_ROOT)/config/bengalauto.conf
|
||||
export
|
||||
INCS += -include $(AUDIO_ROOT)/config/bengalautoconf.h
|
||||
endif
|
||||
ifeq ($(CONFIG_ARCH_QCS405), y)
|
||||
include $(AUDIO_ROOT)/config/qcs405auto.conf
|
||||
export
|
||||
INCS += -include $(AUDIO_ROOT)/config/qcs405autoconf.h
|
||||
endif
|
||||
endif
|
||||
|
||||
# As per target team, build is done as follows:
|
||||
# Defconfig : build with default flags
|
||||
# Slub : defconfig + CONFIG_SLUB_DEBUG := y +
|
||||
# CONFIG_SLUB_DEBUG_ON := y + CONFIG_PAGE_POISONING := y
|
||||
# Perf : Using appropriate msmXXXX-perf_defconfig
|
||||
#
|
||||
# Shipment builds (user variants) should not have any debug feature
|
||||
# enabled. This is identified using 'TARGET_BUILD_VARIANT'. Slub builds
|
||||
# are identified using the CONFIG_SLUB_DEBUG_ON configuration. Since
|
||||
# there is no other way to identify defconfig builds, QTI internal
|
||||
# representation of perf builds (identified using the string 'perf'),
|
||||
# is used to identify if the build is a slub or defconfig one. This
|
||||
# way no critical debug feature will be enabled for perf and shipment
|
||||
# builds. Other OEMs are also protected using the TARGET_BUILD_VARIANT
|
||||
# config.
|
||||
|
||||
############ UAPI ############
|
||||
UAPI_DIR := uapi/audio
|
||||
UAPI_INC := -I$(AUDIO_ROOT)/include/$(UAPI_DIR)
|
||||
|
||||
############ COMMON ############
|
||||
COMMON_DIR := include
|
||||
COMMON_INC := -I$(AUDIO_ROOT)/$(COMMON_DIR)
|
||||
|
||||
############ LPASS_CDC ############
|
||||
|
||||
# for LPASS_CDC Codec
|
||||
ifdef CONFIG_SND_SOC_LPASS_CDC
|
||||
LPASS_CDC_OBJS += lpass-cdc.o
|
||||
LPASS_CDC_OBJS += lpass-cdc-comp.o
|
||||
LPASS_CDC_OBJS += lpass-cdc-utils.o
|
||||
LPASS_CDC_OBJS += lpass-cdc-regmap.o
|
||||
LPASS_CDC_OBJS += lpass-cdc-tables.o
|
||||
LPASS_CDC_OBJS += lpass-cdc-clk-rsc.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_LPASS_CDC_WSA2_MACRO
|
||||
WSA2_OBJS += lpass-cdc-wsa2-macro.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_LPASS_CDC_WSA_MACRO
|
||||
WSA_OBJS += lpass-cdc-wsa-macro.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_LPASS_CDC_VA_MACRO
|
||||
VA_OBJS += lpass-cdc-va-macro.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_LPASS_CDC_TX_MACRO
|
||||
TX_OBJS += lpass-cdc-tx-macro.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_LPASS_CDC_RX_MACRO
|
||||
RX_OBJS += lpass-cdc-rx-macro.o
|
||||
endif
|
||||
|
||||
LINUX_INC += -Iinclude/linux
|
||||
|
||||
INCS += $(COMMON_INC) \
|
||||
$(UAPI_INC)
|
||||
|
||||
EXTRA_CFLAGS += $(INCS)
|
||||
|
||||
|
||||
CDEFINES += -DANI_LITTLE_BYTE_ENDIAN \
|
||||
-DANI_LITTLE_BIT_ENDIAN \
|
||||
-DDOT11F_LITTLE_ENDIAN_HOST \
|
||||
-DANI_COMPILER_TYPE_GCC \
|
||||
-DANI_OS_TYPE_ANDROID=6 \
|
||||
-DPTT_SOCK_SVC_ENABLE \
|
||||
-Wall\
|
||||
-Werror\
|
||||
-D__linux__
|
||||
|
||||
KBUILD_CPPFLAGS += $(CDEFINES)
|
||||
|
||||
# Currently, for versions of gcc which support it, the kernel Makefile
|
||||
# is disabling the maybe-uninitialized warning. Re-enable it for the
|
||||
# AUDIO driver. Note that we must use EXTRA_CFLAGS here so that it
|
||||
# will override the kernel settings.
|
||||
ifeq ($(call cc-option-yn, -Wmaybe-uninitialized),y)
|
||||
EXTRA_CFLAGS += -Wmaybe-uninitialized
|
||||
endif
|
||||
#EXTRA_CFLAGS += -Wmissing-prototypes
|
||||
|
||||
ifeq ($(call cc-option-yn, -Wheader-guard),y)
|
||||
EXTRA_CFLAGS += -Wheader-guard
|
||||
endif
|
||||
|
||||
ifeq ($(KERNEL_BUILD), 0)
|
||||
KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/ipc/Module.symvers
|
||||
KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/dsp/Module.symvers
|
||||
KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/Module.symvers
|
||||
KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/codecs/Module.symvers
|
||||
KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/soc/Module.symvers
|
||||
endif
|
||||
|
||||
# Module information used by KBuild framework
|
||||
obj-$(CONFIG_SND_SOC_LPASS_CDC) += lpass_cdc_dlkm.o
|
||||
lpass_cdc_dlkm-y := $(LPASS_CDC_OBJS)
|
||||
|
||||
obj-$(CONFIG_LPASS_CDC_WSA2_MACRO) += lpass_cdc_wsa2_macro_dlkm.o
|
||||
lpass_cdc_wsa2_macro_dlkm-y := $(WSA2_OBJS)
|
||||
|
||||
obj-$(CONFIG_LPASS_CDC_WSA_MACRO) += lpass_cdc_wsa_macro_dlkm.o
|
||||
lpass_cdc_wsa_macro_dlkm-y := $(WSA_OBJS)
|
||||
|
||||
obj-$(CONFIG_LPASS_CDC_VA_MACRO) += lpass_cdc_va_macro_dlkm.o
|
||||
lpass_cdc_va_macro_dlkm-y := $(VA_OBJS)
|
||||
|
||||
obj-$(CONFIG_LPASS_CDC_TX_MACRO) += lpass_cdc_tx_macro_dlkm.o
|
||||
lpass_cdc_tx_macro_dlkm-y := $(TX_OBJS)
|
||||
|
||||
obj-$(CONFIG_LPASS_CDC_RX_MACRO) += lpass_cdc_rx_macro_dlkm.o
|
||||
lpass_cdc_rx_macro_dlkm-y := $(RX_OBJS)
|
||||
|
||||
# inject some build related information
|
||||
DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\"
|
@@ -0,0 +1,6 @@
|
||||
modules:
|
||||
$(MAKE) -C $(KERNEL_SRC) M=$(M) modules $(KBUILD_OPTIONS) VERBOSE=1
|
||||
modules_install:
|
||||
$(MAKE) M=$(M) -C $(KERNEL_SRC) modules_install
|
||||
clean:
|
||||
$(MAKE) -C $(KERNEL_SRC) M=$(M) clean
|
112
qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/internal.h
Normal file
112
qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/internal.h
Normal file
@@ -0,0 +1,112 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _LPASS_CDC_INTERNAL_H
|
||||
#define _LPASS_CDC_INTERNAL_H
|
||||
|
||||
#include "lpass-cdc-registers.h"
|
||||
|
||||
#define LPASS_CDC_CHILD_DEVICES_MAX 6
|
||||
|
||||
/* from lpass_cdc to WCD events */
|
||||
enum {
|
||||
LPASS_CDC_WCD_EVT_TX_CH_HOLD_CLEAR = 1,
|
||||
LPASS_CDC_WCD_EVT_PA_OFF_PRE_SSR,
|
||||
LPASS_CDC_WCD_EVT_SSR_DOWN,
|
||||
LPASS_CDC_WCD_EVT_SSR_UP,
|
||||
LPASS_CDC_WCD_EVT_PA_ON_POST_FSCLK,
|
||||
LPASS_CDC_WCD_EVT_PA_ON_POST_FSCLK_ADIE_LB,
|
||||
LPASS_CDC_WCD_EVT_CLK_NOTIFY,
|
||||
};
|
||||
|
||||
enum {
|
||||
REG_NO_ACCESS,
|
||||
RD_REG,
|
||||
WR_REG,
|
||||
RD_WR_REG
|
||||
};
|
||||
|
||||
/* from WCD to lpass_cdc events */
|
||||
enum {
|
||||
WCD_LPASS_CDC_EVT_RX_MUTE = 1, /* for RX mute/unmute */
|
||||
WCD_LPASS_CDC_EVT_IMPED_TRUE, /* for imped true */
|
||||
WCD_LPASS_CDC_EVT_IMPED_FALSE, /* for imped false */
|
||||
WCD_LPASS_CDC_EVT_RX_COMPANDER_SOFT_RST,
|
||||
WCD_LPASS_CDC_EVT_BCS_CLK_OFF,
|
||||
WCD_LPASS_CDC_EVT_RX_PA_GAIN_UPDATE,
|
||||
WCD_LPASS_CDC_EVT_HPHL_HD2_ENABLE, /* to enable hd2 config for hphl */
|
||||
WCD_LPASS_CDC_EVT_HPHR_HD2_ENABLE, /* to enable hd2 config for hphr */
|
||||
};
|
||||
|
||||
struct wcd_ctrl_platform_data {
|
||||
void *handle;
|
||||
int (*update_wcd_event)(void *handle, u16 event, u32 data);
|
||||
int (*register_notifier)(void *handle,
|
||||
struct notifier_block *nblock,
|
||||
bool enable);
|
||||
};
|
||||
|
||||
struct lpass_cdc_priv {
|
||||
struct device *dev;
|
||||
struct snd_soc_component *component;
|
||||
struct regmap *regmap;
|
||||
struct mutex macro_lock;
|
||||
struct mutex io_lock;
|
||||
struct mutex clk_lock;
|
||||
struct mutex vote_lock;
|
||||
bool va_without_decimation;
|
||||
bool macros_supported[MAX_MACRO];
|
||||
bool dev_up;
|
||||
bool pre_dev_up;
|
||||
bool initial_boot;
|
||||
struct macro_ops macro_params[MAX_MACRO];
|
||||
struct snd_soc_dai_driver *lpass_cdc_dais;
|
||||
u16 num_dais;
|
||||
u16 num_macros_registered;
|
||||
u16 num_macros;
|
||||
u16 current_mclk_mux_macro[MAX_MACRO];
|
||||
struct work_struct lpass_cdc_add_child_devices_work;
|
||||
u32 version;
|
||||
struct clk *lpass_core_hw_vote;
|
||||
struct clk *lpass_audio_hw_vote;
|
||||
int core_hw_vote_count;
|
||||
int core_audio_vote_count;
|
||||
int core_clk_vote_count;
|
||||
|
||||
/* Entry for version info */
|
||||
struct snd_info_entry *entry;
|
||||
struct snd_info_entry *version_entry;
|
||||
|
||||
int (*read_dev)(struct lpass_cdc_priv *priv,
|
||||
u16 macro_id, u16 reg, u8 *val);
|
||||
int (*write_dev)(struct lpass_cdc_priv *priv,
|
||||
u16 macro_id, u16 reg, u8 val);
|
||||
struct platform_device *pdev_child_devices
|
||||
[LPASS_CDC_CHILD_DEVICES_MAX];
|
||||
u16 child_count;
|
||||
struct wcd_ctrl_platform_data plat_data;
|
||||
struct device *wcd_dev;
|
||||
struct blocking_notifier_head notifier;
|
||||
struct device *clk_dev;
|
||||
rsc_clk_cb_t rsc_clk_cb;
|
||||
s32 dmic_0_1_clk_cnt;
|
||||
s32 dmic_2_3_clk_cnt;
|
||||
s32 dmic_4_5_clk_cnt;
|
||||
s32 dmic_6_7_clk_cnt;
|
||||
u8 dmic_0_1_clk_div;
|
||||
u8 dmic_2_3_clk_div;
|
||||
u8 dmic_4_5_clk_div;
|
||||
u8 dmic_6_7_clk_div;
|
||||
};
|
||||
|
||||
struct regmap *lpass_cdc_regmap_init(struct device *dev,
|
||||
const struct regmap_config *config);
|
||||
int lpass_cdc_get_macro_id(bool va_no_dec_flag, u16 reg);
|
||||
|
||||
extern const struct regmap_config lpass_cdc_regmap_config;
|
||||
extern u8 *lpass_cdc_reg_access[MAX_MACRO];
|
||||
extern const u16 macro_id_base_offset[MAX_MACRO];
|
||||
|
||||
#endif
|
@@ -0,0 +1,785 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2019-2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. 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 <linux/clk-provider.h>
|
||||
#include "lpass-cdc.h"
|
||||
#include "lpass-cdc-clk-rsc.h"
|
||||
|
||||
#define DRV_NAME "lpass-cdc-clk-rsc"
|
||||
#define LPASS_CDC_CLK_NAME_LENGTH 30
|
||||
#define NPL_CLK_OFFSET (TX_NPL_CLK - TX_CORE_CLK)
|
||||
|
||||
static char clk_src_name[MAX_CLK][LPASS_CDC_CLK_NAME_LENGTH] = {
|
||||
"tx_core_clk",
|
||||
"rx_core_clk",
|
||||
"wsa_core_clk",
|
||||
"va_core_clk",
|
||||
"wsa2_core_clk",
|
||||
"rx_tx_core_clk",
|
||||
"wsa_tx_core_clk",
|
||||
"wsa2_tx_core_clk",
|
||||
"tx_npl_clk",
|
||||
"rx_npl_clk",
|
||||
"wsa_npl_clk",
|
||||
"va_npl_clk",
|
||||
};
|
||||
|
||||
struct lpass_cdc_clk_rsc {
|
||||
struct device *dev;
|
||||
struct mutex rsc_clk_lock;
|
||||
struct mutex fs_gen_lock;
|
||||
struct clk *clk[MAX_CLK];
|
||||
int clk_cnt[MAX_CLK];
|
||||
int reg_seq_en_cnt;
|
||||
int va_tx_clk_cnt;
|
||||
bool dev_up;
|
||||
bool dev_up_gfmux;
|
||||
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 lpass_cdc_clk_rsc_cb(struct device *dev, u16 event)
|
||||
{
|
||||
struct lpass_cdc_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 == LPASS_CDC_MACRO_EVT_SSR_UP) {
|
||||
priv->dev_up = true;
|
||||
} else if (event == LPASS_CDC_MACRO_EVT_SSR_DOWN) {
|
||||
priv->dev_up = false;
|
||||
priv->dev_up_gfmux = false;
|
||||
} else if (event == LPASS_CDC_MACRO_EVT_SSR_GFMUX_UP) {
|
||||
priv->dev_up_gfmux = true;
|
||||
}
|
||||
mutex_unlock(&priv->rsc_clk_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char __iomem *lpass_cdc_clk_rsc_get_clk_muxsel(struct lpass_cdc_clk_rsc *priv,
|
||||
int clk_id)
|
||||
{
|
||||
switch (clk_id) {
|
||||
case RX_CORE_CLK:
|
||||
return priv->rx_clk_muxsel;
|
||||
case WSA_CORE_CLK:
|
||||
case WSA2_CORE_CLK:
|
||||
return priv->wsa_clk_muxsel;
|
||||
case VA_CORE_CLK:
|
||||
return priv->va_clk_muxsel;
|
||||
case TX_CORE_CLK:
|
||||
case RX_TX_CORE_CLK:
|
||||
case WSA_TX_CORE_CLK:
|
||||
case WSA2_TX_CORE_CLK:
|
||||
default:
|
||||
dev_err_ratelimited(priv->dev, "%s: Invalid case\n", __func__);
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int lpass_cdc_rsc_clk_reset(struct device *dev, int clk_id)
|
||||
{
|
||||
struct device *clk_dev = NULL;
|
||||
struct lpass_cdc_clk_rsc *priv = NULL;
|
||||
int count = 0;
|
||||
|
||||
if (!dev) {
|
||||
pr_err("%s: dev is null\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BOLERO_VER_2P1
|
||||
if (clk_id < 0 || clk_id >= MAX_CLK - NPL_CLK_OFFSET) {
|
||||
#else
|
||||
if (clk_id < 0 || clk_id >= MAX_CLK) {
|
||||
#endif
|
||||
pr_err("%s: Invalid clk_id: %d\n",
|
||||
__func__, clk_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
clk_dev = lpass_cdc_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);
|
||||
while (__clk_is_enabled(priv->clk[clk_id])) {
|
||||
#ifdef CONFIG_BOLERO_VER_2P1
|
||||
clk_disable_unprepare(priv->clk[clk_id + NPL_CLK_OFFSET]);
|
||||
#endif
|
||||
clk_disable_unprepare(priv->clk[clk_id]);
|
||||
count++;
|
||||
}
|
||||
dev_dbg(priv->dev,
|
||||
"%s: clock reset after ssr, count %d\n", __func__, count);
|
||||
|
||||
while (count--) {
|
||||
clk_prepare_enable(priv->clk[clk_id]);
|
||||
#ifdef CONFIG_BOLERO_VER_2P1
|
||||
clk_prepare_enable(priv->clk[clk_id + NPL_CLK_OFFSET]);
|
||||
#endif
|
||||
}
|
||||
mutex_unlock(&priv->rsc_clk_lock);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(lpass_cdc_rsc_clk_reset);
|
||||
|
||||
void lpass_cdc_clk_rsc_enable_all_clocks(struct device *dev, bool enable)
|
||||
{
|
||||
struct device *clk_dev = NULL;
|
||||
struct lpass_cdc_clk_rsc *priv = NULL;
|
||||
int i = 0;
|
||||
|
||||
if (!dev) {
|
||||
pr_err("%s: dev is null\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
clk_dev = lpass_cdc_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 private data\n", __func__);
|
||||
return;
|
||||
}
|
||||
mutex_lock(&priv->rsc_clk_lock);
|
||||
#ifdef CONFIG_BOLERO_VER_2P1
|
||||
for (i = 0; i < MAX_CLK - NPL_CLK_OFFSET; i++) {
|
||||
#else
|
||||
for (i = 0; i < MAX_CLK; i++) {
|
||||
#endif
|
||||
if (enable) {
|
||||
if (priv->clk[i])
|
||||
clk_prepare_enable(priv->clk[i]);
|
||||
#ifdef CONFIG_BOLERO_VER_2P1
|
||||
if (priv->clk[i + NPL_CLK_OFFSET])
|
||||
clk_prepare_enable(
|
||||
priv->clk[i + NPL_CLK_OFFSET]);
|
||||
#endif
|
||||
} else {
|
||||
#ifdef CONFIG_BOLERO_VER_2P1
|
||||
if (priv->clk[i + NPL_CLK_OFFSET] &&
|
||||
__clk_is_enabled(priv->clk[i + NPL_CLK_OFFSET]))
|
||||
clk_disable_unprepare(
|
||||
priv->clk[i + NPL_CLK_OFFSET]);
|
||||
#endif
|
||||
if (priv->clk[i] && __clk_is_enabled(priv->clk[i]))
|
||||
clk_disable_unprepare(priv->clk[i]);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&priv->rsc_clk_lock);
|
||||
return;
|
||||
}
|
||||
EXPORT_SYMBOL(lpass_cdc_clk_rsc_enable_all_clocks);
|
||||
|
||||
static int lpass_cdc_clk_rsc_mux0_clk_request(struct lpass_cdc_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;
|
||||
}
|
||||
#ifdef CONFIG_BOLERO_VER_2P1
|
||||
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;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
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) {
|
||||
#ifdef CONFIG_BOLERO_VER_2P1
|
||||
if (priv->clk[clk_id + NPL_CLK_OFFSET])
|
||||
clk_disable_unprepare(
|
||||
priv->clk[clk_id + NPL_CLK_OFFSET]);
|
||||
#endif
|
||||
clk_disable_unprepare(priv->clk[clk_id]);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
#ifdef CONFIG_BOLERO_VER_2P1
|
||||
err:
|
||||
clk_disable_unprepare(priv->clk[clk_id]);
|
||||
#endif
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int lpass_cdc_clk_rsc_mux1_clk_request(struct lpass_cdc_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];
|
||||
u32 muxsel = 0;
|
||||
|
||||
clk_muxsel = lpass_cdc_clk_rsc_get_clk_muxsel(priv, clk_id);
|
||||
if (!clk_muxsel) {
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (enable) {
|
||||
if (priv->clk_cnt[clk_id] == 0) {
|
||||
if (clk_id != VA_CORE_CLK) {
|
||||
ret = lpass_cdc_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;
|
||||
}
|
||||
#ifdef CONFIG_BOLERO_VER_2P1
|
||||
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;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* Temp SW workaround to address a glitch issue of
|
||||
* VA GFMux instance responsible for switching from
|
||||
* TX MCLK to VA MCLK. This configuration would be taken
|
||||
* care in DSP itself
|
||||
*/
|
||||
if (clk_id != VA_CORE_CLK) {
|
||||
if (priv->dev_up_gfmux) {
|
||||
iowrite32(0x1, clk_muxsel);
|
||||
muxsel = ioread32(clk_muxsel);
|
||||
}
|
||||
lpass_cdc_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) {
|
||||
/*
|
||||
* Temp SW workaround to address a glitch issue
|
||||
* of VA GFMux instance responsible for
|
||||
* switching from TX MCLK to VA MCLK.
|
||||
* This configuration would be taken
|
||||
* care in DSP itself.
|
||||
*/
|
||||
if (clk_id != VA_CORE_CLK) {
|
||||
ret = lpass_cdc_clk_rsc_mux0_clk_request(priv,
|
||||
default_clk_id, true);
|
||||
if (!ret && priv->dev_up_gfmux) {
|
||||
iowrite32(0x0, clk_muxsel);
|
||||
muxsel = ioread32(clk_muxsel);
|
||||
}
|
||||
}
|
||||
#ifdef CONFIG_BOLERO_VER_2P1
|
||||
if (priv->clk[clk_id + NPL_CLK_OFFSET])
|
||||
clk_disable_unprepare(priv->clk[clk_id + NPL_CLK_OFFSET]);
|
||||
#endif
|
||||
clk_disable_unprepare(priv->clk[clk_id]);
|
||||
if (clk_id != VA_CORE_CLK && !ret)
|
||||
lpass_cdc_clk_rsc_mux0_clk_request(priv,
|
||||
default_clk_id, false);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
#ifdef CONFIG_BOLERO_VER_2P1
|
||||
err_npl_clk:
|
||||
clk_disable_unprepare(priv->clk[clk_id]);
|
||||
#endif
|
||||
err_clk:
|
||||
if (clk_id != VA_CORE_CLK)
|
||||
lpass_cdc_clk_rsc_mux0_clk_request(priv, default_clk_id, false);
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int lpass_cdc_clk_rsc_check_and_update_va_clk(struct lpass_cdc_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 = lpass_cdc_clk_rsc_mux1_clk_request(priv,
|
||||
VA_CORE_CLK, enable);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
} else {
|
||||
ret = lpass_cdc_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 = lpass_cdc_clk_rsc_mux0_clk_request(priv,
|
||||
TX_CORE_CLK, true);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
lpass_cdc_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]) {
|
||||
lpass_cdc_clk_rsc_mux1_clk_request(priv,
|
||||
VA_CORE_CLK, enable);
|
||||
} else if (priv->va_tx_clk_cnt) {
|
||||
lpass_cdc_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 = lpass_cdc_clk_rsc_mux1_clk_request(priv,
|
||||
VA_CORE_CLK, true);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
lpass_cdc_clk_rsc_mux0_clk_request(priv,
|
||||
TX_CORE_CLK, false);
|
||||
priv->va_tx_clk_cnt--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* lpass_cdc_clk_rsc_fs_gen_request - request to enable/disable fs generation
|
||||
* sequence
|
||||
*
|
||||
* @dev: Macro device pointer
|
||||
* @enable: enable or disable flag
|
||||
*/
|
||||
void lpass_cdc_clk_rsc_fs_gen_request(struct device *dev, bool enable)
|
||||
{
|
||||
int i;
|
||||
struct regmap *regmap;
|
||||
struct device *clk_dev = NULL;
|
||||
struct lpass_cdc_clk_rsc *priv = NULL;
|
||||
|
||||
if (!dev) {
|
||||
pr_err("%s: dev is null\n", __func__);
|
||||
return;
|
||||
}
|
||||
clk_dev = lpass_cdc_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 (!regmap) {
|
||||
pr_err("%s: regmap is null\n", __func__);
|
||||
return;
|
||||
}
|
||||
mutex_lock(&priv->fs_gen_lock);
|
||||
if (enable) {
|
||||
if (priv->reg_seq_en_cnt++ == 0) {
|
||||
for (i = 0; i < (priv->num_fs_reg * 3); i += 3) {
|
||||
dev_dbg(priv->dev, "%s: Register: %d, mask: %d, value: %d\n",
|
||||
__func__, priv->fs_gen_seq[i],
|
||||
priv->fs_gen_seq[i + 1],
|
||||
priv->fs_gen_seq[i + 2]);
|
||||
regmap_update_bits(regmap,
|
||||
priv->fs_gen_seq[i],
|
||||
priv->fs_gen_seq[i + 1],
|
||||
priv->fs_gen_seq[i + 2]);
|
||||
}
|
||||
}
|
||||
} 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;
|
||||
mutex_unlock(&priv->fs_gen_lock);
|
||||
return;
|
||||
}
|
||||
if (--priv->reg_seq_en_cnt == 0) {
|
||||
for (i = ((priv->num_fs_reg - 1) * 3); i >= 0; i -= 3) {
|
||||
dev_dbg(priv->dev, "%s: Register: %d, mask: %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);
|
||||
}
|
||||
}
|
||||
}
|
||||
mutex_unlock(&priv->fs_gen_lock);
|
||||
}
|
||||
EXPORT_SYMBOL(lpass_cdc_clk_rsc_fs_gen_request);
|
||||
|
||||
/**
|
||||
* lpass_cdc_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 lpass_cdc_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 lpass_cdc_clk_rsc *priv = NULL;
|
||||
bool mux_switch = false;
|
||||
|
||||
if (!dev) {
|
||||
pr_err("%s: dev is null\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 = lpass_cdc_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 && enable) {
|
||||
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 = lpass_cdc_clk_rsc_mux1_clk_request(priv, clk_id_req,
|
||||
enable);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
ret = lpass_cdc_clk_rsc_mux0_clk_request(priv, clk_id_req, enable);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = lpass_cdc_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(lpass_cdc_clk_rsc_request_clock);
|
||||
|
||||
|
||||
static int lpass_cdc_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 lpass_cdc_clk_rsc *priv = NULL;
|
||||
u32 muxsel = 0;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(struct lpass_cdc_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/(3 * 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 * 3);
|
||||
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);
|
||||
if (!clk_name_array) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
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]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
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 = lpass_cdc_register_res_clk(&pdev->dev, lpass_cdc_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;
|
||||
priv->dev_up_gfmux = true;
|
||||
mutex_init(&priv->rsc_clk_lock);
|
||||
mutex_init(&priv->fs_gen_lock);
|
||||
dev_set_drvdata(&pdev->dev, priv);
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int lpass_cdc_clk_rsc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct lpass_cdc_clk_rsc *priv = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
lpass_cdc_unregister_res_clk(&pdev->dev);
|
||||
of_platform_depopulate(&pdev->dev);
|
||||
if (!priv)
|
||||
return -EINVAL;
|
||||
mutex_destroy(&priv->rsc_clk_lock);
|
||||
mutex_destroy(&priv->fs_gen_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id lpass_cdc_clk_rsc_dt_match[] = {
|
||||
{.compatible = "qcom,lpass-cdc-clk-rsc-mngr"},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, lpass_cdc_clk_rsc_dt_match);
|
||||
|
||||
static struct platform_driver lpass_cdc_clk_rsc_mgr = {
|
||||
.driver = {
|
||||
.name = "lpass-cdc-clk-rsc-mngr",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = lpass_cdc_clk_rsc_dt_match,
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
.probe = lpass_cdc_clk_rsc_probe,
|
||||
.remove = lpass_cdc_clk_rsc_remove,
|
||||
};
|
||||
|
||||
int lpass_cdc_clk_rsc_mgr_init(void)
|
||||
{
|
||||
return platform_driver_register(&lpass_cdc_clk_rsc_mgr);
|
||||
}
|
||||
|
||||
void lpass_cdc_clk_rsc_mgr_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&lpass_cdc_clk_rsc_mgr);
|
||||
}
|
||||
MODULE_DESCRIPTION("LPASS codec clock resource manager driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@@ -0,0 +1,52 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2019-2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef LPASS_CDC_CLK_RSC_H
|
||||
#define LPASS_CDC_CLK_RSC_H
|
||||
|
||||
#include <linux/regmap.h>
|
||||
#include <bindings/qcom,lpass-cdc-clk-rsc.h>
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_LPASS_CDC)
|
||||
int lpass_cdc_clk_rsc_mgr_init(void);
|
||||
void lpass_cdc_clk_rsc_mgr_exit(void);
|
||||
void lpass_cdc_clk_rsc_fs_gen_request(struct device *dev,
|
||||
bool enable);
|
||||
int lpass_cdc_clk_rsc_request_clock(struct device *dev,
|
||||
int default_clk_id,
|
||||
int clk_id_req,
|
||||
bool enable);
|
||||
int lpass_cdc_rsc_clk_reset(struct device *dev, int clk_id);
|
||||
void lpass_cdc_clk_rsc_enable_all_clocks(struct device *dev, bool enable);
|
||||
#else
|
||||
static inline void lpass_cdc_clk_rsc_fs_gen_request(struct device *dev,
|
||||
bool enable)
|
||||
{
|
||||
}
|
||||
static inline int lpass_cdc_clk_rsc_mgr_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void lpass_cdc_clk_rsc_mgr_exit(void)
|
||||
{
|
||||
}
|
||||
static inline int lpass_cdc_clk_rsc_request_clock(struct device *dev,
|
||||
int default_clk_id,
|
||||
int clk_id_req,
|
||||
bool enable)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int lpass_cdc_rsc_clk_reset(struct device *dev, int clk_id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void lpass_cdc_clk_rsc_enable_all_clocks(struct device *dev,
|
||||
bool enable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_SND_SOC_LPASS_CDC */
|
||||
#endif /* LPASS_CDC_CLK_RSC_H */
|
@@ -0,0 +1,117 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
#include "lpass-cdc-comp.h"
|
||||
|
||||
int lpass_cdc_load_compander_coeff(struct snd_soc_component *component,
|
||||
u16 lsb_reg, u16 msb_reg,
|
||||
struct comp_coeff_val *comp_coeff_table,
|
||||
u16 arr_size)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
/* Load Compander Coeff */
|
||||
for (i = 0; i < arr_size; i++) {
|
||||
snd_soc_component_write(component, lsb_reg,
|
||||
comp_coeff_table[i].lsb);
|
||||
snd_soc_component_write(component, msb_reg,
|
||||
comp_coeff_table[i].msb);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(lpass_cdc_load_compander_coeff);
|
||||
|
||||
int lpass_cdc_update_compander_setting(struct snd_soc_component *component,
|
||||
u16 start_addr,
|
||||
struct lpass_cdc_comp_setting *comp_setting)
|
||||
{
|
||||
int zone2_rms, zone3_rms, zone4_rms, zone5_rms, zone6_rms;
|
||||
int path_gain;
|
||||
int max_attn;
|
||||
int zone1_rms = 6;
|
||||
int upper_gain_int = comp_setting->upper_gain_int;
|
||||
int lower_gain_int = comp_setting->lower_gain_int;
|
||||
int ana_addr_map = comp_setting->ana_addr_map;
|
||||
int upper_gain_dig_int = upper_gain_int - lower_gain_int;
|
||||
|
||||
/* skip comp_ctl8, comp_ctl9 default settings is fine */
|
||||
|
||||
/* apply zone settings */
|
||||
snd_soc_component_write(component,
|
||||
start_addr + 8,
|
||||
zone1_rms);
|
||||
|
||||
if (upper_gain_dig_int >= 24)
|
||||
zone2_rms = 18;
|
||||
else if (upper_gain_dig_int >= 18)
|
||||
zone2_rms = 12;
|
||||
else
|
||||
zone2_rms = upper_gain_dig_int;
|
||||
snd_soc_component_write(component,
|
||||
start_addr + 0xC,
|
||||
zone2_rms);
|
||||
|
||||
if (upper_gain_dig_int >= 66)
|
||||
zone3_rms = 33;
|
||||
else if (upper_gain_dig_int >= 36)
|
||||
zone3_rms = 30;
|
||||
else if (upper_gain_dig_int >= 30)
|
||||
zone3_rms = 24;
|
||||
else
|
||||
zone3_rms = upper_gain_dig_int;
|
||||
snd_soc_component_write(component,
|
||||
start_addr + 0x10,
|
||||
zone3_rms);
|
||||
|
||||
if (upper_gain_dig_int >= 66)
|
||||
zone4_rms = 48;
|
||||
else if (upper_gain_dig_int >= 48)
|
||||
zone4_rms = 42;
|
||||
else if (upper_gain_dig_int >= 42)
|
||||
zone4_rms = 36;
|
||||
else
|
||||
zone4_rms = upper_gain_dig_int;
|
||||
snd_soc_component_write(component,
|
||||
start_addr + 0x14,
|
||||
zone4_rms);
|
||||
|
||||
if (upper_gain_dig_int >= 69)
|
||||
zone5_rms = 63;
|
||||
else if (upper_gain_dig_int >= 66)
|
||||
zone5_rms = 60;
|
||||
else if (upper_gain_dig_int >= 60)
|
||||
zone5_rms = 54;
|
||||
else if (upper_gain_dig_int >= 54)
|
||||
zone5_rms = 48;
|
||||
else
|
||||
zone5_rms = upper_gain_dig_int;
|
||||
snd_soc_component_write(component,
|
||||
start_addr + 0x18,
|
||||
zone5_rms);
|
||||
|
||||
zone6_rms = upper_gain_dig_int;
|
||||
snd_soc_component_write(component,
|
||||
start_addr + 0x1C,
|
||||
zone6_rms);
|
||||
|
||||
if (lower_gain_int < 0)
|
||||
max_attn = 256 + lower_gain_int;
|
||||
else
|
||||
max_attn = lower_gain_int;
|
||||
snd_soc_component_write(component,
|
||||
start_addr + 0x20,
|
||||
max_attn);
|
||||
|
||||
path_gain = zone6_rms - abs(lower_gain_int);
|
||||
snd_soc_component_write(component,
|
||||
start_addr + 0x24,
|
||||
path_gain);
|
||||
|
||||
snd_soc_component_write(component,
|
||||
start_addr + 0x28,
|
||||
ana_addr_map);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(lpass_cdc_update_compander_setting);
|
@@ -0,0 +1,27 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
#ifndef LPASS_CDC_COMP_H
|
||||
#define LPASS_CDC_COMP_H
|
||||
|
||||
#include <sound/soc.h>
|
||||
|
||||
struct comp_coeff_val {
|
||||
u8 lsb;
|
||||
u8 msb;
|
||||
};
|
||||
|
||||
struct lpass_cdc_comp_setting {
|
||||
int upper_gain_int;
|
||||
int lower_gain_int;
|
||||
int ana_addr_map;
|
||||
};
|
||||
|
||||
int lpass_cdc_load_compander_coeff(struct snd_soc_component *component,
|
||||
u16 lsb_reg, u16 msb_reg,
|
||||
struct comp_coeff_val *comp_coeff_table,
|
||||
u16 arr_size);
|
||||
int lpass_cdc_update_compander_setting(struct snd_soc_component *component,
|
||||
u16 start_addr,
|
||||
struct lpass_cdc_comp_setting *comp_setting);
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,172 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/* Copyright (c) 2018, 2020, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/regmap.h>
|
||||
#include "lpass-cdc.h"
|
||||
#include "internal.h"
|
||||
|
||||
#define REG_BYTES 2
|
||||
#define VAL_BYTES 1
|
||||
|
||||
const u16 macro_id_base_offset[MAX_MACRO] = {
|
||||
TX_START_OFFSET,
|
||||
RX_START_OFFSET,
|
||||
WSA_START_OFFSET,
|
||||
VA_START_OFFSET,
|
||||
WSA2_START_OFFSET,
|
||||
};
|
||||
|
||||
int lpass_cdc_get_macro_id(bool va_no_dec_flag, u16 reg)
|
||||
{
|
||||
if (reg >= TX_START_OFFSET
|
||||
&& reg <= TX_MAX_OFFSET)
|
||||
return TX_MACRO;
|
||||
if (reg >= RX_START_OFFSET
|
||||
&& reg <= RX_MAX_OFFSET)
|
||||
return RX_MACRO;
|
||||
if (reg >= WSA_START_OFFSET
|
||||
&& reg <= WSA_MAX_OFFSET)
|
||||
return WSA_MACRO;
|
||||
if (reg >= WSA2_START_OFFSET
|
||||
&& reg <= WSA2_MAX_OFFSET)
|
||||
return WSA2_MACRO;
|
||||
if (reg >= VA_START_OFFSET &&
|
||||
reg <= VA_MAX_OFFSET)
|
||||
return VA_MACRO;
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int regmap_bus_read(void *context, const void *reg, size_t reg_size,
|
||||
void *val, size_t val_size)
|
||||
{
|
||||
struct device *dev = context;
|
||||
struct lpass_cdc_priv *priv = dev_get_drvdata(dev);
|
||||
u16 *reg_p;
|
||||
u16 __reg;
|
||||
int macro_id, i;
|
||||
u8 temp = 0;
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (!priv) {
|
||||
dev_err_ratelimited(dev, "%s: priv is NULL\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
if (!reg || !val) {
|
||||
dev_err_ratelimited(dev, "%s: reg or val is NULL\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
if (reg_size != REG_BYTES) {
|
||||
dev_err_ratelimited(dev, "%s: register size %zd bytes, not supported\n",
|
||||
__func__, reg_size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
reg_p = (u16 *)reg;
|
||||
macro_id = lpass_cdc_get_macro_id(priv->va_without_decimation,
|
||||
reg_p[0]);
|
||||
if (macro_id < 0 || !priv->macros_supported[macro_id])
|
||||
return 0;
|
||||
|
||||
mutex_lock(&priv->io_lock);
|
||||
for (i = 0; i < val_size; i++) {
|
||||
__reg = (reg_p[0] + i * 4) - macro_id_base_offset[macro_id];
|
||||
ret = priv->read_dev(priv, macro_id, __reg, &temp);
|
||||
if (ret < 0) {
|
||||
dev_err_ratelimited(dev,
|
||||
"%s: Codec read failed (%d), reg: 0x%x, size:%zd\n",
|
||||
__func__, ret, reg_p[0] + i * 4, val_size);
|
||||
break;
|
||||
}
|
||||
((u8 *)val)[i] = temp;
|
||||
dev_dbg(dev, "%s: Read 0x%02x from reg 0x%x\n",
|
||||
__func__, temp, reg_p[0] + i * 4);
|
||||
}
|
||||
mutex_unlock(&priv->io_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int regmap_bus_gather_write(void *context,
|
||||
const void *reg, size_t reg_size,
|
||||
const void *val, size_t val_size)
|
||||
{
|
||||
struct device *dev = context;
|
||||
struct lpass_cdc_priv *priv = dev_get_drvdata(dev);
|
||||
u16 *reg_p;
|
||||
u16 __reg;
|
||||
int macro_id, i;
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (!priv) {
|
||||
dev_err_ratelimited(dev, "%s: priv is NULL\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
if (!reg || !val) {
|
||||
dev_err_ratelimited(dev, "%s: reg or val is NULL\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
if (reg_size != REG_BYTES) {
|
||||
dev_err_ratelimited(dev, "%s: register size %zd bytes, not supported\n",
|
||||
__func__, reg_size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
reg_p = (u16 *)reg;
|
||||
macro_id = lpass_cdc_get_macro_id(priv->va_without_decimation,
|
||||
reg_p[0]);
|
||||
if (macro_id < 0 || !priv->macros_supported[macro_id])
|
||||
return 0;
|
||||
|
||||
mutex_lock(&priv->io_lock);
|
||||
for (i = 0; i < val_size; i++) {
|
||||
__reg = (reg_p[0] + i * 4) - macro_id_base_offset[macro_id];
|
||||
ret = priv->write_dev(priv, macro_id, __reg, ((u8 *)val)[i]);
|
||||
if (ret < 0) {
|
||||
dev_err_ratelimited(dev,
|
||||
"%s: Codec write failed (%d), reg:0x%x, size:%zd\n",
|
||||
__func__, ret, reg_p[0] + i * 4, val_size);
|
||||
break;
|
||||
}
|
||||
dev_dbg(dev, "Write %02x to reg 0x%x\n", ((u8 *)val)[i],
|
||||
reg_p[0] + i * 4);
|
||||
}
|
||||
mutex_unlock(&priv->io_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int regmap_bus_write(void *context, const void *data, size_t count)
|
||||
{
|
||||
struct device *dev = context;
|
||||
struct lpass_cdc_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
if (!priv)
|
||||
return -EINVAL;
|
||||
|
||||
if (count < REG_BYTES) {
|
||||
dev_err_ratelimited(dev, "%s: count %zd bytes < %d, not supported\n",
|
||||
__func__, count, REG_BYTES);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return regmap_bus_gather_write(context, data, REG_BYTES,
|
||||
data + REG_BYTES,
|
||||
count - REG_BYTES);
|
||||
}
|
||||
|
||||
static struct regmap_bus regmap_bus_config = {
|
||||
.write = regmap_bus_write,
|
||||
.gather_write = regmap_bus_gather_write,
|
||||
.read = regmap_bus_read,
|
||||
.reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
|
||||
.val_format_endian_default = REGMAP_ENDIAN_NATIVE,
|
||||
};
|
||||
|
||||
struct regmap *lpass_cdc_regmap_init(struct device *dev,
|
||||
const struct regmap_config *config)
|
||||
{
|
||||
return devm_regmap_init(dev, ®map_bus_config, dev, config);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,22 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
#ifndef LPASS_CDC_WSA_MACRO_H
|
||||
#define LPASS_CDC_WSA_MACRO_H
|
||||
|
||||
/*
|
||||
* Selects compander and smart boost settings
|
||||
* for a given speaker mode
|
||||
*/
|
||||
enum {
|
||||
LPASS_CDC_WSA_MACRO_SPKR_MODE_DEFAULT,
|
||||
LPASS_CDC_WSA_MACRO_SPKR_MODE_1, /* COMP Gain = 12dB, Smartboost Max = 5.5V */
|
||||
};
|
||||
|
||||
/* Rx path gain offsets */
|
||||
enum {
|
||||
LPASS_CDC_WSA_MACRO_GAIN_OFFSET_M1P5_DB,
|
||||
LPASS_CDC_WSA_MACRO_GAIN_OFFSET_0_DB,
|
||||
};
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,22 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
#ifndef LPASS_CDC_WSA2_MACRO_H
|
||||
#define LPASS_CDC_WSA2_MACRO_H
|
||||
|
||||
/*
|
||||
* Selects compander and smart boost settings
|
||||
* for a given speaker mode
|
||||
*/
|
||||
enum {
|
||||
LPASS_CDC_WSA2_MACRO_SPKR_MODE_DEFAULT,
|
||||
LPASS_CDC_WSA2_MACRO_SPKR_MODE_1, /* COMP Gain = 12dB, Smartboost Max = 5.5V */
|
||||
};
|
||||
|
||||
/* Rx path gain offsets */
|
||||
enum {
|
||||
LPASS_CDC_WSA2_MACRO_GAIN_OFFSET_M1P5_DB,
|
||||
LPASS_CDC_WSA2_MACRO_GAIN_OFFSET_0_DB,
|
||||
};
|
||||
|
||||
#endif
|
1571
qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc.c
Normal file
1571
qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc.c
Normal file
File diff suppressed because it is too large
Load Diff
394
qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc.h
Normal file
394
qcom/opensource/audio-kernel/asoc/codecs/lpass-cdc/lpass-cdc.h
Normal file
@@ -0,0 +1,394 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef LPASS_CDC_H
|
||||
#define LPASS_CDC_H
|
||||
|
||||
#include <sound/soc.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define LPASS_CDC_VERSION_1_0 0x0001
|
||||
#define LPASS_CDC_VERSION_1_1 0x0002
|
||||
#define LPASS_CDC_VERSION_1_2 0x0003
|
||||
#define LPASS_CDC_VERSION_2_0 0x0004
|
||||
#define LPASS_CDC_VERSION_2_1 0x0005
|
||||
#define LPASS_CDC_VERSION_2_5 0x0006
|
||||
#define LPASS_CDC_VERSION_2_6 0x0007
|
||||
#define LPASS_CDC_VERSION_2_7 0x0008
|
||||
#define LPASS_CDC_VERSION_2_8 0x0009
|
||||
|
||||
enum {
|
||||
START_MACRO,
|
||||
TX_MACRO = START_MACRO,
|
||||
RX_MACRO,
|
||||
WSA_MACRO,
|
||||
VA_MACRO,
|
||||
WSA2_MACRO,
|
||||
MAX_MACRO
|
||||
};
|
||||
|
||||
enum mclk_mux {
|
||||
MCLK_MUX0,
|
||||
MCLK_MUX1,
|
||||
MCLK_MUX_MAX
|
||||
};
|
||||
|
||||
enum {
|
||||
LPASS_CDC_ADC0 = 1,
|
||||
LPASS_CDC_ADC1,
|
||||
LPASS_CDC_ADC2,
|
||||
LPASS_CDC_ADC3,
|
||||
LPASS_CDC_ADC_MAX
|
||||
};
|
||||
|
||||
enum {
|
||||
LPASS_CDC_MACRO_EVT_RX_MUTE = 1, /* for RX mute/unmute */
|
||||
LPASS_CDC_MACRO_EVT_IMPED_TRUE, /* for imped true */
|
||||
LPASS_CDC_MACRO_EVT_IMPED_FALSE, /* for imped false */
|
||||
LPASS_CDC_MACRO_EVT_SSR_DOWN,
|
||||
LPASS_CDC_MACRO_EVT_SSR_UP,
|
||||
LPASS_CDC_MACRO_EVT_WAIT_VA_CLK_RESET,
|
||||
LPASS_CDC_MACRO_EVT_CLK_RESET,
|
||||
LPASS_CDC_MACRO_EVT_REG_WAKE_IRQ,
|
||||
LPASS_CDC_MACRO_EVT_RX_COMPANDER_SOFT_RST,
|
||||
LPASS_CDC_MACRO_EVT_BCS_CLK_OFF,
|
||||
LPASS_CDC_MACRO_EVT_SSR_GFMUX_UP,
|
||||
LPASS_CDC_MACRO_EVT_PRE_SSR_UP,
|
||||
LPASS_CDC_MACRO_EVT_RX_PA_GAIN_UPDATE,
|
||||
LPASS_CDC_MACRO_EVT_HPHL_HD2_ENABLE, /* Enable HD2 cfg for HPHL */
|
||||
LPASS_CDC_MACRO_EVT_HPHR_HD2_ENABLE, /* Enable HD2 cfg for HPHR */
|
||||
};
|
||||
|
||||
enum {
|
||||
DMIC_TX = 0,
|
||||
DMIC_VA = 1,
|
||||
|
||||
};
|
||||
|
||||
struct macro_ops {
|
||||
int (*init)(struct snd_soc_component *component);
|
||||
int (*exit)(struct snd_soc_component *component);
|
||||
u16 num_dais;
|
||||
struct device *dev;
|
||||
struct snd_soc_dai_driver *dai_ptr;
|
||||
int (*mclk_fn)(struct device *dev, bool enable);
|
||||
int (*event_handler)(struct snd_soc_component *component, u16 event,
|
||||
u32 data);
|
||||
int (*reg_wake_irq)(struct snd_soc_component *component, u32 data);
|
||||
int (*set_port_map)(struct snd_soc_component *component, u32 uc,
|
||||
u32 size, void *data);
|
||||
int (*clk_div_get)(struct snd_soc_component *component);
|
||||
int (*reg_evt_listener)(struct snd_soc_component *component, bool en);
|
||||
int (*clk_enable)(struct snd_soc_component *c, bool en);
|
||||
char __iomem *io_base;
|
||||
u16 clk_id_req;
|
||||
u16 default_clk_id;
|
||||
};
|
||||
|
||||
enum {
|
||||
G_21_DB = 0,
|
||||
G_19P5_DB,
|
||||
G_18_DB,
|
||||
G_16P5_DB,
|
||||
G_15_DB,
|
||||
G_13P5_DB,
|
||||
G_12_DB,
|
||||
G_10P5_DB,
|
||||
G_9_DB,
|
||||
G_7P5_DB,
|
||||
G_6_DB,
|
||||
G_4P5_DB,
|
||||
G_3_DB,
|
||||
G_1P5_DB,
|
||||
G_0_DB,
|
||||
G_M1P5_DB,
|
||||
G_M3_DB,
|
||||
G_M4P5_DB,
|
||||
G_M6_DB,
|
||||
G_MAX_DB,
|
||||
};
|
||||
|
||||
enum {
|
||||
EXT_ABOVE_3S,
|
||||
CONFIG_1S,
|
||||
CONFIG_2S,
|
||||
CONFIG_3S,
|
||||
EXT_1S,
|
||||
EXT_2S,
|
||||
EXT_3S,
|
||||
CONFIG_MAX,
|
||||
};
|
||||
|
||||
enum {
|
||||
WSA_4_OHMS = 0,
|
||||
WSA_6_OHMS,
|
||||
WSA_8_OHMS,
|
||||
WSA_32_OHMS,
|
||||
WSA_MAX_OHMS,
|
||||
};
|
||||
|
||||
/*
|
||||
* PBR Thresholds from system_gain, bat_cfg, and rload
|
||||
* EXT_ABOVE_3S: WSA_4_OHMS, WSA_6_OHMS, WSA_8_OHMS, WSA_32_OHMS, CONFIG_1S: ...
|
||||
*/
|
||||
static const int pbr_vth1_data[G_MAX_DB][CONFIG_MAX][WSA_MAX_OHMS] = {
|
||||
/* G_21_DB */
|
||||
{
|
||||
{0, 0, 0, 0}, {81, 92, 106, 0},
|
||||
{121, 148, 144, 0}, {158, 193, 192, 0}
|
||||
},
|
||||
/* G_19P5_DB */
|
||||
{
|
||||
{0, 0, 0, 0}, {96, 109, 126, 0},
|
||||
{143, 148, 203, 0}, {188, 198, 255, 0}
|
||||
},
|
||||
/* G_18_DB */
|
||||
{
|
||||
{0, 0, 0, 0}, {106, 130, 150, 0},
|
||||
{144, 209, 241, 0}, {192, 255, 255, 0}
|
||||
},
|
||||
/* G_16P5_DB */
|
||||
{
|
||||
{0, 0, 0, 0}, {135, 154, 178, 0},
|
||||
{202, 248, 255, 0}, {255, 255, 255, 0}
|
||||
},
|
||||
/* G_15_DB */
|
||||
{
|
||||
{0, 0, 0, 0}, {160, 183, 211, 0},
|
||||
{240, 255, 255, 0}, {255, 255, 255, 0}
|
||||
},
|
||||
/* G_13P5_DB */
|
||||
{
|
||||
{0, 0, 0, 0}, {190, 217, 251, 0},
|
||||
{255, 255, 255, 0}, {255, 255, 255, 0}
|
||||
},
|
||||
/* G_12_DB */
|
||||
{
|
||||
{0, 0, 0, 0}, {226, 255, 255, 0},
|
||||
{225, 255, 255, 0}, {255, 255, 255, 0}
|
||||
},
|
||||
};
|
||||
static const int pbr_vth2_data[G_MAX_DB][CONFIG_MAX][WSA_MAX_OHMS] = {
|
||||
{ {0, 0, 0, 0}, {0, 0, 112, 0}, {0, 0, 151, 0}, {0, 0, 196, 0} }, /* G_21_DB */
|
||||
{ {0, 0, 0, 0}, {0, 115, 0, 0}, {0, 155, 0, 0}, {0, 201, 0, 0} }, /* G_19P5_DB */
|
||||
{ {0, 0, 0, 0}, {112, 0, 0, 0}, {150, 0, 0, 0}, {195, 0, 0, 0} }, /* G_18_DB */
|
||||
};
|
||||
|
||||
static const int pbr_vth3_data[G_MAX_DB][CONFIG_MAX][WSA_MAX_OHMS] = {
|
||||
{ {0, 0, 0, 0}, {0, 0, 118, 0}, {0, 0, 157, 0}, {0, 0, 199, 0} }, /* G_21_DB */
|
||||
{ {0, 0, 0, 0}, {0, 122, 0, 0}, {0, 162, 0, 0}, {0, 205, 0, 0} }, /* G_19P5_DB */
|
||||
{ {0, 0, 0, 0}, {118, 0, 0, 0}, {157, 0, 0, 0}, {199, 0, 0, 0} }, /* G_18_DB */
|
||||
};
|
||||
|
||||
static const int pbr_vth4_data[G_MAX_DB][CONFIG_MAX][WSA_MAX_OHMS] = {
|
||||
{ {0, 0, 0, 0}, {0, 0, 125, 0}, {0, 0, 163, 0}, {0, 0, 202, 0} }, /* G_21_DB */
|
||||
{ {0, 0, 0, 0}, {0, 129, 0, 0}, {0, 168, 0, 0}, {0, 208, 0, 0} }, /* G_19P5_DB */
|
||||
{ {0, 0, 0, 0}, {125, 0, 0, 0}, {163, 0, 0, 0}, {202, 0, 0, 0} }, /* G_18_DB */
|
||||
};
|
||||
|
||||
static const int pbr_vth5_data[G_MAX_DB][CONFIG_MAX][WSA_MAX_OHMS] = {
|
||||
{ {0, 0, 0, 0}, {0, 0, 131, 0}, {0, 0, 170, 0}, {0, 0, 205, 0} }, /* G_21_DB */
|
||||
{ {0, 0, 0, 0}, {0, 135, 0, 0}, {0, 175, 0, 0}, {0, 211, 0, 0} }, /* G_19P5_DB */
|
||||
{ {0, 0, 0, 0}, {131, 0, 0, 0}, {170, 0, 0, 0}, {205, 0, 0, 0} }, /* G_18_DB */
|
||||
};
|
||||
|
||||
static const int pbr_vth6_data[G_MAX_DB][CONFIG_MAX][WSA_MAX_OHMS] = {
|
||||
{ {0, 0, 0, 0}, {0, 0, 138, 0}, {0, 0, 176, 0}, {0, 0, 208, 0} }, /* G_21_DB */
|
||||
{ {0, 0, 0, 0}, {0, 142, 0, 0}, {0, 182, 0, 0}, {0, 215, 0, 0} }, /* G_19P5_DB */
|
||||
{ {0, 0, 0, 0}, {138, 0, 0, 0}, {176, 0, 0, 0}, {208, 0, 0, 0} }, /* G_18_DB */
|
||||
};
|
||||
|
||||
static const int pbr_vth7_data[G_MAX_DB][CONFIG_MAX][WSA_MAX_OHMS] = {
|
||||
{ {0, 0, 0, 0}, {0, 0, 144, 0}, {0, 0, 183, 0}, {0, 0, 212, 0} }, /* G_21_DB */
|
||||
{ {0, 0, 0, 0}, {0, 148, 0, 0}, {0, 188, 0, 0}, {0, 218, 0, 0} }, /* G_19P5_DB */
|
||||
{ {0, 0, 0, 0}, {0, 0, 144, 0}, {0, 0, 183, 0}, {0, 0, 212, 0} }, /* G_18_DB */
|
||||
};
|
||||
|
||||
static const int pbr_vth8_data[G_MAX_DB][CONFIG_MAX][WSA_MAX_OHMS] = {
|
||||
{ {0, 0, 0, 0}, {0, 0, 151, 0}, {0, 0, 189, 0}, {0, 0, 215, 0} }, /* G_21_DB */
|
||||
{ {0, 0, 0, 0}, {0, 155, 0, 0}, {0, 195, 0, 0}, {0, 221, 0, 0} }, /* G_19P5_DB */
|
||||
{ {0, 0, 0, 0}, {150, 0, 0, 0}, {189, 0, 0, 0}, {215, 0, 0, 0} }, /* G_18_DB */
|
||||
};
|
||||
|
||||
static const int pbr_vth9_data[G_MAX_DB][CONFIG_MAX][WSA_MAX_OHMS] = {
|
||||
{ {0, 0, 0, 0}, {0, 0, 157, 0}, {0, 0, 196, 0}, {0, 0, 218, 0} }, /* G_21_DB */
|
||||
{ {0, 0, 0, 0}, {0, 162, 0, 0}, {0, 201, 0, 0}, {0, 225, 0, 0} }, /* G_19P5_DB */
|
||||
{ {0, 0, 0, 0}, {157, 0, 0, 0}, {195, 0, 0, 0}, {218, 0, 0, 0} }, /* G_18_DB */
|
||||
};
|
||||
|
||||
static const int pbr_vth10_data[G_MAX_DB][CONFIG_MAX][WSA_MAX_OHMS] = {
|
||||
{ {0, 0, 0, 0}, {0, 0, 163, 0}, {0, 0, 202, 0}, {0, 0, 221, 0} }, /* G_21_DB */
|
||||
{ {0, 0, 0, 0}, {0, 168, 0, 0}, {0, 208, 0, 0}, {0, 228, 0, 0} }, /* G_19P5_DB */
|
||||
{ {0, 0, 0, 0}, {163, 0, 0, 0}, {202, 0, 0, 0}, {221, 0, 0, 0} }, /* G_18_DB */
|
||||
};
|
||||
|
||||
static const int pbr_vth11_data[G_MAX_DB][CONFIG_MAX][WSA_MAX_OHMS] = {
|
||||
{ {0, 0, 0, 0}, {0, 0, 170, 0}, {0, 0, 208, 0}, {0, 0, 225, 0} }, /* G_21_DB */
|
||||
{ {0, 0, 0, 0}, {0, 175, 0, 0}, {0, 215, 0, 0}, {0, 231, 0, 0} }, /* G_19P5_DB */
|
||||
{ {0, 0, 0, 0}, {170, 0, 0, 0}, {208, 0, 0, 0}, {224, 0, 0, 0} }, /* G_18_DB */
|
||||
};
|
||||
|
||||
static const int pbr_vth12_data[G_MAX_DB][CONFIG_MAX][WSA_MAX_OHMS] = {
|
||||
{ {0, 0, 0, 0}, {0, 0, 176, 0}, {0, 0, 215, 0}, {0, 0, 228, 0} }, /* G_21_DB */
|
||||
{ {0, 0, 0, 0}, {0, 182, 0, 0}, {0, 221, 0, 0}, {0, 234, 0, 0} }, /* G_19P5_DB */
|
||||
{ {0, 0, 0, 0}, {176, 0, 0, 0}, {215, 0, 0, 0}, {228, 0, 0, 0} }, /* G_18_DB */
|
||||
};
|
||||
|
||||
static const int pbr_vth13_data[G_MAX_DB][CONFIG_MAX][WSA_MAX_OHMS] = {
|
||||
{ {0, 0, 0, 0}, {0, 0, 183, 0}, {0, 0, 221, 0}, {0, 0, 231, 0} }, /* G_21_DB */
|
||||
{ {0, 0, 0, 0}, {0, 188, 0, 0}, {0, 228, 0, 0}, {0, 238, 0, 0} }, /* G_19P5_DB */
|
||||
{ {0, 0, 0, 0}, {183, 0, 0, 0}, {221, 0, 0, 0}, {231, 0, 0, 0} }, /* G_18_DB */
|
||||
};
|
||||
|
||||
static const int pbr_vth14_data[G_MAX_DB][CONFIG_MAX][WSA_MAX_OHMS] = {
|
||||
{ {0, 0, 0, 0}, {0, 0, 189, 0}, {0, 0, 228, 0}, {0, 0, 234, 0} }, /* G_21_DB */
|
||||
{ {0, 0, 0, 0}, {0, 195, 0, 0}, {0, 234, 0, 0}, {0, 241, 0, 0} }, /* G_19P5_DB */
|
||||
{ {0, 0, 0, 0}, {189, 0, 0, 0}, {228, 0, 0, 0}, {234, 0, 0, 0} }, /* G_18_DB */
|
||||
};
|
||||
|
||||
static const int pbr_vth15_data[G_MAX_DB][CONFIG_MAX][WSA_MAX_OHMS] = {
|
||||
{ {0, 0, 0, 0}, {0, 0, 196, 0}, {0, 0, 234, 0}, {0, 0, 237, 0} }, /* G_21_DB */
|
||||
{ {0, 0, 0, 0}, {0, 201, 0, 0}, {0, 241, 0, 0}, {0, 244, 0, 0} }, /* G_19P5_DB */
|
||||
{ {0, 0, 0, 0}, {195, 0, 0, 0}, {234, 0, 0, 0}, {237, 0, 0, 0} }, /* G_18_DB */
|
||||
};
|
||||
|
||||
typedef int (*rsc_clk_cb_t)(struct device *dev, u16 event);
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_LPASS_CDC)
|
||||
int lpass_cdc_register_res_clk(struct device *dev, rsc_clk_cb_t cb);
|
||||
void lpass_cdc_unregister_res_clk(struct device *dev);
|
||||
bool lpass_cdc_is_va_macro_registered(struct device *dev);
|
||||
int lpass_cdc_register_macro(struct device *dev, u16 macro_id,
|
||||
struct macro_ops *ops);
|
||||
void lpass_cdc_unregister_macro(struct device *dev, u16 macro_id);
|
||||
struct device *lpass_cdc_get_device_ptr(struct device *dev, u16 macro_id);
|
||||
struct device *lpass_cdc_get_rsc_clk_device_ptr(struct device *dev);
|
||||
int lpass_cdc_info_create_codec_entry(
|
||||
struct snd_info_entry *codec_root,
|
||||
struct snd_soc_component *component);
|
||||
int lpass_cdc_register_wake_irq(struct snd_soc_component *component, u32 data);
|
||||
void lpass_cdc_clear_amic_tx_hold(struct device *dev, u16 adc_n);
|
||||
int lpass_cdc_runtime_resume(struct device *dev);
|
||||
int lpass_cdc_runtime_suspend(struct device *dev);
|
||||
int lpass_cdc_set_port_map(struct snd_soc_component *component, u32 size, void *data);
|
||||
int lpass_cdc_register_event_listener(struct snd_soc_component *component,
|
||||
bool enable);
|
||||
void lpass_cdc_wsa_pa_on(struct device *dev, bool adie_lb);
|
||||
void lpass_cdc_notify_wcd_rx_clk(struct device *dev, bool is_native_on);
|
||||
bool lpass_cdc_check_core_votes(struct device *dev);
|
||||
int lpass_cdc_tx_mclk_enable(struct snd_soc_component *c, bool enable);
|
||||
int lpass_cdc_get_version(struct device *dev);
|
||||
int lpass_cdc_dmic_clk_enable(struct snd_soc_component *component,
|
||||
u32 dmic, u32 tx_mode, bool enable);
|
||||
|
||||
/* RX MACRO utilities */
|
||||
int lpass_cdc_rx_set_fir_capability(struct snd_soc_component *component,
|
||||
bool capable);
|
||||
#else
|
||||
static inline int lpass_cdc_register_res_clk(struct device *dev, rsc_clk_cb_t cb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void lpass_cdc_unregister_res_clk(struct device *dev)
|
||||
{
|
||||
}
|
||||
|
||||
static bool lpass_cdc_is_va_macro_registered(struct device *dev)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline int lpass_cdc_register_macro(struct device *dev,
|
||||
u16 macro_id,
|
||||
struct macro_ops *ops)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void lpass_cdc_unregister_macro(struct device *dev, u16 macro_id)
|
||||
{
|
||||
}
|
||||
|
||||
static inline struct device *lpass_cdc_get_device_ptr(struct device *dev,
|
||||
u16 macro_id)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int lpass_cdc_info_create_codec_entry(
|
||||
struct snd_info_entry *codec_root,
|
||||
struct snd_soc_component *component)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void lpass_cdc_clear_amic_tx_hold(struct device *dev, u16 adc_n)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int lpass_cdc_register_wake_irq(struct snd_soc_component *component,
|
||||
u32 data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int lpass_cdc_runtime_resume(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lpass_cdc_runtime_suspend(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int lpass_cdc_set_port_map(struct snd_soc_component *component,
|
||||
u32 size, void *data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int lpass_cdc_register_event_listener(
|
||||
struct snd_soc_component *component,
|
||||
bool enable)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lpass_cdc_wsa_pa_on(struct device *dev, bool adie_lb)
|
||||
{
|
||||
}
|
||||
|
||||
static void lpass_cdc_notify_wcd_rx_clk(struct device *dev, bool is_native_on)
|
||||
{
|
||||
}
|
||||
|
||||
static inline bool lpass_cdc_check_core_votes(struct device *dev)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static int lpass_cdc_get_version(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lpass_cdc_dmic_clk_enable(struct snd_soc_component *component,
|
||||
u32 dmic, u32 tx_mode, bool enable)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static int lpass_cdc_tx_mclk_enable(struct snd_soc_component *c, bool enable)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
/* RX MACRO utilities */
|
||||
static int lpass_cdc_rx_set_fir_capability(struct snd_soc_component *component,
|
||||
bool capable)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_SND_SOC_LPASS_CDC */
|
||||
#endif /* LPASS_CDC_H */
|
Reference in New Issue
Block a user