summaryrefslogtreecommitdiff
path: root/firmware/target/mips/ingenic_x1000/shanlingq1/audiohw-shanlingq1.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/mips/ingenic_x1000/shanlingq1/audiohw-shanlingq1.c')
-rw-r--r--firmware/target/mips/ingenic_x1000/shanlingq1/audiohw-shanlingq1.c191
1 files changed, 191 insertions, 0 deletions
diff --git a/firmware/target/mips/ingenic_x1000/shanlingq1/audiohw-shanlingq1.c b/firmware/target/mips/ingenic_x1000/shanlingq1/audiohw-shanlingq1.c
new file mode 100644
index 0000000000..7314f20412
--- /dev/null
+++ b/firmware/target/mips/ingenic_x1000/shanlingq1/audiohw-shanlingq1.c
@@ -0,0 +1,191 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 Aidan MacDonald
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "audiohw.h"
23#include "system.h"
24#include "pcm_sampr.h"
25#include "aic-x1000.h"
26#include "i2c-x1000.h"
27#include "gpio-x1000.h"
28#include "x1000/aic.h"
29#include "x1000/cpm.h"
30
31/* Codec has an dedicated oscillator connected, so it can operate
32 * as i2s master or slave. I can't distinguish any difference in
33 * terms of audio quality or power consumption. Code is left here
34 * for reference in case it proves useful to change it. */
35#define CODEC_MASTER_MODE 0
36
37static int cur_fsel = HW_FREQ_48;
38static int cur_vol_l = 0, cur_vol_r = 0;
39static int cur_filter = 0;
40static enum es9218_amp_mode cur_amp_mode = ES9218_AMP_MODE_1VRMS;
41
42static void codec_start(void)
43{
44 es9218_open();
45 es9218_mute(true);
46 es9218_set_iface_role(CODEC_MASTER_MODE ? ES9218_IFACE_ROLE_MASTER
47 : ES9218_IFACE_ROLE_SLAVE);
48 es9218_set_iface_format(ES9218_IFACE_FORMAT_I2S, ES9218_IFACE_BITS_32);
49 es9218_set_dpll_bandwidth(10);
50 es9218_set_thd_compensation(true);
51 es9218_set_thd_coeffs(0, 0);
52 audiohw_set_filter_roll_off(cur_filter);
53 audiohw_set_frequency(cur_fsel);
54 audiohw_set_volume(cur_vol_l, cur_vol_r);
55 es9218_set_amp_mode(cur_amp_mode);
56}
57
58static void codec_stop(void)
59{
60 es9218_mute(true);
61 es9218_close();
62 mdelay(1);
63}
64
65void audiohw_init(void)
66{
67 /* Configure AIC */
68 aic_set_external_codec(true);
69 aic_set_i2s_mode(CODEC_MASTER_MODE ? AIC_I2S_SLAVE_MODE
70 : AIC_I2S_MASTER_MODE);
71 aic_enable_i2s_bit_clock(true);
72
73 /* Open DAC driver */
74 i2c_x1000_set_freq(1, I2C_FREQ_400K);
75 codec_start();
76}
77
78void audiohw_postinit(void)
79{
80 es9218_mute(false);
81}
82
83void audiohw_close(void)
84{
85 codec_stop();
86}
87
88void audiohw_set_frequency(int fsel)
89{
90 int sampr = hw_freq_sampr[fsel];
91
92 /* choose clock gear setting, in line with the OF */
93 enum es9218_clock_gear clkgear;
94 if(sampr <= 48000)
95 clkgear = ES9218_CLK_GEAR_4;
96 else if(sampr <= 96000)
97 clkgear = ES9218_CLK_GEAR_2;
98 else
99 clkgear = ES9218_CLK_GEAR_1;
100
101 aic_enable_i2s_bit_clock(false);
102 es9218_set_clock_gear(clkgear);
103
104 if(CODEC_MASTER_MODE)
105 es9218_set_nco_frequency(sampr);
106 else
107 aic_set_i2s_clock(X1000_CLK_SCLK_A, sampr, 64);
108
109 aic_enable_i2s_bit_clock(true);
110
111 /* save frequency selection */
112 cur_fsel = fsel;
113}
114
115static int round_step_up(int x, int step)
116{
117 int rem = x % step;
118 if(rem > 0)
119 rem -= step;
120 return x - rem;
121}
122
123void audiohw_set_volume(int vol_l, int vol_r)
124{
125 /* save volume */
126 cur_vol_l = vol_l;
127 cur_vol_r = vol_r;
128
129 /* adjust the amp setting first */
130 int amp = round_step_up(MAX(vol_l, vol_r), ES9218_AMP_VOLUME_STEP);
131 amp = MIN(amp, ES9218_AMP_VOLUME_MAX);
132 amp = MAX(amp, ES9218_AMP_VOLUME_MIN);
133
134 /* adjust digital volumes */
135 vol_l -= amp;
136 vol_l = MIN(vol_l, ES9218_DIG_VOLUME_MAX);
137 vol_l = MAX(vol_l, ES9218_DIG_VOLUME_MIN);
138
139 vol_r -= amp;
140 vol_r = MIN(vol_r, ES9218_DIG_VOLUME_MAX);
141 vol_r = MAX(vol_r, ES9218_DIG_VOLUME_MIN);
142
143 /* program DAC */
144 es9218_set_amp_volume(amp);
145 es9218_set_dig_volume(vol_l, vol_r);
146}
147
148void audiohw_set_filter_roll_off(int value)
149{
150 cur_filter = value;
151 es9218_set_filter(value);
152}
153
154void audiohw_set_power_mode(int mode)
155{
156 enum es9218_amp_mode new_amp_mode;
157 if(mode == 0)
158 new_amp_mode = ES9218_AMP_MODE_2VRMS;
159 else
160 new_amp_mode = ES9218_AMP_MODE_1VRMS;
161
162 if(new_amp_mode != cur_amp_mode) {
163 codec_stop();
164 cur_amp_mode = new_amp_mode;
165 codec_start();
166 es9218_mute(false);
167 }
168}
169
170void es9218_set_power_pin(int level)
171{
172 gpio_set_level(GPIO_ES9218_POWER, level ? 1 : 0);
173}
174
175void es9218_set_reset_pin(int level)
176{
177 gpio_set_level(GPIO_ES9218_RESET, level ? 1 : 0);
178}
179
180uint32_t es9218_get_mclk(void)
181{
182 /* Measured by running the DAC in asynchronous I2S slave mode,
183 * and reading back the DPLL number from regs 0x42-0x45 while
184 * playing back 44.1 KHz audio.
185 *
186 * CLK = (44_100 * 2**32) / 0x4b46e5
187 * = 38_393_403.29532737
188 * ~ 38.4 Mhz
189 */
190 return 38400000;
191}