1 // SPDX-License-Identifier: GPL-2.0-only 2 // Copyright(c) 2021 Intel Corporation. 3 // Copyright(c) 2021 Nuvoton Corporation. 4 5 /* 6 * Intel SOF Machine Driver with Nuvoton headphone codec NAU8825 7 * and speaker codec RT1019P MAX98360a or MAX98373 8 */ 9 #include <linux/i2c.h> 10 #include <linux/input.h> 11 #include <linux/module.h> 12 #include <linux/platform_device.h> 13 #include <linux/dmi.h> 14 #include <sound/core.h> 15 #include <sound/jack.h> 16 #include <sound/pcm.h> 17 #include <sound/pcm_params.h> 18 #include <sound/soc.h> 19 #include <sound/sof.h> 20 #include <sound/soc-acpi.h> 21 #include "../../codecs/nau8825.h" 22 #include "../common/soc-intel-quirks.h" 23 #include "sof_board_helpers.h" 24 #include "sof_realtek_common.h" 25 #include "sof_maxim_common.h" 26 #include "sof_nuvoton_common.h" 27 28 static unsigned long sof_nau8825_quirk = SOF_SSP_PORT_CODEC(0); 29 30 static struct snd_soc_jack_pin jack_pins[] = { 31 { 32 .pin = "Headphone Jack", 33 .mask = SND_JACK_HEADPHONE, 34 }, 35 { 36 .pin = "Headset Mic", 37 .mask = SND_JACK_MICROPHONE, 38 }, 39 }; 40 41 static int sof_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd) 42 { 43 struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); 44 struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; 45 struct snd_soc_jack *jack = &ctx->headset_jack; 46 int ret; 47 48 /* 49 * Headset buttons map to the google Reference headset. 50 * These can be configured by userspace. 51 */ 52 ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", 53 SND_JACK_HEADSET | SND_JACK_BTN_0 | 54 SND_JACK_BTN_1 | SND_JACK_BTN_2 | 55 SND_JACK_BTN_3, 56 jack, 57 jack_pins, 58 ARRAY_SIZE(jack_pins)); 59 if (ret) { 60 dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); 61 return ret; 62 } 63 64 snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); 65 snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); 66 snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); 67 snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); 68 69 ret = snd_soc_component_set_jack(component, jack, NULL); 70 if (ret) { 71 dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret); 72 return ret; 73 } 74 75 return ret; 76 }; 77 78 static void sof_nau8825_codec_exit(struct snd_soc_pcm_runtime *rtd) 79 { 80 struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; 81 82 snd_soc_component_set_jack(component, NULL, NULL); 83 } 84 85 static int sof_nau8825_hw_params(struct snd_pcm_substream *substream, 86 struct snd_pcm_hw_params *params) 87 { 88 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); 89 struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); 90 int clk_freq, ret; 91 92 clk_freq = sof_dai_get_bclk(rtd); /* BCLK freq */ 93 94 if (clk_freq <= 0) { 95 dev_err(rtd->dev, "get bclk freq failed: %d\n", clk_freq); 96 return -EINVAL; 97 } 98 99 /* Configure clock for codec */ 100 ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_FLL_BLK, 0, 101 SND_SOC_CLOCK_IN); 102 if (ret < 0) { 103 dev_err(codec_dai->dev, "can't set BCLK clock %d\n", ret); 104 return ret; 105 } 106 107 /* Configure pll for codec */ 108 ret = snd_soc_dai_set_pll(codec_dai, 0, 0, clk_freq, 109 params_rate(params) * 256); 110 if (ret < 0) { 111 dev_err(codec_dai->dev, "can't set BCLK: %d\n", ret); 112 return ret; 113 } 114 115 return ret; 116 } 117 118 static struct snd_soc_ops sof_nau8825_ops = { 119 .hw_params = sof_nau8825_hw_params, 120 }; 121 122 static int sof_card_late_probe(struct snd_soc_card *card) 123 { 124 struct sof_card_private *ctx = snd_soc_card_get_drvdata(card); 125 struct snd_soc_dapm_context *dapm = &card->dapm; 126 int err; 127 128 if (ctx->amp_type == CODEC_MAX98373) { 129 /* Disable Left and Right Spk pin after boot */ 130 snd_soc_dapm_disable_pin(dapm, "Left Spk"); 131 snd_soc_dapm_disable_pin(dapm, "Right Spk"); 132 err = snd_soc_dapm_sync(dapm); 133 if (err < 0) 134 return err; 135 } 136 137 return sof_intel_board_card_late_probe(card); 138 } 139 140 static const struct snd_kcontrol_new sof_controls[] = { 141 SOC_DAPM_PIN_SWITCH("Headphone Jack"), 142 SOC_DAPM_PIN_SWITCH("Headset Mic"), 143 SOC_DAPM_PIN_SWITCH("Left Spk"), 144 SOC_DAPM_PIN_SWITCH("Right Spk"), 145 }; 146 147 static const struct snd_soc_dapm_widget sof_widgets[] = { 148 SND_SOC_DAPM_HP("Headphone Jack", NULL), 149 SND_SOC_DAPM_MIC("Headset Mic", NULL), 150 SND_SOC_DAPM_SPK("Left Spk", NULL), 151 SND_SOC_DAPM_SPK("Right Spk", NULL), 152 }; 153 154 static const struct snd_soc_dapm_route sof_map[] = { 155 /* HP jack connectors - unknown if we have jack detection */ 156 { "Headphone Jack", NULL, "HPOL" }, 157 { "Headphone Jack", NULL, "HPOR" }, 158 159 /* other jacks */ 160 { "MIC", NULL, "Headset Mic" }, 161 }; 162 163 /* sof audio machine driver for nau8825 codec */ 164 static struct snd_soc_card sof_audio_card_nau8825 = { 165 .name = "nau8825", /* the sof- prefix is added by the core */ 166 .owner = THIS_MODULE, 167 .controls = sof_controls, 168 .num_controls = ARRAY_SIZE(sof_controls), 169 .dapm_widgets = sof_widgets, 170 .num_dapm_widgets = ARRAY_SIZE(sof_widgets), 171 .dapm_routes = sof_map, 172 .num_dapm_routes = ARRAY_SIZE(sof_map), 173 .fully_routed = true, 174 .late_probe = sof_card_late_probe, 175 }; 176 177 static struct snd_soc_dai_link_component nau8825_component[] = { 178 { 179 .name = "i2c-10508825:00", 180 .dai_name = "nau8825-hifi", 181 } 182 }; 183 184 static int 185 sof_card_dai_links_create(struct device *dev, struct snd_soc_card *card, 186 struct sof_card_private *ctx) 187 { 188 int ret; 189 190 ret = sof_intel_board_set_dai_link(dev, card, ctx); 191 if (ret) 192 return ret; 193 194 if (!ctx->codec_link) { 195 dev_err(dev, "codec link not available"); 196 return -EINVAL; 197 } 198 199 /* codec-specific fields for headphone codec */ 200 ctx->codec_link->codecs = nau8825_component; 201 ctx->codec_link->num_codecs = ARRAY_SIZE(nau8825_component); 202 ctx->codec_link->init = sof_nau8825_codec_init; 203 ctx->codec_link->exit = sof_nau8825_codec_exit; 204 ctx->codec_link->ops = &sof_nau8825_ops; 205 206 if (ctx->amp_type == CODEC_NONE) 207 return 0; 208 209 if (!ctx->amp_link) { 210 dev_err(dev, "amp link not available"); 211 return -EINVAL; 212 } 213 214 /* codec-specific fields for speaker amplifier */ 215 switch (ctx->amp_type) { 216 case CODEC_MAX98360A: 217 max_98360a_dai_link(ctx->amp_link); 218 break; 219 case CODEC_MAX98373: 220 ctx->amp_link->codecs = max_98373_components; 221 ctx->amp_link->num_codecs = ARRAY_SIZE(max_98373_components); 222 ctx->amp_link->init = max_98373_spk_codec_init; 223 ctx->amp_link->ops = &max_98373_ops; 224 break; 225 case CODEC_NAU8318: 226 nau8318_set_dai_link(ctx->amp_link); 227 break; 228 case CODEC_RT1015P: 229 sof_rt1015p_dai_link(ctx->amp_link); 230 break; 231 case CODEC_RT1019P: 232 sof_rt1019p_dai_link(ctx->amp_link); 233 break; 234 default: 235 dev_err(dev, "invalid amp type %d\n", ctx->amp_type); 236 return -EINVAL; 237 } 238 239 return 0; 240 } 241 242 static int sof_audio_probe(struct platform_device *pdev) 243 { 244 struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; 245 struct sof_card_private *ctx; 246 int ret; 247 248 if (pdev->id_entry && pdev->id_entry->driver_data) 249 sof_nau8825_quirk = (unsigned long)pdev->id_entry->driver_data; 250 251 dev_dbg(&pdev->dev, "sof_nau8825_quirk = %lx\n", sof_nau8825_quirk); 252 253 /* initialize ctx with board quirk */ 254 ctx = sof_intel_board_get_ctx(&pdev->dev, sof_nau8825_quirk); 255 if (!ctx) 256 return -ENOMEM; 257 258 if (mach->mach_params.codec_mask & IDISP_CODEC_MASK) 259 ctx->hdmi.idisp_codec = true; 260 261 /* update dai_link */ 262 ret = sof_card_dai_links_create(&pdev->dev, &sof_audio_card_nau8825, ctx); 263 if (ret) 264 return ret; 265 266 /* update codec_conf */ 267 switch (ctx->amp_type) { 268 case CODEC_MAX98373: 269 max_98373_set_codec_conf(&sof_audio_card_nau8825); 270 break; 271 case CODEC_RT1015P: 272 sof_rt1015p_codec_conf(&sof_audio_card_nau8825); 273 break; 274 case CODEC_MAX98360A: 275 case CODEC_NAU8318: 276 case CODEC_RT1019P: 277 case CODEC_NONE: 278 /* no codec conf required */ 279 break; 280 default: 281 dev_err(&pdev->dev, "invalid amp type %d\n", ctx->amp_type); 282 return -EINVAL; 283 } 284 285 sof_audio_card_nau8825.dev = &pdev->dev; 286 287 /* set platform name for each dailink */ 288 ret = snd_soc_fixup_dai_links_platform_name(&sof_audio_card_nau8825, 289 mach->mach_params.platform); 290 if (ret) 291 return ret; 292 293 snd_soc_card_set_drvdata(&sof_audio_card_nau8825, ctx); 294 295 return devm_snd_soc_register_card(&pdev->dev, 296 &sof_audio_card_nau8825); 297 } 298 299 static const struct platform_device_id board_ids[] = { 300 { 301 .name = "adl_rt1019p_8825", 302 .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(0) | 303 SOF_SSP_PORT_AMP(2) | 304 SOF_NUM_IDISP_HDMI(4)), 305 }, 306 { 307 .name = "adl_nau8825_def", 308 .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(0) | 309 SOF_SSP_PORT_AMP(1) | 310 SOF_NUM_IDISP_HDMI(4) | 311 SOF_SSP_PORT_BT_OFFLOAD(2) | 312 SOF_BT_OFFLOAD_PRESENT), 313 }, 314 { 315 .name = "rpl_nau8825_def", 316 .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(0) | 317 SOF_SSP_PORT_AMP(1) | 318 SOF_NUM_IDISP_HDMI(4) | 319 SOF_SSP_PORT_BT_OFFLOAD(2) | 320 SOF_BT_OFFLOAD_PRESENT), 321 }, 322 { 323 .name = "mtl_nau8825_def", 324 .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(2) | 325 SOF_SSP_PORT_AMP(0) | 326 SOF_SSP_PORT_BT_OFFLOAD(1) | 327 SOF_BT_OFFLOAD_PRESENT), 328 }, 329 { } 330 }; 331 MODULE_DEVICE_TABLE(platform, board_ids); 332 333 static struct platform_driver sof_audio = { 334 .probe = sof_audio_probe, 335 .driver = { 336 .name = "sof_nau8825", 337 .pm = &snd_soc_pm_ops, 338 }, 339 .id_table = board_ids, 340 }; 341 module_platform_driver(sof_audio) 342 343 /* Module information */ 344 MODULE_DESCRIPTION("SOF Audio Machine driver for NAU8825"); 345 MODULE_AUTHOR("David Lin <ctlin0@nuvoton.com>"); 346 MODULE_AUTHOR("Mac Chiang <mac.chiang@intel.com>"); 347 MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>"); 348 MODULE_LICENSE("GPL"); 349 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS); 350 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON); 351 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_NUVOTON_COMMON); 352 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_REALTEK_COMMON); 353