[PATCH] ARM: at91/dt: Fix sama5d3x typos.

2014-10-23 Thread Peter Rosin
From c23d712fe924b929c2eb39eba644fe74bcccfd37 Mon Sep 17 00:00:00 2001
From: Peter Rosin p...@axentia.se
Date: Thu, 23 Oct 2014 13:52:03 +0200
Subject: [PATCH] ARM: at91/dt: Fix sama5d3x typos.

The DT compatible strings also need binding documentation, but that is for
someone else to write.

Signed-off-by: Peter Rosin p...@axentia.se
---
 arch/arm/boot/dts/sama5d31.dtsi   |2 +-
 arch/arm/boot/dts/sama5d33.dtsi   |2 +-
 arch/arm/boot/dts/sama5d34.dtsi   |2 +-
 arch/arm/boot/dts/sama5d35.dtsi   |2 +-
 arch/arm/boot/dts/sama5d36.dtsi   |2 +-
 arch/arm/boot/dts/sama5d3xcm.dtsi |2 +-
 6 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/arch/arm/boot/dts/sama5d31.dtsi b/arch/arm/boot/dts/sama5d31.dtsi
index 7997dc9..883878b 100644
--- a/arch/arm/boot/dts/sama5d31.dtsi
+++ b/arch/arm/boot/dts/sama5d31.dtsi
@@ -12,5 +12,5 @@
 #include sama5d3_uart.dtsi
 
 / {
-   compatible = atmel,samad31, atmel,sama5d3, atmel,sama5;
+   compatible = atmel,sama5d31, atmel,sama5d3, atmel,sama5;
 };
diff --git a/arch/arm/boot/dts/sama5d33.dtsi b/arch/arm/boot/dts/sama5d33.dtsi
index 39f8322..4b4434a 100644
--- a/arch/arm/boot/dts/sama5d33.dtsi
+++ b/arch/arm/boot/dts/sama5d33.dtsi
@@ -10,5 +10,5 @@
 #include sama5d3_gmac.dtsi
 
 / {
-   compatible = atmel,samad33, atmel,sama5d3, atmel,sama5;
+   compatible = atmel,sama5d33, atmel,sama5d3, atmel,sama5;
 };
diff --git a/arch/arm/boot/dts/sama5d34.dtsi b/arch/arm/boot/dts/sama5d34.dtsi
index 89cda2c..aa01573 100644
--- a/arch/arm/boot/dts/sama5d34.dtsi
+++ b/arch/arm/boot/dts/sama5d34.dtsi
@@ -12,5 +12,5 @@
 #include sama5d3_mci2.dtsi
 
 / {
-   compatible = atmel,samad34, atmel,sama5d3, atmel,sama5;
+   compatible = atmel,sama5d34, atmel,sama5d3, atmel,sama5;
 };
diff --git a/arch/arm/boot/dts/sama5d35.dtsi b/arch/arm/boot/dts/sama5d35.dtsi
index d20cd71..16c39f4 100644
--- a/arch/arm/boot/dts/sama5d35.dtsi
+++ b/arch/arm/boot/dts/sama5d35.dtsi
@@ -14,5 +14,5 @@
 #include sama5d3_tcb1.dtsi
 
 / {
-   compatible = atmel,samad35, atmel,sama5d3, atmel,sama5;
+   compatible = atmel,sama5d35, atmel,sama5d3, atmel,sama5;
 };
diff --git a/arch/arm/boot/dts/sama5d36.dtsi b/arch/arm/boot/dts/sama5d36.dtsi
index db58cad..e85139e 100644
--- a/arch/arm/boot/dts/sama5d36.dtsi
+++ b/arch/arm/boot/dts/sama5d36.dtsi
@@ -16,5 +16,5 @@
 #include sama5d3_uart.dtsi
 
 / {
-   compatible = atmel,samad36, atmel,sama5d3, atmel,sama5;
+   compatible = atmel,sama5d36, atmel,sama5d3, atmel,sama5;
 };
diff --git a/arch/arm/boot/dts/sama5d3xcm.dtsi 
b/arch/arm/boot/dts/sama5d3xcm.dtsi
index f7d8583..56574c8 100644
--- a/arch/arm/boot/dts/sama5d3xcm.dtsi
+++ b/arch/arm/boot/dts/sama5d3xcm.dtsi
@@ -8,7 +8,7 @@
  */
 
 / {
-   compatible = atmel,samad3xcm, atmel,sama5d3, atmel,sama5;
+   compatible = atmel,sama5d3xcm, atmel,sama5d3, atmel,sama5;
 
chosen {
bootargs = console=ttyS0,115200 rootfstype=ubifs ubi.mtd=5 
root=ubi0:rootfs;
-- 
1.7.10.4

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


RE: [PATCH v2] ASoC: atmel_ssc_dai: Match the CMR divider only in full duplex.

2014-10-24 Thread Peter Rosin
 Hi Peter,
Thanks for your patch.

And thanks for the Ack!

Btw, do you use git send-email command to send the patch?

No, I  didn't, git format-patch and paste into the mail body. Was there some
whitespace issues with the patch?

Cheers,
Peter

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v2] ASoC: atmel_ssc_dai: Match the CMR divider only in full duplex.

2014-10-24 Thread Peter Rosin
Ok, I'm trying with git send-email, sorry for the inconvenience.

Cheers,
Peter

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH] ASoC: atmel_ssc_dai: Match the CMR divider only in full duplex.

2014-10-24 Thread Peter Rosin
The CMR divider register is shared by playback and capture. The SSC driver
therefore tries to enforce rules so that the needed register content do
not conflict during simultaneous playback/capture. However, the
implementation also prevents changing the register content in
half-duplex scenarios, which is needed when using the OSS API.

Thus, only lock the divider if there is a stream in the other direction.

Fixes the below program to not fail with the atmel ssc dai in master mode.

#include sys/ioctl.h
#include unistd.h
#include fcntl.h
#include sys/soundcard.h

int
main(void)
{
int fd;
int format;
int channels;
int speed;

if ((fd = open(/dev/dsp, O_WRONLY, 0)) == -1) {
perror(open);
return 1;
}
format = AFMT_S16_LE;
if (ioctl(fd, SNDCTL_DSP_SETFMT, format) == -1) {
perror(SNDCTL_DSP_SETFMT);
return 1;
}
channels = 2;
if (ioctl(fd, SNDCTL_DSP_CHANNELS, channels) == -1) {
perror(SNDCTL_DSP_CHANNELS);
return 1;
}
speed = 22025;
if (ioctl(fd, SNDCTL_DSP_SPEED, speed) == -1) {
perror(SNDCTL_DSP_SPEED);
return 1;
}
return 0;
}

Signed-off-by: Peter Rosin p...@axentia.se
---
 sound/soc/atmel/atmel_ssc_dai.c | 5 -
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
index f403f39..b1cc2a4 100644
--- a/sound/soc/atmel/atmel_ssc_dai.c
+++ b/sound/soc/atmel/atmel_ssc_dai.c
@@ -310,7 +310,10 @@ static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai 
*cpu_dai,
 * transmit and receive, so if a value has already
 * been set, it must match this value.
 */
-   if (ssc_p-cmr_div == 0)
+   if (ssc_p-dir_mask !=
+   (SSC_DIR_MASK_PLAYBACK | SSC_DIR_MASK_CAPTURE))
+   ssc_p-cmr_div = div;
+   else if (ssc_p-cmr_div == 0)
ssc_p-cmr_div = div;
else
if (div != ssc_p-cmr_div)
-- 
2.1.1

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH] ASoC: atmel_ssc_dai: Track playback and capture CMR dividers separately.

2014-10-20 Thread Peter Rosin
From 1e5621d7b9887c648d1a66238dc82d715c1e2cad Mon Sep 17 00:00:00 2001
From: Peter Rosin p...@axentia.se
Date: Mon, 20 Oct 2014 14:38:04 +0200
Subject: [PATCH] ASoC: atmel_ssc_dai: Track playback and capture CMR dividers
 separately.

The CMR divider register is shared by playback and capture. The SSC driver
therefore tries to enforce rules so that the needed register content do
not conflict during simultaneous playback/capture. However, the
implementation also prevents changing the register content in a
half-duplex scenario, which is needed when changing sample rates.

Thus, keep track of the desired playback and capture clock dividers
separately, and allow changing rates without closing the stream.

Signed-off-by: Peter Rosin p...@axentia.se
---
 sound/soc/atmel/atmel_ssc_dai.c |   31 ++-
 sound/soc/atmel/atmel_ssc_dai.h |   10 ++
 2 files changed, 28 insertions(+), 13 deletions(-)

diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
index f403f39..fec14fb 100644
--- a/sound/soc/atmel/atmel_ssc_dai.c
+++ b/sound/soc/atmel/atmel_ssc_dai.c
@@ -277,7 +277,8 @@ static void atmel_ssc_shutdown(struct snd_pcm_substream 
*substream,
/* Reset the SSC */
ssc_writel(ssc_p-ssc-regs, CR, SSC_BIT(CR_SWRST));
/* Clear the SSC dividers */
-   ssc_p-cmr_div = ssc_p-tcmr_period = ssc_p-rcmr_period = 0;
+   ssc_p-tcmr_div = ssc_p-rcmr_div = 0;
+   ssc_p-tcmr_period = ssc_p-rcmr_period = 0;
}
spin_unlock_irq(ssc_p-lock);
 }
@@ -304,17 +305,27 @@ static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai 
*cpu_dai,
struct atmel_ssc_info *ssc_p = ssc_info[cpu_dai-id];
 
switch (div_id) {
-   case ATMEL_SSC_CMR_DIV:
+   case ATMEL_SSC_TCMR_DIV:
/*
 * The same master clock divider is used for both
 * transmit and receive, so if a value has already
-* been set, it must match this value.
+* been set for the other direction, it must match
+* this value.
 */
-   if (ssc_p-cmr_div == 0)
-   ssc_p-cmr_div = div;
-   else
-   if (div != ssc_p-cmr_div)
-   return -EBUSY;
+   if (ssc_p-rcmr_div == 0)
+   ssc_p-tcmr_div = div;
+   else if (div != ssc_p-rcmr_div)
+   return -EBUSY;
+   break;
+
+   case ATMEL_SSC_RCMR_DIV:
+   /*
+* See ATMEL_SSC_TCMR_DIV.
+*/
+   if (ssc_p-tcmr_div == 0)
+   ssc_p-rcmr_div = div;
+   else if (div != ssc_p-tcmr_div)
+   return -EBUSY;
break;
 
case ATMEL_SSC_TCMR_PERIOD:
@@ -345,6 +356,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream 
*substream,
struct atmel_pcm_dma_params *dma_params;
int dir, channels, bits;
u32 tfmr, rfmr, tcmr, rcmr;
+   u16 cmr;
int start_event;
int ret;
int fslen, fslen_ext;
@@ -626,7 +638,8 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream 
*substream,
}
 
/* set SSC clock mode register */
-   ssc_writel(ssc_p-ssc-regs, CMR, ssc_p-cmr_div);
+   cmr = ssc_p-tcmr_div ? ssc_p-tcmr_div : ssc_p-rcmr_div;
+   ssc_writel(ssc_p-ssc-regs, CMR, cmr);
 
/* set receive clock mode and format */
ssc_writel(ssc_p-ssc-regs, RCMR, rcmr);
diff --git a/sound/soc/atmel/atmel_ssc_dai.h b/sound/soc/atmel/atmel_ssc_dai.h
index b1f08d5..a25df7a 100644
--- a/sound/soc/atmel/atmel_ssc_dai.h
+++ b/sound/soc/atmel/atmel_ssc_dai.h
@@ -39,9 +39,10 @@
 #define ATMEL_SYSCLK_MCK   0 /* SSC uses AT91 MCK as system clock */
 
 /* SSC divider ids */
-#define ATMEL_SSC_CMR_DIV  0 /* MCK divider for BCLK */
-#define ATMEL_SSC_TCMR_PERIOD  1 /* BCLK divider for transmit FS */
-#define ATMEL_SSC_RCMR_PERIOD  2 /* BCLK divider for receive FS */
+#define ATMEL_SSC_TCMR_DIV 0 /* MCK divider for transmit BCLK */
+#define ATMEL_SSC_RCMR_DIV 1 /* MCK divider for receive BCLK */
+#define ATMEL_SSC_TCMR_PERIOD  2 /* BCLK divider for transmit FS */
+#define ATMEL_SSC_RCMR_PERIOD  3 /* BCLK divider for receive FS */
 /*
  * SSC direction masks
  */
