/* * ===================================================================================== * * Filename: snd-i2smic-rpi * * Description: I2S microphone kernel module * * Version: 0.1.0 * Created: 2020-04-14 * Revision: none * Compiler: gcc * * Pi4 Mods: Carter Nelson * Orig Author: Huan Truong (htruong@tnhh.net), originally written by Paul Creaser * * ===================================================================================== */ #include #include #include #include #include #include #include #include "snd-i2smic-rpi.h" /* * modified for linux 4.1.5 * inspired by https://github.com/msperl/spi-config * with thanks for https://github.com/notro/rpi-source/wiki * as well as Florian Meier for the rpi i2s and dma drivers * * to use a differant (simple-card compatible) codec * change the codec name string in two places and the * codec_dai name string. (see codec's source file) * * * N.B. playback vs capture is determined by the codec choice * */ static struct asoc_simple_card_info card_info; static struct platform_device card_device; /* * Setup command line parameter */ static short rpi_platform_generation; module_param(rpi_platform_generation, short, 0); MODULE_PARM_DESC(rpi_platform_generation, "Raspberry Pi generation: 0=Pi0, 1=Pi2/3, 2=Pi4"); /* * Dummy callback for release */ void device_release_callback(struct device *dev) { /* do nothing */ }; /* * Setup the card info */ static struct asoc_simple_card_info default_card_info = { .card = "snd_rpi_i2s_card", // -> snd_soc_card.name .name = "simple-card_codec_link", // -> snd_soc_dai_link.name .codec = "snd-soc-dummy", // "dmic-codec", // -> snd_soc_dai_link.codec_name .platform = "not-set.i2s", .daifmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, .cpu_dai = { .name = "not-set.i2s", // -> snd_soc_dai_link.cpu_dai_name .sysclk = 0 }, .codec_dai = { .name = "snd-soc-dummy-dai", //"dmic-codec", // -> snd_soc_dai_link.codec_dai_name .sysclk = 0 }, }; /* * Setup the card device */ static struct platform_device default_card_device = { .name = "asoc-simple-card", //module alias .id = 0, .num_resources = 0, .dev = { .release = &device_release_callback, .platform_data = &default_card_info, // *HACK ALERT* }, }; /* * Callback for module initialization */ int i2s_mic_rpi_init(void) { const char *dmaengine = "bcm2708-dmaengine"; //module name static char *card_platform; int ret; printk(KERN_INFO "snd-i2smic-rpi: Version %s\n", SND_I2SMIC_RPI_VERSION); // Set platform switch (rpi_platform_generation) { case 0: // Pi Zero card_platform = "20203000.i2s"; break; case 1: // Pi 2 and 3 card_platform = "3f203000.i2s"; break; case 2: default: // Pi 4 card_platform = "fe203000.i2s"; break; } printk(KERN_INFO "snd-i2smic-rpi: Setting platform to %s\n", card_platform); // request DMA engine module ret = request_module(dmaengine); pr_alert("request module load '%s': %d\n",dmaengine, ret); // update info card_info = default_card_info; card_info.platform = card_platform; card_info.cpu_dai.name = card_platform; card_device = default_card_device; card_device.dev.platform_data = &card_info; // register the card device ret = platform_device_register(&card_device); pr_alert("register platform device '%s': %d\n",card_device.name, ret); return 0; } /* * Callback for module exit */ void i2s_mic_rpi_exit(void) { platform_device_unregister(&card_device); pr_alert("i2s mic module unloaded\n"); } // Plumb it up module_init(i2s_mic_rpi_init); module_exit(i2s_mic_rpi_exit); MODULE_DESCRIPTION("ASoC simple-card I2S Microphone"); MODULE_AUTHOR("Carter Nelson"); MODULE_LICENSE("GPL v2");