// SPDX-License-Identifier: GPL-2.0 //! Rust I2C client registration sample. //! //! An I2C client in Rust cannot exist on its own. To register a new I2C client, //! it must be bound to a parent device. In this sample driver, a platform device //! is used as the parent. //! //! ACPI match table test //! //! This demonstrates how to test an ACPI-based Rust I2C client registration driver //! using QEMU with a custom SSDT. //! //! Steps: //! //! 1. **Create an SSDT source file** (`ssdt.dsl`) with the following content: //! //! ```asl //! DefinitionBlock ("", "SSDT", 2, "TEST", "VIRTACPI", 0x00000001) //! { //! Scope (\_SB) //! { //! Device (T432) //! { //! Name (_HID, "LNUXBEEF") // ACPI hardware ID to match //! Name (_UID, 1) //! Name (_STA, 0x0F) // Device present, enabled //! Name (_CRS, ResourceTemplate () //! { //! Memory32Fixed (ReadWrite, 0xFED00000, 0x1000) //! }) //! } //! } //! } //! ``` //! //! 2. **Compile the table**: //! //! ```sh //! iasl -tc ssdt.dsl //! ``` //! //! This generates `ssdt.aml` //! //! 3. **Run QEMU** with the compiled AML file: //! //! ```sh //! qemu-system-x86_64 -m 512M \ //! -enable-kvm \ //! -kernel path/to/bzImage \ //! -append "root=/dev/sda console=ttyS0" \ //! -hda rootfs.img \ //! -serial stdio \ //! -acpitable file=ssdt.aml //! ``` //! //! Requirements: //! - The `rust_driver_platform` must be present either: //! - built directly into the kernel (`bzImage`), or //! - available as a `.ko` file and loadable from `rootfs.img` //! //! 4. **Verify it worked** by checking `dmesg`: //! //! ``` //! rust_driver_platform LNUXBEEF:00: Probed with info: '0'. //! ``` //! use kernel::{ acpi, c_str, device, devres::Devres, i2c, of, platform, prelude::*, sync::aref::ARef, // }; #[pin_data] struct SampleDriver { parent_dev: ARef, #[pin] _reg: Devres, } kernel::of_device_table!( OF_TABLE, MODULE_OF_TABLE, ::IdInfo, [(of::DeviceId::new(c_str!("test,rust-device")), ())] ); kernel::acpi_device_table!( ACPI_TABLE, MODULE_ACPI_TABLE, ::IdInfo, [(acpi::DeviceId::new(c_str!("LNUXBEEF")), ())] ); const SAMPLE_I2C_CLIENT_ADDR: u16 = 0x30; const SAMPLE_I2C_ADAPTER_INDEX: i32 = 0; const BOARD_INFO: i2c::I2cBoardInfo = i2c::I2cBoardInfo::new(c_str!("rust_driver_i2c"), SAMPLE_I2C_CLIENT_ADDR); impl platform::Driver for SampleDriver { type IdInfo = (); const OF_ID_TABLE: Option> = Some(&OF_TABLE); const ACPI_ID_TABLE: Option> = Some(&ACPI_TABLE); fn probe( pdev: &platform::Device, _info: Option<&Self::IdInfo>, ) -> impl PinInit { dev_info!( pdev.as_ref(), "Probe Rust I2C Client registration sample.\n" ); kernel::try_pin_init!( Self { parent_dev: pdev.into(), _reg <- { let adapter = i2c::I2cAdapter::get(SAMPLE_I2C_ADAPTER_INDEX)?; i2c::Registration::new(&adapter, &BOARD_INFO, pdev.as_ref()) } }) } fn unbind(pdev: &platform::Device, _this: Pin<&Self>) { dev_info!( pdev.as_ref(), "Unbind Rust I2C Client registration sample.\n" ); } } kernel::module_platform_driver! { type: SampleDriver, name: "rust_device_i2c", authors: ["Danilo Krummrich", "Igor Korotin"], description: "Rust I2C client registration", license: "GPL v2", }