1use 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 value: ReadOnly<u32, pins::Register>,
17 input_en: ReadWrite<u32, pins::Register>,
19 output_en: ReadWrite<u32, pins::Register>,
21 port: ReadWrite<u32, pins::Register>,
23 pullup: ReadWrite<u32, pins::Register>,
25 drive: ReadWrite<u32, pins::Register>,
27 rise_ie: ReadWrite<u32, pins::Register>,
29 rise_ip: ReadWrite<u32, pins::Register>,
31 fall_ie: ReadWrite<u32, pins::Register>,
33 fall_ip: ReadWrite<u32, pins::Register>,
35 high_ie: ReadWrite<u32, pins::Register>,
37 high_ip: ReadWrite<u32, pins::Register>,
39 low_ie: ReadWrite<u32, pins::Register>,
41 low_ip: ReadWrite<u32, pins::Register>,
43 iof_en: ReadWrite<u32, pins::Register>,
45 iof_sel: ReadWrite<u32, pins::Register>,
47 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 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 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 pub fn handle_interrupt(&self) {
135 let regs = self.registers;
136
137 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}