diff options
Diffstat (limited to 'sound/soc/codecs/wm_adsp.c')
-rw-r--r-- | sound/soc/codecs/wm_adsp.c | 211 |
1 files changed, 129 insertions, 82 deletions
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 46ec0e9744d4..444626fcab40 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c | |||
@@ -1286,6 +1286,7 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp) | |||
1286 | reg = wm_adsp_region_to_reg(mem, | 1286 | reg = wm_adsp_region_to_reg(mem, |
1287 | reg); | 1287 | reg); |
1288 | reg += offset; | 1288 | reg += offset; |
1289 | break; | ||
1289 | } | 1290 | } |
1290 | } | 1291 | } |
1291 | 1292 | ||
@@ -1468,19 +1469,23 @@ static int wm_adsp2_ena(struct wm_adsp *dsp) | |||
1468 | unsigned int val; | 1469 | unsigned int val; |
1469 | int ret, count; | 1470 | int ret, count; |
1470 | 1471 | ||
1471 | ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, | 1472 | ret = regmap_update_bits_async(dsp->regmap, dsp->base + ADSP2_CONTROL, |
1472 | ADSP2_SYS_ENA, ADSP2_SYS_ENA); | 1473 | ADSP2_SYS_ENA, ADSP2_SYS_ENA); |
1473 | if (ret != 0) | 1474 | if (ret != 0) |
1474 | return ret; | 1475 | return ret; |
1475 | 1476 | ||
1476 | /* Wait for the RAM to start, should be near instantaneous */ | 1477 | /* Wait for the RAM to start, should be near instantaneous */ |
1477 | count = 0; | 1478 | for (count = 0; count < 10; ++count) { |
1478 | do { | ||
1479 | ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1, | 1479 | ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1, |
1480 | &val); | 1480 | &val); |
1481 | if (ret != 0) | 1481 | if (ret != 0) |
1482 | return ret; | 1482 | return ret; |
1483 | } while (!(val & ADSP2_RAM_RDY) && ++count < 10); | 1483 | |
1484 | if (val & ADSP2_RAM_RDY) | ||
1485 | break; | ||
1486 | |||
1487 | msleep(1); | ||
1488 | } | ||
1484 | 1489 | ||
1485 | if (!(val & ADSP2_RAM_RDY)) { | 1490 | if (!(val & ADSP2_RAM_RDY)) { |
1486 | adsp_err(dsp, "Failed to start DSP RAM\n"); | 1491 | adsp_err(dsp, "Failed to start DSP RAM\n"); |
@@ -1488,112 +1493,153 @@ static int wm_adsp2_ena(struct wm_adsp *dsp) | |||
1488 | } | 1493 | } |
1489 | 1494 | ||
1490 | adsp_dbg(dsp, "RAM ready after %d polls\n", count); | 1495 | adsp_dbg(dsp, "RAM ready after %d polls\n", count); |
1491 | adsp_info(dsp, "RAM ready after %d polls\n", count); | ||
1492 | 1496 | ||
1493 | return 0; | 1497 | return 0; |
1494 | } | 1498 | } |
1495 | 1499 | ||
1496 | int wm_adsp2_event(struct snd_soc_dapm_widget *w, | 1500 | static void wm_adsp2_boot_work(struct work_struct *work) |
1497 | struct snd_kcontrol *kcontrol, int event) | ||
1498 | { | 1501 | { |
1499 | struct snd_soc_codec *codec = w->codec; | 1502 | struct wm_adsp *dsp = container_of(work, |
1500 | struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); | 1503 | struct wm_adsp, |
1501 | struct wm_adsp *dsp = &dsps[w->shift]; | 1504 | boot_work); |
1502 | struct wm_adsp_alg_region *alg_region; | ||
1503 | struct wm_coeff_ctl *ctl; | ||
1504 | unsigned int val; | ||
1505 | int ret; | 1505 | int ret; |
1506 | unsigned int val; | ||
1506 | 1507 | ||
1507 | dsp->card = codec->card; | 1508 | /* |
1509 | * For simplicity set the DSP clock rate to be the | ||
1510 | * SYSCLK rate rather than making it configurable. | ||
1511 | */ | ||
1512 | ret = regmap_read(dsp->regmap, ARIZONA_SYSTEM_CLOCK_1, &val); | ||
1513 | if (ret != 0) { | ||
1514 | adsp_err(dsp, "Failed to read SYSCLK state: %d\n", ret); | ||
1515 | return; | ||
1516 | } | ||
1517 | val = (val & ARIZONA_SYSCLK_FREQ_MASK) | ||
1518 | >> ARIZONA_SYSCLK_FREQ_SHIFT; | ||
1508 | 1519 | ||
1509 | switch (event) { | 1520 | ret = regmap_update_bits_async(dsp->regmap, |
1510 | case SND_SOC_DAPM_POST_PMU: | 1521 | dsp->base + ADSP2_CLOCKING, |
1511 | /* | 1522 | ADSP2_CLK_SEL_MASK, val); |
1512 | * For simplicity set the DSP clock rate to be the | 1523 | if (ret != 0) { |
1513 | * SYSCLK rate rather than making it configurable. | 1524 | adsp_err(dsp, "Failed to set clock rate: %d\n", ret); |
1514 | */ | 1525 | return; |
1515 | ret = regmap_read(dsp->regmap, ARIZONA_SYSTEM_CLOCK_1, &val); | 1526 | } |
1516 | if (ret != 0) { | ||
1517 | adsp_err(dsp, "Failed to read SYSCLK state: %d\n", | ||
1518 | ret); | ||
1519 | return ret; | ||
1520 | } | ||
1521 | val = (val & ARIZONA_SYSCLK_FREQ_MASK) | ||
1522 | >> ARIZONA_SYSCLK_FREQ_SHIFT; | ||
1523 | 1527 | ||
1524 | ret = regmap_update_bits(dsp->regmap, | 1528 | if (dsp->dvfs) { |
1525 | dsp->base + ADSP2_CLOCKING, | 1529 | ret = regmap_read(dsp->regmap, |
1526 | ADSP2_CLK_SEL_MASK, val); | 1530 | dsp->base + ADSP2_CLOCKING, &val); |
1527 | if (ret != 0) { | 1531 | if (ret != 0) { |
1528 | adsp_err(dsp, "Failed to set clock rate: %d\n", | 1532 | dev_err(dsp->dev, "Failed to read clocking: %d\n", ret); |
1529 | ret); | 1533 | return; |
1530 | return ret; | ||
1531 | } | 1534 | } |
1532 | 1535 | ||
1533 | if (dsp->dvfs) { | 1536 | if ((val & ADSP2_CLK_SEL_MASK) >= 3) { |
1534 | ret = regmap_read(dsp->regmap, | 1537 | ret = regulator_enable(dsp->dvfs); |
1535 | dsp->base + ADSP2_CLOCKING, &val); | ||
1536 | if (ret != 0) { | 1538 | if (ret != 0) { |
1537 | dev_err(dsp->dev, | 1539 | dev_err(dsp->dev, |
1538 | "Failed to read clocking: %d\n", ret); | 1540 | "Failed to enable supply: %d\n", |
1539 | return ret; | 1541 | ret); |
1542 | return; | ||
1540 | } | 1543 | } |
1541 | 1544 | ||
1542 | if ((val & ADSP2_CLK_SEL_MASK) >= 3) { | 1545 | ret = regulator_set_voltage(dsp->dvfs, |
1543 | ret = regulator_enable(dsp->dvfs); | 1546 | 1800000, |
1544 | if (ret != 0) { | 1547 | 1800000); |
1545 | dev_err(dsp->dev, | 1548 | if (ret != 0) { |
1546 | "Failed to enable supply: %d\n", | 1549 | dev_err(dsp->dev, |
1547 | ret); | 1550 | "Failed to raise supply: %d\n", |
1548 | return ret; | 1551 | ret); |
1549 | } | 1552 | return; |
1550 | |||
1551 | ret = regulator_set_voltage(dsp->dvfs, | ||
1552 | 1800000, | ||
1553 | 1800000); | ||
1554 | if (ret != 0) { | ||
1555 | dev_err(dsp->dev, | ||
1556 | "Failed to raise supply: %d\n", | ||
1557 | ret); | ||
1558 | return ret; | ||
1559 | } | ||
1560 | } | 1553 | } |
1561 | } | 1554 | } |
1555 | } | ||
1562 | 1556 | ||
1563 | ret = wm_adsp2_ena(dsp); | 1557 | ret = wm_adsp2_ena(dsp); |
1564 | if (ret != 0) | 1558 | if (ret != 0) |
1565 | return ret; | 1559 | return; |
1566 | 1560 | ||
1567 | ret = wm_adsp_load(dsp); | 1561 | ret = wm_adsp_load(dsp); |
1568 | if (ret != 0) | 1562 | if (ret != 0) |
1569 | goto err; | 1563 | goto err; |
1570 | 1564 | ||
1571 | ret = wm_adsp_setup_algs(dsp); | 1565 | ret = wm_adsp_setup_algs(dsp); |
1572 | if (ret != 0) | 1566 | if (ret != 0) |
1573 | goto err; | 1567 | goto err; |
1574 | 1568 | ||
1575 | ret = wm_adsp_load_coeff(dsp); | 1569 | ret = wm_adsp_load_coeff(dsp); |
1576 | if (ret != 0) | 1570 | if (ret != 0) |
1577 | goto err; | 1571 | goto err; |
1578 | 1572 | ||
1579 | /* Initialize caches for enabled and unset controls */ | 1573 | /* Initialize caches for enabled and unset controls */ |
1580 | ret = wm_coeff_init_control_caches(dsp); | 1574 | ret = wm_coeff_init_control_caches(dsp); |
1581 | if (ret != 0) | 1575 | if (ret != 0) |
1582 | goto err; | 1576 | goto err; |
1583 | 1577 | ||
1584 | /* Sync set controls */ | 1578 | /* Sync set controls */ |
1585 | ret = wm_coeff_sync_controls(dsp); | 1579 | ret = wm_coeff_sync_controls(dsp); |
1586 | if (ret != 0) | 1580 | if (ret != 0) |
1587 | goto err; | 1581 | goto err; |
1582 | |||
1583 | ret = regmap_update_bits_async(dsp->regmap, | ||
1584 | dsp->base + ADSP2_CONTROL, | ||
1585 | ADSP2_CORE_ENA, | ||
1586 | ADSP2_CORE_ENA); | ||
1587 | if (ret != 0) | ||
1588 | goto err; | ||
1589 | |||
1590 | dsp->running = true; | ||
1591 | |||
1592 | return; | ||
1593 | |||
1594 | err: | ||
1595 | regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, | ||
1596 | ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0); | ||
1597 | } | ||
1598 | |||
1599 | int wm_adsp2_early_event(struct snd_soc_dapm_widget *w, | ||
1600 | struct snd_kcontrol *kcontrol, int event) | ||
1601 | { | ||
1602 | struct snd_soc_codec *codec = w->codec; | ||
1603 | struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); | ||
1604 | struct wm_adsp *dsp = &dsps[w->shift]; | ||
1605 | |||
1606 | dsp->card = codec->card; | ||
1607 | |||
1608 | switch (event) { | ||
1609 | case SND_SOC_DAPM_PRE_PMU: | ||
1610 | queue_work(system_unbound_wq, &dsp->boot_work); | ||
1611 | break; | ||
1612 | default: | ||
1613 | break; | ||
1614 | }; | ||
1615 | |||
1616 | return 0; | ||
1617 | } | ||
1618 | EXPORT_SYMBOL_GPL(wm_adsp2_early_event); | ||
1619 | |||
1620 | int wm_adsp2_event(struct snd_soc_dapm_widget *w, | ||
1621 | struct snd_kcontrol *kcontrol, int event) | ||
1622 | { | ||
1623 | struct snd_soc_codec *codec = w->codec; | ||
1624 | struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); | ||
1625 | struct wm_adsp *dsp = &dsps[w->shift]; | ||
1626 | struct wm_adsp_alg_region *alg_region; | ||
1627 | struct wm_coeff_ctl *ctl; | ||
1628 | int ret; | ||
1629 | |||
1630 | switch (event) { | ||
1631 | case SND_SOC_DAPM_POST_PMU: | ||
1632 | flush_work(&dsp->boot_work); | ||
1633 | |||
1634 | if (!dsp->running) | ||
1635 | return -EIO; | ||
1588 | 1636 | ||
1589 | ret = regmap_update_bits(dsp->regmap, | 1637 | ret = regmap_update_bits(dsp->regmap, |
1590 | dsp->base + ADSP2_CONTROL, | 1638 | dsp->base + ADSP2_CONTROL, |
1591 | ADSP2_CORE_ENA | ADSP2_START, | 1639 | ADSP2_START, |
1592 | ADSP2_CORE_ENA | ADSP2_START); | 1640 | ADSP2_START); |
1593 | if (ret != 0) | 1641 | if (ret != 0) |
1594 | goto err; | 1642 | goto err; |
1595 | |||
1596 | dsp->running = true; | ||
1597 | break; | 1643 | break; |
1598 | 1644 | ||
1599 | case SND_SOC_DAPM_PRE_PMD: | 1645 | case SND_SOC_DAPM_PRE_PMD: |
@@ -1664,6 +1710,7 @@ int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs) | |||
1664 | 1710 | ||
1665 | INIT_LIST_HEAD(&adsp->alg_regions); | 1711 | INIT_LIST_HEAD(&adsp->alg_regions); |
1666 | INIT_LIST_HEAD(&adsp->ctl_list); | 1712 | INIT_LIST_HEAD(&adsp->ctl_list); |
1713 | INIT_WORK(&adsp->boot_work, wm_adsp2_boot_work); | ||
1667 | 1714 | ||
1668 | if (dvfs) { | 1715 | if (dvfs) { |
1669 | adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD"); | 1716 | adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD"); |