sifive/
gpio.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
5//! General Purpose Input/Output driver.
6
7use kernel::hil;
8use kernel::utilities::cells::OptionalCell;
9use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
10use kernel::utilities::registers::{register_bitfields, Field, FieldValue, ReadOnly, ReadWrite};
11use kernel::utilities::StaticRef;
12
13#[repr(C)]
14pub struct GpioRegisters {
15    /// Pin value.
16    value: ReadOnly<u32, pins::Register>,
17    /// Pin Input Enable Register
18    input_en: ReadWrite<u32, pins::Register>,
19    /// Pin Output Enable Register
20    output_en: ReadWrite<u32, pins::Register>,
21    /// Output Port Value Register
22    port: ReadWrite<u32, pins::Register>,
23    /// Internal Pull-Up Enable Register
24    pullup: ReadWrite<u32, pins::Register>,
25    /// Drive Strength Register
26    drive: ReadWrite<u32, pins::Register>,
27    /// Rise Interrupt Enable Register
28    rise_ie: ReadWrite<u32, pins::Register>,
29    /// Rise Interrupt Pending Register
30    rise_ip: ReadWrite<u32, pins::Register>,
31    /// Fall Interrupt Enable Register
32    fall_ie: ReadWrite<u32, pins::Register>,
33    /// Fall Interrupt Pending Register
34    fall_ip: ReadWrite<u32, pins::Register>,
35    /// High Interrupt Enable Register
36    high_ie: ReadWrite<u32, pins::Register>,
37    /// High Interrupt Pending Register
38    high_ip: ReadWrite<u32, pins::Register>,
39    /// Low Interrupt Enable Register
40    low_ie: ReadWrite<u32, pins::Register>,
41    /// Low Interrupt Pending Register
42    low_ip: ReadWrite<u32, pins::Register>,
43    /// HW I/O Function Enable Register
44    iof_en: ReadWrite<u32, pins::Register>,
45    /// HW I/O Function Select Register
46    iof_sel: ReadWrite<u32, pins::Register>,
47    /// Output XOR (invert) Register
48    out_xor: ReadWrite<u32, pins::Register>,
49}
50
51register_bitfields![u32,
52    pub pins [
53        pin0 0,
54        pin1 1,
55        pin2 2,
56        pin3 3,
57        pin4 4,
58        pin5 5,
59        pin6 6,
60        pin7 7,
61        pin8 8,
62        pin9 9,
63        pin10 10,
64        pin11 11,
65        pin12 12,
66        pin13 13,
67        pin14 14,
68        pin15 15,
69        pin16 16,
70        pin17 17,
71        pin18 18,
72        pin19 19,
73        pin20 20,
74        pin21 21,
75        pin22 22,
76        pin23 23,
77        pin24 24,
78        pin25 25,
79        pin26 26,
80        pin27 27,
81        pin28 28,
82        pin29 29,
83        pin30 30,
84        pin31 31
85    ]
86];
87
88pub struct GpioPin<'a> {
89    registers: StaticRef<GpioRegisters>,
90    pin: Field<u32, pins::Register>,
91    set: FieldValue<u32, pins::Register>,
92    clear: FieldValue<u32, pins::Register>,
93    client: OptionalCell<&'a dyn hil::gpio::Client>,
94}
95
96impl<'a> GpioPin<'a> {
97    pub const fn new(
98        base: StaticRef<GpioRegisters>,
99        pin: Field<u32, pins::Register>,
100        set: FieldValue<u32, pins::Register>,
101        clear: FieldValue<u32, pins::Register>,
102    ) -> GpioPin<'a> {
103        GpioPin {
104            registers: base,
105            pin,
106            set,
107            clear,
108            client: OptionalCell::empty(),
109        }
110    }
111
112    /// Configure this pin as IO Function 0. What that maps to is chip- and pin-
113    /// specific.
114    pub fn iof0(&self) {
115        let regs = self.registers;
116
117        regs.out_xor.modify(self.clear);
118        regs.iof_sel.modify(self.clear);
119        regs.iof_en.modify(self.set);
120    }
121
122    /// Configure this pin as IO Function 1. What that maps to is chip- and pin-
123    /// specific.
124    pub fn iof1(&self) {
125        let regs = self.registers;
126
127        regs.out_xor.modify(self.clear);
128        regs.iof_sel.modify(self.set);
129        regs.iof_en.modify(self.set);
130    }
131
132    /// There are separate interrupts in PLIC for each pin, so the interrupt
133    /// handler only needs to exist on each pin.
134    pub fn handle_interrupt(&self) {
135        let regs = self.registers;
136
137        // Clear the pending GPIO interrupt.
138        regs.rise_ip.modify(self.set);
139        regs.fall_ip.modify(self.set);
140        regs.high_ip.modify(self.set);
141        regs.low_ip.modify(self.set);
142
143        self.client.map(|client| {
144            client.fired();
145        });
146    }
147}
148
149impl hil::gpio::Configure for GpioPin<'_> {
150    fn configuration(&self) -> hil::gpio::Configuration {
151        let regs = self.registers;
152
153        if regs.iof_en.is_set(self.pin) {
154            return hil::gpio::Configuration::Function;
155        }
156
157        let output = regs.output_en.is_set(self.pin);
158        let input = regs.output_en.is_set(self.pin);
159
160        match (input, output) {
161            (true, true) => hil::gpio::Configuration::InputOutput,
162            (true, false) => hil::gpio::Configuration::Input,
163            (false, true) => hil::gpio::Configuration::Output,
164            (false, false) => hil::gpio::Configuration::LowPower,
165        }
166    }
167
168    fn set_floating_state(&self, mode: hil::gpio::FloatingState) {
169        let regs = self.registers;
170
171        match mode {
172            hil::gpio::FloatingState::PullUp => {
173                regs.pullup.modify(self.set);
174            }
175            hil::gpio::FloatingState::PullDown => {
176                regs.pullup.modify(self.clear);
177            }
178            hil::gpio::FloatingState::PullNone => {
179                regs.pullup.modify(self.clear);
180            }
181        }
182    }
183
184    fn floating_state(&self) -> hil::gpio::FloatingState {
185        let regs = self.registers;
186        if regs.pullup.is_set(self.pin) {
187            hil::gpio::FloatingState::PullUp
188        } else {
189            hil::gpio::FloatingState::PullDown
190        }
191    }
192
193    fn deactivate_to_low_power(&self) {
194        self.disable_input();
195        self.disable_output();
196    }
197
198    fn make_output(&self) -> hil::gpio::Configuration {
199        let regs = self.registers;
200
201        regs.drive.modify(self.clear);
202        regs.out_xor.modify(self.clear);
203        regs.output_en.modify(self.set);
204        regs.iof_en.modify(self.clear);
205
206        self.configuration()
207    }
208
209    fn disable_output(&self) -> hil::gpio::Configuration {
210        let regs = self.registers;
211        regs.output_en.modify(self.clear);
212        self.configuration()
213    }
214
215    fn make_input(&self) -> hil::gpio::Configuration {
216        let regs = self.registers;
217
218        regs.input_en.modify(self.set);
219        regs.iof_en.modify(self.clear);
220
221        self.configuration()
222    }
223
224    fn disable_input(&self) -> hil::gpio::Configuration {
225        let regs = self.registers;
226        regs.input_en.modify(self.clear);
227        self.configuration()
228    }
229}
230
231impl hil::gpio::Input for GpioPin<'_> {
232    fn read(&self) -> bool {
233        let regs = self.registers;
234
235        regs.value.is_set(self.pin)
236    }
237}
238
239impl hil::gpio::Output for GpioPin<'_> {
240    fn toggle(&self) -> bool {
241        let regs = self.registers;
242
243        let current_outputs = regs.port.extract();
244        if current_outputs.is_set(self.pin) {
245            regs.port.modify_no_read(current_outputs, self.clear);
246        } else {
247            regs.port.modify_no_read(current_outputs, self.set);
248        }
249        regs.port.extract().is_set(self.pin)
250    }
251
252    fn set(&self) {
253        let regs = self.registers;
254
255        regs.port.modify(self.set);
256    }
257
258    fn clear(&self) {
259        let regs = self.registers;
260
261        regs.port.modify(self.clear);
262    }
263}
264
265impl<'a> hil::gpio::Interrupt<'a> for GpioPin<'a> {
266    fn set_client(&self, client: &'a dyn hil::gpio::Client) {
267        self.client.set(client);
268    }
269
270    fn enable_interrupts(&self, mode: hil::gpio::InterruptEdge) {
271        let regs = self.registers;
272
273        regs.pullup.modify(self.clear);
274        regs.input_en.modify(self.set);
275        regs.iof_en.modify(self.clear);
276
277        match mode {
278            hil::gpio::InterruptEdge::RisingEdge => {
279                regs.rise_ie.modify(self.set);
280            }
281            hil::gpio::InterruptEdge::FallingEdge => {
282                regs.fall_ie.modify(self.set);
283            }
284            hil::gpio::InterruptEdge::EitherEdge => {
285                regs.rise_ie.modify(self.set);
286                regs.fall_ie.modify(self.set);
287            }
288        }
289    }
290
291    fn disable_interrupts(&self) {
292        let regs = self.registers;
293
294        regs.rise_ie.modify(self.clear);
295        regs.fall_ie.modify(self.clear);
296    }
297
298    fn is_pending(&self) -> bool {
299        let regs = self.registers;
300
301        regs.rise_ip.is_set(self.pin) || regs.fall_ip.is_set(self.pin)
302    }
303}