blob: 0b55837880a711d5ef11805a01371c6e91bd122a [file] [log] [blame]
Hans Verkuil1c1e45d2008-04-28 20:24:33 -03001/*
2 * cx18 ADEC audio functions
3 *
4 * Derived from cx25840-audio.c
5 *
6 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
7 *
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.
12 *
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.
17 *
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
21 * 02110-1301, USA.
22 */
23
24#include "cx18-driver.h"
25
26static int set_audclk_freq(struct cx18 *cx, u32 freq)
27{
28 struct cx18_av_state *state = &cx->av_state;
29
30 if (freq != 32000 && freq != 44100 && freq != 48000)
31 return -EINVAL;
32
Hans Verkuil1c1e45d2008-04-28 20:24:33 -030033 /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */
34 cx18_av_write(cx, 0x127, 0x50);
35
Hans Verkuil81cb727d2008-06-28 12:49:20 -030036 if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
Hans Verkuil1c1e45d2008-04-28 20:24:33 -030037 switch (freq) {
38 case 32000:
39 /* VID_PLL and AUX_PLL */
Andy Wallsf8f62962008-07-23 20:28:23 -030040 cx18_av_write4(cx, 0x108, 0x1408040f);
Hans Verkuil1c1e45d2008-04-28 20:24:33 -030041
42 /* AUX_PLL_FRAC */
Andy Wallsf8f62962008-07-23 20:28:23 -030043 /* 0x8.9504318a * 28,636,363.636 / 0x14 = 32000 * 384 */
44 cx18_av_write4(cx, 0x110, 0x012a0863);
Hans Verkuil1c1e45d2008-04-28 20:24:33 -030045
Andy Wallsf8f62962008-07-23 20:28:23 -030046 /* src3/4/6_ctl */
47 /* 0x1.f77f = (4 * 15734.26) / 32000 */
Hans Verkuil1c1e45d2008-04-28 20:24:33 -030048 cx18_av_write4(cx, 0x900, 0x0801f77f);
49 cx18_av_write4(cx, 0x904, 0x0801f77f);
50 cx18_av_write4(cx, 0x90c, 0x0801f77f);
Andy Wallsf8f62962008-07-23 20:28:23 -030051
52 /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */
53 cx18_av_write(cx, 0x127, 0x54);
Andy Walls35f92b22008-07-25 15:03:08 -030054
55 /* AUD_COUNT = 0x2fff = 8 samples * 4 * 384 - 1 */
56 cx18_av_write4(cx, 0x12c, 0x11202fff);
57
58 /*
59 * EN_AV_LOCK = 1
60 * VID_COUNT = 0x0d2ef8 = 107999.000 * 8 =
61 * ((8 samples/32,000) * (13,500,000 * 8) * 4 - 1) * 8
62 */
63 cx18_av_write4(cx, 0x128, 0xa10d2ef8);
Hans Verkuil1c1e45d2008-04-28 20:24:33 -030064 break;
65
66 case 44100:
67 /* VID_PLL and AUX_PLL */
68 cx18_av_write4(cx, 0x108, 0x1009040f);
69
70 /* AUX_PLL_FRAC */
Andy Walls35f92b22008-07-25 15:03:08 -030071 /* 0x9.7635e7 * 28,636,363.63 / 0x10 = 44100 * 384 */
72 cx18_av_write4(cx, 0x110, 0x00ec6bce);
Hans Verkuil1c1e45d2008-04-28 20:24:33 -030073
Andy Wallsf8f62962008-07-23 20:28:23 -030074 /* src3/4/6_ctl */
75 /* 0x1.6d59 = (4 * 15734.26) / 44100 */
Hans Verkuil1c1e45d2008-04-28 20:24:33 -030076 cx18_av_write4(cx, 0x900, 0x08016d59);
77 cx18_av_write4(cx, 0x904, 0x08016d59);
78 cx18_av_write4(cx, 0x90c, 0x08016d59);
Andy Walls35f92b22008-07-25 15:03:08 -030079
80 /* AUD_COUNT = 0x92ff = 49 samples * 2 * 384 - 1 */
81 cx18_av_write4(cx, 0x12c, 0x112092ff);
82
83 /*
84 * EN_AV_LOCK = 1
85 * VID_COUNT = 0x1d4bf8 = 239999.000 * 8 =
86 * ((49 samples/44,100) * (13,500,000 * 8) * 2 - 1) * 8
87 */
88 cx18_av_write4(cx, 0x128, 0xa11d4bf8);
Hans Verkuil1c1e45d2008-04-28 20:24:33 -030089 break;
90
91 case 48000:
92 /* VID_PLL and AUX_PLL */
93 cx18_av_write4(cx, 0x108, 0x100a040f);
94
95 /* AUX_PLL_FRAC */
Andy Walls35f92b22008-07-25 15:03:08 -030096 /* 0xa.4c6b6ea * 28,636,363.63 / 0x10 = 48000 * 384 */
97 cx18_av_write4(cx, 0x110, 0x0098d6dd);
Hans Verkuil1c1e45d2008-04-28 20:24:33 -030098
Andy Wallsf8f62962008-07-23 20:28:23 -030099 /* src3/4/6_ctl */
100 /* 0x1.4faa = (4 * 15734.26) / 48000 */
Hans Verkuil1c1e45d2008-04-28 20:24:33 -0300101 cx18_av_write4(cx, 0x900, 0x08014faa);
102 cx18_av_write4(cx, 0x904, 0x08014faa);
103 cx18_av_write4(cx, 0x90c, 0x08014faa);
Andy Walls35f92b22008-07-25 15:03:08 -0300104
105 /* AUD_COUNT = 0x5fff = 4 samples * 16 * 384 - 1 */
106 cx18_av_write4(cx, 0x12c, 0x11205fff);
107
108 /*
109 * EN_AV_LOCK = 1
110 * VID_COUNT = 0x1193f8 = 143999.000 * 8 =
111 * ((4 samples/48,000) * (13,500,000 * 8) * 16 - 1) * 8
112 */
113 cx18_av_write4(cx, 0x128, 0xa11193f8);
Hans Verkuil1c1e45d2008-04-28 20:24:33 -0300114 break;
115 }
116 } else {
117 switch (freq) {
118 case 32000:
119 /* VID_PLL and AUX_PLL */
120 cx18_av_write4(cx, 0x108, 0x1e08040f);
121
122 /* AUX_PLL_FRAC */
Andy Walls35f92b22008-07-25 15:03:08 -0300123 /* 0x8.9504318 * 28,636,363.63 / 0x1e = 32000 * 256 */
124 cx18_av_write4(cx, 0x110, 0x012a0863);
Hans Verkuil1c1e45d2008-04-28 20:24:33 -0300125
Andy Wallsf8f62962008-07-23 20:28:23 -0300126 /* src1_ctl */
127 /* 0x1.0000 = 32000/32000 */
Hans Verkuil1c1e45d2008-04-28 20:24:33 -0300128 cx18_av_write4(cx, 0x8f8, 0x08010000);
129
Andy Wallsf8f62962008-07-23 20:28:23 -0300130 /* src3/4/6_ctl */
131 /* 0x2.0000 = 2 * (32000/32000) */
Hans Verkuil1c1e45d2008-04-28 20:24:33 -0300132 cx18_av_write4(cx, 0x900, 0x08020000);
133 cx18_av_write4(cx, 0x904, 0x08020000);
134 cx18_av_write4(cx, 0x90c, 0x08020000);
135
136 /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */
137 cx18_av_write(cx, 0x127, 0x54);
Andy Walls35f92b22008-07-25 15:03:08 -0300138
139 /* AUD_COUNT = 0x1fff = 8 samples * 4 * 256 - 1 */
140 cx18_av_write4(cx, 0x12c, 0x11201fff);
141
142 /*
143 * EN_AV_LOCK = 1
144 * VID_COUNT = 0x0d2ef8 = 107999.000 * 8 =
145 * ((8 samples/32,000) * (13,500,000 * 8) * 4 - 1) * 8
146 */
147 cx18_av_write4(cx, 0x128, 0xa10d2ef8);
Hans Verkuil1c1e45d2008-04-28 20:24:33 -0300148 break;
149
150 case 44100:
151 /* VID_PLL and AUX_PLL */
152 cx18_av_write4(cx, 0x108, 0x1809040f);
153
154 /* AUX_PLL_FRAC */
Andy Walls35f92b22008-07-25 15:03:08 -0300155 /* 0x9.7635e74 * 28,636,363.63 / 0x18 = 44100 * 256 */
156 cx18_av_write4(cx, 0x110, 0x00ec6bce);
Hans Verkuil1c1e45d2008-04-28 20:24:33 -0300157
Andy Wallsf8f62962008-07-23 20:28:23 -0300158 /* src1_ctl */
159 /* 0x1.60cd = 44100/32000 */
Hans Verkuil1c1e45d2008-04-28 20:24:33 -0300160 cx18_av_write4(cx, 0x8f8, 0x080160cd);
161
Andy Wallsf8f62962008-07-23 20:28:23 -0300162 /* src3/4/6_ctl */
163 /* 0x1.7385 = 2 * (32000/44100) */
Hans Verkuil1c1e45d2008-04-28 20:24:33 -0300164 cx18_av_write4(cx, 0x900, 0x08017385);
165 cx18_av_write4(cx, 0x904, 0x08017385);
166 cx18_av_write4(cx, 0x90c, 0x08017385);
Andy Walls35f92b22008-07-25 15:03:08 -0300167
168 /* AUD_COUNT = 0x61ff = 49 samples * 2 * 256 - 1 */
169 cx18_av_write4(cx, 0x12c, 0x112061ff);
170
171 /*
172 * EN_AV_LOCK = 1
173 * VID_COUNT = 0x1d4bf8 = 239999.000 * 8 =
174 * ((49 samples/44,100) * (13,500,000 * 8) * 2 - 1) * 8
175 */
176 cx18_av_write4(cx, 0x128, 0xa11d4bf8);
Hans Verkuil1c1e45d2008-04-28 20:24:33 -0300177 break;
178
179 case 48000:
180 /* VID_PLL and AUX_PLL */
181 cx18_av_write4(cx, 0x108, 0x180a040f);
182
183 /* AUX_PLL_FRAC */
Andy Walls35f92b22008-07-25 15:03:08 -0300184 /* 0xa.4c6b6ea * 28,636,363.63 / 0x18 = 48000 * 256 */
185 cx18_av_write4(cx, 0x110, 0x0098d6dd);
Hans Verkuil1c1e45d2008-04-28 20:24:33 -0300186
Andy Wallsf8f62962008-07-23 20:28:23 -0300187 /* src1_ctl */
188 /* 0x1.8000 = 48000/32000 */
Hans Verkuil1c1e45d2008-04-28 20:24:33 -0300189 cx18_av_write4(cx, 0x8f8, 0x08018000);
190
Andy Wallsf8f62962008-07-23 20:28:23 -0300191 /* src3/4/6_ctl */
192 /* 0x1.5555 = 2 * (32000/48000) */
Hans Verkuil1c1e45d2008-04-28 20:24:33 -0300193 cx18_av_write4(cx, 0x900, 0x08015555);
194 cx18_av_write4(cx, 0x904, 0x08015555);
195 cx18_av_write4(cx, 0x90c, 0x08015555);
Andy Walls35f92b22008-07-25 15:03:08 -0300196
197 /* AUD_COUNT = 0x3fff = 4 samples * 16 * 256 - 1 */
198 cx18_av_write4(cx, 0x12c, 0x11203fff);
199
200 /*
201 * EN_AV_LOCK = 1
202 * VID_COUNT = 0x1193f8 = 143999.000 * 8 =
203 * ((4 samples/48,000) * (13,500,000 * 8) * 16 - 1) * 8
204 */
205 cx18_av_write4(cx, 0x128, 0xa11193f8);
Hans Verkuil1c1e45d2008-04-28 20:24:33 -0300206 break;
207 }
208 }
209
210 state->audclk_freq = freq;
211
212 return 0;
213}
214
215void cx18_av_audio_set_path(struct cx18 *cx)
216{
217 struct cx18_av_state *state = &cx->av_state;
218
219 /* stop microcontroller */
220 cx18_av_and_or(cx, 0x803, ~0x10, 0);
221
222 /* assert soft reset */
223 cx18_av_and_or(cx, 0x810, ~0x1, 0x01);
224
225 /* Mute everything to prevent the PFFT! */
226 cx18_av_write(cx, 0x8d3, 0x1f);
227
Hans Verkuil81cb727d2008-06-28 12:49:20 -0300228 if (state->aud_input <= CX18_AV_AUDIO_SERIAL2) {
Hans Verkuil1c1e45d2008-04-28 20:24:33 -0300229 /* Set Path1 to Serial Audio Input */
230 cx18_av_write4(cx, 0x8d0, 0x01011012);
231
232 /* The microcontroller should not be started for the
233 * non-tuner inputs: autodetection is specific for
234 * TV audio. */
235 } else {
236 /* Set Path1 to Analog Demod Main Channel */
237 cx18_av_write4(cx, 0x8d0, 0x1f063870);
238 }
239
240 set_audclk_freq(cx, state->audclk_freq);
241
242 /* deassert soft reset */
243 cx18_av_and_or(cx, 0x810, ~0x1, 0x00);
244
Hans Verkuil81cb727d2008-06-28 12:49:20 -0300245 if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
Hans Verkuil1c1e45d2008-04-28 20:24:33 -0300246 /* When the microcontroller detects the
247 * audio format, it will unmute the lines */
248 cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
249 }
250}
251
252static int get_volume(struct cx18 *cx)
253{
254 /* Volume runs +18dB to -96dB in 1/2dB steps
255 * change to fit the msp3400 -114dB to +12dB range */
256
257 /* check PATH1_VOLUME */
258 int vol = 228 - cx18_av_read(cx, 0x8d4);
259 vol = (vol / 2) + 23;
260 return vol << 9;
261}
262
263static void set_volume(struct cx18 *cx, int volume)
264{
265 /* First convert the volume to msp3400 values (0-127) */
266 int vol = volume >> 9;
267 /* now scale it up to cx18_av values
268 * -114dB to -96dB maps to 0
269 * this should be 19, but in my testing that was 4dB too loud */
270 if (vol <= 23)
271 vol = 0;
272 else
273 vol -= 23;
274
275 /* PATH1_VOLUME */
276 cx18_av_write(cx, 0x8d4, 228 - (vol * 2));
277}
278
279static int get_bass(struct cx18 *cx)
280{
281 /* bass is 49 steps +12dB to -12dB */
282
283 /* check PATH1_EQ_BASS_VOL */
284 int bass = cx18_av_read(cx, 0x8d9) & 0x3f;
285 bass = (((48 - bass) * 0xffff) + 47) / 48;
286 return bass;
287}
288
289static void set_bass(struct cx18 *cx, int bass)
290{
291 /* PATH1_EQ_BASS_VOL */
292 cx18_av_and_or(cx, 0x8d9, ~0x3f, 48 - (bass * 48 / 0xffff));
293}
294
295static int get_treble(struct cx18 *cx)
296{
297 /* treble is 49 steps +12dB to -12dB */
298
299 /* check PATH1_EQ_TREBLE_VOL */
300 int treble = cx18_av_read(cx, 0x8db) & 0x3f;
301 treble = (((48 - treble) * 0xffff) + 47) / 48;
302 return treble;
303}
304
305static void set_treble(struct cx18 *cx, int treble)
306{
307 /* PATH1_EQ_TREBLE_VOL */
308 cx18_av_and_or(cx, 0x8db, ~0x3f, 48 - (treble * 48 / 0xffff));
309}
310
311static int get_balance(struct cx18 *cx)
312{
313 /* balance is 7 bit, 0 to -96dB */
314
315 /* check PATH1_BAL_LEVEL */
316 int balance = cx18_av_read(cx, 0x8d5) & 0x7f;
317 /* check PATH1_BAL_LEFT */
318 if ((cx18_av_read(cx, 0x8d5) & 0x80) == 0)
319 balance = 0x80 - balance;
320 else
321 balance = 0x80 + balance;
322 return balance << 8;
323}
324
325static void set_balance(struct cx18 *cx, int balance)
326{
327 int bal = balance >> 8;
328 if (bal > 0x80) {
329 /* PATH1_BAL_LEFT */
330 cx18_av_and_or(cx, 0x8d5, 0x7f, 0x80);
331 /* PATH1_BAL_LEVEL */
332 cx18_av_and_or(cx, 0x8d5, ~0x7f, bal & 0x7f);
333 } else {
334 /* PATH1_BAL_LEFT */
335 cx18_av_and_or(cx, 0x8d5, 0x7f, 0x00);
336 /* PATH1_BAL_LEVEL */
337 cx18_av_and_or(cx, 0x8d5, ~0x7f, 0x80 - bal);
338 }
339}
340
341static int get_mute(struct cx18 *cx)
342{
343 /* check SRC1_MUTE_EN */
344 return cx18_av_read(cx, 0x8d3) & 0x2 ? 1 : 0;
345}
346
347static void set_mute(struct cx18 *cx, int mute)
348{
349 struct cx18_av_state *state = &cx->av_state;
350
Hans Verkuil81cb727d2008-06-28 12:49:20 -0300351 if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
Hans Verkuil1c1e45d2008-04-28 20:24:33 -0300352 /* Must turn off microcontroller in order to mute sound.
353 * Not sure if this is the best method, but it does work.
354 * If the microcontroller is running, then it will undo any
355 * changes to the mute register. */
356 if (mute) {
357 /* disable microcontroller */
358 cx18_av_and_or(cx, 0x803, ~0x10, 0x00);
359 cx18_av_write(cx, 0x8d3, 0x1f);
360 } else {
361 /* enable microcontroller */
362 cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
363 }
364 } else {
365 /* SRC1_MUTE_EN */
366 cx18_av_and_or(cx, 0x8d3, ~0x2, mute ? 0x02 : 0x00);
367 }
368}
369
370int cx18_av_audio(struct cx18 *cx, unsigned int cmd, void *arg)
371{
372 struct cx18_av_state *state = &cx->av_state;
373 struct v4l2_control *ctrl = arg;
374 int retval;
375
376 switch (cmd) {
377 case VIDIOC_INT_AUDIO_CLOCK_FREQ:
Hans Verkuil81cb727d2008-06-28 12:49:20 -0300378 if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
Hans Verkuil1c1e45d2008-04-28 20:24:33 -0300379 cx18_av_and_or(cx, 0x803, ~0x10, 0);
380 cx18_av_write(cx, 0x8d3, 0x1f);
381 }
382 cx18_av_and_or(cx, 0x810, ~0x1, 1);
383 retval = set_audclk_freq(cx, *(u32 *)arg);
384 cx18_av_and_or(cx, 0x810, ~0x1, 0);
Hans Verkuil81cb727d2008-06-28 12:49:20 -0300385 if (state->aud_input > CX18_AV_AUDIO_SERIAL2)
Hans Verkuil1c1e45d2008-04-28 20:24:33 -0300386 cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
387 return retval;
388
389 case VIDIOC_G_CTRL:
390 switch (ctrl->id) {
391 case V4L2_CID_AUDIO_VOLUME:
392 ctrl->value = get_volume(cx);
393 break;
394 case V4L2_CID_AUDIO_BASS:
395 ctrl->value = get_bass(cx);
396 break;
397 case V4L2_CID_AUDIO_TREBLE:
398 ctrl->value = get_treble(cx);
399 break;
400 case V4L2_CID_AUDIO_BALANCE:
401 ctrl->value = get_balance(cx);
402 break;
403 case V4L2_CID_AUDIO_MUTE:
404 ctrl->value = get_mute(cx);
405 break;
406 default:
407 return -EINVAL;
408 }
409 break;
410
411 case VIDIOC_S_CTRL:
412 switch (ctrl->id) {
413 case V4L2_CID_AUDIO_VOLUME:
414 set_volume(cx, ctrl->value);
415 break;
416 case V4L2_CID_AUDIO_BASS:
417 set_bass(cx, ctrl->value);
418 break;
419 case V4L2_CID_AUDIO_TREBLE:
420 set_treble(cx, ctrl->value);
421 break;
422 case V4L2_CID_AUDIO_BALANCE:
423 set_balance(cx, ctrl->value);
424 break;
425 case V4L2_CID_AUDIO_MUTE:
426 set_mute(cx, ctrl->value);
427 break;
428 default:
429 return -EINVAL;
430 }
431 break;
432
433 default:
434 return -EINVAL;
435 }
436
437 return 0;
438}