diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/drivers/audio/ak4376.c | 70 | ||||
-rw-r--r-- | firmware/export/ak4376.h | 42 | ||||
-rw-r--r-- | firmware/target/mips/ingenic_x1000/fiiom3k/audiohw-fiiom3k.c | 50 |
3 files changed, 84 insertions, 78 deletions
diff --git a/firmware/drivers/audio/ak4376.c b/firmware/drivers/audio/ak4376.c index 494bbabfa4..11714b210d 100644 --- a/firmware/drivers/audio/ak4376.c +++ b/firmware/drivers/audio/ak4376.c | |||
@@ -27,6 +27,18 @@ | |||
27 | #include "system.h" | 27 | #include "system.h" |
28 | #include "i2c-async.h" | 28 | #include "i2c-async.h" |
29 | 29 | ||
30 | /* sample rates supported by the hardware */ | ||
31 | #define CAPS (SAMPR_CAP_192 | SAMPR_CAP_176 | \ | ||
32 | SAMPR_CAP_96 | SAMPR_CAP_88 | SAMPR_CAP_64 | \ | ||
33 | SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32 | \ | ||
34 | SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16 | \ | ||
35 | SAMPR_CAP_12 | SAMPR_CAP_11 | SAMPR_CAP_8) | ||
36 | |||
37 | /* future proofing */ | ||
38 | #if (HW_SAMPR_CAPS & ~CAPS) != 0 | ||
39 | # error "incorrect HW_SAMPR_CAPS" | ||
40 | #endif | ||
41 | |||
30 | #ifndef HAVE_SW_VOLUME_CONTROL | 42 | #ifndef HAVE_SW_VOLUME_CONTROL |
31 | # error "AK4376 requires HAVE_SW_VOLUME_CONTROL!" | 43 | # error "AK4376 requires HAVE_SW_VOLUME_CONTROL!" |
32 | #endif | 44 | #endif |
@@ -40,7 +52,7 @@ | |||
40 | */ | 52 | */ |
41 | 53 | ||
42 | /* Converts HW_FREQ_XX constants to register values */ | 54 | /* Converts HW_FREQ_XX constants to register values */ |
43 | static const int ak4376_fsel_to_hw[] = { | 55 | static const uint8_t ak4376_fsel_to_hw[] = { |
44 | HW_HAVE_192_(AK4376_FS_192,) | 56 | HW_HAVE_192_(AK4376_FS_192,) |
45 | HW_HAVE_176_(AK4376_FS_176,) | 57 | HW_HAVE_176_(AK4376_FS_176,) |
46 | HW_HAVE_96_(AK4376_FS_96,) | 58 | HW_HAVE_96_(AK4376_FS_96,) |
@@ -57,19 +69,13 @@ static const int ak4376_fsel_to_hw[] = { | |||
57 | HW_HAVE_8_(AK4376_FS_8,) | 69 | HW_HAVE_8_(AK4376_FS_8,) |
58 | }; | 70 | }; |
59 | 71 | ||
60 | static struct ak4376 { | 72 | static int ak4376_regs[AK4376_NUM_REGS]; |
61 | int fsel; | ||
62 | int low_mode; | ||
63 | int regs[AK4376_NUM_REGS]; | ||
64 | } ak4376; | ||
65 | 73 | ||
66 | void ak4376_init(void) | 74 | void ak4376_open(void) |
67 | { | 75 | { |
68 | /* Initialize DAC state */ | 76 | /* Initialize DAC state */ |
69 | ak4376.fsel = HW_FREQ_48; | ||
70 | ak4376.low_mode = 0; | ||
71 | for(int i = 0; i < AK4376_NUM_REGS; ++i) | 77 | for(int i = 0; i < AK4376_NUM_REGS; ++i) |
72 | ak4376.regs[i] = -1; | 78 | ak4376_regs[i] = -1; |
73 | 79 | ||
74 | /* Initial reset after power-on */ | 80 | /* Initial reset after power-on */ |
75 | ak4376_set_pdn_pin(0); | 81 | ak4376_set_pdn_pin(0); |
@@ -102,9 +108,6 @@ void ak4376_init(void) | |||
102 | /* Write initial configuration prior to power-up */ | 108 | /* Write initial configuration prior to power-up */ |
103 | for(size_t i = 0; i < ARRAYLEN(init_config); i += 2) | 109 | for(size_t i = 0; i < ARRAYLEN(init_config); i += 2) |
104 | ak4376_write(init_config[i], init_config[i+1]); | 110 | ak4376_write(init_config[i], init_config[i+1]); |
105 | |||
106 | /* Initial frequency setting, also handles DAC/amp power-up */ | ||
107 | audiohw_set_frequency(HW_FREQ_48); | ||
108 | } | 111 | } |
109 | 112 | ||
110 | void ak4376_close(void) | 113 | void ak4376_close(void) |
@@ -121,22 +124,22 @@ void ak4376_close(void) | |||
121 | void ak4376_write(int reg, int value) | 124 | void ak4376_write(int reg, int value) |
122 | { | 125 | { |
123 | /* Ensure value is sensible and differs from the last set value */ | 126 | /* Ensure value is sensible and differs from the last set value */ |
124 | if((value & 0xff) == value && ak4376.regs[reg] != value) { | 127 | if((value & 0xff) == value && ak4376_regs[reg] != value) { |
125 | int r = i2c_reg_write1(AK4376_BUS, AK4376_ADDR, reg, value); | 128 | int r = i2c_reg_write1(AK4376_BUS, AK4376_ADDR, reg, value); |
126 | if(r == I2C_STATUS_OK) | 129 | if(r == I2C_STATUS_OK) |
127 | ak4376.regs[reg] = value; | 130 | ak4376_regs[reg] = value; |
128 | else | 131 | else |
129 | ak4376.regs[reg] = -1; | 132 | ak4376_regs[reg] = -1; |
130 | } | 133 | } |
131 | } | 134 | } |
132 | 135 | ||
133 | int ak4376_read(int reg) | 136 | int ak4376_read(int reg) |
134 | { | 137 | { |
135 | /* Only read from I2C if we don't already know the value */ | 138 | /* Only read from I2C if we don't already know the value */ |
136 | if(ak4376.regs[reg] < 0) | 139 | if(ak4376_regs[reg] < 0) |
137 | ak4376.regs[reg] = i2c_reg_read1(AK4376_BUS, AK4376_ADDR, reg); | 140 | ak4376_regs[reg] = i2c_reg_read1(AK4376_BUS, AK4376_ADDR, reg); |
138 | 141 | ||
139 | return ak4376.regs[reg]; | 142 | return ak4376_regs[reg]; |
140 | } | 143 | } |
141 | 144 | ||
142 | static int round_step_up(int x, int step) | 145 | static int round_step_up(int x, int step) |
@@ -180,7 +183,7 @@ static int amp_vol_to_hw(int vol) | |||
180 | return (vol - AK4376_AMP_VOLUME_MIN) / AK4376_AMP_VOLUME_STEP + 1; | 183 | return (vol - AK4376_AMP_VOLUME_MIN) / AK4376_AMP_VOLUME_STEP + 1; |
181 | } | 184 | } |
182 | 185 | ||
183 | void audiohw_set_volume(int vol_l, int vol_r) | 186 | void ak4376_set_volume(int vol_l, int vol_r) |
184 | { | 187 | { |
185 | int amp; | 188 | int amp; |
186 | int mix_l = AK4376_MIX_LCH, dig_l, sw_l; | 189 | int mix_l = AK4376_MIX_LCH, dig_l, sw_l; |
@@ -210,7 +213,7 @@ void audiohw_set_volume(int vol_l, int vol_r) | |||
210 | pcm_set_master_volume(sw_l, sw_r); | 213 | pcm_set_master_volume(sw_l, sw_r); |
211 | } | 214 | } |
212 | 215 | ||
213 | void audiohw_set_filter_roll_off(int val) | 216 | void ak4376_set_filter_roll_off(int val) |
214 | { | 217 | { |
215 | int reg = ak4376_read(AK4376_REG_FILTER); | 218 | int reg = ak4376_read(AK4376_REG_FILTER); |
216 | reg &= ~0xc0; | 219 | reg &= ~0xc0; |
@@ -218,11 +221,8 @@ void audiohw_set_filter_roll_off(int val) | |||
218 | ak4376_write(AK4376_REG_FILTER, reg); | 221 | ak4376_write(AK4376_REG_FILTER, reg); |
219 | } | 222 | } |
220 | 223 | ||
221 | void audiohw_set_frequency(int fsel) | 224 | void ak4376_set_freqmode(int fsel, int mult, int power_mode) |
222 | { | 225 | { |
223 | /* Determine master clock multiplier */ | ||
224 | int mult = ak4376_set_mclk_freq(fsel, false); | ||
225 | |||
226 | /* Calculate clock mode for frequency. Multipliers of 32/64 are only | 226 | /* Calculate clock mode for frequency. Multipliers of 32/64 are only |
227 | * for rates >= 256 KHz which are not supported by Rockbox, so they | 227 | * for rates >= 256 KHz which are not supported by Rockbox, so they |
228 | * are commented out -- but they're in the correct place. */ | 228 | * are commented out -- but they're in the correct place. */ |
@@ -248,27 +248,11 @@ void audiohw_set_frequency(int fsel) | |||
248 | 248 | ||
249 | /* Handle the DSMLP bit in the MODE_CTRL register */ | 249 | /* Handle the DSMLP bit in the MODE_CTRL register */ |
250 | int mode_ctrl = 0x00; | 250 | int mode_ctrl = 0x00; |
251 | if(ak4376.low_mode || hw_freq_sampr[fsel] <= SAMPR_12) | 251 | if(power_mode || hw_freq_sampr[fsel] <= SAMPR_12) |
252 | mode_ctrl |= 0x40; | 252 | mode_ctrl |= 0x40; |
253 | 253 | ||
254 | /* Program the new settings */ | 254 | /* Program the new settings */ |
255 | ak4376_write(AK4376_REG_CLOCK_MODE, clock_mode); | 255 | ak4376_write(AK4376_REG_CLOCK_MODE, clock_mode); |
256 | ak4376_write(AK4376_REG_MODE_CTRL, mode_ctrl); | 256 | ak4376_write(AK4376_REG_MODE_CTRL, mode_ctrl); |
257 | ak4376_write(AK4376_REG_PWR3, ak4376.low_mode ? 0x11 : 0x01); | 257 | ak4376_write(AK4376_REG_PWR3, power_mode ? 0x11 : 0x01); |
258 | |||
259 | /* Enable the master clock */ | ||
260 | ak4376_set_mclk_freq(fsel, true); | ||
261 | |||
262 | /* Remember the frequency */ | ||
263 | ak4376.fsel = fsel; | ||
264 | } | ||
265 | |||
266 | void audiohw_set_power_mode(int mode) | ||
267 | { | ||
268 | /* This is handled via audiohw_set_frequency() since changing LPMODE | ||
269 | * bit requires power-down/power-up & changing other bits as well */ | ||
270 | if(ak4376.low_mode != mode) { | ||
271 | ak4376.low_mode = mode; | ||
272 | audiohw_set_frequency(ak4376.fsel); | ||
273 | } | ||
274 | } | 258 | } |
diff --git a/firmware/export/ak4376.h b/firmware/export/ak4376.h index eb06755e92..eab0bc24f3 100644 --- a/firmware/export/ak4376.h +++ b/firmware/export/ak4376.h | |||
@@ -104,10 +104,12 @@ AUDIOHW_SETTING(POWER_MODE, "", 0, 1, 0, 1, 0) | |||
104 | #define AK4376_FS_176 17 | 104 | #define AK4376_FS_176 17 |
105 | #define AK4376_FS_192 18 | 105 | #define AK4376_FS_192 18 |
106 | 106 | ||
107 | /* Functions to power on / off the DAC which should be called from | 107 | /* Functions to power on / off the DAC. |
108 | * the target's audiohw_init() / audiohw_close() implementation. | 108 | * |
109 | * NOTE: Target must call ak4376_set_frequency() after ak4376_open() to | ||
110 | * finish the power-up sequence of the headphone amp. | ||
109 | */ | 111 | */ |
110 | extern void ak4376_init(void); | 112 | extern void ak4376_open(void); |
111 | extern void ak4376_close(void); | 113 | extern void ak4376_close(void); |
112 | 114 | ||
113 | /* Register read/write. Cached to avoid redundant reads/writes. */ | 115 | /* Register read/write. Cached to avoid redundant reads/writes. */ |
@@ -117,16 +119,17 @@ extern int ak4376_read(int reg); | |||
117 | /* Target-specific function to set the PDN pin level. */ | 119 | /* Target-specific function to set the PDN pin level. */ |
118 | extern void ak4376_set_pdn_pin(int level); | 120 | extern void ak4376_set_pdn_pin(int level); |
119 | 121 | ||
120 | /* Target-specific function to control the external master clock frequency. | 122 | /* Set overall output volume */ |
121 | * This is called by the ak4376's audiohw implementation when switching to | 123 | extern void ak4376_set_volume(int vol_l, int vol_r); |
122 | * or from a frequency that is configured to use this clock source. | 124 | |
123 | * | 125 | /* Set the roll-off filter */ |
124 | * - hw_freq is the new sample rate -- one of the HW_FREQ_XX constants. | 126 | extern void ak4376_set_filter_roll_off(int val); |
125 | * - enabled is true if clock should be output, false if not. | 127 | |
128 | /* Set audio sampling frequency and power mode. | ||
126 | * | 129 | * |
127 | * The return value is the master clock rate as a multiple of the sampling | 130 | * If the I2S master clock is being supplied externally, the caller must also |
128 | * frequency. The allowed multiples depend on the sampling frequency, shown | 131 | * give the master clock multiplier 'mult'. The accepted values depend on the |
129 | * in the table below. | 132 | * sampling rate, see below: |
130 | * | 133 | * |
131 | * +-----------+------------------------+ | 134 | * +-----------+------------------------+ |
132 | * | frequency | master clock rate | | 135 | * | frequency | master clock rate | |
@@ -137,16 +140,13 @@ extern void ak4376_set_pdn_pin(int level); | |||
137 | * | 128 - 192 | 128fs | | 140 | * | 128 - 192 | 128fs | |
138 | * +-----------+------------------------+ | 141 | * +-----------+------------------------+ |
139 | * | 142 | * |
140 | * For example, at 48 KHz you could return either 256 or 512 depending on | 143 | * Switching between high-power and low-power mode requires the same registers |
141 | * the rate you decided to actually use. | 144 | * and power-up / power-down sequences as a frequency switch, so both settings |
142 | * | 145 | * are controlled by this function. |
143 | * You need to return a valid master multiplier for supported frequencies | ||
144 | * even when enabled = false, since the driver needs to know the multiplier | ||
145 | * _before_ enabling the clock. | ||
146 | * | 146 | * |
147 | * For unsupported frequencies you don't need to return a valid master | 147 | * high power mode -- use power_mode=0 |
148 | * multiplier, because the DAC doesn't need the return value in such cases. | 148 | * low power mode -- use power_mode=1 |
149 | */ | 149 | */ |
150 | extern int ak4376_set_mclk_freq(int hw_freq, bool enabled); | 150 | extern void ak4376_set_freqmode(int fsel, int mult, int power_mode); |
151 | 151 | ||
152 | #endif /* __AK4376_H__ */ | 152 | #endif /* __AK4376_H__ */ |
diff --git a/firmware/target/mips/ingenic_x1000/fiiom3k/audiohw-fiiom3k.c b/firmware/target/mips/ingenic_x1000/fiiom3k/audiohw-fiiom3k.c index d1c4d67d33..542d1745dc 100644 --- a/firmware/target/mips/ingenic_x1000/fiiom3k/audiohw-fiiom3k.c +++ b/firmware/target/mips/ingenic_x1000/fiiom3k/audiohw-fiiom3k.c | |||
@@ -22,10 +22,24 @@ | |||
22 | #include "audiohw.h" | 22 | #include "audiohw.h" |
23 | #include "system.h" | 23 | #include "system.h" |
24 | #include "pcm_sampr.h" | 24 | #include "pcm_sampr.h" |
25 | #include "logf.h" | ||
26 | #include "aic-x1000.h" | 25 | #include "aic-x1000.h" |
27 | #include "i2c-x1000.h" | 26 | #include "i2c-x1000.h" |
28 | #include "gpio-x1000.h" | 27 | #include "gpio-x1000.h" |
28 | #include "logf.h" | ||
29 | |||
30 | static int cur_fsel = HW_FREQ_48; | ||
31 | static int cur_power_mode = 0; | ||
32 | |||
33 | static void set_ak_freqmode(void) | ||
34 | { | ||
35 | int freq = hw_freq_sampr[cur_fsel]; | ||
36 | int mult = freq >= SAMPR_176 ? 128 : 256; | ||
37 | |||
38 | aic_enable_i2s_bit_clock(false); | ||
39 | aic_set_i2s_clock(X1000_CLK_SCLK_A, freq, mult); | ||
40 | ak4376_set_freqmode(cur_fsel, mult, cur_power_mode); | ||
41 | aic_enable_i2s_bit_clock(true); | ||
42 | } | ||
29 | 43 | ||
30 | void audiohw_init(void) | 44 | void audiohw_init(void) |
31 | { | 45 | { |
@@ -36,7 +50,8 @@ void audiohw_init(void) | |||
36 | 50 | ||
37 | /* Initialize DAC */ | 51 | /* Initialize DAC */ |
38 | i2c_x1000_set_freq(AK4376_BUS, I2C_FREQ_400K); | 52 | i2c_x1000_set_freq(AK4376_BUS, I2C_FREQ_400K); |
39 | ak4376_init(); | 53 | ak4376_open(); |
54 | set_ak_freqmode(); | ||
40 | } | 55 | } |
41 | 56 | ||
42 | void audiohw_postinit(void) | 57 | void audiohw_postinit(void) |
@@ -48,22 +63,29 @@ void audiohw_close(void) | |||
48 | ak4376_close(); | 63 | ak4376_close(); |
49 | } | 64 | } |
50 | 65 | ||
51 | void ak4376_set_pdn_pin(int level) | 66 | void audiohw_set_volume(int vol_l, int vol_r) |
52 | { | 67 | { |
53 | gpio_config(GPIO_A, 1 << 16, GPIO_OUTPUT(level ? 1 : 0)); | 68 | ak4376_set_volume(vol_l, vol_r); |
54 | } | 69 | } |
55 | 70 | ||
56 | int ak4376_set_mclk_freq(int hw_freq, bool enabled) | 71 | void audiohw_set_filter_roll_off(int val) |
57 | { | 72 | { |
58 | int freq = hw_freq_sampr[hw_freq]; | 73 | ak4376_set_filter_roll_off(val); |
59 | int mult = freq >= SAMPR_176 ? 128 : 256; | 74 | } |
75 | |||
76 | void audiohw_set_frequency(int fsel) | ||
77 | { | ||
78 | cur_fsel = fsel; | ||
79 | set_ak_freqmode(); | ||
80 | } | ||
60 | 81 | ||
61 | if(enabled) { | 82 | void audiohw_set_power_mode(int mode) |
62 | if(aic_set_i2s_clock(X1000_CLK_SCLK_A, freq, mult)) { | 83 | { |
63 | logf("WARNING: unachievable audio rate %d x %d!?", freq, mult); | 84 | cur_power_mode = mode; |
64 | } | 85 | set_ak_freqmode(); |
65 | } | 86 | } |
66 | 87 | ||
67 | aic_enable_i2s_bit_clock(enabled); | 88 | void ak4376_set_pdn_pin(int level) |
68 | return mult; | 89 | { |
90 | gpio_config(GPIO_A, 1 << 16, GPIO_OUTPUT(level ? 1 : 0)); | ||
69 | } | 91 | } |