* [PATCH 3/3] ASoC: pxa-ssp.c handle the I2S and LEFT_J cases.
@ 2009-06-16 0:45 Daniel Ribeiro
2009-06-16 21:36 ` Mark Brown
0 siblings, 1 reply; 5+ messages in thread
From: Daniel Ribeiro @ 2009-06-16 0:45 UTC (permalink / raw)
To: Mark Brown, Eric Miao
Cc: Paul Shen, alsa-devel, linux-arm-kernel, Philipp Zabel
[-- Attachment #1.1: Type: text/plain, Size: 7051 bytes --]
Handles I2S and LEFT_J cases, if the user does _not_ call set_tdm_slot
we assume that the codec is I2S compliant, and that we can use
frame_width = sample_width * channels.
If the user calls set_tdm_slot then we assume that the wire is _not_
networked, and that the user wants to set a non-standard frame format
instead, in this case we set the frame duration (the LRCLK falling edge)
to be half of the wire frame width.
eg.
* standard 2*[16|24|32|..] bits I2S/LEFT_J doesn't need to call
set_tdm_slot
* to use 2*16bits I2S/LEFTJ on 64bits frames, with the LRCLK falling
edge at the 32nd bitclk (+1 for I2S) needs to set_tdm_slot(5, 5, 4, 16)
(4 slots of 16 bits, first and third RX/TX slots active). This should
work even if pxa is slave of SFRM.
Signed-off-by: Daniel Ribeiro <drwyrm@gmail.com>
---
arch/arm/mach-pxa/include/mach/regs-ssp.h | 14 ++--
sound/soc/pxa/pxa-ssp.c | 121 +++++++++++++---------------
2 files changed, 63 insertions(+), 72 deletions(-)
diff --git a/arch/arm/mach-pxa/include/mach/regs-ssp.h b/arch/arm/mach-pxa/include/mach/regs-ssp.h
index 6a2ed35..060e23b 100644
--- a/arch/arm/mach-pxa/include/mach/regs-ssp.h
+++ b/arch/arm/mach-pxa/include/mach/regs-ssp.h
@@ -108,21 +108,21 @@
#define SSSR_TINT (1 << 19) /* Receiver Time-out Interrupt */
#define SSSR_PINT (1 << 18) /* Peripheral Trailing Byte Interrupt */
-#if defined(CONFIG_PXA3xx)
-#define SSPSP_EDMYSTOP(x) ((x) << 28) /* Extended Dummy Stop */
-#define SSPSP_EDMYSTRT(x) ((x) << 26) /* Extended Dummy Start */
-#endif
-
#define SSPSP_FSRT (1 << 25) /* Frame Sync Relative Timing */
-#define SSPSP_DMYSTOP(x) ((x) << 23) /* Dummy Stop */
#define SSPSP_SFRMWDTH(x) ((x) << 16) /* Serial Frame Width */
#define SSPSP_SFRMDLY(x) ((x) << 9) /* Serial Frame Delay */
-#define SSPSP_DMYSTRT(x) ((x) << 7) /* Dummy Start */
#define SSPSP_STRTDLY(x) ((x) << 4) /* Start Delay */
#define SSPSP_ETDS (1 << 3) /* End of Transfer data State */
#define SSPSP_SFRMP (1 << 2) /* Serial Frame Polarity */
#define SSPSP_SCMODE(x) ((x) << 0) /* Serial Bit Rate Clock Mode */
+/* NOTE: PXA3xx extends the bit number of dummy start and stop, the macros
+ * below are compatible with PXA25x/27x as long as the parameter is within
+ * the correct limits, driver code has to take care of this.
+ */
+#define SSPSP_DMYSTRT(x) ((((x) & 3) << 7) | ((((x) >> 2) & 3) << 26))
+#define SSPSP_DMYSTOP(x) ((((x) & 3) << 23) | ((((x) >> 2) & 7) << 28))
+
#define SSACD_SCDB (1 << 3) /* SSPSYSCLK Divider Bypass */
#define SSACD_ACPS(x) ((x) << 4) /* Audio clock PLL select */
#define SSACD_ACDS(x) ((x) << 0) /* Audio clock divider select */
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c
index d60492e..aac85fe 100644
--- a/sound/soc/pxa/pxa-ssp.c
+++ b/sound/soc/pxa/pxa-ssp.c
@@ -179,21 +179,6 @@ static void ssp_set_scr(struct ssp_device *ssp, u32 div)
ssp_write_reg(ssp, SSCR0, sscr0);
}
-/**
- * ssp_get_clkdiv - get SSP clock divider
- */
-static u32 ssp_get_scr(struct ssp_device *ssp)
-{
- u32 sscr0 = ssp_read_reg(ssp, SSCR0);
- u32 div;
-
- if (cpu_is_pxa25x() && ssp->type == PXA25x_SSP)
- div = ((sscr0 >> 8) & 0xff) * 2 + 2;
- else
- div = ((sscr0 >> 8) & 0xfff) + 1;
- return div;
-}
-
/*
* Set the SSP ports SYSCLK.
*/
@@ -487,17 +472,14 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
}
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
- case SND_SOC_DAIFMT_I2S:
- sscr0 |= SSCR0_PSP;
- sscr1 |= SSCR1_RWOT | SSCR1_TRAIL;
- /* See hw_params() */
- break;
-
case SND_SOC_DAIFMT_DSP_A:
sspsp |= SSPSP_FSRT;
case SND_SOC_DAIFMT_DSP_B:
+ case SND_SOC_DAIFMT_LEFT_J:
+ case SND_SOC_DAIFMT_I2S:
sscr0 |= SSCR0_PSP;
sscr1 |= SSCR1_TRAIL | SSCR1_RWOT;
+ /* See hw_params() for I2S and LEFT_J */
break;
default:
@@ -561,6 +543,59 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
sscr0 |= SSCR0_FPCKE;
#endif
+ sspsp = ssp_read_reg(ssp, SSPSP);
+ switch (priv->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ /*
+ * I2S and LEFT_J are stereo only, we have to send data for
+ * both channels.
+ */
+ if (chn == 1)
+ frame_width *= 2;
+
+ /*
+ * If the user did not use network mode, we assume the codec
+ * is I2S compliant.
+ */
+ if (frame_width > 0) {
+ sspsp |= SSPSP_SFRMWDTH(frame_width / 2);
+ sspsp |= SSPSP_FSRT;
+ } else {
+ /*
+ * Otherwise we assume that it is a single TDM slot, and
+ * the user is abusing set_tdm_slot to support an
+ * out of spec codec.
+ */
+ int slots = ((sscr0 & SSCR0_SlotsPerFrm(8)) >> 24) + 1;
+
+ /* PXA2XX doesn't support DMYSTOP > 3 */
+ if (slot_width != (width * 2) && !cpu_is_pxa3xx())
+ return -EINVAL;
+
+ sspsp |= SSPSP_DMYSTRT(1);
+ sspsp |= SSPSP_DMYSTOP(
+ (slot_width * slots) / 2 - width - 1);
+ sspsp |= SSPSP_SFRMWDTH((slot_width * slots) / 2);
+ }
+ break;
+
+ case SND_SOC_DAIFMT_LEFT_J:
+ if (chn == 1)
+ frame_width *= 2;
+
+ if (frame_width > 0) {
+ sspsp |= SSPSP_SFRMWDTH(frame_width / 2);
+ } else {
+ int slots = ((sscr0 & SSCR0_SlotsPerFrm(8)) >> 24) + 1;
+
+ sspsp |= SSPSP_SFRMWDTH((slot_width * slots) / 2);
+ }
+ break;
+ default:
+ break;
+ }
+ ssp_write_reg(ssp, SSPSP, sspsp);
+
if (frame_width > 0) {
/* Not using network mode */
if (frame_width > 16)
@@ -598,50 +633,6 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
ssp_write_reg(ssp, SSCR0, sscr0);
- switch (priv->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
- case SND_SOC_DAIFMT_I2S:
- sspsp = ssp_read_reg(ssp, SSPSP);
-
- if ((ssp_get_scr(ssp) == 4) && (width == 16)) {
- /* This is a special case where the bitclk is 64fs
- * and we're not dealing with 2*32 bits of audio
- * samples.
- *
- * The SSP values used for that are all found out by
- * trying and failing a lot; some of the registers
- * needed for that mode are only available on PXA3xx.
- */
-
-#ifdef CONFIG_PXA3xx
- if (!cpu_is_pxa3xx())
- return -EINVAL;
-
- sspsp |= SSPSP_SFRMWDTH(width * 2);
- sspsp |= SSPSP_SFRMDLY(width * 4);
- sspsp |= SSPSP_EDMYSTOP(3);
- sspsp |= SSPSP_DMYSTOP(3);
- sspsp |= SSPSP_DMYSTRT(1);
-#else
- return -EINVAL;
-#endif
- } else {
- /* The frame width is the width the LRCLK is
- * asserted for; the delay is expressed in
- * half cycle units. We need the extra cycle
- * because the data starts clocking out one BCLK
- * after LRCLK changes polarity.
- */
- sspsp |= SSPSP_SFRMWDTH(width + 1);
- sspsp |= SSPSP_SFRMDLY((width + 1) * 2);
- sspsp |= SSPSP_DMYSTRT(1);
- }
-
- ssp_write_reg(ssp, SSPSP, sspsp);
- break;
- default:
- break;
- }
-
dump_registers(ssp);
return 0;
--
tg: (119677b..) asoc/leftj-and-i2s (depends on: asoc/ssp-internals)
--
Daniel Ribeiro
[-- Attachment #1.2: Esta é uma parte de mensagem assinada digitalmente --]
[-- Type: application/pgp-signature, Size: 197 bytes --]
[-- Attachment #2: Type: text/plain, Size: 160 bytes --]
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
^ permalink raw reply related [flat|nested] 5+ messages in thread* Re: [PATCH 3/3] ASoC: pxa-ssp.c handle the I2S and LEFT_J cases.
2009-06-16 0:45 [PATCH 3/3] ASoC: pxa-ssp.c handle the I2S and LEFT_J cases Daniel Ribeiro
@ 2009-06-16 21:36 ` Mark Brown
2009-06-17 3:03 ` Eric Miao
0 siblings, 1 reply; 5+ messages in thread
From: Mark Brown @ 2009-06-16 21:36 UTC (permalink / raw)
To: Daniel Ribeiro
Cc: Paul Shen, alsa-devel, Eric Miao, Philipp Zabel, linux-arm-kernel
On Mon, Jun 15, 2009 at 09:45:35PM -0300, Daniel Ribeiro wrote:
> arch/arm/mach-pxa/include/mach/regs-ssp.h | 14 ++--
Eric, are you happy for this change to go via ALSA? It seems reasonable
enough.
I'm happy with these changes from a code review point of view, though
as well as Eric's ack I'll do some more testing before I apply them.
Thanks a lot for doing this work.
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 3/3] ASoC: pxa-ssp.c handle the I2S and LEFT_J cases.
2009-06-16 21:36 ` Mark Brown
@ 2009-06-17 3:03 ` Eric Miao
2009-06-17 9:35 ` Mark Brown
0 siblings, 1 reply; 5+ messages in thread
From: Eric Miao @ 2009-06-17 3:03 UTC (permalink / raw)
To: Mark Brown
Cc: Paul Shen, alsa-devel, Philipp Zabel, linux-arm-kernel,
Daniel Ribeiro
Mark Brown wrote:
> On Mon, Jun 15, 2009 at 09:45:35PM -0300, Daniel Ribeiro wrote:
>
>> arch/arm/mach-pxa/include/mach/regs-ssp.h | 14 ++--
>
> Eric, are you happy for this change to go via ALSA? It seems reasonable
> enough.
>
> I'm happy with these changes from a code review point of view, though
> as well as Eric's ack I'll do some more testing before I apply them.
> Thanks a lot for doing this work.
OK, I'll take some time to verify that on PXA3xx.
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 3/3] ASoC: pxa-ssp.c handle the I2S and LEFT_J cases.
2009-06-17 3:03 ` Eric Miao
@ 2009-06-17 9:35 ` Mark Brown
0 siblings, 0 replies; 5+ messages in thread
From: Mark Brown @ 2009-06-17 9:35 UTC (permalink / raw)
To: Eric Miao
Cc: Paul Shen, alsa-devel, Philipp Zabel, linux-arm-kernel,
Daniel Ribeiro
On Wed, Jun 17, 2009 at 11:03:28AM +0800, Eric Miao wrote:
> Mark Brown wrote:
> > I'm happy with these changes from a code review point of view, though
> > as well as Eric's ack I'll do some more testing before I apply them.
> > Thanks a lot for doing this work.
> OK, I'll take some time to verify that on PXA3xx.
If you could cover PXA32x that'd be really helpful - I have PXA300 here.
They should be identical but more coverage is always better.
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/3] ASoC: change set_tdm_slot api to allow slot_width override.
@ 2009-08-06 14:55 Mark Brown
2009-08-06 14:55 ` [PATCH 3/3] ASoC: pxa-ssp.c handle the I2S and LEFT_J cases Mark Brown
0 siblings, 1 reply; 5+ messages in thread
From: Mark Brown @ 2009-08-06 14:55 UTC (permalink / raw)
To: Eric Miao, Philipp Zabel, Paul Shen, Daniel Mack
Cc: alsa-devel, Mark Brown, Daniel Ribeiro
From: Daniel Ribeiro <drwyrm@gmail.com>
Extend set_tdm_slot to allow the user to arbitrarily set the frame width
and active TX/RX slots.
Updates magician.c and wm9081.c for the new set_tdm_slot(). wm9081.c
still doesn't handle the slot_width override.
While being there, correct an incorrect use of SlotsPerFrm(7) use in
bitmask on pxa-ssp.c (SSCR0_SlotsPerFrm(x) is (((x) - 1) << 24)) ).
(this series is meant for Mark's for-2.6.32 branch)
Signed-off-by: Daniel Ribeiro <drwyrm@gmail.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
include/sound/soc-dai.h | 5 +++--
sound/soc/codecs/wm9081.c | 5 +++--
sound/soc/pxa/magician.c | 2 +-
sound/soc/pxa/pxa-ssp.c | 27 ++++++++++++++++++++-------
sound/soc/soc-core.c | 9 ++++++---
5 files changed, 33 insertions(+), 15 deletions(-)
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index 25d62ac..2d3fa29 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -106,7 +106,7 @@ int snd_soc_dai_set_pll(struct snd_soc_dai *dai,
int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt);
int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
- unsigned int mask, int slots);
+ unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width);
int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate);
@@ -140,7 +140,8 @@ struct snd_soc_dai_ops {
*/
int (*set_fmt)(struct snd_soc_dai *dai, unsigned int fmt);
int (*set_tdm_slot)(struct snd_soc_dai *dai,
- unsigned int mask, int slots);
+ unsigned int tx_mask, unsigned int rx_mask,
+ int slots, int slot_width);
int (*set_tristate)(struct snd_soc_dai *dai, int tristate);
/*
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c
index 156f2a4..c965323 100644
--- a/sound/soc/codecs/wm9081.c
+++ b/sound/soc/codecs/wm9081.c
@@ -1214,8 +1214,9 @@ static int wm9081_set_sysclk(struct snd_soc_dai *codec_dai,
return 0;
}
+/* FIXME: Needs to handle slot_width */
static int wm9081_set_tdm_slot(struct snd_soc_dai *dai,
- unsigned int mask, int slots)
+ unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
{
struct snd_soc_codec *codec = dai->codec;
unsigned int aif1 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_1);
@@ -1227,7 +1228,7 @@ static int wm9081_set_tdm_slot(struct snd_soc_dai *dai,
aif1 |= (slots - 1) << WM9081_AIFDAC_TDM_MODE_SHIFT;
- switch (mask) {
+ switch (rx_mask) {
case 1:
break;
case 2:
diff --git a/sound/soc/pxa/magician.c b/sound/soc/pxa/magician.c
index 8889cd3..9f7c61e 100644
--- a/sound/soc/pxa/magician.c
+++ b/sound/soc/pxa/magician.c
@@ -190,7 +190,7 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream,
if (ret < 0)
return ret;
- ret = snd_soc_dai_set_tdm_slot(cpu_dai, 1, 1);
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, 1, 0, 1, width);
if (ret < 0)
return ret;
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c
index e22c5ce..5b9ed64 100644
--- a/sound/soc/pxa/pxa-ssp.c
+++ b/sound/soc/pxa/pxa-ssp.c
@@ -375,21 +375,34 @@ static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai,
* Set the active slots in TDM/Network mode
*/
static int pxa_ssp_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
- unsigned int mask, int slots)
+ unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
{
struct ssp_priv *priv = cpu_dai->private_data;
struct ssp_device *ssp = priv->dev.ssp;
u32 sscr0;
- sscr0 = ssp_read_reg(ssp, SSCR0) & ~SSCR0_SlotsPerFrm(7);
+ sscr0 = ssp_read_reg(ssp, SSCR0);
+ sscr0 &= ~(SSCR0_MOD | SSCR0_SlotsPerFrm(8) | SSCR0_EDSS | SSCR0_DSS);
+
+ /* set slot width */
+ if (slot_width > 16)
+ sscr0 |= SSCR0_EDSS | SSCR0_DataSize(slot_width - 16);
+ else
+ sscr0 |= SSCR0_DataSize(slot_width);
- /* set number of active slots */
- sscr0 |= SSCR0_SlotsPerFrm(slots);
+ if (slots > 1) {
+ /* enable network mode */
+ sscr0 |= SSCR0_MOD;
+
+ /* set number of active slots */
+ sscr0 |= SSCR0_SlotsPerFrm(slots);
+
+ /* set active slot mask */
+ ssp_write_reg(ssp, SSTSA, tx_mask);
+ ssp_write_reg(ssp, SSRSA, rx_mask);
+ }
ssp_write_reg(ssp, SSCR0, sscr0);
- /* set active slot mask */
- ssp_write_reg(ssp, SSTSA, mask);
- ssp_write_reg(ssp, SSRSA, mask);
return 0;
}
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index fb8d7a7..e984a17 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -2223,17 +2223,20 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt);
/**
* snd_soc_dai_set_tdm_slot - configure DAI TDM.
* @dai: DAI
- * @mask: DAI specific mask representing used slots.
+ * @tx_mask: bitmask representing active TX slots.
+ * @rx_mask: bitmask representing active RX slots.
* @slots: Number of slots in use.
+ * @slot_width: Width in bits for each slot.
*
* Configures a DAI for TDM operation. Both mask and slots are codec and DAI
* specific.
*/
int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
- unsigned int mask, int slots)
+ unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
{
if (dai->ops && dai->ops->set_tdm_slot)
- return dai->ops->set_tdm_slot(dai, mask, slots);
+ return dai->ops->set_tdm_slot(dai, tx_mask, rx_mask,
+ slots, slot_width);
else
return -EINVAL;
}
--
1.6.3.3
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH 3/3] ASoC: pxa-ssp.c handle the I2S and LEFT_J cases.
2009-08-06 14:55 [PATCH 1/3] ASoC: change set_tdm_slot api to allow slot_width override Mark Brown
@ 2009-08-06 14:55 ` Mark Brown
0 siblings, 0 replies; 5+ messages in thread
From: Mark Brown @ 2009-08-06 14:55 UTC (permalink / raw)
To: Eric Miao, Philipp Zabel, Paul Shen, Daniel Mack
Cc: alsa-devel, Mark Brown, Daniel Ribeiro
From: Daniel Ribeiro <drwyrm@gmail.com>
Handles I2S and LEFT_J cases, if the user does _not_ call set_tdm_slot
we assume that the codec is I2S compliant, and that we can use
frame_width = sample_width * channels.
If the user calls set_tdm_slot then we assume that the wire is _not_
networked, and that the user wants to set a non-standard frame format
instead, in this case we set the frame duration (the LRCLK falling edge)
to be half of the wire frame width.
eg.
* standard 2*[16|24|32|..] bits I2S/LEFT_J doesn't need to call
set_tdm_slot
* to use 2*16bits I2S/LEFTJ on 64bits frames, with the LRCLK falling
edge at the 32nd bitclk (+1 for I2S) needs to set_tdm_slot(5, 5, 4, 16)
(4 slots of 16 bits, first and third RX/TX slots active). This should
work even if pxa is slave of SFRM.
Signed-off-by: Daniel Ribeiro <drwyrm@gmail.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
arch/arm/mach-pxa/include/mach/regs-ssp.h | 14 ++--
sound/soc/pxa/pxa-ssp.c | 121 +++++++++++++---------------
2 files changed, 63 insertions(+), 72 deletions(-)
diff --git a/arch/arm/mach-pxa/include/mach/regs-ssp.h b/arch/arm/mach-pxa/include/mach/regs-ssp.h
index 6a2ed35..060e23b 100644
--- a/arch/arm/mach-pxa/include/mach/regs-ssp.h
+++ b/arch/arm/mach-pxa/include/mach/regs-ssp.h
@@ -108,21 +108,21 @@
#define SSSR_TINT (1 << 19) /* Receiver Time-out Interrupt */
#define SSSR_PINT (1 << 18) /* Peripheral Trailing Byte Interrupt */
-#if defined(CONFIG_PXA3xx)
-#define SSPSP_EDMYSTOP(x) ((x) << 28) /* Extended Dummy Stop */
-#define SSPSP_EDMYSTRT(x) ((x) << 26) /* Extended Dummy Start */
-#endif
-
#define SSPSP_FSRT (1 << 25) /* Frame Sync Relative Timing */
-#define SSPSP_DMYSTOP(x) ((x) << 23) /* Dummy Stop */
#define SSPSP_SFRMWDTH(x) ((x) << 16) /* Serial Frame Width */
#define SSPSP_SFRMDLY(x) ((x) << 9) /* Serial Frame Delay */
-#define SSPSP_DMYSTRT(x) ((x) << 7) /* Dummy Start */
#define SSPSP_STRTDLY(x) ((x) << 4) /* Start Delay */
#define SSPSP_ETDS (1 << 3) /* End of Transfer data State */
#define SSPSP_SFRMP (1 << 2) /* Serial Frame Polarity */
#define SSPSP_SCMODE(x) ((x) << 0) /* Serial Bit Rate Clock Mode */
+/* NOTE: PXA3xx extends the bit number of dummy start and stop, the macros
+ * below are compatible with PXA25x/27x as long as the parameter is within
+ * the correct limits, driver code has to take care of this.
+ */
+#define SSPSP_DMYSTRT(x) ((((x) & 3) << 7) | ((((x) >> 2) & 3) << 26))
+#define SSPSP_DMYSTOP(x) ((((x) & 3) << 23) | ((((x) >> 2) & 7) << 28))
+
#define SSACD_SCDB (1 << 3) /* SSPSYSCLK Divider Bypass */
#define SSACD_ACPS(x) ((x) << 4) /* Audio clock PLL select */
#define SSACD_ACDS(x) ((x) << 0) /* Audio clock divider select */
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c
index d60492e..aac85fe 100644
--- a/sound/soc/pxa/pxa-ssp.c
+++ b/sound/soc/pxa/pxa-ssp.c
@@ -179,21 +179,6 @@ static void ssp_set_scr(struct ssp_device *ssp, u32 div)
ssp_write_reg(ssp, SSCR0, sscr0);
}
-/**
- * ssp_get_clkdiv - get SSP clock divider
- */
-static u32 ssp_get_scr(struct ssp_device *ssp)
-{
- u32 sscr0 = ssp_read_reg(ssp, SSCR0);
- u32 div;
-
- if (cpu_is_pxa25x() && ssp->type == PXA25x_SSP)
- div = ((sscr0 >> 8) & 0xff) * 2 + 2;
- else
- div = ((sscr0 >> 8) & 0xfff) + 1;
- return div;
-}
-
/*
* Set the SSP ports SYSCLK.
*/
@@ -487,17 +472,14 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
}
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
- case SND_SOC_DAIFMT_I2S:
- sscr0 |= SSCR0_PSP;
- sscr1 |= SSCR1_RWOT | SSCR1_TRAIL;
- /* See hw_params() */
- break;
-
case SND_SOC_DAIFMT_DSP_A:
sspsp |= SSPSP_FSRT;
case SND_SOC_DAIFMT_DSP_B:
+ case SND_SOC_DAIFMT_LEFT_J:
+ case SND_SOC_DAIFMT_I2S:
sscr0 |= SSCR0_PSP;
sscr1 |= SSCR1_TRAIL | SSCR1_RWOT;
+ /* See hw_params() for I2S and LEFT_J */
break;
default:
@@ -561,6 +543,59 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
sscr0 |= SSCR0_FPCKE;
#endif
+ sspsp = ssp_read_reg(ssp, SSPSP);
+ switch (priv->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ /*
+ * I2S and LEFT_J are stereo only, we have to send data for
+ * both channels.
+ */
+ if (chn == 1)
+ frame_width *= 2;
+
+ /*
+ * If the user did not use network mode, we assume the codec
+ * is I2S compliant.
+ */
+ if (frame_width > 0) {
+ sspsp |= SSPSP_SFRMWDTH(frame_width / 2);
+ sspsp |= SSPSP_FSRT;
+ } else {
+ /*
+ * Otherwise we assume that it is a single TDM slot, and
+ * the user is abusing set_tdm_slot to support an
+ * out of spec codec.
+ */
+ int slots = ((sscr0 & SSCR0_SlotsPerFrm(8)) >> 24) + 1;
+
+ /* PXA2XX doesn't support DMYSTOP > 3 */
+ if (slot_width != (width * 2) && !cpu_is_pxa3xx())
+ return -EINVAL;
+
+ sspsp |= SSPSP_DMYSTRT(1);
+ sspsp |= SSPSP_DMYSTOP(
+ (slot_width * slots) / 2 - width - 1);
+ sspsp |= SSPSP_SFRMWDTH((slot_width * slots) / 2);
+ }
+ break;
+
+ case SND_SOC_DAIFMT_LEFT_J:
+ if (chn == 1)
+ frame_width *= 2;
+
+ if (frame_width > 0) {
+ sspsp |= SSPSP_SFRMWDTH(frame_width / 2);
+ } else {
+ int slots = ((sscr0 & SSCR0_SlotsPerFrm(8)) >> 24) + 1;
+
+ sspsp |= SSPSP_SFRMWDTH((slot_width * slots) / 2);
+ }
+ break;
+ default:
+ break;
+ }
+ ssp_write_reg(ssp, SSPSP, sspsp);
+
if (frame_width > 0) {
/* Not using network mode */
if (frame_width > 16)
@@ -598,50 +633,6 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
ssp_write_reg(ssp, SSCR0, sscr0);
- switch (priv->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
- case SND_SOC_DAIFMT_I2S:
- sspsp = ssp_read_reg(ssp, SSPSP);
-
- if ((ssp_get_scr(ssp) == 4) && (width == 16)) {
- /* This is a special case where the bitclk is 64fs
- * and we're not dealing with 2*32 bits of audio
- * samples.
- *
- * The SSP values used for that are all found out by
- * trying and failing a lot; some of the registers
- * needed for that mode are only available on PXA3xx.
- */
-
-#ifdef CONFIG_PXA3xx
- if (!cpu_is_pxa3xx())
- return -EINVAL;
-
- sspsp |= SSPSP_SFRMWDTH(width * 2);
- sspsp |= SSPSP_SFRMDLY(width * 4);
- sspsp |= SSPSP_EDMYSTOP(3);
- sspsp |= SSPSP_DMYSTOP(3);
- sspsp |= SSPSP_DMYSTRT(1);
-#else
- return -EINVAL;
-#endif
- } else {
- /* The frame width is the width the LRCLK is
- * asserted for; the delay is expressed in
- * half cycle units. We need the extra cycle
- * because the data starts clocking out one BCLK
- * after LRCLK changes polarity.
- */
- sspsp |= SSPSP_SFRMWDTH(width + 1);
- sspsp |= SSPSP_SFRMDLY((width + 1) * 2);
- sspsp |= SSPSP_DMYSTRT(1);
- }
-
- ssp_write_reg(ssp, SSPSP, sspsp);
- break;
- default:
- break;
- }
-
dump_registers(ssp);
return 0;
--
1.6.3.3
^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2009-08-06 14:55 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-06-16 0:45 [PATCH 3/3] ASoC: pxa-ssp.c handle the I2S and LEFT_J cases Daniel Ribeiro
2009-06-16 21:36 ` Mark Brown
2009-06-17 3:03 ` Eric Miao
2009-06-17 9:35 ` Mark Brown
-- strict thread matches above, loose matches on Subject: below --
2009-08-06 14:55 [PATCH 1/3] ASoC: change set_tdm_slot api to allow slot_width override Mark Brown
2009-08-06 14:55 ` [PATCH 3/3] ASoC: pxa-ssp.c handle the I2S and LEFT_J cases Mark Brown
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.