From: Ke Sun <sk.alvin.x@gmail.com>
To: "Ke Sun" <sunke@kylinos.cn>,
"Alexandre Belloni" <alexandre.belloni@bootlin.com>,
"Miguel Ojeda" <ojeda@kernel.org>,
"Boqun Feng" <boqun.feng@gmail.com>,
"Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Benno Lossin" <lossin@kernel.org>,
"Andreas Hindborg" <a.hindborg@kernel.org>,
"Alice Ryhl" <aliceryhl@google.com>,
"Trevor Gross" <tmgross@umich.edu>,
"Danilo Krummrich" <dakr@kernel.org>
Cc: linux-rtc@vger.kernel.org, rust-for-linux@vger.kernel.org
Subject: Re: [RFC PATCH v3 5/5] rust: add PL031 RTC driver
Date: Mon, 19 Jan 2026 17:12:23 +0800 [thread overview]
Message-ID: <54d8007e-c54e-44a2-8cfe-df10495cda80@gmail.com> (raw)
In-Reply-To: <20260116163401.312002-1-sunke@kylinos.cn>
This driver has been tested on QEMU with the following command:
qemu-system-aarch64 -machine virt,virtualization=on -cpu max -smp 2 -m 4g \
-serial mon:stdio -kernel arch/arm64/boot/Image -hda
PATHTO/virtualdisk.qcow2 \
-append "root=/dev/vdaX no_console_suspend loglevel=8 console=ttyAMA0" \
-display none -nic user,hostfwd=tcp::10022-:22
Test Results:
Driver Registration:
[ 1.886444][ T1] rtc-pl031-rust 9010000.pl031: registered as rtc0
[ 1.888070][ T1] rtc-pl031-rust 9010000.pl031: setting system
clock to 2026-01-19T08:49:36 UTC (1768812576)
Interrupt Registration:
# cat /proc/interrupts |grep pl031
21: 0 0 GICv2 34 Level rtc-pl031
RTC Time Reading:
# hwclock -r
2026-01-19 09:03:24.961787+08:00
Suspend/Resume with Alarm:
# rtcwake --mode mem --seconds 5
rtcwake: wakeup from "mem" using /dev/rtc0 at Mon Jan 19 09:04:13 2026
[ 242.699314][ T2832] PM: suspend entry (s2idle)
[ 242.717296][ T12] Filesystems sync: 0.009 seconds
[ 242.741471][ T2832] Freezing user space processes
[ 242.761472][ T2832] Freezing user space processes completed
(elapsed 0.019 seconds)
[ 242.763281][ T2832] OOM killer disabled.
[ 242.763681][ T2832] Freezing remaining freezable tasks
[ 242.766629][ T2832] Freezing remaining freezable tasks completed
(elapsed 0.002 seconds)
[ 248.678304][ T82] virtio_blk virtio1: 2/0/0 default/read/poll
queues
[ 248.692577][ T2832] OOM killer enabled.
[ 248.692724][ T2832] Restarting tasks: Starting
[ 248.744504][ T2832] Restarting tasks: Done
[ 248.745530][ T2832] random: crng reseeded on system resumption
[ 248.746749][ T2832] PM: suspend exit
Driver Rebind:
/sys/bus/amba/drivers/rtc-pl031-rust# echo 9010000.pl031 > unbind
/sys/bus/amba/drivers/rtc-pl031-rust# echo 9010000.pl031 > bind
[ 334.060940][ T1837] rtc-pl031-rust 9010000.pl031: registered as rtc1
All tests passed successfully.
On 1/17/26 00:34, Ke Sun wrote:
> Add Rust implementation of the PL031 RTC driver.
>
> Signed-off-by: Ke Sun <sunke@kylinos.cn>
> ---
> drivers/rtc/Kconfig | 9 +
> drivers/rtc/Makefile | 1 +
> drivers/rtc/rtc_pl031_rust.rs | 513 ++++++++++++++++++++++++++++++++++
> 3 files changed, 523 insertions(+)
> create mode 100644 drivers/rtc/rtc_pl031_rust.rs
>
> diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
> index 50dc779f7f983..137cea1824edd 100644
> --- a/drivers/rtc/Kconfig
> +++ b/drivers/rtc/Kconfig
> @@ -1591,6 +1591,15 @@ config RTC_DRV_PL031
> To compile this driver as a module, choose M here: the
> module will be called rtc-pl031.
>
> +config RTC_DRV_PL031_RUST
> + tristate "ARM AMBA PL031 RTC (Rust)"
> + depends on RUST && RTC_CLASS
> + help
> + This is the Rust implementation of the PL031 RTC driver.
> + It provides the same functionality as the C driver but is
> + written in Rust for improved memory safety. The driver supports
> + ARM, ST v1, and ST v2 variants of the PL031 RTC controller.
> +
> config RTC_DRV_AT91RM9200
> tristate "AT91RM9200 or some AT91SAM9 RTC"
> depends on ARCH_AT91 || COMPILE_TEST
> diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> index 6cf7e066314e1..10f540e7409b4 100644
> --- a/drivers/rtc/Makefile
> +++ b/drivers/rtc/Makefile
> @@ -139,6 +139,7 @@ obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o
> obj-$(CONFIG_RTC_DRV_PIC32) += rtc-pic32.o
> obj-$(CONFIG_RTC_DRV_PL030) += rtc-pl030.o
> obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o
> +obj-$(CONFIG_RTC_DRV_PL031_RUST) += rtc_pl031_rust.o
> obj-$(CONFIG_RTC_DRV_PM8XXX) += rtc-pm8xxx.o
> obj-$(CONFIG_RTC_DRV_POLARFIRE_SOC) += rtc-mpfs.o
> obj-$(CONFIG_RTC_DRV_PS3) += rtc-ps3.o
> diff --git a/drivers/rtc/rtc_pl031_rust.rs b/drivers/rtc/rtc_pl031_rust.rs
> new file mode 100644
> index 0000000000000..8ae48d96d1f94
> --- /dev/null
> +++ b/drivers/rtc/rtc_pl031_rust.rs
> @@ -0,0 +1,513 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +//! Rust ARM AMBA PrimeCell 031 RTC driver
> +//!
> +//! This driver provides Real Time Clock functionality for ARM AMBA PrimeCell
> +//! 031 RTC controllers and their ST Microelectronics derivatives.
> +
> +use core::marker::PhantomPinned;
> +use kernel::{
> + amba,
> + bindings,
> + c_str,
> + device::{
> + self,
> + Core, //
> + },
> + devres::Devres,
> + io::mem::IoMem,
> + irq::{
> + self,
> + Handler,
> + IrqReturn, //
> + },
> + prelude::*,
> + rtc::{
> + RtcDevice,
> + RtcOps,
> + RtcTime,
> + RtcWkAlrm, //
> + },
> + sync::aref::ARef, //
> +};
> +
> +// Register offsets
> +const RTC_DR: usize = 0x00; // Data read register
> +const RTC_MR: usize = 0x04; // Match register
> +const RTC_LR: usize = 0x08; // Data load register
> +const RTC_CR: usize = 0x0c; // Control register
> +const RTC_IMSC: usize = 0x10; // Interrupt mask and set register
> +const RTC_RIS: usize = 0x14; // Raw interrupt status register
> +const RTC_MIS: usize = 0x18; // Masked interrupt status register
> +const RTC_ICR: usize = 0x1c; // Interrupt clear register
> +
> +// ST variants have additional timer functionality
> +#[allow(dead_code)]
> +const RTC_TDR: usize = 0x20; // Timer data read register
> +#[allow(dead_code)]
> +const RTC_TLR: usize = 0x24; // Timer data load register
> +#[allow(dead_code)]
> +const RTC_TCR: usize = 0x28; // Timer control register
> +const RTC_YDR: usize = 0x30; // Year data read register
> +const RTC_YMR: usize = 0x34; // Year match register
> +const RTC_YLR: usize = 0x38; // Year data load register
> +const PL031_REG_SIZE: usize = RTC_YLR + 4;
> +
> +// Control register bits
> +const RTC_CR_EN: u32 = 1 << 0; // Counter enable bit
> +const RTC_CR_CWEN: u32 = 1 << 26; // Clockwatch enable bit
> +
> +#[allow(dead_code)]
> +const RTC_TCR_EN: u32 = 1 << 1; // Periodic timer enable bit
> +
> +// Interrupt status and control register bits
> +const RTC_BIT_AI: u32 = 1 << 0; // Alarm interrupt bit
> +#[allow(dead_code)]
> +const RTC_BIT_PI: u32 = 1 << 1; // Periodic interrupt bit (ST variants only)
> +
> +// RTC event flags
> +#[allow(dead_code)]
> +const RTC_AF: u32 = bindings::RTC_AF;
> +#[allow(dead_code)]
> +const RTC_IRQF: u32 = bindings::RTC_IRQF;
> +
> +// ST v2 time format bit definitions
> +const RTC_SEC_SHIFT: u32 = 0;
> +const RTC_SEC_MASK: u32 = 0x3F << RTC_SEC_SHIFT; // Second [0-59]
> +const RTC_MIN_SHIFT: u32 = 6;
> +const RTC_MIN_MASK: u32 = 0x3F << RTC_MIN_SHIFT; // Minute [0-59]
> +const RTC_HOUR_SHIFT: u32 = 12;
> +const RTC_HOUR_MASK: u32 = 0x1F << RTC_HOUR_SHIFT; // Hour [0-23]
> +const RTC_WDAY_SHIFT: u32 = 17;
> +const RTC_WDAY_MASK: u32 = 0x7 << RTC_WDAY_SHIFT; // Day of Week [1-7] 1=Sunday
> +const RTC_MDAY_SHIFT: u32 = 20;
> +const RTC_MDAY_MASK: u32 = 0x1F << RTC_MDAY_SHIFT; // Day of Month [1-31]
> +const RTC_MON_SHIFT: u32 = 25;
> +const RTC_MON_MASK: u32 = 0xF << RTC_MON_SHIFT; // Month [1-12] 1=January
> +
> +/// Converts a binary value to BCD.
> +fn bin2bcd(val: u8) -> u8 {
> + ((val / 10) << 4) | (val % 10)
> +}
> +
> +/// Converts a BCD value to binary.
> +fn bcd2bin(val: u8) -> u8 {
> + ((val >> 4) * 10) + (val & 0x0F)
> +}
> +
> +/// Converts a Gregorian date to ST v2 RTC packed BCD format.
> +///
> +/// Returns a tuple of (packed_time, bcd_year) where packed_time contains
> +/// month, day, weekday, hour, minute, and second in a single 32-bit value.
> +fn stv2_tm_to_time(tm: &RtcTime) -> Result<(u32, u32)> {
> + let year = tm.tm_year() + 1900;
> + let mut wday = tm.tm_wday();
> +
> + // Hardware wday masking doesn't work, so wday must be valid.
> + if !(-1..=6).contains(&wday) {
> + return Err(EINVAL);
> + } else if wday == -1 {
> + // wday is not provided, calculate it here.
> + let time64 = tm.to_time64();
> + let mut calc_tm = RtcTime::default();
> + calc_tm.set_from_time64(time64);
> + wday = calc_tm.tm_wday();
> + }
> +
> + // Convert year to BCD.
> + let bcd_year =
> + (u32::from(bin2bcd((year % 100) as u8))) | (u32::from(bin2bcd((year / 100) as u8)) << 8);
> +
> + let st_time = ((tm.tm_mon() + 1) as u32) << RTC_MON_SHIFT
> + | (tm.tm_mday() as u32) << RTC_MDAY_SHIFT
> + | ((wday + 1) as u32) << RTC_WDAY_SHIFT
> + | (tm.tm_hour() as u32) << RTC_HOUR_SHIFT
> + | (tm.tm_min() as u32) << RTC_MIN_SHIFT
> + | (tm.tm_sec() as u32) << RTC_SEC_SHIFT;
> +
> + Ok((st_time, bcd_year))
> +}
> +
> +/// Converts ST v2 RTC packed BCD format to a Gregorian date.
> +///
> +/// Extracts time components from the packed 32-bit value and BCD year register,
> +/// then returns an RtcTime structure.
> +fn stv2_time_to_tm(st_time: u32, bcd_year: u32) -> RtcTime {
> + let year_low = bcd2bin((bcd_year & 0xFF) as u8);
> + let year_high = bcd2bin(((bcd_year >> 8) & 0xFF) as u8);
> + let mut tm = RtcTime::default();
> + tm.set_tm_year(i32::from(year_low) + i32::from(year_high) * 100);
> + tm.set_tm_mon((((st_time & RTC_MON_MASK) >> RTC_MON_SHIFT) - 1) as i32);
> + tm.set_tm_mday(((st_time & RTC_MDAY_MASK) >> RTC_MDAY_SHIFT) as i32);
> + tm.set_tm_wday((((st_time & RTC_WDAY_MASK) >> RTC_WDAY_SHIFT) - 1) as i32);
> + tm.set_tm_hour(((st_time & RTC_HOUR_MASK) >> RTC_HOUR_SHIFT) as i32);
> + tm.set_tm_min(((st_time & RTC_MIN_MASK) >> RTC_MIN_SHIFT) as i32);
> + tm.set_tm_sec(((st_time & RTC_SEC_MASK) >> RTC_SEC_SHIFT) as i32);
> +
> + // Values are from valid RTC time structures and are non-negative.
> + tm.set_tm_yday(tm.year_days());
> + tm.set_tm_year(tm.tm_year() - 1900);
> + tm
> +}
> +
> +/// Vendor-specific variant identifier for PL031 RTC controllers.
> +#[derive(Copy, Clone, PartialEq)]
> +enum VendorVariant {
> + /// Original ARM version with 32-bit Unix timestamp format.
> + Arm,
> + /// First ST derivative with clockwatch mode and weekday support.
> + StV1,
> + /// Second ST derivative with packed BCD time format and year register.
> + StV2,
> +}
> +
> +impl VendorVariant {
> + fn clockwatch(&self) -> bool {
> + matches!(self, VendorVariant::StV1 | VendorVariant::StV2)
> + }
> +
> + #[allow(dead_code)]
> + fn st_weekday(&self) -> bool {
> + matches!(self, VendorVariant::StV1 | VendorVariant::StV2)
> + }
> +
> + #[allow(dead_code)]
> + fn range_min(&self) -> i64 {
> + match self {
> + VendorVariant::Arm | VendorVariant::StV1 => 0,
> + VendorVariant::StV2 => bindings::RTC_TIMESTAMP_BEGIN_0000,
> + }
> + }
> +
> + #[allow(dead_code)]
> + fn range_max(&self) -> u64 {
> + match self {
> + VendorVariant::Arm | VendorVariant::StV1 => u64::from(u32::MAX),
> + VendorVariant::StV2 => bindings::RTC_TIMESTAMP_END_9999,
> + }
> + }
> +}
> +
> +/// The driver's private data struct. It holds all necessary devres managed
> +/// resources.
> +#[pin_data]
> +struct Pl031DrvData {
> + #[pin]
> + regs: Devres<IoMem<PL031_REG_SIZE>>,
> + hw_variant: VendorVariant,
> +}
> +
> +// SAFETY: `Pl031DrvData` contains only `Send`/`Sync` types: `Devres`
> +// (Send+Sync) and `VendorVariant` (Copy).
> +unsafe impl Send for Pl031DrvData {}
> +// SAFETY: `Pl031DrvData` contains only `Send`/`Sync` types: `Devres`
> +// (Send+Sync) and `VendorVariant` (Copy).
> +unsafe impl Sync for Pl031DrvData {}
> +
> +/// Vendor-specific variant identifier used in AMBA device table.
> +#[derive(Copy, Clone)]
> +struct Pl031Variant {
> + variant: VendorVariant,
> +}
> +
> +impl Pl031Variant {
> + const ARM: Self = Self {
> + variant: VendorVariant::Arm,
> + };
> + const STV1: Self = Self {
> + variant: VendorVariant::StV1,
> + };
> + const STV2: Self = Self {
> + variant: VendorVariant::StV2,
> + };
> +}
> +
> +// Use AMBA device table for matching
> +kernel::amba_device_table!(
> + ID_TABLE,
> + MODULE_ID_TABLE,
> + <Pl031AmbaDriver as amba::Driver>::IdInfo,
> + [
> + (
> + amba::DeviceId::new(0x00041031, 0x000fffff),
> + Pl031Variant::ARM
> + ),
> + (
> + amba::DeviceId::new(0x00180031, 0x00ffffff),
> + Pl031Variant::STV1
> + ),
> + (
> + amba::DeviceId::new(0x00280031, 0x00ffffff),
> + Pl031Variant::STV2
> + ),
> + ]
> +);
> +
> +#[pin_data]
> +struct Pl031AmbaDriver {
> + #[pin]
> + irqreg: irq::Registration<Pl031IrqHandler>,
> +}
> +
> +impl amba::Driver for Pl031AmbaDriver {
> + type IdInfo = Pl031Variant;
> + const AMBA_ID_TABLE: amba::IdTable<Self::IdInfo> = &ID_TABLE;
> +
> + fn probe(
> + adev: &amba::Device<Core>,
> + id_info: Option<&Self::IdInfo>,
> + ) -> impl PinInit<Self, Error> {
> + pin_init::pin_init_scope(move || {
> + let dev = adev.as_ref();
> + let io_request = adev.io_request().ok_or(ENODEV)?;
> + let variant = id_info
> + .map(|info| info.variant)
> + .unwrap_or(VendorVariant::Arm);
> +
> + let rtcdev = RtcDevice::<Pl031DrvData>::new(
> + dev,
> + try_pin_init!(Pl031DrvData {
> + regs <- IoMem::new(io_request),
> + hw_variant: variant,
> + }),
> + )?;
> +
> + dev.devm_init_wakeup()?;
> +
> + let drvdata = rtcdev.drvdata()?;
> + let regs = drvdata.regs.access(dev)?;
> +
> + // Enable the clockwatch on ST Variants
> + let mut cr = regs.read32(RTC_CR);
> + if variant.clockwatch() {
> + cr |= RTC_CR_CWEN;
> + } else {
> + cr |= RTC_CR_EN;
> + }
> + regs.write32(cr, RTC_CR);
> +
> + // On ST PL031 variants, the RTC reset value does not provide
> + // correct weekday for 2000-01-01. Correct the erroneous sunday
> + // to saturday.
> + if variant.st_weekday() {
> + let bcd_year = regs.read32(RTC_YDR);
> + if bcd_year == 0x2000 {
> + let st_time = regs.read32(RTC_DR);
> + if (st_time & (RTC_MON_MASK | RTC_MDAY_MASK | RTC_WDAY_MASK)) == 0x02120000 {
> + regs.write32(0x2000, RTC_YLR);
> + regs.write32(st_time | (0x7 << RTC_WDAY_SHIFT), RTC_LR);
> + }
> + }
> + }
> +
> + rtcdev.set_range_min(variant.range_min());
> + rtcdev.set_range_max(variant.range_max());
> +
> + // This variant shares the IRQ with another block and must not
> + // suspend that IRQ line.
> + let irq_flags = if variant == VendorVariant::StV2 {
> + kernel::irq::Flags::SHARED | kernel::irq::Flags::COND_SUSPEND
> + } else {
> + kernel::irq::Flags::SHARED
> + };
> +
> + if adev
> + .irq_by_index(0)
> + .and_then(|irq| irq.devm_set_wake_irq())
> + .is_err()
> + {
> + rtcdev.clear_feature(bindings::RTC_FEATURE_ALARM);
> + }
> +
> + rtcdev.register()?;
> +
> + Ok(try_pin_init!(Pl031AmbaDriver {
> + irqreg <- adev.request_irq_by_index(
> + irq_flags,
> + 0,
> + c_str!("rtc-pl031"),
> + try_pin_init!(Pl031IrqHandler {
> + _pin: PhantomPinned,
> + rtcdev: rtcdev.clone(),
> + }),
> + ),
> + }))
> + })
> + }
> +}
> +
> +/// Interrupt handler for PL031 RTC alarm events.
> +#[pin_data]
> +struct Pl031IrqHandler {
> + #[pin]
> + _pin: PhantomPinned,
> + rtcdev: ARef<RtcDevice<Pl031DrvData>>,
> +}
> +
> +impl Handler for Pl031IrqHandler {
> + fn handle(&self, dev: &device::Device<device::Bound>) -> IrqReturn {
> + // Get driver data using drvdata.
> + let drvdata = match self.rtcdev.drvdata() {
> + Ok(drvdata) => drvdata,
> + Err(_) => return IrqReturn::None,
> + };
> +
> + // Access the MMIO registers.
> + let regs = match drvdata.regs.access(dev) {
> + Ok(regs) => regs,
> + Err(_) => return IrqReturn::None,
> + };
> +
> + // Read masked interrupt status.
> + let rtcmis = regs.read32(RTC_MIS);
> +
> + if (rtcmis & RTC_BIT_AI) != 0 {
> + regs.write32(RTC_BIT_AI, RTC_ICR);
> + self.rtcdev.update_irq(1, (RTC_AF | RTC_IRQF) as usize);
> + return IrqReturn::Handled;
> + }
> +
> + IrqReturn::None
> + }
> +}
> +
> +#[vtable]
> +impl RtcOps for Pl031DrvData {
> + fn read_time(
> + rtcdev: &RtcDevice<Self>,
> + tm: &mut RtcTime,
> + parent_dev: &device::Device<device::Bound>,
> + ) -> Result {
> + let drvdata = rtcdev.drvdata()?;
> + let regs = drvdata.regs.access(parent_dev)?;
> +
> + match drvdata.hw_variant {
> + VendorVariant::Arm | VendorVariant::StV1 => {
> + let time32: u32 = regs.read32(RTC_DR);
> + let time64 = i64::from(time32);
> + tm.set_from_time64(time64);
> + }
> + VendorVariant::StV2 => {
> + let st_time = regs.read32(RTC_DR);
> + let bcd_year = regs.read32(RTC_YDR);
> + *tm = stv2_time_to_tm(st_time, bcd_year);
> + }
> + }
> +
> + Ok(())
> + }
> +
> + fn set_time(
> + rtcdev: &RtcDevice<Self>,
> + tm: &RtcTime,
> + parent_dev: &device::Device<device::Bound>,
> + ) -> Result {
> + let dev: &device::Device = rtcdev.as_ref();
> + let drvdata = rtcdev.drvdata()?;
> + let regs = drvdata.regs.access(parent_dev)?;
> +
> + match drvdata.hw_variant {
> + VendorVariant::Arm | VendorVariant::StV1 => {
> + let time64 = tm.to_time64();
> + regs.write32(time64 as u32, RTC_LR);
> + }
> + VendorVariant::StV2 => {
> + let (st_time, bcd_year) = stv2_tm_to_time(tm).inspect_err(|&err| {
> + if err == EINVAL {
> + dev_err!(dev, "invalid wday value {}\n", tm.tm_wday());
> + }
> + })?;
> + regs.write32(bcd_year, RTC_YLR);
> + regs.write32(st_time, RTC_LR);
> + }
> + }
> +
> + Ok(())
> + }
> +
> + fn read_alarm(
> + rtcdev: &RtcDevice<Self>,
> + alarm: &mut RtcWkAlrm,
> + parent_dev: &device::Device<device::Bound>,
> + ) -> Result {
> + let drvdata = rtcdev.drvdata()?;
> + let regs = drvdata.regs.access(parent_dev)?;
> +
> + match drvdata.hw_variant {
> + VendorVariant::Arm | VendorVariant::StV1 => {
> + let time32: u32 = regs.read32(RTC_MR);
> + let time64 = i64::from(time32);
> + RtcTime::time64_to_tm(time64, alarm.get_time_mut());
> + }
> + VendorVariant::StV2 => {
> + let st_time = regs.read32(RTC_MR);
> + let bcd_year = regs.read32(RTC_YMR);
> + *alarm.get_time_mut() = stv2_time_to_tm(st_time, bcd_year);
> + }
> + }
> +
> + alarm.set_pending((regs.read32(RTC_RIS) & RTC_BIT_AI) != 0);
> + alarm.set_enabled((regs.read32(RTC_IMSC) & RTC_BIT_AI) != 0);
> +
> + Ok(())
> + }
> +
> + fn set_alarm(
> + rtcdev: &RtcDevice<Self>,
> + alarm: &RtcWkAlrm,
> + parent_dev: &device::Device<device::Bound>,
> + ) -> Result {
> + let dev: &device::Device = rtcdev.as_ref();
> + let drvdata = rtcdev.drvdata()?;
> + let regs = drvdata.regs.access(parent_dev)?;
> +
> + match drvdata.hw_variant {
> + VendorVariant::Arm | VendorVariant::StV1 => {
> + let time64 = alarm.get_time().to_time64();
> + regs.write32(time64 as u32, RTC_MR);
> + }
> + VendorVariant::StV2 => {
> + let (st_time, bcd_year) =
> + stv2_tm_to_time(alarm.get_time()).inspect_err(|&err| {
> + if err == EINVAL {
> + dev_err!(dev, "invalid wday value {}\n", alarm.get_time().tm_wday());
> + }
> + })?;
> + regs.write32(bcd_year, RTC_YMR);
> + regs.write32(st_time, RTC_MR);
> + }
> + }
> +
> + Self::alarm_irq_enable(rtcdev, alarm.enabled(), parent_dev)
> + }
> +
> + fn alarm_irq_enable(
> + rtcdev: &RtcDevice<Self>,
> + enabled: bool,
> + parent_dev: &device::Device<device::Bound>,
> + ) -> Result {
> + let drvdata = rtcdev.drvdata()?;
> + let regs = drvdata.regs.access(parent_dev)?;
> +
> + // Clear any pending alarm interrupts.
> + regs.write32(RTC_BIT_AI, RTC_ICR);
> +
> + let mut imsc = regs.read32(RTC_IMSC);
> + if enabled {
> + imsc |= RTC_BIT_AI;
> + } else {
> + imsc &= !RTC_BIT_AI;
> + }
> + regs.write32(imsc, RTC_IMSC);
> +
> + Ok(())
> + }
> +}
> +
> +kernel::module_amba_driver! {
> + type: Pl031AmbaDriver,
> + name: "rtc-pl031-rust",
> + authors: ["Ke Sun <sunke@kylinos.cn>"],
> + description: "Rust PL031 RTC driver",
> + license: "GPL v2",
> + imports_ns: ["RTC"],
> +}
prev parent reply other threads:[~2026-01-19 9:12 UTC|newest]
Thread overview: 43+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-01-16 16:21 [RFC PATCH v3 0/5] rust: Add RTC driver support Ke Sun
2026-01-16 16:21 ` [RFC PATCH v3 1/5] rtc: add device selector for rtc_class_ops callbacks Ke Sun
2026-01-16 16:24 ` Ke Sun
2026-01-19 14:32 ` Danilo Krummrich
2026-01-20 8:01 ` Ke Sun
2026-02-20 22:53 ` Alexandre Belloni
2026-02-21 9:31 ` Alvin Sun
2026-02-21 11:16 ` Alexandre Belloni
2026-02-21 11:19 ` Rafael J. Wysocki
2026-02-21 14:33 ` Danilo Krummrich
2026-02-22 0:05 ` Alexandre Belloni
2026-02-22 12:49 ` Danilo Krummrich
2026-02-22 14:01 ` Rafael J. Wysocki
2026-02-22 16:13 ` Danilo Krummrich
2026-02-24 0:12 ` Danilo Krummrich
2026-02-24 13:28 ` Rafael J. Wysocki
2026-02-24 14:57 ` Alexandre Belloni
2026-02-24 15:23 ` Rafael J. Wysocki
2026-02-24 15:36 ` Danilo Krummrich
2026-02-24 15:01 ` Alexandre Belloni
2026-02-24 16:35 ` Danilo Krummrich
2026-02-24 16:42 ` Danilo Krummrich
2026-02-24 17:28 ` Alexandre Belloni
2026-02-24 22:23 ` Danilo Krummrich
2026-02-24 22:44 ` Alexandre Belloni
2026-02-25 3:19 ` Gary Guo
2026-02-25 13:33 ` Rafael J. Wysocki
2026-02-25 16:26 ` Danilo Krummrich
2026-02-25 21:15 ` Rafael J. Wysocki
2026-02-26 12:28 ` Rafael J. Wysocki
2026-02-27 15:09 ` Benno Lossin
2026-02-22 12:25 ` Rafael J. Wysocki
2026-02-22 14:24 ` Rafael J. Wysocki
2026-02-22 15:29 ` Danilo Krummrich
2026-02-22 15:43 ` Rafael J. Wysocki
2026-02-21 16:32 ` Alvin Sun
2026-02-21 17:53 ` Danilo Krummrich
2026-01-16 16:22 ` [RFC PATCH v3 2/5] rust: add AMBA bus driver support Ke Sun
2026-01-16 16:22 ` [RFC PATCH v3 3/5] rust: add device wakeup capability support Ke Sun
2026-01-17 0:44 ` Ke Sun
2026-01-16 16:22 ` [RFC PATCH v3 4/5] rust: add RTC core abstractions and data structures Ke Sun
2026-01-16 16:34 ` [RFC PATCH v3 5/5] rust: add PL031 RTC driver Ke Sun
2026-01-19 9:12 ` Ke Sun [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=54d8007e-c54e-44a2-8cfe-df10495cda80@gmail.com \
--to=sk.alvin.x@gmail.com \
--cc=a.hindborg@kernel.org \
--cc=alexandre.belloni@bootlin.com \
--cc=aliceryhl@google.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=dakr@kernel.org \
--cc=gary@garyguo.net \
--cc=linux-rtc@vger.kernel.org \
--cc=lossin@kernel.org \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=sunke@kylinos.cn \
--cc=tmgross@umich.edu \
/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