golang.org/x/exp@v0.0.0-20240506185415-9bf2ced13842/io/spi/devfs.go (about)

     1  // Copyright 2016 The Go 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  //go:build linux
     6  
     7  package spi
     8  
     9  import (
    10  	"fmt"
    11  	"os"
    12  	"syscall"
    13  	"unsafe"
    14  
    15  	"golang.org/x/exp/io/spi/driver"
    16  )
    17  
    18  const (
    19  	devfs_MAGIC = 107
    20  
    21  	devfs_NRBITS   = 8
    22  	devfs_TYPEBITS = 8
    23  	devfs_SIZEBITS = 13
    24  	devfs_DIRBITS  = 3
    25  
    26  	devfs_NRSHIFT   = 0
    27  	devfs_TYPESHIFT = devfs_NRSHIFT + devfs_NRBITS
    28  	devfs_SIZESHIFT = devfs_TYPESHIFT + devfs_TYPEBITS
    29  	devfs_DIRSHIFT  = devfs_SIZESHIFT + devfs_SIZEBITS
    30  
    31  	devfs_READ  = 2
    32  	devfs_WRITE = 4
    33  )
    34  
    35  type payload struct {
    36  	tx       uint64
    37  	rx       uint64
    38  	length   uint32
    39  	speed    uint32
    40  	delay    uint16
    41  	bits     uint8
    42  	csChange uint8
    43  	txNBits  uint8
    44  	rxNBits  uint8
    45  	pad      uint16
    46  }
    47  
    48  // Devfs is an SPI driver that works against the devfs.
    49  // You need to have loaded the "spidev" Linux module to use this driver.
    50  type Devfs struct {
    51  	// Dev is the device to be opened.
    52  	// Device name is usually in the /dev/spidev<bus>.<chip> format.
    53  	// Required.
    54  	Dev string
    55  
    56  	// Mode is the SPI mode. SPI mode is a combination of polarity and phases.
    57  	// CPOL is the high order bit, CPHA is the low order. Pre-computed mode
    58  	// values are Mode0, Mode1, Mode2 and Mode3. The value of the mode argument
    59  	// can be overridden by the device's driver.
    60  	// Required.
    61  	Mode Mode
    62  
    63  	// MaxSpeed is the max clock speed (Hz) and can be overridden by the device's driver.
    64  	// Required.
    65  	MaxSpeed int64
    66  }
    67  
    68  // Open opens the provided device with the specified options
    69  // and returns a connection.
    70  func (d *Devfs) Open() (driver.Conn, error) {
    71  	f, err := os.OpenFile(d.Dev, os.O_RDWR, os.ModeDevice)
    72  	if err != nil {
    73  		return nil, err
    74  	}
    75  	conn := &devfsConn{f: f}
    76  	if err := conn.Configure(driver.Mode, int(d.Mode)); err != nil {
    77  		conn.Close()
    78  		return nil, err
    79  	}
    80  	if err := conn.Configure(driver.MaxSpeed, int(d.MaxSpeed)); err != nil {
    81  		conn.Close()
    82  		return nil, err
    83  	}
    84  	return conn, nil
    85  }
    86  
    87  type devfsConn struct {
    88  	f        *os.File
    89  	mode     uint8
    90  	speed    uint32
    91  	bits     uint8
    92  	delay    uint16
    93  	csChange uint8
    94  }
    95  
    96  func (c *devfsConn) Configure(k, v int) error {
    97  	switch k {
    98  	case driver.Mode:
    99  		m := uint8(v)
   100  		if err := c.ioctl(requestCode(devfs_WRITE, devfs_MAGIC, 1, 1), uintptr(unsafe.Pointer(&m))); err != nil {
   101  			return fmt.Errorf("error setting mode to %v: %v", m, err)
   102  		}
   103  		c.mode = m
   104  	case driver.Bits:
   105  		b := uint8(v)
   106  		if err := c.ioctl(requestCode(devfs_WRITE, devfs_MAGIC, 3, 1), uintptr(unsafe.Pointer(&b))); err != nil {
   107  			return fmt.Errorf("error setting bits per word to %v: %v", b, err)
   108  		}
   109  		c.bits = b
   110  	case driver.MaxSpeed:
   111  		s := uint32(v)
   112  		if err := c.ioctl(requestCode(devfs_WRITE, devfs_MAGIC, 4, 4), uintptr(unsafe.Pointer(&s))); err != nil {
   113  			return fmt.Errorf("error setting speed to %v: %v", s, err)
   114  		}
   115  		c.speed = s
   116  	case driver.Order:
   117  		o := uint8(v)
   118  		if err := c.ioctl(requestCode(devfs_WRITE, devfs_MAGIC, 2, 1), uintptr(unsafe.Pointer(&o))); err != nil {
   119  			return fmt.Errorf("error setting bit order to %v: %v", o, err)
   120  		}
   121  	case driver.Delay:
   122  		c.delay = uint16(v)
   123  	case driver.CSChange:
   124  		c.csChange = uint8(v)
   125  	default:
   126  		return fmt.Errorf("unknown key: %v", k)
   127  	}
   128  	return nil
   129  }
   130  
   131  func (c *devfsConn) Tx(w, r []byte) error {
   132  	if r == nil {
   133  		r = make([]byte, len(w))
   134  	}
   135  	// TODO(jbd): len(w) == len(r)?
   136  	// TODO(jbd): Allow nil w.
   137  	p := payload{
   138  		tx:       uint64(uintptr(unsafe.Pointer(&w[0]))),
   139  		rx:       uint64(uintptr(unsafe.Pointer(&r[0]))),
   140  		length:   uint32(len(w)),
   141  		speed:    c.speed,
   142  		delay:    c.delay,
   143  		bits:     c.bits,
   144  		csChange: c.csChange,
   145  	}
   146  	// TODO(jbd): Read from the device and fill rx.
   147  	return c.ioctl(msgRequestCode(1), uintptr(unsafe.Pointer(&p)))
   148  }
   149  
   150  func (c *devfsConn) Close() error {
   151  	return c.f.Close()
   152  }
   153  
   154  // requestCode returns the device specific request code for the specified direction,
   155  // type, number and size to be used in the ioctl call.
   156  func requestCode(dir, typ, nr, size uintptr) uintptr {
   157  	return (dir << devfs_DIRSHIFT) | (typ << devfs_TYPESHIFT) | (nr << devfs_NRSHIFT) | (size << devfs_SIZESHIFT)
   158  }
   159  
   160  // msgRequestCode returns the device specific value for the SPI
   161  // message payload to be used in the ioctl call.
   162  // n represents the number of messages.
   163  func msgRequestCode(n uint32) uintptr {
   164  	return uintptr(0x40006B00 + (n * 0x200000))
   165  }
   166  
   167  // ioctl makes an IOCTL on the open device file descriptor.
   168  func (c *devfsConn) ioctl(a1, a2 uintptr) error {
   169  	_, _, errno := syscall.Syscall(
   170  		syscall.SYS_IOCTL, c.f.Fd(), a1, a2,
   171  	)
   172  	if errno != 0 {
   173  		return syscall.Errno(errno)
   174  	}
   175  	return nil
   176  }