Commit 05739375 authored by Daniel Mack's avatar Daniel Mack Committed by Mark Brown

ASoC: pxa-ssp: remove .set_pll() and .set_clkdiv() callbacks

The .set_pll() and .set_clkdiv() callbacks are considered legacy and should
not be used anymore. In order to support PXA boards on DT platforms, remove
them and let the code figure out the correct dividers and PLL base
frequencies itself.
Signed-off-by: default avatarDaniel Mack <daniel@zonque.org>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 15812501
...@@ -171,6 +171,14 @@ ...@@ -171,6 +171,14 @@
#define SSACD_SCDB (1 << 3) /* SSPSYSCLK Divider Bypass */ #define SSACD_SCDB (1 << 3) /* SSPSYSCLK Divider Bypass */
#define SSACD_ACPS(x) ((x) << 4) /* Audio clock PLL select */ #define SSACD_ACPS(x) ((x) << 4) /* Audio clock PLL select */
#define SSACD_ACDS(x) ((x) << 0) /* Audio clock divider select */ #define SSACD_ACDS(x) ((x) << 0) /* Audio clock divider select */
#define SSACD_ACDS_1 (0)
#define SSACD_ACDS_2 (1)
#define SSACD_ACDS_4 (2)
#define SSACD_ACDS_8 (3)
#define SSACD_ACDS_16 (4)
#define SSACD_ACDS_32 (5)
#define SSACD_SCDB_4X (0)
#define SSACD_SCDB_1X (1)
#define SSACD_SCDX8 (1 << 7) /* SYSCLK division ratio select */ #define SSACD_SCDX8 (1 << 7) /* SYSCLK division ratio select */
/* LPSS SSP */ /* LPSS SSP */
......
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
*/ */
struct ssp_priv { struct ssp_priv {
struct ssp_device *ssp; struct ssp_device *ssp;
unsigned long ssp_clk;
unsigned int sysclk; unsigned int sysclk;
unsigned int dai_fmt; unsigned int dai_fmt;
unsigned int configured_dai_fmt; unsigned int configured_dai_fmt;
...@@ -192,21 +193,6 @@ static void pxa_ssp_set_scr(struct ssp_device *ssp, u32 div) ...@@ -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_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. * Set the SSP ports SYSCLK.
*/ */
...@@ -262,67 +248,18 @@ static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai, ...@@ -262,67 +248,18 @@ static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
return 0; 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) * 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, static int pxa_ssp_set_pll(struct ssp_priv *priv, unsigned int freq)
int source, unsigned int freq_in, unsigned int freq_out)
{ {
struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
struct ssp_device *ssp = priv->ssp; struct ssp_device *ssp = priv->ssp;
u32 ssacd = pxa_ssp_read_reg(ssp, SSACD) & ~0x70; u32 ssacd = pxa_ssp_read_reg(ssp, SSACD) & ~0x70;
if (ssp->type == PXA3xx_SSP) if (ssp->type == PXA3xx_SSP)
pxa_ssp_write_reg(ssp, SSACDD, 0); pxa_ssp_write_reg(ssp, SSACDD, 0);
switch (freq_out) { switch (freq) {
case 5622000: case 5622000:
break; break;
case 11345000: case 11345000:
...@@ -353,7 +290,7 @@ static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, int pll_id, ...@@ -353,7 +290,7 @@ static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, int pll_id,
u64 tmp = 19968; u64 tmp = 19968;
tmp *= 1000000; tmp *= 1000000;
do_div(tmp, freq_out); do_div(tmp, freq);
val = tmp; val = tmp;
val = (val << 16) | 64; val = (val << 16) | 64;
...@@ -363,7 +300,7 @@ static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, int pll_id, ...@@ -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, dev_dbg(&ssp->pdev->dev,
"Using SSACDD %x to supply %uHz\n", "Using SSACDD %x to supply %uHz\n",
val, freq_out); val, freq);
break; break;
} }
...@@ -568,6 +505,24 @@ static int pxa_ssp_configure_dai_fmt(struct ssp_priv *priv) ...@@ -568,6 +505,24 @@ static int pxa_ssp_configure_dai_fmt(struct ssp_priv *priv)
return 0; 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. * Set the SSP audio DMA parameters and sample size.
* Can be called multiple times by oss emulation. * Can be called multiple times by oss emulation.
...@@ -579,11 +534,12 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream, ...@@ -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_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
struct ssp_device *ssp = priv->ssp; struct ssp_device *ssp = priv->ssp;
int chn = params_channels(params); int chn = params_channels(params);
u32 sscr0; u32 sscr0, sspsp;
u32 sspsp;
int width = snd_pcm_format_physical_width(params_format(params)); int width = snd_pcm_format_physical_width(params_format(params));
int ttsa = pxa_ssp_read_reg(ssp, SSTSA) & 0xf; int ttsa = pxa_ssp_read_reg(ssp, SSTSA) & 0xf;
struct snd_dmaengine_dai_dma_data *dma_data; struct snd_dmaengine_dai_dma_data *dma_data;
int rate = params_rate(params);
int bclk = rate * chn * (width / 8);
int ret; int ret;
dma_data = snd_soc_dai_get_dma_data(cpu_dai, substream); 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, ...@@ -623,11 +579,57 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
} }
pxa_ssp_write_reg(ssp, SSCR0, sscr0); 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) { switch (priv->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S: case SND_SOC_DAIFMT_I2S:
sspsp = pxa_ssp_read_reg(ssp, SSPSP); 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 /* This is a special case where the bitclk is 64fs
* and we're not dealing with 2*32 bits of audio * and we're not dealing with 2*32 bits of audio
* samples. * samples.
...@@ -812,8 +814,6 @@ static const struct snd_soc_dai_ops pxa_ssp_dai_ops = { ...@@ -812,8 +814,6 @@ static const struct snd_soc_dai_ops pxa_ssp_dai_ops = {
.trigger = pxa_ssp_trigger, .trigger = pxa_ssp_trigger,
.hw_params = pxa_ssp_hw_params, .hw_params = pxa_ssp_hw_params,
.set_sysclk = pxa_ssp_set_dai_sysclk, .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_fmt = pxa_ssp_set_dai_fmt,
.set_tdm_slot = pxa_ssp_set_dai_tdm_slot, .set_tdm_slot = pxa_ssp_set_dai_tdm_slot,
.set_tristate = pxa_ssp_set_dai_tristate, .set_tristate = pxa_ssp_set_dai_tristate,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment