1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
//! Pin configuration
// This module is only intended to be used internally, hence the semver
// exemption. It probably should be in a HAL crate, but there's no HAL crate
// for RZ/A1.
#![cfg(feature = "semver-exempt")]

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum AltMode {
    Gpio,
    Alt1,
    Alt2,
    Alt3,
    Alt4,
    Alt5,
    Alt6,
    Alt7,
    Alt8,
}

pub type Pin = (u8, u8);

pub trait GpioExt {
    /// Configure the alternate function mode of the specified pin.
    fn set_alt_mode(&self, pin: Pin, mode: AltMode) -> &Self;

    /// Configure the specified pin for output.
    fn set_output(&self, pin: Pin) -> &Self;

    /// Configure the specified pin for input.
    fn set_input(&self, pin: Pin) -> &Self;
}

unsafe fn set_bit16(reg: *mut u16, bit: u8) {
    unsafe { reg.write_volatile(reg.read_volatile() | (1u16 << bit)) };
}

unsafe fn clear_bit16(reg: *mut u16, bit: u8) {
    unsafe { reg.write_volatile(reg.read_volatile() & !(1u16 << bit)) };
}

#[inline]
fn panic_if_pin_is_invalid((n, m): Pin) {
    assert!((1..12).contains(&n), "1 <= {n} < 12");
    assert!(m < 16, "0 <= {m} < 16");
}

impl GpioExt for rza1::gpio::RegisterBlock {
    #[inline]
    fn set_alt_mode(&self, (n, m): Pin, mode: AltMode) -> &Self {
        panic_if_pin_is_invalid((n, m));

        let pmc = (&self.pmc1 as *const _ as *mut u16).wrapping_add((n - 1) as usize * 2);
        let pfcae = (&self.pfcae1 as *const _ as *mut u16).wrapping_add((n - 1) as usize * 2);
        let pfce = (&self.pfce1 as *const _ as *mut u16).wrapping_add((n - 1) as usize * 2);
        let pfc = (&self.pfc1 as *const _ as *mut u16).wrapping_add((n - 1) as usize * 2);

        unsafe {
            match mode {
                AltMode::Gpio => {
                    clear_bit16(pmc, m);
                }
                AltMode::Alt1 => {
                    set_bit16(pmc, m);
                    clear_bit16(pfcae, m);
                    clear_bit16(pfce, m);
                    clear_bit16(pfc, m);
                }
                AltMode::Alt2 => {
                    set_bit16(pmc, m);
                    clear_bit16(pfcae, m);
                    clear_bit16(pfce, m);
                    set_bit16(pfc, m);
                }
                AltMode::Alt3 => {
                    set_bit16(pmc, m);
                    clear_bit16(pfcae, m);
                    set_bit16(pfce, m);
                    clear_bit16(pfc, m);
                }
                AltMode::Alt4 => {
                    set_bit16(pmc, m);
                    clear_bit16(pfcae, m);
                    set_bit16(pfce, m);
                    set_bit16(pfc, m);
                }
                AltMode::Alt5 => {
                    set_bit16(pmc, m);
                    set_bit16(pfcae, m);
                    clear_bit16(pfce, m);
                    clear_bit16(pfc, m);
                }
                AltMode::Alt6 => {
                    set_bit16(pmc, m);
                    set_bit16(pfcae, m);
                    clear_bit16(pfce, m);
                    set_bit16(pfc, m);
                }
                AltMode::Alt7 => {
                    set_bit16(pmc, m);
                    set_bit16(pfcae, m);
                    set_bit16(pfce, m);
                    clear_bit16(pfc, m);
                }
                AltMode::Alt8 => {
                    set_bit16(pmc, m);
                    set_bit16(pfcae, m);
                    set_bit16(pfce, m);
                    set_bit16(pfc, m);
                }
            }
        }
        self
    }

    #[inline]
    fn set_output(&self, (n, m): Pin) -> &Self {
        panic_if_pin_is_invalid((n, m));
        let pm = (&self.pm1 as *const _ as *mut u16).wrapping_add((n - 1) as usize * 2);
        unsafe { clear_bit16(pm, m) };
        self
    }

    #[inline]
    fn set_input(&self, (n, m): Pin) -> &Self {
        panic_if_pin_is_invalid((n, m));
        let pm = (&self.pm1 as *const _ as *mut u16).wrapping_add((n - 1) as usize * 2);
        unsafe { set_bit16(pm, m) };
        self
    }
}