dai: Add support for 16ch MI2S

AFE MI2S interfaces now support up to 8 data lines
(16 channels). Add DAI support for the same.

Change-Id: I7c507c0161733094c1260731c7a046561fb63200
Signed-off-by: Dieter Luecking <dieterl@codeaurora.org>
Signed-off-by: Mangesh Kunchamwar <mangeshk@codeaurora.org>
diff --git a/asoc/msm-dai-fe.c b/asoc/msm-dai-fe.c
index 3dc4509..7654e56 100644
--- a/asoc/msm-dai-fe.c
+++ b/asoc/msm-dai-fe.c
@@ -99,7 +99,7 @@
 						SNDRV_PCM_FMTBIT_S24_3LE |
 						SNDRV_PCM_FMTBIT_S32_LE),
 			.channels_min = 1,
-			.channels_max = 8,
+			.channels_max = 16,
 			.rate_min =     8000,
 			.rate_max =	384000,
 		},
@@ -113,7 +113,7 @@
 				    SNDRV_PCM_FMTBIT_S24_3LE |
 				    SNDRV_PCM_FMTBIT_S32_LE),
 			.channels_min = 1,
-			.channels_max = 8,
+			.channels_max = 16,
 			.rate_min =     8000,
 			.rate_max =	48000,
 		},
@@ -311,7 +311,7 @@
 						SNDRV_PCM_FMTBIT_S24_3LE |
 						SNDRV_PCM_FMTBIT_S32_LE),
 			.channels_min = 1,
-			.channels_max = 8,
+			.channels_max = 16,
 			.rate_min =	8000,
 			.rate_max = 384000,
 		},
diff --git a/asoc/msm-dai-q6-v2.c b/asoc/msm-dai-q6-v2.c
index c24bb65..0c9d0b0 100644
--- a/asoc/msm-dai-q6-v2.c
+++ b/asoc/msm-dai-q6-v2.c
@@ -2095,7 +2095,7 @@
 	return 0;
 }
 
