1 // Copyright 2023 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 #include "pw_digital_io_mcuxpresso/pint.h"
16
17 #include <array>
18 #include <cstdint>
19
20 #include "fsl_pint.h"
21 #include "pw_function/function.h"
22
23 namespace pw::digital_io {
24 namespace {
25
26 using ::pw::digital_io::InterruptTrigger;
27 using ::pw::digital_io::State;
28
29 // PINT API doesn't allow context on callback API, so store globally.
30 std::array<pw::digital_io::InterruptHandler,
31 FSL_FEATURE_PINT_NUMBER_OF_CONNECTED_OUTPUTS>
32 interrupt_handlers;
33 std::array<PINT_Type*, FSL_FEATURE_PINT_NUMBER_OF_CONNECTED_OUTPUTS> bases;
34
PintCallback(pint_pin_int_t pin,uint32_t)35 void PintCallback(pint_pin_int_t pin, uint32_t) {
36 PW_CHECK(pin < interrupt_handlers.size());
37 State state = PINT_PinInterruptGetStatus(bases[pin], pin) == 1
38 ? State::kActive
39 : State::kInactive;
40 interrupt_handlers[pin](state);
41 SDK_ISR_EXIT_BARRIER;
42 }
43
44 } // namespace
45
46 // McuxpressoPintController
47
McuxpressoPintController(PINT_Type * base)48 McuxpressoPintController::McuxpressoPintController(PINT_Type* base)
49 : base_(base) {
50 PINT_Init(base_);
51 }
52
~McuxpressoPintController()53 McuxpressoPintController::~McuxpressoPintController() { PINT_Deinit(base_); }
54
Config(pint_pin_int_t pin,InterruptTrigger trigger,pw::digital_io::InterruptHandler && handler)55 pw::Status McuxpressoPintController::Config(
56 pint_pin_int_t pin,
57 InterruptTrigger trigger,
58 pw::digital_io::InterruptHandler&& handler) {
59 if (pin >= interrupt_handlers.size()) {
60 return pw::Status::InvalidArgument();
61 }
62 interrupt_handlers[pin] = std::move(handler);
63 bases[pin] = base_;
64 switch (trigger) {
65 case InterruptTrigger::kActivatingEdge:
66 PINT_PinInterruptConfig(
67 base_, pin, kPINT_PinIntEnableRiseEdge, PintCallback);
68 break;
69 case InterruptTrigger::kDeactivatingEdge:
70 PINT_PinInterruptConfig(
71 base_, pin, kPINT_PinIntEnableFallEdge, PintCallback);
72 break;
73 case InterruptTrigger::kBothEdges:
74 PINT_PinInterruptConfig(
75 base_, pin, kPINT_PinIntEnableBothEdges, PintCallback);
76 break;
77 default:
78 return pw::Status::InvalidArgument();
79 }
80 return pw::OkStatus();
81 }
82
EnableHandler(pint_pin_int_t pin,bool enable)83 pw::Status McuxpressoPintController::EnableHandler(pint_pin_int_t pin,
84 bool enable) {
85 if (enable) {
86 PINT_EnableCallbackByIndex(base_, pin);
87 } else {
88 PINT_DisableCallbackByIndex(base_, pin);
89 }
90 return pw::OkStatus();
91 }
92
93 // McuxpressoPintInterrupt
94
McuxpressoPintInterrupt(pw::sync::Borrowable<McuxpressoPintController> & controller,pint_pin_int_t pin)95 McuxpressoPintInterrupt::McuxpressoPintInterrupt(
96 pw::sync::Borrowable<McuxpressoPintController>& controller,
97 pint_pin_int_t pin)
98 : controller_(controller), pin_(pin) {}
99
DoEnable(bool)100 pw::Status McuxpressoPintInterrupt::DoEnable(bool) {
101 // Can not enabled at individual line level. Only at controller level, which
102 // is always enabled.
103 return pw::OkStatus();
104 }
105
DoSetInterruptHandler(pw::digital_io::InterruptTrigger trigger,pw::digital_io::InterruptHandler && handler)106 pw::Status McuxpressoPintInterrupt::DoSetInterruptHandler(
107 pw::digital_io::InterruptTrigger trigger,
108 pw::digital_io::InterruptHandler&& handler) {
109 return controller_.acquire()->Config(pin_, trigger, std::move(handler));
110 }
111
DoEnableInterruptHandler(bool enable)112 pw::Status McuxpressoPintInterrupt::DoEnableInterruptHandler(bool enable) {
113 return controller_.acquire()->EnableHandler(pin_, enable);
114 }
115
116 } // namespace pw::digital_io
117