io/i2c: add support 10-bit addresses
10-bit addresses can range from 0 to (1111111111)2. That's why we need
to know in advance if the user is working with a 10-bit addressed
device.
The kernel driver also provides an ioctl function to enable the 10-bit
mode before setting the address globally on the device. Devfs enables
10-bit mode if it is required.
Change-Id: I71e64ab77c68903bbe9c0ac589300eb1bc29ff43
Reviewed-on: https://go-review.googlesource.com/22516
Reviewed-by: Minux Ma <minux@golang.org>
diff --git a/io/i2c/devfs.go b/io/i2c/devfs.go
index 00853a7..34d9c0a 100644
--- a/io/i2c/devfs.go
+++ b/io/i2c/devfs.go
@@ -17,17 +17,24 @@
type Devfs struct{}
const (
- i2c_SLAVE = 0x0703 // TODO(jbd): Allow users to use I2C_SLAVE_FORCE?
+ i2c_SLAVE = 0x0703 // TODO(jbd): Allow users to use I2C_SLAVE_FORCE?
+ i2c_TENBIT = 0x0704
)
// TODO(jbd): Support I2C_RETRIES and I2C_TIMEOUT at the driver and implementation level.
-func (d *Devfs) Open(bus, addr int) (driver.Conn, error) {
+func (d *Devfs) Open(bus, addr int, tenbit bool) (driver.Conn, error) {
f, err := os.OpenFile(fmt.Sprintf("/dev/i2c-%d", bus), os.O_RDWR, os.ModeDevice)
if err != nil {
return nil, err
}
conn := &devfsConn{f: f}
+ if tenbit {
+ if err := conn.ioctl(i2c_TENBIT, uintptr(1)); err != nil {
+ conn.Close()
+ return nil, fmt.Errorf("cannot enable the 10-bit address mode on bus %v: %v", bus, err)
+ }
+ }
if err := conn.ioctl(i2c_SLAVE, uintptr(addr)); err != nil {
conn.Close()
return nil, fmt.Errorf("error opening the address (%v) on the bus (%v): %v", addr, bus, err)
diff --git a/io/i2c/driver/driver.go b/io/i2c/driver/driver.go
index a2be469..09f3bd3 100644
--- a/io/i2c/driver/driver.go
+++ b/io/i2c/driver/driver.go
@@ -7,9 +7,10 @@
// Opener is an interface to be implemented by the I2C driver to open
// a connection to an I2C device with the specified bus number and I2C address.
-// Open should support 7-bit and 10-bit I2C addresses.
+// Open should support 7-bit addresses and should provide support for
+// 10-bit I2C addresses if tenbit is true.
type Opener interface {
- Open(bus, addr int) (Conn, error)
+ Open(bus, addr int, tenbit bool) (Conn, error)
}
// Conn represents an active connection to an I2C device.
diff --git a/io/i2c/i2c.go b/io/i2c/i2c.go
index f48a213..f8f0cf1 100644
--- a/io/i2c/i2c.go
+++ b/io/i2c/i2c.go
@@ -11,15 +11,21 @@
"golang.org/x/exp/io/i2c/driver"
)
+const tenbitMask = 1 << 12
+
// Device represents an I2C device. Devices must be closed once
// they are no longer in use.
type Device struct {
conn driver.Conn
}
+// TenBit marks an I2C address as a 10-bit address.
+func TenBit(addr int) int {
+ return addr | tenbitMask
+}
+
// TOOD(jbd): Do we need higher level I2C packet writers and readers?
// TODO(jbd): Support bidirectional communication.
-// TODO(jbd): How do we support 10-bit addresses and how to enable 10-bit on devfs?
// Read reads len(buf) bytes from the device.
func (d *Device) Read(buf []byte) error {
@@ -47,13 +53,19 @@
}
// Open opens an I2C device with the given I2C address on the specified bus.
+// Use TenBit to mark your address if your device works with 10-bit addresses.
func Open(o driver.Opener, bus, addr int) (*Device, error) {
if o == nil {
o = &Devfs{}
}
- conn, err := o.Open(bus, addr)
+ addr, tenbit := resolveAddr(addr)
+ conn, err := o.Open(bus, addr, tenbit)
if err != nil {
return nil, err
}
return &Device{conn: conn}, nil
}
+
+func resolveAddr(a int) (addr int, tenbit bool) {
+ return a & (tenbitMask - 1), a&tenbitMask == tenbitMask
+}
diff --git a/io/i2c/i2c_test.go b/io/i2c/i2c_test.go
new file mode 100644
index 0000000..a48baad
--- /dev/null
+++ b/io/i2c/i2c_test.go
@@ -0,0 +1,31 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package i2c
+
+import (
+ "testing"
+)
+
+func TestTenBit(t *testing.T) {
+ tc := []struct {
+ masked int
+ addr int
+ tenbit bool
+ }{
+ {TenBit(0x5), 0x5, true},
+ {0x5, 0x5, false},
+ {TenBit(0x40), 0x40, true},
+ }
+
+ for _, tt := range tc {
+ unmasked, tenbit := resolveAddr(tt.masked)
+ if want, got := tt.tenbit, tenbit; got != want {
+ t.Errorf("want address %b as 10-bit; got non 10-bit", tt.addr)
+ }
+ if want, got := tt.addr, unmasked; got != want {
+ t.Errorf("want address %b; got %b", want, got)
+ }
+ }
+}