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