1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <errno.h>
18 #include <isr.h>
19
20 #include <plat/inc/cmsis.h>
21 #include <plat/inc/exti.h>
22 #include <plat/inc/pwr.h>
23
24 struct StmExti
25 {
26 volatile uint32_t IMR;
27 volatile uint32_t EMR;
28 volatile uint32_t RTSR;
29 volatile uint32_t FTSR;
30 volatile uint32_t SWIER;
31 volatile uint32_t PR;
32 };
33
34 #define EXTI ((struct StmExti*)EXTI_BASE)
35
extiEnableIntLine(const enum ExtiLine line,enum ExtiTrigger trigger)36 void extiEnableIntLine(const enum ExtiLine line, enum ExtiTrigger trigger)
37 {
38 if (trigger == EXTI_TRIGGER_BOTH) {
39 EXTI->RTSR |= (1UL << line);
40 EXTI->FTSR |= (1UL << line);
41 } else if (trigger == EXTI_TRIGGER_RISING) {
42 EXTI->RTSR |= (1UL << line);
43 EXTI->FTSR &= ~(1UL << line);
44 } else if (trigger == EXTI_TRIGGER_FALLING) {
45 EXTI->RTSR &= ~(1UL << line);
46 EXTI->FTSR |= (1UL << line);
47 }
48
49 /* Clear pending interrupt */
50 extiClearPendingLine(line);
51
52 /* Enable hardware interrupt */
53 EXTI->IMR |= (1UL << line);
54 }
55
extiDisableIntLine(const enum ExtiLine line)56 void extiDisableIntLine(const enum ExtiLine line)
57 {
58 EXTI->IMR &= ~(1UL << line);
59 }
60
extiClearPendingLine(const enum ExtiLine line)61 void extiClearPendingLine(const enum ExtiLine line)
62 {
63 EXTI->PR = (1UL << line);
64 }
65
extiIsPendingLine(const enum ExtiLine line)66 bool extiIsPendingLine(const enum ExtiLine line)
67 {
68 return (EXTI->PR & (1UL << line)) ? true : false;
69 }
70
71 struct ExtiInterrupt
72 {
73 struct ChainedInterrupt base;
74 IRQn_Type irq;
75 };
76
extiInterruptEnable(struct ChainedInterrupt * irq)77 static void extiInterruptEnable(struct ChainedInterrupt *irq)
78 {
79 struct ExtiInterrupt *exti = container_of(irq, struct ExtiInterrupt, base);
80 NVIC_EnableIRQ(exti->irq);
81 }
82
extiInterruptDisable(struct ChainedInterrupt * irq)83 static void extiInterruptDisable(struct ChainedInterrupt *irq)
84 {
85 struct ExtiInterrupt *exti = container_of(irq, struct ExtiInterrupt, base);
86 NVIC_DisableIRQ(exti->irq);
87 }
88
89 #define DECLARE_SHARED_EXTI(i) { \
90 .base = { \
91 .enable = extiInterruptEnable, \
92 .disable = extiInterruptDisable, \
93 }, \
94 .irq = i, \
95 }
96
97 static struct ExtiInterrupt gInterrupts[] = {
98 DECLARE_SHARED_EXTI(EXTI0_IRQn),
99 DECLARE_SHARED_EXTI(EXTI1_IRQn),
100 DECLARE_SHARED_EXTI(EXTI2_IRQn),
101 DECLARE_SHARED_EXTI(EXTI3_IRQn),
102 DECLARE_SHARED_EXTI(EXTI4_IRQn),
103 DECLARE_SHARED_EXTI(EXTI9_5_IRQn),
104 DECLARE_SHARED_EXTI(EXTI15_10_IRQn),
105 };
106
extiForIrq(IRQn_Type n)107 static inline struct ExtiInterrupt *extiForIrq(IRQn_Type n)
108 {
109 if (n >= EXTI0_IRQn && n <= EXTI4_IRQn)
110 return &gInterrupts[n - EXTI0_IRQn];
111 if (n == EXTI9_5_IRQn)
112 return &gInterrupts[ARRAY_SIZE(gInterrupts) - 2];
113 if (n == EXTI15_10_IRQn)
114 return &gInterrupts[ARRAY_SIZE(gInterrupts) - 1];
115 return NULL;
116 }
117
extiIrqHandler(IRQn_Type n)118 static void extiIrqHandler(IRQn_Type n)
119 {
120 struct ExtiInterrupt *exti = extiForIrq(n);
121 dispatchIsr(&exti->base);
122 }
123
124 #define DEFINE_SHARED_EXTI_ISR(i) \
125 void EXTI##i##_IRQHandler(void); \
126 void EXTI##i##_IRQHandler(void) { \
127 extiIrqHandler(EXTI##i##_IRQn); \
128 } \
129
130 DEFINE_SHARED_EXTI_ISR(0)
131 DEFINE_SHARED_EXTI_ISR(1)
132 DEFINE_SHARED_EXTI_ISR(2)
133 DEFINE_SHARED_EXTI_ISR(3)
134 DEFINE_SHARED_EXTI_ISR(4)
135 DEFINE_SHARED_EXTI_ISR(9_5)
136 DEFINE_SHARED_EXTI_ISR(15_10)
137
extiChainIsr(IRQn_Type n,struct ChainedIsr * isr)138 int extiChainIsr(IRQn_Type n, struct ChainedIsr *isr)
139 {
140 struct ExtiInterrupt *exti = extiForIrq(n);
141 if (!exti)
142 return -EINVAL;
143
144 chainIsr(&exti->base, isr);
145 return 0;
146 }
147
extiUnchainIsr(IRQn_Type n,struct ChainedIsr * isr)148 int extiUnchainIsr(IRQn_Type n, struct ChainedIsr *isr)
149 {
150 struct ExtiInterrupt *exti = extiForIrq(n);
151 if (!exti)
152 return -EINVAL;
153
154 unchainIsr(&exti->base, isr);
155 return 0;
156 }
157
extiUnchainAll(uint32_t tid)158 int extiUnchainAll(uint32_t tid)
159 {
160 int i, count = 0;
161 struct ExtiInterrupt *exti = gInterrupts;
162
163 for (i = 0; i < ARRAY_SIZE(gInterrupts); ++i, ++exti)
164 count += unchainIsrAll(&exti->base, tid);
165
166 return count;
167 }
168