You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

151 lines
3.9 KiB

  1. /*
  2. * =====================================================================================
  3. *
  4. * Filename: snd-i2smic-rpi
  5. *
  6. * Description: I2S microphone kernel module
  7. *
  8. * Version: 0.1.0
  9. * Created: 2020-04-14
  10. * Revision: none
  11. * Compiler: gcc
  12. *
  13. * Pi4 Mods: Carter Nelson
  14. * Orig Author: Huan Truong (htruong@tnhh.net), originally written by Paul Creaser
  15. *
  16. * =====================================================================================
  17. */
  18. #include <linux/module.h>
  19. #include <linux/moduleparam.h>
  20. #include <linux/kernel.h>
  21. #include <linux/kmod.h>
  22. #include <linux/platform_device.h>
  23. #include <sound/simple_card.h>
  24. #include <linux/delay.h>
  25. #include "snd-i2smic-rpi.h"
  26. /*
  27. * modified for linux 4.1.5
  28. * inspired by https://github.com/msperl/spi-config
  29. * with thanks for https://github.com/notro/rpi-source/wiki
  30. * as well as Florian Meier for the rpi i2s and dma drivers
  31. *
  32. * to use a differant (simple-card compatible) codec
  33. * change the codec name string in two places and the
  34. * codec_dai name string. (see codec's source file)
  35. *
  36. *
  37. * N.B. playback vs capture is determined by the codec choice
  38. * */
  39. static struct asoc_simple_card_info card_info;
  40. static struct platform_device card_device;
  41. /*
  42. * Setup command line parameter
  43. */
  44. static short rpi_platform_generation;
  45. module_param(rpi_platform_generation, short, 0);
  46. MODULE_PARM_DESC(rpi_platform_generation, "Raspberry Pi generation: 0=Pi0, 1=Pi2/3, 2=Pi4");
  47. /*
  48. * Dummy callback for release
  49. */
  50. void device_release_callback(struct device *dev) { /* do nothing */ };
  51. /*
  52. * Setup the card info
  53. */
  54. static struct asoc_simple_card_info default_card_info = {
  55. .card = "snd_rpi_i2s_card", // -> snd_soc_card.name
  56. .name = "simple-card_codec_link", // -> snd_soc_dai_link.name
  57. .codec = "snd-soc-dummy", // "dmic-codec", // -> snd_soc_dai_link.codec_name
  58. .platform = "not-set.i2s",
  59. .daifmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS,
  60. .cpu_dai = {
  61. .name = "not-set.i2s", // -> snd_soc_dai_link.cpu_dai_name
  62. .sysclk = 0
  63. },
  64. .codec_dai = {
  65. .name = "snd-soc-dummy-dai", //"dmic-codec", // -> snd_soc_dai_link.codec_dai_name
  66. .sysclk = 0
  67. },
  68. };
  69. /*
  70. * Setup the card device
  71. */
  72. static struct platform_device default_card_device = {
  73. .name = "asoc-simple-card", //module alias
  74. .id = 0,
  75. .num_resources = 0,
  76. .dev = {
  77. .release = &device_release_callback,
  78. .platform_data = &default_card_info, // *HACK ALERT*
  79. },
  80. };
  81. /*
  82. * Callback for module initialization
  83. */
  84. int i2s_mic_rpi_init(void)
  85. {
  86. const char *dmaengine = "bcm2708-dmaengine"; //module name
  87. static char *card_platform;
  88. int ret;
  89. printk(KERN_INFO "snd-i2smic-rpi: Version %s\n", SND_I2SMIC_RPI_VERSION);
  90. // Set platform
  91. switch (rpi_platform_generation) {
  92. case 0:
  93. // Pi Zero
  94. card_platform = "20203000.i2s";
  95. break;
  96. case 1:
  97. // Pi 2 and 3
  98. card_platform = "3f203000.i2s";
  99. break;
  100. case 2:
  101. default:
  102. // Pi 4
  103. card_platform = "fe203000.i2s";
  104. break;
  105. }
  106. printk(KERN_INFO "snd-i2smic-rpi: Setting platform to %s\n", card_platform);
  107. // request DMA engine module
  108. ret = request_module(dmaengine);
  109. pr_alert("request module load '%s': %d\n",dmaengine, ret);
  110. // update info
  111. card_info = default_card_info;
  112. card_info.platform = card_platform;
  113. card_info.cpu_dai.name = card_platform;
  114. card_device = default_card_device;
  115. card_device.dev.platform_data = &card_info;
  116. // register the card device
  117. ret = platform_device_register(&card_device);
  118. pr_alert("register platform device '%s': %d\n",card_device.name, ret);
  119. return 0;
  120. }
  121. /*
  122. * Callback for module exit
  123. */
  124. void i2s_mic_rpi_exit(void)
  125. {
  126. platform_device_unregister(&card_device);
  127. pr_alert("i2s mic module unloaded\n");
  128. }
  129. // Plumb it up
  130. module_init(i2s_mic_rpi_init);
  131. module_exit(i2s_mic_rpi_exit);
  132. MODULE_DESCRIPTION("ASoC simple-card I2S Microphone");
  133. MODULE_AUTHOR("Carter Nelson");
  134. MODULE_LICENSE("GPL v2");