Path: blob/master/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c
10820 views
/*1* Copyright (C) 2008 Freescale Semiconductor, Inc. All rights reserved.2*3* Author: John Rigby, <[email protected]>4*5* Description:6* MPC5121ADS CPLD irq handling7*8* This is free software; you can redistribute it and/or modify it9* under the terms of the GNU General Public License as published by10* the Free Software Foundation; either version 2 of the License, or11* (at your option) any later version.12*/1314#undef DEBUG1516#include <linux/kernel.h>17#include <linux/interrupt.h>18#include <linux/irq.h>19#include <linux/io.h>20#include <asm/prom.h>2122static struct device_node *cpld_pic_node;23static struct irq_host *cpld_pic_host;2425/*26* Bits to ignore in the misc_status register27* 0x10 touch screen pendown is hard routed to irq128* 0x02 pci status is read from pci status register29*/30#define MISC_IGNORE 0x123132/*33* Nothing to ignore in pci status register34*/35#define PCI_IGNORE 0x003637struct cpld_pic {38u8 pci_mask;39u8 pci_status;40u8 route;41u8 misc_mask;42u8 misc_status;43u8 misc_control;44};4546static struct cpld_pic __iomem *cpld_regs;4748static void __iomem *49irq_to_pic_mask(unsigned int irq)50{51return irq <= 7 ? &cpld_regs->pci_mask : &cpld_regs->misc_mask;52}5354static unsigned int55irq_to_pic_bit(unsigned int irq)56{57return 1 << (irq & 0x7);58}5960static void61cpld_mask_irq(struct irq_data *d)62{63unsigned int cpld_irq = (unsigned int)irqd_to_hwirq(d);64void __iomem *pic_mask = irq_to_pic_mask(cpld_irq);6566out_8(pic_mask,67in_8(pic_mask) | irq_to_pic_bit(cpld_irq));68}6970static void71cpld_unmask_irq(struct irq_data *d)72{73unsigned int cpld_irq = (unsigned int)irqd_to_hwirq(d);74void __iomem *pic_mask = irq_to_pic_mask(cpld_irq);7576out_8(pic_mask,77in_8(pic_mask) & ~irq_to_pic_bit(cpld_irq));78}7980static struct irq_chip cpld_pic = {81.name = "CPLD PIC",82.irq_mask = cpld_mask_irq,83.irq_ack = cpld_mask_irq,84.irq_unmask = cpld_unmask_irq,85};8687static int88cpld_pic_get_irq(int offset, u8 ignore, u8 __iomem *statusp,89u8 __iomem *maskp)90{91int cpld_irq;92u8 status = in_8(statusp);93u8 mask = in_8(maskp);9495/* ignore don't cares and masked irqs */96status |= (ignore | mask);9798if (status == 0xff)99return NO_IRQ;100101cpld_irq = ffz(status) + offset;102103return irq_linear_revmap(cpld_pic_host, cpld_irq);104}105106static void107cpld_pic_cascade(unsigned int irq, struct irq_desc *desc)108{109irq = cpld_pic_get_irq(0, PCI_IGNORE, &cpld_regs->pci_status,110&cpld_regs->pci_mask);111if (irq != NO_IRQ) {112generic_handle_irq(irq);113return;114}115116irq = cpld_pic_get_irq(8, MISC_IGNORE, &cpld_regs->misc_status,117&cpld_regs->misc_mask);118if (irq != NO_IRQ) {119generic_handle_irq(irq);120return;121}122}123124static int125cpld_pic_host_match(struct irq_host *h, struct device_node *node)126{127return cpld_pic_node == node;128}129130static int131cpld_pic_host_map(struct irq_host *h, unsigned int virq,132irq_hw_number_t hw)133{134irq_set_status_flags(virq, IRQ_LEVEL);135irq_set_chip_and_handler(virq, &cpld_pic, handle_level_irq);136return 0;137}138139static struct140irq_host_ops cpld_pic_host_ops = {141.match = cpld_pic_host_match,142.map = cpld_pic_host_map,143};144145void __init146mpc5121_ads_cpld_map(void)147{148struct device_node *np = NULL;149150np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121ads-cpld-pic");151if (!np) {152printk(KERN_ERR "CPLD PIC init: can not find cpld-pic node\n");153return;154}155156cpld_regs = of_iomap(np, 0);157of_node_put(np);158}159160void __init161mpc5121_ads_cpld_pic_init(void)162{163unsigned int cascade_irq;164struct device_node *np = NULL;165166pr_debug("cpld_ic_init\n");167168np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121ads-cpld-pic");169if (!np) {170printk(KERN_ERR "CPLD PIC init: can not find cpld-pic node\n");171return;172}173174if (!cpld_regs)175goto end;176177cascade_irq = irq_of_parse_and_map(np, 0);178if (cascade_irq == NO_IRQ)179goto end;180181/*182* statically route touch screen pendown through 1183* and ignore it here184* route all others through our cascade irq185*/186out_8(&cpld_regs->route, 0xfd);187out_8(&cpld_regs->pci_mask, 0xff);188/* unmask pci ints in misc mask */189out_8(&cpld_regs->misc_mask, ~(MISC_IGNORE));190191cpld_pic_node = of_node_get(np);192193cpld_pic_host =194irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, 16, &cpld_pic_host_ops, 16);195if (!cpld_pic_host) {196printk(KERN_ERR "CPLD PIC: failed to allocate irq host!\n");197goto end;198}199200irq_set_chained_handler(cascade_irq, cpld_pic_cascade);201end:202of_node_put(np);203}204205206