// SPDX-License-Identifier: GPL-2.012//! Rust I2C client registration sample.3//!4//! An I2C client in Rust cannot exist on its own. To register a new I2C client,5//! it must be bound to a parent device. In this sample driver, a platform device6//! is used as the parent.7//!89//! ACPI match table test10//!11//! This demonstrates how to test an ACPI-based Rust I2C client registration driver12//! using QEMU with a custom SSDT.13//!14//! Steps:15//!16//! 1. **Create an SSDT source file** (`ssdt.dsl`) with the following content:17//!18//! ```asl19//! DefinitionBlock ("", "SSDT", 2, "TEST", "VIRTACPI", 0x00000001)20//! {21//! Scope (\_SB)22//! {23//! Device (T432)24//! {25//! Name (_HID, "LNUXBEEF") // ACPI hardware ID to match26//! Name (_UID, 1)27//! Name (_STA, 0x0F) // Device present, enabled28//! Name (_CRS, ResourceTemplate ()29//! {30//! Memory32Fixed (ReadWrite, 0xFED00000, 0x1000)31//! })32//! }33//! }34//! }35//! ```36//!37//! 2. **Compile the table**:38//!39//! ```sh40//! iasl -tc ssdt.dsl41//! ```42//!43//! This generates `ssdt.aml`44//!45//! 3. **Run QEMU** with the compiled AML file:46//!47//! ```sh48//! qemu-system-x86_64 -m 512M \49//! -enable-kvm \50//! -kernel path/to/bzImage \51//! -append "root=/dev/sda console=ttyS0" \52//! -hda rootfs.img \53//! -serial stdio \54//! -acpitable file=ssdt.aml55//! ```56//!57//! Requirements:58//! - The `rust_driver_platform` must be present either:59//! - built directly into the kernel (`bzImage`), or60//! - available as a `.ko` file and loadable from `rootfs.img`61//!62//! 4. **Verify it worked** by checking `dmesg`:63//!64//! ```65//! rust_driver_platform LNUXBEEF:00: Probed with info: '0'.66//! ```67//!6869use kernel::{70acpi,71device,72devres::Devres,73i2c,74of,75platform,76prelude::*,77sync::aref::ARef, //78};7980#[pin_data]81struct SampleDriver {82parent_dev: ARef<platform::Device>,83#[pin]84_reg: Devres<i2c::Registration>,85}8687kernel::of_device_table!(88OF_TABLE,89MODULE_OF_TABLE,90<SampleDriver as platform::Driver>::IdInfo,91[(of::DeviceId::new(c"test,rust-device"), ())]92);9394kernel::acpi_device_table!(95ACPI_TABLE,96MODULE_ACPI_TABLE,97<SampleDriver as platform::Driver>::IdInfo,98[(acpi::DeviceId::new(c"LNUXBEEF"), ())]99);100101const SAMPLE_I2C_CLIENT_ADDR: u16 = 0x30;102const SAMPLE_I2C_ADAPTER_INDEX: i32 = 0;103const BOARD_INFO: i2c::I2cBoardInfo =104i2c::I2cBoardInfo::new(c"rust_driver_i2c", SAMPLE_I2C_CLIENT_ADDR);105106impl platform::Driver for SampleDriver {107type IdInfo = ();108const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE);109const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = Some(&ACPI_TABLE);110111fn probe(112pdev: &platform::Device<device::Core>,113_info: Option<&Self::IdInfo>,114) -> impl PinInit<Self, Error> {115dev_info!(116pdev.as_ref(),117"Probe Rust I2C Client registration sample.\n"118);119120kernel::try_pin_init!( Self {121parent_dev: pdev.into(),122123_reg <- {124let adapter = i2c::I2cAdapter::get(SAMPLE_I2C_ADAPTER_INDEX)?;125126i2c::Registration::new(&adapter, &BOARD_INFO, pdev.as_ref())127}128})129}130131fn unbind(pdev: &platform::Device<device::Core>, _this: Pin<&Self>) {132dev_info!(133pdev.as_ref(),134"Unbind Rust I2C Client registration sample.\n"135);136}137}138139kernel::module_platform_driver! {140type: SampleDriver,141name: "rust_device_i2c",142authors: ["Danilo Krummrich", "Igor Korotin"],143description: "Rust I2C client registration",144license: "GPL v2",145}146147148