-static u8 num_of_bits_set(u8 sd_line_mask)
+static u16 num_of_bits_set(u16 sd_line_mask)
 {
 	u8 num_bits_set = 0;
 
@@ -4644,11 +4644,68 @@
 
 	dai_data->channels = params_channels(params);
 	switch (dai_data->channels) {
+	case 15:
+	case 16:
+		switch (mi2s_dai_config->pdata_mi2s_lines) {
+		case AFE_PORT_I2S_16CHS:
+			dai_data->port_config.i2s.channel_mode
+				= AFE_PORT_I2S_16CHS;
+			break;
+		default:
+			goto error_invalid_data;
+		};
+		break;
+	case 13:
+	case 14:
+		switch (mi2s_dai_config->pdata_mi2s_lines) {
+		case AFE_PORT_I2S_14CHS:
+		case AFE_PORT_I2S_16CHS:
+			dai_data->port_config.i2s.channel_mode
+				= AFE_PORT_I2S_14CHS;
+			break;
+		default:
+			goto error_invalid_data;
+		};
+		break;
+	case 11:
+	case 12:
+		switch (mi2s_dai_config->pdata_mi2s_lines) {
+		case AFE_PORT_I2S_12CHS:
+		case AFE_PORT_I2S_14CHS:
+		case AFE_PORT_I2S_16CHS:
+			dai_data->port_config.i2s.channel_mode
+				= AFE_PORT_I2S_12CHS;
+			break;
+		default:
+			goto error_invalid_data;
+		};
+		break;
+	case 9:
+	case 10:
+		switch (mi2s_dai_config->pdata_mi2s_lines) {
+		case AFE_PORT_I2S_10CHS:
+		case AFE_PORT_I2S_12CHS:
+		case AFE_PORT_I2S_14CHS:
+		case AFE_PORT_I2S_16CHS:
+			dai_data->port_config.i2s.channel_mode
+				= AFE_PORT_I2S_10CHS;
+			break;
+		default:
+			goto error_invalid_data;
+		};
+		break;
 	case 8:
 	case 7:
 		if (mi2s_dai_config->pdata_mi2s_lines < AFE_PORT_I2S_8CHS)
 			goto error_invalid_data;
-		dai_data->port_config.i2s.channel_mode = AFE_PORT_I2S_8CHS;
+		else
+			if (mi2s_dai_config->pdata_mi2s_lines
+					== AFE_PORT_I2S_8CHS_2)
+				dai_data->port_config.i2s.channel_mode =
+						AFE_PORT_I2S_8CHS_2;
+			else
+				dai_data->port_config.i2s.channel_mode =
+						AFE_PORT_I2S_8CHS;
 		break;
 	case 6:
 	case 5:
@@ -4658,14 +4715,33 @@
 		break;
 	case 4:
 	case 3:
-		if (mi2s_dai_config->pdata_mi2s_lines < AFE_PORT_I2S_QUAD01)
+		switch (mi2s_dai_config->pdata_mi2s_lines) {
+		case AFE_PORT_I2S_SD0:
+		case AFE_PORT_I2S_SD1:
+		case AFE_PORT_I2S_SD2:
+		case AFE_PORT_I2S_SD3:
+		case AFE_PORT_I2S_SD4:
+		case AFE_PORT_I2S_SD5:
+		case AFE_PORT_I2S_SD6:
+		case AFE_PORT_I2S_SD7:
 			goto error_invalid_data;
-		if (mi2s_dai_config->pdata_mi2s_lines == AFE_PORT_I2S_QUAD23)
+			break;
+		case AFE_PORT_I2S_QUAD01:
+		case AFE_PORT_I2S_QUAD23:
+		case AFE_PORT_I2S_QUAD45:
+		case AFE_PORT_I2S_QUAD67:
 			dai_data->port_config.i2s.channel_mode =
 				mi2s_dai_config->pdata_mi2s_lines;
-		else
+			break;
+		case AFE_PORT_I2S_8CHS_2:
+			dai_data->port_config.i2s.channel_mode =
+					AFE_PORT_I2S_QUAD45;
+			break;
+		default:
 			dai_data->port_config.i2s.channel_mode =
 					AFE_PORT_I2S_QUAD01;
+			break;
+		};
 		break;
 	case 2:
 	case 1:
@@ -4676,12 +4752,20 @@
 		case AFE_PORT_I2S_SD1:
 		case AFE_PORT_I2S_SD2:
 		case AFE_PORT_I2S_SD3:
+		case AFE_PORT_I2S_SD4:
+		case AFE_PORT_I2S_SD5:
+		case AFE_PORT_I2S_SD6:
+		case AFE_PORT_I2S_SD7:
 			dai_data->port_config.i2s.channel_mode =
 				mi2s_dai_config->pdata_mi2s_lines;
 			break;
 		case AFE_PORT_I2S_QUAD01:
 		case AFE_PORT_I2S_6CHS:
 		case AFE_PORT_I2S_8CHS:
+		case AFE_PORT_I2S_10CHS:
+		case AFE_PORT_I2S_12CHS:
+		case AFE_PORT_I2S_14CHS:
+		case AFE_PORT_I2S_16CHS:
 			if (dai_data->vi_feed_mono == SPKR_1)
 				dai_data->port_config.i2s.channel_mode =
 							AFE_PORT_I2S_SD0;
@@ -4693,6 +4777,14 @@
 			dai_data->port_config.i2s.channel_mode =
 						AFE_PORT_I2S_SD2;
 			break;
+		case AFE_PORT_I2S_QUAD45:
+			dai_data->port_config.i2s.channel_mode =
+						AFE_PORT_I2S_SD4;
+			break;
+		case AFE_PORT_I2S_QUAD67:
+			dai_data->port_config.i2s.channel_mode =
+						AFE_PORT_I2S_SD6;
+			break;
 		}
 		if (dai_data->channels == 2)
 			dai_data->port_config.i2s.mono_stereo =
@@ -4864,15 +4956,17 @@
 			.stream_name = "Primary MI2S Playback",
 			.aif_name = "PRI_MI2S_RX",
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
-				 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |
-				 SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
-				 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
-				 SNDRV_PCM_RATE_192000,
+				SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+				SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
+				SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
+				SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_352800 |
+				SNDRV_PCM_RATE_384000,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
 				SNDRV_PCM_FMTBIT_S24_LE |
 				SNDRV_PCM_FMTBIT_S24_3LE,
 			.rate_min =     8000,
-			.rate_max =     192000,
+			.rate_max =     384000,
 		},
 		.capture = {
 			.stream_name = "Primary MI2S Capture",
@@ -5257,6 +5351,18 @@
 		case MSM_MI2S_SD3:
 			*config_ptr = AFE_PORT_I2S_SD3;
 			break;
+		case MSM_MI2S_SD4:
+			*config_ptr = AFE_PORT_I2S_SD4;
+			break;
+		case MSM_MI2S_SD5:
+			*config_ptr = AFE_PORT_I2S_SD5;
+			break;
+		case MSM_MI2S_SD6:
+			*config_ptr = AFE_PORT_I2S_SD6;
+			break;
+		case MSM_MI2S_SD7:
+			*config_ptr = AFE_PORT_I2S_SD7;
+			break;
 		default:
 			pr_err("%s: invalid SD lines %d\n",
 				   __func__, sd_lines);
@@ -5271,6 +5377,12 @@
 		case MSM_MI2S_SD2 | MSM_MI2S_SD3:
 			*config_ptr = AFE_PORT_I2S_QUAD23;
 			break;
+		case MSM_MI2S_SD4 | MSM_MI2S_SD5:
+			*config_ptr = AFE_PORT_I2S_QUAD45;
+			break;
+		case MSM_MI2S_SD6 | MSM_MI2S_SD7:
+			*config_ptr = AFE_PORT_I2S_QUAD67;
+			break;
 		default:
 			pr_err("%s: invalid SD lines %d\n",
 				   __func__, sd_lines);
@@ -5293,6 +5405,57 @@
 		case MSM_MI2S_SD0 | MSM_MI2S_SD1 | MSM_MI2S_SD2 | MSM_MI2S_SD3:
 			*config_ptr = AFE_PORT_I2S_8CHS;
 			break;
+		case MSM_MI2S_SD4 | MSM_MI2S_SD5 | MSM_MI2S_SD6 | MSM_MI2S_SD7:
+			*config_ptr = AFE_PORT_I2S_8CHS_2;
+			break;
+		default:
+			pr_err("%s: invalid SD lines %d\n",
+				   __func__, sd_lines);
+			goto error_invalid_data;
+		}
+		break;
+	case 5:
+		switch (sd_lines) {
+		case MSM_MI2S_SD0 | MSM_MI2S_SD1 | MSM_MI2S_SD2
+		   | MSM_MI2S_SD3 | MSM_MI2S_SD4:
+			*config_ptr = AFE_PORT_I2S_10CHS;
+			break;
+		default:
+			pr_err("%s: invalid SD lines %d\n",
+				   __func__, sd_lines);
+			goto error_invalid_data;
+		}
+		break;
+	case 6:
+		switch (sd_lines) {
+		case MSM_MI2S_SD0 | MSM_MI2S_SD1 | MSM_MI2S_SD2
+		   | MSM_MI2S_SD3 | MSM_MI2S_SD4 | MSM_MI2S_SD5:
+			*config_ptr = AFE_PORT_I2S_12CHS;
+			break;
+		default:
+			pr_err("%s: invalid SD lines %d\n",
+				   __func__, sd_lines);
+			goto error_invalid_data;
+		}
+		break;
+	case 7:
+		switch (sd_lines) {
+		case MSM_MI2S_SD0 | MSM_MI2S_SD1 | MSM_MI2S_SD2 | MSM_MI2S_SD3
+		   | MSM_MI2S_SD4 | MSM_MI2S_SD5 | MSM_MI2S_SD6:
+			*config_ptr = AFE_PORT_I2S_14CHS;
+			break;
+		default:
+			pr_err("%s: invalid SD lines %d\n",
+				   __func__, sd_lines);
+			goto error_invalid_data;
+		}
+		break;
+	case 8:
+		switch (sd_lines) {
+		case MSM_MI2S_SD0 | MSM_MI2S_SD1 | MSM_MI2S_SD2 | MSM_MI2S_SD3
+		   | MSM_MI2S_SD4 | MSM_MI2S_SD5 | MSM_MI2S_SD6 | MSM_MI2S_SD7:
+			*config_ptr = AFE_PORT_I2S_16CHS;
+			break;
 		default:
 			pr_err("%s: invalid SD lines %d\n",
 				   __func__, sd_lines);
diff --git a/asoc/msm-dai-q6-v2.h b/asoc/msm-dai-q6-v2.h
index b3f457e..2327cfd 100644
--- a/asoc/msm-dai-q6-v2.h
+++ b/asoc/msm-dai-q6-v2.h
@@ -18,6 +18,11 @@
 #define MSM_MI2S_SD1 (1 << 1)
 #define MSM_MI2S_SD2 (1 << 2)
 #define MSM_MI2S_SD3 (1 << 3)
+#define MSM_MI2S_SD4 (1 << 4)
+#define MSM_MI2S_SD5 (1 << 5)
+#define MSM_MI2S_SD6 (1 << 6)
+#define MSM_MI2S_SD7 (1 << 7)
+
 #define MSM_MI2S_CAP_RX 0
 #define MSM_MI2S_CAP_TX 1