ASoC: pxa-ssp: remove .set_pll() and .set_clkdiv() callbacks
[sfrench/cifs-2.6.git] / sound / soc / pxa / pxa-ssp.c
index 01d54697ede47142882b3f21a14841fc5c0f83b7..f8339bb01251981462d6e64fcf084960f4dd56dc 100644 (file)
@@ -41,6 +41,7 @@
  */
 struct ssp_priv {
        struct ssp_device *ssp;
+       unsigned long ssp_clk;
        unsigned int sysclk;
        unsigned int dai_fmt;
        unsigned int configured_dai_fmt;
@@ -192,21 +193,6 @@ static void pxa_ssp_set_scr(struct ssp_device *ssp, u32 div)
        pxa_ssp_write_reg(ssp, SSCR0, sscr0);
 }
 
-/**
- * pxa_ssp_get_clkdiv - get SSP clock divider
- */
-static u32 pxa_ssp_get_scr(struct ssp_device *ssp)
-{
-       u32 sscr0 = pxa_ssp_read_reg(ssp, SSCR0);
-       u32 div;
-
-       if (ssp->type == PXA25x_SSP)
-               div = ((sscr0 >> 8) & 0xff) * 2 + 2;
-       else
-               div = ((sscr0 >> 8) & 0xfff) + 1;
-       return div;
-}
-
 /*
  * Set the SSP ports SYSCLK.
  */
@@ -262,67 +248,18 @@ static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
        return 0;
 }
 
-/*
- * Set the SSP clock dividers.
- */
-static int pxa_ssp_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
-       int div_id, int div)
-{
-       struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
-       struct ssp_device *ssp = priv->ssp;
-       int val;
-
-       switch (div_id) {
-       case PXA_SSP_AUDIO_DIV_ACDS:
-               val = (pxa_ssp_read_reg(ssp, SSACD) & ~0x7) | SSACD_ACDS(div);
-               pxa_ssp_write_reg(ssp, SSACD, val);
-               break;
-       case PXA_SSP_AUDIO_DIV_SCDB:
-               val = pxa_ssp_read_reg(ssp, SSACD);
-               val &= ~SSACD_SCDB;
-               if (ssp->type == PXA3xx_SSP)
-                       val &= ~SSACD_SCDX8;
-               switch (div) {
-               case PXA_SSP_CLK_SCDB_1:
-                       val |= SSACD_SCDB;
-                       break;
-               case PXA_SSP_CLK_SCDB_4:
-                       break;
-               case PXA_SSP_CLK_SCDB_8:
-                       if (ssp->type == PXA3xx_SSP)
-                               val |= SSACD_SCDX8;
-                       else
-                               return -EINVAL;
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               pxa_ssp_write_reg(ssp, SSACD, val);
-               break;
-       case PXA_SSP_DIV_SCR:
-               pxa_ssp_set_scr(ssp, div);
-               break;
-       default:
-               return -ENODEV;
-       }
-
-       return 0;
-}
-
 /*
  * Configure the PLL frequency pxa27x and (afaik - pxa320 only)
  */
-static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, int pll_id,
-       int source, unsigned int freq_in, unsigned int freq_out)
+static int pxa_ssp_set_pll(struct ssp_priv *priv, unsigned int freq)
 {
-       struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
        struct ssp_device *ssp = priv->ssp;
        u32 ssacd = pxa_ssp_read_reg(ssp, SSACD) & ~0x70;
 
        if (ssp->type == PXA3xx_SSP)
                pxa_ssp_write_reg(ssp, SSACDD, 0);
 
-       switch (freq_out) {
+       switch (freq) {
        case 5622000:
                break;
        case 11345000:
@@ -353,7 +290,7 @@ static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, int pll_id,
                        u64 tmp = 19968;
 
                        tmp *= 1000000;
-                       do_div(tmp, freq_out);
+                       do_div(tmp, freq);
                        val = tmp;
 
                        val = (val << 16) | 64;
@@ -363,7 +300,7 @@ static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, int pll_id,
 
                        dev_dbg(&ssp->pdev->dev,
                                "Using SSACDD %x to supply %uHz\n",
-                               val, freq_out);
+                               val, freq);
                        break;
                }
 
@@ -568,6 +505,24 @@ static int pxa_ssp_configure_dai_fmt(struct ssp_priv *priv)
        return 0;
 }
 
