• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/drivers/media/video/cx25840/
1/* cx25840 audio functions
2 *
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU General Public License
5 * as published by the Free Software Foundation; either version 2
6 * of the License, or (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
16 */
17
18
19#include <linux/videodev2.h>
20#include <linux/i2c.h>
21#include <media/v4l2-common.h>
22#include <media/cx25840.h>
23
24#include "cx25840-core.h"
25
26/*
27 * Note: The PLL and SRC parameters are based on a reference frequency that
28 * would ideally be:
29 *
30 * NTSC Color subcarrier freq * 8 = 4.5 MHz/286 * 455/2 * 8 = 28.63636363... MHz
31 *
32 * However, it's not the exact reference frequency that matters, only that the
33 * firmware and modules that comprise the driver for a particular board all
34 * use the same value (close to the ideal value).
35 *
36 * Comments below will note which reference frequency is assumed for various
37 * parameters.  They will usually be one of
38 *
39 *	ref_freq = 28.636360 MHz
40 *		or
41 *	ref_freq = 28.636363 MHz
42 */
43
44static int cx25840_set_audclk_freq(struct i2c_client *client, u32 freq)
45{
46	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
47
48	if (state->aud_input != CX25840_AUDIO_SERIAL) {
49		switch (freq) {
50		case 32000:
51			/*
52			 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
53			 * AUX_PLL Integer = 0x06, AUX PLL Post Divider = 0x10
54			 */
55			cx25840_write4(client, 0x108, 0x1006040f);
56
57			/*
58			 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
59			 * 28636360 * 0xf.15f17f0/4 = 108 MHz
60			 * 432 MHz pre-postdivide
61			 */
62
63			cx25840_write4(client, 0x110, 0x01bb39ee);
64
65			/*
66			 * SA_MCLK_SEL = 1
67			 * SA_MCLK_DIV = 0x10 = 384/384 * AUX_PLL post dvivider
68			 */
69			cx25840_write(client, 0x127, 0x50);
70
71			if (is_cx2583x(state))
72				break;
73
74			/* src3/4/6_ctl */
75			/* 0x1.f77f = (4 * 28636360/8 * 2/455) / 32000 */
76			cx25840_write4(client, 0x900, 0x0801f77f);
77			cx25840_write4(client, 0x904, 0x0801f77f);
78			cx25840_write4(client, 0x90c, 0x0801f77f);
79			break;
80
81		case 44100:
82			/*
83			 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
84			 * AUX_PLL Integer = 0x09, AUX PLL Post Divider = 0x10
85			 */
86			cx25840_write4(client, 0x108, 0x1009040f);
87
88			/*
89			 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
90			 * 28636360 * 0xf.15f17f0/4 = 108 MHz
91			 * 432 MHz pre-postdivide
92			 */
93
94			cx25840_write4(client, 0x110, 0x00ec6bd6);
95
96			/*
97			 * SA_MCLK_SEL = 1
98			 * SA_MCLK_DIV = 0x10 = 384/384 * AUX_PLL post dvivider
99			 */
100			cx25840_write(client, 0x127, 0x50);
101
102			if (is_cx2583x(state))
103				break;
104
105			/* src3/4/6_ctl */
106			/* 0x1.6d59 = (4 * 28636360/8 * 2/455) / 44100 */
107			cx25840_write4(client, 0x900, 0x08016d59);
108			cx25840_write4(client, 0x904, 0x08016d59);
109			cx25840_write4(client, 0x90c, 0x08016d59);
110			break;
111
112		case 48000:
113			/*
114			 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
115			 * AUX_PLL Integer = 0x0a, AUX PLL Post Divider = 0x10
116			 */
117			cx25840_write4(client, 0x108, 0x100a040f);
118
119			/*
120			 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
121			 * 28636360 * 0xf.15f17f0/4 = 108 MHz
122			 * 432 MHz pre-postdivide
123			 */
124
125			cx25840_write4(client, 0x110, 0x0098d6e5);
126
127			/*
128			 * SA_MCLK_SEL = 1
129			 * SA_MCLK_DIV = 0x10 = 384/384 * AUX_PLL post dvivider
130			 */
131			cx25840_write(client, 0x127, 0x50);
132
133			if (is_cx2583x(state))
134				break;
135
136			/* src3/4/6_ctl */
137			/* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */
138			cx25840_write4(client, 0x900, 0x08014faa);
139			cx25840_write4(client, 0x904, 0x08014faa);
140			cx25840_write4(client, 0x90c, 0x08014faa);
141			break;
142		}
143	} else {
144		switch (freq) {
145		case 32000:
146			/*
147			 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
148			 * AUX_PLL Integer = 0x08, AUX PLL Post Divider = 0x1e
149			 */
150			cx25840_write4(client, 0x108, 0x1e08040f);
151
152			/*
153			 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
154			 * 28636360 * 0xf.15f17f0/4 = 108 MHz
155			 * 432 MHz pre-postdivide
156			 */
157
158			cx25840_write4(client, 0x110, 0x012a0869);
159
160			/*
161			 * SA_MCLK_SEL = 1
162			 * SA_MCLK_DIV = 0x14 = 256/384 * AUX_PLL post dvivider
163			 */
164			cx25840_write(client, 0x127, 0x54);
165
166			if (is_cx2583x(state))
167				break;
168
169			/* src1_ctl */
170			/* 0x1.0000 = 32000/32000 */
171			cx25840_write4(client, 0x8f8, 0x08010000);
172
173			/* src3/4/6_ctl */
174			/* 0x2.0000 = 2 * (32000/32000) */
175			cx25840_write4(client, 0x900, 0x08020000);
176			cx25840_write4(client, 0x904, 0x08020000);
177			cx25840_write4(client, 0x90c, 0x08020000);
178			break;
179
180		case 44100:
181			/*
182			 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
183			 * AUX_PLL Integer = 0x09, AUX PLL Post Divider = 0x18
184			 */
185			cx25840_write4(client, 0x108, 0x1809040f);
186
187			/*
188			 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
189			 * 28636360 * 0xf.15f17f0/4 = 108 MHz
190			 * 432 MHz pre-postdivide
191			 */
192
193			cx25840_write4(client, 0x110, 0x00ec6bd6);
194
195			/*
196			 * SA_MCLK_SEL = 1
197			 * SA_MCLK_DIV = 0x10 = 256/384 * AUX_PLL post dvivider
198			 */
199			cx25840_write(client, 0x127, 0x50);
200
201			if (is_cx2583x(state))
202				break;
203
204			/* src1_ctl */
205			/* 0x1.60cd = 44100/32000 */
206			cx25840_write4(client, 0x8f8, 0x080160cd);
207
208			/* src3/4/6_ctl */
209			/* 0x1.7385 = 2 * (32000/44100) */
210			cx25840_write4(client, 0x900, 0x08017385);
211			cx25840_write4(client, 0x904, 0x08017385);
212			cx25840_write4(client, 0x90c, 0x08017385);
213			break;
214
215		case 48000:
216			/*
217			 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
218			 * AUX_PLL Integer = 0x0a, AUX PLL Post Divider = 0x18
219			 */
220			cx25840_write4(client, 0x108, 0x180a040f);
221
222			/*
223			 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
224			 * 28636360 * 0xf.15f17f0/4 = 108 MHz
225			 * 432 MHz pre-postdivide
226			 */
227
228			cx25840_write4(client, 0x110, 0x0098d6e5);
229
230			/*
231			 * SA_MCLK_SEL = 1
232			 * SA_MCLK_DIV = 0x10 = 256/384 * AUX_PLL post dvivider
233			 */
234			cx25840_write(client, 0x127, 0x50);
235
236			if (is_cx2583x(state))
237				break;
238
239			/* src1_ctl */
240			/* 0x1.8000 = 48000/32000 */
241			cx25840_write4(client, 0x8f8, 0x08018000);
242
243			/* src3/4/6_ctl */
244			/* 0x1.5555 = 2 * (32000/48000) */
245			cx25840_write4(client, 0x900, 0x08015555);
246			cx25840_write4(client, 0x904, 0x08015555);
247			cx25840_write4(client, 0x90c, 0x08015555);
248			break;
249		}
250	}
251
252	state->audclk_freq = freq;
253
254	return 0;
255}
256
257static inline int cx25836_set_audclk_freq(struct i2c_client *client, u32 freq)
258{
259	return cx25840_set_audclk_freq(client, freq);
260}
261
262static int cx23885_set_audclk_freq(struct i2c_client *client, u32 freq)
263{
264	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
265
266	if (state->aud_input != CX25840_AUDIO_SERIAL) {
267		switch (freq) {
268		case 32000:
269		case 44100:
270		case 48000:
271			/* We don't have register values
272			 * so avoid destroying registers. */
273			break;
274		}
275	} else {
276		switch (freq) {
277		case 32000:
278		case 44100:
279			/* We don't have register values
280			 * so avoid destroying registers. */
281			break;
282
283		case 48000:
284			/* src1_ctl */
285			/* 0x1.867c = 48000 / (2 * 28636360/8 * 2/455) */
286			cx25840_write4(client, 0x8f8, 0x0801867c);
287
288			/* src3/4/6_ctl */
289			/* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */
290			cx25840_write4(client, 0x900, 0x08014faa);
291			cx25840_write4(client, 0x904, 0x08014faa);
292			cx25840_write4(client, 0x90c, 0x08014faa);
293			break;
294		}
295	}
296
297	state->audclk_freq = freq;
298
299	return 0;
300}
301
302static int cx231xx_set_audclk_freq(struct i2c_client *client, u32 freq)
303{
304	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
305
306	if (state->aud_input != CX25840_AUDIO_SERIAL) {
307		switch (freq) {
308		case 32000:
309			/* src3/4/6_ctl */
310			/* 0x1.f77f = (4 * 28636360/8 * 2/455) / 32000 */
311			cx25840_write4(client, 0x900, 0x0801f77f);
312			cx25840_write4(client, 0x904, 0x0801f77f);
313			cx25840_write4(client, 0x90c, 0x0801f77f);
314			break;
315
316		case 44100:
317			/* src3/4/6_ctl */
318			/* 0x1.6d59 = (4 * 28636360/8 * 2/455) / 44100 */
319			cx25840_write4(client, 0x900, 0x08016d59);
320			cx25840_write4(client, 0x904, 0x08016d59);
321			cx25840_write4(client, 0x90c, 0x08016d59);
322			break;
323
324		case 48000:
325			/* src3/4/6_ctl */
326			/* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */
327			cx25840_write4(client, 0x900, 0x08014faa);
328			cx25840_write4(client, 0x904, 0x08014faa);
329			cx25840_write4(client, 0x90c, 0x08014faa);
330			break;
331		}
332	} else {
333		switch (freq) {
334		case 32000:
335			/* src1_ctl */
336			/* 0x1.0000 = 32000/32000 */
337			cx25840_write4(client, 0x8f8, 0x08010000);
338
339			/* src3/4/6_ctl */
340			/* 0x2.0000 = 2 * (32000/32000) */
341			cx25840_write4(client, 0x900, 0x08020000);
342			cx25840_write4(client, 0x904, 0x08020000);
343			cx25840_write4(client, 0x90c, 0x08020000);
344			break;
345
346		case 44100:
347			/* src1_ctl */
348			/* 0x1.60cd = 44100/32000 */
349			cx25840_write4(client, 0x8f8, 0x080160cd);
350
351			/* src3/4/6_ctl */
352			/* 0x1.7385 = 2 * (32000/44100) */
353			cx25840_write4(client, 0x900, 0x08017385);
354			cx25840_write4(client, 0x904, 0x08017385);
355			cx25840_write4(client, 0x90c, 0x08017385);
356			break;
357
358		case 48000:
359			/* src1_ctl */
360			/* 0x1.867c = 48000 / (2 * 28636360/8 * 2/455) */
361			cx25840_write4(client, 0x8f8, 0x0801867c);
362
363			/* src3/4/6_ctl */
364			/* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */
365			cx25840_write4(client, 0x900, 0x08014faa);
366			cx25840_write4(client, 0x904, 0x08014faa);
367			cx25840_write4(client, 0x90c, 0x08014faa);
368			break;
369		}
370	}
371
372	state->audclk_freq = freq;
373
374	return 0;
375}
376
377static int set_audclk_freq(struct i2c_client *client, u32 freq)
378{
379	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
380
381	if (freq != 32000 && freq != 44100 && freq != 48000)
382		return -EINVAL;
383
384	if (is_cx231xx(state))
385		return cx231xx_set_audclk_freq(client, freq);
386
387	if (is_cx2388x(state))
388		return cx23885_set_audclk_freq(client, freq);
389
390	if (is_cx2583x(state))
391		return cx25836_set_audclk_freq(client, freq);
392
393	return cx25840_set_audclk_freq(client, freq);
394}
395
396void cx25840_audio_set_path(struct i2c_client *client)
397{
398	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
399
400	/* assert soft reset */
401	cx25840_and_or(client, 0x810, ~0x1, 0x01);
402
403	/* stop microcontroller */
404	cx25840_and_or(client, 0x803, ~0x10, 0);
405
406	/* Mute everything to prevent the PFFT! */
407	cx25840_write(client, 0x8d3, 0x1f);
408
409	if (state->aud_input == CX25840_AUDIO_SERIAL) {
410		/* Set Path1 to Serial Audio Input */
411		cx25840_write4(client, 0x8d0, 0x01011012);
412
413		/* The microcontroller should not be started for the
414		 * non-tuner inputs: autodetection is specific for
415		 * TV audio. */
416	} else {
417		/* Set Path1 to Analog Demod Main Channel */
418		cx25840_write4(client, 0x8d0, 0x1f063870);
419	}
420
421	set_audclk_freq(client, state->audclk_freq);
422
423	if (state->aud_input != CX25840_AUDIO_SERIAL) {
424		/* When the microcontroller detects the
425		 * audio format, it will unmute the lines */
426		cx25840_and_or(client, 0x803, ~0x10, 0x10);
427	}
428
429	/* deassert soft reset */
430	cx25840_and_or(client, 0x810, ~0x1, 0x00);
431
432	/* Ensure the controller is running when we exit */
433	if (is_cx2388x(state) || is_cx231xx(state))
434		cx25840_and_or(client, 0x803, ~0x10, 0x10);
435}
436
437static void set_volume(struct i2c_client *client, int volume)
438{
439	int vol;
440
441	/* Convert the volume to msp3400 values (0-127) */
442	vol = volume >> 9;
443
444	/* now scale it up to cx25840 values
445	 * -114dB to -96dB maps to 0
446	 * this should be 19, but in my testing that was 4dB too loud */
447	if (vol <= 23) {
448		vol = 0;
449	} else {
450		vol -= 23;
451	}
452
453	/* PATH1_VOLUME */
454	cx25840_write(client, 0x8d4, 228 - (vol * 2));
455}
456
457static void set_balance(struct i2c_client *client, int balance)
458{
459	int bal = balance >> 8;
460	if (bal > 0x80) {
461		/* PATH1_BAL_LEFT */
462		cx25840_and_or(client, 0x8d5, 0x7f, 0x80);
463		/* PATH1_BAL_LEVEL */
464		cx25840_and_or(client, 0x8d5, ~0x7f, bal & 0x7f);
465	} else {
466		/* PATH1_BAL_LEFT */
467		cx25840_and_or(client, 0x8d5, 0x7f, 0x00);
468		/* PATH1_BAL_LEVEL */
469		cx25840_and_or(client, 0x8d5, ~0x7f, 0x80 - bal);
470	}
471}
472
473int cx25840_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
474{
475	struct i2c_client *client = v4l2_get_subdevdata(sd);
476	struct cx25840_state *state = to_state(sd);
477	int retval;
478
479	if (!is_cx2583x(state))
480		cx25840_and_or(client, 0x810, ~0x1, 1);
481	if (state->aud_input != CX25840_AUDIO_SERIAL) {
482		cx25840_and_or(client, 0x803, ~0x10, 0);
483		cx25840_write(client, 0x8d3, 0x1f);
484	}
485	retval = set_audclk_freq(client, freq);
486	if (state->aud_input != CX25840_AUDIO_SERIAL)
487		cx25840_and_or(client, 0x803, ~0x10, 0x10);
488	if (!is_cx2583x(state))
489		cx25840_and_or(client, 0x810, ~0x1, 0);
490	return retval;
491}
492
493static int cx25840_audio_s_ctrl(struct v4l2_ctrl *ctrl)
494{
495	struct v4l2_subdev *sd = to_sd(ctrl);
496	struct cx25840_state *state = to_state(sd);
497	struct i2c_client *client = v4l2_get_subdevdata(sd);
498
499	switch (ctrl->id) {
500	case V4L2_CID_AUDIO_VOLUME:
501		if (state->mute->val)
502			set_volume(client, 0);
503		else
504			set_volume(client, state->volume->val);
505		break;
506	case V4L2_CID_AUDIO_BASS:
507		/* PATH1_EQ_BASS_VOL */
508		cx25840_and_or(client, 0x8d9, ~0x3f,
509					48 - (ctrl->val * 48 / 0xffff));
510		break;
511	case V4L2_CID_AUDIO_TREBLE:
512		/* PATH1_EQ_TREBLE_VOL */
513		cx25840_and_or(client, 0x8db, ~0x3f,
514					48 - (ctrl->val * 48 / 0xffff));
515		break;
516	case V4L2_CID_AUDIO_BALANCE:
517		set_balance(client, ctrl->val);
518		break;
519	default:
520		return -EINVAL;
521	}
522	return 0;
523}
524
525const struct v4l2_ctrl_ops cx25840_audio_ctrl_ops = {
526	.s_ctrl = cx25840_audio_s_ctrl,
527};
528