diff options
author | Manu Abraham <abraham.manu@gmail.com> | 2010-11-14 13:52:10 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-12-29 05:16:49 -0500 |
commit | f14bfe94e459cb070a489e1786f26d54e9e7b5de (patch) | |
tree | 6b75f51ac0bc91bce48412896b0b943f6edcd0da /drivers | |
parent | 3037fd14302d635426996fb7f6fcf7cb98dc15b9 (diff) |
[media] stb6100: Improve tuner performance
- Reduce the amount of white noise present, which causes the
demodulator a significant time to acquire a frontend lock
on a whole. Frontend shows a large significant improvement in
performance.
Thanks to Peter Nayler for helping to identify the potential
hotspots and fixing them.
Signed-off-by: Manu Abraham <manu@linuxtv.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/dvb/frontends/stb6100.c | 193 |
1 files changed, 127 insertions, 66 deletions
diff --git a/drivers/media/dvb/frontends/stb6100.c b/drivers/media/dvb/frontends/stb6100.c index 80a9e4cba631..db66248fed46 100644 --- a/drivers/media/dvb/frontends/stb6100.c +++ b/drivers/media/dvb/frontends/stb6100.c | |||
@@ -51,7 +51,7 @@ module_param(verbose, int, 0644); | |||
51 | if (x > y) \ | 51 | if (x > y) \ |
52 | printk(format, ##arg); \ | 52 | printk(format, ##arg); \ |
53 | } \ | 53 | } \ |
54 | } while(0) | 54 | } while (0) |
55 | 55 | ||
56 | struct stb6100_lkup { | 56 | struct stb6100_lkup { |
57 | u32 val_low; | 57 | u32 val_low; |
@@ -157,13 +157,25 @@ static int stb6100_read_reg(struct stb6100_state *state, u8 reg) | |||
157 | u8 regs[STB6100_NUMREGS]; | 157 | u8 regs[STB6100_NUMREGS]; |
158 | int rc; | 158 | int rc; |
159 | 159 | ||
160 | struct i2c_msg msg = { | ||
161 | .addr = state->config->tuner_address + reg, | ||
162 | .flags = I2C_M_RD, | ||
163 | .buf = regs, | ||
164 | .len = 1 | ||
165 | }; | ||
166 | |||
167 | rc = i2c_transfer(state->i2c, &msg, 1); | ||
168 | |||
160 | if (unlikely(reg >= STB6100_NUMREGS)) { | 169 | if (unlikely(reg >= STB6100_NUMREGS)) { |
161 | dprintk(verbose, FE_ERROR, 1, "Invalid register offset 0x%x", reg); | 170 | dprintk(verbose, FE_ERROR, 1, "Invalid register offset 0x%x", reg); |
162 | return -EINVAL; | 171 | return -EINVAL; |
163 | } | 172 | } |
164 | if ((rc = stb6100_read_regs(state, regs)) < 0) | 173 | if (unlikely(verbose > FE_DEBUG)) { |
165 | return rc; | 174 | dprintk(verbose, FE_DEBUG, 1, " Read from 0x%02x", state->config->tuner_address); |
166 | return (unsigned int)regs[reg]; | 175 | dprintk(verbose, FE_DEBUG, 1, " %s: 0x%02x", stb6100_regnames[reg], regs[0]); |
176 | } | ||
177 | |||
178 | return (unsigned int)regs[0]; | ||
167 | } | 179 | } |
168 | 180 | ||
169 | static int stb6100_write_reg_range(struct stb6100_state *state, u8 buf[], int start, int len) | 181 | static int stb6100_write_reg_range(struct stb6100_state *state, u8 buf[], int start, int len) |
@@ -211,20 +223,17 @@ static int stb6100_write_reg(struct stb6100_state *state, u8 reg, u8 data) | |||
211 | return stb6100_write_reg_range(state, &data, reg, 1); | 223 | return stb6100_write_reg_range(state, &data, reg, 1); |
212 | } | 224 | } |
213 | 225 | ||
214 | static int stb6100_write_regs(struct stb6100_state *state, u8 regs[]) | ||
215 | { | ||
216 | stb6100_normalise_regs(regs); | ||
217 | return stb6100_write_reg_range(state, ®s[1], 1, STB6100_NUMREGS - 1); | ||
218 | } | ||
219 | 226 | ||
220 | static int stb6100_get_status(struct dvb_frontend *fe, u32 *status) | 227 | static int stb6100_get_status(struct dvb_frontend *fe, u32 *status) |
221 | { | 228 | { |
222 | int rc; | 229 | int rc; |
223 | struct stb6100_state *state = fe->tuner_priv; | 230 | struct stb6100_state *state = fe->tuner_priv; |
224 | 231 | ||
225 | if ((rc = stb6100_read_reg(state, STB6100_LD)) < 0) | 232 | rc = stb6100_read_reg(state, STB6100_LD); |
233 | if (rc < 0) { | ||
234 | dprintk(verbose, FE_ERROR, 1, "%s failed", __func__); | ||
226 | return rc; | 235 | return rc; |
227 | 236 | } | |
228 | return (rc & STB6100_LD_LOCK) ? TUNER_STATUS_LOCKED : 0; | 237 | return (rc & STB6100_LD_LOCK) ? TUNER_STATUS_LOCKED : 0; |
229 | } | 238 | } |
230 | 239 | ||
@@ -234,7 +243,8 @@ static int stb6100_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) | |||
234 | u8 f; | 243 | u8 f; |
235 | struct stb6100_state *state = fe->tuner_priv; | 244 | struct stb6100_state *state = fe->tuner_priv; |
236 | 245 | ||
237 | if ((rc = stb6100_read_reg(state, STB6100_F)) < 0) | 246 | rc = stb6100_read_reg(state, STB6100_F); |
247 | if (rc < 0) | ||
238 | return rc; | 248 | return rc; |
239 | f = rc & STB6100_F_F; | 249 | f = rc & STB6100_F_F; |
240 | 250 | ||
@@ -265,14 +275,21 @@ static int stb6100_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth) | |||
265 | /* Turn on LPF bandwidth setting clock control, | 275 | /* Turn on LPF bandwidth setting clock control, |
266 | * set bandwidth, wait 10ms, turn off. | 276 | * set bandwidth, wait 10ms, turn off. |
267 | */ | 277 | */ |
268 | if ((rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d | STB6100_FCCK_FCCK)) < 0) | 278 | rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d | STB6100_FCCK_FCCK); |
279 | if (rc < 0) | ||
269 | return rc; | 280 | return rc; |
270 | if ((rc = stb6100_write_reg(state, STB6100_F, 0xc0 | tmp)) < 0) | 281 | rc = stb6100_write_reg(state, STB6100_F, 0xc0 | tmp); |
282 | if (rc < 0) | ||
271 | return rc; | 283 | return rc; |
272 | msleep(1); | 284 | |
273 | if ((rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d)) < 0) | 285 | msleep(5); /* This is dangerous as another (related) thread may start */ |
286 | |||
287 | rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d); | ||
288 | if (rc < 0) | ||
274 | return rc; | 289 | return rc; |
275 | 290 | ||
291 | msleep(10); /* This is dangerous as another (related) thread may start */ | ||
292 | |||
276 | return 0; | 293 | return 0; |
277 | } | 294 | } |
278 | 295 | ||
@@ -284,7 +301,8 @@ static int stb6100_get_frequency(struct dvb_frontend *fe, u32 *frequency) | |||
284 | struct stb6100_state *state = fe->tuner_priv; | 301 | struct stb6100_state *state = fe->tuner_priv; |
285 | u8 regs[STB6100_NUMREGS]; | 302 | u8 regs[STB6100_NUMREGS]; |
286 | 303 | ||
287 | if ((rc = stb6100_read_regs(state, regs)) < 0) | 304 | rc = stb6100_read_regs(state, regs); |
305 | if (rc < 0) | ||
288 | return rc; | 306 | return rc; |
289 | 307 | ||
290 | odiv = (regs[STB6100_VCO] & STB6100_VCO_ODIV) >> STB6100_VCO_ODIV_SHIFT; | 308 | odiv = (regs[STB6100_VCO] & STB6100_VCO_ODIV) >> STB6100_VCO_ODIV_SHIFT; |
@@ -312,8 +330,7 @@ static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency) | |||
312 | u8 regs[STB6100_NUMREGS]; | 330 | u8 regs[STB6100_NUMREGS]; |
313 | u8 g, psd2, odiv; | 331 | u8 g, psd2, odiv; |
314 | 332 | ||
315 | if ((rc = stb6100_read_regs(state, regs)) < 0) | 333 | dprintk(verbose, FE_DEBUG, 1, "Version 2010-8-14 13:51"); |
316 | return rc; | ||
317 | 334 | ||
318 | if (fe->ops.get_frontend) { | 335 | if (fe->ops.get_frontend) { |
319 | dprintk(verbose, FE_DEBUG, 1, "Get frontend parameters"); | 336 | dprintk(verbose, FE_DEBUG, 1, "Get frontend parameters"); |
@@ -321,96 +338,140 @@ static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency) | |||
321 | } | 338 | } |
322 | srate = p.u.qpsk.symbol_rate; | 339 | srate = p.u.qpsk.symbol_rate; |
323 | 340 | ||
324 | regs[STB6100_DLB] = 0xdc; | 341 | /* Set up tuner cleanly, LPF calibration on */ |
325 | /* Disable LPEN */ | 342 | rc = stb6100_write_reg(state, STB6100_FCCK, 0x4d | STB6100_FCCK_FCCK); |
326 | regs[STB6100_LPEN] &= ~STB6100_LPEN_LPEN; /* PLL Loop disabled */ | 343 | if (rc < 0) |
344 | return rc; /* allow LPF calibration */ | ||
327 | 345 | ||
328 | if ((rc = stb6100_write_regs(state, regs)) < 0) | 346 | /* PLL Loop disabled, bias on, VCO on, synth on */ |
347 | regs[STB6100_LPEN] = 0xeb; | ||
348 | rc = stb6100_write_reg(state, STB6100_LPEN, regs[STB6100_LPEN]); | ||
349 | if (rc < 0) | ||
329 | return rc; | 350 | return rc; |
330 | 351 | ||
331 | /* Baseband gain. */ | 352 | /* Program the registers with their data values */ |
332 | if (srate >= 15000000) | ||
333 | g = 9; // +4 dB | ||
334 | else if (srate >= 5000000) | ||
335 | g = 11; // +8 dB | ||
336 | else | ||
337 | g = 14; // +14 dB | ||
338 | |||
339 | regs[STB6100_G] = (regs[STB6100_G] & ~STB6100_G_G) | g; | ||
340 | regs[STB6100_G] &= ~STB6100_G_GCT; /* mask GCT */ | ||
341 | regs[STB6100_G] |= (1 << 5); /* 2Vp-p Mode */ | ||
342 | 353 | ||
343 | /* VCO divide ratio (LO divide ratio, VCO prescaler enable). */ | 354 | /* VCO divide ratio (LO divide ratio, VCO prescaler enable). */ |
344 | if (frequency <= 1075000) | 355 | if (frequency <= 1075000) |
345 | odiv = 1; | 356 | odiv = 1; |
346 | else | 357 | else |
347 | odiv = 0; | 358 | odiv = 0; |
348 | regs[STB6100_VCO] = (regs[STB6100_VCO] & ~STB6100_VCO_ODIV) | (odiv << STB6100_VCO_ODIV_SHIFT); | ||
349 | 359 | ||
350 | if ((frequency > 1075000) && (frequency <= 1325000)) | 360 | /* VCO enabled, seach clock off as per LL3.7, 3.4.1 */ |
351 | psd2 = 0; | 361 | regs[STB6100_VCO] = 0xe0 | (odiv << STB6100_VCO_ODIV_SHIFT); |
352 | else | ||
353 | psd2 = 1; | ||
354 | regs[STB6100_K] = (regs[STB6100_K] & ~STB6100_K_PSD2) | (psd2 << STB6100_K_PSD2_SHIFT); | ||
355 | 362 | ||
356 | /* OSM */ | 363 | /* OSM */ |
357 | for (ptr = lkup; | 364 | for (ptr = lkup; |
358 | (ptr->val_high != 0) && !CHKRANGE(frequency, ptr->val_low, ptr->val_high); | 365 | (ptr->val_high != 0) && !CHKRANGE(frequency, ptr->val_low, ptr->val_high); |
359 | ptr++); | 366 | ptr++); |
367 | |||
360 | if (ptr->val_high == 0) { | 368 | if (ptr->val_high == 0) { |
361 | printk(KERN_ERR "%s: frequency out of range: %u kHz\n", __func__, frequency); | 369 | printk(KERN_ERR "%s: frequency out of range: %u kHz\n", __func__, frequency); |
362 | return -EINVAL; | 370 | return -EINVAL; |
363 | } | 371 | } |
364 | regs[STB6100_VCO] = (regs[STB6100_VCO] & ~STB6100_VCO_OSM) | ptr->reg; | 372 | regs[STB6100_VCO] = (regs[STB6100_VCO] & ~STB6100_VCO_OSM) | ptr->reg; |
373 | rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO]); | ||
374 | if (rc < 0) | ||
375 | return rc; | ||
365 | 376 | ||
377 | if ((frequency > 1075000) && (frequency <= 1325000)) | ||
378 | psd2 = 0; | ||
379 | else | ||
380 | psd2 = 1; | ||
366 | /* F(VCO) = F(LO) * (ODIV == 0 ? 2 : 4) */ | 381 | /* F(VCO) = F(LO) * (ODIV == 0 ? 2 : 4) */ |
367 | fvco = frequency << (1 + odiv); | 382 | fvco = frequency << (1 + odiv); |
368 | /* N(I) = floor(f(VCO) / (f(XTAL) * (PSD2 ? 2 : 1))) */ | 383 | /* N(I) = floor(f(VCO) / (f(XTAL) * (PSD2 ? 2 : 1))) */ |
369 | nint = fvco / (state->reference << psd2); | 384 | nint = fvco / (state->reference << psd2); |
370 | /* N(F) = round(f(VCO) / f(XTAL) * (PSD2 ? 2 : 1) - N(I)) * 2 ^ 9 */ | 385 | /* N(F) = round(f(VCO) / f(XTAL) * (PSD2 ? 2 : 1) - N(I)) * 2 ^ 9 */ |
371 | nfrac = DIV_ROUND_CLOSEST((fvco - (nint * state->reference << psd2)) | 386 | nfrac = DIV_ROUND_CLOSEST((fvco - (nint * state->reference << psd2)) |
372 | << (9 - psd2), | 387 | << (9 - psd2), state->reference); |
373 | state->reference); | 388 | |
389 | /* NI */ | ||
390 | regs[STB6100_NI] = nint; | ||
391 | rc = stb6100_write_reg(state, STB6100_NI, regs[STB6100_NI]); | ||
392 | if (rc < 0) | ||
393 | return rc; | ||
394 | |||
395 | /* NF */ | ||
396 | regs[STB6100_NF_LSB] = nfrac; | ||
397 | rc = stb6100_write_reg(state, STB6100_NF_LSB, regs[STB6100_NF_LSB]); | ||
398 | if (rc < 0) | ||
399 | return rc; | ||
400 | |||
401 | /* K */ | ||
402 | regs[STB6100_K] = (0x38 & ~STB6100_K_PSD2) | (psd2 << STB6100_K_PSD2_SHIFT); | ||
403 | regs[STB6100_K] = (regs[STB6100_K] & ~STB6100_K_NF_MSB) | ((nfrac >> 8) & STB6100_K_NF_MSB); | ||
404 | rc = stb6100_write_reg(state, STB6100_K, regs[STB6100_K]); | ||
405 | if (rc < 0) | ||
406 | return rc; | ||
407 | |||
408 | /* G Baseband gain. */ | ||
409 | if (srate >= 15000000) | ||
410 | g = 9; /* +4 dB */ | ||
411 | else if (srate >= 5000000) | ||
412 | g = 11; /* +8 dB */ | ||
413 | else | ||
414 | g = 14; /* +14 dB */ | ||
415 | |||
416 | regs[STB6100_G] = (0x10 & ~STB6100_G_G) | g; | ||
417 | regs[STB6100_G] &= ~STB6100_G_GCT; /* mask GCT */ | ||
418 | regs[STB6100_G] |= (1 << 5); /* 2Vp-p Mode */ | ||
419 | rc = stb6100_write_reg(state, STB6100_G, regs[STB6100_G]); | ||
420 | if (rc < 0) | ||
421 | return rc; | ||
422 | |||
423 | /* F we don't write as it is set up in BW set */ | ||
424 | |||
425 | /* DLB set DC servo loop BW to 160Hz (LLA 3.8 / 2.1) */ | ||
426 | regs[STB6100_DLB] = 0xcc; | ||
427 | rc = stb6100_write_reg(state, STB6100_DLB, regs[STB6100_DLB]); | ||
428 | if (rc < 0) | ||
429 | return rc; | ||
430 | |||
374 | dprintk(verbose, FE_DEBUG, 1, | 431 | dprintk(verbose, FE_DEBUG, 1, |
375 | "frequency = %u, srate = %u, g = %u, odiv = %u, psd2 = %u, fxtal = %u, osm = %u, fvco = %u, N(I) = %u, N(F) = %u", | 432 | "frequency = %u, srate = %u, g = %u, odiv = %u, psd2 = %u, fxtal = %u, osm = %u, fvco = %u, N(I) = %u, N(F) = %u", |
376 | frequency, srate, (unsigned int)g, (unsigned int)odiv, | 433 | frequency, srate, (unsigned int)g, (unsigned int)odiv, |
377 | (unsigned int)psd2, state->reference, | 434 | (unsigned int)psd2, state->reference, |
378 | ptr->reg, fvco, nint, nfrac); | 435 | ptr->reg, fvco, nint, nfrac); |
379 | regs[STB6100_NI] = nint; | ||
380 | regs[STB6100_NF_LSB] = nfrac; | ||
381 | regs[STB6100_K] = (regs[STB6100_K] & ~STB6100_K_NF_MSB) | ((nfrac >> 8) & STB6100_K_NF_MSB); | ||
382 | regs[STB6100_VCO] |= STB6100_VCO_OSCH; /* VCO search enabled */ | ||
383 | regs[STB6100_VCO] |= STB6100_VCO_OCK; /* VCO search clock off */ | ||
384 | regs[STB6100_FCCK] |= STB6100_FCCK_FCCK; /* LPF BW setting clock enabled */ | ||
385 | regs[STB6100_LPEN] &= ~STB6100_LPEN_LPEN; /* PLL loop disabled */ | ||
386 | /* Power up. */ | ||
387 | regs[STB6100_LPEN] |= STB6100_LPEN_SYNP | STB6100_LPEN_OSCP | STB6100_LPEN_BEN; | ||
388 | 436 | ||
389 | msleep(2); | 437 | /* Set up the test registers */ |
390 | if ((rc = stb6100_write_regs(state, regs)) < 0) | 438 | regs[STB6100_TEST1] = 0x8f; |
439 | rc = stb6100_write_reg(state, STB6100_TEST1, regs[STB6100_TEST1]); | ||
440 | if (rc < 0) | ||
441 | return rc; | ||
442 | regs[STB6100_TEST3] = 0xde; | ||
443 | rc = stb6100_write_reg(state, STB6100_TEST3, regs[STB6100_TEST3]); | ||
444 | if (rc < 0) | ||
391 | return rc; | 445 | return rc; |
392 | 446 | ||
393 | msleep(2); | 447 | /* Bring up tuner according to LLA 3.7 3.4.1, step 2 */ |
394 | regs[STB6100_LPEN] |= STB6100_LPEN_LPEN; /* PLL loop enabled */ | 448 | regs[STB6100_LPEN] = 0xfb; /* PLL Loop enabled, bias on, VCO on, synth on */ |
395 | if ((rc = stb6100_write_reg(state, STB6100_LPEN, regs[STB6100_LPEN])) < 0) | 449 | rc = stb6100_write_reg(state, STB6100_LPEN, regs[STB6100_LPEN]); |
450 | if (rc < 0) | ||
396 | return rc; | 451 | return rc; |
397 | 452 | ||
453 | msleep(2); | ||
454 | |||
455 | /* Bring up tuner according to LLA 3.7 3.4.1, step 3 */ | ||
398 | regs[STB6100_VCO] &= ~STB6100_VCO_OCK; /* VCO fast search */ | 456 | regs[STB6100_VCO] &= ~STB6100_VCO_OCK; /* VCO fast search */ |
399 | if ((rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO])) < 0) | 457 | rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO]); |
458 | if (rc < 0) | ||
400 | return rc; | 459 | return rc; |
401 | 460 | ||
402 | msleep(10); /* wait for LO to lock */ | 461 | msleep(10); /* This is dangerous as another (related) thread may start */ /* wait for LO to lock */ |
462 | |||
403 | regs[STB6100_VCO] &= ~STB6100_VCO_OSCH; /* vco search disabled */ | 463 | regs[STB6100_VCO] &= ~STB6100_VCO_OSCH; /* vco search disabled */ |
404 | regs[STB6100_VCO] |= STB6100_VCO_OCK; /* search clock off */ | 464 | regs[STB6100_VCO] |= STB6100_VCO_OCK; /* search clock off */ |
405 | if ((rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO])) < 0) | 465 | rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO]); |
406 | return rc; | 466 | if (rc < 0) |
407 | regs[STB6100_FCCK] &= ~STB6100_FCCK_FCCK; /* LPF BW clock disabled */ | ||
408 | stb6100_normalise_regs(regs); | ||
409 | if ((rc = stb6100_write_reg_range(state, ®s[1], 1, STB6100_NUMREGS - 3)) < 0) | ||
410 | return rc; | 467 | return rc; |
411 | 468 | ||
412 | msleep(100); | 469 | rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d); |
470 | if (rc < 0) | ||
471 | return rc; /* Stop LPF calibration */ | ||
413 | 472 | ||
473 | msleep(10); /* This is dangerous as another (related) thread may start */ | ||
474 | /* wait for stabilisation, (should not be necessary) */ | ||
414 | return 0; | 475 | return 0; |
415 | } | 476 | } |
416 | 477 | ||
@@ -433,8 +494,8 @@ static int stb6100_init(struct dvb_frontend *fe) | |||
433 | state->bandwidth = status->bandwidth * 1000; /* Hz */ | 494 | state->bandwidth = status->bandwidth * 1000; /* Hz */ |
434 | state->reference = status->refclock / 1000; /* kHz */ | 495 | state->reference = status->refclock / 1000; /* kHz */ |
435 | 496 | ||
436 | /* Set default bandwidth. */ | 497 | /* Set default bandwidth. Modified, PN 13-May-10 */ |
437 | return stb6100_set_bandwidth(fe, state->bandwidth); | 498 | return 0; |
438 | } | 499 | } |
439 | 500 | ||
440 | static int stb6100_get_state(struct dvb_frontend *fe, | 501 | static int stb6100_get_state(struct dvb_frontend *fe, |