1/* 2 * Machine driver for AMD ACP Audio engine using DA7219 & MAX98357 codec 3 * 4 * Copyright 2017 Advanced Micro Devices, Inc. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 * OTHER DEALINGS IN THE SOFTWARE. 23 * 24 */ 25 26#include <sound/core.h> 27#include <sound/soc.h> 28#include <sound/pcm.h> 29#include <sound/pcm_params.h> 30#include <sound/soc-dapm.h> 31#include <sound/jack.h> 32#include <linux/clk.h> 33#include <linux/gpio.h> 34#include <linux/module.h> 35#include <linux/regulator/machine.h> 36#include <linux/regulator/driver.h> 37#include <linux/i2c.h> 38#include <linux/input.h> 39#include <linux/acpi.h> 40 41#include "acp.h" 42#include "../codecs/da7219.h" 43#include "../codecs/da7219-aad.h" 44 45#define CZ_PLAT_CLK 48000000 46#define DUAL_CHANNEL 2 47 48static struct snd_soc_jack cz_jack; 49static struct clk *da7219_dai_wclk; 50static struct clk *da7219_dai_bclk; 51extern bool bt_uart_enable; 52 53static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd) 54{ 55 int ret; 56 struct snd_soc_card *card = rtd->card; 57 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 58 struct snd_soc_component *component = codec_dai->component; 59 60 dev_info(rtd->dev, "codec dai name = %s\n", codec_dai->name); 61 62 ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, 63 CZ_PLAT_CLK, SND_SOC_CLOCK_IN); 64 if (ret < 0) { 65 dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret); 66 return ret; 67 } 68 69 ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_PLL, 70 CZ_PLAT_CLK, DA7219_PLL_FREQ_OUT_98304); 71 if (ret < 0) { 72 dev_err(rtd->dev, "can't set codec pll: %d\n", ret); 73 return ret; 74 } 75 76 da7219_dai_wclk = devm_clk_get(component->dev, "da7219-dai-wclk"); 77 if (IS_ERR(da7219_dai_wclk)) 78 return PTR_ERR(da7219_dai_wclk); 79 80 da7219_dai_bclk = devm_clk_get(component->dev, "da7219-dai-bclk"); 81 if (IS_ERR(da7219_dai_bclk)) 82 return PTR_ERR(da7219_dai_bclk); 83 84 ret = snd_soc_card_jack_new(card, "Headset Jack", 85 SND_JACK_HEADSET | SND_JACK_LINEOUT | 86 SND_JACK_BTN_0 | SND_JACK_BTN_1 | 87 SND_JACK_BTN_2 | SND_JACK_BTN_3, 88 &cz_jack, NULL, 0); 89 if (ret) { 90 dev_err(card->dev, "HP jack creation failed %d\n", ret); 91 return ret; 92 } 93 94 snd_jack_set_key(cz_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); 95 snd_jack_set_key(cz_jack.jack, SND_JACK_BTN_1, KEY_VOLUMEUP); 96 snd_jack_set_key(cz_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); 97 snd_jack_set_key(cz_jack.jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); 98 99 da7219_aad_jack_det(component, &cz_jack); 100 101 return 0; 102} 103 104static int da7219_clk_enable(struct snd_pcm_substream *substream) 105{ 106 int ret = 0; 107 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 108 109 /* 110 * Set wclk to 48000 because the rate constraint of this driver is 111 * 48000. ADAU7002 spec: "The ADAU7002 requires a BCLK rate that is 112 * minimum of 64x the LRCLK sample rate." DA7219 is the only clk 113 * source so for all codecs we have to limit bclk to 64X lrclk. 114 */ 115 clk_set_rate(da7219_dai_wclk, 48000); 116 clk_set_rate(da7219_dai_bclk, 48000 * 64); 117 ret = clk_prepare_enable(da7219_dai_bclk); 118 if (ret < 0) { 119 dev_err(rtd->dev, "can't enable master clock %d\n", ret); 120 return ret; 121 } 122 123 return ret; 124} 125 126static void da7219_clk_disable(void) 127{ 128 clk_disable_unprepare(da7219_dai_bclk); 129} 130 131static const unsigned int channels[] = { 132 DUAL_CHANNEL, 133}; 134 135static const unsigned int rates[] = { 136 48000, 137}; 138 139static const struct snd_pcm_hw_constraint_list constraints_rates = { 140 .count = ARRAY_SIZE(rates), 141 .list = rates, 142 .mask = 0, 143}; 144 145static const struct snd_pcm_hw_constraint_list constraints_channels = { 146 .count = ARRAY_SIZE(channels), 147 .list = channels, 148 .mask = 0, 149}; 150 151static int cz_da7219_play_startup(struct snd_pcm_substream *substream) 152{ 153 struct snd_pcm_runtime *runtime = substream->runtime; 154 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 155 struct snd_soc_card *card = rtd->card; 156 struct acp_platform_info *machine = snd_soc_card_get_drvdata(card); 157 158 /* 159 * On this platform for PCM device we support stereo 160 */ 161 162 runtime->hw.channels_max = DUAL_CHANNEL; 163 snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 164 &constraints_channels); 165 snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 166 &constraints_rates); 167 168 machine->play_i2s_instance = I2S_SP_INSTANCE; 169 return da7219_clk_enable(substream); 170} 171 172static int cz_da7219_cap_startup(struct snd_pcm_substream *substream) 173{ 174 struct snd_pcm_runtime *runtime = substream->runtime; 175 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 176 struct snd_soc_card *card = rtd->card; 177 struct acp_platform_info *machine = snd_soc_card_get_drvdata(card); 178 179 /* 180 * On this platform for PCM device we support stereo 181 */ 182 183 runtime->hw.channels_max = DUAL_CHANNEL; 184 snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 185 &constraints_channels); 186 snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 187 &constraints_rates); 188 189 machine->cap_i2s_instance = I2S_SP_INSTANCE; 190 machine->capture_channel = CAP_CHANNEL1; 191 return da7219_clk_enable(substream); 192} 193 194static int cz_max_startup(struct snd_pcm_substream *substream) 195{ 196 struct snd_pcm_runtime *runtime = substream->runtime; 197 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 198 struct snd_soc_card *card = rtd->card; 199 struct acp_platform_info *machine = snd_soc_card_get_drvdata(card); 200 201 /* 202 * On this platform for PCM device we support stereo 203 */ 204 205 runtime->hw.channels_max = DUAL_CHANNEL; 206 snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 207 &constraints_channels); 208 snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 209 &constraints_rates); 210 211 machine->play_i2s_instance = I2S_BT_INSTANCE; 212 return da7219_clk_enable(substream); 213} 214 215static int cz_dmic0_startup(struct snd_pcm_substream *substream) 216{ 217 struct snd_pcm_runtime *runtime = substream->runtime; 218 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 219 struct snd_soc_card *card = rtd->card; 220 struct acp_platform_info *machine = snd_soc_card_get_drvdata(card); 221 222 /* 223 * On this platform for PCM device we support stereo 224 */ 225 226 runtime->hw.channels_max = DUAL_CHANNEL; 227 snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 228 &constraints_channels); 229 snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 230 &constraints_rates); 231 232 machine->cap_i2s_instance = I2S_BT_INSTANCE; 233 return da7219_clk_enable(substream); 234} 235 236static int cz_dmic1_startup(struct snd_pcm_substream *substream) 237{ 238 struct snd_pcm_runtime *runtime = substream->runtime; 239 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 240 struct snd_soc_card *card = rtd->card; 241 struct acp_platform_info *machine = snd_soc_card_get_drvdata(card); 242 243 /* 244 * On this platform for PCM device we support stereo 245 */ 246 247 runtime->hw.channels_max = DUAL_CHANNEL; 248 snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 249 &constraints_channels); 250 snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 251 &constraints_rates); 252 253 machine->cap_i2s_instance = I2S_SP_INSTANCE; 254 machine->capture_channel = CAP_CHANNEL0; 255 return da7219_clk_enable(substream); 256} 257 258static void cz_da7219_shutdown(struct snd_pcm_substream *substream) 259{ 260 da7219_clk_disable(); 261} 262 263static const struct snd_soc_ops cz_da7219_play_ops = { 264 .startup = cz_da7219_play_startup, 265 .shutdown = cz_da7219_shutdown, 266}; 267 268static const struct snd_soc_ops cz_da7219_cap_ops = { 269 .startup = cz_da7219_cap_startup, 270 .shutdown = cz_da7219_shutdown, 271}; 272 273static const struct snd_soc_ops cz_max_play_ops = { 274 .startup = cz_max_startup, 275 .shutdown = cz_da7219_shutdown, 276}; 277 278static const struct snd_soc_ops cz_dmic0_cap_ops = { 279 .startup = cz_dmic0_startup, 280 .shutdown = cz_da7219_shutdown, 281}; 282 283static const struct snd_soc_ops cz_dmic1_cap_ops = { 284 .startup = cz_dmic1_startup, 285 .shutdown = cz_da7219_shutdown, 286}; 287 288SND_SOC_DAILINK_DEF(designware1, 289 DAILINK_COMP_ARRAY(COMP_CPU("designware-i2s.1.auto"))); 290SND_SOC_DAILINK_DEF(designware2, 291 DAILINK_COMP_ARRAY(COMP_CPU("designware-i2s.2.auto"))); 292SND_SOC_DAILINK_DEF(designware3, 293 DAILINK_COMP_ARRAY(COMP_CPU("designware-i2s.3.auto"))); 294 295SND_SOC_DAILINK_DEF(dlgs, 296 DAILINK_COMP_ARRAY(COMP_CODEC("i2c-DLGS7219:00", "da7219-hifi"))); 297SND_SOC_DAILINK_DEF(mx, 298 DAILINK_COMP_ARRAY(COMP_CODEC("MX98357A:00", "HiFi"))); 299SND_SOC_DAILINK_DEF(adau, 300 DAILINK_COMP_ARRAY(COMP_CODEC("ADAU7002:00", "adau7002-hifi"))); 301 302SND_SOC_DAILINK_DEF(platform, 303 DAILINK_COMP_ARRAY(COMP_PLATFORM("acp_audio_dma.0.auto"))); 304 305static struct snd_soc_dai_link cz_dai_7219_98357[] = { 306 { 307 .name = "amd-da7219-play", 308 .stream_name = "Playback", 309 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 310 | SND_SOC_DAIFMT_CBM_CFM, 311 .init = cz_da7219_init, 312 .dpcm_playback = 1, 313 .ops = &cz_da7219_play_ops, 314 SND_SOC_DAILINK_REG(designware1, dlgs, platform), 315 }, 316 { 317 .name = "amd-da7219-cap", 318 .stream_name = "Capture", 319 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 320 | SND_SOC_DAIFMT_CBM_CFM, 321 .dpcm_capture = 1, 322 .ops = &cz_da7219_cap_ops, 323 SND_SOC_DAILINK_REG(designware2, dlgs, platform), 324 }, 325 { 326 .name = "amd-max98357-play", 327 .stream_name = "HiFi Playback", 328 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 329 | SND_SOC_DAIFMT_CBM_CFM, 330 .dpcm_playback = 1, 331 .ops = &cz_max_play_ops, 332 SND_SOC_DAILINK_REG(designware3, mx, platform), 333 }, 334 { 335 /* C panel DMIC */ 336 .name = "dmic0", 337 .stream_name = "DMIC0 Capture", 338 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 339 | SND_SOC_DAIFMT_CBM_CFM, 340 .dpcm_capture = 1, 341 .ops = &cz_dmic0_cap_ops, 342 SND_SOC_DAILINK_REG(designware3, adau, platform), 343 }, 344 { 345 /* A/B panel DMIC */ 346 .name = "dmic1", 347 .stream_name = "DMIC1 Capture", 348 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 349 | SND_SOC_DAIFMT_CBM_CFM, 350 .dpcm_capture = 1, 351 .ops = &cz_dmic1_cap_ops, 352 SND_SOC_DAILINK_REG(designware2, adau, platform), 353 }, 354}; 355 356static const struct snd_soc_dapm_widget cz_widgets[] = { 357 SND_SOC_DAPM_HP("Headphones", NULL), 358 SND_SOC_DAPM_SPK("Speakers", NULL), 359 SND_SOC_DAPM_MIC("Headset Mic", NULL), 360 SND_SOC_DAPM_MIC("Int Mic", NULL), 361}; 362 363static const struct snd_soc_dapm_route cz_audio_route[] = { 364 {"Headphones", NULL, "HPL"}, 365 {"Headphones", NULL, "HPR"}, 366 {"MIC", NULL, "Headset Mic"}, 367 {"Speakers", NULL, "Speaker"}, 368 {"PDM_DAT", NULL, "Int Mic"}, 369}; 370 371static const struct snd_kcontrol_new cz_mc_controls[] = { 372 SOC_DAPM_PIN_SWITCH("Headphones"), 373 SOC_DAPM_PIN_SWITCH("Speakers"), 374 SOC_DAPM_PIN_SWITCH("Headset Mic"), 375 SOC_DAPM_PIN_SWITCH("Int Mic"), 376}; 377 378static struct snd_soc_card cz_card = { 379 .name = "acpd7219m98357", 380 .owner = THIS_MODULE, 381 .dai_link = cz_dai_7219_98357, 382 .num_links = ARRAY_SIZE(cz_dai_7219_98357), 383 .dapm_widgets = cz_widgets, 384 .num_dapm_widgets = ARRAY_SIZE(cz_widgets), 385 .dapm_routes = cz_audio_route, 386 .num_dapm_routes = ARRAY_SIZE(cz_audio_route), 387 .controls = cz_mc_controls, 388 .num_controls = ARRAY_SIZE(cz_mc_controls), 389}; 390 391static struct regulator_consumer_supply acp_da7219_supplies[] = { 392 REGULATOR_SUPPLY("VDD", "i2c-DLGS7219:00"), 393 REGULATOR_SUPPLY("VDDMIC", "i2c-DLGS7219:00"), 394 REGULATOR_SUPPLY("VDDIO", "i2c-DLGS7219:00"), 395 REGULATOR_SUPPLY("IOVDD", "ADAU7002:00"), 396}; 397 398static struct regulator_init_data acp_da7219_data = { 399 .constraints = { 400 .always_on = 1, 401 }, 402 .num_consumer_supplies = ARRAY_SIZE(acp_da7219_supplies), 403 .consumer_supplies = acp_da7219_supplies, 404}; 405 406static struct regulator_config acp_da7219_cfg = { 407 .init_data = &acp_da7219_data, 408}; 409 410static struct regulator_ops acp_da7219_ops = { 411}; 412 413static const struct regulator_desc acp_da7219_desc = { 414 .name = "reg-fixed-1.8V", 415 .type = REGULATOR_VOLTAGE, 416 .owner = THIS_MODULE, 417 .ops = &acp_da7219_ops, 418 .fixed_uV = 1800000, /* 1.8V */ 419 .n_voltages = 1, 420}; 421 422static int cz_probe(struct platform_device *pdev) 423{ 424 int ret; 425 struct snd_soc_card *card; 426 struct acp_platform_info *machine; 427 struct regulator_dev *rdev; 428 429 acp_da7219_cfg.dev = &pdev->dev; 430 rdev = devm_regulator_register(&pdev->dev, &acp_da7219_desc, 431 &acp_da7219_cfg); 432 if (IS_ERR(rdev)) { 433 dev_err(&pdev->dev, "Failed to register regulator: %d\n", 434 (int)PTR_ERR(rdev)); 435 return -EINVAL; 436 } 437 438 machine = devm_kzalloc(&pdev->dev, sizeof(struct acp_platform_info), 439 GFP_KERNEL); 440 if (!machine) 441 return -ENOMEM; 442 card = &cz_card; 443 cz_card.dev = &pdev->dev; 444 platform_set_drvdata(pdev, card); 445 snd_soc_card_set_drvdata(card, machine); 446 ret = devm_snd_soc_register_card(&pdev->dev, &cz_card); 447 if (ret) { 448 dev_err(&pdev->dev, 449 "devm_snd_soc_register_card(%s) failed: %d\n", 450 cz_card.name, ret); 451 return ret; 452 } 453 bt_uart_enable = !device_property_read_bool(&pdev->dev, 454 "bt-pad-enable"); 455 return 0; 456} 457 458#ifdef CONFIG_ACPI 459static const struct acpi_device_id cz_audio_acpi_match[] = { 460 { "AMD7219", 0 }, 461 {}, 462}; 463MODULE_DEVICE_TABLE(acpi, cz_audio_acpi_match); 464#endif 465 466static struct platform_driver cz_pcm_driver = { 467 .driver = { 468 .name = "cz-da7219-max98357a", 469 .acpi_match_table = ACPI_PTR(cz_audio_acpi_match), 470 .pm = &snd_soc_pm_ops, 471 }, 472 .probe = cz_probe, 473}; 474 475module_platform_driver(cz_pcm_driver); 476 477MODULE_AUTHOR("akshu.agrawal@amd.com"); 478MODULE_DESCRIPTION("DA7219 & MAX98357A audio support"); 479MODULE_LICENSE("GPL v2"); 480