aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/cx25840
diff options
context:
space:
mode:
authorAndy Walls <awalls@radix.net>2009-09-26 22:54:20 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-12-05 15:40:18 -0500
commit9eef550a9a98c1e3d15aaf490812949fdeb01c7c (patch)
treef038947a4560dec1f56a103a9d2e124834766bff /drivers/media/video/cx25840
parent2a03f03471d3232037e656570ccaf3ff2ffd01e8 (diff)
V4L/DVB (13089): cx25840: Separate set_audclk_freq functionality for the different chips
Separate out the set_audclk_freq() function into separate functions for the four families of cores. These cores all use slightly different sample clock schemes and may be assuming slightly (+/- 3 Hz) different reference frequencies. The code resuse was not worth the maintenance and testing headache of have all chips use the same function peppered with conditional logic. Added comments on how PLL and SRC parameters values are computed. Fixed a few bugs related to the shared code having a large number of conditional statements. Noted inconsistencies with FIXME in the comments. This is done in preparation for getting the CX2388[578] PLL/clock setting logic cleaned up for CX23888 analog video and IR (which need the VID PLL set right). Signed-off-by: Andy Walls <awalls@radix.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/cx25840')
-rw-r--r--drivers/media/video/cx25840/cx25840-audio.c437
1 files changed, 332 insertions, 105 deletions
diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c
index fbccbdce26e0..45608d50529c 100644
--- a/drivers/media/video/cx25840/cx25840-audio.c
+++ b/drivers/media/video/cx25840/cx25840-audio.c
@@ -23,87 +23,137 @@
23 23
24#include "cx25840-core.h" 24#include "cx25840-core.h"
25 25
26static int set_audclk_freq(struct i2c_client *client, u32 freq) 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)
27{ 45{
28 struct cx25840_state *state = to_state(i2c_get_clientdata(client)); 46 struct cx25840_state *state = to_state(i2c_get_clientdata(client));
29 47
30 if (freq != 32000 && freq != 44100 && freq != 48000)
31 return -EINVAL;
32
33 /* common for all inputs and rates */
34 /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */
35 if (!is_cx2388x(state) && !is_cx231xx(state))
36 cx25840_write(client, 0x127, 0x50);
37
38 if (state->aud_input != CX25840_AUDIO_SERIAL) { 48 if (state->aud_input != CX25840_AUDIO_SERIAL) {
39 switch (freq) { 49 switch (freq) {
40 case 32000: 50 case 32000:
41 if (is_cx2388x(state)) { 51 /*
42 /* We don't have register values 52 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
43 * so avoid destroying registers. */ 53 * AUX_PLL Integer = 0x06, AUX PLL Post Divider = 0x10
44 break; 54 */
45 } 55 cx25840_write4(client, 0x108, 0x1006040f);
46 56
47 if (!is_cx231xx(state)) { 57 /*
48 /* VID_PLL and AUX_PLL */ 58 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
49 cx25840_write4(client, 0x108, 0x1006040f); 59 * 28636360 * 0xf.15f17f0/4 = 108 MHz
50 60 * 432 MHz pre-postdivide
51 /* AUX_PLL_FRAC */ 61 */
52 cx25840_write4(client, 0x110, 0x01bb39ee); 62
53 } 63 /*
64 * AUX_PLL Fraction = 0x1bb39ee
65 * 28636363 * 0x6.dd9cf70/0x10 = 32000 * 384
66 * 196.6 MHz pre-postdivide
67 * FIXME < 200 MHz is out of specified valid range
68 * FIXME 28636363 ref_freq doesn't match VID PLL ref
69 */
70 cx25840_write4(client, 0x110, 0x01bb39ee);
71
72 /*
73 * SA_MCLK_SEL = 1
74 * SA_MCLK_DIV = 0x10 = 384/384 * AUX_PLL post dvivider
75 */
76 cx25840_write(client, 0x127, 0x50);
54 77
55 if (is_cx2583x(state)) 78 if (is_cx2583x(state))
56 break; 79 break;
57 80
58 /* src3/4/6_ctl = 0x0801f77f */ 81 /* src3/4/6_ctl */
82 /* 0x1.f77f = (4 * 28636360/8 * 2/455) / 32000 */
59 cx25840_write4(client, 0x900, 0x0801f77f); 83 cx25840_write4(client, 0x900, 0x0801f77f);
60 cx25840_write4(client, 0x904, 0x0801f77f); 84 cx25840_write4(client, 0x904, 0x0801f77f);
61 cx25840_write4(client, 0x90c, 0x0801f77f); 85 cx25840_write4(client, 0x90c, 0x0801f77f);
62 break; 86 break;
63 87
64 case 44100: 88 case 44100:
65 if (is_cx2388x(state)) { 89 /*
66 /* We don't have register values 90 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
67 * so avoid destroying registers. */ 91 * AUX_PLL Integer = 0x09, AUX PLL Post Divider = 0x10
68 break; 92 */
69 } 93 cx25840_write4(client, 0x108, 0x1009040f);
70 94
71 if (!is_cx231xx(state)) { 95 /*
72 /* VID_PLL and AUX_PLL */ 96 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
73 cx25840_write4(client, 0x108, 0x1009040f); 97 * 28636360 * 0xf.15f17f0/4 = 108 MHz
74 98 * 432 MHz pre-postdivide
75 /* AUX_PLL_FRAC */ 99 */
76 cx25840_write4(client, 0x110, 0x00ec6bd6); 100
77 } 101 /*
102 * AUX_PLL Fraction = 0x0ec6bd6
103 * 28636363 * 0x9.7635eb0/0x10 = 44100 * 384
104 * 271 MHz pre-postdivide
105 * FIXME 28636363 ref_freq doesn't match VID PLL ref
106 */
107 cx25840_write4(client, 0x110, 0x00ec6bd6);
108
109 /*
110 * SA_MCLK_SEL = 1
111 * SA_MCLK_DIV = 0x10 = 384/384 * AUX_PLL post dvivider
112 */
113 cx25840_write(client, 0x127, 0x50);
78 114
79 if (is_cx2583x(state)) 115 if (is_cx2583x(state))
80 break; 116 break;
81 117
82 /* src3/4/6_ctl = 0x08016d59 */ 118 /* src3/4/6_ctl */
119 /* 0x1.6d59 = (4 * 28636360/8 * 2/455) / 44100 */
83 cx25840_write4(client, 0x900, 0x08016d59); 120 cx25840_write4(client, 0x900, 0x08016d59);
84 cx25840_write4(client, 0x904, 0x08016d59); 121 cx25840_write4(client, 0x904, 0x08016d59);
85 cx25840_write4(client, 0x90c, 0x08016d59); 122 cx25840_write4(client, 0x90c, 0x08016d59);
86 break; 123 break;
87 124
88 case 48000: 125 case 48000:
89 if (is_cx2388x(state)) { 126 /*
90 /* We don't have register values 127 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
91 * so avoid destroying registers. */ 128 * AUX_PLL Integer = 0x0a, AUX PLL Post Divider = 0x10
92 break; 129 */
93 } 130 cx25840_write4(client, 0x108, 0x100a040f);
94 131
95 if (!is_cx231xx(state)) { 132 /*
96 /* VID_PLL and AUX_PLL */ 133 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
97 cx25840_write4(client, 0x108, 0x100a040f); 134 * 28636360 * 0xf.15f17f0/4 = 108 MHz
98 135 * 432 MHz pre-postdivide
99 /* AUX_PLL_FRAC */ 136 */
100 cx25840_write4(client, 0x110, 0x0098d6e5); 137
101 } 138 /*
139 * AUX_PLL Fraction = 0x098d6e5
140 * 28636363 * 0xa.4c6b728/0x10 = 48000 * 384
141 * 295 MHz pre-postdivide
142 * FIXME 28636363 ref_freq doesn't match VID PLL ref
143 */
144 cx25840_write4(client, 0x110, 0x0098d6e5);
145
146 /*
147 * SA_MCLK_SEL = 1
148 * SA_MCLK_DIV = 0x10 = 384/384 * AUX_PLL post dvivider
149 */
150 cx25840_write(client, 0x127, 0x50);
102 151
103 if (is_cx2583x(state)) 152 if (is_cx2583x(state))
104 break; 153 break;
105 154
106 /* src3/4/6_ctl = 0x08014faa */ 155 /* src3/4/6_ctl */
156 /* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */
107 cx25840_write4(client, 0x900, 0x08014faa); 157 cx25840_write4(client, 0x900, 0x08014faa);
108 cx25840_write4(client, 0x904, 0x08014faa); 158 cx25840_write4(client, 0x904, 0x08014faa);
109 cx25840_write4(client, 0x90c, 0x08014faa); 159 cx25840_write4(client, 0x90c, 0x08014faa);
@@ -112,91 +162,173 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
112 } else { 162 } else {
113 switch (freq) { 163 switch (freq) {
114 case 32000: 164 case 32000:
115 if (is_cx2388x(state)) { 165 /*
116 /* We don't have register values 166 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
117 * so avoid destroying registers. */ 167 * AUX_PLL Integer = 0x08, AUX PLL Post Divider = 0x1e
118 break; 168 */
119 } 169 cx25840_write4(client, 0x108, 0x1e08040f);
120 170
121 if (!is_cx231xx(state)) { 171 /*
122 /* VID_PLL and AUX_PLL */ 172 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
123 cx25840_write4(client, 0x108, 0x1e08040f); 173 * 28636360 * 0xf.15f17f0/4 = 108 MHz
124 174 * 432 MHz pre-postdivide
125 /* AUX_PLL_FRAC */ 175 */
126 cx25840_write4(client, 0x110, 0x012a0869); 176
127 } 177 /*
178 * AUX_PLL Fraction = 0x12a0869
179 * 28636363 * 0x8.9504348/0x1e = 32000 * 256
180 * 246 MHz pre-postdivide
181 * FIXME 28636363 ref_freq doesn't match VID PLL ref
182 */
183 cx25840_write4(client, 0x110, 0x012a0869);
184
185 /*
186 * SA_MCLK_SEL = 1
187 * SA_MCLK_DIV = 0x14 = 256/384 * AUX_PLL post dvivider
188 */
189 cx25840_write(client, 0x127, 0x54);
128 190
129 if (is_cx2583x(state)) 191 if (is_cx2583x(state))
130 break; 192 break;
131 193
132 /* src1_ctl = 0x08010000 */ 194 /* src1_ctl */
195 /* 0x1.0000 = 32000/32000 */
133 cx25840_write4(client, 0x8f8, 0x08010000); 196 cx25840_write4(client, 0x8f8, 0x08010000);
134 197
135 /* src3/4/6_ctl = 0x08020000 */ 198 /* src3/4/6_ctl */
199 /* 0x2.0000 = 2 * (32000/32000) */
136 cx25840_write4(client, 0x900, 0x08020000); 200 cx25840_write4(client, 0x900, 0x08020000);
137 cx25840_write4(client, 0x904, 0x08020000); 201 cx25840_write4(client, 0x904, 0x08020000);
138 cx25840_write4(client, 0x90c, 0x08020000); 202 cx25840_write4(client, 0x90c, 0x08020000);
139
140 /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */
141 cx25840_write(client, 0x127, 0x54);
142 break; 203 break;
143 204
144 case 44100: 205 case 44100:
145 if (is_cx2388x(state)) { 206 /*
146 /* We don't have register values 207 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
147 * so avoid destroying registers. */ 208 * AUX_PLL Integer = 0x09, AUX PLL Post Divider = 0x18
148 break; 209 */
149 } 210 cx25840_write4(client, 0x108, 0x1809040f);
150 211
151 212 /*
152 if (!is_cx231xx(state)) { 213 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
153 /* VID_PLL and AUX_PLL */ 214 * 28636360 * 0xf.15f17f0/4 = 108 MHz
154 cx25840_write4(client, 0x108, 0x1809040f); 215 * 432 MHz pre-postdivide
155 216 */
156 /* AUX_PLL_FRAC */ 217
157 cx25840_write4(client, 0x110, 0x00ec6bd6); 218 /*
158 } 219 * AUX_PLL Fraction = 0x0ec6bd6
220 * 28636363 * 0x9.7635eb0/0x18 = 44100 * 256
221 * 271 MHz pre-postdivide
222 * FIXME 28636363 ref_freq doesn't match VID PLL ref
223 */
224 cx25840_write4(client, 0x110, 0x00ec6bd6);
225
226 /*
227 * SA_MCLK_SEL = 1
228 * SA_MCLK_DIV = 0x10 = 256/384 * AUX_PLL post dvivider
229 */
230 cx25840_write(client, 0x127, 0x50);
159 231
160 if (is_cx2583x(state)) 232 if (is_cx2583x(state))
161 break; 233 break;
162 234
163 /* src1_ctl = 0x08010000 */ 235 /* src1_ctl */
236 /* 0x1.60cd = 44100/32000 */
164 cx25840_write4(client, 0x8f8, 0x080160cd); 237 cx25840_write4(client, 0x8f8, 0x080160cd);
165 238
166 /* src3/4/6_ctl = 0x08020000 */ 239 /* src3/4/6_ctl */
240 /* 0x1.7385 = 2 * (32000/44100) */
167 cx25840_write4(client, 0x900, 0x08017385); 241 cx25840_write4(client, 0x900, 0x08017385);
168 cx25840_write4(client, 0x904, 0x08017385); 242 cx25840_write4(client, 0x904, 0x08017385);
169 cx25840_write4(client, 0x90c, 0x08017385); 243 cx25840_write4(client, 0x90c, 0x08017385);
170 break; 244 break;
171 245
172 case 48000: 246 case 48000:
173 if (!is_cx2388x(state) && !is_cx231xx(state)) { 247 /*
174 /* VID_PLL and AUX_PLL */ 248 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
175 cx25840_write4(client, 0x108, 0x180a040f); 249 * AUX_PLL Integer = 0x0a, AUX PLL Post Divider = 0x18
176 250 */
177 /* AUX_PLL_FRAC */ 251 cx25840_write4(client, 0x108, 0x180a040f);
178 cx25840_write4(client, 0x110, 0x0098d6e5); 252
179 } 253 /*
254 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
255 * 28636360 * 0xf.15f17f0/4 = 108 MHz
256 * 432 MHz pre-postdivide
257 */
258
259 /*
260 * AUX_PLL Fraction = 0x098d6e5
261 * 28636363 * 0xa.4c6b728/0x18 = 48000 * 256
262 * 295 MHz pre-postdivide
263 * FIXME 28636363 ref_freq doesn't match VID PLL ref
264 */
265 cx25840_write4(client, 0x110, 0x0098d6e5);
266
267 /*
268 * SA_MCLK_SEL = 1
269 * SA_MCLK_DIV = 0x10 = 256/384 * AUX_PLL post dvivider
270 */
271 cx25840_write(client, 0x127, 0x50);
180 272
181 if (is_cx2583x(state)) 273 if (is_cx2583x(state))
182 break; 274 break;
183 275
184 if (!is_cx2388x(state) && !is_cx231xx(state)) { 276 /* src1_ctl */
185 /* src1_ctl */ 277 /* 0x1.8000 = 48000/32000 */
186 cx25840_write4(client, 0x8f8, 0x08018000); 278 cx25840_write4(client, 0x8f8, 0x08018000);
187 279
188 /* src3/4/6_ctl */ 280 /* src3/4/6_ctl */
189 cx25840_write4(client, 0x900, 0x08015555); 281 /* 0x1.5555 = 2 * (32000/48000) */
190 cx25840_write4(client, 0x904, 0x08015555); 282 cx25840_write4(client, 0x900, 0x08015555);
191 cx25840_write4(client, 0x90c, 0x08015555); 283 cx25840_write4(client, 0x904, 0x08015555);
192 } else { 284 cx25840_write4(client, 0x90c, 0x08015555);
285 break;
286 }
287 }
288
289 state->audclk_freq = freq;
290
291 return 0;
292}
293
294static inline int cx25836_set_audclk_freq(struct i2c_client *client, u32 freq)
295{
296 return cx25840_set_audclk_freq(client, freq);
297}
298
299static int cx23885_set_audclk_freq(struct i2c_client *client, u32 freq)
300{
301 struct cx25840_state *state = to_state(i2c_get_clientdata(client));
302
303 if (state->aud_input != CX25840_AUDIO_SERIAL) {
304 switch (freq) {
305 case 32000:
306 case 44100:
307 case 48000:
308 /* We don't have register values
309 * so avoid destroying registers. */
310 /* FIXME return -EINVAL; */
311 break;
312 }
313 } else {
314 switch (freq) {
315 case 32000:
316 case 44100:
317 /* We don't have register values
318 * so avoid destroying registers. */
319 /* FIXME return -EINVAL; */
320 break;
193 321
194 cx25840_write4(client, 0x8f8, 0x0801867c); 322 case 48000:
323 /* src1_ctl */
324 /* 0x1.867c = 48000 / (2 * 28636360/8 * 2/455) */
325 cx25840_write4(client, 0x8f8, 0x0801867c);
195 326
196 cx25840_write4(client, 0x900, 0x08014faa); 327 /* src3/4/6_ctl */
197 cx25840_write4(client, 0x904, 0x08014faa); 328 /* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */
198 cx25840_write4(client, 0x90c, 0x08014faa); 329 cx25840_write4(client, 0x900, 0x08014faa);
199 } 330 cx25840_write4(client, 0x904, 0x08014faa);
331 cx25840_write4(client, 0x90c, 0x08014faa);
200 break; 332 break;
201 } 333 }
202 } 334 }
@@ -206,6 +338,101 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
206 return 0; 338 return 0;
207} 339}
208 340
341static int cx231xx_set_audclk_freq(struct i2c_client *client, u32 freq)
342{
343 struct cx25840_state *state = to_state(i2c_get_clientdata(client));
344
345 if (state->aud_input != CX25840_AUDIO_SERIAL) {
346 switch (freq) {
347 case 32000:
348 /* src3/4/6_ctl */
349 /* 0x1.f77f = (4 * 28636360/8 * 2/455) / 32000 */
350 cx25840_write4(client, 0x900, 0x0801f77f);
351 cx25840_write4(client, 0x904, 0x0801f77f);
352 cx25840_write4(client, 0x90c, 0x0801f77f);
353 break;
354
355 case 44100:
356 /* src3/4/6_ctl */
357 /* 0x1.6d59 = (4 * 28636360/8 * 2/455) / 44100 */
358 cx25840_write4(client, 0x900, 0x08016d59);
359 cx25840_write4(client, 0x904, 0x08016d59);
360 cx25840_write4(client, 0x90c, 0x08016d59);
361 break;
362
363 case 48000:
364 /* src3/4/6_ctl */
365 /* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */
366 cx25840_write4(client, 0x900, 0x08014faa);
367 cx25840_write4(client, 0x904, 0x08014faa);
368 cx25840_write4(client, 0x90c, 0x08014faa);
369 break;
370 }
371 } else {
372 switch (freq) {
373 /* FIXME These cases make different assumptions about audclk */
374 case 32000:
375 /* src1_ctl */
376 /* 0x1.0000 = 32000/32000 */
377 cx25840_write4(client, 0x8f8, 0x08010000);
378
379 /* src3/4/6_ctl */
380 /* 0x2.0000 = 2 * (32000/32000) */
381 cx25840_write4(client, 0x900, 0x08020000);
382 cx25840_write4(client, 0x904, 0x08020000);
383 cx25840_write4(client, 0x90c, 0x08020000);
384 break;
385
386 case 44100:
387 /* src1_ctl */
388 /* 0x1.60cd = 44100/32000 */
389 cx25840_write4(client, 0x8f8, 0x080160cd);
390
391 /* src3/4/6_ctl */
392 /* 0x1.7385 = 2 * (32000/44100) */
393 cx25840_write4(client, 0x900, 0x08017385);
394 cx25840_write4(client, 0x904, 0x08017385);
395 cx25840_write4(client, 0x90c, 0x08017385);
396 break;
397
398 case 48000:
399 /* src1_ctl */
400 /* 0x1.867c = 48000 / (2 * 28636360/8 * 2/455) */
401 cx25840_write4(client, 0x8f8, 0x0801867c);
402
403 /* src3/4/6_ctl */
404 /* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */
405 cx25840_write4(client, 0x900, 0x08014faa);
406 cx25840_write4(client, 0x904, 0x08014faa);
407 cx25840_write4(client, 0x90c, 0x08014faa);
408 break;
409 }
410 }
411
412 state->audclk_freq = freq;
413
414 return 0;
415}
416
417static int set_audclk_freq(struct i2c_client *client, u32 freq)
418{
419 struct cx25840_state *state = to_state(i2c_get_clientdata(client));
420
421 if (freq != 32000 && freq != 44100 && freq != 48000)
422 return -EINVAL;
423
424 if (is_cx231xx(state))
425 return cx231xx_set_audclk_freq(client, freq);
426
427 if (is_cx2388x(state))
428 return cx23885_set_audclk_freq(client, freq);
429
430 if (is_cx2583x(state))
431 return cx25836_set_audclk_freq(client, freq);
432
433 return cx25840_set_audclk_freq(client, freq);
434}
435
209void cx25840_audio_set_path(struct i2c_client *client) 436void cx25840_audio_set_path(struct i2c_client *client)
210{ 437{
211 struct cx25840_state *state = to_state(i2c_get_clientdata(client)); 438 struct cx25840_state *state = to_state(i2c_get_clientdata(client));