2 * cx18 ADEC audio functions
4 * Derived from cx25840-audio.c
6 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 #include "cx18-driver.h"
26 static int set_audclk_freq(struct cx18
*cx
, u32 freq
)
28 struct cx18_av_state
*state
= &cx
->av_state
;
30 if (freq
!= 32000 && freq
!= 44100 && freq
!= 48000)
33 /* common for all inputs and rates */
34 /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */
35 cx18_av_write(cx
, 0x127, 0x50);
37 if (state
->aud_input
!= CX18_AV_AUDIO_SERIAL
) {
40 /* VID_PLL and AUX_PLL */
41 cx18_av_write4(cx
, 0x108, 0x1006040f);
44 cx18_av_write4(cx
, 0x110, 0x01bb39ee);
46 /* src3/4/6_ctl = 0x0801f77f */
47 cx18_av_write4(cx
, 0x900, 0x0801f77f);
48 cx18_av_write4(cx
, 0x904, 0x0801f77f);
49 cx18_av_write4(cx
, 0x90c, 0x0801f77f);
53 /* VID_PLL and AUX_PLL */
54 cx18_av_write4(cx
, 0x108, 0x1009040f);
57 cx18_av_write4(cx
, 0x110, 0x00ec6bd6);
59 /* src3/4/6_ctl = 0x08016d59 */
60 cx18_av_write4(cx
, 0x900, 0x08016d59);
61 cx18_av_write4(cx
, 0x904, 0x08016d59);
62 cx18_av_write4(cx
, 0x90c, 0x08016d59);
66 /* VID_PLL and AUX_PLL */
67 cx18_av_write4(cx
, 0x108, 0x100a040f);
70 cx18_av_write4(cx
, 0x110, 0x0098d6e5);
72 /* src3/4/6_ctl = 0x08014faa */
73 cx18_av_write4(cx
, 0x900, 0x08014faa);
74 cx18_av_write4(cx
, 0x904, 0x08014faa);
75 cx18_av_write4(cx
, 0x90c, 0x08014faa);
81 /* VID_PLL and AUX_PLL */
82 cx18_av_write4(cx
, 0x108, 0x1e08040f);
85 cx18_av_write4(cx
, 0x110, 0x012a0869);
87 /* src1_ctl = 0x08010000 */
88 cx18_av_write4(cx
, 0x8f8, 0x08010000);
90 /* src3/4/6_ctl = 0x08020000 */
91 cx18_av_write4(cx
, 0x900, 0x08020000);
92 cx18_av_write4(cx
, 0x904, 0x08020000);
93 cx18_av_write4(cx
, 0x90c, 0x08020000);
95 /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */
96 cx18_av_write(cx
, 0x127, 0x54);
100 /* VID_PLL and AUX_PLL */
101 cx18_av_write4(cx
, 0x108, 0x1809040f);
104 cx18_av_write4(cx
, 0x110, 0x00ec6bd6);
106 /* src1_ctl = 0x08010000 */
107 cx18_av_write4(cx
, 0x8f8, 0x080160cd);
109 /* src3/4/6_ctl = 0x08020000 */
110 cx18_av_write4(cx
, 0x900, 0x08017385);
111 cx18_av_write4(cx
, 0x904, 0x08017385);
112 cx18_av_write4(cx
, 0x90c, 0x08017385);
116 /* VID_PLL and AUX_PLL */
117 cx18_av_write4(cx
, 0x108, 0x180a040f);
120 cx18_av_write4(cx
, 0x110, 0x0098d6e5);
122 /* src1_ctl = 0x08010000 */
123 cx18_av_write4(cx
, 0x8f8, 0x08018000);
125 /* src3/4/6_ctl = 0x08020000 */
126 cx18_av_write4(cx
, 0x900, 0x08015555);
127 cx18_av_write4(cx
, 0x904, 0x08015555);
128 cx18_av_write4(cx
, 0x90c, 0x08015555);
133 state
->audclk_freq
= freq
;
138 void cx18_av_audio_set_path(struct cx18
*cx
)
140 struct cx18_av_state
*state
= &cx
->av_state
;
142 /* stop microcontroller */
143 cx18_av_and_or(cx
, 0x803, ~0x10, 0);
145 /* assert soft reset */
146 cx18_av_and_or(cx
, 0x810, ~0x1, 0x01);
148 /* Mute everything to prevent the PFFT! */
149 cx18_av_write(cx
, 0x8d3, 0x1f);
151 if (state
->aud_input
== CX18_AV_AUDIO_SERIAL
) {
152 /* Set Path1 to Serial Audio Input */
153 cx18_av_write4(cx
, 0x8d0, 0x01011012);
155 /* The microcontroller should not be started for the
156 * non-tuner inputs: autodetection is specific for
159 /* Set Path1 to Analog Demod Main Channel */
160 cx18_av_write4(cx
, 0x8d0, 0x1f063870);
163 set_audclk_freq(cx
, state
->audclk_freq
);
165 /* deassert soft reset */
166 cx18_av_and_or(cx
, 0x810, ~0x1, 0x00);
168 if (state
->aud_input
!= CX18_AV_AUDIO_SERIAL
) {
169 /* When the microcontroller detects the
170 * audio format, it will unmute the lines */
171 cx18_av_and_or(cx
, 0x803, ~0x10, 0x10);
175 static int get_volume(struct cx18
*cx
)
177 /* Volume runs +18dB to -96dB in 1/2dB steps
178 * change to fit the msp3400 -114dB to +12dB range */
180 /* check PATH1_VOLUME */
181 int vol
= 228 - cx18_av_read(cx
, 0x8d4);
182 vol
= (vol
/ 2) + 23;
186 static void set_volume(struct cx18
*cx
, int volume
)
188 /* First convert the volume to msp3400 values (0-127) */
189 int vol
= volume
>> 9;
190 /* now scale it up to cx18_av values
191 * -114dB to -96dB maps to 0
192 * this should be 19, but in my testing that was 4dB too loud */
199 cx18_av_write(cx
, 0x8d4, 228 - (vol
* 2));
202 static int get_bass(struct cx18
*cx
)
204 /* bass is 49 steps +12dB to -12dB */
206 /* check PATH1_EQ_BASS_VOL */
207 int bass
= cx18_av_read(cx
, 0x8d9) & 0x3f;
208 bass
= (((48 - bass
) * 0xffff) + 47) / 48;
212 static void set_bass(struct cx18
*cx
, int bass
)
214 /* PATH1_EQ_BASS_VOL */
215 cx18_av_and_or(cx
, 0x8d9, ~0x3f, 48 - (bass
* 48 / 0xffff));
218 static int get_treble(struct cx18
*cx
)
220 /* treble is 49 steps +12dB to -12dB */
222 /* check PATH1_EQ_TREBLE_VOL */
223 int treble
= cx18_av_read(cx
, 0x8db) & 0x3f;
224 treble
= (((48 - treble
) * 0xffff) + 47) / 48;
228 static void set_treble(struct cx18
*cx
, int treble
)
230 /* PATH1_EQ_TREBLE_VOL */
231 cx18_av_and_or(cx
, 0x8db, ~0x3f, 48 - (treble
* 48 / 0xffff));
234 static int get_balance(struct cx18
*cx
)
236 /* balance is 7 bit, 0 to -96dB */
238 /* check PATH1_BAL_LEVEL */
239 int balance
= cx18_av_read(cx
, 0x8d5) & 0x7f;
240 /* check PATH1_BAL_LEFT */
241 if ((cx18_av_read(cx
, 0x8d5) & 0x80) == 0)
242 balance
= 0x80 - balance
;
244 balance
= 0x80 + balance
;
248 static void set_balance(struct cx18
*cx
, int balance
)
250 int bal
= balance
>> 8;
253 cx18_av_and_or(cx
, 0x8d5, 0x7f, 0x80);
254 /* PATH1_BAL_LEVEL */
255 cx18_av_and_or(cx
, 0x8d5, ~0x7f, bal
& 0x7f);
258 cx18_av_and_or(cx
, 0x8d5, 0x7f, 0x00);
259 /* PATH1_BAL_LEVEL */
260 cx18_av_and_or(cx
, 0x8d5, ~0x7f, 0x80 - bal
);
264 static int get_mute(struct cx18
*cx
)
266 /* check SRC1_MUTE_EN */
267 return cx18_av_read(cx
, 0x8d3) & 0x2 ? 1 : 0;
270 static void set_mute(struct cx18
*cx
, int mute
)
272 struct cx18_av_state
*state
= &cx
->av_state
;
274 if (state
->aud_input
!= CX18_AV_AUDIO_SERIAL
) {
275 /* Must turn off microcontroller in order to mute sound.
276 * Not sure if this is the best method, but it does work.
277 * If the microcontroller is running, then it will undo any
278 * changes to the mute register. */
280 /* disable microcontroller */
281 cx18_av_and_or(cx
, 0x803, ~0x10, 0x00);
282 cx18_av_write(cx
, 0x8d3, 0x1f);
284 /* enable microcontroller */
285 cx18_av_and_or(cx
, 0x803, ~0x10, 0x10);
289 cx18_av_and_or(cx
, 0x8d3, ~0x2, mute
? 0x02 : 0x00);
293 int cx18_av_audio(struct cx18
*cx
, unsigned int cmd
, void *arg
)
295 struct cx18_av_state
*state
= &cx
->av_state
;
296 struct v4l2_control
*ctrl
= arg
;
300 case VIDIOC_INT_AUDIO_CLOCK_FREQ
:
301 if (state
->aud_input
!= CX18_AV_AUDIO_SERIAL
) {
302 cx18_av_and_or(cx
, 0x803, ~0x10, 0);
303 cx18_av_write(cx
, 0x8d3, 0x1f);
305 cx18_av_and_or(cx
, 0x810, ~0x1, 1);
306 retval
= set_audclk_freq(cx
, *(u32
*)arg
);
307 cx18_av_and_or(cx
, 0x810, ~0x1, 0);
308 if (state
->aud_input
!= CX18_AV_AUDIO_SERIAL
)
309 cx18_av_and_or(cx
, 0x803, ~0x10, 0x10);
314 case V4L2_CID_AUDIO_VOLUME
:
315 ctrl
->value
= get_volume(cx
);
317 case V4L2_CID_AUDIO_BASS
:
318 ctrl
->value
= get_bass(cx
);
320 case V4L2_CID_AUDIO_TREBLE
:
321 ctrl
->value
= get_treble(cx
);
323 case V4L2_CID_AUDIO_BALANCE
:
324 ctrl
->value
= get_balance(cx
);
326 case V4L2_CID_AUDIO_MUTE
:
327 ctrl
->value
= get_mute(cx
);
336 case V4L2_CID_AUDIO_VOLUME
:
337 set_volume(cx
, ctrl
->value
);
339 case V4L2_CID_AUDIO_BASS
:
340 set_bass(cx
, ctrl
->value
);
342 case V4L2_CID_AUDIO_TREBLE
:
343 set_treble(cx
, ctrl
->value
);
345 case V4L2_CID_AUDIO_BALANCE
:
346 set_balance(cx
, ctrl
->value
);
348 case V4L2_CID_AUDIO_MUTE
:
349 set_mute(cx
, ctrl
->value
);