esp32/
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//! GPIO driver.
6
7use core::ops::{Index, IndexMut};
8use kernel::hil::gpio;
9use kernel::utilities::cells::OptionalCell;
10use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
11use kernel::utilities::registers::{
12    register_bitfields, register_structs, Field, ReadWrite, WriteOnly,
13};
14use kernel::utilities::StaticRef;
15
16pub const GPIO_BASE: StaticRef<GpioRegisters> =
17    unsafe { StaticRef::new(0x6000_4000 as *const GpioRegisters) };
18
19pub const IOMUX_BASE: StaticRef<IoMuxRegisters> =
20    unsafe { StaticRef::new(0x6000_9000 as *const IoMuxRegisters) };
21
22register_structs! {
23    pub GpioRegisters {
24        (0x0 => bt_select: ReadWrite<u32>),
25        (0x4 => gpio_out: ReadWrite<u32, pins::Register>),
26        (0x8 => gpio_out_w1ts: WriteOnly<u32, pins::Register>),
27        (0xC => gpio_out_w1tc: WriteOnly<u32, pins::Register>),
28        (0x10 => _reserved0),
29        (0x1C => sdio_select: ReadWrite<u32>),
30        (0x20 => enable: ReadWrite<u32, pins::Register>),
31        (0x24 => enable_w1ts: ReadWrite<u32, pins::Register>),
32        (0x28 => enable_w1tc: ReadWrite<u32, pins::Register>),
33        (0x2C => _reserved1),
34        (0x38 => strap: ReadWrite<u32>),
35        (0x3C => gpio_in: ReadWrite<u32, pins::Register>),
36        (0x40 => _reserved2),
37        (0x44 => status: ReadWrite<u32, pins::Register>),
38        (0x48 => status_w1ts: ReadWrite<u32, pins::Register>),
39        (0x4C => status_w1tc: ReadWrite<u32, pins::Register>),
40        (0x50 => _reserved3),
41        (0x5C => pcpu_int: ReadWrite<u32>),
42        (0x60 => pcpu_nmi_int: ReadWrite<u32>),
43        (0x64 => cpusdio_int: ReadWrite<u32>),
44        (0x68 => _reserved4),
45        (0x74 => pin: [ReadWrite<u32, PIN::Register>; 26]),
46        (0xDC => _reserved5),
47        (0x14C => status_next: ReadWrite<u32>),
48        (0x150 => _reserved6),
49        (0x154 => func_in_sel_cfg: [ReadWrite<u32>; 128]),
50        (0x354 => _reserved7),
51        (0x554 => func_out_sel_cfg: [ReadWrite<u32>; 26]),
52        (0x5BC => _reserved8),
53        (0x62C => clock_gate: ReadWrite<u32>),
54        (0x630 => _reserved9),
55        (0x6FC => date: ReadWrite<u32>),
56        (0x700 => @END),
57    },
58
59    pub IoMuxRegisters {
60        (0x00 => pin_ctrl: ReadWrite<u32>),
61        (0x04 => gpio: [ReadWrite<u32, IO_MUX_GPIO::Register>; 22]),
62        (0x5C => _reserved0),
63        (0xFC => date: ReadWrite<u32>),
64        (0x100 => @END),
65    }
66}
67
68register_bitfields![u32,
69    pub pins [
70        pin0 0,
71        pin1 1,
72        pin2 2,
73        pin3 3,
74        pin4 4,
75        pin5 5,
76        pin6 6,
77        pin7 7,
78        pin8 8,
79        pin9 9,
80        pin10 10,
81        pin11 11,
82        pin12 12,
83        pin13 13,
84        pin14 14,
85        pin15 15,
86        pin16 16,
87        pin17 17,
88        pin18 18,
89        pin19 19,
90        pin20 20,
91        pin21 21,
92        pin22 22,
93        pin23 23,
94        pin24 24,
95        pin25 25
96    ],
97    MASK_HALF [
98        DATA OFFSET(0) NUMBITS(16) [],
99        MASK OFFSET(16) NUMBITS(16) [],
100    ],
101    PIN [
102        INT_ENA OFFSET(13) NUMBITS(5) [
103            Disabled = 0,
104            Enable = 1,
105            NMI = 2,
106        ],
107        CONFIG OFFSET(11) NUMBITS(2) [],
108        WAKEUP_ENABLE OFFSET(10) NUMBITS(1) [],
109        INT_TYPE OFFSET(7) NUMBITS(3) [
110            DISABLE = 0,
111            POSEDGE = 1,
112            NEGEDGE = 2,
113            ANYEDGE = 3,
114            LOW_LEVEL = 4,
115            HIGH_LEVEL = 5,
116        ],
117        SYNC1_BYPASS OFFSET(3) NUMBITS(2) [],
118        PAD_DRIVER OFFSET(2) NUMBITS(1) [],
119        SYNC2_BYPASS OFFSET(0) NUMBITS(2) [],
120    ],
121];
122
123register_bitfields![u32,
124    IO_MUX_GPIO [
125        FILTER_EN OFFSET(15) NUMBITS(1) [],
126        MCU_SEL OFFSET(12) NUMBITS(3) [
127            FUN_0 = 0,
128            FUN_1 = 1,
129            FUN_2 = 2,
130            FUN_3 = 3
131        ],
132        FUN_IE OFFSET(9) NUMBITS(1) [],
133        FUN_WPU OFFSET(8) NUMBITS(1) [],
134        FUN_WPD OFFSET(7) NUMBITS(1) [],
135        MCU_IE OFFSET(4) NUMBITS(1) [],
136        MCU_WPU OFFSET(3) NUMBITS(1) [],
137        MCU_WPD OFFSET(2) NUMBITS(1) [],
138        SLP_SEL OFFSET(1) NUMBITS(1) [],
139        MCU_OE OFFSET(0) NUMBITS(1) [],
140    ],
141];
142
143pub struct GpioPin<'a> {
144    registers: StaticRef<GpioRegisters>,
145    iomux_registers: StaticRef<IoMuxRegisters>,
146    pin: Field<u32, pins::Register>,
147    client: OptionalCell<&'a dyn gpio::Client>,
148}
149
150impl<'a> GpioPin<'a> {
151    pub const fn new(
152        gpio_base: StaticRef<GpioRegisters>,
153        iomux_base: StaticRef<IoMuxRegisters>,
154        pin: Field<u32, pins::Register>,
155    ) -> GpioPin<'a> {
156        GpioPin {
157            registers: gpio_base,
158            iomux_registers: iomux_base,
159            pin,
160            client: OptionalCell::empty(),
161        }
162    }
163
164    fn handle_interrupt(&self) {
165        // Clear the interrupt
166        self.registers.status_w1tc.set(1 << self.pin.shift);
167
168        // Trigger the upcall
169        self.client.map(|client| {
170            client.fired();
171        });
172    }
173}
174
175impl gpio::Configure for GpioPin<'_> {
176    fn configuration(&self) -> gpio::Configuration {
177        if self.registers.enable.is_set(self.pin) {
178            gpio::Configuration::Input
179        } else {
180            gpio::Configuration::InputOutput
181        }
182    }
183
184    fn set_floating_state(&self, mode: gpio::FloatingState) {
185        match mode {
186            gpio::FloatingState::PullUp => {
187                self.iomux_registers.gpio[self.pin.shift]
188                    .modify(IO_MUX_GPIO::FUN_WPU::SET + IO_MUX_GPIO::MCU_WPU::SET);
189                self.iomux_registers.gpio[self.pin.shift]
190                    .modify(IO_MUX_GPIO::FUN_WPD::CLEAR + IO_MUX_GPIO::MCU_WPD::CLEAR);
191            }
192            gpio::FloatingState::PullDown => {
193                self.iomux_registers.gpio[self.pin.shift]
194                    .modify(IO_MUX_GPIO::FUN_WPU::CLEAR + IO_MUX_GPIO::MCU_WPU::CLEAR);
195                self.iomux_registers.gpio[self.pin.shift]
196                    .modify(IO_MUX_GPIO::FUN_WPD::SET + IO_MUX_GPIO::MCU_WPD::SET);
197            }
198            gpio::FloatingState::PullNone => {
199                self.iomux_registers.gpio[self.pin.shift]
200                    .modify(IO_MUX_GPIO::FUN_WPU::CLEAR + IO_MUX_GPIO::MCU_WPU::CLEAR);
201                self.iomux_registers.gpio[self.pin.shift]
202                    .modify(IO_MUX_GPIO::FUN_WPD::CLEAR + IO_MUX_GPIO::MCU_WPD::CLEAR);
203            }
204        }
205    }
206
207    fn floating_state(&self) -> gpio::FloatingState {
208        if self.iomux_registers.gpio[self.pin.shift].is_set(IO_MUX_GPIO::FUN_WPU) {
209            gpio::FloatingState::PullUp
210        } else if self.iomux_registers.gpio[self.pin.shift].is_set(IO_MUX_GPIO::FUN_WPD) {
211            gpio::FloatingState::PullDown
212        } else {
213            gpio::FloatingState::PullNone
214        }
215    }
216
217    fn deactivate_to_low_power(&self) {
218        self.disable_input();
219        self.disable_output();
220    }
221
222    fn make_output(&self) -> gpio::Configuration {
223        // Setting peripheral index 128 causes GPIO_OUT_REG and GPIO_ENABLE_REG to enable for the given pin
224        self.registers.func_out_sel_cfg[self.pin.shift].set(0x80);
225
226        // IO Mux function 1 on all pins is GPIO, no alternate peripherals (see table 5-2 in ESP32 datasheet)
227        self.iomux_registers.gpio[self.pin.shift].modify(IO_MUX_GPIO::MCU_SEL::FUN_1);
228
229        self.registers
230            .enable_w1ts
231            .set(self.pin.mask << self.pin.shift);
232        gpio::Configuration::Output
233    }
234
235    fn disable_output(&self) -> gpio::Configuration {
236        self.registers
237            .enable_w1tc
238            .set(self.pin.mask << self.pin.shift);
239        gpio::Configuration::Input
240    }
241
242    fn make_input(&self) -> gpio::Configuration {
243        self.configuration()
244    }
245
246    fn disable_input(&self) -> gpio::Configuration {
247        /* We can't do this from the GPIO controller.
248         * It does look like the IO Mux is capable of this
249         * though.
250         */
251        gpio::Configuration::Input
252    }
253}
254
255impl gpio::Input for GpioPin<'_> {
256    fn read(&self) -> bool {
257        self.registers.gpio_in.is_set(self.pin)
258    }
259}
260
261impl gpio::Output for GpioPin<'_> {
262    fn toggle(&self) -> bool {
263        let old_state = self.registers.gpio_out.is_set(self.pin);
264        if old_state {
265            self.clear();
266        } else {
267            self.set();
268        }
269        self.registers.gpio_out.is_set(self.pin)
270    }
271
272    fn set(&self) {
273        self.registers
274            .gpio_out_w1ts
275            .set(self.pin.mask << self.pin.shift);
276    }
277
278    fn clear(&self) {
279        self.registers
280            .gpio_out_w1tc
281            .set(self.pin.mask << self.pin.shift);
282    }
283}
284
285impl<'a> gpio::Interrupt<'a> for GpioPin<'a> {
286    fn set_client(&self, client: &'a dyn gpio::Client) {
287        self.client.set(client);
288    }
289
290    fn enable_interrupts(&self, mode: gpio::InterruptEdge) {
291        self.registers.pin[self.pin.shift].modify(PIN::INT_ENA::Enable);
292
293        match mode {
294            gpio::InterruptEdge::RisingEdge => {
295                self.registers.pin[self.pin.shift].modify(PIN::INT_TYPE::POSEDGE);
296            }
297            gpio::InterruptEdge::FallingEdge => {
298                self.registers.pin[self.pin.shift].modify(PIN::INT_TYPE::NEGEDGE);
299            }
300            gpio::InterruptEdge::EitherEdge => {
301                self.registers.pin[self.pin.shift].modify(PIN::INT_TYPE::ANYEDGE);
302            }
303        }
304
305        self.iomux_registers.gpio[self.pin.shift]
306            .write(IO_MUX_GPIO::FUN_IE::SET + IO_MUX_GPIO::MCU_IE::SET);
307
308        self.registers.pin[self.pin.shift].modify(PIN::SYNC2_BYPASS::SET);
309        self.registers.pin[self.pin.shift].modify(PIN::SYNC1_BYPASS::SET);
310
311        self.registers
312            .status_next
313            .set(1 << self.pin.shift | self.registers.status_next.get());
314
315        self.registers.pin[self.pin.shift].modify(PIN::WAKEUP_ENABLE::SET);
316    }
317
318    fn disable_interrupts(&self) {
319        self.registers.pin[self.pin.shift].modify(PIN::INT_ENA::Disabled);
320    }
321
322    fn is_pending(&self) -> bool {
323        self.registers.status.is_set(self.pin)
324    }
325}
326
327pub struct Port<'a> {
328    pins: [GpioPin<'a>; 17],
329}
330
331impl Port<'_> {
332    pub const fn new() -> Self {
333        Self {
334            pins: [
335                GpioPin::new(GPIO_BASE, IOMUX_BASE, pins::pin0),
336                GpioPin::new(GPIO_BASE, IOMUX_BASE, pins::pin1),
337                GpioPin::new(GPIO_BASE, IOMUX_BASE, pins::pin2),
338                GpioPin::new(GPIO_BASE, IOMUX_BASE, pins::pin3),
339                GpioPin::new(GPIO_BASE, IOMUX_BASE, pins::pin4),
340                GpioPin::new(GPIO_BASE, IOMUX_BASE, pins::pin5),
341                GpioPin::new(GPIO_BASE, IOMUX_BASE, pins::pin6),
342                GpioPin::new(GPIO_BASE, IOMUX_BASE, pins::pin7),
343                GpioPin::new(GPIO_BASE, IOMUX_BASE, pins::pin8),
344                GpioPin::new(GPIO_BASE, IOMUX_BASE, pins::pin9),
345                GpioPin::new(GPIO_BASE, IOMUX_BASE, pins::pin10),
346                GpioPin::new(GPIO_BASE, IOMUX_BASE, pins::pin11),
347                GpioPin::new(GPIO_BASE, IOMUX_BASE, pins::pin12),
348                GpioPin::new(GPIO_BASE, IOMUX_BASE, pins::pin13),
349                GpioPin::new(GPIO_BASE, IOMUX_BASE, pins::pin14),
350                GpioPin::new(GPIO_BASE, IOMUX_BASE, pins::pin15),
351                GpioPin::new(GPIO_BASE, IOMUX_BASE, pins::pin16),
352            ],
353        }
354    }
355
356    pub fn handle_interrupt(&self) {
357        // Determine the GPIO pin that triggered.
358        let pin = self.pins[0].registers.status.get().trailing_zeros() as usize;
359
360        self.pins[pin].handle_interrupt();
361    }
362}
363
364impl<'a> Index<usize> for Port<'a> {
365    type Output = GpioPin<'a>;
366
367    fn index(&self, index: usize) -> &GpioPin<'a> {
368        &self.pins[index]
369    }
370}
371
372impl<'a> IndexMut<usize> for Port<'a> {
373    fn index_mut(&mut self, index: usize) -> &mut GpioPin<'a> {
374        &mut self.pins[index]
375    }
376}