From 8f48438124803a66dd91a1d44866eebd28eaff8d Mon Sep 17 00:00:00 2001 From: Arun Shamanna Lakshmi Date: Thu, 18 Sep 2014 22:02:59 -0700 Subject: [PATCH] ASoC: tegra-alt: Improvement of t210 drivers 1. Add link name to platform data for unique identification of the dai link 2. Remove set_sysclk from I2S and retreive srate from params 3. Try to retrieve fsync-width from DT file, if not default as 31 4. Add mono channel support in FSYNC mode in machine driver 5. Fix dai_link_idx API to get link_idx from unique name identifier 6. Add tdm_slot mask API for tx/rx mask settting 7. Initialize the DAPM dai link work struct for non-pcm dai-links to avoid kernel crash during powercycle in low power mode. 8. Add slot_size for AMX and ADX 9. Add clk_out_rate for 8kHz in automotive machine driver Bug 1442940 Change-Id: Iaebdd7e12b8490021a9034afa351cdbc1d1d5d38 Signed-off-by: Arun Shamanna Lakshmi Signed-off-by: Junghyun Kim Reviewed-on: http://git-master/r/500553 --- sound/soc/tegra-alt/tegra210_afc_alt.c | 6 +- sound/soc/tegra-alt/tegra210_i2s_alt.c | 102 +++++++++++++++++++------ 2 files changed, 81 insertions(+), 27 deletions(-) diff --git a/sound/soc/tegra-alt/tegra210_afc_alt.c b/sound/soc/tegra-alt/tegra210_afc_alt.c index da37f087..ef3b6f81 100644 --- a/sound/soc/tegra-alt/tegra210_afc_alt.c +++ b/sound/soc/tegra-alt/tegra210_afc_alt.c @@ -119,9 +119,9 @@ static int tegra210_afc_set_thresholds(struct tegra210_afc *afc, if (tegra210_afc_get_sfc_id(afc_id)) { /* TODO program thresholds using SRC_BURST */ } else { - value = 8 << TEGRA210_AFC_FIFO_HIGH_THRESHOLD_SHIFT; - value |= 7 << TEGRA210_AFC_FIFO_START_THRESHOLD_SHIFT; - value |= 6; + value = 4 << TEGRA210_AFC_FIFO_HIGH_THRESHOLD_SHIFT; + value |= 3 << TEGRA210_AFC_FIFO_START_THRESHOLD_SHIFT; + value |= 2; } regmap_write(afc->regmap, TEGRA210_AFC_TXCIF_FIFO_PARAMS, value); diff --git a/sound/soc/tegra-alt/tegra210_i2s_alt.c b/sound/soc/tegra-alt/tegra210_i2s_alt.c index 1b883094..9eb90a64 100644 --- a/sound/soc/tegra-alt/tegra210_i2s_alt.c +++ b/sound/soc/tegra-alt/tegra210_i2s_alt.c @@ -40,6 +40,18 @@ #define DRV_NAME "tegra210-i2s" +static void tegra210_i2s_set_slot_ctrl(struct regmap *regmap, + unsigned int total_slots, + unsigned int tx_slot_mask, + unsigned int rx_slot_mask) +{ + regmap_write(regmap, TEGRA210_I2S_SLOT_CTRL, total_slots - 1); + regmap_write(regmap, TEGRA210_I2S_AXBAR_TX_SLOT_CTRL, + tx_slot_mask); + regmap_write(regmap, TEGRA210_I2S_AXBAR_RX_SLOT_CTRL, + rx_slot_mask); +} + static int tegra210_i2s_set_clock_rate(struct device *dev, int clock_rate) { unsigned int val; @@ -218,11 +230,27 @@ static int tegra210_i2s_set_fmt(struct snd_soc_dai *dai, regmap_update_bits(i2s->regmap, TEGRA210_I2S_AXBAR_RX_CTRL, TEGRA210_I2S_AXBAR_RX_CTRL_DATA_OFFSET_MASK, (data_offset << TEGRA210_I2S_AXBAR_RX_CTRL_DATA_OFFSET_SHIFT)); + regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL, + TEGRA210_I2S_CTRL_FSYNC_WIDTH_MASK, + i2s->fsync_width << TEGRA210_I2S_CTRL_FSYNC_WIDTH_SHIFT); pm_runtime_put(dai->dev); return 0; } +static int tegra210_i2s_set_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, unsigned int rx_mask, + int slots, int slot_width) +{ + struct tegra210_i2s *i2s = snd_soc_dai_get_drvdata(dai); + + /* copy the required tx and rx mask */ + i2s->tx_mask = (tx_mask > 0xFFFF) ? 0xFFFF : tx_mask; + i2s->rx_mask = (rx_mask > 0xFFFF) ? 0xFFFF : rx_mask; + + return 0; +} + static int tegra210_i2s_set_dai_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) { @@ -249,17 +277,29 @@ static int tegra210_i2s_hw_params(struct snd_pcm_substream *substream, mask = TEGRA210_I2S_CTRL_BIT_SIZE_MASK; switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S8: + val = TEGRA210_I2S_CTRL_BIT_SIZE_8; + sample_size = 8; + cif_conf.audio_bits = TEGRA210_AUDIOCIF_BITS_8; + cif_conf.client_bits = TEGRA210_AUDIOCIF_BITS_8; + break; case SNDRV_PCM_FORMAT_S16_LE: val = TEGRA210_I2S_CTRL_BIT_SIZE_16; sample_size = 16; + cif_conf.audio_bits = TEGRA210_AUDIOCIF_BITS_16; + cif_conf.client_bits = TEGRA210_AUDIOCIF_BITS_16; break; case SNDRV_PCM_FORMAT_S24_LE: val = TEGRA210_I2S_CTRL_BIT_SIZE_24; sample_size = 24; + cif_conf.audio_bits = TEGRA210_AUDIOCIF_BITS_24; + cif_conf.client_bits = TEGRA210_AUDIOCIF_BITS_24; break; case SNDRV_PCM_FORMAT_S32_LE: val = TEGRA210_I2S_CTRL_BIT_SIZE_32; sample_size = 32; + cif_conf.audio_bits = TEGRA210_AUDIOCIF_BITS_32; + cif_conf.client_bits = TEGRA210_AUDIOCIF_BITS_32; break; default: dev_err(dev, "Wrong format!\n"); @@ -275,19 +315,35 @@ static int tegra210_i2s_hw_params(struct snd_pcm_substream *substream, frame_format = val & TEGRA210_I2S_CTRL_FRAME_FORMAT_MASK; if (frame_format == TEGRA210_I2S_CTRL_FRAME_FORMAT_FSYNC_MODE) { - regmap_write(i2s->regmap, TEGRA210_I2S_SLOT_CTRL, channels - 1); - regmap_write(i2s->regmap, TEGRA210_I2S_AXBAR_TX_SLOT_CTRL, - ((1 << channels) - 1)); - regmap_write(i2s->regmap, TEGRA210_I2S_AXBAR_RX_SLOT_CTRL, - ((1 << channels) - 1)); + i2s->soc_data->set_slot_ctrl(i2s->regmap, channels, + i2s->tx_mask, i2s->rx_mask); + /* FIXUP : I2S fifo threshold set to 3 when AFC is connected */ + cif_conf.threshold = 3; + cif_conf.audio_channels = channels; + cif_conf.client_channels = channels; + cif_conf.expand = 0; + cif_conf.stereo_conv = 0; + cif_conf.replicate = 0; + cif_conf.truncate = 0; + cif_conf.mono_conv = 0; + } else { + cif_conf.threshold = 3; + cif_conf.audio_channels = channels; + cif_conf.client_channels = (channels == 1) ? 2 : channels; + cif_conf.expand = 0; + cif_conf.stereo_conv = 0; + cif_conf.replicate = 0; + cif_conf.truncate = 0; + cif_conf.mono_conv = 0; } - i2sclock = srate * channels * sample_size; + i2sclock = srate * sample_size * cif_conf.client_channels; if (i2s->bclk_ratio != 0) i2sclock *= i2s->bclk_ratio; bitcnt = (i2sclock / srate) - 1; + if ((bitcnt < 0) || (bitcnt > TEGRA210_I2S_TIMING_CHANNEL_BIT_CNT_MASK)) { dev_err(dev, "Can't set channel bit count\n"); @@ -311,24 +367,6 @@ static int tegra210_i2s_hw_params(struct snd_pcm_substream *substream, regmap_write(i2s->regmap, TEGRA210_I2S_TIMING, val); - regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL, - TEGRA210_I2S_CTRL_FSYNC_WIDTH_MASK, - 31 << TEGRA210_I2S_CTRL_FSYNC_WIDTH_SHIFT); - - cif_conf.threshold = 0; - cif_conf.audio_channels = channels; - cif_conf.client_channels = channels; - cif_conf.audio_bits = (sample_size == 16 ? TEGRA210_AUDIOCIF_BITS_16 : - TEGRA210_AUDIOCIF_BITS_32); - - cif_conf.client_bits = (sample_size == 16 ? TEGRA210_AUDIOCIF_BITS_16 : - TEGRA210_AUDIOCIF_BITS_32); - cif_conf.expand = 0; - cif_conf.stereo_conv = 0; - cif_conf.replicate = 0; - cif_conf.truncate = 0; - cif_conf.mono_conv = 0; - /* As a COCEC DAI, CAPTURE is transmit */ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) reg = TEGRA210_I2S_AXBAR_RX_CIF_CTRL; @@ -388,6 +426,7 @@ static struct snd_soc_dai_ops tegra210_i2s_dai_ops = { .set_fmt = tegra210_i2s_set_fmt, .hw_params = tegra210_i2s_hw_params, .set_bclk_ratio = tegra210_i2s_set_dai_bclk_ratio, + .set_tdm_slot = tegra210_i2s_set_tdm_slot, }; static struct snd_soc_dai_driver tegra210_i2s_dais[] = { @@ -577,6 +616,7 @@ static const struct regmap_config tegra210_i2s_regmap_config = { static const struct tegra210_i2s_soc_data soc_data_tegra210 = { .set_audio_cif = tegra210_xbar_set_cif, + .set_slot_ctrl = tegra210_i2s_set_slot_ctrl, }; static const struct of_device_id tegra210_i2s_of_match[] = { @@ -613,6 +653,7 @@ static int tegra210_i2s_platform_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, i2s); i2s->soc_data = soc_data; + i2s->tx_mask = i2s->rx_mask = 0xFFFF; i2s->bclk_ratio = 2; i2s->clk_i2s = devm_clk_get(&pdev->dev, NULL); @@ -687,6 +728,19 @@ static int tegra210_i2s_platform_probe(struct platform_device *pdev) goto err_pll_a_out0_clk_put; } + if (of_property_read_u32(pdev->dev.of_node, + "fsync-width", &i2s->fsync_width) < 0) { + dev_warn(&pdev->dev, "Missing prop fsync-width for I2S%d\n", + pdev->dev.id); + i2s->fsync_width = 31; + } + + if (i2s->fsync_width > 255) { + dev_warn(&pdev->dev, "Default fsync-width to 31 for I2S%d\n", + pdev->dev.id); + i2s->fsync_width = 31; + } + num_supplies = of_property_count_strings(np, "regulator-supplies"); if (num_supplies > 0) { i2s->num_supplies = num_supplies;