audio: auge: add lower power mode for PDM & vad [1/1]

PD#SWPL-3825

Problem:
VAD & PDM works in 24m clks for lowpower mode when in deep suspend

Solution:
support VAD & PDM in 24m sysclk, 768k dclk

Verify:
x301

Change-Id: Ic363337ee9b0eba0f890ae62b9e0cb6bb54dcd6a
Signed-off-by: Xing Wang <xing.wang@amlogic.com>
This commit is contained in:
Xing Wang
2019-01-19 16:05:46 +08:00
committed by Tao Zeng
parent 4f4b07abdb
commit 9eace31508
17 changed files with 227 additions and 44 deletions

View File

@@ -1429,7 +1429,6 @@
pinctrl-0 = <&spdifout_a>;
pinctrl-1 = <&spdifout_a_mute>;
/*
* whether do asrc for pcm and resample a or b
* if raw data, asrc is disabled automatically

View File

@@ -1651,7 +1651,7 @@
*/
level = <1>;
status = "disabled";
status = "okay";
};
loopbacka:loopback@0 {

View File

@@ -1647,7 +1647,7 @@
*/
level = <1>;
status = "disabled";
status = "okay";
};
loopbacka:loopback@0 {

View File

@@ -1646,7 +1646,7 @@
*/
level = <1>;
status = "disabled";
status = "okay";
};
loopbacka:loopback@0 {

View File

@@ -1641,7 +1641,7 @@
*/
level = <1>;
status = "disabled";
status = "okay";
};
loopbacka:loopback@0 {

View File

@@ -28,6 +28,8 @@
#include <sound/soc.h>
#include <sound/tlv.h>
#include <linux/amlogic/pm.h>
#include "pdm.h"
#include "pdm_hw.h"
#include "pdm_match_table.c"
@@ -230,6 +232,100 @@ static int pdm_bypass_set_enum(
return 0;
}
static const char *const pdm_lowpower_texts[] = {
"PDM Normal Mode",
"PDM Low Power Mode",
};
static const struct soc_enum pdm_lowpower_enum =
SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(pdm_lowpower_texts),
pdm_lowpower_texts);
static void pdm_set_lowpower_mode(struct aml_pdm *p_pdm, bool isLowPower)
{
if (p_pdm->isLowPower == isLowPower)
return;
p_pdm->isLowPower = isLowPower;
if (p_pdm->clk_on) {
int osr, filter_mode, dclk_idx;
if (p_pdm->isLowPower) {
/* dclk for 768k */
dclk_idx = 2;
pr_info("%s force pdm sysclk to 24m, dclk 768k\n",
__func__);
} else
dclk_idx = p_pdm->dclk_idx;
clk_set_rate(p_pdm->clk_pdm_dclk,
pdm_dclkidx2rate(dclk_idx));
/* filter for pdm */
osr = pdm_get_ors(dclk_idx, p_pdm->rate);
if (!osr)
osr = 192;
filter_mode = p_pdm->isLowPower ? 4 : p_pdm->filter_mode;
aml_pdm_filter_ctrl(osr, filter_mode);
/* update sample count */
pdm_set_channel_ctrl(
pdm_get_sample_count(
p_pdm->isLowPower,
dclk_idx)
);
/* check to set pdm sysclk */
pdm_force_sysclk_to_oscin(p_pdm->isLowPower);
pr_info("\n%s, pdm_sysclk:%lu pdm_dclk:%lu, dclk_srcpll:%lu\n",
__func__,
clk_get_rate(p_pdm->clk_pdm_sysclk),
clk_get_rate(p_pdm->clk_pdm_dclk),
clk_get_rate(p_pdm->dclk_srcpll));
/* Check to set vad for Low Power */
if (vad_pdm_is_running())
vad_set_lowerpower_mode(p_pdm->isLowPower);
}
}
static int pdm_lowpower_get_enum(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct aml_pdm *p_pdm = dev_get_drvdata(component->dev);
if (!p_pdm)
return 0;
ucontrol->value.enumerated.item[0] = p_pdm->isLowPower;
return 0;
}
static int pdm_lowpower_set_enum(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct aml_pdm *p_pdm = dev_get_drvdata(component->dev);
bool isLowPower;
if (!p_pdm)
return 0;
isLowPower = (bool)ucontrol->value.enumerated.item[0];
pdm_set_lowpower_mode(p_pdm, isLowPower);
return 0;
}
static const char *const pdm_train_texts[] = {
"Disabled",
"Enable",
@@ -293,6 +389,11 @@ static const struct snd_kcontrol_new snd_pdm_controls[] = {
pdm_dclk_get_enum,
pdm_dclk_set_enum),
SOC_ENUM_EXT("PDM Low Power mode",
pdm_lowpower_enum,
pdm_lowpower_get_enum,
pdm_lowpower_set_enum),
SOC_ENUM_EXT("PDM Train",
pdm_train_enum,
pdm_train_get_enum,
@@ -766,7 +867,7 @@ static int aml_pdm_dai_prepare(
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
struct toddr *to = p_pdm->tddr;
struct toddr_fmt fmt;
unsigned int osr = 192, filter_mode;
unsigned int osr = 192, filter_mode, dclk_idx;
struct pdm_info info;
/* to ddr pdmin */
@@ -781,29 +882,41 @@ static int aml_pdm_dai_prepare(
aml_toddr_set_format(to, &fmt);
aml_toddr_set_fifos(to, 0x40);
info.bitdepth = bitwidth;
info.channels = runtime->channels;
info.lane_masks = p_pdm->lane_mask_in;
info.dclk_idx = p_pdm->dclk_idx;
info.bypass = p_pdm->bypass;
info.sample_count = pdm_get_sample_count(p_pdm->isLowPower,
p_pdm->dclk_idx);
aml_pdm_ctrl(&info);
/* force pdm sysclk to 24m */
if (p_pdm->isLowPower) {
/* dclk for 768k */
dclk_idx = 2;
filter_mode = 4;
pdm_force_sysclk_to_oscin(true);
if (vad_pdm_is_running())
vad_set_lowerpower_mode(true);
filter_mode = p_pdm->filter_mode;
} else {
dclk_idx = p_pdm->dclk_idx;
filter_mode = p_pdm->filter_mode;
}
/* filter for pdm */
osr = pdm_get_ors(p_pdm->dclk_idx, runtime->rate);
osr = pdm_get_ors(dclk_idx, runtime->rate);
if (!osr)
return -EINVAL;
pr_info("%s, pdm_dclk:%d, osr:%d, rate:%d filter mode:%d\n",
__func__,
pdm_dclkidx2rate(p_pdm->dclk_idx),
pdm_dclkidx2rate(dclk_idx),
osr,
runtime->rate,
p_pdm->filter_mode);
info.bitdepth = bitwidth;
info.channels = runtime->channels;
info.lane_masks = p_pdm->lane_mask_in;
info.dclk_idx = dclk_idx;
info.bypass = p_pdm->bypass;
info.sample_count = pdm_get_sample_count(p_pdm->isLowPower,
dclk_idx);
aml_pdm_ctrl(&info);
aml_pdm_filter_ctrl(osr, filter_mode);
if (p_pdm->chipinfo && p_pdm->chipinfo->truncate_data)
@@ -871,6 +984,11 @@ static int aml_pdm_dai_set_sysclk(struct snd_soc_dai *cpu_dai,
{
struct aml_pdm *p_pdm = snd_soc_dai_get_drvdata(cpu_dai);
unsigned int sysclk_srcpll_freq, dclk_srcpll_freq;
unsigned int dclk_idx = p_pdm->dclk_idx;
/* lowpower, force dclk to 768k */
if (p_pdm->isLowPower)
dclk_idx = 2;
sysclk_srcpll_freq = clk_get_rate(p_pdm->sysclk_srcpll);
dclk_srcpll_freq = clk_get_rate(p_pdm->dclk_srcpll);
@@ -886,7 +1004,7 @@ static int aml_pdm_dai_set_sysclk(struct snd_soc_dai *cpu_dai,
clk_set_rate(p_pdm->dclk_srcpll, 24576000);
#endif
clk_set_rate(p_pdm->clk_pdm_dclk,
pdm_dclkidx2rate(p_pdm->dclk_idx));
pdm_dclkidx2rate(dclk_idx));
pr_info("\n%s, pdm_sysclk:%lu pdm_dclk:%lu, dclk_srcpll:%lu\n",
__func__,
@@ -969,6 +1087,11 @@ void aml_pdm_dai_shutdown(struct snd_pcm_substream *substream,
p_pdm->clk_on = false;
p_pdm->rate = 0;
if (p_pdm->isLowPower) {
pdm_force_sysclk_to_oscin(false);
vad_set_lowerpower_mode(false);
}
/* disable clock and gate */
clk_disable_unprepare(p_pdm->clk_pdm_dclk);
clk_disable_unprepare(p_pdm->clk_pdm_sysclk);
@@ -1145,6 +1268,8 @@ static int aml_pdm_platform_probe(struct platform_device *pdev)
/* defulat set 1 */
p_pdm->filter_mode = 1;
}
pr_info("%s pdm filter mode from dts:%d\n",
__func__, p_pdm->filter_mode);
p_pdm->dev = dev;
dev_set_drvdata(&pdev->dev, p_pdm);
@@ -1181,23 +1306,55 @@ static int aml_pdm_platform_remove(struct platform_device *pdev)
snd_soc_unregister_component(&pdev->dev);
snd_soc_unregister_codec(&pdev->dev);
snd_soc_unregister_platform(&pdev->dev);
return 0;
}
static int pdm_platform_suspend(
struct platform_device *pdev, pm_message_t state)
{
struct aml_pdm *p_pdm = dev_get_drvdata(&pdev->dev);
/* whether in freeze */
if (is_pm_freeze_mode()
&& vad_pdm_is_running()) {
pr_info("%s, Entry in freeze\n", __func__);
pdm_set_lowpower_mode(p_pdm, true);
}
return 0;
}
static int pdm_platform_resume(
struct platform_device *pdev)
{
struct aml_pdm *p_pdm = dev_get_drvdata(&pdev->dev);
/* whether in freeze mode */
if (is_pm_freeze_mode()
&& vad_pdm_is_running()) {
pr_info("%s, Exist from freeze\n", __func__);
pdm_set_lowpower_mode(p_pdm, false);
}
return 0;
}
struct platform_driver aml_pdm_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(aml_pdm_device_id),
},
.probe = aml_pdm_platform_probe,
.remove = aml_pdm_platform_remove,
.probe = aml_pdm_platform_probe,
.remove = aml_pdm_platform_remove,
.suspend = pdm_platform_suspend,
.resume = pdm_platform_resume,
};
module_platform_driver(aml_pdm_driver);
MODULE_AUTHOR("AMLogic, Inc.");
MODULE_DESCRIPTION("Amlogic PDM ASoc driver");
MODULE_LICENSE("GPL");

View File

@@ -69,6 +69,10 @@ struct aml_pdm {
struct clk *clk_pdm_sysclk;
struct clk *clk_pdm_dclk;
struct toddr *tddr;
struct pdm_chipinfo *chipinfo;
struct snd_kcontrol *controls[PDM_RUN_MAX];
/* sample rate */
int rate;
/*
@@ -93,9 +97,6 @@ struct aml_pdm {
/* low power mode, for dclk_sycpll to 24m */
bool isLowPower;
struct pdm_chipinfo *chipinfo;
struct snd_kcontrol *controls[PDM_RUN_MAX];
};
#endif /*__AML_PDM_H__*/

View File

@@ -59,6 +59,11 @@ void pdm_fifo_reset(void)
0x1 << 16);
}
void pdm_force_sysclk_to_oscin(bool force)
{
audiobus_update_bits(EE_AUDIO_CLK_PDMIN_CTRL1, 0x1 << 30, force << 30);
}
void pdm_set_channel_ctrl(int sample_count)
{
aml_pdm_write(PDM_CHAN_CTRL, ((sample_count << 24) |
@@ -547,14 +552,16 @@ int pdm_get_ors(int dclk_idx, int sample_rate)
else if (sample_rate == 8000)
osr = 128;
else
pr_err("Not support rate:%d\n", sample_rate);
pr_err("%s, Not support rate:%d\n",
__func__, sample_rate);
} else if (dclk_idx == 2) {
if (sample_rate == 16000)
osr = 48;
else if (sample_rate == 8000)
osr = 96;
else
pr_err("Not support rate:%d\n", sample_rate);
pr_err("%s, Not support rate:%d\n",
__func__, sample_rate);
} else {
if (sample_rate == 96000)
osr = 32;
@@ -569,7 +576,8 @@ int pdm_get_ors(int dclk_idx, int sample_rate)
else if (sample_rate == 8000)
osr = 384;
else
pr_err("Not support rate:%d\n", sample_rate);
pr_err("%s, Not support rate:%d\n",
__func__, sample_rate);
}
return osr;

View File

@@ -34,6 +34,9 @@ struct pdm_info {
extern void aml_pdm_ctrl(struct pdm_info *info);
extern void pdm_force_sysclk_to_oscin(bool force);
extern void pdm_set_channel_ctrl(int sample_count);
extern void aml_pdm_arb_config(struct aml_audio_controller *actrl);
extern int aml_pmd_set_HPF_filter_parameters(void *array);

View File

@@ -107,7 +107,7 @@ enum clk_sel {
#define EE_AUDIO_CLK_RESAMPLEB_CTRL 0x02e
#define EE_AUDIO_CLK_SPDIFIN_LB_CTRL 0x02f
#define EE_AUDIO_CLK_EQDRC_CTRL0 0x030
#define EE_AUDIO_VAD_CLK_CTRL 0x031
#define EE_AUDIO_CLK_VAD_CTRL 0x031
#define EE_AUDIO_EARCTX_CMDC_CLK_CTRL 0x032
#define EE_AUDIO_EARCTX_DMAC_CLK_CTRL 0x033
#define EE_AUDIO_EARCRX_CMDC_CLK_CTRL 0x034

View File

@@ -244,9 +244,9 @@ CLOCK_COM_MUX(eqdrc, AUD_ADDR_OFFSET(EE_AUDIO_CLK_EQDRC_CTRL0), 0x7, 24);
CLOCK_COM_DIV(eqdrc, AUD_ADDR_OFFSET(EE_AUDIO_CLK_EQDRC_CTRL0), 0, 16);
CLOCK_COM_GATE(eqdrc, AUD_ADDR_OFFSET(EE_AUDIO_CLK_EQDRC_CTRL0), 31);
/* audio vad */
CLOCK_COM_MUX(vad, AUD_ADDR_OFFSET(EE_AUDIO_VAD_CLK_CTRL), 0x7, 24);
CLOCK_COM_DIV(vad, AUD_ADDR_OFFSET(EE_AUDIO_VAD_CLK_CTRL), 0, 16);
CLOCK_COM_GATE(vad, AUD_ADDR_OFFSET(EE_AUDIO_VAD_CLK_CTRL), 31);
CLOCK_COM_MUX(vad, AUD_ADDR_OFFSET(EE_AUDIO_CLK_VAD_CTRL), 0x7, 24);
CLOCK_COM_DIV(vad, AUD_ADDR_OFFSET(EE_AUDIO_CLK_VAD_CTRL), 0, 16);
CLOCK_COM_GATE(vad, AUD_ADDR_OFFSET(EE_AUDIO_CLK_VAD_CTRL), 31);
/* EARC TX CMDC */
CLOCK_COM_MUX(earctx_cmdc,
AUD_ADDR_OFFSET(EE_AUDIO_EARCTX_CMDC_CLK_CTRL), 0x7, 24);

View File

@@ -231,9 +231,9 @@ CLOCK_COM_MUX(eqdrc, AUD_ADDR_OFFSET(EE_AUDIO_CLK_EQDRC_CTRL0), 0x7, 24);
CLOCK_COM_DIV(eqdrc, AUD_ADDR_OFFSET(EE_AUDIO_CLK_EQDRC_CTRL0), 0, 16);
CLOCK_COM_GATE(eqdrc, AUD_ADDR_OFFSET(EE_AUDIO_CLK_EQDRC_CTRL0), 31);
/* audio vad */
CLOCK_COM_MUX(vad, AUD_ADDR_OFFSET(EE_AUDIO_VAD_CLK_CTRL), 0x7, 24);
CLOCK_COM_DIV(vad, AUD_ADDR_OFFSET(EE_AUDIO_VAD_CLK_CTRL), 0, 16);
CLOCK_COM_GATE(vad, AUD_ADDR_OFFSET(EE_AUDIO_VAD_CLK_CTRL), 31);
CLOCK_COM_MUX(vad, AUD_ADDR_OFFSET(EE_AUDIO_CLK_VAD_CTRL), 0x7, 24);
CLOCK_COM_DIV(vad, AUD_ADDR_OFFSET(EE_AUDIO_CLK_VAD_CTRL), 0, 16);
CLOCK_COM_GATE(vad, AUD_ADDR_OFFSET(EE_AUDIO_CLK_VAD_CTRL), 31);
static int tl1_clks_init(struct clk **clks, void __iomem *iobase)
{

View File

@@ -260,9 +260,9 @@ CLOCK_COM_MUX(eqdrc, AUD_ADDR_OFFSET(EE_AUDIO_CLK_EQDRC_CTRL0), 0x7, 24);
CLOCK_COM_DIV(eqdrc, AUD_ADDR_OFFSET(EE_AUDIO_CLK_EQDRC_CTRL0), 0, 16);
CLOCK_COM_GATE(eqdrc, AUD_ADDR_OFFSET(EE_AUDIO_CLK_EQDRC_CTRL0), 31);
/* audio vad */
CLOCK_COM_MUX(vad, AUD_ADDR_OFFSET(EE_AUDIO_VAD_CLK_CTRL), 0x7, 24);
CLOCK_COM_DIV(vad, AUD_ADDR_OFFSET(EE_AUDIO_VAD_CLK_CTRL), 0, 16);
CLOCK_COM_GATE(vad, AUD_ADDR_OFFSET(EE_AUDIO_VAD_CLK_CTRL), 31);
CLOCK_COM_MUX(vad, AUD_ADDR_OFFSET(EE_AUDIO_CLK_VAD_CTRL), 0x7, 24);
CLOCK_COM_DIV(vad, AUD_ADDR_OFFSET(EE_AUDIO_CLK_VAD_CTRL), 0, 16);
CLOCK_COM_GATE(vad, AUD_ADDR_OFFSET(EE_AUDIO_CLK_VAD_CTRL), 31);
/* EARC TX CMDC */
CLOCK_COM_MUX(earctx_cmdc,
AUD_ADDR_OFFSET(EE_AUDIO_EARCTX_CMDC_CLK_CTRL), 0x7, 24);

View File

@@ -541,6 +541,11 @@ static void vad_deinit(struct vad *p_vad)
vad_set_clks(p_vad, false);
}
void vad_set_lowerpower_mode(bool isLowPower)
{
vad_force_clk_to_oscin(isLowPower);
}
void vad_update_buffer(int isvad)
{
struct vad *p_vad = get_vad();
@@ -561,7 +566,7 @@ void vad_update_buffer(int isvad)
p_vad->start_last = tddr->start_addr;
p_vad->end_last = tddr->end_addr;
rd_th = 0x100;
rd_th = 0x800;
pr_debug("Switch to VAD buffer\n");
pr_debug("\t ASAL start:%x, end:%x, bytes:%d\n",
@@ -1003,7 +1008,8 @@ static int vad_platform_probe(struct platform_device *pdev)
return 0;
}
int vad_platform_suspend(struct platform_device *pdev, pm_message_t state)
static int vad_platform_suspend(
struct platform_device *pdev, pm_message_t state)
{
struct device *dev = &pdev->dev;
struct vad *p_vad = dev_get_drvdata(dev);
@@ -1022,7 +1028,8 @@ int vad_platform_suspend(struct platform_device *pdev, pm_message_t state)
return 0;
}
int vad_platform_resume(struct platform_device *pdev)
static int vad_platform_resume(
struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct vad *p_vad = dev_get_drvdata(dev);

View File

@@ -44,4 +44,5 @@ extern void vad_set_trunk_data_readable(bool en);
extern int card_add_vad_kcontrols(struct snd_soc_card *card);
extern void vad_set_lowerpower_mode(bool isLowPower);
#endif

View File

@@ -107,3 +107,8 @@ void vad_set_enable(bool enable)
vad_write(VAD_TOP_CTRL1, 0x0);
}
}
void vad_force_clk_to_oscin(bool force)
{
audiobus_update_bits(EE_AUDIO_CLK_VAD_CTRL, 0x1 << 30, force << 30);
}

View File

@@ -35,4 +35,6 @@ extern void vad_set_src(int src);
extern void vad_set_in(void);
extern void vad_set_enable(bool enable);
extern void vad_force_clk_to_oscin(bool force);
#endif