1use core::cell::Cell;
73use kernel::hil;
74use kernel::hil::gpio;
75use kernel::hil::gpio_async;
76use kernel::utilities::cells::{OptionalCell, TakeCell};
77use kernel::ErrorCode;
78
79pub const BUFFER_LENGTH: usize = 7;
81
82#[allow(dead_code)]
83#[derive(Debug)]
84enum Registers {
85 IoDir = 0x00,
86 IPol = 0x01,
87 GpIntEn = 0x02,
88 DefVal = 0x03,
89 IntCon = 0x04,
90 IoCon = 0x05,
91 GpPu = 0x06,
92 IntF = 0x07,
93 IntCap = 0x08,
94 Gpio = 0x09,
95 OLat = 0x0a,
96}
97
98#[derive(Clone, Copy, Debug, PartialEq)]
100enum State {
101 Idle,
102
103 SelectIoDir(u8, Direction),
105 ReadIoDir(u8, Direction),
106 SelectIoDirForGpPu(u8, bool),
107 ReadIoDirForGpPu(u8, bool),
108 SetIoDirForGpPu(u8, bool),
109 ReadGpPu(u8, bool),
110 SelectGpio(u8, PinState),
111 ReadGpio(u8, PinState),
112 SelectGpioToggle(u8),
113 ReadGpioToggle(u8),
114 SelectGpioRead(u8),
115 ReadGpioRead(u8),
116 EnableInterruptSettings(u8),
117 ReadInterruptSetup(u8),
118 ReadInterruptValues(u8),
119
120 Done,
122}
123
124#[derive(Clone, Copy, Debug, PartialEq)]
125enum Direction {
126 Input = 0x01,
127 Output = 0x00,
128}
129
130#[derive(Clone, Copy, Debug, PartialEq)]
131enum PinState {
132 High = 0x01,
133 Low = 0x00,
134}
135
136pub struct MCP230xx<'a, I: hil::i2c::I2CDevice> {
137 i2c: &'a I,
138 state: Cell<State>,
139 bank_size: u8, number_of_banks: u8, buffer: TakeCell<'static, [u8]>,
142 interrupt_pin_a: Option<&'a dyn gpio::InterruptValuePin<'a>>,
143 interrupt_pin_b: Option<&'a dyn gpio::InterruptValuePin<'a>>,
144 interrupts_enabled: Cell<u32>, interrupts_mode: Cell<u32>, client: OptionalCell<&'static dyn gpio_async::Client>,
147}
148
149impl<'a, I: hil::i2c::I2CDevice> MCP230xx<'a, I> {
150 pub fn new(
151 i2c: &'a I,
152 interrupt_pin_a: Option<&'a dyn gpio::InterruptValuePin<'a>>,
153 interrupt_pin_b: Option<&'a dyn gpio::InterruptValuePin<'a>>,
154 buffer: &'static mut [u8],
155 bank_size: u8,
156 number_of_banks: u8,
157 ) -> MCP230xx<'a, I> {
158 MCP230xx {
159 i2c,
160 state: Cell::new(State::Idle),
161 bank_size,
162 number_of_banks,
163 buffer: TakeCell::new(buffer),
164 interrupt_pin_a,
165 interrupt_pin_b,
166 interrupts_enabled: Cell::new(0),
167 interrupts_mode: Cell::new(0),
168 client: OptionalCell::empty(),
169 }
170 }
171
172 pub fn set_client<C: gpio_async::Client>(&self, client: &'static C) {
176 self.client.set(client);
177 }
178
179 fn enable_host_interrupt(&self) -> Result<(), ErrorCode> {
180 let first = self
184 .interrupt_pin_a
185 .map_or(Err(ErrorCode::FAIL), |interrupt_pin| {
186 interrupt_pin.make_input();
187 let _ = interrupt_pin.enable_interrupts(gpio::InterruptEdge::RisingEdge);
188 Ok(())
189 });
190 if first != Ok(()) {
191 return first;
192 }
193 self.interrupt_pin_b.map(|interrupt_pin| {
195 interrupt_pin.make_input();
196 let _ = interrupt_pin.enable_interrupts(gpio::InterruptEdge::RisingEdge);
197 });
198 Ok(())
199 }
200
201 fn calc_register_addr(&self, register: Registers, pin_number: u8) -> u8 {
211 if self.number_of_banks == 1 {
212 pin_number
213 } else {
214 let offset = pin_number / self.bank_size;
216 (register as u8 * self.number_of_banks) + offset
219 }
220 }
221
222 fn set_direction(&self, pin_number: u8, direction: Direction) -> Result<(), ErrorCode> {
223 self.buffer.take().map_or(Err(ErrorCode::BUSY), |buffer| {
224 self.i2c.enable();
225
226 buffer[0] = self.calc_register_addr(Registers::IoDir, pin_number);
227 let _ = self.i2c.write(buffer, 1);
229 self.state.set(State::SelectIoDir(pin_number, direction));
230
231 Ok(())
232 })
233 }
234
235 fn configure_pullup(&self, pin_number: u8, enabled: bool) -> Result<(), ErrorCode> {
237 self.buffer.take().map_or(Err(ErrorCode::BUSY), |buffer| {
238 self.i2c.enable();
239
240 buffer[0] = self.calc_register_addr(Registers::IoDir, pin_number);
241 let _ = self.i2c.write(buffer, 1);
243 self.state
244 .set(State::SelectIoDirForGpPu(pin_number, enabled));
245
246 Ok(())
247 })
248 }
249
250 fn set_pin(&self, pin_number: u8, value: PinState) -> Result<(), ErrorCode> {
251 self.buffer.take().map_or(Err(ErrorCode::BUSY), |buffer| {
252 self.i2c.enable();
253
254 buffer[0] = self.calc_register_addr(Registers::Gpio, pin_number);
255 let _ = self.i2c.write(buffer, 1);
257 self.state.set(State::SelectGpio(pin_number, value));
258
259 Ok(())
260 })
261 }
262
263 fn toggle_pin(&self, pin_number: u8) -> Result<(), ErrorCode> {
264 self.buffer.take().map_or(Err(ErrorCode::BUSY), |buffer| {
265 self.i2c.enable();
266
267 buffer[0] = self.calc_register_addr(Registers::Gpio, pin_number);
268 let _ = self.i2c.write(buffer, 1);
270 self.state.set(State::SelectGpioToggle(pin_number));
271
272 Ok(())
273 })
274 }
275
276 fn read_pin(&self, pin_number: u8) -> Result<(), ErrorCode> {
277 self.buffer.take().map_or(Err(ErrorCode::BUSY), |buffer| {
278 self.i2c.enable();
279
280 buffer[0] = self.calc_register_addr(Registers::Gpio, pin_number);
281 let _ = self.i2c.write(buffer, 1);
283 self.state.set(State::SelectGpioRead(pin_number));
284
285 Ok(())
286 })
287 }
288
289 fn enable_interrupt_pin(
290 &self,
291 pin_number: u8,
292 direction: gpio::InterruptEdge,
293 ) -> Result<(), ErrorCode> {
294 self.buffer.take().map_or(Err(ErrorCode::BUSY), |buffer| {
295 self.i2c.enable();
296
297 self.save_pin_interrupt_state(pin_number, true, direction);
304
305 buffer[0] = self.calc_register_addr(Registers::IntCon, 0);
307 let mut i: usize = 1;
309 for _ in 0..(self.number_of_banks as usize) {
310 buffer[i] = 0; i += 1;
312 }
313 buffer[i] = 0b00000010; let _ = self.i2c.write(buffer, i + 1);
318 self.state.set(State::EnableInterruptSettings(pin_number));
319
320 Ok(())
321 })
322 }
323
324 fn disable_interrupt_pin(&self, pin_number: u8) -> Result<(), ErrorCode> {
325 self.buffer.take().map_or(Err(ErrorCode::BUSY), |buffer| {
326 self.i2c.enable();
327
328 self.remove_pin_interrupt_state(pin_number);
330
331 buffer[0] = self.calc_register_addr(Registers::GpIntEn, pin_number);
333 buffer[1] = self.get_pin_interrupt_enabled_state(pin_number);
334 let _ = self.i2c.write(buffer, 2);
336 self.state.set(State::Done);
337
338 Ok(())
339 })
340 }
341
342 fn save_pin_interrupt_state(
345 &self,
346 pin_number: u8,
347 enabled: bool,
348 direction: gpio::InterruptEdge,
349 ) {
350 let mut current_enabled = self.interrupts_enabled.get();
352 current_enabled &= !(1 << pin_number);
354 current_enabled |= (enabled as u32) << pin_number;
356 self.interrupts_enabled.set(current_enabled);
357
358 let mut current_mode = self.interrupts_mode.get();
360 current_mode &= !(0x03 << (2 * pin_number));
362 let new_settings = (direction as u32) & 0x03;
364 current_mode |= new_settings << (2 * pin_number);
366 self.interrupts_mode.set(current_mode);
367 }
368
369 fn remove_pin_interrupt_state(&self, pin_number: u8) {
370 let new_enabled = self.interrupts_enabled.get() & !(1 << pin_number);
371 self.interrupts_enabled.set(new_enabled);
372 let new_mode = self.interrupts_mode.get() & !(0x03 << (2 * pin_number));
373 self.interrupts_mode.set(new_mode);
374 }
375
376 fn get_pin_interrupt_enabled_state(&self, pin_number: u8) -> u8 {
378 let offset = (pin_number / self.bank_size) * self.bank_size;
379 let interrupts_enabled = self.interrupts_enabled.get();
380 (interrupts_enabled >> offset) as u8
381 }
382
383 fn check_pin_interrupt_enabled(&self, pin_number: u8) -> bool {
384 (self.interrupts_enabled.get() >> pin_number) & 0x01 == 0x01
385 }
386
387 fn get_pin_interrupt_direction(&self, pin_number: u8) -> gpio::InterruptEdge {
388 let direction = self.interrupts_mode.get() >> (pin_number * 2) & 0x03;
389 match direction {
390 0 => gpio::InterruptEdge::RisingEdge,
391 1 => gpio::InterruptEdge::FallingEdge,
392 _ => gpio::InterruptEdge::EitherEdge,
393 }
394 }
395}
396
397impl<I: hil::i2c::I2CDevice> hil::i2c::I2CClient for MCP230xx<'_, I> {
398 fn command_complete(&self, buffer: &'static mut [u8], _status: Result<(), hil::i2c::Error>) {
399 match self.state.get() {
400 State::SelectIoDir(pin_number, direction) => {
401 let _ = self.i2c.read(buffer, 1);
403 self.state.set(State::ReadIoDir(pin_number, direction));
404 }
405 State::ReadIoDir(pin_number, direction) => {
406 if direction == Direction::Input {
407 buffer[1] = buffer[0] | (1 << pin_number);
408 } else {
409 buffer[1] = buffer[0] & !(1 << pin_number);
410 }
411 buffer[0] = self.calc_register_addr(Registers::IoDir, pin_number);
412 let _ = self.i2c.write(buffer, 2);
414 self.state.set(State::Done);
415 }
416 State::SelectIoDirForGpPu(pin_number, enabled) => {
417 let _ = self.i2c.read(buffer, 1);
419 self.state.set(State::ReadIoDirForGpPu(pin_number, enabled));
420 }
421 State::ReadIoDirForGpPu(pin_number, enabled) => {
422 buffer[1] = buffer[0] | (1 << pin_number);
424 buffer[0] = self.calc_register_addr(Registers::IoDir, pin_number);
425 let _ = self.i2c.write(buffer, 2);
427 self.state.set(State::SetIoDirForGpPu(pin_number, enabled));
428 }
429 State::SetIoDirForGpPu(pin_number, enabled) => {
430 buffer[0] = self.calc_register_addr(Registers::GpPu, pin_number);
431 let _ = self.i2c.write(buffer, 1);
433 self.state.set(State::ReadGpPu(pin_number, enabled));
434 }
435 State::ReadGpPu(pin_number, enabled) => {
436 let pullup = match enabled {
438 true => buffer[0] | (1 << pin_number),
439 false => buffer[0] & !(1 << pin_number),
440 };
441 buffer[0] = self.calc_register_addr(Registers::GpPu, pin_number);
442 buffer[1] = pullup;
443 let _ = self.i2c.write(buffer, 2);
445 self.state.set(State::Done);
446 }
447 State::SelectGpio(pin_number, value) => {
448 let _ = self.i2c.read(buffer, 1);
450 self.state.set(State::ReadGpio(pin_number, value));
451 }
452 State::ReadGpio(pin_number, value) => {
453 buffer[1] = match value {
454 PinState::High => buffer[0] | (1 << pin_number),
455 PinState::Low => buffer[0] & !(1 << pin_number),
456 };
457 buffer[0] = self.calc_register_addr(Registers::Gpio, pin_number);
458 let _ = self.i2c.write(buffer, 2);
460 self.state.set(State::Done);
461 }
462 State::SelectGpioToggle(pin_number) => {
463 let _ = self.i2c.read(buffer, 1);
465 self.state.set(State::ReadGpioToggle(pin_number));
466 }
467 State::ReadGpioToggle(pin_number) => {
468 buffer[1] = buffer[0] ^ (1 << pin_number);
469 buffer[0] = self.calc_register_addr(Registers::Gpio, pin_number);
470 let _ = self.i2c.write(buffer, 2);
472 self.state.set(State::Done);
473 }
474 State::SelectGpioRead(pin_number) => {
475 let _ = self.i2c.read(buffer, 1);
477 self.state.set(State::ReadGpioRead(pin_number));
478 }
479 State::ReadGpioRead(pin_number) => {
480 let pin_value = (buffer[0] >> pin_number) & 0x01;
481
482 self.client.map(|client| {
483 client.done(pin_value as usize);
484 });
485
486 self.buffer.replace(buffer);
487 self.i2c.disable();
488 self.state.set(State::Idle);
489 }
490 State::EnableInterruptSettings(pin_number) => {
491 buffer[0] = self.calc_register_addr(Registers::GpIntEn, pin_number);
494 buffer[1] = self.get_pin_interrupt_enabled_state(pin_number);
495 let _ = self.i2c.write(buffer, 2);
497 self.state.set(State::Done);
498 }
499 State::ReadInterruptSetup(bank_number) => {
500 let _ = self.i2c.read(buffer, 3);
503 self.state.set(State::ReadInterruptValues(bank_number));
504 }
505 State::ReadInterruptValues(bank_number) => {
506 let interrupt_flags = buffer[0];
507 let pins_status = buffer[2];
508 for i in 0..8 {
510 let pin_number = i + (bank_number * self.bank_size);
513 if !self.check_pin_interrupt_enabled(pin_number) {
515 continue;
516 }
517 if (interrupt_flags >> i) & 0x01 == 0x01 {
518 let pin_status = (pins_status >> i) & 0x01;
521 let interrupt_direction = self.get_pin_interrupt_direction(pin_number);
522 let fire_interrupt = match interrupt_direction {
525 gpio::InterruptEdge::EitherEdge => true,
526 gpio::InterruptEdge::RisingEdge => pin_status == 0x01,
527 gpio::InterruptEdge::FallingEdge => pin_status == 0x00,
528 };
529 if fire_interrupt {
530 self.client.map(|client| {
532 client.fired(pin_number as usize, 0);
536 });
537 break;
538 }
539 }
540 }
541 self.buffer.replace(buffer);
542 self.i2c.disable();
543 self.state.set(State::Idle);
544 }
545 State::Done => {
546 self.client.map(|client| {
547 client.done(0);
548 });
549
550 self.buffer.replace(buffer);
551 self.i2c.disable();
552 self.state.set(State::Idle);
553 }
554 _ => {}
555 }
556 }
557}
558
559impl<I: hil::i2c::I2CDevice> gpio::ClientWithValue for MCP230xx<'_, I> {
560 fn fired(&self, value: u32) {
561 if value < 2 {
562 return; }
564 self.buffer.take().map(|buffer| {
565 let bank_number = value;
566 self.i2c.enable();
567
568 buffer[0] =
571 self.calc_register_addr(Registers::IntF, bank_number as u8 * self.bank_size);
572 let _ = self.i2c.write(buffer, 1);
574 self.state.set(State::ReadInterruptSetup(bank_number as u8));
575 });
576 }
577}
578
579impl<I: hil::i2c::I2CDevice> gpio_async::Port for MCP230xx<'_, I> {
580 fn disable(&self, pin: usize) -> Result<(), ErrorCode> {
581 self.set_direction(pin as u8, Direction::Input)
583 }
584
585 fn make_output(&self, pin: usize) -> Result<(), ErrorCode> {
586 if pin > ((self.number_of_banks * self.bank_size) - 1) as usize {
587 return Err(ErrorCode::INVAL);
588 }
589 self.set_direction(pin as u8, Direction::Output)
590 }
591
592 fn make_input(&self, pin: usize, mode: gpio::FloatingState) -> Result<(), ErrorCode> {
593 if pin > ((self.number_of_banks * self.bank_size) - 1) as usize {
594 return Err(ErrorCode::INVAL);
595 }
596 match mode {
597 gpio::FloatingState::PullUp => self.configure_pullup(pin as u8, true),
598 gpio::FloatingState::PullDown => {
599 self.configure_pullup(pin as u8, false)
601 }
602 gpio::FloatingState::PullNone => self.configure_pullup(pin as u8, false),
603 }
604 }
605
606 fn read(&self, pin: usize) -> Result<(), ErrorCode> {
607 if pin > ((self.number_of_banks * self.bank_size) - 1) as usize {
608 return Err(ErrorCode::INVAL);
609 }
610 self.read_pin(pin as u8)
611 }
612
613 fn toggle(&self, pin: usize) -> Result<(), ErrorCode> {
614 if pin > ((self.number_of_banks * self.bank_size) - 1) as usize {
615 return Err(ErrorCode::INVAL);
616 }
617 self.toggle_pin(pin as u8)
618 }
619
620 fn set(&self, pin: usize) -> Result<(), ErrorCode> {
621 if pin > ((self.number_of_banks * self.bank_size) - 1) as usize {
622 return Err(ErrorCode::INVAL);
623 }
624 self.set_pin(pin as u8, PinState::High)
625 }
626
627 fn clear(&self, pin: usize) -> Result<(), ErrorCode> {
628 if pin > ((self.number_of_banks * self.bank_size) - 1) as usize {
629 return Err(ErrorCode::INVAL);
630 }
631 self.set_pin(pin as u8, PinState::Low)
632 }
633
634 fn enable_interrupt(&self, pin: usize, mode: gpio::InterruptEdge) -> Result<(), ErrorCode> {
635 if pin > ((self.number_of_banks * self.bank_size) - 1) as usize {
636 return Err(ErrorCode::INVAL);
637 }
638 let ret = self.enable_host_interrupt();
639 match ret {
640 Ok(()) => self.enable_interrupt_pin(pin as u8, mode),
641 _ => ret,
642 }
643 }
644
645 fn disable_interrupt(&self, pin: usize) -> Result<(), ErrorCode> {
646 if pin > ((self.number_of_banks * self.bank_size) - 1) as usize {
647 return Err(ErrorCode::INVAL);
648 }
649 self.disable_interrupt_pin(pin as u8)
650 }
651
652 fn is_pending(&self, _pin: usize) -> bool {
653 false
654 }
655}