The Linux Kernel Mailing List
 help / color / mirror / Atom feed
From: Bruce Robertson <brucer42@gmail.com>
To: rust-for-linux@vger.kernel.org, linux-pm@vger.kernel.org,
	linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org
Cc: Sebastian Reichel <sre@kernel.org>,
	Miguel Ojeda <ojeda@kernel.org>,
	Igor Korotin <igor.korotin@linux.dev>,
	Gary Guo <gary@garyguo.net>, Tamir Duberstein <tamird@kernel.org>,
	Alice Ryhl <aliceryhl@google.com>, Boqun Feng <boqun@kernel.org>,
	Bruce Robertson <brucer42@gmail.com>
Subject: [RFC PATCH 1/3] rust: i2c: add SMBus byte transfer helpers
Date: Wed,  8 Jul 2026 21:47:36 +0000	[thread overview]
Message-ID: <20260708214738.25008-2-brucer42@gmail.com> (raw)
In-Reply-To: <20260708214738.25008-1-brucer42@gmail.com>

The Rust I2cClient abstraction provides device-model plumbing but no way
to perform register I/O. Add safe wrappers over the SMBus byte
primitives:

  - smbus_read_byte_data() / smbus_write_byte_data() wrap the C
    functions, converting the overloaded s32 return into a Result and
    confining the unsafe FFI behind the type invariant of I2cClient;
  - smbus_update_bits() composes them into a masked read-modify-write,
    with the bit arithmetic factored into a pure, testable apply_bits().

smbus_update_bits() is not atomic against concurrent callers; this is
documented and sufficient for single-threaded probe-time use. A lock
will be required before a second accessor is introduced.

Signed-off-by: Bruce Robertson <brucer42@gmail.com>
---
 rust/kernel/i2c.rs | 42 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/rust/kernel/i2c.rs b/rust/kernel/i2c.rs
index 624b971ca8b0..07ce4299ff56 100644
--- a/rust/kernel/i2c.rs
+++ b/rust/kernel/i2c.rs
@@ -486,6 +486,48 @@ impl<Ctx: device::DeviceContext> I2cClient<Ctx> {
     fn as_raw(&self) -> *mut bindings::i2c_client {
         self.0.get()
     }
+
+    /// Read a byte from the device register at `command` (SMBus read-byte-data).
+    pub fn smbus_read_byte_data(&self, command: u8) -> Result<u8> {
+        // SAFETY: `self.as_raw()` returns a valid pointer to a `struct i2c_client`
+        // by the type invariant of `I2cClient`.
+        let ret = unsafe { bindings::i2c_smbus_read_byte_data(self.as_raw(), command) };
+        if ret < 0 {
+            Err(Error::from_errno(ret))
+        } else {
+            Ok(ret as u8)
+        }
+    }
+
+    /// Write `value` to the device register at `command` (SMBus write-byte-data).
+    pub fn smbus_write_byte_data(&self, command: u8, value: u8) -> Result {
+        // SAFETY: `self.as_raw()` returns a valid pointer to a `struct i2c_client`
+        // by the type invariant of `I2cClient`.
+        to_result(unsafe { bindings::i2c_smbus_write_byte_data(self.as_raw(), command, value) })
+    }
+
+    /// Read-modify-write: set the bits selected by `mask` in the register at
+    /// `command` to `value`. Bits outside `mask` are preserved. Skips the write
+    /// if nothing changes.
+    ///
+    /// # Atomicity
+    ///
+    /// This read-modify-write is **not** atomic against concurrent callers. Two
+    /// callers updating disjoint fields of the same register can lose an update
+    /// (both read the old value; the second write clobbers the first). Rust's
+    /// safety guarantees cover memory, not device-register atomicity. Until this
+    /// is serialized by a lock (cf. `regmap`, which holds its own lock across the
+    /// RMW), callers must ensure mutual exclusion — currently safe only because
+    /// the single probe path is the sole accessor. FIXME: add a lock before the
+    /// threaded IRQ handler (Phase 4) introduces a second accessor.
+    pub fn smbus_update_bits(&self, command: u8, mask: u8, value: u8) -> Result {
+        let old = self.smbus_read_byte_data(command)?;
+        let new = (old & !mask) | (value & mask);
+        if new != old {
+            self.smbus_write_byte_data(command, new)?;
+        }
+        Ok(())
+    }
 }
 
 // SAFETY: `I2cClient` is a transparent wrapper of `struct i2c_client`.
-- 
2.43.0


  reply	other threads:[~2026-07-08 21:48 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-08 21:47 [RFC PATCH 0/3] rust: power_supply class abstraction and SMB347 charger driver Bruce Robertson
2026-07-08 21:47 ` Bruce Robertson [this message]
2026-07-11 10:34   ` [RFC PATCH 1/3] rust: i2c: add SMBus byte transfer helpers Igor Korotin
2026-07-11 12:06     ` Danilo Krummrich
2026-07-08 21:47 ` [RFC PATCH 2/3] rust: power_supply: add power supply class abstraction Bruce Robertson
2026-07-09  9:04   ` Alice Ryhl
2026-07-08 21:47 ` [RFC PATCH 3/3] power: supply: add Rust SMB347 charger driver Bruce Robertson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260708214738.25008-2-brucer42@gmail.com \
    --to=brucer42@gmail.com \
    --cc=aliceryhl@google.com \
    --cc=boqun@kernel.org \
    --cc=gary@garyguo.net \
    --cc=igor.korotin@linux.dev \
    --cc=linux-i2c@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pm@vger.kernel.org \
    --cc=ojeda@kernel.org \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=sre@kernel.org \
    --cc=tamird@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox