1use 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 (gpio::Configuration::Input, true) => gpio::Configuration::Function,
144 (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 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 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 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}