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

sof_da7219_max98373.c (12095B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2// Copyright(c) 2019 Intel Corporation.
      3
      4/*
      5 * Intel SOF Machine driver for DA7219 + MAX98373/MAX98360A codec
      6 */
      7
      8#include <linux/input.h>
      9#include <linux/module.h>
     10#include <sound/pcm.h>
     11#include <sound/pcm_params.h>
     12#include <linux/platform_device.h>
     13#include <sound/soc.h>
     14#include <sound/soc-acpi.h>
     15#include "../../codecs/da7219.h"
     16#include "../../codecs/da7219-aad.h"
     17#include "hda_dsp_common.h"
     18
     19#define DIALOG_CODEC_DAI	"da7219-hifi"
     20#define MAX98373_CODEC_DAI	"max98373-aif1"
     21#define MAXIM_DEV0_NAME		"i2c-MX98373:00"
     22#define MAXIM_DEV1_NAME		"i2c-MX98373:01"
     23
     24struct hdmi_pcm {
     25	struct list_head head;
     26	struct snd_soc_dai *codec_dai;
     27	int device;
     28};
     29
     30struct card_private {
     31	struct snd_soc_jack headset;
     32	struct list_head hdmi_pcm_list;
     33	struct snd_soc_jack hdmi[3];
     34};
     35
     36static int platform_clock_control(struct snd_soc_dapm_widget *w,
     37				  struct snd_kcontrol *k, int  event)
     38{
     39	struct snd_soc_dapm_context *dapm = w->dapm;
     40	struct snd_soc_card *card = dapm->card;
     41	struct snd_soc_dai *codec_dai;
     42	int ret = 0;
     43
     44	codec_dai = snd_soc_card_get_codec_dai(card, DIALOG_CODEC_DAI);
     45	if (!codec_dai) {
     46		dev_err(card->dev, "Codec dai not found; Unable to set/unset codec pll\n");
     47		return -EIO;
     48	}
     49
     50	if (SND_SOC_DAPM_EVENT_OFF(event)) {
     51		ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK,
     52					  0, 0);
     53		if (ret)
     54			dev_err(card->dev, "failed to stop PLL: %d\n", ret);
     55	} else if (SND_SOC_DAPM_EVENT_ON(event)) {
     56		ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_PLL_SRM,
     57					  0, DA7219_PLL_FREQ_OUT_98304);
     58		if (ret)
     59			dev_err(card->dev, "failed to start PLL: %d\n", ret);
     60	}
     61
     62	return ret;
     63}
     64
     65static const struct snd_kcontrol_new controls[] = {
     66	SOC_DAPM_PIN_SWITCH("Headphone Jack"),
     67	SOC_DAPM_PIN_SWITCH("Headset Mic"),
     68	SOC_DAPM_PIN_SWITCH("Left Spk"),
     69	SOC_DAPM_PIN_SWITCH("Right Spk"),
     70};
     71
     72static const struct snd_kcontrol_new m98360a_controls[] = {
     73	SOC_DAPM_PIN_SWITCH("Headphone Jack"),
     74	SOC_DAPM_PIN_SWITCH("Headset Mic"),
     75	SOC_DAPM_PIN_SWITCH("Spk"),
     76};
     77
     78/* For MAX98373 amp */
     79static const struct snd_soc_dapm_widget widgets[] = {
     80	SND_SOC_DAPM_HP("Headphone Jack", NULL),
     81	SND_SOC_DAPM_MIC("Headset Mic", NULL),
     82
     83	SND_SOC_DAPM_SPK("Left Spk", NULL),
     84	SND_SOC_DAPM_SPK("Right Spk", NULL),
     85
     86	SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
     87			    platform_clock_control, SND_SOC_DAPM_POST_PMD |
     88			    SND_SOC_DAPM_PRE_PMU),
     89
     90	SND_SOC_DAPM_MIC("SoC DMIC", NULL),
     91};
     92
     93static const struct snd_soc_dapm_route audio_map[] = {
     94	{ "Headphone Jack", NULL, "HPL" },
     95	{ "Headphone Jack", NULL, "HPR" },
     96
     97	{ "MIC", NULL, "Headset Mic" },
     98
     99	{ "Headphone Jack", NULL, "Platform Clock" },
    100	{ "Headset Mic", NULL, "Platform Clock" },
    101
    102	{ "Left Spk", NULL, "Left BE_OUT" },
    103	{ "Right Spk", NULL, "Right BE_OUT" },
    104
    105	/* digital mics */
    106	{"DMic", NULL, "SoC DMIC"},
    107};
    108
    109/* For MAX98360A amp */
    110static const struct snd_soc_dapm_widget max98360a_widgets[] = {
    111	SND_SOC_DAPM_HP("Headphone Jack", NULL),
    112	SND_SOC_DAPM_MIC("Headset Mic", NULL),
    113
    114	SND_SOC_DAPM_SPK("Spk", NULL),
    115
    116	SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
    117			    platform_clock_control, SND_SOC_DAPM_POST_PMD |
    118			    SND_SOC_DAPM_PRE_PMU),
    119
    120	SND_SOC_DAPM_MIC("SoC DMIC", NULL),
    121};
    122
    123static const struct snd_soc_dapm_route max98360a_map[] = {
    124	{ "Headphone Jack", NULL, "HPL" },
    125	{ "Headphone Jack", NULL, "HPR" },
    126
    127	{ "MIC", NULL, "Headset Mic" },
    128
    129	{ "Headphone Jack", NULL, "Platform Clock" },
    130	{ "Headset Mic", NULL, "Platform Clock" },
    131
    132	{"Spk", NULL, "Speaker"},
    133
    134	/* digital mics */
    135	{"DMic", NULL, "SoC DMIC"},
    136};
    137
    138static struct snd_soc_jack headset;
    139
    140static int da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
    141{
    142	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
    143	struct snd_soc_component *component = codec_dai->component;
    144	struct snd_soc_jack *jack;
    145	int ret;
    146
    147	/* Configure sysclk for codec */
    148	ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, 24000000,
    149				     SND_SOC_CLOCK_IN);
    150	if (ret) {
    151		dev_err(rtd->dev, "can't set codec sysclk configuration\n");
    152		return ret;
    153	}
    154
    155	/*
    156	 * Headset buttons map to the google Reference headset.
    157	 * These can be configured by userspace.
    158	 */
    159	ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
    160				    SND_JACK_HEADSET | SND_JACK_BTN_0 |
    161				    SND_JACK_BTN_1 | SND_JACK_BTN_2 |
    162				    SND_JACK_BTN_3 | SND_JACK_LINEOUT,
    163				    &headset);
    164	if (ret) {
    165		dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
    166		return ret;
    167	}
    168
    169	jack = &headset;
    170	snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
    171	snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
    172	snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
    173	snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
    174	da7219_aad_jack_det(component, jack);
    175
    176	return ret;
    177}
    178
    179static int ssp1_hw_params(struct snd_pcm_substream *substream,
    180			      struct snd_pcm_hw_params *params)
    181{
    182	struct snd_soc_pcm_runtime *runtime = asoc_substream_to_rtd(substream);
    183	int ret, j;
    184
    185	for (j = 0; j < runtime->num_codecs; j++) {
    186		struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, j);
    187
    188		if (!strcmp(codec_dai->component->name, MAXIM_DEV0_NAME)) {
    189			/* vmon_slot_no = 0 imon_slot_no = 1 for TX slots */
    190			ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x3, 3, 4, 16);
    191			if (ret < 0) {
    192				dev_err(runtime->dev, "DEV0 TDM slot err:%d\n", ret);
    193				return ret;
    194			}
    195		}
    196		if (!strcmp(codec_dai->component->name, MAXIM_DEV1_NAME)) {
    197			/* vmon_slot_no = 2 imon_slot_no = 3 for TX slots */
    198			ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC, 3, 4, 16);
    199			if (ret < 0) {
    200				dev_err(runtime->dev, "DEV1 TDM slot err:%d\n", ret);
    201				return ret;
    202			}
    203		}
    204	}
    205
    206	return 0;
    207}
    208
    209static struct snd_soc_ops ssp1_ops = {
    210	.hw_params = ssp1_hw_params,
    211};
    212
    213static struct snd_soc_codec_conf max98373_codec_conf[] = {
    214	{
    215		.dlc = COMP_CODEC_CONF(MAXIM_DEV0_NAME),
    216		.name_prefix = "Right",
    217	},
    218	{
    219		.dlc = COMP_CODEC_CONF(MAXIM_DEV1_NAME),
    220		.name_prefix = "Left",
    221	},
    222};
    223
    224static int hdmi_init(struct snd_soc_pcm_runtime *rtd)
    225{
    226	struct card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
    227	struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
    228	struct hdmi_pcm *pcm;
    229
    230	pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
    231	if (!pcm)
    232		return -ENOMEM;
    233
    234	pcm->device = dai->id;
    235	pcm->codec_dai = dai;
    236
    237	list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
    238
    239	return 0;
    240}
    241
    242static int card_late_probe(struct snd_soc_card *card)
    243{
    244	struct card_private *ctx = snd_soc_card_get_drvdata(card);
    245	struct snd_soc_acpi_mach *mach = (card->dev)->platform_data;
    246	struct hdmi_pcm *pcm;
    247
    248	if (mach->mach_params.common_hdmi_codec_drv) {
    249		pcm = list_first_entry(&ctx->hdmi_pcm_list, struct hdmi_pcm,
    250				       head);
    251		return hda_dsp_hdmi_build_controls(card,
    252						   pcm->codec_dai->component);
    253	}
    254
    255	return -EINVAL;
    256}
    257
    258SND_SOC_DAILINK_DEF(ssp0_pin,
    259	DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin")));
    260SND_SOC_DAILINK_DEF(ssp0_codec,
    261	DAILINK_COMP_ARRAY(COMP_CODEC("i2c-DLGS7219:00", DIALOG_CODEC_DAI)));
    262
    263SND_SOC_DAILINK_DEF(ssp1_pin,
    264	DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin")));
    265SND_SOC_DAILINK_DEF(ssp1_amps,
    266	DAILINK_COMP_ARRAY(
    267	/* Left */	COMP_CODEC(MAXIM_DEV0_NAME, MAX98373_CODEC_DAI),
    268	/* Right */	COMP_CODEC(MAXIM_DEV1_NAME, MAX98373_CODEC_DAI)));
    269
    270SND_SOC_DAILINK_DEF(ssp1_m98360a,
    271	DAILINK_COMP_ARRAY(COMP_CODEC("MX98360A:00", "HiFi")));
    272
    273SND_SOC_DAILINK_DEF(dmic_pin,
    274	DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin")));
    275SND_SOC_DAILINK_DEF(dmic_codec,
    276	DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi")));
    277
    278SND_SOC_DAILINK_DEF(dmic16k_pin,
    279	DAILINK_COMP_ARRAY(COMP_CPU("DMIC16k Pin")));
    280
    281SND_SOC_DAILINK_DEF(idisp1_pin,
    282	DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin")));
    283SND_SOC_DAILINK_DEF(idisp1_codec,
    284	DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1")));
    285
    286SND_SOC_DAILINK_DEF(idisp2_pin,
    287	DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin")));
    288SND_SOC_DAILINK_DEF(idisp2_codec,
    289	DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2")));
    290
    291SND_SOC_DAILINK_DEF(idisp3_pin,
    292	DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin")));
    293SND_SOC_DAILINK_DEF(idisp3_codec,
    294	DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3")));
    295
    296SND_SOC_DAILINK_DEF(platform, /* subject to be overridden during probe */
    297	DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3")));
    298
    299static struct snd_soc_dai_link dais[] = {
    300	/* Back End DAI links */
    301	{
    302		.name = "SSP1-Codec",
    303		.id = 0,
    304		.ignore_pmdown_time = 1,
    305		.no_pcm = 1,
    306		.dpcm_playback = 1,
    307		.dpcm_capture = 1, /* IV feedback */
    308		.ops = &ssp1_ops,
    309		SND_SOC_DAILINK_REG(ssp1_pin, ssp1_amps, platform),
    310	},
    311	{
    312		.name = "SSP0-Codec",
    313		.id = 1,
    314		.no_pcm = 1,
    315		.init = da7219_codec_init,
    316		.ignore_pmdown_time = 1,
    317		.dpcm_playback = 1,
    318		.dpcm_capture = 1,
    319		SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform),
    320	},
    321	{
    322		.name = "dmic01",
    323		.id = 2,
    324		.ignore_suspend = 1,
    325		.dpcm_capture = 1,
    326		.no_pcm = 1,
    327		SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform),
    328	},
    329	{
    330		.name = "iDisp1",
    331		.id = 3,
    332		.init = hdmi_init,
    333		.dpcm_playback = 1,
    334		.no_pcm = 1,
    335		SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform),
    336	},
    337	{
    338		.name = "iDisp2",
    339		.id = 4,
    340		.init = hdmi_init,
    341		.dpcm_playback = 1,
    342		.no_pcm = 1,
    343		SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform),
    344	},
    345	{
    346		.name = "iDisp3",
    347		.id = 5,
    348		.init = hdmi_init,
    349		.dpcm_playback = 1,
    350		.no_pcm = 1,
    351		SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform),
    352	},
    353	{
    354		.name = "dmic16k",
    355		.id = 6,
    356		.ignore_suspend = 1,
    357		.dpcm_capture = 1,
    358		.no_pcm = 1,
    359		SND_SOC_DAILINK_REG(dmic16k_pin, dmic_codec, platform),
    360	}
    361};
    362
    363static struct snd_soc_card card_da7219_m98373 = {
    364	.name = "da7219max",
    365	.owner = THIS_MODULE,
    366	.dai_link = dais,
    367	.num_links = ARRAY_SIZE(dais),
    368	.controls = controls,
    369	.num_controls = ARRAY_SIZE(controls),
    370	.dapm_widgets = widgets,
    371	.num_dapm_widgets = ARRAY_SIZE(widgets),
    372	.dapm_routes = audio_map,
    373	.num_dapm_routes = ARRAY_SIZE(audio_map),
    374	.codec_conf = max98373_codec_conf,
    375	.num_configs = ARRAY_SIZE(max98373_codec_conf),
    376	.fully_routed = true,
    377	.late_probe = card_late_probe,
    378};
    379
    380static struct snd_soc_card card_da7219_m98360a = {
    381	.name = "da7219max98360a",
    382	.owner = THIS_MODULE,
    383	.dai_link = dais,
    384	.num_links = ARRAY_SIZE(dais),
    385	.controls = m98360a_controls,
    386	.num_controls = ARRAY_SIZE(m98360a_controls),
    387	.dapm_widgets = max98360a_widgets,
    388	.num_dapm_widgets = ARRAY_SIZE(max98360a_widgets),
    389	.dapm_routes = max98360a_map,
    390	.num_dapm_routes = ARRAY_SIZE(max98360a_map),
    391	.fully_routed = true,
    392	.late_probe = card_late_probe,
    393};
    394
    395static int audio_probe(struct platform_device *pdev)
    396{
    397	static struct snd_soc_card *card;
    398	struct snd_soc_acpi_mach *mach;
    399	struct card_private *ctx;
    400	int ret;
    401
    402	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
    403	if (!ctx)
    404		return -ENOMEM;
    405
    406	/* By default dais[0] is configured for max98373 */
    407	if (!strcmp(pdev->name, "sof_da7219_mx98360a")) {
    408		dais[0] = (struct snd_soc_dai_link) {
    409			.name = "SSP1-Codec",
    410			.id = 0,
    411			.no_pcm = 1,
    412			.dpcm_playback = 1,
    413			.ignore_pmdown_time = 1,
    414			SND_SOC_DAILINK_REG(ssp1_pin, ssp1_m98360a, platform) };
    415	}
    416
    417	INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
    418	card = (struct snd_soc_card *)pdev->id_entry->driver_data;
    419	card->dev = &pdev->dev;
    420
    421	mach = pdev->dev.platform_data;
    422	ret = snd_soc_fixup_dai_links_platform_name(card,
    423						    mach->mach_params.platform);
    424	if (ret)
    425		return ret;
    426
    427	snd_soc_card_set_drvdata(card, ctx);
    428
    429	return devm_snd_soc_register_card(&pdev->dev, card);
    430}
    431
    432static const struct platform_device_id board_ids[] = {
    433	{
    434		.name = "sof_da7219_mx98373",
    435		.driver_data = (kernel_ulong_t)&card_da7219_m98373,
    436	},
    437	{
    438		.name = "sof_da7219_mx98360a",
    439		.driver_data = (kernel_ulong_t)&card_da7219_m98360a,
    440	},
    441	{ }
    442};
    443MODULE_DEVICE_TABLE(platform, board_ids);
    444
    445static struct platform_driver audio = {
    446	.probe = audio_probe,
    447	.driver = {
    448		.name = "sof_da7219_max98_360a_373",
    449		.pm = &snd_soc_pm_ops,
    450	},
    451	.id_table = board_ids,
    452};
    453module_platform_driver(audio)
    454
    455/* Module information */
    456MODULE_DESCRIPTION("ASoC Intel(R) SOF Machine driver");
    457MODULE_AUTHOR("Yong Zhi <yong.zhi@intel.com>");
    458MODULE_LICENSE("GPL v2");
    459MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);