@@ -110,7 +111,8 @@ struct atmel_ssc_info {
unsigned short dir_mask;/* 0=unused, 1=playback, 2=capture */
unsigned short initialized; /* true if SSC has been initialized */
unsigned short daifmt;
-   unsigned short cmr_div;
+   unsigned short tcmr_div;
+   unsigned short rcmr_div;
unsigned short tcmr_period;
unsigned short rcmr_period;
struct atmel_pcm_dma_params *dma_params[2];
-- 
1.7.10.4

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message

RE: [alsa-devel] [PATCH] ASoC: atmel_ssc_dai: Track playback and capture CMR dividers separately.

2014-10-21 Thread Peter Rosin
Hi!

(and thank you for the pointer to the example with the ssc-dai in master mode)

 Hi Peter,
 
 On 10/20/2014 09:45 PM, Peter Rosin wrote:
   From 1e5621d7b9887c648d1a66238dc82d715c1e2cad Mon Sep 17 00:00:00
  2001
  From: Peter Rosin p...@axentia.se
  Date: Mon, 20 Oct 2014 14:38:04 +0200
  Subject: [PATCH] ASoC: atmel_ssc_dai: Track playback and capture CMR
 dividers
separately.
 
  The CMR divider register is shared by playback and capture. The SSC
  driver therefore tries to enforce rules so that the needed register
  content do not conflict during simultaneous playback/capture. However,
  the implementation also prevents changing the register content in a
  half-duplex scenario, which is needed when changing sample rates.
 
 I am not fully get what you mean here, do you mean:
- when playback, first playback 48kHz, and then playback 8Khz, the 8Khz 
 still
 playback in 48kHz mode?
 
 or other things?

I do not know exactly why the problem occurs, but it might be connected to
the library (proprietary) we are using. It apparently uses the OSS interface
and somehow it opens a stream and changes the playback sample-rate a
couple of time before it settles on something. I don't know why this is
done, and I have no control over it. The end result is that without this patch,
the ssc-dai driver returns -EBUSY when the library changes the playback
sample-rate (the driver returns -EBUSY because it thinks that the new
sample rate does not match a previously given capture sample-rate, but
that is of course bogus when no capture is going on at all).

  Thus, keep track of the desired playback and capture clock dividers
  separately, and allow changing rates without closing the stream.
 
  Signed-off-by: Peter Rosin p...@axentia.se
  ---
sound/soc/atmel/atmel_ssc_dai.c |   31 ++--
 ---
sound/soc/atmel/atmel_ssc_dai.h |   10 ++
2 files changed, 28 insertions(+), 13 deletions(-)
 
  diff --git a/sound/soc/atmel/atmel_ssc_dai.c
  b/sound/soc/atmel/atmel_ssc_dai.c index f403f39..fec14fb 100644
  --- a/sound/soc/atmel/atmel_ssc_dai.c
  +++ b/sound/soc/atmel/atmel_ssc_dai.c
  @@ -277,7 +277,8 @@ static void atmel_ssc_shutdown(struct
 snd_pcm_substream *substream,
  /* Reset the SSC */
  ssc_writel(ssc_p-ssc-regs, CR, SSC_BIT(CR_SWRST));
  /* Clear the SSC dividers */
  -   ssc_p-cmr_div = ssc_p-tcmr_period = ssc_p-rcmr_period
 = 0;
  +   ssc_p-tcmr_div = ssc_p-rcmr_div = 0;
  +   ssc_p-tcmr_period = ssc_p-rcmr_period = 0;
  }
  spin_unlock_irq(ssc_p-lock);
}
  @@ -304,17 +305,27 @@ static int atmel_ssc_set_dai_clkdiv(struct
 snd_soc_dai *cpu_dai,
  struct atmel_ssc_info *ssc_p = ssc_info[cpu_dai-id];
 
  switch (div_id) {
  -   case ATMEL_SSC_CMR_DIV:
  +   case ATMEL_SSC_TCMR_DIV:
  /*
   * The same master clock divider is used for both
   * transmit and receive, so if a value has already
  -* been set, it must match this value.
  +* been set for the other direction, it must match
  +* this value.
   */
  -   if (ssc_p-cmr_div == 0)
  -   ssc_p-cmr_div = div;
  -   else
  -   if (div != ssc_p-cmr_div)
  -   return -EBUSY;
  +   if (ssc_p-rcmr_div == 0)
  +   ssc_p-tcmr_div = div;
  +   else if (div != ssc_p-rcmr_div)
  +   return -EBUSY;
  +   break;
  +
  +   case ATMEL_SSC_RCMR_DIV:
  +   /*
  +* See ATMEL_SSC_TCMR_DIV.
  +*/
  +   if (ssc_p-tcmr_div == 0)
  +   ssc_p-rcmr_div = div;
  +   else if (div != ssc_p-tcmr_div)
  +   return -EBUSY;
  break;
 
  case ATMEL_SSC_TCMR_PERIOD:
  @@ -345,6 +356,7 @@ static int atmel_ssc_hw_params(struct
 snd_pcm_substream *substream,
  struct atmel_pcm_dma_params *dma_params;
  int dir, channels, bits;
  u32 tfmr, rfmr, tcmr, rcmr;
  +   u16 cmr;
 
 should be u32.

Ok, I'll send an updated patch later.

  int start_event;
  int ret;
  int fslen, fslen_ext;
  @@ -626,7 +638,8 @@ static int atmel_ssc_hw_params(struct
 snd_pcm_substream *substream,
  }
 
  /* set SSC clock mode register */
  -   ssc_writel(ssc_p-ssc-regs, CMR, ssc_p-cmr_div);
  +   cmr = ssc_p-tcmr_div ? ssc_p-tcmr_div : ssc_p-rcmr_div;
  +   ssc_writel(ssc_p-ssc-regs, CMR, cmr);
 
  /* set receive clock mode and format */
  ssc_writel(ssc_p-ssc-regs, RCMR, rcmr); diff --git
  a/sound/soc/atmel/atmel_ssc_dai.h b/sound/soc/atmel/atmel_ssc_dai.h
  index b1f08d5..a25df7a 100644
  --- a/sound/soc/atmel/atmel_ssc_dai.h
  +++ b/sound/soc/atmel/atmel_ssc_dai.h
  @@ -39,9 +39,10 @@
#define ATMEL_SYSCLK_MCK  0 /* SSC uses AT91 MCK as system
 clock */
 
/* SSC divider ids */
  -#define ATMEL_SSC_CMR_DIV  0 /* MCK divider for BCLK */
  -#define

RE: [alsa-devel] [PATCH] ASoC: atmel_ssc_dai: Track playback and capture CMR dividers separately.

2014-10-21 Thread Peter Rosin
Hi again!

 Hi Peter,
 
 On 10/21/2014 03:55 PM, Peter Rosin wrote:
  Hi!
 
  (and thank you for the pointer to the example with the ssc-dai in
  master mode)
 
  Hi Peter,
 
  On 10/20/2014 09:45 PM, Peter Rosin wrote:
From 1e5621d7b9887c648d1a66238dc82d715c1e2cad Mon Sep 17
 00:00:00
  2001
  From: Peter Rosin p...@axentia.se
  Date: Mon, 20 Oct 2014 14:38:04 +0200
  Subject: [PATCH] ASoC: atmel_ssc_dai: Track playback and capture CMR
  dividers
 separately.
 
  The CMR divider register is shared by playback and capture. The SSC
  driver therefore tries to enforce rules so that the needed register
  content do not conflict during simultaneous playback/capture.
  However, the implementation also prevents changing the register
  content in a half-duplex scenario, which is needed when changing
 sample rates.
 
  I am not fully get what you mean here, do you mean:
  - when playback, first playback 48kHz, and then playback 8Khz,
  the 8Khz still playback in 48kHz mode?
 
  or other things?
 
  I do not know exactly why the problem occurs, but it might be
  connected to the library (proprietary) we are using. It apparently
  uses the OSS interface and somehow it opens a stream and changes the
  playback sample-rate a couple of time before it settles on something.
  I don't know why this is done, and I have no control over it. The end
  result is that without this patch, the ssc-dai driver returns -EBUSY
  when the library changes the playback sample-rate (the driver returns
  -EBUSY because it thinks that the new sample rate does not match a
  previously given capture sample-rate, but that is of course bogus when no
 capture is going on at all).
 
 If this issue is caused by your proprietary library, please fix in the 
 library.

Ah, but it's not our proprietary library to fix, it's simply a library that we
are using (speech synthesis, not our area of expertise). So, I'm not in a
position to simply fix it, as I have no source code.

 I don't know how this code can fix your issue and also there is no
 improvement to the code and it absolutely increase work (choose which
 clock to configure: tcmr or rcmr) for the SSC work in master. And also this
 patch may confuse the end user, let them thinking the clock for tcmr and
 rcmr can configure seperately.

I added some traces to our hw_params and got the following (without the patch):

[  161.17] atmel ssc startup
[  161.17]  TFA9879: axentia_asoc_tfa9879_hw_params - mclk rate 6600
[  161.18]  TFA9879: axentia_asoc_tfa9879_hw_params - bclk rate 128000
[  161.18]  TFA9879: axentia_asoc_tfa9879_hw_params - bclk divider 128
[  161.19]  TFA9879: axentia_asoc_tfa9879_hw_params - period 7
[  161.20]  TFA9879: axentia_asoc_tfa9879_hw_params - mclk rate 6600
[  161.20]  TFA9879: axentia_asoc_tfa9879_hw_params - bclk rate 128000
[  161.21]  TFA9879: axentia_asoc_tfa9879_hw_params - bclk divider 128
[  161.22]  TFA9879: axentia_asoc_tfa9879_hw_params - period 7
[  161.23]  TFA9879: axentia_asoc_tfa9879_hw_params - mclk rate 6600
[  161.23]  TFA9879: axentia_asoc_tfa9879_hw_params - bclk rate 256000
[  161.24]  TFA9879: axentia_asoc_tfa9879_hw_params - bclk divider 64
[  161.25]  TFA9879: axentia_asoc_tfa9879_hw_params - Failed to set cpu dai 
clk divider
[  161.26] axentia-tfa9879-audio sound.9: ASoC: machine hw_params failed: 
-16

 So, I think keep the code as is (without this patch applied), what's your
 opinion?

In that case we'll simply carry the patch ourselves. I don't know why the above
happens, or if it is caused by bad behavior in the library, or what. But I do 
know
that the library is unusable for us without some action.

I thought it was an improvement, and therefore sent the patch...

Cheers,
Peter
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


RE: [alsa-devel] [PATCH] ASoC: atmel_ssc_dai: Track playback and capture CMR dividers separately.

2014-10-21 Thread Peter Rosin
Hi again,

 -Original Message-
 From: Peter Rosin
 Sent: Tuesday, October 21, 2014 13:05
 To: 'Bo Shen'
 Cc: Liam Girdwood; Mark Brown; Jaroslav Kysela; Takashi Iwai; 'alsa-
 de...@alsa-project.org'; linux-kernel@vger.kernel.org
 Subject: RE: [alsa-devel] [PATCH] ASoC: atmel_ssc_dai: Track playback and
 capture CMR dividers separately.
 
 Hi again!
 
  Hi Peter,
 
  On 10/21/2014 03:55 PM, Peter Rosin wrote:
   Hi!
  
   (and thank you for the pointer to the example with the ssc-dai in
   master mode)
  
   Hi Peter,
  
   On 10/20/2014 09:45 PM, Peter Rosin wrote:
 From 1e5621d7b9887c648d1a66238dc82d715c1e2cad Mon Sep 17
  00:00:00
   2001
   From: Peter Rosin p...@axentia.se
   Date: Mon, 20 Oct 2014 14:38:04 +0200
   Subject: [PATCH] ASoC: atmel_ssc_dai: Track playback and capture
 CMR
   dividers
  separately.
  
   The CMR divider register is shared by playback and capture. The SSC
   driver therefore tries to enforce rules so that the needed register
   content do not conflict during simultaneous playback/capture.
   However, the implementation also prevents changing the register
   content in a half-duplex scenario, which is needed when changing
  sample rates.
  
   I am not fully get what you mean here, do you mean:
   - when playback, first playback 48kHz, and then playback 8Khz,
   the 8Khz still playback in 48kHz mode?
  
   or other things?
  
   I do not know exactly why the problem occurs, but it might be
   connected to the library (proprietary) we are using. It apparently
   uses the OSS interface and somehow it opens a stream and changes the
   playback sample-rate a couple of time before it settles on something.
   I don't know why this is done, and I have no control over it. The end
   result is that without this patch, the ssc-dai driver returns -EBUSY
   when the library changes the playback sample-rate (the driver returns
   -EBUSY because it thinks that the new sample rate does not match a
   previously given capture sample-rate, but that is of course bogus when
 no
  capture is going on at all).
 
  If this issue is caused by your proprietary library, please fix in the 
  library.
 
 Ah, but it's not our proprietary library to fix, it's simply a library that 
 we
 are using (speech synthesis, not our area of expertise). So, I'm not in a
 position to simply fix it, as I have no source code.
 
  I don't know how this code can fix your issue and also there is no
  improvement to the code and it absolutely increase work (choose which
  clock to configure: tcmr or rcmr) for the SSC work in master. And also this
  patch may confuse the end user, let them thinking the clock for tcmr and
  rcmr can configure seperately.
 
 I added some traces to our hw_params and got the following (without the
 patch):
 
 [  161.17] atmel ssc startup
 [  161.17]  TFA9879: axentia_asoc_tfa9879_hw_params - mclk rate
 6600
 [  161.18]  TFA9879: axentia_asoc_tfa9879_hw_params - bclk rate 128000
 [  161.18]  TFA9879: axentia_asoc_tfa9879_hw_params - bclk divider 128
 [  161.19]  TFA9879: axentia_asoc_tfa9879_hw_params - period 7
 [  161.20]  TFA9879: axentia_asoc_tfa9879_hw_params - mclk rate
 6600
 [  161.20]  TFA9879: axentia_asoc_tfa9879_hw_params - bclk rate 128000
 [  161.21]  TFA9879: axentia_asoc_tfa9879_hw_params - bclk divider 128
 [  161.22]  TFA9879: axentia_asoc_tfa9879_hw_params - period 7
 [  161.23]  TFA9879: axentia_asoc_tfa9879_hw_params - mclk rate
 6600
 [  161.23]  TFA9879: axentia_asoc_tfa9879_hw_params - bclk rate 256000
 [  161.24]  TFA9879: axentia_asoc_tfa9879_hw_params - bclk divider 64
 [  161.25]  TFA9879: axentia_asoc_tfa9879_hw_params - Failed to set cpu
 dai clk divider
 [  161.26] axentia-tfa9879-audio sound.9: ASoC: machine hw_params
 failed: -16

I did some further tests, and the following program fails without the patch:

#include sys/ioctl.h
#include unistd.h
#include fcntl.h
#include sys/soundcard.h

int
main(void)
{
int fd;
int format;
int channels;

if ((fd = open(/dev/dsp, O_WRONLY, 0)) == -1) {
perror(open);
return 1;
}
format = AFMT_S16_LE;
if (ioctl(fd, SNDCTL_DSP_SETFMT, format) == -1) {
perror(SNDCTL_DSP_SETFMT);
return 1;
}
channels = 2;
if (ioctl(fd, SNDCTL_DSP_CHANNELS, channels) == -1) {
perror(SNDCTL_DSP_CHANNELS);
return 1;
}
return 0;
}

Output:
SNDCTL_DSP_CHANNELS: Device or resource busy

(I admin to having edited the above code slightly in this mail, so I might have
introduced some silly bug, but you get what I mean, just open the device
and request some parameters, and boom: -EBUSY)

Cheers,
Peter

  So, I think keep the code as is (without this patch applied), what's your
  opinion?
 
 In that case we'll simply carry the patch ourselves. I don't know why the
 above
 happens

RE: [alsa-devel] [PATCH] ASoC: atmel_ssc_dai: Track playback and capture CMR dividers separately.

2014-10-21 Thread Peter Rosin
Hi!

 Hi Peter,
 
 On 10/21/2014 09:05 PM, Peter Rosin wrote:
  I did some further tests, and the following program fails without the patch:
 
 With the patch, it is OK?

Yes.

  #include sys/ioctl.h
  #include unistd.h
  #include fcntl.h
  #include sys/soundcard.h
 
  int
  main(void)
  {
  int fd;
  int format;
  int channels;
 
  if ((fd = open(/dev/dsp, O_WRONLY, 0)) == -1) {
  perror(open);
  return 1;
  }
  format = AFMT_S16_LE;
  if (ioctl(fd, SNDCTL_DSP_SETFMT, format) == -1) {
  perror(SNDCTL_DSP_SETFMT);
  return 1;
  }
  channels = 2;
  if (ioctl(fd, SNDCTL_DSP_CHANNELS, channels) == -1) {
  perror(SNDCTL_DSP_CHANNELS);
  return 1;
  }
  return 0;
  }
 
  Output:
  SNDCTL_DSP_CHANNELS: Device or resource busy
 
 This return from codec or from atmel_ssc_dai?

This -EBUSY definitely comes from atmel_ssc_set_dai_sysclk, when my
card-driver tries to set ATMEL_SSC_CMR_DIV. With the patch, it works.
(the codec is spdif-transmitter, since the i2c interface of the actual tfa9879
codec is not directly reachable from the linux cpu, but that has nothing to
do with this issue).

  (I admin to having edited the above code slightly in this mail, so I
s/admin/admit/
  might have introduced some silly bug, but you get what I mean, just
  open the device and request some parameters, and boom: -EBUSY)

Cheers,
Peter

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


RE: [alsa-devel] [PATCH] ASoC: atmel_ssc_dai: Track playback and capture CMR dividers separately.

2014-10-22 Thread Peter Rosin
Hi!

  With the patch, it is OK?
 
  Yes.
 
  #include sys/ioctl.h
  #include unistd.h
  #include fcntl.h
  #include sys/soundcard.h
 
  int
  main(void)
  {
int fd;
int format;
int channels;
 
if ((fd = open(/dev/dsp, O_WRONLY, 0)) == -1) {
perror(open);
return 1;
}
format = AFMT_S16_LE;
if (ioctl(fd, SNDCTL_DSP_SETFMT, format) == -1) {
perror(SNDCTL_DSP_SETFMT);
return 1;
}
channels = 2;
if (ioctl(fd, SNDCTL_DSP_CHANNELS, channels) == -1) {
perror(SNDCTL_DSP_CHANNELS);
return 1;
}
return 0;
  }
 
  Output:
  SNDCTL_DSP_CHANNELS: Device or resource busy
 
  This return from codec or from atmel_ssc_dai?
 
  This -EBUSY definitely comes from atmel_ssc_set_dai_sysclk, when my
  card-driver tries to set ATMEL_SSC_CMR_DIV. With the patch, it works.
  (the codec is spdif-transmitter, since the i2c interface of the actual
  tfa9879 codec is not directly reachable from the linux cpu, but that
  has nothing to do with this issue).
 
 I try to reproduce it (using the code your pasted directly) on atmel
 sama5d3xek with wm8904 code, don't meet this error.
 
 I also go through the OSS code, I still don't find this is related with
 atmel_ssc_set_dai_sysclk.
 
 So, am I missing something or something else?

The sama5d3xek/wm9804 combo, as implemented in the kernel, has the
ssc dai in slave mode, and therefore don't need to fiddle with any
ssc dai dividers (atmel_9804.c :atmel_asoc_wm9804_hw_params() only
sets things in the wm9804 codec dai driver and leaves the ssc dai to itself). 

Instead, try the above code on your code with the ssc dai in master mode
that you pointed at previously.

https://github.com/Android4SAM/linux-at91/commit/33db8ebd3e75632c482dda271340f4d2adcfd320

If that happens to not hit -EBUSY (which it might not, since the wm9804 codec
will only allow stereo, so the SNDCTL_DSP_CHANNELS ioctl might not need
to make any change for any ssc divider) add code to also set a non-default
sample rate, e.g.:

speed = 22050;
if (ioctl(fd, SNDCTL_DSP_SPEED, speed) == -1) {
perror(SNDCTL_DSP_SPEED);
return 1;
}

Cheers,
Peter

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


RE: [alsa-devel] [PATCH] ASoC: atmel_ssc_dai: Track playback and capture CMR dividers separately.

2014-10-22 Thread Peter Rosin
Bo Chen wrote:
 with this piece of code, I reproduce your issue.
 
 Now, I know the reason of this issue, work in oss mode, it will set the 
 default
 clock to 8KHz, and then if change to other sample rate, for example 48KHz,
 the div is different, then it reports -EBUSY.

Indeed.

 So, I think we won't change the ATMEL_SSC_CMR_DIV to
 ATMEL_SSC_TCMR_DIV and ATMEL_SSC_RCMR_DIV, as it will affect other
 users. We just deal with this situation in ATMEL_SSC_CMR_DIV block, check
 the direction, if the same direction change the div, then accept the change,
 otherwise, return -EBUSY.

Ok.

But I'm not sure it is possible to dig out the current direction in the
.set_clkdiv callback? Perhaps the correct fix is to set the bits
.symmetric_rates, .symmetric_channels and .symmetric_samplebits
in the atmel_ssc_dai struct when the ssc dai is master? Then I
expect that other mechanisms will kick in that will render the current
CMR_DIV check pointless?

Is a dai driver allowed to change these symmetry bits after registration?
Can they be set in the .set_sysclk callback? Perhaps in the
ATMEL_SSC_CMR_DIV block itself? That callback should only be
called when the dai is master, so that would be perfect...

Yes, the limitation would be a little bit more strict than today, but is it
really common to require different modes on playback and capture?

Cheers,
Peter

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v2] ASoC: atmel_ssc_dai: Match the CMR divider only in full duplex.

2014-10-22 Thread Peter Rosin
From 86be84c4de4e7b21cfda9656a02a902c543210af Mon Sep 17 00:00:00 2001
From: Peter Rosin p...@axentia.se
Date: Wed, 22 Oct 2014 16:45:29 +0200
Subject: [PATCH v2] ASoC: atmel_ssc_dai: Match the CMR divider only in full
 duplex.

The CMR divider register is shared by playback and capture. The SSC driver
therefore tries to enforce rules so that the needed register content do
not conflict during simultaneous playback/capture. However, the
implementation also prevents changing the register content in
half-duplex scenarios, which is needed when using the OSS API.

Thus, only lock the divider if there is a stream in the other direction.

Fixes the below program to not fail with the atmel ssc dai in master mode.

#include sys/ioctl.h
#include unistd.h
#include fcntl.h
#include sys/soundcard.h

int
main(void)
{
int fd;
int format;
int channels;
int speed;

if ((fd = open(/dev/dsp, O_WRONLY, 0)) == -1) {
perror(open);
return 1;
}
format = AFMT_S16_LE;
if (ioctl(fd, SNDCTL_DSP_SETFMT, format) == -1) {
perror(SNDCTL_DSP_SETFMT);
return 1;
}
channels = 2;
if (ioctl(fd, SNDCTL_DSP_CHANNELS, channels) == -1) {
perror(SNDCTL_DSP_CHANNELS);
return 1;
}
speed = 22025;
if (ioctl(fd, SNDCTL_DSP_SPEED, speed) == -1) {
perror(SNDCTL_DSP_SPEED);
return 1;
}
return 0;
}

Signed-off-by: Peter Rosin p...@axentia.se
---
 sound/soc/atmel/atmel_ssc_dai.c |5 -
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
index de433cfd..9ae8475 100644
--- a/sound/soc/atmel/atmel_ssc_dai.c
+++ b/sound/soc/atmel/atmel_ssc_dai.c
@@ -310,7 +310,10 @@ static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai 
*cpu_dai,
 * transmit and receive, so if a value has already
 * been set, it must match this value.
 */
-   if (ssc_p-cmr_div == 0)
+   if (ssc_p-dir_mask !=
+   (SSC_DIR_MASK_PLAYBACK | SSC_DIR_MASK_CAPTURE))
+   ssc_p-cmr_div = div;
+   else if (ssc_p-cmr_div == 0)
ssc_p-cmr_div = div;
else
if (div != ssc_p-cmr_div)
-- 
1.7.10.4

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


RE: [PATCH 1/2] ASoC: tfa9879: New driver for NXP Semiconductors TFA9879 amplifier.

2014-11-06 Thread Peter Rosin
Thanks for the review! I'm answering here, but would like to thank
Lars-Peter for the review as well.

Mark Brown wrote:
 On Thu, Nov 06, 2014 at 01:54:00PM +0100, Peter Rosin wrote:
 
  +#define TFA9879_REG(codec, reg, field, value)  \
  +   snd_soc_update_bits(codec, TFA9879_ ## reg, \
  +   TFA9879_ ## field ## _MASK, \
  +   (value)  TFA9879_ ## field ## _SHIFT)
 
 Please don't do stuff like this, it just makes the code look more obscure than
 it should be for people who work with multiple devices - just use
 update_bits() directly.

Ok, I'll zap it. Pity though, I really liked the actual code even if the macro 
was a
bit hard to digest...

  +static int tfa9879_prepare(struct snd_pcm_substream *substream,
  +  struct snd_soc_dai *dai)
  +{
  +   struct snd_soc_codec *codec = dai-codec;
  +
  +   TFA9879_REG(codec, DEVICE_CONTROL, POWERUP, 1);
 
 Use DAPM to manage power, you're probably looking for a supply widget.

I'll try to find out how to hook that up. BTW, there is very limited info about
the supply widget at http://www.alsa-project.org/main/index.php/DAPM

  +   switch (params_format(params)) {
  +   case SNDRV_PCM_FORMAT_S16_LE:
 
 Use params_width() rather than a specific memory layout.

Ok.

  +   if (tfa9879-lsb_justified)
  +   TFA9879_REG(codec, SERIAL_INTERFACE_1, I2S_SET,
 i2s_set);
 
 Why does this need to be reset every time, shouldn't we just be setting the
 register in set_fmt().?

Yes, I'd sure like to do that, but how do I get to the width in set_fmt()?

  +static int tfa9879_probe(struct snd_soc_codec *codec) {
  +   struct tfa9879_priv *tfa9879 = snd_soc_codec_get_drvdata(codec);
  +
  +   codec-control_data = tfa9879-regmap;
 
 This is redundant, just remove the entire function - ASoC will get the regmap
 automatically.

Oops, sorry. Forward-porting in progress...

  +   { TFA9879_MISC_STATUS,  0x }, /* 0x15, read-only */
  +};
  +
  +static bool tfa9879_volatile_register(struct device *dev, unsigned
  +int reg) {
  +   return reg == TFA9879_MISC_STATUS;
 
 If the register is volatile it shouldn't have a default value provided.

Then I misunderstood what volatile was meant to do. I'll just nuke the
function. It works fine anyway...

I'll send a v2 later, with the other bits from Lars-Peter taken care of, and
with 2/2 squashed. Need to test first though...

Cheers,
Peter

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v2] ASoC: tfa9879: New driver for NXP Semiconductors TFA9879 amplifier.

2014-11-06 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

Signed-off-by: Peter Rosin p...@axentia.se
---
 MAINTAINERS|6 +
 sound/soc/codecs/Kconfig   |5 +
 sound/soc/codecs/Makefile  |2 +
 sound/soc/codecs/tfa9879.c |  323 
 sound/soc/codecs/tfa9879.h |  202 +++
 5 files changed, 538 insertions(+)
 create mode 100644 sound/soc/codecs/tfa9879.c
 create mode 100644 sound/soc/codecs/tfa9879.h

diff --git a/MAINTAINERS b/MAINTAINERS
index f10ed3914ea8..9ca9e68ea9ab 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6467,6 +6467,12 @@ S:   Supported
 F: drivers/gpu/drm/i2c/tda998x_drv.c
 F: include/drm/i2c/tda998x.h
 
+NXP TFA9879 DRIVER
+M: Peter Rosin p...@axentia.se
+L: alsa-de...@alsa-project.org (moderated for non-subscribers)
+S: Maintained
+F: sound/soc/codecs/tfa9879*
+
 OMAP SUPPORT
 M: Tony Lindgren t...@atomide.com
 L: linux-o...@vger.kernel.org
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 8838838e25ed..36bf3f83a333 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -96,6 +96,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
select SND_SOC_TAS2552 if I2C
select SND_SOC_TAS5086 if I2C
+   select SND_SOC_TFA9879 if I2C
select SND_SOC_TLV320AIC23_I2C if I2C
select SND_SOC_TLV320AIC23_SPI if SPI_MASTER
select SND_SOC_TLV320AIC26 if SPI_MASTER
@@ -548,6 +549,10 @@ config SND_SOC_TAS5086
tristate Texas Instruments TAS5086 speaker amplifier
depends on I2C
 
+config SND_SOC_TFA9879
+   tristate NXP Semiconductors TFA9879 amplifier
+   depends on I2C
+
 config SND_SOC_TLV320AIC23
tristate
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 20afe0f0c5be..678a3a6df8a5 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -96,6 +96,7 @@ snd-soc-sta350-objs := sta350.o
 snd-soc-sta529-objs := sta529.o
 snd-soc-stac9766-objs := stac9766.o
 snd-soc-tas5086-objs := tas5086.o
+snd-soc-tfa9879-objs := tfa9879.o
 snd-soc-tlv320aic23-objs := tlv320aic23.o
 snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o
 snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o
@@ -264,6 +265,7 @@ obj-$(CONFIG_SND_SOC_STA529)   += snd-soc-sta529.o
 obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o
 obj-$(CONFIG_SND_SOC_TAS2552)  += snd-soc-tas2552.o
 obj-$(CONFIG_SND_SOC_TAS5086)  += snd-soc-tas5086.o
+obj-$(CONFIG_SND_SOC_TFA9879)  += snd-soc-tfa9879.o
 obj-$(CONFIG_SND_SOC_TLV320AIC23)  += snd-soc-tlv320aic23.o
 obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C)  += snd-soc-tlv320aic23-i2c.o
 obj-$(CONFIG_SND_SOC_TLV320AIC23_SPI)  += snd-soc-tlv320aic23-spi.o
diff --git a/sound/soc/codecs/tfa9879.c b/sound/soc/codecs/tfa9879.c
new file mode 100644
index ..c48022639a29
--- /dev/null
+++ b/sound/soc/codecs/tfa9879.c
@@ -0,0 +1,323 @@
+/*
+ * tfa9879.c  --  driver for NXP Semiconductors TFA9879
+ *
+ * Copyright (C) 2014 Axentia Technologies AB
+ * Author: Peter Rosin p...@axentia.se
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include linux/module.h
+#include linux/init.h
+#include linux/i2c.h
+#include linux/regmap.h
+#include sound/soc.h
+#include sound/tlv.h
+#include sound/pcm_params.h
+
+#include tfa9879.h
+
+struct tfa9879_priv {
+   struct regmap *regmap;
+   int lsb_justified;
+};
+
+static int tfa9879_hw_params(struct snd_pcm_substream *substream,
+struct snd_pcm_hw_params *params,
+struct snd_soc_dai *dai)
+{
+   struct snd_soc_codec *codec = dai-codec;
+   struct tfa9879_priv *tfa9879 = snd_soc_codec_get_drvdata(codec);
+   int fs;
+   int i2s_set = 0;
+
+   switch (params_rate(params)) {
+   case 8000:
+   fs = TFA9879_I2S_FS_8000;
+   break;
+   case 11025:
+   fs = TFA9879_I2S_FS_11025;
+   break;
+   case 12000:
+   fs = TFA9879_I2S_FS_12000;
+   break;
+   case 16000:
+   fs = TFA9879_I2S_FS_16000;
+   break;
+   case 22050:
+   fs = TFA9879_I2S_FS_22050;
+   break;
+   case 24000:
+   fs = TFA9879_I2S_FS_24000;
+   break;
+   case 32000:
+   fs = TFA9879_I2S_FS_32000;
+   break;
+   case 44100:
+   fs = TFA9879_I2S_FS_44100;
+   break;
+   case 48000:
+   fs = TFA9879_I2S_FS_48000;
+   break;
+   case 64000:
+   fs = TFA9879_I2S_FS_64000;
+   break;
+   case 88200:
+   fs = TFA9879_I2S_FS_88200

[v2] NXP Semiconductors TFA9879 Amplifier Driver

2014-11-06 Thread Peter Rosin
On 2014-11-06 17:02, Mark Brown wrote: On Thu, Nov 06, 2014 at 02:37:31PM 
+, Peter Rosin wrote:
  Mark Brown wrote:
+if (tfa9879-lsb_justified)
+TFA9879_REG(codec, SERIAL_INTERFACE_1, I2S_SET, 
i2s_set);
   Why does this need to be reset every time, shouldn't we just be setting 
   the
   register in set_fmt().?
  Yes, I'd sure like to do that, but how do I get to the width in set_fmt()?
 Oh, this has some width related thing in it?

Yes, the amp has a different setting for each lsb-justified width.
(It also supports 18 and 20 bits wide data)

+{ TFA9879_MISC_STATUS,  0x }, /* 0x15, read-only */
+};
+static bool tfa9879_volatile_register(struct device *dev, unsigned
+int reg) {
+return reg == TFA9879_MISC_STATUS;
   If the register is volatile it shouldn't have a default value provided.
  Then I misunderstood what volatile was meant to do. I'll just nuke the
  function. It works fine anyway...
 A volatile register is one that the chip may change autonomously (eg, an
 interrupt status register).

That was what I assumed, and the register behaves like that. I naively
thought that declaring it as volatile would prevent the asoc core from
writing to it. In retrospect, I don't understand why I thought that...
Anyway, that bit can wait until someone actually needs to read the staus.

Here's an update with the following changes since v1:

- squashed patch 2/2
- zapped the TFA9879_REG macro
- zapped tfa9879_probe (which needlessly registered the regmap)
- moved tfa9879_prepare/_shutdown to a DAPM_SUPPLY widget
- zapped the tfa9879_volatile() thing
- made tfa9879_dai_ops const
- erased the redundant Gain from the bass/treble volume controls
- using params_width() instead of params_format()

Cheers,
Peter


--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


NXP Semiconductors TFA9879 Amplifier Driver

2014-11-08 Thread Peter Rosin
Mark Brown wrote:
 On Thu, Nov 06, 2014 at 05:39:45PM +0100, Peter Rosin wrote:
 
  +   { TFA9879_MISC_STATUS,  0x }, /* 0x15, read-only
 */
 
 The fix here is the wrong way round - if the device is reporting status
 here there should be no default and there should be a volatile operation
 (though it's not the end of the world to omit that if it's not used).
 
 Otherwise this looks good.

Ok, I think I finally see what you mean...

Diff since v2 below.

Cheers,
Peter

diff --git a/sound/soc/codecs/tfa9879.c b/sound/soc/codecs/tfa9879.c
index c48022639a29..16f1b71edb55 100644
--- a/sound/soc/codecs/tfa9879.c
+++ b/sound/soc/codecs/tfa9879.c
@@ -182,9 +182,13 @@ static struct reg_default tfa9879_regs[] = {
{ TFA9879_HIGH_PASS_FILTER, 0x0004 }, /* 0x12 */
{ TFA9879_VOLUME_CONTROL,   0x10bd }, /* 0x13 */
{ TFA9879_MISC_CONTROL, 0x }, /* 0x14 */
-   { TFA9879_MISC_STATUS,  0x }, /* 0x15, read-only */
 };
 
+static bool tfa9879_volatile_reg(struct device *dev, unsigned int reg)
+{
+   return reg == TFA9879_MISC_STATUS;
+}
+
 static const DECLARE_TLV_DB_SCALE(volume_tlv, -7050, 50, 1);
 static const DECLARE_TLV_DB_SCALE(tb_gain_tlv, -1800, 200, 0);
 static const char * const tb_freq_text[] = {
@@ -240,6 +244,7 @@ static const struct regmap_config tfa9879_regmap = {
.reg_bits = 8,
.val_bits = 16,
 
+   .volatile_reg = tfa9879_volatile_reg,
.max_register = TFA9879_MISC_STATUS,
.reg_defaults = tfa9879_regs,
.num_reg_defaults = ARRAY_SIZE(tfa9879_regs),
@@ -285,7 +290,7 @@ static int tfa9879_i2c_probe(struct i2c_client *i2c,
return PTR_ERR(tfa9879-regmap);
 
/* Ensure the device is in reset state */
-   for (i = 0; i  ARRAY_SIZE(tfa9879_regs) - 1; i++)
+   for (i = 0; i  ARRAY_SIZE(tfa9879_regs); i++)
regmap_write(tfa9879-regmap,
 tfa9879_regs[i].reg, tfa9879_regs[i].def);
 

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v3] ASoC: tfa9879: New driver for NXP Semiconductors TFA9879 amplifier.

2014-11-08 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

Signed-off-by: Peter Rosin p...@axentia.se
---
 MAINTAINERS|6 +
 sound/soc/codecs/Kconfig   |5 +
 sound/soc/codecs/Makefile  |2 +
 sound/soc/codecs/tfa9879.c |  328 
 sound/soc/codecs/tfa9879.h |  202 +++
 5 files changed, 543 insertions(+)
 create mode 100644 sound/soc/codecs/tfa9879.c
 create mode 100644 sound/soc/codecs/tfa9879.h

diff --git a/MAINTAINERS b/MAINTAINERS
index f10ed3914ea8..9ca9e68ea9ab 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6467,6 +6467,12 @@ S:   Supported
 F: drivers/gpu/drm/i2c/tda998x_drv.c
 F: include/drm/i2c/tda998x.h
 
+NXP TFA9879 DRIVER
+M: Peter Rosin p...@axentia.se
+L: alsa-de...@alsa-project.org (moderated for non-subscribers)
+S: Maintained
+F: sound/soc/codecs/tfa9879*
+
 OMAP SUPPORT
 M: Tony Lindgren t...@atomide.com
 L: linux-o...@vger.kernel.org
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 8838838e25ed..36bf3f83a333 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -96,6 +96,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
select SND_SOC_TAS2552 if I2C
select SND_SOC_TAS5086 if I2C
+   select SND_SOC_TFA9879 if I2C
select SND_SOC_TLV320AIC23_I2C if I2C
select SND_SOC_TLV320AIC23_SPI if SPI_MASTER
select SND_SOC_TLV320AIC26 if SPI_MASTER
@@ -548,6 +549,10 @@ config SND_SOC_TAS5086
tristate Texas Instruments TAS5086 speaker amplifier
depends on I2C
 
+config SND_SOC_TFA9879
+   tristate NXP Semiconductors TFA9879 amplifier
+   depends on I2C
+
 config SND_SOC_TLV320AIC23
tristate
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 20afe0f0c5be..678a3a6df8a5 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -96,6 +96,7 @@ snd-soc-sta350-objs := sta350.o
 snd-soc-sta529-objs := sta529.o
 snd-soc-stac9766-objs := stac9766.o
 snd-soc-tas5086-objs := tas5086.o
+snd-soc-tfa9879-objs := tfa9879.o
 snd-soc-tlv320aic23-objs := tlv320aic23.o
 snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o
 snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o
@@ -264,6 +265,7 @@ obj-$(CONFIG_SND_SOC_STA529)   += snd-soc-sta529.o
 obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o
 obj-$(CONFIG_SND_SOC_TAS2552)  += snd-soc-tas2552.o
 obj-$(CONFIG_SND_SOC_TAS5086)  += snd-soc-tas5086.o
+obj-$(CONFIG_SND_SOC_TFA9879)  += snd-soc-tfa9879.o
 obj-$(CONFIG_SND_SOC_TLV320AIC23)  += snd-soc-tlv320aic23.o
 obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C)  += snd-soc-tlv320aic23-i2c.o
 obj-$(CONFIG_SND_SOC_TLV320AIC23_SPI)  += snd-soc-tlv320aic23-spi.o
diff --git a/sound/soc/codecs/tfa9879.c b/sound/soc/codecs/tfa9879.c
new file mode 100644
index ..16f1b71edb55
--- /dev/null
+++ b/sound/soc/codecs/tfa9879.c
@@ -0,0 +1,328 @@
+/*
+ * tfa9879.c  --  driver for NXP Semiconductors TFA9879
+ *
+ * Copyright (C) 2014 Axentia Technologies AB
+ * Author: Peter Rosin p...@axentia.se
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include linux/module.h
+#include linux/init.h
+#include linux/i2c.h
+#include linux/regmap.h
+#include sound/soc.h
+#include sound/tlv.h
+#include sound/pcm_params.h
+
+#include tfa9879.h
+
+struct tfa9879_priv {
+   struct regmap *regmap;
+   int lsb_justified;
+};
+
+static int tfa9879_hw_params(struct snd_pcm_substream *substream,
+struct snd_pcm_hw_params *params,
+struct snd_soc_dai *dai)
+{
+   struct snd_soc_codec *codec = dai-codec;
+   struct tfa9879_priv *tfa9879 = snd_soc_codec_get_drvdata(codec);
+   int fs;
+   int i2s_set = 0;
+
+   switch (params_rate(params)) {
+   case 8000:
+   fs = TFA9879_I2S_FS_8000;
+   break;
+   case 11025:
+   fs = TFA9879_I2S_FS_11025;
+   break;
+   case 12000:
+   fs = TFA9879_I2S_FS_12000;
+   break;
+   case 16000:
+   fs = TFA9879_I2S_FS_16000;
+   break;
+   case 22050:
+   fs = TFA9879_I2S_FS_22050;
+   break;
+   case 24000:
+   fs = TFA9879_I2S_FS_24000;
+   break;
+   case 32000:
+   fs = TFA9879_I2S_FS_32000;
+   break;
+   case 44100:
+   fs = TFA9879_I2S_FS_44100;
+   break;
+   case 48000:
+   fs = TFA9879_I2S_FS_48000;
+   break;
+   case 64000:
+   fs = TFA9879_I2S_FS_64000;
+   break;
+   case 88200:
+   fs = TFA9879_I2S_FS_88200

[PATCH] pm: at91: Workaround DDRSDRC self-refresh bug with LPDDR1 memories

2014-12-22 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

The DDRSDR controller (on the ATSAMA5D31) fails miserably to put LPDDR1
memories in self-refresh. Force the controller to think it has DDR2
memories during the self-refresh period, as the DDR2 self-refresh spec
is equivalent to LPDDR1, and is correctly implemented in the controller.

Assume that the second controller has the same fault, and that other
CPUs in the family has the same problem, but that is untested.

Signed-off-by: Peter Rosin p...@axentia.se
---
 arch/arm/mach-at91/pm_slowclock.S  |   43 +++-
 include/soc/at91/at91sam9_ddrsdr.h |2 +-
 2 files changed, 39 insertions(+), 6 deletions(-)

diff --git a/arch/arm/mach-at91/pm_slowclock.S 
b/arch/arm/mach-at91/pm_slowclock.S
index 20018779bae7..63a9e0b0a17d 100644
--- a/arch/arm/mach-at91/pm_slowclock.S
+++ b/arch/arm/mach-at91/pm_slowclock.S
@@ -143,6 +143,16 @@ ddr_sr_enable:
cmp memctrl, #AT91_MEMCTRL_DDRSDR
bne sdr_sr_enable
 
+   /* LPDDR1 -- force DDR2 mode during self-refresh */
+   ldr tmp1, [sdramc, #AT91_DDRSDRC_MDR]
+   str tmp1, .saved_sam9_mdr
+   bic tmp1, tmp1, #~AT91_DDRSDRC_MD
+   cmp tmp1, #AT91_DDRSDRC_MD_LOW_POWER_DDR
+   ldreq   tmp1, [sdramc, #AT91_DDRSDRC_MDR]
+   biceq   tmp1, tmp1, #AT91_DDRSDRC_MD
+   orreq   tmp1, tmp1, #AT91_DDRSDRC_MD_DDR2
+   streq   tmp1, [sdramc, #AT91_DDRSDRC_MDR]
+
/* prepare for DDRAM self-refresh mode */
ldr tmp1, [sdramc, #AT91_DDRSDRC_LPR]
str tmp1, .saved_sam9_lpr
@@ -151,14 +161,26 @@ ddr_sr_enable:
 
/* figure out if we use the second ram controller */
cmp ramc1, #0
-   ldrne   tmp2, [ramc1, #AT91_DDRSDRC_LPR]
-   strne   tmp2, .saved_sam9_lpr1
-   bicne   tmp2, #AT91_DDRSDRC_LPCB
-   orrne   tmp2, #AT91_DDRSDRC_LPCB_SELF_REFRESH
+   beq ddr_no_2nd_ctrl
+
+   ldr tmp2, [ramc1, #AT91_DDRSDRC_MDR]
+   str tmp2, .saved_sam9_mdr1
+   bic tmp2, tmp2, #~AT91_DDRSDRC_MD
+   cmp tmp2, #AT91_DDRSDRC_MD_LOW_POWER_DDR
+   ldreq   tmp2, [ramc1, #AT91_DDRSDRC_MDR]
+   biceq   tmp2, tmp2, #AT91_DDRSDRC_MD
+   orreq   tmp2, tmp2, #AT91_DDRSDRC_MD_DDR2
+   streq   tmp2, [ramc1, #AT91_DDRSDRC_MDR]
+
+   ldr tmp2, [ramc1, #AT91_DDRSDRC_LPR]
+   str tmp2, .saved_sam9_lpr1
+   bic tmp2, #AT91_DDRSDRC_LPCB
+   orr tmp2, #AT91_DDRSDRC_LPCB_SELF_REFRESH
 
/* Enable DDRAM self-refresh mode */
+   str tmp2, [ramc1, #AT91_DDRSDRC_LPR]
+ddr_no_2nd_ctrl:
str tmp1, [sdramc, #AT91_DDRSDRC_LPR]
-   strne   tmp2, [ramc1, #AT91_DDRSDRC_LPR]
 
b   sdr_sr_done
 
@@ -289,12 +311,17 @@ sdr_sr_done:
 */
cmp memctrl, #AT91_MEMCTRL_DDRSDR
bne sdr_en_restore
+   /* Restore MDR in case of LPDDR1 */
+   ldr tmp1, .saved_sam9_mdr
+   str tmp1, [sdramc, #AT91_DDRSDRC_MDR]
/* Restore LPR on AT91 with DDRAM */
ldr tmp1, .saved_sam9_lpr
str tmp1, [sdramc, #AT91_DDRSDRC_LPR]
 
/* if we use the second ram controller */
cmp ramc1, #0
+   ldrne   tmp2, .saved_sam9_mdr1
+   strne   tmp2, [ramc1, #AT91_DDRSDRC_MDR]
ldrne   tmp2, .saved_sam9_lpr1
strne   tmp2, [ramc1, #AT91_DDRSDRC_LPR]
 
@@ -328,5 +355,11 @@ ram_restored:
 .saved_sam9_lpr1:
.word 0
 
+.saved_sam9_mdr:
+   .word 0
+
+.saved_sam9_mdr1:
+   .word 0
+
 ENTRY(at91_slow_clock_sz)
.word .-at91_slow_clock
diff --git a/include/soc/at91/at91sam9_ddrsdr.h 
b/include/soc/at91/at91sam9_ddrsdr.h
index 0210797abf2e..cd2c18787833 100644
--- a/include/soc/at91/at91sam9_ddrsdr.h
+++ b/include/soc/at91/at91sam9_ddrsdr.h
@@ -92,7 +92,7 @@
 #defineAT91_DDRSDRC_UPD_MR (3  20)/* Update load 
mode register and extended mode register */
 
 #define AT91_DDRSDRC_MDR   0x20/* Memory Device Register */
-#defineAT91_DDRSDRC_MD (3  0)/* 
Memory Device Type */
+#defineAT91_DDRSDRC_MD (7  0)/* 
Memory Device Type */
 #defineAT91_DDRSDRC_MD_SDR 0
 #defineAT91_DDRSDRC_MD_LOW_POWER_SDR   1
 #defineAT91_DDRSDRC_MD_LOW_POWER_DDR   3
-- 
1.7.10.4

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


NXP Semiconductors TFA9879 Amplifier Driver

2014-11-06 Thread Peter Rosin
Hi!

Sorry for not sending this from my axentia.se account, but I tend to
get high spam-scores from there when I use git send-email.

This is a new driver, and it's pretty minimalistic with support for
only a few basic controls. However, it is usable and I'd be happy
to see it included.

I don't know if it's presumptious to add myself as a maintainer, but
checkpatch complained...

Are the alsa control names wisely chosen?

Please review!

Cheers,
Peter
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 1/2] ASoC: tfa9879: New driver for NXP Semiconductors TFA9879 amplifier.

2014-11-06 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

Signed-off-by: Peter Rosin p...@axentia.se
---
 MAINTAINERS|6 +
 sound/soc/codecs/Kconfig   |5 +
 sound/soc/codecs/Makefile  |2 +
 sound/soc/codecs/tfa9879.c |  334 
 sound/soc/codecs/tfa9879.h |  202 +++
 5 files changed, 549 insertions(+)
 create mode 100644 sound/soc/codecs/tfa9879.c
 create mode 100644 sound/soc/codecs/tfa9879.h

diff --git a/MAINTAINERS b/MAINTAINERS
index f10ed3914ea8..9ca9e68ea9ab 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6467,6 +6467,12 @@ S:   Supported
 F: drivers/gpu/drm/i2c/tda998x_drv.c
 F: include/drm/i2c/tda998x.h
 
+NXP TFA9879 DRIVER
+M: Peter Rosin p...@axentia.se
+L: alsa-de...@alsa-project.org (moderated for non-subscribers)
+S: Maintained
+F: sound/soc/codecs/tfa9879*
+
 OMAP SUPPORT
 M: Tony Lindgren t...@atomide.com
 L: linux-o...@vger.kernel.org
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 8838838e25ed..36bf3f83a333 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -96,6 +96,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
select SND_SOC_TAS2552 if I2C
select SND_SOC_TAS5086 if I2C
+   select SND_SOC_TFA9879 if I2C
select SND_SOC_TLV320AIC23_I2C if I2C
select SND_SOC_TLV320AIC23_SPI if SPI_MASTER
select SND_SOC_TLV320AIC26 if SPI_MASTER
@@ -548,6 +549,10 @@ config SND_SOC_TAS5086
tristate Texas Instruments TAS5086 speaker amplifier
depends on I2C
 
+config SND_SOC_TFA9879
+   tristate NXP Semiconductors TFA9879 amplifier
+   depends on I2C
+
 config SND_SOC_TLV320AIC23
tristate
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 20afe0f0c5be..678a3a6df8a5 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -96,6 +96,7 @@ snd-soc-sta350-objs := sta350.o
 snd-soc-sta529-objs := sta529.o
 snd-soc-stac9766-objs := stac9766.o
 snd-soc-tas5086-objs := tas5086.o
+snd-soc-tfa9879-objs := tfa9879.o
 snd-soc-tlv320aic23-objs := tlv320aic23.o
 snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o
 snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o
@@ -264,6 +265,7 @@ obj-$(CONFIG_SND_SOC_STA529)   += snd-soc-sta529.o
 obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o
 obj-$(CONFIG_SND_SOC_TAS2552)  += snd-soc-tas2552.o
 obj-$(CONFIG_SND_SOC_TAS5086)  += snd-soc-tas5086.o
+obj-$(CONFIG_SND_SOC_TFA9879)  += snd-soc-tfa9879.o
 obj-$(CONFIG_SND_SOC_TLV320AIC23)  += snd-soc-tlv320aic23.o
 obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C)  += snd-soc-tlv320aic23-i2c.o
 obj-$(CONFIG_SND_SOC_TLV320AIC23_SPI)  += snd-soc-tlv320aic23-spi.o
diff --git a/sound/soc/codecs/tfa9879.c b/sound/soc/codecs/tfa9879.c
new file mode 100644
index ..90cc28f7e6ed
--- /dev/null
+++ b/sound/soc/codecs/tfa9879.c
@@ -0,0 +1,334 @@
+/*
+ * tfa9879.c  --  driver for NXP Semiconductors TFA9879
+ *
+ * Copyright (C) 2014 Axentia Technologies AB
+ * Author: Peter Rosin p...@axentia.se
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include linux/module.h
+#include linux/init.h
+#include linux/i2c.h
+#include linux/regmap.h
+#include sound/soc.h
+#include sound/tlv.h
+#include sound/pcm_params.h
+
+#include tfa9879.h
+
+struct tfa9879_priv {
+   struct regmap *regmap;
+   int lsb_justified;
+};
+
+#define TFA9879_REG(codec, reg, field, value)  \
+   snd_soc_update_bits(codec, TFA9879_ ## reg, \
+   TFA9879_ ## field ## _MASK, \
+   (value)  TFA9879_ ## field ## _SHIFT)
+
+static int tfa9879_prepare(struct snd_pcm_substream *substream,
+  struct snd_soc_dai *dai)
+{
+   struct snd_soc_codec *codec = dai-codec;
+
+   TFA9879_REG(codec, DEVICE_CONTROL, POWERUP, 1);
+
+   return 0;
+}
+
+static int tfa9879_hw_params(struct snd_pcm_substream *substream,
+struct snd_pcm_hw_params *params,
+struct snd_soc_dai *dai)
+{
+   struct snd_soc_codec *codec = dai-codec;
+   struct tfa9879_priv *tfa9879 = snd_soc_codec_get_drvdata(codec);
+   int fs;
+   int i2s_set = 0;
+
+   switch (params_rate(params)) {
+   case 8000:
+   fs = TFA9879_I2S_FS_8000;
+   break;
+   case 11025:
+   fs = TFA9879_I2S_FS_11025;
+   break;
+   case 12000:
+   fs = TFA9879_I2S_FS_12000;
+   break;
+   case 16000:
+   fs = TFA9879_I2S_FS_16000;
+   break;
+   case 22050:
+   fs

[PATCH 2/2] ASoC: tfa9879: Add bass and treble gain/freq controls.

2014-11-06 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

Signed-off-by: Peter Rosin p...@axentia.se
---
 sound/soc/codecs/tfa9879.c |   16 
 1 file changed, 16 insertions(+)

diff --git a/sound/soc/codecs/tfa9879.c b/sound/soc/codecs/tfa9879.c
index 90cc28f7e6ed..0d62962542e2 100644
--- a/sound/soc/codecs/tfa9879.c
+++ b/sound/soc/codecs/tfa9879.c
@@ -213,10 +213,26 @@ static bool tfa9879_volatile_register(struct device *dev, 
unsigned int reg)
 }
 
 static const DECLARE_TLV_DB_SCALE(volume_tlv, -7050, 50, 1);
+static const DECLARE_TLV_DB_SCALE(tb_gain_tlv, -1800, 200, 0);
+static const char * const tb_freq_text[] = {
+   Low, Mid, High
+};
+static const struct soc_enum treble_freq_enum =
+   SOC_ENUM_SINGLE(TFA9879_BASS_TREBLE, TFA9879_F_TRBLE_SHIFT,
+   ARRAY_SIZE(tb_freq_text), tb_freq_text);
+static const struct soc_enum bass_freq_enum =
+   SOC_ENUM_SINGLE(TFA9879_BASS_TREBLE, TFA9879_F_BASS_SHIFT,
+   ARRAY_SIZE(tb_freq_text), tb_freq_text);
 
 static const struct snd_kcontrol_new tfa9879_controls[] = {
SOC_SINGLE_TLV(PCM Playback Volume, TFA9879_VOLUME_CONTROL,
   TFA9879_VOL_SHIFT, 0xbd, 1, volume_tlv),
+   SOC_SINGLE_TLV(Treble Gain Volume, TFA9879_BASS_TREBLE,
+  TFA9879_G_TRBLE_SHIFT, 18, 0, tb_gain_tlv),
+   SOC_SINGLE_TLV(Bass Gain Volume, TFA9879_BASS_TREBLE,
+  TFA9879_G_BASS_SHIFT, 18, 0, tb_gain_tlv),
+   SOC_ENUM(Treble Corner Freq, treble_freq_enum),
+   SOC_ENUM(Bass Corner Freq, bass_freq_enum),
 };
 
 static const struct snd_soc_dapm_widget tfa9879_dapm_widgets[] = {
-- 
1.7.10.4

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH] ASoC: Augment existing card DAPM routes in snd_soc_of_parse_audio_routing

2014-11-27 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

If a snd_soc_card has any DAPM routes when it calls
snd_soc_of_parse_audio_routing, those are clobbered without this change.

Signed-off-by: Peter Rosin p...@axentia.se
---
 sound/soc/soc-core.c |   14 +-
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index b60ff56ebc0f..377db486852e 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -4585,7 +4585,7 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card 
*card,
   const char *propname)
 {
struct device_node *np = card-dev-of_node;
-   int num_routes;
+   int num_routes, old_routes;
struct snd_soc_dapm_route *routes;
int i, ret;
 
@@ -4603,7 +4603,9 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card 
*card,
return -EINVAL;
}
 
-   routes = devm_kzalloc(card-dev, num_routes * sizeof(*routes),
+   old_routes = card-num_dapm_routes;
+   routes = devm_kzalloc(card-dev,
+ (old_routes + num_routes) * sizeof(*routes),
  GFP_KERNEL);
if (!routes) {
dev_err(card-dev,
@@ -4611,9 +4613,11 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card 
*card,
return -EINVAL;
}
 
+   memcpy(routes, card-dapm_routes, old_routes * sizeof(*routes));
+
for (i = 0; i  num_routes; i++) {
ret = of_property_read_string_index(np, propname,
-   2 * i, routes[i].sink);
+   2 * i, routes[old_routes + i].sink);
if (ret) {
dev_err(card-dev,
ASoC: Property '%s' index %d could not be 
read: %d\n,
@@ -4621,7 +4625,7 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card 
*card,
return -EINVAL;
}
ret = of_property_read_string_index(np, propname,
-   (2 * i) + 1, routes[i].source);
+   (2 * i) + 1, routes[old_routes + i].source);
if (ret) {
dev_err(card-dev,
ASoC: Property '%s' index %d could not be 
read: %d\n,
@@ -4630,7 +4634,7 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card 
*card,
}
}
 
-   card-num_dapm_routes = num_routes;
+   card-num_dapm_routes += num_routes;
card-dapm_routes = routes;
 
return 0;
-- 
1.7.10.4

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


RE: [PATCH] ASoC: Augment existing card DAPM routes in snd_soc_of_parse_audio_routing

2014-11-28 Thread Peter Rosin
Mark Brown wrote:
 On Thu, Nov 27, 2014 at 10:02:42PM +0100, Peter Rosin wrote:
 
  -   routes = devm_kzalloc(card-dev, num_routes * sizeof(*routes),
  +   old_routes = card-num_dapm_routes;
  +   routes = devm_kzalloc(card-dev,
  + (old_routes + num_routes) * sizeof(*routes),
GFP_KERNEL);
  if (!routes) {
  dev_err(card-dev,
  @@ -4611,9 +4613,11 @@ int snd_soc_of_parse_audio_routing(struct
 snd_soc_card *card,
  return -EINVAL;
  }
 
  +   memcpy(routes, card-dapm_routes, old_routes * sizeof(*routes));
  +
 
 Aren't we open coding krealloc() here?

I don't think krealloc() is appropriate since we don't know where the memory
comes from. The typical use I see is that the card struct is initialized as:

static const struct snd_soc_dapm_route foo_intercon[] = {
{ MUX1, Loop, IN1 },
{ MUX1, Mixer, MIX1 },

{ MIX1, NULL, DAC },
{ MIX1, IN1 Switch, IN1 },

{ Line Out Jack, NULL, MUX1 },
};

static struct snd_soc_card foo_card = {
.name = foo,
.owner = THIS_MODULE,
.dapm_routes = foo_intercon,
.num_dapm_routes = ARRAY_SIZE(foo_intercon),
/* etc */
};

If that's the case, krealloc() seems dead wrong. On the other hand, if
snd_soc_of_parse_audio_routing() were to be called many times, a lot
of devm_kzalloc()ed memory would be kept dangling. I don't expect a card
to call snd_soc_of_parse_audio_routing() more than once though...

Cheers,
Peter

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH] ASoC: pcm512x: Trigger auto-increment of register addresses on i2c

2014-12-08 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

When the codec is connected using i2c, it will only auto-increment
register addresses if msb (0x80) of the register address byte is set.

Signed-off-by: Peter Rosin p...@axentia.se
---
 sound/soc/codecs/pcm512x-i2c.c |7 ++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/sound/soc/codecs/pcm512x-i2c.c b/sound/soc/codecs/pcm512x-i2c.c
index 4d62230bd378..d0547fa275fc 100644
--- a/sound/soc/codecs/pcm512x-i2c.c
+++ b/sound/soc/codecs/pcm512x-i2c.c
@@ -24,8 +24,13 @@ static int pcm512x_i2c_probe(struct i2c_client *i2c,
 const struct i2c_device_id *id)
 {
struct regmap *regmap;
+   struct regmap_config config = pcm512x_regmap;
 
-   regmap = devm_regmap_init_i2c(i2c, pcm512x_regmap);
+   /* msb needs to be set to enable auto-increment of addresses */
+   config.read_flag_mask = 0x80;
+   config.write_flag_mask = 0x80;
+
+   regmap = devm_regmap_init_i2c(i2c, config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
 
-- 
1.7.10.4

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH] ASoC: pcm512x: Also support PCM514x devices

2014-12-09 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

Signed-off-by: Peter Rosin p...@axentia.se
---
 Documentation/devicetree/bindings/sound/pcm512x.txt |3 ++-
 sound/soc/codecs/pcm512x-i2c.c  |4 
 sound/soc/codecs/pcm512x-spi.c  |4 
 3 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/sound/pcm512x.txt 
b/Documentation/devicetree/bindings/sound/pcm512x.txt
index faff75e64573..98e0d34915e8 100644
--- a/Documentation/devicetree/bindings/sound/pcm512x.txt
+++ b/Documentation/devicetree/bindings/sound/pcm512x.txt
@@ -5,7 +5,8 @@ on the board).
 
 Required properties:
 
-  - compatible : One of ti,pcm5121 or ti,pcm5122
+  - compatible : One of ti,pcm5121, ti,pcm5122, ti,pcm5141 or
+ ti,pcm5142
 
   - reg : the I2C address of the device for I2C, the chip select
   number for SPI.
diff --git a/sound/soc/codecs/pcm512x-i2c.c b/sound/soc/codecs/pcm512x-i2c.c
index 4d62230bd378..08047ac952f4 100644
--- a/sound/soc/codecs/pcm512x-i2c.c
+++ b/sound/soc/codecs/pcm512x-i2c.c
@@ -41,6 +41,8 @@ static int pcm512x_i2c_remove(struct i2c_client *i2c)
 static const struct i2c_device_id pcm512x_i2c_id[] = {
{ pcm5121, },
{ pcm5122, },
+   { pcm5141, },
+   { pcm5142, },
{ }
 };
 MODULE_DEVICE_TABLE(i2c, pcm512x_i2c_id);
@@ -48,6 +50,8 @@ MODULE_DEVICE_TABLE(i2c, pcm512x_i2c_id);
 static const struct of_device_id pcm512x_of_match[] = {
{ .compatible = ti,pcm5121, },
{ .compatible = ti,pcm5122, },
+   { .compatible = ti,pcm5141, },
+   { .compatible = ti,pcm5142, },
{ }
 };
 MODULE_DEVICE_TABLE(of, pcm512x_of_match);
diff --git a/sound/soc/codecs/pcm512x-spi.c b/sound/soc/codecs/pcm512x-spi.c
index f297058c0038..7b64a9cef704 100644
--- a/sound/soc/codecs/pcm512x-spi.c
+++ b/sound/soc/codecs/pcm512x-spi.c
@@ -43,6 +43,8 @@ static int pcm512x_spi_remove(struct spi_device *spi)
 static const struct spi_device_id pcm512x_spi_id[] = {
{ pcm5121, },
{ pcm5122, },
+   { pcm5141, },
+   { pcm5142, },
{ },
 };
 MODULE_DEVICE_TABLE(spi, pcm512x_spi_id);
@@ -50,6 +52,8 @@ MODULE_DEVICE_TABLE(spi, pcm512x_spi_id);
 static const struct of_device_id pcm512x_of_match[] = {
{ .compatible = ti,pcm5121, },
{ .compatible = ti,pcm5122, },
+   { .compatible = ti,pcm5141, },
+   { .compatible = ti,pcm5142, },
{ }
 };
 MODULE_DEVICE_TABLE(of, pcm512x_of_match);
-- 
1.7.10.4

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


RE: [PATCH v2 02/12] pm: at91: Workaround DDRSDRC self-refresh bug with LPDDR1 memories.

2015-01-26 Thread Peter Rosin
Sylvain Rochet wrote:
 Hello Nicolas,
 
 On Mon, Jan 26, 2015 at 02:34:38PM +0100, Nicolas Ferre wrote:
  Le 26/01/2015 11:36, Sylvain Rochet a écrit :
  
   I think we should explain we are dealing with an errata here, this
   is not obvious at first sight, the patch summary may find its place
   here :-)
 
  True but the problem is that this errata is not public yet, it will be
  in a couple of weeks.
 
  I have the feeling though that the commit message is pretty clear.
  We'll maybe add that its an actual errata.
 
 Humm, this is not what I meant actually. I only proposed a code source
 comment explaining why this is done this way, the current patch summary
 looked like it will be perfect between /* */ ;-)

I did not want to fill up the source with wordy comments, and settled
for a one-liner. I don't know much about the underlying reasons other
than the fact that LPDDR1 mode of the controller isn't working properly
in self-refresh and that the DDR2 spec is similar enough to work.

The one-liner comment says about the same thing, but not with so
many words. The comment does make it clear that the switch to DDR2
is intentional, and that is all that is needed as protection from some
future cleanup. I mean, anyone seeing that comment and just erasing
the whole thing without further investigation is not doing a very good
job as there is no reason to intentionally switch from LPDDR1 mode to
DDR2 mode, other that the fact that the LPDDR1 mode isn't working for
some reason. That reason is not to be found in the commit message
and I have no information to improve the situation. IMO, the only thing
missing is a pointer to the as yet unreleased errata, which should explain
the situation clearly for any and all interested parties. May I suggest that
someone who cares sends a patch with the comment update when the
errata is released?

If others feel differently, by all means please reword and expand the
comment.

Cheers,
Peter
N�r��yb�X��ǧv�^�)޺{.n�+{zX����ܨ}���Ơz�j:+v���zZ+��+zf���h���~i���z��w���?��)ߢf��^jǫy�m��@A�a���
0��h���i

RE: [PATCH v2] ASoC: atmel_ssc_dai: Allow more rates

2015-02-07 Thread Peter Rosin
Mark Brown wrote:
 On Wed, Feb 04, 2015 at 12:52:25PM +0100, Peter Rosin wrote:
 
  One thing remains a bit unclear, and that is the 500ppm deduction. Is
  that really warranted? The number was just pulled out of my hat...
 
 I don't really get what this is supposed to be protecting against.
 
  +   case SND_SOC_DAIFMT_CBM_CFS:
  +   case SND_SOC_DAIFMT_CBM_CFM:
  +   t.min = 8000;
  +   t.max = ssc_p-mck_rate / mck_div / frame_size;
  +   /* Take away 500ppm, just to be on the safe side. */
  +   t.max -= t.max / 2000;
  +   t.openmin = t.openmax = 0;
  +   t.integer = 0;
  +   ret = snd_interval_refine(i, t);
 
 As I understand it this is a straight divider rather than something that's 
 doing
 dithering or anything else more fancy.  Given that it seems as well just to
 trust the clock rate we've got - we don't do any error tracking with the clock
 API (perhaps we should) and for many applications some degree of
 divergence from the nominal rate is not
 *too* bad for audio systems (for application specific values of some
 and too of course).  If it is just dividers I'm not sure the situation is 
 really
 improved materially by knocking off the top frequency.
 
 If we are doing something more fancy than divididing my analysis is off base
 of course.

I'm thinking that the SSC samples the selected BCK pin using the (possibly
divided) peripheral clock. Getting too near the theoretical rate limit would
be bad, if these two independent clocks drift the wrong way. At least that
is my take on it, but I don't know the internal workings of the SSC, so...

I was hoping that someone from Atmel could chime in? Maybe I'm totally
off base, and the SSC is doing this completely differently?

In our application, we're not near the limit. Therefore, it really doesn't
matter much to us.

Should I resend w/o the 500ppm deduction?

Cheers,
Peter

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v2] ASoC: atmel_ssc_dai: Allow more rates

2015-02-04 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

When the SSC acts as BCK master, use a ratnum rule to limit
the rate instead of only doing the standard rates. When the SSC
acts as BCK slave, allow any BCK frequency up to within 500ppm
of the SSC master clock, possibly divided by 2, 3 or 6.

Put a cap at 384kHz. Who's /ever/ going to need more than that?

The divider of 2, 3 or 6 is selected based on the Serial Clock Ratio
Considerations section from the SSC documentation:

The Transmitter and the Receiver can be programmed to operate
with the clock signals provided on either the TK or RK pins.
This allows the SSC to support many slave-mode data transfers.
In this case, the maximum clock speed allowed on the RK pin is:
- Peripheral clock divided by 2 if Receiver Frame Synchro is input
- Peripheral clock divided by 3 if Receiver Frame Synchro is output
In addition, the maximum clock speed allowed on the TK pin is:
- Peripheral clock divided by 6 if Transmit Frame Synchro is input
- Peripheral clock divided by 2 if Transmit Frame Synchro is output

Signed-off-by: Peter Rosin p...@axentia.se
---
 sound/soc/atmel/atmel_ssc_dai.c |  113 +--
 sound/soc/atmel/atmel_ssc_dai.h |1 +
 2 files changed, 110 insertions(+), 4 deletions(-)

Changes since v1:

- I have checked all Atmel datasheets I could get my hands on (and
  that seemed relevant), and in every instance where they have
  described the SSC, the description have the exact rate limitations
  on the RK and TK pin that I have implemented here.

- Improved the comments.

- Rebased on top of the latest patches from Bo Chen.

One thing remains a bit unclear, and that is the 500ppm deduction. Is
that really warranted? The number was just pulled out of my hat...

Cheers,
Peter

diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
index 379ac2a6ab16..767f65bab25d 100644
--- a/sound/soc/atmel/atmel_ssc_dai.c
+++ b/sound/soc/atmel/atmel_ssc_dai.c
@@ -187,6 +187,96 @@ static irqreturn_t atmel_ssc_interrupt(int irq, void 
*dev_id)
return IRQ_HANDLED;
 }
 
+/*
+ * When the bit clock is input, limit the maximum rate according to the
+ * Serial Clock Ratio Considerations section from the SSC documentation:
+ *
+ *   The Transmitter and the Receiver can be programmed to operate
+ *   with the clock signals provided on either the TK or RK pins.
+ *   This allows the SSC to support many slave-mode data transfers.
+ *   In this case, the maximum clock speed allowed on the RK pin is:
+ *   - Peripheral clock divided by 2 if Receiver Frame Synchro is input
+ *   - Peripheral clock divided by 3 if Receiver Frame Synchro is output
+ *   In addition, the maximum clock speed allowed on the TK pin is:
+ *   - Peripheral clock divided by 6 if Transmit Frame Synchro is input
+ *   - Peripheral clock divided by 2 if Transmit Frame Synchro is output
+ *
+ * When the bit clock is output, limit the rate according to the
+ * SSC divider restrictions.
+ */
+static int atmel_ssc_hw_rule_rate(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+   struct atmel_ssc_info *ssc_p = rule-private;
+   struct ssc_device *ssc = ssc_p-ssc;
+   struct snd_interval *i = hw_param_interval(params, rule-var);
+   struct snd_interval t;
+   struct snd_ratnum r = {
+   .den_min = 1,
+   .den_max = 4095,
+   .den_step = 1,
+   };
+   unsigned int num = 0, den = 0;
+   int frame_size;
+   int mck_div = 2;
+   int ret;
+
+   frame_size = snd_soc_params_to_frame_size(params);
+   if (frame_size  0)
+   return frame_size;
+
+   switch (ssc_p-daifmt  SND_SOC_DAIFMT_MASTER_MASK) {
+   case SND_SOC_DAIFMT_CBM_CFS:
+   if ((ssc_p-dir_mask  SSC_DIR_MASK_CAPTURE)
+ssc-clk_from_rk_pin)
+   /* Receiver Frame Synchro (i.e. capture)
+* is output (format is _CFS) and the RK pin
+* is used for input (format is _CBM_).
+*/
+   mck_div = 3;
+   break;
+
+   case SND_SOC_DAIFMT_CBM_CFM:
+   if ((ssc_p-dir_mask  SSC_DIR_MASK_PLAYBACK)
+!ssc-clk_from_rk_pin)
+   /* Transmit Frame Synchro (i.e. playback)
+* is input (format is _CFM) and the TK pin
+* is used for input (format _CBM_ but not
+* using the RK pin).
+*/
+   mck_div = 6;
+   break;
+   }
+
+   switch (ssc_p-daifmt  SND_SOC_DAIFMT_MASTER_MASK) {
+   case SND_SOC_DAIFMT_CBS_CFS:
+   r.num = ssc_p-mck_rate / mck_div / frame_size;
+
+   ret = snd_interval_ratnum(i, 1, r, num, den);
+   if (ret = 0  den  rule-var == SNDRV_PCM_HW_PARAM_RATE

RE: [PATCH v2] ASoC: atmel_ssc_dai: Allow more rates

2015-02-08 Thread Peter Rosin
Bo Shen wrote:
 Hi Peter,

Hi!

 On 02/07/2015 06:51 PM, Peter Rosin wrote:
  Mark Brown wrote:
  On Wed, Feb 04, 2015 at 12:52:25PM +0100, Peter Rosin wrote:
 
  One thing remains a bit unclear, and that is the 500ppm deduction.
  Is that really warranted? The number was just pulled out of my hat...
 
  I don't really get what this is supposed to be protecting against.
 
  + case SND_SOC_DAIFMT_CBM_CFS:
  + case SND_SOC_DAIFMT_CBM_CFM:
  + t.min = 8000;
  + t.max = ssc_p-mck_rate / mck_div / frame_size;
  + /* Take away 500ppm, just to be on the safe side. */
  + t.max -= t.max / 2000;
  + t.openmin = t.openmax = 0;
  + t.integer = 0;
  + ret = snd_interval_refine(i, t);
 
  As I understand it this is a straight divider rather than something
  that's doing dithering or anything else more fancy.  Given that it
  seems as well just to trust the clock rate we've got - we don't do
  any error tracking with the clock API (perhaps we should) and for
  many applications some degree of divergence from the nominal rate is
  not
  *too* bad for audio systems (for application specific values of some
  and too of course).  If it is just dividers I'm not sure the
  situation is really improved materially by knocking off the top frequency.
 
  If we are doing something more fancy than divididing my analysis is
  off base of course.
 
  I'm thinking that the SSC samples the selected BCK pin using the
  (possibly
  divided) peripheral clock. Getting too near the theoretical rate limit
  would be bad, if these two independent clocks drift the wrong way. At
  least that is my take on it, but I don't know the internal workings of the 
  SSC, so...
 
  I was hoping that someone from Atmel could chime in? Maybe I'm totally
 
 Sorry for late response.

No problem!

  off base, and the SSC is doing this completely differently?
 
 What you mean here? I am not sure I fully understand.

The SSC spec list a maximum rate (which varies with the direction
of various signals, ignoring that for the sake of this explanation). Lets
assume that this maximum rate is 11MHz, derived from the peripheral
clock which might be 66MHz. If you then try to input an 11MHz signal
derived from some unrelated xtal you might think it should work. My
theory was that the rate limit would be broken if the peripheral clock
wasn't really 66MHz, but instead a few ppm lower than nominal, and
the unrelated xtal was a few ppm higher than nominal.

If this matters or not depends on how the SSC is implemented.

There might be other reasons for not caring all that much about
this fringe case, and just trust the nominal rates and limits.

  In our application, we're not near the limit. Therefore, it really
  doesn't matter much to us.
 
  Should I resend w/o the 500ppm deduction?
 
  Cheers,
  Peter
 
 
 Best Regards,
 Bo Shen
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


RE: [PATCH v2] ASoC: atmel_ssc_dai: Allow more rates

2015-02-09 Thread Peter Rosin
Bo Shen wrote:
 Hi Peter,
 
 On 02/09/2015 04:09 PM, Peter Rosin wrote:
 
 [Snip]
 
 
 
  /*-*\
  * DAI functions
  @@ -200,6 +290,7 @@ static int atmel_ssc_startup(struct
 snd_pcm_substream *substream,
struct atmel_ssc_info *ssc_p = ssc_info[dai-id];
struct atmel_pcm_dma_params *dma_params;
int dir, dir_mask;
  + int ret;
 
pr_debug(atmel_ssc_startup: SSC_SR=0x%u\n,
ssc_readl(ssc_p-ssc-regs, SR)); @@ -207,6 +298,7 @@
 static
  int atmel_ssc_startup(struct snd_pcm_substream *substream,
/* Enable PMC peripheral clock for this SSC */
pr_debug(atmel_ssc_dai: Starting clock\n);
clk_enable(ssc_p-ssc-clk);
  + ssc_p-mck_rate = clk_get_rate(ssc_p-ssc-clk) * 2;
 
  Why the mck_rate is calculated in this form?
 
  What did you have in mind? Add another clock to the ssc node in the
  device tree?
 
  IIUC, the device tree (at least normally) has the ssc clk as the
  peripheral clock divided by 2, but the ssc specifies (when capturing
  in the CBM/CFS
  case) the rate limit as the peripheral clock divided by 3 (i.e. ssc clk / 
  1.5).
  Since the SSC spec expresses the rate limit in terms of the peripheral
  clock, this was what I came up with. I didn't want to require dt changes...
 
 You make a misunderstand for the mck for ssc peripheral. The mck here is
 not the system mck, it only related with the ssc, it is the PMC output.
 For example, in device tree, the ssc clock divided by 2, then the pmc output
 for ssc is system mck / 2, so the ssc mck is system mck / 2.
 If divided by 4, then the ssc mck is system / 4

I think the reason for my misunderstanding might be that in the
3.10-at91 tree, the ssc clk is twice the rate compared to what it is
in the 3.18-at91 tree. This made me assume that the ssc clk had
been changed to mean the rate after the fixed divider by two that
is activated as soon as the ssc clock divider (given by SSC_CMR) is
activated, and that it was a simple matter of multiplying by two to
get to the MCK rate. I further assumed that Master Clock in the
Serial Clock Ratio Considerations section was this MCK. Maybe
the mistake was to involve the peripheral clock at all?

Ok, so I may have misunderstood, but in that case what does that
mean in terms of finding the Master Clock rate that is mentioned
in the Serial Clock Ratio Considerations section? Is it perhaps the
rate of the parent clock of the given ssc clk? Or, given the above
explanation, is it correct to simply multiply by two as I have done?

[snip]

Cheers,
Peter
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


RE: [PATCH RESEND] pm: at91: Workaround DDRSDRC self-refresh bug with LPDDR1 memories

2015-01-14 Thread Peter Rosin
Nicolas Ferre wrote:
 Le 14/01/2015 14:20, Peter Rosin a écrit :
  From: Peter Rosin p...@axentia.se
 
  The DDRSDR controller (on the ATSAMA5D31) fails miserably to put
  LPDDR1 memories in self-refresh. Force the controller to think it has
  DDR2 memories during the self-refresh period, as the DDR2 self-refresh
  spec is equivalent to LPDDR1, and is correctly implemented in the
 controller.
 
  Assume that the second controller has the same fault, and that other
  CPUs in the family has the same problem, but that is untested.
 
  Signed-off-by: Peter Rosin p...@axentia.se
 
 I've just verified your code and the scope of this issue and your
 implementation makes perfect sense.
 
 Acked-by: Nicolas Ferre nicolas.fe...@atmel.com
 
 Peter,
 Thanks for your patch. You will probably see it appearing in 3.20 or 3.21.

Great!

 Wenyou,
 Can you please integrate the patch from Peter in your current rework of the
 PM routines (keeping his authorship of course)?
 Please tell me if I can help with this.

To be 100% honest with credits, I should perhaps have mentioned that I
received an unconditional proof-of-concept patch from Atmel support
(Case 7347). I'm not certain who wrote that patch, but the only thing
that has survived is the idea to temporarily use DDR2 mode and the trivial
change of the register field width in the header file. So, I do not feel too
dishonest by claiming authorship...

Cheers,
Peter

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 2/2] ASoC: atmel_ssc_dai: remove clock pin comments

2015-01-19 Thread Peter Rosin
 As the clock can be get from TK/RK pin, so remove the comments.
 
 Signed-off-by: Bo Shen voice.s...@atmel.com
 ---
  sound/soc/atmel/atmel_ssc_dai.c | 4 
  1 file changed, 4 deletions(-)
 diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
 index e691aab..198661b 100644
 --- a/sound/soc/atmel/atmel_ssc_dai.c
 +++ b/sound/soc/atmel/atmel_ssc_dai.c
 @@ -452,10 +452,6 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream 
 *substream,
   case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM:
   /*
* I2S format, CODEC supplies BCLK and LRC clocks.
 -  *
 -  * The SSC transmit clock is obtained from the BCLK signal on
 -  * on the TK line, and the SSC receive clock is
 -  * generated from the transmit clock.
*/
   rcmr =SSC_BF(RCMR_PERIOD, 0)
   | SSC_BF(RCMR_STTDLY, START_DELAY)
 -- 
 2.3.0.rc0

Hi!

You should probably remove that comment from the case with
SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM as well...

Cheers,
Peter

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 0/2] ASoC: pcm512x: Add knobs to allow and control overclocking

2015-02-16 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

Hi!

I wasn't sure if I should add Documentation/* for these sysfs knobs
or not? A lot of knobs do not seem to have docs (no specific example,
just a gut feeling). And I'm not sure how I should name the doc-file
since the pcm512x driver handles devices connected with both i2c and
spi. And what KernelVersion should I enter? That depends... So, this
isn't perfect, suggestions welcome.

The first patch is a preparatory patch that makes 2/2 slightly simpler.
I can fold them together if that's desired. Or I could split 2/2 up in
three logical patches, one for each of the independent PLL/DSP/DAC
knobs.

Another feature that one might want, is that attempts to change the
overclocking should fail with EBUSY when the device is already in use.
But I haven't invested enough time to find out how I should determine
when to fail, so for this version the driver accepts the change but
doesn't enforce the new limit until the clock rates are recalculated.

Cheers,
Peter

Peter Rosin (2):
  ASoC: pcm512x: Rearrange to not repeat dacsrc_rate / dac_div
  ASoC: pcm512x: Allow independently overclocking PLL, DAC and DSP

 Documentation/ABI/testing/sysfs-i2c-pcm512x |   35 +
 sound/soc/codecs/pcm512x.c  |  189 ---
 2 files changed, 205 insertions(+), 19 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-i2c-pcm512x

-- 
1.7.10.4

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 1/2] ASoC: pcm512x: Rearrange to not repeat dacsrc_rate / dac_div

2015-02-16 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

Signed-off-by: Peter Rosin p...@axentia.se
---
 sound/soc/codecs/pcm512x.c |   19 ++-
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index 884784fb1566..f13ff7578c78 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -863,28 +863,29 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai,
dacsrc_rate = sck_rate;
}
 
+   osr_div = DIV_ROUND_CLOSEST(dac_rate, osr_rate);
+   if (osr_div  128) {
+   dev_err(dev, Failed to find OSR divider\n);
+   return -EINVAL;
+   }
+
dac_div = DIV_ROUND_CLOSEST(dacsrc_rate, dac_rate);
if (dac_div  128) {
dev_err(dev, Failed to find DAC divider\n);
return -EINVAL;
}
+   dac_rate = dacsrc_rate / dac_div;
 
-   ncp_div = DIV_ROUND_CLOSEST(dacsrc_rate / dac_div, 1536000);
-   if (ncp_div  128 || dacsrc_rate / dac_div / ncp_div  2048000) {
+   ncp_div = DIV_ROUND_CLOSEST(dac_rate, 1536000);
+   if (ncp_div  128 || dac_rate / ncp_div  2048000) {
/* run NCP no faster than 2048000 Hz, but why? */
-   ncp_div = DIV_ROUND_UP(dacsrc_rate / dac_div, 2048000);
+   ncp_div = DIV_ROUND_UP(dac_rate, 2048000);
if (ncp_div  128) {
dev_err(dev, Failed to find NCP divider\n);
return -EINVAL;
}
}
 
-   osr_div = DIV_ROUND_CLOSEST(dac_rate, osr_rate);
-   if (osr_div  128) {
-   dev_err(dev, Failed to find OSR divider\n);
-   return -EINVAL;
-   }
-
idac = mck_rate / (dsp_div * sample_rate);
 
ret = regmap_write(pcm512x-regmap, PCM512x_DSP_CLKDIV, dsp_div - 1);
-- 
1.7.10.4

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 2/2] ASoC: pcm512x: Allow independently overclocking PLL, DAC and DSP

2015-02-16 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

When using non-standard rates, a relatively small amount of overclocking
can make a big difference to a number of cases.

- Not all rates are possible to achieve with the PLL, due to divider
  restrictions.

- The higher oversampling rates that can be used by the DAC, the
  simpler the analog output filters get (mirror frequencies move up,
  away from the desired spectrum).

- The more work the DSP can perform per sample, the better.

For standard rates, there is little to gain as everything is
designed just right, and the needed overclocking to make a
real difference would be significant.

Signed-off-by: Peter Rosin p...@axentia.se
---
 Documentation/ABI/testing/sysfs-i2c-pcm512x |   35 ++
 sound/soc/codecs/pcm512x.c  |  172 +--
 2 files changed, 196 insertions(+), 11 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-i2c-pcm512x

diff --git a/Documentation/ABI/testing/sysfs-i2c-pcm512x 
b/Documentation/ABI/testing/sysfs-i2c-pcm512x
new file mode 100644
index ..596cd97788db
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-i2c-pcm512x
@@ -0,0 +1,35 @@
+What:  /sys/bus/i2c/devices/busnum-devaddr/overclock_pll
+Date:  February 2015
+Contact:   Peter Rosin p...@axentia.se
+Description:   When the codec acts as clock master, tell the pcm512x
+   to allow overclocking the PLL (as a percentage). Zero
+   disables PLL overclocking.
+
+   Reading: returns the current PLL overclocking setting.
+
+   Writing: set a new PLL overclocking setting.
+   Accepted values: 0..20.
+
+What:  /sys/bus/i2c/devices/busnum-devaddr/overclock_dac
+Date:  February 2015
+Contact:   Peter Rosin p...@axentia.se
+Description:   When the codec acts as clock master, tell the pcm512x
+   to allow overclocking the DAC (as a percentage). Zero
+   disables DAC overclocking.
+
+   Reading: returns the current DAC overclocking setting.
+
+   Writing: set a new DAC overclocking setting.
+   Accepted values: 0..40.
+
+What:  /sys/bus/i2c/devices/busnum-devaddr/overclock_dsp
+Date:  February 2015
+Contact:   Peter Rosin p...@axentia.se
+Description:   When the codec acts as clock master, tell the pcm512x
+   to allow overclocking the DSP (as a percentage). Zero
+   disables DSP overclocking.
+
+   Reading: returns the current DSP overclocking setting.
+
+   Writing: set a new DSP overclocking setting.
+   Accepted values: 0..40.
diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index f13ff7578c78..f4d3dc390aed 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -54,6 +54,9 @@ struct pcm512x_priv {
int pll_d;
int pll_p;
unsigned long real_pll;
+   unsigned long overclock_pll;
+   unsigned long overclock_dac;
+   unsigned long overclock_dsp;
 };
 
 /*
@@ -346,6 +349,132 @@ static const struct snd_soc_dapm_route 
pcm512x_dapm_routes[] = {
{ OUTR, NULL, DACR },
 };
 
+static ssize_t pcm512x_overclock_pll(struct device *dev,
+struct device_attribute *attr, char *buf)
+{
+   struct pcm512x_priv *pcm512x = dev_get_drvdata(dev);
+
+   return sprintf(buf, %lu\n, pcm512x-overclock_pll);
+}
+
+static ssize_t pcm512x_overclock_pll_set(struct device *dev,
+struct device_attribute *attr,
+const char *buf, size_t count)
+{
+   struct pcm512x_priv *pcm512x = dev_get_drvdata(dev);
+   unsigned long value;
+   int ret;
+
+   ret = kstrtoul(buf, 10, value);
+   if (ret)
+   return ret;
+   if (value  20)
+   return -EINVAL;
+   pcm512x-overclock_pll = value;
+
+   return count;
+}
+
+static DEVICE_ATTR(overclock_pll, 0644,
+  pcm512x_overclock_pll, pcm512x_overclock_pll_set);
+
+static ssize_t pcm512x_overclock_dsp(struct device *dev,
+struct device_attribute *attr, char *buf)
+{
+   struct pcm512x_priv *pcm512x = dev_get_drvdata(dev);
+
+   return sprintf(buf, %lu\n, pcm512x-overclock_dsp);
+}
+
+static ssize_t pcm512x_overclock_dsp_set(struct device *dev,
+struct device_attribute *attr,
+const char *buf, size_t count)
+{
+   struct pcm512x_priv *pcm512x = dev_get_drvdata(dev);
+   unsigned long value;
+   int ret;
+
+   ret = kstrtoul(buf, 10, value);
+   if (ret)
+   return ret;
+   if (value  40)
+   return -EINVAL;
+   pcm512x-overclock_dsp = value;
+
+   return count;
+}
+
+static DEVICE_ATTR(overclock_dsp, 0644,
+  pcm512x_overclock_dsp

[PATCH 0/2] ASoC: pcm512x: Add knobs to allow and control overclocking

2015-02-16 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

Hi!

I wasn't sure if I should add Documentation/* for these sysfs knobs
or not? A lot of knobs do not have docs... And I'm not sure how I
should name the doc-file since the pcm512x driver handles devices
connected with both i2c and spi. So, this isn't perfect, suggestions
welcome.

The first patch is a preparatory patch that makes 2/2 slightly simpler.
I can fold them together if that's desired. Or I could split 2/2 up in
three logical pieces, one for each of the independent PLL/DSP/DAC
knob. Whatever...

Cheers,
Peter

Peter Rosin (2):
  ASoC: pcm512x: Rearrange to not repeat dacsrc_rate / dac_div
  ASoC: pcm512x: Allow independently overclocking PLL, DAC and DSP

 Documentation/ABI/testing/sysfs-i2c-pcm512x |   35 +
 sound/soc/codecs/pcm512x.c  |  189 ---
 2 files changed, 205 insertions(+), 19 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-i2c-pcm512x

-- 
1.7.10.4

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 1/7 RESEND] ALSA: pcm: Add snd_interval_ranges() and snd_pcm_hw_constraint_ranges()

2015-01-27 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

Add helper functions to allow drivers to specify several disjoint
ranges for a variable. In particular, there is a codec (PCM512x) that
has a hole in its supported range of rates, due to PLL and divider
restrictions.

This is like snd_pcm_hw_constraint_list(), but for ranges instead of
points.

Signed-off-by: Peter Rosin p...@axentia.se
Reviewed-by: Lars-Peter Clausen l...@metafoo.de
---
 include/sound/pcm.h  |   12 +++
 sound/core/pcm_lib.c |   85 ++
 2 files changed, 97 insertions(+)

diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 1e7f74acc2ec..04fc037e0555 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -275,6 +275,12 @@ struct snd_pcm_hw_constraint_list {
unsigned int mask;
 };
 
+struct snd_pcm_hw_constraint_ranges {
+   unsigned int count;
+   const struct snd_interval *ranges;
+   unsigned int mask;
+};
+
 struct snd_pcm_hwptr_log;
 
 struct snd_pcm_runtime {
@@ -910,6 +916,8 @@ void snd_interval_mulkdiv(const struct snd_interval *a, 
unsigned int k,
  const struct snd_interval *b, struct snd_interval *c);
 int snd_interval_list(struct snd_interval *i, unsigned int count,
  const unsigned int *list, unsigned int mask);
+int snd_interval_ranges(struct snd_interval *i, unsigned int count,
+   const struct snd_interval *list, unsigned int mask);
 int snd_interval_ratnum(struct snd_interval *i,
unsigned int rats_count, struct snd_ratnum *rats,
unsigned int *nump, unsigned int *denp);
@@ -934,6 +942,10 @@ int snd_pcm_hw_constraint_list(struct snd_pcm_runtime 
*runtime,
   unsigned int cond,
   snd_pcm_hw_param_t var,
   const struct snd_pcm_hw_constraint_list *l);
+int snd_pcm_hw_constraint_ranges(struct snd_pcm_runtime *runtime,
+unsigned int cond,
+snd_pcm_hw_param_t var,
+const struct snd_pcm_hw_constraint_ranges *r);
 int snd_pcm_hw_constraint_ratnums(struct snd_pcm_runtime *runtime, 
  unsigned int cond,
  snd_pcm_hw_param_t var,
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index ec9e7866177f..446c00bd908b 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -1015,6 +1015,60 @@ int snd_interval_list(struct snd_interval *i, unsigned 
int count,
 
 EXPORT_SYMBOL(snd_interval_list);
 
+/**
+ * snd_interval_ranges - refine the interval value from the list of ranges
+ * @i: the interval value to refine
+ * @count: the number of elements in the list of ranges
+ * @ranges: the ranges list
+ * @mask: the bit-mask to evaluate
+ *
+ * Refines the interval value from the list of ranges.
+ * When mask is non-zero, only the elements corresponding to bit 1 are
+ * evaluated.
+ *
+ * Return: Positive if the value is changed, zero if it's not changed, or a
+ * negative error code.
+ */
+int snd_interval_ranges(struct snd_interval *i, unsigned int count,
+   const struct snd_interval *ranges, unsigned int mask)
+{
+   unsigned int k;
+   struct snd_interval range_union;
+   struct snd_interval range;
+
+   if (!count) {
+   snd_interval_none(i);
+   return -EINVAL;
+   }
+   snd_interval_any(range_union);
+   range_union.min = UINT_MAX;
+   range_union.max = 0;
+   for (k = 0; k  count; k++) {
+   if (mask  !(mask  (1  k)))
+   continue;
+   snd_interval_copy(range, ranges[k]);
+   if (snd_interval_refine(range, i)  0)
+   continue;
+   if (snd_interval_empty(range))
+   continue;
+
+   if (range.min  range_union.min) {
+   range_union.min = range.min;
+   range_union.openmin = 1;
+   }
+   if (range.min == range_union.min  !range.openmin)
+   range_union.openmin = 0;
+   if (range.max  range_union.max) {
+   range_union.max = range.max;
+   range_union.openmax = 1;
+   }
+   if (range.max == range_union.max  !range.openmax)
+   range_union.openmax = 0;
+   }
+   return snd_interval_refine(i, range_union);
+}
+EXPORT_SYMBOL(snd_interval_ranges);
+
 static int snd_interval_step(struct snd_interval *i, unsigned int step)
 {
unsigned int n;
@@ -1221,6 +1275,37 @@ int snd_pcm_hw_constraint_list(struct snd_pcm_runtime 
*runtime,
 
 EXPORT_SYMBOL(snd_pcm_hw_constraint_list);
 
+static int snd_pcm_hw_rule_ranges(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+   struct

[PATCH 2/7 RESEND] ASoC: pcm512x: Fix spelling of register field names.

2015-01-27 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

Signed-off-by: Peter Rosin p...@axentia.se
---
 sound/soc/codecs/pcm512x.c |2 +-
 sound/soc/codecs/pcm512x.h |6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index e5f2fb884bf3..874723c36d65 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -277,7 +277,7 @@ SOC_ENUM(Auto Mute Time Right, pcm512x_autom_r),
 SOC_SINGLE(Auto Mute Mono Switch, PCM512x_DIGITAL_MUTE_3,
   PCM512x_ACTL_SHIFT, 1, 0),
 SOC_DOUBLE(Auto Mute Switch, PCM512x_DIGITAL_MUTE_3, PCM512x_AMLE_SHIFT,
-  PCM512x_AMLR_SHIFT, 1, 0),
+  PCM512x_AMRE_SHIFT, 1, 0),
 
 SOC_ENUM(Volume Ramp Down Rate, pcm512x_vndf),
 SOC_ENUM(Volume Ramp Down Step, pcm512x_vnds),
diff --git a/sound/soc/codecs/pcm512x.h b/sound/soc/codecs/pcm512x.h
index 6ee76aaca09a..28b3dfd302bc 100644
--- a/sound/soc/codecs/pcm512x.h
+++ b/sound/soc/codecs/pcm512x.h
@@ -108,8 +108,8 @@
 #define PCM512x_RQML_SHIFT 4
 
 /* Page 0, Register 4 - PLL */
-#define PCM512x_PLCE   (1  0)
-#define PCM512x_RLCE_SHIFT 0
+#define PCM512x_PLLE   (1  0)
+#define PCM512x_PLLE_SHIFT 0
 #define PCM512x_PLCK   (1  4)
 #define PCM512x_PLCK_SHIFT 4
 
@@ -152,7 +152,7 @@
 /* Page 0, Register 65 - Digital mute enables */
 #define PCM512x_ACTL_SHIFT 2
 #define PCM512x_AMLE_SHIFT 1
-#define PCM512x_AMLR_SHIFT 0
+#define PCM512x_AMRE_SHIFT 0
 
 /* Page 1, Register 2 - analog volume control */
 #define PCM512x_RAGN_SHIFT 0
-- 
1.7.10.4

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 0/7 RESEND] ASoC: pcm512x: Clock master modes

2015-01-27 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

Hi!

[ Note that the dt change is in patch 5/7, for those only interested
  in that particular bit. ]

This series implements BCLK master modes for the pcm512x driver. It has
only been tested with the pcm5142 chip, but they are from the same family
and should be compatible. I have mainly used the spec for the newer
pcm5242 chip (also from the same family) as it fills in a lot of blanks
in the pcm512x/pcm514x specs.

The code has also seen most of its testing in a 3.10 environment, so
there might be some forward-porting warts. But it is able to play sound
in 3.18 as well, and most of the changes have little to do with anything
but the clocking in the chip itself.

This is technically not a clean resend, since I'm now sending the whole
series to all parties, hopefully using the correct email addesses this
time. I have also augmented the commit message of patch 1/7 according
to the review comments by Lars-Peter Clausen.

Cheers,
Peter

Peter Rosin (7):
  ALSA: pcm: Add snd_interval_ranges() and
snd_pcm_hw_constraint_ranges()
  ASoC: pcm512x: Fix spelling of register field names.
  ASoC: pcm512x: Change register default to match actual content after
reset
  ASoC: pcm512x: Support mastering BCLK/LRCLK without using the PLL
  ASoC: pcm512x: Support mastering BCLK/LRCLK using the PLL
  ASoC: pcm512x: Avoid the PLL for the DAC clock, if possible
  ASoC: pcm512x: Support SND_SOC_DAIFMT_CBM_CFS

 .../devicetree/bindings/sound/pcm512x.txt  |   25 +-
 include/sound/pcm.h|   12 +
 sound/core/pcm_lib.c   |   85 ++
 sound/soc/codecs/pcm512x.c |  955 +++-
 sound/soc/codecs/pcm512x.h |  109 ++-
 5 files changed, 1161 insertions(+), 25 deletions(-)

-- 
1.7.10.4

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 4/7 RESEND] ASoC: pcm512x: Support mastering BCLK/LRCLK without using the PLL

2015-01-27 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

Use register field names from the seemingly compatible PCM5242 datasheet,
as the PCM512x and PCM514x datasheets are severly lacking.

Signed-off-by: Peter Rosin p...@axentia.se
---
 sound/soc/codecs/pcm512x.c |  452 ++--
 sound/soc/codecs/pcm512x.h |   57 +-
 2 files changed, 492 insertions(+), 17 deletions(-)

diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index 4c65eb9ab59b..ac9a0b25b863 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -23,6 +23,7 @@
 #include linux/regulator/consumer.h
 #include sound/soc.h
 #include sound/soc-dapm.h
+#include sound/pcm_params.h
 #include sound/tlv.h
 
 #include pcm512x.h
@@ -39,6 +40,7 @@ struct pcm512x_priv {
struct clk *sclk;
struct regulator_bulk_data supplies[PCM512x_NUM_SUPPLIES];
struct notifier_block supply_nb[PCM512x_NUM_SUPPLIES];
+   int fmt;
 };
 
 /*
@@ -69,6 +71,7 @@ static const struct reg_default pcm512x_reg_defaults[] = {
{ PCM512x_MUTE,  0x00 },
{ PCM512x_DSP,   0x00 },
{ PCM512x_PLL_REF,   0x00 },
+   { PCM512x_DAC_REF,   0x00 },
{ PCM512x_DAC_ROUTING,   0x11 },
{ PCM512x_DSP_PROGRAM,   0x01 },
{ PCM512x_CLKDET,0x00 },
@@ -87,6 +90,18 @@ static const struct reg_default pcm512x_reg_defaults[] = {
{ PCM512x_ANALOG_GAIN_BOOST, 0x00 },
{ PCM512x_VCOM_CTRL_1,   0x00 },
{ PCM512x_VCOM_CTRL_2,   0x01 },
+   { PCM512x_BCLK_LRCLK_CFG,0x00 },
+   { PCM512x_MASTER_MODE,   0x7c },
+   { PCM512x_SYNCHRONIZE,   0x10 },
+   { PCM512x_DSP_CLKDIV,0x00 },
+   { PCM512x_DAC_CLKDIV,0x00 },
+   { PCM512x_NCP_CLKDIV,0x00 },
+   { PCM512x_OSR_CLKDIV,0x00 },
+   { PCM512x_MASTER_CLKDIV_1,   0x00 },
+   { PCM512x_MASTER_CLKDIV_2,   0x00 },
+   { PCM512x_FS_SPEED_MODE, 0x00 },
+   { PCM512x_IDAC_1,0x01 },
+   { PCM512x_IDAC_2,0x00 },
 };
 
 static bool pcm512x_readable(struct device *dev, unsigned int reg)
@@ -103,6 +118,8 @@ static bool pcm512x_readable(struct device *dev, unsigned 
int reg)
case PCM512x_DSP_GPIO_INPUT:
case PCM512x_MASTER_MODE:
case PCM512x_PLL_REF:
+   case PCM512x_DAC_REF:
+   case PCM512x_SYNCHRONIZE:
case PCM512x_PLL_COEFF_0:
case PCM512x_PLL_COEFF_1:
case PCM512x_PLL_COEFF_2:
@@ -303,6 +320,105 @@ static const struct snd_soc_dapm_route 
pcm512x_dapm_routes[] = {
{ OUTR, NULL, DACR },
 };
 
+static const u32 pcm512x_dai_rates[] = {
+   8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000,
+   88200, 96000, 176400, 192000, 384000,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_slave = {
+   .count = ARRAY_SIZE(pcm512x_dai_rates),
+   .list  = pcm512x_dai_rates,
+};
+
+static int pcm512x_params_to_frame_size(struct snd_pcm_hw_params *params)
+{
+   int sample_size;
+
+   sample_size = snd_pcm_format_physical_width(params_format(params));
+   if (sample_size  0)
+   return sample_size;
+
+   return snd_soc_calc_frame_size(sample_size, params_channels(params), 1);
+}
+
+static int pcm512x_dai_startup_master(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+   struct snd_soc_codec *codec = dai-codec;
+   struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+   struct device *dev = dai-dev;
+   struct snd_pcm_hw_constraint_ratnums *constraints_no_pll;
+   struct snd_ratnum *rats_no_pll;
+
+   if (IS_ERR(pcm512x-sclk)) {
+   dev_err(dev, Need SCLK for master mode: %ld\n,
+   PTR_ERR(pcm512x-sclk));
+   return PTR_ERR(pcm512x-sclk);
+   }
+
+   constraints_no_pll = devm_kzalloc(dev, sizeof(*constraints_no_pll),
+ GFP_KERNEL);
+   if (!constraints_no_pll)
+   return -ENOMEM;
+   constraints_no_pll-nrats = 1;
+   rats_no_pll = devm_kzalloc(dev, sizeof(*rats_no_pll), GFP_KERNEL);
+   if (!rats_no_pll)
+   return -ENOMEM;
+   constraints_no_pll-rats = rats_no_pll;
+   rats_no_pll-num = clk_get_rate(pcm512x-sclk) / 64;
+   rats_no_pll-den_min = 1;
+   rats_no_pll-den_max = 128;
+   rats_no_pll-den_step = 1;
+
+   return snd_pcm_hw_constraint_ratnums(substream-runtime, 0,
+SNDRV_PCM_HW_PARAM_RATE,
+constraints_no_pll);
+}
+
+static int pcm512x_dai_startup_slave(struct snd_pcm_substream *substream,
+struct snd_soc_dai *dai)
+{
+   struct snd_soc_codec *codec = dai-codec;
+   struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+   struct device

[PATCH 5/7 RESEND] ASoC: pcm512x: Support mastering BCLK/LRCLK using the PLL

2015-01-27 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

Using the PLL in master mode requires using an external connection
between one of the GPIO pins (configured as PLL/4 output) and the
SCK pin. It also requires the external clock to be fed to some other
GPIO pin instead of the SCK pin.

This is described for the PCM5122 chip in the answers to the forum post
PCM5122 DAC as I2S master troubles with PLL mode at the TI E2E
community pages (1). The clocking functionality is also much better
described in the datasheet for the chip PCM5242, which seems to be
register compatible with PCM512x and PCM514x (which both have severely
lacking datasheets).

(1) http://e2e.ti.com/support/data_converters/audio_converters/f/64/t/267830

Signed-off-by: Peter Rosin p...@axentia.se
---
 .../devicetree/bindings/sound/pcm512x.txt  |   25 +-
 sound/soc/codecs/pcm512x.c |  469 +++-
 sound/soc/codecs/pcm512x.h |   44 +-
 3 files changed, 512 insertions(+), 26 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/pcm512x.txt 
b/Documentation/devicetree/bindings/sound/pcm512x.txt
index 98e0d34915e8..3aae3b41bd8e 100644
--- a/Documentation/devicetree/bindings/sound/pcm512x.txt
+++ b/Documentation/devicetree/bindings/sound/pcm512x.txt
@@ -17,9 +17,16 @@ Required properties:
 Optional properties:
 
   - clocks : A clock specifier for the clock connected as SCLK.  If this
-is absent the device will be configured to clock from BCLK.
+is absent the device will be configured to clock from BCLK.  If pll-in
+and pll-out are specified in addition to a clock, the device is
+configured to accept clock input on a specified gpio pin.
 
-Example:
+  - pll-in, pll-out : gpio pins used to connect the pll using 1
+through 6.  The device will be configured for clock input on the
+given pll-in pin and PLL output on the given pll-out pin.  An
+external connection from the pll-out pin to the SCLK pin is assumed.
+
+Examples:
 
pcm5122: pcm5122@4c {
compatible = ti,pcm5122;
@@ -29,3 +36,17 @@ Example:
DVDD-supply = reg_1v8;
CPVDD-supply = reg_3v3;
};
+
+
+   pcm5142: pcm5142@4c {
+   compatible = ti,pcm5142;
+   reg = 0x4c;
+
+   AVDD-supply = reg_3v3_analog;
+   DVDD-supply = reg_1v8;
+   CPVDD-supply = reg_3v3;
+
+   clocks = sck;
+   pll-in = 3;
+   pll-out = 6;
+   };
diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index ac9a0b25b863..57940ea8b139 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -21,6 +21,7 @@
 #include linux/pm_runtime.h
 #include linux/regmap.h
 #include linux/regulator/consumer.h
+#include linux/gcd.h
 #include sound/soc.h
 #include sound/soc-dapm.h
 #include sound/pcm_params.h
@@ -28,6 +29,11 @@
 
 #include pcm512x.h
 
+#define DIV_ROUND_DOWN_ULL(ll, d) \
+   ({ unsigned long long _tmp = (ll); do_div(_tmp, d); _tmp; })
+#define DIV_ROUND_CLOSEST_ULL(ll, d) \
+   ({ unsigned long long _tmp = (ll)+(d)/2; do_div(_tmp, d); _tmp; })
+
 #define PCM512x_NUM_SUPPLIES 3
 static const char * const pcm512x_supply_names[PCM512x_NUM_SUPPLIES] = {
AVDD,
@@ -41,6 +47,13 @@ struct pcm512x_priv {
struct regulator_bulk_data supplies[PCM512x_NUM_SUPPLIES];
struct notifier_block supply_nb[PCM512x_NUM_SUPPLIES];
int fmt;
+   int pll_in;
+   int pll_out;
+   int pll_r;
+   int pll_j;
+   int pll_d;
+   int pll_p;
+   unsigned long real_pll;
 };
 
 /*
@@ -92,7 +105,13 @@ static const struct reg_default pcm512x_reg_defaults[] = {
{ PCM512x_VCOM_CTRL_2,   0x01 },
{ PCM512x_BCLK_LRCLK_CFG,0x00 },
{ PCM512x_MASTER_MODE,   0x7c },
+   { PCM512x_GPIO_PLLIN,0x00 },
{ PCM512x_SYNCHRONIZE,   0x10 },
+   { PCM512x_PLL_COEFF_0,   0x00 },
+   { PCM512x_PLL_COEFF_1,   0x00 },
+   { PCM512x_PLL_COEFF_2,   0x00 },
+   { PCM512x_PLL_COEFF_3,   0x00 },
+   { PCM512x_PLL_COEFF_4,   0x00 },
{ PCM512x_DSP_CLKDIV,0x00 },
{ PCM512x_DAC_CLKDIV,0x00 },
{ PCM512x_NCP_CLKDIV,0x00 },
@@ -119,6 +138,7 @@ static bool pcm512x_readable(struct device *dev, unsigned 
int reg)
case PCM512x_MASTER_MODE:
case PCM512x_PLL_REF:
case PCM512x_DAC_REF:
+   case PCM512x_GPIO_PLLIN:
case PCM512x_SYNCHRONIZE:
case PCM512x_PLL_COEFF_0:
case PCM512x_PLL_COEFF_1:
@@ -160,6 +180,7 @@ static bool pcm512x_readable(struct device *dev, unsigned 
int reg)
case PCM512x_RATE_DET_2:
case PCM512x_RATE_DET_3:
case PCM512x_RATE_DET_4:
+   case PCM512x_CLOCK_STATUS:
case PCM512x_ANALOG_MUTE_DET:
case PCM512x_GPIN:
case PCM512x_DIGITAL_MUTE_DET:
@@ -171,6 +192,8 @@ static bool pcm512x_readable

[PATCH 7/7 RESEND] ASoC: pcm512x: Support SND_SOC_DAIFMT_CBM_CFS

2015-01-27 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

Signed-off-by: Peter Rosin p...@axentia.se
---
 sound/soc/codecs/pcm512x.c |   13 +++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index 7f45cc468fa1..33aa18c8c88e 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -486,6 +486,7 @@ static int pcm512x_dai_startup(struct snd_pcm_substream 
*substream,
 
switch (pcm512x-fmt  SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
+   case SND_SOC_DAIFMT_CBM_CFS:
return pcm512x_dai_startup_master(substream, dai);
 
case SND_SOC_DAIFMT_CBS_CFS:
@@ -992,6 +993,8 @@ static int pcm512x_hw_params(struct snd_pcm_substream 
*substream,
struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
int alen;
int gpio;
+   int clock_output;
+   int master_mode;
int ret;
 
dev_dbg(codec-dev, hw_params %u Hz, %u channels\n,
@@ -1040,6 +1043,12 @@ static int pcm512x_hw_params(struct snd_pcm_substream 
*substream,
}
return 0;
case SND_SOC_DAIFMT_CBM_CFM:
+   clock_output = PCM512x_BCKO | PCM512x_LRKO;
+   master_mode = PCM512x_RLRK | PCM512x_RBCK;
+   break;
+   case SND_SOC_DAIFMT_CBM_CFS:
+   clock_output = PCM512x_BCKO;
+   master_mode = PCM512x_RBCK;
break;
default:
return -EINVAL;
@@ -1136,7 +1145,7 @@ static int pcm512x_hw_params(struct snd_pcm_substream 
*substream,
 
ret = regmap_update_bits(pcm512x-regmap, PCM512x_BCLK_LRCLK_CFG,
 PCM512x_BCKP | PCM512x_BCKO | PCM512x_LRKO,
-PCM512x_BCKO | PCM512x_LRKO);
+clock_output);
if (ret != 0) {
dev_err(codec-dev, Failed to enable clock output: %d\n, ret);
return ret;
@@ -1144,7 +1153,7 @@ static int pcm512x_hw_params(struct snd_pcm_substream 
*substream,
 
ret = regmap_update_bits(pcm512x-regmap, PCM512x_MASTER_MODE,
 PCM512x_RLRK | PCM512x_RBCK,
-PCM512x_RLRK | PCM512x_RBCK);
+master_mode);
if (ret != 0) {
dev_err(codec-dev, Failed to enable master mode: %d\n, ret);
return ret;
-- 
1.7.10.4

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 6/7 RESEND] ASoC: pcm512x: Avoid the PLL for the DAC clock, if possible

2015-01-27 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

The PLL introduces jitter, which in turn introduces noice if used
to clock the DAC. Thus, avoid the PLL output, and use the PLL input
to drive the DAC clock, if possible.

This is described for the PCM5142/PCM5242 chips in the answers to the
forum post PCM5142/PCM5242 DAC clock source at the TI E2E community
pages (1).

(1) http://e2e.ti.com/support/data_converters/audio_converters/f/64/t/389994

Signed-off-by: Peter Rosin p...@axentia.se
---
 sound/soc/codecs/pcm512x.c |  119 ++--
 sound/soc/codecs/pcm512x.h |4 +-
 2 files changed, 96 insertions(+), 27 deletions(-)

diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index 57940ea8b139..7f45cc468fa1 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -105,6 +105,7 @@ static const struct reg_default pcm512x_reg_defaults[] = {
{ PCM512x_VCOM_CTRL_2,   0x01 },
{ PCM512x_BCLK_LRCLK_CFG,0x00 },
{ PCM512x_MASTER_MODE,   0x7c },
+   { PCM512x_GPIO_DACIN,0x00 },
{ PCM512x_GPIO_PLLIN,0x00 },
{ PCM512x_SYNCHRONIZE,   0x10 },
{ PCM512x_PLL_COEFF_0,   0x00 },
@@ -138,6 +139,7 @@ static bool pcm512x_readable(struct device *dev, unsigned 
int reg)
case PCM512x_MASTER_MODE:
case PCM512x_PLL_REF:
case PCM512x_DAC_REF:
+   case PCM512x_GPIO_DACIN:
case PCM512x_GPIO_PLLIN:
case PCM512x_SYNCHRONIZE:
case PCM512x_PLL_COEFF_0:
@@ -681,6 +683,37 @@ done:
return 0;
 }
 
+static unsigned long pcm512x_pllin_dac_rate(struct snd_soc_dai *dai,
+   unsigned long osr_rate,
+   unsigned long pllin_rate)
+{
+   struct snd_soc_codec *codec = dai-codec;
+   struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+   unsigned long dac_rate;
+
+   if (!pcm512x-pll_out)
+   return 0; /* no PLL to bypass, force SCK as DAC input */
+
+   if (pllin_rate % osr_rate)
+   return 0; /* futile, quit early */
+
+   /* run DAC no faster than 6144000 Hz */
+   for (dac_rate = rounddown(6144000, osr_rate);
+dac_rate;
+dac_rate -= osr_rate) {
+
+   if (pllin_rate / dac_rate  128)
+   return 0; /* DAC divider would be too big */
+
+   if (!(pllin_rate % dac_rate))
+   return dac_rate;
+
+   dac_rate -= osr_rate;
+   }
+
+   return 0;
+}
+
 static int pcm512x_set_dividers(struct snd_soc_dai *dai,
struct snd_pcm_hw_params *params)
 {
@@ -694,6 +727,7 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai,
unsigned long bclk_rate;
unsigned long sample_rate;
unsigned long osr_rate;
+   unsigned long dacsrc_rate;
int bclk_div;
int lrclk_div;
int dsp_div;
@@ -701,11 +735,10 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai,
unsigned long dac_rate;
int ncp_div;
int osr_div;
-   unsigned long dac_mul;
-   unsigned long sck_mul;
int ret;
int idac;
int fssp;
+   int gpio;
 
lrclk_div = pcm512x_params_to_frame_size(params);
if (lrclk_div == 0) {
@@ -794,31 +827,72 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai,
/* run DSP no faster than 50 MHz */
dsp_div = mck_rate  5000 ? 2 : 1;
 
-   /* run DAC no faster than 6144000 Hz */
-   dac_mul = 6144000 / osr_rate;
-   sck_mul = sck_rate / osr_rate;
-   for (; dac_mul; dac_mul--) {
-   if (!(sck_mul % dac_mul))
-   break;
-   }
-   if (!dac_mul) {
-   dev_err(dev, Failed to find DAC rate\n);
-   return -EINVAL;
-   }
+   dac_rate = pcm512x_pllin_dac_rate(dai, osr_rate, pllin_rate);
+   if (dac_rate) {
+   /* the desired clock rate is compatible with the pll input
+* clock, so use that clock as dac input instead of the pll
+* output clock since the pll will introduce jitter and thus
+* noise.
+*/
+   dev_dbg(dev, using pll input as dac input\n);
+   ret = regmap_update_bits(pcm512x-regmap, PCM512x_DAC_REF,
+PCM512x_SDAC, PCM512x_SDAC_GPIO);
+   if (ret != 0) {
+   dev_err(codec-dev,
+   Failed to set gpio as dacref: %d\n, ret);
+   return ret;
+   }
 
-   dac_rate = dac_mul * osr_rate;
-   dev_dbg(dev, dac_rate %lu sample_rate %lu\n, dac_rate, sample_rate);
+   gpio = PCM512x_GREF_GPIO1 + pcm512x-pll_in - 1;
+   ret = regmap_update_bits(pcm512x-regmap, PCM512x_GPIO_DACIN

[PATCH 3/7 RESEND] ASoC: pcm512x: Change register default to match actual content after reset

2015-01-27 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

Signed-off-by: Peter Rosin p...@axentia.se
---
 sound/soc/codecs/pcm512x.c |2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index 874723c36d65..4c65eb9ab59b 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -78,7 +78,7 @@ static const struct reg_default pcm512x_reg_defaults[] = {
{ PCM512x_DIGITAL_VOLUME_2,  0x30 },
{ PCM512x_DIGITAL_VOLUME_3,  0x30 },
{ PCM512x_DIGITAL_MUTE_1,0x22 },
-   { PCM512x_DIGITAL_MUTE_2,0x00 },
+   { PCM512x_DIGITAL_MUTE_2,0x02 },
{ PCM512x_DIGITAL_MUTE_3,0x07 },
{ PCM512x_OUTPUT_AMPLITUDE,  0x00 },
{ PCM512x_ANALOG_GAIN_CTRL,  0x00 },
-- 
1.7.10.4

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


RE: [PATCH v3 03/13] pm: at91: Workaround DDRSDRC self-refresh bug with LPDDR1 memories.

2015-01-27 Thread Peter Rosin
I wrote:
 Sergei Shtylyov wrote:
  On 1/27/2015 8:53 AM, Wenyou Yang wrote:
 
   From: Peter Rosin p...@axentia.se
 
   The DDRSDR controller fails miserably to put LPDDR1 memories in
   self-refresh. Force the controller to think it has DDR2 memories
   during the self-refresh period, as the DDR2 self-refresh spec is
   equivalent to LPDDR1, and is correctly implemented in the controller.
 
   Assume that the second controller has the same fault, but that is
   untested.
 
   Signed-off-by: Peter Rosin p...@axentia.se
   Acked-by: Nicolas Ferre nicolas.fe...@atmel.com
   ---
 arch/arm/mach-at91/pm_slowclock.S  |   43
  +++-
 include/soc/at91/at91sam9_ddrsdr.h |2 +-
 2 files changed, 39 insertions(+), 6 deletions(-)
 
   diff --git a/arch/arm/mach-at91/pm_slowclock.S
   b/arch/arm/mach-at91/pm_slowclock.S
   index e2bfaf5..1155217 100644
   --- a/arch/arm/mach-at91/pm_slowclock.S
   +++ b/arch/arm/mach-at91/pm_slowclock.S
  [...]
   @@ -108,14 +118,26 @@ ddr_sr_enable:
  
 /* figure out if we use the second ram controller */
 cmp ramc1, #0
   - ldrne   tmp2, [ramc1, #AT91_DDRSDRC_LPR]
   - strne   tmp2, .saved_sam9_lpr1
   - bicne   tmp2, #AT91_DDRSDRC_LPCB
   - orrne   tmp2, #AT91_DDRSDRC_LPCB_SELF_REFRESH
   + beq ddr_no_2nd_ctrl
   +
   + ldr tmp2, [ramc1, #AT91_DDRSDRC_MDR]
   + str tmp2, .saved_sam9_mdr1
   + bic tmp2, tmp2, #~AT91_DDRSDRC_MD
   + cmp tmp2, #AT91_DDRSDRC_MD_LOW_POWER_DDR
   + ldreq   tmp2, [ramc1, #AT91_DDRSDRC_MDR]
   + biceq   tmp2, tmp2, #AT91_DDRSDRC_MD
 
  Didn't you forget ~? Either that, or ~ above is not needed, I think.
 
 The code is correct, the first bic with ~ clears bits not in the relevant
 field in order to compare if LPDDR mode is active. The second bic(eq)
 w/o ~ clears the field, to make way for the bits in the below orreq
 when actually changing the register content into DDR2 mode.
 
   + orreq   tmp2, tmp2, #AT91_DDRSDRC_MD_DDR2
   + streq   tmp2, [ramc1, #AT91_DDRSDRC_MDR]
   +
   + ldr tmp2, [ramc1, #AT91_DDRSDRC_LPR]
   + str tmp2, .saved_sam9_lpr1
   + bic tmp2, #AT91_DDRSDRC_LPCB
 
  Didn't you forget ~? And isn't it 3-operand instruction (as seen in the 
  above
  code)?
 
 The logic for the LPR register is from the old code, the only thing
 I did to it was changing the instruction sequence to not have the
 ???ne form, i.e. ldrne, strne, bicne, orrne became ldr, str, bic, orr
 with a jump around it instead. So, the original code also had a two
 argument bic(ne), which indeed is strange, and I don't know why
 there is no warning from the assembler. Since there is no warning,
 my guess is that the assembler somehow mends it? Or does the
 patch actually break the second controller? It would be a surprise
 it the assembler handles 2-operand bicne differently from a

s/it the/if the/

 2-operand bic, no?
 
   + orr tmp2, #AT91_DDRSDRC_LPCB_SELF_REFRESH
 
  Only 2 operands?
 
 Same argument as above. I didn't touch it (sort of...)
 
 Should I update the patch and fix this collateral 2-operand problem as
 well? To me, it feels like a separate patch, no?

I have now checked the assembler output, and apparently it mends the
input, just as I thought. That might be a fluke, of course, or it might be a
deliberate shorthand when the destination register is the same as the
following operand? But I also note that there are more instances of this
2 vs. 3 argument syntax, and I suggest that they are all fixed in one go,
if it is determined that they need fixing. I am obviously not an authority
when it comes to arm assembler syntax, so someone else will have to
advise...

Cheers,
Peter

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


RE: [PATCH v3 03/13] pm: at91: Workaround DDRSDRC self-refresh bug with LPDDR1 memories.

2015-01-27 Thread Peter Rosin
Sergei Shtylyov wrote:
 Hello.

Hi!

 On 1/27/2015 8:53 AM, Wenyou Yang wrote:
 
  From: Peter Rosin p...@axentia.se
 
  The DDRSDR controller fails miserably to put LPDDR1 memories in
  self-refresh. Force the controller to think it has DDR2 memories
  during the self-refresh period, as the DDR2 self-refresh spec is
  equivalent to LPDDR1, and is correctly implemented in the controller.
 
  Assume that the second controller has the same fault, but that is
  untested.
 
  Signed-off-by: Peter Rosin p...@axentia.se
  Acked-by: Nicolas Ferre nicolas.fe...@atmel.com
  ---
arch/arm/mach-at91/pm_slowclock.S  |   43
 +++-
include/soc/at91/at91sam9_ddrsdr.h |2 +-
2 files changed, 39 insertions(+), 6 deletions(-)
 
  diff --git a/arch/arm/mach-at91/pm_slowclock.S
  b/arch/arm/mach-at91/pm_slowclock.S
  index e2bfaf5..1155217 100644
  --- a/arch/arm/mach-at91/pm_slowclock.S
  +++ b/arch/arm/mach-at91/pm_slowclock.S
 [...]
  @@ -108,14 +118,26 @@ ddr_sr_enable:
 
  /* figure out if we use the second ram controller */
  cmp ramc1, #0
  -   ldrne   tmp2, [ramc1, #AT91_DDRSDRC_LPR]
  -   strne   tmp2, .saved_sam9_lpr1
  -   bicne   tmp2, #AT91_DDRSDRC_LPCB
  -   orrne   tmp2, #AT91_DDRSDRC_LPCB_SELF_REFRESH
  +   beq ddr_no_2nd_ctrl
  +
  +   ldr tmp2, [ramc1, #AT91_DDRSDRC_MDR]
  +   str tmp2, .saved_sam9_mdr1
  +   bic tmp2, tmp2, #~AT91_DDRSDRC_MD
  +   cmp tmp2, #AT91_DDRSDRC_MD_LOW_POWER_DDR
  +   ldreq   tmp2, [ramc1, #AT91_DDRSDRC_MDR]
  +   biceq   tmp2, tmp2, #AT91_DDRSDRC_MD
 
 Didn't you forget ~? Either that, or ~ above is not needed, I think.

The code is correct, the first bic with ~ clears bits not in the relevant
field in order to compare if LPDDR mode is active. The second bic(eq)
w/o ~ clears the field, to make way for the bits in the below orreq
when actually changing the register content into DDR2 mode.

  +   orreq   tmp2, tmp2, #AT91_DDRSDRC_MD_DDR2
  +   streq   tmp2, [ramc1, #AT91_DDRSDRC_MDR]
  +
  +   ldr tmp2, [ramc1, #AT91_DDRSDRC_LPR]
  +   str tmp2, .saved_sam9_lpr1
  +   bic tmp2, #AT91_DDRSDRC_LPCB
 
 Didn't you forget ~? And isn't it 3-operand instruction (as seen in the 
 above
 code)?

The logic for the LPR register is from the old code, the only thing
I did to it was changing the instruction sequence to not have the
???ne form, i.e. ldrne, strne, bicne, orrne became ldr, str, bic, orr
with a jump around it instead. So, the original code also had a two
argument bic(ne), which indeed is strange, and I don't know why
there is no warning from the assembler. Since there is no warning,
my guess is that the assembler somehow mends it? Or does the
patch actually break the second controller? It would be a surprise
it the assembler handles 2-operand bicne differently from a
2-operand bic, no?

  +   orr tmp2, #AT91_DDRSDRC_LPCB_SELF_REFRESH
 
 Only 2 operands?

Same argument as above. I didn't touch it (sort of...)

Should I update the patch and fix this collateral 2-operand problem as
well? To me, it feels like a separate patch, no?

 [...]
 
 WBR, Sergei

Cheers,
Peter
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


RE: [PATCH v2 3/7] ASoC: pcm512x: Change register default to match actual content after reset

2015-01-28 Thread Peter Rosin
Hi Mark,

First of all, thanks for taking the rest of the series!

Mark Brown wrote:
 On Wed, Jan 28, 2015 at 03:16:08PM +0100, Peter Rosin wrote:
 
  @@ -78,7 +78,7 @@ static const struct reg_default
 pcm512x_reg_defaults[] = {
  { PCM512x_DIGITAL_VOLUME_2,  0x30 },
  { PCM512x_DIGITAL_VOLUME_3,  0x30 },
  { PCM512x_DIGITAL_MUTE_1,0x22 },
  -   { PCM512x_DIGITAL_MUTE_2,0x00 },
  +   { PCM512x_DIGITAL_MUTE_2,0x02 },
 
 The datasheet claims these have undefined values as reserved bits - what
 would be a more robust change here would be to remove the register
 default entirely so that we take the value the hardware has, giving
 robustness against any hardware revisions.  Of course the device has rather a
 lot of such reserved bits which is unfortunate.

Given the incompleteness of the datasheets this might be safest; a lot
of the reserved areas appear to have undocumented functions. But it
works as is of course, so it is not high priority... I don't know what happens
when this particular bit is cleared, but it doesn't change anything for the
pcm5142 that I am able to detect. So, no real problem with dropping 3/7.

Cheers,
Peter

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v2 0/7] ASoC: pcm512x: Clock master modes

2015-01-28 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

Hi!

[ Note that the dt change is in patch 5/7, for those only interested
  in that particular bit. ]

This series implements BCLK master modes for the pcm512x driver. It has
only been tested with the pcm5142 chip, but they are from the same family
and should be compatible. I have mainly used the spec for the newer
pcm5242 chip (also from the same family) as it fills in a lot of blanks
in the pcm512x/pcm514x specs.

The code has also seen most of its testing in a 3.10 environment, so
there might be some forward-porting warts. But it is able to play sound
in 3.18 as well, and most of the changes have little to do with anything
but the clocking in the chip itself.

Changes since v1:
- Use snd_soc_params_to_frame_size and snd_soc_params_to_bclk instead of
  implementing home-grown versions based on the physical width. The
  I2S-communication will no longer have padding bits for S24_LE.

Cheers,
Peter

Peter Rosin (7):
  ALSA: pcm: Add snd_interval_ranges() and
snd_pcm_hw_constraint_ranges()
  ASoC: pcm512x: Fix spelling of register field names.
  ASoC: pcm512x: Change register default to match actual content after
reset
  ASoC: pcm512x: Support mastering BCLK/LRCLK without using the PLL
  ASoC: pcm512x: Support mastering BCLK/LRCLK using the PLL
  ASoC: pcm512x: Avoid the PLL for the DAC clock, if possible
  ASoC: pcm512x: Support SND_SOC_DAIFMT_CBM_CFS

 .../devicetree/bindings/sound/pcm512x.txt  |   25 +-
 include/sound/pcm.h|   12 +
 sound/core/pcm_lib.c   |   85 ++
 sound/soc/codecs/pcm512x.c |  933 +++-
 sound/soc/codecs/pcm512x.h |  109 ++-
 5 files changed, 1139 insertions(+), 25 deletions(-)

-- 
1.7.10.4

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v2 1/7] ALSA: pcm: Add snd_interval_ranges() and snd_pcm_hw_constraint_ranges()

2015-01-28 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

Add helper functions to allow drivers to specify several disjoint
ranges for a variable. In particular, there is a codec (PCM512x) that
has a hole in its supported range of rates, due to PLL and divider
restrictions.

This is like snd_pcm_hw_constraint_list(), but for ranges instead of
points.

Signed-off-by: Peter Rosin p...@axentia.se
Reviewed-by: Lars-Peter Clausen l...@metafoo.de
---
 include/sound/pcm.h  |   12 +++
 sound/core/pcm_lib.c |   85 ++
 2 files changed, 97 insertions(+)

diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 1e7f74acc2ec..04fc037e0555 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -275,6 +275,12 @@ struct snd_pcm_hw_constraint_list {
unsigned int mask;
 };
 
+struct snd_pcm_hw_constraint_ranges {
+   unsigned int count;
+   const struct snd_interval *ranges;
+   unsigned int mask;
+};
+
 struct snd_pcm_hwptr_log;
 
 struct snd_pcm_runtime {
@@ -910,6 +916,8 @@ void snd_interval_mulkdiv(const struct snd_interval *a, 
unsigned int k,
  const struct snd_interval *b, struct snd_interval *c);
 int snd_interval_list(struct snd_interval *i, unsigned int count,
  const unsigned int *list, unsigned int mask);
+int snd_interval_ranges(struct snd_interval *i, unsigned int count,
+   const struct snd_interval *list, unsigned int mask);
 int snd_interval_ratnum(struct snd_interval *i,
unsigned int rats_count, struct snd_ratnum *rats,
unsigned int *nump, unsigned int *denp);
@@ -934,6 +942,10 @@ int snd_pcm_hw_constraint_list(struct snd_pcm_runtime 
*runtime,
   unsigned int cond,
   snd_pcm_hw_param_t var,
   const struct snd_pcm_hw_constraint_list *l);
+int snd_pcm_hw_constraint_ranges(struct snd_pcm_runtime *runtime,
+unsigned int cond,
+snd_pcm_hw_param_t var,
+const struct snd_pcm_hw_constraint_ranges *r);
 int snd_pcm_hw_constraint_ratnums(struct snd_pcm_runtime *runtime, 
  unsigned int cond,
  snd_pcm_hw_param_t var,
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index ec9e7866177f..446c00bd908b 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -1015,6 +1015,60 @@ int snd_interval_list(struct snd_interval *i, unsigned 
int count,
 
 EXPORT_SYMBOL(snd_interval_list);
 
+/**
+ * snd_interval_ranges - refine the interval value from the list of ranges
+ * @i: the interval value to refine
+ * @count: the number of elements in the list of ranges
+ * @ranges: the ranges list
+ * @mask: the bit-mask to evaluate
+ *
+ * Refines the interval value from the list of ranges.
+ * When mask is non-zero, only the elements corresponding to bit 1 are
+ * evaluated.
+ *
+ * Return: Positive if the value is changed, zero if it's not changed, or a
+ * negative error code.
+ */
+int snd_interval_ranges(struct snd_interval *i, unsigned int count,
+   const struct snd_interval *ranges, unsigned int mask)
+{
+   unsigned int k;
+   struct snd_interval range_union;
+   struct snd_interval range;
+
+   if (!count) {
+   snd_interval_none(i);
+   return -EINVAL;
+   }
+   snd_interval_any(range_union);
+   range_union.min = UINT_MAX;
+   range_union.max = 0;
+   for (k = 0; k  count; k++) {
+   if (mask  !(mask  (1  k)))
+   continue;
+   snd_interval_copy(range, ranges[k]);
+   if (snd_interval_refine(range, i)  0)
+   continue;
+   if (snd_interval_empty(range))
+   continue;
+
+   if (range.min  range_union.min) {
+   range_union.min = range.min;
+   range_union.openmin = 1;
+   }
+   if (range.min == range_union.min  !range.openmin)
+   range_union.openmin = 0;
+   if (range.max  range_union.max) {
+   range_union.max = range.max;
+   range_union.openmax = 1;
+   }
+   if (range.max == range_union.max  !range.openmax)
+   range_union.openmax = 0;
+   }
+   return snd_interval_refine(i, range_union);
+}
+EXPORT_SYMBOL(snd_interval_ranges);
+
 static int snd_interval_step(struct snd_interval *i, unsigned int step)
 {
unsigned int n;
@@ -1221,6 +1275,37 @@ int snd_pcm_hw_constraint_list(struct snd_pcm_runtime 
*runtime,
 
 EXPORT_SYMBOL(snd_pcm_hw_constraint_list);
 
+static int snd_pcm_hw_rule_ranges(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+   struct

[PATCH v2 6/7] ASoC: pcm512x: Avoid the PLL for the DAC clock, if possible

2015-01-28 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

The PLL introduces jitter, which in turn introduces noice if used
to clock the DAC. Thus, avoid the PLL output, and use the PLL input
to drive the DAC clock, if possible.

This is described for the PCM5142/PCM5242 chips in the answers to the
forum post PCM5142/PCM5242 DAC clock source at the TI E2E community
pages (1).

(1) http://e2e.ti.com/support/data_converters/audio_converters/f/64/t/389994

Signed-off-by: Peter Rosin p...@axentia.se
---
 sound/soc/codecs/pcm512x.c |  119 ++--
 sound/soc/codecs/pcm512x.h |4 +-
 2 files changed, 96 insertions(+), 27 deletions(-)

diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index f0c7ec2a2f31..d46d6cdb6b87 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -105,6 +105,7 @@ static const struct reg_default pcm512x_reg_defaults[] = {
{ PCM512x_VCOM_CTRL_2,   0x01 },
{ PCM512x_BCLK_LRCLK_CFG,0x00 },
{ PCM512x_MASTER_MODE,   0x7c },
+   { PCM512x_GPIO_DACIN,0x00 },
{ PCM512x_GPIO_PLLIN,0x00 },
{ PCM512x_SYNCHRONIZE,   0x10 },
{ PCM512x_PLL_COEFF_0,   0x00 },
@@ -138,6 +139,7 @@ static bool pcm512x_readable(struct device *dev, unsigned 
int reg)
case PCM512x_MASTER_MODE:
case PCM512x_PLL_REF:
case PCM512x_DAC_REF:
+   case PCM512x_GPIO_DACIN:
case PCM512x_GPIO_PLLIN:
case PCM512x_SYNCHRONIZE:
case PCM512x_PLL_COEFF_0:
@@ -659,6 +661,37 @@ done:
return 0;
 }
 
+static unsigned long pcm512x_pllin_dac_rate(struct snd_soc_dai *dai,
+   unsigned long osr_rate,
+   unsigned long pllin_rate)
+{
+   struct snd_soc_codec *codec = dai-codec;
+   struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+   unsigned long dac_rate;
+
+   if (!pcm512x-pll_out)
+   return 0; /* no PLL to bypass, force SCK as DAC input */
+
+   if (pllin_rate % osr_rate)
+   return 0; /* futile, quit early */
+
+   /* run DAC no faster than 6144000 Hz */
+   for (dac_rate = rounddown(6144000, osr_rate);
+dac_rate;
+dac_rate -= osr_rate) {
+
+   if (pllin_rate / dac_rate  128)
+   return 0; /* DAC divider would be too big */
+
+   if (!(pllin_rate % dac_rate))
+   return dac_rate;
+
+   dac_rate -= osr_rate;
+   }
+
+   return 0;
+}
+
 static int pcm512x_set_dividers(struct snd_soc_dai *dai,
struct snd_pcm_hw_params *params)
 {
@@ -672,6 +705,7 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai,
unsigned long bclk_rate;
unsigned long sample_rate;
unsigned long osr_rate;
+   unsigned long dacsrc_rate;
int bclk_div;
int lrclk_div;
int dsp_div;
@@ -679,11 +713,10 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai,
unsigned long dac_rate;
int ncp_div;
int osr_div;
-   unsigned long dac_mul;
-   unsigned long sck_mul;
int ret;
int idac;
int fssp;
+   int gpio;
 
lrclk_div = snd_soc_params_to_frame_size(params);
if (lrclk_div == 0) {
@@ -772,31 +805,72 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai,
/* run DSP no faster than 50 MHz */
dsp_div = mck_rate  5000 ? 2 : 1;
 
-   /* run DAC no faster than 6144000 Hz */
-   dac_mul = 6144000 / osr_rate;
-   sck_mul = sck_rate / osr_rate;
-   for (; dac_mul; dac_mul--) {
-   if (!(sck_mul % dac_mul))
-   break;
-   }
-   if (!dac_mul) {
-   dev_err(dev, Failed to find DAC rate\n);
-   return -EINVAL;
-   }
+   dac_rate = pcm512x_pllin_dac_rate(dai, osr_rate, pllin_rate);
+   if (dac_rate) {
+   /* the desired clock rate is compatible with the pll input
+* clock, so use that clock as dac input instead of the pll
+* output clock since the pll will introduce jitter and thus
+* noise.
+*/
+   dev_dbg(dev, using pll input as dac input\n);
+   ret = regmap_update_bits(pcm512x-regmap, PCM512x_DAC_REF,
+PCM512x_SDAC, PCM512x_SDAC_GPIO);
+   if (ret != 0) {
+   dev_err(codec-dev,
+   Failed to set gpio as dacref: %d\n, ret);
+   return ret;
+   }
 
-   dac_rate = dac_mul * osr_rate;
-   dev_dbg(dev, dac_rate %lu sample_rate %lu\n, dac_rate, sample_rate);
+   gpio = PCM512x_GREF_GPIO1 + pcm512x-pll_in - 1;
+   ret = regmap_update_bits(pcm512x-regmap, PCM512x_GPIO_DACIN

[PATCH v2 3/7] ASoC: pcm512x: Change register default to match actual content after reset

2015-01-28 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

Signed-off-by: Peter Rosin p...@axentia.se
---
 sound/soc/codecs/pcm512x.c |2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index 874723c36d65..4c65eb9ab59b 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -78,7 +78,7 @@ static const struct reg_default pcm512x_reg_defaults[] = {
{ PCM512x_DIGITAL_VOLUME_2,  0x30 },
{ PCM512x_DIGITAL_VOLUME_3,  0x30 },
{ PCM512x_DIGITAL_MUTE_1,0x22 },
-   { PCM512x_DIGITAL_MUTE_2,0x00 },
+   { PCM512x_DIGITAL_MUTE_2,0x02 },
{ PCM512x_DIGITAL_MUTE_3,0x07 },
{ PCM512x_OUTPUT_AMPLITUDE,  0x00 },
{ PCM512x_ANALOG_GAIN_CTRL,  0x00 },
-- 
1.7.10.4

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v2 5/7] ASoC: pcm512x: Support mastering BCLK/LRCLK using the PLL

2015-01-28 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

Using the PLL in master mode requires using an external connection
between one of the GPIO pins (configured as PLL/4 output) and the
SCK pin. It also requires the external clock to be fed to some other
GPIO pin instead of the SCK pin.

This is described for the PCM5122 chip in the answers to the forum post
PCM5122 DAC as I2S master troubles with PLL mode at the TI E2E
community pages (1). The clocking functionality is also much better
described in the datasheet for the chip PCM5242, which seems to be
register compatible with PCM512x and PCM514x (which both have severely
lacking datasheets).

(1) http://e2e.ti.com/support/data_converters/audio_converters/f/64/t/267830

Signed-off-by: Peter Rosin p...@axentia.se
---
 .../devicetree/bindings/sound/pcm512x.txt  |   25 +-
 sound/soc/codecs/pcm512x.c |  458 +++-
 sound/soc/codecs/pcm512x.h |   44 +-
 3 files changed, 501 insertions(+), 26 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/pcm512x.txt 
b/Documentation/devicetree/bindings/sound/pcm512x.txt
index 98e0d34915e8..3aae3b41bd8e 100644
--- a/Documentation/devicetree/bindings/sound/pcm512x.txt
+++ b/Documentation/devicetree/bindings/sound/pcm512x.txt
@@ -17,9 +17,16 @@ Required properties:
 Optional properties:
 
   - clocks : A clock specifier for the clock connected as SCLK.  If this
-is absent the device will be configured to clock from BCLK.
+is absent the device will be configured to clock from BCLK.  If pll-in
+and pll-out are specified in addition to a clock, the device is
+configured to accept clock input on a specified gpio pin.
 
-Example:
+  - pll-in, pll-out : gpio pins used to connect the pll using 1
+through 6.  The device will be configured for clock input on the
+given pll-in pin and PLL output on the given pll-out pin.  An
+external connection from the pll-out pin to the SCLK pin is assumed.
+
+Examples:
 
pcm5122: pcm5122@4c {
compatible = ti,pcm5122;
@@ -29,3 +36,17 @@ Example:
DVDD-supply = reg_1v8;
CPVDD-supply = reg_3v3;
};
+
+
+   pcm5142: pcm5142@4c {
+   compatible = ti,pcm5142;
+   reg = 0x4c;
+
+   AVDD-supply = reg_3v3_analog;
+   DVDD-supply = reg_1v8;
+   CPVDD-supply = reg_3v3;
+
+   clocks = sck;
+   pll-in = 3;
+   pll-out = 6;
+   };
diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index 124388809d48..f0c7ec2a2f31 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -21,6 +21,7 @@
 #include linux/pm_runtime.h
 #include linux/regmap.h
 #include linux/regulator/consumer.h
+#include linux/gcd.h
 #include sound/soc.h
 #include sound/soc-dapm.h
 #include sound/pcm_params.h
@@ -28,6 +29,11 @@
 
 #include pcm512x.h
 
+#define DIV_ROUND_DOWN_ULL(ll, d) \
+   ({ unsigned long long _tmp = (ll); do_div(_tmp, d); _tmp; })
+#define DIV_ROUND_CLOSEST_ULL(ll, d) \
+   ({ unsigned long long _tmp = (ll)+(d)/2; do_div(_tmp, d); _tmp; })
+
 #define PCM512x_NUM_SUPPLIES 3
 static const char * const pcm512x_supply_names[PCM512x_NUM_SUPPLIES] = {
AVDD,
@@ -41,6 +47,13 @@ struct pcm512x_priv {
struct regulator_bulk_data supplies[PCM512x_NUM_SUPPLIES];
struct notifier_block supply_nb[PCM512x_NUM_SUPPLIES];
int fmt;
+   int pll_in;
+   int pll_out;
+   int pll_r;
+   int pll_j;
+   int pll_d;
+   int pll_p;
+   unsigned long real_pll;
 };
 
 /*
@@ -92,7 +105,13 @@ static const struct reg_default pcm512x_reg_defaults[] = {
{ PCM512x_VCOM_CTRL_2,   0x01 },
{ PCM512x_BCLK_LRCLK_CFG,0x00 },
{ PCM512x_MASTER_MODE,   0x7c },
+   { PCM512x_GPIO_PLLIN,0x00 },
{ PCM512x_SYNCHRONIZE,   0x10 },
+   { PCM512x_PLL_COEFF_0,   0x00 },
+   { PCM512x_PLL_COEFF_1,   0x00 },
+   { PCM512x_PLL_COEFF_2,   0x00 },
+   { PCM512x_PLL_COEFF_3,   0x00 },
+   { PCM512x_PLL_COEFF_4,   0x00 },
{ PCM512x_DSP_CLKDIV,0x00 },
{ PCM512x_DAC_CLKDIV,0x00 },
{ PCM512x_NCP_CLKDIV,0x00 },
@@ -119,6 +138,7 @@ static bool pcm512x_readable(struct device *dev, unsigned 
int reg)
case PCM512x_MASTER_MODE:
case PCM512x_PLL_REF:
case PCM512x_DAC_REF:
+   case PCM512x_GPIO_PLLIN:
case PCM512x_SYNCHRONIZE:
case PCM512x_PLL_COEFF_0:
case PCM512x_PLL_COEFF_1:
@@ -160,6 +180,7 @@ static bool pcm512x_readable(struct device *dev, unsigned 
int reg)
case PCM512x_RATE_DET_2:
case PCM512x_RATE_DET_3:
case PCM512x_RATE_DET_4:
+   case PCM512x_CLOCK_STATUS:
case PCM512x_ANALOG_MUTE_DET:
case PCM512x_GPIN:
case PCM512x_DIGITAL_MUTE_DET:
@@ -171,6 +192,8 @@ static bool pcm512x_readable

[PATCH v2 7/7] ASoC: pcm512x: Support SND_SOC_DAIFMT_CBM_CFS

2015-01-28 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

Signed-off-by: Peter Rosin p...@axentia.se
---
 sound/soc/codecs/pcm512x.c |   13 +++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index d46d6cdb6b87..64be85fb2748 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -464,6 +464,7 @@ static int pcm512x_dai_startup(struct snd_pcm_substream 
*substream,
 
switch (pcm512x-fmt  SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
+   case SND_SOC_DAIFMT_CBM_CFS:
return pcm512x_dai_startup_master(substream, dai);
 
case SND_SOC_DAIFMT_CBS_CFS:
@@ -970,6 +971,8 @@ static int pcm512x_hw_params(struct snd_pcm_substream 
*substream,
struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
int alen;
int gpio;
+   int clock_output;
+   int master_mode;
int ret;
 
dev_dbg(codec-dev, hw_params %u Hz, %u channels\n,
@@ -1018,6 +1021,12 @@ static int pcm512x_hw_params(struct snd_pcm_substream 
*substream,
}
return 0;
case SND_SOC_DAIFMT_CBM_CFM:
+   clock_output = PCM512x_BCKO | PCM512x_LRKO;
+   master_mode = PCM512x_RLRK | PCM512x_RBCK;
+   break;
+   case SND_SOC_DAIFMT_CBM_CFS:
+   clock_output = PCM512x_BCKO;
+   master_mode = PCM512x_RBCK;
break;
default:
return -EINVAL;
@@ -1114,7 +1123,7 @@ static int pcm512x_hw_params(struct snd_pcm_substream 
*substream,
 
ret = regmap_update_bits(pcm512x-regmap, PCM512x_BCLK_LRCLK_CFG,
 PCM512x_BCKP | PCM512x_BCKO | PCM512x_LRKO,
-PCM512x_BCKO | PCM512x_LRKO);
+clock_output);
if (ret != 0) {
dev_err(codec-dev, Failed to enable clock output: %d\n, ret);
return ret;
@@ -1122,7 +1131,7 @@ static int pcm512x_hw_params(struct snd_pcm_substream 
*substream,
 
ret = regmap_update_bits(pcm512x-regmap, PCM512x_MASTER_MODE,
 PCM512x_RLRK | PCM512x_RBCK,
-PCM512x_RLRK | PCM512x_RBCK);
+master_mode);
if (ret != 0) {
dev_err(codec-dev, Failed to enable master mode: %d\n, ret);
return ret;
-- 
1.7.10.4

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v2 2/7] ASoC: pcm512x: Fix spelling of register field names.

2015-01-28 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

Signed-off-by: Peter Rosin p...@axentia.se
---
 sound/soc/codecs/pcm512x.c |2 +-
 sound/soc/codecs/pcm512x.h |6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index e5f2fb884bf3..874723c36d65 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -277,7 +277,7 @@ SOC_ENUM(Auto Mute Time Right, pcm512x_autom_r),
 SOC_SINGLE(Auto Mute Mono Switch, PCM512x_DIGITAL_MUTE_3,
   PCM512x_ACTL_SHIFT, 1, 0),
 SOC_DOUBLE(Auto Mute Switch, PCM512x_DIGITAL_MUTE_3, PCM512x_AMLE_SHIFT,
-  PCM512x_AMLR_SHIFT, 1, 0),
+  PCM512x_AMRE_SHIFT, 1, 0),
 
 SOC_ENUM(Volume Ramp Down Rate, pcm512x_vndf),
 SOC_ENUM(Volume Ramp Down Step, pcm512x_vnds),
diff --git a/sound/soc/codecs/pcm512x.h b/sound/soc/codecs/pcm512x.h
index 6ee76aaca09a..28b3dfd302bc 100644
--- a/sound/soc/codecs/pcm512x.h
+++ b/sound/soc/codecs/pcm512x.h
@@ -108,8 +108,8 @@
 #define PCM512x_RQML_SHIFT 4
 
 /* Page 0, Register 4 - PLL */
-#define PCM512x_PLCE   (1  0)
-#define PCM512x_RLCE_SHIFT 0
+#define PCM512x_PLLE   (1  0)
+#define PCM512x_PLLE_SHIFT 0
 #define PCM512x_PLCK   (1  4)
 #define PCM512x_PLCK_SHIFT 4
 
@@ -152,7 +152,7 @@
 /* Page 0, Register 65 - Digital mute enables */
 #define PCM512x_ACTL_SHIFT 2
 #define PCM512x_AMLE_SHIFT 1
-#define PCM512x_AMLR_SHIFT 0
+#define PCM512x_AMRE_SHIFT 0
 
 /* Page 1, Register 2 - analog volume control */
 #define PCM512x_RAGN_SHIFT 0
-- 
1.7.10.4

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v2 4/7] ASoC: pcm512x: Support mastering BCLK/LRCLK without using the PLL

2015-01-28 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

Use register field names from the seemingly compatible PCM5242 datasheet,
as the PCM512x and PCM514x datasheets are severly lacking.

Signed-off-by: Peter Rosin p...@axentia.se
---
 sound/soc/codecs/pcm512x.c |  441 ++--
 sound/soc/codecs/pcm512x.h |   57 +-
 2 files changed, 481 insertions(+), 17 deletions(-)

diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index 4c65eb9ab59b..124388809d48 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -23,6 +23,7 @@
 #include linux/regulator/consumer.h
 #include sound/soc.h
 #include sound/soc-dapm.h
+#include sound/pcm_params.h
 #include sound/tlv.h
 
 #include pcm512x.h
@@ -39,6 +40,7 @@ struct pcm512x_priv {
struct clk *sclk;
struct regulator_bulk_data supplies[PCM512x_NUM_SUPPLIES];
struct notifier_block supply_nb[PCM512x_NUM_SUPPLIES];
+   int fmt;
 };
 
 /*
@@ -69,6 +71,7 @@ static const struct reg_default pcm512x_reg_defaults[] = {
{ PCM512x_MUTE,  0x00 },
{ PCM512x_DSP,   0x00 },
{ PCM512x_PLL_REF,   0x00 },
+   { PCM512x_DAC_REF,   0x00 },
{ PCM512x_DAC_ROUTING,   0x11 },
{ PCM512x_DSP_PROGRAM,   0x01 },
{ PCM512x_CLKDET,0x00 },
@@ -87,6 +90,18 @@ static const struct reg_default pcm512x_reg_defaults[] = {
{ PCM512x_ANALOG_GAIN_BOOST, 0x00 },
{ PCM512x_VCOM_CTRL_1,   0x00 },
{ PCM512x_VCOM_CTRL_2,   0x01 },
+   { PCM512x_BCLK_LRCLK_CFG,0x00 },
+   { PCM512x_MASTER_MODE,   0x7c },
+   { PCM512x_SYNCHRONIZE,   0x10 },
+   { PCM512x_DSP_CLKDIV,0x00 },
+   { PCM512x_DAC_CLKDIV,0x00 },
+   { PCM512x_NCP_CLKDIV,0x00 },
+   { PCM512x_OSR_CLKDIV,0x00 },
+   { PCM512x_MASTER_CLKDIV_1,   0x00 },
+   { PCM512x_MASTER_CLKDIV_2,   0x00 },
+   { PCM512x_FS_SPEED_MODE, 0x00 },
+   { PCM512x_IDAC_1,0x01 },
+   { PCM512x_IDAC_2,0x00 },
 };
 
 static bool pcm512x_readable(struct device *dev, unsigned int reg)
@@ -103,6 +118,8 @@ static bool pcm512x_readable(struct device *dev, unsigned 
int reg)
case PCM512x_DSP_GPIO_INPUT:
case PCM512x_MASTER_MODE:
case PCM512x_PLL_REF:
+   case PCM512x_DAC_REF:
+   case PCM512x_SYNCHRONIZE:
case PCM512x_PLL_COEFF_0:
case PCM512x_PLL_COEFF_1:
case PCM512x_PLL_COEFF_2:
@@ -303,6 +320,94 @@ static const struct snd_soc_dapm_route 
pcm512x_dapm_routes[] = {
{ OUTR, NULL, DACR },
 };
 
+static const u32 pcm512x_dai_rates[] = {
+   8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000,
+   88200, 96000, 176400, 192000, 384000,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_slave = {
+   .count = ARRAY_SIZE(pcm512x_dai_rates),
+   .list  = pcm512x_dai_rates,
+};
+
+static int pcm512x_dai_startup_master(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+   struct snd_soc_codec *codec = dai-codec;
+   struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+   struct device *dev = dai-dev;
+   struct snd_pcm_hw_constraint_ratnums *constraints_no_pll;
+   struct snd_ratnum *rats_no_pll;
+
+   if (IS_ERR(pcm512x-sclk)) {
+   dev_err(dev, Need SCLK for master mode: %ld\n,
+   PTR_ERR(pcm512x-sclk));
+   return PTR_ERR(pcm512x-sclk);
+   }
+
+   constraints_no_pll = devm_kzalloc(dev, sizeof(*constraints_no_pll),
+ GFP_KERNEL);
+   if (!constraints_no_pll)
+   return -ENOMEM;
+   constraints_no_pll-nrats = 1;
+   rats_no_pll = devm_kzalloc(dev, sizeof(*rats_no_pll), GFP_KERNEL);
+   if (!rats_no_pll)
+   return -ENOMEM;
+   constraints_no_pll-rats = rats_no_pll;
+   rats_no_pll-num = clk_get_rate(pcm512x-sclk) / 64;
+   rats_no_pll-den_min = 1;
+   rats_no_pll-den_max = 128;
+   rats_no_pll-den_step = 1;
+
+   return snd_pcm_hw_constraint_ratnums(substream-runtime, 0,
+SNDRV_PCM_HW_PARAM_RATE,
+constraints_no_pll);
+}
+
+static int pcm512x_dai_startup_slave(struct snd_pcm_substream *substream,
+struct snd_soc_dai *dai)
+{
+   struct snd_soc_codec *codec = dai-codec;
+   struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+   struct device *dev = dai-dev;
+   struct regmap *regmap = pcm512x-regmap;
+
+   if (IS_ERR(pcm512x-sclk)) {
+   dev_info(dev, No SCLK, using BCLK: %ld\n,
+PTR_ERR(pcm512x-sclk));
+
+   /* Disable reporting of missing SCLK as an error */
+   regmap_update_bits(regmap

[PATCH] ASoC: atmel_ssc_dai: Support SND_SOC_DAIFMT_CBM_CFS on I2S

2015-01-29 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

Signed-off-by: Peter Rosin p...@axentia.se
---
 sound/soc/atmel/atmel_ssc_dai.c |   48 +++
 1 file changed, 48 insertions(+)

diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
index 3cd70597d109..f55f3aab8bdd 100644
--- a/sound/soc/atmel/atmel_ssc_dai.c
+++ b/sound/soc/atmel/atmel_ssc_dai.c
@@ -485,6 +485,54 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream 
*substream,
| SSC_BF(TFMR_DATLEN, (bits - 1));
break;
 
+   case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFS:
+   /* I2S format, CODEC supplies BCLK, SSC supplies LRCLK. */
+   if (bits  16  !ssc-pdata-has_fslen_ext) {
+   dev_err(dai-dev,
+   sample size %d is too large for SSC device\n,
+   bits);
+   return -EINVAL;
+   }
+
+   fslen_ext = (bits - 1) / 16;
+   fslen = (bits - 1) % 16;
+
+   rcmr =SSC_BF(RCMR_PERIOD, ssc_p-rcmr_period)
+   | SSC_BF(RCMR_STTDLY, START_DELAY)
+   | SSC_BF(RCMR_START, SSC_START_FALLING_RF)
+   | SSC_BF(RCMR_CKI, SSC_CKI_RISING)
+   | SSC_BF(RCMR_CKO, SSC_CKO_NONE)
+   | SSC_BF(RCMR_CKS, ssc-clk_from_rk_pin ?
+  SSC_CKS_PIN : SSC_CKS_CLOCK);
+
+   rfmr =SSC_BF(RFMR_FSLEN_EXT, fslen_ext)
+   | SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
+   | SSC_BF(RFMR_FSOS, SSC_FSOS_NEGATIVE)
+   | SSC_BF(RFMR_FSLEN, fslen)
+   | SSC_BF(RFMR_DATNB, (channels - 1))
+   | SSC_BIT(RFMR_MSBF)
+   | SSC_BF(RFMR_LOOP, 0)
+   | SSC_BF(RFMR_DATLEN, (bits - 1));
+
+   tcmr =SSC_BF(TCMR_PERIOD, ssc_p-tcmr_period)
+   | SSC_BF(TCMR_STTDLY, START_DELAY)
+   | SSC_BF(TCMR_START, SSC_START_FALLING_RF)
+   | SSC_BF(TCMR_CKI, SSC_CKI_FALLING)
+   | SSC_BF(TCMR_CKO, SSC_CKO_NONE)
+   | SSC_BF(TCMR_CKS, ssc-clk_from_rk_pin ?
+  SSC_CKS_CLOCK : SSC_CKS_PIN);
+
+   tfmr =SSC_BF(TFMR_FSLEN_EXT, fslen_ext)
+   | SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_NEGATIVE)
+   | SSC_BF(TFMR_FSDEN, 0)
+   | SSC_BF(TFMR_FSOS, SSC_FSOS_NEGATIVE)
+   | SSC_BF(TFMR_FSLEN, fslen)
+   | SSC_BF(TFMR_DATNB, (channels - 1))
+   | SSC_BIT(TFMR_MSBF)
+   | SSC_BF(TFMR_DATDEF, 0)
+   | SSC_BF(TFMR_DATLEN, (bits - 1));
+   break;
+
case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS:
/*
 * DSP/PCM Mode A format, SSC provides BCLK and LRC clocks.
-- 
1.7.10.4

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 1/2] ASoC: pcm512x: Fixup warning splat

2015-01-29 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

Reported-by: kbuild test robot fengguang...@intel.com
Signed-off-by: Peter Rosin p...@axentia.se
---
 sound/soc/codecs/pcm512x.c |2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index 51b279e3f465..067d11743c31 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -1266,7 +1266,6 @@ int pcm512x_probe(struct device *dev, struct regmap 
*regmap)
 {
struct pcm512x_priv *pcm512x;
int i, ret;
-   u32 val;
 
pcm512x = devm_kzalloc(dev, sizeof(struct pcm512x_priv), GFP_KERNEL);
if (!pcm512x)
@@ -1347,6 +1346,7 @@ int pcm512x_probe(struct device *dev, struct regmap 
*regmap)
 #ifdef CONFIG_OF
if (dev-of_node) {
const struct device_node *np = dev-of_node;
+   u32 val;
 
if (of_property_read_u32(np, pll-in, val) = 0) {
if (val  6) {
-- 
1.7.10.4

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 2/2] ASoC: pcm512x: Use the correct range constraints for S24_LE

2015-01-29 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

This was overlooked in the late change to remove the I2S padding bits
from S24_LE mode. The patch also limits S32_LE mode to 384kHz, the
maximum according to the datasheets.

Signed-off-by: Peter Rosin p...@axentia.se
---
 sound/soc/codecs/pcm512x.c |   39 ---
 1 file changed, 20 insertions(+), 19 deletions(-)

diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index 067d11743c31..884784fb1566 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -356,36 +356,37 @@ static const struct snd_pcm_hw_constraint_list 
constraints_slave = {
.list  = pcm512x_dai_rates,
 };
 
-static const struct snd_interval pcm512x_dai_ranges_64bpf[] = {
-   {
-   .min = 8000,
-   .max = 195312,
-   }, {
-   .min = 25,
-   .max = 390625,
-   },
-};
-
-static struct snd_pcm_hw_constraint_ranges constraints_64bpf = {
-   .count  = ARRAY_SIZE(pcm512x_dai_ranges_64bpf),
-   .ranges = pcm512x_dai_ranges_64bpf,
-};
-
 static int pcm512x_hw_rule_rate(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
 {
-   struct snd_pcm_hw_constraint_ranges *r = rule-private;
+   struct snd_interval ranges[2];
int frame_size;
 
frame_size = snd_soc_params_to_frame_size(params);
if (frame_size  0)
return frame_size;
 
-   if (frame_size != 64)
+   switch (frame_size) {
+   case 32:
+   /* No hole when the frame size is 32. */
return 0;
+   case 48:
+   case 64:
+   /* There is only one hole in the range of supported
+* rates, but it moves with the frame size.
+*/
+   memset(ranges, 0, sizeof(ranges));
+   ranges[0].min = 8000;
+   ranges[0].max = 2500 / frame_size / 2;
+   ranges[1].min = DIV_ROUND_UP(1600, frame_size);
+   ranges[1].max = 384000;
+   break;
+   default:
+   return -EINVAL;
+   }
 
return snd_interval_ranges(hw_param_interval(params, rule-var),
-  r-count, r-ranges, r-mask);
+  ARRAY_SIZE(ranges), ranges, 0);
 }
 
 static int pcm512x_dai_startup_master(struct snd_pcm_substream *substream,
@@ -407,7 +408,7 @@ static int pcm512x_dai_startup_master(struct 
snd_pcm_substream *substream,
return snd_pcm_hw_rule_add(substream-runtime, 0,
   SNDRV_PCM_HW_PARAM_RATE,
   pcm512x_hw_rule_rate,
-  (void *)constraints_64bpf,
+  NULL,
   SNDRV_PCM_HW_PARAM_FRAME_BITS,
   SNDRV_PCM_HW_PARAM_CHANNELS, -1);
 
-- 
1.7.10.4

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 0/2] ASoC: pcm512x: Fixups for the Clock master modes series

2015-01-29 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

These fixups can either be squashed in with 5/7 from the Clock master mode
series, or they can be added on top of the current topic/pcm512x. Sorry for
the trouble.

I can squash them, and resend the Clock master modes series if that helps.
Let me know how you'd like it.

Cheers,
Peter

Peter Rosin (2):
  ASoC: pcm512x: Fixup warning splat
  ASoC: pcm512x: Use the correct range constraints for S24_LE

 sound/soc/codecs/pcm512x.c |   41 +
 1 file changed, 21 insertions(+), 20 deletions(-)

-- 
1.7.10.4

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH] ASoC: pcm512x: Fix DSP program selection

2015-01-08 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

The DSP programs are listed out of order.

Signed-off-by: Peter Rosin p...@axentia.se
Cc: sta...@vger.kernel.org
---
 sound/soc/codecs/pcm512x.c |2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index 0c8aefab404c..640c99198cda 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -188,8 +188,8 @@ static const DECLARE_TLV_DB_SCALE(boost_tlv, 0, 80, 0);
 static const char * const pcm512x_dsp_program_texts[] = {
FIR interpolation with de-emphasis,
Low latency IIR with de-emphasis,
-   Fixed process flow,
High attenuation with de-emphasis,
+   Fixed process flow,
Ringing-less low latency FIR,
 };
 
-- 
1.7.10.4

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH RESEND] pm: at91: Workaround DDRSDRC self-refresh bug with LPDDR1 memories

2015-01-14 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

The DDRSDR controller (on the ATSAMA5D31) fails miserably to put LPDDR1
memories in self-refresh. Force the controller to think it has DDR2
memories during the self-refresh period, as the DDR2 self-refresh spec
is equivalent to LPDDR1, and is correctly implemented in the controller.

Assume that the second controller has the same fault, and that other
CPUs in the family has the same problem, but that is untested.

Signed-off-by: Peter Rosin p...@axentia.se
---
 arch/arm/mach-at91/pm_slowclock.S  |   43 +++-
 include/soc/at91/at91sam9_ddrsdr.h |2 +-
 2 files changed, 39 insertions(+), 6 deletions(-)

diff --git a/arch/arm/mach-at91/pm_slowclock.S 
b/arch/arm/mach-at91/pm_slowclock.S
index 20018779bae7..63a9e0b0a17d 100644
--- a/arch/arm/mach-at91/pm_slowclock.S
+++ b/arch/arm/mach-at91/pm_slowclock.S
@@ -143,6 +143,16 @@ ddr_sr_enable:
cmp memctrl, #AT91_MEMCTRL_DDRSDR
bne sdr_sr_enable
 
+   /* LPDDR1 -- force DDR2 mode during self-refresh */
+   ldr tmp1, [sdramc, #AT91_DDRSDRC_MDR]
+   str tmp1, .saved_sam9_mdr
+   bic tmp1, tmp1, #~AT91_DDRSDRC_MD
+   cmp tmp1, #AT91_DDRSDRC_MD_LOW_POWER_DDR
+   ldreq   tmp1, [sdramc, #AT91_DDRSDRC_MDR]
+   biceq   tmp1, tmp1, #AT91_DDRSDRC_MD
+   orreq   tmp1, tmp1, #AT91_DDRSDRC_MD_DDR2
+   streq   tmp1, [sdramc, #AT91_DDRSDRC_MDR]
+
/* prepare for DDRAM self-refresh mode */
ldr tmp1, [sdramc, #AT91_DDRSDRC_LPR]
str tmp1, .saved_sam9_lpr
@@ -151,14 +161,26 @@ ddr_sr_enable:
 
/* figure out if we use the second ram controller */
cmp ramc1, #0
-   ldrne   tmp2, [ramc1, #AT91_DDRSDRC_LPR]
-   strne   tmp2, .saved_sam9_lpr1
-   bicne   tmp2, #AT91_DDRSDRC_LPCB
-   orrne   tmp2, #AT91_DDRSDRC_LPCB_SELF_REFRESH
+   beq ddr_no_2nd_ctrl
+
+   ldr tmp2, [ramc1, #AT91_DDRSDRC_MDR]
+   str tmp2, .saved_sam9_mdr1
+   bic tmp2, tmp2, #~AT91_DDRSDRC_MD
+   cmp tmp2, #AT91_DDRSDRC_MD_LOW_POWER_DDR
+   ldreq   tmp2, [ramc1, #AT91_DDRSDRC_MDR]
+   biceq   tmp2, tmp2, #AT91_DDRSDRC_MD
+   orreq   tmp2, tmp2, #AT91_DDRSDRC_MD_DDR2
+   streq   tmp2, [ramc1, #AT91_DDRSDRC_MDR]
+
+   ldr tmp2, [ramc1, #AT91_DDRSDRC_LPR]
+   str tmp2, .saved_sam9_lpr1
+   bic tmp2, #AT91_DDRSDRC_LPCB
+   orr tmp2, #AT91_DDRSDRC_LPCB_SELF_REFRESH
 
/* Enable DDRAM self-refresh mode */
+   str tmp2, [ramc1, #AT91_DDRSDRC_LPR]
+ddr_no_2nd_ctrl:
str tmp1, [sdramc, #AT91_DDRSDRC_LPR]
-   strne   tmp2, [ramc1, #AT91_DDRSDRC_LPR]
 
b   sdr_sr_done
 
@@ -289,12 +311,17 @@ sdr_sr_done:
 */
cmp memctrl, #AT91_MEMCTRL_DDRSDR
bne sdr_en_restore
+   /* Restore MDR in case of LPDDR1 */
+   ldr tmp1, .saved_sam9_mdr
+   str tmp1, [sdramc, #AT91_DDRSDRC_MDR]
/* Restore LPR on AT91 with DDRAM */
ldr tmp1, .saved_sam9_lpr
str tmp1, [sdramc, #AT91_DDRSDRC_LPR]
 
/* if we use the second ram controller */
cmp ramc1, #0
+   ldrne   tmp2, .saved_sam9_mdr1
+   strne   tmp2, [ramc1, #AT91_DDRSDRC_MDR]
ldrne   tmp2, .saved_sam9_lpr1
strne   tmp2, [ramc1, #AT91_DDRSDRC_LPR]
 
@@ -328,5 +355,11 @@ ram_restored:
 .saved_sam9_lpr1:
.word 0
 
+.saved_sam9_mdr:
+   .word 0
+
+.saved_sam9_mdr1:
+   .word 0
+
 ENTRY(at91_slow_clock_sz)
.word .-at91_slow_clock
diff --git a/include/soc/at91/at91sam9_ddrsdr.h 
b/include/soc/at91/at91sam9_ddrsdr.h
index 0210797abf2e..cd2c18787833 100644
--- a/include/soc/at91/at91sam9_ddrsdr.h
+++ b/include/soc/at91/at91sam9_ddrsdr.h
@@ -92,7 +92,7 @@
 #defineAT91_DDRSDRC_UPD_MR (3  20)/* Update load 
mode register and extended mode register */
 
 #define AT91_DDRSDRC_MDR   0x20/* Memory Device Register */
-#defineAT91_DDRSDRC_MD (3  0)/* 
Memory Device Type */
+#defineAT91_DDRSDRC_MD (7  0)/* 
Memory Device Type */
 #defineAT91_DDRSDRC_MD_SDR 0
 #defineAT91_DDRSDRC_MD_LOW_POWER_SDR   1
 #defineAT91_DDRSDRC_MD_LOW_POWER_DDR   3
-- 
1.7.10.4

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 1/7] ALSA: pcm: Add snd_interval_ranges() and snd_pcm_hw_constraint_ranges()

2015-01-14 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

Add helper functions to allow drivers to specify several disjoint
ranges for a variable. In particular, there is a codec (PCM512x) that
has a hole in its supported range of rates, due to PLL and divider
restrictions.

Signed-off-by: Peter Rosin p...@axentia.se
---
 include/sound/pcm.h  |   12 +++
 sound/core/pcm_lib.c |   85 ++
 2 files changed, 97 insertions(+)

diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index b429b73e875e..95d1c20fa659 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -275,6 +275,12 @@ struct snd_pcm_hw_constraint_list {
unsigned int mask;
 };
 
+struct snd_pcm_hw_constraint_ranges {
+   unsigned int count;
+   const struct snd_interval *ranges;
+   unsigned int mask;
+};
+
 struct snd_pcm_hwptr_log;
 
 struct snd_pcm_runtime {
@@ -910,6 +916,8 @@ void snd_interval_mulkdiv(const struct snd_interval *a, 
unsigned int k,
  const struct snd_interval *b, struct snd_interval *c);
 int snd_interval_list(struct snd_interval *i, unsigned int count,
  const unsigned int *list, unsigned int mask);
+int snd_interval_ranges(struct snd_interval *i, unsigned int count,
+   const struct snd_interval *list, unsigned int mask);
 int snd_interval_ratnum(struct snd_interval *i,
unsigned int rats_count, struct snd_ratnum *rats,
unsigned int *nump, unsigned int *denp);
@@ -934,6 +942,10 @@ int snd_pcm_hw_constraint_list(struct snd_pcm_runtime 
*runtime,
   unsigned int cond,
   snd_pcm_hw_param_t var,
   const struct snd_pcm_hw_constraint_list *l);
+int snd_pcm_hw_constraint_ranges(struct snd_pcm_runtime *runtime,
+unsigned int cond,
+snd_pcm_hw_param_t var,
+const struct snd_pcm_hw_constraint_ranges *r);
 int snd_pcm_hw_constraint_ratnums(struct snd_pcm_runtime *runtime, 
  unsigned int cond,
  snd_pcm_hw_param_t var,
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index ec9e7866177f..446c00bd908b 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -1015,6 +1015,60 @@ int snd_interval_list(struct snd_interval *i, unsigned 
int count,
 
 EXPORT_SYMBOL(snd_interval_list);
 
+/**
+ * snd_interval_ranges - refine the interval value from the list of ranges
+ * @i: the interval value to refine
+ * @count: the number of elements in the list of ranges
+ * @ranges: the ranges list
+ * @mask: the bit-mask to evaluate
+ *
+ * Refines the interval value from the list of ranges.
+ * When mask is non-zero, only the elements corresponding to bit 1 are
+ * evaluated.
+ *
+ * Return: Positive if the value is changed, zero if it's not changed, or a
+ * negative error code.
+ */
+int snd_interval_ranges(struct snd_interval *i, unsigned int count,
+   const struct snd_interval *ranges, unsigned int mask)
+{
+   unsigned int k;
+   struct snd_interval range_union;
+   struct snd_interval range;
+
+   if (!count) {
+   snd_interval_none(i);
+   return -EINVAL;
+   }
+   snd_interval_any(range_union);
+   range_union.min = UINT_MAX;
+   range_union.max = 0;
+   for (k = 0; k  count; k++) {
+   if (mask  !(mask  (1  k)))
+   continue;
+   snd_interval_copy(range, ranges[k]);
+   if (snd_interval_refine(range, i)  0)
+   continue;
+   if (snd_interval_empty(range))
+   continue;
+
+   if (range.min  range_union.min) {
+   range_union.min = range.min;
+   range_union.openmin = 1;
+   }
+   if (range.min == range_union.min  !range.openmin)
+   range_union.openmin = 0;
+   if (range.max  range_union.max) {
+   range_union.max = range.max;
+   range_union.openmax = 1;
+   }
+   if (range.max == range_union.max  !range.openmax)
+   range_union.openmax = 0;
+   }
+   return snd_interval_refine(i, range_union);
+}
+EXPORT_SYMBOL(snd_interval_ranges);
+
 static int snd_interval_step(struct snd_interval *i, unsigned int step)
 {
unsigned int n;
@@ -1221,6 +1275,37 @@ int snd_pcm_hw_constraint_list(struct snd_pcm_runtime 
*runtime,
 
 EXPORT_SYMBOL(snd_pcm_hw_constraint_list);
 
+static int snd_pcm_hw_rule_ranges(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+   struct snd_pcm_hw_constraint_ranges *r = rule-private;
+   return snd_interval_ranges(hw_param_interval(params, rule-var

[PATCH 2/7] ASoC: pcm512x: Fix spelling of register field names.

2015-01-14 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

Signed-off-by: Peter Rosin p...@axentia.se
---
 sound/soc/codecs/pcm512x.c |2 +-
 sound/soc/codecs/pcm512x.h |6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index 30c673cdc12e..355a8543c8b1 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -277,7 +277,7 @@ SOC_ENUM(Auto Mute Time Right, pcm512x_autom_r),
 SOC_SINGLE(Auto Mute Mono Switch, PCM512x_DIGITAL_MUTE_3,
   PCM512x_ACTL_SHIFT, 1, 0),
 SOC_DOUBLE(Auto Mute Switch, PCM512x_DIGITAL_MUTE_3, PCM512x_AMLE_SHIFT,
-  PCM512x_AMLR_SHIFT, 1, 0),
+  PCM512x_AMRE_SHIFT, 1, 0),
 
 SOC_ENUM(Volume Ramp Down Rate, pcm512x_vndf),
 SOC_ENUM(Volume Ramp Down Step, pcm512x_vnds),
diff --git a/sound/soc/codecs/pcm512x.h b/sound/soc/codecs/pcm512x.h
index 6ee76aaca09a..28b3dfd302bc 100644
--- a/sound/soc/codecs/pcm512x.h
+++ b/sound/soc/codecs/pcm512x.h
@@ -108,8 +108,8 @@
 #define PCM512x_RQML_SHIFT 4
 
 /* Page 0, Register 4 - PLL */
-#define PCM512x_PLCE   (1  0)
-#define PCM512x_RLCE_SHIFT 0
+#define PCM512x_PLLE   (1  0)
+#define PCM512x_PLLE_SHIFT 0
 #define PCM512x_PLCK   (1  4)
 #define PCM512x_PLCK_SHIFT 4
 
@@ -152,7 +152,7 @@
 /* Page 0, Register 65 - Digital mute enables */
 #define PCM512x_ACTL_SHIFT 2
 #define PCM512x_AMLE_SHIFT 1
-#define PCM512x_AMLR_SHIFT 0
+#define PCM512x_AMRE_SHIFT 0
 
 /* Page 1, Register 2 - analog volume control */
 #define PCM512x_RAGN_SHIFT 0
-- 
1.7.10.4

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 4/7] ASoC: pcm512x: Support mastering BCLK/LRCLK without using the PLL

2015-01-14 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

Use register field names from the seemingly compatible PCM5242 datasheet,
as the PCM512x and PCM514x datasheets are severly lacking.

Signed-off-by: Peter Rosin p...@axentia.se
---
 sound/soc/codecs/pcm512x.c |  452 ++--
 sound/soc/codecs/pcm512x.h |   57 +-
 2 files changed, 492 insertions(+), 17 deletions(-)

diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index 78dc3306d2f2..70a88c7d2b1d 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -23,6 +23,7 @@
 #include linux/regulator/consumer.h
 #include sound/soc.h
 #include sound/soc-dapm.h
+#include sound/pcm_params.h
 #include sound/tlv.h
 
 #include pcm512x.h
@@ -39,6 +40,7 @@ struct pcm512x_priv {
struct clk *sclk;
struct regulator_bulk_data supplies[PCM512x_NUM_SUPPLIES];
struct notifier_block supply_nb[PCM512x_NUM_SUPPLIES];
+   int fmt;
 };
 
 /*
@@ -69,6 +71,7 @@ static const struct reg_default pcm512x_reg_defaults[] = {
{ PCM512x_MUTE,  0x00 },
{ PCM512x_DSP,   0x00 },
{ PCM512x_PLL_REF,   0x00 },
+   { PCM512x_DAC_REF,   0x00 },
{ PCM512x_DAC_ROUTING,   0x11 },
{ PCM512x_DSP_PROGRAM,   0x01 },
{ PCM512x_CLKDET,0x00 },
@@ -87,6 +90,18 @@ static const struct reg_default pcm512x_reg_defaults[] = {
{ PCM512x_ANALOG_GAIN_BOOST, 0x00 },
{ PCM512x_VCOM_CTRL_1,   0x00 },
{ PCM512x_VCOM_CTRL_2,   0x01 },
+   { PCM512x_BCLK_LRCLK_CFG,0x00 },
+   { PCM512x_MASTER_MODE,   0x7c },
+   { PCM512x_SYNCHRONIZE,   0x10 },
+   { PCM512x_DSP_CLKDIV,0x00 },
+   { PCM512x_DAC_CLKDIV,0x00 },
+   { PCM512x_NCP_CLKDIV,0x00 },
+   { PCM512x_OSR_CLKDIV,0x00 },
+   { PCM512x_MASTER_CLKDIV_1,   0x00 },
+   { PCM512x_MASTER_CLKDIV_2,   0x00 },
+   { PCM512x_FS_SPEED_MODE, 0x00 },
+   { PCM512x_IDAC_1,0x01 },
+   { PCM512x_IDAC_2,0x00 },
 };
 
 static bool pcm512x_readable(struct device *dev, unsigned int reg)
@@ -103,6 +118,8 @@ static bool pcm512x_readable(struct device *dev, unsigned 
int reg)
case PCM512x_DSP_GPIO_INPUT:
case PCM512x_MASTER_MODE:
case PCM512x_PLL_REF:
+   case PCM512x_DAC_REF:
+   case PCM512x_SYNCHRONIZE:
case PCM512x_PLL_COEFF_0:
case PCM512x_PLL_COEFF_1:
case PCM512x_PLL_COEFF_2:
@@ -303,6 +320,105 @@ static const struct snd_soc_dapm_route 
pcm512x_dapm_routes[] = {
{ OUTR, NULL, DACR },
 };
 
+static const u32 pcm512x_dai_rates[] = {
+   8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000,
+   88200, 96000, 176400, 192000, 384000,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_slave = {
+   .count = ARRAY_SIZE(pcm512x_dai_rates),
+   .list  = pcm512x_dai_rates,
+};
+
+static int pcm512x_params_to_frame_size(struct snd_pcm_hw_params *params)
+{
+   int sample_size;
+
+   sample_size = snd_pcm_format_physical_width(params_format(params));
+   if (sample_size  0)
+   return sample_size;
+
+   return snd_soc_calc_frame_size(sample_size, params_channels(params), 1);
+}
+
+static int pcm512x_dai_startup_master(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+   struct snd_soc_codec *codec = dai-codec;
+   struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+   struct device *dev = dai-dev;
+   struct snd_pcm_hw_constraint_ratnums *constraints_no_pll;
+   struct snd_ratnum *rats_no_pll;
+
+   if (IS_ERR(pcm512x-sclk)) {
+   dev_err(dev, Need SCLK for master mode: %ld\n,
+   PTR_ERR(pcm512x-sclk));
+   return PTR_ERR(pcm512x-sclk);
+   }
+
+   constraints_no_pll = devm_kzalloc(dev, sizeof(*constraints_no_pll),
+ GFP_KERNEL);
+   if (!constraints_no_pll)
+   return -ENOMEM;
+   constraints_no_pll-nrats = 1;
+   rats_no_pll = devm_kzalloc(dev, sizeof(*rats_no_pll), GFP_KERNEL);
+   if (!rats_no_pll)
+   return -ENOMEM;
+   constraints_no_pll-rats = rats_no_pll;
+   rats_no_pll-num = clk_get_rate(pcm512x-sclk) / 64;
+   rats_no_pll-den_min = 1;
+   rats_no_pll-den_max = 128;
+   rats_no_pll-den_step = 1;
+
+   return snd_pcm_hw_constraint_ratnums(substream-runtime, 0,
+SNDRV_PCM_HW_PARAM_RATE,
+constraints_no_pll);
+}
+
+static int pcm512x_dai_startup_slave(struct snd_pcm_substream *substream,
+struct snd_soc_dai *dai)
+{
+   struct snd_soc_codec *codec = dai-codec;
+   struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+   struct device

[PATCH 5/7] ASoC: pcm512x: Support mastering BCLK/LRCLK using the PLL

2015-01-14 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

Using the PLL in master mode requires using an external connection
between one of the GPIO pins (configured as PLL/4 output) and the
SCK pin. It also requires the external clock to be fed to some other
GPIO pin instead of the SCK pin.

This is described for the PCM5122 chip in the answers to the forum post
PCM5122 DAC as I2S master troubles with PLL mode at the TI E2E
community pages (1). The clocking functionality is also much better
described in the datasheet for the chip PCM5242, which seems to be
register compatible with PCM512x and PCM514x (which both have severely
lacking datasheets).

(1) http://e2e.ti.com/support/data_converters/audio_converters/f/64/t/267830

Signed-off-by: Peter Rosin p...@axentia.se
---
 .../devicetree/bindings/sound/pcm512x.txt  |   25 +-
 sound/soc/codecs/pcm512x.c |  469 +++-
 sound/soc/codecs/pcm512x.h |   44 +-
 3 files changed, 512 insertions(+), 26 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/pcm512x.txt 
b/Documentation/devicetree/bindings/sound/pcm512x.txt
index 98e0d34915e8..3aae3b41bd8e 100644
--- a/Documentation/devicetree/bindings/sound/pcm512x.txt
+++ b/Documentation/devicetree/bindings/sound/pcm512x.txt
@@ -17,9 +17,16 @@ Required properties:
 Optional properties:
 
   - clocks : A clock specifier for the clock connected as SCLK.  If this
-is absent the device will be configured to clock from BCLK.
+is absent the device will be configured to clock from BCLK.  If pll-in
+and pll-out are specified in addition to a clock, the device is
+configured to accept clock input on a specified gpio pin.
 
-Example:
+  - pll-in, pll-out : gpio pins used to connect the pll using 1
+through 6.  The device will be configured for clock input on the
+given pll-in pin and PLL output on the given pll-out pin.  An
+external connection from the pll-out pin to the SCLK pin is assumed.
+
+Examples:
 
pcm5122: pcm5122@4c {
compatible = ti,pcm5122;
@@ -29,3 +36,17 @@ Example:
DVDD-supply = reg_1v8;
CPVDD-supply = reg_3v3;
};
+
+
+   pcm5142: pcm5142@4c {
+   compatible = ti,pcm5142;
+   reg = 0x4c;
+
+   AVDD-supply = reg_3v3_analog;
+   DVDD-supply = reg_1v8;
+   CPVDD-supply = reg_3v3;
+
+   clocks = sck;
+   pll-in = 3;
+   pll-out = 6;
+   };
diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index 70a88c7d2b1d..df8948b4e848 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -21,6 +21,7 @@
 #include linux/pm_runtime.h
 #include linux/regmap.h
 #include linux/regulator/consumer.h
+#include linux/gcd.h
 #include sound/soc.h
 #include sound/soc-dapm.h
 #include sound/pcm_params.h
@@ -28,6 +29,11 @@
 
 #include pcm512x.h
 
+#define DIV_ROUND_DOWN_ULL(ll, d) \
+   ({ unsigned long long _tmp = (ll); do_div(_tmp, d); _tmp; })
+#define DIV_ROUND_CLOSEST_ULL(ll, d) \
+   ({ unsigned long long _tmp = (ll)+(d)/2; do_div(_tmp, d); _tmp; })
+
 #define PCM512x_NUM_SUPPLIES 3
 static const char * const pcm512x_supply_names[PCM512x_NUM_SUPPLIES] = {
AVDD,
@@ -41,6 +47,13 @@ struct pcm512x_priv {
struct regulator_bulk_data supplies[PCM512x_NUM_SUPPLIES];
struct notifier_block supply_nb[PCM512x_NUM_SUPPLIES];
int fmt;
+   int pll_in;
+   int pll_out;
+   int pll_r;
+   int pll_j;
+   int pll_d;
+   int pll_p;
+   unsigned long real_pll;
 };
 
 /*
@@ -92,7 +105,13 @@ static const struct reg_default pcm512x_reg_defaults[] = {
{ PCM512x_VCOM_CTRL_2,   0x01 },
{ PCM512x_BCLK_LRCLK_CFG,0x00 },
{ PCM512x_MASTER_MODE,   0x7c },
+   { PCM512x_GPIO_PLLIN,0x00 },
{ PCM512x_SYNCHRONIZE,   0x10 },
+   { PCM512x_PLL_COEFF_0,   0x00 },
+   { PCM512x_PLL_COEFF_1,   0x00 },
+   { PCM512x_PLL_COEFF_2,   0x00 },
+   { PCM512x_PLL_COEFF_3,   0x00 },
+   { PCM512x_PLL_COEFF_4,   0x00 },
{ PCM512x_DSP_CLKDIV,0x00 },
{ PCM512x_DAC_CLKDIV,0x00 },
{ PCM512x_NCP_CLKDIV,0x00 },
@@ -119,6 +138,7 @@ static bool pcm512x_readable(struct device *dev, unsigned 
int reg)
case PCM512x_MASTER_MODE:
case PCM512x_PLL_REF:
case PCM512x_DAC_REF:
+   case PCM512x_GPIO_PLLIN:
case PCM512x_SYNCHRONIZE:
case PCM512x_PLL_COEFF_0:
case PCM512x_PLL_COEFF_1:
@@ -160,6 +180,7 @@ static bool pcm512x_readable(struct device *dev, unsigned 
int reg)
case PCM512x_RATE_DET_2:
case PCM512x_RATE_DET_3:
case PCM512x_RATE_DET_4:
+   case PCM512x_CLOCK_STATUS:
case PCM512x_ANALOG_MUTE_DET:
case PCM512x_GPIN:
case PCM512x_DIGITAL_MUTE_DET:
@@ -171,6 +192,8 @@ static bool pcm512x_readable

[PATCH 7/7] ASoC: pcm512x: Support SND_SOC_DAIFMT_CBM_CFS

2015-01-14 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

Signed-off-by: Peter Rosin p...@axentia.se
---
 sound/soc/codecs/pcm512x.c |   13 +++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index 2a50c58a2fb1..511d98b3afa4 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -486,6 +486,7 @@ static int pcm512x_dai_startup(struct snd_pcm_substream 
*substream,
 
switch (pcm512x-fmt  SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
+   case SND_SOC_DAIFMT_CBM_CFS:
return pcm512x_dai_startup_master(substream, dai);
 
case SND_SOC_DAIFMT_CBS_CFS:
@@ -992,6 +993,8 @@ static int pcm512x_hw_params(struct snd_pcm_substream 
*substream,
struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
int alen;
int gpio;
+   int clock_output;
+   int master_mode;
int ret;
 
dev_dbg(codec-dev, hw_params %u Hz, %u channels\n,
@@ -1040,6 +1043,12 @@ static int pcm512x_hw_params(struct snd_pcm_substream 
*substream,
}
return 0;
case SND_SOC_DAIFMT_CBM_CFM:
+   clock_output = PCM512x_BCKO | PCM512x_LRKO;
+   master_mode = PCM512x_RLRK | PCM512x_RBCK;
+   break;
+   case SND_SOC_DAIFMT_CBM_CFS:
+   clock_output = PCM512x_BCKO;
+   master_mode = PCM512x_RBCK;
break;
default:
return -EINVAL;
@@ -1136,7 +1145,7 @@ static int pcm512x_hw_params(struct snd_pcm_substream 
*substream,
 
ret = regmap_update_bits(pcm512x-regmap, PCM512x_BCLK_LRCLK_CFG,
 PCM512x_BCKP | PCM512x_BCKO | PCM512x_LRKO,
-PCM512x_BCKO | PCM512x_LRKO);
+clock_output);
if (ret != 0) {
dev_err(codec-dev, Failed to enable clock output: %d\n, ret);
return ret;
@@ -1144,7 +1153,7 @@ static int pcm512x_hw_params(struct snd_pcm_substream 
*substream,
 
ret = regmap_update_bits(pcm512x-regmap, PCM512x_MASTER_MODE,
 PCM512x_RLRK | PCM512x_RBCK,
-PCM512x_RLRK | PCM512x_RBCK);
+master_mode);
if (ret != 0) {
dev_err(codec-dev, Failed to enable master mode: %d\n, ret);
return ret;
-- 
1.7.10.4

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 0/7] ASoC: pcm512x: Clock master modes

2015-01-14 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

Hi!

This series implements BCLK master modes for the pcm512x driver. It has
only been tested with the pcm5142 chip, but they are from the same family
and should be compatible. I have mainly used the spec for the newer
pcm5242 chip (also from the same family) as it fills in a lot of blanks
in the pcm512x/pcm514x specs.

The code has also seen most of its testing in a 3.10 environment, so
there might be some forward-porting warts. But it is able to play sound
in 3.18 as well, and most of the changes have little to do with anything
but the clocking in the chip itself.

Cheers,
Peter

Peter Rosin (7):
  ALSA: pcm: Add snd_interval_ranges() and
snd_pcm_hw_constraint_ranges()
  ASoC: pcm512x: Fix spelling of register field names.
  ASoC: pcm512x: Change register default to match actual content after
reset
  ASoC: pcm512x: Support mastering BCLK/LRCLK without using the PLL
  ASoC: pcm512x: Support mastering BCLK/LRCLK using the PLL
  ASoC: pcm512x: Avoid the PLL for the DAC clock, if possible
  ASoC: pcm512x: Support SND_SOC_DAIFMT_CBM_CFS

 .../devicetree/bindings/sound/pcm512x.txt  |   25 +-
 include/sound/pcm.h|   12 +
 sound/core/pcm_lib.c   |   85 ++
 sound/soc/codecs/pcm512x.c |  955 +++-
 sound/soc/codecs/pcm512x.h |  109 ++-
 5 files changed, 1161 insertions(+), 25 deletions(-)

-- 
1.7.10.4

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 6/7] ASoC: pcm512x: Avoid the PLL for the DAC clock, if possible

2015-01-14 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

The PLL introduces jitter, which in turn introduces noice if used
to clock the DAC. Thus, avoid the PLL output, and use the PLL input
to drive the DAC clock, if possible.

This is described for the PCM5142/PCM5242 chips in the answers to the
forum post PCM5142/PCM5242 DAC clock source at the TI E2E community
pages (1).

(1) http://e2e.ti.com/support/data_converters/audio_converters/f/64/t/389994

Signed-off-by: Peter Rosin p...@axentia.se
---
 sound/soc/codecs/pcm512x.c |  119 ++--
 sound/soc/codecs/pcm512x.h |4 +-
 2 files changed, 96 insertions(+), 27 deletions(-)

diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index df8948b4e848..2a50c58a2fb1 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -105,6 +105,7 @@ static const struct reg_default pcm512x_reg_defaults[] = {
{ PCM512x_VCOM_CTRL_2,   0x01 },
{ PCM512x_BCLK_LRCLK_CFG,0x00 },
{ PCM512x_MASTER_MODE,   0x7c },
+   { PCM512x_GPIO_DACIN,0x00 },
{ PCM512x_GPIO_PLLIN,0x00 },
{ PCM512x_SYNCHRONIZE,   0x10 },
{ PCM512x_PLL_COEFF_0,   0x00 },
@@ -138,6 +139,7 @@ static bool pcm512x_readable(struct device *dev, unsigned 
int reg)
case PCM512x_MASTER_MODE:
case PCM512x_PLL_REF:
case PCM512x_DAC_REF:
+   case PCM512x_GPIO_DACIN:
case PCM512x_GPIO_PLLIN:
case PCM512x_SYNCHRONIZE:
case PCM512x_PLL_COEFF_0:
@@ -681,6 +683,37 @@ done:
return 0;
 }
 
+static unsigned long pcm512x_pllin_dac_rate(struct snd_soc_dai *dai,
+   unsigned long osr_rate,
+   unsigned long pllin_rate)
+{
+   struct snd_soc_codec *codec = dai-codec;
+   struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+   unsigned long dac_rate;
+
+   if (!pcm512x-pll_out)
+   return 0; /* no PLL to bypass, force SCK as DAC input */
+
+   if (pllin_rate % osr_rate)
+   return 0; /* futile, quit early */
+
+   /* run DAC no faster than 6144000 Hz */
+   for (dac_rate = rounddown(6144000, osr_rate);
+dac_rate;
+dac_rate -= osr_rate) {
+
+   if (pllin_rate / dac_rate  128)
+   return 0; /* DAC divider would be too big */
+
+   if (!(pllin_rate % dac_rate))
+   return dac_rate;
+
+   dac_rate -= osr_rate;
+   }
+
+   return 0;
+}
+
 static int pcm512x_set_dividers(struct snd_soc_dai *dai,
struct snd_pcm_hw_params *params)
 {
@@ -694,6 +727,7 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai,
unsigned long bclk_rate;
unsigned long sample_rate;
unsigned long osr_rate;
+   unsigned long dacsrc_rate;
int bclk_div;
int lrclk_div;
int dsp_div;
@@ -701,11 +735,10 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai,
unsigned long dac_rate;
int ncp_div;
int osr_div;
-   unsigned long dac_mul;
-   unsigned long sck_mul;
int ret;
int idac;
int fssp;
+   int gpio;
 
lrclk_div = pcm512x_params_to_frame_size(params);
if (lrclk_div == 0) {
@@ -794,31 +827,72 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai,
/* run DSP no faster than 50 MHz */
dsp_div = mck_rate  5000 ? 2 : 1;
 
-   /* run DAC no faster than 6144000 Hz */
-   dac_mul = 6144000 / osr_rate;
-   sck_mul = sck_rate / osr_rate;
-   for (; dac_mul; dac_mul--) {
-   if (!(sck_mul % dac_mul))
-   break;
-   }
-   if (!dac_mul) {
-   dev_err(dev, Failed to find DAC rate\n);
-   return -EINVAL;
-   }
+   dac_rate = pcm512x_pllin_dac_rate(dai, osr_rate, pllin_rate);
+   if (dac_rate) {
+   /* the desired clock rate is compatible with the pll input
+* clock, so use that clock as dac input instead of the pll
+* output clock since the pll will introduce jitter and thus
+* noise.
+*/
+   dev_dbg(dev, using pll input as dac input\n);
+   ret = regmap_update_bits(pcm512x-regmap, PCM512x_DAC_REF,
+PCM512x_SDAC, PCM512x_SDAC_GPIO);
+   if (ret != 0) {
+   dev_err(codec-dev,
+   Failed to set gpio as dacref: %d\n, ret);
+   return ret;
+   }
 
-   dac_rate = dac_mul * osr_rate;
-   dev_dbg(dev, dac_rate %lu sample_rate %lu\n, dac_rate, sample_rate);
+   gpio = PCM512x_GREF_GPIO1 + pcm512x-pll_in - 1;
+   ret = regmap_update_bits(pcm512x-regmap, PCM512x_GPIO_DACIN

[PATCH 3/7] ASoC: pcm512x: Change register default to match actual content after reset

2015-01-14 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

Signed-off-by: Peter Rosin p...@axentia.se
---
 sound/soc/codecs/pcm512x.c |2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index 355a8543c8b1..78dc3306d2f2 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -78,7 +78,7 @@ static const struct reg_default pcm512x_reg_defaults[] = {
{ PCM512x_DIGITAL_VOLUME_2,  0x30 },
{ PCM512x_DIGITAL_VOLUME_3,  0x30 },
{ PCM512x_DIGITAL_MUTE_1,0x22 },
-   { PCM512x_DIGITAL_MUTE_2,0x00 },
+   { PCM512x_DIGITAL_MUTE_2,0x02 },
{ PCM512x_DIGITAL_MUTE_3,0x07 },
{ PCM512x_OUTPUT_AMPLITUDE,  0x00 },
{ PCM512x_ANALOG_GAIN_CTRL,  0x00 },
-- 
1.7.10.4

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v3] ASoC: atmel_ssc_dai: Allow more rates

2015-02-09 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

When the SSC acts as BCK master, use a ratnum rule to limit
the rate instead of only doing the standard rates. When the SSC
acts as BCK slave, allow any BCK frequency up to the SSC master
clock, divided by either of 2, 3 or 6.

Put a cap at 384kHz. Who's /ever/ going to need more than that?

The divider of 2, 3 or 6 is selected based on the Serial Clock Ratio
Considerations section from the SSC documentation:

The Transmitter and the Receiver can be programmed to operate
with the clock signals provided on either the TK or RK pins.
This allows the SSC to support many slave-mode data transfers.
In this case, the maximum clock speed allowed on the RK pin is:
- Peripheral clock divided by 2 if Receiver Frame Synchro is input
- Peripheral clock divided by 3 if Receiver Frame Synchro is output
In addition, the maximum clock speed allowed on the TK pin is:
- Peripheral clock divided by 6 if Transmit Frame Synchro is input
- Peripheral clock divided by 2 if Transmit Frame Synchro is output

Signed-off-by: Peter Rosin p...@axentia.se
---
 sound/soc/atmel/atmel_ssc_dai.c |  111 +--
 sound/soc/atmel/atmel_ssc_dai.h |1 +
 2 files changed, 108 insertions(+), 4 deletions(-)

Changes since v2:

- Killed the 500ppm reduction. Just trust the nominal clock
  rates of the given clocks.

- Don't multiply the given SSC clk rate by two to get to the
  SSC master clock rate. That factor was the result of some
  confusion on my part. The SSC clk *is* the SSC master clock.

Changes since v1:

- I have checked all Atmel datasheets I could get my hands on (and
  that seemed relevant), and in every instance where they have
  described the SSC, the description have the exact rate limitations
  on the RK and TK pin that I have implemented here.

- Improved the comments.

- Rebased on top of the latest patches from Bo Chen.

diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
index 379ac2a6ab16..6b8e64899205 100644
--- a/sound/soc/atmel/atmel_ssc_dai.c
+++ b/sound/soc/atmel/atmel_ssc_dai.c
@@ -187,6 +187,94 @@ static irqreturn_t atmel_ssc_interrupt(int irq, void 
*dev_id)
return IRQ_HANDLED;
 }
 
+/*
+ * When the bit clock is input, limit the maximum rate according to the
+ * Serial Clock Ratio Considerations section from the SSC documentation:
+ *
+ *   The Transmitter and the Receiver can be programmed to operate
+ *   with the clock signals provided on either the TK or RK pins.
+ *   This allows the SSC to support many slave-mode data transfers.
+ *   In this case, the maximum clock speed allowed on the RK pin is:
+ *   - Peripheral clock divided by 2 if Receiver Frame Synchro is input
+ *   - Peripheral clock divided by 3 if Receiver Frame Synchro is output
+ *   In addition, the maximum clock speed allowed on the TK pin is:
+ *   - Peripheral clock divided by 6 if Transmit Frame Synchro is input
+ *   - Peripheral clock divided by 2 if Transmit Frame Synchro is output
+ *
+ * When the bit clock is output, limit the rate according to the
+ * SSC divider restrictions.
+ */
+static int atmel_ssc_hw_rule_rate(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+   struct atmel_ssc_info *ssc_p = rule-private;
+   struct ssc_device *ssc = ssc_p-ssc;
+   struct snd_interval *i = hw_param_interval(params, rule-var);
+   struct snd_interval t;
+   struct snd_ratnum r = {
+   .den_min = 1,
+   .den_max = 4095,
+   .den_step = 1,
+   };
+   unsigned int num = 0, den = 0;
+   int frame_size;
+   int mck_div = 2;
+   int ret;
+
+   frame_size = snd_soc_params_to_frame_size(params);
+   if (frame_size  0)
+   return frame_size;
+
+   switch (ssc_p-daifmt  SND_SOC_DAIFMT_MASTER_MASK) {
+   case SND_SOC_DAIFMT_CBM_CFS:
+   if ((ssc_p-dir_mask  SSC_DIR_MASK_CAPTURE)
+ssc-clk_from_rk_pin)
+   /* Receiver Frame Synchro (i.e. capture)
+* is output (format is _CFS) and the RK pin
+* is used for input (format is _CBM_).
+*/
+   mck_div = 3;
+   break;
+
+   case SND_SOC_DAIFMT_CBM_CFM:
+   if ((ssc_p-dir_mask  SSC_DIR_MASK_PLAYBACK)
+!ssc-clk_from_rk_pin)
+   /* Transmit Frame Synchro (i.e. playback)
+* is input (format is _CFM) and the TK pin
+* is used for input (format _CBM_ but not
+* using the RK pin).
+*/
+   mck_div = 6;
+   break;
+   }
+
+   switch (ssc_p-daifmt  SND_SOC_DAIFMT_MASTER_MASK) {
+   case SND_SOC_DAIFMT_CBS_CFS:
+   r.num = ssc_p-mck_rate / mck_div / frame_size

RE: [PATCH v2] ASoC: atmel_ssc_dai: Allow more rates

2015-02-09 Thread Peter Rosin
Bo Shen wrote:
 Hi Peter,

Hi!

 On 02/04/2015 07:52 PM, Peter Rosin wrote:
  From: Peter Rosin p...@axentia.se
 
  When the SSC acts as BCK master, use a ratnum rule to limit the rate
  instead of only doing the standard rates. When the SSC acts as BCK
  slave, allow any BCK frequency up to within 500ppm of the SSC master
  clock, possibly divided by 2, 3 or 6.
 
  Put a cap at 384kHz. Who's /ever/ going to need more than that?
 
  The divider of 2, 3 or 6 is selected based on the Serial Clock Ratio
  Considerations section from the SSC documentation:
 
   The Transmitter and the Receiver can be programmed to operate
   with the clock signals provided on either the TK or RK pins.
   This allows the SSC to support many slave-mode data transfers.
   In this case, the maximum clock speed allowed on the RK pin is:
   - Peripheral clock divided by 2 if Receiver Frame Synchro is input
   - Peripheral clock divided by 3 if Receiver Frame Synchro is output
   In addition, the maximum clock speed allowed on the TK pin is:
   - Peripheral clock divided by 6 if Transmit Frame Synchro is input
   - Peripheral clock divided by 2 if Transmit Frame Synchro is
  output
 
  Signed-off-by: Peter Rosin p...@axentia.se
  ---
sound/soc/atmel/atmel_ssc_dai.c |  113
 +--
sound/soc/atmel/atmel_ssc_dai.h |1 +
2 files changed, 110 insertions(+), 4 deletions(-)
 
  Changes since v1:
 
  - I have checked all Atmel datasheets I could get my hands on (and
 that seemed relevant), and in every instance where they have
 described the SSC, the description have the exact rate limitations
 on the RK and TK pin that I have implemented here.
 
  - Improved the comments.
 
  - Rebased on top of the latest patches from Bo Chen.
 
  One thing remains a bit unclear, and that is the 500ppm deduction. Is
  that really warranted? The number was just pulled out of my hat...
 
  Cheers,
  Peter
 
  diff --git a/sound/soc/atmel/atmel_ssc_dai.c
  b/sound/soc/atmel/atmel_ssc_dai.c index 379ac2a6ab16..767f65bab25d
  100644
  --- a/sound/soc/atmel/atmel_ssc_dai.c
  +++ b/sound/soc/atmel/atmel_ssc_dai.c
  @@ -187,6 +187,96 @@ static irqreturn_t atmel_ssc_interrupt(int irq, void 
  *dev_id)
  return IRQ_HANDLED;
}
 
  +/*
  + * When the bit clock is input, limit the maximum rate according to
  +the
  + * Serial Clock Ratio Considerations section from the SSC documentation:
  + *
  + *   The Transmitter and the Receiver can be programmed to operate
  + *   with the clock signals provided on either the TK or RK pins.
  + *   This allows the SSC to support many slave-mode data transfers.
  + *   In this case, the maximum clock speed allowed on the RK pin is:
  + *   - Peripheral clock divided by 2 if Receiver Frame Synchro is input
  + *   - Peripheral clock divided by 3 if Receiver Frame Synchro is output
  + *   In addition, the maximum clock speed allowed on the TK pin is:
  + *   - Peripheral clock divided by 6 if Transmit Frame Synchro is input
  + *   - Peripheral clock divided by 2 if Transmit Frame Synchro is output
  + *
  + * When the bit clock is output, limit the rate according to the
  + * SSC divider restrictions.
  + */
  +static int atmel_ssc_hw_rule_rate(struct snd_pcm_hw_params *params,
  + struct snd_pcm_hw_rule *rule)
  +{
  +   struct atmel_ssc_info *ssc_p = rule-private;
  +   struct ssc_device *ssc = ssc_p-ssc;
  +   struct snd_interval *i = hw_param_interval(params, rule-var);
  +   struct snd_interval t;
  +   struct snd_ratnum r = {
  +   .den_min = 1,
  +   .den_max = 4095,
  +   .den_step = 1,
  +   };
  +   unsigned int num = 0, den = 0;
  +   int frame_size;
  +   int mck_div = 2;
  +   int ret;
  +
  +   frame_size = snd_soc_params_to_frame_size(params);
  +   if (frame_size  0)
  +   return frame_size;
  +
  +   switch (ssc_p-daifmt  SND_SOC_DAIFMT_MASTER_MASK) {
  +   case SND_SOC_DAIFMT_CBM_CFS:
  +   if ((ssc_p-dir_mask  SSC_DIR_MASK_CAPTURE)
  +ssc-clk_from_rk_pin)
  +   /* Receiver Frame Synchro (i.e. capture)
  +* is output (format is _CFS) and the RK pin
  +* is used for input (format is _CBM_).
  +*/
  +   mck_div = 3;
  +   break;
  +
  +   case SND_SOC_DAIFMT_CBM_CFM:
  +   if ((ssc_p-dir_mask  SSC_DIR_MASK_PLAYBACK)
  +!ssc-clk_from_rk_pin)
  +   /* Transmit Frame Synchro (i.e. playback)
  +* is input (format is _CFM) and the TK pin
  +* is used for input (format _CBM_ but not
  +* using the RK pin).
  +*/
  +   mck_div = 6;
  +   break;
  +   }
  +
  +   switch (ssc_p-daifmt  SND_SOC_DAIFMT_MASTER_MASK) {
  +   case SND_SOC_DAIFMT_CBS_CFS:
  +   r.num = ssc_p-mck_rate / mck_div

RE: [PATCH v2] ASoC: atmel_ssc_dai: Allow more rates

2015-02-09 Thread Peter Rosin
Bo Shen wrote:
 Hi Peter,
 
 On 02/09/2015 03:35 PM, Peter Rosin wrote:
  Bo Shen wrote:
  Hi Peter,
 
  Hi!
 
  On 02/07/2015 06:51 PM, Peter Rosin wrote:
  Mark Brown wrote:
  On Wed, Feb 04, 2015 at 12:52:25PM +0100, Peter Rosin wrote:
 
  One thing remains a bit unclear, and that is the 500ppm deduction.
  Is that really warranted? The number was just pulled out of my hat...
 
  I don't really get what this is supposed to be protecting against.
 
  +   case SND_SOC_DAIFMT_CBM_CFS:
  +   case SND_SOC_DAIFMT_CBM_CFM:
  +   t.min = 8000;
  +   t.max = ssc_p-mck_rate / mck_div / frame_size;
  +   /* Take away 500ppm, just to be on the safe side. */
  +   t.max -= t.max / 2000;
  +   t.openmin = t.openmax = 0;
  +   t.integer = 0;
  +   ret = snd_interval_refine(i, t);
 
  As I understand it this is a straight divider rather than something
  that's doing dithering or anything else more fancy.  Given that it
  seems as well just to trust the clock rate we've got - we don't do
  any error tracking with the clock API (perhaps we should) and for
  many applications some degree of divergence from the nominal rate
  is not
  *too* bad for audio systems (for application specific values of some
  and too of course).  If it is just dividers I'm not sure the
  situation is really improved materially by knocking off the top 
  frequency.
 
  If we are doing something more fancy than divididing my analysis is
  off base of course.
 
  I'm thinking that the SSC samples the selected BCK pin using the
  (possibly
  divided) peripheral clock. Getting too near the theoretical rate
  limit would be bad, if these two independent clocks drift the wrong
  way. At least that is my take on it, but I don't know the internal 
  workings of the SSC, so...
 
  I was hoping that someone from Atmel could chime in? Maybe I'm
  totally
 
  Sorry for late response.
 
  No problem!
 
  off base, and the SSC is doing this completely differently?
 
  What you mean here? I am not sure I fully understand.
 
  The SSC spec list a maximum rate (which varies with the direction of
  various signals, ignoring that for the sake of this explanation). Lets
  assume that this maximum rate is 11MHz, derived from the peripheral
  clock which might be 66MHz. If you then try to input an 11MHz signal
  derived from some unrelated xtal you might think it should work. My
  theory was that the rate limit would be broken if the peripheral clock
  wasn't really 66MHz, but instead a few ppm lower than nominal, and the
  unrelated xtal was a few ppm higher than nominal.
 
  If this matters or not depends on how the SSC is implemented.
 
 This is to let the user to know the clock limitation, am I right?

Yes, sort of, to prevent the user from even attempting to go too
near the nominal limit.

 And at the same time deal with the un-precise clock which come to SSC?
 If this case, I think we should trust the clock come to SSC.

Ok, I'll just kill the 500ppm thing for the next round. I'll wait a bit
for the discussion in the other branch to fade out though. :-)

Cheers,
Peter

  There might be other reasons for not caring all that much about this
  fringe case, and just trust the nominal rates and limits.
 
  In our application, we're not near the limit. Therefore, it really
  doesn't matter much to us.
 
  Should I resend w/o the 500ppm deduction?
 
  Cheers,
  Peter
 
 
  Best Regards,
  Bo Shen
 
 Best Regards,
 Bo Shen
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


RE: [PATCH v2] ASoC: atmel_ssc_dai: Allow more rates

2015-02-09 Thread Peter Rosin
Bo Shen wrote:
 Hi Peter,
 

Hi!

 On 02/09/2015 05:07 PM, Peter Rosin wrote:
  Bo Shen wrote:
  Hi Peter,
 
  On 02/09/2015 04:09 PM, Peter Rosin wrote:
 
  [Snip]
 
 
  
  /*-*\
   * DAI functions
  @@ -200,6 +290,7 @@ static int atmel_ssc_startup(struct
  snd_pcm_substream *substream,
  struct atmel_ssc_info *ssc_p = ssc_info[dai-id];
  struct atmel_pcm_dma_params *dma_params;
  int dir, dir_mask;
  +   int ret;
 
  pr_debug(atmel_ssc_startup: SSC_SR=0x%u\n,
  ssc_readl(ssc_p-ssc-regs, SR)); @@ -207,6 +298,7
 @@
  static
  int atmel_ssc_startup(struct snd_pcm_substream *substream,
  /* Enable PMC peripheral clock for this SSC */
  pr_debug(atmel_ssc_dai: Starting clock\n);
  clk_enable(ssc_p-ssc-clk);
  +   ssc_p-mck_rate = clk_get_rate(ssc_p-ssc-clk) * 2;
 
  Why the mck_rate is calculated in this form?
 
  What did you have in mind? Add another clock to the ssc node in the
  device tree?
 
  IIUC, the device tree (at least normally) has the ssc clk as the
  peripheral clock divided by 2, but the ssc specifies (when capturing
  in the CBM/CFS
  case) the rate limit as the peripheral clock divided by 3 (i.e. ssc clk / 
  1.5).
  Since the SSC spec expresses the rate limit in terms of the
  peripheral clock, this was what I came up with. I didn't want to require 
  dt
 changes...
 
  You make a misunderstand for the mck for ssc peripheral. The mck here
  is not the system mck, it only related with the ssc, it is the PMC output.
  For example, in device tree, the ssc clock divided by 2, then the pmc
  output for ssc is system mck / 2, so the ssc mck is system mck / 2.
  If divided by 4, then the ssc mck is system / 4
 
  I think the reason for my misunderstanding might be that in the
  3.10-at91 tree, the ssc clk is twice the rate compared to what it is
  in the 3.18-at91 tree. This made me assume that the ssc clk had
 
 I think maybe you didn't use the latest linux-3.10-at91 code. In that code, we
 also divided by 2 in device tree.

That's a rather confusing statement. The clock tree isn't even managed
by the device tree in linux-3.10-at91. Sure, there's the 12MHz system
master clock in sama5d3.dtsi, but that's about it. The rest of the clocks
are in arch/arm/mach-at91/sama5d3.c. And the part about ssc0/ssc1
hasn't been updated since it was added in 3.9. What am I missing?

  been changed to mean the rate after the fixed divider by two that is
  activated as soon as the ssc clock divider (given by SSC_CMR) is
  activated, and that it was a simple matter of multiplying by two to
  get to the MCK rate. I further assumed that Master Clock in the
  Serial Clock Ratio Considerations section was this MCK. Maybe the
  mistake was to involve the peripheral clock at all?
 
  Ok, so I may have misunderstood, but in that case what does that mean
  in terms of finding the Master Clock rate that is mentioned in the
  Serial Clock Ratio Considerations section? Is it perhaps the rate of
  the parent clock of the given ssc clk? Or, given the above
  explanation, is it correct to simply multiply by two as I have done?
 
 The Master Clock actually is the same as Peripheral clock.
 
 Thanks for your information, I will send this to our datasheet team to update
 this part.

You are still not saying how to get to the Master Clock rate (i.e. the
Master Clock that is mentioned in the Serial Clock Ratio Considerations
section. You are only implying that multiplying the ssc clock rate with 2 is
wrong for some reason.

Are you saying that the ssc clock is supposed to be this Master Clock?

Cheers,
Peter
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


RE: [PATCH v2] ASoC: atmel_ssc_dai: Allow more rates

2015-02-09 Thread Peter Rosin
Bo Shen write:
 Hi Peter,

Hi!

[Snip]
 
 
   
  /*-*\
* DAI functions
  @@ -200,6 +290,7 @@ static int atmel_ssc_startup(struct
  snd_pcm_substream *substream,
struct atmel_ssc_info *ssc_p = ssc_info[dai-id];
struct atmel_pcm_dma_params *dma_params;
int dir, dir_mask;
  + int ret;
 
pr_debug(atmel_ssc_startup: SSC_SR=0x%u\n,
ssc_readl(ssc_p-ssc-regs, SR)); @@ -207,6 +298,7
  @@
  static
  int atmel_ssc_startup(struct snd_pcm_substream *substream,
/* Enable PMC peripheral clock for this SSC */
pr_debug(atmel_ssc_dai: Starting clock\n);
clk_enable(ssc_p-ssc-clk);
  + ssc_p-mck_rate = clk_get_rate(ssc_p-ssc-clk) * 2;
 
  Why the mck_rate is calculated in this form?
 
  What did you have in mind? Add another clock to the ssc node in
  the device tree?
 
  IIUC, the device tree (at least normally) has the ssc clk as the
  peripheral clock divided by 2, but the ssc specifies (when
  capturing in the CBM/CFS
  case) the rate limit as the peripheral clock divided by 3 (i.e. ssc clk 
  /
 1.5).
  Since the SSC spec expresses the rate limit in terms of the
  peripheral clock, this was what I came up with. I didn't want to
  require dt
  changes...
 
  You make a misunderstand for the mck for ssc peripheral. The mck
  here is not the system mck, it only related with the ssc, it is the PMC
 output.
  For example, in device tree, the ssc clock divided by 2, then the
  pmc output for ssc is system mck / 2, so the ssc mck is system mck /
 2.
  If divided by 4, then the ssc mck is system / 4
 
  I think the reason for my misunderstanding might be that in the
  3.10-at91 tree, the ssc clk is twice the rate compared to what it is
  in the 3.18-at91 tree. This made me assume that the ssc clk had
 
  I think maybe you didn't use the latest linux-3.10-at91 code. In that
  code, we also divided by 2 in device tree.
 
  That's a rather confusing statement. The clock tree isn't even managed
  by the device tree in linux-3.10-at91. Sure, there's the 12MHz system
  master clock in sama5d3.dtsi, but that's about it. The rest of the
  clocks are in arch/arm/mach-at91/sama5d3.c. And the part about
  ssc0/ssc1 hasn't been updated since it was added in 3.9. What am I missing?
 
 I am not sure what the kernel you are talking about now.
 
 In linux-3.10-at91 branch on github.com/linux4sam/linux-at91. In the
 arch/arm/mach-at91/sama5d3.c
 
 ---8---
 static struct clk ssc0_clk = {
  .name   = ssc0_clk,
  .pid= SAMA5D3_ID_SSC0,
  .type   = CLK_TYPE_PERIPHERAL,
  .div= AT91_PMC_PCR_DIV2,
 };
 static struct clk ssc1_clk = {
  .name   = ssc1_clk,
  .pid= SAMA5D3_ID_SSC1,
  .type   = CLK_TYPE_PERIPHERAL,
  .div= AT91_PMC_PCR_DIV2,
 };
 ---8---

That's the same code I'm looking at. This has always worked as
expected for me in the linux-3.10-at91 kernel. However, in the
linux-3.18-at91 kernel, I definitely recall getting half the rate
when querying the ssc0 clock. I thought the 3.18 way was
the future, and adjusted. However, I don't get that difference
now, and I can't really explain what has changed. Strange.
Anyway, thanks for setting me straight!

 That means, the clock output from PMC is system clock / 2 which will be fed
 to ssc (here we call it SSC peripheral clock = system clock / 2).
 
  been changed to mean the rate after the fixed divider by two that is
  activated as soon as the ssc clock divider (given by SSC_CMR) is
  activated, and that it was a simple matter of multiplying by two to
  get to the MCK rate. I further assumed that Master Clock in the
  Serial Clock Ratio Considerations section was this MCK. Maybe the
  mistake was to involve the peripheral clock at all?
 
  Ok, so I may have misunderstood, but in that case what does that
  mean in terms of finding the Master Clock rate that is mentioned
  in the Serial Clock Ratio Considerations section? Is it perhaps
  the rate of the parent clock of the given ssc clk? Or, given the
  above explanation, is it correct to simply multiply by two as I have done?
 
  The Master Clock actually is the same as Peripheral clock.
 
  Thanks for your information, I will send this to our datasheet team
  to update this part.
 
  You are still not saying how to get to the Master Clock rate (i.e.
  the Master Clock that is mentioned in the Serial Clock Ratio
 Considerations
  section. You are only implying that multiplying the ssc clock rate
  with 2 is wrong for some reason.
 
 I mean in that section you mentioned. The Master Clock is the same as
 Peripheral Clock. So, you get the SSC peripheral clock is what the clock
 (Master Clock) you try to get ( clk_get_rate(ssc_p-ssc-clk)).
 

Yes, I see now. I'll resend with the *2 (and the 500ppm discussed in the
other thread) removed.

  Are you 

RE: [PATCH] ASoC:pcm512x: Fix divide by zero issue.

2015-03-22 Thread Peter Rosin
Howard Mitchell wrote;
 If den=1 and pllin_rate20MHz then den and num are adjusted to 0
 causing a divide by zero error a few lines further on. Therefore
 this patch correctly scales num and den such that
 pllin_rate/den  20MHz as required in the device data sheet.

Yep, the old code is plain broken and never actually ran, we have been
using 16MHz pllin_rate, and I apparently never hit this code path.

 Signed-off-by: Howard Mitchell h...@hmbedded.co.uk

Acked-by: Peter Rosin p...@axentia.se

Cheers,
Peter

 ---
  sound/soc/codecs/pcm512x.c |4 ++--
  1 file changed, 2 insertions(+), 2 deletions(-)
 
 diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
 index 5301c4a..8472099 100644
 --- a/sound/soc/codecs/pcm512x.c
 +++ b/sound/soc/codecs/pcm512x.c
 @@ -713,8 +713,8 @@ static int pcm512x_find_pll_coeff(struct snd_soc_dai
 *dai,
 
   /* pllin_rate / P (or here, den) cannot be greater than 20 MHz */
   if (pllin_rate / den  2000  num  8) {
 - num *= 2000 / (pllin_rate / den);
 - den *= 2000 / (pllin_rate / den);
 + num *= DIV_ROUND_UP(pllin_rate / den, 2000);
 + den *= DIV_ROUND_UP(pllin_rate / den, 2000);
   }
   dev_dbg(dev, num / den = %lu / %lu\n, num, den);
 
 --
 1.7.9.5

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


RE: [PATCH] ASoC:pcm512x: Make PLL lock output selectable via device tree.

2015-03-22 Thread Peter Rosin
Howard Mitchell wrote:
 Currently the PLL Lock output signal is hardcoded to GPIO4. This
 makes it seletable in the same way as pll-in and pll-out.

Oops, I never intended the plllock code the hit upstream. I thought
I had removed that testing code and was very surprised to see it, that
was an odd experience. From my point of view it is fine to instead
remove the whole pll-lock thing.

But now the cat is out, so maybe we have to keep a way to output
the pll-lock signal for backwards compatibility?

Appart from the space-indent changes, this looks fine (if we do in fact
need to keep it at all). But I would like to see a new version of the
patch without the whitespace changes before I commit to that.

Cheers,
Peter

 Signed-off-by: Howard Mitchell h...@hmbedded.co.uk
 ---
  .../devicetree/bindings/sound/pcm512x.txt  |3 ++
  sound/soc/codecs/pcm512x.c |   47 
 +---
  2 files changed, 33 insertions(+), 17 deletions(-)
 
 diff --git a/Documentation/devicetree/bindings/sound/pcm512x.txt
 b/Documentation/devicetree/bindings/sound/pcm512x.txt
 index 3aae3b4..432f186 100644
 --- a/Documentation/devicetree/bindings/sound/pcm512x.txt
 +++ b/Documentation/devicetree/bindings/sound/pcm512x.txt
 @@ -26,6 +26,8 @@ Optional properties:
  given pll-in pin and PLL output on the given pll-out pin.  An
  external connection from the pll-out pin to the SCLK pin is assumed.
 
 +  - pll-lock : gpio pin used to output the PLL lock flag.
 +
  Examples:
 
   pcm5122: pcm5122@4c {
 @@ -49,4 +51,5 @@ Examples:
   clocks = sck;
   pll-in = 3;
   pll-out = 6;
 + pll-lock = 4;
   };
 diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
 index 8472099..a4217d7 100644
 --- a/sound/soc/codecs/pcm512x.c
 +++ b/sound/soc/codecs/pcm512x.c
 @@ -49,6 +49,7 @@ struct pcm512x_priv {
   int fmt;
   int pll_in;
   int pll_out;
 + int pll_lock;
   int pll_r;
   int pll_j;
   int pll_d;
 @@ -1296,24 +1297,26 @@ static int pcm512x_hw_params(struct
 snd_pcm_substream *substream,
   ret, pcm512x-pll_out);
   return ret;
   }
 + }
 
 - gpio = PCM512x_G1OE  (4 - 1);
 - ret = regmap_update_bits(pcm512x-regmap, PCM512x_GPIO_EN,
 -  gpio, gpio);
 - if (ret != 0) {
 - dev_err(codec-dev, Failed to enable gpio %d: %d\n,
 - 4, ret);
 - return ret;
 - }
 -
 - gpio = PCM512x_GPIO_OUTPUT_1 + 4 - 1;
 - ret = regmap_update_bits(pcm512x-regmap, gpio,
 -  PCM512x_GxSL, PCM512x_GxSL_PLLLK);
 - if (ret != 0) {
 - dev_err(codec-dev,
 - Failed to output pll lock on %d: %d\n,
 - ret, 4);
 - return ret;
 + if (pcm512x-pll_lock) {
 +gpio = PCM512x_G1OE  (pcm512x-pll_lock - 1);
 +ret = regmap_update_bits(pcm512x-regmap, PCM512x_GPIO_EN,
 + gpio, gpio);
 +if (ret != 0) {
 +dev_err(codec-dev, Failed to enable gpio %d: %d\n,
 +pcm512x-pll_lock, ret);
 +return ret;
 +}
 +
 +gpio = PCM512x_GPIO_OUTPUT_1 + pcm512x-pll_lock - 1;
 +ret = regmap_update_bits(pcm512x-regmap, gpio,
 + PCM512x_GxSL, PCM512x_GxSL_PLLLK);
 +if (ret != 0) {
 +dev_err(codec-dev,
 +Failed to output pll lock on %d: %d\n,
 +ret, pcm512x-pll_lock);
 +return ret;
   }
   }
 
 @@ -1518,6 +1521,16 @@ int pcm512x_probe(struct device *dev, struct
 regmap *regmap)
   ret = -EINVAL;
   goto err_clk;
   }
 +
 +if (of_property_read_u32(np, pll-lock, val) = 0) {
 +if (val  6) {
 +dev_err(dev, Invalid pll-lock\n);
 +ret = -EINVAL;
 +goto err_clk;
 +}
 +pcm512x-pll_lock = val;
 +}
 +
   }
  #endif
 
 --
 1.7.9.5

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


RE: [PATCH] ASoC:pcm512x: Make PLL lock output selectable via device tree.

2015-03-23 Thread Peter Rosin
Howard Mitchell wrote:
 On 22/03/15 16:24, Mark Brown wrote:
  On Fri, Mar 20, 2015 at 09:22:43PM +, Howard Mitchell wrote:
 
  +  if (pcm512x-pll_lock) {
  +if (of_property_read_u32(np, pll-lock, val) = 0) {
  +if (val  6) {
  +dev_err(dev, Invalid pll-lock\n);
  +ret = -EINVAL;
  +goto err_clk;
  +}
  +pcm512x-pll_lock = val;
  +}
  This breaks existing boards which rely on GPIO 4 being set as the lock
  output.  This is very unfortunate since it's a silly thing for the
  driver to default to but nontheless we should really continue to support
  them - at a guess Peter's board is relying on this, and even if it isn't
  someone else's might.
 I take your point, but the reason I pushed this patch was that I wanted
 to use GPIO4 for pll-out and unfortunately because the pll-lock
 configuration is after the pll-out configuration it stomps on it. If I
 modify the patch to provide a default for pll-lock I will then be
 obliged to specify pll-lock on another GPIO. The pcm5122 has limited IO
 so being forced to have a GPIO for pll-lock seems wrong to me. A future
 user of the device may well decide to use the GPIOs for other purposes
 and therefore not want a pll-lock signal at all. Surely we should allow
 for that possibility?
 
 Given that Peter has indicated that he'd be happy with this solution and
 that this code hasn't reached a published kernel would it be reasonable
 to go ahead with my current patch (happy to clean up the indent issues
 that Peter pointed out of course)?

Strongly agreed that we should fix this before it is published (I assumed
that is was included in 3.19, it felt so long ago that Mark merged it...). My
preference would be to remove the pll-lock things entirely though. Assuming
you don't need it for your board of course, but I doubt it from your 
description.
I used it to make sure I had understood the chip correctly, that's all.

Cheers,
Peter

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v2] ASoC: pcm512x: Allow independently overclocking PLL, DAC and DSP

2015-02-23 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

When using non-standard rates, a relatively small amount of overclocking
can make a big difference to a number of cases.

- Not all rates are possible to achieve with the PLL, due to divider
  restrictions.

- The higher oversampling rates that can be used by the DAC, the
  simpler the analog output filters get (mirror frequencies move up,
  away from the desired spectrum).

- The more work the DSP can perform per sample, the better.

For standard rates, there is little to gain as everything is
designed just right, and the needed overclocking to make a
real difference would be significant.

Signed-off-by: Peter Rosin p...@axentia.se
---
 sound/soc/codecs/pcm512x.c |  161 +---
 1 file changed, 150 insertions(+), 11 deletions(-)

diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index f11c76f1acfe..4b5f1fe9be97 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -54,6 +54,9 @@ struct pcm512x_priv {
int pll_d;
int pll_p;
unsigned long real_pll;
+   unsigned long overclock_pll;
+   unsigned long overclock_dac;
+   unsigned long overclock_dsp;
 };
 
 /*
@@ -224,6 +227,90 @@ static bool pcm512x_volatile(struct device *dev, unsigned 
int reg)
}
 }
 
+static int pcm512x_overclock_pll_get(struct snd_kcontrol *kcontrol,
+struct snd_ctl_elem_value *ucontrol)
+{
+   struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+   struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+
+   ucontrol-value.integer.value[0] = pcm512x-overclock_pll;
+   return 0;
+}
+
+static int pcm512x_overclock_pll_put(struct snd_kcontrol *kcontrol,
+struct snd_ctl_elem_value *ucontrol)
+{
+   struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+   struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+
+   switch (codec-dapm.bias_level) {
+   case SND_SOC_BIAS_OFF:
+   case SND_SOC_BIAS_STANDBY:
+   break;
+   default:
+   return -EBUSY;
+   }
+
+   pcm512x-overclock_pll = ucontrol-value.integer.value[0];
+   return 0;
+}
+
+static int pcm512x_overclock_dsp_get(struct snd_kcontrol *kcontrol,
+struct snd_ctl_elem_value *ucontrol)
+{
+   struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+   struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+
+   ucontrol-value.integer.value[0] = pcm512x-overclock_dsp;
+   return 0;
+}
+
+static int pcm512x_overclock_dsp_put(struct snd_kcontrol *kcontrol,
+struct snd_ctl_elem_value *ucontrol)
+{
+   struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+   struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+
+   switch (codec-dapm.bias_level) {
+   case SND_SOC_BIAS_OFF:
+   case SND_SOC_BIAS_STANDBY:
+   break;
+   default:
+   return -EBUSY;
+   }
+
+   pcm512x-overclock_dsp = ucontrol-value.integer.value[0];
+   return 0;
+}
+
+static int pcm512x_overclock_dac_get(struct snd_kcontrol *kcontrol,
+struct snd_ctl_elem_value *ucontrol)
+{
+   struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+   struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+
+   ucontrol-value.integer.value[0] = pcm512x-overclock_dac;
+   return 0;
+}
+
+static int pcm512x_overclock_dac_put(struct snd_kcontrol *kcontrol,
+struct snd_ctl_elem_value *ucontrol)
+{
+   struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+   struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+
+   switch (codec-dapm.bias_level) {
+   case SND_SOC_BIAS_OFF:
+   case SND_SOC_BIAS_STANDBY:
+   break;
+   default:
+   return -EBUSY;
+   }
+
+   pcm512x-overclock_dac = ucontrol-value.integer.value[0];
+   return 0;
+}
+
 static const DECLARE_TLV_DB_SCALE(digital_tlv, -10350, 50, 1);
 static const DECLARE_TLV_DB_SCALE(analog_tlv, -600, 600, 0);
 static const DECLARE_TLV_DB_SCALE(boost_tlv, 0, 80, 0);
@@ -328,6 +415,13 @@ SOC_ENUM(Volume Ramp Up Rate, pcm512x_vnuf),
 SOC_ENUM(Volume Ramp Up Step, pcm512x_vnus),
 SOC_ENUM(Volume Ramp Down Emergency Rate, pcm512x_vedf),
 SOC_ENUM(Volume Ramp Down Emergency Step, pcm512x_veds),
+
+SOC_SINGLE_EXT(Max Overclock PLL, SND_SOC_NOPM, 0, 20, 0,
+  pcm512x_overclock_pll_get, pcm512x_overclock_pll_put),
+SOC_SINGLE_EXT(Max Overclock DSP, SND_SOC_NOPM, 0, 40, 0,
+  pcm512x_overclock_dsp_get, pcm512x_overclock_dsp_put),
+SOC_SINGLE_EXT(Max Overclock DAC, SND_SOC_NOPM, 0, 40, 0,
+  pcm512x_overclock_dac_get, pcm512x_overclock_dac_put),
 };
 
 static const

Re: [PATCH 2/2] ASoC: pcm512x: Allow independently overclocking PLL, DAC and DSP

2015-02-23 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

On 2015-02-23 15:31, Mark Brown wrote:
 On Sun, Feb 22, 2015 at 12:24:12AM +, Peter Rosin wrote:
 
 ...but I'm not sure everybody agrees that overclocking games should
 be allowed by any and all users?
 
 I don't see why not, ASoC controls are already way beyond end user a lot
 of the time.

*snip*

Ok, so going to ALSA-control route, changes since v1:

- Uses ALSA-controls instead of sysfs knobs.
- Returns -EBUSY if trying to change the values while active.

Cheers,
Peter

Peter Rosin (1):
  ASoC: pcm512x: Allow independently overclocking PLL, DAC and DSP

 sound/soc/codecs/pcm512x.c |  161 +---
 1 file changed, 150 insertions(+), 11 deletions(-)

-- 
1.7.10.4

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


RE: [PATCH 2/2] ASoC: pcm512x: Allow independently overclocking PLL, DAC and DSP

2015-02-21 Thread Peter Rosin
Mark Brown wrote:
 On Mon, Feb 16, 2015 at 10:02:48PM +0100, Peter Rosin wrote:
  From: Peter Rosin p...@axentia.se
 
  When using non-standard rates, a relatively small amount of
  overclocking can make a big difference to a number of cases.
 
 This is all basically fine but I'm wondering why this is being configured via
 sysfs and not via ALSA controls?  It's going to be more fiddly for people to
 have to work with both control methods when they need to configure these
 things.

Originally, I had the limits in .config. Then Lars-Peter suggested
sysfs (on irc) and perhaps some way to disable overclocking. ALSA
controls were never on the table, but now that you mention it, it sounds
about right. So, I'm fine with having it as ALSA-controls...

*time passes*

...but I'm not sure everybody agrees that overclocking games should
be allowed by any and all users?

If you still want me to convert to ALSA controls, what control do you
suggest? SOC_SINGLE_EXT? Or should I use an enumeration, because
mixers tend to present volume controls as a percentage of max, which
will be confusing: You are now at volume 75% (of max 40), when the
value is 30. Eeek. But enumerations from 0% to 40% sounds tedious.

And how would you suggest that I name the controls?
Max Overclock DAC, Max Overclock DSP and Max Overclock PLL?

BTW, the only troubles I've had with overclocking too much is that it
has stopped working. I have not managed to fry any chip. But that is no
guarantee, of course.

Cheers,
Peter

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


RE: [PATCH] ASoC: pcm512x: Remove hardcoding of pll-lock to GPIO4

2015-03-24 Thread Peter Rosin
Howard Mitchell wrote:
 Currently GPIO4 is hardcoded to output the pll-lock signal.
 Unfortunately this is after the pll-out GPIO is configured which
 is selectable in the device tree. Therefore it is not possible to
 use GPIO4 for pll-out. Therefore this patch removes the
 configuration of GPIO4.

Howard, thanks for picking up my laundry!

Is master mode working for you otherwise? Have you seen any sign
of bad dividers for the various clocks, or anything like that?

Regarding the pin configuration, I suppose the cleanest approach
would be to implement it as a pin control driver? Then you could
also expose the pins as gpios and  select the pin functions in a more
standard way, right? I wouldn't know where to start with that
though. I have the feeling that it would also mean that there would
have to be a mfd driver for the chip???

However, there is the issue that we don't need anything more from
the chip, so we're happy with the driver as is (assuming the overclocking
patch goes in as planned for 4.1).

Cheers,
Peter

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[RFC PATCH] ASoC: atmel_ssc_dai: Allow more rates

2015-01-29 Thread Peter Rosin
From: Peter Rosin p...@axentia.se

When the SSC acts as BCK master, use a ratnum rule to limit
the rate instead of only doing the standard rates. When the SSC
acts as BCK slave, allow any BCK frequency up to within 500ppm
of the SSC master clock, possibly divided by 2, 3 or 6.

Put a cap at 384kHz. Who's /ever/ going to need more than that?

Signed-off-by: Peter Rosin p...@axentia.se
---
 sound/soc/atmel/atmel_ssc_dai.c |   98 +--
 sound/soc/atmel/atmel_ssc_dai.h |1 +
 2 files changed, 95 insertions(+), 4 deletions(-)


This patch depends on the patch I sent earlier that enables the
_CBS_CFS mode on the atmel SSC dai (1).

I'm unsure about the rate rules for reception on the TK pin when
outputting LRCLK and the rate rules for transmitting on the RK pin
when inputting LRCLK. The datasheet for my chip (SAMA5D31) doesn't
say anything about what rates are allowed when using the RK pin
for transmitting or the TK pin for receiving.

Another question I have is if these rate rules are the same across
all chips supported by this driver, or if there is need for some
amount of special casing? And what special casing if that is the
case?

The reason I'm digging around in this area is that I need support
for inputting a BCK of 16MHz on the TK pin during playback, i.e.
with the codec mastering BCK. And the only way I can get that is
to use _CBM_CFS. My SSC master clock is 66MHz, which means that
the max supported rate for _CBM_CFM is 11MHz, i.e. not enough.

This patch unlocks my use case, but I would like to correctly stop
rates that the SSC does not support in other use cases as well. I
simply do not have the hardware to fully test this myself.

An lastly, is it reasonable to deduct 500ppm to allow for some
clock skew? FYI, the 500ppm was pulled out of my hat...

Cheers,
Peter

(1) ASoC: atmel_ssc_dai: Support SND_SOC_DAIFMT_CBM_CFS on I2S
https://lkml.org/lkml/2015/1/29/373

diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
index f55f3aab8bdd..11eab65c86c8 100644
--- a/sound/soc/atmel/atmel_ssc_dai.c
+++ b/sound/soc/atmel/atmel_ssc_dai.c
@@ -187,6 +187,76 @@ static irqreturn_t atmel_ssc_interrupt(int irq, void 
*dev_id)
return IRQ_HANDLED;
 }
 
+static int atmel_ssc_hw_rule_rate(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+   struct atmel_ssc_info *ssc_p = rule-private;
+   struct ssc_device *ssc = ssc_p-ssc;
+   struct snd_interval *i = hw_param_interval(params, rule-var);
+   struct snd_interval t;
+   struct snd_ratnum r = {
+   .den_min = 1,
+   .den_max = 4095,
+   .den_step = 1,
+   };
+   unsigned int num = 0, den = 0;
+   int frame_size;
+   int mck_div = 2;
+   int ret;
+
+   frame_size = snd_soc_params_to_frame_size(params);
+   if (frame_size  0)
+   return frame_size;
+
+   switch (ssc_p-daifmt  SND_SOC_DAIFMT_MASTER_MASK) {
+   case SND_SOC_DAIFMT_CBM_CFS:
+   if ((ssc_p-dir_mask  SSC_DIR_MASK_CAPTURE)
+ssc-clk_from_rk_pin)
+   /* Receiver Frame Synchro is output on RK pin.
+* What rules are there when outputting on the TK pin?
+*/
+   mck_div = 3;
+   break;
+
+   case SND_SOC_DAIFMT_CBM_CFM:
+   if ((ssc_p-dir_mask  SSC_DIR_MASK_PLAYBACK)
+!ssc-clk_from_rk_pin)
+   /* Transmit Frame Synchro is input on TK pin.
+* What rules are there when inputting from the RK pin?
+*/
+   mck_div = 6;
+   break;
+   }
+
+   switch (ssc_p-daifmt  SND_SOC_DAIFMT_MASTER_MASK) {
+   case SND_SOC_DAIFMT_CBS_CFS:
+   r.num = ssc_p-mck_rate / mck_div / frame_size;
+
+   ret = snd_interval_ratnum(i, 1, r, num, den);
+   if (ret = 0  den  rule-var == SNDRV_PCM_HW_PARAM_RATE) {
+   params-rate_num = num;
+   params-rate_den = den;
+   }
+   break;
+
+   case SND_SOC_DAIFMT_CBM_CFS:
+   case SND_SOC_DAIFMT_CBM_CFM:
+   t.min = 8000;
+   t.max = ssc_p-mck_rate / mck_div / frame_size;
+   /* Take away 500ppm, just to be on the safe side. */
+   t.max -= t.max / 2000;
+   t.openmin = t.openmax = 0;
+   t.integer = 0;
+   ret = snd_interval_refine(i, t);
+   break;
+
+   default:
+   ret = -EINVAL;
+   break;
+   }
+
+   return ret;
+}
 
 /*-*\
  * DAI functions
@@ -200,10 +270,17 @@ static int atmel_ssc_startup(struct snd_pcm_substream 
*substream,
struct atmel_ssc_info *ssc_p = ssc_info[dai-id

Re: [PATCH] adm8211: fix checkpatch errors for indentation and new line around switch-case

2015-05-05 Thread Peter Rosin
 diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c
 index f07a618..058fb4b 100644
 --- a/drivers/net/wireless/adm8211.c
 +++ b/drivers/net/wireless/adm8211.c
 @@ -1098,14 +1098,18 @@ static void adm8211_hw_init(struct ieee80211_hw *dev)
   pci_read_config_byte(priv-pdev, PCI_CACHE_LINE_SIZE, cline);
  
   switch (cline) {
 - case  0x8: reg |= (0x1  14);
 -break;
 - case 0x16: reg |= (0x2  14);
 -break;
 - case 0x32: reg |= (0x3  14);
 -break;
 -   default: reg |= (0x0  14);
 -break;
 + case  0x8:
 + reg |= (0x1  14);
 + break;
 + case 0x16:
 + reg |= (0x2  14);
 + break;
 + case 0x32:
 + reg |= (0x3  14);
 + break;
 + default:
 + reg |= (0x0  14);
 + break;
   }
   }
  

Those 0x16/0x32 hexadecimal case-selectors looking suspiciously like
decimal bits need a comment if they are in fact correct, which I doubt.

Cheers,
Peter

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


RE: [PATCH] ASoC: tfa9879: Fix return value check in tfa9879_i2c_probe()

2015-04-16 Thread Peter Rosin
Wei Yongjun wrote:
 In case of error, the function devm_kzalloc() returns NULL not ERR_PTR().
 The IS_ERR() test in the return value check should be replaced with NULL
 test.

Acked-by: Peter Rosin p...@axentia.se

Thanks,
Peter

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH] i2c: at91: fix write transfers by clearing pending interrupt first

2015-10-19 Thread Peter Rosin
On 2015-10-19 10:51, Ludovic Desroches wrote:
> Hi Peter,
> 
> On Fri, Oct 16, 2015 at 11:08:42AM +0200, Peter Rosin wrote:
>> On 2015-10-16 01:47, Peter Rosin wrote:
>>> On 2015-10-14 07:43, Ludovic Desroches wrote:
>>>> On Tue, Oct 13, 2015 at 08:01:34PM +0200, Peter Rosin wrote:
>>>>> On 2015-10-13 18:47, Cyrille Pitchen wrote:
>>>>>> Le 13/10/2015 17:19, Peter Rosin a écrit :
>>>>>>> On 2015-10-13 16:21, Ludovic Desroches wrote:
> 
> [...]
> 
>>> I have started to get this when I run with this patch:
>>>
>>> [   73.31] at91_i2c f0014000.i2c: RXRDY still set!
>>> [  198.20] at91_i2c f0014000.i2c: RXRDY still set!
>>> [  509.88] at91_i2c f0014000.i2c: RXRDY still set!
>>> [  615.75] at91_i2c f0014000.i2c: RXRDY still set!
>>> [  617.75] at91_i2c f0014000.i2c: RXRDY still set!
>>> [ 1766.64] at91_i2c f0014000.i2c: RXRDY still set!
>>> [ 2035.38] at91_i2c f0014000.i2c: RXRDY still set!
>>> [ 2227.19] at91_i2c f0014000.i2c: RXRDY still set!
>>> [ 2313.10] at91_i2c f0014000.i2c: RXRDY still set!
>>>
>>> My USB serial dongle was hung which was why I didn't notice until just now.
>>>
>>> This is probably not when communication with the eeprom though, and 
>>> certainly not
>>> writing to it, but perhpaps when polling the temperature (using the jc42 
>>> driver).
>>> I'll investigate further in the morning to see if I can pinpoint it.
>>
>> Yep, it's the jc42 accesses that triggers this (to the same chip as the
>> eeprom, but a different block of transistors I suppose).
>>
>> Looking at the i2c bus, the accesses normally go like this:
>>
>> [0.00] S 0x18 W 0x05 S 0x18 R 0xc1 0xbe NACK P
>> [0.000521] S 0x18 W 0x04 S 0x18 R 0x00 0x00 NACK P
>> [0.001024] S 0x18 W 0x03 S 0x18 R 0x00 0x00 NACK P
>> [0.001524] S 0x18 W 0x02 S 0x18 R 0x00 0x00 NACK P
>> [0.196991] S 0x18 W 0x05 S 0x18 R 0xc1 0xbe NACK P
>> [0.197514] S 0x18 W 0x04 S 0x18 R 0x00 0x00 NACK P
>> [0.198019] S 0x18 W 0x03 S 0x18 R 0x00 0x00 NACK P
>> [0.198520] S 0x18 W 0x02 S 0x18 R 0x00 0x00 NACK P
>>
>> I.e. chunks of four transfers every ~200 ms (I removed the 1Hz rate
>> limiter in the jc42 driver to get more frequent incidents).
>>
>> But when the diagnostic (RXRDY still set!) is output it continues
>> with this:
>>
>> [0.399755] S 0x18 W 0x05 S 0x18 R 0xc1 0xbe NACK P
>> [0.404998] S 0x18 W 0x04 S 0x18 R 0x00 0x00 NACK P
>> [0.405508] S 0x18 W 0x03 S 0x18 R 0x00 0x00 NACK P
>> [0.406008] S 0x18 W 0x02 S 0x18 R 0x00 0x00 NACK P
>>
>> Notice the ~5 ms delay (about the time it should take to output
>> the diagnostic at 115200 baud) after the access to register 0x05
>> at 0.399755.
>>
>> This is the only thing that I can observe on the bus, so it appears
>> to be harmless.
>>
>> It appears that the i2c access at 0.399755 finds the TWI
>> registers in an odd state, but nothing from the access at
>> 0.198520 appears to have gone wrong. Is this a race? Anyway,
>> the diagnostic is pretty frequent and annoying. printk_once?
> 
> I'll try to reproduce it on my side. The only issue you have is having
> the message about RXRDY? I mean no issue with i2c transfers?

Exactly, the only issue is the message, the bus looks good and transfers
work as they should AFAICT.

> It is not the possible bug we had in mind, this bug will prevent the
> master device to release the i2c bus. It will stop the transfer but
> without sending a stop on the bus.

Agreed, this is not about the extra frame caused by the spurious write
to the THR register. This is something else.

One suspicion is that the driver gets an unexpected irq from its own
NACK (the one that it puts out to end the read) and races with the
expected interrupt at TXCOMP?

Cheers,
Peter

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH] i2c: at91: fix write transfers by clearing pending interrupt first

2015-10-15 Thread Peter Rosin
On 2015-10-14 07:43, Ludovic Desroches wrote:
> On Tue, Oct 13, 2015 at 08:01:34PM +0200, Peter Rosin wrote:
>> On 2015-10-13 18:47, Cyrille Pitchen wrote:
>>> Le 13/10/2015 17:19, Peter Rosin a écrit :
>>>> On 2015-10-13 16:21, Ludovic Desroches wrote:
>>>>> From: Cyrille Pitchen <cyrille.pitc...@atmel.com>
>>>>>
>>>>> In some cases a NACK interrupt may be pending in the Status Register (SR)
>>>>> as a result of a previous transfer. However at91_do_twi_transfer() did not
>>>>> read the SR to clear pending interruptions before starting a new transfer.
>>>>> Hence a NACK interrupt rose as soon as it was enabled again at the I2C
>>>>> controller level, resulting in a wrong sequence of operations and strange
>>>>> patterns of behaviour on the I2C bus, such as a clock stretch followed by
>>>>> a restart of the transfer.
>>>>>
>>>>> This first issue occurred with both DMA and PIO write transfers.
>>>>>
>>>>> Also when a NACK error was detected during a PIO write transfer, the
>>>>> interrupt handler used to wrongly start a new transfer by writing into the
>>>>> Transmit Holding Register (THR). Then the I2C slave was likely to reply
>>>>> with a second NACK.
>>>>>
>>>>> This second issue is fixed in atmel_twi_interrupt() by handling the TXRDY
>>>>> status bit only if both the TXCOMP and NACK status bits are cleared.
>>>>>
>>>>> Tested with a at24 eeprom on sama5d36ek board running a linux-4.1-at91
>>>>> kernel image. Adapted to linux-next.
>>>>>
>>>>> Signed-off-by: Cyrille Pitchen <cyrille.pitc...@atmel.com>
>>>>> Fixes: 93563a6a71bb ("i2c: at91: fix a race condition when using the DMA 
>>>>> controller")
>>>>> Reported-by: Peter Rosin <p...@lysator.liu.se>
>>>>> Signed-off-by: Ludovic Desroches <ludovic.desroc...@atmel.com>
>>>>> Cc: sta...@vger.kernel.org #4.1
>>>>
>>>> The regression is gone with this patch (vanilla 4.2), thank you!
>>>>
>>>> However, looking at the bus, there are two NACKs after each
>>>> successful chunk of memory written by the eeprom driver.
>>>>
>>>> Looking at the eeprom driver, I expect this on the bus:
>>>>
>>>> S 0x50 0x00 "hello there guys" P
>>>> S 0x50 NACK P
>>>> delay for at least 1 ms (since the eeprom driver has a msleep(1) call).
>>>> S 0x50 NACK P
>>>> delay for at least 1 ms
>>>> ...
>>>> ...
>>>> S 0x50 NACK P
>>>> delay for at least 1 ms
>>>> S 0x50 0x10 "and girls\n" P
>>>>
>>>> This is not what I observe on the bus, most of the time there is a
>>>> second NACK immediately following the first. I suspect that it is
>>>> the i2c bus driver that somehow confuses itself and reissues the
>>>> command for some reason?
>>>>
>>>> But this behavior has been there since the beginning, so it's probably
>>>> orthogonal, and killing the data corrupting regression is much more
>>>> important to me than fussing over a surplus failed transfer. Hence
>>>>
>>>> Tested-by: Peter Rosin <p...@lysator.liu.se>
>>>>
>>>> Cheers,
>>>> Peter
>>>>
>>>
>>> Hi Peter,
>>>
>>> sama5d3x and sama5d4x don't support the so called "Alternative Command mode"
>>> whereas sama5d2x do. The Alternative Command mode comes with a new hardware
>>> mechanism inside the I2C controller which locks the transmission of data on
>>> the I2C bus when a NACK is detected. It means that even if a data is written
>>> into the THR, the I2C controller doesn't push this data on the I2C bus but
>>> retains the data in the THR (and its associated FIFO for sama5d2x and future
>>> SoCs) until the driver unlocks the transmitter by writing the LOCKCLR (Lock
>>> Clear) bit in the Control Register. Then and only then, the transmitter 
>>> outputs
>>> pending data again.
>>> This new mechanism was introduced to cope with an unwanted DMA write into 
>>> the
>>> THR after a NACK. Indeed, as I've tried to explain in my patch, when a first
>>> NACK is detected, the I2C controller sets the TXCOMP, NACK and TXRDY bits
>>> alltogether in the Status Register. However s

Re: [PATCH] i2c: at91: fix write transfers by clearing pending interrupt first

2015-10-16 Thread Peter Rosin
On 2015-10-16 01:47, Peter Rosin wrote:
> On 2015-10-14 07:43, Ludovic Desroches wrote:
>> On Tue, Oct 13, 2015 at 08:01:34PM +0200, Peter Rosin wrote:
>>> On 2015-10-13 18:47, Cyrille Pitchen wrote:
>>>> Le 13/10/2015 17:19, Peter Rosin a écrit :
>>>>> On 2015-10-13 16:21, Ludovic Desroches wrote:
>>>>>> From: Cyrille Pitchen <cyrille.pitc...@atmel.com>
>>>>>>
>>>>>> In some cases a NACK interrupt may be pending in the Status Register (SR)
>>>>>> as a result of a previous transfer. However at91_do_twi_transfer() did 
>>>>>> not
>>>>>> read the SR to clear pending interruptions before starting a new 
>>>>>> transfer.
>>>>>> Hence a NACK interrupt rose as soon as it was enabled again at the I2C
>>>>>> controller level, resulting in a wrong sequence of operations and strange
>>>>>> patterns of behaviour on the I2C bus, such as a clock stretch followed by
>>>>>> a restart of the transfer.
>>>>>>
>>>>>> This first issue occurred with both DMA and PIO write transfers.
>>>>>>
>>>>>> Also when a NACK error was detected during a PIO write transfer, the
>>>>>> interrupt handler used to wrongly start a new transfer by writing into 
>>>>>> the
>>>>>> Transmit Holding Register (THR). Then the I2C slave was likely to reply
>>>>>> with a second NACK.
>>>>>>
>>>>>> This second issue is fixed in atmel_twi_interrupt() by handling the TXRDY
>>>>>> status bit only if both the TXCOMP and NACK status bits are cleared.
>>>>>>
>>>>>> Tested with a at24 eeprom on sama5d36ek board running a linux-4.1-at91
>>>>>> kernel image. Adapted to linux-next.
>>>>>>
>>>>>> Signed-off-by: Cyrille Pitchen <cyrille.pitc...@atmel.com>
>>>>>> Fixes: 93563a6a71bb ("i2c: at91: fix a race condition when using the DMA 
>>>>>> controller")
>>>>>> Reported-by: Peter Rosin <p...@lysator.liu.se>
>>>>>> Signed-off-by: Ludovic Desroches <ludovic.desroc...@atmel.com>
>>>>>> Cc: sta...@vger.kernel.org #4.1
>>>>>
>>>>> The regression is gone with this patch (vanilla 4.2), thank you!
>>>>>
>>>>> However, looking at the bus, there are two NACKs after each
>>>>> successful chunk of memory written by the eeprom driver.
>>>>>
>>>>> Looking at the eeprom driver, I expect this on the bus:
>>>>>
>>>>> S 0x50 0x00 "hello there guys" P
>>>>> S 0x50 NACK P
>>>>> delay for at least 1 ms (since the eeprom driver has a msleep(1) call).
>>>>> S 0x50 NACK P
>>>>> delay for at least 1 ms
>>>>> ...
>>>>> ...
>>>>> S 0x50 NACK P
>>>>> delay for at least 1 ms
>>>>> S 0x50 0x10 "and girls\n" P
>>>>>
>>>>> This is not what I observe on the bus, most of the time there is a
>>>>> second NACK immediately following the first. I suspect that it is
>>>>> the i2c bus driver that somehow confuses itself and reissues the
>>>>> command for some reason?
>>>>>
>>>>> But this behavior has been there since the beginning, so it's probably
>>>>> orthogonal, and killing the data corrupting regression is much more
>>>>> important to me than fussing over a surplus failed transfer. Hence
>>>>>
>>>>> Tested-by: Peter Rosin <p...@lysator.liu.se>
>>>>>
>>>>> Cheers,
>>>>> Peter
>>>>>
>>>>
>>>> Hi Peter,
>>>>
>>>> sama5d3x and sama5d4x don't support the so called "Alternative Command 
>>>> mode"
>>>> whereas sama5d2x do. The Alternative Command mode comes with a new hardware
>>>> mechanism inside the I2C controller which locks the transmission of data on
>>>> the I2C bus when a NACK is detected. It means that even if a data is 
>>>> written
>>>> into the THR, the I2C controller doesn't push this data on the I2C bus but
>>>> retains the data in the THR (and its associated FIFO for sama5d2x and 
>>>> future
>>>> SoCs) until the driver unlocks the transmitter by writing the LOCKCLR (Loc

Re: [PATCH] i2c: at91: fix write transfers by clearing pending interrupt first

2015-10-21 Thread Peter Rosin
On 2015-10-20 15:27, Ludovic Desroches wrote:
> On Mon, Oct 19, 2015 at 12:49:03PM +0200, Peter Rosin wrote:
>> On 2015-10-19 10:51, Ludovic Desroches wrote:
>>> Hi Peter,
>>>
>>> On Fri, Oct 16, 2015 at 11:08:42AM +0200, Peter Rosin wrote:
>>>> On 2015-10-16 01:47, Peter Rosin wrote:
>>>>> On 2015-10-14 07:43, Ludovic Desroches wrote:
>>>>>> On Tue, Oct 13, 2015 at 08:01:34PM +0200, Peter Rosin wrote:
>>>>>>> On 2015-10-13 18:47, Cyrille Pitchen wrote:
>>>>>>>> Le 13/10/2015 17:19, Peter Rosin a écrit :
>>>>>>>>> On 2015-10-13 16:21, Ludovic Desroches wrote:
>>>
>>> [...]
>>>
>>>>> I have started to get this when I run with this patch:
>>>>>
>>>>> [   73.31] at91_i2c f0014000.i2c: RXRDY still set!
>>>>> [  198.20] at91_i2c f0014000.i2c: RXRDY still set!
>>>>> [  509.88] at91_i2c f0014000.i2c: RXRDY still set!
>>>>> [  615.75] at91_i2c f0014000.i2c: RXRDY still set!
>>>>> [  617.75] at91_i2c f0014000.i2c: RXRDY still set!
>>>>> [ 1766.64] at91_i2c f0014000.i2c: RXRDY still set!
>>>>> [ 2035.38] at91_i2c f0014000.i2c: RXRDY still set!
>>>>> [ 2227.19] at91_i2c f0014000.i2c: RXRDY still set!
>>>>> [ 2313.10] at91_i2c f0014000.i2c: RXRDY still set!
>>>>>
>>>>> My USB serial dongle was hung which was why I didn't notice until just 
>>>>> now.
>>>>>
>>>>> This is probably not when communication with the eeprom though, and 
>>>>> certainly not
>>>>> writing to it, but perhpaps when polling the temperature (using the jc42 
>>>>> driver).
>>>>> I'll investigate further in the morning to see if I can pinpoint it.
>>>>
>>>> Yep, it's the jc42 accesses that triggers this (to the same chip as the
>>>> eeprom, but a different block of transistors I suppose).
>>>>
>>>> Looking at the i2c bus, the accesses normally go like this:
>>>>
>>>> [0.00] S 0x18 W 0x05 S 0x18 R 0xc1 0xbe NACK P
>>>> [0.000521] S 0x18 W 0x04 S 0x18 R 0x00 0x00 NACK P
>>>> [0.001024] S 0x18 W 0x03 S 0x18 R 0x00 0x00 NACK P
>>>> [0.001524] S 0x18 W 0x02 S 0x18 R 0x00 0x00 NACK P
>>>> [0.196991] S 0x18 W 0x05 S 0x18 R 0xc1 0xbe NACK P
>>>> [0.197514] S 0x18 W 0x04 S 0x18 R 0x00 0x00 NACK P
>>>> [0.198019] S 0x18 W 0x03 S 0x18 R 0x00 0x00 NACK P
>>>> [0.198520] S 0x18 W 0x02 S 0x18 R 0x00 0x00 NACK P
>>>>
>>>> I.e. chunks of four transfers every ~200 ms (I removed the 1Hz rate
>>>> limiter in the jc42 driver to get more frequent incidents).
>>>>
>>>> But when the diagnostic (RXRDY still set!) is output it continues
>>>> with this:
>>>>
>>>> [0.399755] S 0x18 W 0x05 S 0x18 R 0xc1 0xbe NACK P
>>>> [0.404998] S 0x18 W 0x04 S 0x18 R 0x00 0x00 NACK P
>>>> [0.405508] S 0x18 W 0x03 S 0x18 R 0x00 0x00 NACK P
>>>> [0.406008] S 0x18 W 0x02 S 0x18 R 0x00 0x00 NACK P
>>>>
>>>> Notice the ~5 ms delay (about the time it should take to output
>>>> the diagnostic at 115200 baud) after the access to register 0x05
>>>> at 0.399755.
>>>>
>>>> This is the only thing that I can observe on the bus, so it appears
>>>> to be harmless.
>>>>
>>>> It appears that the i2c access at 0.399755 finds the TWI
>>>> registers in an odd state, but nothing from the access at
>>>> 0.198520 appears to have gone wrong. Is this a race? Anyway,
>>>> the diagnostic is pretty frequent and annoying. printk_once?
>>>
>>> I'll try to reproduce it on my side. The only issue you have is having
>>> the message about RXRDY? I mean no issue with i2c transfers?
>>
>> Exactly, the only issue is the message, the bus looks good and transfers
>> work as they should AFAICT.
>>> It is not the possible bug we had in mind, this bug will prevent the
>>> master device to release the i2c bus. It will stop the transfer but
>>> without sending a stop on the bus.
>>
>> Agreed, this is not about the extra frame caused by the spurious write
>> to the THR register. This is something else.
>>
>> One suspicion is that the driver gets an unexpected irq from its own
>> NACK (the one that it puts out to end the read) and races with the
>> expected interrupt a

Re: [PATCH] i2c: at91: fix write transfers by clearing pending interrupt first

2015-10-21 Thread Peter Rosin
On 2015-10-21 09:21, Peter Rosin wrote:
> On 2015-10-20 15:27, Ludovic Desroches wrote:
>> On Mon, Oct 19, 2015 at 12:49:03PM +0200, Peter Rosin wrote:
>>> On 2015-10-19 10:51, Ludovic Desroches wrote:
>>>> Hi Peter,
>>>>
>>>> On Fri, Oct 16, 2015 at 11:08:42AM +0200, Peter Rosin wrote:
>>>>> On 2015-10-16 01:47, Peter Rosin wrote:
>>>>>> On 2015-10-14 07:43, Ludovic Desroches wrote:
>>>>>>> On Tue, Oct 13, 2015 at 08:01:34PM +0200, Peter Rosin wrote:
>>>>>>>> On 2015-10-13 18:47, Cyrille Pitchen wrote:
>>>>>>>>> Le 13/10/2015 17:19, Peter Rosin a écrit :
>>>>>>>>>> On 2015-10-13 16:21, Ludovic Desroches wrote:
>>>>
>>>> [...]
>>>>
>>>>>> I have started to get this when I run with this patch:
>>>>>>
>>>>>> [   73.31] at91_i2c f0014000.i2c: RXRDY still set!
>>>>>> [  198.20] at91_i2c f0014000.i2c: RXRDY still set!
>>>>>> [  509.88] at91_i2c f0014000.i2c: RXRDY still set!
>>>>>> [  615.75] at91_i2c f0014000.i2c: RXRDY still set!
>>>>>> [  617.75] at91_i2c f0014000.i2c: RXRDY still set!
>>>>>> [ 1766.64] at91_i2c f0014000.i2c: RXRDY still set!
>>>>>> [ 2035.38] at91_i2c f0014000.i2c: RXRDY still set!
>>>>>> [ 2227.19] at91_i2c f0014000.i2c: RXRDY still set!
>>>>>> [ 2313.10] at91_i2c f0014000.i2c: RXRDY still set!
>>>>>>
>>>>>> My USB serial dongle was hung which was why I didn't notice until just 
>>>>>> now.
>>>>>>
>>>>>> This is probably not when communication with the eeprom though, and 
>>>>>> certainly not
>>>>>> writing to it, but perhpaps when polling the temperature (using the jc42 
>>>>>> driver).
>>>>>> I'll investigate further in the morning to see if I can pinpoint it.
>>>>>
>>>>> Yep, it's the jc42 accesses that triggers this (to the same chip as the
>>>>> eeprom, but a different block of transistors I suppose).
>>>>>
>>>>> Looking at the i2c bus, the accesses normally go like this:
>>>>>
>>>>> [0.00] S 0x18 W 0x05 S 0x18 R 0xc1 0xbe NACK P
>>>>> [0.000521] S 0x18 W 0x04 S 0x18 R 0x00 0x00 NACK P
>>>>> [0.001024] S 0x18 W 0x03 S 0x18 R 0x00 0x00 NACK P
>>>>> [0.001524] S 0x18 W 0x02 S 0x18 R 0x00 0x00 NACK P
>>>>> [0.196991] S 0x18 W 0x05 S 0x18 R 0xc1 0xbe NACK P
>>>>> [0.197514] S 0x18 W 0x04 S 0x18 R 0x00 0x00 NACK P
>>>>> [0.198019] S 0x18 W 0x03 S 0x18 R 0x00 0x00 NACK P
>>>>> [0.198520] S 0x18 W 0x02 S 0x18 R 0x00 0x00 NACK P
>>>>>
>>>>> I.e. chunks of four transfers every ~200 ms (I removed the 1Hz rate
>>>>> limiter in the jc42 driver to get more frequent incidents).
>>>>>
>>>>> But when the diagnostic (RXRDY still set!) is output it continues
>>>>> with this:
>>>>>
>>>>> [0.399755] S 0x18 W 0x05 S 0x18 R 0xc1 0xbe NACK P
>>>>> [0.404998] S 0x18 W 0x04 S 0x18 R 0x00 0x00 NACK P
>>>>> [0.405508] S 0x18 W 0x03 S 0x18 R 0x00 0x00 NACK P
>>>>> [0.406008] S 0x18 W 0x02 S 0x18 R 0x00 0x00 NACK P
>>>>>
>>>>> Notice the ~5 ms delay (about the time it should take to output
>>>>> the diagnostic at 115200 baud) after the access to register 0x05
>>>>> at 0.399755.
>>>>>
>>>>> This is the only thing that I can observe on the bus, so it appears
>>>>> to be harmless.
>>>>>
>>>>> It appears that the i2c access at 0.399755 finds the TWI
>>>>> registers in an odd state, but nothing from the access at
>>>>> 0.198520 appears to have gone wrong. Is this a race? Anyway,
>>>>> the diagnostic is pretty frequent and annoying. printk_once?
>>>>
>>>> I'll try to reproduce it on my side. The only issue you have is having
>>>> the message about RXRDY? I mean no issue with i2c transfers?
>>>
>>> Exactly, the only issue is the message, the bus looks good and transfers
>>> work as they should AFAICT.
>>>> It is not the possible bug we had in mind, this bug will prevent the
>>>> master device to release the i2c bus. It will stop the transfer but
>>>> without 

Re: Regression: at24 eeprom writing

2015-10-12 Thread Peter Rosin
On 2015-10-05 17:09, Peter Rosin wrote:
> But what trouble does the i2c bus driver see? Admittedly I only
> have a simple logic level bus viewer, and not a full-blown
> oscilloscope, so there might be something analogue going on?
> I don't think so though, those signals looked fine last time we
> looked (but we obviously didn't have these issues then, and
> didn't really look that closely). I'll see if I can recheck
> with a real scope too.

We redid the tests with a real scope, and the signal looks nice
and square, so it is not that.

Speculating further on the cause of the long ACKs, I think that
the i2c driver gets confused by an interrupt that marks the
transfer complete, and thinks it's a NACK interrupt instead. Is that
plausible?

If the peripheral unit is such that it generates a stop automatically
on NACKs, then this makes perfect sense. I.e. the TWI sees that the
transfer is complete, generates an interrupt, and waits for further
data or a stop command. Meanwhile the driver thinks it's a NACK and
that a stop condition has already been sent to the bus, and just
notifies the i2c consumer (the eeprom driver in this case) of the
failure and frees up the bus for any future user.

This also matches what I see when I turn on some more traffic on the
bus, that is interleaved with the eeprom traffic. AFAICT, it can be
any command that gets chewed up by the eeprom if it is sent to the
i2c driver during the long ACK.

Are you Atmel people making any progress on this data corrupting
regression? Is there anything else I can do to help?

Cheers,
Peter
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: Regression: at24 eeprom writing

2015-10-13 Thread Peter Rosin
On 2015-10-12 18:13, Cyrille Pitchen wrote:
> Le 12/10/2015 17:13, Peter Rosin a écrit :
>> On 2015-10-05 17:09, Peter Rosin wrote:
>>> But what trouble does the i2c bus driver see? Admittedly I only
>>> have a simple logic level bus viewer, and not a full-blown
>>> oscilloscope, so there might be something analogue going on?
>>> I don't think so though, those signals looked fine last time we
>>> looked (but we obviously didn't have these issues then, and
>>> didn't really look that closely). I'll see if I can recheck
>>> with a real scope too.
>>
>> We redid the tests with a real scope, and the signal looks nice
>> and square, so it is not that.
>>
>> Speculating further on the cause of the long ACKs, I think that
>> the i2c driver gets confused by an interrupt that marks the
>> transfer complete, and thinks it's a NACK interrupt instead. Is that
>> plausible?
>>
>> If the peripheral unit is such that it generates a stop automatically
>> on NACKs, then this makes perfect sense. I.e. the TWI sees that the
>> transfer is complete, generates an interrupt, and waits for further
>> data or a stop command. Meanwhile the driver thinks it's a NACK and
>> that a stop condition has already been sent to the bus, and just
>> notifies the i2c consumer (the eeprom driver in this case) of the
>> failure and frees up the bus for any future user.
>>
>> This also matches what I see when I turn on some more traffic on the
>> bus, that is interleaved with the eeprom traffic. AFAICT, it can be
>> any command that gets chewed up by the eeprom if it is sent to the
>> i2c driver during the long ACK.
>>
>> Are you Atmel people making any progress on this data corrupting
>> regression? Is there anything else I can do to help?
>>
>> Cheers,
>> Peter
>>
> 
> Hi Peter,
> 
> I have sent a patch to Ludovic for a first internal review before publishing 
> to
> mainline. The patch should fix your issue since it fixes it on my sama5d36ek
> board with an at24 eeprom.
> 
> More details on the reason of this bug would be provided in both the commit
> message and comments in the code provided by the reviewed patch but I you want
> an early fix just read the Status Register (AT91_TWI_SR) at the beginning of
> at91_do_twi_transfer(). This read clears the NACK bit in the Status Register.
> Then the following source code can safely enable the NACK interrupt, otherwise
> in some cases a pending NACK interrupt would rise immediately after the line:
> at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_NACK);
> hence breaking the sequence of operations to be done because the interrupt
> handler would call complete() too early so wait_for_completion_timeout()
> also exits too early.
> 
> So reading the Status Register at the beginning of at91_do_twi_transfer()
> should be enough to fix the issue.

Yes, I see no more long ACKs after that reading the Status Register there.
Great!

> Another mistake is in the interrupt handler itself, ie atmel_twi_interrupt():
> we should check the TWI_TXRDY status bit before calling
> at91_twi_write_next_byte() only if both the TWI_TXCOMP and TWI_NACK status 
> bits
> are clear. Otherwise, writing a new byte into the THR tells the I2C controller
> to start a new transfer. Then the I2C slave, the at24 eeprom, is likely to
> also reply by a second NACK. Hence the NACK bit is already set into the Status
> Register on the next call of at91_do_twi_transfer().
> This is what I saw on my scope for PIO transfers.

I interpret this as a proposed solution for the strange double NACKs?

Anyway, I find it unnecessarily hard to grasp exactly what you mean
(wasteful policy you are apparently suffering from where it is OK to
publish a patch written in English, but apparently a big no-no to
send a diff until it passes some internal review???). I interpreted
your "patch" in English as:

at91_twi_read_next_byte(dev);
-   else if (irqstatus & AT_TWI_TXRDY)
+   else if ((irqstatus & (AT91_TWI_TXCOMP | AT91_TWI_TXRDY | 
AT91_TWI_NACK)) == AT91_TWI_TXRDY)
at91_twi_write_next_byte(dev);

But still see some double NACKs. Not always though, and it doesn't wreak
any havoc. But it still looks strange and I can't explain them when looking
at what the eeprom driver requests. Does this mean that there are more
races present?

Or, did I just parse your English "patch" badly?

> By the way, in my case, the first NACK occurs because the at24 driver tries to
> perform a second write transfer too quickly and the eeprom is not ready yet,
> then replies with a NACK.

Yes, I believe this is by design. Noone wants to encode the exact delays
needed since they are

Re: [PATCH] i2c: at91: fix write transfers by clearing pending interrupt first

2015-10-13 Thread Peter Rosin
On 2015-10-13 16:21, Ludovic Desroches wrote:
> From: Cyrille Pitchen <cyrille.pitc...@atmel.com>
> 
> In some cases a NACK interrupt may be pending in the Status Register (SR)
> as a result of a previous transfer. However at91_do_twi_transfer() did not
> read the SR to clear pending interruptions before starting a new transfer.
> Hence a NACK interrupt rose as soon as it was enabled again at the I2C
> controller level, resulting in a wrong sequence of operations and strange
> patterns of behaviour on the I2C bus, such as a clock stretch followed by
> a restart of the transfer.
> 
> This first issue occurred with both DMA and PIO write transfers.
> 
> Also when a NACK error was detected during a PIO write transfer, the
> interrupt handler used to wrongly start a new transfer by writing into the
> Transmit Holding Register (THR). Then the I2C slave was likely to reply
> with a second NACK.
> 
> This second issue is fixed in atmel_twi_interrupt() by handling the TXRDY
> status bit only if both the TXCOMP and NACK status bits are cleared.
> 
> Tested with a at24 eeprom on sama5d36ek board running a linux-4.1-at91
> kernel image. Adapted to linux-next.
> 
> Signed-off-by: Cyrille Pitchen <cyrille.pitc...@atmel.com>
> Fixes: 93563a6a71bb ("i2c: at91: fix a race condition when using the DMA 
> controller")
> Reported-by: Peter Rosin <p...@lysator.liu.se>
> Signed-off-by: Ludovic Desroches <ludovic.desroc...@atmel.com>
> Cc: sta...@vger.kernel.org #4.1

The regression is gone with this patch (vanilla 4.2), thank you!

However, looking at the bus, there are two NACKs after each
successful chunk of memory written by the eeprom driver.

Looking at the eeprom driver, I expect this on the bus:

S 0x50 0x00 "hello there guys" P
S 0x50 NACK P
delay for at least 1 ms (since the eeprom driver has a msleep(1) call).
S 0x50 NACK P
delay for at least 1 ms
...
...
S 0x50 NACK P
delay for at least 1 ms
S 0x50 0x10 "and girls\n" P

This is not what I observe on the bus, most of the time there is a
second NACK immediately following the first. I suspect that it is
the i2c bus driver that somehow confuses itself and reissues the
command for some reason?

But this behavior has been there since the beginning, so it's probably
orthogonal, and killing the data corrupting regression is much more
important to me than fussing over a surplus failed transfer. Hence

Tested-by: Peter Rosin <p...@lysator.liu.se>

Cheers,
Peter

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: Regression: at24 eeprom writing

2015-10-13 Thread Peter Rosin
On 2015-10-13 14:57, Nicolas Ferre wrote:
> Le 13/10/2015 12:38, Peter Rosin a écrit :
>> On 2015-10-12 18:13, Cyrille Pitchen wrote:
>>> Le 12/10/2015 17:13, Peter Rosin a écrit :
>>>> On 2015-10-05 17:09, Peter Rosin wrote:
>>>>> But what trouble does the i2c bus driver see? Admittedly I only
>>>>> have a simple logic level bus viewer, and not a full-blown
>>>>> oscilloscope, so there might be something analogue going on?
>>>>> I don't think so though, those signals looked fine last time we
>>>>> looked (but we obviously didn't have these issues then, and
>>>>> didn't really look that closely). I'll see if I can recheck
>>>>> with a real scope too.
>>>>
>>>> We redid the tests with a real scope, and the signal looks nice
>>>> and square, so it is not that.
>>>>
>>>> Speculating further on the cause of the long ACKs, I think that
>>>> the i2c driver gets confused by an interrupt that marks the
>>>> transfer complete, and thinks it's a NACK interrupt instead. Is that
>>>> plausible?
>>>>
>>>> If the peripheral unit is such that it generates a stop automatically
>>>> on NACKs, then this makes perfect sense. I.e. the TWI sees that the
>>>> transfer is complete, generates an interrupt, and waits for further
>>>> data or a stop command. Meanwhile the driver thinks it's a NACK and
>>>> that a stop condition has already been sent to the bus, and just
>>>> notifies the i2c consumer (the eeprom driver in this case) of the
>>>> failure and frees up the bus for any future user.
>>>>
>>>> This also matches what I see when I turn on some more traffic on the
>>>> bus, that is interleaved with the eeprom traffic. AFAICT, it can be
>>>> any command that gets chewed up by the eeprom if it is sent to the
>>>> i2c driver during the long ACK.
>>>>
>>>> Are you Atmel people making any progress on this data corrupting
>>>> regression? Is there anything else I can do to help?
>>>>
>>>> Cheers,
>>>> Peter
>>>>
>>>
>>> Hi Peter,
>>>
>>> I have sent a patch to Ludovic for a first internal review before 
>>> publishing to
>>> mainline. The patch should fix your issue since it fixes it on my sama5d36ek
>>> board with an at24 eeprom.
>>>
>>> More details on the reason of this bug would be provided in both the commit
>>> message and comments in the code provided by the reviewed patch but I you 
>>> want
>>> an early fix just read the Status Register (AT91_TWI_SR) at the beginning of
>>> at91_do_twi_transfer(). This read clears the NACK bit in the Status 
>>> Register.
>>> Then the following source code can safely enable the NACK interrupt, 
>>> otherwise
>>> in some cases a pending NACK interrupt would rise immediately after the 
>>> line:
>>> at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_NACK);
>>> hence breaking the sequence of operations to be done because the interrupt
>>> handler would call complete() too early so wait_for_completion_timeout()
>>> also exits too early.
>>>
>>> So reading the Status Register at the beginning of at91_do_twi_transfer()
>>> should be enough to fix the issue.
>>
>> Yes, I see no more long ACKs after that reading the Status Register there.
>> Great!
>>
>>> Another mistake is in the interrupt handler itself, ie 
>>> atmel_twi_interrupt():
>>> we should check the TWI_TXRDY status bit before calling
>>> at91_twi_write_next_byte() only if both the TWI_TXCOMP and TWI_NACK status 
>>> bits
>>> are clear. Otherwise, writing a new byte into the THR tells the I2C 
>>> controller
>>> to start a new transfer. Then the I2C slave, the at24 eeprom, is likely to
>>> also reply by a second NACK. Hence the NACK bit is already set into the 
>>> Status
>>> Register on the next call of at91_do_twi_transfer().
>>> This is what I saw on my scope for PIO transfers.
>>
>> I interpret this as a proposed solution for the strange double NACKs?
>>
>> Anyway, I find it unnecessarily hard to grasp exactly what you mean
>> (wasteful policy you are apparently suffering from where it is OK to
>> publish a patch written in English, but apparently a big no-no to
>> send a diff until it passes some internal review???). I interpreted
> 
> I find your remark pretty rude as I'm 

Re: [PATCH] i2c: at91: fix write transfers by clearing pending interrupt first

2015-10-13 Thread Peter Rosin
On 2015-10-13 18:47, Cyrille Pitchen wrote:
> Le 13/10/2015 17:19, Peter Rosin a écrit :
>> On 2015-10-13 16:21, Ludovic Desroches wrote:
>>> From: Cyrille Pitchen <cyrille.pitc...@atmel.com>
>>>
>>> In some cases a NACK interrupt may be pending in the Status Register (SR)
>>> as a result of a previous transfer. However at91_do_twi_transfer() did not
>>> read the SR to clear pending interruptions before starting a new transfer.
>>> Hence a NACK interrupt rose as soon as it was enabled again at the I2C
>>> controller level, resulting in a wrong sequence of operations and strange
>>> patterns of behaviour on the I2C bus, such as a clock stretch followed by
>>> a restart of the transfer.
>>>
>>> This first issue occurred with both DMA and PIO write transfers.
>>>
>>> Also when a NACK error was detected during a PIO write transfer, the
>>> interrupt handler used to wrongly start a new transfer by writing into the
>>> Transmit Holding Register (THR). Then the I2C slave was likely to reply
>>> with a second NACK.
>>>
>>> This second issue is fixed in atmel_twi_interrupt() by handling the TXRDY
>>> status bit only if both the TXCOMP and NACK status bits are cleared.
>>>
>>> Tested with a at24 eeprom on sama5d36ek board running a linux-4.1-at91
>>> kernel image. Adapted to linux-next.
>>>
>>> Signed-off-by: Cyrille Pitchen <cyrille.pitc...@atmel.com>
>>> Fixes: 93563a6a71bb ("i2c: at91: fix a race condition when using the DMA 
>>> controller")
>>> Reported-by: Peter Rosin <p...@lysator.liu.se>
>>> Signed-off-by: Ludovic Desroches <ludovic.desroc...@atmel.com>
>>> Cc: sta...@vger.kernel.org #4.1
>>
>> The regression is gone with this patch (vanilla 4.2), thank you!
>>
>> However, looking at the bus, there are two NACKs after each
>> successful chunk of memory written by the eeprom driver.
>>
>> Looking at the eeprom driver, I expect this on the bus:
>>
>> S 0x50 0x00 "hello there guys" P
>> S 0x50 NACK P
>> delay for at least 1 ms (since the eeprom driver has a msleep(1) call).
>> S 0x50 NACK P
>> delay for at least 1 ms
>> ...
>> ...
>> S 0x50 NACK P
>> delay for at least 1 ms
>> S 0x50 0x10 "and girls\n" P
>>
>> This is not what I observe on the bus, most of the time there is a
>> second NACK immediately following the first. I suspect that it is
>> the i2c bus driver that somehow confuses itself and reissues the
>> command for some reason?
>>
>> But this behavior has been there since the beginning, so it's probably
>> orthogonal, and killing the data corrupting regression is much more
>> important to me than fussing over a surplus failed transfer. Hence
>>
>> Tested-by: Peter Rosin <p...@lysator.liu.se>
>>
>> Cheers,
>> Peter
>>
> 
> Hi Peter,
> 
> sama5d3x and sama5d4x don't support the so called "Alternative Command mode"
> whereas sama5d2x do. The Alternative Command mode comes with a new hardware
> mechanism inside the I2C controller which locks the transmission of data on
> the I2C bus when a NACK is detected. It means that even if a data is written
> into the THR, the I2C controller doesn't push this data on the I2C bus but
> retains the data in the THR (and its associated FIFO for sama5d2x and future
> SoCs) until the driver unlocks the transmitter by writing the LOCKCLR (Lock
> Clear) bit in the Control Register. Then and only then, the transmitter 
> outputs
> pending data again.
> This new mechanism was introduced to cope with an unwanted DMA write into the
> THR after a NACK. Indeed, as I've tried to explain in my patch, when a first
> NACK is detected, the I2C controller sets the TXCOMP, NACK and TXRDY bits
> alltogether in the Status Register. However setting the TXRDY bit also 
> triggers
> the DMA controller to write the next data into the THR. Pitifully, WITHOUT the
> new lock mechanism, writing into the THR starts a new I2C frame. Since the
> eeprom is likely not to be ready yet, it replies by a second NACK. So you
> see on the scope two consecutive NACKs.
> 
> On sama5d3x and sama5d4x, which do not support this lock mechanism, you are
> likely to see a successful write transfer followed by two NACKs then a delay
> and finally a new successful write transfer. This is the case 2b:
> 
> 1 - A successfull write transfer is completed.
> 2 - The at24 driver immediately tries to perform the next write transfer...
> 3 - ... but the eeprom is not ready yet and replies with

Re: Regression: at24 eeprom writing

2015-10-04 Thread Peter Rosin
On 2015-10-03 01:05, Peter Rosin wrote:
> I looked around and found that if I revert 
> a839ce663b3183209fdf7b1fc4796bfe2a4679c3
> "eeprom: at24: extend driver to allow writing via i2c_smbus_write_byte_data"
> eeprom writing starts working again.
> 
> AFAICT, the i2c-at91 bus driver makes the eeprom driver use the
> i2c_transfer code path both with that patch and with it reverted,
> so I sadly don't see why the patch makes a difference.

And now when I retry the same thing, that patch is no longer affecting things.
I must have confused myself over what kernel was actually running. Christian,
please accept my deepest apologies for implicating you in this regression.

But the regression is still there. In short, linux-3.18-at91 from the
linux4sam tree works, linux-4.1-at91 from the same tree does not, and
vanilla 4.2 also doesn't work. I have a hard time bisecting this thing
though, since the last known good version has a long list of atmel
patches that I refuse to even try to rebase...

Ideas still welcome of course.

Cheers,
Peter
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: Regression: at24 eeprom writing

2015-10-05 Thread Peter Rosin
On 2015-10-03 01:05, Peter Rosin wrote:
> Hi!
> 
> I recently upgraded from the atmel linux-3.18-at91 kernel to vanilla 4.2
> and everything seemed fine. Until I tried to write to the little eeprom
> chip. I then tried the linux-4.1-at91 kernel and that suffers too.
> 
> The symptoms are that it seems like writes get interrupted, and restarted
> again without properly initializing everything again. Inspecting the i2c
> bus during these fails gets me something like this (int hex) when I
> 
> echo abcdefghijklmnopqr > /sys/bus/i2c/devices/0-0050/eeprom
> 
> S a0 00 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 P
> S a0 10 (clk and data low for a "long" time) 10 71 72 0a P
> 
> Notice how the address byte in the second chunk (10) is repeated after
> the strange event on the i2c bus.
> 
> I looked around and found that if I revert 
> a839ce663b3183209fdf7b1fc4796bfe2a4679c3
> "eeprom: at24: extend driver to allow writing via i2c_smbus_write_byte_data"
> eeprom writing starts working again.
> 
> AFAICT, the i2c-at91 bus driver makes the eeprom driver use the
> i2c_transfer code path both with that patch and with it reverted,
> so I sadly don't see why the patch makes a difference.
> 
> I'm on a board that is based on the sama5d31 evaluation kit, with a
> NXP SE97BTP,547 chip and this in the devicetree:
> 
>   i2c0: i2c@f0014000 {
>   status = "okay";
> 
>   jc42@18 {
>   compatible = "jc42";
>   reg = <0x18>;
>   };
> 
>   eeprom@50 {
>   compatible = "24c02";
>   reg = <0x50>;
>   pagesize = <16>;
>   };
>   };

Ok, I found the culprit, and I double and triple checked it this time...

If I move to the very latest on the linux-3.18-at91 branch, the bug is
there too. Which made it vastly more palatable to bisect the bug.

The offender (in the 4.2 kernel) is 93563a6a71bb69dd324fc7354c60fb05f84aae6b
"i2c: at91: fix a race condition when using the DMA controller"
which is far more understandable. Ao, adding Cyrille Pitchen to the Cc list.

If I add that patch on top of my previously working tree, it behaves just
as newer kernels, i.e. equally bad. The patch doesn't revert cleanly, but
reverting the patch and quick-n-dirty-fixing the conflict on vanilla 4.2
makes the problem go away.

I have attached what I actually reverted.

Cheers,
Peter

>From d178e0636358e61503ac55d39c8612ef93c1d893 Mon Sep 17 00:00:00 2001
From: Peter Rosin <p...@axentia.se>
Date: Mon, 5 Oct 2015 10:16:18 +0200
Subject: [PATCH] Revert "i2c: at91: fix a race condition when using the DMA
 controller"

This reverts commit 93563a6a71bb69dd324fc7354c60fb05f84aae6b.

Conflicts:
	drivers/i2c/busses/i2c-at91.c
---
 drivers/i2c/busses/i2c-at91.c |   97 +
 1 file changed, 21 insertions(+), 76 deletions(-)

diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
index 1c758cd1e1ba..b5a5ef26b142 100644
--- a/drivers/i2c/busses/i2c-at91.c
+++ b/drivers/i2c/busses/i2c-at91.c
@@ -74,9 +74,6 @@
 #define	AT91_TWI_NACK		BIT(8)	/* Not Acknowledged */
 #define	AT91_TWI_LOCK		BIT(23) /* TWI Lock due to Frame Errors */
 
-#define	AT91_TWI_INT_MASK \
-	(AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY | AT91_TWI_NACK)
-
 #define	AT91_TWI_IER		0x0024	/* Interrupt Enable Register */
 #define	AT91_TWI_IDR		0x0028	/* Interrupt Disable Register */
 #define	AT91_TWI_IMR		0x002c	/* Interrupt Mask Register */
@@ -155,12 +152,13 @@ static void at91_twi_write(struct at91_twi_dev *dev, unsigned reg, unsigned val)
 
 static void at91_disable_twi_interrupts(struct at91_twi_dev *dev)
 {
-	at91_twi_write(dev, AT91_TWI_IDR, AT91_TWI_INT_MASK);
+	at91_twi_write(dev, AT91_TWI_IDR,
+		   AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY);
 }
 
 static void at91_twi_irq_save(struct at91_twi_dev *dev)
 {
-	dev->imr = at91_twi_read(dev, AT91_TWI_IMR) & AT91_TWI_INT_MASK;
+	dev->imr = at91_twi_read(dev, AT91_TWI_IMR) & 0x7;
 	at91_disable_twi_interrupts(dev);
 }
 
@@ -255,16 +253,7 @@ static void at91_twi_write_data_dma_callback(void *data)
 	dma_unmap_single(dev->dev, sg_dma_address(>dma.sg[0]),
 			 dev->buf_len, DMA_TO_DEVICE);
 
-	/*
-	 * When this callback is called, THR/TX FIFO is likely not to be empty
-	 * yet. So we have to wait for TXCOMP or NACK bits to be set into the
-	 * Status Register to be sure that the STOP bit has been sent and the
-	 * transfer is completed. The NACK interrupt has already been enable

Regression: at24 eeprom writing

2015-10-02 Thread Peter Rosin
Hi!

I recently upgraded from the atmel linux-3.18-at91 kernel to vanilla 4.2
and everything seemed fine. Until I tried to write to the little eeprom
chip. I then tried the linux-4.1-at91 kernel and that suffers too.

The symptoms are that it seems like writes get interrupted, and restarted
again without properly initializing everything again. Inspecting the i2c
bus during these fails gets me something like this (int hex) when I

echo abcdefghijklmnopqr > /sys/bus/i2c/devices/0-0050/eeprom

S a0 00 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 P
S a0 10 (clk and data low for a "long" time) 10 71 72 0a P

Notice how the address byte in the second chunk (10) is repeated after
the strange event on the i2c bus.

I looked around and found that if I revert 
a839ce663b3183209fdf7b1fc4796bfe2a4679c3
"eeprom: at24: extend driver to allow writing via i2c_smbus_write_byte_data"
eeprom writing starts working again.

AFAICT, the i2c-at91 bus driver makes the eeprom driver use the
i2c_transfer code path both with that patch and with it reverted,
so I sadly don't see why the patch makes a difference.

I'm on a board that is based on the sama5d31 evaluation kit, with a
NXP SE97BTP,547 chip and this in the devicetree:

i2c0: i2c@f0014000 {
status = "okay";

jc42@18 {
compatible = "jc42";
reg = <0x18>;
};

eeprom@50 {
compatible = "24c02";
reg = <0x50>;
pagesize = <16>;
};
};

Any ideas?

Cheers,
Peter
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v6 2/2] iio: mcp4531: Driver for Microchip digital potentiometers

2015-09-28 Thread Peter Rosin
On 2015-09-27 17:50, Jonathan Cameron wrote:
> On 23/09/15 15:26, Peter Rosin wrote:
>> From: Peter Rosin <p...@axentia.se>
>>
>> Add support for Microchip digital potentiometers and rheostats
>>  MCP4531, MCP4532, MCP4551, MCP4552
>>  MCP4631, MCP4632, MCP4651, MCP4652
>>
>> DEVICE   Wipers  Steps  Resistor Opts (kOhm)  i2c address
>> MCP4531  1   1295, 10, 50, 100010111x
>> MCP4532  1   1295, 10, 50, 10001011xx
>> MCP4551  1   2575, 10, 50, 100010111x
>> MCP4552  1   2575, 10, 50, 10001011xx
>> MCP4631  2   1295, 10, 50, 1000101xxx
>> MCP4632  2   1295, 10, 50, 10001011xx
>> MCP4651  2   2575, 10, 50, 1000101xxx
>> MCP4652  2   2575, 10, 50, 10001011xx
>>
>> Datasheet: http://www.microchip.com/downloads/en/DeviceDoc/22096b.pdf
> Applied to the togreg branch of iio.git - initially pushed out as
> testing for the autobuilders to play with it.
> 
> If anyone wants to add reviewed-by / acked-by then as I'll be
> rebasing sometime in next few days anyway there is still time!

Great, thanks,

but I don't see this where I expected it[1]. So, the question is if I'm
too impatient, if am I looking in the wrong place or if you perhaps forgot
to actually push it out? Or if something went totally wrong and the patches
got lost...

Cheers,
Peter

[1] http://git.kernel.org/cgit/linux/kernel/git/jic23/iio.git
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v5 2/2] iio: mcp4531: Driver for Microchip digital potentiometers

2015-09-23 Thread Peter Rosin
From: Peter Rosin <p...@axentia.se>

Add support for Microchip digital potentiometers and rheostats
MCP4531, MCP4532, MCP4551, MCP4552
MCP4631, MCP4632, MCP4651, MCP4652

DEVICE   Wipers  Steps  Resistor Opts (kOhm)  i2c address
MCP4531  1   1295, 10, 50, 100010111x
MCP4532  1   1295, 10, 50, 10001011xx
MCP4551  1   2575, 10, 50, 100010111x
MCP4552  1   2575, 10, 50, 10001011xx
MCP4631  2   1295, 10, 50, 1000101xxx
MCP4632  2   1295, 10, 50, 10001011xx
MCP4651  2   2575, 10, 50, 1000101xxx
MCP4652  2   2575, 10, 50, 10001011xx

Datasheet: http://www.microchip.com/downloads/en/DeviceDoc/22096b.pdf

Signed-off-by: Peter Rosin <p...@axentia.se>
---
 MAINTAINERS |6 +
 drivers/iio/Kconfig |1 +
 drivers/iio/Makefile|1 +
 drivers/iio/potentiometer/Kconfig   |   20 +++
 drivers/iio/potentiometer/Makefile  |6 +
 drivers/iio/potentiometer/mcp4531.c |  228 +++
 6 files changed, 262 insertions(+)
 create mode 100644 drivers/iio/potentiometer/Kconfig
 create mode 100644 drivers/iio/potentiometer/Makefile
 create mode 100644 drivers/iio/potentiometer/mcp4531.c

diff --git a/MAINTAINERS b/MAINTAINERS
index b60e2b2369d2..27862156c7a7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6600,6 +6600,12 @@ W:   http://linuxtv.org
 S: Maintained
 F: drivers/media/radio/radio-maxiradio*
 
+MCP4531 MICROCHIP DIGITAL POTENTIOMETER DRIVER
+M: Peter Rosin <p...@axentia.se>
+L: linux-...@vger.kernel.org
+S: Maintained
+F: drivers/iio/potentiometer/mcp4531.c
+
 MEDIA DRIVERS FOR RENESAS - VSP1
 M: Laurent Pinchart <laurent.pinch...@ideasonboard.com>
 L: linux-me...@vger.kernel.org
diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
index 4011effe4c05..7cc87f322655 100644
--- a/drivers/iio/Kconfig
+++ b/drivers/iio/Kconfig
@@ -73,6 +73,7 @@ source "drivers/iio/orientation/Kconfig"
 if IIO_TRIGGER
source "drivers/iio/trigger/Kconfig"
 endif #IIO_TRIGGER
+source "drivers/iio/potentiometer/Kconfig"
 source "drivers/iio/pressure/Kconfig"
 source "drivers/iio/proximity/Kconfig"
 source "drivers/iio/temperature/Kconfig"
diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
index 698afc2d17ce..121c814e366b 100644
--- a/drivers/iio/Makefile
+++ b/drivers/iio/Makefile
@@ -23,6 +23,7 @@ obj-y += imu/
 obj-y += light/
 obj-y += magnetometer/
 obj-y += orientation/
+obj-y += potentiometer/
 obj-y += pressure/
 obj-y += proximity/
 obj-y += temperature/
diff --git a/drivers/iio/potentiometer/Kconfig 
b/drivers/iio/potentiometer/Kconfig
new file mode 100644
index ..fd75db73e582
--- /dev/null
+++ b/drivers/iio/potentiometer/Kconfig
@@ -0,0 +1,20 @@
+#
+# Potentiometer drivers
+#
+# When adding new entries keep the list in alphabetical order
+
+menu "Digital potentiometers"
+
+config MCP4531
+   tristate "Microchip MCP45xx/MCP46xx Digital Potentiometer driver"
+   depends on I2C
+   help
+ Say yes here to build support for the Microchip
+ MCP4531, MCP4532, MCP4551, MCP4552,
+ MCP4631, MCP4632, MCP4651, MCP4652
+ digital potentiomenter chips.
+
+ To compile this driver as a module, choose M here: the
+ module will be called mcp4531.
+
+endmenu
diff --git a/drivers/iio/potentiometer/Makefile 
b/drivers/iio/potentiometer/Makefile
new file mode 100644
index ..8afe49227012
--- /dev/null
+++ b/drivers/iio/potentiometer/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for industrial I/O potentiometer drivers
+#
+
+# When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_MCP4531) += mcp4531.o
diff --git a/drivers/iio/potentiometer/mcp4531.c 
b/drivers/iio/potentiometer/mcp4531.c
new file mode 100644
index ..82c24c6dcde0
--- /dev/null
+++ b/drivers/iio/potentiometer/mcp4531.c
@@ -0,0 +1,228 @@
+/*
+ * Industrial I/O driver for Microchip digital potentiometers
+ * Copyright (c) 2015  Axentia Technologies AB
+ * Author: Peter Rosin <p...@axentia.se>
+ *
+ * Datasheet: http://www.microchip.com/downloads/en/DeviceDoc/22096b.pdf
+ *
+ * DEVID   #Wipers #Positions  Resistor Opts (kOhm)i2c address
+ * mcp4531 1   129 5, 10, 50, 100  010111x
+ * mcp4532 1   129 5, 10, 50, 100  01011xx
+ * mcp4551 1   257 5, 10, 50, 100  010111x
+ * mcp4552 1   257 5, 10, 50, 100  01011xx
+ * mcp4631 2   129 5, 10, 50, 100  0101xxx
+ * mcp4632 2   129 5, 10, 50, 100  01011xx
+ * mcp4651 2   257 5, 10, 50, 100  0101xxx
+ * mcp4652 2   257 5, 10, 50, 100   

[PATCH v5 0/2] Driver for Microchip digital potentiometers

2015-09-23 Thread Peter Rosin
From: Peter Rosin <p...@axentia.se>

This is the fifth attempt for a driver for these chips.

Thanks for review comments from Greg Kroah-Hartman, Crt Mori,
Daniel Baluta, Lars-Peter Clauson, Andreas Dannenberg, Peter
Meerwald and Jonathan Cameron. I think and hope I got it all sorted.

Changes since v4:
- Less convoluted changelog (Jonathan)
- Use an index into an array of configs as dev_id (Jonathan)
- Drop .address and use .channel (Jonathan)
- Remove one layer of wrappers (Jonathan)
- Provide a scale (Jonathan, Lars-Peter)

Changes since v3:
- Use i2c_smbus_read_word_swapped (Peter)
- Use devm_iio_device_register and drop the mcp4531_remove op (Peter)
- Add defines for a few magic numbers (Peter)
- Deduplicate channel params with a macro (Peter)
- Mention the i2c client address options (Peter)
- Whitespace and other trivial nits (Peter)

Changes since v2:
- Change naming from mcp4xxx_dpot to mcp4531 (Daniel)
- Added links to datasheet in commit message and source (Daniel)
- Rename from pot to potentiometer (Daniel, Crt)
- Use IIO_RESISTANCE instead of IIO_STEPS (Crt, Lars-Peter)
- Don't use wildcards in MAINTAINERS and point to the iio list (Crt)
- Avoid races by not caching values (Crt)
- Spell Microchip correctly (Andreas)

Changes since v1:
- Make it an IIO driver instead (Greg)
- Don't convolute the code with big obscure macros (Greg)
- Inline the bits from mcp4xxx_dpot.h that are actually used
  and drop that file (me)
- Better Changelog (Greg)

Cheers,
Peter

Peter Rosin (2):
  iio: resistance: Document that resistance can be output
  iio: mcp4531: Driver for Microchip digital potentiometers

 Documentation/ABI/testing/sysfs-bus-iio |2 +
 MAINTAINERS |6 +
 drivers/iio/Kconfig |1 +
 drivers/iio/Makefile|1 +
 drivers/iio/potentiometer/Kconfig   |   20 +++
 drivers/iio/potentiometer/Makefile  |6 +
 drivers/iio/potentiometer/mcp4531.c |  228 +++
 7 files changed, 264 insertions(+)
 create mode 100644 drivers/iio/potentiometer/Kconfig
 create mode 100644 drivers/iio/potentiometer/Makefile
 create mode 100644 drivers/iio/potentiometer/mcp4531.c

-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


  1   2   3   4   5   6   7   8   9   10   >