Compare commits
232 commits
remove-for
...
v6.6-order
Author | SHA1 | Date | |
---|---|---|---|
|
c3f0119ae9 | ||
|
c693d203d9 | ||
|
005fc23648 | ||
|
58082f3fe8 | ||
|
cc37c8fb52 | ||
|
c3a2d96ba2 | ||
|
7aef82f3be | ||
|
4ab8158c18 | ||
|
8f377d1eaa | ||
|
aaa2090dbf | ||
|
f25e76508f | ||
|
a46c3f6324 | ||
|
2a40c7dbff | ||
|
f69370b841 | ||
|
a03624a0ce | ||
|
0bb3ca6c98 | ||
|
18e297d2d8 | ||
|
280bb390a2 | ||
|
19ca5aeb50 | ||
|
ebd1fa605c | ||
|
a57389693c | ||
|
977a7ff321 | ||
|
4d0e36d426 | ||
|
99bbf880e9 | ||
|
8dbe3726b7 | ||
|
e452172d8c | ||
|
a8ee041f21 | ||
|
6bf1dbd04e | ||
|
b093f59250 | ||
|
8fa56e18bb | ||
|
dd9391fb78 | ||
|
d840f77541 | ||
|
bd7623e9fb | ||
|
17e2875d4d | ||
|
b595b95b21 | ||
|
48dbb3f815 | ||
|
41a09a3b67 | ||
|
81e0f0879d | ||
|
d841b2a0fb | ||
|
f9427ea449 | ||
|
efa999f0f3 | ||
|
d688a02f14 | ||
|
a1a51f8aab | ||
|
31d750c981 | ||
|
c8d97904ce | ||
|
c5f3836dd8 | ||
|
19067f3333 | ||
|
5793cf6bf0 | ||
|
ffcdafb798 | ||
|
e553d4f851 | ||
|
de70691526 | ||
|
1774a54301 | ||
|
af484de3af | ||
|
9796ad49ff | ||
|
43b6034266 | ||
|
eab694c170 | ||
|
fdd67ea2c4 | ||
|
f8d47b5c64 | ||
|
47d09dba0e | ||
|
d692927067 | ||
|
14317817f8 | ||
|
3ba6aec5bb | ||
|
8b2094fc23 | ||
|
c84b644247 | ||
|
8e1c59be7e | ||
|
f289f5586e | ||
|
3ad10c131c | ||
|
cbb5e082f2 | ||
|
43532cfada | ||
|
eea6066d70 | ||
|
44d47226dc | ||
|
50dbe24b78 | ||
|
ebcf755c1a | ||
|
484c03d4c8 | ||
|
a79b7d94a5 | ||
|
87f42ed64d | ||
|
379f791b3c | ||
|
8cce4e8ffa | ||
|
ac2bf5f638 | ||
|
4b7559b320 | ||
|
526d0ddef9 | ||
|
6fb0c63581 | ||
|
06e054aa06 | ||
|
1a7fbee50e | ||
|
7e635f5d57 | ||
|
7461921407 | ||
|
794d7a3527 | ||
|
c206a43374 | ||
|
e0f9a554fc | ||
|
e85006b775 | ||
|
921ac8fba5 | ||
|
30ceb546fa | ||
|
e1110617b2 | ||
|
a891e0260e | ||
|
c1c2e5ca56 | ||
|
f1a46d63cc | ||
|
2e8586d547 | ||
|
ac1dddeaed | ||
|
6a30a3efc6 | ||
|
84247b0037 | ||
|
9bb3afb358 | ||
|
2baddde5ba | ||
|
b5def1af8e | ||
|
0abc6ed072 | ||
|
30216a9c7c | ||
|
6af23967a5 | ||
|
74620fbdbf | ||
|
4cec9e73df | ||
|
957b1298d5 | ||
|
901b451bd5 | ||
|
b83519eb82 | ||
|
1372794704 | ||
|
19cfed5bd7 | ||
|
6875869cb2 | ||
|
9285159a7d | ||
|
90144a2f2e | ||
|
cbd6da78fc | ||
|
cf98b67079 | ||
|
c4c112dcaf | ||
|
9722cb01e4 | ||
|
f4f303f9bd | ||
|
de23c61210 | ||
|
cca7bbfe2a | ||
|
5ca9ab45df | ||
|
8c25d81890 | ||
|
f47375e54d | ||
|
1f7323417b | ||
|
e82e6fde67 | ||
|
cd899a83d5 | ||
|
e750de0ecc | ||
|
efaa210d79 | ||
|
e6e5240922 | ||
|
8ea751c4e9 | ||
|
e2529f9eee | ||
|
6aff6e0b33 | ||
|
bb09e9d24b | ||
|
edddb2fbe4 | ||
|
655d7fe57b | ||
|
d64e994982 | ||
|
673305fc4e | ||
|
47d97e7bd5 | ||
|
955707d944 | ||
|
cf2a5fe807 | ||
|
471f88b337 | ||
|
d5b71a009d | ||
|
bccf557d62 | ||
|
a5095cd7b2 | ||
|
bcdc10e193 | ||
|
ebb9a9d82a | ||
|
783eff8779 | ||
|
ec5fc9d9b8 | ||
|
bb1422182b | ||
|
f2b2516426 | ||
|
e26006d40c | ||
|
138d22226e | ||
|
a24da444df | ||
|
c3adcde556 | ||
|
1452d85e0f | ||
|
329c8090ea | ||
|
53c0db449b | ||
|
89f8a76646 | ||
|
39c134f430 | ||
|
17944791bb | ||
|
df68ab22d6 | ||
|
88aae48c41 | ||
|
6bcd4cad2f | ||
|
7f88e11fd0 | ||
|
60e90d6fae | ||
|
5cefec4cca | ||
|
1f9c1464ab | ||
|
71f01070d8 | ||
|
19d1e6eb88 | ||
|
07dc49259a | ||
|
d8775ccb93 | ||
|
c3ddbb521d | ||
|
1456785779 | ||
|
02eccbcd55 | ||
|
131ee8187d | ||
|
ed615d2318 | ||
|
2cc009619e | ||
|
aaf0cc2c61 | ||
|
a6db04e724 | ||
|
0be1de9750 | ||
|
fcbc3b6d6b | ||
|
c2b419c286 | ||
|
ed094dece5 | ||
|
51966603da | ||
|
6afe18224a | ||
|
953fa50f4f | ||
|
4396e4f834 | ||
|
26754b0821 | ||
|
af8668ff97 | ||
|
2d08bb0b35 | ||
|
c2f81c1f23 | ||
|
63fa92db39 | ||
|
d2c0f1b5c9 | ||
|
775005d865 | ||
|
8c80018c3e | ||
|
076d12f7fb | ||
|
c0f1dfa8bb | ||
|
67f7942cfd | ||
|
86c198d7dc | ||
|
1d4abfa41d | ||
|
f52ed1b363 | ||
|
97146337cb | ||
|
1046e30108 | ||
|
97fd3f2eab | ||
|
60d2a5129d | ||
|
6b4133b5f0 | ||
|
0ed11aa9a4 | ||
|
2e1940bb0f | ||
|
6c6dfaa7d3 | ||
|
468b40eee5 | ||
|
07a6c4659e | ||
|
ad4d66d3f7 | ||
|
add12477e9 | ||
|
74d65bfcbd | ||
|
deed034f31 | ||
|
2563020e29 | ||
|
30276c80bc | ||
|
82c8d1024a | ||
|
476378c156 | ||
|
4c15036368 | ||
|
cb9bf1c913 | ||
|
37a37a6d16 | ||
|
de22f92298 | ||
|
72d3c9e2f6 | ||
|
b9272dcee8 | ||
|
61022875b3 | ||
|
41c71f1b45 | ||
|
8c5ffaeed3 | ||
|
920ef83b63 |
21 changed files with 1342 additions and 414 deletions
245
README.md
245
README.md
|
@ -1,231 +1,20 @@
|
||||||
# seeed-voicecard
|
# seeed-voicecard
|
||||||
|
|
||||||
[![Join the chat at https://gitter.im/seeed-voicecard/Lobby](https://badges.gitter.im/seeed-voicecard/Lobby.svg)](https://gitter.im/seeed-voicecard/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
The drivers for [ReSpeaker Mic Hat](https://www.seeedstudio.com/ReSpeaker-2-Mics-Pi-HAT-p-2874.html), [ReSpeaker 4 Mic Array](https://www.seeedstudio.com/ReSpeaker-4-Mic-Array-for-Raspberry-Pi-p-2941.html), [6-Mics Circular Array Kit](), and [4-Mics Linear Array Kit]() for Raspberry Pi.
|
||||||
|
|
||||||
The drivers of [ReSpeaker Mic Hat](https://www.seeedstudio.com/ReSpeaker-2-Mics-Pi-HAT-p-2874.html),[ReSpeaker 4 Mic Array](https://www.seeedstudio.com/ReSpeaker-4-Mic-Array-for-Raspberry-Pi-p-2941.html),[6-Mics Circular Array Kit](), and [4-Mics Linear Array Kit]() for Raspberry Pi.
|
|
||||||
|
|
||||||
### Install seeed-voicecard
|
### Install seeed-voicecard
|
||||||
Get the seeed voice card source code. and install all linux kernel drivers
|
Get the seeed voice card source code and install all linux kernel drivers
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/respeaker/seeed-voicecard
|
git clone https://github.com/HinTak/seeed-voicecard
|
||||||
cd seeed-voicecard
|
cd seeed-voicecard
|
||||||
sudo ./install.sh
|
sudo ./install.sh
|
||||||
sudo reboot
|
sudo reboot
|
||||||
```
|
```
|
||||||
|
## ReSpeaker Documentation
|
||||||
|
|
||||||
## ReSpeaker Mic Hat
|
Up to date documentation for reSpeaker products can be found in [Seeed Studio Wiki](https://wiki.seeedstudio.com/ReSpeaker/)!
|
||||||
|
![](https://files.seeedstudio.com/wiki/ReSpeakerProductGuide/img/Raspberry_Pi_Mic_Array_Solutions.png)
|
||||||
|
|
||||||
[![](https://github.com/SeeedDocument/MIC_HATv1.0_for_raspberrypi/blob/master/img/mic_hatv1.0.png?raw=true)](https://www.seeedstudio.com/ReSpeaker-2-Mics-Pi-HAT-p-2874.html)
|
|
||||||
|
|
||||||
While the upstream wm8960 codec is not currently supported by current Pi kernel builds, upstream wm8960 has some bugs, we had fixed it. we must it build manually.
|
|
||||||
|
|
||||||
Check that the sound card name matches the source code seeed-voicecard.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
#for ReSpeaker 2-mic
|
|
||||||
pi@raspberrypi:~/seeed-voicecard $ aplay -l
|
|
||||||
**** List of PLAYBACK Hardware Devices ****
|
|
||||||
card 0: ALSA [bcm2835 ALSA], device 0: bcm2835 ALSA [bcm2835 ALSA]
|
|
||||||
Subdevices: 8/8
|
|
||||||
Subdevice #0: subdevice #0
|
|
||||||
Subdevice #1: subdevice #1
|
|
||||||
Subdevice #2: subdevice #2
|
|
||||||
Subdevice #3: subdevice #3
|
|
||||||
Subdevice #4: subdevice #4
|
|
||||||
Subdevice #5: subdevice #5
|
|
||||||
Subdevice #6: subdevice #6
|
|
||||||
Subdevice #7: subdevice #7
|
|
||||||
card 0: ALSA [bcm2835 ALSA], device 1: bcm2835 ALSA [bcm2835 IEC958/HDMI]
|
|
||||||
Subdevices: 1/1
|
|
||||||
Subdevice #0: subdevice #0
|
|
||||||
card 1: seeed2micvoicec [seeed-2mic-voicecard], device 0: bcm2835-i2s-wm8960-hifi wm8960-hifi-0 []
|
|
||||||
Subdevices: 1/1
|
|
||||||
Subdevice #0: subdevice #0
|
|
||||||
pi@raspberrypi:~/seeed-voicecard $ arecord -l
|
|
||||||
**** List of CAPTURE Hardware Devices ****
|
|
||||||
card 1: seeed2micvoicec [seeed-2mic-voicecard], device 0: bcm2835-i2s-wm8960-hifi wm8960-hifi-0 []
|
|
||||||
Subdevices: 1/1
|
|
||||||
Subdevice #0: subdevice #0
|
|
||||||
pi@raspberrypi:~/seeed-voicecard $
|
|
||||||
```
|
|
||||||
If you want to change the alsa settings, You can use `sudo alsactl --file=/etc/voicecard/wm8960_asound.state store` to save it.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### Next step
|
|
||||||
Go to https://github.com/respeaker/mic_hat to build voice enabled projects with Google Assistant SDK or Alexa Voice Service.
|
|
||||||
|
|
||||||
## ReSpeaker 4 Mic Array
|
|
||||||
|
|
||||||
[![](https://github.com/SeeedDocument/ReSpeaker-4-Mic-Array-for-Raspberry-Pi/blob/master/img/features.png?raw=true)](https://www.seeedstudio.com/ReSpeaker-4-Mic-Array-for-Raspberry-Pi-p-2941.html)
|
|
||||||
|
|
||||||
The 4 Mic Array uses ac108 which includes 4 ADCs, we also write ac108 rapberry pi linux kernel driver.
|
|
||||||
|
|
||||||
Check that the sound card name matches the source code seeed-voicecard.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
#for ReSpeaker 4 Mic Array
|
|
||||||
pi@raspberrypi:~ $ arecord -L
|
|
||||||
null
|
|
||||||
Discard all samples (playback) or generate zero samples (capture)
|
|
||||||
playback
|
|
||||||
capture
|
|
||||||
dmixed
|
|
||||||
array
|
|
||||||
ac108
|
|
||||||
default:CARD=seeed4micvoicec
|
|
||||||
seeed-4mic-voicecard,
|
|
||||||
Default Audio Device
|
|
||||||
sysdefault:CARD=seeed4micvoicec
|
|
||||||
seeed-4mic-voicecard,
|
|
||||||
Default Audio Device
|
|
||||||
dmix:CARD=seeed4micvoicec,DEV=0
|
|
||||||
seeed-4mic-voicecard,
|
|
||||||
Direct sample mixing device
|
|
||||||
dsnoop:CARD=seeed4micvoicec,DEV=0
|
|
||||||
seeed-4mic-voicecard,
|
|
||||||
Direct sample snooping device
|
|
||||||
hw:CARD=seeed4micvoicec,DEV=0
|
|
||||||
seeed-4mic-voicecard,
|
|
||||||
Direct hardware device without any conversions
|
|
||||||
plughw:CARD=seeed4micvoicec,DEV=0
|
|
||||||
seeed-4mic-voicecard,
|
|
||||||
Hardware device with all software conversions
|
|
||||||
pi@raspberrypi:~ $
|
|
||||||
```
|
|
||||||
If you want to change the alsa settings, You can use `sudo alsactl --file=/etc/voicecard/ac108_asound.state store` to save it.
|
|
||||||
|
|
||||||
## 6-Mics Circular Array Kit
|
|
||||||
|
|
||||||
[![](https://user-images.githubusercontent.com/3901856/37268348-6adef768-2600-11e8-8861-588b1c3ea142.png)]()
|
|
||||||
|
|
||||||
The 6 Mics Circular Array Kit uses ac108 x 2 / ac101 x 1 / micphones x 6, includes 8 ADCs and 2 DACs.
|
|
||||||
|
|
||||||
The driver is implemented with 8 input channels & 8 output channels.
|
|
||||||
>**The first 6 input channel are MIC recording data,
|
|
||||||
the rest 2 input channel are echo channel of playback
|
|
||||||
The first 2 output channel are playing data, the rest 6 output channel are dummy**
|
|
||||||
|
|
||||||
|
|
||||||
Check that the sound card name matches the source code seeed-voicecard.
|
|
||||||
```bash
|
|
||||||
#for 6 Mic Circular Array
|
|
||||||
pi@raspberrypi:~ $ arecord -L
|
|
||||||
null
|
|
||||||
Discard all samples (playback) or generate zero samples (capture)
|
|
||||||
default
|
|
||||||
playback
|
|
||||||
dmixed
|
|
||||||
ac108
|
|
||||||
multiapps
|
|
||||||
ac101
|
|
||||||
sysdefault:CARD=seeed8micvoicec
|
|
||||||
seeed-8mic-voicecard,
|
|
||||||
Default Audio Device
|
|
||||||
dmix:CARD=seeed8micvoicec,DEV=0
|
|
||||||
seeed-8mic-voicecard,
|
|
||||||
Direct sample mixing device
|
|
||||||
dsnoop:CARD=seeed8micvoicec,DEV=0
|
|
||||||
seeed-8mic-voicecard,
|
|
||||||
Direct sample snooping device
|
|
||||||
hw:CARD=seeed8micvoicec,DEV=0
|
|
||||||
seeed-8mic-voicecard,
|
|
||||||
Direct hardware device without any conversions
|
|
||||||
plughw:CARD=seeed8micvoicec,DEV=0
|
|
||||||
seeed-8mic-voicecard,
|
|
||||||
Hardware device with all software conversions
|
|
||||||
|
|
||||||
pi@raspberrypi:~ $ aplay -L
|
|
||||||
null
|
|
||||||
Discard all samples (playback) or generate zero samples (capture)
|
|
||||||
default
|
|
||||||
playback
|
|
||||||
dmixed
|
|
||||||
ac108
|
|
||||||
multiapps
|
|
||||||
ac101
|
|
||||||
sysdefault:CARD=ALSA
|
|
||||||
bcm2835 ALSA, bcm2835 ALSA
|
|
||||||
Default Audio Device
|
|
||||||
dmix:CARD=ALSA,DEV=0
|
|
||||||
bcm2835 ALSA, bcm2835 ALSA
|
|
||||||
Direct sample mixing device
|
|
||||||
dmix:CARD=ALSA,DEV=1
|
|
||||||
bcm2835 ALSA, bcm2835 IEC958/HDMI
|
|
||||||
Direct sample mixing device
|
|
||||||
dsnoop:CARD=ALSA,DEV=0
|
|
||||||
bcm2835 ALSA, bcm2835 ALSA
|
|
||||||
Direct sample snooping device
|
|
||||||
dsnoop:CARD=ALSA,DEV=1
|
|
||||||
bcm2835 ALSA, bcm2835 IEC958/HDMI
|
|
||||||
Direct sample snooping device
|
|
||||||
hw:CARD=ALSA,DEV=0
|
|
||||||
bcm2835 ALSA, bcm2835 ALSA
|
|
||||||
Direct hardware device without any conversions
|
|
||||||
hw:CARD=ALSA,DEV=1
|
|
||||||
bcm2835 ALSA, bcm2835 IEC958/HDMI
|
|
||||||
Direct hardware device without any conversions
|
|
||||||
plughw:CARD=ALSA,DEV=0
|
|
||||||
bcm2835 ALSA, bcm2835 ALSA
|
|
||||||
Hardware device with all software conversions
|
|
||||||
plughw:CARD=ALSA,DEV=1
|
|
||||||
bcm2835 ALSA, bcm2835 IEC958/HDMI
|
|
||||||
Hardware device with all software conversions
|
|
||||||
sysdefault:CARD=seeed8micvoicec
|
|
||||||
seeed-8mic-voicecard,
|
|
||||||
Default Audio Device
|
|
||||||
dmix:CARD=seeed8micvoicec,DEV=0
|
|
||||||
seeed-8mic-voicecard,
|
|
||||||
Direct sample mixing device
|
|
||||||
dsnoop:CARD=seeed8micvoicec,DEV=0
|
|
||||||
seeed-8mic-voicecard,
|
|
||||||
Direct sample snooping device
|
|
||||||
hw:CARD=seeed8micvoicec,DEV=0
|
|
||||||
seeed-8mic-voicecard,
|
|
||||||
Direct hardware device without any conversions
|
|
||||||
plughw:CARD=seeed8micvoicec,DEV=0
|
|
||||||
seeed-8mic-voicecard,
|
|
||||||
Hardware device with all software conversions
|
|
||||||
```
|
|
||||||
|
|
||||||
## 4-Mics Linear Array Kit
|
|
||||||
|
|
||||||
[![](https://user-images.githubusercontent.com/3901856/37194106-a0ccebce-23a7-11e8-88c5-ec611e44ec49.png)]()
|
|
||||||
|
|
||||||
In contrast to 6-Mics Circular Array Kit for Raspberry Pi,
|
|
||||||
the difference is only first 4 input channels are valid capture data.
|
|
||||||
|
|
||||||
### Usage:
|
|
||||||
```bash
|
|
||||||
#for ReSpeaker 2-mic
|
|
||||||
#It will capture sound an playback on hw:1
|
|
||||||
arecord -f cd -Dhw:1 | aplay -Dhw:1
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
|
||||||
#for ReSpeaker 4-mic
|
|
||||||
#It will capture sound on AC108 and save as a.wav
|
|
||||||
arecord -Dac108 -f S32_LE -r 16000 -c 4 a.wav
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
|
||||||
#for 6-Mics Circular Array Kit and 4-Mics Linear Array Kit
|
|
||||||
#It will capture sound on AC108 and save as a.wav
|
|
||||||
arecord -Dac108 -f S32_LE -r 16000 -c 8 a.wav
|
|
||||||
#Take care of that the captured mic audio is on the first 6 channels
|
|
||||||
|
|
||||||
#It will play a mono channel sound file mono_to_play.wav
|
|
||||||
#The file to play must be mono channel or else the speaker output nothing.
|
|
||||||
aplay -D plughw:1,0 mono_to_play.wav
|
|
||||||
|
|
||||||
#Doing capture && playback the same time
|
|
||||||
arecord -D hw:1,0 -f S32_LE -r 16000 -c 8 to_be_record.wav &
|
|
||||||
#mono_to_play.wav is a mono channel wave file to play
|
|
||||||
aplay -D plughw:1,0 -r 16000 mono_to_play.wav
|
|
||||||
```
|
|
||||||
**Note: Limit for developer using 6-Mics Circular Array Kit(or 4-Mics Linear Array Kit) doing capture & playback the same time:
|
|
||||||
1. capture must be start first, or else the capture channels will possibly be disorder.
|
|
||||||
2. playback output channels must fill with 8 same channels data or 4 same stereo channels data, or else the speaker or headphone will output nothing possibly.**
|
|
||||||
|
|
||||||
### Coherence
|
### Coherence
|
||||||
|
|
||||||
|
@ -255,13 +44,21 @@ Thank you!
|
||||||
------------------------------------------------------
|
------------------------------------------------------
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Enjoy !
|
Enjoy !
|
||||||
|
|
||||||
### FAQ
|
### Technical support
|
||||||
|
|
||||||
|
For hardware testing purposes we made a Rasperry Pi OS 5.10.17-v7l+ 32-bit image with reSpeaker drivers pre-installed, which you can download by clicking on [this link](https://files.seeedstudio.com/linux/Raspberry%20Pi%204%20reSpeaker/2021-05-07-raspios-buster-armhf-lite-respeaker.img.xz).
|
||||||
|
|
||||||
|
We provide official support for using reSpeaker with the following OS:
|
||||||
|
- 32-bit Raspberry Pi OS
|
||||||
|
- 64-bit Raspberry Pi OS
|
||||||
|
|
||||||
|
And following hardware platforms:
|
||||||
|
- Raspberry Pi 3 (all models), Raspberry Pi 4 (all models)
|
||||||
|
|
||||||
|
Anything beyond the scope of official support is considered to be community supported. Support for other OS/hardware platforms can be added, provided MOQ requirements can be met.
|
||||||
|
|
||||||
|
If you have a technical problem when using reSpeaker with one of the officially supported platforms/OS, feel free to create an issue on Github. For general questions or suggestions, please use [Seeed forum](https://forum.seeedstudio.com/c/products/respeaker/15).
|
||||||
|
|
||||||
When you encounter any installation and use problems when you start your ReSpeaker Pi hat, please use the following image for testing. We have installed seeed-voicecard based on the latest PI image, which can be used by burning it directly on SD. If this still cannot solve your problem, you can ask in the issue. We will try our best to solve your problem.
|
|
||||||
|
|
||||||
<p style="text-align:center"><a href="https://v2.fangcloud.com/share/7395fd138a1cab496fd4792fe5" target="_blank"><img src="https://github.com/SeeedDocument/Respeaker_V2/raw/master/img/efangyun.png" width="200" height="40" border=0 /></a></p>
|
|
||||||
|
|
32
ac101.c
32
ac101.c
|
@ -376,7 +376,7 @@ static int ac101_switch_probe(struct ac10x_priv *ac10x) {
|
||||||
|
|
||||||
ac10x->irq = gpiod_to_irq(ac10x->gpiod_irq);
|
ac10x->irq = gpiod_to_irq(ac10x->gpiod_irq);
|
||||||
if (IS_ERR_VALUE(ac10x->irq)) {
|
if (IS_ERR_VALUE(ac10x->irq)) {
|
||||||
pr_info("[ac101] map gpio to irq failed, errno = %ld\n", ac10x->irq);
|
pr_warn("[ac101] map gpio to irq failed, errno = %ld\n", ac10x->irq);
|
||||||
ac10x->irq = 0;
|
ac10x->irq = 0;
|
||||||
goto _err_irq;
|
goto _err_irq;
|
||||||
}
|
}
|
||||||
|
@ -384,7 +384,7 @@ static int ac101_switch_probe(struct ac10x_priv *ac10x) {
|
||||||
/* request irq, set irq type to falling edge trigger */
|
/* request irq, set irq type to falling edge trigger */
|
||||||
ret = devm_request_irq(ac10x->codec->dev, ac10x->irq, audio_hmic_irq, IRQF_TRIGGER_FALLING, "SWTICH_EINT", ac10x);
|
ret = devm_request_irq(ac10x->codec->dev, ac10x->irq, audio_hmic_irq, IRQF_TRIGGER_FALLING, "SWTICH_EINT", ac10x);
|
||||||
if (IS_ERR_VALUE(ret)) {
|
if (IS_ERR_VALUE(ret)) {
|
||||||
pr_info("[ac101] request virq %ld failed, errno = %ld\n", ac10x->irq, ret);
|
pr_warn("[ac101] request virq %ld failed, errno = %ld\n", ac10x->irq, ret);
|
||||||
goto _err_irq;
|
goto _err_irq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -782,8 +782,8 @@ static struct snd_kcontrol_new ac101_controls[] = {
|
||||||
SOC_DOUBLE_TLV("DAC volume", DAC_VOL_CTRL, DAC_VOL_L, DAC_VOL_R, 0xff, 0, dac_vol_tlv),
|
SOC_DOUBLE_TLV("DAC volume", DAC_VOL_CTRL, DAC_VOL_L, DAC_VOL_R, 0xff, 0, dac_vol_tlv),
|
||||||
SOC_DOUBLE_TLV("DAC mixer gain", DAC_MXR_GAIN, DACL_MXR_GAIN, DACR_MXR_GAIN, 0xf, 0, dac_mix_vol_tlv),
|
SOC_DOUBLE_TLV("DAC mixer gain", DAC_MXR_GAIN, DACL_MXR_GAIN, DACR_MXR_GAIN, 0xf, 0, dac_mix_vol_tlv),
|
||||||
SOC_SINGLE_TLV("digital volume", DAC_DBG_CTRL, DVC, 0x3f, 1, dig_vol_tlv),
|
SOC_SINGLE_TLV("digital volume", DAC_DBG_CTRL, DVC, 0x3f, 1, dig_vol_tlv),
|
||||||
SOC_SINGLE_TLV("speaker volume", SPKOUT_CTRL, SPK_VOL, 0x1f, 0, speaker_vol_tlv),
|
SOC_SINGLE_TLV("Speaker Playback Volume", SPKOUT_CTRL, SPK_VOL, 0x1f, 0, speaker_vol_tlv),
|
||||||
SOC_SINGLE_TLV("headphone volume", HPOUT_CTRL, HP_VOL, 0x3f, 0, headphone_vol_tlv),
|
SOC_SINGLE_TLV("Headphone Playback Volume", HPOUT_CTRL, HP_VOL, 0x3f, 0, headphone_vol_tlv),
|
||||||
};
|
};
|
||||||
|
|
||||||
/* PLL divisors */
|
/* PLL divisors */
|
||||||
|
@ -955,10 +955,10 @@ void ac101_aif_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai
|
||||||
|
|
||||||
AC101_DBG("stream = %s, play: %d, capt: %d, active: %d\n",
|
AC101_DBG("stream = %s, play: %d, capt: %d, active: %d\n",
|
||||||
snd_pcm_stream_str(substream),
|
snd_pcm_stream_str(substream),
|
||||||
codec_dai->playback_active, codec_dai->capture_active,
|
codec_dai->stream[SNDRV_PCM_STREAM_PLAYBACK].active, codec_dai->stream[SNDRV_PCM_STREAM_CAPTURE].active,
|
||||||
codec_dai->active);
|
snd_soc_dai_active(codec_dai));
|
||||||
|
|
||||||
if (!codec_dai->active) {
|
if (!snd_soc_dai_active(codec_dai)) {
|
||||||
ac10x->aif1_clken = 1;
|
ac10x->aif1_clken = 1;
|
||||||
ac101_aif1clk(codec, SND_SOC_DAPM_POST_PMD, 0);
|
ac101_aif1clk(codec, SND_SOC_DAPM_POST_PMD, 0);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1080,7 +1080,7 @@ int ac101_hw_params(struct snd_pcm_substream *substream,
|
||||||
freq_out = _FREQ_24_576K;
|
freq_out = _FREQ_24_576K;
|
||||||
for (i = 0; i < ARRAY_SIZE(codec_aif1_fs); i++) {
|
for (i = 0; i < ARRAY_SIZE(codec_aif1_fs); i++) {
|
||||||
if (codec_aif1_fs[i].samp_rate == params_rate(params)) {
|
if (codec_aif1_fs[i].samp_rate == params_rate(params)) {
|
||||||
if (codec_dai->capture_active && dmic_used && codec_aif1_fs[i].samp_rate == 44100) {
|
if (codec_dai->stream[SNDRV_PCM_STREAM_CAPTURE].active && dmic_used && codec_aif1_fs[i].samp_rate == 44100) {
|
||||||
ac101_update_bits(codec, AIF_SR_CTRL, (0xf<<AIF1_FS), (0x4<<AIF1_FS));
|
ac101_update_bits(codec, AIF_SR_CTRL, (0xf<<AIF1_FS), (0x4<<AIF1_FS));
|
||||||
} else {
|
} else {
|
||||||
ac101_update_bits(codec, AIF_SR_CTRL, (0xf<<AIF1_FS), ((codec_aif1_fs[i].srbit)<<AIF1_FS));
|
ac101_update_bits(codec, AIF_SR_CTRL, (0xf<<AIF1_FS), ((codec_aif1_fs[i].srbit)<<AIF1_FS));
|
||||||
|
@ -1152,14 +1152,14 @@ int ac101_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
|
||||||
switch(fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
switch(fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||||
case SND_SOC_DAIFMT_CBM_CFM: /* codec clk & frm master, ap is slave*/
|
case SND_SOC_DAIFMT_CBM_CFM: /* codec clk & frm master, ap is slave*/
|
||||||
#if _MASTER_MULTI_CODEC == _MASTER_AC101
|
#if _MASTER_MULTI_CODEC == _MASTER_AC101
|
||||||
pr_warn("AC101 as Master\n");
|
pr_info("AC101 as Master\n");
|
||||||
reg_val |= (0x0<<AIF1_MSTR_MOD);
|
reg_val |= (0x0<<AIF1_MSTR_MOD);
|
||||||
break;
|
break;
|
||||||
#else
|
#else
|
||||||
pr_warn("AC108 as Master\n");
|
pr_info("AC108 as Master\n");
|
||||||
#endif
|
#endif
|
||||||
case SND_SOC_DAIFMT_CBS_CFS: /* codec clk & frm slave, ap is master*/
|
case SND_SOC_DAIFMT_CBS_CFS: /* codec clk & frm slave, ap is master*/
|
||||||
pr_warn("AC101 as Slave\n");
|
pr_info("AC101 as Slave\n");
|
||||||
reg_val |= (0x1<<AIF1_MSTR_MOD);
|
reg_val |= (0x1<<AIF1_MSTR_MOD);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -1237,7 +1237,7 @@ int ac101_audio_startup(struct snd_pcm_substream *substream,
|
||||||
}
|
}
|
||||||
|
|
||||||
#if _MASTER_MULTI_CODEC == _MASTER_AC101
|
#if _MASTER_MULTI_CODEC == _MASTER_AC101
|
||||||
static int ac101_set_clock(int y_start_n_stop) {
|
static int ac101_set_clock(int y_start_n_stop, struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (y_start_n_stop) {
|
if (y_start_n_stop) {
|
||||||
|
@ -1258,6 +1258,7 @@ int ac101_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||||
struct snd_soc_codec *codec = dai->codec;
|
struct snd_soc_codec *codec = dai->codec;
|
||||||
struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
|
struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
AC101_DBG("stream=%s cmd=%d\n",
|
AC101_DBG("stream=%s cmd=%d\n",
|
||||||
snd_pcm_stream_str(substream),
|
snd_pcm_stream_str(substream),
|
||||||
|
@ -1268,6 +1269,7 @@ int ac101_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||||
case SNDRV_PCM_TRIGGER_RESUME:
|
case SNDRV_PCM_TRIGGER_RESUME:
|
||||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||||
#if _MASTER_MULTI_CODEC == _MASTER_AC101
|
#if _MASTER_MULTI_CODEC == _MASTER_AC101
|
||||||
|
spin_lock_irqsave(&ac10x->lock, flags);
|
||||||
if (ac10x->aif1_clken == 0){
|
if (ac10x->aif1_clken == 0){
|
||||||
/*
|
/*
|
||||||
* enable aif1clk, it' here due to reduce time between 'AC108 Sysclk Enable' and 'AC101 Sysclk Enable'
|
* enable aif1clk, it' here due to reduce time between 'AC108 Sysclk Enable' and 'AC101 Sysclk Enable'
|
||||||
|
@ -1277,15 +1279,21 @@ int ac101_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||||
ret = ret || ac101_update_bits(codec, MOD_CLK_ENA, (0x1<<MOD_CLK_AIF1), (0x1<<MOD_CLK_AIF1));
|
ret = ret || ac101_update_bits(codec, MOD_CLK_ENA, (0x1<<MOD_CLK_AIF1), (0x1<<MOD_CLK_AIF1));
|
||||||
ret = ret || ac101_update_bits(codec, MOD_RST_CTRL, (0x1<<MOD_RESET_AIF1), (0x1<<MOD_RESET_AIF1));
|
ret = ret || ac101_update_bits(codec, MOD_RST_CTRL, (0x1<<MOD_RESET_AIF1), (0x1<<MOD_RESET_AIF1));
|
||||||
}
|
}
|
||||||
|
spin_unlock_irqrestore(&ac10x->lock, flags);
|
||||||
|
ac101_set_clock(1, substream, cmd, dai);
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
case SNDRV_PCM_TRIGGER_STOP:
|
case SNDRV_PCM_TRIGGER_STOP:
|
||||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||||
|
ac101_set_clock(0, NULL, 0, NULL);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
}
|
}
|
||||||
|
AC101_DBG("stream=%s cmd=%d;finished %d\n",
|
||||||
|
snd_pcm_stream_str(substream),
|
||||||
|
cmd, ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
78
ac108.c
78
ac108.c
|
@ -653,7 +653,7 @@ static int ac108_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_h
|
||||||
|
|
||||||
dev_dbg(dai->dev, "%s() stream=%s play:%d capt:%d +++\n", __func__,
|
dev_dbg(dai->dev, "%s() stream=%s play:%d capt:%d +++\n", __func__,
|
||||||
snd_pcm_stream_str(substream),
|
snd_pcm_stream_str(substream),
|
||||||
dai->playback_active, dai->capture_active);
|
dai->stream[SNDRV_PCM_STREAM_PLAYBACK].active, dai->stream[SNDRV_PCM_STREAM_CAPTURE].active);
|
||||||
|
|
||||||
if (ac10x->i2c101) {
|
if (ac10x->i2c101) {
|
||||||
ret = ac101_hw_params(substream, params, dai);
|
ret = ac101_hw_params(substream, params, dai);
|
||||||
|
@ -664,8 +664,8 @@ static int ac108_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_h
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE && dai->playback_active)
|
if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE && dai->stream[SNDRV_PCM_STREAM_PLAYBACK].active)
|
||||||
|| (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && dai->capture_active)) {
|
|| (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && dai->stream[SNDRV_PCM_STREAM_CAPTURE].active)) {
|
||||||
/* not configure hw_param twice */
|
/* not configure hw_param twice */
|
||||||
/* return 0; */
|
/* return 0; */
|
||||||
}
|
}
|
||||||
|
@ -810,6 +810,9 @@ static int ac108_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int fr
|
||||||
|
|
||||||
struct ac10x_priv *ac10x = snd_soc_dai_get_drvdata(dai);
|
struct ac10x_priv *ac10x = snd_soc_dai_get_drvdata(dai);
|
||||||
|
|
||||||
|
if (freq != 24000000 || clk_id != SYSCLK_SRC_PLL)
|
||||||
|
dev_warn(dai->dev, "ac108_set_sysclk freq = %d clk = %d\n", freq, clk_id);
|
||||||
|
|
||||||
freq = 24000000;
|
freq = 24000000;
|
||||||
clk_id = SYSCLK_SRC_PLL;
|
clk_id = SYSCLK_SRC_PLL;
|
||||||
|
|
||||||
|
@ -865,6 +868,7 @@ static int ac108_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) {
|
||||||
/* TODO: Both cpu_dai and codec_dai(AC108) be set as slave in DTS */
|
/* TODO: Both cpu_dai and codec_dai(AC108) be set as slave in DTS */
|
||||||
dev_dbg(dai->dev, "used as slave when AC101 is master\n");
|
dev_dbg(dai->dev, "used as slave when AC101 is master\n");
|
||||||
}
|
}
|
||||||
|
fallthrough;
|
||||||
case SND_SOC_DAIFMT_CBS_CFS: /*AC108 Slave*/
|
case SND_SOC_DAIFMT_CBS_CFS: /*AC108 Slave*/
|
||||||
dev_dbg(dai->dev, "AC108 set to work as Slave\n");
|
dev_dbg(dai->dev, "AC108 set to work as Slave\n");
|
||||||
/**
|
/**
|
||||||
|
@ -987,7 +991,7 @@ static int ac108_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) {
|
||||||
/*
|
/*
|
||||||
* due to miss channels order in cpu_dai, we meed defer the clock starting.
|
* due to miss channels order in cpu_dai, we meed defer the clock starting.
|
||||||
*/
|
*/
|
||||||
static int ac108_set_clock(int y_start_n_stop) {
|
static int ac108_set_clock(int y_start_n_stop, struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) {
|
||||||
u8 reg;
|
u8 reg;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
|
@ -995,6 +999,9 @@ static int ac108_set_clock(int y_start_n_stop) {
|
||||||
|
|
||||||
/* spin_lock move to machine trigger */
|
/* spin_lock move to machine trigger */
|
||||||
|
|
||||||
|
if (ac10x->i2c101 && _MASTER_MULTI_CODEC == _MASTER_AC101) {
|
||||||
|
ac101_trigger(substream, cmd, dai);
|
||||||
|
}
|
||||||
if (y_start_n_stop && ac10x->sysclk_en == 0) {
|
if (y_start_n_stop && ac10x->sysclk_en == 0) {
|
||||||
/* enable lrck clock */
|
/* enable lrck clock */
|
||||||
ac10x_read(I2S_CTRL, ®, ac10x->i2cmap[_MASTER_INDEX]);
|
ac10x_read(I2S_CTRL, ®, ac10x->i2cmap[_MASTER_INDEX]);
|
||||||
|
@ -1054,39 +1061,33 @@ static int ac108_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||||
snd_pcm_stream_str(substream),
|
snd_pcm_stream_str(substream),
|
||||||
cmd);
|
cmd);
|
||||||
|
|
||||||
spin_lock_irqsave(&ac10x->lock, flags);
|
|
||||||
|
|
||||||
if (ac10x->i2c101 && _MASTER_MULTI_CODEC == _MASTER_AC101) {
|
|
||||||
ac101_trigger(substream, cmd, dai);
|
|
||||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
|
||||||
goto __ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case SNDRV_PCM_TRIGGER_START:
|
case SNDRV_PCM_TRIGGER_START:
|
||||||
case SNDRV_PCM_TRIGGER_RESUME:
|
case SNDRV_PCM_TRIGGER_RESUME:
|
||||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||||
|
spin_lock_irqsave(&ac10x->lock, flags);
|
||||||
/* disable global clock if lrck disabled */
|
/* disable global clock if lrck disabled */
|
||||||
ac10x_read(I2S_CTRL, &r, ac10x->i2cmap[_MASTER_INDEX]);
|
ac10x_read(I2S_CTRL, &r, ac10x->i2cmap[_MASTER_INDEX]);
|
||||||
if ((r & (0x01 << BCLK_IOEN)) && (r & (0x01 << LRCK_IOEN)) == 0) {
|
if ((r & (0x01 << BCLK_IOEN)) && (r & (0x01 << LRCK_IOEN)) == 0) {
|
||||||
/* disable global clock */
|
/* disable global clock */
|
||||||
ac108_multi_update_bits(I2S_CTRL, 0x1 << TXEN | 0x1 << GEN, 0x0 << TXEN | 0x0 << GEN, ac10x);
|
ac108_multi_update_bits(I2S_CTRL, 0x1 << TXEN | 0x1 << GEN, 0x0 << TXEN | 0x0 << GEN, ac10x);
|
||||||
}
|
}
|
||||||
|
spin_unlock_irqrestore(&ac10x->lock, flags);
|
||||||
/* delayed clock starting, move to machine trigger() */
|
ac108_set_clock(1, substream, cmd, dai);
|
||||||
break;
|
break;
|
||||||
case SNDRV_PCM_TRIGGER_STOP:
|
case SNDRV_PCM_TRIGGER_STOP:
|
||||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||||
|
ac108_set_clock(0, substream, cmd, dai);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
__ret:
|
dev_dbg(dai->dev, "%s() stream=%s cmd=%d; finished %d\n",
|
||||||
spin_unlock_irqrestore(&ac10x->lock, flags);
|
__FUNCTION__,
|
||||||
|
snd_pcm_stream_str(substream),
|
||||||
|
cmd, ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1120,7 +1121,7 @@ void ac108_aif_shutdown(struct snd_pcm_substream *substream,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int ac108_aif_mute(struct snd_soc_dai *dai, int mute) {
|
int ac108_aif_mute(struct snd_soc_dai *dai, int mute, int direction) {
|
||||||
struct snd_soc_codec *codec = dai->codec;
|
struct snd_soc_codec *codec = dai->codec;
|
||||||
struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
|
struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
|
||||||
|
|
||||||
|
@ -1141,12 +1142,13 @@ static const struct snd_soc_dai_ops ac108_dai_ops = {
|
||||||
.hw_params = ac108_hw_params,
|
.hw_params = ac108_hw_params,
|
||||||
.prepare = ac108_prepare,
|
.prepare = ac108_prepare,
|
||||||
.trigger = ac108_trigger,
|
.trigger = ac108_trigger,
|
||||||
.digital_mute = ac108_aif_mute,
|
.mute_stream = ac108_aif_mute,
|
||||||
|
|
||||||
/*DAI format configuration*/
|
/*DAI format configuration*/
|
||||||
.set_fmt = ac108_set_fmt,
|
.set_fmt = ac108_set_fmt,
|
||||||
|
|
||||||
// .hw_free = ac108_hw_free,
|
// .hw_free = ac108_hw_free,
|
||||||
|
.no_capture_mute = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct snd_soc_dai_driver ac108_dai0 = {
|
static struct snd_soc_dai_driver ac108_dai0 = {
|
||||||
|
@ -1320,6 +1322,11 @@ static struct snd_soc_codec_driver ac10x_soc_codec_driver = {
|
||||||
.set_bias_level = ac108_set_bias_level,
|
.set_bias_level = ac108_set_bias_level,
|
||||||
.read = ac108_codec_read,
|
.read = ac108_codec_read,
|
||||||
.write = ac108_codec_write,
|
.write = ac108_codec_write,
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,17,0)
|
||||||
|
.idle_bias_on = 1,
|
||||||
|
.use_pmdown_time = 1,
|
||||||
|
.endianness = 1,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static ssize_t ac108_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) {
|
static ssize_t ac108_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) {
|
||||||
|
@ -1400,7 +1407,15 @@ static const struct regmap_config ac108_regmap = {
|
||||||
.max_register = 0xDF,
|
.max_register = 0xDF,
|
||||||
.cache_type = REGCACHE_FLAT,
|
.cache_type = REGCACHE_FLAT,
|
||||||
};
|
};
|
||||||
static int ac108_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *i2c_id) {
|
static const struct i2c_device_id ac108_i2c_id[] = {
|
||||||
|
{ "ac108_0", 0 },
|
||||||
|
{ "ac108_1", 1 },
|
||||||
|
{ "ac108_2", 2 },
|
||||||
|
{ "ac108_3", 3 },
|
||||||
|
{ "ac101", AC101_I2C_ID },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
static int ac108_i2c_probe(struct i2c_client *i2c) {
|
||||||
struct device_node *np = i2c->dev.of_node;
|
struct device_node *np = i2c->dev.of_node;
|
||||||
unsigned int val = 0;
|
unsigned int val = 0;
|
||||||
int ret = 0, index;
|
int ret = 0, index;
|
||||||
|
@ -1413,11 +1428,11 @@ static int ac108_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
index = (int)i2c_id->driver_data;
|
index = (int)i2c_match_id(ac108_i2c_id, i2c)->driver_data;
|
||||||
if (index == AC101_I2C_ID) {
|
if (index == AC101_I2C_ID) {
|
||||||
ac10x->i2c101 = i2c;
|
ac10x->i2c101 = i2c;
|
||||||
i2c_set_clientdata(i2c, ac10x);
|
i2c_set_clientdata(i2c, ac10x);
|
||||||
ret = ac101_probe(i2c, i2c_id);
|
ret = ac101_probe(i2c, i2c_match_id(ac108_i2c_id, i2c));
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ac10x->i2c101 = NULL;
|
ac10x->i2c101 = NULL;
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1435,8 +1450,8 @@ static int ac108_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *i
|
||||||
if (of_property_read_u32(np, "tdm-chips-count", &val)) val = 1;
|
if (of_property_read_u32(np, "tdm-chips-count", &val)) val = 1;
|
||||||
ac10x->tdm_chips_cnt = val;
|
ac10x->tdm_chips_cnt = val;
|
||||||
|
|
||||||
pr_err(" ac10x i2c_id number: %d\n", index);
|
pr_info(" ac10x i2c_id number: %d\n", index);
|
||||||
pr_err(" ac10x data protocol: %d\n", ac10x->data_protocol);
|
pr_info(" ac10x data protocol: %d\n", ac10x->data_protocol);
|
||||||
|
|
||||||
ac10x->i2c[index] = i2c;
|
ac10x->i2c[index] = i2c;
|
||||||
ac10x->i2cmap[index] = devm_regmap_init_i2c(i2c, &ac108_regmap);
|
ac10x->i2cmap[index] = devm_regmap_init_i2c(i2c, &ac108_regmap);
|
||||||
|
@ -1458,7 +1473,7 @@ static int ac108_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *i
|
||||||
ac10x_fill_regcache(&i2c->dev, ac10x->i2cmap[index]);
|
ac10x_fill_regcache(&i2c->dev, ac10x->i2cmap[index]);
|
||||||
|
|
||||||
ac10x->codec_cnt++;
|
ac10x->codec_cnt++;
|
||||||
pr_err(" ac10x codec count : %d\n", ac10x->codec_cnt);
|
pr_info(" ac10x codec count : %d\n", ac10x->codec_cnt);
|
||||||
|
|
||||||
ret = sysfs_create_group(&i2c->dev.kobj, &ac108_debug_attr_group);
|
ret = sysfs_create_group(&i2c->dev.kobj, &ac108_debug_attr_group);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
@ -1483,7 +1498,7 @@ __ret:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ac108_i2c_remove(struct i2c_client *i2c) {
|
static void ac108_i2c_remove(struct i2c_client *i2c) {
|
||||||
if (ac10x->codec != NULL) {
|
if (ac10x->codec != NULL) {
|
||||||
snd_soc_unregister_codec(&ac10x->i2c[_MASTER_INDEX]->dev);
|
snd_soc_unregister_codec(&ac10x->i2c[_MASTER_INDEX]->dev);
|
||||||
ac10x->codec = NULL;
|
ac10x->codec = NULL;
|
||||||
|
@ -1508,17 +1523,8 @@ __ret:
|
||||||
kfree(ac10x);
|
kfree(ac10x);
|
||||||
ac10x = NULL;
|
ac10x = NULL;
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct i2c_device_id ac108_i2c_id[] = {
|
|
||||||
{ "ac108_0", 0 },
|
|
||||||
{ "ac108_1", 1 },
|
|
||||||
{ "ac108_2", 2 },
|
|
||||||
{ "ac108_3", 3 },
|
|
||||||
{ "ac101", AC101_I2C_ID },
|
|
||||||
{ }
|
|
||||||
};
|
|
||||||
MODULE_DEVICE_TABLE(i2c, ac108_i2c_id);
|
MODULE_DEVICE_TABLE(i2c, ac108_i2c_id);
|
||||||
|
|
||||||
static const struct of_device_id ac108_of_match[] = {
|
static const struct of_device_id ac108_of_match[] = {
|
||||||
|
|
|
@ -338,7 +338,7 @@ state.seeed8micvoicec {
|
||||||
}
|
}
|
||||||
control.20 {
|
control.20 {
|
||||||
iface MIXER
|
iface MIXER
|
||||||
name 'speaker volume'
|
name 'Speaker Playback Volume'
|
||||||
value 25
|
value 25
|
||||||
comment {
|
comment {
|
||||||
access 'read write'
|
access 'read write'
|
||||||
|
@ -352,7 +352,7 @@ state.seeed8micvoicec {
|
||||||
}
|
}
|
||||||
control.21 {
|
control.21 {
|
||||||
iface MIXER
|
iface MIXER
|
||||||
name 'headphone volume'
|
name 'Headphone Playback Volume'
|
||||||
value 52
|
value 52
|
||||||
comment {
|
comment {
|
||||||
access 'read write'
|
access 'read write'
|
||||||
|
|
2
ac10x.h
2
ac10x.h
|
@ -119,7 +119,7 @@ void ac101_shutdown(struct i2c_client *i2c);
|
||||||
int ac101_remove(struct i2c_client *i2c);
|
int ac101_remove(struct i2c_client *i2c);
|
||||||
|
|
||||||
/* seeed voice card export */
|
/* seeed voice card export */
|
||||||
int seeed_voice_card_register_set_clock(int stream, int (*set_clock)(int));
|
int seeed_voice_card_register_set_clock(int stream, int (*set_clock)(int, struct snd_pcm_substream *, int, struct snd_soc_dai *));
|
||||||
|
|
||||||
int ac10x_fill_regcache(struct device* dev, struct regmap* map);
|
int ac10x_fill_regcache(struct device* dev, struct regmap* map);
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#!/bin/sh
|
||||||
#dtoverlay -r seeed-2mic-voicecard
|
#dtoverlay -r seeed-2mic-voicecard
|
||||||
DTC_FLAGS="-b 0 -Wno-unit_address_vs_reg -I dts -O dtb"
|
DTC_FLAGS="-b 0 -Wno-unit_address_vs_reg -I dts -O dtb"
|
||||||
|
|
||||||
|
|
|
@ -6,4 +6,10 @@ BUILT_MODULE_NAME[2]="snd-soc-seeed-voicecard"
|
||||||
DEST_MODULE_LOCATION[0]="/kernel/sound/soc/codecs"
|
DEST_MODULE_LOCATION[0]="/kernel/sound/soc/codecs"
|
||||||
DEST_MODULE_LOCATION[1]="/kernel/sound/soc/codecs"
|
DEST_MODULE_LOCATION[1]="/kernel/sound/soc/codecs"
|
||||||
DEST_MODULE_LOCATION[2]="/kernel/sound/soc/bcm"
|
DEST_MODULE_LOCATION[2]="/kernel/sound/soc/bcm"
|
||||||
|
PATCH[0]="back-to-v4.19.diff"
|
||||||
|
PATCH[1]="back-to-v5.4.diff"
|
||||||
|
PATCH[2]="back-to-v5.8.diff"
|
||||||
|
PATCH_MATCH[0]="^4\.19\.*"
|
||||||
|
PATCH_MATCH[1]="^5\.4\.*"
|
||||||
|
PATCH_MATCH[2]="^5\.8\.*"
|
||||||
AUTOINSTALL="yes"
|
AUTOINSTALL="yes"
|
||||||
|
|
91
install.sh
91
install.sh
|
@ -1,7 +1,5 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
FORCE_KERNEL="1.20190925+1-1"
|
|
||||||
|
|
||||||
if [[ $EUID -ne 0 ]]; then
|
if [[ $EUID -ne 0 ]]; then
|
||||||
echo "This script must be run as root (use sudo)" 1>&2
|
echo "This script must be run as root (use sudo)" 1>&2
|
||||||
exit 1
|
exit 1
|
||||||
|
@ -28,19 +26,24 @@ fi
|
||||||
|
|
||||||
#
|
#
|
||||||
# make sure that we are on something ARM/Raspberry related
|
# make sure that we are on something ARM/Raspberry related
|
||||||
# either a bare metal Raspberry or a qemu session with
|
# either a bare metal Raspberry or a qemu session with
|
||||||
# Raspberry stuff available
|
# Raspberry stuff available
|
||||||
# - check for /boot/overlays
|
# - check for /boot/overlays
|
||||||
# - dtparam and dtoverlay is available
|
# - dtparam and dtoverlay is available
|
||||||
errorFound=0
|
errorFound=0
|
||||||
if [ ! -d /boot/overlays ] ; then
|
OVERLAYS=/boot/overlays
|
||||||
echo "/boot/overlays not found or not a directory" 1>&2
|
[ -d /boot/firmware/overlays ] && OVERLAYS=/boot/firmware/overlays
|
||||||
|
|
||||||
|
if [ ! -d $OVERLAYS ] ; then
|
||||||
|
echo "$OVERLAYS not found or not a directory" 1>&2
|
||||||
errorFound=1
|
errorFound=1
|
||||||
fi
|
fi
|
||||||
# should we also check for alsactl and amixer used in seeed-voicecard?
|
# should we also check for alsactl and amixer used in seeed-voicecard?
|
||||||
|
PATH=$PATH:/opt/vc/bin
|
||||||
for cmd in dtparam dtoverlay ; do
|
for cmd in dtparam dtoverlay ; do
|
||||||
if ! which $cmd &>/dev/null ; then
|
if ! which $cmd &>/dev/null ; then
|
||||||
echo "$cmd not found" 1>&2
|
echo "$cmd not found" 1>&2
|
||||||
|
echo "You may need to run ./ubuntu-prerequisite.sh"
|
||||||
errorFound=1
|
errorFound=1
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
@ -63,8 +66,11 @@ function get_kernel_version() {
|
||||||
_VER_RUN=""
|
_VER_RUN=""
|
||||||
[ -z "$_VER_RUN" ] && {
|
[ -z "$_VER_RUN" ] && {
|
||||||
ZIMAGE=/boot/kernel.img
|
ZIMAGE=/boot/kernel.img
|
||||||
|
[ -f /boot/firmware/vmlinuz ] && ZIMAGE=/boot/firmware/vmlinuz
|
||||||
|
# 64-bit-only kernel package
|
||||||
|
[ ! -f /boot/kernel.img ] && [ -f /boot/kernel8.img ] && ZIMAGE=/boot/kernel8.img
|
||||||
IMG_OFFSET=$(LC_ALL=C grep -abo $'\x1f\x8b\x08\x00' $ZIMAGE | head -n 1 | cut -d ':' -f 1)
|
IMG_OFFSET=$(LC_ALL=C grep -abo $'\x1f\x8b\x08\x00' $ZIMAGE | head -n 1 | cut -d ':' -f 1)
|
||||||
_VER_RUN=$(dd if=$ZIMAGE obs=64K ibs=4 skip=$(( IMG_OFFSET / 4)) | zcat | grep -a -m1 "Linux version" | strings | awk '{ print $3; }')
|
_VER_RUN=$(dd if=$ZIMAGE obs=64K ibs=4 skip=$(( IMG_OFFSET / 4)) 2>/dev/null | zcat | grep -a -m1 "Linux version" | LC_ALL=C sed -e 's/^.*Linux/Linux/' | strings | awk '{ print $3; }')
|
||||||
}
|
}
|
||||||
echo "$_VER_RUN"
|
echo "$_VER_RUN"
|
||||||
return 0
|
return 0
|
||||||
|
@ -72,14 +78,18 @@ function get_kernel_version() {
|
||||||
|
|
||||||
function check_kernel_headers() {
|
function check_kernel_headers() {
|
||||||
VER_RUN=$(get_kernel_version)
|
VER_RUN=$(get_kernel_version)
|
||||||
VER_HDR=$(dpkg -L raspberrypi-kernel-headers | egrep -m1 "/lib/modules/[^-]+/build" | awk -F'/' '{ print $4; }')
|
VER_HDR=$(dpkg -L raspberrypi-kernel-headers | egrep -m1 "/lib/modules/[^\/]+/build" | awk -F'/' '{ print $4; }')
|
||||||
|
[ "X$VER_RUN" == "X$VER_HDR" ] && {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
VER_HDR=$(dpkg -L linux-headers-$VER_RUN | egrep -m1 "/lib/modules/[^\/]+/build" | awk -F'/' '{ print $4; }')
|
||||||
[ "X$VER_RUN" == "X$VER_HDR" ] && {
|
[ "X$VER_RUN" == "X$VER_HDR" ] && {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
# echo RUN=$VER_RUN HDR=$VER_HDR
|
# echo RUN=$VER_RUN HDR=$VER_HDR
|
||||||
echo " !!! Your kernel version is $VER_RUN"
|
echo " !!! Your kernel version is $VER_RUN"
|
||||||
echo " Not found *** coressponding *** kernel headers with apt-get."
|
echo " Not found *** corresponding *** kernel headers with apt-get."
|
||||||
echo " This may occur if you have ran 'rpi-update'."
|
echo " This may occur if you have ran 'rpi-update'."
|
||||||
echo " Choose *** y *** will revert the kernel to version $VER_HDR then continue."
|
echo " Choose *** y *** will revert the kernel to version $VER_HDR then continue."
|
||||||
echo " Choose *** N *** will exit without this driver support, by default."
|
echo " Choose *** N *** will exit without this driver support, by default."
|
||||||
|
@ -92,43 +102,17 @@ function check_kernel_headers() {
|
||||||
apt-get -y --reinstall install raspberrypi-kernel
|
apt-get -y --reinstall install raspberrypi-kernel
|
||||||
}
|
}
|
||||||
|
|
||||||
function download_install_debpkg() {
|
|
||||||
local prefix name r
|
|
||||||
prefix=$1
|
|
||||||
name=$2
|
|
||||||
|
|
||||||
for (( i = 0; i < 3; i++ )); do
|
|
||||||
wget $prefix$name -O /tmp/$name && break
|
|
||||||
done
|
|
||||||
dpkg -i /tmp/$name; r=$?
|
|
||||||
rm -f /tmp/$name
|
|
||||||
return $r
|
|
||||||
}
|
|
||||||
|
|
||||||
function install_kernel() {
|
|
||||||
local _url _prefix
|
|
||||||
|
|
||||||
# Instead of retriving the lastest kernel & headers
|
|
||||||
[ "X$FORCE_KERNEL" == "X" ] && {
|
|
||||||
apt-get -y --force-yes install raspberrypi-kernel-headers raspberrypi-kernel
|
|
||||||
} || {
|
|
||||||
# We would like to a fixed version
|
|
||||||
KERN_NAME=raspberrypi-kernel_${FORCE_KERNEL}_armhf.deb
|
|
||||||
HDR_NAME=raspberrypi-kernel-headers_${FORCE_KERNEL}_armhf.deb
|
|
||||||
_url=$(apt-get download --print-uris raspberrypi-kernel | sed -nre "s/'([^']+)'.*$/\1/g;p")
|
|
||||||
_prefix=$(echo $_url | sed -nre 's/^(.*)raspberrypi-kernel_.*$/\1/g;p')
|
|
||||||
|
|
||||||
download_install_debpkg "$_prefix" "$KERN_NAME"
|
|
||||||
download_install_debpkg "$_prefix" "$HDR_NAME"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# update and install required packages
|
# update and install required packages
|
||||||
which apt &>/dev/null
|
which apt &>/dev/null
|
||||||
if [[ $? -eq 0 ]]; then
|
if [[ $? -eq 0 ]]; then
|
||||||
apt update -y
|
apt update -y
|
||||||
|
# Raspbian kernel packages
|
||||||
|
apt-get -y install raspberrypi-kernel-headers raspberrypi-kernel
|
||||||
|
# Recent Raspbian has 64-bit kernel on 32-bit userspace
|
||||||
|
apt-get -y install gcc-aarch64-linux-gnu
|
||||||
|
# Ubuntu kernel packages
|
||||||
|
apt-get -y install linux-raspi linux-headers-raspi linux-image-raspi
|
||||||
apt-get -y install dkms git i2c-tools libasound2-plugins
|
apt-get -y install dkms git i2c-tools libasound2-plugins
|
||||||
install_kernel
|
|
||||||
# rpi-update checker
|
# rpi-update checker
|
||||||
check_kernel_headers
|
check_kernel_headers
|
||||||
fi
|
fi
|
||||||
|
@ -143,7 +127,8 @@ fi
|
||||||
# it's just been updated)
|
# it's just been updated)
|
||||||
base_ver=$(get_kernel_version)
|
base_ver=$(get_kernel_version)
|
||||||
base_ver=${base_ver%%[-+]*}
|
base_ver=${base_ver%%[-+]*}
|
||||||
kernels="${base_ver}+ ${base_ver}-v7+ ${base_ver}-v7l+"
|
#kernels="${base_ver}+ ${base_ver}-v7+ ${base_ver}-v7l+"
|
||||||
|
kernels=$(uname -r)
|
||||||
|
|
||||||
function install_module {
|
function install_module {
|
||||||
local _i
|
local _i
|
||||||
|
@ -177,9 +162,9 @@ install_module "./" "seeed-voicecard"
|
||||||
|
|
||||||
|
|
||||||
# install dtbos
|
# install dtbos
|
||||||
cp seeed-2mic-voicecard.dtbo /boot/overlays
|
cp seeed-2mic-voicecard.dtbo $OVERLAYS
|
||||||
cp seeed-4mic-voicecard.dtbo /boot/overlays
|
cp seeed-4mic-voicecard.dtbo $OVERLAYS
|
||||||
cp seeed-8mic-voicecard.dtbo /boot/overlays
|
cp seeed-8mic-voicecard.dtbo $OVERLAYS
|
||||||
|
|
||||||
#install alsa plugins
|
#install alsa plugins
|
||||||
# no need this plugin now
|
# no need this plugin now
|
||||||
|
@ -192,16 +177,20 @@ grep -q "^snd-soc-seeed-voicecard$" /etc/modules || \
|
||||||
grep -q "^snd-soc-ac108$" /etc/modules || \
|
grep -q "^snd-soc-ac108$" /etc/modules || \
|
||||||
echo "snd-soc-ac108" >> /etc/modules
|
echo "snd-soc-ac108" >> /etc/modules
|
||||||
grep -q "^snd-soc-wm8960$" /etc/modules || \
|
grep -q "^snd-soc-wm8960$" /etc/modules || \
|
||||||
echo "snd-soc-wm8960" >> /etc/modules
|
echo "snd-soc-wm8960" >> /etc/modules
|
||||||
|
|
||||||
#set dtoverlays
|
#set dtoverlays
|
||||||
sed -i -e 's:#dtparam=i2c_arm=on:dtparam=i2c_arm=on:g' /boot/config.txt || true
|
CONFIG=/boot/config.txt
|
||||||
grep -q "^dtoverlay=i2s-mmap$" /boot/config.txt || \
|
[ -f /boot/firmware/config.txt ] && CONFIG=/boot/firmware/config.txt
|
||||||
echo "dtoverlay=i2s-mmap" >> /boot/config.txt
|
[ -f /boot/firmware/usercfg.txt ] && CONFIG=/boot/firmware/usercfg.txt
|
||||||
|
|
||||||
|
sed -i -e 's:#dtparam=i2c_arm=on:dtparam=i2c_arm=on:g' $CONFIG || true
|
||||||
|
grep -q "^dtoverlay=i2s-mmap$" $CONFIG || \
|
||||||
|
echo "dtoverlay=i2s-mmap" >> $CONFIG
|
||||||
|
|
||||||
|
|
||||||
grep -q "^dtparam=i2s=on$" /boot/config.txt || \
|
grep -q "^dtparam=i2s=on$" $CONFIG || \
|
||||||
echo "dtparam=i2s=on" >> /boot/config.txt
|
echo "dtparam=i2s=on" >> $CONFIG
|
||||||
|
|
||||||
#install config files
|
#install config files
|
||||||
mkdir /etc/voicecard || true
|
mkdir /etc/voicecard || true
|
||||||
|
@ -225,7 +214,7 @@ git --git-dir=/etc/voicecard/.git --work-tree=/etc/voicecard/ commit -m "origin
|
||||||
|
|
||||||
cp seeed-voicecard /usr/bin/
|
cp seeed-voicecard /usr/bin/
|
||||||
cp seeed-voicecard.service /lib/systemd/system/
|
cp seeed-voicecard.service /lib/systemd/system/
|
||||||
systemctl enable seeed-voicecard.service
|
systemctl enable seeed-voicecard.service
|
||||||
systemctl start seeed-voicecard
|
systemctl start seeed-voicecard
|
||||||
|
|
||||||
echo "------------------------------------------------------"
|
echo "------------------------------------------------------"
|
||||||
|
|
454
patches/back-to-v4.19.diff
Normal file
454
patches/back-to-v4.19.diff
Normal file
|
@ -0,0 +1,454 @@
|
||||||
|
diff --git a/ac101.c b/ac101.c
|
||||||
|
index 23837a7..41c15f3 100644
|
||||||
|
--- a/ac101.c
|
||||||
|
+++ b/ac101.c
|
||||||
|
@@ -955,10 +955,10 @@ void ac101_aif_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai
|
||||||
|
|
||||||
|
AC101_DBG("stream = %s, play: %d, capt: %d, active: %d\n",
|
||||||
|
snd_pcm_stream_str(substream),
|
||||||
|
- codec_dai->stream_active[SNDRV_PCM_STREAM_PLAYBACK], codec_dai->stream_active[SNDRV_PCM_STREAM_CAPTURE],
|
||||||
|
- snd_soc_dai_active(codec_dai));
|
||||||
|
+ codec_dai->playback_active, codec_dai->capture_active,
|
||||||
|
+ codec_dai->active);
|
||||||
|
|
||||||
|
- if (!snd_soc_dai_active(codec_dai)) {
|
||||||
|
+ if (!codec_dai->active) {
|
||||||
|
ac10x->aif1_clken = 1;
|
||||||
|
ac101_aif1clk(codec, SND_SOC_DAPM_POST_PMD, 0);
|
||||||
|
} else {
|
||||||
|
@@ -1080,7 +1080,7 @@ int ac101_hw_params(struct snd_pcm_substream *substream,
|
||||||
|
freq_out = _FREQ_24_576K;
|
||||||
|
for (i = 0; i < ARRAY_SIZE(codec_aif1_fs); i++) {
|
||||||
|
if (codec_aif1_fs[i].samp_rate == params_rate(params)) {
|
||||||
|
- if (codec_dai->stream_active[SNDRV_PCM_STREAM_CAPTURE] && dmic_used && codec_aif1_fs[i].samp_rate == 44100) {
|
||||||
|
+ if (codec_dai->capture_active && dmic_used && codec_aif1_fs[i].samp_rate == 44100) {
|
||||||
|
ac101_update_bits(codec, AIF_SR_CTRL, (0xf<<AIF1_FS), (0x4<<AIF1_FS));
|
||||||
|
} else {
|
||||||
|
ac101_update_bits(codec, AIF_SR_CTRL, (0xf<<AIF1_FS), ((codec_aif1_fs[i].srbit)<<AIF1_FS));
|
||||||
|
diff --git a/ac108.c b/ac108.c
|
||||||
|
index d5dd12d..0a8c462 100644
|
||||||
|
--- a/ac108.c
|
||||||
|
+++ b/ac108.c
|
||||||
|
@@ -653,7 +653,7 @@ static int ac108_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_h
|
||||||
|
|
||||||
|
dev_dbg(dai->dev, "%s() stream=%s play:%d capt:%d +++\n", __func__,
|
||||||
|
snd_pcm_stream_str(substream),
|
||||||
|
- dai->stream_active[SNDRV_PCM_STREAM_PLAYBACK], dai->stream_active[SNDRV_PCM_STREAM_CAPTURE]);
|
||||||
|
+ dai->playback_active, dai->capture_active);
|
||||||
|
|
||||||
|
if (ac10x->i2c101) {
|
||||||
|
ret = ac101_hw_params(substream, params, dai);
|
||||||
|
@@ -664,8 +664,8 @@ static int ac108_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_h
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE && dai->stream_active[SNDRV_PCM_STREAM_PLAYBACK])
|
||||||
|
- || (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && dai->stream_active[SNDRV_PCM_STREAM_CAPTURE])) {
|
||||||
|
+ if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE && dai->playback_active)
|
||||||
|
+ || (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && dai->capture_active)) {
|
||||||
|
/* not configure hw_param twice */
|
||||||
|
/* return 0; */
|
||||||
|
}
|
||||||
|
@@ -810,9 +810,6 @@ static int ac108_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int fr
|
||||||
|
|
||||||
|
struct ac10x_priv *ac10x = snd_soc_dai_get_drvdata(dai);
|
||||||
|
|
||||||
|
- if (freq != 24000000 || clk_id != SYSCLK_SRC_PLL)
|
||||||
|
- dev_warn(dai->dev, "ac108_set_sysclk freq = %d clk = %d\n", freq, clk_id);
|
||||||
|
-
|
||||||
|
freq = 24000000;
|
||||||
|
clk_id = SYSCLK_SRC_PLL;
|
||||||
|
|
||||||
|
@@ -1124,7 +1121,7 @@ void ac108_aif_shutdown(struct snd_pcm_substream *substream,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-int ac108_aif_mute(struct snd_soc_dai *dai, int mute, int direction) {
|
||||||
|
+int ac108_aif_mute(struct snd_soc_dai *dai, int mute) {
|
||||||
|
struct snd_soc_codec *codec = dai->codec;
|
||||||
|
struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
|
||||||
|
|
||||||
|
@@ -1145,13 +1142,12 @@ static const struct snd_soc_dai_ops ac108_dai_ops = {
|
||||||
|
.hw_params = ac108_hw_params,
|
||||||
|
.prepare = ac108_prepare,
|
||||||
|
.trigger = ac108_trigger,
|
||||||
|
- .mute_stream = ac108_aif_mute,
|
||||||
|
+ .digital_mute = ac108_aif_mute,
|
||||||
|
|
||||||
|
/*DAI format configuration*/
|
||||||
|
.set_fmt = ac108_set_fmt,
|
||||||
|
|
||||||
|
// .hw_free = ac108_hw_free,
|
||||||
|
- .no_capture_mute = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct snd_soc_dai_driver ac108_dai0 = {
|
||||||
|
diff --git a/seeed-voicecard.c b/seeed-voicecard.c
|
||||||
|
index b90af93..af6db74 100644
|
||||||
|
--- a/seeed-voicecard.c
|
||||||
|
+++ b/seeed-voicecard.c
|
||||||
|
@@ -28,8 +28,6 @@
|
||||||
|
#include <sound/simple_card_utils.h>
|
||||||
|
#include "ac10x.h"
|
||||||
|
|
||||||
|
-#define LINUX_VERSION_IS_GEQ(x1,x2,x3) (LINUX_VERSION_CODE >= KERNEL_VERSION(x1,x2,x3))
|
||||||
|
-
|
||||||
|
/*
|
||||||
|
* single codec:
|
||||||
|
* 0 - allow multi codec
|
||||||
|
@@ -42,9 +40,6 @@ struct seeed_card_data {
|
||||||
|
struct seeed_dai_props {
|
||||||
|
struct asoc_simple_dai cpu_dai;
|
||||||
|
struct asoc_simple_dai codec_dai;
|
||||||
|
- struct snd_soc_dai_link_component cpus; /* single cpu */
|
||||||
|
- struct snd_soc_dai_link_component codecs; /* single codec */
|
||||||
|
- struct snd_soc_dai_link_component platforms;
|
||||||
|
unsigned int mclk_fs;
|
||||||
|
} *dai_props;
|
||||||
|
unsigned int mclk_fs;
|
||||||
|
@@ -97,16 +92,16 @@ static int seeed_voice_card_startup(struct snd_pcm_substream *substream)
|
||||||
|
if (ret)
|
||||||
|
clk_disable_unprepare(dai_props->cpu_dai.clk);
|
||||||
|
|
||||||
|
- if (asoc_rtd_to_cpu(rtd, 0)->driver->playback.channels_min) {
|
||||||
|
- priv->channels_playback_default = asoc_rtd_to_cpu(rtd, 0)->driver->playback.channels_min;
|
||||||
|
+ if (rtd->cpu_dai->driver->playback.channels_min) {
|
||||||
|
+ priv->channels_playback_default = rtd->cpu_dai->driver->playback.channels_min;
|
||||||
|
}
|
||||||
|
- if (asoc_rtd_to_cpu(rtd, 0)->driver->capture.channels_min) {
|
||||||
|
- priv->channels_capture_default = asoc_rtd_to_cpu(rtd, 0)->driver->capture.channels_min;
|
||||||
|
+ if (rtd->cpu_dai->driver->capture.channels_min) {
|
||||||
|
+ priv->channels_capture_default = rtd->cpu_dai->driver->capture.channels_min;
|
||||||
|
}
|
||||||
|
- asoc_rtd_to_cpu(rtd, 0)->driver->playback.channels_min = priv->channels_playback_override;
|
||||||
|
- asoc_rtd_to_cpu(rtd, 0)->driver->playback.channels_max = priv->channels_playback_override;
|
||||||
|
- asoc_rtd_to_cpu(rtd, 0)->driver->capture.channels_min = priv->channels_capture_override;
|
||||||
|
- asoc_rtd_to_cpu(rtd, 0)->driver->capture.channels_max = priv->channels_capture_override;
|
||||||
|
+ rtd->cpu_dai->driver->playback.channels_min = priv->channels_playback_override;
|
||||||
|
+ rtd->cpu_dai->driver->playback.channels_max = priv->channels_playback_override;
|
||||||
|
+ rtd->cpu_dai->driver->capture.channels_min = priv->channels_capture_override;
|
||||||
|
+ rtd->cpu_dai->driver->capture.channels_max = priv->channels_capture_override;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@@ -118,10 +113,10 @@ static void seeed_voice_card_shutdown(struct snd_pcm_substream *substream)
|
||||||
|
struct seeed_dai_props *dai_props =
|
||||||
|
seeed_priv_to_props(priv, rtd->num);
|
||||||
|
|
||||||
|
- asoc_rtd_to_cpu(rtd, 0)->driver->playback.channels_min = priv->channels_playback_default;
|
||||||
|
- asoc_rtd_to_cpu(rtd, 0)->driver->playback.channels_max = priv->channels_playback_default;
|
||||||
|
- asoc_rtd_to_cpu(rtd, 0)->driver->capture.channels_min = priv->channels_capture_default;
|
||||||
|
- asoc_rtd_to_cpu(rtd, 0)->driver->capture.channels_max = priv->channels_capture_default;
|
||||||
|
+ rtd->cpu_dai->driver->playback.channels_min = priv->channels_playback_default;
|
||||||
|
+ rtd->cpu_dai->driver->playback.channels_max = priv->channels_playback_default;
|
||||||
|
+ rtd->cpu_dai->driver->capture.channels_min = priv->channels_capture_default;
|
||||||
|
+ rtd->cpu_dai->driver->capture.channels_max = priv->channels_capture_default;
|
||||||
|
|
||||||
|
clk_disable_unprepare(dai_props->cpu_dai.clk);
|
||||||
|
|
||||||
|
@@ -132,8 +127,8 @@ static int seeed_voice_card_hw_params(struct snd_pcm_substream *substream,
|
||||||
|
struct snd_pcm_hw_params *params)
|
||||||
|
{
|
||||||
|
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||||
|
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
|
||||||
|
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
|
||||||
|
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||||
|
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||||
|
struct seeed_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
|
||||||
|
struct seeed_dai_props *dai_props =
|
||||||
|
seeed_priv_to_props(priv, rtd->num);
|
||||||
|
@@ -197,7 +192,7 @@ static void work_cb_codec_clk(struct work_struct *work)
|
||||||
|
static int seeed_voice_card_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||||
|
{
|
||||||
|
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||||
|
- struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
|
||||||
|
+ struct snd_soc_dai *dai = rtd->codec_dai;
|
||||||
|
struct seeed_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
|
||||||
|
#if CONFIG_AC10X_TRIG_LOCK
|
||||||
|
unsigned long flags;
|
||||||
|
@@ -206,7 +201,7 @@ static int seeed_voice_card_trigger(struct snd_pcm_substream *substream, int cmd
|
||||||
|
|
||||||
|
dev_dbg(rtd->card->dev, "%s() stream=%s cmd=%d play:%d, capt:%d\n",
|
||||||
|
__FUNCTION__, snd_pcm_stream_str(substream), cmd,
|
||||||
|
- dai->stream_active[SNDRV_PCM_STREAM_PLAYBACK], dai->stream_active[SNDRV_PCM_STREAM_CAPTURE]);
|
||||||
|
+ dai->playback_active, dai->capture_active);
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case SNDRV_PCM_TRIGGER_START:
|
||||||
|
@@ -228,7 +223,7 @@ static int seeed_voice_card_trigger(struct snd_pcm_substream *substream, int cmd
|
||||||
|
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||||
|
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||||
|
/* capture channel resync, if overrun */
|
||||||
|
- if (dai->stream_active[SNDRV_PCM_STREAM_CAPTURE] && substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||||
|
+ if (dai->capture_active && substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -248,7 +243,7 @@ static int seeed_voice_card_trigger(struct snd_pcm_substream *substream, int cmd
|
||||||
|
|
||||||
|
dev_dbg(rtd->card->dev, "%s() stream=%s cmd=%d play:%d, capt:%d;finished %d\n",
|
||||||
|
__FUNCTION__, snd_pcm_stream_str(substream), cmd,
|
||||||
|
- dai->stream_active[SNDRV_PCM_STREAM_PLAYBACK], dai->stream_active[SNDRV_PCM_STREAM_CAPTURE], ret);
|
||||||
|
+ dai->playback_active, dai->capture_active, ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@@ -387,8 +382,8 @@ static int asoc_simple_init_dai_link_params(struct snd_soc_pcm_runtime *rtd)
|
||||||
|
static int seeed_voice_card_dai_init(struct snd_soc_pcm_runtime *rtd)
|
||||||
|
{
|
||||||
|
struct seeed_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
|
||||||
|
- struct snd_soc_dai *codec = asoc_rtd_to_codec(rtd, 0);
|
||||||
|
- struct snd_soc_dai *cpu = asoc_rtd_to_cpu(rtd, 0);
|
||||||
|
+ struct snd_soc_dai *codec = rtd->codec_dai;
|
||||||
|
+ struct snd_soc_dai *cpu = rtd->cpu_dai;
|
||||||
|
struct seeed_dai_props *dai_props =
|
||||||
|
seeed_priv_to_props(priv, rtd->num);
|
||||||
|
int ret;
|
||||||
|
@@ -453,19 +448,20 @@ static int seeed_voice_card_dai_link_of(struct device_node *node,
|
||||||
|
goto dai_link_of_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
- ret = asoc_simple_parse_daifmt(dev, node, codec,
|
||||||
|
+ ret = asoc_simple_card_parse_daifmt(dev, node, codec,
|
||||||
|
prefix, &dai_link->dai_fmt);
|
||||||
|
if (ret < 0)
|
||||||
|
goto dai_link_of_err;
|
||||||
|
|
||||||
|
of_property_read_u32(node, "mclk-fs", &dai_props->mclk_fs);
|
||||||
|
|
||||||
|
- ret = asoc_simple_parse_cpu(cpu, dai_link, &single_cpu);
|
||||||
|
+ ret = asoc_simple_card_parse_cpu(cpu, dai_link,
|
||||||
|
+ DAI, CELL, &single_cpu);
|
||||||
|
if (ret < 0)
|
||||||
|
goto dai_link_of_err;
|
||||||
|
|
||||||
|
#if _SINGLE_CODEC
|
||||||
|
- ret = asoc_simple_parse_codec(codec, dai_link);
|
||||||
|
+ ret = asoc_simple_card_parse_codec(codec, dai_link, DAI, CELL);
|
||||||
|
if (ret < 0)
|
||||||
|
goto dai_link_of_err;
|
||||||
|
#else
|
||||||
|
@@ -477,7 +473,7 @@ static int seeed_voice_card_dai_link_of(struct device_node *node,
|
||||||
|
dev_dbg(dev, "dai_link num_codecs = %d\n", dai_link->num_codecs);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
- ret = asoc_simple_parse_platform(plat, dai_link);
|
||||||
|
+ ret = asoc_simple_card_parse_platform(plat, dai_link, DAI, CELL);
|
||||||
|
if (ret < 0)
|
||||||
|
goto dai_link_of_err;
|
||||||
|
|
||||||
|
@@ -502,7 +498,7 @@ static int seeed_voice_card_dai_link_of(struct device_node *node,
|
||||||
|
#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,10,0)
|
||||||
|
ret = asoc_simple_card_parse_clk_cpu(cpu, dai_link, cpu_dai);
|
||||||
|
#else
|
||||||
|
- ret = asoc_simple_parse_clk_cpu(dev, cpu, dai_link, cpu_dai);
|
||||||
|
+ ret = asoc_simple_card_parse_clk_cpu(dev, cpu, dai_link, cpu_dai);
|
||||||
|
#endif
|
||||||
|
if (ret < 0)
|
||||||
|
goto dai_link_of_err;
|
||||||
|
@@ -510,16 +506,16 @@ static int seeed_voice_card_dai_link_of(struct device_node *node,
|
||||||
|
#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,10,0)
|
||||||
|
ret = asoc_simple_card_parse_clk_codec(codec, dai_link, codec_dai);
|
||||||
|
#else
|
||||||
|
- ret = asoc_simple_parse_clk_codec(dev, codec, dai_link, codec_dai);
|
||||||
|
+ ret = asoc_simple_card_parse_clk_codec(dev, codec, dai_link, codec_dai);
|
||||||
|
#endif
|
||||||
|
if (ret < 0)
|
||||||
|
goto dai_link_of_err;
|
||||||
|
|
||||||
|
- ret = asoc_simple_set_dailink_name(dev, dai_link,
|
||||||
|
+ ret = asoc_simple_card_set_dailink_name(dev, dai_link,
|
||||||
|
"%s-%s",
|
||||||
|
- dai_link->cpus->dai_name,
|
||||||
|
+ dai_link->cpu_dai_name,
|
||||||
|
#if _SINGLE_CODEC
|
||||||
|
- dai_link->codecs->dai_name
|
||||||
|
+ dai_link->codec_dai_name
|
||||||
|
#else
|
||||||
|
dai_link->codecs[0].dai_name
|
||||||
|
#endif
|
||||||
|
@@ -533,19 +529,21 @@ static int seeed_voice_card_dai_link_of(struct device_node *node,
|
||||||
|
dev_dbg(dev, "\tname : %s\n", dai_link->stream_name);
|
||||||
|
dev_dbg(dev, "\tformat : %04x\n", dai_link->dai_fmt);
|
||||||
|
dev_dbg(dev, "\tcpu : %s / %d\n",
|
||||||
|
- dai_link->cpus->dai_name,
|
||||||
|
+ dai_link->cpu_dai_name,
|
||||||
|
dai_props->cpu_dai.sysclk);
|
||||||
|
dev_dbg(dev, "\tcodec : %s / %d\n",
|
||||||
|
#if _SINGLE_CODEC
|
||||||
|
- dai_link->codecs->dai_name,
|
||||||
|
+ dai_link->codec_dai_name,
|
||||||
|
#else
|
||||||
|
dai_link->codecs[0].dai_name,
|
||||||
|
#endif
|
||||||
|
dai_props->codec_dai.sysclk);
|
||||||
|
|
||||||
|
- asoc_simple_canonicalize_cpu(dai_link, single_cpu);
|
||||||
|
+ asoc_simple_card_canonicalize_cpu(dai_link, single_cpu);
|
||||||
|
#if _SINGLE_CODEC
|
||||||
|
- asoc_simple_canonicalize_platform(dai_link);
|
||||||
|
+ ret = asoc_simple_card_canonicalize_dailink(dai_link);
|
||||||
|
+ if (ret < 0)
|
||||||
|
+ goto dai_link_of_err;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
dai_link_of_err:
|
||||||
|
@@ -578,7 +576,7 @@ static int seeed_voice_card_parse_aux_devs(struct device_node *node,
|
||||||
|
aux_node = of_parse_phandle(node, PREFIX "aux-devs", i);
|
||||||
|
if (!aux_node)
|
||||||
|
return -EINVAL;
|
||||||
|
- priv->snd_card.aux_dev[i].dlc.of_node = aux_node;
|
||||||
|
+ priv->snd_card.aux_dev[i].codec_of_node = aux_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->snd_card.num_aux_devs = n;
|
||||||
|
@@ -638,7 +636,7 @@ static int seeed_voice_card_parse_of(struct device_node *node,
|
||||||
|
goto card_parse_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
- ret = asoc_simple_parse_card_name(&priv->snd_card, PREFIX);
|
||||||
|
+ ret = asoc_simple_card_parse_card_name(&priv->snd_card, PREFIX);
|
||||||
|
if (ret < 0)
|
||||||
|
goto card_parse_end;
|
||||||
|
|
||||||
|
@@ -743,7 +741,7 @@ static int seeed_voice_card_probe(struct platform_device *pdev)
|
||||||
|
struct seeed_dai_props *dai_props;
|
||||||
|
struct device_node *np = pdev->dev.of_node;
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
- int num, ret, i;
|
||||||
|
+ int num, ret;
|
||||||
|
|
||||||
|
/* Get the number of DAI links */
|
||||||
|
if (np && of_get_child_by_name(np, PREFIX "dai-link"))
|
||||||
|
@@ -761,25 +759,6 @@ static int seeed_voice_card_probe(struct platform_device *pdev)
|
||||||
|
if (!dai_props || !dai_link)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
- /*
|
||||||
|
- * Use snd_soc_dai_link_component instead of legacy style
|
||||||
|
- * It is codec only. but cpu/platform will be supported in the future.
|
||||||
|
- * see
|
||||||
|
- * soc-core.c :: snd_soc_init_multicodec()
|
||||||
|
- *
|
||||||
|
- * "platform" might be removed
|
||||||
|
- * see
|
||||||
|
- * simple-card-utils.c :: asoc_simple_canonicalize_platform()
|
||||||
|
- */
|
||||||
|
- for (i = 0; i < num; i++) {
|
||||||
|
- dai_link[i].cpus = &dai_props[i].cpus;
|
||||||
|
- dai_link[i].num_cpus = 1;
|
||||||
|
- dai_link[i].codecs = &dai_props[i].codecs;
|
||||||
|
- dai_link[i].num_codecs = 1;
|
||||||
|
- dai_link[i].platforms = &dai_props[i].platforms;
|
||||||
|
- dai_link[i].num_platforms = 1;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
priv->dai_props = dai_props;
|
||||||
|
priv->dai_link = dai_link;
|
||||||
|
|
||||||
|
@@ -798,9 +777,6 @@ static int seeed_voice_card_probe(struct platform_device *pdev)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
struct seeed_card_info *cinfo;
|
||||||
|
- struct snd_soc_dai_link_component *cpus;
|
||||||
|
- struct snd_soc_dai_link_component *codecs;
|
||||||
|
- struct snd_soc_dai_link_component *platform;
|
||||||
|
|
||||||
|
cinfo = dev->platform_data;
|
||||||
|
if (!cinfo) {
|
||||||
|
@@ -817,19 +793,13 @@ static int seeed_voice_card_probe(struct platform_device *pdev)
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
- cpus = dai_link->cpus;
|
||||||
|
- cpus->dai_name = cinfo->cpu_dai.name;
|
||||||
|
-
|
||||||
|
- codecs = dai_link->codecs;
|
||||||
|
- codecs->name = cinfo->codec;
|
||||||
|
- codecs->dai_name = cinfo->codec_dai.name;
|
||||||
|
-
|
||||||
|
- platform = dai_link->platforms;
|
||||||
|
- platform->name = cinfo->platform;
|
||||||
|
-
|
||||||
|
priv->snd_card.name = (cinfo->card) ? cinfo->card : cinfo->name;
|
||||||
|
dai_link->name = cinfo->name;
|
||||||
|
dai_link->stream_name = cinfo->name;
|
||||||
|
+ dai_link->platform_name = cinfo->platform;
|
||||||
|
+ dai_link->codec_name = cinfo->codec;
|
||||||
|
+ dai_link->cpu_dai_name = cinfo->cpu_dai.name;
|
||||||
|
+ dai_link->codec_dai_name = cinfo->codec_dai.name;
|
||||||
|
dai_link->dai_fmt = cinfo->daifmt;
|
||||||
|
dai_link->init = seeed_voice_card_dai_init;
|
||||||
|
memcpy(&priv->dai_props->cpu_dai, &cinfo->cpu_dai,
|
||||||
|
@@ -853,7 +823,7 @@ static int seeed_voice_card_probe(struct platform_device *pdev)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
err:
|
||||||
|
- asoc_simple_clean_reference(&priv->snd_card);
|
||||||
|
+ asoc_simple_card_clean_reference(&priv->snd_card);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@@ -865,7 +835,7 @@ static int seeed_voice_card_remove(struct platform_device *pdev)
|
||||||
|
|
||||||
|
if (cancel_work_sync(&priv->work_codec_clk) != 0) {
|
||||||
|
}
|
||||||
|
- return asoc_simple_clean_reference(card);
|
||||||
|
+ return asoc_simple_card_clean_reference(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct of_device_id seeed_voice_of_match[] = {
|
||||||
|
diff --git a/sound-compatible-4.18.h b/sound-compatible-4.18.h
|
||||||
|
index 550b3a7..6c1a014 100644
|
||||||
|
--- a/sound-compatible-4.18.h
|
||||||
|
+++ b/sound-compatible-4.18.h
|
||||||
|
@@ -16,6 +16,10 @@
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0)
|
||||||
|
+#ifndef __has_attribute
|
||||||
|
+# define __has_attribute(x) __GCC4_has_attribute_##x
|
||||||
|
+# define __GCC4_has_attribute___fallthrough__ 0
|
||||||
|
+#endif
|
||||||
|
#if __has_attribute(__fallthrough__)
|
||||||
|
# define fallthrough __attribute__((__fallthrough__))
|
||||||
|
#else
|
||||||
|
@@ -31,11 +35,7 @@
|
||||||
|
#define snd_soc_codec_get_dapm snd_soc_component_get_dapm
|
||||||
|
#define snd_soc_codec_get_bias_level snd_soc_component_get_bias_level
|
||||||
|
#define snd_soc_kcontrol_codec snd_soc_kcontrol_component
|
||||||
|
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,9,0)
|
||||||
|
-#define snd_soc_read snd_soc_component_read
|
||||||
|
-#else
|
||||||
|
#define snd_soc_read snd_soc_component_read32
|
||||||
|
-#endif
|
||||||
|
#define snd_soc_register_codec devm_snd_soc_register_component
|
||||||
|
#define snd_soc_unregister_codec snd_soc_unregister_component
|
||||||
|
#define snd_soc_update_bits snd_soc_component_update_bits
|
||||||
|
diff --git a/wm8960.c b/wm8960.c
|
||||||
|
index 465c6dc..34d4dad 100644
|
||||||
|
--- a/wm8960.c
|
||||||
|
+++ b/wm8960.c
|
||||||
|
@@ -796,7 +796,7 @@ static int wm8960_hw_free(struct snd_pcm_substream *substream,
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
-static int wm8960_mute(struct snd_soc_dai *dai, int mute, int direction)
|
||||||
|
+static int wm8960_mute(struct snd_soc_dai *dai, int mute)
|
||||||
|
{
|
||||||
|
struct snd_soc_codec *codec = dai->codec;
|
||||||
|
|
||||||
|
@@ -1236,12 +1236,11 @@ static int wm8960_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
|
||||||
|
static const struct snd_soc_dai_ops wm8960_dai_ops = {
|
||||||
|
.hw_params = wm8960_hw_params,
|
||||||
|
.hw_free = wm8960_hw_free,
|
||||||
|
- .mute_stream = wm8960_mute,
|
||||||
|
+ .digital_mute = wm8960_mute,
|
||||||
|
.set_fmt = wm8960_set_dai_fmt,
|
||||||
|
.set_clkdiv = wm8960_set_dai_clkdiv,
|
||||||
|
.set_pll = wm8960_set_dai_pll,
|
||||||
|
.set_sysclk = wm8960_set_dai_sysclk,
|
||||||
|
- .no_capture_mute = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct snd_soc_dai_driver wm8960_dai = {
|
245
patches/back-to-v5.4.diff
Normal file
245
patches/back-to-v5.4.diff
Normal file
|
@ -0,0 +1,245 @@
|
||||||
|
diff --git a/ac101.c b/ac101.c
|
||||||
|
index be9b1d8..343f030 100644
|
||||||
|
--- a/ac101.c
|
||||||
|
+++ b/ac101.c
|
||||||
|
@@ -955,10 +955,10 @@ void ac101_aif_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai
|
||||||
|
|
||||||
|
AC101_DBG("stream = %s, play: %d, capt: %d, active: %d\n",
|
||||||
|
snd_pcm_stream_str(substream),
|
||||||
|
- codec_dai->stream_active[SNDRV_PCM_STREAM_PLAYBACK], codec_dai->stream_active[SNDRV_PCM_STREAM_CAPTURE],
|
||||||
|
- snd_soc_dai_active(codec_dai));
|
||||||
|
+ codec_dai->playback_active, codec_dai->capture_active,
|
||||||
|
+ codec_dai->active);
|
||||||
|
|
||||||
|
- if (!snd_soc_dai_active(codec_dai)) {
|
||||||
|
+ if (!codec_dai->active) {
|
||||||
|
ac10x->aif1_clken = 1;
|
||||||
|
ac101_aif1clk(codec, SND_SOC_DAPM_POST_PMD, 0);
|
||||||
|
} else {
|
||||||
|
@@ -1080,7 +1080,7 @@ int ac101_hw_params(struct snd_pcm_substream *substream,
|
||||||
|
freq_out = _FREQ_24_576K;
|
||||||
|
for (i = 0; i < ARRAY_SIZE(codec_aif1_fs); i++) {
|
||||||
|
if (codec_aif1_fs[i].samp_rate == params_rate(params)) {
|
||||||
|
- if (codec_dai->stream_active[SNDRV_PCM_STREAM_CAPTURE] && dmic_used && codec_aif1_fs[i].samp_rate == 44100) {
|
||||||
|
+ if (codec_dai->capture_active && dmic_used && codec_aif1_fs[i].samp_rate == 44100) {
|
||||||
|
ac101_update_bits(codec, AIF_SR_CTRL, (0xf<<AIF1_FS), (0x4<<AIF1_FS));
|
||||||
|
} else {
|
||||||
|
ac101_update_bits(codec, AIF_SR_CTRL, (0xf<<AIF1_FS), ((codec_aif1_fs[i].srbit)<<AIF1_FS));
|
||||||
|
diff --git a/ac108.c b/ac108.c
|
||||||
|
index 4663df0..12ab27b 100644
|
||||||
|
--- a/ac108.c
|
||||||
|
+++ b/ac108.c
|
||||||
|
@@ -653,7 +653,7 @@ static int ac108_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_h
|
||||||
|
|
||||||
|
dev_dbg(dai->dev, "%s() stream=%s play:%d capt:%d +++\n", __func__,
|
||||||
|
snd_pcm_stream_str(substream),
|
||||||
|
- dai->stream_active[SNDRV_PCM_STREAM_PLAYBACK], dai->stream_active[SNDRV_PCM_STREAM_CAPTURE]);
|
||||||
|
+ dai->playback_active, dai->capture_active);
|
||||||
|
|
||||||
|
if (ac10x->i2c101) {
|
||||||
|
ret = ac101_hw_params(substream, params, dai);
|
||||||
|
@@ -664,8 +664,8 @@ static int ac108_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_h
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE && dai->stream_active[SNDRV_PCM_STREAM_PLAYBACK])
|
||||||
|
- || (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && dai->stream_active[SNDRV_PCM_STREAM_CAPTURE])) {
|
||||||
|
+ if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE && dai->playback_active)
|
||||||
|
+ || (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && dai->capture_active)) {
|
||||||
|
/* not configure hw_param twice */
|
||||||
|
/* return 0; */
|
||||||
|
}
|
||||||
|
@@ -1124,7 +1124,7 @@ void ac108_aif_shutdown(struct snd_pcm_substream *substream,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-int ac108_aif_mute(struct snd_soc_dai *dai, int mute, int direction) {
|
||||||
|
+int ac108_aif_mute(struct snd_soc_dai *dai, int mute) {
|
||||||
|
struct snd_soc_codec *codec = dai->codec;
|
||||||
|
struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
|
||||||
|
|
||||||
|
@@ -1145,13 +1145,12 @@ static const struct snd_soc_dai_ops ac108_dai_ops = {
|
||||||
|
.hw_params = ac108_hw_params,
|
||||||
|
.prepare = ac108_prepare,
|
||||||
|
.trigger = ac108_trigger,
|
||||||
|
- .mute_stream = ac108_aif_mute,
|
||||||
|
+ .digital_mute = ac108_aif_mute,
|
||||||
|
|
||||||
|
/*DAI format configuration*/
|
||||||
|
.set_fmt = ac108_set_fmt,
|
||||||
|
|
||||||
|
// .hw_free = ac108_hw_free,
|
||||||
|
- .no_capture_mute = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct snd_soc_dai_driver ac108_dai0 = {
|
||||||
|
diff --git a/seeed-voicecard.c b/seeed-voicecard.c
|
||||||
|
index c6d9048..43535aa 100644
|
||||||
|
--- a/seeed-voicecard.c
|
||||||
|
+++ b/seeed-voicecard.c
|
||||||
|
@@ -96,16 +96,16 @@ static int seeed_voice_card_startup(struct snd_pcm_substream *substream)
|
||||||
|
if (ret)
|
||||||
|
clk_disable_unprepare(dai_props->cpu_dai.clk);
|
||||||
|
|
||||||
|
- if (asoc_rtd_to_cpu(rtd, 0)->driver->playback.channels_min) {
|
||||||
|
- priv->channels_playback_default = asoc_rtd_to_cpu(rtd, 0)->driver->playback.channels_min;
|
||||||
|
+ if (rtd->cpu_dai->driver->playback.channels_min) {
|
||||||
|
+ priv->channels_playback_default = rtd->cpu_dai->driver->playback.channels_min;
|
||||||
|
}
|
||||||
|
- if (asoc_rtd_to_cpu(rtd, 0)->driver->capture.channels_min) {
|
||||||
|
- priv->channels_capture_default = asoc_rtd_to_cpu(rtd, 0)->driver->capture.channels_min;
|
||||||
|
+ if (rtd->cpu_dai->driver->capture.channels_min) {
|
||||||
|
+ priv->channels_capture_default = rtd->cpu_dai->driver->capture.channels_min;
|
||||||
|
}
|
||||||
|
- asoc_rtd_to_cpu(rtd, 0)->driver->playback.channels_min = priv->channels_playback_override;
|
||||||
|
- asoc_rtd_to_cpu(rtd, 0)->driver->playback.channels_max = priv->channels_playback_override;
|
||||||
|
- asoc_rtd_to_cpu(rtd, 0)->driver->capture.channels_min = priv->channels_capture_override;
|
||||||
|
- asoc_rtd_to_cpu(rtd, 0)->driver->capture.channels_max = priv->channels_capture_override;
|
||||||
|
+ rtd->cpu_dai->driver->playback.channels_min = priv->channels_playback_override;
|
||||||
|
+ rtd->cpu_dai->driver->playback.channels_max = priv->channels_playback_override;
|
||||||
|
+ rtd->cpu_dai->driver->capture.channels_min = priv->channels_capture_override;
|
||||||
|
+ rtd->cpu_dai->driver->capture.channels_max = priv->channels_capture_override;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@@ -117,10 +117,10 @@ static void seeed_voice_card_shutdown(struct snd_pcm_substream *substream)
|
||||||
|
struct seeed_dai_props *dai_props =
|
||||||
|
seeed_priv_to_props(priv, rtd->num);
|
||||||
|
|
||||||
|
- asoc_rtd_to_cpu(rtd, 0)->driver->playback.channels_min = priv->channels_playback_default;
|
||||||
|
- asoc_rtd_to_cpu(rtd, 0)->driver->playback.channels_max = priv->channels_playback_default;
|
||||||
|
- asoc_rtd_to_cpu(rtd, 0)->driver->capture.channels_min = priv->channels_capture_default;
|
||||||
|
- asoc_rtd_to_cpu(rtd, 0)->driver->capture.channels_max = priv->channels_capture_default;
|
||||||
|
+ rtd->cpu_dai->driver->playback.channels_min = priv->channels_playback_default;
|
||||||
|
+ rtd->cpu_dai->driver->playback.channels_max = priv->channels_playback_default;
|
||||||
|
+ rtd->cpu_dai->driver->capture.channels_min = priv->channels_capture_default;
|
||||||
|
+ rtd->cpu_dai->driver->capture.channels_max = priv->channels_capture_default;
|
||||||
|
|
||||||
|
clk_disable_unprepare(dai_props->cpu_dai.clk);
|
||||||
|
|
||||||
|
@@ -131,8 +131,8 @@ static int seeed_voice_card_hw_params(struct snd_pcm_substream *substream,
|
||||||
|
struct snd_pcm_hw_params *params)
|
||||||
|
{
|
||||||
|
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||||
|
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
|
||||||
|
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
|
||||||
|
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||||
|
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||||
|
struct seeed_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
|
||||||
|
struct seeed_dai_props *dai_props =
|
||||||
|
seeed_priv_to_props(priv, rtd->num);
|
||||||
|
@@ -196,7 +196,7 @@ static void work_cb_codec_clk(struct work_struct *work)
|
||||||
|
static int seeed_voice_card_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||||
|
{
|
||||||
|
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||||
|
- struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
|
||||||
|
+ struct snd_soc_dai *dai = rtd->codec_dai;
|
||||||
|
struct seeed_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
|
||||||
|
#if CONFIG_AC10X_TRIG_LOCK
|
||||||
|
unsigned long flags;
|
||||||
|
@@ -205,7 +205,7 @@ static int seeed_voice_card_trigger(struct snd_pcm_substream *substream, int cmd
|
||||||
|
|
||||||
|
dev_dbg(rtd->card->dev, "%s() stream=%s cmd=%d play:%d, capt:%d\n",
|
||||||
|
__FUNCTION__, snd_pcm_stream_str(substream), cmd,
|
||||||
|
- dai->stream_active[SNDRV_PCM_STREAM_PLAYBACK], dai->stream_active[SNDRV_PCM_STREAM_CAPTURE]);
|
||||||
|
+ dai->playback_active, dai->capture_active);
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case SNDRV_PCM_TRIGGER_START:
|
||||||
|
@@ -227,7 +227,7 @@ static int seeed_voice_card_trigger(struct snd_pcm_substream *substream, int cmd
|
||||||
|
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||||
|
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||||
|
/* capture channel resync, if overrun */
|
||||||
|
- if (dai->stream_active[SNDRV_PCM_STREAM_CAPTURE] && substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||||
|
+ if (dai->capture_active && substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -252,7 +247,7 @@ static int seeed_voice_card_trigger(struct snd_pcm_substream *substream, int cmd
|
||||||
|
|
||||||
|
dev_dbg(rtd->card->dev, "%s() stream=%s cmd=%d play:%d, capt:%d;finished %d\n",
|
||||||
|
__FUNCTION__, snd_pcm_stream_str(substream), cmd,
|
||||||
|
- dai->stream_active[SNDRV_PCM_STREAM_PLAYBACK], dai->stream_active[SNDRV_PCM_STREAM_CAPTURE], ret);
|
||||||
|
+ dai->playback_active, dai->capture_active, ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@@ -337,8 +337,8 @@ static int asoc_simple_init_dai(struct snd_soc_dai *dai,
|
||||||
|
static int seeed_voice_card_dai_init(struct snd_soc_pcm_runtime *rtd)
|
||||||
|
{
|
||||||
|
struct seeed_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
|
||||||
|
- struct snd_soc_dai *codec = asoc_rtd_to_codec(rtd, 0);
|
||||||
|
- struct snd_soc_dai *cpu = asoc_rtd_to_cpu(rtd, 0);
|
||||||
|
+ struct snd_soc_dai *codec = rtd->codec_dai;
|
||||||
|
+ struct snd_soc_dai *cpu = rtd->cpu_dai;
|
||||||
|
struct seeed_dai_props *dai_props =
|
||||||
|
seeed_priv_to_props(priv, rtd->num);
|
||||||
|
int ret;
|
||||||
|
@@ -636,11 +636,11 @@ static int seeed_voice_card_probe(struct platform_device *pdev)
|
||||||
|
* Use snd_soc_dai_link_component instead of legacy style
|
||||||
|
* It is codec only. but cpu/platform will be supported in the future.
|
||||||
|
* see
|
||||||
|
- * soc-core.c :: snd_soc_init_multicodec()
|
||||||
|
+ * soc-core.c :: snd_soc_init_multicodec()
|
||||||
|
*
|
||||||
|
* "platform" might be removed
|
||||||
|
* see
|
||||||
|
- * simple-card-utils.c :: asoc_simple_canonicalize_platform()
|
||||||
|
+ * simple-card-utils.c :: asoc_simple_canonicalize_platform()
|
||||||
|
*/
|
||||||
|
for (i = 0; i < num; i++) {
|
||||||
|
dai_link[i].cpus = &dai_props[i].cpus;
|
||||||
|
diff --git a/sound-compatible-4.18.h b/sound-compatible-4.18.h
|
||||||
|
index 080325b..eefa7de 100644
|
||||||
|
--- a/sound-compatible-4.18.h
|
||||||
|
+++ b/sound-compatible-4.18.h
|
||||||
|
@@ -16,6 +16,10 @@
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0)
|
||||||
|
+#ifndef __has_attribute
|
||||||
|
+# define __has_attribute(x) __GCC4_has_attribute_##x
|
||||||
|
+# define __GCC4_has_attribute___fallthrough__ 0
|
||||||
|
+#endif
|
||||||
|
#if __has_attribute(__fallthrough__)
|
||||||
|
# define fallthrough __attribute__((__fallthrough__))
|
||||||
|
#else
|
||||||
|
@@ -31,11 +35,7 @@
|
||||||
|
#define snd_soc_codec_get_dapm snd_soc_component_get_dapm
|
||||||
|
#define snd_soc_codec_get_bias_level snd_soc_component_get_bias_level
|
||||||
|
#define snd_soc_kcontrol_codec snd_soc_kcontrol_component
|
||||||
|
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,9,0)
|
||||||
|
-#define snd_soc_read snd_soc_component_read
|
||||||
|
-#else
|
||||||
|
#define snd_soc_read snd_soc_component_read32
|
||||||
|
-#endif
|
||||||
|
#define snd_soc_register_codec devm_snd_soc_register_component
|
||||||
|
#define snd_soc_unregister_codec snd_soc_unregister_component
|
||||||
|
#define snd_soc_update_bits snd_soc_component_update_bits
|
||||||
|
diff --git a/wm8960.c b/wm8960.c
|
||||||
|
index 465c6dc..34d4dad 100644
|
||||||
|
--- a/wm8960.c
|
||||||
|
+++ b/wm8960.c
|
||||||
|
@@ -796,7 +796,7 @@ static int wm8960_hw_free(struct snd_pcm_substream *substream,
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
-static int wm8960_mute(struct snd_soc_dai *dai, int mute, int direction)
|
||||||
|
+static int wm8960_mute(struct snd_soc_dai *dai, int mute)
|
||||||
|
{
|
||||||
|
struct snd_soc_codec *codec = dai->codec;
|
||||||
|
|
||||||
|
@@ -1236,12 +1236,11 @@ static int wm8960_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
|
||||||
|
static const struct snd_soc_dai_ops wm8960_dai_ops = {
|
||||||
|
.hw_params = wm8960_hw_params,
|
||||||
|
.hw_free = wm8960_hw_free,
|
||||||
|
- .mute_stream = wm8960_mute,
|
||||||
|
+ .digital_mute = wm8960_mute,
|
||||||
|
.set_fmt = wm8960_set_dai_fmt,
|
||||||
|
.set_clkdiv = wm8960_set_dai_clkdiv,
|
||||||
|
.set_pll = wm8960_set_dai_pll,
|
||||||
|
.set_sysclk = wm8960_set_dai_sysclk,
|
||||||
|
- .no_capture_mute = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct snd_soc_dai_driver wm8960_dai = {
|
71
patches/back-to-v5.8.diff
Normal file
71
patches/back-to-v5.8.diff
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
diff --git a/ac108.c b/ac108.c
|
||||||
|
index 4663df0..67edeae 100644
|
||||||
|
--- a/ac108.c
|
||||||
|
+++ b/ac108.c
|
||||||
|
@@ -1124,7 +1124,7 @@ void ac108_aif_shutdown(struct snd_pcm_substream *substream,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-int ac108_aif_mute(struct snd_soc_dai *dai, int mute, int direction) {
|
||||||
|
+int ac108_aif_mute(struct snd_soc_dai *dai, int mute) {
|
||||||
|
struct snd_soc_codec *codec = dai->codec;
|
||||||
|
struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
|
||||||
|
|
||||||
|
@@ -1145,13 +1145,12 @@ static const struct snd_soc_dai_ops ac108_dai_ops = {
|
||||||
|
.hw_params = ac108_hw_params,
|
||||||
|
.prepare = ac108_prepare,
|
||||||
|
.trigger = ac108_trigger,
|
||||||
|
- .mute_stream = ac108_aif_mute,
|
||||||
|
+ .digital_mute = ac108_aif_mute,
|
||||||
|
|
||||||
|
/*DAI format configuration*/
|
||||||
|
.set_fmt = ac108_set_fmt,
|
||||||
|
|
||||||
|
// .hw_free = ac108_hw_free,
|
||||||
|
- .no_capture_mute = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct snd_soc_dai_driver ac108_dai0 = {
|
||||||
|
diff --git a/sound-compatible-4.18.h b/sound-compatible-4.18.h
|
||||||
|
index 080325b..faed848 100644
|
||||||
|
--- a/sound-compatible-4.18.h
|
||||||
|
+++ b/sound-compatible-4.18.h
|
||||||
|
@@ -31,11 +31,7 @@
|
||||||
|
#define snd_soc_codec_get_dapm snd_soc_component_get_dapm
|
||||||
|
#define snd_soc_codec_get_bias_level snd_soc_component_get_bias_level
|
||||||
|
#define snd_soc_kcontrol_codec snd_soc_kcontrol_component
|
||||||
|
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,9,0)
|
||||||
|
-#define snd_soc_read snd_soc_component_read
|
||||||
|
-#else
|
||||||
|
#define snd_soc_read snd_soc_component_read32
|
||||||
|
-#endif
|
||||||
|
#define snd_soc_register_codec devm_snd_soc_register_component
|
||||||
|
#define snd_soc_unregister_codec snd_soc_unregister_component
|
||||||
|
#define snd_soc_update_bits snd_soc_component_update_bits
|
||||||
|
diff --git a/wm8960.c b/wm8960.c
|
||||||
|
index 465c6dc..34d4dad 100644
|
||||||
|
--- a/wm8960.c
|
||||||
|
+++ b/wm8960.c
|
||||||
|
@@ -796,7 +796,7 @@ static int wm8960_hw_free(struct snd_pcm_substream *substream,
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
-static int wm8960_mute(struct snd_soc_dai *dai, int mute, int direction)
|
||||||
|
+static int wm8960_mute(struct snd_soc_dai *dai, int mute)
|
||||||
|
{
|
||||||
|
struct snd_soc_codec *codec = dai->codec;
|
||||||
|
|
||||||
|
@@ -1236,12 +1236,11 @@ static int wm8960_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
|
||||||
|
static const struct snd_soc_dai_ops wm8960_dai_ops = {
|
||||||
|
.hw_params = wm8960_hw_params,
|
||||||
|
.hw_free = wm8960_hw_free,
|
||||||
|
- .mute_stream = wm8960_mute,
|
||||||
|
+ .digital_mute = wm8960_mute,
|
||||||
|
.set_fmt = wm8960_set_dai_fmt,
|
||||||
|
.set_clkdiv = wm8960_set_dai_clkdiv,
|
||||||
|
.set_pll = wm8960_set_dai_pll,
|
||||||
|
.set_sysclk = wm8960_set_dai_sysclk,
|
||||||
|
- .no_capture_mute = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct snd_soc_dai_driver wm8960_dai = {
|
|
@ -13,7 +13,7 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
fragment@1 {
|
fragment@1 {
|
||||||
target-path = "/clocks";
|
target-path = "/";
|
||||||
__overlay__ {
|
__overlay__ {
|
||||||
ac108_mclk: codec-mclk {
|
ac108_mclk: codec-mclk {
|
||||||
compatible = "fixed-clock";
|
compatible = "fixed-clock";
|
||||||
|
|
Binary file not shown.
|
@ -13,7 +13,7 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
fragment@1 {
|
fragment@1 {
|
||||||
target-path = "/clocks";
|
target-path = "/";
|
||||||
__overlay__ {
|
__overlay__ {
|
||||||
ac10x_mclk: codec-mclk {
|
ac10x_mclk: codec-mclk {
|
||||||
compatible = "fixed-clock";
|
compatible = "fixed-clock";
|
||||||
|
|
Binary file not shown.
|
@ -21,13 +21,18 @@
|
||||||
# THE SOFTWARE.
|
# THE SOFTWARE.
|
||||||
|
|
||||||
set -x
|
set -x
|
||||||
exec 1>/var/log/$(basename $0).log 2>&1
|
#exec 1>/var/log/$(basename $0).log 2>&1
|
||||||
|
|
||||||
|
export PATH=$PATH:/opt/vc/bin
|
||||||
|
OVERLAYS=/boot/overlays
|
||||||
|
[ -d /boot/firmware/overlays ] && OVERLAYS=/boot/firmware/overlays
|
||||||
|
|
||||||
#enable i2c interface
|
#enable i2c interface
|
||||||
dtparam i2c_arm=on
|
dtparam -d $OVERLAYS i2c_arm=on
|
||||||
modprobe i2c-dev
|
modprobe i2c-dev
|
||||||
|
|
||||||
#enable spi interface
|
#enable spi interface
|
||||||
dtparam spi=on
|
dtparam -d $OVERLAYS spi=on
|
||||||
|
|
||||||
_VER_RUN=
|
_VER_RUN=
|
||||||
function get_kernel_version() {
|
function get_kernel_version() {
|
||||||
|
@ -37,13 +42,17 @@ function get_kernel_version() {
|
||||||
[ -z "$_VER_RUN" ] && {
|
[ -z "$_VER_RUN" ] && {
|
||||||
ZIMAGE=/boot/kernel.img
|
ZIMAGE=/boot/kernel.img
|
||||||
IMG_OFFSET=$(LC_ALL=C grep -abo $'\x1f\x8b\x08\x00' $ZIMAGE | head -n 1 | cut -d ':' -f 1)
|
IMG_OFFSET=$(LC_ALL=C grep -abo $'\x1f\x8b\x08\x00' $ZIMAGE | head -n 1 | cut -d ':' -f 1)
|
||||||
_VER_RUN=$(dd if=$ZIMAGE obs=64K ibs=4 skip=$(( IMG_OFFSET / 4)) | zcat | grep -a -m1 "Linux version" | strings | awk '{ print $3; }')
|
# 64-bit-only kernel package
|
||||||
|
[ ! -f /boot/kernel.img ] && [ -f /boot/kernel8.img ] && ZIMAGE=/boot/kernel8.img
|
||||||
|
_VER_RUN=$(dd if=$ZIMAGE obs=64K ibs=4 skip=$(( IMG_OFFSET / 4)) 2>/dev/null | zcat | grep -a -m1 "Linux version" | LC_ALL=C sed -e 's/^.*Linux/Linux/' | strings | awk '{ print $3; }')
|
||||||
}
|
}
|
||||||
echo "$_VER_RUN"
|
echo "$_VER_RUN"
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
CONFIG=/boot/config.txt
|
CONFIG=/boot/config.txt
|
||||||
|
[ -f /boot/firmware/usercfg.txt ] && CONFIG=/boot/firmware/usercfg.txt
|
||||||
|
|
||||||
get_overlay() {
|
get_overlay() {
|
||||||
ov=$1
|
ov=$1
|
||||||
if grep -q -E "^dtoverlay=$ov" $CONFIG; then
|
if grep -q -E "^dtoverlay=$ov" $CONFIG; then
|
||||||
|
@ -115,25 +124,23 @@ if [ "$overlay" ]; then
|
||||||
rm /etc/asound.conf
|
rm /etc/asound.conf
|
||||||
rm /var/lib/alsa/asound.state
|
rm /var/lib/alsa/asound.state
|
||||||
|
|
||||||
: <<\EOF
|
kernel_ver=$(uname -r) # get_kernel_version)
|
||||||
kernel_ver=$(get_kernel_version)
|
|
||||||
# echo kernel_ver=$kernel_ver
|
# echo kernel_ver=$kernel_ver
|
||||||
|
|
||||||
# TODO: dynamic dtoverlay Bug of v4.19.x
|
# TODO: dynamic dtoverlay Bug of v4.19.x
|
||||||
# no DT node phandle inserted.
|
# no DT node phandle inserted.
|
||||||
if [[ "$kernel_ver" =~ ^4\.19.*$ ]]; then
|
if [[ "$kernel_ver" =~ ^4\.19.*$ || "$kernel_ver" =~ ^5\.*$ ]]; then
|
||||||
for i in $RPI_HATS; do
|
for i in $RPI_HATS; do
|
||||||
if [ "$i" == "$overlay" ]; then
|
if [ "$i" == "$overlay" ]; then
|
||||||
do_overlay $overlay 0
|
/bin/true #do_overlay $overlay 0
|
||||||
else
|
else
|
||||||
echo Uninstall $i ...
|
echo Uninstall $i ...
|
||||||
do_overlay $i 1
|
/bin/true #do_overlay $i 1
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
EOF
|
|
||||||
#make sure the driver loads correctly
|
#make sure the driver loads correctly
|
||||||
dtoverlay $overlay || true
|
dtoverlay -d $OVERLAYS $overlay || true
|
||||||
|
|
||||||
|
|
||||||
echo "create $overlay asound configure file"
|
echo "create $overlay asound configure file"
|
||||||
|
@ -145,5 +152,12 @@ fi
|
||||||
alsactl restore
|
alsactl restore
|
||||||
|
|
||||||
#Force 3.5mm ('headphone') jack
|
#Force 3.5mm ('headphone') jack
|
||||||
amixer cset numid=3 1
|
# The Raspberry Pi 4, released on 24th Jun 2019, has two HDMI ports,
|
||||||
|
# and can drive two displays with audios for two users simultaneously,
|
||||||
|
# in a "multiseat" configuration. The earlier single virtual ALSA
|
||||||
|
# option for re-directing audio playback between headphone jack and HDMI
|
||||||
|
# via a 'Routing' mixer setting was turned off eventually to allow
|
||||||
|
# simultaneous usage of all 3 playback devices.
|
||||||
|
if aplay -l | grep -q "bcm2835 ALSA"; then
|
||||||
|
amixer cset numid=3 1 || true
|
||||||
|
fi
|
||||||
|
|
|
@ -28,6 +28,22 @@
|
||||||
#include <sound/simple_card_utils.h>
|
#include <sound/simple_card_utils.h>
|
||||||
#include "ac10x.h"
|
#include "ac10x.h"
|
||||||
|
|
||||||
|
#define LINUX_VERSION_IS_GEQ(x1,x2,x3) (LINUX_VERSION_CODE >= KERNEL_VERSION(x1,x2,x3))
|
||||||
|
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,13,0)
|
||||||
|
#define asoc_simple_parse_clk_cpu(dev, node, dai_link, simple_dai) \
|
||||||
|
asoc_simple_parse_clk(dev, node, simple_dai, dai_link->cpus)
|
||||||
|
#define asoc_simple_parse_clk_codec(dev, node, dai_link, simple_dai) \
|
||||||
|
asoc_simple_parse_clk(dev, node, simple_dai, dai_link->codecs)
|
||||||
|
#define asoc_simple_parse_cpu(node, dai_link, is_single_link) \
|
||||||
|
asoc_simple_parse_dai(node, dai_link->cpus, is_single_link)
|
||||||
|
#define asoc_simple_parse_codec(node, dai_link) \
|
||||||
|
asoc_simple_parse_dai(node, dai_link->codecs, NULL)
|
||||||
|
#define asoc_simple_parse_platform(node, dai_link) \
|
||||||
|
asoc_simple_parse_dai(node, dai_link->platforms, NULL)
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* single codec:
|
* single codec:
|
||||||
* 0 - allow multi codec
|
* 0 - allow multi codec
|
||||||
|
@ -40,6 +56,9 @@ struct seeed_card_data {
|
||||||
struct seeed_dai_props {
|
struct seeed_dai_props {
|
||||||
struct asoc_simple_dai cpu_dai;
|
struct asoc_simple_dai cpu_dai;
|
||||||
struct asoc_simple_dai codec_dai;
|
struct asoc_simple_dai codec_dai;
|
||||||
|
struct snd_soc_dai_link_component cpus; /* single cpu */
|
||||||
|
struct snd_soc_dai_link_component codecs; /* single codec */
|
||||||
|
struct snd_soc_dai_link_component platforms;
|
||||||
unsigned int mclk_fs;
|
unsigned int mclk_fs;
|
||||||
} *dai_props;
|
} *dai_props;
|
||||||
unsigned int mclk_fs;
|
unsigned int mclk_fs;
|
||||||
|
@ -67,6 +86,7 @@ struct seeed_card_info {
|
||||||
struct asoc_simple_dai codec_dai;
|
struct asoc_simple_dai codec_dai;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define seeed_priv_to_card(priv) (&(priv)->snd_card)
|
||||||
#define seeed_priv_to_dev(priv) ((priv)->snd_card.dev)
|
#define seeed_priv_to_dev(priv) ((priv)->snd_card.dev)
|
||||||
#define seeed_priv_to_link(priv, i) ((priv)->snd_card.dai_link + (i))
|
#define seeed_priv_to_link(priv, i) ((priv)->snd_card.dai_link + (i))
|
||||||
#define seeed_priv_to_props(priv, i) ((priv)->dai_props + (i))
|
#define seeed_priv_to_props(priv, i) ((priv)->dai_props + (i))
|
||||||
|
@ -91,16 +111,16 @@ static int seeed_voice_card_startup(struct snd_pcm_substream *substream)
|
||||||
if (ret)
|
if (ret)
|
||||||
clk_disable_unprepare(dai_props->cpu_dai.clk);
|
clk_disable_unprepare(dai_props->cpu_dai.clk);
|
||||||
|
|
||||||
if (rtd->cpu_dai->driver->playback.channels_min) {
|
if (asoc_rtd_to_cpu(rtd, 0)->driver->playback.channels_min) {
|
||||||
priv->channels_playback_default = rtd->cpu_dai->driver->playback.channels_min;
|
priv->channels_playback_default = asoc_rtd_to_cpu(rtd, 0)->driver->playback.channels_min;
|
||||||
}
|
}
|
||||||
if (rtd->cpu_dai->driver->capture.channels_min) {
|
if (asoc_rtd_to_cpu(rtd, 0)->driver->capture.channels_min) {
|
||||||
priv->channels_capture_default = rtd->cpu_dai->driver->capture.channels_min;
|
priv->channels_capture_default = asoc_rtd_to_cpu(rtd, 0)->driver->capture.channels_min;
|
||||||
}
|
}
|
||||||
rtd->cpu_dai->driver->playback.channels_min = priv->channels_playback_override;
|
asoc_rtd_to_cpu(rtd, 0)->driver->playback.channels_min = priv->channels_playback_override;
|
||||||
rtd->cpu_dai->driver->playback.channels_max = priv->channels_playback_override;
|
asoc_rtd_to_cpu(rtd, 0)->driver->playback.channels_max = priv->channels_playback_override;
|
||||||
rtd->cpu_dai->driver->capture.channels_min = priv->channels_capture_override;
|
asoc_rtd_to_cpu(rtd, 0)->driver->capture.channels_min = priv->channels_capture_override;
|
||||||
rtd->cpu_dai->driver->capture.channels_max = priv->channels_capture_override;
|
asoc_rtd_to_cpu(rtd, 0)->driver->capture.channels_max = priv->channels_capture_override;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -112,10 +132,10 @@ static void seeed_voice_card_shutdown(struct snd_pcm_substream *substream)
|
||||||
struct seeed_dai_props *dai_props =
|
struct seeed_dai_props *dai_props =
|
||||||
seeed_priv_to_props(priv, rtd->num);
|
seeed_priv_to_props(priv, rtd->num);
|
||||||
|
|
||||||
rtd->cpu_dai->driver->playback.channels_min = priv->channels_playback_default;
|
asoc_rtd_to_cpu(rtd, 0)->driver->playback.channels_min = priv->channels_playback_default;
|
||||||
rtd->cpu_dai->driver->playback.channels_max = priv->channels_playback_default;
|
asoc_rtd_to_cpu(rtd, 0)->driver->playback.channels_max = priv->channels_playback_default;
|
||||||
rtd->cpu_dai->driver->capture.channels_min = priv->channels_capture_default;
|
asoc_rtd_to_cpu(rtd, 0)->driver->capture.channels_min = priv->channels_capture_default;
|
||||||
rtd->cpu_dai->driver->capture.channels_max = priv->channels_capture_default;
|
asoc_rtd_to_cpu(rtd, 0)->driver->capture.channels_max = priv->channels_capture_default;
|
||||||
|
|
||||||
clk_disable_unprepare(dai_props->cpu_dai.clk);
|
clk_disable_unprepare(dai_props->cpu_dai.clk);
|
||||||
|
|
||||||
|
@ -126,8 +146,8 @@ static int seeed_voice_card_hw_params(struct snd_pcm_substream *substream,
|
||||||
struct snd_pcm_hw_params *params)
|
struct snd_pcm_hw_params *params)
|
||||||
{
|
{
|
||||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
|
||||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
|
||||||
struct seeed_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
|
struct seeed_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
|
||||||
struct seeed_dai_props *dai_props =
|
struct seeed_dai_props *dai_props =
|
||||||
seeed_priv_to_props(priv, rtd->num);
|
seeed_priv_to_props(priv, rtd->num);
|
||||||
|
@ -157,9 +177,9 @@ err:
|
||||||
}
|
}
|
||||||
|
|
||||||
#define _SET_CLOCK_CNT 2
|
#define _SET_CLOCK_CNT 2
|
||||||
static int (* _set_clock[_SET_CLOCK_CNT])(int y_start_n_stop);
|
static int (* _set_clock[_SET_CLOCK_CNT])(int y_start_n_stop, struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai);
|
||||||
|
|
||||||
int seeed_voice_card_register_set_clock(int stream, int (*set_clock)(int)) {
|
int seeed_voice_card_register_set_clock(int stream, int (*set_clock)(int, struct snd_pcm_substream *, int, struct snd_soc_dai *)) {
|
||||||
if (! _set_clock[stream]) {
|
if (! _set_clock[stream]) {
|
||||||
_set_clock[stream] = set_clock;
|
_set_clock[stream] = set_clock;
|
||||||
}
|
}
|
||||||
|
@ -176,10 +196,10 @@ static void work_cb_codec_clk(struct work_struct *work)
|
||||||
int r = 0;
|
int r = 0;
|
||||||
|
|
||||||
if (_set_clock[SNDRV_PCM_STREAM_CAPTURE]) {
|
if (_set_clock[SNDRV_PCM_STREAM_CAPTURE]) {
|
||||||
r = r || _set_clock[SNDRV_PCM_STREAM_CAPTURE](0);
|
r = r || _set_clock[SNDRV_PCM_STREAM_CAPTURE](0, NULL, 0, NULL); /* not using 2nd to 4th arg if 1st == 0 */
|
||||||
}
|
}
|
||||||
if (_set_clock[SNDRV_PCM_STREAM_PLAYBACK]) {
|
if (_set_clock[SNDRV_PCM_STREAM_PLAYBACK]) {
|
||||||
r = r || _set_clock[SNDRV_PCM_STREAM_PLAYBACK](0);
|
r = r || _set_clock[SNDRV_PCM_STREAM_PLAYBACK](0, NULL, 0, NULL); /* not using 2nd to 4th arg if 1st == 0 */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r && priv->try_stop++ < TRY_STOP_MAX) {
|
if (r && priv->try_stop++ < TRY_STOP_MAX) {
|
||||||
|
@ -191,7 +211,7 @@ static void work_cb_codec_clk(struct work_struct *work)
|
||||||
static int seeed_voice_card_trigger(struct snd_pcm_substream *substream, int cmd)
|
static int seeed_voice_card_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||||
{
|
{
|
||||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||||
struct snd_soc_dai *dai = rtd->codec_dai;
|
struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
|
||||||
struct seeed_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
|
struct seeed_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
|
||||||
#if CONFIG_AC10X_TRIG_LOCK
|
#if CONFIG_AC10X_TRIG_LOCK
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
@ -200,7 +220,7 @@ static int seeed_voice_card_trigger(struct snd_pcm_substream *substream, int cmd
|
||||||
|
|
||||||
dev_dbg(rtd->card->dev, "%s() stream=%s cmd=%d play:%d, capt:%d\n",
|
dev_dbg(rtd->card->dev, "%s() stream=%s cmd=%d play:%d, capt:%d\n",
|
||||||
__FUNCTION__, snd_pcm_stream_str(substream), cmd,
|
__FUNCTION__, snd_pcm_stream_str(substream), cmd,
|
||||||
dai->playback_active, dai->capture_active);
|
dai->stream[SNDRV_PCM_STREAM_PLAYBACK].active, dai->stream[SNDRV_PCM_STREAM_CAPTURE].active);
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case SNDRV_PCM_TRIGGER_START:
|
case SNDRV_PCM_TRIGGER_START:
|
||||||
|
@ -211,8 +231,8 @@ static int seeed_voice_card_trigger(struct snd_pcm_substream *substream, int cmd
|
||||||
/* I know it will degrades performance, but I have no choice */
|
/* I know it will degrades performance, but I have no choice */
|
||||||
spin_lock_irqsave(&priv->lock, flags);
|
spin_lock_irqsave(&priv->lock, flags);
|
||||||
#endif
|
#endif
|
||||||
if (_set_clock[SNDRV_PCM_STREAM_CAPTURE]) _set_clock[SNDRV_PCM_STREAM_CAPTURE](1);
|
// if (_set_clock[SNDRV_PCM_STREAM_CAPTURE]) _set_clock[SNDRV_PCM_STREAM_CAPTURE](1, substream, cmd, dai);
|
||||||
if (_set_clock[SNDRV_PCM_STREAM_PLAYBACK]) _set_clock[SNDRV_PCM_STREAM_PLAYBACK](1);
|
// if (_set_clock[SNDRV_PCM_STREAM_PLAYBACK]) _set_clock[SNDRV_PCM_STREAM_PLAYBACK](1, substream, cmd, dai);
|
||||||
#if CONFIG_AC10X_TRIG_LOCK
|
#if CONFIG_AC10X_TRIG_LOCK
|
||||||
spin_unlock_irqrestore(&priv->lock, flags);
|
spin_unlock_irqrestore(&priv->lock, flags);
|
||||||
#endif
|
#endif
|
||||||
|
@ -222,7 +242,7 @@ static int seeed_voice_card_trigger(struct snd_pcm_substream *substream, int cmd
|
||||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||||
/* capture channel resync, if overrun */
|
/* capture channel resync, if overrun */
|
||||||
if (dai->capture_active && substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
if (dai->stream[SNDRV_PCM_STREAM_CAPTURE].active && substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,14 +252,18 @@ static int seeed_voice_card_trigger(struct snd_pcm_substream *substream, int cmd
|
||||||
if (0 != schedule_work(&priv->work_codec_clk)) {
|
if (0 != schedule_work(&priv->work_codec_clk)) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (_set_clock[SNDRV_PCM_STREAM_CAPTURE]) _set_clock[SNDRV_PCM_STREAM_CAPTURE](0);
|
// if (_set_clock[SNDRV_PCM_STREAM_CAPTURE]) _set_clock[SNDRV_PCM_STREAM_CAPTURE](0, NULL, 0, NULL); /* not using 2nd to 4th arg if 1st == 0 */
|
||||||
if (_set_clock[SNDRV_PCM_STREAM_PLAYBACK]) _set_clock[SNDRV_PCM_STREAM_PLAYBACK](0);
|
// if (_set_clock[SNDRV_PCM_STREAM_PLAYBACK]) _set_clock[SNDRV_PCM_STREAM_PLAYBACK](0, NULL, 0, NULL); /* not using 2nd to 4th arg if 1st == 0 */
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dev_dbg(rtd->card->dev, "%s() stream=%s cmd=%d play:%d, capt:%d;finished %d\n",
|
||||||
|
__FUNCTION__, snd_pcm_stream_str(substream), cmd,
|
||||||
|
dai->stream[SNDRV_PCM_STREAM_PLAYBACK].active, dai->stream[SNDRV_PCM_STREAM_CAPTURE].active, ret);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,23 +274,165 @@ static struct snd_soc_ops seeed_voice_card_ops = {
|
||||||
.trigger = seeed_voice_card_trigger,
|
.trigger = seeed_voice_card_trigger,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int asoc_simple_parse_dai(struct device_node *node,
|
||||||
|
struct snd_soc_dai_link_component *dlc,
|
||||||
|
int *is_single_link)
|
||||||
|
{
|
||||||
|
struct of_phandle_args args;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!node)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get node via "sound-dai = <&phandle port>"
|
||||||
|
* it will be used as xxx_of_node on soc_bind_dai_link()
|
||||||
|
*/
|
||||||
|
ret = of_parse_phandle_with_args(node, DAI, CELL, 0, &args);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FIXME
|
||||||
|
*
|
||||||
|
* Here, dlc->dai_name is pointer to CPU/Codec DAI name.
|
||||||
|
* If user unbinded CPU or Codec driver, but not for Sound Card,
|
||||||
|
* dlc->dai_name is keeping unbinded CPU or Codec
|
||||||
|
* driver's pointer.
|
||||||
|
*
|
||||||
|
* If user re-bind CPU or Codec driver again, ALSA SoC will try
|
||||||
|
* to rebind Card via snd_soc_try_rebind_card(), but because of
|
||||||
|
* above reason, it might can't bind Sound Card.
|
||||||
|
* Because Sound Card is pointing to released dai_name pointer.
|
||||||
|
*
|
||||||
|
* To avoid this rebind Card issue,
|
||||||
|
* 1) It needs to alloc memory to keep dai_name eventhough
|
||||||
|
* CPU or Codec driver was unbinded, or
|
||||||
|
* 2) user need to rebind Sound Card everytime
|
||||||
|
* if he unbinded CPU or Codec.
|
||||||
|
*/
|
||||||
|
ret = snd_soc_of_get_dai_name(node, &dlc->dai_name, 0);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
dlc->of_node = args.np;
|
||||||
|
|
||||||
|
if (is_single_link)
|
||||||
|
*is_single_link = !args.args_count;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int asoc_simple_init_dai(struct snd_soc_dai *dai,
|
||||||
|
struct asoc_simple_dai *simple_dai)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!simple_dai)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (simple_dai->sysclk) {
|
||||||
|
ret = snd_soc_dai_set_sysclk(dai, 0, simple_dai->sysclk,
|
||||||
|
simple_dai->clk_direction);
|
||||||
|
if (ret && ret != -ENOTSUPP) {
|
||||||
|
dev_err(dai->dev, "simple-card: set_sysclk error\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (simple_dai->slots) {
|
||||||
|
ret = snd_soc_dai_set_bclk_ratio(dai,
|
||||||
|
simple_dai->slots *
|
||||||
|
simple_dai->slot_width);
|
||||||
|
if (ret && ret != -ENOTSUPP) {
|
||||||
|
dev_err(dai->dev, "simple-card: set_tdm_slot error\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,7,0)
|
||||||
|
static inline int asoc_simple_component_is_codec(struct snd_soc_component *component)
|
||||||
|
{
|
||||||
|
return component->driver->endianness;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int asoc_simple_init_dai_link_params(struct snd_soc_pcm_runtime *rtd)
|
||||||
|
{
|
||||||
|
struct snd_soc_dai_link *dai_link = rtd->dai_link;
|
||||||
|
struct snd_soc_component *component;
|
||||||
|
struct snd_soc_pcm_stream *params;
|
||||||
|
struct snd_pcm_hardware hw;
|
||||||
|
int i, ret, stream;
|
||||||
|
|
||||||
|
/* Only Codecs */
|
||||||
|
for_each_rtd_components(rtd, i, component) {
|
||||||
|
if (!asoc_simple_component_is_codec(component))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Assumes the capabilities are the same for all supported streams */
|
||||||
|
for (stream = 0; stream < 2; stream++) {
|
||||||
|
ret = snd_soc_runtime_calc_hw(rtd, &hw, stream);
|
||||||
|
if (ret == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(rtd->dev, "simple-card: no valid dai_link params\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
params = devm_kzalloc(rtd->dev, sizeof(*params), GFP_KERNEL);
|
||||||
|
if (!params)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
params->formats = hw.formats;
|
||||||
|
params->rates = hw.rates;
|
||||||
|
params->rate_min = hw.rate_min;
|
||||||
|
params->rate_max = hw.rate_max;
|
||||||
|
params->channels_min = hw.channels_min;
|
||||||
|
params->channels_max = hw.channels_max;
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,4,0)
|
||||||
|
dai_link->c2c_params = params;
|
||||||
|
dai_link->num_c2c_params = 1;
|
||||||
|
#else
|
||||||
|
/* apparently this goes back to 5.6.x */
|
||||||
|
dai_link->params = params;
|
||||||
|
dai_link->num_params = 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static int seeed_voice_card_dai_init(struct snd_soc_pcm_runtime *rtd)
|
static int seeed_voice_card_dai_init(struct snd_soc_pcm_runtime *rtd)
|
||||||
{
|
{
|
||||||
struct seeed_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
|
struct seeed_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
|
||||||
struct snd_soc_dai *codec = rtd->codec_dai;
|
struct snd_soc_dai *codec = asoc_rtd_to_codec(rtd, 0);
|
||||||
struct snd_soc_dai *cpu = rtd->cpu_dai;
|
struct snd_soc_dai *cpu = asoc_rtd_to_cpu(rtd, 0);
|
||||||
struct seeed_dai_props *dai_props =
|
struct seeed_dai_props *dai_props =
|
||||||
seeed_priv_to_props(priv, rtd->num);
|
seeed_priv_to_props(priv, rtd->num);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = asoc_simple_card_init_dai(codec, &dai_props->codec_dai);
|
ret = asoc_simple_init_dai(codec, &dai_props->codec_dai);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = asoc_simple_card_init_dai(cpu, &dai_props->cpu_dai);
|
ret = asoc_simple_init_dai(cpu, &dai_props->cpu_dai);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,7,0)
|
||||||
|
ret = asoc_simple_init_dai_link_params(rtd);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
dev_dbg(rtd->card->dev, "codec \"%s\" mapping to cpu \"%s\"\n", codec->name, cpu->name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -312,20 +478,19 @@ static int seeed_voice_card_dai_link_of(struct device_node *node,
|
||||||
goto dai_link_of_err;
|
goto dai_link_of_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = asoc_simple_card_parse_daifmt(dev, node, codec,
|
ret = asoc_simple_parse_daifmt(dev, node, codec,
|
||||||
prefix, &dai_link->dai_fmt);
|
prefix, &dai_link->dai_fmt);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto dai_link_of_err;
|
goto dai_link_of_err;
|
||||||
|
|
||||||
of_property_read_u32(node, "mclk-fs", &dai_props->mclk_fs);
|
of_property_read_u32(node, "mclk-fs", &dai_props->mclk_fs);
|
||||||
|
|
||||||
ret = asoc_simple_card_parse_cpu(cpu, dai_link,
|
ret = asoc_simple_parse_cpu(cpu, dai_link, &single_cpu);
|
||||||
DAI, CELL, &single_cpu);
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto dai_link_of_err;
|
goto dai_link_of_err;
|
||||||
|
|
||||||
#if _SINGLE_CODEC
|
#if _SINGLE_CODEC
|
||||||
ret = asoc_simple_card_parse_codec(codec, dai_link, DAI, CELL);
|
ret = asoc_simple_parse_codec(codec, dai_link);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto dai_link_of_err;
|
goto dai_link_of_err;
|
||||||
#else
|
#else
|
||||||
|
@ -337,7 +502,7 @@ static int seeed_voice_card_dai_link_of(struct device_node *node,
|
||||||
dev_dbg(dev, "dai_link num_codecs = %d\n", dai_link->num_codecs);
|
dev_dbg(dev, "dai_link num_codecs = %d\n", dai_link->num_codecs);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ret = asoc_simple_card_parse_platform(plat, dai_link, DAI, CELL);
|
ret = asoc_simple_parse_platform(plat, dai_link);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto dai_link_of_err;
|
goto dai_link_of_err;
|
||||||
|
|
||||||
|
@ -362,7 +527,7 @@ static int seeed_voice_card_dai_link_of(struct device_node *node,
|
||||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,10,0)
|
#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,10,0)
|
||||||
ret = asoc_simple_card_parse_clk_cpu(cpu, dai_link, cpu_dai);
|
ret = asoc_simple_card_parse_clk_cpu(cpu, dai_link, cpu_dai);
|
||||||
#else
|
#else
|
||||||
ret = asoc_simple_card_parse_clk_cpu(dev, cpu, dai_link, cpu_dai);
|
ret = asoc_simple_parse_clk_cpu(dev, cpu, dai_link, cpu_dai);
|
||||||
#endif
|
#endif
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto dai_link_of_err;
|
goto dai_link_of_err;
|
||||||
|
@ -370,22 +535,16 @@ static int seeed_voice_card_dai_link_of(struct device_node *node,
|
||||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,10,0)
|
#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,10,0)
|
||||||
ret = asoc_simple_card_parse_clk_codec(codec, dai_link, codec_dai);
|
ret = asoc_simple_card_parse_clk_codec(codec, dai_link, codec_dai);
|
||||||
#else
|
#else
|
||||||
ret = asoc_simple_card_parse_clk_codec(dev, codec, dai_link, codec_dai);
|
ret = asoc_simple_parse_clk_codec(dev, codec, dai_link, codec_dai);
|
||||||
#endif
|
#endif
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto dai_link_of_err;
|
goto dai_link_of_err;
|
||||||
|
|
||||||
#if _SINGLE_CODEC
|
ret = asoc_simple_set_dailink_name(dev, dai_link,
|
||||||
ret = asoc_simple_card_canonicalize_dailink(dai_link);
|
|
||||||
if (ret < 0)
|
|
||||||
goto dai_link_of_err;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ret = asoc_simple_card_set_dailink_name(dev, dai_link,
|
|
||||||
"%s-%s",
|
"%s-%s",
|
||||||
dai_link->cpu_dai_name,
|
dai_link->cpus->dai_name,
|
||||||
#if _SINGLE_CODEC
|
#if _SINGLE_CODEC
|
||||||
dai_link->codec_dai_name
|
dai_link->codecs->dai_name
|
||||||
#else
|
#else
|
||||||
dai_link->codecs[0].dai_name
|
dai_link->codecs[0].dai_name
|
||||||
#endif
|
#endif
|
||||||
|
@ -399,17 +558,27 @@ static int seeed_voice_card_dai_link_of(struct device_node *node,
|
||||||
dev_dbg(dev, "\tname : %s\n", dai_link->stream_name);
|
dev_dbg(dev, "\tname : %s\n", dai_link->stream_name);
|
||||||
dev_dbg(dev, "\tformat : %04x\n", dai_link->dai_fmt);
|
dev_dbg(dev, "\tformat : %04x\n", dai_link->dai_fmt);
|
||||||
dev_dbg(dev, "\tcpu : %s / %d\n",
|
dev_dbg(dev, "\tcpu : %s / %d\n",
|
||||||
dai_link->cpu_dai_name,
|
dai_link->cpus->dai_name,
|
||||||
dai_props->cpu_dai.sysclk);
|
dai_props->cpu_dai.sysclk);
|
||||||
dev_dbg(dev, "\tcodec : %s / %d\n",
|
dev_dbg(dev, "\tcodec : %s / %d\n",
|
||||||
#if _SINGLE_CODEC
|
#if _SINGLE_CODEC
|
||||||
dai_link->codec_dai_name,
|
dai_link->codecs->dai_name,
|
||||||
#else
|
#else
|
||||||
dai_link->codecs[0].dai_name,
|
dai_link->codecs[0].dai_name,
|
||||||
#endif
|
#endif
|
||||||
dai_props->codec_dai.sysclk);
|
dai_props->codec_dai.sysclk);
|
||||||
|
|
||||||
asoc_simple_card_canonicalize_cpu(dai_link, single_cpu);
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,13,0)
|
||||||
|
asoc_simple_canonicalize_cpu(dai_link->cpus, single_cpu);
|
||||||
|
#if _SINGLE_CODEC
|
||||||
|
asoc_simple_canonicalize_platform(dai_link->platforms, dai_link->cpus);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
asoc_simple_canonicalize_cpu(dai_link, single_cpu);
|
||||||
|
#if _SINGLE_CODEC
|
||||||
|
asoc_simple_canonicalize_platform(dai_link);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
dai_link_of_err:
|
dai_link_of_err:
|
||||||
of_node_put(cpu);
|
of_node_put(cpu);
|
||||||
|
@ -441,7 +610,7 @@ static int seeed_voice_card_parse_aux_devs(struct device_node *node,
|
||||||
aux_node = of_parse_phandle(node, PREFIX "aux-devs", i);
|
aux_node = of_parse_phandle(node, PREFIX "aux-devs", i);
|
||||||
if (!aux_node)
|
if (!aux_node)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
priv->snd_card.aux_dev[i].codec_of_node = aux_node;
|
priv->snd_card.aux_dev[i].dlc.of_node = aux_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
priv->snd_card.num_aux_devs = n;
|
priv->snd_card.num_aux_devs = n;
|
||||||
|
@ -501,7 +670,7 @@ static int seeed_voice_card_parse_of(struct device_node *node,
|
||||||
goto card_parse_end;
|
goto card_parse_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = asoc_simple_card_parse_card_name(&priv->snd_card, PREFIX);
|
ret = asoc_simple_parse_card_name(&priv->snd_card, PREFIX);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto card_parse_end;
|
goto card_parse_end;
|
||||||
|
|
||||||
|
@ -526,6 +695,79 @@ card_parse_end:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
inline void seeed_debug_dai(struct seeed_card_data *priv,
|
||||||
|
char *name,
|
||||||
|
struct asoc_simple_dai *dai)
|
||||||
|
{
|
||||||
|
struct device *dev = seeed_priv_to_dev(priv);
|
||||||
|
|
||||||
|
if (dai->name)
|
||||||
|
dev_dbg(dev, "%s dai name = %s\n",
|
||||||
|
name, dai->name);
|
||||||
|
if (dai->sysclk)
|
||||||
|
dev_dbg(dev, "%s sysclk = %d\n",
|
||||||
|
name, dai->sysclk);
|
||||||
|
|
||||||
|
dev_dbg(dev, "%s direction = %s\n",
|
||||||
|
name, dai->clk_direction ? "OUT" : "IN");
|
||||||
|
|
||||||
|
if (dai->slots)
|
||||||
|
dev_dbg(dev, "%s slots = %d\n", name, dai->slots);
|
||||||
|
if (dai->slot_width)
|
||||||
|
dev_dbg(dev, "%s slot width = %d\n", name, dai->slot_width);
|
||||||
|
if (dai->tx_slot_mask)
|
||||||
|
dev_dbg(dev, "%s tx slot mask = %d\n", name, dai->tx_slot_mask);
|
||||||
|
if (dai->rx_slot_mask)
|
||||||
|
dev_dbg(dev, "%s rx slot mask = %d\n", name, dai->rx_slot_mask);
|
||||||
|
if (dai->clk)
|
||||||
|
dev_dbg(dev, "%s clk %luHz\n", name, clk_get_rate(dai->clk));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void seeed_debug_info(struct seeed_card_data *priv)
|
||||||
|
{
|
||||||
|
struct snd_soc_card *card = seeed_priv_to_card(priv);
|
||||||
|
struct device *dev = seeed_priv_to_dev(priv);
|
||||||
|
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (card->name)
|
||||||
|
dev_dbg(dev, "Card Name: %s\n", card->name);
|
||||||
|
|
||||||
|
for (i = 0; i < card->num_links; i++) {
|
||||||
|
struct seeed_dai_props *props = seeed_priv_to_props(priv, i);
|
||||||
|
struct snd_soc_dai_link *link = seeed_priv_to_link(priv, i);
|
||||||
|
|
||||||
|
dev_dbg(dev, "DAI%d\n", i);
|
||||||
|
|
||||||
|
seeed_debug_dai(priv, "cpu", &props->cpu_dai);
|
||||||
|
seeed_debug_dai(priv, "codec", &props->codec_dai);
|
||||||
|
|
||||||
|
if (link->name)
|
||||||
|
dev_dbg(dev, "dai name = %s\n", link->name);
|
||||||
|
|
||||||
|
dev_dbg(dev, "dai format = %04x\n", link->dai_fmt);
|
||||||
|
|
||||||
|
/*
|
||||||
|
if (props->adata.convert_rate)
|
||||||
|
dev_dbg(dev, "convert_rate = %d\n",
|
||||||
|
props->adata.convert_rate);
|
||||||
|
if (props->adata.convert_channels)
|
||||||
|
dev_dbg(dev, "convert_channels = %d\n",
|
||||||
|
props->adata.convert_channels);
|
||||||
|
if (props->codec_conf && props->codec_conf->name_prefix)
|
||||||
|
dev_dbg(dev, "name prefix = %s\n",
|
||||||
|
props->codec_conf->name_prefix);
|
||||||
|
*/
|
||||||
|
if (props->mclk_fs)
|
||||||
|
dev_dbg(dev, "mclk-fs = %d\n",
|
||||||
|
props->mclk_fs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define seeed_debug_info(priv)
|
||||||
|
#endif /* DEBUG */
|
||||||
|
|
||||||
static int seeed_voice_card_probe(struct platform_device *pdev)
|
static int seeed_voice_card_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct seeed_card_data *priv;
|
struct seeed_card_data *priv;
|
||||||
|
@ -533,7 +775,7 @@ static int seeed_voice_card_probe(struct platform_device *pdev)
|
||||||
struct seeed_dai_props *dai_props;
|
struct seeed_dai_props *dai_props;
|
||||||
struct device_node *np = pdev->dev.of_node;
|
struct device_node *np = pdev->dev.of_node;
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
int num, ret;
|
int num, ret, i;
|
||||||
|
|
||||||
/* Get the number of DAI links */
|
/* Get the number of DAI links */
|
||||||
if (np && of_get_child_by_name(np, PREFIX "dai-link"))
|
if (np && of_get_child_by_name(np, PREFIX "dai-link"))
|
||||||
|
@ -551,6 +793,25 @@ static int seeed_voice_card_probe(struct platform_device *pdev)
|
||||||
if (!dai_props || !dai_link)
|
if (!dai_props || !dai_link)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use snd_soc_dai_link_component instead of legacy style
|
||||||
|
* It is codec only. but cpu/platform will be supported in the future.
|
||||||
|
* see
|
||||||
|
* soc-core.c :: snd_soc_init_multicodec()
|
||||||
|
*
|
||||||
|
* "platform" might be removed
|
||||||
|
* see
|
||||||
|
* simple-card-utils.c :: asoc_simple_canonicalize_platform()
|
||||||
|
*/
|
||||||
|
for (i = 0; i < num; i++) {
|
||||||
|
dai_link[i].cpus = &dai_props[i].cpus;
|
||||||
|
dai_link[i].num_cpus = 1;
|
||||||
|
dai_link[i].codecs = &dai_props[i].codecs;
|
||||||
|
dai_link[i].num_codecs = 1;
|
||||||
|
dai_link[i].platforms = &dai_props[i].platforms;
|
||||||
|
dai_link[i].num_platforms = 1;
|
||||||
|
}
|
||||||
|
|
||||||
priv->dai_props = dai_props;
|
priv->dai_props = dai_props;
|
||||||
priv->dai_link = dai_link;
|
priv->dai_link = dai_link;
|
||||||
|
|
||||||
|
@ -569,6 +830,9 @@ static int seeed_voice_card_probe(struct platform_device *pdev)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
struct seeed_card_info *cinfo;
|
struct seeed_card_info *cinfo;
|
||||||
|
struct snd_soc_dai_link_component *cpus;
|
||||||
|
struct snd_soc_dai_link_component *codecs;
|
||||||
|
struct snd_soc_dai_link_component *platform;
|
||||||
|
|
||||||
cinfo = dev->platform_data;
|
cinfo = dev->platform_data;
|
||||||
if (!cinfo) {
|
if (!cinfo) {
|
||||||
|
@ -585,13 +849,19 @@ static int seeed_voice_card_probe(struct platform_device *pdev)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cpus = dai_link->cpus;
|
||||||
|
cpus->dai_name = cinfo->cpu_dai.name;
|
||||||
|
|
||||||
|
codecs = dai_link->codecs;
|
||||||
|
codecs->name = cinfo->codec;
|
||||||
|
codecs->dai_name = cinfo->codec_dai.name;
|
||||||
|
|
||||||
|
platform = dai_link->platforms;
|
||||||
|
platform->name = cinfo->platform;
|
||||||
|
|
||||||
priv->snd_card.name = (cinfo->card) ? cinfo->card : cinfo->name;
|
priv->snd_card.name = (cinfo->card) ? cinfo->card : cinfo->name;
|
||||||
dai_link->name = cinfo->name;
|
dai_link->name = cinfo->name;
|
||||||
dai_link->stream_name = cinfo->name;
|
dai_link->stream_name = cinfo->name;
|
||||||
dai_link->platform_name = cinfo->platform;
|
|
||||||
dai_link->codec_name = cinfo->codec;
|
|
||||||
dai_link->cpu_dai_name = cinfo->cpu_dai.name;
|
|
||||||
dai_link->codec_dai_name = cinfo->codec_dai.name;
|
|
||||||
dai_link->dai_fmt = cinfo->daifmt;
|
dai_link->dai_fmt = cinfo->daifmt;
|
||||||
dai_link->init = seeed_voice_card_dai_init;
|
dai_link->init = seeed_voice_card_dai_init;
|
||||||
memcpy(&priv->dai_props->cpu_dai, &cinfo->cpu_dai,
|
memcpy(&priv->dai_props->cpu_dai, &cinfo->cpu_dai,
|
||||||
|
@ -608,12 +878,14 @@ static int seeed_voice_card_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
INIT_WORK(&priv->work_codec_clk, work_cb_codec_clk);
|
INIT_WORK(&priv->work_codec_clk, work_cb_codec_clk);
|
||||||
|
|
||||||
|
seeed_debug_info(priv);
|
||||||
|
|
||||||
ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card);
|
ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card);
|
||||||
if (ret >= 0)
|
if (ret >= 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
asoc_simple_card_clean_reference(&priv->snd_card);
|
asoc_simple_clean_reference(&priv->snd_card);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -625,7 +897,9 @@ static int seeed_voice_card_remove(struct platform_device *pdev)
|
||||||
|
|
||||||
if (cancel_work_sync(&priv->work_codec_clk) != 0) {
|
if (cancel_work_sync(&priv->work_codec_clk) != 0) {
|
||||||
}
|
}
|
||||||
return asoc_simple_card_clean_reference(card);
|
asoc_simple_clean_reference(card);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id seeed_voice_of_match[] = {
|
static const struct of_device_id seeed_voice_of_match[] = {
|
||||||
|
|
|
@ -9,12 +9,20 @@
|
||||||
|
|
||||||
#include <linux/version.h>
|
#include <linux/version.h>
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,18,0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,17,0)
|
||||||
#define __NO_SND_SOC_CODEC_DRV 1
|
#define __NO_SND_SOC_CODEC_DRV 1
|
||||||
#else
|
#else
|
||||||
#define __NO_SND_SOC_CODEC_DRV 0
|
#define __NO_SND_SOC_CODEC_DRV 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0)
|
||||||
|
#if __has_attribute(__fallthrough__)
|
||||||
|
# define fallthrough __attribute__((__fallthrough__))
|
||||||
|
#else
|
||||||
|
# define fallthrough do {} while (0) /* fallthrough */
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#if __NO_SND_SOC_CODEC_DRV
|
#if __NO_SND_SOC_CODEC_DRV
|
||||||
#define codec component
|
#define codec component
|
||||||
#define snd_soc_codec snd_soc_component
|
#define snd_soc_codec snd_soc_component
|
||||||
|
@ -23,8 +31,12 @@
|
||||||
#define snd_soc_codec_get_dapm snd_soc_component_get_dapm
|
#define snd_soc_codec_get_dapm snd_soc_component_get_dapm
|
||||||
#define snd_soc_codec_get_bias_level snd_soc_component_get_bias_level
|
#define snd_soc_codec_get_bias_level snd_soc_component_get_bias_level
|
||||||
#define snd_soc_kcontrol_codec snd_soc_kcontrol_component
|
#define snd_soc_kcontrol_codec snd_soc_kcontrol_component
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,9,0)
|
||||||
|
#define snd_soc_read snd_soc_component_read
|
||||||
|
#else
|
||||||
#define snd_soc_read snd_soc_component_read32
|
#define snd_soc_read snd_soc_component_read32
|
||||||
#define snd_soc_register_codec snd_soc_register_component
|
#endif
|
||||||
|
#define snd_soc_register_codec devm_snd_soc_register_component
|
||||||
#define snd_soc_unregister_codec snd_soc_unregister_component
|
#define snd_soc_unregister_codec snd_soc_unregister_component
|
||||||
#define snd_soc_update_bits snd_soc_component_update_bits
|
#define snd_soc_update_bits snd_soc_component_update_bits
|
||||||
#define snd_soc_write snd_soc_component_write
|
#define snd_soc_write snd_soc_component_write
|
||||||
|
|
37
ubuntu-prerequisite.sh
Executable file
37
ubuntu-prerequisite.sh
Executable file
|
@ -0,0 +1,37 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Copyright (c) Hin-Tak Leung 2020
|
||||||
|
#
|
||||||
|
# Overview:
|
||||||
|
# This script compiles and install the Broadcom VideoCore tools,
|
||||||
|
# configure the dynamic loader for the non-standard library location,
|
||||||
|
# and update the loader cache.
|
||||||
|
#
|
||||||
|
# A few steps explicitly requires root privilege, which are
|
||||||
|
# marked with "sudo". The rest is just checking for duplicate/previous
|
||||||
|
# action.
|
||||||
|
#
|
||||||
|
# This derived from my command history on ubuntu 20.04.1 .YMMV
|
||||||
|
|
||||||
|
sudo apt install -y git gcc g++ make alsa-utils cmake
|
||||||
|
|
||||||
|
git clone git://github.com/raspberrypi/userland.git
|
||||||
|
pushd userland/
|
||||||
|
|
||||||
|
arch=$(uname -m)
|
||||||
|
if [[ "$arch" =~ aarch64 ]]; then
|
||||||
|
./buildme --aarch64
|
||||||
|
else
|
||||||
|
./buildme
|
||||||
|
fi
|
||||||
|
# ./buildme already includes "sudo make install" at the end
|
||||||
|
|
||||||
|
popd
|
||||||
|
|
||||||
|
# matches Raspbian's location:
|
||||||
|
if [ ! -f /etc/ld.so.conf.d/00-vmcs.conf ] ; then
|
||||||
|
echo "/opt/vc/lib" | sudo tee -a /etc/ld.so.conf.d/00-vmcs.conf
|
||||||
|
sudo ldconfig -v
|
||||||
|
else
|
||||||
|
echo "/etc/ld.so.conf.d/00-vmcs.conf exists - no need to update ld.cache!"
|
||||||
|
fi
|
25
uninstall.sh
25
uninstall.sh
|
@ -14,6 +14,9 @@ fi
|
||||||
uname_r=$(uname -r)
|
uname_r=$(uname -r)
|
||||||
|
|
||||||
CONFIG=/boot/config.txt
|
CONFIG=/boot/config.txt
|
||||||
|
[ -f /boot/firmware/config.txt ] && CONFIG=/boot/firmware/config.txt
|
||||||
|
[ -f /boot/firmware/usercfg.txt ] && CONFIG=/boot/firmware/usercfg.txt
|
||||||
|
|
||||||
get_overlay() {
|
get_overlay() {
|
||||||
ov=$1
|
ov=$1
|
||||||
if grep -q -E "^dtoverlay=$ov" $CONFIG; then
|
if grep -q -E "^dtoverlay=$ov" $CONFIG; then
|
||||||
|
@ -51,19 +54,24 @@ do_overlay() {
|
||||||
|
|
||||||
RPI_HATS="seeed-2mic-voicecard seeed-4mic-voicecard seeed-8mic-voicecard"
|
RPI_HATS="seeed-2mic-voicecard seeed-4mic-voicecard seeed-8mic-voicecard"
|
||||||
|
|
||||||
|
PATH=$PATH:/opt/vc/bin
|
||||||
echo "remove dtbos"
|
echo "remove dtbos"
|
||||||
for i in $RPI_HATS; do
|
for i in $RPI_HATS; do
|
||||||
dtoverlay -r $i
|
dtoverlay -r $i
|
||||||
done
|
done
|
||||||
rm /boot/overlays/seeed-2mic-voicecard.dtbo || true
|
OVERLAYS=/boot/overlays
|
||||||
rm /boot/overlays/seeed-4mic-voicecard.dtbo || true
|
[ -d /boot/firmware/overlays ] && OVERLAYS=/boot/firmware/overlays
|
||||||
rm /boot/overlays/seeed-8mic-voicecard.dtbo || true
|
|
||||||
|
rm ${OVERLAYS}/seeed-2mic-voicecard.dtbo || true
|
||||||
|
rm ${OVERLAYS}/seeed-4mic-voicecard.dtbo || true
|
||||||
|
rm ${OVERLAYS}/seeed-8mic-voicecard.dtbo || true
|
||||||
|
|
||||||
echo "remove alsa configs"
|
echo "remove alsa configs"
|
||||||
rm -rf /etc/voicecard/ || true
|
rm -rf /etc/voicecard/ || true
|
||||||
|
|
||||||
echo "disabled seeed-voicecard.service "
|
echo "disabled seeed-voicecard.service "
|
||||||
systemctl disable seeed-voicecard.service
|
systemctl stop seeed-voicecard.service
|
||||||
|
systemctl disable seeed-voicecard.service
|
||||||
|
|
||||||
echo "remove seeed-voicecard"
|
echo "remove seeed-voicecard"
|
||||||
rm /usr/bin/seeed-voicecard || true
|
rm /usr/bin/seeed-voicecard || true
|
||||||
|
@ -73,9 +81,12 @@ echo "remove dkms"
|
||||||
rm -rf /var/lib/dkms/seeed-voicecard || true
|
rm -rf /var/lib/dkms/seeed-voicecard || true
|
||||||
|
|
||||||
echo "remove kernel modules"
|
echo "remove kernel modules"
|
||||||
rm /lib/modules/${uname_r}/kernel/sound/soc/codecs/snd-soc-wm8960.ko || true
|
rm /lib/modules/*/kernel/sound/soc/codecs/snd-soc-wm8960.ko || true
|
||||||
rm /lib/modules/${uname_r}/kernel/sound/soc/codecs/snd-soc-ac108.ko || true
|
rm /lib/modules/*/kernel/sound/soc/codecs/snd-soc-ac108.ko || true
|
||||||
rm /lib/modules/${uname_r}/kernel/sound/soc/bcm/snd-soc-seeed-voicecard.ko || true
|
rm /lib/modules/*/kernel/sound/soc/bcm/snd-soc-seeed-voicecard.ko || true
|
||||||
|
rm /lib/modules/*/updates/dkms/snd-soc-wm8960.ko || true
|
||||||
|
rm /lib/modules/*/updates/dkms/snd-soc-ac108.ko || true
|
||||||
|
rm /lib/modules/*/updates/dkms/snd-soc-seeed-voicecard.ko || true
|
||||||
|
|
||||||
echo "remove $CONFIG configuration"
|
echo "remove $CONFIG configuration"
|
||||||
for i in $RPI_HATS; do
|
for i in $RPI_HATS; do
|
||||||
|
|
17
wm8960.c
17
wm8960.c
|
@ -753,6 +753,7 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,
|
||||||
iface |= 0x000c;
|
iface |= 0x000c;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
fallthrough;
|
||||||
default:
|
default:
|
||||||
dev_err(codec->dev, "unsupported width %d\n",
|
dev_err(codec->dev, "unsupported width %d\n",
|
||||||
params_width(params));
|
params_width(params));
|
||||||
|
@ -795,7 +796,7 @@ static int wm8960_hw_free(struct snd_pcm_substream *substream,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int wm8960_mute(struct snd_soc_dai *dai, int mute)
|
static int wm8960_mute(struct snd_soc_dai *dai, int mute, int direction)
|
||||||
{
|
{
|
||||||
struct snd_soc_codec *codec = dai->codec;
|
struct snd_soc_codec *codec = dai->codec;
|
||||||
|
|
||||||
|
@ -1235,11 +1236,12 @@ static int wm8960_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
|
||||||
static const struct snd_soc_dai_ops wm8960_dai_ops = {
|
static const struct snd_soc_dai_ops wm8960_dai_ops = {
|
||||||
.hw_params = wm8960_hw_params,
|
.hw_params = wm8960_hw_params,
|
||||||
.hw_free = wm8960_hw_free,
|
.hw_free = wm8960_hw_free,
|
||||||
.digital_mute = wm8960_mute,
|
.mute_stream = wm8960_mute,
|
||||||
.set_fmt = wm8960_set_dai_fmt,
|
.set_fmt = wm8960_set_dai_fmt,
|
||||||
.set_clkdiv = wm8960_set_dai_clkdiv,
|
.set_clkdiv = wm8960_set_dai_clkdiv,
|
||||||
.set_pll = wm8960_set_dai_pll,
|
.set_pll = wm8960_set_dai_pll,
|
||||||
.set_sysclk = wm8960_set_dai_sysclk,
|
.set_sysclk = wm8960_set_dai_sysclk,
|
||||||
|
.no_capture_mute = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct snd_soc_dai_driver wm8960_dai = {
|
static struct snd_soc_dai_driver wm8960_dai = {
|
||||||
|
@ -1257,7 +1259,11 @@ static struct snd_soc_dai_driver wm8960_dai = {
|
||||||
.rates = WM8960_RATES,
|
.rates = WM8960_RATES,
|
||||||
.formats = WM8960_FORMATS,},
|
.formats = WM8960_FORMATS,},
|
||||||
.ops = &wm8960_dai_ops,
|
.ops = &wm8960_dai_ops,
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,12,0)
|
||||||
|
.symmetric_rate = 1,
|
||||||
|
#else
|
||||||
.symmetric_rates = 1,
|
.symmetric_rates = 1,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static int wm8960_probe(struct snd_soc_codec *codec)
|
static int wm8960_probe(struct snd_soc_codec *codec)
|
||||||
|
@ -1285,7 +1291,6 @@ static const struct snd_soc_codec_driver soc_codec_dev_wm8960 = {
|
||||||
.idle_bias_on = 1,
|
.idle_bias_on = 1,
|
||||||
.use_pmdown_time = 1,
|
.use_pmdown_time = 1,
|
||||||
.endianness = 1,
|
.endianness = 1,
|
||||||
.non_legacy_dai_naming = 1,
|
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1313,8 +1318,7 @@ static void wm8960_set_pdata_from_of(struct i2c_client *i2c,
|
||||||
pdata->shared_lrclk = true;
|
pdata->shared_lrclk = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int wm8960_i2c_probe(struct i2c_client *i2c,
|
static int wm8960_i2c_probe(struct i2c_client *i2c)
|
||||||
const struct i2c_device_id *id)
|
|
||||||
{
|
{
|
||||||
struct wm8960_data *pdata = dev_get_platdata(&i2c->dev);
|
struct wm8960_data *pdata = dev_get_platdata(&i2c->dev);
|
||||||
struct wm8960_priv *wm8960;
|
struct wm8960_priv *wm8960;
|
||||||
|
@ -1379,10 +1383,9 @@ static int wm8960_i2c_probe(struct i2c_client *i2c,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int wm8960_i2c_remove(struct i2c_client *client)
|
static void wm8960_i2c_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
snd_soc_unregister_codec(&client->dev);
|
snd_soc_unregister_codec(&client->dev);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct i2c_device_id wm8960_i2c_id[] = {
|
static const struct i2c_device_id wm8960_i2c_id[] = {
|
||||||
|
|
Loading…
Reference in a new issue