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 /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */
34 cx18_av_write(cx, 0x127, 0x50);
36 if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
39 /* VID_PLL and AUX_PLL */
40 cx18_av_write4(cx, 0x108, 0x1408040f);
43 /* 0x8.9504318a * 28,636,363.636 / 0x14 = 32000 * 384 */
44 cx18_av_write4(cx, 0x110, 0x012a0863);
47 /* 0x1.f77f = (4 * 15734.26) / 32000 */
48 cx18_av_write4(cx, 0x900, 0x0801f77f);
49 cx18_av_write4(cx, 0x904, 0x0801f77f);
50 cx18_av_write4(cx, 0x90c, 0x0801f77f);
52 /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */
53 cx18_av_write(cx, 0x127, 0x54);
55 /* AUD_COUNT = 0x2fff = 8 samples * 4 * 384 - 1 */
56 cx18_av_write4(cx, 0x12c, 0x11202fff);
60 * VID_COUNT = 0x0d2ef8 = 107999.000 * 8 =
61 * ((8 samples/32,000) * (13,500,000 * 8) * 4 - 1) * 8
63 cx18_av_write4(cx, 0x128, 0xa10d2ef8);
67 /* VID_PLL and AUX_PLL */
68 cx18_av_write4(cx, 0x108, 0x1009040f);
71 /* 0x9.7635e7 * 28,636,363.63 / 0x10 = 44100 * 384 */
72 cx18_av_write4(cx, 0x110, 0x00ec6bce);
75 /* 0x1.6d59 = (4 * 15734.26) / 44100 */
76 cx18_av_write4(cx, 0x900, 0x08016d59);
77 cx18_av_write4(cx, 0x904, 0x08016d59);
78 cx18_av_write4(cx, 0x90c, 0x08016d59);
80 /* AUD_COUNT = 0x92ff = 49 samples * 2 * 384 - 1 */
81 cx18_av_write4(cx, 0x12c, 0x112092ff);
85 * VID_COUNT = 0x1d4bf8 = 239999.000 * 8 =
86 * ((49 samples/44,100) * (13,500,000 * 8) * 2 - 1) * 8
88 cx18_av_write4(cx, 0x128, 0xa11d4bf8);
92 /* VID_PLL and AUX_PLL */
93 cx18_av_write4(cx, 0x108, 0x100a040f);
96 /* 0xa.4c6b6ea * 28,636,363.63 / 0x10 = 48000 * 384 */
97 cx18_av_write4(cx, 0x110, 0x0098d6dd);
100 /* 0x1.4faa = (4 * 15734.26) / 48000 */
101 cx18_av_write4(cx, 0x900, 0x08014faa);
102 cx18_av_write4(cx, 0x904, 0x08014faa);
103 cx18_av_write4(cx, 0x90c, 0x08014faa);
105 /* AUD_COUNT = 0x5fff = 4 samples * 16 * 384 - 1 */
106 cx18_av_write4(cx, 0x12c, 0x11205fff);
110 * VID_COUNT = 0x1193f8 = 143999.000 * 8 =
111 * ((4 samples/48,000) * (13,500,000 * 8) * 16 - 1) * 8
113 cx18_av_write4(cx, 0x128, 0xa11193f8);
119 /* VID_PLL and AUX_PLL */
120 cx18_av_write4(cx, 0x108, 0x1e08040f);
123 /* 0x8.9504318 * 28,636,363.63 / 0x1e = 32000 * 256 */
124 cx18_av_write4(cx, 0x110, 0x012a0863);
127 /* 0x1.0000 = 32000/32000 */
128 cx18_av_write4(cx, 0x8f8, 0x08010000);
131 /* 0x2.0000 = 2 * (32000/32000) */
132 cx18_av_write4(cx, 0x900, 0x08020000);
133 cx18_av_write4(cx, 0x904, 0x08020000);
134 cx18_av_write4(cx, 0x90c, 0x08020000);
136 /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */
137 cx18_av_write(cx, 0x127, 0x54);
139 /* AUD_COUNT = 0x1fff = 8 samples * 4 * 256 - 1 */
140 cx18_av_write4(cx, 0x12c, 0x11201fff);
144 * VID_COUNT = 0x0d2ef8 = 107999.000 * 8 =
145 * ((8 samples/32,000) * (13,500,000 * 8) * 4 - 1) * 8
147 cx18_av_write4(cx, 0x128, 0xa10d2ef8);
151 /* VID_PLL and AUX_PLL */
152 cx18_av_write4(cx, 0x108, 0x1809040f);
155 /* 0x9.7635e74 * 28,636,363.63 / 0x18 = 44100 * 256 */
156 cx18_av_write4(cx, 0x110, 0x00ec6bce);
159 /* 0x1.60cd = 44100/32000 */
160 cx18_av_write4(cx, 0x8f8, 0x080160cd);
163 /* 0x1.7385 = 2 * (32000/44100) */
164 cx18_av_write4(cx, 0x900, 0x08017385);
165 cx18_av_write4(cx, 0x904, 0x08017385);
166 cx18_av_write4(cx, 0x90c, 0x08017385);
168 /* AUD_COUNT = 0x61ff = 49 samples * 2 * 256 - 1 */
169 cx18_av_write4(cx, 0x12c, 0x112061ff);
173 * VID_COUNT = 0x1d4bf8 = 239999.000 * 8 =
174 * ((49 samples/44,100) * (13,500,000 * 8) * 2 - 1) * 8
176 cx18_av_write4(cx, 0x128, 0xa11d4bf8);
180 /* VID_PLL and AUX_PLL */
181 cx18_av_write4(cx, 0x108, 0x180a040f);
184 /* 0xa.4c6b6ea * 28,636,363.63 / 0x18 = 48000 * 256 */
185 cx18_av_write4(cx, 0x110, 0x0098d6dd);
188 /* 0x1.8000 = 48000/32000 */
189 cx18_av_write4(cx, 0x8f8, 0x08018000);
192 /* 0x1.5555 = 2 * (32000/48000) */
193 cx18_av_write4(cx, 0x900, 0x08015555);
194 cx18_av_write4(cx, 0x904, 0x08015555);
195 cx18_av_write4(cx, 0x90c, 0x08015555);
197 /* AUD_COUNT = 0x3fff = 4 samples * 16 * 256 - 1 */
198 cx18_av_write4(cx, 0x12c, 0x11203fff);
202 * VID_COUNT = 0x1193f8 = 143999.000 * 8 =
203 * ((4 samples/48,000) * (13,500,000 * 8) * 16 - 1) * 8
205 cx18_av_write4(cx, 0x128, 0xa11193f8);
210 state->audclk_freq = freq;
215 void cx18_av_audio_set_path(struct cx18 *cx)
217 struct cx18_av_state *state = &cx->av_state;
220 /* stop microcontroller */
221 v = cx18_av_read(cx, 0x803) & ~0x10;
222 cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
224 /* assert soft reset */
225 v = cx18_av_read(cx, 0x810) | 0x01;
226 cx18_av_write_expect(cx, 0x810, v, v, 0x0f);
228 /* Mute everything to prevent the PFFT! */
229 cx18_av_write(cx, 0x8d3, 0x1f);
231 if (state->aud_input <= CX18_AV_AUDIO_SERIAL2) {
232 /* Set Path1 to Serial Audio Input */
233 cx18_av_write4(cx, 0x8d0, 0x01011012);
235 /* The microcontroller should not be started for the
236 * non-tuner inputs: autodetection is specific for
239 /* Set Path1 to Analog Demod Main Channel */
240 cx18_av_write4(cx, 0x8d0, 0x1f063870);
243 set_audclk_freq(cx, state->audclk_freq);
245 /* deassert soft reset */
246 v = cx18_av_read(cx, 0x810) & ~0x01;
247 cx18_av_write_expect(cx, 0x810, v, v, 0x0f);
249 if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
250 /* When the microcontroller detects the
251 * audio format, it will unmute the lines */
252 v = cx18_av_read(cx, 0x803) | 0x10;
253 cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
257 static int get_volume(struct cx18 *cx)
259 /* Volume runs +18dB to -96dB in 1/2dB steps
260 * change to fit the msp3400 -114dB to +12dB range */
262 /* check PATH1_VOLUME */
263 int vol = 228 - cx18_av_read(cx, 0x8d4);
264 vol = (vol / 2) + 23;
268 static void set_volume(struct cx18 *cx, int volume)
270 /* First convert the volume to msp3400 values (0-127) */
271 int vol = volume >> 9;
272 /* now scale it up to cx18_av values
273 * -114dB to -96dB maps to 0
274 * this should be 19, but in my testing that was 4dB too loud */
281 cx18_av_write(cx, 0x8d4, 228 - (vol * 2));
284 static int get_bass(struct cx18 *cx)
286 /* bass is 49 steps +12dB to -12dB */
288 /* check PATH1_EQ_BASS_VOL */
289 int bass = cx18_av_read(cx, 0x8d9) & 0x3f;
290 bass = (((48 - bass) * 0xffff) + 47) / 48;
294 static void set_bass(struct cx18 *cx, int bass)
296 /* PATH1_EQ_BASS_VOL */
297 cx18_av_and_or(cx, 0x8d9, ~0x3f, 48 - (bass * 48 / 0xffff));
300 static int get_treble(struct cx18 *cx)
302 /* treble is 49 steps +12dB to -12dB */
304 /* check PATH1_EQ_TREBLE_VOL */
305 int treble = cx18_av_read(cx, 0x8db) & 0x3f;
306 treble = (((48 - treble) * 0xffff) + 47) / 48;
310 static void set_treble(struct cx18 *cx, int treble)
312 /* PATH1_EQ_TREBLE_VOL */
313 cx18_av_and_or(cx, 0x8db, ~0x3f, 48 - (treble * 48 / 0xffff));
316 static int get_balance(struct cx18 *cx)
318 /* balance is 7 bit, 0 to -96dB */
320 /* check PATH1_BAL_LEVEL */
321 int balance = cx18_av_read(cx, 0x8d5) & 0x7f;
322 /* check PATH1_BAL_LEFT */
323 if ((cx18_av_read(cx, 0x8d5) & 0x80) == 0)
324 balance = 0x80 - balance;
326 balance = 0x80 + balance;
330 static void set_balance(struct cx18 *cx, int balance)
332 int bal = balance >> 8;
335 cx18_av_and_or(cx, 0x8d5, 0x7f, 0x80);
336 /* PATH1_BAL_LEVEL */
337 cx18_av_and_or(cx, 0x8d5, ~0x7f, bal & 0x7f);
340 cx18_av_and_or(cx, 0x8d5, 0x7f, 0x00);
341 /* PATH1_BAL_LEVEL */
342 cx18_av_and_or(cx, 0x8d5, ~0x7f, 0x80 - bal);
346 static int get_mute(struct cx18 *cx)
348 /* check SRC1_MUTE_EN */
349 return cx18_av_read(cx, 0x8d3) & 0x2 ? 1 : 0;
352 static void set_mute(struct cx18 *cx, int mute)
354 struct cx18_av_state *state = &cx->av_state;
357 if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
358 /* Must turn off microcontroller in order to mute sound.
359 * Not sure if this is the best method, but it does work.
360 * If the microcontroller is running, then it will undo any
361 * changes to the mute register. */
362 v = cx18_av_read(cx, 0x803);
364 /* disable microcontroller */
366 cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
367 cx18_av_write(cx, 0x8d3, 0x1f);
369 /* enable microcontroller */
371 cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
375 cx18_av_and_or(cx, 0x8d3, ~0x2, mute ? 0x02 : 0x00);
379 int cx18_av_audio(struct cx18 *cx, unsigned int cmd, void *arg)
381 struct cx18_av_state *state = &cx->av_state;
382 struct v4l2_control *ctrl = arg;
386 case VIDIOC_INT_AUDIO_CLOCK_FREQ:
389 if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
390 v = cx18_av_read(cx, 0x803) & ~0x10;
391 cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
392 cx18_av_write(cx, 0x8d3, 0x1f);
394 v = cx18_av_read(cx, 0x810) | 0x1;
395 cx18_av_write_expect(cx, 0x810, v, v, 0x0f);
397 retval = set_audclk_freq(cx, *(u32 *)arg);
399 v = cx18_av_read(cx, 0x810) & ~0x1;
400 cx18_av_write_expect(cx, 0x810, v, v, 0x0f);
401 if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
402 v = cx18_av_read(cx, 0x803) | 0x10;
403 cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
410 case V4L2_CID_AUDIO_VOLUME:
411 ctrl->value = get_volume(cx);
413 case V4L2_CID_AUDIO_BASS:
414 ctrl->value = get_bass(cx);
416 case V4L2_CID_AUDIO_TREBLE:
417 ctrl->value = get_treble(cx);
419 case V4L2_CID_AUDIO_BALANCE:
420 ctrl->value = get_balance(cx);
422 case V4L2_CID_AUDIO_MUTE:
423 ctrl->value = get_mute(cx);
432 case V4L2_CID_AUDIO_VOLUME:
433 set_volume(cx, ctrl->value);
435 case V4L2_CID_AUDIO_BASS:
436 set_bass(cx, ctrl->value);
438 case V4L2_CID_AUDIO_TREBLE:
439 set_treble(cx, ctrl->value);
441 case V4L2_CID_AUDIO_BALANCE:
442 set_balance(cx, ctrl->value);
444 case V4L2_CID_AUDIO_MUTE:
445 set_mute(cx, ctrl->value);