Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[media] tda10071: implement DVBv5 statistics

Implement DVBv5 CNR, signal strength, BER and block errors.

Wrap legacy DVBv3 statistics to DVBv5 internally.

Signed-off-by: Antti Palosaari <crope@iki.fi>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>

authored by

Antti Palosaari and committed by
Mauro Carvalho Chehab
267897a4 4c4acb7a

+138 -133
+134 -130
drivers/media/dvb-frontends/tda10071.c
··· 377 377 { 378 378 struct tda10071_dev *dev = fe->demodulator_priv; 379 379 struct i2c_client *client = dev->client; 380 + struct dtv_frontend_properties *c = &fe->dtv_property_cache; 381 + struct tda10071_cmd cmd; 380 382 int ret; 381 383 unsigned int uitmp; 384 + u8 buf[8]; 382 385 383 386 *status = 0; 384 387 ··· 404 401 405 402 dev->fe_status = *status; 406 403 404 + /* signal strength */ 405 + if (dev->fe_status & FE_HAS_SIGNAL) { 406 + cmd.args[0] = CMD_GET_AGCACC; 407 + cmd.args[1] = 0; 408 + cmd.len = 2; 409 + ret = tda10071_cmd_execute(dev, &cmd); 410 + if (ret) 411 + goto error; 412 + 413 + /* input power estimate dBm */ 414 + ret = regmap_read(dev->regmap, 0x50, &uitmp); 415 + if (ret) 416 + goto error; 417 + 418 + c->strength.stat[0].scale = FE_SCALE_DECIBEL; 419 + c->strength.stat[0].svalue = (int) (uitmp - 256) * 1000; 420 + } else { 421 + c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 422 + } 423 + 424 + /* CNR */ 425 + if (dev->fe_status & FE_HAS_VITERBI) { 426 + /* Es/No */ 427 + ret = regmap_bulk_read(dev->regmap, 0x3a, buf, 2); 428 + if (ret) 429 + goto error; 430 + 431 + c->cnr.stat[0].scale = FE_SCALE_DECIBEL; 432 + c->cnr.stat[0].svalue = (buf[0] << 8 | buf[1] << 0) * 100; 433 + } else { 434 + c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 435 + } 436 + 437 + /* UCB/PER/BER */ 438 + if (dev->fe_status & FE_HAS_LOCK) { 439 + /* TODO: report total bits/packets */ 440 + u8 delivery_system, reg, len; 441 + 442 + switch (dev->delivery_system) { 443 + case SYS_DVBS: 444 + reg = 0x4c; 445 + len = 8; 446 + delivery_system = 1; 447 + break; 448 + case SYS_DVBS2: 449 + reg = 0x4d; 450 + len = 4; 451 + delivery_system = 0; 452 + break; 453 + default: 454 + ret = -EINVAL; 455 + goto error; 456 + } 457 + 458 + ret = regmap_read(dev->regmap, reg, &uitmp); 459 + if (ret) 460 + goto error; 461 + 462 + if (dev->meas_count == uitmp) { 463 + dev_dbg(&client->dev, "meas not ready=%02x\n", uitmp); 464 + ret = 0; 465 + goto error; 466 + } else { 467 + dev->meas_count = uitmp; 468 + } 469 + 470 + cmd.args[0] = CMD_BER_UPDATE_COUNTERS; 471 + cmd.args[1] = 0; 472 + cmd.args[2] = delivery_system; 473 + cmd.len = 3; 474 + ret = tda10071_cmd_execute(dev, &cmd); 475 + if (ret) 476 + goto error; 477 + 478 + ret = regmap_bulk_read(dev->regmap, cmd.len, buf, len); 479 + if (ret) 480 + goto error; 481 + 482 + if (dev->delivery_system == SYS_DVBS) { 483 + dev->dvbv3_ber = buf[0] << 24 | buf[1] << 16 | 484 + buf[2] << 8 | buf[3] << 0; 485 + dev->post_bit_error += buf[0] << 24 | buf[1] << 16 | 486 + buf[2] << 8 | buf[3] << 0; 487 + c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; 488 + c->post_bit_error.stat[0].uvalue = dev->post_bit_error; 489 + dev->block_error += buf[4] << 8 | buf[5] << 0; 490 + c->block_error.stat[0].scale = FE_SCALE_COUNTER; 491 + c->block_error.stat[0].uvalue = dev->block_error; 492 + } else { 493 + dev->dvbv3_ber = buf[0] << 8 | buf[1] << 0; 494 + dev->post_bit_error += buf[0] << 8 | buf[1] << 0; 495 + c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; 496 + c->post_bit_error.stat[0].uvalue = dev->post_bit_error; 497 + c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 498 + } 499 + } else { 500 + c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 501 + c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 502 + } 503 + 407 504 return ret; 408 505 error: 409 506 dev_dbg(&client->dev, "failed=%d\n", ret); ··· 512 409 513 410 static int tda10071_read_snr(struct dvb_frontend *fe, u16 *snr) 514 411 { 515 - struct tda10071_dev *dev = fe->demodulator_priv; 516 - struct i2c_client *client = dev->client; 517 - int ret; 518 - u8 buf[2]; 412 + struct dtv_frontend_properties *c = &fe->dtv_property_cache; 519 413 520 - if (!dev->warm || !(dev->fe_status & FE_HAS_LOCK)) { 414 + if (c->cnr.stat[0].scale == FE_SCALE_DECIBEL) 415 + *snr = div_s64(c->cnr.stat[0].svalue, 100); 416 + else 521 417 *snr = 0; 522 - ret = 0; 523 - goto error; 524 - } 525 - 526 - ret = regmap_bulk_read(dev->regmap, 0x3a, buf, 2); 527 - if (ret) 528 - goto error; 529 - 530 - /* Es/No dBx10 */ 531 - *snr = buf[0] << 8 | buf[1]; 532 - 533 - return ret; 534 - error: 535 - dev_dbg(&client->dev, "failed=%d\n", ret); 536 - return ret; 418 + return 0; 537 419 } 538 420 539 421 static int tda10071_read_signal_strength(struct dvb_frontend *fe, u16 *strength) 540 422 { 541 - struct tda10071_dev *dev = fe->demodulator_priv; 542 - struct i2c_client *client = dev->client; 543 - struct tda10071_cmd cmd; 544 - int ret; 423 + struct dtv_frontend_properties *c = &fe->dtv_property_cache; 545 424 unsigned int uitmp; 546 425 547 - if (!dev->warm || !(dev->fe_status & FE_HAS_LOCK)) { 426 + if (c->strength.stat[0].scale == FE_SCALE_DECIBEL) { 427 + uitmp = c->strength.stat[0].svalue / 1000 + 256; 428 + uitmp = clamp(uitmp, 181U, 236U); /* -75dBm - -20dBm */ 429 + /* scale value to 0x0000-0xffff */ 430 + *strength = (uitmp-181) * 0xffff / (236-181); 431 + } else { 548 432 *strength = 0; 549 - ret = 0; 550 - goto error; 551 433 } 552 - 553 - cmd.args[0] = CMD_GET_AGCACC; 554 - cmd.args[1] = 0; 555 - cmd.len = 2; 556 - ret = tda10071_cmd_execute(dev, &cmd); 557 - if (ret) 558 - goto error; 559 - 560 - /* input power estimate dBm */ 561 - ret = regmap_read(dev->regmap, 0x50, &uitmp); 562 - if (ret) 563 - goto error; 564 - 565 - if (uitmp < 181) 566 - uitmp = 181; /* -75 dBm */ 567 - else if (uitmp > 236) 568 - uitmp = 236; /* -20 dBm */ 569 - 570 - /* scale value to 0x0000-0xffff */ 571 - *strength = (uitmp-181) * 0xffff / (236-181); 572 - 573 - return ret; 574 - error: 575 - dev_dbg(&client->dev, "failed=%d\n", ret); 576 - return ret; 434 + return 0; 577 435 } 578 436 579 437 static int tda10071_read_ber(struct dvb_frontend *fe, u32 *ber) 580 438 { 581 439 struct tda10071_dev *dev = fe->demodulator_priv; 582 - struct i2c_client *client = dev->client; 583 - struct tda10071_cmd cmd; 584 - int ret, i, len; 585 - unsigned int uitmp; 586 - u8 reg, buf[8]; 587 440 588 - if (!dev->warm || !(dev->fe_status & FE_HAS_LOCK)) { 589 - *ber = dev->ber = 0; 590 - ret = 0; 591 - goto error; 592 - } 593 - 594 - switch (dev->delivery_system) { 595 - case SYS_DVBS: 596 - reg = 0x4c; 597 - len = 8; 598 - i = 1; 599 - break; 600 - case SYS_DVBS2: 601 - reg = 0x4d; 602 - len = 4; 603 - i = 0; 604 - break; 605 - default: 606 - *ber = dev->ber = 0; 607 - return 0; 608 - } 609 - 610 - ret = regmap_read(dev->regmap, reg, &uitmp); 611 - if (ret) 612 - goto error; 613 - 614 - if (dev->meas_count[i] == uitmp) { 615 - dev_dbg(&client->dev, "meas not ready=%02x\n", uitmp); 616 - *ber = dev->ber; 617 - return 0; 618 - } else { 619 - dev->meas_count[i] = uitmp; 620 - } 621 - 622 - cmd.args[0] = CMD_BER_UPDATE_COUNTERS; 623 - cmd.args[1] = 0; 624 - cmd.args[2] = i; 625 - cmd.len = 3; 626 - ret = tda10071_cmd_execute(dev, &cmd); 627 - if (ret) 628 - goto error; 629 - 630 - ret = regmap_bulk_read(dev->regmap, cmd.len, buf, len); 631 - if (ret) 632 - goto error; 633 - 634 - if (dev->delivery_system == SYS_DVBS) { 635 - *ber = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; 636 - dev->ucb += (buf[4] << 8) | buf[5]; 637 - } else { 638 - *ber = (buf[0] << 8) | buf[1]; 639 - } 640 - dev->ber = *ber; 641 - 642 - return ret; 643 - error: 644 - dev_dbg(&client->dev, "failed=%d\n", ret); 645 - return ret; 441 + *ber = dev->dvbv3_ber; 442 + return 0; 646 443 } 647 444 648 445 static int tda10071_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) 649 446 { 650 - struct tda10071_dev *dev = fe->demodulator_priv; 651 - struct i2c_client *client = dev->client; 652 - int ret = 0; 447 + struct dtv_frontend_properties *c = &fe->dtv_property_cache; 653 448 654 - if (!dev->warm || !(dev->fe_status & FE_HAS_LOCK)) { 449 + if (c->block_error.stat[0].scale == FE_SCALE_COUNTER) 450 + *ucblocks = c->block_error.stat[0].uvalue; 451 + else 655 452 *ucblocks = 0; 656 - goto error; 657 - } 658 - 659 - /* UCB is updated when BER is read. Assume BER is read anyway. */ 660 - 661 - *ucblocks = dev->ucb; 662 - 663 - return ret; 664 - error: 665 - dev_dbg(&client->dev, "failed=%d\n", ret); 666 - return ret; 453 + return 0; 667 454 } 668 455 669 456 static int tda10071_set_frontend(struct dvb_frontend *fe) ··· 763 770 { 764 771 struct tda10071_dev *dev = fe->demodulator_priv; 765 772 struct i2c_client *client = dev->client; 773 + struct dtv_frontend_properties *c = &fe->dtv_property_cache; 766 774 struct tda10071_cmd cmd; 767 775 int ret, i, len, remaining, fw_size; 768 776 unsigned int uitmp; ··· 1028 1034 if (ret) 1029 1035 goto error; 1030 1036 } 1037 + 1038 + /* init stats here in order signal app which stats are supported */ 1039 + c->strength.len = 1; 1040 + c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 1041 + c->cnr.len = 1; 1042 + c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 1043 + c->post_bit_error.len = 1; 1044 + c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 1045 + c->block_error.len = 1; 1046 + c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 1031 1047 1032 1048 return ret; 1033 1049 error_release_firmware:
+4 -3
drivers/media/dvb-frontends/tda10071_priv.h
··· 38 38 u8 pll_multiplier; 39 39 u8 tuner_i2c_addr; 40 40 41 - u8 meas_count[2]; 42 - u32 ber; 43 - u32 ucb; 41 + u8 meas_count; 42 + u32 dvbv3_ber; 44 43 enum fe_status fe_status; 45 44 enum fe_delivery_system delivery_system; 46 45 bool warm; /* FW running */ 46 + u64 post_bit_error; 47 + u64 block_error; 47 48 }; 48 49 49 50 static struct tda10071_modcod {