dmic.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * dmic.c -- SoC audio for Generic Digital MICs
  4. *
  5. * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  6. */
  7. #include <linux/delay.h>
  8. #include <linux/gpio.h>
  9. #include <linux/gpio/consumer.h>
  10. #include <linux/platform_device.h>
  11. #include <linux/slab.h>
  12. #include <linux/module.h>
  13. #include <sound/core.h>
  14. #include <sound/pcm.h>
  15. #include <sound/soc.h>
  16. #include <sound/soc-dapm.h>
  17. #define MAX_MODESWITCH_DELAY 70
  18. static int modeswitch_delay;
  19. module_param(modeswitch_delay, uint, 0644);
  20. static int wakeup_delay;
  21. module_param(wakeup_delay, uint, 0644);
  22. struct dmic {
  23. struct gpio_desc *gpio_en;
  24. int wakeup_delay;
  25. /* Delay after DMIC mode switch */
  26. int modeswitch_delay;
  27. };
  28. static int dmic_daiops_trigger(struct snd_pcm_substream *substream,
  29. int cmd, struct snd_soc_dai *dai)
  30. {
  31. struct snd_soc_component *component = dai->component;
  32. struct dmic *dmic = snd_soc_component_get_drvdata(component);
  33. switch (cmd) {
  34. case SNDRV_PCM_TRIGGER_STOP:
  35. if (dmic->modeswitch_delay)
  36. mdelay(dmic->modeswitch_delay);
  37. break;
  38. }
  39. return 0;
  40. }
  41. static const struct snd_soc_dai_ops dmic_dai_ops = {
  42. .trigger = dmic_daiops_trigger,
  43. };
  44. static int dmic_aif_event(struct snd_soc_dapm_widget *w,
  45. struct snd_kcontrol *kcontrol, int event) {
  46. struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
  47. struct dmic *dmic = snd_soc_component_get_drvdata(component);
  48. switch (event) {
  49. case SND_SOC_DAPM_POST_PMU:
  50. if (dmic->gpio_en)
  51. gpiod_set_value_cansleep(dmic->gpio_en, 1);
  52. if (dmic->wakeup_delay)
  53. msleep(dmic->wakeup_delay);
  54. break;
  55. case SND_SOC_DAPM_POST_PMD:
  56. if (dmic->gpio_en)
  57. gpiod_set_value_cansleep(dmic->gpio_en, 0);
  58. break;
  59. }
  60. return 0;
  61. }
  62. static struct snd_soc_dai_driver dmic_dai = {
  63. .name = "dmic-hifi",
  64. .capture = {
  65. .stream_name = "Capture",
  66. .channels_min = 1,
  67. .channels_max = 8,
  68. .rates = SNDRV_PCM_RATE_CONTINUOUS,
  69. .formats = SNDRV_PCM_FMTBIT_S32_LE
  70. | SNDRV_PCM_FMTBIT_S24_LE
  71. | SNDRV_PCM_FMTBIT_S16_LE,
  72. },
  73. .ops = &dmic_dai_ops,
  74. };
  75. static int dmic_component_probe(struct snd_soc_component *component)
  76. {
  77. struct dmic *dmic;
  78. dmic = devm_kzalloc(component->dev, sizeof(*dmic), GFP_KERNEL);
  79. if (!dmic)
  80. return -ENOMEM;
  81. dmic->gpio_en = devm_gpiod_get_optional(component->dev,
  82. "dmicen", GPIOD_OUT_LOW);
  83. if (IS_ERR(dmic->gpio_en))
  84. return PTR_ERR(dmic->gpio_en);
  85. device_property_read_u32(component->dev, "wakeup-delay-ms",
  86. &dmic->wakeup_delay);
  87. device_property_read_u32(component->dev, "modeswitch-delay-ms",
  88. &dmic->modeswitch_delay);
  89. if (wakeup_delay)
  90. dmic->wakeup_delay = wakeup_delay;
  91. if (modeswitch_delay)
  92. dmic->modeswitch_delay = modeswitch_delay;
  93. if (dmic->modeswitch_delay > MAX_MODESWITCH_DELAY)
  94. dmic->modeswitch_delay = MAX_MODESWITCH_DELAY;
  95. snd_soc_component_set_drvdata(component, dmic);
  96. return 0;
  97. }
  98. static const struct snd_soc_dapm_widget dmic_dapm_widgets[] = {
  99. SND_SOC_DAPM_AIF_OUT_E("DMIC AIF", "Capture", 0,
  100. SND_SOC_NOPM, 0, 0, dmic_aif_event,
  101. SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
  102. SND_SOC_DAPM_INPUT("DMic"),
  103. };
  104. static const struct snd_soc_dapm_route intercon[] = {
  105. {"DMIC AIF", NULL, "DMic"},
  106. };
  107. static const struct snd_soc_component_driver soc_dmic = {
  108. .probe = dmic_component_probe,
  109. .dapm_widgets = dmic_dapm_widgets,
  110. .num_dapm_widgets = ARRAY_SIZE(dmic_dapm_widgets),
  111. .dapm_routes = intercon,
  112. .num_dapm_routes = ARRAY_SIZE(intercon),
  113. .idle_bias_on = 1,
  114. .use_pmdown_time = 1,
  115. .endianness = 1,
  116. .non_legacy_dai_naming = 1,
  117. };
  118. static int dmic_dev_probe(struct platform_device *pdev)
  119. {
  120. int err;
  121. u32 chans;
  122. struct snd_soc_dai_driver *dai_drv = &dmic_dai;
  123. if (pdev->dev.of_node) {
  124. err = of_property_read_u32(pdev->dev.of_node, "num-channels", &chans);
  125. if (err && (err != -EINVAL))
  126. return err;
  127. if (!err) {
  128. if (chans < 1 || chans > 8)
  129. return -EINVAL;
  130. dai_drv = devm_kzalloc(&pdev->dev, sizeof(*dai_drv), GFP_KERNEL);
  131. if (!dai_drv)
  132. return -ENOMEM;
  133. memcpy(dai_drv, &dmic_dai, sizeof(*dai_drv));
  134. dai_drv->capture.channels_max = chans;
  135. }
  136. }
  137. return devm_snd_soc_register_component(&pdev->dev,
  138. &soc_dmic, dai_drv, 1);
  139. }
  140. MODULE_ALIAS("platform:dmic-codec");
  141. static const struct of_device_id dmic_dev_match[] = {
  142. {.compatible = "dmic-codec"},
  143. {}
  144. };
  145. MODULE_DEVICE_TABLE(of, dmic_dev_match);
  146. static struct platform_driver dmic_driver = {
  147. .driver = {
  148. .name = "dmic-codec",
  149. .of_match_table = dmic_dev_match,
  150. },
  151. .probe = dmic_dev_probe,
  152. };
  153. module_platform_driver(dmic_driver);
  154. MODULE_DESCRIPTION("Generic DMIC driver");
  155. MODULE_AUTHOR("Liam Girdwood <lrg@slimlogic.co.uk>");
  156. MODULE_LICENSE("GPL");