From 12bac32cc204885975d661a6e11c3f0e86c450af Mon Sep 17 00:00:00 2001
From: smj <smj@rock-chips.com>
Date: Thu, 9 Apr 2015 11:22:23 +0800
Subject: [PATCH] i2s:fix the hdmi no sound sometimes     support for hdmi
 passthrough output

Signed-off-by: smj  <smj@rock-chips.com>
---
 .../hdmi/rockchip-hdmiv2/rockchip_hdmiv2_hw.c | 17 +++---
 sound/soc/codecs/rk1000_codec.c               |  4 +-
 sound/soc/rockchip/rk30_i2s.c                 | 60 ++++++++++++++++++-
 sound/soc/rockchip/rk_hdmi_i2s.c              |  2 +-
 sound/soc/rockchip/rk_pcm.c                   |  6 +-
 sound/soc/rockchip/rk_rk1000codec.c           | 39 ++++++++++++
 6 files changed, 110 insertions(+), 18 deletions(-)
 mode change 100644 => 100755 drivers/video/rockchip/hdmi/rockchip-hdmiv2/rockchip_hdmiv2_hw.c

diff --git a/drivers/video/rockchip/hdmi/rockchip-hdmiv2/rockchip_hdmiv2_hw.c b/drivers/video/rockchip/hdmi/rockchip-hdmiv2/rockchip_hdmiv2_hw.c
old mode 100644
new mode 100755
index b35c424c2d77..24b7934607f9
--- a/drivers/video/rockchip/hdmi/rockchip-hdmiv2/rockchip_hdmiv2_hw.c
+++ b/drivers/video/rockchip/hdmi/rockchip-hdmiv2/rockchip_hdmiv2_hw.c
@@ -1372,7 +1372,7 @@ static int hdmi_dev_config_audio(struct hdmi *hdmi, struct hdmi_audio *audio)
 
 	switch (audio->rate) {
 	case HDMI_AUDIO_FS_32000:
-		mclk_fs = FS_64;
+		mclk_fs = FS_128;
 		rate = AUDIO_32K;
 		if (hdmi_dev->tmdsclk >= 594000000)
 			N = N_32K_HIGHCLK;
@@ -1384,7 +1384,7 @@ static int hdmi_dev_config_audio(struct hdmi *hdmi, struct hdmi_audio *audio)
 		CTS = CALC_CTS(N, hdmi_dev->tmdsclk/1000, 32);
 		break;
 	case HDMI_AUDIO_FS_44100:
-		mclk_fs = FS_64;
+		mclk_fs = FS_128;
 		rate = AUDIO_441K;
 		if (hdmi_dev->tmdsclk >= 594000000)
 			N = N_441K_HIGHCLK;
@@ -1396,7 +1396,7 @@ static int hdmi_dev_config_audio(struct hdmi *hdmi, struct hdmi_audio *audio)
 		CTS = CALC_CTS(N, hdmi_dev->tmdsclk/100, 441);
 		break;
 	case HDMI_AUDIO_FS_48000:
-		mclk_fs = FS_64;
+		mclk_fs = FS_128;
 		rate = AUDIO_48K;
 		if (hdmi_dev->tmdsclk >= 594000000)	/*FS_153.6*/
 			N = N_48K_HIGHCLK;
@@ -1408,7 +1408,7 @@ static int hdmi_dev_config_audio(struct hdmi *hdmi, struct hdmi_audio *audio)
 		CTS = CALC_CTS(N, hdmi_dev->tmdsclk/1000, 48);
 		break;
 	case HDMI_AUDIO_FS_88200:
-		mclk_fs = FS_64;
+		mclk_fs = FS_128;
 		rate = AUDIO_882K;
 		if (hdmi_dev->tmdsclk >= 594000000)
 			N = N_882K_HIGHCLK;
@@ -1420,7 +1420,7 @@ static int hdmi_dev_config_audio(struct hdmi *hdmi, struct hdmi_audio *audio)
 		CTS = CALC_CTS(N, hdmi_dev->tmdsclk/100, 882);
 		break;
 	case HDMI_AUDIO_FS_96000:
-		mclk_fs = FS_64;
+		mclk_fs = FS_128;
 		rate = AUDIO_96K;
 		if (hdmi_dev->tmdsclk >= 594000000)	/*FS_153.6*/
 			N = N_96K_HIGHCLK;
@@ -1432,7 +1432,7 @@ static int hdmi_dev_config_audio(struct hdmi *hdmi, struct hdmi_audio *audio)
 		CTS = CALC_CTS(N, hdmi_dev->tmdsclk/1000, 96);
 		break;
 	case HDMI_AUDIO_FS_176400:
-		mclk_fs = FS_64;
+		mclk_fs = FS_128;
 		rate = AUDIO_1764K;
 		if (hdmi_dev->tmdsclk >= 594000000)
 			N = N_1764K_HIGHCLK;
@@ -1444,7 +1444,7 @@ static int hdmi_dev_config_audio(struct hdmi *hdmi, struct hdmi_audio *audio)
 		CTS = CALC_CTS(N, hdmi_dev->tmdsclk/100, 1764);
 		break;
 	case HDMI_AUDIO_FS_192000:
-		mclk_fs = FS_64;
+		mclk_fs = FS_128;
 		rate = AUDIO_192K;
 		if (hdmi_dev->tmdsclk >= 594000000)	/*FS_153.6*/
 			N = N_192K_HIGHCLK;
@@ -1535,8 +1535,7 @@ static int hdmi_dev_config_audio(struct hdmi *hdmi, struct hdmi_audio *audio)
 	/* set channel status register */
 	hdmi_msk_reg(hdmi_dev, FC_AUDSCHNLS7,
 		     m_AUDIO_SAMPLE_RATE, v_AUDIO_SAMPLE_RATE(rate));
-	/* hdmi_writel(hdmi_dev, FC_AUDSCHNLS2, 0x1); */
-	/* hdmi_writel(hdmi_dev, FC_AUDSCHNLS8, ((~rate) << 4) | 0x2); */
+	hdmi_writel(hdmi_dev, FC_AUDSCHNLS8, ((~rate) << 4) | 0x2);
 
 	hdmi_dev_config_aai(hdmi_dev, audio);
 
diff --git a/sound/soc/codecs/rk1000_codec.c b/sound/soc/codecs/rk1000_codec.c
index bd979cd255a4..ffc0b98a9bee 100755
--- a/sound/soc/codecs/rk1000_codec.c
+++ b/sound/soc/codecs/rk1000_codec.c
@@ -613,7 +613,7 @@ static struct snd_soc_dai_ops rk1000_codec_ops = {
 	.digital_mute = rk1000_codec_mute,
 };
 
-#define RK1000_CODEC_RATES SNDRV_PCM_RATE_8000_96000
+#define RK1000_CODEC_RATES SNDRV_PCM_RATE_8000_192000
 #define RK1000_CODEC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
 				SNDRV_PCM_FMTBIT_S20_3LE |\
 				SNDRV_PCM_FMTBIT_S24_LE)
