diff mbox series

[RFC,3/3] drm/i2c: tda998x: add support for bclk_ratio

Message ID E1gxILr-0004Mm-WE@rmk-PC.armlinux.org.uk (mailing list archive)
State New, archived
Headers show
Series tda998x updates for DAI formats and bclk_ratio | expand

Commit Message

Russell King (Oracle) Feb. 22, 2019, 9:27 p.m. UTC
It appears that TDA998x derives the CTS value using the supplied I2S
bit clock (BCLK) rather than 128·fs.  TDA998x uses two constants named
m and k in the CTS generator such that we have this relationship
between the source BCLK and the sink fs:

	128·fs_sink = BCLK·m / k

Where BCLK = bclk_ratio·fs_source.

We have been lucky up to now that all users have scaled their bclk_ratio
to match the sample width - for example, on Beagle Bone Black, with a
16-bit sample width, BCLK = 32·fs, which increases to 64·fs for 32-bit
samples.  24-bit samples are sent as 32-bit.

We are now starting to see users whose I2S blocks send at 64·fs for
16-bit samples, which means TDA998x now breaks.

ASoC has a snd_soc_dai_set_bclk_ratio() call available which sets the
ratio of BCLK to the sample rate.  Implement support for this.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 drivers/gpu/drm/i2c/tda998x_drv.c | 20 +++++++++++++-------
 include/drm/i2c/tda998x.h         |  1 +
 2 files changed, 14 insertions(+), 7 deletions(-)

Comments

Jyri Sarha Feb. 25, 2019, 1:47 p.m. UTC | #1
On 22/02/2019 23:27, Russell King wrote:
> It appears that TDA998x derives the CTS value using the supplied I2S
> bit clock (BCLK) rather than 128·fs.  TDA998x uses two constants named
> m and k in the CTS generator such that we have this relationship
> between the source BCLK and the sink fs:
> 
> 	128·fs_sink = BCLK·m / k
> 
> Where BCLK = bclk_ratio·fs_source.
> 
> We have been lucky up to now that all users have scaled their bclk_ratio
> to match the sample width - for example, on Beagle Bone Black, with a
> 16-bit sample width, BCLK = 32·fs, which increases to 64·fs for 32-bit
> samples.  24-bit samples are sent as 32-bit.
> 
> We are now starting to see users whose I2S blocks send at 64·fs for
> 16-bit samples, which means TDA998x now breaks.
> 
> ASoC has a snd_soc_dai_set_bclk_ratio() call available which sets the
> ratio of BCLK to the sample rate.  Implement support for this.
> 
> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>

Works at least on Beaglebone-black.

Tested-by: Jyri Sarha <jsarha@ti.com>
Reviewed-by: Jyri Sarha <jsarha@ti.com>

