6db4831e98
Android 14
1479 lines
36 KiB
C
1479 lines
36 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* Copyright (c) 2019 MediaTek Inc.
|
|
*/
|
|
/*****************************************************************************
|
|
*
|
|
* Filename:
|
|
* ---------
|
|
* AudDrv_Clk.c
|
|
*
|
|
* Project:
|
|
* --------
|
|
* MT6739 Audio Driver clock control implement
|
|
*
|
|
* Description:
|
|
* ------------
|
|
* Audio register
|
|
*
|
|
* Author:
|
|
* -------
|
|
* Chipeng Chang (MTK02308)
|
|
*
|
|
*----------------------------------------------------------------------------
|
|
*
|
|
*
|
|
*****************************************************************************/
|
|
|
|
/*****************************************************************************
|
|
* C O M P I L E R F L A G S
|
|
*****************************************************************************/
|
|
|
|
/*****************************************************************************
|
|
* E X T E R N A L R E F E R E N C E S
|
|
*****************************************************************************/
|
|
|
|
#include <linux/clk.h>
|
|
|
|
#include "mtk-auddrv-afe.h"
|
|
#include "mtk-auddrv-clk.h"
|
|
#include "mtk-auddrv-common.h"
|
|
#include "mtk-soc-digital-type.h"
|
|
|
|
#include <linux/delay.h>
|
|
#include <linux/spinlock.h>
|
|
#if defined(_MT_IDLE_HEADER) && !defined(CONFIG_FPGA_EARLY_PORTING)
|
|
#include <mtk_idle.h>
|
|
#endif
|
|
#include <linux/err.h>
|
|
#include <linux/platform_device.h>
|
|
|
|
#define _MT_SPM_RESOURCE
|
|
#if defined(_MT_SPM_RESOURCE) && !defined(CONFIG_FPGA_EARLY_PORTING)
|
|
#include "mtk_spm_resource_req.h"
|
|
bool spm_resource_req(unsigned int user, unsigned int req_mask)
|
|
__attribute__((weak));
|
|
#endif
|
|
/*****************************************************************************
|
|
* D A T A T Y P E S
|
|
*****************************************************************************/
|
|
|
|
static int APLL1Counter;
|
|
static int APLL2Counter;
|
|
static int Aud_APLL_DIV_APLL1_cntr;
|
|
static int Aud_APLL_DIV_APLL2_cntr;
|
|
static unsigned int MCLKFS = 128;
|
|
static unsigned int MCLKFS_HDMI = 256;
|
|
|
|
int Aud_Core_Clk_cntr;
|
|
int Aud_AFE_Clk_cntr;
|
|
int Aud_I2S_Clk_cntr;
|
|
int Aud_TDM_Clk_cntr;
|
|
int Aud_ADC_Clk_cntr;
|
|
#ifdef _NON_COMMON_FEATURE_READY
|
|
int Aud_HDMI_Clk_cntr;
|
|
#endif
|
|
int Aud_APLL22M_Clk_cntr;
|
|
int Aud_APLL24M_Clk_cntr;
|
|
int Aud_APLL1_Tuner_cntr;
|
|
int Aud_APLL2_Tuner_cntr;
|
|
static int Aud_EMI_cntr;
|
|
|
|
static DEFINE_SPINLOCK(auddrv_Clk_lock);
|
|
|
|
/* amp mutex lock */
|
|
static DEFINE_MUTEX(auddrv_pmic_mutex);
|
|
static DEFINE_MUTEX(audEMI_Clk_mutex);
|
|
static DEFINE_MUTEX(auddrv_clk_mutex);
|
|
|
|
/* AUDIO_APLL_DIVIDER_GROUP may vary by chip!!! */
|
|
enum AUDIO_APLL_DIVIDER_GROUP {
|
|
AUDIO_APLL1_DIV0,
|
|
AUDIO_APLL2_DIV0,
|
|
AUDIO_APLL12_DIV0,
|
|
AUDIO_APLL12_DIV1,
|
|
AUDIO_APLL12_DIV2,
|
|
AUDIO_APLL12_DIV3,
|
|
AUDIO_APLL12_DIV4,
|
|
AUDIO_APLL12_DIVB,
|
|
AUDIO_APLL12_DIV5,
|
|
AUDIO_APLL_DIV_NUM
|
|
};
|
|
|
|
/* mI2SAPLLDivSelect may vary by chip!!! */
|
|
static const unsigned int mI2SAPLLDivSelect[Soc_Aud_I2S_CLKDIV_NUMBER] = {
|
|
AUDIO_APLL1_DIV0, AUDIO_APLL2_DIV0, AUDIO_APLL12_DIV0,
|
|
AUDIO_APLL12_DIV1, AUDIO_APLL12_DIV2, AUDIO_APLL12_DIV3,
|
|
AUDIO_APLL12_DIV4, AUDIO_APLL12_DIVB, AUDIO_APLL12_DIV5};
|
|
|
|
enum audio_system_clock_type {
|
|
CLOCK_AFE = 0,
|
|
CLOCK_DAC,
|
|
CLOCK_DAC_PREDIS,
|
|
CLOCK_ADC,
|
|
CLOCK_TML,
|
|
CLOCK_APLL22M,
|
|
CLOCK_APLL1_TUNER,
|
|
#ifdef MT6739_scp
|
|
CLOCK_SCP_SYS_AUD,
|
|
#endif
|
|
CLOCK_INFRA_SYS_AUDIO,
|
|
CLOCK_MTKAIF_26M_CLK,
|
|
CLOCK_MUX_AUDIO,
|
|
CLOCK_MUX_AUDIOINTBUS,
|
|
CLOCK_TOP_SYSPLL1_D4,
|
|
/* apll related mux */
|
|
CLOCK_TOP_MUX_AUD_1,
|
|
CLOCK_TOP_APLL1_CK,
|
|
CLOCK_TOP_MUX_AUD_ENG1,
|
|
CLOCK_TOP_APLL1_D8,
|
|
CLOCK_APMIXED_APLL1,
|
|
CLOCK_CLK26M,
|
|
CLOCK_NUM
|
|
};
|
|
|
|
struct audio_clock_attr {
|
|
const char *name;
|
|
bool clk_prepare;
|
|
bool clk_status;
|
|
struct clk *clock;
|
|
};
|
|
|
|
static struct audio_clock_attr aud_clks[CLOCK_NUM] = {
|
|
[CLOCK_AFE] = {"aud_afe_clk", false, false, NULL},
|
|
[CLOCK_DAC] = {"aud_dac_clk", false, false, NULL},
|
|
/* AudDrv_Clk_On only */
|
|
[CLOCK_DAC_PREDIS] = {"aud_dac_predis_clk", false, false, NULL},
|
|
/* AudDrv_Clk_On only */
|
|
[CLOCK_ADC] = {"aud_adc_clk", false, false, NULL},
|
|
/* AudDrv_ADC_Clk_On only */
|
|
[CLOCK_TML] = {"aud_tml_clk", false, false, NULL}, /* NOT USED */
|
|
[CLOCK_APLL22M] = {"aud_apll22m_clk", false, false, NULL},
|
|
[CLOCK_APLL1_TUNER] = {"aud_apll1_tuner_clk", false, false, NULL},
|
|
#ifdef MT6739_scp
|
|
[CLOCK_SCP_SYS_AUD] = {"scp_sys_audio", false, false, NULL},
|
|
#endif
|
|
[CLOCK_INFRA_SYS_AUDIO] = {"aud_infra_clk", false, false, NULL},
|
|
[CLOCK_MTKAIF_26M_CLK] = {"mtkaif_26m_clk", false, false, NULL},
|
|
[CLOCK_MUX_AUDIO] = {"top_mux_audio", false, false, NULL},
|
|
[CLOCK_MUX_AUDIOINTBUS] = {"top_mux_audio_int", false, false, NULL},
|
|
/* AudDrv_AUDINTBUS_Sel */
|
|
[CLOCK_TOP_SYSPLL1_D4] = {"top_sys_pll1_d4", false, false, NULL},
|
|
/* AudDrv_AUDINTBUS_Sel */
|
|
[CLOCK_TOP_MUX_AUD_1] = {"top_mux_aud_1", false, false, NULL},
|
|
[CLOCK_TOP_APLL1_CK] = {"top_apll1_ck", false, false, NULL},
|
|
[CLOCK_TOP_MUX_AUD_ENG1] = {"top_mux_aud_eng1", false, false, NULL},
|
|
[CLOCK_TOP_APLL1_D8] = {"top_apll1_d8", false, false, NULL},
|
|
[CLOCK_APMIXED_APLL1] = {"apmixed_apll1", false, false, NULL},
|
|
[CLOCK_CLK26M] = {"top_clk26m_clk", false, false, NULL}
|
|
};
|
|
|
|
static int apll1_mux_setting(bool enable);
|
|
static int apll2_mux_setting(bool enable);
|
|
|
|
#if !defined(CONFIG_FPGA_EARLY_PORTING)
|
|
static int aud_clk_enable(const struct audio_clock_attr *clk)
|
|
{
|
|
int ret;
|
|
|
|
if (clk->clk_prepare) {
|
|
ret = clk_enable(clk->clock);
|
|
if (ret) {
|
|
pr_debug("%s(), clk_enable %s fail, ret %d\n",
|
|
__func__,
|
|
clk->name, ret);
|
|
return -EPERM;
|
|
}
|
|
} else {
|
|
pr_debug("%s(), clk %s, not prepared\n", __func__, clk->name);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
int AudDrv_Clk_probe(void *dev)
|
|
{
|
|
size_t i;
|
|
int ret = 0;
|
|
|
|
Aud_EMI_cntr = 0;
|
|
|
|
pr_debug("%s\n", __func__);
|
|
|
|
for (i = 0; i < ARRAY_SIZE(aud_clks); i++) {
|
|
aud_clks[i].clock = devm_clk_get(dev, aud_clks[i].name);
|
|
if (IS_ERR(aud_clks[i].clock)) {
|
|
ret = PTR_ERR(aud_clks[i].clock);
|
|
pr_debug("%s devm_clk_get %s fail %d\n", __func__,
|
|
aud_clks[i].name, ret);
|
|
} else {
|
|
aud_clks[i].clk_status = true;
|
|
}
|
|
}
|
|
|
|
if (ret)
|
|
return ret;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(aud_clks); i++) {
|
|
#ifdef MT6739_scp
|
|
if (i == CLOCK_SCP_SYS_AUD) /* CLOCK_SCP_SYS_AUD is MTCMOS */
|
|
continue;
|
|
#endif
|
|
if (aud_clks[i].clk_status) {
|
|
ret = clk_prepare(aud_clks[i].clock);
|
|
if (ret) {
|
|
pr_debug("%s clk_prepare %s fail %d\n",
|
|
__func__,
|
|
aud_clks[i].name, ret);
|
|
} else {
|
|
aud_clks[i].clk_prepare = true;
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void AudDrv_Clk_Deinit(void *dev)
|
|
{
|
|
size_t i;
|
|
|
|
pr_debug("%s\n", __func__);
|
|
for (i = 0; i < ARRAY_SIZE(aud_clks); i++) {
|
|
#ifdef MT6739_scp
|
|
if (i == CLOCK_SCP_SYS_AUD) /* CLOCK_SCP_SYS_AUD is MTCMOS */
|
|
continue;
|
|
#endif
|
|
if (aud_clks[i].clock && !IS_ERR(aud_clks[i].clock) &&
|
|
aud_clks[i].clk_prepare) {
|
|
clk_unprepare(aud_clks[i].clock);
|
|
aud_clks[i].clk_prepare = false;
|
|
}
|
|
}
|
|
}
|
|
#if defined(_MT_IDLE_HEADER) && !defined(CONFIG_FPGA_EARLY_PORTING)
|
|
static int audio_idle_notify_call(struct notifier_block *nfb,
|
|
unsigned long id,
|
|
void *arg)
|
|
{
|
|
|
|
switch (id) {
|
|
case NOTIFY_DPIDLE_ENTER:
|
|
case NOTIFY_SOIDLE_ENTER:
|
|
/* intbus pll -> 26m */
|
|
if (aud_clk_enable(&aud_clks[CLOCK_MUX_AUDIOINTBUS]))
|
|
return NOTIFY_OK;
|
|
|
|
AudDrv_AUDINTBUS_Sel(0);
|
|
|
|
if (aud_clks[CLOCK_MUX_AUDIOINTBUS].clk_prepare)
|
|
clk_disable(aud_clks[CLOCK_MUX_AUDIOINTBUS].clock);
|
|
|
|
break;
|
|
case NOTIFY_DPIDLE_LEAVE:
|
|
case NOTIFY_SOIDLE_LEAVE:
|
|
/* Audio Clock: 26m -> pll */
|
|
if (aud_clk_enable(&aud_clks[CLOCK_MUX_AUDIOINTBUS]))
|
|
return NOTIFY_OK;
|
|
|
|
AudDrv_AUDINTBUS_Sel(1);
|
|
|
|
if (aud_clks[CLOCK_MUX_AUDIOINTBUS].clk_prepare)
|
|
clk_disable(aud_clks[CLOCK_MUX_AUDIOINTBUS].clock);
|
|
|
|
break;
|
|
case NOTIFY_SOIDLE3_ENTER:
|
|
case NOTIFY_SOIDLE3_LEAVE:
|
|
default:
|
|
break;
|
|
}
|
|
return NOTIFY_OK;
|
|
}
|
|
|
|
#endif
|
|
|
|
#if defined(_MT_IDLE_HEADER) && !defined(CONFIG_FPGA_EARLY_PORTING)
|
|
static struct notifier_block audio_idle_nfb = {
|
|
.notifier_call = audio_idle_notify_call,
|
|
};
|
|
#endif
|
|
void AudDrv_Clk_Global_Variable_Init(void)
|
|
{
|
|
APLL1Counter = 0;
|
|
APLL2Counter = 0;
|
|
Aud_APLL_DIV_APLL1_cntr = 0;
|
|
Aud_APLL_DIV_APLL2_cntr = 0;
|
|
MCLKFS = 128;
|
|
MCLKFS_HDMI = 256;
|
|
#if defined(_MT_IDLE_HEADER) && !defined(CONFIG_FPGA_EARLY_PORTING)
|
|
mtk_idle_notifier_register(&audio_idle_nfb);
|
|
#endif
|
|
}
|
|
|
|
void AudDrv_Bus_Init(void)
|
|
{
|
|
/* No need on 6759, system default set bit14 to 1 */
|
|
}
|
|
void AudDrv_AUDINTBUS_Sel(int parentidx)
|
|
{
|
|
#if !defined(CONFIG_FPGA_EARLY_PORTING)
|
|
|
|
int ret = 0;
|
|
|
|
if (!aud_clks[CLOCK_MUX_AUDIOINTBUS].clk_prepare ||
|
|
!aud_clks[CLOCK_TOP_SYSPLL1_D4].clk_prepare ||
|
|
!aud_clks[CLOCK_CLK26M].clk_prepare) {
|
|
pr_debug("%s(), clk_prepare = false\n", __func__);
|
|
goto EXIT;
|
|
}
|
|
|
|
/* pr_debug("+AudDrv_AUDINTBUS_Sel, parentidx = %d\n", parentidx); */
|
|
if (parentidx == 1) {
|
|
ret = clk_set_parent(aud_clks[CLOCK_MUX_AUDIOINTBUS].clock,
|
|
aud_clks[CLOCK_TOP_SYSPLL1_D4].clock);
|
|
if (ret) {
|
|
pr_debug("%s clk_set_parent %s-%s fail %d\n", __func__,
|
|
aud_clks[CLOCK_MUX_AUDIOINTBUS].name,
|
|
aud_clks[CLOCK_TOP_SYSPLL1_D4].name, ret);
|
|
goto EXIT;
|
|
}
|
|
} else if (parentidx == 0) {
|
|
ret = clk_set_parent(aud_clks[CLOCK_MUX_AUDIOINTBUS].clock,
|
|
aud_clks[CLOCK_CLK26M].clock);
|
|
if (ret) {
|
|
pr_debug("%s clk_set_parent %s-%s fail %d\n", __func__,
|
|
aud_clks[CLOCK_MUX_AUDIOINTBUS].name,
|
|
aud_clks[CLOCK_CLK26M].name, ret);
|
|
goto EXIT;
|
|
}
|
|
}
|
|
EXIT:
|
|
/* pr_debug("-%s()\n", __func__); */
|
|
return;
|
|
#endif /* #if !defined(CONFIG_FPGA_EARLY_PORTING) */
|
|
}
|
|
#if !defined(CONFIG_FPGA_EARLY_PORTING)
|
|
static int apll1_mux_setting(bool enable)
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
if (!aud_clks[CLOCK_TOP_MUX_AUD_1].clk_prepare ||
|
|
!aud_clks[CLOCK_TOP_APLL1_CK].clk_prepare ||
|
|
!aud_clks[CLOCK_TOP_MUX_AUD_ENG1].clk_prepare ||
|
|
!aud_clks[CLOCK_TOP_APLL1_D8].clk_prepare ||
|
|
!aud_clks[CLOCK_CLK26M].clk_prepare) {
|
|
pr_debug("%s(), clk_prepare = false\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* pr_debug("+%s(), enable %d\n", __func__, enable); */
|
|
if (enable) {
|
|
/* CLOCK_TOP_MUX_AUD_1 */
|
|
if (aud_clk_enable(&aud_clks[CLOCK_TOP_MUX_AUD_1]))
|
|
goto EXIT;
|
|
|
|
ret = clk_set_parent(aud_clks[CLOCK_TOP_MUX_AUD_1].clock,
|
|
aud_clks[CLOCK_TOP_APLL1_CK].clock);
|
|
if (ret) {
|
|
pr_debug("%s clk_set_parent %s-%s fail %d\n",
|
|
__func__, aud_clks[CLOCK_TOP_MUX_AUD_1].name,
|
|
aud_clks[CLOCK_TOP_APLL1_CK].name, ret);
|
|
goto EXIT;
|
|
}
|
|
|
|
/* CLOCK_TOP_MUX_AUD_ENG1 */
|
|
if (aud_clk_enable(&aud_clks[CLOCK_TOP_MUX_AUD_ENG1]))
|
|
goto EXIT;
|
|
|
|
ret = clk_set_parent(aud_clks[CLOCK_TOP_MUX_AUD_ENG1].clock,
|
|
aud_clks[CLOCK_TOP_APLL1_D8].clock);
|
|
if (ret) {
|
|
pr_debug("%s clk_set_parent %s-%s fail %d\n",
|
|
__func__,
|
|
aud_clks[CLOCK_TOP_MUX_AUD_ENG1].name,
|
|
aud_clks[CLOCK_TOP_APLL1_D8].name, ret);
|
|
goto EXIT;
|
|
}
|
|
|
|
} else {
|
|
/* CLOCK_TOP_MUX_AUD_ENG1 */
|
|
ret = clk_set_parent(aud_clks[CLOCK_TOP_MUX_AUD_ENG1].clock,
|
|
aud_clks[CLOCK_CLK26M].clock);
|
|
if (ret) {
|
|
pr_debug("%s clk_set_parent %s-%s fail %d\n",
|
|
__func__,
|
|
aud_clks[CLOCK_TOP_MUX_AUD_ENG1].name,
|
|
aud_clks[CLOCK_CLK26M].name, ret);
|
|
goto EXIT;
|
|
}
|
|
if (aud_clks[CLOCK_TOP_MUX_AUD_ENG1].clk_prepare)
|
|
clk_disable(aud_clks[CLOCK_TOP_MUX_AUD_ENG1].clock);
|
|
|
|
/* CLOCK_TOP_MUX_AUD_1 */
|
|
ret = clk_set_parent(aud_clks[CLOCK_TOP_MUX_AUD_1].clock,
|
|
aud_clks[CLOCK_CLK26M].clock);
|
|
if (ret) {
|
|
pr_debug("%s clk_set_parent %s-%s fail %d\n",
|
|
__func__, aud_clks[CLOCK_TOP_MUX_AUD_1].name,
|
|
aud_clks[CLOCK_CLK26M].name, ret);
|
|
goto EXIT;
|
|
}
|
|
|
|
if (aud_clks[CLOCK_TOP_MUX_AUD_1].clk_prepare)
|
|
clk_disable(aud_clks[CLOCK_TOP_MUX_AUD_1].clock);
|
|
}
|
|
|
|
EXIT:
|
|
return 0;
|
|
}
|
|
|
|
static int apll2_mux_setting(bool enable)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (!aud_clks[CLOCK_TOP_MUX_AUD_1].clk_prepare ||
|
|
!aud_clks[CLOCK_TOP_APLL1_CK].clk_prepare ||
|
|
!aud_clks[CLOCK_TOP_MUX_AUD_ENG1].clk_prepare ||
|
|
!aud_clks[CLOCK_TOP_APLL1_D8].clk_prepare ||
|
|
!aud_clks[CLOCK_CLK26M].clk_prepare) {
|
|
pr_debug("%s(), clk_prepare = false\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* pr_debug("+%s(), enable %d\n", __func__, enable); */
|
|
if (enable) {
|
|
/* CLOCK_TOP_MUX_AUD_1 */
|
|
if (aud_clk_enable(&aud_clks[CLOCK_TOP_MUX_AUD_1]))
|
|
goto EXIT;
|
|
|
|
ret = clk_set_parent(aud_clks[CLOCK_TOP_MUX_AUD_1].clock,
|
|
aud_clks[CLOCK_TOP_APLL1_CK].clock);
|
|
if (ret) {
|
|
pr_debug("%s clk_set_parent %s-%s fail %d\n",
|
|
__func__, aud_clks[CLOCK_TOP_MUX_AUD_1].name,
|
|
aud_clks[CLOCK_TOP_APLL1_CK].name, ret);
|
|
goto EXIT;
|
|
}
|
|
|
|
/* CLOCK_TOP_MUX_AUD_ENG1 */
|
|
if (aud_clk_enable(&aud_clks[CLOCK_TOP_MUX_AUD_ENG1]))
|
|
goto EXIT;
|
|
|
|
ret = clk_set_parent(aud_clks[CLOCK_TOP_MUX_AUD_ENG1].clock,
|
|
aud_clks[CLOCK_TOP_APLL1_D8].clock);
|
|
if (ret) {
|
|
pr_debug("%s clk_set_parent %s-%s fail %d\n",
|
|
__func__,
|
|
aud_clks[CLOCK_TOP_MUX_AUD_ENG1].name,
|
|
aud_clks[CLOCK_TOP_APLL1_D8].name, ret);
|
|
goto EXIT;
|
|
}
|
|
|
|
} else {
|
|
/* CLOCK_TOP_MUX_AUD_ENG1 */
|
|
ret = clk_set_parent(aud_clks[CLOCK_TOP_MUX_AUD_ENG1].clock,
|
|
aud_clks[CLOCK_CLK26M].clock);
|
|
if (ret) {
|
|
pr_debug("%s clk_set_parent %s-%s fail %d\n",
|
|
__func__,
|
|
aud_clks[CLOCK_TOP_MUX_AUD_ENG1].name,
|
|
aud_clks[CLOCK_CLK26M].name, ret);
|
|
goto EXIT;
|
|
}
|
|
if (aud_clks[CLOCK_TOP_MUX_AUD_ENG1].clk_prepare)
|
|
clk_disable(aud_clks[CLOCK_TOP_MUX_AUD_ENG1].clock);
|
|
|
|
/* CLOCK_TOP_MUX_AUD_1 */
|
|
ret = clk_set_parent(aud_clks[CLOCK_TOP_MUX_AUD_1].clock,
|
|
aud_clks[CLOCK_CLK26M].clock);
|
|
if (ret) {
|
|
pr_debug("%s clk_set_parent %s-%s fail %d\n",
|
|
__func__, aud_clks[CLOCK_TOP_MUX_AUD_1].name,
|
|
aud_clks[CLOCK_CLK26M].name, ret);
|
|
goto EXIT;
|
|
}
|
|
|
|
if (aud_clks[CLOCK_TOP_MUX_AUD_1].clk_prepare)
|
|
clk_disable(aud_clks[CLOCK_TOP_MUX_AUD_1].clock);
|
|
}
|
|
|
|
EXIT:
|
|
return 0;
|
|
}
|
|
#endif
|
|
/*****************************************************************************
|
|
* FUNCTION
|
|
* AudDrv_Clk_On / AudDrv_Clk_Off
|
|
*
|
|
* DESCRIPTION
|
|
* Enable/Disable PLL(26M clock) \ AFE clock
|
|
*
|
|
****************************************************************************/
|
|
void AudDrv_Clk_On(void)
|
|
{
|
|
#if !defined(CONFIG_FPGA_EARLY_PORTING)
|
|
int ret = 0;
|
|
|
|
pr_debug("AudDrv_Clk_On, Aud_AFE_Clk_cntr:%d\n",
|
|
Aud_AFE_Clk_cntr);
|
|
mutex_lock(&auddrv_clk_mutex);
|
|
Aud_AFE_Clk_cntr++;
|
|
if (Aud_AFE_Clk_cntr == 1) {
|
|
#ifdef PM_MANAGER_API
|
|
#ifdef MT6739_scp
|
|
if (aud_clks[CLOCK_SCP_SYS_AUD].clk_status) {
|
|
ret = clk_prepare_enable(
|
|
aud_clks[CLOCK_SCP_SYS_AUD].clock);
|
|
if (ret) {
|
|
pr_debug("%s [CCF]Aud clk_prepare_enable %s fail\n",
|
|
__func__,
|
|
aud_clks[CLOCK_SCP_SYS_AUD].name);
|
|
goto EXIT;
|
|
}
|
|
}
|
|
#endif
|
|
if (aud_clk_enable(&aud_clks[CLOCK_INFRA_SYS_AUDIO]))
|
|
goto EXIT;
|
|
|
|
if (aud_clk_enable(&aud_clks[CLOCK_MUX_AUDIO]))
|
|
goto EXIT;
|
|
|
|
ret = clk_set_parent(aud_clks[CLOCK_MUX_AUDIO].clock,
|
|
aud_clks[CLOCK_CLK26M].clock);
|
|
if (ret) {
|
|
pr_debug("%s clk_set_parent %s-%s fail %d\n", __func__,
|
|
aud_clks[CLOCK_MUX_AUDIO].name,
|
|
aud_clks[CLOCK_CLK26M].name, ret);
|
|
}
|
|
|
|
/* AUD_INTBUS */
|
|
if (aud_clk_enable(&aud_clks[CLOCK_MUX_AUDIOINTBUS]))
|
|
goto EXIT;
|
|
AudDrv_AUDINTBUS_Sel(1);
|
|
|
|
if (aud_clk_enable(&aud_clks[CLOCK_AFE]))
|
|
goto EXIT;
|
|
|
|
if (aud_clk_enable(&aud_clks[CLOCK_DAC]))
|
|
goto EXIT;
|
|
|
|
if (aud_clk_enable(&aud_clks[CLOCK_DAC_PREDIS]))
|
|
goto EXIT;
|
|
|
|
if (aud_clk_enable(&aud_clks[CLOCK_MTKAIF_26M_CLK]))
|
|
goto EXIT;
|
|
/* enable audio sys DCM for power saving */
|
|
Afe_Set_Reg(AUDIO_TOP_CON0, 0x1 << 29, 0x1 << 29);
|
|
#else
|
|
SetInfraCfg(AUDIO_CG_CLR, 0x2000000, 0x2000000);
|
|
/* bit 25=0, without 133m master and 66m slave bus clock cg
|
|
* gating
|
|
*/
|
|
Afe_Set_Reg(AUDIO_TOP_CON0, 0x4000, 0x06004044);
|
|
#endif
|
|
}
|
|
EXIT:
|
|
mutex_unlock(&auddrv_clk_mutex);
|
|
#endif /* #if !defined(CONFIG_FPGA_EARLY_PORTING) */
|
|
}
|
|
EXPORT_SYMBOL(AudDrv_Clk_On);
|
|
|
|
void AudDrv_Clk_Off(void)
|
|
{
|
|
#if !defined(CONFIG_FPGA_EARLY_PORTING)
|
|
pr_debug("!! AudDrv_Clk_Off, Aud_AFE_Clk_cntr:%d\n",
|
|
Aud_AFE_Clk_cntr);
|
|
mutex_lock(&auddrv_clk_mutex);
|
|
|
|
Aud_AFE_Clk_cntr--;
|
|
if (Aud_AFE_Clk_cntr == 0) {
|
|
/* Disable AFE clock */
|
|
#ifdef PM_MANAGER_API
|
|
if (aud_clks[CLOCK_MTKAIF_26M_CLK].clk_prepare)
|
|
clk_disable(aud_clks[CLOCK_MTKAIF_26M_CLK].clock);
|
|
/* Make sure all IRQ status is cleared */
|
|
Afe_Set_Reg(AFE_IRQ_MCU_CLR, 0xffff, 0xffff);
|
|
Afe_Set_Reg(AFE_IRQ_MCU_CLR, 0xffff, 0xffff);
|
|
|
|
if (aud_clks[CLOCK_AFE].clk_prepare)
|
|
clk_disable(aud_clks[CLOCK_AFE].clock);
|
|
|
|
if (aud_clks[CLOCK_DAC].clk_prepare)
|
|
clk_disable(aud_clks[CLOCK_DAC].clock);
|
|
|
|
if (aud_clks[CLOCK_DAC_PREDIS].clk_prepare)
|
|
clk_disable(aud_clks[CLOCK_DAC_PREDIS].clock);
|
|
|
|
AudDrv_AUDINTBUS_Sel(0);
|
|
if (aud_clks[CLOCK_MUX_AUDIOINTBUS].clk_prepare)
|
|
clk_disable(aud_clks[CLOCK_MUX_AUDIOINTBUS].clock);
|
|
|
|
if (aud_clks[CLOCK_MUX_AUDIO].clk_prepare)
|
|
clk_disable(aud_clks[CLOCK_MUX_AUDIO].clock);
|
|
|
|
if (aud_clks[CLOCK_INFRA_SYS_AUDIO].clk_prepare)
|
|
clk_disable(aud_clks[CLOCK_INFRA_SYS_AUDIO].clock);
|
|
#ifdef MT6739_scp
|
|
if (aud_clks[CLOCK_SCP_SYS_AUD].clk_status)
|
|
clk_disable_unprepare(
|
|
aud_clks[CLOCK_SCP_SYS_AUD].clock);
|
|
#endif
|
|
#else
|
|
Afe_Set_Reg(AUDIO_TOP_CON0, 0x06000044, 0x06000044);
|
|
/* bit25=1, with 133m mastesr and 66m slave bus clock cg gating */
|
|
#endif
|
|
} else if (Aud_AFE_Clk_cntr < 0) {
|
|
pr_debug("!! AudDrv_Clk_Off, Aud_AFE_Clk_cntr<0 (%d)\n",
|
|
Aud_AFE_Clk_cntr);
|
|
Aud_AFE_Clk_cntr = 0;
|
|
}
|
|
mutex_unlock(&auddrv_clk_mutex);
|
|
#endif /* #if !defined(CONFIG_FPGA_EARLY_PORTING) */
|
|
}
|
|
EXPORT_SYMBOL(AudDrv_Clk_Off);
|
|
|
|
/*****************************************************************************
|
|
* FUNCTION
|
|
* AudDrv_ANA_Clk_On / AudDrv_ANA_Clk_Off
|
|
*
|
|
* DESCRIPTION
|
|
* Enable/Disable analog part clock
|
|
*
|
|
*****************************************************************************/
|
|
void AudDrv_ANA_Clk_On(void)
|
|
{
|
|
}
|
|
EXPORT_SYMBOL(AudDrv_ANA_Clk_On);
|
|
|
|
void AudDrv_ANA_Clk_Off(void)
|
|
{
|
|
}
|
|
EXPORT_SYMBOL(AudDrv_ANA_Clk_Off);
|
|
|
|
/*****************************************************************************
|
|
* FUNCTION
|
|
* AudDrv_ADC_Clk_On / AudDrv_ADC_Clk_Off
|
|
*
|
|
* DESCRIPTION
|
|
* Enable/Disable analog part clock
|
|
*
|
|
****************************************************************************
|
|
*/
|
|
|
|
void AudDrv_ADC_Clk_On(void)
|
|
{
|
|
int ret = 0;
|
|
unsigned long flags = 0;
|
|
|
|
spin_lock_irqsave(&auddrv_Clk_lock, flags);
|
|
|
|
if (Aud_ADC_Clk_cntr == 0) {
|
|
pr_debug("+%s enable_clock ADC clk(%x)\n", __func__,
|
|
Aud_ADC_Clk_cntr);
|
|
/* Afe_Set_Reg(AUDIO_TOP_CON0, 0 << 24 , 1 << 24); */
|
|
#ifdef PM_MANAGER_API
|
|
if (aud_clks[CLOCK_ADC].clk_prepare) {
|
|
ret = clk_enable(aud_clks[CLOCK_ADC].clock);
|
|
if (ret) {
|
|
pr_debug("%s [CCF]Aud enable_clock %s fail",
|
|
__func__, aud_clks[CLOCK_ADC].name);
|
|
goto EXIT;
|
|
}
|
|
} else {
|
|
pr_debug("%s [CCF]clk_prepare error %s fail", __func__,
|
|
aud_clks[CLOCK_ADC].name);
|
|
goto EXIT;
|
|
}
|
|
#else
|
|
Afe_Set_Reg(AUDIO_TOP_CON0, 0 << 24, 1 << 24);
|
|
#endif
|
|
}
|
|
Aud_ADC_Clk_cntr++;
|
|
EXIT:
|
|
spin_unlock_irqrestore(&auddrv_Clk_lock, flags);
|
|
}
|
|
|
|
void AudDrv_ADC_Clk_Off(void)
|
|
{
|
|
unsigned long flags = 0;
|
|
|
|
spin_lock_irqsave(&auddrv_Clk_lock, flags);
|
|
Aud_ADC_Clk_cntr--;
|
|
if (Aud_ADC_Clk_cntr == 0) {
|
|
pr_debug("+%s disable_clock ADC clk(%x)\n", __func__,
|
|
Aud_ADC_Clk_cntr);
|
|
#ifdef PM_MANAGER_API
|
|
if (aud_clks[CLOCK_ADC].clk_prepare)
|
|
clk_disable(aud_clks[CLOCK_ADC].clock);
|
|
#else
|
|
Afe_Set_Reg(AUDIO_TOP_CON0, 1 << 24, 1 << 24);
|
|
#endif
|
|
}
|
|
if (Aud_ADC_Clk_cntr < 0) {
|
|
pr_debug("!! %s, Aud_ADC_Clk_cntr<0 (%d)\n", __func__,
|
|
Aud_ADC_Clk_cntr);
|
|
Aud_ADC_Clk_cntr = 0;
|
|
}
|
|
spin_unlock_irqrestore(&auddrv_Clk_lock, flags);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* FUNCTION
|
|
* AudDrv_ADC2_Clk_On / AudDrv_ADC2_Clk_Off
|
|
*
|
|
* DESCRIPTION
|
|
* Enable/Disable clock
|
|
*
|
|
****************************************************************************
|
|
*/
|
|
|
|
void AudDrv_ADC2_Clk_On(void)
|
|
{
|
|
}
|
|
|
|
void AudDrv_ADC2_Clk_Off(void)
|
|
{
|
|
}
|
|
/*****************************************************************************
|
|
* FUNCTION
|
|
* AudDrv_ADC3_Clk_On / AudDrv_ADC3_Clk_Off
|
|
*
|
|
* DESCRIPTION
|
|
* Enable/Disable clock
|
|
*
|
|
****************************************************************************
|
|
*/
|
|
|
|
void AudDrv_ADC3_Clk_On(void)
|
|
{
|
|
}
|
|
|
|
void AudDrv_ADC3_Clk_Off(void)
|
|
{
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* FUNCTION
|
|
* AudDrv_ADC_Hires_Clk_On / AudDrv_ADC_Hires_Clk_Off
|
|
*
|
|
* DESCRIPTION
|
|
* Enable/Disable analog part clock
|
|
*
|
|
****************************************************************************
|
|
*/
|
|
|
|
void AudDrv_ADC_Hires_Clk_On(void)
|
|
{
|
|
}
|
|
|
|
void AudDrv_ADC_Hires_Clk_Off(void)
|
|
{
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* FUNCTION
|
|
* AudDrv_ADC2_Hires_Clk_On / AudDrv_ADC2_Hires_Clk_Off
|
|
*
|
|
* DESCRIPTION
|
|
* Enable/Disable analog part clock
|
|
*
|
|
****************************************************************************
|
|
*/
|
|
|
|
void AudDrv_ADC2_Hires_Clk_On(void)
|
|
{
|
|
}
|
|
|
|
void AudDrv_ADC2_Hires_Clk_Off(void)
|
|
{
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* FUNCTION
|
|
* AudDrv_APLL22M_Clk_On / AudDrv_APLL22M_Clk_Off
|
|
*
|
|
* DESCRIPTION
|
|
* Enable/Disable clock
|
|
*
|
|
****************************************************************************
|
|
*/
|
|
|
|
void AudDrv_APLL22M_Clk_On(void)
|
|
{
|
|
int ret = 0;
|
|
|
|
mutex_lock(&auddrv_clk_mutex);
|
|
/* pr_debug("%s counter = %d\n", __func__, Aud_APLL22M_Clk_cntr); */
|
|
|
|
if (Aud_APLL22M_Clk_cntr == 0) {
|
|
#ifdef PM_MANAGER_API
|
|
if (aud_clks[CLOCK_APMIXED_APLL1].clk_prepare) {
|
|
ret = clk_set_rate(aud_clks[CLOCK_APMIXED_APLL1].clock,
|
|
180633600);
|
|
if (ret) {
|
|
pr_debug("%s clk_set_rate %s-180633600 fail %d\n",
|
|
__func__,
|
|
aud_clks[CLOCK_APMIXED_APLL1].name,
|
|
ret);
|
|
goto EXIT;
|
|
}
|
|
}
|
|
if (aud_clks[CLOCK_APLL22M].clk_prepare) {
|
|
ret = clk_enable(aud_clks[CLOCK_APLL22M].clock);
|
|
if (ret) {
|
|
pr_debug("%s [CCF]Aud enable_clock %s fail",
|
|
__func__,
|
|
aud_clks[CLOCK_APLL22M].name);
|
|
goto EXIT;
|
|
}
|
|
} else {
|
|
pr_debug("%s [CCF]clk_prepare error %s fail", __func__,
|
|
aud_clks[CLOCK_APLL22M].name);
|
|
goto EXIT;
|
|
}
|
|
#endif
|
|
}
|
|
Aud_APLL22M_Clk_cntr++;
|
|
EXIT:
|
|
mutex_unlock(&auddrv_clk_mutex);
|
|
}
|
|
|
|
void AudDrv_APLL22M_Clk_Off(void)
|
|
{
|
|
unsigned long flags = 0;
|
|
|
|
spin_lock_irqsave(&auddrv_Clk_lock, flags);
|
|
/* pr_debug("%s: counter = %d\n", __func__, Aud_APLL22M_Clk_cntr); */
|
|
|
|
Aud_APLL22M_Clk_cntr--;
|
|
|
|
if (Aud_APLL22M_Clk_cntr == 0) {
|
|
#ifdef PM_MANAGER_API
|
|
if (aud_clks[CLOCK_APLL22M].clk_prepare)
|
|
clk_disable(aud_clks[CLOCK_APLL22M].clock);
|
|
else {
|
|
pr_debug("%s [CCF]clk_prepare error %s fail", __func__,
|
|
aud_clks[CLOCK_APLL22M].name);
|
|
goto EXIT;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
EXIT:
|
|
if (Aud_APLL22M_Clk_cntr < 0) {
|
|
pr_debug("err, %s <0 (%d)\n", __func__, Aud_APLL22M_Clk_cntr);
|
|
Aud_APLL22M_Clk_cntr = 0;
|
|
}
|
|
|
|
spin_unlock_irqrestore(&auddrv_Clk_lock, flags);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* FUNCTION
|
|
* AudDrv_APLL24M_Clk_On / AudDrv_APLL24M_Clk_Off
|
|
*
|
|
* DESCRIPTION
|
|
* Enable/Disable clock
|
|
*
|
|
****************************************************************************
|
|
*/
|
|
|
|
void AudDrv_APLL24M_Clk_On(void)
|
|
{
|
|
int ret = 0;
|
|
|
|
/* pr_debug("%s counter = %d\n", __func__, Aud_APLL24M_Clk_cntr); */
|
|
|
|
mutex_lock(&auddrv_clk_mutex);
|
|
|
|
if (Aud_APLL24M_Clk_cntr == 0) {
|
|
#ifdef PM_MANAGER_API
|
|
if (aud_clks[CLOCK_APMIXED_APLL1].clk_prepare) {
|
|
ret = clk_set_rate(aud_clks[CLOCK_APMIXED_APLL1].clock,
|
|
196608000);
|
|
if (ret) {
|
|
pr_debug("%s clk_set_rate %s-196608000 fail %d\n",
|
|
__func__,
|
|
aud_clks[CLOCK_APMIXED_APLL1].name,
|
|
ret);
|
|
goto EXIT;
|
|
}
|
|
}
|
|
if (aud_clks[CLOCK_APLL22M].clk_prepare) {
|
|
ret = clk_enable(aud_clks[CLOCK_APLL22M].clock);
|
|
if (ret) {
|
|
pr_debug("%s [CCF]Aud enable_clock %s fail",
|
|
__func__,
|
|
aud_clks[CLOCK_APLL22M].name);
|
|
goto EXIT;
|
|
}
|
|
} else {
|
|
pr_debug("%s [CCF]clk_prepare error %s fail",
|
|
__func__, aud_clks[CLOCK_APLL22M].name);
|
|
goto EXIT;
|
|
}
|
|
#endif
|
|
}
|
|
Aud_APLL24M_Clk_cntr++;
|
|
EXIT:
|
|
mutex_unlock(&auddrv_clk_mutex);
|
|
}
|
|
|
|
void AudDrv_APLL24M_Clk_Off(void)
|
|
{
|
|
unsigned long flags = 0;
|
|
|
|
pr_debug("+%s counter = %d\n", __func__, Aud_APLL24M_Clk_cntr);
|
|
|
|
spin_lock_irqsave(&auddrv_Clk_lock, flags);
|
|
|
|
Aud_APLL24M_Clk_cntr--;
|
|
|
|
if (Aud_APLL24M_Clk_cntr == 0) {
|
|
#ifdef PM_MANAGER_API
|
|
if (aud_clks[CLOCK_APLL22M].clk_prepare) {
|
|
clk_disable(aud_clks[CLOCK_APLL22M].clock);
|
|
} else {
|
|
pr_debug("%s [CCF]clk_prepare error %s fail",
|
|
__func__, aud_clks[CLOCK_APLL22M].name);
|
|
goto EXIT;
|
|
}
|
|
#endif
|
|
}
|
|
EXIT:
|
|
if (Aud_APLL24M_Clk_cntr < 0) {
|
|
pr_debug("%s <0 (%d)\n", __func__,
|
|
Aud_APLL24M_Clk_cntr);
|
|
Aud_APLL24M_Clk_cntr = 0;
|
|
}
|
|
|
|
spin_unlock_irqrestore(&auddrv_Clk_lock, flags);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* FUNCTION
|
|
* AudDrv_I2S_Clk_On / AudDrv_I2S_Clk_Off
|
|
*
|
|
* DESCRIPTION
|
|
* Enable I2S In clock (bck)
|
|
* This should be enabled in slave i2s mode.
|
|
*
|
|
****************************************************************************
|
|
*/
|
|
void aud_top_con_pdn_i2s(bool _pdn)
|
|
{
|
|
if (_pdn)
|
|
Afe_Set_Reg(AUDIO_TOP_CON0, 0x1 << 6,
|
|
0x1 << 6); /* power off I2S clock */
|
|
else
|
|
Afe_Set_Reg(AUDIO_TOP_CON0, 0x0 << 6,
|
|
0x1 << 6); /* power on I2S clock */
|
|
}
|
|
|
|
void AudDrv_I2S_Clk_On(void)
|
|
{
|
|
unsigned long flags = 0;
|
|
|
|
spin_lock_irqsave(&auddrv_Clk_lock, flags);
|
|
|
|
if (Aud_I2S_Clk_cntr == 0)
|
|
aud_top_con_pdn_i2s(false);
|
|
|
|
Aud_I2S_Clk_cntr++;
|
|
spin_unlock_irqrestore(&auddrv_Clk_lock, flags);
|
|
}
|
|
EXPORT_SYMBOL(AudDrv_I2S_Clk_On);
|
|
|
|
void AudDrv_I2S_Clk_Off(void)
|
|
{
|
|
unsigned long flags = 0;
|
|
|
|
spin_lock_irqsave(&auddrv_Clk_lock, flags);
|
|
Aud_I2S_Clk_cntr--;
|
|
if (Aud_I2S_Clk_cntr == 0) {
|
|
aud_top_con_pdn_i2s(true);
|
|
} else if (Aud_I2S_Clk_cntr < 0) {
|
|
pr_debug("!! AudDrv_I2S_Clk_Off, Aud_I2S_Clk_cntr<0 (%d)\n",
|
|
Aud_I2S_Clk_cntr);
|
|
Aud_I2S_Clk_cntr = 0;
|
|
}
|
|
spin_unlock_irqrestore(&auddrv_Clk_lock, flags);
|
|
}
|
|
EXPORT_SYMBOL(AudDrv_I2S_Clk_Off);
|
|
|
|
/*****************************************************************************
|
|
* FUNCTION
|
|
* AudDrv_TDM_Clk_On / AudDrv_TDM_Clk_Off
|
|
*
|
|
* DESCRIPTION
|
|
* Enable/Disable TDM clock
|
|
*
|
|
****************************************************************************
|
|
*/
|
|
void aud_top_con_pdn_tdm_ck(bool _pdn)
|
|
{
|
|
Afe_Set_Reg(AUDIO_TOP_CON0, _pdn << 20,
|
|
0x1 << 20); /* power on I2S clock */
|
|
}
|
|
|
|
void AudDrv_TDM_Clk_On(void)
|
|
{
|
|
unsigned long flags = 0;
|
|
|
|
spin_lock_irqsave(&auddrv_Clk_lock, flags);
|
|
if (Aud_TDM_Clk_cntr == 0)
|
|
aud_top_con_pdn_tdm_ck(false); /* enable HDMI CK */
|
|
|
|
Aud_TDM_Clk_cntr++;
|
|
spin_unlock_irqrestore(&auddrv_Clk_lock, flags);
|
|
}
|
|
EXPORT_SYMBOL(AudDrv_TDM_Clk_On);
|
|
|
|
void AudDrv_TDM_Clk_Off(void)
|
|
{
|
|
unsigned long flags = 0;
|
|
|
|
spin_lock_irqsave(&auddrv_Clk_lock, flags);
|
|
Aud_TDM_Clk_cntr--;
|
|
if (Aud_TDM_Clk_cntr == 0) {
|
|
aud_top_con_pdn_tdm_ck(true); /* disable HDMI CK */
|
|
} else if (Aud_TDM_Clk_cntr < 0) {
|
|
pr_debug("!! %s(), Aud_TDM_Clk_cntr<0 (%d)\n", __func__,
|
|
Aud_TDM_Clk_cntr);
|
|
Aud_TDM_Clk_cntr = 0;
|
|
}
|
|
spin_unlock_irqrestore(&auddrv_Clk_lock, flags);
|
|
}
|
|
EXPORT_SYMBOL(AudDrv_TDM_Clk_Off);
|
|
|
|
void AudDrv_APLL1Tuner_Clk_On(void)
|
|
{
|
|
unsigned long flags = 0;
|
|
int ret = 0;
|
|
|
|
spin_lock_irqsave(&auddrv_Clk_lock, flags);
|
|
if (Aud_APLL1_Tuner_cntr == 0) {
|
|
/* pr_debug("+%s, Aud_APLL1_Tuner_cntr:%d\n", __func__,
|
|
* Aud_APLL1_Tuner_cntr);
|
|
*/
|
|
#ifdef PM_MANAGER_API
|
|
if (aud_clks[CLOCK_APLL1_TUNER].clk_prepare) {
|
|
ret = clk_enable(aud_clks[CLOCK_APLL1_TUNER].clock);
|
|
if (ret) {
|
|
pr_debug("%s [CCF]Aud enable_clock %s fail\n",
|
|
__func__,
|
|
aud_clks[CLOCK_APLL1_TUNER].name);
|
|
goto EXIT;
|
|
}
|
|
} else {
|
|
pr_debug("%s [CCF]clk_prepare error %s fail\n",
|
|
__func__,
|
|
aud_clks[CLOCK_APLL1_TUNER].name);
|
|
goto EXIT;
|
|
}
|
|
#else
|
|
Afe_Set_Reg(AUDIO_TOP_CON0, 0x0 << 19, 0x1 << 19);
|
|
#endif
|
|
SetApmixedCfg(AP_PLL_CON5, 0x1, 0x1);
|
|
}
|
|
Aud_APLL1_Tuner_cntr++;
|
|
EXIT:
|
|
spin_unlock_irqrestore(&auddrv_Clk_lock, flags);
|
|
}
|
|
|
|
void AudDrv_APLL1Tuner_Clk_Off(void)
|
|
{
|
|
unsigned long flags = 0;
|
|
|
|
spin_lock_irqsave(&auddrv_Clk_lock, flags);
|
|
Aud_APLL1_Tuner_cntr--;
|
|
if (Aud_APLL1_Tuner_cntr == 0) {
|
|
SetApmixedCfg(AP_PLL_CON5, 0x0, 0x1);
|
|
#ifdef PM_MANAGER_API
|
|
if (aud_clks[CLOCK_APLL1_TUNER].clk_prepare)
|
|
clk_disable(aud_clks[CLOCK_APLL1_TUNER].clock);
|
|
#else
|
|
Afe_Set_Reg(AUDIO_TOP_CON0, 0x1 << 19, 0x1 << 19);
|
|
#endif
|
|
} else if (Aud_APLL1_Tuner_cntr < 0) {
|
|
pr_debug("!! %s, Aud_APLL1_Tuner_cntr<0 (%d)\n", __func__,
|
|
Aud_APLL1_Tuner_cntr);
|
|
Aud_APLL1_Tuner_cntr = 0;
|
|
}
|
|
spin_unlock_irqrestore(&auddrv_Clk_lock, flags);
|
|
}
|
|
|
|
void AudDrv_APLL2Tuner_Clk_On(void)
|
|
{
|
|
unsigned long flags = 0;
|
|
int ret = 0;
|
|
|
|
spin_lock_irqsave(&auddrv_Clk_lock, flags);
|
|
if (Aud_APLL2_Tuner_cntr == 0) {
|
|
/* pr_debug("+%s, Aud_APLL2_Tuner_cntr:%d\n", __func__,
|
|
* Aud_APLL2_Tuner_cntr);
|
|
*/
|
|
#ifdef PM_MANAGER_API
|
|
if (aud_clks[CLOCK_APLL1_TUNER].clk_prepare) {
|
|
ret = clk_enable(aud_clks[CLOCK_APLL1_TUNER].clock);
|
|
if (ret) {
|
|
pr_debug("%s [CCF]Aud enable_clock %s fail\n",
|
|
__func__,
|
|
aud_clks[CLOCK_APLL1_TUNER].name);
|
|
goto EXIT;
|
|
}
|
|
} else {
|
|
pr_debug("%s [CCF]clk_prepare error %s fail\n",
|
|
__func__, aud_clks[CLOCK_APLL1_TUNER].name);
|
|
goto EXIT;
|
|
}
|
|
#else
|
|
Afe_Set_Reg(AUDIO_TOP_CON0, 0x0 << 18, 0x1 << 18);
|
|
#endif
|
|
SetApmixedCfg(AP_PLL_CON5, 0x1, 0x1);
|
|
}
|
|
Aud_APLL2_Tuner_cntr++;
|
|
EXIT:
|
|
spin_unlock_irqrestore(&auddrv_Clk_lock, flags);
|
|
}
|
|
|
|
void AudDrv_APLL2Tuner_Clk_Off(void)
|
|
{
|
|
unsigned long flags = 0;
|
|
|
|
spin_lock_irqsave(&auddrv_Clk_lock, flags);
|
|
Aud_APLL2_Tuner_cntr--;
|
|
if (Aud_APLL2_Tuner_cntr == 0) {
|
|
SetApmixedCfg(AP_PLL_CON5, 0x0, 0x1);
|
|
#ifdef PM_MANAGER_API
|
|
if (aud_clks[CLOCK_APLL1_TUNER].clk_prepare)
|
|
clk_disable(aud_clks[CLOCK_APLL1_TUNER].clock);
|
|
#else
|
|
Afe_Set_Reg(AUDIO_TOP_CON0, 0x1 << 18, 0x1 << 18);
|
|
#endif
|
|
} else if (Aud_APLL2_Tuner_cntr < 0) {
|
|
pr_debug("!! %s, Aud_APLL1_Tuner_cntr<0 (%d)\n", __func__,
|
|
Aud_APLL2_Tuner_cntr);
|
|
Aud_APLL2_Tuner_cntr = 0;
|
|
}
|
|
spin_unlock_irqrestore(&auddrv_Clk_lock, flags);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* FUNCTION
|
|
* AudDrv_HDMI_Clk_On / AudDrv_HDMI_Clk_Off
|
|
*
|
|
* DESCRIPTION
|
|
* Enable/Disable analog part clock
|
|
*
|
|
****************************************************************************
|
|
*/
|
|
|
|
void AudDrv_HDMI_Clk_On(void)
|
|
{
|
|
#ifdef _NON_COMMON_FEATURE_READY
|
|
/* pr_debug("+AudDrv_HDMI_Clk_On, Aud_I2S_Clk_cntr:%d\n",
|
|
* Aud_HDMI_Clk_cntr);
|
|
*/
|
|
if (Aud_HDMI_Clk_cntr == 0) {
|
|
AudDrv_ANA_Clk_On();
|
|
AudDrv_Clk_On();
|
|
}
|
|
Aud_HDMI_Clk_cntr++;
|
|
#endif
|
|
}
|
|
|
|
void AudDrv_HDMI_Clk_Off(void)
|
|
{
|
|
#ifdef _NON_COMMON_FEATURE_READY
|
|
/* pr_debug("+AudDrv_HDMI_Clk_Off, Aud_I2S_Clk_cntr:%d\n",
|
|
* Aud_HDMI_Clk_cntr);
|
|
*/
|
|
Aud_HDMI_Clk_cntr--;
|
|
if (Aud_HDMI_Clk_cntr == 0) {
|
|
AudDrv_ANA_Clk_Off();
|
|
AudDrv_Clk_Off();
|
|
} else if (Aud_HDMI_Clk_cntr < 0) {
|
|
pr_debug("!! AudDrv_Linein_Clk_Off, Aud_I2S_Clk_cntr<0 (%d)\n",
|
|
Aud_HDMI_Clk_cntr);
|
|
Aud_HDMI_Clk_cntr = 0;
|
|
}
|
|
/* pr_debug("-AudDrv_I2S_Clk_Off, Aud_I2S_Clk_cntr:%d\n",
|
|
* Aud_HDMI_Clk_cntr);
|
|
*/
|
|
#endif
|
|
}
|
|
|
|
void AudDrv_Emi_Clk_On(void)
|
|
{
|
|
#if !defined(CONFIG_FPGA_EARLY_PORTING)
|
|
mutex_lock(&auddrv_pmic_mutex);
|
|
if (Aud_EMI_cntr == 0) {
|
|
#if defined(_MT_IDLE_HEADER)
|
|
/* mutex is used in these api */
|
|
spm_resource_req(SPM_RESOURCE_USER_AUDIO, SPM_RESOURCE_DRAM);
|
|
#endif
|
|
}
|
|
Aud_EMI_cntr++;
|
|
mutex_unlock(&auddrv_pmic_mutex);
|
|
#endif
|
|
}
|
|
|
|
void AudDrv_Emi_Clk_Off(void)
|
|
{
|
|
#if !defined(CONFIG_FPGA_EARLY_PORTING)
|
|
mutex_lock(&auddrv_pmic_mutex);
|
|
Aud_EMI_cntr--;
|
|
if (Aud_EMI_cntr == 0) {
|
|
#if defined(_MT_IDLE_HEADER)
|
|
/* mutex is used in these api */
|
|
spm_resource_req(SPM_RESOURCE_USER_AUDIO,
|
|
SPM_RESOURCE_RELEASE);
|
|
#endif
|
|
}
|
|
|
|
if (Aud_EMI_cntr < 0) {
|
|
Aud_EMI_cntr = 0;
|
|
pr_debug("Aud_EMI_cntr = %d\n", Aud_EMI_cntr);
|
|
}
|
|
mutex_unlock(&auddrv_pmic_mutex);
|
|
#endif
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* FUNCTION
|
|
* AudDrv_ANC_Clk_On / AudDrv_ANC_Clk_Off
|
|
*
|
|
* DESCRIPTION
|
|
* Enable/Disable ANC clock
|
|
*
|
|
****************************************************************************
|
|
*/
|
|
|
|
void AudDrv_ANC_Clk_On(void)
|
|
{
|
|
/* MT6759 no ANC */
|
|
}
|
|
|
|
void AudDrv_ANC_Clk_Off(void)
|
|
{
|
|
/* MT6759 no ANC*/
|
|
}
|
|
|
|
unsigned int GetApllbySampleRate(unsigned int SampleRate)
|
|
{
|
|
if (SampleRate == 176400 || SampleRate == 88200 ||
|
|
SampleRate == 44100 || SampleRate == 22050 ||
|
|
SampleRate == 11025)
|
|
return Soc_Aud_APLL1;
|
|
else
|
|
return Soc_Aud_APLL2;
|
|
}
|
|
|
|
void SetckSel(unsigned int I2snum, unsigned int SampleRate)
|
|
{
|
|
/* always from APLL1 */
|
|
unsigned int ApllSource;
|
|
|
|
ApllSource = 0; /* mt6739 only has one apll */
|
|
|
|
switch (I2snum) {
|
|
case Soc_Aud_I2S0:
|
|
clksys_set_reg(CLK_AUDDIV_0, ApllSource << 8, 1 << 8);
|
|
break;
|
|
case Soc_Aud_I2S1:
|
|
clksys_set_reg(CLK_AUDDIV_0, ApllSource << 9, 1 << 9);
|
|
break;
|
|
case Soc_Aud_I2S2:
|
|
clksys_set_reg(CLK_AUDDIV_0, ApllSource << 10, 1 << 10);
|
|
break;
|
|
case Soc_Aud_I2S3:
|
|
clksys_set_reg(CLK_AUDDIV_0, ApllSource << 11, 1 << 11);
|
|
break;
|
|
default:
|
|
pr_debug("%s(), not support I2snum %u\n", __func__, I2snum);
|
|
break;
|
|
}
|
|
pr_debug("%s I2snum = %d ApllSource = %d\n", __func__, I2snum,
|
|
ApllSource);
|
|
}
|
|
|
|
void EnableALLbySampleRate(unsigned int SampleRate)
|
|
{
|
|
pr_debug("%s, APLL1Counter = %d, APLL2Counter = %d, SampleRate = %d\n",
|
|
__func__, APLL1Counter, APLL2Counter, SampleRate);
|
|
|
|
switch (GetApllbySampleRate(SampleRate)) {
|
|
case Soc_Aud_APLL1:
|
|
APLL1Counter++;
|
|
if (APLL1Counter == 1) {
|
|
EnableApll1(true);
|
|
AudDrv_APLL1Tuner_Clk_On();
|
|
}
|
|
break;
|
|
case Soc_Aud_APLL2:
|
|
APLL2Counter++;
|
|
if (APLL2Counter == 1) {
|
|
EnableApll2(true);
|
|
AudDrv_APLL2Tuner_Clk_On();
|
|
}
|
|
break;
|
|
default:
|
|
pr_debug("%s, invalid SampleRate %d\n", __func__, SampleRate);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void DisableALLbySampleRate(unsigned int SampleRate)
|
|
{
|
|
pr_debug("%s, APLL1Counter = %d, APLL2Counter = %d, SampleRate = %d\n",
|
|
__func__, APLL1Counter, APLL2Counter, SampleRate);
|
|
|
|
switch (GetApllbySampleRate(SampleRate)) {
|
|
case Soc_Aud_APLL1:
|
|
APLL1Counter--;
|
|
if (APLL1Counter == 0) {
|
|
AudDrv_APLL1Tuner_Clk_Off();
|
|
EnableApll1(false);
|
|
} else if (APLL1Counter < 0) {
|
|
pr_debug("%s(), APLL1Counter %d < 0\n", __func__,
|
|
APLL1Counter);
|
|
APLL1Counter = 0;
|
|
}
|
|
break;
|
|
case Soc_Aud_APLL2:
|
|
APLL2Counter--;
|
|
if (APLL2Counter == 0) {
|
|
AudDrv_APLL2Tuner_Clk_Off();
|
|
EnableApll2(false);
|
|
} else if (APLL2Counter < 0) {
|
|
pr_debug("%s(), APLL2Counter %d < 0\n", __func__,
|
|
APLL2Counter);
|
|
APLL2Counter = 0;
|
|
}
|
|
break;
|
|
default:
|
|
pr_info("%s(), invalid SampleRate %d\n", __func__, SampleRate);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void EnableI2SDivPower(unsigned int Diveder_name, bool bEnable)
|
|
{
|
|
pr_debug("%s bEnable = %d\n", __func__, bEnable);
|
|
if (Diveder_name < AUDIO_APLL12_DIV5)
|
|
clksys_set_reg(CLK_AUDDIV_0, !bEnable << Diveder_name,
|
|
1 << Diveder_name);
|
|
else
|
|
clksys_set_reg(CLK_AUDDIV_2,
|
|
!bEnable << 16 /*APLL_apll12_div5_pdn_POS*/,
|
|
1 << 16);
|
|
}
|
|
|
|
void EnableI2SCLKDiv(unsigned int I2snum, bool bEnable)
|
|
{
|
|
pr_debug("%s mI2SAPLLDivSelect = %d, i2snum = %d\n", __func__,
|
|
mI2SAPLLDivSelect[I2snum], I2snum);
|
|
EnableI2SDivPower(mI2SAPLLDivSelect[I2snum], bEnable);
|
|
}
|
|
|
|
void EnableApll1(bool enable)
|
|
{
|
|
pr_debug("%s enable = %d\n", __func__, enable);
|
|
|
|
if (enable) {
|
|
if (Aud_APLL_DIV_APLL1_cntr == 0) {
|
|
clksys_set_reg(CLK_AUDDIV_0, 7 << 24, 0xf << 24);
|
|
AudDrv_APLL22M_Clk_On();
|
|
apll1_mux_setting(true);
|
|
Afe_Set_Reg(AFE_HD_ENGEN_ENABLE, 0x1 << 0, 0x1 << 0);
|
|
}
|
|
Aud_APLL_DIV_APLL1_cntr++;
|
|
} else {
|
|
Aud_APLL_DIV_APLL1_cntr--;
|
|
if (Aud_APLL_DIV_APLL1_cntr == 0) {
|
|
Afe_Set_Reg(AFE_HD_ENGEN_ENABLE, 0x0 << 0, 0x1 << 0);
|
|
apll1_mux_setting(false);
|
|
AudDrv_APLL22M_Clk_Off();
|
|
}
|
|
}
|
|
}
|
|
|
|
void EnableApll2(bool enable)
|
|
{
|
|
/* pr_debug("%s enable = %d\n", __func__, enable); */
|
|
|
|
if (enable) {
|
|
if (Aud_APLL_DIV_APLL2_cntr == 0) {
|
|
clksys_set_reg(CLK_AUDDIV_0, 7 << 24, 0xf << 24);
|
|
AudDrv_APLL24M_Clk_On();
|
|
apll2_mux_setting(true);
|
|
Afe_Set_Reg(AFE_HD_ENGEN_ENABLE, 0x1 << 1, 0x1 << 1);
|
|
}
|
|
Aud_APLL_DIV_APLL2_cntr++;
|
|
} else {
|
|
Aud_APLL_DIV_APLL2_cntr--;
|
|
if (Aud_APLL_DIV_APLL2_cntr == 0) {
|
|
Afe_Set_Reg(AFE_HD_ENGEN_ENABLE, 0x0 << 1, 0x1 << 1);
|
|
apll2_mux_setting(false);
|
|
AudDrv_APLL24M_Clk_Off();
|
|
}
|
|
}
|
|
}
|
|
|
|
unsigned int SetCLkMclk(unsigned int I2snum, unsigned int SampleRate)
|
|
{
|
|
unsigned int I2S_APll = 0;
|
|
unsigned int I2s_ck_div = 0;
|
|
|
|
if (GetApllbySampleRate(SampleRate) == Soc_Aud_APLL1)
|
|
I2S_APll = APLL_44K_BASE;
|
|
else
|
|
I2S_APll = APLL_48K_BASE;
|
|
|
|
SetckSel(I2snum, SampleRate); /* set I2Sx mck source */
|
|
|
|
switch (I2snum) {
|
|
case Soc_Aud_I2S0:
|
|
I2s_ck_div = (I2S_APll / MCLKFS / SampleRate) - 1;
|
|
clksys_set_reg(CLK_AUDDIV_1, I2s_ck_div << 0, 0xff << 0);
|
|
break;
|
|
case Soc_Aud_I2S1:
|
|
I2s_ck_div = (I2S_APll / MCLKFS / SampleRate) - 1;
|
|
clksys_set_reg(CLK_AUDDIV_1, I2s_ck_div << 8, 0xff << 8);
|
|
break;
|
|
case Soc_Aud_I2S2:
|
|
I2s_ck_div = (I2S_APll / MCLKFS / SampleRate) - 1;
|
|
clksys_set_reg(CLK_AUDDIV_1, I2s_ck_div << 16, 0xff << 16);
|
|
break;
|
|
case Soc_Aud_I2S3:
|
|
I2s_ck_div = (I2S_APll / MCLKFS / SampleRate) - 1;
|
|
clksys_set_reg(CLK_AUDDIV_1, I2s_ck_div << 24, 0xff << 24);
|
|
break;
|
|
default:
|
|
pr_debug("[AudioWarn] SetCLkMclk: I2snum = %d not recognized\n",
|
|
I2snum);
|
|
break;
|
|
}
|
|
|
|
pr_debug("%s I2snum = %d I2s_ck_div = %d I2S_APll = %d\n", __func__,
|
|
I2snum, I2s_ck_div, I2S_APll);
|
|
|
|
return I2s_ck_div;
|
|
}
|
|
|
|
void SetCLkBclk(unsigned int MckDiv, unsigned int SampleRate,
|
|
unsigned int Channels, unsigned int Wlength)
|
|
{
|
|
}
|
|
|
|
void PowerDownAllI2SDiv(void)
|
|
{
|
|
int i = 0;
|
|
|
|
for (i = AUDIO_APLL1_DIV0; i < AUDIO_APLL_DIV_NUM; i++)
|
|
EnableI2SDivPower(i, false);
|
|
}
|
|
|