lowrisc/
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::gpio;
8use kernel::utilities::cells::OptionalCell;
9use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
10use kernel::utilities::registers::{
11    register_bitfields, register_structs, Field, ReadOnly, ReadWrite, WriteOnly,
12};
13use kernel::utilities::StaticRef;
14
15register_structs! {
16    pub GpioRegisters {
17        (0x00 => intr_state: ReadWrite<u32, pins::Register>),
18        (0x04 => intr_enable: ReadWrite<u32, pins::Register>),
19        (0x08 => intr_test: WriteOnly<u32, pins::Register>),
20        (0x0c => alert_test: ReadOnly<u32>),
21        (0x10 => data_in: ReadOnly<u32, pins::Register>),
22        (0x14 => direct_out: ReadWrite<u32, pins::Register>),
23        (0x18 => masked_out_lower: ReadWrite<u32, mask_half::Register>),
24        (0x1c => masked_out_upper: ReadWrite<u32, mask_half::Register>),
25        (0x20 => direct_oe: ReadWrite<u32, pins::Register>),
26        (0x24 => masked_oe_lower: ReadWrite<u32, mask_half::Register>),
27        (0x28 => masked_oe_upper: ReadWrite<u32, mask_half::Register>),
28        (0x2c => intr_ctrl_en_rising: ReadWrite<u32, pins::Register>),
29        (0x30 => intr_ctrl_en_falling: ReadWrite<u32, pins::Register>),
30        (0x34 => intr_ctrl_en_lvlhigh: ReadWrite<u32, pins::Register>),
31        (0x38 => intr_ctrl_en_lvllow: ReadWrite<u32, pins::Register>),
32        (0x3c => ctrl_en_input_filter: ReadWrite<u32, pins::Register>),
33        (0x40 => @END),
34    }
35}
36
37register_bitfields![u32,
38    pub pins [
39        pin0 0,
40        pin1 1,
41        pin2 2,
42        pin3 3,
43        pin4 4,
44        pin5 5,
45        pin6 6,
46        pin7 7,
47        pin8 8,
48        pin9 9,
49        pin10 10,
50        pin11 11,
51        pin12 12,
52        pin13 13,
53        pin14 14,
54        pin15 15,
55        pin16 16,
56        pin17 17,
57        pin18 18,
58        pin19 19,
59        pin20 20,
60        pin21 21,
61        pin22 22,
62        pin23 23,
63        pin24 24,
64        pin25 25,
65        pin26 26,
66        pin27 27,
67        pin28 28,
68        pin29 29,
69        pin30 30,
70        pin31 31
71    ],
72    mask_half [
73        data OFFSET(0) NUMBITS(16) [],
74        mask OFFSET(16) NUMBITS(16) []
75    ]
76];
77
78pub type GpioBitfield = Field<u32, pins::Register>;
79
80pub struct GpioPin<'a, PAD> {
81    gpio_registers: StaticRef<GpioRegisters>,
82    padctl: PAD,
83    pin: Field<u32, pins::Register>,
84    client: OptionalCell<&'a dyn gpio::Client>,
85}
86
87impl<'a, PAD> GpioPin<'a, PAD> {
88    pub const fn new(
89        gpio_base: StaticRef<GpioRegisters>,
90        padctl: PAD,
91        pin: Field<u32, pins::Register>,
92    ) -> GpioPin<'a, PAD> {
93        GpioPin {
94            gpio_registers: gpio_base,
95            padctl,
96            pin,
97            client: OptionalCell::empty(),
98        }
99    }
100
101    #[inline(always)]
102    fn half_set(
103        val: bool,
104        field: Field<u32, pins::Register>,
105        lower: &ReadWrite<u32, mask_half::Register>,
106        upper: &ReadWrite<u32, mask_half::Register>,
107    ) {
108        let shift = field.shift;
109        let bit = u32::from(val);
110        if shift < 16 {
111            lower.write(mask_half::data.val(bit << shift) + mask_half::mask.val(1u32 << shift));
112        } else {
113            let upper_shift = shift - 16;
114            upper.write(
115                mask_half::data.val(bit << upper_shift) + mask_half::mask.val(1u32 << upper_shift),
116            );
117        }
118    }
119
120    pub fn handle_interrupt(&self) {
121        let pin = self.pin;
122
123        if self.gpio_registers.intr_state.is_set(pin) {
124            self.gpio_registers.intr_state.modify(pin.val(1));
125            self.client.map(|client| {
126                client.fired();
127            });
128        }
129    }
130}
131
132impl<PAD: gpio::Configure> gpio::Configure for GpioPin<'_, PAD> {
133    fn configuration(&self) -> gpio::Configuration {
134        match (
135            self.padctl.configuration(),
136            self.gpio_registers.direct_oe.is_set(self.pin),
137        ) {
138            (gpio::Configuration::InputOutput, true) => gpio::Configuration::InputOutput,
139            (gpio::Configuration::InputOutput, false) => gpio::Configuration::Input,
140            (gpio::Configuration::Input, false) => gpio::Configuration::Input,
141            // This is configuration error we can't enable ouput
142            // for GPIO pin connect to input only pad.
143            (gpio::Configuration::Input, true) => gpio::Configuration::Function,
144            // We curently dont support output only GPIO
145            // OT register have only output_enable flag.
146            (gpio::Configuration::Output, _) => gpio::Configuration::Function,
147            (conf, _) => conf,
148        }
149    }
150
151    fn set_floating_state(&self, mode: gpio::FloatingState) {
152        self.padctl.set_floating_state(mode);
153    }
154
155    fn floating_state(&self) -> gpio::FloatingState {
156        self.padctl.floating_state()
157    }
158
159    fn deactivate_to_low_power(&self) {
160        self.disable_input();
161        self.disable_output();
162        self.padctl.deactivate_to_low_power();
163    }
164
165    fn make_output(&self) -> gpio::Configuration {
166        // Re-connect in case we make output after switching from LowPower state.
167        if let gpio::Configuration::InputOutput = self.padctl.make_output() {
168            Self::half_set(
169                true,
170                self.pin,
171                &self.gpio_registers.masked_oe_lower,
172                &self.gpio_registers.masked_oe_upper,
173            );
174        }
175        self.configuration()
176    }
177
178    fn disable_output(&self) -> gpio::Configuration {
179        Self::half_set(
180            false,
181            self.pin,
182            &self.gpio_registers.masked_oe_lower,
183            &self.gpio_registers.masked_oe_upper,
184        );
185        self.configuration()
186    }
187
188    fn make_input(&self) -> gpio::Configuration {
189        // Re-connect in case we make input after switching from LowPower state.
190        self.padctl.make_input();
191        self.configuration()
192    }
193
194    fn disable_input(&self) -> gpio::Configuration {
195        self.configuration()
196    }
197}
198
199impl<PAD> gpio::Input for GpioPin<'_, PAD> {
200    fn read(&self) -> bool {
201        self.gpio_registers.data_in.is_set(self.pin)
202    }
203}
204
205impl<PAD> gpio::Output for GpioPin<'_, PAD> {
206    fn toggle(&self) -> bool {
207        let pin = self.pin;
208        let new_state = !self.gpio_registers.direct_out.is_set(pin);
209
210        Self::half_set(
211            new_state,
212            self.pin,
213            &self.gpio_registers.masked_out_lower,
214            &self.gpio_registers.masked_out_upper,
215        );
216        new_state
217    }
218
219    fn set(&self) {
220        Self::half_set(
221            true,
222            self.pin,
223            &self.gpio_registers.masked_out_lower,
224            &self.gpio_registers.masked_out_upper,
225        );
226    }
227
228    fn clear(&self) {
229        Self::half_set(
230            false,
231            self.pin,
232            &self.gpio_registers.masked_out_lower,
233            &self.gpio_registers.masked_out_upper,
234        );
235    }
236}
237
238impl<'a, PAD> gpio::Interrupt<'a> for GpioPin<'a, PAD> {
239    fn set_client(&self, client: &'a dyn gpio::Client) {
240        self.client.set(client);
241    }
242
243    fn enable_interrupts(&self, mode: gpio::InterruptEdge) {
244        let pin = self.pin;
245
246        match mode {
247            gpio::InterruptEdge::RisingEdge => {
248                self.gpio_registers.intr_ctrl_en_rising.modify(pin.val(1));
249                self.gpio_registers.intr_ctrl_en_falling.modify(pin.val(0));
250            }
251            gpio::InterruptEdge::FallingEdge => {
252                self.gpio_registers.intr_ctrl_en_rising.modify(pin.val(0));
253                self.gpio_registers.intr_ctrl_en_falling.modify(pin.val(1));
254            }
255            gpio::InterruptEdge::EitherEdge => {
256                self.gpio_registers.intr_ctrl_en_rising.modify(pin.val(1));
257                self.gpio_registers.intr_ctrl_en_falling.modify(pin.val(1));
258            }
259        }
260        self.gpio_registers.intr_state.modify(pin.val(1));
261        self.gpio_registers.intr_enable.modify(pin.val(1));
262    }
263
264    fn disable_interrupts(&self) {
265        let pin = self.pin;
266
267        self.gpio_registers.intr_enable.modify(pin.val(0));
268        // Clear any pending interrupt
269        self.gpio_registers.intr_state.modify(pin.val(1));
270    }
271
272    fn is_pending(&self) -> bool {
273        self.gpio_registers.intr_state.is_set(self.pin)
274    }
275}