1#![doc = concat!("## Relation to the ", crate::trm_markdown_link!("iomuxgpio"))]
16# RX line, you will need to make sure
60 one of the signals is frozen, otherwise the driver that is configured later
61 will overwrite the other driver's configuration. Configuring the signals on
62 multiple cores is undefined behaviour unless you ensure the configuration
63 does not happen at the same time."
64)]
65#![cfg_attr(spi_master_driver_supported, doc = "[`Spi::with_mosi`].")]
70#![cfg_attr(not(spi_master_driver_supported), doc = "`Spi::with_mosi`.")]
71#![cfg_attr(
100 spi_master_driver_supported,
101 doc = "[`Spi::with_mosi`]: crate::spi::master::Spi::with_mosi"
102)]
103
104#[cfg(feature = "unstable")]
105use crate::gpio::{Input, Output};
106use crate::{
107 gpio::{
108 self,
109 AlternateFunction,
110 AnyPin,
111 Flex,
112 InputPin,
113 Level,
114 NoPin,
115 OutputPin,
116 Pin,
117 PinGuard,
118 },
119 peripherals::GPIO,
120 private::{self, Sealed},
121};
122
123pub trait PeripheralSignal<'d>: Sealed {
132 #[doc(hidden)] fn connect_input_to_peripheral(&self, signal: gpio::InputSignal);
135}
136
137#[allow(
142 private_bounds,
143 reason = "InputSignal is unstable, but the trait needs to be public"
144)]
145pub trait PeripheralInput<'d>: Into<InputSignal<'d>> + PeripheralSignal<'d> {}
146
147#[allow(
152 private_bounds,
153 reason = "OutputSignal is unstable, but the trait needs to be public"
154)]
155pub trait PeripheralOutput<'d>: Into<OutputSignal<'d>> + PeripheralSignal<'d> {
156 #[doc(hidden)] fn connect_peripheral_to_output(&self, signal: gpio::OutputSignal);
159
160 #[doc(hidden)] fn disconnect_from_peripheral_output(&self);
168}
169
170impl<'d, P> PeripheralSignal<'d> for P
172where
173 P: Pin + 'd,
174{
175 fn connect_input_to_peripheral(&self, signal: gpio::InputSignal) {
176 let pin = unsafe { AnyPin::steal(self.number()) };
177 InputSignal::new(pin).connect_input_to_peripheral(signal);
178 }
179}
180impl<'d, P> PeripheralInput<'d> for P where P: InputPin + 'd {}
181
182impl<'d, P> PeripheralOutput<'d> for P
183where
184 P: OutputPin + 'd,
185{
186 fn connect_peripheral_to_output(&self, signal: gpio::OutputSignal) {
187 let pin = unsafe { AnyPin::steal(self.number()) };
188 OutputSignal::new(pin).connect_peripheral_to_output(signal);
189 }
190 fn disconnect_from_peripheral_output(&self) {
191 let pin = unsafe { AnyPin::steal(self.number()) };
192 OutputSignal::new(pin).disconnect_from_peripheral_output();
193 }
194}
195
196#[instability::unstable]
198impl<'d> PeripheralSignal<'d> for Flex<'d> {
199 fn connect_input_to_peripheral(&self, signal: gpio::InputSignal) {
200 self.pin.connect_input_to_peripheral(signal);
201 }
202}
203#[instability::unstable]
204impl<'d> PeripheralInput<'d> for Flex<'d> {}
205#[instability::unstable]
206impl<'d> PeripheralOutput<'d> for Flex<'d> {
207 fn connect_peripheral_to_output(&self, signal: gpio::OutputSignal) {
208 self.pin.connect_peripheral_to_output(signal);
209 }
210 fn disconnect_from_peripheral_output(&self) {
211 self.pin.disconnect_from_peripheral_output();
212 }
213}
214
215#[instability::unstable]
216impl<'d> PeripheralSignal<'d> for Input<'d> {
217 fn connect_input_to_peripheral(&self, signal: gpio::InputSignal) {
218 self.pin.connect_input_to_peripheral(signal);
219 }
220}
221#[instability::unstable]
222impl<'d> PeripheralInput<'d> for Input<'d> {}
223
224#[instability::unstable]
225impl<'d> PeripheralSignal<'d> for Output<'d> {
226 fn connect_input_to_peripheral(&self, signal: gpio::InputSignal) {
227 self.pin.connect_input_to_peripheral(signal);
228 }
229}
230#[instability::unstable]
231impl<'d> PeripheralOutput<'d> for Output<'d> {
232 fn connect_peripheral_to_output(&self, signal: gpio::OutputSignal) {
233 self.pin.connect_peripheral_to_output(signal);
234 }
235 fn disconnect_from_peripheral_output(&self) {
236 self.pin.disconnect_from_peripheral_output();
237 }
238}
239
240impl PeripheralSignal<'_> for NoPin {
242 fn connect_input_to_peripheral(&self, signal: gpio::InputSignal) {
243 Level::Low.connect_input_to_peripheral(signal);
246 }
247}
248impl PeripheralInput<'_> for NoPin {}
249impl PeripheralOutput<'_> for NoPin {
250 fn connect_peripheral_to_output(&self, _: gpio::OutputSignal) {
251 }
256 fn disconnect_from_peripheral_output(&self) {
257 }
262}
263
264impl PeripheralSignal<'_> for Level {
265 fn connect_input_to_peripheral(&self, signal: gpio::InputSignal) {
266 Signal::Level(*self).connect_to_peripheral_input(signal, false, true);
267 }
268}
269impl PeripheralInput<'_> for Level {}
270impl PeripheralOutput<'_> for Level {
271 fn connect_peripheral_to_output(&self, _: gpio::OutputSignal) {
272 }
275 fn disconnect_from_peripheral_output(&self) {
276 }
279}
280
281impl<'d> PeripheralSignal<'d> for InputSignal<'d> {
283 fn connect_input_to_peripheral(&self, signal: gpio::InputSignal) {
284 self.pin.connect_to_peripheral_input(
288 signal,
289 self.is_input_inverted(),
290 self.is_gpio_matrix_forced(),
291 );
292 }
293}
294impl<'d> PeripheralInput<'d> for InputSignal<'d> {}
295
296impl<'d> PeripheralSignal<'d> for OutputSignal<'d> {
297 fn connect_input_to_peripheral(&self, signal: gpio::InputSignal) {
298 self.pin.connect_to_peripheral_input(
299 signal,
300 self.is_input_inverted(),
301 self.is_gpio_matrix_forced(),
302 );
303 }
304}
305impl<'d> PeripheralOutput<'d> for OutputSignal<'d> {
306 fn connect_peripheral_to_output(&self, signal: gpio::OutputSignal) {
307 self.pin.connect_peripheral_to_output(
308 signal,
309 self.is_output_inverted(),
310 self.is_gpio_matrix_forced(),
311 true,
312 false,
313 );
314 }
315 fn disconnect_from_peripheral_output(&self) {
316 self.pin.disconnect_from_peripheral_output();
317 }
318}
319
320impl gpio::InputSignal {
321 fn can_use_gpio_matrix(self) -> bool {
322 self as usize <= property!("gpio.input_signal_max")
323 }
324
325 #[inline]
337 #[instability::unstable]
338 pub fn connect_to<'a>(self, pin: &impl PeripheralSignal<'a>) {
339 pin.connect_input_to_peripheral(self);
340 }
341}
342
343impl gpio::OutputSignal {
344 fn can_use_gpio_matrix(self) -> bool {
345 self as usize <= property!("gpio.output_signal_max")
346 }
347
348 #[inline]
356 #[instability::unstable]
357 pub fn connect_to<'d>(self, pin: &impl PeripheralOutput<'d>) {
358 pin.connect_peripheral_to_output(self);
359 }
360
361 #[inline]
363 #[instability::unstable]
364 pub fn disconnect_from<'d>(self, pin: &impl PeripheralOutput<'d>) {
365 pin.disconnect_from_peripheral_output();
366 }
367}
368
369enum Signal<'d> {
370 Pin(AnyPin<'d>),
371 Level(Level),
372}
373impl Signal<'_> {
374 fn gpio_number(&self) -> Option<u8> {
375 match &self {
376 Signal::Pin(pin) => Some(pin.number()),
377 Signal::Level(_) => None,
378 }
379 }
380
381 unsafe fn clone_unchecked(&self) -> Self {
382 match self {
383 Signal::Pin(pin) => Signal::Pin(unsafe { pin.clone_unchecked() }),
384 Signal::Level(level) => Signal::Level(*level),
385 }
386 }
387
388 fn is_set_high(&self) -> bool {
389 match &self {
390 Signal::Pin(signal) => signal.is_set_high(),
391 Signal::Level(level) => *level == Level::High,
392 }
393 }
394
395 fn is_input_high(&self) -> bool {
396 match &self {
397 Signal::Pin(signal) => signal.is_input_high(),
398 Signal::Level(level) => *level == Level::High,
399 }
400 }
401
402 fn connect_to_peripheral_input(
403 &self,
404 signal: gpio::InputSignal,
405 is_inverted: bool,
406 force_gpio: bool,
407 ) {
408 let use_gpio_matrix = match self {
409 Signal::Pin(pin) => {
410 let af = if is_inverted || force_gpio {
411 AlternateFunction::GPIO
412 } else {
413 pin.input_signals(private::Internal)
414 .iter()
415 .find(|(_af, s)| *s == signal)
416 .map(|(af, _)| *af)
417 .unwrap_or(AlternateFunction::GPIO)
418 };
419 pin.disable_usb_pads();
420 pin.set_alternate_function(af);
421 af == AlternateFunction::GPIO
422 }
423 Signal::Level(_) => true,
424 };
425
426 if !signal.can_use_gpio_matrix() {
427 assert!(
428 !use_gpio_matrix,
429 "{:?} cannot be routed through the GPIO matrix",
430 signal
431 );
432 return;
435 }
436
437 let input = match self {
438 Signal::Pin(pin) => pin.number(),
439 Signal::Level(Level::Low) => property!("gpio.constant_0_input"),
440 Signal::Level(Level::High) => property!("gpio.constant_1_input"),
441 };
442
443 let offset = property!("gpio.func_in_sel_offset");
445 GPIO::regs()
446 .func_in_sel_cfg(signal as usize - offset)
447 .write(|w| unsafe {
448 w.sel().bit(use_gpio_matrix);
449 w.in_inv_sel().bit(is_inverted);
450 w.in_sel().bits(input)
452 });
453 }
454
455 fn connect_peripheral_to_output(
456 &self,
457 signal: gpio::OutputSignal,
458 is_inverted: bool,
459 force_gpio: bool,
460 peripheral_control_output_enable: bool,
461 invert_output_enable: bool,
462 ) {
463 let Signal::Pin(pin) = self else {
464 return;
465 };
466 let af = if is_inverted || force_gpio {
467 AlternateFunction::GPIO
468 } else {
469 pin.output_signals(private::Internal)
470 .iter()
471 .find(|(_af, s)| *s == signal)
472 .map(|(af, _)| *af)
473 .unwrap_or(AlternateFunction::GPIO)
474 };
475 pin.disable_usb_pads();
476 pin.set_alternate_function(af);
477
478 let use_gpio_matrix = af == AlternateFunction::GPIO;
479
480 assert!(
481 signal.can_use_gpio_matrix() || !use_gpio_matrix,
482 "{:?} cannot be routed through the GPIO matrix",
483 signal
484 );
485
486 GPIO::regs()
487 .func_out_sel_cfg(pin.number() as usize)
488 .write(|w| unsafe {
489 if use_gpio_matrix {
490 w.out_sel().bits(signal as _);
493 w.inv_sel().bit(is_inverted);
494 }
495 w.oen_sel().bit(!peripheral_control_output_enable);
496 w.oen_inv_sel().bit(invert_output_enable)
497 });
498 }
499
500 fn disconnect_from_peripheral_output(&self) {
501 let Some(number) = self.gpio_number() else {
502 return;
503 };
504 GPIO::regs()
505 .func_out_sel_cfg(number as usize)
506 .modify(|_, w| unsafe { w.out_sel().bits(gpio::OutputSignal::GPIO as _) });
507 }
508}
509
510bitflags::bitflags! {
511 #[derive(Clone, Copy)]
512 struct InputFlags: u8 {
513 const ForceGpioMatrix = 1 << 0;
514 const Frozen = 1 << 1;
515 const InvertInput = 1 << 2;
516 }
517}
518
519#[instability::unstable]
528pub struct InputSignal<'d> {
529 pin: Signal<'d>,
530 flags: InputFlags,
531}
532
533impl From<Level> for InputSignal<'_> {
534 fn from(level: Level) -> Self {
535 InputSignal::new_level(level)
536 }
537}
538
539impl From<NoPin> for InputSignal<'_> {
540 fn from(_pin: NoPin) -> Self {
541 InputSignal::new_level(Level::Low)
542 }
543}
544
545impl<'d, P> From<P> for InputSignal<'d>
546where
547 P: Pin + 'd,
548{
549 fn from(input: P) -> Self {
550 InputSignal::new(input.degrade())
551 }
552}
553
554impl<'d> From<Flex<'d>> for InputSignal<'d> {
555 fn from(pin: Flex<'d>) -> Self {
556 pin.peripheral_input()
557 }
558}
559
560#[instability::unstable]
561impl<'d> From<Input<'d>> for InputSignal<'d> {
562 fn from(pin: Input<'d>) -> Self {
563 pin.pin.into()
564 }
565}
566
567impl Sealed for InputSignal<'_> {}
568
569impl Clone for InputSignal<'_> {
570 fn clone(&self) -> Self {
571 Self {
572 pin: unsafe { self.pin.clone_unchecked() },
573 flags: self.flags,
574 }
575 }
576}
577
578impl<'d> InputSignal<'d> {
579 fn new_inner(inner: Signal<'d>) -> Self {
580 Self {
581 pin: inner,
582 flags: InputFlags::empty(),
583 }
584 }
585
586 pub(crate) fn new(pin: AnyPin<'d>) -> Self {
587 Self::new_inner(Signal::Pin(pin))
588 }
589
590 pub(crate) fn new_level(level: Level) -> Self {
591 Self::new_inner(Signal::Level(level))
592 }
593
594 pub fn freeze(mut self) -> Self {
599 self.flags.insert(InputFlags::Frozen);
600 self
601 }
602
603 pub unsafe fn unfreeze(&mut self) {
616 self.flags.remove(InputFlags::Frozen);
617 }
618
619 pub fn gpio_number(&self) -> Option<u8> {
623 self.pin.gpio_number()
624 }
625
626 pub fn is_input_high(&self) -> bool {
630 self.pin.is_input_high()
631 }
632
633 pub fn level(&self) -> Level {
637 self.is_input_high().into()
638 }
639
640 pub fn is_input_inverted(&self) -> bool {
645 self.flags.contains(InputFlags::InvertInput)
646 }
647
648 pub fn with_input_inverter(mut self, invert: bool) -> Self {
651 self.flags.set(InputFlags::InvertInput, invert);
652 self
653 }
654
655 pub fn with_gpio_matrix_forced(mut self, force: bool) -> Self {
658 self.flags.set(InputFlags::ForceGpioMatrix, force);
659 self
660 }
661
662 pub fn is_gpio_matrix_forced(&self) -> bool {
665 self.flags.contains(InputFlags::ForceGpioMatrix)
666 }
667
668 delegate::delegate! {
669 #[instability::unstable]
670 #[doc(hidden)]
671 to match &self.pin {
672 Signal::Pin(signal) => signal,
673 Signal::Level(_) => NoOp,
674 } {
675 pub fn input_signals(&self, _internal: private::Internal) -> &'static [(AlternateFunction, gpio::InputSignal)];
676 }
677 }
678
679 delegate::delegate! {
680 #[instability::unstable]
681 #[doc(hidden)]
682 to match &self.pin {
683 Signal::Pin(_) if self.flags.contains(InputFlags::Frozen) => NoOp,
684 Signal::Pin(signal) => signal,
685 Signal::Level(_) => NoOp,
686 } {
687 pub fn apply_input_config(&self, _config: &gpio::InputConfig);
688 pub fn set_input_enable(&self, on: bool);
689 }
690 }
691}
692
693bitflags::bitflags! {
694 #[derive(Clone, Copy)]
695 struct OutputFlags: u8 {
696 const ForceGpioMatrix = 1 << 0;
697 const Frozen = 1 << 1;
698 const InvertInput = 1 << 2;
699 const InvertOutput = 1 << 3;
700 }
701}
702
703#[instability::unstable]
715pub struct OutputSignal<'d> {
716 pin: Signal<'d>,
717 flags: OutputFlags,
718}
719
720impl Sealed for OutputSignal<'_> {}
721
722impl From<Level> for OutputSignal<'_> {
723 fn from(level: Level) -> Self {
724 OutputSignal::new_level(level)
725 }
726}
727
728impl From<NoPin> for OutputSignal<'_> {
729 fn from(_pin: NoPin) -> Self {
730 OutputSignal::new_level(Level::Low)
731 }
732}
733
734impl<'d, P> From<P> for OutputSignal<'d>
735where
736 P: OutputPin + 'd,
737{
738 fn from(output: P) -> Self {
739 OutputSignal::new(output.degrade())
740 }
741}
742
743impl<'d> From<Flex<'d>> for OutputSignal<'d> {
744 fn from(pin: Flex<'d>) -> Self {
745 pin.into_peripheral_output()
746 }
747}
748
749#[instability::unstable]
750impl<'d> From<Output<'d>> for OutputSignal<'d> {
751 fn from(pin: Output<'d>) -> Self {
752 pin.pin.into()
753 }
754}
755
756impl<'d> OutputSignal<'d> {
757 fn new_inner(inner: Signal<'d>) -> Self {
758 Self {
759 pin: inner,
760 flags: OutputFlags::empty(),
761 }
762 }
763
764 pub(crate) fn new(pin: AnyPin<'d>) -> Self {
765 Self::new_inner(Signal::Pin(pin))
766 }
767
768 pub(crate) fn new_level(level: Level) -> Self {
769 Self::new_inner(Signal::Level(level))
770 }
771
772 pub fn freeze(mut self) -> Self {
777 self.flags.insert(OutputFlags::Frozen);
778 self
779 }
780
781 pub unsafe fn unfreeze(&mut self) {
794 self.flags.remove(OutputFlags::Frozen);
795 }
796
797 pub fn gpio_number(&self) -> Option<u8> {
801 self.pin.gpio_number()
802 }
803
804 pub fn is_input_inverted(&self) -> bool {
809 self.flags.contains(OutputFlags::InvertInput)
810 }
811
812 pub fn is_output_inverted(&self) -> bool {
817 self.flags.contains(OutputFlags::InvertOutput)
818 }
819
820 pub fn with_output_inverter(mut self, invert: bool) -> Self {
823 self.flags.set(OutputFlags::InvertOutput, invert);
824 self
825 }
826
827 pub fn with_input_inverter(mut self, invert: bool) -> Self {
830 self.flags.set(OutputFlags::InvertInput, invert);
831 self
832 }
833
834 pub fn with_gpio_matrix_forced(mut self, force: bool) -> Self {
837 self.flags.set(OutputFlags::ForceGpioMatrix, force);
838 self
839 }
840
841 pub fn is_gpio_matrix_forced(&self) -> bool {
844 self.flags.contains(OutputFlags::ForceGpioMatrix)
845 }
846
847 pub fn is_input_high(&self) -> bool {
851 self.pin.is_input_high()
852 }
853
854 pub fn is_set_high(&self) -> bool {
859 self.pin.is_set_high()
860 }
861
862 #[doc(hidden)]
863 #[instability::unstable]
864 #[cfg_attr(
865 not(any(
866 i2c_master_driver_supported,
867 spi_master_driver_supported,
868 uart_driver_supported
869 )),
870 expect(unused)
871 )]
872 pub(crate) fn connect_with_guard(self, signal: crate::gpio::OutputSignal) -> PinGuard {
873 signal.connect_to(&self);
874 match self.pin {
875 Signal::Pin(pin) => PinGuard::new(pin),
876 Signal::Level(_) => PinGuard::new_unconnected(),
877 }
878 }
879
880 delegate::delegate! {
881 #[instability::unstable]
882 #[doc(hidden)]
883 to match &self.pin {
884 Signal::Pin(signal) => signal,
885 Signal::Level(_) => NoOp,
886 } {
887 pub fn input_signals(&self, _internal: private::Internal) -> &'static [(AlternateFunction, gpio::InputSignal)];
888 pub fn output_signals(&self, _internal: private::Internal) -> &'static [(AlternateFunction, gpio::OutputSignal)];
889 }
890 }
891
892 delegate::delegate! {
893 #[instability::unstable]
894 #[doc(hidden)]
895 to match &self.pin {
896 Signal::Pin(_) if self.flags.contains(OutputFlags::Frozen) => NoOp,
897 Signal::Pin(pin) => pin,
898 Signal::Level(_) => NoOp,
899 } {
900 pub fn apply_input_config(&self, _config: &gpio::InputConfig);
901 pub fn apply_output_config(&self, _config: &gpio::OutputConfig);
902 pub fn set_input_enable(&self, on: bool);
903 pub fn set_output_enable(&self, on: bool);
904 pub fn set_output_high(&self, on: bool);
905 }
906 }
907}
908
909struct NoOp;
910
911impl NoOp {
912 fn set_input_enable(&self, _on: bool) {}
913 fn set_output_enable(&self, _on: bool) {}
914 fn set_output_high(&self, _on: bool) {}
915 fn apply_input_config(&self, _config: &gpio::InputConfig) {}
916 fn apply_output_config(&self, _config: &gpio::OutputConfig) {}
917
918 fn input_signals(
919 &self,
920 _: private::Internal,
921 ) -> &'static [(AlternateFunction, gpio::InputSignal)] {
922 &[]
923 }
924
925 fn output_signals(
926 &self,
927 _: private::Internal,
928 ) -> &'static [(AlternateFunction, gpio::OutputSignal)] {
929 &[]
930 }
931}
932
933#[procmacros::doc_replace]
934fn _compile_tests() {}