public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Muchamad Coirul Anwar <muchamadcoirulanwar@gmail.com>
To: jic23@kernel.org, linux-iio@vger.kernel.org,
	rust-for-linux@vger.kernel.org, devicetree@vger.kernel.org
Cc: branstj@gmail.com, lars@metafoo.de, ojeda@kernel.org,
	robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org,
	igor.korotin.linux@gmail.com, linux-kernel@vger.kernel.org,
	Muchamad Coirul Anwar <muchamadcoirulanwar@gmail.com>
Subject: [RFC PATCH v2 4/4] iio: position: add Rust driver for ams AS5600
Date: Wed, 29 Apr 2026 20:22:30 +0700	[thread overview]
Message-ID: <20260429132234.30514-5-muchamadcoirulanwar@gmail.com> (raw)
In-Reply-To: <20260429132234.30514-1-muchamadcoirulanwar@gmail.com>

Signed-off-by: Muchamad Coirul Anwar <muchamadcoirulanwar@gmail.com>
---
 drivers/iio/position/Kconfig   |  14 ++++
 drivers/iio/position/Makefile  |   1 +
 drivers/iio/position/as5600.rs | 129 +++++++++++++++++++++++++++++++++
 3 files changed, 144 insertions(+)
 create mode 100644 drivers/iio/position/as5600.rs

diff --git a/drivers/iio/position/Kconfig b/drivers/iio/position/Kconfig
index 1576a6380b53..dab9310e8079 100644
--- a/drivers/iio/position/Kconfig
+++ b/drivers/iio/position/Kconfig
@@ -6,6 +6,20 @@
 
 menu "Linear and angular position sensors"
 
+config AS5600
+	tristate "ams AS5600 magnetic rotary position sensor"
+	depends on I2C && RUST
+	help
+	  Say Y here to build support for the ams AS5600 12-bit
+	  magnetic rotary position sensor with IIO channel support
+	  (in_angl_raw and in_angl_scale).
+
+	  This is a Rust driver that exposes the 12-bit raw angle
+	  and radian scale via the IIO subsystem.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called as5600.
+
 config IQS624_POS
 	tristate "Azoteq IQS624/625 angular position sensors"
 	depends on MFD_IQS62X || COMPILE_TEST
diff --git a/drivers/iio/position/Makefile b/drivers/iio/position/Makefile
index d70902f2979d..2d26f6d6ace3 100644
--- a/drivers/iio/position/Makefile
+++ b/drivers/iio/position/Makefile
@@ -4,5 +4,6 @@
 
 # When adding new entries keep the list in alphabetical order
 
+obj-$(CONFIG_AS5600) += as5600.o
 obj-$(CONFIG_HID_SENSOR_CUSTOM_INTEL_HINGE) += hid-sensor-custom-intel-hinge.o
 obj-$(CONFIG_IQS624_POS)	+= iqs624-pos.o
