/* * Prepare interrupt subsystem for entering sleep -- phase 2. * Detect any pending interrupts and configure interrupt hardware. * * Return value: * -EAGAIN: there are pending interrupt(s); interrupt configuration * is not changed. * 0: success */ int msm_irq_enter_sleep2(bool modem_wake, int from_idle) { int i, limit = 10; uint32_t pending[VIC_NUM_REGS]; if (from_idle && !modem_wake) return 0; /* edge triggered interrupt may get lost if this mode is used */ WARN_ON_ONCE(!modem_wake && !from_idle); if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP) DPRINT_REGS(VIC_IRQ_STATUS, "%s change irq, pend", __func__); for (i = 0; i < VIC_NUM_REGS; i++) { pending[i] = readl(VIC_IRQ_STATUS0 + (i * 4)); pending[i] &= msm_irq_shadow_reg[i].int_en[!from_idle]; } /* * Clear INT_A9_M2A_5 since requesting sleep triggers it. * In some arch e.g. FSM9XXX, INT_A9_M2A_5 may not be in the first set. */ pending[INT_A9_M2A_5 / 32] &= ~(1U << (INT_A9_M2A_5 % 32)); for (i = 0; i < VIC_NUM_REGS; i++) { if (pending[i]) { if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_ABORT) DPRINT_ARRAY(pending, "%s abort", __func__); return -EAGAIN; } } msm_irq_write_all_regs(VIC_INT_EN0, 0); while (limit-- > 0) { int pend_irq; int irq = readl(VIC_IRQ_VEC_RD); if (irq == -1) break; pend_irq = readl(VIC_IRQ_VEC_PEND_RD); if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_INT) printk(KERN_INFO "%s cleared int %d (%d)\n", __func__, irq, pend_irq); } if (modem_wake) { msm_irq_set_type(INT_A9_M2A_6, IRQF_TRIGGER_RISING); __raw_writel(1U << (INT_A9_M2A_6 % 32), VIC_INT_TO_REG_ADDR(VIC_INT_ENSET0, INT_A9_M2A_6)); } else { for (i = 0; i < VIC_NUM_REGS; i++) writel(msm_irq_shadow_reg[i].int_en[1], VIC_INT_ENSET0 + (i * 4)); } dsb(); return 0; }
/* * Restore interrupt subsystem from sleep -- phase 1. * Configure interrupt hardware. */ void msm_irq_exit_sleep1(uint32_t irq_mask, uint32_t wakeup_reason, uint32_t pending_irqs) { int i; msm_irq_ack(INT_A9_M2A_6); for (i = 0; i < VIC_NUM_REGS; i++) { writel(msm_irq_shadow_reg[i].int_type, VIC_INT_TYPE0 + i * 4); writel(msm_irq_shadow_reg[i].int_polarity, VIC_INT_POLARITY0 + i * 4); writel(msm_irq_shadow_reg[i].int_en[0], VIC_INT_EN0 + i * 4); writel(msm_irq_shadow_reg[i].int_select, VIC_INT_SELECT0 + i * 4); } writel(3, VIC_INT_MASTEREN); dsb(); if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP) DPRINT_REGS(VIC_IRQ_STATUS, "%s %x %x %x now", __func__, irq_mask, pending_irqs, wakeup_reason); }
/* * Restore interrupt subsystem from sleep -- phase 3. * Print debug information. */ void msm_irq_exit_sleep3(uint32_t irq_mask, uint32_t wakeup_reason, uint32_t pending_irqs) { if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP) DPRINT_REGS(VIC_IRQ_STATUS, "%s %x %x %x state %x now", __func__, irq_mask, pending_irqs, wakeup_reason, smsm_get_state(SMSM_MODEM_STATE)); }
/* * Restore interrupt subsystem from sleep -- phase 2. * Poke the specified pending interrupts into interrupt hardware. */ void msm_irq_exit_sleep2(uint32_t irq_mask, uint32_t wakeup_reason, uint32_t pending) { int i; if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP) DPRINT_REGS(VIC_IRQ_STATUS, "%s %x %x %x now", __func__, irq_mask, pending, wakeup_reason); for (i = 0; pending && i < ARRAY_SIZE(msm_irq_to_smsm); i++) { unsigned reg_offset = VIC_INT_TO_REG_ADDR(0, i); uint32_t reg_mask = 1UL << (i & 31); int smsm_irq = msm_irq_to_smsm[i]; uint32_t smsm_mask; if (smsm_irq == 0) continue; smsm_mask = 1U << (smsm_irq - 1); if (!(pending & smsm_mask)) continue; pending &= ~smsm_mask; if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_INT) DPRINT_REGS(VIC_IRQ_STATUS, "%s: irq %d still pending %x now", __func__, i, pending); #ifdef DEBUG_INTERRUPT_TRIGGER if (readl(VIC_IRQ_STATUS0 + reg_offset) & reg_mask) writel(reg_mask, VIC_INT_CLEAR0 + reg_offset); #endif if (readl(VIC_IRQ_STATUS0 + reg_offset) & reg_mask) continue; writel(reg_mask, VIC_SOFTINT0 + reg_offset); if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_INT_TRIGGER) DPRINT_REGS(VIC_IRQ_STATUS, "%s: irq %d need trigger, now", __func__, i); } dsb(); }
int msm_irq_enter_sleep2(bool modem_wake, int from_idle) { int i, limit = 10; uint32_t pending[VIC_NUM_REGS]; if (from_idle && !modem_wake) return 0; /* */ WARN_ON_ONCE(!modem_wake && !from_idle); if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP) DPRINT_REGS(VIC_IRQ_STATUS, "%s change irq, pend", __func__); for (i = 0; i < VIC_NUM_REGS; i++) { pending[i] = readl(VIC_IRQ_STATUS0 + (i * 4)); pending[i] &= msm_irq_shadow_reg[i].int_en[!from_idle]; } /* */ pending[INT_A9_M2A_5 / 32] &= ~(1U << (INT_A9_M2A_5 % 32)); for (i = 0; i < VIC_NUM_REGS; i++) { if (pending[i]) { if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_ABORT) DPRINT_ARRAY(pending, "%s abort", __func__); return -EAGAIN; } } msm_irq_write_all_regs(VIC_INT_EN0, 0); while (limit-- > 0) { int pend_irq; int irq = readl(VIC_IRQ_VEC_RD); if (irq == -1) break; pend_irq = readl(VIC_IRQ_VEC_PEND_RD); if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_INT) printk(KERN_INFO "%s cleared int %d (%d)\n", __func__, irq, pend_irq); } if (modem_wake) { struct irq_data d = { .irq = INT_A9_M2A_6 }; msm_irq_set_type(&d, IRQF_TRIGGER_RISING); __raw_writel(1U << (INT_A9_M2A_6 % 32), VIC_INT_TO_REG_ADDR(VIC_INT_ENSET0, INT_A9_M2A_6)); } else { for (i = 0; i < VIC_NUM_REGS; i++)