rppal/
i2c.rs

1//! Interface for the I2C peripheral.
2//!
3//! The Broadcom Serial Controller (BSC) peripheral controls a proprietary bus
4//! compliant with the I2C bus/interface. RPPAL communicates with the BSC
5//! using the `i2cdev` device interface.
6//!
7//! ## I2C buses
8//!
9//! The Raspberry Pi 3 B+ and earlier models support three hardware I2C buses,
10//! however only the I2C bus on physical pins 3 and 5 should be used to communicate
11//! with slave devices. The other two buses are used internally as an HDMI
12//! interface, and for HAT identification.
13//!
14//! On the Raspberry Pi 4 B, 400 and 5, three additional I2C buses are available,
15//! depending on your configuration, as explained below.
16//!
17//! ### I2C0 / I2C1
18//!
19//! On the Raspberry Pi B Rev 1, physical pins 3 (SDA) and 5 (SCL) are tied to I2C0.
20//! On every other Raspberry Pi model, they're connected to I2C1.
21//!
22//! The I2C bus connected to these pins is disabled by
23//! default. You can enable it through `sudo raspi-config`, or by manually
24//! adding `dtparam=i2c_arm=on` to `/boot/firmware/config.txt`. Remember to reboot
25//! the Raspberry Pi afterwards.
26//!
27//! * SDA: BCM GPIO 2 (physical pin 3)
28//! * SCL: BCM GPIO 3 (physical pin 5)
29//!
30//! ### I2C3
31//!
32//! I2C3 can be enabled by adding `dtoverlay=i2c3` to `/boot/firmware/config.txt`.
33//!
34//! * SDA: BCM GPIO 4 (physical pin 7)
35//! * SCL: BCM GPIO 5 (physical pin 29)
36//!
37//! ### I2C4
38//!
39//! I2C4 can be enabled by adding `dtoverlay=i2c4` to `/boot/firmware/config.txt`.
40//!
41//! * SDA: BCM GPIO 8 (physical pin 24)
42//! * SCL: BCM GPIO 9 (physical pin 21)
43//!
44//! ### I2C5
45//!
46//! I2C5 can be enabled by adding `dtoverlay=i2c5` to `/boot/firmware/config.txt`.
47//!
48//! * SDA: BCM GPIO 12 (physical pin 32)
49//! * SCL: BCM GPIO 13 (physical pin 33)
50//!
51//! ### I2C6
52//!
53//! I2C6 can be enabled by adding `dtoverlay=i2c6` to `/boot/firmware/config.txt`.
54//!
55//! * SDA: BCM GPIO 22 (physical pin 15)
56//! * SCL: BCM GPIO 23 (physical pin 16)
57//!
58//! ### Alternative pins
59//!
60//! The GPIO pin numbers mentioned above are part of the default configuration.
61//! Some of their functionality can be moved to different pins. Read
62//! `/boot/overlays/README` for more information.
63//!
64//! ### Software I2C
65//!
66//! In addition to the hardware I2C buses, it's possible to configure a
67//! bit-banged software I2C bus on any available GPIO pins through the `i2c-gpio`
68//! device tree overlay. More details on enabling and configuring `i2c-gpio`
69//! can be found in `/boot/overlays/README`.
70//!
71//! ## Transmission speed
72//!
73//! The BSC supports I2C data transfer rates up to 400 kbit/s (Fast-mode).
74//!
75//! By default, the I2C bus clock speed is set to 100 kHz. Transferring
76//! 1 bit takes 1 clock cycle. You can change the
77//! transfer rate by adding `dtparam=i2c_arm_baudrate=X` to
78//! `/boot/firmware/config.txt`, where `X` should be replaced with the
79//! clock frequency in hertz (Hz). Remember to reboot
80//! the Raspberry Pi afterwards.
81//!
82//! ## Not supported
83//!
84//! Some I2C and SMBus features aren't fully supported by the `i2cdev` interface, the underlying driver or
85//! the BCM283x SoC: 10-bit slave addresses, SMBus Block Read, SMBus Block Process Call, SMBus Host Notify,
86//! SMBus Read/Write 32/64, and the SMBus Address Resolution Protocol.
87//!
88//! While clock stretching is supported, a bug exists in the implementation on the BCM283x SoC that will result
89//! in corrupted data when a slave device uses clock stretching at arbitrary points during the transfer.
90//! Clock stretching only works properly during read operations, directly after the ACK phase, when the additional
91//! delay is longer than half of a clock period. More information can be found [here](https://elinux.org/BCM2835_datasheet_errata#p35_I2C_clock_stretching).
92//!
93//! A possible workaround for slave devices that require clock stretching at other points during the transfer is
94//! to use a bit-banged software I2C bus by configuring the `i2c-gpio` device tree overlay as described in `/boot/overlays/README`.
95//!
96//! ## Troubleshooting
97//!
98//! ### Permission denied
99//!
100//! If [`new`] or [`with_bus`] returns an `io::ErrorKind::PermissionDenied`
101//! error, make sure the file permissions for `/dev/i2c-1` or `/dev/i2c-0`
102//! are correct, and the current user is a member of the `i2c` group.
103//!
104//! ### Timed out
105//!
106//! Transactions return an `io::ErrorKind::TimedOut` error when their duration
107//! exceeds the timeout value. You can change the timeout using [`set_timeout`].
108//!
109//! [`new`]: struct.I2c.html#method.new
110//! [`with_bus`]: struct.I2c.html#method.with_bus
111//! [`set_timeout`]: struct.I2c.html#method.set_timeout
112
113#![allow(dead_code)]
114
115use std::error;
116use std::fmt;
117use std::fs::{File, OpenOptions};
118use std::io;
119use std::io::{Read, Write};
120use std::marker::PhantomData;
121use std::os::unix::io::AsRawFd;
122use std::result;
123
124use libc::c_ulong;
125
126use crate::system;
127use crate::system::{DeviceInfo, Model};
128
129#[cfg(any(
130    feature = "embedded-hal-0",
131    feature = "embedded-hal",
132    feature = "embedded-hal-nb"
133))]
134mod hal;
135mod ioctl;
136
137pub use self::ioctl::Capabilities;
138
139/// Errors that can occur when accessing the I2C peripheral.
140#[derive(Debug)]
141pub enum Error {
142    /// I/O error.
143    Io(io::Error),
144    /// Invalid slave address.
145    ///
146    /// I2C supports 7-bit and 10-bit addresses. Several 7-bit addresses
147    /// can't be used as slave addresses.
148    InvalidSlaveAddress(u16),
149    /// I2C/SMBus feature not supported.
150    ///
151    /// The underlying drivers don't support the selected I2C feature or SMBus protocol.
152    FeatureNotSupported,
153    /// Unknown model.
154    ///
155    /// The Raspberry Pi model or SoC can't be identified. Support for
156    /// new models is usually added shortly after they are officially
157    /// announced and available to the public. Make sure you're using
158    /// the latest release of RPPAL.
159    ///
160    /// You may also encounter this error if your Linux distribution
161    /// doesn't provide any of the common user-accessible system files
162    /// that are used to identify the model and SoC.
163    UnknownModel,
164}
165
166impl fmt::Display for Error {
167    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
168        match *self {
169            Error::Io(ref err) => write!(f, "I/O error: {}", err),
170            Error::InvalidSlaveAddress(address) => write!(f, "Invalid slave address: {}", address),
171            Error::FeatureNotSupported => write!(f, "I2C/SMBus feature not supported"),
172            Error::UnknownModel => write!(f, "Unknown Raspberry Pi model"),
173        }
174    }
175}
176
177impl error::Error for Error {}
178
179impl From<io::Error> for Error {
180    fn from(err: io::Error) -> Error {
181        Error::Io(err)
182    }
183}
184
185impl From<system::Error> for Error {
186    fn from(_err: system::Error) -> Error {
187        Error::UnknownModel
188    }
189}
190
191/// Result type returned from methods that can have `i2c::Error`s.
192pub type Result<T> = result::Result<T, Error>;
193
194/// Provides access to the Raspberry Pi's I2C peripheral.
195///
196/// Before using `I2c`, make sure your Raspberry Pi has the necessary I2C buses
197/// enabled. More information can be found [here].
198///
199/// Besides basic I2C communication through buffer reads and writes, `I2c` can
200/// also be used with devices that require SMBus (System Management Bus) support.
201/// SMBus is based on I2C, and defines more structured message transactions
202/// through its various protocols. More details can be found in the latest SMBus
203/// [specification].
204///
205/// The `embedded-hal` trait implementations for `I2c` can be enabled by specifying
206/// the optional `hal` feature in the dependency declaration for the `rppal` crate.
207///
208/// [here]: index.html#i2c-buses
209/// [specification]: http://smbus.org/specs/SMBus_3_1_20180319.pdf
210#[derive(Debug)]
211pub struct I2c {
212    bus: u8,
213    funcs: Capabilities,
214    i2cdev: File,
215    addr_10bit: bool,
216    address: u16,
217    // The not_sync field is a workaround to force !Sync. I2c isn't safe for
218    // Sync because of ioctl() and the underlying drivers. This avoids needing
219    // #![feature(optin_builtin_traits)] to manually add impl !Sync for I2c.
220    not_sync: PhantomData<*const ()>,
221}
222
223impl I2c {
224    /// Constructs a new `I2c`.
225    ///
226    /// `new` attempts to identify which I2C bus is bound to physical pins 3 (SDA)
227    /// and 5 (SCL) based on the Raspberry Pi model.
228    ///
229    /// More information on configuring the I2C buses can be found [here].
230    ///
231    /// [here]: index.html#i2c-buses
232    pub fn new() -> Result<I2c> {
233        match DeviceInfo::new()?.model() {
234            // Pi B Rev 1 uses I2C0
235            Model::RaspberryPiBRev1 => I2c::with_bus(0),
236            Model::RaspberryPi4B
237            | Model::RaspberryPi400
238            | Model::RaspberryPiComputeModule4
239            | Model::RaspberryPiComputeModule4S
240            | Model::RaspberryPi5
241            | Model::RaspberryPi500
242            | Model::RaspberryPiComputeModule5
243            | Model::RaspberryPiComputeModule5Lite => {
244                // Pi 4B/400 could have I2C3 enabled on pins 3 and 5
245                I2c::with_bus(1).or_else(|_| I2c::with_bus(3))
246            }
247            // Everything else should be using I2C1
248            _ => I2c::with_bus(1),
249        }
250    }
251
252    /// Constructs a new `I2c` using the specified bus.
253    ///
254    /// `bus` indicates the selected I2C bus. You'll typically want to select the
255    /// bus that's bound to physical pins 3 (SDA) and 5 (SCL). On the Raspberry
256    /// Pi B Rev 1, those pins are tied to bus 0. On every other Raspberry
257    /// Pi model, they're connected to bus 1. Additional I2C buses are available
258    /// on the Raspberry Pi 4 B, 400 and 5.
259    ///
260    /// More information on configuring the I2C buses can be found [here].
261    ///
262    /// [here]: index.html#i2c-buses
263    pub fn with_bus(bus: u8) -> Result<I2c> {
264        // bus is a u8, because any 8-bit bus ID could potentially
265        // be configured for bit banging I2C using i2c-gpio.
266        let i2cdev = OpenOptions::new()
267            .read(true)
268            .write(true)
269            .open(format!("/dev/i2c-{}", bus))?;
270
271        let capabilities = ioctl::funcs(i2cdev.as_raw_fd())?;
272
273        // Disable 10-bit addressing if it's supported
274        if capabilities.addr_10bit() {
275            ioctl::set_addr_10bit(i2cdev.as_raw_fd(), 0)?;
276        }
277
278        // Disable PEC if it's supported
279        if capabilities.smbus_pec() {
280            ioctl::set_pec(i2cdev.as_raw_fd(), 0)?;
281        }
282
283        Ok(I2c {
284            bus,
285            funcs: capabilities,
286            i2cdev,
287            addr_10bit: false,
288            address: 0,
289            not_sync: PhantomData,
290        })
291    }
292
293    /// Returns information on the functionality supported by the underlying drivers.
294    ///
295    /// The returned [`Capabilities`] instance lists the available
296    /// I2C and SMBus features.
297    ///
298    /// [`Capabilities`]: struct.Capabilities.html
299    pub fn capabilities(&self) -> Capabilities {
300        self.funcs
301    }
302
303    /// Returns the I2C bus ID.
304    pub fn bus(&self) -> u8 {
305        self.bus
306    }
307
308    /// Returns the clock frequency in hertz (Hz).
309    pub fn clock_speed(&self) -> Result<u32> {
310        let mut buffer = [0u8; 4];
311
312        File::open(format!(
313            "/sys/class/i2c-adapter/i2c-{}/of_node/clock-frequency",
314            self.bus
315        ))?
316        .read_exact(&mut buffer)?;
317
318        Ok(u32::from(buffer[3])
319            | (u32::from(buffer[2]) << 8)
320            | (u32::from(buffer[1]) << 16)
321            | (u32::from(buffer[0]) << 24))
322    }
323
324    /// Sets a 7-bit or 10-bit slave address.
325    ///
326    /// `slave_address` refers to the slave device you're communicating with.
327    /// The specified address shouldn't include the R/W bit.
328    ///
329    /// By default, 10-bit addressing is disabled, which means
330    /// `set_slave_address` only accepts 7-bit addresses. 10-bit addressing
331    /// can be enabled with [`set_addr_10bit`]. Note that setting a 7-bit
332    /// address when 10-bit addressing is enabled won't correctly target a
333    /// slave device that doesn't support 10-bit addresses.
334    ///
335    /// [`set_addr_10bit`]: #method.set_addr_10bit
336    pub fn set_slave_address(&mut self, slave_address: u16) -> Result<()> {
337        // Filter out invalid and unsupported addresses
338        if (!self.addr_10bit && ((slave_address >> 3) == 0b1111 || slave_address > 0x7F))
339            || (self.addr_10bit && slave_address > 0x03FF)
340        {
341            return Err(Error::InvalidSlaveAddress(slave_address));
342        }
343
344        ioctl::set_slave_address(self.i2cdev.as_raw_fd(), c_ulong::from(slave_address))?;
345
346        self.address = slave_address;
347
348        Ok(())
349    }
350
351    /// Sets the maximum duration of a transaction in milliseconds (ms).
352    ///
353    /// Transactions that take longer than `timeout` return an
354    /// `io::ErrorKind::TimedOut` error.
355    ///
356    /// `timeout` has a resolution of 10ms.
357    pub fn set_timeout(&self, timeout: u32) -> Result<()> {
358        // Contrary to the i2cdev documentation, this seems to
359        // be used as a timeout for (part of?) the I2C transaction.
360        ioctl::set_timeout(self.i2cdev.as_raw_fd(), timeout as c_ulong)?;
361
362        Ok(())
363    }
364
365    fn set_retries(&self, retries: u32) -> Result<()> {
366        // Set to private. While i2cdev implements retries, the underlying drivers don't.
367        ioctl::set_retries(self.i2cdev.as_raw_fd(), retries as c_ulong)?;
368
369        Ok(())
370    }
371
372    /// Enables or disables 10-bit addressing.
373    ///
374    /// 10-bit addressing currently isn't supported on the Raspberry Pi. `set_addr_10bit` returns
375    /// `Err(`[`Error::FeatureNotSupported`]`)` unless underlying driver support is detected.
376    ///
377    /// By default, `addr_10bit` is set to `false`.
378    ///
379    /// [`Error::FeatureNotSupported`]: enum.Error.html#variant.FeatureNotSupported
380    pub fn set_addr_10bit(&mut self, addr_10bit: bool) -> Result<()> {
381        if !self.capabilities().addr_10bit() {
382            return Err(Error::FeatureNotSupported);
383        }
384
385        ioctl::set_addr_10bit(self.i2cdev.as_raw_fd(), addr_10bit as c_ulong)?;
386
387        self.addr_10bit = addr_10bit;
388
389        Ok(())
390    }
391
392    /// Receives incoming data from the slave device and writes it to `buffer`.
393    ///
394    /// `read` reads as many bytes as can fit in `buffer`.
395    ///
396    /// Sequence: START → Address + Read Bit → Incoming Bytes → STOP
397    ///
398    /// Returns how many bytes were read.
399    pub fn read(&mut self, buffer: &mut [u8]) -> Result<usize> {
400        Ok(self.i2cdev.read(buffer)?)
401    }
402
403    /// Sends the outgoing data contained in `buffer` to the slave device.
404    ///
405    /// Sequence: START → Address + Write Bit → Outgoing Bytes → STOP
406    ///
407    /// Returns how many bytes were written.
408    pub fn write(&mut self, buffer: &[u8]) -> Result<usize> {
409        Ok(self.i2cdev.write(buffer)?)
410    }
411
412    /// Sends the outgoing data contained in `write_buffer` to the slave device, and
413    /// then fills `read_buffer` with incoming data.
414    ///
415    /// Compared to calling [`write`] and [`read`] separately, `write_read` doesn't
416    /// issue a STOP condition in between the write and read operation. A repeated
417    /// START is sent instead.
418    ///
419    /// `write_read` reads as many bytes as can fit in `read_buffer`. The maximum
420    /// number of bytes in either `write_buffer` or `read_buffer` can't exceed 8192.
421    ///
422    /// Sequence: START → Address + Write Bit → Outgoing Bytes → Repeated START →
423    /// Address + Read Bit → Incoming Bytes → STOP
424    ///
425    /// [`write`]: #method.write
426    /// [`read`]: #method.read
427    pub fn write_read(&self, write_buffer: &[u8], read_buffer: &mut [u8]) -> Result<()> {
428        ioctl::i2c_write_read(
429            self.i2cdev.as_raw_fd(),
430            self.address,
431            self.addr_10bit,
432            write_buffer,
433            read_buffer,
434        )?;
435
436        Ok(())
437    }
438
439    /// Sends an 8-bit `command`, and then fills a multi-byte `buffer` with
440    /// incoming data.
441    ///
442    /// `block_read` can read a maximum of 32 bytes.
443    ///
444    /// Although `block_read` isn't part of the SMBus protocol, it uses the
445    /// SMBus functionality to offer this commonly used I2C transaction format.
446    /// The difference between `block_read` and [`smbus_block_read`] is that the
447    /// latter also expects a byte count from the slave device.
448    ///
449    /// Sequence: START → Address + Write Bit → Command → Repeated START
450    /// → Address + Read Bit → Incoming Bytes → STOP
451    ///
452    /// [`smbus_block_read`]: #method.smbus_block_read
453    pub fn block_read(&self, command: u8, buffer: &mut [u8]) -> Result<()> {
454        ioctl::i2c_block_read(self.i2cdev.as_raw_fd(), command, buffer)?;
455
456        Ok(())
457    }
458
459    /// Sends an 8-bit `command` followed by a multi-byte `buffer`.
460    ///
461    /// `block_write` can write a maximum of 32 bytes. Any additional data contained
462    /// in `buffer` is ignored.
463    ///
464    /// Although `block_write` isn't part of the SMBus protocol, it uses the
465    /// SMBus functionality to offer this commonly used I2C transaction format. The
466    /// difference between `block_write` and [`smbus_block_write`] is that the latter
467    /// also sends a byte count to the slave device.
468    ///
469    /// Sequence: START → Address + Write Bit → Command → Outgoing Bytes → STOP
470    ///
471    /// [`smbus_block_write`]: #method.smbus_block_write
472    pub fn block_write(&self, command: u8, buffer: &[u8]) -> Result<()> {
473        ioctl::i2c_block_write(self.i2cdev.as_raw_fd(), command, buffer)?;
474
475        Ok(())
476    }
477
478    // Note: smbus_read/write_32/64 could theoretically be emulated using block_read/write
479    // provided the PEC value is calculated in software
480
481    /// Sends a 1-bit `command` in place of the R/W bit.
482    ///
483    /// Sequence: START → Address + Command Bit → STOP
484    pub fn smbus_quick_command(&self, command: bool) -> Result<()> {
485        ioctl::smbus_quick_command(self.i2cdev.as_raw_fd(), command)?;
486
487        Ok(())
488    }
489
490    /// Receives an 8-bit value.
491    ///
492    /// Sequence: START → Address + Read Bit → Incoming Byte → STOP
493    pub fn smbus_receive_byte(&self) -> Result<u8> {
494        Ok(ioctl::smbus_receive_byte(self.i2cdev.as_raw_fd())?)
495    }
496
497    /// Sends an 8-bit `value`.
498    ///
499    /// Sequence: START → Address + Write Bit → Outgoing Byte → STOP
500    pub fn smbus_send_byte(&self, value: u8) -> Result<()> {
501        ioctl::smbus_send_byte(self.i2cdev.as_raw_fd(), value)?;
502
503        Ok(())
504    }
505
506    /// Sends an 8-bit `command`, and receives an 8-bit value.
507    ///
508    /// Sequence: START → Address + Write Bit → Command → Repeated START
509    /// → Address + Read Bit → Incoming Byte → STOP
510    pub fn smbus_read_byte(&self, command: u8) -> Result<u8> {
511        Ok(ioctl::smbus_read_byte(self.i2cdev.as_raw_fd(), command)?)
512    }
513
514    /// Sends an 8-bit `command` and an 8-bit `value`.
515    ///
516    /// Sequence: START → Address + Write Bit → Command → Outgoing Byte → STOP
517    pub fn smbus_write_byte(&self, command: u8, value: u8) -> Result<()> {
518        ioctl::smbus_write_byte(self.i2cdev.as_raw_fd(), command, value)?;
519
520        Ok(())
521    }
522
523    /// Sends an 8-bit `command`, and receives a 16-bit value.
524    ///
525    /// Based on the SMBus protocol definition, the first byte received is
526    /// stored as the low byte of the 16-bit value, and the second byte as
527    /// the high byte. Some devices may require you to swap these bytes. In those
528    /// cases you can use the convenience method [`smbus_read_word_swapped`] instead.
529    ///
530    /// Sequence: START → Address + Write Bit → Command → Repeated START
531    /// → Address + Read Bit → Incoming Byte Low → Incoming Byte High → STOP
532    ///
533    /// [`smbus_read_word_swapped`]: #method.smbus_read_word_swapped
534    pub fn smbus_read_word(&self, command: u8) -> Result<u16> {
535        Ok(ioctl::smbus_read_word(self.i2cdev.as_raw_fd(), command)?)
536    }
537
538    /// Sends an 8-bit `command`, and receives a 16-bit `value` in a non-standard swapped byte order.
539    ///
540    /// `smbus_read_word_swapped` is a convenience method that works similarly to [`smbus_read_word`],
541    /// but reverses the byte order of the incoming 16-bit value. The high byte is received first,
542    /// and the low byte second.
543    ///
544    /// Sequence: START → Address + Write Bit → Command → Repeated START
545    /// → Address + Read Bit → Incoming Byte High → Incoming Byte Low → STOP
546    ///
547    /// [`smbus_read_word`]: #method.smbus_read_word
548    pub fn smbus_read_word_swapped(&self, command: u8) -> Result<u16> {
549        let value = ioctl::smbus_read_word(self.i2cdev.as_raw_fd(), command)?;
550
551        Ok(((value & 0xFF00) >> 8) | ((value & 0xFF) << 8))
552    }
553
554    /// Sends an 8-bit `command` and a 16-bit `value`.
555    ///
556    /// Based on the SMBus protocol definition, the first byte sent is the low byte
557    /// of the 16-bit value, and the second byte is the high byte. Some devices may
558    /// require you to swap these bytes. In those cases you can use the convenience method
559    /// [`smbus_write_word_swapped`] instead.
560    ///
561    /// Sequence: START → Address + Write Bit → Command → Outgoing Byte Low → Outgoing Byte High → STOP
562    ///
563    /// [`smbus_write_word_swapped`]: #method.smbus_write_word_swapped
564    pub fn smbus_write_word(&self, command: u8, value: u16) -> Result<()> {
565        ioctl::smbus_write_word(self.i2cdev.as_raw_fd(), command, value)?;
566
567        Ok(())
568    }
569
570    /// Sends an 8-bit `command` and a 16-bit `value` in a non-standard swapped byte order.
571    ///
572    /// `smbus_write_word_swapped` is a convenience method that works similarly to [`smbus_write_word`], but reverses the byte
573    /// order of the outgoing 16-bit value. The high byte is sent first, and the low byte second.
574    ///
575    /// Sequence: START → Address + Write Bit → Command → Outgoing Byte High → Outgoing Byte Low → STOP
576    ///
577    /// [`smbus_write_word`]: #method.smbus_write_word
578    pub fn smbus_write_word_swapped(&self, command: u8, value: u16) -> Result<()> {
579        ioctl::smbus_write_word(
580            self.i2cdev.as_raw_fd(),
581            command,
582            ((value & 0xFF00) >> 8) | ((value & 0xFF) << 8),
583        )?;
584
585        Ok(())
586    }
587
588    /// Sends an 8-bit `command` and a 16-bit `value`, and then receives a 16-bit value in response.
589    ///
590    /// Based on the SMBus protocol definition, for both the outgoing and incoming 16-bit value,
591    /// the first byte transferred is the low byte of the 16-bit value, and the second byte is the
592    /// high byte. Some devices may require you to swap these bytes. In those cases you can use the
593    /// convenience method [`smbus_process_call_swapped`] instead.
594    ///
595    /// Sequence: START → Address + Write Bit → Command → Outgoing Byte Low →
596    /// Outgoing Byte High → Repeated START → Address + Read Bit → Incoming Byte Low →
597    /// Incoming Byte High → STOP
598    ///
599    /// [`smbus_process_call_swapped`]: #method.smbus_process_call_swapped
600    pub fn smbus_process_call(&self, command: u8, value: u16) -> Result<u16> {
601        Ok(ioctl::smbus_process_call(
602            self.i2cdev.as_raw_fd(),
603            command,
604            value,
605        )?)
606    }
607
608    /// Sends an 8-bit `command` and a 16-bit `value`, and then receives a 16-bit value in response, in
609    /// a non-standard byte order.
610    ///
611    /// `smbus_process_call_swapped` is a convenience method that works similarly to [`smbus_process_call`],
612    /// but reverses the byte order of the outgoing and incoming 16-bit value. The high byte is transferred
613    /// first, and the low byte second.
614    ///
615    /// Sequence: START → Address + Write Bit → Command → Outgoing Byte High →
616    /// Outgoing Byte Low → Repeated START → Address + Read Bit → Incoming Byte High →
617    /// Incoming Byte Low → STOP
618    ///
619    /// [`smbus_process_call`]: #method.smbus_process_call
620    pub fn smbus_process_call_swapped(&self, command: u8, value: u16) -> Result<u16> {
621        let response = ioctl::smbus_process_call(
622            self.i2cdev.as_raw_fd(),
623            command,
624            ((value & 0xFF00) >> 8) | ((value & 0xFF) << 8),
625        )?;
626
627        Ok(((response & 0xFF00) >> 8) | ((response & 0xFF) << 8))
628    }
629
630    /// Sends an 8-bit `command`, and then receives an 8-bit byte count along with a
631    /// multi-byte `buffer`.
632    ///
633    /// `smbus_block_read` currently isn't supported on the Raspberry Pi, and returns
634    /// `Err(`[`Error::FeatureNotSupported`]`)` unless underlying driver support is
635    /// detected. You might be able to emulate the `smbus_block_read` functionality
636    /// with [`write_read`], [`block_read`] or [`read`] provided the length of the
637    /// expected incoming data is known beforehand, or the slave device allows the
638    /// master to read more data than it needs to send.
639    ///
640    /// `smbus_block_read` can read a maximum of 32 bytes.
641    ///
642    /// Sequence: START → Address + Write Bit → Command → Repeated START →
643    /// Address + Read Bit → Incoming Byte Count → Incoming Bytes → STOP
644    ///
645    /// Returns how many bytes were read.
646    ///
647    /// [`Error::FeatureNotSupported`]: enum.Error.html#variant.FeatureNotSupported
648    /// [`write_read`]: #method.write_read
649    /// [`block_read`]: #method.block_read
650    /// [`read`]: #method.read
651    pub fn smbus_block_read(&self, command: u8, buffer: &mut [u8]) -> Result<usize> {
652        if !self.capabilities().smbus_block_read() {
653            return Err(Error::FeatureNotSupported);
654        }
655
656        Ok(ioctl::smbus_block_read(
657            self.i2cdev.as_raw_fd(),
658            command,
659            buffer,
660        )?)
661    }
662
663    /// Sends an 8-bit `command` and an 8-bit byte count along with a multi-byte `buffer`.
664    ///
665    /// `smbus_block_write` can write a maximum of 32 bytes. Any additional data contained
666    /// in `buffer` is ignored.
667    ///
668    /// Sequence: START → Address + Write Bit → Command → Outgoing Byte Count
669    /// → Outgoing Bytes → STOP
670    pub fn smbus_block_write(&self, command: u8, buffer: &[u8]) -> Result<()> {
671        ioctl::smbus_block_write(self.i2cdev.as_raw_fd(), command, buffer)?;
672
673        Ok(())
674    }
675
676    /// Enables or disables SMBus Packet Error Checking.
677    ///
678    /// Packet Error Checking inserts a CRC-8 Packet Error Code (PEC) byte before each STOP
679    /// condition for all SMBus protocols, except Quick Command and Host Notify.
680    ///
681    /// The PEC is calculated on all message bytes except the START, STOP, ACK and NACK bits.
682    ///
683    /// By default, `pec` is set to `false`.
684    pub fn set_smbus_pec(&self, pec: bool) -> Result<()> {
685        ioctl::set_pec(self.i2cdev.as_raw_fd(), pec as c_ulong)?;
686
687        Ok(())
688    }
689}
690
691// Send is safe for I2c, but we're marked !Send because of the dummy pointer that's
692// needed to force !Sync.
693unsafe impl Send for I2c {}