diff options
Diffstat (limited to 'drivers/video/omap2/dss/hdmi.c')
-rw-r--r-- | drivers/video/omap2/dss/hdmi.c | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index 0b209d38a10..b0555f4f0a7 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c | |||
@@ -30,9 +30,15 @@ | |||
30 | #include <linux/delay.h> | 30 | #include <linux/delay.h> |
31 | #include <linux/string.h> | 31 | #include <linux/string.h> |
32 | #include <video/omapdss.h> | 32 | #include <video/omapdss.h> |
33 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ | ||
34 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | ||
35 | #include <sound/soc.h> | ||
36 | #include <sound/pcm_params.h> | ||
37 | #endif | ||
33 | 38 | ||
34 | #include "dss.h" | 39 | #include "dss.h" |
35 | #include "hdmi.h" | 40 | #include "hdmi.h" |
41 | #include "dss_features.h" | ||
36 | 42 | ||
37 | static struct { | 43 | static struct { |
38 | struct mutex lock; | 44 | struct mutex lock; |
@@ -1487,12 +1493,207 @@ static int hdmi_config_audio_acr(u32 sample_freq, u32 *n, u32 *cts) | |||
1487 | 1493 | ||
1488 | return 0; | 1494 | return 0; |
1489 | } | 1495 | } |
1496 | |||
1497 | static int hdmi_audio_hw_params(struct snd_pcm_substream *substream, | ||
1498 | struct snd_pcm_hw_params *params, | ||
1499 | struct snd_soc_dai *dai) | ||
1500 | { | ||
1501 | struct hdmi_audio_format audio_format; | ||
1502 | struct hdmi_audio_dma audio_dma; | ||
1503 | struct hdmi_core_audio_config core_cfg; | ||
1504 | struct hdmi_core_infoframe_audio aud_if_cfg; | ||
1505 | int err, n, cts; | ||
1506 | enum hdmi_core_audio_sample_freq sample_freq; | ||
1507 | |||
1508 | switch (params_format(params)) { | ||
1509 | case SNDRV_PCM_FORMAT_S16_LE: | ||
1510 | core_cfg.i2s_cfg.word_max_length = | ||
1511 | HDMI_AUDIO_I2S_MAX_WORD_20BITS; | ||
1512 | core_cfg.i2s_cfg.word_length = HDMI_AUDIO_I2S_CHST_WORD_16_BITS; | ||
1513 | core_cfg.i2s_cfg.in_length_bits = | ||
1514 | HDMI_AUDIO_I2S_INPUT_LENGTH_16; | ||
1515 | core_cfg.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_LEFT; | ||
1516 | audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_TWOSAMPLES; | ||
1517 | audio_format.sample_size = HDMI_AUDIO_SAMPLE_16BITS; | ||
1518 | audio_format.justification = HDMI_AUDIO_JUSTIFY_LEFT; | ||
1519 | audio_dma.transfer_size = 0x10; | ||
1520 | break; | ||
1521 | case SNDRV_PCM_FORMAT_S24_LE: | ||
1522 | core_cfg.i2s_cfg.word_max_length = | ||
1523 | HDMI_AUDIO_I2S_MAX_WORD_24BITS; | ||
1524 | core_cfg.i2s_cfg.word_length = HDMI_AUDIO_I2S_CHST_WORD_24_BITS; | ||
1525 | core_cfg.i2s_cfg.in_length_bits = | ||
1526 | HDMI_AUDIO_I2S_INPUT_LENGTH_24; | ||
1527 | audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_ONESAMPLE; | ||
1528 | audio_format.sample_size = HDMI_AUDIO_SAMPLE_24BITS; | ||
1529 | audio_format.justification = HDMI_AUDIO_JUSTIFY_RIGHT; | ||
1530 | core_cfg.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_RIGHT; | ||
1531 | audio_dma.transfer_size = 0x20; | ||
1532 | break; | ||
1533 | default: | ||
1534 | return -EINVAL; | ||
1535 | } | ||
1536 | |||
1537 | switch (params_rate(params)) { | ||
1538 | case 32000: | ||
1539 | sample_freq = HDMI_AUDIO_FS_32000; | ||
1540 | break; | ||
1541 | case 44100: | ||
1542 | sample_freq = HDMI_AUDIO_FS_44100; | ||
1543 | break; | ||
1544 | case 48000: | ||
1545 | sample_freq = HDMI_AUDIO_FS_48000; | ||
1546 | break; | ||
1547 | default: | ||
1548 | return -EINVAL; | ||
1549 | } | ||
1550 | |||
1551 | err = hdmi_config_audio_acr(params_rate(params), &n, &cts); | ||
1552 | if (err < 0) | ||
1553 | return err; | ||
1554 | |||
1555 | /* Audio wrapper config */ | ||
1556 | audio_format.stereo_channels = HDMI_AUDIO_STEREO_ONECHANNEL; | ||
1557 | audio_format.active_chnnls_msk = 0x03; | ||
1558 | audio_format.type = HDMI_AUDIO_TYPE_LPCM; | ||
1559 | audio_format.sample_order = HDMI_AUDIO_SAMPLE_LEFT_FIRST; | ||
1560 | /* Disable start/stop signals of IEC 60958 blocks */ | ||
1561 | audio_format.en_sig_blk_strt_end = HDMI_AUDIO_BLOCK_SIG_STARTEND_OFF; | ||
1562 | |||
1563 | audio_dma.block_size = 0xC0; | ||
1564 | audio_dma.mode = HDMI_AUDIO_TRANSF_DMA; | ||
1565 | audio_dma.fifo_threshold = 0x20; /* in number of samples */ | ||
1566 | |||
1567 | hdmi_wp_audio_config_dma(&audio_dma); | ||
1568 | hdmi_wp_audio_config_format(&audio_format); | ||
1569 | |||
1570 | /* | ||
1571 | * I2S config | ||
1572 | */ | ||
1573 | core_cfg.i2s_cfg.en_high_bitrate_aud = false; | ||
1574 | /* Only used with high bitrate audio */ | ||
1575 | core_cfg.i2s_cfg.cbit_order = false; | ||
1576 | /* Serial data and word select should change on sck rising edge */ | ||
1577 | core_cfg.i2s_cfg.sck_edge_mode = HDMI_AUDIO_I2S_SCK_EDGE_RISING; | ||
1578 | core_cfg.i2s_cfg.vbit = HDMI_AUDIO_I2S_VBIT_FOR_PCM; | ||
1579 | /* Set I2S word select polarity */ | ||
1580 | core_cfg.i2s_cfg.ws_polarity = HDMI_AUDIO_I2S_WS_POLARITY_LOW_IS_LEFT; | ||
1581 | core_cfg.i2s_cfg.direction = HDMI_AUDIO_I2S_MSB_SHIFTED_FIRST; | ||
1582 | /* Set serial data to word select shift. See Phillips spec. */ | ||
1583 | core_cfg.i2s_cfg.shift = HDMI_AUDIO_I2S_FIRST_BIT_SHIFT; | ||
1584 | /* Enable one of the four available serial data channels */ | ||
1585 | core_cfg.i2s_cfg.active_sds = HDMI_AUDIO_I2S_SD0_EN; | ||
1586 | |||
1587 | /* Core audio config */ | ||
1588 | core_cfg.freq_sample = sample_freq; | ||
1589 | core_cfg.n = n; | ||
1590 | core_cfg.cts = cts; | ||
1591 | if (dss_has_feature(FEAT_HDMI_CTS_SWMODE)) { | ||
1592 | core_cfg.aud_par_busclk = 0; | ||
1593 | core_cfg.cts_mode = HDMI_AUDIO_CTS_MODE_SW; | ||
1594 | core_cfg.use_mclk = false; | ||
1595 | } else { | ||
1596 | core_cfg.aud_par_busclk = (((128 * 31) - 1) << 8); | ||
1597 | core_cfg.cts_mode = HDMI_AUDIO_CTS_MODE_HW; | ||
1598 | core_cfg.use_mclk = true; | ||
1599 | core_cfg.mclk_mode = HDMI_AUDIO_MCLK_128FS; | ||
1600 | } | ||
1601 | core_cfg.layout = HDMI_AUDIO_LAYOUT_2CH; | ||
1602 | core_cfg.en_spdif = false; | ||
1603 | /* Use sample frequency from channel status word */ | ||
1604 | core_cfg.fs_override = true; | ||
1605 | /* Enable ACR packets */ | ||
1606 | core_cfg.en_acr_pkt = true; | ||
1607 | /* Disable direct streaming digital audio */ | ||
1608 | core_cfg.en_dsd_audio = false; | ||
1609 | /* Use parallel audio interface */ | ||
1610 | core_cfg.en_parallel_aud_input = true; | ||
1611 | |||
1612 | hdmi_core_audio_config(&core_cfg); | ||
1613 | |||
1614 | /* | ||
1615 | * Configure packet | ||
1616 | * info frame audio see doc CEA861-D page 74 | ||
1617 | */ | ||
1618 | aud_if_cfg.db1_coding_type = HDMI_INFOFRAME_AUDIO_DB1CT_FROM_STREAM; | ||
1619 | aud_if_cfg.db1_channel_count = 2; | ||
1620 | aud_if_cfg.db2_sample_freq = HDMI_INFOFRAME_AUDIO_DB2SF_FROM_STREAM; | ||
1621 | aud_if_cfg.db2_sample_size = HDMI_INFOFRAME_AUDIO_DB2SS_FROM_STREAM; | ||
1622 | aud_if_cfg.db4_channel_alloc = 0x00; | ||
1623 | aud_if_cfg.db5_downmix_inh = false; | ||
1624 | aud_if_cfg.db5_lsv = 0; | ||
1625 | |||
1626 | hdmi_core_audio_infoframe_config(&aud_if_cfg); | ||
1627 | return 0; | ||
1628 | } | ||
1629 | |||
1630 | static int hdmi_audio_trigger(struct snd_pcm_substream *substream, int cmd, | ||
1631 | struct snd_soc_dai *dai) | ||
1632 | { | ||
1633 | int err = 0; | ||
1634 | switch (cmd) { | ||
1635 | case SNDRV_PCM_TRIGGER_START: | ||
1636 | case SNDRV_PCM_TRIGGER_RESUME: | ||
1637 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
1638 | REG_FLD_MOD(HDMI_CORE_AV_AUD_MODE, 1, 0, 0); | ||
1639 | REG_FLD_MOD(HDMI_WP_AUDIO_CTRL, 1, 31, 31); | ||
1640 | REG_FLD_MOD(HDMI_WP_AUDIO_CTRL, 1, 30, 30); | ||
1641 | break; | ||
1642 | |||
1643 | case SNDRV_PCM_TRIGGER_STOP: | ||
1644 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
1645 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
1646 | REG_FLD_MOD(HDMI_CORE_AV_AUD_MODE, 0, 0, 0); | ||
1647 | REG_FLD_MOD(HDMI_WP_AUDIO_CTRL, 0, 30, 30); | ||
1648 | REG_FLD_MOD(HDMI_WP_AUDIO_CTRL, 0, 31, 31); | ||
1649 | break; | ||
1650 | default: | ||
1651 | err = -EINVAL; | ||
1652 | } | ||
1653 | return err; | ||
1654 | } | ||
1655 | |||
1656 | static int hdmi_audio_startup(struct snd_pcm_substream *substream, | ||
1657 | struct snd_soc_dai *dai) | ||
1658 | { | ||
1659 | if (!hdmi.mode) { | ||
1660 | pr_err("Current video settings do not support audio.\n"); | ||
1661 | return -EIO; | ||
1662 | } | ||
1663 | return 0; | ||
1664 | } | ||
1665 | |||
1666 | static struct snd_soc_codec_driver hdmi_audio_codec_drv = { | ||
1667 | }; | ||
1668 | |||
1669 | static struct snd_soc_dai_ops hdmi_audio_codec_ops = { | ||
1670 | .hw_params = hdmi_audio_hw_params, | ||
1671 | .trigger = hdmi_audio_trigger, | ||
1672 | .startup = hdmi_audio_startup, | ||
1673 | }; | ||
1674 | |||
1675 | static struct snd_soc_dai_driver hdmi_codec_dai_drv = { | ||
1676 | .name = "hdmi-audio-codec", | ||
1677 | .playback = { | ||
1678 | .channels_min = 2, | ||
1679 | .channels_max = 2, | ||
1680 | .rates = SNDRV_PCM_RATE_32000 | | ||
1681 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, | ||
1682 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | ||
1683 | SNDRV_PCM_FMTBIT_S24_LE, | ||
1684 | }, | ||
1685 | .ops = &hdmi_audio_codec_ops, | ||
1686 | }; | ||
1490 | #endif | 1687 | #endif |
1491 | 1688 | ||
1492 | /* HDMI HW IP initialisation */ | 1689 | /* HDMI HW IP initialisation */ |
1493 | static int omapdss_hdmihw_probe(struct platform_device *pdev) | 1690 | static int omapdss_hdmihw_probe(struct platform_device *pdev) |
1494 | { | 1691 | { |
1495 | struct resource *hdmi_mem; | 1692 | struct resource *hdmi_mem; |
1693 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ | ||
1694 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | ||
1695 | int ret; | ||
1696 | #endif | ||
1496 | 1697 | ||
1497 | hdmi.pdata = pdev->dev.platform_data; | 1698 | hdmi.pdata = pdev->dev.platform_data; |
1498 | hdmi.pdev = pdev; | 1699 | hdmi.pdev = pdev; |
@@ -1514,6 +1715,17 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev) | |||
1514 | 1715 | ||
1515 | hdmi_panel_init(); | 1716 | hdmi_panel_init(); |
1516 | 1717 | ||
1718 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ | ||
1719 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | ||
1720 | |||
1721 | /* Register ASoC codec DAI */ | ||
1722 | ret = snd_soc_register_codec(&pdev->dev, &hdmi_audio_codec_drv, | ||
1723 | &hdmi_codec_dai_drv, 1); | ||
1724 | if (ret) { | ||
1725 | DSSERR("can't register ASoC HDMI audio codec\n"); | ||
1726 | return ret; | ||
1727 | } | ||
1728 | #endif | ||
1517 | return 0; | 1729 | return 0; |
1518 | } | 1730 | } |
1519 | 1731 | ||
@@ -1521,6 +1733,11 @@ static int omapdss_hdmihw_remove(struct platform_device *pdev) | |||
1521 | { | 1733 | { |
1522 | hdmi_panel_exit(); | 1734 | hdmi_panel_exit(); |
1523 | 1735 | ||
1736 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ | ||
1737 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | ||
1738 | snd_soc_unregister_codec(&pdev->dev); | ||
1739 | #endif | ||
1740 | |||
1524 | iounmap(hdmi.base_wp); | 1741 | iounmap(hdmi.base_wp); |
1525 | 1742 | ||
1526 | return 0; | 1743 | return 0; |