rust_i2c_client.rs 3.8 KB

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