diff --git a/drivers/iio/position/as5600.rs b/drivers/iio/position/as5600.rs
new file mode 100644
index 000000000000..0cbf8be58b64
--- /dev/null
+++ b/drivers/iio/position/as5600.rs
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (C) 2026 Muchamad Coirul Anwar <muchamadcoirulanwar@gmail.com>
+//! Driver for ams AS5600 12-bit magnetic rotary position sensor.
+//!
+//! Datasheet: https://ams.com/documents/20143/36005/AS5600_DS000365_5-00.pdf
+
+use kernel::{
+    bindings::{
+        iio_chan_info_enum_IIO_CHAN_INFO_RAW, iio_chan_info_enum_IIO_CHAN_INFO_SCALE,
+        iio_chan_spec, iio_chan_type_IIO_ANGL, ENODATA,
+    },
+    bits::bit_u8,
+    device::Core,
+    i2c::{DeviceId, Driver, I2cClient, IdTable},
+    i2c_device_table,
+    iio::{Device, IioDriver, IioVal},
+    module_i2c_driver, of, of_device_table,
+    prelude::*,
+};
+
+const AS5600_REG_STATUS: u8 = 0x0B;
+const AS5600_REG_RAW_ANGLE_H: u8 = 0x0C;
+const AS5600_REG_RAW_ANGLE_L: u8 = 0x0D;
+
+const AS5600_STATUS_MD: u8 = bit_u8(5);
+
+module_i2c_driver! {
+    type: As5600,
+    name: "as5600",
+    authors: ["Muchamad Coirul Anwar"],
+    description: "I2C Driver for ams OSRAM AS5600 Magnetic Rotary Position Sensor",
+    license: "GPL",
+}
+
+i2c_device_table!(
+    I2C_TABLE,
+    MODULE_I2C_TABLE,
+    <As5600 as Driver>::IdInfo,
+    [(DeviceId::new(c"as5600"), ())]
+);
+
+of_device_table!(
+    OF_TABLE,
+    MODULE_OF_TABLE,
+    <As5600 as Driver>::IdInfo,
+    [(of::DeviceId::new(c"ams,as5600"), ())]
+);
+
+struct As5600Priv {
+    client_ptr: *const I2cClient<Core>,
+    channels: [iio_chan_spec; 1],
+}
+
+// SAFETY: `client_ptr` points to an `I2cClient` that is owned by the I2C
+// subsystem and outlives the driver binding. `iio_device_unregister` in
+// `Device<T>::PinnedDrop` drains pending callbacks before this struct is
+// dropped, so `client_ptr` is valid for every `read_raw` invocation.
+// Concurrent access is safe because the I2C adapter lock serializes all
+// SMBus transactions.
+unsafe impl Send for As5600Priv {}
+unsafe impl Sync for As5600Priv {}
+
+impl IioDriver for As5600Priv {
+    fn read_raw(&self, _chan: *const iio_chan_spec, mask: isize) -> Result<IioVal> {
+        // SAFETY: `client_ptr` was set from a valid `&I2cClient` in `probe()`.
+        // The I2C client outlives the driver binding, and `read_raw` is only
+        // called while the driver is bound.
+        let client = unsafe { &*self.client_ptr };
+
+        #[allow(non_upper_case_globals)]
+        match mask as u32 {
+            // IIO_CHAN_INFO_RAW
+            iio_chan_info_enum_IIO_CHAN_INFO_RAW => {
+                let status = client.smbus_read_byte_data(AS5600_REG_STATUS)?;
+                if (status & AS5600_STATUS_MD) == 0 {
+                    return Err(Error::from_errno(-(ENODATA as i32)));
+                }
+
+                let angle_h = client.smbus_read_byte_data(AS5600_REG_RAW_ANGLE_H)? as u16;
+                let angle_l = client.smbus_read_byte_data(AS5600_REG_RAW_ANGLE_L)? as u16;
+
+                let angle = (angle_h << 8 | angle_l) & 0x0FFF;
+                Ok(IioVal::Int(angle as i32))
+            }
+            // IIO_CHAN_INFO_SCALE
+            iio_chan_info_enum_IIO_CHAN_INFO_SCALE => Ok(IioVal::IntPlusNano(0, 1533981)),
+            _ => Err(EINVAL),
+        }
+    }
+
+    fn channels(&self) -> &[iio_chan_spec] {
+        &self.channels
+    }
+}
+
+struct As5600 {
+    _iio_dev: Device<As5600Priv>,
+}
+
+impl Driver for As5600 {
+    type IdInfo = ();
+    const I2C_ID_TABLE: Option<IdTable<Self::IdInfo>> = Some(&I2C_TABLE);
+    const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE);
+
+    fn probe(dev: &I2cClient<Core>, _id_info: Option<&Self::IdInfo>) -> impl PinInit<Self, Error> {
+        let _status = dev.smbus_read_byte_data(AS5600_REG_STATUS)?;
+
+        // SAFETY: `iio_chan_spec` is a C struct whose fields are all integers
+        // and pointers. Zero is a valid initialization for all of them.
+        let mut channels: [iio_chan_spec; 1] = unsafe { core::mem::zeroed() };
+        channels[0].info_mask_separate = (1 << iio_chan_info_enum_IIO_CHAN_INFO_RAW)
+            | (1 << iio_chan_info_enum_IIO_CHAN_INFO_SCALE);
+        channels[0].type_ = iio_chan_type_IIO_ANGL;
+
+        let priv_data = As5600Priv {
+            client_ptr: dev as *const _,
+            channels,
+        };
+
+        let mut iio_dev = Device::new(dev.as_ref(), priv_data, c"as5600")?;
+
+        iio_dev.register(dev.as_ref(), &crate::THIS_MODULE)?;
+
+        dev_dbg!(dev.as_ref(), "AS5600: Sensor probed, driver ready\n");
+        Ok::<_, Error>(As5600 { _iio_dev: iio_dev })
+    }
+
+    fn unbind(_dev: &I2cClient<Core>, _this: Pin<&Self>) {}
+}
-- 
2.50.0


      parent reply	other threads:[~2026-04-29 13:23 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-29 13:22 [RFC PATCH v2 0/4] iio: position: add Rust driver for ams AS5600 Muchamad Coirul Anwar
2026-04-29 13:22 ` [RFC PATCH v2 1/4] i2c: rust: add smbus_read_byte_data and smbus_read_word_data Muchamad Coirul Anwar
2026-05-04 10:29   ` Igor Korotin
2026-04-29 13:22 ` [RFC PATCH v2 2/4] rust: add minimal IIO subsystem abstractions Muchamad Coirul Anwar
2026-04-29 13:22 ` [RFC PATCH v2 3/4] dt-bindings: iio: position: add ams,as5600 Muchamad Coirul Anwar
2026-04-29 13:46   ` Krzysztof Kozlowski
2026-04-29 13:22 ` Muchamad Coirul Anwar [this message]

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=20260429132234.30514-5-muchamadcoirulanwar@gmail.com \
    --to=muchamadcoirulanwar@gmail.com \
    --cc=branstj@gmail.com \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=igor.korotin.linux@gmail.com \
    --cc=jic23@kernel.org \
    --cc=krzk+dt@kernel.org \
    --cc=lars@metafoo.de \
    --cc=linux-iio@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=ojeda@kernel.org \
    --cc=robh@kernel.org \
    --cc=rust-for-linux@vger.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