1ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. 2ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean * 3ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean * This program is free software; you can redistribute it and/or modify 4ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean * it under the terms of the GNU General Public License version 2 and 5ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean * only version 2 as published by the Free Software Foundation. 6ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean * 7ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean * This program is distributed in the hope that it will be useful, 8ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean * but WITHOUT ANY WARRANTY; without even the implied warranty of 9ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean * GNU General Public License for more details. 11ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean * 12ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean * You should have received a copy of the GNU General Public License 13ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean * along with this program; if not, write to the Free Software 14ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 15ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean * 02110-1301, USA. 16ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean * 17ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean */ 18ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean 19ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean#include <linux/io.h> 20ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean#include <linux/irq.h> 21ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean#include <linux/interrupt.h> 22ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean#include <asm/irq.h> 23ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean 24ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Beanstatic unsigned int int_enable; 25ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Beanstatic unsigned int wake_enable; 26ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean 27ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Beanstatic struct sirc_regs_t sirc_regs = { 28ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean .int_enable = SPSS_SIRC_INT_ENABLE, 29ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean .int_enable_clear = SPSS_SIRC_INT_ENABLE_CLEAR, 30ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean .int_enable_set = SPSS_SIRC_INT_ENABLE_SET, 31ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean .int_type = SPSS_SIRC_INT_TYPE, 32ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean .int_polarity = SPSS_SIRC_INT_POLARITY, 33ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean .int_clear = SPSS_SIRC_INT_CLEAR, 34ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean}; 35ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean 36ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Beanstatic struct sirc_cascade_regs sirc_reg_table[] = { 37ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean { 38ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean .int_status = SPSS_SIRC_IRQ_STATUS, 39ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean .cascade_irq = INT_SIRC_0, 40ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean } 41ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean}; 42ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean 43ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean/* Mask off the given interrupt. Keep the int_enable mask in sync with 44ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean the enable reg, so it can be restored after power collapse. */ 450f86ee082caa043d5e2990d42a1d5034d2a5caf6Lennert Buytenhekstatic void sirc_irq_mask(struct irq_data *d) 46ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean{ 47ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean unsigned int mask; 48ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean 490f86ee082caa043d5e2990d42a1d5034d2a5caf6Lennert Buytenhek mask = 1 << (d->irq - FIRST_SIRC_IRQ); 50ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean writel(mask, sirc_regs.int_enable_clear); 51ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean int_enable &= ~mask; 52ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean return; 53ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean} 54ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean 55ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean/* Unmask the given interrupt. Keep the int_enable mask in sync with 56ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean the enable reg, so it can be restored after power collapse. */ 570f86ee082caa043d5e2990d42a1d5034d2a5caf6Lennert Buytenhekstatic void sirc_irq_unmask(struct irq_data *d) 58ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean{ 59ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean unsigned int mask; 60ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean 610f86ee082caa043d5e2990d42a1d5034d2a5caf6Lennert Buytenhek mask = 1 << (d->irq - FIRST_SIRC_IRQ); 62ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean writel(mask, sirc_regs.int_enable_set); 63ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean int_enable |= mask; 64ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean return; 65ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean} 66ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean 670f86ee082caa043d5e2990d42a1d5034d2a5caf6Lennert Buytenhekstatic void sirc_irq_ack(struct irq_data *d) 68ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean{ 69ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean unsigned int mask; 70ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean 710f86ee082caa043d5e2990d42a1d5034d2a5caf6Lennert Buytenhek mask = 1 << (d->irq - FIRST_SIRC_IRQ); 72ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean writel(mask, sirc_regs.int_clear); 73ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean return; 74ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean} 75ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean 760f86ee082caa043d5e2990d42a1d5034d2a5caf6Lennert Buytenhekstatic int sirc_irq_set_wake(struct irq_data *d, unsigned int on) 77ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean{ 78ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean unsigned int mask; 79ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean 80ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean /* Used to set the interrupt enable mask during power collapse. */ 810f86ee082caa043d5e2990d42a1d5034d2a5caf6Lennert Buytenhek mask = 1 << (d->irq - FIRST_SIRC_IRQ); 82ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean if (on) 83ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean wake_enable |= mask; 84ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean else 85ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean wake_enable &= ~mask; 86ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean 87ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean return 0; 88ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean} 89ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean 900f86ee082caa043d5e2990d42a1d5034d2a5caf6Lennert Buytenhekstatic int sirc_irq_set_type(struct irq_data *d, unsigned int flow_type) 91ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean{ 92ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean unsigned int mask; 93ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean unsigned int val; 94ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean 950f86ee082caa043d5e2990d42a1d5034d2a5caf6Lennert Buytenhek mask = 1 << (d->irq - FIRST_SIRC_IRQ); 96ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean val = readl(sirc_regs.int_polarity); 97ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean 98ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean if (flow_type & (IRQF_TRIGGER_LOW | IRQF_TRIGGER_FALLING)) 99ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean val |= mask; 100ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean else 101ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean val &= ~mask; 102ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean 103ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean writel(val, sirc_regs.int_polarity); 104ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean 105ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean val = readl(sirc_regs.int_type); 106ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) { 107ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean val |= mask; 10870c4fa2265dde6570fe5bd300fe56986190d7c8cThomas Gleixner __irq_set_handler_locked(d->irq, handle_edge_irq); 109ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean } else { 110ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean val &= ~mask; 11170c4fa2265dde6570fe5bd300fe56986190d7c8cThomas Gleixner __irq_set_handler_locked(d->irq, handle_level_irq); 112ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean } 113ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean 114ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean writel(val, sirc_regs.int_type); 115ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean 116ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean return 0; 117ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean} 118ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean 119ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean/* Finds the pending interrupt on the passed cascade irq and redrives it */ 120ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Beanstatic void sirc_irq_handler(unsigned int irq, struct irq_desc *desc) 121ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean{ 122ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean unsigned int reg = 0; 123ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean unsigned int sirq; 124ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean unsigned int status; 125ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean 126ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean while ((reg < ARRAY_SIZE(sirc_reg_table)) && 127ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean (sirc_reg_table[reg].cascade_irq != irq)) 128ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean reg++; 129ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean 130ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean status = readl(sirc_reg_table[reg].int_status); 131ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean status &= SIRC_MASK; 132ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean if (status == 0) 133ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean return; 134ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean 135ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean for (sirq = 0; 136ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean (sirq < NR_SIRC_IRQS) && ((status & (1U << sirq)) == 0); 137ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean sirq++) 138ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean ; 139ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean generic_handle_irq(sirq+FIRST_SIRC_IRQ); 140ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean 1410f86ee082caa043d5e2990d42a1d5034d2a5caf6Lennert Buytenhek desc->irq_data.chip->irq_ack(&desc->irq_data); 142ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean} 143ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean 144ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Beanstatic struct irq_chip sirc_irq_chip = { 1450f86ee082caa043d5e2990d42a1d5034d2a5caf6Lennert Buytenhek .name = "sirc", 1460f86ee082caa043d5e2990d42a1d5034d2a5caf6Lennert Buytenhek .irq_ack = sirc_irq_ack, 1470f86ee082caa043d5e2990d42a1d5034d2a5caf6Lennert Buytenhek .irq_mask = sirc_irq_mask, 1480f86ee082caa043d5e2990d42a1d5034d2a5caf6Lennert Buytenhek .irq_unmask = sirc_irq_unmask, 1490f86ee082caa043d5e2990d42a1d5034d2a5caf6Lennert Buytenhek .irq_set_wake = sirc_irq_set_wake, 1500f86ee082caa043d5e2990d42a1d5034d2a5caf6Lennert Buytenhek .irq_set_type = sirc_irq_set_type, 151ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean}; 152ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean 153ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Beanvoid __init msm_init_sirc(void) 154ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean{ 155ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean int i; 156ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean 157ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean int_enable = 0; 158ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean wake_enable = 0; 159ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean 160ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean for (i = FIRST_SIRC_IRQ; i < LAST_SIRC_IRQ; i++) { 161f38c02f3b338651e145aac2889ba976baf6b28b3Thomas Gleixner irq_set_chip_and_handler(i, &sirc_irq_chip, handle_edge_irq); 162ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean set_irq_flags(i, IRQF_VALID); 163ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean } 164ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean 165ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean for (i = 0; i < ARRAY_SIZE(sirc_reg_table); i++) { 1666845664a6a7d443f03883db59d10749d38d98b8eThomas Gleixner irq_set_chained_handler(sirc_reg_table[i].cascade_irq, 167ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean sirc_irq_handler); 1686845664a6a7d443f03883db59d10749d38d98b8eThomas Gleixner irq_set_irq_wake(sirc_reg_table[i].cascade_irq, 1); 169ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean } 170ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean return; 171ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean} 172ec4d79255c684a74ade2f2394b9f9a669cee0036Gregory Bean 173