summaryrefslogtreecommitdiff
path: root/firmware/drivers/audio/ak4376.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers/audio/ak4376.c')
-rw-r--r--firmware/drivers/audio/ak4376.c70
1 files changed, 27 insertions, 43 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}