1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Intel Haswell Lynxpoint 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/soc-acpi.h> 14 #include <sound/pcm_params.h> 15 16 #include "../common/sst-dsp.h" 17 #include "../haswell/sst-haswell-ipc.h" 18 19 #include "../../codecs/rt5640.h" 20 21 /* Haswell ULT platforms have a Headphone and Mic jack */ 22 static const struct snd_soc_dapm_widget haswell_widgets[] = { 23 SND_SOC_DAPM_HP("Headphones", NULL), 24 SND_SOC_DAPM_MIC("Mic", NULL), 25 }; 26 27 static const struct snd_soc_dapm_route haswell_rt5640_map[] = { 28 29 {"Headphones", NULL, "HPOR"}, 30 {"Headphones", NULL, "HPOL"}, 31 {"IN2P", NULL, "Mic"}, 32 33 /* CODEC BE connections */ 34 {"SSP0 CODEC IN", NULL, "AIF1 Capture"}, 35 {"AIF1 Playback", NULL, "SSP0 CODEC OUT"}, 36 }; 37 38 static int haswell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, 39 struct snd_pcm_hw_params *params) 40 { 41 struct snd_interval *rate = hw_param_interval(params, 42 SNDRV_PCM_HW_PARAM_RATE); 43 struct snd_interval *channels = hw_param_interval(params, 44 SNDRV_PCM_HW_PARAM_CHANNELS); 45 46 /* The ADSP will covert the FE rate to 48k, stereo */ 47 rate->min = rate->max = 48000; 48 channels->min = channels->max = 2; 49 50 /* set SSP0 to 16 bit */ 51 params_set_format(params, SNDRV_PCM_FORMAT_S16_LE); 52 return 0; 53 } 54 55 static int haswell_rt5640_hw_params(struct snd_pcm_substream *substream, 56 struct snd_pcm_hw_params *params) 57 { 58 struct snd_soc_pcm_runtime *rtd = substream->private_data; 59 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 60 int ret; 61 62 ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_MCLK, 12288000, 63 SND_SOC_CLOCK_IN); 64 65 if (ret < 0) { 66 dev_err(rtd->dev, "can't set codec sysclk configuration\n"); 67 return ret; 68 } 69 70 /* set correct codec filter for DAI format and clock config */ 71 snd_soc_component_update_bits(codec_dai->component, 0x83, 0xffff, 0x8000); 72 73 return ret; 74 } 75 76 static const struct snd_soc_ops haswell_rt5640_ops = { 77 .hw_params = haswell_rt5640_hw_params, 78 }; 79 80 static int haswell_rtd_init(struct snd_soc_pcm_runtime *rtd) 81 { 82 struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); 83 struct sst_pdata *pdata = dev_get_platdata(component->dev); 84 struct sst_hsw *haswell = pdata->dsp; 85 int ret; 86 87 /* Set ADSP SSP port settings */ 88 ret = sst_hsw_device_set_config(haswell, SST_HSW_DEVICE_SSP_0, 89 SST_HSW_DEVICE_MCLK_FREQ_24_MHZ, 90 SST_HSW_DEVICE_CLOCK_MASTER, 9); 91 if (ret < 0) { 92 dev_err(rtd->dev, "failed to set device config\n"); 93 return ret; 94 } 95 96 return 0; 97 } 98 99 SND_SOC_DAILINK_DEF(dummy, 100 DAILINK_COMP_ARRAY(COMP_DUMMY())); 101 102 SND_SOC_DAILINK_DEF(system, 103 DAILINK_COMP_ARRAY(COMP_CPU("System Pin"))); 104 105 SND_SOC_DAILINK_DEF(offload0, 106 DAILINK_COMP_ARRAY(COMP_CPU("Offload0 Pin"))); 107 108 SND_SOC_DAILINK_DEF(offload1, 109 DAILINK_COMP_ARRAY(COMP_CPU("Offload1 Pin"))); 110 111 SND_SOC_DAILINK_DEF(loopback, 112 DAILINK_COMP_ARRAY(COMP_CPU("Loopback Pin"))); 113 114 SND_SOC_DAILINK_DEF(codec, 115 DAILINK_COMP_ARRAY(COMP_CODEC("i2c-INT33CA:00", "rt5640-aif1"))); 116 117 SND_SOC_DAILINK_DEF(platform, 118 DAILINK_COMP_ARRAY(COMP_PLATFORM("haswell-pcm-audio"))); 119 120 static struct snd_soc_dai_link haswell_rt5640_dais[] = { 121 /* Front End DAI links */ 122 { 123 .name = "System", 124 .stream_name = "System Playback/Capture", 125 .dynamic = 1, 126 .init = haswell_rtd_init, 127 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, 128 .dpcm_playback = 1, 129 .dpcm_capture = 1, 130 SND_SOC_DAILINK_REG(system, dummy, platform), 131 }, 132 { 133 .name = "Offload0", 134 .stream_name = "Offload0 Playback", 135 .dynamic = 1, 136 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, 137 .dpcm_playback = 1, 138 SND_SOC_DAILINK_REG(offload0, dummy, platform), 139 }, 140 { 141 .name = "Offload1", 142 .stream_name = "Offload1 Playback", 143 .dynamic = 1, 144 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, 145 .dpcm_playback = 1, 146 SND_SOC_DAILINK_REG(offload1, dummy, platform), 147 }, 148 { 149 .name = "Loopback", 150 .stream_name = "Loopback", 151 .dynamic = 1, 152 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, 153 .dpcm_capture = 1, 154 SND_SOC_DAILINK_REG(loopback, dummy, platform), 155 }, 156 157 /* Back End DAI links */ 158 { 159 /* SSP0 - Codec */ 160 .name = "Codec", 161 .id = 0, 162 .no_pcm = 1, 163 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 164 SND_SOC_DAIFMT_CBS_CFS, 165 .ignore_pmdown_time = 1, 166 .be_hw_params_fixup = haswell_ssp0_fixup, 167 .ops = &haswell_rt5640_ops, 168 .dpcm_playback = 1, 169 .dpcm_capture = 1, 170 SND_SOC_DAILINK_REG(dummy, codec, dummy), 171 }, 172 }; 173 174 /* audio machine driver for Haswell Lynxpoint DSP + RT5640 */ 175 static struct snd_soc_card haswell_rt5640 = { 176 .name = "haswell-rt5640", 177 .owner = THIS_MODULE, 178 .dai_link = haswell_rt5640_dais, 179 .num_links = ARRAY_SIZE(haswell_rt5640_dais), 180 .dapm_widgets = haswell_widgets, 181 .num_dapm_widgets = ARRAY_SIZE(haswell_widgets), 182 .dapm_routes = haswell_rt5640_map, 183 .num_dapm_routes = ARRAY_SIZE(haswell_rt5640_map), 184 .fully_routed = true, 185 }; 186 187 static int haswell_audio_probe(struct platform_device *pdev) 188 { 189 struct snd_soc_acpi_mach *mach; 190 int ret; 191 192 haswell_rt5640.dev = &pdev->dev; 193 194 /* override plaform name, if required */ 195 mach = pdev->dev.platform_data; 196 ret = snd_soc_fixup_dai_links_platform_name(&haswell_rt5640, 197 mach->mach_params.platform); 198 if (ret) 199 return ret; 200 201 return devm_snd_soc_register_card(&pdev->dev, &haswell_rt5640); 202 } 203 204 static struct platform_driver haswell_audio = { 205 .probe = haswell_audio_probe, 206 .driver = { 207 .name = "haswell-audio", 208 }, 209 }; 210 211 module_platform_driver(haswell_audio) 212 213 /* Module information */ 214 MODULE_AUTHOR("Liam Girdwood, Xingchao Wang"); 215 MODULE_DESCRIPTION("Intel SST Audio for Haswell Lynxpoint"); 216 MODULE_LICENSE("GPL v2"); 217 MODULE_ALIAS("platform:haswell-audio"); 218
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.