cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ehl_rt5660.c (8083B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2// Copyright (c) 2020 Intel Corporation
      3
      4/*
      5 * ehl_rt5660 - ASOC Machine driver for Elkhart Lake platforms
      6 * with rt5660 codec
      7 */
      8
      9#include <linux/acpi.h>
     10#include <sound/core.h>
     11#include <linux/device.h>
     12#include <linux/errno.h>
     13#include <linux/gfp.h>
     14#include <sound/jack.h>
     15#include <linux/kernel.h>
     16#include <linux/list.h>
     17#include <linux/module.h>
     18#include <sound/pcm.h>
     19#include <sound/pcm_params.h>
     20#include <sound/soc.h>
     21#include <sound/soc-acpi.h>
     22
     23#include "hda_dsp_common.h"
     24#include "../../codecs/rt5660.h"
     25
     26#define DUAL_CHANNEL 2
     27#define HDMI_LINK_START 3
     28#define HDMI_LINE_END 6
     29#define NAME_SIZE	32
     30#define IDISP_CODEC_MASK	0x4
     31
     32struct sof_card_private {
     33	struct list_head hdmi_pcm_list;
     34	bool idisp_codec;
     35};
     36
     37static const struct snd_kcontrol_new rt5660_controls[] = {
     38	SOC_DAPM_PIN_SWITCH("Speaker"),
     39	/* There are two MICBIAS in rt5660, each for one MIC */
     40	SOC_DAPM_PIN_SWITCH("Headset Mic"),
     41	SOC_DAPM_PIN_SWITCH("Headset Mic2"),
     42	SOC_DAPM_PIN_SWITCH("Line Out"),
     43};
     44
     45static const struct snd_soc_dapm_widget rt5660_widgets[] = {
     46	SND_SOC_DAPM_SPK("Speaker", NULL),
     47	SND_SOC_DAPM_MIC("Headset Mic", NULL),
     48	SND_SOC_DAPM_MIC("Headset Mic2", NULL),
     49	SND_SOC_DAPM_MIC("SoC DMIC", NULL),
     50	SND_SOC_DAPM_LINE("Line Out", NULL),
     51};
     52
     53static const struct snd_soc_dapm_route rt5660_map[] = {
     54	{"Speaker", NULL, "SPO"},
     55
     56	{"Headset Mic", NULL, "MICBIAS1"},
     57	{"Headset Mic2", NULL, "MICBIAS2"},
     58
     59	{"IN1P", NULL, "Headset Mic"},
     60	{"IN2P", NULL, "Headset Mic2"},
     61
     62	{"Line Out", NULL, "LOUTL"},
     63	{"Line Out", NULL, "LOUTR"},
     64
     65	{"DMic", NULL, "SoC DMIC"},
     66};
     67
     68struct sof_hdmi_pcm {
     69	struct list_head head;
     70	struct snd_soc_dai *codec_dai;
     71	int device;
     72};
     73
     74static int hdmi_init(struct snd_soc_pcm_runtime *rtd)
     75{
     76	struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
     77	struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
     78	struct sof_hdmi_pcm *pcm;
     79
     80	pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
     81	if (!pcm)
     82		return -ENOMEM;
     83
     84	/* dai_link id is 1:1 mapped to the PCM device */
     85	pcm->device = rtd->dai_link->id;
     86	pcm->codec_dai = dai;
     87
     88	list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
     89
     90	return 0;
     91}
     92
     93static int card_late_probe(struct snd_soc_card *card)
     94{
     95	struct sof_card_private *ctx = snd_soc_card_get_drvdata(card);
     96	struct sof_hdmi_pcm *pcm;
     97
     98	if (list_empty(&ctx->hdmi_pcm_list))
     99		return -ENOENT;
    100
    101	if (!ctx->idisp_codec)
    102		return 0;
    103
    104	pcm = list_first_entry(&ctx->hdmi_pcm_list, struct sof_hdmi_pcm, head);
    105
    106	return hda_dsp_hdmi_build_controls(card, pcm->codec_dai->component);
    107}
    108
    109static int rt5660_hw_params(struct snd_pcm_substream *substream,
    110			    struct snd_pcm_hw_params *params)
    111{
    112	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
    113	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
    114	int ret;
    115
    116	ret = snd_soc_dai_set_sysclk(codec_dai,
    117				     RT5660_SCLK_S_PLL1,
    118				     params_rate(params) * 512,
    119				     SND_SOC_CLOCK_IN);
    120	if (ret < 0) {
    121		dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
    122		return ret;
    123	}
    124
    125	ret = snd_soc_dai_set_pll(codec_dai, 0,
    126				  RT5660_PLL1_S_BCLK,
    127				  params_rate(params) * 50,
    128				  params_rate(params) * 512);
    129	if (ret < 0)
    130		dev_err(codec_dai->dev, "can't set codec pll: %d\n", ret);
    131
    132	return ret;
    133}
    134
    135static struct snd_soc_ops rt5660_ops = {
    136	.hw_params = rt5660_hw_params,
    137};
    138
    139SND_SOC_DAILINK_DEF(ssp0_pin,
    140	DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin")));
    141
    142SND_SOC_DAILINK_DEF(rt5660_codec,
    143	DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5660:00", "rt5660-aif1")));
    144
    145SND_SOC_DAILINK_DEF(platform,
    146	DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3")));
    147
    148SND_SOC_DAILINK_DEF(dmic_pin,
    149	DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin")));
    150SND_SOC_DAILINK_DEF(dmic_codec,
    151	DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi")));
    152SND_SOC_DAILINK_DEF(dmic16k,
    153	DAILINK_COMP_ARRAY(COMP_CPU("DMIC16k Pin")));
    154
    155SND_SOC_DAILINK_DEF(idisp1_pin,
    156	DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin")));
    157SND_SOC_DAILINK_DEF(idisp1_codec,
    158	DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1")));
    159
    160SND_SOC_DAILINK_DEF(idisp2_pin,
    161	DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin")));
    162SND_SOC_DAILINK_DEF(idisp2_codec,
    163	DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2")));
    164
    165SND_SOC_DAILINK_DEF(idisp3_pin,
    166	DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin")));
    167SND_SOC_DAILINK_DEF(idisp3_codec,
    168	DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3")));
    169
    170SND_SOC_DAILINK_DEF(idisp4_pin,
    171	DAILINK_COMP_ARRAY(COMP_CPU("iDisp4 Pin")));
    172SND_SOC_DAILINK_DEF(idisp4_codec,
    173	DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi4")));
    174
    175static struct snd_soc_dai_link ehl_rt5660_dailink[] = {
    176	/* back ends */
    177	{
    178		.name = "SSP0-Codec",
    179		.id = 0,
    180		.no_pcm = 1,
    181		.dpcm_playback = 1,
    182		.dpcm_capture = 1,
    183		.ops = &rt5660_ops,
    184		SND_SOC_DAILINK_REG(ssp0_pin, rt5660_codec, platform),
    185	},
    186	{
    187		.name = "dmic48k",
    188		.id = 1,
    189		.ignore_suspend = 1,
    190		.dpcm_capture = 1,
    191		.no_pcm = 1,
    192		SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform),
    193	},
    194	{
    195		.name = "dmic16k",
    196		.id = 2,
    197		.ignore_suspend = 1,
    198		.dpcm_capture = 1,
    199		.no_pcm = 1,
    200		SND_SOC_DAILINK_REG(dmic16k, dmic_codec, platform),
    201	},
    202	{
    203		.name = "iDisp1",
    204		.id = 5,
    205		.init = hdmi_init,
    206		.dpcm_playback = 1,
    207		.no_pcm = 1,
    208		SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform),
    209	},
    210	{
    211		.name = "iDisp2",
    212		.id = 6,
    213		.init = hdmi_init,
    214		.dpcm_playback = 1,
    215		.no_pcm = 1,
    216		SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform),
    217	},
    218	{
    219		.name = "iDisp3",
    220		.id = 7,
    221		.init = hdmi_init,
    222		.dpcm_playback = 1,
    223		.no_pcm = 1,
    224		SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform),
    225	},
    226	{
    227		.name = "iDisp4",
    228		.id = 8,
    229		.init = hdmi_init,
    230		.dpcm_playback = 1,
    231		.no_pcm = 1,
    232		SND_SOC_DAILINK_REG(idisp4_pin, idisp4_codec, platform),
    233	},
    234};
    235
    236/* SoC card */
    237static struct snd_soc_card snd_soc_card_ehl_rt5660 = {
    238	.name = "ehl-rt5660",
    239	.owner = THIS_MODULE,
    240	.dai_link = ehl_rt5660_dailink,
    241	.num_links = ARRAY_SIZE(ehl_rt5660_dailink),
    242	.dapm_widgets = rt5660_widgets,
    243	.num_dapm_widgets = ARRAY_SIZE(rt5660_widgets),
    244	.dapm_routes = rt5660_map,
    245	.num_dapm_routes = ARRAY_SIZE(rt5660_map),
    246	.controls = rt5660_controls,
    247	.num_controls = ARRAY_SIZE(rt5660_controls),
    248	.fully_routed = true,
    249	.late_probe = card_late_probe,
    250};
    251
    252/* If hdmi codec is not supported, switch to use dummy codec */
    253static void hdmi_link_init(struct snd_soc_card *card,
    254			   struct sof_card_private *ctx,
    255			   struct snd_soc_acpi_mach *mach)
    256{
    257	struct snd_soc_dai_link *link;
    258	int i;
    259
    260	if (mach->mach_params.common_hdmi_codec_drv &&
    261	    (mach->mach_params.codec_mask & IDISP_CODEC_MASK)) {
    262		ctx->idisp_codec = true;
    263		return;
    264	}
    265
    266	/*
    267	 * if HDMI is not enabled in kernel config, or
    268	 * hdmi codec is not supported
    269	 */
    270	for (i = HDMI_LINK_START; i <= HDMI_LINE_END; i++) {
    271		link = &card->dai_link[i];
    272		link->codecs[0].name = "snd-soc-dummy";
    273		link->codecs[0].dai_name = "snd-soc-dummy-dai";
    274	}
    275}
    276
    277static int snd_ehl_rt5660_probe(struct platform_device *pdev)
    278{
    279	struct snd_soc_acpi_mach *mach;
    280	struct snd_soc_card *card = &snd_soc_card_ehl_rt5660;
    281	struct sof_card_private *ctx;
    282	int ret;
    283
    284	card->dev = &pdev->dev;
    285
    286	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
    287	if (!ctx)
    288		return -ENOMEM;
    289	INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
    290	snd_soc_card_set_drvdata(card, ctx);
    291
    292	mach = pdev->dev.platform_data;
    293	ret = snd_soc_fixup_dai_links_platform_name(card,
    294						    mach->mach_params.platform);
    295	if (ret)
    296		return ret;
    297
    298	hdmi_link_init(card, ctx, mach);
    299
    300	return devm_snd_soc_register_card(&pdev->dev, card);
    301}
    302
    303static const struct platform_device_id ehl_board_ids[] = {
    304	{ .name = "ehl_rt5660" },
    305	{ }
    306};
    307MODULE_DEVICE_TABLE(platform, ehl_board_ids);
    308
    309static struct platform_driver snd_ehl_rt5660_driver = {
    310	.driver = {
    311		.name = "ehl_rt5660",
    312		.pm = &snd_soc_pm_ops,
    313	},
    314	.probe = snd_ehl_rt5660_probe,
    315	.id_table = ehl_board_ids,
    316};
    317
    318module_platform_driver(snd_ehl_rt5660_driver);
    319
    320MODULE_DESCRIPTION("ASoC Intel(R) Elkhartlake + rt5660 Machine driver");
    321MODULE_AUTHOR("libin.yang@intel.com");
    322MODULE_LICENSE("GPL v2");
    323MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);