1 // SPDX-License-Identifier: GPL-2.0+ 2 // 3 // Machine driver for AMD ACP Audio engine using ES8336 codec. 4 // 5 // Copyright 2023 Marian Postevca <posteuca@mutex.one> 6 #include <sound/core.h> 7 #include <sound/soc.h> 8 #include <sound/pcm.h> 9 #include <sound/pcm_params.h> 10 #include <sound/soc-dapm.h> 11 #include <sound/jack.h> 12 #include <sound/soc-acpi.h> 13 #include <linux/clk.h> 14 #include <linux/gpio.h> 15 #include <linux/gpio/consumer.h> 16 #include <linux/module.h> 17 #include <linux/i2c.h> 18 #include <linux/input.h> 19 #include <linux/io.h> 20 #include <linux/acpi.h> 21 #include <linux/dmi.h> 22 #include <linux/string_choices.h> 23 #include "../acp-mach.h" 24 #include "acp3x-es83xx.h" 25 26 #define get_mach_priv(card) ((struct acp3x_es83xx_private *)((acp_get_drvdata(card))->mach_priv)) 27 28 #define DUAL_CHANNEL 2 29 30 #define ES83XX_ENABLE_DMIC BIT(4) 31 #define ES83XX_48_MHZ_MCLK BIT(5) 32 33 struct acp3x_es83xx_private { 34 bool speaker_on; 35 bool headphone_on; 36 unsigned long quirk; 37 struct snd_soc_component *codec; 38 struct device *codec_dev; 39 struct gpio_desc *gpio_speakers, *gpio_headphone; 40 struct acpi_gpio_params enable_spk_gpio, enable_hp_gpio; 41 struct acpi_gpio_mapping gpio_mapping[3]; 42 struct snd_soc_dapm_route mic_map[2]; 43 }; 44 45 static const unsigned int channels[] = { 46 DUAL_CHANNEL, 47 }; 48 49 static const struct snd_pcm_hw_constraint_list constraints_channels = { 50 .count = ARRAY_SIZE(channels), 51 .list = channels, 52 .mask = 0, 53 }; 54 55 #define ES83xx_12288_KHZ_MCLK_FREQ (48000 * 256) 56 #define ES83xx_48_MHZ_MCLK_FREQ (48000 * 1000) 57 58 static int acp3x_es83xx_headphone_power_event(struct snd_soc_dapm_widget *w, 59 struct snd_kcontrol *kcontrol, int event); 60 static int acp3x_es83xx_speaker_power_event(struct snd_soc_dapm_widget *w, 61 struct snd_kcontrol *kcontrol, int event); 62 63 static int acp3x_es83xx_codec_startup(struct snd_pcm_substream *substream) 64 { 65 struct snd_pcm_runtime *runtime; 66 struct snd_soc_pcm_runtime *rtd; 67 struct snd_soc_dai *codec_dai; 68 struct acp3x_es83xx_private *priv; 69 unsigned int freq; 70 int ret; 71 72 runtime = substream->runtime; 73 rtd = snd_soc_substream_to_rtd(substream); 74 codec_dai = snd_soc_rtd_to_codec(rtd, 0); 75 priv = get_mach_priv(rtd->card); 76 77 if (priv->quirk & ES83XX_48_MHZ_MCLK) { 78 dev_dbg(priv->codec_dev, "using a 48Mhz MCLK\n"); 79 freq = ES83xx_48_MHZ_MCLK_FREQ; 80 } else { 81 dev_dbg(priv->codec_dev, "using a 12.288Mhz MCLK\n"); 82 freq = ES83xx_12288_KHZ_MCLK_FREQ; 83 } 84 85 ret = snd_soc_dai_set_sysclk(codec_dai, 0, freq, SND_SOC_CLOCK_OUT); 86 if (ret < 0) { 87 dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret); 88 return ret; 89 } 90 91 runtime->hw.channels_max = DUAL_CHANNEL; 92 snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 93 &constraints_channels); 94 95 return 0; 96 } 97 98 static struct snd_soc_jack es83xx_jack; 99 100 static struct snd_soc_jack_pin es83xx_jack_pins[] = { 101 { 102 .pin = "Headphone", 103 .mask = SND_JACK_HEADPHONE, 104 }, 105 { 106 .pin = "Headset Mic", 107 .mask = SND_JACK_MICROPHONE, 108 }, 109 }; 110 111 static const struct snd_soc_dapm_widget acp3x_es83xx_widgets[] = { 112 SND_SOC_DAPM_SPK("Speaker", NULL), 113 SND_SOC_DAPM_HP("Headphone", NULL), 114 SND_SOC_DAPM_MIC("Headset Mic", NULL), 115 SND_SOC_DAPM_MIC("Internal Mic", NULL), 116 117 SND_SOC_DAPM_SUPPLY("Headphone Power", SND_SOC_NOPM, 0, 0, 118 acp3x_es83xx_headphone_power_event, 119 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), 120 SND_SOC_DAPM_SUPPLY("Speaker Power", SND_SOC_NOPM, 0, 0, 121 acp3x_es83xx_speaker_power_event, 122 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), 123 }; 124 125 static const struct snd_soc_dapm_route acp3x_es83xx_audio_map[] = { 126 {"Headphone", NULL, "HPOL"}, 127 {"Headphone", NULL, "HPOR"}, 128 {"Headphone", NULL, "Headphone Power"}, 129 130 /* 131 * There is no separate speaker output instead the speakers are muxed to 132 * the HP outputs. The mux is controlled Speaker and/or headphone switch. 133 */ 134 {"Speaker", NULL, "HPOL"}, 135 {"Speaker", NULL, "HPOR"}, 136 {"Speaker", NULL, "Speaker Power"}, 137 }; 138 139 140 static const struct snd_kcontrol_new acp3x_es83xx_controls[] = { 141 SOC_DAPM_PIN_SWITCH("Speaker"), 142 SOC_DAPM_PIN_SWITCH("Headphone"), 143 SOC_DAPM_PIN_SWITCH("Headset Mic"), 144 SOC_DAPM_PIN_SWITCH("Internal Mic"), 145 }; 146 147 static int acp3x_es83xx_configure_widgets(struct snd_soc_card *card) 148 { 149 card->dapm_widgets = acp3x_es83xx_widgets; 150 card->num_dapm_widgets = ARRAY_SIZE(acp3x_es83xx_widgets); 151 card->controls = acp3x_es83xx_controls; 152 card->num_controls = ARRAY_SIZE(acp3x_es83xx_controls); 153 card->dapm_routes = acp3x_es83xx_audio_map; 154 card->num_dapm_routes = ARRAY_SIZE(acp3x_es83xx_audio_map); 155 156 return 0; 157 } 158 159 static int acp3x_es83xx_headphone_power_event(struct snd_soc_dapm_widget *w, 160 struct snd_kcontrol *kcontrol, int event) 161 { 162 struct acp3x_es83xx_private *priv = get_mach_priv(w->dapm->card); 163 164 dev_dbg(priv->codec_dev, "headphone power event = %d\n", event); 165 if (SND_SOC_DAPM_EVENT_ON(event)) 166 priv->headphone_on = true; 167 else 168 priv->headphone_on = false; 169 170 gpiod_set_value_cansleep(priv->gpio_speakers, priv->speaker_on); 171 gpiod_set_value_cansleep(priv->gpio_headphone, priv->headphone_on); 172 173 return 0; 174 } 175 176 static int acp3x_es83xx_speaker_power_event(struct snd_soc_dapm_widget *w, 177 struct snd_kcontrol *kcontrol, int event) 178 { 179 struct acp3x_es83xx_private *priv = get_mach_priv(w->dapm->card); 180 181 dev_dbg(priv->codec_dev, "speaker power event: %d\n", event); 182 if (SND_SOC_DAPM_EVENT_ON(event)) 183 priv->speaker_on = true; 184 else 185 priv->speaker_on = false; 186 187 gpiod_set_value_cansleep(priv->gpio_speakers, priv->speaker_on); 188 gpiod_set_value_cansleep(priv->gpio_headphone, priv->headphone_on); 189 190 return 0; 191 } 192 193 static int acp3x_es83xx_suspend_pre(struct snd_soc_card *card) 194 { 195 struct acp3x_es83xx_private *priv = get_mach_priv(card); 196 197 /* We need to disable the jack in the machine driver suspend 198 * callback so that the CODEC suspend callback actually gets 199 * called. Without doing it, the CODEC suspend/resume 200 * callbacks do not get called if headphones are plugged in. 201 * This is because plugging in headphones keeps some supplies 202 * active, this in turn means that the lowest bias level 203 * that the CODEC can go to is SND_SOC_BIAS_STANDBY. 204 * If components do not set idle_bias_on to true then 205 * their suspend/resume callbacks do not get called. 206 */ 207 dev_dbg(priv->codec_dev, "card suspend\n"); 208 snd_soc_component_set_jack(priv->codec, NULL, NULL); 209 return 0; 210 } 211 212 static int acp3x_es83xx_resume_post(struct snd_soc_card *card) 213 { 214 struct acp3x_es83xx_private *priv = get_mach_priv(card); 215 216 /* We disabled jack detection in suspend callback, 217 * enable it back. 218 */ 219 dev_dbg(priv->codec_dev, "card resume\n"); 220 snd_soc_component_set_jack(priv->codec, &es83xx_jack, NULL); 221 return 0; 222 } 223 224 static int acp3x_es83xx_configure_gpios(struct acp3x_es83xx_private *priv) 225 { 226 227 priv->enable_spk_gpio.crs_entry_index = 0; 228 priv->enable_hp_gpio.crs_entry_index = 1; 229 230 priv->enable_spk_gpio.active_low = false; 231 priv->enable_hp_gpio.active_low = false; 232 233 priv->gpio_mapping[0].name = "speakers-enable-gpios"; 234 priv->gpio_mapping[0].data = &priv->enable_spk_gpio; 235 priv->gpio_mapping[0].size = 1; 236 priv->gpio_mapping[0].quirks = ACPI_GPIO_QUIRK_ONLY_GPIOIO; 237 238 priv->gpio_mapping[1].name = "headphone-enable-gpios"; 239 priv->gpio_mapping[1].data = &priv->enable_hp_gpio; 240 priv->gpio_mapping[1].size = 1; 241 priv->gpio_mapping[1].quirks = ACPI_GPIO_QUIRK_ONLY_GPIOIO; 242 243 dev_info(priv->codec_dev, "speaker gpio %d active %s, headphone gpio %d active %s\n", 244 priv->enable_spk_gpio.crs_entry_index, 245 str_low_high(priv->enable_spk_gpio.active_low), 246 priv->enable_hp_gpio.crs_entry_index, 247 str_low_high(priv->enable_hp_gpio.active_low)); 248 return 0; 249 } 250 251 static int acp3x_es83xx_configure_mics(struct acp3x_es83xx_private *priv) 252 { 253 int num_routes = 0; 254 int i; 255 256 if (!(priv->quirk & ES83XX_ENABLE_DMIC)) { 257 priv->mic_map[num_routes].sink = "MIC1"; 258 priv->mic_map[num_routes].source = "Internal Mic"; 259 num_routes++; 260 } 261 262 priv->mic_map[num_routes].sink = "MIC2"; 263 priv->mic_map[num_routes].source = "Headset Mic"; 264 num_routes++; 265 266 for (i = 0; i < num_routes; i++) 267 dev_info(priv->codec_dev, "%s is %s\n", 268 priv->mic_map[i].source, priv->mic_map[i].sink); 269 270 return num_routes; 271 } 272 273 static int acp3x_es83xx_init(struct snd_soc_pcm_runtime *runtime) 274 { 275 struct snd_soc_component *codec = snd_soc_rtd_to_codec(runtime, 0)->component; 276 struct snd_soc_card *card = runtime->card; 277 struct acp3x_es83xx_private *priv = get_mach_priv(card); 278 int ret = 0; 279 int num_routes; 280 281 ret = snd_soc_card_jack_new_pins(card, "Headset", 282 SND_JACK_HEADSET | SND_JACK_BTN_0, 283 &es83xx_jack, es83xx_jack_pins, 284 ARRAY_SIZE(es83xx_jack_pins)); 285 if (ret) { 286 dev_err(card->dev, "jack creation failed %d\n", ret); 287 return ret; 288 } 289 290 snd_jack_set_key(es83xx_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); 291 292 snd_soc_component_set_jack(codec, &es83xx_jack, NULL); 293 294 priv->codec = codec; 295 acp3x_es83xx_configure_gpios(priv); 296 297 ret = devm_acpi_dev_add_driver_gpios(priv->codec_dev, priv->gpio_mapping); 298 if (ret) 299 dev_warn(priv->codec_dev, "failed to add speaker gpio\n"); 300 301 priv->gpio_speakers = gpiod_get_optional(priv->codec_dev, "speakers-enable", 302 priv->enable_spk_gpio.active_low ? GPIOD_OUT_LOW : GPIOD_OUT_HIGH); 303 if (IS_ERR(priv->gpio_speakers)) { 304 dev_err(priv->codec_dev, "could not get speakers-enable GPIO\n"); 305 return PTR_ERR(priv->gpio_speakers); 306 } 307 308 priv->gpio_headphone = gpiod_get_optional(priv->codec_dev, "headphone-enable", 309 priv->enable_hp_gpio.active_low ? GPIOD_OUT_LOW : GPIOD_OUT_HIGH); 310 if (IS_ERR(priv->gpio_headphone)) { 311 dev_err(priv->codec_dev, "could not get headphone-enable GPIO\n"); 312 return PTR_ERR(priv->gpio_headphone); 313 } 314 315 num_routes = acp3x_es83xx_configure_mics(priv); 316 if (num_routes > 0) { 317 ret = snd_soc_dapm_add_routes(&card->dapm, priv->mic_map, num_routes); 318 if (ret != 0) 319 device_remove_software_node(priv->codec_dev); 320 } 321 322 return ret; 323 } 324 325 static const struct snd_soc_ops acp3x_es83xx_ops = { 326 .startup = acp3x_es83xx_codec_startup, 327 }; 328 329 330 SND_SOC_DAILINK_DEF(codec, 331 DAILINK_COMP_ARRAY(COMP_CODEC("i2c-ESSX8336:00", "ES8316 HiFi"))); 332 333 static const struct dmi_system_id acp3x_es83xx_dmi_table[] = { 334 { 335 .matches = { 336 DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "HUAWEI"), 337 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "KLVL-WXXW"), 338 DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "M1010"), 339 }, 340 .driver_data = (void *)(ES83XX_ENABLE_DMIC), 341 }, 342 { 343 .matches = { 344 DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "HUAWEI"), 345 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "KLVL-WXX9"), 346 DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "M1010"), 347 }, 348 .driver_data = (void *)(ES83XX_ENABLE_DMIC), 349 }, 350 { 351 .matches = { 352 DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "HUAWEI"), 353 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "BOM-WXX9"), 354 DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "M1010"), 355 }, 356 .driver_data = (void *)(ES83XX_ENABLE_DMIC|ES83XX_48_MHZ_MCLK), 357 }, 358 { 359 .matches = { 360 DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "HUAWEI"), 361 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HVY-WXX9"), 362 DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "M1010"), 363 }, 364 .driver_data = (void *)(ES83XX_ENABLE_DMIC), 365 }, 366 { 367 .matches = { 368 DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "HUAWEI"), 369 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HVY-WXX9"), 370 DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "M1020"), 371 }, 372 .driver_data = (void *)(ES83XX_ENABLE_DMIC), 373 }, 374 { 375 .matches = { 376 DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "HUAWEI"), 377 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HVY-WXX9"), 378 DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "M1040"), 379 }, 380 .driver_data = (void *)(ES83XX_ENABLE_DMIC), 381 }, 382 {} 383 }; 384 385 static int acp3x_es83xx_configure_link(struct snd_soc_card *card, struct snd_soc_dai_link *link) 386 { 387 link->codecs = codec; 388 link->num_codecs = ARRAY_SIZE(codec); 389 link->init = acp3x_es83xx_init; 390 link->ops = &acp3x_es83xx_ops; 391 link->dai_fmt = SND_SOC_DAIFMT_I2S 392 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP; 393 394 return 0; 395 } 396 397 static int acp3x_es83xx_probe(struct snd_soc_card *card) 398 { 399 int ret = 0; 400 struct device *dev = card->dev; 401 const struct dmi_system_id *dmi_id; 402 403 dmi_id = dmi_first_match(acp3x_es83xx_dmi_table); 404 if (dmi_id && dmi_id->driver_data) { 405 struct acp3x_es83xx_private *priv; 406 struct acp_card_drvdata *acp_drvdata; 407 struct acpi_device *adev; 408 struct device *codec_dev; 409 410 acp_drvdata = (struct acp_card_drvdata *)card->drvdata; 411 412 dev_info(dev, "matched DMI table with this system, trying to register sound card\n"); 413 414 adev = acpi_dev_get_first_match_dev(acp_drvdata->acpi_mach->id, NULL, -1); 415 if (!adev) { 416 dev_err(dev, "Error cannot find '%s' dev\n", acp_drvdata->acpi_mach->id); 417 return -ENXIO; 418 } 419 420 codec_dev = acpi_get_first_physical_node(adev); 421 acpi_dev_put(adev); 422 if (!codec_dev) { 423 dev_warn(dev, "Error cannot find codec device, will defer probe\n"); 424 return -EPROBE_DEFER; 425 } 426 427 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 428 if (!priv) { 429 put_device(codec_dev); 430 return -ENOMEM; 431 } 432 433 priv->codec_dev = codec_dev; 434 priv->quirk = (unsigned long)dmi_id->driver_data; 435 acp_drvdata->mach_priv = priv; 436 dev_info(dev, "successfully probed the sound card\n"); 437 } else { 438 ret = -ENODEV; 439 dev_warn(dev, "this system has a ES83xx codec defined in ACPI, but the driver doesn't have this system registered in DMI table\n"); 440 } 441 return ret; 442 } 443 444 445 void acp3x_es83xx_init_ops(struct acp_mach_ops *ops) 446 { 447 ops->probe = acp3x_es83xx_probe; 448 ops->configure_widgets = acp3x_es83xx_configure_widgets; 449 ops->configure_link = acp3x_es83xx_configure_link; 450 ops->suspend_pre = acp3x_es83xx_suspend_pre; 451 ops->resume_post = acp3x_es83xx_resume_post; 452 } 453