Home | History | Annotate | Download | only in stm32
      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 #include <platform.h>
     20 
     21 #include <plat/cmsis.h>
     22 #include <plat/exti.h>
     23 #include <plat/pwr.h>
     24 
     25 struct StmExti
     26 {
     27     volatile uint32_t IMR;
     28     volatile uint32_t EMR;
     29     volatile uint32_t RTSR;
     30     volatile uint32_t FTSR;
     31     volatile uint32_t SWIER;
     32     volatile uint32_t PR;
     33 };
     34 
     35 #define EXTI ((struct StmExti*)EXTI_BASE)
     36 
     37 void extiEnableIntLine(const enum ExtiLine line, enum ExtiTrigger trigger)
     38 {
     39     if (trigger == EXTI_TRIGGER_BOTH) {
     40         EXTI->RTSR |= (1UL << line);
     41         EXTI->FTSR |= (1UL << line);
     42     } else if (trigger == EXTI_TRIGGER_RISING) {
     43         EXTI->RTSR |= (1UL << line);
     44         EXTI->FTSR &= ~(1UL << line);
     45     } else if (trigger == EXTI_TRIGGER_FALLING) {
     46         EXTI->RTSR &= ~(1UL << line);
     47         EXTI->FTSR |= (1UL << line);
     48     }
     49 
     50     /* Clear pending interrupt */
     51     extiClearPendingLine(line);
     52 
     53     /* Enable hardware interrupt */
     54     EXTI->IMR |= (1UL << line);
     55 }
     56 
     57 void extiDisableIntLine(const enum ExtiLine line)
     58 {
     59     EXTI->IMR &= ~(1UL << line);
     60 }
     61 
     62 void extiClearPendingLine(const enum ExtiLine line)
     63 {
     64     EXTI->PR = (1UL << line);
     65 }
     66 
     67 bool extiIsPendingLine(const enum ExtiLine line)
     68 {
     69     return (EXTI->PR & (1UL << line)) ? true : false;
     70 }
     71 
     72 struct ExtiInterrupt
     73 {
     74     struct ChainedInterrupt base;
     75     IRQn_Type irq;
     76 };
     77 
     78 static void extiInterruptEnable(struct ChainedInterrupt *irq)
     79 {
     80     struct ExtiInterrupt *exti = container_of(irq, struct ExtiInterrupt, base);
     81     NVIC_EnableIRQ(exti->irq);
     82 }
     83 
     84 static void extiInterruptDisable(struct ChainedInterrupt *irq)
     85 {
     86     struct ExtiInterrupt *exti = container_of(irq, struct ExtiInterrupt, base);
     87     NVIC_DisableIRQ(exti->irq);
     88 }
     89 
     90 #define DECLARE_SHARED_EXTI(i) {            \
     91     .base = {                               \
     92         .enable = extiInterruptEnable,      \
     93         .disable = extiInterruptDisable,    \
     94     },                                      \
     95     .irq = i,                               \
     96 }
     97 
     98 uint32_t mMaxLatency = 0;
     99 
    100 static struct ExtiInterrupt mInterrupts[] = {
    101     DECLARE_SHARED_EXTI(EXTI0_IRQn),
    102     DECLARE_SHARED_EXTI(EXTI1_IRQn),
    103     DECLARE_SHARED_EXTI(EXTI2_IRQn),
    104     DECLARE_SHARED_EXTI(EXTI3_IRQn),
    105     DECLARE_SHARED_EXTI(EXTI4_IRQn),
    106     DECLARE_SHARED_EXTI(EXTI9_5_IRQn),
    107     DECLARE_SHARED_EXTI(EXTI15_10_IRQn),
    108 };
    109 
    110 static void extiUpdateMaxLatency(uint32_t maxLatencyNs)
    111 {
    112     if (!maxLatencyNs && mMaxLatency)
    113         platReleaseDevInSleepMode(Stm32sleepDevExti);
    114     else if (maxLatencyNs && !mMaxLatency)
    115         platRequestDevInSleepMode(Stm32sleepDevExti, maxLatencyNs);
    116     else if (maxLatencyNs && mMaxLatency)
    117         platAdjustDevInSleepMode(Stm32sleepDevExti, maxLatencyNs);
    118     mMaxLatency = maxLatencyNs;
    119 }
    120 
    121 static void extiCalcMaxLatency()
    122 {
    123     int i;
    124     uint32_t maxLatency, newMaxLatency = 0;
    125     struct ExtiInterrupt *exti = mInterrupts;
    126 
    127     for (i = 0; i < ARRAY_SIZE(mInterrupts); ++i, ++exti) {
    128         maxLatency = maxLatencyIsr(&exti->base);
    129         if (!newMaxLatency || (maxLatency && maxLatency < newMaxLatency))
    130             newMaxLatency = maxLatency;
    131     }
    132     extiUpdateMaxLatency(newMaxLatency);
    133 }
    134 
    135 static inline struct ExtiInterrupt *extiForIrq(IRQn_Type n)
    136 {
    137     if (n >= EXTI0_IRQn && n <= EXTI4_IRQn)
    138         return &mInterrupts[n - EXTI0_IRQn];
    139     if (n == EXTI9_5_IRQn)
    140         return &mInterrupts[ARRAY_SIZE(mInterrupts) - 2];
    141     if (n == EXTI15_10_IRQn)
    142         return &mInterrupts[ARRAY_SIZE(mInterrupts) - 1];
    143     return NULL;
    144 }
    145 
    146 static void extiIrqHandler(IRQn_Type n)
    147 {
    148     struct ExtiInterrupt *exti = extiForIrq(n);
    149     dispatchIsr(&exti->base);
    150 }
    151 
    152 #define DEFINE_SHARED_EXTI_ISR(i)           \
    153     void EXTI##i##_IRQHandler(void);        \
    154     void EXTI##i##_IRQHandler(void) {       \
    155         extiIrqHandler(EXTI##i##_IRQn);     \
    156     }                                       \
    157 
    158 DEFINE_SHARED_EXTI_ISR(0)
    159 DEFINE_SHARED_EXTI_ISR(1)
    160 DEFINE_SHARED_EXTI_ISR(2)
    161 DEFINE_SHARED_EXTI_ISR(3)
    162 DEFINE_SHARED_EXTI_ISR(4)
    163 DEFINE_SHARED_EXTI_ISR(9_5)
    164 DEFINE_SHARED_EXTI_ISR(15_10)
    165 
    166 int extiSetMaxLatency(struct ChainedIsr *isr, uint32_t maxLatencyNs)
    167 {
    168     uint32_t latency;
    169 
    170     if (!isr)
    171         return -EINVAL;
    172 
    173     if (maxLatencyNs != isr->maxLatencyNs) {
    174         latency = isr->maxLatencyNs;
    175         isr->maxLatencyNs = maxLatencyNs;
    176         if (!mMaxLatency || latency == mMaxLatency || (maxLatencyNs && maxLatencyNs < mMaxLatency)) {
    177             extiCalcMaxLatency();
    178         }
    179     }
    180 
    181     return 0;
    182 }
    183 
    184 int extiChainIsr(IRQn_Type n, struct ChainedIsr *isr)
    185 {
    186     struct ExtiInterrupt *exti = extiForIrq(n);
    187     if (!exti)
    188         return -EINVAL;
    189     else if (!list_is_empty(&isr->node))
    190         return -EINVAL;
    191 
    192     chainIsr(&exti->base, isr);
    193     if (!mMaxLatency || (isr->maxLatencyNs && isr->maxLatencyNs < mMaxLatency))
    194         extiUpdateMaxLatency(isr->maxLatencyNs);
    195 
    196     return 0;
    197 }
    198 
    199 int extiUnchainIsr(IRQn_Type n, struct ChainedIsr *isr)
    200 {
    201     struct ExtiInterrupt *exti = extiForIrq(n);
    202     if (!exti)
    203         return -EINVAL;
    204     else if (list_is_empty(&isr->node))
    205         return -EINVAL;
    206 
    207     unchainIsr(&exti->base, isr);
    208     if (isr->maxLatencyNs && isr->maxLatencyNs == mMaxLatency)
    209         extiCalcMaxLatency();
    210     return 0;
    211 }
    212 
    213 int extiUnchainAll(uint32_t tid)
    214 {
    215     int i, count = 0;
    216     struct ExtiInterrupt *exti = mInterrupts;
    217 
    218     for (i = 0; i < ARRAY_SIZE(mInterrupts); ++i, ++exti)
    219         count += unchainIsrAll(&exti->base, tid);
    220     extiCalcMaxLatency();
    221 
    222     return count;
    223 }
    224