From 63b81694ef7736849dcf7f7daf0becc6ebc02844 Mon Sep 17 00:00:00 2001
From: Viorel Suman <viorel.suman@nxp.com>
Date: Mon, 14 May 2018 16:28:48 +0300
Subject: [PATCH] MLK-17531-1: ASoC: fsl: sai: add support for SAI v3.01

a) Add support for new SAI (VERID, PARAM, MCTL, MDIV) registers
   available in i.MX 850d (SAI v3.00) and i.MX 845s (SAI v3.01).
b) Handle SAI MCLK register as function of SAI IP version.

Signed-off-by: Viorel Suman <viorel.suman@nxp.com>
Reviewed-by: Daniel Baluta <daniel.baluta@nxp.com>
---
 sound/soc/fsl/fsl_sai.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++-
 sound/soc/fsl/fsl_sai.h | 59 +++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 122 insertions(+), 2 deletions(-)

--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -29,6 +29,8 @@
 #define FSL_SAI_FLAGS (FSL_SAI_CSR_SEIE |\
 		       FSL_SAI_CSR_FEIE)
 
+#define FSL_SAI_VERID_0301	0x0301
+
 static struct fsl_sai_soc_data fsl_sai_vf610 = {
 	.imx = false,
 	/*dataline is mask, not index*/
@@ -422,6 +424,48 @@ static int fsl_sai_set_dai_fmt(struct sn
 	return ret;
 }
 
+static int fsl_sai_check_ver(struct snd_soc_dai *cpu_dai)
+{
+	struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev);
+	unsigned char offset = sai->soc->reg_offset;
+	unsigned int val;
+
+	if (FSL_SAI_TCSR(offset) == FSL_SAI_VERID)
+		return 0;
+
+	if (sai->verid.loaded)
+		return 0;
+
+	sai->verid.loaded = true;
+	regmap_read(sai->regmap, FSL_SAI_VERID, &val);
+	dev_dbg(cpu_dai->dev, "VERID: 0x%016X\n", val);
+
+	sai->verid.id = (val & FSL_SAI_VER_ID_MASK) >> FSL_SAI_VER_ID_SHIFT;
+	sai->verid.extfifo_en = (val & FSL_SAI_VER_EFIFO_EN);
+	sai->verid.timestamp_en = (val & FSL_SAI_VER_TSTMP_EN);
+
+	regmap_read(sai->regmap, FSL_SAI_PARAM, &val);
+	dev_dbg(cpu_dai->dev, "PARAM: 0x%016X\n", val);
+
+	/* max slots per frame, power of 2 */
+	sai->param.spf = 1 <<
+		((val & FSL_SAI_PAR_SPF_MASK) >> FSL_SAI_PAR_SPF_SHIFT);
+
+	/* words per fifo, power of 2 */
+	sai->param.wpf = 1 <<
+		((val & FSL_SAI_PAR_WPF_MASK) >> FSL_SAI_PAR_WPF_SHIFT);
+
+	/* number of datalines implemented */
+	sai->param.dln = val & FSL_SAI_PAR_DLN_MASK;
+
+	dev_dbg(cpu_dai->dev,
+		"Version: 0x%08X, SPF: %u, WPF: %u, DLN: %u\n",
+		sai->verid.id, sai->param.spf, sai->param.wpf, sai->param.dln
+	);
+
+	return 0;
+}
+
 static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
 {
 	struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai);
@@ -502,6 +546,15 @@ static int fsl_sai_set_bclk(struct snd_s
 				   FSL_SAI_CR2_DIV_MASK, savediv - 1);
 	}
 
+	fsl_sai_check_ver(dai);
+	switch (sai->verid.id) {
+	case FSL_SAI_VERID_0301:
+		/* SAI is in master mode at this point, so enable MCLK */
+		regmap_update_bits(sai->regmap, FSL_SAI_MCTL,
+				FSL_SAI_MCTL_MCLK_EN, FSL_SAI_MCTL_MCLK_EN);
+		break;
+	}
+
 	dev_dbg(dai->dev, "best fit: clock id=%d, div=%d, deviation =%d\n",
 			sai->mclk_id[tx], savediv, savesub);
 
@@ -1001,6 +1054,8 @@ static struct reg_default fsl_sai_v3_reg
 	{FSL_SAI_RCR4(8), 0},
 	{FSL_SAI_RCR5(8), 0},
 	{FSL_SAI_RMR,  0},
