Skip to content

Commit

Permalink
ASoC: Intel: sof_da7219: add adl_mx98360_da7219 board config
Browse files Browse the repository at this point in the history
This configuration supports ADL boards which implement DA7219 on SSP0
and MAX98360A on SSP1. DA7219 uses PLL bypass mode to avoid WCLK
locking problem. To use this mode, MCLK frequency must be 12.288 or
24.576MHz.

Signed-off-by: Brent Lu <[email protected]>
  • Loading branch information
brentlu committed Aug 29, 2023
1 parent 6c5415c commit b0e9b32
Show file tree
Hide file tree
Showing 2 changed files with 208 additions and 26 deletions.
227 changes: 201 additions & 26 deletions sound/soc/intel/boards/sof_da7219.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <linux/platform_device.h>
#include <sound/soc.h>
#include <sound/soc-acpi.h>
#include <sound/sof.h>
#include "../../codecs/da7219.h"
#include "hda_dsp_common.h"
#include "sof_maxim_common.h"
Expand All @@ -21,6 +22,10 @@
#define SOF_MAX98360A_SPEAKER_AMP_PRESENT BIT(0)
#define SOF_MAX98373_SPEAKER_AMP_PRESENT BIT(1)

/* Other flags */
#define SOF_DA7219_JSL_BOARD BIT(2)
#define SOF_DA7219_PLL_BYPASS BIT(3)

#define DIALOG_CODEC_DAI "da7219-hifi"

struct hdmi_pcm {
Expand All @@ -33,16 +38,23 @@ struct card_private {
struct snd_soc_jack headset_jack;
struct list_head hdmi_pcm_list;
struct snd_soc_jack hdmi[3];

unsigned int pll_bypass:1;
};

static int platform_clock_control(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
struct snd_soc_dapm_context *dapm = w->dapm;
struct snd_soc_card *card = dapm->card;
struct card_private *ctx = snd_soc_card_get_drvdata(card);
struct snd_soc_dai *codec_dai;
int ret = 0;

if (ctx->pll_bypass)
return ret;

/* PLL SRM mode */
codec_dai = snd_soc_card_get_codec_dai(card, DIALOG_CODEC_DAI);
if (!codec_dai) {
dev_err(card->dev, "Codec dai not found; Unable to set/unset codec pll\n");
Expand All @@ -55,6 +67,8 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
if (ret)
dev_err(card->dev, "failed to stop PLL: %d\n", ret);
} else if (SND_SOC_DAPM_EVENT_ON(event)) {
dev_dbg(card->dev, "pll srm mode\n");

ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_PLL_SRM,
0, DA7219_PLL_FREQ_OUT_98304);
if (ret)
Expand Down Expand Up @@ -124,14 +138,6 @@ static int da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_jack *jack = &ctx->headset_jack;
int ret;

/* Configure sysclk for codec */
ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, 24000000,
SND_SOC_CLOCK_IN);
if (ret) {
dev_err(rtd->dev, "can't set codec sysclk configuration\n");
return ret;
}

/*
* Headset buttons map to the google Reference headset.
* These can be configured by userspace.
Expand Down Expand Up @@ -160,6 +166,51 @@ static int da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}

static int da7219_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
int mclk_rate, ret;

mclk_rate = sof_dai_get_mclk(rtd);
if (mclk_rate <= 0) {
dev_err(rtd->dev, "invalid mclk freq %d\n", mclk_rate);
return -EINVAL;
}

ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, mclk_rate,
SND_SOC_CLOCK_IN);
if (ret) {
dev_err(rtd->dev, "fail to set sysclk, ret %d\n", ret);
return ret;
}

if (ctx->pll_bypass) {
/* PLL bypass mode */
dev_dbg(rtd->dev, "pll bypass mode, mclk rate %d\n", mclk_rate);

if (mclk_rate != 12288000 && mclk_rate != 24576000 &&
mclk_rate != 49152000) {
dev_err(rtd->dev, "invalid mclk freq %d\n", mclk_rate);
return -EINVAL;
}

ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK, 0, 0);
if (ret) {
dev_err(rtd->dev, "fail to set pll, ret %d\n", ret);
return ret;
}
}

return ret;
}

static const struct snd_soc_ops da7219_ops = {
.hw_params = da7219_hw_params,
};

