All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/9] ASoC: cygnus: Various improvements and fixes
@ 2017-08-14 22:06 ` Lori Hikichi
  0 siblings, 0 replies; 50+ messages in thread
From: Lori Hikichi @ 2017-08-14 22:06 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Mark Rutland, Ray Jui,
	Scott Branden, Jon Mason, bcm-kernel-feedback-list,
	Jaroslav Kysela, Takashi Iwai
  Cc: alsa-devel, devicetree, linux-arm-kernel, linux-kernel, Lori Hikichi

This patch series contains an number of improvements and refinements
to the driver. There is also a fix for a problem when transferring
four or more channels in TDM mode.

Lori Hikichi (9):
  ASoC: cygnus: Add support for 384kHz frame rates
  ASoC: cygnus: Update bindings for audio clock changes
  ASoC: cygnus: Allow each port to select its clock source
  ASoC: cygnus: Only enable MCLK pins when in use
  ASoC: cygnus: Remove support for 8 bit audio and for mono
  ASoc: cygnus: Fix problems with multichannel transfers
  ASoC: cygnus: Remove set_fmt from SPDIF dai ops
  ASoC: cygnus: Add EXPORT_SYMBOL for helper function
  ASoC: cygnus: Tidy up of structure access

 .../bindings/sound/brcm,cygnus-audio.txt           |   70 +-
 sound/soc/bcm/cygnus-pcm.c                         |   50 +-
 sound/soc/bcm/cygnus-ssp.c                         | 1336 ++++++++++----------
 sound/soc/bcm/cygnus-ssp.h                         |   51 +-
 4 files changed, 739 insertions(+), 768 deletions(-)

-- 
1.9.1

^ permalink raw reply	[flat|nested] 50+ messages in thread

* [PATCH 0/9] ASoC: cygnus: Various improvements and fixes
@ 2017-08-14 22:06 ` Lori Hikichi
  0 siblings, 0 replies; 50+ messages in thread
From: Lori Hikichi @ 2017-08-14 22:06 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Mark Rutland, Ray Jui,
	Scott Branden, Jon Mason,
	bcm-kernel-feedback-list-dY08KVG/lbpWk0Htik3J/w, Jaroslav Kysela,
	Takashi Iwai
  Cc: alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Lori Hikichi

This patch series contains an number of improvements and refinements
to the driver. There is also a fix for a problem when transferring
four or more channels in TDM mode.

Lori Hikichi (9):
  ASoC: cygnus: Add support for 384kHz frame rates
  ASoC: cygnus: Update bindings for audio clock changes
  ASoC: cygnus: Allow each port to select its clock source
  ASoC: cygnus: Only enable MCLK pins when in use
  ASoC: cygnus: Remove support for 8 bit audio and for mono
  ASoc: cygnus: Fix problems with multichannel transfers
  ASoC: cygnus: Remove set_fmt from SPDIF dai ops
  ASoC: cygnus: Add EXPORT_SYMBOL for helper function
  ASoC: cygnus: Tidy up of structure access

 .../bindings/sound/brcm,cygnus-audio.txt           |   70 +-
 sound/soc/bcm/cygnus-pcm.c                         |   50 +-
 sound/soc/bcm/cygnus-ssp.c                         | 1336 ++++++++++----------
 sound/soc/bcm/cygnus-ssp.h                         |   51 +-
 4 files changed, 739 insertions(+), 768 deletions(-)

-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 50+ messages in thread

* [PATCH 0/9] ASoC: cygnus: Various improvements and fixes
@ 2017-08-14 22:06 ` Lori Hikichi
  0 siblings, 0 replies; 50+ messages in thread
From: Lori Hikichi @ 2017-08-14 22:06 UTC (permalink / raw)
  To: linux-arm-kernel

This patch series contains an number of improvements and refinements
to the driver. There is also a fix for a problem when transferring
four or more channels in TDM mode.

Lori Hikichi (9):
  ASoC: cygnus: Add support for 384kHz frame rates
  ASoC: cygnus: Update bindings for audio clock changes
  ASoC: cygnus: Allow each port to select its clock source
  ASoC: cygnus: Only enable MCLK pins when in use
  ASoC: cygnus: Remove support for 8 bit audio and for mono
  ASoc: cygnus: Fix problems with multichannel transfers
  ASoC: cygnus: Remove set_fmt from SPDIF dai ops
  ASoC: cygnus: Add EXPORT_SYMBOL for helper function
  ASoC: cygnus: Tidy up of structure access

 .../bindings/sound/brcm,cygnus-audio.txt           |   70 +-
 sound/soc/bcm/cygnus-pcm.c                         |   50 +-
 sound/soc/bcm/cygnus-ssp.c                         | 1336 ++++++++++----------
 sound/soc/bcm/cygnus-ssp.h                         |   51 +-
 4 files changed, 739 insertions(+), 768 deletions(-)

-- 
1.9.1

^ permalink raw reply	[flat|nested] 50+ messages in thread

* [PATCH 1/9] ASoC: cygnus: Add support for 384kHz frame rates
  2017-08-14 22:06 ` Lori Hikichi
@ 2017-08-14 22:06   ` Lori Hikichi
  -1 siblings, 0 replies; 50+ messages in thread
From: Lori Hikichi @ 2017-08-14 22:06 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Mark Rutland, Ray Jui,
	Scott Branden, Jon Mason, bcm-kernel-feedback-list,
	Jaroslav Kysela, Takashi Iwai
  Cc: alsa-devel, devicetree, linux-arm-kernel, linux-kernel, Lori Hikichi

Allow the audio ports to operate at 384kHz.

Signed-off-by: Lori Hikichi <lori.hikichi@broadcom.com>
---
 sound/soc/bcm/cygnus-ssp.c | 235 +++++++++++----------------------------------
 1 file changed, 55 insertions(+), 180 deletions(-)

diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c
index e710bb0..1a57a4e 100644
--- a/sound/soc/bcm/cygnus-ssp.c
+++ b/sound/soc/bcm/cygnus-ssp.c
@@ -27,12 +27,6 @@
 
 #define DEFAULT_VCO    1354750204
 
-#define CYGNUS_TDM_RATE \
-		(SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | \
-		SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_22050 | \
-		SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
-		SNDRV_PCM_RATE_48000)
-
 #define CAPTURE_FCI_ID_BASE 0x180
 #define CYGNUS_SSP_TRISTATE_MASK 0x001fff
 #define CYGNUS_PLLCLKSEL_MASK 0xf
@@ -234,152 +228,20 @@ struct pll_macro_entry {
 	{98304000, 2},
 };
 
+#define CYGNUS_RATE_MIN     8000
+#define CYGNUS_RATE_MAX   384000
+
 /* List of valid frame sizes for tdm mode */
 static const int ssp_valid_tdm_framesize[] = {32, 64, 128, 256, 512};
 
-/*
- * Use this relationship to derive the sampling rate (lrclk)
- * lrclk = (mclk) / ((2*mclk_to_sclk_ratio) * (32 * SCLK))).
- *
- * Use mclk and pll_ch from the table above
- *
- * Valid SCLK = 0/1/2/4/8/12
- *
- * mclk_to_sclk_ratio = number of MCLK per SCLK. Division is twice the
- * value programmed in this field.
- * Valid mclk_to_sclk_ratio = 1 through to 15
- *
- * eg: To set lrclk = 48khz, set mclk = 12288000, mclk_to_sclk_ratio = 2,
- * SCLK = 64
- */
-struct _ssp_clk_coeff {
-	u32 mclk;
-	u32 sclk_rate;
-	u32 rate;
-	u32 mclk_rate;
+static const unsigned int cygnus_rates[] = {
+	 8000, 11025,  16000,  22050,  32000,  44100, 48000,
+	88200, 96000, 176400, 192000, 352800, 384000
 };
 
-static const struct _ssp_clk_coeff ssp_clk_coeff[] = {
-	{ 4096000,  32,  16000, 4},
-	{ 4096000,  32,  32000, 2},
-	{ 4096000,  64,   8000, 4},
-	{ 4096000,  64,  16000, 2},
-	{ 4096000,  64,  32000, 1},
-	{ 4096000, 128,   8000, 2},
-	{ 4096000, 128,  16000, 1},
-	{ 4096000, 256,   8000, 1},
-
-	{ 6144000,  32,  16000, 6},
-	{ 6144000,  32,  32000, 3},
-	{ 6144000,  32,  48000, 2},
-	{ 6144000,  32,  96000, 1},
-	{ 6144000,  64,   8000, 6},
-	{ 6144000,  64,  16000, 3},
-	{ 6144000,  64,  48000, 1},
-	{ 6144000, 128,   8000, 3},
-
-	{ 8192000,  32,  32000, 4},
-	{ 8192000,  64,  16000, 4},
-	{ 8192000,  64,  32000, 2},
-	{ 8192000, 128,   8000, 4},
-	{ 8192000, 128,  16000, 2},
-	{ 8192000, 128,  32000, 1},
-	{ 8192000, 256,   8000, 2},
-	{ 8192000, 256,  16000, 1},
-	{ 8192000, 512,   8000, 1},
-
-	{12288000,  32,  32000, 6},
-	{12288000,  32,  48000, 4},
-	{12288000,  32,  96000, 2},
-	{12288000,  32, 192000, 1},
-	{12288000,  64,  16000, 6},
-	{12288000,  64,  32000, 3},
-	{12288000,  64,  48000, 2},
-	{12288000,  64,  96000, 1},
-	{12288000, 128,   8000, 6},
-	{12288000, 128,  16000, 3},
-	{12288000, 128,  48000, 1},
-	{12288000, 256,   8000, 3},
-
-	{16384000,  64,  32000, 4},
-	{16384000, 128,  16000, 4},
-	{16384000, 128,  32000, 2},
-	{16384000, 256,   8000, 4},
-	{16384000, 256,  16000, 2},
-	{16384000, 256,  32000, 1},
-	{16384000, 512,   8000, 2},
-	{16384000, 512,  16000, 1},
-
-	{24576000,  32,  96000, 4},
-	{24576000,  32, 192000, 2},
-	{24576000,  64,  32000, 6},
-	{24576000,  64,  48000, 4},
-	{24576000,  64,  96000, 2},
-	{24576000,  64, 192000, 1},
-	{24576000, 128,  16000, 6},
-	{24576000, 128,  32000, 3},
-	{24576000, 128,  48000, 2},
-	{24576000, 256,   8000, 6},
-	{24576000, 256,  16000, 3},
-	{24576000, 256,  48000, 1},
-	{24576000, 512,   8000, 3},
-
-	{49152000,  32, 192000, 4},
-	{49152000,  64,  96000, 4},
-	{49152000,  64, 192000, 2},
-	{49152000, 128,  32000, 6},
-	{49152000, 128,  48000, 4},
-	{49152000, 128,  96000, 2},
-	{49152000, 128, 192000, 1},
-	{49152000, 256,  16000, 6},
-	{49152000, 256,  32000, 3},
-	{49152000, 256,  48000, 2},
-	{49152000, 256,  96000, 1},
-	{49152000, 512,   8000, 6},
-	{49152000, 512,  16000, 3},
-	{49152000, 512,  48000, 1},
-
-	{ 5644800,  32,  22050, 4},
-	{ 5644800,  32,  44100, 2},
-	{ 5644800,  32,  88200, 1},
-	{ 5644800,  64,  11025, 4},
-	{ 5644800,  64,  22050, 2},
-	{ 5644800,  64,  44100, 1},
-
-	{11289600,  32,  44100, 4},
-	{11289600,  32,  88200, 2},
-	{11289600,  32, 176400, 1},
-	{11289600,  64,  22050, 4},
-	{11289600,  64,  44100, 2},
-	{11289600,  64,  88200, 1},
-	{11289600, 128,  11025, 4},
-	{11289600, 128,  22050, 2},
-	{11289600, 128,  44100, 1},
-
-	{22579200,  32,  88200, 4},
-	{22579200,  32, 176400, 2},
-	{22579200,  64,  44100, 4},
-	{22579200,  64,  88200, 2},
-	{22579200,  64, 176400, 1},
-	{22579200, 128,  22050, 4},
-	{22579200, 128,  44100, 2},
-	{22579200, 128,  88200, 1},
-	{22579200, 256,  11025, 4},
-	{22579200, 256,  22050, 2},
-	{22579200, 256,  44100, 1},
-
-	{45158400,  32, 176400, 4},
-	{45158400,  64,  88200, 4},
-	{45158400,  64, 176400, 2},
-	{45158400, 128,  44100, 4},
-	{45158400, 128,  88200, 2},
-	{45158400, 128, 176400, 1},
-	{45158400, 256,  22050, 4},
-	{45158400, 256,  44100, 2},
-	{45158400, 256,  88200, 1},
-	{45158400, 512,  11025, 4},
-	{45158400, 512,  22050, 2},
-	{45158400, 512,  44100, 1},
+static const struct snd_pcm_hw_constraint_list cygnus_rate_constraint = {
+	.count = ARRAY_SIZE(cygnus_rates),
+	.list = cygnus_rates,
 };
 
 static struct cygnus_aio_port *cygnus_dai_get_portinfo(struct snd_soc_dai *dai)
@@ -679,40 +541,55 @@ static int pll_configure_mclk(struct cygnus_audio *cygaud, u32 mclk,
 	return p_entry->pll_ch_num;
 }
 
-static int cygnus_ssp_set_clocks(struct cygnus_aio_port *aio,
-			struct cygnus_audio *cygaud)
+static int cygnus_ssp_set_clocks(struct cygnus_aio_port *aio)
 {
-	u32 value, i = 0;
+	u32 value;
 	u32 mask = 0xf;
 	u32 sclk;
-	bool found = false;
-	const struct _ssp_clk_coeff *p_entry = NULL;
+	u32 mclk_rate;
+	unsigned int bit_rate;
+	unsigned int ratio;
 
-	for (i = 0; i < ARRAY_SIZE(ssp_clk_coeff); i++) {
-		p_entry = &ssp_clk_coeff[i];
-		if ((p_entry->rate == aio->lrclk) &&
-		    (p_entry->sclk_rate == aio->bit_per_frame) &&
-		    (p_entry->mclk == aio->mclk)) {
-			found = true;
-			break;
-		}
-	}
-	if (!found) {
+	bit_rate = aio->bit_per_frame * aio->lrclk;
+
+	/*
+	 * Check if the bit clock can be generated from the given MCLK.
+	 * MCLK must be a perfect multiple of bit clock and must be one of the
+	 * following values... (2,4,6,8,10,12,14)
+	 */
+	if ((aio->mclk % bit_rate) != 0)
+		return -EINVAL;
+
+	ratio = aio->mclk / bit_rate;
+	switch (ratio) {
+	case 2:
+	case 4:
+	case 6:
+	case 8:
+	case 10:
+	case 12:
+	case 14:
+		mclk_rate = ratio / 2;
+		break;
+
+	default:
 		dev_err(aio->cygaud->dev,
-			"No valid match found in ssp_clk_coeff array\n");
+			"Invalid combination of MCLK and BCLK\n");
 		dev_err(aio->cygaud->dev, "lrclk = %u, bits/frame = %u, mclk = %u\n",
 			aio->lrclk, aio->bit_per_frame, aio->mclk);
 		return -EINVAL;
 	}
 
-	sclk = aio->bit_per_frame;
-	if (sclk == 512)
-		sclk = 0;
-	/* sclks_per_1fs_div = sclk cycles/32 */
-	sclk /= 32;
 	/* Set sclk rate */
 	switch (aio->port_type) {
 	case PORT_TDM:
+		sclk = aio->bit_per_frame;
+		if (sclk == 512)
+			sclk = 0;
+
+		/* sclks_per_1fs_div = sclk cycles/32 */
+		sclk /= 32;
+
 		/* Set number of bitclks per frame */
 		value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
 		value &= ~(mask << I2S_OUT_CFGX_SCLKS_PER_1FS_DIV32);
@@ -731,7 +608,7 @@ static int cygnus_ssp_set_clocks(struct cygnus_aio_port *aio,
 	/* Set MCLK_RATE ssp port (spdif and ssp are the same) */
 	value = readl(aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
 	value &= ~(0xf << I2S_OUT_MCLKRATE_SHIFT);
-	value |= (p_entry->mclk_rate << I2S_OUT_MCLKRATE_SHIFT);
+	value |= (mclk_rate << I2S_OUT_MCLKRATE_SHIFT);
 	writel(value, aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
 
 	dev_dbg(aio->cygaud->dev, "mclk cfg reg = 0x%x\n", value);
@@ -745,7 +622,6 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 				 struct snd_soc_dai *dai)
 {
 	struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai);
-	struct cygnus_audio *cygaud = snd_soc_dai_get_drvdata(dai);
 	int rate, bitres;
 	u32 value;
 	u32 mask = 0x1f;
@@ -841,7 +717,7 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 	aio->lrclk = rate;
 
 	if (!aio->is_slave)
-		ret = cygnus_ssp_set_clocks(aio, cygaud);
+		ret = cygnus_ssp_set_clocks(aio);
 
 	return ret;
 }
@@ -888,6 +764,11 @@ static int cygnus_ssp_startup(struct snd_pcm_substream *substream,
 	else
 		aio->clk_trace.cap_en = true;
 
+	substream->runtime->hw.rate_min = CYGNUS_RATE_MIN;
+	substream->runtime->hw.rate_max = CYGNUS_RATE_MAX;
+
+	snd_pcm_hw_constraint_list(substream->runtime, 0,
+			SNDRV_PCM_HW_PARAM_RATE, &cygnus_rate_constraint);
 	return 0;
 }
 
@@ -1261,9 +1142,7 @@ static int cygnus_ssp_resume(struct snd_soc_dai *cpu_dai)
 	.playback = { \
 		.channels_min = 1, \
 		.channels_max = 16, \
-		.rates = CYGNUS_TDM_RATE | SNDRV_PCM_RATE_88200 | \
-			SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | \
-			SNDRV_PCM_RATE_192000, \
+		.rates = SNDRV_PCM_RATE_KNOT, \
 		.formats = SNDRV_PCM_FMTBIT_S8 | \
 				SNDRV_PCM_FMTBIT_S16_LE | \
 				SNDRV_PCM_FMTBIT_S32_LE, \
@@ -1271,9 +1150,7 @@ static int cygnus_ssp_resume(struct snd_soc_dai *cpu_dai)
 	.capture = { \
 		.channels_min = 2, \
 		.channels_max = 16, \
-		.rates = CYGNUS_TDM_RATE | SNDRV_PCM_RATE_88200 | \
-			SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | \
-			SNDRV_PCM_RATE_192000, \
+		.rates = SNDRV_PCM_RATE_KNOT, \
 		.formats =  SNDRV_PCM_FMTBIT_S16_LE | \
 					SNDRV_PCM_FMTBIT_S32_LE, \
 	}, \
@@ -1293,9 +1170,7 @@ static int cygnus_ssp_resume(struct snd_soc_dai *cpu_dai)
 	.playback = {
 		.channels_min = 2,
 		.channels_max = 2,
-		.rates = CYGNUS_TDM_RATE | SNDRV_PCM_RATE_88200 |
-			SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
-			SNDRV_PCM_RATE_192000,
+		.rates = SNDRV_PCM_RATE_KNOT,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE |
 			SNDRV_PCM_FMTBIT_S32_LE,
 	},
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH 1/9] ASoC: cygnus: Add support for 384kHz frame rates
@ 2017-08-14 22:06   ` Lori Hikichi
  0 siblings, 0 replies; 50+ messages in thread
From: Lori Hikichi @ 2017-08-14 22:06 UTC (permalink / raw)
  To: linux-arm-kernel

Allow the audio ports to operate at 384kHz.

Signed-off-by: Lori Hikichi <lori.hikichi@broadcom.com>
---
 sound/soc/bcm/cygnus-ssp.c | 235 +++++++++++----------------------------------
 1 file changed, 55 insertions(+), 180 deletions(-)

diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c
index e710bb0..1a57a4e 100644
--- a/sound/soc/bcm/cygnus-ssp.c
+++ b/sound/soc/bcm/cygnus-ssp.c
@@ -27,12 +27,6 @@
 
 #define DEFAULT_VCO    1354750204
 
-#define CYGNUS_TDM_RATE \
-		(SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | \
-		SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_22050 | \
-		SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
-		SNDRV_PCM_RATE_48000)
-
 #define CAPTURE_FCI_ID_BASE 0x180
 #define CYGNUS_SSP_TRISTATE_MASK 0x001fff
 #define CYGNUS_PLLCLKSEL_MASK 0xf
@@ -234,152 +228,20 @@ struct pll_macro_entry {
 	{98304000, 2},
 };
 
+#define CYGNUS_RATE_MIN     8000
+#define CYGNUS_RATE_MAX   384000
+
 /* List of valid frame sizes for tdm mode */
 static const int ssp_valid_tdm_framesize[] = {32, 64, 128, 256, 512};
 
-/*
- * Use this relationship to derive the sampling rate (lrclk)
- * lrclk = (mclk) / ((2*mclk_to_sclk_ratio) * (32 * SCLK))).
- *
- * Use mclk and pll_ch from the table above
- *
- * Valid SCLK = 0/1/2/4/8/12
- *
- * mclk_to_sclk_ratio = number of MCLK per SCLK. Division is twice the
- * value programmed in this field.
- * Valid mclk_to_sclk_ratio = 1 through to 15
- *
- * eg: To set lrclk = 48khz, set mclk = 12288000, mclk_to_sclk_ratio = 2,
- * SCLK = 64
- */
-struct _ssp_clk_coeff {
-	u32 mclk;
-	u32 sclk_rate;
-	u32 rate;
-	u32 mclk_rate;
+static const unsigned int cygnus_rates[] = {
+	 8000, 11025,  16000,  22050,  32000,  44100, 48000,
+	88200, 96000, 176400, 192000, 352800, 384000
 };
 
-static const struct _ssp_clk_coeff ssp_clk_coeff[] = {
-	{ 4096000,  32,  16000, 4},
-	{ 4096000,  32,  32000, 2},
-	{ 4096000,  64,   8000, 4},
-	{ 4096000,  64,  16000, 2},
-	{ 4096000,  64,  32000, 1},
-	{ 4096000, 128,   8000, 2},
-	{ 4096000, 128,  16000, 1},
-	{ 4096000, 256,   8000, 1},
-
-	{ 6144000,  32,  16000, 6},
-	{ 6144000,  32,  32000, 3},
-	{ 6144000,  32,  48000, 2},
-	{ 6144000,  32,  96000, 1},
-	{ 6144000,  64,   8000, 6},
-	{ 6144000,  64,  16000, 3},
-	{ 6144000,  64,  48000, 1},
-	{ 6144000, 128,   8000, 3},
-
-	{ 8192000,  32,  32000, 4},
-	{ 8192000,  64,  16000, 4},
-	{ 8192000,  64,  32000, 2},
-	{ 8192000, 128,   8000, 4},
-	{ 8192000, 128,  16000, 2},
-	{ 8192000, 128,  32000, 1},
-	{ 8192000, 256,   8000, 2},
-	{ 8192000, 256,  16000, 1},
-	{ 8192000, 512,   8000, 1},
-
-	{12288000,  32,  32000, 6},
-	{12288000,  32,  48000, 4},
-	{12288000,  32,  96000, 2},
-	{12288000,  32, 192000, 1},
-	{12288000,  64,  16000, 6},
-	{12288000,  64,  32000, 3},
-	{12288000,  64,  48000, 2},
-	{12288000,  64,  96000, 1},
-	{12288000, 128,   8000, 6},
-	{12288000, 128,  16000, 3},
-	{12288000, 128,  48000, 1},
-	{12288000, 256,   8000, 3},
-
-	{16384000,  64,  32000, 4},
-	{16384000, 128,  16000, 4},
-	{16384000, 128,  32000, 2},
-	{16384000, 256,   8000, 4},
-	{16384000, 256,  16000, 2},
-	{16384000, 256,  32000, 1},
-	{16384000, 512,   8000, 2},
-	{16384000, 512,  16000, 1},
-
-	{24576000,  32,  96000, 4},
-	{24576000,  32, 192000, 2},
-	{24576000,  64,  32000, 6},
-	{24576000,  64,  48000, 4},
-	{24576000,  64,  96000, 2},
-	{24576000,  64, 192000, 1},
-	{24576000, 128,  16000, 6},
-	{24576000, 128,  32000, 3},
-	{24576000, 128,  48000, 2},
-	{24576000, 256,   8000, 6},
-	{24576000, 256,  16000, 3},
-	{24576000, 256,  48000, 1},
-	{24576000, 512,   8000, 3},
-
-	{49152000,  32, 192000, 4},
-	{49152000,  64,  96000, 4},
-	{49152000,  64, 192000, 2},
-	{49152000, 128,  32000, 6},
-	{49152000, 128,  48000, 4},
-	{49152000, 128,  96000, 2},
-	{49152000, 128, 192000, 1},
-	{49152000, 256,  16000, 6},
-	{49152000, 256,  32000, 3},
-	{49152000, 256,  48000, 2},
-	{49152000, 256,  96000, 1},
-	{49152000, 512,   8000, 6},
-	{49152000, 512,  16000, 3},
-	{49152000, 512,  48000, 1},
-
-	{ 5644800,  32,  22050, 4},
-	{ 5644800,  32,  44100, 2},
-	{ 5644800,  32,  88200, 1},
-	{ 5644800,  64,  11025, 4},
-	{ 5644800,  64,  22050, 2},
-	{ 5644800,  64,  44100, 1},
-
-	{11289600,  32,  44100, 4},
-	{11289600,  32,  88200, 2},
-	{11289600,  32, 176400, 1},
-	{11289600,  64,  22050, 4},
-	{11289600,  64,  44100, 2},
-	{11289600,  64,  88200, 1},
-	{11289600, 128,  11025, 4},
-	{11289600, 128,  22050, 2},
-	{11289600, 128,  44100, 1},
-
-	{22579200,  32,  88200, 4},
-	{22579200,  32, 176400, 2},
-	{22579200,  64,  44100, 4},
-	{22579200,  64,  88200, 2},
-	{22579200,  64, 176400, 1},
-	{22579200, 128,  22050, 4},
-	{22579200, 128,  44100, 2},
-	{22579200, 128,  88200, 1},
-	{22579200, 256,  11025, 4},
-	{22579200, 256,  22050, 2},
-	{22579200, 256,  44100, 1},
-
-	{45158400,  32, 176400, 4},
-	{45158400,  64,  88200, 4},
-	{45158400,  64, 176400, 2},
-	{45158400, 128,  44100, 4},
-	{45158400, 128,  88200, 2},
-	{45158400, 128, 176400, 1},
-	{45158400, 256,  22050, 4},
-	{45158400, 256,  44100, 2},
-	{45158400, 256,  88200, 1},
-	{45158400, 512,  11025, 4},
-	{45158400, 512,  22050, 2},
-	{45158400, 512,  44100, 1},
+static const struct snd_pcm_hw_constraint_list cygnus_rate_constraint = {
+	.count = ARRAY_SIZE(cygnus_rates),
+	.list = cygnus_rates,
 };
 
 static struct cygnus_aio_port *cygnus_dai_get_portinfo(struct snd_soc_dai *dai)
@@ -679,40 +541,55 @@ static int pll_configure_mclk(struct cygnus_audio *cygaud, u32 mclk,
 	return p_entry->pll_ch_num;
 }
 
-static int cygnus_ssp_set_clocks(struct cygnus_aio_port *aio,
-			struct cygnus_audio *cygaud)
+static int cygnus_ssp_set_clocks(struct cygnus_aio_port *aio)
 {
-	u32 value, i = 0;
+	u32 value;
 	u32 mask = 0xf;
 	u32 sclk;
-	bool found = false;
-	const struct _ssp_clk_coeff *p_entry = NULL;
+	u32 mclk_rate;
+	unsigned int bit_rate;
+	unsigned int ratio;
 
-	for (i = 0; i < ARRAY_SIZE(ssp_clk_coeff); i++) {
-		p_entry = &ssp_clk_coeff[i];
-		if ((p_entry->rate == aio->lrclk) &&
-		    (p_entry->sclk_rate == aio->bit_per_frame) &&
-		    (p_entry->mclk == aio->mclk)) {
-			found = true;
-			break;
-		}
-	}
-	if (!found) {
+	bit_rate = aio->bit_per_frame * aio->lrclk;
+
+	/*
+	 * Check if the bit clock can be generated from the given MCLK.
+	 * MCLK must be a perfect multiple of bit clock and must be one of the
+	 * following values... (2,4,6,8,10,12,14)
+	 */
+	if ((aio->mclk % bit_rate) != 0)
+		return -EINVAL;
+
+	ratio = aio->mclk / bit_rate;
+	switch (ratio) {
+	case 2:
+	case 4:
+	case 6:
+	case 8:
+	case 10:
+	case 12:
+	case 14:
+		mclk_rate = ratio / 2;
+		break;
+
+	default:
 		dev_err(aio->cygaud->dev,
-			"No valid match found in ssp_clk_coeff array\n");
+			"Invalid combination of MCLK and BCLK\n");
 		dev_err(aio->cygaud->dev, "lrclk = %u, bits/frame = %u, mclk = %u\n",
 			aio->lrclk, aio->bit_per_frame, aio->mclk);
 		return -EINVAL;
 	}
 
-	sclk = aio->bit_per_frame;
-	if (sclk == 512)
-		sclk = 0;
-	/* sclks_per_1fs_div = sclk cycles/32 */
-	sclk /= 32;
 	/* Set sclk rate */
 	switch (aio->port_type) {
 	case PORT_TDM:
+		sclk = aio->bit_per_frame;
+		if (sclk == 512)
+			sclk = 0;
+
+		/* sclks_per_1fs_div = sclk cycles/32 */
+		sclk /= 32;
+
 		/* Set number of bitclks per frame */
 		value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
 		value &= ~(mask << I2S_OUT_CFGX_SCLKS_PER_1FS_DIV32);
@@ -731,7 +608,7 @@ static int cygnus_ssp_set_clocks(struct cygnus_aio_port *aio,
 	/* Set MCLK_RATE ssp port (spdif and ssp are the same) */
 	value = readl(aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
 	value &= ~(0xf << I2S_OUT_MCLKRATE_SHIFT);
-	value |= (p_entry->mclk_rate << I2S_OUT_MCLKRATE_SHIFT);
+	value |= (mclk_rate << I2S_OUT_MCLKRATE_SHIFT);
 	writel(value, aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
 
 	dev_dbg(aio->cygaud->dev, "mclk cfg reg = 0x%x\n", value);
@@ -745,7 +622,6 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 				 struct snd_soc_dai *dai)
 {
 	struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai);
-	struct cygnus_audio *cygaud = snd_soc_dai_get_drvdata(dai);
 	int rate, bitres;
 	u32 value;
 	u32 mask = 0x1f;
@@ -841,7 +717,7 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 	aio->lrclk = rate;
 
 	if (!aio->is_slave)
-		ret = cygnus_ssp_set_clocks(aio, cygaud);
+		ret = cygnus_ssp_set_clocks(aio);
 
 	return ret;
 }
@@ -888,6 +764,11 @@ static int cygnus_ssp_startup(struct snd_pcm_substream *substream,
 	else
 		aio->clk_trace.cap_en = true;
 
+	substream->runtime->hw.rate_min = CYGNUS_RATE_MIN;
+	substream->runtime->hw.rate_max = CYGNUS_RATE_MAX;
+
+	snd_pcm_hw_constraint_list(substream->runtime, 0,
+			SNDRV_PCM_HW_PARAM_RATE, &cygnus_rate_constraint);
 	return 0;
 }
 
@@ -1261,9 +1142,7 @@ static int cygnus_ssp_resume(struct snd_soc_dai *cpu_dai)
 	.playback = { \
 		.channels_min = 1, \
 		.channels_max = 16, \
-		.rates = CYGNUS_TDM_RATE | SNDRV_PCM_RATE_88200 | \
-			SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | \
-			SNDRV_PCM_RATE_192000, \
+		.rates = SNDRV_PCM_RATE_KNOT, \
 		.formats = SNDRV_PCM_FMTBIT_S8 | \
 				SNDRV_PCM_FMTBIT_S16_LE | \
 				SNDRV_PCM_FMTBIT_S32_LE, \
@@ -1271,9 +1150,7 @@ static int cygnus_ssp_resume(struct snd_soc_dai *cpu_dai)
 	.capture = { \
 		.channels_min = 2, \
 		.channels_max = 16, \
-		.rates = CYGNUS_TDM_RATE | SNDRV_PCM_RATE_88200 | \
-			SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | \
-			SNDRV_PCM_RATE_192000, \
+		.rates = SNDRV_PCM_RATE_KNOT, \
 		.formats =  SNDRV_PCM_FMTBIT_S16_LE | \
 					SNDRV_PCM_FMTBIT_S32_LE, \
 	}, \
@@ -1293,9 +1170,7 @@ static int cygnus_ssp_resume(struct snd_soc_dai *cpu_dai)
 	.playback = {
 		.channels_min = 2,
 		.channels_max = 2,
-		.rates = CYGNUS_TDM_RATE | SNDRV_PCM_RATE_88200 |
-			SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
-			SNDRV_PCM_RATE_192000,
+		.rates = SNDRV_PCM_RATE_KNOT,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE |
 			SNDRV_PCM_FMTBIT_S32_LE,
 	},
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH 2/9] ASoC: cygnus: Update bindings for audio clock changes
  2017-08-14 22:06 ` Lori Hikichi
@ 2017-08-14 22:06   ` Lori Hikichi
  -1 siblings, 0 replies; 50+ messages in thread
From: Lori Hikichi @ 2017-08-14 22:06 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Mark Rutland, Ray Jui,
	Scott Branden, Jon Mason, bcm-kernel-feedback-list,
	Jaroslav Kysela, Takashi Iwai
  Cc: alsa-devel, devicetree, linux-arm-kernel, linux-kernel, Lori Hikichi

Allow each audio port to select which clock (if any) it wants to use.

Signed-off-by: Lori Hikichi <lori.hikichi@broadcom.com>
---
 .../bindings/sound/brcm,cygnus-audio.txt           | 70 ++++++++++++++--------
 1 file changed, 45 insertions(+), 25 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/brcm,cygnus-audio.txt b/Documentation/devicetree/bindings/sound/brcm,cygnus-audio.txt
index b139e66..2ef2f2c 100644
--- a/Documentation/devicetree/bindings/sound/brcm,cygnus-audio.txt
+++ b/Documentation/devicetree/bindings/sound/brcm,cygnus-audio.txt
@@ -9,19 +9,28 @@ Required properties:
 		Valid names are "aud" and "i2s_in". "aud" contains a
 		set of DMA, I2S_OUT and SPDIF registers. "i2s_in" contains
 		a set of I2S_IN registers.
-	- clocks: PLL and leaf clocks used by audio ports
-	- assigned-clocks: PLL and leaf clocks
-	- assigned-clock-parents: parent clocks of the assigned clocks
-		(usually the PLL)
-	- assigned-clock-rates: List of clock frequencies of the
-		assigned clocks
-	- clock-names: names of 3 leaf clocks used by audio ports
-		Valid names are "ch0_audio", "ch1_audio", "ch2_audio"
 	- interrupts: audio DMA interrupt number
 
+Optional properties:
+	- assigned-clocks: only valid choice is audiopll
+	- assigned-clock-rates: clock frequency for audiopll
+If none of the ports need an internal master clock then there no need to
+initialize the pll clock.
+
+
 SSP Subnode properties:
-- reg: The index of ssp port interface to use
-	Valid value are 0, 1, 2, or 3 (for spdif)
+Required:
+	- reg: The index of ssp port interface to use
+		Valid value are 0, 1, 2, or 3 (for spdif)
+Optional:
+	- clocks: clock used by audio port
+		  one of the audiopll outputs (see brcm,iproc-clocks.txt).
+	- clock-names: Must be "ssp_clk"
+	- brcm,ssp-clk-mux = Needed if a clock is named and used.  This value is
+			used to program the mux within the audio driver which selects
+			the incoming clock. Here is the mapping.
+			audio_pll   output 0 = 0, output 1 = 1, and output 2 = 2
+
 
 Example:
 	cygnus_audio: audio@180ae000 {
@@ -30,38 +39,49 @@ Example:
 		#size-cells = <0>;
 		reg = <0x180ae000 0xafd>, <0x180aec00 0x1f8>;
 		reg-names = "aud", "i2s_in";
-		clocks = <&audiopll BCM_CYGNUS_AUDIOPLL_CH0>,
-				<&audiopll BCM_CYGNUS_AUDIOPLL_CH1>,
-				<&audiopll BCM_CYGNUS_AUDIOPLL_CH2>;
-		assigned-clocks = <&audiopll BCM_CYGNUS_AUDIOPLL>,
-							<&audiopll BCM_CYGNUS_AUDIOPLL_CH0>,
-							<&audiopll BCM_CYGNUS_AUDIOPLL_CH1>,
-							<&audiopll BCM_CYGNUS_AUDIOPLL_CH2>;
-		assigned-clock-parents = <&audiopll BCM_CYGNUS_AUDIOPLL>;
-		assigned-clock-rates = <1769470191>,
-								<0>,
-								<0>,
-								<0>;
-		clock-names = "ch0_audio", "ch1_audio", "ch2_audio";
+
+		assigned-clocks = <&audiopll BCM_CYGNUS_AUDIOPLL>;
+		assigned-clock-rates = <1376255989>;
+
 		interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
 
 		ssp0: ssp_port@0 {
 			reg = <0>;
+
+			clocks = <&audiopll BCM_CYGNUS_AUDIOPLL_CH0>;
+			clock-names = "ssp_clk";
+			brcm,ssp-clk-mux = <0>;
+
 			status = "okay";
 		};
 
 		ssp1: ssp_port@1 {
 			reg = <1>;
-			status = "disabled";
+
+			clocks = <&audiopll BCM_CYGNUS_AUDIOPLL_CH1>;
+			clock-names = "ssp_clk";
+			brcm,ssp-clk-mux = <1>;
+
+			status = "okay";
 		};
 
 		ssp2: ssp_port@2 {
 			reg = <2>;
-			status = "disabled";
+
+			clocks = <&audiopll BCM_CYGNUS_AUDIOPLL_CH2>;
+			clock-names = "ssp_clk";
+			brcm,ssp-clk-mux = <2>;
+
+			status = "okay";
 		};
 
 		spdif: spdif_port@3 {
 			reg = <3>;
+
+			clocks = <&audiopll BCM_CYGNUS_AUDIOPLL_CH2>;
+       			clock-names = "ssp_clk";
+			brcm,ssp-clk-mux = <2>;
+
 			status = "disabled";
 		};
 	};
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH 2/9] ASoC: cygnus: Update bindings for audio clock changes
@ 2017-08-14 22:06   ` Lori Hikichi
  0 siblings, 0 replies; 50+ messages in thread
From: Lori Hikichi @ 2017-08-14 22:06 UTC (permalink / raw)
  To: linux-arm-kernel

Allow each audio port to select which clock (if any) it wants to use.

Signed-off-by: Lori Hikichi <lori.hikichi@broadcom.com>
---
 .../bindings/sound/brcm,cygnus-audio.txt           | 70 ++++++++++++++--------
 1 file changed, 45 insertions(+), 25 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/brcm,cygnus-audio.txt b/Documentation/devicetree/bindings/sound/brcm,cygnus-audio.txt
index b139e66..2ef2f2c 100644
--- a/Documentation/devicetree/bindings/sound/brcm,cygnus-audio.txt
+++ b/Documentation/devicetree/bindings/sound/brcm,cygnus-audio.txt
@@ -9,19 +9,28 @@ Required properties:
 		Valid names are "aud" and "i2s_in". "aud" contains a
 		set of DMA, I2S_OUT and SPDIF registers. "i2s_in" contains
 		a set of I2S_IN registers.
-	- clocks: PLL and leaf clocks used by audio ports
-	- assigned-clocks: PLL and leaf clocks
-	- assigned-clock-parents: parent clocks of the assigned clocks
-		(usually the PLL)
-	- assigned-clock-rates: List of clock frequencies of the
-		assigned clocks
-	- clock-names: names of 3 leaf clocks used by audio ports
-		Valid names are "ch0_audio", "ch1_audio", "ch2_audio"
 	- interrupts: audio DMA interrupt number
 
+Optional properties:
+	- assigned-clocks: only valid choice is audiopll
+	- assigned-clock-rates: clock frequency for audiopll
+If none of the ports need an internal master clock then there no need to
+initialize the pll clock.
+
+
 SSP Subnode properties:
-- reg: The index of ssp port interface to use
-	Valid value are 0, 1, 2, or 3 (for spdif)
+Required:
+	- reg: The index of ssp port interface to use
+		Valid value are 0, 1, 2, or 3 (for spdif)
+Optional:
+	- clocks: clock used by audio port
+		  one of the audiopll outputs (see brcm,iproc-clocks.txt).
+	- clock-names: Must be "ssp_clk"
+	- brcm,ssp-clk-mux = Needed if a clock is named and used.  This value is
+			used to program the mux within the audio driver which selects
+			the incoming clock. Here is the mapping.
+			audio_pll   output 0 = 0, output 1 = 1, and output 2 = 2
+
 
 Example:
 	cygnus_audio: audio at 180ae000 {
@@ -30,38 +39,49 @@ Example:
 		#size-cells = <0>;
 		reg = <0x180ae000 0xafd>, <0x180aec00 0x1f8>;
 		reg-names = "aud", "i2s_in";
-		clocks = <&audiopll BCM_CYGNUS_AUDIOPLL_CH0>,
-				<&audiopll BCM_CYGNUS_AUDIOPLL_CH1>,
-				<&audiopll BCM_CYGNUS_AUDIOPLL_CH2>;
-		assigned-clocks = <&audiopll BCM_CYGNUS_AUDIOPLL>,
-							<&audiopll BCM_CYGNUS_AUDIOPLL_CH0>,
-							<&audiopll BCM_CYGNUS_AUDIOPLL_CH1>,
-							<&audiopll BCM_CYGNUS_AUDIOPLL_CH2>;
-		assigned-clock-parents = <&audiopll BCM_CYGNUS_AUDIOPLL>;
-		assigned-clock-rates = <1769470191>,
-								<0>,
-								<0>,
-								<0>;
-		clock-names = "ch0_audio", "ch1_audio", "ch2_audio";
+
+		assigned-clocks = <&audiopll BCM_CYGNUS_AUDIOPLL>;
+		assigned-clock-rates = <1376255989>;
+
 		interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
 
 		ssp0: ssp_port at 0 {
 			reg = <0>;
+
+			clocks = <&audiopll BCM_CYGNUS_AUDIOPLL_CH0>;
+			clock-names = "ssp_clk";
+			brcm,ssp-clk-mux = <0>;
+
 			status = "okay";
 		};
 
 		ssp1: ssp_port at 1 {
 			reg = <1>;
-			status = "disabled";
+
+			clocks = <&audiopll BCM_CYGNUS_AUDIOPLL_CH1>;
+			clock-names = "ssp_clk";
+			brcm,ssp-clk-mux = <1>;
+
+			status = "okay";
 		};
 
 		ssp2: ssp_port at 2 {
 			reg = <2>;
-			status = "disabled";
+
+			clocks = <&audiopll BCM_CYGNUS_AUDIOPLL_CH2>;
+			clock-names = "ssp_clk";
+			brcm,ssp-clk-mux = <2>;
+
+			status = "okay";
 		};
 
 		spdif: spdif_port at 3 {
 			reg = <3>;
+
+			clocks = <&audiopll BCM_CYGNUS_AUDIOPLL_CH2>;
+       			clock-names = "ssp_clk";
+			brcm,ssp-clk-mux = <2>;
+
 			status = "disabled";
 		};
 	};
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH 3/9] ASoC: cygnus: Allow each port to select its clock source
@ 2017-08-14 22:06   ` Lori Hikichi
  0 siblings, 0 replies; 50+ messages in thread
From: Lori Hikichi @ 2017-08-14 22:06 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Mark Rutland, Ray Jui,
	Scott Branden, Jon Mason, bcm-kernel-feedback-list,
	Jaroslav Kysela, Takashi Iwai
  Cc: alsa-devel, devicetree, linux-arm-kernel, linux-kernel, Lori Hikichi

Add the ability to assign which of the 3 audio PLL outputs are to be
used by each port. Remove the suspend and resume handlers because the only
thing they were doing was unnecessarily maintaining the clock state.

Signed-off-by: Lori Hikichi <lori.hikichi@broadcom.com>
---
 sound/soc/bcm/cygnus-ssp.c | 332 ++++++++++++++-------------------------------
 sound/soc/bcm/cygnus-ssp.h |  15 +-
 2 files changed, 103 insertions(+), 244 deletions(-)

diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c
index 1a57a4e..00fd4dc 100644
--- a/sound/soc/bcm/cygnus-ssp.c
+++ b/sound/soc/bcm/cygnus-ssp.c
@@ -25,8 +25,6 @@
 
 #include "cygnus-ssp.h"
 
-#define DEFAULT_VCO    1354750204
-
 #define CAPTURE_FCI_ID_BASE 0x180
 #define CYGNUS_SSP_TRISTATE_MASK 0x001fff
 #define CYGNUS_PLLCLKSEL_MASK 0xf
@@ -95,22 +93,10 @@
 #define SPDIF_FORMAT_CFG_OFFSET  0xad8
 #define SPDIF_MCLK_CFG_OFFSET    0xadc
 
-/* AUD_FMM_IOP_PLL_0_xxx regs */
-#define IOP_PLL_0_MACRO_OFFSET    0xb00
-#define IOP_PLL_0_MDIV_Ch0_OFFSET 0xb14
-#define IOP_PLL_0_MDIV_Ch1_OFFSET 0xb18
-#define IOP_PLL_0_MDIV_Ch2_OFFSET 0xb1c
-
-#define IOP_PLL_0_ACTIVE_MDIV_Ch0_OFFSET 0xb30
-#define IOP_PLL_0_ACTIVE_MDIV_Ch1_OFFSET 0xb34
-#define IOP_PLL_0_ACTIVE_MDIV_Ch2_OFFSET 0xb38
-
-/* AUD_FMM_IOP_xxx regs */
-#define IOP_PLL_0_CONTROL_OFFSET     0xb04
-#define IOP_PLL_0_USER_NDIV_OFFSET   0xb08
-#define IOP_PLL_0_ACTIVE_NDIV_OFFSET 0xb20
-#define IOP_PLL_0_RESET_OFFSET       0xb5c
 
+/*--------------------------------------------
+ * Register offsets for i2s_in io space
+ */
 /* AUD_FMM_IOP_IN_I2S_xxx regs */
 #define IN_I2S_0_STREAM_CFG_OFFSET 0x00
 #define IN_I2S_0_CFG_OFFSET        0x04
@@ -173,12 +159,6 @@
 #define SPDIF_0_OUT_DITHER_ENA     3
 #define SPDIF_0_OUT_STREAM_ENA    31
 
-/* AUD_FMM_IOP_PLL_0_USER */
-#define IOP_PLL_0_USER_NDIV_FRAC   10
-
-/* AUD_FMM_IOP_PLL_0_ACTIVE */
-#define IOP_PLL_0_ACTIVE_NDIV_FRAC 10
-
 
 #define INIT_SSP_REGS(num) (struct cygnus_ssp_regs){ \
 		.i2s_stream_cfg = OUT_I2S_ ##num## _STREAM_CFG_OFFSET, \
@@ -193,41 +173,6 @@
 		.bf_sourcech_grp = BF_SRC_GRP ##num## _OFFSET \
 }
 
-struct pll_macro_entry {
-	u32 mclk;
-	u32 pll_ch_num;
-};
-
-/*
- * PLL has 3 output channels (1x, 2x, and 4x). Below are
- * the common MCLK frequencies used by audio driver
- */
-static const struct pll_macro_entry pll_predef_mclk[] = {
-	{ 4096000, 0},
-	{ 8192000, 1},
-	{16384000, 2},
-
-	{ 5644800, 0},
-	{11289600, 1},
-	{22579200, 2},
-
-	{ 6144000, 0},
-	{12288000, 1},
-	{24576000, 2},
-
-	{12288000, 0},
-	{24576000, 1},
-	{49152000, 2},
-
-	{22579200, 0},
-	{45158400, 1},
-	{90316800, 2},
-
-	{24576000, 0},
-	{49152000, 1},
-	{98304000, 2},
-};
-
 #define CYGNUS_RATE_MIN     8000
 #define CYGNUS_RATE_MAX   384000
 
@@ -488,59 +433,6 @@ static int audio_ssp_out_disable(struct cygnus_aio_port *aio)
 	return status;
 }
 
-static int pll_configure_mclk(struct cygnus_audio *cygaud, u32 mclk,
-	struct cygnus_aio_port *aio)
-{
-	int i = 0, error;
-	bool found = false;
-	const struct pll_macro_entry *p_entry;
-	struct clk *ch_clk;
-
-	for (i = 0; i < ARRAY_SIZE(pll_predef_mclk); i++) {
-		p_entry = &pll_predef_mclk[i];
-		if (p_entry->mclk == mclk) {
-			found = true;
-			break;
-		}
-	}
-	if (!found) {
-		dev_err(cygaud->dev,
-			"%s No valid mclk freq (%u) found!\n", __func__, mclk);
-		return -EINVAL;
-	}
-
-	ch_clk = cygaud->audio_clk[p_entry->pll_ch_num];
-
-	if ((aio->clk_trace.cap_en) && (!aio->clk_trace.cap_clk_en)) {
-		error = clk_prepare_enable(ch_clk);
-		if (error) {
-			dev_err(cygaud->dev, "%s clk_prepare_enable failed %d\n",
-				__func__, error);
-			return error;
-		}
-		aio->clk_trace.cap_clk_en = true;
-	}
-
-	if ((aio->clk_trace.play_en) && (!aio->clk_trace.play_clk_en)) {
-		error = clk_prepare_enable(ch_clk);
-		if (error) {
-			dev_err(cygaud->dev, "%s clk_prepare_enable failed %d\n",
-				__func__, error);
-			return error;
-		}
-		aio->clk_trace.play_clk_en = true;
-	}
-
-	error = clk_set_rate(ch_clk, mclk);
-	if (error) {
-		dev_err(cygaud->dev, "%s Set MCLK rate failed: %d\n",
-			__func__, error);
-		return error;
-	}
-
-	return p_entry->pll_ch_num;
-}
-
 static int cygnus_ssp_set_clocks(struct cygnus_aio_port *aio)
 {
 	u32 value;
@@ -723,26 +615,68 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 }
 
 /*
+ * Check that the actual mclk is within about 1% of the requested rate.
+ * The check is rather loose and is intended to catch any big mistakes.
+ * It is expected that the actual mclk rate may be a little different
+ * than the requested rate because the clock from which the mclk is
+ * derived (PLL) may not be an exact multiple of the mclk.
+ */
+static bool mclk_in_range(unsigned int target, unsigned int actual)
+{
+	unsigned int delta;
+
+	/* Mclk is at least several MHz, so simple div by 100 will suffice */
+	delta = target / 100;
+	return (actual > (target - delta)) && (actual < (target + delta));
+}
+
+/*
  * This function sets the mclk frequency for pll clock
  */
 static int cygnus_ssp_set_sysclk(struct snd_soc_dai *dai,
 			int clk_id, unsigned int freq, int dir)
 {
 	int sel;
+	int ret;
 	u32 value;
+	long rate;
 	struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai);
-	struct cygnus_audio *cygaud = snd_soc_dai_get_drvdata(dai);
 
 	dev_dbg(aio->cygaud->dev,
 		"%s Enter port = %d\n", __func__, aio->portnum);
-	sel = pll_configure_mclk(cygaud, freq, aio);
-	if (sel < 0) {
+
+	/*
+	 * This should not happen, but the machine file may inadvertently
+	 * call set_sysclk without configuring a clock via the devicetree.
+	 */
+	if (!aio->clk_info.audio_clk) {
 		dev_err(aio->cygaud->dev,
-			"%s Setting mclk failed.\n", __func__);
+			"%s Error. No clock assigned.\n", __func__);
+		return -ENODEV;
+	}
+
+	rate = clk_round_rate(aio->clk_info.audio_clk, freq);
+	if (rate < 0) {
+		dev_err(aio->cygaud->dev, "%s Error with with clock %ld.\n",
+			__func__, rate);
+		return rate;
+	}
+
+	if (!mclk_in_range(freq, rate)) {
+		dev_err(aio->cygaud->dev, "%s Can not set rate to %u  actual %ld.\n",
+			__func__, freq, rate);
 		return -EINVAL;
 	}
 
+	ret = clk_set_rate(aio->clk_info.audio_clk, freq);
+	if (ret) {
+		dev_err(aio->cygaud->dev,
+			"%s Set MCLK rate fail %d\n", __func__, ret);
+		return ret;
+	}
+
 	aio->mclk = freq;
+	sel = aio->clk_info.clk_mux;
 
 	dev_dbg(aio->cygaud->dev, "%s Setting MCLKSEL to %d\n", __func__, sel);
 	value = readl(aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
@@ -759,17 +693,14 @@ static int cygnus_ssp_startup(struct snd_pcm_substream *substream,
 	struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai);
 
 	snd_soc_dai_set_dma_data(dai, substream, aio);
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		aio->clk_trace.play_en = true;
-	else
-		aio->clk_trace.cap_en = true;
 
 	substream->runtime->hw.rate_min = CYGNUS_RATE_MIN;
 	substream->runtime->hw.rate_max = CYGNUS_RATE_MAX;
 
 	snd_pcm_hw_constraint_list(substream->runtime, 0,
 			SNDRV_PCM_HW_PARAM_RATE, &cygnus_rate_constraint);
-	return 0;
+
+	return clk_prepare_enable(aio->clk_info.audio_clk);
 }
 
 static void cygnus_ssp_shutdown(struct snd_pcm_substream *substream,
@@ -777,36 +708,7 @@ static void cygnus_ssp_shutdown(struct snd_pcm_substream *substream,
 {
 	struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai);
 
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		aio->clk_trace.play_en = false;
-	else
-		aio->clk_trace.cap_en = false;
-
-	if (!aio->is_slave) {
-		u32 val;
-
-		val = readl(aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
-		val &= CYGNUS_PLLCLKSEL_MASK;
-		if (val >= ARRAY_SIZE(aio->cygaud->audio_clk)) {
-			dev_err(aio->cygaud->dev, "Clk index %u is out of bounds\n",
-				val);
-			return;
-		}
-
-		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-			if (aio->clk_trace.play_clk_en) {
-				clk_disable_unprepare(aio->cygaud->
-						audio_clk[val]);
-				aio->clk_trace.play_clk_en = false;
-			}
-		} else {
-			if (aio->clk_trace.cap_clk_en) {
-				clk_disable_unprepare(aio->cygaud->
-						audio_clk[val]);
-				aio->clk_trace.cap_clk_en = false;
-			}
-		}
-	}
+	clk_disable_unprepare(aio->clk_info.audio_clk);
 }
 
 /*
@@ -945,7 +847,6 @@ static int cygnus_ssp_trigger(struct snd_pcm_substream *substream, int cmd,
 			       struct snd_soc_dai *dai)
 {
 	struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai);
-	struct cygnus_audio *cygaud = snd_soc_dai_get_drvdata(dai);
 
 	dev_dbg(aio->cygaud->dev,
 		"%s cmd %d at port = %d\n", __func__, cmd, aio->portnum);
@@ -958,7 +859,6 @@ static int cygnus_ssp_trigger(struct snd_pcm_substream *substream, int cmd,
 			audio_ssp_out_enable(aio);
 		else
 			audio_ssp_in_enable(aio);
-		cygaud->active_ports++;
 
 		break;
 
@@ -969,7 +869,6 @@ static int cygnus_ssp_trigger(struct snd_pcm_substream *substream, int cmd,
 			audio_ssp_out_disable(aio);
 		else
 			audio_ssp_in_disable(aio);
-		cygaud->active_ports--;
 		break;
 
 	default:
@@ -1063,68 +962,34 @@ static int cygnus_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
 	return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int cygnus_ssp_suspend(struct snd_soc_dai *cpu_dai)
+static int cygnus_ssp_set_pll(struct snd_soc_dai *cpu_dai, int pll_id,
+				 int source, unsigned int freq_in,
+				 unsigned int freq_out)
 {
 	struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(cpu_dai);
+	struct clk *clk_pll;
+	int ret = 0;
 
-	if (!aio->is_slave) {
-		u32 val;
-
-		val = readl(aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
-		val &= CYGNUS_PLLCLKSEL_MASK;
-		if (val >= ARRAY_SIZE(aio->cygaud->audio_clk)) {
-			dev_err(aio->cygaud->dev, "Clk index %u is out of bounds\n",
-				val);
-			return -EINVAL;
-		}
-
-		if (aio->clk_trace.cap_clk_en)
-			clk_disable_unprepare(aio->cygaud->audio_clk[val]);
-		if (aio->clk_trace.play_clk_en)
-			clk_disable_unprepare(aio->cygaud->audio_clk[val]);
+	if (!aio->clk_info.audio_clk) {
+		dev_err(aio->cygaud->dev,
+			"%s: port %d does not have an assigned clock.\n",
+			__func__, aio->portnum);
+		return -ENODEV;
+	}
 
-		aio->pll_clk_num = val;
+	clk_pll = clk_get_parent(aio->clk_info.audio_clk);
+	if (IS_ERR(clk_pll)) {
+		dev_err(aio->cygaud->dev,
+			"%s: could not get audiopll clock.\n", __func__);
+		return -ENODEV;
 	}
 
-	return 0;
+	ret = clk_set_rate(clk_pll, freq_out);
+
+	return ret;
 }
 
-static int cygnus_ssp_resume(struct snd_soc_dai *cpu_dai)
-{
-	struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(cpu_dai);
-	int error;
-
-	if (!aio->is_slave) {
-		if (aio->clk_trace.cap_clk_en) {
-			error = clk_prepare_enable(aio->cygaud->
-					audio_clk[aio->pll_clk_num]);
-			if (error) {
-				dev_err(aio->cygaud->dev, "%s clk_prepare_enable failed\n",
-					__func__);
-				return -EINVAL;
-			}
-		}
-		if (aio->clk_trace.play_clk_en) {
-			error = clk_prepare_enable(aio->cygaud->
-					audio_clk[aio->pll_clk_num]);
-			if (error) {
-				if (aio->clk_trace.cap_clk_en)
-					clk_disable_unprepare(aio->cygaud->
-						audio_clk[aio->pll_clk_num]);
-				dev_err(aio->cygaud->dev, "%s clk_prepare_enable failed\n",
-					__func__);
-				return -EINVAL;
-			}
-		}
-	}
 
-	return 0;
-}
-#else
-#define cygnus_ssp_suspend NULL
-#define cygnus_ssp_resume  NULL
-#endif
 
 static const struct snd_soc_dai_ops cygnus_ssp_dai_ops = {
 	.startup	= cygnus_ssp_startup,
@@ -1134,6 +999,7 @@ static int cygnus_ssp_resume(struct snd_soc_dai *cpu_dai)
 	.set_fmt	= cygnus_ssp_set_fmt,
 	.set_sysclk	= cygnus_ssp_set_sysclk,
 	.set_tdm_slot	= cygnus_set_dai_tdm_slot,
+	.set_pll	= cygnus_ssp_set_pll,
 };
 
 
@@ -1155,8 +1021,6 @@ static int cygnus_ssp_resume(struct snd_soc_dai *cpu_dai)
 					SNDRV_PCM_FMTBIT_S32_LE, \
 	}, \
 	.ops = &cygnus_ssp_dai_ops, \
-	.suspend = cygnus_ssp_suspend, \
-	.resume = cygnus_ssp_resume, \
 }
 
 static const struct snd_soc_dai_driver cygnus_ssp_dai_info[] = {
@@ -1175,8 +1039,6 @@ static int cygnus_ssp_resume(struct snd_soc_dai *cpu_dai)
 			SNDRV_PCM_FMTBIT_S32_LE,
 	},
 	.ops = &cygnus_ssp_dai_ops,
-	.suspend = cygnus_ssp_suspend,
-	.resume = cygnus_ssp_resume,
 };
 
 static struct snd_soc_dai_driver cygnus_ssp_dai[CYGNUS_MAX_PORTS];
@@ -1200,6 +1062,8 @@ static int parse_ssp_child_node(struct platform_device *pdev,
 	u32 rawval;
 	int portnum = -1;
 	enum cygnus_audio_port_type port_type;
+	u32 muxval;
+	struct clk *clk;
 
 	if (of_property_read_u32(dn, "reg", &rawval)) {
 		dev_err(&pdev->dev, "Missing reg property\n");
@@ -1259,28 +1123,37 @@ static int parse_ssp_child_node(struct platform_device *pdev,
 	dev_dbg(&pdev->dev, "%s portnum = %d\n", __func__, aio->portnum);
 	aio->streams_on = 0;
 	aio->cygaud->dev = &pdev->dev;
-	aio->clk_trace.play_en = false;
-	aio->clk_trace.cap_en = false;
 
-	audio_ssp_init_portregs(aio);
-	return 0;
-}
 
-static int audio_clk_init(struct platform_device *pdev,
-						struct cygnus_audio *cygaud)
-{
-	int i;
-	char clk_name[PROP_LEN_MAX];
+	aio->clk_info.audio_clk = NULL;
 
-	for (i = 0; i < ARRAY_SIZE(cygaud->audio_clk); i++) {
-		snprintf(clk_name, PROP_LEN_MAX, "ch%d_audio", i);
+	/*
+	 * The default in the DT is to assign a clock. It is possible
+	 * the user may not want a clock if the port is only used in slave
+	 * mode.  In this case, they could override the default using this
+	 * mechanism:    /delete-property/ clocks;
+	 */
+	if (of_property_read_bool(dn, "clocks")) {
+		clk = devm_get_clk_from_child(&pdev->dev, dn, "ssp_clk");
+		if (IS_ERR(clk)) {
+			dev_err(&pdev->dev,
+				"Port %d: devm_clk_get ssp-clk err %ld\n",
+				portnum, PTR_ERR(clk));
+			return PTR_ERR(clk);
+		}
 
-		cygaud->audio_clk[i] = devm_clk_get(&pdev->dev, clk_name);
-		if (IS_ERR(cygaud->audio_clk[i]))
-			return PTR_ERR(cygaud->audio_clk[i]);
+		aio->clk_info.audio_clk = clk;
+
+		if (of_property_read_u32(dn, "brcm,ssp-clk-mux", &muxval)) {
+			dev_err(&pdev->dev, "Missing property clock-mux\n");
+			return -EINVAL;
+		}
+		aio->clk_info.clk_mux = muxval;
+	} else {
+		dev_dbg(&pdev->dev, "No clock provided for port %d\n", portnum);
 	}
 
-	return 0;
+	return audio_ssp_init_portregs(aio);
 }
 
 static int cygnus_ssp_probe(struct platform_device *pdev)
@@ -1337,7 +1210,6 @@ static int cygnus_ssp_probe(struct platform_device *pdev)
 	}
 
 	cygaud->dev = dev;
-	cygaud->active_ports = 0;
 
 	dev_dbg(dev, "Registering %d DAIs\n", active_port_count);
 	err = snd_soc_register_component(dev, &cygnus_ssp_component,
@@ -1354,12 +1226,6 @@ static int cygnus_ssp_probe(struct platform_device *pdev)
 		goto err_irq;
 	}
 
-	err = audio_clk_init(pdev, cygaud);
-	if (err) {
-		dev_err(dev, "audio clock initialization failed\n");
-		goto err_irq;
-	}
-
 	err = cygnus_soc_platform_register(dev, cygaud);
 	if (err) {
 		dev_err(dev, "platform reg error %d\n", err);
diff --git a/sound/soc/bcm/cygnus-ssp.h b/sound/soc/bcm/cygnus-ssp.h
index 33dd343..ad15a00 100644
--- a/sound/soc/bcm/cygnus-ssp.h
+++ b/sound/soc/bcm/cygnus-ssp.h
@@ -19,7 +19,6 @@
 #define CYGNUS_MAX_CAPTURE_PORTS 3
 #define CYGNUS_MAX_I2S_PORTS 3
 #define CYGNUS_MAX_PORTS  CYGNUS_MAX_PLAYBACK_PORTS
-#define CYGNUS_AUIDO_MAX_NUM_CLKS 3
 
 #define CYGNUS_SSP_FRAMEBITS_DIV 1
 
@@ -81,11 +80,9 @@ struct cygnus_ssp_regs {
 	u32 bf_sourcech_grp;
 };
 
-struct cygnus_track_clk {
-	bool cap_en;
-	bool play_en;
-	bool cap_clk_en;
-	bool play_clk_en;
+struct cygnus_audio_clkinfo {
+	struct clk *audio_clk;
+	int clk_mux;
 };
 
 struct cygnus_aio_port {
@@ -110,7 +107,7 @@ struct cygnus_aio_port {
 	struct snd_pcm_substream *play_stream;
 	struct snd_pcm_substream *capture_stream;
 
-	struct cygnus_track_clk clk_trace;
+	struct cygnus_audio_clkinfo clk_info;
 };
 
 
@@ -121,10 +118,6 @@ struct cygnus_audio {
 	void __iomem *audio;
 	struct device *dev;
 	void __iomem *i2s_in;
-
-	struct clk *audio_clk[CYGNUS_AUIDO_MAX_NUM_CLKS];
-	int active_ports;
-	unsigned long vco_rate;
 };
 
 extern int cygnus_ssp_get_mode(struct snd_soc_dai *cpu_dai);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH 3/9] ASoC: cygnus: Allow each port to select its clock source
@ 2017-08-14 22:06   ` Lori Hikichi
  0 siblings, 0 replies; 50+ messages in thread
From: Lori Hikichi @ 2017-08-14 22:06 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Mark Rutland, Ray Jui,
	Scott Branden, Jon Mason,
	bcm-kernel-feedback-list-dY08KVG/lbpWk0Htik3J/w, Jaroslav Kysela,
	Takashi Iwai
  Cc: alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Lori Hikichi

Add the ability to assign which of the 3 audio PLL outputs are to be
used by each port. Remove the suspend and resume handlers because the only
thing they were doing was unnecessarily maintaining the clock state.

Signed-off-by: Lori Hikichi <lori.hikichi-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
---
 sound/soc/bcm/cygnus-ssp.c | 332 ++++++++++++++-------------------------------
 sound/soc/bcm/cygnus-ssp.h |  15 +-
 2 files changed, 103 insertions(+), 244 deletions(-)

diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c
index 1a57a4e..00fd4dc 100644
--- a/sound/soc/bcm/cygnus-ssp.c
+++ b/sound/soc/bcm/cygnus-ssp.c
@@ -25,8 +25,6 @@
 
 #include "cygnus-ssp.h"
 
-#define DEFAULT_VCO    1354750204
-
 #define CAPTURE_FCI_ID_BASE 0x180
 #define CYGNUS_SSP_TRISTATE_MASK 0x001fff
 #define CYGNUS_PLLCLKSEL_MASK 0xf
@@ -95,22 +93,10 @@
 #define SPDIF_FORMAT_CFG_OFFSET  0xad8
 #define SPDIF_MCLK_CFG_OFFSET    0xadc
 
-/* AUD_FMM_IOP_PLL_0_xxx regs */
-#define IOP_PLL_0_MACRO_OFFSET    0xb00
-#define IOP_PLL_0_MDIV_Ch0_OFFSET 0xb14
-#define IOP_PLL_0_MDIV_Ch1_OFFSET 0xb18
-#define IOP_PLL_0_MDIV_Ch2_OFFSET 0xb1c
-
-#define IOP_PLL_0_ACTIVE_MDIV_Ch0_OFFSET 0xb30
-#define IOP_PLL_0_ACTIVE_MDIV_Ch1_OFFSET 0xb34
-#define IOP_PLL_0_ACTIVE_MDIV_Ch2_OFFSET 0xb38
-
-/* AUD_FMM_IOP_xxx regs */
-#define IOP_PLL_0_CONTROL_OFFSET     0xb04
-#define IOP_PLL_0_USER_NDIV_OFFSET   0xb08
-#define IOP_PLL_0_ACTIVE_NDIV_OFFSET 0xb20
-#define IOP_PLL_0_RESET_OFFSET       0xb5c
 
+/*--------------------------------------------
+ * Register offsets for i2s_in io space
+ */
 /* AUD_FMM_IOP_IN_I2S_xxx regs */
 #define IN_I2S_0_STREAM_CFG_OFFSET 0x00
 #define IN_I2S_0_CFG_OFFSET        0x04
@@ -173,12 +159,6 @@
 #define SPDIF_0_OUT_DITHER_ENA     3
 #define SPDIF_0_OUT_STREAM_ENA    31
 
-/* AUD_FMM_IOP_PLL_0_USER */
-#define IOP_PLL_0_USER_NDIV_FRAC   10
-
-/* AUD_FMM_IOP_PLL_0_ACTIVE */
-#define IOP_PLL_0_ACTIVE_NDIV_FRAC 10
-
 
 #define INIT_SSP_REGS(num) (struct cygnus_ssp_regs){ \
 		.i2s_stream_cfg = OUT_I2S_ ##num## _STREAM_CFG_OFFSET, \
@@ -193,41 +173,6 @@
 		.bf_sourcech_grp = BF_SRC_GRP ##num## _OFFSET \
 }
 
-struct pll_macro_entry {
-	u32 mclk;
-	u32 pll_ch_num;
-};
-
-/*
- * PLL has 3 output channels (1x, 2x, and 4x). Below are
- * the common MCLK frequencies used by audio driver
- */
-static const struct pll_macro_entry pll_predef_mclk[] = {
-	{ 4096000, 0},
-	{ 8192000, 1},
-	{16384000, 2},
-
-	{ 5644800, 0},
-	{11289600, 1},
-	{22579200, 2},
-
-	{ 6144000, 0},
-	{12288000, 1},
-	{24576000, 2},
-
-	{12288000, 0},
-	{24576000, 1},
-	{49152000, 2},
-
-	{22579200, 0},
-	{45158400, 1},
-	{90316800, 2},
-
-	{24576000, 0},
-	{49152000, 1},
-	{98304000, 2},
-};
-
 #define CYGNUS_RATE_MIN     8000
 #define CYGNUS_RATE_MAX   384000
 
@@ -488,59 +433,6 @@ static int audio_ssp_out_disable(struct cygnus_aio_port *aio)
 	return status;
 }
 
-static int pll_configure_mclk(struct cygnus_audio *cygaud, u32 mclk,
-	struct cygnus_aio_port *aio)
-{
-	int i = 0, error;
-	bool found = false;
-	const struct pll_macro_entry *p_entry;
-	struct clk *ch_clk;
-
-	for (i = 0; i < ARRAY_SIZE(pll_predef_mclk); i++) {
-		p_entry = &pll_predef_mclk[i];
-		if (p_entry->mclk == mclk) {
-			found = true;
-			break;
-		}
-	}
-	if (!found) {
-		dev_err(cygaud->dev,
-			"%s No valid mclk freq (%u) found!\n", __func__, mclk);
-		return -EINVAL;
-	}
-
-	ch_clk = cygaud->audio_clk[p_entry->pll_ch_num];
-
-	if ((aio->clk_trace.cap_en) && (!aio->clk_trace.cap_clk_en)) {
-		error = clk_prepare_enable(ch_clk);
-		if (error) {
-			dev_err(cygaud->dev, "%s clk_prepare_enable failed %d\n",
-				__func__, error);
-			return error;
-		}
-		aio->clk_trace.cap_clk_en = true;
-	}
-
-	if ((aio->clk_trace.play_en) && (!aio->clk_trace.play_clk_en)) {
-		error = clk_prepare_enable(ch_clk);
-		if (error) {
-			dev_err(cygaud->dev, "%s clk_prepare_enable failed %d\n",
-				__func__, error);
-			return error;
-		}
-		aio->clk_trace.play_clk_en = true;
-	}
-
-	error = clk_set_rate(ch_clk, mclk);
-	if (error) {
-		dev_err(cygaud->dev, "%s Set MCLK rate failed: %d\n",
-			__func__, error);
-		return error;
-	}
-
-	return p_entry->pll_ch_num;
-}
-
 static int cygnus_ssp_set_clocks(struct cygnus_aio_port *aio)
 {
 	u32 value;
@@ -723,26 +615,68 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 }
 
 /*
+ * Check that the actual mclk is within about 1% of the requested rate.
+ * The check is rather loose and is intended to catch any big mistakes.
+ * It is expected that the actual mclk rate may be a little different
+ * than the requested rate because the clock from which the mclk is
+ * derived (PLL) may not be an exact multiple of the mclk.
+ */
+static bool mclk_in_range(unsigned int target, unsigned int actual)
+{
+	unsigned int delta;
+
+	/* Mclk is at least several MHz, so simple div by 100 will suffice */
+	delta = target / 100;
+	return (actual > (target - delta)) && (actual < (target + delta));
+}
+
+/*
  * This function sets the mclk frequency for pll clock
  */
 static int cygnus_ssp_set_sysclk(struct snd_soc_dai *dai,
 			int clk_id, unsigned int freq, int dir)
 {
 	int sel;
+	int ret;
 	u32 value;
+	long rate;
 	struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai);
-	struct cygnus_audio *cygaud = snd_soc_dai_get_drvdata(dai);
 
 	dev_dbg(aio->cygaud->dev,
 		"%s Enter port = %d\n", __func__, aio->portnum);
-	sel = pll_configure_mclk(cygaud, freq, aio);
-	if (sel < 0) {
+
+	/*
+	 * This should not happen, but the machine file may inadvertently
+	 * call set_sysclk without configuring a clock via the devicetree.
+	 */
+	if (!aio->clk_info.audio_clk) {
 		dev_err(aio->cygaud->dev,
-			"%s Setting mclk failed.\n", __func__);
+			"%s Error. No clock assigned.\n", __func__);
+		return -ENODEV;
+	}
+
+	rate = clk_round_rate(aio->clk_info.audio_clk, freq);
+	if (rate < 0) {
+		dev_err(aio->cygaud->dev, "%s Error with with clock %ld.\n",
+			__func__, rate);
+		return rate;
+	}
+
+	if (!mclk_in_range(freq, rate)) {
+		dev_err(aio->cygaud->dev, "%s Can not set rate to %u  actual %ld.\n",
+			__func__, freq, rate);
 		return -EINVAL;
 	}
 
+	ret = clk_set_rate(aio->clk_info.audio_clk, freq);
+	if (ret) {
+		dev_err(aio->cygaud->dev,
+			"%s Set MCLK rate fail %d\n", __func__, ret);
+		return ret;
+	}
+
 	aio->mclk = freq;
+	sel = aio->clk_info.clk_mux;
 
 	dev_dbg(aio->cygaud->dev, "%s Setting MCLKSEL to %d\n", __func__, sel);
 	value = readl(aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
@@ -759,17 +693,14 @@ static int cygnus_ssp_startup(struct snd_pcm_substream *substream,
 	struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai);
 
 	snd_soc_dai_set_dma_data(dai, substream, aio);
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		aio->clk_trace.play_en = true;
-	else
-		aio->clk_trace.cap_en = true;
 
 	substream->runtime->hw.rate_min = CYGNUS_RATE_MIN;
 	substream->runtime->hw.rate_max = CYGNUS_RATE_MAX;
 
 	snd_pcm_hw_constraint_list(substream->runtime, 0,
 			SNDRV_PCM_HW_PARAM_RATE, &cygnus_rate_constraint);
-	return 0;
+
+	return clk_prepare_enable(aio->clk_info.audio_clk);
 }
 
 static void cygnus_ssp_shutdown(struct snd_pcm_substream *substream,
@@ -777,36 +708,7 @@ static void cygnus_ssp_shutdown(struct snd_pcm_substream *substream,
 {
 	struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai);
 
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		aio->clk_trace.play_en = false;
-	else
-		aio->clk_trace.cap_en = false;
-
-	if (!aio->is_slave) {
-		u32 val;
-
-		val = readl(aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
-		val &= CYGNUS_PLLCLKSEL_MASK;
-		if (val >= ARRAY_SIZE(aio->cygaud->audio_clk)) {
-			dev_err(aio->cygaud->dev, "Clk index %u is out of bounds\n",
-				val);
-			return;
-		}
-
-		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-			if (aio->clk_trace.play_clk_en) {
-				clk_disable_unprepare(aio->cygaud->
-						audio_clk[val]);
-				aio->clk_trace.play_clk_en = false;
-			}
-		} else {
-			if (aio->clk_trace.cap_clk_en) {
-				clk_disable_unprepare(aio->cygaud->
-						audio_clk[val]);
-				aio->clk_trace.cap_clk_en = false;
-			}
-		}
-	}
+	clk_disable_unprepare(aio->clk_info.audio_clk);
 }
 
 /*
@@ -945,7 +847,6 @@ static int cygnus_ssp_trigger(struct snd_pcm_substream *substream, int cmd,
 			       struct snd_soc_dai *dai)
 {
 	struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai);
-	struct cygnus_audio *cygaud = snd_soc_dai_get_drvdata(dai);
 
 	dev_dbg(aio->cygaud->dev,
 		"%s cmd %d at port = %d\n", __func__, cmd, aio->portnum);
@@ -958,7 +859,6 @@ static int cygnus_ssp_trigger(struct snd_pcm_substream *substream, int cmd,
 			audio_ssp_out_enable(aio);
 		else
 			audio_ssp_in_enable(aio);
-		cygaud->active_ports++;
 
 		break;
 
@@ -969,7 +869,6 @@ static int cygnus_ssp_trigger(struct snd_pcm_substream *substream, int cmd,
 			audio_ssp_out_disable(aio);
 		else
 			audio_ssp_in_disable(aio);
-		cygaud->active_ports--;
 		break;
 
 	default:
@@ -1063,68 +962,34 @@ static int cygnus_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
 	return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int cygnus_ssp_suspend(struct snd_soc_dai *cpu_dai)
+static int cygnus_ssp_set_pll(struct snd_soc_dai *cpu_dai, int pll_id,
+				 int source, unsigned int freq_in,
+				 unsigned int freq_out)
 {
 	struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(cpu_dai);
+	struct clk *clk_pll;
+	int ret = 0;
 
-	if (!aio->is_slave) {
-		u32 val;
-
-		val = readl(aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
-		val &= CYGNUS_PLLCLKSEL_MASK;
-		if (val >= ARRAY_SIZE(aio->cygaud->audio_clk)) {
-			dev_err(aio->cygaud->dev, "Clk index %u is out of bounds\n",
-				val);
-			return -EINVAL;
-		}
-
-		if (aio->clk_trace.cap_clk_en)
-			clk_disable_unprepare(aio->cygaud->audio_clk[val]);
-		if (aio->clk_trace.play_clk_en)
-			clk_disable_unprepare(aio->cygaud->audio_clk[val]);
+	if (!aio->clk_info.audio_clk) {
+		dev_err(aio->cygaud->dev,
+			"%s: port %d does not have an assigned clock.\n",
+			__func__, aio->portnum);
+		return -ENODEV;
+	}
 
-		aio->pll_clk_num = val;
+	clk_pll = clk_get_parent(aio->clk_info.audio_clk);
+	if (IS_ERR(clk_pll)) {
+		dev_err(aio->cygaud->dev,
+			"%s: could not get audiopll clock.\n", __func__);
+		return -ENODEV;
 	}
 
-	return 0;
+	ret = clk_set_rate(clk_pll, freq_out);
+
+	return ret;
 }
 
-static int cygnus_ssp_resume(struct snd_soc_dai *cpu_dai)
-{
-	struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(cpu_dai);
-	int error;
-
-	if (!aio->is_slave) {
-		if (aio->clk_trace.cap_clk_en) {
-			error = clk_prepare_enable(aio->cygaud->
-					audio_clk[aio->pll_clk_num]);
-			if (error) {
-				dev_err(aio->cygaud->dev, "%s clk_prepare_enable failed\n",
-					__func__);
-				return -EINVAL;
-			}
-		}
-		if (aio->clk_trace.play_clk_en) {
-			error = clk_prepare_enable(aio->cygaud->
-					audio_clk[aio->pll_clk_num]);
-			if (error) {
-				if (aio->clk_trace.cap_clk_en)
-					clk_disable_unprepare(aio->cygaud->
-						audio_clk[aio->pll_clk_num]);
-				dev_err(aio->cygaud->dev, "%s clk_prepare_enable failed\n",
-					__func__);
-				return -EINVAL;
-			}
-		}
-	}
 
-	return 0;
-}
-#else
-#define cygnus_ssp_suspend NULL
-#define cygnus_ssp_resume  NULL
-#endif
 
 static const struct snd_soc_dai_ops cygnus_ssp_dai_ops = {
 	.startup	= cygnus_ssp_startup,
@@ -1134,6 +999,7 @@ static int cygnus_ssp_resume(struct snd_soc_dai *cpu_dai)
 	.set_fmt	= cygnus_ssp_set_fmt,
 	.set_sysclk	= cygnus_ssp_set_sysclk,
 	.set_tdm_slot	= cygnus_set_dai_tdm_slot,
+	.set_pll	= cygnus_ssp_set_pll,
 };
 
 
@@ -1155,8 +1021,6 @@ static int cygnus_ssp_resume(struct snd_soc_dai *cpu_dai)
 					SNDRV_PCM_FMTBIT_S32_LE, \
 	}, \
 	.ops = &cygnus_ssp_dai_ops, \
-	.suspend = cygnus_ssp_suspend, \
-	.resume = cygnus_ssp_resume, \
 }
 
 static const struct snd_soc_dai_driver cygnus_ssp_dai_info[] = {
@@ -1175,8 +1039,6 @@ static int cygnus_ssp_resume(struct snd_soc_dai *cpu_dai)
 			SNDRV_PCM_FMTBIT_S32_LE,
 	},
 	.ops = &cygnus_ssp_dai_ops,
-	.suspend = cygnus_ssp_suspend,
-	.resume = cygnus_ssp_resume,
 };
 
 static struct snd_soc_dai_driver cygnus_ssp_dai[CYGNUS_MAX_PORTS];
@@ -1200,6 +1062,8 @@ static int parse_ssp_child_node(struct platform_device *pdev,
 	u32 rawval;
 	int portnum = -1;
 	enum cygnus_audio_port_type port_type;
+	u32 muxval;
+	struct clk *clk;
 
 	if (of_property_read_u32(dn, "reg", &rawval)) {
 		dev_err(&pdev->dev, "Missing reg property\n");
@@ -1259,28 +1123,37 @@ static int parse_ssp_child_node(struct platform_device *pdev,
 	dev_dbg(&pdev->dev, "%s portnum = %d\n", __func__, aio->portnum);
 	aio->streams_on = 0;
 	aio->cygaud->dev = &pdev->dev;
-	aio->clk_trace.play_en = false;
-	aio->clk_trace.cap_en = false;
 
-	audio_ssp_init_portregs(aio);
-	return 0;
-}
 
-static int audio_clk_init(struct platform_device *pdev,
-						struct cygnus_audio *cygaud)
-{
-	int i;
-	char clk_name[PROP_LEN_MAX];
+	aio->clk_info.audio_clk = NULL;
 
-	for (i = 0; i < ARRAY_SIZE(cygaud->audio_clk); i++) {
-		snprintf(clk_name, PROP_LEN_MAX, "ch%d_audio", i);
+	/*
+	 * The default in the DT is to assign a clock. It is possible
+	 * the user may not want a clock if the port is only used in slave
+	 * mode.  In this case, they could override the default using this
+	 * mechanism:    /delete-property/ clocks;
+	 */
+	if (of_property_read_bool(dn, "clocks")) {
+		clk = devm_get_clk_from_child(&pdev->dev, dn, "ssp_clk");
+		if (IS_ERR(clk)) {
+			dev_err(&pdev->dev,
+				"Port %d: devm_clk_get ssp-clk err %ld\n",
+				portnum, PTR_ERR(clk));
+			return PTR_ERR(clk);
+		}
 
-		cygaud->audio_clk[i] = devm_clk_get(&pdev->dev, clk_name);
-		if (IS_ERR(cygaud->audio_clk[i]))
-			return PTR_ERR(cygaud->audio_clk[i]);
+		aio->clk_info.audio_clk = clk;
+
+		if (of_property_read_u32(dn, "brcm,ssp-clk-mux", &muxval)) {
+			dev_err(&pdev->dev, "Missing property clock-mux\n");
+			return -EINVAL;
+		}
+		aio->clk_info.clk_mux = muxval;
+	} else {
+		dev_dbg(&pdev->dev, "No clock provided for port %d\n", portnum);
 	}
 
-	return 0;
+	return audio_ssp_init_portregs(aio);
 }
 
 static int cygnus_ssp_probe(struct platform_device *pdev)
@@ -1337,7 +1210,6 @@ static int cygnus_ssp_probe(struct platform_device *pdev)
 	}
 
 	cygaud->dev = dev;
-	cygaud->active_ports = 0;
 
 	dev_dbg(dev, "Registering %d DAIs\n", active_port_count);
 	err = snd_soc_register_component(dev, &cygnus_ssp_component,
@@ -1354,12 +1226,6 @@ static int cygnus_ssp_probe(struct platform_device *pdev)
 		goto err_irq;
 	}
 
-	err = audio_clk_init(pdev, cygaud);
-	if (err) {
-		dev_err(dev, "audio clock initialization failed\n");
-		goto err_irq;
-	}
-
 	err = cygnus_soc_platform_register(dev, cygaud);
 	if (err) {
 		dev_err(dev, "platform reg error %d\n", err);
diff --git a/sound/soc/bcm/cygnus-ssp.h b/sound/soc/bcm/cygnus-ssp.h
index 33dd343..ad15a00 100644
--- a/sound/soc/bcm/cygnus-ssp.h
+++ b/sound/soc/bcm/cygnus-ssp.h
@@ -19,7 +19,6 @@
 #define CYGNUS_MAX_CAPTURE_PORTS 3
 #define CYGNUS_MAX_I2S_PORTS 3
 #define CYGNUS_MAX_PORTS  CYGNUS_MAX_PLAYBACK_PORTS
-#define CYGNUS_AUIDO_MAX_NUM_CLKS 3
 
 #define CYGNUS_SSP_FRAMEBITS_DIV 1
 
@@ -81,11 +80,9 @@ struct cygnus_ssp_regs {
 	u32 bf_sourcech_grp;
 };
 
-struct cygnus_track_clk {
-	bool cap_en;
-	bool play_en;
-	bool cap_clk_en;
-	bool play_clk_en;
+struct cygnus_audio_clkinfo {
+	struct clk *audio_clk;
+	int clk_mux;
 };
 
 struct cygnus_aio_port {
@@ -110,7 +107,7 @@ struct cygnus_aio_port {
 	struct snd_pcm_substream *play_stream;
 	struct snd_pcm_substream *capture_stream;
 
-	struct cygnus_track_clk clk_trace;
+	struct cygnus_audio_clkinfo clk_info;
 };
 
 
@@ -121,10 +118,6 @@ struct cygnus_audio {
 	void __iomem *audio;
 	struct device *dev;
 	void __iomem *i2s_in;
-
-	struct clk *audio_clk[CYGNUS_AUIDO_MAX_NUM_CLKS];
-	int active_ports;
-	unsigned long vco_rate;
 };
 
 extern int cygnus_ssp_get_mode(struct snd_soc_dai *cpu_dai);
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH 3/9] ASoC: cygnus: Allow each port to select its clock source
@ 2017-08-14 22:06   ` Lori Hikichi
  0 siblings, 0 replies; 50+ messages in thread
From: Lori Hikichi @ 2017-08-14 22:06 UTC (permalink / raw)
  To: linux-arm-kernel

Add the ability to assign which of the 3 audio PLL outputs are to be
used by each port. Remove the suspend and resume handlers because the only
thing they were doing was unnecessarily maintaining the clock state.

Signed-off-by: Lori Hikichi <lori.hikichi@broadcom.com>
---
 sound/soc/bcm/cygnus-ssp.c | 332 ++++++++++++++-------------------------------
 sound/soc/bcm/cygnus-ssp.h |  15 +-
 2 files changed, 103 insertions(+), 244 deletions(-)

diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c
index 1a57a4e..00fd4dc 100644
--- a/sound/soc/bcm/cygnus-ssp.c
+++ b/sound/soc/bcm/cygnus-ssp.c
@@ -25,8 +25,6 @@
 
 #include "cygnus-ssp.h"
 
-#define DEFAULT_VCO    1354750204
-
 #define CAPTURE_FCI_ID_BASE 0x180
 #define CYGNUS_SSP_TRISTATE_MASK 0x001fff
 #define CYGNUS_PLLCLKSEL_MASK 0xf
@@ -95,22 +93,10 @@
 #define SPDIF_FORMAT_CFG_OFFSET  0xad8
 #define SPDIF_MCLK_CFG_OFFSET    0xadc
 
-/* AUD_FMM_IOP_PLL_0_xxx regs */
-#define IOP_PLL_0_MACRO_OFFSET    0xb00
-#define IOP_PLL_0_MDIV_Ch0_OFFSET 0xb14
-#define IOP_PLL_0_MDIV_Ch1_OFFSET 0xb18
-#define IOP_PLL_0_MDIV_Ch2_OFFSET 0xb1c
-
-#define IOP_PLL_0_ACTIVE_MDIV_Ch0_OFFSET 0xb30
-#define IOP_PLL_0_ACTIVE_MDIV_Ch1_OFFSET 0xb34
-#define IOP_PLL_0_ACTIVE_MDIV_Ch2_OFFSET 0xb38
-
-/* AUD_FMM_IOP_xxx regs */
-#define IOP_PLL_0_CONTROL_OFFSET     0xb04
-#define IOP_PLL_0_USER_NDIV_OFFSET   0xb08
-#define IOP_PLL_0_ACTIVE_NDIV_OFFSET 0xb20
-#define IOP_PLL_0_RESET_OFFSET       0xb5c
 
+/*--------------------------------------------
+ * Register offsets for i2s_in io space
+ */
 /* AUD_FMM_IOP_IN_I2S_xxx regs */
 #define IN_I2S_0_STREAM_CFG_OFFSET 0x00
 #define IN_I2S_0_CFG_OFFSET        0x04
@@ -173,12 +159,6 @@
 #define SPDIF_0_OUT_DITHER_ENA     3
 #define SPDIF_0_OUT_STREAM_ENA    31
 
-/* AUD_FMM_IOP_PLL_0_USER */
-#define IOP_PLL_0_USER_NDIV_FRAC   10
-
-/* AUD_FMM_IOP_PLL_0_ACTIVE */
-#define IOP_PLL_0_ACTIVE_NDIV_FRAC 10
-
 
 #define INIT_SSP_REGS(num) (struct cygnus_ssp_regs){ \
 		.i2s_stream_cfg = OUT_I2S_ ##num## _STREAM_CFG_OFFSET, \
@@ -193,41 +173,6 @@
 		.bf_sourcech_grp = BF_SRC_GRP ##num## _OFFSET \
 }
 
-struct pll_macro_entry {
-	u32 mclk;
-	u32 pll_ch_num;
-};
-
-/*
- * PLL has 3 output channels (1x, 2x, and 4x). Below are
- * the common MCLK frequencies used by audio driver
- */
-static const struct pll_macro_entry pll_predef_mclk[] = {
-	{ 4096000, 0},
-	{ 8192000, 1},
-	{16384000, 2},
-
-	{ 5644800, 0},
-	{11289600, 1},
-	{22579200, 2},
-
-	{ 6144000, 0},
-	{12288000, 1},
-	{24576000, 2},
-
-	{12288000, 0},
-	{24576000, 1},
-	{49152000, 2},
-
-	{22579200, 0},
-	{45158400, 1},
-	{90316800, 2},
-
-	{24576000, 0},
-	{49152000, 1},
-	{98304000, 2},
-};
-
 #define CYGNUS_RATE_MIN     8000
 #define CYGNUS_RATE_MAX   384000
 
@@ -488,59 +433,6 @@ static int audio_ssp_out_disable(struct cygnus_aio_port *aio)
 	return status;
 }
 
-static int pll_configure_mclk(struct cygnus_audio *cygaud, u32 mclk,
-	struct cygnus_aio_port *aio)
-{
-	int i = 0, error;
-	bool found = false;
-	const struct pll_macro_entry *p_entry;
-	struct clk *ch_clk;
-
-	for (i = 0; i < ARRAY_SIZE(pll_predef_mclk); i++) {
-		p_entry = &pll_predef_mclk[i];
-		if (p_entry->mclk == mclk) {
-			found = true;
-			break;
-		}
-	}
-	if (!found) {
-		dev_err(cygaud->dev,
-			"%s No valid mclk freq (%u) found!\n", __func__, mclk);
-		return -EINVAL;
-	}
-
-	ch_clk = cygaud->audio_clk[p_entry->pll_ch_num];
-
-	if ((aio->clk_trace.cap_en) && (!aio->clk_trace.cap_clk_en)) {
-		error = clk_prepare_enable(ch_clk);
-		if (error) {
-			dev_err(cygaud->dev, "%s clk_prepare_enable failed %d\n",
-				__func__, error);
-			return error;
-		}
-		aio->clk_trace.cap_clk_en = true;
-	}
-
-	if ((aio->clk_trace.play_en) && (!aio->clk_trace.play_clk_en)) {
-		error = clk_prepare_enable(ch_clk);
-		if (error) {
-			dev_err(cygaud->dev, "%s clk_prepare_enable failed %d\n",
-				__func__, error);
-			return error;
-		}
-		aio->clk_trace.play_clk_en = true;
-	}
-
-	error = clk_set_rate(ch_clk, mclk);
-	if (error) {
-		dev_err(cygaud->dev, "%s Set MCLK rate failed: %d\n",
-			__func__, error);
-		return error;
-	}
-
-	return p_entry->pll_ch_num;
-}
-
 static int cygnus_ssp_set_clocks(struct cygnus_aio_port *aio)
 {
 	u32 value;
@@ -723,26 +615,68 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 }
 
 /*
+ * Check that the actual mclk is within about 1% of the requested rate.
+ * The check is rather loose and is intended to catch any big mistakes.
+ * It is expected that the actual mclk rate may be a little different
+ * than the requested rate because the clock from which the mclk is
+ * derived (PLL) may not be an exact multiple of the mclk.
+ */
+static bool mclk_in_range(unsigned int target, unsigned int actual)
+{
+	unsigned int delta;
+
+	/* Mclk is at least several MHz, so simple div by 100 will suffice */
+	delta = target / 100;
+	return (actual > (target - delta)) && (actual < (target + delta));
+}
+
+/*
  * This function sets the mclk frequency for pll clock
  */
 static int cygnus_ssp_set_sysclk(struct snd_soc_dai *dai,
 			int clk_id, unsigned int freq, int dir)
 {
 	int sel;
+	int ret;
 	u32 value;
+	long rate;
 	struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai);
-	struct cygnus_audio *cygaud = snd_soc_dai_get_drvdata(dai);
 
 	dev_dbg(aio->cygaud->dev,
 		"%s Enter port = %d\n", __func__, aio->portnum);
-	sel = pll_configure_mclk(cygaud, freq, aio);
-	if (sel < 0) {
+
+	/*
+	 * This should not happen, but the machine file may inadvertently
+	 * call set_sysclk without configuring a clock via the devicetree.
+	 */
+	if (!aio->clk_info.audio_clk) {
 		dev_err(aio->cygaud->dev,
-			"%s Setting mclk failed.\n", __func__);
+			"%s Error. No clock assigned.\n", __func__);
+		return -ENODEV;
+	}
+
+	rate = clk_round_rate(aio->clk_info.audio_clk, freq);
+	if (rate < 0) {
+		dev_err(aio->cygaud->dev, "%s Error with with clock %ld.\n",
+			__func__, rate);
+		return rate;
+	}
+
+	if (!mclk_in_range(freq, rate)) {
+		dev_err(aio->cygaud->dev, "%s Can not set rate to %u  actual %ld.\n",
+			__func__, freq, rate);
 		return -EINVAL;
 	}
 
+	ret = clk_set_rate(aio->clk_info.audio_clk, freq);
+	if (ret) {
+		dev_err(aio->cygaud->dev,
+			"%s Set MCLK rate fail %d\n", __func__, ret);
+		return ret;
+	}
+
 	aio->mclk = freq;
+	sel = aio->clk_info.clk_mux;
 
 	dev_dbg(aio->cygaud->dev, "%s Setting MCLKSEL to %d\n", __func__, sel);
 	value = readl(aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
@@ -759,17 +693,14 @@ static int cygnus_ssp_startup(struct snd_pcm_substream *substream,
 	struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai);
 
 	snd_soc_dai_set_dma_data(dai, substream, aio);
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		aio->clk_trace.play_en = true;
-	else
-		aio->clk_trace.cap_en = true;
 
 	substream->runtime->hw.rate_min = CYGNUS_RATE_MIN;
 	substream->runtime->hw.rate_max = CYGNUS_RATE_MAX;
 
 	snd_pcm_hw_constraint_list(substream->runtime, 0,
 			SNDRV_PCM_HW_PARAM_RATE, &cygnus_rate_constraint);
-	return 0;
+
+	return clk_prepare_enable(aio->clk_info.audio_clk);
 }
 
 static void cygnus_ssp_shutdown(struct snd_pcm_substream *substream,
@@ -777,36 +708,7 @@ static void cygnus_ssp_shutdown(struct snd_pcm_substream *substream,
 {
 	struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai);
 
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		aio->clk_trace.play_en = false;
-	else
-		aio->clk_trace.cap_en = false;
-
-	if (!aio->is_slave) {
-		u32 val;
-
-		val = readl(aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
-		val &= CYGNUS_PLLCLKSEL_MASK;
-		if (val >= ARRAY_SIZE(aio->cygaud->audio_clk)) {
-			dev_err(aio->cygaud->dev, "Clk index %u is out of bounds\n",
-				val);
-			return;
-		}
-
-		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-			if (aio->clk_trace.play_clk_en) {
-				clk_disable_unprepare(aio->cygaud->
-						audio_clk[val]);
-				aio->clk_trace.play_clk_en = false;
-			}
-		} else {
-			if (aio->clk_trace.cap_clk_en) {
-				clk_disable_unprepare(aio->cygaud->
-						audio_clk[val]);
-				aio->clk_trace.cap_clk_en = false;
-			}
-		}
-	}
+	clk_disable_unprepare(aio->clk_info.audio_clk);
 }
 
 /*
@@ -945,7 +847,6 @@ static int cygnus_ssp_trigger(struct snd_pcm_substream *substream, int cmd,
 			       struct snd_soc_dai *dai)
 {
 	struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai);
-	struct cygnus_audio *cygaud = snd_soc_dai_get_drvdata(dai);
 
 	dev_dbg(aio->cygaud->dev,
 		"%s cmd %d at port = %d\n", __func__, cmd, aio->portnum);
@@ -958,7 +859,6 @@ static int cygnus_ssp_trigger(struct snd_pcm_substream *substream, int cmd,
 			audio_ssp_out_enable(aio);
 		else
 			audio_ssp_in_enable(aio);
-		cygaud->active_ports++;
 
 		break;
 
@@ -969,7 +869,6 @@ static int cygnus_ssp_trigger(struct snd_pcm_substream *substream, int cmd,
 			audio_ssp_out_disable(aio);
 		else
 			audio_ssp_in_disable(aio);
-		cygaud->active_ports--;
 		break;
 
 	default:
@@ -1063,68 +962,34 @@ static int cygnus_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
 	return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int cygnus_ssp_suspend(struct snd_soc_dai *cpu_dai)
+static int cygnus_ssp_set_pll(struct snd_soc_dai *cpu_dai, int pll_id,
+				 int source, unsigned int freq_in,
+				 unsigned int freq_out)
 {
 	struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(cpu_dai);
+	struct clk *clk_pll;
+	int ret = 0;
 
-	if (!aio->is_slave) {
-		u32 val;
-
-		val = readl(aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
-		val &= CYGNUS_PLLCLKSEL_MASK;
-		if (val >= ARRAY_SIZE(aio->cygaud->audio_clk)) {
-			dev_err(aio->cygaud->dev, "Clk index %u is out of bounds\n",
-				val);
-			return -EINVAL;
-		}
-
-		if (aio->clk_trace.cap_clk_en)
-			clk_disable_unprepare(aio->cygaud->audio_clk[val]);
-		if (aio->clk_trace.play_clk_en)
-			clk_disable_unprepare(aio->cygaud->audio_clk[val]);
+	if (!aio->clk_info.audio_clk) {
+		dev_err(aio->cygaud->dev,
+			"%s: port %d does not have an assigned clock.\n",
+			__func__, aio->portnum);
+		return -ENODEV;
+	}
 
-		aio->pll_clk_num = val;
+	clk_pll = clk_get_parent(aio->clk_info.audio_clk);
+	if (IS_ERR(clk_pll)) {
+		dev_err(aio->cygaud->dev,
+			"%s: could not get audiopll clock.\n", __func__);
+		return -ENODEV;
 	}
 
-	return 0;
+	ret = clk_set_rate(clk_pll, freq_out);
+
+	return ret;
 }
 
-static int cygnus_ssp_resume(struct snd_soc_dai *cpu_dai)
-{
-	struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(cpu_dai);
-	int error;
-
-	if (!aio->is_slave) {
-		if (aio->clk_trace.cap_clk_en) {
-			error = clk_prepare_enable(aio->cygaud->
-					audio_clk[aio->pll_clk_num]);
-			if (error) {
-				dev_err(aio->cygaud->dev, "%s clk_prepare_enable failed\n",
-					__func__);
-				return -EINVAL;
-			}
-		}
-		if (aio->clk_trace.play_clk_en) {
-			error = clk_prepare_enable(aio->cygaud->
-					audio_clk[aio->pll_clk_num]);
-			if (error) {
-				if (aio->clk_trace.cap_clk_en)
-					clk_disable_unprepare(aio->cygaud->
-						audio_clk[aio->pll_clk_num]);
-				dev_err(aio->cygaud->dev, "%s clk_prepare_enable failed\n",
-					__func__);
-				return -EINVAL;
-			}
-		}
-	}
 
-	return 0;
-}
-#else
-#define cygnus_ssp_suspend NULL
-#define cygnus_ssp_resume  NULL
-#endif
 
 static const struct snd_soc_dai_ops cygnus_ssp_dai_ops = {
 	.startup	= cygnus_ssp_startup,
@@ -1134,6 +999,7 @@ static int cygnus_ssp_resume(struct snd_soc_dai *cpu_dai)
 	.set_fmt	= cygnus_ssp_set_fmt,
 	.set_sysclk	= cygnus_ssp_set_sysclk,
 	.set_tdm_slot	= cygnus_set_dai_tdm_slot,
+	.set_pll	= cygnus_ssp_set_pll,
 };
 
 
@@ -1155,8 +1021,6 @@ static int cygnus_ssp_resume(struct snd_soc_dai *cpu_dai)
 					SNDRV_PCM_FMTBIT_S32_LE, \
 	}, \
 	.ops = &cygnus_ssp_dai_ops, \
-	.suspend = cygnus_ssp_suspend, \
-	.resume = cygnus_ssp_resume, \
 }
 
 static const struct snd_soc_dai_driver cygnus_ssp_dai_info[] = {
@@ -1175,8 +1039,6 @@ static int cygnus_ssp_resume(struct snd_soc_dai *cpu_dai)
 			SNDRV_PCM_FMTBIT_S32_LE,
 	},
 	.ops = &cygnus_ssp_dai_ops,
-	.suspend = cygnus_ssp_suspend,
-	.resume = cygnus_ssp_resume,
 };
 
 static struct snd_soc_dai_driver cygnus_ssp_dai[CYGNUS_MAX_PORTS];
@@ -1200,6 +1062,8 @@ static int parse_ssp_child_node(struct platform_device *pdev,
 	u32 rawval;
 	int portnum = -1;
 	enum cygnus_audio_port_type port_type;
+	u32 muxval;
+	struct clk *clk;
 
 	if (of_property_read_u32(dn, "reg", &rawval)) {
 		dev_err(&pdev->dev, "Missing reg property\n");
@@ -1259,28 +1123,37 @@ static int parse_ssp_child_node(struct platform_device *pdev,
 	dev_dbg(&pdev->dev, "%s portnum = %d\n", __func__, aio->portnum);
 	aio->streams_on = 0;
 	aio->cygaud->dev = &pdev->dev;
-	aio->clk_trace.play_en = false;
-	aio->clk_trace.cap_en = false;
 
-	audio_ssp_init_portregs(aio);
-	return 0;
-}
 
-static int audio_clk_init(struct platform_device *pdev,
-						struct cygnus_audio *cygaud)
-{
-	int i;
-	char clk_name[PROP_LEN_MAX];
+	aio->clk_info.audio_clk = NULL;
 
-	for (i = 0; i < ARRAY_SIZE(cygaud->audio_clk); i++) {
-		snprintf(clk_name, PROP_LEN_MAX, "ch%d_audio", i);
+	/*
+	 * The default in the DT is to assign a clock. It is possible
+	 * the user may not want a clock if the port is only used in slave
+	 * mode.  In this case, they could override the default using this
+	 * mechanism:    /delete-property/ clocks;
+	 */
+	if (of_property_read_bool(dn, "clocks")) {
+		clk = devm_get_clk_from_child(&pdev->dev, dn, "ssp_clk");
+		if (IS_ERR(clk)) {
+			dev_err(&pdev->dev,
+				"Port %d: devm_clk_get ssp-clk err %ld\n",
+				portnum, PTR_ERR(clk));
+			return PTR_ERR(clk);
+		}
 
-		cygaud->audio_clk[i] = devm_clk_get(&pdev->dev, clk_name);
-		if (IS_ERR(cygaud->audio_clk[i]))
-			return PTR_ERR(cygaud->audio_clk[i]);
+		aio->clk_info.audio_clk = clk;
+
+		if (of_property_read_u32(dn, "brcm,ssp-clk-mux", &muxval)) {
+			dev_err(&pdev->dev, "Missing property clock-mux\n");
+			return -EINVAL;
+		}
+		aio->clk_info.clk_mux = muxval;
+	} else {
+		dev_dbg(&pdev->dev, "No clock provided for port %d\n", portnum);
 	}
 
-	return 0;
+	return audio_ssp_init_portregs(aio);
 }
 
 static int cygnus_ssp_probe(struct platform_device *pdev)
@@ -1337,7 +1210,6 @@ static int cygnus_ssp_probe(struct platform_device *pdev)
 	}
 
 	cygaud->dev = dev;
-	cygaud->active_ports = 0;
 
 	dev_dbg(dev, "Registering %d DAIs\n", active_port_count);
 	err = snd_soc_register_component(dev, &cygnus_ssp_component,
@@ -1354,12 +1226,6 @@ static int cygnus_ssp_probe(struct platform_device *pdev)
 		goto err_irq;
 	}
 
-	err = audio_clk_init(pdev, cygaud);
-	if (err) {
-		dev_err(dev, "audio clock initialization failed\n");
-		goto err_irq;
-	}
-
 	err = cygnus_soc_platform_register(dev, cygaud);
 	if (err) {
 		dev_err(dev, "platform reg error %d\n", err);
diff --git a/sound/soc/bcm/cygnus-ssp.h b/sound/soc/bcm/cygnus-ssp.h
index 33dd343..ad15a00 100644
--- a/sound/soc/bcm/cygnus-ssp.h
+++ b/sound/soc/bcm/cygnus-ssp.h
@@ -19,7 +19,6 @@
 #define CYGNUS_MAX_CAPTURE_PORTS 3
 #define CYGNUS_MAX_I2S_PORTS 3
 #define CYGNUS_MAX_PORTS  CYGNUS_MAX_PLAYBACK_PORTS
-#define CYGNUS_AUIDO_MAX_NUM_CLKS 3
 
 #define CYGNUS_SSP_FRAMEBITS_DIV 1
 
@@ -81,11 +80,9 @@ struct cygnus_ssp_regs {
 	u32 bf_sourcech_grp;
 };
 
-struct cygnus_track_clk {
-	bool cap_en;
-	bool play_en;
-	bool cap_clk_en;
-	bool play_clk_en;
+struct cygnus_audio_clkinfo {
+	struct clk *audio_clk;
+	int clk_mux;
 };
 
 struct cygnus_aio_port {
@@ -110,7 +107,7 @@ struct cygnus_aio_port {
 	struct snd_pcm_substream *play_stream;
 	struct snd_pcm_substream *capture_stream;
 
-	struct cygnus_track_clk clk_trace;
+	struct cygnus_audio_clkinfo clk_info;
 };
 
 
@@ -121,10 +118,6 @@ struct cygnus_audio {
 	void __iomem *audio;
 	struct device *dev;
 	void __iomem *i2s_in;
-
-	struct clk *audio_clk[CYGNUS_AUIDO_MAX_NUM_CLKS];
-	int active_ports;
-	unsigned long vco_rate;
 };
 
 extern int cygnus_ssp_get_mode(struct snd_soc_dai *cpu_dai);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH 4/9] ASoC: cygnus: Only enable MCLK pins when in use
  2017-08-14 22:06 ` Lori Hikichi
@ 2017-08-14 22:06   ` Lori Hikichi
  -1 siblings, 0 replies; 50+ messages in thread
From: Lori Hikichi @ 2017-08-14 22:06 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Mark Rutland, Ray Jui,
	Scott Branden, Jon Mason, bcm-kernel-feedback-list,
	Jaroslav Kysela, Takashi Iwai
  Cc: alsa-devel, devicetree, linux-arm-kernel, linux-kernel, Lori Hikichi

The MCLK pins are now only enabled when they are in use.

Signed-off-by: Lori Hikichi <lori.hikichi@broadcom.com>
---
 sound/soc/bcm/cygnus-ssp.c | 22 ++++++++++++----------
 1 file changed, 12 insertions(+), 10 deletions(-)

diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c
index 00fd4dc..4c476ce 100644
--- a/sound/soc/bcm/cygnus-ssp.c
+++ b/sound/soc/bcm/cygnus-ssp.c
@@ -41,10 +41,10 @@
 /* Begin register offset defines */
 #define AUD_MISC_SEROUT_OE_REG_BASE  0x01c
 #define AUD_MISC_SEROUT_SPDIF_OE  12
-#define AUD_MISC_SEROUT_MCLK_OE   3
-#define AUD_MISC_SEROUT_LRCK_OE   2
-#define AUD_MISC_SEROUT_SCLK_OE   1
-#define AUD_MISC_SEROUT_SDAT_OE   0
+#define AUD_MISC_SEROUT_MCLK_OE    3
+#define AUD_MISC_SEROUT_LRCK_OE    2
+#define AUD_MISC_SEROUT_SCLK_OE    1
+#define AUD_MISC_SEROUT_SDAT_OE    0
 
 /* AUD_FMM_BF_CTRL_xxx regs */
 #define BF_DST_CFG0_OFFSET  0x100
@@ -684,6 +684,11 @@ static int cygnus_ssp_set_sysclk(struct snd_soc_dai *dai,
 	value |= (sel << I2S_OUT_PLLCLKSEL_SHIFT);
 	writel(value, aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
 
+	/* Clear bit for active */
+	value = readl(aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
+	value &= ~BIT(AUD_MISC_SEROUT_MCLK_OE + (aio->portnum * 4));
+	writel(value, aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
+
 	return 0;
 }
 
@@ -827,15 +832,12 @@ static int cygnus_ssp_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 	 * Shift the mask based upon port number.
 	 */
 	mask = BIT(AUD_MISC_SEROUT_LRCK_OE)
-			| BIT(AUD_MISC_SEROUT_SCLK_OE)
-			| BIT(AUD_MISC_SEROUT_MCLK_OE);
+			| BIT(AUD_MISC_SEROUT_SCLK_OE);
 	mask = mask << (aio->portnum * 4);
 	if (aio->is_slave)
-		/* Set bit for tri-state */
-		val |= mask;
+		val |= mask;   /* Set bit for tri-state */
 	else
-		/* Clear bit for drive */
-		val &= ~mask;
+		val &= ~mask;  /* Clear bit for drive */
 
 	dev_dbg(aio->cygaud->dev, "%s  Set OE bits 0x%x\n", __func__, val);
 	writel(val, aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH 4/9] ASoC: cygnus: Only enable MCLK pins when in use
@ 2017-08-14 22:06   ` Lori Hikichi
  0 siblings, 0 replies; 50+ messages in thread
From: Lori Hikichi @ 2017-08-14 22:06 UTC (permalink / raw)
  To: linux-arm-kernel

The MCLK pins are now only enabled when they are in use.

Signed-off-by: Lori Hikichi <lori.hikichi@broadcom.com>
---
 sound/soc/bcm/cygnus-ssp.c | 22 ++++++++++++----------
 1 file changed, 12 insertions(+), 10 deletions(-)

diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c
index 00fd4dc..4c476ce 100644
--- a/sound/soc/bcm/cygnus-ssp.c
+++ b/sound/soc/bcm/cygnus-ssp.c
@@ -41,10 +41,10 @@
 /* Begin register offset defines */
 #define AUD_MISC_SEROUT_OE_REG_BASE  0x01c
 #define AUD_MISC_SEROUT_SPDIF_OE  12
-#define AUD_MISC_SEROUT_MCLK_OE   3
-#define AUD_MISC_SEROUT_LRCK_OE   2
-#define AUD_MISC_SEROUT_SCLK_OE   1
-#define AUD_MISC_SEROUT_SDAT_OE   0
+#define AUD_MISC_SEROUT_MCLK_OE    3
+#define AUD_MISC_SEROUT_LRCK_OE    2
+#define AUD_MISC_SEROUT_SCLK_OE    1
+#define AUD_MISC_SEROUT_SDAT_OE    0
 
 /* AUD_FMM_BF_CTRL_xxx regs */
 #define BF_DST_CFG0_OFFSET  0x100
@@ -684,6 +684,11 @@ static int cygnus_ssp_set_sysclk(struct snd_soc_dai *dai,
 	value |= (sel << I2S_OUT_PLLCLKSEL_SHIFT);
 	writel(value, aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
 
+	/* Clear bit for active */
+	value = readl(aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
+	value &= ~BIT(AUD_MISC_SEROUT_MCLK_OE + (aio->portnum * 4));
+	writel(value, aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
+
 	return 0;
 }
 
@@ -827,15 +832,12 @@ static int cygnus_ssp_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 	 * Shift the mask based upon port number.
 	 */
 	mask = BIT(AUD_MISC_SEROUT_LRCK_OE)
-			| BIT(AUD_MISC_SEROUT_SCLK_OE)
-			| BIT(AUD_MISC_SEROUT_MCLK_OE);
+			| BIT(AUD_MISC_SEROUT_SCLK_OE);
 	mask = mask << (aio->portnum * 4);
 	if (aio->is_slave)
-		/* Set bit for tri-state */
-		val |= mask;
+		val |= mask;   /* Set bit for tri-state */
 	else
-		/* Clear bit for drive */
-		val &= ~mask;
+		val &= ~mask;  /* Clear bit for drive */
 
 	dev_dbg(aio->cygaud->dev, "%s  Set OE bits 0x%x\n", __func__, val);
 	writel(val, aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH 5/9] ASoC: cygnus: Remove support for 8 bit audio and for mono
@ 2017-08-14 22:06   ` Lori Hikichi
  0 siblings, 0 replies; 50+ messages in thread
From: Lori Hikichi @ 2017-08-14 22:06 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Mark Rutland, Ray Jui,
	Scott Branden, Jon Mason, bcm-kernel-feedback-list,
	Jaroslav Kysela, Takashi Iwai
  Cc: alsa-devel, devicetree, linux-arm-kernel, linux-kernel, Lori Hikichi

These modes of operation were not working properly. There is little to
be gained by enabling these modes and the changes required to
potentially fix these modes would complicate the driver.

Signed-off-by: Lori Hikichi <lori.hikichi@broadcom.com>
---
 sound/soc/bcm/cygnus-ssp.c | 24 +++++-------------------
 1 file changed, 5 insertions(+), 19 deletions(-)

diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c
index 4c476ce..5b6e345 100644
--- a/sound/soc/bcm/cygnus-ssp.c
+++ b/sound/soc/bcm/cygnus-ssp.c
@@ -547,23 +547,10 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
 		value &= ~BIT(BF_SRC_CFGX_BUFFER_PAIR_ENABLE);
-		/* Configure channels as mono or stereo/TDM */
-		if (params_channels(params) == 1)
-			value |= BIT(BF_SRC_CFGX_SAMPLE_CH_MODE);
-		else
-			value &= ~BIT(BF_SRC_CFGX_SAMPLE_CH_MODE);
+		value &= ~BIT(BF_SRC_CFGX_SAMPLE_CH_MODE);
 		writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
 
 		switch (params_format(params)) {
-		case SNDRV_PCM_FORMAT_S8:
-			if (aio->port_type == PORT_SPDIF) {
-				dev_err(aio->cygaud->dev,
-				"SPDIF does not support 8bit format\n");
-				return -EINVAL;
-			}
-			bitres = 8;
-			break;
-
 		case SNDRV_PCM_FORMAT_S16_LE:
 			bitres = 16;
 			break;
@@ -1008,19 +995,18 @@ static int cygnus_ssp_set_pll(struct snd_soc_dai *cpu_dai, int pll_id,
 #define INIT_CPU_DAI(num) { \
 	.name = "cygnus-ssp" #num, \
 	.playback = { \
-		.channels_min = 1, \
+		.channels_min = 2, \
 		.channels_max = 16, \
 		.rates = SNDRV_PCM_RATE_KNOT, \
-		.formats = SNDRV_PCM_FMTBIT_S8 | \
-				SNDRV_PCM_FMTBIT_S16_LE | \
+		.formats = SNDRV_PCM_FMTBIT_S16_LE | \
 				SNDRV_PCM_FMTBIT_S32_LE, \
 	}, \
 	.capture = { \
 		.channels_min = 2, \
 		.channels_max = 16, \
 		.rates = SNDRV_PCM_RATE_KNOT, \
-		.formats =  SNDRV_PCM_FMTBIT_S16_LE | \
-					SNDRV_PCM_FMTBIT_S32_LE, \
+		.formats = SNDRV_PCM_FMTBIT_S16_LE | \
+				SNDRV_PCM_FMTBIT_S32_LE, \
 	}, \
 	.ops = &cygnus_ssp_dai_ops, \
 }
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH 5/9] ASoC: cygnus: Remove support for 8 bit audio and for mono
@ 2017-08-14 22:06   ` Lori Hikichi
  0 siblings, 0 replies; 50+ messages in thread
From: Lori Hikichi @ 2017-08-14 22:06 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Mark Rutland, Ray Jui,
	Scott Branden, Jon Mason,
	bcm-kernel-feedback-list-dY08KVG/lbpWk0Htik3J/w, Jaroslav Kysela,
	Takashi Iwai
  Cc: alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Lori Hikichi

These modes of operation were not working properly. There is little to
be gained by enabling these modes and the changes required to
potentially fix these modes would complicate the driver.

Signed-off-by: Lori Hikichi <lori.hikichi-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
---
 sound/soc/bcm/cygnus-ssp.c | 24 +++++-------------------
 1 file changed, 5 insertions(+), 19 deletions(-)

diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c
index 4c476ce..5b6e345 100644
--- a/sound/soc/bcm/cygnus-ssp.c
+++ b/sound/soc/bcm/cygnus-ssp.c
@@ -547,23 +547,10 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
 		value &= ~BIT(BF_SRC_CFGX_BUFFER_PAIR_ENABLE);
-		/* Configure channels as mono or stereo/TDM */
-		if (params_channels(params) == 1)
-			value |= BIT(BF_SRC_CFGX_SAMPLE_CH_MODE);
-		else
-			value &= ~BIT(BF_SRC_CFGX_SAMPLE_CH_MODE);
+		value &= ~BIT(BF_SRC_CFGX_SAMPLE_CH_MODE);
 		writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
 
 		switch (params_format(params)) {
-		case SNDRV_PCM_FORMAT_S8:
-			if (aio->port_type == PORT_SPDIF) {
-				dev_err(aio->cygaud->dev,
-				"SPDIF does not support 8bit format\n");
-				return -EINVAL;
-			}
-			bitres = 8;
-			break;
-
 		case SNDRV_PCM_FORMAT_S16_LE:
 			bitres = 16;
 			break;
@@ -1008,19 +995,18 @@ static int cygnus_ssp_set_pll(struct snd_soc_dai *cpu_dai, int pll_id,
 #define INIT_CPU_DAI(num) { \
 	.name = "cygnus-ssp" #num, \
 	.playback = { \
-		.channels_min = 1, \
+		.channels_min = 2, \
 		.channels_max = 16, \
 		.rates = SNDRV_PCM_RATE_KNOT, \
-		.formats = SNDRV_PCM_FMTBIT_S8 | \
-				SNDRV_PCM_FMTBIT_S16_LE | \
+		.formats = SNDRV_PCM_FMTBIT_S16_LE | \
 				SNDRV_PCM_FMTBIT_S32_LE, \
 	}, \
 	.capture = { \
 		.channels_min = 2, \
 		.channels_max = 16, \
 		.rates = SNDRV_PCM_RATE_KNOT, \
-		.formats =  SNDRV_PCM_FMTBIT_S16_LE | \
-					SNDRV_PCM_FMTBIT_S32_LE, \
+		.formats = SNDRV_PCM_FMTBIT_S16_LE | \
+				SNDRV_PCM_FMTBIT_S32_LE, \
 	}, \
 	.ops = &cygnus_ssp_dai_ops, \
 }
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH 5/9] ASoC: cygnus: Remove support for 8 bit audio and for mono
@ 2017-08-14 22:06   ` Lori Hikichi
  0 siblings, 0 replies; 50+ messages in thread
From: Lori Hikichi @ 2017-08-14 22:06 UTC (permalink / raw)
  To: linux-arm-kernel

These modes of operation were not working properly. There is little to
be gained by enabling these modes and the changes required to
potentially fix these modes would complicate the driver.

Signed-off-by: Lori Hikichi <lori.hikichi@broadcom.com>
---
 sound/soc/bcm/cygnus-ssp.c | 24 +++++-------------------
 1 file changed, 5 insertions(+), 19 deletions(-)

diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c
index 4c476ce..5b6e345 100644
--- a/sound/soc/bcm/cygnus-ssp.c
+++ b/sound/soc/bcm/cygnus-ssp.c
@@ -547,23 +547,10 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
 		value &= ~BIT(BF_SRC_CFGX_BUFFER_PAIR_ENABLE);
-		/* Configure channels as mono or stereo/TDM */
-		if (params_channels(params) == 1)
-			value |= BIT(BF_SRC_CFGX_SAMPLE_CH_MODE);
-		else
-			value &= ~BIT(BF_SRC_CFGX_SAMPLE_CH_MODE);
+		value &= ~BIT(BF_SRC_CFGX_SAMPLE_CH_MODE);
 		writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
 
 		switch (params_format(params)) {
-		case SNDRV_PCM_FORMAT_S8:
-			if (aio->port_type == PORT_SPDIF) {
-				dev_err(aio->cygaud->dev,
-				"SPDIF does not support 8bit format\n");
-				return -EINVAL;
-			}
-			bitres = 8;
-			break;
-
 		case SNDRV_PCM_FORMAT_S16_LE:
 			bitres = 16;
 			break;
@@ -1008,19 +995,18 @@ static int cygnus_ssp_set_pll(struct snd_soc_dai *cpu_dai, int pll_id,
 #define INIT_CPU_DAI(num) { \
 	.name = "cygnus-ssp" #num, \
 	.playback = { \
-		.channels_min = 1, \
+		.channels_min = 2, \
 		.channels_max = 16, \
 		.rates = SNDRV_PCM_RATE_KNOT, \
-		.formats = SNDRV_PCM_FMTBIT_S8 | \
-				SNDRV_PCM_FMTBIT_S16_LE | \
+		.formats = SNDRV_PCM_FMTBIT_S16_LE | \
 				SNDRV_PCM_FMTBIT_S32_LE, \
 	}, \
 	.capture = { \
 		.channels_min = 2, \
 		.channels_max = 16, \
 		.rates = SNDRV_PCM_RATE_KNOT, \
-		.formats =  SNDRV_PCM_FMTBIT_S16_LE | \
-					SNDRV_PCM_FMTBIT_S32_LE, \
+		.formats = SNDRV_PCM_FMTBIT_S16_LE | \
+				SNDRV_PCM_FMTBIT_S32_LE, \
 	}, \
 	.ops = &cygnus_ssp_dai_ops, \
 }
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH 6/9] ASoc: cygnus: Fix problems with multichannel transfers
  2017-08-14 22:06 ` Lori Hikichi
@ 2017-08-14 22:06   ` Lori Hikichi
  -1 siblings, 0 replies; 50+ messages in thread
From: Lori Hikichi @ 2017-08-14 22:06 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Mark Rutland, Ray Jui,
	Scott Branden, Jon Mason, bcm-kernel-feedback-list,
	Jaroslav Kysela, Takashi Iwai
  Cc: alsa-devel, devicetree, linux-arm-kernel, linux-kernel, Lori Hikichi

Problems were found with multi-channel (4+) TDM transfers. The alignment
of the channels within the frame could shift when starting a new transfer.
In order to implement a fix the register programming sequence needed to
be revised.

Signed-off-by: Lori Hikichi <lori.hikichi@broadcom.com>
---
 sound/soc/bcm/cygnus-ssp.c | 539 ++++++++++++++++++++++++++++++++-------------
 sound/soc/bcm/cygnus-ssp.h |  14 +-
 2 files changed, 394 insertions(+), 159 deletions(-)

diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c
index 5b6e345..5292c04 100644
--- a/sound/soc/bcm/cygnus-ssp.c
+++ b/sound/soc/bcm/cygnus-ssp.c
@@ -121,6 +121,7 @@
 #define I2S_OUT_STREAM_ENA  31
 #define I2S_OUT_STREAM_CFG_GROUP_ID  20
 #define I2S_OUT_STREAM_CFG_CHANNEL_GROUPING  24
+#define I2S_OUT_STREAM_CFG_FCI_ID_MASK  0x3ff
 
 /* AUD_FMM_IOP_IN_I2S_x_CAP */
 #define I2S_IN_STREAM_CFG_CAP_ENA   31
@@ -129,7 +130,11 @@
 /* AUD_FMM_IOP_OUT_I2S_x_I2S_CFG_REG */
 #define I2S_OUT_CFGX_CLK_ENA         0
 #define I2S_OUT_CFGX_DATA_ENABLE     1
+#define I2S_OUT_CFGX_LRCK_POLARITY   4
+#define I2S_OUT_CFGX_SCLK_POLARITY   5
 #define I2S_OUT_CFGX_DATA_ALIGNMENT  6
+#define I2S_OUT_CFGX_BITS_PER_SAMPLE 8
+#define I2S_OUT_CFGX_BIT_PER_SAMPLE_MASK 0x1f
 #define I2S_OUT_CFGX_BITS_PER_SLOT  13
 #define I2S_OUT_CFGX_VALID_SLOT     14
 #define I2S_OUT_CFGX_FSYNC_WIDTH    18
@@ -137,14 +142,27 @@
 #define I2S_OUT_CFGX_SLAVE_MODE     30
 #define I2S_OUT_CFGX_TDM_MODE       31
 
+#define I2S_IN_CFGX_DATA_ALIGNMENT   6
+#define I2S_IN_CFGX_BITS_PER_SAMPLE  8
+#define I2S_IN_CFGX_BIT_PER_SAMPLE_MASK 0x1f
+#define I2S_IN_CFGX_BITS_PER_SLOT   13
+#define I2S_IN_CFGX_VALID_SLOT      14
+#define I2S_IN_CFGX_SLAVE_MODE      30
+#define I2S_IN_CFGX_TDM_MODE        31
+
 /* AUD_FMM_BF_CTRL_SOURCECH_CFGx_REG */
 #define BF_SRC_CFGX_SFIFO_ENA              0
 #define BF_SRC_CFGX_BUFFER_PAIR_ENABLE     1
 #define BF_SRC_CFGX_SAMPLE_CH_MODE         2
 #define BF_SRC_CFGX_SFIFO_SZ_DOUBLE        5
 #define BF_SRC_CFGX_NOT_PAUSE_WHEN_EMPTY  10
+#define BF_SRC_CFGX_SAMPLE_REPEAT_ENABLE  11
 #define BF_SRC_CFGX_BIT_RES               20
 #define BF_SRC_CFGX_PROCESS_SEQ_ID_VALID  31
+#define BF_SRC_CFGX_BITRES_MASK           0x1f
+
+/* AUD_FMM_BF_CTRL_SOURCECH_CTRLx_REG */
+#define BF_SOURCECH_CTRL_PLAY_RUN   0
 
 /* AUD_FMM_BF_CTRL_DESTCH_CFGx_REG */
 #define BF_DST_CFGX_CAP_ENA              0
@@ -154,11 +172,16 @@
 #define BF_DST_CFGX_FCI_ID              12
 #define BF_DST_CFGX_CAP_MODE            24
 #define BF_DST_CFGX_PROC_SEQ_ID_VALID   31
+#define BF_DST_CFGX_BITRES_MASK         0x1f
+
+/* AUD_FMM_BF_CTRL_DESTCH_CTRLX */
+#define BF_DESTCH_CTRLX_CAP_RUN  0x1
 
 /* AUD_FMM_IOP_OUT_SPDIF_xxx */
 #define SPDIF_0_OUT_DITHER_ENA     3
 #define SPDIF_0_OUT_STREAM_ENA    31
 
+#define IOP_LOGIC_RESET_IN_OFFSET(x) ((x) + 7) /* Capture ports offset by 7 */
 
 #define INIT_SSP_REGS(num) (struct cygnus_ssp_regs){ \
 		.i2s_stream_cfg = OUT_I2S_ ##num## _STREAM_CFG_OFFSET, \
@@ -169,8 +192,7 @@
 		.bf_destch_ctrl = BF_DST_CTRL ##num## _OFFSET, \
 		.bf_destch_cfg = BF_DST_CFG ##num## _OFFSET, \
 		.bf_sourcech_ctrl = BF_SRC_CTRL ##num## _OFFSET, \
-		.bf_sourcech_cfg = BF_SRC_CFG ##num## _OFFSET, \
-		.bf_sourcech_grp = BF_SRC_GRP ##num## _OFFSET \
+		.bf_sourcech_cfg = BF_SRC_CFG ##num## _OFFSET \
 }
 
 #define CYGNUS_RATE_MIN     8000
@@ -189,6 +211,8 @@
 	.list = cygnus_rates,
 };
 
+static void update_ssp_cfg(struct cygnus_aio_port *aio);
+
 static struct cygnus_aio_port *cygnus_dai_get_portinfo(struct snd_soc_dai *dai)
 {
 	struct cygnus_audio *cygaud = snd_soc_dai_get_drvdata(dai);
@@ -201,15 +225,17 @@ static int audio_ssp_init_portregs(struct cygnus_aio_port *aio)
 	u32 value, fci_id;
 	int status = 0;
 
+	/* Set Group ID */
+	writel(0, aio->cygaud->audio + BF_SRC_GRP0_OFFSET);
+	writel(1, aio->cygaud->audio + BF_SRC_GRP1_OFFSET);
+	writel(2, aio->cygaud->audio + BF_SRC_GRP2_OFFSET);
+	writel(3, aio->cygaud->audio + BF_SRC_GRP3_OFFSET);
+
 	switch (aio->port_type) {
 	case PORT_TDM:
 		value = readl(aio->cygaud->audio + aio->regs.i2s_stream_cfg);
 		value &= ~I2S_STREAM_CFG_MASK;
 
-		/* Set Group ID */
-		writel(aio->portnum,
-			aio->cygaud->audio + aio->regs.bf_sourcech_grp);
-
 		/* Configure the AUD_FMM_IOP_OUT_I2S_x_STREAM_CFG reg */
 		value |= aio->portnum << I2S_OUT_STREAM_CFG_GROUP_ID;
 		value |= aio->portnum; /* FCI ID is the port num */
@@ -219,6 +245,7 @@ static int audio_ssp_init_portregs(struct cygnus_aio_port *aio)
 		/* Configure the AUD_FMM_BF_CTRL_SOURCECH_CFGX reg */
 		value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
 		value &= ~BIT(BF_SRC_CFGX_NOT_PAUSE_WHEN_EMPTY);
+		value &= ~BIT(BF_SRC_CFGX_SAMPLE_REPEAT_ENABLE);
 		value |= BIT(BF_SRC_CFGX_SFIFO_SZ_DOUBLE);
 		value |= BIT(BF_SRC_CFGX_PROCESS_SEQ_ID_VALID);
 		writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
@@ -247,8 +274,6 @@ static int audio_ssp_init_portregs(struct cygnus_aio_port *aio)
 		writel(value, aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
 		break;
 	case PORT_SPDIF:
-		writel(aio->portnum, aio->cygaud->audio + BF_SRC_GRP3_OFFSET);
-
 		value = readl(aio->cygaud->audio + SPDIF_CTRL_OFFSET);
 		value |= BIT(SPDIF_0_OUT_DITHER_ENA);
 		writel(value, aio->cygaud->audio + SPDIF_CTRL_OFFSET);
@@ -287,17 +312,35 @@ static void audio_ssp_in_enable(struct cygnus_aio_port *aio)
 	value |= BIT(BF_DST_CFGX_CAP_ENA);
 	writel(value, aio->cygaud->audio + aio->regs.bf_destch_cfg);
 
-	writel(0x1, aio->cygaud->audio + aio->regs.bf_destch_ctrl);
-
-	value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
-	value |= BIT(I2S_OUT_CFGX_CLK_ENA);
-	value |= BIT(I2S_OUT_CFGX_DATA_ENABLE);
-	writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
+	/*
+	 * DATA_ENABLE need to be set even if doing capture.
+	 * Subsequent Tx will fail if this is not done.
+	 */
+	if (!aio->streams_on) {
+		value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
+		value |= BIT(I2S_OUT_CFGX_CLK_ENA);
+		value |= BIT(I2S_OUT_CFGX_DATA_ENABLE);
+		writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
+	}
 
 	value = readl(aio->cygaud->i2s_in + aio->regs.i2s_cap_stream_cfg);
 	value |= BIT(I2S_IN_STREAM_CFG_CAP_ENA);
 	writel(value, aio->cygaud->i2s_in + aio->regs.i2s_cap_stream_cfg);
 
+	/* Enable input portion of block */
+	udelay(10);
+
+	/*
+	 * The input port may or may not be held in reset. Always clear
+	 * the reset. This will be benign if the port is not in reset.
+	 */
+	value = readl(aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+	value &= ~BIT(IOP_LOGIC_RESET_IN_OFFSET(aio->portnum));
+	writel(value, aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+
+	writel(BF_DESTCH_CTRLX_CAP_RUN,
+		aio->cygaud->audio + aio->regs.bf_destch_ctrl);
+
 	aio->streams_on |= CAPTURE_STREAM_MASK;
 }
 
@@ -305,25 +348,50 @@ static void audio_ssp_in_disable(struct cygnus_aio_port *aio)
 {
 	u32 value;
 
+	value = readl(aio->cygaud->audio + aio->regs.bf_destch_cfg);
+	value &= ~BIT(BF_DST_CFGX_CAP_ENA);
+	writel(value, aio->cygaud->audio + aio->regs.bf_destch_cfg);
+
 	value = readl(aio->cygaud->i2s_in + aio->regs.i2s_cap_stream_cfg);
 	value &= ~BIT(I2S_IN_STREAM_CFG_CAP_ENA);
 	writel(value, aio->cygaud->i2s_in + aio->regs.i2s_cap_stream_cfg);
 
 	aio->streams_on &= ~CAPTURE_STREAM_MASK;
 
+	writel(0x0, aio->cygaud->audio + aio->regs.bf_destch_ctrl);
+
+	/*
+	 * Put input portion of port in reset.
+	 * Clears residual data (32 bits) from internal formatter buffer
+	 * BIT_CLOCK must be present for this to take effect.  For Cygnus
+	 * in slave mode this means we must master after Cygnus port
+	 */
+	/*
+	 * TDM Slave Rx needs to toggle this reset.
+	 * See comment in cygnus_ssp_hw_params() about JIRA-1312.
+	 * TDM Master Rx also needs this fix
+	 *   32 bit transfers of fully populated TDM frames will have every
+	 *   transfer after the first with misaligned channels.
+	 *
+	 */
+	if (aio->mode == CYGNUS_SSPMODE_TDM) {
+		value = readl(aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+		value |= BIT(IOP_LOGIC_RESET_IN_OFFSET(aio->portnum));
+		writel(value, aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+	}
+
 	/* If both playback and capture are off */
 	if (!aio->streams_on) {
+		/*
+		 * Add small delay before turning off clock
+		 * Need 1 bit clock tick for INIT_LOGIC to activate
+		 */
+		udelay(10);
 		value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
 		value &= ~BIT(I2S_OUT_CFGX_CLK_ENA);
 		value &= ~BIT(I2S_OUT_CFGX_DATA_ENABLE);
 		writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
 	}
-
-	writel(0x0, aio->cygaud->audio + aio->regs.bf_destch_ctrl);
-
-	value = readl(aio->cygaud->audio + aio->regs.bf_destch_cfg);
-	value &= ~BIT(BF_DST_CFGX_CAP_ENA);
-	writel(value, aio->cygaud->audio + aio->regs.bf_destch_cfg);
 }
 
 static int audio_ssp_out_enable(struct cygnus_aio_port *aio)
@@ -334,19 +402,33 @@ static int audio_ssp_out_enable(struct cygnus_aio_port *aio)
 	switch (aio->port_type) {
 	case PORT_TDM:
 		value = readl(aio->cygaud->audio + aio->regs.i2s_stream_cfg);
-		value |= BIT(I2S_OUT_STREAM_ENA);
+		value &= ~(I2S_OUT_STREAM_CFG_FCI_ID_MASK);
+		value |= aio->portnum;
 		writel(value, aio->cygaud->audio + aio->regs.i2s_stream_cfg);
 
-		writel(1, aio->cygaud->audio + aio->regs.bf_sourcech_ctrl);
+		value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		value |= BIT(BF_SRC_CFGX_SFIFO_ENA);
+		writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+
+		writel(BIT(BF_SOURCECH_CTRL_PLAY_RUN),
+			aio->cygaud->audio + aio->regs.bf_sourcech_ctrl);
+
+		value = readl(aio->cygaud->audio + aio->regs.i2s_stream_cfg);
+		value |= BIT(I2S_OUT_STREAM_ENA);
+		writel(value, aio->cygaud->audio + aio->regs.i2s_stream_cfg);
 
 		value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
 		value |= BIT(I2S_OUT_CFGX_CLK_ENA);
 		value |= BIT(I2S_OUT_CFGX_DATA_ENABLE);
 		writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
 
-		value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
-		value |= BIT(BF_SRC_CFGX_SFIFO_ENA);
-		writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		/*
+		 * The output port may or may not be in reset. Always clear
+		 * the reset. This will be benign if the port is not in reset.
+		 */
+		value = readl(aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+		value &= ~BIT(aio->portnum);
+		writel(value, aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
 
 		aio->streams_on |= PLAYBACK_STREAM_MASK;
 		break;
@@ -355,7 +437,8 @@ static int audio_ssp_out_enable(struct cygnus_aio_port *aio)
 		value |= 0x3;
 		writel(value, aio->cygaud->audio + SPDIF_FORMAT_CFG_OFFSET);
 
-		writel(1, aio->cygaud->audio + aio->regs.bf_sourcech_ctrl);
+		writel(BIT(BF_SOURCECH_CTRL_PLAY_RUN),
+			aio->cygaud->audio + aio->regs.bf_sourcech_ctrl);
 
 		value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
 		value |= BIT(BF_SRC_CFGX_SFIFO_ENA);
@@ -379,13 +462,17 @@ static int audio_ssp_out_disable(struct cygnus_aio_port *aio)
 	case PORT_TDM:
 		aio->streams_on &= ~PLAYBACK_STREAM_MASK;
 
-		/* If both playback and capture are off */
-		if (!aio->streams_on) {
-			value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
-			value &= ~BIT(I2S_OUT_CFGX_CLK_ENA);
-			value &= ~BIT(I2S_OUT_CFGX_DATA_ENABLE);
-			writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
-		}
+		/* Set the FCI ID to INVALID */
+		value = readl(aio->cygaud->audio + aio->regs.i2s_stream_cfg);
+		value |= 0x3ff;
+		writel(value, aio->cygaud->audio + aio->regs.i2s_stream_cfg);
+
+		/*
+		 * We want to wait enough time for 2 LRCLK.
+		 * At 8 kHz framerate, this would be 250 us.
+		 * Set delay to 300 us to be safe.
+		 */
+		udelay(300);
 
 		/* set group_sync_dis = 1 */
 		value = readl(aio->cygaud->audio + BF_SRC_GRP_SYNC_DIS_OFFSET);
@@ -403,16 +490,27 @@ static int audio_ssp_out_disable(struct cygnus_aio_port *aio)
 		value &= ~BIT(aio->portnum);
 		writel(value, aio->cygaud->audio + BF_SRC_GRP_SYNC_DIS_OFFSET);
 
-		value = readl(aio->cygaud->audio + aio->regs.i2s_stream_cfg);
-		value &= ~BIT(I2S_OUT_STREAM_ENA);
-		writel(value, aio->cygaud->audio + aio->regs.i2s_stream_cfg);
+		/*
+		 * We want to wait enough time for 1 LRCLK.
+		 * At 8 kHz framerate, this would be 125 us.
+		 * Set delay to 175 us to be safe.
+		 */
+		udelay(175);
+
+		if (aio->is_slave && (aio->mode == CYGNUS_SSPMODE_TDM)) {
+			value = readl(aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+			value |= BIT(aio->portnum);
+			writel(value, aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+		}
+
+		/* If both playback and capture are off */
+		if (aio->streams_on == 0) {
+			value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
+			value &= ~BIT(I2S_OUT_CFGX_DATA_ENABLE);
+			value &= ~BIT(I2S_OUT_CFGX_CLK_ENA);
+			writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
+		}
 
-		/* IOP SW INIT on OUT_I2S_x */
-		value = readl(aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
-		value |= BIT(aio->portnum);
-		writel(value, aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
-		value &= ~BIT(aio->portnum);
-		writel(value, aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
 		break;
 	case PORT_SPDIF:
 		value = readl(aio->cygaud->audio + SPDIF_FORMAT_CFG_OFFSET);
@@ -439,10 +537,12 @@ static int cygnus_ssp_set_clocks(struct cygnus_aio_port *aio)
 	u32 mask = 0xf;
 	u32 sclk;
 	u32 mclk_rate;
+	unsigned int bits_per_frame;
 	unsigned int bit_rate;
 	unsigned int ratio;
 
-	bit_rate = aio->bit_per_frame * aio->lrclk;
+	bits_per_frame = aio->slots_per_frame * aio->slot_width;
+	bit_rate = bits_per_frame * aio->lrclk;
 
 	/*
 	 * Check if the bit clock can be generated from the given MCLK.
@@ -468,14 +568,14 @@ static int cygnus_ssp_set_clocks(struct cygnus_aio_port *aio)
 		dev_err(aio->cygaud->dev,
 			"Invalid combination of MCLK and BCLK\n");
 		dev_err(aio->cygaud->dev, "lrclk = %u, bits/frame = %u, mclk = %u\n",
-			aio->lrclk, aio->bit_per_frame, aio->mclk);
+			aio->lrclk, bits_per_frame, aio->mclk);
 		return -EINVAL;
 	}
 
 	/* Set sclk rate */
 	switch (aio->port_type) {
 	case PORT_TDM:
-		sclk = aio->bit_per_frame;
+		sclk = bits_per_frame;
 		if (sclk == 512)
 			sclk = 0;
 
@@ -505,7 +605,7 @@ static int cygnus_ssp_set_clocks(struct cygnus_aio_port *aio)
 
 	dev_dbg(aio->cygaud->dev, "mclk cfg reg = 0x%x\n", value);
 	dev_dbg(aio->cygaud->dev, "bits per frame = %u, mclk = %u Hz, lrclk = %u Hz\n",
-			aio->bit_per_frame, aio->mclk, aio->lrclk);
+			bits_per_frame, aio->mclk, aio->lrclk);
 	return 0;
 }
 
@@ -514,9 +614,9 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 				 struct snd_soc_dai *dai)
 {
 	struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai);
-	int rate, bitres;
+	int rate, bitres, bits_per_sample;
 	u32 value;
-	u32 mask = 0x1f;
+	u32 mask;
 	int ret = 0;
 
 	dev_dbg(aio->cygaud->dev, "%s port = %d\n", __func__, aio->portnum);
@@ -529,6 +629,7 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 
 	switch (aio->mode) {
 	case CYGNUS_SSPMODE_TDM:
+		/* It's expected that set_dai_tdm_slot has been called */
 		if ((rate == 192000) && (params_channels(params) > 4)) {
 			dev_err(aio->cygaud->dev, "Cannot run %d channels at %dHz\n",
 				params_channels(params), rate);
@@ -536,7 +637,15 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 		}
 		break;
 	case CYGNUS_SSPMODE_I2S:
-		aio->bit_per_frame = 64; /* I2S must be 64 bit per frame */
+		if (params_channels(params) != 2) {
+			dev_err(aio->cygaud->dev, "i2s mode must use 2 channels\n");
+			return -EINVAL;
+		}
+
+		aio->active_slots = 2;
+		aio->slots_per_frame = 2;
+		aio->slot_width = 32; /* Use 64Fs */
+
 		break;
 	default:
 		dev_err(aio->cygaud->dev,
@@ -553,26 +662,36 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 		switch (params_format(params)) {
 		case SNDRV_PCM_FORMAT_S16_LE:
 			bitres = 16;
+			bits_per_sample = 16;
 			break;
 
 		case SNDRV_PCM_FORMAT_S32_LE:
-			/* 32 bit mode is coded as 0 */
-			bitres = 0;
+			bitres = 0; /* 32 bit mode is coded as 0 */
+			bits_per_sample = 24; /* Only 24 valid bits */
 			break;
 
 		default:
 			return -EINVAL;
 		}
 
+		mask = BF_SRC_CFGX_BITRES_MASK;
 		value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
 		value &= ~(mask << BF_SRC_CFGX_BIT_RES);
 		value |= (bitres << BF_SRC_CFGX_BIT_RES);
 		writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
 
+		/* Only needed for LSB mode, ignored for MSB */
+		mask = I2S_OUT_CFGX_BIT_PER_SAMPLE_MASK;
+		value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
+		value &= ~(mask << I2S_OUT_CFGX_BITS_PER_SAMPLE);
+		value |= (bits_per_sample << I2S_OUT_CFGX_BITS_PER_SAMPLE);
+		writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
 	} else {
 
 		switch (params_format(params)) {
 		case SNDRV_PCM_FORMAT_S16_LE:
+			bits_per_sample = 16;
+
 			value = readl(aio->cygaud->audio +
 					aio->regs.bf_destch_cfg);
 			value |= BIT(BF_DST_CFGX_CAP_MODE);
@@ -581,6 +700,8 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 			break;
 
 		case SNDRV_PCM_FORMAT_S32_LE:
+			bits_per_sample = 24; /* Only 24 valid bits */
+
 			value = readl(aio->cygaud->audio +
 					aio->regs.bf_destch_cfg);
 			value &= ~BIT(BF_DST_CFGX_CAP_MODE);
@@ -591,12 +712,52 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 		default:
 			return -EINVAL;
 		}
+
+		/* Used for both LSB and MSB modes */
+		mask = I2S_IN_CFGX_BIT_PER_SAMPLE_MASK;
+		value = readl(aio->cygaud->i2s_in + aio->regs.i2s_cap_cfg);
+		value &= ~(mask << I2S_IN_CFGX_BITS_PER_SAMPLE);
+		value |= (bits_per_sample << I2S_IN_CFGX_BITS_PER_SAMPLE);
+		writel(value, aio->cygaud->i2s_in + aio->regs.i2s_cap_cfg);
 	}
 
-	aio->lrclk = rate;
+	/* Put output port into reset prior to configuring.
+	 * This action is a workaround for couple situations:
+	 *   1) JIRA-1312: 16-bit TDM Slave Tx problem
+	 *      If the port is configured as 16-bit slave and
+	 *      both CLK_ENA and DATA_ENABLE bits are off then the port will
+	 *      fail to Tx.  Therefore, we hold port in reset until the
+	 *      we are ready to enable
+	 *   2) The TDM Slave Tx stream will be misaligned on the first
+	 *      transfer after boot/reset (both 16 and 32 bit modes).
+	 *      Applying reset will workaround this problem.
+	 */
+	if (aio->streams_on == 0) {
+		if (aio->is_slave && (aio->mode == CYGNUS_SSPMODE_TDM)) {
+			/*
+			 * Need to do this LOGIC reset after boot/reset
+			 * because it puts the logic in a slightly different
+			 * than hard reset. In this way the chip logic will be
+			 * in the same state for our first transfer as it is
+			 * every transfer.
+			 */
+			value = readl(aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+			value |= BIT(aio->portnum);
+			writel(value, aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+
+			value = readl(aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+			value |= BIT(IOP_LOGIC_RESET_IN_OFFSET(aio->portnum));
+			writel(value, aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+		}
+
+		if (aio->port_type != PORT_SPDIF)
+			update_ssp_cfg(aio);
 
-	if (!aio->is_slave)
-		ret = cygnus_ssp_set_clocks(aio);
+		aio->lrclk = rate;
+
+		if (!aio->is_slave)
+			ret = cygnus_ssp_set_clocks(aio);
+	}
 
 	return ret;
 }
@@ -703,28 +864,6 @@ static void cygnus_ssp_shutdown(struct snd_pcm_substream *substream,
 	clk_disable_unprepare(aio->clk_info.audio_clk);
 }
 
-/*
- * Bit    Update  Notes
- * 31     Yes     TDM Mode        (1 = TDM, 0 = i2s)
- * 30     Yes     Slave Mode	  (1 = Slave, 0 = Master)
- * 29:26  No      Sclks per frame
- * 25:18  Yes     FS Width
- * 17:14  No      Valid Slots
- * 13     No      Bits		  (1 = 16 bits, 0 = 32 bits)
- * 12:08  No     Bits per samp
- * 07     Yes     Justifcation    (1 = LSB, 0 = MSB)
- * 06     Yes     Alignment       (1 = Delay 1 clk, 0 = no delay
- * 05     Yes     SCLK polarity   (1 = Rising, 0 = Falling)
- * 04     Yes     LRCLK Polarity  (1 = High for left, 0 = Low for left)
- * 03:02  Yes     Reserved - write as zero
- * 01     No      Data Enable
- * 00     No      CLK Enable
- */
-#define I2S_OUT_CFG_REG_UPDATE_MASK   0x3C03FF03
-
-/* Input cfg is same as output, but the FS width is not a valid field */
-#define I2S_IN_CFG_REG_UPDATE_MASK  (I2S_OUT_CFG_REG_UPDATE_MASK | 0x03FC0000)
-
 int cygnus_ssp_set_custom_fsync_width(struct snd_soc_dai *cpu_dai, int len)
 {
 	struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(cpu_dai);
@@ -740,10 +879,6 @@ int cygnus_ssp_set_custom_fsync_width(struct snd_soc_dai *cpu_dai, int len)
 static int cygnus_ssp_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 {
 	struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(cpu_dai);
-	u32 ssp_curcfg;
-	u32 ssp_newcfg;
-	u32 ssp_outcfg;
-	u32 ssp_incfg;
 	u32 val;
 	u32 mask;
 
@@ -752,15 +887,11 @@ static int cygnus_ssp_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 	if (aio->port_type == PORT_SPDIF)
 		return -EINVAL;
 
-	ssp_newcfg = 0;
-
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBM_CFM:
-		ssp_newcfg |= BIT(I2S_OUT_CFGX_SLAVE_MODE);
 		aio->is_slave = 1;
 		break;
 	case SND_SOC_DAIFMT_CBS_CFS:
-		ssp_newcfg &= ~BIT(I2S_OUT_CFGX_SLAVE_MODE);
 		aio->is_slave = 0;
 		break;
 	default:
@@ -769,25 +900,24 @@ static int cygnus_ssp_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 	case SND_SOC_DAIFMT_I2S:
-		ssp_newcfg |= BIT(I2S_OUT_CFGX_DATA_ALIGNMENT);
-		ssp_newcfg |= BIT(I2S_OUT_CFGX_FSYNC_WIDTH);
+		aio->fs_delay = 1;
 		aio->mode = CYGNUS_SSPMODE_I2S;
 		break;
 
 	case SND_SOC_DAIFMT_DSP_A:
 	case SND_SOC_DAIFMT_DSP_B:
-		ssp_newcfg |= BIT(I2S_OUT_CFGX_TDM_MODE);
-
 		/* DSP_A = data after FS, DSP_B = data during FS */
 		if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_DSP_A)
-			ssp_newcfg |= BIT(I2S_OUT_CFGX_DATA_ALIGNMENT);
-
-		if ((aio->fsync_width > 0) && (aio->fsync_width < 256))
-			ssp_newcfg |=
-				(aio->fsync_width << I2S_OUT_CFGX_FSYNC_WIDTH);
-		else
-			ssp_newcfg |= BIT(I2S_OUT_CFGX_FSYNC_WIDTH);
-
+			aio->fs_delay = 1;
+		else {
+			if (aio->is_slave) {
+				dev_err(aio->cygaud->dev,
+				"%s DSP_B mode not supported while slave.\n",
+					__func__);
+				return -EINVAL;
+			}
+			aio->fs_delay = 0;
+		}
 		aio->mode = CYGNUS_SSPMODE_TDM;
 		break;
 
@@ -795,21 +925,36 @@ static int cygnus_ssp_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 		return -EINVAL;
 	}
 
-	/*
-	 * SSP out cfg.
-	 * Retain bits we do not want to update, then OR in new bits
-	 */
-	ssp_curcfg = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
-	ssp_outcfg = (ssp_curcfg & I2S_OUT_CFG_REG_UPDATE_MASK) | ssp_newcfg;
-	writel(ssp_outcfg, aio->cygaud->audio + aio->regs.i2s_cfg);
+	/* We must be i2s master to invert any clock */
+	if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) {
+		if (aio->is_slave || (aio->mode == CYGNUS_SSPMODE_TDM)) {
+			dev_err(aio->cygaud->dev,
+			"%s Can only invert clocks in i2s master mode\n",
+				__func__);
+			return -EINVAL;
+		}
+	}
 
-	/*
-	 * SSP in cfg.
-	 * Retain bits we do not want to update, then OR in new bits
-	 */
-	ssp_curcfg = readl(aio->cygaud->i2s_in + aio->regs.i2s_cap_cfg);
-	ssp_incfg = (ssp_curcfg & I2S_IN_CFG_REG_UPDATE_MASK) | ssp_newcfg;
-	writel(ssp_incfg, aio->cygaud->i2s_in + aio->regs.i2s_cap_cfg);
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_IB_NF:
+		aio->invert_bclk = true;
+		aio->invert_fs = false;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		aio->invert_bclk = false;
+		aio->invert_fs = true;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		aio->invert_bclk = true;
+		aio->invert_fs = true;
+		break;
+	case SND_SOC_DAIFMT_NB_NF:
+		aio->invert_bclk = false;
+		aio->invert_fs = false;
+		break;
+	default:
+		return -EINVAL;
+	}
 
 	val = readl(aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
 
@@ -871,12 +1016,10 @@ static int cygnus_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
 	unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
 {
 	struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(cpu_dai);
-	u32 value;
-	int bits_per_slot = 0;     /* default to 32-bits per slot */
-	int frame_bits;
 	unsigned int active_slots;
+	unsigned int bits_per_frame;
 	bool found = false;
-	int i;
+	unsigned int i;
 
 	if (tx_mask != rx_mask) {
 		dev_err(aio->cygaud->dev,
@@ -886,35 +1029,20 @@ static int cygnus_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
 
 	active_slots = hweight32(tx_mask);
 
-	if ((active_slots < 0) || (active_slots > 16))
+	if ((active_slots == 0) || (active_slots > 16))
 		return -EINVAL;
 
 	/* Slot value must be even */
 	if (active_slots % 2)
 		return -EINVAL;
 
-	/* We encode 16 slots as 0 in the reg */
-	if (active_slots == 16)
-		active_slots = 0;
-
-	/* Slot Width is either 16 or 32 */
-	switch (slot_width) {
-	case 16:
-		bits_per_slot = 1;
-		break;
-	case 32:
-		bits_per_slot = 0;
-		break;
-	default:
-		bits_per_slot = 0;
-		dev_warn(aio->cygaud->dev,
-			"%s Defaulting Slot Width to 32\n", __func__);
-	}
+	if ((slot_width != 16) && (slot_width != 32))
+		return -EINVAL;
 
-	frame_bits = slots * slot_width;
+	bits_per_frame = slots * slot_width;
 
 	for (i = 0; i < ARRAY_SIZE(ssp_valid_tdm_framesize); i++) {
-		if (ssp_valid_tdm_framesize[i] == frame_bits) {
+		if (ssp_valid_tdm_framesize[i] == bits_per_frame) {
 			found = true;
 			break;
 		}
@@ -923,31 +1051,16 @@ static int cygnus_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
 	if (!found) {
 		dev_err(aio->cygaud->dev,
 			"%s In TDM mode, frame bits INVALID (%d)\n",
-			__func__, frame_bits);
+			__func__, bits_per_frame);
 		return -EINVAL;
 	}
 
-	aio->bit_per_frame = frame_bits;
+	aio->active_slots = active_slots;
+	aio->slot_width = slot_width;
+	aio->slots_per_frame = slots;
 
 	dev_dbg(aio->cygaud->dev, "%s active_slots %u, bits per frame %d\n",
-			__func__, active_slots, frame_bits);
-
-	/* Set capture side of ssp port */
-	value = readl(aio->cygaud->i2s_in + aio->regs.i2s_cap_cfg);
-	value &= ~(0xf << I2S_OUT_CFGX_VALID_SLOT);
-	value |= (active_slots << I2S_OUT_CFGX_VALID_SLOT);
-	value &= ~BIT(I2S_OUT_CFGX_BITS_PER_SLOT);
-	value |= (bits_per_slot << I2S_OUT_CFGX_BITS_PER_SLOT);
-	writel(value, aio->cygaud->i2s_in + aio->regs.i2s_cap_cfg);
-
-	/* Set playback side of ssp port */
-	value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
-	value &= ~(0xf << I2S_OUT_CFGX_VALID_SLOT);
-	value |= (active_slots << I2S_OUT_CFGX_VALID_SLOT);
-	value &= ~BIT(I2S_OUT_CFGX_BITS_PER_SLOT);
-	value |= (bits_per_slot << I2S_OUT_CFGX_BITS_PER_SLOT);
-	writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
-
+			__func__, aio->active_slots, bits_per_frame);
 	return 0;
 }
 
@@ -978,6 +1091,124 @@ static int cygnus_ssp_set_pll(struct snd_soc_dai *cpu_dai, int pll_id,
 	return ret;
 }
 
+/*
+ * Bit    Update  Notes
+ * 31     Yes     TDM Mode        (1 = TDM, 0 = i2s)
+ * 30     Yes     Slave Mode      (1 = Slave, 0 = Master)
+ * 29:26  No      Sclks per frame
+ * 25:18  Yes     FS Width
+ * 17:14  No      Valid Slots
+ * 13     No      Bits            (1 = 16 bits, 0 = 32 bits)
+ * 12:08  No      Bits per samp
+ * 07     Yes     Justifcation    (1 = LSB, 0 = MSB)
+ * 06     Yes     Alignment       (1 = Delay 1 clk, 0 = no delay
+ * 05     Yes     SCLK polarity   (1 = Rising, 0 = Falling)
+ * 04     Yes     LRCLK Polarity  (1 = High for left, 0 = Low for left)
+ * 03:02  Yes     Reserved - write as zero
+ * 01     No      Data Enable
+ * 00     No      CLK Enable
+ */
+#define I2S_OUT_CFG_REG_UPDATE_MASK   0x3c03ff03  /* set bit = do not modify */
+
+/* Input cfg is same as output, but the FS width is not a valid field */
+#define I2S_IN_CFG_REG_UPDATE_MASK  (I2S_OUT_CFG_REG_UPDATE_MASK | 0x03fc0000)
+
+static void update_ssp_cfg(struct cygnus_aio_port *aio)
+{
+	u32 valid_slots;       /* reg val to program */
+	int bits_per_slot_cmn;
+	int bits_per_slot_in;
+	int bits_per_slot_out;
+
+	u32 ssp_newcfg;
+	u32 ssp_curcfg;
+	u32 ssp_outcfg;
+	u32 ssp_incfg;
+	u32 fsync_width;
+
+	if (aio->port_type == PORT_SPDIF)
+		return;
+
+	/* We encode 16 slots as 0 in the reg */
+	valid_slots = aio->active_slots;
+	if (aio->active_slots == 16)
+		valid_slots = 0;
+
+	/* Slot Width is either 16 or 32 */
+	bits_per_slot_cmn = 0;     /* Default to 32 bits */
+	if (aio->slot_width <= 16)
+		bits_per_slot_cmn = 1;
+
+	bits_per_slot_in = bits_per_slot_cmn;
+	bits_per_slot_out = bits_per_slot_cmn;
+
+	ssp_newcfg = 0;
+
+	if (aio->mode == CYGNUS_SSPMODE_TDM) {
+		ssp_newcfg |= BIT(I2S_OUT_CFGX_TDM_MODE);
+		if (aio->fsync_width == -1)
+			fsync_width = 1;
+		else
+			fsync_width = aio->fsync_width;
+
+		ssp_newcfg |= (fsync_width << I2S_OUT_CFGX_FSYNC_WIDTH);
+	}
+
+	if (aio->is_slave)
+		ssp_newcfg |= BIT(I2S_OUT_CFGX_SLAVE_MODE);
+	else
+		ssp_newcfg &= ~BIT(I2S_OUT_CFGX_SLAVE_MODE);
+
+	if (aio->mode == CYGNUS_SSPMODE_I2S) {
+		ssp_newcfg |= BIT(I2S_OUT_CFGX_DATA_ALIGNMENT);
+		ssp_newcfg |= BIT(I2S_OUT_CFGX_FSYNC_WIDTH);
+	} else {
+		if (aio->fs_delay == 0)
+			ssp_newcfg &= ~BIT(I2S_OUT_CFGX_DATA_ALIGNMENT);
+		else
+			ssp_newcfg |= BIT(I2S_OUT_CFGX_DATA_ALIGNMENT);
+	}
+
+	if (aio->invert_bclk)
+		ssp_newcfg |= BIT(I2S_OUT_CFGX_SCLK_POLARITY);
+
+	if (aio->invert_fs)
+		ssp_newcfg |= BIT(I2S_OUT_CFGX_LRCK_POLARITY);
+
+	/*
+	 * SSP in cfg.
+	 * Retain bits we do not want to update, then OR in new bits
+	 * Always set slave mode for Rx formatter.
+	 * The Rx formatter's Slave Mode bit controls if it uses its own
+	 * internal clock or the clock signal that comes from the Slave Mode
+	 * bit set in the Tx formatter (which would be the Tx Formatters
+	 * internal clock or signal from external pin).
+	 */
+	ssp_curcfg = readl(aio->cygaud->i2s_in + aio->regs.i2s_cap_cfg);
+	ssp_incfg = (ssp_curcfg & I2S_IN_CFG_REG_UPDATE_MASK) | ssp_newcfg;
+	ssp_incfg |= BIT(I2S_OUT_CFGX_SLAVE_MODE);
+
+	ssp_incfg &= ~(0xf << I2S_OUT_CFGX_VALID_SLOT);
+	ssp_incfg |= (valid_slots << I2S_OUT_CFGX_VALID_SLOT);
+	ssp_incfg &= ~BIT(I2S_OUT_CFGX_BITS_PER_SLOT);
+	ssp_incfg |= (bits_per_slot_in << I2S_OUT_CFGX_BITS_PER_SLOT);
+
+	writel(ssp_incfg, aio->cygaud->i2s_in + aio->regs.i2s_cap_cfg);
+
+	/*
+	 * SSP out cfg.
+	 * Retain bits we do not want to update, then OR in new bits
+	 */
+	ssp_curcfg = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
+	ssp_outcfg = (ssp_curcfg & I2S_OUT_CFG_REG_UPDATE_MASK) | ssp_newcfg;
+
+	ssp_outcfg &= ~(0xf << I2S_OUT_CFGX_VALID_SLOT);
+	ssp_outcfg |= (valid_slots << I2S_OUT_CFGX_VALID_SLOT);
+	ssp_outcfg &= ~BIT(I2S_OUT_CFGX_BITS_PER_SLOT);
+	ssp_outcfg |= (bits_per_slot_out << I2S_OUT_CFGX_BITS_PER_SLOT);
+
+	writel(ssp_outcfg, aio->cygaud->audio + aio->regs.i2s_cfg);
+}
 
 
 static const struct snd_soc_dai_ops cygnus_ssp_dai_ops = {
diff --git a/sound/soc/bcm/cygnus-ssp.h b/sound/soc/bcm/cygnus-ssp.h
index ad15a00..648321d 100644
--- a/sound/soc/bcm/cygnus-ssp.h
+++ b/sound/soc/bcm/cygnus-ssp.h
@@ -77,7 +77,6 @@ struct cygnus_ssp_regs {
 	u32 bf_destch_cfg;
 	u32 bf_sourcech_ctrl;
 	u32 bf_sourcech_cfg;
-	u32 bf_sourcech_grp;
 };
 
 struct cygnus_audio_clkinfo {
@@ -90,14 +89,21 @@ struct cygnus_aio_port {
 	int mode;
 	bool is_slave;
 	int streams_on;   /* will be 0 if both capture and play are off */
-	int fsync_width;
 	int port_type;
 
+	unsigned int fsync_width;
+	unsigned int fs_delay;
+	bool invert_bclk;
+	bool invert_fs;
+
 	u32 mclk;
 	u32 lrclk;
-	u32 bit_per_frame;
 	u32 pll_clk_num;
 
+	unsigned int slot_width;
+	unsigned int slots_per_frame;
+	unsigned int active_slots;
+
 	struct cygnus_audio *cygaud;
 	struct cygnus_ssp_regs regs;
 
@@ -120,8 +126,6 @@ struct cygnus_audio {
 	void __iomem *i2s_in;
 };
 
-extern int cygnus_ssp_get_mode(struct snd_soc_dai *cpu_dai);
-extern int cygnus_ssp_add_pll_tweak_controls(struct snd_soc_pcm_runtime *rtd);
 extern int cygnus_ssp_set_custom_fsync_width(struct snd_soc_dai *cpu_dai,
 						int len);
 extern int cygnus_soc_platform_register(struct device *dev,
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH 6/9] ASoc: cygnus: Fix problems with multichannel transfers
@ 2017-08-14 22:06   ` Lori Hikichi
  0 siblings, 0 replies; 50+ messages in thread
From: Lori Hikichi @ 2017-08-14 22:06 UTC (permalink / raw)
  To: linux-arm-kernel

Problems were found with multi-channel (4+) TDM transfers. The alignment
of the channels within the frame could shift when starting a new transfer.
In order to implement a fix the register programming sequence needed to
be revised.

Signed-off-by: Lori Hikichi <lori.hikichi@broadcom.com>
---
 sound/soc/bcm/cygnus-ssp.c | 539 ++++++++++++++++++++++++++++++++-------------
 sound/soc/bcm/cygnus-ssp.h |  14 +-
 2 files changed, 394 insertions(+), 159 deletions(-)

diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c
index 5b6e345..5292c04 100644
--- a/sound/soc/bcm/cygnus-ssp.c
+++ b/sound/soc/bcm/cygnus-ssp.c
@@ -121,6 +121,7 @@
 #define I2S_OUT_STREAM_ENA  31
 #define I2S_OUT_STREAM_CFG_GROUP_ID  20
 #define I2S_OUT_STREAM_CFG_CHANNEL_GROUPING  24
+#define I2S_OUT_STREAM_CFG_FCI_ID_MASK  0x3ff
 
 /* AUD_FMM_IOP_IN_I2S_x_CAP */
 #define I2S_IN_STREAM_CFG_CAP_ENA   31
@@ -129,7 +130,11 @@
 /* AUD_FMM_IOP_OUT_I2S_x_I2S_CFG_REG */
 #define I2S_OUT_CFGX_CLK_ENA         0
 #define I2S_OUT_CFGX_DATA_ENABLE     1
+#define I2S_OUT_CFGX_LRCK_POLARITY   4
+#define I2S_OUT_CFGX_SCLK_POLARITY   5
 #define I2S_OUT_CFGX_DATA_ALIGNMENT  6
+#define I2S_OUT_CFGX_BITS_PER_SAMPLE 8
+#define I2S_OUT_CFGX_BIT_PER_SAMPLE_MASK 0x1f
 #define I2S_OUT_CFGX_BITS_PER_SLOT  13
 #define I2S_OUT_CFGX_VALID_SLOT     14
 #define I2S_OUT_CFGX_FSYNC_WIDTH    18
@@ -137,14 +142,27 @@
 #define I2S_OUT_CFGX_SLAVE_MODE     30
 #define I2S_OUT_CFGX_TDM_MODE       31
 
+#define I2S_IN_CFGX_DATA_ALIGNMENT   6
+#define I2S_IN_CFGX_BITS_PER_SAMPLE  8
+#define I2S_IN_CFGX_BIT_PER_SAMPLE_MASK 0x1f
+#define I2S_IN_CFGX_BITS_PER_SLOT   13
+#define I2S_IN_CFGX_VALID_SLOT      14
+#define I2S_IN_CFGX_SLAVE_MODE      30
+#define I2S_IN_CFGX_TDM_MODE        31
+
 /* AUD_FMM_BF_CTRL_SOURCECH_CFGx_REG */
 #define BF_SRC_CFGX_SFIFO_ENA              0
 #define BF_SRC_CFGX_BUFFER_PAIR_ENABLE     1
 #define BF_SRC_CFGX_SAMPLE_CH_MODE         2
 #define BF_SRC_CFGX_SFIFO_SZ_DOUBLE        5
 #define BF_SRC_CFGX_NOT_PAUSE_WHEN_EMPTY  10
+#define BF_SRC_CFGX_SAMPLE_REPEAT_ENABLE  11
 #define BF_SRC_CFGX_BIT_RES               20
 #define BF_SRC_CFGX_PROCESS_SEQ_ID_VALID  31
+#define BF_SRC_CFGX_BITRES_MASK           0x1f
+
+/* AUD_FMM_BF_CTRL_SOURCECH_CTRLx_REG */
+#define BF_SOURCECH_CTRL_PLAY_RUN   0
 
 /* AUD_FMM_BF_CTRL_DESTCH_CFGx_REG */
 #define BF_DST_CFGX_CAP_ENA              0
@@ -154,11 +172,16 @@
 #define BF_DST_CFGX_FCI_ID              12
 #define BF_DST_CFGX_CAP_MODE            24
 #define BF_DST_CFGX_PROC_SEQ_ID_VALID   31
+#define BF_DST_CFGX_BITRES_MASK         0x1f
+
+/* AUD_FMM_BF_CTRL_DESTCH_CTRLX */
+#define BF_DESTCH_CTRLX_CAP_RUN  0x1
 
 /* AUD_FMM_IOP_OUT_SPDIF_xxx */
 #define SPDIF_0_OUT_DITHER_ENA     3
 #define SPDIF_0_OUT_STREAM_ENA    31
 
+#define IOP_LOGIC_RESET_IN_OFFSET(x) ((x) + 7) /* Capture ports offset by 7 */
 
 #define INIT_SSP_REGS(num) (struct cygnus_ssp_regs){ \
 		.i2s_stream_cfg = OUT_I2S_ ##num## _STREAM_CFG_OFFSET, \
@@ -169,8 +192,7 @@
 		.bf_destch_ctrl = BF_DST_CTRL ##num## _OFFSET, \
 		.bf_destch_cfg = BF_DST_CFG ##num## _OFFSET, \
 		.bf_sourcech_ctrl = BF_SRC_CTRL ##num## _OFFSET, \
-		.bf_sourcech_cfg = BF_SRC_CFG ##num## _OFFSET, \
-		.bf_sourcech_grp = BF_SRC_GRP ##num## _OFFSET \
+		.bf_sourcech_cfg = BF_SRC_CFG ##num## _OFFSET \
 }
 
 #define CYGNUS_RATE_MIN     8000
@@ -189,6 +211,8 @@
 	.list = cygnus_rates,
 };
 
+static void update_ssp_cfg(struct cygnus_aio_port *aio);
+
 static struct cygnus_aio_port *cygnus_dai_get_portinfo(struct snd_soc_dai *dai)
 {
 	struct cygnus_audio *cygaud = snd_soc_dai_get_drvdata(dai);
@@ -201,15 +225,17 @@ static int audio_ssp_init_portregs(struct cygnus_aio_port *aio)
 	u32 value, fci_id;
 	int status = 0;
 
+	/* Set Group ID */
+	writel(0, aio->cygaud->audio + BF_SRC_GRP0_OFFSET);
+	writel(1, aio->cygaud->audio + BF_SRC_GRP1_OFFSET);
+	writel(2, aio->cygaud->audio + BF_SRC_GRP2_OFFSET);
+	writel(3, aio->cygaud->audio + BF_SRC_GRP3_OFFSET);
+
 	switch (aio->port_type) {
 	case PORT_TDM:
 		value = readl(aio->cygaud->audio + aio->regs.i2s_stream_cfg);
 		value &= ~I2S_STREAM_CFG_MASK;
 
-		/* Set Group ID */
-		writel(aio->portnum,
-			aio->cygaud->audio + aio->regs.bf_sourcech_grp);
-
 		/* Configure the AUD_FMM_IOP_OUT_I2S_x_STREAM_CFG reg */
 		value |= aio->portnum << I2S_OUT_STREAM_CFG_GROUP_ID;
 		value |= aio->portnum; /* FCI ID is the port num */
@@ -219,6 +245,7 @@ static int audio_ssp_init_portregs(struct cygnus_aio_port *aio)
 		/* Configure the AUD_FMM_BF_CTRL_SOURCECH_CFGX reg */
 		value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
 		value &= ~BIT(BF_SRC_CFGX_NOT_PAUSE_WHEN_EMPTY);
+		value &= ~BIT(BF_SRC_CFGX_SAMPLE_REPEAT_ENABLE);
 		value |= BIT(BF_SRC_CFGX_SFIFO_SZ_DOUBLE);
 		value |= BIT(BF_SRC_CFGX_PROCESS_SEQ_ID_VALID);
 		writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
@@ -247,8 +274,6 @@ static int audio_ssp_init_portregs(struct cygnus_aio_port *aio)
 		writel(value, aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
 		break;
 	case PORT_SPDIF:
-		writel(aio->portnum, aio->cygaud->audio + BF_SRC_GRP3_OFFSET);
-
 		value = readl(aio->cygaud->audio + SPDIF_CTRL_OFFSET);
 		value |= BIT(SPDIF_0_OUT_DITHER_ENA);
 		writel(value, aio->cygaud->audio + SPDIF_CTRL_OFFSET);
@@ -287,17 +312,35 @@ static void audio_ssp_in_enable(struct cygnus_aio_port *aio)
 	value |= BIT(BF_DST_CFGX_CAP_ENA);
 	writel(value, aio->cygaud->audio + aio->regs.bf_destch_cfg);
 
-	writel(0x1, aio->cygaud->audio + aio->regs.bf_destch_ctrl);
-
-	value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
-	value |= BIT(I2S_OUT_CFGX_CLK_ENA);
-	value |= BIT(I2S_OUT_CFGX_DATA_ENABLE);
-	writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
+	/*
+	 * DATA_ENABLE need to be set even if doing capture.
+	 * Subsequent Tx will fail if this is not done.
+	 */
+	if (!aio->streams_on) {
+		value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
+		value |= BIT(I2S_OUT_CFGX_CLK_ENA);
+		value |= BIT(I2S_OUT_CFGX_DATA_ENABLE);
+		writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
+	}
 
 	value = readl(aio->cygaud->i2s_in + aio->regs.i2s_cap_stream_cfg);
 	value |= BIT(I2S_IN_STREAM_CFG_CAP_ENA);
 	writel(value, aio->cygaud->i2s_in + aio->regs.i2s_cap_stream_cfg);
 
+	/* Enable input portion of block */
+	udelay(10);
+
+	/*
+	 * The input port may or may not be held in reset. Always clear
+	 * the reset. This will be benign if the port is not in reset.
+	 */
+	value = readl(aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+	value &= ~BIT(IOP_LOGIC_RESET_IN_OFFSET(aio->portnum));
+	writel(value, aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+
+	writel(BF_DESTCH_CTRLX_CAP_RUN,
+		aio->cygaud->audio + aio->regs.bf_destch_ctrl);
+
 	aio->streams_on |= CAPTURE_STREAM_MASK;
 }
 
@@ -305,25 +348,50 @@ static void audio_ssp_in_disable(struct cygnus_aio_port *aio)
 {
 	u32 value;
 
+	value = readl(aio->cygaud->audio + aio->regs.bf_destch_cfg);
+	value &= ~BIT(BF_DST_CFGX_CAP_ENA);
+	writel(value, aio->cygaud->audio + aio->regs.bf_destch_cfg);
+
 	value = readl(aio->cygaud->i2s_in + aio->regs.i2s_cap_stream_cfg);
 	value &= ~BIT(I2S_IN_STREAM_CFG_CAP_ENA);
 	writel(value, aio->cygaud->i2s_in + aio->regs.i2s_cap_stream_cfg);
 
 	aio->streams_on &= ~CAPTURE_STREAM_MASK;
 
+	writel(0x0, aio->cygaud->audio + aio->regs.bf_destch_ctrl);
+
+	/*
+	 * Put input portion of port in reset.
+	 * Clears residual data (32 bits) from internal formatter buffer
+	 * BIT_CLOCK must be present for this to take effect.  For Cygnus
+	 * in slave mode this means we must master after Cygnus port
+	 */
+	/*
+	 * TDM Slave Rx needs to toggle this reset.
+	 * See comment in cygnus_ssp_hw_params() about JIRA-1312.
+	 * TDM Master Rx also needs this fix
+	 *   32 bit transfers of fully populated TDM frames will have every
+	 *   transfer after the first with misaligned channels.
+	 *
+	 */
+	if (aio->mode == CYGNUS_SSPMODE_TDM) {
+		value = readl(aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+		value |= BIT(IOP_LOGIC_RESET_IN_OFFSET(aio->portnum));
+		writel(value, aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+	}
+
 	/* If both playback and capture are off */
 	if (!aio->streams_on) {
+		/*
+		 * Add small delay before turning off clock
+		 * Need 1 bit clock tick for INIT_LOGIC to activate
+		 */
+		udelay(10);
 		value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
 		value &= ~BIT(I2S_OUT_CFGX_CLK_ENA);
 		value &= ~BIT(I2S_OUT_CFGX_DATA_ENABLE);
 		writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
 	}
-
-	writel(0x0, aio->cygaud->audio + aio->regs.bf_destch_ctrl);
-
-	value = readl(aio->cygaud->audio + aio->regs.bf_destch_cfg);
-	value &= ~BIT(BF_DST_CFGX_CAP_ENA);
-	writel(value, aio->cygaud->audio + aio->regs.bf_destch_cfg);
 }
 
 static int audio_ssp_out_enable(struct cygnus_aio_port *aio)
@@ -334,19 +402,33 @@ static int audio_ssp_out_enable(struct cygnus_aio_port *aio)
 	switch (aio->port_type) {
 	case PORT_TDM:
 		value = readl(aio->cygaud->audio + aio->regs.i2s_stream_cfg);
-		value |= BIT(I2S_OUT_STREAM_ENA);
+		value &= ~(I2S_OUT_STREAM_CFG_FCI_ID_MASK);
+		value |= aio->portnum;
 		writel(value, aio->cygaud->audio + aio->regs.i2s_stream_cfg);
 
-		writel(1, aio->cygaud->audio + aio->regs.bf_sourcech_ctrl);
+		value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		value |= BIT(BF_SRC_CFGX_SFIFO_ENA);
+		writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+
+		writel(BIT(BF_SOURCECH_CTRL_PLAY_RUN),
+			aio->cygaud->audio + aio->regs.bf_sourcech_ctrl);
+
+		value = readl(aio->cygaud->audio + aio->regs.i2s_stream_cfg);
+		value |= BIT(I2S_OUT_STREAM_ENA);
+		writel(value, aio->cygaud->audio + aio->regs.i2s_stream_cfg);
 
 		value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
 		value |= BIT(I2S_OUT_CFGX_CLK_ENA);
 		value |= BIT(I2S_OUT_CFGX_DATA_ENABLE);
 		writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
 
-		value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
-		value |= BIT(BF_SRC_CFGX_SFIFO_ENA);
-		writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		/*
+		 * The output port may or may not be in reset. Always clear
+		 * the reset. This will be benign if the port is not in reset.
+		 */
+		value = readl(aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+		value &= ~BIT(aio->portnum);
+		writel(value, aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
 
 		aio->streams_on |= PLAYBACK_STREAM_MASK;
 		break;
@@ -355,7 +437,8 @@ static int audio_ssp_out_enable(struct cygnus_aio_port *aio)
 		value |= 0x3;
 		writel(value, aio->cygaud->audio + SPDIF_FORMAT_CFG_OFFSET);
 
-		writel(1, aio->cygaud->audio + aio->regs.bf_sourcech_ctrl);
+		writel(BIT(BF_SOURCECH_CTRL_PLAY_RUN),
+			aio->cygaud->audio + aio->regs.bf_sourcech_ctrl);
 
 		value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
 		value |= BIT(BF_SRC_CFGX_SFIFO_ENA);
@@ -379,13 +462,17 @@ static int audio_ssp_out_disable(struct cygnus_aio_port *aio)
 	case PORT_TDM:
 		aio->streams_on &= ~PLAYBACK_STREAM_MASK;
 
-		/* If both playback and capture are off */
-		if (!aio->streams_on) {
-			value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
-			value &= ~BIT(I2S_OUT_CFGX_CLK_ENA);
-			value &= ~BIT(I2S_OUT_CFGX_DATA_ENABLE);
-			writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
-		}
+		/* Set the FCI ID to INVALID */
+		value = readl(aio->cygaud->audio + aio->regs.i2s_stream_cfg);
+		value |= 0x3ff;
+		writel(value, aio->cygaud->audio + aio->regs.i2s_stream_cfg);
+
+		/*
+		 * We want to wait enough time for 2 LRCLK.
+		 * At 8 kHz framerate, this would be 250 us.
+		 * Set delay to 300 us to be safe.
+		 */
+		udelay(300);
 
 		/* set group_sync_dis = 1 */
 		value = readl(aio->cygaud->audio + BF_SRC_GRP_SYNC_DIS_OFFSET);
@@ -403,16 +490,27 @@ static int audio_ssp_out_disable(struct cygnus_aio_port *aio)
 		value &= ~BIT(aio->portnum);
 		writel(value, aio->cygaud->audio + BF_SRC_GRP_SYNC_DIS_OFFSET);
 
-		value = readl(aio->cygaud->audio + aio->regs.i2s_stream_cfg);
-		value &= ~BIT(I2S_OUT_STREAM_ENA);
-		writel(value, aio->cygaud->audio + aio->regs.i2s_stream_cfg);
+		/*
+		 * We want to wait enough time for 1 LRCLK.
+		 * At 8 kHz framerate, this would be 125 us.
+		 * Set delay to 175 us to be safe.
+		 */
+		udelay(175);
+
+		if (aio->is_slave && (aio->mode == CYGNUS_SSPMODE_TDM)) {
+			value = readl(aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+			value |= BIT(aio->portnum);
+			writel(value, aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+		}
+
+		/* If both playback and capture are off */
+		if (aio->streams_on == 0) {
+			value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
+			value &= ~BIT(I2S_OUT_CFGX_DATA_ENABLE);
+			value &= ~BIT(I2S_OUT_CFGX_CLK_ENA);
+			writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
+		}
 
-		/* IOP SW INIT on OUT_I2S_x */
-		value = readl(aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
-		value |= BIT(aio->portnum);
-		writel(value, aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
-		value &= ~BIT(aio->portnum);
-		writel(value, aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
 		break;
 	case PORT_SPDIF:
 		value = readl(aio->cygaud->audio + SPDIF_FORMAT_CFG_OFFSET);
@@ -439,10 +537,12 @@ static int cygnus_ssp_set_clocks(struct cygnus_aio_port *aio)
 	u32 mask = 0xf;
 	u32 sclk;
 	u32 mclk_rate;
+	unsigned int bits_per_frame;
 	unsigned int bit_rate;
 	unsigned int ratio;
 
-	bit_rate = aio->bit_per_frame * aio->lrclk;
+	bits_per_frame = aio->slots_per_frame * aio->slot_width;
+	bit_rate = bits_per_frame * aio->lrclk;
 
 	/*
 	 * Check if the bit clock can be generated from the given MCLK.
@@ -468,14 +568,14 @@ static int cygnus_ssp_set_clocks(struct cygnus_aio_port *aio)
 		dev_err(aio->cygaud->dev,
 			"Invalid combination of MCLK and BCLK\n");
 		dev_err(aio->cygaud->dev, "lrclk = %u, bits/frame = %u, mclk = %u\n",
-			aio->lrclk, aio->bit_per_frame, aio->mclk);
+			aio->lrclk, bits_per_frame, aio->mclk);
 		return -EINVAL;
 	}
 
 	/* Set sclk rate */
 	switch (aio->port_type) {
 	case PORT_TDM:
-		sclk = aio->bit_per_frame;
+		sclk = bits_per_frame;
 		if (sclk == 512)
 			sclk = 0;
 
@@ -505,7 +605,7 @@ static int cygnus_ssp_set_clocks(struct cygnus_aio_port *aio)
 
 	dev_dbg(aio->cygaud->dev, "mclk cfg reg = 0x%x\n", value);
 	dev_dbg(aio->cygaud->dev, "bits per frame = %u, mclk = %u Hz, lrclk = %u Hz\n",
-			aio->bit_per_frame, aio->mclk, aio->lrclk);
+			bits_per_frame, aio->mclk, aio->lrclk);
 	return 0;
 }
 
@@ -514,9 +614,9 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 				 struct snd_soc_dai *dai)
 {
 	struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai);
-	int rate, bitres;
+	int rate, bitres, bits_per_sample;
 	u32 value;
-	u32 mask = 0x1f;
+	u32 mask;
 	int ret = 0;
 
 	dev_dbg(aio->cygaud->dev, "%s port = %d\n", __func__, aio->portnum);
@@ -529,6 +629,7 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 
 	switch (aio->mode) {
 	case CYGNUS_SSPMODE_TDM:
+		/* It's expected that set_dai_tdm_slot has been called */
 		if ((rate == 192000) && (params_channels(params) > 4)) {
 			dev_err(aio->cygaud->dev, "Cannot run %d channels at %dHz\n",
 				params_channels(params), rate);
@@ -536,7 +637,15 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 		}
 		break;
 	case CYGNUS_SSPMODE_I2S:
-		aio->bit_per_frame = 64; /* I2S must be 64 bit per frame */
+		if (params_channels(params) != 2) {
+			dev_err(aio->cygaud->dev, "i2s mode must use 2 channels\n");
+			return -EINVAL;
+		}
+
+		aio->active_slots = 2;
+		aio->slots_per_frame = 2;
+		aio->slot_width = 32; /* Use 64Fs */
+
 		break;
 	default:
 		dev_err(aio->cygaud->dev,
@@ -553,26 +662,36 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 		switch (params_format(params)) {
 		case SNDRV_PCM_FORMAT_S16_LE:
 			bitres = 16;
+			bits_per_sample = 16;
 			break;
 
 		case SNDRV_PCM_FORMAT_S32_LE:
-			/* 32 bit mode is coded as 0 */
-			bitres = 0;
+			bitres = 0; /* 32 bit mode is coded as 0 */
+			bits_per_sample = 24; /* Only 24 valid bits */
 			break;
 
 		default:
 			return -EINVAL;
 		}
 
+		mask = BF_SRC_CFGX_BITRES_MASK;
 		value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
 		value &= ~(mask << BF_SRC_CFGX_BIT_RES);
 		value |= (bitres << BF_SRC_CFGX_BIT_RES);
 		writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
 
+		/* Only needed for LSB mode, ignored for MSB */
+		mask = I2S_OUT_CFGX_BIT_PER_SAMPLE_MASK;
+		value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
+		value &= ~(mask << I2S_OUT_CFGX_BITS_PER_SAMPLE);
+		value |= (bits_per_sample << I2S_OUT_CFGX_BITS_PER_SAMPLE);
+		writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
 	} else {
 
 		switch (params_format(params)) {
 		case SNDRV_PCM_FORMAT_S16_LE:
+			bits_per_sample = 16;
+
 			value = readl(aio->cygaud->audio +
 					aio->regs.bf_destch_cfg);
 			value |= BIT(BF_DST_CFGX_CAP_MODE);
@@ -581,6 +700,8 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 			break;
 
 		case SNDRV_PCM_FORMAT_S32_LE:
+			bits_per_sample = 24; /* Only 24 valid bits */
+
 			value = readl(aio->cygaud->audio +
 					aio->regs.bf_destch_cfg);
 			value &= ~BIT(BF_DST_CFGX_CAP_MODE);
@@ -591,12 +712,52 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 		default:
 			return -EINVAL;
 		}
+
+		/* Used for both LSB and MSB modes */
+		mask = I2S_IN_CFGX_BIT_PER_SAMPLE_MASK;
+		value = readl(aio->cygaud->i2s_in + aio->regs.i2s_cap_cfg);
+		value &= ~(mask << I2S_IN_CFGX_BITS_PER_SAMPLE);
+		value |= (bits_per_sample << I2S_IN_CFGX_BITS_PER_SAMPLE);
+		writel(value, aio->cygaud->i2s_in + aio->regs.i2s_cap_cfg);
 	}
 
-	aio->lrclk = rate;
+	/* Put output port into reset prior to configuring.
+	 * This action is a workaround for couple situations:
+	 *   1) JIRA-1312: 16-bit TDM Slave Tx problem
+	 *      If the port is configured as 16-bit slave and
+	 *      both CLK_ENA and DATA_ENABLE bits are off then the port will
+	 *      fail to Tx.  Therefore, we hold port in reset until the
+	 *      we are ready to enable
+	 *   2) The TDM Slave Tx stream will be misaligned on the first
+	 *      transfer after boot/reset (both 16 and 32 bit modes).
+	 *      Applying reset will workaround this problem.
+	 */
+	if (aio->streams_on == 0) {
+		if (aio->is_slave && (aio->mode == CYGNUS_SSPMODE_TDM)) {
+			/*
+			 * Need to do this LOGIC reset after boot/reset
+			 * because it puts the logic in a slightly different
+			 * than hard reset. In this way the chip logic will be
+			 * in the same state for our first transfer as it is
+			 * every transfer.
+			 */
+			value = readl(aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+			value |= BIT(aio->portnum);
+			writel(value, aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+
+			value = readl(aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+			value |= BIT(IOP_LOGIC_RESET_IN_OFFSET(aio->portnum));
+			writel(value, aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+		}
+
+		if (aio->port_type != PORT_SPDIF)
+			update_ssp_cfg(aio);
 
-	if (!aio->is_slave)
-		ret = cygnus_ssp_set_clocks(aio);
+		aio->lrclk = rate;
+
+		if (!aio->is_slave)
+			ret = cygnus_ssp_set_clocks(aio);
+	}
 
 	return ret;
 }
@@ -703,28 +864,6 @@ static void cygnus_ssp_shutdown(struct snd_pcm_substream *substream,
 	clk_disable_unprepare(aio->clk_info.audio_clk);
 }
 
-/*
- * Bit    Update  Notes
- * 31     Yes     TDM Mode        (1 = TDM, 0 = i2s)
- * 30     Yes     Slave Mode	  (1 = Slave, 0 = Master)
- * 29:26  No      Sclks per frame
- * 25:18  Yes     FS Width
- * 17:14  No      Valid Slots
- * 13     No      Bits		  (1 = 16 bits, 0 = 32 bits)
- * 12:08  No     Bits per samp
- * 07     Yes     Justifcation    (1 = LSB, 0 = MSB)
- * 06     Yes     Alignment       (1 = Delay 1 clk, 0 = no delay
- * 05     Yes     SCLK polarity   (1 = Rising, 0 = Falling)
- * 04     Yes     LRCLK Polarity  (1 = High for left, 0 = Low for left)
- * 03:02  Yes     Reserved - write as zero
- * 01     No      Data Enable
- * 00     No      CLK Enable
- */
-#define I2S_OUT_CFG_REG_UPDATE_MASK   0x3C03FF03
-
-/* Input cfg is same as output, but the FS width is not a valid field */
-#define I2S_IN_CFG_REG_UPDATE_MASK  (I2S_OUT_CFG_REG_UPDATE_MASK | 0x03FC0000)
-
 int cygnus_ssp_set_custom_fsync_width(struct snd_soc_dai *cpu_dai, int len)
 {
 	struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(cpu_dai);
@@ -740,10 +879,6 @@ int cygnus_ssp_set_custom_fsync_width(struct snd_soc_dai *cpu_dai, int len)
 static int cygnus_ssp_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 {
 	struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(cpu_dai);
-	u32 ssp_curcfg;
-	u32 ssp_newcfg;
-	u32 ssp_outcfg;
-	u32 ssp_incfg;
 	u32 val;
 	u32 mask;
 
@@ -752,15 +887,11 @@ static int cygnus_ssp_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 	if (aio->port_type == PORT_SPDIF)
 		return -EINVAL;
 
-	ssp_newcfg = 0;
-
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBM_CFM:
-		ssp_newcfg |= BIT(I2S_OUT_CFGX_SLAVE_MODE);
 		aio->is_slave = 1;
 		break;
 	case SND_SOC_DAIFMT_CBS_CFS:
-		ssp_newcfg &= ~BIT(I2S_OUT_CFGX_SLAVE_MODE);
 		aio->is_slave = 0;
 		break;
 	default:
@@ -769,25 +900,24 @@ static int cygnus_ssp_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 	case SND_SOC_DAIFMT_I2S:
-		ssp_newcfg |= BIT(I2S_OUT_CFGX_DATA_ALIGNMENT);
-		ssp_newcfg |= BIT(I2S_OUT_CFGX_FSYNC_WIDTH);
+		aio->fs_delay = 1;
 		aio->mode = CYGNUS_SSPMODE_I2S;
 		break;
 
 	case SND_SOC_DAIFMT_DSP_A:
 	case SND_SOC_DAIFMT_DSP_B:
-		ssp_newcfg |= BIT(I2S_OUT_CFGX_TDM_MODE);
-
 		/* DSP_A = data after FS, DSP_B = data during FS */
 		if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_DSP_A)
-			ssp_newcfg |= BIT(I2S_OUT_CFGX_DATA_ALIGNMENT);
-
-		if ((aio->fsync_width > 0) && (aio->fsync_width < 256))
-			ssp_newcfg |=
-				(aio->fsync_width << I2S_OUT_CFGX_FSYNC_WIDTH);
-		else
-			ssp_newcfg |= BIT(I2S_OUT_CFGX_FSYNC_WIDTH);
-
+			aio->fs_delay = 1;
+		else {
+			if (aio->is_slave) {
+				dev_err(aio->cygaud->dev,
+				"%s DSP_B mode not supported while slave.\n",
+					__func__);
+				return -EINVAL;
+			}
+			aio->fs_delay = 0;
+		}
 		aio->mode = CYGNUS_SSPMODE_TDM;
 		break;
 
@@ -795,21 +925,36 @@ static int cygnus_ssp_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 		return -EINVAL;
 	}
 
-	/*
-	 * SSP out cfg.
-	 * Retain bits we do not want to update, then OR in new bits
-	 */
-	ssp_curcfg = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
-	ssp_outcfg = (ssp_curcfg & I2S_OUT_CFG_REG_UPDATE_MASK) | ssp_newcfg;
-	writel(ssp_outcfg, aio->cygaud->audio + aio->regs.i2s_cfg);
+	/* We must be i2s master to invert any clock */
+	if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) {
+		if (aio->is_slave || (aio->mode == CYGNUS_SSPMODE_TDM)) {
+			dev_err(aio->cygaud->dev,
+			"%s Can only invert clocks in i2s master mode\n",
+				__func__);
+			return -EINVAL;
+		}
+	}
 
-	/*
-	 * SSP in cfg.
-	 * Retain bits we do not want to update, then OR in new bits
-	 */
-	ssp_curcfg = readl(aio->cygaud->i2s_in + aio->regs.i2s_cap_cfg);
-	ssp_incfg = (ssp_curcfg & I2S_IN_CFG_REG_UPDATE_MASK) | ssp_newcfg;
-	writel(ssp_incfg, aio->cygaud->i2s_in + aio->regs.i2s_cap_cfg);
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_IB_NF:
+		aio->invert_bclk = true;
+		aio->invert_fs = false;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		aio->invert_bclk = false;
+		aio->invert_fs = true;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		aio->invert_bclk = true;
+		aio->invert_fs = true;
+		break;
+	case SND_SOC_DAIFMT_NB_NF:
+		aio->invert_bclk = false;
+		aio->invert_fs = false;
+		break;
+	default:
+		return -EINVAL;
+	}
 
 	val = readl(aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
 
@@ -871,12 +1016,10 @@ static int cygnus_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
 	unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
 {
 	struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(cpu_dai);
-	u32 value;
-	int bits_per_slot = 0;     /* default to 32-bits per slot */
-	int frame_bits;
 	unsigned int active_slots;
+	unsigned int bits_per_frame;
 	bool found = false;
-	int i;
+	unsigned int i;
 
 	if (tx_mask != rx_mask) {
 		dev_err(aio->cygaud->dev,
@@ -886,35 +1029,20 @@ static int cygnus_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
 
 	active_slots = hweight32(tx_mask);
 
-	if ((active_slots < 0) || (active_slots > 16))
+	if ((active_slots == 0) || (active_slots > 16))
 		return -EINVAL;
 
 	/* Slot value must be even */
 	if (active_slots % 2)
 		return -EINVAL;
 
-	/* We encode 16 slots as 0 in the reg */
-	if (active_slots == 16)
-		active_slots = 0;
-
-	/* Slot Width is either 16 or 32 */
-	switch (slot_width) {
-	case 16:
-		bits_per_slot = 1;
-		break;
-	case 32:
-		bits_per_slot = 0;
-		break;
-	default:
-		bits_per_slot = 0;
-		dev_warn(aio->cygaud->dev,
-			"%s Defaulting Slot Width to 32\n", __func__);
-	}
+	if ((slot_width != 16) && (slot_width != 32))
+		return -EINVAL;
 
-	frame_bits = slots * slot_width;
+	bits_per_frame = slots * slot_width;
 
 	for (i = 0; i < ARRAY_SIZE(ssp_valid_tdm_framesize); i++) {
-		if (ssp_valid_tdm_framesize[i] == frame_bits) {
+		if (ssp_valid_tdm_framesize[i] == bits_per_frame) {
 			found = true;
 			break;
 		}
@@ -923,31 +1051,16 @@ static int cygnus_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
 	if (!found) {
 		dev_err(aio->cygaud->dev,
 			"%s In TDM mode, frame bits INVALID (%d)\n",
-			__func__, frame_bits);
+			__func__, bits_per_frame);
 		return -EINVAL;
 	}
 
-	aio->bit_per_frame = frame_bits;
+	aio->active_slots = active_slots;
+	aio->slot_width = slot_width;
+	aio->slots_per_frame = slots;
 
 	dev_dbg(aio->cygaud->dev, "%s active_slots %u, bits per frame %d\n",
-			__func__, active_slots, frame_bits);
-
-	/* Set capture side of ssp port */
-	value = readl(aio->cygaud->i2s_in + aio->regs.i2s_cap_cfg);
-	value &= ~(0xf << I2S_OUT_CFGX_VALID_SLOT);
-	value |= (active_slots << I2S_OUT_CFGX_VALID_SLOT);
-	value &= ~BIT(I2S_OUT_CFGX_BITS_PER_SLOT);
-	value |= (bits_per_slot << I2S_OUT_CFGX_BITS_PER_SLOT);
-	writel(value, aio->cygaud->i2s_in + aio->regs.i2s_cap_cfg);
-
-	/* Set playback side of ssp port */
-	value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
-	value &= ~(0xf << I2S_OUT_CFGX_VALID_SLOT);
-	value |= (active_slots << I2S_OUT_CFGX_VALID_SLOT);
-	value &= ~BIT(I2S_OUT_CFGX_BITS_PER_SLOT);
-	value |= (bits_per_slot << I2S_OUT_CFGX_BITS_PER_SLOT);
-	writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
-
+			__func__, aio->active_slots, bits_per_frame);
 	return 0;
 }
 
@@ -978,6 +1091,124 @@ static int cygnus_ssp_set_pll(struct snd_soc_dai *cpu_dai, int pll_id,
 	return ret;
 }
 
+/*
+ * Bit    Update  Notes
+ * 31     Yes     TDM Mode        (1 = TDM, 0 = i2s)
+ * 30     Yes     Slave Mode      (1 = Slave, 0 = Master)
+ * 29:26  No      Sclks per frame
+ * 25:18  Yes     FS Width
+ * 17:14  No      Valid Slots
+ * 13     No      Bits            (1 = 16 bits, 0 = 32 bits)
+ * 12:08  No      Bits per samp
+ * 07     Yes     Justifcation    (1 = LSB, 0 = MSB)
+ * 06     Yes     Alignment       (1 = Delay 1 clk, 0 = no delay
+ * 05     Yes     SCLK polarity   (1 = Rising, 0 = Falling)
+ * 04     Yes     LRCLK Polarity  (1 = High for left, 0 = Low for left)
+ * 03:02  Yes     Reserved - write as zero
+ * 01     No      Data Enable
+ * 00     No      CLK Enable
+ */
+#define I2S_OUT_CFG_REG_UPDATE_MASK   0x3c03ff03  /* set bit = do not modify */
+
+/* Input cfg is same as output, but the FS width is not a valid field */
+#define I2S_IN_CFG_REG_UPDATE_MASK  (I2S_OUT_CFG_REG_UPDATE_MASK | 0x03fc0000)
+
+static void update_ssp_cfg(struct cygnus_aio_port *aio)
+{
+	u32 valid_slots;       /* reg val to program */
+	int bits_per_slot_cmn;
+	int bits_per_slot_in;
+	int bits_per_slot_out;
+
+	u32 ssp_newcfg;
+	u32 ssp_curcfg;
+	u32 ssp_outcfg;
+	u32 ssp_incfg;
+	u32 fsync_width;
+
+	if (aio->port_type == PORT_SPDIF)
+		return;
+
+	/* We encode 16 slots as 0 in the reg */
+	valid_slots = aio->active_slots;
+	if (aio->active_slots == 16)
+		valid_slots = 0;
+
+	/* Slot Width is either 16 or 32 */
+	bits_per_slot_cmn = 0;     /* Default to 32 bits */
+	if (aio->slot_width <= 16)
+		bits_per_slot_cmn = 1;
+
+	bits_per_slot_in = bits_per_slot_cmn;
+	bits_per_slot_out = bits_per_slot_cmn;
+
+	ssp_newcfg = 0;
+
+	if (aio->mode == CYGNUS_SSPMODE_TDM) {
+		ssp_newcfg |= BIT(I2S_OUT_CFGX_TDM_MODE);
+		if (aio->fsync_width == -1)
+			fsync_width = 1;
+		else
+			fsync_width = aio->fsync_width;
+
+		ssp_newcfg |= (fsync_width << I2S_OUT_CFGX_FSYNC_WIDTH);
+	}
+
+	if (aio->is_slave)
+		ssp_newcfg |= BIT(I2S_OUT_CFGX_SLAVE_MODE);
+	else
+		ssp_newcfg &= ~BIT(I2S_OUT_CFGX_SLAVE_MODE);
+
+	if (aio->mode == CYGNUS_SSPMODE_I2S) {
+		ssp_newcfg |= BIT(I2S_OUT_CFGX_DATA_ALIGNMENT);
+		ssp_newcfg |= BIT(I2S_OUT_CFGX_FSYNC_WIDTH);
+	} else {
+		if (aio->fs_delay == 0)
+			ssp_newcfg &= ~BIT(I2S_OUT_CFGX_DATA_ALIGNMENT);
+		else
+			ssp_newcfg |= BIT(I2S_OUT_CFGX_DATA_ALIGNMENT);
+	}
+
+	if (aio->invert_bclk)
+		ssp_newcfg |= BIT(I2S_OUT_CFGX_SCLK_POLARITY);
+
+	if (aio->invert_fs)
+		ssp_newcfg |= BIT(I2S_OUT_CFGX_LRCK_POLARITY);
+
+	/*
+	 * SSP in cfg.
+	 * Retain bits we do not want to update, then OR in new bits
+	 * Always set slave mode for Rx formatter.
+	 * The Rx formatter's Slave Mode bit controls if it uses its own
+	 * internal clock or the clock signal that comes from the Slave Mode
+	 * bit set in the Tx formatter (which would be the Tx Formatters
+	 * internal clock or signal from external pin).
+	 */
+	ssp_curcfg = readl(aio->cygaud->i2s_in + aio->regs.i2s_cap_cfg);
+	ssp_incfg = (ssp_curcfg & I2S_IN_CFG_REG_UPDATE_MASK) | ssp_newcfg;
+	ssp_incfg |= BIT(I2S_OUT_CFGX_SLAVE_MODE);
+
+	ssp_incfg &= ~(0xf << I2S_OUT_CFGX_VALID_SLOT);
+	ssp_incfg |= (valid_slots << I2S_OUT_CFGX_VALID_SLOT);
+	ssp_incfg &= ~BIT(I2S_OUT_CFGX_BITS_PER_SLOT);
+	ssp_incfg |= (bits_per_slot_in << I2S_OUT_CFGX_BITS_PER_SLOT);
+
+	writel(ssp_incfg, aio->cygaud->i2s_in + aio->regs.i2s_cap_cfg);
+
+	/*
+	 * SSP out cfg.
+	 * Retain bits we do not want to update, then OR in new bits
+	 */
+	ssp_curcfg = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
+	ssp_outcfg = (ssp_curcfg & I2S_OUT_CFG_REG_UPDATE_MASK) | ssp_newcfg;
+
+	ssp_outcfg &= ~(0xf << I2S_OUT_CFGX_VALID_SLOT);
+	ssp_outcfg |= (valid_slots << I2S_OUT_CFGX_VALID_SLOT);
+	ssp_outcfg &= ~BIT(I2S_OUT_CFGX_BITS_PER_SLOT);
+	ssp_outcfg |= (bits_per_slot_out << I2S_OUT_CFGX_BITS_PER_SLOT);
+
+	writel(ssp_outcfg, aio->cygaud->audio + aio->regs.i2s_cfg);
+}
 
 
 static const struct snd_soc_dai_ops cygnus_ssp_dai_ops = {
diff --git a/sound/soc/bcm/cygnus-ssp.h b/sound/soc/bcm/cygnus-ssp.h
index ad15a00..648321d 100644
--- a/sound/soc/bcm/cygnus-ssp.h
+++ b/sound/soc/bcm/cygnus-ssp.h
@@ -77,7 +77,6 @@ struct cygnus_ssp_regs {
 	u32 bf_destch_cfg;
 	u32 bf_sourcech_ctrl;
 	u32 bf_sourcech_cfg;
-	u32 bf_sourcech_grp;
 };
 
 struct cygnus_audio_clkinfo {
@@ -90,14 +89,21 @@ struct cygnus_aio_port {
 	int mode;
 	bool is_slave;
 	int streams_on;   /* will be 0 if both capture and play are off */
-	int fsync_width;
 	int port_type;
 
+	unsigned int fsync_width;
+	unsigned int fs_delay;
+	bool invert_bclk;
+	bool invert_fs;
+
 	u32 mclk;
 	u32 lrclk;
-	u32 bit_per_frame;
 	u32 pll_clk_num;
 
+	unsigned int slot_width;
+	unsigned int slots_per_frame;
+	unsigned int active_slots;
+
 	struct cygnus_audio *cygaud;
 	struct cygnus_ssp_regs regs;
 
@@ -120,8 +126,6 @@ struct cygnus_audio {
 	void __iomem *i2s_in;
 };
 
-extern int cygnus_ssp_get_mode(struct snd_soc_dai *cpu_dai);
-extern int cygnus_ssp_add_pll_tweak_controls(struct snd_soc_pcm_runtime *rtd);
 extern int cygnus_ssp_set_custom_fsync_width(struct snd_soc_dai *cpu_dai,
 						int len);
 extern int cygnus_soc_platform_register(struct device *dev,
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH 7/9] ASoC: cygnus: Remove set_fmt from SPDIF dai ops
@ 2017-08-14 22:06   ` Lori Hikichi
  0 siblings, 0 replies; 50+ messages in thread
From: Lori Hikichi @ 2017-08-14 22:06 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Mark Rutland, Ray Jui,
	Scott Branden, Jon Mason, bcm-kernel-feedback-list,
	Jaroslav Kysela, Takashi Iwai
  Cc: alsa-devel, devicetree, linux-arm-kernel, linux-kernel, Lori Hikichi

The SPDIF port cannot modify its format so a set_fmt function is not
needed.  Previously, we used a generic set_fmt for all ports and returned
an error code for the SPDIF port.  It is cleaner to not populate the
set_fmt field.

Signed-off-by: Lori Hikichi <lori.hikichi@broadcom.com>
---
 sound/soc/bcm/cygnus-ssp.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c
index 5292c04..e72d8a8 100644
--- a/sound/soc/bcm/cygnus-ssp.c
+++ b/sound/soc/bcm/cygnus-ssp.c
@@ -1222,6 +1222,13 @@ static void update_ssp_cfg(struct cygnus_aio_port *aio)
 	.set_pll	= cygnus_ssp_set_pll,
 };
 
+static const struct snd_soc_dai_ops cygnus_spdif_dai_ops = {
+	.startup	= cygnus_ssp_startup,
+	.shutdown	= cygnus_ssp_shutdown,
+	.trigger	= cygnus_ssp_trigger,
+	.hw_params	= cygnus_ssp_hw_params,
+	.set_sysclk	= cygnus_ssp_set_sysclk,
+};
 
 #define INIT_CPU_DAI(num) { \
 	.name = "cygnus-ssp" #num, \
@@ -1255,9 +1262,9 @@ static void update_ssp_cfg(struct cygnus_aio_port *aio)
 		.channels_max = 2,
 		.rates = SNDRV_PCM_RATE_KNOT,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE |
-			SNDRV_PCM_FMTBIT_S32_LE,
+				SNDRV_PCM_FMTBIT_S32_LE,
 	},
-	.ops = &cygnus_ssp_dai_ops,
+	.ops = &cygnus_spdif_dai_ops,
 };
 
 static struct snd_soc_dai_driver cygnus_ssp_dai[CYGNUS_MAX_PORTS];
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH 7/9] ASoC: cygnus: Remove set_fmt from SPDIF dai ops
@ 2017-08-14 22:06   ` Lori Hikichi
  0 siblings, 0 replies; 50+ messages in thread
From: Lori Hikichi @ 2017-08-14 22:06 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Mark Rutland, Ray Jui,
	Scott Branden, Jon Mason,
	bcm-kernel-feedback-list-dY08KVG/lbpWk0Htik3J/w, Jaroslav Kysela,
	Takashi Iwai
  Cc: alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Lori Hikichi

The SPDIF port cannot modify its format so a set_fmt function is not
needed.  Previously, we used a generic set_fmt for all ports and returned
an error code for the SPDIF port.  It is cleaner to not populate the
set_fmt field.

Signed-off-by: Lori Hikichi <lori.hikichi-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
---
 sound/soc/bcm/cygnus-ssp.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c
index 5292c04..e72d8a8 100644
--- a/sound/soc/bcm/cygnus-ssp.c
+++ b/sound/soc/bcm/cygnus-ssp.c
@@ -1222,6 +1222,13 @@ static void update_ssp_cfg(struct cygnus_aio_port *aio)
 	.set_pll	= cygnus_ssp_set_pll,
 };
 
+static const struct snd_soc_dai_ops cygnus_spdif_dai_ops = {
+	.startup	= cygnus_ssp_startup,
+	.shutdown	= cygnus_ssp_shutdown,
+	.trigger	= cygnus_ssp_trigger,
+	.hw_params	= cygnus_ssp_hw_params,
+	.set_sysclk	= cygnus_ssp_set_sysclk,
+};
 
 #define INIT_CPU_DAI(num) { \
 	.name = "cygnus-ssp" #num, \
@@ -1255,9 +1262,9 @@ static void update_ssp_cfg(struct cygnus_aio_port *aio)
 		.channels_max = 2,
 		.rates = SNDRV_PCM_RATE_KNOT,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE |
-			SNDRV_PCM_FMTBIT_S32_LE,
+				SNDRV_PCM_FMTBIT_S32_LE,
 	},
-	.ops = &cygnus_ssp_dai_ops,
+	.ops = &cygnus_spdif_dai_ops,
 };
 
 static struct snd_soc_dai_driver cygnus_ssp_dai[CYGNUS_MAX_PORTS];
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH 7/9] ASoC: cygnus: Remove set_fmt from SPDIF dai ops
@ 2017-08-14 22:06   ` Lori Hikichi
  0 siblings, 0 replies; 50+ messages in thread
From: Lori Hikichi @ 2017-08-14 22:06 UTC (permalink / raw)
  To: linux-arm-kernel

The SPDIF port cannot modify its format so a set_fmt function is not
needed.  Previously, we used a generic set_fmt for all ports and returned
an error code for the SPDIF port.  It is cleaner to not populate the
set_fmt field.

Signed-off-by: Lori Hikichi <lori.hikichi@broadcom.com>
---
 sound/soc/bcm/cygnus-ssp.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c
index 5292c04..e72d8a8 100644
--- a/sound/soc/bcm/cygnus-ssp.c
+++ b/sound/soc/bcm/cygnus-ssp.c
@@ -1222,6 +1222,13 @@ static void update_ssp_cfg(struct cygnus_aio_port *aio)
 	.set_pll	= cygnus_ssp_set_pll,
 };
 
+static const struct snd_soc_dai_ops cygnus_spdif_dai_ops = {
+	.startup	= cygnus_ssp_startup,
+	.shutdown	= cygnus_ssp_shutdown,
+	.trigger	= cygnus_ssp_trigger,
+	.hw_params	= cygnus_ssp_hw_params,
+	.set_sysclk	= cygnus_ssp_set_sysclk,
+};
 
 #define INIT_CPU_DAI(num) { \
 	.name = "cygnus-ssp" #num, \
@@ -1255,9 +1262,9 @@ static void update_ssp_cfg(struct cygnus_aio_port *aio)
 		.channels_max = 2,
 		.rates = SNDRV_PCM_RATE_KNOT,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE |
-			SNDRV_PCM_FMTBIT_S32_LE,
+				SNDRV_PCM_FMTBIT_S32_LE,
 	},
-	.ops = &cygnus_ssp_dai_ops,
+	.ops = &cygnus_spdif_dai_ops,
 };
 
 static struct snd_soc_dai_driver cygnus_ssp_dai[CYGNUS_MAX_PORTS];
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH 8/9] ASoC: cygnus: Add EXPORT_SYMBOL for helper function
  2017-08-14 22:06 ` Lori Hikichi
@ 2017-08-14 22:06   ` Lori Hikichi
  -1 siblings, 0 replies; 50+ messages in thread
From: Lori Hikichi @ 2017-08-14 22:06 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Mark Rutland, Ray Jui,
	Scott Branden, Jon Mason, bcm-kernel-feedback-list,
	Jaroslav Kysela, Takashi Iwai
  Cc: alsa-devel, devicetree, linux-arm-kernel, linux-kernel, Lori Hikichi

The helper function cygnus_ssp_set_custom_fsync_width() is intended
to be called from an ASoC machine driver, need to export symbol
if using modules.

Signed-off-by: Lori Hikichi <lori.hikichi@broadcom.com>
---
 sound/soc/bcm/cygnus-ssp.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c
index e72d8a8..97bf67a 100644
--- a/sound/soc/bcm/cygnus-ssp.c
+++ b/sound/soc/bcm/cygnus-ssp.c
@@ -875,6 +875,7 @@ int cygnus_ssp_set_custom_fsync_width(struct snd_soc_dai *cpu_dai, int len)
 		return -EINVAL;
 	}
 }
+EXPORT_SYMBOL_GPL(cygnus_ssp_set_custom_fsync_width);
 
 static int cygnus_ssp_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 {
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH 8/9] ASoC: cygnus: Add EXPORT_SYMBOL for helper function
@ 2017-08-14 22:06   ` Lori Hikichi
  0 siblings, 0 replies; 50+ messages in thread
From: Lori Hikichi @ 2017-08-14 22:06 UTC (permalink / raw)
  To: linux-arm-kernel

The helper function cygnus_ssp_set_custom_fsync_width() is intended
to be called from an ASoC machine driver, need to export symbol
if using modules.

Signed-off-by: Lori Hikichi <lori.hikichi@broadcom.com>
---
 sound/soc/bcm/cygnus-ssp.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c
index e72d8a8..97bf67a 100644
--- a/sound/soc/bcm/cygnus-ssp.c
+++ b/sound/soc/bcm/cygnus-ssp.c
@@ -875,6 +875,7 @@ int cygnus_ssp_set_custom_fsync_width(struct snd_soc_dai *cpu_dai, int len)
 		return -EINVAL;
 	}
 }
+EXPORT_SYMBOL_GPL(cygnus_ssp_set_custom_fsync_width);
 
 static int cygnus_ssp_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 {
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH 9/9] ASoC: cygnus: Tidy up of structure access
@ 2017-08-14 22:06   ` Lori Hikichi
  0 siblings, 0 replies; 50+ messages in thread
From: Lori Hikichi @ 2017-08-14 22:06 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Mark Rutland, Ray Jui,
	Scott Branden, Jon Mason, bcm-kernel-feedback-list,
	Jaroslav Kysela, Takashi Iwai
  Cc: alsa-devel, devicetree, linux-arm-kernel, linux-kernel, Lori Hikichi

Adds copies of the frequently accessed io handles to each ports
data structure, making it more convenient to access.  Also, a small
cleanup to the type names used in cygnus_pcm.  None of this should
result in a functional change to the driver.

Signed-off-by: Lori Hikichi <lori.hikichi@broadcom.com>
---
 sound/soc/bcm/cygnus-pcm.c |  50 ++++----
 sound/soc/bcm/cygnus-ssp.c | 298 +++++++++++++++++++++------------------------
 sound/soc/bcm/cygnus-ssp.h |  22 ++--
 3 files changed, 178 insertions(+), 192 deletions(-)

diff --git a/sound/soc/bcm/cygnus-pcm.c b/sound/soc/bcm/cygnus-pcm.c
index d616e096..d82bf55 100644
--- a/sound/soc/bcm/cygnus-pcm.c
+++ b/sound/soc/bcm/cygnus-pcm.c
@@ -329,24 +329,24 @@ static void enable_intr(struct snd_pcm_substream *substream)
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		/* Clear interrupt status before enabling them */
-		writel(clear_mask, aio->cygaud->audio + ESR0_STATUS_CLR_OFFSET);
-		writel(clear_mask, aio->cygaud->audio + ESR1_STATUS_CLR_OFFSET);
-		writel(clear_mask, aio->cygaud->audio + ESR3_STATUS_CLR_OFFSET);
+		writel(clear_mask, aio->audio + ESR0_STATUS_CLR_OFFSET);
+		writel(clear_mask, aio->audio + ESR1_STATUS_CLR_OFFSET);
+		writel(clear_mask, aio->audio + ESR3_STATUS_CLR_OFFSET);
 		/* Unmask the interrupts of the given port*/
-		writel(clear_mask, aio->cygaud->audio + ESR0_MASK_CLR_OFFSET);
-		writel(clear_mask, aio->cygaud->audio + ESR1_MASK_CLR_OFFSET);
-		writel(clear_mask, aio->cygaud->audio + ESR3_MASK_CLR_OFFSET);
+		writel(clear_mask, aio->audio + ESR0_MASK_CLR_OFFSET);
+		writel(clear_mask, aio->audio + ESR1_MASK_CLR_OFFSET);
+		writel(clear_mask, aio->audio + ESR3_MASK_CLR_OFFSET);
 
 		writel(ANY_PLAYBACK_IRQ,
-			aio->cygaud->audio + INTH_R5F_MASK_CLEAR_OFFSET);
+			aio->audio + INTH_R5F_MASK_CLEAR_OFFSET);
 	} else {
-		writel(clear_mask, aio->cygaud->audio + ESR2_STATUS_CLR_OFFSET);
-		writel(clear_mask, aio->cygaud->audio + ESR4_STATUS_CLR_OFFSET);
-		writel(clear_mask, aio->cygaud->audio + ESR2_MASK_CLR_OFFSET);
-		writel(clear_mask, aio->cygaud->audio + ESR4_MASK_CLR_OFFSET);
+		writel(clear_mask, aio->audio + ESR2_STATUS_CLR_OFFSET);
+		writel(clear_mask, aio->audio + ESR4_STATUS_CLR_OFFSET);
+		writel(clear_mask, aio->audio + ESR2_MASK_CLR_OFFSET);
+		writel(clear_mask, aio->audio + ESR4_MASK_CLR_OFFSET);
 
 		writel(ANY_CAPTURE_IRQ,
-			aio->cygaud->audio + INTH_R5F_MASK_CLEAR_OFFSET);
+			aio->audio + INTH_R5F_MASK_CLEAR_OFFSET);
 	}
 
 }
@@ -366,12 +366,12 @@ static void disable_intr(struct snd_pcm_substream *substream)
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		/* Mask the interrupts of the given port*/
-		writel(set_mask, aio->cygaud->audio + ESR0_MASK_SET_OFFSET);
-		writel(set_mask, aio->cygaud->audio + ESR1_MASK_SET_OFFSET);
-		writel(set_mask, aio->cygaud->audio + ESR3_MASK_SET_OFFSET);
+		writel(set_mask, aio->audio + ESR0_MASK_SET_OFFSET);
+		writel(set_mask, aio->audio + ESR1_MASK_SET_OFFSET);
+		writel(set_mask, aio->audio + ESR3_MASK_SET_OFFSET);
 	} else {
-		writel(set_mask, aio->cygaud->audio + ESR2_MASK_SET_OFFSET);
-		writel(set_mask, aio->cygaud->audio + ESR4_MASK_SET_OFFSET);
+		writel(set_mask, aio->audio + ESR2_MASK_SET_OFFSET);
+		writel(set_mask, aio->audio + ESR4_MASK_SET_OFFSET);
 	}
 
 }
@@ -415,13 +415,13 @@ static void cygnus_pcm_period_elapsed(struct snd_pcm_substream *substream)
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		/* Set the ring buffer to full */
-		regval = readl(aio->cygaud->audio + p_rbuf->rdaddr);
+		regval = readl(aio->audio + p_rbuf->rdaddr);
 		regval = regval ^ BIT(31);
-		writel(regval, aio->cygaud->audio + p_rbuf->wraddr);
+		writel(regval, aio->audio + p_rbuf->wraddr);
 	} else {
 		/* Set the ring buffer to empty */
-		regval = readl(aio->cygaud->audio + p_rbuf->wraddr);
-		writel(regval, aio->cygaud->audio + p_rbuf->rdaddr);
+		regval = readl(aio->audio + p_rbuf->wraddr);
+		writel(regval, aio->audio + p_rbuf->rdaddr);
 	}
 }
 
@@ -690,7 +690,7 @@ static int cygnus_pcm_prepare(struct snd_pcm_substream *substream)
 
 	is_play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? 1 : 0;
 
-	ringbuf_set_initial(aio->cygaud->audio, p_rbuf, is_play, start,
+	ringbuf_set_initial(aio->audio, p_rbuf, is_play, start,
 				periodsize, bufsize);
 
 	return ret;
@@ -710,11 +710,11 @@ static snd_pcm_uframes_t cygnus_pcm_pointer(struct snd_pcm_substream *substream)
 	 */
 	p_rbuf = get_ringbuf(substream);
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		cur = readl(aio->cygaud->audio + p_rbuf->rdaddr);
+		cur = readl(aio->audio + p_rbuf->rdaddr);
 	else
-		cur = readl(aio->cygaud->audio + p_rbuf->wraddr);
+		cur = readl(aio->audio + p_rbuf->wraddr);
 
-	base = readl(aio->cygaud->audio + p_rbuf->baseaddr);
+	base = readl(aio->audio + p_rbuf->baseaddr);
 
 	/*
 	 * Mask off the MSB of the rdaddr,wraddr and baseaddr
diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c
index 97bf67a..7535613 100644
--- a/sound/soc/bcm/cygnus-ssp.c
+++ b/sound/soc/bcm/cygnus-ssp.c
@@ -226,78 +226,76 @@ static int audio_ssp_init_portregs(struct cygnus_aio_port *aio)
 	int status = 0;
 
 	/* Set Group ID */
-	writel(0, aio->cygaud->audio + BF_SRC_GRP0_OFFSET);
-	writel(1, aio->cygaud->audio + BF_SRC_GRP1_OFFSET);
-	writel(2, aio->cygaud->audio + BF_SRC_GRP2_OFFSET);
-	writel(3, aio->cygaud->audio + BF_SRC_GRP3_OFFSET);
+	writel(0, aio->audio + BF_SRC_GRP0_OFFSET);
+	writel(1, aio->audio + BF_SRC_GRP1_OFFSET);
+	writel(2, aio->audio + BF_SRC_GRP2_OFFSET);
+	writel(3, aio->audio + BF_SRC_GRP3_OFFSET);
 
 	switch (aio->port_type) {
 	case PORT_TDM:
-		value = readl(aio->cygaud->audio + aio->regs.i2s_stream_cfg);
+		value = readl(aio->audio + aio->regs.i2s_stream_cfg);
 		value &= ~I2S_STREAM_CFG_MASK;
 
 		/* Configure the AUD_FMM_IOP_OUT_I2S_x_STREAM_CFG reg */
 		value |= aio->portnum << I2S_OUT_STREAM_CFG_GROUP_ID;
 		value |= aio->portnum; /* FCI ID is the port num */
 		value |= CH_GRP_STEREO << I2S_OUT_STREAM_CFG_CHANNEL_GROUPING;
-		writel(value, aio->cygaud->audio + aio->regs.i2s_stream_cfg);
+		writel(value, aio->audio + aio->regs.i2s_stream_cfg);
 
 		/* Configure the AUD_FMM_BF_CTRL_SOURCECH_CFGX reg */
-		value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		value = readl(aio->audio + aio->regs.bf_sourcech_cfg);
 		value &= ~BIT(BF_SRC_CFGX_NOT_PAUSE_WHEN_EMPTY);
 		value &= ~BIT(BF_SRC_CFGX_SAMPLE_REPEAT_ENABLE);
 		value |= BIT(BF_SRC_CFGX_SFIFO_SZ_DOUBLE);
 		value |= BIT(BF_SRC_CFGX_PROCESS_SEQ_ID_VALID);
-		writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		writel(value, aio->audio + aio->regs.bf_sourcech_cfg);
 
 		/* Configure the AUD_FMM_IOP_IN_I2S_x_CAP_STREAM_CFG_0 reg */
-		value = readl(aio->cygaud->i2s_in +
-			aio->regs.i2s_cap_stream_cfg);
+		value = readl(aio->i2s_in + aio->regs.i2s_cap_stream_cfg);
 		value &= ~I2S_CAP_STREAM_CFG_MASK;
 		value |= aio->portnum << I2S_IN_STREAM_CFG_0_GROUP_ID;
-		writel(value, aio->cygaud->i2s_in +
-			aio->regs.i2s_cap_stream_cfg);
+		writel(value, aio->i2s_in + aio->regs.i2s_cap_stream_cfg);
 
 		/* Configure the AUD_FMM_BF_CTRL_DESTCH_CFGX_REG_BASE reg */
 		fci_id = CAPTURE_FCI_ID_BASE + aio->portnum;
 
-		value = readl(aio->cygaud->audio + aio->regs.bf_destch_cfg);
+		value = readl(aio->audio + aio->regs.bf_destch_cfg);
 		value |= BIT(BF_DST_CFGX_DFIFO_SZ_DOUBLE);
 		value &= ~BIT(BF_DST_CFGX_NOT_PAUSE_WHEN_FULL);
 		value |= (fci_id << BF_DST_CFGX_FCI_ID);
 		value |= BIT(BF_DST_CFGX_PROC_SEQ_ID_VALID);
-		writel(value, aio->cygaud->audio + aio->regs.bf_destch_cfg);
+		writel(value, aio->audio + aio->regs.bf_destch_cfg);
 
 		/* Enable the transmit pin for this port */
-		value = readl(aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
+		value = readl(aio->audio + AUD_MISC_SEROUT_OE_REG_BASE);
 		value &= ~BIT((aio->portnum * 4) + AUD_MISC_SEROUT_SDAT_OE);
-		writel(value, aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
+		writel(value, aio->audio + AUD_MISC_SEROUT_OE_REG_BASE);
 		break;
 	case PORT_SPDIF:
-		value = readl(aio->cygaud->audio + SPDIF_CTRL_OFFSET);
+		value = readl(aio->audio + SPDIF_CTRL_OFFSET);
 		value |= BIT(SPDIF_0_OUT_DITHER_ENA);
-		writel(value, aio->cygaud->audio + SPDIF_CTRL_OFFSET);
+		writel(value, aio->audio + SPDIF_CTRL_OFFSET);
 
 		/* Enable and set the FCI ID for the SPDIF channel */
-		value = readl(aio->cygaud->audio + SPDIF_STREAM_CFG_OFFSET);
+		value = readl(aio->audio + SPDIF_STREAM_CFG_OFFSET);
 		value &= ~SPDIF_STREAM_CFG_MASK;
 		value |= aio->portnum; /* FCI ID is the port num */
 		value |= BIT(SPDIF_0_OUT_STREAM_ENA);
-		writel(value, aio->cygaud->audio + SPDIF_STREAM_CFG_OFFSET);
+		writel(value, aio->audio + SPDIF_STREAM_CFG_OFFSET);
 
-		value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		value = readl(aio->audio + aio->regs.bf_sourcech_cfg);
 		value &= ~BIT(BF_SRC_CFGX_NOT_PAUSE_WHEN_EMPTY);
 		value |= BIT(BF_SRC_CFGX_SFIFO_SZ_DOUBLE);
 		value |= BIT(BF_SRC_CFGX_PROCESS_SEQ_ID_VALID);
-		writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		writel(value, aio->audio + aio->regs.bf_sourcech_cfg);
 
 		/* Enable the spdif output pin */
-		value = readl(aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
+		value = readl(aio->audio + AUD_MISC_SEROUT_OE_REG_BASE);
 		value &= ~BIT(AUD_MISC_SEROUT_SPDIF_OE);
-		writel(value, aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
+		writel(value, aio->audio + AUD_MISC_SEROUT_OE_REG_BASE);
 		break;
 	default:
-		dev_err(aio->cygaud->dev, "Port not supported\n");
+		dev_err(aio->dev, "Port not supported\n");
 		status = -EINVAL;
 	}
 
@@ -308,24 +306,24 @@ static void audio_ssp_in_enable(struct cygnus_aio_port *aio)
 {
 	u32 value;
 
-	value = readl(aio->cygaud->audio + aio->regs.bf_destch_cfg);
+	value = readl(aio->audio + aio->regs.bf_destch_cfg);
 	value |= BIT(BF_DST_CFGX_CAP_ENA);
-	writel(value, aio->cygaud->audio + aio->regs.bf_destch_cfg);
+	writel(value, aio->audio + aio->regs.bf_destch_cfg);
 
 	/*
 	 * DATA_ENABLE need to be set even if doing capture.
 	 * Subsequent Tx will fail if this is not done.
 	 */
 	if (!aio->streams_on) {
-		value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
+		value = readl(aio->audio + aio->regs.i2s_cfg);
 		value |= BIT(I2S_OUT_CFGX_CLK_ENA);
 		value |= BIT(I2S_OUT_CFGX_DATA_ENABLE);
-		writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
+		writel(value, aio->audio + aio->regs.i2s_cfg);
 	}
 
-	value = readl(aio->cygaud->i2s_in + aio->regs.i2s_cap_stream_cfg);
+	value = readl(aio->i2s_in + aio->regs.i2s_cap_stream_cfg);
 	value |= BIT(I2S_IN_STREAM_CFG_CAP_ENA);
-	writel(value, aio->cygaud->i2s_in + aio->regs.i2s_cap_stream_cfg);
+	writel(value, aio->i2s_in + aio->regs.i2s_cap_stream_cfg);
 
 	/* Enable input portion of block */
 	udelay(10);
@@ -334,12 +332,11 @@ static void audio_ssp_in_enable(struct cygnus_aio_port *aio)
 	 * The input port may or may not be held in reset. Always clear
 	 * the reset. This will be benign if the port is not in reset.
 	 */
-	value = readl(aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+	value = readl(aio->i2s_in + IOP_SW_INIT_LOGIC);
 	value &= ~BIT(IOP_LOGIC_RESET_IN_OFFSET(aio->portnum));
-	writel(value, aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+	writel(value, aio->i2s_in + IOP_SW_INIT_LOGIC);
 
-	writel(BF_DESTCH_CTRLX_CAP_RUN,
-		aio->cygaud->audio + aio->regs.bf_destch_ctrl);
+	writel(BF_DESTCH_CTRLX_CAP_RUN, aio->audio + aio->regs.bf_destch_ctrl);
 
 	aio->streams_on |= CAPTURE_STREAM_MASK;
 }
@@ -348,17 +345,17 @@ static void audio_ssp_in_disable(struct cygnus_aio_port *aio)
 {
 	u32 value;
 
-	value = readl(aio->cygaud->audio + aio->regs.bf_destch_cfg);
+	value = readl(aio->audio + aio->regs.bf_destch_cfg);
 	value &= ~BIT(BF_DST_CFGX_CAP_ENA);
-	writel(value, aio->cygaud->audio + aio->regs.bf_destch_cfg);
+	writel(value, aio->audio + aio->regs.bf_destch_cfg);
 
-	value = readl(aio->cygaud->i2s_in + aio->regs.i2s_cap_stream_cfg);
+	value = readl(aio->i2s_in + aio->regs.i2s_cap_stream_cfg);
 	value &= ~BIT(I2S_IN_STREAM_CFG_CAP_ENA);
-	writel(value, aio->cygaud->i2s_in + aio->regs.i2s_cap_stream_cfg);
+	writel(value, aio->i2s_in + aio->regs.i2s_cap_stream_cfg);
 
 	aio->streams_on &= ~CAPTURE_STREAM_MASK;
 
-	writel(0x0, aio->cygaud->audio + aio->regs.bf_destch_ctrl);
+	writel(0x0, aio->audio + aio->regs.bf_destch_ctrl);
 
 	/*
 	 * Put input portion of port in reset.
@@ -375,9 +372,9 @@ static void audio_ssp_in_disable(struct cygnus_aio_port *aio)
 	 *
 	 */
 	if (aio->mode == CYGNUS_SSPMODE_TDM) {
-		value = readl(aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+		value = readl(aio->i2s_in + IOP_SW_INIT_LOGIC);
 		value |= BIT(IOP_LOGIC_RESET_IN_OFFSET(aio->portnum));
-		writel(value, aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+		writel(value, aio->i2s_in + IOP_SW_INIT_LOGIC);
 	}
 
 	/* If both playback and capture are off */
@@ -387,10 +384,10 @@ static void audio_ssp_in_disable(struct cygnus_aio_port *aio)
 		 * Need 1 bit clock tick for INIT_LOGIC to activate
 		 */
 		udelay(10);
-		value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
+		value = readl(aio->audio + aio->regs.i2s_cfg);
 		value &= ~BIT(I2S_OUT_CFGX_CLK_ENA);
 		value &= ~BIT(I2S_OUT_CFGX_DATA_ENABLE);
-		writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
+		writel(value, aio->audio + aio->regs.i2s_cfg);
 	}
 }
 
@@ -401,52 +398,51 @@ static int audio_ssp_out_enable(struct cygnus_aio_port *aio)
 
 	switch (aio->port_type) {
 	case PORT_TDM:
-		value = readl(aio->cygaud->audio + aio->regs.i2s_stream_cfg);
+		value = readl(aio->audio + aio->regs.i2s_stream_cfg);
 		value &= ~(I2S_OUT_STREAM_CFG_FCI_ID_MASK);
 		value |= aio->portnum;
-		writel(value, aio->cygaud->audio + aio->regs.i2s_stream_cfg);
+		writel(value, aio->audio + aio->regs.i2s_stream_cfg);
 
-		value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		value = readl(aio->audio + aio->regs.bf_sourcech_cfg);
 		value |= BIT(BF_SRC_CFGX_SFIFO_ENA);
-		writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		writel(value, aio->audio + aio->regs.bf_sourcech_cfg);
 
 		writel(BIT(BF_SOURCECH_CTRL_PLAY_RUN),
-			aio->cygaud->audio + aio->regs.bf_sourcech_ctrl);
+			aio->audio + aio->regs.bf_sourcech_ctrl);
 
-		value = readl(aio->cygaud->audio + aio->regs.i2s_stream_cfg);
+		value = readl(aio->audio + aio->regs.i2s_stream_cfg);
 		value |= BIT(I2S_OUT_STREAM_ENA);
-		writel(value, aio->cygaud->audio + aio->regs.i2s_stream_cfg);
+		writel(value, aio->audio + aio->regs.i2s_stream_cfg);
 
-		value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
+		value = readl(aio->audio + aio->regs.i2s_cfg);
 		value |= BIT(I2S_OUT_CFGX_CLK_ENA);
 		value |= BIT(I2S_OUT_CFGX_DATA_ENABLE);
-		writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
+		writel(value, aio->audio + aio->regs.i2s_cfg);
 
 		/*
 		 * The output port may or may not be in reset. Always clear
 		 * the reset. This will be benign if the port is not in reset.
 		 */
-		value = readl(aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+		value = readl(aio->i2s_in + IOP_SW_INIT_LOGIC);
 		value &= ~BIT(aio->portnum);
-		writel(value, aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+		writel(value, aio->i2s_in + IOP_SW_INIT_LOGIC);
 
 		aio->streams_on |= PLAYBACK_STREAM_MASK;
 		break;
 	case PORT_SPDIF:
-		value = readl(aio->cygaud->audio + SPDIF_FORMAT_CFG_OFFSET);
+		value = readl(aio->audio + SPDIF_FORMAT_CFG_OFFSET);
 		value |= 0x3;
-		writel(value, aio->cygaud->audio + SPDIF_FORMAT_CFG_OFFSET);
+		writel(value, aio->audio + SPDIF_FORMAT_CFG_OFFSET);
 
 		writel(BIT(BF_SOURCECH_CTRL_PLAY_RUN),
-			aio->cygaud->audio + aio->regs.bf_sourcech_ctrl);
+			aio->audio + aio->regs.bf_sourcech_ctrl);
 
-		value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		value = readl(aio->audio + aio->regs.bf_sourcech_cfg);
 		value |= BIT(BF_SRC_CFGX_SFIFO_ENA);
-		writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		writel(value, aio->audio + aio->regs.bf_sourcech_cfg);
 		break;
 	default:
-		dev_err(aio->cygaud->dev,
-			"Port not supported %d\n", aio->portnum);
+		dev_err(aio->dev, "Port not supported %d\n", aio->portnum);
 		status = -EINVAL;
 	}
 
@@ -463,9 +459,9 @@ static int audio_ssp_out_disable(struct cygnus_aio_port *aio)
 		aio->streams_on &= ~PLAYBACK_STREAM_MASK;
 
 		/* Set the FCI ID to INVALID */
-		value = readl(aio->cygaud->audio + aio->regs.i2s_stream_cfg);
+		value = readl(aio->audio + aio->regs.i2s_stream_cfg);
 		value |= 0x3ff;
-		writel(value, aio->cygaud->audio + aio->regs.i2s_stream_cfg);
+		writel(value, aio->audio + aio->regs.i2s_stream_cfg);
 
 		/*
 		 * We want to wait enough time for 2 LRCLK.
@@ -475,20 +471,20 @@ static int audio_ssp_out_disable(struct cygnus_aio_port *aio)
 		udelay(300);
 
 		/* set group_sync_dis = 1 */
-		value = readl(aio->cygaud->audio + BF_SRC_GRP_SYNC_DIS_OFFSET);
+		value = readl(aio->audio + BF_SRC_GRP_SYNC_DIS_OFFSET);
 		value |= BIT(aio->portnum);
-		writel(value, aio->cygaud->audio + BF_SRC_GRP_SYNC_DIS_OFFSET);
+		writel(value, aio->audio + BF_SRC_GRP_SYNC_DIS_OFFSET);
 
-		writel(0, aio->cygaud->audio + aio->regs.bf_sourcech_ctrl);
+		writel(0, aio->audio + aio->regs.bf_sourcech_ctrl);
 
-		value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		value = readl(aio->audio + aio->regs.bf_sourcech_cfg);
 		value &= ~BIT(BF_SRC_CFGX_SFIFO_ENA);
-		writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		writel(value, aio->audio + aio->regs.bf_sourcech_cfg);
 
 		/* set group_sync_dis = 0 */
-		value = readl(aio->cygaud->audio + BF_SRC_GRP_SYNC_DIS_OFFSET);
+		value = readl(aio->audio + BF_SRC_GRP_SYNC_DIS_OFFSET);
 		value &= ~BIT(aio->portnum);
-		writel(value, aio->cygaud->audio + BF_SRC_GRP_SYNC_DIS_OFFSET);
+		writel(value, aio->audio + BF_SRC_GRP_SYNC_DIS_OFFSET);
 
 		/*
 		 * We want to wait enough time for 1 LRCLK.
@@ -498,33 +494,32 @@ static int audio_ssp_out_disable(struct cygnus_aio_port *aio)
 		udelay(175);
 
 		if (aio->is_slave && (aio->mode == CYGNUS_SSPMODE_TDM)) {
-			value = readl(aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+			value = readl(aio->i2s_in + IOP_SW_INIT_LOGIC);
 			value |= BIT(aio->portnum);
-			writel(value, aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+			writel(value, aio->i2s_in + IOP_SW_INIT_LOGIC);
 		}
 
 		/* If both playback and capture are off */
 		if (aio->streams_on == 0) {
-			value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
+			value = readl(aio->audio + aio->regs.i2s_cfg);
 			value &= ~BIT(I2S_OUT_CFGX_DATA_ENABLE);
 			value &= ~BIT(I2S_OUT_CFGX_CLK_ENA);
-			writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
+			writel(value, aio->audio + aio->regs.i2s_cfg);
 		}
 
 		break;
 	case PORT_SPDIF:
-		value = readl(aio->cygaud->audio + SPDIF_FORMAT_CFG_OFFSET);
+		value = readl(aio->audio + SPDIF_FORMAT_CFG_OFFSET);
 		value &= ~0x3;
-		writel(value, aio->cygaud->audio + SPDIF_FORMAT_CFG_OFFSET);
-		writel(0, aio->cygaud->audio + aio->regs.bf_sourcech_ctrl);
+		writel(value, aio->audio + SPDIF_FORMAT_CFG_OFFSET);
+		writel(0, aio->audio + aio->regs.bf_sourcech_ctrl);
 
-		value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		value = readl(aio->audio + aio->regs.bf_sourcech_cfg);
 		value &= ~BIT(BF_SRC_CFGX_SFIFO_ENA);
-		writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		writel(value, aio->audio + aio->regs.bf_sourcech_cfg);
 		break;
 	default:
-		dev_err(aio->cygaud->dev,
-			"Port not supported %d\n", aio->portnum);
+		dev_err(aio->dev, "Port not supported %d\n", aio->portnum);
 		status = -EINVAL;
 	}
 
@@ -565,9 +560,8 @@ static int cygnus_ssp_set_clocks(struct cygnus_aio_port *aio)
 		break;
 
 	default:
-		dev_err(aio->cygaud->dev,
-			"Invalid combination of MCLK and BCLK\n");
-		dev_err(aio->cygaud->dev, "lrclk = %u, bits/frame = %u, mclk = %u\n",
+		dev_err(aio->dev, "Invalid combination of MCLK and BCLK\n");
+		dev_err(aio->dev, "lrclk = %u, bits/frame = %u, mclk = %u\n",
 			aio->lrclk, bits_per_frame, aio->mclk);
 		return -EINVAL;
 	}
@@ -583,28 +577,27 @@ static int cygnus_ssp_set_clocks(struct cygnus_aio_port *aio)
 		sclk /= 32;
 
 		/* Set number of bitclks per frame */
-		value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
+		value = readl(aio->audio + aio->regs.i2s_cfg);
 		value &= ~(mask << I2S_OUT_CFGX_SCLKS_PER_1FS_DIV32);
 		value |= sclk << I2S_OUT_CFGX_SCLKS_PER_1FS_DIV32;
-		writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
-		dev_dbg(aio->cygaud->dev,
-			"SCLKS_PER_1FS_DIV32 = 0x%x\n", value);
+		writel(value, aio->audio + aio->regs.i2s_cfg);
+		dev_dbg(aio->dev, "SCLKS_PER_1FS_DIV32 = 0x%x\n", value);
 		break;
 	case PORT_SPDIF:
 		break;
 	default:
-		dev_err(aio->cygaud->dev, "Unknown port type\n");
+		dev_err(aio->dev, "Unknown port type\n");
 		return -EINVAL;
 	}
 
 	/* Set MCLK_RATE ssp port (spdif and ssp are the same) */
-	value = readl(aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
+	value = readl(aio->audio + aio->regs.i2s_mclk_cfg);
 	value &= ~(0xf << I2S_OUT_MCLKRATE_SHIFT);
 	value |= (mclk_rate << I2S_OUT_MCLKRATE_SHIFT);
-	writel(value, aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
+	writel(value, aio->audio + aio->regs.i2s_mclk_cfg);
 
-	dev_dbg(aio->cygaud->dev, "mclk cfg reg = 0x%x\n", value);
-	dev_dbg(aio->cygaud->dev, "bits per frame = %u, mclk = %u Hz, lrclk = %u Hz\n",
+	dev_dbg(aio->dev, "mclk cfg reg = 0x%x\n", value);
+	dev_dbg(aio->dev, "bits per frame = %u, mclk = %u Hz, lrclk = %u Hz\n",
 			bits_per_frame, aio->mclk, aio->lrclk);
 	return 0;
 }
@@ -619,11 +612,10 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 	u32 mask;
 	int ret = 0;
 
-	dev_dbg(aio->cygaud->dev, "%s port = %d\n", __func__, aio->portnum);
-	dev_dbg(aio->cygaud->dev, "params_channels %d\n",
-			params_channels(params));
-	dev_dbg(aio->cygaud->dev, "rate %d\n", params_rate(params));
-	dev_dbg(aio->cygaud->dev, "format %d\n", params_format(params));
+	dev_dbg(aio->dev, "%s port = %d\n", __func__, aio->portnum);
+	dev_dbg(aio->dev, "params_channels %d\n", params_channels(params));
+	dev_dbg(aio->dev, "rate %d\n", params_rate(params));
+	dev_dbg(aio->dev, "format %d\n", params_format(params));
 
 	rate = params_rate(params);
 
@@ -631,14 +623,14 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 	case CYGNUS_SSPMODE_TDM:
 		/* It's expected that set_dai_tdm_slot has been called */
 		if ((rate == 192000) && (params_channels(params) > 4)) {
-			dev_err(aio->cygaud->dev, "Cannot run %d channels at %dHz\n",
+			dev_err(aio->dev, "Cannot run %d channels at %dHz\n",
 				params_channels(params), rate);
 			return -EINVAL;
 		}
 		break;
 	case CYGNUS_SSPMODE_I2S:
 		if (params_channels(params) != 2) {
-			dev_err(aio->cygaud->dev, "i2s mode must use 2 channels\n");
+			dev_err(aio->dev, "i2s mode must use 2 channels\n");
 			return -EINVAL;
 		}
 
@@ -648,16 +640,15 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 
 		break;
 	default:
-		dev_err(aio->cygaud->dev,
-			"%s port running in unknown mode\n", __func__);
+		dev_err(aio->dev, "%s unknown mode\n", __func__);
 		return -EINVAL;
 	}
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		value = readl(aio->audio + aio->regs.bf_sourcech_cfg);
 		value &= ~BIT(BF_SRC_CFGX_BUFFER_PAIR_ENABLE);
 		value &= ~BIT(BF_SRC_CFGX_SAMPLE_CH_MODE);
-		writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		writel(value, aio->audio + aio->regs.bf_sourcech_cfg);
 
 		switch (params_format(params)) {
 		case SNDRV_PCM_FORMAT_S16_LE:
@@ -675,38 +666,34 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 		}
 
 		mask = BF_SRC_CFGX_BITRES_MASK;
-		value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		value = readl(aio->audio + aio->regs.bf_sourcech_cfg);
 		value &= ~(mask << BF_SRC_CFGX_BIT_RES);
 		value |= (bitres << BF_SRC_CFGX_BIT_RES);
-		writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		writel(value, aio->audio + aio->regs.bf_sourcech_cfg);
 
 		/* Only needed for LSB mode, ignored for MSB */
 		mask = I2S_OUT_CFGX_BIT_PER_SAMPLE_MASK;
-		value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
+		value = readl(aio->audio + aio->regs.i2s_cfg);
 		value &= ~(mask << I2S_OUT_CFGX_BITS_PER_SAMPLE);
 		value |= (bits_per_sample << I2S_OUT_CFGX_BITS_PER_SAMPLE);
-		writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
+		writel(value, aio->audio + aio->regs.i2s_cfg);
 	} else {
 
 		switch (params_format(params)) {
 		case SNDRV_PCM_FORMAT_S16_LE:
 			bits_per_sample = 16;
 
-			value = readl(aio->cygaud->audio +
-					aio->regs.bf_destch_cfg);
+			value = readl(aio->audio + aio->regs.bf_destch_cfg);
 			value |= BIT(BF_DST_CFGX_CAP_MODE);
-			writel(value, aio->cygaud->audio +
-					aio->regs.bf_destch_cfg);
+			writel(value, aio->audio + aio->regs.bf_destch_cfg);
 			break;
 
 		case SNDRV_PCM_FORMAT_S32_LE:
 			bits_per_sample = 24; /* Only 24 valid bits */
 
-			value = readl(aio->cygaud->audio +
-					aio->regs.bf_destch_cfg);
+			value = readl(aio->audio + aio->regs.bf_destch_cfg);
 			value &= ~BIT(BF_DST_CFGX_CAP_MODE);
-			writel(value, aio->cygaud->audio +
-					aio->regs.bf_destch_cfg);
+			writel(value, aio->audio + aio->regs.bf_destch_cfg);
 			break;
 
 		default:
@@ -715,10 +702,10 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 
 		/* Used for both LSB and MSB modes */
 		mask = I2S_IN_CFGX_BIT_PER_SAMPLE_MASK;
-		value = readl(aio->cygaud->i2s_in + aio->regs.i2s_cap_cfg);
+		value = readl(aio->i2s_in + aio->regs.i2s_cap_cfg);
 		value &= ~(mask << I2S_IN_CFGX_BITS_PER_SAMPLE);
 		value |= (bits_per_sample << I2S_IN_CFGX_BITS_PER_SAMPLE);
-		writel(value, aio->cygaud->i2s_in + aio->regs.i2s_cap_cfg);
+		writel(value, aio->i2s_in + aio->regs.i2s_cap_cfg);
 	}
 
 	/* Put output port into reset prior to configuring.
@@ -741,13 +728,13 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 			 * in the same state for our first transfer as it is
 			 * every transfer.
 			 */
-			value = readl(aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+			value = readl(aio->i2s_in + IOP_SW_INIT_LOGIC);
 			value |= BIT(aio->portnum);
-			writel(value, aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+			writel(value, aio->i2s_in + IOP_SW_INIT_LOGIC);
 
-			value = readl(aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+			value = readl(aio->i2s_in + IOP_SW_INIT_LOGIC);
 			value |= BIT(IOP_LOGIC_RESET_IN_OFFSET(aio->portnum));
-			writel(value, aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+			writel(value, aio->i2s_in + IOP_SW_INIT_LOGIC);
 		}
 
 		if (aio->port_type != PORT_SPDIF)
@@ -790,52 +777,49 @@ static int cygnus_ssp_set_sysclk(struct snd_soc_dai *dai,
 	long rate;
 	struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai);
 
-	dev_dbg(aio->cygaud->dev,
-		"%s Enter port = %d\n", __func__, aio->portnum);
+	dev_dbg(aio->dev, "%s Enter port = %d\n", __func__, aio->portnum);
 
 	/*
 	 * This should not happen, but the machine file may inadvertently
 	 * call set_sysclk without configuring a clock via the devicetree.
 	 */
 	if (!aio->clk_info.audio_clk) {
-		dev_err(aio->cygaud->dev,
-			"%s Error. No clock assigned.\n", __func__);
+		dev_err(aio->dev, "%s Error. No clock assigned.\n", __func__);
 		return -ENODEV;
 	}
 
 	rate = clk_round_rate(aio->clk_info.audio_clk, freq);
 	if (rate < 0) {
-		dev_err(aio->cygaud->dev, "%s Error with with clock %ld.\n",
+		dev_err(aio->dev, "%s Error with with clock %ld.\n",
 			__func__, rate);
 		return rate;
 	}
 
 	if (!mclk_in_range(freq, rate)) {
-		dev_err(aio->cygaud->dev, "%s Can not set rate to %u  actual %ld.\n",
+		dev_err(aio->dev, "%s Can not set rate to %u  actual %ld.\n",
 			__func__, freq, rate);
 		return -EINVAL;
 	}
 
 	ret = clk_set_rate(aio->clk_info.audio_clk, freq);
 	if (ret) {
-		dev_err(aio->cygaud->dev,
-			"%s Set MCLK rate fail %d\n", __func__, ret);
+		dev_err(aio->dev, "%s Set MCLK rate fail %d\n", __func__, ret);
 		return ret;
 	}
 
 	aio->mclk = freq;
 	sel = aio->clk_info.clk_mux;
 
-	dev_dbg(aio->cygaud->dev, "%s Setting MCLKSEL to %d\n", __func__, sel);
-	value = readl(aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
+	dev_dbg(aio->dev, "%s Setting MCLKSEL to %d\n", __func__, sel);
+	value = readl(aio->audio + aio->regs.i2s_mclk_cfg);
 	value &= ~(0xf << I2S_OUT_PLLCLKSEL_SHIFT);
 	value |= (sel << I2S_OUT_PLLCLKSEL_SHIFT);
-	writel(value, aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
+	writel(value, aio->audio + aio->regs.i2s_mclk_cfg);
 
 	/* Clear bit for active */
-	value = readl(aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
+	value = readl(aio->audio + AUD_MISC_SEROUT_OE_REG_BASE);
 	value &= ~BIT(AUD_MISC_SEROUT_MCLK_OE + (aio->portnum * 4));
-	writel(value, aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
+	writel(value, aio->audio + AUD_MISC_SEROUT_OE_REG_BASE);
 
 	return 0;
 }
@@ -883,7 +867,7 @@ static int cygnus_ssp_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 	u32 val;
 	u32 mask;
 
-	dev_dbg(aio->cygaud->dev, "%s Enter  fmt: %x\n", __func__, fmt);
+	dev_dbg(aio->dev, "%s Enter  fmt: %x\n", __func__, fmt);
 
 	if (aio->port_type == PORT_SPDIF)
 		return -EINVAL;
@@ -912,7 +896,7 @@ static int cygnus_ssp_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 			aio->fs_delay = 1;
 		else {
 			if (aio->is_slave) {
-				dev_err(aio->cygaud->dev,
+				dev_err(aio->dev,
 				"%s DSP_B mode not supported while slave.\n",
 					__func__);
 				return -EINVAL;
@@ -929,7 +913,7 @@ static int cygnus_ssp_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 	/* We must be i2s master to invert any clock */
 	if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) {
 		if (aio->is_slave || (aio->mode == CYGNUS_SSPMODE_TDM)) {
-			dev_err(aio->cygaud->dev,
+			dev_err(aio->dev,
 			"%s Can only invert clocks in i2s master mode\n",
 				__func__);
 			return -EINVAL;
@@ -957,7 +941,7 @@ static int cygnus_ssp_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 		return -EINVAL;
 	}
 
-	val = readl(aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
+	val = readl(aio->audio + AUD_MISC_SEROUT_OE_REG_BASE);
 
 	/*
 	 * Configure the word clk and bit clk as output or tristate
@@ -972,8 +956,8 @@ static int cygnus_ssp_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 	else
 		val &= ~mask;  /* Clear bit for drive */
 
-	dev_dbg(aio->cygaud->dev, "%s  Set OE bits 0x%x\n", __func__, val);
-	writel(val, aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
+	dev_dbg(aio->dev, "%s  Set OE bits 0x%x\n", __func__, val);
+	writel(val, aio->audio + AUD_MISC_SEROUT_OE_REG_BASE);
 
 	return 0;
 }
@@ -983,7 +967,7 @@ static int cygnus_ssp_trigger(struct snd_pcm_substream *substream, int cmd,
 {
 	struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai);
 
-	dev_dbg(aio->cygaud->dev,
+	dev_dbg(aio->dev,
 		"%s cmd %d at port = %d\n", __func__, cmd, aio->portnum);
 
 	switch (cmd) {
@@ -1023,8 +1007,7 @@ static int cygnus_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
 	unsigned int i;
 
 	if (tx_mask != rx_mask) {
-		dev_err(aio->cygaud->dev,
-			"%s tx_mask must equal rx_mask\n", __func__);
+		dev_err(aio->dev, "%s tx_mask must equal rx_mask\n", __func__);
 		return -EINVAL;
 	}
 
@@ -1050,8 +1033,7 @@ static int cygnus_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
 	}
 
 	if (!found) {
-		dev_err(aio->cygaud->dev,
-			"%s In TDM mode, frame bits INVALID (%d)\n",
+		dev_err(aio->dev, "%s In TDM mode, frame bits INVALID (%d)\n",
 			__func__, bits_per_frame);
 		return -EINVAL;
 	}
@@ -1060,7 +1042,7 @@ static int cygnus_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
 	aio->slot_width = slot_width;
 	aio->slots_per_frame = slots;
 
-	dev_dbg(aio->cygaud->dev, "%s active_slots %u, bits per frame %d\n",
+	dev_dbg(aio->dev, "%s active_slots %u, bits per frame %d\n",
 			__func__, aio->active_slots, bits_per_frame);
 	return 0;
 }
@@ -1074,7 +1056,7 @@ static int cygnus_ssp_set_pll(struct snd_soc_dai *cpu_dai, int pll_id,
 	int ret = 0;
 
 	if (!aio->clk_info.audio_clk) {
-		dev_err(aio->cygaud->dev,
+		dev_err(aio->dev,
 			"%s: port %d does not have an assigned clock.\n",
 			__func__, aio->portnum);
 		return -ENODEV;
@@ -1082,7 +1064,7 @@ static int cygnus_ssp_set_pll(struct snd_soc_dai *cpu_dai, int pll_id,
 
 	clk_pll = clk_get_parent(aio->clk_info.audio_clk);
 	if (IS_ERR(clk_pll)) {
-		dev_err(aio->cygaud->dev,
+		dev_err(aio->dev,
 			"%s: could not get audiopll clock.\n", __func__);
 		return -ENODEV;
 	}
@@ -1185,7 +1167,7 @@ static void update_ssp_cfg(struct cygnus_aio_port *aio)
 	 * bit set in the Tx formatter (which would be the Tx Formatters
 	 * internal clock or signal from external pin).
 	 */
-	ssp_curcfg = readl(aio->cygaud->i2s_in + aio->regs.i2s_cap_cfg);
+	ssp_curcfg = readl(aio->i2s_in + aio->regs.i2s_cap_cfg);
 	ssp_incfg = (ssp_curcfg & I2S_IN_CFG_REG_UPDATE_MASK) | ssp_newcfg;
 	ssp_incfg |= BIT(I2S_OUT_CFGX_SLAVE_MODE);
 
@@ -1194,13 +1176,13 @@ static void update_ssp_cfg(struct cygnus_aio_port *aio)
 	ssp_incfg &= ~BIT(I2S_OUT_CFGX_BITS_PER_SLOT);
 	ssp_incfg |= (bits_per_slot_in << I2S_OUT_CFGX_BITS_PER_SLOT);
 
-	writel(ssp_incfg, aio->cygaud->i2s_in + aio->regs.i2s_cap_cfg);
+	writel(ssp_incfg, aio->i2s_in + aio->regs.i2s_cap_cfg);
 
 	/*
 	 * SSP out cfg.
 	 * Retain bits we do not want to update, then OR in new bits
 	 */
-	ssp_curcfg = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
+	ssp_curcfg = readl(aio->audio + aio->regs.i2s_cfg);
 	ssp_outcfg = (ssp_curcfg & I2S_OUT_CFG_REG_UPDATE_MASK) | ssp_newcfg;
 
 	ssp_outcfg &= ~(0xf << I2S_OUT_CFGX_VALID_SLOT);
@@ -1208,7 +1190,7 @@ static void update_ssp_cfg(struct cygnus_aio_port *aio)
 	ssp_outcfg &= ~BIT(I2S_OUT_CFGX_BITS_PER_SLOT);
 	ssp_outcfg |= (bits_per_slot_out << I2S_OUT_CFGX_BITS_PER_SLOT);
 
-	writel(ssp_outcfg, aio->cygaud->audio + aio->regs.i2s_cfg);
+	writel(ssp_outcfg, aio->audio + aio->regs.i2s_cfg);
 }
 
 
@@ -1320,7 +1302,9 @@ static int parse_ssp_child_node(struct platform_device *pdev,
 	}
 
 	aio = &cygaud->portinfo[portnum];
-	aio->cygaud = cygaud;
+
+	aio->audio = cygaud->audio;
+	aio->i2s_in = cygaud->i2s_in;
 	aio->portnum = portnum;
 	aio->port_type = port_type;
 	aio->fsync_width = -1;
@@ -1349,8 +1333,7 @@ static int parse_ssp_child_node(struct platform_device *pdev,
 
 	dev_dbg(&pdev->dev, "%s portnum = %d\n", __func__, aio->portnum);
 	aio->streams_on = 0;
-	aio->cygaud->dev = &pdev->dev;
-
+	aio->dev = &pdev->dev;
 
 	aio->clk_info.audio_clk = NULL;
 
@@ -1421,7 +1404,6 @@ static int cygnus_ssp_probe(struct platform_device *pdev)
 	}
 
 	active_port_count = 0;
-
 	for_each_available_child_of_node(pdev->dev.of_node, child_node) {
 		err = parse_ssp_child_node(pdev, child_node, cygaud,
 					&cygnus_ssp_dai[active_port_count]);
diff --git a/sound/soc/bcm/cygnus-ssp.h b/sound/soc/bcm/cygnus-ssp.h
index 648321d..ac346b8 100644
--- a/sound/soc/bcm/cygnus-ssp.h
+++ b/sound/soc/bcm/cygnus-ssp.h
@@ -32,13 +32,13 @@
 #define PROP_LEN_MAX 40
 
 struct ringbuf_regs {
-	unsigned rdaddr;
-	unsigned wraddr;
-	unsigned baseaddr;
-	unsigned endaddr;
-	unsigned fmark;   /* freemark for play, fullmark for caputure */
-	unsigned period_bytes;
-	unsigned buf_size;
+	unsigned int rdaddr;
+	unsigned int wraddr;
+	unsigned int baseaddr;
+	unsigned int endaddr;
+	unsigned int fmark;   /* freemark for play, fullmark for caputure */
+	u32 period_bytes;
+	u32 buf_size;
 };
 
 #define RINGBUF_REG_PLAYBACK(num) ((struct ringbuf_regs) { \
@@ -85,6 +85,8 @@ struct cygnus_audio_clkinfo {
 };
 
 struct cygnus_aio_port {
+	struct device *dev;
+
 	int portnum;
 	int mode;
 	bool is_slave;
@@ -104,7 +106,9 @@ struct cygnus_aio_port {
 	unsigned int slots_per_frame;
 	unsigned int active_slots;
 
-	struct cygnus_audio *cygaud;
+	void __iomem *audio;
+	void __iomem *i2s_in;
+
 	struct cygnus_ssp_regs regs;
 
 	struct ringbuf_regs play_rb_regs;
@@ -122,8 +126,8 @@ struct cygnus_audio {
 
 	int irq_num;
 	void __iomem *audio;
-	struct device *dev;
 	void __iomem *i2s_in;
+	struct device *dev;
 };
 
 extern int cygnus_ssp_set_custom_fsync_width(struct snd_soc_dai *cpu_dai,
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH 9/9] ASoC: cygnus: Tidy up of structure access
@ 2017-08-14 22:06   ` Lori Hikichi
  0 siblings, 0 replies; 50+ messages in thread
From: Lori Hikichi @ 2017-08-14 22:06 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Mark Rutland, Ray Jui,
	Scott Branden, Jon Mason,
	bcm-kernel-feedback-list-dY08KVG/lbpWk0Htik3J/w, Jaroslav Kysela,
	Takashi Iwai
  Cc: alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Lori Hikichi

Adds copies of the frequently accessed io handles to each ports
data structure, making it more convenient to access.  Also, a small
cleanup to the type names used in cygnus_pcm.  None of this should
result in a functional change to the driver.

Signed-off-by: Lori Hikichi <lori.hikichi-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
---
 sound/soc/bcm/cygnus-pcm.c |  50 ++++----
 sound/soc/bcm/cygnus-ssp.c | 298 +++++++++++++++++++++------------------------
 sound/soc/bcm/cygnus-ssp.h |  22 ++--
 3 files changed, 178 insertions(+), 192 deletions(-)

diff --git a/sound/soc/bcm/cygnus-pcm.c b/sound/soc/bcm/cygnus-pcm.c
index d616e096..d82bf55 100644
--- a/sound/soc/bcm/cygnus-pcm.c
+++ b/sound/soc/bcm/cygnus-pcm.c
@@ -329,24 +329,24 @@ static void enable_intr(struct snd_pcm_substream *substream)
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		/* Clear interrupt status before enabling them */
-		writel(clear_mask, aio->cygaud->audio + ESR0_STATUS_CLR_OFFSET);
-		writel(clear_mask, aio->cygaud->audio + ESR1_STATUS_CLR_OFFSET);
-		writel(clear_mask, aio->cygaud->audio + ESR3_STATUS_CLR_OFFSET);
+		writel(clear_mask, aio->audio + ESR0_STATUS_CLR_OFFSET);
+		writel(clear_mask, aio->audio + ESR1_STATUS_CLR_OFFSET);
+		writel(clear_mask, aio->audio + ESR3_STATUS_CLR_OFFSET);
 		/* Unmask the interrupts of the given port*/
-		writel(clear_mask, aio->cygaud->audio + ESR0_MASK_CLR_OFFSET);
-		writel(clear_mask, aio->cygaud->audio + ESR1_MASK_CLR_OFFSET);
-		writel(clear_mask, aio->cygaud->audio + ESR3_MASK_CLR_OFFSET);
+		writel(clear_mask, aio->audio + ESR0_MASK_CLR_OFFSET);
+		writel(clear_mask, aio->audio + ESR1_MASK_CLR_OFFSET);
+		writel(clear_mask, aio->audio + ESR3_MASK_CLR_OFFSET);
 
 		writel(ANY_PLAYBACK_IRQ,
-			aio->cygaud->audio + INTH_R5F_MASK_CLEAR_OFFSET);
+			aio->audio + INTH_R5F_MASK_CLEAR_OFFSET);
 	} else {
-		writel(clear_mask, aio->cygaud->audio + ESR2_STATUS_CLR_OFFSET);
-		writel(clear_mask, aio->cygaud->audio + ESR4_STATUS_CLR_OFFSET);
-		writel(clear_mask, aio->cygaud->audio + ESR2_MASK_CLR_OFFSET);
-		writel(clear_mask, aio->cygaud->audio + ESR4_MASK_CLR_OFFSET);
+		writel(clear_mask, aio->audio + ESR2_STATUS_CLR_OFFSET);
+		writel(clear_mask, aio->audio + ESR4_STATUS_CLR_OFFSET);
+		writel(clear_mask, aio->audio + ESR2_MASK_CLR_OFFSET);
+		writel(clear_mask, aio->audio + ESR4_MASK_CLR_OFFSET);
 
 		writel(ANY_CAPTURE_IRQ,
-			aio->cygaud->audio + INTH_R5F_MASK_CLEAR_OFFSET);
+			aio->audio + INTH_R5F_MASK_CLEAR_OFFSET);
 	}
 
 }
@@ -366,12 +366,12 @@ static void disable_intr(struct snd_pcm_substream *substream)
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		/* Mask the interrupts of the given port*/
-		writel(set_mask, aio->cygaud->audio + ESR0_MASK_SET_OFFSET);
-		writel(set_mask, aio->cygaud->audio + ESR1_MASK_SET_OFFSET);
-		writel(set_mask, aio->cygaud->audio + ESR3_MASK_SET_OFFSET);
+		writel(set_mask, aio->audio + ESR0_MASK_SET_OFFSET);
+		writel(set_mask, aio->audio + ESR1_MASK_SET_OFFSET);
+		writel(set_mask, aio->audio + ESR3_MASK_SET_OFFSET);
 	} else {
-		writel(set_mask, aio->cygaud->audio + ESR2_MASK_SET_OFFSET);
-		writel(set_mask, aio->cygaud->audio + ESR4_MASK_SET_OFFSET);
+		writel(set_mask, aio->audio + ESR2_MASK_SET_OFFSET);
+		writel(set_mask, aio->audio + ESR4_MASK_SET_OFFSET);
 	}
 
 }
@@ -415,13 +415,13 @@ static void cygnus_pcm_period_elapsed(struct snd_pcm_substream *substream)
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		/* Set the ring buffer to full */
-		regval = readl(aio->cygaud->audio + p_rbuf->rdaddr);
+		regval = readl(aio->audio + p_rbuf->rdaddr);
 		regval = regval ^ BIT(31);
-		writel(regval, aio->cygaud->audio + p_rbuf->wraddr);
+		writel(regval, aio->audio + p_rbuf->wraddr);
 	} else {
 		/* Set the ring buffer to empty */
-		regval = readl(aio->cygaud->audio + p_rbuf->wraddr);
-		writel(regval, aio->cygaud->audio + p_rbuf->rdaddr);
+		regval = readl(aio->audio + p_rbuf->wraddr);
+		writel(regval, aio->audio + p_rbuf->rdaddr);
 	}
 }
 
@@ -690,7 +690,7 @@ static int cygnus_pcm_prepare(struct snd_pcm_substream *substream)
 
 	is_play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? 1 : 0;
 
-	ringbuf_set_initial(aio->cygaud->audio, p_rbuf, is_play, start,
+	ringbuf_set_initial(aio->audio, p_rbuf, is_play, start,
 				periodsize, bufsize);
 
 	return ret;
@@ -710,11 +710,11 @@ static snd_pcm_uframes_t cygnus_pcm_pointer(struct snd_pcm_substream *substream)
 	 */
 	p_rbuf = get_ringbuf(substream);
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		cur = readl(aio->cygaud->audio + p_rbuf->rdaddr);
+		cur = readl(aio->audio + p_rbuf->rdaddr);
 	else
-		cur = readl(aio->cygaud->audio + p_rbuf->wraddr);
+		cur = readl(aio->audio + p_rbuf->wraddr);
 
-	base = readl(aio->cygaud->audio + p_rbuf->baseaddr);
+	base = readl(aio->audio + p_rbuf->baseaddr);
 
 	/*
 	 * Mask off the MSB of the rdaddr,wraddr and baseaddr
diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c
index 97bf67a..7535613 100644
--- a/sound/soc/bcm/cygnus-ssp.c
+++ b/sound/soc/bcm/cygnus-ssp.c
@@ -226,78 +226,76 @@ static int audio_ssp_init_portregs(struct cygnus_aio_port *aio)
 	int status = 0;
 
 	/* Set Group ID */
-	writel(0, aio->cygaud->audio + BF_SRC_GRP0_OFFSET);
-	writel(1, aio->cygaud->audio + BF_SRC_GRP1_OFFSET);
-	writel(2, aio->cygaud->audio + BF_SRC_GRP2_OFFSET);
-	writel(3, aio->cygaud->audio + BF_SRC_GRP3_OFFSET);
+	writel(0, aio->audio + BF_SRC_GRP0_OFFSET);
+	writel(1, aio->audio + BF_SRC_GRP1_OFFSET);
+	writel(2, aio->audio + BF_SRC_GRP2_OFFSET);
+	writel(3, aio->audio + BF_SRC_GRP3_OFFSET);
 
 	switch (aio->port_type) {
 	case PORT_TDM:
-		value = readl(aio->cygaud->audio + aio->regs.i2s_stream_cfg);
+		value = readl(aio->audio + aio->regs.i2s_stream_cfg);
 		value &= ~I2S_STREAM_CFG_MASK;
 
 		/* Configure the AUD_FMM_IOP_OUT_I2S_x_STREAM_CFG reg */
 		value |= aio->portnum << I2S_OUT_STREAM_CFG_GROUP_ID;
 		value |= aio->portnum; /* FCI ID is the port num */
 		value |= CH_GRP_STEREO << I2S_OUT_STREAM_CFG_CHANNEL_GROUPING;
-		writel(value, aio->cygaud->audio + aio->regs.i2s_stream_cfg);
+		writel(value, aio->audio + aio->regs.i2s_stream_cfg);
 
 		/* Configure the AUD_FMM_BF_CTRL_SOURCECH_CFGX reg */
-		value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		value = readl(aio->audio + aio->regs.bf_sourcech_cfg);
 		value &= ~BIT(BF_SRC_CFGX_NOT_PAUSE_WHEN_EMPTY);
 		value &= ~BIT(BF_SRC_CFGX_SAMPLE_REPEAT_ENABLE);
 		value |= BIT(BF_SRC_CFGX_SFIFO_SZ_DOUBLE);
 		value |= BIT(BF_SRC_CFGX_PROCESS_SEQ_ID_VALID);
-		writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		writel(value, aio->audio + aio->regs.bf_sourcech_cfg);
 
 		/* Configure the AUD_FMM_IOP_IN_I2S_x_CAP_STREAM_CFG_0 reg */
-		value = readl(aio->cygaud->i2s_in +
-			aio->regs.i2s_cap_stream_cfg);
+		value = readl(aio->i2s_in + aio->regs.i2s_cap_stream_cfg);
 		value &= ~I2S_CAP_STREAM_CFG_MASK;
 		value |= aio->portnum << I2S_IN_STREAM_CFG_0_GROUP_ID;
-		writel(value, aio->cygaud->i2s_in +
-			aio->regs.i2s_cap_stream_cfg);
+		writel(value, aio->i2s_in + aio->regs.i2s_cap_stream_cfg);
 
 		/* Configure the AUD_FMM_BF_CTRL_DESTCH_CFGX_REG_BASE reg */
 		fci_id = CAPTURE_FCI_ID_BASE + aio->portnum;
 
-		value = readl(aio->cygaud->audio + aio->regs.bf_destch_cfg);
+		value = readl(aio->audio + aio->regs.bf_destch_cfg);
 		value |= BIT(BF_DST_CFGX_DFIFO_SZ_DOUBLE);
 		value &= ~BIT(BF_DST_CFGX_NOT_PAUSE_WHEN_FULL);
 		value |= (fci_id << BF_DST_CFGX_FCI_ID);
 		value |= BIT(BF_DST_CFGX_PROC_SEQ_ID_VALID);
-		writel(value, aio->cygaud->audio + aio->regs.bf_destch_cfg);
+		writel(value, aio->audio + aio->regs.bf_destch_cfg);
 
 		/* Enable the transmit pin for this port */
-		value = readl(aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
+		value = readl(aio->audio + AUD_MISC_SEROUT_OE_REG_BASE);
 		value &= ~BIT((aio->portnum * 4) + AUD_MISC_SEROUT_SDAT_OE);
-		writel(value, aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
+		writel(value, aio->audio + AUD_MISC_SEROUT_OE_REG_BASE);
 		break;
 	case PORT_SPDIF:
-		value = readl(aio->cygaud->audio + SPDIF_CTRL_OFFSET);
+		value = readl(aio->audio + SPDIF_CTRL_OFFSET);
 		value |= BIT(SPDIF_0_OUT_DITHER_ENA);
-		writel(value, aio->cygaud->audio + SPDIF_CTRL_OFFSET);
+		writel(value, aio->audio + SPDIF_CTRL_OFFSET);
 
 		/* Enable and set the FCI ID for the SPDIF channel */
-		value = readl(aio->cygaud->audio + SPDIF_STREAM_CFG_OFFSET);
+		value = readl(aio->audio + SPDIF_STREAM_CFG_OFFSET);
 		value &= ~SPDIF_STREAM_CFG_MASK;
 		value |= aio->portnum; /* FCI ID is the port num */
 		value |= BIT(SPDIF_0_OUT_STREAM_ENA);
-		writel(value, aio->cygaud->audio + SPDIF_STREAM_CFG_OFFSET);
+		writel(value, aio->audio + SPDIF_STREAM_CFG_OFFSET);
 
-		value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		value = readl(aio->audio + aio->regs.bf_sourcech_cfg);
 		value &= ~BIT(BF_SRC_CFGX_NOT_PAUSE_WHEN_EMPTY);
 		value |= BIT(BF_SRC_CFGX_SFIFO_SZ_DOUBLE);
 		value |= BIT(BF_SRC_CFGX_PROCESS_SEQ_ID_VALID);
-		writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		writel(value, aio->audio + aio->regs.bf_sourcech_cfg);
 
 		/* Enable the spdif output pin */
-		value = readl(aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
+		value = readl(aio->audio + AUD_MISC_SEROUT_OE_REG_BASE);
 		value &= ~BIT(AUD_MISC_SEROUT_SPDIF_OE);
-		writel(value, aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
+		writel(value, aio->audio + AUD_MISC_SEROUT_OE_REG_BASE);
 		break;
 	default:
-		dev_err(aio->cygaud->dev, "Port not supported\n");
+		dev_err(aio->dev, "Port not supported\n");
 		status = -EINVAL;
 	}
 
@@ -308,24 +306,24 @@ static void audio_ssp_in_enable(struct cygnus_aio_port *aio)
 {
 	u32 value;
 
-	value = readl(aio->cygaud->audio + aio->regs.bf_destch_cfg);
+	value = readl(aio->audio + aio->regs.bf_destch_cfg);
 	value |= BIT(BF_DST_CFGX_CAP_ENA);
-	writel(value, aio->cygaud->audio + aio->regs.bf_destch_cfg);
+	writel(value, aio->audio + aio->regs.bf_destch_cfg);
 
 	/*
 	 * DATA_ENABLE need to be set even if doing capture.
 	 * Subsequent Tx will fail if this is not done.
 	 */
 	if (!aio->streams_on) {
-		value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
+		value = readl(aio->audio + aio->regs.i2s_cfg);
 		value |= BIT(I2S_OUT_CFGX_CLK_ENA);
 		value |= BIT(I2S_OUT_CFGX_DATA_ENABLE);
-		writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
+		writel(value, aio->audio + aio->regs.i2s_cfg);
 	}
 
-	value = readl(aio->cygaud->i2s_in + aio->regs.i2s_cap_stream_cfg);
+	value = readl(aio->i2s_in + aio->regs.i2s_cap_stream_cfg);
 	value |= BIT(I2S_IN_STREAM_CFG_CAP_ENA);
-	writel(value, aio->cygaud->i2s_in + aio->regs.i2s_cap_stream_cfg);
+	writel(value, aio->i2s_in + aio->regs.i2s_cap_stream_cfg);
 
 	/* Enable input portion of block */
 	udelay(10);
@@ -334,12 +332,11 @@ static void audio_ssp_in_enable(struct cygnus_aio_port *aio)
 	 * The input port may or may not be held in reset. Always clear
 	 * the reset. This will be benign if the port is not in reset.
 	 */
-	value = readl(aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+	value = readl(aio->i2s_in + IOP_SW_INIT_LOGIC);
 	value &= ~BIT(IOP_LOGIC_RESET_IN_OFFSET(aio->portnum));
-	writel(value, aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+	writel(value, aio->i2s_in + IOP_SW_INIT_LOGIC);
 
-	writel(BF_DESTCH_CTRLX_CAP_RUN,
-		aio->cygaud->audio + aio->regs.bf_destch_ctrl);
+	writel(BF_DESTCH_CTRLX_CAP_RUN, aio->audio + aio->regs.bf_destch_ctrl);
 
 	aio->streams_on |= CAPTURE_STREAM_MASK;
 }
@@ -348,17 +345,17 @@ static void audio_ssp_in_disable(struct cygnus_aio_port *aio)
 {
 	u32 value;
 
-	value = readl(aio->cygaud->audio + aio->regs.bf_destch_cfg);
+	value = readl(aio->audio + aio->regs.bf_destch_cfg);
 	value &= ~BIT(BF_DST_CFGX_CAP_ENA);
-	writel(value, aio->cygaud->audio + aio->regs.bf_destch_cfg);
+	writel(value, aio->audio + aio->regs.bf_destch_cfg);
 
-	value = readl(aio->cygaud->i2s_in + aio->regs.i2s_cap_stream_cfg);
+	value = readl(aio->i2s_in + aio->regs.i2s_cap_stream_cfg);
 	value &= ~BIT(I2S_IN_STREAM_CFG_CAP_ENA);
-	writel(value, aio->cygaud->i2s_in + aio->regs.i2s_cap_stream_cfg);
+	writel(value, aio->i2s_in + aio->regs.i2s_cap_stream_cfg);
 
 	aio->streams_on &= ~CAPTURE_STREAM_MASK;
 
-	writel(0x0, aio->cygaud->audio + aio->regs.bf_destch_ctrl);
+	writel(0x0, aio->audio + aio->regs.bf_destch_ctrl);
 
 	/*
 	 * Put input portion of port in reset.
@@ -375,9 +372,9 @@ static void audio_ssp_in_disable(struct cygnus_aio_port *aio)
 	 *
 	 */
 	if (aio->mode == CYGNUS_SSPMODE_TDM) {
-		value = readl(aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+		value = readl(aio->i2s_in + IOP_SW_INIT_LOGIC);
 		value |= BIT(IOP_LOGIC_RESET_IN_OFFSET(aio->portnum));
-		writel(value, aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+		writel(value, aio->i2s_in + IOP_SW_INIT_LOGIC);
 	}
 
 	/* If both playback and capture are off */
@@ -387,10 +384,10 @@ static void audio_ssp_in_disable(struct cygnus_aio_port *aio)
 		 * Need 1 bit clock tick for INIT_LOGIC to activate
 		 */
 		udelay(10);
-		value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
+		value = readl(aio->audio + aio->regs.i2s_cfg);
 		value &= ~BIT(I2S_OUT_CFGX_CLK_ENA);
 		value &= ~BIT(I2S_OUT_CFGX_DATA_ENABLE);
-		writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
+		writel(value, aio->audio + aio->regs.i2s_cfg);
 	}
 }
 
@@ -401,52 +398,51 @@ static int audio_ssp_out_enable(struct cygnus_aio_port *aio)
 
 	switch (aio->port_type) {
 	case PORT_TDM:
-		value = readl(aio->cygaud->audio + aio->regs.i2s_stream_cfg);
+		value = readl(aio->audio + aio->regs.i2s_stream_cfg);
 		value &= ~(I2S_OUT_STREAM_CFG_FCI_ID_MASK);
 		value |= aio->portnum;
-		writel(value, aio->cygaud->audio + aio->regs.i2s_stream_cfg);
+		writel(value, aio->audio + aio->regs.i2s_stream_cfg);
 
-		value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		value = readl(aio->audio + aio->regs.bf_sourcech_cfg);
 		value |= BIT(BF_SRC_CFGX_SFIFO_ENA);
-		writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		writel(value, aio->audio + aio->regs.bf_sourcech_cfg);
 
 		writel(BIT(BF_SOURCECH_CTRL_PLAY_RUN),
-			aio->cygaud->audio + aio->regs.bf_sourcech_ctrl);
+			aio->audio + aio->regs.bf_sourcech_ctrl);
 
-		value = readl(aio->cygaud->audio + aio->regs.i2s_stream_cfg);
+		value = readl(aio->audio + aio->regs.i2s_stream_cfg);
 		value |= BIT(I2S_OUT_STREAM_ENA);
-		writel(value, aio->cygaud->audio + aio->regs.i2s_stream_cfg);
+		writel(value, aio->audio + aio->regs.i2s_stream_cfg);
 
-		value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
+		value = readl(aio->audio + aio->regs.i2s_cfg);
 		value |= BIT(I2S_OUT_CFGX_CLK_ENA);
 		value |= BIT(I2S_OUT_CFGX_DATA_ENABLE);
-		writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
+		writel(value, aio->audio + aio->regs.i2s_cfg);
 
 		/*
 		 * The output port may or may not be in reset. Always clear
 		 * the reset. This will be benign if the port is not in reset.
 		 */
-		value = readl(aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+		value = readl(aio->i2s_in + IOP_SW_INIT_LOGIC);
 		value &= ~BIT(aio->portnum);
-		writel(value, aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+		writel(value, aio->i2s_in + IOP_SW_INIT_LOGIC);
 
 		aio->streams_on |= PLAYBACK_STREAM_MASK;
 		break;
 	case PORT_SPDIF:
-		value = readl(aio->cygaud->audio + SPDIF_FORMAT_CFG_OFFSET);
+		value = readl(aio->audio + SPDIF_FORMAT_CFG_OFFSET);
 		value |= 0x3;
-		writel(value, aio->cygaud->audio + SPDIF_FORMAT_CFG_OFFSET);
+		writel(value, aio->audio + SPDIF_FORMAT_CFG_OFFSET);
 
 		writel(BIT(BF_SOURCECH_CTRL_PLAY_RUN),
-			aio->cygaud->audio + aio->regs.bf_sourcech_ctrl);
+			aio->audio + aio->regs.bf_sourcech_ctrl);
 
-		value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		value = readl(aio->audio + aio->regs.bf_sourcech_cfg);
 		value |= BIT(BF_SRC_CFGX_SFIFO_ENA);
-		writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		writel(value, aio->audio + aio->regs.bf_sourcech_cfg);
 		break;
 	default:
-		dev_err(aio->cygaud->dev,
-			"Port not supported %d\n", aio->portnum);
+		dev_err(aio->dev, "Port not supported %d\n", aio->portnum);
 		status = -EINVAL;
 	}
 
@@ -463,9 +459,9 @@ static int audio_ssp_out_disable(struct cygnus_aio_port *aio)
 		aio->streams_on &= ~PLAYBACK_STREAM_MASK;
 
 		/* Set the FCI ID to INVALID */
-		value = readl(aio->cygaud->audio + aio->regs.i2s_stream_cfg);
+		value = readl(aio->audio + aio->regs.i2s_stream_cfg);
 		value |= 0x3ff;
-		writel(value, aio->cygaud->audio + aio->regs.i2s_stream_cfg);
+		writel(value, aio->audio + aio->regs.i2s_stream_cfg);
 
 		/*
 		 * We want to wait enough time for 2 LRCLK.
@@ -475,20 +471,20 @@ static int audio_ssp_out_disable(struct cygnus_aio_port *aio)
 		udelay(300);
 
 		/* set group_sync_dis = 1 */
-		value = readl(aio->cygaud->audio + BF_SRC_GRP_SYNC_DIS_OFFSET);
+		value = readl(aio->audio + BF_SRC_GRP_SYNC_DIS_OFFSET);
 		value |= BIT(aio->portnum);
-		writel(value, aio->cygaud->audio + BF_SRC_GRP_SYNC_DIS_OFFSET);
+		writel(value, aio->audio + BF_SRC_GRP_SYNC_DIS_OFFSET);
 
-		writel(0, aio->cygaud->audio + aio->regs.bf_sourcech_ctrl);
+		writel(0, aio->audio + aio->regs.bf_sourcech_ctrl);
 
-		value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		value = readl(aio->audio + aio->regs.bf_sourcech_cfg);
 		value &= ~BIT(BF_SRC_CFGX_SFIFO_ENA);
-		writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		writel(value, aio->audio + aio->regs.bf_sourcech_cfg);
 
 		/* set group_sync_dis = 0 */
-		value = readl(aio->cygaud->audio + BF_SRC_GRP_SYNC_DIS_OFFSET);
+		value = readl(aio->audio + BF_SRC_GRP_SYNC_DIS_OFFSET);
 		value &= ~BIT(aio->portnum);
-		writel(value, aio->cygaud->audio + BF_SRC_GRP_SYNC_DIS_OFFSET);
+		writel(value, aio->audio + BF_SRC_GRP_SYNC_DIS_OFFSET);
 
 		/*
 		 * We want to wait enough time for 1 LRCLK.
@@ -498,33 +494,32 @@ static int audio_ssp_out_disable(struct cygnus_aio_port *aio)
 		udelay(175);
 
 		if (aio->is_slave && (aio->mode == CYGNUS_SSPMODE_TDM)) {
-			value = readl(aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+			value = readl(aio->i2s_in + IOP_SW_INIT_LOGIC);
 			value |= BIT(aio->portnum);
-			writel(value, aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+			writel(value, aio->i2s_in + IOP_SW_INIT_LOGIC);
 		}
 
 		/* If both playback and capture are off */
 		if (aio->streams_on == 0) {
-			value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
+			value = readl(aio->audio + aio->regs.i2s_cfg);
 			value &= ~BIT(I2S_OUT_CFGX_DATA_ENABLE);
 			value &= ~BIT(I2S_OUT_CFGX_CLK_ENA);
-			writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
+			writel(value, aio->audio + aio->regs.i2s_cfg);
 		}
 
 		break;
 	case PORT_SPDIF:
-		value = readl(aio->cygaud->audio + SPDIF_FORMAT_CFG_OFFSET);
+		value = readl(aio->audio + SPDIF_FORMAT_CFG_OFFSET);
 		value &= ~0x3;
-		writel(value, aio->cygaud->audio + SPDIF_FORMAT_CFG_OFFSET);
-		writel(0, aio->cygaud->audio + aio->regs.bf_sourcech_ctrl);
+		writel(value, aio->audio + SPDIF_FORMAT_CFG_OFFSET);
+		writel(0, aio->audio + aio->regs.bf_sourcech_ctrl);
 
-		value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		value = readl(aio->audio + aio->regs.bf_sourcech_cfg);
 		value &= ~BIT(BF_SRC_CFGX_SFIFO_ENA);
-		writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		writel(value, aio->audio + aio->regs.bf_sourcech_cfg);
 		break;
 	default:
-		dev_err(aio->cygaud->dev,
-			"Port not supported %d\n", aio->portnum);
+		dev_err(aio->dev, "Port not supported %d\n", aio->portnum);
 		status = -EINVAL;
 	}
 
@@ -565,9 +560,8 @@ static int cygnus_ssp_set_clocks(struct cygnus_aio_port *aio)
 		break;
 
 	default:
-		dev_err(aio->cygaud->dev,
-			"Invalid combination of MCLK and BCLK\n");
-		dev_err(aio->cygaud->dev, "lrclk = %u, bits/frame = %u, mclk = %u\n",
+		dev_err(aio->dev, "Invalid combination of MCLK and BCLK\n");
+		dev_err(aio->dev, "lrclk = %u, bits/frame = %u, mclk = %u\n",
 			aio->lrclk, bits_per_frame, aio->mclk);
 		return -EINVAL;
 	}
@@ -583,28 +577,27 @@ static int cygnus_ssp_set_clocks(struct cygnus_aio_port *aio)
 		sclk /= 32;
 
 		/* Set number of bitclks per frame */
-		value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
+		value = readl(aio->audio + aio->regs.i2s_cfg);
 		value &= ~(mask << I2S_OUT_CFGX_SCLKS_PER_1FS_DIV32);
 		value |= sclk << I2S_OUT_CFGX_SCLKS_PER_1FS_DIV32;
-		writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
-		dev_dbg(aio->cygaud->dev,
-			"SCLKS_PER_1FS_DIV32 = 0x%x\n", value);
+		writel(value, aio->audio + aio->regs.i2s_cfg);
+		dev_dbg(aio->dev, "SCLKS_PER_1FS_DIV32 = 0x%x\n", value);
 		break;
 	case PORT_SPDIF:
 		break;
 	default:
-		dev_err(aio->cygaud->dev, "Unknown port type\n");
+		dev_err(aio->dev, "Unknown port type\n");
 		return -EINVAL;
 	}
 
 	/* Set MCLK_RATE ssp port (spdif and ssp are the same) */
-	value = readl(aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
+	value = readl(aio->audio + aio->regs.i2s_mclk_cfg);
 	value &= ~(0xf << I2S_OUT_MCLKRATE_SHIFT);
 	value |= (mclk_rate << I2S_OUT_MCLKRATE_SHIFT);
-	writel(value, aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
+	writel(value, aio->audio + aio->regs.i2s_mclk_cfg);
 
-	dev_dbg(aio->cygaud->dev, "mclk cfg reg = 0x%x\n", value);
-	dev_dbg(aio->cygaud->dev, "bits per frame = %u, mclk = %u Hz, lrclk = %u Hz\n",
+	dev_dbg(aio->dev, "mclk cfg reg = 0x%x\n", value);
+	dev_dbg(aio->dev, "bits per frame = %u, mclk = %u Hz, lrclk = %u Hz\n",
 			bits_per_frame, aio->mclk, aio->lrclk);
 	return 0;
 }
@@ -619,11 +612,10 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 	u32 mask;
 	int ret = 0;
 
-	dev_dbg(aio->cygaud->dev, "%s port = %d\n", __func__, aio->portnum);
-	dev_dbg(aio->cygaud->dev, "params_channels %d\n",
-			params_channels(params));
-	dev_dbg(aio->cygaud->dev, "rate %d\n", params_rate(params));
-	dev_dbg(aio->cygaud->dev, "format %d\n", params_format(params));
+	dev_dbg(aio->dev, "%s port = %d\n", __func__, aio->portnum);
+	dev_dbg(aio->dev, "params_channels %d\n", params_channels(params));
+	dev_dbg(aio->dev, "rate %d\n", params_rate(params));
+	dev_dbg(aio->dev, "format %d\n", params_format(params));
 
 	rate = params_rate(params);
 
@@ -631,14 +623,14 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 	case CYGNUS_SSPMODE_TDM:
 		/* It's expected that set_dai_tdm_slot has been called */
 		if ((rate == 192000) && (params_channels(params) > 4)) {
-			dev_err(aio->cygaud->dev, "Cannot run %d channels at %dHz\n",
+			dev_err(aio->dev, "Cannot run %d channels at %dHz\n",
 				params_channels(params), rate);
 			return -EINVAL;
 		}
 		break;
 	case CYGNUS_SSPMODE_I2S:
 		if (params_channels(params) != 2) {
-			dev_err(aio->cygaud->dev, "i2s mode must use 2 channels\n");
+			dev_err(aio->dev, "i2s mode must use 2 channels\n");
 			return -EINVAL;
 		}
 
@@ -648,16 +640,15 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 
 		break;
 	default:
-		dev_err(aio->cygaud->dev,
-			"%s port running in unknown mode\n", __func__);
+		dev_err(aio->dev, "%s unknown mode\n", __func__);
 		return -EINVAL;
 	}
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		value = readl(aio->audio + aio->regs.bf_sourcech_cfg);
 		value &= ~BIT(BF_SRC_CFGX_BUFFER_PAIR_ENABLE);
 		value &= ~BIT(BF_SRC_CFGX_SAMPLE_CH_MODE);
-		writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		writel(value, aio->audio + aio->regs.bf_sourcech_cfg);
 
 		switch (params_format(params)) {
 		case SNDRV_PCM_FORMAT_S16_LE:
@@ -675,38 +666,34 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 		}
 
 		mask = BF_SRC_CFGX_BITRES_MASK;
-		value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		value = readl(aio->audio + aio->regs.bf_sourcech_cfg);
 		value &= ~(mask << BF_SRC_CFGX_BIT_RES);
 		value |= (bitres << BF_SRC_CFGX_BIT_RES);
-		writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		writel(value, aio->audio + aio->regs.bf_sourcech_cfg);
 
 		/* Only needed for LSB mode, ignored for MSB */
 		mask = I2S_OUT_CFGX_BIT_PER_SAMPLE_MASK;
-		value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
+		value = readl(aio->audio + aio->regs.i2s_cfg);
 		value &= ~(mask << I2S_OUT_CFGX_BITS_PER_SAMPLE);
 		value |= (bits_per_sample << I2S_OUT_CFGX_BITS_PER_SAMPLE);
-		writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
+		writel(value, aio->audio + aio->regs.i2s_cfg);
 	} else {
 
 		switch (params_format(params)) {
 		case SNDRV_PCM_FORMAT_S16_LE:
 			bits_per_sample = 16;
 
-			value = readl(aio->cygaud->audio +
-					aio->regs.bf_destch_cfg);
+			value = readl(aio->audio + aio->regs.bf_destch_cfg);
 			value |= BIT(BF_DST_CFGX_CAP_MODE);
-			writel(value, aio->cygaud->audio +
-					aio->regs.bf_destch_cfg);
+			writel(value, aio->audio + aio->regs.bf_destch_cfg);
 			break;
 
 		case SNDRV_PCM_FORMAT_S32_LE:
 			bits_per_sample = 24; /* Only 24 valid bits */
 
-			value = readl(aio->cygaud->audio +
-					aio->regs.bf_destch_cfg);
+			value = readl(aio->audio + aio->regs.bf_destch_cfg);
 			value &= ~BIT(BF_DST_CFGX_CAP_MODE);
-			writel(value, aio->cygaud->audio +
-					aio->regs.bf_destch_cfg);
+			writel(value, aio->audio + aio->regs.bf_destch_cfg);
 			break;
 
 		default:
@@ -715,10 +702,10 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 
 		/* Used for both LSB and MSB modes */
 		mask = I2S_IN_CFGX_BIT_PER_SAMPLE_MASK;
-		value = readl(aio->cygaud->i2s_in + aio->regs.i2s_cap_cfg);
+		value = readl(aio->i2s_in + aio->regs.i2s_cap_cfg);
 		value &= ~(mask << I2S_IN_CFGX_BITS_PER_SAMPLE);
 		value |= (bits_per_sample << I2S_IN_CFGX_BITS_PER_SAMPLE);
-		writel(value, aio->cygaud->i2s_in + aio->regs.i2s_cap_cfg);
+		writel(value, aio->i2s_in + aio->regs.i2s_cap_cfg);
 	}
 
 	/* Put output port into reset prior to configuring.
@@ -741,13 +728,13 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 			 * in the same state for our first transfer as it is
 			 * every transfer.
 			 */
-			value = readl(aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+			value = readl(aio->i2s_in + IOP_SW_INIT_LOGIC);
 			value |= BIT(aio->portnum);
-			writel(value, aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+			writel(value, aio->i2s_in + IOP_SW_INIT_LOGIC);
 
-			value = readl(aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+			value = readl(aio->i2s_in + IOP_SW_INIT_LOGIC);
 			value |= BIT(IOP_LOGIC_RESET_IN_OFFSET(aio->portnum));
-			writel(value, aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+			writel(value, aio->i2s_in + IOP_SW_INIT_LOGIC);
 		}
 
 		if (aio->port_type != PORT_SPDIF)
@@ -790,52 +777,49 @@ static int cygnus_ssp_set_sysclk(struct snd_soc_dai *dai,
 	long rate;
 	struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai);
 
-	dev_dbg(aio->cygaud->dev,
-		"%s Enter port = %d\n", __func__, aio->portnum);
+	dev_dbg(aio->dev, "%s Enter port = %d\n", __func__, aio->portnum);
 
 	/*
 	 * This should not happen, but the machine file may inadvertently
 	 * call set_sysclk without configuring a clock via the devicetree.
 	 */
 	if (!aio->clk_info.audio_clk) {
-		dev_err(aio->cygaud->dev,
-			"%s Error. No clock assigned.\n", __func__);
+		dev_err(aio->dev, "%s Error. No clock assigned.\n", __func__);
 		return -ENODEV;
 	}
 
 	rate = clk_round_rate(aio->clk_info.audio_clk, freq);
 	if (rate < 0) {
-		dev_err(aio->cygaud->dev, "%s Error with with clock %ld.\n",
+		dev_err(aio->dev, "%s Error with with clock %ld.\n",
 			__func__, rate);
 		return rate;
 	}
 
 	if (!mclk_in_range(freq, rate)) {
-		dev_err(aio->cygaud->dev, "%s Can not set rate to %u  actual %ld.\n",
+		dev_err(aio->dev, "%s Can not set rate to %u  actual %ld.\n",
 			__func__, freq, rate);
 		return -EINVAL;
 	}
 
 	ret = clk_set_rate(aio->clk_info.audio_clk, freq);
 	if (ret) {
-		dev_err(aio->cygaud->dev,
-			"%s Set MCLK rate fail %d\n", __func__, ret);
+		dev_err(aio->dev, "%s Set MCLK rate fail %d\n", __func__, ret);
 		return ret;
 	}
 
 	aio->mclk = freq;
 	sel = aio->clk_info.clk_mux;
 
-	dev_dbg(aio->cygaud->dev, "%s Setting MCLKSEL to %d\n", __func__, sel);
-	value = readl(aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
+	dev_dbg(aio->dev, "%s Setting MCLKSEL to %d\n", __func__, sel);
+	value = readl(aio->audio + aio->regs.i2s_mclk_cfg);
 	value &= ~(0xf << I2S_OUT_PLLCLKSEL_SHIFT);
 	value |= (sel << I2S_OUT_PLLCLKSEL_SHIFT);
-	writel(value, aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
+	writel(value, aio->audio + aio->regs.i2s_mclk_cfg);
 
 	/* Clear bit for active */
-	value = readl(aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
+	value = readl(aio->audio + AUD_MISC_SEROUT_OE_REG_BASE);
 	value &= ~BIT(AUD_MISC_SEROUT_MCLK_OE + (aio->portnum * 4));
-	writel(value, aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
+	writel(value, aio->audio + AUD_MISC_SEROUT_OE_REG_BASE);
 
 	return 0;
 }
@@ -883,7 +867,7 @@ static int cygnus_ssp_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 	u32 val;
 	u32 mask;
 
-	dev_dbg(aio->cygaud->dev, "%s Enter  fmt: %x\n", __func__, fmt);
+	dev_dbg(aio->dev, "%s Enter  fmt: %x\n", __func__, fmt);
 
 	if (aio->port_type == PORT_SPDIF)
 		return -EINVAL;
@@ -912,7 +896,7 @@ static int cygnus_ssp_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 			aio->fs_delay = 1;
 		else {
 			if (aio->is_slave) {
-				dev_err(aio->cygaud->dev,
+				dev_err(aio->dev,
 				"%s DSP_B mode not supported while slave.\n",
 					__func__);
 				return -EINVAL;
@@ -929,7 +913,7 @@ static int cygnus_ssp_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 	/* We must be i2s master to invert any clock */
 	if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) {
 		if (aio->is_slave || (aio->mode == CYGNUS_SSPMODE_TDM)) {
-			dev_err(aio->cygaud->dev,
+			dev_err(aio->dev,
 			"%s Can only invert clocks in i2s master mode\n",
 				__func__);
 			return -EINVAL;
@@ -957,7 +941,7 @@ static int cygnus_ssp_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 		return -EINVAL;
 	}
 
-	val = readl(aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
+	val = readl(aio->audio + AUD_MISC_SEROUT_OE_REG_BASE);
 
 	/*
 	 * Configure the word clk and bit clk as output or tristate
@@ -972,8 +956,8 @@ static int cygnus_ssp_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 	else
 		val &= ~mask;  /* Clear bit for drive */
 
-	dev_dbg(aio->cygaud->dev, "%s  Set OE bits 0x%x\n", __func__, val);
-	writel(val, aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
+	dev_dbg(aio->dev, "%s  Set OE bits 0x%x\n", __func__, val);
+	writel(val, aio->audio + AUD_MISC_SEROUT_OE_REG_BASE);
 
 	return 0;
 }
@@ -983,7 +967,7 @@ static int cygnus_ssp_trigger(struct snd_pcm_substream *substream, int cmd,
 {
 	struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai);
 
-	dev_dbg(aio->cygaud->dev,
+	dev_dbg(aio->dev,
 		"%s cmd %d at port = %d\n", __func__, cmd, aio->portnum);
 
 	switch (cmd) {
@@ -1023,8 +1007,7 @@ static int cygnus_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
 	unsigned int i;
 
 	if (tx_mask != rx_mask) {
-		dev_err(aio->cygaud->dev,
-			"%s tx_mask must equal rx_mask\n", __func__);
+		dev_err(aio->dev, "%s tx_mask must equal rx_mask\n", __func__);
 		return -EINVAL;
 	}
 
@@ -1050,8 +1033,7 @@ static int cygnus_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
 	}
 
 	if (!found) {
-		dev_err(aio->cygaud->dev,
-			"%s In TDM mode, frame bits INVALID (%d)\n",
+		dev_err(aio->dev, "%s In TDM mode, frame bits INVALID (%d)\n",
 			__func__, bits_per_frame);
 		return -EINVAL;
 	}
@@ -1060,7 +1042,7 @@ static int cygnus_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
 	aio->slot_width = slot_width;
 	aio->slots_per_frame = slots;
 
-	dev_dbg(aio->cygaud->dev, "%s active_slots %u, bits per frame %d\n",
+	dev_dbg(aio->dev, "%s active_slots %u, bits per frame %d\n",
 			__func__, aio->active_slots, bits_per_frame);
 	return 0;
 }
@@ -1074,7 +1056,7 @@ static int cygnus_ssp_set_pll(struct snd_soc_dai *cpu_dai, int pll_id,
 	int ret = 0;
 
 	if (!aio->clk_info.audio_clk) {
-		dev_err(aio->cygaud->dev,
+		dev_err(aio->dev,
 			"%s: port %d does not have an assigned clock.\n",
 			__func__, aio->portnum);
 		return -ENODEV;
@@ -1082,7 +1064,7 @@ static int cygnus_ssp_set_pll(struct snd_soc_dai *cpu_dai, int pll_id,
 
 	clk_pll = clk_get_parent(aio->clk_info.audio_clk);
 	if (IS_ERR(clk_pll)) {
-		dev_err(aio->cygaud->dev,
+		dev_err(aio->dev,
 			"%s: could not get audiopll clock.\n", __func__);
 		return -ENODEV;
 	}
@@ -1185,7 +1167,7 @@ static void update_ssp_cfg(struct cygnus_aio_port *aio)
 	 * bit set in the Tx formatter (which would be the Tx Formatters
 	 * internal clock or signal from external pin).
 	 */
-	ssp_curcfg = readl(aio->cygaud->i2s_in + aio->regs.i2s_cap_cfg);
+	ssp_curcfg = readl(aio->i2s_in + aio->regs.i2s_cap_cfg);
 	ssp_incfg = (ssp_curcfg & I2S_IN_CFG_REG_UPDATE_MASK) | ssp_newcfg;
 	ssp_incfg |= BIT(I2S_OUT_CFGX_SLAVE_MODE);
 
@@ -1194,13 +1176,13 @@ static void update_ssp_cfg(struct cygnus_aio_port *aio)
 	ssp_incfg &= ~BIT(I2S_OUT_CFGX_BITS_PER_SLOT);
 	ssp_incfg |= (bits_per_slot_in << I2S_OUT_CFGX_BITS_PER_SLOT);
 
-	writel(ssp_incfg, aio->cygaud->i2s_in + aio->regs.i2s_cap_cfg);
+	writel(ssp_incfg, aio->i2s_in + aio->regs.i2s_cap_cfg);
 
 	/*
 	 * SSP out cfg.
 	 * Retain bits we do not want to update, then OR in new bits
 	 */
-	ssp_curcfg = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
+	ssp_curcfg = readl(aio->audio + aio->regs.i2s_cfg);
 	ssp_outcfg = (ssp_curcfg & I2S_OUT_CFG_REG_UPDATE_MASK) | ssp_newcfg;
 
 	ssp_outcfg &= ~(0xf << I2S_OUT_CFGX_VALID_SLOT);
@@ -1208,7 +1190,7 @@ static void update_ssp_cfg(struct cygnus_aio_port *aio)
 	ssp_outcfg &= ~BIT(I2S_OUT_CFGX_BITS_PER_SLOT);
 	ssp_outcfg |= (bits_per_slot_out << I2S_OUT_CFGX_BITS_PER_SLOT);
 
-	writel(ssp_outcfg, aio->cygaud->audio + aio->regs.i2s_cfg);
+	writel(ssp_outcfg, aio->audio + aio->regs.i2s_cfg);
 }
 
 
@@ -1320,7 +1302,9 @@ static int parse_ssp_child_node(struct platform_device *pdev,
 	}
 
 	aio = &cygaud->portinfo[portnum];
-	aio->cygaud = cygaud;
+
+	aio->audio = cygaud->audio;
+	aio->i2s_in = cygaud->i2s_in;
 	aio->portnum = portnum;
 	aio->port_type = port_type;
 	aio->fsync_width = -1;
@@ -1349,8 +1333,7 @@ static int parse_ssp_child_node(struct platform_device *pdev,
 
 	dev_dbg(&pdev->dev, "%s portnum = %d\n", __func__, aio->portnum);
 	aio->streams_on = 0;
-	aio->cygaud->dev = &pdev->dev;
-
+	aio->dev = &pdev->dev;
 
 	aio->clk_info.audio_clk = NULL;
 
@@ -1421,7 +1404,6 @@ static int cygnus_ssp_probe(struct platform_device *pdev)
 	}
 
 	active_port_count = 0;
-
 	for_each_available_child_of_node(pdev->dev.of_node, child_node) {
 		err = parse_ssp_child_node(pdev, child_node, cygaud,
 					&cygnus_ssp_dai[active_port_count]);
diff --git a/sound/soc/bcm/cygnus-ssp.h b/sound/soc/bcm/cygnus-ssp.h
index 648321d..ac346b8 100644
--- a/sound/soc/bcm/cygnus-ssp.h
+++ b/sound/soc/bcm/cygnus-ssp.h
@@ -32,13 +32,13 @@
 #define PROP_LEN_MAX 40
 
 struct ringbuf_regs {
-	unsigned rdaddr;
-	unsigned wraddr;
-	unsigned baseaddr;
-	unsigned endaddr;
-	unsigned fmark;   /* freemark for play, fullmark for caputure */
-	unsigned period_bytes;
-	unsigned buf_size;
+	unsigned int rdaddr;
+	unsigned int wraddr;
+	unsigned int baseaddr;
+	unsigned int endaddr;
+	unsigned int fmark;   /* freemark for play, fullmark for caputure */
+	u32 period_bytes;
+	u32 buf_size;
 };
 
 #define RINGBUF_REG_PLAYBACK(num) ((struct ringbuf_regs) { \
@@ -85,6 +85,8 @@ struct cygnus_audio_clkinfo {
 };
 
 struct cygnus_aio_port {
+	struct device *dev;
+
 	int portnum;
 	int mode;
 	bool is_slave;
@@ -104,7 +106,9 @@ struct cygnus_aio_port {
 	unsigned int slots_per_frame;
 	unsigned int active_slots;
 
-	struct cygnus_audio *cygaud;
+	void __iomem *audio;
+	void __iomem *i2s_in;
+
 	struct cygnus_ssp_regs regs;
 
 	struct ringbuf_regs play_rb_regs;
@@ -122,8 +126,8 @@ struct cygnus_audio {
 
 	int irq_num;
 	void __iomem *audio;
-	struct device *dev;
 	void __iomem *i2s_in;
+	struct device *dev;
 };
 
 extern int cygnus_ssp_set_custom_fsync_width(struct snd_soc_dai *cpu_dai,
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH 9/9] ASoC: cygnus: Tidy up of structure access
@ 2017-08-14 22:06   ` Lori Hikichi
  0 siblings, 0 replies; 50+ messages in thread
From: Lori Hikichi @ 2017-08-14 22:06 UTC (permalink / raw)
  To: linux-arm-kernel

Adds copies of the frequently accessed io handles to each ports
data structure, making it more convenient to access.  Also, a small
cleanup to the type names used in cygnus_pcm.  None of this should
result in a functional change to the driver.

Signed-off-by: Lori Hikichi <lori.hikichi@broadcom.com>
---
 sound/soc/bcm/cygnus-pcm.c |  50 ++++----
 sound/soc/bcm/cygnus-ssp.c | 298 +++++++++++++++++++++------------------------
 sound/soc/bcm/cygnus-ssp.h |  22 ++--
 3 files changed, 178 insertions(+), 192 deletions(-)

diff --git a/sound/soc/bcm/cygnus-pcm.c b/sound/soc/bcm/cygnus-pcm.c
index d616e096..d82bf55 100644
--- a/sound/soc/bcm/cygnus-pcm.c
+++ b/sound/soc/bcm/cygnus-pcm.c
@@ -329,24 +329,24 @@ static void enable_intr(struct snd_pcm_substream *substream)
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		/* Clear interrupt status before enabling them */
-		writel(clear_mask, aio->cygaud->audio + ESR0_STATUS_CLR_OFFSET);
-		writel(clear_mask, aio->cygaud->audio + ESR1_STATUS_CLR_OFFSET);
-		writel(clear_mask, aio->cygaud->audio + ESR3_STATUS_CLR_OFFSET);
+		writel(clear_mask, aio->audio + ESR0_STATUS_CLR_OFFSET);
+		writel(clear_mask, aio->audio + ESR1_STATUS_CLR_OFFSET);
+		writel(clear_mask, aio->audio + ESR3_STATUS_CLR_OFFSET);
 		/* Unmask the interrupts of the given port*/
-		writel(clear_mask, aio->cygaud->audio + ESR0_MASK_CLR_OFFSET);
-		writel(clear_mask, aio->cygaud->audio + ESR1_MASK_CLR_OFFSET);
-		writel(clear_mask, aio->cygaud->audio + ESR3_MASK_CLR_OFFSET);
+		writel(clear_mask, aio->audio + ESR0_MASK_CLR_OFFSET);
+		writel(clear_mask, aio->audio + ESR1_MASK_CLR_OFFSET);
+		writel(clear_mask, aio->audio + ESR3_MASK_CLR_OFFSET);
 
 		writel(ANY_PLAYBACK_IRQ,
-			aio->cygaud->audio + INTH_R5F_MASK_CLEAR_OFFSET);
+			aio->audio + INTH_R5F_MASK_CLEAR_OFFSET);
 	} else {
-		writel(clear_mask, aio->cygaud->audio + ESR2_STATUS_CLR_OFFSET);
-		writel(clear_mask, aio->cygaud->audio + ESR4_STATUS_CLR_OFFSET);
-		writel(clear_mask, aio->cygaud->audio + ESR2_MASK_CLR_OFFSET);
-		writel(clear_mask, aio->cygaud->audio + ESR4_MASK_CLR_OFFSET);
+		writel(clear_mask, aio->audio + ESR2_STATUS_CLR_OFFSET);
+		writel(clear_mask, aio->audio + ESR4_STATUS_CLR_OFFSET);
+		writel(clear_mask, aio->audio + ESR2_MASK_CLR_OFFSET);
+		writel(clear_mask, aio->audio + ESR4_MASK_CLR_OFFSET);
 
 		writel(ANY_CAPTURE_IRQ,
-			aio->cygaud->audio + INTH_R5F_MASK_CLEAR_OFFSET);
+			aio->audio + INTH_R5F_MASK_CLEAR_OFFSET);
 	}
 
 }
@@ -366,12 +366,12 @@ static void disable_intr(struct snd_pcm_substream *substream)
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		/* Mask the interrupts of the given port*/
-		writel(set_mask, aio->cygaud->audio + ESR0_MASK_SET_OFFSET);
-		writel(set_mask, aio->cygaud->audio + ESR1_MASK_SET_OFFSET);
-		writel(set_mask, aio->cygaud->audio + ESR3_MASK_SET_OFFSET);
+		writel(set_mask, aio->audio + ESR0_MASK_SET_OFFSET);
+		writel(set_mask, aio->audio + ESR1_MASK_SET_OFFSET);
+		writel(set_mask, aio->audio + ESR3_MASK_SET_OFFSET);
 	} else {
-		writel(set_mask, aio->cygaud->audio + ESR2_MASK_SET_OFFSET);
-		writel(set_mask, aio->cygaud->audio + ESR4_MASK_SET_OFFSET);
+		writel(set_mask, aio->audio + ESR2_MASK_SET_OFFSET);
+		writel(set_mask, aio->audio + ESR4_MASK_SET_OFFSET);
 	}
 
 }
@@ -415,13 +415,13 @@ static void cygnus_pcm_period_elapsed(struct snd_pcm_substream *substream)
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		/* Set the ring buffer to full */
-		regval = readl(aio->cygaud->audio + p_rbuf->rdaddr);
+		regval = readl(aio->audio + p_rbuf->rdaddr);
 		regval = regval ^ BIT(31);
-		writel(regval, aio->cygaud->audio + p_rbuf->wraddr);
+		writel(regval, aio->audio + p_rbuf->wraddr);
 	} else {
 		/* Set the ring buffer to empty */
-		regval = readl(aio->cygaud->audio + p_rbuf->wraddr);
-		writel(regval, aio->cygaud->audio + p_rbuf->rdaddr);
+		regval = readl(aio->audio + p_rbuf->wraddr);
+		writel(regval, aio->audio + p_rbuf->rdaddr);
 	}
 }
 
@@ -690,7 +690,7 @@ static int cygnus_pcm_prepare(struct snd_pcm_substream *substream)
 
 	is_play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? 1 : 0;
 
-	ringbuf_set_initial(aio->cygaud->audio, p_rbuf, is_play, start,
+	ringbuf_set_initial(aio->audio, p_rbuf, is_play, start,
 				periodsize, bufsize);
 
 	return ret;
@@ -710,11 +710,11 @@ static snd_pcm_uframes_t cygnus_pcm_pointer(struct snd_pcm_substream *substream)
 	 */
 	p_rbuf = get_ringbuf(substream);
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		cur = readl(aio->cygaud->audio + p_rbuf->rdaddr);
+		cur = readl(aio->audio + p_rbuf->rdaddr);
 	else
-		cur = readl(aio->cygaud->audio + p_rbuf->wraddr);
+		cur = readl(aio->audio + p_rbuf->wraddr);
 
-	base = readl(aio->cygaud->audio + p_rbuf->baseaddr);
+	base = readl(aio->audio + p_rbuf->baseaddr);
 
 	/*
 	 * Mask off the MSB of the rdaddr,wraddr and baseaddr
diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c
index 97bf67a..7535613 100644
--- a/sound/soc/bcm/cygnus-ssp.c
+++ b/sound/soc/bcm/cygnus-ssp.c
@@ -226,78 +226,76 @@ static int audio_ssp_init_portregs(struct cygnus_aio_port *aio)
 	int status = 0;
 
 	/* Set Group ID */
-	writel(0, aio->cygaud->audio + BF_SRC_GRP0_OFFSET);
-	writel(1, aio->cygaud->audio + BF_SRC_GRP1_OFFSET);
-	writel(2, aio->cygaud->audio + BF_SRC_GRP2_OFFSET);
-	writel(3, aio->cygaud->audio + BF_SRC_GRP3_OFFSET);
+	writel(0, aio->audio + BF_SRC_GRP0_OFFSET);
+	writel(1, aio->audio + BF_SRC_GRP1_OFFSET);
+	writel(2, aio->audio + BF_SRC_GRP2_OFFSET);
+	writel(3, aio->audio + BF_SRC_GRP3_OFFSET);
 
 	switch (aio->port_type) {
 	case PORT_TDM:
-		value = readl(aio->cygaud->audio + aio->regs.i2s_stream_cfg);
+		value = readl(aio->audio + aio->regs.i2s_stream_cfg);
 		value &= ~I2S_STREAM_CFG_MASK;
 
 		/* Configure the AUD_FMM_IOP_OUT_I2S_x_STREAM_CFG reg */
 		value |= aio->portnum << I2S_OUT_STREAM_CFG_GROUP_ID;
 		value |= aio->portnum; /* FCI ID is the port num */
 		value |= CH_GRP_STEREO << I2S_OUT_STREAM_CFG_CHANNEL_GROUPING;
-		writel(value, aio->cygaud->audio + aio->regs.i2s_stream_cfg);
+		writel(value, aio->audio + aio->regs.i2s_stream_cfg);
 
 		/* Configure the AUD_FMM_BF_CTRL_SOURCECH_CFGX reg */
-		value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		value = readl(aio->audio + aio->regs.bf_sourcech_cfg);
 		value &= ~BIT(BF_SRC_CFGX_NOT_PAUSE_WHEN_EMPTY);
 		value &= ~BIT(BF_SRC_CFGX_SAMPLE_REPEAT_ENABLE);
 		value |= BIT(BF_SRC_CFGX_SFIFO_SZ_DOUBLE);
 		value |= BIT(BF_SRC_CFGX_PROCESS_SEQ_ID_VALID);
-		writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		writel(value, aio->audio + aio->regs.bf_sourcech_cfg);
 
 		/* Configure the AUD_FMM_IOP_IN_I2S_x_CAP_STREAM_CFG_0 reg */
-		value = readl(aio->cygaud->i2s_in +
-			aio->regs.i2s_cap_stream_cfg);
+		value = readl(aio->i2s_in + aio->regs.i2s_cap_stream_cfg);
 		value &= ~I2S_CAP_STREAM_CFG_MASK;
 		value |= aio->portnum << I2S_IN_STREAM_CFG_0_GROUP_ID;
-		writel(value, aio->cygaud->i2s_in +
-			aio->regs.i2s_cap_stream_cfg);
+		writel(value, aio->i2s_in + aio->regs.i2s_cap_stream_cfg);
 
 		/* Configure the AUD_FMM_BF_CTRL_DESTCH_CFGX_REG_BASE reg */
 		fci_id = CAPTURE_FCI_ID_BASE + aio->portnum;
 
-		value = readl(aio->cygaud->audio + aio->regs.bf_destch_cfg);
+		value = readl(aio->audio + aio->regs.bf_destch_cfg);
 		value |= BIT(BF_DST_CFGX_DFIFO_SZ_DOUBLE);
 		value &= ~BIT(BF_DST_CFGX_NOT_PAUSE_WHEN_FULL);
 		value |= (fci_id << BF_DST_CFGX_FCI_ID);
 		value |= BIT(BF_DST_CFGX_PROC_SEQ_ID_VALID);
-		writel(value, aio->cygaud->audio + aio->regs.bf_destch_cfg);
+		writel(value, aio->audio + aio->regs.bf_destch_cfg);
 
 		/* Enable the transmit pin for this port */
-		value = readl(aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
+		value = readl(aio->audio + AUD_MISC_SEROUT_OE_REG_BASE);
 		value &= ~BIT((aio->portnum * 4) + AUD_MISC_SEROUT_SDAT_OE);
-		writel(value, aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
+		writel(value, aio->audio + AUD_MISC_SEROUT_OE_REG_BASE);
 		break;
 	case PORT_SPDIF:
-		value = readl(aio->cygaud->audio + SPDIF_CTRL_OFFSET);
+		value = readl(aio->audio + SPDIF_CTRL_OFFSET);
 		value |= BIT(SPDIF_0_OUT_DITHER_ENA);
-		writel(value, aio->cygaud->audio + SPDIF_CTRL_OFFSET);
+		writel(value, aio->audio + SPDIF_CTRL_OFFSET);
 
 		/* Enable and set the FCI ID for the SPDIF channel */
-		value = readl(aio->cygaud->audio + SPDIF_STREAM_CFG_OFFSET);
+		value = readl(aio->audio + SPDIF_STREAM_CFG_OFFSET);
 		value &= ~SPDIF_STREAM_CFG_MASK;
 		value |= aio->portnum; /* FCI ID is the port num */
 		value |= BIT(SPDIF_0_OUT_STREAM_ENA);
-		writel(value, aio->cygaud->audio + SPDIF_STREAM_CFG_OFFSET);
+		writel(value, aio->audio + SPDIF_STREAM_CFG_OFFSET);
 
-		value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		value = readl(aio->audio + aio->regs.bf_sourcech_cfg);
 		value &= ~BIT(BF_SRC_CFGX_NOT_PAUSE_WHEN_EMPTY);
 		value |= BIT(BF_SRC_CFGX_SFIFO_SZ_DOUBLE);
 		value |= BIT(BF_SRC_CFGX_PROCESS_SEQ_ID_VALID);
-		writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		writel(value, aio->audio + aio->regs.bf_sourcech_cfg);
 
 		/* Enable the spdif output pin */
-		value = readl(aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
+		value = readl(aio->audio + AUD_MISC_SEROUT_OE_REG_BASE);
 		value &= ~BIT(AUD_MISC_SEROUT_SPDIF_OE);
-		writel(value, aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
+		writel(value, aio->audio + AUD_MISC_SEROUT_OE_REG_BASE);
 		break;
 	default:
-		dev_err(aio->cygaud->dev, "Port not supported\n");
+		dev_err(aio->dev, "Port not supported\n");
 		status = -EINVAL;
 	}
 
@@ -308,24 +306,24 @@ static void audio_ssp_in_enable(struct cygnus_aio_port *aio)
 {
 	u32 value;
 
-	value = readl(aio->cygaud->audio + aio->regs.bf_destch_cfg);
+	value = readl(aio->audio + aio->regs.bf_destch_cfg);
 	value |= BIT(BF_DST_CFGX_CAP_ENA);
-	writel(value, aio->cygaud->audio + aio->regs.bf_destch_cfg);
+	writel(value, aio->audio + aio->regs.bf_destch_cfg);
 
 	/*
 	 * DATA_ENABLE need to be set even if doing capture.
 	 * Subsequent Tx will fail if this is not done.
 	 */
 	if (!aio->streams_on) {
-		value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
+		value = readl(aio->audio + aio->regs.i2s_cfg);
 		value |= BIT(I2S_OUT_CFGX_CLK_ENA);
 		value |= BIT(I2S_OUT_CFGX_DATA_ENABLE);
-		writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
+		writel(value, aio->audio + aio->regs.i2s_cfg);
 	}
 
-	value = readl(aio->cygaud->i2s_in + aio->regs.i2s_cap_stream_cfg);
+	value = readl(aio->i2s_in + aio->regs.i2s_cap_stream_cfg);
 	value |= BIT(I2S_IN_STREAM_CFG_CAP_ENA);
-	writel(value, aio->cygaud->i2s_in + aio->regs.i2s_cap_stream_cfg);
+	writel(value, aio->i2s_in + aio->regs.i2s_cap_stream_cfg);
 
 	/* Enable input portion of block */
 	udelay(10);
@@ -334,12 +332,11 @@ static void audio_ssp_in_enable(struct cygnus_aio_port *aio)
 	 * The input port may or may not be held in reset. Always clear
 	 * the reset. This will be benign if the port is not in reset.
 	 */
-	value = readl(aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+	value = readl(aio->i2s_in + IOP_SW_INIT_LOGIC);
 	value &= ~BIT(IOP_LOGIC_RESET_IN_OFFSET(aio->portnum));
-	writel(value, aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+	writel(value, aio->i2s_in + IOP_SW_INIT_LOGIC);
 
-	writel(BF_DESTCH_CTRLX_CAP_RUN,
-		aio->cygaud->audio + aio->regs.bf_destch_ctrl);
+	writel(BF_DESTCH_CTRLX_CAP_RUN, aio->audio + aio->regs.bf_destch_ctrl);
 
 	aio->streams_on |= CAPTURE_STREAM_MASK;
 }
@@ -348,17 +345,17 @@ static void audio_ssp_in_disable(struct cygnus_aio_port *aio)
 {
 	u32 value;
 
-	value = readl(aio->cygaud->audio + aio->regs.bf_destch_cfg);
+	value = readl(aio->audio + aio->regs.bf_destch_cfg);
 	value &= ~BIT(BF_DST_CFGX_CAP_ENA);
-	writel(value, aio->cygaud->audio + aio->regs.bf_destch_cfg);
+	writel(value, aio->audio + aio->regs.bf_destch_cfg);
 
-	value = readl(aio->cygaud->i2s_in + aio->regs.i2s_cap_stream_cfg);
+	value = readl(aio->i2s_in + aio->regs.i2s_cap_stream_cfg);
 	value &= ~BIT(I2S_IN_STREAM_CFG_CAP_ENA);
-	writel(value, aio->cygaud->i2s_in + aio->regs.i2s_cap_stream_cfg);
+	writel(value, aio->i2s_in + aio->regs.i2s_cap_stream_cfg);
 
 	aio->streams_on &= ~CAPTURE_STREAM_MASK;
 
-	writel(0x0, aio->cygaud->audio + aio->regs.bf_destch_ctrl);
+	writel(0x0, aio->audio + aio->regs.bf_destch_ctrl);
 
 	/*
 	 * Put input portion of port in reset.
@@ -375,9 +372,9 @@ static void audio_ssp_in_disable(struct cygnus_aio_port *aio)
 	 *
 	 */
 	if (aio->mode == CYGNUS_SSPMODE_TDM) {
-		value = readl(aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+		value = readl(aio->i2s_in + IOP_SW_INIT_LOGIC);
 		value |= BIT(IOP_LOGIC_RESET_IN_OFFSET(aio->portnum));
-		writel(value, aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+		writel(value, aio->i2s_in + IOP_SW_INIT_LOGIC);
 	}
 
 	/* If both playback and capture are off */
@@ -387,10 +384,10 @@ static void audio_ssp_in_disable(struct cygnus_aio_port *aio)
 		 * Need 1 bit clock tick for INIT_LOGIC to activate
 		 */
 		udelay(10);
-		value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
+		value = readl(aio->audio + aio->regs.i2s_cfg);
 		value &= ~BIT(I2S_OUT_CFGX_CLK_ENA);
 		value &= ~BIT(I2S_OUT_CFGX_DATA_ENABLE);
-		writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
+		writel(value, aio->audio + aio->regs.i2s_cfg);
 	}
 }
 
@@ -401,52 +398,51 @@ static int audio_ssp_out_enable(struct cygnus_aio_port *aio)
 
 	switch (aio->port_type) {
 	case PORT_TDM:
-		value = readl(aio->cygaud->audio + aio->regs.i2s_stream_cfg);
+		value = readl(aio->audio + aio->regs.i2s_stream_cfg);
 		value &= ~(I2S_OUT_STREAM_CFG_FCI_ID_MASK);
 		value |= aio->portnum;
-		writel(value, aio->cygaud->audio + aio->regs.i2s_stream_cfg);
+		writel(value, aio->audio + aio->regs.i2s_stream_cfg);
 
-		value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		value = readl(aio->audio + aio->regs.bf_sourcech_cfg);
 		value |= BIT(BF_SRC_CFGX_SFIFO_ENA);
-		writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		writel(value, aio->audio + aio->regs.bf_sourcech_cfg);
 
 		writel(BIT(BF_SOURCECH_CTRL_PLAY_RUN),
-			aio->cygaud->audio + aio->regs.bf_sourcech_ctrl);
+			aio->audio + aio->regs.bf_sourcech_ctrl);
 
-		value = readl(aio->cygaud->audio + aio->regs.i2s_stream_cfg);
+		value = readl(aio->audio + aio->regs.i2s_stream_cfg);
 		value |= BIT(I2S_OUT_STREAM_ENA);
-		writel(value, aio->cygaud->audio + aio->regs.i2s_stream_cfg);
+		writel(value, aio->audio + aio->regs.i2s_stream_cfg);
 
-		value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
+		value = readl(aio->audio + aio->regs.i2s_cfg);
 		value |= BIT(I2S_OUT_CFGX_CLK_ENA);
 		value |= BIT(I2S_OUT_CFGX_DATA_ENABLE);
-		writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
+		writel(value, aio->audio + aio->regs.i2s_cfg);
 
 		/*
 		 * The output port may or may not be in reset. Always clear
 		 * the reset. This will be benign if the port is not in reset.
 		 */
-		value = readl(aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+		value = readl(aio->i2s_in + IOP_SW_INIT_LOGIC);
 		value &= ~BIT(aio->portnum);
-		writel(value, aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+		writel(value, aio->i2s_in + IOP_SW_INIT_LOGIC);
 
 		aio->streams_on |= PLAYBACK_STREAM_MASK;
 		break;
 	case PORT_SPDIF:
-		value = readl(aio->cygaud->audio + SPDIF_FORMAT_CFG_OFFSET);
+		value = readl(aio->audio + SPDIF_FORMAT_CFG_OFFSET);
 		value |= 0x3;
-		writel(value, aio->cygaud->audio + SPDIF_FORMAT_CFG_OFFSET);
+		writel(value, aio->audio + SPDIF_FORMAT_CFG_OFFSET);
 
 		writel(BIT(BF_SOURCECH_CTRL_PLAY_RUN),
-			aio->cygaud->audio + aio->regs.bf_sourcech_ctrl);
+			aio->audio + aio->regs.bf_sourcech_ctrl);
 
-		value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		value = readl(aio->audio + aio->regs.bf_sourcech_cfg);
 		value |= BIT(BF_SRC_CFGX_SFIFO_ENA);
-		writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		writel(value, aio->audio + aio->regs.bf_sourcech_cfg);
 		break;
 	default:
-		dev_err(aio->cygaud->dev,
-			"Port not supported %d\n", aio->portnum);
+		dev_err(aio->dev, "Port not supported %d\n", aio->portnum);
 		status = -EINVAL;
 	}
 
@@ -463,9 +459,9 @@ static int audio_ssp_out_disable(struct cygnus_aio_port *aio)
 		aio->streams_on &= ~PLAYBACK_STREAM_MASK;
 
 		/* Set the FCI ID to INVALID */
-		value = readl(aio->cygaud->audio + aio->regs.i2s_stream_cfg);
+		value = readl(aio->audio + aio->regs.i2s_stream_cfg);
 		value |= 0x3ff;
-		writel(value, aio->cygaud->audio + aio->regs.i2s_stream_cfg);
+		writel(value, aio->audio + aio->regs.i2s_stream_cfg);
 
 		/*
 		 * We want to wait enough time for 2 LRCLK.
@@ -475,20 +471,20 @@ static int audio_ssp_out_disable(struct cygnus_aio_port *aio)
 		udelay(300);
 
 		/* set group_sync_dis = 1 */
-		value = readl(aio->cygaud->audio + BF_SRC_GRP_SYNC_DIS_OFFSET);
+		value = readl(aio->audio + BF_SRC_GRP_SYNC_DIS_OFFSET);
 		value |= BIT(aio->portnum);
-		writel(value, aio->cygaud->audio + BF_SRC_GRP_SYNC_DIS_OFFSET);
+		writel(value, aio->audio + BF_SRC_GRP_SYNC_DIS_OFFSET);
 
-		writel(0, aio->cygaud->audio + aio->regs.bf_sourcech_ctrl);
+		writel(0, aio->audio + aio->regs.bf_sourcech_ctrl);
 
-		value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		value = readl(aio->audio + aio->regs.bf_sourcech_cfg);
 		value &= ~BIT(BF_SRC_CFGX_SFIFO_ENA);
-		writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		writel(value, aio->audio + aio->regs.bf_sourcech_cfg);
 
 		/* set group_sync_dis = 0 */
-		value = readl(aio->cygaud->audio + BF_SRC_GRP_SYNC_DIS_OFFSET);
+		value = readl(aio->audio + BF_SRC_GRP_SYNC_DIS_OFFSET);
 		value &= ~BIT(aio->portnum);
-		writel(value, aio->cygaud->audio + BF_SRC_GRP_SYNC_DIS_OFFSET);
+		writel(value, aio->audio + BF_SRC_GRP_SYNC_DIS_OFFSET);
 
 		/*
 		 * We want to wait enough time for 1 LRCLK.
@@ -498,33 +494,32 @@ static int audio_ssp_out_disable(struct cygnus_aio_port *aio)
 		udelay(175);
 
 		if (aio->is_slave && (aio->mode == CYGNUS_SSPMODE_TDM)) {
-			value = readl(aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+			value = readl(aio->i2s_in + IOP_SW_INIT_LOGIC);
 			value |= BIT(aio->portnum);
-			writel(value, aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+			writel(value, aio->i2s_in + IOP_SW_INIT_LOGIC);
 		}
 
 		/* If both playback and capture are off */
 		if (aio->streams_on == 0) {
-			value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
+			value = readl(aio->audio + aio->regs.i2s_cfg);
 			value &= ~BIT(I2S_OUT_CFGX_DATA_ENABLE);
 			value &= ~BIT(I2S_OUT_CFGX_CLK_ENA);
-			writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
+			writel(value, aio->audio + aio->regs.i2s_cfg);
 		}
 
 		break;
 	case PORT_SPDIF:
-		value = readl(aio->cygaud->audio + SPDIF_FORMAT_CFG_OFFSET);
+		value = readl(aio->audio + SPDIF_FORMAT_CFG_OFFSET);
 		value &= ~0x3;
-		writel(value, aio->cygaud->audio + SPDIF_FORMAT_CFG_OFFSET);
-		writel(0, aio->cygaud->audio + aio->regs.bf_sourcech_ctrl);
+		writel(value, aio->audio + SPDIF_FORMAT_CFG_OFFSET);
+		writel(0, aio->audio + aio->regs.bf_sourcech_ctrl);
 
-		value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		value = readl(aio->audio + aio->regs.bf_sourcech_cfg);
 		value &= ~BIT(BF_SRC_CFGX_SFIFO_ENA);
-		writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		writel(value, aio->audio + aio->regs.bf_sourcech_cfg);
 		break;
 	default:
-		dev_err(aio->cygaud->dev,
-			"Port not supported %d\n", aio->portnum);
+		dev_err(aio->dev, "Port not supported %d\n", aio->portnum);
 		status = -EINVAL;
 	}
 
@@ -565,9 +560,8 @@ static int cygnus_ssp_set_clocks(struct cygnus_aio_port *aio)
 		break;
 
 	default:
-		dev_err(aio->cygaud->dev,
-			"Invalid combination of MCLK and BCLK\n");
-		dev_err(aio->cygaud->dev, "lrclk = %u, bits/frame = %u, mclk = %u\n",
+		dev_err(aio->dev, "Invalid combination of MCLK and BCLK\n");
+		dev_err(aio->dev, "lrclk = %u, bits/frame = %u, mclk = %u\n",
 			aio->lrclk, bits_per_frame, aio->mclk);
 		return -EINVAL;
 	}
@@ -583,28 +577,27 @@ static int cygnus_ssp_set_clocks(struct cygnus_aio_port *aio)
 		sclk /= 32;
 
 		/* Set number of bitclks per frame */
-		value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
+		value = readl(aio->audio + aio->regs.i2s_cfg);
 		value &= ~(mask << I2S_OUT_CFGX_SCLKS_PER_1FS_DIV32);
 		value |= sclk << I2S_OUT_CFGX_SCLKS_PER_1FS_DIV32;
-		writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
-		dev_dbg(aio->cygaud->dev,
-			"SCLKS_PER_1FS_DIV32 = 0x%x\n", value);
+		writel(value, aio->audio + aio->regs.i2s_cfg);
+		dev_dbg(aio->dev, "SCLKS_PER_1FS_DIV32 = 0x%x\n", value);
 		break;
 	case PORT_SPDIF:
 		break;
 	default:
-		dev_err(aio->cygaud->dev, "Unknown port type\n");
+		dev_err(aio->dev, "Unknown port type\n");
 		return -EINVAL;
 	}
 
 	/* Set MCLK_RATE ssp port (spdif and ssp are the same) */
-	value = readl(aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
+	value = readl(aio->audio + aio->regs.i2s_mclk_cfg);
 	value &= ~(0xf << I2S_OUT_MCLKRATE_SHIFT);
 	value |= (mclk_rate << I2S_OUT_MCLKRATE_SHIFT);
-	writel(value, aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
+	writel(value, aio->audio + aio->regs.i2s_mclk_cfg);
 
-	dev_dbg(aio->cygaud->dev, "mclk cfg reg = 0x%x\n", value);
-	dev_dbg(aio->cygaud->dev, "bits per frame = %u, mclk = %u Hz, lrclk = %u Hz\n",
+	dev_dbg(aio->dev, "mclk cfg reg = 0x%x\n", value);
+	dev_dbg(aio->dev, "bits per frame = %u, mclk = %u Hz, lrclk = %u Hz\n",
 			bits_per_frame, aio->mclk, aio->lrclk);
 	return 0;
 }
@@ -619,11 +612,10 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 	u32 mask;
 	int ret = 0;
 
-	dev_dbg(aio->cygaud->dev, "%s port = %d\n", __func__, aio->portnum);
-	dev_dbg(aio->cygaud->dev, "params_channels %d\n",
-			params_channels(params));
-	dev_dbg(aio->cygaud->dev, "rate %d\n", params_rate(params));
-	dev_dbg(aio->cygaud->dev, "format %d\n", params_format(params));
+	dev_dbg(aio->dev, "%s port = %d\n", __func__, aio->portnum);
+	dev_dbg(aio->dev, "params_channels %d\n", params_channels(params));
+	dev_dbg(aio->dev, "rate %d\n", params_rate(params));
+	dev_dbg(aio->dev, "format %d\n", params_format(params));
 
 	rate = params_rate(params);
 
@@ -631,14 +623,14 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 	case CYGNUS_SSPMODE_TDM:
 		/* It's expected that set_dai_tdm_slot has been called */
 		if ((rate == 192000) && (params_channels(params) > 4)) {
-			dev_err(aio->cygaud->dev, "Cannot run %d channels at %dHz\n",
+			dev_err(aio->dev, "Cannot run %d channels at %dHz\n",
 				params_channels(params), rate);
 			return -EINVAL;
 		}
 		break;
 	case CYGNUS_SSPMODE_I2S:
 		if (params_channels(params) != 2) {
-			dev_err(aio->cygaud->dev, "i2s mode must use 2 channels\n");
+			dev_err(aio->dev, "i2s mode must use 2 channels\n");
 			return -EINVAL;
 		}
 
@@ -648,16 +640,15 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 
 		break;
 	default:
-		dev_err(aio->cygaud->dev,
-			"%s port running in unknown mode\n", __func__);
+		dev_err(aio->dev, "%s unknown mode\n", __func__);
 		return -EINVAL;
 	}
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		value = readl(aio->audio + aio->regs.bf_sourcech_cfg);
 		value &= ~BIT(BF_SRC_CFGX_BUFFER_PAIR_ENABLE);
 		value &= ~BIT(BF_SRC_CFGX_SAMPLE_CH_MODE);
-		writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		writel(value, aio->audio + aio->regs.bf_sourcech_cfg);
 
 		switch (params_format(params)) {
 		case SNDRV_PCM_FORMAT_S16_LE:
@@ -675,38 +666,34 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 		}
 
 		mask = BF_SRC_CFGX_BITRES_MASK;
-		value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		value = readl(aio->audio + aio->regs.bf_sourcech_cfg);
 		value &= ~(mask << BF_SRC_CFGX_BIT_RES);
 		value |= (bitres << BF_SRC_CFGX_BIT_RES);
-		writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
+		writel(value, aio->audio + aio->regs.bf_sourcech_cfg);
 
 		/* Only needed for LSB mode, ignored for MSB */
 		mask = I2S_OUT_CFGX_BIT_PER_SAMPLE_MASK;
-		value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
+		value = readl(aio->audio + aio->regs.i2s_cfg);
 		value &= ~(mask << I2S_OUT_CFGX_BITS_PER_SAMPLE);
 		value |= (bits_per_sample << I2S_OUT_CFGX_BITS_PER_SAMPLE);
-		writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
+		writel(value, aio->audio + aio->regs.i2s_cfg);
 	} else {
 
 		switch (params_format(params)) {
 		case SNDRV_PCM_FORMAT_S16_LE:
 			bits_per_sample = 16;
 
-			value = readl(aio->cygaud->audio +
-					aio->regs.bf_destch_cfg);
+			value = readl(aio->audio + aio->regs.bf_destch_cfg);
 			value |= BIT(BF_DST_CFGX_CAP_MODE);
-			writel(value, aio->cygaud->audio +
-					aio->regs.bf_destch_cfg);
+			writel(value, aio->audio + aio->regs.bf_destch_cfg);
 			break;
 
 		case SNDRV_PCM_FORMAT_S32_LE:
 			bits_per_sample = 24; /* Only 24 valid bits */
 
-			value = readl(aio->cygaud->audio +
-					aio->regs.bf_destch_cfg);
+			value = readl(aio->audio + aio->regs.bf_destch_cfg);
 			value &= ~BIT(BF_DST_CFGX_CAP_MODE);
-			writel(value, aio->cygaud->audio +
-					aio->regs.bf_destch_cfg);
+			writel(value, aio->audio + aio->regs.bf_destch_cfg);
 			break;
 
 		default:
@@ -715,10 +702,10 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 
 		/* Used for both LSB and MSB modes */
 		mask = I2S_IN_CFGX_BIT_PER_SAMPLE_MASK;
-		value = readl(aio->cygaud->i2s_in + aio->regs.i2s_cap_cfg);
+		value = readl(aio->i2s_in + aio->regs.i2s_cap_cfg);
 		value &= ~(mask << I2S_IN_CFGX_BITS_PER_SAMPLE);
 		value |= (bits_per_sample << I2S_IN_CFGX_BITS_PER_SAMPLE);
-		writel(value, aio->cygaud->i2s_in + aio->regs.i2s_cap_cfg);
+		writel(value, aio->i2s_in + aio->regs.i2s_cap_cfg);
 	}
 
 	/* Put output port into reset prior to configuring.
@@ -741,13 +728,13 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 			 * in the same state for our first transfer as it is
 			 * every transfer.
 			 */
-			value = readl(aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+			value = readl(aio->i2s_in + IOP_SW_INIT_LOGIC);
 			value |= BIT(aio->portnum);
-			writel(value, aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+			writel(value, aio->i2s_in + IOP_SW_INIT_LOGIC);
 
-			value = readl(aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+			value = readl(aio->i2s_in + IOP_SW_INIT_LOGIC);
 			value |= BIT(IOP_LOGIC_RESET_IN_OFFSET(aio->portnum));
-			writel(value, aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
+			writel(value, aio->i2s_in + IOP_SW_INIT_LOGIC);
 		}
 
 		if (aio->port_type != PORT_SPDIF)
@@ -790,52 +777,49 @@ static int cygnus_ssp_set_sysclk(struct snd_soc_dai *dai,
 	long rate;
 	struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai);
 
-	dev_dbg(aio->cygaud->dev,
-		"%s Enter port = %d\n", __func__, aio->portnum);
+	dev_dbg(aio->dev, "%s Enter port = %d\n", __func__, aio->portnum);
 
 	/*
 	 * This should not happen, but the machine file may inadvertently
 	 * call set_sysclk without configuring a clock via the devicetree.
 	 */
 	if (!aio->clk_info.audio_clk) {
-		dev_err(aio->cygaud->dev,
-			"%s Error. No clock assigned.\n", __func__);
+		dev_err(aio->dev, "%s Error. No clock assigned.\n", __func__);
 		return -ENODEV;
 	}
 
 	rate = clk_round_rate(aio->clk_info.audio_clk, freq);
 	if (rate < 0) {
-		dev_err(aio->cygaud->dev, "%s Error with with clock %ld.\n",
+		dev_err(aio->dev, "%s Error with with clock %ld.\n",
 			__func__, rate);
 		return rate;
 	}
 
 	if (!mclk_in_range(freq, rate)) {
-		dev_err(aio->cygaud->dev, "%s Can not set rate to %u  actual %ld.\n",
+		dev_err(aio->dev, "%s Can not set rate to %u  actual %ld.\n",
 			__func__, freq, rate);
 		return -EINVAL;
 	}
 
 	ret = clk_set_rate(aio->clk_info.audio_clk, freq);
 	if (ret) {
-		dev_err(aio->cygaud->dev,
-			"%s Set MCLK rate fail %d\n", __func__, ret);
+		dev_err(aio->dev, "%s Set MCLK rate fail %d\n", __func__, ret);
 		return ret;
 	}
 
 	aio->mclk = freq;
 	sel = aio->clk_info.clk_mux;
 
-	dev_dbg(aio->cygaud->dev, "%s Setting MCLKSEL to %d\n", __func__, sel);
-	value = readl(aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
+	dev_dbg(aio->dev, "%s Setting MCLKSEL to %d\n", __func__, sel);
+	value = readl(aio->audio + aio->regs.i2s_mclk_cfg);
 	value &= ~(0xf << I2S_OUT_PLLCLKSEL_SHIFT);
 	value |= (sel << I2S_OUT_PLLCLKSEL_SHIFT);
-	writel(value, aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
+	writel(value, aio->audio + aio->regs.i2s_mclk_cfg);
 
 	/* Clear bit for active */
-	value = readl(aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
+	value = readl(aio->audio + AUD_MISC_SEROUT_OE_REG_BASE);
 	value &= ~BIT(AUD_MISC_SEROUT_MCLK_OE + (aio->portnum * 4));
-	writel(value, aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
+	writel(value, aio->audio + AUD_MISC_SEROUT_OE_REG_BASE);
 
 	return 0;
 }
@@ -883,7 +867,7 @@ static int cygnus_ssp_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 	u32 val;
 	u32 mask;
 
-	dev_dbg(aio->cygaud->dev, "%s Enter  fmt: %x\n", __func__, fmt);
+	dev_dbg(aio->dev, "%s Enter  fmt: %x\n", __func__, fmt);
 
 	if (aio->port_type == PORT_SPDIF)
 		return -EINVAL;
@@ -912,7 +896,7 @@ static int cygnus_ssp_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 			aio->fs_delay = 1;
 		else {
 			if (aio->is_slave) {
-				dev_err(aio->cygaud->dev,
+				dev_err(aio->dev,
 				"%s DSP_B mode not supported while slave.\n",
 					__func__);
 				return -EINVAL;
@@ -929,7 +913,7 @@ static int cygnus_ssp_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 	/* We must be i2s master to invert any clock */
 	if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) {
 		if (aio->is_slave || (aio->mode == CYGNUS_SSPMODE_TDM)) {
-			dev_err(aio->cygaud->dev,
+			dev_err(aio->dev,
 			"%s Can only invert clocks in i2s master mode\n",
 				__func__);
 			return -EINVAL;
@@ -957,7 +941,7 @@ static int cygnus_ssp_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 		return -EINVAL;
 	}
 
-	val = readl(aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
+	val = readl(aio->audio + AUD_MISC_SEROUT_OE_REG_BASE);
 
 	/*
 	 * Configure the word clk and bit clk as output or tristate
@@ -972,8 +956,8 @@ static int cygnus_ssp_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 	else
 		val &= ~mask;  /* Clear bit for drive */
 
-	dev_dbg(aio->cygaud->dev, "%s  Set OE bits 0x%x\n", __func__, val);
-	writel(val, aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
+	dev_dbg(aio->dev, "%s  Set OE bits 0x%x\n", __func__, val);
+	writel(val, aio->audio + AUD_MISC_SEROUT_OE_REG_BASE);
 
 	return 0;
 }
@@ -983,7 +967,7 @@ static int cygnus_ssp_trigger(struct snd_pcm_substream *substream, int cmd,
 {
 	struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai);
 
-	dev_dbg(aio->cygaud->dev,
+	dev_dbg(aio->dev,
 		"%s cmd %d at port = %d\n", __func__, cmd, aio->portnum);
 
 	switch (cmd) {
@@ -1023,8 +1007,7 @@ static int cygnus_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
 	unsigned int i;
 
 	if (tx_mask != rx_mask) {
-		dev_err(aio->cygaud->dev,
-			"%s tx_mask must equal rx_mask\n", __func__);
+		dev_err(aio->dev, "%s tx_mask must equal rx_mask\n", __func__);
 		return -EINVAL;
 	}
 
@@ -1050,8 +1033,7 @@ static int cygnus_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
 	}
 
 	if (!found) {
-		dev_err(aio->cygaud->dev,
-			"%s In TDM mode, frame bits INVALID (%d)\n",
+		dev_err(aio->dev, "%s In TDM mode, frame bits INVALID (%d)\n",
 			__func__, bits_per_frame);
 		return -EINVAL;
 	}
@@ -1060,7 +1042,7 @@ static int cygnus_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
 	aio->slot_width = slot_width;
 	aio->slots_per_frame = slots;
 
-	dev_dbg(aio->cygaud->dev, "%s active_slots %u, bits per frame %d\n",
+	dev_dbg(aio->dev, "%s active_slots %u, bits per frame %d\n",
 			__func__, aio->active_slots, bits_per_frame);
 	return 0;
 }
@@ -1074,7 +1056,7 @@ static int cygnus_ssp_set_pll(struct snd_soc_dai *cpu_dai, int pll_id,
 	int ret = 0;
 
 	if (!aio->clk_info.audio_clk) {
-		dev_err(aio->cygaud->dev,
+		dev_err(aio->dev,
 			"%s: port %d does not have an assigned clock.\n",
 			__func__, aio->portnum);
 		return -ENODEV;
@@ -1082,7 +1064,7 @@ static int cygnus_ssp_set_pll(struct snd_soc_dai *cpu_dai, int pll_id,
 
 	clk_pll = clk_get_parent(aio->clk_info.audio_clk);
 	if (IS_ERR(clk_pll)) {
-		dev_err(aio->cygaud->dev,
+		dev_err(aio->dev,
 			"%s: could not get audiopll clock.\n", __func__);
 		return -ENODEV;
 	}
@@ -1185,7 +1167,7 @@ static void update_ssp_cfg(struct cygnus_aio_port *aio)
 	 * bit set in the Tx formatter (which would be the Tx Formatters
 	 * internal clock or signal from external pin).
 	 */
-	ssp_curcfg = readl(aio->cygaud->i2s_in + aio->regs.i2s_cap_cfg);
+	ssp_curcfg = readl(aio->i2s_in + aio->regs.i2s_cap_cfg);
 	ssp_incfg = (ssp_curcfg & I2S_IN_CFG_REG_UPDATE_MASK) | ssp_newcfg;
 	ssp_incfg |= BIT(I2S_OUT_CFGX_SLAVE_MODE);
 
@@ -1194,13 +1176,13 @@ static void update_ssp_cfg(struct cygnus_aio_port *aio)
 	ssp_incfg &= ~BIT(I2S_OUT_CFGX_BITS_PER_SLOT);
 	ssp_incfg |= (bits_per_slot_in << I2S_OUT_CFGX_BITS_PER_SLOT);
 
-	writel(ssp_incfg, aio->cygaud->i2s_in + aio->regs.i2s_cap_cfg);
+	writel(ssp_incfg, aio->i2s_in + aio->regs.i2s_cap_cfg);
 
 	/*
 	 * SSP out cfg.
 	 * Retain bits we do not want to update, then OR in new bits
 	 */
-	ssp_curcfg = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
+	ssp_curcfg = readl(aio->audio + aio->regs.i2s_cfg);
 	ssp_outcfg = (ssp_curcfg & I2S_OUT_CFG_REG_UPDATE_MASK) | ssp_newcfg;
 
 	ssp_outcfg &= ~(0xf << I2S_OUT_CFGX_VALID_SLOT);
@@ -1208,7 +1190,7 @@ static void update_ssp_cfg(struct cygnus_aio_port *aio)
 	ssp_outcfg &= ~BIT(I2S_OUT_CFGX_BITS_PER_SLOT);
 	ssp_outcfg |= (bits_per_slot_out << I2S_OUT_CFGX_BITS_PER_SLOT);
 
-	writel(ssp_outcfg, aio->cygaud->audio + aio->regs.i2s_cfg);
+	writel(ssp_outcfg, aio->audio + aio->regs.i2s_cfg);
 }
 
 
@@ -1320,7 +1302,9 @@ static int parse_ssp_child_node(struct platform_device *pdev,
 	}
 
 	aio = &cygaud->portinfo[portnum];
-	aio->cygaud = cygaud;
+
+	aio->audio = cygaud->audio;
+	aio->i2s_in = cygaud->i2s_in;
 	aio->portnum = portnum;
 	aio->port_type = port_type;
 	aio->fsync_width = -1;
@@ -1349,8 +1333,7 @@ static int parse_ssp_child_node(struct platform_device *pdev,
 
 	dev_dbg(&pdev->dev, "%s portnum = %d\n", __func__, aio->portnum);
 	aio->streams_on = 0;
-	aio->cygaud->dev = &pdev->dev;
-
+	aio->dev = &pdev->dev;
 
 	aio->clk_info.audio_clk = NULL;
 
@@ -1421,7 +1404,6 @@ static int cygnus_ssp_probe(struct platform_device *pdev)
 	}
 
 	active_port_count = 0;
-
 	for_each_available_child_of_node(pdev->dev.of_node, child_node) {
 		err = parse_ssp_child_node(pdev, child_node, cygaud,
 					&cygnus_ssp_dai[active_port_count]);
diff --git a/sound/soc/bcm/cygnus-ssp.h b/sound/soc/bcm/cygnus-ssp.h
index 648321d..ac346b8 100644
--- a/sound/soc/bcm/cygnus-ssp.h
+++ b/sound/soc/bcm/cygnus-ssp.h
@@ -32,13 +32,13 @@
 #define PROP_LEN_MAX 40
 
 struct ringbuf_regs {
-	unsigned rdaddr;
-	unsigned wraddr;
-	unsigned baseaddr;
-	unsigned endaddr;
-	unsigned fmark;   /* freemark for play, fullmark for caputure */
-	unsigned period_bytes;
-	unsigned buf_size;
+	unsigned int rdaddr;
+	unsigned int wraddr;
+	unsigned int baseaddr;
+	unsigned int endaddr;
+	unsigned int fmark;   /* freemark for play, fullmark for caputure */
+	u32 period_bytes;
+	u32 buf_size;
 };
 
 #define RINGBUF_REG_PLAYBACK(num) ((struct ringbuf_regs) { \
@@ -85,6 +85,8 @@ struct cygnus_audio_clkinfo {
 };
 
 struct cygnus_aio_port {
+	struct device *dev;
+
 	int portnum;
 	int mode;
 	bool is_slave;
@@ -104,7 +106,9 @@ struct cygnus_aio_port {
 	unsigned int slots_per_frame;
 	unsigned int active_slots;
 
-	struct cygnus_audio *cygaud;
+	void __iomem *audio;
+	void __iomem *i2s_in;
+
 	struct cygnus_ssp_regs regs;
 
 	struct ringbuf_regs play_rb_regs;
@@ -122,8 +126,8 @@ struct cygnus_audio {
 
 	int irq_num;
 	void __iomem *audio;
-	struct device *dev;
 	void __iomem *i2s_in;
+	struct device *dev;
 };
 
 extern int cygnus_ssp_set_custom_fsync_width(struct snd_soc_dai *cpu_dai,
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 50+ messages in thread

* Re: [PATCH 2/9] ASoC: cygnus: Update bindings for audio clock changes
  2017-08-14 22:06   ` Lori Hikichi
  (?)
@ 2017-08-15 17:14     ` Mark Brown
  -1 siblings, 0 replies; 50+ messages in thread
From: Mark Brown @ 2017-08-15 17:14 UTC (permalink / raw)
  To: Lori Hikichi
  Cc: Liam Girdwood, Rob Herring, Mark Rutland, Ray Jui, Scott Branden,
	Jon Mason, bcm-kernel-feedback-list, Jaroslav Kysela,
	Takashi Iwai, alsa-devel, devicetree, linux-arm-kernel,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 279 bytes --]

On Mon, Aug 14, 2017 at 03:06:50PM -0700, Lori Hikichi wrote:
> Allow each audio port to select which clock (if any) it wants to use.

Why is this in DT for the port and not either using standard clock
bindings to configure the clock tree or allowing the machine driver to
pick?

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH 2/9] ASoC: cygnus: Update bindings for audio clock changes
@ 2017-08-15 17:14     ` Mark Brown
  0 siblings, 0 replies; 50+ messages in thread
From: Mark Brown @ 2017-08-15 17:14 UTC (permalink / raw)
  To: Lori Hikichi
  Cc: Mark Rutland, devicetree, alsa-devel, linux-kernel,
	Scott Branden, Jon Mason, Ray Jui, Takashi Iwai, Liam Girdwood,
	Rob Herring, bcm-kernel-feedback-list, linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 279 bytes --]

On Mon, Aug 14, 2017 at 03:06:50PM -0700, Lori Hikichi wrote:
> Allow each audio port to select which clock (if any) it wants to use.

Why is this in DT for the port and not either using standard clock
bindings to configure the clock tree or allowing the machine driver to
pick?

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 50+ messages in thread

* [PATCH 2/9] ASoC: cygnus: Update bindings for audio clock changes
@ 2017-08-15 17:14     ` Mark Brown
  0 siblings, 0 replies; 50+ messages in thread
From: Mark Brown @ 2017-08-15 17:14 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Aug 14, 2017 at 03:06:50PM -0700, Lori Hikichi wrote:
> Allow each audio port to select which clock (if any) it wants to use.

Why is this in DT for the port and not either using standard clock
bindings to configure the clock tree or allowing the machine driver to
pick?
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20170815/d38a3b7e/attachment.sig>

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Applied "ASoC: cygnus: Add support for 384kHz frame rates" to the asoc tree
  2017-08-14 22:06   ` Lori Hikichi
  (?)
@ 2017-08-15 17:15     ` Mark Brown
  -1 siblings, 0 replies; 50+ messages in thread
From: Mark Brown @ 2017-08-15 17:15 UTC (permalink / raw)
  To: Lori Hikichi
  Cc: Mark Brown, Liam Girdwood, Mark Brown, Rob Herring, Mark Rutland,
	Ray Jui, Scott Branden, Jon Mason, bcm-kernel-feedback-list,
	Jaroslav Kysela, Takashi Iwai, devicetree, alsa-devel,
	linux-kernel, linux-arm-kernel, alsa-devel

The patch

   ASoC: cygnus: Add support for 384kHz frame rates

has been applied to the asoc tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 8937ea0f3c3a90da3c594a4e2b038d2c7b282eec Mon Sep 17 00:00:00 2001
From: Lori Hikichi <lori.hikichi@broadcom.com>
Date: Mon, 14 Aug 2017 15:06:49 -0700
Subject: [PATCH] ASoC: cygnus: Add support for 384kHz frame rates

Allow the audio ports to operate at 384kHz.

Signed-off-by: Lori Hikichi <lori.hikichi@broadcom.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
 sound/soc/bcm/cygnus-ssp.c | 235 +++++++++++----------------------------------
 1 file changed, 55 insertions(+), 180 deletions(-)

diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c
index e710bb0c5637..1a57a4ebc8f0 100644
--- a/sound/soc/bcm/cygnus-ssp.c
+++ b/sound/soc/bcm/cygnus-ssp.c
@@ -27,12 +27,6 @@
 
 #define DEFAULT_VCO    1354750204
 
-#define CYGNUS_TDM_RATE \
-		(SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | \
-		SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_22050 | \
-		SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
-		SNDRV_PCM_RATE_48000)
-
 #define CAPTURE_FCI_ID_BASE 0x180
 #define CYGNUS_SSP_TRISTATE_MASK 0x001fff
 #define CYGNUS_PLLCLKSEL_MASK 0xf
@@ -234,152 +228,20 @@ static const struct pll_macro_entry pll_predef_mclk[] = {
 	{98304000, 2},
 };
 
+#define CYGNUS_RATE_MIN     8000
+#define CYGNUS_RATE_MAX   384000
+
 /* List of valid frame sizes for tdm mode */
 static const int ssp_valid_tdm_framesize[] = {32, 64, 128, 256, 512};
 
-/*
- * Use this relationship to derive the sampling rate (lrclk)
- * lrclk = (mclk) / ((2*mclk_to_sclk_ratio) * (32 * SCLK))).
- *
- * Use mclk and pll_ch from the table above
- *
- * Valid SCLK = 0/1/2/4/8/12
- *
- * mclk_to_sclk_ratio = number of MCLK per SCLK. Division is twice the
- * value programmed in this field.
- * Valid mclk_to_sclk_ratio = 1 through to 15
- *
- * eg: To set lrclk = 48khz, set mclk = 12288000, mclk_to_sclk_ratio = 2,
- * SCLK = 64
- */
-struct _ssp_clk_coeff {
-	u32 mclk;
-	u32 sclk_rate;
-	u32 rate;
-	u32 mclk_rate;
+static const unsigned int cygnus_rates[] = {
+	 8000, 11025,  16000,  22050,  32000,  44100, 48000,
+	88200, 96000, 176400, 192000, 352800, 384000
 };
 
-static const struct _ssp_clk_coeff ssp_clk_coeff[] = {
-	{ 4096000,  32,  16000, 4},
-	{ 4096000,  32,  32000, 2},
-	{ 4096000,  64,   8000, 4},
-	{ 4096000,  64,  16000, 2},
-	{ 4096000,  64,  32000, 1},
-	{ 4096000, 128,   8000, 2},
-	{ 4096000, 128,  16000, 1},
-	{ 4096000, 256,   8000, 1},
-
-	{ 6144000,  32,  16000, 6},
-	{ 6144000,  32,  32000, 3},
-	{ 6144000,  32,  48000, 2},
-	{ 6144000,  32,  96000, 1},
-	{ 6144000,  64,   8000, 6},
-	{ 6144000,  64,  16000, 3},
-	{ 6144000,  64,  48000, 1},
-	{ 6144000, 128,   8000, 3},
-
-	{ 8192000,  32,  32000, 4},
-	{ 8192000,  64,  16000, 4},
-	{ 8192000,  64,  32000, 2},
-	{ 8192000, 128,   8000, 4},
-	{ 8192000, 128,  16000, 2},
-	{ 8192000, 128,  32000, 1},
-	{ 8192000, 256,   8000, 2},
-	{ 8192000, 256,  16000, 1},
-	{ 8192000, 512,   8000, 1},
-
-	{12288000,  32,  32000, 6},
-	{12288000,  32,  48000, 4},
-	{12288000,  32,  96000, 2},
-	{12288000,  32, 192000, 1},
-	{12288000,  64,  16000, 6},
-	{12288000,  64,  32000, 3},
-	{12288000,  64,  48000, 2},
-	{12288000,  64,  96000, 1},
-	{12288000, 128,   8000, 6},
-	{12288000, 128,  16000, 3},
-	{12288000, 128,  48000, 1},
-	{12288000, 256,   8000, 3},
-
-	{16384000,  64,  32000, 4},
-	{16384000, 128,  16000, 4},
-	{16384000, 128,  32000, 2},
-	{16384000, 256,   8000, 4},
-	{16384000, 256,  16000, 2},
-	{16384000, 256,  32000, 1},
-	{16384000, 512,   8000, 2},
-	{16384000, 512,  16000, 1},
-
-	{24576000,  32,  96000, 4},
-	{24576000,  32, 192000, 2},
-	{24576000,  64,  32000, 6},
-	{24576000,  64,  48000, 4},
-	{24576000,  64,  96000, 2},
-	{24576000,  64, 192000, 1},
-	{24576000, 128,  16000, 6},
-	{24576000, 128,  32000, 3},
-	{24576000, 128,  48000, 2},
-	{24576000, 256,   8000, 6},
-	{24576000, 256,  16000, 3},
-	{24576000, 256,  48000, 1},
-	{24576000, 512,   8000, 3},
-
-	{49152000,  32, 192000, 4},
-	{49152000,  64,  96000, 4},
-	{49152000,  64, 192000, 2},
-	{49152000, 128,  32000, 6},
-	{49152000, 128,  48000, 4},
-	{49152000, 128,  96000, 2},
-	{49152000, 128, 192000, 1},
-	{49152000, 256,  16000, 6},
-	{49152000, 256,  32000, 3},
-	{49152000, 256,  48000, 2},
-	{49152000, 256,  96000, 1},
-	{49152000, 512,   8000, 6},
-	{49152000, 512,  16000, 3},
-	{49152000, 512,  48000, 1},
-
-	{ 5644800,  32,  22050, 4},
-	{ 5644800,  32,  44100, 2},
-	{ 5644800,  32,  88200, 1},
-	{ 5644800,  64,  11025, 4},
-	{ 5644800,  64,  22050, 2},
-	{ 5644800,  64,  44100, 1},
-
-	{11289600,  32,  44100, 4},
-	{11289600,  32,  88200, 2},
-	{11289600,  32, 176400, 1},
-	{11289600,  64,  22050, 4},
-	{11289600,  64,  44100, 2},
-	{11289600,  64,  88200, 1},
-	{11289600, 128,  11025, 4},
-	{11289600, 128,  22050, 2},
-	{11289600, 128,  44100, 1},
-
-	{22579200,  32,  88200, 4},
-	{22579200,  32, 176400, 2},
-	{22579200,  64,  44100, 4},
-	{22579200,  64,  88200, 2},
-	{22579200,  64, 176400, 1},
-	{22579200, 128,  22050, 4},
-	{22579200, 128,  44100, 2},
-	{22579200, 128,  88200, 1},
-	{22579200, 256,  11025, 4},
-	{22579200, 256,  22050, 2},
-	{22579200, 256,  44100, 1},
-
-	{45158400,  32, 176400, 4},
-	{45158400,  64,  88200, 4},
-	{45158400,  64, 176400, 2},
-	{45158400, 128,  44100, 4},
-	{45158400, 128,  88200, 2},
-	{45158400, 128, 176400, 1},
-	{45158400, 256,  22050, 4},
-	{45158400, 256,  44100, 2},
-	{45158400, 256,  88200, 1},
-	{45158400, 512,  11025, 4},
-	{45158400, 512,  22050, 2},
-	{45158400, 512,  44100, 1},
+static const struct snd_pcm_hw_constraint_list cygnus_rate_constraint = {
+	.count = ARRAY_SIZE(cygnus_rates),
+	.list = cygnus_rates,
 };
 
 static struct cygnus_aio_port *cygnus_dai_get_portinfo(struct snd_soc_dai *dai)
@@ -679,40 +541,55 @@ static int pll_configure_mclk(struct cygnus_audio *cygaud, u32 mclk,
 	return p_entry->pll_ch_num;
 }
 
-static int cygnus_ssp_set_clocks(struct cygnus_aio_port *aio,
-			struct cygnus_audio *cygaud)
+static int cygnus_ssp_set_clocks(struct cygnus_aio_port *aio)
 {
-	u32 value, i = 0;
+	u32 value;
 	u32 mask = 0xf;
 	u32 sclk;
-	bool found = false;
-	const struct _ssp_clk_coeff *p_entry = NULL;
+	u32 mclk_rate;
+	unsigned int bit_rate;
+	unsigned int ratio;
 
-	for (i = 0; i < ARRAY_SIZE(ssp_clk_coeff); i++) {
-		p_entry = &ssp_clk_coeff[i];
-		if ((p_entry->rate == aio->lrclk) &&
-		    (p_entry->sclk_rate == aio->bit_per_frame) &&
-		    (p_entry->mclk == aio->mclk)) {
-			found = true;
-			break;
-		}
-	}
-	if (!found) {
+	bit_rate = aio->bit_per_frame * aio->lrclk;
+
+	/*
+	 * Check if the bit clock can be generated from the given MCLK.
+	 * MCLK must be a perfect multiple of bit clock and must be one of the
+	 * following values... (2,4,6,8,10,12,14)
+	 */
+	if ((aio->mclk % bit_rate) != 0)
+		return -EINVAL;
+
+	ratio = aio->mclk / bit_rate;
+	switch (ratio) {
+	case 2:
+	case 4:
+	case 6:
+	case 8:
+	case 10:
+	case 12:
+	case 14:
+		mclk_rate = ratio / 2;
+		break;
+
+	default:
 		dev_err(aio->cygaud->dev,
-			"No valid match found in ssp_clk_coeff array\n");
+			"Invalid combination of MCLK and BCLK\n");
 		dev_err(aio->cygaud->dev, "lrclk = %u, bits/frame = %u, mclk = %u\n",
 			aio->lrclk, aio->bit_per_frame, aio->mclk);
 		return -EINVAL;
 	}
 
-	sclk = aio->bit_per_frame;
-	if (sclk == 512)
-		sclk = 0;
-	/* sclks_per_1fs_div = sclk cycles/32 */
-	sclk /= 32;
 	/* Set sclk rate */
 	switch (aio->port_type) {
 	case PORT_TDM:
+		sclk = aio->bit_per_frame;
+		if (sclk == 512)
+			sclk = 0;
+
+		/* sclks_per_1fs_div = sclk cycles/32 */
+		sclk /= 32;
+
 		/* Set number of bitclks per frame */
 		value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
 		value &= ~(mask << I2S_OUT_CFGX_SCLKS_PER_1FS_DIV32);
@@ -731,7 +608,7 @@ static int cygnus_ssp_set_clocks(struct cygnus_aio_port *aio,
 	/* Set MCLK_RATE ssp port (spdif and ssp are the same) */
 	value = readl(aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
 	value &= ~(0xf << I2S_OUT_MCLKRATE_SHIFT);
-	value |= (p_entry->mclk_rate << I2S_OUT_MCLKRATE_SHIFT);
+	value |= (mclk_rate << I2S_OUT_MCLKRATE_SHIFT);
 	writel(value, aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
 
 	dev_dbg(aio->cygaud->dev, "mclk cfg reg = 0x%x\n", value);
@@ -745,7 +622,6 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 				 struct snd_soc_dai *dai)
 {
 	struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai);
-	struct cygnus_audio *cygaud = snd_soc_dai_get_drvdata(dai);
 	int rate, bitres;
 	u32 value;
 	u32 mask = 0x1f;
@@ -841,7 +717,7 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 	aio->lrclk = rate;
 
 	if (!aio->is_slave)
-		ret = cygnus_ssp_set_clocks(aio, cygaud);
+		ret = cygnus_ssp_set_clocks(aio);
 
 	return ret;
 }
@@ -888,6 +764,11 @@ static int cygnus_ssp_startup(struct snd_pcm_substream *substream,
 	else
 		aio->clk_trace.cap_en = true;
 
+	substream->runtime->hw.rate_min = CYGNUS_RATE_MIN;
+	substream->runtime->hw.rate_max = CYGNUS_RATE_MAX;
+
+	snd_pcm_hw_constraint_list(substream->runtime, 0,
+			SNDRV_PCM_HW_PARAM_RATE, &cygnus_rate_constraint);
 	return 0;
 }
 
@@ -1261,9 +1142,7 @@ static const struct snd_soc_dai_ops cygnus_ssp_dai_ops = {
 	.playback = { \
 		.channels_min = 1, \
 		.channels_max = 16, \
-		.rates = CYGNUS_TDM_RATE | SNDRV_PCM_RATE_88200 | \
-			SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | \
-			SNDRV_PCM_RATE_192000, \
+		.rates = SNDRV_PCM_RATE_KNOT, \
 		.formats = SNDRV_PCM_FMTBIT_S8 | \
 				SNDRV_PCM_FMTBIT_S16_LE | \
 				SNDRV_PCM_FMTBIT_S32_LE, \
@@ -1271,9 +1150,7 @@ static const struct snd_soc_dai_ops cygnus_ssp_dai_ops = {
 	.capture = { \
 		.channels_min = 2, \
 		.channels_max = 16, \
-		.rates = CYGNUS_TDM_RATE | SNDRV_PCM_RATE_88200 | \
-			SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | \
-			SNDRV_PCM_RATE_192000, \
+		.rates = SNDRV_PCM_RATE_KNOT, \
 		.formats =  SNDRV_PCM_FMTBIT_S16_LE | \
 					SNDRV_PCM_FMTBIT_S32_LE, \
 	}, \
@@ -1293,9 +1170,7 @@ static struct snd_soc_dai_driver cygnus_spdif_dai_info = {
 	.playback = {
 		.channels_min = 2,
 		.channels_max = 2,
-		.rates = CYGNUS_TDM_RATE | SNDRV_PCM_RATE_88200 |
-			SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
-			SNDRV_PCM_RATE_192000,
+		.rates = SNDRV_PCM_RATE_KNOT,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE |
 			SNDRV_PCM_FMTBIT_S32_LE,
 	},
-- 
2.13.3

^ permalink raw reply related	[flat|nested] 50+ messages in thread

* Applied "ASoC: cygnus: Add support for 384kHz frame rates" to the asoc tree
@ 2017-08-15 17:15     ` Mark Brown
  0 siblings, 0 replies; 50+ messages in thread
From: Mark Brown @ 2017-08-15 17:15 UTC (permalink / raw)
  To: Lori Hikichi
  Cc: Mark Rutland, devicetree, alsa-devel, Scott Branden, Jon Mason,
	Ray Jui, Takashi Iwai, Liam Girdwood, Rob Herring, Mark Brown,
	bcm-kernel-feedback-list, linux-arm-kernel, linux-kernel

The patch

   ASoC: cygnus: Add support for 384kHz frame rates

has been applied to the asoc tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 8937ea0f3c3a90da3c594a4e2b038d2c7b282eec Mon Sep 17 00:00:00 2001
From: Lori Hikichi <lori.hikichi@broadcom.com>
Date: Mon, 14 Aug 2017 15:06:49 -0700
Subject: [PATCH] ASoC: cygnus: Add support for 384kHz frame rates

Allow the audio ports to operate at 384kHz.

Signed-off-by: Lori Hikichi <lori.hikichi@broadcom.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
 sound/soc/bcm/cygnus-ssp.c | 235 +++++++++++----------------------------------
 1 file changed, 55 insertions(+), 180 deletions(-)

diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c
index e710bb0c5637..1a57a4ebc8f0 100644
--- a/sound/soc/bcm/cygnus-ssp.c
+++ b/sound/soc/bcm/cygnus-ssp.c
@@ -27,12 +27,6 @@
 
 #define DEFAULT_VCO    1354750204
 
-#define CYGNUS_TDM_RATE \
-		(SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | \
-		SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_22050 | \
-		SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
-		SNDRV_PCM_RATE_48000)
-
 #define CAPTURE_FCI_ID_BASE 0x180
 #define CYGNUS_SSP_TRISTATE_MASK 0x001fff
 #define CYGNUS_PLLCLKSEL_MASK 0xf
@@ -234,152 +228,20 @@ static const struct pll_macro_entry pll_predef_mclk[] = {
 	{98304000, 2},
 };
 
+#define CYGNUS_RATE_MIN     8000
+#define CYGNUS_RATE_MAX   384000
+
 /* List of valid frame sizes for tdm mode */
 static const int ssp_valid_tdm_framesize[] = {32, 64, 128, 256, 512};
 
-/*
- * Use this relationship to derive the sampling rate (lrclk)
- * lrclk = (mclk) / ((2*mclk_to_sclk_ratio) * (32 * SCLK))).
- *
- * Use mclk and pll_ch from the table above
- *
- * Valid SCLK = 0/1/2/4/8/12
- *
- * mclk_to_sclk_ratio = number of MCLK per SCLK. Division is twice the
- * value programmed in this field.
- * Valid mclk_to_sclk_ratio = 1 through to 15
- *
- * eg: To set lrclk = 48khz, set mclk = 12288000, mclk_to_sclk_ratio = 2,
- * SCLK = 64
- */
-struct _ssp_clk_coeff {
-	u32 mclk;
-	u32 sclk_rate;
-	u32 rate;
-	u32 mclk_rate;
+static const unsigned int cygnus_rates[] = {
+	 8000, 11025,  16000,  22050,  32000,  44100, 48000,
+	88200, 96000, 176400, 192000, 352800, 384000
 };
 
-static const struct _ssp_clk_coeff ssp_clk_coeff[] = {
-	{ 4096000,  32,  16000, 4},
-	{ 4096000,  32,  32000, 2},
-	{ 4096000,  64,   8000, 4},
-	{ 4096000,  64,  16000, 2},
-	{ 4096000,  64,  32000, 1},
-	{ 4096000, 128,   8000, 2},
-	{ 4096000, 128,  16000, 1},
-	{ 4096000, 256,   8000, 1},
-
-	{ 6144000,  32,  16000, 6},
-	{ 6144000,  32,  32000, 3},
-	{ 6144000,  32,  48000, 2},
-	{ 6144000,  32,  96000, 1},
-	{ 6144000,  64,   8000, 6},
-	{ 6144000,  64,  16000, 3},
-	{ 6144000,  64,  48000, 1},
-	{ 6144000, 128,   8000, 3},
-
-	{ 8192000,  32,  32000, 4},
-	{ 8192000,  64,  16000, 4},
-	{ 8192000,  64,  32000, 2},
-	{ 8192000, 128,   8000, 4},
-	{ 8192000, 128,  16000, 2},
-	{ 8192000, 128,  32000, 1},
-	{ 8192000, 256,   8000, 2},
-	{ 8192000, 256,  16000, 1},
-	{ 8192000, 512,   8000, 1},
-
-	{12288000,  32,  32000, 6},
-	{12288000,  32,  48000, 4},
-	{12288000,  32,  96000, 2},
-	{12288000,  32, 192000, 1},
-	{12288000,  64,  16000, 6},
-	{12288000,  64,  32000, 3},
-	{12288000,  64,  48000, 2},
-	{12288000,  64,  96000, 1},
-	{12288000, 128,   8000, 6},
-	{12288000, 128,  16000, 3},
-	{12288000, 128,  48000, 1},
-	{12288000, 256,   8000, 3},
-
-	{16384000,  64,  32000, 4},
-	{16384000, 128,  16000, 4},
-	{16384000, 128,  32000, 2},
-	{16384000, 256,   8000, 4},
-	{16384000, 256,  16000, 2},
-	{16384000, 256,  32000, 1},
-	{16384000, 512,   8000, 2},
-	{16384000, 512,  16000, 1},
-
-	{24576000,  32,  96000, 4},
-	{24576000,  32, 192000, 2},
-	{24576000,  64,  32000, 6},
-	{24576000,  64,  48000, 4},
-	{24576000,  64,  96000, 2},
-	{24576000,  64, 192000, 1},
-	{24576000, 128,  16000, 6},
-	{24576000, 128,  32000, 3},
-	{24576000, 128,  48000, 2},
-	{24576000, 256,   8000, 6},
-	{24576000, 256,  16000, 3},
-	{24576000, 256,  48000, 1},
-	{24576000, 512,   8000, 3},
-
-	{49152000,  32, 192000, 4},
-	{49152000,  64,  96000, 4},
-	{49152000,  64, 192000, 2},
-	{49152000, 128,  32000, 6},
-	{49152000, 128,  48000, 4},
-	{49152000, 128,  96000, 2},
-	{49152000, 128, 192000, 1},
-	{49152000, 256,  16000, 6},
-	{49152000, 256,  32000, 3},
-	{49152000, 256,  48000, 2},
-	{49152000, 256,  96000, 1},
-	{49152000, 512,   8000, 6},
-	{49152000, 512,  16000, 3},
-	{49152000, 512,  48000, 1},
-
-	{ 5644800,  32,  22050, 4},
-	{ 5644800,  32,  44100, 2},
-	{ 5644800,  32,  88200, 1},
-	{ 5644800,  64,  11025, 4},
-	{ 5644800,  64,  22050, 2},
-	{ 5644800,  64,  44100, 1},
-
-	{11289600,  32,  44100, 4},
-	{11289600,  32,  88200, 2},
-	{11289600,  32, 176400, 1},
-	{11289600,  64,  22050, 4},
-	{11289600,  64,  44100, 2},
-	{11289600,  64,  88200, 1},
-	{11289600, 128,  11025, 4},
-	{11289600, 128,  22050, 2},
-	{11289600, 128,  44100, 1},
-
-	{22579200,  32,  88200, 4},
-	{22579200,  32, 176400, 2},
-	{22579200,  64,  44100, 4},
-	{22579200,  64,  88200, 2},
-	{22579200,  64, 176400, 1},
-	{22579200, 128,  22050, 4},
-	{22579200, 128,  44100, 2},
-	{22579200, 128,  88200, 1},
-	{22579200, 256,  11025, 4},
-	{22579200, 256,  22050, 2},
-	{22579200, 256,  44100, 1},
-
-	{45158400,  32, 176400, 4},
-	{45158400,  64,  88200, 4},
-	{45158400,  64, 176400, 2},
-	{45158400, 128,  44100, 4},
-	{45158400, 128,  88200, 2},
-	{45158400, 128, 176400, 1},
-	{45158400, 256,  22050, 4},
-	{45158400, 256,  44100, 2},
-	{45158400, 256,  88200, 1},
-	{45158400, 512,  11025, 4},
-	{45158400, 512,  22050, 2},
-	{45158400, 512,  44100, 1},
+static const struct snd_pcm_hw_constraint_list cygnus_rate_constraint = {
+	.count = ARRAY_SIZE(cygnus_rates),
+	.list = cygnus_rates,
 };
 
 static struct cygnus_aio_port *cygnus_dai_get_portinfo(struct snd_soc_dai *dai)
@@ -679,40 +541,55 @@ static int pll_configure_mclk(struct cygnus_audio *cygaud, u32 mclk,
 	return p_entry->pll_ch_num;
 }
 
-static int cygnus_ssp_set_clocks(struct cygnus_aio_port *aio,
-			struct cygnus_audio *cygaud)
+static int cygnus_ssp_set_clocks(struct cygnus_aio_port *aio)
 {
-	u32 value, i = 0;
+	u32 value;
 	u32 mask = 0xf;
 	u32 sclk;
-	bool found = false;
-	const struct _ssp_clk_coeff *p_entry = NULL;
+	u32 mclk_rate;
+	unsigned int bit_rate;
+	unsigned int ratio;
 
-	for (i = 0; i < ARRAY_SIZE(ssp_clk_coeff); i++) {
-		p_entry = &ssp_clk_coeff[i];
-		if ((p_entry->rate == aio->lrclk) &&
-		    (p_entry->sclk_rate == aio->bit_per_frame) &&
-		    (p_entry->mclk == aio->mclk)) {
-			found = true;
-			break;
-		}
-	}
-	if (!found) {
+	bit_rate = aio->bit_per_frame * aio->lrclk;
+
+	/*
+	 * Check if the bit clock can be generated from the given MCLK.
+	 * MCLK must be a perfect multiple of bit clock and must be one of the
+	 * following values... (2,4,6,8,10,12,14)
+	 */
+	if ((aio->mclk % bit_rate) != 0)
+		return -EINVAL;
+
+	ratio = aio->mclk / bit_rate;
+	switch (ratio) {
+	case 2:
+	case 4:
+	case 6:
+	case 8:
+	case 10:
+	case 12:
+	case 14:
+		mclk_rate = ratio / 2;
+		break;
+
+	default:
 		dev_err(aio->cygaud->dev,
-			"No valid match found in ssp_clk_coeff array\n");
+			"Invalid combination of MCLK and BCLK\n");
 		dev_err(aio->cygaud->dev, "lrclk = %u, bits/frame = %u, mclk = %u\n",
 			aio->lrclk, aio->bit_per_frame, aio->mclk);
 		return -EINVAL;
 	}
 
-	sclk = aio->bit_per_frame;
-	if (sclk == 512)
-		sclk = 0;
-	/* sclks_per_1fs_div = sclk cycles/32 */
-	sclk /= 32;
 	/* Set sclk rate */
 	switch (aio->port_type) {
 	case PORT_TDM:
+		sclk = aio->bit_per_frame;
+		if (sclk == 512)
+			sclk = 0;
+
+		/* sclks_per_1fs_div = sclk cycles/32 */
+		sclk /= 32;
+
 		/* Set number of bitclks per frame */
 		value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
 		value &= ~(mask << I2S_OUT_CFGX_SCLKS_PER_1FS_DIV32);
@@ -731,7 +608,7 @@ static int cygnus_ssp_set_clocks(struct cygnus_aio_port *aio,
 	/* Set MCLK_RATE ssp port (spdif and ssp are the same) */
 	value = readl(aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
 	value &= ~(0xf << I2S_OUT_MCLKRATE_SHIFT);
-	value |= (p_entry->mclk_rate << I2S_OUT_MCLKRATE_SHIFT);
+	value |= (mclk_rate << I2S_OUT_MCLKRATE_SHIFT);
 	writel(value, aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
 
 	dev_dbg(aio->cygaud->dev, "mclk cfg reg = 0x%x\n", value);
@@ -745,7 +622,6 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 				 struct snd_soc_dai *dai)
 {
 	struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai);
-	struct cygnus_audio *cygaud = snd_soc_dai_get_drvdata(dai);
 	int rate, bitres;
 	u32 value;
 	u32 mask = 0x1f;
@@ -841,7 +717,7 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 	aio->lrclk = rate;
 
 	if (!aio->is_slave)
-		ret = cygnus_ssp_set_clocks(aio, cygaud);
+		ret = cygnus_ssp_set_clocks(aio);
 
 	return ret;
 }
@@ -888,6 +764,11 @@ static int cygnus_ssp_startup(struct snd_pcm_substream *substream,
 	else
 		aio->clk_trace.cap_en = true;
 
+	substream->runtime->hw.rate_min = CYGNUS_RATE_MIN;
+	substream->runtime->hw.rate_max = CYGNUS_RATE_MAX;
+
+	snd_pcm_hw_constraint_list(substream->runtime, 0,
+			SNDRV_PCM_HW_PARAM_RATE, &cygnus_rate_constraint);
 	return 0;
 }
 
@@ -1261,9 +1142,7 @@ static const struct snd_soc_dai_ops cygnus_ssp_dai_ops = {
 	.playback = { \
 		.channels_min = 1, \
 		.channels_max = 16, \
-		.rates = CYGNUS_TDM_RATE | SNDRV_PCM_RATE_88200 | \
-			SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | \
-			SNDRV_PCM_RATE_192000, \
+		.rates = SNDRV_PCM_RATE_KNOT, \
 		.formats = SNDRV_PCM_FMTBIT_S8 | \
 				SNDRV_PCM_FMTBIT_S16_LE | \
 				SNDRV_PCM_FMTBIT_S32_LE, \
@@ -1271,9 +1150,7 @@ static const struct snd_soc_dai_ops cygnus_ssp_dai_ops = {
 	.capture = { \
 		.channels_min = 2, \
 		.channels_max = 16, \
-		.rates = CYGNUS_TDM_RATE | SNDRV_PCM_RATE_88200 | \
-			SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | \
-			SNDRV_PCM_RATE_192000, \
+		.rates = SNDRV_PCM_RATE_KNOT, \
 		.formats =  SNDRV_PCM_FMTBIT_S16_LE | \
 					SNDRV_PCM_FMTBIT_S32_LE, \
 	}, \
@@ -1293,9 +1170,7 @@ static struct snd_soc_dai_driver cygnus_spdif_dai_info = {
 	.playback = {
 		.channels_min = 2,
 		.channels_max = 2,
-		.rates = CYGNUS_TDM_RATE | SNDRV_PCM_RATE_88200 |
-			SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
-			SNDRV_PCM_RATE_192000,
+		.rates = SNDRV_PCM_RATE_KNOT,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE |
 			SNDRV_PCM_FMTBIT_S32_LE,
 	},
-- 
2.13.3

^ permalink raw reply related	[flat|nested] 50+ messages in thread

* Applied "ASoC: cygnus: Add support for 384kHz frame rates" to the asoc tree
@ 2017-08-15 17:15     ` Mark Brown
  0 siblings, 0 replies; 50+ messages in thread
From: Mark Brown @ 2017-08-15 17:15 UTC (permalink / raw)
  To: linux-arm-kernel

The patch

   ASoC: cygnus: Add support for 384kHz frame rates

has been applied to the asoc tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 8937ea0f3c3a90da3c594a4e2b038d2c7b282eec Mon Sep 17 00:00:00 2001
From: Lori Hikichi <lori.hikichi@broadcom.com>
Date: Mon, 14 Aug 2017 15:06:49 -0700
Subject: [PATCH] ASoC: cygnus: Add support for 384kHz frame rates

Allow the audio ports to operate at 384kHz.

Signed-off-by: Lori Hikichi <lori.hikichi@broadcom.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
 sound/soc/bcm/cygnus-ssp.c | 235 +++++++++++----------------------------------
 1 file changed, 55 insertions(+), 180 deletions(-)

diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c
index e710bb0c5637..1a57a4ebc8f0 100644
--- a/sound/soc/bcm/cygnus-ssp.c
+++ b/sound/soc/bcm/cygnus-ssp.c
@@ -27,12 +27,6 @@
 
 #define DEFAULT_VCO    1354750204
 
-#define CYGNUS_TDM_RATE \
-		(SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | \
-		SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_22050 | \
-		SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
-		SNDRV_PCM_RATE_48000)
-
 #define CAPTURE_FCI_ID_BASE 0x180
 #define CYGNUS_SSP_TRISTATE_MASK 0x001fff
 #define CYGNUS_PLLCLKSEL_MASK 0xf
@@ -234,152 +228,20 @@ static const struct pll_macro_entry pll_predef_mclk[] = {
 	{98304000, 2},
 };
 
+#define CYGNUS_RATE_MIN     8000
+#define CYGNUS_RATE_MAX   384000
+
 /* List of valid frame sizes for tdm mode */
 static const int ssp_valid_tdm_framesize[] = {32, 64, 128, 256, 512};
 
-/*
- * Use this relationship to derive the sampling rate (lrclk)
- * lrclk = (mclk) / ((2*mclk_to_sclk_ratio) * (32 * SCLK))).
- *
- * Use mclk and pll_ch from the table above
- *
- * Valid SCLK = 0/1/2/4/8/12
- *
- * mclk_to_sclk_ratio = number of MCLK per SCLK. Division is twice the
- * value programmed in this field.
- * Valid mclk_to_sclk_ratio = 1 through to 15
- *
- * eg: To set lrclk = 48khz, set mclk = 12288000, mclk_to_sclk_ratio = 2,
- * SCLK = 64
- */
-struct _ssp_clk_coeff {
-	u32 mclk;
-	u32 sclk_rate;
-	u32 rate;
-	u32 mclk_rate;
+static const unsigned int cygnus_rates[] = {
+	 8000, 11025,  16000,  22050,  32000,  44100, 48000,
+	88200, 96000, 176400, 192000, 352800, 384000
 };
 
-static const struct _ssp_clk_coeff ssp_clk_coeff[] = {
-	{ 4096000,  32,  16000, 4},
-	{ 4096000,  32,  32000, 2},
-	{ 4096000,  64,   8000, 4},
-	{ 4096000,  64,  16000, 2},
-	{ 4096000,  64,  32000, 1},
-	{ 4096000, 128,   8000, 2},
-	{ 4096000, 128,  16000, 1},
-	{ 4096000, 256,   8000, 1},
-
-	{ 6144000,  32,  16000, 6},
-	{ 6144000,  32,  32000, 3},
-	{ 6144000,  32,  48000, 2},
-	{ 6144000,  32,  96000, 1},
-	{ 6144000,  64,   8000, 6},
-	{ 6144000,  64,  16000, 3},
-	{ 6144000,  64,  48000, 1},
-	{ 6144000, 128,   8000, 3},
-
-	{ 8192000,  32,  32000, 4},
-	{ 8192000,  64,  16000, 4},
-	{ 8192000,  64,  32000, 2},
-	{ 8192000, 128,   8000, 4},
-	{ 8192000, 128,  16000, 2},
-	{ 8192000, 128,  32000, 1},
-	{ 8192000, 256,   8000, 2},
-	{ 8192000, 256,  16000, 1},
-	{ 8192000, 512,   8000, 1},
-
-	{12288000,  32,  32000, 6},
-	{12288000,  32,  48000, 4},
-	{12288000,  32,  96000, 2},
-	{12288000,  32, 192000, 1},
-	{12288000,  64,  16000, 6},
-	{12288000,  64,  32000, 3},
-	{12288000,  64,  48000, 2},
-	{12288000,  64,  96000, 1},
-	{12288000, 128,   8000, 6},
-	{12288000, 128,  16000, 3},
-	{12288000, 128,  48000, 1},
-	{12288000, 256,   8000, 3},
-
-	{16384000,  64,  32000, 4},
-	{16384000, 128,  16000, 4},
-	{16384000, 128,  32000, 2},
-	{16384000, 256,   8000, 4},
-	{16384000, 256,  16000, 2},
-	{16384000, 256,  32000, 1},
-	{16384000, 512,   8000, 2},
-	{16384000, 512,  16000, 1},
-
-	{24576000,  32,  96000, 4},
-	{24576000,  32, 192000, 2},
-	{24576000,  64,  32000, 6},
-	{24576000,  64,  48000, 4},
-	{24576000,  64,  96000, 2},
-	{24576000,  64, 192000, 1},
-	{24576000, 128,  16000, 6},
-	{24576000, 128,  32000, 3},
-	{24576000, 128,  48000, 2},
-	{24576000, 256,   8000, 6},
-	{24576000, 256,  16000, 3},
-	{24576000, 256,  48000, 1},
-	{24576000, 512,   8000, 3},
-
-	{49152000,  32, 192000, 4},
-	{49152000,  64,  96000, 4},
-	{49152000,  64, 192000, 2},
-	{49152000, 128,  32000, 6},
-	{49152000, 128,  48000, 4},
-	{49152000, 128,  96000, 2},
-	{49152000, 128, 192000, 1},
-	{49152000, 256,  16000, 6},
-	{49152000, 256,  32000, 3},
-	{49152000, 256,  48000, 2},
-	{49152000, 256,  96000, 1},
-	{49152000, 512,   8000, 6},
-	{49152000, 512,  16000, 3},
-	{49152000, 512,  48000, 1},
-
-	{ 5644800,  32,  22050, 4},
-	{ 5644800,  32,  44100, 2},
-	{ 5644800,  32,  88200, 1},
-	{ 5644800,  64,  11025, 4},
-	{ 5644800,  64,  22050, 2},
-	{ 5644800,  64,  44100, 1},
-
-	{11289600,  32,  44100, 4},
-	{11289600,  32,  88200, 2},
-	{11289600,  32, 176400, 1},
-	{11289600,  64,  22050, 4},
-	{11289600,  64,  44100, 2},
-	{11289600,  64,  88200, 1},
-	{11289600, 128,  11025, 4},
-	{11289600, 128,  22050, 2},
-	{11289600, 128,  44100, 1},
-
-	{22579200,  32,  88200, 4},
-	{22579200,  32, 176400, 2},
-	{22579200,  64,  44100, 4},
-	{22579200,  64,  88200, 2},
-	{22579200,  64, 176400, 1},
-	{22579200, 128,  22050, 4},
-	{22579200, 128,  44100, 2},
-	{22579200, 128,  88200, 1},
-	{22579200, 256,  11025, 4},
-	{22579200, 256,  22050, 2},
-	{22579200, 256,  44100, 1},
-
-	{45158400,  32, 176400, 4},
-	{45158400,  64,  88200, 4},
-	{45158400,  64, 176400, 2},
-	{45158400, 128,  44100, 4},
-	{45158400, 128,  88200, 2},
-	{45158400, 128, 176400, 1},
-	{45158400, 256,  22050, 4},
-	{45158400, 256,  44100, 2},
-	{45158400, 256,  88200, 1},
-	{45158400, 512,  11025, 4},
-	{45158400, 512,  22050, 2},
-	{45158400, 512,  44100, 1},
+static const struct snd_pcm_hw_constraint_list cygnus_rate_constraint = {
+	.count = ARRAY_SIZE(cygnus_rates),
+	.list = cygnus_rates,
 };
 
 static struct cygnus_aio_port *cygnus_dai_get_portinfo(struct snd_soc_dai *dai)
@@ -679,40 +541,55 @@ static int pll_configure_mclk(struct cygnus_audio *cygaud, u32 mclk,
 	return p_entry->pll_ch_num;
 }
 
-static int cygnus_ssp_set_clocks(struct cygnus_aio_port *aio,
-			struct cygnus_audio *cygaud)
+static int cygnus_ssp_set_clocks(struct cygnus_aio_port *aio)
 {
-	u32 value, i = 0;
+	u32 value;
 	u32 mask = 0xf;
 	u32 sclk;
-	bool found = false;
-	const struct _ssp_clk_coeff *p_entry = NULL;
+	u32 mclk_rate;
+	unsigned int bit_rate;
+	unsigned int ratio;
 
-	for (i = 0; i < ARRAY_SIZE(ssp_clk_coeff); i++) {
-		p_entry = &ssp_clk_coeff[i];
-		if ((p_entry->rate == aio->lrclk) &&
-		    (p_entry->sclk_rate == aio->bit_per_frame) &&
-		    (p_entry->mclk == aio->mclk)) {
-			found = true;
-			break;
-		}
-	}
-	if (!found) {
+	bit_rate = aio->bit_per_frame * aio->lrclk;
+
+	/*
+	 * Check if the bit clock can be generated from the given MCLK.
+	 * MCLK must be a perfect multiple of bit clock and must be one of the
+	 * following values... (2,4,6,8,10,12,14)
+	 */
+	if ((aio->mclk % bit_rate) != 0)
+		return -EINVAL;
+
+	ratio = aio->mclk / bit_rate;
+	switch (ratio) {
+	case 2:
+	case 4:
+	case 6:
+	case 8:
+	case 10:
+	case 12:
+	case 14:
+		mclk_rate = ratio / 2;
+		break;
+
+	default:
 		dev_err(aio->cygaud->dev,
-			"No valid match found in ssp_clk_coeff array\n");
+			"Invalid combination of MCLK and BCLK\n");
 		dev_err(aio->cygaud->dev, "lrclk = %u, bits/frame = %u, mclk = %u\n",
 			aio->lrclk, aio->bit_per_frame, aio->mclk);
 		return -EINVAL;
 	}
 
-	sclk = aio->bit_per_frame;
-	if (sclk == 512)
-		sclk = 0;
-	/* sclks_per_1fs_div = sclk cycles/32 */
-	sclk /= 32;
 	/* Set sclk rate */
 	switch (aio->port_type) {
 	case PORT_TDM:
+		sclk = aio->bit_per_frame;
+		if (sclk == 512)
+			sclk = 0;
+
+		/* sclks_per_1fs_div = sclk cycles/32 */
+		sclk /= 32;
+
 		/* Set number of bitclks per frame */
 		value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
 		value &= ~(mask << I2S_OUT_CFGX_SCLKS_PER_1FS_DIV32);
@@ -731,7 +608,7 @@ static int cygnus_ssp_set_clocks(struct cygnus_aio_port *aio,
 	/* Set MCLK_RATE ssp port (spdif and ssp are the same) */
 	value = readl(aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
 	value &= ~(0xf << I2S_OUT_MCLKRATE_SHIFT);
-	value |= (p_entry->mclk_rate << I2S_OUT_MCLKRATE_SHIFT);
+	value |= (mclk_rate << I2S_OUT_MCLKRATE_SHIFT);
 	writel(value, aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
 
 	dev_dbg(aio->cygaud->dev, "mclk cfg reg = 0x%x\n", value);
@@ -745,7 +622,6 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 				 struct snd_soc_dai *dai)
 {
 	struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai);
-	struct cygnus_audio *cygaud = snd_soc_dai_get_drvdata(dai);
 	int rate, bitres;
 	u32 value;
 	u32 mask = 0x1f;
@@ -841,7 +717,7 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
 	aio->lrclk = rate;
 
 	if (!aio->is_slave)
-		ret = cygnus_ssp_set_clocks(aio, cygaud);
+		ret = cygnus_ssp_set_clocks(aio);
 
 	return ret;
 }
@@ -888,6 +764,11 @@ static int cygnus_ssp_startup(struct snd_pcm_substream *substream,
 	else
 		aio->clk_trace.cap_en = true;
 
+	substream->runtime->hw.rate_min = CYGNUS_RATE_MIN;
+	substream->runtime->hw.rate_max = CYGNUS_RATE_MAX;
+
+	snd_pcm_hw_constraint_list(substream->runtime, 0,
+			SNDRV_PCM_HW_PARAM_RATE, &cygnus_rate_constraint);
 	return 0;
 }
 
@@ -1261,9 +1142,7 @@ static const struct snd_soc_dai_ops cygnus_ssp_dai_ops = {
 	.playback = { \
 		.channels_min = 1, \
 		.channels_max = 16, \
-		.rates = CYGNUS_TDM_RATE | SNDRV_PCM_RATE_88200 | \
-			SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | \
-			SNDRV_PCM_RATE_192000, \
+		.rates = SNDRV_PCM_RATE_KNOT, \
 		.formats = SNDRV_PCM_FMTBIT_S8 | \
 				SNDRV_PCM_FMTBIT_S16_LE | \
 				SNDRV_PCM_FMTBIT_S32_LE, \
@@ -1271,9 +1150,7 @@ static const struct snd_soc_dai_ops cygnus_ssp_dai_ops = {
 	.capture = { \
 		.channels_min = 2, \
 		.channels_max = 16, \
-		.rates = CYGNUS_TDM_RATE | SNDRV_PCM_RATE_88200 | \
-			SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | \
-			SNDRV_PCM_RATE_192000, \
+		.rates = SNDRV_PCM_RATE_KNOT, \
 		.formats =  SNDRV_PCM_FMTBIT_S16_LE | \
 					SNDRV_PCM_FMTBIT_S32_LE, \
 	}, \
@@ -1293,9 +1170,7 @@ static struct snd_soc_dai_driver cygnus_spdif_dai_info = {
 	.playback = {
 		.channels_min = 2,
 		.channels_max = 2,
-		.rates = CYGNUS_TDM_RATE | SNDRV_PCM_RATE_88200 |
-			SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
-			SNDRV_PCM_RATE_192000,
+		.rates = SNDRV_PCM_RATE_KNOT,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE |
 			SNDRV_PCM_FMTBIT_S32_LE,
 	},
-- 
2.13.3

^ permalink raw reply related	[flat|nested] 50+ messages in thread

* Re: [PATCH 2/9] ASoC: cygnus: Update bindings for audio clock changes
  2017-08-15 17:14     ` Mark Brown
@ 2017-08-15 19:29       ` Lori Hikichi
  -1 siblings, 0 replies; 50+ messages in thread
From: Lori Hikichi @ 2017-08-15 19:29 UTC (permalink / raw)
  To: Mark Brown
  Cc: Liam Girdwood, Rob Herring, Mark Rutland, Ray Jui, Scott Branden,
	Jon Mason, bcm-kernel-feedback-list, Jaroslav Kysela,
	Takashi Iwai, alsa-devel, devicetree, linux-arm-kernel,
	linux-kernel


On 8/15/2017 10:14 AM, Mark Brown wrote:
> On Mon, Aug 14, 2017 at 03:06:50PM -0700, Lori Hikichi wrote:
>> Allow each audio port to select which clock (if any) it wants to use.
> Why is this in DT for the port and not either using standard clock
> bindings to configure the clock tree or allowing the machine driver to
> pick?
The previous version of the driver essentially had a clock mapping
that could not be changed. This is fine for 99% of our use cases. 
If we need to change the mapping, then we need to modify the audio
port's clock mux. Creating a clock for these muxes was going to be messy.
There is a mux per audio port and the registers used to program the
muxes are staggered throughout the io space used by the audio driver.
Additionally, these registers have bits that are controlled by the
audio driver. Had I used syscon to access these registers this would
have resulted in a very fragmented io space, complicating the audio
drivers access this space.
I have put the mux assignment in DT because the assignment is a
static property and did not need run time programmability from the
machine driver.

Lori.

^ permalink raw reply	[flat|nested] 50+ messages in thread

* [PATCH 2/9] ASoC: cygnus: Update bindings for audio clock changes
@ 2017-08-15 19:29       ` Lori Hikichi
  0 siblings, 0 replies; 50+ messages in thread
From: Lori Hikichi @ 2017-08-15 19:29 UTC (permalink / raw)
  To: linux-arm-kernel


On 8/15/2017 10:14 AM, Mark Brown wrote:
> On Mon, Aug 14, 2017 at 03:06:50PM -0700, Lori Hikichi wrote:
>> Allow each audio port to select which clock (if any) it wants to use.
> Why is this in DT for the port and not either using standard clock
> bindings to configure the clock tree or allowing the machine driver to
> pick?
The previous version of the driver essentially had a clock mapping
that could not be changed. This is fine for 99% of our use cases. 
If we need to change the mapping, then we need to modify the audio
port's clock mux. Creating a clock for these muxes was going to be messy.
There is a mux per audio port and the registers used to program the
muxes are staggered throughout the io space used by the audio driver.
Additionally, these registers have bits that are controlled by the
audio driver. Had I used syscon to access these registers this would
have resulted in a very fragmented io space, complicating the audio
drivers access this space.
I have put the mux assignment in DT because the assignment is a
static property and did not need run time programmability from the
machine driver.

Lori.

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH 2/9] ASoC: cygnus: Update bindings for audio clock changes
  2017-08-15 19:29       ` Lori Hikichi
  (?)
@ 2017-08-16 10:59         ` Mark Brown
  -1 siblings, 0 replies; 50+ messages in thread
From: Mark Brown @ 2017-08-16 10:59 UTC (permalink / raw)
  To: Lori Hikichi
  Cc: Liam Girdwood, Rob Herring, Mark Rutland, Ray Jui, Scott Branden,
	Jon Mason, bcm-kernel-feedback-list, Jaroslav Kysela,
	Takashi Iwai, alsa-devel, devicetree, linux-arm-kernel,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 414 bytes --]

On Tue, Aug 15, 2017 at 12:29:44PM -0700, Lori Hikichi wrote:

> I have put the mux assignment in DT because the assignment is a
> static property and did not need run time programmability from the
> machine driver.

Why is this a static property, what prevents something wanting to change
things at runtime?  You might be running with simpler setups now but
perhaps you'll run into a more complex use case later?

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH 2/9] ASoC: cygnus: Update bindings for audio clock changes
@ 2017-08-16 10:59         ` Mark Brown
  0 siblings, 0 replies; 50+ messages in thread
From: Mark Brown @ 2017-08-16 10:59 UTC (permalink / raw)
  To: Lori Hikichi
  Cc: Mark Rutland, devicetree, alsa-devel, linux-kernel,
	Scott Branden, Jon Mason, Ray Jui, Takashi Iwai, Liam Girdwood,
	Rob Herring, bcm-kernel-feedback-list, linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 414 bytes --]

On Tue, Aug 15, 2017 at 12:29:44PM -0700, Lori Hikichi wrote:

> I have put the mux assignment in DT because the assignment is a
> static property and did not need run time programmability from the
> machine driver.

Why is this a static property, what prevents something wanting to change
things at runtime?  You might be running with simpler setups now but
perhaps you'll run into a more complex use case later?

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 50+ messages in thread

* [PATCH 2/9] ASoC: cygnus: Update bindings for audio clock changes
@ 2017-08-16 10:59         ` Mark Brown
  0 siblings, 0 replies; 50+ messages in thread
From: Mark Brown @ 2017-08-16 10:59 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Aug 15, 2017 at 12:29:44PM -0700, Lori Hikichi wrote:

> I have put the mux assignment in DT because the assignment is a
> static property and did not need run time programmability from the
> machine driver.

Why is this a static property, what prevents something wanting to change
things at runtime?  You might be running with simpler setups now but
perhaps you'll run into a more complex use case later?
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20170816/98363145/attachment.sig>

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH 2/9] ASoC: cygnus: Update bindings for audio clock changes
  2017-08-16 10:59         ` Mark Brown
@ 2017-08-16 19:39           ` Lori Hikichi
  -1 siblings, 0 replies; 50+ messages in thread
From: Lori Hikichi @ 2017-08-16 19:39 UTC (permalink / raw)
  To: Mark Brown
  Cc: Liam Girdwood, Rob Herring, Mark Rutland, Ray Jui, Scott Branden,
	Jon Mason, bcm-kernel-feedback-list, Jaroslav Kysela,
	Takashi Iwai, alsa-devel, devicetree, linux-arm-kernel,
	linux-kernel


On 8/16/2017 3:59 AM, Mark Brown wrote:
> On Tue, Aug 15, 2017 at 12:29:44PM -0700, Lori Hikichi wrote:
>
>> I have put the mux assignment in DT because the assignment is a
>> static property and did not need run time programmability from the
>> machine driver.
> Why is this a static property, what prevents something wanting to change
> things at runtime?  You might be running with simpler setups now but
> perhaps you'll run into a more complex use case later?
The short answer is I have analyzed the possible use cases for Cygnus'
audio block, and nothing should need to change the assignments at
runtime.  The longer explanation follows.

The clocking configuration is this. There is one pll with its output run
through 3 post dividers. The audio ports can select one of these
outputs.  There are only 5 possible consumers of these 3 clocks.
The 3 i2s/tdm ports, 1 spdif port, and an exceptional case of another
"non-audio" IP block. For the i2s/tdm ports this clock is the MCLK.

By far the most common usage case for Cygnus is a configuration which
uses only the three i2s/tdm ports. In this case each port is assigned
a clock.  Each clock has the same capabilities so there would never be
a reason change the static mapping.

Now for the case when the "non-audio block" uses one of these clocks.
In this situation we will only need one i2s port because this
configuration of the chip is not audio intensive.  When the system
is designed we know if this non-audio block will be in use, it is not
a runtime configurable thing. Again, a static mapping is fine.

The only situation which could get more complex is with SPDIF.
First off, the SPDIF port is not actively used in any current
configuration and I do not think there are any plans for it to be used.
But, we are talking about possible future configurations.  The only
limitation the current static scheme would introduce is if SPDIF is
active along with all 3 i2s ports. Additionally, all 3 of the i2s ports
would need to be in master mode (slave mode would free up a clock for
SPDIF). In this case, two of the clock consumers would need to share a
clock. In this situation I envisioned that both consumers would agree on
a fixed rate and work within those limitation.  For example, the ports
would choose 24.576 MHz as their mclk and be limited to the the frame
rates that could be derived from that clock. 

At the time it did not seem necessary to make addition driver changes to
support a use case that will very likely never arise. As it turns out,
we are working on a new version of this audio block.  The clocking
configuration for this new version is more complex and I am already in
the process of creating clock bindings for all this this. I am hopeful
that the driver for this new version will be applicable to Cygnus.

Lori.

^ permalink raw reply	[flat|nested] 50+ messages in thread

* [PATCH 2/9] ASoC: cygnus: Update bindings for audio clock changes
@ 2017-08-16 19:39           ` Lori Hikichi
  0 siblings, 0 replies; 50+ messages in thread
From: Lori Hikichi @ 2017-08-16 19:39 UTC (permalink / raw)
  To: linux-arm-kernel


On 8/16/2017 3:59 AM, Mark Brown wrote:
> On Tue, Aug 15, 2017 at 12:29:44PM -0700, Lori Hikichi wrote:
>
>> I have put the mux assignment in DT because the assignment is a
>> static property and did not need run time programmability from the
>> machine driver.
> Why is this a static property, what prevents something wanting to change
> things at runtime?  You might be running with simpler setups now but
> perhaps you'll run into a more complex use case later?
The short answer is I have analyzed the possible use cases for Cygnus'
audio block, and nothing should need to change the assignments at
runtime.  The longer explanation follows.

The clocking configuration is this. There is one pll with its output run
through 3 post dividers. The audio ports can select one of these
outputs.  There are only 5 possible consumers of these 3 clocks.
The 3 i2s/tdm ports, 1 spdif port, and an exceptional case of another
"non-audio" IP block. For the i2s/tdm ports this clock is the MCLK.

By far the most common usage case for Cygnus is a configuration which
uses only the three i2s/tdm ports. In this case each port is assigned
a clock.  Each clock has the same capabilities so there would never be
a reason change the static mapping.

Now for the case when the "non-audio block" uses one of these clocks.
In this situation we will only need one i2s port because this
configuration of the chip is not audio intensive.  When the system
is designed we know if this non-audio block will be in use, it is not
a runtime configurable thing. Again, a static mapping is fine.

The only situation which could get more complex is with SPDIF.
First off, the SPDIF port is not actively used in any current
configuration and I do not think there are any plans for it to be used.
But, we are talking about possible future configurations.  The only
limitation the current static scheme would introduce is if SPDIF is
active along with all 3 i2s ports. Additionally, all 3 of the i2s ports
would need to be in master mode (slave mode would free up a clock for
SPDIF). In this case, two of the clock consumers would need to share a
clock. In this situation I envisioned that both consumers would agree on
a fixed rate and work within those limitation.  For example, the ports
would choose 24.576 MHz as their mclk and be limited to the the frame
rates that could be derived from that clock. 

At the time it did not seem necessary to make addition driver changes to
support a use case that will very likely never arise. As it turns out,
we are working on a new version of this audio block.  The clocking
configuration for this new version is more complex and I am already in
the process of creating clock bindings for all this this. I am hopeful
that the driver for this new version will be applicable to Cygnus.

Lori.

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH 2/9] ASoC: cygnus: Update bindings for audio clock changes
  2017-08-16 19:39           ` Lori Hikichi
  (?)
@ 2017-08-22 16:07             ` Mark Brown
  -1 siblings, 0 replies; 50+ messages in thread
From: Mark Brown @ 2017-08-22 16:07 UTC (permalink / raw)
  To: Lori Hikichi
  Cc: Liam Girdwood, Rob Herring, Mark Rutland, Ray Jui, Scott Branden,
	Jon Mason, bcm-kernel-feedback-list, Jaroslav Kysela,
	Takashi Iwai, alsa-devel, devicetree, linux-arm-kernel,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 1523 bytes --]

On Wed, Aug 16, 2017 at 12:39:42PM -0700, Lori Hikichi wrote:

> By far the most common usage case for Cygnus is a configuration which
> uses only the three i2s/tdm ports. In this case each port is assigned
> a clock.  Each clock has the same capabilities so there would never be
> a reason change the static mapping.

The usual reason would be to bring things into sync.

> Now for the case when the "non-audio block" uses one of these clocks.
> In this situation we will only need one i2s port because this
> configuration of the chip is not audio intensive.  When the system
> is designed we know if this non-audio block will be in use, it is not
> a runtime configurable thing. Again, a static mapping is fine.

Is this limitation when the other block is in use a physical limitation
or is it just a case of not seeing the use case.

> At the time it did not seem necessary to make addition driver changes to
> support a use case that will very likely never arise. As it turns out,
> we are working on a new version of this audio block.  The clocking
> configuration for this new version is more complex and I am already in
> the process of creating clock bindings for all this this. I am hopeful
> that the driver for this new version will be applicable to Cygnus.

If the clocking is more complex that seems like even more reason to not
fix this in the binding, and possibly to do as I think I suggested
earlier and use the common clock bindings to manage this rather than
doing something custom and driver specific.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH 2/9] ASoC: cygnus: Update bindings for audio clock changes
@ 2017-08-22 16:07             ` Mark Brown
  0 siblings, 0 replies; 50+ messages in thread
From: Mark Brown @ 2017-08-22 16:07 UTC (permalink / raw)
  To: Lori Hikichi
  Cc: Mark Rutland, devicetree, alsa-devel, linux-kernel,
	Scott Branden, Jon Mason, Ray Jui, Takashi Iwai, Liam Girdwood,
	Rob Herring, bcm-kernel-feedback-list, linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 1523 bytes --]

On Wed, Aug 16, 2017 at 12:39:42PM -0700, Lori Hikichi wrote:

> By far the most common usage case for Cygnus is a configuration which
> uses only the three i2s/tdm ports. In this case each port is assigned
> a clock.  Each clock has the same capabilities so there would never be
> a reason change the static mapping.

The usual reason would be to bring things into sync.

> Now for the case when the "non-audio block" uses one of these clocks.
> In this situation we will only need one i2s port because this
> configuration of the chip is not audio intensive.  When the system
> is designed we know if this non-audio block will be in use, it is not
> a runtime configurable thing. Again, a static mapping is fine.

Is this limitation when the other block is in use a physical limitation
or is it just a case of not seeing the use case.

> At the time it did not seem necessary to make addition driver changes to
> support a use case that will very likely never arise. As it turns out,
> we are working on a new version of this audio block.  The clocking
> configuration for this new version is more complex and I am already in
> the process of creating clock bindings for all this this. I am hopeful
> that the driver for this new version will be applicable to Cygnus.

If the clocking is more complex that seems like even more reason to not
fix this in the binding, and possibly to do as I think I suggested
earlier and use the common clock bindings to manage this rather than
doing something custom and driver specific.

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 50+ messages in thread

* [PATCH 2/9] ASoC: cygnus: Update bindings for audio clock changes
@ 2017-08-22 16:07             ` Mark Brown
  0 siblings, 0 replies; 50+ messages in thread
From: Mark Brown @ 2017-08-22 16:07 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Aug 16, 2017 at 12:39:42PM -0700, Lori Hikichi wrote:

> By far the most common usage case for Cygnus is a configuration which
> uses only the three i2s/tdm ports. In this case each port is assigned
> a clock.  Each clock has the same capabilities so there would never be
> a reason change the static mapping.

The usual reason would be to bring things into sync.

> Now for the case when the "non-audio block" uses one of these clocks.
> In this situation we will only need one i2s port because this
> configuration of the chip is not audio intensive.  When the system
> is designed we know if this non-audio block will be in use, it is not
> a runtime configurable thing. Again, a static mapping is fine.

Is this limitation when the other block is in use a physical limitation
or is it just a case of not seeing the use case.

> At the time it did not seem necessary to make addition driver changes to
> support a use case that will very likely never arise. As it turns out,
> we are working on a new version of this audio block.  The clocking
> configuration for this new version is more complex and I am already in
> the process of creating clock bindings for all this this. I am hopeful
> that the driver for this new version will be applicable to Cygnus.

If the clocking is more complex that seems like even more reason to not
fix this in the binding, and possibly to do as I think I suggested
earlier and use the common clock bindings to manage this rather than
doing something custom and driver specific.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20170822/11261f81/attachment-0001.sig>

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH 2/9] ASoC: cygnus: Update bindings for audio clock changes
@ 2017-09-07  1:45               ` Lori Hikichi
  0 siblings, 0 replies; 50+ messages in thread
From: Lori Hikichi @ 2017-09-07  1:45 UTC (permalink / raw)
  To: Mark Brown
  Cc: Liam Girdwood, Rob Herring, Mark Rutland, Ray Jui, Scott Branden,
	Jon Mason, bcm-kernel-feedback-list, Jaroslav Kysela,
	Takashi Iwai, alsa-devel, devicetree, linux-arm-kernel,
	linux-kernel



On 8/22/2017 9:07 AM, Mark Brown wrote:
> On Wed, Aug 16, 2017 at 12:39:42PM -0700, Lori Hikichi wrote:
>
>> By far the most common usage case for Cygnus is a configuration which
>> uses only the three i2s/tdm ports. In this case each port is assigned
>> a clock.  Each clock has the same capabilities so there would never be
>> a reason change the static mapping.
> The usual reason would be to bring things into sync.
>
>> Now for the case when the "non-audio block" uses one of these clocks.
>> In this situation we will only need one i2s port because this
>> configuration of the chip is not audio intensive.  When the system
>> is designed we know if this non-audio block will be in use, it is not
>> a runtime configurable thing. Again, a static mapping is fine.
> Is this limitation when the other block is in use a physical limitation
> or is it just a case of not seeing the use case.
>
>> At the time it did not seem necessary to make addition driver changes to
>> support a use case that will very likely never arise. As it turns out,
>> we are working on a new version of this audio block.  The clocking
>> configuration for this new version is more complex and I am already in
>> the process of creating clock bindings for all this this. I am hopeful
>> that the driver for this new version will be applicable to Cygnus.
> If the clocking is more complex that seems like even more reason to not
> fix this in the binding, and possibly to do as I think I suggested
> earlier and use the common clock bindings to manage this rather than
> doing something custom and driver specific.
Ok, I will create the necessary clocks to allow this to work.
This will likely impact a couple of the other patches in the series, but
most should be applicable. What would be the best way to have some of the
other patches in this series reviewed?  Should I just drop this series and
resubmit new individual patches for review.

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH 2/9] ASoC: cygnus: Update bindings for audio clock changes
@ 2017-09-07  1:45               ` Lori Hikichi
  0 siblings, 0 replies; 50+ messages in thread
From: Lori Hikichi @ 2017-09-07  1:45 UTC (permalink / raw)
  To: Mark Brown
  Cc: Liam Girdwood, Rob Herring, Mark Rutland, Ray Jui, Scott Branden,
	Jon Mason, bcm-kernel-feedback-list-dY08KVG/lbpWk0Htik3J/w,
	Jaroslav Kysela, Takashi Iwai, alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA



On 8/22/2017 9:07 AM, Mark Brown wrote:
> On Wed, Aug 16, 2017 at 12:39:42PM -0700, Lori Hikichi wrote:
>
>> By far the most common usage case for Cygnus is a configuration which
>> uses only the three i2s/tdm ports. In this case each port is assigned
>> a clock.  Each clock has the same capabilities so there would never be
>> a reason change the static mapping.
> The usual reason would be to bring things into sync.
>
>> Now for the case when the "non-audio block" uses one of these clocks.
>> In this situation we will only need one i2s port because this
>> configuration of the chip is not audio intensive.  When the system
>> is designed we know if this non-audio block will be in use, it is not
>> a runtime configurable thing. Again, a static mapping is fine.
> Is this limitation when the other block is in use a physical limitation
> or is it just a case of not seeing the use case.
>
>> At the time it did not seem necessary to make addition driver changes to
>> support a use case that will very likely never arise. As it turns out,
>> we are working on a new version of this audio block.  The clocking
>> configuration for this new version is more complex and I am already in
>> the process of creating clock bindings for all this this. I am hopeful
>> that the driver for this new version will be applicable to Cygnus.
> If the clocking is more complex that seems like even more reason to not
> fix this in the binding, and possibly to do as I think I suggested
> earlier and use the common clock bindings to manage this rather than
> doing something custom and driver specific.
Ok, I will create the necessary clocks to allow this to work.
This will likely impact a couple of the other patches in the series, but
most should be applicable. What would be the best way to have some of the
other patches in this series reviewed?  Should I just drop this series and
resubmit new individual patches for review.




--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 50+ messages in thread

* [PATCH 2/9] ASoC: cygnus: Update bindings for audio clock changes
@ 2017-09-07  1:45               ` Lori Hikichi
  0 siblings, 0 replies; 50+ messages in thread
From: Lori Hikichi @ 2017-09-07  1:45 UTC (permalink / raw)
  To: linux-arm-kernel



On 8/22/2017 9:07 AM, Mark Brown wrote:
> On Wed, Aug 16, 2017 at 12:39:42PM -0700, Lori Hikichi wrote:
>
>> By far the most common usage case for Cygnus is a configuration which
>> uses only the three i2s/tdm ports. In this case each port is assigned
>> a clock.  Each clock has the same capabilities so there would never be
>> a reason change the static mapping.
> The usual reason would be to bring things into sync.
>
>> Now for the case when the "non-audio block" uses one of these clocks.
>> In this situation we will only need one i2s port because this
>> configuration of the chip is not audio intensive.  When the system
>> is designed we know if this non-audio block will be in use, it is not
>> a runtime configurable thing. Again, a static mapping is fine.
> Is this limitation when the other block is in use a physical limitation
> or is it just a case of not seeing the use case.
>
>> At the time it did not seem necessary to make addition driver changes to
>> support a use case that will very likely never arise. As it turns out,
>> we are working on a new version of this audio block.  The clocking
>> configuration for this new version is more complex and I am already in
>> the process of creating clock bindings for all this this. I am hopeful
>> that the driver for this new version will be applicable to Cygnus.
> If the clocking is more complex that seems like even more reason to not
> fix this in the binding, and possibly to do as I think I suggested
> earlier and use the common clock bindings to manage this rather than
> doing something custom and driver specific.
Ok, I will create the necessary clocks to allow this to work.
This will likely impact a couple of the other patches in the series, but
most should be applicable. What would be the best way to have some of the
other patches in this series reviewed?  Should I just drop this series and
resubmit new individual patches for review.

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH 2/9] ASoC: cygnus: Update bindings for audio clock changes
  2017-09-07  1:45               ` Lori Hikichi
  (?)
@ 2017-09-25 16:28                 ` Mark Brown
  -1 siblings, 0 replies; 50+ messages in thread
From: Mark Brown @ 2017-09-25 16:28 UTC (permalink / raw)
  To: Lori Hikichi
  Cc: Liam Girdwood, Rob Herring, Mark Rutland, Ray Jui, Scott Branden,
	Jon Mason, bcm-kernel-feedback-list, Jaroslav Kysela,
	Takashi Iwai, alsa-devel, devicetree, linux-arm-kernel,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 462 bytes --]

On Wed, Sep 06, 2017 at 06:45:22PM -0700, Lori Hikichi wrote:

> This will likely impact a couple of the other patches in the series, but
> most should be applicable. What would be the best way to have some of the
> other patches in this series reviewed?  Should I just drop this series and
> resubmit new individual patches for review.

Resubmit the ones that can be applied as is please, that'll avoid me
making a mistake about which ones have the dependency.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH 2/9] ASoC: cygnus: Update bindings for audio clock changes
@ 2017-09-25 16:28                 ` Mark Brown
  0 siblings, 0 replies; 50+ messages in thread
From: Mark Brown @ 2017-09-25 16:28 UTC (permalink / raw)
  To: Lori Hikichi
  Cc: Mark Rutland, devicetree, alsa-devel, linux-kernel,
	Scott Branden, Jon Mason, Ray Jui, Takashi Iwai, Liam Girdwood,
	Jaroslav Kysela, Rob Herring, bcm-kernel-feedback-list,
	linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 462 bytes --]

On Wed, Sep 06, 2017 at 06:45:22PM -0700, Lori Hikichi wrote:

> This will likely impact a couple of the other patches in the series, but
> most should be applicable. What would be the best way to have some of the
> other patches in this series reviewed?  Should I just drop this series and
> resubmit new individual patches for review.

Resubmit the ones that can be applied as is please, that'll avoid me
making a mistake about which ones have the dependency.

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 50+ messages in thread

* [PATCH 2/9] ASoC: cygnus: Update bindings for audio clock changes
@ 2017-09-25 16:28                 ` Mark Brown
  0 siblings, 0 replies; 50+ messages in thread
From: Mark Brown @ 2017-09-25 16:28 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Sep 06, 2017 at 06:45:22PM -0700, Lori Hikichi wrote:

> This will likely impact a couple of the other patches in the series, but
> most should be applicable. What would be the best way to have some of the
> other patches in this series reviewed?  Should I just drop this series and
> resubmit new individual patches for review.

Resubmit the ones that can be applied as is please, that'll avoid me
making a mistake about which ones have the dependency.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20170925/04624d06/attachment-0001.sig>

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Applied "ASoC: cygnus: Add EXPORT_SYMBOL for helper function" to the asoc tree
  2017-08-14 22:06   ` Lori Hikichi
  (?)
@ 2017-10-04 11:27     ` Mark Brown
  -1 siblings, 0 replies; 50+ messages in thread
From: Mark Brown @ 2017-10-04 11:27 UTC (permalink / raw)
  To: Lori Hikichi
  Cc: Mark Brown, Liam Girdwood, Mark Brown, Rob Herring, Mark Rutland,
	Ray Jui, Scott Branden, Jon Mason, bcm-kernel-feedback-list,
	Jaroslav Kysela, Takashi Iwai, devicetree, alsa-devel,
	linux-kernel, linux-arm-kernel, alsa-devel

The patch

   ASoC: cygnus: Add EXPORT_SYMBOL for helper function

has been applied to the asoc tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From d8302aa6b53acbe421fe615b9d704fd813623e96 Mon Sep 17 00:00:00 2001
From: Lori Hikichi <lori.hikichi@broadcom.com>
Date: Thu, 28 Sep 2017 15:29:32 -0700
Subject: [PATCH] ASoC: cygnus: Add EXPORT_SYMBOL for helper function

The helper function cygnus_ssp_set_custom_fsync_width() is intended
to be called from an ASoC machine driver, need to export symbol
if using modules.

Signed-off-by: Lori Hikichi <lori.hikichi@broadcom.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
 sound/soc/bcm/cygnus-ssp.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c
index 15c438f0f22d..e9c73a451cf6 100644
--- a/sound/soc/bcm/cygnus-ssp.c
+++ b/sound/soc/bcm/cygnus-ssp.c
@@ -842,6 +842,7 @@ int cygnus_ssp_set_custom_fsync_width(struct snd_soc_dai *cpu_dai, int len)
 		return -EINVAL;
 	}
 }
+EXPORT_SYMBOL_GPL(cygnus_ssp_set_custom_fsync_width);
 
 static int cygnus_ssp_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 {
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 50+ messages in thread

* Applied "ASoC: cygnus: Add EXPORT_SYMBOL for helper function" to the asoc tree
@ 2017-10-04 11:27     ` Mark Brown
  0 siblings, 0 replies; 50+ messages in thread
From: Mark Brown @ 2017-10-04 11:27 UTC (permalink / raw)
  To: Lori Hikichi; +Cc: Mark Brown, Liam Girdwood

The patch

   ASoC: cygnus: Add EXPORT_SYMBOL for helper function

has been applied to the asoc tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From d8302aa6b53acbe421fe615b9d704fd813623e96 Mon Sep 17 00:00:00 2001
From: Lori Hikichi <lori.hikichi@broadcom.com>
Date: Thu, 28 Sep 2017 15:29:32 -0700
Subject: [PATCH] ASoC: cygnus: Add EXPORT_SYMBOL for helper function

The helper function cygnus_ssp_set_custom_fsync_width() is intended
to be called from an ASoC machine driver, need to export symbol
if using modules.

Signed-off-by: Lori Hikichi <lori.hikichi@broadcom.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
 sound/soc/bcm/cygnus-ssp.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c
index 15c438f0f22d..e9c73a451cf6 100644
--- a/sound/soc/bcm/cygnus-ssp.c
+++ b/sound/soc/bcm/cygnus-ssp.c
@@ -842,6 +842,7 @@ int cygnus_ssp_set_custom_fsync_width(struct snd_soc_dai *cpu_dai, int len)
 		return -EINVAL;
 	}
 }
+EXPORT_SYMBOL_GPL(cygnus_ssp_set_custom_fsync_width);
 
 static int cygnus_ssp_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 {
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 50+ messages in thread

* Applied "ASoC: cygnus: Add EXPORT_SYMBOL for helper function" to the asoc tree
@ 2017-10-04 11:27     ` Mark Brown
  0 siblings, 0 replies; 50+ messages in thread
From: Mark Brown @ 2017-10-04 11:27 UTC (permalink / raw)
  To: linux-arm-kernel

The patch

   ASoC: cygnus: Add EXPORT_SYMBOL for helper function

has been applied to the asoc tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From d8302aa6b53acbe421fe615b9d704fd813623e96 Mon Sep 17 00:00:00 2001
From: Lori Hikichi <lori.hikichi@broadcom.com>
Date: Thu, 28 Sep 2017 15:29:32 -0700
Subject: [PATCH] ASoC: cygnus: Add EXPORT_SYMBOL for helper function

The helper function cygnus_ssp_set_custom_fsync_width() is intended
to be called from an ASoC machine driver, need to export symbol
if using modules.

Signed-off-by: Lori Hikichi <lori.hikichi@broadcom.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
 sound/soc/bcm/cygnus-ssp.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c
index 15c438f0f22d..e9c73a451cf6 100644
--- a/sound/soc/bcm/cygnus-ssp.c
+++ b/sound/soc/bcm/cygnus-ssp.c
@@ -842,6 +842,7 @@ int cygnus_ssp_set_custom_fsync_width(struct snd_soc_dai *cpu_dai, int len)
 		return -EINVAL;
 	}
 }
+EXPORT_SYMBOL_GPL(cygnus_ssp_set_custom_fsync_width);
 
 static int cygnus_ssp_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 {
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 50+ messages in thread

end of thread, other threads:[~2017-10-04 11:28 UTC | newest]

Thread overview: 50+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-08-14 22:06 [PATCH 0/9] ASoC: cygnus: Various improvements and fixes Lori Hikichi
2017-08-14 22:06 ` Lori Hikichi
2017-08-14 22:06 ` Lori Hikichi
2017-08-14 22:06 ` [PATCH 1/9] ASoC: cygnus: Add support for 384kHz frame rates Lori Hikichi
2017-08-14 22:06   ` Lori Hikichi
2017-08-15 17:15   ` Applied "ASoC: cygnus: Add support for 384kHz frame rates" to the asoc tree Mark Brown
2017-08-15 17:15     ` Mark Brown
2017-08-15 17:15     ` Mark Brown
2017-08-14 22:06 ` [PATCH 2/9] ASoC: cygnus: Update bindings for audio clock changes Lori Hikichi
2017-08-14 22:06   ` Lori Hikichi
2017-08-15 17:14   ` Mark Brown
2017-08-15 17:14     ` Mark Brown
2017-08-15 17:14     ` Mark Brown
2017-08-15 19:29     ` Lori Hikichi
2017-08-15 19:29       ` Lori Hikichi
2017-08-16 10:59       ` Mark Brown
2017-08-16 10:59         ` Mark Brown
2017-08-16 10:59         ` Mark Brown
2017-08-16 19:39         ` Lori Hikichi
2017-08-16 19:39           ` Lori Hikichi
2017-08-22 16:07           ` Mark Brown
2017-08-22 16:07             ` Mark Brown
2017-08-22 16:07             ` Mark Brown
2017-09-07  1:45             ` Lori Hikichi
2017-09-07  1:45               ` Lori Hikichi
2017-09-07  1:45               ` Lori Hikichi
2017-09-25 16:28               ` Mark Brown
2017-09-25 16:28                 ` Mark Brown
2017-09-25 16:28                 ` Mark Brown
2017-08-14 22:06 ` [PATCH 3/9] ASoC: cygnus: Allow each port to select its clock source Lori Hikichi
2017-08-14 22:06   ` Lori Hikichi
2017-08-14 22:06   ` Lori Hikichi
2017-08-14 22:06 ` [PATCH 4/9] ASoC: cygnus: Only enable MCLK pins when in use Lori Hikichi
2017-08-14 22:06   ` Lori Hikichi
2017-08-14 22:06 ` [PATCH 5/9] ASoC: cygnus: Remove support for 8 bit audio and for mono Lori Hikichi
2017-08-14 22:06   ` Lori Hikichi
2017-08-14 22:06   ` Lori Hikichi
2017-08-14 22:06 ` [PATCH 6/9] ASoc: cygnus: Fix problems with multichannel transfers Lori Hikichi
2017-08-14 22:06   ` Lori Hikichi
2017-08-14 22:06 ` [PATCH 7/9] ASoC: cygnus: Remove set_fmt from SPDIF dai ops Lori Hikichi
2017-08-14 22:06   ` Lori Hikichi
2017-08-14 22:06   ` Lori Hikichi
2017-08-14 22:06 ` [PATCH 8/9] ASoC: cygnus: Add EXPORT_SYMBOL for helper function Lori Hikichi
2017-08-14 22:06   ` Lori Hikichi
2017-10-04 11:27   ` Applied "ASoC: cygnus: Add EXPORT_SYMBOL for helper function" to the asoc tree Mark Brown
2017-10-04 11:27     ` Mark Brown
2017-10-04 11:27     ` Mark Brown
2017-08-14 22:06 ` [PATCH 9/9] ASoC: cygnus: Tidy up of structure access Lori Hikichi
2017-08-14 22:06   ` Lori Hikichi
2017-08-14 22:06   ` Lori Hikichi

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.