io/spi: add CSChange config option
Some SPI devices use a half-duplex request/response model where the user
submits a request and then continues reading until a full response is
received. This requires multiple Tx calls, but also requires that the
device's chipselect stays enabled until the full response has been read.
The linux spidev interface has a flag cs_change which, when set to true,
causes the device's chipselect to stay enabled after the data has been
written. The SPI devfs driver payload contains a field for this option,
but it is not currently used.
This change exposes that parameter by adding a CSChange option to the
SPI driver's configuration options and a SetCSChange function to the
spi.Device. The following flow then becomes possible:
* call SetCSChange(true) so the chipselect stays enabled after Tx calls
* call Tx() to write the request data
* call Tx() repeatedly to continue reading until full response data has
been received
* call SetCSChange(false) so the chipselect gets disabled after Tx calls
* call Tx() one more time to release the device
Fixes #16239
Change-Id: Ide41f706a2605d483e160f861082d8f7e1796e82
Reviewed-on: https://go-review.googlesource.com/24910
Reviewed-by: Jaana Burcu Dogan <jbd@google.com>
diff --git a/io/spi/devfs.go b/io/spi/devfs.go
index a24c067..04b54c3 100644
--- a/io/spi/devfs.go
+++ b/io/spi/devfs.go
@@ -85,11 +85,12 @@
}
type devfsConn struct {
- f *os.File
- mode uint8
- speed uint32
- bits uint8
- delay uint16
+ f *os.File
+ mode uint8
+ speed uint32
+ bits uint8
+ delay uint16
+ csChange uint8
}
func (c *devfsConn) Configure(k, v int) error {
@@ -119,6 +120,8 @@
}
case driver.Delay:
c.delay = uint16(v)
+ case driver.CSChange:
+ c.csChange = uint8(v)
default:
return fmt.Errorf("unknown key: %v", k)
}
@@ -132,12 +135,13 @@
// TODO(jbd): len(w) == len(r)?
// TODO(jbd): Allow nil w.
p := payload{
- tx: uint64(uintptr(unsafe.Pointer(&w[0]))),
- rx: uint64(uintptr(unsafe.Pointer(&r[0]))),
- length: uint32(len(w)),
- speed: c.speed,
- delay: c.delay,
- bits: c.bits,
+ tx: uint64(uintptr(unsafe.Pointer(&w[0]))),
+ rx: uint64(uintptr(unsafe.Pointer(&r[0]))),
+ length: uint32(len(w)),
+ speed: c.speed,
+ delay: c.delay,
+ bits: c.bits,
+ csChange: c.csChange,
}
// TODO(jbd): Read from the device and fill rx.
return c.ioctl(msgRequestCode(1), uintptr(unsafe.Pointer(&p)))
diff --git a/io/spi/driver/driver.go b/io/spi/driver/driver.go
index 0f28201..7634440 100644
--- a/io/spi/driver/driver.go
+++ b/io/spi/driver/driver.go
@@ -11,6 +11,7 @@
MaxSpeed
Order
Delay
+ CSChange
)
// Opener is an interface to be implemented by the SPI driver to open
@@ -34,6 +35,7 @@
// Some SPI devices require a minimum amount of wait time after
// each frame write. If set, Delay amount of usecs are inserted after
// each write.
+ // - CSChange, whether to leave the device's chipselect active after a Tx.
//
// SPI devices can override these values.
Configure(k, v int) error
diff --git a/io/spi/spi.go b/io/spi/spi.go
index 999f429..e351a57 100644
--- a/io/spi/spi.go
+++ b/io/spi/spi.go
@@ -67,6 +67,15 @@
return d.conn.Configure(driver.Delay, int(t.Nanoseconds()/1000))
}
+// SetCSChange sets whether to leave the chipselect enabled after a Tx.
+func (d *Device) SetCSChange(leaveEnabled bool) error {
+ v := 0
+ if leaveEnabled {
+ v = 1
+ }
+ return d.conn.Configure(driver.CSChange, v)
+}
+
// Tx performs a duplex transmission to write w to the SPI device
// and read len(r) bytes to r.
// User should not mutate the w and r until this call returns.