224 lines
5.9 KiB
C
224 lines
5.9 KiB
C
/*
|
|
* Copyright (C) 2016 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#include <isr.h>
|
|
#include <platform.h>
|
|
|
|
#include <plat/cmsis.h>
|
|
#include <plat/exti.h>
|
|
#include <plat/pwr.h>
|
|
|
|
struct StmExti
|
|
{
|
|
volatile uint32_t IMR;
|
|
volatile uint32_t EMR;
|
|
volatile uint32_t RTSR;
|
|
volatile uint32_t FTSR;
|
|
volatile uint32_t SWIER;
|
|
volatile uint32_t PR;
|
|
};
|
|
|
|
#define EXTI ((struct StmExti*)EXTI_BASE)
|
|
|
|
void extiEnableIntLine(const enum ExtiLine line, enum ExtiTrigger trigger)
|
|
{
|
|
if (trigger == EXTI_TRIGGER_BOTH) {
|
|
EXTI->RTSR |= (1UL << line);
|
|
EXTI->FTSR |= (1UL << line);
|
|
} else if (trigger == EXTI_TRIGGER_RISING) {
|
|
EXTI->RTSR |= (1UL << line);
|
|
EXTI->FTSR &= ~(1UL << line);
|
|
} else if (trigger == EXTI_TRIGGER_FALLING) {
|
|
EXTI->RTSR &= ~(1UL << line);
|
|
EXTI->FTSR |= (1UL << line);
|
|
}
|
|
|
|
/* Clear pending interrupt */
|
|
extiClearPendingLine(line);
|
|
|
|
/* Enable hardware interrupt */
|
|
EXTI->IMR |= (1UL << line);
|
|
}
|
|
|
|
void extiDisableIntLine(const enum ExtiLine line)
|
|
{
|
|
EXTI->IMR &= ~(1UL << line);
|
|
}
|
|
|
|
void extiClearPendingLine(const enum ExtiLine line)
|
|
{
|
|
EXTI->PR = (1UL << line);
|
|
}
|
|
|
|
bool extiIsPendingLine(const enum ExtiLine line)
|
|
{
|
|
return (EXTI->PR & (1UL << line)) ? true : false;
|
|
}
|
|
|
|
struct ExtiInterrupt
|
|
{
|
|
struct ChainedInterrupt base;
|
|
IRQn_Type irq;
|
|
};
|
|
|
|
static void extiInterruptEnable(struct ChainedInterrupt *irq)
|
|
{
|
|
struct ExtiInterrupt *exti = container_of(irq, struct ExtiInterrupt, base);
|
|
NVIC_EnableIRQ(exti->irq);
|
|
}
|
|
|
|
static void extiInterruptDisable(struct ChainedInterrupt *irq)
|
|
{
|
|
struct ExtiInterrupt *exti = container_of(irq, struct ExtiInterrupt, base);
|
|
NVIC_DisableIRQ(exti->irq);
|
|
}
|
|
|
|
#define DECLARE_SHARED_EXTI(i) { \
|
|
.base = { \
|
|
.enable = extiInterruptEnable, \
|
|
.disable = extiInterruptDisable, \
|
|
}, \
|
|
.irq = i, \
|
|
}
|
|
|
|
uint32_t mMaxLatency = 0;
|
|
|
|
static struct ExtiInterrupt mInterrupts[] = {
|
|
DECLARE_SHARED_EXTI(EXTI0_IRQn),
|
|
DECLARE_SHARED_EXTI(EXTI1_IRQn),
|
|
DECLARE_SHARED_EXTI(EXTI2_IRQn),
|
|
DECLARE_SHARED_EXTI(EXTI3_IRQn),
|
|
DECLARE_SHARED_EXTI(EXTI4_IRQn),
|
|
DECLARE_SHARED_EXTI(EXTI9_5_IRQn),
|
|
DECLARE_SHARED_EXTI(EXTI15_10_IRQn),
|
|
};
|
|
|
|
static void extiUpdateMaxLatency(uint32_t maxLatencyNs)
|
|
{
|
|
if (!maxLatencyNs && mMaxLatency)
|
|
platReleaseDevInSleepMode(Stm32sleepDevExti);
|
|
else if (maxLatencyNs && !mMaxLatency)
|
|
platRequestDevInSleepMode(Stm32sleepDevExti, maxLatencyNs);
|
|
else if (maxLatencyNs && mMaxLatency)
|
|
platAdjustDevInSleepMode(Stm32sleepDevExti, maxLatencyNs);
|
|
mMaxLatency = maxLatencyNs;
|
|
}
|
|
|
|
static void extiCalcMaxLatency()
|
|
{
|
|
int i;
|
|
uint32_t maxLatency, newMaxLatency = 0;
|
|
struct ExtiInterrupt *exti = mInterrupts;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(mInterrupts); ++i, ++exti) {
|
|
maxLatency = maxLatencyIsr(&exti->base);
|
|
if (!newMaxLatency || (maxLatency && maxLatency < newMaxLatency))
|
|
newMaxLatency = maxLatency;
|
|
}
|
|
extiUpdateMaxLatency(newMaxLatency);
|
|
}
|
|
|
|
static inline struct ExtiInterrupt *extiForIrq(IRQn_Type n)
|
|
{
|
|
if (n >= EXTI0_IRQn && n <= EXTI4_IRQn)
|
|
return &mInterrupts[n - EXTI0_IRQn];
|
|
if (n == EXTI9_5_IRQn)
|
|
return &mInterrupts[ARRAY_SIZE(mInterrupts) - 2];
|
|
if (n == EXTI15_10_IRQn)
|
|
return &mInterrupts[ARRAY_SIZE(mInterrupts) - 1];
|
|
return NULL;
|
|
}
|
|
|
|
static void extiIrqHandler(IRQn_Type n)
|
|
{
|
|
struct ExtiInterrupt *exti = extiForIrq(n);
|
|
dispatchIsr(&exti->base);
|
|
}
|
|
|
|
#define DEFINE_SHARED_EXTI_ISR(i) \
|
|
void EXTI##i##_IRQHandler(void); \
|
|
void EXTI##i##_IRQHandler(void) { \
|
|
extiIrqHandler(EXTI##i##_IRQn); \
|
|
} \
|
|
|
|
DEFINE_SHARED_EXTI_ISR(0)
|
|
DEFINE_SHARED_EXTI_ISR(1)
|
|
DEFINE_SHARED_EXTI_ISR(2)
|
|
DEFINE_SHARED_EXTI_ISR(3)
|
|
DEFINE_SHARED_EXTI_ISR(4)
|
|
DEFINE_SHARED_EXTI_ISR(9_5)
|
|
DEFINE_SHARED_EXTI_ISR(15_10)
|
|
|
|
int extiSetMaxLatency(struct ChainedIsr *isr, uint32_t maxLatencyNs)
|
|
{
|
|
uint32_t latency;
|
|
|
|
if (!isr)
|
|
return -EINVAL;
|
|
|
|
if (maxLatencyNs != isr->maxLatencyNs) {
|
|
latency = isr->maxLatencyNs;
|
|
isr->maxLatencyNs = maxLatencyNs;
|
|
if (!mMaxLatency || latency == mMaxLatency || (maxLatencyNs && maxLatencyNs < mMaxLatency)) {
|
|
extiCalcMaxLatency();
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int extiChainIsr(IRQn_Type n, struct ChainedIsr *isr)
|
|
{
|
|
struct ExtiInterrupt *exti = extiForIrq(n);
|
|
if (!exti)
|
|
return -EINVAL;
|
|
else if (!list_is_empty(&isr->node))
|
|
return -EINVAL;
|
|
|
|
chainIsr(&exti->base, isr);
|
|
if (!mMaxLatency || (isr->maxLatencyNs && isr->maxLatencyNs < mMaxLatency))
|
|
extiUpdateMaxLatency(isr->maxLatencyNs);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int extiUnchainIsr(IRQn_Type n, struct ChainedIsr *isr)
|
|
{
|
|
struct ExtiInterrupt *exti = extiForIrq(n);
|
|
if (!exti)
|
|
return -EINVAL;
|
|
else if (list_is_empty(&isr->node))
|
|
return -EINVAL;
|
|
|
|
unchainIsr(&exti->base, isr);
|
|
if (isr->maxLatencyNs && isr->maxLatencyNs == mMaxLatency)
|
|
extiCalcMaxLatency();
|
|
return 0;
|
|
}
|
|
|
|
int extiUnchainAll(uint32_t tid)
|
|
{
|
|
int i, count = 0;
|
|
struct ExtiInterrupt *exti = mInterrupts;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(mInterrupts); ++i, ++exti)
|
|
count += unchainIsrAll(&exti->base, tid);
|
|
extiCalcMaxLatency();
|
|
|
|
return count;
|
|
}
|