rp2350/
clocks.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 OxidOS Automotive 2025.
4
5use core::cell::Cell;
6use kernel::utilities::registers::{
7    interfaces::{ReadWriteable, Readable, Writeable},
8    register_bitfields, register_structs, ReadOnly, ReadWrite,
9};
10use kernel::utilities::StaticRef;
11
12register_structs! {
13    GpioClockRegisters {
14        /// Clock control, can be changed on-the-fly (except for auxsrc)
15        (0x000 => ctrl: ReadWrite<u32, CLK_GPOUTx_CTRL::Register>),
16        /// Clock divisor, can be changed on-the-fly
17        (0x004 => div: ReadWrite<u32, CLK_GPOUTx_DIV::Register>),
18        /// Indicates which src is currently selected (one-hot)
19        (0x008 => selected: ReadOnly<u32, CLK_GPOUTx_SELECTED::Register>),
20        /// Clock control, can be changed on-the-fly (except for auxsrc)
21        (0x00C => @END),
22    },
23    ClocksRegisters {
24        (0x000 => clk_gpio: [GpioClockRegisters; 4]),
25        /// Clock control, can be changed on-the-fly (except for auxsrc)
26        (0x030 => clk_ref_ctrl: ReadWrite<u32, CLK_REF_CTRL::Register>),
27
28        (0x034 => clk_ref_div: ReadWrite<u32>),
29        /// Indicates which src is currently selected (one-hot)
30        (0x038 => clk_ref_selected: ReadWrite<u32, CLK_REF_SELECTED::Register>),
31        /// Clock control, can be changed on-the-fly (except for auxsrc)
32        (0x03C => clk_sys_ctrl: ReadWrite<u32, CLK_SYS_CTRL::Register>),
33
34        (0x040 => clk_sys_div: ReadWrite<u32, CLK_SYS_DIV::Register>),
35        /// Indicates which src is currently selected (one-hot)
36        (0x044 => clk_sys_selected: ReadWrite<u32, CLK_SYS_SELECTED::Register>),
37        /// Clock control, can be changed on-the-fly (except for auxsrc)
38        (0x048 => clk_peri_ctrl: ReadWrite<u32, CLK_PERI_CTRL::Register>),
39
40        (0x04C => clk_peri_div: ReadWrite<u32>),
41        /// Indicates which src is currently selected (one-hot)
42        (0x050 => clk_peri_selected: ReadWrite<u32>),
43        /// Clock control, can be changed on-the-fly (except for auxsrc)
44        (0x054 => clk_hstx_ctrl: ReadWrite<u32, CLK_HSTX_CTRL::Register>),
45
46        (0x058 => clk_hstx_div: ReadWrite<u32>),
47        /// Indicates which src is currently selected (one-hot)
48        (0x05C => clk_hstx_selected: ReadWrite<u32>),
49        /// Clock control, can be changed on-the-fly (except for auxsrc)
50        (0x060 => clk_usb_ctrl: ReadWrite<u32, CLK_USB_CTRL::Register>),
51
52        (0x064 => clk_usb_div: ReadWrite<u32>),
53        /// Indicates which src is currently selected (one-hot)
54        (0x068 => clk_usb_selected: ReadWrite<u32>),
55        /// Clock control, can be changed on-the-fly (except for auxsrc)
56        (0x06C => clk_adc_ctrl: ReadWrite<u32, CLK_ADC_CTRL::Register>),
57
58        (0x070 => clk_adc_div: ReadWrite<u32>),
59        /// Indicates which src is currently selected (one-hot)
60        (0x074 => clk_adc_selected: ReadWrite<u32>),
61
62        (0x078 => dftclk_xosc_ctrl: ReadWrite<u32>),
63
64        (0x07C => dftclk_rosc_ctrl: ReadWrite<u32>),
65
66        (0x080 => dftclk_lposc_ctrl: ReadWrite<u32>),
67
68        (0x084 => clk_sys_resus_ctrl: ReadWrite<u32, CLK_SYS_RESUS_CTRL::Register>),
69
70        (0x088 => clk_sys_resus_status: ReadWrite<u32>),
71        /// Reference clock frequency in kHz
72        (0x08C => fc0_ref_khz: ReadWrite<u32>),
73        /// Minimum pass frequency in kHz. This is optional. Set to 0 if you are not using t
74        (0x090 => fc0_min_khz: ReadWrite<u32>),
75        /// Maximum pass frequency in kHz. This is optional. Set to 0x1ffffff if you are not
76        (0x094 => fc0_max_khz: ReadWrite<u32>),
77        /// Delays the start of frequency counting to allow the mux to settle
78        /// Delay is measured in multiples of the reference clock period
79        (0x098 => fc0_delay: ReadWrite<u32>),
80        /// The test interval is 0.98us * 2**interval, but let's call it 1us * 2**interval
81        /// The default gives a test interval of 250us
82        (0x09C => fc0_interval: ReadWrite<u32>),
83        /// Clock sent to frequency counter, set to 0 when not required
84        /// Writing to this register initiates the frequency count
85        (0x0A0 => fc0_src: ReadWrite<u32>),
86        /// Frequency counter status
87        (0x0A4 => fc0_status: ReadWrite<u32, FC0_STATUS::Register>),
88        /// Result of frequency measurement, only valid when status_done=1
89        (0x0A8 => fc0_result: ReadWrite<u32, FC0_RESULT::Register>),
90        /// enable clock in wake mode
91        (0x0AC => wake_en0: ReadWrite<u32, WAKE_EN0::Register>),
92        /// enable clock in wake mode
93        (0x0B0 => wake_en1: ReadWrite<u32, WAKE_EN1::Register>),
94        /// enable clock in sleep mode
95        (0x0B4 => sleep_en0: ReadWrite<u32, SLEEP_EN0::Register>),
96        /// enable clock in sleep mode
97        (0x0B8 => sleep_en1: ReadWrite<u32, SLEEP_EN1::Register>),
98        /// indicates the state of the clock enable
99        (0x0BC => enabled0: ReadWrite<u32, ENABLED0::Register>),
100        /// indicates the state of the clock enable
101        (0x0C0 => enabled1: ReadWrite<u32, ENABLED1::Register>),
102        /// Raw Interrupts
103        (0x0C4 => intr: ReadWrite<u32>),
104        /// Interrupt Enable
105        (0x0C8 => inte: ReadWrite<u32>),
106        /// Interrupt Force
107        (0x0CC => intf: ReadWrite<u32>),
108        /// Interrupt status after masking & forcing
109        (0x0D0 => ints: ReadWrite<u32>),
110        (0x0D4 => @END),
111    },
112     PllRegisters {
113        /// Control and Status
114        /// GENERAL CONSTRAINTS:
115        /// Reference clock frequency min=5MHz, max=800MHz
116        /// Feedback divider min=16, max=320
117        /// VCO frequency min=750MHz, max=1600MHz
118        (0x000 => cs: ReadWrite<u32, CS::Register>),
119        /// Controls the PLL power modes.
120        (0x004 => pwr: ReadWrite<u32, PWR::Register>),
121        /// Feedback divisor
122        /// (note: this PLL does not support fractional division)
123        (0x008 => fbdiv_int: ReadWrite<u32, FBDIV_INT::Register>),
124        /// Controls the PLL post dividers for the primary output
125        /// (note: this PLL does not have a secondary output)
126        /// the primary output is driven from VCO divided by postdiv1*po
127        (0x00C => prim: ReadWrite<u32, PRIM::Register>),
128        /// Raw Interrupts
129        (0x010 => intr: ReadWrite<u32>),
130        /// Interrupt Enable
131        (0x014 => inte: ReadWrite<u32>),
132        /// Interrupt Force
133        (0x018 => intf: ReadWrite<u32>),
134        /// Interrupt status after masking & forcing
135        (0x01C => ints: ReadWrite<u32>),
136        (0x020 => @END),
137    }
138}
139register_bitfields![u32,
140CLK_GPOUTx_CTRL [
141    /// clock generator is enabled
142    ENABLED OFFSET(28) NUMBITS(1) [],
143    /// An edge on this signal shifts the phase of the output by 1 cycle of the input cl
144        /// This can be done at any time
145    NUDGE OFFSET(20) NUMBITS(1) [],
146    /// This delays the enable signal by up to 3 cycles of the input clock
147    /// This must be set before the clock is enabled to have
148    PHASE OFFSET(16) NUMBITS(2) [],
149    /// Enables duty cycle correction for odd divisors, can be changed on-the-fly
150    DC50 OFFSET(12) NUMBITS(1) [],
151    /// Starts and stops the clock generator cleanly
152    ENABLE OFFSET(11) NUMBITS(1) [],
153    /// Asynchronously kills the clock generator, enable must be set low before deassert
154    KILL OFFSET(10) NUMBITS(1) [],
155    /// Selects the auxiliary clock source, will glitch when switching
156    AUXSRC OFFSET(5) NUMBITS(4) [
157
158        Clksrc_pll_sys = 0
159    ]
160],
161CLK_GPOUTx_DIV [
162    /// Integer part of clock divisor, 0 -> max+1, can be changed on-the-fly
163    INT OFFSET(16) NUMBITS(16) [],
164    /// Fractional component of the divisor, can be changed on-the-fly
165    FRAC OFFSET(0) NUMBITS(16) []
166],
167CLK_GPOUTx_SELECTED [
168    /// This slice does not have a glitchless mux (only the AUX_SRC field is present, no
169    CLK_GPOUT0_SELECTED OFFSET(0) NUMBITS(1) []
170],
171CLK_REF_CTRL [
172    /// Selects the auxiliary clock source, will glitch when switching
173    AUXSRC OFFSET(5) NUMBITS(2) [
174
175        Clksrc_pll_usb = 0
176    ],
177    /// Selects the clock source glitchlessly, can be changed on-the-fly
178    SRC OFFSET(0) NUMBITS(2) [
179
180        Rosc_clksrc_ph = 0
181    ]
182],
183CLK_REF_DIV [
184    /// Integer part of clock divisor, 0 -> max+1, can be changed on-the-fly
185    INT OFFSET(16) NUMBITS(8) []
186],
187CLK_REF_SELECTED [
188    /// The glitchless multiplexer does not switch instantaneously (to avoid glitches),
189    CLK_REF_SELECTED OFFSET(0) NUMBITS(4) []
190],
191CLK_SYS_CTRL [
192    /// Selects the auxiliary clock source, will glitch when switching
193    AUXSRC OFFSET(5) NUMBITS(3) [
194
195        Clksrc_pll_sys = 0
196    ],
197    /// Selects the clock source glitchlessly, can be changed on-the-fly
198    SRC OFFSET(0) NUMBITS(1) [
199
200        Clk_ref = 0
201    ]
202],
203CLK_SYS_DIV [
204    /// Integer part of clock divisor, 0 -> max+1, can be changed on-the-fly
205    INT OFFSET(16) NUMBITS(16) [],
206    /// Fractional component of the divisor, can be changed on-the-fly
207    FRAC OFFSET(0) NUMBITS(16) []
208],
209CLK_SYS_SELECTED [
210    /// The glitchless multiplexer does not switch instantaneously (to avoid glitches),
211    CLK_SYS_SELECTED OFFSET(0) NUMBITS(2) []
212],
213CLK_PERI_CTRL [
214    /// clock generator is enabled
215    ENABLED OFFSET(28) NUMBITS(1) [],
216    /// Starts and stops the clock generator cleanly
217    ENABLE OFFSET(11) NUMBITS(1) [],
218    /// Asynchronously kills the clock generator, enable must be set low before deassert
219    KILL OFFSET(10) NUMBITS(1) [],
220    /// Selects the auxiliary clock source, will glitch when switching
221    AUXSRC OFFSET(5) NUMBITS(3) [
222
223        Clk_sys = 0
224    ]
225],
226CLK_PERI_DIV [
227    /// Integer part of clock divisor, 0 -> max+1, can be changed on-the-fly
228    INT OFFSET(16) NUMBITS(2) []
229],
230CLK_PERI_SELECTED [
231    /// This slice does not have a glitchless mux (only the AUX_SRC field is present, no
232    CLK_PERI_SELECTED OFFSET(0) NUMBITS(1) []
233],
234CLK_HSTX_CTRL [
235    /// clock generator is enabled
236    ENABLED OFFSET(28) NUMBITS(1) [],
237    /// An edge on this signal shifts the phase of the output by 1 cycle of the input cl
238    /// This can be done at any time
239    NUDGE OFFSET(20) NUMBITS(1) [],
240    /// This delays the enable signal by up to 3 cycles of the input clock
241    /// This must be set before the clock is enabled to have
242    PHASE OFFSET(16) NUMBITS(2) [],
243    /// Starts and stops the clock generator cleanly
244    ENABLE OFFSET(11) NUMBITS(1) [],
245    /// Asynchronously kills the clock generator, enable must be set low before deassert
246    KILL OFFSET(10) NUMBITS(1) [],
247    /// Selects the auxiliary clock source, will glitch when switching
248    AUXSRC OFFSET(5) NUMBITS(3) [
249
250        Clk_sys = 0
251    ]
252],
253CLK_HSTX_DIV [
254    /// Integer part of clock divisor, 0 -> max+1, can be changed on-the-fly
255    INT OFFSET(16) NUMBITS(2) []
256],
257CLK_HSTX_SELECTED [
258    /// This slice does not have a glitchless mux (only the AUX_SRC field is present, no
259    CLK_HSTX_SELECTED OFFSET(0) NUMBITS(1) []
260],
261CLK_USB_CTRL [
262    /// clock generator is enabled
263    ENABLED OFFSET(28) NUMBITS(1) [],
264    /// An edge on this signal shifts the phase of the output by 1 cycle of the input cl
265    /// This can be done at any time
266    NUDGE OFFSET(20) NUMBITS(1) [],
267    /// This delays the enable signal by up to 3 cycles of the input clock
268    /// This must be set before the clock is enabled to have
269    PHASE OFFSET(16) NUMBITS(2) [],
270    /// Starts and stops the clock generator cleanly
271    ENABLE OFFSET(11) NUMBITS(1) [],
272    /// Asynchronously kills the clock generator, enable must be set low before deassert
273    KILL OFFSET(10) NUMBITS(1) [],
274    /// Selects the auxiliary clock source, will glitch when switching
275    AUXSRC OFFSET(5) NUMBITS(3) [
276
277        Clksrc_pll_usb = 0
278    ]
279],
280CLK_USB_DIV [
281    /// Integer part of clock divisor, 0 -> max+1, can be changed on-the-fly
282    INT OFFSET(16) NUMBITS(4) []
283],
284CLK_USB_SELECTED [
285    /// This slice does not have a glitchless mux (only the AUX_SRC field is present, no
286    CLK_USB_SELECTED OFFSET(0) NUMBITS(1) []
287],
288CLK_ADC_CTRL [
289    /// clock generator is enabled
290    ENABLED OFFSET(28) NUMBITS(1) [],
291    /// An edge on this signal shifts the phase of the output by 1 cycle of the input cl
292    /// This can be done at any time
293    NUDGE OFFSET(20) NUMBITS(1) [],
294    /// This delays the enable signal by up to 3 cycles of the input clock
295    /// This must be set before the clock is enabled to have
296    PHASE OFFSET(16) NUMBITS(2) [],
297    /// Starts and stops the clock generator cleanly
298    ENABLE OFFSET(11) NUMBITS(1) [],
299    /// Asynchronously kills the clock generator, enable must be set low before deassert
300    KILL OFFSET(10) NUMBITS(1) [],
301    /// Selects the auxiliary clock source, will glitch when switching
302    AUXSRC OFFSET(5) NUMBITS(3) [
303
304        Clksrc_pll_usb = 0
305    ]
306],
307CLK_ADC_DIV [
308    /// Integer part of clock divisor, 0 -> max+1, can be changed on-the-fly
309    INT OFFSET(16) NUMBITS(4) []
310],
311CLK_ADC_SELECTED [
312    /// This slice does not have a glitchless mux (only the AUX_SRC field is present, no
313    CLK_ADC_SELECTED OFFSET(0) NUMBITS(1) []
314],
315DFTCLK_XOSC_CTRL [
316
317    SRC OFFSET(0) NUMBITS(2) [
318
319        NULL = 0
320    ]
321],
322DFTCLK_ROSC_CTRL [
323
324    SRC OFFSET(0) NUMBITS(2) [
325
326        NULL = 0
327    ]
328],
329DFTCLK_LPOSC_CTRL [
330
331    SRC OFFSET(0) NUMBITS(2) [
332
333        NULL = 0
334    ]
335],
336CLK_SYS_RESUS_CTRL [
337    /// For clearing the resus after the fault that triggered it has been corrected
338    CLEAR OFFSET(16) NUMBITS(1) [],
339    /// Force a resus, for test purposes only
340    FRCE OFFSET(12) NUMBITS(1) [],
341    /// Enable resus
342    ENABLE OFFSET(8) NUMBITS(1) [],
343    /// This is expressed as a number of clk_ref cycles
344    /// and must be >= 2x clk_ref_freq/min_clk_tst_freq
345    TIMEOUT OFFSET(0) NUMBITS(8) []
346],
347CLK_SYS_RESUS_STATUS [
348    /// Clock has been resuscitated, correct the error then send ctrl_clear=1
349    RESUSSED OFFSET(0) NUMBITS(1) []
350],
351FC0_REF_KHZ [
352
353    FC0_REF_KHZ OFFSET(0) NUMBITS(20) []
354],
355FC0_MIN_KHZ [
356
357    FC0_MIN_KHZ OFFSET(0) NUMBITS(25) []
358],
359FC0_MAX_KHZ [
360
361    FC0_MAX_KHZ OFFSET(0) NUMBITS(25) []
362],
363FC0_DELAY [
364
365    FC0_DELAY OFFSET(0) NUMBITS(3) []
366],
367FC0_INTERVAL [
368
369    FC0_INTERVAL OFFSET(0) NUMBITS(4) []
370],
371FC0_SRC [
372
373    FC0_SRC OFFSET(0) NUMBITS(8) [
374
375        NULL = 0
376    ]
377],
378FC0_STATUS [
379    /// Test clock stopped during test
380    DIED OFFSET(28) NUMBITS(1) [],
381    /// Test clock faster than expected, only valid when status_done=1
382    FAST OFFSET(24) NUMBITS(1) [],
383    /// Test clock slower than expected, only valid when status_done=1
384    SLOW OFFSET(20) NUMBITS(1) [],
385    /// Test failed
386    FAIL OFFSET(16) NUMBITS(1) [],
387    /// Waiting for test clock to start
388    WAITING OFFSET(12) NUMBITS(1) [],
389    /// Test running
390    RUNNING OFFSET(8) NUMBITS(1) [],
391    /// Test complete
392    DONE OFFSET(4) NUMBITS(1) [],
393    /// Test passed
394    PASS OFFSET(0) NUMBITS(1) []
395],
396FC0_RESULT [
397
398    KHZ OFFSET(5) NUMBITS(25) [],
399
400    FRAC OFFSET(0) NUMBITS(5) []
401],
402WAKE_EN0 [
403
404    CLK_SYS_SIO OFFSET(31) NUMBITS(1) [],
405
406    CLK_SYS_SHA256 OFFSET(30) NUMBITS(1) [],
407
408    CLK_SYS_PSM OFFSET(29) NUMBITS(1) [],
409
410    CLK_SYS_ROSC OFFSET(28) NUMBITS(1) [],
411
412    CLK_SYS_ROM OFFSET(27) NUMBITS(1) [],
413
414    CLK_SYS_RESETS OFFSET(26) NUMBITS(1) [],
415
416    CLK_SYS_PWM OFFSET(25) NUMBITS(1) [],
417
418    CLK_SYS_POWMAN OFFSET(24) NUMBITS(1) [],
419
420    CLK_REF_POWMAN OFFSET(23) NUMBITS(1) [],
421
422    CLK_SYS_PLL_USB OFFSET(22) NUMBITS(1) [],
423
424    CLK_SYS_PLL_SYS OFFSET(21) NUMBITS(1) [],
425
426    CLK_SYS_PIO2 OFFSET(20) NUMBITS(1) [],
427
428    CLK_SYS_PIO1 OFFSET(19) NUMBITS(1) [],
429
430    CLK_SYS_PIO0 OFFSET(18) NUMBITS(1) [],
431
432    CLK_SYS_PADS OFFSET(17) NUMBITS(1) [],
433
434    CLK_SYS_OTP OFFSET(16) NUMBITS(1) [],
435
436    CLK_REF_OTP OFFSET(15) NUMBITS(1) [],
437
438    CLK_SYS_JTAG OFFSET(14) NUMBITS(1) [],
439
440    CLK_SYS_IO OFFSET(13) NUMBITS(1) [],
441
442    CLK_SYS_I2C1 OFFSET(12) NUMBITS(1) [],
443
444    CLK_SYS_I2C0 OFFSET(11) NUMBITS(1) [],
445
446    CLK_SYS_HSTX OFFSET(10) NUMBITS(1) [],
447
448    CLK_HSTX OFFSET(9) NUMBITS(1) [],
449
450    CLK_SYS_GLITCH_DETECTOR OFFSET(8) NUMBITS(1) [],
451
452    CLK_SYS_DMA OFFSET(7) NUMBITS(1) [],
453
454    CLK_SYS_BUSFABRIC OFFSET(6) NUMBITS(1) [],
455
456    CLK_SYS_BUSCTRL OFFSET(5) NUMBITS(1) [],
457
458    CLK_SYS_BOOTRAM OFFSET(4) NUMBITS(1) [],
459
460    CLK_SYS_ADC OFFSET(3) NUMBITS(1) [],
461
462    CLK_ADC OFFSET(2) NUMBITS(1) [],
463
464    CLK_SYS_ACCESSCTRL OFFSET(1) NUMBITS(1) [],
465
466    CLK_SYS_CLOCKS OFFSET(0) NUMBITS(1) []
467],
468WAKE_EN1 [
469
470    CLK_SYS_XOSC OFFSET(30) NUMBITS(1) [],
471
472    CLK_SYS_XIP OFFSET(29) NUMBITS(1) [],
473
474    CLK_SYS_WATCHDOG OFFSET(28) NUMBITS(1) [],
475
476    CLK_USB OFFSET(27) NUMBITS(1) [],
477
478    CLK_SYS_USBCTRL OFFSET(26) NUMBITS(1) [],
479
480    CLK_SYS_UART1 OFFSET(25) NUMBITS(1) [],
481
482    CLK_PERI_UART1 OFFSET(24) NUMBITS(1) [],
483
484    CLK_SYS_UART0 OFFSET(23) NUMBITS(1) [],
485
486    CLK_PERI_UART0 OFFSET(22) NUMBITS(1) [],
487
488    CLK_SYS_TRNG OFFSET(21) NUMBITS(1) [],
489
490    CLK_SYS_TIMER1 OFFSET(20) NUMBITS(1) [],
491
492    CLK_SYS_TIMER0 OFFSET(19) NUMBITS(1) [],
493
494    CLK_SYS_TICKS OFFSET(18) NUMBITS(1) [],
495
496    CLK_REF_TICKS OFFSET(17) NUMBITS(1) [],
497
498    CLK_SYS_TBMAN OFFSET(16) NUMBITS(1) [],
499
500    CLK_SYS_SYSINFO OFFSET(15) NUMBITS(1) [],
501
502    CLK_SYS_SYSCFG OFFSET(14) NUMBITS(1) [],
503
504    CLK_SYS_SRAM9 OFFSET(13) NUMBITS(1) [],
505
506    CLK_SYS_SRAM8 OFFSET(12) NUMBITS(1) [],
507
508    CLK_SYS_SRAM7 OFFSET(11) NUMBITS(1) [],
509
510    CLK_SYS_SRAM6 OFFSET(10) NUMBITS(1) [],
511
512    CLK_SYS_SRAM5 OFFSET(9) NUMBITS(1) [],
513
514    CLK_SYS_SRAM4 OFFSET(8) NUMBITS(1) [],
515
516    CLK_SYS_SRAM3 OFFSET(7) NUMBITS(1) [],
517
518    CLK_SYS_SRAM2 OFFSET(6) NUMBITS(1) [],
519
520    CLK_SYS_SRAM1 OFFSET(5) NUMBITS(1) [],
521
522    CLK_SYS_SRAM0 OFFSET(4) NUMBITS(1) [],
523
524    CLK_SYS_SPI1 OFFSET(3) NUMBITS(1) [],
525
526    CLK_PERI_SPI1 OFFSET(2) NUMBITS(1) [],
527
528    CLK_SYS_SPI0 OFFSET(1) NUMBITS(1) [],
529
530    CLK_PERI_SPI0 OFFSET(0) NUMBITS(1) []
531],
532SLEEP_EN0 [
533
534    CLK_SYS_SIO OFFSET(31) NUMBITS(1) [],
535
536    CLK_SYS_SHA256 OFFSET(30) NUMBITS(1) [],
537
538    CLK_SYS_PSM OFFSET(29) NUMBITS(1) [],
539
540    CLK_SYS_ROSC OFFSET(28) NUMBITS(1) [],
541
542    CLK_SYS_ROM OFFSET(27) NUMBITS(1) [],
543
544    CLK_SYS_RESETS OFFSET(26) NUMBITS(1) [],
545
546    CLK_SYS_PWM OFFSET(25) NUMBITS(1) [],
547
548    CLK_SYS_POWMAN OFFSET(24) NUMBITS(1) [],
549
550    CLK_REF_POWMAN OFFSET(23) NUMBITS(1) [],
551
552    CLK_SYS_PLL_USB OFFSET(22) NUMBITS(1) [],
553
554    CLK_SYS_PLL_SYS OFFSET(21) NUMBITS(1) [],
555
556    CLK_SYS_PIO2 OFFSET(20) NUMBITS(1) [],
557
558    CLK_SYS_PIO1 OFFSET(19) NUMBITS(1) [],
559
560    CLK_SYS_PIO0 OFFSET(18) NUMBITS(1) [],
561
562    CLK_SYS_PADS OFFSET(17) NUMBITS(1) [],
563
564    CLK_SYS_OTP OFFSET(16) NUMBITS(1) [],
565
566    CLK_REF_OTP OFFSET(15) NUMBITS(1) [],
567
568    CLK_SYS_JTAG OFFSET(14) NUMBITS(1) [],
569
570    CLK_SYS_IO OFFSET(13) NUMBITS(1) [],
571
572    CLK_SYS_I2C1 OFFSET(12) NUMBITS(1) [],
573
574    CLK_SYS_I2C0 OFFSET(11) NUMBITS(1) [],
575
576    CLK_SYS_HSTX OFFSET(10) NUMBITS(1) [],
577
578    CLK_HSTX OFFSET(9) NUMBITS(1) [],
579
580    CLK_SYS_GLITCH_DETECTOR OFFSET(8) NUMBITS(1) [],
581
582    CLK_SYS_DMA OFFSET(7) NUMBITS(1) [],
583
584    CLK_SYS_BUSFABRIC OFFSET(6) NUMBITS(1) [],
585
586    CLK_SYS_BUSCTRL OFFSET(5) NUMBITS(1) [],
587
588    CLK_SYS_BOOTRAM OFFSET(4) NUMBITS(1) [],
589
590    CLK_SYS_ADC OFFSET(3) NUMBITS(1) [],
591
592    CLK_ADC OFFSET(2) NUMBITS(1) [],
593
594    CLK_SYS_ACCESSCTRL OFFSET(1) NUMBITS(1) [],
595
596    CLK_SYS_CLOCKS OFFSET(0) NUMBITS(1) []
597],
598SLEEP_EN1 [
599
600    CLK_SYS_XOSC OFFSET(30) NUMBITS(1) [],
601
602    CLK_SYS_XIP OFFSET(29) NUMBITS(1) [],
603
604    CLK_SYS_WATCHDOG OFFSET(28) NUMBITS(1) [],
605
606    CLK_USB OFFSET(27) NUMBITS(1) [],
607
608    CLK_SYS_USBCTRL OFFSET(26) NUMBITS(1) [],
609
610    CLK_SYS_UART1 OFFSET(25) NUMBITS(1) [],
611
612    CLK_PERI_UART1 OFFSET(24) NUMBITS(1) [],
613
614    CLK_SYS_UART0 OFFSET(23) NUMBITS(1) [],
615
616    CLK_PERI_UART0 OFFSET(22) NUMBITS(1) [],
617
618    CLK_SYS_TRNG OFFSET(21) NUMBITS(1) [],
619
620    CLK_SYS_TIMER1 OFFSET(20) NUMBITS(1) [],
621
622    CLK_SYS_TIMER0 OFFSET(19) NUMBITS(1) [],
623
624    CLK_SYS_TICKS OFFSET(18) NUMBITS(1) [],
625
626    CLK_REF_TICKS OFFSET(17) NUMBITS(1) [],
627
628    CLK_SYS_TBMAN OFFSET(16) NUMBITS(1) [],
629
630    CLK_SYS_SYSINFO OFFSET(15) NUMBITS(1) [],
631
632    CLK_SYS_SYSCFG OFFSET(14) NUMBITS(1) [],
633
634    CLK_SYS_SRAM9 OFFSET(13) NUMBITS(1) [],
635
636    CLK_SYS_SRAM8 OFFSET(12) NUMBITS(1) [],
637
638    CLK_SYS_SRAM7 OFFSET(11) NUMBITS(1) [],
639
640    CLK_SYS_SRAM6 OFFSET(10) NUMBITS(1) [],
641
642    CLK_SYS_SRAM5 OFFSET(9) NUMBITS(1) [],
643
644    CLK_SYS_SRAM4 OFFSET(8) NUMBITS(1) [],
645
646    CLK_SYS_SRAM3 OFFSET(7) NUMBITS(1) [],
647
648    CLK_SYS_SRAM2 OFFSET(6) NUMBITS(1) [],
649
650    CLK_SYS_SRAM1 OFFSET(5) NUMBITS(1) [],
651
652    CLK_SYS_SRAM0 OFFSET(4) NUMBITS(1) [],
653
654    CLK_SYS_SPI1 OFFSET(3) NUMBITS(1) [],
655
656    CLK_PERI_SPI1 OFFSET(2) NUMBITS(1) [],
657
658    CLK_SYS_SPI0 OFFSET(1) NUMBITS(1) [],
659
660    CLK_PERI_SPI0 OFFSET(0) NUMBITS(1) []
661],
662ENABLED0 [
663
664    CLK_SYS_SIO OFFSET(31) NUMBITS(1) [],
665
666    CLK_SYS_SHA256 OFFSET(30) NUMBITS(1) [],
667
668    CLK_SYS_PSM OFFSET(29) NUMBITS(1) [],
669
670    CLK_SYS_ROSC OFFSET(28) NUMBITS(1) [],
671
672    CLK_SYS_ROM OFFSET(27) NUMBITS(1) [],
673
674    CLK_SYS_RESETS OFFSET(26) NUMBITS(1) [],
675
676    CLK_SYS_PWM OFFSET(25) NUMBITS(1) [],
677
678    CLK_SYS_POWMAN OFFSET(24) NUMBITS(1) [],
679
680    CLK_REF_POWMAN OFFSET(23) NUMBITS(1) [],
681
682    CLK_SYS_PLL_USB OFFSET(22) NUMBITS(1) [],
683
684    CLK_SYS_PLL_SYS OFFSET(21) NUMBITS(1) [],
685
686    CLK_SYS_PIO2 OFFSET(20) NUMBITS(1) [],
687
688    CLK_SYS_PIO1 OFFSET(19) NUMBITS(1) [],
689
690    CLK_SYS_PIO0 OFFSET(18) NUMBITS(1) [],
691
692    CLK_SYS_PADS OFFSET(17) NUMBITS(1) [],
693
694    CLK_SYS_OTP OFFSET(16) NUMBITS(1) [],
695
696    CLK_REF_OTP OFFSET(15) NUMBITS(1) [],
697
698    CLK_SYS_JTAG OFFSET(14) NUMBITS(1) [],
699
700    CLK_SYS_IO OFFSET(13) NUMBITS(1) [],
701
702    CLK_SYS_I2C1 OFFSET(12) NUMBITS(1) [],
703
704    CLK_SYS_I2C0 OFFSET(11) NUMBITS(1) [],
705
706    CLK_SYS_HSTX OFFSET(10) NUMBITS(1) [],
707
708    CLK_HSTX OFFSET(9) NUMBITS(1) [],
709
710    CLK_SYS_GLITCH_DETECTOR OFFSET(8) NUMBITS(1) [],
711
712    CLK_SYS_DMA OFFSET(7) NUMBITS(1) [],
713
714    CLK_SYS_BUSFABRIC OFFSET(6) NUMBITS(1) [],
715
716    CLK_SYS_BUSCTRL OFFSET(5) NUMBITS(1) [],
717
718    CLK_SYS_BOOTRAM OFFSET(4) NUMBITS(1) [],
719
720    CLK_SYS_ADC OFFSET(3) NUMBITS(1) [],
721
722    CLK_ADC OFFSET(2) NUMBITS(1) [],
723
724    CLK_SYS_ACCESSCTRL OFFSET(1) NUMBITS(1) [],
725
726    CLK_SYS_CLOCKS OFFSET(0) NUMBITS(1) []
727],
728ENABLED1 [
729
730    CLK_SYS_XOSC OFFSET(30) NUMBITS(1) [],
731
732    CLK_SYS_XIP OFFSET(29) NUMBITS(1) [],
733
734    CLK_SYS_WATCHDOG OFFSET(28) NUMBITS(1) [],
735
736    CLK_USB OFFSET(27) NUMBITS(1) [],
737
738    CLK_SYS_USBCTRL OFFSET(26) NUMBITS(1) [],
739
740    CLK_SYS_UART1 OFFSET(25) NUMBITS(1) [],
741
742    CLK_PERI_UART1 OFFSET(24) NUMBITS(1) [],
743
744    CLK_SYS_UART0 OFFSET(23) NUMBITS(1) [],
745
746    CLK_PERI_UART0 OFFSET(22) NUMBITS(1) [],
747
748    CLK_SYS_TRNG OFFSET(21) NUMBITS(1) [],
749
750    CLK_SYS_TIMER1 OFFSET(20) NUMBITS(1) [],
751
752    CLK_SYS_TIMER0 OFFSET(19) NUMBITS(1) [],
753
754    CLK_SYS_TICKS OFFSET(18) NUMBITS(1) [],
755
756    CLK_REF_TICKS OFFSET(17) NUMBITS(1) [],
757
758    CLK_SYS_TBMAN OFFSET(16) NUMBITS(1) [],
759
760    CLK_SYS_SYSINFO OFFSET(15) NUMBITS(1) [],
761
762    CLK_SYS_SYSCFG OFFSET(14) NUMBITS(1) [],
763
764    CLK_SYS_SRAM9 OFFSET(13) NUMBITS(1) [],
765
766    CLK_SYS_SRAM8 OFFSET(12) NUMBITS(1) [],
767
768    CLK_SYS_SRAM7 OFFSET(11) NUMBITS(1) [],
769
770    CLK_SYS_SRAM6 OFFSET(10) NUMBITS(1) [],
771
772    CLK_SYS_SRAM5 OFFSET(9) NUMBITS(1) [],
773
774    CLK_SYS_SRAM4 OFFSET(8) NUMBITS(1) [],
775
776    CLK_SYS_SRAM3 OFFSET(7) NUMBITS(1) [],
777
778    CLK_SYS_SRAM2 OFFSET(6) NUMBITS(1) [],
779
780    CLK_SYS_SRAM1 OFFSET(5) NUMBITS(1) [],
781
782    CLK_SYS_SRAM0 OFFSET(4) NUMBITS(1) [],
783
784    CLK_SYS_SPI1 OFFSET(3) NUMBITS(1) [],
785
786    CLK_PERI_SPI1 OFFSET(2) NUMBITS(1) [],
787
788    CLK_SYS_SPI0 OFFSET(1) NUMBITS(1) [],
789
790    CLK_PERI_SPI0 OFFSET(0) NUMBITS(1) []
791],
792INTR [
793
794    CLK_SYS_RESUS OFFSET(0) NUMBITS(1) []
795],
796INTE [
797
798    CLK_SYS_RESUS OFFSET(0) NUMBITS(1) []
799],
800INTF [
801
802    CLK_SYS_RESUS OFFSET(0) NUMBITS(1) []
803],
804INTS [
805
806    CLK_SYS_RESUS OFFSET(0) NUMBITS(1) []
807],
808CS [
809    /// PLL is locked
810    LOCK OFFSET(31) NUMBITS(1) [],
811    /// PLL is not locked
812    /// Ideally this is cleared when PLL lock is seen and th
813    LOCK_N OFFSET(30) NUMBITS(1) [],
814    /// Passes the reference clock to the output instead of the divided VCO. The VCO con
815    BYPASS OFFSET(8) NUMBITS(1) [],
816    /// Divides the PLL input reference clock.
817    /// Behaviour is undefined for div=0.
818    /// PLL output will be unpredictable during refdiv chang
819    REFDIV OFFSET(0) NUMBITS(6) []
820],
821PWR [
822    /// PLL VCO powerdown
823    /// To save power set high when PLL output not required
824    VCOPD OFFSET(5) NUMBITS(1) [],
825    /// PLL post divider powerdown
826    /// To save power set high when PLL output not required
827    POSTDIVPD OFFSET(3) NUMBITS(1) [],
828    /// PLL DSM powerdown
829    /// Nothing is achieved by setting this low.
830    DSMPD OFFSET(2) NUMBITS(1) [],
831    /// PLL powerdown
832    /// To save power set high when PLL output not required.
833    PD OFFSET(0) NUMBITS(1) []
834],
835FBDIV_INT [
836    /// see ctrl reg description for constraints
837    FBDIV_INT OFFSET(0) NUMBITS(12) []
838],
839PRIM [
840    /// divide by 1-7
841    POSTDIV1 OFFSET(16) NUMBITS(3) [],
842    /// divide by 1-7
843    POSTDIV2 OFFSET(12) NUMBITS(3) []
844],
845];
846
847#[derive(Copy, Clone, PartialEq, Debug)]
848#[repr(usize)]
849pub enum Clock {
850    GpioOut0 = 0,
851    GpioOut1 = 1,
852    GpioOut2 = 2,
853    GpioOut3 = 3,
854    Reference = 4,
855    System = 5,
856    Peripheral = 6,
857    Hstx = 7,
858    Usb = 8,
859    Adc = 9,
860}
861
862const CLOCKS_BASE: StaticRef<ClocksRegisters> =
863    unsafe { StaticRef::new(0x40010000 as *const ClocksRegisters) };
864const PLL_SYS_BASE: StaticRef<PllRegisters> =
865    unsafe { StaticRef::new(0x40050000 as *const PllRegisters) };
866const PLL_USB_BASE: StaticRef<PllRegisters> =
867    unsafe { StaticRef::new(0x40058000 as *const PllRegisters) };
868
869pub enum PllClock {
870    Sys = 0,
871    Usb = 1,
872}
873
874#[derive(Copy, Clone, PartialEq, Debug)]
875#[repr(u8)]
876pub enum GpioAuxiliaryClockSource {
877    PllSys = 0,
878    Gpio0 = 1,
879    Gpio1 = 2,
880    PllUsb = 3,
881    Rsoc = 4,
882    Xosc = 5,
883    Sys = 6,
884    Usb = 7,
885    Adc = 8,
886    Rtc = 9,
887    Ref = 10,
888}
889
890#[derive(Copy, Clone, PartialEq, Debug)]
891#[repr(u8)]
892pub enum ReferenceClockSource {
893    Rsoc = 0,
894    Auxiliary = 1,
895    Xosc = 2,
896}
897
898#[derive(Copy, Clone, PartialEq, Debug)]
899#[repr(u8)]
900pub enum ReferenceAuxiliaryClockSource {
901    PllUsb = 0,
902    Gpio0 = 1,
903    Gpio1 = 2,
904}
905
906#[derive(Copy, Clone, PartialEq, Debug)]
907#[repr(u8)]
908pub enum SystemClockSource {
909    Reference = 0,
910    Auxiliary = 1,
911}
912
913#[derive(Copy, Clone, PartialEq, Debug)]
914#[repr(u8)]
915pub enum SystemAuxiliaryClockSource {
916    PllSys = 0,
917    PllUsb = 1,
918    Rsoc = 2,
919    Xsoc = 3,
920    Gpio0 = 4,
921    Gpio1 = 5,
922}
923
924#[derive(Copy, Clone, PartialEq, Debug)]
925#[repr(u8)]
926pub enum PeripheralAuxiliaryClockSource {
927    System = 0,
928    PllSys = 1,
929    PllUsb = 2,
930    Rsoc = 3,
931    Xsoc = 4,
932    Gpio0 = 5,
933    Gpio1 = 6,
934}
935
936#[derive(Copy, Clone, PartialEq, Debug)]
937#[repr(u8)]
938pub enum UsbAuxiliaryClockSource {
939    PllSys = 0,
940    PllUsb = 1,
941    Rsoc = 2,
942    Xsoc = 3,
943    Gpio0 = 4,
944    Gpio1 = 5,
945}
946
947#[derive(Copy, Clone, PartialEq, Debug)]
948#[repr(u8)]
949pub enum AdcAuxiliaryClockSource {
950    PllSys = 0,
951    PllUsb = 1,
952    Rsoc = 2,
953    Xsoc = 3,
954    Gpio0 = 4,
955    Gpio1 = 5,
956}
957
958#[derive(Copy, Clone, PartialEq, Debug)]
959#[repr(u8)]
960pub enum HstxAuxiliaryClockSource {
961    PllSys = 0,
962    PllUsb = 1,
963    Rsoc = 2,
964    Xsoc = 3,
965    Gpio0 = 4,
966    Gpio1 = 5,
967}
968
969#[derive(Copy, Clone, PartialEq, Debug)]
970pub enum ClockSource {
971    GpioOut,
972    Reference(ReferenceClockSource),
973    System(SystemClockSource),
974    Peripheral,
975    Usb,
976    Adc,
977    Rtc,
978}
979
980#[derive(Copy, Clone, PartialEq, Debug)]
981pub enum ClockAuxiliarySource {
982    GpioOut(GpioAuxiliaryClockSource),
983    Reference(ReferenceAuxiliaryClockSource),
984    System(SystemAuxiliaryClockSource),
985    Peripheral(PeripheralAuxiliaryClockSource),
986    Usb(UsbAuxiliaryClockSource),
987    Adc(AdcAuxiliaryClockSource),
988    Hstx(HstxAuxiliaryClockSource),
989}
990
991const NUM_CLOCKS: usize = 10;
992
993pub struct Clocks {
994    registers: StaticRef<ClocksRegisters>,
995    pll_registers: &'static [StaticRef<PllRegisters>],
996    frequencies: [Cell<u32>; NUM_CLOCKS],
997}
998
999impl Clocks {
1000    pub const fn new() -> Self {
1001        Self {
1002            registers: CLOCKS_BASE,
1003            pll_registers: &[PLL_SYS_BASE, PLL_USB_BASE],
1004            frequencies: [
1005                Cell::new(0),
1006                Cell::new(0),
1007                Cell::new(0),
1008                Cell::new(0),
1009                Cell::new(0),
1010                Cell::new(0),
1011                Cell::new(0),
1012                Cell::new(0),
1013                Cell::new(0),
1014                Cell::new(0),
1015            ],
1016        }
1017    }
1018
1019    pub fn enable_resus(&self) {
1020        self.registers
1021            .clk_sys_resus_ctrl
1022            .modify(CLK_SYS_RESUS_CTRL::ENABLE::SET);
1023    }
1024
1025    pub fn disable_resus(&self) {
1026        self.registers
1027            .clk_sys_resus_ctrl
1028            .modify(CLK_SYS_RESUS_CTRL::ENABLE::CLEAR);
1029    }
1030
1031    pub fn disable_sys_aux(&self) {
1032        self.registers
1033            .clk_sys_ctrl
1034            .modify(CLK_SYS_CTRL::SRC::Clk_ref);
1035        while self
1036            .registers
1037            .clk_sys_selected
1038            .read(CLK_SYS_SELECTED::CLK_SYS_SELECTED)
1039            != 0x1
1040        {}
1041    }
1042
1043    pub fn disable_ref_aux(&self) {
1044        self.registers
1045            .clk_ref_ctrl
1046            .modify(CLK_REF_CTRL::SRC::Rosc_clksrc_ph);
1047        while self
1048            .registers
1049            .clk_ref_selected
1050            .read(CLK_REF_SELECTED::CLK_REF_SELECTED)
1051            != 0x1
1052        {}
1053    }
1054
1055    pub fn pll_init(
1056        &self,
1057        clock: PllClock,
1058        xosc_freq: u32,
1059        refdiv: u32,
1060        vco_freq: u32,
1061        post_div1: u32,
1062        post_div2: u32,
1063    ) {
1064        let registers = self.pll_registers[clock as usize];
1065
1066        // Turn off PLL
1067        registers
1068            .pwr
1069            .modify(PWR::PD::SET + PWR::DSMPD::SET + PWR::POSTDIVPD::SET + PWR::VCOPD::SET);
1070        registers.fbdiv_int.modify(FBDIV_INT::FBDIV_INT.val(0));
1071
1072        let ref_mhz = xosc_freq / refdiv;
1073        registers.cs.modify(CS::REFDIV.val(refdiv));
1074
1075        // Calculate feedback divider
1076        let fbdiv = vco_freq / (ref_mhz * 1000000);
1077
1078        // Should we use assert instead of if and panic! ?
1079        if fbdiv < 16 || fbdiv > 320 {
1080            panic!("Invalid feedback divider number {} not in [16, 320]", fbdiv)
1081        }
1082
1083        if post_div1 < 1 || post_div1 > 7 || post_div2 < 1 || post_div2 > 7 {
1084            panic!(
1085                "Invalid post_div number {} or {} not in [1, 7]",
1086                post_div1, post_div2
1087            );
1088        }
1089
1090        if post_div2 > post_div1 {
1091            panic!(
1092                "post_div2 must be less than post_div1 ({} >= {})",
1093                post_div1, post_div2
1094            );
1095        }
1096
1097        if ref_mhz > vco_freq / 16 {
1098            panic!(
1099                "ref_mhz must be less than vco_freq / 16 ({} <= {})",
1100                ref_mhz,
1101                vco_freq / 16
1102            );
1103        }
1104
1105        // Set feedback divider
1106        registers.fbdiv_int.modify(FBDIV_INT::FBDIV_INT.val(fbdiv));
1107
1108        // Turn on PLL
1109        registers.pwr.modify(PWR::PD::CLEAR + PWR::VCOPD::CLEAR);
1110
1111        // Wait for PLL to lock
1112        while !registers.cs.is_set(CS::LOCK) {}
1113
1114        // Set up post divider
1115        registers
1116            .prim
1117            .modify(PRIM::POSTDIV1.val(post_div1) + PRIM::POSTDIV2.val(post_div2));
1118
1119        // Turn on post divider
1120        registers.pwr.modify(PWR::POSTDIVPD::CLEAR);
1121    }
1122
1123    pub fn pll_deinit(&self, clock: PllClock) {
1124        self.pll_registers[clock as usize]
1125            .pwr
1126            .modify(PWR::PD::SET + PWR::DSMPD::SET + PWR::POSTDIVPD::SET + PWR::VCOPD::SET);
1127    }
1128
1129    pub fn set_frequency(&self, clock: Clock, freq: u32) {
1130        self.frequencies[clock as usize].set(freq);
1131    }
1132
1133    pub fn get_frequency(&self, clock: Clock) -> u32 {
1134        self.frequencies[clock as usize].get()
1135    }
1136
1137    fn set_divider(&self, clock: Clock, div: u32) {
1138        match clock {
1139            Clock::GpioOut0 | Clock::GpioOut1 | Clock::GpioOut2 | Clock::GpioOut3 => {
1140                self.registers.clk_gpio[clock as usize].div.set(div)
1141            }
1142            Clock::System => self.registers.clk_sys_div.set(div),
1143            Clock::Reference => self.registers.clk_ref_div.set(div),
1144            Clock::Usb => self.registers.clk_usb_div.set(div),
1145            Clock::Adc => self.registers.clk_adc_div.set(div),
1146            Clock::Hstx => self.registers.clk_hstx_div.set(div),
1147            // Clock::Reference
1148            _ => panic!("failed to set div"),
1149        }
1150    }
1151
1152    fn get_divider(&self, source_freq: u32, freq: u32) -> u32 {
1153        // pico-sdk: Div register is 24.8 int.frac divider so multiply by 2^8 (left shift by 8)
1154        (((source_freq as u64) << 16) / freq as u64) as u32
1155    }
1156
1157    #[cfg(any(doc, all(target_arch = "arm", target_os = "none")))]
1158    #[inline]
1159    fn loop_3_cycles(&self, clock: Clock) {
1160        if self.get_frequency(clock) > 0 {
1161            let _delay_cyc: u32 = self.get_frequency(Clock::System) / self.get_frequency(clock) + 1;
1162            unsafe {
1163                use core::arch::asm;
1164                asm! (
1165                    "1:",
1166                    "subs {0}, #1",
1167                    "bne 1b",
1168                    in (reg) _delay_cyc
1169                );
1170            }
1171        }
1172    }
1173
1174    #[cfg(not(any(doc, all(target_arch = "arm", target_os = "none"))))]
1175    fn loop_3_cycles(&self, _clock: Clock) {
1176        unimplemented!()
1177    }
1178
1179    pub fn configure_gpio_out(
1180        &self,
1181        clock: Clock,
1182        auxiliary_source: GpioAuxiliaryClockSource,
1183        source_freq: u32,
1184        freq: u32,
1185    ) {
1186        match clock {
1187            Clock::GpioOut0 | Clock::GpioOut1 | Clock::GpioOut2 | Clock::GpioOut3 => {
1188                if freq > source_freq {
1189                    panic!(
1190                        "freq is greater than source freq ({} > {})",
1191                        freq, source_freq
1192                    );
1193                }
1194
1195                let div = self.get_divider(source_freq, freq);
1196
1197                // pico-sdk:
1198                // If increasing divisor, set divisor before source. Otherwise set source
1199                // before divisor. This avoids a momentary overspeed when e.g. switching
1200                // to a faster source and increasing divisor to compensate.
1201                if div > self.registers.clk_gpio[clock as usize].div.get() {
1202                    self.set_divider(clock, div);
1203                }
1204
1205                self.registers.clk_gpio[clock as usize]
1206                    .ctrl
1207                    .modify(CLK_GPOUTx_CTRL::ENABLE::CLEAR);
1208                // pico-sdk:
1209                // Delay for 3 cycles of the target clock, for ENABLE propagation.
1210                // Note XOSC_COUNT is not helpful here because XOSC is not
1211                // necessarily running, nor is timer... so, 3 cycles per loop:
1212                self.loop_3_cycles(clock);
1213
1214                self.registers.clk_gpio[clock as usize]
1215                    .ctrl
1216                    .modify(CLK_GPOUTx_CTRL::AUXSRC.val(auxiliary_source as u32));
1217
1218                self.registers.clk_gpio[clock as usize]
1219                    .ctrl
1220                    .modify(CLK_GPOUTx_CTRL::ENABLE::SET);
1221
1222                // pico-sdk:
1223                // Now that the source is configured, we can trust that the user-supplied
1224                // divisor is a safe value.
1225                self.set_divider(clock, div);
1226
1227                self.set_frequency(clock, freq);
1228            }
1229            _ => panic!("trying to set a non gpio clock"),
1230        }
1231    }
1232
1233    pub fn configure_system(
1234        &self,
1235        source: SystemClockSource,
1236        auxiliary_source: SystemAuxiliaryClockSource,
1237        source_freq: u32,
1238        freq: u32,
1239    ) {
1240        if freq > source_freq {
1241            panic!(
1242                "freq is greater than source freq ({} > {})",
1243                freq, source_freq
1244            );
1245        }
1246        let div = self.get_divider(source_freq, freq);
1247
1248        // pico-sdk:
1249        // If increasing divisor, set divisor before source. Otherwise set source
1250        // before divisor. This avoids a momentary overspeed when e.g. switching
1251        // to a faster source and increasing divisor to compensate.
1252        if div > self.registers.clk_sys_div.get() {
1253            self.set_divider(Clock::System, div);
1254        }
1255
1256        // pico-sdk:
1257        // If switching a glitchless slice (ref or sys) to an aux source, switch
1258        // away from aux *first* to avoid passing glitches when changing aux mux.
1259        // Assume (!!!) glitchless source 0 is no faster than the aux source.
1260        if source == SystemClockSource::Auxiliary {
1261            self.registers
1262                .clk_sys_ctrl
1263                .modify(CLK_SYS_CTRL::SRC::Clk_ref);
1264            while self
1265                .registers
1266                .clk_sys_selected
1267                .read(CLK_SYS_SELECTED::CLK_SYS_SELECTED)
1268                != 0x1
1269            {}
1270        }
1271
1272        self.registers
1273            .clk_sys_ctrl
1274            .modify(CLK_SYS_CTRL::AUXSRC.val(auxiliary_source as u32));
1275        self.registers
1276            .clk_sys_ctrl
1277            .modify(CLK_SYS_CTRL::SRC.val(source as u32));
1278        while self
1279            .registers
1280            .clk_sys_selected
1281            .read(CLK_SYS_SELECTED::CLK_SYS_SELECTED)
1282            & (1 << (source as u32))
1283            == 0x0
1284        {}
1285
1286        // pico-sdk:
1287        // Now that the source is configured, we can trust that the user-supplied
1288        // divisor is a safe value.
1289        self.set_divider(Clock::System, div);
1290
1291        self.set_frequency(Clock::System, freq);
1292    }
1293
1294    pub fn configure_reference(
1295        &self,
1296        source: ReferenceClockSource,
1297        auxiliary_source: ReferenceAuxiliaryClockSource,
1298        source_freq: u32,
1299        freq: u32,
1300    ) {
1301        if freq > source_freq {
1302            panic!(
1303                "freq is greater than source freq ({} > {})",
1304                freq, source_freq
1305            );
1306        }
1307        let div = self.get_divider(source_freq, freq);
1308
1309        // pico-sdk:
1310        // If increasing divisor, set divisor before source. Otherwise set source
1311        // before divisor. This avoids a momentary overspeed when e.g. switching
1312        // to a faster source and increasing divisor to compensate.
1313        if div > self.registers.clk_ref_div.get() {
1314            self.set_divider(Clock::Reference, div);
1315        }
1316
1317        // pico-sdk:
1318        // If switching a glitchless slice (ref or sys) to an aux source, switch
1319        // away from aux *first* to avoid passing glitches when changing aux mux.
1320        // Assume (!!!) glitchless source 0 is no faster than the aux source.
1321        if source == ReferenceClockSource::Auxiliary {
1322            self.registers
1323                .clk_ref_ctrl
1324                .modify(CLK_REF_CTRL::SRC::Rosc_clksrc_ph);
1325            while self
1326                .registers
1327                .clk_ref_selected
1328                .read(CLK_REF_SELECTED::CLK_REF_SELECTED)
1329                != 0x1
1330            {}
1331        }
1332
1333        self.registers
1334            .clk_ref_ctrl
1335            .modify(CLK_REF_CTRL::AUXSRC.val(auxiliary_source as u32));
1336        self.registers
1337            .clk_ref_ctrl
1338            .modify(CLK_REF_CTRL::SRC.val(source as u32));
1339        while self
1340            .registers
1341            .clk_ref_selected
1342            .read(CLK_REF_SELECTED::CLK_REF_SELECTED)
1343            & (1 << (source as u32))
1344            == 0x0
1345        {}
1346
1347        // pico-sdk:
1348        // Now that the source is configured, we can trust that the user-supplied
1349        // divisor is a safe value.
1350        self.set_divider(Clock::Reference, div);
1351
1352        self.set_frequency(Clock::Reference, freq);
1353    }
1354
1355    pub fn configure_peripheral(
1356        &self,
1357        auxiliary_source: PeripheralAuxiliaryClockSource,
1358        freq: u32,
1359    ) {
1360        self.registers
1361            .clk_peri_ctrl
1362            .modify(CLK_PERI_CTRL::ENABLE::CLEAR);
1363
1364        // pico-sdk:
1365        // Delay for 3 cycles of the target clock, for ENABLE propagation.
1366        // Note XOSC_COUNT is not helpful here because XOSC is not
1367        // necessarily running, nor is timer... so, 3 cycles per loop:
1368        self.loop_3_cycles(Clock::Peripheral);
1369
1370        self.registers
1371            .clk_peri_ctrl
1372            .modify(CLK_PERI_CTRL::AUXSRC.val(auxiliary_source as u32));
1373
1374        self.registers
1375            .clk_peri_ctrl
1376            .modify(CLK_PERI_CTRL::ENABLE::SET);
1377
1378        self.set_frequency(Clock::Peripheral, freq);
1379    }
1380
1381    pub fn configure_usb(
1382        &self,
1383        auxiliary_source: UsbAuxiliaryClockSource,
1384        source_freq: u32,
1385        freq: u32,
1386    ) {
1387        if freq > source_freq {
1388            panic!(
1389                "freq is greater than source freq ({} > {})",
1390                freq, source_freq
1391            );
1392        }
1393        let div = self.get_divider(source_freq, freq);
1394
1395        // pico-sdk:
1396        // If increasing divisor, set divisor before source. Otherwise set source
1397        // before divisor. This avoids a momentary overspeed when e.g. switching
1398        // to a faster source and increasing divisor to compensate.
1399        if div > self.registers.clk_usb_div.get() {
1400            self.set_divider(Clock::Usb, div);
1401        }
1402
1403        self.registers
1404            .clk_usb_ctrl
1405            .modify(CLK_USB_CTRL::ENABLE::CLEAR);
1406        // pico-sdk:
1407        // Delay for 3 cycles of the target clock, for ENABLE propagation.
1408        // Note XOSC_COUNT is not helpful here because XOSC is not
1409        // necessarily running, nor is timer... so, 3 cycles per loop:
1410        self.loop_3_cycles(Clock::Usb);
1411
1412        self.registers
1413            .clk_usb_ctrl
1414            .modify(CLK_USB_CTRL::AUXSRC.val(auxiliary_source as u32));
1415
1416        self.registers
1417            .clk_usb_ctrl
1418            .modify(CLK_USB_CTRL::ENABLE::SET);
1419
1420        // pico-sdk:
1421        // Now that the source is configured, we can trust that the user-supplied
1422        // divisor is a safe value.
1423        self.set_divider(Clock::Usb, div);
1424
1425        self.set_frequency(Clock::Usb, freq);
1426    }
1427
1428    pub fn configure_hstx(
1429        &self,
1430        auxiliary_source: HstxAuxiliaryClockSource,
1431        source_freq: u32,
1432        freq: u32,
1433    ) {
1434        if freq > source_freq {
1435            panic!(
1436                "freq is greater than source freq ({} > {})",
1437                freq, source_freq
1438            );
1439        }
1440        let div = self.get_divider(source_freq, freq);
1441
1442        // pico-sdk:
1443        // If increasing divisor, set divisor before source. Otherwise set source
1444        // before divisor. This avoids a momentary overspeed when e.g. switching
1445        // to a faster source and increasing divisor to compensate.
1446        if div > self.registers.clk_hstx_div.get() {
1447            self.set_divider(Clock::Hstx, div);
1448        }
1449
1450        self.registers
1451            .clk_hstx_ctrl
1452            .modify(CLK_HSTX_CTRL::ENABLE::CLEAR);
1453        // pico-sdk:
1454        // Delay for 3 cycles of the target clock, for ENABLE propagation.
1455        // Note XOSC_COUNT is not helpful here because XOSC is not
1456        // necessarily running, nor is timer... so, 3 cycles per loop:
1457        self.loop_3_cycles(Clock::Hstx);
1458
1459        self.registers
1460            .clk_hstx_ctrl
1461            .modify(CLK_HSTX_CTRL::AUXSRC.val(auxiliary_source as u32));
1462
1463        self.registers
1464            .clk_hstx_ctrl
1465            .modify(CLK_HSTX_CTRL::ENABLE::SET);
1466
1467        // pico-sdk:
1468        // Now that the source is configured, we can trust that the user-supplied
1469        // divisor is a safe value.
1470        self.set_divider(Clock::Hstx, div);
1471
1472        self.set_frequency(Clock::Hstx, freq);
1473    }
1474
1475    pub fn configure_adc(
1476        &self,
1477        auxiliary_source: AdcAuxiliaryClockSource,
1478        source_freq: u32,
1479        freq: u32,
1480    ) {
1481        if freq > source_freq {
1482            panic!(
1483                "freq is greater than source freq ({} > {})",
1484                freq, source_freq
1485            );
1486        }
1487        let div = self.get_divider(source_freq, freq);
1488
1489        // pico-sdk:
1490        // If increasing divisor, set divisor before source. Otherwise set source
1491        // before divisor. This avoids a momentary overspeed when e.g. switching
1492        // to a faster source and increasing divisor to compensate.
1493        if div > self.registers.clk_adc_div.get() {
1494            self.set_divider(Clock::Adc, div);
1495        }
1496
1497        self.registers
1498            .clk_adc_ctrl
1499            .modify(CLK_ADC_CTRL::ENABLE::CLEAR);
1500        // pico-sdk:
1501        // Delay for 3 cycles of the target clock, for ENABLE propagation.
1502        // Note XOSC_COUNT is not helpful here because XOSC is not
1503        // necessarily running, nor is timer... so, 3 cycles per loop:
1504        self.loop_3_cycles(Clock::Adc);
1505
1506        self.registers
1507            .clk_adc_ctrl
1508            .modify(CLK_ADC_CTRL::AUXSRC.val(auxiliary_source as u32));
1509
1510        self.registers
1511            .clk_adc_ctrl
1512            .modify(CLK_ADC_CTRL::ENABLE::SET);
1513
1514        // pico-sdk:
1515        // Now that the source is configured, we can trust that the user-supplied
1516        // divisor is a safe value.
1517        self.set_divider(Clock::Adc, div);
1518
1519        self.set_frequency(Clock::Adc, freq);
1520    }
1521}