2015-04-03 20:39:50

by Aaron Brice

[permalink] [raw]
Subject: [PATCH v3 0/3] spi: fsl-dspi (vf610) clock fixes

We were having intermittent problems writing to SRAM chip on SPI bus on vf610
SoM. Added support for CS setup and hold times to meet the SRAM spec. In the
process noticed that the baud rate was a little high.

Changes since v2:
* Incorporate fixes per Stefen Agner review, namely moved hard-coded 50ns
delays to device tree properties
* Fix for baud rate scale value remainders, reported by Andy Shevchenko

Changes since v1:
* More detail in commit message for clock rate fix

Aaron Brice (3):
spi: fsl-dspi: Fix clock rate scale values
devicetree: spi: fsl-dspi: Add cs-sck delays
spi: fsl-dspi: Add ~50ns delay between cs and sck

.../devicetree/bindings/spi/spi-fsl-dspi.txt | 8 ++
drivers/spi/spi-fsl-dspi.c | 97 ++++++++++++++++++----
2 files changed, 89 insertions(+), 16 deletions(-)

--
2.1.0


2015-04-03 20:39:48

by Aaron Brice

[permalink] [raw]
Subject: [PATCH v3 1/3] spi: fsl-dspi: Fix clock rate scale values

Previous algorithm had an outer loop with the values {2,3,5,7} and an
inner loop with {2,4,6,8,16,32,...,32768}, and would pick the first
value over the required scaling value (where the total scale was the two
numbers multiplied).

Since the inner loop went up to 32768 it would always pick a value of 2
for PBR and a much higher than necessary value for BR. The desired
scale factor was being divided by two I believe to compensate for the
much higher scale factors (the divide by two not specified in the
reference manual).

Updated to check all values and find the smallest scale factor possible
without going over the desired clock rate.

Signed-off-by: Aaron Brice <[email protected]>
---
drivers/spi/spi-fsl-dspi.c | 37 +++++++++++++++++++++++--------------
1 file changed, 23 insertions(+), 14 deletions(-)

diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c
index d1a3924..8213358 100644
--- a/drivers/spi/spi-fsl-dspi.c
+++ b/drivers/spi/spi-fsl-dspi.c
@@ -148,23 +148,32 @@ static void hz_to_spi_baud(char *pbr, char *br, int speed_hz,
16, 32, 64, 128,
256, 512, 1024, 2048,
4096, 8192, 16384, 32768 };
- int temp, i = 0, j = 0;
-
- temp = clkrate / 2 / speed_hz;
-
- for (i = 0; i < ARRAY_SIZE(pbr_tbl); i++)
- for (j = 0; j < ARRAY_SIZE(brs); j++) {
- if (pbr_tbl[i] * brs[j] >= temp) {
- *pbr = i;
- *br = j;
- return;
+ int scale_needed, scale, minscale = INT_MAX;
+ int i, j;
+
+ scale_needed = clkrate / speed_hz;
+ if (clkrate % speed_hz)
+ scale_needed++;
+
+ for (i = 0; i < ARRAY_SIZE(brs); i++)
+ for (j = 0; j < ARRAY_SIZE(pbr_tbl); j++) {
+ scale = brs[i] * pbr_tbl[j];
+ if (scale >= scale_needed) {
+ if (scale < minscale) {
+ minscale = scale;
+ *br = i;
+ *pbr = j;
+ }
+ break;
}
}

- pr_warn("Can not find valid baud rate,speed_hz is %d,clkrate is %ld\
- ,we use the max prescaler value.\n", speed_hz, clkrate);
- *pbr = ARRAY_SIZE(pbr_tbl) - 1;
- *br = ARRAY_SIZE(brs) - 1;
+ if (minscale == INT_MAX) {
+ pr_warn("Can not find valid baud rate,speed_hz is %d,clkrate is %ld, we use the max prescaler value.\n",
+ speed_hz, clkrate);
+ *pbr = ARRAY_SIZE(pbr_tbl) - 1;
+ *br = ARRAY_SIZE(brs) - 1;
+ }
}

static int dspi_transfer_write(struct fsl_dspi *dspi)
--
2.1.0

2015-04-03 20:39:52

by Aaron Brice

[permalink] [raw]
Subject: [PATCH v3 2/3] devicetree: spi: fsl-dspi: Add cs-sck delays

Adding fsl,spi-cs-sck-delay and fsl,spi-sck-cs-delay properties to
support delays before and after starting the clock in a transfer.

Signed-off-by: Aaron Brice <[email protected]>
---
Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt | 8 ++++++++
1 file changed, 8 insertions(+)

diff --git a/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt b/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt
index cbbe16e..70af78a 100644
--- a/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt
+++ b/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt
@@ -16,6 +16,12 @@ Optional property:
in big endian mode, otherwise in native mode(same with CPU), for more
detail please see: Documentation/devicetree/bindings/regmap/regmap.txt.

+Optional SPI slave node properties:
+- fsl,spi-cs-sck-delay: a delay in nanoseconds between activating chip
+ select and the start of clock signal, at the start of a transfer.
+- fsl,spi-sck-cs-delay: a delay in nanoseconds between stopping the clock
+ signal and deactivating chip select, at the end of a transfer.
+
Example:

dspi0@4002c000 {
@@ -43,6 +49,8 @@ dspi0@4002c000 {
reg = <0>;
linux,modalias = "m25p80";
modal = "at26df081a";
+ fsl,spi-cs-sck-delay = <100>;
+ fsl,spi-sck-cs-delay = <50>;
};
};

--
2.1.0

2015-04-03 20:40:32

by Aaron Brice

[permalink] [raw]
Subject: [PATCH v3 3/3] spi: fsl-dspi: Add ~50ns delay between cs and sck

Add delay between chip select and clock signals, before clock starts and
after clock stops.

Signed-off-by: Aaron Brice <[email protected]>
---
drivers/spi/spi-fsl-dspi.c | 64 +++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 60 insertions(+), 4 deletions(-)

diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c
index 8213358..5fe54cd 100644
--- a/drivers/spi/spi-fsl-dspi.c
+++ b/drivers/spi/spi-fsl-dspi.c
@@ -20,6 +20,7 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
+#include <linux/math64.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -29,6 +30,7 @@
#include <linux/sched.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
+#include <linux/time.h>

#define DRIVER_NAME "fsl-dspi"

@@ -51,7 +53,7 @@
#define SPI_CTAR_CPOL(x) ((x) << 26)
#define SPI_CTAR_CPHA(x) ((x) << 25)
#define SPI_CTAR_LSBFE(x) ((x) << 24)
-#define SPI_CTAR_PCSSCR(x) (((x) & 0x00000003) << 22)
+#define SPI_CTAR_PCSSCK(x) (((x) & 0x00000003) << 22)
#define SPI_CTAR_PASC(x) (((x) & 0x00000003) << 20)
#define SPI_CTAR_PDT(x) (((x) & 0x00000003) << 18)
#define SPI_CTAR_PBR(x) (((x) & 0x00000003) << 16)
@@ -59,6 +61,7 @@
#define SPI_CTAR_ASC(x) (((x) & 0x0000000f) << 8)
#define SPI_CTAR_DT(x) (((x) & 0x0000000f) << 4)
#define SPI_CTAR_BR(x) ((x) & 0x0000000f)
+#define SPI_CTAR_SCALE_BITS 0xf

#define SPI_CTAR0_SLAVE 0x0c

@@ -176,6 +179,40 @@ static void hz_to_spi_baud(char *pbr, char *br, int speed_hz,
}
}

