diff mbox

[v2] spi: dts: sun4i: Add support for inter-word wait cycles using the SPI Wait Clock Register

Message ID 1449873940-10167-1-git-send-email-mweseloh42@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Marcus Weseloh Dec. 11, 2015, 10:45 p.m. UTC
Adds support and binding documentation for a new slave device property
"sun4i,spi-word-wait-ns" that allows to set a hardware based delay
between the transmission of words using the SPI Wait Clock Register.
The SPI hardware needs 3 clock cycles to set up the delay, which makes
the minimum non-zero wait time 4 clock cycles.

Signed-off-by: Marcus Weseloh <mweseloh42@gmail.com>
---
Changes from v1:
 * renamed the property for more clarity
 * wait time is set in nanoseconds instead of number of clock cycles
 * transparently handle the 3 setup clock cycles

There is one review comment that I didn't address: Rob Herring suggested
that this should be in the core-binding rather than in sun4i. I checked
many of the hardware manuals of other SPI drivers and it looks to me like
this hardware based inter-word delay is a feature that not many SPI
controllers offer. And the SPI core currently has no way to control an
inter-word delay, only inter-message. So I would like to propose this again
as a sun4i binding, as it targets a sun4i (or sunxi?) specific hardware
feature.
---
 .../devicetree/bindings/spi/spi-sun4i.txt          | 11 +++++++++++
 drivers/spi/spi-sun4i.c                            | 23 ++++++++++++++++++++++
 2 files changed, 34 insertions(+)

Comments

Priit Laes Dec. 12, 2015, 9:19 a.m. UTC | #1
On Fri, 2015-12-11 at 23:45 +0100, Marcus Weseloh wrote:

[...]
> 
> diff --git a/Documentation/devicetree/bindings/spi/spi-sun4i.txt b/Documentation/devicetree/bindings/spi/spi-sun4i.txt
> index de827f5..d6c55fc 100644
> --- a/Documentation/devicetree/bindings/spi/spi-sun4i.txt
> +++ b/Documentation/devicetree/bindings/spi/spi-sun4i.txt
> @@ -10,6 +10,10 @@ Required properties:
>    - "mod": the parent module clock
>  - clock-names: Must contain the clock names described just above
>  
> +Optional properties for slave devices:
> +- sun4i,spi-word-wait-ns: hardware based delay in nanoseconds between
> +			  transmission of words

Should be 'allwinner,spi-word-wait-ns'

Vendor prefix do come from:
Documentation/devicetree/bindings/vendor-prefixes.txt