+	{FSL_SAI_MCTL, 0},
+	{FSL_SAI_MDIV, 0},
 };
 
 static bool fsl_sai_readable_reg(struct device *dev, unsigned int reg)
@@ -1041,6 +1096,10 @@ static bool fsl_sai_readable_reg(struct
 	case FSL_SAI_RFR6:
 	case FSL_SAI_RFR7:
 	case FSL_SAI_RMR:
+	case FSL_SAI_MCTL:
+	case FSL_SAI_MDIV:
+	case FSL_SAI_VERID:
+	case FSL_SAI_PARAM:
 		return true;
 	default:
 		return false;
@@ -1056,6 +1115,8 @@ static bool fsl_sai_volatile_reg(struct
 		return true;
 
 	switch (reg) {
+	case FSL_SAI_VERID:
+	case FSL_SAI_PARAM:
 	case FSL_SAI_TFR0:
 	case FSL_SAI_TFR1:
 	case FSL_SAI_TFR2:
@@ -1108,6 +1169,8 @@ static bool fsl_sai_writeable_reg(struct
 	case FSL_SAI_TDR7:
 	case FSL_SAI_TMR:
 	case FSL_SAI_RMR:
+	case FSL_SAI_MCTL:
+	case FSL_SAI_MDIV:
 		return true;
 	default:
 		return false;
@@ -1133,7 +1196,7 @@ static const struct regmap_config fsl_sa
 	.reg_stride = 4,
 	.val_bits = 32,
 
-	.max_register = FSL_SAI_RMR,
+	.max_register = FSL_SAI_MDIV,
 	.reg_defaults = fsl_sai_v3_reg_defaults,
 	.num_reg_defaults = ARRAY_SIZE(fsl_sai_v3_reg_defaults),
 	.readable_reg = fsl_sai_readable_reg,
--- a/sound/soc/fsl/fsl_sai.h
+++ b/sound/soc/fsl/fsl_sai.h
@@ -17,6 +17,8 @@
 			 SNDRV_PCM_FMTBIT_DSD_U32_LE)
 
 /* SAI Register Map Register */
+#define FSL_SAI_VERID	0x00 /* SAI Version ID Register */
+#define FSL_SAI_PARAM	0x04 /* SAI Parameter Register */
 #define FSL_SAI_TCSR(offset) (0x00 + offset) /* SAI Transmit Control */
 #define FSL_SAI_TCR1(offset) (0x04 + offset) /* SAI Transmit Configuration 1 */
 #define FSL_SAI_TCR2(offset) (0x08 + offset) /* SAI Transmit Configuration 2 */
@@ -39,8 +41,12 @@
 #define FSL_SAI_TFR5    0x54 /* SAI Transmit FIFO */
 #define FSL_SAI_TFR6    0x58 /* SAI Transmit FIFO */
 #define FSL_SAI_TFR7    0x5C /* SAI Transmit FIFO */
-#define FSL_SAI_TFR	0x40 /* SAI Transmit FIFO */
 #define FSL_SAI_TMR	0x60 /* SAI Transmit Mask */
+#define FSL_SAI_TTCTL	0x70 /* SAI Transmit Timestamp Control Register */
+#define FSL_SAI_TTCTN	0x74 /* SAI Transmit Timestamp Counter Register */
+#define FSL_SAI_TBCTN	0x78 /* SAI Transmit Bit Counter Register */
+#define FSL_SAI_TTCAP	0x7C /* SAI Transmit Timestamp Capture */
+
 #define FSL_SAI_RCSR(offset) (0x80 + offset) /* SAI Receive Control */
 #define FSL_SAI_RCR1(offset) (0x84 + offset) /* SAI Receive Configuration 1 */
 #define FSL_SAI_RCR2(offset) (0x88 + offset) /* SAI Receive Configuration 2 */
@@ -64,6 +70,13 @@
 #define FSL_SAI_RFR6    0xd8 /* SAI Receive FIFO */
 #define FSL_SAI_RFR7    0xdc /* SAI Receive FIFO */
 #define FSL_SAI_RMR	0xe0 /* SAI Receive Mask */
+#define FSL_SAI_RTCTL	0xf0 /* SAI Receive Timestamp Control Register */
+#define FSL_SAI_RTCTN	0xf4 /* SAI Receive Timestamp Counter Register */
+#define FSL_SAI_RBCTN	0xf8 /* SAI Receive Bit Counter Register */
+#define FSL_SAI_RTCAP	0xfc /* SAI Receive Timestamp Capture */
+
+#define FSL_SAI_MCTL	0x100 /* SAI MCLK Control Register */
+#define FSL_SAI_MDIV	0x104 /* SAI MCLK Divide Register */
 
 #define FSL_SAI_xCSR(tx, off)	(tx ? FSL_SAI_TCSR(off) : FSL_SAI_RCSR(off))
 #define FSL_SAI_xCR1(tx, off)	(tx ? FSL_SAI_TCR1(off) : FSL_SAI_RCR1(off))
@@ -109,6 +122,7 @@
 #define FSL_SAI_CR2_MSEL(ID)	((ID) << 26)
 #define FSL_SAI_CR2_BCP		BIT(25)
 #define FSL_SAI_CR2_BCD_MSTR	BIT(24)
+#define FSL_SAI_CR2_BCBP	BIT(23) /* BCLK bypass */
 #define FSL_SAI_CR2_DIV_MASK	0xff
 
 /* SAI Transmit and Receive Configuration 3 Register */
@@ -144,6 +158,33 @@
 #define FSL_SAI_CR5_FBT(x)	((x) << 8)
 #define FSL_SAI_CR5_FBT_MASK	(0x1f << 8)
 
+/* SAI MCLK Control Register */
+#define FSL_SAI_MCTL_MCLK_EN	BIT(30)	/* MCLK Enable */
+#define FSL_SAI_MCTL_MSEL_MASK	(0x3 << 24)
+#define FSL_SAI_MCTL_MSEL(ID)   ((ID) << 24)
+#define FSL_SAI_MCTL_MSEL_BUS	0
+#define FSL_SAI_MCTL_MSEL_MCLK1	BIT(24)
+#define FSL_SAI_MCTL_MSEL_MCLK2	BIT(25)
+#define FSL_SAI_MCTL_MSEL_MCLK3	(BIT(24) | BIT(25))
+#define FSL_SAI_MCTL_DIV_EN	BIT(23)
+#define FSL_SAI_MCTL_DIV_MASK	0xFF
+
+/* SAI VERID Register */
+#define FSL_SAI_VER_ID_SHIFT	16
+#define FSL_SAI_VER_ID_MASK	(0xFFFF << FSL_SAI_VER_ID_SHIFT)
+#define FSL_SAI_VER_EFIFO_EN	BIT(0)
+#define FSL_SAI_VER_TSTMP_EN	BIT(1)
+
+/* SAI PARAM Register */
+#define FSL_SAI_PAR_SPF_SHIFT	16
+#define FSL_SAI_PAR_SPF_MASK	(0x0F << FSL_SAI_PAR_SPF_SHIFT)
+#define FSL_SAI_PAR_WPF_SHIFT	8
+#define FSL_SAI_PAR_WPF_MASK	(0x0F << FSL_SAI_PAR_WPF_SHIFT)
+#define FSL_SAI_PAR_DLN_MASK	(0x0F)
+
+/* SAI MCLK Divide Register */
+#define FSL_SAI_MDIV_MASK	0xFFFFF
+
 /* SAI type */
 #define FSL_SAI_DMA		BIT(0)
 #define FSL_SAI_USE_AC97	BIT(1)
@@ -181,6 +222,19 @@ struct fsl_sai_soc_data {
 	bool constrain_period_size;
 };
 
+struct fsl_sai_verid {
+	u32 id;
+	bool timestamp_en;
+	bool extfifo_en;
+	bool loaded;
+};
+
+struct fsl_sai_param {
+	u32 spf; /* max slots per frame */
+	u32 wpf; /* words in fifo */
+	u32 dln; /* number of datalines implemented */
+};
+
 struct fsl_sai {
 	struct platform_device *pdev;
 	struct regmap *regmap;
@@ -213,6 +267,9 @@ struct fsl_sai {
 	struct pm_qos_request pm_qos_req;
 	struct pinctrl *pinctrl;
 	struct pinctrl_state *pins_state;
+
+	struct fsl_sai_verid verid;
+	struct fsl_sai_param param;
 };
 
 #define TX 1
