ASoC: jz4740: Add dynamic sampling rate support to jz4740-i2s
[firefly-linux-kernel-4.4.55.git] / sound / soc / jz4740 / jz4740-i2s.c
index d3d45c6f064f37d7f72647d8aca6948a8772a077..b7a7e8295d3c8a4a27833c1e54c216489e4c93fd 100644 (file)
@@ -83,6 +83,8 @@
 #define JZ_AIC_I2S_STATUS_BUSY BIT(2)
 
 #define JZ_AIC_CLK_DIV_MASK 0xf
+#define I2SDIV_DV_SHIFT 8
+#define I2SDIV_DV_MASK (0xf << I2SDIV_DV_SHIFT)
 
 struct jz4740_i2s {
        struct resource *mem;
@@ -237,10 +239,14 @@ static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream,
 {
        struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
        unsigned int sample_size;
-       uint32_t ctrl;
+       uint32_t ctrl, div_reg;
+       int div;
 
        ctrl = jz4740_i2s_read(i2s, JZ_REG_AIC_CTRL);
 
+       div_reg = jz4740_i2s_read(i2s, JZ_REG_AIC_CLK_DIV);
+       div = clk_get_rate(i2s->clk_i2s) / (64 * params_rate(params));
+
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S8:
                sample_size = 0;
@@ -264,7 +270,10 @@ static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream,
                ctrl |= sample_size << JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_OFFSET;
        }
 
+       div_reg &= ~I2SDIV_DV_MASK;
+       div_reg |= (div - 1) << I2SDIV_DV_SHIFT;
        jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl);
+       jz4740_i2s_write(i2s, JZ_REG_AIC_CLK_DIV, div_reg);
 
        return 0;
 }