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  }