+struct pxa_ssp_clock_mode {
+       int rate;
+       int pll;
+       u8 acds;
+       u8 scdb;
+};
+
+static const struct pxa_ssp_clock_mode pxa_ssp_clock_modes[] = {
+       { .rate =  8000, .pll = 32842000, .acds = SSACD_ACDS_32, .scdb = SSACD_SCDB_4X },
+       { .rate = 11025, .pll =  5622000, .acds = SSACD_ACDS_4,  .scdb = SSACD_SCDB_4X },
+       { .rate = 16000, .pll = 32842000, .acds = SSACD_ACDS_16, .scdb = SSACD_SCDB_4X },
+       { .rate = 22050, .pll =  5622000, .acds = SSACD_ACDS_2,  .scdb = SSACD_SCDB_4X },
+       { .rate = 44100, .pll = 11345000, .acds = SSACD_ACDS_2,  .scdb = SSACD_SCDB_4X },
+       { .rate = 48000, .pll = 12235000, .acds = SSACD_ACDS_2,  .scdb = SSACD_SCDB_4X },
+       { .rate = 96000, .pll = 12235000, .acds = SSACD_ACDS_4,  .scdb = SSACD_SCDB_1X },
+       {}
+};
+
 /*
  * Set the SSP audio DMA parameters and sample size.
  * Can be called multiple times by oss emulation.
@@ -579,11 +534,12 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
        struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
        struct ssp_device *ssp = priv->ssp;
        int chn = params_channels(params);
-       u32 sscr0;
-       u32 sspsp;
+       u32 sscr0, sspsp;
        int width = snd_pcm_format_physical_width(params_format(params));
        int ttsa = pxa_ssp_read_reg(ssp, SSTSA) & 0xf;
        struct snd_dmaengine_dai_dma_data *dma_data;
+       int rate = params_rate(params);
+       int bclk = rate * chn * (width / 8);
        int ret;
 
        dma_data = snd_soc_dai_get_dma_data(cpu_dai, substream);
@@ -623,11 +579,57 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
        }
        pxa_ssp_write_reg(ssp, SSCR0, sscr0);
 
+       if (sscr0 & SSCR0_ACS) {
+               ret = pxa_ssp_set_pll(priv, bclk);
+
+               /*
+                * If we were able to generate the bclk directly,
+                * all is fine. Otherwise, look up the closest rate
+                * from the table and also set the dividers.
+                */
+
+               if (ret < 0) {
+                       const struct pxa_ssp_clock_mode *m;
+                       int ssacd, acds;
+
+                       for (m = pxa_ssp_clock_modes; m->rate; m++) {
+                               if (m->rate == rate)
+                                       break;
+                       }
+
+                       if (!m->rate)
+                               return -EINVAL;
+
+                       acds = m->acds;
+
+                       /* The values in the table are for 16 bits */
+                       if (width == 32)
+                               acds--;
+
+                       ret = pxa_ssp_set_pll(priv, bclk);
+                       if (ret < 0)
+                               return ret;
+
+                       ssacd = pxa_ssp_read_reg(ssp, SSACD);
+                       ssacd &= ~(SSACD_ACDS(7) | SSACD_SCDB_1X);
+                       ssacd |= SSACD_ACDS(m->acds);
+                       ssacd |= m->scdb;
+                       pxa_ssp_write_reg(ssp, SSACD, ssacd);
+               }
+       } else if (sscr0 & SSCR0_ECS) {
+               /*
+                * For setups with external clocking, the PLL and its diviers
+                * are not active. Instead, the SCR bits in SSCR0 can be used
+                * to divide the clock.
+                */
+               pxa_ssp_set_scr(ssp, bclk / rate);
+       }
+
        switch (priv->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_I2S:
               sspsp = pxa_ssp_read_reg(ssp, SSPSP);
 
-               if ((pxa_ssp_get_scr(ssp) == 4) && (width == 16)) {
+               if (((priv->sysclk / bclk) == 64) && (width == 16)) {
                        /* This is a special case where the bitclk is 64fs
                         * and we're not dealing with 2*32 bits of audio
                         * samples.
@@ -812,8 +814,6 @@ static const struct snd_soc_dai_ops pxa_ssp_dai_ops = {
        .trigger        = pxa_ssp_trigger,
        .hw_params      = pxa_ssp_hw_params,
        .set_sysclk     = pxa_ssp_set_dai_sysclk,
-       .set_clkdiv     = pxa_ssp_set_dai_clkdiv,
-       .set_pll        = pxa_ssp_set_dai_pll,
        .set_fmt        = pxa_ssp_set_dai_fmt,
        .set_tdm_slot   = pxa_ssp_set_dai_tdm_slot,
        .set_tristate   = pxa_ssp_set_dai_tristate,