Path: blob/master/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c
26481 views
// SPDX-License-Identifier: GPL-2.0-or-later1/*2* Copyright (C) 2008 Freescale Semiconductor, Inc. All rights reserved.3*4* Author: John Rigby, <[email protected]>5*6* Description:7* MPC5121ADS CPLD irq handling8*/910#undef DEBUG1112#include <linux/kernel.h>13#include <linux/interrupt.h>14#include <linux/irq.h>15#include <linux/io.h>16#include <linux/of_address.h>17#include <linux/of_irq.h>1819#include "mpc5121_ads.h"2021static struct device_node *cpld_pic_node;22static struct irq_domain *cpld_pic_host;2324/*25* Bits to ignore in the misc_status register26* 0x10 touch screen pendown is hard routed to irq127* 0x02 pci status is read from pci status register28*/29#define MISC_IGNORE 0x123031/*32* Nothing to ignore in pci status register33*/34#define PCI_IGNORE 0x003536struct cpld_pic {37u8 pci_mask;38u8 pci_status;39u8 route;40u8 misc_mask;41u8 misc_status;42u8 misc_control;43};4445static struct cpld_pic __iomem *cpld_regs;4647static void __iomem *48irq_to_pic_mask(unsigned int irq)49{50return irq <= 7 ? &cpld_regs->pci_mask : &cpld_regs->misc_mask;51}5253static unsigned int54irq_to_pic_bit(unsigned int irq)55{56return 1 << (irq & 0x7);57}5859static void60cpld_mask_irq(struct irq_data *d)61{62unsigned int cpld_irq = (unsigned int)irqd_to_hwirq(d);63void __iomem *pic_mask = irq_to_pic_mask(cpld_irq);6465out_8(pic_mask,66in_8(pic_mask) | irq_to_pic_bit(cpld_irq));67}6869static void70cpld_unmask_irq(struct irq_data *d)71{72unsigned int cpld_irq = (unsigned int)irqd_to_hwirq(d);73void __iomem *pic_mask = irq_to_pic_mask(cpld_irq);7475out_8(pic_mask,76in_8(pic_mask) & ~irq_to_pic_bit(cpld_irq));77}7879static struct irq_chip cpld_pic = {80.name = "CPLD PIC",81.irq_mask = cpld_mask_irq,82.irq_ack = cpld_mask_irq,83.irq_unmask = cpld_unmask_irq,84};8586static unsigned int87cpld_pic_get_irq(int offset, u8 ignore, u8 __iomem *statusp,88u8 __iomem *maskp)89{90u8 status = in_8(statusp);91u8 mask = in_8(maskp);9293/* ignore don't cares and masked irqs */94status |= (ignore | mask);9596if (status == 0xff)97return ~0;9899return ffz(status) + offset;100}101102static void cpld_pic_cascade(struct irq_desc *desc)103{104unsigned int hwirq;105106hwirq = cpld_pic_get_irq(0, PCI_IGNORE, &cpld_regs->pci_status,107&cpld_regs->pci_mask);108if (hwirq != ~0) {109generic_handle_domain_irq(cpld_pic_host, hwirq);110return;111}112113hwirq = cpld_pic_get_irq(8, MISC_IGNORE, &cpld_regs->misc_status,114&cpld_regs->misc_mask);115if (hwirq != ~0) {116generic_handle_domain_irq(cpld_pic_host, hwirq);117return;118}119}120121static int122cpld_pic_host_match(struct irq_domain *h, struct device_node *node,123enum irq_domain_bus_token bus_token)124{125return cpld_pic_node == node;126}127128static int129cpld_pic_host_map(struct irq_domain *h, unsigned int virq,130irq_hw_number_t hw)131{132irq_set_status_flags(virq, IRQ_LEVEL);133irq_set_chip_and_handler(virq, &cpld_pic, handle_level_irq);134return 0;135}136137static const struct irq_domain_ops cpld_pic_host_ops = {138.match = cpld_pic_host_match,139.map = cpld_pic_host_map,140};141142void __init143mpc5121_ads_cpld_map(void)144{145struct device_node *np = NULL;146147np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121ads-cpld-pic");148if (!np) {149printk(KERN_ERR "CPLD PIC init: can not find cpld-pic node\n");150return;151}152153cpld_regs = of_iomap(np, 0);154of_node_put(np);155}156157void __init158mpc5121_ads_cpld_pic_init(void)159{160unsigned int cascade_irq;161struct device_node *np = NULL;162163pr_debug("cpld_ic_init\n");164165np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121ads-cpld-pic");166if (!np) {167printk(KERN_ERR "CPLD PIC init: can not find cpld-pic node\n");168return;169}170171if (!cpld_regs)172goto end;173174cascade_irq = irq_of_parse_and_map(np, 0);175if (!cascade_irq)176goto end;177178/*179* statically route touch screen pendown through 1180* and ignore it here181* route all others through our cascade irq182*/183out_8(&cpld_regs->route, 0xfd);184out_8(&cpld_regs->pci_mask, 0xff);185/* unmask pci ints in misc mask */186out_8(&cpld_regs->misc_mask, ~(MISC_IGNORE));187188cpld_pic_node = of_node_get(np);189190cpld_pic_host = irq_domain_create_linear(of_fwnode_handle(np), 16,191&cpld_pic_host_ops, NULL);192if (!cpld_pic_host) {193printk(KERN_ERR "CPLD PIC: failed to allocate irq host!\n");194goto end;195}196197irq_set_chained_handler(cascade_irq, cpld_pic_cascade);198end:199of_node_put(np);200}201202203