diff options
author | Aidan MacDonald <amachronic@protonmail.com> | 2022-01-11 13:58:41 +0000 |
---|---|---|
committer | Aidan MacDonald <amachronic@protonmail.com> | 2022-01-29 19:28:03 +0000 |
commit | c1f1d9140407757fab16c418eed09f5517c649d7 (patch) | |
tree | ee75be10480d454ea8a8cbd38cb51d29b7019433 /firmware/target/mips/ingenic_x1000/fiiom3k/audiohw-fiiom3k.c | |
parent | bc5a6385949c9f0a17173f3512aa9a6db9175803 (diff) | |
download | rockbox-c1f1d9140407757fab16c418eed09f5517c649d7.tar.gz rockbox-c1f1d9140407757fab16c418eed09f5517c649d7.zip |
FiiO M3K: audio recording
Recording works now, although I'm sure there will be a few
things that need fine-tuning. A major issue is that writing
to the SD card creates noticable interference, which happens
on the original firmware too but seems worse under Rockbox.
(Since Rockbox waits until RAM fills up before writing data,
the interference will only be heard on >50 MiB recordings.)
Change-Id: I5561dd9668c3bdd34e92f34ef50848aef8c0b7eb
Diffstat (limited to 'firmware/target/mips/ingenic_x1000/fiiom3k/audiohw-fiiom3k.c')
-rw-r--r-- | firmware/target/mips/ingenic_x1000/fiiom3k/audiohw-fiiom3k.c | 127 |
1 files changed, 121 insertions, 6 deletions
diff --git a/firmware/target/mips/ingenic_x1000/fiiom3k/audiohw-fiiom3k.c b/firmware/target/mips/ingenic_x1000/fiiom3k/audiohw-fiiom3k.c index f7dced8f54..9374d23a81 100644 --- a/firmware/target/mips/ingenic_x1000/fiiom3k/audiohw-fiiom3k.c +++ b/firmware/target/mips/ingenic_x1000/fiiom3k/audiohw-fiiom3k.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * \/ \/ \/ \/ \/ | 7 | * \/ \/ \/ \/ \/ |
8 | * $Id$ | 8 | * $Id$ |
9 | * | 9 | * |
10 | * Copyright (C) 2021 Aidan MacDonald | 10 | * Copyright (C) 2021-2022 Aidan MacDonald |
11 | * | 11 | * |
12 | * This program is free software; you can redistribute it and/or | 12 | * This program is free software; you can redistribute it and/or |
13 | * modify it under the terms of the GNU General Public License | 13 | * modify it under the terms of the GNU General Public License |
@@ -20,6 +20,7 @@ | |||
20 | ****************************************************************************/ | 20 | ****************************************************************************/ |
21 | 21 | ||
22 | #include "audiohw.h" | 22 | #include "audiohw.h" |
23 | #include "audio.h" | ||
23 | #include "system.h" | 24 | #include "system.h" |
24 | #include "pcm_sampr.h" | 25 | #include "pcm_sampr.h" |
25 | #include "aic-x1000.h" | 26 | #include "aic-x1000.h" |
@@ -27,6 +28,11 @@ | |||
27 | #include "gpio-x1000.h" | 28 | #include "gpio-x1000.h" |
28 | #include "logf.h" | 29 | #include "logf.h" |
29 | 30 | ||
31 | static int cur_audio_source = AUDIO_SRC_PLAYBACK; | ||
32 | static int cur_vol_r = AK4376_MIN_VOLUME; | ||
33 | static int cur_vol_l = AK4376_MIN_VOLUME; | ||
34 | static int cur_recvol = 0; | ||
35 | static int cur_filter_roll_off = 0; | ||
30 | static int cur_fsel = HW_FREQ_48; | 36 | static int cur_fsel = HW_FREQ_48; |
31 | static int cur_power_mode = SOUND_HIGH_POWER; | 37 | static int cur_power_mode = SOUND_HIGH_POWER; |
32 | 38 | ||
@@ -60,29 +66,138 @@ void audiohw_postinit(void) | |||
60 | 66 | ||
61 | void audiohw_close(void) | 67 | void audiohw_close(void) |
62 | { | 68 | { |
63 | ak4376_close(); | 69 | if(cur_audio_source == AUDIO_SRC_PLAYBACK) |
70 | ak4376_close(); | ||
71 | else if(cur_audio_source == AUDIO_SRC_MIC) | ||
72 | x1000_icodec_close(); | ||
73 | } | ||
74 | |||
75 | void audio_set_output_source(int source) | ||
76 | { | ||
77 | /* this is a no-op */ | ||
78 | (void)source; | ||
79 | } | ||
80 | |||
81 | void audio_input_mux(int source, unsigned flags) | ||
82 | { | ||
83 | (void)flags; | ||
84 | |||
85 | if(source == cur_audio_source) | ||
86 | return; | ||
87 | |||
88 | /* close whatever codec is currently in use */ | ||
89 | audiohw_close(); | ||
90 | aic_enable_i2s_bit_clock(false); | ||
91 | |||
92 | /* switch to new source */ | ||
93 | cur_audio_source = source; | ||
94 | |||
95 | if(source == AUDIO_SRC_PLAYBACK) { | ||
96 | /* power on DAC */ | ||
97 | aic_set_external_codec(true); | ||
98 | aic_set_i2s_mode(AIC_I2S_MASTER_MODE); | ||
99 | ak4376_open(); | ||
100 | |||
101 | /* apply the old settings */ | ||
102 | audiohw_set_volume(cur_vol_l, cur_vol_r); | ||
103 | audiohw_set_filter_roll_off(cur_filter_roll_off); | ||
104 | set_ak_freqmode(); | ||
105 | } else if(source == AUDIO_SRC_MIC) { | ||
106 | aic_set_external_codec(false); | ||
107 | aic_set_i2s_mode(AIC_I2S_SLAVE_MODE); | ||
108 | /* Note: Sampling frequency is irrelevant here */ | ||
109 | aic_set_i2s_clock(X1000_CLK_EXCLK, 48000, 0); | ||
110 | aic_enable_i2s_bit_clock(true); | ||
111 | |||
112 | x1000_icodec_open(); | ||
113 | |||
114 | /* configure the mic */ | ||
115 | x1000_icodec_mic1_enable(true); | ||
116 | x1000_icodec_mic1_bias_enable(true); | ||
117 | x1000_icodec_mic1_configure(JZCODEC_MIC1_DIFFERENTIAL | | ||
118 | JZCODEC_MIC1_BIAS_2_08V); | ||
119 | |||
120 | /* configure the ADC */ | ||
121 | x1000_icodec_adc_mic_sel(JZCODEC_MIC_SEL_ANALOG); | ||
122 | x1000_icodec_adc_highpass_filter(true); | ||
123 | x1000_icodec_adc_frequency(cur_fsel); | ||
124 | x1000_icodec_adc_enable(true); | ||
125 | |||
126 | /* configure the mixer to put mic input in both channels */ | ||
127 | x1000_icodec_mixer_enable(true); | ||
128 | x1000_icodec_write(JZCODEC_MIX2, 0x10); | ||
129 | |||
130 | /* set gain and unmute */ | ||
131 | audiohw_set_recvol(cur_recvol, 0, AUDIO_GAIN_MIC); | ||
132 | x1000_icodec_adc_mute(false); | ||
133 | } else { | ||
134 | logf("bad audio input source: %d (flags: %x)", source, flags); | ||
135 | } | ||
64 | } | 136 | } |
65 | 137 | ||
66 | void audiohw_set_volume(int vol_l, int vol_r) | 138 | void audiohw_set_volume(int vol_l, int vol_r) |
67 | { | 139 | { |
68 | ak4376_set_volume(vol_l, vol_r); | 140 | cur_vol_l = vol_l; |
141 | cur_vol_r = vol_r; | ||
142 | |||
143 | if(cur_audio_source == AUDIO_SRC_PLAYBACK) | ||
144 | ak4376_set_volume(vol_l, vol_r); | ||
69 | } | 145 | } |
70 | 146 | ||
71 | void audiohw_set_filter_roll_off(int val) | 147 | void audiohw_set_filter_roll_off(int val) |
72 | { | 148 | { |
73 | ak4376_set_filter_roll_off(val); | 149 | cur_filter_roll_off = val; |
150 | |||
151 | if(cur_audio_source == AUDIO_SRC_PLAYBACK) | ||
152 | ak4376_set_filter_roll_off(val); | ||
74 | } | 153 | } |
75 | 154 | ||
76 | void audiohw_set_frequency(int fsel) | 155 | void audiohw_set_frequency(int fsel) |
77 | { | 156 | { |
78 | cur_fsel = fsel; | 157 | cur_fsel = fsel; |
79 | set_ak_freqmode(); | 158 | |
159 | if(cur_audio_source == AUDIO_SRC_PLAYBACK) | ||
160 | set_ak_freqmode(); | ||
161 | else | ||
162 | x1000_icodec_adc_frequency(fsel); | ||
80 | } | 163 | } |
81 | 164 | ||
82 | void audiohw_set_power_mode(int mode) | 165 | void audiohw_set_power_mode(int mode) |
83 | { | 166 | { |
84 | cur_power_mode = mode; | 167 | cur_power_mode = mode; |
85 | set_ak_freqmode(); | 168 | |
169 | if(cur_audio_source == AUDIO_SRC_PLAYBACK) | ||
170 | set_ak_freqmode(); | ||
171 | } | ||
172 | |||
173 | static int round_step_up(int x, int step) | ||
174 | { | ||
175 | int rem = x % step; | ||
176 | if(rem > 0) | ||
177 | rem -= step; | ||
178 | return x - rem; | ||
179 | } | ||
180 | |||
181 | void audiohw_set_recvol(int left, int right, int type) | ||
182 | { | ||
183 | (void)right; | ||
184 | |||
185 | if(type == AUDIO_GAIN_MIC) { | ||
186 | cur_recvol = left; | ||
187 | |||
188 | if(cur_audio_source == AUDIO_SRC_MIC) { | ||
189 | int mic_gain = round_step_up(left, X1000_ICODEC_MIC_GAIN_STEP); | ||
190 | mic_gain = MIN(mic_gain, X1000_ICODEC_MIC_GAIN_MAX); | ||
191 | mic_gain = MAX(mic_gain, X1000_ICODEC_MIC_GAIN_MIN); | ||
192 | |||
193 | int adc_gain = left - mic_gain; | ||
194 | adc_gain = MIN(adc_gain, X1000_ICODEC_ADC_GAIN_MAX); | ||
195 | adc_gain = MAX(adc_gain, X1000_ICODEC_ADC_GAIN_MIN); | ||
196 | |||
197 | x1000_icodec_adc_gain(adc_gain); | ||
198 | x1000_icodec_mic1_gain(mic_gain); | ||
199 | } | ||
200 | } | ||
86 | } | 201 | } |
87 | 202 | ||
88 | void ak4376_set_pdn_pin(int level) | 203 | void ak4376_set_pdn_pin(int level) |