From 5b49bfb4ec8596a52b9cfd79ceb7a4c91fa42660 Mon Sep 17 00:00:00 2001 From: Baozhu Zuo Date: Thu, 14 Sep 2017 08:29:26 +0000 Subject: [PATCH] add respeaker 4mic audio card driver --- Makefile | 11 +- ac108.c | 1297 +++++++++++++ ac108.h | 774 ++++++++ ac108_asound.conf | 12 + ac108_asound.state | 1644 +++++++++++++++++ ac108_plugin/Makefile | 58 + ac108_plugin/README.md | 5 + ac108_plugin/libasound_module_pcm_ac108.so | Bin 0 -> 32624 bytes ac108_plugin/pcm_ac108.c | 479 +++++ ac108_plugin/pcm_ac108.o | Bin 0 -> 28216 bytes builddtbo.sh | 11 +- dkms.conf | 6 +- install.sh | 20 +- ...ay.dts => seeed-2mic-voicecard-overlay.dts | 4 +- seeed-2mic-voicecard.dtbo | Bin 0 -> 3465 bytes seeed-4mic-voicecard-overlay.dts | 66 + seeed-4mic-voicecard.dtbo | Bin 0 -> 2074 bytes seeed-voicecard.dtbo | Bin 3449 -> 0 bytes wm8960.ko | Bin 43588 -> 0 bytes asound.conf => wm8960_asound.conf | 0 asound.state => wm8960_asound.state | 0 21 files changed, 4365 insertions(+), 22 deletions(-) create mode 100644 ac108.c create mode 100755 ac108.h create mode 100644 ac108_asound.conf create mode 100644 ac108_asound.state create mode 100644 ac108_plugin/Makefile create mode 100644 ac108_plugin/README.md create mode 100755 ac108_plugin/libasound_module_pcm_ac108.so create mode 100644 ac108_plugin/pcm_ac108.c create mode 100644 ac108_plugin/pcm_ac108.o rename seeed-voicecard-overlay.dts => seeed-2mic-voicecard-overlay.dts (96%) create mode 100644 seeed-2mic-voicecard.dtbo create mode 100644 seeed-4mic-voicecard-overlay.dts create mode 100644 seeed-4mic-voicecard.dtbo delete mode 100644 seeed-voicecard.dtbo delete mode 100644 wm8960.ko rename asound.conf => wm8960_asound.conf (100%) rename asound.state => wm8960_asound.state (100%) diff --git a/Makefile b/Makefile index d62649d..6053ab7 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,10 @@ -obj-m := wm8960.o +snd-soc-wm8960-objs := wm8960.o +snd-soc-ac108-objs := ac108.o + + +obj-m += snd-soc-wm8960.o +obj-m += snd-soc-ac108.o + all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules @@ -7,5 +13,6 @@ clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean install: - sudo cp wm8960.ko /lib/modules/$(shell uname -r) + sudo cp snd-soc-ac108.ko /lib/modules/$(shell uname -r)/sound/soc/codecs/ + sudo cp snd-soc-wm8960.ko /lib/modules/$(shell uname -r)/sound/soc/codecs/ sudo depmod -a diff --git a/ac108.c b/ac108.c new file mode 100644 index 0000000..03589e4 --- /dev/null +++ b/ac108.c @@ -0,0 +1,1297 @@ +/* + * ac108.c -- ac108 ALSA SoC Audio driver + * + * + * Author: Baozhu Zuo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#define DEBUG 1 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ac108.h" + +/** + * TODO: + * 1, add PM API: ac108_suspend,ac108_resume + * 2, add set_pll ,set_clkdiv + * 3,0x65-0x6a + * 4,0x76-0x79 high 4bit + */ +struct pll_div { + unsigned int freq_in; + unsigned int freq_out; + unsigned int m1; + unsigned int m2; + unsigned int n; + unsigned int k1; + unsigned int k2; +}; + + +struct ac108_priv { + struct i2c_client *i2c[4]; + int codec_index; + int sysclk; + int clk_id; + unsigned char i2s_mode; + unsigned char data_protocol; +}; +static struct ac108_priv *ac108; + +struct real_val_to_reg_val { + unsigned int real_val; + unsigned int reg_val; +}; + +static const struct real_val_to_reg_val ac108_sample_rate[] = { + { 8000, 0 }, + { 11025, 1 }, + { 12000, 2 }, + { 16000, 3 }, + { 22050, 4 }, + { 24000, 5 }, + { 32000, 6 }, + { 44100, 7 }, + { 48000, 8 }, + { 96000, 9 }, +}; + +static const struct real_val_to_reg_val ac108_sample_resolution[] = { + { 8, 1 }, + { 12, 2 }, + { 16, 3 }, + { 20, 4 }, + { 24, 5 }, + { 28, 6 }, + { 32, 7 }, +}; + +/* FOUT =(FIN * N) / [(M1+1) * (M2+1)*(K1+1)*(K2+1)] ; M1[0,31], M2[0,1], N[0,1023], K1[0,31], K2[0,1] */ +static const struct pll_div ac108_pll_div_list[] = { + { 400000, 24576000, 0, 0, 614, 4, 1 }, + { 512000, 24576000, 0, 0, 960, 9, 1 }, //24576000/48 + { 768000, 24576000, 0, 0, 640, 9, 1 }, //24576000/32 + { 800000, 24576000, 0, 0, 614, 9, 1 }, + { 1024000, 24576000, 0, 0, 480, 9, 1 }, //24576000/24 + { 1600000, 24576000, 0, 0, 307, 9, 1 }, + { 2048000, 24576000, 0, 0, 240, 9, 1 }, //24576000/12 + { 3072000, 24576000, 0, 0, 160, 9, 1 }, //24576000/8 + { 4096000, 24576000, 2, 0, 360, 9, 1 }, //24576000/6 + { 6000000, 24576000, 4, 0, 410, 9, 1 }, + { 12000000, 24576000, 9, 0, 410, 9, 1 }, + { 13000000, 24576000, 8, 0, 340, 9, 1 }, + { 15360000, 24576000, 12, 0, 415, 9, 1 }, + { 16000000, 24576000, 12, 0, 400, 9, 1 }, + { 19200000, 24576000, 15, 0, 410, 9, 1 }, + { 19680000, 24576000, 15, 0, 400, 9, 1 }, + { 24000000, 24576000, 9, 0, 205, 9, 1 }, + + { 400000, 22579200, 0, 0, 566, 4, 1 }, + { 512000, 22579200, 0, 0, 880, 9, 1 }, + { 768000, 22579200, 0, 0, 587, 9, 1 }, + { 800000, 22579200, 0, 0, 567, 9, 1 }, + { 1024000, 22579200, 0, 0, 440, 9, 1 }, + { 1600000, 22579200, 1, 0, 567, 9, 1 }, + { 2048000, 22579200, 0, 0, 220, 9, 1 }, + { 3072000, 22579200, 0, 0, 148, 9, 1 }, + { 4096000, 22579200, 2, 0, 330, 9, 1 }, + { 6000000, 22579200, 2, 0, 227, 9, 1 }, + { 12000000, 22579200, 8, 0, 340, 9, 1 }, + { 13000000, 22579200, 9, 0, 350, 9, 1 }, + { 15360000, 22579200, 10, 0, 325, 9, 1 }, + { 16000000, 22579200, 11, 0, 340, 9, 1 }, + { 19200000, 22579200, 13, 0, 330, 9, 1 }, + { 19680000, 22579200, 14, 0, 345, 9, 1 }, + { 24000000, 22579200, 16, 0, 320, 9, 1 }, + + { 12288000, 24576000, 9, 0, 400, 9, 1 }, //24576000/2 + { 11289600, 22579200, 9, 0, 400, 9, 1 }, //22579200/2 + + { 24576000 / 1, 24576000, 9, 0, 200, 9, 1 }, //24576000 + { 24576000 / 4, 24576000, 4, 0, 400, 9, 1 }, //6144000 + { 24576000 / 16, 24576000, 0, 0, 320, 9, 1 }, //1536000 + { 24576000 / 64, 24576000, 0, 0, 640, 4, 1 }, //384000 + { 24576000 / 96, 24576000, 0, 0, 960, 4, 1 }, //256000 + { 24576000 / 128, 24576000, 0, 0, 512, 1, 1 }, //192000 + { 24576000 / 176, 24576000, 0, 0, 880, 4, 0 }, //140000 + { 24576000 / 192, 24576000, 0, 0, 960, 4, 0 }, //128000 + + { 22579200 / 1, 22579200, 9, 0, 200, 9, 1 }, //22579200 + { 22579200 / 4, 22579200, 4, 0, 400, 9, 1 }, //5644800 + { 22579200 / 16, 22579200, 0, 0, 320, 9, 1 }, //1411200 + { 22579200 / 64, 22579200, 0, 0, 640, 4, 1 }, //352800 + { 22579200 / 96, 22579200, 0, 0, 960, 4, 1 }, //235200 + { 22579200 / 128, 22579200, 0, 0, 512, 1, 1 }, //176400 + { 22579200 / 176, 22579200, 0, 0, 880, 4, 0 }, //128290 + { 22579200 / 192, 22579200, 0, 0, 960, 4, 0 }, //117600 + + { 22579200 / 6, 22579200, 2, 0, 360, 9, 1 }, //3763200 + { 22579200 / 8, 22579200, 0, 0, 160, 9, 1 }, //2822400 + { 22579200 / 12, 22579200, 0, 0, 240, 9, 1 }, //1881600 + { 22579200 / 24, 22579200, 0, 0, 480, 9, 1 }, //940800 + { 22579200 / 32, 22579200, 0, 0, 640, 9, 1 }, //705600 + { 22579200 / 48, 22579200, 0, 0, 960, 9, 1 }, //470400 +}; + + + +//AC108 define +#define AC108_CHANNELS_MAX 16 //range[1, 16] +#define AC108_RATES (SNDRV_PCM_RATE_8000_96000 | SNDRV_PCM_RATE_KNOT) +#define AC108_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +static const DECLARE_TLV_DB_SCALE(adc1_pga_gain_tlv, 0, 100, 0); +static const DECLARE_TLV_DB_SCALE(adc2_pga_gain_tlv, 0, 100, 0); +static const DECLARE_TLV_DB_SCALE(adc3_pga_gain_tlv, 0, 100, 0); +static const DECLARE_TLV_DB_SCALE(adc4_pga_gain_tlv, 0, 100, 0); + +static const DECLARE_TLV_DB_SCALE(ch1_digital_vol_tlv, -11925,75,0); +static const DECLARE_TLV_DB_SCALE(ch2_digital_vol_tlv, -11925,75,0); +static const DECLARE_TLV_DB_SCALE(ch3_digital_vol_tlv, -11925,75,0); +static const DECLARE_TLV_DB_SCALE(ch4_digital_vol_tlv, -11925,75,0); + +static const DECLARE_TLV_DB_SCALE(digital_mix_vol_tlv, -600,600,0); + +static const DECLARE_TLV_DB_SCALE(channel_enable_tlv, -1500, 100, 0); + +/* Analog ADC */ +static const char *analog_adc_mux_text[] = { + "Analog ADC1", + "Analog ADC2", + "Analog ADC3", + "Analog ADC4", +}; + +/* Channel Mapping */ +static const char *channel_map_mux_text[] = { + "1st adc sample", + "2st adc sample", + "3st adc sample", + "4st adc sample", +}; + +/*Tx source select channel*/ +static const char *channels_src_mux_text[] = { + "1 channels ", + "2 channels ", + "3 channels ", + "4 channels ", + "5 channels ", + "6 channels ", + "7 channels ", + "8 channels ", + "9 channels ", + "10 channels ", + "11 channels ", + "12 channels ", + "13 channels ", + "14 channels ", + "15 channels ", + "16 channels ", +}; + +static const unsigned int ac108_channel_enable_values[] = { + 0x00, + 0x01, + 0x03, + 0x07, + 0x0f, + 0x1f, + 0x3f, + 0x7f, + 0xff, +}; + +static const char *const ac108_channel_low_enable_texts[] = { + "disable all", + "1-1 channels ", + "1-2 channels ", + "1-3 channels ", + "1-4 channels ", + "1-5 channels ", + "1-6 channels ", + "1-7 channels ", + "1-8 channels ", +}; +static const char *const ac108_channel_high_enable_texts[] = { + "disable all", + "8-9 channels ", + "8-10 channels ", + "8-11 channels ", + "8-12 channels ", + "8-13 channels ", + "8-14 channels ", + "8-15 channels ", + "8-16 channels ", +}; + +static const char *const ac108_data_source_texts[] = { + "disable all", + "ADC1 data", + "ADC2 data", + "ADC3 data", + "ADC4 data", +}; +static const unsigned int ac108_data_source_values[] = { + 0x00, + 0x01, + 0x02, + 0x04, + 0x08, +}; +static SOC_VALUE_ENUM_SINGLE_DECL(ac108_tx1_channel_low_enum, + I2S_TX1_CTRL2, 0, 0xff, + ac108_channel_low_enable_texts, + ac108_channel_enable_values); + +static SOC_VALUE_ENUM_SINGLE_DECL(ac108_tx1_channel_high_enum, + I2S_TX1_CTRL3, 0, 0xff, + ac108_channel_high_enable_texts, + ac108_channel_enable_values); + +static SOC_VALUE_ENUM_SINGLE_DECL(ac108_tx2_channel_low_enum, + I2S_TX2_CTRL2, 0, 0xff, + ac108_channel_low_enable_texts, + ac108_channel_enable_values); + +static SOC_VALUE_ENUM_SINGLE_DECL(ac108_tx2_channel_high_enum, + I2S_TX2_CTRL3, 0, 0xff, + ac108_channel_high_enable_texts, + ac108_channel_enable_values); +/*0x76: ADC1 Digital Mixer Source Control Register*/ +static SOC_VALUE_ENUM_SINGLE_DECL(ac108_adc1_data_src_enum, + ADC1_DMIX_SRC, 0, 0x0f, + ac108_data_source_texts, + ac108_data_source_values); +static SOC_VALUE_ENUM_SINGLE_DECL(ac108_adc1_data_gc_enum, + ADC1_DMIX_SRC, ADC1_ADC1_DMXL_GC, 0xf0, + ac108_data_source_texts, + ac108_data_source_values); +/*0x77: ADC2 Digital Mixer Source Control Register*/ +static SOC_VALUE_ENUM_SINGLE_DECL(ac108_adc2_data_src_enum, + ADC2_DMIX_SRC, 0, 0x0f, + ac108_data_source_texts, + ac108_data_source_values); +static SOC_VALUE_ENUM_SINGLE_DECL(ac108_adc2_data_gc_enum, + ADC2_DMIX_SRC, ADC2_ADC1_DMXL_GC, 0xf0, + ac108_data_source_texts, + ac108_data_source_values); +/*0x78: ADC3 Digital Mixer Source Control Register*/ +static SOC_VALUE_ENUM_SINGLE_DECL(ac108_adc3_data_src_enum, + ADC3_DMIX_SRC, 0, 0x0f, + ac108_data_source_texts, + ac108_data_source_values); +static SOC_VALUE_ENUM_SINGLE_DECL(ac108_adc3_data_gc_enum, + ADC3_DMIX_SRC, ADC3_ADC1_DMXL_GC, 0xf0, + ac108_data_source_texts, + ac108_data_source_values); +/*0x79: ADC4 Digital Mixer Source Control Register*/ +static SOC_VALUE_ENUM_SINGLE_DECL(ac108_adc4_data_src_enum, + ADC4_DMIX_SRC, 0, 0x0f, + ac108_data_source_texts, + ac108_data_source_values); +static SOC_VALUE_ENUM_SINGLE_DECL(ac108_adc4_data_gc_enum, + ADC4_DMIX_SRC, ADC4_ADC1_DMXL_GC, 0xf0, + ac108_data_source_texts, + ac108_data_source_values); + +static const struct soc_enum ac108_enum[] = { + /*0x38:TX1 Channel (slot) number Select for each output*/ + SOC_ENUM_SINGLE(I2S_TX1_CTRL1, TX1_CHSEL, 16, channels_src_mux_text), + /*0x40:TX1 Channel (slot) number Select for each output*/ + SOC_ENUM_SINGLE(I2S_TX2_CTRL1, TX2_CHSEL, 16, channels_src_mux_text), + /*0x3c: TX1 Channel Mapping Control 1*/ + SOC_ENUM_SINGLE(I2S_TX1_CHMP_CTRL1, TX1_CH1_MAP, 4, channel_map_mux_text), + SOC_ENUM_SINGLE(I2S_TX1_CHMP_CTRL1, TX1_CH2_MAP, 4, channel_map_mux_text), + SOC_ENUM_SINGLE(I2S_TX1_CHMP_CTRL1, TX1_CH3_MAP, 4, channel_map_mux_text), + SOC_ENUM_SINGLE(I2S_TX1_CHMP_CTRL1, TX1_CH4_MAP, 4, channel_map_mux_text), + + /*0x3d: TX1 Channel Mapping Control 2*/ + SOC_ENUM_SINGLE(I2S_TX1_CHMP_CTRL2, TX1_CH5_MAP, 4, channel_map_mux_text), + SOC_ENUM_SINGLE(I2S_TX1_CHMP_CTRL2, TX1_CH6_MAP, 4, channel_map_mux_text), + SOC_ENUM_SINGLE(I2S_TX1_CHMP_CTRL2, TX1_CH7_MAP, 4, channel_map_mux_text), + SOC_ENUM_SINGLE(I2S_TX1_CHMP_CTRL2, TX1_CH8_MAP, 4, channel_map_mux_text), + + /*0x3e: TX1 Channel Mapping Control 3*/ + SOC_ENUM_SINGLE(I2S_TX1_CHMP_CTRL3, TX1_CH9_MAP, 4, channel_map_mux_text), + SOC_ENUM_SINGLE(I2S_TX1_CHMP_CTRL3, TX1_CH10_MAP, 4, channel_map_mux_text), + SOC_ENUM_SINGLE(I2S_TX1_CHMP_CTRL3, TX1_CH11_MAP, 4, channel_map_mux_text), + SOC_ENUM_SINGLE(I2S_TX1_CHMP_CTRL3, TX1_CH12_MAP, 4, channel_map_mux_text), + + /*0x3f: TX1 Channel Mapping Control 4*/ + SOC_ENUM_SINGLE(I2S_TX1_CHMP_CTRL4, TX1_CH13_MAP, 4, channel_map_mux_text), + SOC_ENUM_SINGLE(I2S_TX1_CHMP_CTRL4, TX1_CH14_MAP, 4, channel_map_mux_text), + SOC_ENUM_SINGLE(I2S_TX1_CHMP_CTRL4, TX1_CH15_MAP, 4, channel_map_mux_text), + SOC_ENUM_SINGLE(I2S_TX1_CHMP_CTRL4, TX1_CH16_MAP, 4, channel_map_mux_text), + + /*0x44: TX2 Channel Mapping Control 1*/ + SOC_ENUM_SINGLE(I2S_TX2_CHMP_CTRL1, TX2_CH1_MAP, 4, channel_map_mux_text), + SOC_ENUM_SINGLE(I2S_TX2_CHMP_CTRL1, TX2_CH2_MAP, 4, channel_map_mux_text), + SOC_ENUM_SINGLE(I2S_TX2_CHMP_CTRL1, TX2_CH3_MAP, 4, channel_map_mux_text), + SOC_ENUM_SINGLE(I2S_TX2_CHMP_CTRL1, TX2_CH4_MAP, 4, channel_map_mux_text), + + /*0x45: TX2 Channel Mapping Control 2*/ + SOC_ENUM_SINGLE(I2S_TX2_CHMP_CTRL2, TX2_CH5_MAP, 4, channel_map_mux_text), + SOC_ENUM_SINGLE(I2S_TX2_CHMP_CTRL2, TX2_CH6_MAP, 4, channel_map_mux_text), + SOC_ENUM_SINGLE(I2S_TX2_CHMP_CTRL2, TX2_CH7_MAP, 4, channel_map_mux_text), + SOC_ENUM_SINGLE(I2S_TX2_CHMP_CTRL2, TX2_CH8_MAP, 4, channel_map_mux_text), + + /*0x46: TX2 Channel Mapping Control 3*/ + SOC_ENUM_SINGLE(I2S_TX2_CHMP_CTRL3, TX2_CH9_MAP, 4, channel_map_mux_text), + SOC_ENUM_SINGLE(I2S_TX2_CHMP_CTRL3, TX2_CH10_MAP, 4, channel_map_mux_text), + SOC_ENUM_SINGLE(I2S_TX2_CHMP_CTRL3, TX2_CH11_MAP, 4, channel_map_mux_text), + SOC_ENUM_SINGLE(I2S_TX2_CHMP_CTRL3, TX2_CH12_MAP, 4, channel_map_mux_text), + + /*0x47: TX2 Channel Mapping Control 4*/ + SOC_ENUM_SINGLE(I2S_TX2_CHMP_CTRL4, TX2_CH13_MAP, 4, channel_map_mux_text), + SOC_ENUM_SINGLE(I2S_TX2_CHMP_CTRL4, TX2_CH14_MAP, 4, channel_map_mux_text), + SOC_ENUM_SINGLE(I2S_TX2_CHMP_CTRL4, TX2_CH15_MAP, 4, channel_map_mux_text), + SOC_ENUM_SINGLE(I2S_TX2_CHMP_CTRL4, TX2_CH16_MAP, 4, channel_map_mux_text), + + /*0x63: ADC Digital Source Select Register*/ + SOC_ENUM_SINGLE(ADC_DSR, DIG_ADC4_SRS, 4, analog_adc_mux_text), + SOC_ENUM_SINGLE(ADC_DSR, DIG_ADC3_SRS, 4, analog_adc_mux_text), + SOC_ENUM_SINGLE(ADC_DSR, DIG_ADC2_SRS, 4, analog_adc_mux_text), + SOC_ENUM_SINGLE(ADC_DSR, DIG_ADC1_SRS, 4, analog_adc_mux_text), + +}; + + +static const struct snd_kcontrol_new ac108_snd_controls[] = { + + SOC_SINGLE("OUT1 Mute", I2S_FMT_CTRL3, 3, 1, 0), + SOC_SINGLE("OUT2 Mute", I2S_FMT_CTRL3, 4, 1, 0), + + /*0x39:TX1 Channel1 ~Channel8 (slot) enable*/ + SOC_ENUM("TX1 Channel1~8 enable", ac108_tx1_channel_low_enum), + /*0x3A:TX1 Channel1 ~Channel8 (slot) enable*/ + SOC_ENUM("TX1 Channel9~16 enable", ac108_tx1_channel_high_enum), + /*0x41:TX2 Channel1 ~Channel8 (slot) enable*/ + SOC_ENUM("TX2 Channel1~8 enable", ac108_tx2_channel_low_enum), + /*0x42:TX2 Channel1 ~Channel8 (slot) enable*/ + SOC_ENUM("TX2 Channel9~16 enable", ac108_tx2_channel_high_enum), + + /*0x70: ADC1 Digital Channel Volume Control Register*/ + SOC_SINGLE_TLV("CH1 digital volume", ADC1_DVOL_CTRL, 0, 0xff, 0, ch1_digital_vol_tlv), + /*0x71: ADC2 Digital Channel Volume Control Register*/ + SOC_SINGLE_TLV("CH2 digital volume", ADC2_DVOL_CTRL, 0, 0xff, 0, ch2_digital_vol_tlv), + /*0x72: ADC3 Digital Channel Volume Control Register*/ + SOC_SINGLE_TLV("CH3 digital volume", ADC3_DVOL_CTRL, 0, 0xff, 0, ch3_digital_vol_tlv), + /*0x73: ADC4 Digital Channel Volume Control Register*/ + SOC_SINGLE_TLV("CH4 digital volume", ADC4_DVOL_CTRL, 0, 0xff, 0, ch4_digital_vol_tlv), + + /*0x90: Analog PGA1 Control Register*/ + SOC_SINGLE_TLV("ADC1 PGA gain", ANA_PGA1_CTRL, ADC1_ANALOG_PGA, 0x1f, 0, adc1_pga_gain_tlv), + /*0x91: Analog PGA2 Control Register*/ + SOC_SINGLE_TLV("ADC2 PGA gain", ANA_PGA2_CTRL, ADC2_ANALOG_PGA, 0x1f, 0, adc2_pga_gain_tlv), + /*0x92: Analog PGA3 Control Register*/ + SOC_SINGLE_TLV("ADC3 PGA gain", ANA_PGA3_CTRL, ADC3_ANALOG_PGA, 0x1f, 0, adc3_pga_gain_tlv), + /*0x93: Analog PGA4 Control Register*/ + SOC_SINGLE_TLV("ADC4 PGA gain", ANA_PGA4_CTRL, ADC4_ANALOG_PGA, 0x1f, 0, adc4_pga_gain_tlv), + + /*0x96-0x9F: use the default value*/ + + SOC_ENUM("Tx1 Channels", ac108_enum[0]), + SOC_ENUM("Tx2 Channels", ac108_enum[1]), + + SOC_ENUM("Tx1 Channels 1 MAP", ac108_enum[2]), + SOC_ENUM("Tx1 Channels 2 MAP", ac108_enum[3]), + SOC_ENUM("Tx1 Channels 3 MAP", ac108_enum[4]), + SOC_ENUM("Tx1 Channels 4 MAP", ac108_enum[5]), + SOC_ENUM("Tx1 Channels 5 MAP", ac108_enum[6]), + SOC_ENUM("Tx1 Channels 6 MAP", ac108_enum[7]), + SOC_ENUM("Tx1 Channels 7 MAP", ac108_enum[8]), + SOC_ENUM("Tx1 Channels 8 MAP", ac108_enum[9]), + SOC_ENUM("Tx1 Channels 9 MAP", ac108_enum[10]), + SOC_ENUM("Tx1 Channels 10 MAP", ac108_enum[11]), + SOC_ENUM("Tx1 Channels 11 MAP", ac108_enum[12]), + SOC_ENUM("Tx1 Channels 12 MAP", ac108_enum[13]), + SOC_ENUM("Tx1 Channels 13 MAP", ac108_enum[14]), + SOC_ENUM("Tx1 Channels 14 MAP", ac108_enum[15]), + SOC_ENUM("Tx1 Channels 15 MAP", ac108_enum[16]), + SOC_ENUM("Tx1 Channels 16 MAP", ac108_enum[17]), + + SOC_ENUM("Tx2 Channels 1 MAP", ac108_enum[18]), + SOC_ENUM("Tx2 Channels 2 MAP", ac108_enum[19]), + SOC_ENUM("Tx2 Channels 3 MAP", ac108_enum[20]), + SOC_ENUM("Tx2 Channels 4 MAP", ac108_enum[21]), + SOC_ENUM("Tx2 Channels 5 MAP", ac108_enum[22]), + SOC_ENUM("Tx2 Channels 6 MAP", ac108_enum[23]), + SOC_ENUM("Tx2 Channels 7 MAP", ac108_enum[24]), + SOC_ENUM("Tx2 Channels 8 MAP", ac108_enum[25]), + SOC_ENUM("Tx2 Channels 9 MAP", ac108_enum[26]), + SOC_ENUM("Tx2 Channels 10 MAP", ac108_enum[27]), + SOC_ENUM("Tx2 Channels 11 MAP", ac108_enum[28]), + SOC_ENUM("Tx2 Channels 12 MAP", ac108_enum[29]), + SOC_ENUM("Tx2 Channels 13 MAP", ac108_enum[30]), + SOC_ENUM("Tx2 Channels 14 MAP", ac108_enum[31]), + SOC_ENUM("Tx2 Channels 15 MAP", ac108_enum[32]), + SOC_ENUM("Tx2 Channels 16 MAP", ac108_enum[33]), + + SOC_ENUM("ADC4 Source", ac108_enum[34]), + SOC_ENUM("ADC3 Source", ac108_enum[35]), + SOC_ENUM("ADC2 Source", ac108_enum[36]), + SOC_ENUM("ADC1 Source", ac108_enum[37]), + + SOC_ENUM("ADC1 Digital Mixer gc", ac108_adc1_data_gc_enum), + SOC_ENUM("ADC1 Digital Mixer src", ac108_adc1_data_src_enum), + + SOC_ENUM("ADC2 Digital Mixer gc", ac108_adc2_data_gc_enum), + SOC_ENUM("ADC2 Digital Mixer src", ac108_adc2_data_src_enum), + + SOC_ENUM("ADC3 Digital Mixer gc", ac108_adc3_data_gc_enum), + SOC_ENUM("ADC3 Digital Mixer src", ac108_adc3_data_src_enum), + + SOC_ENUM("ADC4 Digital Mixer gc", ac108_adc4_data_gc_enum), + SOC_ENUM("ADC4 Digital Mixer src", ac108_adc4_data_src_enum), +}; + + +static const struct snd_soc_dapm_widget ac108_dapm_widgets[] = { + //input widgets + SND_SOC_DAPM_INPUT("MIC1P"), + SND_SOC_DAPM_INPUT("MIC1N"), + + SND_SOC_DAPM_INPUT("MIC2P"), + SND_SOC_DAPM_INPUT("MIC2N"), + + SND_SOC_DAPM_INPUT("MIC3P"), + SND_SOC_DAPM_INPUT("MIC3N"), + + SND_SOC_DAPM_INPUT("MIC4P"), + SND_SOC_DAPM_INPUT("MIC4N"), + + SND_SOC_DAPM_INPUT("DMIC1"), + SND_SOC_DAPM_INPUT("DMIC2"), + + /*0xa0: ADC1 Analog Control 1 Register*/ + /*0xa1-0xa6:use the defualt value*/ + SND_SOC_DAPM_AIF_IN("Channel 1 AAF", "Capture", 0, ANA_ADC1_CTRL1, ADC1_DSM_ENABLE, 1), + SND_SOC_DAPM_SUPPLY("Channel 1 EN", ANA_ADC1_CTRL1, ADC1_PGA_ENABLE, 1, NULL, 0), + SND_SOC_DAPM_MICBIAS("MIC1BIAS", ANA_ADC1_CTRL1, ADC1_MICBIAS_EN, 1), + + /*0xa7: ADC2 Analog Control 1 Register*/ + /*0xa8-0xad:use the defualt value*/ + SND_SOC_DAPM_AIF_IN("Channel 2 AAF", "Capture", 0, ANA_ADC2_CTRL1, ADC2_DSM_ENABLE, 1), + SND_SOC_DAPM_SUPPLY("Channel 2 EN", ANA_ADC2_CTRL1, ADC2_PGA_ENABLE, 1, NULL, 0), + SND_SOC_DAPM_MICBIAS("MIC2BIAS", ANA_ADC2_CTRL1, ADC2_MICBIAS_EN, 1), + + /*0xae: ADC3 Analog Control 1 Register*/ + /*0xaf-0xb4:use the defualt value*/ + SND_SOC_DAPM_AIF_IN("Channel 3 AAF", "Capture", 0, ANA_ADC3_CTRL1, ADC3_DSM_ENABLE, 1), + SND_SOC_DAPM_SUPPLY("Channel 3 EN", ANA_ADC3_CTRL1, ADC3_PGA_ENABLE, 1, NULL, 0), + SND_SOC_DAPM_MICBIAS("MIC3BIAS", ANA_ADC3_CTRL1, ADC3_MICBIAS_EN, 1), + + /*0xb5: ADC4 Analog Control 1 Register*/ + /*0xb6-0xbb:use the defualt value*/ + SND_SOC_DAPM_AIF_IN("Channel 4 AAF", "Capture", 0, ANA_ADC4_CTRL1, ADC4_DSM_ENABLE, 1), + SND_SOC_DAPM_SUPPLY("Channel 4 EN", ANA_ADC4_CTRL1, ADC4_PGA_ENABLE, 1, NULL, 0), + SND_SOC_DAPM_MICBIAS("MIC4BIAS", ANA_ADC4_CTRL1, ADC4_MICBIAS_EN, 1), + + + /*0x61: ADC Digital Part Enable Register*/ + SND_SOC_DAPM_SUPPLY("ADC EN", ADC_DIG_EN, 4, 1, NULL, 0), + SND_SOC_DAPM_ADC("ADC1", "Capture", ADC_DIG_EN, 0, 1), + SND_SOC_DAPM_ADC("ADC2", "Capture", ADC_DIG_EN, 1, 1), + SND_SOC_DAPM_ADC("ADC3", "Capture", ADC_DIG_EN, 2, 1), + SND_SOC_DAPM_ADC("ADC4", "Capture", ADC_DIG_EN, 3, 1), + + SND_SOC_DAPM_SUPPLY("ADC1 CLK", ANA_ADC4_CTRL7, ADC1_CLK_GATING, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC2 CLK", ANA_ADC4_CTRL7, ADC2_CLK_GATING, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC3 CLK", ANA_ADC4_CTRL7, ADC3_CLK_GATING, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC4 CLK", ANA_ADC4_CTRL7, ADC4_CLK_GATING, 1, NULL, 0), + + SND_SOC_DAPM_SUPPLY("DSM EN", ANA_ADC4_CTRL6, DSM_DEMOFF, 1, NULL, 0), + + /*0x62:Digital MIC Enable Register*/ + SND_SOC_DAPM_MICBIAS("DMIC1 enable", DMIC_EN, 0, 0), + SND_SOC_DAPM_MICBIAS("DMIC2 enable", DMIC_EN, 1, 0), + + /**/ +}; + +static const struct snd_soc_dapm_route ac108_dapm_routes[] = { + + { "ADC1", NULL, "Channel 1 AAF" }, + { "ADC2", NULL, "Channel 2 AAF" }, + { "ADC3", NULL, "Channel 3 AAF" }, + { "ADC4", NULL, "Channel 4 AAF" }, + + { "Channel 1 AAF", NULL, "MIC1BIAS" }, + { "Channel 2 AAF", NULL, "MIC2BIAS" }, + { "Channel 3 AAF", NULL, "MIC3BIAS" }, + { "Channel 4 AAF", NULL, "MIC4BIAS" }, + + { "MIC1BIAS", NULL, "ADC1 CLK" }, + { "MIC2BIAS", NULL, "ADC2 CLK" }, + { "MIC3BIAS", NULL, "ADC3 CLK" }, + { "MIC4BIAS", NULL, "ADC4 CLK" }, + + + { "ADC1 CLK", NULL, "DSM EN" }, + { "ADC2 CLK", NULL, "DSM EN" }, + { "ADC3 CLK", NULL, "DSM EN" }, + { "ADC4 CLK", NULL, "DSM EN" }, + + + { "DSM EN", NULL, "ADC EN" }, + + { "Channel 1 EN", NULL, "DSM EN" }, + { "Channel 2 EN", NULL, "DSM EN" }, + { "Channel 3 EN", NULL, "DSM EN" }, + { "Channel 4 EN", NULL, "DSM EN" }, + + + { "MIC1P", NULL, "Channel 1 EN" }, + { "MIC1N", NULL, "Channel 1 EN" }, + + { "MIC2P", NULL, "Channel 2 EN" }, + { "MIC2N", NULL, "Channel 2 EN" }, + + { "MIC3P", NULL, "Channel 3 EN" }, + { "MIC3N", NULL, "Channel 3 EN" }, + + { "MIC4P", NULL, "Channel 4 EN" }, + { "MIC4N", NULL, "Channel 4 EN" }, + +}; +static int ac108_read(u8 reg, u8 *rt_value, struct i2c_client *client) { + int ret; + u8 read_cmd[3] = { reg, 0, 0 }; + u8 cmd_len = 1; + + ret = i2c_master_send(client, read_cmd, cmd_len); + if (ret != cmd_len) { + pr_err("ac108_read error1\n"); + return -1; + } + ret = i2c_master_recv(client, rt_value, 1); + if (ret != 1) { + pr_err("ac108_read error2, ret = %d.\n", ret); + return -1; + } + + return 0; +} + +static int ac108_write(u8 reg, unsigned char val, struct i2c_client *client) { + int ret = 0; + u8 write_cmd[2] = { reg, val }; + + ret = i2c_master_send(client, write_cmd, 2); + if (ret != 2) { + pr_err("ac108_write error->[REG-0x%02x,val-0x%02x]\n", reg, val); + return -1; + } + return 0; +} + +static int ac108_update_bits(u8 reg, u8 mask, u8 val, struct i2c_client *client) { + u8 val_old, val_new; + + ac108_read(reg, &val_old, client); + val_new = (val_old & ~mask) | (val & mask); + if (val_new != val_old) { + ac108_write(reg, val_new, client); + } + + return 0; +} + +static int ac108_multi_chips_read(u8 reg, u8 *rt_value, struct ac108_priv *ac108) { + u8 i; + for (i = 0; i < ac108->codec_index; i++) { + ac108_read(reg, rt_value++, ac108->i2c[i]); + } + + return 0; +} + + +static int ac108_multi_chips_write(u8 reg, u8 val, struct ac108_priv *ac108) { + u8 i; + for (i = 0; i < ac108->codec_index; i++) { + ac108_write(reg, val, ac108->i2c[i]); + } + return 0; +} + +static int ac108_multi_chips_update_bits(u8 reg, u8 mask, u8 val, struct ac108_priv *ac108) { + u8 i; + for (i = 0; i < ac108->codec_index; i++) { + ac108_update_bits(reg, mask, val, ac108->i2c[i]); + } + return 0; +} + +static unsigned int ac108_codec_read(struct snd_soc_codec *codec, unsigned int reg) { + unsigned char val_r; + struct ac108_priv *ac108 = dev_get_drvdata(codec->dev); + /*read one chip is fine*/ + ac108_read(reg, &val_r, ac108->i2c[0]); + return val_r; +} + +static int ac108_codec_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int val) { + struct ac108_priv *ac108 = dev_get_drvdata(codec->dev); + ac108_multi_chips_write(reg, val, ac108); + return 0; +} + +/** + * The Power management related registers are Reg01h~Reg09h + * 0x01-0x05,0x08,use the default value + * @author baozhu (17-6-21) + * + * @param ac108 + */ +static void ac108_configure_power(struct ac108_priv *ac108) { + /** + * 0x06:Enable Analog LDO + */ + ac108_multi_chips_update_bits(PWR_CTRL6, 0x01 << LDO33ANA_ENABLE, 0x01 << LDO33ANA_ENABLE, ac108); + /** + * 0x07: + * Control VREF output and micbias voltage ? + * REF faststart disable, enable Enable VREF (needed for Analog + * LDO and MICBIAS) + */ + ac108_multi_chips_update_bits(PWR_CTRL7, 0x1f << VREF_SEL | 0x01 << VREF_FASTSTART_ENABLE | 0x01 << VREF_ENABLE, + 0x13 << VREF_SEL | 0x00 << VREF_FASTSTART_ENABLE | 0x01 << VREF_ENABLE, ac108); + /** + * 0x09: + * Disable fast-start circuit on VREFP + * VREFP_RESCTRL=00=1 MOhm + * IGEN_TRIM=100=+25% + * Enable VREFP (needed by all audio input channels) + */ + ac108_multi_chips_update_bits(PWR_CTRL9, 0x01 << VREFP_FASTSTART_ENABLE | 0x03 << VREFP_RESCTRL | + 0x07 << IGEN_TRIM | 0x01 << VREFP_ENABLE, + 0x00 << VREFP_FASTSTART_ENABLE | 0x00 << VREFP_RESCTRL | + 0x04 << IGEN_TRIM | 0x01 << VREFP_ENABLE, ac108); +} + +/** + * The clock management related registers are Reg20h~Reg25h + * The PLL management related registers are Reg10h~Reg18h. + * @author baozhu (17-6-20) + * + * @param ac108 + * @param rate : sample rate + * + * @return int : fail or success + */ +static int ac108_configure_clocking(struct ac108_priv *ac108, unsigned int rate) { + unsigned int i = 0; + struct pll_div ac108_pll_div = { 0 }; + if (ac108->clk_id == SYSCLK_SRC_PLL) { + /* FOUT =(FIN * N) / [(M1+1) * (M2+1)*(K1+1)*(K2+1)] */ + for (i = 0; i < ARRAY_SIZE(ac108_pll_div_list); i++) { + if (ac108_pll_div_list[i].freq_in == ac108->sysclk && ac108_pll_div_list[i].freq_out % rate == 0) { + ac108_pll_div = ac108_pll_div_list[i]; + pr_err("AC108 PLL freq_in match:%u, freq_out:%u\n\n", ac108_pll_div.freq_in, ac108_pll_div.freq_out); + break; + } + } + /* 0x11,0x12,0x13,0x14: Config PLL DIV param M1/M2/N/K1/K2 */ + ac108_multi_chips_update_bits(PLL_CTRL5, 0x1f << PLL_POSTDIV1 | 0x01 << PLL_POSTDIV2, ac108_pll_div.k1 << PLL_POSTDIV1 | + ac108_pll_div.k2 << PLL_POSTDIV2, ac108); + ac108_multi_chips_update_bits(PLL_CTRL4, 0xff << PLL_LOOPDIV_LSB, (unsigned char)ac108_pll_div.n << PLL_LOOPDIV_LSB, ac108); + ac108_multi_chips_update_bits(PLL_CTRL3, 0x03 << PLL_LOOPDIV_MSB, (ac108_pll_div.n >> 8) << PLL_LOOPDIV_MSB, ac108); + ac108_multi_chips_update_bits(PLL_CTRL2, 0x1f << PLL_PREDIV1 | 0x01 << PLL_PREDIV2, + ac108_pll_div.m1 << PLL_PREDIV1 | ac108_pll_div.m2 << PLL_PREDIV2, ac108); + + /*0x18: PLL clk lock enable*/ + ac108_multi_chips_update_bits(PLL_LOCK_CTRL, 0x1 << PLL_LOCK_EN, 0x1 << PLL_LOCK_EN, ac108); + /*0x10: PLL Common voltage Enable, PLL Enable,PLL loop divider factor detection enable*/ + ac108_multi_chips_update_bits(PLL_CTRL1, 0x01 << PLL_EN | 0x01 << PLL_COM_EN | 0x01 << PLL_NDET, + 0x1 << PLL_EN | 0x1 << PLL_COM_EN | 0x01 << PLL_NDET, ac108); + + /** + * 0x20: enable pll,pll source from mclk, sysclk source from + * pll,enable sysclk + */ + ac108_multi_chips_update_bits(SYSCLK_CTRL, 0x01 << PLLCLK_EN | 0x03 << PLLCLK_SRC | 0x01 << SYSCLK_SRC | 0x01 << SYSCLK_EN, + 0x01 << PLLCLK_EN | 0x00 << PLLCLK_SRC | 0x01 << SYSCLK_SRC | 0x01 << SYSCLK_EN, ac108); + } + if (ac108->clk_id == SYSCLK_SRC_MCLK) { + /** + *0x20: sysclk source from mclk,enable sysclk + */ + ac108_multi_chips_update_bits(SYSCLK_CTRL, 0x01 << PLLCLK_EN | 0x01 << SYSCLK_SRC | 0x01 << SYSCLK_EN, + 0x00 << PLLCLK_EN | 0x00 << SYSCLK_SRC | 0x01 << SYSCLK_EN, ac108); + } + /*0x21: Module clock enable*/ + ac108_multi_chips_write(MOD_CLK_EN, 1 << I2S | 1 << ADC_DIGITAL | 1 << MIC_OFFSET_CALIBRATION | 1 << ADC_ANALOG, ac108); + /*0x22: Module reset de-asserted*/ + ac108_multi_chips_write(MOD_RST_CTRL, 1 << I2S | 1 << ADC_DIGITAL | 1 << MIC_OFFSET_CALIBRATION | 1 << ADC_ANALOG, ac108); + return 0; +} + +static int ac108_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { + unsigned int i, channels, sample_resolution, rate; + struct snd_soc_codec *codec = dai->codec; + struct ac108_priv *ac108 = snd_soc_codec_get_drvdata(codec); + rate = 99; + dev_dbg(dai->dev, "%s\n", __FUNCTION__); + + channels = params_channels(params); + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S8: + sample_resolution = 0; + break; + case SNDRV_PCM_FORMAT_S16_LE: + sample_resolution = 2; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + sample_resolution = 3; + break; + case SNDRV_PCM_FORMAT_S24_LE: + sample_resolution = 4; + break; + case SNDRV_PCM_FORMAT_S32_LE: + sample_resolution = 6; + break; + default: + pr_err("AC108 don't supported the sample resolution: %u\n", params_format(params)); + return -EINVAL; + } + + dev_dbg(dai->dev,"rate:%d \n", params_rate(params)); + for (i = 0; i < ARRAY_SIZE(ac108_sample_rate); i++) { + if (ac108_sample_rate[i].real_val == params_rate(params)) { + rate = i; + break; + } + } + if (rate == 99) return -EINVAL; + + + dev_dbg(dai->dev, "rate: %d , channels: %d , sample_resolution: %d", + ac108_sample_rate[rate].real_val, + channels, + ac108_sample_resolution[sample_resolution].real_val); + + /** + * 0x33: + * The 8-Low bit of LRCK period value. It is used to program + * the number of BCLKs per channel of sample frame. This value + * is interpreted as follow: + * The 8-Low bit of LRCK period value. It is used to program + * the number of BCLKs per channel of sample frame. This value + * is interpreted as follow: PCM mode: Number of BCLKs within + * (Left + Right) channel width I2S / Left-Justified / + * Right-Justified mode: Number of BCLKs within each individual + * channel width (Left or Right) N+1 + * For example: + * n = 7: 8 BCLK width + * … + * n = 1023: 1024 BCLKs width + * 0X32[0:1]: + * The 2-High bit of LRCK period value. + */ + if (ac108->i2s_mode != PCM_FORMAT) { + if (ac108->data_protocol) { + ac108_multi_chips_write(I2S_LRCK_CTRL2, ac108_sample_resolution[sample_resolution].real_val - 1, ac108); + /*encoding mode, the max LRCK period value < 32,so the 2-High bit is zero*/ + ac108_multi_chips_update_bits(I2S_LRCK_CTRL1, 0x03 << 0, 0x00, ac108); + } else { + /*TDM mode or normal mode*/ + /** + * TODO: need test. + */ + } + + } else { + /** + * TODO: need test. + */ + } + + /** + * 0x35: + * TX Encoding mode will add 4bits to mark channel number + * TODO: need a chat to explain this + */ + ac108_multi_chips_update_bits(I2S_FMT_CTRL2, 0x07 << SAMPLE_RESOLUTION | 0x07 << SLOT_WIDTH_SEL, + ac108_sample_resolution[sample_resolution].reg_val << SAMPLE_RESOLUTION + | ac108_sample_resolution[sample_resolution].reg_val << SLOT_WIDTH_SEL, ac108); + + /** + * 0x60: + * ADC Sample Rate synchronised with I2S1 clock zone + */ + ac108_multi_chips_update_bits(ADC_SPRC, 0x0f << ADC_FS_I2S1, ac108_sample_rate[rate].reg_val << ADC_FS_I2S1, ac108); + + ac108_configure_clocking(ac108, rate); + return 0; +} + +static int ac108_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir) { + + struct ac108_priv *ac108 = snd_soc_dai_get_drvdata(dai); + + pr_info("%s :%d\n", __FUNCTION__, freq); + switch (clk_id) { + case SYSCLK_SRC_MCLK: + ac108_multi_chips_update_bits(SYSCLK_CTRL, 0x1 << SYSCLK_SRC, SYSCLK_SRC_MCLK << SYSCLK_SRC, ac108); + break; + case SYSCLK_SRC_PLL: + ac108_multi_chips_update_bits(SYSCLK_CTRL, 0x1 << SYSCLK_SRC, SYSCLK_SRC_PLL << SYSCLK_SRC, ac108); + break; + default: + return -EINVAL; + } + ac108->sysclk = freq; + ac108->clk_id = clk_id; + + return 0; +} + +/** + * The i2s format management related registers are Reg + * 30h~Reg36h + * 33h,35h will be set in ac108_hw_params, It's BCLK width and + * Sample Resolution. + * @author baozhu (17-6-20) + * + * @param dai + * @param fmt + * + * @return int + */ +static int ac108_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { + + unsigned char tx_offset, lrck_polarity, brck_polarity; + struct ac108_priv *ac108 = dev_get_drvdata(dai->dev); + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: /*AC108 Master*/ + dev_dbg(dai->dev, "AC108 set to work as Master\n"); + /** + * 0x30:chip is master mode ,BCLK & LRCK output + */ + ac108_multi_chips_update_bits(I2S_CTRL, 0x03 << LRCK_IOEN, 0x03 << LRCK_IOEN, ac108); + /* multi_chips: only one chip set as Master, and the others also need to set as Slave */ + if (ac108->codec_index > 1) ac108_update_bits(I2S_CTRL, 0x3 << LRCK_IOEN, 0x0 << LRCK_IOEN, ac108->i2c[1]); + + break; + case SND_SOC_DAIFMT_CBS_CFS: /*AC108 Slave*/ + dev_dbg(dai->dev, "AC108 set to work as Slave\n"); + /** + * 0x30:chip is slave mode, BCLK & LRCK input,enable SDO1_EN and + * SDO2_EN, Transmitter Block Enable, Globe Enable + */ + ac108_multi_chips_update_bits(I2S_CTRL, 0x03 << LRCK_IOEN | 0x03 << SDO1_EN | 0x1 << TXEN | 0x1 << GEN, + 0x00 << LRCK_IOEN | 0x03 << SDO1_EN | 0x1 << TXEN | 0x1 << GEN, ac108); + break; + default: + pr_err("AC108 Master/Slave mode config error:%u\n\n", (fmt & SND_SOC_DAIFMT_MASTER_MASK) >> 12); + return -EINVAL; + } + + /*AC108 config I2S/LJ/RJ/PCM format*/ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + dev_dbg(dai->dev, "AC108 config I2S format\n"); + ac108->i2s_mode = LEFT_JUSTIFIED_FORMAT; + tx_offset = 1; + break; + case SND_SOC_DAIFMT_RIGHT_J: + dev_dbg(dai->dev, "AC108 config RIGHT-JUSTIFIED format\n"); + ac108->i2s_mode = RIGHT_JUSTIFIED_FORMAT; + tx_offset = 0; + break; + case SND_SOC_DAIFMT_LEFT_J: + dev_dbg(dai->dev, "AC108 config LEFT-JUSTIFIED format\n"); + ac108->i2s_mode = LEFT_JUSTIFIED_FORMAT; + tx_offset = 0; + break; + case SND_SOC_DAIFMT_DSP_A: + dev_dbg(dai->dev, "AC108 config PCM-A format\n"); + ac108->i2s_mode = PCM_FORMAT; + tx_offset = 1; + break; + case SND_SOC_DAIFMT_DSP_B: + dev_dbg(dai->dev, "AC108 config PCM-B format\n"); + ac108->i2s_mode = PCM_FORMAT; + tx_offset = 0; + break; + default: + ac108->i2s_mode = LEFT_JUSTIFIED_FORMAT; + tx_offset = 1; + return -EINVAL; + pr_err("AC108 I2S format config error:%u\n\n", fmt & SND_SOC_DAIFMT_FORMAT_MASK); + } + /*AC108 config BCLK&LRCK polarity*/ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + dev_dbg(dai->dev, "AC108 config BCLK&LRCK polarity: BCLK_normal,LRCK_normal\n"); + brck_polarity = BCLK_NORMAL_DRIVE_N_SAMPLE_P; + lrck_polarity = LRCK_LEFT_LOW_RIGHT_HIGH; + break; + case SND_SOC_DAIFMT_NB_IF: + dev_dbg(dai->dev, "AC108 config BCLK&LRCK polarity: BCLK_normal,LRCK_invert\n"); + brck_polarity = BCLK_NORMAL_DRIVE_N_SAMPLE_P; + lrck_polarity = LRCK_LEFT_HIGH_RIGHT_LOW; + break; + case SND_SOC_DAIFMT_IB_NF: + dev_dbg(dai->dev, "AC108 config BCLK&LRCK polarity: BCLK_invert,LRCK_normal\n"); + brck_polarity = BCLK_INVERT_DRIVE_P_SAMPLE_N; + lrck_polarity = LRCK_LEFT_LOW_RIGHT_HIGH; + break; + case SND_SOC_DAIFMT_IB_IF: + dev_dbg(dai->dev, "AC108 config BCLK&LRCK polarity: BCLK_invert,LRCK_invert\n"); + brck_polarity = BCLK_INVERT_DRIVE_P_SAMPLE_N; + lrck_polarity = LRCK_LEFT_HIGH_RIGHT_LOW; + break; + default: + pr_err("AC108 config BCLK/LRCLK polarity error:%u\n\n", (fmt & SND_SOC_DAIFMT_INV_MASK) >> 8); + return -EINVAL; + } + ac108_configure_power(ac108); + + /** + *0x31: 0: normal mode, negative edge drive and positive edge sample + 1: invert mode, positive edge drive and negative edge sample + */ + ac108_multi_chips_update_bits(I2S_BCLK_CTRL, 0x01 << BCLK_POLARITY, brck_polarity << BCLK_POLARITY, ac108); + /** + * 0x32: same as 0x31 + */ + ac108_multi_chips_update_bits(I2S_LRCK_CTRL1, 0x01 << LRCK_POLARITY, lrck_polarity << LRCK_POLARITY, ac108); + /** + * 0x34:Encoding Mode Selection,Mode + * Selection,data is offset by 1 BCLKs to LRCK + * normal mode for the last half cycle of BCLK in the slot ? + * turn to hi-z state (TDM) when not transferring slot ? + */ + ac108_multi_chips_update_bits(I2S_FMT_CTRL1, 0x01 << ENCD_SEL | 0x03 << MODE_SEL | 0x01 << TX2_OFFSET | + 0x01 << TX1_OFFSET | 0x01 << TX_SLOT_HIZ | 0x01 << TX_STATE, + ac108->data_protocol << ENCD_SEL | + ac108->i2s_mode << MODE_SEL | + tx_offset << TX2_OFFSET | + tx_offset << TX1_OFFSET | + 0x00 << TX_SLOT_HIZ | + 0x01 << TX_STATE, ac108); + + /** + * 0x60: + * MSB / LSB First Select: This driver only support MSB First + * Select . + * OUT2_MUTE,OUT1_MUTE shoule be set in widget. + * LRCK = 1 BCLK width + * Linear PCM + * + * TODO:pcm mode, bit[0:1] and bit[2] is special + */ + ac108_multi_chips_update_bits(I2S_FMT_CTRL3, 0x01 << TX_MLS | 0x03 << SEXT | 0x01 << LRCK_WIDTH | 0x03 << TX_PDM, + 0x00 << TX_MLS | 0x03 << SEXT | 0x00 << LRCK_WIDTH | 0x00 << TX_PDM, ac108); + + /**???*/ + ac108_multi_chips_write(HPF_EN,0x00,ac108); + return 0; +} + +static const struct snd_soc_dai_ops ac108_dai_ops = { + /*DAI clocking configuration*/ + .set_sysclk = ac108_set_sysclk, + + + /*ALSA PCM audio operations*/ + .hw_params = ac108_hw_params, +// .trigger = ac108_trigger, +// .hw_free = ac108_hw_free, +// +// /*DAI format configuration*/ + .set_fmt = ac108_set_fmt, +}; + + +static const struct regmap_config ac108_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = PRNG_CLK_CTRL, + .cache_type = REGCACHE_RBTREE, +}; +static struct snd_soc_dai_driver ac108_dai0 = { + .name = "ac108-codec0", + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = AC108_CHANNELS_MAX, + .rates = AC108_RATES, + .formats = AC108_FORMATS, + }, + .ops = &ac108_dai_ops, +}; + + +static struct snd_soc_dai_driver ac108_dai1 = { + .name = "ac108-codec1", + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = AC108_CHANNELS_MAX, + .rates = AC108_RATES, + .formats = AC108_FORMATS, + }, + .ops = &ac108_dai_ops, +}; + +static struct snd_soc_dai_driver ac108_dai2 = { + .name = "ac108-codec2", + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = AC108_CHANNELS_MAX, + .rates = AC108_RATES, + .formats = AC108_FORMATS, + }, + .ops = &ac108_dai_ops, +}; + +static struct snd_soc_dai_driver ac108_dai3 = { + .name = "ac108-codec3", + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = AC108_CHANNELS_MAX, + .rates = AC108_RATES, + .formats = AC108_FORMATS, + }, + .ops = &ac108_dai_ops, +}; + +static struct snd_soc_dai_driver *ac108_dai[] = { + &ac108_dai0, + + &ac108_dai1, + + &ac108_dai2, + + &ac108_dai3, +}; + +static int ac108_add_widgets(struct snd_soc_codec *codec) { + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + + snd_soc_add_codec_controls(codec, ac108_snd_controls, + ARRAY_SIZE(ac108_snd_controls)); + + + snd_soc_dapm_new_controls(dapm, ac108_dapm_widgets, + ARRAY_SIZE(ac108_dapm_widgets)); + + snd_soc_dapm_add_routes(dapm, ac108_dapm_routes, ARRAY_SIZE(ac108_dapm_routes)); + + return 0; +} +static int ac108_probe(struct snd_soc_codec *codec) { + + dev_set_drvdata(codec->dev, ac108); + ac108_add_widgets(codec); + + return 0; +} + + +static int ac108_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) { + struct ac108_priv *ac108 = snd_soc_codec_get_drvdata(codec); + dev_dbg(codec->dev, "AC108 level:%d\n", level); + switch (level) { + case SND_SOC_BIAS_ON: + ac108_multi_chips_update_bits(ANA_ADC1_CTRL1, 0x01 << ADC1_MICBIAS_EN, 0x01 << ADC1_MICBIAS_EN, ac108); + ac108_multi_chips_update_bits(ANA_ADC2_CTRL1, 0x01 << ADC2_MICBIAS_EN, 0x01 << ADC2_MICBIAS_EN, ac108); + ac108_multi_chips_update_bits(ANA_ADC3_CTRL1, 0x01 << ADC3_MICBIAS_EN, 0x01 << ADC3_MICBIAS_EN, ac108); + ac108_multi_chips_update_bits(ANA_ADC4_CTRL1, 0x01 << ADC4_MICBIAS_EN, 0x01 << ADC4_MICBIAS_EN, ac108); + break; + case SND_SOC_BIAS_PREPARE: + /* Put the MICBIASes into regulating mode */ + break; + + case SND_SOC_BIAS_STANDBY: + + break; + + case SND_SOC_BIAS_OFF: + ac108_multi_chips_update_bits(ANA_ADC1_CTRL1, 0x01 << ADC1_MICBIAS_EN, 0x00 << ADC1_MICBIAS_EN, ac108); + ac108_multi_chips_update_bits(ANA_ADC2_CTRL1, 0x01 << ADC2_MICBIAS_EN, 0x00 << ADC2_MICBIAS_EN, ac108); + ac108_multi_chips_update_bits(ANA_ADC3_CTRL1, 0x01 << ADC3_MICBIAS_EN, 0x00 << ADC3_MICBIAS_EN, ac108); + ac108_multi_chips_update_bits(ANA_ADC4_CTRL1, 0x01 << ADC4_MICBIAS_EN, 0x00 << ADC4_MICBIAS_EN, ac108); + break; + } + + return 0; +} + + +static const struct snd_soc_codec_driver ac108_soc_codec_driver = { + .probe = ac108_probe, + .set_bias_level = ac108_set_bias_level, + .read = ac108_codec_read, + .write = ac108_codec_write, +}; + + +static ssize_t ac108_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { + int val = 0, flag = 0; + u8 i = 0, reg, num, value_w, value_r; + + val = simple_strtol(buf, NULL, 16); + flag = (val >> 16) & 0xF; + + if (flag) { + reg = (val >> 8) & 0xFF; + value_w = val & 0xFF; + ac108_multi_chips_write(reg, value_w, ac108); + printk("Write 0x%02x to REG:0x%02x\n", value_w, reg); + } else { + reg = (val >> 8) & 0xFF; + num = val & 0xff; + printk("\nRead: start REG:0x%02x,count:0x%02x\n", reg, num); + + do { + value_r = 0; + ac108_multi_chips_read(reg, &value_r, ac108); + printk("REG[0x%02x]: 0x%02x; ", reg, value_r); + reg++; + i++; + if ((i == num) || (i % 4 == 0)) printk("\n"); + } while (i < num); + } + + return count; +} + +static ssize_t ac108_show(struct device *dev, struct device_attribute *attr, char *buf) { +#if 1 + printk("echo flag|reg|val > ac108\n"); + printk("eg read star addres=0x06,count 0x10:echo 0610 >ac108\n"); + printk("eg write value:0xfe to address:0x06 :echo 106fe > ac108\n"); + return 0; +#else + return snprintf(buf, PAGE_SIZE, + "echo flag|reg|val > ac108\n" + "eg read star addres=0x06,count 0x10:echo 0610 >ac108\n" + "eg write value:0xfe to address:0x06 :echo 106fe > ac108\n"); +#endif +} + +static DEVICE_ATTR(ac108, 0644, ac108_show, ac108_store); + +static struct attribute *ac108_debug_attrs[] = { + &dev_attr_ac108.attr, + NULL, +}; + +static struct attribute_group ac108_debug_attr_group = { + .name = "ac108_debug", + .attrs = ac108_debug_attrs, +}; + + + + +static int ac108_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *i2c_id) { + int ret = 0; + struct device_node *np = i2c->dev.of_node; + unsigned int val = 0; + + if (ac108 == NULL) { + ac108 = devm_kzalloc(&i2c->dev, sizeof(struct ac108_priv), GFP_KERNEL); + if (ac108 == NULL) { + dev_err(&i2c->dev, "Unable to allocate ac108 private data\n"); + return -ENOMEM; + } + } + ret = of_property_read_u32(np, "data-protocol", &val); + if (ret) { + pr_err("Please set data-protocol.\n"); + return -EINVAL; + } + ac108->data_protocol = val; + + + pr_err(" i2c_id number :%d\n", (int)(i2c_id->driver_data)); + pr_err(" ac108 codec_index :%d\n", ac108->codec_index); + pr_err(" ac108 I2S data protocol type :%d\n", ac108->data_protocol); + + ac108->i2c[i2c_id->driver_data] = i2c; + if (ac108->codec_index == 0) { + ret = snd_soc_register_codec(&i2c->dev, &ac108_soc_codec_driver, ac108_dai[i2c_id->driver_data], 1); + if (ret < 0) { + dev_err(&i2c->dev, "Failed to register ac108 codec: %d\n", ret); + } + } + + ac108->codec_index++; + + /*Writing this register 0x12 resets all register to their default state.*/ + ac108_write(CHIP_RST, CHIP_RST_VAL, i2c); + + ret = sysfs_create_group(&i2c->dev.kobj, &ac108_debug_attr_group); + if (ret) { + pr_err("failed to create attr group\n"); + } + + return ret; +} + +static int ac108_i2c_remove(struct i2c_client *client) { + snd_soc_unregister_codec(&client->dev); + return 0; +} + +static const struct i2c_device_id ac108_i2c_id[] = { + { "ac108_0", 0 }, + { "ac108_1", 1 }, + { "ac108_2", 2 }, + { "ac108_3", 3 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ac108_i2c_id); + +static const struct of_device_id ac108_of_match[] = { + { .compatible = "x-power,ac108_0", }, + { .compatible = "x-power,ac108_1", }, + { .compatible = "x-power,ac108_2", }, + { .compatible = "x-power,ac108_3", }, + { } +}; +MODULE_DEVICE_TABLE(of, ac108_of_match); + +static struct i2c_driver ac108_i2c_driver = { + .driver = { + .name = "ac108-codec", + .of_match_table = ac108_of_match, + }, + .probe = ac108_i2c_probe, + .remove = ac108_i2c_remove, + .id_table = ac108_i2c_id, +}; + +module_i2c_driver(ac108_i2c_driver); + +MODULE_DESCRIPTION("ASoC AC108 driver"); +MODULE_AUTHOR("Baozhu Zuo"); +MODULE_LICENSE("GPL"); diff --git a/ac108.h b/ac108.h new file mode 100755 index 0000000..8ab57bb --- /dev/null +++ b/ac108.h @@ -0,0 +1,774 @@ +/* + * ac108.h -- ac108 ALSA Soc Audio driver + * + * Author: panjunwen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#ifndef _AC108_H +#define _AC108_H + + +/*** AC108 Codec Register Define***/ + +//Chip Reset +#define CHIP_RST 0x00 +#define CHIP_RST_VAL 0x12 + +//Power Control +#define PWR_CTRL1 0x01 +#define PWR_CTRL2 0x02 +#define PWR_CTRL3 0x03 +#define PWR_CTRL4 0x04 +#define PWR_CTRL5 0x05 +#define PWR_CTRL6 0x06 +#define PWR_CTRL7 0x07 +#define PWR_CTRL8 0x08 +#define PWR_CTRL9 0x09 + +//PLL Configure Control +#define PLL_CTRL1 0x10 +#define PLL_CTRL2 0x11 +#define PLL_CTRL3 0x12 +#define PLL_CTRL4 0x13 +#define PLL_CTRL5 0x14 +#define PLL_CTRL6 0x16 +#define PLL_CTRL7 0x17 +#define PLL_LOCK_CTRL 0x18 + +//System Clock Control +#define SYSCLK_CTRL 0x20 +#define MOD_CLK_EN 0x21 +#define MOD_RST_CTRL 0x22 +#define DSM_CLK_CTRL 0x25 + +//I2S Common Control +#define I2S_CTRL 0x30 +#define I2S_BCLK_CTRL 0x31 +#define I2S_LRCK_CTRL1 0x32 +#define I2S_LRCK_CTRL2 0x33 +#define I2S_FMT_CTRL1 0x34 +#define I2S_FMT_CTRL2 0x35 +#define I2S_FMT_CTRL3 0x36 + +//I2S TX1 Control +#define I2S_TX1_CTRL1 0x38 +#define I2S_TX1_CTRL2 0x39 +#define I2S_TX1_CTRL3 0x3A +#define I2S_TX1_CHMP_CTRL1 0x3C +#define I2S_TX1_CHMP_CTRL2 0x3D +#define I2S_TX1_CHMP_CTRL3 0x3E +#define I2S_TX1_CHMP_CTRL4 0x3F + +//I2S TX2 Control +#define I2S_TX2_CTRL1 0x40 +#define I2S_TX2_CTRL2 0x41 +#define I2S_TX2_CTRL3 0x42 +#define I2S_TX2_CHMP_CTRL1 0x44 +#define I2S_TX2_CHMP_CTRL2 0x45 +#define I2S_TX2_CHMP_CTRL3 0x46 +#define I2S_TX2_CHMP_CTRL4 0x47 + +//I2S RX1 Control +#define I2S_RX1_CTRL1 0x50 +#define I2S_RX1_CHMP_CTRL1 0x54 +#define I2S_RX1_CHMP_CTRL2 0x55 +#define I2S_RX1_CHMP_CTRL3 0x56 +#define I2S_RX1_CHMP_CTRL4 0x57 + +//I2S Loopback Debug +#define I2S_LPB_DEBUG 0x58 + +//ADC Common Control +#define ADC_SPRC 0x60 +#define ADC_DIG_EN 0x61 +#define DMIC_EN 0x62 +#define ADC_DSR 0x63 +#define ADC_FIR 0x64 +#define ADC_DDT_CTRL 0x65 + +//HPF Control +#define HPF_EN 0x66 +#define HPF_COEF_REGH1 0x67 +#define HPF_COEF_REGH2 0x68 +#define HPF_COEF_REGL1 0x69 +#define HPF_COEF_REGL2 0x6A +#define HPF_GAIN_REGH1 0x6B +#define HPF_GAIN_REGH2 0x6C +#define HPF_GAIN_REGL1 0x6D +#define HPF_GAIN_REGL2 0x6E + +//ADC Digital Channel Volume Control +#define ADC1_DVOL_CTRL 0x70 +#define ADC2_DVOL_CTRL 0x71 +#define ADC3_DVOL_CTRL 0x72 +#define ADC4_DVOL_CTRL 0x73 + +//ADC Digital Mixer Source and Gain Control +#define ADC1_DMIX_SRC 0x76 +#define ADC2_DMIX_SRC 0x77 +#define ADC3_DMIX_SRC 0x78 +#define ADC4_DMIX_SRC 0x79 + +//ADC Digital Debug Control +#define ADC_DIG_DEBUG 0x7F + +//I2S Pad Drive Control +#define I2S_DAT_PADDRV_CTRL 0x80 +#define I2S_CLK_PADDRV_CTRL 0x81 + +//Analog PGA Control +#define ANA_PGA1_CTRL 0x90 +#define ANA_PGA2_CTRL 0x91 +#define ANA_PGA3_CTRL 0x92 +#define ANA_PGA4_CTRL 0x93 + +//MIC Offset Control +#define MIC_OFFSET_CTRL1 0x96 +#define MIC_OFFSET_CTRL2 0x97 +#define MIC1_OFFSET_STATU1 0x98 +#define MIC1_OFFSET_STATU2 0x99 +#define MIC2_OFFSET_STATU1 0x9A +#define MIC2_OFFSET_STATU2 0x9B +#define MIC3_OFFSET_STATU1 0x9C +#define MIC3_OFFSET_STATU2 0x9D +#define MIC4_OFFSET_STATU1 0x9E +#define MIC4_OFFSET_STATU2 0x9F + +//ADC1 Analog Control +#define ANA_ADC1_CTRL1 0xA0 +#define ANA_ADC1_CTRL2 0xA1 +#define ANA_ADC1_CTRL3 0xA2 +#define ANA_ADC1_CTRL4 0xA3 +#define ANA_ADC1_CTRL5 0xA4 +#define ANA_ADC1_CTRL6 0xA5 +#define ANA_ADC1_CTRL7 0xA6 + +//ADC2 Analog Control +#define ANA_ADC2_CTRL1 0xA7 +#define ANA_ADC2_CTRL2 0xA8 +#define ANA_ADC2_CTRL3 0xA9 +#define ANA_ADC2_CTRL4 0xAA +#define ANA_ADC2_CTRL5 0xAB +#define ANA_ADC2_CTRL6 0xAC +#define ANA_ADC2_CTRL7 0xAD + +//ADC3 Analog Control +#define ANA_ADC3_CTRL1 0xAE +#define ANA_ADC3_CTRL2 0xAF +#define ANA_ADC3_CTRL3 0xB0 +#define ANA_ADC3_CTRL4 0xB1 +#define ANA_ADC3_CTRL5 0xB2 +#define ANA_ADC3_CTRL6 0xB3 +#define ANA_ADC3_CTRL7 0xB4 + +//ADC4 Analog Control +#define ANA_ADC4_CTRL1 0xB5 +#define ANA_ADC4_CTRL2 0xB6 +#define ANA_ADC4_CTRL3 0xB7 +#define ANA_ADC4_CTRL4 0xB8 +#define ANA_ADC4_CTRL5 0xB9 +#define ANA_ADC4_CTRL6 0xBA +#define ANA_ADC4_CTRL7 0xBB + +//GPIO Configure +#define GPIO_CFG1 0xC0 +#define GPIO_CFG2 0xC1 +#define GPIO_DAT 0xC2 +#define GPIO_DRV 0xC3 +#define GPIO_PULL 0xC4 +#define GPIO_INT_CFG 0xC5 +#define GPIO_INT_EN 0xC6 +#define GPIO_INT_STATUS 0xC7 + +//Misc +#define BGTC_DAT 0xD1 +#define BGVC_DAT 0xD2 +#define PRNG_CLK_CTRL 0xDF + + + +/*** AC108 Codec Register Bit Define***/ + +/*PWR_CTRL1*/ +#define CP12_CTRL 4 +#define CP12_SENSE_SELECT 3 + +/*PWR_CTRL2*/ +#define CP12_SENSE_FILT 6 +#define CP12_COMP_FF_EN 3 +#define CP12_FORCE_ENABLE 2 +#define CP12_FORCE_RSTB 1 + +/*PWR_CTRL3*/ +#define LDO33DIG_CTRL 0 + +/*PWR_CTRL6*/ +#define LDO33ANA_2XHDRM 2 +#define LDO33ANA_ENABLE 0 + +/*PWR_CTRL7*/ +#define VREF_SEL 3 +#define VREF_FASTSTART_ENABLE 1 +#define VREF_ENABLE 0 + +/*PWR_CTRL9*/ +#define VREFP_FASTSTART_ENABLE 7 +#define VREFP_RESCTRL 5 +#define VREFP_LPMODE 4 +#define IGEN_TRIM 1 +#define VREFP_ENABLE 0 + + +/*PLL_CTRL1*/ +#define PLL_IBIAS 4 +#define PLL_NDET 3 +#define PLL_LOCKED_STATUS 2 +#define PLL_COM_EN 1 +#define PLL_EN 0 + +/*PLL_CTRL2*/ +#define PLL_PREDIV2 5 +#define PLL_PREDIV1 0 + +/*PLL_CTRL3*/ +#define PLL_LOOPDIV_MSB 0 + +/*PLL_CTRL4*/ +#define PLL_LOOPDIV_LSB 0 + +/*PLL_CTRL5*/ +#define PLL_POSTDIV2 5 +#define PLL_POSTDIV1 0 + +/*PLL_CTRL6*/ +#define PLL_LDO 6 +#define PLL_CP 0 + +/*PLL_CTRL7*/ +#define PLL_CAP 6 +#define PLL_RES 4 +#define PLL_TEST_EN 0 + +/*PLL_LOCK_CTRL*/ +#define LOCK_LEVEL1 2 +#define LOCK_LEVEL2 1 +#define PLL_LOCK_EN 0 + + +/*SYSCLK_CTRL*/ +#define PLLCLK_EN 7 +#define PLLCLK_SRC 4 +#define SYSCLK_SRC 3 +#define SYSCLK_EN 0 + +/*MOD_CLK_EN & MOD_RST_CTRL*/ +#define I2S 7 +#define ADC_DIGITAL 4 +#define MIC_OFFSET_CALIBRATION 1 +#define ADC_ANALOG 0 + +/*DSM_CLK_CTRL*/ +#define MIC_OFFSET_DIV 4 +#define DSM_CLK_SEL 0 + + +/*I2S_CTRL*/ +#define BCLK_IOEN 7 +#define LRCK_IOEN 6 +#define SDO2_EN 5 +#define SDO1_EN 4 +#define TXEN 2 +#define RXEN 1 +#define GEN 0 + +/*I2S_BCLK_CTRL*/ +#define EDGE_TRANSFER 5 +#define BCLK_POLARITY 4 +#define BCLKDIV 0 + +/*I2S_LRCK_CTRL1*/ +#define LRCK_POLARITY 4 +#define LRCK_PERIODH 0 + +/*I2S_LRCK_CTRL2*/ +#define LRCK_PERIODL 0 + +/*I2S_FMT_CTRL1*/ +#define ENCD_SEL 6 +#define MODE_SEL 4 +#define TX2_OFFSET 3 +#define TX1_OFFSET 2 +#define TX_SLOT_HIZ 1 +#define TX_STATE 0 + +/*I2S_FMT_CTRL2*/ +#define SLOT_WIDTH_SEL 4 +#define SAMPLE_RESOLUTION 0 + +/*I2S_FMT_CTRL3*/ +#define TX_MLS 7 +#define SEXT 5 +#define OUT2_MUTE 4 +#define OUT1_MUTE 3 +#define LRCK_WIDTH 2 +#define TX_PDM 0 + + +/*I2S_TX1_CTRL1*/ +#define TX1_CHSEL 0 + +/*I2S_TX1_CTRL2*/ +#define TX1_CH8_EN 7 +#define TX1_CH7_EN 6 +#define TX1_CH6_EN 5 +#define TX1_CH5_EN 4 +#define TX1_CH4_EN 3 +#define TX1_CH3_EN 2 +#define TX1_CH2_EN 1 +#define TX1_CH1_EN 0 + +/*I2S_TX1_CTRL3*/ +#define TX1_CH16_EN 7 +#define TX1_CH15_EN 6 +#define TX1_CH14_EN 5 +#define TX1_CH13_EN 4 +#define TX1_CH12_EN 3 +#define TX1_CH11_EN 2 +#define TX1_CH10_EN 1 +#define TX1_CH9_EN 0 + +/*I2S_TX1_CHMP_CTRL1*/ +#define TX1_CH4_MAP 6 +#define TX1_CH3_MAP 4 +#define TX1_CH2_MAP 2 +#define TX1_CH1_MAP 0 + +/*I2S_TX1_CHMP_CTRL2*/ +#define TX1_CH8_MAP 6 +#define TX1_CH7_MAP 4 +#define TX1_CH6_MAP 2 +#define TX1_CH5_MAP 0 + +/*I2S_TX1_CHMP_CTRL3*/ +#define TX1_CH12_MAP 6 +#define TX1_CH11_MAP 4 +#define TX1_CH10_MAP 2 +#define TX1_CH9_MAP 0 + +/*I2S_TX1_CHMP_CTRL4*/ +#define TX1_CH16_MAP 6 +#define TX1_CH15_MAP 4 +#define TX1_CH14_MAP 2 +#define TX1_CH13_MAP 0 + + +/*I2S_TX2_CTRL1*/ +#define TX2_CHSEL 0 + +/*I2S_TX2_CHMP_CTRL1*/ +#define TX2_CH4_MAP 6 +#define TX2_CH3_MAP 4 +#define TX2_CH2_MAP 2 +#define TX2_CH1_MAP 0 + +/*I2S_TX2_CHMP_CTRL2*/ +#define TX2_CH8_MAP 6 +#define TX2_CH7_MAP 4 +#define TX2_CH6_MAP 2 +#define TX2_CH5_MAP 0 + +/*I2S_TX2_CHMP_CTRL3*/ +#define TX2_CH12_MAP 6 +#define TX2_CH11_MAP 4 +#define TX2_CH10_MAP 2 +#define TX2_CH9_MAP 0 + +/*I2S_TX2_CHMP_CTRL4*/ +#define TX2_CH16_MAP 6 +#define TX2_CH15_MAP 4 +#define TX2_CH14_MAP 2 +#define TX2_CH13_MAP 0 + + +/*I2S_RX1_CTRL1*/ +#define RX1_CHSEL 0 + +/*I2S_RX1_CHMP_CTRL1*/ +#define RX1_CH4_MAP 6 +#define RX1_CH3_MAP 4 +#define RX1_CH2_MAP 2 +#define RX1_CH1_MAP 0 + +/*I2S_RX1_CHMP_CTRL2*/ +#define RX1_CH8_MAP 6 +#define RX1_CH7_MAP 4 +#define RX1_CH6_MAP 2 +#define RX1_CH5_MAP 0 + +/*I2S_RX1_CHMP_CTRL3*/ +#define RX1_CH12_MAP 6 +#define RX1_CH11_MAP 4 +#define RX1_CH10_MAP 2 +#define RX1_CH9_MAP 0 + +/*I2S_RX1_CHMP_CTRL4*/ +#define RX1_CH16_MAP 6 +#define RX1_CH15_MAP 4 +#define RX1_CH14_MAP 2 +#define RX1_CH13_MAP 0 + + +/*I2S_LPB_DEBUG*/ +#define I2S_LPB_DEBUG_EN 0 + + +/*ADC_SPRC*/ +#define ADC_FS_I2S1 0 + +/*ADC_DIG_EN*/ +#define DG_EN 4 +#define ENAD4 3 +#define ENAD3 2 +#define ENAD2 1 +#define ENAD1 0 + +/*DMIC_EN*/ +#define DMIC2_EN 1 +#define DMIC1_EN 0 + +/*ADC_DSR*/ +#define DIG_ADC4_SRS 6 +#define DIG_ADC3_SRS 4 +#define DIG_ADC2_SRS 2 +#define DIG_ADC1_SRS 0 + +/*ADC_DDT_CTRL*/ +#define ADOUT_DLY_EN 2 +#define ADOUT_DTS 0 + + +/*HPF_EN*/ +#define DIG_ADC4_HPF_EN 3 +#define DIG_ADC3_HPF_EN 2 +#define DIG_ADC2_HPF_EN 1 +#define DIG_ADC1_HPF_EN 0 + + +/*ADC1_DMIX_SRC*/ +#define ADC1_ADC4_DMXL_GC 7 +#define ADC1_ADC3_DMXL_GC 6 +#define ADC1_ADC2_DMXL_GC 5 +#define ADC1_ADC1_DMXL_GC 4 +#define ADC1_ADC4_DMXL_SRC 3 +#define ADC1_ADC3_DMXL_SRC 2 +#define ADC1_ADC2_DMXL_SRC 1 +#define ADC1_ADC1_DMXL_SRC 0 + +/*ADC2_DMIX_SRC*/ +#define ADC2_ADC4_DMXL_GC 7 +#define ADC2_ADC3_DMXL_GC 6 +#define ADC2_ADC2_DMXL_GC 5 +#define ADC2_ADC1_DMXL_GC 4 +#define ADC2_ADC4_DMXL_SRC 3 +#define ADC2_ADC3_DMXL_SRC 2 +#define ADC2_ADC2_DMXL_SRC 1 +#define ADC2_ADC1_DMXL_SRC 0 + +/*ADC3_DMIX_SRC*/ +#define ADC3_ADC4_DMXL_GC 7 +#define ADC3_ADC3_DMXL_GC 6 +#define ADC3_ADC2_DMXL_GC 5 +#define ADC3_ADC1_DMXL_GC 4 +#define ADC3_ADC4_DMXL_SRC 3 +#define ADC3_ADC3_DMXL_SRC 2 +#define ADC3_ADC2_DMXL_SRC 1 +#define ADC3_ADC1_DMXL_SRC 0 + +/*ADC4_DMIX_SRC*/ +#define ADC4_ADC4_DMXL_GC 7 +#define ADC4_ADC3_DMXL_GC 6 +#define ADC4_ADC2_DMXL_GC 5 +#define ADC4_ADC1_DMXL_GC 4 +#define ADC4_ADC4_DMXL_SRC 3 +#define ADC4_ADC3_DMXL_SRC 2 +#define ADC4_ADC2_DMXL_SRC 1 +#define ADC4_ADC1_DMXL_SRC 0 + + +/*ADC_DIG_DEBUG*/ +#define ADC_PTN_SEL 0 + + +/*I2S_DAT_PADDRV_CTRL*/ +#define TX2_DAT_DRV 4 +#define TX1_DAT_DRV 0 + +/*I2S_CLK_PADDRV_CTRL*/ +#define LRCK_DRV 4 +#define BCLK_DRV 0 + + +/*ANA_PGA1_CTRL*/ +#define ADC1_ANALOG_PGA 1 +#define ADC1_ANALOG_PGA_STEP 0 + +/*ANA_PGA2_CTRL*/ +#define ADC2_ANALOG_PGA 1 +#define ADC2_ANALOG_PGA_STEP 0 + +/*ANA_PGA3_CTRL*/ +#define ADC3_ANALOG_PGA 1 +#define ADC3_ANALOG_PGA_STEP 0 + +/*ANA_PGA4_CTRL*/ +#define ADC4_ANALOG_PGA 1 +#define ADC4_ANALOG_PGA_STEP 0 + + +/*MIC_OFFSET_CTRL1*/ +#define MIC_OFFSET_CAL_EN4 3 +#define MIC_OFFSET_CAL_EN3 2 +#define MIC_OFFSET_CAL_EN2 1 +#define MIC_OFFSET_CAL_EN1 0 + +/*MIC_OFFSET_CTRL2*/ +#define MIC_OFFSET_CAL_GAIN 3 +#define MIC_OFFSET_CAL_CHANNEL 1 +#define MIC_OFFSET_CAL_EN_ONCE 0 + +/*MIC1_OFFSET_STATU1*/ +#define MIC1_OFFSET_CAL_DONE 7 +#define MIC1_OFFSET_CAL_RUN_STA 6 +#define MIC1_OFFSET_MSB 0 + +/*MIC1_OFFSET_STATU2*/ +#define MIC1_OFFSET_LSB 0 + +/*MIC2_OFFSET_STATU1*/ +#define MIC2_OFFSET_CAL_DONE 7 +#define MIC2_OFFSET_CAL_RUN_STA 6 +#define MIC2_OFFSET_MSB 0 + +/*MIC2_OFFSET_STATU2*/ +#define MIC2_OFFSET_LSB 0 + +/*MIC3_OFFSET_STATU1*/ +#define MIC3_OFFSET_CAL_DONE 7 +#define MIC3_OFFSET_CAL_RUN_STA 6 +#define MIC3_OFFSET_MSB 0 + +/*MIC3_OFFSET_STATU2*/ +#define MIC3_OFFSET_LSB 0 + +/*MIC4_OFFSET_STATU1*/ +#define MIC4_OFFSET_CAL_DONE 7 +#define MIC4_OFFSET_CAL_RUN_STA 6 +#define MIC4_OFFSET_MSB 0 + +/*MIC4_OFFSET_STATU2*/ +#define MIC4_OFFSET_LSB 0 + + +/*ANA_ADC1_CTRL1*/ +#define ADC1_PGA_BYPASS 7 +#define ADC1_PGA_BYP_RCM 6 +#define ADC1_PGA_CTRL_RCM 4 +#define ADC1_PGA_MUTE 3 +#define ADC1_DSM_ENABLE 2 +#define ADC1_PGA_ENABLE 1 +#define ADC1_MICBIAS_EN 0 + +/*ANA_ADC1_CTRL3*/ +#define ADC1_ANA_CAL_EN 5 +#define ADC1_SEL_OUT_EDGE 3 +#define ADC1_DSM_DISABLE 2 +#define ADC1_VREFP_DISABLE 1 +#define ADC1_AAF_DISABLE 0 + +/*ANA_ADC1_CTRL6*/ +#define PGA_CTRL_TC 6 +#define PGA_CTRL_RC 4 +#define PGA_CTRL_I_LIN 2 +#define PGA_CTRL_I_IN 0 + +/*ANA_ADC1_CTRL7*/ +#define PGA_CTRL_HI_Z 7 +#define PGA_CTRL_SHORT_RF 6 +#define PGA_CTRL_VCM_VG 4 +#define PGA_CTRL_VCM_IN 0 + + +/*ANA_ADC2_CTRL1*/ +#define ADC2_PGA_BYPASS 7 +#define ADC2_PGA_BYP_RCM 6 +#define ADC2_PGA_CTRL_RCM 4 +#define ADC2_PGA_MUTE 3 +#define ADC2_DSM_ENABLE 2 +#define ADC2_PGA_ENABLE 1 +#define ADC2_MICBIAS_EN 0 + +/*ANA_ADC2_CTRL3*/ +#define ADC2_ANA_CAL_EN 5 +#define ADC2_SEL_OUT_EDGE 3 +#define ADC2_DSM_DISABLE 2 +#define ADC2_VREFP_DISABLE 1 +#define ADC2_AAF_DISABLE 0 + +/*ANA_ADC2_CTRL6*/ +#define PGA_CTRL_IBOOST 7 +#define PGA_CTRL_IQCTRL 6 +#define PGA_CTRL_OABIAS 4 +#define PGA_CTRL_CMLP_DIS 3 +#define PGA_CTRL_PDB_RIN 2 +#define PGA_CTRL_PEAKDET 0 + +/*ANA_ADC2_CTRL7*/ +#define AAF_LPMODE_EN 7 +#define AAF_STG2_IB_SEL 4 +#define AAFDSM_IB_DIV2 3 +#define AAF_STG1_IB_SEL 0 + + +/*ANA_ADC3_CTRL1*/ +#define ADC3_PGA_BYPASS 7 +#define ADC3_PGA_BYP_RCM 6 +#define ADC3_PGA_CTRL_RCM 4 +#define ADC3_PGA_MUTE 3 +#define ADC3_DSM_ENABLE 2 +#define ADC3_PGA_ENABLE 1 +#define ADC3_MICBIAS_EN 0 + +/*ANA_ADC3_CTRL3*/ +#define ADC3_ANA_CAL_EN 5 +#define ADC3_INVERT_CLK 4 +#define ADC3_SEL_OUT_EDGE 3 +#define ADC3_DSM_DISABLE 2 +#define ADC3_VREFP_DISABLE 1 +#define ADC3_AAF_DISABLE 0 + +/*ANA_ADC3_CTRL7*/ +#define DSM_COMP_IB_SEL 6 +#define DSM_OTA_CTRL 4 +#define DSM_LPMODE 3 +#define DSM_OTA_IB_SEL 0 + + +/*ANA_ADC4_CTRL1*/ +#define ADC4_PGA_BYPASS 7 +#define ADC4_PGA_BYP_RCM 6 +#define ADC4_PGA_CTRL_RCM 4 +#define ADC4_PGA_MUTE 3 +#define ADC4_DSM_ENABLE 2 +#define ADC4_PGA_ENABLE 1 +#define ADC4_MICBIAS_EN 0 + +/*ANA_ADC4_CTRL3*/ +#define ADC4_ANA_CAL_EN 5 +#define ADC4_SEL_OUT_EDGE 3 +#define ADC4_DSM_DISABLE 2 +#define ADC4_VREFP_DISABLE 1 +#define ADC4_AAF_DISABLE 0 + +/*ANA_ADC4_CTRL6*/ +#define DSM_DEMOFF 5 +#define DSM_EN_DITHER 4 +#define DSM_VREFP_LPMODE 2 +#define DSM_VREFP_OUTCTRL 0 + +/*ANA_ADC4_CTRL7*/ +#define CK8M_EN 5 +#define OSC_EN 4 +#define ADC4_CLK_GATING 3 +#define ADC3_CLK_GATING 2 +#define ADC2_CLK_GATING 1 +#define ADC1_CLK_GATING 0 + + +/*GPIO_CFG1*/ +#define GPIO2_SELECT 4 +#define GPIO1_SELECT 0 + +/*GPIO_CFG2*/ +#define GPIO4_SELECT 4 +#define GPIO3_SELECT 0 + +/*GPIO_DAT*///order??? +#define GPIO4_DAT 3 +#define GPIO3_DAT 2 +#define GPIO2_DAT 1 +#define GPIO1_DAT 0 + +/*GPIO_DRV*/ +#define GPIO4_DRV 6 +#define GPIO3_DRV 4 +#define GPIO2_DRV 2 +#define GPIO1_DRV 0 + +/*GPIO_PULL*/ +#define GPIO4_PULL 6 +#define GPIO3_PULL 4 +#define GPIO2_PULL 2 +#define GPIO1_PULL 0 + +/*GPIO_INT_CFG*/ +#define GPIO4_EINT_CFG 6 +#define GPIO3_EINT_CFG 4 +#define GPIO2_EINT_CFG 2 +#define GPIO1_EINT_CFG 0 + +/*GPIO_INT_EN*///order??? +#define GPIO4_EINT_EN 3 +#define GPIO3_EINT_EN 2 +#define GPIO2_EINT_EN 1 +#define GPIO1_EINT_EN 0 + +/*GPIO_INT_STATUS*///order??? +#define GPIO4_EINT_STA 3 +#define GPIO3_EINT_STA 2 +#define GPIO2_EINT_STA 1 +#define GPIO1_EINT_STA 0 + + +/*PRNG_CLK_CTRL*/ +#define PRNG_CLK_EN 1 +#define PRNG_CLK_POS 0 + + + +/*** Some Config Value ***/ + +//[SYSCLK_CTRL]: PLLCLK_SRC +#define PLLCLK_SRC_MCLK 0 +#define PLLCLK_SRC_BCLK 1 +#define PLLCLK_SRC_GPIO2 2 +#define PLLCLK_SRC_GPIO3 3 + +//[SYSCLK_CTRL]: SYSCLK_SRC +#define SYSCLK_SRC_MCLK 0 +#define SYSCLK_SRC_PLL 1 + +//I2S BCLK POLARITY Control +#define BCLK_NORMAL_DRIVE_N_SAMPLE_P 0 +#define BCLK_INVERT_DRIVE_P_SAMPLE_N 1 + +//I2S LRCK POLARITY Control +#define LRCK_LEFT_LOW_RIGHT_HIGH 0 +#define LRCK_LEFT_HIGH_RIGHT_LOW 1 + +//I2S Format Selection +#define PCM_FORMAT 0 +#define LEFT_JUSTIFIED_FORMAT 1 +#define RIGHT_JUSTIFIED_FORMAT 2 + + +//I2S data protocol types + +#define IS_ENCODING_MODE 0 + +#endif + diff --git a/ac108_asound.conf b/ac108_asound.conf new file mode 100644 index 0000000..e5fd849 --- /dev/null +++ b/ac108_asound.conf @@ -0,0 +1,12 @@ +pcm.!default { + type ac108 + slavepcm "hw:1,0" + channels 4 +} + + +pcm.ac108 { + type ac108 + slavepcm "hw:1,0" + channels 4 +} diff --git a/ac108_asound.state b/ac108_asound.state new file mode 100644 index 0000000..7b13c1e --- /dev/null +++ b/ac108_asound.state @@ -0,0 +1,1644 @@ +state.ALSA { + control.1 { + iface MIXER + name 'PCM Playback Volume' + value 400 + comment { + access 'read write' + type INTEGER + count 1 + range '-10239 - 400' + dbmin -9999999 + dbmax 400 + dbvalue.0 400 + } + } + control.2 { + iface MIXER + name 'PCM Playback Switch' + value true + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.3 { + iface MIXER + name 'PCM Playback Route' + value 0 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 2' + } + } + control.4 { + iface PCM + name 'IEC958 Playback Default' + value '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' + comment { + access 'read write' + type IEC958 + count 1 + } + } + control.5 { + iface PCM + name 'IEC958 Playback Con Mask' + value '0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' + comment { + access read + type IEC958 + count 1 + } + } + control.6 { + iface PCM + name 'IEC958 Playback PCM Stream' + value '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' + comment { + access 'read write inactive' + type IEC958 + count 1 + } + } +} +state.seeedvoicecard { + control.1 { + iface MIXER + name 'Capture Volume' + value.0 63 + value.1 63 + comment { + access 'read write' + type INTEGER + count 2 + range '0 - 63' + dbmin -1725 + dbmax 3000 + dbvalue.0 3000 + dbvalue.1 3000 + } + } + control.2 { + iface MIXER + name 'Capture Volume ZC Switch' + value.0 0 + value.1 0 + comment { + access 'read write' + type INTEGER + count 2 + range '0 - 1' + } + } + control.3 { + iface MIXER + name 'Capture Switch' + value.0 true + value.1 true + comment { + access 'read write' + type BOOLEAN + count 2 + } + } + control.4 { + iface MIXER + name 'Left Input Boost Mixer LINPUT3 Volume' + value 0 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 7' + dbmin -9999999 + dbmax 600 + dbvalue.0 -9999999 + } + } + control.5 { + iface MIXER + name 'Left Input Boost Mixer LINPUT2 Volume' + value 0 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 7' + dbmin -9999999 + dbmax 600 + dbvalue.0 -9999999 + } + } + control.6 { + iface MIXER + name 'Right Input Boost Mixer RINPUT3 Volume' + value 0 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 7' + dbmin -9999999 + dbmax 600 + dbvalue.0 -9999999 + } + } + control.7 { + iface MIXER + name 'Right Input Boost Mixer RINPUT2 Volume' + value 0 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 7' + dbmin -9999999 + dbmax 600 + dbvalue.0 -9999999 + } + } + control.8 { + iface MIXER + name 'Right Input Boost Mixer RINPUT1 Volume' + value 3 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 3' + dbmin 0 + dbmax 2900 + dbvalue.0 2900 + } + } + control.9 { + iface MIXER + name 'Left Input Boost Mixer LINPUT1 Volume' + value 3 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 3' + dbmin 0 + dbmax 2900 + dbvalue.0 2900 + } + } + control.10 { + iface MIXER + name 'Playback Volume' + value.0 255 + value.1 255 + comment { + access 'read write' + type INTEGER + count 2 + range '0 - 255' + dbmin -9999999 + dbmax 0 + dbvalue.0 0 + dbvalue.1 0 + } + } + control.11 { + iface MIXER + name 'Headphone Playback Volume' + value.0 127 + value.1 127 + comment { + access 'read write' + type INTEGER + count 2 + range '0 - 127' + dbmin -9999999 + dbmax 600 + dbvalue.0 600 + dbvalue.1 600 + } + } + control.12 { + iface MIXER + name 'Headphone Playback ZC Switch' + value.0 false + value.1 false + comment { + access 'read write' + type BOOLEAN + count 2 + } + } + control.13 { + iface MIXER + name 'Speaker Playback Volume' + value.0 127 + value.1 127 + comment { + access 'read write' + type INTEGER + count 2 + range '0 - 127' + dbmin -9999999 + dbmax 600 + dbvalue.0 600 + dbvalue.1 600 + } + } + control.14 { + iface MIXER + name 'Speaker Playback ZC Switch' + value.0 false + value.1 false + comment { + access 'read write' + type BOOLEAN + count 2 + } + } + control.15 { + iface MIXER + name 'Speaker DC Volume' + value 4 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 5' + } + } + control.16 { + iface MIXER + name 'Speaker AC Volume' + value 5 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 5' + } + } + control.17 { + iface MIXER + name 'PCM Playback -6dB Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.18 { + iface MIXER + name 'ADC Polarity' + value 'No Inversion' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 'No Inversion' + item.1 'Left Inverted' + item.2 'Right Inverted' + item.3 'Stereo Inversion' + } + } + control.19 { + iface MIXER + name 'ADC High Pass Filter Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.20 { + iface MIXER + name 'DAC Polarity' + value 'No Inversion' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 'No Inversion' + item.1 'Left Inverted' + item.2 'Right Inverted' + item.3 'Stereo Inversion' + } + } + control.21 { + iface MIXER + name 'DAC Deemphasis Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.22 { + iface MIXER + name '3D Filter Upper Cut-Off' + value High + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 High + item.1 Low + } + } + control.23 { + iface MIXER + name '3D Filter Lower Cut-Off' + value Low + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 Low + item.1 High + } + } + control.24 { + iface MIXER + name '3D Volume' + value 0 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 15' + } + } + control.25 { + iface MIXER + name '3D Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.26 { + iface MIXER + name 'ALC Function' + value Off + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 Off + item.1 Right + item.2 Left + item.3 Stereo + } + } + control.27 { + iface MIXER + name 'ALC Max Gain' + value 7 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 7' + } + } + control.28 { + iface MIXER + name 'ALC Target' + value 4 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 15' + } + } + control.29 { + iface MIXER + name 'ALC Min Gain' + value 0 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 7' + } + } + control.30 { + iface MIXER + name 'ALC Hold Time' + value 0 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 15' + } + } + control.31 { + iface MIXER + name 'ALC Mode' + value ALC + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 ALC + item.1 Limiter + } + } + control.32 { + iface MIXER + name 'ALC Decay' + value 3 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 15' + } + } + control.33 { + iface MIXER + name 'ALC Attack' + value 2 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 15' + } + } + control.34 { + iface MIXER + name 'Noise Gate Threshold' + value 0 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 31' + } + } + control.35 { + iface MIXER + name 'Noise Gate Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.36 { + iface MIXER + name 'ADC PCM Capture Volume' + value.0 195 + value.1 195 + comment { + access 'read write' + type INTEGER + count 2 + range '0 - 255' + dbmin -9999999 + dbmax 3000 + dbvalue.0 0 + dbvalue.1 0 + } + } + control.37 { + iface MIXER + name 'Left Output Mixer Boost Bypass Volume' + value 0 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 7' + dbmin -2100 + dbmax 0 + dbvalue.0 -2100 + } + } + control.38 { + iface MIXER + name 'Left Output Mixer LINPUT3 Volume' + value 0 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 7' + dbmin -2100 + dbmax 0 + dbvalue.0 -2100 + } + } + control.39 { + iface MIXER + name 'Right Output Mixer Boost Bypass Volume' + value 5 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 7' + dbmin -2100 + dbmax 0 + dbvalue.0 -600 + } + } + control.40 { + iface MIXER + name 'Right Output Mixer RINPUT3 Volume' + value 2 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 7' + dbmin -2100 + dbmax 0 + dbvalue.0 -1500 + } + } + control.41 { + iface MIXER + name 'ADC Data Output Select' + value 'Left Data = Left ADC; Right Data = Right ADC' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 'Left Data = Left ADC; Right Data = Right ADC' + item.1 'Left Data = Left ADC; Right Data = Left ADC' + item.2 'Left Data = Right ADC; Right Data = Right ADC' + item.3 'Left Data = Right ADC; Right Data = Left ADC' + } + } + control.42 { + iface MIXER + name 'DAC Mono Mix' + value Stereo + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 Stereo + item.1 Mono + } + } + control.43 { + iface MIXER + name 'Left Boost Mixer LINPUT2 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.44 { + iface MIXER + name 'Left Boost Mixer LINPUT3 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.45 { + iface MIXER + name 'Left Boost Mixer LINPUT1 Switch' + value true + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.46 { + iface MIXER + name 'Right Boost Mixer RINPUT2 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.47 { + iface MIXER + name 'Right Boost Mixer RINPUT3 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.48 { + iface MIXER + name 'Right Boost Mixer RINPUT1 Switch' + value true + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.49 { + iface MIXER + name 'Left Input Mixer Boost Switch' + value true + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.50 { + iface MIXER + name 'Right Input Mixer Boost Switch' + value true + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.51 { + iface MIXER + name 'Left Output Mixer PCM Playback Switch' + value true + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.52 { + iface MIXER + name 'Left Output Mixer LINPUT3 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.53 { + iface MIXER + name 'Left Output Mixer Boost Bypass Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.54 { + iface MIXER + name 'Right Output Mixer PCM Playback Switch' + value true + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.55 { + iface MIXER + name 'Right Output Mixer RINPUT3 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.56 { + iface MIXER + name 'Right Output Mixer Boost Bypass Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.57 { + iface MIXER + name 'Mono Output Mixer Left Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.58 { + iface MIXER + name 'Mono Output Mixer Right Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } +} +state.seeedvoicecard4 { + control.1 { + iface MIXER + name 'OUT1 Mute' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.2 { + iface MIXER + name 'OUT2 Mute' + value true + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.3 { + iface MIXER + name 'TX1 Channel1~8 enable' + value '1-4 channels ' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 'disable all' + item.1 '1-1 channels ' + item.2 '1-2 channels ' + item.3 '1-3 channels ' + item.4 '1-4 channels ' + item.5 '1-5 channels ' + item.6 '1-6 channels ' + item.7 '1-7 channels ' + item.8 '1-8 channels ' + } + } + control.4 { + iface MIXER + name 'TX1 Channel9~16 enable' + value 'disable all' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 'disable all' + item.1 '8-9 channels ' + item.2 '8-10 channels ' + item.3 '8-11 channels ' + item.4 '8-12 channels ' + item.5 '8-13 channels ' + item.6 '8-14 channels ' + item.7 '8-15 channels ' + item.8 '8-16 channels ' + } + } + control.5 { + iface MIXER + name 'TX2 Channel1~8 enable' + value 'disable all' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 'disable all' + item.1 '1-1 channels ' + item.2 '1-2 channels ' + item.3 '1-3 channels ' + item.4 '1-4 channels ' + item.5 '1-5 channels ' + item.6 '1-6 channels ' + item.7 '1-7 channels ' + item.8 '1-8 channels ' + } + } + control.6 { + iface MIXER + name 'TX2 Channel9~16 enable' + value 'disable all' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 'disable all' + item.1 '8-9 channels ' + item.2 '8-10 channels ' + item.3 '8-11 channels ' + item.4 '8-12 channels ' + item.5 '8-13 channels ' + item.6 '8-14 channels ' + item.7 '8-15 channels ' + item.8 '8-16 channels ' + } + } + control.7 { + iface MIXER + name 'CH1 digital volume' + value 180 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 255' + dbmin -11925 + dbmax 7200 + dbvalue.0 1575 + } + } + control.8 { + iface MIXER + name 'CH2 digital volume' + value 181 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 255' + dbmin -11925 + dbmax 7200 + dbvalue.0 1650 + } + } + control.9 { + iface MIXER + name 'CH3 digital volume' + value 180 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 255' + dbmin -11925 + dbmax 7200 + dbvalue.0 1575 + } + } + control.10 { + iface MIXER + name 'CH4 digital volume' + value 181 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 255' + dbmin -11925 + dbmax 7200 + dbvalue.0 1650 + } + } + control.11 { + iface MIXER + name 'ADC1 PGA gain' + value 31 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 31' + dbmin 0 + dbmax 3100 + dbvalue.0 3100 + } + } + control.12 { + iface MIXER + name 'ADC2 PGA gain' + value 31 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 31' + dbmin 0 + dbmax 3100 + dbvalue.0 3100 + } + } + control.13 { + iface MIXER + name 'ADC3 PGA gain' + value 31 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 31' + dbmin 0 + dbmax 3100 + dbvalue.0 3100 + } + } + control.14 { + iface MIXER + name 'ADC4 PGA gain' + value 31 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 31' + dbmin 0 + dbmax 3100 + dbvalue.0 3100 + } + } + control.15 { + iface MIXER + name 'Tx1 Channels' + value '4 channels ' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 '1 channels ' + item.1 '2 channels ' + item.2 '3 channels ' + item.3 '4 channels ' + item.4 '5 channels ' + item.5 '6 channels ' + item.6 '7 channels ' + item.7 '8 channels ' + item.8 '9 channels ' + item.9 '10 channels ' + item.10 '11 channels ' + item.11 '12 channels ' + item.12 '13 channels ' + item.13 '14 channels ' + item.14 '15 channels ' + item.15 '16 channels ' + } + } + control.16 { + iface MIXER + name 'Tx2 Channels' + value '1 channels ' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 '1 channels ' + item.1 '2 channels ' + item.2 '3 channels ' + item.3 '4 channels ' + item.4 '5 channels ' + item.5 '6 channels ' + item.6 '7 channels ' + item.7 '8 channels ' + item.8 '9 channels ' + item.9 '10 channels ' + item.10 '11 channels ' + item.11 '12 channels ' + item.12 '13 channels ' + item.13 '14 channels ' + item.14 '15 channels ' + item.15 '16 channels ' + } + } + control.17 { + iface MIXER + name 'Tx1 Channels 1 MAP' + value '1st adc sample' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 '1st adc sample' + item.1 '2st adc sample' + item.2 '3st adc sample' + item.3 '4st adc sample' + } + } + control.18 { + iface MIXER + name 'Tx1 Channels 2 MAP' + value '2st adc sample' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 '1st adc sample' + item.1 '2st adc sample' + item.2 '3st adc sample' + item.3 '4st adc sample' + } + } + control.19 { + iface MIXER + name 'Tx1 Channels 3 MAP' + value '3st adc sample' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 '1st adc sample' + item.1 '2st adc sample' + item.2 '3st adc sample' + item.3 '4st adc sample' + } + } + control.20 { + iface MIXER + name 'Tx1 Channels 4 MAP' + value '4st adc sample' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 '1st adc sample' + item.1 '2st adc sample' + item.2 '3st adc sample' + item.3 '4st adc sample' + } + } + control.21 { + iface MIXER + name 'Tx1 Channels 5 MAP' + value '1st adc sample' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 '1st adc sample' + item.1 '2st adc sample' + item.2 '3st adc sample' + item.3 '4st adc sample' + } + } + control.22 { + iface MIXER + name 'Tx1 Channels 6 MAP' + value '1st adc sample' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 '1st adc sample' + item.1 '2st adc sample' + item.2 '3st adc sample' + item.3 '4st adc sample' + } + } + control.23 { + iface MIXER + name 'Tx1 Channels 7 MAP' + value '1st adc sample' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 '1st adc sample' + item.1 '2st adc sample' + item.2 '3st adc sample' + item.3 '4st adc sample' + } + } + control.24 { + iface MIXER + name 'Tx1 Channels 8 MAP' + value '1st adc sample' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 '1st adc sample' + item.1 '2st adc sample' + item.2 '3st adc sample' + item.3 '4st adc sample' + } + } + control.25 { + iface MIXER + name 'Tx1 Channels 9 MAP' + value '1st adc sample' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 '1st adc sample' + item.1 '2st adc sample' + item.2 '3st adc sample' + item.3 '4st adc sample' + } + } + control.26 { + iface MIXER + name 'Tx1 Channels 10 MAP' + value '1st adc sample' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 '1st adc sample' + item.1 '2st adc sample' + item.2 '3st adc sample' + item.3 '4st adc sample' + } + } + control.27 { + iface MIXER + name 'Tx1 Channels 11 MAP' + value '1st adc sample' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 '1st adc sample' + item.1 '2st adc sample' + item.2 '3st adc sample' + item.3 '4st adc sample' + } + } + control.28 { + iface MIXER + name 'Tx1 Channels 12 MAP' + value '1st adc sample' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 '1st adc sample' + item.1 '2st adc sample' + item.2 '3st adc sample' + item.3 '4st adc sample' + } + } + control.29 { + iface MIXER + name 'Tx1 Channels 13 MAP' + value '1st adc sample' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 '1st adc sample' + item.1 '2st adc sample' + item.2 '3st adc sample' + item.3 '4st adc sample' + } + } + control.30 { + iface MIXER + name 'Tx1 Channels 14 MAP' + value '1st adc sample' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 '1st adc sample' + item.1 '2st adc sample' + item.2 '3st adc sample' + item.3 '4st adc sample' + } + } + control.31 { + iface MIXER + name 'Tx1 Channels 15 MAP' + value '1st adc sample' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 '1st adc sample' + item.1 '2st adc sample' + item.2 '3st adc sample' + item.3 '4st adc sample' + } + } + control.32 { + iface MIXER + name 'Tx1 Channels 16 MAP' + value '1st adc sample' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 '1st adc sample' + item.1 '2st adc sample' + item.2 '3st adc sample' + item.3 '4st adc sample' + } + } + control.33 { + iface MIXER + name 'Tx2 Channels 1 MAP' + value '1st adc sample' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 '1st adc sample' + item.1 '2st adc sample' + item.2 '3st adc sample' + item.3 '4st adc sample' + } + } + control.34 { + iface MIXER + name 'Tx2 Channels 2 MAP' + value '1st adc sample' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 '1st adc sample' + item.1 '2st adc sample' + item.2 '3st adc sample' + item.3 '4st adc sample' + } + } + control.35 { + iface MIXER + name 'Tx2 Channels 3 MAP' + value '1st adc sample' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 '1st adc sample' + item.1 '2st adc sample' + item.2 '3st adc sample' + item.3 '4st adc sample' + } + } + control.36 { + iface MIXER + name 'Tx2 Channels 4 MAP' + value '1st adc sample' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 '1st adc sample' + item.1 '2st adc sample' + item.2 '3st adc sample' + item.3 '4st adc sample' + } + } + control.37 { + iface MIXER + name 'Tx2 Channels 5 MAP' + value '1st adc sample' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 '1st adc sample' + item.1 '2st adc sample' + item.2 '3st adc sample' + item.3 '4st adc sample' + } + } + control.38 { + iface MIXER + name 'Tx2 Channels 6 MAP' + value '1st adc sample' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 '1st adc sample' + item.1 '2st adc sample' + item.2 '3st adc sample' + item.3 '4st adc sample' + } + } + control.39 { + iface MIXER + name 'Tx2 Channels 7 MAP' + value '1st adc sample' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 '1st adc sample' + item.1 '2st adc sample' + item.2 '3st adc sample' + item.3 '4st adc sample' + } + } + control.40 { + iface MIXER + name 'Tx2 Channels 8 MAP' + value '1st adc sample' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 '1st adc sample' + item.1 '2st adc sample' + item.2 '3st adc sample' + item.3 '4st adc sample' + } + } + control.41 { + iface MIXER + name 'Tx2 Channels 9 MAP' + value '1st adc sample' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 '1st adc sample' + item.1 '2st adc sample' + item.2 '3st adc sample' + item.3 '4st adc sample' + } + } + control.42 { + iface MIXER + name 'Tx2 Channels 10 MAP' + value '1st adc sample' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 '1st adc sample' + item.1 '2st adc sample' + item.2 '3st adc sample' + item.3 '4st adc sample' + } + } + control.43 { + iface MIXER + name 'Tx2 Channels 11 MAP' + value '1st adc sample' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 '1st adc sample' + item.1 '2st adc sample' + item.2 '3st adc sample' + item.3 '4st adc sample' + } + } + control.44 { + iface MIXER + name 'Tx2 Channels 12 MAP' + value '1st adc sample' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 '1st adc sample' + item.1 '2st adc sample' + item.2 '3st adc sample' + item.3 '4st adc sample' + } + } + control.45 { + iface MIXER + name 'Tx2 Channels 13 MAP' + value '1st adc sample' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 '1st adc sample' + item.1 '2st adc sample' + item.2 '3st adc sample' + item.3 '4st adc sample' + } + } + control.46 { + iface MIXER + name 'Tx2 Channels 14 MAP' + value '1st adc sample' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 '1st adc sample' + item.1 '2st adc sample' + item.2 '3st adc sample' + item.3 '4st adc sample' + } + } + control.47 { + iface MIXER + name 'Tx2 Channels 15 MAP' + value '1st adc sample' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 '1st adc sample' + item.1 '2st adc sample' + item.2 '3st adc sample' + item.3 '4st adc sample' + } + } + control.48 { + iface MIXER + name 'Tx2 Channels 16 MAP' + value '1st adc sample' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 '1st adc sample' + item.1 '2st adc sample' + item.2 '3st adc sample' + item.3 '4st adc sample' + } + } + control.49 { + iface MIXER + name 'ADC4 Source' + value 'Analog ADC4' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 'Analog ADC1' + item.1 'Analog ADC2' + item.2 'Analog ADC3' + item.3 'Analog ADC4' + } + } + control.50 { + iface MIXER + name 'ADC3 Source' + value 'Analog ADC3' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 'Analog ADC1' + item.1 'Analog ADC2' + item.2 'Analog ADC3' + item.3 'Analog ADC4' + } + } + control.51 { + iface MIXER + name 'ADC2 Source' + value 'Analog ADC2' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 'Analog ADC1' + item.1 'Analog ADC2' + item.2 'Analog ADC3' + item.3 'Analog ADC4' + } + } + control.52 { + iface MIXER + name 'ADC1 Source' + value 'Analog ADC1' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 'Analog ADC1' + item.1 'Analog ADC2' + item.2 'Analog ADC3' + item.3 'Analog ADC4' + } + } + control.53 { + iface MIXER + name 'ADC1 Digital Mixer gc' + value 'disable all' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 'disable all' + item.1 'ADC1 data' + item.2 'ADC2 data' + item.3 'ADC3 data' + item.4 'ADC4 data' + } + } + control.54 { + iface MIXER + name 'ADC1 Digital Mixer src' + value 'ADC1 data' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 'disable all' + item.1 'ADC1 data' + item.2 'ADC2 data' + item.3 'ADC3 data' + item.4 'ADC4 data' + } + } + control.55 { + iface MIXER + name 'ADC2 Digital Mixer gc' + value 'disable all' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 'disable all' + item.1 'ADC1 data' + item.2 'ADC2 data' + item.3 'ADC3 data' + item.4 'ADC4 data' + } + } + control.56 { + iface MIXER + name 'ADC2 Digital Mixer src' + value 'ADC2 data' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 'disable all' + item.1 'ADC1 data' + item.2 'ADC2 data' + item.3 'ADC3 data' + item.4 'ADC4 data' + } + } + control.57 { + iface MIXER + name 'ADC3 Digital Mixer gc' + value 'disable all' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 'disable all' + item.1 'ADC1 data' + item.2 'ADC2 data' + item.3 'ADC3 data' + item.4 'ADC4 data' + } + } + control.58 { + iface MIXER + name 'ADC3 Digital Mixer src' + value 'ADC3 data' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 'disable all' + item.1 'ADC1 data' + item.2 'ADC2 data' + item.3 'ADC3 data' + item.4 'ADC4 data' + } + } + control.59 { + iface MIXER + name 'ADC4 Digital Mixer gc' + value 'disable all' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 'disable all' + item.1 'ADC1 data' + item.2 'ADC2 data' + item.3 'ADC3 data' + item.4 'ADC4 data' + } + } + control.60 { + iface MIXER + name 'ADC4 Digital Mixer src' + value 'ADC4 data' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 'disable all' + item.1 'ADC1 data' + item.2 'ADC2 data' + item.3 'ADC3 data' + item.4 'ADC4 data' + } + } +} diff --git a/ac108_plugin/Makefile b/ac108_plugin/Makefile new file mode 100644 index 0000000..fede526 --- /dev/null +++ b/ac108_plugin/Makefile @@ -0,0 +1,58 @@ + +# Quiet (set to @ for a quite compile) +Q ?= @ +#Q ?= + +# Build Tools +CC := gcc +CFLAGS += -I. -Wall -funroll-loops -ffast-math -fPIC -DPIC -O0 -g +LD := gcc +LDFLAGS += -Wall -shared -lasound + +SND_PCM_OBJECTS = pcm_ac108.o +SND_PCM_LIBS = +SND_PCM_BIN = libasound_module_pcm_ac108.so + +#SND_CTL_OBJECTS = ctl_ac108.o ladspa_utils.o +#SND_CTL_LIBS = +#SND_CTL_BIN = libasound_module_ctl_ac108.so + +MULTIARCH:=$(shell gcc --print-multiarch) +LIBDIR = lib/$(MULTIARCH) + +.PHONY: all clean dep load_default + +all: Makefile $(SND_PCM_BIN) $(SND_CTL_BIN) + +dep: + @echo DEP $@ + $(Q)for i in *.c; do $(CC) -MM $(CFLAGS) "$${i}" ; done > makefile.dep + +-include makefile.dep + +$(SND_PCM_BIN): $(SND_PCM_OBJECTS) + @echo LD $@ + $(Q)$(LD) $(LDFLAGS) $(SND_PCM_LIBS) $(SND_PCM_OBJECTS) -o $(SND_PCM_BIN) + +#$(SND_CTL_BIN): $(SND_CTL_OBJECTS) +# @echo LD $@ +# $(Q)$(LD) $(LDFLAGS) $(SND_CTL_LIBS) $(SND_CTL_OBJECTS) -o $(SND_CTL_BIN) + +%.o: %.c + @echo GCC $< + $(Q)$(CC) -c $(CFLAGS) $(CPPFLAGS) $< + +clean: + @echo Cleaning... + $(Q)rm -vf *.o *.so + +install: all + @echo Installing... + $(Q)mkdir -p ${DESTDIR}/usr/$(LIBDIR)/alsa-lib/ + $(Q)install -m 644 $(SND_PCM_BIN) ${DESTDIR}/usr/$(LIBDIR)/alsa-lib/ + #$(Q)install -m 644 $(SND_CTL_BIN) ${DESTDIR}/usr/$(LIBDIR)/alsa-lib/ + +uninstall: + @echo Un-installing... + $(Q)rm ${DESTDIR}/usr/lib/alsa-lib/$(SND_PCM_BIN) + #$(Q)rm ${DESTDIR}/usr/lib/alsa-lib/$(SND_CTL_BIN) diff --git a/ac108_plugin/README.md b/ac108_plugin/README.md new file mode 100644 index 0000000..38137b2 --- /dev/null +++ b/ac108_plugin/README.md @@ -0,0 +1,5 @@ +#seeed-4mic-voicecard alsa plugin +``` +sudo apt install libasound2-dev +make && sudo make install +``` \ No newline at end of file diff --git a/ac108_plugin/libasound_module_pcm_ac108.so b/ac108_plugin/libasound_module_pcm_ac108.so new file mode 100755 index 0000000000000000000000000000000000000000..a1ee3b387b886f1c73163e29b4128bca21c2a3a2 GIT binary patch literal 32624 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�HR%g~YBCKu_FU!yluy!iftS#8k`B$+r*XFH)f!%^!)gp3Mw><$=`%8(g}nP* zaxi`SDrp{Z&81+&LuMYdoN=HFraw~mF#79bz^NDOH@d?qc9!YW{T#+;X7xmti0;#ucc5B~AKy2-`?x3kz{I}UtHX|l9l-ml zw0{-+HS7T1H%t4^g1?3x!22q-e;T?Zq5Ui1uVDx9zH;qf4u1_hfcFKoe*pd( zb^!15YkxodHS7T1SEl{T;ICl^@V-**UkZN>JAn6dc%N7M zd*QEP2k<_R_V>VF!w%qmj`nxpuVDx9KIDtEvw**b9l#tXax8#)id-F^N0|9_PI%{w z5swN(uAe|@nTM=L8NKQR*P*>whu(|z(Ne5Ke_UX_0qgCI>w&)?b$u2*>ZQjsb93?uuD20#!h-Tmx}F5gbQa7gbBj|038;S=Vrn^?}~2N+}GLD)!FvW z&W;)A%n_RKvgthZ`57&@$eTxJ!i(dmE@JBlj}3+M>99O|;64)L3ZHfeMyP}&b734M z$)nz76a8XwE}S0Chvl)5OBcr>sodftlb;^QUysueVR=vld->VirQyXnw?1KcR3uzD z1wu6!r$)mAI3bZxF{bDb`gG=P$t^w9iG)!oAy1J=GvHiBa(HxD%h4*$7$`9NL_JmO$ z!u_#K9*IVf=uZz1^B7NlPe$THIIux~sXYoVVVNFPB;gYt9?j*$J7F@IS|0f@#gDWb zMt0$BSv*XBQWkR5gco8iTN-W+Ll5i=_pACKPl521M_W6UjVJok@kF>A=V5R_=JfW| zxu^81Z&!}K3EqLA% z;|F=J659*%Y&-Tu1iEa2F`_)Dg87fc-}vLHG?wuNq6$CyZ~PZSz*$ee08dWW(J>2j z214Nc0qf3DgkwyJ^O=~_dlzHAvt8tFKApOfJtAF&~(ZVHkcK?+bWe#a_`-WbDH@6Y~nr!SKn1F;>HC zo(U9$TF?x!0N{x)Qm*;CuD$)za6?Zlm)V(&jf7V;EpLi6wyeA`n@P5uuh8(aNXx~M zi&|EQwxx&`OT>02g;NKxWQ8a#^*aHl+%wl#?aX&V-Wq3tbEc=(sdHG;nDa_+to)#8 z>}K)N&yN5zMfmFsqexUP$Dex42W&#mw-N4nK7zkqU)kqSfP4~m{2xSIucyq90*H_Y z5aM-8KP){o0i$<0O3Toc$&_`e9(1`b0x z-yaEw%M%dj6AqF3@|#i1e2zpK$}tKTK959}mY1Va`+UyzppKN^%{Zmb`{A^fUl;`9 zcc|^k@()m}N{Os0?}j0KRn7+xvby|Jj5F712hvggYZ%ox&$$Z7+VU?@Xtgs2f_3H0 zW?zkS7o7FwePpo6*$=Yr@_97M`Obqtww0erT%BJuKOB2CU> z#2G426KR&ZrOHoI(H7^gAtxg$A~fi_`yGApI;=Z)`qqN)thXTOueFLUTW`+25*m4YV_&v&_m z%Y2U$`94TIPXa0#`V9UC|0klC9HJ({g~;fVzmZ^!W%RHFKZl^wGpSzX^8n95isrz& zaDsnC+|q^gnf-eNmDPDJ16<}~)(8I=a?yW@1kZwY{&i##yb#LyyCnDt6mfsIWXzPl zA5mpW%Y;9MZ1M-r`vSb?4#Y*^d{T+P8kD%e1=|4n0-P=eE+kwkDkU zzGvZ2@HGU@+Io}py$XLlFGJ0$cicsS)sXIa33aHd?Lp#ShY8L&&T15a@T&f&;Ta0R z>>~6fSlkKiL5V}>_zUP)m3$bXXWW25MV+bu<4_N{VFety?Sy&&dP40`z#IB2DC-MV zvvm-jN2$W@AIkWwKTK-X`^F%+=08C3fzWEnAAzzw^d|ULgkA&7%1{>EW`!D<&QJ?t%?@Qj9}LAnKPSYW z;>-;lf!ukaJv4l18&W(!bUCD)5xNRKq0ozesXr&wjKAT~?-9BvbPRFpLc@rA zZs^1CsSkYvQWl4@&|yjF>(Jr6&{o842tAFz=Z8K9TU-!&2+6-NG!L3D4Sfy8w=uK< zf15%HaA*$A2OJ4qhtQVLdC-4Zs11LYhi-%Bt)XY+--{v96Pgb`zR=GAmxita><|44 znwN*316&z;0}`u3C&4Wkx*a;t6$`F_LRDoB55Jyy2coHro8$Zx0zyy08X`0gpc8tF zTgNNN=~N@_2ovQBsqx$nkI)#{iqH=LI-&0%&=dL_Nb`pNfu&K@j*w|p zmxsl=yc~X2n>-XG&dQ{7qH41Y@Zsn%yq*Nj*|No45MeU6NC`fA*M1SK{Z&1l|017z zfK>H*-UC>iH5|)`sy+{?d}6@?25t5HE3h(ODgH{%=OBf$g~AUrFGi#bfTJm-_w0M1 z?(7>p^g2hTEO^0gz@fWg2oX99W_Lp0g&91d8vON!;z+PB)C1d>ggyhp($H=ATZV8r z!4+fp>;EjGb_aX+!peaJ3&u8?=70xrgWK8a_yU*17{T|@-ye9E@L$LVHE=m11*7y2 z2Hu2j!5xIF16QLQ1>?7avL@hzR>7eM;a@wK6UbmH0I}h~%P0lG5w<4vfqO}xW{GPE zoT3hyHvlgU+(4S^2uA{kVW41^a$5r*q{KYimX(1IGAW~MCsqZRX~A98VRhhE#=V|! zN8owtwwvW{ec(>|?;+eJJQpK*!IgI+89o}oeOhPF5756RP)T{?=fS@=Fha#2 zqJKE>H;nZ#;rhTR;lpj9X$Y*K@s7}cY2amKY48!kk-%4J_@e`$X$_>w|FJs(uMFf# z^Tc7ms{*H>c<{+*0Iv>wiSSdu0^AYEqPzy5@x#pP1B(079zy z2c9foWxl(Bgnti7Ot%U8AI9^z@vN2*ja$t>h`3Fb?r)KjoE@kjqgN9`_$?>^WxijT z@I{4iLI~lHXv=)FfXMi5g>Z61NTUhaQ3#O`GakY0@5_Aa4ADoY6IIg>H0|hgu*EJ zPUy!db)L}o;O`X+?njZGv(s4z(%Dxa`{xYGX#T%LaLSqWTlmjSriD|*j2D3%;ySZg zWxHjmc7hJ%_66RB#><&QD{q^d$!CQ#m+SB&=5JK3y z|L~2A*-`;#Q{~mvEKT`D^EM2>0you47Z?d{T?*TQU&O z3FlJ|i?etCV>h1nC=`4gq$S?%jc6#6r2dg3&clFW@3|-hNb-^q;XEL%;Mu=z34W*L zJg9AS^u`NdXR!oJbC^NNKG?heksIMv=3`FF(LWWD{m=*Cdn-ysB}ev@DShV&-xmO1 zc!b6slzQH_2nB<-Kd>5>SSk}Vs1p>gdxEAMa%O{niPw)Du4`bvrKAsRt&BUOQ=D&X zp!w1cn~}yZv%F+vN8dOMRWvM`eg~DD%`y&W^$kQ1?51=U;mr=)Fwg${;;%5$W{1_) zvp*x6N~!gF883o(tuo%%O}zCwUTX385CL?HWV|7jM;mmK^5VkJ(Ci(O4Hq0%NjASV zY&r}Z6|b`xZ-{BTRL097-pw*zb5N^&>C||a72~~|C3mTe$Hfj6Z_vbBIyGKnG2W9* zMwyJqg^~`Y{=m;oyfPhcyVBFIyq*opPBSEc)z4oeGWaP`S~|D4nY05SJxqw(wDO^BL6Qn{2--u|ju1>NJK*5s?Mwo2nx8wS1qFzNKs zJW7sSN9u#?95_lfSb`o^1t_&l>hze>DKDCnRO$#LaZ#yTMhap5PewYTBSkWpRXRu5 z9l%ISTE;iso0@_|C61{7rHL+snQ%J!<%Vi{JjWFkMLB5iM- zL%APjzmI07bt|!3l-2uMf5t-d5ruUtoj$7Ar=_s&O?0O4Q9q0hoW)i1D!f$-tL8X!OM^(V=M3Sky0qf5iVaAL7w2gz-hpros+S1* zlxQC)Q92ue=#S_y$Uo2VR#j9mt^*YPvSG9mWaSzy*)Wf2g%JbQ9B0Ek#+bDTBAO9c zH4jl&p%%<;RXh;siUsrtY7Yoh9&^w&h`HeHS2~mTy!p;~3&^m#MCv>rRRg~umD+8X zXY>m-fOjp(Yb1c$w?OLzX_%T?^d)4r@FK~qwvbBcdzKchlXW(ez?q*zn;21HDx}i5 zs1PEf*A)}!ftKeM(JL0vqrSXDA%NOQ18yKK(^0CS-haa*@_&$unCr7#Ayniliv!Ae6aJLQ#hb;SnPMJ$&volXgnb#sYYfb-I>IN z3^vsiWX34DJyT;e$5Oc%)`+d622d0?Qp6JjO+(a}JF+=|XmX);G7S)^14RMcljB7e zymdg4jgA0}D?04hr!(|N99}j72+byM*HC_F9WtW~#~2Sx(pd#^gIz(;OaZyXbp;>& z6Mu!{nvWqs5P+7!!^RIgE3Xd@ZQLk4KBx3QO1u15`}aru*YJ-GeYfTLv5iBo5B?^C zw`Fi>)7T(mGUuo#ldqY2lw`__J%- zbDF1rPnV3+?C*H=+A;s4!QX5GjsLq{>Mzyagk=aSx8#hm!LhNip`r2Q*x=wG^c)-; zJUDo8sQKpcX73p{efTp!)=aznb&YQ{zP|BsgBO6uB&#R<=Wg7%We}{N8=@kfQhykZ z&mS)J*ZCJc=ik4@U-ul8P=*{J$v`RSy{RiVUgfR2k{;f{COA&%{iWWszIqUWUC&($ zg~o;+9eQ-IYs@=*rML1*Z@D76sdP;8YWA!~oxm`Rd!DDTD11XztQ#q?r)GCrf$GE1-Zz%GWv;2i{)7x6%+w5@D|6Adn8$l4({LM&a ziVmK?qzVNYW{70*m?FcB$*k}lwhm@UXoc^z!_7F;3Xe0qUh8Ov!)vO7H~T(VwA7`r zR1h>KEoLY`H7##VNsE~#Sh8-gburVA(}kO9jTJt{7H0OerpkA#vu0LB&#YN%o<@&u z^3%-9On8?o+{_s*{+|1xph=^d`cFxtcZr9I?A_cE?QY)`UAv`cQ(IrOcUfz+tFz$S z+t=3D8SU86+rDM<=Fav$oRo4!SlhJ)(bjYd9p0G?CpCl}vKDO(ZApjmf)J z>uT%m!@W&gqRXN!xRZqU2=VTbfzgqETtcD_z~IJ{*dCEhr*Q`qD04VH#>+_xs)^{f zE!~})qi)_R*_Ne@{ZuJuu ztGhd+-EA9srsqfRvPg6}vO{0OM9UPcUc6{1FNTo;(d_jiihHN7HK&2hMMVN<)_V0p ztZsQj75X&Xm(@4zZXt7>49*(ujP+j|ot6okx;xhuO{>zzGkOIxX~S*W8trO(7miMi z3<%^b@9>G@IwV}llo}nz?K|j4M>wO==az734$dEe8powTJ5B7?l_J``rFX-&C{E7h zMpMN*e-I&odw`JN$mm_kY1rZ*4)ap5 zEw~3Odo2z{nOs#hMixEeWr{}23RbPRIe5i0Ww>l8S74@#5Y8%Y-m=*)Lt4q5d-Awl zjF%PBZn&9fx*brTmrpOI8#>!BxoBmyck7z9J#CvhsTb3-b^`%pznzgy~ z2;tp5oqc^*N7ruM+}^ig%Vtz2O9ev*T`)Y!6w;!tAS=#_R=ZN?#pp;bIXIGthmr9` zQ|cI7kp#9cx(UdsLy9s3Ee(vZmHk;~3zC&r&(_T_;X27j4Xh-K{Ch`m=CP3aD6Wet z+TUn^BP;62Ct4eriB*P?jY`m(x2;8S@G@4AYT{zhY;-FYqwdb04O=>*Yp(9=?3KY* zy+&56+~B2UQ7#Lc_=aW6N?FB?cy*$c3UP~#gU^v^QI^ki>l`XYad;|pNiL>d*{!#; zZ)>-kpJ|$>mn<2Al8zixB^}jtfcJwbOx~$xu1n(yLL@JRx;N5~R+wiM^+{OSZv7ee zP!;l^(6$M4f>bwLMG9H*-6>)7J3SR!RSGaVPogtWI`y(CHK|ZXBV8G@VN+YQtpmNO zEG4?vNsdhGJl0*jYLd;5Ai z+crhp+q(O<_JF$gof|roG^;$V-LMVaM09jyG?$1kL-oCG6y<7KOTnI>9R~|>@g_Un zzUNK8@OCtvMVzM;YNe_kEQ7dtE}9+~Ko26~Y(tpiSi;kW)0efWi_;2Oqt8>DWLfp3 z4b79PAsnPw0kQ%WLrm4sy&NwE>5)O4pT-~d5Inc8KSyrjuK>P)_4EO#Hfa4T5ht!A~y$8>DV;8n+6f#v3NWyCBVXJ z7+~}%Bu|dcOd*_ld*O^yk)bXg>v}i2y`&0-6U8VYnOM9;0mMf=KITxYngNnNF z7Pu9AE4!;=D^}-0tb@Zku65C2K2Mansz67CIo8wyZ&xy^Do)&DOPR zJA16w-WqV5_LAA(&;FmqRG{I(f2#l&dPrH4(OC}0hLIVlXsB~4V(~n-(MzRk8+txh zQhT@dqJ!+1K6+%k2TcqEUF@WeE2$JmU?xy;@91gUAp2G0t>fr64z(_k5xej^gd_%9 zXg&1ppgBE2m5nMZ6-SSwnW?3|XhBu9kfB5AY@S6=j@zdVE_7DOh7~+@3yexRtqIn( zPQ)^qlgS`o^87)H>7iV@ z^r~*(_-d2LtWl{e{0731815J$8f{%uB9y6kY)>jVI8-cDg`}%4mkW&gXCH+o3+*9B zLs49X8GUDGPcMhrob|brE$^~h2sx(c?rOVwO!G%Sx}2%YZ(V}hapOfXHsL z5evSTV>S?{M`rZ$T>}|F`Bbhko{Xgu{rStWDjaSc3^#6xgc~uZ&!TuYrqY-`0Ubc` z1K0cz;O-6WY`S9E!D-gOs5n2IVd)jJWeHDhX7lLz(IynSd=6GkF00aqP~%Z-e&dN< z$W2LE==h?TBE(a?J6Z6;SGE3OqRPBR$X@K2uE&Pr4!m)^Z}+^e1HD{^##5sltn^|n z8V`Si!H0L8^5JhY`0$2PKKu;@AFsgTG9LcMf{$1Jf%MT&HtDtZt$lTHGmA^2-ot5WHa?oR62Tz9Egm}CH3txD6Cn_H=j{oxE z-Kc!Lf~$AfIV#{V8Xoie4zK(L2|Vyy6Fy$~OA_pkwHTb+YNBvQxmV1WxcTE1+>9$e zUV#l5>+uR~gjf#_16dg5=^sdFU$5XVXNnJwNEQ)5Ucn9Y;^P%(>l{^nKJnVA^#Gqx z$plm(Hd?p`_%`4#SmC5M`GajfLEP9MAp*aBFFb}n4-l(I(LbZ}hx8AaAh@Le0$gK% z2S;$o|0PTQS1sJ=7cP|N3P~Ta@W()Ja6_N5!kIpke~>KW@3q4J1>pua@t?KAClS5_ z`Ogx7n`@=LOnE}d5^uoY;J8Ua^5<`))KejNC8EI%{|0QOm~iT6$}6@+1rJ0U97o)x zJjz$ke6h}e@Sr^z-_!?evP$_}=T}dK=mou5_c!vNDHPKRxtGT6WR^5X$LHp_iN6o= z&1SiYf43FR{NtX0p}!sU#8<(C^!EZcdjcl@OEpFM&mx@L{H(b~KKBUJQz4!}xY;u> z@sAa%O@;Uug!5nmi=c_m{R0#K-wgO@GI4 zf?VyAmvGU4#D#y|h5y>ZnSMu)r6`l~7P|087vAB*cewD6xbP#u?QfX;z!m;$7w)Jb z8r6~d@I;?^sNY5x-f!Vygl8?B^!K^&M_l+1UHETZcsUyy{g5B;1~CuuUKjp87k;k` zKLp$^FMsO_f7*q=;=*~Cy&eB7;CA^vAGmp_U(|(vz=eO_h5wri|4$cQg(GX`2?MCJ zaLQZb!gspxdtLYu7yiFoctDTsDKm`sT;OI8nBUa7*b1loYk-^aBEPY-!xetL3s)y; z-u|3UQ&Y40KhrUu{%k(klos_dTvdQY% zy$93O-ahP86+iA1%@0R0Qysy|2`1?2=wK?nGls9h$nU_!MtAcPhYY`l5pQaVEWZRx zo-Kw@tn>HPy0-Chtb?*Hg8xv^i^QB|H?%K$@b+t@6hA?>Xz zxY#|#)~zcq#>PoJxht1kj#Aa6!D#N9*R^F$TUT_;+O^ogi}tmx>B3SwYg@X1_3GjmR^)eFY!9qlVAt06iB9>xl^tT% zFZ7BRtt(e0`Qace^{!rB_@v9*eOZfK3hN|xoZ`1+^bRvCOrglgZ~Ab{(2By6GLwRZ z!oed2{KAqIM}N77TDW$)RgJbtO?r#$xWbtpn1Mu_M14?ahHzOgEPvUMAP4#R9IV@& zW=maen_01pLQ{=monVmPTq;ITAKEdotYjePWNT9VFjO%Tca*W%JCj}Yx0fth^{KC! zXu11h5l&NLhA_FkHtqXdGZ0QqzuHZ-$o`CdWTQ@jlNDWkoXwpkcVXfFffZ>QLs?!` zb29^(w7%u<`bwSQHq9cswY6fBlxJLcUex97Rv87&MIl$B%_$(+@LB}=^J#8F=vt}j zUZKVtjopRJ{`i>1+mKIdN_cX120AXHsvQt3P<>a;){k{bF2w4jGg{J}Xgf@OSWIA}pIokzN5A9H?uO zU(RgGbKkT{em}D*o0doDni4~5d zwe@Ujisf-5+Rjm)bZd$ycH(P(*!dh8ETYMg0gTOb(9WG`5)Fo*47of9|Ece+;@%8juGg8R7t--viI>wW^5dQj-*E&m zjI?yQ4z(IDanf-whwm4xbqPe1&wBhdcV%&phwt6+GjbW9?^e9LTZ=IFe)v*9%A+4$ zK5@L9&eD(fbMZY2*zhAAr`yALNw)?s@AKk&6iShfOWB5Q7hvkjB@E6vj8e%u$HFR7X;%hAv6w-T(rlTmX$@3jIiG`oh z?@o)3Yman+a literal 0 HcmV?d00001 diff --git a/ac108_plugin/pcm_ac108.c b/ac108_plugin/pcm_ac108.c new file mode 100644 index 0000000..8b5da04 --- /dev/null +++ b/ac108_plugin/pcm_ac108.c @@ -0,0 +1,479 @@ +//https://github.com/HazouPH/android_device_motorola_smi-plus/blob/48029b4afc307c73181b108a5b0155b9f20856ca/smi-modules/alsa-lib_module_voice/pcm_voice.c +#include +#include +#include +#include +#include +#include + +#include + +#define ARRAY_SIZE(ary) (sizeof(ary)/sizeof(ary[0])) +#define AC108_FRAME_SIZE 4096 +struct ac108_t { + snd_pcm_ioplug_t io; + snd_pcm_t *slave; + snd_pcm_hw_params_t *hw_params; + unsigned int last_size; + unsigned int ptr; + void *buf; + unsigned int latency; // Delay in usec + unsigned int bufferSize; // Size of sample buffer +}; + +/* set up the fixed parameters of slave PCM hw_parmas */ +static int ac108_slave_hw_params_half(struct ac108_t *rec, unsigned int rate,snd_pcm_format_t format) { + int err; + snd_pcm_uframes_t bufferSize = rec->bufferSize; + unsigned int latency = rec->latency; + + unsigned int buffer_time = 0; + unsigned int period_time = 0; + if ((err = snd_pcm_hw_params_malloc(&rec->hw_params)) < 0) return err; + + if ((err = snd_pcm_hw_params_any(rec->slave, rec->hw_params)) < 0) { + SNDERR("Cannot get slave hw_params"); + goto out; + } + if ((err = snd_pcm_hw_params_set_access(rec->slave, rec->hw_params, + SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { + SNDERR("Cannot set slave access RW_INTERLEAVED"); + goto out; + } + if ((err = snd_pcm_hw_params_set_channels(rec->slave, rec->hw_params, 2)) < 0) { + SNDERR("Cannot set slave channels 2"); + goto out; + } + if ((err = snd_pcm_hw_params_set_format(rec->slave, rec->hw_params, + format)) < 0) { + SNDERR("Cannot set slave format"); + goto out; + } + if ((err = snd_pcm_hw_params_set_rate(rec->slave, rec->hw_params, rate, 0)) < 0) { + SNDERR("Cannot set slave rate %d", rate); + goto out; + } + + err = snd_pcm_hw_params_get_buffer_time_max(rec->hw_params, + &buffer_time, 0); + if (buffer_time > 80000) + buffer_time = 80000; + period_time = buffer_time / 4; + + err = snd_pcm_hw_params_set_period_time_near(rec->slave, rec->hw_params, + &period_time, 0); + if (err < 0) { + fprintf(stderr,"Unable to set_period_time_near"); + goto out; + } + err = snd_pcm_hw_params_set_buffer_time_near(rec->slave, rec->hw_params, + &buffer_time, 0); + if (err < 0) { + fprintf(stderr,"Unable to set_buffer_time_near"); + goto out; + } + + rec->bufferSize = bufferSize; + rec->latency = latency; + + return 0; + +out: + free(rec->hw_params); + rec->hw_params = NULL; + return err; +} + +/* + * start and stop callbacks - just trigger slave PCM + */ +static int ac108_start(snd_pcm_ioplug_t *io) { + struct ac108_t *rec = io->private_data; + + if(!rec->slave) { + fprintf(stderr, "slave is lost\n"); + } + + return snd_pcm_start(rec->slave); +} + +static int ac108_stop(snd_pcm_ioplug_t *io) { + struct ac108_t *rec = io->private_data; + + return snd_pcm_drop(rec->slave); +} +/* + * pointer callback + * + * Calculate the current position from the delay of slave PCM + */ +static snd_pcm_sframes_t ac108_pointer(snd_pcm_ioplug_t *io) { + struct ac108_t *rec = io->private_data; + int err, size; + + assert(rec); + + + size = snd_pcm_avail(rec->slave); + if (size < 0) return size; + size = size /2; + if (size > rec->last_size) { + rec->ptr += size - rec->last_size; + rec->ptr %= io->buffer_size; + } + + rec->last_size = size; + + //fprintf(stderr, "%s :%d %d %d %d\n", __func__, rec->ptr,size, io->appl_ptr, io->hw_ptr); + return rec->ptr; +} + +/* + * transfer callback + */ +static snd_pcm_sframes_t ac108_transfer(snd_pcm_ioplug_t *io, + const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size) { + struct ac108_t *rec = io->private_data; + char *buf; + ssize_t result; + int err; + + + /* we handle only an interleaved buffer */ + buf = (char *)areas->addr + (areas->first + areas->step * offset) / 8; + result = snd_pcm_readi(rec->slave, buf, size*2); + if (result <= 0) { + fprintf(stderr, "%s out error:%d %d\n", __func__, result); + return result; + } + rec->last_size -= size; + + + return size; + +} + +/* + * poll-related callbacks - just pass to slave PCM + */ +static int ac108_poll_descriptors_count(snd_pcm_ioplug_t *io) { + struct ac108_t *rec = io->private_data; + + //fprintf(stderr, "%s\n", __FUNCTION__); + return snd_pcm_poll_descriptors_count(rec->slave); +} + +static int ac108_poll_descriptors(snd_pcm_ioplug_t *io, struct pollfd *pfd, + unsigned int space) { + struct ac108_t *rec = io->private_data; + + //fprintf(stderr, "%s\n", __FUNCTION__); + return snd_pcm_poll_descriptors(rec->slave, pfd, space); +} + +static int ac108_poll_revents(snd_pcm_ioplug_t *io, struct pollfd *pfd, + unsigned int nfds, unsigned short *revents) { + struct ac108_t *rec = io->private_data; + + //fprintf(stderr, "%s\n", __FUNCTION__); + return snd_pcm_poll_descriptors_revents(rec->slave, pfd, nfds, revents); +} + +/* + * close callback + */ +static int ac108_close(snd_pcm_ioplug_t *io) { + struct ac108_t *rec = io->private_data; + + if (rec->slave) return snd_pcm_close(rec->slave); + return 0; +} + +static int setSoftwareParams(struct ac108_t *rec) { + snd_pcm_sw_params_t *softwareParams; + int err; + + snd_pcm_uframes_t bufferSize = 0; + snd_pcm_uframes_t periodSize = 0; + snd_pcm_uframes_t startThreshold, stopThreshold; + snd_pcm_sw_params_alloca(&softwareParams); + + // Get the current software parameters + err = snd_pcm_sw_params_current(rec->slave, softwareParams); + if (err < 0) { + fprintf(stderr, "Unable to get software parameters: %s", snd_strerror(err)); + goto done; + } + + // Configure ALSA to start the transfer when the buffer is almost full. + snd_pcm_get_params(rec->slave, &bufferSize, &periodSize); + + + startThreshold = 1; + stopThreshold = bufferSize; + + + err = snd_pcm_sw_params_set_start_threshold(rec->slave, softwareParams, + startThreshold); + if (err < 0) { + fprintf(stderr, "Unable to set start threshold to %lu frames: %s", + startThreshold, snd_strerror(err)); + goto done; + } + + err = snd_pcm_sw_params_set_stop_threshold(rec->slave, softwareParams, + stopThreshold); + if (err < 0) { + fprintf(stderr, "Unable to set stop threshold to %lu frames: %s", + stopThreshold, snd_strerror(err)); + goto done; + } + // Allow the transfer to start when at least periodSize samples can be + // processed. + err = snd_pcm_sw_params_set_avail_min(rec->slave, softwareParams, + periodSize); + if (err < 0) { + fprintf(stderr, "Unable to configure available minimum to %lu: %s", + periodSize, snd_strerror(err)); + goto done; + } + + // Commit the software parameters back to the device. + err = snd_pcm_sw_params(rec->slave, softwareParams); + if (err < 0) fprintf(stderr, "Unable to configure software parameters: %s", + snd_strerror(err)); + + + + return 0; +done: + snd_pcm_sw_params_free(softwareParams); + + return err; +} +/* + * hw_params callback + * + * Set up slave PCM according to the current parameters + */ +//static int ac108_hw_params(snd_pcm_ioplug_t *io, +// snd_pcm_hw_params_t *params ATTRIBUTE_UNUSED) { +static int ac108_hw_params(snd_pcm_ioplug_t *io) { + struct ac108_t *rec = io->private_data; + snd_pcm_sw_params_t *sparams; + snd_pcm_uframes_t period_size; + snd_pcm_uframes_t buffer_size; + int err; + if (!rec->hw_params) { + err = ac108_slave_hw_params_half(rec, io->rate*2,io->format); + if (err < 0) { + fprintf(stderr, "ac108_slave_hw_params_half error\n"); + return err; + } + } + period_size = io->period_size; + if ((err = snd_pcm_hw_params_set_period_size_near(rec->slave, rec->hw_params, + &period_size, NULL)) < 0) { + SNDERR("Cannot set slave period size %ld", period_size); + return err; + } + buffer_size = io->buffer_size; + if ((err = snd_pcm_hw_params_set_buffer_size_near(rec->slave, rec->hw_params, + &buffer_size)) < 0) { + SNDERR("Cannot set slave buffer size %ld", buffer_size); + return err; + } + if ((err = snd_pcm_hw_params(rec->slave, rec->hw_params)) < 0) { + SNDERR("Cannot set slave hw_params"); + return err; + } + + setSoftwareParams(rec); + + return 0; +} +/* + * hw_free callback + */ +static int ac108_hw_free(snd_pcm_ioplug_t *io) { + struct ac108_t *rec = io->private_data; + free(rec->hw_params); + if (rec->buf != NULL) { + free(rec->buf); + rec->buf = NULL; + } + rec->hw_params = NULL; + + return snd_pcm_hw_free(rec->slave); + +} + + +static int ac108_prepare(snd_pcm_ioplug_t *io) { + struct ac108_t *rec = io->private_data; + rec->ptr = 0; + rec->last_size =0; + if (rec->buf == NULL) { + rec->buf = malloc(io->buffer_size); + } + + return snd_pcm_prepare(rec->slave); +} +static int ac108_drain(snd_pcm_ioplug_t *io) { + struct ac108_t *rec = io->private_data; + return snd_pcm_drain(rec->slave); +} +static int ac108_sw_params(snd_pcm_ioplug_t *io, snd_pcm_sw_params_t *params) { + struct ac108_t *rec = io->private_data; + + return 0; +} + +static int ac108_delay(snd_pcm_ioplug_t * io, snd_pcm_sframes_t * delayp){ + + return 0; +} +/* + * callback table + */ +static snd_pcm_ioplug_callback_t a108_ops = { + .start = ac108_start, + .stop = ac108_stop, + .pointer = ac108_pointer, + .transfer = ac108_transfer, + .poll_descriptors_count = ac108_poll_descriptors_count, + .poll_descriptors = ac108_poll_descriptors, + .poll_revents = ac108_poll_revents, + .close = ac108_close, + .hw_params = ac108_hw_params, + .hw_free = ac108_hw_free, +// .sw_params = ac108_sw_params, + .prepare = ac108_prepare, + .drain = ac108_drain, + .delay = ac108_delay, +}; + + +static int ac108_set_hw_constraint(struct ac108_t *rec) { + static unsigned int accesses[] = { + SND_PCM_ACCESS_RW_INTERLEAVED, + SND_PCM_ACCESS_RW_NONINTERLEAVED + }; + unsigned int formats[] = { SND_PCM_FORMAT_S32, + SND_PCM_FORMAT_S16 }; + int err; + snd_pcm_uframes_t buffer_max; + unsigned int period_bytes, max_periods; + + + err = snd_pcm_ioplug_set_param_list(&rec->io, + SND_PCM_IOPLUG_HW_ACCESS, + ARRAY_SIZE(accesses), + accesses); + if (err < 0) return err; + + if ((err = snd_pcm_ioplug_set_param_list(&rec->io, SND_PCM_IOPLUG_HW_FORMAT, + ARRAY_SIZE(formats), formats)) < 0 || + (err = snd_pcm_ioplug_set_param_minmax(&rec->io, SND_PCM_IOPLUG_HW_CHANNELS, + 1, 4)) < 0 || + (err = snd_pcm_ioplug_set_param_minmax(&rec->io, SND_PCM_IOPLUG_HW_RATE, + 8000, 96000)) < 0) return err; + err = snd_pcm_ioplug_set_param_minmax(&rec->io, + SND_PCM_IOPLUG_HW_BUFFER_BYTES, + 1, 4 * 1024 * 1024); + if (err < 0) return err; + + err = snd_pcm_ioplug_set_param_minmax(&rec->io, + SND_PCM_IOPLUG_HW_PERIOD_BYTES, + 128, 2 * 1024 * 1024); + if (err < 0) return err; + + err = snd_pcm_ioplug_set_param_minmax(&rec->io, SND_PCM_IOPLUG_HW_PERIODS, + 3, 1024); + return 0; +} + +/* +/* + * Main entry point + */ +SND_PCM_PLUGIN_DEFINE_FUNC(ac108) { + snd_config_iterator_t i, next; + int err; + const char *card = NULL; + const char *pcm_string = NULL; + snd_pcm_format_t format = SND_PCM_FORMAT_S32_LE; + char devstr[128], tmpcard[8]; + struct ac108_t *rec; + int channels; + struct pollfd fds; + if (stream != SND_PCM_STREAM_CAPTURE) { + SNDERR("a108 is only for capture"); + return -EINVAL; + } + + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) continue; + if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0 || strcmp(id, "hint") == 0) continue; + + if (strcmp(id, "slavepcm") == 0) { + if (snd_config_get_string(n, &pcm_string) < 0) { + SNDERR("ac108 slavepcm must be a string"); + return -EINVAL; + } + continue; + } + + if (strcmp(id, "channels") == 0) { + long val; + if (snd_config_get_integer(n, &val) < 0) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + channels = val; + if (channels != 2 && channels != 4 && channels != 6) { + SNDERR("channels must be 2, 4 or 6"); + return -EINVAL; + } + continue; + } + } + + rec = calloc(1, sizeof(*rec)); + if (!rec) { + SNDERR("cannot allocate"); + return -ENOMEM; + } + err = snd_pcm_open(&rec->slave, pcm_string, stream, mode); + if (err < 0) goto error; + + + + //SND_PCM_NONBLOCK + rec->io.version = SND_PCM_IOPLUG_VERSION; + rec->io.name = "AC108 decode Plugin"; + rec->io.mmap_rw = 0; + rec->io.callback = &a108_ops; + rec->io.private_data = rec; + + err = snd_pcm_ioplug_create(&rec->io, name, stream, mode); + if (err < 0) goto error; + + if ((err = ac108_set_hw_constraint(rec)) < 0) { + snd_pcm_ioplug_delete(&rec->io); + return err; + } + *pcmp = rec->io.pcm; + return 0; + +error: + if (rec->slave) snd_pcm_close(rec->slave); + free(rec); + return err; +} + +SND_PCM_PLUGIN_SYMBOL(ac108); diff --git a/ac108_plugin/pcm_ac108.o b/ac108_plugin/pcm_ac108.o new file mode 100644 index 0000000000000000000000000000000000000000..26d718d6a5b8813b95f5d19316d784601a66e77c GIT binary patch literal 28216 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 /dev/null +echo 'snd-soc-ac108' | sudo tee --append /etc/modules > /dev/null +echo 'snd-soc-wm8960' | sudo tee --append /etc/modules > /dev/null + -sed -i \ - -e "s/^dtparam=audio=on/#\0/" \ - -e "s/^#\(dtparam=i2s=on\)/\1/" \ - /boot/config.txt grep -q "dtoverlay=i2s-mmap" /boot/config.txt || \ echo "dtoverlay=i2s-mmap" >> /boot/config.txt -grep -q "dtoverlay=seeed-voicecard" /boot/config.txt || \ - echo "dtoverlay=seeed-voicecard" >> /boot/config.txt + + grep -q "dtparam=i2s=on" /boot/config.txt || \ echo "dtparam=i2s=on" >> /boot/config.txt diff --git a/seeed-voicecard-overlay.dts b/seeed-2mic-voicecard-overlay.dts similarity index 96% rename from seeed-voicecard-overlay.dts rename to seeed-2mic-voicecard-overlay.dts index 1503409..5aee876 100644 --- a/seeed-voicecard-overlay.dts +++ b/seeed-2mic-voicecard-overlay.dts @@ -43,7 +43,7 @@ master_overlay: __dormant__ { compatible = "simple-audio-card"; simple-audio-card,format = "i2s"; - simple-audio-card,name = "seeed-voicecard"; + simple-audio-card,name = "seeed-2mic-voicecard"; simple-audio-card,bitclock-master = <&dailink0_master>; simple-audio-card,frame-master = <&dailink0_master>; status = "okay"; @@ -80,7 +80,7 @@ slave_overlay: __overlay__ { compatible = "simple-audio-card"; simple-audio-card,format = "i2s"; - simple-audio-card,name = "seeed-voicecard"; + simple-audio-card,name = "seeed-2mic-voicecard"; status = "okay"; simple-audio-card,widgets = "Microphone", "Mic Jack", diff --git a/seeed-2mic-voicecard.dtbo b/seeed-2mic-voicecard.dtbo new file mode 100644 index 0000000000000000000000000000000000000000..cbb75ab98293de5be3da45d6cf1656913ab4b8cc GIT binary patch literal 3465 zcmeHK&5ImG6t9knxNH_RAgDPcG72Ko%xupZlZAyS3vP5>hr|TQrKzc|*=@GJ?CPG~ z$tjl{lw1Yx{sZd4Oa1^o3Z6WB6Z{v{_v)jodU|H{5W#~5HC^w$U%h%?^)Wwf{P8;> z8=n(Gt`oBU4Se5({vz}jphNS10sg5Pw|+fMJpv-myx5- zuD@-cMQy*pGq2pR2brhxoXz$en`I zV_r7jJx(JvyBR4RpdZ)x0@mm)i1xN~28BQDelru?}EqWd5}->vX!fKJy@jRlSonv`g&?=rJa-NLW8t{Kb z;ZE?HI$4!nV2_xmlRVMZU~FFpTiBqvY&Qqay*gNO4_*O$Zt=kqJgzM5cp0!WiyZ;B zbDqQP?mb$88FYid+_M4oe`)7#xwaS^Q2*B}FlXu4`GXt3E==+;Uhv-WzO(v<+Z8Pj zd9^(xmf3Q2*&;=~E%G{x{D{V_nJpLo!A$g0#TxE8?|W-PVC}LPA23fGj2kbV>+N^% z?e6-bE{bFhmbK^p@HcaJSIm72*8SPe9a-BfbIUU2qB{QY)S^k)$^s~B%2ic2)ODw> z@GinT9h*5r@J`3J>|ipJV&ry zhHm_n4ES+vU31O}RkB1>w5kPBln;l<5$VadtZS? lZE8Yiyek#RCiset1GY(KQ53#C8-^HH9FJxrIhIzDzW}4k16}|C literal 0 HcmV?d00001 diff --git a/seeed-4mic-voicecard-overlay.dts b/seeed-4mic-voicecard-overlay.dts new file mode 100644 index 0000000..4b81453 --- /dev/null +++ b/seeed-4mic-voicecard-overlay.dts @@ -0,0 +1,66 @@ +/dts-v1/; +/plugin/; + +/ { + compatible = "brcm,bcm2708"; + fragment@0 { + target = <&i2s>; + __overlay__ { + #sound-dai-cells = <0>; + status = "okay"; + }; + }; + fragment@1 { + target-path = "/clocks"; + __overlay__ { + ac108_mclk: codec-mclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + }; + }; + }; + fragment@2 { + target = <&i2c1>; + __overlay__ { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + ac108_a: ac108@3b{ + compatible = "x-power,ac108_0"; + reg = <0x3b>; + #sound-dai-cells = <0>; + data-protocol = <1>; + }; + }; + }; + + + + fragment@3 { + target = <&sound>; + sound_overlay: __overlay__ { + compatible = "simple-audio-card"; + simple-audio-card,format = "i2s"; + simple-audio-card,name = "seeed-4mic-voicecard"; + status = "okay"; + + simple-audio-card,bitclock-master = <&dailink0_slave>; + simple-audio-card,frame-slave = <&dailink0_slave>; + dailink0_slave: simple-audio-card,cpu { + sound-dai = <&i2s>; + }; + codec_dai: simple-audio-card,codec { + sound-dai = <&ac108_a>; + clocks = <&ac108_mclk>; + }; + }; + }; + __overrides__ { + card-name = <&sound_overlay>,"seeed-voicecard,name"; + }; + + +}; + diff --git a/seeed-4mic-voicecard.dtbo b/seeed-4mic-voicecard.dtbo new file mode 100644 index 0000000000000000000000000000000000000000..4ea2ece612c955799306b03e80007198b0409657 GIT binary patch literal 2074 zcmb7F&2H2%5O$!TBB=P0kSI5_91z;De+a7OQi&5M4m}_wq{wl+t+h!U?4)!Nhdu$X z!7Fg$8F+-g0IyJ(@lTxHhQE=#@p!)ZJTo49zwey?AY}VKA!Lt`t6$;!2*zy~w_t!o zDXgEG>H1IP)XVVQ!Fj4!F-%!8eLe;*Bhf<9!-ALf{@Cb<-GXubCkT9_B$3Bl<#d%K z2=MkhsDPk;1;#)w=?WJ>F1Zo7CuSY7+b|xFST5O8l_%PRQ%~3yv(cK?&#eBR!=Gx73J=Ymn1NKk3 zntin>s+`BP$%Kpz6g68=Usm61Fs`L z>fJMO{jWsEwY^~$zYC$<1nicrV_U*uNed3^C??J%(W@erx%0-o2H?9pYA^O=)Vaf> zp8NFx@DBrix`yxR+k1c?2K=mx$G9+tCxDs%1~clZZTGC;5=5{5!`GjSs|UOkP34P; zvAhPpgTObQ*Hj(ydOjv$aV?4d0OwjZWfo^tfF}xaL$60~0?jmV8%T?J7cjF;jEfuI zM4BgS(F1vVjP|~6zLyvS_CMYm6tABd4g7m*?d#>S=ML+1)5o~zp2Q v(xys`lP385#fI8G^yUxFPN_xv|5=D!K&H!aVyVo9O<(m9Fkt zCnql+6t96C1DN=r#-8AkKn%9yxu4I%t}sN1oiVyIoS_n$-sg_WgO(r6 z$mlcrrS<5u?QhfP0cZ`@@;S_kgr=p*@ks>oD9K~y(khHHH=sp`lg9q1$m3eZTKttW z26>xgQNT1>^ZEnycKrUf8Ie>$3=1H1HrGR@;A} z#wbH>oE`mw8Vo^xc0Q3G%D9g1=3QHZ*?Rp$&z4tNcW>%SyfKZ~W8N?>D%S+_hVtuF zS8vboLs{1pKGmI6L?Pqy#FGA80M#wfA8prsN)rYea%{0muJI0{pdAUaB&TIGiiMqs z*AmSCg~|=@ygW%IFW|$c$ta5z8;tFTz$NI_m+NZJx<`9+?!B{s&kWw1gU6i(kJEsi z80-MBt@9ghbLZ{?Os^e;z&;aj{U43(n$1OX!1W(4z#O)|${$?qH1^@1ukt#D*4-?l z3vq4vg=Zk%CD?Qg<6VMnUJcuRfvvM4q1x8LvkqIMzUs8eb8Ge+=#}jwYob-h$AKr- zF}5?%wVz@Fel%C$)rcVC?t$$ilb8N_NsC=puJ?(VY!uAAWaZU5&#E+ZLmD+K8>R3P zmXa~@It9EQ8w#G`WiT#ao>&;W?$kT8e)+r2O_x`B9#4T;)Asil*lsSc{RH-XW^4zB zo0(iQlVVeygC*;nkfA2Lq-Dj4lw3GO_DDy3%en!JV@~9FT(IvemIhN2M`?AtoA1#y zgu|vo!?0kSD{zNLKQJ{e*e>bRiBXeQK#1jF``fKM#&5iGjzS!c?K5E%m6B>gc?q9Y zZ3Mh033C^!526rCkIykIvZ{>IT~a$EgQ8=DggBuwr-GV&T&hoKxu^bXLZD6|iu>?a lLQ#$BgtfICrwM+wMqaQ=CSmA*I_diuR~!!}12Gn?$o~wK`NaSL diff --git a/wm8960.ko b/wm8960.ko deleted file mode 100644 index 164ef7cc01207f06b19dbbb5f8966f4cb8e7562f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43588 zcmeHw4|r5po%Wd|K%lXNlD3gXy|k%Kn-C{|fV8G|AhAuiflh%cx~!8SGmz0qW|~YO zRb11SDs|c2XtA;t?d&6~_$<4dRd$!}+kE>)#a;BtuB^ospJmr1!xU^$QBkR)`QG>3 z-zp1J4d18;4;*W>Xh<2NQlT zTa={=a9skQ4}ag9a3+&V2DT!^tsqV%c{K23yAq zMwg|3H8JthLbYnVcwuZTnTNOopFER|)8-vWE0s(Yd7n;igfI0zpKkF!mcAUn!TXW4 zw-{-xWGYW3$Lb|ro_c7^<9#B}Ykm2$Y3q>}^C*O`n|RY@ZL(DVIPIrhm$O589~y5^ z1L;C5xp+=-a&ewFxd@mKIe(_K3-9ubdlsxuG5zb6THu+#K2@aD5|(M97jfRE@dC9z zmH)%%K0a5e7e~=RJK;~j55xDvEA>$78l=5mjcOYgTaTv}mU+hWiXKWWMEFl9CZ5g5 z^>x&L%|odH>+$>_PfRSCSDZ{a?eihev5AQnnKmCfnEnUg72_KG7d^l;z&zj!z<%KO zfNV>ztG!vj%AXw5?dW?R?YbdV;7xi;VMAH*(~wn4DPQXSt-!N_^CiDfP&05^sdXu3ZT@_|H#lmz`D)$RPG9oR=aS<^ zAESN?zW8Iv%ZF>9F6$ih6UL)`QgcyWmfw51{%8%L|9vD~p;nIMK z-u&@W@0Zg5mwf~2P2ICD`doF<;Ag*9DU<YkM z7Wf-sBkd*kmrGTOva<3<88+8?T!$k?st@_=a!Gr>3~m9g*=El0e?j;Kgw;Fr^7+w5}Yq22R}?XuQ;pGkXA&l`PD>v@3Jb74Qm$QW&8*;X_r zQ(ZN_6ywVMJ5g83RF!vUy29F-HhEq6_SE@A_b=3A^P=a{`}`jqXFsd8*w5HE)MEI2 zv^mg+ari{~4(MiHw5J4VUJsdN-Wa#-;67L@H9v=G{ z##llBp0p}vfAysbp_lrNtdu`h{Ul4EN!^STx9A0M^~Q>qQ~FWPe+ zZ1>&lOC@~I==N5A|M+K7R+h!%MgK+lD!fmo$zvHk3*srIo=iWBF~vF0^o{s+&)NM2 z@db!)XFSGB0=fpR<71z{K&XzeaV!kDv9(T)9r%( zHl}=koGySbgxC2y;yu(iP5kvU#NRMO{DK+cubCkpV`^Ia@@I&zm?8f5Eb$mesXqS) zb$f9RJ;^@gwd>qE_Q3c#^egruQ^%(MN}lOH+E%h>$b zn?|u_@Q(#C_C~t?&ZU--_{IfwUI%rA@C*FAB}VaeoJ1Nvj$M_?=F zcYUAnE8QRGBQM-vbs6WtHida1pwzReJQ{9Z%aAlqXXkx%r7vg?i0Lyr+0zED!i@^mB4`9azb+e{C#EjWo8VKAQj7 zsIlqKYY<+B@Uqrae$5l3Pk2|4a!sMUA4|`%9)J9!k3BW|xuwamkJg?%tuQtx%D7`x$DhKy^EaP7!+C*R9gq59 z9Vm`d3+?60AAjDPI(_YRUrN29_=`yUQ0g8voGMt|KbG)KypZqPId&7vh_X=!bx{v( z;ato7jqaZ#KNH6=-e1VE?XqoQ-kC@D)96BuD zPJ51ly$oA{uy4Ha^l7bE!d5cuW;^V8_C53mj7RhfpH9pBChLM>Ot%LdJ*P?^t9Q() zyti>}hWTr3W1D?{@~L933l~%rKa;NVbFA2FJEa~@y@qv-zOEGSA(Q!4aC{<9-48I1 z%{oXG@6ly_2{x4Be#m&MpXf`?v65r?!&uLGuSu(6%#%`o6$7}psduFQ5jK?TH0x81 z;QSM055f!Uo=g8Vt~tl$CzE3zDO97)h-X<_2ChkO-8MJn9k?mIW!t@}Ind93)Zn`& zT@Q{=U6U>-e)g0{J(5}h9gXUybnCF4_R#oqC{r@kI(!rIS1)>s9~+;CvR8pu;Qgoc z)ARF3ac>^Ox@L*bdlSmAe(X;W*MBqSsW!Af)3kkXyjZ=BYgwfEeER9a{L!cH`^xB- z?@5lmwWeLC{|VAJ_-;ybT-QSn`_5eSG0quJNF6Y&0bw7)cw#uqHm}a^XY-cXT!t}j zF4Az#v=DrTaV)T3Q8)VAILpm3IE;K-P%lM(%q7U5b^JE8XES(PKQlMA>#v zU9rCZ0(x1mtUu~#)V4mY>#m{L=J-(l9W|&oe=_AQMxC_5w)hv)@m0^IKkk_~+JLZ+ zd*+Yk6=NL?-SfW)kNiCYnA05fg>~tIg3&|iPZeG}`l$t99R0T+B*#{bb&bwb?;2x$ zDcFksxA;e>*CLd8KJ@uvQ>%4Nx<%Tr1?|?1{93J>(tg;g=fctC82MOgeAo|OE7G(e z4eQAdek*t_;4ARvj;_Vr_^#BqCni4Z^Pzs?c0RP5^}Od-6EA%f^_oZf{ZFEAJe-=3 zIM%DXuD^gV>c}=$>Y#)5ngp^Buq{|`?}N<#$GkA-j5YeNNpDA<91lJncj>sZ5Plx_ zkUj8+;0NJ3*4_7$hB%%nU^mA($9ui^@hE>naDf2#+Zb|OU%SYeAz466D z-_G#`SPS#{R9Sn{9^Rr~3@%R;)KOW8ci_%;WBh6EA&3_lNdzu1Rs<99?`*Z0rr* z_VGOR#3-MWm9pcMEAHcr^R|s!NXIxl51`MrYnghuJ}S7y?nCZpOZ3q(h51|eBh25t zzZ6)XNay?PzS5vLZ$FH_W$$-X`JO<%VO$IE$S)^e;xiWO&^&9o^I%%)=e^c>Px3%7 z%)-8dx{G<_u`T@ea}{;%L;JFCHX@vD#pj#~+&l7c{UEt`M(`|1q<)C8&GE&wY-e5* zS#E|=E<@h?P(KWREw1NSlkM=#LOYz}!{o~`fca$s(~>_I^RoxfnI;dzEkOO4Je_&; zBdnI3&sb4F=<8_TyXg%0{*t{ceXc!Uj$ZeaNx_v|?+599xa zZ4K_v&@Oy-`b&-zM;ZFPw*J2W&x19=U+MMo^vHzI;UAB24o(WC6b1!TVflf|=vY+Km-0Dww9vd9&{~&1U*LB^jbv|*4 z&U+F5p$``RE%S0-w;=pE3BOOLeNLzSJzP&n`29M3;*xNu9{2U&;Gb$f^P?+=$GTl@ zfXCja8h~fmVR$e6NqEeUsuVY}7T`G`xrflf+kh8=QQ#?bz&@bA0QH!i~74R8oJ0!%K(o-xo_-w?IS7N#TKuT=9v><3}d4>K}u5H`?3 zQe!q*~I0L`I z#ShKEKZg$Cv}gA;d_U|t;Nl;ef#2rhpPYt&82U?H{Ik>W_kw>6ea&fq;as~uFZb^* z7r#RI+3KJAeJ;Ll2K^UsgLT@oX$JnFiyxnX-{Io#oPlq-_{kagXHaIR{ev^`Pt2dn zADMw)fd@IK{*yEC*^W;B`5E{fF8xJVcunUHxcKEW@CRJw_0GU=aq$~x;Gc2X(>eoR zx%6+Efq%GgYJGOhz>mB5eKYVYT>M=#@$Z;w&z>3hc;KJXACfch_qzB8XW;u?{3A2) z3tjvZ!p}CJoWR%`M*ns8Xa2@PmyLe_{5}`I6!kkD-|ONx&cHu|`PFGpXa;`L#or}- z+p0_d?Qpekat8hZ@aami#>mA@z~#dGZE^O#O6~T(O6?wemDu-v~M~Sn}$$6TLXg8P2#`eomSq;OtT`u<56HdGN4oNPK zc9Wlr-Riesw?9X_-vpa;sc)8R;J0A+v02!iOMTPsV{gPizd^^P0QV9)a_HmiCoJMj z{p2@jZbmijJ~s=yS-e+*-FQ?`n>|{}7G$p@ zz5&-}kBiULA$X(5$R<5yI+NbWCVgfvL3osR!JEBS%1QV^csk05;g5=Z49NVA9wVFd zl<7=*Bb)SmMy2x$o)a{@-6($p!i>F?FG4ourCf~u%4aV+uC1N+Q6}HmN11%D@I!X8 z%(H}9E1EUBnKKQ~%teN0)@ZbY&M$gRdUJ0!JhR3yya8i}pt&cSbY?7?bY@O5GVkX* zbj~yX!}XTA_Y;4Y&eW^1-PEg*4Vrp2vZ+^A7vG)8#pPOVs`LMbpQC8=QFv1>%E#eN zxy&5qEF0IF#&Mq^SGO_?@eFunx7emEs5$6oX!op_%qp43Vlv{cwe8+9dp?~lRdj! ze6CBTb8RkrxXzi*HK4wo_RmzGT+2B5Tvtu!4!HO;+28N7$C^R^ModypduFQtVi&(~ z2K`524=HB)Lif<~DEGSQ_&y%wiKZcvzP6Qaa{O1!BRUS`99y&HL5rSmmNAPla z6$B&K{@cVvts}na<%x+09Qt3xffB}Zex8GWIAoZA1#cj;a9n3yP5NS_p9>`{KW(>W znLpDrf0Mp+mg(_&sG5hmHsvpzWqSV3TZjfT`Rf}n!g6&tf|!TICjWDIw{td*=?jq9 z6zDO;aT@Y>Y-y_prc)M>?iD(Y;QVLnO<)&Y#52n`ipB2z8r&B7&Wqe=vdG1 zgU2@*bY`qKyg#qkDh$FI3iV}poD0y%a#3$7kdD8_(Q(a6hxhHZD-*<#ZS5@ni*!o` zZwC6|Zxwta!{KhTL9dZ`dArDb703sVrHpn}f_Tqg>%r1S1|%X%Bbxgzvu3->QPWiH=zJ-K~*er*&VXJG4C(3#m}Jr@cE8 zPefu}cduF>YqH+HhASW|)E(It?p8hB?SLM}uCA}YclGkR`kJ@au3o*oX~n&DHOp7j z)v91L670D???e)SVvV#15%^oFhOFieCIli}g6;O1!9YF*c~Mhx_vCw%%odpNMpA zh3zfxUG^6K%QATCoScWddV1sWSa$+ht-YJ2oT>w1ebxi~C*BXtb!~}k?d=X*?a^5Kdzh_S8?)9lwLV~F;*b}LidtqRZ|M#{ z5{Pu^y4-9k)zXzAWkdS)?^y5FpwyO3J!Ld!a_x1LZhIt@=*ZrV@o4le*kHHuCG|_I z#fJ53n*-|~YznNtf7SZHgKMQfn0~RWBeEr;nu75JO0N9T;G>&^?Yga7{DD^10dO6$ zHM}KZJ=mLw_a>}0kv@zt^q0ui4tL<17%J7p(`nalk0jbVB#j8r!G4y}zd9D{nN+XV z+~2fX$KAiy&t7U$wc4_>vDOt{E8%sn@H)E;_jfsqpzJJ-W>coAhOBetFS4?6GJlaJ zd@_GKyiUqK)c{>LtD2iwPP;yB!M0%aqw!!*k12@1X^myt$b{+i&8r;gZNaYdcsTf; zaJLL^Q}r||4{bMYh)_O16n5NKU1h?@rGbt12WEd9uOTP)h!8FtIoJDZHr&}F!$ z=CvJm)i^5OvYQw)k*IXG;ibIVNuFJomnxLD$PlOJO)8w8SCi2L`-3+4pN&rW-9B$`0qlLkhwoWiBtJb7O;-9Xhfn}iR?<4E4rn^^YXmMxC( z*4Xx`;hB0u+Kir6txeXwyevIouv(fthYqBB5u@wXsM~7#b2`YeNTad>u$nz9W3nHr5-)vKa%W0J`ru z=T2+NEMRDt&c&Aw6B)xZE3^Cc6rOvC=yq)mCW2;OUmuQ!+fi?9Lp|T)hQP9}M|+23 zN->PGE{{%lx23PqLEdaxc9s%u3-+9s3*YE*>(A(Ub8h-C$9L*S`>NJRX9UGk?1MUu zluPFy+pgH(d5wGh{avz*({a3C>JY3`5Mbvw8DQ7d)HKE5aa~M)681pX83@ICvHYANr5#-|r}CUhPt#|c{UH|(|D^C*lV00Di?*kN{;$pXEFP@_p>Q-H zk7QbJuK)buj<-L`^xfgDksb`d*(&+Wu7@AvTHSu)$TinV-XlHF?qGU6L&WivGZ~TN z)ffKvcmD*ow+Guh!hxPgyV`S1XJ`vfZy#j-yoxPz?+9SP^8s)LC)HWHmmlB%a%WF89FEU2q0m2A-v2XWe=iGw$#^!JZaFdU z^py0oNeu494c}Q4+Y;CkVHa=5q91Z~v-J%|WPFnbVN7MC~d6{j)m#dpd(r>_}vxOdIsh zTfaHpljv^myu$w5edcrDHtnbH|G`iw(2aFOxM$jYP2}2bf2ik=%=)1#ygh*Jjzl-s z5Qa1jzU9z+V&(}|K0CDK4j8629Vp#%gWzhwD8@T^j)(b!T(&mu{twPo@!4=$UD=}wcnz8ogTK!iJ-Lgd2 zA?7T{OgyH^)or*;Sz2$&O~di>>^#~)&;5S-dEx=Haz+pL@aeBsPc?MVU#%WC9sRFM z4}Y_upRF_X!{15huhyQMp@aU{rRQqPwG_6{=Zgo-%9;8xdVXE@Ty6ard*-4v^s{xQ zTow}2Uv2#uJy%;lM$gsOkI{3b^<(lk;}lbC<~LQ=U9QgPG4saN>M`T%YW0}$ex-W& zTQNO<|K)GLSL#eZEP(?0D|L8fP0<@YSK6PkU8P?Iz*be(?`$AAC+F7Vtmm8*2+8QV z4l@0fI@1r0o~yM7+j;uk0H-}yGA@jsE49b;AFg}ouhf}(HhPTS+3GXt<{%;cl{&W` z(|)tnXY8m$Li#IpZar5zzD&6)UhIaxWBb9HV#SGxYW2N}}S%_e_4h5hd!7K8kT*f9J#cndF^`QiKFcf#+6=Qq;! z!jqc>?ibJNgYZM}Bk(8Tv$@~pyV2R~`Tt?Rg&Mf8sp&4OVqLH&zBv-?viJsD?Xnv0 z?e-P^z}NKgtGF1~TlmUTj>|bKm#tEB7tC8#=$W5)T|tTGde4pdrJmP%mgK!Y?`Dsx z?s>E`5!?(+blccruDW80a5Z*=syFvWqM>DxkgDzuN2?RzzJz_n-C2hi?#qaHrLGz@ z>SYpJjD-4>Tq360l{&+5Mr8CrTSoa5jqZr<7&fkhsv2AW`d7pO<^_#b6?cn^(+p|VCZ_gUpyhUqd zo+6rb`FJvN&fx{>hxmB1)8(nxh{*AfhySK(EOg29l?5KTUg6gQH^B4E64S2&4!~E4 z{C41Bc%wgpYo28?{9au1Tf!%RCjU(tqx1AT%W;Ri3p{>v_=xbI1x~s}YX78ws}l7& z{9BL-D^Y)qYo1AK0W!Z~;6=!1ME(!pWGj^D^4D`Qq@8V#Im1Z}|A}y({fq*s?}xx< z&E-EO>ZkbE4+Ho&@ED&DOyVKahde1Sh0Jdr;}2qJxe*w0q+bO&?vU?=yu%^0y$)v{ zIBfg)t!3NgsRzKPd`|LX-LejCSE7QDCtay}59FhnfD-ixWVWa6O4K&U`;3V4y$|xB zL#91Lg(kqZhu?g*U7mUje99rQX8`gk6AgXOK%R7E_=^VezKISjQJ;ZanBkPDgN(<5 z`7GLi_4&_``yKHkxNddG-@x@AhkOFp^tLNe|BdTmhs^R6@F7tLU5k8*;B8l;N^o7_keA?^ zwwU;-A zhRknbH;BCtLFV_dP5f5K{Qk9(-w&DJxHkDe37Ox!Hu0Z;%x_Mc_)kOT_pMF*|ANf# zR~z~3kbMrBe@uhlpEmKofXwep8+lOy-rI7>w?VcX^4*a6{bw|`uJ8LH^ZU*weE>4o z_D1f7%?_x_%?e^r91|iKXeU9|M(GPehbhm@-HFt8+%6Px6Ao$FT;Nw zV?1#QKiRT}2<=<5_`5%Cs zgxoLje-D{wvHN8Fehsp9vwd!v<@*lgy^uLSP(A~he`Cle@{b^&hg>Z3uORbp$Jq6` zNVgq-?`)O$8&Q`$Z))m$8Dz^LH$i6EP5e6`UvR|7AoIMZiGLC@$FPw<0r{9C{og|7 zc}x@kFOb_D{QrW?^OPq3$B=nm(#Z1*(Vrah8zA>P_{$;lJfq=10Ga0%jU0r`^N2>? z4w+~E?D{HIAA-y?cmULIsrnQyc&5(Ce}@a6ku!XKFLuN~k9eM8Gx6Vt%rj{w{jYcd zhbaj97poGCU0!qlpYrXHm*N^-Ov_W}>r&N(c)CG&+P4-muj3+5<=g8mM2Ra?ZIT{U zfb?amOJowbo@II;1??8A_aWYg>s#Py-yX>AxaKXD@&U*RT=P5{W$rWlDXw2D^4B3B zz%|Rn_)*AT#r0hxPqp_(^;5)ahdCC1pTu>)TH=xyyX5OtKIT^A*anMS@*7-ol}oJY<6S%CLRx(1dhs58%XG*oZuQh)toM zKs3B995tc#8@rvcZ5duCHXcl@Ik32;GchGd9|KXoI6PmN*m1?Z{P z7*%+?jxUEI1^ytj{sczmSfqW_kx_Lf3NJ!#o?^{p2?FgwIoLR<#Sx1a-|DCeyEd&& z%lXd=qm*T~6(e*dqU>VSl2lW}e;fGEom%#qR4f1v@##QP?L<0{8l6c^#_G%=L7eo& z(L|h&)TvhJf3+<&%(kh<&Z5C&fflphyk%tVl$?2NRC2G?Ce~_mYcqMWQ1)xv`n^Y^ z(hcp8*san1ZX5Ivhbj7y@1BvK1?0#VzD~@-) zLV+lcTm+-lsJ?8WwOK>!aAvqG9O=Sofu6)=HP&ZMyF6>?imah4RcEAq`b-+KCcIOH zg6)?x4DEwHcG=jh6@f;}QaxzIY@t~TUYoVxwOI>ZyV5iu&q8F)BWt;9@65)n^JWdr zT27qR&QhYftmUlBTF$zx<*dtE&bpOZb8Aq+&}Cb%?oPE?AJx2E1J-9PZhh9`)@Lnl zeP(Rx*KzSOKIZ7mm_pa*F`1sski@I2Qv<*-?T0vX8AYe#?Aoc1^vVF`Yrd0#!QN0L zhM6SMk;%J@ z3g&yZwn9C^a6{-(JZZpp|H0Eo-tFsP6emjXGP$E9kw7foldZ*_w*8a6TYojmE+Q*k??c>X{cc!eRsLx)C?42~Lz4cjbsLxst^_hER+?*Db_OHW7 z5O~Zp(B7Mf;e_2}aFnM!UBPI*EjZF?SP=0mNalXd;mKc2*nil2dnT79A@(zLaWwP8 zYwv&P;kO3vZ^lhVe_^7A6*L)Ye`^9aRA->$TN5>zvfv(SESbD5D%@4s)vD{3*EX0t zF@FHUg3GCK^79lmYrkKvTj4$1@OZi)~xzihWr}Fl;*h9We#tcthvB-n#61}MKj+J!BT{? zjN|;9<4BQtyIr47qT1|76-|bE4rE2x2k9<3n`3y+m-XfF0OvQJ!!Z2%)*oK*qNmEUT);;AIhx-M6!_0DEV~V+GF8v`5b2yC!l(I?( zbku@<=EtbkMoe0(N8aQS!%QwyPaLpc$U#7($8{!6j(Rcnk`r%CJ$Vez?v-dh(<#m3 zcWSrfvs&2??eo0EkjP2Fqk_kXC+u^+Oz%?yXh65&M@6hrEXfc`vZ+CwLcxi2RQbX%F_&h$Xnl`(y>kA6N=x{#8WS+eQSBdwrE}LV1Z^lowb9c{dUAUSQdeuqQ@5hrL?jOZZJp zc@Lj;l)%LqmRls8mN4itQ z7ob@jkun$!>j`k8fPDHuR2woH{#{Lq+3$cgIay1C@H^9mk^gmz~@F2rs*I9<& zkM?3X@PdT%H($0V_s)q$g2jUTz5&bKOhmai5r2X55r2t%fShLz3JwY$5hEqJY`lz0;37g&iGPQ1V>U<1QpcN-CUcM*S%{zZfx{PqOxJW7O} z7l4%yV>|+@fOzG=?$5;Y&`(6VMk4D?aHrrt!9gPIKPqzh^)|mj&__f$Hi*1QTRAa z-cjHRpKsSw9_AX>N8YIY`)J1tEO8X$iwORCBKQ}G;9n$y z&vhU9WyDeRHzN4uMDV#DB)^IXKHpm+zm*8Sp9ua2BKRAL;Oq4x_)*H>?;wKTPXvD_ z5&T_5@OKlz-$w-hAQ622hD-h-BKU`i;13bOA0dK&k_i4N5&Tm`@XrvzKT8DvA`yJP zTSI;^5q!R1Lw+d{{4yf=RYdR`iQxN);Pc%Z@>_}EZ6bmfC4v_xf|nqI*GGij9YpYV z6T#m{1V2dxe?JlYgGBI#h~SM7!Q*e%^8`;kul9`1cFQ zYbAomck{^GKm>0S5xgi7yd6Z?-%o`7T*uS?-9*^Gj|kpDB6wWKlXr*+-VhPI5h8de ziO6@9h9Uq9VCJ`LaStwiwo4iotsh~RG|g3rI*PJWaK{thDe{Y3D0 z62a&568XD{;O`@Xe~^fF8ziFL4iV9ALqzaLh~S+hvY!&!Pl@cOMDWfNsjtw+5blYT z`5Z#z^8|4>xWwin8@W!W?1!hGLqvG4*C|JdkcUO)I-7DI5%GGx3t6vsfqPIk#_ttu z#d?&oU$6k{NXmtRLxROv|50Cphn}d z&kF8eV#}K_M=^a#nT;cYd`FAny95UW_XzG4ObYH7JRmqIcu4TD;IQBk!J~r51dj`z z5F8aeBX~~mf}nc6ZD*liv0#Z{sh}lTE?6Px6|5I*5cCN)3$_UQ1vdz86l@dh5R41< z3HA%_5*!fRE0`4AFL*$3Q1Fo8VZmX+BZ5Z-j|mJwD1pR^=1=|EW1ml8zg8hQK1P2873MK^)2o4G!7Ca)@XW8ZG z7u+Q{Ah=gBDR@9|P;f}Fcq#N?{PA5w)=NULPq1Hbr{FHZ0l~e3Lqv?pb42LlyNG$! z7-vNEX}(LCSA}{fuERV{tibpr!j=jm%GN+^#k@?!nB7E#T~XpF>?HmSb`nov9wuTA z+D!y+9}&DH5xo6G@D38e8zO=?LIm#^5xnC>@J)-9+#Ph~VuZg13(d-a#UGLqza~ ziQpX}f;U10?<5htvqbRD5y3l81n(jdyrSEH;FS@og{)cN(Ao|5xlcR z@GcU;D?;BQub2p42@$+9B6w9q@EVEW`H0{(6TxdGf_Fi%;dWc@6Fe+h}*FaM;01!+tY|4q!C?Tqa|1_2y=8ehLT3FV7*|2V56WQyb(BxwTp3vSB-%A@IHxX{3AR&BLhsAIuG*LH{J{H)YpLZPquv7 z&Q5*jKZ-GnFzTZ&qwfH&o%%LGAN!VZK;7t1S(8n=koYD6b0>I1U z%Z)qMtBE)GB*L8eZrWq-v49Baof?c0=DF#v03krFcf)30ynNv7;Gr3=n7ZjX`EG`!!wv zTQR1YfjIIQe_qhEXZ%6TnZh9$edloPw6F2gc0X8(a1Iml*ghU8rCy_N2>P7wFdKcv z!o&81cEj&Pe__Rmqb@qmPtJUgBi}O!UkZ<^%;dYorBA&Zk;VvI`rzqqaOoS`KRG_| z$dS=k4<2nW_Hl#J*iJp>`cBE$%RoBteEP!v2hqAdRtwKW`M`5J^61v#0(o+nXh+_g zi~uw|_KA#bxQ>Ch*+e>c402S1I^KzZV*6WT$8gDVK-6{Y)OY;-_zeT|wQ)xE{{uF( Bqrw0H diff --git a/asound.conf b/wm8960_asound.conf similarity index 100% rename from asound.conf rename to wm8960_asound.conf diff --git a/asound.state b/wm8960_asound.state similarity index 100% rename from asound.state rename to wm8960_asound.state