| // Licensed under the Apache-2.0 license | |
| // SPDX-License-Identifier: Apache-2.0 | |
| //! # Design Considerations | |
| //! | |
| //! This module defines traits and error types for abstracting system-level | |
| //! clock and reset control operations. The design emphasizes **flexibility**, | |
| //! **composability**, and **extensibility** to support a wide range of hardware | |
| //! platforms and use cases. | |
| //! | |
| //! ## Flexibility | |
| //! | |
| //! - **Platform Independence**: The traits abstract hardware-specific operations, | |
| //! allowing implementations to target different platforms without modifying | |
| //! consumer code. | |
| //! - **Custom Identifiers and Configurations**: Associated types like `ClockId`, | |
| //! `ClockConfig`, and `ResetId` allow implementers to define identifiers and | |
| //! configurations that match their hardware model. | |
| //! - **Error Abstraction**: The `Error` trait and `ErrorKind` enum decouple | |
| //! error handling from specific implementations, enabling generic code to | |
| //! respond to common failure modes while supporting detailed diagnostics. | |
| //! | |
| //! ## Composability | |
| //! | |
| //! - **Unified Error Handling**: The `ErrorType` supertrait provides a consistent | |
| //! interface for accessing error types, enabling integration with other traits | |
| //! and systems. | |
| //! - **Non-Exhaustive ErrorKind**: The `#[non_exhaustive]` attribute on `ErrorKind` | |
| //! allows future expansion without breaking existing code, supporting long-term | |
| //! composability. | |
| //! | |
| //! ## Extensibility | |
| //! | |
| //! - **Custom Error Types**: Implementers can define their own error types and | |
| //! map them to `ErrorKind`, enabling rich, context-specific error reporting | |
| //! while maintaining compatibility with generic consumers. | |
| //! - **Vendor-Specific Configuration**: The `ClockConfig` type supports complex | |
| //! configuration structures such as PLL settings, dividers, or source selectors. | |
| //! - **Partial Implementations**: While all trait methods are required, implementers | |
| //! can provide no-op or stub implementations for unsupported features, enabling | |
| //! partial functionality where appropriate. | |
| //! | |
| //! ## Summary | |
| //! | |
| //! This design provides a robust foundation for building portable, maintainable, | |
| //! and scalable hardware abstraction layers. By leveraging Rust’s trait system, | |
| //! it enables: | |
| //! | |
| //! - Reuse of generic drivers across platforms. | |
| //! - Simplified testing and mocking. | |
| //! - Clear contracts between hardware abstraction and higher-level logic. | |
| use core::time::Duration; | |
| /// Represents common system control operation errors. | |
| /// | |
| /// This enumeration defines a standard set of error conditions that can occur | |
| /// during clock and reset control operations. Implementations are free to define | |
| /// more specific or additional error types. However, by providing a mapping to | |
| /// these common errors, generic code can still react to them appropriately. | |
| #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] | |
| #[non_exhaustive] | |
| pub enum ErrorKind { | |
| /// The specified clock identifier was not found or is invalid. | |
| ClockNotFound, | |
| /// Attempted to enable a clock that is already enabled. | |
| ClockAlreadyEnabled, | |
| /// Attempted to disable a clock that is already disabled. | |
| ClockAlreadyDisabled, | |
| /// The specified clock frequency is invalid or not supported. | |
| InvalidClockFrequency, | |
| /// Clock configuration operation failed due to invalid parameters or hardware constraints. | |
| ClockConfigurationFailed, | |
| /// The specified reset identifier was not found or is invalid. | |
| InvalidResetId, | |
| /// A hardware-level failure occurred during the operation. | |
| HardwareFailure, | |
| /// The operation was denied due to insufficient permissions or security restrictions. | |
| PermissionDenied, | |
| /// The operation timed out before completion. | |
| Timeout, | |
| } | |
| /// Trait for system control error types. | |
| /// | |
| /// This trait provides a standard interface for all error types used in | |
| /// system control operations. It requires implementors to provide a mapping | |
| /// to the common `ErrorKind` enumeration, enabling generic error handling | |
| /// while preserving implementation-specific error details. | |
| pub trait Error: core::fmt::Debug { | |
| /// Convert error to a generic error kind. | |
| /// | |
| /// By using this method, errors freely defined by system control implementations | |
| /// can be converted to a set of generic errors upon which generic | |
| /// code can act. | |
| fn kind(&self) -> ErrorKind; | |
| } | |
| impl Error for core::convert::Infallible { | |
| /// Convert error to a generic error kind. | |
| /// | |
| /// Since `core::convert::Infallible` represents an error that can never occur, | |
| /// this implementation uses pattern matching on the uninhabited type to | |
| /// ensure this method can never actually be called. | |
| fn kind(&self) -> ErrorKind { | |
| match *self {} | |
| } | |
| } | |
| /// Trait providing access to the associated error type. | |
| /// | |
| /// This trait serves as a foundation for other traits that need to define | |
| /// error handling. By separating error type definition from specific operations, | |
| /// it enables composition and reuse across different trait implementations. | |
| pub trait ErrorType { | |
| /// The error type used by this implementation. | |
| /// | |
| /// This associated type must implement the `Error` trait to ensure | |
| /// it can be converted to generic error kinds for interoperability. | |
| type Error: Error; | |
| } | |
| /// Trait for clock control operations. | |
| /// Abstracts enabling, disabling, and configuring clocks for peripherals or system components. | |
| pub trait ClockControl: ErrorType { | |
| /// Type for identifying a clock (e.g., peripheral ID, clock name, or register offset). | |
| type ClockId: Clone + PartialEq; | |
| /// Type for configuring a clock. | |
| type ClockConfig: PartialEq; | |
| /// Enables a clock for the specified clock ID. | |
| /// | |
| /// # Arguments | |
| /// | |
| /// * `clock_id` - A reference to the identifier of the clock to enable. | |
| /// | |
| /// # Returns | |
| /// | |
| /// * `Result<(), Self::Error>` - Ok if the operation is successful, or an error of type `Self::Error`. | |
| fn enable(&mut self, clock_id: &Self::ClockId) -> Result<(), Self::Error>; | |
| /// Disables a clock for the specified clock ID. | |
| /// | |
| /// # Arguments | |
| /// | |
| /// * `clock_id` - A reference to the identifier of the clock to disable. | |
| /// | |
| /// # Returns | |
| /// | |
| /// * `Result<(), Self::Error>` - Ok if the operation is successful, or an error of type `Self::Error`. | |
| fn disable(&mut self, clock_id: &Self::ClockId) -> Result<(), Self::Error>; | |
| /// Sets the frequency of a clock (in Hz). | |
| /// | |
| /// # Arguments | |
| /// | |
| /// * `clock_id` - A reference to the identifier of the clock to set the frequency for. | |
| /// * `frequency_hz` - The frequency to set, in Hertz. | |
| /// | |
| /// # Returns | |
| /// | |
| /// * `Result<(), Self::Error>` - Ok if the operation is successful, or an error of type `Self::Error`. | |
| fn set_frequency( | |
| &mut self, | |
| clock_id: &Self::ClockId, | |
| frequency_hz: u64, | |
| ) -> Result<(), Self::Error>; | |
| /// Gets the current frequency of a clock (in Hz). | |
| /// | |
| /// # Arguments | |
| /// | |
| /// * `clock_id` - A reference to the identifier of the clock to get the frequency for. | |
| /// | |
| /// # Returns | |
| /// | |
| /// * `Result<u64, Self::Error>` - Ok with the current frequency in Hertz, or an error of type `Self::Error`. | |
| fn get_frequency(&self, clock_id: &Self::ClockId) -> Result<u64, Self::Error>; | |
| /// Configures clock-specific parameters (e.g., divider, source). | |
| /// Vendor-specific parameters can be passed via `ClockConfig`. | |
| /// | |
| /// # Arguments | |
| /// | |
| /// * `clock_id` - A reference to the identifier of the clock to configure. | |
| /// * `config` - The configuration parameters for the clock. | |
| /// | |
| /// # Returns | |
| /// | |
| /// * `Result<(), Self::Error>` - Ok if the operation is successful, or an error of type `Self::Error`. | |
| fn configure( | |
| &mut self, | |
| clock_id: &Self::ClockId, | |
| config: Self::ClockConfig, | |
| ) -> Result<(), Self::Error>; | |
| /// Retrieves the current configuration of a clock. | |
| /// | |
| /// # Arguments | |
| /// | |
| /// * `clock_id` - A reference to the identifier of the clock to get the configuration for. | |
| /// | |
| /// # Returns | |
| /// | |
| /// * `Result<Self::ClockConfig, Self::Error>` - Ok with the current configuration, or an error of type `Self::Error`. | |
| fn get_config(&self, clock_id: &Self::ClockId) -> Result<Self::ClockConfig, Self::Error>; | |
| } | |
| /// Trait for reset control operations. | |
| /// Abstracts asserting and deasserting reset signals for peripherals or system components. | |
| pub trait ResetControl: ErrorType { | |
| /// Type for identifying a reset line (e.g., peripheral ID, reset name, or register offset). | |
| type ResetId: Clone + PartialEq; | |
| /// Asserts the reset signal for the specified reset ID (holds the component in reset). | |
| /// | |
| /// # Arguments | |
| /// | |
| /// * `reset_id` - A reference to the identifier of the reset line to assert. | |
| /// | |
| /// # Returns | |
| /// | |
| /// * `Result<(), Self::Error>` - Ok if the operation is successful, or an error of type `Self::Error`. | |
| fn reset_assert(&mut self, reset_id: &Self::ResetId) -> Result<(), Self::Error>; | |
| /// Deasserts the reset signal for the specified reset ID (releases the component from reset). | |
| /// | |
| /// # Arguments | |
| /// | |
| /// * `reset_id` - A reference to the identifier of the reset line to deassert. | |
| /// | |
| /// # Returns | |
| /// | |
| /// * `Result<(), Self::Error>` - Ok if the operation is successful, or an error of type `Self::Error`. | |
| fn reset_deassert(&mut self, reset_id: &Self::ResetId) -> Result<(), Self::Error>; | |
| /// Performs a pulse reset (asserts then deasserts) with a specified duration (in microseconds). | |
| /// | |
| /// # Arguments | |
| /// | |
| /// * `reset_id` - A reference to the identifier of the reset line to pulse. | |
| /// * `duration_us` - The duration of the pulse in microseconds. | |
| /// | |
| /// # Returns | |
| /// | |
| /// * `Result<(), Self::Error>` - Ok if the operation is successful, or an error of type `Self::Error`. | |
| fn reset_pulse( | |
| &mut self, | |
| reset_id: &Self::ResetId, | |
| duration: Duration, | |
| ) -> Result<(), Self::Error>; | |
| /// Checks if the reset signal is currently asserted for the specified reset ID. | |
| /// | |
| /// # Arguments | |
| /// | |
| /// * `reset_id` - A reference to the identifier of the reset line to check. | |
| /// | |
| /// # Returns | |
| /// | |
| /// * `Result<bool, Self::Error>` - Ok with a boolean indicating if the reset is asserted, or an error of type `Self::Error`. | |
| fn reset_is_asserted(&self, reset_id: &Self::ResetId) -> Result<bool, Self::Error>; | |
| } | |
| /// Blanket trait that combines clock and reset control functionality. | |
| /// | |
| /// This trait provides a unified interface for system control operations, | |
| /// combining both clock management and reset control capabilities. It is | |
| /// automatically implemented for any type that implements both `ClockControl` | |
| /// and `ResetControl` with the same error type. | |
| /// | |
| /// # Design | |
| /// | |
| /// The blanket implementation pattern allows consumers to use a single trait | |
| /// bound for system control operations while maintaining the flexibility of | |
| /// separate, composable traits for clock and reset functionality. | |
| /// | |
| /// # Example | |
| /// | |
| /// ```rust,ignore | |
| /// fn configure_system<T: SystemControl>(controller: &mut T) | |
| /// where | |
| /// T::ClockId: From<u32>, | |
| /// T::ResetId: From<u32>, | |
| /// T::ClockConfig: Default, | |
| /// { | |
| /// // Enable peripheral clock | |
| /// controller.enable(&T::ClockId::from(42)).unwrap(); | |
| /// | |
| /// // Release from reset | |
| /// controller.reset_deassert(&T::ResetId::from(42)).unwrap(); | |
| /// } | |
| /// ``` | |
| pub trait SystemControl: ClockControl + ResetControl {} | |
| /// Blanket implementation of SystemControl for types implementing both traits. | |
| /// | |
| /// This implementation is automatically provided for any type that implements | |
| /// both `ClockControl` and `ResetControl` with compatible error types. | |
| impl<T> SystemControl for T where T: ClockControl + ResetControl {} |