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