diff options
author | Vadim Catana <skystar@moldova.cc> | 2006-04-13 09:19:52 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2006-05-12 18:55:02 -0400 |
commit | a74b51fca9d9b6774413d700ade1e9ae1f0c0e75 (patch) | |
tree | ac02ba7f67f5b51805a4a0dda1d09701c1e3aab8 /drivers | |
parent | 3a63fc4bfd8579bda1f6a03b3fcb792f59cb15f8 (diff) |
V4L/DVB (3795): Fix for CX24123 & low symbol rates
- fixed the reception of channels with low symbol rates.
( The VGA1 and VGA2 offsets recommended by cx24109 docs for
symbol rates from 1 to 5 MSps do not work. I changed them
to values found experimentally. The charge pump current
and FILTUNE voltage are now set to values recommended in
the docs. This improves reception for symbol rates < 15 MSps.
The values written in the SYSSymbolRate registers are calculated
with better precision. )
- fixed the cx24123_get_fec() function. It was returning the values
for DCII mode.
- removed some unused variables
Signed-off-by: Vadim Catana <skystar at moldova.cc>
Signed-off-by: Andrew de Quincey <adq_dvb@lidskialf.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/dvb/frontends/cx24123.c | 262 |
1 files changed, 181 insertions, 81 deletions
diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c index d661c6f9cbe5..e430e6a50831 100644 --- a/drivers/media/dvb/frontends/cx24123.c +++ b/drivers/media/dvb/frontends/cx24123.c | |||
@@ -29,6 +29,8 @@ | |||
29 | #include "dvb_frontend.h" | 29 | #include "dvb_frontend.h" |
30 | #include "cx24123.h" | 30 | #include "cx24123.h" |
31 | 31 | ||
32 | #define XTAL 10111000 | ||
33 | |||
32 | static int debug; | 34 | static int debug; |
33 | #define dprintk(args...) \ | 35 | #define dprintk(args...) \ |
34 | do { \ | 36 | do { \ |
@@ -52,6 +54,7 @@ struct cx24123_state | |||
52 | u32 VGAarg; | 54 | u32 VGAarg; |
53 | u32 bandselectarg; | 55 | u32 bandselectarg; |
54 | u32 pllarg; | 56 | u32 pllarg; |
57 | u32 FILTune; | ||
55 | 58 | ||
56 | /* The Demod/Tuner can't easily provide these, we cache them */ | 59 | /* The Demod/Tuner can't easily provide these, we cache them */ |
57 | u32 currentfreq; | 60 | u32 currentfreq; |
@@ -63,43 +66,33 @@ static struct | |||
63 | { | 66 | { |
64 | u32 symbolrate_low; | 67 | u32 symbolrate_low; |
65 | u32 symbolrate_high; | 68 | u32 symbolrate_high; |
66 | u32 VCAslope; | ||
67 | u32 VCAoffset; | ||
68 | u32 VGA1offset; | ||
69 | u32 VGA2offset; | ||
70 | u32 VCAprogdata; | 69 | u32 VCAprogdata; |
71 | u32 VGAprogdata; | 70 | u32 VGAprogdata; |
71 | u32 FILTune; | ||
72 | } cx24123_AGC_vals[] = | 72 | } cx24123_AGC_vals[] = |
73 | { | 73 | { |
74 | { | 74 | { |
75 | .symbolrate_low = 1000000, | 75 | .symbolrate_low = 1000000, |
76 | .symbolrate_high = 4999999, | 76 | .symbolrate_high = 4999999, |
77 | .VCAslope = 0x07, | 77 | /* the specs recommend other values for VGA offsets, |
78 | .VCAoffset = 0x0f, | 78 | but tests show they are wrong */ |
79 | .VGA1offset = 0x1f8, | 79 | .VGAprogdata = (2 << 18) | (0x180 << 9) | 0x1e0, |
80 | .VGA2offset = 0x1f8, | ||
81 | .VGAprogdata = (2 << 18) | (0x1f8 << 9) | 0x1f8, | ||
82 | .VCAprogdata = (4 << 18) | (0x07 << 9) | 0x07, | 80 | .VCAprogdata = (4 << 18) | (0x07 << 9) | 0x07, |
81 | .FILTune = 0x280 /* 0.41 V */ | ||
83 | }, | 82 | }, |
84 | { | 83 | { |
85 | .symbolrate_low = 5000000, | 84 | .symbolrate_low = 5000000, |
86 | .symbolrate_high = 14999999, | 85 | .symbolrate_high = 14999999, |
87 | .VCAslope = 0x1f, | ||
88 | .VCAoffset = 0x1f, | ||
89 | .VGA1offset = 0x1e0, | ||
90 | .VGA2offset = 0x180, | ||
91 | .VGAprogdata = (2 << 18) | (0x180 << 9) | 0x1e0, | 86 | .VGAprogdata = (2 << 18) | (0x180 << 9) | 0x1e0, |
92 | .VCAprogdata = (4 << 18) | (0x07 << 9) | 0x1f, | 87 | .VCAprogdata = (4 << 18) | (0x07 << 9) | 0x1f, |
88 | .FILTune = 0x317 /* 0.90 V */ | ||
93 | }, | 89 | }, |
94 | { | 90 | { |
95 | .symbolrate_low = 15000000, | 91 | .symbolrate_low = 15000000, |
96 | .symbolrate_high = 45000000, | 92 | .symbolrate_high = 45000000, |
97 | .VCAslope = 0x3f, | ||
98 | .VCAoffset = 0x3f, | ||
99 | .VGA1offset = 0x180, | ||
100 | .VGA2offset = 0x100, | ||
101 | .VGAprogdata = (2 << 18) | (0x100 << 9) | 0x180, | 93 | .VGAprogdata = (2 << 18) | (0x100 << 9) | 0x180, |
102 | .VCAprogdata = (4 << 18) | (0x07 << 9) | 0x3f, | 94 | .VCAprogdata = (4 << 18) | (0x07 << 9) | 0x3f, |
95 | .FILTune = 0x146 /* 2.70 V */ | ||
103 | }, | 96 | }, |
104 | }; | 97 | }; |
105 | 98 | ||
@@ -112,90 +105,68 @@ static struct | |||
112 | { | 105 | { |
113 | u32 freq_low; | 106 | u32 freq_low; |
114 | u32 freq_high; | 107 | u32 freq_high; |
115 | u32 bandselect; | ||
116 | u32 VCOdivider; | 108 | u32 VCOdivider; |
117 | u32 VCOnumber; | ||
118 | u32 progdata; | 109 | u32 progdata; |
119 | } cx24123_bandselect_vals[] = | 110 | } cx24123_bandselect_vals[] = |
120 | { | 111 | { |
121 | { | 112 | { |
122 | .freq_low = 950000, | 113 | .freq_low = 950000, |
123 | .freq_high = 1018999, | 114 | .freq_high = 1018999, |
124 | .bandselect = 0x40, | ||
125 | .VCOdivider = 4, | 115 | .VCOdivider = 4, |
126 | .VCOnumber = 7, | ||
127 | .progdata = (0 << 18) | (0 << 9) | 0x40, | 116 | .progdata = (0 << 18) | (0 << 9) | 0x40, |
128 | }, | 117 | }, |
129 | { | 118 | { |
130 | .freq_low = 1019000, | 119 | .freq_low = 1019000, |
131 | .freq_high = 1074999, | 120 | .freq_high = 1074999, |
132 | .bandselect = 0x80, | ||
133 | .VCOdivider = 4, | 121 | .VCOdivider = 4, |
134 | .VCOnumber = 8, | ||
135 | .progdata = (0 << 18) | (0 << 9) | 0x80, | 122 | .progdata = (0 << 18) | (0 << 9) | 0x80, |
136 | }, | 123 | }, |
137 | { | 124 | { |
138 | .freq_low = 1075000, | 125 | .freq_low = 1075000, |
139 | .freq_high = 1227999, | 126 | .freq_high = 1227999, |
140 | .bandselect = 0x01, | ||
141 | .VCOdivider = 2, | 127 | .VCOdivider = 2, |
142 | .VCOnumber = 1, | ||
143 | .progdata = (0 << 18) | (1 << 9) | 0x01, | 128 | .progdata = (0 << 18) | (1 << 9) | 0x01, |
144 | }, | 129 | }, |
145 | { | 130 | { |
146 | .freq_low = 1228000, | 131 | .freq_low = 1228000, |
147 | .freq_high = 1349999, | 132 | .freq_high = 1349999, |
148 | .bandselect = 0x02, | ||
149 | .VCOdivider = 2, | 133 | .VCOdivider = 2, |
150 | .VCOnumber = 2, | ||
151 | .progdata = (0 << 18) | (1 << 9) | 0x02, | 134 | .progdata = (0 << 18) | (1 << 9) | 0x02, |
152 | }, | 135 | }, |
153 | { | 136 | { |
154 | .freq_low = 1350000, | 137 | .freq_low = 1350000, |
155 | .freq_high = 1481999, | 138 | .freq_high = 1481999, |
156 | .bandselect = 0x04, | ||
157 | .VCOdivider = 2, | 139 | .VCOdivider = 2, |
158 | .VCOnumber = 3, | ||
159 | .progdata = (0 << 18) | (1 << 9) | 0x04, | 140 | .progdata = (0 << 18) | (1 << 9) | 0x04, |
160 | }, | 141 | }, |
161 | { | 142 | { |
162 | .freq_low = 1482000, | 143 | .freq_low = 1482000, |
163 | .freq_high = 1595999, | 144 | .freq_high = 1595999, |
164 | .bandselect = 0x08, | ||
165 | .VCOdivider = 2, | 145 | .VCOdivider = 2, |
166 | .VCOnumber = 4, | ||
167 | .progdata = (0 << 18) | (1 << 9) | 0x08, | 146 | .progdata = (0 << 18) | (1 << 9) | 0x08, |
168 | }, | 147 | }, |
169 | { | 148 | { |
170 | .freq_low = 1596000, | 149 | .freq_low = 1596000, |
171 | .freq_high = 1717999, | 150 | .freq_high = 1717999, |
172 | .bandselect = 0x10, | ||
173 | .VCOdivider = 2, | 151 | .VCOdivider = 2, |
174 | .VCOnumber = 5, | ||
175 | .progdata = (0 << 18) | (1 << 9) | 0x10, | 152 | .progdata = (0 << 18) | (1 << 9) | 0x10, |
176 | }, | 153 | }, |
177 | { | 154 | { |
178 | .freq_low = 1718000, | 155 | .freq_low = 1718000, |
179 | .freq_high = 1855999, | 156 | .freq_high = 1855999, |
180 | .bandselect = 0x20, | ||
181 | .VCOdivider = 2, | 157 | .VCOdivider = 2, |
182 | .VCOnumber = 6, | ||
183 | .progdata = (0 << 18) | (1 << 9) | 0x20, | 158 | .progdata = (0 << 18) | (1 << 9) | 0x20, |
184 | }, | 159 | }, |
185 | { | 160 | { |
186 | .freq_low = 1856000, | 161 | .freq_low = 1856000, |
187 | .freq_high = 2035999, | 162 | .freq_high = 2035999, |
188 | .bandselect = 0x40, | ||
189 | .VCOdivider = 2, | 163 | .VCOdivider = 2, |
190 | .VCOnumber = 7, | ||
191 | .progdata = (0 << 18) | (1 << 9) | 0x40, | 164 | .progdata = (0 << 18) | (1 << 9) | 0x40, |
192 | }, | 165 | }, |
193 | { | 166 | { |
194 | .freq_low = 2036000, | 167 | .freq_low = 2036000, |
195 | .freq_high = 2149999, | 168 | .freq_high = 2149999, |
196 | .bandselect = 0x80, | ||
197 | .VCOdivider = 2, | 169 | .VCOdivider = 2, |
198 | .VCOnumber = 8, | ||
199 | .progdata = (0 << 18) | (1 << 9) | 0x80, | 170 | .progdata = (0 << 18) | (1 << 9) | 0x80, |
200 | }, | 171 | }, |
201 | }; | 172 | }; |
@@ -207,7 +178,6 @@ static struct { | |||
207 | { | 178 | { |
208 | {0x00, 0x03}, /* Reset system */ | 179 | {0x00, 0x03}, /* Reset system */ |
209 | {0x00, 0x00}, /* Clear reset */ | 180 | {0x00, 0x00}, /* Clear reset */ |
210 | {0x01, 0x3b}, /* Apply sensible defaults, from an i2c sniffer */ | ||
211 | {0x03, 0x07}, | 181 | {0x03, 0x07}, |
212 | {0x04, 0x10}, | 182 | {0x04, 0x10}, |
213 | {0x05, 0x04}, | 183 | {0x05, 0x04}, |
@@ -217,7 +187,6 @@ static struct { | |||
217 | {0x0f, 0xfe}, | 187 | {0x0f, 0xfe}, |
218 | {0x10, 0x01}, | 188 | {0x10, 0x01}, |
219 | {0x14, 0x01}, | 189 | {0x14, 0x01}, |
220 | {0x15, 0x98}, | ||
221 | {0x16, 0x00}, | 190 | {0x16, 0x00}, |
222 | {0x17, 0x01}, | 191 | {0x17, 0x01}, |
223 | {0x1b, 0x05}, | 192 | {0x1b, 0x05}, |
@@ -226,8 +195,6 @@ static struct { | |||
226 | {0x1e, 0x00}, | 195 | {0x1e, 0x00}, |
227 | {0x20, 0x41}, | 196 | {0x20, 0x41}, |
228 | {0x21, 0x15}, | 197 | {0x21, 0x15}, |
229 | {0x27, 0x14}, | ||
230 | {0x28, 0x46}, | ||
231 | {0x29, 0x00}, | 198 | {0x29, 0x00}, |
232 | {0x2a, 0xb0}, | 199 | {0x2a, 0xb0}, |
233 | {0x2b, 0x73}, | 200 | {0x2b, 0x73}, |
@@ -375,55 +342,103 @@ static int cx24123_set_fec(struct cx24123_state* state, fe_code_rate_t fec) | |||
375 | static int cx24123_get_fec(struct cx24123_state* state, fe_code_rate_t *fec) | 342 | static int cx24123_get_fec(struct cx24123_state* state, fe_code_rate_t *fec) |
376 | { | 343 | { |
377 | int ret; | 344 | int ret; |
378 | u8 val; | ||
379 | 345 | ||
380 | ret = cx24123_readreg (state, 0x1b); | 346 | ret = cx24123_readreg (state, 0x1b); |
381 | if (ret < 0) | 347 | if (ret < 0) |
382 | return ret; | 348 | return ret; |
383 | val = ret & 0x07; | 349 | ret = ret & 0x07; |
384 | switch (val) { | 350 | |
351 | switch (ret) { | ||
385 | case 1: | 352 | case 1: |
386 | *fec = FEC_1_2; | 353 | *fec = FEC_1_2; |
387 | break; | 354 | break; |
388 | case 3: | 355 | case 2: |
389 | *fec = FEC_2_3; | 356 | *fec = FEC_2_3; |
390 | break; | 357 | break; |
391 | case 4: | 358 | case 3: |
392 | *fec = FEC_3_4; | 359 | *fec = FEC_3_4; |
393 | break; | 360 | break; |
394 | case 5: | 361 | case 4: |
395 | *fec = FEC_4_5; | 362 | *fec = FEC_4_5; |
396 | break; | 363 | break; |
397 | case 6: | 364 | case 5: |
398 | *fec = FEC_5_6; | 365 | *fec = FEC_5_6; |
399 | break; | 366 | break; |
367 | case 6: | ||
368 | *fec = FEC_6_7; | ||
369 | break; | ||
400 | case 7: | 370 | case 7: |
401 | *fec = FEC_7_8; | 371 | *fec = FEC_7_8; |
402 | break; | 372 | break; |
403 | case 2: /* *fec = FEC_3_5; break; */ | ||
404 | case 0: /* *fec = FEC_5_11; break; */ | ||
405 | *fec = FEC_AUTO; | ||
406 | break; | ||
407 | default: | 373 | default: |
408 | *fec = FEC_NONE; // can't happen | 374 | *fec = FEC_NONE; // can't happen |
375 | printk("FEC_NONE ?\n"); | ||
409 | } | 376 | } |
410 | 377 | ||
411 | return 0; | 378 | return 0; |
412 | } | 379 | } |
413 | 380 | ||
414 | /* fixme: Symbol rates < 3MSps may not work because of precision loss */ | ||
415 | static int cx24123_set_symbolrate(struct cx24123_state* state, u32 srate) | 381 | static int cx24123_set_symbolrate(struct cx24123_state* state, u32 srate) |
416 | { | 382 | { |
417 | u32 val; | 383 | u32 tmp, sample_rate, ratio; |
384 | u8 pll_mult; | ||
385 | |||
386 | /* check if symbol rate is within limits */ | ||
387 | if ((srate > state->ops.info.symbol_rate_max) || | ||
388 | (srate < state->ops.info.symbol_rate_min)) | ||
389 | return -EOPNOTSUPP;; | ||
390 | |||
391 | /* choose the sampling rate high enough for the required operation, | ||
392 | while optimizing the power consumed by the demodulator */ | ||
393 | if (srate < (XTAL*2)/2) | ||
394 | pll_mult = 2; | ||
395 | else if (srate < (XTAL*3)/2) | ||
396 | pll_mult = 3; | ||
397 | else if (srate < (XTAL*4)/2) | ||
398 | pll_mult = 4; | ||
399 | else if (srate < (XTAL*5)/2) | ||
400 | pll_mult = 5; | ||
401 | else if (srate < (XTAL*6)/2) | ||
402 | pll_mult = 6; | ||
403 | else if (srate < (XTAL*7)/2) | ||
404 | pll_mult = 7; | ||
405 | else if (srate < (XTAL*8)/2) | ||
406 | pll_mult = 8; | ||
407 | else | ||
408 | pll_mult = 9; | ||
409 | |||
410 | |||
411 | sample_rate = pll_mult * XTAL; | ||
418 | 412 | ||
419 | val = (srate / 1185) * 100; | 413 | /* |
414 | SYSSymbolRate[21:0] = (srate << 23) / sample_rate | ||
420 | 415 | ||
421 | /* Compensate for scaling up, by removing 17 symbols per 1Msps */ | 416 | We have to use 32 bit unsigned arithmetic without precision loss. |
422 | val = val - (17 * (srate / 1000000)); | 417 | The maximum srate is 45000000 or 0x02AEA540. This number has |
418 | only 6 clear bits on top, hence we can shift it left only 6 bits | ||
419 | at a time. Borrowed from cx24110.c | ||
420 | */ | ||
423 | 421 | ||
424 | cx24123_writereg(state, 0x08, (val >> 16) & 0xff ); | 422 | tmp = srate << 6; |
425 | cx24123_writereg(state, 0x09, (val >> 8) & 0xff ); | 423 | ratio = tmp / sample_rate; |
426 | cx24123_writereg(state, 0x0a, (val ) & 0xff ); | 424 | |
425 | tmp = (tmp % sample_rate) << 6; | ||
426 | ratio = (ratio << 6) + (tmp / sample_rate); | ||
427 | |||
428 | tmp = (tmp % sample_rate) << 6; | ||
429 | ratio = (ratio << 6) + (tmp / sample_rate); | ||
430 | |||
431 | tmp = (tmp % sample_rate) << 5; | ||
432 | ratio = (ratio << 5) + (tmp / sample_rate); | ||
433 | |||
434 | |||
435 | cx24123_writereg(state, 0x01, pll_mult * 6); | ||
436 | |||
437 | cx24123_writereg(state, 0x08, (ratio >> 16) & 0x3f ); | ||
438 | cx24123_writereg(state, 0x09, (ratio >> 8) & 0xff ); | ||
439 | cx24123_writereg(state, 0x0a, (ratio ) & 0xff ); | ||
440 | |||
441 | dprintk("%s: srate=%d, ratio=0x%08x, sample_rate=%i\n", __FUNCTION__, srate, ratio, sample_rate); | ||
427 | 442 | ||
428 | return 0; | 443 | return 0; |
429 | } | 444 | } |
@@ -437,6 +452,7 @@ static int cx24123_pll_calculate(struct dvb_frontend* fe, struct dvb_frontend_pa | |||
437 | struct cx24123_state *state = fe->demodulator_priv; | 452 | struct cx24123_state *state = fe->demodulator_priv; |
438 | u32 ndiv = 0, adiv = 0, vco_div = 0; | 453 | u32 ndiv = 0, adiv = 0, vco_div = 0; |
439 | int i = 0; | 454 | int i = 0; |
455 | int pump = 2; | ||
440 | 456 | ||
441 | /* Defaults for low freq, low rate */ | 457 | /* Defaults for low freq, low rate */ |
442 | state->VCAarg = cx24123_AGC_vals[0].VCAprogdata; | 458 | state->VCAarg = cx24123_AGC_vals[0].VCAprogdata; |
@@ -444,13 +460,14 @@ static int cx24123_pll_calculate(struct dvb_frontend* fe, struct dvb_frontend_pa | |||
444 | state->bandselectarg = cx24123_bandselect_vals[0].progdata; | 460 | state->bandselectarg = cx24123_bandselect_vals[0].progdata; |
445 | vco_div = cx24123_bandselect_vals[0].VCOdivider; | 461 | vco_div = cx24123_bandselect_vals[0].VCOdivider; |
446 | 462 | ||
447 | /* For the given symbolerate, determine the VCA and VGA programming bits */ | 463 | /* For the given symbol rate, determine the VCA, VGA and FILTUNE programming bits */ |
448 | for (i = 0; i < sizeof(cx24123_AGC_vals) / sizeof(cx24123_AGC_vals[0]); i++) | 464 | for (i = 0; i < sizeof(cx24123_AGC_vals) / sizeof(cx24123_AGC_vals[0]); i++) |
449 | { | 465 | { |
450 | if ((cx24123_AGC_vals[i].symbolrate_low <= p->u.qpsk.symbol_rate) && | 466 | if ((cx24123_AGC_vals[i].symbolrate_low <= p->u.qpsk.symbol_rate) && |
451 | (cx24123_AGC_vals[i].symbolrate_high >= p->u.qpsk.symbol_rate) ) { | 467 | (cx24123_AGC_vals[i].symbolrate_high >= p->u.qpsk.symbol_rate) ) { |
452 | state->VCAarg = cx24123_AGC_vals[i].VCAprogdata; | 468 | state->VCAarg = cx24123_AGC_vals[i].VCAprogdata; |
453 | state->VGAarg = cx24123_AGC_vals[i].VGAprogdata; | 469 | state->VGAarg = cx24123_AGC_vals[i].VGAprogdata; |
470 | state->FILTune = cx24123_AGC_vals[i].FILTune; | ||
454 | } | 471 | } |
455 | } | 472 | } |
456 | 473 | ||
@@ -458,24 +475,28 @@ static int cx24123_pll_calculate(struct dvb_frontend* fe, struct dvb_frontend_pa | |||
458 | for (i = 0; i < sizeof(cx24123_bandselect_vals) / sizeof(cx24123_bandselect_vals[0]); i++) | 475 | for (i = 0; i < sizeof(cx24123_bandselect_vals) / sizeof(cx24123_bandselect_vals[0]); i++) |
459 | { | 476 | { |
460 | if ((cx24123_bandselect_vals[i].freq_low <= p->frequency) && | 477 | if ((cx24123_bandselect_vals[i].freq_low <= p->frequency) && |
461 | (cx24123_bandselect_vals[i].freq_high >= p->frequency) ) { | 478 | (cx24123_bandselect_vals[i].freq_high >= p->frequency) ) { |
462 | state->bandselectarg = cx24123_bandselect_vals[i].progdata; | 479 | state->bandselectarg = cx24123_bandselect_vals[i].progdata; |
463 | vco_div = cx24123_bandselect_vals[i].VCOdivider; | 480 | vco_div = cx24123_bandselect_vals[i].VCOdivider; |
481 | |||
482 | /* determine the charge pump current */ | ||
483 | if ( p->frequency < (cx24123_bandselect_vals[i].freq_low + cx24123_bandselect_vals[i].freq_high)/2 ) | ||
484 | pump = 0x01; | ||
485 | else | ||
486 | pump = 0x02; | ||
464 | } | 487 | } |
465 | } | 488 | } |
466 | 489 | ||
467 | /* Determine the N/A dividers for the requested lband freq (in kHz). */ | 490 | /* Determine the N/A dividers for the requested lband freq (in kHz). */ |
468 | /* Note: 10111 (kHz) is the Crystal Freq and divider of 10. */ | 491 | /* Note: the reference divider R=10, frequency is in KHz, XTAL is in Hz */ |
469 | ndiv = ( ((p->frequency * vco_div) / (10111 / 10) / 2) / 32) & 0x1ff; | 492 | ndiv = ( ((p->frequency * vco_div * 10) / (2 * XTAL / 1000)) / 32) & 0x1ff; |
470 | adiv = ( ((p->frequency * vco_div) / (10111 / 10) / 2) % 32) & 0x1f; | 493 | adiv = ( ((p->frequency * vco_div * 10) / (2 * XTAL / 1000)) % 32) & 0x1f; |
471 | 494 | ||
472 | if (adiv == 0) | 495 | if (adiv == 0) |
473 | adiv++; | 496 | ndiv++; |
474 | 497 | ||
475 | /* determine the correct pll frequency values. */ | 498 | /* control bits 11, refdiv 11, charge pump polarity 1, charge pump current, ndiv, adiv */ |
476 | /* Command 11, refdiv 11, cpump polarity 1, cpump current 3mA 10. */ | 499 | state->pllarg = (3 << 19) | (3 << 17) | (1 << 16) | (pump << 14) | (ndiv << 5) | adiv; |
477 | state->pllarg = (3 << 19) | (3 << 17) | (1 << 16) | (2 << 14); | ||
478 | state->pllarg |= (ndiv << 5) | adiv; | ||
479 | 500 | ||
480 | return 0; | 501 | return 0; |
481 | } | 502 | } |
@@ -538,6 +559,9 @@ static int cx24123_pll_writereg(struct dvb_frontend* fe, struct dvb_frontend_par | |||
538 | static int cx24123_pll_tune(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) | 559 | static int cx24123_pll_tune(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) |
539 | { | 560 | { |
540 | struct cx24123_state *state = fe->demodulator_priv; | 561 | struct cx24123_state *state = fe->demodulator_priv; |
562 | u8 val; | ||
563 | |||
564 | dprintk("frequency=%i\n", p->frequency); | ||
541 | 565 | ||
542 | if (cx24123_pll_calculate(fe, p) != 0) { | 566 | if (cx24123_pll_calculate(fe, p) != 0) { |
543 | printk("%s: cx24123_pll_calcutate failed\n",__FUNCTION__); | 567 | printk("%s: cx24123_pll_calcutate failed\n",__FUNCTION__); |
@@ -552,6 +576,11 @@ static int cx24123_pll_tune(struct dvb_frontend* fe, struct dvb_frontend_paramet | |||
552 | cx24123_pll_writereg(fe, p, state->bandselectarg); | 576 | cx24123_pll_writereg(fe, p, state->bandselectarg); |
553 | cx24123_pll_writereg(fe, p, state->pllarg); | 577 | cx24123_pll_writereg(fe, p, state->pllarg); |
554 | 578 | ||
579 | /* set the FILTUNE voltage */ | ||
580 | val = cx24123_readreg(state, 0x28) & ~0x3; | ||
581 | cx24123_writereg(state, 0x27, state->FILTune >> 2); | ||
582 | cx24123_writereg(state, 0x28, val | (state->FILTune & 0x3)); | ||
583 | |||
555 | return 0; | 584 | return 0; |
556 | } | 585 | } |
557 | 586 | ||
@@ -624,13 +653,81 @@ static int cx24123_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage | |||
624 | return 0; | 653 | return 0; |
625 | } | 654 | } |
626 | 655 | ||
627 | static int cx24123_send_diseqc_msg(struct dvb_frontend* fe, | 656 | static int cx24123_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *cmd) |
628 | struct dvb_diseqc_master_cmd *cmd) | ||
629 | { | 657 | { |
630 | /* fixme: Implement diseqc */ | 658 | struct cx24123_state *state = fe->demodulator_priv; |
631 | printk("%s: No support yet\n",__FUNCTION__); | 659 | int i, val; |
660 | unsigned long timeout; | ||
661 | |||
662 | dprintk("%s:\n",__FUNCTION__); | ||
632 | 663 | ||
633 | return -ENOTSUPP; | 664 | /* check if continuous tone has been stoped */ |
665 | if (state->config->use_isl6421) | ||
666 | val = cx24123_readlnbreg(state, 0x00) & 0x10; | ||
667 | else | ||
668 | val = cx24123_readreg(state, 0x29) & 0x10; | ||
669 | |||
670 | |||
671 | if (val) { | ||
672 | printk("%s: ERROR: attempt to send diseqc command before tone is off\n", __FUNCTION__); | ||
673 | return -ENOTSUPP; | ||
674 | } | ||
675 | |||
676 | /* select tone mode */ | ||
677 | cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) & 0xf8); | ||
678 | |||
679 | for (i = 0; i < cmd->msg_len; i++) | ||
680 | cx24123_writereg(state, 0x2C + i, cmd->msg[i]); | ||
681 | |||
682 | val = cx24123_readreg(state, 0x29); | ||
683 | cx24123_writereg(state, 0x29, ((val & 0x90) | 0x40) | ((cmd->msg_len-3) & 3)); | ||
684 | |||
685 | timeout = jiffies + msecs_to_jiffies(100); | ||
686 | while (!time_after(jiffies, timeout) && !(cx24123_readreg(state, 0x29) & 0x40)) | ||
687 | ; // wait for LNB ready | ||
688 | |||
689 | return 0; | ||
690 | } | ||
691 | |||
692 | static int cx24123_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst) | ||
693 | { | ||
694 | struct cx24123_state *state = fe->demodulator_priv; | ||
695 | int val; | ||
696 | unsigned long timeout; | ||
697 | |||
698 | dprintk("%s:\n", __FUNCTION__); | ||
699 | |||
700 | /* check if continuous tone has been stoped */ | ||
701 | if (state->config->use_isl6421) | ||
702 | val = cx24123_readlnbreg(state, 0x00) & 0x10; | ||
703 | else | ||
704 | val = cx24123_readreg(state, 0x29) & 0x10; | ||
705 | |||
706 | |||
707 | if (val) { | ||
708 | printk("%s: ERROR: attempt to send diseqc command before tone is off\n", __FUNCTION__); | ||
709 | return -ENOTSUPP; | ||
710 | } | ||
711 | |||
712 | /* select tone mode */ | ||
713 | val = cx24123_readreg(state, 0x2a) & 0xf8; | ||
714 | cx24123_writereg(state, 0x2a, val | 0x04); | ||
715 | |||
716 | val = cx24123_readreg(state, 0x29); | ||
717 | |||
718 | if (burst == SEC_MINI_A) | ||
719 | cx24123_writereg(state, 0x29, ((val & 0x90) | 0x40 | 0x00)); | ||
720 | else if (burst == SEC_MINI_B) | ||
721 | cx24123_writereg(state, 0x29, ((val & 0x90) | 0x40 | 0x08)); | ||
722 | else | ||
723 | return -EINVAL; | ||
724 | |||
725 | |||
726 | timeout = jiffies + msecs_to_jiffies(100); | ||
727 | while (!time_after(jiffies, timeout) && !(cx24123_readreg(state, 0x29) & 0x40)) | ||
728 | ; // wait for LNB ready | ||
729 | |||
730 | return 0; | ||
634 | } | 731 | } |
635 | 732 | ||
636 | static int cx24123_read_status(struct dvb_frontend* fe, fe_status_t* status) | 733 | static int cx24123_read_status(struct dvb_frontend* fe, fe_status_t* status) |
@@ -642,13 +739,15 @@ static int cx24123_read_status(struct dvb_frontend* fe, fe_status_t* status) | |||
642 | 739 | ||
643 | *status = 0; | 740 | *status = 0; |
644 | if (lock & 0x01) | 741 | if (lock & 0x01) |
645 | *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; | 742 | *status |= FE_HAS_SIGNAL; |
743 | if (sync & 0x02) | ||
744 | *status |= FE_HAS_CARRIER; | ||
646 | if (sync & 0x04) | 745 | if (sync & 0x04) |
647 | *status |= FE_HAS_VITERBI; | 746 | *status |= FE_HAS_VITERBI; |
648 | if (sync & 0x08) | 747 | if (sync & 0x08) |
649 | *status |= FE_HAS_CARRIER; | 748 | *status |= FE_HAS_SYNC; |
650 | if (sync & 0x80) | 749 | if (sync & 0x80) |
651 | *status |= FE_HAS_SYNC | FE_HAS_LOCK; | 750 | *status |= FE_HAS_LOCK; |
652 | 751 | ||
653 | return 0; | 752 | return 0; |
654 | } | 753 | } |
@@ -875,6 +974,7 @@ static struct dvb_frontend_ops cx24123_ops = { | |||
875 | .read_snr = cx24123_read_snr, | 974 | .read_snr = cx24123_read_snr, |
876 | .read_ucblocks = cx24123_read_ucblocks, | 975 | .read_ucblocks = cx24123_read_ucblocks, |
877 | .diseqc_send_master_cmd = cx24123_send_diseqc_msg, | 976 | .diseqc_send_master_cmd = cx24123_send_diseqc_msg, |
977 | .diseqc_send_burst = cx24123_diseqc_send_burst, | ||
878 | .set_tone = cx24123_set_tone, | 978 | .set_tone = cx24123_set_tone, |
879 | .set_voltage = cx24123_set_voltage, | 979 | .set_voltage = cx24123_set_voltage, |
880 | }; | 980 | }; |