Skip to content

Commit f52ebf0

Browse files
committed
Implement SMBus read/write byte data when I2C functions are not available
1 parent 9cd28b7 commit f52ebf0

File tree

1 file changed

+65
-0
lines changed

1 file changed

+65
-0
lines changed

sysfs/i2c.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,11 @@ func (i *I2C) Tx(addr uint16, w, r []byte) error {
9797
return nil
9898
}
9999

100+
// If I2C is not supported, fallback to SMBus
101+
if i.fn&funcI2C == 0 {
102+
return i.smbusTx(addr, w, r)
103+
}
104+
100105
// Convert the messages to the internal format.
101106
var buf [2]i2cMsg
102107
msgs := buf[0:0]
@@ -197,6 +202,65 @@ func (i *I2C) initPins() {
197202
i.mu.Unlock()
198203
}
199204

205+
func (i *I2C) smbusTx(addr uint16, w, r []byte) error {
206+
switch {
207+
case len(w) == 1 && len(r) == 1:
208+
// SMBus Read Byte Data
209+
return i.smbusCmd(addr, true, w[0], protocolByteData, r)
210+
case len(w) == 2 && len(r) == 0:
211+
// SMBus Write Byte Data
212+
return i.smbusCmd(addr, false, w[0], protocolByteData, w[1:])
213+
default:
214+
return errors.New("sysfs-i2c: unsupported SMBus transaction")
215+
}
216+
}
217+
218+
// SMBus IOCTL calls this size but it's not actually a size field.
219+
type smbusProtocol uint32
220+
221+
const (
222+
protocolByteData smbusProtocol = 2
223+
)
224+
225+
func (i *I2C) smbusCmd(addr uint16, read bool, reg byte, protocol smbusProtocol, data []byte) error {
226+
rw := byte(0) // write
227+
if read {
228+
rw = byte(1) // read
229+
}
230+
231+
// Make a contiguous copy of data to avoid issues with slices.
232+
buf := make([]byte, len(data))
233+
copy(buf, data)
234+
defer copy(data, buf)
235+
236+
// Prepare the I2C_SMBUS ioctl command.
237+
cmd := struct {
238+
rw byte
239+
command byte
240+
size uint32
241+
data unsafe.Pointer
242+
}{
243+
rw,
244+
reg,
245+
uint32(protocol),
246+
unsafe.Pointer(&buf[0]),
247+
}
248+
249+
i.mu.Lock()
250+
defer i.mu.Unlock()
251+
252+
// Set the slave address.
253+
if err := i.f.Ioctl(ioctlSlave, uintptr(addr)); err != nil {
254+
return fmt.Errorf("sysfs-smbus: %v", err)
255+
}
256+
257+
// Perform the transaction.
258+
if err := i.f.Ioctl(ioctlSmbus, uintptr(unsafe.Pointer(&cmd))); err != nil {
259+
return fmt.Errorf("sysfs-smbus: %v", err)
260+
}
261+
return nil
262+
}
263+
200264
// i2cdev driver IOCTL control codes.
201265
//
202266
// Constants and structure definition can be found at
@@ -208,6 +272,7 @@ const (
208272
ioctlTenBits = 0x704 // TODO(maruel): Expose this but the header says it's broken (!?)
209273
ioctlFuncs = 0x705
210274
ioctlRdwr = 0x707
275+
ioctlSmbus = 0x720
211276
)
212277

213278
// flags

0 commit comments

Comments
 (0)