@@ -623,7 +623,7 @@ static struct snd_soc_dai_driver rk1000_codec_dai[] = {
 		.playback = {
 			.stream_name = "Playback",
 			.channels_min = 1,
-			.channels_max = 2,
+			.channels_max = 8,
 			.rates = RK1000_CODEC_RATES,
 			.formats = RK1000_CODEC_FORMATS,
 		},
diff --git a/sound/soc/rockchip/rk30_i2s.c b/sound/soc/rockchip/rk30_i2s.c
index bb15f42b3250..d66d5ffd9ec1 100755
--- a/sound/soc/rockchip/rk30_i2s.c
+++ b/sound/soc/rockchip/rk30_i2s.c
@@ -44,6 +44,7 @@
 
 #include "rk_pcm.h"
 #include "rk_i2s.h"
+#include "../../../drivers/video/rockchip/hdmi/rockchip-hdmi.h"
 
 #if 0
 #define I2S_DBG(x...) printk(KERN_INFO x)
@@ -82,6 +83,8 @@ extern int hdmi_get_hotplug(void);
 #define hdmi_get_hotplug() 0
 #endif
 
+
+
 static inline struct rk30_i2s_info *to_info(struct snd_soc_dai *dai)
 {
 	return snd_soc_dai_get_drvdata(dai);
@@ -283,6 +286,29 @@ out_:
 	return ret;
 }
 
+static int SR2FS(int samplerate)
+{
+	switch (samplerate) {
+	case 32000:
+		return HDMI_AUDIO_FS_32000;
+	case 44100:
+		return HDMI_AUDIO_FS_44100;
+	case 48000:
+		return HDMI_AUDIO_FS_48000;
+	case 88200:
+		return HDMI_AUDIO_FS_88200;
+	case 96000:
+		return HDMI_AUDIO_FS_96000;
+	case 176400:
+		return HDMI_AUDIO_FS_176400;
+	case 192000:
+		return HDMI_AUDIO_FS_192000;
+	default:
+		I2S_DBG("SR2FS %d unsupport.", samplerate);
+		return HDMI_AUDIO_FS_44100;
+	}
+}
+
 static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream,
 				struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
@@ -290,9 +316,9 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream,
 	u32 iismod;
 	u32 dmarc;
 	unsigned long flags;
+	struct hdmi_audio hdmi_audio_cfg;
 
 	I2S_DBG("Enter %s, %d \n", __func__, __LINE__);
-
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		dai->playback_dma_data = &i2s->playback_dma_data;
 	else
@@ -315,14 +341,42 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream,
 		iismod |= I2S_DATA_WIDTH(19);
 		break;
 	case SNDRV_PCM_FORMAT_S24_LE:
+	case SNDRV_PCM_FORMAT_S24_3LE:
 		iismod |= I2S_DATA_WIDTH(23);
 		break;
 	case SNDRV_PCM_FORMAT_S32_LE:
 		iismod |= I2S_DATA_WIDTH(31);
 		break;
 	}
