diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-04-10 14:55:48 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-04-16 20:33:11 -0400 |
commit | 25cf4d462abd6d78d224b564de82dcdab7973673 (patch) | |
tree | 2ebbc629fdadcdb92f4817a95587b26f5b9109bc | |
parent | d75d538899da00bdf8f152c65a99eda1ab59daa3 (diff) |
[media] r820t: add IMR calibrate code
This code seems to calibrate I/Q phase and gain during the
device initialization.
This is done only once, and it doesn't seem to be needed to
happen after resuming.
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Tested-by: Antti Palosaari <crope@iki.fi>
-rw-r--r-- | drivers/media/tuners/r820t.c | 702 |
1 files changed, 681 insertions, 21 deletions
diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index 07d032350c1b..fa2e9ae48c98 100644 --- a/drivers/media/tuners/r820t.c +++ b/drivers/media/tuners/r820t.c | |||
@@ -47,6 +47,8 @@ | |||
47 | */ | 47 | */ |
48 | #define REG_SHADOW_START 5 | 48 | #define REG_SHADOW_START 5 |
49 | #define NUM_REGS 27 | 49 | #define NUM_REGS 27 |
50 | #define NUM_IMR 5 | ||
51 | #define IMR_TRIAL 9 | ||
50 | 52 | ||
51 | #define VER_NUM 49 | 53 | #define VER_NUM 49 |
52 | 54 | ||
@@ -66,6 +68,12 @@ enum xtal_cap_value { | |||
66 | XTAL_HIGH_CAP_0P | 68 | XTAL_HIGH_CAP_0P |
67 | }; | 69 | }; |
68 | 70 | ||
71 | struct r820t_sect_type { | ||
72 | u8 phase_y; | ||
73 | u8 gain_x; | ||
74 | u16 value; | ||
75 | }; | ||
76 | |||
69 | struct r820t_priv { | 77 | struct r820t_priv { |
70 | struct list_head hybrid_tuner_instance_list; | 78 | struct list_head hybrid_tuner_instance_list; |
71 | const struct r820t_config *cfg; | 79 | const struct r820t_config *cfg; |
@@ -80,6 +88,8 @@ struct r820t_priv { | |||
80 | u8 fil_cal_code; | 88 | u8 fil_cal_code; |
81 | bool imr_done; | 89 | bool imr_done; |
82 | 90 | ||
91 | struct r820t_sect_type imr_data[NUM_IMR]; | ||
92 | |||
83 | /* Store current mode */ | 93 | /* Store current mode */ |
84 | u32 delsys; | 94 | u32 delsys; |
85 | enum v4l2_tuner_type type; | 95 | enum v4l2_tuner_type type; |
@@ -459,7 +469,7 @@ static int r820t_set_mux(struct r820t_priv *priv, u32 freq) | |||
459 | { | 469 | { |
460 | const struct r820t_freq_range *range; | 470 | const struct r820t_freq_range *range; |
461 | int i, rc; | 471 | int i, rc; |
462 | u8 val; | 472 | u8 val, reg08, reg09; |
463 | 473 | ||
464 | /* Get the proper frequency range */ | 474 | /* Get the proper frequency range */ |
465 | freq = freq / 1000000; | 475 | freq = freq / 1000000; |
@@ -507,17 +517,18 @@ static int r820t_set_mux(struct r820t_priv *priv, u32 freq) | |||
507 | if (rc < 0) | 517 | if (rc < 0) |
508 | return rc; | 518 | return rc; |
509 | 519 | ||
510 | /* | 520 | if (priv->imr_done) { |
511 | * FIXME: the original driver has a logic there with preserves | 521 | reg08 = priv->imr_data[range->imr_mem].gain_x; |
512 | * gain/phase from registers 8 and 9 reading the data from the | 522 | reg09 = priv->imr_data[range->imr_mem].phase_y; |
513 | * registers before writing, if "IMF done". That code was sort of | 523 | } else { |
514 | * commented there, as the flag is always false. | 524 | reg08 = 0; |
515 | */ | 525 | reg09 = 0; |
516 | rc = r820t_write_reg_mask(priv, 0x08, 0, 0x3f); | 526 | } |
527 | rc = r820t_write_reg_mask(priv, 0x08, reg08, 0x3f); | ||
517 | if (rc < 0) | 528 | if (rc < 0) |
518 | return rc; | 529 | return rc; |
519 | 530 | ||
520 | rc = r820t_write_reg_mask(priv, 0x09, 0, 0x3f); | 531 | rc = r820t_write_reg_mask(priv, 0x09, reg09, 0x3f); |
521 | 532 | ||
522 | return rc; | 533 | return rc; |
523 | } | 534 | } |
@@ -1383,24 +1394,621 @@ static int r820t_xtal_check(struct r820t_priv *priv) | |||
1383 | return r820t_xtal_capacitor[i][1]; | 1394 | return r820t_xtal_capacitor[i][1]; |
1384 | } | 1395 | } |
1385 | 1396 | ||
1386 | /* | 1397 | static int r820t_imr_prepare(struct r820t_priv *priv) |
1387 | * r820t frontend operations and tuner attach code | 1398 | { |
1388 | * | 1399 | int rc; |
1389 | * All driver locks and i2c control are only in this part of the code | ||
1390 | */ | ||
1391 | 1400 | ||
1392 | static int r820t_init(struct dvb_frontend *fe) | 1401 | /* Initialize the shadow registers */ |
1402 | memcpy(priv->regs, r820t_init_array, sizeof(r820t_init_array)); | ||
1403 | |||
1404 | /* lna off (air-in off) */ | ||
1405 | rc = r820t_write_reg_mask(priv, 0x05, 0x20, 0x20); | ||
1406 | if (rc < 0) | ||
1407 | return rc; | ||
1408 | |||
1409 | /* mixer gain mode = manual */ | ||
1410 | rc = r820t_write_reg_mask(priv, 0x07, 0, 0x10); | ||
1411 | if (rc < 0) | ||
1412 | return rc; | ||
1413 | |||
1414 | /* filter corner = lowest */ | ||
1415 | rc = r820t_write_reg_mask(priv, 0x0a, 0x0f, 0x0f); | ||
1416 | if (rc < 0) | ||
1417 | return rc; | ||
1418 | |||
1419 | /* filter bw=+2cap, hp=5M */ | ||
1420 | rc = r820t_write_reg_mask(priv, 0x0b, 0x60, 0x6f); | ||
1421 | if (rc < 0) | ||
1422 | return rc; | ||
1423 | |||
1424 | /* adc=on, vga code mode, gain = 26.5dB */ | ||
1425 | rc = r820t_write_reg_mask(priv, 0x0c, 0x0b, 0x9f); | ||
1426 | if (rc < 0) | ||
1427 | return rc; | ||
1428 | |||
1429 | /* ring clk = on */ | ||
1430 | rc = r820t_write_reg_mask(priv, 0x0f, 0, 0x08); | ||
1431 | if (rc < 0) | ||
1432 | return rc; | ||
1433 | |||
1434 | /* ring power = on */ | ||
1435 | rc = r820t_write_reg_mask(priv, 0x18, 0x10, 0x10); | ||
1436 | if (rc < 0) | ||
1437 | return rc; | ||
1438 | |||
1439 | /* from ring = ring pll in */ | ||
1440 | rc = r820t_write_reg_mask(priv, 0x1c, 0x02, 0x02); | ||
1441 | if (rc < 0) | ||
1442 | return rc; | ||
1443 | |||
1444 | /* sw_pdect = det3 */ | ||
1445 | rc = r820t_write_reg_mask(priv, 0x1e, 0x80, 0x80); | ||
1446 | if (rc < 0) | ||
1447 | return rc; | ||
1448 | |||
1449 | /* Set filt_3dB */ | ||
1450 | rc = r820t_write_reg_mask(priv, 0x06, 0x20, 0x20); | ||
1451 | |||
1452 | return rc; | ||
1453 | } | ||
1454 | |||
1455 | static int r820t_multi_read(struct r820t_priv *priv) | ||
1456 | { | ||
1457 | int rc, i; | ||
1458 | u8 data[2], min = 0, max = 255, sum = 0; | ||
1459 | |||
1460 | usleep_range(5000, 6000); | ||
1461 | |||
1462 | for (i = 0; i < 6; i++) { | ||
1463 | rc = r820t_read(priv, 0x00, data, sizeof(data)); | ||
1464 | if (rc < 0) | ||
1465 | return rc; | ||
1466 | |||
1467 | sum += data[1]; | ||
1468 | |||
1469 | if (data[1] < min) | ||
1470 | min = data[1]; | ||
1471 | |||
1472 | if (data[1] > max) | ||
1473 | max = data[1]; | ||
1474 | } | ||
1475 | rc = sum - max - min; | ||
1476 | |||
1477 | return rc; | ||
1478 | } | ||
1479 | |||
1480 | static int r820t_imr_cross(struct r820t_priv *priv, | ||
1481 | struct r820t_sect_type iq_point[3], | ||
1482 | u8 *x_direct) | ||
1483 | { | ||
1484 | struct r820t_sect_type cross[5]; /* (0,0)(0,Q-1)(0,I-1)(Q-1,0)(I-1,0) */ | ||
1485 | struct r820t_sect_type tmp; | ||
1486 | int i, rc; | ||
1487 | u8 reg08, reg09; | ||
1488 | |||
1489 | reg08 = r820t_read_cache_reg(priv, 8) & 0xc0; | ||
1490 | reg09 = r820t_read_cache_reg(priv, 9) & 0xc0; | ||
1491 | |||
1492 | tmp.gain_x = 0; | ||
1493 | tmp.phase_y = 0; | ||
1494 | tmp.value = 255; | ||
1495 | |||
1496 | for (i = 0; i < 5; i++) { | ||
1497 | switch (i) { | ||
1498 | case 0: | ||
1499 | cross[i].gain_x = reg08; | ||
1500 | cross[i].phase_y = reg09; | ||
1501 | break; | ||
1502 | case 1: | ||
1503 | cross[i].gain_x = reg08; /* 0 */ | ||
1504 | cross[i].phase_y = reg09 + 1; /* Q-1 */ | ||
1505 | break; | ||
1506 | case 2: | ||
1507 | cross[i].gain_x = reg08; /* 0 */ | ||
1508 | cross[i].phase_y = (reg09 | 0x20) + 1; /* I-1 */ | ||
1509 | break; | ||
1510 | case 3: | ||
1511 | cross[i].gain_x = reg08 + 1; /* Q-1 */ | ||
1512 | cross[i].phase_y = reg09; | ||
1513 | break; | ||
1514 | default: | ||
1515 | cross[i].gain_x = (reg08 | 0x20) + 1; /* I-1 */ | ||
1516 | cross[i].phase_y = reg09; | ||
1517 | } | ||
1518 | |||
1519 | rc = r820t_write_reg(priv, 0x08, cross[i].gain_x); | ||
1520 | if (rc < 0) | ||
1521 | return rc; | ||
1522 | |||
1523 | rc = r820t_write_reg(priv, 0x09, cross[i].phase_y); | ||
1524 | if (rc < 0) | ||
1525 | return rc; | ||
1526 | |||
1527 | rc = r820t_multi_read(priv); | ||
1528 | if (rc < 0) | ||
1529 | return rc; | ||
1530 | |||
1531 | cross[i].value = rc; | ||
1532 | |||
1533 | if (cross[i].value < tmp.value) | ||
1534 | memcpy(&tmp, &cross[i], sizeof(tmp)); | ||
1535 | } | ||
1536 | |||
1537 | if ((tmp.phase_y & 0x1f) == 1) { /* y-direction */ | ||
1538 | *x_direct = 0; | ||
1539 | |||
1540 | iq_point[0] = cross[0]; | ||
1541 | iq_point[1] = cross[1]; | ||
1542 | iq_point[2] = cross[2]; | ||
1543 | } else { /* (0,0) or x-direction */ | ||
1544 | *x_direct = 1; | ||
1545 | |||
1546 | iq_point[0] = cross[0]; | ||
1547 | iq_point[1] = cross[3]; | ||
1548 | iq_point[2] = cross[4]; | ||
1549 | } | ||
1550 | return 0; | ||
1551 | } | ||
1552 | |||
1553 | static void r820t_compre_cor(struct r820t_sect_type iq[3]) | ||
1554 | { | ||
1555 | int i; | ||
1556 | |||
1557 | for (i = 3; i > 0; i--) { | ||
1558 | if (iq[0].value > iq[i - 1].value) | ||
1559 | swap(iq[0], iq[i - 1]); | ||
1560 | } | ||
1561 | } | ||
1562 | |||
1563 | static int r820t_compre_step(struct r820t_priv *priv, | ||
1564 | struct r820t_sect_type iq[3], u8 reg) | ||
1565 | { | ||
1566 | int rc; | ||
1567 | struct r820t_sect_type tmp; | ||
1568 | |||
1569 | /* | ||
1570 | * Purpose: if (Gain<9 or Phase<9), Gain+1 or Phase+1 and compare | ||
1571 | * with min value: | ||
1572 | * new < min => update to min and continue | ||
1573 | * new > min => Exit | ||
1574 | */ | ||
1575 | |||
1576 | /* min value already saved in iq[0] */ | ||
1577 | tmp.phase_y = iq[0].phase_y; | ||
1578 | tmp.gain_x = iq[0].gain_x; | ||
1579 | |||
1580 | while (((tmp.gain_x & 0x1f) < IMR_TRIAL) && | ||
1581 | ((tmp.phase_y & 0x1f) < IMR_TRIAL)) { | ||
1582 | if (reg == 0x08) | ||
1583 | tmp.gain_x++; | ||
1584 | else | ||
1585 | tmp.phase_y++; | ||
1586 | |||
1587 | rc = r820t_write_reg(priv, 0x08, tmp.gain_x); | ||
1588 | if (rc < 0) | ||
1589 | return rc; | ||
1590 | |||
1591 | rc = r820t_write_reg(priv, 0x09, tmp.phase_y); | ||
1592 | if (rc < 0) | ||
1593 | return rc; | ||
1594 | |||
1595 | rc = r820t_multi_read(priv); | ||
1596 | if (rc < 0) | ||
1597 | return rc; | ||
1598 | tmp.value = rc; | ||
1599 | |||
1600 | if (tmp.value <= iq[0].value) { | ||
1601 | iq[0].gain_x = tmp.gain_x; | ||
1602 | iq[0].phase_y = tmp.phase_y; | ||
1603 | iq[0].value = tmp.value; | ||
1604 | } else { | ||
1605 | return 0; | ||
1606 | } | ||
1607 | |||
1608 | } | ||
1609 | |||
1610 | return 0; | ||
1611 | } | ||
1612 | |||
1613 | static int r820t_iq_tree(struct r820t_priv *priv, | ||
1614 | struct r820t_sect_type iq[3], | ||
1615 | u8 fix_val, u8 var_val, u8 fix_reg) | ||
1616 | { | ||
1617 | int rc, i; | ||
1618 | u8 tmp, var_reg; | ||
1619 | |||
1620 | /* | ||
1621 | * record IMC results by input gain/phase location then adjust | ||
1622 | * gain or phase positive 1 step and negtive 1 step, | ||
1623 | * both record results | ||
1624 | */ | ||
1625 | |||
1626 | if (fix_reg == 0x08) | ||
1627 | var_reg = 0x09; | ||
1628 | else | ||
1629 | var_reg = 0x08; | ||
1630 | |||
1631 | for (i = 0; i < 3; i++) { | ||
1632 | rc = r820t_write_reg(priv, fix_reg, fix_val); | ||
1633 | if (rc < 0) | ||
1634 | return rc; | ||
1635 | |||
1636 | rc = r820t_write_reg(priv, var_reg, var_val); | ||
1637 | if (rc < 0) | ||
1638 | return rc; | ||
1639 | |||
1640 | rc = r820t_multi_read(priv); | ||
1641 | if (rc < 0) | ||
1642 | return rc; | ||
1643 | iq[i].value = rc; | ||
1644 | |||
1645 | if (fix_reg == 0x08) { | ||
1646 | iq[i].gain_x = fix_val; | ||
1647 | iq[i].phase_y = var_val; | ||
1648 | } else { | ||
1649 | iq[i].phase_y = fix_val; | ||
1650 | iq[i].gain_x = var_val; | ||
1651 | } | ||
1652 | |||
1653 | if (i == 0) { /* try right-side point */ | ||
1654 | var_val++; | ||
1655 | } else if (i == 1) { /* try left-side point */ | ||
1656 | /* if absolute location is 1, change I/Q direction */ | ||
1657 | if ((var_val & 0x1f) < 0x02) { | ||
1658 | tmp = 2 - (var_val & 0x1f); | ||
1659 | |||
1660 | /* b[5]:I/Q selection. 0:Q-path, 1:I-path */ | ||
1661 | if (var_val & 0x20) { | ||
1662 | var_val &= 0xc0; | ||
1663 | var_val |= tmp; | ||
1664 | } else { | ||
1665 | var_val |= 0x20 | tmp; | ||
1666 | } | ||
1667 | } else { | ||
1668 | var_val -= 2; | ||
1669 | } | ||
1670 | } | ||
1671 | } | ||
1672 | |||
1673 | return 0; | ||
1674 | } | ||
1675 | |||
1676 | static int r820t_section(struct r820t_priv *priv, | ||
1677 | struct r820t_sect_type *iq_point) | ||
1678 | { | ||
1679 | int rc; | ||
1680 | struct r820t_sect_type compare_iq[3], compare_bet[3]; | ||
1681 | |||
1682 | /* Try X-1 column and save min result to compare_bet[0] */ | ||
1683 | if (!(iq_point->gain_x & 0x1f)) | ||
1684 | compare_iq[0].gain_x = ((iq_point->gain_x) & 0xdf) + 1; /* Q-path, Gain=1 */ | ||
1685 | else | ||
1686 | compare_iq[0].gain_x = iq_point->gain_x - 1; /* left point */ | ||
1687 | compare_iq[0].phase_y = iq_point->phase_y; | ||
1688 | |||
1689 | /* y-direction */ | ||
1690 | rc = r820t_iq_tree(priv, compare_iq, compare_iq[0].gain_x, | ||
1691 | compare_iq[0].phase_y, 0x08); | ||
1692 | if (rc < 0) | ||
1693 | return rc; | ||
1694 | |||
1695 | r820t_compre_cor(compare_iq); | ||
1696 | |||
1697 | compare_bet[0] = compare_iq[0]; | ||
1698 | |||
1699 | /* Try X column and save min result to compare_bet[1] */ | ||
1700 | compare_iq[0].gain_x = iq_point->gain_x; | ||
1701 | compare_iq[0].phase_y = iq_point->phase_y; | ||
1702 | |||
1703 | rc = r820t_iq_tree(priv, compare_iq, compare_iq[0].gain_x, | ||
1704 | compare_iq[0].phase_y, 0x08); | ||
1705 | if (rc < 0) | ||
1706 | return rc; | ||
1707 | |||
1708 | r820t_compre_cor(compare_iq); | ||
1709 | |||
1710 | compare_bet[1] = compare_iq[0]; | ||
1711 | |||
1712 | /* Try X+1 column and save min result to compare_bet[2] */ | ||
1713 | if ((iq_point->gain_x & 0x1f) == 0x00) | ||
1714 | compare_iq[0].gain_x = ((iq_point->gain_x) | 0x20) + 1; /* I-path, Gain=1 */ | ||
1715 | else | ||
1716 | compare_iq[0].gain_x = iq_point->gain_x + 1; | ||
1717 | compare_iq[0].phase_y = iq_point->phase_y; | ||
1718 | |||
1719 | rc = r820t_iq_tree(priv, compare_iq, compare_iq[0].gain_x, | ||
1720 | compare_iq[0].phase_y, 0x08); | ||
1721 | if (rc < 0) | ||
1722 | return rc; | ||
1723 | |||
1724 | r820t_compre_cor(compare_iq); | ||
1725 | |||
1726 | compare_bet[2] = compare_iq[0]; | ||
1727 | |||
1728 | r820t_compre_cor(compare_bet); | ||
1729 | |||
1730 | *iq_point = compare_bet[0]; | ||
1731 | |||
1732 | return 0; | ||
1733 | } | ||
1734 | |||
1735 | static int r820t_vga_adjust(struct r820t_priv *priv) | ||
1736 | { | ||
1737 | int rc; | ||
1738 | u8 vga_count; | ||
1739 | |||
1740 | /* increase vga power to let image significant */ | ||
1741 | for (vga_count = 12; vga_count < 16; vga_count++) { | ||
1742 | rc = r820t_write_reg_mask(priv, 0x0c, vga_count, 0x0f); | ||
1743 | if (rc < 0) | ||
1744 | return rc; | ||
1745 | |||
1746 | usleep_range(10000, 11000); | ||
1747 | |||
1748 | rc = r820t_multi_read(priv); | ||
1749 | if (rc < 0) | ||
1750 | return rc; | ||
1751 | |||
1752 | if (rc > 40 * 4) | ||
1753 | break; | ||
1754 | } | ||
1755 | |||
1756 | return 0; | ||
1757 | } | ||
1758 | |||
1759 | static int r820t_iq(struct r820t_priv *priv, struct r820t_sect_type *iq_pont) | ||
1760 | { | ||
1761 | struct r820t_sect_type compare_iq[3]; | ||
1762 | int rc; | ||
1763 | u8 x_direction = 0; /* 1:x, 0:y */ | ||
1764 | u8 dir_reg, other_reg; | ||
1765 | |||
1766 | r820t_vga_adjust(priv); | ||
1767 | |||
1768 | rc = r820t_imr_cross(priv, compare_iq, &x_direction); | ||
1769 | if (rc < 0) | ||
1770 | return rc; | ||
1771 | |||
1772 | if (x_direction == 1) { | ||
1773 | dir_reg = 0x08; | ||
1774 | other_reg = 0x09; | ||
1775 | } else { | ||
1776 | dir_reg = 0x09; | ||
1777 | other_reg = 0x08; | ||
1778 | } | ||
1779 | |||
1780 | /* compare and find min of 3 points. determine i/q direction */ | ||
1781 | r820t_compre_cor(compare_iq); | ||
1782 | |||
1783 | /* increase step to find min value of this direction */ | ||
1784 | rc = r820t_compre_step(priv, compare_iq, dir_reg); | ||
1785 | if (rc < 0) | ||
1786 | return rc; | ||
1787 | |||
1788 | /* the other direction */ | ||
1789 | rc = r820t_iq_tree(priv, compare_iq, compare_iq[0].gain_x, | ||
1790 | compare_iq[0].phase_y, dir_reg); | ||
1791 | if (rc < 0) | ||
1792 | return rc; | ||
1793 | |||
1794 | /* compare and find min of 3 points. determine i/q direction */ | ||
1795 | r820t_compre_cor(compare_iq); | ||
1796 | |||
1797 | /* increase step to find min value on this direction */ | ||
1798 | rc = r820t_compre_step(priv, compare_iq, other_reg); | ||
1799 | if (rc < 0) | ||
1800 | return rc; | ||
1801 | |||
1802 | /* check 3 points again */ | ||
1803 | rc = r820t_iq_tree(priv, compare_iq, compare_iq[0].gain_x, | ||
1804 | compare_iq[0].phase_y, other_reg); | ||
1805 | if (rc < 0) | ||
1806 | return rc; | ||
1807 | |||
1808 | r820t_compre_cor(compare_iq); | ||
1809 | |||
1810 | /* section-9 check */ | ||
1811 | rc = r820t_section(priv, compare_iq); | ||
1812 | |||
1813 | *iq_pont = compare_iq[0]; | ||
1814 | |||
1815 | /* reset gain/phase control setting */ | ||
1816 | rc = r820t_write_reg_mask(priv, 0x08, 0, 0x3f); | ||
1817 | if (rc < 0) | ||
1818 | return rc; | ||
1819 | |||
1820 | rc = r820t_write_reg_mask(priv, 0x09, 0, 0x3f); | ||
1821 | |||
1822 | return rc; | ||
1823 | } | ||
1824 | |||
1825 | static int r820t_f_imr(struct r820t_priv *priv, struct r820t_sect_type *iq_pont) | ||
1826 | { | ||
1827 | int rc; | ||
1828 | |||
1829 | r820t_vga_adjust(priv); | ||
1830 | |||
1831 | /* | ||
1832 | * search surrounding points from previous point | ||
1833 | * try (x-1), (x), (x+1) columns, and find min IMR result point | ||
1834 | */ | ||
1835 | rc = r820t_section(priv, iq_pont); | ||
1836 | if (rc < 0) | ||
1837 | return rc; | ||
1838 | |||
1839 | return 0; | ||
1840 | } | ||
1841 | |||
1842 | static int r820t_imr(struct r820t_priv *priv, unsigned imr_mem, bool im_flag) | ||
1843 | { | ||
1844 | struct r820t_sect_type imr_point; | ||
1845 | int rc; | ||
1846 | u32 ring_vco, ring_freq, ring_ref; | ||
1847 | u8 n_ring, n; | ||
1848 | int reg18, reg19, reg1f; | ||
1849 | |||
1850 | if (priv->cfg->xtal > 24000000) | ||
1851 | ring_ref = priv->cfg->xtal / 2; | ||
1852 | else | ||
1853 | ring_ref = priv->cfg->xtal; | ||
1854 | |||
1855 | for (n = 0; n < 16; n++) { | ||
1856 | if ((16 + n) * 8 * ring_ref >= 3100000) { | ||
1857 | n_ring = n; | ||
1858 | break; | ||
1859 | } | ||
1860 | |||
1861 | /* n_ring not found */ | ||
1862 | if (n == 15) | ||
1863 | n_ring = n; | ||
1864 | } | ||
1865 | |||
1866 | reg18 = r820t_read_cache_reg(priv, 0x18); | ||
1867 | reg19 = r820t_read_cache_reg(priv, 0x19); | ||
1868 | reg1f = r820t_read_cache_reg(priv, 0x1f); | ||
1869 | |||
1870 | reg18 &= 0xf0; /* set ring[3:0] */ | ||
1871 | reg18 |= n_ring; | ||
1872 | |||
1873 | ring_vco = (16 + n_ring) * 8 * ring_ref; | ||
1874 | |||
1875 | reg18 &= 0xdf; /* clear ring_se23 */ | ||
1876 | reg19 &= 0xfc; /* clear ring_seldiv */ | ||
1877 | reg1f &= 0xfc; /* clear ring_att */ | ||
1878 | |||
1879 | switch (imr_mem) { | ||
1880 | case 0: | ||
1881 | ring_freq = ring_vco / 48; | ||
1882 | reg18 |= 0x20; /* ring_se23 = 1 */ | ||
1883 | reg19 |= 0x03; /* ring_seldiv = 3 */ | ||
1884 | reg1f |= 0x02; /* ring_att 10 */ | ||
1885 | break; | ||
1886 | case 1: | ||
1887 | ring_freq = ring_vco / 16; | ||
1888 | reg18 |= 0x00; /* ring_se23 = 0 */ | ||
1889 | reg19 |= 0x02; /* ring_seldiv = 2 */ | ||
1890 | reg1f |= 0x00; /* pw_ring 00 */ | ||
1891 | break; | ||
1892 | case 2: | ||
1893 | ring_freq = ring_vco / 8; | ||
1894 | reg18 |= 0x00; /* ring_se23 = 0 */ | ||
1895 | reg19 |= 0x01; /* ring_seldiv = 1 */ | ||
1896 | reg1f |= 0x03; /* pw_ring 11 */ | ||
1897 | break; | ||
1898 | case 3: | ||
1899 | ring_freq = ring_vco / 6; | ||
1900 | reg18 |= 0x20; /* ring_se23 = 1 */ | ||
1901 | reg19 |= 0x00; /* ring_seldiv = 0 */ | ||
1902 | reg1f |= 0x03; /* pw_ring 11 */ | ||
1903 | break; | ||
1904 | case 4: | ||
1905 | ring_freq = ring_vco / 4; | ||
1906 | reg18 |= 0x00; /* ring_se23 = 0 */ | ||
1907 | reg19 |= 0x00; /* ring_seldiv = 0 */ | ||
1908 | reg1f |= 0x01; /* pw_ring 01 */ | ||
1909 | break; | ||
1910 | default: | ||
1911 | ring_freq = ring_vco / 4; | ||
1912 | reg18 |= 0x00; /* ring_se23 = 0 */ | ||
1913 | reg19 |= 0x00; /* ring_seldiv = 0 */ | ||
1914 | reg1f |= 0x01; /* pw_ring 01 */ | ||
1915 | break; | ||
1916 | } | ||
1917 | |||
1918 | |||
1919 | /* write pw_ring, n_ring, ringdiv2 registers */ | ||
1920 | |||
1921 | /* n_ring, ring_se23 */ | ||
1922 | rc = r820t_write_reg(priv, 0x18, reg18); | ||
1923 | if (rc < 0) | ||
1924 | return rc; | ||
1925 | |||
1926 | /* ring_sediv */ | ||
1927 | rc = r820t_write_reg(priv, 0x19, reg19); | ||
1928 | if (rc < 0) | ||
1929 | return rc; | ||
1930 | |||
1931 | /* pw_ring */ | ||
1932 | rc = r820t_write_reg(priv, 0x1f, reg1f); | ||
1933 | if (rc < 0) | ||
1934 | return rc; | ||
1935 | |||
1936 | /* mux input freq ~ rf_in freq */ | ||
1937 | rc = r820t_set_mux(priv, (ring_freq - 5300) * 1000); | ||
1938 | if (rc < 0) | ||
1939 | return rc; | ||
1940 | |||
1941 | rc = r820t_set_pll(priv, V4L2_TUNER_DIGITAL_TV, | ||
1942 | (ring_freq - 5300) * 1000); | ||
1943 | if (!priv->has_lock) | ||
1944 | rc = -EINVAL; | ||
1945 | if (rc < 0) | ||
1946 | return rc; | ||
1947 | |||
1948 | if (im_flag) { | ||
1949 | rc = r820t_iq(priv, &imr_point); | ||
1950 | } else { | ||
1951 | imr_point.gain_x = priv->imr_data[3].gain_x; | ||
1952 | imr_point.phase_y = priv->imr_data[3].phase_y; | ||
1953 | imr_point.value = priv->imr_data[3].value; | ||
1954 | |||
1955 | rc = r820t_f_imr(priv, &imr_point); | ||
1956 | } | ||
1957 | if (rc < 0) | ||
1958 | return rc; | ||
1959 | |||
1960 | /* save IMR value */ | ||
1961 | switch (imr_mem) { | ||
1962 | case 0: | ||
1963 | priv->imr_data[0].gain_x = imr_point.gain_x; | ||
1964 | priv->imr_data[0].phase_y = imr_point.phase_y; | ||
1965 | priv->imr_data[0].value = imr_point.value; | ||
1966 | break; | ||
1967 | case 1: | ||
1968 | priv->imr_data[1].gain_x = imr_point.gain_x; | ||
1969 | priv->imr_data[1].phase_y = imr_point.phase_y; | ||
1970 | priv->imr_data[1].value = imr_point.value; | ||
1971 | break; | ||
1972 | case 2: | ||
1973 | priv->imr_data[2].gain_x = imr_point.gain_x; | ||
1974 | priv->imr_data[2].phase_y = imr_point.phase_y; | ||
1975 | priv->imr_data[2].value = imr_point.value; | ||
1976 | break; | ||
1977 | case 3: | ||
1978 | priv->imr_data[3].gain_x = imr_point.gain_x; | ||
1979 | priv->imr_data[3].phase_y = imr_point.phase_y; | ||
1980 | priv->imr_data[3].value = imr_point.value; | ||
1981 | break; | ||
1982 | case 4: | ||
1983 | priv->imr_data[4].gain_x = imr_point.gain_x; | ||
1984 | priv->imr_data[4].phase_y = imr_point.phase_y; | ||
1985 | priv->imr_data[4].value = imr_point.value; | ||
1986 | break; | ||
1987 | default: | ||
1988 | priv->imr_data[4].gain_x = imr_point.gain_x; | ||
1989 | priv->imr_data[4].phase_y = imr_point.phase_y; | ||
1990 | priv->imr_data[4].value = imr_point.value; | ||
1991 | break; | ||
1992 | } | ||
1993 | |||
1994 | return 0; | ||
1995 | } | ||
1996 | |||
1997 | static int r820t_imr_callibrate(struct r820t_priv *priv) | ||
1393 | { | 1998 | { |
1394 | struct r820t_priv *priv = fe->tuner_priv; | ||
1395 | int rc, i; | 1999 | int rc, i; |
1396 | int xtal_cap = 0; | 2000 | int xtal_cap = 0; |
1397 | 2001 | ||
1398 | tuner_dbg("%s:\n", __func__); | 2002 | if (priv->imr_done) |
2003 | return 0; | ||
1399 | 2004 | ||
1400 | mutex_lock(&priv->lock); | 2005 | /* Initialize registers */ |
1401 | if (fe->ops.i2c_gate_ctrl) | 2006 | rc = r820t_write(priv, 0x05, |
1402 | fe->ops.i2c_gate_ctrl(fe, 1); | 2007 | r820t_init_array, sizeof(r820t_init_array)); |
2008 | if (rc < 0) | ||
2009 | return rc; | ||
1403 | 2010 | ||
2011 | /* Detect Xtal capacitance */ | ||
1404 | if ((priv->cfg->rafael_chip == CHIP_R820T) || | 2012 | if ((priv->cfg->rafael_chip == CHIP_R820T) || |
1405 | (priv->cfg->rafael_chip == CHIP_R828S) || | 2013 | (priv->cfg->rafael_chip == CHIP_R828S) || |
1406 | (priv->cfg->rafael_chip == CHIP_R820C)) { | 2014 | (priv->cfg->rafael_chip == CHIP_R820C)) { |
@@ -1409,7 +2017,7 @@ static int r820t_init(struct dvb_frontend *fe) | |||
1409 | for (i = 0; i < 3; i++) { | 2017 | for (i = 0; i < 3; i++) { |
1410 | rc = r820t_xtal_check(priv); | 2018 | rc = r820t_xtal_check(priv); |
1411 | if (rc < 0) | 2019 | if (rc < 0) |
1412 | goto err; | 2020 | return rc; |
1413 | if (!i || rc > xtal_cap) | 2021 | if (!i || rc > xtal_cap) |
1414 | xtal_cap = rc; | 2022 | xtal_cap = rc; |
1415 | } | 2023 | } |
@@ -1419,6 +2027,58 @@ static int r820t_init(struct dvb_frontend *fe) | |||
1419 | /* Initialize registers */ | 2027 | /* Initialize registers */ |
1420 | rc = r820t_write(priv, 0x05, | 2028 | rc = r820t_write(priv, 0x05, |
1421 | r820t_init_array, sizeof(r820t_init_array)); | 2029 | r820t_init_array, sizeof(r820t_init_array)); |
2030 | if (rc < 0) | ||
2031 | return rc; | ||
2032 | |||
2033 | rc = r820t_imr_prepare(priv); | ||
2034 | if (rc < 0) | ||
2035 | return rc; | ||
2036 | |||
2037 | rc = r820t_imr(priv, 3, true); | ||
2038 | if (rc < 0) | ||
2039 | return rc; | ||
2040 | rc = r820t_imr(priv, 1, false); | ||
2041 | if (rc < 0) | ||
2042 | return rc; | ||
2043 | rc = r820t_imr(priv, 0, false); | ||
2044 | if (rc < 0) | ||
2045 | return rc; | ||
2046 | rc = r820t_imr(priv, 2, false); | ||
2047 | if (rc < 0) | ||
2048 | return rc; | ||
2049 | rc = r820t_imr(priv, 4, false); | ||
2050 | if (rc < 0) | ||
2051 | return rc; | ||
2052 | |||
2053 | priv->imr_done = true; | ||
2054 | |||
2055 | return 0; | ||
2056 | } | ||
2057 | |||
2058 | /* | ||
2059 | * r820t frontend operations and tuner attach code | ||
2060 | * | ||
2061 | * All driver locks and i2c control are only in this part of the code | ||
2062 | */ | ||
2063 | |||
2064 | static int r820t_init(struct dvb_frontend *fe) | ||
2065 | { | ||
2066 | struct r820t_priv *priv = fe->tuner_priv; | ||
2067 | int rc; | ||
2068 | |||
2069 | tuner_dbg("%s:\n", __func__); | ||
2070 | |||
2071 | mutex_lock(&priv->lock); | ||
2072 | if (fe->ops.i2c_gate_ctrl) | ||
2073 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
2074 | |||
2075 | rc = r820t_imr_callibrate(priv); | ||
2076 | if (rc < 0) | ||
2077 | goto err; | ||
2078 | |||
2079 | /* Initialize registers */ | ||
2080 | rc = r820t_write(priv, 0x05, | ||
2081 | r820t_init_array, sizeof(r820t_init_array)); | ||
1422 | 2082 | ||
1423 | err: | 2083 | err: |
1424 | if (fe->ops.i2c_gate_ctrl) | 2084 | if (fe->ops.i2c_gate_ctrl) |