|
@@ -28,6 +28,9 @@
|
|
#include "../../codecs/rt5663.h"
|
|
#include "../../codecs/rt5663.h"
|
|
#include "../../codecs/hdac_hdmi.h"
|
|
#include "../../codecs/hdac_hdmi.h"
|
|
#include "../skylake/skl.h"
|
|
#include "../skylake/skl.h"
|
|
|
|
+#include <linux/clk.h>
|
|
|
|
+#include <linux/clk-provider.h>
|
|
|
|
+#include <linux/clkdev.h>
|
|
|
|
|
|
#define KBL_REALTEK_CODEC_DAI "rt5663-aif"
|
|
#define KBL_REALTEK_CODEC_DAI "rt5663-aif"
|
|
#define KBL_MAXIM_CODEC_DAI "max98927-aif1"
|
|
#define KBL_MAXIM_CODEC_DAI "max98927-aif1"
|
|
@@ -48,6 +51,8 @@ struct kbl_hdmi_pcm {
|
|
struct kbl_rt5663_private {
|
|
struct kbl_rt5663_private {
|
|
struct snd_soc_jack kabylake_headset;
|
|
struct snd_soc_jack kabylake_headset;
|
|
struct list_head hdmi_pcm_list;
|
|
struct list_head hdmi_pcm_list;
|
|
|
|
+ struct clk *mclk;
|
|
|
|
+ struct clk *sclk;
|
|
};
|
|
};
|
|
|
|
|
|
enum {
|
|
enum {
|
|
@@ -69,6 +74,61 @@ static const struct snd_kcontrol_new kabylake_controls[] = {
|
|
SOC_DAPM_PIN_SWITCH("Right Spk"),
|
|
SOC_DAPM_PIN_SWITCH("Right Spk"),
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+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 kbl_rt5663_private *priv = snd_soc_card_get_drvdata(card);
|
|
|
|
+ int ret = 0;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * MCLK/SCLK need to be ON early for a successful synchronization of
|
|
|
|
+ * codec internal clock. And the clocks are turned off during
|
|
|
|
+ * POST_PMD after the stream is stopped.
|
|
|
|
+ */
|
|
|
|
+ switch (event) {
|
|
|
|
+ case SND_SOC_DAPM_PRE_PMU:
|
|
|
|
+ /* Enable MCLK */
|
|
|
|
+ ret = clk_set_rate(priv->mclk, 24000000);
|
|
|
|
+ if (ret < 0) {
|
|
|
|
+ dev_err(card->dev, "Can't set rate for mclk, err: %d\n",
|
|
|
|
+ ret);
|
|
|
|
+ return ret;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ret = clk_prepare_enable(priv->mclk);
|
|
|
|
+ if (ret < 0) {
|
|
|
|
+ dev_err(card->dev, "Can't enable mclk, err: %d\n", ret);
|
|
|
|
+ return ret;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Enable SCLK */
|
|
|
|
+ ret = clk_set_rate(priv->sclk, 3072000);
|
|
|
|
+ if (ret < 0) {
|
|
|
|
+ dev_err(card->dev, "Can't set rate for sclk, err: %d\n",
|
|
|
|
+ ret);
|
|
|
|
+ clk_disable_unprepare(priv->mclk);
|
|
|
|
+ return ret;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ret = clk_prepare_enable(priv->sclk);
|
|
|
|
+ if (ret < 0) {
|
|
|
|
+ dev_err(card->dev, "Can't enable sclk, err: %d\n", ret);
|
|
|
|
+ clk_disable_unprepare(priv->mclk);
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ case SND_SOC_DAPM_POST_PMD:
|
|
|
|
+ clk_disable_unprepare(priv->mclk);
|
|
|
|
+ clk_disable_unprepare(priv->sclk);
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
static const struct snd_soc_dapm_widget kabylake_widgets[] = {
|
|
static const struct snd_soc_dapm_widget kabylake_widgets[] = {
|
|
SND_SOC_DAPM_HP("Headphone Jack", NULL),
|
|
SND_SOC_DAPM_HP("Headphone Jack", NULL),
|
|
SND_SOC_DAPM_MIC("Headset Mic", NULL),
|
|
SND_SOC_DAPM_MIC("Headset Mic", NULL),
|
|
@@ -78,11 +138,14 @@ static const struct snd_soc_dapm_widget kabylake_widgets[] = {
|
|
SND_SOC_DAPM_SPK("HDMI1", NULL),
|
|
SND_SOC_DAPM_SPK("HDMI1", NULL),
|
|
SND_SOC_DAPM_SPK("HDMI2", NULL),
|
|
SND_SOC_DAPM_SPK("HDMI2", NULL),
|
|
SND_SOC_DAPM_SPK("HDMI3", NULL),
|
|
SND_SOC_DAPM_SPK("HDMI3", NULL),
|
|
-
|
|
|
|
|
|
+ SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
|
|
|
|
+ platform_clock_control, SND_SOC_DAPM_PRE_PMU |
|
|
|
|
+ SND_SOC_DAPM_POST_PMD),
|
|
};
|
|
};
|
|
|
|
|
|
static const struct snd_soc_dapm_route kabylake_map[] = {
|
|
static const struct snd_soc_dapm_route kabylake_map[] = {
|
|
/* HP jack connectors - unknown if we have jack detection */
|
|
/* HP jack connectors - unknown if we have jack detection */
|
|
|
|
+ { "Headphone Jack", NULL, "Platform Clock" },
|
|
{ "Headphone Jack", NULL, "HPOL" },
|
|
{ "Headphone Jack", NULL, "HPOL" },
|
|
{ "Headphone Jack", NULL, "HPOR" },
|
|
{ "Headphone Jack", NULL, "HPOR" },
|
|
|
|
|
|
@@ -91,6 +154,7 @@ static const struct snd_soc_dapm_route kabylake_map[] = {
|
|
{ "Right Spk", NULL, "Right BE_OUT" },
|
|
{ "Right Spk", NULL, "Right BE_OUT" },
|
|
|
|
|
|
/* other jacks */
|
|
/* other jacks */
|
|
|
|
+ { "Headset Mic", NULL, "Platform Clock" },
|
|
{ "IN1P", NULL, "Headset Mic" },
|
|
{ "IN1P", NULL, "Headset Mic" },
|
|
{ "IN1N", NULL, "Headset Mic" },
|
|
{ "IN1N", NULL, "Headset Mic" },
|
|
{ "DMic", NULL, "SoC DMIC" },
|
|
{ "DMic", NULL, "SoC DMIC" },
|
|
@@ -901,6 +965,7 @@ static int kabylake_audio_probe(struct platform_device *pdev)
|
|
{
|
|
{
|
|
struct kbl_rt5663_private *ctx;
|
|
struct kbl_rt5663_private *ctx;
|
|
struct skl_machine_pdata *pdata;
|
|
struct skl_machine_pdata *pdata;
|
|
|
|
+ int ret;
|
|
|
|
|
|
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
|
|
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
|
|
if (!ctx)
|
|
if (!ctx)
|
|
@@ -919,6 +984,34 @@ static int kabylake_audio_probe(struct platform_device *pdev)
|
|
dmic_constraints = pdata->dmic_num == 2 ?
|
|
dmic_constraints = pdata->dmic_num == 2 ?
|
|
&constraints_dmic_2ch : &constraints_dmic_channels;
|
|
&constraints_dmic_2ch : &constraints_dmic_channels;
|
|
|
|
|
|
|
|
+ ctx->mclk = devm_clk_get(&pdev->dev, "ssp1_mclk");
|
|
|
|
+ if (IS_ERR(ctx->mclk)) {
|
|
|
|
+ ret = PTR_ERR(ctx->mclk);
|
|
|
|
+ if (ret == -ENOENT) {
|
|
|
|
+ dev_info(&pdev->dev,
|
|
|
|
+ "Failed to get ssp1_sclk, defer probe\n");
|
|
|
|
+ return -EPROBE_DEFER;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ dev_err(&pdev->dev, "Failed to get ssp1_mclk with err:%d\n",
|
|
|
|
+ ret);
|
|
|
|
+ return ret;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ctx->sclk = devm_clk_get(&pdev->dev, "ssp1_sclk");
|
|
|
|
+ if (IS_ERR(ctx->sclk)) {
|
|
|
|
+ ret = PTR_ERR(ctx->sclk);
|
|
|
|
+ if (ret == -ENOENT) {
|
|
|
|
+ dev_info(&pdev->dev,
|
|
|
|
+ "Failed to get ssp1_sclk, defer probe\n");
|
|
|
|
+ return -EPROBE_DEFER;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ dev_err(&pdev->dev, "Failed to get ssp1_sclk with err:%d\n",
|
|
|
|
+ ret);
|
|
|
|
+ return ret;
|
|
|
|
+ }
|
|
|
|
+
|
|
return devm_snd_soc_register_card(&pdev->dev, kabylake_audio_card);
|
|
return devm_snd_soc_register_card(&pdev->dev, kabylake_audio_card);
|
|
}
|
|
}
|
|
|
|
|