+	iismod &= ~CHANNLE_4_EN;
+	switch (params_channels(params)) {
+	case 8:
+		iismod |= CHANNLE_4_EN;
+		break;
+	case 6:
+		iismod |= CHANNEL_3_EN;
+		break;
+	case 4:
+		iismod |= CHANNEL_2_EN;
+		break;
+	case 2:
+		iismod |= CHANNEL_1_EN;
+		break;
+	default:
+		I2S_DBG("%d channels not supported\n",
+			params_channels(params));
+		return -EINVAL;
+	}
+	/* set  hdmi codec params */
+	if (HW_PARAMS_FLAG_NLPCM == params->flags)
+		hdmi_audio_cfg.type = HDMI_AUDIO_NLPCM;
+	else
+		hdmi_audio_cfg.type = HDMI_AUDIO_LPCM;
+	hdmi_audio_cfg.channel = params_channels(params);
+	hdmi_audio_cfg.rate = SR2FS(params_rate(params));
+	hdmi_audio_cfg.word_length = HDMI_AUDIO_WORD_LENGTH_16bit;
+	hdmi_config_audio(&hdmi_audio_cfg);
 
-//	writel((16<<24) |(16<<18)|(16<<12)|(16<<6)|16, &(pheadi2s->I2S_FIFOLR));
 	dmarc = readl(&(pheadi2s->I2S_DMACR));
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -445,7 +499,7 @@ static struct snd_soc_dai_ops rockchip_i2s_dai_ops = {
 	.set_sysclk = rockchip_i2s_set_sysclk,
 };
 
-#define ROCKCHIP_I2S_STEREO_RATES SNDRV_PCM_RATE_8000_96000
+#define ROCKCHIP_I2S_STEREO_RATES SNDRV_PCM_RATE_8000_192000
 #define ROCKCHIP_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
 
