sof_cs42l42.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. // Copyright(c) 2021 Intel Corporation.
  3. /*
  4. * Intel SOF Machine Driver with Cirrus Logic CS42L42 Codec
  5. * and speaker codec MAX98357A
  6. */
  7. #include <linux/i2c.h>
  8. #include <linux/input.h>
  9. #include <linux/module.h>
  10. #include <linux/platform_device.h>
  11. #include <linux/regulator/consumer.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 <dt-bindings/sound/cs42l42.h>
  21. #include "../common/soc-intel-quirks.h"
  22. #include "sof_board_helpers.h"
  23. #include "sof_maxim_common.h"
  24. static struct snd_soc_jack_pin jack_pins[] = {
  25. {
  26. .pin = "Headphone Jack",
  27. .mask = SND_JACK_HEADPHONE,
  28. },
  29. {
  30. .pin = "Headset Mic",
  31. .mask = SND_JACK_MICROPHONE,
  32. },
  33. };
  34. /* Default: SSP2 */
  35. static unsigned long sof_cs42l42_quirk = SOF_SSP_PORT_CODEC(2);
  36. static int sof_cs42l42_init(struct snd_soc_pcm_runtime *rtd)
  37. {
  38. struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
  39. struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
  40. struct snd_soc_jack *jack = &ctx->headset_jack;
  41. int ret;
  42. /*
  43. * Headset buttons map to the google Reference headset.
  44. * These can be configured by userspace.
  45. */
  46. ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack",
  47. SND_JACK_HEADSET | SND_JACK_BTN_0 |
  48. SND_JACK_BTN_1 | SND_JACK_BTN_2 |
  49. SND_JACK_BTN_3,
  50. jack,
  51. jack_pins,
  52. ARRAY_SIZE(jack_pins));
  53. if (ret) {
  54. dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
  55. return ret;
  56. }
  57. snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
  58. snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
  59. snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
  60. snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
  61. ret = snd_soc_component_set_jack(component, jack, NULL);
  62. if (ret) {
  63. dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
  64. return ret;
  65. }
  66. return ret;
  67. };
  68. static void sof_cs42l42_exit(struct snd_soc_pcm_runtime *rtd)
  69. {
  70. struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
  71. snd_soc_component_set_jack(component, NULL, NULL);
  72. }
  73. static int sof_cs42l42_hw_params(struct snd_pcm_substream *substream,
  74. struct snd_pcm_hw_params *params)
  75. {
  76. struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
  77. struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
  78. int clk_freq, ret;
  79. clk_freq = sof_dai_get_bclk(rtd); /* BCLK freq */
  80. if (clk_freq <= 0) {
  81. dev_err(rtd->dev, "get bclk freq failed: %d\n", clk_freq);
  82. return -EINVAL;
  83. }
  84. /* Configure sysclk for codec */
  85. ret = snd_soc_dai_set_sysclk(codec_dai, 0,
  86. clk_freq, SND_SOC_CLOCK_IN);
  87. if (ret < 0)
  88. dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
  89. return ret;
  90. }
  91. static const struct snd_soc_ops sof_cs42l42_ops = {
  92. .hw_params = sof_cs42l42_hw_params,
  93. };
  94. static int sof_card_late_probe(struct snd_soc_card *card)
  95. {
  96. return sof_intel_board_card_late_probe(card);
  97. }
  98. static const struct snd_kcontrol_new sof_controls[] = {
  99. SOC_DAPM_PIN_SWITCH("Headphone Jack"),
  100. SOC_DAPM_PIN_SWITCH("Headset Mic"),
  101. };
  102. static const struct snd_soc_dapm_widget sof_widgets[] = {
  103. SND_SOC_DAPM_HP("Headphone Jack", NULL),
  104. SND_SOC_DAPM_MIC("Headset Mic", NULL),
  105. };
  106. static const struct snd_soc_dapm_route sof_map[] = {
  107. /* HP jack connectors - unknown if we have jack detection */
  108. {"Headphone Jack", NULL, "HP"},
  109. /* other jacks */
  110. {"HS", NULL, "Headset Mic"},
  111. };
  112. /* sof audio machine driver for cs42l42 codec */
  113. static struct snd_soc_card sof_audio_card_cs42l42 = {
  114. .name = "cs42l42", /* the sof- prefix is added by the core */
  115. .owner = THIS_MODULE,
  116. .controls = sof_controls,
  117. .num_controls = ARRAY_SIZE(sof_controls),
  118. .dapm_widgets = sof_widgets,
  119. .num_dapm_widgets = ARRAY_SIZE(sof_widgets),
  120. .dapm_routes = sof_map,
  121. .num_dapm_routes = ARRAY_SIZE(sof_map),
  122. .fully_routed = true,
  123. .late_probe = sof_card_late_probe,
  124. };
  125. static struct snd_soc_dai_link_component cs42l42_component[] = {
  126. {
  127. .name = "i2c-10134242:00",
  128. .dai_name = "cs42l42",
  129. }
  130. };
  131. static int
  132. sof_card_dai_links_create(struct device *dev, struct snd_soc_card *card,
  133. struct sof_card_private *ctx)
  134. {
  135. int ret;
  136. ret = sof_intel_board_set_dai_link(dev, card, ctx);
  137. if (ret)
  138. return ret;
  139. if (!ctx->codec_link) {
  140. dev_err(dev, "codec link not available");
  141. return -EINVAL;
  142. }
  143. /* codec-specific fields for headphone codec */
  144. ctx->codec_link->codecs = cs42l42_component;
  145. ctx->codec_link->num_codecs = ARRAY_SIZE(cs42l42_component);
  146. ctx->codec_link->init = sof_cs42l42_init;
  147. ctx->codec_link->exit = sof_cs42l42_exit;
  148. ctx->codec_link->ops = &sof_cs42l42_ops;
  149. if (ctx->amp_type == CODEC_NONE)
  150. return 0;
  151. if (!ctx->amp_link) {
  152. dev_err(dev, "amp link not available");
  153. return -EINVAL;
  154. }
  155. /* codec-specific fields for speaker amplifier */
  156. switch (ctx->amp_type) {
  157. case CODEC_MAX98357A:
  158. max_98357a_dai_link(ctx->amp_link);
  159. break;
  160. case CODEC_MAX98360A:
  161. max_98360a_dai_link(ctx->amp_link);
  162. break;
  163. default:
  164. dev_err(dev, "invalid amp type %d\n", ctx->amp_type);
  165. return -EINVAL;
  166. }
  167. return 0;
  168. }
  169. #define GLK_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_AMP, \
  170. SOF_LINK_CODEC, \
  171. SOF_LINK_DMIC01, \
  172. SOF_LINK_IDISP_HDMI, \
  173. SOF_LINK_NONE, \
  174. SOF_LINK_NONE, \
  175. SOF_LINK_NONE)
  176. static int sof_audio_probe(struct platform_device *pdev)
  177. {
  178. struct snd_soc_acpi_mach *mach = pdev->dev.platform_data;
  179. struct sof_card_private *ctx;
  180. int ret;
  181. if (pdev->id_entry && pdev->id_entry->driver_data)
  182. sof_cs42l42_quirk = (unsigned long)pdev->id_entry->driver_data;
  183. dev_dbg(&pdev->dev, "sof_cs42l42_quirk = %lx\n", sof_cs42l42_quirk);
  184. /* initialize ctx with board quirk */
  185. ctx = sof_intel_board_get_ctx(&pdev->dev, sof_cs42l42_quirk);
  186. if (!ctx)
  187. return -ENOMEM;
  188. if (soc_intel_is_glk()) {
  189. ctx->dmic_be_num = 1;
  190. /* overwrite the DAI link order for GLK boards */
  191. ctx->link_order_overwrite = GLK_LINK_ORDER;
  192. }
  193. if (mach->mach_params.codec_mask & IDISP_CODEC_MASK)
  194. ctx->hdmi.idisp_codec = true;
  195. /* update dai_link */
  196. ret = sof_card_dai_links_create(&pdev->dev, &sof_audio_card_cs42l42, ctx);
  197. if (ret)
  198. return ret;
  199. sof_audio_card_cs42l42.dev = &pdev->dev;
  200. /* set platform name for each dailink */
  201. ret = snd_soc_fixup_dai_links_platform_name(&sof_audio_card_cs42l42,
  202. mach->mach_params.platform);
  203. if (ret)
  204. return ret;
  205. snd_soc_card_set_drvdata(&sof_audio_card_cs42l42, ctx);
  206. return devm_snd_soc_register_card(&pdev->dev,
  207. &sof_audio_card_cs42l42);
  208. }
  209. static const struct platform_device_id board_ids[] = {
  210. {
  211. .name = "glk_cs4242_mx98357a",
  212. .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(2) |
  213. SOF_SSP_PORT_AMP(1)),
  214. },
  215. {
  216. .name = "jsl_cs4242_mx98360a",
  217. .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(0) |
  218. SOF_SSP_PORT_AMP(1)),
  219. },
  220. {
  221. .name = "adl_cs42l42_def",
  222. .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(0) |
  223. SOF_SSP_PORT_AMP(1) |
  224. SOF_NUM_IDISP_HDMI(4) |
  225. SOF_BT_OFFLOAD_PRESENT |
  226. SOF_SSP_PORT_BT_OFFLOAD(2)),
  227. },
  228. {
  229. .name = "rpl_cs42l42_def",
  230. .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(0) |
  231. SOF_SSP_PORT_AMP(1) |
  232. SOF_NUM_IDISP_HDMI(4) |
  233. SOF_BT_OFFLOAD_PRESENT |
  234. SOF_SSP_PORT_BT_OFFLOAD(2)),
  235. },
  236. {
  237. .name = "mtl_cs42l42_def",
  238. .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(2) |
  239. SOF_SSP_PORT_AMP(0) |
  240. SOF_BT_OFFLOAD_PRESENT |
  241. SOF_SSP_PORT_BT_OFFLOAD(1)),
  242. },
  243. { }
  244. };
  245. MODULE_DEVICE_TABLE(platform, board_ids);
  246. static struct platform_driver sof_audio = {
  247. .probe = sof_audio_probe,
  248. .driver = {
  249. .name = "sof_cs42l42",
  250. .pm = &snd_soc_pm_ops,
  251. },
  252. .id_table = board_ids,
  253. };
  254. module_platform_driver(sof_audio)
  255. /* Module information */
  256. MODULE_DESCRIPTION("SOF Audio Machine driver for CS42L42");
  257. MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>");
  258. MODULE_LICENSE("GPL");
  259. MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS);
  260. MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON);