Browse Source

add i2s mic setup

caternuson 2 months ago
parent
commit
0de6e91c1a

+ 54
- 0
i2s_mic_module/Makefile View File

@@ -0,0 +1,54 @@
1
+MOD_NAME	:= snd-i2smic-rpi
2
+
3
+ifneq ($(KERNELRELEASE),)
4
+
5
+# call from kernel build system
6
+
7
+all:
8
+	@echo "Building from the kernel build system"
9
+	@echo "Module build: $(CONFIG_SND_I2S_RPI)"
10
+	@echo "Name: $(MOD_NAME)"
11
+
12
+obj-$(CONFIG_SND_I2S_RPI) := $(MOD_NAME).o
13
+
14
+else
15
+# external module build
16
+
17
+EXTRA_FLAGS += -I$(PWD)
18
+
19
+#
20
+# KDIR is a path to a directory containing kernel source.
21
+# It can be specified on the command line passed to make to enable the module to
22
+# be built and installed for a kernel other than the one currently running.
23
+# By default it is the path to the symbolic link created when
24
+# the current kernel's modules were installed, but
25
+# any valid path to the directory in which the target kernel's source is located
26
+# can be provided on the command line.
27
+#
28
+KDIR	?= /lib/modules/$(shell uname -r)/build
29
+MDIR	?= /lib/modules/$(shell uname -r)
30
+PWD	:= $(shell pwd)
31
+
32
+export CONFIG_SND_I2S_RPI := m
33
+
34
+all:
35
+	$(MAKE) -C $(KDIR) M=$(PWD) modules
36
+
37
+clean:
38
+	$(MAKE) -C $(KDIR) M=$(PWD) clean
39
+
40
+help:
41
+	$(MAKE) -C $(KDIR) M=$(PWD) help
42
+
43
+install: snd-i2smic-rpi.ko
44
+	rm -f ${MDIR}/kernel/sound/drivers/$(MOD_NAME).ko
45
+	install -m644 -b -D $(MOD_NAME).ko ${MDIR}/kernel/sound/drivers/$(MOD_NAME).ko
46
+	depmod -a
47
+
48
+uninstall:
49
+	rm -rf ${MDIR}/kernel/sound/drivers/$(MOD_NAME).ko
50
+	depmod -a
51
+
52
+endif
53
+
54
+.PHONY : all clean install uninstall

+ 114
- 0
i2s_mic_module/README.md View File

