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