github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/pkg/spidev/spidev_linux.go (about) 1 // Copyright 2021 the u-root Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package spidev wraps the Linux spidev driver and performs low-level SPI 6 // operations. 7 package spidev 8 9 import ( 10 "encoding/binary" 11 "fmt" 12 "math" 13 "os" 14 "runtime" 15 "unsafe" 16 17 "golang.org/x/sys/unix" 18 ) 19 20 // See Linux "include/uapi/linux/spi/spidev.h" and 21 // "Documentation/spi/spidev.rst" 22 23 // Various ioctl numbers. 24 const ( 25 iocRdMode = 0x80016b01 26 iocWrMode = 0x40016b01 27 iocRdLSBFirst = 0x80016b02 28 iocWrLSBFirst = 0x40016b02 29 iocRdBitsPerWord = 0x80016b03 30 iocWrBitsPerWord = 0x40016b03 31 iocRdMaxSpeedHz = 0x80046b04 32 iocWrMaxSpeedHz = 0x40046b04 33 iocRdMode32 = 0x80046b05 34 iocWrMode32 = 0x40046b05 35 ) 36 37 // Constants used by iocMessage function. 38 const ( 39 // iocMessage0 is the length of a message of 0 length. Use the 40 // iocMessage(n) function for an iocMessage of length n. 41 iocMessage0 = 0x40006b00 42 sizeBits = 14 43 sizeShift = 16 44 sizeMask = ((1 << sizeBits) - 1) << sizeShift 45 ) 46 47 // maxTransferSize is the maximum size of a transfer. This is limited by the 48 // `length uint32` in the iocTransfer struct. 49 var maxTransferSize = math.MaxInt32 50 51 // iocMessage is an ioctl number for n Transfers. Since the ioctl number 52 // contains the size of the message, it is not a constant. 53 func iocMessage(n int) uint32 { 54 size := uint32(n * binary.Size(iocTransfer{})) 55 if n < 0 || size > (1<<sizeBits) { 56 return iocMessage(0) 57 } 58 return iocMessage0 | (size << sizeShift) 59 } 60 61 // Mode is a bitset of the current SPI mode bits. 62 type Mode uint32 63 64 const ( 65 // CPHA determines clock phase sampling (1=trailing edge). 66 CPHA Mode = 1 << iota 67 // CPOL determines clock polarity (1=idle high). 68 CPOL 69 // CS_HIGH determines chip select polarity (1=idle high). 70 CS_HIGH 71 // LSB_FIRST determines whether least significant bit comes first in a 72 // word (1=LSB first). 73 LSB_FIRST 74 // THREE_WIRE determines whether the bus operates in three wire mode 75 // (1=three wire). 76 THREE_WIRE 77 // LOOP determines whether the device should loop (1=loop enabled). 78 LOOP 79 // NO_CS determines whether to disable chip select (1=no chip select). 80 NO_CS 81 // READY determins ready mode bit. 82 READY 83 // TX_DUAL determines whether to transmit in dual mode. 84 TX_DUAL 85 // TX_QUAD determines whether to transmit in quad mode. 86 TX_QUAD 87 // RX_DUAL determines whether to receive in dual mode. 88 RX_DUAL 89 // RX_QUAD determines whether to receive in quad mode. 90 RX_QUAD 91 ) 92 93 // iocTransfer is the data type used by the iocMessage ioctl. Multiple such 94 // transfers may be chained together in a single ioctl call. 95 type iocTransfer struct { 96 // txBuf contains the userspace address of data to send. If this is 0, 97 // then zeros are shifted onto the SPI bus. 98 txBuf uint64 99 // rxBuf contains the userspace address of data to receive. If this is 100 // 0, data received is ignored. 101 rxBuf uint64 102 // length is the length of max{transfer, txBuf, rxBuf} in bytes. 103 length uint32 104 105 speedHz uint32 106 delayUSecs uint16 107 bitsPerWord uint8 108 csChange uint8 109 txNBits uint8 110 rxNBits uint8 111 wordDelayUSecs uint8 112 pad uint8 113 } 114 115 // Transfer is the data and options for a single SPI transfer. Note that a SPI 116 // transfer is full-duplex meaning data is shifted out of Tx and shifted into 117 // Rx on the same clock cycle. 118 type Transfer struct { 119 // Tx contains a slice sent over the SPI bus. 120 Tx []byte 121 // Rx contains a slice received from the SPI bus. 122 Rx []byte 123 124 // The following temporarily override the SPI mode. They only apply to 125 // the current transfer. 126 127 // SpeedHz sets speed in Hz (optional). 128 SpeedHz uint32 129 // DelayUSecs is how long to delay before the next transfer (optional). 130 DelayUSecs uint16 131 // BitsPerWord is the device's wordsize (optional). 132 BitsPerWord uint8 133 // CSChange controls whether the CS (Chip Select) signal will be 134 // de-asserted at the end of the transfer. 135 CSChange bool 136 // TxNbits controls single, dual or quad mode (optional). 137 TxNBits uint8 138 // RxNbits controls single, dual or quad mode (optional). 139 RxNBits uint8 140 // WordDelayUSecs is the delay between words (optional). 141 WordDelayUSecs uint8 142 } 143 144 // ErrTxOverflow is returned if the Transfer buffer is too large. 145 type ErrTxOverflow struct { 146 TxLen, TxMax int 147 } 148 149 // Error implements the error interface. 150 func (e ErrTxOverflow) Error() string { 151 return fmt.Sprintf("SPI tx buffer overflow (%d > %d)", e.TxLen, e.TxMax) 152 } 153 154 // ErrRxOverflow is returned if the Transfer buffer is too large. 155 type ErrRxOverflow struct { 156 RxLen, RxMax int 157 } 158 159 // Error implements the error interface. 160 func (e ErrRxOverflow) Error() string { 161 return fmt.Sprintf("SPI rx buffer overflow (%d > %d)", e.RxLen, e.RxMax) 162 } 163 164 // ErrBufferMismatch is returned if the rx and tx buffers do not have equal 165 // length. 166 type ErrBufferMismatch struct { 167 TxLen, RxLen int 168 } 169 170 // Error implements the error interface. 171 func (e ErrBufferMismatch) Error() string { 172 return fmt.Sprintf("SPI tx and rx buffers of unequal length (%d != %d)", e.TxLen, e.RxLen) 173 } 174 175 // SPI wraps the Linux device driver and provides low-level SPI operations. 176 type SPI struct { 177 f *os.File 178 // Used for mocking. 179 syscall func(trap, a1, a2 uintptr, a3 unsafe.Pointer) (r1, r2 uintptr, err unix.Errno) 180 } 181 182 // Open opens a new SPI device. dev is a filename such as "/dev/spidev0.0". 183 // Remember to call Close() once done. 184 func Open(dev string) (*SPI, error) { 185 f, err := os.OpenFile(dev, os.O_RDWR, 0) 186 if err != nil { 187 return nil, err 188 } 189 return &SPI{ 190 f: f, 191 // a3 must be an unsafe.Pointer instead of a uintptr, otherwise 192 // we cannot mock out in the test without creating a race 193 // condition. See `go doc unsafe.Pointer`. 194 syscall: func(trap, a1, a2 uintptr, a3 unsafe.Pointer) (r1, r2 uintptr, err unix.Errno) { 195 return unix.Syscall(trap, a1, a2, uintptr(a3)) 196 }, 197 }, err 198 } 199 200 // Close closes the SPI device. 201 func (s *SPI) Close() error { 202 return s.f.Close() 203 } 204 205 // Transfer performs multiple SPI reads and/or writes in a single function. 206 // See the Transfer struct for details. 207 func (s *SPI) Transfer(transfers []Transfer) error { 208 // Convert []Transfer to []iocTransfer. 209 it := make([]iocTransfer, len(transfers)) 210 for i, t := range transfers { 211 it[i] = iocTransfer{ 212 speedHz: t.SpeedHz, 213 delayUSecs: t.DelayUSecs, 214 bitsPerWord: t.BitsPerWord, 215 txNBits: t.TxNBits, 216 rxNBits: t.RxNBits, 217 wordDelayUSecs: t.WordDelayUSecs, 218 } 219 if len(t.Tx) > maxTransferSize { 220 return ErrTxOverflow{len(t.Tx), maxTransferSize} 221 } 222 if len(t.Rx) > maxTransferSize { 223 return ErrRxOverflow{len(t.Rx), maxTransferSize} 224 } 225 if len(t.Tx) != 0 && len(t.Rx) != 0 && len(t.Tx) != len(t.Rx) { 226 return ErrBufferMismatch{len(t.Tx), len(t.Rx)} 227 } 228 if len(t.Tx) != 0 { 229 txBuf := &transfers[i].Tx[0] 230 it[i].txBuf = uint64(uintptr(unsafe.Pointer(txBuf))) 231 it[i].length = uint32(len(t.Tx)) 232 // Defer garbage collection until after the syscall. 233 defer runtime.KeepAlive(txBuf) 234 } 235 if len(t.Rx) != 0 { 236 rxBuf := &transfers[i].Rx[0] 237 it[i].rxBuf = uint64(uintptr(unsafe.Pointer(rxBuf))) 238 it[i].length = uint32(len(t.Rx)) 239 // Defer garbage collection until after the syscall. 240 defer runtime.KeepAlive(rxBuf) 241 } 242 if transfers[i].CSChange { 243 it[i].csChange = 1 244 } 245 } 246 247 if _, _, err := s.syscall(unix.SYS_IOCTL, s.f.Fd(), uintptr(iocMessage(len(transfers))), unsafe.Pointer(&it[0])); err != 0 { 248 return os.NewSyscallError("ioctl(SPI_IOC_MESSAGE)", err) 249 } 250 return nil 251 } 252 253 // Mode returns the Mode bitset. 254 func (s *SPI) Mode() (Mode, error) { 255 var m Mode 256 if _, _, err := s.syscall(unix.SYS_IOCTL, s.f.Fd(), iocRdMode32, unsafe.Pointer(&m)); err != 0 { 257 return 0, os.NewSyscallError("ioctl(SPI_IOC_RD_MODE32)", err) 258 } 259 return m, nil 260 } 261 262 // SetMode sets the Mode bitset. 263 func (s *SPI) SetMode(m Mode) error { 264 if _, _, err := s.syscall(unix.SYS_IOCTL, s.f.Fd(), iocWrMode32, unsafe.Pointer(&m)); err != 0 { 265 return os.NewSyscallError("ioctl(SPI_IOC_WR_MODE32)", err) 266 } 267 return nil 268 } 269 270 // BitsPerWord sets the number of bits per word. Myy understanding is this is 271 // only useful if there is a word delay. 272 func (s *SPI) BitsPerWord() (uint8, error) { 273 var bpw uint8 274 if _, _, err := s.syscall(unix.SYS_IOCTL, s.f.Fd(), iocRdBitsPerWord, unsafe.Pointer(&bpw)); err != 0 { 275 return bpw, os.NewSyscallError("ioctl(SPI_IOC_RD_BITS_PER_WORD)", err) 276 } 277 return bpw, nil 278 } 279 280 // SetBitsPerWord sets the number of bits per word. 281 func (s *SPI) SetBitsPerWord(bpw uint8) error { 282 if _, _, err := s.syscall(unix.SYS_IOCTL, s.f.Fd(), iocWrBitsPerWord, unsafe.Pointer(&bpw)); err != 0 { 283 return os.NewSyscallError("ioctl(SPI_IOC_WR_BITS_PER_WORD)", err) 284 } 285 return nil 286 } 287 288 // SpeedHz gets the transfer speed. 289 func (s *SPI) SpeedHz() (uint32, error) { 290 var hz uint32 291 if _, _, err := s.syscall(unix.SYS_IOCTL, s.f.Fd(), iocRdMaxSpeedHz, unsafe.Pointer(&hz)); err != 0 { 292 return hz, os.NewSyscallError("ioctl(SPI_IOC_RD_MAX_SPEED_HZ)", err) 293 } 294 return hz, nil 295 } 296 297 // SetSpeedHz sets the transfer speed. 298 func (s *SPI) SetSpeedHz(hz uint32) error { 299 if _, _, err := s.syscall(unix.SYS_IOCTL, s.f.Fd(), iocWrMaxSpeedHz, unsafe.Pointer(&hz)); err != 0 { 300 return os.NewSyscallError("ioctl(SPI_IOC_WR_MAX_SPEED_HZ)", err) 301 } 302 return nil 303 }