LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
From: Hans-Peter Nilsson <hans-peter.nilsson@axis.com>
To: david-b@pacbell.net
Cc: linux-kernel@vger.kernel.org, mikael.starvik@axis.com,
	spi-devel-general@lists.sourceforge.net
Subject: [PATCH 1/2] take 2: (was-kind-of: 3/5 SPI tx_default) 2.6.20-rc6
Date: Fri, 26 Jan 2007 11:46:18 +0100	[thread overview]
Message-ID: <200701261046.l0QAkIdt032408@ignucius.se.axis.com> (raw)
In-Reply-To: <200701250502.56467.david-b@pacbell.net> (message from David Brownell on Thu, 25 Jan 2007 05:02:56 -0800)

> From: David Brownell <david-b@pacbell.net>
> Date: Thu, 25 Jan 2007 05:02:56 -0800

> On Wednesday 24 January 2007 8:52 pm, Hans-Peter Nilsson wrote:
> > (Please CC me on replies, I'm not subscribed to LKML or the SPI list.  Thanks.)
> > 
> > The SD/MMC SPI-based protocol isn't really duplex.  In the
> > normal case there's either information transmitted or received,
> > not both simultaneously.  The unused data is always 0xff; ones.
> > Unfortunately, the SPI framework leaves outgoing data for a
> > left-out tx_buf just as "undefined"
> 
> In current kernels that's actually changed.  The value to be shifted
> out is now specified ... as all-zeroes, which is what various chips
> need to receive, and various (half-duplex/Microwire) controllers seem
> to be doing in any case.
> 
> If that's an issue -- and MMC-over-SPI needs to specify some other
> value --

Well, it *is* specified as ones (0xff).  Curiously enough, I
can't point to a statement in the "Simplified Physical Layer
Specification 2.0".  It's likely specified in the "7.5 SPI Bus
Timing Diagrams", which is "blank for the Simplified
Specification".  If you look at SanDisk's OEM documents for
"MultiMediaCard"/ "Reduced-Size MultiMediaCard" v1.3, you can
see that *that* document nicely complements the "Simplified
Specification", and specifies it as 0xff (see "5.23 SPI Bus
Timing Diagrams").  FWIW, I found this referenced from somewhere
I-forgot when I STFW'd for SD/MMC SPI documentation or Linux
drivers, so I'm not "ratting them out" for providing
documentation withheld elsewhere. :-} Besides, I think they're
one of those making the rules for the SDcard organization.

...and anyway, I just *had* to try: well, it doesn't work with 0. :-)

> I think a better way to package this would be to define a new
> flag for spi->mode, since controller drivers are already supposed
> to be checking that to make sure they handle all the options which
> have been specified.

But it's unspecified what the controller drivers should do with
flags don't recognize (should they refuse? warn? ignore? - I see
they all ignore) so with that suggestion, we'll have a situation
where drivers wouldn't know about the new flag and would
silently not work.

Perhaps it can be "legislated" or at least strongly suggested
that SPI drivers must return -EINVAL for flags in spi->mode that
they don't recognise?  Typically, for 2.6.19 flags, in their
master-setup method:

  if (spi->mode & ~(SPI_CPHA | SPI_CPOL | SPI_CS_HIGH | SPI_LSB_FIRST))
	return -EINVAL;

(I think I'll do exactly that with the drivers I wrote.)

>  That flag could work in conjunction with
> a byte

Or why not a 32-bit word!  If controllers can only handle non-0
values for bits_per_word <= 8, they can check for that.  (Before
you suggest a 64-bit value, consider that the 64-bit-ness would
supposedly be rarely used and the value is likely to be looked
up in inner loops like for the bitbanged driver.  Ok, there are
ways around that, it's just that I don't think a 64-bit value
would be more useful than the implications.  We can always
change it when a use-case appears.  I guess that implies having
it a u8, but typically the 32 vs 8 bit difference is much less
than 64 vs 32.  Toolshed alert!)

> provided in the spi_device, that would be used instead of
> zero.  (Some folk have noted that when debugging, it's easier if
> the pattern there is neither all-ones nor all-zeroes ... something
> that a digital scope will show is easier to work with.)

FWIW, I defined it as a single bit in that patch, because that's
what my HW can do when the transmitter is disabled - and because
MOSI *is* a single-valued signal. ;-)  Also, I made it
per-transfer, which for mmc_spi wouldn't mean much, only perhaps
to possibly drop all-zero buffers, which of course implied that
someone would have to scan them first anyway (i.e. no fewer
memory accesses), so I guess I had no serious use-case.