> ---
>  drivers/gpu/drm/i2c/tda998x_drv.c | 20 +++++++++++++-------
>  include/drm/i2c/tda998x.h         |  1 +
>  2 files changed, 14 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c
> index 645d884fb9e8..f2d40235acf9 100644
> --- a/drivers/gpu/drm/i2c/tda998x_drv.c
> +++ b/drivers/gpu/drm/i2c/tda998x_drv.c
> @@ -895,21 +895,26 @@ tda998x_configure_audio(struct tda998x_priv *priv,
>  		reg_write(priv, REG_MUX_AP, MUX_AP_SELECT_I2S);
>  		clksel_aip = AIP_CLKSEL_AIP_I2S;
>  		clksel_fs = AIP_CLKSEL_FS_ACLK;
> -		switch (params->sample_width) {
> +		switch (params->bclk_ratio) {
>  		case 16:
> +			cts_n = CTS_N_M(3) | CTS_N_K(0);
> +			break;
> +		case 32:
>  			cts_n = CTS_N_M(3) | CTS_N_K(1);
>  			break;
> -		case 18:
> -		case 20:
> -		case 24:
> +		case 48:
>  			cts_n = CTS_N_M(3) | CTS_N_K(2);
>  			break;
> -		default:
> -		case 32:
> +		case 64:
>  			cts_n = CTS_N_M(3) | CTS_N_K(3);
>  			break;
> +		case 128:
> +			cts_n = CTS_N_M(0) | CTS_N_K(0);
> +			break;
> +		default:
> +			dev_err(&priv->hdmi->dev, "unsupported I2S bclk ratio\n");
> +			return -EINVAL;
>  		}
> -
>  		switch (params->format & AFMT_I2S_MASK) {
>  		case AFMT_I2S_LEFT_J:
>  			i2s_fmt = I2S_FORMAT_LEFT_J;
> @@ -997,6 +1002,7 @@ static int tda998x_audio_hw_params(struct device *dev, void *data,
>  	struct tda998x_priv *priv = dev_get_drvdata(dev);
>  	int i, ret;
>  	struct tda998x_audio_params audio = {
> +		.bclk_ratio = daifmt->bclk_ratio,
>  		.sample_width = params->sample_width,
>  		.sample_rate = params->sample_rate,
>  		.cea = params->cea,
> diff --git a/include/drm/i2c/tda998x.h b/include/drm/i2c/tda998x.h
> index b0864f0be017..4e0f0cd2d428 100644
> --- a/include/drm/i2c/tda998x.h
> +++ b/include/drm/i2c/tda998x.h
> @@ -19,6 +19,7 @@ enum {
>  struct tda998x_audio_params {
>  	u8 config;
>  	u8 format;
> +	u8 bclk_ratio;
>  	unsigned sample_width;
>  	unsigned sample_rate;
>  	struct hdmi_audio_infoframe cea;
>
Sven Van Asbroeck Feb. 25, 2019, 4:26 p.m. UTC | #2
On Fri, Feb 22, 2019 at 4:27 PM Russell King <rmk+kernel@armlinux.org.uk> wrote:
>
> It appears that TDA998x derives the CTS value using the supplied I2S
> bit clock (BCLK) rather than 128·fs.  TDA998x uses two constants named
> m and k in the CTS generator such that we have this relationship
> between the source BCLK and the sink fs:
>
>         128·fs_sink = BCLK·m / k
>
> Where BCLK = bclk_ratio·fs_source.
>
> We have been lucky up to now that all users have scaled their bclk_ratio
> to match the sample width - for example, on Beagle Bone Black, with a
> 16-bit sample width, BCLK = 32·fs, which increases to 64·fs for 32-bit
> samples.  24-bit samples are sent as 32-bit.
>
> We are now starting to see users whose I2S blocks send at 64·fs for
> 16-bit samples, which means TDA998x now breaks.
>
> ASoC has a snd_soc_dai_set_bclk_ratio() call available which sets the
> ratio of BCLK to the sample rate.  Implement support for this.
>
> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>

Works with an imx6q ssi, but only if the card driver calls
set_bclk_ratio() with the correct value, which is 32/channel
for the fsl_ssi in master mode.

I will post an RFC patch shortly which adds bclk-ratio support
to simple-card.

Tested-by: Sven Van Asbroeck <TheSven73@gmail.com>
diff mbox series

Patch

diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c
index 645d884fb9e8..f2d40235acf9 100644
--- a/drivers/gpu/drm/i2c/tda998x_drv.c
+++ b/drivers/gpu/drm/i2c/tda998x_drv.c
@@ -895,21 +895,26 @@  tda998x_configure_audio(struct tda998x_priv *priv,
 		reg_write(priv, REG_MUX_AP, MUX_AP_SELECT_I2S);
 		clksel_aip = AIP_CLKSEL_AIP_I2S;
 		clksel_fs = AIP_CLKSEL_FS_ACLK;
-		switch (params->sample_width) {
+		switch (params->bclk_ratio) {
 		case 16:
+			cts_n = CTS_N_M(3) | CTS_N_K(0);
+			break;
+		case 32:
 			cts_n = CTS_N_M(3) | CTS_N_K(1);
 			break;
-		case 18:
-		case 20:
-		case 24:
+		case 48:
 			cts_n = CTS_N_M(3) | CTS_N_K(2);
 			break;
-		default:
-		case 32:
+		case 64:
 			cts_n = CTS_N_M(3) | CTS_N_K(3);
 			break;
+		case 128:
+			cts_n = CTS_N_M(0) | CTS_N_K(0);
+			break;
+		default:
+			dev_err(&priv->hdmi->dev, "unsupported I2S bclk ratio\n");
+			return -EINVAL;
 		}
-
 		switch (params->format & AFMT_I2S_MASK) {
 		case AFMT_I2S_LEFT_J:
 			i2s_fmt = I2S_FORMAT_LEFT_J;
@@ -997,6 +1002,7 @@  static int tda998x_audio_hw_params(struct device *dev, void *data,
 	struct tda998x_priv *priv = dev_get_drvdata(dev);
 	int i, ret;
 	struct tda998x_audio_params audio = {
+		.bclk_ratio = daifmt->bclk_ratio,
 		.sample_width = params->sample_width,
 		.sample_rate = params->sample_rate,
 		.cea = params->cea,
diff --git a/include/drm/i2c/tda998x.h b/include/drm/i2c/tda998x.h
index b0864f0be017..4e0f0cd2d428 100644
--- a/include/drm/i2c/tda998x.h
+++ b/include/drm/i2c/tda998x.h
@@ -19,6 +19,7 @@  enum {
 struct tda998x_audio_params {
 	u8 config;
 	u8 format;
+	u8 bclk_ratio;
 	unsigned sample_width;
 	unsigned sample_rate;
 	struct hdmi_audio_infoframe cea;