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
next prev parent 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