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 }