@@ -0,0 +1,114 @@
1
+**Driver for the Adafruit I2S MEMS Microphone**
2
+
3
+[Product learn page on Adafruit](https://learn.adafruit.com/adafruit-i2s-mems-microphone-breakout/overview).
4
+
5
+Known problems with this driver: Low vol level. While you can use the alsa magic socery to make an alsa softvol input, that approach won't work out of the box with anything that uses Pulseaudio. If you have any idea how to make this work with Pulse, please drop me a line.
6
+
7
+Installing the I2S microphone driver the easy way
8
+====================================
9
+
10
+If you use Raspbian or any Debian-derived distribution, [go to the releases tab](https://github.com/htruong/snd-i2s_rpi/releases) and download the newest deb version.
11
+
12
+Then do the following
13
+
14
+```bash
15
+
16
+# Installing raspberrypi-kernel-headers works only if you haven't messed with
17
+# the rpi-update thing.
18
+# If you did, then you would have to do the rpi-source method
19
+# to get the kernel headers. See: 
20
+# https://learn.adafruit.com/adafruit-i2s-mems-microphone-breakout/raspberry-pi-wiring-and-test#kernel-compiling
21
+
22
+$ sudo apt install dkms raspberrypi-kernel-headers
23
+
24
+$ sudo dpkg -i snd-i2s-rpi-dkms_0.0.2_all.deb
25
+
26
+# For this to work, remember to modify these first:
27
+# /boot/config.txt -> dtparam=i2s=on
28
+# and 
29
+# /etc/modules -> snd-bcm2835
30
+# remember to reboot
31
+
32
+$ sudo modprobe snd-i2s_rpi rpi_platform_generation=0
33
+
34
+# rpi_platform_generation=0 for Raspberry Pi 1 B/A/A+, 0
35
+# do not add anything for everything else (2/3).
36
+
37
+# see if it works
38
+
39
+$ dmesg | grep i2s
40
+
41
+# it should say blah.i2s mapping OK
42
+
43
+# [    3.519017] snd_i2s_rpi: loading out-of-tree module taints kernel.
44
+# [    3.519881] snd-i2s_rpi: Version 0.0.2
45
+# [    3.519889] snd-i2s_rpi: Setting platform to 20203000.i2s
46
+# [    7.624559] asoc-simple-card asoc-simple-card.0: ASoC: CPU DAI 20203000.i2s not registered - will retry
47
+#  ... snip ...
48
+# [    9.507142] asoc-simple-card asoc-simple-card.0: snd-soc-dummy-dai <-> 20203000.i2s mapping ok
49
+
50
+$ arecord -l
51
+
52
+# it should list your mic
53
+# note that the default vol level is very low, you need
54
+# to follow the ladyada's guide to make it hearable
55
+
56
+
57
+# If you want it to load automatically at startup
58
+
59
+# 1. Add to /etc/modules
60
+# snd-i2s_rpi
61
+
62
+# 2. If you have a Pi old-gen, you need to do this:
63
+# create file called /etc/modprobe.d/snd-i2s_rpi.conf
64
+# add this line
65
+# options snd-i2s_rpi rpi_platform_generation=0
66
+
67
+```
68
+
69
+
70
+Installing as a stand-alone module
71
+====================================
72
+
73
+    make
74
+    sudo make install
75
+
76
+To load the driver manually, run this as root:
77
+
78
+    modprobe snd-i2s_rpi
79
+
80
+You may also specify custom toolchains by using the `CROSS_COMPILE` flag:
81
+
82
+    CROSS_COMPILE=/usr/local/bin/arm-eabi-
83
+
84
+
85
+Installing as a part of the kernel
86
+======================================
87
+
88
+Instructions to come later. Who would ever want to do that?
89
+
90
+
91
+
92
+
93
+Installing as a DKMS module
94
+=================================
95
+
96
+You can have even more fun with snd-i2s\_rpi by installing it as a DKMS module has the main advantage of being auto-compiled (and thus, possibly surviving) between kernel upgrades.
97
+
98
+First, get dkms. On Raspbian this should be:
99
+
100
+	sudo apt install dkms
101
+
102
+Then copy the root of this repository to `/usr/share`:
103
+
104
+	sudo cp -R . /usr/src/snd-i2s_rpi-0.0.2 (or whatever version number declared on dkms.conf is)
105
+	sudo dkms add -m snd-i2s_rpi -v 0.0.2
106
+
107
+Build and load the module:
108
+
109
+	sudo dkms build -m snd-i2s_rpi -v 0.0.2
110
+	sudo dkms install -m snd-i2s_rpi -v 0.0.2
111
+
112
+Now you have a proper dkms module that will work for a long time... hopefully.
113
+
114
+

+ 7
- 0
i2s_mic_module/dkms.conf View File

@@ -0,0 +1,7 @@
1
+PACKAGE_NAME="snd-i2smic-rpi"
2
+PACKAGE_VERSION="0.1.0"
3
+MAKE="KDIR=/lib/modules/$kernelver/build MDIR=/lib/modules/$kernelver make"
4
+CLEAN="make clean"
5
+BUILT_MODULE_NAME[0]="snd-i2smic-rpi"
6
+AUTOINSTALL="yes"
7
+DEST_MODULE_LOCATION="/kernel/sound/drivers"

+ 151
- 0
i2s_mic_module/snd-i2smic-rpi.c View File

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

+ 6
- 0
i2s_mic_module/snd-i2smic-rpi.h View File

@@ -0,0 +1,6 @@
1
+#ifndef _SND_I2SMIC_RPI_H_
2
+#define _SND_I2SMIC_RPI_H_
3
+
4
+#define SND_I2SMIC_RPI_VERSION  "0.1.0"
5
+
6
+#endif

+ 120
- 0
i2smic.sh View File

@@ -0,0 +1,120 @@
1
+#!/bin/bash
2
+#-------------------------------------------------------------------------
3
+# Installer script for I2S microphone support on Raspberry Pi
4
+#
5
+# 2020/04/15
6
+#-------------------------------------------------------------------------
7
+
8
+############################ Script assisters ############################
9
+
10
+# Given a list of strings representing options, display each option
11
+# preceded by a number (1 to N), display a prompt, check input until
12
+# a valid number within the selection range is entered.
13
+selectN() {
14
+        for ((i=1; i<=$#; i++)); do
15
+                echo $i. ${!i}
16
+        done
17
+        echo
18
+        REPLY=""
19
+        while :
20
+        do
21
+                echo -n "SELECT 1-$#: "
22
+                read
23
+                if [[ $REPLY -ge 1 ]] && [[ $REPLY -le $# ]]; then
24
+                        return $REPLY
25
+                fi
26
+        done
27
+}
28
+
29
+function ask() {
30
+    # http://djm.me/ask
31
+    while true; do
32
+
33
+        if [ "${2:-}" = "Y" ]; then
34
+            prompt="Y/n"
35
+            default=Y
36
+        elif [ "${2:-}" = "N" ]; then
37
+            prompt="y/N"
38
+            default=N
39
+        else
40
+            prompt="y/n"
41
+            default=
42
+        fi
43
+
44
+        # Ask the question
45
+        read -p "$1 [$prompt] " REPLY
46
+
47
+        # Default?
48
+        if [ -z "$REPLY" ]; then
49
+            REPLY=$default
50
+        fi
51
+
52
+        # Check if the reply is valid
53
+        case "$REPLY" in
54
+            Y*|y*) return 0 ;;
55
+            N*|n*) return 1 ;;
56
+        esac
57
+    done
58
+}
59
+
60
+####################################################### MAIN
61
+
62
+clear
63
+echo "This script downloads and installs"
64
+echo "I2S microphone support."
65
+echo
66
+
67
+echo "Select Pi Model:"
68
+selectN "Pi 0 or 0W" \
69
+        "Pi 2 or 3" \
70
+        "Pi 4"
71
+PIMODEL_SELECT=$(($?-1))
72
+
73
+ask "Auto load module at boot?"
74
+AUTO_LOAD=$?
75
+
76
+echo
77
+echo "Installing..."
78
+
79
+# System update and install
80
+apt-get -y update
81
+apt-get -y upgrade
82
+apt-get -y install git dkms raspberrypi-kernel-headers
83
+
84
+# Clone the repo
85
+git clone https://github.com/adafruit/Raspberry-Pi-Installer-Scripts.git
86
+
87
+# Install and build module
88
+cd Raspberry-Pi-Installer-Scripts/i2s_mic_module
89
+cp -R . /usr/src/snd-i2smic-rpi-0.1.0
90
+dkms add -m snd-i2smic-rpi -v 0.1.0
91
+dkms build -m snd-i2smic-rpi -v 0.1.0
92
+dkms install -m snd-i2smic-rpi -v 0.1.0
93
+
94
+# Setup auto load at boot if selected
95
+if [ $AUTO_LOAD = 0 ]; then
96
+  cat > /etc/modules-load.d/snd-i2smic-rpi.conf<<EOF
97
+snd-i2smic-rpi
98
+EOF
99
+  cat > /etc/modprobe.d/snd-i2smic-rpi.conf<<EOF
100
+options snd-i2smic-rpi rpi_platform_generation=$PIMODEL_SELECT
101
+EOF
102
+fi
103
+
104
+# Enable I2S overlay
105
+sed -i -e 's/#dtparam=i2s/dtparam=i2s/g' /boot/config.txt
106
+
107
+# Done
108
+echo "DONE."
109
+echo
110
+echo "Settings take effect on next boot."
111
+echo
112
+echo -n "REBOOT NOW? [y/N] "
113
+read
114
+if [[ ! "$REPLY" =~ ^(yes|y|Y)$ ]]; then
115
+        echo "Exiting without reboot."
116
+        exit 0
117
+fi
118
+echo "Reboot started..."
119
+reboot
120
+exit 0

Loading…
Cancel
Save