mt8173-max98090.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. /*
  2. * mt8173-max98090.c -- MT8173 MAX98090 ALSA SoC machine driver
  3. *
  4. * Copyright (c) 2015 MediaTek Inc.
  5. * Author: Koro Chen <koro.chen@mediatek.com>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License version 2 and
  9. * only version 2 as published by the Free Software Foundation.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. */
  16. #include <linux/module.h>
  17. #include <sound/soc.h>
  18. #include <sound/jack.h>
  19. #include <linux/gpio.h>
  20. #include "../codecs/max98090.h"
  21. static struct snd_soc_jack mt8173_max98090_jack;
  22. static struct snd_soc_jack_pin mt8173_max98090_jack_pins[] = {
  23. {
  24. .pin = "Headphone",
  25. .mask = SND_JACK_HEADPHONE,
  26. },
  27. {
  28. .pin = "Headset Mic",
  29. .mask = SND_JACK_MICROPHONE,
  30. },
  31. };
  32. static const struct snd_soc_dapm_widget mt8173_max98090_widgets[] = {
  33. SND_SOC_DAPM_SPK("Speaker", NULL),
  34. SND_SOC_DAPM_MIC("Int Mic", NULL),
  35. SND_SOC_DAPM_HP("Headphone", NULL),
  36. SND_SOC_DAPM_MIC("Headset Mic", NULL),
  37. };
  38. static const struct snd_soc_dapm_route mt8173_max98090_routes[] = {
  39. {"Speaker", NULL, "SPKL"},
  40. {"Speaker", NULL, "SPKR"},
  41. {"DMICL", NULL, "Int Mic"},
  42. {"Headphone", NULL, "HPL"},
  43. {"Headphone", NULL, "HPR"},
  44. {"Headset Mic", NULL, "MICBIAS"},
  45. {"IN34", NULL, "Headset Mic"},
  46. };
  47. static const struct snd_kcontrol_new mt8173_max98090_controls[] = {
  48. SOC_DAPM_PIN_SWITCH("Speaker"),
  49. SOC_DAPM_PIN_SWITCH("Int Mic"),
  50. SOC_DAPM_PIN_SWITCH("Headphone"),
  51. SOC_DAPM_PIN_SWITCH("Headset Mic"),
  52. };
  53. static int mt8173_max98090_hw_params(struct snd_pcm_substream *substream,
  54. struct snd_pcm_hw_params *params)
  55. {
  56. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  57. struct snd_soc_dai *codec_dai = rtd->codec_dai;
  58. return snd_soc_dai_set_sysclk(codec_dai, 0, params_rate(params) * 256,
  59. SND_SOC_CLOCK_IN);
  60. }
  61. static struct snd_soc_ops mt8173_max98090_ops = {
  62. .hw_params = mt8173_max98090_hw_params,
  63. };
  64. static int mt8173_max98090_init(struct snd_soc_pcm_runtime *runtime)
  65. {
  66. int ret;
  67. struct snd_soc_card *card = runtime->card;
  68. struct snd_soc_codec *codec = runtime->codec;
  69. /* enable jack detection */
  70. ret = snd_soc_card_jack_new(card, "Headphone", SND_JACK_HEADPHONE,
  71. &mt8173_max98090_jack, NULL, 0);
  72. if (ret) {
  73. dev_err(card->dev, "Can't snd_soc_jack_new %d\n", ret);
  74. return ret;
  75. }
  76. ret = snd_soc_jack_add_pins(&mt8173_max98090_jack,
  77. ARRAY_SIZE(mt8173_max98090_jack_pins),
  78. mt8173_max98090_jack_pins);
  79. if (ret) {
  80. dev_err(card->dev, "Can't snd_soc_jack_add_pins %d\n", ret);
  81. return ret;
  82. }
  83. return max98090_mic_detect(codec, &mt8173_max98090_jack);
  84. }
  85. /* Digital audio interface glue - connects codec <---> CPU */
  86. static struct snd_soc_dai_link mt8173_max98090_dais[] = {
  87. /* Front End DAI links */
  88. {
  89. .name = "MAX98090 Playback",
  90. .stream_name = "MAX98090 Playback",
  91. .cpu_dai_name = "DL1",
  92. .codec_name = "snd-soc-dummy",
  93. .codec_dai_name = "snd-soc-dummy-dai",
  94. .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
  95. .dynamic = 1,
  96. .dpcm_playback = 1,
  97. },
  98. {
  99. .name = "MAX98090 Capture",
  100. .stream_name = "MAX98090 Capture",
  101. .cpu_dai_name = "VUL",
  102. .codec_name = "snd-soc-dummy",
  103. .codec_dai_name = "snd-soc-dummy-dai",
  104. .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
  105. .dynamic = 1,
  106. .dpcm_capture = 1,
  107. },
  108. /* Back End DAI links */
  109. {
  110. .name = "Codec",
  111. .cpu_dai_name = "I2S",
  112. .no_pcm = 1,
  113. .codec_dai_name = "HiFi",
  114. .init = mt8173_max98090_init,
  115. .ops = &mt8173_max98090_ops,
  116. .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
  117. SND_SOC_DAIFMT_CBS_CFS,
  118. .dpcm_playback = 1,
  119. .dpcm_capture = 1,
  120. },
  121. };
  122. static struct snd_soc_card mt8173_max98090_card = {
  123. .name = "mt8173-max98090",
  124. .owner = THIS_MODULE,
  125. .dai_link = mt8173_max98090_dais,
  126. .num_links = ARRAY_SIZE(mt8173_max98090_dais),
  127. .controls = mt8173_max98090_controls,
  128. .num_controls = ARRAY_SIZE(mt8173_max98090_controls),
  129. .dapm_widgets = mt8173_max98090_widgets,
  130. .num_dapm_widgets = ARRAY_SIZE(mt8173_max98090_widgets),
  131. .dapm_routes = mt8173_max98090_routes,
  132. .num_dapm_routes = ARRAY_SIZE(mt8173_max98090_routes),
  133. };
  134. static int mt8173_max98090_dev_probe(struct platform_device *pdev)
  135. {
  136. struct snd_soc_card *card = &mt8173_max98090_card;
  137. struct device_node *codec_node, *platform_node;
  138. int ret, i;
  139. platform_node = of_parse_phandle(pdev->dev.of_node,
  140. "mediatek,platform", 0);
  141. if (!platform_node) {
  142. dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");
  143. return -EINVAL;
  144. }
  145. for (i = 0; i < card->num_links; i++) {
  146. if (mt8173_max98090_dais[i].platform_name)
  147. continue;
  148. mt8173_max98090_dais[i].platform_of_node = platform_node;
  149. }
  150. codec_node = of_parse_phandle(pdev->dev.of_node,
  151. "mediatek,audio-codec", 0);
  152. if (!codec_node) {
  153. dev_err(&pdev->dev,
  154. "Property 'audio-codec' missing or invalid\n");
  155. return -EINVAL;
  156. }
  157. for (i = 0; i < card->num_links; i++) {
  158. if (mt8173_max98090_dais[i].codec_name)
  159. continue;
  160. mt8173_max98090_dais[i].codec_of_node = codec_node;
  161. }
  162. card->dev = &pdev->dev;
  163. ret = devm_snd_soc_register_card(&pdev->dev, card);
  164. if (ret)
  165. dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n",
  166. __func__, ret);
  167. return ret;
  168. }
  169. static const struct of_device_id mt8173_max98090_dt_match[] = {
  170. { .compatible = "mediatek,mt8173-max98090", },
  171. { }
  172. };
  173. MODULE_DEVICE_TABLE(of, mt8173_max98090_dt_match);
  174. static struct platform_driver mt8173_max98090_driver = {
  175. .driver = {
  176. .name = "mt8173-max98090",
  177. .of_match_table = mt8173_max98090_dt_match,
  178. #ifdef CONFIG_PM
  179. .pm = &snd_soc_pm_ops,
  180. #endif
  181. },
  182. .probe = mt8173_max98090_dev_probe,
  183. };
  184. module_platform_driver(mt8173_max98090_driver);
  185. /* Module information */
  186. MODULE_DESCRIPTION("MT8173 MAX98090 ALSA SoC machine driver");
  187. MODULE_AUTHOR("Koro Chen <koro.chen@mediatek.com>");
  188. MODULE_LICENSE("GPL v2");
  189. MODULE_ALIAS("platform:mt8173-max98090");