sof_da7219.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. // Copyright(c) 2019 Intel Corporation.
  3. /*
  4. * Intel SOF Machine driver for Dialog headphone codec
  5. */
  6. #include <linux/input.h>
  7. #include <linux/module.h>
  8. #include <sound/jack.h>
  9. #include <sound/pcm.h>
  10. #include <sound/pcm_params.h>
  11. #include <linux/platform_device.h>
  12. #include <sound/soc.h>
  13. #include <sound/soc-acpi.h>
  14. #include <sound/sof.h>
  15. #include "../../codecs/da7219.h"
  16. #include "sof_board_helpers.h"
  17. #include "sof_maxim_common.h"
  18. /* Driver-specific board quirks: from bit 0 to 7 */
  19. #define SOF_DA7219_GLK_BOARD BIT(0)
  20. #define SOF_DA7219_CML_BOARD BIT(1)
  21. #define SOF_DA7219_JSL_BOARD BIT(2)
  22. #define SOF_DA7219_MCLK_EN BIT(3)
  23. #define DIALOG_CODEC_DAI "da7219-hifi"
  24. static int platform_clock_control(struct snd_soc_dapm_widget *w,
  25. struct snd_kcontrol *k, int event)
  26. {
  27. struct snd_soc_dapm_context *dapm = w->dapm;
  28. struct snd_soc_card *card = dapm->card;
  29. struct sof_card_private *ctx = snd_soc_card_get_drvdata(card);
  30. struct snd_soc_dai *codec_dai;
  31. int ret = 0;
  32. if (ctx->da7219.pll_bypass)
  33. return ret;
  34. /* PLL SRM mode */
  35. codec_dai = snd_soc_card_get_codec_dai(card, DIALOG_CODEC_DAI);
  36. if (!codec_dai) {
  37. dev_err(card->dev, "Codec dai not found; Unable to set/unset codec pll\n");
  38. return -EIO;
  39. }
  40. if (SND_SOC_DAPM_EVENT_OFF(event)) {
  41. ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK,
  42. 0, 0);
  43. if (ret)
  44. dev_err(card->dev, "failed to stop PLL: %d\n", ret);
  45. } else if (SND_SOC_DAPM_EVENT_ON(event)) {
  46. dev_dbg(card->dev, "pll srm mode\n");
  47. ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_PLL_SRM,
  48. 0, DA7219_PLL_FREQ_OUT_98304);
  49. if (ret)
  50. dev_err(card->dev, "failed to start PLL: %d\n", ret);
  51. }
  52. return ret;
  53. }
  54. static const struct snd_kcontrol_new controls[] = {
  55. SOC_DAPM_PIN_SWITCH("Headphone Jack"),
  56. SOC_DAPM_PIN_SWITCH("Headset Mic"),
  57. SOC_DAPM_PIN_SWITCH("Line Out"),
  58. };
  59. static const struct snd_soc_dapm_widget widgets[] = {
  60. SND_SOC_DAPM_HP("Headphone Jack", NULL),
  61. SND_SOC_DAPM_MIC("Headset Mic", NULL),
  62. SND_SOC_DAPM_LINE("Line Out", NULL),
  63. SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
  64. platform_clock_control, SND_SOC_DAPM_POST_PMD |
  65. SND_SOC_DAPM_PRE_PMU),
  66. };
  67. static const struct snd_soc_dapm_route audio_map[] = {
  68. { "Headphone Jack", NULL, "HPL" },
  69. { "Headphone Jack", NULL, "HPR" },
  70. { "MIC", NULL, "Headset Mic" },
  71. { "Headphone Jack", NULL, "Platform Clock" },
  72. { "Headset Mic", NULL, "Platform Clock" },
  73. { "Line Out", NULL, "Platform Clock" },
  74. };
  75. static struct snd_soc_jack_pin jack_pins[] = {
  76. {
  77. .pin = "Headphone Jack",
  78. .mask = SND_JACK_HEADPHONE,
  79. },
  80. {
  81. .pin = "Headset Mic",
  82. .mask = SND_JACK_MICROPHONE,
  83. },
  84. {
  85. .pin = "Line Out",
  86. .mask = SND_JACK_LINEOUT,
  87. },
  88. };
  89. static int da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
  90. {
  91. struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
  92. struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
  93. struct snd_soc_component *component = codec_dai->component;
  94. struct snd_soc_jack *jack = &ctx->headset_jack;
  95. int mclk_rate, ret;
  96. mclk_rate = sof_dai_get_mclk(rtd);
  97. if (mclk_rate <= 0) {
  98. dev_err(rtd->dev, "invalid mclk freq %d\n", mclk_rate);
  99. return -EINVAL;
  100. }
  101. ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, mclk_rate,
  102. SND_SOC_CLOCK_IN);
  103. if (ret) {
  104. dev_err(rtd->dev, "fail to set sysclk, ret %d\n", ret);
  105. return ret;
  106. }
  107. /*
  108. * Use PLL bypass mode if MCLK is available, be sure to set the
  109. * frequency of MCLK to 12.288 or 24.576MHz on topology side.
  110. */
  111. if (ctx->da7219.mclk_en &&
  112. (mclk_rate == 12288000 || mclk_rate == 24576000)) {
  113. /* PLL bypass mode */
  114. dev_dbg(rtd->dev, "pll bypass mode, mclk rate %d\n", mclk_rate);
  115. ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK, 0, 0);
  116. if (ret) {
  117. dev_err(rtd->dev, "fail to set pll, ret %d\n", ret);
  118. return ret;
  119. }
  120. ctx->da7219.pll_bypass = true;
  121. }
  122. /*
  123. * Headset buttons map to the google Reference headset.
  124. * These can be configured by userspace.
  125. */
  126. ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack",
  127. SND_JACK_HEADSET | SND_JACK_BTN_0 |
  128. SND_JACK_BTN_1 | SND_JACK_BTN_2 |
  129. SND_JACK_BTN_3 | SND_JACK_LINEOUT,
  130. jack, jack_pins, ARRAY_SIZE(jack_pins));
  131. if (ret) {
  132. dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
  133. return ret;
  134. }
  135. snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
  136. snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
  137. snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
  138. snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
  139. ret = snd_soc_component_set_jack(component, jack, NULL);
  140. if (ret) {
  141. dev_err(rtd->dev, "fail to set component jack, ret %d\n", ret);
  142. return ret;
  143. }
  144. return ret;
  145. }
  146. static void da7219_codec_exit(struct snd_soc_pcm_runtime *rtd)
  147. {
  148. struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
  149. snd_soc_component_set_jack(component, NULL, NULL);
  150. }
  151. static int card_late_probe(struct snd_soc_card *card)
  152. {
  153. struct sof_card_private *ctx = snd_soc_card_get_drvdata(card);
  154. struct snd_soc_dapm_context *dapm = &card->dapm;
  155. int err;
  156. if (ctx->amp_type == CODEC_MAX98373) {
  157. /* Disable Left and Right Spk pin after boot */
  158. snd_soc_dapm_disable_pin(dapm, "Left Spk");
  159. snd_soc_dapm_disable_pin(dapm, "Right Spk");
  160. err = snd_soc_dapm_sync(dapm);
  161. if (err < 0)
  162. return err;
  163. }
  164. return sof_intel_board_card_late_probe(card);
  165. }
  166. static struct snd_soc_card card_da7219 = {
  167. .name = "da7219", /* the sof- prefix is added by the core */
  168. .owner = THIS_MODULE,
  169. .controls = controls,
  170. .num_controls = ARRAY_SIZE(controls),
  171. .dapm_widgets = widgets,
  172. .num_dapm_widgets = ARRAY_SIZE(widgets),
  173. .dapm_routes = audio_map,
  174. .num_dapm_routes = ARRAY_SIZE(audio_map),
  175. .fully_routed = true,
  176. .late_probe = card_late_probe,
  177. };
  178. static struct snd_soc_dai_link_component da7219_component[] = {
  179. {
  180. .name = "i2c-DLGS7219:00",
  181. .dai_name = DIALOG_CODEC_DAI,
  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. ret = sof_intel_board_set_dai_link(dev, card, ctx);
  190. if (ret)
  191. return ret;
  192. if (!ctx->codec_link) {
  193. dev_err(dev, "codec link not available");
  194. return -EINVAL;
  195. }
  196. /* codec-specific fields for headphone codec */
  197. ctx->codec_link->codecs = da7219_component;
  198. ctx->codec_link->num_codecs = ARRAY_SIZE(da7219_component);
  199. ctx->codec_link->init = da7219_codec_init;
  200. ctx->codec_link->exit = da7219_codec_exit;
  201. if (ctx->amp_type == CODEC_NONE)
  202. return 0;
  203. if (!ctx->amp_link) {
  204. dev_err(dev, "amp link not available");
  205. return -EINVAL;
  206. }
  207. /* codec-specific fields for speaker amplifier */
  208. switch (ctx->amp_type) {
  209. case CODEC_MAX98357A:
  210. max_98357a_dai_link(ctx->amp_link);
  211. break;
  212. case CODEC_MAX98360A:
  213. max_98360a_dai_link(ctx->amp_link);
  214. break;
  215. case CODEC_MAX98373:
  216. max_98373_dai_link(dev, ctx->amp_link);
  217. break;
  218. case CODEC_MAX98390:
  219. max_98390_dai_link(dev, ctx->amp_link);
  220. break;
  221. default:
  222. dev_err(dev, "invalid amp type %d\n", ctx->amp_type);
  223. return -EINVAL;
  224. }
  225. return 0;
  226. }
  227. #define GLK_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_AMP, \
  228. SOF_LINK_CODEC, \
  229. SOF_LINK_DMIC01, \
  230. SOF_LINK_IDISP_HDMI, \
  231. SOF_LINK_NONE, \
  232. SOF_LINK_NONE, \
  233. SOF_LINK_NONE)
  234. #define CML_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_AMP, \
  235. SOF_LINK_CODEC, \
  236. SOF_LINK_DMIC01, \
  237. SOF_LINK_IDISP_HDMI, \
  238. SOF_LINK_DMIC16K, \
  239. SOF_LINK_NONE, \
  240. SOF_LINK_NONE)
  241. #define JSL_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_AMP, \
  242. SOF_LINK_CODEC, \
  243. SOF_LINK_DMIC01, \
  244. SOF_LINK_IDISP_HDMI, \
  245. SOF_LINK_DMIC16K, \
  246. SOF_LINK_NONE, \
  247. SOF_LINK_NONE)
  248. static int audio_probe(struct platform_device *pdev)
  249. {
  250. struct snd_soc_acpi_mach *mach = pdev->dev.platform_data;
  251. struct sof_card_private *ctx;
  252. char *card_name;
  253. unsigned long board_quirk = 0;
  254. int ret;
  255. if (pdev->id_entry && pdev->id_entry->driver_data)
  256. board_quirk = (unsigned long)pdev->id_entry->driver_data;
  257. dev_dbg(&pdev->dev, "board_quirk = %lx\n", board_quirk);
  258. /* initialize ctx with board quirk */
  259. ctx = sof_intel_board_get_ctx(&pdev->dev, board_quirk);
  260. if (!ctx)
  261. return -ENOMEM;
  262. if (mach->mach_params.codec_mask & IDISP_CODEC_MASK)
  263. ctx->hdmi.idisp_codec = true;
  264. if (board_quirk & SOF_DA7219_GLK_BOARD) {
  265. /* dmic16k not support */
  266. ctx->dmic_be_num = 1;
  267. /* overwrite the DAI link order for GLK boards */
  268. ctx->link_order_overwrite = GLK_LINK_ORDER;
  269. /* backward-compatible with existing devices */
  270. switch (ctx->amp_type) {
  271. case CODEC_MAX98357A:
  272. card_name = devm_kstrdup(&pdev->dev, "glkda7219max",
  273. GFP_KERNEL);
  274. if (!card_name)
  275. return -ENOMEM;
  276. card_da7219.name = card_name;
  277. break;
  278. default:
  279. break;
  280. }
  281. } else if (board_quirk & SOF_DA7219_CML_BOARD) {
  282. /* overwrite the DAI link order for CML boards */
  283. ctx->link_order_overwrite = CML_LINK_ORDER;
  284. /* backward-compatible with existing devices */
  285. switch (ctx->amp_type) {
  286. case CODEC_MAX98357A:
  287. card_name = devm_kstrdup(&pdev->dev, "cmlda7219max",
  288. GFP_KERNEL);
  289. if (!card_name)
  290. return -ENOMEM;
  291. card_da7219.name = card_name;
  292. break;
  293. case CODEC_MAX98390:
  294. card_name = devm_kstrdup(&pdev->dev,
  295. "cml_max98390_da7219",
  296. GFP_KERNEL);
  297. if (!card_name)
  298. return -ENOMEM;
  299. card_da7219.name = card_name;
  300. break;
  301. default:
  302. break;
  303. }
  304. } else if (board_quirk & SOF_DA7219_JSL_BOARD) {
  305. /* overwrite the DAI link order for JSL boards */
  306. ctx->link_order_overwrite = JSL_LINK_ORDER;
  307. /* backward-compatible with existing devices */
  308. switch (ctx->amp_type) {
  309. case CODEC_MAX98360A:
  310. card_name = devm_kstrdup(&pdev->dev, "da7219max98360a",
  311. GFP_KERNEL);
  312. if (!card_name)
  313. return -ENOMEM;
  314. card_da7219.name = card_name;
  315. break;
  316. case CODEC_MAX98373:
  317. card_name = devm_kstrdup(&pdev->dev, "da7219max",
  318. GFP_KERNEL);
  319. if (!card_name)
  320. return -ENOMEM;
  321. card_da7219.name = card_name;
  322. break;
  323. default:
  324. break;
  325. }
  326. }
  327. if (board_quirk & SOF_DA7219_MCLK_EN)
  328. ctx->da7219.mclk_en = true;
  329. /* update dai_link */
  330. ret = sof_card_dai_links_create(&pdev->dev, &card_da7219, ctx);
  331. if (ret)
  332. return ret;
  333. /* update codec_conf */
  334. switch (ctx->amp_type) {
  335. case CODEC_MAX98373:
  336. max_98373_set_codec_conf(&card_da7219);
  337. break;
  338. case CODEC_MAX98390:
  339. max_98390_set_codec_conf(&pdev->dev, &card_da7219);
  340. break;
  341. case CODEC_MAX98357A:
  342. case CODEC_MAX98360A:
  343. case CODEC_NONE:
  344. /* no codec conf required */
  345. break;
  346. default:
  347. dev_err(&pdev->dev, "invalid amp type %d\n", ctx->amp_type);
  348. return -EINVAL;
  349. }
  350. card_da7219.dev = &pdev->dev;
  351. ret = snd_soc_fixup_dai_links_platform_name(&card_da7219,
  352. mach->mach_params.platform);
  353. if (ret)
  354. return ret;
  355. snd_soc_card_set_drvdata(&card_da7219, ctx);
  356. return devm_snd_soc_register_card(&pdev->dev, &card_da7219);
  357. }
  358. static const struct platform_device_id board_ids[] = {
  359. {
  360. .name = "glk_da7219_def",
  361. .driver_data = (kernel_ulong_t)(SOF_DA7219_GLK_BOARD |
  362. SOF_SSP_PORT_CODEC(2) |
  363. SOF_SSP_PORT_AMP(1)),
  364. },
  365. {
  366. .name = "cml_da7219_def",
  367. .driver_data = (kernel_ulong_t)(SOF_DA7219_CML_BOARD |
  368. SOF_SSP_PORT_CODEC(0) |
  369. SOF_SSP_PORT_AMP(1)),
  370. },
  371. {
  372. .name = "jsl_da7219_def",
  373. .driver_data = (kernel_ulong_t)(SOF_DA7219_JSL_BOARD |
  374. SOF_SSP_PORT_CODEC(0) |
  375. SOF_SSP_PORT_AMP(1)),
  376. },
  377. {
  378. .name = "adl_da7219_def",
  379. .driver_data = (kernel_ulong_t)(SOF_DA7219_MCLK_EN |
  380. SOF_SSP_PORT_CODEC(0) |
  381. SOF_SSP_PORT_AMP(1) |
  382. SOF_NUM_IDISP_HDMI(4) |
  383. SOF_SSP_PORT_BT_OFFLOAD(2) |
  384. SOF_BT_OFFLOAD_PRESENT),
  385. },
  386. {
  387. .name = "rpl_da7219_def",
  388. .driver_data = (kernel_ulong_t)(SOF_DA7219_MCLK_EN |
  389. SOF_SSP_PORT_CODEC(0) |
  390. SOF_SSP_PORT_AMP(1) |
  391. SOF_NUM_IDISP_HDMI(4) |
  392. SOF_SSP_PORT_BT_OFFLOAD(2) |
  393. SOF_BT_OFFLOAD_PRESENT),
  394. },
  395. {
  396. .name = "mtl_da7219_def",
  397. .driver_data = (kernel_ulong_t)(SOF_DA7219_MCLK_EN |
  398. SOF_SSP_PORT_CODEC(2) |
  399. SOF_SSP_PORT_AMP(0) |
  400. SOF_SSP_PORT_BT_OFFLOAD(1) |
  401. SOF_BT_OFFLOAD_PRESENT),
  402. },
  403. { }
  404. };
  405. MODULE_DEVICE_TABLE(platform, board_ids);
  406. static struct platform_driver audio = {
  407. .probe = audio_probe,
  408. .driver = {
  409. .name = "sof_da7219",
  410. .pm = &snd_soc_pm_ops,
  411. },
  412. .id_table = board_ids,
  413. };
  414. module_platform_driver(audio)
  415. /* Module information */
  416. MODULE_DESCRIPTION("ASoC Intel(R) SOF Machine driver for Dialog codec");
  417. MODULE_AUTHOR("Yong Zhi <yong.zhi@intel.com>");
  418. MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>");
  419. MODULE_LICENSE("GPL v2");
  420. MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS);
  421. MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON);