/* * Enable or disable interrupt on the rising edge of a event line */ void stm32_exti_enable_int(unsigned int line, int enable) { if (line >= STM32F2_EXTI_NUM_LINES) goto out; if (enable) { stm32_exti_clear_pending(line); /* Enable trigger on rising edge */ KINETIS_EXTI->rtsr |= (1 << line); /* Disable trigger on falling edge */ KINETIS_EXTI->ftsr &= ~(1 << line); /* Enable interrupt for the event */ KINETIS_EXTI->imr |= (1 << line); } else { /* Disable interrupt for the event */ KINETIS_EXTI->imr &= ~(1 << line); /* Disable trigger on rising edge */ KINETIS_EXTI->rtsr &= ~(1 << line); /* Disable trigger on falling edge */ KINETIS_EXTI->ftsr &= ~(1 << line); stm32_exti_clear_pending(line); } out: ; }
/* * enable or disable interrupt * @line EXTI line * @enable enable(1) / disable(0) */ void stm32_exti_enable_int(unsigned int line, int enable) { if (enable) { stm32_exti_clear_pending(line); /* Enable interrupt for the event */ writel(readl(&STM32_EXTI->imr) | (1 << line), &STM32_EXTI->imr); } else { /* Disable interrupt for the event */ writel(readl(&STM32_EXTI->imr) & ~(1 << line), &STM32_EXTI->imr); /* Disable trigger on rising edge */ writel(readl(&STM32_EXTI->rtsr) & ~(1 << line), &STM32_EXTI->rtsr); /* Disable trigger on falling edge */ writel(readl(&STM32_EXTI->ftsr) & ~(1 << line), &STM32_EXTI->ftsr); /* Clear pending events if any */ stm32_exti_clear_pending(line); } #if defined(DEBUG) printk("%s:%d,%d=%x\n", __func__, line, enable, readl(&STM32_EXTI->imr)); #endif }
/* * Enable or disable the update interrupts */ static int stm32f2_rtc_update_irq_enable( struct device *dev, unsigned int enabled) { struct stm32f2_rtc *rtc = dev_get_drvdata(dev); spin_lock_irq(&rtc->lock); if (enabled) { /* Use Alarm B to emulate update interrupts (1 Hz) */ stm32f2_setup_alarm(1, -1, -1, -1, -1, -1); stm32f2_alarm_irq_enable(1, 1); } else { /* Disable interrupts from Alarm B */ stm32f2_alarm_irq_enable(1, 0); /* Disable Alarm B */ stm32f2_rtc_write_enable(1); STM32_RTC->cr &= ~STM32F2_RTC_CR_ALRBE_MSK; stm32f2_rtc_write_enable(0); stm32_exti_clear_pending(STM32F2_EXTI_LINE_RTC_ALARM); } spin_unlock_irq(&rtc->lock); return 0; }
/* * RTC wakeup interrupt handler */ static irqreturn_t stm32f2_rtc_wakeup_irq(int irq, void *dev_id) { struct stm32f2_rtc *rtc = (struct stm32f2_rtc *)dev_id; irqreturn_t rv; spin_lock(&rtc->lock); if (!(STM32_RTC->isr & STM32F2_RTC_ISR_WUTF_MSK) || !(STM32_RTC->cr & STM32F2_RTC_CR_WUTIE_MSK)) { rv = IRQ_NONE; goto out; } /* Clear event flag, otherwise new events won't be received */ stm32f2_rtc_write_enable(1); STM32_RTC->isr &= ~STM32F2_RTC_ISR_WUTF_MSK; stm32f2_rtc_write_enable(0); stm32_exti_clear_pending(STM32F2_EXTI_LINE_RTC_WAKEUP); /* Pass periodic interrupt event to the kernel */ rtc_update_irq(rtc->rtc_dev, 1, RTC_PF | RTC_IRQF); rv = IRQ_HANDLED; out: spin_unlock(&rtc->lock); return rv; }
/** * @brief EXTI ISR handler * * Check EXTI lines in range @min @max for pending interrupts * * @param arg isr argument * @parram min low end of EXTI# range * @parram max low end of EXTI# range */ static void __stm32_exti_isr(int min, int max, void *arg) { struct device *dev = arg; struct stm32_exti_data *data = dev->driver_data; int line; /* see which bits are set */ for (line = min; line < max; line++) { /* check if interrupt is pending */ if (stm32_exti_is_pending(line)) { /* clear pending interrupt */ stm32_exti_clear_pending(line); /* run callback only if one is registered */ if (!data->cb[line].cb) { continue; } data->cb[line].cb(line, data->cb[line].data); } } }
/* * RTC alarm interrupt handler */ static irqreturn_t stm32f2_rtc_alarm_irq(int irq, void *dev_id) { unsigned long events = 0; struct stm32f2_rtc *rtc = (struct stm32f2_rtc *)dev_id; u32 status; u32 enabled_irqs; spin_lock(&rtc->lock); status = STM32_RTC->isr; enabled_irqs = STM32_RTC->cr; stm32f2_rtc_write_enable(1); /* clear event flags, otherwise new events won't be received */ STM32_RTC->isr &= ~(status & (STM32F2_RTC_ISR_ALRBF_MSK | STM32F2_RTC_ISR_ALRAF_MSK)); stm32f2_rtc_write_enable(0); if ((status & STM32F2_RTC_ISR_ALRAF_MSK) && (enabled_irqs & STM32F2_RTC_CR_ALRAIE_MSK)) { /* Normal alarm interrupt */ events |= (RTC_AF | RTC_IRQF); } if ((status & STM32F2_RTC_ISR_ALRBF_MSK) && (enabled_irqs & STM32F2_RTC_CR_ALRBIE_MSK)) { /* Update interrupt (1 Hz) */ events |= (RTC_UF | RTC_IRQF); } if (events) { stm32_exti_clear_pending(STM32F2_EXTI_LINE_RTC_ALARM); rtc_update_irq(rtc->rtc_dev, 1, events); } spin_unlock(&rtc->lock); return events ? IRQ_HANDLED : IRQ_NONE; }