sof_pcm512x.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. // Copyright(c) 2018-2020 Intel Corporation.
  3. /*
  4. * Intel SOF Machine Driver for Intel platforms with TI PCM512x codec,
  5. * e.g. Up or Up2 with Hifiberry DAC+ HAT
  6. */
  7. #include <linux/clk.h>
  8. #include <linux/dmi.h>
  9. #include <linux/i2c.h>
  10. #include <linux/input.h>
  11. #include <linux/module.h>
  12. #include <linux/platform_device.h>
  13. #include <linux/types.h>
  14. #include <sound/core.h>
  15. #include <sound/jack.h>
  16. #include <sound/pcm.h>
  17. #include <sound/pcm_params.h>
  18. #include <sound/soc.h>
  19. #include <sound/soc-acpi.h>
  20. #include "../../codecs/pcm512x.h"
  21. #include "../common/soc-intel-quirks.h"
  22. #include "hda_dsp_common.h"
  23. #define NAME_SIZE 32
  24. #define SOF_PCM512X_SSP_CODEC(quirk) ((quirk) & GENMASK(3, 0))
  25. #define SOF_PCM512X_SSP_CODEC_MASK (GENMASK(3, 0))
  26. #define SOF_PCM512X_ENABLE_SSP_CAPTURE BIT(4)
  27. #define SOF_PCM512X_ENABLE_DMIC BIT(5)
  28. #define IDISP_CODEC_MASK 0x4
  29. /* Default: SSP5 */
  30. static unsigned long sof_pcm512x_quirk =
  31. SOF_PCM512X_SSP_CODEC(5) |
  32. SOF_PCM512X_ENABLE_SSP_CAPTURE |
  33. SOF_PCM512X_ENABLE_DMIC;
  34. static bool is_legacy_cpu;
  35. struct sof_hdmi_pcm {
  36. struct list_head head;
  37. struct snd_soc_dai *codec_dai;
  38. int device;
  39. };
  40. struct sof_card_private {
  41. struct list_head hdmi_pcm_list;
  42. bool idisp_codec;
  43. };
  44. static int sof_pcm512x_quirk_cb(const struct dmi_system_id *id)
  45. {
  46. sof_pcm512x_quirk = (unsigned long)id->driver_data;
  47. return 1;
  48. }
  49. static const struct dmi_system_id sof_pcm512x_quirk_table[] = {
  50. {
  51. .callback = sof_pcm512x_quirk_cb,
  52. .matches = {
  53. DMI_MATCH(DMI_SYS_VENDOR, "AAEON"),
  54. DMI_MATCH(DMI_PRODUCT_NAME, "UP-CHT01"),
  55. },
  56. .driver_data = (void *)(SOF_PCM512X_SSP_CODEC(2)),
  57. },
  58. {}
  59. };
  60. static int sof_hdmi_init(struct snd_soc_pcm_runtime *rtd)
  61. {
  62. struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
  63. struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
  64. struct sof_hdmi_pcm *pcm;
  65. pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
  66. if (!pcm)
  67. return -ENOMEM;
  68. /* dai_link id is 1:1 mapped to the PCM device */
  69. pcm->device = rtd->dai_link->id;
  70. pcm->codec_dai = dai;
  71. list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
  72. return 0;
  73. }
  74. static int sof_pcm512x_codec_init(struct snd_soc_pcm_runtime *rtd)
  75. {
  76. struct snd_soc_component *codec = asoc_rtd_to_codec(rtd, 0)->component;
  77. snd_soc_component_update_bits(codec, PCM512x_GPIO_EN, 0x08, 0x08);
  78. snd_soc_component_update_bits(codec, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02);
  79. snd_soc_component_update_bits(codec, PCM512x_GPIO_CONTROL_1,
  80. 0x08, 0x08);
  81. return 0;
  82. }
  83. static int aif1_startup(struct snd_pcm_substream *substream)
  84. {
  85. struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
  86. struct snd_soc_component *codec = asoc_rtd_to_codec(rtd, 0)->component;
  87. snd_soc_component_update_bits(codec, PCM512x_GPIO_CONTROL_1,
  88. 0x08, 0x08);
  89. return 0;
  90. }
  91. static void aif1_shutdown(struct snd_pcm_substream *substream)
  92. {
  93. struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
  94. struct snd_soc_component *codec = asoc_rtd_to_codec(rtd, 0)->component;
  95. snd_soc_component_update_bits(codec, PCM512x_GPIO_CONTROL_1,
  96. 0x08, 0x00);
  97. }
  98. static const struct snd_soc_ops sof_pcm512x_ops = {
  99. .startup = aif1_startup,
  100. .shutdown = aif1_shutdown,
  101. };
  102. static struct snd_soc_dai_link_component platform_component[] = {
  103. {
  104. /* name might be overridden during probe */
  105. .name = "0000:00:1f.3"
  106. }
  107. };
  108. static int sof_card_late_probe(struct snd_soc_card *card)
  109. {
  110. struct sof_card_private *ctx = snd_soc_card_get_drvdata(card);
  111. struct sof_hdmi_pcm *pcm;
  112. /* HDMI is not supported by SOF on Baytrail/CherryTrail */
  113. if (is_legacy_cpu)
  114. return 0;
  115. if (list_empty(&ctx->hdmi_pcm_list))
  116. return -EINVAL;
  117. if (!ctx->idisp_codec)
  118. return 0;
  119. pcm = list_first_entry(&ctx->hdmi_pcm_list, struct sof_hdmi_pcm, head);
  120. return hda_dsp_hdmi_build_controls(card, pcm->codec_dai->component);
  121. }
  122. static const struct snd_kcontrol_new sof_controls[] = {
  123. SOC_DAPM_PIN_SWITCH("Ext Spk"),
  124. };
  125. static const struct snd_soc_dapm_widget sof_widgets[] = {
  126. SND_SOC_DAPM_SPK("Ext Spk", NULL),
  127. };
  128. static const struct snd_soc_dapm_widget dmic_widgets[] = {
  129. SND_SOC_DAPM_MIC("SoC DMIC", NULL),
  130. };
  131. static const struct snd_soc_dapm_route sof_map[] = {
  132. /* Speaker */
  133. {"Ext Spk", NULL, "OUTR"},
  134. {"Ext Spk", NULL, "OUTL"},
  135. };
  136. static const struct snd_soc_dapm_route dmic_map[] = {
  137. /* digital mics */
  138. {"DMic", NULL, "SoC DMIC"},
  139. };
  140. static int dmic_init(struct snd_soc_pcm_runtime *rtd)
  141. {
  142. struct snd_soc_card *card = rtd->card;
  143. int ret;
  144. ret = snd_soc_dapm_new_controls(&card->dapm, dmic_widgets,
  145. ARRAY_SIZE(dmic_widgets));
  146. if (ret) {
  147. dev_err(card->dev, "DMic widget addition failed: %d\n", ret);
  148. /* Don't need to add routes if widget addition failed */
  149. return ret;
  150. }
  151. ret = snd_soc_dapm_add_routes(&card->dapm, dmic_map,
  152. ARRAY_SIZE(dmic_map));
  153. if (ret)
  154. dev_err(card->dev, "DMic map addition failed: %d\n", ret);
  155. return ret;
  156. }
  157. /* sof audio machine driver for pcm512x codec */
  158. static struct snd_soc_card sof_audio_card_pcm512x = {
  159. .name = "pcm512x",
  160. .owner = THIS_MODULE,
  161. .controls = sof_controls,
  162. .num_controls = ARRAY_SIZE(sof_controls),
  163. .dapm_widgets = sof_widgets,
  164. .num_dapm_widgets = ARRAY_SIZE(sof_widgets),
  165. .dapm_routes = sof_map,
  166. .num_dapm_routes = ARRAY_SIZE(sof_map),
  167. .fully_routed = true,
  168. .late_probe = sof_card_late_probe,
  169. };
  170. SND_SOC_DAILINK_DEF(pcm512x_component,
  171. DAILINK_COMP_ARRAY(COMP_CODEC("i2c-104C5122:00", "pcm512x-hifi")));
  172. SND_SOC_DAILINK_DEF(dmic_component,
  173. DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi")));
  174. static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
  175. int ssp_codec,
  176. int dmic_be_num,
  177. int hdmi_num,
  178. bool idisp_codec)
  179. {
  180. struct snd_soc_dai_link_component *idisp_components;
  181. struct snd_soc_dai_link_component *cpus;
  182. struct snd_soc_dai_link *links;
  183. int i, id = 0;
  184. links = devm_kcalloc(dev, sof_audio_card_pcm512x.num_links,
  185. sizeof(struct snd_soc_dai_link), GFP_KERNEL);
  186. cpus = devm_kcalloc(dev, sof_audio_card_pcm512x.num_links,
  187. sizeof(struct snd_soc_dai_link_component), GFP_KERNEL);
  188. if (!links || !cpus)
  189. goto devm_err;
  190. /* codec SSP */
  191. links[id].name = devm_kasprintf(dev, GFP_KERNEL,
  192. "SSP%d-Codec", ssp_codec);
  193. if (!links[id].name)
  194. goto devm_err;
  195. links[id].id = id;
  196. links[id].codecs = pcm512x_component;
  197. links[id].num_codecs = ARRAY_SIZE(pcm512x_component);
  198. links[id].platforms = platform_component;
  199. links[id].num_platforms = ARRAY_SIZE(platform_component);
  200. links[id].init = sof_pcm512x_codec_init;
  201. links[id].ops = &sof_pcm512x_ops;
  202. links[id].dpcm_playback = 1;
  203. /*
  204. * capture only supported with specific versions of the Hifiberry DAC+
  205. */
  206. if (sof_pcm512x_quirk & SOF_PCM512X_ENABLE_SSP_CAPTURE)
  207. links[id].dpcm_capture = 1;
  208. links[id].no_pcm = 1;
  209. links[id].cpus = &cpus[id];
  210. links[id].num_cpus = 1;
  211. if (is_legacy_cpu) {
  212. links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
  213. "ssp%d-port",
  214. ssp_codec);
  215. if (!links[id].cpus->dai_name)
  216. goto devm_err;
  217. } else {
  218. links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
  219. "SSP%d Pin",
  220. ssp_codec);
  221. if (!links[id].cpus->dai_name)
  222. goto devm_err;
  223. }
  224. id++;
  225. /* dmic */
  226. if (dmic_be_num > 0) {
  227. /* at least we have dmic01 */
  228. links[id].name = "dmic01";
  229. links[id].cpus = &cpus[id];
  230. links[id].cpus->dai_name = "DMIC01 Pin";
  231. links[id].init = dmic_init;
  232. if (dmic_be_num > 1) {
  233. /* set up 2 BE links at most */
  234. links[id + 1].name = "dmic16k";
  235. links[id + 1].cpus = &cpus[id + 1];
  236. links[id + 1].cpus->dai_name = "DMIC16k Pin";
  237. dmic_be_num = 2;
  238. }
  239. }
  240. for (i = 0; i < dmic_be_num; i++) {
  241. links[id].id = id;
  242. links[id].num_cpus = 1;
  243. links[id].codecs = dmic_component;
  244. links[id].num_codecs = ARRAY_SIZE(dmic_component);
  245. links[id].platforms = platform_component;
  246. links[id].num_platforms = ARRAY_SIZE(platform_component);
  247. links[id].ignore_suspend = 1;
  248. links[id].dpcm_capture = 1;
  249. links[id].no_pcm = 1;
  250. id++;
  251. }
  252. /* HDMI */
  253. if (hdmi_num > 0) {
  254. idisp_components = devm_kcalloc(dev, hdmi_num,
  255. sizeof(struct snd_soc_dai_link_component),
  256. GFP_KERNEL);
  257. if (!idisp_components)
  258. goto devm_err;
  259. }
  260. for (i = 1; i <= hdmi_num; i++) {
  261. links[id].name = devm_kasprintf(dev, GFP_KERNEL,
  262. "iDisp%d", i);
  263. if (!links[id].name)
  264. goto devm_err;
  265. links[id].id = id;
  266. links[id].cpus = &cpus[id];
  267. links[id].num_cpus = 1;
  268. links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
  269. "iDisp%d Pin", i);
  270. if (!links[id].cpus->dai_name)
  271. goto devm_err;
  272. /*
  273. * topology cannot be loaded if codec is missing, so
  274. * use the dummy codec if needed
  275. */
  276. if (idisp_codec) {
  277. idisp_components[i - 1].name = "ehdaudio0D2";
  278. idisp_components[i - 1].dai_name =
  279. devm_kasprintf(dev, GFP_KERNEL,
  280. "intel-hdmi-hifi%d", i);
  281. } else {
  282. idisp_components[i - 1].name = "snd-soc-dummy";
  283. idisp_components[i - 1].dai_name = "snd-soc-dummy-dai";
  284. }
  285. if (!idisp_components[i - 1].dai_name)
  286. goto devm_err;
  287. links[id].codecs = &idisp_components[i - 1];
  288. links[id].num_codecs = 1;
  289. links[id].platforms = platform_component;
  290. links[id].num_platforms = ARRAY_SIZE(platform_component);
  291. links[id].init = sof_hdmi_init;
  292. links[id].dpcm_playback = 1;
  293. links[id].no_pcm = 1;
  294. id++;
  295. }
  296. return links;
  297. devm_err:
  298. return NULL;
  299. }
  300. static int sof_audio_probe(struct platform_device *pdev)
  301. {
  302. struct snd_soc_acpi_mach *mach = pdev->dev.platform_data;
  303. struct snd_soc_dai_link *dai_links;
  304. struct sof_card_private *ctx;
  305. int dmic_be_num, hdmi_num;
  306. int ret, ssp_codec;
  307. ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
  308. if (!ctx)
  309. return -ENOMEM;
  310. hdmi_num = 0;
  311. if (soc_intel_is_byt() || soc_intel_is_cht()) {
  312. is_legacy_cpu = true;
  313. dmic_be_num = 0;
  314. /* default quirk for legacy cpu */
  315. sof_pcm512x_quirk = SOF_PCM512X_SSP_CODEC(2);
  316. } else {
  317. dmic_be_num = 2;
  318. if (mach->mach_params.common_hdmi_codec_drv &&
  319. (mach->mach_params.codec_mask & IDISP_CODEC_MASK))
  320. ctx->idisp_codec = true;
  321. /* links are always present in topology */
  322. hdmi_num = 3;
  323. }
  324. dmi_check_system(sof_pcm512x_quirk_table);
  325. dev_dbg(&pdev->dev, "sof_pcm512x_quirk = %lx\n", sof_pcm512x_quirk);
  326. ssp_codec = sof_pcm512x_quirk & SOF_PCM512X_SSP_CODEC_MASK;
  327. if (!(sof_pcm512x_quirk & SOF_PCM512X_ENABLE_DMIC))
  328. dmic_be_num = 0;
  329. /* compute number of dai links */
  330. sof_audio_card_pcm512x.num_links = 1 + dmic_be_num + hdmi_num;
  331. dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec,
  332. dmic_be_num, hdmi_num,
  333. ctx->idisp_codec);
  334. if (!dai_links)
  335. return -ENOMEM;
  336. sof_audio_card_pcm512x.dai_link = dai_links;
  337. INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
  338. sof_audio_card_pcm512x.dev = &pdev->dev;
  339. /* set platform name for each dailink */
  340. ret = snd_soc_fixup_dai_links_platform_name(&sof_audio_card_pcm512x,
  341. mach->mach_params.platform);
  342. if (ret)
  343. return ret;
  344. snd_soc_card_set_drvdata(&sof_audio_card_pcm512x, ctx);
  345. return devm_snd_soc_register_card(&pdev->dev,
  346. &sof_audio_card_pcm512x);
  347. }
  348. static int sof_pcm512x_remove(struct platform_device *pdev)
  349. {
  350. struct snd_soc_card *card = platform_get_drvdata(pdev);
  351. struct snd_soc_component *component;
  352. for_each_card_components(card, component) {
  353. if (!strcmp(component->name, pcm512x_component[0].name)) {
  354. snd_soc_component_set_jack(component, NULL, NULL);
  355. break;
  356. }
  357. }
  358. return 0;
  359. }
  360. static struct platform_driver sof_audio = {
  361. .probe = sof_audio_probe,
  362. .remove = sof_pcm512x_remove,
  363. .driver = {
  364. .name = "sof_pcm512x",
  365. .pm = &snd_soc_pm_ops,
  366. },
  367. };
  368. module_platform_driver(sof_audio)
  369. MODULE_DESCRIPTION("ASoC Intel(R) SOF + PCM512x Machine driver");
  370. MODULE_AUTHOR("Pierre-Louis Bossart");
  371. MODULE_LICENSE("GPL v2");
  372. MODULE_ALIAS("platform:sof_pcm512x");
  373. MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);