root/sound/soc/amd/acp-da7219-max98357a.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cz_da7219_init
  2. da7219_clk_enable
  3. da7219_clk_disable
  4. cz_da7219_play_startup
  5. cz_da7219_cap_startup
  6. cz_max_startup
  7. cz_dmic0_startup
  8. cz_dmic1_startup
  9. cz_da7219_params
  10. cz_da7219_shutdown
  11. cz_probe

   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 
  48 static struct snd_soc_jack cz_jack;
  49 static struct clk *da7219_dai_wclk;
  50 static struct clk *da7219_dai_bclk;
  51 extern bool bt_uart_enable;
  52 
  53 static 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 = rtd->codec_dai;
  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 = clk_get(component->dev, "da7219-dai-wclk");
  77         da7219_dai_bclk = clk_get(component->dev, "da7219-dai-bclk");
  78 
  79         ret = snd_soc_card_jack_new(card, "Headset Jack",
  80                                 SND_JACK_HEADSET | SND_JACK_LINEOUT |
  81                                 SND_JACK_BTN_0 | SND_JACK_BTN_1 |
  82                                 SND_JACK_BTN_2 | SND_JACK_BTN_3,
  83                                 &cz_jack, NULL, 0);
  84         if (ret) {
  85                 dev_err(card->dev, "HP jack creation failed %d\n", ret);
  86                 return ret;
  87         }
  88 
  89         snd_jack_set_key(cz_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
  90         snd_jack_set_key(cz_jack.jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
  91         snd_jack_set_key(cz_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
  92         snd_jack_set_key(cz_jack.jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
  93 
  94         da7219_aad_jack_det(component, &cz_jack);
  95 
  96         return 0;
  97 }
  98 
  99 static int da7219_clk_enable(struct snd_pcm_substream *substream,
 100                              int wclk_rate, int bclk_rate)
 101 {
 102         int ret = 0;
 103         struct snd_soc_pcm_runtime *rtd = substream->private_data;
 104 
 105         clk_set_rate(da7219_dai_wclk, wclk_rate);
 106         clk_set_rate(da7219_dai_bclk, bclk_rate);
 107         ret = clk_prepare_enable(da7219_dai_bclk);
 108         if (ret < 0) {
 109                 dev_err(rtd->dev, "can't enable master clock %d\n", ret);
 110                 return ret;
 111         }
 112 
 113         return ret;
 114 }
 115 
 116 static void da7219_clk_disable(void)
 117 {
 118         clk_disable_unprepare(da7219_dai_bclk);
 119 }
 120 
 121 static const unsigned int channels[] = {
 122         DUAL_CHANNEL,
 123 };
 124 
 125 static const unsigned int rates[] = {
 126         48000,
 127 };
 128 
 129 static const struct snd_pcm_hw_constraint_list constraints_rates = {
 130         .count = ARRAY_SIZE(rates),
 131         .list  = rates,
 132         .mask = 0,
 133 };
 134 
 135 static const struct snd_pcm_hw_constraint_list constraints_channels = {
 136         .count = ARRAY_SIZE(channels),
 137         .list = channels,
 138         .mask = 0,
 139 };
 140 
 141 static int cz_da7219_play_startup(struct snd_pcm_substream *substream)
 142 {
 143         struct snd_pcm_runtime *runtime = substream->runtime;
 144         struct snd_soc_pcm_runtime *rtd = substream->private_data;
 145         struct snd_soc_card *card = rtd->card;
 146         struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
 147 
 148         /*
 149          * On this platform for PCM device we support stereo
 150          */
 151 
 152         runtime->hw.channels_max = DUAL_CHANNEL;
 153         snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
 154                                    &constraints_channels);
 155         snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
 156                                    &constraints_rates);
 157 
 158         machine->play_i2s_instance = I2S_SP_INSTANCE;
 159         return 0;
 160 }
 161 
 162 static int cz_da7219_cap_startup(struct snd_pcm_substream *substream)
 163 {
 164         struct snd_pcm_runtime *runtime = substream->runtime;
 165         struct snd_soc_pcm_runtime *rtd = substream->private_data;
 166         struct snd_soc_card *card = rtd->card;
 167         struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
 168 
 169         /*
 170          * On this platform for PCM device we support stereo
 171          */
 172 
 173         runtime->hw.channels_max = DUAL_CHANNEL;
 174         snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
 175                                    &constraints_channels);
 176         snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
 177                                    &constraints_rates);
 178 
 179         machine->cap_i2s_instance = I2S_SP_INSTANCE;
 180         machine->capture_channel = CAP_CHANNEL1;
 181         return 0;
 182 }
 183 
 184 static int cz_max_startup(struct snd_pcm_substream *substream)
 185 {
 186         struct snd_pcm_runtime *runtime = substream->runtime;
 187         struct snd_soc_pcm_runtime *rtd = substream->private_data;
 188         struct snd_soc_card *card = rtd->card;
 189         struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
 190 
 191         /*
 192          * On this platform for PCM device we support stereo
 193          */
 194 
 195         runtime->hw.channels_max = DUAL_CHANNEL;
 196         snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
 197                                    &constraints_channels);
 198         snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
 199                                    &constraints_rates);
 200 
 201         machine->play_i2s_instance = I2S_BT_INSTANCE;
 202         return 0;
 203 }
 204 
 205 static int cz_dmic0_startup(struct snd_pcm_substream *substream)
 206 {
 207         struct snd_pcm_runtime *runtime = substream->runtime;
 208         struct snd_soc_pcm_runtime *rtd = substream->private_data;
 209         struct snd_soc_card *card = rtd->card;
 210         struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
 211 
 212         /*
 213          * On this platform for PCM device we support stereo
 214          */
 215 
 216         runtime->hw.channels_max = DUAL_CHANNEL;
 217         snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
 218                                    &constraints_channels);
 219         snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
 220                                    &constraints_rates);
 221 
 222         machine->cap_i2s_instance = I2S_BT_INSTANCE;
 223         return 0;
 224 }
 225 
 226 static int cz_dmic1_startup(struct snd_pcm_substream *substream)
 227 {
 228         struct snd_pcm_runtime *runtime = substream->runtime;
 229         struct snd_soc_pcm_runtime *rtd = substream->private_data;
 230         struct snd_soc_card *card = rtd->card;
 231         struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
 232 
 233         /*
 234          * On this platform for PCM device we support stereo
 235          */
 236 
 237         runtime->hw.channels_max = DUAL_CHANNEL;
 238         snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
 239                                    &constraints_channels);
 240         snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
 241                                    &constraints_rates);
 242 
 243         machine->cap_i2s_instance = I2S_SP_INSTANCE;
 244         machine->capture_channel = CAP_CHANNEL0;
 245         return 0;
 246 }
 247 
 248 static int cz_da7219_params(struct snd_pcm_substream *substream,
 249                                       struct snd_pcm_hw_params *params)
 250 {
 251         int wclk, bclk;
 252 
 253         wclk = params_rate(params);
 254         bclk = wclk * params_channels(params) *
 255                 snd_pcm_format_width(params_format(params));
 256         /* ADAU7002 spec: "The ADAU7002 requires a BCLK rate
 257          * that is minimum of 64x the LRCLK sample rate."
 258          * DA7219 is the only clk source so for all codecs
 259          * we have to limit bclk to 64X lrclk.
 260          */
 261         if (bclk < (wclk * 64))
 262                 bclk = wclk * 64;
 263         return da7219_clk_enable(substream, wclk, bclk);
 264 }
 265 
 266 static void cz_da7219_shutdown(struct snd_pcm_substream *substream)
 267 {
 268         da7219_clk_disable();
 269 }
 270 
 271 static const struct snd_soc_ops cz_da7219_play_ops = {
 272         .startup = cz_da7219_play_startup,
 273         .shutdown = cz_da7219_shutdown,
 274         .hw_params = cz_da7219_params,
 275 };
 276 
 277 static const struct snd_soc_ops cz_da7219_cap_ops = {
 278         .startup = cz_da7219_cap_startup,
 279         .shutdown = cz_da7219_shutdown,
 280         .hw_params = cz_da7219_params,
 281 };
 282 
 283 static const struct snd_soc_ops cz_max_play_ops = {
 284         .startup = cz_max_startup,
 285         .shutdown = cz_da7219_shutdown,
 286         .hw_params = cz_da7219_params,
 287 };
 288 
 289 static const struct snd_soc_ops cz_dmic0_cap_ops = {
 290         .startup = cz_dmic0_startup,
 291         .shutdown = cz_da7219_shutdown,
 292         .hw_params = cz_da7219_params,
 293 };
 294 
 295 static const struct snd_soc_ops cz_dmic1_cap_ops = {
 296         .startup = cz_dmic1_startup,
 297         .shutdown = cz_da7219_shutdown,
 298         .hw_params = cz_da7219_params,
 299 };
 300 
 301 SND_SOC_DAILINK_DEF(designware1,
 302         DAILINK_COMP_ARRAY(COMP_CPU("designware-i2s.1.auto")));
 303 SND_SOC_DAILINK_DEF(designware2,
 304         DAILINK_COMP_ARRAY(COMP_CPU("designware-i2s.2.auto")));
 305 SND_SOC_DAILINK_DEF(designware3,
 306         DAILINK_COMP_ARRAY(COMP_CPU("designware-i2s.3.auto")));
 307 
 308 SND_SOC_DAILINK_DEF(dlgs,
 309         DAILINK_COMP_ARRAY(COMP_CODEC("i2c-DLGS7219:00", "da7219-hifi")));
 310 SND_SOC_DAILINK_DEF(mx,
 311         DAILINK_COMP_ARRAY(COMP_CODEC("MX98357A:00", "HiFi")));
 312 SND_SOC_DAILINK_DEF(adau,
 313         DAILINK_COMP_ARRAY(COMP_CODEC("ADAU7002:00", "adau7002-hifi")));
 314 
 315 SND_SOC_DAILINK_DEF(platform,
 316         DAILINK_COMP_ARRAY(COMP_PLATFORM("acp_audio_dma.0.auto")));
 317 
 318 static struct snd_soc_dai_link cz_dai_7219_98357[] = {
 319         {
 320                 .name = "amd-da7219-play",
 321                 .stream_name = "Playback",
 322                 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
 323                                 | SND_SOC_DAIFMT_CBM_CFM,
 324                 .init = cz_da7219_init,
 325                 .dpcm_playback = 1,
 326                 .ops = &cz_da7219_play_ops,
 327                 SND_SOC_DAILINK_REG(designware1, dlgs, platform),
 328         },
 329         {
 330                 .name = "amd-da7219-cap",
 331                 .stream_name = "Capture",
 332                 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
 333                                 | SND_SOC_DAIFMT_CBM_CFM,
 334                 .dpcm_capture = 1,
 335                 .ops = &cz_da7219_cap_ops,
 336                 SND_SOC_DAILINK_REG(designware2, dlgs, platform),
 337         },
 338         {
 339                 .name = "amd-max98357-play",
 340                 .stream_name = "HiFi Playback",
 341                 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
 342                                 | SND_SOC_DAIFMT_CBM_CFM,
 343                 .dpcm_playback = 1,
 344                 .ops = &cz_max_play_ops,
 345                 SND_SOC_DAILINK_REG(designware3, mx, platform),
 346         },
 347         {
 348                 /* C panel DMIC */
 349                 .name = "dmic0",
 350                 .stream_name = "DMIC0 Capture",
 351                 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
 352                                 | SND_SOC_DAIFMT_CBM_CFM,
 353                 .dpcm_capture = 1,
 354                 .ops = &cz_dmic0_cap_ops,
 355                 SND_SOC_DAILINK_REG(designware3, adau, platform),
 356         },
 357         {
 358                 /* A/B panel DMIC */
 359                 .name = "dmic1",
 360                 .stream_name = "DMIC1 Capture",
 361                 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
 362                                 | SND_SOC_DAIFMT_CBM_CFM,
 363                 .dpcm_capture = 1,
 364                 .ops = &cz_dmic1_cap_ops,
 365                 SND_SOC_DAILINK_REG(designware2, adau, platform),
 366         },
 367 };
 368 
 369 static const struct snd_soc_dapm_widget cz_widgets[] = {
 370         SND_SOC_DAPM_HP("Headphones", NULL),
 371         SND_SOC_DAPM_SPK("Speakers", NULL),
 372         SND_SOC_DAPM_MIC("Headset Mic", NULL),
 373         SND_SOC_DAPM_MIC("Int Mic", NULL),
 374 };
 375 
 376 static const struct snd_soc_dapm_route cz_audio_route[] = {
 377         {"Headphones", NULL, "HPL"},
 378         {"Headphones", NULL, "HPR"},
 379         {"MIC", NULL, "Headset Mic"},
 380         {"Speakers", NULL, "Speaker"},
 381         {"PDM_DAT", NULL, "Int Mic"},
 382 };
 383 
 384 static const struct snd_kcontrol_new cz_mc_controls[] = {
 385         SOC_DAPM_PIN_SWITCH("Headphones"),
 386         SOC_DAPM_PIN_SWITCH("Speakers"),
 387         SOC_DAPM_PIN_SWITCH("Headset Mic"),
 388         SOC_DAPM_PIN_SWITCH("Int Mic"),
 389 };
 390 
 391 static struct snd_soc_card cz_card = {
 392         .name = "acpd7219m98357",
 393         .owner = THIS_MODULE,
 394         .dai_link = cz_dai_7219_98357,
 395         .num_links = ARRAY_SIZE(cz_dai_7219_98357),
 396         .dapm_widgets = cz_widgets,
 397         .num_dapm_widgets = ARRAY_SIZE(cz_widgets),
 398         .dapm_routes = cz_audio_route,
 399         .num_dapm_routes = ARRAY_SIZE(cz_audio_route),
 400         .controls = cz_mc_controls,
 401         .num_controls = ARRAY_SIZE(cz_mc_controls),
 402 };
 403 
 404 static struct regulator_consumer_supply acp_da7219_supplies[] = {
 405         REGULATOR_SUPPLY("VDD", "i2c-DLGS7219:00"),
 406         REGULATOR_SUPPLY("VDDMIC", "i2c-DLGS7219:00"),
 407         REGULATOR_SUPPLY("VDDIO", "i2c-DLGS7219:00"),
 408         REGULATOR_SUPPLY("IOVDD", "ADAU7002:00"),
 409 };
 410 
 411 static struct regulator_init_data acp_da7219_data = {
 412         .constraints = {
 413                 .always_on = 1,
 414         },
 415         .num_consumer_supplies = ARRAY_SIZE(acp_da7219_supplies),
 416         .consumer_supplies = acp_da7219_supplies,
 417 };
 418 
 419 static struct regulator_config acp_da7219_cfg = {
 420         .init_data = &acp_da7219_data,
 421 };
 422 
 423 static struct regulator_ops acp_da7219_ops = {
 424 };
 425 
 426 static const struct regulator_desc acp_da7219_desc = {
 427         .name = "reg-fixed-1.8V",
 428         .type = REGULATOR_VOLTAGE,
 429         .owner = THIS_MODULE,
 430         .ops = &acp_da7219_ops,
 431         .fixed_uV = 1800000, /* 1.8V */
 432         .n_voltages = 1,
 433 };
 434 
 435 static int cz_probe(struct platform_device *pdev)
 436 {
 437         int ret;
 438         struct snd_soc_card *card;
 439         struct acp_platform_info *machine;
 440         struct regulator_dev *rdev;
 441 
 442         acp_da7219_cfg.dev = &pdev->dev;
 443         rdev = devm_regulator_register(&pdev->dev, &acp_da7219_desc,
 444                                        &acp_da7219_cfg);
 445         if (IS_ERR(rdev)) {
 446                 dev_err(&pdev->dev, "Failed to register regulator: %d\n",
 447                         (int)PTR_ERR(rdev));
 448                 return -EINVAL;
 449         }
 450 
 451         machine = devm_kzalloc(&pdev->dev, sizeof(struct acp_platform_info),
 452                                GFP_KERNEL);
 453         if (!machine)
 454                 return -ENOMEM;
 455         card = &cz_card;
 456         cz_card.dev = &pdev->dev;
 457         platform_set_drvdata(pdev, card);
 458         snd_soc_card_set_drvdata(card, machine);
 459         ret = devm_snd_soc_register_card(&pdev->dev, &cz_card);
 460         if (ret) {
 461                 dev_err(&pdev->dev,
 462                                 "devm_snd_soc_register_card(%s) failed: %d\n",
 463                                 cz_card.name, ret);
 464                 return ret;
 465         }
 466         bt_uart_enable = !device_property_read_bool(&pdev->dev,
 467                                                     "bt-pad-enable");
 468         return 0;
 469 }
 470 
 471 static const struct acpi_device_id cz_audio_acpi_match[] = {
 472         { "AMD7219", 0 },
 473         {},
 474 };
 475 MODULE_DEVICE_TABLE(acpi, cz_audio_acpi_match);
 476 
 477 static struct platform_driver cz_pcm_driver = {
 478         .driver = {
 479                 .name = "cz-da7219-max98357a",
 480                 .acpi_match_table = ACPI_PTR(cz_audio_acpi_match),
 481                 .pm = &snd_soc_pm_ops,
 482         },
 483         .probe = cz_probe,
 484 };
 485 
 486 module_platform_driver(cz_pcm_driver);
 487 
 488 MODULE_AUTHOR("akshu.agrawal@amd.com");
 489 MODULE_DESCRIPTION("DA7219 & MAX98357A audio support");
 490 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */