cregit-Linux how code gets into the kernel

Release 4.11 arch/avr32/mach-at32ap/extint.c

/*
 * External interrupt handling for AT32AP CPUs
 *
 * Copyright (C) 2006 Atmel Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#include <linux/errno.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/platform_device.h>
#include <linux/random.h>
#include <linux/slab.h>

#include <asm/io.h>

/* EIC register offsets */

#define EIC_IER					0x0000

#define EIC_IDR					0x0004

#define EIC_IMR					0x0008

#define EIC_ISR					0x000c

#define EIC_ICR					0x0010

#define EIC_MODE				0x0014

#define EIC_EDGE				0x0018

#define EIC_LEVEL				0x001c

#define EIC_NMIC				0x0024

/* Bitfields in NMIC */

#define EIC_NMIC_ENABLE				(1 << 0)

/* Bit manipulation macros */

#define EIC_BIT(name)					\
	(1 << EIC_##name##_OFFSET)

#define EIC_BF(name,value)				\
	(((value) & ((1 << EIC_##name##_SIZE) - 1))     \
         << EIC_##name##_OFFSET)

#define EIC_BFEXT(name,value)				\
	(((value) >> EIC_##name##_OFFSET)               \
         & ((1 << EIC_##name##_SIZE) - 1))

#define EIC_BFINS(name,value,old)			\
	(((old) & ~(((1 << EIC_##name##_SIZE) - 1)      \
                    << EIC_##name##_OFFSET))            \
         | EIC_BF(name,value))

/* Register access macros */

#define eic_readl(port,reg)				\
	__raw_readl((port)->regs + EIC_##reg)

#define eic_writel(port,reg,value)			\
	__raw_writel((value), (port)->regs + EIC_##reg)


struct eic {
	
void __iomem *regs;
	
struct irq_chip *chip;
	
unsigned int first_irq;
};


static struct eic *nmi_eic;

static bool nmi_enabled;


static void eic_ack_irq(struct irq_data *d) { struct eic *eic = irq_data_get_irq_chip_data(d); eic_writel(eic, ICR, 1 << (d->irq - eic->first_irq)); }

Contributors

PersonTokensPropCommitsCommitProp
Håvard Skinnemoen3280.00%250.00%
Thomas Gleixner615.00%125.00%
Wanlong Gao25.00%125.00%
Total40100.00%4100.00%


static void eic_mask_irq(struct irq_data *d) { struct eic *eic = irq_data_get_irq_chip_data(d); eic_writel(eic, IDR, 1 << (d->irq - eic->first_irq)); }

Contributors

PersonTokensPropCommitsCommitProp
Håvard Skinnemoen3280.00%250.00%
Thomas Gleixner615.00%125.00%
Wanlong Gao25.00%125.00%
Total40100.00%4100.00%


static void eic_mask_ack_irq(struct irq_data *d) { struct eic *eic = irq_data_get_irq_chip_data(d); eic_writel(eic, ICR, 1 << (d->irq - eic->first_irq)); eic_writel(eic, IDR, 1 << (d->irq - eic->first_irq)); }

Contributors

PersonTokensPropCommitsCommitProp
Håvard Skinnemoen4983.05%250.00%
Thomas Gleixner813.56%125.00%
Wanlong Gao23.39%125.00%
Total59100.00%4100.00%


static void eic_unmask_irq(struct irq_data *d) { struct eic *eic = irq_data_get_irq_chip_data(d); eic_writel(eic, IER, 1 << (d->irq - eic->first_irq)); }

Contributors

PersonTokensPropCommitsCommitProp
Håvard Skinnemoen3280.00%250.00%
Thomas Gleixner615.00%125.00%
Wanlong Gao25.00%125.00%
Total40100.00%4100.00%


static int eic_set_irq_type(struct irq_data *d, unsigned int flow_type) { struct eic *eic = irq_data_get_irq_chip_data(d); unsigned int irq = d->irq; unsigned int i = irq - eic->first_irq; u32 mode, edge, level; flow_type &= IRQ_TYPE_SENSE_MASK; if (flow_type == IRQ_TYPE_NONE) flow_type = IRQ_TYPE_LEVEL_LOW; mode = eic_readl(eic, MODE); edge = eic_readl(eic, EDGE); level = eic_readl(eic, LEVEL); switch (flow_type) { case IRQ_TYPE_LEVEL_LOW: mode |= 1 << i; level &= ~(1 << i); break; case IRQ_TYPE_LEVEL_HIGH: mode |= 1 << i; level |= 1 << i; break; case IRQ_TYPE_EDGE_RISING: mode &= ~(1 << i); edge |= 1 << i; break; case IRQ_TYPE_EDGE_FALLING: mode &= ~(1 << i); edge &= ~(1 << i); break; default: return -EINVAL; } eic_writel(eic, MODE, mode); eic_writel(eic, EDGE, edge); eic_writel(eic, LEVEL, level); irqd_set_trigger_type(d, flow_type); if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) irq_set_handler_locked(d, handle_level_irq); else irq_set_handler_locked(d, handle_edge_irq); return IRQ_SET_MASK_OK_NOCOPY; }

Contributors

PersonTokensPropCommitsCommitProp
Håvard Skinnemoen18777.92%333.33%
Thomas Gleixner2610.83%333.33%
David Brownell2510.42%222.22%
Wanlong Gao20.83%111.11%
Total240100.00%9100.00%

static struct irq_chip eic_chip = { .name = "eic", .irq_ack = eic_ack_irq, .irq_mask = eic_mask_irq, .irq_mask_ack = eic_mask_ack_irq, .irq_unmask = eic_unmask_irq, .irq_set_type = eic_set_irq_type, };
static void demux_eic_irq(struct irq_desc *desc) { struct eic *eic = irq_desc_get_handler_data(desc); unsigned long status, pending; unsigned int i; status = eic_readl(eic, ISR); pending = status & eic_readl(eic, IMR); while (pending) { i = fls(pending) - 1; pending &= ~(1 << i); generic_handle_irq(i + eic->first_irq); } }

Contributors

PersonTokensPropCommitsCommitProp
Håvard Skinnemoen7892.86%233.33%
David Brownell33.57%233.33%
Thomas Gleixner33.57%233.33%
Total84100.00%6100.00%


int nmi_enable(void) { nmi_enabled = true; if (nmi_eic) eic_writel(nmi_eic, NMIC, EIC_NMIC_ENABLE); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Håvard Skinnemoen27100.00%1100.00%
Total27100.00%1100.00%


void nmi_disable(void) { if (nmi_eic) eic_writel(nmi_eic, NMIC, 0); nmi_enabled = false; }

Contributors

PersonTokensPropCommitsCommitProp
Håvard Skinnemoen24100.00%1100.00%
Total24100.00%1100.00%


static int __init eic_probe(struct platform_device *pdev) { struct eic *eic; struct resource *regs; unsigned int i; unsigned int nr_of_irqs; unsigned int int_irq; int ret; u32 pattern; regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); int_irq = platform_get_irq(pdev, 0); if (!regs || (int)int_irq <= 0) { dev_dbg(&pdev->dev, "missing regs and/or irq resource\n"); return -ENXIO; } ret = -ENOMEM; eic = kzalloc(sizeof(struct eic), GFP_KERNEL); if (!eic) { dev_dbg(&pdev->dev, "no memory for eic structure\n"); goto err_kzalloc; } eic->first_irq = EIM_IRQ_BASE + 32 * pdev->id; eic->regs = ioremap(regs->start, resource_size(regs)); if (!eic->regs) { dev_dbg(&pdev->dev, "failed to map regs\n"); goto err_ioremap; } /* * Find out how many interrupt lines that are actually * implemented in hardware. */ eic_writel(eic, IDR, ~0UL); eic_writel(eic, MODE, ~0UL); pattern = eic_readl(eic, MODE); nr_of_irqs = fls(pattern); /* Trigger on low level unless overridden by driver */ eic_writel(eic, EDGE, 0UL); eic_writel(eic, LEVEL, 0UL); eic->chip = &eic_chip; for (i = 0; i < nr_of_irqs; i++) { irq_set_chip_and_handler(eic->first_irq + i, &eic_chip, handle_level_irq); irq_set_chip_data(eic->first_irq + i, eic); } irq_set_chained_handler_and_data(int_irq, demux_eic_irq, eic); if (pdev->id == 0) { nmi_eic = eic; if (nmi_enabled) /* * Someone tried to enable NMI before we were * ready. Do it now. */ nmi_enable(); } dev_info(&pdev->dev, "External Interrupt Controller at 0x%p, IRQ %u\n", eic->regs, int_irq); dev_info(&pdev->dev, "Handling %u external IRQs, starting with IRQ %u\n", nr_of_irqs, eic->first_irq); return 0; err_ioremap: kfree(eic); err_kzalloc: return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Håvard Skinnemoen34295.80%550.00%
Thomas Gleixner71.96%330.00%
Uwe Kleine-König51.40%110.00%
Joe Perches30.84%110.00%
Total357100.00%10100.00%

static struct platform_driver eic_driver = { .driver = { .name = "at32_eic", }, };
static int __init eic_init(void) { return platform_driver_probe(&eic_driver, eic_probe); }

Contributors

PersonTokensPropCommitsCommitProp
Håvard Skinnemoen18100.00%2100.00%
Total18100.00%2100.00%

arch_initcall(eic_init);

Overall Contributors

PersonTokensPropCommitsCommitProp
Håvard Skinnemoen103289.90%633.33%
Thomas Gleixner675.84%633.33%
David Brownell282.44%211.11%
Wanlong Gao100.87%15.56%
Uwe Kleine-König50.44%15.56%
Tejun Heo30.26%15.56%
Joe Perches30.26%15.56%
Total1148100.00%18100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.