Compare commits

..

No commits in common. "v6.6-order-bugfix" and "master" have entirely different histories.

21 changed files with 433 additions and 1336 deletions

247
README.md
View file

@ -1,20 +1,233 @@
# seeed-voicecard # seeed-voicecard
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. [![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 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/HinTak/seeed-voicecard git clone https://github.com/respeaker/seeed-voicecard
cd seeed-voicecard cd seeed-voicecard
sudo ./install.sh #sudo ./install.sh
sudo ./install.sh --compat-kernel
sudo reboot sudo reboot
``` ```
## ReSpeaker Documentation It may probably happen that the driver won't compile with the latest kernel when raspbian rolls out new patches to the kernel. If so, please try `sudo ./install.sh --compat-kernel` which uses an older kernel but ensures that the driver can work.
Up to date documentation for reSpeaker products can be found in [Seeed Studio Wiki](https://wiki.seeedstudio.com/ReSpeaker/)! ## ReSpeaker Mic Hat
![](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
@ -44,21 +257,13 @@ Thank you!
------------------------------------------------------ ------------------------------------------------------
``` ```
Enjoy ! Enjoy !
### Technical support ### FAQ
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
View file

@ -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_warn("[ac101] map gpio to irq failed, errno = %ld\n", ac10x->irq); pr_info("[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_warn("[ac101] request virq %ld failed, errno = %ld\n", ac10x->irq, ret); pr_info("[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 Playback Volume", SPKOUT_CTRL, SPK_VOL, 0x1f, 0, speaker_vol_tlv), SOC_SINGLE_TLV("speaker volume", SPKOUT_CTRL, SPK_VOL, 0x1f, 0, speaker_vol_tlv),
SOC_SINGLE_TLV("Headphone Playback Volume", HPOUT_CTRL, HP_VOL, 0x3f, 0, headphone_vol_tlv), SOC_SINGLE_TLV("headphone 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->stream[SNDRV_PCM_STREAM_PLAYBACK].active, codec_dai->stream[SNDRV_PCM_STREAM_CAPTURE].active, codec_dai->playback_active, codec_dai->capture_active,
snd_soc_dai_active(codec_dai)); codec_dai->active);
if (!snd_soc_dai_active(codec_dai)) { if (!codec_dai->active) {
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->stream[SNDRV_PCM_STREAM_CAPTURE].active && 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)); 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_info("AC101 as Master\n"); pr_warn("AC101 as Master\n");
reg_val |= (0x0<<AIF1_MSTR_MOD); reg_val |= (0x0<<AIF1_MSTR_MOD);
break; break;
#else #else
pr_info("AC108 as Master\n"); pr_warn("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_info("AC101 as Slave\n"); pr_warn("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, struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { static int ac101_set_clock(int y_start_n_stop) {
int r; int r;
if (y_start_n_stop) { if (y_start_n_stop) {
@ -1258,7 +1258,6 @@ 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),
@ -1269,7 +1268,6 @@ 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'
@ -1279,21 +1277,15 @@ 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;
} }

77
ac108.c
View file

@ -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->stream[SNDRV_PCM_STREAM_PLAYBACK].active, dai->stream[SNDRV_PCM_STREAM_CAPTURE].active); dai->playback_active, dai->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->stream[SNDRV_PCM_STREAM_PLAYBACK].active) if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE && dai->playback_active)
|| (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && dai->stream[SNDRV_PCM_STREAM_CAPTURE].active)) { || (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && dai->capture_active)) {
/* not configure hw_param twice */ /* not configure hw_param twice */
/* return 0; */ /* 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); 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;
@ -991,7 +988,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, struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { static int ac108_set_clock(int y_start_n_stop) {
u8 reg; u8 reg;
int ret = 0; int ret = 0;
@ -999,9 +996,6 @@ static int ac108_set_clock(int y_start_n_stop, struct snd_pcm_substream *substre
/* 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, &reg, ac10x->i2cmap[_MASTER_INDEX]); ac10x_read(I2S_CTRL, &reg, ac10x->i2cmap[_MASTER_INDEX]);
@ -1061,33 +1055,39 @@ 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);
ac108_set_clock(1, substream, cmd, dai); /* delayed clock starting, move to machine trigger() */
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;
} }
dev_dbg(dai->dev, "%s() stream=%s cmd=%d; finished %d\n", __ret:
__FUNCTION__, spin_unlock_irqrestore(&ac10x->lock, flags);
snd_pcm_stream_str(substream),
cmd, ret);
return ret; return ret;
} }
@ -1121,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 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);
@ -1142,13 +1142,12 @@ 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,
.mute_stream = ac108_aif_mute, .digital_mute = 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 = {
@ -1322,11 +1321,6 @@ 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) {
@ -1407,15 +1401,7 @@ static const struct regmap_config ac108_regmap = {
.max_register = 0xDF, .max_register = 0xDF,
.cache_type = REGCACHE_FLAT, .cache_type = REGCACHE_FLAT,
}; };
static const struct i2c_device_id ac108_i2c_id[] = { static int ac108_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *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;
@ -1428,11 +1414,11 @@ static int ac108_i2c_probe(struct i2c_client *i2c) {
} }
} }
index = (int)i2c_match_id(ac108_i2c_id, i2c)->driver_data; index = (int)i2c_id->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_match_id(ac108_i2c_id, i2c)); ret = ac101_probe(i2c, i2c_id);
if (ret) { if (ret) {
ac10x->i2c101 = NULL; ac10x->i2c101 = NULL;
return ret; return ret;
@ -1450,8 +1436,8 @@ static int ac108_i2c_probe(struct i2c_client *i2c) {
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_info(" ac10x i2c_id number: %d\n", index); pr_err(" ac10x i2c_id number: %d\n", index);
pr_info(" ac10x data protocol: %d\n", ac10x->data_protocol); pr_err(" 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);
@ -1473,7 +1459,7 @@ static int ac108_i2c_probe(struct i2c_client *i2c) {
ac10x_fill_regcache(&i2c->dev, ac10x->i2cmap[index]); ac10x_fill_regcache(&i2c->dev, ac10x->i2cmap[index]);
ac10x->codec_cnt++; ac10x->codec_cnt++;
pr_info(" ac10x codec count : %d\n", ac10x->codec_cnt); pr_err(" 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) {
@ -1498,7 +1484,7 @@ __ret:
return ret; return ret;
} }
static void ac108_i2c_remove(struct i2c_client *i2c) { static int 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;
@ -1523,8 +1509,17 @@ __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[] = {

View file

@ -338,7 +338,7 @@ state.seeed8micvoicec {
} }
control.20 { control.20 {
iface MIXER iface MIXER
name 'Speaker Playback Volume' name 'speaker 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 Playback Volume' name 'headphone volume'
value 52 value 52
comment { comment {
access 'read write' access 'read write'

View file

@ -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, struct snd_pcm_substream *, int, struct snd_soc_dai *)); int seeed_voice_card_register_set_clock(int stream, int (*set_clock)(int));
int ac10x_fill_regcache(struct device* dev, struct regmap* map); int ac10x_fill_regcache(struct device* dev, struct regmap* map);

View file

@ -1,4 +1,3 @@
#!/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"

View file

@ -6,10 +6,4 @@ 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"

View file

@ -1,11 +1,14 @@
#!/bin/bash #!/bin/bash
#FORCE_KERNEL="1.20190925+1-1"
FORCE_KERNEL="1.20200601-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
fi fi
# Check for enough space on /boot volume # Check if enough space on /boot volume
boot_line=$(df -h | grep /boot | head -n 1) boot_line=$(df -h | grep /boot | head -n 1)
if [ "x${boot_line}" = "x" ]; then if [ "x${boot_line}" = "x" ]; then
echo "Warning: /boot volume not found .." echo "Warning: /boot volume not found .."
@ -31,19 +34,14 @@ fi
# - check for /boot/overlays # - check for /boot/overlays
# - dtparam and dtoverlay is available # - dtparam and dtoverlay is available
errorFound=0 errorFound=0
OVERLAYS=/boot/overlays if [ ! -d /boot/overlays ] ; then
[ -d /boot/firmware/overlays ] && OVERLAYS=/boot/firmware/overlays echo "/boot/overlays not found or not a directory" 1>&2
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
@ -66,11 +64,8 @@ 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)) 2>/dev/null | zcat | grep -a -m1 "Linux version" | LC_ALL=C sed -e 's/^.*Linux/Linux/' | strings | awk '{ print $3; }') _VER_RUN=$(dd if=$ZIMAGE obs=64K ibs=4 skip=$(( IMG_OFFSET / 4)) | zcat | grep -a -m1 "Linux version" | strings | awk '{ print $3; }')
} }
echo "$_VER_RUN" echo "$_VER_RUN"
return 0 return 0
@ -78,21 +73,17 @@ 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 *** corresponding *** kernel headers with apt-get." echo " Couldn't find *** corresponding *** kernel headers with apt-get."
echo " This may occur if you have ran 'rpi-update'." echo " This may happen if you ran 'rpi-update'."
echo " Choose *** y *** will revert the kernel to version $VER_HDR then continue." echo " Choose *** y *** to revert the kernel to version $VER_HDR and continue."
echo " Choose *** N *** will exit without this driver support, by default." echo " Choose *** N *** to exit without this driver support, by default."
read -p "Would you like to proceed? (y/N)" -n 1 -r -s read -p "Would you like to proceed? (y/N)" -n 1 -r -s
echo echo
if ! [[ $REPLY =~ ^[Yy]$ ]]; then if ! [[ $REPLY =~ ^[Yy]$ ]]; then
@ -102,17 +93,51 @@ 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
}
option_pattern="compat-kernel"
if [[ $1 =~ ${option_pattern} ]]; then
echo "will compile with a compatible kernel..."
else
FORCE_KERNEL=""
echo "will compile with the latest kernel..."
fi
function install_kernel() {
local _url _prefix
# Instead of retrieving 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
@ -127,8 +152,7 @@ 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
@ -152,6 +176,10 @@ function install_module {
for _i in $kernels; do for _i in $kernels; do
dkms build -k $_i -m $mod -v $ver && { dkms build -k $_i -m $mod -v $ver && {
dkms install --force -k $_i -m $mod -v $ver dkms install --force -k $_i -m $mod -v $ver
} || {
echo "Can't compile with this kernel, aborting"
echo "Please try to compile with the option --compat-kernel"
exit 1
} }
done done
@ -162,12 +190,12 @@ install_module "./" "seeed-voicecard"
# install dtbos # install dtbos
cp seeed-2mic-voicecard.dtbo $OVERLAYS cp seeed-2mic-voicecard.dtbo /boot/overlays
cp seeed-4mic-voicecard.dtbo $OVERLAYS cp seeed-4mic-voicecard.dtbo /boot/overlays
cp seeed-8mic-voicecard.dtbo $OVERLAYS cp seeed-8mic-voicecard.dtbo /boot/overlays
#install alsa plugins # install alsa plugins
# no need this plugin now # we don't need this plugin now
# install -D ac108_plugin/libasound_module_pcm_ac108.so /usr/lib/arm-linux-gnueabihf/alsa-lib/ # install -D ac108_plugin/libasound_module_pcm_ac108.so /usr/lib/arm-linux-gnueabihf/alsa-lib/
rm -f /usr/lib/arm-linux-gnueabihf/alsa-lib/libasound_module_pcm_ac108.so rm -f /usr/lib/arm-linux-gnueabihf/alsa-lib/libasound_module_pcm_ac108.so
@ -180,17 +208,13 @@ grep -q "^snd-soc-wm8960$" /etc/modules || \
echo "snd-soc-wm8960" >> /etc/modules echo "snd-soc-wm8960" >> /etc/modules
#set dtoverlays #set dtoverlays
CONFIG=/boot/config.txt sed -i -e 's:#dtparam=i2c_arm=on:dtparam=i2c_arm=on:g' /boot/config.txt || true
[ -f /boot/firmware/config.txt ] && CONFIG=/boot/firmware/config.txt grep -q "^dtoverlay=i2s-mmap$" /boot/config.txt || \
[ -f /boot/firmware/usercfg.txt ] && CONFIG=/boot/firmware/usercfg.txt echo "dtoverlay=i2s-mmap" >> /boot/config.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$" $CONFIG || \ grep -q "^dtparam=i2s=on$" /boot/config.txt || \
echo "dtparam=i2s=on" >> $CONFIG echo "dtparam=i2s=on" >> /boot/config.txt
#install config files #install config files
mkdir /etc/voicecard || true mkdir /etc/voicecard || true
@ -218,6 +242,6 @@ systemctl enable seeed-voicecard.service
systemctl start seeed-voicecard systemctl start seeed-voicecard
echo "------------------------------------------------------" echo "------------------------------------------------------"
echo "Please reboot your raspberry pi to apply all settings" echo "Please reboot your device to apply all settings"
echo "Enjoy!" echo "Enjoy!"
echo "------------------------------------------------------" echo "------------------------------------------------------"

View file

@ -1,454 +0,0 @@
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 = {

View file

@ -1,245 +0,0 @@
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 = {

View file

@ -1,71 +0,0 @@
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 = {

View file

@ -13,7 +13,7 @@
}; };
fragment@1 { fragment@1 {
target-path = "/"; target-path = "/clocks";
__overlay__ { __overlay__ {
ac108_mclk: codec-mclk { ac108_mclk: codec-mclk {
compatible = "fixed-clock"; compatible = "fixed-clock";

Binary file not shown.

View file

@ -13,7 +13,7 @@
}; };
fragment@1 { fragment@1 {
target-path = "/"; target-path = "/clocks";
__overlay__ { __overlay__ {
ac10x_mclk: codec-mclk { ac10x_mclk: codec-mclk {
compatible = "fixed-clock"; compatible = "fixed-clock";

Binary file not shown.

View file

@ -21,18 +21,13 @@
# 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 -d $OVERLAYS i2c_arm=on dtparam i2c_arm=on
modprobe i2c-dev modprobe i2c-dev
#enable spi interface #enable spi interface
dtparam -d $OVERLAYS spi=on dtparam spi=on
_VER_RUN= _VER_RUN=
function get_kernel_version() { function get_kernel_version() {
@ -42,17 +37,13 @@ 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)
# 64-bit-only kernel package _VER_RUN=$(dd if=$ZIMAGE obs=64K ibs=4 skip=$(( IMG_OFFSET / 4)) | zcat | grep -a -m1 "Linux version" | strings | awk '{ print $3; }')
[ ! -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
@ -124,23 +115,25 @@ if [ "$overlay" ]; then
rm /etc/asound.conf rm /etc/asound.conf
rm /var/lib/alsa/asound.state rm /var/lib/alsa/asound.state
kernel_ver=$(uname -r) # get_kernel_version) : <<\EOF
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.*$ || "$kernel_ver" =~ ^5\.*$ ]]; then if [[ "$kernel_ver" =~ ^4\.19.*$ ]]; then
for i in $RPI_HATS; do for i in $RPI_HATS; do
if [ "$i" == "$overlay" ]; then if [ "$i" == "$overlay" ]; then
/bin/true #do_overlay $overlay 0 do_overlay $overlay 0
else else
echo Uninstall $i ... echo Uninstall $i ...
/bin/true #do_overlay $i 1 do_overlay $i 1
fi fi
done done
fi fi
EOF
#make sure the driver loads correctly #make sure the driver loads correctly
dtoverlay -d $OVERLAYS $overlay || true dtoverlay $overlay || true
echo "create $overlay asound configure file" echo "create $overlay asound configure file"
@ -152,12 +145,5 @@ fi
alsactl restore alsactl restore
#Force 3.5mm ('headphone') jack #Force 3.5mm ('headphone') jack
# The Raspberry Pi 4, released on 24th Jun 2019, has two HDMI ports, amixer cset numid=3 1
# 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

View file

@ -28,22 +28,6 @@
#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
@ -56,9 +40,6 @@ 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;
@ -86,7 +67,6 @@ 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))
@ -111,16 +91,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 (asoc_rtd_to_cpu(rtd, 0)->driver->playback.channels_min) { if (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_min;
} }
if (asoc_rtd_to_cpu(rtd, 0)->driver->capture.channels_min) { if (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_min;
} }
asoc_rtd_to_cpu(rtd, 0)->driver->playback.channels_min = priv->channels_playback_override; rtd->cpu_dai->driver->playback.channels_min = priv->channels_playback_override;
asoc_rtd_to_cpu(rtd, 0)->driver->playback.channels_max = priv->channels_playback_override; rtd->cpu_dai->driver->playback.channels_max = priv->channels_playback_override;
asoc_rtd_to_cpu(rtd, 0)->driver->capture.channels_min = priv->channels_capture_override; rtd->cpu_dai->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->capture.channels_max = priv->channels_capture_override;
return ret; return ret;
} }
@ -132,10 +112,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);
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_max = priv->channels_playback_default; rtd->cpu_dai->driver->playback.channels_max = priv->channels_playback_default;
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_max = priv->channels_capture_default; rtd->cpu_dai->driver->capture.channels_max = priv->channels_capture_default;
clk_disable_unprepare(dai_props->cpu_dai.clk); clk_disable_unprepare(dai_props->cpu_dai.clk);
@ -146,8 +126,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 = asoc_rtd_to_codec(rtd, 0); struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
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);
@ -177,9 +157,9 @@ err:
} }
#define _SET_CLOCK_CNT 2 #define _SET_CLOCK_CNT 2
static int (* _set_clock[_SET_CLOCK_CNT])(int y_start_n_stop, struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai); static int (* _set_clock[_SET_CLOCK_CNT])(int y_start_n_stop);
int seeed_voice_card_register_set_clock(int stream, int (*set_clock)(int, struct snd_pcm_substream *, int, struct snd_soc_dai *)) { int seeed_voice_card_register_set_clock(int stream, int (*set_clock)(int)) {
if (! _set_clock[stream]) { if (! _set_clock[stream]) {
_set_clock[stream] = set_clock; _set_clock[stream] = set_clock;
} }
@ -196,10 +176,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, NULL, 0, NULL); /* not using 2nd to 4th arg if 1st == 0 */ r = r || _set_clock[SNDRV_PCM_STREAM_CAPTURE](0);
} }
if (_set_clock[SNDRV_PCM_STREAM_PLAYBACK]) { if (_set_clock[SNDRV_PCM_STREAM_PLAYBACK]) {
r = r || _set_clock[SNDRV_PCM_STREAM_PLAYBACK](0, NULL, 0, NULL); /* not using 2nd to 4th arg if 1st == 0 */ r = r || _set_clock[SNDRV_PCM_STREAM_PLAYBACK](0);
} }
if (r && priv->try_stop++ < TRY_STOP_MAX) { if (r && priv->try_stop++ < TRY_STOP_MAX) {
@ -211,7 +191,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 = 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); 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;
@ -220,7 +200,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->stream[SNDRV_PCM_STREAM_PLAYBACK].active, dai->stream[SNDRV_PCM_STREAM_CAPTURE].active); dai->playback_active, dai->capture_active);
switch (cmd) { switch (cmd) {
case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_START:
@ -231,8 +211,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, substream, cmd, dai); if (_set_clock[SNDRV_PCM_STREAM_CAPTURE]) _set_clock[SNDRV_PCM_STREAM_CAPTURE](1);
// if (_set_clock[SNDRV_PCM_STREAM_PLAYBACK]) _set_clock[SNDRV_PCM_STREAM_PLAYBACK](1, substream, cmd, dai); if (_set_clock[SNDRV_PCM_STREAM_PLAYBACK]) _set_clock[SNDRV_PCM_STREAM_PLAYBACK](1);
#if CONFIG_AC10X_TRIG_LOCK #if CONFIG_AC10X_TRIG_LOCK
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
#endif #endif
@ -242,7 +222,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->stream[SNDRV_PCM_STREAM_CAPTURE].active && substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (dai->capture_active && substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
break; break;
} }
@ -252,18 +232,14 @@ 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, NULL, 0, NULL); /* not using 2nd to 4th arg if 1st == 0 */ if (_set_clock[SNDRV_PCM_STREAM_CAPTURE]) _set_clock[SNDRV_PCM_STREAM_CAPTURE](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 */ if (_set_clock[SNDRV_PCM_STREAM_PLAYBACK]) _set_clock[SNDRV_PCM_STREAM_PLAYBACK](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;
} }
@ -274,165 +250,23 @@ 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 = asoc_rtd_to_codec(rtd, 0); struct snd_soc_dai *codec = rtd->codec_dai;
struct snd_soc_dai *cpu = asoc_rtd_to_cpu(rtd, 0); struct snd_soc_dai *cpu = rtd->cpu_dai;
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_init_dai(codec, &dai_props->codec_dai); ret = asoc_simple_card_init_dai(codec, &dai_props->codec_dai);
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = asoc_simple_init_dai(cpu, &dai_props->cpu_dai); ret = asoc_simple_card_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;
} }
@ -478,19 +312,20 @@ 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_parse_daifmt(dev, node, codec, ret = asoc_simple_card_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_parse_cpu(cpu, dai_link, &single_cpu); ret = asoc_simple_card_parse_cpu(cpu, dai_link,
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_parse_codec(codec, dai_link); ret = asoc_simple_card_parse_codec(codec, dai_link, DAI, CELL);
if (ret < 0) if (ret < 0)
goto dai_link_of_err; goto dai_link_of_err;
#else #else
@ -502,7 +337,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_parse_platform(plat, dai_link); ret = asoc_simple_card_parse_platform(plat, dai_link, DAI, CELL);
if (ret < 0) if (ret < 0)
goto dai_link_of_err; goto dai_link_of_err;
@ -527,7 +362,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_parse_clk_cpu(dev, cpu, dai_link, cpu_dai); ret = asoc_simple_card_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;
@ -535,16 +370,22 @@ 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_parse_clk_codec(dev, codec, dai_link, codec_dai); ret = asoc_simple_card_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;
ret = asoc_simple_set_dailink_name(dev, dai_link, #if _SINGLE_CODEC
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->cpus->dai_name, dai_link->cpu_dai_name,
#if _SINGLE_CODEC #if _SINGLE_CODEC
dai_link->codecs->dai_name dai_link->codec_dai_name
#else #else
dai_link->codecs[0].dai_name dai_link->codecs[0].dai_name
#endif #endif
@ -558,27 +399,17 @@ 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->cpus->dai_name, dai_link->cpu_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->codecs->dai_name, dai_link->codec_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);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,13,0) asoc_simple_card_canonicalize_cpu(dai_link, single_cpu);
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);
@ -610,7 +441,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].dlc.of_node = aux_node; priv->snd_card.aux_dev[i].codec_of_node = aux_node;
} }
priv->snd_card.num_aux_devs = n; priv->snd_card.num_aux_devs = n;
@ -670,7 +501,7 @@ static int seeed_voice_card_parse_of(struct device_node *node,
goto card_parse_end; 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) if (ret < 0)
goto card_parse_end; goto card_parse_end;
@ -695,79 +526,6 @@ 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;
@ -775,7 +533,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, i; int num, ret;
/* 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"))
@ -793,25 +551,6 @@ 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;
@ -830,9 +569,6 @@ 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) {
@ -849,19 +585,13 @@ 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,
@ -878,14 +608,12 @@ 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_clean_reference(&priv->snd_card); asoc_simple_card_clean_reference(&priv->snd_card);
return ret; return ret;
} }
@ -897,9 +625,7 @@ 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) {
} }
asoc_simple_clean_reference(card); return asoc_simple_card_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[] = {

View file

@ -9,7 +9,7 @@
#include <linux/version.h> #include <linux/version.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,17,0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,18,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
@ -31,12 +31,8 @@
#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
#endif #define snd_soc_register_codec snd_soc_register_component
#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

View file

@ -1,37 +0,0 @@
#!/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

View file

@ -14,9 +14,6 @@ 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
@ -54,23 +51,18 @@ 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
OVERLAYS=/boot/overlays rm /boot/overlays/seeed-2mic-voicecard.dtbo || true
[ -d /boot/firmware/overlays ] && OVERLAYS=/boot/firmware/overlays rm /boot/overlays/seeed-4mic-voicecard.dtbo || true
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 stop seeed-voicecard.service
systemctl disable seeed-voicecard.service systemctl disable seeed-voicecard.service
echo "remove seeed-voicecard" echo "remove seeed-voicecard"
@ -84,9 +76,6 @@ echo "remove kernel modules"
rm /lib/modules/*/kernel/sound/soc/codecs/snd-soc-wm8960.ko || true rm /lib/modules/*/kernel/sound/soc/codecs/snd-soc-wm8960.ko || true
rm /lib/modules/*/kernel/sound/soc/codecs/snd-soc-ac108.ko || true rm /lib/modules/*/kernel/sound/soc/codecs/snd-soc-ac108.ko || true
rm /lib/modules/*/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

View file

@ -796,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, int direction) static int wm8960_mute(struct snd_soc_dai *dai, int mute)
{ {
struct snd_soc_codec *codec = dai->codec; 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 = { 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,
.mute_stream = wm8960_mute, .digital_mute = 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 = {
@ -1259,11 +1258,7 @@ 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)
@ -1291,6 +1286,7 @@ 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
}; };
@ -1318,7 +1314,8 @@ 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;
@ -1383,9 +1380,10 @@ static int wm8960_i2c_probe(struct i2c_client *i2c)
return ret; return ret;
} }
static void wm8960_i2c_remove(struct i2c_client *client) static int 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[] = {