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/interrupt_controller.h"
16
17 #include <array>
18 #include <cstdint>
19
20 #include "fsl_pint.h"
21 #include "pw_digital_io/digital_io.h"
22 #include "pw_function/function.h"
23 #include "pw_result/result.h"
24 #include "pw_status/status.h"
25
26 namespace pw::digital_io {
27 namespace {
28
29 using ::pw::digital_io::InterruptTrigger;
30 using ::pw::digital_io::State;
31
32 // PINT API doesn't allow context on callback API, so store globally.
33 std::array<pw::digital_io::InterruptHandler,
34 FSL_FEATURE_PINT_NUMBER_OF_CONNECTED_OUTPUTS>
35 interrupt_handlers;
36 std::array<PINT_Type*, FSL_FEATURE_PINT_NUMBER_OF_CONNECTED_OUTPUTS> bases;
37
PintCallback(pint_pin_int_t pin,uint32_t)38 void PintCallback(pint_pin_int_t pin, uint32_t) {
39 PW_CHECK(pin < interrupt_handlers.size());
40 State state = PINT_PinInterruptGetStatus(bases[pin], pin) == 1
41 ? State::kActive
42 : State::kInactive;
43 interrupt_handlers[pin](state);
44 SDK_ISR_EXIT_BARRIER;
45 }
46
47 } // namespace
48
McuxpressoInterruptController(PINT_Type * base)49 McuxpressoInterruptController::McuxpressoInterruptController(PINT_Type* base)
50 : base_(base) {
51 PINT_Init(base_);
52 }
53
~McuxpressoInterruptController()54 McuxpressoInterruptController::~McuxpressoInterruptController() {
55 PINT_Deinit(base_);
56 }
57
Config(pint_pin_int_t pin,InterruptTrigger trigger,pw::digital_io::InterruptHandler && handler)58 pw::Status McuxpressoInterruptController::Config(
59 pint_pin_int_t pin,
60 InterruptTrigger trigger,
61 pw::digital_io::InterruptHandler&& handler) {
62 if (pin >= interrupt_handlers.size()) {
63 return pw::Status::InvalidArgument();
64 }
65 interrupt_handlers[pin] = std::move(handler);
66 bases[pin] = base_;
67 switch (trigger) {
68 case InterruptTrigger::kActivatingEdge:
69 PINT_PinInterruptConfig(
70 base_, pin, kPINT_PinIntEnableRiseEdge, PintCallback);
71 break;
72 case InterruptTrigger::kDeactivatingEdge:
73 PINT_PinInterruptConfig(
74 base_, pin, kPINT_PinIntEnableFallEdge, PintCallback);
75 break;
76 case InterruptTrigger::kBothEdges:
77 PINT_PinInterruptConfig(
78 base_, pin, kPINT_PinIntEnableBothEdges, PintCallback);
79 break;
80 default:
81 return pw::Status::InvalidArgument();
82 }
83 return pw::OkStatus();
84 }
85
EnableHandler(pint_pin_int_t pin,bool enable)86 pw::Status McuxpressoInterruptController::EnableHandler(pint_pin_int_t pin,
87 bool enable) {
88 if (enable) {
89 PINT_EnableCallbackByIndex(base_, pin);
90 } else {
91 PINT_DisableCallbackByIndex(base_, pin);
92 }
93 return pw::OkStatus();
94 }
95
GetState(pint_pin_int_t pin)96 pw::Result<pw::digital_io::State> McuxpressoInterruptController::GetState(
97 pint_pin_int_t pin) {
98 switch (PINT_PinInterruptGetStatus(base_, pin)) {
99 case 0:
100 return State::kInactive;
101 case 1:
102 return State::kActive;
103 default:
104 return pw::Status::Unknown();
105 }
106 }
107
108 } // namespace pw::digital_io
109