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

broadwell.c (8868B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Intel Broadwell Wildcatpoint SST Audio
      4 *
      5 * Copyright (C) 2013, Intel Corporation. All rights reserved.
      6 */
      7
      8#include <linux/module.h>
      9#include <linux/platform_device.h>
     10#include <sound/core.h>
     11#include <sound/pcm.h>
     12#include <sound/soc.h>
     13#include <sound/jack.h>
     14#include <sound/pcm_params.h>
     15#include <sound/soc-acpi.h>
     16
     17#include "../../codecs/rt286.h"
     18
     19static struct snd_soc_jack broadwell_headset;
     20/* Headset jack detection DAPM pins */
     21static struct snd_soc_jack_pin broadwell_headset_pins[] = {
     22	{
     23		.pin = "Mic Jack",
     24		.mask = SND_JACK_MICROPHONE,
     25	},
     26	{
     27		.pin = "Headphone Jack",
     28		.mask = SND_JACK_HEADPHONE,
     29	},
     30};
     31
     32static const struct snd_kcontrol_new broadwell_controls[] = {
     33	SOC_DAPM_PIN_SWITCH("Speaker"),
     34	SOC_DAPM_PIN_SWITCH("Headphone Jack"),
     35};
     36
     37static const struct snd_soc_dapm_widget broadwell_widgets[] = {
     38	SND_SOC_DAPM_HP("Headphone Jack", NULL),
     39	SND_SOC_DAPM_SPK("Speaker", NULL),
     40	SND_SOC_DAPM_MIC("Mic Jack", NULL),
     41	SND_SOC_DAPM_MIC("DMIC1", NULL),
     42	SND_SOC_DAPM_MIC("DMIC2", NULL),
     43	SND_SOC_DAPM_LINE("Line Jack", NULL),
     44};
     45
     46static const struct snd_soc_dapm_route broadwell_rt286_map[] = {
     47
     48	/* speaker */
     49	{"Speaker", NULL, "SPOR"},
     50	{"Speaker", NULL, "SPOL"},
     51
     52	/* HP jack connectors - unknown if we have jack deteck */
     53	{"Headphone Jack", NULL, "HPO Pin"},
     54
     55	/* other jacks */
     56	{"MIC1", NULL, "Mic Jack"},
     57	{"LINE1", NULL, "Line Jack"},
     58
     59	/* digital mics */
     60	{"DMIC1 Pin", NULL, "DMIC1"},
     61	{"DMIC2 Pin", NULL, "DMIC2"},
     62
     63	/* CODEC BE connections */
     64	{"SSP0 CODEC IN", NULL, "AIF1 Capture"},
     65	{"AIF1 Playback", NULL, "SSP0 CODEC OUT"},
     66};
     67
     68static int broadwell_rt286_codec_init(struct snd_soc_pcm_runtime *rtd)
     69{
     70	struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
     71	int ret = 0;
     72	ret = snd_soc_card_jack_new_pins(rtd->card, "Headset",
     73		SND_JACK_HEADSET | SND_JACK_BTN_0, &broadwell_headset,
     74		broadwell_headset_pins, ARRAY_SIZE(broadwell_headset_pins));
     75	if (ret)
     76		return ret;
     77
     78	rt286_mic_detect(component, &broadwell_headset);
     79	return 0;
     80}
     81
     82
     83static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
     84			struct snd_pcm_hw_params *params)
     85{
     86	struct snd_interval *rate = hw_param_interval(params,
     87						      SNDRV_PCM_HW_PARAM_RATE);
     88	struct snd_interval *chan = hw_param_interval(params,
     89						      SNDRV_PCM_HW_PARAM_CHANNELS);
     90
     91	/* The ADSP will covert the FE rate to 48k, stereo */
     92	rate->min = rate->max = 48000;
     93	chan->min = chan->max = 2;
     94
     95	/* set SSP0 to 16 bit */
     96	params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
     97	return 0;
     98}
     99
    100static int broadwell_rt286_hw_params(struct snd_pcm_substream *substream,
    101	struct snd_pcm_hw_params *params)
    102{
    103	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
    104	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
    105	int ret;
    106
    107	ret = snd_soc_dai_set_sysclk(codec_dai, RT286_SCLK_S_PLL, 24000000,
    108		SND_SOC_CLOCK_IN);
    109
    110	if (ret < 0) {
    111		dev_err(rtd->dev, "can't set codec sysclk configuration\n");
    112		return ret;
    113	}
    114
    115	return ret;
    116}
    117
    118static const struct snd_soc_ops broadwell_rt286_ops = {
    119	.hw_params = broadwell_rt286_hw_params,
    120};
    121
    122static const unsigned int channels[] = {
    123	2,
    124};
    125
    126static const struct snd_pcm_hw_constraint_list constraints_channels = {
    127	.count = ARRAY_SIZE(channels),
    128	.list = channels,
    129	.mask = 0,
    130};
    131
    132static int broadwell_fe_startup(struct snd_pcm_substream *substream)
    133{
    134	struct snd_pcm_runtime *runtime = substream->runtime;
    135
    136	/* Board supports stereo configuration only */
    137	runtime->hw.channels_max = 2;
    138	return snd_pcm_hw_constraint_list(runtime, 0,
    139					  SNDRV_PCM_HW_PARAM_CHANNELS,
    140					  &constraints_channels);
    141}
    142
    143static const struct snd_soc_ops broadwell_fe_ops = {
    144	.startup = broadwell_fe_startup,
    145};
    146
    147SND_SOC_DAILINK_DEF(system,
    148	DAILINK_COMP_ARRAY(COMP_CPU("System Pin")));
    149
    150SND_SOC_DAILINK_DEF(offload0,
    151	DAILINK_COMP_ARRAY(COMP_CPU("Offload0 Pin")));
    152
    153SND_SOC_DAILINK_DEF(offload1,
    154	DAILINK_COMP_ARRAY(COMP_CPU("Offload1 Pin")));
    155
    156SND_SOC_DAILINK_DEF(loopback,
    157	DAILINK_COMP_ARRAY(COMP_CPU("Loopback Pin")));
    158
    159SND_SOC_DAILINK_DEF(dummy,
    160	DAILINK_COMP_ARRAY(COMP_DUMMY()));
    161
    162SND_SOC_DAILINK_DEF(platform,
    163	DAILINK_COMP_ARRAY(COMP_PLATFORM("haswell-pcm-audio")));
    164
    165SND_SOC_DAILINK_DEF(codec,
    166	DAILINK_COMP_ARRAY(COMP_CODEC("i2c-INT343A:00", "rt286-aif1")));
    167
    168SND_SOC_DAILINK_DEF(ssp0_port,
    169	    DAILINK_COMP_ARRAY(COMP_CPU("ssp0-port")));
    170
    171/* broadwell digital audio interface glue - connects codec <--> CPU */
    172static struct snd_soc_dai_link broadwell_rt286_dais[] = {
    173	/* Front End DAI links */
    174	{
    175		.name = "System PCM",
    176		.stream_name = "System Playback/Capture",
    177		.nonatomic = 1,
    178		.dynamic = 1,
    179		.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
    180		.ops = &broadwell_fe_ops,
    181		.dpcm_playback = 1,
    182		.dpcm_capture = 1,
    183		SND_SOC_DAILINK_REG(system, dummy, platform),
    184	},
    185	{
    186		.name = "Offload0",
    187		.stream_name = "Offload0 Playback",
    188		.nonatomic = 1,
    189		.dynamic = 1,
    190		.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
    191		.dpcm_playback = 1,
    192		SND_SOC_DAILINK_REG(offload0, dummy, platform),
    193	},
    194	{
    195		.name = "Offload1",
    196		.stream_name = "Offload1 Playback",
    197		.nonatomic = 1,
    198		.dynamic = 1,
    199		.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
    200		.dpcm_playback = 1,
    201		SND_SOC_DAILINK_REG(offload1, dummy, platform),
    202	},
    203	{
    204		.name = "Loopback PCM",
    205		.stream_name = "Loopback",
    206		.nonatomic = 1,
    207		.dynamic = 1,
    208		.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
    209		.dpcm_capture = 1,
    210		SND_SOC_DAILINK_REG(loopback, dummy, platform),
    211	},
    212	/* Back End DAI links */
    213	{
    214		/* SSP0 - Codec */
    215		.name = "Codec",
    216		.id = 0,
    217		.no_pcm = 1,
    218		.init = broadwell_rt286_codec_init,
    219		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
    220			SND_SOC_DAIFMT_CBC_CFC,
    221		.ignore_pmdown_time = 1,
    222		.be_hw_params_fixup = broadwell_ssp0_fixup,
    223		.ops = &broadwell_rt286_ops,
    224		.dpcm_playback = 1,
    225		.dpcm_capture = 1,
    226		SND_SOC_DAILINK_REG(ssp0_port, codec, platform),
    227	},
    228};
    229
    230static int broadwell_disable_jack(struct snd_soc_card *card)
    231{
    232	struct snd_soc_component *component;
    233
    234	for_each_card_components(card, component) {
    235		if (!strcmp(component->name, "i2c-INT343A:00")) {
    236
    237			dev_dbg(component->dev, "disabling jack detect before going to suspend.\n");
    238			rt286_mic_detect(component, NULL);
    239			break;
    240		}
    241	}
    242
    243	return 0;
    244}
    245
    246static int broadwell_suspend(struct snd_soc_card *card)
    247{
    248	return broadwell_disable_jack(card);
    249}
    250
    251static int broadwell_resume(struct snd_soc_card *card){
    252	struct snd_soc_component *component;
    253
    254	for_each_card_components(card, component) {
    255		if (!strcmp(component->name, "i2c-INT343A:00")) {
    256
    257			dev_dbg(component->dev, "enabling jack detect for resume.\n");
    258			rt286_mic_detect(component, &broadwell_headset);
    259			break;
    260		}
    261	}
    262	return 0;
    263}
    264
    265/* use space before codec name to simplify card ID, and simplify driver name */
    266#define SOF_CARD_NAME "bdw rt286" /* card name will be 'sof-bdw rt286' */
    267#define SOF_DRIVER_NAME "SOF"
    268
    269#define CARD_NAME "broadwell-rt286"
    270#define DRIVER_NAME NULL /* card name will be used for driver name */
    271
    272/* broadwell audio machine driver for WPT + RT286S */
    273static struct snd_soc_card broadwell_rt286 = {
    274	.owner = THIS_MODULE,
    275	.dai_link = broadwell_rt286_dais,
    276	.num_links = ARRAY_SIZE(broadwell_rt286_dais),
    277	.controls = broadwell_controls,
    278	.num_controls = ARRAY_SIZE(broadwell_controls),
    279	.dapm_widgets = broadwell_widgets,
    280	.num_dapm_widgets = ARRAY_SIZE(broadwell_widgets),
    281	.dapm_routes = broadwell_rt286_map,
    282	.num_dapm_routes = ARRAY_SIZE(broadwell_rt286_map),
    283	.fully_routed = true,
    284	.suspend_pre = broadwell_suspend,
    285	.resume_post = broadwell_resume,
    286};
    287
    288static int broadwell_audio_probe(struct platform_device *pdev)
    289{
    290	struct snd_soc_acpi_mach *mach;
    291	int ret;
    292
    293	broadwell_rt286.dev = &pdev->dev;
    294
    295	/* override platform name, if required */
    296	mach = pdev->dev.platform_data;
    297	ret = snd_soc_fixup_dai_links_platform_name(&broadwell_rt286,
    298						    mach->mach_params.platform);
    299	if (ret)
    300		return ret;
    301
    302	/* set card and driver name */
    303	if (snd_soc_acpi_sof_parent(&pdev->dev)) {
    304		broadwell_rt286.name = SOF_CARD_NAME;
    305		broadwell_rt286.driver_name = SOF_DRIVER_NAME;
    306	} else {
    307		broadwell_rt286.name = CARD_NAME;
    308		broadwell_rt286.driver_name = DRIVER_NAME;
    309	}
    310
    311	return devm_snd_soc_register_card(&pdev->dev, &broadwell_rt286);
    312}
    313
    314static int broadwell_audio_remove(struct platform_device *pdev)
    315{
    316	struct snd_soc_card *card = platform_get_drvdata(pdev);
    317
    318	return broadwell_disable_jack(card);
    319}
    320
    321static struct platform_driver broadwell_audio = {
    322	.probe = broadwell_audio_probe,
    323	.remove = broadwell_audio_remove,
    324	.driver = {
    325		.name = "broadwell-audio",
    326		.pm = &snd_soc_pm_ops
    327	},
    328};
    329
    330module_platform_driver(broadwell_audio)
    331
    332/* Module information */
    333MODULE_AUTHOR("Liam Girdwood, Xingchao Wang");
    334MODULE_DESCRIPTION("Intel SST Audio for WPT/Broadwell");
    335MODULE_LICENSE("GPL v2");
    336MODULE_ALIAS("platform:broadwell-audio");