0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/acpi.h>
0010 #include <sound/core.h>
0011 #include <linux/device.h>
0012 #include <linux/errno.h>
0013 #include <linux/gfp.h>
0014 #include <sound/jack.h>
0015 #include <linux/kernel.h>
0016 #include <linux/list.h>
0017 #include <linux/module.h>
0018 #include <sound/pcm.h>
0019 #include <sound/pcm_params.h>
0020 #include <sound/soc.h>
0021 #include <sound/soc-acpi.h>
0022
0023 #include "hda_dsp_common.h"
0024 #include "../../codecs/rt5660.h"
0025
0026 #define DUAL_CHANNEL 2
0027 #define HDMI_LINK_START 3
0028 #define HDMI_LINE_END 6
0029 #define NAME_SIZE 32
0030 #define IDISP_CODEC_MASK 0x4
0031
0032 struct sof_card_private {
0033 struct list_head hdmi_pcm_list;
0034 bool idisp_codec;
0035 };
0036
0037 static const struct snd_kcontrol_new rt5660_controls[] = {
0038 SOC_DAPM_PIN_SWITCH("Speaker"),
0039
0040 SOC_DAPM_PIN_SWITCH("Headset Mic"),
0041 SOC_DAPM_PIN_SWITCH("Headset Mic2"),
0042 SOC_DAPM_PIN_SWITCH("Line Out"),
0043 };
0044
0045 static const struct snd_soc_dapm_widget rt5660_widgets[] = {
0046 SND_SOC_DAPM_SPK("Speaker", NULL),
0047 SND_SOC_DAPM_MIC("Headset Mic", NULL),
0048 SND_SOC_DAPM_MIC("Headset Mic2", NULL),
0049 SND_SOC_DAPM_MIC("SoC DMIC", NULL),
0050 SND_SOC_DAPM_LINE("Line Out", NULL),
0051 };
0052
0053 static const struct snd_soc_dapm_route rt5660_map[] = {
0054 {"Speaker", NULL, "SPO"},
0055
0056 {"Headset Mic", NULL, "MICBIAS1"},
0057 {"Headset Mic2", NULL, "MICBIAS2"},
0058
0059 {"IN1P", NULL, "Headset Mic"},
0060 {"IN2P", NULL, "Headset Mic2"},
0061
0062 {"Line Out", NULL, "LOUTL"},
0063 {"Line Out", NULL, "LOUTR"},
0064
0065 {"DMic", NULL, "SoC DMIC"},
0066 };
0067
0068 struct sof_hdmi_pcm {
0069 struct list_head head;
0070 struct snd_soc_dai *codec_dai;
0071 int device;
0072 };
0073
0074 static int hdmi_init(struct snd_soc_pcm_runtime *rtd)
0075 {
0076 struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
0077 struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
0078 struct sof_hdmi_pcm *pcm;
0079
0080 pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
0081 if (!pcm)
0082 return -ENOMEM;
0083
0084
0085 pcm->device = rtd->dai_link->id;
0086 pcm->codec_dai = dai;
0087
0088 list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
0089
0090 return 0;
0091 }
0092
0093 static int card_late_probe(struct snd_soc_card *card)
0094 {
0095 struct sof_card_private *ctx = snd_soc_card_get_drvdata(card);
0096 struct sof_hdmi_pcm *pcm;
0097
0098 if (list_empty(&ctx->hdmi_pcm_list))
0099 return -ENOENT;
0100
0101 if (!ctx->idisp_codec)
0102 return 0;
0103
0104 pcm = list_first_entry(&ctx->hdmi_pcm_list, struct sof_hdmi_pcm, head);
0105
0106 return hda_dsp_hdmi_build_controls(card, pcm->codec_dai->component);
0107 }
0108
0109 static int rt5660_hw_params(struct snd_pcm_substream *substream,
0110 struct snd_pcm_hw_params *params)
0111 {
0112 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0113 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
0114 int ret;
0115
0116 ret = snd_soc_dai_set_sysclk(codec_dai,
0117 RT5660_SCLK_S_PLL1,
0118 params_rate(params) * 512,
0119 SND_SOC_CLOCK_IN);
0120 if (ret < 0) {
0121 dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
0122 return ret;
0123 }
0124
0125 ret = snd_soc_dai_set_pll(codec_dai, 0,
0126 RT5660_PLL1_S_BCLK,
0127 params_rate(params) * 50,
0128 params_rate(params) * 512);
0129 if (ret < 0)
0130 dev_err(codec_dai->dev, "can't set codec pll: %d\n", ret);
0131
0132 return ret;
0133 }
0134
0135 static struct snd_soc_ops rt5660_ops = {
0136 .hw_params = rt5660_hw_params,
0137 };
0138
0139 SND_SOC_DAILINK_DEF(ssp0_pin,
0140 DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin")));
0141
0142 SND_SOC_DAILINK_DEF(rt5660_codec,
0143 DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5660:00", "rt5660-aif1")));
0144
0145 SND_SOC_DAILINK_DEF(platform,
0146 DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3")));
0147
0148 SND_SOC_DAILINK_DEF(dmic_pin,
0149 DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin")));
0150 SND_SOC_DAILINK_DEF(dmic_codec,
0151 DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi")));
0152 SND_SOC_DAILINK_DEF(dmic16k,
0153 DAILINK_COMP_ARRAY(COMP_CPU("DMIC16k Pin")));
0154
0155 SND_SOC_DAILINK_DEF(idisp1_pin,
0156 DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin")));
0157 SND_SOC_DAILINK_DEF(idisp1_codec,
0158 DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1")));
0159
0160 SND_SOC_DAILINK_DEF(idisp2_pin,
0161 DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin")));
0162 SND_SOC_DAILINK_DEF(idisp2_codec,
0163 DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2")));
0164
0165 SND_SOC_DAILINK_DEF(idisp3_pin,
0166 DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin")));
0167 SND_SOC_DAILINK_DEF(idisp3_codec,
0168 DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3")));
0169
0170 SND_SOC_DAILINK_DEF(idisp4_pin,
0171 DAILINK_COMP_ARRAY(COMP_CPU("iDisp4 Pin")));
0172 SND_SOC_DAILINK_DEF(idisp4_codec,
0173 DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi4")));
0174
0175 static struct snd_soc_dai_link ehl_rt5660_dailink[] = {
0176
0177 {
0178 .name = "SSP0-Codec",
0179 .id = 0,
0180 .no_pcm = 1,
0181 .dpcm_playback = 1,
0182 .dpcm_capture = 1,
0183 .ops = &rt5660_ops,
0184 SND_SOC_DAILINK_REG(ssp0_pin, rt5660_codec, platform),
0185 },
0186 {
0187 .name = "dmic48k",
0188 .id = 1,
0189 .ignore_suspend = 1,
0190 .dpcm_capture = 1,
0191 .no_pcm = 1,
0192 SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform),
0193 },
0194 {
0195 .name = "dmic16k",
0196 .id = 2,
0197 .ignore_suspend = 1,
0198 .dpcm_capture = 1,
0199 .no_pcm = 1,
0200 SND_SOC_DAILINK_REG(dmic16k, dmic_codec, platform),
0201 },
0202 {
0203 .name = "iDisp1",
0204 .id = 5,
0205 .init = hdmi_init,
0206 .dpcm_playback = 1,
0207 .no_pcm = 1,
0208 SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform),
0209 },
0210 {
0211 .name = "iDisp2",
0212 .id = 6,
0213 .init = hdmi_init,
0214 .dpcm_playback = 1,
0215 .no_pcm = 1,
0216 SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform),
0217 },
0218 {
0219 .name = "iDisp3",
0220 .id = 7,
0221 .init = hdmi_init,
0222 .dpcm_playback = 1,
0223 .no_pcm = 1,
0224 SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform),
0225 },
0226 {
0227 .name = "iDisp4",
0228 .id = 8,
0229 .init = hdmi_init,
0230 .dpcm_playback = 1,
0231 .no_pcm = 1,
0232 SND_SOC_DAILINK_REG(idisp4_pin, idisp4_codec, platform),
0233 },
0234 };
0235
0236
0237 static struct snd_soc_card snd_soc_card_ehl_rt5660 = {
0238 .name = "ehl-rt5660",
0239 .owner = THIS_MODULE,
0240 .dai_link = ehl_rt5660_dailink,
0241 .num_links = ARRAY_SIZE(ehl_rt5660_dailink),
0242 .dapm_widgets = rt5660_widgets,
0243 .num_dapm_widgets = ARRAY_SIZE(rt5660_widgets),
0244 .dapm_routes = rt5660_map,
0245 .num_dapm_routes = ARRAY_SIZE(rt5660_map),
0246 .controls = rt5660_controls,
0247 .num_controls = ARRAY_SIZE(rt5660_controls),
0248 .fully_routed = true,
0249 .late_probe = card_late_probe,
0250 };
0251
0252
0253 static void hdmi_link_init(struct snd_soc_card *card,
0254 struct sof_card_private *ctx,
0255 struct snd_soc_acpi_mach *mach)
0256 {
0257 struct snd_soc_dai_link *link;
0258 int i;
0259
0260 if (mach->mach_params.common_hdmi_codec_drv &&
0261 (mach->mach_params.codec_mask & IDISP_CODEC_MASK)) {
0262 ctx->idisp_codec = true;
0263 return;
0264 }
0265
0266
0267
0268
0269
0270 for (i = HDMI_LINK_START; i <= HDMI_LINE_END; i++) {
0271 link = &card->dai_link[i];
0272 link->codecs[0].name = "snd-soc-dummy";
0273 link->codecs[0].dai_name = "snd-soc-dummy-dai";
0274 }
0275 }
0276
0277 static int snd_ehl_rt5660_probe(struct platform_device *pdev)
0278 {
0279 struct snd_soc_acpi_mach *mach;
0280 struct snd_soc_card *card = &snd_soc_card_ehl_rt5660;
0281 struct sof_card_private *ctx;
0282 int ret;
0283
0284 card->dev = &pdev->dev;
0285
0286 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
0287 if (!ctx)
0288 return -ENOMEM;
0289 INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
0290 snd_soc_card_set_drvdata(card, ctx);
0291
0292 mach = pdev->dev.platform_data;
0293 ret = snd_soc_fixup_dai_links_platform_name(card,
0294 mach->mach_params.platform);
0295 if (ret)
0296 return ret;
0297
0298 hdmi_link_init(card, ctx, mach);
0299
0300 return devm_snd_soc_register_card(&pdev->dev, card);
0301 }
0302
0303 static const struct platform_device_id ehl_board_ids[] = {
0304 { .name = "ehl_rt5660" },
0305 { }
0306 };
0307 MODULE_DEVICE_TABLE(platform, ehl_board_ids);
0308
0309 static struct platform_driver snd_ehl_rt5660_driver = {
0310 .driver = {
0311 .name = "ehl_rt5660",
0312 .pm = &snd_soc_pm_ops,
0313 },
0314 .probe = snd_ehl_rt5660_probe,
0315 .id_table = ehl_board_ids,
0316 };
0317
0318 module_platform_driver(snd_ehl_rt5660_driver);
0319
0320 MODULE_DESCRIPTION("ASoC Intel(R) Elkhartlake + rt5660 Machine driver");
0321 MODULE_AUTHOR("libin.yang@intel.com");
0322 MODULE_LICENSE("GPL v2");
0323 MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);