diff options
Diffstat (limited to 'sound/soc/codecs/wm_adsp.c')
-rw-r--r-- | sound/soc/codecs/wm_adsp.c | 201 |
1 files changed, 122 insertions, 79 deletions
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 4fbcab63e61f..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,8 +1469,8 @@ 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 | ||
@@ -1492,112 +1493,153 @@ static int wm_adsp2_ena(struct wm_adsp *dsp) | |||
1492 | } | 1493 | } |
1493 | 1494 | ||
1494 | adsp_dbg(dsp, "RAM ready after %d polls\n", count); | 1495 | adsp_dbg(dsp, "RAM ready after %d polls\n", count); |
1495 | adsp_info(dsp, "RAM ready after %d polls\n", count); | ||
1496 | 1496 | ||
1497 | return 0; | 1497 | return 0; |
1498 | } | 1498 | } |
1499 | 1499 | ||
1500 | int wm_adsp2_event(struct snd_soc_dapm_widget *w, | 1500 | static void wm_adsp2_boot_work(struct work_struct *work) |
1501 | struct snd_kcontrol *kcontrol, int event) | ||
1502 | { | 1501 | { |
1503 | struct snd_soc_codec *codec = w->codec; | 1502 | struct wm_adsp *dsp = container_of(work, |
1504 | struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); | 1503 | struct wm_adsp, |
1505 | struct wm_adsp *dsp = &dsps[w->shift]; | 1504 | boot_work); |
1506 | struct wm_adsp_alg_region *alg_region; | ||
1507 | struct wm_coeff_ctl *ctl; | ||
1508 | unsigned int val; | ||
1509 | int ret; | 1505 | int ret; |
1506 | unsigned int val; | ||
1510 | 1507 | ||
1511 | 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; | ||
1512 | 1519 | ||
1513 | switch (event) { | 1520 | ret = regmap_update_bits_async(dsp->regmap, |
1514 | case SND_SOC_DAPM_POST_PMU: | 1521 | dsp->base + ADSP2_CLOCKING, |
1515 | /* | 1522 | ADSP2_CLK_SEL_MASK, val); |
1516 | * For simplicity set the DSP clock rate to be the | 1523 | if (ret != 0) { |
1517 | * SYSCLK rate rather than making it configurable. | 1524 | adsp_err(dsp, "Failed to set clock rate: %d\n", ret); |
1518 | */ | 1525 | return; |
1519 | ret = regmap_read(dsp->regmap, ARIZONA_SYSTEM_CLOCK_1, &val); | 1526 | } |
1520 | if (ret != 0) { | ||
1521 | adsp_err(dsp, "Failed to read SYSCLK state: %d\n", | ||
1522 | ret); | ||
1523 | return ret; | ||
1524 | } | ||
1525 | val = (val & ARIZONA_SYSCLK_FREQ_MASK) | ||
1526 | >> ARIZONA_SYSCLK_FREQ_SHIFT; | ||
1527 | 1527 | ||
1528 | ret = regmap_update_bits(dsp->regmap, | 1528 | if (dsp->dvfs) { |
1529 | dsp->base + ADSP2_CLOCKING, | 1529 | ret = regmap_read(dsp->regmap, |
1530 | ADSP2_CLK_SEL_MASK, val); | 1530 | dsp->base + ADSP2_CLOCKING, &val); |
1531 | if (ret != 0) { | 1531 | if (ret != 0) { |
1532 | adsp_err(dsp, "Failed to set clock rate: %d\n", | 1532 | dev_err(dsp->dev, "Failed to read clocking: %d\n", ret); |
1533 | ret); | 1533 | return; |
1534 | return ret; | ||
1535 | } | 1534 | } |
1536 | 1535 | ||
1537 | if (dsp->dvfs) { | 1536 | if ((val & ADSP2_CLK_SEL_MASK) >= 3) { |
1538 | ret = regmap_read(dsp->regmap, | 1537 | ret = regulator_enable(dsp->dvfs); |
1539 | dsp->base + ADSP2_CLOCKING, &val); | ||
1540 | if (ret != 0) { | 1538 | if (ret != 0) { |
1541 | dev_err(dsp->dev, | 1539 | dev_err(dsp->dev, |
1542 | "Failed to read clocking: %d\n", ret); | 1540 | "Failed to enable supply: %d\n", |
1543 | return ret; | 1541 | ret); |
1542 | return; | ||
1544 | } | 1543 | } |
1545 | 1544 | ||
1546 | if ((val & ADSP2_CLK_SEL_MASK) >= 3) { | 1545 | ret = regulator_set_voltage(dsp->dvfs, |
1547 | ret = regulator_enable(dsp->dvfs); | 1546 | 1800000, |
1548 | if (ret != 0) { | 1547 | 1800000); |
1549 | dev_err(dsp->dev, | 1548 | if (ret != 0) { |
1550 | "Failed to enable supply: %d\n", | 1549 | dev_err(dsp->dev, |
1551 | ret); | 1550 | "Failed to raise supply: %d\n", |
1552 | return ret; | 1551 | ret); |
1553 | } | 1552 | return; |
1554 | |||
1555 | ret = regulator_set_voltage(dsp->dvfs, | ||
1556 | 1800000, | ||
1557 | 1800000); | ||
1558 | if (ret != 0) { | ||
1559 | dev_err(dsp->dev, | ||
1560 | "Failed to raise supply: %d\n", | ||
1561 | ret); | ||
1562 | return ret; | ||
1563 | } | ||
1564 | } | 1553 | } |
1565 | } | 1554 | } |
1555 | } | ||
1566 | 1556 | ||
1567 | ret = wm_adsp2_ena(dsp); | 1557 | ret = wm_adsp2_ena(dsp); |
1568 | if (ret != 0) | 1558 | if (ret != 0) |
1569 | return ret; | 1559 | return; |
1570 | 1560 | ||
1571 | ret = wm_adsp_load(dsp); | 1561 | ret = wm_adsp_load(dsp); |
1572 | if (ret != 0) | 1562 | if (ret != 0) |
1573 | goto err; | 1563 | goto err; |
1574 | 1564 | ||
1575 | ret = wm_adsp_setup_algs(dsp); | 1565 | ret = wm_adsp_setup_algs(dsp); |
1576 | if (ret != 0) | 1566 | if (ret != 0) |
1577 | goto err; | 1567 | goto err; |
1578 | 1568 | ||
1579 | ret = wm_adsp_load_coeff(dsp); | 1569 | ret = wm_adsp_load_coeff(dsp); |
1580 | if (ret != 0) | 1570 | if (ret != 0) |
1581 | goto err; | 1571 | goto err; |
1582 | 1572 | ||
1583 | /* Initialize caches for enabled and unset controls */ | 1573 | /* Initialize caches for enabled and unset controls */ |
1584 | ret = wm_coeff_init_control_caches(dsp); | 1574 | ret = wm_coeff_init_control_caches(dsp); |
1585 | if (ret != 0) | 1575 | if (ret != 0) |
1586 | goto err; | 1576 | goto err; |
1587 | 1577 | ||
1588 | /* Sync set controls */ | 1578 | /* Sync set controls */ |
1589 | ret = wm_coeff_sync_controls(dsp); | 1579 | ret = wm_coeff_sync_controls(dsp); |
1590 | if (ret != 0) | 1580 | if (ret != 0) |
1591 | 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; | ||
1592 | 1636 | ||
1593 | ret = regmap_update_bits(dsp->regmap, | 1637 | ret = regmap_update_bits(dsp->regmap, |
1594 | dsp->base + ADSP2_CONTROL, | 1638 | dsp->base + ADSP2_CONTROL, |
1595 | ADSP2_CORE_ENA | ADSP2_START, | 1639 | ADSP2_START, |
1596 | ADSP2_CORE_ENA | ADSP2_START); | 1640 | ADSP2_START); |
1597 | if (ret != 0) | 1641 | if (ret != 0) |
1598 | goto err; | 1642 | goto err; |
1599 | |||
1600 | dsp->running = true; | ||
1601 | break; | 1643 | break; |
1602 | 1644 | ||
1603 | case SND_SOC_DAPM_PRE_PMD: | 1645 | case SND_SOC_DAPM_PRE_PMD: |
@@ -1668,6 +1710,7 @@ int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs) | |||
1668 | 1710 | ||
1669 | INIT_LIST_HEAD(&adsp->alg_regions); | 1711 | INIT_LIST_HEAD(&adsp->alg_regions); |
1670 | INIT_LIST_HEAD(&adsp->ctl_list); | 1712 | INIT_LIST_HEAD(&adsp->ctl_list); |
1713 | INIT_WORK(&adsp->boot_work, wm_adsp2_boot_work); | ||
1671 | 1714 | ||
1672 | if (dvfs) { | 1715 | if (dvfs) { |
1673 | adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD"); | 1716 | adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD"); |