FILE
rt5640.c
File preview with syntax highlighting.
linux-6.19.14/sound/soc/intel/avs/boards/rt5640.c
1// SPDX-License-Identifier: GPL-2.0-only 2// 3// Copyright(c) 2022-2025 Intel Corporation 4// 5// Authors: Cezary Rojewski <cezary.rojewski@intel.com> 6// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> 7// 8 9#include <linux/module.h> 10#include <sound/jack.h> 11#include <sound/pcm.h> 12#include <sound/pcm_params.h> 13#include <sound/soc.h> 14#include <sound/soc-acpi.h> 15#include "../../../codecs/rt5640.h" 16#include "../utils.h" 17 18#define AVS_RT5640_MCLK_HZ 19200000 19#define RT5640_CODEC_DAI "rt5640-aif1" 20 21static const struct snd_soc_dapm_widget card_widgets[] = { 22 SND_SOC_DAPM_HP("Headphone Jack", NULL), 23 SND_SOC_DAPM_MIC("Mic Jack", NULL), 24 SND_SOC_DAPM_SPK("Speaker", NULL), 25}; 26 27static const struct snd_soc_dapm_route card_routes[] = { 28 { "Headphone Jack", NULL, "HPOR" }, 29 { "Headphone Jack", NULL, "HPOL" }, 30 { "IN2P", NULL, "Mic Jack" }, 31 { "IN2P", NULL, "MICBIAS1" }, 32 { "Speaker", NULL, "SPOLP" }, 33 { "Speaker", NULL, "SPOLN" }, 34 { "Speaker", NULL, "SPORP" }, 35 { "Speaker", NULL, "SPORN" }, 36}; 37 38static const struct snd_soc_jack_pin card_headset_pins[] = { 39 { 40 .pin = "Headphone Jack", 41 .mask = SND_JACK_HEADPHONE, 42 }, 43 { 44 .pin = "Mic Jack", 45 .mask = SND_JACK_MICROPHONE, 46 }, 47}; 48 49static int avs_rt5640_codec_init(struct snd_soc_pcm_runtime *runtime) 50{ 51 struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(runtime, 0); 52 struct snd_soc_card *card = runtime->card; 53 struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card); 54 struct snd_soc_jack_pin *pins; 55 struct snd_soc_jack *jack; 56 int num_pins, ret; 57 58 jack = snd_soc_card_get_drvdata(card); 59 num_pins = ARRAY_SIZE(card_headset_pins); 60 61 pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL); 62 if (!pins) 63 return -ENOMEM; 64 65 ret = snd_soc_card_jack_new_pins(card, "Headset Jack", SND_JACK_HEADSET, jack, pins, 66 num_pins); 67 if (ret) 68 return ret; 69 70 snd_soc_component_set_jack(codec_dai->component, jack, NULL); 71 snd_soc_dapm_set_idle_bias(dapm, false); 72 73 return 0; 74} 75 76static void avs_rt5640_codec_exit(struct snd_soc_pcm_runtime *runtime) 77{ 78 struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(runtime, 0); 79 80 snd_soc_component_set_jack(codec_dai->component, NULL, NULL); 81} 82 83static int avs_rt5640_be_fixup(struct snd_soc_pcm_runtime *runtime, 84 struct snd_pcm_hw_params *params) 85{ 86 struct snd_mask *fmask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); 87 88 /* Format 24/32 is MSB-aligned for HDAudio and LSB-aligned for I2S. */ 89 if (params_format(params) == SNDRV_PCM_FORMAT_S32_LE) 90 snd_mask_set_format(fmask, SNDRV_PCM_FORMAT_S24_LE); 91 92 return 0; 93} 94 95static int avs_rt5640_hw_params(struct snd_pcm_substream *substream, 96 struct snd_pcm_hw_params *params) 97{ 98 struct snd_soc_pcm_runtime *runtime = snd_soc_substream_to_rtd(substream); 99 struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(runtime, 0); 100 int ret; 101 102 ret = snd_soc_dai_set_pll(codec_dai, 0, RT5640_PLL1_S_MCLK, AVS_RT5640_MCLK_HZ, 103 params_rate(params) * 512); 104 if (ret < 0) { 105 dev_err(runtime->dev, "Set codec PLL failed: %d\n", ret); 106 return ret; 107 } 108 109 ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1, params_rate(params) * 512, 110 SND_SOC_CLOCK_IN); 111 if (ret < 0) { 112 dev_err(runtime->dev, "Set codec SCLK failed: %d\n", ret); 113 return ret; 114 } 115 116 ret = rt5640_sel_asrc_clk_src(codec_dai->component, 117 RT5640_DA_STEREO_FILTER | RT5640_AD_STEREO_FILTER | 118 RT5640_DA_MONO_L_FILTER | RT5640_DA_MONO_R_FILTER | 119 RT5640_AD_MONO_L_FILTER | RT5640_AD_MONO_R_FILTER, 120 RT5640_CLK_SEL_ASRC); 121 if (ret) 122 dev_err(runtime->dev, "Set codec ASRC failed: %d\n", ret); 123 124 return ret; 125} 126 127static const struct snd_soc_ops avs_rt5640_ops = { 128 .hw_params = avs_rt5640_hw_params, 129}; 130 131static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot, 132 struct snd_soc_acpi_mach *mach, 133 struct snd_soc_dai_link **dai_link) 134{ 135 struct snd_soc_dai_link_component *platform; 136 struct snd_soc_dai_link *dl; 137 u32 uid = 0; 138 int ret; 139 140 if (mach->uid) { 141 ret = kstrtou32(mach->uid, 0, &uid); 142 if (ret) 143 return ret; 144 uid--; /* 0-based indexing. */ 145 } 146 147 dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL); 148 platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL); 149 if (!dl || !platform) 150 return -ENOMEM; 151 152 dl->name = devm_kasprintf(dev, GFP_KERNEL, 153 AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot)); 154 dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); 155 dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL); 156 if (!dl->name || !dl->cpus || !dl->codecs) 157 return -ENOMEM; 158 159 dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, 160 AVS_STRING_FMT("SSP", " Pin", ssp_port, tdm_slot)); 161 dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-10EC5640:0%d", uid); 162 dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, RT5640_CODEC_DAI); 163 if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name) 164 return -ENOMEM; 165 166 platform->name = dev_name(dev); 167 dl->num_cpus = 1; 168 dl->num_codecs = 1; 169 dl->platforms = platform; 170 dl->num_platforms = 1; 171 dl->id = 0; 172 dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC; 173 dl->init = avs_rt5640_codec_init; 174 dl->exit = avs_rt5640_codec_exit; 175 dl->be_hw_params_fixup = avs_rt5640_be_fixup; 176 dl->ops = &avs_rt5640_ops; 177 dl->nonatomic = 1; 178 dl->no_pcm = 1; 179 180 *dai_link = dl; 181 182 return 0; 183} 184 185static int avs_card_suspend_pre(struct snd_soc_card *card) 186{ 187 struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, RT5640_CODEC_DAI); 188 189 return snd_soc_component_set_jack(codec_dai->component, NULL, NULL); 190} 191 192static int avs_card_resume_post(struct snd_soc_card *card) 193{ 194 struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, RT5640_CODEC_DAI); 195 struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card); 196 197 return snd_soc_component_set_jack(codec_dai->component, jack, NULL); 198} 199 200static int avs_rt5640_probe(struct platform_device *pdev) 201{ 202 struct snd_soc_dai_link *dai_link; 203 struct device *dev = &pdev->dev; 204 struct snd_soc_acpi_mach *mach; 205 struct snd_soc_card *card; 206 struct snd_soc_jack *jack; 207 int ssp_port, tdm_slot, ret; 208 209 mach = dev_get_platdata(dev); 210 211 ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); 212 if (ret) 213 return ret; 214 215 ret = avs_create_dai_link(dev, ssp_port, tdm_slot, mach, &dai_link); 216 if (ret) { 217 dev_err(dev, "Failed to create dai link: %d", ret); 218 return ret; 219 } 220 221 jack = devm_kzalloc(dev, sizeof(*jack), GFP_KERNEL); 222 card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); 223 if (!jack || !card) 224 return -ENOMEM; 225 226 if (mach->uid) { 227 card->name = devm_kasprintf(dev, GFP_KERNEL, "AVS I2S ALC5640.%s", mach->uid); 228 if (!card->name) 229 return -ENOMEM; 230 } else { 231 card->name = "AVS I2S ALC5640"; 232 } 233 card->driver_name = "avs_rt5640"; 234 card->long_name = card->name; 235 card->dev = dev; 236 card->owner = THIS_MODULE; 237 card->suspend_pre = avs_card_suspend_pre; 238 card->resume_post = avs_card_resume_post; 239 card->dai_link = dai_link; 240 card->num_links = 1; 241 card->dapm_widgets = card_widgets; 242 card->num_dapm_widgets = ARRAY_SIZE(card_widgets); 243 card->dapm_routes = card_routes; 244 card->num_dapm_routes = ARRAY_SIZE(card_routes); 245 card->fully_routed = true; 246 snd_soc_card_set_drvdata(card, jack); 247 248 return devm_snd_soc_register_deferrable_card(dev, card); 249} 250 251static const struct platform_device_id avs_rt5640_driver_ids[] = { 252 { 253 .name = "avs_rt5640", 254 }, 255 {}, 256}; 257MODULE_DEVICE_TABLE(platform, avs_rt5640_driver_ids); 258 259static struct platform_driver avs_rt5640_driver = { 260 .probe = avs_rt5640_probe, 261 .driver = { 262 .name = "avs_rt5640", 263 .pm = &snd_soc_pm_ops, 264 }, 265 .id_table = avs_rt5640_driver_ids, 266}; 267 268module_platform_driver(avs_rt5640_driver); 269 270MODULE_DESCRIPTION("Intel rt5640 machine driver"); 271MODULE_LICENSE("GPL");
~/
Read-only file preview.