sof_nau8825.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. // Copyright(c) 2021 Intel Corporation.
  3. // Copyright(c) 2021 Nuvoton Corporation.
  4. /*
  5. * Intel SOF Machine Driver with Nuvoton headphone codec NAU8825
  6. * and speaker codec RT1019P MAX98360a or MAX98373
  7. */
  8. #include <linux/i2c.h>
  9. #include <linux/input.h>
  10. #include <linux/module.h>
  11. #include <linux/platform_device.h>
  12. #include <linux/dmi.h>
  13. #include <sound/core.h>
  14. #include <sound/jack.h>
  15. #include <sound/pcm.h>
  16. #include <sound/pcm_params.h>
  17. #include <sound/soc.h>
  18. #include <sound/sof.h>
  19. #include <sound/soc-acpi.h>
  20. #include "../../codecs/nau8825.h"
  21. #include "../common/soc-intel-quirks.h"
  22. #include "sof_board_helpers.h"
  23. #include "sof_realtek_common.h"
  24. #include "sof_maxim_common.h"
  25. #include "sof_nuvoton_common.h"
  26. static unsigned long sof_nau8825_quirk = SOF_SSP_PORT_CODEC(0);
  27. static struct snd_soc_jack_pin jack_pins[] = {
  28. {
  29. .pin = "Headphone Jack",
  30. .mask = SND_JACK_HEADPHONE,
  31. },
  32. {
  33. .pin = "Headset Mic",
  34. .mask = SND_JACK_MICROPHONE,
  35. },
  36. };
  37. static int sof_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
  38. {
  39. struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
  40. struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
  41. struct snd_soc_jack *jack = &ctx->headset_jack;
  42. int ret;
  43. /*
  44. * Headset buttons map to the google Reference headset.
  45. * These can be configured by userspace.
  46. */
  47. ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack",
  48. SND_JACK_HEADSET | SND_JACK_BTN_0 |
  49. SND_JACK_BTN_1 | SND_JACK_BTN_2 |
  50. SND_JACK_BTN_3,
  51. jack,
  52. jack_pins,
  53. ARRAY_SIZE(jack_pins));
  54. if (ret) {
  55. dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
  56. return ret;
  57. }
  58. snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
  59. snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
  60. snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
  61. snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
  62. ret = snd_soc_component_set_jack(component, jack, NULL);
  63. if (ret) {
  64. dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
  65. return ret;
  66. }
  67. return ret;
  68. };
  69. static void sof_nau8825_codec_exit(struct snd_soc_pcm_runtime *rtd)
  70. {
  71. struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
  72. snd_soc_component_set_jack(component, NULL, NULL);
  73. }
  74. static int sof_nau8825_hw_params(struct snd_pcm_substream *substream,
  75. struct snd_pcm_hw_params *params)
  76. {
  77. struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
  78. struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
  79. int clk_freq, ret;
  80. clk_freq = sof_dai_get_bclk(rtd); /* BCLK freq */
  81. if (clk_freq <= 0) {
  82. dev_err(rtd->dev, "get bclk freq failed: %d\n", clk_freq);
  83. return -EINVAL;
  84. }
  85. /* Configure clock for codec */
  86. ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_FLL_BLK, 0,
  87. SND_SOC_CLOCK_IN);
  88. if (ret < 0) {
  89. dev_err(codec_dai->dev, "can't set BCLK clock %d\n", ret);
  90. return ret;
  91. }
  92. /* Configure pll for codec */
  93. ret = snd_soc_dai_set_pll(codec_dai, 0, 0, clk_freq,
  94. params_rate(params) * 256);
  95. if (ret < 0) {
  96. dev_err(codec_dai->dev, "can't set BCLK: %d\n", ret);
  97. return ret;
  98. }
  99. return ret;
  100. }
  101. static const struct snd_soc_ops sof_nau8825_ops = {
  102. .hw_params = sof_nau8825_hw_params,
  103. };
  104. static int sof_card_late_probe(struct snd_soc_card *card)
  105. {
  106. struct sof_card_private *ctx = snd_soc_card_get_drvdata(card);
  107. struct snd_soc_dapm_context *dapm = &card->dapm;
  108. int err;
  109. if (ctx->amp_type == CODEC_MAX98373) {
  110. /* Disable Left and Right Spk pin after boot */
  111. snd_soc_dapm_disable_pin(dapm, "Left Spk");
  112. snd_soc_dapm_disable_pin(dapm, "Right Spk");
  113. err = snd_soc_dapm_sync(dapm);
  114. if (err < 0)
  115. return err;
  116. }
  117. return sof_intel_board_card_late_probe(card);
  118. }
  119. static const struct snd_kcontrol_new sof_controls[] = {
  120. SOC_DAPM_PIN_SWITCH("Headphone Jack"),
  121. SOC_DAPM_PIN_SWITCH("Headset Mic"),
  122. };
  123. static const struct snd_soc_dapm_widget sof_widgets[] = {
  124. SND_SOC_DAPM_HP("Headphone Jack", NULL),
  125. SND_SOC_DAPM_MIC("Headset Mic", NULL),
  126. };
  127. static const struct snd_soc_dapm_route sof_map[] = {
  128. /* HP jack connectors - unknown if we have jack detection */
  129. { "Headphone Jack", NULL, "HPOL" },
  130. { "Headphone Jack", NULL, "HPOR" },
  131. /* other jacks */
  132. { "MIC", NULL, "Headset Mic" },
  133. };
  134. /* sof audio machine driver for nau8825 codec */
  135. static struct snd_soc_card sof_audio_card_nau8825 = {
  136. .name = "nau8825", /* the sof- prefix is added by the core */
  137. .owner = THIS_MODULE,
  138. .controls = sof_controls,
  139. .num_controls = ARRAY_SIZE(sof_controls),
  140. .dapm_widgets = sof_widgets,
  141. .num_dapm_widgets = ARRAY_SIZE(sof_widgets),
  142. .dapm_routes = sof_map,
  143. .num_dapm_routes = ARRAY_SIZE(sof_map),
  144. .fully_routed = true,
  145. .late_probe = sof_card_late_probe,
  146. };
  147. static struct snd_soc_dai_link_component nau8825_component[] = {
  148. {
  149. .name = "i2c-10508825:00",
  150. .dai_name = "nau8825-hifi",
  151. }
  152. };
  153. static int
  154. sof_card_dai_links_create(struct device *dev, struct snd_soc_card *card,
  155. struct sof_card_private *ctx)
  156. {
  157. int ret;
  158. ret = sof_intel_board_set_dai_link(dev, card, ctx);
  159. if (ret)
  160. return ret;
  161. if (!ctx->codec_link) {
  162. dev_err(dev, "codec link not available");
  163. return -EINVAL;
  164. }
  165. /* codec-specific fields for headphone codec */
  166. ctx->codec_link->codecs = nau8825_component;
  167. ctx->codec_link->num_codecs = ARRAY_SIZE(nau8825_component);
  168. ctx->codec_link->init = sof_nau8825_codec_init;
  169. ctx->codec_link->exit = sof_nau8825_codec_exit;
  170. ctx->codec_link->ops = &sof_nau8825_ops;
  171. if (ctx->amp_type == CODEC_NONE)
  172. return 0;
  173. if (!ctx->amp_link) {
  174. dev_err(dev, "amp link not available");
  175. return -EINVAL;
  176. }
  177. /* codec-specific fields for speaker amplifier */
  178. switch (ctx->amp_type) {
  179. case CODEC_MAX98360A:
  180. max_98360a_dai_link(ctx->amp_link);
  181. break;
  182. case CODEC_MAX98373:
  183. max_98373_dai_link(dev, ctx->amp_link);
  184. break;
  185. case CODEC_NAU8318:
  186. nau8318_set_dai_link(ctx->amp_link);
  187. break;
  188. case CODEC_RT1015P:
  189. sof_rt1015p_dai_link(ctx->amp_link);
  190. break;
  191. case CODEC_RT1019P:
  192. sof_rt1019p_dai_link(ctx->amp_link);
  193. break;
  194. default:
  195. dev_err(dev, "invalid amp type %d\n", ctx->amp_type);
  196. return -EINVAL;
  197. }
  198. return 0;
  199. }
  200. static int sof_audio_probe(struct platform_device *pdev)
  201. {
  202. struct snd_soc_acpi_mach *mach = pdev->dev.platform_data;
  203. struct sof_card_private *ctx;
  204. int ret;
  205. if (pdev->id_entry && pdev->id_entry->driver_data)
  206. sof_nau8825_quirk = (unsigned long)pdev->id_entry->driver_data;
  207. dev_dbg(&pdev->dev, "sof_nau8825_quirk = %lx\n", sof_nau8825_quirk);
  208. /* initialize ctx with board quirk */
  209. ctx = sof_intel_board_get_ctx(&pdev->dev, sof_nau8825_quirk);
  210. if (!ctx)
  211. return -ENOMEM;
  212. if (mach->mach_params.codec_mask & IDISP_CODEC_MASK)
  213. ctx->hdmi.idisp_codec = true;
  214. /* update dai_link */
  215. ret = sof_card_dai_links_create(&pdev->dev, &sof_audio_card_nau8825, ctx);
  216. if (ret)
  217. return ret;
  218. /* update codec_conf */
  219. switch (ctx->amp_type) {
  220. case CODEC_MAX98373:
  221. max_98373_set_codec_conf(&sof_audio_card_nau8825);
  222. break;
  223. case CODEC_RT1015P:
  224. sof_rt1015p_codec_conf(&sof_audio_card_nau8825);
  225. break;
  226. case CODEC_MAX98360A:
  227. case CODEC_NAU8318:
  228. case CODEC_RT1019P:
  229. case CODEC_NONE:
  230. /* no codec conf required */
  231. break;
  232. default:
  233. dev_err(&pdev->dev, "invalid amp type %d\n", ctx->amp_type);
  234. return -EINVAL;
  235. }
  236. sof_audio_card_nau8825.dev = &pdev->dev;
  237. /* set platform name for each dailink */
  238. ret = snd_soc_fixup_dai_links_platform_name(&sof_audio_card_nau8825,
  239. mach->mach_params.platform);
  240. if (ret)
  241. return ret;
  242. snd_soc_card_set_drvdata(&sof_audio_card_nau8825, ctx);
  243. return devm_snd_soc_register_card(&pdev->dev,
  244. &sof_audio_card_nau8825);
  245. }
  246. static const struct platform_device_id board_ids[] = {
  247. {
  248. .name = "adl_rt1019p_8825",
  249. .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(0) |
  250. SOF_SSP_PORT_AMP(2) |
  251. SOF_NUM_IDISP_HDMI(4)),
  252. },
  253. {
  254. .name = "adl_nau8825_def",
  255. .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(0) |
  256. SOF_SSP_PORT_AMP(1) |
  257. SOF_NUM_IDISP_HDMI(4) |
  258. SOF_SSP_PORT_BT_OFFLOAD(2) |
  259. SOF_BT_OFFLOAD_PRESENT),
  260. },
  261. {
  262. .name = "rpl_nau8825_def",
  263. .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(0) |
  264. SOF_SSP_PORT_AMP(1) |
  265. SOF_NUM_IDISP_HDMI(4) |
  266. SOF_SSP_PORT_BT_OFFLOAD(2) |
  267. SOF_BT_OFFLOAD_PRESENT),
  268. },
  269. {
  270. .name = "mtl_nau8825_def",
  271. .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(2) |
  272. SOF_SSP_PORT_AMP(0) |
  273. SOF_SSP_PORT_BT_OFFLOAD(1) |
  274. SOF_BT_OFFLOAD_PRESENT),
  275. },
  276. { }
  277. };
  278. MODULE_DEVICE_TABLE(platform, board_ids);
  279. static struct platform_driver sof_audio = {
  280. .probe = sof_audio_probe,
  281. .driver = {
  282. .name = "sof_nau8825",
  283. .pm = &snd_soc_pm_ops,
  284. },
  285. .id_table = board_ids,
  286. };
  287. module_platform_driver(sof_audio)
  288. /* Module information */
  289. MODULE_DESCRIPTION("SOF Audio Machine driver for NAU8825");
  290. MODULE_AUTHOR("David Lin <ctlin0@nuvoton.com>");
  291. MODULE_AUTHOR("Mac Chiang <mac.chiang@intel.com>");
  292. MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>");
  293. MODULE_LICENSE("GPL");
  294. MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS);
  295. MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON);
  296. MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_NUVOTON_COMMON);
  297. MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_REALTEK_COMMON);