smartq_wm8987.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. // SPDX-License-Identifier: GPL-2.0+
  2. //
  3. // Copyright 2010 Maurus Cuelenaere <[email protected]>
  4. //
  5. // Based on smdk6410_wm8987.c
  6. // Copyright 2007 Wolfson Microelectronics PLC. - [email protected]
  7. // Graeme Gregory - [email protected]
  8. #include <linux/gpio/consumer.h>
  9. #include <linux/module.h>
  10. #include <sound/soc.h>
  11. #include <sound/jack.h>
  12. #include "i2s.h"
  13. #include "../codecs/wm8750.h"
  14. /*
  15. * WM8987 is register compatible with WM8750, so using that as base driver.
  16. */
  17. static struct snd_soc_card snd_soc_smartq;
  18. static int smartq_hifi_hw_params(struct snd_pcm_substream *substream,
  19. struct snd_pcm_hw_params *params)
  20. {
  21. struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
  22. struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
  23. struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
  24. unsigned int clk = 0;
  25. int ret;
  26. switch (params_rate(params)) {
  27. case 8000:
  28. case 16000:
  29. case 32000:
  30. case 48000:
  31. case 96000:
  32. clk = 12288000;
  33. break;
  34. case 11025:
  35. case 22050:
  36. case 44100:
  37. case 88200:
  38. clk = 11289600;
  39. break;
  40. }
  41. /* Use PCLK for I2S signal generation */
  42. ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_RCLKSRC_0,
  43. 0, SND_SOC_CLOCK_IN);
  44. if (ret < 0)
  45. return ret;
  46. /* Gate the RCLK output on PAD */
  47. ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_CDCLK,
  48. 0, SND_SOC_CLOCK_IN);
  49. if (ret < 0)
  50. return ret;
  51. /* set the codec system clock for DAC and ADC */
  52. ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk,
  53. SND_SOC_CLOCK_IN);
  54. if (ret < 0)
  55. return ret;
  56. return 0;
  57. }
  58. /*
  59. * SmartQ WM8987 HiFi DAI operations.
  60. */
  61. static const struct snd_soc_ops smartq_hifi_ops = {
  62. .hw_params = smartq_hifi_hw_params,
  63. };
  64. static struct snd_soc_jack smartq_jack;
  65. static struct snd_soc_jack_pin smartq_jack_pins[] = {
  66. /* Disable speaker when headphone is plugged in */
  67. {
  68. .pin = "Internal Speaker",
  69. .mask = SND_JACK_HEADPHONE,
  70. },
  71. };
  72. static struct snd_soc_jack_gpio smartq_jack_gpios[] = {
  73. {
  74. .gpio = -1,
  75. .name = "headphone detect",
  76. .report = SND_JACK_HEADPHONE,
  77. .debounce_time = 200,
  78. },
  79. };
  80. static const struct snd_kcontrol_new wm8987_smartq_controls[] = {
  81. SOC_DAPM_PIN_SWITCH("Internal Speaker"),
  82. SOC_DAPM_PIN_SWITCH("Headphone Jack"),
  83. SOC_DAPM_PIN_SWITCH("Internal Mic"),
  84. };
  85. static int smartq_speaker_event(struct snd_soc_dapm_widget *w,
  86. struct snd_kcontrol *k,
  87. int event)
  88. {
  89. struct gpio_desc *gpio = snd_soc_card_get_drvdata(&snd_soc_smartq);
  90. gpiod_set_value(gpio, SND_SOC_DAPM_EVENT_OFF(event));
  91. return 0;
  92. }
  93. static const struct snd_soc_dapm_widget wm8987_dapm_widgets[] = {
  94. SND_SOC_DAPM_SPK("Internal Speaker", smartq_speaker_event),
  95. SND_SOC_DAPM_HP("Headphone Jack", NULL),
  96. SND_SOC_DAPM_MIC("Internal Mic", NULL),
  97. };
  98. static const struct snd_soc_dapm_route audio_map[] = {
  99. {"Headphone Jack", NULL, "LOUT2"},
  100. {"Headphone Jack", NULL, "ROUT2"},
  101. {"Internal Speaker", NULL, "LOUT2"},
  102. {"Internal Speaker", NULL, "ROUT2"},
  103. {"Mic Bias", NULL, "Internal Mic"},
  104. {"LINPUT2", NULL, "Mic Bias"},
  105. };
  106. static int smartq_wm8987_init(struct snd_soc_pcm_runtime *rtd)
  107. {
  108. struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
  109. int err = 0;
  110. /* set endpoints to not connected */
  111. snd_soc_dapm_nc_pin(dapm, "LINPUT1");
  112. snd_soc_dapm_nc_pin(dapm, "RINPUT1");
  113. snd_soc_dapm_nc_pin(dapm, "OUT3");
  114. snd_soc_dapm_nc_pin(dapm, "ROUT1");
  115. /* Headphone jack detection */
  116. err = snd_soc_card_jack_new_pins(rtd->card, "Headphone Jack",
  117. SND_JACK_HEADPHONE, &smartq_jack,
  118. smartq_jack_pins,
  119. ARRAY_SIZE(smartq_jack_pins));
  120. if (err)
  121. return err;
  122. err = snd_soc_jack_add_gpios(&smartq_jack,
  123. ARRAY_SIZE(smartq_jack_gpios),
  124. smartq_jack_gpios);
  125. return err;
  126. }
  127. SND_SOC_DAILINK_DEFS(wm8987,
  128. DAILINK_COMP_ARRAY(COMP_CPU("samsung-i2s.0")),
  129. DAILINK_COMP_ARRAY(COMP_CODEC("wm8750.0-0x1a", "wm8750-hifi")),
  130. DAILINK_COMP_ARRAY(COMP_PLATFORM("samsung-i2s.0")));
  131. static struct snd_soc_dai_link smartq_dai[] = {
  132. {
  133. .name = "wm8987",
  134. .stream_name = "SmartQ Hi-Fi",
  135. .init = smartq_wm8987_init,
  136. .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
  137. SND_SOC_DAIFMT_CBS_CFS,
  138. .ops = &smartq_hifi_ops,
  139. SND_SOC_DAILINK_REG(wm8987),
  140. },
  141. };
  142. static struct snd_soc_card snd_soc_smartq = {
  143. .name = "SmartQ",
  144. .owner = THIS_MODULE,
  145. .dai_link = smartq_dai,
  146. .num_links = ARRAY_SIZE(smartq_dai),
  147. .dapm_widgets = wm8987_dapm_widgets,
  148. .num_dapm_widgets = ARRAY_SIZE(wm8987_dapm_widgets),
  149. .dapm_routes = audio_map,
  150. .num_dapm_routes = ARRAY_SIZE(audio_map),
  151. .controls = wm8987_smartq_controls,
  152. .num_controls = ARRAY_SIZE(wm8987_smartq_controls),
  153. };
  154. static int smartq_probe(struct platform_device *pdev)
  155. {
  156. struct gpio_desc *gpio;
  157. int ret;
  158. platform_set_drvdata(pdev, &snd_soc_smartq);
  159. /* Initialise GPIOs used by amplifiers */
  160. gpio = devm_gpiod_get(&pdev->dev, "amplifiers shutdown",
  161. GPIOD_OUT_HIGH);
  162. if (IS_ERR(gpio)) {
  163. dev_err(&pdev->dev, "Failed to register GPK12\n");
  164. ret = PTR_ERR(gpio);
  165. goto out;
  166. }
  167. snd_soc_card_set_drvdata(&snd_soc_smartq, gpio);
  168. ret = devm_snd_soc_register_card(&pdev->dev, &snd_soc_smartq);
  169. if (ret)
  170. dev_err(&pdev->dev, "Failed to register card\n");
  171. out:
  172. return ret;
  173. }
  174. static struct platform_driver smartq_driver = {
  175. .driver = {
  176. .name = "smartq-audio",
  177. },
  178. .probe = smartq_probe,
  179. };
  180. module_platform_driver(smartq_driver);
  181. /* Module information */
  182. MODULE_AUTHOR("Maurus Cuelenaere <[email protected]>");
  183. MODULE_DESCRIPTION("ALSA SoC SmartQ WM8987");
  184. MODULE_LICENSE("GPL");