static int max98373_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
Expand Down Expand Up @@ -236,6 +287,11 @@ SND_SOC_DAILINK_DEF(ssp0_codec,
SND_SOC_DAILINK_DEF(ssp1_pin,
DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin")));

SND_SOC_DAILINK_DEF(ssp2_pin,
DAILINK_COMP_ARRAY(COMP_CPU("SSP2 Pin")));
SND_SOC_DAILINK_DEF(dummy_codec,
DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")));

SND_SOC_DAILINK_DEF(dmic_pin,
DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin")));
SND_SOC_DAILINK_DEF(dmic_codec,
Expand All @@ -259,10 +315,15 @@ SND_SOC_DAILINK_DEF(idisp3_pin,
SND_SOC_DAILINK_DEF(idisp3_codec,
DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3")));

SND_SOC_DAILINK_DEF(idisp4_pin,
DAILINK_COMP_ARRAY(COMP_CPU("iDisp4 Pin")));
SND_SOC_DAILINK_DEF(idisp4_codec,
DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi4")));

SND_SOC_DAILINK_DEF(platform, /* subject to be overridden during probe */
DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3")));

static struct snd_soc_dai_link dais[] = {
static struct snd_soc_dai_link jsl_dais[] = {
/* Back End DAI links */
{
.name = "SSP1-Codec",
Expand All @@ -278,6 +339,7 @@ static struct snd_soc_dai_link dais[] = {
.id = 1,
.no_pcm = 1,
.init = da7219_codec_init,
.ops = &da7219_ops,
.ignore_pmdown_time = 1,
.dpcm_playback = 1,
.dpcm_capture = 1,
Expand Down Expand Up @@ -325,11 +387,89 @@ static struct snd_soc_dai_link dais[] = {
}
};

static struct snd_soc_dai_link adl_dais[] = {
/* Back End DAI links */
{
.name = "SSP0-Codec",
.id = 0,
.no_pcm = 1,
.init = da7219_codec_init,
.ops = &da7219_ops,
.ignore_pmdown_time = 1,
.dpcm_playback = 1,
.dpcm_capture = 1,
SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform),
},
{
.name = "dmic01",
.id = 1,
.ignore_suspend = 1,
.dpcm_capture = 1,
.no_pcm = 1,
SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform),
},
{
.name = "dmic16k",
.id = 2,
.ignore_suspend = 1,
.dpcm_capture = 1,
.no_pcm = 1,
SND_SOC_DAILINK_REG(dmic16k_pin, dmic_codec, platform),
},
{
.name = "iDisp1",
.id = 3,
.init = hdmi_init,
.dpcm_playback = 1,
.no_pcm = 1,
SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform),
},
{
.name = "iDisp2",
.id = 4,
.init = hdmi_init,
.dpcm_playback = 1,
.no_pcm = 1,
SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform),
},
{
.name = "iDisp3",
.id = 5,
.init = hdmi_init,
.dpcm_playback = 1,
.no_pcm = 1,
SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform),
},
{
.name = "iDisp4",
.id = 6,
.init = hdmi_init,
.dpcm_playback = 1,
.no_pcm = 1,
SND_SOC_DAILINK_REG(idisp4_pin, idisp4_codec, platform),
},
{
.name = "SSP1-Codec",
.id = 7,
.no_pcm = 1,
.dpcm_playback = 1,
/* feedback stream or firmware-generated echo reference */
.dpcm_capture = 1,
SND_SOC_DAILINK_REG(ssp1_pin, max_98373_components, platform),
},
{
.name = "SSP2-BT",
.id = 8,
.no_pcm = 1,
.dpcm_playback = 1,
.dpcm_capture = 1,
SND_SOC_DAILINK_REG(ssp2_pin, dummy_codec, platform),
},
};

static struct snd_soc_card card_da7219 = {
.name = "da7219", /* the sof- prefix is added by the core */
.owner = THIS_MODULE,
.dai_link = dais,
.num_links = ARRAY_SIZE(dais),
.controls = controls,
.num_controls = ARRAY_SIZE(controls),
.dapm_widgets = widgets,
Expand All @@ -343,9 +483,10 @@ static struct snd_soc_card card_da7219 = {
static int audio_probe(struct platform_device *pdev)
{
struct snd_soc_acpi_mach *mach = pdev->dev.platform_data;
struct snd_soc_dai_link *dai_links;
struct card_private *ctx;
unsigned long board_quirk = 0;
int ret;
int ret, amp_idx;

ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
Expand All @@ -354,30 +495,57 @@ static int audio_probe(struct platform_device *pdev)
if (pdev->id_entry && pdev->id_entry->driver_data)
board_quirk = (unsigned long)pdev->id_entry->driver_data;

/* backward-compatible with existing devices */
if (board_quirk & SOF_MAX98360A_SPEAKER_AMP_PRESENT)
card_da7219.name = devm_kstrdup(&pdev->dev, "da7219max98360a",
GFP_KERNEL);
else if (board_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT)
card_da7219.name = devm_kstrdup(&pdev->dev, "da7219max",
GFP_KERNEL);
if (board_quirk & SOF_DA7219_JSL_BOARD) {
/* backward-compatible with existing devices */
if (board_quirk & SOF_MAX98360A_SPEAKER_AMP_PRESENT)
card_da7219.name = devm_kstrdup(&pdev->dev,
"da7219max98360a",
GFP_KERNEL);
else if (board_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT)
card_da7219.name = devm_kstrdup(&pdev->dev, "da7219max",
GFP_KERNEL);

dai_links = jsl_dais;
amp_idx = 0;

card_da7219.num_links = ARRAY_SIZE(jsl_dais);
} else {
dai_links = adl_dais;
amp_idx = 7;

card_da7219.num_links = ARRAY_SIZE(adl_dais);
}

dev_dbg(&pdev->dev, "board_quirk = %lx\n", board_quirk);

/* speaker amp */
if (board_quirk & SOF_MAX98360A_SPEAKER_AMP_PRESENT) {
max_98360a_dai_link(&dais[0]);
max_98360a_dai_link(&dai_links[amp_idx]);
} else if (board_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT) {
dais[0].codecs = max_98373_components;
dais[0].num_codecs = ARRAY_SIZE(max_98373_components);
dais[0].init = max_98373_spk_codec_init;
dais[0].ops = &max98373_ops; /* use local ops */
dai_links[amp_idx].codecs = max_98373_components;
dai_links[amp_idx].num_codecs = ARRAY_SIZE(max_98373_components);
dai_links[amp_idx].init = max_98373_spk_codec_init;
if (board_quirk & SOF_DA7219_JSL_BOARD) {
dai_links[amp_idx].ops = &max98373_ops; /* use local ops */
} else {
/* TBD: implement the amp for later platform */
dev_err(&pdev->dev, "max98373 not support yet\n");
return -EINVAL;
}

max_98373_set_codec_conf(&card_da7219);
}

card_da7219.dai_link = dai_links;

INIT_LIST_HEAD(&ctx->hdmi_pcm_list);

/* Use PLL bypass mode if MCLK is available, be sure to set the
* frequency of MCLK to 12.288 or 24.576MHz on topology side.
*/
if (board_quirk & SOF_DA7219_PLL_BYPASS)
ctx->pll_bypass = 1;

card_da7219.dev = &pdev->dev;

ret = snd_soc_fixup_dai_links_platform_name(&card_da7219,
Expand All @@ -393,11 +561,18 @@ static int audio_probe(struct platform_device *pdev)
static const struct platform_device_id board_ids[] = {
{
.name = "sof_da7219_mx98373",
.driver_data = (kernel_ulong_t)(SOF_MAX98373_SPEAKER_AMP_PRESENT),
.driver_data = (kernel_ulong_t)(SOF_MAX98373_SPEAKER_AMP_PRESENT |
SOF_DA7219_JSL_BOARD),
},
{
.name = "sof_da7219_mx98360a",
.driver_data = (kernel_ulong_t)(SOF_MAX98360A_SPEAKER_AMP_PRESENT),
.driver_data = (kernel_ulong_t)(SOF_MAX98360A_SPEAKER_AMP_PRESENT |
SOF_DA7219_JSL_BOARD),
},
{
.name = "adl_mx98360_da7219",
.driver_data = (kernel_ulong_t)(SOF_MAX98360A_SPEAKER_AMP_PRESENT |
SOF_DA7219_PLL_BYPASS),
},
{ }
};
Expand Down
7 changes: 7 additions & 0 deletions sound/soc/intel/common/soc-acpi-intel-adl-match.c
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = {
SND_SOC_ACPI_TPLG_INTEL_SSP_MSB |
SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER,
},
{
.id = "DLGS7219",
.drv_name = "adl_mx98360_da7219",
.machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &adl_max98360a_amp,
.sof_tplg_filename = "sof-adl-max98360a-da7219.tplg",
},
/* place amp-only boards in the end of table */
{
.id = "CSC3541",
Expand Down

0 comments on commit b0e9b32

Please sign in to comment.