> +
>  Example:
>  
>  spi1: spi@01c06000 {
> @@ -21,4 +25,11 @@ spi1: spi@01c06000 {
>  	status = "disabled";
>  	#address-cells = <1>;
>  	#size-cells = <0>;
> +
> +	spi1_0 {
> +		compatible = "example,dummy";
> +		reg = <0>;
> +		spi-max-frequency = <1000000>;
> +		sun4i,spi-word-wait-ns = <12000>;
> +	};
>  };
> diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c
> index f60a6d6..8cfd96c 100644
> --- a/drivers/spi/spi-sun4i.c
> +++ b/drivers/spi/spi-sun4i.c
> @@ -19,6 +19,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  
>  #include 
>  
> @@ -173,6 +174,9 @@ static int sun4i_spi_transfer_one(struct spi_master *master,
>  	unsigned int tx_len = 0;
>  	int ret = 0;
>  	u32 reg;
> +	u32 wait_ns = 0;
> +	int wait_clk = 0;
> +	int clk_ns = 0;
>  
>  	/* We don't support transfer larger than the FIFO */
>  	if (tfr->len > SUN4I_FIFO_DEPTH)
> @@ -261,6 +265,25 @@ static int sun4i_spi_transfer_one(struct spi_master *master,
>  
>  	sun4i_spi_write(sspi, SUN4I_CLK_CTL_REG, reg);
>  
> +	/* Setup wait time beteen words */
typo

> +	of_property_read_u32(spi->dev.of_node, "sun4i,spi-word-wait-ns",
> +			     &wait_ns);
> +	if (wait_ns) {
> +		/* The wait time is set in SPI_CLK cycles. The SPI hardware
> +		 * needs 3 additional cycles to setup the wait counter, so
> +		 * the minimum delay time is 4 cycles.
> +		 */
> +		clk_ns = DIV_ROUND_UP(1000000000, tfr->speed_hz);
> +		wait_clk = DIV_ROUND_UP(wait_ns, clk_ns) - 3;
> +		if (wait_clk < 1) {
> +			wait_clk = 1;
> +			dev_info(&spi->dev,
> +				 "using minimum of 4 word wait cycles (%uns)",
> +				 4 * clk_ns);
> +		}
> +	}
> +	sun4i_spi_write(sspi, SUN4I_WAIT_REG, (u16)wait_clk);
> +
>  	/* Setup the transfer now... */
>  	if (sspi->tx_buf)
>  		tx_len = tfr->len;
> -- 
> 1.9.1
>
Marcus Weseloh Dec. 12, 2015, 10:44 a.m. UTC | #2
2015-12-12 10:19 GMT+01:00 Priit Laes <plaes@plaes.org>:
> On Fri, 2015-12-11 at 23:45 +0100, Marcus Weseloh wrote:
> [...]
>> +- sun4i,spi-word-wait-ns: hardware based delay in nanoseconds between
>> +                       transmission of words
>
> Should be 'allwinner,spi-word-wait-ns'

Thanks for the review, I will change the prefix.

> [...]
>> +     /* Setup wait time beteen words */
> typo

Ah, yes. I will wait for more review comments and post a v3 after that.

Cheers,

   Marcus
Maxime Ripard Dec. 13, 2015, 9:07 p.m. UTC | #3
Hi,

On Fri, Dec 11, 2015 at 11:45:39PM +0100, Marcus Weseloh wrote:
> Adds support and binding documentation for a new slave device property
> "sun4i,spi-word-wait-ns" that allows to set a hardware based delay
> between the transmission of words using the SPI Wait Clock Register.
> The SPI hardware needs 3 clock cycles to set up the delay, which makes
> the minimum non-zero wait time 4 clock cycles.
> 
> Signed-off-by: Marcus Weseloh <mweseloh42@gmail.com>
> ---
> Changes from v1:
>  * renamed the property for more clarity
>  * wait time is set in nanoseconds instead of number of clock cycles
>  * transparently handle the 3 setup clock cycles
> 
> There is one review comment that I didn't address: Rob Herring suggested
> that this should be in the core-binding rather than in sun4i. I checked
> many of the hardware manuals of other SPI drivers and it looks to me like
> this hardware based inter-word delay is a feature that not many SPI
> controllers offer. And the SPI core currently has no way to control an
> inter-word delay, only inter-message. So I would like to propose this again
> as a sun4i binding, as it targets a sun4i (or sunxi?) specific hardware
> feature.

Only a few of them justify to have this in the framework. There's a
bunch of controllers that support such a feature, and it definitely
belongs in the core.

The point of the framework is not to be the least common denominator,
it's about having as much code in common as possible, and it
definitely falls into that category.

Thanks,
Maxime
Marcus Weseloh Dec. 13, 2015, 9:52 p.m. UTC | #4
2015-12-13 22:07 GMT+01:00 Maxime Ripard <maxime.ripard@free-electrons.com>:
[...]
>> There is one review comment that I didn't address: Rob Herring suggested
>> that this should be in the core-binding rather than in sun4i. I checked
>> many of the hardware manuals of other SPI drivers and it looks to me like
>> this hardware based inter-word delay is a feature that not many SPI
>> controllers offer. And the SPI core currently has no way to control an
>> inter-word delay, only inter-message. So I would like to propose this again
>> as a sun4i binding, as it targets a sun4i (or sunxi?) specific hardware
>> feature.
>
> Only a few of them justify to have this in the framework. There's a
> bunch of controllers that support such a feature, and it definitely
> belongs in the core.
>
> The point of the framework is not to be the least common denominator,
> it's about having as much code in common as possible, and it
> definitely falls into that category.

Ok, now I understand. I did indeed think that the SPI core is more
like a least common denominator. So I will add the property to the
spi-core binding, as initially requested by Rob and send a v3.

Thanks for the review, Maxime!

Marcus
diff mbox

Patch

diff --git a/Documentation/devicetree/bindings/spi/spi-sun4i.txt b/Documentation/devicetree/bindings/spi/spi-sun4i.txt
index de827f5..d6c55fc 100644
--- a/Documentation/devicetree/bindings/spi/spi-sun4i.txt
+++ b/Documentation/devicetree/bindings/spi/spi-sun4i.txt
@@ -10,6 +10,10 @@  Required properties:
   - "mod": the parent module clock
 - clock-names: Must contain the clock names described just above
 
+Optional properties for slave devices:
+- sun4i,spi-word-wait-ns: hardware based delay in nanoseconds between
+			  transmission of words
+
 Example:
 
 spi1: spi@01c06000 {
@@ -21,4 +25,11 @@  spi1: spi@01c06000 {
 	status = "disabled";
 	#address-cells = <1>;
 	#size-cells = <0>;
+
+	spi1_0 {
+		compatible = "example,dummy";
+		reg = <0>;
+		spi-max-frequency = <1000000>;
+		sun4i,spi-word-wait-ns = <12000>;
+	};
 };
diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c
index f60a6d6..8cfd96c 100644
--- a/drivers/spi/spi-sun4i.c
+++ b/drivers/spi/spi-sun4i.c
@@ -19,6 +19,7 @@ 
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
+#include <linux/of.h>
 
 #include <linux/spi/spi.h>
 
@@ -173,6 +174,9 @@  static int sun4i_spi_transfer_one(struct spi_master *master,
 	unsigned int tx_len = 0;
 	int ret = 0;
 	u32 reg;
+	u32 wait_ns = 0;
+	int wait_clk = 0;
+	int clk_ns = 0;
 
 	/* We don't support transfer larger than the FIFO */
 	if (tfr->len > SUN4I_FIFO_DEPTH)
@@ -261,6 +265,25 @@  static int sun4i_spi_transfer_one(struct spi_master *master,
 
 	sun4i_spi_write(sspi, SUN4I_CLK_CTL_REG, reg);
 
+	/* Setup wait time beteen words */
+	of_property_read_u32(spi->dev.of_node, "sun4i,spi-word-wait-ns",
+			     &wait_ns);
+	if (wait_ns) {
+		/* The wait time is set in SPI_CLK cycles. The SPI hardware
+		 * needs 3 additional cycles to setup the wait counter, so
+		 * the minimum delay time is 4 cycles.
+		 */
+		clk_ns = DIV_ROUND_UP(1000000000, tfr->speed_hz);
+		wait_clk = DIV_ROUND_UP(wait_ns, clk_ns) - 3;
+		if (wait_clk < 1) {
+			wait_clk = 1;
+			dev_info(&spi->dev,
+				 "using minimum of 4 word wait cycles (%uns)",
+				 4 * clk_ns);
+		}
+	}
+	sun4i_spi_write(sspi, SUN4I_WAIT_REG, (u16)wait_clk);
+
 	/* Setup the transfer now... */
 	if (sspi->tx_buf)
 		tx_len = tfr->len;