aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/arizona.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/arizona.c')
-rw-r--r--sound/soc/codecs/arizona.c254
1 files changed, 168 insertions, 86 deletions
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c
index a32b84ac03f6..29e198f57d4c 100644
--- a/sound/soc/codecs/arizona.c
+++ b/sound/soc/codecs/arizona.c
@@ -53,6 +53,14 @@
53#define ARIZONA_AIF_RX_ENABLES 0x1A 53#define ARIZONA_AIF_RX_ENABLES 0x1A
54#define ARIZONA_AIF_FORCE_WRITE 0x1B 54#define ARIZONA_AIF_FORCE_WRITE 0x1B
55 55
56#define ARIZONA_FLL_VCO_CORNER 141900000
57#define ARIZONA_FLL_MAX_FREF 13500000
58#define ARIZONA_FLL_MIN_FVCO 90000000
59#define ARIZONA_FLL_MAX_FRATIO 16
60#define ARIZONA_FLL_MAX_REFDIV 8
61#define ARIZONA_FLL_MIN_OUTDIV 2
62#define ARIZONA_FLL_MAX_OUTDIV 7
63
56#define arizona_fll_err(_fll, fmt, ...) \ 64#define arizona_fll_err(_fll, fmt, ...) \
57 dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__) 65 dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
58#define arizona_fll_warn(_fll, fmt, ...) \ 66#define arizona_fll_warn(_fll, fmt, ...) \
@@ -1386,74 +1394,147 @@ struct arizona_fll_cfg {
1386 int gain; 1394 int gain;
1387}; 1395};
1388 1396
1389static int arizona_calc_fll(struct arizona_fll *fll, 1397static int arizona_validate_fll(struct arizona_fll *fll,
1390 struct arizona_fll_cfg *cfg, 1398 unsigned int Fref,
1391 unsigned int Fref, 1399 unsigned int Fout)
1392 unsigned int Fout)
1393{ 1400{
1394 unsigned int target, div, gcd_fll; 1401 unsigned int Fvco_min;
1395 int i, ratio; 1402
1403 if (Fref / ARIZONA_FLL_MAX_REFDIV > ARIZONA_FLL_MAX_FREF) {
1404 arizona_fll_err(fll,
1405 "Can't scale %dMHz in to <=13.5MHz\n",
1406 Fref);
1407 return -EINVAL;
1408 }
1396 1409
1397 arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, Fout); 1410 Fvco_min = ARIZONA_FLL_MIN_FVCO * fll->vco_mult;
1411 if (Fout * ARIZONA_FLL_MAX_OUTDIV < Fvco_min) {
1412 arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
1413 Fout);
1414 return -EINVAL;
1415 }
1416
1417 return 0;
1418}
1419
1420static int arizona_find_fratio(unsigned int Fref, int *fratio)
1421{
1422 int i;
1423
1424 /* Find an appropriate FLL_FRATIO */
1425 for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
1426 if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
1427 if (fratio)
1428 *fratio = fll_fratios[i].fratio;
1429 return fll_fratios[i].ratio;
1430 }
1431 }
1432
1433 return -EINVAL;
1434}
1435
1436static int arizona_calc_fratio(struct arizona_fll *fll,
1437 struct arizona_fll_cfg *cfg,
1438 unsigned int target,
1439 unsigned int Fref, bool sync)
1440{
1441 int init_ratio, ratio;
1442 int refdiv, div;
1398 1443
1399 /* Fref must be <=13.5MHz */ 1444 /* Fref must be <=13.5MHz, find initial refdiv */
1400 div = 1; 1445 div = 1;
1401 cfg->refdiv = 0; 1446 cfg->refdiv = 0;
1402 while ((Fref / div) > 13500000) { 1447 while (Fref > ARIZONA_FLL_MAX_FREF) {
1403 div *= 2; 1448 div *= 2;
1449 Fref /= 2;
1404 cfg->refdiv++; 1450 cfg->refdiv++;
1405 1451
1406 if (div > 8) { 1452 if (div > ARIZONA_FLL_MAX_REFDIV)
1407 arizona_fll_err(fll,
1408 "Can't scale %dMHz in to <=13.5MHz\n",
1409 Fref);
1410 return -EINVAL; 1453 return -EINVAL;
1454 }
1455
1456 /* Find an appropriate FLL_FRATIO */
1457 init_ratio = arizona_find_fratio(Fref, &cfg->fratio);
1458 if (init_ratio < 0) {
1459 arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
1460 Fref);
1461 return init_ratio;
1462 }
1463
1464 switch (fll->arizona->type) {
1465 case WM5110:
1466 if (fll->arizona->rev < 3 || sync)
1467 return init_ratio;
1468 break;
1469 default:
1470 return init_ratio;
1471 }
1472
1473 cfg->fratio = init_ratio - 1;
1474
1475 /* Adjust FRATIO/refdiv to avoid integer mode if possible */
1476 refdiv = cfg->refdiv;
1477
1478 while (div <= ARIZONA_FLL_MAX_REFDIV) {
1479 for (ratio = init_ratio; ratio <= ARIZONA_FLL_MAX_FRATIO;
1480 ratio++) {
1481 if (target % (ratio * Fref)) {
1482 cfg->refdiv = refdiv;
1483 cfg->fratio = ratio - 1;
1484 return ratio;
1485 }
1411 } 1486 }
1487
1488 for (ratio = init_ratio - 1; ratio >= 0; ratio--) {
1489 if (ARIZONA_FLL_VCO_CORNER / (fll->vco_mult * ratio) <
1490 Fref)
1491 break;
1492
1493 if (target % (ratio * Fref)) {
1494 cfg->refdiv = refdiv;
1495 cfg->fratio = ratio - 1;
1496 return ratio;
1497 }
1498 }
1499
1500 div *= 2;
1501 Fref /= 2;
1502 refdiv++;
1503 init_ratio = arizona_find_fratio(Fref, NULL);
1412 } 1504 }
1413 1505
1414 /* Apply the division for our remaining calculations */ 1506 arizona_fll_warn(fll, "Falling back to integer mode operation\n");
1415 Fref /= div; 1507 return cfg->fratio + 1;
1508}
1509
1510static int arizona_calc_fll(struct arizona_fll *fll,
1511 struct arizona_fll_cfg *cfg,
1512 unsigned int Fref, bool sync)
1513{
1514 unsigned int target, div, gcd_fll;
1515 int i, ratio;
1516
1517 arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, fll->fout);
1416 1518
1417 /* Fvco should be over the targt; don't check the upper bound */ 1519 /* Fvco should be over the targt; don't check the upper bound */
1418 div = 1; 1520 div = ARIZONA_FLL_MIN_OUTDIV;
1419 while (Fout * div < 90000000 * fll->vco_mult) { 1521 while (fll->fout * div < ARIZONA_FLL_MIN_FVCO * fll->vco_mult) {
1420 div++; 1522 div++;
1421 if (div > 7) { 1523 if (div > ARIZONA_FLL_MAX_OUTDIV)
1422 arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
1423 Fout);
1424 return -EINVAL; 1524 return -EINVAL;
1425 }
1426 } 1525 }
1427 target = Fout * div / fll->vco_mult; 1526 target = fll->fout * div / fll->vco_mult;
1428 cfg->outdiv = div; 1527 cfg->outdiv = div;
1429 1528
1430 arizona_fll_dbg(fll, "Fvco=%dHz\n", target); 1529 arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
1431 1530
1432 /* Find an appropraite FLL_FRATIO and factor it out of the target */ 1531 /* Find an appropriate FLL_FRATIO and refdiv */
1433 for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) { 1532 ratio = arizona_calc_fratio(fll, cfg, target, Fref, sync);
1434 if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) { 1533 if (ratio < 0)
1435 cfg->fratio = fll_fratios[i].fratio; 1534 return ratio;
1436 ratio = fll_fratios[i].ratio;
1437 break;
1438 }
1439 }
1440 if (i == ARRAY_SIZE(fll_fratios)) {
1441 arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
1442 Fref);
1443 return -EINVAL;
1444 }
1445 1535
1446 for (i = 0; i < ARRAY_SIZE(fll_gains); i++) { 1536 /* Apply the division for our remaining calculations */
1447 if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) { 1537 Fref = Fref / (1 << cfg->refdiv);
1448 cfg->gain = fll_gains[i].gain;
1449 break;
1450 }
1451 }
1452 if (i == ARRAY_SIZE(fll_gains)) {
1453 arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n",
1454 Fref);
1455 return -EINVAL;
1456 }
1457 1538
1458 cfg->n = target / (ratio * Fref); 1539 cfg->n = target / (ratio * Fref);
1459 1540
@@ -1478,6 +1559,18 @@ static int arizona_calc_fll(struct arizona_fll *fll,
1478 cfg->lambda >>= 1; 1559 cfg->lambda >>= 1;
1479 } 1560 }
1480 1561
1562 for (i = 0; i < ARRAY_SIZE(fll_gains); i++) {
1563 if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) {
1564 cfg->gain = fll_gains[i].gain;
1565 break;
1566 }
1567 }
1568 if (i == ARRAY_SIZE(fll_gains)) {
1569 arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n",
1570 Fref);
1571 return -EINVAL;
1572 }
1573
1481 arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n", 1574 arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
1482 cfg->n, cfg->theta, cfg->lambda); 1575 cfg->n, cfg->theta, cfg->lambda);
1483 arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n", 1576 arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
@@ -1505,14 +1598,18 @@ static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
1505 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT | 1598 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
1506 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT); 1599 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
1507 1600
1508 if (sync) 1601 if (sync) {
1509 regmap_update_bits_async(arizona->regmap, base + 0x7, 1602 regmap_update_bits(arizona->regmap, base + 0x7,
1510 ARIZONA_FLL1_GAIN_MASK, 1603 ARIZONA_FLL1_GAIN_MASK,
1511 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT); 1604 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
1512 else 1605 } else {
1513 regmap_update_bits_async(arizona->regmap, base + 0x9, 1606 regmap_update_bits(arizona->regmap, base + 0x5,
1514 ARIZONA_FLL1_GAIN_MASK, 1607 ARIZONA_FLL1_OUTDIV_MASK,
1515 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT); 1608 cfg->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
1609 regmap_update_bits(arizona->regmap, base + 0x9,
1610 ARIZONA_FLL1_GAIN_MASK,
1611 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
1612 }
1516 1613
1517 regmap_update_bits_async(arizona->regmap, base + 2, 1614 regmap_update_bits_async(arizona->regmap, base + 2,
1518 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK, 1615 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
@@ -1535,13 +1632,12 @@ static bool arizona_is_enabled_fll(struct arizona_fll *fll)
1535 return reg & ARIZONA_FLL1_ENA; 1632 return reg & ARIZONA_FLL1_ENA;
1536} 1633}
1537 1634
1538static void arizona_enable_fll(struct arizona_fll *fll, 1635static void arizona_enable_fll(struct arizona_fll *fll)
1539 struct arizona_fll_cfg *ref,
1540 struct arizona_fll_cfg *sync)
1541{ 1636{
1542 struct arizona *arizona = fll->arizona; 1637 struct arizona *arizona = fll->arizona;
1543 int ret; 1638 int ret;
1544 bool use_sync = false; 1639 bool use_sync = false;
1640 struct arizona_fll_cfg cfg;
1545 1641
1546 /* 1642 /*
1547 * If we have both REFCLK and SYNCCLK then enable both, 1643 * If we have both REFCLK and SYNCCLK then enable both,
@@ -1549,23 +1645,21 @@ static void arizona_enable_fll(struct arizona_fll *fll,
1549 */ 1645 */
1550 if (fll->ref_src >= 0 && fll->ref_freq && 1646 if (fll->ref_src >= 0 && fll->ref_freq &&
1551 fll->ref_src != fll->sync_src) { 1647 fll->ref_src != fll->sync_src) {
1552 regmap_update_bits_async(arizona->regmap, fll->base + 5, 1648 arizona_calc_fll(fll, &cfg, fll->ref_freq, false);
1553 ARIZONA_FLL1_OUTDIV_MASK,
1554 ref->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
1555 1649
1556 arizona_apply_fll(arizona, fll->base, ref, fll->ref_src, 1650 arizona_apply_fll(arizona, fll->base, &cfg, fll->ref_src,
1557 false); 1651 false);
1558 if (fll->sync_src >= 0) { 1652 if (fll->sync_src >= 0) {
1559 arizona_apply_fll(arizona, fll->base + 0x10, sync, 1653 arizona_calc_fll(fll, &cfg, fll->sync_freq, true);
1654
1655 arizona_apply_fll(arizona, fll->base + 0x10, &cfg,
1560 fll->sync_src, true); 1656 fll->sync_src, true);
1561 use_sync = true; 1657 use_sync = true;
1562 } 1658 }
1563 } else if (fll->sync_src >= 0) { 1659 } else if (fll->sync_src >= 0) {
1564 regmap_update_bits_async(arizona->regmap, fll->base + 5, 1660 arizona_calc_fll(fll, &cfg, fll->sync_freq, false);
1565 ARIZONA_FLL1_OUTDIV_MASK,
1566 sync->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
1567 1661
1568 arizona_apply_fll(arizona, fll->base, sync, 1662 arizona_apply_fll(arizona, fll->base, &cfg,
1569 fll->sync_src, false); 1663 fll->sync_src, false);
1570 1664
1571 regmap_update_bits_async(arizona->regmap, fll->base + 0x11, 1665 regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
@@ -1627,32 +1721,22 @@ static void arizona_disable_fll(struct arizona_fll *fll)
1627int arizona_set_fll_refclk(struct arizona_fll *fll, int source, 1721int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
1628 unsigned int Fref, unsigned int Fout) 1722 unsigned int Fref, unsigned int Fout)
1629{ 1723{
1630 struct arizona_fll_cfg ref, sync;
1631 int ret; 1724 int ret;
1632 1725
1633 if (fll->ref_src == source && fll->ref_freq == Fref) 1726 if (fll->ref_src == source && fll->ref_freq == Fref)
1634 return 0; 1727 return 0;
1635 1728
1636 if (fll->fout) { 1729 if (fll->fout && Fref > 0) {
1637 if (Fref > 0) { 1730 ret = arizona_validate_fll(fll, Fref, fll->fout);
1638 ret = arizona_calc_fll(fll, &ref, Fref, fll->fout); 1731 if (ret != 0)
1639 if (ret != 0) 1732 return ret;
1640 return ret;
1641 }
1642
1643 if (fll->sync_src >= 0) {
1644 ret = arizona_calc_fll(fll, &sync, fll->sync_freq,
1645 fll->fout);
1646 if (ret != 0)
1647 return ret;
1648 }
1649 } 1733 }
1650 1734
1651 fll->ref_src = source; 1735 fll->ref_src = source;
1652 fll->ref_freq = Fref; 1736 fll->ref_freq = Fref;
1653 1737
1654 if (fll->fout && Fref > 0) { 1738 if (fll->fout && Fref > 0) {
1655 arizona_enable_fll(fll, &ref, &sync); 1739 arizona_enable_fll(fll);
1656 } 1740 }
1657 1741
1658 return 0; 1742 return 0;
@@ -1662,7 +1746,6 @@ EXPORT_SYMBOL_GPL(arizona_set_fll_refclk);
1662int arizona_set_fll(struct arizona_fll *fll, int source, 1746int arizona_set_fll(struct arizona_fll *fll, int source,
1663 unsigned int Fref, unsigned int Fout) 1747 unsigned int Fref, unsigned int Fout)
1664{ 1748{
1665 struct arizona_fll_cfg ref, sync;
1666 int ret; 1749 int ret;
1667 1750
1668 if (fll->sync_src == source && 1751 if (fll->sync_src == source &&
@@ -1671,13 +1754,12 @@ int arizona_set_fll(struct arizona_fll *fll, int source,
1671 1754
1672 if (Fout) { 1755 if (Fout) {
1673 if (fll->ref_src >= 0) { 1756 if (fll->ref_src >= 0) {
1674 ret = arizona_calc_fll(fll, &ref, fll->ref_freq, 1757 ret = arizona_validate_fll(fll, fll->ref_freq, Fout);
1675 Fout);
1676 if (ret != 0) 1758 if (ret != 0)
1677 return ret; 1759 return ret;
1678 } 1760 }
1679 1761
1680 ret = arizona_calc_fll(fll, &sync, Fref, Fout); 1762 ret = arizona_validate_fll(fll, Fref, Fout);
1681 if (ret != 0) 1763 if (ret != 0)
1682 return ret; 1764 return ret;
1683 } 1765 }
@@ -1687,7 +1769,7 @@ int arizona_set_fll(struct arizona_fll *fll, int source,
1687 fll->fout = Fout; 1769 fll->fout = Fout;
1688 1770
1689 if (Fout) { 1771 if (Fout) {
1690 arizona_enable_fll(fll, &ref, &sync); 1772 arizona_enable_fll(fll);
1691 } else { 1773 } else {
1692 arizona_disable_fll(fll); 1774 arizona_disable_fll(fll);
1693 } 1775 }