1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Driver for WM8758 audio codec - based on datasheet for WM8983
12 * Based on code from the ipodlinux project - http://ipodlinux.org/
13 * Adapted for Rockbox in December 2005
15 * Original file: linux/arch/armnommu/mach-ipod/audio.c
17 * Copyright (c) 2003-2005 Bernard Leach (leachbj@bouncycastle.org)
19 * This program is free software; you can redistribute it and/or
20 * modify it under the terms of the GNU General Public License
21 * as published by the Free Software Foundation; either version 2
22 * of the License, or (at your option) any later version.
24 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
25 * KIND, either express or implied.
27 ****************************************************************************/
35 const struct sound_settings_info audiohw_settings
[] = {
36 [SOUND_VOLUME
] = {"dB", 0, 1, -58, 6, -25},
37 [SOUND_BASS
] = {"dB", 0, 1, -12, 12, 0},
38 [SOUND_TREBLE
] = {"dB", 0, 1, -12, 12, 0},
39 [SOUND_BALANCE
] = {"%", 0, 1,-100, 100, 0},
40 [SOUND_CHANNELS
] = {"", 0, 1, 0, 5, 0},
41 [SOUND_STEREO_WIDTH
] = {"%", 0, 5, 0, 250, 100},
43 [SOUND_LEFT_GAIN
] = {"dB", 1, 1, 0, 63, 16},
44 [SOUND_RIGHT_GAIN
] = {"dB", 1, 1, 0, 63, 16},
45 [SOUND_MIC_GAIN
] = {"dB", 1, 1, 0, 63, 16},
47 [SOUND_BASS_CUTOFF
] = {"", 0, 1, 1, 4, 1},
48 [SOUND_TREBLE_CUTOFF
] = {"", 0, 1, 1, 4, 1},
51 /* shadow registers */
52 static unsigned short eq1_reg
= EQ1_EQ3DMODE
| EQ_GAIN_VALUE(0);
53 static unsigned short eq5_reg
= EQ_GAIN_VALUE(0);
55 /* convert tenth of dB volume (-57..6) to master volume register value */
56 int tenthdb2master(int db
)
58 if (db
< VOLUME_MIN
) {
65 int sound_val2phys(int setting
, int value
)
73 case SOUND_RIGHT_GAIN
:
75 result
= ((value
- 16) * 15) / 2;
86 void audiohw_mute(bool mute
)
89 wmcodec_write(DACCTRL
, DACCTRL_SOFTMUTE
);
91 wmcodec_write(DACCTRL
, 0);
95 void audiohw_preinit(void)
97 wmcodec_write(RESET
, RESET_RESET
);
99 wmcodec_write(PWRMGMT1
, PWRMGMT1_PLLEN
| PWRMGMT1_BIASEN
100 | PWRMGMT1_VMIDSEL_5K
);
101 wmcodec_write(PWRMGMT2
, PWRMGMT2_ROUT1EN
| PWRMGMT2_LOUT1EN
);
102 wmcodec_write(PWRMGMT3
, PWRMGMT3_LOUT2EN
| PWRMGMT3_ROUT2EN
103 | PWRMGMT3_RMIXEN
| PWRMGMT3_LMIXEN
104 | PWRMGMT3_DACENR
| PWRMGMT3_DACENL
);
106 wmcodec_write(AINTFCE
, AINTFCE_IWL_16BIT
| AINTFCE_FORMAT_I2S
);
107 wmcodec_write(OUTCTRL
, OUTCTRL_VROI
);
108 wmcodec_write(CLKCTRL
, CLKCTRL_MS
); /* WM8758 is clock master */
110 audiohw_set_sample_rate(HW_FREQ_44
);
112 wmcodec_write(LOUTMIX
, LOUTMIX_DACL2LMIX
);
113 wmcodec_write(ROUTMIX
, ROUTMIX_DACR2RMIX
);
116 void audiohw_postinit(void)
118 wmcodec_write(PWRMGMT1
, PWRMGMT1_PLLEN
| PWRMGMT1_BIASEN
119 | PWRMGMT1_VMIDSEL_75K
);
120 /* lower the VMID power consumption */
124 void audiohw_set_master_vol(int vol_l
, int vol_r
)
127 wmcodec_write(LOUT1VOL
, LOUT1VOL_LOUT1ZC
| vol_l
);
128 wmcodec_write(ROUT1VOL
, ROUT1VOL_OUT1VU
| ROUT1VOL_ROUT1ZC
| vol_r
);
131 void audiohw_set_lineout_vol(int vol_l
, int vol_r
)
134 wmcodec_write(LOUT2VOL
, LOUT2VOL_LOUT2ZC
| vol_l
);
135 wmcodec_write(ROUT2VOL
, ROUT2VOL_OUT2VU
| ROUT2VOL_ROUT2ZC
| vol_r
);
138 void audiohw_set_bass(int value
)
140 eq1_reg
= (eq1_reg
& ~EQ_GAIN_MASK
) | EQ_GAIN_VALUE(value
);
141 wmcodec_write(EQ1
, eq1_reg
);
144 void audiohw_set_bass_cutoff(int value
)
146 eq1_reg
= (eq1_reg
& ~EQ_CUTOFF_MASK
) | EQ_CUTOFF_VALUE(value
);
147 wmcodec_write(EQ1
, eq1_reg
);
150 void audiohw_set_treble(int value
)
152 eq5_reg
= (eq5_reg
& ~EQ_GAIN_MASK
) | EQ_GAIN_VALUE(value
);
153 wmcodec_write(EQ5
, eq5_reg
);
156 void audiohw_set_treble_cutoff(int value
)
158 eq5_reg
= (eq5_reg
& ~EQ_CUTOFF_MASK
) | EQ_CUTOFF_VALUE(value
);
159 wmcodec_write(EQ5
, eq5_reg
);
162 /* Nice shutdown of WM8758 codec */
163 void audiohw_close(void)
167 wmcodec_write(PWRMGMT3
, 0);
168 wmcodec_write(PWRMGMT1
, 0);
169 wmcodec_write(PWRMGMT2
, PWRMGMT2_SLEEP
);
172 /* Note: Disable output before calling this function */
173 void audiohw_set_frequency(int fsel
)
175 /**** We force 44.1KHz for now. ****/
178 /* setup PLL for MHZ=11.2896 */
179 wmcodec_write(PLLN
, PLLN_PLLPRESCALE
| 0x7);
180 wmcodec_write(PLLK1
, 0x21);
181 wmcodec_write(PLLK2
, 0x161);
182 wmcodec_write(PLLK3
, 0x26);
185 wmcodec_write(CLKCTRL
, CLKCTRL_CLKSEL
| CLKCTRL_MCLKDIV_2
186 | CLKCTRL_BCLKDIV_2
| CLKCTRL_MS
);
188 wmcodec_write(ADDCTRL
, ADDCTRL_SR_48kHz
| ADDCTRL_SLOWCLKEN
);
189 /* SLOWCLK enabled for zero cross timeout to work */
192 void audiohw_enable_recording(bool source_mic
)
194 (void)source_mic
; /* We only have a line-in (I think) */
196 wmcodec_write(PWRMGMT2
, PWRMGMT2_ROUT1EN
| PWRMGMT2_LOUT1EN
197 | PWRMGMT2_INPGAENR
| PWRMGMT2_INPGAENL
198 | PWRMGMT2_ADCENR
| PWRMGMT2_ADCENL
);
200 wmcodec_write(INCTRL
, INCTRL_R2_2INPGA
| INCTRL_L2_2INPGA
);
202 wmcodec_write(LADCBOOST
, LADCBOOST_L2_2BOOST(5));
203 wmcodec_write(RADCBOOST
, RADCBOOST_R2_2BOOST(5));
205 /* Enable monitoring */
206 wmcodec_write(LOUTMIX
, LOUTMIX_BYP2LMIXVOL(5)
207 | LOUTMIX_BYPL2LMIX
| LOUTMIX_DACL2LMIX
);
208 wmcodec_write(ROUTMIX
, ROUTMIX_BYP2RMIXVOL(5)
209 | ROUTMIX_BYPR2RMIX
| ROUTMIX_DACR2RMIX
);
212 void audiohw_disable_recording(void)
214 wmcodec_write(LOUTMIX
, LOUTMIX_DACL2LMIX
);
215 wmcodec_write(ROUTMIX
, ROUTMIX_DACR2RMIX
);
217 wmcodec_write(PWRMGMT2
, PWRMGMT2_ROUT1EN
| PWRMGMT2_LOUT1EN
);
220 void audiohw_set_recvol(int left
, int right
, int type
)
227 case AUDIO_GAIN_LINEIN
:
228 wmcodec_write(LINPGAVOL
, LINPGAVOL_INPGAZCL
229 | (left
& LINPGAVOL_INPGAVOL_MASK
));
230 wmcodec_write(RINPGAVOL
, RINPGAVOL_INPGAVU
| RINPGAVOL_INPGAZCR
231 | (right
& RINPGAVOL_INPGAVOL_MASK
));
238 void audiohw_set_monitor(bool enable
)