diff --git a/sound/soc/rockchip/rk_hdmi_i2s.c b/sound/soc/rockchip/rk_hdmi_i2s.c
index fe9c716861e0..2d4c63daae72 100755
--- a/sound/soc/rockchip/rk_hdmi_i2s.c
+++ b/sound/soc/rockchip/rk_hdmi_i2s.c
@@ -75,7 +75,7 @@ static int hdmi_i2s_hifi_hw_params(struct snd_pcm_substream *substream,
 		__func__, __LINE__,
 		params_rate(params));
 
-	div_bclk = 63;
+	div_bclk = 127;
 	div_mclk = pll_out/(params_rate(params)*(div_bclk+1))-1;
 
 	snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
diff --git a/sound/soc/rockchip/rk_pcm.c b/sound/soc/rockchip/rk_pcm.c
index dad8e63e34dd..426be3eda105 100755
--- a/sound/soc/rockchip/rk_pcm.c
+++ b/sound/soc/rockchip/rk_pcm.c
@@ -34,9 +34,9 @@ static const struct snd_pcm_hardware rockchip_pcm_hardware = {
 				    SNDRV_PCM_FMTBIT_S16_LE,
 	.channels_min		= 2,
 	.channels_max		= 8,
-	.buffer_bytes_max	= 128*1024,
+	.buffer_bytes_max	= 2*1024*1024,/*128*1024,*/
 	.period_bytes_min	= 64,
-	.period_bytes_max	= 32*1024,//2048*4,///PAGE_SIZE*2,
+	.period_bytes_max	= 512*1024,/*32*1024,//2048*4,///PAGE_SIZE*2,*/
 	.periods_min		= 3,
 	.periods_max		= 128,
 	.fifo_size		= 16,
@@ -46,7 +46,7 @@ static const struct snd_dmaengine_pcm_config rockchip_dmaengine_pcm_config = {
 	.pcm_hardware = &rockchip_pcm_hardware,
 	.prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
 	.compat_filter_fn = NULL,
-	.prealloc_buffer_size = PAGE_SIZE * 32,
+	.prealloc_buffer_size = PAGE_SIZE * 512,
 };
 
 int rockchip_pcm_platform_register(struct device *dev)
diff --git a/sound/soc/rockchip/rk_rk1000codec.c b/sound/soc/rockchip/rk_rk1000codec.c
index 55610210238f..f2a2c1e1a14c 100755
--- a/sound/soc/rockchip/rk_rk1000codec.c
+++ b/sound/soc/rockchip/rk_rk1000codec.c
@@ -39,6 +39,8 @@ static int rk29_hw_params(struct snd_pcm_substream *substream,
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 	unsigned int dai_fmt = rtd->dai_link->dai_fmt;
 	int ret;
+	unsigned int pll_out = 0;
+	int div_bclk, div_mclk;
 
 	DBG("Enter::%s----%d\n",  __func__, __LINE__);
 	/* set codec DAI configuration */
@@ -55,6 +57,43 @@ static int rk29_hw_params(struct snd_pcm_substream *substream,
 		       __func__);
 		return ret;
 	}
+
+	switch (params_rate(params)) {
+	case 8000:
+	case 16000:
+	case 24000:
+	case 32000:
+	case 48000:
+	case 96000:
+		pll_out = 12288000;
+		break;
+	case 11025:
+	case 22050:
+	case 44100:
+	case 88200:
+		pll_out = 11289600;
+		break;
+	case 176400:
+		pll_out = 11289600*2;
+		break;
+	case 192000:
+		pll_out = 12288000*2;
+		break;
+	default:
+		DBG("Enter:%s, %d, Error rate=%d\n", __func__,
+		    __LINE__, params_rate(params));
+		return -EINVAL;
+		break;
+	}
+	DBG("Enter:%s, %d, rate=%d\n", __func__, __LINE__, params_rate(params));
+	snd_soc_dai_set_sysclk(codec_dai, 0, pll_out, SND_SOC_CLOCK_IN);
+
+	div_bclk = 127;
+	div_mclk = pll_out/(params_rate(params)*128) - 1;
+
+	snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
+	snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, div_bclk);
+	snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, div_mclk);
 	return 0;
 }
 
-- 
2.34.1