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