Still, making it a u32 (or u8), with spi->bits_per_word
specifying the actual length, makes sense for example to
implementations around a shift-register but with no DMA.  A
controller can return -EINVAL (shouldn't that be -ENOSYS?) if it
finds a default_tx_word it can't support simply enough.  If we
define returning -EINVAL as always ok and that the driver/client
part is responsible for a fallback, I think we have agreement.

While I was looking, I noticed that the memory-layout of
non-8-bit words for SPI is a bit unclear.  The endianness of
data shifted out doesn't really define endianness in memory or
whether 24-bit words bytes are in order {hi, med, low, pad} or
indeed {pad, low, med, hi or whatever combination.  For a LE
architecture, storing data as LE in memory makes sense, and both
with and without padding makes sense too.  Perhaps best to just
document that it's undefined?

> then please re-issue this patch against 2.6.20, including
> the update to the bitbang driver ("reference implementation").

I used patch-2.6.20-rc6; I see not too many SPI things changed
besides defining the previously undefined as 0.  I didn't find a
reason to introduce a mode-flag; it should always be enough to
look at the word.  A flag is redundant with default_tx_word != 0
(in 2.6.20 semantics).  So, I just added that word and adjusted
the bitbang-driver.  As a courtesy, I also added simple bail-out
code for the other drivers (not compiled and submitted
separately).

Here's an updated patch for 2.6.20-rc6.  Tested against 2.6.19
and adjusted to 2.6.20-rx6; it applies to 2.6.19, except for the
last hunk of spi.h which is in a comment and due to that
s/undefined data/zeroes/.  It's just the first line changed, the
rest is the result of M-x fill-paragraph.

BTW, I hope I'm unnecessarily pointing out that if you'd prefer
just initializing "word = spi->default_tx_word;" that may
(depending on your gcc version) introduce a memory access which
we can avoid.  Sure, it's just bitbanging SPI, but why not win.

Signed-off-by: Hans-Peter Nilsson <hp@axis.com>

diff -upr a/include/linux/spi/spi.h b/include/linux/spi/spi.h
--- a/include/linux/spi/spi.h	2007-01-26 10:38:50.000000000 +0100
+++ b/include/linux/spi/spi.h	2007-01-26 10:53:30.000000000 +0100
@@ -43,6 +43,10 @@ extern struct bus_type spi_bus_type;
  *	This may be changed by the device's driver, or left at the
  *	default (0) indicating protocol words are eight bit bytes.
  *	The spi_transfer.bits_per_word can override this for each transfer.
+ * @default_tx_word: This word, of size bits_per_word, will be the value
+ *	shifted out if the transmit buffer is null.  This may be changed
+ *	by the device's driver, but the controller doesn't have to accept
+ *	all values.  The default for a controller is 0, and is always valid.
  * @irq: Negative, or the number passed to request_irq() to receive
  *	interrupts from this device.
  * @controller_state: Controller's runtime state
@@ -72,6 +76,7 @@ struct spi_device {
 #define	SPI_CS_HIGH	0x04			/* chipselect active high? */
 #define	SPI_LSB_FIRST	0x08			/* per-word bits-on-wire */
 	u8			bits_per_word;
+	u32			default_tx_word;
 	int			irq;
 	void			*controller_state;
 	void			*controller_data;
@@ -289,12 +294,13 @@ extern struct spi_master *spi_busnum_to_
  * the data being transferred; that may reduce overhead, when the
  * underlying driver uses dma.
  *
- * If the transmit buffer is null, zeroes will be shifted out
- * while filling rx_buf.  If the receive buffer is null, the data
- * shifted in will be discarded.  Only "len" bytes shift out (or in).
- * It's an error to try to shift out a partial word.  (For example, by
- * shifting out three bytes with word size of sixteen or twenty bits;
- * the former uses two bytes per word, the latter uses four bytes.)
+ * If the transmit buffer is null, the word in spi_device.default_tx_word
+ * will be shifted out while filling rx_buf.  If the receive buffer is
+ * null, the data shifted in will be discarded.  Only "len" bytes shift
+ * out (or in).  It's an error to try to shift out a partial word.  (For
+ * example, by shifting out three bytes with word size of sixteen or
+ * twenty bits; the former uses two bytes per word, the latter uses four
+ * bytes.)
  *
  * All SPI transfers start with the relevant chipselect active.  Normally
  * it stays selected until after the last transfer in a message.  Drivers
diff -upr a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c
--- a/drivers/spi/spi_bitbang.c	2007-01-26 10:38:49.000000000 +0100
+++ b/drivers/spi/spi_bitbang.c	2007-01-26 10:57:38.292130863 +0100
@@ -73,10 +73,9 @@ static unsigned bitbang_txrx_8(
 	u8			*rx = t->rx_buf;
 
 	while (likely(count > 0)) {
-		u8		word = 0;
+		u8		word;
 
-		if (tx)
-			word = *tx++;
+		word = (tx != NULL) ? *tx++ : spi->default_tx_word;
 		word = txrx_word(spi, ns, word, bits);
 		if (rx)
 			*rx++ = word;
@@ -101,8 +100,7 @@ static unsigned bitbang_txrx_16(
 	while (likely(count > 1)) {
 		u16		word = 0;
 
-		if (tx)
-			word = *tx++;
+		word = (tx != NULL) ? *tx++ : spi->default_tx_word;
 		word = txrx_word(spi, ns, word, bits);
 		if (rx)
 			*rx++ = word;
@@ -127,8 +125,7 @@ static unsigned bitbang_txrx_32(
 	while (likely(count > 3)) {
 		u32		word = 0;
 
-		if (tx)
-			word = *tx++;
+		word = (tx != NULL) ? *tx++ : spi->default_tx_word;
 		word = txrx_word(spi, ns, word, bits);
 		if (rx)
 			*rx++ = word;

brgds, H-P

  reply	other threads:[~2007-01-26 10:46 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-01-25  4:52 [PATCH] 3/5: Updates to SPI and mmc_spi: tx_default, kernel 2.6.19 Hans-Peter Nilsson
2007-01-25 13:02 ` David Brownell
2007-01-26 10:46   ` Hans-Peter Nilsson [this message]
2007-01-26 23:21     ` [PATCH 1/2] take 2: (was-kind-of: 3/5 SPI tx_default) 2.6.20-rc6 David Brownell
2007-01-27  4:21       ` David Brownell
2007-01-27 20:19         ` Hans-Peter Nilsson
2007-01-27 20:26           ` Hans-Peter Nilsson
2007-01-27 20:59           ` [PATCH] take 3: mmc_spi with SPI_TX_1 2.6.20-rc6 Hans-Peter Nilsson
2007-01-28 17:46             ` [PATCH] take 4: " Hans-Peter Nilsson
2007-01-27 10:11       ` [PATCH 1/2] take 2: (was-kind-of: 3/5 SPI tx_default) 2.6.20-rc6 Hans-Peter Nilsson
2007-01-27 19:25         ` David Brownell
2007-01-26 10:48   ` [PATCH 2/2] " Hans-Peter Nilsson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=200701261046.l0QAkIdt032408@ignucius.se.axis.com \
    --to=hans-peter.nilsson@axis.com \
    --cc=david-b@pacbell.net \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mikael.starvik@axis.com \
    --cc=spi-devel-general@lists.sourceforge.net \
    --subject='Re: [PATCH 1/2] take 2: (was-kind-of: 3/5 SPI tx_default) 2.6.20-rc6' \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).