1use 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 self.registers.status_w1tc.set(1 << self.pin.shift);
167
168 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 self.registers.func_out_sel_cfg[self.pin.shift].set(0x80);
225
226 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 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 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}