+static void ns_delay_scale(char *psc, char *sc, int delay_ns,
+ unsigned long clkrate)
+{
+ int pscale_tbl[4] = {1, 3, 5, 7};
+ int scale_needed, scale, minscale = INT_MAX;
+ int i, j;
+ u32 remainder;
+
+ scale_needed = div_u64_rem((u64)delay_ns * clkrate, NSEC_PER_SEC,
+ &remainder);
+ if (remainder)
+ scale_needed++;
+
+ for (i = 0; i < ARRAY_SIZE(pscale_tbl); i++)
+ for (j = 0; j <= SPI_CTAR_SCALE_BITS; j++) {
+ scale = pscale_tbl[i] * (2 << j);
+ if (scale >= scale_needed) {
+ if (scale < minscale) {
+ minscale = scale;
+ *psc = i;
+ *sc = j;
+ }
+ break;
+ }
+ }
+
+ if (minscale == INT_MAX) {
+ pr_warn("Cannot find correct scale values for %dns delay at clkrate %ld, using max prescaler value",
+ delay_ns, clkrate);
+ *psc = ARRAY_SIZE(pscale_tbl) - 1;
+ *sc = SPI_CTAR_SCALE_BITS;
+ }
+}
+
static int dspi_transfer_write(struct fsl_dspi *dspi)
{
int tx_count = 0;
@@ -354,7 +391,10 @@ static int dspi_setup(struct spi_device *spi)
{
struct chip_data *chip;
struct fsl_dspi *dspi = spi_master_get_devdata(spi->master);
- unsigned char br = 0, pbr = 0, fmsz = 0;
+ u32 cs_sck_delay = 0, sck_cs_delay = 0;
+ unsigned char br = 0, pbr = 0, pcssck = 0, cssck = 0;
+ unsigned char pasc = 0, asc = 0, fmsz = 0;
+ unsigned long clkrate;

if ((spi->bits_per_word >= 4) && (spi->bits_per_word <= 16)) {
fmsz = spi->bits_per_word - 1;
@@ -371,18 +411,34 @@ static int dspi_setup(struct spi_device *spi)
return -ENOMEM;
}

+ of_property_read_u32(spi->dev.of_node, "fsl,spi-cs-sck-delay",
+ &cs_sck_delay);
+
+ of_property_read_u32(spi->dev.of_node, "fsl,spi-sck-cs-delay",
+ &sck_cs_delay);
+
chip->mcr_val = SPI_MCR_MASTER | SPI_MCR_PCSIS |
SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF;

chip->void_write_data = 0;

- hz_to_spi_baud(&pbr, &br,
- spi->max_speed_hz, clk_get_rate(dspi->clk));
+ clkrate = clk_get_rate(dspi->clk);
+ hz_to_spi_baud(&pbr, &br, spi->max_speed_hz, clkrate);
+
+ /* Set PCS to SCK delay scale values */
+ ns_delay_scale(&pcssck, &cssck, cs_sck_delay, clkrate);
+
+ /* Set After SCK delay scale values */
+ ns_delay_scale(&pasc, &asc, sck_cs_delay, clkrate);

chip->ctar_val = SPI_CTAR_FMSZ(fmsz)
| SPI_CTAR_CPOL(spi->mode & SPI_CPOL ? 1 : 0)
| SPI_CTAR_CPHA(spi->mode & SPI_CPHA ? 1 : 0)
| SPI_CTAR_LSBFE(spi->mode & SPI_LSB_FIRST ? 1 : 0)
+ | SPI_CTAR_PCSSCK(pcssck)
+ | SPI_CTAR_CSSCK(cssck)
+ | SPI_CTAR_PASC(pasc)
+ | SPI_CTAR_ASC(asc)
| SPI_CTAR_PBR(pbr)
| SPI_CTAR_BR(br);

--
2.1.0

2015-04-06 17:11:39

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH v3 1/3] spi: fsl-dspi: Fix clock rate scale values

On Fri, Apr 03, 2015 at 01:39:29PM -0700, Aaron Brice wrote:
> Previous algorithm had an outer loop with the values {2,3,5,7} and an
> inner loop with {2,4,6,8,16,32,...,32768}, and would pick the first
> value over the required scaling value (where the total scale was the two
> numbers multiplied).

Applied, thanks.


Attachments:
(No filename) (319.00 B)
signature.asc (473.00 B)
Digital signature
Download all attachments

2015-04-06 17:12:52

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH v3 2/3] devicetree: spi: fsl-dspi: Add cs-sck delays

On Fri, Apr 03, 2015 at 01:39:30PM -0700, Aaron Brice wrote:
> Adding fsl,spi-cs-sck-delay and fsl,spi-sck-cs-delay properties to
> support delays before and after starting the clock in a transfer.

Applied, please use subject lines matching the style for the subsystem.


Attachments:
(No filename) (271.00 B)
signature.asc (473.00 B)
Digital signature
Download all attachments

2015-04-06 17:13:03

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH v3 3/3] spi: fsl-dspi: Add ~50ns delay between cs and sck

On Fri, Apr 03, 2015 at 01:39:31PM -0700, Aaron Brice wrote:
> Add delay between chip select and clock signals, before clock starts and
> after clock stops.

Applied, thanks.


Attachments:
(No filename) (175.00 B)
signature.asc (473.00 B)
Digital signature
Download all attachments