lpc55s6x/clocks/
mod.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2025.
4
5//! Clock configuration and control for the LPC55S6x system controller (SYSCON).
6//!
7//! This module provides safe abstractions for enabling peripheral clocks,
8//! configuring Fractional Rate Generators (FRGs), and setting up UART clock
9//! sources. It wraps low-level register access in a structured API to ensure
10//! clarity and maintainability across the Tock kernel codebase.
11
12pub mod syscon;
13use crate::clocks::syscon::SYSCON_BASE;
14
15use self::syscon::SysconRegisters;
16use enum_primitive::{cast::FromPrimitive, enum_from_primitive};
17use kernel::utilities::registers::interfaces::ReadWriteable;
18
19pub enum Peripheral {
20    Flexcomm0,
21    Flexcomm1,
22    Flexcomm2,
23    Flexcomm3,
24    Flexcomm4,
25    Gpio0,
26    Gpio1,
27    Dma0,
28}
29
30enum_from_primitive! {
31    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
32    #[repr(u8)]
33    pub enum FrgId {
34        Frg0 = 0,
35        Frg1 = 1,
36        Frg2 = 2,
37        Frg3 = 3,
38        Frg4 = 4,
39        Frg5 = 5,
40        Frg6 = 6,
41        Frg7 = 7,
42    }
43}
44
45#[derive(Copy, Clone)]
46pub enum FrgClockSource {
47    MainClock,
48    SystemPll,
49    Fro12Mhz,
50    Fro96Mhz,
51    Fro1Mhz,
52    Mclk,
53    Osc32Khz,
54    NoClock,
55}
56
57pub struct Clock {
58    syscon: &'static SysconRegisters,
59}
60
61impl Clock {
62    pub fn new() -> Clock {
63        Clock {
64            syscon: &SYSCON_BASE,
65        }
66    }
67
68    pub fn start_gpio_clocks(&self) {
69        self.syscon.ahbclkctrl0.modify(
70            syscon::AHBCLKCTRL0::SRAM_CTRL1::SET
71                + syscon::AHBCLKCTRL0::SRAM_CTRL2::SET
72                + syscon::AHBCLKCTRL0::SRAM_CTRL3::SET
73                + syscon::AHBCLKCTRL0::SRAM_CTRL4::SET
74                + syscon::AHBCLKCTRL0::IOCON::SET
75                + syscon::AHBCLKCTRL0::GPIO0::SET
76                + syscon::AHBCLKCTRL0::GPIO1::SET
77                + syscon::AHBCLKCTRL0::GPIO2::SET
78                + syscon::AHBCLKCTRL0::GPIO3::SET
79                + syscon::AHBCLKCTRL0::PINT::SET
80                + syscon::AHBCLKCTRL0::MUX::SET,
81        );
82    }
83
84    pub fn start_timer_clocks(&self) {
85        self.syscon
86            .ctimerclksel0
87            .modify(syscon::CTIMERCLKSEL0::SEL::CLEAR);
88
89        self.syscon
90            .ahbclkctrl1
91            .modify(syscon::AHBCLKCTRL1::TIMER0::SET);
92
93        self.syscon.clkoutsel.modify(syscon::CLKOUTSEL::SEL::SET);
94    }
95
96    pub fn set_frg_clock_source(&self, frg_id: FrgId, source: FrgClockSource) {
97        let sel_val = match source {
98            FrgClockSource::MainClock => syscon::FCCLKSEL::SEL::MainClock,
99            FrgClockSource::SystemPll => syscon::FCCLKSEL::SEL::SystemPLLDividedClock,
100            FrgClockSource::Fro12Mhz => syscon::FCCLKSEL::SEL::FRO12MHzClock,
101            FrgClockSource::Fro96Mhz => syscon::FCCLKSEL::SEL::FRO96MHzClock,
102            FrgClockSource::Fro1Mhz => syscon::FCCLKSEL::SEL::FRO1MHzClock,
103            FrgClockSource::Mclk => syscon::FCCLKSEL::SEL::MCLKClock,
104            FrgClockSource::Osc32Khz => syscon::FCCLKSEL::SEL::Oscillator32KHzClock,
105            FrgClockSource::NoClock => syscon::FCCLKSEL::SEL::NoClock,
106        };
107
108        match frg_id {
109            FrgId::Frg0 => self.syscon.fcclksel0.modify(sel_val),
110            FrgId::Frg1 => self.syscon.fcclksel1.modify(sel_val),
111            FrgId::Frg2 => self.syscon.fcclksel2.modify(sel_val),
112            FrgId::Frg3 => self.syscon.fcclksel3.modify(sel_val),
113            FrgId::Frg4 => self.syscon.fcclksel4.modify(sel_val),
114            FrgId::Frg5 => self.syscon.fcclksel5.modify(sel_val),
115            FrgId::Frg6 => self.syscon.fcclksel6.modify(sel_val),
116            FrgId::Frg7 => self.syscon.fcclksel7.modify(sel_val),
117        }
118    }
119
120    pub fn get_frg_clock_frequency(&self, source: FrgClockSource) -> u32 {
121        match source {
122            FrgClockSource::Fro12Mhz => 12_000_000,
123            FrgClockSource::Fro96Mhz => 96_000_000,
124            FrgClockSource::Fro1Mhz => 1_000_000,
125            FrgClockSource::Osc32Khz => 32_768,
126            FrgClockSource::MainClock => 12_000_000, //not definitive, should check mainclksel
127            FrgClockSource::SystemPll => 0,
128            FrgClockSource::Mclk => 0,
129            FrgClockSource::NoClock => 0,
130        }
131    }
132
133    pub fn setup_uart_clock(&self, flexcomm_id: FrgId, frg_source: FrgClockSource) {
134        // Enable the bus clock for the peripheral
135        match flexcomm_id {
136            FrgId::Frg0 => self
137                .syscon
138                .ahbclkctrl1
139                .modify(syscon::AHBCLKCTRL1::FC0::SET),
140            FrgId::Frg1 => self
141                .syscon
142                .ahbclkctrl1
143                .modify(syscon::AHBCLKCTRL1::FC1::SET),
144            FrgId::Frg2 => self
145                .syscon
146                .ahbclkctrl1
147                .modify(syscon::AHBCLKCTRL1::FC2::SET),
148            FrgId::Frg3 => self
149                .syscon
150                .ahbclkctrl1
151                .modify(syscon::AHBCLKCTRL1::FC3::SET),
152            FrgId::Frg4 => self
153                .syscon
154                .ahbclkctrl1
155                .modify(syscon::AHBCLKCTRL1::FC4::SET),
156            FrgId::Frg5 => self
157                .syscon
158                .ahbclkctrl1
159                .modify(syscon::AHBCLKCTRL1::FC5::SET),
160            FrgId::Frg6 => self
161                .syscon
162                .ahbclkctrl1
163                .modify(syscon::AHBCLKCTRL1::FC6::SET),
164            FrgId::Frg7 => self
165                .syscon
166                .ahbclkctrl1
167                .modify(syscon::AHBCLKCTRL1::FC7::SET),
168        }
169
170        // Setting the clock source for the Fractional Rate Divider
171        self.set_frg_clock_source(flexcomm_id, frg_source);
172    }
173}