aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/wm_adsp.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/wm_adsp.c')
-rw-r--r--sound/soc/codecs/wm_adsp.c211
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
1496int wm_adsp2_event(struct snd_soc_dapm_widget *w, 1500static 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
1594err:
1595 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
1596 ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0);
1597}
1598
1599int 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}
1618EXPORT_SYMBOL_GPL(wm_adsp2_early_event);
1619
1620int 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");