1 /* cx25840 audio functions
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.
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.
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.
19 #include <linux/videodev2.h>
20 #include <linux/i2c.h>
21 #include <media/v4l2-common.h>
22 #include <media/cx25840.h>
24 #include "cx25840-core.h"
27 * Note: The PLL and SRC parameters are based on a reference frequency that
30 * NTSC Color subcarrier freq * 8 = 4.5 MHz/286 * 455/2 * 8 = 28.63636363... MHz
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).
36 * Comments below will note which reference frequency is assumed for various
37 * parameters. They will usually be one of
39 * ref_freq = 28.636360 MHz
41 * ref_freq = 28.636363 MHz
44 static int cx25840_set_audclk_freq(struct i2c_client
*client
, u32 freq
)
46 struct cx25840_state
*state
= to_state(i2c_get_clientdata(client
));
48 if (state
->aud_input
!= CX25840_AUDIO_SERIAL
) {
52 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
53 * AUX_PLL Integer = 0x06, AUX PLL Post Divider = 0x10
55 cx25840_write4(client
, 0x108, 0x1006040f);
58 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
59 * 28636360 * 0xf.15f17f0/4 = 108 MHz
60 * 432 MHz pre-postdivide
63 cx25840_write4(client
, 0x110, 0x01bb39ee);
67 * SA_MCLK_DIV = 0x10 = 384/384 * AUX_PLL post dvivider
69 cx25840_write(client
, 0x127, 0x50);
71 if (is_cx2583x(state
))
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);
83 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
84 * AUX_PLL Integer = 0x09, AUX PLL Post Divider = 0x10
86 cx25840_write4(client
, 0x108, 0x1009040f);
89 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
90 * 28636360 * 0xf.15f17f0/4 = 108 MHz
91 * 432 MHz pre-postdivide
94 cx25840_write4(client
, 0x110, 0x00ec6bd6);
98 * SA_MCLK_DIV = 0x10 = 384/384 * AUX_PLL post dvivider
100 cx25840_write(client
, 0x127, 0x50);
102 if (is_cx2583x(state
))
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);
114 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
115 * AUX_PLL Integer = 0x0a, AUX PLL Post Divider = 0x10
117 cx25840_write4(client
, 0x108, 0x100a040f);
120 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
121 * 28636360 * 0xf.15f17f0/4 = 108 MHz
122 * 432 MHz pre-postdivide
125 cx25840_write4(client
, 0x110, 0x0098d6e5);
129 * SA_MCLK_DIV = 0x10 = 384/384 * AUX_PLL post dvivider
131 cx25840_write(client
, 0x127, 0x50);
133 if (is_cx2583x(state
))
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);
147 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
148 * AUX_PLL Integer = 0x08, AUX PLL Post Divider = 0x1e
150 cx25840_write4(client
, 0x108, 0x1e08040f);
153 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
154 * 28636360 * 0xf.15f17f0/4 = 108 MHz
155 * 432 MHz pre-postdivide
158 cx25840_write4(client
, 0x110, 0x012a0869);
162 * SA_MCLK_DIV = 0x14 = 256/384 * AUX_PLL post dvivider
164 cx25840_write(client
, 0x127, 0x54);
166 if (is_cx2583x(state
))
170 /* 0x1.0000 = 32000/32000 */
171 cx25840_write4(client
, 0x8f8, 0x08010000);
174 /* 0x2.0000 = 2 * (32000/32000) */
175 cx25840_write4(client
, 0x900, 0x08020000);
176 cx25840_write4(client
, 0x904, 0x08020000);
177 cx25840_write4(client
, 0x90c, 0x08020000);
182 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
183 * AUX_PLL Integer = 0x09, AUX PLL Post Divider = 0x18
185 cx25840_write4(client
, 0x108, 0x1809040f);
188 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
189 * 28636360 * 0xf.15f17f0/4 = 108 MHz
190 * 432 MHz pre-postdivide
193 cx25840_write4(client
, 0x110, 0x00ec6bd6);
197 * SA_MCLK_DIV = 0x10 = 256/384 * AUX_PLL post dvivider
199 cx25840_write(client
, 0x127, 0x50);
201 if (is_cx2583x(state
))
205 /* 0x1.60cd = 44100/32000 */
206 cx25840_write4(client
, 0x8f8, 0x080160cd);
209 /* 0x1.7385 = 2 * (32000/44100) */
210 cx25840_write4(client
, 0x900, 0x08017385);
211 cx25840_write4(client
, 0x904, 0x08017385);
212 cx25840_write4(client
, 0x90c, 0x08017385);
217 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
218 * AUX_PLL Integer = 0x0a, AUX PLL Post Divider = 0x18
220 cx25840_write4(client
, 0x108, 0x180a040f);
223 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
224 * 28636360 * 0xf.15f17f0/4 = 108 MHz
225 * 432 MHz pre-postdivide
228 cx25840_write4(client
, 0x110, 0x0098d6e5);
232 * SA_MCLK_DIV = 0x10 = 256/384 * AUX_PLL post dvivider
234 cx25840_write(client
, 0x127, 0x50);
236 if (is_cx2583x(state
))
240 /* 0x1.8000 = 48000/32000 */
241 cx25840_write4(client
, 0x8f8, 0x08018000);
244 /* 0x1.5555 = 2 * (32000/48000) */
245 cx25840_write4(client
, 0x900, 0x08015555);
246 cx25840_write4(client
, 0x904, 0x08015555);
247 cx25840_write4(client
, 0x90c, 0x08015555);
252 state
->audclk_freq
= freq
;
257 static inline int cx25836_set_audclk_freq(struct i2c_client
*client
, u32 freq
)
259 return cx25840_set_audclk_freq(client
, freq
);
262 static int cx23885_set_audclk_freq(struct i2c_client
*client
, u32 freq
)
264 struct cx25840_state
*state
= to_state(i2c_get_clientdata(client
));
266 if (state
->aud_input
!= CX25840_AUDIO_SERIAL
) {
271 /* We don't have register values
272 * so avoid destroying registers. */
279 /* We don't have register values
280 * so avoid destroying registers. */
285 /* 0x1.867c = 48000 / (2 * 28636360/8 * 2/455) */
286 cx25840_write4(client
, 0x8f8, 0x0801867c);
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);
297 state
->audclk_freq
= freq
;
302 static int cx231xx_set_audclk_freq(struct i2c_client
*client
, u32 freq
)
304 struct cx25840_state
*state
= to_state(i2c_get_clientdata(client
));
306 if (state
->aud_input
!= CX25840_AUDIO_SERIAL
) {
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);
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);
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);
336 /* 0x1.0000 = 32000/32000 */
337 cx25840_write4(client
, 0x8f8, 0x08010000);
340 /* 0x2.0000 = 2 * (32000/32000) */
341 cx25840_write4(client
, 0x900, 0x08020000);
342 cx25840_write4(client
, 0x904, 0x08020000);
343 cx25840_write4(client
, 0x90c, 0x08020000);
348 /* 0x1.60cd = 44100/32000 */
349 cx25840_write4(client
, 0x8f8, 0x080160cd);
352 /* 0x1.7385 = 2 * (32000/44100) */
353 cx25840_write4(client
, 0x900, 0x08017385);
354 cx25840_write4(client
, 0x904, 0x08017385);
355 cx25840_write4(client
, 0x90c, 0x08017385);
360 /* 0x1.867c = 48000 / (2 * 28636360/8 * 2/455) */
361 cx25840_write4(client
, 0x8f8, 0x0801867c);
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);
372 state
->audclk_freq
= freq
;
377 static int set_audclk_freq(struct i2c_client
*client
, u32 freq
)
379 struct cx25840_state
*state
= to_state(i2c_get_clientdata(client
));
381 if (freq
!= 32000 && freq
!= 44100 && freq
!= 48000)
384 if (is_cx231xx(state
))
385 return cx231xx_set_audclk_freq(client
, freq
);
387 if (is_cx2388x(state
))
388 return cx23885_set_audclk_freq(client
, freq
);
390 if (is_cx2583x(state
))
391 return cx25836_set_audclk_freq(client
, freq
);
393 return cx25840_set_audclk_freq(client
, freq
);
396 void cx25840_audio_set_path(struct i2c_client
*client
)
398 struct cx25840_state
*state
= to_state(i2c_get_clientdata(client
));
400 /* assert soft reset */
401 cx25840_and_or(client
, 0x810, ~0x1, 0x01);
403 /* stop microcontroller */
404 cx25840_and_or(client
, 0x803, ~0x10, 0);
406 /* Mute everything to prevent the PFFT! */
407 cx25840_write(client
, 0x8d3, 0x1f);
409 if (state
->aud_input
== CX25840_AUDIO_SERIAL
) {
410 /* Set Path1 to Serial Audio Input */
411 cx25840_write4(client
, 0x8d0, 0x01011012);
413 /* The microcontroller should not be started for the
414 * non-tuner inputs: autodetection is specific for
417 /* Set Path1 to Analog Demod Main Channel */
418 cx25840_write4(client
, 0x8d0, 0x1f063870);
421 set_audclk_freq(client
, state
->audclk_freq
);
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);
429 /* deassert soft reset */
430 cx25840_and_or(client
, 0x810, ~0x1, 0x00);
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);
437 static void set_volume(struct i2c_client
*client
, int volume
)
441 /* Convert the volume to msp3400 values (0-127) */
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 */
454 cx25840_write(client
, 0x8d4, 228 - (vol
* 2));
457 static void set_balance(struct i2c_client
*client
, int balance
)
459 int bal
= balance
>> 8;
462 cx25840_and_or(client
, 0x8d5, 0x7f, 0x80);
463 /* PATH1_BAL_LEVEL */
464 cx25840_and_or(client
, 0x8d5, ~0x7f, bal
& 0x7f);
467 cx25840_and_or(client
, 0x8d5, 0x7f, 0x00);
468 /* PATH1_BAL_LEVEL */
469 cx25840_and_or(client
, 0x8d5, ~0x7f, 0x80 - bal
);
473 int cx25840_s_clock_freq(struct v4l2_subdev
*sd
, u32 freq
)
475 struct i2c_client
*client
= v4l2_get_subdevdata(sd
);
476 struct cx25840_state
*state
= to_state(sd
);
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);
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);
493 static int cx25840_audio_s_ctrl(struct v4l2_ctrl
*ctrl
)
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
);
500 case V4L2_CID_AUDIO_VOLUME
:
501 if (state
->mute
->val
)
502 set_volume(client
, 0);
504 set_volume(client
, state
->volume
->val
);
506 case V4L2_CID_AUDIO_BASS
:
507 /* PATH1_EQ_BASS_VOL */
508 cx25840_and_or(client
, 0x8d9, ~0x3f,
509 48 - (ctrl
->val
* 48 / 0xffff));
511 case V4L2_CID_AUDIO_TREBLE
:
512 /* PATH1_EQ_TREBLE_VOL */
513 cx25840_and_or(client
, 0x8db, ~0x3f,
514 48 - (ctrl
->val
* 48 / 0xffff));
516 case V4L2_CID_AUDIO_BALANCE
:
517 set_balance(client
, ctrl
->val
);
525 const struct v4l2_ctrl_ops cx25840_audio_ctrl_ops
= {
526 .s_ctrl
= cx25840_audio_s_ctrl
,