aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorManu Abraham <abraham.manu@gmail.com>2010-11-14 13:52:10 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-12-29 05:16:49 -0500
commitf14bfe94e459cb070a489e1786f26d54e9e7b5de (patch)
tree6b75f51ac0bc91bce48412896b0b943f6edcd0da /drivers
parent3037fd14302d635426996fb7f6fcf7cb98dc15b9 (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.c193
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
56struct stb6100_lkup { 56struct 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
169static int stb6100_write_reg_range(struct stb6100_state *state, u8 buf[], int start, int len) 181static 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
214static int stb6100_write_regs(struct stb6100_state *state, u8 regs[])
215{
216 stb6100_normalise_regs(regs);
217 return stb6100_write_reg_range(state, &regs[1], 1, STB6100_NUMREGS - 1);
218}
219 226
220static int stb6100_get_status(struct dvb_frontend *fe, u32 *status) 227static 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, &regs[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
440static int stb6100_get_state(struct dvb_frontend *fe, 501static int stb6100_get_state(struct dvb_frontend *fe,