summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
Diffstat (limited to 'firmware')
-rw-r--r--firmware/drivers/audio/ak4376.c70
-rw-r--r--firmware/export/ak4376.h42
-rw-r--r--firmware/target/mips/ingenic_x1000/fiiom3k/audiohw-fiiom3k.c50
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 */
43static const int ak4376_fsel_to_hw[] = { 55static 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
60static struct ak4376 { 72static int ak4376_regs[AK4376_NUM_REGS];
61 int fsel;
62 int low_mode;
63 int regs[AK4376_NUM_REGS];
64} ak4376;
65 73
66void ak4376_init(void) 74void 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
110void ak4376_close(void) 113void ak4376_close(void)
@@ -121,22 +124,22 @@ void ak4376_close(void)
121void ak4376_write(int reg, int value) 124void 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
133int ak4376_read(int reg) 136int 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
142static int round_step_up(int x, int step) 145static 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
183void audiohw_set_volume(int vol_l, int vol_r) 186void 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
213void audiohw_set_filter_roll_off(int val) 216void 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
221void audiohw_set_frequency(int fsel) 224void 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
266void 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 */
110extern void ak4376_init(void); 112extern void ak4376_open(void);
111extern void ak4376_close(void); 113extern 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. */
118extern void ak4376_set_pdn_pin(int level); 120extern 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 123extern 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. 126extern 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 */
150extern int ak4376_set_mclk_freq(int hw_freq, bool enabled); 150extern 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
30static int cur_fsel = HW_FREQ_48;
31static int cur_power_mode = 0;
32
33static 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
30void audiohw_init(void) 44void 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
42void audiohw_postinit(void) 57void audiohw_postinit(void)
@@ -48,22 +63,29 @@ void audiohw_close(void)
48 ak4376_close(); 63 ak4376_close();
49} 64}
50 65
51void ak4376_set_pdn_pin(int level) 66void 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
56int ak4376_set_mclk_freq(int hw_freq, bool enabled) 71void 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
76void audiohw_set_frequency(int fsel)
77{
78 cur_fsel = fsel;
79 set_ak_freqmode();
80}
60 81
61 if(enabled) { 82void 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); 88void ak4376_set_pdn_pin(int level)
68 return mult; 89{
90 gpio_config(GPIO_A, 1 << 16, GPIO_OUTPUT(level ? 1 : 0));
69} 91}